Free cookie consent management tool by TermsFeed Policy Generator

source: branches/ichiriac/HeuristicLab.Algorithms.GDE3/GDE3.cs @ 13749

Last change on this file since 13749 was 13749, checked in by ichiriac, 8 years ago

Add GDE3 algorithm implementation

File size: 24.7 KB
Line 
1using System;
2using System.Linq;
3using System.Collections.Generic;
4using HeuristicLab.Analysis;
5using HeuristicLab.Common;
6using HeuristicLab.Core;
7using HeuristicLab.Data;
8using HeuristicLab.Encodings.RealVectorEncoding;
9using HeuristicLab.Operators;
10using HeuristicLab.Optimization;
11using HeuristicLab.Optimization.Operators;
12using HeuristicLab.Parameters;
13using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
14using HeuristicLab.PluginInfrastructure;
15using HeuristicLab.Problems.MultiObjectiveTestFunctions;
16using HeuristicLab.Random;
17using System.Threading;
18
19namespace HeuristicLab.Algoritms.GDE3
20{
21
22    [Item("Generalized Differential Evolution (GDE3)", "A generalized differential evolution algorithm.")]
23    [StorableClass]
24    [Creatable(CreatableAttribute.Categories.PopulationBasedAlgorithms, Priority = 400)]
25    public class GDE3 : BasicAlgorithm
26    {
27        public Func<IEnumerable<double>, double> Evaluation;
28        private enum DominationResult { Dominates, IsDominated, IsNonDominated };
29        IComparer<RealVector> dominance;
30        public double[] ReferencePoint(int objectives)
31        {
32            return new double[] { 11, 11 };
33        }
34
35        public override Type ProblemType
36        {
37            get { return typeof(MultiObjectiveTestFunctionProblem); }
38        }
39         public new MultiObjectiveTestFunctionProblem Problem
40        {
41            get { return (MultiObjectiveTestFunctionProblem)base.Problem; }
42            set { base.Problem = value; }
43        }
44
45        public ILookupParameter<DoubleMatrix> BestKnownFrontParameter
46        {
47            get
48            {
49                return (ILookupParameter<DoubleMatrix>)Parameters["BestKnownFront"];
50            }
51        }
52
53        private readonly IRandom _random = new MersenneTwister();
54        private int evals;
55
56        #region ParameterNames
57        private const string MaximumEvaluationsParameterName = "Maximum Evaluations";
58        private const string CrossoverProbabilityParameterName = "CrossoverProbability";
59        private const string PopulationSizeParameterName = "PopulationSize";
60        private const string ScalingFactorParameterName = "ScalingFactor";
61        #endregion
62
63        #region ParameterProperties
64        public IFixedValueParameter<IntValue> MaximumEvaluationsParameter
65        {
66            get { return (IFixedValueParameter<IntValue>)Parameters[MaximumEvaluationsParameterName]; }
67        }
68        private ValueParameter<IntValue> PopulationSizeParameter
69        {
70            get { return (ValueParameter<IntValue>)Parameters[PopulationSizeParameterName]; }
71        }
72        public ValueParameter<DoubleValue> CrossoverProbabilityParameter
73        {
74            get { return (ValueParameter<DoubleValue>)Parameters[CrossoverProbabilityParameterName]; }
75        }
76        public ValueParameter<DoubleValue> ScalingFactorParameter
77        {
78            get { return (ValueParameter<DoubleValue>)Parameters[ScalingFactorParameterName]; }
79        }
80        #endregion
81
82        #region Properties
83        public int MaximumEvaluations
84        {
85            get { return MaximumEvaluationsParameter.Value.Value; }
86            set { MaximumEvaluationsParameter.Value.Value = value; }
87        }
88
89        public Double CrossoverProbability
90        {
91            get { return CrossoverProbabilityParameter.Value.Value; }
92            set { CrossoverProbabilityParameter.Value.Value = value; }
93        }
94        public Double ScalingFactor
95        {
96            get { return ScalingFactorParameter.Value.Value; }
97            set { ScalingFactorParameter.Value.Value = value; }
98        }
99        public IntValue PopulationSize
100        {
101            get { return PopulationSizeParameter.Value; }
102            set { PopulationSizeParameter.Value = value; }
103        }
104        #endregion
105
106        #region ResultsProperties
107        private double ResultsBestQuality
108        {
109            get { return ((DoubleValue)Results["Best Quality"].Value).Value; }
110            set { ((DoubleValue)Results["Best Quality"].Value).Value = value; }
111        }
112
113        private double ResultsGenerationalDistance
114        {
115            get { return ((DoubleValue)Results["InvertedGenerationalDistance"].Value).Value; }
116            set { ((DoubleValue)Results["InvertedGenerationalDistance"].Value).Value = value; }
117        }
118
119        private double ResultsHypervolume
120        {
121            get { return ((DoubleValue)Results["HipervolumeValue"].Value).Value; }
122            set { ((DoubleValue)Results["HipervolumeValue"].Value).Value = value; }
123        }
124
125        private DoubleMatrix ResultsBestFront
126        {
127            get { return (DoubleMatrix)Results["Best Front"].Value; }
128            set { Results["Best Front"].Value = value; }
129        }
130
131        private int ResultsEvaluations
132        {
133            get { return ((IntValue)Results["Evaluations"].Value).Value; }
134            set { ((IntValue)Results["Evaluations"].Value).Value = value; }
135        }
136        private int ResultsIterations
137        {
138            get { return ((IntValue)Results["Iterations"].Value).Value; }
139            set { ((IntValue)Results["Iterations"].Value).Value = value; }
140        }
141
142        private DataTable ResultsQualities
143        {
144            get { return ((DataTable)Results["Qualities"].Value); }
145        }
146        private DataRow ResultsQualitiesBest
147        {
148            get { return ResultsQualities.Rows["Best Quality"]; }
149        }
150
151        #endregion
152
153        [Storable]
154        private RankBasedParetoFrontAnalyzer paretoFrontAnalyzer;
155
156        [StorableConstructor]
157        protected GDE3(bool deserializing) : base(deserializing) { }
158
159        protected GDE3(GDE3 original, Cloner cloner)
160          : base(original, cloner)
161        {
162            paretoFrontAnalyzer = (RankBasedParetoFrontAnalyzer)cloner.Clone(original.paretoFrontAnalyzer);
163        }
164
165        public override IDeepCloneable Clone(Cloner cloner)
166        {
167            return new GDE3(this, cloner);
168        }
169
170        public GDE3()
171        {
172            Parameters.Add(new FixedValueParameter<IntValue>(MaximumEvaluationsParameterName, "", new IntValue(Int32.MaxValue)));
173            Parameters.Add(new ValueParameter<IntValue>(PopulationSizeParameterName, "The size of the population of solutions.", new IntValue(100)));
174            Parameters.Add(new ValueParameter<DoubleValue>(CrossoverProbabilityParameterName, "The value for crossover rate", new DoubleValue(0.5)));
175            Parameters.Add(new ValueParameter<DoubleValue>(ScalingFactorParameterName, "The value for scaling factor", new DoubleValue(0.5)));
176            Parameters.Add(new LookupParameter<DoubleMatrix>("BestKnownFront", "The currently best known Pareto front"));
177        }
178
179        protected override void Run(CancellationToken cancellationToken)
180        {
181            // Set up the results display
182            Results.Add(new Result("Iterations", new IntValue(0)));
183            Results.Add(new Result("Evaluations", new IntValue(0)));
184            Results.Add(new Result("Best Front", new DoubleMatrix()));
185            Results.Add(new Result("InvertedGenerationalDistance", new DoubleValue(0)));
186            Results.Add(new Result("HipervolumeValue", new DoubleValue(0)));
187            Results.Add(new Result("Scatterplot", typeof(IMOFrontModel)));
188            var table = new DataTable("Qualities");
189            table.Rows.Add(new DataRow("Best Quality"));
190            Results.Add(new Result("Qualities", table));
191
192            //create initial population
193            var population = new List<SolutionSet>(PopulationSizeParameter.Value.Value);
194            var offspringPopulation = new List<SolutionSet>(PopulationSizeParameter.Value.Value);
195            var matingPopulation = new List<SolutionSet>();
196
197            for (int i = 0; i < PopulationSizeParameter.Value.Value; ++i)
198            {
199                var m = createIndividual();
200                population.Add(m);
201                var n = createEmptyIndividual();
202                offspringPopulation.Add(n);
203            }
204
205            this.initProgress();
206            int iterations = 1;
207
208            while (ResultsEvaluations < MaximumEvaluations
209               && !cancellationToken.IsCancellationRequested)
210            {
211                matingPopulation = selection(population);
212                offspringPopulation = reproduction(matingPopulation, population, offspringPopulation);
213
214                population = replacement(population, offspringPopulation);
215
216                double[][] qualitiesFinal = new double[PopulationSizeParameter.Value.Value][];
217
218                for (int i = 0; i < PopulationSizeParameter.Value.Value; ++i)
219                {
220                    qualitiesFinal[i] = new double[Problem.Objectives];
221                    for (int j = 0; j < Problem.Objectives; ++j)
222                    {
223                        qualitiesFinal[i][j] = population[i].Quality[j];
224                    }
225                }
226
227                double[][] populationFinal = new double[PopulationSizeParameter.Value.Value][];
228
229                for (int i = 0; i < PopulationSizeParameter.Value.Value; ++i)
230                {
231                    populationFinal[i] = new double[Problem.ProblemSize];
232                    for (int j = 0; j < Problem.ProblemSize; ++j)
233                    {
234                        populationFinal[i][j] = population[i].Population[j];
235                    }
236                }
237
238                int objectives = Problem.Objectives;
239                var optimalfront = Problem.TestFunction.OptimalParetoFront(objectives);
240
241                IEnumerable<double[]> en = qualitiesFinal;
242
243                double[][] opf = new double[0][];
244                if (optimalfront != null)
245                {
246                    opf = optimalfront.Select(s => s.ToArray()).ToArray();
247                }
248
249                iterations = iterations + 1;
250
251                IEnumerable<double[]> front = NonDominatedSelect.selectNonDominatedVectors(qualitiesFinal, Problem.TestFunction.Maximization(objectives), true);
252                //update the results
253                ResultsEvaluations = evals;
254                ResultsIterations = iterations;
255                ResultsBestFront = new DoubleMatrix(MultiObjectiveTestFunctionProblem.To2D(qualitiesFinal));
256                ResultsGenerationalDistance = InvertedGenerationalDistance.Calculate(en, optimalfront, 1);
257                ResultsHypervolume = Hypervolume.Calculate(front, ReferencePoint(objectives), Problem.TestFunction.Maximization(objectives));
258
259                Results["Scatterplot"].Value = new MOSolution(qualitiesFinal, populationFinal, opf, objectives);
260            }
261        }
262       
263        protected SolutionSet createIndividual()
264        {
265            var dim = Problem.ProblemSize;
266            var lb = Problem.Bounds[0, 0];
267            var ub = Problem.Bounds[0, 1];
268            var range = ub - lb;
269            var v = new double[Problem.ProblemSize];
270            SolutionSet solutionObject = new SolutionSet(PopulationSizeParameter.Value.Value);
271
272            for (int i = 0; i < Problem.ProblemSize; ++i)
273            {
274                v[i] = _random.NextDouble() * range + lb;
275
276            }
277            var m = new RealVector(v);
278            solutionObject.Population = m;
279            solutionObject.Quality = Problem.Evaluate(m, _random);
280            return solutionObject;
281        }
282
283        private SolutionSet createEmptyIndividual()
284        {
285            SolutionSet solutionObject = new SolutionSet(PopulationSizeParameter.Value.Value);
286            var n = new RealVector(Problem.ProblemSize);
287            solutionObject.Population = n;
288            return solutionObject;
289        }
290
291        protected void initProgress()
292        {
293            this.evals = PopulationSizeParameter.Value.Value;
294        }
295
296        protected void updateProgres()
297        {
298            this.evals += PopulationSizeParameter.Value.Value;
299        }
300
301        protected List<SolutionSet> selection(List<SolutionSet> population)
302        {
303            List<SolutionSet> parents = new List<SolutionSet>();
304            for (int i = 0; i < PopulationSizeParameter.Value.Value; i++)
305            {
306                int r0, r1, r2;
307                //assure the selected vectors r0, r1 and r2 are different
308                do
309                {
310                    r0 = _random.Next(0, PopulationSizeParameter.Value.Value);
311                } while (r0 == i);
312                do
313                {
314                    r1 = _random.Next(0, PopulationSizeParameter.Value.Value);
315                } while (r1 == i || r1 == r0);
316                do
317                {
318                    r2 = _random.Next(0, PopulationSizeParameter.Value.Value);
319                } while (r2 == i || r2 == r0 || r2 == r1);
320
321                parents.Add(population[r0]);
322                parents.Add(population[r1]);
323                parents.Add(population[r2]);
324            }
325            return parents;
326        }
327
328        protected List<SolutionSet> reproduction(List<SolutionSet> matingPopulation, List<SolutionSet> parentPopulation, List<SolutionSet> offspringPopulation)
329        {
330            for (int i = 0; i < PopulationSizeParameter.Value.Value; i++)
331            {
332                List<SolutionSet> parents = new List<SolutionSet>(3);
333                for (int j = 0; j < 3; j++) {
334                    parents.Add(matingPopulation[0]);
335                    matingPopulation.RemoveAt(0);
336                }
337
338                double rnbr = _random.Next(0, Problem.ProblemSize);
339                for (int m = 0; m < Problem.ProblemSize; m++)
340                {
341                    if (_random.NextDouble() < CrossoverProbabilityParameter.Value.Value || m == rnbr)
342                    {
343                        offspringPopulation[i].Population[m] = parents[2].Population[m] +
344                            ScalingFactorParameter.Value.Value * (parents[1].Population[m] - parents[2].Population[0]);
345                        //check the problem upper and lower bounds
346                        if (offspringPopulation[i].Population[m] > Problem.Bounds[0, 1]) offspringPopulation[i].Population[m] = Problem.Bounds[0, 1];
347                        if (offspringPopulation[i].Population[m] < Problem.Bounds[0, 0]) offspringPopulation[i].Population[m] = Problem.Bounds[0, 0];
348                    }
349                    else
350                    {
351                        offspringPopulation[i].Population[m] = parentPopulation[i].Population[m]; // check again
352                    }
353                }
354                offspringPopulation[i].Quality = Problem.Evaluate(offspringPopulation[i].Population, _random);
355            }
356            this.updateProgres();
357            return offspringPopulation;
358        }
359
360        private List<SolutionSet> replacement(List<SolutionSet> population, List<SolutionSet> offspringPopulation)
361        {
362            List<SolutionSet> tmpList = new List<SolutionSet>();
363            for (int i = 0; i < PopulationSizeParameter.Value.Value; i++)
364            {
365                int result;
366                result = compareDomination(population[i].Quality, offspringPopulation[i].Quality);
367                if (result == -1)
368                { // Solution i dominates child
369                    tmpList.Add(population[i]);
370                }
371                else if (result == 1)
372                { // child dominates
373                    tmpList.Add(offspringPopulation[i]);
374                }
375                else
376                { // the two solutions are non-dominated
377                    tmpList.Add(offspringPopulation[i]);
378                    tmpList.Add(population[i]);
379                }
380            }
381
382            List<SolutionSet>[]ranking = computeRanking(tmpList);
383            List<SolutionSet> finalPopulation = crowdingDistanceSelection(ranking);
384            return finalPopulation;
385        }
386
387        private List<SolutionSet> crowdingDistanceSelection(List<SolutionSet>[] ranking)
388        {
389            List<SolutionSet> population = new List<SolutionSet>();
390            int rankingIndex = 0;
391            while (populationIsNotFull(population))
392            {
393                if (subFrontFillsIntoThePopulation(ranking, rankingIndex, population)){
394                    addRankedSolutionToPopulation(ranking, rankingIndex, population);
395                    rankingIndex++;
396                } else {
397                    crowdingDistanceAssignment(ranking[rankingIndex], rankingIndex);
398                    addLastRankedSolutionToPopulation(ranking, rankingIndex, population);
399                }
400            }
401            return population;
402        }
403
404        private void addLastRankedSolutionToPopulation(List<SolutionSet>[] ranking, int rankingIndex, List<SolutionSet> population)
405        {
406            List<SolutionSet> currentRankedFront = ranking[rankingIndex];
407            currentRankedFront.Sort((x, y) => x.CrowdingDistance.CompareTo(y.CrowdingDistance));
408            int i = 0;
409            while (population.Count < PopulationSizeParameter.Value.Value)
410            {
411                population.Add(currentRankedFront[i]);
412                i++;
413            }
414        }
415
416        public void crowdingDistanceAssignment(List<SolutionSet> rankingSubfront, int index)
417        {
418            int size = rankingSubfront.Count;
419
420            if (size == 0)
421                return;
422
423            if (size == 1)
424            {
425                rankingSubfront[0].CrowdingDistance = double.PositiveInfinity;
426                return;
427            }
428
429            if (size == 2)
430            {
431                rankingSubfront[0].CrowdingDistance = double.PositiveInfinity;
432                rankingSubfront[1].CrowdingDistance = double.PositiveInfinity;
433                return;
434            }
435
436            //Use a new SolutionSet to evite alter original solutionSet
437            List<SolutionSet> front = new List<SolutionSet>(size);
438            for (int i = 0; i < size; i++)
439            {
440                front.Add(rankingSubfront[i]);
441            }
442
443            for (int i = 0; i < size; i++)
444                rankingSubfront[i].CrowdingDistance = 0.0;
445
446            double objetiveMaxn;
447            double objetiveMinn;
448            double distance;
449
450            for (int i = 0; i < Problem.Objectives ; i++)
451            {
452                // Sort the population by Obj n           
453                front.Sort((x, y) => x.Quality[i].CompareTo(y.Quality[i]));
454                objetiveMinn = front[0].Quality[i];
455                objetiveMaxn = front[front.Count - 1].Quality[i];
456
457                //Set de crowding distance           
458                front[0].CrowdingDistance = double.PositiveInfinity;
459                front[size - 1].CrowdingDistance = double.PositiveInfinity;
460
461                for (int j = 1; j < size - 1; j++)
462                {
463                    distance = front[j + 1].Quality[i] - front[j - 1].Quality[i];
464                    distance = distance / (objetiveMaxn - objetiveMinn);
465                    distance += front[j].CrowdingDistance;
466                    front[j].CrowdingDistance = distance;
467                }
468            }
469        }
470
471        private void addRankedSolutionToPopulation(List<SolutionSet>[] ranking, int rankingIndex, List<SolutionSet> population)
472        {
473            foreach(SolutionSet solution in ranking[rankingIndex])
474            {
475                population.Add(solution);
476            }
477        }
478
479        private bool subFrontFillsIntoThePopulation(List<SolutionSet>[] ranking, int rankingIndex, List<SolutionSet> population)
480        {
481            return ranking[rankingIndex].Count < (PopulationSizeParameter.Value.Value - population.Count);
482        }
483
484        private bool populationIsNotFull(List<SolutionSet> population)
485        {
486            return population.Count < PopulationSizeParameter.Value.Value;
487        }
488
489        private List<SolutionSet>[] computeRanking(List<SolutionSet> tmpList)
490        {
491            // dominateMe[i] contains the number of solutions dominating i       
492            int[] dominateMe = new int[tmpList.Count];
493
494            // iDominate[k] contains the list of solutions dominated by k
495            List<int>[] iDominate = new List<int>[tmpList.Count];
496
497            // front[i] contains the list of individuals belonging to the front i
498            List<int>[] front = new List<int>[tmpList.Count + 1];
499            int[] solutionsRanks = new int[tmpList.Count];
500
501            // flagDominate is an auxiliar encodings.variable
502            int flagDominate;
503
504            // Initialize the fronts
505            for (int i = 0; i < front.Length; i++)
506            {
507                front[i] = new List<int>();
508            }
509
510            //-> Fast non dominated sorting algorithm
511            // Contribution of Guillaume Jacquenot
512            for (int p = 0; p < tmpList.Count; p++)
513            {
514                // Initialize the list of individuals that i dominate and the number
515                // of individuals that dominate me
516                iDominate[p] = new List<int>();
517                dominateMe[p] = 0;
518            }
519            for (int p = 0; p < (tmpList.Count - 1); p++)
520            {
521                // For all q individuals , calculate if p dominates q or vice versa
522                for (int q = p + 1; q < tmpList.Count; q++)
523                {
524                    flagDominate = compareDomination(tmpList[p].Quality, tmpList[q].Quality);
525                    if (flagDominate == -1)
526                    {
527                        iDominate[p].Add(q);
528                        dominateMe[q]++;
529                    }
530                    else if (flagDominate == 1)
531                    {
532                        iDominate[q].Add(p);
533                        dominateMe[p]++;
534                    }
535                }
536                // If nobody dominates p, p belongs to the first front
537            }
538            for (int i = 0; i < tmpList.Count; i++)
539            {
540                if (dominateMe[i] == 0)
541                {
542                    front[0].Add(i);
543                    tmpList[i].Rank = 0;
544                }
545            }
546
547            //Obtain the rest of fronts
548            int k = 0;
549
550            while (front[k].Count != 0)
551            {
552                k++;
553                foreach (var it1 in front[k - 1])
554                {
555                    foreach (var it2 in iDominate[it1])
556                    {
557                        int index = it2;
558                        dominateMe[index]--;
559                        if (dominateMe[index] == 0)
560                        {
561                            front[k].Add(index);
562                            tmpList[index].Rank = k;
563                        }
564                    }
565                }
566            }
567            //<-
568
569            var rankedSubpopulation = new List<SolutionSet>[k];
570            //0,1,2,....,i-1 are front, then i fronts
571            for (int j = 0; j < k; j++)
572            {
573                rankedSubpopulation[j] = new List<SolutionSet>(front[j].Count);
574                foreach (var it1 in front[j])
575                {
576                    rankedSubpopulation[j].Add(tmpList[it1]);
577                }
578            }
579            return rankedSubpopulation;
580        }
581
582        private int compareDomination(double[] solution1, double[] solution2)
583        {
584            int dominate1; // dominate1 indicates if some objective of solution1
585                           // dominates the same objective in solution2. dominate2
586            int dominate2; // is the complementary of dominate1.
587
588            dominate1 = 0;
589            dominate2 = 0;
590
591            int flag; //stores the result of the comparison
592
593            // Equal number of violated constraints. Applying a dominance Test then
594            double value1, value2;
595            for (int i = 0; i < Problem.Objectives; i++)
596            {
597                value1 = solution1[i];
598                value2 = solution2[i];
599                if (value1 < value2)
600                {
601                    flag = -1;
602                }
603                else if (value1 > value2)
604                {
605                    flag = 1;
606                }
607                else
608                {
609                    flag = 0;
610                }
611
612                if (flag == -1)
613                {
614                    dominate1 = 1;
615                }
616
617                if (flag == 1)
618                {
619                    dominate2 = 1;
620                }
621            }
622
623            if (dominate1 == dominate2)
624            {
625                return 0; //No one dominate the other
626            }
627            if (dominate1 == 1)
628            {
629                return -1; // solution1 dominate
630            }
631            return 1;    // solution2 dominate   
632        }
633    }
634}
635
636
637
Note: See TracBrowser for help on using the repository browser.