dimension = guess.length;
initializeCMA(guess);
iterations = 0;
double bestValue = fitfun.value(guess);
push(fitnessHistory, bestValue);
PointValuePair optimum = new PointValuePair(getStartPoint(),
isMinimize ? bestValue : -bestValue);
PointValuePair lastResult = null;
// -------------------- Generation Loop --------------------------------
generationLoop:
for (iterations = 1; iterations <= maxIterations; iterations++) {
// Generate and evaluate lambda offspring
final RealMatrix arz = randn1(dimension, lambda);
final RealMatrix arx = zeros(dimension, lambda);
final double[] fitness = new double[lambda];
// generate random offspring
for (int k = 0; k < lambda; k++) {
RealMatrix arxk = null;
for (int i = 0; i < checkFeasableCount + 1; i++) {
if (diagonalOnly <= 0) {
arxk = xmean.add(BD.multiply(arz.getColumnMatrix(k))
.scalarMultiply(sigma)); // m + sig * Normal(0,C)
} else {
arxk = xmean.add(times(diagD,arz.getColumnMatrix(k))
.scalarMultiply(sigma));
}
if (i >= checkFeasableCount ||
fitfun.isFeasible(arxk.getColumn(0))) {
break;
}
// regenerate random arguments for row
arz.setColumn(k, randn(dimension));
}
copyColumn(arxk, 0, arx, k);
try {
fitness[k] = fitfun.value(arx.getColumn(k)); // compute fitness
} catch (TooManyEvaluationsException e) {
break generationLoop;
}
}
// Sort by fitness and compute weighted mean into xmean
final int[] arindex = sortedIndices(fitness);
// Calculate new xmean, this is selection and recombination
final RealMatrix xold = xmean; // for speed up of Eq. (2) and (3)
final RealMatrix bestArx = selectColumns(arx, MathArrays.copyOf(arindex, mu));
xmean = bestArx.multiply(weights);
final RealMatrix bestArz = selectColumns(arz, MathArrays.copyOf(arindex, mu));
final RealMatrix zmean = bestArz.multiply(weights);
final boolean hsig = updateEvolutionPaths(zmean, xold);
if (diagonalOnly <= 0) {
updateCovariance(hsig, bestArx, arz, arindex, xold);
} else {
updateCovarianceDiagonalOnly(hsig, bestArz);
}
// Adapt step size sigma - Eq. (5)
sigma *= FastMath.exp(FastMath.min(1, (normps/chiN - 1) * cs / damps));
final double bestFitness = fitness[arindex[0]];
final double worstFitness = fitness[arindex[arindex.length - 1]];
if (bestValue > bestFitness) {
bestValue = bestFitness;
lastResult = optimum;
optimum = new PointValuePair(fitfun.repair(bestArx.getColumn(0)),
isMinimize ? bestFitness : -bestFitness);
if (getConvergenceChecker() != null && lastResult != null &&
getConvergenceChecker().converged(iterations, optimum, lastResult)) {
break generationLoop;
}
}
// handle termination criteria
// Break, if fitness is good enough
if (stopFitness != 0 && bestFitness < (isMinimize ? stopFitness : -stopFitness)) {
break generationLoop;
}
final double[] sqrtDiagC = sqrt(diagC).getColumn(0);
final double[] pcCol = pc.getColumn(0);
for (int i = 0; i < dimension; i++) {
if (sigma * FastMath.max(FastMath.abs(pcCol[i]), sqrtDiagC[i]) > stopTolX) {
break;
}
if (i >= dimension - 1) {
break generationLoop;
}
}
for (int i = 0; i < dimension; i++) {
if (sigma * sqrtDiagC[i] > stopTolUpX) {
break generationLoop;
}
}
final double historyBest = min(fitnessHistory);
final double historyWorst = max(fitnessHistory);
if (iterations > 2 &&
FastMath.max(historyWorst, worstFitness) -
FastMath.min(historyBest, bestFitness) < stopTolFun) {
break generationLoop;
}
if (iterations > fitnessHistory.length &&
historyWorst-historyBest < stopTolHistFun) {
break generationLoop;
}
// condition number of the covariance matrix exceeds 1e14
if (max(diagD)/min(diagD) > 1e7) {
break generationLoop;
}
// user defined termination
if (getConvergenceChecker() != null) {
final PointValuePair current
= new PointValuePair(bestArx.getColumn(0),
isMinimize ? bestFitness : -bestFitness);
if (lastResult != null &&
getConvergenceChecker().converged(iterations, current, lastResult)) {
break generationLoop;
}