Free cookie consent management tool by TermsFeed Policy Generator

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

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

#2457: fixed bugs in suggestions

File size: 27.3 KB
RevLine 
[12842]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
[12860]22using HeuristicLab.Analysis;
[13551]23using HeuristicLab.Collections;
[13485]24using HeuristicLab.Common;
25using HeuristicLab.Common.Resources;
[12842]26using HeuristicLab.Core;
[13485]27using HeuristicLab.Data;
28using HeuristicLab.MainForm;
[12842]29using HeuristicLab.Optimization;
30using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
[13485]31using HeuristicLab.Persistence.Default.Xml;
[13649]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;
[13551]40using RunCreationClient = HeuristicLab.Clients.OKB.RunCreation.RunCreationClient;
41using SingleObjectiveOKBProblem = HeuristicLab.Clients.OKB.RunCreation.SingleObjectiveOKBProblem;
[12842]42
43namespace HeuristicLab.OptimizationExpertSystem {
[12860]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.")]
[12842]45  [StorableClass]
[12860]46  [Creatable(CreatableAttribute.Categories.TestingAndAnalysis, Priority = 119)]
47  public sealed class ExpertSystem : NamedItem, IStorableContent, INotifyPropertyChanged {
[12842]48
49    public string Filename { get; set; }
50
51    public static new Image StaticItemImage {
52      get { return VSImageLibrary.Library; }
53    }
54
55    [Storable]
[12847]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");
[12860]63        UpdateSuggestions();
[12847]64      }
65    }
66
67    [Storable]
[12842]68    private RunCollection runs;
69    public RunCollection Runs {
70      get { return runs; }
71    }
72
73    [Storable]
[13551]74    private RunCollection knowledgeBase;
75    public RunCollection KnowledgeBase {
76      get { return knowledgeBase; }
[12957]77      set {
[13551]78        if (knowledgeBase == value) return;
79        knowledgeBase = value;
80        OnPropertyChanged("KnowledgeBase");
[12957]81      }
[12842]82    }
83
84    [Storable]
[13551]85    private SingleObjectiveOKBProblem problem;
86    public SingleObjectiveOKBProblem Problem {
[12842]87      get { return problem; }
88      set {
89        if (problem == value) return;
90        problem = value;
91        OnPropertyChanged("Problem");
[12860]92        UpdateSuggestions();
[12842]93      }
94    }
95
[12847]96    [Storable]
97    private ItemList<IAlgorithm> suggestedInstances;
98    private ReadOnlyItemList<IAlgorithm> readOnlySuggestedInstances;
99    public ReadOnlyItemList<IAlgorithm> SuggestedInstances {
100      get { return readOnlySuggestedInstances; }
101    }
102
[12957]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
[13551]114    [Storable]
[13649]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]
[13551]126    private BidirectionalLookup<long, IRun> algorithmId2RunMapping;
127    [Storable]
128    private BidirectionalDictionary<long, IAlgorithm> algorithmId2AlgorithmInstanceMapping;
129
[13561]130    [Storable]
131    private Run currentInstance;
132
[12860]133    private bool Maximization {
[13551]134      get {
135        return Problem != null && Problem.ProblemId >= 0 && ((IValueParameter<BoolValue>)Problem.MaximizationParameter).Value.Value;
136      }
[12842]137    }
138
139    [StorableConstructor]
[12860]140    private ExpertSystem(bool deserializing) : base(deserializing) { }
141    private ExpertSystem(ExpertSystem original, Cloner cloner)
[12842]142      : base(original, cloner) {
143      runs = cloner.Clone(original.runs);
[13551]144      knowledgeBase = cloner.Clone(original.knowledgeBase);
[12847]145      suggestedInstances = cloner.Clone(original.suggestedInstances);
146      readOnlySuggestedInstances = suggestedInstances.AsReadOnly();
[12957]147      problemInstances = cloner.Clone(original.problemInstances);
[13551]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      }
[13561]157      currentInstance = cloner.Clone(original.currentInstance);
[12860]158      RegisterEventHandlers();
[12842]159    }
[12860]160    public ExpertSystem() {
161      Name = ItemName;
162      Description = ItemDescription;
163      runs = new RunCollection();
[13551]164      knowledgeBase = new RunCollection();
[12847]165      suggestedInstances = new ItemList<IAlgorithm>();
166      readOnlySuggestedInstances = suggestedInstances.AsReadOnly();
[12957]167      problemInstances = new RunCollection();
[13551]168      problem = new SingleObjectiveOKBProblem();
169      algorithmId2RunMapping = new BidirectionalLookup<long, IRun>();
170      algorithmId2AlgorithmInstanceMapping = new BidirectionalDictionary<long, IAlgorithm>();
[12860]171      RegisterEventHandlers();
[12842]172    }
173
[13551]174    private void ProblemOnProblemChanged(object sender, EventArgs eventArgs) {
175      if (Problem == null) return;
176    }
177
[12842]178    public override IDeepCloneable Clone(Cloner cloner) {
[12860]179      return new ExpertSystem(this, cloner);
[12842]180    }
181
[12847]182    [StorableHook(HookType.AfterDeserialization)]
183    private void AfterDeserialization() {
184      readOnlySuggestedInstances = suggestedInstances.AsReadOnly();
[12860]185      RegisterEventHandlers();
[12847]186    }
187
[12860]188    private void RegisterEventHandlers() {
[13551]189      problem.ProblemChanged += ProblemOnProblemChanged;
[12860]190      runs.CollectionReset += InformationChanged;
191      runs.ItemsAdded += InformationChanged;
192      runs.ItemsRemoved += InformationChanged;
193      runs.Reset += InformationChanged;
194      runs.UpdateOfRunsInProgressChanged += InformationChanged;
[13551]195      knowledgeBase.CollectionReset += InformationChanged;
196      knowledgeBase.ItemsAdded += InformationChanged;
197      knowledgeBase.ItemsRemoved += InformationChanged;
[12842]198    }
199
[12860]200    private void InformationChanged(object sender, EventArgs e) {
201      var runCollection = sender as RunCollection;
202      if (runCollection != null && runCollection.UpdateOfRunsInProgress) return;
203      UpdateSuggestions();
[12842]204    }
205
[13561]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        }
[12957]218      }
[13561]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]);
[12957]226
[13561]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
[12957]271      int info;
272      double[] s2;
273      double[,] v;
[13561]274      alglib.pcabuildbasis(ds, ds.GetLength(0), ds.GetLength(1), out info, out s2, out v);
275      #endregion
[12957]276
277      ProblemInstances.UpdateOfRunsInProgress = true;
278      try {
279        foreach (var instance in ProblemInstances) {
280          double x = 0, y = 0;
[13561]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];
[12957]284          }
[13561]285
[12957]286          IItem item;
[13561]287          if (instance.Results.TryGetValue("Projection.PCA.X", out item)) {
[12957]288            ((DoubleValue)item).Value = x;
[13561]289          } else instance.Results.Add("Projection.PCA.X", new DoubleValue(x));
290          if (instance.Results.TryGetValue("Projection.PCA.Y", out item)) {
[12957]291            ((DoubleValue)item).Value = y;
[13561]292          } else instance.Results.Add("Projection.PCA.Y", new DoubleValue(y));
[12957]293
[13561]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]));
[12957]300        }
301      } finally { ProblemInstances.UpdateOfRunsInProgress = false; }
[13561]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      }
[12957]325    }
326
[13561]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
[13485]338    private static readonly HashSet<string> InterestingValueNames = new HashSet<string>() {
[13551]339      "QualityPerEvaluations", "Problem Name", "Problem Type", "Algorithm Name", "Algorithm Type", "Maximization", "BestKnownQuality"
[13485]340    };
341
[13649]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
[13485]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 {
[13551]432        progress.Status = "Downloading run information...";
433        progress.ProgressValue = 0;
434        // FIXME: How to tell if refresh is necessary?
[13485]435        queryClient.Refresh();
[13551]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);
[13649]463                probRun.Parameters["Problem Name"] = new StringValue(prob.Name);
464                probRun.Parameters["Problem Type"] = new StringValue(prob.GetType().Name);
[13551]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
[13485]498        var interestingValues = queryClient.ValueNames.Where(x => InterestingValueNames.Contains(x.Name)).ToList();
499
500        progress.Status = "Obtaining number of runs...";
[13551]501        progress.ProgressValue = 0;
502        p = 0;
503        var count = queryClient.GetNumberOfRuns(problemClassFilter);
[13485]504        if (count == 0) return;
[13649]505       
[13551]506        var runIds = queryClient.GetRunIds(problemClassFilter).ToList();
[13485]507        var conversions = new List<Task>();
[13551]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);
[13485]512          var okbRuns = queryClient.GetRunsWithValues(nextIds, true, interestingValues);
513          conversions.Add(Task.Factory.StartNew(() => {
[13551]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);
[13485]519              }
520            }
521          }));
[13551]522          p += nextIds.Count;
523          progress.ProgressValue = p / (double)count;
[13485]524        }
525        Task.WaitAll(conversions.ToArray());
[13551]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;
[13649]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"];
[13551]550
[13649]551          var bkQuality = ((DoubleValue)bkParam).Value;
552
[13551]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);
[13649]558              var resultName = kvp.Key + "@" + ((target - 1) * 100) + "%";
[13551]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)));
[13485]563            }
564          }
565        }
[13551]566        KnowledgeBase = new RunCollection(runList);
567      } finally { progress.Finish(); ProblemInstances.UpdateOfRunsInProgress = false; }
[13485]568    }
569
[12860]570    private void UpdateSuggestions() {
571      if (Problem == null) return;
572      var instances = new SortedList<double, IAlgorithm>();
[13649]573      foreach (var relevantRuns in knowledgeBase.GroupBy(x => algorithmId2RunMapping.GetBySecond(x).Single())) {
574        var algorithm = algorithmId2AlgorithmInstanceMapping.GetByFirst(relevantRuns.Key);
[12860]575        var avgQuality = 0.0;
576        var counter = 0;
[13649]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          }
[12860]590        }
591        avgQuality /= counter;
[13649]592        instances.Add(avgQuality, algorithm);
[12860]593      }
[12842]594
[12860]595      suggestedInstances.Clear();
[13649]596      var instanceLadder = instances.Select(x => (IAlgorithm)x.Value.Clone()).ToList();
597      if (Maximization) instanceLadder.Reverse();
598      suggestedInstances.AddRange(instanceLadder);
[12842]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.