Free cookie consent management tool by TermsFeed Policy Generator

source: branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/KnowledgeCenter.cs @ 13751

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

#2457: worked on problem instance mapping

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