Free cookie consent management tool by TermsFeed Policy Generator

source: branches/2987_MOEAD_Algorithm/HeuristicLab.Algorithms.MOEAD/3.4/MOEADAlgorithmBase.cs @ 16630

Last change on this file since 16630 was 16630, checked in by bburlacu, 5 years ago

#2987: Migrate to new persistence. Add support for objective scaling.

File size: 28.0 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2019 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using HEAL.Attic;
23using HeuristicLab.Analysis;
24using HeuristicLab.Common;
25using HeuristicLab.Core;
26using HeuristicLab.Data;
27using HeuristicLab.ExpressionGenerator;
28using HeuristicLab.Optimization;
29using HeuristicLab.Parameters;
30using HeuristicLab.Problems.DataAnalysis;
31using HeuristicLab.Random;
32using System;
33using System.Collections.Generic;
34using System.Linq;
35using CancellationToken = System.Threading.CancellationToken;
36
37namespace HeuristicLab.Algorithms.MOEAD {
38  [Item("MOEADAlgorithmBase", "Base class for all MOEA/D algorithm variants.")]
39  [StorableType("E00BAC79-C6F9-42B6-8468-DEEC7FFCE804")]
40  public abstract class MOEADAlgorithmBase : BasicAlgorithm {
41    #region data members
42    protected enum NeighborType { NEIGHBOR, POPULATION }
43    // TCHE = Chebyshev (Tchebyshev)
44    // PBI  = Penalty-based boundary intersection
45    // AGG  = Weighted sum
46    public enum FunctionType { TCHE, PBI, AGG }
47
48    [Storable]
49    protected double[] IdealPoint { get; set; }
50    [Storable]
51    protected double[] NadirPoint { get; set; } // potentially useful for objective normalization
52
53    [Storable]
54    protected double[][] lambda;
55
56    [Storable]
57    protected int[][] neighbourhood;
58
59    [Storable]
60    protected IList<IMOEADSolution> solutions;
61
62    [Storable]
63    protected FunctionType functionType;
64
65    [Storable]
66    protected List<IMOEADSolution> population;
67
68    [Storable]
69    protected List<IMOEADSolution> offspringPopulation;
70
71    [Storable]
72    protected List<IMOEADSolution> jointPopulation;
73
74    [Storable]
75    protected int evaluatedSolutions;
76
77    [Storable]
78    protected ExecutionContext executionContext;
79
80    [Storable]
81    protected IScope globalScope;
82
83    [Storable]
84    protected ExecutionState previousExecutionState;
85
86    [Storable]
87    protected ExecutionState executionState;
88    #endregion
89
90    #region parameters
91    private const string SeedParameterName = "Seed";
92    private const string SetSeedRandomlyParameterName = "SetSeedRandomly";
93    private const string PopulationSizeParameterName = "PopulationSize";
94    private const string ResultPopulationSizeParameterName = "ResultPopulationSize";
95    private const string CrossoverProbabilityParameterName = "CrossoverProbability";
96    private const string CrossoverParameterName = "Crossover";
97    private const string MutationProbabilityParameterName = "MutationProbability";
98    private const string MutatorParameterName = "Mutator";
99    private const string MaximumEvaluatedSolutionsParameterName = "MaximumEvaluatedSolutions";
100    private const string RandomParameterName = "Random";
101    private const string AnalyzerParameterName = "Analyzer";
102    // MOEA-D parameters
103    private const string NeighbourSizeParameterName = "NeighbourSize";
104    private const string NeighbourhoodSelectionProbabilityParameterName = "NeighbourhoodSelectionProbability";
105    private const string MaximumNumberOfReplacedSolutionsParameterName = "MaximumNumberOfReplacedSolutions";
106    private const string FunctionTypeParameterName = "FunctionType";
107    private const string NormalizeObjectivesParameterName = "NormalizeObjectives";
108
109    public IValueParameter<MultiAnalyzer> AnalyzerParameter {
110      get { return (ValueParameter<MultiAnalyzer>)Parameters[AnalyzerParameterName]; }
111    }
112
113    public IConstrainedValueParameter<StringValue> FunctionTypeParameter {
114      get { return (IConstrainedValueParameter<StringValue>)Parameters[FunctionTypeParameterName]; }
115    }
116    public IFixedValueParameter<IntValue> NeighbourSizeParameter {
117      get { return (IFixedValueParameter<IntValue>)Parameters[NeighbourSizeParameterName]; }
118    }
119    public IFixedValueParameter<BoolValue> NormalizeObjectivesParameter {
120      get { return (IFixedValueParameter<BoolValue>)Parameters[NormalizeObjectivesParameterName]; }
121    }
122    public IFixedValueParameter<IntValue> MaximumNumberOfReplacedSolutionsParameter {
123      get { return (IFixedValueParameter<IntValue>)Parameters[MaximumNumberOfReplacedSolutionsParameterName]; }
124    }
125    public IFixedValueParameter<DoubleValue> NeighbourhoodSelectionProbabilityParameter {
126      get { return (IFixedValueParameter<DoubleValue>)Parameters[NeighbourhoodSelectionProbabilityParameterName]; }
127    }
128    public IFixedValueParameter<IntValue> SeedParameter {
129      get { return (IFixedValueParameter<IntValue>)Parameters[SeedParameterName]; }
130    }
131    public IFixedValueParameter<BoolValue> SetSeedRandomlyParameter {
132      get { return (IFixedValueParameter<BoolValue>)Parameters[SetSeedRandomlyParameterName]; }
133    }
134    private IValueParameter<IntValue> PopulationSizeParameter {
135      get { return (IValueParameter<IntValue>)Parameters[PopulationSizeParameterName]; }
136    }
137    private IValueParameter<IntValue> ResultPopulationSizeParameter {
138      get { return (IValueParameter<IntValue>)Parameters[ResultPopulationSizeParameterName]; }
139    }
140    public IValueParameter<PercentValue> CrossoverProbabilityParameter {
141      get { return (IValueParameter<PercentValue>)Parameters[CrossoverProbabilityParameterName]; }
142    }
143    public IConstrainedValueParameter<ICrossover> CrossoverParameter {
144      get { return (IConstrainedValueParameter<ICrossover>)Parameters[CrossoverParameterName]; }
145    }
146    public IValueParameter<PercentValue> MutationProbabilityParameter {
147      get { return (IValueParameter<PercentValue>)Parameters[MutationProbabilityParameterName]; }
148    }
149    public IConstrainedValueParameter<IManipulator> MutatorParameter {
150      get { return (IConstrainedValueParameter<IManipulator>)Parameters[MutatorParameterName]; }
151    }
152    public IValueParameter<IntValue> MaximumEvaluatedSolutionsParameter {
153      get { return (IValueParameter<IntValue>)Parameters[MaximumEvaluatedSolutionsParameterName]; }
154    }
155    public IValueParameter<IRandom> RandomParameter {
156      get { return (IValueParameter<IRandom>)Parameters[RandomParameterName]; }
157    }
158    #endregion
159
160    #region parameter properties
161    public new IMultiObjectiveHeuristicOptimizationProblem Problem {
162      get { return (IMultiObjectiveHeuristicOptimizationProblem)base.Problem; }
163    }
164    public int Seed {
165      get { return SeedParameter.Value.Value; }
166      set { SeedParameter.Value.Value = value; }
167    }
168    public bool SetSeedRandomly {
169      get { return SetSeedRandomlyParameter.Value.Value; }
170      set { SetSeedRandomlyParameter.Value.Value = value; }
171    }
172    public bool NormalizeObjectives {
173      get { return NormalizeObjectivesParameter.Value.Value; }
174      set { NormalizeObjectivesParameter.Value.Value = value; }
175    }
176    public IntValue PopulationSize {
177      get { return PopulationSizeParameter.Value; }
178      set { PopulationSizeParameter.Value = value; }
179    }
180    public IntValue ResultPopulationSize {
181      get { return ResultPopulationSizeParameter.Value; }
182      set { ResultPopulationSizeParameter.Value = value; }
183    }
184    public PercentValue CrossoverProbability {
185      get { return CrossoverProbabilityParameter.Value; }
186      set { CrossoverProbabilityParameter.Value = value; }
187    }
188    public ICrossover Crossover {
189      get { return CrossoverParameter.Value; }
190      set { CrossoverParameter.Value = value; }
191    }
192    public PercentValue MutationProbability {
193      get { return MutationProbabilityParameter.Value; }
194      set { MutationProbabilityParameter.Value = value; }
195    }
196    public IManipulator Mutator {
197      get { return MutatorParameter.Value; }
198      set { MutatorParameter.Value = value; }
199    }
200    public MultiAnalyzer Analyzer {
201      get { return AnalyzerParameter.Value; }
202      set { AnalyzerParameter.Value = value; }
203    }
204    public IntValue MaximumEvaluatedSolutions {
205      get { return MaximumEvaluatedSolutionsParameter.Value; }
206      set { MaximumEvaluatedSolutionsParameter.Value = value; }
207    }
208    public int NeighbourSize {
209      get { return NeighbourSizeParameter.Value.Value; }
210      set { NeighbourSizeParameter.Value.Value = value; }
211    }
212    public int MaximumNumberOfReplacedSolutions {
213      get { return MaximumNumberOfReplacedSolutionsParameter.Value.Value; }
214      set { MaximumNumberOfReplacedSolutionsParameter.Value.Value = value; }
215    }
216    public double NeighbourhoodSelectionProbability {
217      get { return NeighbourhoodSelectionProbabilityParameter.Value.Value; }
218      set { NeighbourhoodSelectionProbabilityParameter.Value.Value = value; }
219    }
220    #endregion
221
222    #region constructors
223    public MOEADAlgorithmBase() {
224      Parameters.Add(new FixedValueParameter<IntValue>(SeedParameterName, "The random seed used to initialize the new pseudo random number generator.", new IntValue(0)));
225      Parameters.Add(new FixedValueParameter<BoolValue>(SetSeedRandomlyParameterName, "True if the random seed should be set to a random value, otherwise false.", new BoolValue(true)));
226      Parameters.Add(new ValueParameter<IntValue>(PopulationSizeParameterName, "The size of the population of solutions.", new IntValue(100)));
227      Parameters.Add(new ValueParameter<IntValue>(ResultPopulationSizeParameterName, "The size of the population of solutions.", new IntValue(100)));
228      Parameters.Add(new ValueParameter<PercentValue>(CrossoverProbabilityParameterName, "The probability that the crossover operator is applied.", new PercentValue(0.9)));
229      Parameters.Add(new ConstrainedValueParameter<ICrossover>(CrossoverParameterName, "The operator used to cross solutions."));
230      Parameters.Add(new ValueParameter<PercentValue>(MutationProbabilityParameterName, "The probability that the mutation operator is applied on a solution.", new PercentValue(0.25)));
231      Parameters.Add(new ConstrainedValueParameter<IManipulator>(MutatorParameterName, "The operator used to mutate solutions."));
232      Parameters.Add(new ValueParameter<MultiAnalyzer>("Analyzer", "The operator used to analyze each generation.", new MultiAnalyzer()));
233      Parameters.Add(new ValueParameter<IntValue>(MaximumEvaluatedSolutionsParameterName, "The maximum number of evaluated solutions (approximately).", new IntValue(100_000)));
234      Parameters.Add(new ValueParameter<IRandom>(RandomParameterName, new MersenneTwister()));
235      Parameters.Add(new FixedValueParameter<IntValue>(NeighbourSizeParameterName, new IntValue(20)));
236      Parameters.Add(new FixedValueParameter<IntValue>(MaximumNumberOfReplacedSolutionsParameterName, new IntValue(2)));
237      Parameters.Add(new FixedValueParameter<DoubleValue>(NeighbourhoodSelectionProbabilityParameterName, new DoubleValue(0.1)));
238      Parameters.Add(new FixedValueParameter<BoolValue>(NormalizeObjectivesParameterName, new BoolValue(true)));
239
240      var functionTypeParameter = new ConstrainedValueParameter<StringValue>(FunctionTypeParameterName);
241      foreach (var s in new[] { "Chebyshev", "PBI", "Weighted Sum" }) {
242        functionTypeParameter.ValidValues.Add(new StringValue(s));
243      }
244      Parameters.Add(functionTypeParameter);
245    }
246
247    protected MOEADAlgorithmBase(MOEADAlgorithmBase original, Cloner cloner) : base(original, cloner) {
248      functionType = original.functionType;
249      evaluatedSolutions = original.evaluatedSolutions;
250      previousExecutionState = original.previousExecutionState;
251
252      if (original.IdealPoint != null) {
253        IdealPoint = (double[])original.IdealPoint.Clone();
254      }
255
256      if (original.NadirPoint != null) {
257        NadirPoint = (double[])original.NadirPoint.Clone();
258      }
259
260      if (original.lambda != null) {
261        lambda = (double[][])original.lambda.Clone();
262      }
263
264      if (original.neighbourhood != null) {
265        neighbourhood = (int[][])original.neighbourhood.Clone();
266      }
267
268      if (original.solutions != null) {
269        solutions = original.solutions.Select(cloner.Clone).ToArray();
270      }
271
272      if (original.population != null) {
273        population = original.population.Select(cloner.Clone).ToList();
274      }
275
276      if (original.offspringPopulation != null) {
277        offspringPopulation = original.offspringPopulation.Select(cloner.Clone).ToList();
278      }
279
280      if (original.jointPopulation != null) {
281        jointPopulation = original.jointPopulation.Select(x => cloner.Clone(x)).ToList();
282      }
283
284      if (original.executionContext != null) {
285        executionContext = cloner.Clone(original.executionContext);
286      }
287
288      if (original.globalScope != null) {
289        globalScope = cloner.Clone(original.globalScope);
290      }
291    }
292
293
294    [StorableHook(HookType.AfterDeserialization)]
295    private void AfterDeserialization() {
296      if (!Parameters.ContainsKey(NormalizeObjectivesParameterName)) {
297        Parameters.Add(new FixedValueParameter<BoolValue>(NormalizeObjectivesParameterName, new BoolValue(true)));
298      }
299    }
300
301    [StorableConstructor]
302    protected MOEADAlgorithmBase(StorableConstructorFlag _) : base(_) { }
303    #endregion
304
305    private void InitializePopulation(ExecutionContext executionContext, CancellationToken cancellationToken, IRandom random, bool[] maximization) {
306      var creator = Problem.SolutionCreator;
307      var evaluator = Problem.Evaluator;
308
309      var dimensions = maximization.Length;
310      var populationSize = PopulationSize.Value;
311      population = new List<IMOEADSolution>(populationSize);
312
313      var parentScope = executionContext.Scope;
314      // first, create all individuals
315      for (int i = 0; i < populationSize; ++i) {
316        var childScope = new Scope(i.ToString()) { Parent = parentScope };
317        ExecuteOperation(executionContext, cancellationToken, executionContext.CreateChildOperation(creator, childScope));
318        parentScope.SubScopes.Add(childScope);
319      }
320
321      // then, evaluate them and update qualities
322      for (int i = 0; i < populationSize; ++i) {
323        var childScope = parentScope.SubScopes[i];
324        ExecuteOperation(executionContext, cancellationToken, executionContext.CreateChildOperation(evaluator, childScope));
325
326        var qualities = (DoubleArray)childScope.Variables["Qualities"].Value;
327        var solution = new MOEADSolution(childScope, dimensions, 0);
328        for (int j = 0; j < dimensions; ++j) {
329          solution.Qualities[j] = maximization[j] ? 1 - qualities[j] : qualities[j];
330        }
331        population.Add(solution);
332      }
333    }
334
335    protected void InitializeAlgorithm(CancellationToken cancellationToken) {
336      var rand = RandomParameter.Value;
337      if (SetSeedRandomly) Seed = RandomSeedGenerator.GetSeed();
338      rand.Reset(Seed);
339
340      bool[] maximization = ((BoolArray)Problem.MaximizationParameter.ActualValue).CloneAsArray();
341      var dimensions = maximization.Length;
342
343      var populationSize = PopulationSize.Value;
344
345      InitializePopulation(executionContext, cancellationToken, rand, maximization);
346      InitializeUniformWeights(rand, populationSize, dimensions);
347      InitializeNeighbourHood(lambda, populationSize, NeighbourSize);
348
349      //IdealPoint = Enumerable.Repeat(double.MaxValue, dimensions).ToArray();
350      IdealPoint = new double[dimensions];
351      IdealPoint.UpdateIdeal(population);
352
353      //NadirPoint = Enumerable.Repeat(double.MinValue, dimensions).ToArray();
354      NadirPoint = new double[dimensions];
355      NadirPoint.UpdateNadir(population);
356
357      var functionTypeString = FunctionTypeParameter.Value.Value;
358      switch (functionTypeString) {
359        case "Chebyshev":
360          functionType = FunctionType.TCHE;
361          break;
362        case "PBI":
363          functionType = FunctionType.PBI;
364          break;
365        case "Weighted Sum":
366          functionType = FunctionType.AGG;
367          break;
368      }
369
370      evaluatedSolutions = populationSize;
371    }
372
373    protected override void Initialize(CancellationToken cancellationToken) {
374      globalScope = new Scope("Global Scope");
375      executionContext = new ExecutionContext(null, this, globalScope);
376
377      // set the execution context for parameters to allow lookup
378      foreach (var parameter in Problem.Parameters.OfType<IValueParameter>()) {
379        // we need all of these in order for the wiring of the operators to work
380        globalScope.Variables.Add(new Variable(parameter.Name, parameter.Value));
381      }
382      globalScope.Variables.Add(new Variable("Results", Results)); // make results available as a parameter for analyzers etc.
383
384      base.Initialize(cancellationToken);
385    }
386
387    public override bool SupportsPause => true;
388
389    protected void InitializeUniformWeights(IRandom random, int populationSize, int dimensions) {
390      lambda = Enumerable.Range(0, populationSize).Select(_ => GenerateSample(random, dimensions)).ToArray();
391    }
392
393    // implements random number generation from https://en.wikipedia.org/wiki/Dirichlet_distribution#Random_number_generation
394    private double[] GenerateSample(IRandom random, int dim) {
395      var sum = 0d;
396      var sample = new double[dim];
397      for (int i = 0; i < dim; ++i) {
398        sample[i] = GammaDistributedRandom.NextDouble(random, 1, 1);
399        sum += sample[i];
400      }
401      for (int i = 0; i < dim; ++i) {
402        sample[i] /= sum;
403      }
404      return sample;
405    }
406
407    protected void InitializeNeighbourHood(double[][] lambda, int populationSize, int neighbourSize) {
408      neighbourhood = new int[populationSize][];
409
410      var x = new double[populationSize];
411      var idx = new int[populationSize];
412
413      for (int i = 0; i < populationSize; ++i) {
414        for (int j = 0; j < populationSize; ++j) {
415          x[j] = MOEADUtil.EuclideanDistance(lambda[i], lambda[j]);
416          idx[j] = j;
417        }
418
419        MOEADUtil.MinFastSort(x, idx, populationSize, neighbourSize);
420        neighbourhood[i] = (int[])idx.Clone();
421      }
422    }
423
424    protected NeighborType ChooseNeighborType(IRandom random, double neighbourhoodSelectionProbability) {
425      return random.NextDouble() < neighbourhoodSelectionProbability
426        ? NeighborType.NEIGHBOR
427        : NeighborType.POPULATION;
428    }
429
430    protected IList<IMOEADSolution> ParentSelection(IRandom random, int subProblemId, NeighborType neighbourType) {
431      List<int> matingPool = MatingSelection(random, subProblemId, 2, neighbourType);
432
433      var parents = new IMOEADSolution[3];
434
435      parents[0] = population[matingPool[0]];
436      parents[1] = population[matingPool[1]];
437      parents[2] = population[subProblemId];
438
439      return parents;
440    }
441
442    protected List<int> MatingSelection(IRandom random, int subproblemId, int numberOfSolutionsToSelect, NeighborType neighbourType) {
443      int populationSize = PopulationSize.Value;
444
445      var listOfSolutions = new List<int>(numberOfSolutionsToSelect);
446
447      int neighbourSize = neighbourhood[subproblemId].Length;
448      while (listOfSolutions.Count < numberOfSolutionsToSelect) {
449        var selectedSolution = neighbourType == NeighborType.NEIGHBOR
450          ? neighbourhood[subproblemId][random.Next(neighbourSize)]
451          : random.Next(populationSize);
452
453        bool flag = true;
454        foreach (int individualId in listOfSolutions) {
455          if (individualId == selectedSolution) {
456            flag = false;
457            break;
458          }
459        }
460
461        if (flag) {
462          listOfSolutions.Add(selectedSolution);
463        }
464      }
465
466      return listOfSolutions;
467    }
468
469    protected void UpdateNeighbourHood(IRandom random, IMOEADSolution individual, int subProblemId, NeighborType neighbourType) {
470      int replacedSolutions = 0;
471      int size = neighbourType == NeighborType.NEIGHBOR ? NeighbourSize : population.Count;
472
473      foreach (var i in Enumerable.Range(0, size).Shuffle(random)) {
474        int k = neighbourType == NeighborType.NEIGHBOR
475          ? neighbourhood[subProblemId][i]
476          : i;
477
478        double f1 = CalculateFitness(population[k].Qualities, lambda[k]);
479        double f2 = CalculateFitness(individual.Qualities, lambda[k]);
480
481        if (f2 < f1) {
482          population[k] = (IMOEADSolution)individual.Clone();
483          replacedSolutions++;
484        }
485
486        if (replacedSolutions >= MaximumNumberOfReplacedSolutions) {
487          return;
488        }
489      }
490    }
491
492    private double CalculateFitness(double[] qualities, double[] lambda) {
493      double fitness;
494      int dim = qualities.Length;
495      switch (functionType) {
496        case FunctionType.TCHE: {
497            double maxFun = double.MinValue;
498
499            for (int n = 0; n < dim; n++) {
500              var diff = qualities[n] - IdealPoint[n];
501              if (NormalizeObjectives) {
502                diff /= NadirPoint[n] - IdealPoint[n];
503              }
504              var l = lambda[n].IsAlmost(0) ? 1e-4 : lambda[n];
505              var feval = l * Math.Abs(diff);
506
507              if (feval > maxFun) {
508                maxFun = feval;
509              }
510            }
511
512            fitness = maxFun;
513            return fitness;
514          }
515        case FunctionType.AGG: {
516            double sum = 0.0;
517            for (int n = 0; n < dim; n++) {
518              sum += lambda[n] * qualities[n];
519            }
520
521            fitness = sum;
522            return fitness;
523          }
524        case FunctionType.PBI: {
525            double d1, d2, nl;
526            double theta = 5.0;
527            int dimensions = dim;
528
529            d1 = d2 = nl = 0.0;
530
531            for (int i = 0; i < dimensions; i++) {
532              d1 += (qualities[i] - IdealPoint[i]) * lambda[i];
533              nl += Math.Pow(lambda[i], 2.0);
534            }
535            nl = Math.Sqrt(nl);
536            d1 = Math.Abs(d1) / nl;
537
538            for (int i = 0; i < dimensions; i++) {
539              d2 += Math.Pow((qualities[i] - IdealPoint[i]) - d1 * (lambda[i] / nl), 2.0);
540            }
541            d2 = Math.Sqrt(d2);
542
543            fitness = (d1 + theta * d2);
544            return fitness;
545          }
546        default: {
547            throw new ArgumentException($"Unknown function type: {functionType}");
548          }
549      }
550    }
551
552    public IList<IMOEADSolution> GetResult(IRandom random) {
553      var populationSize = PopulationSize.Value;
554      var resultPopulationSize = ResultPopulationSize.Value;
555
556      if (populationSize > resultPopulationSize) {
557        return MOEADUtil.GetSubsetOfEvenlyDistributedSolutions(random, population, resultPopulationSize);
558      } else {
559        return population;
560      }
561    }
562
563    protected void UpdateParetoFronts() {
564      bool dominates(Point2D<double> x, Point2D<double> y) => x.X <= y.X && x.Y <= y.Y;
565      // get all non-dominated points
566      var points = population.Select(x => new Point2D<double>(Math.Round(x.Qualities[0], 6), Math.Round(x.Qualities[1], 6))).OrderBy(_ => _.X).ThenBy(_ => _.Y).ToArray();
567      var dominated = new bool[points.Length];
568
569      for (int i = 0; i < points.Length; ++i) {
570        if (dominated[i]) { continue; }
571        for (int j = 0; j < points.Length; ++j) {
572          if (i == j) { continue; }
573          if (dominated[j]) { continue; }
574          dominated[j] = dominates(points[i], points[j]);
575        }
576      }
577
578      var pf = Enumerable.Range(0, dominated.Length).Where(x => !dominated[x]).Select(x => points[x]);
579
580      ScatterPlot sp;
581      if (!Results.ContainsKey("Pareto Front")) {
582        sp = new ScatterPlot();
583        sp.Rows.Add(new ScatterPlotDataRow("Pareto Front", "", pf) { VisualProperties = { PointSize = 5 } });
584        Results.AddOrUpdateResult("Pareto Front", sp);
585      } else {
586        sp = (ScatterPlot)Results["Pareto Front"].Value;
587        sp.Rows["Pareto Front"].Points.Replace(pf);
588      }
589    }
590
591    #region operator wiring and events
592    protected void ExecuteOperation(ExecutionContext executionContext, CancellationToken cancellationToken, IOperation operation) {
593      Stack<IOperation> executionStack = new Stack<IOperation>();
594      executionStack.Push(operation);
595      while (executionStack.Count > 0) {
596        cancellationToken.ThrowIfCancellationRequested();
597        IOperation next = executionStack.Pop();
598        if (next is OperationCollection) {
599          OperationCollection coll = (OperationCollection)next;
600          for (int i = coll.Count - 1; i >= 0; i--)
601            if (coll[i] != null) executionStack.Push(coll[i]);
602        } else if (next is IAtomicOperation) {
603          IAtomicOperation op = (IAtomicOperation)next;
604          next = op.Operator.Execute((IExecutionContext)op, cancellationToken);
605          if (next != null) executionStack.Push(next);
606        }
607      }
608    }
609
610    private void UpdateAnalyzers() {
611      Analyzer.Operators.Clear();
612      if (Problem != null) {
613        foreach (IAnalyzer analyzer in Problem.Operators.OfType<IAnalyzer>()) {
614          foreach (IScopeTreeLookupParameter param in analyzer.Parameters.OfType<IScopeTreeLookupParameter>())
615            param.Depth = 1;
616          Analyzer.Operators.Add(analyzer, analyzer.EnabledByDefault);
617        }
618      }
619    }
620
621    private void UpdateCrossovers() {
622      ICrossover oldCrossover = CrossoverParameter.Value;
623      CrossoverParameter.ValidValues.Clear();
624      ICrossover defaultCrossover = Problem.Operators.OfType<ICrossover>().FirstOrDefault();
625
626      foreach (ICrossover crossover in Problem.Operators.OfType<ICrossover>().OrderBy(x => x.Name))
627        CrossoverParameter.ValidValues.Add(crossover);
628
629      if (oldCrossover != null) {
630        ICrossover crossover = CrossoverParameter.ValidValues.FirstOrDefault(x => x.GetType() == oldCrossover.GetType());
631        if (crossover != null) CrossoverParameter.Value = crossover;
632        else oldCrossover = null;
633      }
634      if (oldCrossover == null && defaultCrossover != null)
635        CrossoverParameter.Value = defaultCrossover;
636    }
637
638    private void UpdateMutators() {
639      IManipulator oldMutator = MutatorParameter.Value;
640      MutatorParameter.ValidValues.Clear();
641      IManipulator defaultMutator = Problem.Operators.OfType<IManipulator>().FirstOrDefault();
642
643      foreach (IManipulator mutator in Problem.Operators.OfType<IManipulator>().OrderBy(x => x.Name))
644        MutatorParameter.ValidValues.Add(mutator);
645
646      if (oldMutator != null) {
647        IManipulator mutator = MutatorParameter.ValidValues.FirstOrDefault(x => x.GetType() == oldMutator.GetType());
648        if (mutator != null) MutatorParameter.Value = mutator;
649        else oldMutator = null;
650      }
651
652      if (oldMutator == null && defaultMutator != null)
653        MutatorParameter.Value = defaultMutator;
654    }
655
656    protected override void OnProblemChanged() {
657      UpdateCrossovers();
658      UpdateMutators();
659      UpdateAnalyzers();
660      base.OnProblemChanged();
661    }
662
663    protected override void OnExecutionStateChanged() {
664      previousExecutionState = executionState;
665      executionState = ExecutionState;
666      base.OnExecutionStateChanged();
667    }
668
669    public void ClearState() {
670      if (solutions != null) {
671        solutions.Clear();
672      }
673      if (population != null) {
674        population.Clear();
675      }
676      if (offspringPopulation != null) {
677        offspringPopulation.Clear();
678      }
679      if (jointPopulation != null) {
680        jointPopulation.Clear();
681      }
682      lambda = null;
683      neighbourhood = null;
684      if (executionContext != null && executionContext.Scope != null) {
685        executionContext.Scope.SubScopes.Clear();
686      }
687    }
688
689    protected override void OnStopped() {
690      ClearState();
691      base.OnStopped();
692    }
693    #endregion
694  }
695}
Note: See TracBrowser for help on using the repository browser.