/*
Copyright 2006 by Sean Luke and George Mason University
Licensed under the Academic Free License version 3.0
See the file "LICENSE" for more information
*/
package ec.app.ecsuite;
import ec.util.*;
import ec.*;
import ec.simple.*;
import ec.vector.*;
/*
* ECSuite.java
*
* Created: Thu Mar 22 16:27:15 2001
* By: Liviu Panait and Sean Luke
*/
/*
* @author Liviu Panait and Sean Luke and Khaled Talukder
* @version 2.0
*/
/**
Several standard Evolutionary Computation functions are implemented.
As the SimpleFitness is used for maximization problems, the mapping f(x) --> -f(x) is used to transform
the problems into maximization ones.
Parameters
base.type
String, one of: rosenbrock rastrigin sphere step noisy-quartic kdj-f1 kdj-f2 kdj-f3 kdj-f4 booth griewank median sum product schwefel min rotated-rastrigin rotated-schwefel rotated-griewank langerman lennard-jones lunacek
(The vector problem to test against. Some of the types are synonyms: kdj-f1 = sphere, kdj-f2 = rosenbrock, kdj-f3 = step, kdj-f4 = noisy-quartic. "kdj" stands for "Ken DeJong", and the numbers are the problems in his test suite)
base.seed
int > 0
(Random number seed for rotated problems)
*/
public class ECSuite extends Problem implements SimpleProblemForm
{
public static final String P_SEED = "seed";
public static final String P_WHICH_PROBLEM = "type";
public static final String V_ROSENBROCK = "rosenbrock";
public static final String V_RASTRIGIN = "rastrigin";
public static final String V_SPHERE = "sphere";
public static final String V_STEP = "step";
public static final String V_NOISY_QUARTIC = "noisy-quartic";
public static final String V_F1 = "kdj-f1";
public static final String V_F2 = "kdj-f2";
public static final String V_F3 = "kdj-f3";
public static final String V_F4 = "kdj-f4";
public static final String V_BOOTH = "booth";
public static final String V_GRIEWANGK = "griewangk";
public static final String V_GRIEWANK = "griewank";
public static final String V_MEDIAN = "median";
public static final String V_SUM = "sum";
public static final String V_PRODUCT = "product";
public static final String V_SCHWEFEL = "schwefel";
public static final String V_MIN = "min";
public static final String V_ROTATED_RASTRIGIN = "rotated-rastrigin";
public static final String V_ROTATED_SCHWEFEL = "rotated-schwefel";
public static final String V_ROTATED_GRIEWANK = "rotated-griewank";
public static final String V_LANGERMAN = "langerman" ;
public static final String V_LENNARDJONES = "lennard-jones" ;
public static final String V_LUNACEK = "lunacek" ;
public static final int PROB_ROSENBROCK = 0;
public static final int PROB_RASTRIGIN = 1;
public static final int PROB_SPHERE = 2;
public static final int PROB_STEP = 3;
public static final int PROB_NOISY_QUARTIC = 4;
public static final int PROB_BOOTH = 5;
public static final int PROB_GRIEWANK = 6;
public static final int PROB_MEDIAN = 7;
public static final int PROB_SUM = 8;
public static final int PROB_PRODUCT = 9;
public static final int PROB_SCHWEFEL = 10;
public static final int PROB_MIN = 11;
public static final int PROB_ROTATED_RASTRIGIN = 12;
public static final int PROB_ROTATED_SCHWEFEL = 13;
public static final int PROB_ROTATED_GRIEWANK = 14;
public static final int PROB_LANGERMAN = 15 ;
public static final int PROB_LENNARDJONES = 16 ;
public static final int PROB_LUNACEK = 17 ;
public int problemType = PROB_ROSENBROCK; // defaults on Rosenbrock
public static final String problemName[] = new String[]
{
V_ROSENBROCK,
V_RASTRIGIN,
V_SPHERE,
V_STEP,
V_NOISY_QUARTIC,
V_BOOTH,
V_GRIEWANK,
V_MEDIAN,
V_SUM,
V_PRODUCT,
V_SCHWEFEL,
V_MIN,
V_ROTATED_RASTRIGIN,
V_ROTATED_SCHWEFEL,
V_ROTATED_GRIEWANK,
V_LANGERMAN,
V_LENNARDJONES,
V_LUNACEK
};
public static final double minRange[] = new double[]
{
-2.048, // rosenbrock
-5.12, // rastrigin
-5.12, // sphere
-5.12, // step
-1.28, // noisy quartic
-5.12, // booth
-600.0, // griewank
0.0, // median
0.0, // sum
0.0, // product
-512.03, // schwefel
0.0, // min
-5.12, // rotated-rastrigin
-512.03, // rotated-schwefel
-600.0, // rotated-griewank
0, // langerman
-3.0, // lennard-jones
-5.0, // lunacek
};
public static final double maxRange[] = new double[]
{
2.048, // rosenbrock
5.12, // rastrigin
5.12, // sphere
5.12, // step
1.28, // noisy quartic
5.12, // booth
600.0, // griewank
1.0, // median
1.0, // sum
2.0, // product
511.97, // schwefel
1.0, // min
5.12, // rotated-rastrigin
511.97, // rotated-schwefel
600.0, // rotated-griewank
10, // langerman
3.0, // lennard-jones
5.0 // lunacek
};
public long seed; // rotation seed for rotation problems
boolean alreadyChecked = false;
public void checkRange(EvolutionState state, int problem, double[] genome)
{
if (alreadyChecked || state.generation > 0) return;
alreadyChecked = true;
for(int i = 0; i < state.population.subpops.length; i++)
{
if (!(state.population.subpops[i].species instanceof FloatVectorSpecies))
{
state.output.fatal("ECSuite requires species " + i + " to be a FloatVectorSpecies, but it is a: " + state.population.subpops[i].species);
}
FloatVectorSpecies species = (FloatVectorSpecies)(state.population.subpops[i].species);
for(int k = 0; k < genome.length; k++)
{
if (species.minGene(k) != minRange[problem] ||
species.maxGene(k) != maxRange[problem])
{
state.output.warning("Gene range is nonstandard for problem " + problemName[problem] + ".\nFirst occurrence: Subpopulation " + i + " Gene " + k +
" range was [" + species.minGene(k) + ", " + species.maxGene(k) +
"], expected [" + minRange[problem] + ", " + maxRange[problem] + "]");
return; // done here
}
}
}
if (problemType == PROB_LANGERMAN)
{
// Langerman has a maximum genome size of 10
if (genome.length > 10)
state.output.fatal("The Langerman function requires that the genome size be a value from 1 to 10 inclusive. It is presently " + genome.length);
}
else if (problemType == PROB_LENNARDJONES)
{
// Lennard-Jones requires that its genomes be multiples of 3
if (genome.length % 3 != 0)
state.output.fatal("The Lennard-Jones function requires that the genome size be a multiple of 3. It is presently " + genome.length);
}
}
// nothing....
public void setup(final EvolutionState state, final Parameter base)
{
super.setup(state, base);
String wp = state.parameters.getStringWithDefault( base.push( P_WHICH_PROBLEM ), null, "" );
if( wp.compareTo( V_ROSENBROCK ) == 0 || wp.compareTo (V_F2)==0 )
problemType = PROB_ROSENBROCK;
else if ( wp.compareTo( V_RASTRIGIN ) == 0 )
problemType = PROB_RASTRIGIN;
else if ( wp.compareTo( V_SPHERE ) == 0 || wp.compareTo (V_F1)==0)
problemType = PROB_SPHERE;
else if ( wp.compareTo( V_STEP ) == 0 || wp.compareTo (V_F3)==0)
problemType = PROB_STEP;
else if ( wp.compareTo( V_NOISY_QUARTIC ) == 0 || wp.compareTo (V_F4)==0)
problemType = PROB_NOISY_QUARTIC;
else if( wp.compareTo( V_BOOTH ) == 0 )
problemType = PROB_BOOTH;
else if( wp.compareTo( V_GRIEWANK ) == 0 )
problemType = PROB_GRIEWANK;
else if (wp.compareTo( V_GRIEWANGK ) == 0 )
{
state.output.warning("Incorrect parameter name (\"griewangk\") used, should be \"griewank\"", base.push( P_WHICH_PROBLEM ), null );
problemType = PROB_GRIEWANK;
}
else if( wp.compareTo( V_MEDIAN ) == 0 )
problemType = PROB_MEDIAN;
else if( wp.compareTo( V_SUM ) == 0 )
problemType = PROB_SUM;
else if( wp.compareTo( V_PRODUCT ) == 0 )
problemType = PROB_PRODUCT;
else if (wp.compareTo( V_SCHWEFEL ) == 0 )
problemType = PROB_SCHWEFEL;
else if (wp.compareTo( V_MIN ) == 0 )
problemType = PROB_MIN;
else if (wp.compareTo( V_ROTATED_RASTRIGIN) == 0)
problemType = PROB_ROTATED_RASTRIGIN;
else if (wp.compareTo( V_ROTATED_SCHWEFEL) == 0)
problemType = PROB_ROTATED_SCHWEFEL;
else if (wp.compareTo( V_ROTATED_GRIEWANK) == 0)
problemType = PROB_ROTATED_GRIEWANK;
else if (wp.compareTo(V_LANGERMAN) == 0)
problemType = PROB_LANGERMAN ;
else if (wp.compareTo(V_LENNARDJONES) == 0)
problemType = PROB_LENNARDJONES ;
else if (wp.compareTo(V_LUNACEK) == 0)
problemType = PROB_LUNACEK ;
else state.output.fatal(
"Invalid value for parameter, or parameter not found.\n" +
"Acceptable values are:\n" +
" " + V_ROSENBROCK + " (or " + V_F2 + ")\n" +
" " + V_RASTRIGIN + "\n" +
" " + V_SPHERE + " (or " + V_F1 + ")\n" +
" " + V_STEP + " (or " + V_F3 + ")\n" +
" " + V_NOISY_QUARTIC + " (or " + V_F4 + ")\n"+
" " + V_BOOTH + "\n" +
" " + V_GRIEWANK + "\n" +
" " + V_MEDIAN + "\n" +
" " + V_SUM + "\n" +
" " + V_PRODUCT + "\n" +
" " + V_SCHWEFEL + "\n"+
" " + V_MIN + "\n"+
" " + V_ROTATED_RASTRIGIN + "\n" +
" " + V_ROTATED_SCHWEFEL + "\n" +
" " + V_ROTATED_GRIEWANK + "\n" +
" " + V_LANGERMAN + "\n" +
" " + V_LENNARDJONES + "\n" +
" " + V_LUNACEK + "\n",
base.push( P_WHICH_PROBLEM ) );
seed = state.parameters.getLongWithDefault( base.push( P_SEED ), null, ROTATION_SEED );
if (seed <= 0)
state.output.fatal("If a rotation seed is provided, it must be > 0", base.push( P_SEED ), null);
}
public void evaluate(final EvolutionState state,
final Individual ind,
final int subpopulation,
final int threadnum)
{
if (ind.evaluated) // don't bother reevaluating
return;
if( !( ind instanceof DoubleVectorIndividual ) )
state.output.fatal( "The individuals for this problem should be DoubleVectorIndividuals." );
DoubleVectorIndividual temp = (DoubleVectorIndividual)ind;
double[] genome = temp.genome;
//int len = genome.length;
// this curious break-out makes it easy to use the isOptimal() and function() methods
// for other purposes, such as coevolutionary versions of this class.
// compute the fitness on a per-function basis
double fit = (function(state, problemType, temp.genome, threadnum));
// compute if we're optimal on a per-function basis
boolean isOptimal = isOptimal(problemType, fit);
// set the fitness appropriately
if (fit < (0.0 - Double.MAX_VALUE)) // uh oh -- can be caused by Product for example
{
((SimpleFitness)(ind.fitness)).setFitness( state, 0.0 - Double.MAX_VALUE, isOptimal );
state.output.warnOnce("'Product' type used: some fitnesses are negative infinity, setting to lowest legal negative number.");
}
else if (fit > Double.MAX_VALUE) // uh oh -- can be caused by Product for example
{
((SimpleFitness)(ind.fitness)).setFitness( state, Double.MAX_VALUE, isOptimal );
state.output.warnOnce("'Product' type used: some fitnesses are negative infinity, setting to lowest legal negative number.");
}
else
{
((SimpleFitness)(ind.fitness)).setFitness( state, fit, isOptimal );
}
ind.evaluated = true;
}
public boolean isOptimal(int function, double fitness)
{
switch(problemType)
{
case PROB_ROSENBROCK:
case PROB_RASTRIGIN:
case PROB_SPHERE:
case PROB_STEP:
return fitness == 0.0;
case PROB_NOISY_QUARTIC:
case PROB_BOOTH:
case PROB_GRIEWANK:
case PROB_MEDIAN:
case PROB_SUM:
case PROB_PRODUCT:
case PROB_SCHWEFEL:
case PROB_ROTATED_RASTRIGIN: // not sure
case PROB_ROTATED_SCHWEFEL:
case PROB_ROTATED_GRIEWANK:
case PROB_MIN:
case PROB_LANGERMAN: // may be around -1.4
case PROB_LENNARDJONES:
case PROB_LUNACEK:
default:
return false;
}
}
public double function(EvolutionState state, int function, double[] genome, int threadnum)
{
checkRange(state, function, genome);
double value = 0;
double len = genome.length;
switch(function)
{
case PROB_ROSENBROCK:
for( int i = 1 ; i < len ; i++ )
{
double gj = genome[i-1] ;
double gi = genome[i] ;
value += 100 * (gj*gj - gj) * (gj*gj - gj) + (1-gj) * (1-gj);
}
return -value;
case PROB_RASTRIGIN:
final double A = 10.0;
value = len * A;
for( int i = 0 ; i < len ; i++ )
{
double gi = genome[i] ;
value += ( gi*gi - A * Math.cos( 2 * Math.PI * gi ) );
}
return -value;
case PROB_SPHERE:
for( int i = 0 ; i < len ; i++ )
{
double gi = genome[i] ;
value += gi * gi;
}
return -value;
case PROB_STEP:
for( int i = 0 ; i < len ; i++ )
{
double gi = genome[i] ;
// The reason for the 6 is that this is the equation De Jong used in the De Jong Test Suite
value += 6 + Math.floor( gi );
}
return -value;
case PROB_NOISY_QUARTIC:
for( int i = 0 ; i < len ; i++ )
{
double gi = genome[i] ;
value += (i+1)*(gi*gi*gi*gi) + state.random[threadnum].nextDouble();
}
return -value;
case PROB_BOOTH:
if( len != 2 )
state.output.fatal( "The Booth problem is defined for only two terms, and as a consequence the genome of the DoubleVectorIndividual should have size 2." );
double g0 = genome[0] ;
double g1 = genome[1] ;
value = (g0 + 2*g1 - 7) * (g0 + 2*g1 - 7) +
(2*g0 + g1 - 5) * (2*g0 + g1 - 5);
return -value;
case PROB_GRIEWANK:
value = 1;
double prod = 1;
for( int i = 0 ; i < len ; i++ )
{
double gi = genome[i] ;
value += (gi*gi)/4000.0;
prod *= Math.cos( gi / Math.sqrt(i+1) );
}
value -= prod;
return -value;
case PROB_SCHWEFEL:
for( int i = 0 ; i < len ; i++ )
{
double gi = genome[i] ;
value += -gi * Math.sin(Math.sqrt(Math.abs(gi)));
}
return -value;
case PROB_MEDIAN: // FIXME, need to do a better median-finding algorithm, such as http://www.ics.uci.edu/~eppstein/161/960130.html
double[] sorted = new double[(int)len];
System.arraycopy(genome, 0, sorted, 0, sorted.length);
ec.util.QuickSort.qsort(sorted);
return sorted[sorted.length / 2] ; // note positive
case PROB_SUM:
value = 0.0;
for( int i = 0 ; i < len ; i++ )
{
double gi = genome[i] ;
value += gi;
}
return value; // note positive
case PROB_MIN:
value = genome[0] ;
for( int i = 1 ; i < len ; i++ )
{
double gi = genome[i] ;
if (value > gi) value = gi;
}
return value; // note positive
case PROB_PRODUCT:
value = 1.0;
for( int i = 0 ; i < len ; i++ )
{
double gi = genome[i] ;
value *= gi;
}
return value; // note positive
case PROB_ROTATED_RASTRIGIN:
{
synchronized(rotationMatrix) // synchronizations are rare in ECJ. :-(
{
if (rotationMatrix[0] == null)
rotationMatrix[0] = buildRotationMatrix(state, seed, (int)len);
}
// now we know the matrix exists rotate the matrix and return its value
double[] val = mul(rotationMatrix[0], genome);
return function(state, PROB_RASTRIGIN, val, threadnum);
}
case PROB_ROTATED_SCHWEFEL:
{
synchronized(rotationMatrix) // synchronizations are rare in ECJ. :-(
{
if (rotationMatrix[0] == null)
rotationMatrix[0] = buildRotationMatrix(state, seed, (int)len);
}
// now we know the matrix exists rotate the matrix and return its value
double[] val = mul(rotationMatrix[0], genome);
return function(state, PROB_SCHWEFEL, val, threadnum);
}
case PROB_ROTATED_GRIEWANK:
{
synchronized(rotationMatrix) // synchronizations are rare in ECJ. :-(
{
if (rotationMatrix[0] == null)
rotationMatrix[0] = buildRotationMatrix(state, seed, (int)len);
}
// now we know the matrix exists rotate the matrix and return its value
double[] val = mul(rotationMatrix[0], genome);
return function(state, PROB_GRIEWANK, val, threadnum);
}
case PROB_LANGERMAN:
{
return 0.0 - langerman(genome);
}
case PROB_LENNARDJONES:
{
int numAtoms = genome.length / 3;
double v = 0.0 ;
for(int i = 0 ; i < numAtoms - 1 ; i++ )
{
for(int j = i + 1 ; j < numAtoms ; j++ )
{
// double d = dist(genome, i, j);
double a = genome[i * 3] - genome[j * 3];
double b = genome[i * 3 + 1] - genome[j * 3 + 1];
double c = genome[i * 3 + 2] - genome[j * 3 + 2];
double d = Math.sqrt(a * a + b * b + c * c);
double r12 = Math.pow(d, -12.0);
double r6 = Math.pow(d, -6.0);
double e = r12 - r6 ;
v += e ;
}
}
v *= -4.0 ;
return v;
}
case PROB_LUNACEK:
{
// Lunacek function: for more information, please see --
// http://arxiv.org/pdf/1207.4318.pdf
// http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.154.1657
// // // //
double s = 0.7 ; // The shape of the boundary of the double sphere,
// could be like [0.2 - 1.4] but not 0.0.
// > 1.0 or < 1.0 means a parabolic shape, 1.0 means a linear boundary.
double d = 1.0 ; // depth of the sphere, could be 1, 2, 3, or 4. 1 is deeper than 4
// this could be also be a fraction I guess.
double mu1 = 0.0 ;
for(int i = 0 ; i < genome.length ; i++)
mu1 = genome[i] ;
double mu2 = -1.0 * Math.sqrt(((mu1 * mu1) - d)/s);
double sigma1 = 0.0;
double sigma2 = 0.0 ;
for(int i = 0 ; i < genome.length ; i++)
{
sigma1 = (genome[i] - mu1) * (genome[i] - mu1);
sigma2 = (genome[i] - mu2) * (genome[i] - mu2);
}
sigma2 = d * genome.length + s * sigma1 ;
double sphere = Math.min(sigma1, sigma2);
double rastrigin = function(state, PROB_RASTRIGIN, genome, threadnum);
// + or - ? not sure, I always get confused.
// Lunacek function is a combination of Rastrigin and a Double Sphere.
// As the Rastrigin is -, so this function should be.
return -1.0 * (sphere + rastrigin) ;
}
default:
state.output.fatal( "ec.app.ecsuite.ECSuite has an invalid problem -- how on earth did that happen?" );
return 0; // never happens
}
}
// magic arrays for the Langerman problem
private double[][] afox10 =
{
{9.681, 0.667, 4.783, 9.095, 3.517, 9.325, 6.544, 0.211, 5.122, 2.020},
{9.400, 2.041, 3.788, 7.931, 2.882, 2.672, 3.568, 1.284, 7.033, 7.374},
{8.025, 9.152, 5.114, 7.621, 4.564, 4.711, 2.996, 6.126, 0.734, 4.982},
{2.196, 0.415, 5.649, 6.979, 9.510, 9.166, 6.304, 6.054, 9.377, 1.426},
{8.074, 8.777, 3.467, 1.863, 6.708, 6.349, 4.534, 0.276, 7.633, 1.567},
{7.650, 5.658, 0.720, 2.764, 3.278, 5.283, 7.474, 6.274, 1.409, 8.208},
{1.256, 3.605, 8.623, 6.905, 0.584, 8.133, 6.071, 6.888, 4.187, 5.448},
{8.314, 2.261, 4.224, 1.781, 4.124, 0.932, 8.129, 8.658, 1.208, 5.762},
{0.226, 8.858, 1.420, 0.945, 1.622, 4.698, 6.228, 9.096, 0.972, 7.637},
{7.305, 2.228, 1.242, 5.928, 9.133, 1.826, 4.060, 5.204, 8.713, 8.247},
{0.652, 7.027, 0.508, 4.876, 8.807, 4.632, 5.808, 6.937, 3.291, 7.016},
{2.699, 3.516, 5.874, 4.119, 4.461, 7.496, 8.817, 0.690, 6.593, 9.789},
{8.327, 3.897, 2.017, 9.570, 9.825, 1.150, 1.395, 3.885, 6.354, 0.109},
{2.132, 7.006, 7.136, 2.641, 1.882, 5.943, 7.273, 7.691, 2.880, 0.564},
{4.707, 5.579, 4.080, 0.581, 9.698, 8.542, 8.077, 8.515, 9.231, 4.670},
{8.304, 7.559, 8.567, 0.322, 7.128, 8.392, 1.472, 8.524, 2.277, 7.826},
{8.632, 4.409, 4.832, 5.768, 7.050, 6.715, 1.711, 4.323, 4.405, 4.591},
{4.887, 9.112, 0.170, 8.967, 9.693, 9.867, 7.508, 7.770, 8.382, 6.740},
{2.440, 6.686, 4.299, 1.007, 7.008, 1.427, 9.398, 8.480, 9.950, 1.675},
{6.306, 8.583, 6.084, 1.138, 4.350, 3.134, 7.853, 6.061, 7.457, 2.258},
{0.652, 0.343, 1.370, 0.821, 1.310, 1.063, 0.689, 8.819, 8.833, 9.070},
{5.558, 1.272, 5.756, 9.857, 2.279, 2.764, 1.284, 1.677, 1.244, 1.234},
{3.352, 7.549, 9.817, 9.437, 8.687, 4.167, 2.570, 6.540, 0.228, 0.027},
{8.798, 0.880, 2.370, 0.168, 1.701, 3.680, 1.231, 2.390, 2.499, 0.064},
{1.460, 8.057, 1.336, 7.217, 7.914, 3.615, 9.981, 9.198, 5.292, 1.224},
{0.432, 8.645, 8.774, 0.249, 8.081, 7.461, 4.416, 0.652, 4.002, 4.644},
{0.679, 2.800, 5.523, 3.049, 2.968, 7.225, 6.730, 4.199, 9.614, 9.229},
{4.263, 1.074, 7.286, 5.599, 8.291, 5.200, 9.214, 8.272, 4.398, 4.506},
{9.496, 4.830, 3.150, 8.270, 5.079, 1.231, 5.731, 9.494, 1.883, 9.732},
{4.138, 2.562, 2.532, 9.661, 5.611, 5.500, 6.886, 2.341, 9.699, 6.500}
};
private double[] cfox10 =
{
0.806, 0.517, 1.5, 0.908, 0.965,
0.669, 0.524, 0.902, 0.531, 0.876,
0.462, 0.491, 0.463, 0.714, 0.352,
0.869, 0.813, 0.811, 0.828, 0.964,
0.789, 0.360, 0.369, 0.992, 0.332,
0.817, 0.632, 0.883, 0.608, 0.326
};
private double langerman(double genome[])
{
double sum = 0 ;
for ( int i = 0 ; i < 30 ; i++ )
{
// compute squared distance
double distsq = 0.0;
double t;
double[] afox10i = afox10[i];
for(int j = 0; j < genome.length; j++)
{
t = genome[j] - afox10i[j];
distsq += t * t;
}
sum += cfox10[i] * Math.exp(-distsq / Math.PI) * Math.cos(distsq * Math.PI);
}
return 0 - sum;
}
/*
-----------------
Rotation facility
-----------------
This code is just used by the Rotated Schwefel and Rotated Rastrigin functions to rotate their
functions by a certain amount. The code is largely based on the rotation scheme described in
"Completely Derandomized Self-Adaptation in Evolutionary Strategies",
Nikolaus Hansen and Andreas Ostermeier, Evolutionary Computation 9(2): 159--195.
We fix a hard-coded rotation matrix which is the same for all problems, in order to guarantee
correctness in gathering results over multiple jobs. But you can change that easily if you like.
*/
public static double[][][] rotationMatrix = new double[1][][]; // the actual matrix is stored in rotationMatrix[0] -- a hack
/** Dot product between two column vectors. Does not modify the original vectors. */
public static double dot(double[] x, double[] y)
{
double val = 0;
for(int i =0; i < x.length; i++)
val += x[i] * y[i];
return val;
}
/** Multiply a column vector against a matrix[row][column]. Does not modify the original vector or matrix. */
public static double[] mul(double [/* row */ ][ /* column */] matrix, double[] x)
{
double[] val = new double[matrix.length];
for(int i = 0; i < matrix.length; i++)
{
double sum = 0.0;
double[] m = matrix[i];
for(int j = 0; j < m.length; j++)
sum += m[j] * x[j];
val[i] = sum;
}
return val;
}
/** Scalar multiply against a column vector. Does not modify the original vector. */
public static double[] scalarMul(double scalar, double[] x)
{
double[] val = new double[x.length];
for(int i =0; i < x.length; i++)
val[i] = x[i] * scalar;
return val;
}
/** Subtract two column vectors. Does not modify the original vectors. */
public static double[] sub(double[] x, double[] y)
{
double[] val = new double[x.length];
for(int i =0; i < x.length; i++)
val[i] = x[i] - y[i];
return val;
}
/** Normalize a column vector. Does not modify the original vector. */
public static double[] normalize(double[] x)
{
double[] val = new double[x.length];
double sumsq = 0;
for(int i =0; i < x.length; i++)
sumsq += x[i] * x[i];
sumsq = Math.sqrt(sumsq);
for(int i =0; i < x.length; i++)
val[i] = x[i] / sumsq;
return val;
}
/** Fixed rotation seed so all jobs use exactly the same rotation space. */
public static final long ROTATION_SEED = 9731297;
/** Build an NxN rotation matrix[row][column] with a given seed. */
public static double[ /* row */ ][ /* column */] buildRotationMatrix(EvolutionState state, long rotationSeed, int N)
{
if (rotationSeed == ROTATION_SEED)
state.output.warnOnce("Default rotation seed being used (" + rotationSeed + ")");
MersenneTwisterFast rand = new MersenneTwisterFast(rotationSeed); // it's rare to need to do this, but we need to guarantee the same rotation space
for(int i = 0; i < 624 * 4; i++) // prime the MT for 4 full sample iterations to get it warmed up
rand.nextInt();
double o[ /* row */ ][ /* column */ ] = new double[N][N];
// make random values
for(int i = 0; i < N; i++)
for(int k = 0; k < N; k++)
o[i][k] = rand.nextGaussian();
// build random values
for(int i = 0; i < N; i++)
{
// extract o[i] -> no
double[] no = new double[N];
for(int k=0; k < N; k++)
no[k] = o[i][k];
// go through o[i] and o[j], modifying no
for(int j = 0; j < i; j++)
{
double d = dot(o[i], o[j]);
double[] val = scalarMul(d, o[j]);
no = sub(no, val);
}
o[i] = normalize(no);
}
return o;
}
}
Ads help maintain this website.