Free cookie consent management tool by TermsFeed Policy Generator

source: branches/2780_SAPBA/HeuristicLab.Algorithms.SAPBA/Strategies/LamarckianStrategy.cs @ 16386

Last change on this file since 16386 was 16108, checked in by bwerth, 6 years ago

#2780 renamed branch to include ticket number

File size: 13.2 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.Collections.Generic;
24using System.Linq;
25using HeuristicLab.Algorithms.DataAnalysis;
26using HeuristicLab.Algorithms.EGO;
27using HeuristicLab.Algorithms.SAPBA.Operators;
28using HeuristicLab.Analysis;
29using HeuristicLab.Common;
30using HeuristicLab.Core;
31using HeuristicLab.Data;
32using HeuristicLab.Encodings.RealVectorEncoding;
33using HeuristicLab.Optimization;
34using HeuristicLab.Parameters;
35using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
36using HeuristicLab.Problems.DataAnalysis;
37
38namespace HeuristicLab.Algorithms.SAPBA {
39  [StorableClass]
40  public class LamarckianStrategy : InfillStrategy {
41    #region Parameternames
42    public const string NoTrainingPointsParameterName = "Number of Trainingpoints";
43    public const string LocalInfillCriterionParameterName = "LocalInfillCriterion";
44    public const string OptimizationAlgorithmParameterName = "Optimization Algorithm";
45    public const string RegressionAlgorithmParameterName = "Regression Algorithm";
46    #endregion
47    #region Parameters
48    public IFixedValueParameter<IntValue> NoTrainingPointsParameter => Parameters[NoTrainingPointsParameterName] as IFixedValueParameter<IntValue>;
49    public IValueParameter<IAlgorithm> OptimizationAlgorithmParameter => Parameters[OptimizationAlgorithmParameterName] as IValueParameter<IAlgorithm>;
50    public IValueParameter<IDataAnalysisAlgorithm<IRegressionProblem>> RegressionAlgorithmParameter => Parameters[RegressionAlgorithmParameterName] as IValueParameter<IDataAnalysisAlgorithm<IRegressionProblem>>;
51    public IConstrainedValueParameter<IInfillCriterion> LocalInfillCriterionParameter => Parameters[LocalInfillCriterionParameterName] as IConstrainedValueParameter<IInfillCriterion>;
52    #endregion
53    #region Properties
54    public IntValue NoTrainingPoints => NoTrainingPointsParameter.Value;
55    public IAlgorithm OptimizationAlgorithm => OptimizationAlgorithmParameter.Value;
56    public IDataAnalysisAlgorithm<IRegressionProblem> RegressionAlgorithm => RegressionAlgorithmParameter.Value;
57    public IInfillCriterion LocalInfillCriterion => LocalInfillCriterionParameter.Value;
58    #endregion
59
60    #region Constructors
61    [StorableConstructor]
62    protected LamarckianStrategy(bool deserializing) : base(deserializing) { }
63    [StorableHook(HookType.AfterDeserialization)]
64    private void AfterDeserialization() {
65      RegisterParameterEvents();
66    }
67    protected LamarckianStrategy(LamarckianStrategy original, Cloner cloner) : base(original, cloner) {
68      RegisterParameterEvents();
69    }
70    public LamarckianStrategy() {
71      var localCritera = new ItemSet<IInfillCriterion> { new ExpectedQuality(), new ExpectedImprovement(), new AugmentedExpectedImprovement(), new ExpectedQuantileImprovement(), new MinimalQuantileCriterium(), new PluginExpectedImprovement() };
72      var osEs = new OffspringSelectionEvolutionStrategy.OffspringSelectionEvolutionStrategy {
73        Problem = new InfillProblem(),
74        ComparisonFactor = { Value = 1.0 },
75        MaximumGenerations = { Value = 1000 },
76        MaximumEvaluatedSolutions = { Value = 100000 },
77        PlusSelection = { Value = true },
78        PopulationSize = { Value = 1 }
79      };
80      osEs.MutatorParameter.Value = osEs.MutatorParameter.ValidValues.OfType<MultiRealVectorManipulator>().First();
81      Parameters.Add(new FixedValueParameter<IntValue>(NoTrainingPointsParameterName, "The number of sample points used to create a local model", new IntValue(50)));
82      Parameters.Add(new ConstrainedValueParameter<IInfillCriterion>(LocalInfillCriterionParameterName, "The infill criterion used to cheaply evaluate points.", localCritera, localCritera.First()));
83      Parameters.Add(new ValueParameter<IAlgorithm>(OptimizationAlgorithmParameterName, "The algorithm used to solve the expected improvement subproblem", osEs));
84      Parameters.Add(new ValueParameter<IDataAnalysisAlgorithm<IRegressionProblem>>(RegressionAlgorithmParameterName, "The model used to approximate the problem", new GaussianProcessRegression { Problem = new RegressionProblem() }));
85      RegisterParameterEvents();
86    }
87    public override IDeepCloneable Clone(Cloner cloner) {
88      return new LamarckianStrategy(this, cloner);
89    }
90    #endregion
91
92    //Short lived stores for analysis
93    private readonly List<double> LamarckValues = new List<double>();
94    private readonly List<double> SampleValues = new List<double>();
95
96    protected override void Initialize() {
97      base.Initialize();
98      var infillProblem = OptimizationAlgorithm.Problem as InfillProblem;
99      if (infillProblem == null) throw new ArgumentException("InfillOptimizationAlgorithm does not have an InfillProblem.");
100      infillProblem.InfillCriterion = LocalInfillCriterion;
101    }
102    protected override void Analyze(Individual[] individuals, double[] qualities, ResultCollection results, ResultCollection globalResults, IRandom random) {
103      base.Analyze(individuals, qualities, results, globalResults, random);
104      const string plotName = "Lamarck Comparison";
105      const string lamarckRow = "Lamarck Values";
106      const string samplesRow = "Original Values";
107      if (!globalResults.ContainsKey(plotName))
108        globalResults.Add(new Result(plotName, new DataTable(plotName)));
109
110      var plot = (DataTable)globalResults[plotName].Value;
111      if (!plot.Rows.ContainsKey(lamarckRow)) plot.Rows.Add(new DataRow(lamarckRow));
112      if (!plot.Rows.ContainsKey(samplesRow)) plot.Rows.Add(new DataRow(samplesRow));
113      plot.Rows[lamarckRow].Values.AddRange(LamarckValues);
114      plot.Rows[samplesRow].Values.AddRange(SampleValues);
115      LamarckValues.Clear();
116      SampleValues.Clear();
117
118      //analyze Hypervolumes
119      const string volPlotName = "Hypervolumes Comparison";
120      const string mainRowName = "Population Volume (log)";
121      const string subspaceRowName = "Subspace Volume (log) for Lamarck Candidate ";
122      if (!globalResults.ContainsKey(volPlotName))
123        globalResults.Add(new Result(volPlotName, new DataTable(volPlotName)));
124
125      plot = (DataTable)globalResults[volPlotName].Value;
126      if (!plot.Rows.ContainsKey(mainRowName)) plot.Rows.Add(new DataRow(mainRowName));
127      var v = Math.Log(GetStableVolume(GetBoundingBox(individuals.Select(x => x.RealVector()))));
128      plot.Rows[mainRowName].Values.Add(v);
129
130      var indis = individuals
131          .Zip(qualities, (individual, d) => new Tuple<Individual, double>(individual, d))
132          .OrderBy(t => SapbaAlgorithm.Problem.Maximization ? -t.Item2 : t.Item2)
133          .Take(NoIndividuals.Value)
134          .Select(t => t.Item1).ToArray();
135
136      for (var i = 0; i < indis.Length; i++) {
137        var samples = GetNearestSamples(NoTrainingPoints.Value, indis[i].RealVector());
138        var d = Math.Log(GetStableVolume(GetBoundingBox(samples.Select(x => x.Item1))));
139        if (!plot.Rows.ContainsKey(subspaceRowName + i)) plot.Rows.Add(new DataRow(subspaceRowName + i));
140        plot.Rows[subspaceRowName + i].Values.Add(d);
141      }
142
143
144
145    }
146    protected override void ProcessPopulation(Individual[] individuals, double[] qualities, IRandom random) {
147      if (RegressionSolution == null) return;
148      if (Generations < NoGenerations.Value) Generations++;
149      else {
150        //Select best Individuals
151        var indis = individuals
152          .Zip(qualities, (individual, d) => new Tuple<Individual, double>(individual, d))
153          .OrderBy(t => Problem.Maximization ? -t.Item2 : t.Item2)
154          .Take(NoIndividuals.Value)
155          .Select(t => t.Item1).ToArray();
156        //Evaluate individuals
157        foreach (var individual in indis)
158          SampleValues.Add(EvaluateSample(individual.RealVector(), random).Item2);
159
160        //Perform memetic replacement for all points
161        for (var i = 0; i < indis.Length; i++) {
162          var vector = indis[i].RealVector();
163          var altVector = OptimizeInfillProblem(vector, random);
164          LamarckValues.Add(EvaluateSample(altVector, random).Item2);
165          if (LamarckValues[i] < SampleValues[i] == Problem.Maximization) continue;
166          for (var j = 0; j < vector.Length; j++) vector[j] = altVector[j];
167        }
168
169        BuildRegressionSolution(random);
170        Generations = 0;
171      }
172    }
173
174    #region Events
175    private void RegisterParameterEvents() {
176      OptimizationAlgorithmParameter.ValueChanged += OnInfillAlgorithmChanged;
177      OptimizationAlgorithm.ProblemChanged += OnInfillProblemChanged;
178      LocalInfillCriterionParameter.ValueChanged += OnInfillCriterionChanged;
179    }
180    private void OnInfillCriterionChanged(object sender, EventArgs e) {
181      ((InfillProblem)OptimizationAlgorithm.Problem).InfillCriterion = LocalInfillCriterion;
182    }
183    private void OnInfillAlgorithmChanged(object sender, EventArgs e) {
184      OptimizationAlgorithm.Problem = new InfillProblem { InfillCriterion = LocalInfillCriterion };
185      OptimizationAlgorithm.ProblemChanged -= OnInfillProblemChanged; //avoid double attaching
186      OptimizationAlgorithm.ProblemChanged += OnInfillProblemChanged;
187    }
188    private void OnInfillProblemChanged(object sender, EventArgs e) {
189      OptimizationAlgorithm.ProblemChanged -= OnInfillProblemChanged;
190      OptimizationAlgorithm.Problem = new InfillProblem { InfillCriterion = LocalInfillCriterion };
191      OptimizationAlgorithm.ProblemChanged += OnInfillProblemChanged;
192    }
193    #endregion
194
195    #region helpers
196    private RealVector OptimizeInfillProblem(RealVector point, IRandom random) {
197      var infillProblem = OptimizationAlgorithm.Problem as InfillProblem;
198      if (infillProblem == null) throw new ArgumentException("InfillOptimizationAlgorithm does not have an InfillProblem.");
199      if (infillProblem.InfillCriterion != LocalInfillCriterion) throw new ArgumentException("InfillCiriterion for Problem is not correctly set.");
200
201      var points = Math.Min(NoTrainingPoints.Value, Samples.Count);
202      var samples = GetNearestSamples(points, point);
203      var regression = SapbaUtilities.BuildModel(samples, RegressionAlgorithm, random);
204      var box = GetBoundingBox(samples.Select(x => x.Item1));
205
206      infillProblem.Encoding.Length = ((RealVectorEncoding)Problem.Encoding).Length;
207      infillProblem.Encoding.Bounds = box;
208      infillProblem.Encoding.SolutionCreator = new FixedRealVectorCreator(point);
209      infillProblem.Initialize(regression, Problem.Maximization);
210      var res = SapbaUtilities.SyncRunSubAlgorithm(OptimizationAlgorithm, random.Next(int.MaxValue));
211      if (!res.ContainsKey(InfillProblem.BestInfillSolutionResultName)) throw new ArgumentException("The InfillOptimizationAlgorithm did not return a best solution");
212      var v = res[InfillProblem.BestInfillSolutionResultName].Value as RealVector;
213      if (v == null) throw new ArgumentException("The InfillOptimizationAlgorithm did not return the expected result types");
214      if (!InBounds(v, box)) throw new ArgumentException("Vector not in bounds");
215      OptimizationAlgorithm.Runs.Clear();
216      return v;
217    }
218    private Tuple<RealVector, double>[] GetNearestSamples(int noSamples, RealVector point) {
219      return Samples.Select(sample => Tuple.Create(SquaredEuclidean(sample.Item1, point), sample)).OrderBy(x => x.Item1).Take(noSamples).Select(x => x.Item2).ToArray();
220    }
221    private static DoubleMatrix GetBoundingBox(IEnumerable<RealVector> samples) {
222      DoubleMatrix m = null;
223      foreach (var sample in samples)
224        if (m == null) {
225          m = new DoubleMatrix(sample.Length, 2);
226          for (var i = 0; i < sample.Length; i++) m[i, 0] = m[i, 1] = sample[i];
227        } else
228          for (var i = 0; i < sample.Length; i++) {
229            m[i, 0] = Math.Min(m[i, 0], sample[i]);
230            m[i, 1] = Math.Max(m[i, 1], sample[i]);
231          }
232      return m;
233    }
234
235    //the volume of a bounded-box whith slightly increased dimensions (Volume can never reach 0)
236    private static double GetStableVolume(DoubleMatrix bounds) {
237      var res = 1.0;
238      for (var i = 0; i < bounds.Rows; i++) res *= bounds[i, 1] - bounds[i, 0] + 0.1;
239      return res;
240    }
241    private static bool InBounds(RealVector r, DoubleMatrix bounds) {
242      return !r.Where((t, i) => t < bounds[i, 0] || t > bounds[i, 1]).Any();
243    }
244    private static double SquaredEuclidean(RealVector a, RealVector b) {
245      return a.Select((t, i) => t - b[i]).Sum(d => d * d);
246    }
247    #endregion
248  }
249}
Note: See TracBrowser for help on using the repository browser.