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

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

#2457: worked on expert system

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