Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 13685 was 13685, checked in by abeham, 8 years ago

#2457: updated to changes in RunCreationClient in trunk

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