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

Last change on this file since 16583 was 16583, checked in by bburlacu, 4 months ago

#2987: Implement better uniform weight generation, objective scaling, algorithm Pause support.

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