summaryrefslogtreecommitdiff
path: root/src/main/java/org/apache/commons/math3/optimization/direct/CMAESOptimizer.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/apache/commons/math3/optimization/direct/CMAESOptimizer.java')
-rw-r--r--src/main/java/org/apache/commons/math3/optimization/direct/CMAESOptimizer.java1441
1 files changed, 1441 insertions, 0 deletions
diff --git a/src/main/java/org/apache/commons/math3/optimization/direct/CMAESOptimizer.java b/src/main/java/org/apache/commons/math3/optimization/direct/CMAESOptimizer.java
new file mode 100644
index 0000000..388a6f7
--- /dev/null
+++ b/src/main/java/org/apache/commons/math3/optimization/direct/CMAESOptimizer.java
@@ -0,0 +1,1441 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.math3.optimization.direct;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.commons.math3.analysis.MultivariateFunction;
+import org.apache.commons.math3.exception.DimensionMismatchException;
+import org.apache.commons.math3.exception.NotPositiveException;
+import org.apache.commons.math3.exception.NotStrictlyPositiveException;
+import org.apache.commons.math3.exception.OutOfRangeException;
+import org.apache.commons.math3.exception.TooManyEvaluationsException;
+import org.apache.commons.math3.linear.Array2DRowRealMatrix;
+import org.apache.commons.math3.linear.EigenDecomposition;
+import org.apache.commons.math3.linear.MatrixUtils;
+import org.apache.commons.math3.linear.RealMatrix;
+import org.apache.commons.math3.optimization.ConvergenceChecker;
+import org.apache.commons.math3.optimization.OptimizationData;
+import org.apache.commons.math3.optimization.GoalType;
+import org.apache.commons.math3.optimization.MultivariateOptimizer;
+import org.apache.commons.math3.optimization.PointValuePair;
+import org.apache.commons.math3.optimization.SimpleValueChecker;
+import org.apache.commons.math3.random.MersenneTwister;
+import org.apache.commons.math3.random.RandomGenerator;
+import org.apache.commons.math3.util.FastMath;
+import org.apache.commons.math3.util.MathArrays;
+
+/**
+ * <p>An implementation of the active Covariance Matrix Adaptation Evolution Strategy (CMA-ES)
+ * for non-linear, non-convex, non-smooth, global function minimization.
+ * The CMA-Evolution Strategy (CMA-ES) is a reliable stochastic optimization method
+ * which should be applied if derivative-based methods, e.g. quasi-Newton BFGS or
+ * conjugate gradient, fail due to a rugged search landscape (e.g. noise, local
+ * optima, outlier, etc.) of the objective function. Like a
+ * quasi-Newton method, the CMA-ES learns and applies a variable metric
+ * on the underlying search space. Unlike a quasi-Newton method, the
+ * CMA-ES neither estimates nor uses gradients, making it considerably more
+ * reliable in terms of finding a good, or even close to optimal, solution.</p>
+ *
+ * <p>In general, on smooth objective functions the CMA-ES is roughly ten times
+ * slower than BFGS (counting objective function evaluations, no gradients provided).
+ * For up to <math>N=10</math> variables also the derivative-free simplex
+ * direct search method (Nelder and Mead) can be faster, but it is
+ * far less reliable than CMA-ES.</p>
+ *
+ * <p>The CMA-ES is particularly well suited for non-separable
+ * and/or badly conditioned problems. To observe the advantage of CMA compared
+ * to a conventional evolution strategy, it will usually take about
+ * <math>30 N</math> function evaluations. On difficult problems the complete
+ * optimization (a single run) is expected to take <em>roughly</em> between
+ * <math>30 N</math> and <math>300 N<sup>2</sup></math>
+ * function evaluations.</p>
+ *
+ * <p>This implementation is translated and adapted from the Matlab version
+ * of the CMA-ES algorithm as implemented in module {@code cmaes.m} version 3.51.</p>
+ *
+ * For more information, please refer to the following links:
+ * <ul>
+ * <li><a href="http://www.lri.fr/~hansen/cmaes.m">Matlab code</a></li>
+ * <li><a href="http://www.lri.fr/~hansen/cmaesintro.html">Introduction to CMA-ES</a></li>
+ * <li><a href="http://en.wikipedia.org/wiki/CMA-ES">Wikipedia</a></li>
+ * </ul>
+ *
+ * @deprecated As of 3.1 (to be removed in 4.0).
+ * @since 3.0
+ */
+@Deprecated
+public class CMAESOptimizer
+ extends BaseAbstractMultivariateSimpleBoundsOptimizer<MultivariateFunction>
+ implements MultivariateOptimizer {
+ /** Default value for {@link #checkFeasableCount}: {@value}. */
+ public static final int DEFAULT_CHECKFEASABLECOUNT = 0;
+ /** Default value for {@link #stopFitness}: {@value}. */
+ public static final double DEFAULT_STOPFITNESS = 0;
+ /** Default value for {@link #isActiveCMA}: {@value}. */
+ public static final boolean DEFAULT_ISACTIVECMA = true;
+ /** Default value for {@link #maxIterations}: {@value}. */
+ public static final int DEFAULT_MAXITERATIONS = 30000;
+ /** Default value for {@link #diagonalOnly}: {@value}. */
+ public static final int DEFAULT_DIAGONALONLY = 0;
+ /** Default value for {@link #random}. */
+ public static final RandomGenerator DEFAULT_RANDOMGENERATOR = new MersenneTwister();
+
+ // global search parameters
+ /**
+ * Population size, offspring number. The primary strategy parameter to play
+ * with, which can be increased from its default value. Increasing the
+ * population size improves global search properties in exchange to speed.
+ * Speed decreases, as a rule, at most linearly with increasing population
+ * size. It is advisable to begin with the default small population size.
+ */
+ private int lambda; // population size
+ /**
+ * Covariance update mechanism, default is active CMA. isActiveCMA = true
+ * turns on "active CMA" with a negative update of the covariance matrix and
+ * checks for positive definiteness. OPTS.CMA.active = 2 does not check for
+ * pos. def. and is numerically faster. Active CMA usually speeds up the
+ * adaptation.
+ */
+ private boolean isActiveCMA;
+ /**
+ * Determines how often a new random offspring is generated in case it is
+ * not feasible / beyond the defined limits, default is 0.
+ */
+ private int checkFeasableCount;
+ /**
+ * @see Sigma
+ */
+ private double[] inputSigma;
+ /** Number of objective variables/problem dimension */
+ private int dimension;
+ /**
+ * Defines the number of initial iterations, where the covariance matrix
+ * remains diagonal and the algorithm has internally linear time complexity.
+ * diagonalOnly = 1 means keeping the covariance matrix always diagonal and
+ * this setting also exhibits linear space complexity. This can be
+ * particularly useful for dimension > 100.
+ * @see <a href="http://hal.archives-ouvertes.fr/inria-00287367/en">A Simple Modification in CMA-ES</a>
+ */
+ private int diagonalOnly = 0;
+ /** Number of objective variables/problem dimension */
+ private boolean isMinimize = true;
+ /** Indicates whether statistic data is collected. */
+ private boolean generateStatistics = false;
+
+ // termination criteria
+ /** Maximal number of iterations allowed. */
+ private int maxIterations;
+ /** Limit for fitness value. */
+ private double stopFitness;
+ /** Stop if x-changes larger stopTolUpX. */
+ private double stopTolUpX;
+ /** Stop if x-change smaller stopTolX. */
+ private double stopTolX;
+ /** Stop if fun-changes smaller stopTolFun. */
+ private double stopTolFun;
+ /** Stop if back fun-changes smaller stopTolHistFun. */
+ private double stopTolHistFun;
+
+ // selection strategy parameters
+ /** Number of parents/points for recombination. */
+ private int mu; //
+ /** log(mu + 0.5), stored for efficiency. */
+ private double logMu2;
+ /** Array for weighted recombination. */
+ private RealMatrix weights;
+ /** Variance-effectiveness of sum w_i x_i. */
+ private double mueff; //
+
+ // dynamic strategy parameters and constants
+ /** Overall standard deviation - search volume. */
+ private double sigma;
+ /** Cumulation constant. */
+ private double cc;
+ /** Cumulation constant for step-size. */
+ private double cs;
+ /** Damping for step-size. */
+ private double damps;
+ /** Learning rate for rank-one update. */
+ private double ccov1;
+ /** Learning rate for rank-mu update' */
+ private double ccovmu;
+ /** Expectation of ||N(0,I)|| == norm(randn(N,1)). */
+ private double chiN;
+ /** Learning rate for rank-one update - diagonalOnly */
+ private double ccov1Sep;
+ /** Learning rate for rank-mu update - diagonalOnly */
+ private double ccovmuSep;
+
+ // CMA internal values - updated each generation
+ /** Objective variables. */
+ private RealMatrix xmean;
+ /** Evolution path. */
+ private RealMatrix pc;
+ /** Evolution path for sigma. */
+ private RealMatrix ps;
+ /** Norm of ps, stored for efficiency. */
+ private double normps;
+ /** Coordinate system. */
+ private RealMatrix B;
+ /** Scaling. */
+ private RealMatrix D;
+ /** B*D, stored for efficiency. */
+ private RealMatrix BD;
+ /** Diagonal of sqrt(D), stored for efficiency. */
+ private RealMatrix diagD;
+ /** Covariance matrix. */
+ private RealMatrix C;
+ /** Diagonal of C, used for diagonalOnly. */
+ private RealMatrix diagC;
+ /** Number of iterations already performed. */
+ private int iterations;
+
+ /** History queue of best values. */
+ private double[] fitnessHistory;
+ /** Size of history queue of best values. */
+ private int historySize;
+
+ /** Random generator. */
+ private RandomGenerator random;
+
+ /** History of sigma values. */
+ private List<Double> statisticsSigmaHistory = new ArrayList<Double>();
+ /** History of mean matrix. */
+ private List<RealMatrix> statisticsMeanHistory = new ArrayList<RealMatrix>();
+ /** History of fitness values. */
+ private List<Double> statisticsFitnessHistory = new ArrayList<Double>();
+ /** History of D matrix. */
+ private List<RealMatrix> statisticsDHistory = new ArrayList<RealMatrix>();
+
+ /**
+ * Default constructor, uses default parameters
+ *
+ * @deprecated As of version 3.1: Parameter {@code lambda} must be
+ * passed with the call to {@link #optimize(int,MultivariateFunction,GoalType,OptimizationData[])
+ * optimize} (whereas in the current code it is set to an undocumented value).
+ */
+ @Deprecated
+ public CMAESOptimizer() {
+ this(0);
+ }
+
+ /**
+ * @param lambda Population size.
+ * @deprecated As of version 3.1: Parameter {@code lambda} must be
+ * passed with the call to {@link #optimize(int,MultivariateFunction,GoalType,OptimizationData[])
+ * optimize} (whereas in the current code it is set to an undocumented value)..
+ */
+ @Deprecated
+ public CMAESOptimizer(int lambda) {
+ this(lambda, null, DEFAULT_MAXITERATIONS, DEFAULT_STOPFITNESS,
+ DEFAULT_ISACTIVECMA, DEFAULT_DIAGONALONLY,
+ DEFAULT_CHECKFEASABLECOUNT, DEFAULT_RANDOMGENERATOR,
+ false, null);
+ }
+
+ /**
+ * @param lambda Population size.
+ * @param inputSigma Initial standard deviations to sample new points
+ * around the initial guess.
+ * @deprecated As of version 3.1: Parameters {@code lambda} and {@code inputSigma} must be
+ * passed with the call to {@link #optimize(int,MultivariateFunction,GoalType,OptimizationData[])
+ * optimize}.
+ */
+ @Deprecated
+ public CMAESOptimizer(int lambda, double[] inputSigma) {
+ this(lambda, inputSigma, DEFAULT_MAXITERATIONS, DEFAULT_STOPFITNESS,
+ DEFAULT_ISACTIVECMA, DEFAULT_DIAGONALONLY,
+ DEFAULT_CHECKFEASABLECOUNT, DEFAULT_RANDOMGENERATOR, false);
+ }
+
+ /**
+ * @param lambda Population size.
+ * @param inputSigma Initial standard deviations to sample new points
+ * around the initial guess.
+ * @param maxIterations Maximal number of iterations.
+ * @param stopFitness Whether to stop if objective function value is smaller than
+ * {@code stopFitness}.
+ * @param isActiveCMA Chooses the covariance matrix update method.
+ * @param diagonalOnly Number of initial iterations, where the covariance matrix
+ * remains diagonal.
+ * @param checkFeasableCount Determines how often new random objective variables are
+ * generated in case they are out of bounds.
+ * @param random Random generator.
+ * @param generateStatistics Whether statistic data is collected.
+ * @deprecated See {@link SimpleValueChecker#SimpleValueChecker()}
+ */
+ @Deprecated
+ public CMAESOptimizer(int lambda, double[] inputSigma,
+ int maxIterations, double stopFitness,
+ boolean isActiveCMA, int diagonalOnly, int checkFeasableCount,
+ RandomGenerator random, boolean generateStatistics) {
+ this(lambda, inputSigma, maxIterations, stopFitness, isActiveCMA,
+ diagonalOnly, checkFeasableCount, random, generateStatistics,
+ new SimpleValueChecker());
+ }
+
+ /**
+ * @param lambda Population size.
+ * @param inputSigma Initial standard deviations to sample new points
+ * around the initial guess.
+ * @param maxIterations Maximal number of iterations.
+ * @param stopFitness Whether to stop if objective function value is smaller than
+ * {@code stopFitness}.
+ * @param isActiveCMA Chooses the covariance matrix update method.
+ * @param diagonalOnly Number of initial iterations, where the covariance matrix
+ * remains diagonal.
+ * @param checkFeasableCount Determines how often new random objective variables are
+ * generated in case they are out of bounds.
+ * @param random Random generator.
+ * @param generateStatistics Whether statistic data is collected.
+ * @param checker Convergence checker.
+ * @deprecated As of version 3.1: Parameters {@code lambda} and {@code inputSigma} must be
+ * passed with the call to {@link #optimize(int,MultivariateFunction,GoalType,OptimizationData[])
+ * optimize}.
+ */
+ @Deprecated
+ public CMAESOptimizer(int lambda, double[] inputSigma,
+ int maxIterations, double stopFitness,
+ boolean isActiveCMA, int diagonalOnly, int checkFeasableCount,
+ RandomGenerator random, boolean generateStatistics,
+ ConvergenceChecker<PointValuePair> checker) {
+ super(checker);
+ this.lambda = lambda;
+ this.inputSigma = inputSigma == null ? null : (double[]) inputSigma.clone();
+ this.maxIterations = maxIterations;
+ this.stopFitness = stopFitness;
+ this.isActiveCMA = isActiveCMA;
+ this.diagonalOnly = diagonalOnly;
+ this.checkFeasableCount = checkFeasableCount;
+ this.random = random;
+ this.generateStatistics = generateStatistics;
+ }
+
+ /**
+ * @param maxIterations Maximal number of iterations.
+ * @param stopFitness Whether to stop if objective function value is smaller than
+ * {@code stopFitness}.
+ * @param isActiveCMA Chooses the covariance matrix update method.
+ * @param diagonalOnly Number of initial iterations, where the covariance matrix
+ * remains diagonal.
+ * @param checkFeasableCount Determines how often new random objective variables are
+ * generated in case they are out of bounds.
+ * @param random Random generator.
+ * @param generateStatistics Whether statistic data is collected.
+ * @param checker Convergence checker.
+ *
+ * @since 3.1
+ */
+ public CMAESOptimizer(int maxIterations,
+ double stopFitness,
+ boolean isActiveCMA,
+ int diagonalOnly,
+ int checkFeasableCount,
+ RandomGenerator random,
+ boolean generateStatistics,
+ ConvergenceChecker<PointValuePair> checker) {
+ super(checker);
+ this.maxIterations = maxIterations;
+ this.stopFitness = stopFitness;
+ this.isActiveCMA = isActiveCMA;
+ this.diagonalOnly = diagonalOnly;
+ this.checkFeasableCount = checkFeasableCount;
+ this.random = random;
+ this.generateStatistics = generateStatistics;
+ }
+
+ /**
+ * @return History of sigma values.
+ */
+ public List<Double> getStatisticsSigmaHistory() {
+ return statisticsSigmaHistory;
+ }
+
+ /**
+ * @return History of mean matrix.
+ */
+ public List<RealMatrix> getStatisticsMeanHistory() {
+ return statisticsMeanHistory;
+ }
+
+ /**
+ * @return History of fitness values.
+ */
+ public List<Double> getStatisticsFitnessHistory() {
+ return statisticsFitnessHistory;
+ }
+
+ /**
+ * @return History of D matrix.
+ */
+ public List<RealMatrix> getStatisticsDHistory() {
+ return statisticsDHistory;
+ }
+
+ /**
+ * Input sigma values.
+ * They define the initial coordinate-wise standard deviations for
+ * sampling new search points around the initial guess.
+ * It is suggested to set them to the estimated distance from the
+ * initial to the desired optimum.
+ * Small values induce the search to be more local (and very small
+ * values are more likely to find a local optimum close to the initial
+ * guess).
+ * Too small values might however lead to early termination.
+ * @since 3.1
+ */
+ public static class Sigma implements OptimizationData {
+ /** Sigma values. */
+ private final double[] sigma;
+
+ /**
+ * @param s Sigma values.
+ * @throws NotPositiveException if any of the array entries is smaller
+ * than zero.
+ */
+ public Sigma(double[] s)
+ throws NotPositiveException {
+ for (int i = 0; i < s.length; i++) {
+ if (s[i] < 0) {
+ throw new NotPositiveException(s[i]);
+ }
+ }
+
+ sigma = s.clone();
+ }
+
+ /**
+ * @return the sigma values.
+ */
+ public double[] getSigma() {
+ return sigma.clone();
+ }
+ }
+
+ /**
+ * Population size.
+ * The number of offspring is the primary strategy parameter.
+ * In the absence of better clues, a good default could be an
+ * integer close to {@code 4 + 3 ln(n)}, where {@code n} is the
+ * number of optimized parameters.
+ * Increasing the population size improves global search properties
+ * at the expense of speed (which in general decreases at most
+ * linearly with increasing population size).
+ * @since 3.1
+ */
+ public static class PopulationSize implements OptimizationData {
+ /** Population size. */
+ private final int lambda;
+
+ /**
+ * @param size Population size.
+ * @throws NotStrictlyPositiveException if {@code size <= 0}.
+ */
+ public PopulationSize(int size)
+ throws NotStrictlyPositiveException {
+ if (size <= 0) {
+ throw new NotStrictlyPositiveException(size);
+ }
+ lambda = size;
+ }
+
+ /**
+ * @return the population size.
+ */
+ public int getPopulationSize() {
+ return lambda;
+ }
+ }
+
+ /**
+ * Optimize an objective function.
+ *
+ * @param maxEval Allowed number of evaluations of the objective function.
+ * @param f Objective function.
+ * @param goalType Optimization type.
+ * @param optData Optimization data. The following data will be looked for:
+ * <ul>
+ * <li>{@link org.apache.commons.math3.optimization.InitialGuess InitialGuess}</li>
+ * <li>{@link Sigma}</li>
+ * <li>{@link PopulationSize}</li>
+ * </ul>
+ * @return the point/value pair giving the optimal value for objective
+ * function.
+ */
+ @Override
+ protected PointValuePair optimizeInternal(int maxEval, MultivariateFunction f,
+ GoalType goalType,
+ OptimizationData... optData) {
+ // Scan "optData" for the input specific to this optimizer.
+ parseOptimizationData(optData);
+
+ // The parent's method will retrieve the common parameters from
+ // "optData" and call "doOptimize".
+ return super.optimizeInternal(maxEval, f, goalType, optData);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected PointValuePair doOptimize() {
+ checkParameters();
+ // -------------------- Initialization --------------------------------
+ isMinimize = getGoalType().equals(GoalType.MINIMIZE);
+ final FitnessFunction fitfun = new FitnessFunction();
+ final double[] guess = getStartPoint();
+ // number of objective variables/problem dimension
+ 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;
+ }
+ lastResult = current;
+ }
+ // Adjust step size in case of equal function values (flat fitness)
+ if (bestValue == fitness[arindex[(int)(0.1+lambda/4.)]]) {
+ sigma *= FastMath.exp(0.2 + cs / damps);
+ }
+ if (iterations > 2 && FastMath.max(historyWorst, bestFitness) -
+ FastMath.min(historyBest, bestFitness) == 0) {
+ sigma *= FastMath.exp(0.2 + cs / damps);
+ }
+ // store best in history
+ push(fitnessHistory,bestFitness);
+ fitfun.setValueRange(worstFitness-bestFitness);
+ if (generateStatistics) {
+ statisticsSigmaHistory.add(sigma);
+ statisticsFitnessHistory.add(bestFitness);
+ statisticsMeanHistory.add(xmean.transpose());
+ statisticsDHistory.add(diagD.transpose().scalarMultiply(1E5));
+ }
+ }
+ return optimum;
+ }
+
+ /**
+ * Scans the list of (required and optional) optimization data that
+ * characterize the problem.
+ *
+ * @param optData Optimization data. The following data will be looked for:
+ * <ul>
+ * <li>{@link Sigma}</li>
+ * <li>{@link PopulationSize}</li>
+ * </ul>
+ */
+ private void parseOptimizationData(OptimizationData... optData) {
+ // The existing values (as set by the previous call) are reused if
+ // not provided in the argument list.
+ for (OptimizationData data : optData) {
+ if (data instanceof Sigma) {
+ inputSigma = ((Sigma) data).getSigma();
+ continue;
+ }
+ if (data instanceof PopulationSize) {
+ lambda = ((PopulationSize) data).getPopulationSize();
+ continue;
+ }
+ }
+ }
+
+ /**
+ * Checks dimensions and values of boundaries and inputSigma if defined.
+ */
+ private void checkParameters() {
+ final double[] init = getStartPoint();
+ final double[] lB = getLowerBound();
+ final double[] uB = getUpperBound();
+
+ if (inputSigma != null) {
+ if (inputSigma.length != init.length) {
+ throw new DimensionMismatchException(inputSigma.length, init.length);
+ }
+ for (int i = 0; i < init.length; i++) {
+ if (inputSigma[i] < 0) {
+ // XXX Remove this block in 4.0 (check performed in "Sigma" class).
+ throw new NotPositiveException(inputSigma[i]);
+ }
+ if (inputSigma[i] > uB[i] - lB[i]) {
+ throw new OutOfRangeException(inputSigma[i], 0, uB[i] - lB[i]);
+ }
+ }
+ }
+ }
+
+ /**
+ * Initialization of the dynamic search parameters
+ *
+ * @param guess Initial guess for the arguments of the fitness function.
+ */
+ private void initializeCMA(double[] guess) {
+ if (lambda <= 0) {
+ // XXX Line below to replace the current one in 4.0 (MATH-879).
+ // throw new NotStrictlyPositiveException(lambda);
+ lambda = 4 + (int) (3 * FastMath.log(dimension));
+ }
+ // initialize sigma
+ final double[][] sigmaArray = new double[guess.length][1];
+ for (int i = 0; i < guess.length; i++) {
+ // XXX Line below to replace the current one in 4.0 (MATH-868).
+ // sigmaArray[i][0] = inputSigma[i];
+ sigmaArray[i][0] = inputSigma == null ? 0.3 : inputSigma[i];
+ }
+ final RealMatrix insigma = new Array2DRowRealMatrix(sigmaArray, false);
+ sigma = max(insigma); // overall standard deviation
+
+ // initialize termination criteria
+ stopTolUpX = 1e3 * max(insigma);
+ stopTolX = 1e-11 * max(insigma);
+ stopTolFun = 1e-12;
+ stopTolHistFun = 1e-13;
+
+ // initialize selection strategy parameters
+ mu = lambda / 2; // number of parents/points for recombination
+ logMu2 = FastMath.log(mu + 0.5);
+ weights = log(sequence(1, mu, 1)).scalarMultiply(-1).scalarAdd(logMu2);
+ double sumw = 0;
+ double sumwq = 0;
+ for (int i = 0; i < mu; i++) {
+ double w = weights.getEntry(i, 0);
+ sumw += w;
+ sumwq += w * w;
+ }
+ weights = weights.scalarMultiply(1 / sumw);
+ mueff = sumw * sumw / sumwq; // variance-effectiveness of sum w_i x_i
+
+ // initialize dynamic strategy parameters and constants
+ cc = (4 + mueff / dimension) /
+ (dimension + 4 + 2 * mueff / dimension);
+ cs = (mueff + 2) / (dimension + mueff + 3.);
+ damps = (1 + 2 * FastMath.max(0, FastMath.sqrt((mueff - 1) /
+ (dimension + 1)) - 1)) *
+ FastMath.max(0.3,
+ 1 - dimension / (1e-6 + maxIterations)) + cs; // minor increment
+ ccov1 = 2 / ((dimension + 1.3) * (dimension + 1.3) + mueff);
+ ccovmu = FastMath.min(1 - ccov1, 2 * (mueff - 2 + 1 / mueff) /
+ ((dimension + 2) * (dimension + 2) + mueff));
+ ccov1Sep = FastMath.min(1, ccov1 * (dimension + 1.5) / 3);
+ ccovmuSep = FastMath.min(1 - ccov1, ccovmu * (dimension + 1.5) / 3);
+ chiN = FastMath.sqrt(dimension) *
+ (1 - 1 / ((double) 4 * dimension) + 1 / ((double) 21 * dimension * dimension));
+ // intialize CMA internal values - updated each generation
+ xmean = MatrixUtils.createColumnRealMatrix(guess); // objective variables
+ diagD = insigma.scalarMultiply(1 / sigma);
+ diagC = square(diagD);
+ pc = zeros(dimension, 1); // evolution paths for C and sigma
+ ps = zeros(dimension, 1); // B defines the coordinate system
+ normps = ps.getFrobeniusNorm();
+
+ B = eye(dimension, dimension);
+ D = ones(dimension, 1); // diagonal D defines the scaling
+ BD = times(B, repmat(diagD.transpose(), dimension, 1));
+ C = B.multiply(diag(square(D)).multiply(B.transpose())); // covariance
+ historySize = 10 + (int) (3 * 10 * dimension / (double) lambda);
+ fitnessHistory = new double[historySize]; // history of fitness values
+ for (int i = 0; i < historySize; i++) {
+ fitnessHistory[i] = Double.MAX_VALUE;
+ }
+ }
+
+ /**
+ * Update of the evolution paths ps and pc.
+ *
+ * @param zmean Weighted row matrix of the gaussian random numbers generating
+ * the current offspring.
+ * @param xold xmean matrix of the previous generation.
+ * @return hsig flag indicating a small correction.
+ */
+ private boolean updateEvolutionPaths(RealMatrix zmean, RealMatrix xold) {
+ ps = ps.scalarMultiply(1 - cs).add(
+ B.multiply(zmean).scalarMultiply(FastMath.sqrt(cs * (2 - cs) * mueff)));
+ normps = ps.getFrobeniusNorm();
+ final boolean hsig = normps /
+ FastMath.sqrt(1 - FastMath.pow(1 - cs, 2 * iterations)) /
+ chiN < 1.4 + 2 / ((double) dimension + 1);
+ pc = pc.scalarMultiply(1 - cc);
+ if (hsig) {
+ pc = pc.add(xmean.subtract(xold).scalarMultiply(FastMath.sqrt(cc * (2 - cc) * mueff) / sigma));
+ }
+ return hsig;
+ }
+
+ /**
+ * Update of the covariance matrix C for diagonalOnly > 0
+ *
+ * @param hsig Flag indicating a small correction.
+ * @param bestArz Fitness-sorted matrix of the gaussian random values of the
+ * current offspring.
+ */
+ private void updateCovarianceDiagonalOnly(boolean hsig,
+ final RealMatrix bestArz) {
+ // minor correction if hsig==false
+ double oldFac = hsig ? 0 : ccov1Sep * cc * (2 - cc);
+ oldFac += 1 - ccov1Sep - ccovmuSep;
+ diagC = diagC.scalarMultiply(oldFac) // regard old matrix
+ .add(square(pc).scalarMultiply(ccov1Sep)) // plus rank one update
+ .add((times(diagC, square(bestArz).multiply(weights))) // plus rank mu update
+ .scalarMultiply(ccovmuSep));
+ diagD = sqrt(diagC); // replaces eig(C)
+ if (diagonalOnly > 1 &&
+ iterations > diagonalOnly) {
+ // full covariance matrix from now on
+ diagonalOnly = 0;
+ B = eye(dimension, dimension);
+ BD = diag(diagD);
+ C = diag(diagC);
+ }
+ }
+
+ /**
+ * Update of the covariance matrix C.
+ *
+ * @param hsig Flag indicating a small correction.
+ * @param bestArx Fitness-sorted matrix of the argument vectors producing the
+ * current offspring.
+ * @param arz Unsorted matrix containing the gaussian random values of the
+ * current offspring.
+ * @param arindex Indices indicating the fitness-order of the current offspring.
+ * @param xold xmean matrix of the previous generation.
+ */
+ private void updateCovariance(boolean hsig, final RealMatrix bestArx,
+ final RealMatrix arz, final int[] arindex,
+ final RealMatrix xold) {
+ double negccov = 0;
+ if (ccov1 + ccovmu > 0) {
+ final RealMatrix arpos = bestArx.subtract(repmat(xold, 1, mu))
+ .scalarMultiply(1 / sigma); // mu difference vectors
+ final RealMatrix roneu = pc.multiply(pc.transpose())
+ .scalarMultiply(ccov1); // rank one update
+ // minor correction if hsig==false
+ double oldFac = hsig ? 0 : ccov1 * cc * (2 - cc);
+ oldFac += 1 - ccov1 - ccovmu;
+ if (isActiveCMA) {
+ // Adapt covariance matrix C active CMA
+ negccov = (1 - ccovmu) * 0.25 * mueff / (FastMath.pow(dimension + 2, 1.5) + 2 * mueff);
+ // keep at least 0.66 in all directions, small popsize are most
+ // critical
+ final double negminresidualvariance = 0.66;
+ // where to make up for the variance loss
+ final double negalphaold = 0.5;
+ // prepare vectors, compute negative updating matrix Cneg
+ final int[] arReverseIndex = reverse(arindex);
+ RealMatrix arzneg = selectColumns(arz, MathArrays.copyOf(arReverseIndex, mu));
+ RealMatrix arnorms = sqrt(sumRows(square(arzneg)));
+ final int[] idxnorms = sortedIndices(arnorms.getRow(0));
+ final RealMatrix arnormsSorted = selectColumns(arnorms, idxnorms);
+ final int[] idxReverse = reverse(idxnorms);
+ final RealMatrix arnormsReverse = selectColumns(arnorms, idxReverse);
+ arnorms = divide(arnormsReverse, arnormsSorted);
+ final int[] idxInv = inverse(idxnorms);
+ final RealMatrix arnormsInv = selectColumns(arnorms, idxInv);
+ // check and set learning rate negccov
+ final double negcovMax = (1 - negminresidualvariance) /
+ square(arnormsInv).multiply(weights).getEntry(0, 0);
+ if (negccov > negcovMax) {
+ negccov = negcovMax;
+ }
+ arzneg = times(arzneg, repmat(arnormsInv, dimension, 1));
+ final RealMatrix artmp = BD.multiply(arzneg);
+ final RealMatrix Cneg = artmp.multiply(diag(weights)).multiply(artmp.transpose());
+ oldFac += negalphaold * negccov;
+ C = C.scalarMultiply(oldFac)
+ .add(roneu) // regard old matrix
+ .add(arpos.scalarMultiply( // plus rank one update
+ ccovmu + (1 - negalphaold) * negccov) // plus rank mu update
+ .multiply(times(repmat(weights, 1, dimension),
+ arpos.transpose())))
+ .subtract(Cneg.scalarMultiply(negccov));
+ } else {
+ // Adapt covariance matrix C - nonactive
+ C = C.scalarMultiply(oldFac) // regard old matrix
+ .add(roneu) // plus rank one update
+ .add(arpos.scalarMultiply(ccovmu) // plus rank mu update
+ .multiply(times(repmat(weights, 1, dimension),
+ arpos.transpose())));
+ }
+ }
+ updateBD(negccov);
+ }
+
+ /**
+ * Update B and D from C.
+ *
+ * @param negccov Negative covariance factor.
+ */
+ private void updateBD(double negccov) {
+ if (ccov1 + ccovmu + negccov > 0 &&
+ (iterations % 1. / (ccov1 + ccovmu + negccov) / dimension / 10.) < 1) {
+ // to achieve O(N^2)
+ C = triu(C, 0).add(triu(C, 1).transpose());
+ // enforce symmetry to prevent complex numbers
+ final EigenDecomposition eig = new EigenDecomposition(C);
+ B = eig.getV(); // eigen decomposition, B==normalized eigenvectors
+ D = eig.getD();
+ diagD = diag(D);
+ if (min(diagD) <= 0) {
+ for (int i = 0; i < dimension; i++) {
+ if (diagD.getEntry(i, 0) < 0) {
+ diagD.setEntry(i, 0, 0);
+ }
+ }
+ final double tfac = max(diagD) / 1e14;
+ C = C.add(eye(dimension, dimension).scalarMultiply(tfac));
+ diagD = diagD.add(ones(dimension, 1).scalarMultiply(tfac));
+ }
+ if (max(diagD) > 1e14 * min(diagD)) {
+ final double tfac = max(diagD) / 1e14 - min(diagD);
+ C = C.add(eye(dimension, dimension).scalarMultiply(tfac));
+ diagD = diagD.add(ones(dimension, 1).scalarMultiply(tfac));
+ }
+ diagC = diag(C);
+ diagD = sqrt(diagD); // D contains standard deviations now
+ BD = times(B, repmat(diagD.transpose(), dimension, 1)); // O(n^2)
+ }
+ }
+
+ /**
+ * Pushes the current best fitness value in a history queue.
+ *
+ * @param vals History queue.
+ * @param val Current best fitness value.
+ */
+ private static void push(double[] vals, double val) {
+ for (int i = vals.length-1; i > 0; i--) {
+ vals[i] = vals[i-1];
+ }
+ vals[0] = val;
+ }
+
+ /**
+ * Sorts fitness values.
+ *
+ * @param doubles Array of values to be sorted.
+ * @return a sorted array of indices pointing into doubles.
+ */
+ private int[] sortedIndices(final double[] doubles) {
+ final DoubleIndex[] dis = new DoubleIndex[doubles.length];
+ for (int i = 0; i < doubles.length; i++) {
+ dis[i] = new DoubleIndex(doubles[i], i);
+ }
+ Arrays.sort(dis);
+ final int[] indices = new int[doubles.length];
+ for (int i = 0; i < doubles.length; i++) {
+ indices[i] = dis[i].index;
+ }
+ return indices;
+ }
+
+ /**
+ * Used to sort fitness values. Sorting is always in lower value first
+ * order.
+ */
+ private static class DoubleIndex implements Comparable<DoubleIndex> {
+ /** Value to compare. */
+ private final double value;
+ /** Index into sorted array. */
+ private final int index;
+
+ /**
+ * @param value Value to compare.
+ * @param index Index into sorted array.
+ */
+ DoubleIndex(double value, int index) {
+ this.value = value;
+ this.index = index;
+ }
+
+ /** {@inheritDoc} */
+ public int compareTo(DoubleIndex o) {
+ return Double.compare(value, o.value);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean equals(Object other) {
+
+ if (this == other) {
+ return true;
+ }
+
+ if (other instanceof DoubleIndex) {
+ return Double.compare(value, ((DoubleIndex) other).value) == 0;
+ }
+
+ return false;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public int hashCode() {
+ long bits = Double.doubleToLongBits(value);
+ return (int) ((1438542 ^ (bits >>> 32) ^ bits) & 0xffffffff);
+ }
+ }
+
+ /**
+ * Normalizes fitness values to the range [0,1]. Adds a penalty to the
+ * fitness value if out of range. The penalty is adjusted by calling
+ * setValueRange().
+ */
+ private class FitnessFunction {
+ /** Determines the penalty for boundary violations */
+ private double valueRange;
+ /**
+ * Flag indicating whether the objective variables are forced into their
+ * bounds if defined
+ */
+ private final boolean isRepairMode;
+
+ /** Simple constructor.
+ */
+ FitnessFunction() {
+ valueRange = 1;
+ isRepairMode = true;
+ }
+
+ /**
+ * @param point Normalized objective variables.
+ * @return the objective value + penalty for violated bounds.
+ */
+ public double value(final double[] point) {
+ double value;
+ if (isRepairMode) {
+ double[] repaired = repair(point);
+ value = CMAESOptimizer.this.computeObjectiveValue(repaired) +
+ penalty(point, repaired);
+ } else {
+ value = CMAESOptimizer.this.computeObjectiveValue(point);
+ }
+ return isMinimize ? value : -value;
+ }
+
+ /**
+ * @param x Normalized objective variables.
+ * @return {@code true} if in bounds.
+ */
+ public boolean isFeasible(final double[] x) {
+ final double[] lB = CMAESOptimizer.this.getLowerBound();
+ final double[] uB = CMAESOptimizer.this.getUpperBound();
+
+ for (int i = 0; i < x.length; i++) {
+ if (x[i] < lB[i]) {
+ return false;
+ }
+ if (x[i] > uB[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * @param valueRange Adjusts the penalty computation.
+ */
+ public void setValueRange(double valueRange) {
+ this.valueRange = valueRange;
+ }
+
+ /**
+ * @param x Normalized objective variables.
+ * @return the repaired (i.e. all in bounds) objective variables.
+ */
+ private double[] repair(final double[] x) {
+ final double[] lB = CMAESOptimizer.this.getLowerBound();
+ final double[] uB = CMAESOptimizer.this.getUpperBound();
+
+ final double[] repaired = new double[x.length];
+ for (int i = 0; i < x.length; i++) {
+ if (x[i] < lB[i]) {
+ repaired[i] = lB[i];
+ } else if (x[i] > uB[i]) {
+ repaired[i] = uB[i];
+ } else {
+ repaired[i] = x[i];
+ }
+ }
+ return repaired;
+ }
+
+ /**
+ * @param x Normalized objective variables.
+ * @param repaired Repaired objective variables.
+ * @return Penalty value according to the violation of the bounds.
+ */
+ private double penalty(final double[] x, final double[] repaired) {
+ double penalty = 0;
+ for (int i = 0; i < x.length; i++) {
+ double diff = FastMath.abs(x[i] - repaired[i]);
+ penalty += diff * valueRange;
+ }
+ return isMinimize ? penalty : -penalty;
+ }
+ }
+
+ // -----Matrix utility functions similar to the Matlab build in functions------
+
+ /**
+ * @param m Input matrix
+ * @return Matrix representing the element-wise logarithm of m.
+ */
+ private static RealMatrix log(final RealMatrix m) {
+ final double[][] d = new double[m.getRowDimension()][m.getColumnDimension()];
+ for (int r = 0; r < m.getRowDimension(); r++) {
+ for (int c = 0; c < m.getColumnDimension(); c++) {
+ d[r][c] = FastMath.log(m.getEntry(r, c));
+ }
+ }
+ return new Array2DRowRealMatrix(d, false);
+ }
+
+ /**
+ * @param m Input matrix.
+ * @return Matrix representing the element-wise square root of m.
+ */
+ private static RealMatrix sqrt(final RealMatrix m) {
+ final double[][] d = new double[m.getRowDimension()][m.getColumnDimension()];
+ for (int r = 0; r < m.getRowDimension(); r++) {
+ for (int c = 0; c < m.getColumnDimension(); c++) {
+ d[r][c] = FastMath.sqrt(m.getEntry(r, c));
+ }
+ }
+ return new Array2DRowRealMatrix(d, false);
+ }
+
+ /**
+ * @param m Input matrix.
+ * @return Matrix representing the element-wise square of m.
+ */
+ private static RealMatrix square(final RealMatrix m) {
+ final double[][] d = new double[m.getRowDimension()][m.getColumnDimension()];
+ for (int r = 0; r < m.getRowDimension(); r++) {
+ for (int c = 0; c < m.getColumnDimension(); c++) {
+ double e = m.getEntry(r, c);
+ d[r][c] = e * e;
+ }
+ }
+ return new Array2DRowRealMatrix(d, false);
+ }
+
+ /**
+ * @param m Input matrix 1.
+ * @param n Input matrix 2.
+ * @return the matrix where the elements of m and n are element-wise multiplied.
+ */
+ private static RealMatrix times(final RealMatrix m, final RealMatrix n) {
+ final double[][] d = new double[m.getRowDimension()][m.getColumnDimension()];
+ for (int r = 0; r < m.getRowDimension(); r++) {
+ for (int c = 0; c < m.getColumnDimension(); c++) {
+ d[r][c] = m.getEntry(r, c) * n.getEntry(r, c);
+ }
+ }
+ return new Array2DRowRealMatrix(d, false);
+ }
+
+ /**
+ * @param m Input matrix 1.
+ * @param n Input matrix 2.
+ * @return Matrix where the elements of m and n are element-wise divided.
+ */
+ private static RealMatrix divide(final RealMatrix m, final RealMatrix n) {
+ final double[][] d = new double[m.getRowDimension()][m.getColumnDimension()];
+ for (int r = 0; r < m.getRowDimension(); r++) {
+ for (int c = 0; c < m.getColumnDimension(); c++) {
+ d[r][c] = m.getEntry(r, c) / n.getEntry(r, c);
+ }
+ }
+ return new Array2DRowRealMatrix(d, false);
+ }
+
+ /**
+ * @param m Input matrix.
+ * @param cols Columns to select.
+ * @return Matrix representing the selected columns.
+ */
+ private static RealMatrix selectColumns(final RealMatrix m, final int[] cols) {
+ final double[][] d = new double[m.getRowDimension()][cols.length];
+ for (int r = 0; r < m.getRowDimension(); r++) {
+ for (int c = 0; c < cols.length; c++) {
+ d[r][c] = m.getEntry(r, cols[c]);
+ }
+ }
+ return new Array2DRowRealMatrix(d, false);
+ }
+
+ /**
+ * @param m Input matrix.
+ * @param k Diagonal position.
+ * @return Upper triangular part of matrix.
+ */
+ private static RealMatrix triu(final RealMatrix m, int k) {
+ final double[][] d = new double[m.getRowDimension()][m.getColumnDimension()];
+ for (int r = 0; r < m.getRowDimension(); r++) {
+ for (int c = 0; c < m.getColumnDimension(); c++) {
+ d[r][c] = r <= c - k ? m.getEntry(r, c) : 0;
+ }
+ }
+ return new Array2DRowRealMatrix(d, false);
+ }
+
+ /**
+ * @param m Input matrix.
+ * @return Row matrix representing the sums of the rows.
+ */
+ private static RealMatrix sumRows(final RealMatrix m) {
+ final double[][] d = new double[1][m.getColumnDimension()];
+ for (int c = 0; c < m.getColumnDimension(); c++) {
+ double sum = 0;
+ for (int r = 0; r < m.getRowDimension(); r++) {
+ sum += m.getEntry(r, c);
+ }
+ d[0][c] = sum;
+ }
+ return new Array2DRowRealMatrix(d, false);
+ }
+
+ /**
+ * @param m Input matrix.
+ * @return the diagonal n-by-n matrix if m is a column matrix or the column
+ * matrix representing the diagonal if m is a n-by-n matrix.
+ */
+ private static RealMatrix diag(final RealMatrix m) {
+ if (m.getColumnDimension() == 1) {
+ final double[][] d = new double[m.getRowDimension()][m.getRowDimension()];
+ for (int i = 0; i < m.getRowDimension(); i++) {
+ d[i][i] = m.getEntry(i, 0);
+ }
+ return new Array2DRowRealMatrix(d, false);
+ } else {
+ final double[][] d = new double[m.getRowDimension()][1];
+ for (int i = 0; i < m.getColumnDimension(); i++) {
+ d[i][0] = m.getEntry(i, i);
+ }
+ return new Array2DRowRealMatrix(d, false);
+ }
+ }
+
+ /**
+ * Copies a column from m1 to m2.
+ *
+ * @param m1 Source matrix.
+ * @param col1 Source column.
+ * @param m2 Target matrix.
+ * @param col2 Target column.
+ */
+ private static void copyColumn(final RealMatrix m1, int col1,
+ RealMatrix m2, int col2) {
+ for (int i = 0; i < m1.getRowDimension(); i++) {
+ m2.setEntry(i, col2, m1.getEntry(i, col1));
+ }
+ }
+
+ /**
+ * @param n Number of rows.
+ * @param m Number of columns.
+ * @return n-by-m matrix filled with 1.
+ */
+ private static RealMatrix ones(int n, int m) {
+ final double[][] d = new double[n][m];
+ for (int r = 0; r < n; r++) {
+ Arrays.fill(d[r], 1);
+ }
+ return new Array2DRowRealMatrix(d, false);
+ }
+
+ /**
+ * @param n Number of rows.
+ * @param m Number of columns.
+ * @return n-by-m matrix of 0 values out of diagonal, and 1 values on
+ * the diagonal.
+ */
+ private static RealMatrix eye(int n, int m) {
+ final double[][] d = new double[n][m];
+ for (int r = 0; r < n; r++) {
+ if (r < m) {
+ d[r][r] = 1;
+ }
+ }
+ return new Array2DRowRealMatrix(d, false);
+ }
+
+ /**
+ * @param n Number of rows.
+ * @param m Number of columns.
+ * @return n-by-m matrix of zero values.
+ */
+ private static RealMatrix zeros(int n, int m) {
+ return new Array2DRowRealMatrix(n, m);
+ }
+
+ /**
+ * @param mat Input matrix.
+ * @param n Number of row replicates.
+ * @param m Number of column replicates.
+ * @return a matrix which replicates the input matrix in both directions.
+ */
+ private static RealMatrix repmat(final RealMatrix mat, int n, int m) {
+ final int rd = mat.getRowDimension();
+ final int cd = mat.getColumnDimension();
+ final double[][] d = new double[n * rd][m * cd];
+ for (int r = 0; r < n * rd; r++) {
+ for (int c = 0; c < m * cd; c++) {
+ d[r][c] = mat.getEntry(r % rd, c % cd);
+ }
+ }
+ return new Array2DRowRealMatrix(d, false);
+ }
+
+ /**
+ * @param start Start value.
+ * @param end End value.
+ * @param step Step size.
+ * @return a sequence as column matrix.
+ */
+ private static RealMatrix sequence(double start, double end, double step) {
+ final int size = (int) ((end - start) / step + 1);
+ final double[][] d = new double[size][1];
+ double value = start;
+ for (int r = 0; r < size; r++) {
+ d[r][0] = value;
+ value += step;
+ }
+ return new Array2DRowRealMatrix(d, false);
+ }
+
+ /**
+ * @param m Input matrix.
+ * @return the maximum of the matrix element values.
+ */
+ private static double max(final RealMatrix m) {
+ double max = -Double.MAX_VALUE;
+ for (int r = 0; r < m.getRowDimension(); r++) {
+ for (int c = 0; c < m.getColumnDimension(); c++) {
+ double e = m.getEntry(r, c);
+ if (max < e) {
+ max = e;
+ }
+ }
+ }
+ return max;
+ }
+
+ /**
+ * @param m Input matrix.
+ * @return the minimum of the matrix element values.
+ */
+ private static double min(final RealMatrix m) {
+ double min = Double.MAX_VALUE;
+ for (int r = 0; r < m.getRowDimension(); r++) {
+ for (int c = 0; c < m.getColumnDimension(); c++) {
+ double e = m.getEntry(r, c);
+ if (min > e) {
+ min = e;
+ }
+ }
+ }
+ return min;
+ }
+
+ /**
+ * @param m Input array.
+ * @return the maximum of the array values.
+ */
+ private static double max(final double[] m) {
+ double max = -Double.MAX_VALUE;
+ for (int r = 0; r < m.length; r++) {
+ if (max < m[r]) {
+ max = m[r];
+ }
+ }
+ return max;
+ }
+
+ /**
+ * @param m Input array.
+ * @return the minimum of the array values.
+ */
+ private static double min(final double[] m) {
+ double min = Double.MAX_VALUE;
+ for (int r = 0; r < m.length; r++) {
+ if (min > m[r]) {
+ min = m[r];
+ }
+ }
+ return min;
+ }
+
+ /**
+ * @param indices Input index array.
+ * @return the inverse of the mapping defined by indices.
+ */
+ private static int[] inverse(final int[] indices) {
+ final int[] inverse = new int[indices.length];
+ for (int i = 0; i < indices.length; i++) {
+ inverse[indices[i]] = i;
+ }
+ return inverse;
+ }
+
+ /**
+ * @param indices Input index array.
+ * @return the indices in inverse order (last is first).
+ */
+ private static int[] reverse(final int[] indices) {
+ final int[] reverse = new int[indices.length];
+ for (int i = 0; i < indices.length; i++) {
+ reverse[i] = indices[indices.length - i - 1];
+ }
+ return reverse;
+ }
+
+ /**
+ * @param size Length of random array.
+ * @return an array of Gaussian random numbers.
+ */
+ private double[] randn(int size) {
+ final double[] randn = new double[size];
+ for (int i = 0; i < size; i++) {
+ randn[i] = random.nextGaussian();
+ }
+ return randn;
+ }
+
+ /**
+ * @param size Number of rows.
+ * @param popSize Population size.
+ * @return a 2-dimensional matrix of Gaussian random numbers.
+ */
+ private RealMatrix randn1(int size, int popSize) {
+ final double[][] d = new double[size][popSize];
+ for (int r = 0; r < size; r++) {
+ for (int c = 0; c < popSize; c++) {
+ d[r][c] = random.nextGaussian();
+ }
+ }
+ return new Array2DRowRealMatrix(d, false);
+ }
+}