Optimization is over both discrete and real-valued parameters.
Gradient information is not available, even for the real-valued parameters. A tiny change in a threshold leads to either no change at all, or to changed actions, hence to a jump in the objective function. So we choose a standard genetic algorithm. Our encoding has 16 bits per rule, so some bits are wasted. More importantly, single-bit changes can yield very different strategies, so local search by flipping single bits is less useful.