Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.MetaOptimization/HeuristicLab.Problems.MetaOptimization/3.3/Evaluators/ParameterConfigurationEvaluator.cs @ 5357

Last change on this file since 5357 was 5357, checked in by cneumuel, 13 years ago

#1215

  • changed ordering of parameter combinations to make them better readable
  • changed handling of invalid parameter settings from penalty approach to repair approach
File size: 12.5 KB
Line 
1using System;
2using System.Linq;
3using System.Threading;
4using HeuristicLab.Common;
5using HeuristicLab.Core;
6using HeuristicLab.Data;
7using HeuristicLab.Operators;
8using HeuristicLab.Optimization;
9using HeuristicLab.Parameters;
10using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
11using System.Collections.Generic;
12using HeuristicLab.Algorithms.GeneticAlgorithm;
13using System.Threading.Tasks;
14using System.Diagnostics;
15using System.Reflection;
16
17namespace HeuristicLab.Problems.MetaOptimization {
18  /// <summary>
19  /// A base class for operators which evaluate TSP solutions.
20  /// </summary>
21  [Item("ParameterConfigurationEvaluator", "A base class for operators which evaluate Meta Optimization solutions.")]
22  [StorableClass]
23  public class ParameterConfigurationEvaluator : SingleSuccessorOperator, IParameterConfigurationEvaluator, IStochasticOperator {
24    public ILookupParameter<IRandom> RandomParameter {
25      get { return (LookupParameter<IRandom>)Parameters["Random"]; }
26    }
27    public ILookupParameter<DoubleValue> QualityParameter {
28      get { return (ILookupParameter<DoubleValue>)Parameters["Quality"]; }
29    }
30    public ILookupParameter<TypeValue> AlgorithmTypeParameter {
31      get { return (ILookupParameter<TypeValue>)Parameters[MetaOptimizationProblem.AlgorithmTypeParameterName]; }
32    }
33    public ILookupParameter<IItemList<IProblem>> ProblemsParameter {
34      get { return (ILookupParameter<IItemList<IProblem>>)Parameters[MetaOptimizationProblem.ProblemsParameterName]; }
35    }
36    public ILookupParameter<ParameterConfigurationTree> ParameterConfigurationParameter {
37      get { return (ILookupParameter<ParameterConfigurationTree>)Parameters["ParameterConfigurationTree"]; }
38    }
39    public LookupParameter<IntValue> RepetitionsParameter {
40      get { return (LookupParameter<IntValue>)Parameters[MetaOptimizationProblem.RepetitionsParameterName]; }
41    }
42
43    public LookupParameter<DoubleArray> ProblemQualityReferencesParameter {
44      get { return (LookupParameter<DoubleArray>)Parameters["ProblemQualityReferences"]; }
45    }
46    public LookupParameter<IntValue> GenerationsParameter {
47      get { return (LookupParameter<IntValue>)Parameters["Generations"]; }
48    }
49    public LookupParameter<ResultCollection> ResultsParameter {
50      get { return (LookupParameter<ResultCollection>)Parameters["Results"]; }
51    }
52   
53    public IntValue Repetitions {
54      get { return RepetitionsParameter.ActualValue; }
55    }
56
57    public ParameterConfigurationEvaluator()
58      : base() {
59      Parameters.Add(new LookupParameter<IRandom>("Random", "The pseudo random number generator which should be used to initialize the new random permutation."));
60      Parameters.Add(new LookupParameter<DoubleValue>("Quality", "The evaluated quality of the ParameterVector."));
61      Parameters.Add(new LookupParameter<TypeValue>(MetaOptimizationProblem.AlgorithmTypeParameterName, "Missing description."));
62      Parameters.Add(new LookupParameter<IItemList<IProblem>>(MetaOptimizationProblem.ProblemsParameterName, "Missing description."));
63      Parameters.Add(new LookupParameter<ParameterConfigurationTree>("ParameterConfigurationTree", "Missing description."));
64      Parameters.Add(new LookupParameter<IntValue>(MetaOptimizationProblem.RepetitionsParameterName, "Number of evaluations on one problem."));
65      Parameters.Add(new LookupParameter<DoubleArray>("ProblemQualityReferences", ""));
66      Parameters.Add(new LookupParameter<IntValue>("Generations", ""));
67      Parameters.Add(new LookupParameter<ResultCollection>("Results", ""));
68    }
69
70    [StorableConstructor]
71    protected ParameterConfigurationEvaluator(bool deserializing) : base(deserializing) { }
72    protected ParameterConfigurationEvaluator(ParameterConfigurationEvaluator original, Cloner cloner)
73      : base(original, cloner) {
74    }
75    public override IDeepCloneable Clone(Cloner cloner) {
76      return new ParameterConfigurationEvaluator(this, cloner);
77    }
78
79    public override IOperation Apply() {
80      IRandom random = RandomParameter.ActualValue;
81      ParameterConfigurationTree parameterConfiguration = ParameterConfigurationParameter.ActualValue;
82      IAlgorithm algorithm = (IAlgorithm)Activator.CreateInstance(AlgorithmTypeParameter.ActualValue.Value);
83      IItemList<IProblem> problems = ProblemsParameter.ActualValue;
84      ItemDictionary<StringValue, RunCollection> runsCache = ResultsParameter.ActualValue.ContainsKey("Runs") ? (ItemDictionary<StringValue, RunCollection>)ResultsParameter.ActualValue["Runs"].Value : null;
85      double[] referenceQualities = GetReferenceQualities(problems);
86
87      RunCollection runs;
88      if (runsCache != null && runsCache.Count(x => x.Key.Value == parameterConfiguration.ParameterInfoString) > 0) {
89        runs = runsCache.Single(x => x.Key.Value == parameterConfiguration.ParameterInfoString).Value;
90        Console.WriteLine("Used Cache for {0}", parameterConfiguration.ParameterInfoString);
91      } else {
92        do {
93          runs = ExecuteAlgorithm(parameterConfiguration, algorithm, problems, Repetitions.Value, GenerationsParameter.ActualValue != null ? GenerationsParameter.ActualValue.Value : 0);
94          if (runs == null) {
95            Repair(parameterConfiguration, random);
96            parameterConfiguration.Parameterize(algorithm);
97          }
98        } while (runs == null);
99      }
100
101      List<List<double>> qualities = new List<List<double>>();
102      List<List<TimeSpan>> executionTimes = new List<List<TimeSpan>>();
103
104      for (int i = 0; i < problems.Count; i++) {
105        var problemRuns = runs.Where(x => ((IntValue)x.Results["Meta.ProblemIndex"]).Value == i + 1);
106        qualities.Add(problemRuns.Select(x => ((DoubleValue)x.Results["BestQuality"]).Value).ToList());
107        executionTimes.Add(problemRuns.Select(x => ((TimeSpanValue)x.Results["Execution Time"]).Value).ToList());
108      }
109
110      parameterConfiguration.AverageExecutionTimes = new ItemList<TimeSpanValue>(executionTimes.Select(t => new TimeSpanValue(TimeSpan.FromMilliseconds(t.Average(ts => ts.TotalMilliseconds)))));
111      parameterConfiguration.Repetitions = (IntValue)Repetitions.Clone();
112      parameterConfiguration.BestQualities = new DoubleArray(qualities.Select(q => q.Min()).ToArray()); // todo: respect Maximization:true/false
113      parameterConfiguration.AverageQualities = new DoubleArray(qualities.Select(q => q.Average()).ToArray());
114      parameterConfiguration.WorstQualities = new DoubleArray(qualities.Select(q => q.Max()).ToArray()); // todo: respect Maximization:true/false
115      parameterConfiguration.QualityVariances = new DoubleArray(qualities.Select(q => q.Variance()).ToArray());
116      parameterConfiguration.QualityStandardDeviations = new DoubleArray(qualities.Select(q => q.StandardDeviation()).ToArray());
117      parameterConfiguration.Runs = (RunCollection)runs.Clone();
118
119      this.QualityParameter.ActualValue = new DoubleValue(NormalizeQualities(parameterConfiguration, referenceQualities));
120
121      return base.Apply();
122    }
123
124    /// <summary>
125    /// This method should repair an invalid parameterConfiguration.
126    /// The strategy is to just randomize parameter settings. It's not guaranteed to be a vaild setting
127    /// </summary>
128    private void Repair(ParameterConfigurationTree parameterConfiguration, IRandom random) {
129      parameterConfiguration.Randomize(random);
130    }
131
132    private double[] GetReferenceQualities(IItemList<IProblem> problems) {
133      double[] referenceQualities;
134      if (ProblemQualityReferencesParameter.ActualValue == null) {
135        // this is generation zero. no reference qualities for normalization have been calculated yet. in this special case the ReferenceQualityAnalyzer will do the normalization
136        referenceQualities = new double[problems.Count];
137        for (int i = 0; i < referenceQualities.Length; i++) {
138          referenceQualities[i] = 1;
139        }
140      } else {
141        referenceQualities = ProblemQualityReferencesParameter.ActualValue.ToArray();
142      }
143      return referenceQualities;
144    }
145
146    /// <summary>
147    /// Executes an algorithm
148    /// </summary>
149    /// <param name="parameterConfiguration"></param>
150    /// <param name="algorithm"></param>
151    /// <param name="problems"></param>
152    /// <returns></returns>
153    private static RunCollection ExecuteAlgorithm(ParameterConfigurationTree parameterConfiguration, IAlgorithm algorithm, IItemList<IProblem> problems, int repetitions, int currentGeneration) {
154      IAlgorithm algorithmClone = (IAlgorithm)algorithm.Clone();
155      var parameterNames = new List<string>();
156      var resultNames = new List<string> { "BestQuality", "Execution Time" };
157      parameterConfiguration.CollectOptimizedParameterNames(parameterNames, "");
158
159      // set parameters
160      parameterConfiguration.Parameterize(algorithmClone);
161      algorithmClone.StoreAlgorithmInEachRun = false;
162
163      if (algorithmClone is EngineAlgorithm) {
164        ((EngineAlgorithm)algorithmClone).Engine = new SequentialEngine.SequentialEngine();
165      }
166      algorithmClone.Prepare(true);
167
168      foreach (IProblem problem in problems) {
169        algorithmClone.Problem = (IProblem)problem.Clone();
170
171        for (int i = 0; i < repetitions; i++) {
172          algorithmClone.Prepare();
173
174          AlgorithmExecutor executor = new AlgorithmExecutor(algorithmClone);
175          executor.StartSync();
176
177          if (algorithmClone.ExecutionState == ExecutionState.Paused) {
178            // the parameter settings were invalid.
179            // (1) set penalty for this solution.
180            //     it's difficult to create penalty values for BestQuality and ExecutionTime. Maybe ReferenceQuality * X (but what about ExecutionTime?)
181            //     therefore use repair instead.
182           
183            // (2) repair and retry
184            return null;
185          }
186          int problemIndex = problems.IndexOf(problem) + 1;
187          IRun run = algorithmClone.Runs.Last();
188          CleanRun(run, resultNames, parameterNames);
189          run.Results.Add("Meta.FromCache", new BoolValue(false));
190          run.Results.Add("Meta.Generation", new IntValue(currentGeneration));
191          run.Results.Add("Meta.ProblemIndex", new IntValue(problemIndex));
192          int runCountOfThisProblem = algorithmClone.Runs.Where(x => ((IntValue)x.Results["Meta.ProblemIndex"]).Value == problemIndex).Count();
193          run.Name = string.Format("{0} Problem {1} Run {2}", parameterConfiguration.ParameterInfoString, problemIndex, runCountOfThisProblem);
194        }
195      }
196      algorithmClone.Prepare();
197      return algorithmClone.Runs;
198    }
199
200    /// <summary>
201    /// Removes all information from the run which is not needed for lated analysis
202    /// only keep the results which are important and the parameters which were optimized
203    /// </summary>
204    private static void CleanRun(IRun run, IEnumerable<string> resultsToKeep, IEnumerable<string> parametersToKeep) {
205      var resultsToRemove = new List<string>();
206      var parametersToRemove = new List<string>();
207      foreach (var result in run.Results) {
208        if (!resultsToKeep.Contains(result.Key))
209          resultsToRemove.Add(result.Key);
210      }
211      foreach (var parameter in run.Parameters) {
212        if (!parametersToKeep.Contains(parameter.Key))
213          parametersToRemove.Add(parameter.Key);
214      }
215
216      foreach (var result in resultsToRemove)
217        run.Results.Remove(result);
218      foreach (var parameter in parametersToRemove)
219        run.Parameters.Remove(parameter);
220    }
221
222    public static double NormalizeQualities(ParameterConfigurationTree parameterConfigurationTree, double[] referenceQualities) {
223      double[] qualitiesNormalized = new double[referenceQualities.Length];
224      for (int i = 0; i < referenceQualities.Length; i++) {
225        qualitiesNormalized[i] = parameterConfigurationTree.AverageQualities[i] / referenceQualities[i];
226      }
227      parameterConfigurationTree.QualitiesNormalized = new DoubleArray(qualitiesNormalized);
228      parameterConfigurationTree.AverageQualityNormalized = new DoubleValue(qualitiesNormalized.Average());
229      return parameterConfigurationTree.AverageQualityNormalized.Value;
230    }
231
232    public static double Variance(IEnumerable<double> source) {
233      double avg = source.Average();
234      double d = source.Aggregate(0.0, (total, next) => total += Math.Pow(next - avg, 2));
235      return d / (source.Count() - 1);
236    }
237
238    public static double StandardDeviation(IEnumerable<double> source) {
239      return Math.Sqrt(source.Variance());
240    }
241  }
242}
Note: See TracBrowser for help on using the repository browser.