source: branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/ExpertSystem.cs @ 13649

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

#2457: fixed bugs in suggestions

File size: 27.3 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2015 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 HeuristicLab.Analysis;
23using HeuristicLab.Collections;
24using HeuristicLab.Common;
25using HeuristicLab.Common.Resources;
26using HeuristicLab.Core;
27using HeuristicLab.Data;
28using HeuristicLab.MainForm;
29using HeuristicLab.Optimization;
30using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
31using HeuristicLab.Persistence.Default.Xml;
32using System;
33using System.Collections.Generic;
34using System.ComponentModel;
35using System.Drawing;
36using System.IO;
37using System.Linq;
38using System.Threading;
39using System.Threading.Tasks;
40using RunCreationClient = HeuristicLab.Clients.OKB.RunCreation.RunCreationClient;
41using SingleObjectiveOKBProblem = HeuristicLab.Clients.OKB.RunCreation.SingleObjectiveOKBProblem;
42
43namespace HeuristicLab.OptimizationExpertSystem {
44  [Item("Expert-System", "Currently in experimental phase, an expert system that makes algorithm suggestions based on fitness landscape analysis features and an optimization knowledge base.")]
45  [StorableClass]
46  [Creatable(CreatableAttribute.Categories.TestingAndAnalysis, Priority = 119)]
47  public sealed class ExpertSystem : NamedItem, IStorableContent, INotifyPropertyChanged {
48
49    public string Filename { get; set; }
50
51    public static new Image StaticItemImage {
52      get { return VSImageLibrary.Library; }
53    }
54
55    [Storable]
56    private int maximumEvaluations;
57    public int MaximumEvaluations {
58      get { return maximumEvaluations; }
59      set {
60        if (maximumEvaluations == value) return;
61        maximumEvaluations = value;
62        OnPropertyChanged("MaximumEvaluations");
63        UpdateSuggestions();
64      }
65    }
66
67    [Storable]
68    private RunCollection runs;
69    public RunCollection Runs {
70      get { return runs; }
71    }
72
73    [Storable]
74    private RunCollection knowledgeBase;
75    public RunCollection KnowledgeBase {
76      get { return knowledgeBase; }
77      set {
78        if (knowledgeBase == value) return;
79        knowledgeBase = value;
80        OnPropertyChanged("KnowledgeBase");
81      }
82    }
83
84    [Storable]
85    private SingleObjectiveOKBProblem problem;
86    public SingleObjectiveOKBProblem Problem {
87      get { return problem; }
88      set {
89        if (problem == value) return;
90        problem = value;
91        OnPropertyChanged("Problem");
92        UpdateSuggestions();
93      }
94    }
95
96    [Storable]
97    private ItemList<IAlgorithm> suggestedInstances;
98    private ReadOnlyItemList<IAlgorithm> readOnlySuggestedInstances;
99    public ReadOnlyItemList<IAlgorithm> SuggestedInstances {
100      get { return readOnlySuggestedInstances; }
101    }
102
103    [Storable]
104    private RunCollection problemInstances;
105    public RunCollection ProblemInstances {
106      get { return problemInstances; }
107      set {
108        if (problemInstances == value) return;
109        problemInstances = value;
110        OnPropertyChanged("ProblemInstances");
111      }
112    }
113
114    [Storable]
115    private ResultCollection currentResult;
116    public ResultCollection CurrentResult {
117      get { return currentResult; }
118      set {
119        if (currentResult == value) return;
120        currentResult = value;
121        OnPropertyChanged("CurrentResult");
122      }
123    }
124
125    [Storable]
126    private BidirectionalLookup<long, IRun> algorithmId2RunMapping;
127    [Storable]
128    private BidirectionalDictionary<long, IAlgorithm> algorithmId2AlgorithmInstanceMapping;
129
130    [Storable]
131    private Run currentInstance;
132
133    private bool Maximization {
134      get {
135        return Problem != null && Problem.ProblemId >= 0 && ((IValueParameter<BoolValue>)Problem.MaximizationParameter).Value.Value;
136      }
137    }
138
139    [StorableConstructor]
140    private ExpertSystem(bool deserializing) : base(deserializing) { }
141    private ExpertSystem(ExpertSystem original, Cloner cloner)
142      : base(original, cloner) {
143      runs = cloner.Clone(original.runs);
144      knowledgeBase = cloner.Clone(original.knowledgeBase);
145      suggestedInstances = cloner.Clone(original.suggestedInstances);
146      readOnlySuggestedInstances = suggestedInstances.AsReadOnly();
147      problemInstances = cloner.Clone(original.problemInstances);
148      problem = cloner.Clone(original.problem);
149      algorithmId2RunMapping = new BidirectionalLookup<long, IRun>();
150      foreach (var kvp in original.algorithmId2RunMapping.FirstEnumerable) {
151        algorithmId2RunMapping.AddRangeFirst(kvp.Key, kvp.Select(cloner.Clone));
152      }
153      algorithmId2AlgorithmInstanceMapping = new BidirectionalDictionary<long, IAlgorithm>();
154      foreach (var kvp in original.algorithmId2AlgorithmInstanceMapping) {
155        algorithmId2AlgorithmInstanceMapping.Add(kvp.Key, cloner.Clone(kvp.Value));
156      }
157      currentInstance = cloner.Clone(original.currentInstance);
158      RegisterEventHandlers();
159    }
160    public ExpertSystem() {
161      Name = ItemName;
162      Description = ItemDescription;
163      runs = new RunCollection();
164      knowledgeBase = new RunCollection();
165      suggestedInstances = new ItemList<IAlgorithm>();
166      readOnlySuggestedInstances = suggestedInstances.AsReadOnly();
167      problemInstances = new RunCollection();
168      problem = new SingleObjectiveOKBProblem();
169      algorithmId2RunMapping = new BidirectionalLookup<long, IRun>();
170      algorithmId2AlgorithmInstanceMapping = new BidirectionalDictionary<long, IAlgorithm>();
171      RegisterEventHandlers();
172    }
173
174    private void ProblemOnProblemChanged(object sender, EventArgs eventArgs) {
175      if (Problem == null) return;
176    }
177
178    public override IDeepCloneable Clone(Cloner cloner) {
179      return new ExpertSystem(this, cloner);
180    }
181
182    [StorableHook(HookType.AfterDeserialization)]
183    private void AfterDeserialization() {
184      readOnlySuggestedInstances = suggestedInstances.AsReadOnly();
185      RegisterEventHandlers();
186    }
187
188    private void RegisterEventHandlers() {
189      problem.ProblemChanged += ProblemOnProblemChanged;
190      runs.CollectionReset += InformationChanged;
191      runs.ItemsAdded += InformationChanged;
192      runs.ItemsRemoved += InformationChanged;
193      runs.Reset += InformationChanged;
194      runs.UpdateOfRunsInProgressChanged += InformationChanged;
195      knowledgeBase.CollectionReset += InformationChanged;
196      knowledgeBase.ItemsAdded += InformationChanged;
197      knowledgeBase.ItemsRemoved += InformationChanged;
198    }
199
200    private void InformationChanged(object sender, EventArgs e) {
201      var runCollection = sender as RunCollection;
202      if (runCollection != null && runCollection.UpdateOfRunsInProgress) return;
203      UpdateSuggestions();
204    }
205
206    public void UpdateInstanceProjection() {
207      currentInstance = null;
208      var filter = new HashSet<string>();
209
210      if (Problem.ProblemId != -1) {
211        currentInstance = new Run { Name = Problem.Name };
212        Problem.Problem.CollectParameterValues(currentInstance.Parameters);
213        foreach (var c in RunCreationClient.GetCharacteristicValues(Problem.ProblemId)) {
214          var key = "Characteristic." + c.Name;
215          currentInstance.Results.Add(key, RunCreationClient.Instance.ConvertToItem(c));
216          filter.Add(key);
217        }
218      }
219      // TODO: There is a problem with missing values that has to be solved
220      // The common set of characteristics among all problems may be too small to be useful
221      // It has to be decided somehow which problem instances to include in order to obtain the set of features that is expressive and available
222      var allCharacteristics = ProblemInstances.Select(x => new HashSet<string>(x.Results.Where(y => y.Key.StartsWith("Characteristic.", StringComparison.Ordinal)).Select(y => y.Key))).ToList();
223      var commonCharacteristics = filter.Count > 0 ? filter : allCharacteristics[0];
224      for (var i = 0; i < allCharacteristics.Count; i++)
225        commonCharacteristics.IntersectWith(allCharacteristics[i]);
226
227      if (commonCharacteristics.Count == 0) return;
228
229      var instances = new Dictionary<string, double[]>();
230      foreach (var i in ProblemInstances)
231        instances[i.Name] = i.Results.Where(x => commonCharacteristics.Contains(x.Key)).OrderBy(x => x.Key).Select(x => (double)((dynamic)x.Value).Value).ToArray();
232      if (currentInstance != null)
233        instances[currentInstance.Name] = currentInstance.Results.Where(x => commonCharacteristics.Contains(x.Key)).OrderBy(x => x.Key).Select(x => (double)((dynamic)x.Value).Value).ToArray();
234
235      var allValues = instances.SelectMany(x => x.Value).ToList();
236      var avg = allValues.Average();
237      var stdev = allValues.StandardDeviation();
238
239      // normalize characteristic values by transforming them to their z-score
240      foreach (var key in instances.Keys.ToList()) {
241        var arr = instances[key];
242        for (var i = 0; i < arr.Length; i++) {
243          arr[i] = (arr[i] - avg) / stdev;
244        }
245      }
246
247      var key2Idx = new BidirectionalDictionary<string, int>();
248      foreach (var kvp in instances.Select((k, i) => new { Index = i, Key = k.Key }))
249        key2Idx.Add(kvp.Key, kvp.Index);
250
251      #region MDS
252      Func<double[], double[], double> euclid = (a, b) => Math.Sqrt(a.Zip(b, (x, y) => (x - y)).Sum(x => x * x));
253      var num = instances.Count;
254      var matrix = new DoubleMatrix(num, num);
255      for (var i = 0; i < num - 1; i++) {
256        for (var j = i + 1; j < num; j++) {
257          matrix[i, j] = matrix[j, i] = euclid(instances[key2Idx.GetBySecond(i)], instances[key2Idx.GetBySecond(j)]);
258        }
259      }
260
261      var coords = MultidimensionalScaling.KruskalShepard(matrix);
262      #endregion
263      #region PCA
264      var ds = new double[instances.Count, commonCharacteristics.Count];
265      foreach (var instance in instances) {
266        var arr = instance.Value;
267        for (var feature = 0; feature < arr.Length; feature++)
268          ds[key2Idx.GetByFirst(instance.Key), feature] = arr[feature];
269      }
270
271      int info;
272      double[] s2;
273      double[,] v;
274      alglib.pcabuildbasis(ds, ds.GetLength(0), ds.GetLength(1), out info, out s2, out v);
275      #endregion
276
277      ProblemInstances.UpdateOfRunsInProgress = true;
278      try {
279        foreach (var instance in ProblemInstances) {
280          double x = 0, y = 0;
281          for (var feature = 0; feature < ds.GetLength(1); feature++) {
282            x += ds[key2Idx.GetByFirst(instance.Name), feature] * v[feature, 0];
283            y += ds[key2Idx.GetByFirst(instance.Name), feature] * v[feature, 1];
284          }
285
286          IItem item;
287          if (instance.Results.TryGetValue("Projection.PCA.X", out item)) {
288            ((DoubleValue)item).Value = x;
289          } else instance.Results.Add("Projection.PCA.X", new DoubleValue(x));
290          if (instance.Results.TryGetValue("Projection.PCA.Y", out item)) {
291            ((DoubleValue)item).Value = y;
292          } else instance.Results.Add("Projection.PCA.Y", new DoubleValue(y));
293
294          if (instance.Results.TryGetValue("Projection.MDS.X", out item)) {
295            ((DoubleValue)item).Value = coords[key2Idx.GetByFirst(instance.Name), 0];
296          } else instance.Results.Add("Projection.MDS.X", new DoubleValue(coords[key2Idx.GetByFirst(instance.Name), 0]));
297          if (instance.Results.TryGetValue("Projection.MDS.Y", out item)) {
298            ((DoubleValue)item).Value = coords[key2Idx.GetByFirst(instance.Name), 1];
299          } else instance.Results.Add("Projection.MDS.Y", new DoubleValue(coords[key2Idx.GetByFirst(instance.Name), 1]));
300        }
301      } finally { ProblemInstances.UpdateOfRunsInProgress = false; }
302
303      if (currentInstance != null) {
304        double x = 0, y = 0;
305        for (var feature = 0; feature < ds.GetLength(1); feature++) {
306          x += ds[key2Idx.GetByFirst(currentInstance.Name), feature] * v[feature, 0];
307          y += ds[key2Idx.GetByFirst(currentInstance.Name), feature] * v[feature, 1];
308        }
309
310        IItem item;
311        if (currentInstance.Results.TryGetValue("Projection.PCA.X", out item)) {
312          ((DoubleValue)item).Value = x;
313        } else currentInstance.Results.Add("Projection.PCA.X", new DoubleValue(x));
314        if (currentInstance.Results.TryGetValue("Projection.PCA.Y", out item)) {
315          ((DoubleValue)item).Value = y;
316        } else currentInstance.Results.Add("Projection.PCA.Y", new DoubleValue(y));
317
318        if (currentInstance.Results.TryGetValue("Projection.MDS.X", out item)) {
319          ((DoubleValue)item).Value = coords[key2Idx.GetByFirst(currentInstance.Name), 0];
320        } else currentInstance.Results.Add("Projection.MDS.X", new DoubleValue(coords[key2Idx.GetByFirst(currentInstance.Name), 0]));
321        if (currentInstance.Results.TryGetValue("Projection.MDS.Y", out item)) {
322          ((DoubleValue)item).Value = coords[key2Idx.GetByFirst(currentInstance.Name), 1];
323        } else currentInstance.Results.Add("Projection.MDS.Y", new DoubleValue(coords[key2Idx.GetByFirst(currentInstance.Name), 1]));
324      }
325    }
326
327    public Tuple<double, double> ProjectCurrentInstance(string projection) {
328      if (currentInstance == null) return null;
329      var xKey = "Projection." + projection + ".X";
330      var yKey = "Projection." + projection + ".Y";
331      if (!currentInstance.Results.ContainsKey(xKey) || !currentInstance.Results.ContainsKey(yKey))
332        return null;
333      var x = ((DoubleValue)currentInstance.Results[xKey]).Value;
334      var y = ((DoubleValue)currentInstance.Results[yKey]).Value;
335      return Tuple.Create(x, y);
336    }
337
338    private static readonly HashSet<string> InterestingValueNames = new HashSet<string>() {
339      "QualityPerEvaluations", "Problem Name", "Problem Type", "Algorithm Name", "Algorithm Type", "Maximization", "BestKnownQuality"
340    };
341
342    public async void StartAlgorithmAsync(int index) {
343      var selectedInstance = suggestedInstances[index];
344      var algorithm = (IAlgorithm)selectedInstance.Clone();
345      algorithm.Prepare(true);
346      IParameter stopParam;
347      var monitorStop = true;
348      if (algorithm.Parameters.TryGetValue("MaximumEvaluations", out stopParam)) {
349        var maxEvalParam = stopParam as IValueParameter<Data.IntValue>;
350        if (maxEvalParam != null) {
351          maxEvalParam.Value.Value = MaximumEvaluations;
352          monitorStop = false;
353        }
354      }
355      algorithm.ExecutionStateChanged += AlgorithmOnExecutionStateChanged;
356      algorithm.ExceptionOccurred += AlgorithmOnExceptionOccurred;
357      if (monitorStop) algorithm.ExecutionTimeChanged += AlgorithmOnExecutionTimeChanged;
358
359      algorithm.Start();
360    }
361
362    public void StartAlgorithm(int index) {
363      var selectedInstance = suggestedInstances[index];
364      var algorithm = (IAlgorithm)selectedInstance.Clone();
365      algorithm.Prepare(true);
366      IParameter stopParam;
367      var monitorStop = true;
368      if (algorithm.Parameters.TryGetValue("MaximumEvaluations", out stopParam)) {
369        var maxEvalParam = stopParam as IValueParameter<Data.IntValue>;
370        if (maxEvalParam != null) {
371          maxEvalParam.Value.Value = MaximumEvaluations;
372          monitorStop = false;
373        }
374      }
375      algorithm.ExecutionStateChanged += AlgorithmOnExecutionStateChanged;
376      algorithm.ExceptionOccurred += AlgorithmOnExceptionOccurred;
377      if (monitorStop) algorithm.ExecutionTimeChanged += AlgorithmOnExecutionTimeChanged;
378
379      using (algWh = new AutoResetEvent(false)) {
380        algorithm.Start();
381        algWh.WaitOne();
382      }
383      algWh = null;
384    }
385
386    private AutoResetEvent algWh;
387
388    private void AlgorithmOnExecutionStateChanged(object sender, EventArgs eventArgs) {
389      var alg = sender as IAlgorithm;
390      if (alg == null) return;
391      if (alg.ExecutionState == ExecutionState.Started) {
392        CurrentResult = alg.Results;
393      } else if (alg.ExecutionState == ExecutionState.Stopped) {
394        alg.ExecutionStateChanged -= AlgorithmOnExecutionStateChanged;
395        alg.ExceptionOccurred -= AlgorithmOnExceptionOccurred;
396        alg.ExecutionTimeChanged -= AlgorithmOnExecutionTimeChanged;
397        if (algWh != null) algWh.Set();
398      }
399    }
400
401    private void AlgorithmOnExceptionOccurred(object sender, EventArgs<Exception> eventArgs) {
402      var alg = sender as IAlgorithm;
403      if (alg == null) return;
404      alg.ExecutionStateChanged -= AlgorithmOnExecutionStateChanged;
405      alg.ExceptionOccurred -= AlgorithmOnExceptionOccurred;
406      alg.ExecutionTimeChanged -= AlgorithmOnExecutionTimeChanged;
407      if (algWh != null) algWh.Set();
408    }
409
410    private void AlgorithmOnExecutionTimeChanged(object sender, EventArgs eventArgs) {
411      var alg = sender as IAlgorithm;
412      if (alg == null) return;
413      IResult evalSolResult;
414      if (!alg.Results.TryGetValue("EvaluatedSolutions", out evalSolResult) || !(evalSolResult.Value is Data.IntValue)) return;
415      var evalSols = ((Data.IntValue)evalSolResult.Value).Value;
416      if (evalSols >= MaximumEvaluations) alg.Stop();
417    }
418
419    public async void UpdateKnowledgeBaseAsync(IProgress progress) {
420      progress.Start("Updating Knowledge Base from OKB");
421      await Task.Factory.StartNew(() => { DoUpdateKnowledgeBase(progress); }, TaskCreationOptions.LongRunning);
422    }
423
424    public void UpdateKnowledgeBase() {
425      DoUpdateKnowledgeBase(new Progress(string.Empty, ProgressState.Started));
426    }
427
428    private void DoUpdateKnowledgeBase(IProgress progress) {
429      var queryClient = Clients.OKB.Query.QueryClient.Instance;
430      var adminClient = Clients.OKB.Administration.AdministrationClient.Instance;
431      try {
432        progress.Status = "Downloading run information...";
433        progress.ProgressValue = 0;
434        // FIXME: How to tell if refresh is necessary?
435        queryClient.Refresh();
436        progress.ProgressValue = 0.5;
437        progress.Status = "Downloading algorithm and problem instance information...";
438        // FIXME: How to tell if refresh is necessary?
439        adminClient.Refresh();
440
441        var probInstance = adminClient.Problems.SingleOrDefault(x => x.Id == Problem.ProblemId);
442        if (probInstance == null) throw new InvalidOperationException("The chosen problem instance cannot be found in the OKB.");
443        var probClassId = probInstance.ProblemClassId;
444
445        var problemClassFilter = (Clients.OKB.Query.StringComparisonAvailableValuesFilter)queryClient.Filters.Single(x => x.Label == "Problem Class Name");
446        problemClassFilter.Value = adminClient.ProblemClasses.Single(x => x.Id == probClassId).Name;
447
448        progress.Status = "Downloading problem instances...";
449        progress.ProgressValue = 0;
450        var p = 0;
451        ProblemInstances.UpdateOfRunsInProgress = true;
452        ProblemInstances.Clear();
453        var totalProblems = adminClient.Problems.Count(x => x.ProblemClassId == probClassId);
454        foreach (var problInst in adminClient.Problems.Where(x => x.ProblemClassId == probClassId)) {
455          progress.Status = string.Format("Downloading problem {0} (okb-id: {1})....", problInst.Name, problInst.Id);
456          var data = Clients.OKB.Administration.AdministrationClient.GetProblemData(problInst.Id);
457          if (data != null) {
458            using (var stream = new MemoryStream(data)) {
459              try {
460                var prob = (IProblem)XmlParser.Deserialize<IContent>(stream);
461                var probRun = new Run() { Name = prob.Name };
462                prob.CollectParameterValues(probRun.Parameters);
463                probRun.Parameters["Problem Name"] = new StringValue(prob.Name);
464                probRun.Parameters["Problem Type"] = new StringValue(prob.GetType().Name);
465                progress.Status += Environment.NewLine + "Downloading characteristics...";
466                foreach (var v in RunCreationClient.GetCharacteristicValues(problInst.Id)) {
467                  probRun.Results.Add("Characteristic." + v.Name, RunCreationClient.Instance.ConvertToItem(v));
468                }
469                ProblemInstances.Add(probRun);
470              } catch { }
471              stream.Close();
472            }
473          }
474          p++;
475          progress.ProgressValue = p / (double)totalProblems;
476        }
477
478        algorithmId2AlgorithmInstanceMapping.Clear();
479        progress.Status = "Downloading algorithm instances...";
480        progress.ProgressValue = 0;
481        p = 0;
482        foreach (var algInst in adminClient.Algorithms) {
483          progress.Status = string.Format("Downloading algorithm {0} (okb-id: {1})...", algInst.Name, algInst.Id);
484          var data = Clients.OKB.Administration.AdministrationClient.GetAlgorithmData(algInst.Id);
485          if (data != null) {
486            using (var stream = new MemoryStream(data)) {
487              try {
488                var alg = (IAlgorithm)XmlParser.Deserialize<IContent>(stream);
489                algorithmId2AlgorithmInstanceMapping.Add(algInst.Id, alg);
490              } catch { }
491              stream.Close();
492            }
493          }
494          p++;
495          progress.ProgressValue = p / (double)adminClient.Algorithms.Count;
496        }
497
498        var interestingValues = queryClient.ValueNames.Where(x => InterestingValueNames.Contains(x.Name)).ToList();
499
500        progress.Status = "Obtaining number of runs...";
501        progress.ProgressValue = 0;
502        p = 0;
503        var count = queryClient.GetNumberOfRuns(problemClassFilter);
504        if (count == 0) return;
505       
506        var runIds = queryClient.GetRunIds(problemClassFilter).ToList();
507        var conversions = new List<Task>();
508        var runList = new List<IRun>();
509        while (p < count) {
510          var nextIds = runIds.Skip(p).Take(500).ToList();
511          progress.Status = string.Format("Downloading runs {0} to {1} of {2}...", p, p + nextIds.Count, count);
512          var okbRuns = queryClient.GetRunsWithValues(nextIds, true, interestingValues);
513          conversions.Add(Task.Factory.StartNew(() => {
514            var hlRuns = okbRuns.AsParallel().Select(x => new { AlgorithmId = x.Algorithm.Id, Run = queryClient.ConvertToOptimizationRun(x) }).ToList();
515            lock (runList) {
516              foreach (var r in hlRuns) {
517                algorithmId2RunMapping.Add(r.AlgorithmId, r.Run);
518                runList.Add(r.Run);
519              }
520            }
521          }));
522          p += nextIds.Count;
523          progress.ProgressValue = p / (double)count;
524        }
525        Task.WaitAll(conversions.ToArray());
526
527        progress.Status = "Finishing...";
528        var algInstRunDict = runList.Where(x => x.Parameters.ContainsKey("Problem Name") && x.Parameters["Problem Name"] is StringValue)
529                                          .GroupBy(x => ((StringValue)x.Parameters["Problem Name"]).Value)
530                                          .ToDictionary(x => x.Key, x => x.GroupBy(y => ((StringValue)y.Parameters["Algorithm Name"]).Value)
531                                                                                  .ToDictionary(y => y.Key, y => y.ToList()));
532
533        foreach (var instance in ProblemInstances) {
534          IItem probNameParam;
535          if (!instance.Parameters.TryGetValue("Problem Name", out probNameParam)) continue;
536
537          var probInstanceName = ((StringValue)probNameParam).Value;
538          var maximization = ((BoolValue)instance.Parameters["Maximization"]).Value;
539         
540          IItem bkParam;
541          if (!instance.Parameters.TryGetValue("BestKnownQuality", out bkParam) || !(bkParam is DoubleValue)) {
542            Dictionary<string, List<IRun>> algRuns;
543            if (!algInstRunDict.TryGetValue(probInstanceName, out algRuns)) continue;
544            var list = algRuns.SelectMany(x => x.Value)
545                              .Where(x => x.Results.ContainsKey("QualityPerEvaluations"))
546                              .Select(x => ((IndexedDataTable<double>)x.Results["QualityPerEvaluations"]).Rows.First().Values.Last().Item2);
547            bkParam = new DoubleValue(maximization ? list.Max() : list.Min());
548            instance.Parameters["BestKnownQuality"] = bkParam;
549          } else bkParam = instance.Parameters["BestKnownQuality"];
550
551          var bkQuality = ((DoubleValue)bkParam).Value;
552
553          if (!algInstRunDict.ContainsKey(probInstanceName)) continue;
554          foreach (var kvp in algInstRunDict[probInstanceName]) {
555            // TODO: Things needs to be configurable here (table name, targets)
556            foreach (var target in new[] { 1, 1.01, 1.05, 1.1, 1.2, 1.5 }) {
557              var result = ExpectedRuntimeHelper.CalculateErt(kvp.Value, "QualityPerEvaluations", bkQuality * target, maximization);
558              var resultName = kvp.Key + "@" + ((target - 1) * 100) + "%";
559              IItem item;
560              if (instance.Results.TryGetValue(resultName, out item)) {
561                ((DoubleValue)item).Value = Math.Log10(result.ExpectedRuntime);
562              } else instance.Results.Add(resultName, new DoubleValue(Math.Log10(result.ExpectedRuntime)));
563            }
564          }
565        }
566        KnowledgeBase = new RunCollection(runList);
567      } finally { progress.Finish(); ProblemInstances.UpdateOfRunsInProgress = false; }
568    }
569
570    private void UpdateSuggestions() {
571      if (Problem == null) return;
572      var instances = new SortedList<double, IAlgorithm>();
573      foreach (var relevantRuns in knowledgeBase.GroupBy(x => algorithmId2RunMapping.GetBySecond(x).Single())) {
574        var algorithm = algorithmId2AlgorithmInstanceMapping.GetByFirst(relevantRuns.Key);
575        var avgQuality = 0.0;
576        var counter = 0;
577        foreach (var problemRuns in relevantRuns.GroupBy(x => ((StringValue)x.Parameters["Problem Name"]).Value)) {
578          var probInstance = ProblemInstances.SingleOrDefault(x => x.Name == problemRuns.Key);
579          if (probInstance == null) continue;
580          var bkQuality = ((DoubleValue)probInstance.Parameters["BestKnownQuality"]).Value;
581          foreach (var run in problemRuns) {
582            var performanceGraph = ((IndexedDataTable<double>)run.Results["QualityPerEvaluations"]);
583            try {
584              avgQuality += performanceGraph.Rows.First().Values.TakeWhile(x => x.Item1 < MaximumEvaluations).Last().Item2 / bkQuality;
585              counter++;
586            } catch {
587              continue;
588            }
589          }
590        }
591        avgQuality /= counter;
592        instances.Add(avgQuality, algorithm);
593      }
594
595      suggestedInstances.Clear();
596      var instanceLadder = instances.Select(x => (IAlgorithm)x.Value.Clone()).ToList();
597      if (Maximization) instanceLadder.Reverse();
598      suggestedInstances.AddRange(instanceLadder);
599    }
600
601    public event PropertyChangedEventHandler PropertyChanged;
602    private void OnPropertyChanged(string propertyName) {
603      var handler = PropertyChanged;
604      if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
605    }
606  }
607}
Note: See TracBrowser for help on using the repository browser.