[jrgp -- Documentation ]

Micro guide to gap.

BASIC CONCEPTS ADVANCED CONCEPTS

BASIC CONCEPTS

  'gap' is the genetic programming basic runtime library of 'jrgp'.

* Using 'gap' in a java program *

Here is a typical java program using 'gap':

import gap.*;

public class SymbolicRegressionMain extends Object {

  public static void main (String args[]) {
    try{
      Class[] functionSet = {Add.class,Cos.class,Div.class,Exp.class,Mul.class,
                             Rlog.class,Sin.class,Sub.class};
      Class[] terminalSet = {};
      int[] argumentsType = {GPFunction.NO_TYPE};
      GPParams params = new GPParams( functionSet, terminalSet, argumentType );
      params.makeDefinitive();

      GPPopulation pop = new GPPopulation( 5000, params, new RegrEvaluator() );
      pop.setLogBook( new LogScreen() );
      pop.setOverSelection( -1.0f );
      for( int i=0; i<20; i++)
        pop.nextGeneration();
    } catch (Exception e) {
      e.printStackTrace();
      System.exit(1);
    }
  }

}

First of all, you have to define the parameters of your GP-problems. You have to create a gap.GPParams object specifying the function set and the type of the arguments (if any).

Then you can define the ADFs using the functions setADFs, setADFFunctionSets (to define a function set different from the main one for an ADF), setADFLinks (to specify how the ADF can use each other). Please refer to the java documentation for more details. You may also want to specify the type of the root (see the setRootCompatibility method) and set standard parameters such as the maximal depth of new programs or the max depth of the ADFs.

When you have finished with these settings, call the GPParams.makeDefinitive method to have your program setting up all the GPParams internal tables. After this point, you can only modify the numerical parameters of your parameters object, while the structure (e.g. the number of ADFs or the content of the function set) can only be modified in a GP-population (gap.GPPopulation) . See Modifying the structure of a parameters object.

  You can now use your parameters to create a GP-program or a new random GP-population. Otherwise You can write a program as a LISP-like string and parse it constructing a GP-program.

The GPPopulation constructor takes as arguments the size of the created population, a GPParams instance and an evaluator implementing the gap.Evaluator interface. (A possible start-point for implementing this is given by gap.DefaultEvaluator class, check the shipped examples for the concrete details). Note that a GPPopulation contains additional parameters (e.g. the probability of mutation or a overselection flag).  If you want your GPPopulation to print some information during the run, you can set a log book (see the GPPopulation.setLogBook method). Standard log books are provided: LogFile prints to a file and LogScreen to the standard output.

Using 'gap' in a jython session *

We found very comfortable to work on GP-problems with jython. In this way you merge the flexibility of an interactive session as in 'gool' and the power of low-level interaction with the objects.

Here's a possible jython session:

>>> import java
>>> import gap
>>> from symbolic_regression import *
>>> no_type=gap.GPFunction.NO_TYPE
>>> fs=[Add,Cos,Div,Exp,Mul,Rlog,Sin,Sub]
>>> ts=[]
>>> arg_type=[no_type]
>>> params=gap.GPParams( fs, ts, arg_type )
>>> # create a new population
>>> pop=gap.GPPopulation(5000, params, RegrEvaluator())
>>> pop.setOverSelection(-1.0)
>>> # 10 generations
>>> for i in range(10):
...  pop.nextGeneration()
...
>>> pop.getBestIndividual()
 (* jython output omitted *)
>>> pop.getBestFitness()
 (* jython output omitted *)
>>> pop.save('test.pop')
>>> # remove the Sin function from the function set
>>> pop.removeFunction(Sin, gap.GPPopulation.REPLACE_BRANCH)
>>> # add an ADF
>>> pop.addADF(no_type, [no_type, no_type], None, None, None)

Using 'gap' through 'gool' *

See the gool how-to.

ADVANCED CONCEPTS

Compiling GP-programs *

You can make your GP-programs independent from the gap library by compiling them into self-standing java classes. This is really useful in particular if you evolved a program that is interesting because of its effects (e.g. if your program controls an external agent as in the 'ant' example).

Just call the the GPProgram.compile method specifying the class name (package name included) and the file in which to save the class. 'gool' has a 'compile...' option for population program nodes too.

 

* Modifying the structure of a parameters object *

You may want to modify the structure of your parameters during a run, for example if you find out that a function is not useful or if you want to add an ADF. Although you can`t modify the parameters directly after you made them definitive, you can do this by calling the corresponding methods of your GPPopulation.

If you remove something from the function set some branches of your program trees may be invalid. You can choose one out of three ways of replacing them: you can replace the entire program with a new random one (GPPopulation.REPLACE_PROGRAM), or only the tree (GPPopulation.REPLACE_TREE) or the branch in which the removed function is called (GPPopulation.REPLACE_BRANCH). See removeADF, removeFunction, removeTerminal, removeArg, addADF, addFunction, addTerminal, addArg in the java documentation for further details.

 * Subclassing GPPopulation *

There are a few important methods you may want to overload in your GPPopulation to change the standard behaviour:

  1. newIndividual: overload this method if you want to implement special ways to create new individuals. This method is called at the creation of a new population and when a program is created to replace an invalid one (see Modifying the structure of a parameters object );
  2. nextGeneration: overload this method if you need to create new generation in a non-standard way or if you want to implement your own genetic operations;
  3. fitnessDependentChoice: this method is called when 'gap' has to choose a random individual in the population.

Setting a random numbers generator *

The standard random numbers generator in 'gap' is an implementation of the Park-Miller one and is defined in the TheRandomGenerator class, which contains static methods to obtain random numbers or to set the seed. 

If you want 'gap' to use another generator, you have to create an implementation of the RandomGenerator interface, and then call the TheRandomGenerator.setRandomGenerator(RandomGenerator rg) method.

Strong type question *

Q: You claim that gap is strong-typed, but actually only float values can be returned.

A: The structure of the program tree is strong-typed, as you can define arbitrary types and then require that the different branches of a function node belong to a subset of this types by specifying a compatibility table.

In contrast, the computed value type is always 'float'. This is enough for most application. However, if you need to return something else, you can play with the free Object argument of the GPFunction exec method.