Free cookie consent management tool by TermsFeed Policy Generator

source: branches/3057_DynamicALPS/backup/13022020/HeuristicLab.Algorithms.DynamicALPS/3.4/DynamicALPSAlgorithmBase.cs @ 17479

Last change on this file since 17479 was 17479, checked in by kyang, 4 years ago

#3057

  1. upload the latest version of ALPS with SMS-EMOA
  2. upload the related dynamic test problems (dynamic, single-objective symbolic regression), written by David Daninel.
File size: 37.3 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
22// 03/02/2020
23// TODO LIST:                                                                     
24// 1. Dynamic reference point strategy                                               
25// 2. Normalized fitness value strategy, desibility function.                         
26// 3. HVC calculation should be definitely improved, at least in the 2D case.
27// 4. multiple point strategy when $\lambda>1$
28
29using HEAL.Attic;
30using HeuristicLab.Analysis;
31using HeuristicLab.Common;
32using HeuristicLab.Core;
33using HeuristicLab.Data;
34using HeuristicLab.ExpressionGenerator;
35using HeuristicLab.Optimization;
36using HeuristicLab.Parameters;
37using HeuristicLab.Problems.DataAnalysis;
38using HeuristicLab.Problems.TestFunctions.MultiObjective;
39using HeuristicLab.Random;
40using System;
41using System.Collections.Generic;
42using System.Drawing;
43using System.Linq;
44using CancellationToken = System.Threading.CancellationToken;
45
46namespace HeuristicLab.Algorithms.DynamicALPS {
47  [Item("DynamicALPSAlgorithmBase", "Base class for all DynamicALPS algorithm variants.")]
48  [StorableType("C0141748-DF5A-4CA0-A3DD-1DFB98236F7E")]
49  public abstract class DynamicALPSAlgorithmBase : BasicAlgorithm {
50    #region data members
51 
52    [StorableType("75C9EA99-D699-4A1F-8AB2-AB86B7A2FD68")]
53    protected enum NeighborType { NEIGHBOR, POPULATION }
54
55
56    [StorableType("2A71E397-05CE-460F-B982-EE2F4B37C354")]
57    // TCHE = Chebyshev (Tchebyshev)
58    // PBI  = Penalty-based boundary intersection
59    // AGG  = Weighted sum
60    public enum FunctionType { TCHE, PBI, AGG }
61
62    [Storable]
63    protected double[] IdealPoint { get; set; }
64    [Storable]
65    protected double[] NadirPoint { get; set; } // potentially useful for objective normalization
66
67    [Storable]
68    protected double[][] lambda_moead;
69
70    [Storable]
71    protected int[][] neighbourhood;
72
73    [Storable]
74    protected IDynamicALPSSolution[] solutions;
75
76    [Storable]
77    protected FunctionType functionType;
78
79    [Storable]
80    protected IDynamicALPSSolution[] population;
81
82    [Storable]
83    protected IDynamicALPSSolution[][] layerPopulation;
84
85    [Storable]
86    protected IDynamicALPSSolution[][] layerOffspringPopulation;
87
88    [Storable]
89    protected IDynamicALPSSolution[][] layerJointPopulation;
90
91    [Storable]
92    protected IDynamicALPSSolution[] offspringPopulation;
93
94    //[Storable]
95    //protected IDynamicALPSSolution[] jointPopulation;
96
97    [Storable]
98    protected int evaluatedSolutions;
99
100    [Storable]
101    protected ExecutionContext executionContext;
102
103    [Storable]
104    protected IScope globalScope;
105
106    [Storable]
107    protected ExecutionState previousExecutionState;
108
109    [Storable]
110    protected ExecutionState executionState;
111
112    private DoubleArray ReferencePoint {
113      get {
114        var problem = (MultiObjectiveTestFunctionProblem)Problem;
115        return problem.ReferencePoint;
116      }
117    }
118    #endregion
119
120    #region parameters
121    private const string SeedParameterName = "Seed";
122    private const string SetSeedRandomlyParameterName = "SetSeedRandomly";
123    private const string PopulationSizeParameterName = "PopulationSize";
124    private const string ResultPopulationSizeParameterName = "ResultPopulationSize";
125    private const string CrossoverProbabilityParameterName = "CrossoverProbability";
126    private const string CrossoverParameterName = "Crossover";
127    private const string MutationProbabilityParameterName = "MutationProbability";
128    private const string MutatorParameterName = "Mutator";
129    private const string MaximumEvaluatedSolutionsParameterName = "MaximumEvaluatedSolutions";
130    private const string RandomParameterName = "Random";
131    private const string AnalyzerParameterName = "Analyzer";
132    // MOEA-D parameters
133    //private const string NeighbourSizeParameterName = "NeighbourSize";
134    //private const string NeighbourhoodSelectionProbabilityParameterName = "NeighbourhoodSelectionProbability";
135    //private const string MaximumNumberOfReplacedSolutionsParameterName = "MaximumNumberOfReplacedSolutions";
136    //private const string FunctionTypeParameterName = "FunctionType";
137    // private const string NormalizeObjectivesParameterName = "NormalizeObjectives";
138
139    // SMS-EMOA parameters:
140    private const string LambdaParameterName = "Lambda";   // The number of offspring size
141    private const string ALPSLayersParameterName = "ALPSLayers";   // The number of offspring size
142    private const string ALPSAgeGapParameterName = "ALPSAgeGap";   // The number of offspring size
143
144
145
146    // "Parameters" are defined in "HeuristicLab.Parameters"
147    // Contains: generic parameters of every class/algorithm/instance,
148    // It seems that "I***ValueParameter" is declared in "Heuristic.core", where "***ValueParameter" are defined in "HeuristicLab.Parameter"
149    // The function of "I***ValueParameter" is to bridge current scripts to "HeuristicLab.Parameter".
150    public IValueParameter<MultiAnalyzer> AnalyzerParameter {
151      get { return (ValueParameter<MultiAnalyzer>)Parameters[AnalyzerParameterName]; }
152    }
153
154    //public IConstrainedValueParameter<StringValue> FunctionTypeParameter
155    //{
156    //  get { return (IConstrainedValueParameter<StringValue>)Parameters[FunctionTypeParameterName]; }
157    //}
158    //public IFixedValueParameter<IntValue> NeighbourSizeParameter
159    //{
160    //  get { return (IFixedValueParameter<IntValue>)Parameters[NeighbourSizeParameterName]; }
161    //}
162    //public IFixedValueParameter<BoolValue> NormalizeObjectivesParameter
163    //{
164    //  get { return (IFixedValueParameter<BoolValue>)Parameters[NormalizeObjectivesParameterName]; }
165    //}
166    //public IFixedValueParameter<IntValue> MaximumNumberOfReplacedSolutionsParameter
167    //{
168    //  get { return (IFixedValueParameter<IntValue>)Parameters[MaximumNumberOfReplacedSolutionsParameterName]; }
169    //}
170    //public IFixedValueParameter<DoubleValue> NeighbourhoodSelectionProbabilityParameter
171    //{
172    //  get { return (IFixedValueParameter<DoubleValue>)Parameters[NeighbourhoodSelectionProbabilityParameterName]; }
173    //}
174    public IFixedValueParameter<IntValue> SeedParameter {
175      get { return (IFixedValueParameter<IntValue>)Parameters[SeedParameterName]; }
176    }
177    public IFixedValueParameter<BoolValue> SetSeedRandomlyParameter {
178      get { return (IFixedValueParameter<BoolValue>)Parameters[SetSeedRandomlyParameterName]; }
179    }
180    private IValueParameter<IntValue> PopulationSizeParameter {
181      get { return (IValueParameter<IntValue>)Parameters[PopulationSizeParameterName]; }
182    }
183    // KF, SMS-EMOA
184    private IValueParameter<IntValue> LambdaParameter {
185      get { return (IValueParameter<IntValue>)Parameters[LambdaParameterName]; }
186    }
187    //// KF, DynamicALPS
188    private IValueParameter<IntValue> ALPSLayersParameter{
189      get { return (IValueParameter<IntValue>)Parameters[ALPSLayersParameterName]; }
190    }
191    private IValueParameter<IntValue> ALPSAgeGapParameter {
192      get { return (IValueParameter<IntValue>)Parameters[ALPSAgeGapParameterName]; }
193    }
194
195    private IValueParameter<IntValue> ResultPopulationSizeParameter {
196      get { return (IValueParameter<IntValue>)Parameters[ResultPopulationSizeParameterName]; }
197    }
198
199    public IValueParameter<PercentValue> CrossoverProbabilityParameter {
200      get { return (IValueParameter<PercentValue>)Parameters[CrossoverProbabilityParameterName]; }
201    }
202    public IConstrainedValueParameter<ICrossover> CrossoverParameter {
203      get { return (IConstrainedValueParameter<ICrossover>)Parameters[CrossoverParameterName]; }
204    }
205    public IValueParameter<PercentValue> MutationProbabilityParameter {
206      get { return (IValueParameter<PercentValue>)Parameters[MutationProbabilityParameterName]; }
207    }
208    public IConstrainedValueParameter<IManipulator> MutatorParameter {
209      get { return (IConstrainedValueParameter<IManipulator>)Parameters[MutatorParameterName]; }
210    }
211    public IValueParameter<IntValue> MaximumEvaluatedSolutionsParameter {
212      get { return (IValueParameter<IntValue>)Parameters[MaximumEvaluatedSolutionsParameterName]; }
213    }
214    public IValueParameter<IRandom> RandomParameter {
215      get { return (IValueParameter<IRandom>)Parameters[RandomParameterName]; }
216    }
217    #endregion
218
219    #region parameter properties
220    public new IMultiObjectiveHeuristicOptimizationProblem Problem {
221      get { return (IMultiObjectiveHeuristicOptimizationProblem)base.Problem; }
222      set { base.Problem = value; }
223    }
224    public int Seed {
225      get { return SeedParameter.Value.Value; }
226      set { SeedParameter.Value.Value = value; }
227    }
228    public bool SetSeedRandomly {
229      get { return SetSeedRandomlyParameter.Value.Value; }
230      set { SetSeedRandomlyParameter.Value.Value = value; }
231    }
232    public IntValue PopulationSize {
233      get { return PopulationSizeParameter.Value; }
234      set { PopulationSizeParameter.Value = value; }
235    }
236    public IntValue Lambda {
237      get { return LambdaParameter.Value; }
238      set { LambdaParameter.Value = value; }
239    }
240
241    public IntValue ResultPopulationSize {
242      get { return ResultPopulationSizeParameter.Value; }
243      set { ResultPopulationSizeParameter.Value = value; }
244    }
245
246    public IntValue ALPSLayers {
247      get { return ALPSLayersParameter.Value; }
248      set { ALPSLayersParameter.Value = value; }
249    }
250
251    public IntValue ALPSAgeGap {
252      get { return ALPSAgeGapParameter.Value; }
253      set { ALPSAgeGapParameter.Value = value; }
254    }
255
256    public PercentValue CrossoverProbability {
257      get { return CrossoverProbabilityParameter.Value; }
258      set { CrossoverProbabilityParameter.Value = value; }
259    }
260    public ICrossover Crossover {
261      get { return CrossoverParameter.Value; }
262      set { CrossoverParameter.Value = value; }
263    }
264    public PercentValue MutationProbability {
265      get { return MutationProbabilityParameter.Value; }
266      set { MutationProbabilityParameter.Value = value; }
267    }
268    public IManipulator Mutator {
269      get { return MutatorParameter.Value; }
270      set { MutatorParameter.Value = value; }
271    }
272    public MultiAnalyzer Analyzer {
273      get { return AnalyzerParameter.Value; }
274      set { AnalyzerParameter.Value = value; }
275    }
276    public IntValue MaximumEvaluatedSolutions {
277      get { return MaximumEvaluatedSolutionsParameter.Value; }
278      set { MaximumEvaluatedSolutionsParameter.Value = value; }
279    }
280    #endregion
281
282    #region constructors
283    public DynamicALPSAlgorithmBase() {
284      // Add or define or specify the parameters that may be use in SMS-EMOA.   
285      // ***("Name", "Description", "Value")
286      //  Name                            Type                Description
287      //  FixedValueParameter:            ANY                 Not changed???
288      //  ValueParameter:                                     Changable??? What is the difference between "ValueParameter" and "FixedVlaueParameter"?????
289
290
291      // types:
292      //      IntValue
293      //      BoolValue
294      //      DoubleValue
295      //      PercentValue
296      //      ICrossover:       
297      //      IManipulator:     
298      //      IRandom:         
299      //      MultiAnalyzer:   
300      //      ---------
301      Parameters.Add(new FixedValueParameter<IntValue>(SeedParameterName, "The random seed used to initialize the new pseudo random number generator.", new IntValue(0)));
302      Parameters.Add(new FixedValueParameter<BoolValue>(SetSeedRandomlyParameterName, "True if the random seed should be set to a random value, otherwise false.", new BoolValue(true)));
303      Parameters.Add(new ValueParameter<IntValue>(PopulationSizeParameterName, "The size of the population of solutions.", new IntValue(100)));
304      Parameters.Add(new ValueParameter<IntValue>(ResultPopulationSizeParameterName, "The size of the population of solutions.", new IntValue(100)));
305      Parameters.Add(new ValueParameter<PercentValue>(CrossoverProbabilityParameterName, "The probability that the crossover operator is applied.", new PercentValue(0.9)));
306      Parameters.Add(new ConstrainedValueParameter<ICrossover>(CrossoverParameterName, "The operator used to cross solutions."));
307      Parameters.Add(new ValueParameter<PercentValue>(MutationProbabilityParameterName, "The probability that the mutation operator is applied on a solution.", new PercentValue(0.25)));
308      Parameters.Add(new ConstrainedValueParameter<IManipulator>(MutatorParameterName, "The operator used to mutate solutions."));
309      Parameters.Add(new ValueParameter<MultiAnalyzer>("Analyzer", "The operator used to analyze each generation.", new MultiAnalyzer()));
310      Parameters.Add(new ValueParameter<IntValue>(MaximumEvaluatedSolutionsParameterName, "The maximum number of evaluated solutions (approximately).", new IntValue(100_000)));
311      Parameters.Add(new ValueParameter<IRandom>(RandomParameterName, new FastRandom()));
312
313      // SMS-EMOA, kf
314      Parameters.Add(new ValueParameter<IntValue>(LambdaParameterName, "The size of the offsprings. Now, it only works when lambda = 1", new IntValue(1)));
315      // DynamicALPS, KF
316      Parameters.Add(new ValueParameter<IntValue>(ALPSLayersParameterName, "Test, maximum = 1000, defualt is 1", new IntValue(10)));
317      Parameters.Add(new ValueParameter<IntValue>(ALPSAgeGapParameterName, "Test, maximum = 1000, defualt is 20", new IntValue(20)));
318     
319
320    }
321
322    protected DynamicALPSAlgorithmBase(DynamicALPSAlgorithmBase original, Cloner cloner) : base(original, cloner) {
323      functionType = original.functionType;
324      evaluatedSolutions = original.evaluatedSolutions;
325      previousExecutionState = original.previousExecutionState;
326
327      if (original.IdealPoint != null) {
328        IdealPoint = (double[])original.IdealPoint.Clone();
329      }
330
331      if (original.NadirPoint != null) {
332        NadirPoint = (double[])original.NadirPoint.Clone();
333      }
334
335      if (original.lambda_moead != null) {
336        lambda_moead = (double[][])original.lambda_moead.Clone();
337      }
338
339      if (original.neighbourhood != null) {
340        neighbourhood = (int[][])original.neighbourhood.Clone();
341      }
342
343      if (original.solutions != null) {
344        solutions = original.solutions.Select(cloner.Clone).ToArray();
345      }
346
347      if (original.population != null) {
348        population = original.population.Select(cloner.Clone).ToArray();
349      }
350
351      if (original.offspringPopulation != null) {
352        offspringPopulation = original.offspringPopulation.Select(cloner.Clone).ToArray();
353      }
354
355      //if (original.jointPopulation != null) {
356      //  jointPopulation = original.jointPopulation.Select(x => cloner.Clone(x)).ToArray();
357      //}
358
359      if (original.executionContext != null) {
360        executionContext = cloner.Clone(original.executionContext);
361      }
362
363      if (original.globalScope != null) {
364        globalScope = cloner.Clone(original.globalScope);
365      }
366    }
367
368
369
370    [StorableConstructor]
371    protected DynamicALPSAlgorithmBase(StorableConstructorFlag deserializing) : base(deserializing) { }
372    #endregion
373
374    private void InitializePopulation(ExecutionContext executionContext, CancellationToken cancellationToken, IRandom random, bool[] maximization) {
375      // creator: how to create the initilized population. "UniformRandom" is used here.
376      // TODO: LHS, latin hypercube sampling? Exisit???
377      var creator = Problem.SolutionCreator;
378      var evaluator = Problem.Evaluator;
379
380      // dimensions: objective space
381      var dimensions = maximization.Length;
382      var populationSize = PopulationSize.Value;
383      population = new IDynamicALPSSolution[populationSize];
384
385      var parentScope = executionContext.Scope;
386      // first, create all individuals
387      for (int i = 0; i < populationSize; ++i) {
388        var childScope = new Scope(i.ToString()) { Parent = parentScope };
389        ExecuteOperation(executionContext, cancellationToken, executionContext.CreateChildOperation(creator, childScope));
390        parentScope.SubScopes.Add(childScope);
391      }
392
393      for (int i = 0; i < populationSize; ++i) {
394        var childScope = parentScope.SubScopes[i];
395        ExecuteOperation(executionContext, cancellationToken, executionContext.CreateChildOperation(evaluator, childScope));
396
397        var qualities = (DoubleArray)childScope.Variables["Qualities"].Value;
398
399        // solution: a method, contains a decision vector and objecitve values     
400        //    solution.Qualities:     objective values, fitness values
401        //    solution.Individual:    decision vector
402        var solution = new DynamicALPSSolution(childScope, dimensions, 0);
403        for (int j = 0; j < dimensions; ++j) {
404          // TODO: convert maximization problems into minimization problems.
405          solution.Qualities[j] = maximization[j] ? 1 - qualities[j] : qualities[j];
406        }
407
408        // population is a collection of solution. 
409        population[i] = solution;
410
411        // KF, DyanmicALPS
412        population[i].HypervolumeContribution[0] = -0;
413        population[i].NondominanceRanking[0] = -0;
414        population[i].Age = 1;
415        population[i].IndividualPc = CrossoverProbability.Value;
416        population[i].IndividualPc = MutationProbability.Value;
417      }
418    }
419
420    protected void InitializeAlgorithm(CancellationToken cancellationToken) { // Type of random operator, "FastRandom" in this script.
421      // RandomParameter <-- Parameters in "HeuristicLab.Core.ParameterizedNameItem",
422      var rand = RandomParameter.Value;
423
424      // Initialize random seed
425      // If random seed exist, get it; otherwise,
426      if (SetSeedRandomly) Seed = RandomSeedGenerator.GetSeed();
427
428      // Call
429      rand.Reset(Seed);
430
431      bool[] maximization = ((BoolArray)Problem.MaximizationParameter.ActualValue).CloneAsArray();
432
433      // dimensions: the dimension in an objective space
434      var dimensions = maximization.Length;
435
436
437      var populationSize = PopulationSize.Value;
438
439      InitializePopulation(executionContext, cancellationToken, rand, maximization);
440
441      IdealPoint = new double[dimensions];
442      IdealPoint.UpdateIdeal(population);
443
444      NadirPoint = Enumerable.Repeat(double.MinValue, dimensions).ToArray();
445      //NadirPoint = new double[dimensions];
446      NadirPoint.UpdateNadir(population);
447
448
449      evaluatedSolutions = populationSize;
450    }
451
452    protected override void Initialize(CancellationToken cancellationToken) {
453      globalScope = new Scope("Global Scope");
454      executionContext = new ExecutionContext(null, this, globalScope);
455
456      // set the execution context for parameters to allow lookup
457      foreach (var parameter in Problem.Parameters.OfType<IValueParameter>()) {
458        // we need all of these in order for the wiring of the operators to work
459        globalScope.Variables.Add(new Variable(parameter.Name, parameter.Value));
460      }
461      globalScope.Variables.Add(new Variable("Results", Results)); // make results available as a parameter for analyzers etc.
462
463      base.Initialize(cancellationToken);
464    }
465
466    public override bool SupportsPause => true;
467
468
469
470
471    // Mate Selection.
472    // Randomly select a specific number of individuals for later operators.
473    // Inputs:
474    //    1. random:                      Random number generate method
475    //    2. numberOfSolutionToSelect:    The number of selection   
476    // Outputs:
477    //    1. listOfSolutions:             The selection individuals
478    protected List<int> MatingSelection(IRandom random, int numberOfSolutionsToSelect) {
479      int populationSize = PopulationSize.Value;
480
481      var listOfSolutions = new List<int>(numberOfSolutionsToSelect);
482
483      while (listOfSolutions.Count < numberOfSolutionsToSelect) {
484        var selectedSolution = random.Next(populationSize);
485
486        bool flag = true;
487        foreach (int individualId in listOfSolutions) {
488          if (individualId == selectedSolution) {
489            flag = false;
490            break;
491          }
492        }
493
494        if (flag) {
495          listOfSolutions.Add(selectedSolution);
496        }
497      }
498      return listOfSolutions;
499    }
500
501    protected void ApplyCrossover(int lambda) {
502    }
503
504    protected void ApplyMutation(int lambda) {
505    }
506
507
508    protected void ApplyEvaluation(int lambda) {
509    }
510
511    protected void ApplyMateSelection(int rho) {
512    }
513
514
515    // Select/Discard the individual(s) according to HVC
516    protected void SmetricSelection(int lambda, int nLayerALPS) {
517      var wholePopulation = layerJointPopulation[nLayerALPS];
518      var qualities = wholePopulation.Select(x => x.Qualities).ToArray();
519
520      var maximization = Enumerable.Repeat(false, IdealPoint.Length).ToArray(); // Minimization or maximization ????
521      var pf2 = DominationCalculator<IDynamicALPSSolution>.CalculateAllParetoFronts(wholePopulation, qualities, maximization, out int[] ranking);
522
523      int numberOfLayer;             // number of layers in PF
524      int numberOfLastLayer;          // number of discarded points in PF (the number of points in the last layer)
525
526      pf2.RemoveAt(pf2.Count() - 1);
527      numberOfLayer = pf2.Count();
528      numberOfLastLayer = pf2[numberOfLayer - 1].Count();
529      double[] hvc = new double[numberOfLastLayer];
530      int discardIndex;
531      if (numberOfLastLayer > lambda) {
532        double tempHV;
533        double smetric;
534        var lastLayer = pf2.Last();
535
536        // TODO: This can be use for dynamic reference point strategy later. Kaifeng , 02/2020
537        // smetric = Hypervolume.Calculate(lastLayer.Select(x => x.Item2), Enumerable.Repeat(11d, NadirPoint.Length).ToArray(), maximization);
538        var reference = ReferencePoint.ToArray();
539        var nondominated = NonDominatedSelect.GetDominatingVectors(lastLayer.Select(x => x.Item2), reference, maximization, false);
540        smetric = nondominated.Any() ? Hypervolume.Calculate(nondominated, reference, maximization) : int.MinValue;
541
542        for (int ii = 0; ii < lastLayer.Count; ++ii) {
543          try { // TODO: This can be use for dynamic reference point strategy later. Kaifeng , 02/2020
544            // tempHV = Hypervolume.Calculate(indices.Where(idx => idx != ii).Select(idx => lastLayer[idx].Item2), Enumerable.Repeat(11d, NadirPoint.Length).ToArray(), maximization);
545            tempHV = Hypervolume.Calculate(Enumerable.Range(0, lastLayer.Count).Where(idx => idx != ii).Select(idx => lastLayer[idx].Item2), reference, maximization);
546          }
547          catch {
548            tempHV = int.MinValue;
549          }
550          hvc[ii] = smetric - tempHV;
551          tempHV = 0;
552        }
553        discardIndex = Array.IndexOf(hvc, hvc.Min());
554        pf2[numberOfLayer - 1].RemoveAt(discardIndex);
555      }
556      else {
557        // TODO: This should be updated when $lambda > 1$
558        pf2.RemoveAt(pf2.Count() - 1);
559        numberOfLayer = numberOfLayer - 1;
560      }
561      layerPopulation[nLayerALPS] = pf2.SelectMany(x => x.Select(y => y.Item1)).ToArray();
562    }
563
564    protected int SMSEMOA(int populationSize, int lambda, int counterLayerALPS) {
565      var innerToken = new CancellationToken();
566      bool[] maximization = ((BoolArray)Problem.MaximizationParameter.ActualValue).CloneAsArray();
567      var maximumEvaluatedSolutions = MaximumEvaluatedSolutions.Value;
568      var crossover = Crossover;
569      var crossoverProbability = CrossoverProbability.Value;
570      var mutator = Mutator;
571      var mutationProbability = MutationProbability.Value;
572      var evaluator = Problem.Evaluator;
573      var analyzer = Analyzer;
574      var rand = RandomParameter.Value;
575
576
577      int indexOffspring = 0;
578      var mates = MatingSelection(rand, 2); // select parents
579                                            //var s1 = (IScope)population[mates[0]].Individual.Clone();
580                                            //var s2 = (IScope)population[mates[1]].Individual.Clone();
581                                            //var ages = population.Select(x => x.Age).ToArray();
582
583      var s1 = (IScope)layerPopulation[counterLayerALPS][mates[0]].Individual.Clone();
584      var s2 = (IScope)layerPopulation[counterLayerALPS][mates[1]].Individual.Clone();
585      var ages = layerPopulation[counterLayerALPS].Select(x => x.Age).ToArray();
586
587      var s1_age = ages[mates[0]];
588      var s2_age = ages[mates[1]];
589      int offSpringAge = 0;
590      s1.Parent = s2.Parent = globalScope;
591      IScope childScope = null;
592
593      // crossover
594      if (rand.NextDouble() < crossoverProbability) {
595        childScope = new Scope($"{mates[0]}+{mates[1]}") { Parent = executionContext.Scope };
596        childScope.SubScopes.Add(s1);
597        childScope.SubScopes.Add(s2);
598        var opCrossover = executionContext.CreateChildOperation(crossover, childScope);
599        ExecuteOperation(executionContext, innerToken, opCrossover);
600        offSpringAge = Math.Max(s1_age, s2_age) + 1;
601        childScope.SubScopes.Clear(); // <<-- VERY IMPORTANT!
602      }
603      else { // MUTATION   POLISHI
604        if (childScope == null) {
605          offSpringAge = ages[mates[0]] + 1;
606        }
607        else {
608        }
609        childScope = childScope ?? s1;
610        var opMutation = executionContext.CreateChildOperation(mutator, childScope);
611        ExecuteOperation(executionContext, innerToken, opMutation);
612      }
613      if (childScope != null) { // Evaluate the childScope
614        var opEvaluation = executionContext.CreateChildOperation(evaluator, childScope);
615        ExecuteOperation(executionContext, innerToken, opEvaluation);
616        // childScope
617        var qualities = (DoubleArray)childScope.Variables["Qualities"].Value;
618        var childSolution = new DynamicALPSSolution(childScope, maximization.Length, 0);
619        // set child qualities
620        for (int j = 0; j < maximization.Length; ++j) {
621          childSolution.Qualities[j] = maximization[j] ? 1 - qualities[j] : qualities[j];
622        }
623        IdealPoint.UpdateIdeal(childSolution.Qualities);
624        NadirPoint.UpdateNadir(childSolution.Qualities);
625        // TODO, KF -- For later usage when $lambda > 1$
626        childSolution.HypervolumeContribution = null;
627        childSolution.NondominanceRanking = null;
628        childSolution.Age = offSpringAge;
629        layerOffspringPopulation[counterLayerALPS][indexOffspring] = childSolution;
630        ++evaluatedSolutions;
631        indexOffspring += 1;
632      }
633      else {
634        // no crossover or mutation were applied, a child was not produced, do nothing
635      }
636
637
638      layerJointPopulation[counterLayerALPS] = new IDynamicALPSSolution[populationSize + lambda];
639      layerPopulation[counterLayerALPS].CopyTo(layerJointPopulation[counterLayerALPS], 0);
640      layerOffspringPopulation[counterLayerALPS].CopyTo(layerJointPopulation[counterLayerALPS], populationSize);
641
642      SmetricSelection(lambda, counterLayerALPS);   // SMS-EMOA
643      return evaluatedSolutions;
644    }
645
646
647
648
649
650
651
652    // Update the Pareto-front approximation set and scatter the solutions in PF approximation set.
653    protected void UpdateParetoFronts() {
654      //var qualities = population.Select(x => Enumerable.Range(0, NadirPoint.Length).Select(i => x.Qualities[i] / NadirPoint[i]).ToArray()).ToArray();
655      var qualities = population.Select(x => x.Qualities).ToArray();
656      var maximization = Enumerable.Repeat(false, IdealPoint.Length).ToArray();                             // DynamicALPS minimizes everything internally
657      var pf = DominationCalculator<IDynamicALPSSolution>.CalculateBestParetoFront(population, qualities, maximization);
658
659      var pf2 = DominationCalculator<IDynamicALPSSolution>.CalculateAllParetoFronts(population, qualities, maximization, out int[] ranking);
660      var n = (int)EnumerableExtensions.BinomialCoefficient(IdealPoint.Length, 2);
661
662
663      // Struture hypervolume
664      // [0,0]:  Value of HV
665      // [0,1]:  PF size, $|PF|$
666      var hypervolumes = new DoubleMatrix(n == 1 ? 1 : n + 1, 2) { ColumnNames = new[] { "PF hypervolume", "PF size" } };
667
668
669      // HV calculation
670      // pf.Select(x => x.Item2): the "Item2" in var "pd"
671      // Enumerable.Repeat(1d, NadirPoint.Length).ToArray():     reference point
672      // maximization:   type of optimization problem:
673      //               True:  maximization problem
674      //               False: minimization problem
675      var reference = ReferencePoint.ToArray();
676      var nondominated = NonDominatedSelect.GetDominatingVectors(pf.Select(x => x.Item2), reference, maximization, false);
677      hypervolumes[0, 0] = nondominated.Any() ? Hypervolume.Calculate(nondominated, reference, maximization) : int.MinValue;
678
679      //hypervolumes[0, 0] = Hypervolume.Calculate(pf.Select(x => x.Item2), reference, maximization);
680      hypervolumes[0, 1] = pf.Count;
681      Console.WriteLine("Current HV is", hypervolumes[0, 0]);
682
683      var elementNames = new List<string>() { "Pareto Front" };
684
685      ResultCollection results;
686      if (Results.ContainsKey("Hypervolume Analysis")) {
687        results = (ResultCollection)Results["Hypervolume Analysis"].Value;
688      }
689      else {
690        results = new ResultCollection();
691        Results.AddOrUpdateResult("Hypervolume Analysis", results);
692      }
693
694      ScatterPlot sp;
695      if (IdealPoint.Length == 2) {
696        var points = pf.Select(x => new Point2D<double>(x.Item2[0], x.Item2[1]));
697        var r = OnlinePearsonsRCalculator.Calculate(points.Select(x => x.X), points.Select(x => x.Y), out OnlineCalculatorError error);
698        if (error != OnlineCalculatorError.None) { r = double.NaN; }
699        var resultName = "Pareto Front Analysis ";
700        if (!results.ContainsKey(resultName)) {
701          sp = new ScatterPlot() {
702            VisualProperties = {
703              XAxisMinimumAuto = false, XAxisMinimumFixedValue = 0d, XAxisMaximumAuto = false, XAxisMaximumFixedValue = 1d,
704              YAxisMinimumAuto = false, YAxisMinimumFixedValue = 0d, YAxisMaximumAuto = false, YAxisMaximumFixedValue = 1d
705            }
706          };
707          sp.Rows.Add(new ScatterPlotDataRow(resultName, "", points) { VisualProperties = { PointSize = 8 } });
708          results.AddOrUpdateResult(resultName, sp);
709        }
710        else {
711          sp = (ScatterPlot)results[resultName].Value;
712          sp.Rows[resultName].Points.Replace(points);
713        }
714        sp.Name = $"Dimensions [0, 1], correlation: {r.ToString("N2")}";
715      }
716      else if (IdealPoint.Length > 2) {
717        var indices = Enumerable.Range(0, IdealPoint.Length).ToArray();
718        var visualProperties = new ScatterPlotDataRowVisualProperties { PointSize = 8, Color = Color.LightGray };
719        var combinations = indices.Combinations(2).ToArray();
720        var maximization2d = new[] { false, false };
721        var solutions2d = pf.Select(x => x.Item1).ToArray();
722        for (int i = 0; i < combinations.Length; ++i) {
723          var c = combinations[i].ToArray();
724
725          // calculate the hypervolume in the 2d coordinate space
726          var reference2d = new[] { 1d, 1d };
727          var qualities2d = pf.Select(x => new[] { x.Item2[c[0]], x.Item2[c[1]] }).ToArray();
728          var pf2d = DominationCalculator<IDynamicALPSSolution>.CalculateBestParetoFront(solutions2d, qualities2d, maximization2d);
729
730          hypervolumes[i + 1, 0] = pf2d.Count > 0 ? Hypervolume.Calculate(pf2d.Select(x => x.Item2), reference2d, maximization2d) : 0d;
731          hypervolumes[i + 1, 1] = pf2d.Count;
732
733          var resultName = $"Pareto Front Analysis [{c[0]}, {c[1]}]";
734          elementNames.Add(resultName);
735
736          var points = pf.Select(x => new Point2D<double>(x.Item2[c[0]], x.Item2[c[1]]));
737          var pf2dPoints = pf2d.Select(x => new Point2D<double>(x.Item2[0], x.Item2[1]));
738
739          if (!results.ContainsKey(resultName)) {
740            sp = new ScatterPlot() {
741              VisualProperties = {
742                XAxisMinimumAuto = false, XAxisMinimumFixedValue = 0d, XAxisMaximumAuto = false, XAxisMaximumFixedValue = 1d,
743                YAxisMinimumAuto = false, YAxisMinimumFixedValue = 0d, YAxisMaximumAuto = false, YAxisMaximumFixedValue = 1d
744              }
745            };
746            sp.Rows.Add(new ScatterPlotDataRow("Pareto Front", "", points) { VisualProperties = visualProperties });
747            sp.Rows.Add(new ScatterPlotDataRow($"Pareto Front [{c[0]}, {c[1]}]", "", pf2dPoints) { VisualProperties = { PointSize = 10, Color = Color.OrangeRed } });
748            results.AddOrUpdateResult(resultName, sp);
749          }
750          else {
751            sp = (ScatterPlot)results[resultName].Value;
752            sp.Rows["Pareto Front"].Points.Replace(points);
753            sp.Rows[$"Pareto Front [{c[0]}, {c[1]}]"].Points.Replace(pf2dPoints);
754          }
755          var r = OnlinePearsonsRCalculator.Calculate(points.Select(x => x.X), points.Select(x => x.Y), out OnlineCalculatorError error);
756          var r2 = r * r;
757          sp.Name = $"Pareto Front [{c[0]}, {c[1]}], correlation: {r2.ToString("N2")}";
758        }
759      }
760      hypervolumes.RowNames = elementNames;
761      results.AddOrUpdateResult("Hypervolumes", hypervolumes);
762    }
763
764    #region operator wiring and events
765    protected void ExecuteOperation(ExecutionContext executionContext, CancellationToken cancellationToken, IOperation operation) {
766      Stack<IOperation> executionStack = new Stack<IOperation>();
767      executionStack.Push(operation);
768      while (executionStack.Count > 0) {
769        cancellationToken.ThrowIfCancellationRequested();
770        IOperation next = executionStack.Pop();
771        if (next is OperationCollection) {
772          OperationCollection coll = (OperationCollection)next;
773          for (int i = coll.Count - 1; i >= 0; i--)
774            if (coll[i] != null) executionStack.Push(coll[i]);
775        }
776        else if (next is IAtomicOperation) {
777          IAtomicOperation op = (IAtomicOperation)next;
778          next = op.Operator.Execute((IExecutionContext)op, cancellationToken);
779          if (next != null) executionStack.Push(next);
780        }
781      }
782    }
783
784    private void UpdateAnalyzers() {
785      Analyzer.Operators.Clear();
786      if (Problem != null) {
787        foreach (IAnalyzer analyzer in Problem.Operators.OfType<IAnalyzer>()) {
788          foreach (IScopeTreeLookupParameter param in analyzer.Parameters.OfType<IScopeTreeLookupParameter>())
789            param.Depth = 1;
790          Analyzer.Operators.Add(analyzer, analyzer.EnabledByDefault);
791        }
792      }
793    }
794
795    private void UpdateCrossovers() {
796      ICrossover oldCrossover = CrossoverParameter.Value;
797      CrossoverParameter.ValidValues.Clear();
798      ICrossover defaultCrossover = Problem.Operators.OfType<ICrossover>().FirstOrDefault();
799
800      foreach (ICrossover crossover in Problem.Operators.OfType<ICrossover>().OrderBy(x => x.Name))
801        CrossoverParameter.ValidValues.Add(crossover);
802
803      if (oldCrossover != null) {
804        ICrossover crossover = CrossoverParameter.ValidValues.FirstOrDefault(x => x.GetType() == oldCrossover.GetType());
805        if (crossover != null) CrossoverParameter.Value = crossover;
806        else oldCrossover = null;
807      }
808      if (oldCrossover == null && defaultCrossover != null)
809        CrossoverParameter.Value = defaultCrossover;
810    }
811
812    private void UpdateMutators() {
813      IManipulator oldMutator = MutatorParameter.Value;
814      MutatorParameter.ValidValues.Clear();
815      IManipulator defaultMutator = Problem.Operators.OfType<IManipulator>().FirstOrDefault();
816
817      foreach (IManipulator mutator in Problem.Operators.OfType<IManipulator>().OrderBy(x => x.Name))
818        MutatorParameter.ValidValues.Add(mutator);
819
820      if (oldMutator != null) {
821        IManipulator mutator = MutatorParameter.ValidValues.FirstOrDefault(x => x.GetType() == oldMutator.GetType());
822        if (mutator != null) MutatorParameter.Value = mutator;
823        else oldMutator = null;
824      }
825
826      if (oldMutator == null && defaultMutator != null)
827        MutatorParameter.Value = defaultMutator;
828    }
829
830    protected override void OnProblemChanged() {
831      UpdateCrossovers();
832      UpdateMutators();
833      UpdateAnalyzers();
834      base.OnProblemChanged();
835    }
836
837    protected override void OnExecutionStateChanged() {
838      previousExecutionState = executionState;
839      executionState = ExecutionState;
840      base.OnExecutionStateChanged();
841    }
842
843    public void ClearState() {
844      solutions = null;
845      population = null;
846      offspringPopulation = null;
847      //jointPopulation = null;
848      lambda_moead = null;
849      neighbourhood = null;
850      if (executionContext != null && executionContext.Scope != null) {
851        executionContext.Scope.SubScopes.Clear();
852      }
853    }
854
855    protected override void OnStopped() {
856      ClearState();
857      base.OnStopped();
858    }
859    #endregion
860  }
861}
Note: See TracBrowser for help on using the repository browser.