Free cookie consent management tool by TermsFeed Policy Generator

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

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

#2457:

  • fixed bugs in iterated sampling view
  • worked on download runs from okb feature
File size: 14.1 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 System;
23using System.Collections.Generic;
24using System.ComponentModel;
25using System.Drawing;
26using System.IO;
27using System.Linq;
28using System.Threading.Tasks;
29using HeuristicLab.Analysis;
30using HeuristicLab.Common;
31using HeuristicLab.Common.Resources;
32using HeuristicLab.Core;
33using HeuristicLab.Data;
34using HeuristicLab.MainForm;
35using HeuristicLab.Optimization;
36using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
37using HeuristicLab.Persistence.Default.Xml;
38
39namespace HeuristicLab.OptimizationExpertSystem {
40  [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.")]
41  [StorableClass]
42  [Creatable(CreatableAttribute.Categories.TestingAndAnalysis, Priority = 119)]
43  public sealed class ExpertSystem : NamedItem, IStorableContent, INotifyPropertyChanged {
44
45    public string Filename { get; set; }
46
47    public static new Image StaticItemImage {
48      get { return VSImageLibrary.Library; }
49    }
50
51    [Storable]
52    private int maximumEvaluations;
53    public int MaximumEvaluations {
54      get { return maximumEvaluations; }
55      set {
56        if (maximumEvaluations == value) return;
57        maximumEvaluations = value;
58        OnPropertyChanged("MaximumEvaluations");
59        UpdateSuggestions();
60      }
61    }
62
63    [Storable]
64    private RunCollection runs;
65    public RunCollection Runs {
66      get { return runs; }
67    }
68
69    [Storable]
70    private ItemList<IAlgorithm> algorithmInstances;
71    public ItemList<IAlgorithm> AlgorithmInstances {
72      get { return algorithmInstances; }
73      set {
74        if (algorithmInstances == value) return;
75        algorithmInstances = value;
76        OnPropertyChanged("AlgorithmInstances");
77        // TODO: Attach event handlers
78      }
79    }
80
81    [Storable]
82    private ISingleObjectiveHeuristicOptimizationProblem problem;
83    public ISingleObjectiveHeuristicOptimizationProblem Problem {
84      get { return problem; }
85      set {
86        if (problem == value) return;
87        problem = value;
88        OnPropertyChanged("Problem");
89        UpdateSuggestions();
90      }
91    }
92
93    [Storable]
94    private ItemList<IAlgorithm> suggestedInstances;
95    private ReadOnlyItemList<IAlgorithm> readOnlySuggestedInstances;
96    public ReadOnlyItemList<IAlgorithm> SuggestedInstances {
97      get { return readOnlySuggestedInstances; }
98    }
99
100    [Storable]
101    private RunCollection problemInstances;
102    public RunCollection ProblemInstances {
103      get { return problemInstances; }
104      set {
105        if (problemInstances == value) return;
106        problemInstances = value;
107        OnPropertyChanged("ProblemInstances");
108      }
109    }
110
111    private bool Maximization {
112      get { return Problem != null && ((IValueParameter<BoolValue>)Problem.MaximizationParameter).Value.Value; }
113    }
114
115    [StorableConstructor]
116    private ExpertSystem(bool deserializing) : base(deserializing) { }
117    private ExpertSystem(ExpertSystem original, Cloner cloner)
118      : base(original, cloner) {
119      runs = cloner.Clone(original.runs);
120      algorithmInstances = cloner.Clone(original.algorithmInstances);
121      problem = cloner.Clone(original.problem);
122      suggestedInstances = cloner.Clone(original.suggestedInstances);
123      readOnlySuggestedInstances = suggestedInstances.AsReadOnly();
124      problemInstances = cloner.Clone(original.problemInstances);
125      RegisterEventHandlers();
126    }
127    public ExpertSystem() {
128      Name = ItemName;
129      Description = ItemDescription;
130      runs = new RunCollection();
131      algorithmInstances = new ItemList<IAlgorithm>();
132      suggestedInstances = new ItemList<IAlgorithm>();
133      readOnlySuggestedInstances = suggestedInstances.AsReadOnly();
134      problemInstances = new RunCollection();
135      RegisterEventHandlers();
136    }
137
138    public override IDeepCloneable Clone(Cloner cloner) {
139      return new ExpertSystem(this, cloner);
140    }
141
142    [StorableHook(HookType.AfterDeserialization)]
143    private void AfterDeserialization() {
144      readOnlySuggestedInstances = suggestedInstances.AsReadOnly();
145      RegisterEventHandlers();
146    }
147
148    private void RegisterEventHandlers() {
149      runs.CollectionReset += InformationChanged;
150      runs.ItemsAdded += InformationChanged;
151      runs.ItemsRemoved += InformationChanged;
152      runs.Reset += InformationChanged;
153      runs.UpdateOfRunsInProgressChanged += InformationChanged;
154      algorithmInstances.CollectionReset += InformationChanged;
155      algorithmInstances.ItemsAdded += InformationChanged;
156      algorithmInstances.ItemsRemoved += InformationChanged;
157    }
158
159    private void InformationChanged(object sender, EventArgs e) {
160      var runCollection = sender as RunCollection;
161      if (runCollection != null && runCollection.UpdateOfRunsInProgress) return;
162      UpdateSuggestions();
163    }
164
165    public void UpdateInstanceMap() {
166      var flaValues = ProblemInstances.ResultNames
167                      .Where(x => x.StartsWith("Characteristic.")
168                        && ProblemInstances.All(y => y.Results.ContainsKey(x) && y.Results[x] is DoubleValue))
169                      .Select(x => x).ToList();
170      var ds = new double[ProblemInstances.Count, flaValues.Count];
171      var instanceCounter = 0;
172      foreach (var instance in ProblemInstances) {
173        for (var feature = 0; feature < flaValues.Count; feature++)
174          ds[instanceCounter, feature] = ((DoubleValue)instance.Results[flaValues[feature]]).Value;
175        instanceCounter++;
176      }
177
178      int info;
179      double[] s2;
180      double[,] v;
181      alglib.pcabuildbasis(ds, instanceCounter, flaValues.Count, out info, out s2, out v);
182
183      var algInstRunDict = AlgorithmInstances.SelectMany(x => x.Runs)
184                                             .Where(x => x.Parameters.ContainsKey("Problem Name") && x.Parameters["Problem Name"] is StringValue)
185                                             .GroupBy(x => ((StringValue)x.Parameters["Problem Name"]).Value)
186                                             .ToDictionary(x => x.Key, x => x.GroupBy(y => ((StringValue)y.Parameters["Algorithm Name"]).Value)
187                                                                             .ToDictionary(y => y.Key, y => y.ToList()));
188      ProblemInstances.UpdateOfRunsInProgress = true;
189      try {
190        instanceCounter = 0;
191        foreach (var instance in ProblemInstances) {
192          IItem probNameParam;
193          if (!instance.Parameters.TryGetValue("Problem Name", out probNameParam)) continue;
194          var probInstanceName = ((StringValue)probNameParam).Value;
195
196          double x = 0, y = 0;
197          for (var feature = 0; feature < flaValues.Count; feature++) {
198            x += ds[instanceCounter, feature] * v[feature, 0];
199            y += ds[instanceCounter, feature] * v[feature, 1];
200          }
201          IItem item;
202          if (instance.Results.TryGetValue("Projection.PCA1", out item)) {
203            ((DoubleValue)item).Value = x;
204          } else instance.Results.Add("Projection.PCA1", new DoubleValue(x));
205          if (instance.Results.TryGetValue("Projection.PCA2", out item)) {
206            ((DoubleValue)item).Value = y;
207          } else instance.Results.Add("Projection.PCA2", new DoubleValue(y));
208
209          instanceCounter++;
210
211          var bkQuality = ((DoubleValue)instance.Parameters["BestKnownQuality"]).Value;
212          var maximization = ((BoolValue)instance.Parameters["Maximization"]).Value;
213
214          if (!algInstRunDict.ContainsKey(probInstanceName)) continue;
215          foreach (var kvp in algInstRunDict[probInstanceName]) {
216            var algInstanceName = kvp.Key;
217            // TODO: Things needs to be configurable here (table name, targets)
218            foreach (var target in new[] { 1, 1.01, 1.05, 1.1, 1.2, 1.5 }) {
219              var result = ExpectedRuntimeHelper.CalculateErt(kvp.Value, "QualityPerEvaluations", bkQuality * target, maximization);
220              var resultName = algInstanceName + "@" + ((target - 1) * 100) + "%";
221              if (instance.Results.TryGetValue(resultName, out item)) {
222                ((DoubleValue)item).Value = Math.Log10(result.ExpectedRuntime);
223              } else instance.Results.Add(resultName, new DoubleValue(Math.Log10(result.ExpectedRuntime)));
224            }
225          }
226        }
227      } finally { ProblemInstances.UpdateOfRunsInProgress = false; }
228    }
229
230    private static readonly HashSet<string> InterestingValueNames = new HashSet<string>() {
231      "QualityPerEvaluations", "Problem Name", "Problem Type", "Algorithm Name", "Algorithm Type", "Maximization"
232    };
233
234    public async void UpdateKnowledgeBaseAsync(IProgress progress) {
235      progress.Start("Updating Knowledge Base from OKB");
236      await Task.Factory.StartNew(() => { DoUpdateKnowledgeBase(progress); }, TaskCreationOptions.LongRunning);
237    }
238
239    public void UpdateKnowledgeBase() {
240      DoUpdateKnowledgeBase(new Progress(string.Empty, ProgressState.Started));
241    }
242
243    private void DoUpdateKnowledgeBase(IProgress progress) {
244      var queryClient = Clients.OKB.Query.QueryClient.Instance;
245      var adminClient = Clients.OKB.Administration.AdministrationClient.Instance;
246      try {
247        progress.Status = "Refreshing query client...";
248        queryClient.Refresh();
249        var interestingValues = queryClient.ValueNames.Where(x => InterestingValueNames.Contains(x.Name)).ToList();
250
251        var problemTypeFilter = (Clients.OKB.Query.StringComparisonAvailableValuesFilter)queryClient.Filters.Single(x => x.Label == "Problem Data Type Name");
252        problemTypeFilter.Value = Problem.GetType().Name;
253
254        progress.Status = "Obtaining number of runs...";
255        var count = queryClient.GetNumberOfRuns(problemTypeFilter);
256        if (count == 0) return;
257
258        var runIds = queryClient.GetRunIds(problemTypeFilter).ToList();
259        adminClient.Refresh();
260        var i = 0;
261        var conversions = new List<Task>();
262        var runGroup = new Dictionary<Tuple<long, string>, List<IRun>>();
263        while (i < count) {
264          var nextIds = runIds.Skip(i).Take(500).ToList();
265          progress.Status = string.Format("Downloading runs {0} to {1} of {2}...", i, i + nextIds.Count, count);
266          var okbRuns = queryClient.GetRunsWithValues(nextIds, true, interestingValues);
267          conversions.Add(Task.Factory.StartNew(() => {
268            var hlRuns = okbRuns.AsParallel().Select(x => new { Id = x.Algorithm.Id, Name = x.Algorithm.Name, Run = queryClient.ConvertToOptimizationRun(x) })
269                                .GroupBy(x => Tuple.Create(x.Id, x.Name)).ToList();
270            lock (runGroup) {
271              foreach (var hr in hlRuns) {
272                List<IRun> runList;
273                if (!runGroup.TryGetValue(hr.Key, out runList)) {
274                  runList = new List<IRun>();
275                  runGroup[hr.Key] = runList;
276                }
277                runList.AddRange(hr.Select(x => x.Run));
278              }
279            }
280          }));
281          i += nextIds.Count;
282          progress.ProgressValue = 0.8 * (i / (double)count);
283        }
284        Task.WaitAll(conversions.ToArray());
285        var list = new ItemList<IAlgorithm>();
286        i = 0;
287        foreach (var rGroup in runGroup) {
288          progress.Status = string.Format("Downloading algorithm {0}...", rGroup.Key.Item2);
289          var data = Clients.OKB.Administration.AdministrationClient.GetAlgorithmData(rGroup.Key.Item1);
290          if (data != null) {
291            using (var stream = new MemoryStream(data)) {
292              try {
293                var alg = (IAlgorithm)XmlParser.Deserialize<IContent>(stream);
294                alg.Runs.AddRange(rGroup.Value);
295                list.Add(alg);
296              } catch (Exception) { }
297              stream.Close();
298            }
299          }
300          i++;
301          progress.ProgressValue = 0.8 + 0.2 * (i / (double)runGroup.Count);
302        }
303        AlgorithmInstances = list;
304      } finally { progress.Finish(); }
305    }
306
307    private void UpdateSuggestions() {
308      if (Problem == null) return;
309      var instances = new SortedList<double, IAlgorithm>();
310      foreach (var instance in algorithmInstances) {
311        var relevantRuns = instance.Runs.Where(x => ((StringValue)x.Parameters["Problem Type"]).Value == Problem.GetType().Name);
312        var avgQuality = 0.0;
313        var counter = 0;
314        foreach (var run in relevantRuns) {
315          var performanceGraph = ((IndexedDataTable<double>)run.Results["QualityPerEvaluations"]);
316          try {
317            avgQuality += performanceGraph.Rows.First().Values.TakeWhile(x => x.Item1 < MaximumEvaluations).Last().Item2;
318            counter++;
319          } catch { continue; }
320        }
321        avgQuality /= counter;
322        instances.Add(avgQuality, instance);
323      }
324
325      suggestedInstances.Clear();
326      var instanceLadder = instances.Select(x => x.Value);
327      suggestedInstances.AddRange(Maximization ? instanceLadder.Reverse() : instanceLadder);
328    }
329
330    public event PropertyChangedEventHandler PropertyChanged;
331    private void OnPropertyChanged(string propertyName) {
332      var handler = PropertyChanged;
333      if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
334    }
335  }
336}
Note: See TracBrowser for help on using the repository browser.