Free cookie consent management tool by TermsFeed Policy Generator

source: branches/2521_ProblemRefactoring/HeuristicLab.Algorithms.ParameterlessPopulationPyramid/3.3/ParameterlessPopulationPyramid.cs @ 16752

Last change on this file since 16752 was 16752, checked in by abeham, 5 years ago

#2521: added comment to P3

  • removed todos from EvaluationServiceClientView
File size: 12.4 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2019 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 * and the BEACON Center for the Study of Evolution in Action.
5 *
6 * This file is part of HeuristicLab.
7 *
8 * HeuristicLab is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * HeuristicLab is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
20 */
21#endregion
22
23using System;
24using System.Collections.Generic;
25using System.Linq;
26using System.Threading;
27using HEAL.Attic;
28using HeuristicLab.Analysis;
29using HeuristicLab.Common;
30using HeuristicLab.Core;
31using HeuristicLab.Data;
32using HeuristicLab.Encodings.BinaryVectorEncoding;
33using HeuristicLab.Optimization;
34using HeuristicLab.Parameters;
35using HeuristicLab.Random;
36
37namespace HeuristicLab.Algorithms.ParameterlessPopulationPyramid {
38  // This code is based off the publication
39  // B. W. Goldman and W. F. Punch, "Parameter-less Population Pyramid," GECCO, pp. 785–792, 2014
40  // and the original source code in C++11 available from: https://github.com/brianwgoldman/Parameter-less_Population_Pyramid
41  [Item("Parameter-less Population Pyramid (P3)", "Binary value optimization algorithm which requires no configuration. B. W. Goldman and W. F. Punch, Parameter-less Population Pyramid, GECCO, pp. 785–792, 2014")]
42  [StorableType("CAD84CAB-1ECC-4D76-BDC5-701AAF690E17")]
43  [Creatable(CreatableAttribute.Categories.PopulationBasedAlgorithms, Priority = 400)]
44  public class ParameterlessPopulationPyramid : BasicAlgorithm {
45    public override Type ProblemType {
46      get { return typeof(SingleObjectiveProblem<BinaryVectorEncoding, BinaryVector>); }
47    }
48    // TODO: Type of this property should be ISingleObjectiveProblemDefinition instead of the SingleObjectiveProblem
49    //       However, this requires that BasicAlgorithm's Problem property is also changed
50    public new SingleObjectiveProblem<BinaryVectorEncoding, BinaryVector> Problem {
51      get { return (SingleObjectiveProblem<BinaryVectorEncoding, BinaryVector>)base.Problem; }
52      set { base.Problem = value; }
53    }
54
55    [Storable]
56    private readonly IRandom random = new MersenneTwister();
57    [Storable]
58    private List<Population> pyramid = new List<Population>();
59    [Storable]
60    private EvaluationTracker tracker;
61
62    // Tracks all solutions in Pyramid for quick membership checks
63
64    private HashSet<BinaryVector> seen = new HashSet<BinaryVector>(new EnumerableBoolEqualityComparer());
65    [Storable]
66    private IEnumerable<BinaryVector> StorableSeen {
67      get { return seen; }
68      set { seen = new HashSet<BinaryVector>(value, new EnumerableBoolEqualityComparer()); }
69    }
70
71    #region ParameterNames
72    private const string MaximumIterationsParameterName = "Maximum Iterations";
73    private const string MaximumEvaluationsParameterName = "Maximum Evaluations";
74    private const string MaximumRuntimeParameterName = "Maximum Runtime";
75    private const string SeedParameterName = "Seed";
76    private const string SetSeedRandomlyParameterName = "SetSeedRandomly";
77    #endregion
78
79    #region ParameterProperties
80    public IFixedValueParameter<IntValue> MaximumIterationsParameter {
81      get { return (IFixedValueParameter<IntValue>)Parameters[MaximumIterationsParameterName]; }
82    }
83    public IFixedValueParameter<IntValue> MaximumEvaluationsParameter {
84      get { return (IFixedValueParameter<IntValue>)Parameters[MaximumEvaluationsParameterName]; }
85    }
86    public IFixedValueParameter<IntValue> MaximumRuntimeParameter {
87      get { return (IFixedValueParameter<IntValue>)Parameters[MaximumRuntimeParameterName]; }
88    }
89    public IFixedValueParameter<IntValue> SeedParameter {
90      get { return (IFixedValueParameter<IntValue>)Parameters[SeedParameterName]; }
91    }
92    public FixedValueParameter<BoolValue> SetSeedRandomlyParameter {
93      get { return (FixedValueParameter<BoolValue>)Parameters[SetSeedRandomlyParameterName]; }
94    }
95    #endregion
96
97    #region Properties
98    public int MaximumIterations {
99      get { return MaximumIterationsParameter.Value.Value; }
100      set { MaximumIterationsParameter.Value.Value = value; }
101    }
102    public int MaximumEvaluations {
103      get { return MaximumEvaluationsParameter.Value.Value; }
104      set { MaximumEvaluationsParameter.Value.Value = value; }
105    }
106    public int MaximumRuntime {
107      get { return MaximumRuntimeParameter.Value.Value; }
108      set { MaximumRuntimeParameter.Value.Value = value; }
109    }
110    public int Seed {
111      get { return SeedParameter.Value.Value; }
112      set { SeedParameter.Value.Value = value; }
113    }
114    public bool SetSeedRandomly {
115      get { return SetSeedRandomlyParameter.Value.Value; }
116      set { SetSeedRandomlyParameter.Value.Value = value; }
117    }
118    #endregion
119
120    #region ResultsProperties
121    private double ResultsBestQuality {
122      get { return ((DoubleValue)Results["Best Quality"].Value).Value; }
123      set { ((DoubleValue)Results["Best Quality"].Value).Value = value; }
124    }
125
126    private BinaryVector ResultsBestSolution {
127      get { return (BinaryVector)Results["Best Solution"].Value; }
128      set { Results["Best Solution"].Value = value; }
129    }
130
131    private int ResultsBestFoundOnEvaluation {
132      get { return ((IntValue)Results["Evaluation Best Solution Was Found"].Value).Value; }
133      set { ((IntValue)Results["Evaluation Best Solution Was Found"].Value).Value = value; }
134    }
135
136    private int ResultsEvaluations {
137      get { return ((IntValue)Results["Evaluations"].Value).Value; }
138      set { ((IntValue)Results["Evaluations"].Value).Value = value; }
139    }
140    private int ResultsIterations {
141      get { return ((IntValue)Results["Iterations"].Value).Value; }
142      set { ((IntValue)Results["Iterations"].Value).Value = value; }
143    }
144
145    private DataTable ResultsQualities {
146      get { return ((DataTable)Results["Qualities"].Value); }
147    }
148    private DataRow ResultsQualitiesBest {
149      get { return ResultsQualities.Rows["Best Quality"]; }
150    }
151
152    private DataRow ResultsQualitiesIteration {
153      get { return ResultsQualities.Rows["Iteration Quality"]; }
154    }
155
156
157    private DataRow ResultsLevels {
158      get { return ((DataTable)Results["Pyramid Levels"].Value).Rows["Levels"]; }
159    }
160
161    private DataRow ResultsSolutions {
162      get { return ((DataTable)Results["Stored Solutions"].Value).Rows["Solutions"]; }
163    }
164    #endregion
165
166    public override bool SupportsPause { get { return true; } }
167
168    [StorableConstructor]
169    protected ParameterlessPopulationPyramid(StorableConstructorFlag _) : base(_) { }
170
171    protected ParameterlessPopulationPyramid(ParameterlessPopulationPyramid original, Cloner cloner)
172      : base(original, cloner) {
173      random = cloner.Clone(original.random);
174      pyramid = original.pyramid.Select(cloner.Clone).ToList();
175      tracker = cloner.Clone(original.tracker);
176      seen = new HashSet<BinaryVector>(original.seen.Select(cloner.Clone), new EnumerableBoolEqualityComparer());
177    }
178
179    public override IDeepCloneable Clone(Cloner cloner) {
180      return new ParameterlessPopulationPyramid(this, cloner);
181    }
182
183    public ParameterlessPopulationPyramid() : base() {
184      Parameters.Add(new FixedValueParameter<IntValue>(MaximumIterationsParameterName, "", new IntValue(Int32.MaxValue)));
185      Parameters.Add(new FixedValueParameter<IntValue>(MaximumEvaluationsParameterName, "", new IntValue(Int32.MaxValue)));
186      Parameters.Add(new FixedValueParameter<IntValue>(MaximumRuntimeParameterName, "The maximum runtime in seconds after which the algorithm stops. Use -1 to specify no limit for the runtime", new IntValue(3600)));
187      Parameters.Add(new FixedValueParameter<IntValue>(SeedParameterName, "The random seed used to initialize the new pseudo random number generator.", new IntValue(0)));
188      Parameters.Add(new FixedValueParameter<BoolValue>(SetSeedRandomlyParameterName, "True if the random seed should be set to a random value, otherwise false.", new BoolValue(true)));
189    }
190
191    protected override void OnExecutionTimeChanged() {
192      base.OnExecutionTimeChanged();
193      if (CancellationTokenSource == null) return;
194      if (MaximumRuntime == -1) return;
195      if (ExecutionTime.TotalSeconds > MaximumRuntime) CancellationTokenSource.Cancel();
196    }
197
198    private void AddIfUnique(BinaryVector solution, int level) {
199      // Don't add things you have seen
200      if (seen.Contains(solution)) return;
201      if (level == pyramid.Count) {
202        pyramid.Add(new Population(Problem.Encoding.Length, random));
203      }
204      var copied = (BinaryVector)solution.Clone();
205      pyramid[level].Add(copied);
206      seen.Add(copied);
207    }
208
209    // In the GECCO paper, Figure 1
210    private double iterate() {
211      // Create a random solution
212      BinaryVector solution = new BinaryVector(Problem.Encoding.Length);
213      for (int i = 0; i < solution.Length; i++) {
214        solution[i] = random.Next(2) == 1;
215      }
216      double fitness = tracker.Evaluate(solution, random);
217      fitness = HillClimber.ImproveToLocalOptimum(tracker, solution, fitness, random);
218      AddIfUnique(solution, 0);
219
220      for (int level = 0; level < pyramid.Count; level++) {
221        var current = pyramid[level];
222        double newFitness = LinkageCrossover.ImproveUsingTree(current.Tree, current.Solutions, solution, fitness, tracker, random);
223        // add it to the next level if its a strict fitness improvement
224        if (tracker.IsBetter(newFitness, fitness)) {
225          fitness = newFitness;
226          AddIfUnique(solution, level + 1);
227        }
228      }
229      return fitness;
230    }
231
232    protected override void Initialize(CancellationToken cancellationToken) {
233      // Set up the algorithm
234      if (SetSeedRandomly) Seed = RandomSeedGenerator.GetSeed();
235      pyramid = new List<Population>();
236      seen.Clear();
237      random.Reset(Seed);
238      tracker = new EvaluationTracker(Problem, MaximumEvaluations);
239
240      // Set up the results display
241      Results.Add(new Result("Iterations", new IntValue(0)));
242      Results.Add(new Result("Evaluations", new IntValue(0)));
243      Results.Add(new Result("Best Solution", new BinaryVector(tracker.BestSolution)));
244      Results.Add(new Result("Best Quality", new DoubleValue(tracker.BestQuality)));
245      Results.Add(new Result("Evaluation Best Solution Was Found", new IntValue(tracker.BestFoundOnEvaluation)));
246      var table = new DataTable("Qualities");
247      table.Rows.Add(new DataRow("Best Quality"));
248      var iterationRows = new DataRow("Iteration Quality");
249      iterationRows.VisualProperties.LineStyle = DataRowVisualProperties.DataRowLineStyle.Dot;
250      table.Rows.Add(iterationRows);
251      Results.Add(new Result("Qualities", table));
252
253      table = new DataTable("Pyramid Levels");
254      table.Rows.Add(new DataRow("Levels"));
255      Results.Add(new Result("Pyramid Levels", table));
256
257      table = new DataTable("Stored Solutions");
258      table.Rows.Add(new DataRow("Solutions"));
259      Results.Add(new Result("Stored Solutions", table));
260
261      base.Initialize(cancellationToken);
262    }
263
264    protected override void Run(CancellationToken cancellationToken) {
265      // Loop until iteration limit reached or canceled.
266      while (ResultsIterations < MaximumIterations) {
267        double fitness = double.NaN;
268
269        try {
270          fitness = iterate();
271          ResultsIterations++;
272          cancellationToken.ThrowIfCancellationRequested();
273        }
274        finally {
275          ResultsEvaluations = tracker.Evaluations;
276          ResultsBestSolution = new BinaryVector(tracker.BestSolution);
277          ResultsBestQuality = tracker.BestQuality;
278          ResultsBestFoundOnEvaluation = tracker.BestFoundOnEvaluation;
279          ResultsQualitiesBest.Values.Add(tracker.BestQuality);
280          ResultsQualitiesIteration.Values.Add(fitness);
281          ResultsLevels.Values.Add(pyramid.Count);
282          ResultsSolutions.Values.Add(seen.Count);
283        }
284      }
285    }
286  }
287}
Note: See TracBrowser for help on using the repository browser.