#region License Information /* HeuristicLab * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL) * * This file is part of HeuristicLab. * * HeuristicLab is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * HeuristicLab is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with HeuristicLab. If not, see . */ #endregion using HeuristicLab.Common; using HeuristicLab.Core; using HeuristicLab.Data; using HeuristicLab.Operators; using HeuristicLab.Optimization; using HeuristicLab.Parameters; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; using System; using System.Collections.Generic; using System.Linq; namespace HeuristicLab.Algorithms.CMAEvolutionStrategy { [Item("CMAInitializer", "Initializes the covariance matrix and step size variables.")] [StorableClass] public class CMAInitializer : SingleSuccessorOperator, ICMAInitializer, IIterationBasedOperator { public Type CMAType { get { return typeof(CMAParameters); } } #region Parameter Properties public IValueLookupParameter DimensionParameter { get { return (IValueLookupParameter)Parameters["Dimension"]; } } public IValueLookupParameter InitialSigmaParameter { get { return (IValueLookupParameter)Parameters["InitialSigma"]; } } public IValueLookupParameter SigmaBoundsParameter { get { return (IValueLookupParameter)Parameters["SigmaBounds"]; } } public ILookupParameter IterationsParameter { get { return (ILookupParameter)Parameters["Iterations"]; } } public IValueLookupParameter MaximumIterationsParameter { get { return (IValueLookupParameter)Parameters["MaximumIterations"]; } } public IValueLookupParameter InitialIterationsParameter { get { return (IValueLookupParameter)Parameters["InitialIterations"]; } } public ILookupParameter PopulationSizeParameter { get { return (ILookupParameter)Parameters["PopulationSize"]; } } public ILookupParameter MuParameter { get { return (ILookupParameter)Parameters["Mu"]; } } public ILookupParameter StrategyParametersParameter { get { return (ILookupParameter)Parameters["StrategyParameters"]; } } #endregion [StorableConstructor] protected CMAInitializer(bool deserializing) : base(deserializing) { } protected CMAInitializer(CMAInitializer original, Cloner cloner) : base(original, cloner) { } public CMAInitializer() : base() { Parameters.Add(new ValueLookupParameter("Dimension", "The problem dimension (N).")); Parameters.Add(new ValueLookupParameter("InitialSigma", "The initial value for Sigma (need to be > 0), can be single dimensioned or an array that should be equal to the size of the vector.")); Parameters.Add(new ValueLookupParameter("SigmaBounds", "The bounds for sigma value can be omitted, given as one value for all dimensions or a value for each dimension. First column specifies minimum, second column maximum value.")); Parameters.Add(new LookupParameter("Iterations", "The current iteration that is being processed.")); Parameters.Add(new ValueLookupParameter("MaximumIterations", "The maximum number of iterations to be processed.")); Parameters.Add(new ValueLookupParameter("InitialIterations", "The number of iterations that should be performed using the diagonal covariance matrix only.", new IntValue(0))); Parameters.Add(new LookupParameter("PopulationSize", "The population size (lambda).")); Parameters.Add(new LookupParameter("Mu", "Optional, the number of offspring considered for updating of the strategy parameters.")); Parameters.Add(new LookupParameter("StrategyParameters", "The strategy parameters for real-encoded CMA-ES.")); } public override IDeepCloneable Clone(Cloner cloner) { return new CMAInitializer(this, cloner); } public override IOperation Apply() { var N = DimensionParameter.ActualValue.Value; var lambda = PopulationSizeParameter.ActualValue.Value; var mu = MuParameter.ActualValue; var sp = new CMAParameters(); sp.Mu = mu == null ? (int)Math.Floor(lambda / 2.0) : mu.Value; sp.QualityHistorySize = 10 + 30 * N / lambda; sp.QualityHistory = new Queue(sp.QualityHistorySize + 1); var s = InitialSigmaParameter.ActualValue; if (s == null || s.Length == 0) throw new InvalidOperationException("Initial standard deviation (sigma) must be given."); var sigma = s.Max(); if (sigma <= 0) throw new InvalidOperationException("Initial standard deviation (sigma) must be > 0."); var pc = new double[N]; // evolution paths for C var ps = new double[N]; // evolution paths for sigma var B = new double[N, N]; // B defines the coordinate system var D = new double[N]; // diagonal D defines the scaling var C = new double[N, N]; // covariance matrix C var BDz = new double[N]; double minSqrtdiagC = int.MaxValue, maxSqrtdiagC = int.MinValue; for (int i = 0; i < N; i++) { B[i, i] = 1; if (s.Length == 1) D[i] = 1; else if (s.Length == N) D[i] = s[i] / sigma; else throw new InvalidOperationException("Initial standard deviation (sigma) must either contain only one value for all dimension or for every dimension."); if (D[i] <= 0) throw new InvalidOperationException("Initial standard deviation (sigma) values must all be > 0."); C[i, i] = D[i] * D[i]; if (Math.Sqrt(C[i, i]) < minSqrtdiagC) minSqrtdiagC = Math.Sqrt(C[i, i]); if (Math.Sqrt(C[i, i]) > maxSqrtdiagC) maxSqrtdiagC = Math.Sqrt(C[i, i]); } // ensure maximal and minimal standard deviations var sigmaBounds = SigmaBoundsParameter.ActualValue; if (sigmaBounds != null && sigmaBounds.Rows > 0) { for (int i = 0; i < N; i++) { var d = sigmaBounds[Math.Min(i, sigmaBounds.Rows - 1), 0]; if (d > sigma * minSqrtdiagC) sigma = d / minSqrtdiagC; } for (int i = 0; i < N; i++) { var d = sigmaBounds[Math.Min(i, sigmaBounds.Rows - 1), 1]; if (d > sigma * maxSqrtdiagC) sigma = d / maxSqrtdiagC; } } // end ensure ... // testAndCorrectNumerics double fac = 1; if (D.Max() < 1e-6) fac = 1.0 / D.Max(); else if (D.Min() > 1e4) fac = 1.0 / D.Min(); if (fac != 1.0) { sigma /= fac; for (int i = 0; i < N; i++) { pc[i] *= fac; D[i] *= fac; for (int j = 0; j < N; j++) C[i, j] *= fac * fac; } } // end testAndCorrectNumerics var initialIterations = InitialIterationsParameter.ActualValue; if (initialIterations == null) { initialIterations = new IntValue(0); } double maxD = D.Max(), minD = D.Min(); if (minD == 0) sp.AxisRatio = double.PositiveInfinity; else sp.AxisRatio = maxD / minD; sp.PC = pc; sp.PS = ps; sp.B = B; sp.D = D; sp.C = C; sp.BDz = BDz; sp.Sigma = sigma; if (sigmaBounds != null) { sp.SigmaBounds = new double[sigmaBounds.Rows, sigmaBounds.Columns]; for (int i = 0; i < sigmaBounds.Rows; i++) for (int j = 0; j < sigmaBounds.Columns; j++) sp.SigmaBounds[i, j] = sigmaBounds[i, j]; } sp.InitialIterations = initialIterations.Value; StrategyParametersParameter.ActualValue = sp; return base.Apply(); } } }