#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;
}
}
}