JGAP

Java Genetic Algorithm Package "JGAP"
http://jgap.sourceforge.net/
を用いて,Rastrign 関数の最適化を試みるプログラム.

import java.io.*;
import org.jgap.*;
import org.jgap.impl.DoubleGene;
import org.jgap.impl.DefaultConfiguration;

public class GAsample {
    
    private static final int MAX_ALLOWED_EVOLUTIONS = 140;

    public static void main(String[] args) throws Exception {
	//GAのパラメータ設定などのコンフィギュレーション
	Configuration conf = new DefaultConfiguration();
	
	//最大適合度をもつ個体を保存する
	conf.setPreservFittestIndividual(true);
	
	final int dimension = 3;
	
	//適合度関数の定義
	FitnessFunction myFunc =
	    new GAsampleFitnessFunction(dimension);	//引数:次元数
	conf.setFitnessFunction(myFunc);	//適合度関数の登録
	
	//遺伝子の定義
	Gene[] sampleGenes = new Gene[dimension];
	for (int i = 0; i < dimension; i++) {
	    sampleGenes[i] = new DoubleGene(conf, //コンフィギュレーション
					    -5.12, //遺伝子のとりうる値の下限
					    5.12); //遺伝子のとりうる値の上限
	}
	
	//染色体の定義
	//(メモ)第2引数 : 初期遺伝子集合
	IChromosome sampleChromosome = new Chromosome(conf,
						      sampleGenes);	
	conf.setSampleChromosome(sampleChromosome);	//染色体の登録
	
	//集団(染色体)サイズの設定
	conf.setPopulationSize(1000);
	
	//遺伝子型・・・遺伝子型は,染色体の固定長集団である.
	//遺伝子型の集団をランダムに生成する
	Genotype population;
	population = Genotype.randomInitialGenotype(conf);
	
	//進化させる
	for (int i = 0; i < MAX_ALLOWED_EVOLUTIONS; i++) {
	    population.evolve();
	}
	
	//最大の適合度を有する染色体を得る.
	IChromosome bestSolutionSoFar = population.getFittestChromosome();
	System.out.println("Fitness value of the best solution : " +
			   bestSolutionSoFar.getFitnessValue()); //適合度の値を得る
	
	System.out.println("Value of parameters: ");
	double[] x = new double[dimension];
	for (int i = 0; i < bestSolutionSoFar.size(); i++) {
	    //(メモ) IChromosome.getGene(i) i番目の遺伝子座の遺伝子を得る
	    //(メモ) Gene.getAllele() この遺伝子によって表される値(Object型)を得る.
	    x[i] = ((Double) bestSolutionSoFar.getGene(i).getAllele()).doubleValue();
	}
	for(int i = 0; i < dimension; i++){
	    System.out.printf("x[%d]=%f\n", i, x[i]);
	}
    }
    
    //適合度関数
    static class GAsampleFitnessFunction extends FitnessFunction {
	
	private final int m_dimension;
	
	public GAsampleFitnessFunction(int dimension) {
	    m_dimension = dimension;
	}
	
	public double evaluate(IChromosome a_subject) {
	    double fitness;
	    
	    //Rastrign関数
	    double functionValue = 10 * m_dimension;
	    for (int i = 0; i < a_subject.size(); i++) {
		double x = ((Double) a_subject.getGene(i).getAllele()).doubleValue();
		functionValue += (x * x - 10 * Math.cos(2 * Math.PI * x));
	    }
	    
	    fitness = 1000-functionValue;	//最小化問題だからひっくり返す
	    
	    return fitness;
	}
    }
}

実行結果は以下のとおり:

Fitness value of the best solution : 999.9998905747874
Value of parameters: 
x[0]=-0.000309
x[1]=0.000648
x[2]=-0.000192

Rastrign関数は x=(0, 0, ..., 0) で最小値(最大適合度)をとるから,よい感じに収まっているみたいですね.
現実には複数回の試行が必要だし,パラメータ設定もきちんとやるべきだが,とりあえずの最適化はできているみたいだ.

JGAP における交叉確率,突然変異確率の設定

DefaultConfiguration() ではダメっぽいため,Configuration を自前で設定した上で Configuration.addGeneticOperator() により設定する.

Configuration conf = new Configuration();
conf.setBreeder(new GABreeder());
conf.setRandomGenerator(new StockRandomGenerator());
conf.setEventManager(new EventManager());
conf.setSelectFromPrevGen(1.0d);
conf.setKeepPopulationSizeConstant(true);
conf.setFitnessEvaluator(new DefaultFitnessEvaluator());
conf.setChromosomePool(new ChromosomePool());

conf.addGeneticOperator(new CrossoverOperator(conf, 0.35d));
conf.addGeneticOperator(new MutationOperator(conf, 5));

JGAP におけるルーレット戦略の実装および実行

以下のように NaturalSelector を設定すると,実行時に例外が発生する.

WeightedRouletteSelector weightedRouletteSelector = new WeightedRouletteSelector(conf);
weightedRouletteSelector.setDoubletteChromosomesAllowed(true);
conf.addNaturalSelector(weightedRouletteSelector, true);

例外の内容は以下のとおり:

Exception in thread "main" java.lang.NoClassDefFoundError: gnu/trove/THashMap
	at org.jgap.impl.WeightedRouletteSelector.<init>(WeightedRouletteSelector.java:48)
	at Sample.main(Sample.java:31)
Caused by: java.lang.ClassNotFoundException: gnu.trove.THashMap
	at java.net.URLClassLoader$1.run(URLClassLoader.java:202)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:248)
	... 2 more

Ubuntu Synaptic パッケージマネージャで "trove" を検索すると,
libtrove-java 2.1.0-1ubuntu1 と libtrove-java-doc を発見.パッケージの説明には "high performance collections for java" とある.
これをインストールして,次のように実行時に trove.jar をクラスパスに加えると,OK.

java -cp jgap.jar:/usr/share/java/trove.jar:. Sample 99

・・・と思っていたら,JGAP の lib ディレクトリの中に trove-2.0.2.jar が入っていました.