eva2/src/eva2/problems/F8Problem.java
Fabian Becker 0202692844 Various bugfixes.
- Properly handle loading/searching of classes with EvA prefix
- Properly open Main window and set Logger when invoked from within JVM
- New F22Problem
2014-10-29 17:44:34 +01:00

259 lines
9.1 KiB
Java

package eva2.problems;
import eva2.optimization.individuals.AbstractEAIndividual;
import eva2.optimization.operator.distancemetric.EuclideanMetric;
import eva2.optimization.operator.postprocess.SolutionHistogram;
import eva2.optimization.population.Population;
import eva2.optimization.population.PopulationInterface;
import eva2.tools.ToolBox;
import eva2.tools.math.Mathematics;
import eva2.util.annotation.Description;
import java.util.Arrays;
/**
* Ackley's function.
*/
@Description("Ackley's function.")
public class F8Problem extends AbstractProblemDoubleOffset
implements InterfaceInterestingHistogram, InterfaceMultimodalProblem, //InterfaceFirstOrderDerivableProblem,
InterfaceMultimodalProblemKnown, java.io.Serializable {
transient protected Population listOfOptima = null;
private static transient boolean stateInitializingOptima = false;
private double a = 20;
private double b = 0.2;
private double c = 2 * Math.PI;
final static double f8Range = 32.768;
public F8Problem() {
setDefaultRange(f8Range);
}
public F8Problem(F8Problem b) {
super(b);
this.a = b.a;
this.b = b.b;
this.c = b.c;
}
public F8Problem(int dim) {
super(dim);
setDefaultRange(f8Range);
}
// make this a multimodal problem known and add the best optima as in the niching ES papers!
/**
* This method returns a deep clone of the problem.
*
* @return the clone
*/
@Override
public Object clone() {
return new F8Problem(this);
}
/**
* Ths method allows you to evaluate a double[] to determine the fitness
*
* @param x The n-dimensional input vector
* @return The m-dimensional output vector.
*/
@Override
public double[] evaluate(double[] x) {
x = rotateMaybe(x);
double[] result = new double[1];
double sum1 = 0, sum2 = 0, exp1, exp2;
for (int i = 0; i < x.length; i++) {
double xi = x[i] - xOffset;
sum1 += (xi) * (xi);
sum2 += Math.cos(c * (xi));
}
exp1 = -b * Math.sqrt(sum1 / (double) this.problemDimension);
exp2 = sum2 / (double) this.problemDimension;
result[0] = yOffset + a + Math.E - a * Math.exp(exp1) - Math.exp(exp2);
return result;
}
/**
* This method returns a string describing the optimization problem.
*
* @return The description.
*/
public String getStringRepresentationForProblem() {
String result = "";
result += "F8 Ackley's function.\n";
result += "This problem is multimodal.\n";
result += "Parameters:\n";
result += "Dimension : " + this.problemDimension + "\n";
result += "Noise level : " + this.getNoise() + "\n";
result += "Solution representation:\n";
//result += this.template.getSolutionRepresentationFor();
return result;
}
@Override
public void initializeProblem() {
super.initializeProblem();
initListOfOptima();
}
/**
* This method allows the CommonJavaObjectEditorPanel to read the
* name to the current object.
*
* @return The name.
*/
@Override
public String getName() {
return "Ackley";
}
@Override
public SolutionHistogram getHistogram() {
if (getProblemDimension() < 15) {
return new SolutionHistogram(-0.1, 7.9, 16);
} else if (getProblemDimension() < 25) {
return new SolutionHistogram(-0.5, 15.5, 16);
} else {
return new SolutionHistogram(0, 16, 16);
}
}
@Override
public boolean fullListAvailable() {
return true;
}
@Override
public double getMaximumPeakRatio(Population pop) {
return AbstractMultiModalProblemKnown.getMaximumPeakRatioMinimization(listOfOptima, pop, getDefaultAccuracy(), 0, 5);
}
@Override
public int getNumberOfFoundOptima(Population pop) {
return AbstractMultiModalProblemKnown.getNoFoundOptimaOf(this, pop);
}
@Override
public Population getRealOptima() {
return listOfOptima;
}
@Override
public String[] getAdditionalDataHeader() {
String[] superHd = super.getAdditionalDataHeader();
return ToolBox.appendArrays(new String[]{"numOptimaFound", "maxPeakRatio"}, superHd);
// return "#Optima found \tMaximum Peak Ratio \t" + super.getAdditionalDataHeader(population);
}
@Override
public Object[] getAdditionalDataValue(PopulationInterface pop) {
Object[] myRet = new Object[2];
myRet[0] = this.getNumberOfFoundOptima((Population) pop);
myRet[1] = this.getMaximumPeakRatio((Population) pop);
return ToolBox.appendArrays(myRet, super.getAdditionalDataValue(pop));
}
/**
* We identify a set of 2*n+1 optima, which are the global and the first level
* of local optima.
* Interestingly, the local optima in the first sphere (close to (1,0,0,0,...) vanish starting
* with n=18 (checked with Matlab). The next sphere contains O(n^2) optima (I think 3*n*(n-1)).
* This is unfortunately not mentioned in the papers by Shir
* and Bäck who still seemed to be able to find 2*n+1...
*/
@Override
public void initListOfOptima() {
if (listOfOptimaNeedsUpdate()) {
stateInitializingOptima = true;
listOfOptima = new Population();
// ingeniously avoid recursive calls during refinement!
double[] pos = new double[getProblemDimension()];
Arrays.fill(pos, getXOffset());
addOptimum(pos); // the global optimum
double refinedX = 0;
if (getProblemDimension() < 18) {
for (int i = 0; i < getProblemDimension(); i++) {
// TODO what about dimensions higher than 18???
for (int k = -1; k <= 1; k += 2) {
Arrays.fill(pos, getXOffset());
if (refinedX == 0) { // we dont know the exact x-offset for the optima, so refine once
pos[i] = k + getXOffset();
double[] dir = pos.clone();
dir[i] -= 0.05;
pos = inverseRotateMaybe(pos);
// ab dim 18/20 oder so finde ich plötzlich keine optima bei x[i]<1 mehr???
dir = inverseRotateMaybe(dir);
pos = refineSolution(this, pos, dir, 0.0005, 1e-20, 0);
if (EuclideanMetric.euclideanDistance(pos, listOfOptima.getEAIndividual(0).getDoublePosition()) < 0.5) {
System.err.println("Warning, possibly converged to a wrong optimum in F8Problem.initListOfOptima!");
}
pos = rotateMaybe(pos);
refinedX = Math.abs(pos[i] - getXOffset()); // store the refined position which is equal in any direction and dimension
} else {
pos[i] = (k * refinedX) + getXOffset();
}
addOptimum(pos);
}
}
}
stateInitializingOptima = false;
}
}
private double[] refineSolution(AbstractProblemDouble prob, double[] pos, double[] vect, double initStep, double thresh, int fitCrit) {
// a line search along a vector
double[] tmpP = pos.clone();
double[] normedVect = Mathematics.normVect(vect);
double dx = initStep;
double tmpFit, oldFit = prob.evaluate(pos)[fitCrit];
int dir = 1;
while (dx > thresh) {
// add a step to tmpP
Mathematics.svvAddScaled(dx * dir, normedVect, pos, tmpP);
// evaluate tmpP
tmpFit = prob.evaluate(tmpP)[fitCrit];
if (tmpFit < oldFit) {
// if tmpP is better than pos continue at new pos
double[] tmp = pos;
pos = tmpP;
tmpP = tmp;
oldFit = tmpFit;
} else {
// otherwise invert direction, reduce step, continue
dx *= 0.73;
dir *= -1;
}
}
return pos;
}
private boolean listOfOptimaNeedsUpdate() {
if (stateInitializingOptima) {
return false;
} // avoid recursive call during refining with GDA
if (listOfOptima == null || (listOfOptima.size() != (1 + 2 * getProblemDimension()))) {
return true;
} else { // the number of optima is corret - now check different offset or rotation by comparing one fitness value
AbstractEAIndividual indy = listOfOptima.getEAIndividual(1);
double[] curFit = evaluate(indy.getDoublePosition());
if (Math.abs(Mathematics.dist(curFit, indy.getFitness(), 2)) > 1e-10) {
return true;
} else {
return false;
}
}
}
private void addOptimum(double[] pos) {
AbstractProblemDouble.addUnrotatedOptimum(listOfOptima, this, pos);
}
}