Free cookie consent management tool by TermsFeed Policy Generator

source: branches/MOCMAEvolutionStrategy/HeuristicLab.Algorithms.MOCMAEvolutionStrategy/3.3/MOCMASEvolutionStrategy.cs @ 14614

Last change on this file since 14614 was 14614, checked in by pfleck, 7 years ago

#2592

  • Fixed scale invariant initialization by changing the initial sigma to a DoubleArray for initializing the covariance matrix (similar to the CMA-ES).
  • Made the MO-CMA-ES pausable (although the algorithm state is not yet storable when paused).
File size: 29.7 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 * and the BEACON Center for the Study of Evolution in Action.
5 *
6 * This file is part of HeuristicLab.
7 *
8 * HeuristicLab is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * HeuristicLab is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
20 */
21#endregion
22
23using System;
24using System.Collections.Generic;
25using System.Linq;
26using System.Threading;
27using HeuristicLab.Algorithms.CMAEvolutionStrategy;
28using HeuristicLab.Analysis;
29using HeuristicLab.Common;
30using HeuristicLab.Core;
31using HeuristicLab.Data;
32using HeuristicLab.Encodings.RealVectorEncoding;
33using HeuristicLab.Optimization;
34using HeuristicLab.Parameters;
35using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
36using HeuristicLab.Problems.TestFunctions.MultiObjective;
37using HeuristicLab.Random;
38
39namespace HeuristicLab.Algorithms.MOCMAEvolutionStrategy {
40  [Item("MOCMAS Evolution Strategy (MOCMASES)", "A multi objective evolution strategy based on covariance matrix adaptation. Code is based on 'Covariance Matrix Adaptation for Multi - objective Optimization' by Igel, Hansen and Roth")]
41  [Creatable(CreatableAttribute.Categories.PopulationBasedAlgorithms, Priority = 210)]
42  [StorableClass]
43  public class MOCMASEvolutionStrategy : BasicAlgorithm {
44    public override Type ProblemType {
45      get { return typeof(MultiObjectiveBasicProblem<RealVectorEncoding>); }
46    }
47    public new MultiObjectiveBasicProblem<RealVectorEncoding> Problem {
48      get { return (MultiObjectiveBasicProblem<RealVectorEncoding>)base.Problem; }
49      set { base.Problem = value; }
50    }
51    public override bool SupportsPause {
52      get { return true; }
53    }
54
55    #region internal variables
56    private readonly IRandom random = new MersenneTwister();
57    private NormalDistributedRandom gauss;
58    private MOCMAESIndividual[] solutions;
59    private MOCMAESParameters internals;
60    #endregion
61
62    #region ParameterNames
63    private const string MaximumRuntimeName = "Maximum Runtime";
64    private const string SeedName = "Seed";
65    private const string SetSeedRandomlyName = "SetSeedRandomly";
66    private const string PopulationSizeName = "PopulationSize";
67    private const string MaximumGenerationsName = "MaximumGenerations";
68    private const string MaximumEvaluatedSolutionsName = "MaximumEvaluatedSolutions";
69    private const string InitialSigmaName = "InitialSigma";
70    private const string IndicatorName = "Indicator";
71
72    private const string EvaluationsResultName = "Evaluations";
73    private const string IterationsResultName = "Generations";
74    private const string TimetableResultName = "Timetable";
75    private const string HypervolumeResultName = "Hypervolume";
76    private const string GenerationalDistanceResultName = "Generational Distance";
77    private const string InvertedGenerationalDistanceResultName = "Inverted Generational Distance";
78    private const string CrowdingResultName = "Crowding";
79    private const string SpacingResultName = "Spacing";
80    private const string CurrentFrontResultName = "Pareto Front";
81    private const string BestHypervolumeResultName = "Best Hypervolume";
82    private const string BestKnownHypervolumeResultName = "Best known hypervolume";
83    private const string DifferenceToBestKnownHypervolumeResultName = "Absolute Distance to BestKnownHypervolume";
84    private const string ScatterPlotResultName = "ScatterPlot";
85
86    #endregion
87
88    #region ParameterProperties
89    public IFixedValueParameter<IntValue> MaximumRuntimeParameter {
90      get { return (IFixedValueParameter<IntValue>)Parameters[MaximumRuntimeName]; }
91    }
92    public IFixedValueParameter<IntValue> SeedParameter {
93      get { return (IFixedValueParameter<IntValue>)Parameters[SeedName]; }
94    }
95    public FixedValueParameter<BoolValue> SetSeedRandomlyParameter {
96      get { return (FixedValueParameter<BoolValue>)Parameters[SetSeedRandomlyName]; }
97    }
98    public IFixedValueParameter<IntValue> PopulationSizeParameter {
99      get { return (IFixedValueParameter<IntValue>)Parameters[PopulationSizeName]; }
100    }
101    public IFixedValueParameter<IntValue> MaximumGenerationsParameter {
102      get { return (IFixedValueParameter<IntValue>)Parameters[MaximumGenerationsName]; }
103    }
104    public IFixedValueParameter<IntValue> MaximumEvaluatedSolutionsParameter {
105      get { return (IFixedValueParameter<IntValue>)Parameters[MaximumEvaluatedSolutionsName]; }
106    }
107    public IValueParameter<DoubleArray> InitialSigmaParameter {
108      get { return (IValueParameter<DoubleArray>)Parameters[InitialSigmaName]; }
109    }
110    public IConstrainedValueParameter<IIndicator> IndicatorParameter {
111      get { return (IConstrainedValueParameter<IIndicator>)Parameters[IndicatorName]; }
112    }
113    #endregion
114
115    #region Properties
116    public int MaximumRuntime {
117      get { return MaximumRuntimeParameter.Value.Value; }
118      set { MaximumRuntimeParameter.Value.Value = value; }
119    }
120    public int Seed {
121      get { return SeedParameter.Value.Value; }
122      set { SeedParameter.Value.Value = value; }
123    }
124    public bool SetSeedRandomly {
125      get { return SetSeedRandomlyParameter.Value.Value; }
126      set { SetSeedRandomlyParameter.Value.Value = value; }
127    }
128    public int PopulationSize {
129      get { return PopulationSizeParameter.Value.Value; }
130      set { PopulationSizeParameter.Value.Value = value; }
131    }
132    public int MaximumGenerations {
133      get { return MaximumGenerationsParameter.Value.Value; }
134      set { MaximumGenerationsParameter.Value.Value = value; }
135    }
136    public int MaximumEvaluatedSolutions {
137      get { return MaximumEvaluatedSolutionsParameter.Value.Value; }
138      set { MaximumEvaluatedSolutionsParameter.Value.Value = value; }
139    }
140    public DoubleArray InitialSigma {
141      get { return InitialSigmaParameter.Value; }
142      set { InitialSigmaParameter.Value = value; }
143    }
144    public IIndicator Indicator {
145      get { return IndicatorParameter.Value; }
146      set { IndicatorParameter.Value = value; }
147    }
148
149
150    #endregion
151
152    #region ResultsProperties
153    private int ResultsEvaluations {
154      get { return ((IntValue)Results[EvaluationsResultName].Value).Value; }
155      set { ((IntValue)Results[EvaluationsResultName].Value).Value = value; }
156    }
157    private int ResultsIterations {
158      get { return ((IntValue)Results[IterationsResultName].Value).Value; }
159      set { ((IntValue)Results[IterationsResultName].Value).Value = value; }
160    }
161    #region Datatable
162    private DataTable ResultsQualities {
163      get { return (DataTable)Results[TimetableResultName].Value; }
164    }
165    private DataRow ResultsBestHypervolumeDataLine {
166      get { return ResultsQualities.Rows[BestHypervolumeResultName]; }
167    }
168    private DataRow ResultsHypervolumeDataLine {
169      get { return ResultsQualities.Rows[HypervolumeResultName]; }
170    }
171    private DataRow ResultsGenerationalDistanceDataLine {
172      get { return ResultsQualities.Rows[GenerationalDistanceResultName]; }
173    }
174    private DataRow ResultsInvertedGenerationalDistanceDataLine {
175      get { return ResultsQualities.Rows[InvertedGenerationalDistanceResultName]; }
176    }
177    private DataRow ResultsCrowdingDataLine {
178      get { return ResultsQualities.Rows[CrowdingResultName]; }
179    }
180    private DataRow ResultsSpacingDataLine {
181      get { return ResultsQualities.Rows[SpacingResultName]; }
182    }
183    private DataRow ResultsHypervolumeDifferenceDataLine {
184      get { return ResultsQualities.Rows[DifferenceToBestKnownHypervolumeResultName]; }
185    }
186    #endregion
187    //QualityIndicators
188    private double ResultsHypervolume {
189      get { return ((DoubleValue)Results[HypervolumeResultName].Value).Value; }
190      set { ((DoubleValue)Results[HypervolumeResultName].Value).Value = value; }
191    }
192    private double ResultsGenerationalDistance {
193      get { return ((DoubleValue)Results[GenerationalDistanceResultName].Value).Value; }
194      set { ((DoubleValue)Results[GenerationalDistanceResultName].Value).Value = value; }
195    }
196    private double ResultsInvertedGenerationalDistance {
197      get { return ((DoubleValue)Results[InvertedGenerationalDistanceResultName].Value).Value; }
198      set { ((DoubleValue)Results[InvertedGenerationalDistanceResultName].Value).Value = value; }
199    }
200    private double ResultsCrowding {
201      get { return ((DoubleValue)Results[CrowdingResultName].Value).Value; }
202      set { ((DoubleValue)Results[CrowdingResultName].Value).Value = value; }
203    }
204    private double ResultsSpacing {
205      get { return ((DoubleValue)Results[SpacingResultName].Value).Value; }
206      set { ((DoubleValue)Results[SpacingResultName].Value).Value = value; }
207    }
208    private double ResultsBestHypervolume {
209      get { return ((DoubleValue)Results[BestHypervolumeResultName].Value).Value; }
210      set { ((DoubleValue)Results[BestHypervolumeResultName].Value).Value = value; }
211    }
212    private double ResultsBestKnownHypervolume {
213      get { return ((DoubleValue)Results[BestKnownHypervolumeResultName].Value).Value; }
214      set { ((DoubleValue)Results[BestKnownHypervolumeResultName].Value).Value = value; }
215    }
216    private double ResultsDifferenceBestKnownHypervolume {
217      get { return ((DoubleValue)Results[DifferenceToBestKnownHypervolumeResultName].Value).Value; }
218      set { ((DoubleValue)Results[DifferenceToBestKnownHypervolumeResultName].Value).Value = value; }
219
220    }
221    //Solutions
222    private DoubleMatrix ResultsSolutions {
223      get { return ((DoubleMatrix)Results[CurrentFrontResultName].Value); }
224      set { Results[CurrentFrontResultName].Value = value; }
225    }
226    private ScatterPlotContent ResultsScatterPlot {
227      get { return ((ScatterPlotContent)Results[ScatterPlotResultName].Value); }
228      set { Results[ScatterPlotResultName].Value = value; }
229    }
230    #endregion
231
232    #region Constructors
233    public MOCMASEvolutionStrategy() {
234      Parameters.Add(new FixedValueParameter<IntValue>(MaximumRuntimeName, "The maximum runtime in seconds after which the algorithm stops. Use -1 to specify no limit for the runtime", new IntValue(3600)));
235      Parameters.Add(new FixedValueParameter<IntValue>(SeedName, "The random seed used to initialize the new pseudo random number generator.", new IntValue(0)));
236      Parameters.Add(new FixedValueParameter<BoolValue>(SetSeedRandomlyName, "True if the random seed should be set to a random value, otherwise false.", new BoolValue(true)));
237      Parameters.Add(new FixedValueParameter<IntValue>(PopulationSizeName, "λ (lambda) - the size of the offspring population.", new IntValue(20)));
238      Parameters.Add(new ValueParameter<DoubleArray>(InitialSigmaName, "The initial sigma can be a single value or a value for each dimension. All values need to be > 0.", new DoubleArray(new[] { 0.5 })));
239      Parameters.Add(new FixedValueParameter<IntValue>(MaximumGenerationsName, "The maximum number of generations which should be processed.", new IntValue(1000)));
240      Parameters.Add(new FixedValueParameter<IntValue>(MaximumEvaluatedSolutionsName, "The maximum number of evaluated solutions that should be computed.", new IntValue(int.MaxValue)));
241      var set = new ItemSet<IIndicator> { new HypervolumeIndicator(), new CrowdingIndicator(), new MinimalDistanceIndicator() };
242      Parameters.Add(new ConstrainedValueParameter<IIndicator>(IndicatorName, "The selection mechanism on non-dominated solutions", set, set.First()));
243    }
244
245    [StorableConstructor]
246    protected MOCMASEvolutionStrategy(bool deserializing) : base(deserializing) { }
247    protected MOCMASEvolutionStrategy(MOCMASEvolutionStrategy original, Cloner cloner) : base(original, cloner) { }
248    public override IDeepCloneable Clone(Cloner cloner) { return new MOCMASEvolutionStrategy(this, cloner); }
249    #endregion
250
251    #region Mainloop
252
253    protected override void Initialize(CancellationToken cancellationToken) {
254      if (SetSeedRandomly) Seed = new System.Random().Next();
255      random.Reset(Seed);
256      gauss = new NormalDistributedRandom(random, 0, 1);
257
258      InitResults();
259      InitStrategy();
260      InitSolutions();
261      AnalyzeSolutions();
262
263      ResultsIterations = 1;
264    }
265
266    protected override void Run(CancellationToken cancellationToken) {
267      // Loop until iteration limit reached or canceled.
268      while (ResultsIterations < MaximumGenerations) {
269        try {
270          Iterate();
271          ResultsIterations++;
272          cancellationToken.ThrowIfCancellationRequested();
273        } finally {
274          AnalyzeSolutions();
275        }
276      }
277    }
278    private void Iterate() {
279      var offspring = MutateOffspring();
280      PenalizeEvaluate(offspring);
281      var parents = solutions.Concat(offspring).ToArray();
282      SelectParents(parents, solutions.Length);
283      UpdatePopulation(parents);
284    }
285    protected override void OnExecutionTimeChanged() {
286      base.OnExecutionTimeChanged();
287      if (CancellationTokenSource == null) return;
288      if (MaximumRuntime == -1) return;
289      if (ExecutionTime.TotalSeconds > MaximumRuntime) CancellationTokenSource.Cancel();
290    }
291    #endregion
292
293    #region Initialization
294    private MOCMAESIndividual InitializeIndividual(RealVector x) {
295      var zeros = new RealVector(x.Length);
296      var c = new double[x.Length, x.Length];
297      double sigma = InitialSigma.Max();
298      for (var i = 0; i < x.Length; i++) {
299        double d = InitialSigma[i % InitialSigma.Length] / sigma;
300        c[i, i] = d * d;
301      }
302      return new MOCMAESIndividual(x, internals.TargetSuccessProbability, sigma, zeros, c, internals);
303    }
304    private void InitSolutions() {
305      solutions = new MOCMAESIndividual[PopulationSize];
306      for (var i = 0; i < PopulationSize; i++) {
307        var x = new RealVector(Problem.Encoding.Length); // Uniform distibution in all dimensions assumed.
308                                                         // There is the UniformSolutionCreater associated with the Encoding, but it was considered not usable here
309        var bounds = Problem.Encoding.Bounds;
310        for (var j = 0; j < Problem.Encoding.Length; j++) {
311          var dim = j % bounds.Rows;
312          x[j] = random.NextDouble() * (bounds[dim, 1] - bounds[dim, 0]) + bounds[dim, 0];
313        }
314        solutions[i] = InitializeIndividual(x);
315      }
316      PenalizeEvaluate(solutions);
317    }
318    private void InitStrategy() {
319      const int lambda = 1;
320      double n = Problem.Encoding.Length;
321
322      var targetSuccessProbability = 1.0 / (5.0 + Math.Sqrt(lambda) / 2.0);
323      var stepSizeDampeningFactor = 1.0 + n / (2.0 * lambda);
324      var stepSizeLearningRate = targetSuccessProbability * lambda / (2.0 + targetSuccessProbability * lambda);
325      var evolutionPathLearningRate = 2.0 / (n + 2.0);
326      var covarianceMatrixLearningRate = 2.0 / (n * n + 6.0);
327      var covarianceMatrixUnlearningRate = 0.4 / (Math.Pow(n, 1.6) + 1);
328      var successThreshold = 0.44;
329      internals = new MOCMAESParameters(stepSizeLearningRate, stepSizeDampeningFactor, targetSuccessProbability, evolutionPathLearningRate, covarianceMatrixLearningRate, covarianceMatrixUnlearningRate, successThreshold);
330
331    }
332    private void InitResults() {
333      AddResult(IterationsResultName, "The number of gererations evaluated", new IntValue(0));
334      AddResult(EvaluationsResultName, "The number of function evaltions performed", new IntValue(0));
335      AddResult(HypervolumeResultName, "The hypervolume of the current front considering the Referencepoint defined in the Problem", new DoubleValue(0.0));
336      AddResult(BestHypervolumeResultName, "The best hypervolume of the current run considering the Referencepoint defined in the Problem", new DoubleValue(0.0));
337      AddResult(BestKnownHypervolumeResultName, "The best knwon hypervolume considering the Referencepoint defined in the Problem", new DoubleValue(double.NaN));
338      AddResult(DifferenceToBestKnownHypervolumeResultName, "The difference between the current and the best known hypervolume", new DoubleValue(double.NaN));
339      AddResult(GenerationalDistanceResultName, "The generational distance to an optimal pareto front defined in the Problem", new DoubleValue(double.NaN));
340      AddResult(InvertedGenerationalDistanceResultName, "The inverted generational distance to an optimal pareto front defined in the Problem", new DoubleValue(double.NaN));
341      AddResult(CrowdingResultName, "The average crowding value for the current front (excluding infinities)", new DoubleValue(0.0));
342      AddResult(SpacingResultName, "The spacing for the current front (excluding infinities)", new DoubleValue(0.0));
343
344      var table = new DataTable("QualityIndicators");
345      table.Rows.Add(new DataRow(BestHypervolumeResultName));
346      table.Rows.Add(new DataRow(HypervolumeResultName));
347      table.Rows.Add(new DataRow(CrowdingResultName));
348      table.Rows.Add(new DataRow(GenerationalDistanceResultName));
349      table.Rows.Add(new DataRow(InvertedGenerationalDistanceResultName));
350      table.Rows.Add(new DataRow(DifferenceToBestKnownHypervolumeResultName));
351      table.Rows.Add(new DataRow(SpacingResultName));
352      AddResult(TimetableResultName, "Different quality meassures in a timeseries", table);
353      AddResult(CurrentFrontResultName, "The current front", new DoubleMatrix());
354      AddResult(ScatterPlotResultName, "A scatterplot displaying the evaluated solutions and (if available) the analytically optimal front", new ScatterPlotContent(null, null, null, 2));
355
356      var problem = Problem as MultiObjectiveTestFunctionProblem;
357      if (problem == null) return;
358      if (problem.BestKnownFront != null) {
359        ResultsBestKnownHypervolume = Hypervolume.Calculate(Utilities.ToArray(problem.BestKnownFront), problem.TestFunction.ReferencePoint(problem.Objectives), Problem.Maximization);
360        ResultsDifferenceBestKnownHypervolume = ResultsBestKnownHypervolume;
361      }
362      ResultsScatterPlot = new ScatterPlotContent(new double[0][], new double[0][], Utilities.ToArray(problem.BestKnownFront), problem.Objectives);
363    }
364    #endregion
365
366    private MOCMAESIndividual[] MutateOffspring() {
367      var offspring = new MOCMAESIndividual[PopulationSize];
368      for (var i = 0; i < PopulationSize; i++) {
369        offspring[i] = new MOCMAESIndividual(solutions[i]);
370        offspring[i].Mutate(gauss);
371      }
372      return offspring;
373    }
374
375    #region Evaluation
376    private void PenalizeEvaluate(IEnumerable<MOCMAESIndividual> offspring) {
377      foreach (var child in offspring) {
378        if (IsFeasable(child.Mean)) {
379          child.Fitness = Evaluate(child.Mean);
380          child.PenalizedFitness = child.Fitness;
381        } else {
382          var t = ClosestFeasible(child.Mean);
383          child.Fitness = Evaluate(t);
384          child.PenalizedFitness = Penalize(child.Mean, t, child.Fitness);
385        }
386      }
387    }
388    private double[] Evaluate(RealVector x) {
389      var s = new Scope();
390      s.Variables.Add(new Variable(Problem.Encoding.Name, x));
391      var ind = new SingleEncodingIndividual(Problem.Encoding, s);
392      var res = Problem.Evaluate(ind, random);
393      ResultsEvaluations++;
394      return res;
395    }
396    private double[] Penalize(RealVector x, RealVector t, IEnumerable<double> fitness) {
397      var penalty = x.Zip(t, (a, b) => (a - b) * (a - b)).Sum() * 1E-6;
398      return fitness.Select((v, i) => Problem.Maximization[i] ? v - penalty : v + penalty).ToArray();
399    }
400    private RealVector ClosestFeasible(RealVector x) {
401      var bounds = Problem.Encoding.Bounds;
402      var r = new RealVector(x.Length);
403      for (var i = 0; i < x.Length; i++) {
404        var dim = i % bounds.Rows;
405        r[i] = Math.Min(Math.Max(bounds[dim, 0], x[i]), bounds[dim, 1]);
406      }
407      return r;
408    }
409    private bool IsFeasable(RealVector offspring) {
410      var bounds = Problem.Encoding.Bounds;
411      for (var i = 0; i < offspring.Length; i++) {
412        var dim = i % bounds.Rows;
413        if (bounds[dim, 0] > offspring[i] || offspring[i] > bounds[dim, 1]) return false;
414      }
415      return true;
416    }
417    #endregion
418
419    private void SelectParents(IReadOnlyList<MOCMAESIndividual> parents, int length) {
420      //perform a nondominated sort to assign the rank to every element
421      var fronts = NonDominatedSort(parents);
422
423      //deselect the highest rank fronts until we would end up with less or equal mu elements
424      var rank = fronts.Count - 1;
425      var popSize = parents.Count;
426      while (popSize - fronts[rank].Count >= length) {
427        var front = fronts[rank];
428        foreach (var i in front) i.Selected = false;
429        popSize -= front.Count;
430        rank--;
431      }
432
433
434      //now use the indicator to deselect the approximatingly worst elements of the last selected front
435      var front1 = fronts[rank];
436      front1.Sort(new HelpComparer());
437      for (; popSize > length; popSize--) {
438        var lc = Indicator.LeastContributer(front1.ToArray(), x => x.PenalizedFitness, Problem);
439        front1[lc].Selected = false;
440        front1.Swap(lc, front1.Count - 1);
441        front1.RemoveAt(front1.Count - 1);
442      }
443    }
444
445    private void UpdatePopulation(IReadOnlyList<MOCMAESIndividual> parents) {
446      var offspringSucess = new int[solutions.Length];
447      var offspringLength = parents.Count - solutions.Length;
448      for (var i = 0; i < offspringLength; i++) {
449        if (!parents[i + solutions.Length].Selected) continue;
450        parents[i + solutions.Length].UpdateAsOffspring();
451        offspringSucess[i] += MOCMAESIndividual.Success;
452      }
453      for (var i = 0; i < solutions.Length; i++) if (parents[i].Selected) parents[i].UpdateAsParent(offspringSucess[i]);
454      solutions = new MOCMAESIndividual[solutions.Length];
455      var j = 0;
456      foreach (var ind in parents) if (ind.Selected) solutions[j++] = ind;
457    }
458
459    #region Analysis
460    private void AnalyzeSolutions() {
461      ResultsScatterPlot = new ScatterPlotContent(solutions.Select(x => x.Fitness).ToArray(),
462          solutions.Select(x => x.Mean.ToArray()).ToArray(),
463          ResultsScatterPlot.ParetoFront,
464          ResultsScatterPlot.Objectives);
465      ResultsSolutions = ToMatrix(solutions.Select(x => x.Mean.ToArray()));
466      AnalyzeQualityIndicators();
467    }
468    private void AnalyzeQualityIndicators() {
469      var problem = Problem as MultiObjectiveTestFunctionProblem;
470      if (problem == null) return;
471
472      var front = NonDominatedSelect.GetDominatingVectors(solutions.Select(x => x.Fitness), problem.TestFunction.ReferencePoint(problem.Objectives), Problem.Maximization, true).ToArray();
473      if (front.Length == 0) return;
474      var bounds = problem.Bounds.CloneAsMatrix();
475      ResultsCrowding = Crowding.Calculate(front, bounds);
476      ResultsSpacing = Spacing.Calculate(front);
477      ResultsGenerationalDistance = problem.BestKnownFront != null ? GenerationalDistance.Calculate(front, Utilities.ToArray(problem.BestKnownFront), 1) : double.NaN;
478
479      ResultsInvertedGenerationalDistance = problem.BestKnownFront != null ? InvertedGenerationalDistance.Calculate(front, Utilities.ToArray(problem.BestKnownFront), 1) : double.NaN;
480
481      ResultsHypervolume = Hypervolume.Calculate(front, problem.TestFunction.ReferencePoint(problem.Objectives), Problem.Maximization);
482      ResultsBestHypervolume = Math.Max(ResultsHypervolume, ResultsBestHypervolume);
483      ResultsDifferenceBestKnownHypervolume = ResultsBestKnownHypervolume - ResultsBestHypervolume;
484
485      //Datalines
486      ResultsBestHypervolumeDataLine.Values.Add(ResultsBestHypervolume);
487      ResultsHypervolumeDataLine.Values.Add(ResultsHypervolume);
488      ResultsCrowdingDataLine.Values.Add(ResultsCrowding);
489      ResultsGenerationalDistanceDataLine.Values.Add(ResultsGenerationalDistance);
490      ResultsInvertedGenerationalDistanceDataLine.Values.Add(ResultsInvertedGenerationalDistance);
491      ResultsSpacingDataLine.Values.Add(ResultsSpacing);
492      ResultsHypervolumeDifferenceDataLine.Values.Add(ResultsDifferenceBestKnownHypervolume);
493
494    }
495    #endregion
496
497    private class HelpComparer : IComparer<MOCMAESIndividual> {
498      public int Compare(MOCMAESIndividual x, MOCMAESIndividual y) {
499        return x.PenalizedFitness[0].CompareTo(y.PenalizedFitness[0]);
500      }
501    }
502
503    #region Helpers
504    public DoubleMatrix ToMatrix(IEnumerable<double[]> data) {
505      var d2 = data.ToArray();
506      var mat = new DoubleMatrix(d2.Length, d2[0].Length);
507      for (var i = 0; i < mat.Rows; i++) {
508        for (var j = 0; j < mat.Columns; j++) {
509          mat[i, j] = d2[i][j];
510        }
511      }
512      return mat;
513    }
514    private void AddResult<T>(string name1, string desc, T defaultValue) where T : class, IItem {
515      Results.Add(new Result(name1, desc, defaultValue));
516    }
517    //blatantly stolen form HeuristicLab.Optimization.Operators.FastNonDominatedSort
518    //however: Operators.FastNonDominatedSort does not return ranked fronts => rerank after sorting would not be sensible
519    #region FastNonDominatedSort   
520    private enum DominationResult { Dominates, IsDominated, IsNonDominated };
521    private List<List<MOCMAESIndividual>> NonDominatedSort(IReadOnlyList<MOCMAESIndividual> individuals) {
522      const bool dominateOnEqualQualities = false;
523      var maximization = Problem.Maximization;
524      if (individuals == null) throw new InvalidOperationException(Name + ": No qualities found.");
525      var populationSize = individuals.Count;
526
527      var fronts = new List<List<MOCMAESIndividual>>();
528      var dominatedScopes = new Dictionary<MOCMAESIndividual, List<int>>();
529      var dominationCounter = new int[populationSize];
530
531      for (var pI = 0; pI < populationSize - 1; pI++) {
532        var p = individuals[pI];
533        List<int> dominatedScopesByp;
534        if (!dominatedScopes.TryGetValue(p, out dominatedScopesByp))
535          dominatedScopes[p] = dominatedScopesByp = new List<int>();
536        for (var qI = pI + 1; qI < populationSize; qI++) {
537          var test = Dominates(individuals[pI], individuals[qI], maximization, dominateOnEqualQualities);
538          if (test == DominationResult.Dominates) {
539            dominatedScopesByp.Add(qI);
540            dominationCounter[qI] += 1;
541          } else if (test == DominationResult.IsDominated) {
542            dominationCounter[pI] += 1;
543            if (!dominatedScopes.ContainsKey(individuals[qI]))
544              dominatedScopes.Add(individuals[qI], new List<int>());
545            dominatedScopes[individuals[qI]].Add(pI);
546          }
547          if (pI == populationSize - 2
548            && qI == populationSize - 1
549            && dominationCounter[qI] == 0) {
550            AddToFront(individuals[qI], fronts, 0);
551          }
552        }
553        if (dominationCounter[pI] == 0) {
554          AddToFront(p, fronts, 0);
555        }
556      }
557      var i = 0;
558      while (i < fronts.Count && fronts[i].Count > 0) {
559        var nextFront = new List<MOCMAESIndividual>();
560        foreach (var p in fronts[i]) {
561          List<int> dominatedScopesByp;
562          if (!dominatedScopes.TryGetValue(p, out dominatedScopesByp)) continue;
563          foreach (var dominatedScope in dominatedScopesByp) {
564            dominationCounter[dominatedScope] -= 1;
565            if (dominationCounter[dominatedScope] != 0) continue;
566            nextFront.Add(individuals[dominatedScope]);
567          }
568        }
569        i += 1;
570        fronts.Add(nextFront);
571      }
572
573      for (i = 0; i < fronts.Count; i++) {
574        foreach (var p in fronts[i]) {
575          p.Rank = i;
576        }
577      }
578      return fronts;
579    }
580    private static void AddToFront(MOCMAESIndividual p, IList<List<MOCMAESIndividual>> fronts, int i) {
581      if (i == fronts.Count) fronts.Add(new List<MOCMAESIndividual>());
582      fronts[i].Add(p);
583    }
584    private static DominationResult Dominates(MOCMAESIndividual left, MOCMAESIndividual right, bool[] maximizations, bool dominateOnEqualQualities) {
585      return Dominates(left.PenalizedFitness, right.PenalizedFitness, maximizations, dominateOnEqualQualities);
586    }
587    private static DominationResult Dominates(IReadOnlyList<double> left, IReadOnlyList<double> right, IReadOnlyList<bool> maximizations, bool dominateOnEqualQualities) {
588      //mkommend Caution: do not use LINQ.SequenceEqual for comparing the two quality arrays (left and right) due to performance reasons
589      if (dominateOnEqualQualities) {
590        var equal = true;
591        for (var i = 0; i < left.Count; i++) {
592          if (left[i] != right[i]) {
593            equal = false;
594            break;
595          }
596        }
597        if (equal) return DominationResult.Dominates;
598      }
599
600      bool leftIsBetter = false, rightIsBetter = false;
601      for (var i = 0; i < left.Count; i++) {
602        if (IsDominated(left[i], right[i], maximizations[i])) rightIsBetter = true;
603        else if (IsDominated(right[i], left[i], maximizations[i])) leftIsBetter = true;
604        if (leftIsBetter && rightIsBetter) break;
605      }
606
607      if (leftIsBetter && !rightIsBetter) return DominationResult.Dominates;
608      if (!leftIsBetter && rightIsBetter) return DominationResult.IsDominated;
609      return DominationResult.IsNonDominated;
610    }
611    private static bool IsDominated(double left, double right, bool maximization) {
612      return maximization && left < right
613        || !maximization && left > right;
614    }
615    #endregion
616    #endregion
617  }
618}
Note: See TracBrowser for help on using the repository browser.