View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.math.optimization.direct;
19  
20  import java.util.ArrayList;
21  import java.util.Arrays;
22  import java.util.List;
23  
24  import org.apache.commons.math.analysis.MultivariateRealFunction;
25  import org.apache.commons.math.exception.MultiDimensionMismatchException;
26  import org.apache.commons.math.exception.NoDataException;
27  import org.apache.commons.math.exception.NotPositiveException;
28  import org.apache.commons.math.exception.OutOfRangeException;
29  import org.apache.commons.math.exception.TooManyEvaluationsException;
30  import org.apache.commons.math.linear.Array2DRowRealMatrix;
31  import org.apache.commons.math.linear.EigenDecomposition;
32  import org.apache.commons.math.linear.MatrixUtils;
33  import org.apache.commons.math.linear.RealMatrix;
34  import org.apache.commons.math.optimization.GoalType;
35  import org.apache.commons.math.optimization.MultivariateRealOptimizer;
36  import org.apache.commons.math.optimization.RealPointValuePair;
37  import org.apache.commons.math.random.MersenneTwister;
38  import org.apache.commons.math.random.RandomGenerator;
39  import org.apache.commons.math.util.MathArrays;
40  
41  /**
42   * <p>An implementation of the active Covariance Matrix Adaptation Evolution Strategy (CMA-ES)
43   * for non-linear, non-convex, non-smooth, global function minimization.
44   * The CMA-Evolution Strategy (CMA-ES) is a reliable stochastic optimization method
45   * which should be applied if derivative-based methods, e.g. quasi-Newton BFGS or
46   * conjugate gradient, fail due to a rugged search landscape (e.g. noise, local
47   * optima, outlier, etc.) of the objective function. Like a
48   * quasi-Newton method, the CMA-ES learns and applies a variable metric
49   * on the underlying search space. Unlike a quasi-Newton method, the
50   * CMA-ES neither estimates nor uses gradients, making it considerably more
51   * reliable in terms of finding a good, or even close to optimal, solution.</p>
52   *
53   * <p>In general, on smooth objective functions the CMA-ES is roughly ten times
54   * slower than BFGS (counting objective function evaluations, no gradients provided).
55   * For up to <math>N=10</math> variables also the derivative-free simplex
56   * direct search method (Nelder and Mead) can be faster, but it is
57   * far less reliable than CMA-ES.</p>
58   *
59   * <p>The CMA-ES is particularly well suited for non-separable
60   * and/or badly conditioned problems. To observe the advantage of CMA compared
61   * to a conventional evolution strategy, it will usually take about
62   * <math>30 N</math> function evaluations. On difficult problems the complete
63   * optimization (a single run) is expected to take <em>roughly</em> between
64   * <math>30 N</math> and <math>300 N<sup>2</sup></math>
65   * function evaluations.</p>
66   *
67   * <p>This implementation is translated and adapted from the Matlab version
68   * of the CMA-ES algorithm as implemented in module {@code cmaes.m} version 3.51.</p>
69   *
70   * For more information, please refer to the following links:
71   * <ul>
72   *  <li><a href="http://www.lri.fr/~hansen/cmaes.m">Matlab code</a></li>
73   *  <li><a href="http://www.lri.fr/~hansen/cmaesintro.html">Introduction to CMA-ES</a></li>
74   *  <li><a href="http://en.wikipedia.org/wiki/CMA-ES">Wikipedia</a></li>
75   * </ul>
76   *
77   * @version $Id$
78   * @since 3.0
79   */
80  
81  public class CMAESOptimizer extends
82          BaseAbstractScalarOptimizer<MultivariateRealFunction> implements
83          MultivariateRealOptimizer {
84  
85      /** Default value for {@link #checkFeasableCount}: {@value}. */
86      public static final int DEFAULT_CHECKFEASABLECOUNT = 0;
87      /** Default value for {@link #stopfitness}: {@value}. */
88      public static final double DEFAULT_STOPFITNESS = 0;
89      /** Default value for {@link #isActiveCMA}: {@value}. */
90      public static final boolean DEFAULT_ISACTIVECMA = true;
91      /** Default value for {@link #maxIterations}: {@value}. */
92      public static final int DEFAULT_MAXITERATIONS = 30000;
93      /** Default value for {@link #diagonalOnly}: {@value}. */
94      public static final int DEFAULT_DIAGONALONLY = 0;
95      /** Default value for {@link #random}. */
96      public static final RandomGenerator DEFAULT_RANDOMGENERATOR = new MersenneTwister();
97  
98      // global search parameters
99      /**
100      * Population size, offspring number. The primary strategy parameter to play
101      * with, which can be increased from its default value. Increasing the
102      * population size improves global search properties in exchange to speed.
103      * Speed decreases, as a rule, at most linearly with increasing population
104      * size. It is advisable to begin with the default small population size.
105      */
106     private int lambda; // population size
107     /**
108      * Covariance update mechanism, default is active CMA. isActiveCMA = true
109      * turns on "active CMA" with a negative update of the covariance matrix and
110      * checks for positive definiteness. OPTS.CMA.active = 2 does not check for
111      * pos. def. and is numerically faster. Active CMA usually speeds up the
112      * adaptation.
113      */
114     private boolean isActiveCMA;
115     /**
116      * Determines how often a new random offspring is generated in case it is
117      * not feasible / beyond the defined limits, default is 0. Only relevant if
118      * boundaries != null.
119      */
120     private int checkFeasableCount;
121     /**
122      * Lower and upper boundaries of the objective variables. boundaries == null
123      * means no boundaries.
124      */
125     private double[][] boundaries;
126     /**
127      * Individual sigma values - initial search volume. inputSigma determines
128      * the initial coordinate wise standard deviations for the search. Setting
129      * SIGMA one third of the initial search region is appropriate.
130      */
131     private double[] inputSigma;
132     /** Number of objective variables/problem dimension */
133     private int dimension;
134     /**
135      * Defines the number of initial iterations, where the covariance matrix
136      * remains diagonal and the algorithm has internally linear time complexity.
137      * diagonalOnly = 1 means keeping the covariance matrix always diagonal and
138      * this setting also exhibits linear space complexity. This can be
139      * particularly useful for dimension > 100.
140      * @see <a href="http://hal.archives-ouvertes.fr/inria-00287367/en">A Simple Modification in CMA-ES</a>
141      */
142     private int diagonalOnly = 0;
143     /** Number of objective variables/problem dimension */
144     private boolean isMinimize = true;
145     /** Indicates whether statistic data is collected. */
146     private boolean generateStatistics = false;
147 
148     // termination criteria
149     /** Maximal number of iterations allowed. */
150     private int maxIterations;
151     /** Limit for fitness value. */
152     private double stopfitness;
153     /** Stop if x-changes larger stopTolUpX. */
154     private double stopTolUpX;
155     /** Stop if x-change smaller stopTolX. */
156     private double stopTolX;
157     /** Stop if fun-changes smaller stopTolFun. */
158     private double stopTolFun;
159     /** Stop if back fun-changes smaller stopTolHistFun. */
160     private double stopTolHistFun;
161 
162     // selection strategy parameters
163     /** Number of parents/points for recombination. */
164     private int mu; //
165     /** log(mu + 0.5), stored for efficiency. */
166     private double logMu2;
167     /** Array for weighted recombination. */
168     private RealMatrix weights;
169     /** Variance-effectiveness of sum w_i x_i. */
170     private double mueff; //
171 
172     // dynamic strategy parameters and constants
173     /** Overall standard deviation - search volume. */
174     private double sigma;
175     /** Cumulation constant. */
176     private double cc;
177     /** Cumulation constant for step-size. */
178     private double cs;
179     /** Damping for step-size. */
180     private double damps;
181     /** Learning rate for rank-one update. */
182     private double ccov1;
183     /** Learning rate for rank-mu update' */
184     private double ccovmu;
185     /** Expectation of ||N(0,I)|| == norm(randn(N,1)). */
186     private double chiN;
187     /** Learning rate for rank-one update - diagonalOnly */
188     private double ccov1Sep;
189     /** Learning rate for rank-mu update - diagonalOnly */
190     private double ccovmuSep;
191 
192     // CMA internal values - updated each generation
193     /** Objective variables. */
194     private RealMatrix xmean;
195     /** Evolution path. */
196     private RealMatrix pc;
197     /** Evolution path for sigma. */
198     private RealMatrix ps;
199     /** Norm of ps, stored for efficiency. */
200     private double normps;
201     /** Coordinate system. */
202     private RealMatrix B;
203     /** Scaling. */
204     private RealMatrix D;
205     /** B*D, stored for efficiency. */
206     private RealMatrix BD;
207     /** Diagonal of sqrt(D), stored for efficiency. */
208     private RealMatrix diagD;
209     /** Covariance matrix. */
210     private RealMatrix C;
211     /** Diagonal of C, used for diagonalOnly. */
212     private RealMatrix diagC;
213     /** Number of iterations already performed. */
214     private int iterations;
215 
216     /** History queue of best values. */
217     private double[] fitnessHistory;
218     /** Size of history queue of best values. */
219     private int historySize;
220 
221     /** Random generator. */
222     private RandomGenerator random;
223 
224     /** History of sigma values. */
225     private List<Double> statisticsSigmaHistory = new ArrayList<Double>();
226     /** History of mean matrix. */
227     private List<RealMatrix> statisticsMeanHistory = new ArrayList<RealMatrix>();
228     /** History of fitness values. */
229     private List<Double> statisticsFitnessHistory = new ArrayList<Double>();
230     /** History of D matrix. */
231     private List<RealMatrix> statisticsDHistory = new ArrayList<RealMatrix>();
232 
233     /**
234      * Default constructor, uses default parameters
235      */
236     public CMAESOptimizer() {
237         this(0);
238     }
239 
240     /**
241      * @param lambda
242      *            Population size.
243      */
244     public CMAESOptimizer(int lambda) {
245         this(lambda, null, null, DEFAULT_MAXITERATIONS, DEFAULT_STOPFITNESS,
246                 DEFAULT_ISACTIVECMA, DEFAULT_DIAGONALONLY,
247                 DEFAULT_CHECKFEASABLECOUNT, DEFAULT_RANDOMGENERATOR, false);
248     }
249 
250     /**
251      * @param lambda
252      *            Population size.
253      * @param inputSigma
254      *            Initial search volume - sigma of offspring objective
255      *            variables.
256      * @param boundaries
257      *            Boundaries for objective variables.
258      */
259     public CMAESOptimizer(int lambda, double[] inputSigma,
260             double[][] boundaries) {
261         this(lambda, inputSigma, boundaries, DEFAULT_MAXITERATIONS, DEFAULT_STOPFITNESS,
262                 DEFAULT_ISACTIVECMA, DEFAULT_DIAGONALONLY,
263                 DEFAULT_CHECKFEASABLECOUNT, DEFAULT_RANDOMGENERATOR, false);
264     }
265 
266     /**
267      * @param lambda
268      *            Population size.
269      * @param inputSigma
270      *            Initial search volume - sigma of offspring objective
271      *            variables.
272      * @param boundaries
273      *            Boundaries for objective variables.
274      * @param maxIterations
275      *            Maximal number of iterations.
276      * @param stopfitness
277      *            stop if objective function value < stopfitness.
278      * @param isActiveCMA
279      *            Chooses the covariance matrix update method.
280      * @param diagonalOnly
281      *            Number of initial iterations, where the covariance matrix
282      *            remains diagonal.
283      * @param checkFeasableCount
284      *            Determines how often new. random objective variables are
285      *            generated in case they are out of bounds.
286      * @param random
287      *            Used random generator.
288      * @param generateStatistics
289      *            Indicates whether statistic data is collected.
290      */
291     public CMAESOptimizer(int lambda, double[] inputSigma,
292             double[][] boundaries, int maxIterations, double stopfitness,
293             boolean isActiveCMA, int diagonalOnly, int checkFeasableCount,
294             RandomGenerator random, boolean generateStatistics) {
295         this.lambda = lambda;
296         this.inputSigma = inputSigma == null ? null : (double[]) inputSigma.clone();
297         if (boundaries == null) {
298             this.boundaries = null;
299         } else {
300             final int len = boundaries.length;
301             this.boundaries = new double[len][];
302             for (int i = 0; i < len; i++) {
303                 this.boundaries[i] =
304                     boundaries[i] == null ? null : (double[]) boundaries[i].clone();
305             }
306         }
307         this.maxIterations = maxIterations;
308         this.stopfitness = stopfitness;
309         this.isActiveCMA = isActiveCMA;
310         this.diagonalOnly = diagonalOnly;
311         this.checkFeasableCount = checkFeasableCount;
312         this.random = random;
313         this.generateStatistics = generateStatistics;
314     }
315 
316     /**
317      * @return History of sigma values.
318      */
319     public List<Double> getStatisticsSigmaHistory() {
320         return statisticsSigmaHistory;
321     }
322 
323     /**
324      * @return History of mean matrix.
325      */
326     public List<RealMatrix> getStatisticsMeanHistory() {
327         return statisticsMeanHistory;
328     }
329 
330     /**
331      * @return History of fitness values.
332      */
333     public List<Double> getStatisticsFitnessHistory() {
334         return statisticsFitnessHistory;
335     }
336 
337     /**
338      * @return History of D matrix.
339      */
340     public List<RealMatrix> getStatisticsDHistory() {
341         return statisticsDHistory;
342     }
343 
344     /** {@inheritDoc} */
345     @Override
346     protected RealPointValuePair doOptimize() {
347         checkParameters();
348          // -------------------- Initialization --------------------------------
349         isMinimize = getGoalType().equals(GoalType.MINIMIZE);
350         final FitnessFunction fitfun = new FitnessFunction();
351         final double[] guess = fitfun.encode(getStartPoint());
352         // number of objective variables/problem dimension
353         dimension = guess.length;
354         initializeCMA(guess);
355         iterations = 0;
356         double bestValue = fitfun.value(guess);
357         push(fitnessHistory, bestValue);
358         RealPointValuePair optimum = new RealPointValuePair(getStartPoint(),
359                 isMinimize ? bestValue : -bestValue);
360         RealPointValuePair lastResult = null;
361 
362         // -------------------- Generation Loop --------------------------------
363 
364         generationLoop:
365             for (iterations = 1; iterations <= maxIterations; iterations++) {
366                 // Generate and evaluate lambda offspring
367                 RealMatrix arz = randn1(dimension, lambda);
368                 RealMatrix arx = zeros(dimension, lambda);
369                 double[] fitness = new double[lambda];
370                 // generate random offspring
371                 for (int k = 0; k < lambda; k++) {
372                     RealMatrix arxk = null;
373                     for (int i = 0; i < checkFeasableCount+1; i++) {
374                         if (diagonalOnly <= 0) {
375                             arxk = xmean.add(BD.multiply(arz.getColumnMatrix(k))
376                                     .scalarMultiply(sigma)); // m + sig * Normal(0,C)
377                         } else {
378                             arxk = xmean.add(times(diagD,arz.getColumnMatrix(k))
379                                     .scalarMultiply(sigma));
380                         }
381                         if (i >= checkFeasableCount || fitfun.isFeasible(arxk.getColumn(0))) {
382                             break;
383                         }
384                         // regenerate random arguments for row
385                         arz.setColumn(k, randn(dimension));
386                     }
387                     copyColumn(arxk, 0, arx, k);
388                     try {
389                         fitness[k] = fitfun.value(arx.getColumn(k)); // compute fitness
390                     } catch (TooManyEvaluationsException e) {
391                         break generationLoop;
392                     }
393                 }
394                 // Sort by fitness and compute weighted mean into xmean
395                 int[] arindex = sortedIndices(fitness);
396                 // Calculate new xmean, this is selection and recombination
397                 RealMatrix xold = xmean; // for speed up of Eq. (2) and (3)
398                 RealMatrix bestArx = selectColumns(arx, MathArrays.copyOf(arindex, mu));
399                 xmean = bestArx.multiply(weights);
400                 RealMatrix bestArz = selectColumns(arz, MathArrays.copyOf(arindex, mu));
401                 RealMatrix zmean = bestArz.multiply(weights);
402                 boolean hsig = updateEvolutionPaths(zmean, xold);
403                 if (diagonalOnly <= 0) {
404                     updateCovariance(hsig, bestArx, arz, arindex, xold);
405                 } else {
406                     updateCovarianceDiagonalOnly(hsig, bestArz, xold);
407                 }
408                 // Adapt step size sigma - Eq. (5)
409                 sigma *= Math.exp(Math.min(1.0,(normps/chiN - 1.)*cs/damps));
410                 double bestFitness = fitness[arindex[0]];
411                 double worstFitness = fitness[arindex[arindex.length-1]];
412                 if (bestValue > bestFitness) {
413                     bestValue = bestFitness;
414                     lastResult = optimum;
415                     optimum = new RealPointValuePair(
416                             fitfun.decode(bestArx.getColumn(0)),
417                             isMinimize ? bestFitness : -bestFitness);
418                     if (getConvergenceChecker() != null && lastResult != null) {
419                         if (getConvergenceChecker().converged(iterations, optimum, lastResult)) {
420                             break generationLoop;
421                         }
422                     }
423                 }
424                 // handle termination criteria
425                 // Break, if fitness is good enough
426                 if (stopfitness != 0) { // only if stopfitness is defined
427                     if (bestFitness < (isMinimize ? stopfitness : -stopfitness)) {
428                         break generationLoop;
429                     }
430                 }
431                 double[] sqrtDiagC = sqrt(diagC).getColumn(0);
432                 double[] pcCol = pc.getColumn(0);
433                 for (int i = 0; i < dimension; i++) {
434                     if (sigma*(Math.max(Math.abs(pcCol[i]), sqrtDiagC[i])) > stopTolX) {
435                         break;
436                     }
437                     if (i >= dimension-1) {
438                         break generationLoop;
439                     }
440                 }
441                 for (int i = 0; i < dimension; i++) {
442                     if (sigma*sqrtDiagC[i] > stopTolUpX) {
443                         break generationLoop;
444                     }
445                 }
446                 double historyBest = min(fitnessHistory);
447                 double historyWorst = max(fitnessHistory);
448                 if (iterations > 2 && Math.max(historyWorst, worstFitness) -
449                         Math.min(historyBest, bestFitness) < stopTolFun) {
450                     break generationLoop;
451                 }
452                 if (iterations > fitnessHistory.length &&
453                         historyWorst-historyBest < stopTolHistFun) {
454                     break generationLoop;
455                 }
456                 // condition number of the covariance matrix exceeds 1e14
457                 if (max(diagD)/min(diagD) > 1e7) {
458                     break generationLoop;
459                 }
460                 // user defined termination
461                 if (getConvergenceChecker() != null) {
462                     RealPointValuePair current =
463                         new RealPointValuePair(bestArx.getColumn(0),
464                                 isMinimize ? bestFitness : -bestFitness);
465                     if (lastResult != null &&
466                         getConvergenceChecker().converged(iterations, current, lastResult)) {
467                         break generationLoop;
468                     }
469                     lastResult = current;
470                 }
471                 // Adjust step size in case of equal function values (flat fitness)
472                 if (bestValue == fitness[arindex[(int)(0.1+lambda/4.)]]) {
473                     sigma = sigma * Math.exp(0.2+cs/damps);
474                 }
475                 if (iterations > 2 && Math.max(historyWorst, bestFitness) -
476                         Math.min(historyBest, bestFitness) == 0) {
477                     sigma = sigma * Math.exp(0.2+cs/damps);
478                 }
479                 // store best in history
480                 push(fitnessHistory,bestFitness);
481                 fitfun.setValueRange(worstFitness-bestFitness);
482                 if (generateStatistics) {
483                     statisticsSigmaHistory.add(sigma);
484                     statisticsFitnessHistory.add(bestFitness);
485                     statisticsMeanHistory.add(xmean.transpose());
486                     statisticsDHistory.add(diagD.transpose().scalarMultiply(1E5));
487                 }
488             }
489         return optimum;
490     }
491 
492     /**
493      * Checks dimensions and values of boundaries and inputSigma if defined.
494      */
495     private void checkParameters() {
496         double[] init = getStartPoint();
497         if (boundaries != null) {
498             if (boundaries.length != 2) {
499                 throw new MultiDimensionMismatchException(
500                         new Integer[] { boundaries.length },
501                         new Integer[] { 2 });
502             }
503             if (boundaries[0] == null || boundaries[1] == null) {
504                 throw new NoDataException();
505             }
506             if (boundaries[0].length != init.length) {
507                 throw new MultiDimensionMismatchException(
508                         new Integer[] { boundaries[0].length },
509                         new Integer[] { init.length });
510             }
511             if (boundaries[1].length != init.length) {
512                 throw new MultiDimensionMismatchException(
513                         new Integer[] { boundaries[1].length },
514                         new Integer[] { init.length });
515             }
516             for (int i = 0; i < init.length; i++) {
517                 if (boundaries[0][i] > init[i] || boundaries[1][i] < init[i]) {
518                     throw new OutOfRangeException(init[i], boundaries[0][i],
519                             boundaries[1][i]);
520                 }
521             }
522         }
523         if (inputSigma != null) {
524             if (inputSigma.length != init.length) {
525                 throw new MultiDimensionMismatchException(
526                         new Integer[] { inputSigma.length },
527                         new Integer[] { init.length });
528             }
529             for (int i = 0; i < init.length; i++) {
530                 if (inputSigma[i] < 0) {
531                     throw new NotPositiveException(inputSigma[i]);
532                 }
533                 if (boundaries != null) {
534                     if (inputSigma[i] > 1.0) {
535                         throw new OutOfRangeException(inputSigma[i], 0, 1.0);
536                     }
537                 }
538             }
539         }
540     }
541 
542     /**
543      * Initialization of the dynamic search parameters
544      *
545      * @param guess
546      *            initial guess for the arguments of the fitness function
547      */
548 
549     private void initializeCMA(double[] guess) {
550         if (lambda <= 0) {
551             lambda = 4 + (int) (3. * Math.log(dimension));
552         }
553         // initialize sigma
554         double[][] sigmaArray = new double[guess.length][1];
555         for (int i = 0; i < guess.length; i++) {
556             sigmaArray[i][0] = inputSigma != null ? inputSigma[i] : 0.3;
557         }
558         RealMatrix insigma = new Array2DRowRealMatrix(sigmaArray, false);
559         sigma = max(insigma); // overall standard deviation
560 
561         // initialize termination criteria
562         stopTolUpX = 1e3 * max(insigma);
563         stopTolX = 1e-11 * max(insigma);
564         stopTolFun = 1e-12;
565         stopTolHistFun = 1e-13;
566 
567         // initialize selection strategy parameters
568         mu = lambda / 2; // number of parents/points for recombination
569         logMu2 = Math.log(mu + 0.5);
570         weights = log(sequence(1, mu, 1)).scalarMultiply(-1.).scalarAdd(logMu2);
571         double sumw = 0;
572         double sumwq = 0;
573         for (int i = 0; i < mu; i++) {
574             double w = weights.getEntry(i, 0);
575             sumw += w;
576             sumwq += w * w;
577         }
578         weights = weights.scalarMultiply(1. / sumw);
579         mueff = sumw * sumw / sumwq; // variance-effectiveness of sum w_i x_i
580 
581         // initialize dynamic strategy parameters and constants
582         cc = (4. + mueff / dimension) /
583                 (dimension + 4. + 2. * mueff / dimension);
584         cs = (mueff + 2.) / (dimension + mueff + 3.);
585         damps = (1. + 2. * Math.max(0, Math.sqrt((mueff - 1.) /
586                 (dimension + 1.)) - 1.)) *
587                 Math.max(0.3, 1. - dimension /
588                         (1e-6 + Math.min(maxIterations, getMaxEvaluations() /
589                                 lambda))) + cs; // minor increment
590         ccov1 = 2. / ((dimension + 1.3) * (dimension + 1.3) + mueff);
591         ccovmu = Math.min(1 - ccov1, 2. * (mueff - 2. + 1. / mueff) /
592                 ((dimension + 2.) * (dimension + 2.) + mueff));
593         ccov1Sep = Math.min(1, ccov1 * (dimension + 1.5) / 3.);
594         ccovmuSep = Math.min(1 - ccov1, ccovmu * (dimension + 1.5) / 3.);
595         chiN = Math.sqrt(dimension) *
596                 (1. - 1. / (4. * dimension) + 1 / (21. * dimension * dimension));
597         // intialize CMA internal values - updated each generation
598         xmean = MatrixUtils.createColumnRealMatrix(guess); // objective
599                                                            // variables
600         diagD = insigma.scalarMultiply(1. / sigma);
601         diagC = square(diagD);
602         pc = zeros(dimension, 1); // evolution paths for C and sigma
603         ps = zeros(dimension, 1); // B defines the coordinate system
604         normps = ps.getFrobeniusNorm();
605 
606         B = eye(dimension, dimension);
607         D = ones(dimension, 1); // diagonal D defines the scaling
608         BD = times(B, repmat(diagD.transpose(), dimension, 1));
609         C = B.multiply(diag(square(D)).multiply(B.transpose())); // covariance
610         historySize = 10 + (int) (3. * 10. * dimension / lambda);
611         fitnessHistory = new double[historySize]; // history of fitness values
612         for (int i = 0; i < historySize; i++) {
613             fitnessHistory[i] = Double.MAX_VALUE;
614         }
615     }
616 
617     /**
618      * Update of the evolution paths ps and pc
619      *
620      * @param zmean
621      *            weighted row matrix of the gaussian random numbers generating
622      *            the current offspring
623      * @param xold
624      *            xmean matrix of the previous generation
625      * @return hsig flag indicating a small correction
626      */
627     private boolean updateEvolutionPaths(RealMatrix zmean, RealMatrix xold) {
628         ps = ps.scalarMultiply(1. - cs).add(
629                 B.multiply(zmean).scalarMultiply(
630                         Math.sqrt(cs * (2. - cs) * mueff)));
631         normps = ps.getFrobeniusNorm();
632         boolean hsig = normps /
633             Math.sqrt(1. - Math.pow(1. - cs, 2. * iterations)) /
634                 chiN < 1.4 + 2. / (dimension + 1.);
635         pc = pc.scalarMultiply(1. - cc);
636         if (hsig) {
637             pc = pc.add(xmean.subtract(xold).scalarMultiply(
638                     Math.sqrt(cc * (2. - cc) * mueff) / sigma));
639         }
640         return hsig;
641     }
642 
643     /**
644      * Update of the covariance matrix C for diagonalOnly > 0
645      *
646      * @param hsig
647      *            flag indicating a small correction
648      * @param bestArz
649      *            fitness-sorted matrix of the gaussian random values of the
650      *            current offspring
651      * @param xold
652      *            xmean matrix of the previous generation
653      */
654     private void updateCovarianceDiagonalOnly(boolean hsig, final RealMatrix bestArz,
655             final RealMatrix xold) {
656         // minor correction if hsig==false
657         double oldFac = hsig ? 0 : ccov1Sep * cc * (2. - cc);
658         oldFac += 1. - ccov1Sep - ccovmuSep;
659         diagC = diagC.scalarMultiply(oldFac) // regard old matrix
660                 // plus rank one update
661                 .add(square(pc).scalarMultiply(ccov1Sep))
662                 // plus rank mu update
663                 .add((times(diagC, square(bestArz).multiply(weights)))
664                         .scalarMultiply(ccovmuSep));
665         diagD = sqrt(diagC); // replaces eig(C)
666         if (diagonalOnly > 1 && iterations > diagonalOnly) {
667             // full covariance matrix from now on
668             diagonalOnly = 0;
669             B = eye(dimension, dimension);
670             BD = diag(diagD);
671             C = diag(diagC);
672         }
673     }
674 
675     /**
676      * Update of the covariance matrix C
677      *
678      * @param hsig
679      *            flag indicating a small correction
680      * @param bestArx
681      *            fitness-sorted matrix of the argument vectors producing the
682      *            current offspring
683      * @param arz
684      *            unsorted matrix containing the gaussian random values of the
685      *            current offspring
686      * @param arindex
687      *            indices indicating the fitness-order of the current offspring
688      * @param xold
689      *            xmean matrix of the previous generation
690      */
691     private void updateCovariance(boolean hsig, final RealMatrix bestArx,
692             final RealMatrix arz, final int[] arindex, final RealMatrix xold) {
693         double negccov = 0;
694         if (ccov1 + ccovmu > 0) {
695             RealMatrix arpos = bestArx.subtract(repmat(xold, 1, mu))
696                     .scalarMultiply(1. / sigma); // mu difference vectors
697             RealMatrix roneu = pc.multiply(pc.transpose())
698                     .scalarMultiply(ccov1); // rank one update
699             // minor correction if hsig==false
700             double oldFac = hsig ? 0 : ccov1 * cc * (2. - cc);
701             oldFac += 1. - ccov1 - ccovmu;
702             if (isActiveCMA) {
703                 // Adapt covariance matrix C active CMA
704                 negccov = (1. - ccovmu) * 0.25 * mueff /
705                 (Math.pow(dimension + 2., 1.5) + 2. * mueff);
706                 double negminresidualvariance = 0.66;
707                 // keep at least 0.66 in all directions, small popsize are most
708                 // critical
709                 double negalphaold = 0.5; // where to make up for the variance
710                                           // loss,
711                 // prepare vectors, compute negative updating matrix Cneg
712                 int[] arReverseIndex = reverse(arindex);
713                 RealMatrix arzneg
714                     = selectColumns(arz, MathArrays.copyOf(arReverseIndex, mu));
715                 RealMatrix arnorms = sqrt(sumRows(square(arzneg)));
716                 int[] idxnorms = sortedIndices(arnorms.getRow(0));
717                 RealMatrix arnormsSorted = selectColumns(arnorms, idxnorms);
718                 int[] idxReverse = reverse(idxnorms);
719                 RealMatrix arnormsReverse = selectColumns(arnorms, idxReverse);
720                 arnorms = divide(arnormsReverse, arnormsSorted);
721                 int[] idxInv = inverse(idxnorms);
722                 RealMatrix arnormsInv = selectColumns(arnorms, idxInv);
723                 // check and set learning rate negccov
724                 double negcovMax = (1. - negminresidualvariance) /
725                         square(arnormsInv).multiply(weights).getEntry(0, 0);
726                 if (negccov > negcovMax) {
727                     negccov = negcovMax;
728                 }
729                 arzneg = times(arzneg, repmat(arnormsInv, dimension, 1));
730                 RealMatrix artmp = BD.multiply(arzneg);
731                 RealMatrix Cneg = artmp.multiply(diag(weights)).multiply(
732                         artmp.transpose());
733                 oldFac += negalphaold * negccov;
734                 C = C.scalarMultiply(oldFac)
735                         // regard old matrix
736                         .add(roneu)
737                         // plus rank one update
738                         .add(arpos.scalarMultiply(
739                                 // plus rank mu update
740                                 ccovmu + (1. - negalphaold) * negccov)
741                                 .multiply(
742                                         times(repmat(weights, 1, dimension),
743                                                 arpos.transpose())))
744                         .subtract(Cneg.scalarMultiply(negccov));
745             } else {
746                 // Adapt covariance matrix C - nonactive
747                 C = C.scalarMultiply(oldFac) // regard old matrix
748                         .add(roneu)
749                         // plus rank one update
750                         .add(arpos.scalarMultiply(ccovmu) // plus rank mu update
751                                 .multiply(
752                                         times(repmat(weights, 1, dimension),
753                                                 arpos.transpose())));
754             }
755         }
756         updateBD(negccov);
757     }
758 
759     /**
760      * Update B and D from C
761      *
762      * @param negccov
763      *            Negative covariance factor.
764      */
765     private void updateBD(double negccov) {
766         if (ccov1 + ccovmu + negccov > 0 &&
767                 (iterations % 1. / (ccov1 + ccovmu + negccov) / dimension / 10.) < 1.) {
768             // to achieve O(N^2)
769             C = triu(C, 0).add(triu(C, 1).transpose());
770             // enforce symmetry to prevent complex numbers
771             EigenDecomposition eig = new EigenDecomposition(C, 1.0);
772             B = eig.getV(); // eigen decomposition, B==normalized eigenvectors
773             D = eig.getD();
774             diagD = diag(D);
775             if (min(diagD) <= 0) {
776                 for (int i = 0; i < dimension; i++) {
777                     if (diagD.getEntry(i, 0) < 0) {
778                         diagD.setEntry(i, 0, 0.);
779                     }
780                 }
781                 double tfac = max(diagD) / 1e14;
782                 C = C.add(eye(dimension, dimension).scalarMultiply(tfac));
783                 diagD = diagD.add(ones(dimension, 1).scalarMultiply(tfac));
784             }
785             if (max(diagD) > 1e14 * min(diagD)) {
786                 double tfac = max(diagD) / 1e14 - min(diagD);
787                 C = C.add(eye(dimension, dimension).scalarMultiply(tfac));
788                 diagD = diagD.add(ones(dimension, 1).scalarMultiply(tfac));
789             }
790             diagC = diag(C);
791             diagD = sqrt(diagD); // D contains standard deviations now
792             BD = times(B, repmat(diagD.transpose(), dimension, 1)); // O(n^2)
793         }
794     }
795 
796     /**
797      * Pushes the current best fitness value in a history queue.
798      *
799      * @param vals
800      *            the history queue
801      * @param val
802      *            current best fitness value
803      */
804     private static void push(double[] vals, double val) {
805         for (int i = vals.length-1; i > 0; i--) {
806             vals[i] = vals[i-1];
807         }
808         vals[0] = val;
809     }
810 
811     /**
812      * Sorts fitness values.
813      *
814      * @param doubles
815      *            array of values to be sorted
816      * @return sorted array of indices pointing into doubles
817      */
818     private int[] sortedIndices(final double[] doubles) {
819         DoubleIndex[] dis = new DoubleIndex[doubles.length];
820         for (int i = 0; i < doubles.length; i++) {
821             dis[i] = new DoubleIndex(doubles[i], i);
822         }
823         Arrays.sort(dis);
824         int[] indices = new int[doubles.length];
825         for (int i = 0; i < doubles.length; i++) {
826             indices[i] = dis[i].index;
827         }
828         return indices;
829     }
830 
831     /**
832      * Used to sort fitness values. Sorting is always in lower value first
833      * order.
834      */
835     private static class DoubleIndex implements Comparable<DoubleIndex> {
836 
837         /** Value to compare. */
838         private double value;
839         /** Index into sorted array. */
840         private int index;
841 
842         /**
843          * @param value
844          *            Value to compare.
845          * @param index
846          *            Index into sorted array.
847          */
848         DoubleIndex(double value, int index) {
849             this.value = value;
850             this.index = index;
851         }
852 
853         /** {@inheritDoc} */
854         public int compareTo(DoubleIndex o) {
855             return Double.compare(value, o.value);
856         }
857 
858         /** {@inheritDoc} */
859         @Override
860         public boolean equals(Object other) {
861 
862             if (this == other) {
863                 return true;
864             }
865 
866             if (other instanceof DoubleIndex) {
867                 return Double.compare(value, ((DoubleIndex) other).value) == 0;
868             }
869 
870             return false;
871 
872         }
873 
874         /** {@inheritDoc} */
875         @Override
876         public int hashCode() {
877             long bits = Double.doubleToLongBits(value);
878             return (int) ((1438542 ^ (bits >>> 32) ^ bits) & 0xffffffff);
879         }
880 
881     }
882 
883     /**
884      * Normalizes fitness values to the range [0,1]. Adds a penalty to the
885      * fitness value if out of range. The penalty is adjusted by calling
886      * setValueRange().
887      */
888     private class FitnessFunction {
889 
890         /** Determines the penalty for boundary violations */
891         private double valueRange;
892         /**
893          * Flag indicating whether the objective variables are forced into their
894          * bounds if defined
895          */
896         private boolean isRepairMode;
897 
898         /** Simple constructor.
899          */
900         public FitnessFunction() {
901             valueRange = 1.0;
902             isRepairMode = true;
903         }
904 
905         /**
906          * @param x
907          *            Original objective variables.
908          * @return Normalized objective variables.
909          */
910         public double[] encode(final double[] x) {
911             if (boundaries == null) {
912                 return x;
913             }
914             double[] res = new double[x.length];
915             for (int i = 0; i < x.length; i++) {
916                 double diff = boundaries[1][i] - boundaries[0][i];
917                 res[i] = (x[i] - boundaries[0][i]) / diff;
918             }
919             return res;
920         }
921 
922         /**
923          * @param x
924          *            Normalized objective variables.
925          * @return Original objective variables.
926          */
927         public double[] decode(final double[] x) {
928             if (boundaries == null) {
929                 return x;
930             }
931             double[] res = new double[x.length];
932             for (int i = 0; i < x.length; i++) {
933                 double diff = boundaries[1][i] - boundaries[0][i];
934                 res[i] = diff * x[i] + boundaries[0][i];
935             }
936             return res;
937         }
938 
939         /**
940          * @param point
941          *            Normalized objective variables.
942          * @return Objective value + penalty for violated bounds.
943          */
944         public double value(final double[] point) {
945             double value;
946             if (boundaries != null && isRepairMode) {
947                 double[] repaired = repair(point);
948                 value = CMAESOptimizer.this
949                         .computeObjectiveValue(decode(repaired)) +
950                         penalty(point, repaired);
951             } else {
952                 value = CMAESOptimizer.this
953                         .computeObjectiveValue(decode(point));
954             }
955             return isMinimize ? value : -value;
956         }
957 
958         /**
959          * @param x
960          *            Normalized objective variables.
961          * @return True if in bounds
962          */
963         public boolean isFeasible(final double[] x) {
964             if (boundaries == null) {
965                 return true;
966             }
967             for (int i = 0; i < x.length; i++) {
968                 if (x[i] < 0) {
969                     return false;
970                 }
971                 if (x[i] > 1.0) {
972                     return false;
973                 }
974             }
975             return true;
976         }
977 
978         /**
979          * @param valueRange
980          *            Adjusts the penalty computation.
981          */
982         public void setValueRange(double valueRange) {
983             this.valueRange = valueRange;
984         }
985 
986         /**
987          * @param x
988          *            Normalized objective variables.
989          * @return Repaired objective variables - all in bounds.
990          */
991         private double[] repair(final double[] x) {
992             double[] repaired = new double[x.length];
993             for (int i = 0; i < x.length; i++) {
994                 if (x[i] < 0) {
995                     repaired[i] = 0;
996                 } else if (x[i] > 1.0) {
997                     repaired[i] = 1.0;
998                 } else {
999                     repaired[i] = x[i];
1000                 }
1001             }
1002             return repaired;
1003         }
1004 
1005         /**
1006          * @param x
1007          *            Normalized objective variables.
1008          * @param repaired
1009          *            Repaired objective variables.
1010          * @return Penalty value according to the violation of the bounds.
1011          */
1012         private double penalty(final double[] x, final double[] repaired) {
1013             double penalty = 0;
1014             for (int i = 0; i < x.length; i++) {
1015                 double diff = Math.abs(x[i] - repaired[i]);
1016                 penalty += diff * valueRange;
1017             }
1018             return isMinimize ? penalty : -penalty;
1019         }
1020     }
1021 
1022     // -----Matrix utility functions similar to the Matlab build in functions------
1023 
1024     /**
1025      * @param m
1026      *            Input matrix
1027      * @return Matrix representing the element wise logarithm of m.
1028      */
1029     private static RealMatrix log(final RealMatrix m) {
1030         double[][] d = new double[m.getRowDimension()][m.getColumnDimension()];
1031         for (int r = 0; r < m.getRowDimension(); r++) {
1032             for (int c = 0; c < m.getColumnDimension(); c++) {
1033                 d[r][c] = Math.log(m.getEntry(r, c));
1034             }
1035         }
1036         return new Array2DRowRealMatrix(d, false);
1037     }
1038 
1039     /**
1040      * @param m
1041      *            Input matrix
1042      * @return Matrix representing the element wise square root of m.
1043      */
1044     private static RealMatrix sqrt(final RealMatrix m) {
1045         double[][] d = new double[m.getRowDimension()][m.getColumnDimension()];
1046         for (int r = 0; r < m.getRowDimension(); r++) {
1047             for (int c = 0; c < m.getColumnDimension(); c++) {
1048                 d[r][c] = Math.sqrt(m.getEntry(r, c));
1049             }
1050         }
1051         return new Array2DRowRealMatrix(d, false);
1052     }
1053 
1054     /**
1055      * @param m Input matrix
1056      * @return Matrix representing the element wise square (^2) of m.
1057      */
1058     private static RealMatrix square(final RealMatrix m) {
1059         double[][] d = new double[m.getRowDimension()][m.getColumnDimension()];
1060         for (int r = 0; r < m.getRowDimension(); r++) {
1061             for (int c = 0; c < m.getColumnDimension(); c++) {
1062                 double e = m.getEntry(r, c);
1063                 d[r][c] = e * e;
1064             }
1065         }
1066         return new Array2DRowRealMatrix(d, false);
1067     }
1068 
1069     /**
1070      * @param m
1071      *            Input matrix 1.
1072      * @param n
1073      *            Input matrix 2.
1074      * @return Matrix where the elements of m and m are element wise multiplied.
1075      */
1076     private static RealMatrix times(final RealMatrix m, final RealMatrix n) {
1077         double[][] d = new double[m.getRowDimension()][m.getColumnDimension()];
1078         for (int r = 0; r < m.getRowDimension(); r++) {
1079             for (int c = 0; c < m.getColumnDimension(); c++) {
1080                 d[r][c] = m.getEntry(r, c)*n.getEntry(r, c);
1081             }
1082         }
1083         return new Array2DRowRealMatrix(d, false);
1084     }
1085 
1086     /**
1087      * @param m
1088      *            Input matrix 1.
1089      * @param n
1090      *            Input matrix 2.
1091      * @return Matrix where the elements of m and m are element wise divided.
1092      */
1093     private static RealMatrix divide(final RealMatrix m, final RealMatrix n) {
1094         double[][] d = new double[m.getRowDimension()][m.getColumnDimension()];
1095         for (int r = 0; r < m.getRowDimension(); r++) {
1096             for (int c = 0; c < m.getColumnDimension(); c++) {
1097                 d[r][c] = m.getEntry(r, c)/n.getEntry(r, c);
1098             }
1099         }
1100         return new Array2DRowRealMatrix(d, false);
1101     }
1102 
1103     /**
1104      * @param m Input matrix.
1105      * @param cols Columns to select.
1106      * @return Matrix representing the selected columns.
1107      */
1108     private static RealMatrix selectColumns(final RealMatrix m, final int[] cols) {
1109         double[][] d = new double[m.getRowDimension()][cols.length];
1110         for (int r = 0; r < m.getRowDimension(); r++) {
1111             for (int c = 0; c < cols.length; c++) {
1112                 d[r][c] = m.getEntry(r, cols[c]);
1113             }
1114         }
1115         return new Array2DRowRealMatrix(d, false);
1116     }
1117 
1118     /**
1119      * @param m Input matrix.
1120      * @param k diagonal position.
1121      * @return Upper triangular part of matrix.
1122      */
1123     private static RealMatrix triu(final RealMatrix m, int k) {
1124         double[][] d = new double[m.getRowDimension()][m.getColumnDimension()];
1125         for (int r = 0; r < m.getRowDimension(); r++) {
1126             for (int c = 0; c < m.getColumnDimension(); c++) {
1127                 d[r][c] = r <= c - k ? m.getEntry(r, c) : 0;
1128             }
1129         }
1130         return new Array2DRowRealMatrix(d, false);
1131     }
1132 
1133     /**
1134      * @param m
1135      *            Input matrix.
1136      * @return Row matrix representing the sums of the rows.
1137      */
1138     private static RealMatrix sumRows(final RealMatrix m) {
1139         double[][] d = new double[1][m.getColumnDimension()];
1140         for (int c = 0; c < m.getColumnDimension(); c++) {
1141             double sum = 0;
1142             for (int r = 0; r < m.getRowDimension(); r++) {
1143                 sum += m.getEntry(r, c);
1144             }
1145             d[0][c] = sum;
1146         }
1147         return new Array2DRowRealMatrix(d, false);
1148     }
1149 
1150     /**
1151      * @param m
1152      *            Input matrix.
1153      * @return Diagonal n X n matrix if m is a column matrix, Column matrix
1154      *         representing the diagonal if m is a nXn matrix.
1155      */
1156     private static RealMatrix diag(final RealMatrix m) {
1157         if (m.getColumnDimension() == 1) {
1158             double[][] d = new double[m.getRowDimension()][m.getRowDimension()];
1159             for (int i = 0; i < m.getRowDimension(); i++) {
1160                 d[i][i] = m.getEntry(i, 0);
1161             }
1162             return new Array2DRowRealMatrix(d, false);
1163         } else {
1164             double[][] d = new double[m.getRowDimension()][1];
1165             for (int i = 0; i < m.getColumnDimension(); i++) {
1166                 d[i][0] = m.getEntry(i, i);
1167             }
1168             return new Array2DRowRealMatrix(d, false);
1169         }
1170     }
1171 
1172     /**
1173      * Copies a column from m1 to m2.
1174      *
1175      * @param m1
1176      *            Source matrix 1.
1177      * @param col1
1178      *            Source column.
1179      * @param m2
1180      *            Target matrix.
1181      * @param col2
1182      *            Target column.
1183      */
1184     private static void copyColumn(final RealMatrix m1, int col1, RealMatrix m2, int col2) {
1185         for (int i = 0; i < m1.getRowDimension(); i++) {
1186             m2.setEntry(i, col2, m1.getEntry(i, col1));
1187         }
1188     }
1189 
1190     /**
1191      * @param n
1192      *            Number of rows.
1193      * @param m
1194      *            Number of columns.
1195      * @return n X m matrix of 1.0-values.
1196      */
1197     private static RealMatrix ones(int n, int m) {
1198         double[][] d = new double[n][m];
1199         for (int r = 0; r < n; r++) {
1200             Arrays.fill(d[r], 1.0);
1201         }
1202         return new Array2DRowRealMatrix(d, false);
1203     }
1204 
1205     /**
1206      * @param n
1207      *            Number of rows.
1208      * @param m
1209      *            Number of columns.
1210      * @return n X m matrix of 0.0-values, diagonal has values 1.0.
1211      */
1212     private static RealMatrix eye(int n, int m) {
1213         double[][] d = new double[n][m];
1214         for (int r = 0; r < n; r++) {
1215             if (r < m) {
1216                 d[r][r] = 1;
1217             }
1218         }
1219         return new Array2DRowRealMatrix(d, false);
1220     }
1221 
1222     /**
1223      * @param n
1224      *            Number of rows.
1225      * @param m
1226      *            Number of columns.
1227      * @return n X m matrix of 0.0-values.
1228      */
1229     private static RealMatrix zeros(int n, int m) {
1230         return new Array2DRowRealMatrix(n, m);
1231     }
1232 
1233     /**
1234      * @param mat
1235      *            Input matrix.
1236      * @param n
1237      *            Number of row replicates.
1238      * @param m
1239      *            Number of column replicates.
1240      * @return Matrix which replicates the input matrix in both directions.
1241      */
1242     private static RealMatrix repmat(final RealMatrix mat, int n, int m) {
1243         int rd = mat.getRowDimension();
1244         int cd = mat.getColumnDimension();
1245         double[][] d = new double[n * rd][m * cd];
1246         for (int r = 0; r < n * rd; r++) {
1247             for (int c = 0; c < m * cd; c++) {
1248                 d[r][c] = mat.getEntry(r % rd, c % cd);
1249             }
1250         }
1251         return new Array2DRowRealMatrix(d, false);
1252     }
1253 
1254     /**
1255      * @param start
1256      *            Start value.
1257      * @param end
1258      *            End value.
1259      * @param step
1260      *            Step size.
1261      * @return Sequence as column matrix.
1262      */
1263     private static RealMatrix sequence(double start, double end, double step) {
1264         int size = (int) ((end - start) / step + 1);
1265         double[][] d = new double[size][1];
1266         double value = start;
1267         for (int r = 0; r < size; r++) {
1268             d[r][0] = value;
1269             value += step;
1270         }
1271         return new Array2DRowRealMatrix(d, false);
1272     }
1273 
1274     /**
1275      * @param m
1276      *            Input matrix.
1277      * @return Maximum of matrix element values.
1278      */
1279     private static double max(final RealMatrix m) {
1280         double max = -Double.MAX_VALUE;
1281         for (int r = 0; r < m.getRowDimension(); r++) {
1282             for (int c = 0; c < m.getColumnDimension(); c++) {
1283                 double e = m.getEntry(r, c);
1284                 if (max < e) {
1285                     max = e;
1286                 }
1287             }
1288         }
1289         return max;
1290     }
1291 
1292     /**
1293      * @param m
1294      *            Input matrix.
1295      * @return Minimum of matrix element values.
1296      */
1297     private static double min(final RealMatrix m) {
1298         double min = Double.MAX_VALUE;
1299         for (int r = 0; r < m.getRowDimension(); r++) {
1300             for (int c = 0; c < m.getColumnDimension(); c++) {
1301                 double e = m.getEntry(r, c);
1302                 if (min > e) {
1303                     min = e;
1304                 }
1305             }
1306         }
1307         return min;
1308     }
1309 
1310     /**
1311      * @param m
1312      *            Input array.
1313      * @return Maximum of array values.
1314      */
1315     private static double max(final double[] m) {
1316         double max = -Double.MAX_VALUE;
1317         for (int r = 0; r < m.length; r++) {
1318             if (max < m[r]) {
1319                 max = m[r];
1320             }
1321         }
1322         return max;
1323     }
1324 
1325     /**
1326      * @param m
1327      *            Input array.
1328      * @return Minimum of array values.
1329      */
1330     private static double min(final double[] m) {
1331         double min = Double.MAX_VALUE;
1332         for (int r = 0; r < m.length; r++) {
1333             if (min > m[r]) {
1334                 min = m[r];
1335             }
1336         }
1337         return min;
1338     }
1339 
1340     /**
1341      * @param indices
1342      *            Input index array.
1343      * @return Inverse of the mapping defined by indices
1344      */
1345     private static int[] inverse(final int[] indices) {
1346         int[] inverse = new int[indices.length];
1347         for (int i = 0; i < indices.length; i++) {
1348             inverse[indices[i]] = i;
1349         }
1350         return inverse;
1351     }
1352 
1353     /**
1354      * @param indices
1355      *            Input index array.
1356      * @return Indices in inverse order (last is first)
1357      */
1358     private static int[] reverse(final int[] indices) {
1359         int[] reverse = new int[indices.length];
1360         for (int i = 0; i < indices.length; i++) {
1361             reverse[i] = indices[indices.length - i - 1];
1362         }
1363         return reverse;
1364     }
1365 
1366     /**
1367      * @param size
1368      *            Length of random array.
1369      * @return Array of gaussian random numbers.
1370      */
1371     private double[] randn(int size) {
1372         double[] randn = new double[size];
1373         for (int i = 0; i < size; i++) {
1374             randn[i] = random.nextGaussian();
1375         }
1376         return randn;
1377     }
1378 
1379     /**
1380      * @param size
1381      *            Number of rows.
1382      * @param popSize
1383      *            Population size.
1384      * @return 2-dimensional matrix of gaussian random numbers.
1385      */
1386     private RealMatrix randn1(int size, int popSize) {
1387         double[][] d = new double[size][popSize];
1388         for (int r = 0; r < size; r++) {
1389             for (int c = 0; c < popSize; c++) {
1390                 d[r][c] = random.nextGaussian();
1391             }
1392         }
1393         return new Array2DRowRealMatrix(d, false);
1394     }
1395 }
1396