#region License Information /* HeuristicLab * Copyright (C) 2002-2015 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.Linq; namespace HeuristicLab.Algorithms.CMAEvolutionStrategy { [Item("Terminator", "Decides if the algorithm should terminate or not.")] [StorableType("0DEE7C0B-08FD-47B4-A8D2-18626C5BFE47")] public class Terminator : Operator, IIterationBasedOperator, ISingleObjectiveOperator { protected OperatorParameter ContinueParameter { get { return (OperatorParameter)Parameters["Continue"]; } } protected OperatorParameter TerminateParameter { get { return (OperatorParameter)Parameters["Terminate"]; } } public IOperator Continue { get { return ContinueParameter.Value; } set { ContinueParameter.Value = value; } } public IOperator Terminate { get { return TerminateParameter.Value; } set { TerminateParameter.Value = value; } } public IValueLookupParameter MaximizationParameter { get { return (IValueLookupParameter)Parameters["Maximization"]; } } public ILookupParameter StrategyParametersParameter { get { return (ILookupParameter)Parameters["StrategyParameters"]; } } public ILookupParameter IterationsParameter { get { return (ILookupParameter)Parameters["Iterations"]; } } public IValueLookupParameter MaximumIterationsParameter { get { return (IValueLookupParameter)Parameters["MaximumIterations"]; } } public ILookupParameter EvaluatedSolutionsParameter { get { return (ILookupParameter)Parameters["EvaluatedSolutions"]; } } public IValueLookupParameter MaximumEvaluatedSolutionsParameter { get { return (IValueLookupParameter)Parameters["MaximumEvaluatedSolutions"]; } } public IScopeTreeLookupParameter QualityParameter { get { return (IScopeTreeLookupParameter)Parameters["Quality"]; } } public IValueLookupParameter TargetQualityParameter { get { return (IValueLookupParameter)Parameters["TargetQuality"]; } } public IValueLookupParameter MinimumQualityChangeParameter { get { return (IValueLookupParameter)Parameters["MinimumQualityChange"]; } } public IValueLookupParameter MinimumQualityHistoryChangeParameter { get { return (IValueLookupParameter)Parameters["MinimumQualityHistoryChange"]; } } public IValueLookupParameter MinimumStandardDeviationParameter { get { return (IValueLookupParameter)Parameters["MinimumStandardDeviation"]; } } public ILookupParameter InitialSigmaParameter { get { return (ILookupParameter)Parameters["InitialSigma"]; } } public IValueLookupParameter MaximumStandardDeviationChangeParameter { get { return (IValueLookupParameter)Parameters["MaximumStandardDeviationChange"]; } } public ILookupParameter DegenerateStateParameter { get { return (ILookupParameter)Parameters["DegenerateState"]; } } [StorableConstructor] protected Terminator(bool deserializing) : base(deserializing) { } protected Terminator(Terminator original, Cloner cloner) : base(original, cloner) { } public Terminator() { Parameters.Add(new OperatorParameter("Continue", "The operator that is executed if the stop conditions have not been met!")); Parameters.Add(new OperatorParameter("Terminate", "The operator that is executed if the stop conditions have been met!")); Parameters.Add(new ValueLookupParameter("Maximization", "True if the problem is to be maximized and false otherwise.")); Parameters.Add(new LookupParameter("StrategyParameters", "The CMA-ES strategy parameters.")); Parameters.Add(new LookupParameter("Iterations", "The number of iterations passed.")); Parameters.Add(new ValueLookupParameter("MaximumIterations", "The maximum number of iterations.")); Parameters.Add(new LookupParameter("EvaluatedSolutions", "The number of evaluated solutions.")); Parameters.Add(new ValueLookupParameter("MaximumEvaluatedSolutions", "The maximum number of evaluated solutions.")); Parameters.Add(new ScopeTreeLookupParameter("Quality", "The quality of the offspring.")); Parameters.Add(new ValueLookupParameter("TargetQuality", "(stopFitness) Surpassing this quality value terminates the algorithm.")); Parameters.Add(new ValueLookupParameter("MinimumQualityChange", "(stopTolFun) If the range of fitness values is less than a certain value the algorithm terminates (set to 0 or positive value to enable).")); Parameters.Add(new ValueLookupParameter("MinimumQualityHistoryChange", "(stopTolFunHist) If the range of fitness values is less than a certain value for a certain time the algorithm terminates (set to 0 or positive to enable).")); Parameters.Add(new ValueLookupParameter("MinimumStandardDeviation", "(stopTolXFactor) If the standard deviation falls below a certain value the algorithm terminates (set to 0 or positive to enable).")); Parameters.Add(new LookupParameter("InitialSigma", "The initial value for Sigma.")); Parameters.Add(new ValueLookupParameter("MaximumStandardDeviationChange", "(stopTolUpXFactor) If the standard deviation changes by a value larger than this parameter the algorithm stops (set to a value > 0 to enable).")); Parameters.Add(new LookupParameter("DegenerateState", "Whether the algorithm state has degenerated and should be terminated.")); } public override IDeepCloneable Clone(Cloner cloner) { return new Terminator(this, cloner); } public override IOperation Apply() { var terminateOp = Terminate != null ? ExecutionContext.CreateOperation(Terminate) : null; var degenerated = DegenerateStateParameter.ActualValue.Value; if (degenerated) return terminateOp; var iterations = IterationsParameter.ActualValue.Value; var maxIterations = MaximumIterationsParameter.ActualValue.Value; if (iterations >= maxIterations) return terminateOp; var evals = EvaluatedSolutionsParameter.ActualValue.Value; var maxEvals = MaximumEvaluatedSolutionsParameter.ActualValue.Value; if (evals >= maxEvals) return terminateOp; var maximization = MaximizationParameter.ActualValue.Value; var bestQuality = QualityParameter.ActualValue.First().Value; var targetQuality = TargetQualityParameter.ActualValue.Value; if (iterations > 1 && (maximization && bestQuality >= targetQuality || !maximization && bestQuality <= targetQuality)) return terminateOp; var sp = StrategyParametersParameter.ActualValue; var worstQuality = QualityParameter.ActualValue.Last().Value; var minHist = sp.QualityHistory.Min(); var maxHist = sp.QualityHistory.Max(); var change = Math.Max(maxHist, Math.Max(bestQuality, worstQuality)) - Math.Min(minHist, Math.Min(bestQuality, worstQuality)); var stopTolFun = MinimumQualityChangeParameter.ActualValue.Value; if (change <= stopTolFun) return terminateOp; if (iterations > sp.QualityHistorySize && maxHist - minHist <= MinimumQualityHistoryChangeParameter.ActualValue.Value) return terminateOp; double minSqrtdiagC = int.MaxValue, maxSqrtdiagC = int.MinValue; for (int i = 0; i < sp.C.GetLength(0); i++) { if (Math.Sqrt(sp.C[i, i]) < minSqrtdiagC) minSqrtdiagC = Math.Sqrt(sp.C[i, i]); if (Math.Sqrt(sp.C[i, i]) > maxSqrtdiagC) maxSqrtdiagC = Math.Sqrt(sp.C[i, i]); } var tolx = MinimumStandardDeviationParameter.ActualValue.Value; if (sp.Sigma * maxSqrtdiagC < tolx && sp.Sigma * sp.PC.Select(x => Math.Abs(x)).Max() < tolx) return terminateOp; var stopTolUpXFactor = MaximumStandardDeviationChangeParameter.ActualValue.Value; if (sp.Sigma * maxSqrtdiagC > stopTolUpXFactor * InitialSigmaParameter.ActualValue.Max()) return terminateOp; return Continue != null ? ExecutionContext.CreateOperation(Continue) : null; } } }