Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 14612 was 14612, checked in by bwerth, 8 years ago

#2592 made initialization solutionspace-scaling invariant

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