The GA Procedure

Defining a User Update Routine

The GA procedure enables you to define a routine that is to be called at each generation in the optimization process, after the designated objective function has been evaluated for each solution, before the selection process takes place. Some of the tasks that can be handled with an update routine include evaluating global solution fitness criteria, logging intermediate optimization progress, evaluating termination criteria and stopping the optimization, modifying the properties of the genetic operators to intensify or diversify the search process, or even to reinitialize portions of the solution population. You can designate a user update function with the call

call SetUpdateRoutine('name');

where name is the name of the routine you have defined.

The parameters defined for the update routine must correspond to variables of the same name established in the global portion of your procedure input. If you desire to update a parameter and have that update retained across generations, that parameter must also be declared in an OUTARGS statement in the update routine definition. The following program snippet illustrates how a user might specify an update routine that monitors the best objective value at each generation and terminates the optimization when no improvement is seen after a specified number of iterations.


   subroutine no_improvement_terminator(iteration, 
                                        saved_value, 
                                        nsame, 
                                        same_limit,
                                        populationSize);
   outargs iteration, saved_value, nsame;
  
   array objValues[1] /nosym;

   /* dynamically allocate array to fit populationSize */
   call dynamic_array(objValues, populationSize);

   /* read in current objective values */
   call GetObjValues(objValues, populationSize);

   /* find best value */
   current_best = objValues[1];
   do i = 2 to populationSize;
     /* for a minimization problem, use < here */
     if(objValues[i] > current_best) then 
        current_best = objValues[i];
   end;
     
   if iteration > 0 then do;
     /* for a minimization problem, use < here */
     if current_best > saved_value then do;
       /* reset same value counter */
       nsame = 1;
       saved_value = current_best;
     end;
     else do;
       /* increment same value counter */
       nsame = nsame + 1;
       /* if counter equals limit, then make this the last generation */
       if nsame >= same_limit then
         call ContinueFor(0);
     end;
   end;
   else do;
     saved_value = current_best;
     nsame = 1;
   end;       
     
   iteration = iteration + 1;

   endsub;

   iteration = 0;
   saved_value = 0;
   nsame = 0;
   /* terminate when no improvement after 30 generations */
   same_limit = 30; 
   populationSize = 100;
   call SetUpdateRoutine('no_improvement_terminator');

From within a user update routine you can use a GetObjValues call to get the current solution objective values, a GetSolutions call to get the current solution population, an UpdateSolutions call to reset solution values, a ReEvaluate call to recompute objective values, or an Initialize call to reinitialize and resize the solution population.