IBM ILOG Solver User's Manual > Evolutionary Algorithms > Using More Advanced EA Features > Using custom selectors and multiple operators

In this section, you will learn how to:

Make a copy of the example file YourSolverHome/examples/src/tutorial/ea1max_cust_partial.cpp and open this copy in your development environment. This file is a program that is only partially completed. You will fill in the blanks in each step in this section. At the end of the section, you will have completed the example and you can compile and run the program.

You define the runtime custom selector that will be invoked at solve time. This is a tournament selector whose constructor takes one argument--the tournament size. Recall that a tournament selector takes the best of n solutions drawn randomly from the population, where n is the tournament size. In the custom operator, you add each selected solution to the selector's output solution pool. The use of IloSolution::isBetterThan facilitates the construction of this selector.

Step 1   -  

The custom selector

Add the following code after the comment //The custom selector

ILOCTXSELECTOR1(CustomSelector, IloSolution, IloSolutionPool, in,
                IloSolver, solver, IlcInt, tournamentSize) {
  IloInt size = in.getSize(); 
  if (size != 0) {
    IlcRandom rnd = solver.getRandom();
    IloSolution candidate = in.getSolution(rnd.getInt(size));
    for (IlcInt tournament = 1; tournament < tournamentSize; tournament++) {
      IloSolution competition = in.getSolution(rnd.getInt(size));
      if (competition.isBetterThan(candidate))
        candidate = competition;
    }
    select(candidate);
  }
}

In the main code, instead of a predefined selector, you will instantiate your own selector, specifying the tournament size.

Step 2   -  

Create the user-defined tournament selector

Add the following code after the comment
//Create the user-defined tournament selector

    IloPoolProc selector =
      IloSelectSolutions(env, CustomSelector(env, 3), IloTrue);

This creates a pool processor which uses CustomSelector to select solutions. Here a selector of tournament size 3 is created. The boolean parameter to IloSelectSolutions indicates whether the same solution can be selected more than once or when selector is asked for more than one solution. In this case, IloTrue is specified, meaning that all solutions generated must be unique, and duplicates are forbidden. This ensures that later, a crossover cannot be performed between two instances of the same parent.

Now you will learn how to use more than one genetic operator to evolve the population. These alternative operators will be stored in a processor pool, which is similar to a solution pool.

Step 3   -  

Create a processor pool to store operators

Add the following code after the comment
//Create a processor array to store operators

    IloPoolProcArray ops(env);

You will keep the mutation operator in your operator set, and so you add the mutation operator to the processor pool.

Step 4   -  

Add the mutation operator to the pool

Add the following code after the comment
//Add the mutation operator to the pool

    ops.add(factory.mutate(1.0 / problemSize, "mutate"));

You also add the uniform crossover operator to the processor array in the same manner as for mutation.

Step 5   -  

Add the crossover operator to the pool

Add the following code after the comment
//Add the crossover operator to the pool

    ops.add(factory.uniformXover(0.5, "uXover"));

Now you produce a new composite operator which selects a random operator from the array and invokes it. You do this by:

Step 6   -  

Creates a goal selector which will choose the goal to apply

Add the following code after the comment
//Creates a goal selector which will choose the goal to apply

    IloPoolProc applyOp = IloSelectProcessor(
      env, ops, IloRandomSelector<IloPoolProc,IloPoolProcArray>(env)
    );

You have now learned how to write a custom selector and use multiple operators in a processor pool. In the next section, you will learn how to use listeners.

Step 7   -  

Compile and run the program

Compile and run the program. You should get the following results:

Problem size: 50
Population size: 50
Max generation: 60
GENERATION 0 WORST 17 BEST 34 AVERAGE 25.06
Optimum value: 50
GENERATION 1 WORST 20 BEST 33 AVERAGE 27.7
GENERATION 2 WORST 24 BEST 34 AVERAGE 30.54
GENERATION 3 WORST 29 BEST 36 AVERAGE 32.34
GENERATION 4 WORST 29 BEST 38 AVERAGE 33.52
GENERATION 5 WORST 30 BEST 41 AVERAGE 34.76
GENERATION 6 WORST 32 BEST 41 AVERAGE 35.8
GENERATION 7 WORST 33 BEST 42 AVERAGE 37.02
GENERATION 8 WORST 34 BEST 42 AVERAGE 38.6
GENERATION 9 WORST 35 BEST 44 AVERAGE 39.28
GENERATION 10 WORST 37 BEST 46 AVERAGE 40.92
GENERATION 11 WORST 40 BEST 46 AVERAGE 42.36
GENERATION 12 WORST 40 BEST 47 AVERAGE 43.36
GENERATION 13 WORST 42 BEST 48 AVERAGE 44.44
GENERATION 14 WORST 42 BEST 49 AVERAGE 45.64
GENERATION 15 WORST 43 BEST 49 AVERAGE 46.38
GENERATION 16 WORST 43 BEST 50 AVERAGE 47.06
OPTIMUM FOUND 

The complete program is available in the YourSolverHome/examples/src/ea1max_cust.cpp file.