Index: anches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/DistanceWeightedRecommender.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/DistanceWeightedRecommender.cs	(revision 13786)
+++ 	(revision )
@@ -1,118 +1,0 @@
-﻿#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
- */
-#endregion
-
-using HeuristicLab.Analysis;
-using HeuristicLab.Common;
-using HeuristicLab.Core;
-using HeuristicLab.Data;
-using HeuristicLab.Optimization;
-using HeuristicLab.Parameters;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-namespace HeuristicLab.OptimizationExpertSystem.Common {
-  [Item("Distance Weighted Recommender", "")]
-  [StorableClass]
-  public class DistanceWeightedRecommender : ParameterizedNamedItem, IAlgorithmInstanceRecommender {
-    private KnowledgeCenter okc;
-
-    private IFixedValueParameter<EnumValue<ProblemInstanceProximityType>> ProximityTypeParameter {
-      get { return (IFixedValueParameter<EnumValue<ProblemInstanceProximityType>>)Parameters["ProximityType"]; }
-    }
-
-    private IFixedValueParameter<DoubleValue> NeighborhoodFactorParameter {
-      get { return (IFixedValueParameter<DoubleValue>)Parameters["NeighborhoodFactor"]; }
-    }
-
-    public ProblemInstanceProximityType ProximityType {
-      get { return ProximityTypeParameter.Value.Value; }
-      set { ProximityTypeParameter.Value.Value = value; }
-    }
-
-    public double NeighborhoodFactor {
-      get { return NeighborhoodFactorParameter.Value.Value; }
-      set { NeighborhoodFactorParameter.Value.Value = value; }
-    }
-    
-    [StorableConstructor]
-    private DistanceWeightedRecommender(bool deserializing) : base(deserializing) { }
-    private DistanceWeightedRecommender(DistanceWeightedRecommender original, Cloner cloner)
-      : base(original, cloner) { }
-    public DistanceWeightedRecommender(KnowledgeCenter okc) {
-      this.okc = okc;
-      Parameters.Add(new FixedValueParameter<EnumValue<ProblemInstanceProximityType>>("ProximityType", "The type of neighbor proximity.", new EnumValue<ProblemInstanceProximityType>(ProblemInstanceProximityType.FeatureSpace)));
-      Parameters.Add(new FixedValueParameter<DoubleValue>("NeighborhoodFactor", "Penalize neighbors that are far away.", new DoubleValue(5)));
-    }
-
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new DistanceWeightedRecommender(this, cloner);
-    }
-
-    public IEnumerable<IAlgorithm> GetRanking() {
-      if (okc.Problem.ProblemId == -1) yield break;
-
-      var piDistances = okc.GetProblemDistances(ProximityType);
-      var maxDist = piDistances.Max(x => x.Value);
-      var instances = new SortedList<double, IAlgorithm>();
-      foreach (var relevantRuns in okc.GetKnowledgeBaseByAlgorithm()) {
-        var algorithm = relevantRuns.Key;
-        Func<double, double> distFunc = (d) => Math.Exp(NeighborhoodFactor * (-d / maxDist));
-        var pis = relevantRuns.Value.Select(x => ((StringValue)x.Parameters["Problem Name"]).Value).Distinct()
-                              .Select(x => Tuple.Create(x, okc.ProblemInstances.SingleOrDefault(y => ((StringValue)y.Parameters["Problem Name"]).Value == x)))
-                              .Where(x => x.Item2 != null && x.Item2.Parameters.ContainsKey("BestKnownQuality") && piDistances.ContainsKey(x.Item2))
-                              .Select(x => Tuple.Create(x.Item1, distFunc(piDistances[x.Item2]), ((DoubleValue)x.Item2.Parameters["BestKnownQuality"]).Value))
-                              .ToDictionary(x => x.Item1, x => Tuple.Create(x.Item2, x.Item3));
-        var sumPis = pis.Sum(x => x.Value.Item1);
-        var avgERT = 0.0;
-        foreach (var problemRuns in relevantRuns.Value.GroupBy(x => ((StringValue)x.Parameters["Problem Name"]).Value)) {
-          Tuple<double, double> info;
-          if (!pis.TryGetValue(problemRuns.Key, out info)) continue;
-          var convGraph = new List<List<Tuple<double, double>>>();
-          foreach (var run in problemRuns) {
-            var current = new List<Tuple<double, double>>();
-            var performanceGraph = ((IndexedDataTable<double>)run.Results["QualityPerEvaluations"]);
-            current.AddRange(performanceGraph.Rows.First().Values.TakeWhile(v => v.Item1 < okc.MaximumEvaluations.Value));
-            if (current.Count > 0) {
-              current.Add(Tuple.Create((double)okc.MaximumEvaluations.Value, current.Last().Item2));
-              convGraph.Add(current);
-            }
-          }
-          var ert = ExpectedRuntimeHelper.CalculateErt(convGraph, (okc.Maximization ? (1 - okc.MinimumTarget.Value) : (1 + okc.MinimumTarget.Value)) * info.Item2, okc.Maximization).ExpectedRuntime;
-          if (double.IsNaN(ert)) {
-            ert = ExpectedRuntimeHelper.CalculateErt(problemRuns.ToList(), "QualityPerEvaluations", (okc.Maximization ? (1 - okc.MinimumTarget.Value) : (1 + okc.MinimumTarget.Value)) * info.Item2, okc.Maximization).ExpectedRuntime;
-            if (double.IsNaN(ert)) ert = int.MaxValue;
-          }
-          avgERT += info.Item1 * ert;
-        }
-        avgERT /= sumPis;
-        if (instances.ContainsKey(avgERT)) {
-          avgERT += new System.Random().NextDouble();
-        }
-        instances.Add(avgERT, algorithm);
-      }
-
-      foreach (var alg in instances.Select(x => (IAlgorithm)x.Value.Clone()))
-        yield return alg;
-    }
-  }
-}
Index: /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/Enums.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/Enums.cs	(revision 13786)
+++ /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/Enums.cs	(revision 13787)
@@ -26,10 +26,3 @@
     SeedByCloning
   }
-
-  public enum ProblemInstanceProximityType {
-    FeatureSpace,
-    PCA,
-    MDS,
-    SOM
-  }
 }
Index: /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/HeuristicLab.OptimizationExpertSystem.Common-3.3.csproj
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/HeuristicLab.OptimizationExpertSystem.Common-3.3.csproj	(revision 13786)
+++ /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/HeuristicLab.OptimizationExpertSystem.Common-3.3.csproj	(revision 13787)
@@ -158,11 +158,14 @@
   </ItemGroup>
   <ItemGroup>
-    <Compile Include="OverallBestRecommender.cs" />
-    <Compile Include="DistanceWeightedRecommender.cs" />
-    <Compile Include="IAlgorithmInstanceRecommender.cs" />
-    <Compile Include="KNearestNeighborRecommender.cs" />
+    <Compile Include="Interfaces\IRecommendationModel.cs" />
+    <Compile Include="Recommenders\KNearestNeighborModel.cs" />
+    <Compile Include="Recommenders\OverallBestRecommender.cs" />
+    <Compile Include="Recommenders\DistanceWeightedRecommender.cs" />
+    <Compile Include="Interfaces\IAlgorithmInstanceRecommender.cs" />
+    <Compile Include="Recommenders\KNearestNeighborRecommender.cs" />
     <Compile Include="KnowledgeCenter.cs" />
     <Compile Include="Plugin.cs" />
     <Compile Include="Enums.cs" />
+    <Compile Include="Recommenders\FixedRankModel.cs" />
     <None Include="Properties\AssemblyInfo.cs.frame" />
     <Compile Include="ProblemCharacteristicAnalysis\CharacteristicCalculator.cs" />
Index: anches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/IAlgorithmInstanceRecommender.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/IAlgorithmInstanceRecommender.cs	(revision 13786)
+++ 	(revision )
@@ -1,30 +1,0 @@
-﻿#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
- */
-#endregion
-
-using HeuristicLab.Common;
-using HeuristicLab.Optimization;
-using System.Collections.Generic;
-
-namespace HeuristicLab.OptimizationExpertSystem.Common {
-  public interface IAlgorithmInstanceRecommender : IContent {
-    IEnumerable<IAlgorithm> GetRanking();
-  }
-}
Index: /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/Interfaces/IAlgorithmInstanceRecommender.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/Interfaces/IAlgorithmInstanceRecommender.cs	(revision 13787)
+++ /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/Interfaces/IAlgorithmInstanceRecommender.cs	(revision 13787)
@@ -0,0 +1,28 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Core;
+
+namespace HeuristicLab.OptimizationExpertSystem.Common {
+  public interface IAlgorithmInstanceRecommender : IParameterizedItem {
+    IRecommendationModel TrainModel(KnowledgeCenter kc, string[] characteristics);
+  }
+}
Index: /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/Interfaces/IRecommendationModel.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/Interfaces/IRecommendationModel.cs	(revision 13787)
+++ /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/Interfaces/IRecommendationModel.cs	(revision 13787)
@@ -0,0 +1,31 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Optimization;
+using System;
+using System.Collections.Generic;
+
+namespace HeuristicLab.OptimizationExpertSystem.Common {
+  public interface IRecommendationModel : IContent {
+    IEnumerable<Tuple<IAlgorithm, double>> GetRanking(KnowledgeCenter kc);
+  }
+}
Index: anches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/KNearestNeighborRecommender.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/KNearestNeighborRecommender.cs	(revision 13786)
+++ 	(revision )
@@ -1,95 +1,0 @@
-﻿#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
- */
-#endregion
-
-using HeuristicLab.Common;
-using HeuristicLab.Core;
-using HeuristicLab.Data;
-using HeuristicLab.Optimization;
-using HeuristicLab.Parameters;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-using System.Collections.Generic;
-using System.Linq;
-
-namespace HeuristicLab.OptimizationExpertSystem.Common {
-  [Item("K-Nearest Neighbor Recommender", "")]
-  [StorableClass]
-  public sealed class KNearestNeighborRecommender : ParameterizedNamedItem, IAlgorithmInstanceRecommender {
-    private KnowledgeCenter okc;
-
-    private IFixedValueParameter<EnumValue<ProblemInstanceProximityType>> ProximityTypeParameter {
-      get { return (IFixedValueParameter<EnumValue<ProblemInstanceProximityType>>)Parameters["ProximityType"]; }
-    }
-
-    public ProblemInstanceProximityType ProximityType {
-      get { return ProximityTypeParameter.Value.Value; }
-      set { ProximityTypeParameter.Value.Value = value; }
-    }
-
-    private IFixedValueParameter<IntValue> KParameter {
-      get { return (IFixedValueParameter<IntValue>)Parameters["K"]; }
-    }
-
-    [StorableConstructor]
-    private KNearestNeighborRecommender(bool deserializing) : base(deserializing) { }
-    private KNearestNeighborRecommender(KNearestNeighborRecommender original, Cloner cloner)
-      : base(original, cloner) { }
-    public KNearestNeighborRecommender(KnowledgeCenter okc) {
-      this.okc = okc;
-      Parameters.Add(new FixedValueParameter<EnumValue<ProblemInstanceProximityType>>("ProximityType", "The type of neighbor proximity.", new EnumValue<ProblemInstanceProximityType>(ProblemInstanceProximityType.FeatureSpace)));
-      Parameters.Add(new FixedValueParameter<IntValue>("K", "The number of nearest neighbors to consider.", new IntValue(5)));
-    }
-
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new KNearestNeighborRecommender(this, cloner);
-    }
-
-    public IEnumerable<IAlgorithm> GetRanking() {
-      if (okc.Problem.ProblemId == -1) yield break;
-
-      var distances = okc.GetProblemDistances(ProximityType);
-      var K = KParameter.Value.Value;
-      var performances = new Dictionary<IAlgorithm, List<double>>();
-      for (var k = 0; k < K; k++) {
-        if (distances.Count == 0) break;
-        var min = distances.MinItems(x => x.Value).First();
-        // lookup algorithm performances in min
-        var perfs = okc.GetAlgorithmPerformance(min.Key);
-        if (perfs.Count == 0) {
-          k--;
-          continue;
-        }
-        foreach (var p in perfs) {
-          var ert = p.Value;
-          if (double.IsNaN(ert)) ert = int.MaxValue;
-          List<double> erts;
-          if (!performances.TryGetValue(p.Key, out erts)) {
-            performances[p.Key] = new List<double>() { ert }; ;
-          } else erts.Add(ert);
-        }
-        distances.Remove(min.Key);
-      }
-      foreach (var alg in performances.Select(x => new { Alg = x.Key, Perf = x.Value.Average() })
-                         .OrderBy(x => x.Perf)
-                         .Select(x => x.Alg))
-        yield return alg;
-    }
-  }
-}
Index: /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/KnowledgeCenter.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/KnowledgeCenter.cs	(revision 13786)
+++ /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/KnowledgeCenter.cs	(revision 13787)
@@ -96,14 +96,12 @@
     }
 
-    private readonly CheckedItemList<StringValue> problemCharacteristics;
-    private readonly ReadOnlyCheckedItemList<StringValue> readonlyProblemCharacteristics; 
-    public ReadOnlyCheckedItemList<StringValue> ProblemCharacteristics {
-      get { return readonlyProblemCharacteristics; }
-    }
-
-    private IAlgorithmInstanceRecommender algorithmInstanceRecommender;
-    public IAlgorithmInstanceRecommender AlgorithmInstanceRecommender {
-      get { return algorithmInstanceRecommender; }
-      set { algorithmInstanceRecommender = value; }
+    private IRecommendationModel recommendationModel;
+    public IRecommendationModel RecommendationModel {
+      get { return recommendationModel; }
+      set {
+        if (recommendationModel == value) return;
+        recommendationModel = value;
+        OnRecommenderModelChanged();
+      }
     }
 
@@ -135,7 +133,5 @@
       readonlyAlgorithmInstances = algorithmInstances.AsReadOnly();
       problemInstances = new RunCollection();
-      problemCharacteristics = new CheckedItemList<StringValue>();
-      readonlyProblemCharacteristics = problemCharacteristics.AsReadOnly();
-      algorithmInstanceRecommender = new OverallBestRecommender(this);
+      recommendationModel = FixedRankModel.GetEmpty();
       problem = new SingleObjectiveOKBProblem();
       algorithmId2RunMapping = new BidirectionalLookup<long, IRun>();
@@ -167,17 +163,12 @@
       knowledgeBase.ItemsAdded += InformationChanged;
       knowledgeBase.ItemsRemoved += InformationChanged;
-      problemCharacteristics.ItemsAdded += CharacteristicChanged;
-      problemCharacteristics.ItemsReplaced += CharacteristicChanged;
-      problemCharacteristics.ItemsRemoved += CharacteristicChanged;
-      problemCharacteristics.CollectionReset += CharacteristicChanged;
-      problemCharacteristics.CheckedItemsChanged += CharacteristicChanged;
     }
 
     private void MaximumEvaluationsOnValueChanged(object sender, EventArgs eventArgs) {
-      UpdateSuggestions();
+
     }
 
     private void MinimumTargetOnValueChanged(object sender, EventArgs e) {
-      UpdateSuggestions();
+
     }
 
@@ -192,10 +183,4 @@
       var runCollection = sender as RunCollection;
       if (runCollection != null && runCollection.UpdateOfRunsInProgress) return;
-      UpdateSuggestions();
-    }
-
-    private void CharacteristicChanged(object sender, EventArgs e) {
-      if (SuppressEvents) return;
-      UpdateInstanceProjection();
     }
     
@@ -205,8 +190,8 @@
     }
 
-    public void UpdateInstanceProjection() {
-      if (ProblemCharacteristics.Count == 0) return;
-
-      var instances = GetProblemCharacteristics();
+    public void UpdateInstanceProjection(string[] characteristics) {
+      if (characteristics.Length == 0) return;
+
+      var instances = GetProblemCharacteristics(characteristics);
 
       var key2Idx = new BidirectionalDictionary<IRun, int>();
@@ -227,5 +212,5 @@
       #endregion
       #region PCA
-      var ds = new double[instances.Count, ProblemCharacteristics.CheckedItems.Count()];
+      var ds = new double[instances.Count, characteristics.Length];
       foreach (var instance in instances) {
         var arr = instance.Value;
@@ -240,5 +225,5 @@
       #endregion
       #region SOM
-      var features = new DoubleMatrix(ProblemCharacteristics.CheckedItems.Count(), instances.Count);
+      var features = new DoubleMatrix(characteristics.Length, instances.Count);
       foreach (var instance in instances) {
         var arr = instance.Value;
@@ -283,11 +268,11 @@
     }
 
-    private Dictionary<IRun, double[]> GetProblemCharacteristics() {
+    public Dictionary<IRun, double[]> GetProblemCharacteristics(string[] characteristics) {
       var instances = new Dictionary<IRun, double[]>();
-      var values = new List<double>[ProblemCharacteristics.CheckedItems.Count()];
+      var values = new List<double>[characteristics.Length];
       foreach (var run in ProblemInstances) {
         var f = 0;
-        instances[run] = new double[ProblemCharacteristics.CheckedItems.Count()];
-        foreach (var c in ProblemCharacteristics.CheckedItems.Select(x => x.Value.Value)) {
+        instances[run] = new double[characteristics.Length];
+        foreach (var c in characteristics) {
           if (values[f] == null) values[f] = new List<double>(ProblemInstances.Count);
           IItem item;
@@ -514,4 +499,5 @@
             if (alg != null) {
               lock (algorithmId2AlgorithmInstanceMapping) {
+                algorithmInstances.Add(alg);
                 algorithmId2AlgorithmInstanceMapping.Add(algInst.Id, alg);
                 progress.Status = string.Format("Downloaded algorithm {0} (okb-id: {1})...", algInst.Name, algInst.Id);
@@ -549,62 +535,5 @@
 
         progress.Status = "Finishing...";
-        var algInstRunDict = runList.Where(x => x.Parameters.ContainsKey("Problem Name") && x.Parameters["Problem Name"] is StringValue)
-                                          .GroupBy(x => ((StringValue)x.Parameters["Problem Name"]).Value)
-                                          .ToDictionary(x => x.Key, x => x.GroupBy(y => ((StringValue)y.Parameters["Algorithm Name"]).Value)
-                                                                                  .ToDictionary(y => y.Key, y => y.ToList()));
-
-        foreach (var instance in ProblemInstances) {
-          IItem probNameParam;
-          if (!instance.Parameters.TryGetValue("Problem Name", out probNameParam)) continue;
-
-          var probInstanceName = ((StringValue)probNameParam).Value;
-          var maximization = ((BoolValue)instance.Parameters["Maximization"]).Value;
-          
-          IItem bkParam;
-          if (!instance.Parameters.TryGetValue("BestKnownQuality", out bkParam) || !(bkParam is DoubleValue)) {
-            Dictionary<string, List<IRun>> algRuns;
-            if (!algInstRunDict.TryGetValue(probInstanceName, out algRuns)) continue;
-            var list = algRuns.SelectMany(x => x.Value)
-                              .Where(x => x.Results.ContainsKey("QualityPerEvaluations"))
-                              .Select(x => ((IndexedDataTable<double>)x.Results["QualityPerEvaluations"]).Rows.First().Values.Last().Item2);
-            bkParam = new DoubleValue(maximization ? list.Max() : list.Min());
-            instance.Parameters["BestKnownQuality"] = bkParam;
-          } else bkParam = instance.Parameters["BestKnownQuality"];
-
-          var bkQuality = ((DoubleValue)bkParam).Value;
-
-          if (!algInstRunDict.ContainsKey(probInstanceName)) continue;
-          // TODO: Things needs to be configurable here (table name, targets)
-          foreach (var target in new[] { 1, 1.01, 1.05, 1.1, 1.2, 1.5 }) {
-            var indexMap = new BidirectionalDictionary<string, int>();
-            var dict = new Dictionary<string, double>();
-            var idx = 0;
-            foreach (var kvp in algInstRunDict[probInstanceName]) {
-              var result = ExpectedRuntimeHelper.CalculateErt(kvp.Value, "QualityPerEvaluations", bkQuality * target, maximization);
-              indexMap.Add(kvp.Key, idx);
-              dict[kvp.Key] = !double.IsNaN(result.ExpectedRuntime) ? result.ExpectedRuntime : int.MaxValue;
-              idx++;
-            }
-            var points = dict.OrderBy(x => indexMap.GetByFirst(x.Key)).Select(x => x.Value > 0 ? Math.Log10(x.Value) : 0).ToArray();
-            int[] clusters;
-            Ckmeans1dClusters(points, 5, out clusters);
-            var ranks = clusters.Select((c, i) => new { Cluster = c, Perf = dict[indexMap.GetBySecond(i)] })
-                                .GroupBy(x => x.Cluster, x => x.Perf)
-                                .Select(x => new { Cluster = x.Key, AvgPerf = x.Average() })
-                                .OrderBy(x => x.AvgPerf)
-                                .Select((c, i) => new { Cluster = c.Cluster, Rank = i })
-                                .ToDictionary(x => x.Cluster, x => x.Rank);
-            for (var i = 0; i < clusters.Length; i++) {
-              var resultName = "Rank." + indexMap.GetBySecond(i) + "@" + ((target - 1) * 100) + "%";
-              instance.Results[resultName] = new IntValue(dict[indexMap.GetBySecond(i)] < int.MaxValue ? ranks[clusters[i]] : 6);
-            }
-          }
-        }
-        try {
-          SuppressEvents = true;
-          problemCharacteristics.Replace(characteristics.Select(x => new StringValue(x)));
-          foreach (var pc in problemCharacteristics.Where(x => !x.Value.StartsWith("Characteristic.")))
-            problemCharacteristics.SetItemCheckedState(pc, false);
-        } finally { SuppressEvents = false; }
+        
         try {
           KnowledgeBase.UpdateOfRunsInProgress = true;
@@ -612,18 +541,45 @@
           KnowledgeBase.AddRange(runList);
         } finally { KnowledgeBase.UpdateOfRunsInProgress = false; }
+
+        var algInstRunDict = runList.Where(x => x.Parameters.ContainsKey("Problem Name") && x.Parameters["Problem Name"] is StringValue)
+                                          .GroupBy(x => ((StringValue)x.Parameters["Problem Name"]).Value)
+                                          .ToDictionary(x => x.Key, x => x.GroupBy(y => ((StringValue)y.Parameters["Algorithm Name"]).Value)
+                                                                                  .ToDictionary(y => y.Key, y => y.ToList()));
+
+        // set best-known quality to best-found in case it is not known
+        foreach (var kvp in algInstRunDict) {
+          var prob = ProblemInstances.SingleOrDefault(x => ((StringValue)x.Parameters["Problem Name"]).Value == kvp.Key);
+          if (prob == null) continue;
+          var maximization = ((BoolValue)prob.Parameters["Maximization"]).Value;
+
+          IItem bkParam;
+          if (!prob.Parameters.TryGetValue("BestKnownQuality", out bkParam) || !(bkParam is DoubleValue)) {
+            var list = kvp.Value.SelectMany(x => x.Value)
+              .Where(x => x.Results.ContainsKey("QualityPerEvaluations"))
+              .Select(x => ((IndexedDataTable<double>)x.Results["QualityPerEvaluations"]).Rows.First().Values.Last().Item2);
+            if (!list.Any()) continue;
+            bkParam = new DoubleValue(maximization ? list.Max() : list.Min());
+            prob.Parameters["BestKnownQuality"] = bkParam;
+          }
+        }
+
+        // add algorithm instance ranks as features to the problem instances for a range of targets
+        foreach (var target in new[] {1, 1.01, 1.05, 1.1, 1.2, 1.5}) {
+          var cls = GetPerformanceClasses(target, 5);
+          foreach (var kvp in cls) {
+            var prob = kvp.Key;
+            foreach (var kvp2 in kvp.Value) {
+              var resultName = "Rank." + algorithmId2AlgorithmInstanceMapping.GetByFirst(kvp2.Key) + "@" + ((target - 1) * 100) + "%";
+              prob.Results[resultName] = new IntValue(kvp2.Value);
+            }
+          }
+        }
       } finally { progress.Finish(); ProblemInstances.UpdateOfRunsInProgress = false; }
-      UpdateInstanceProjection();
-      UpdateSuggestions();
-    }
-
-    public void UpdateSuggestions() {
-      // TODO: Maintain a separate list of suggested instances
-      // TODO: expose expected expected run time
-      algorithmInstances.Replace(AlgorithmInstanceRecommender.GetRanking());
+      UpdateInstanceProjection(ProblemInstances.ResultNames.Where(x => x.StartsWith("Characteristic.")).ToArray());
     }
 
     public Dictionary<IAlgorithm, double> GetAlgorithmPerformance(IRun problemInstance) {
       if (!problemInstance.Parameters.ContainsKey("BestKnownQuality")) return new Dictionary<IAlgorithm, double>();
-      var target = GetTarget(((DoubleValue)problemInstance.Parameters["BestKnownQuality"]).Value);
+      var target = GetTarget(((DoubleValue)problemInstance.Parameters["BestKnownQuality"]).Value, Maximization);
       return knowledgeBase.Where(x => ((StringValue)x.Parameters["Problem Name"]).Value == ((StringValue)problemInstance.Parameters["Problem Name"]).Value)
                           .GroupBy(x => algorithmId2AlgorithmInstanceMapping.GetByFirst(algorithmId2RunMapping.GetBySecond(x).Single()))
@@ -636,7 +592,7 @@
     }
 
-    public IEnumerable<IRegressionProblem> GetDataAnalysisProblem(double target) {
+    public IEnumerable<IRegressionProblem> GetRegressionProblemPerAlgorithmInstance(double target, string[] characteristics) {
       if (Problem == null) yield break;
-      var characteristics = GetProblemCharacteristics();
+      var features = GetProblemCharacteristics(characteristics);
       // TODO: knowledgebase only stores problem name as a string
       // this doesn't work if there are two equally named problem instances
@@ -647,17 +603,17 @@
         var ds = new ModifiableDataset();
         ds.AddVariable("Problem Name", new List<string>());
-        foreach (var pc in ProblemCharacteristics.CheckedItems)
-          ds.AddVariable(pc.Value.Value, new List<double>());
+        foreach (var pc in characteristics)
+          ds.AddVariable(pc, new List<double>());
         ds.AddVariable("ERT", new List<double>());
-        var max = Maximization;
         foreach (var pr in problemRuns) {
           var prob = problemMap[pr.Key];
-          var features = characteristics[prob];
+          var f = features[prob];
+          var max = ((BoolValue)prob.Parameters["Maximization"]).Value;
           var bkq = ((DoubleValue)prob.Parameters["BestKnownQuality"]).Value;
-          var ert = ExpectedRuntimeHelper.CalculateErt(pr.ToList(), "QualityPerEvaluations", GetTarget(bkq), max).ExpectedRuntime;
+          var ert = ExpectedRuntimeHelper.CalculateErt(pr.ToList(), "QualityPerEvaluations", GetTarget(bkq, max), max).ExpectedRuntime;
           if (double.IsNaN(ert)) ert = int.MaxValue;
-          ds.AddRow(new object[] { pr.Key }.Concat(features.Cast<object>()).Concat(new object[] { ert }));
-        }
-        var datAnalysisData = new RegressionProblemData(ds, ProblemCharacteristics.CheckedItems.Select(x => x.Value.Value), "ERT");
+          ds.AddRow(new object[] { pr.Key }.Concat(f.Cast<object>()).Concat(new object[] { ert }));
+        }
+        var datAnalysisData = new RegressionProblemData(ds, characteristics, "ERT");
         var result = new RegressionProblem() {
           Name = algorithmId2AlgorithmInstanceMapping.GetByFirst(relevantRuns.Key).Name
@@ -668,46 +624,90 @@
     }
 
-    private double GetTarget(double bestKnownQuality) {
-      return bestKnownQuality * (Maximization ? (1 - MinimumTarget.Value) : (1 + MinimumTarget.Value));
-    }
-
-    public Dictionary<IRun, double> GetProblemDistances(ProblemInstanceProximityType proximityType) {
-      var result = new Dictionary<IRun, double>(); 
+    public IEnumerable<IClassificationProblem> GetClassificationProblemPerAlgorithmInstance(double target, string[] characteristics) {
+      if (Problem == null) yield break;
+
+      var classes = GetPerformanceClasses(target, 5);
+      var features = GetProblemCharacteristics(characteristics);
+
+      foreach (var alg in AlgorithmInstances) {
+        var ds = new ModifiableDataset();
+        ds.AddVariable("Problem Name", new List<string>());
+        foreach (var pc in characteristics)
+          ds.AddVariable(pc, new List<double>());
+        ds.AddVariable("Class", new List<double>());
+
+        foreach (var c in classes) {
+          int cls;
+          if (c.Value.TryGetValue(algorithmId2AlgorithmInstanceMapping.GetBySecond(alg), out cls)) {
+            ds.AddRow(new object[] { ((StringValue)c.Key.Parameters["Problem Name"]).Value }
+              .Concat(features[c.Key].Cast<object>()).Concat(new object[] { cls }));
+          }
+        }
+        var datAnalysisData = new ClassificationProblemData(ds, characteristics, "Class");
+        var result = new ClassificationProblem() {
+          Name = alg.Name
+        };
+        result.ProblemDataParameter.Value = datAnalysisData;
+        yield return result;
+      }
+    }
+
+    public Dictionary<IRun, double> GetProblemDistances(string[] characteristics) {
+      var result = new Dictionary<IRun, double>();
       var currentInstance = problemId2ProblemInstanceMapping.GetByFirst(Problem.ProblemId);
-      switch (proximityType) {
-        case ProblemInstanceProximityType.MDS:
-        case ProblemInstanceProximityType.PCA:
-        case ProblemInstanceProximityType.SOM:
-          double xa, ya;
-          GetProjectionCoordinates(currentInstance, proximityType, out xa, out ya);
-          foreach (var b in ProblemInstances) {
-            if (b == currentInstance) continue;
-            double xb, yb;
-            GetProjectionCoordinates(b, proximityType, out xb, out yb);
-            var d = Math.Sqrt((xa - xb) * (xa - xb) + (ya - yb) * (ya - yb));
-            result[b] = d;
-          }
-          break;
-        case ProblemInstanceProximityType.FeatureSpace:
-          var features = GetProblemCharacteristics();
-          var cF = features[currentInstance];
-          foreach (var b in ProblemInstances) {
-            if (b == currentInstance) continue;
-            var sum = features[b].Select((t, f) => (cF[f] - t) * (cF[f] - t)).Sum();
-            result[b] = Math.Sqrt(sum);
-          }
-          break;
-        default: throw new InvalidOperationException(string.Format("Unkonwn proximity type {0}", proximityType));
+      var features = GetProblemCharacteristics(characteristics);
+      var cF = features[currentInstance];
+      foreach (var b in ProblemInstances) {
+        if (b == currentInstance) continue;
+        var sum = features[b].Select((t, f) => (cF[f] - t) * (cF[f] - t)).Sum();
+        result[b] = Math.Sqrt(sum);
       }
       return result;
     }
 
-    private void GetProjectionCoordinates(IRun problemInstance, ProblemInstanceProximityType proximityType, out double x, out double y) {
-      x = ((DoubleValue)problemInstance.Results["Projection." + proximityType + ".X"]).Value;
-      y = ((DoubleValue)problemInstance.Results["Projection." + proximityType + ".Y"]).Value;
-      if (proximityType == ProblemInstanceProximityType.SOM) {
-        x = Math.Floor(x);
-        y = Math.Floor(y);
-      }
+    public Dictionary<IRun, Dictionary<long, int>> GetPerformanceClasses(double target, int nClasses) {
+      var result = new Dictionary<IRun, Dictionary<long, int>>();
+      var problemMap = ProblemInstances.Select(x => new { Key = ((StringValue)x.Parameters["Problem Name"]).Value, Value = x })
+                                       .ToDictionary(x => x.Key, x => x.Value);
+      foreach (var pr in KnowledgeBase.GroupBy(x => ((StringValue)x.Parameters["Problem Name"]).Value).ToList()) {
+        var bkq = ((DoubleValue)problemMap[pr.Key].Parameters["BestKnownQuality"]).Value;
+        var max = ((BoolValue)problemMap[pr.Key].Parameters["Maximization"]).Value;
+
+        result[problemMap[pr.Key]] = new Dictionary<long, int>();
+
+        var indexMap = new BidirectionalDictionary<long, int>();
+        var perf = new Dictionary<long, double>();
+        var idx = 0;
+        foreach (var kvp in pr.GroupBy(x => algorithmId2RunMapping.GetBySecond(x).Single())) {
+          var ert = ExpectedRuntimeHelper.CalculateErt(kvp.ToList(), "QualityPerEvaluations", GetTarget(bkq, max), max).ExpectedRuntime;
+          if (double.IsNaN(ert)) {
+            // algorithm can't solve that instance with the given target
+            // these are put into their own additional class
+            result[problemMap[pr.Key]][kvp.Key] = nClasses;
+            continue;
+          }
+          indexMap.Add(kvp.Key, idx);
+          perf[kvp.Key] = Math.Log10(ert);
+          idx++;
+        }
+        if (perf.Count == 0) continue;
+        
+        var points = perf.OrderBy(x => indexMap.GetByFirst(x.Key)).Select(x => x.Value).ToArray();
+        int[] clusters;
+        Ckmeans1dClusters(points, nClasses, out clusters);
+        var ranks = clusters.Select((c, i) => new { Cluster = c, Perf = perf[indexMap.GetBySecond(i)] })
+                            .GroupBy(x => x.Cluster, x => x.Perf)
+                            .Select(x => new { Cluster = x.Key, AvgPerf = x.Average() })
+                            .OrderBy(x => x.AvgPerf)
+                            .Select((c, i) => new { Cluster = c.Cluster, Rank = i })
+                            .ToDictionary(x => x.Cluster, x => x.Rank);
+        for (var i = 0; i < clusters.Length; i++)
+          result[problemMap[pr.Key]][indexMap.GetBySecond(i)] = ranks[clusters[i]];
+      }
+      return result;
+    }
+
+    private double GetTarget(double bestKnownQuality, bool maximization) {
+      return bestKnownQuality * (maximization ? (1 - MinimumTarget.Value) : (1 + MinimumTarget.Value));
     }
 
@@ -722,4 +722,10 @@
       var handler = AlgorithmInstanceStarted;
       if (handler != null) handler(this, new EventArgs<IAlgorithm>(instance));
+    }
+
+    public event EventHandler RecommendationModelChanged;
+    private void OnRecommenderModelChanged() {
+      var handler = RecommendationModelChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
     }
 
@@ -809,4 +815,8 @@
       return mean;
     }
+
+    public IEnumerable<Tuple<IAlgorithm, double>> GetAlgorithmInstanceRanking() {
+      return RecommendationModel.GetRanking(this);
+    }
   }
 }
Index: anches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/OverallBestRecommender.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/OverallBestRecommender.cs	(revision 13786)
+++ 	(revision )
@@ -1,99 +1,0 @@
-﻿#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
- */
-#endregion
-
-using HeuristicLab.Analysis;
-using HeuristicLab.Common;
-using HeuristicLab.Core;
-using HeuristicLab.Data;
-using HeuristicLab.Optimization;
-using HeuristicLab.Parameters;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-namespace HeuristicLab.OptimizationExpertSystem.Common {
-  [Item("Overall Best Recommender", "")]
-  [StorableClass]
-  public class OverallBestRecommender : ParameterizedNamedItem, IAlgorithmInstanceRecommender {
-    private KnowledgeCenter okc;
-
-    private IFixedValueParameter<EnumValue<ProblemInstanceProximityType>> ProximityTypeParameter {
-      get { return (IFixedValueParameter<EnumValue<ProblemInstanceProximityType>>)Parameters["ProximityType"]; }
-    }
-
-    private IFixedValueParameter<DoubleValue> NeighborhoodFactorParameter {
-      get { return (IFixedValueParameter<DoubleValue>)Parameters["NeighborhoodFactor"]; }
-    }
-
-    public ProblemInstanceProximityType ProximityType {
-      get { return ProximityTypeParameter.Value.Value; }
-      set { ProximityTypeParameter.Value.Value = value; }
-    }
-
-    public double NeighborhoodFactor {
-      get { return NeighborhoodFactorParameter.Value.Value; }
-      set { NeighborhoodFactorParameter.Value.Value = value; }
-    }
-    
-    [StorableConstructor]
-    private OverallBestRecommender(bool deserializing) : base(deserializing) { }
-    private OverallBestRecommender(OverallBestRecommender original, Cloner cloner)
-      : base(original, cloner) { }
-    public OverallBestRecommender(KnowledgeCenter okc) {
-      this.okc = okc;
-      Parameters.Add(new FixedValueParameter<EnumValue<ProblemInstanceProximityType>>("ProximityType", "The type of neighbor proximity.", new EnumValue<ProblemInstanceProximityType>(ProblemInstanceProximityType.FeatureSpace)));
-      Parameters.Add(new FixedValueParameter<DoubleValue>("NeighborhoodFactor", "Penalize neighbors that are far away.", new DoubleValue(5)));
-    }
-
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new OverallBestRecommender(this, cloner);
-    }
-
-    public IEnumerable<IAlgorithm> GetRanking() {
-      if (okc.Problem.ProblemId == -1) yield break;
-
-      var instances = new List<Tuple<IAlgorithm, double>>();
-      foreach (var relevantRuns in okc.GetKnowledgeBaseByAlgorithm()) {
-        var algorithm = relevantRuns.Key;
-        var pis = relevantRuns.Value.Select(x => ((StringValue)x.Parameters["Problem Name"]).Value).Distinct()
-                              .Select(x => Tuple.Create(x, okc.ProblemInstances.SingleOrDefault(y => ((StringValue)y.Parameters["Problem Name"]).Value == x)))
-                              .Where(x => x.Item2 != null)
-                              .Select(x => Tuple.Create(x.Item1, ((DoubleValue)x.Item2.Parameters["BestKnownQuality"]).Value))
-                              .ToDictionary(x => x.Item1, x => x.Item2);
-        var avgERT = 0.0;
-        var count = 0;
-        foreach (var problemRuns in relevantRuns.Value.GroupBy(x => ((StringValue)x.Parameters["Problem Name"]).Value)) {
-          var bkq = pis[problemRuns.Key];
-          var ert = ExpectedRuntimeHelper.CalculateErt(problemRuns.ToList(), "QualityPerEvaluations", (okc.Maximization ? (1 - okc.MinimumTarget.Value) : (1 + okc.MinimumTarget.Value)) * bkq, okc.Maximization).ExpectedRuntime;
-          if (double.IsNaN(ert)) ert = int.MaxValue;
-          avgERT += ert;
-          count++;
-        }
-        avgERT /= count;
-        instances.Add(Tuple.Create(algorithm, avgERT));
-      }
-
-      foreach (var alg in instances.OrderBy(x => x.Item2).Select(x => (IAlgorithm)x.Item1.Clone()))
-        yield return alg;
-    }
-  }
-}
Index: /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/Recommenders/DistanceWeightedRecommender.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/Recommenders/DistanceWeightedRecommender.cs	(revision 13787)
+++ /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/Recommenders/DistanceWeightedRecommender.cs	(revision 13787)
@@ -0,0 +1,103 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Analysis;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace HeuristicLab.OptimizationExpertSystem.Common {
+  [Item("Distance Weighted Recommender", "")]
+  [StorableClass]
+  public class DistanceWeightedRecommender : ParameterizedNamedItem, IAlgorithmInstanceRecommender {
+
+    private IFixedValueParameter<DoubleValue> NeighborhoodFactorParameter {
+      get { return (IFixedValueParameter<DoubleValue>)Parameters["NeighborhoodFactor"]; }
+    }
+
+    public double NeighborhoodFactor {
+      get { return NeighborhoodFactorParameter.Value.Value; }
+      set { NeighborhoodFactorParameter.Value.Value = value; }
+    }
+    
+    [StorableConstructor]
+    private DistanceWeightedRecommender(bool deserializing) : base(deserializing) { }
+    private DistanceWeightedRecommender(DistanceWeightedRecommender original, Cloner cloner)
+      : base(original, cloner) { }
+    public DistanceWeightedRecommender() {
+      Parameters.Add(new FixedValueParameter<DoubleValue>("NeighborhoodFactor", "Penalize neighbors that are far away.", new DoubleValue(5)));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new DistanceWeightedRecommender(this, cloner);
+    }
+
+    public IRecommendationModel TrainModel(KnowledgeCenter okc, string[] characteristics) {
+      var piDistances = okc.GetProblemDistances(characteristics);
+      var maxDist = piDistances.Max(x => x.Value);
+      var instances = new SortedList<double, IAlgorithm>();
+      foreach (var relevantRuns in okc.GetKnowledgeBaseByAlgorithm()) {
+        var algorithm = relevantRuns.Key;
+        Func<double, double> distFunc = (d) => Math.Exp(NeighborhoodFactor * (-d / maxDist));
+        var pis = relevantRuns.Value.Select(x => ((StringValue)x.Parameters["Problem Name"]).Value).Distinct()
+                              .Select(x => Tuple.Create(x, okc.ProblemInstances.SingleOrDefault(y => ((StringValue)y.Parameters["Problem Name"]).Value == x)))
+                              .Where(x => x.Item2 != null && x.Item2.Parameters.ContainsKey("BestKnownQuality") && piDistances.ContainsKey(x.Item2))
+                              .Select(x => Tuple.Create(x.Item1, distFunc(piDistances[x.Item2]), ((DoubleValue)x.Item2.Parameters["BestKnownQuality"]).Value))
+                              .ToDictionary(x => x.Item1, x => Tuple.Create(x.Item2, x.Item3));
+        var sumPis = pis.Sum(x => x.Value.Item1);
+        var avgERT = 0.0;
+        foreach (var problemRuns in relevantRuns.Value.GroupBy(x => ((StringValue)x.Parameters["Problem Name"]).Value)) {
+          Tuple<double, double> info;
+          if (!pis.TryGetValue(problemRuns.Key, out info)) continue;
+          var convGraph = new List<List<Tuple<double, double>>>();
+          foreach (var run in problemRuns) {
+            var current = new List<Tuple<double, double>>();
+            var performanceGraph = ((IndexedDataTable<double>)run.Results["QualityPerEvaluations"]);
+            current.AddRange(performanceGraph.Rows.First().Values.TakeWhile(v => v.Item1 < okc.MaximumEvaluations.Value));
+            if (current.Count > 0) {
+              current.Add(Tuple.Create((double)okc.MaximumEvaluations.Value, current.Last().Item2));
+              convGraph.Add(current);
+            }
+          }
+          var ert = ExpectedRuntimeHelper.CalculateErt(convGraph, (okc.Maximization ? (1 - okc.MinimumTarget.Value) : (1 + okc.MinimumTarget.Value)) * info.Item2, okc.Maximization).ExpectedRuntime;
+          if (double.IsNaN(ert)) {
+            ert = ExpectedRuntimeHelper.CalculateErt(problemRuns.ToList(), "QualityPerEvaluations", (okc.Maximization ? (1 - okc.MinimumTarget.Value) : (1 + okc.MinimumTarget.Value)) * info.Item2, okc.Maximization).ExpectedRuntime;
+            if (double.IsNaN(ert)) ert = int.MaxValue;
+          }
+          avgERT += info.Item1 * ert;
+        }
+        avgERT /= sumPis;
+        if (instances.ContainsKey(avgERT)) {
+          avgERT += new System.Random().NextDouble();
+        }
+        instances.Add(avgERT, (IAlgorithm)algorithm.Clone());
+      }
+
+      return new FixedRankModel(instances.Select(x => Tuple.Create(x.Value, x.Key)));
+    }
+  }
+}
Index: /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/Recommenders/FixedRankModel.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/Recommenders/FixedRankModel.cs	(revision 13787)
+++ /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/Recommenders/FixedRankModel.cs	(revision 13787)
@@ -0,0 +1,44 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Optimization;
+using System;
+using System.Collections.Generic;
+
+namespace HeuristicLab.OptimizationExpertSystem.Common {
+  public class FixedRankModel : IRecommendationModel {
+    private List<Tuple<IAlgorithm, double>> ranking;
+
+    public FixedRankModel(IEnumerable<Tuple<IAlgorithm, double>> ranking) {
+      this.ranking = new List<Tuple<IAlgorithm, double>>();
+      foreach (var r in ranking) this.ranking.Add(r);
+    }
+ 
+    public IEnumerable<Tuple<IAlgorithm, double>> GetRanking(KnowledgeCenter kc) { 
+      if (kc.Problem.ProblemId == -1) return new Tuple<IAlgorithm, double>[0];
+      return ranking;
+    }
+
+    public static FixedRankModel GetEmpty() {
+      return new FixedRankModel(new Tuple<IAlgorithm, double>[0]);
+    }
+  }
+}
Index: /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/Recommenders/KNearestNeighborModel.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/Recommenders/KNearestNeighborModel.cs	(revision 13787)
+++ /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/Recommenders/KNearestNeighborModel.cs	(revision 13787)
@@ -0,0 +1,66 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Optimization;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace HeuristicLab.OptimizationExpertSystem.Common {
+  public class KNearestNeighborModel : IRecommendationModel {
+    private readonly int K;
+    private readonly string[] characteristics;
+
+    public KNearestNeighborModel(int k, string[] characteristics) {
+      this.K = k;
+      this.characteristics = characteristics;
+    }
+
+    public IEnumerable<Tuple<IAlgorithm, double>> GetRanking(KnowledgeCenter kc) {
+      var distances = kc.GetProblemDistances(characteristics);
+      var performances = new Dictionary<IAlgorithm, List<double>>();
+      for (var k = 0; k < K; k++) {
+        if (distances.Count == 0) break;
+        var min = distances.MinItems(x => x.Value).First();
+        // lookup algorithm performances in min
+        var perfs = kc.GetAlgorithmPerformance(min.Key);
+        if (perfs.Count == 0) {
+          k--;
+          continue;
+        }
+        foreach (var p in perfs) {
+          var ert = p.Value;
+          if (double.IsNaN(ert)) ert = int.MaxValue;
+          List<double> erts;
+          if (!performances.TryGetValue(p.Key, out erts)) {
+            performances[p.Key] = new List<double>() { ert }; ;
+          } else erts.Add(ert);
+        }
+        distances.Remove(min.Key);
+      }
+
+      return performances.Select(x => new { Alg = x.Key, Perf = x.Value.Average() })
+                         .OrderBy(x => x.Perf)
+                         .Select(x => Tuple.Create(x.Alg, x.Perf));
+    }
+  }
+}
Index: /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/Recommenders/KNearestNeighborRecommender.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/Recommenders/KNearestNeighborRecommender.cs	(revision 13787)
+++ /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/Recommenders/KNearestNeighborRecommender.cs	(revision 13787)
@@ -0,0 +1,53 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.OptimizationExpertSystem.Common {
+  [Item("K-Nearest Neighbor Recommender", "")]
+  [StorableClass]
+  public sealed class KNearestNeighborRecommender : ParameterizedNamedItem, IAlgorithmInstanceRecommender {
+    
+    private IFixedValueParameter<IntValue> KParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters["K"]; }
+    }
+
+    [StorableConstructor]
+    private KNearestNeighborRecommender(bool deserializing) : base(deserializing) { }
+    private KNearestNeighborRecommender(KNearestNeighborRecommender original, Cloner cloner)
+      : base(original, cloner) { }
+    public KNearestNeighborRecommender() {
+      Parameters.Add(new FixedValueParameter<IntValue>("K", "The number of nearest neighbors to consider.", new IntValue(5)));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new KNearestNeighborRecommender(this, cloner);
+    }
+
+    public IRecommendationModel TrainModel(KnowledgeCenter kc, string[] characteristics) {
+      return new KNearestNeighborModel(KParameter.Value.Value, characteristics);
+    }
+  }
+}
Index: /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/Recommenders/OverallBestRecommender.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/Recommenders/OverallBestRecommender.cs	(revision 13787)
+++ /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/Recommenders/OverallBestRecommender.cs	(revision 13787)
@@ -0,0 +1,84 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Analysis;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace HeuristicLab.OptimizationExpertSystem.Common {
+  [Item("Overall Best Recommender", "")]
+  [StorableClass]
+  public class OverallBestRecommender : ParameterizedNamedItem, IAlgorithmInstanceRecommender {
+
+    private IFixedValueParameter<DoubleValue> NeighborhoodFactorParameter {
+      get { return (IFixedValueParameter<DoubleValue>)Parameters["NeighborhoodFactor"]; }
+    }
+
+    public double NeighborhoodFactor {
+      get { return NeighborhoodFactorParameter.Value.Value; }
+      set { NeighborhoodFactorParameter.Value.Value = value; }
+    }
+    
+    [StorableConstructor]
+    private OverallBestRecommender(bool deserializing) : base(deserializing) { }
+    private OverallBestRecommender(OverallBestRecommender original, Cloner cloner)
+      : base(original, cloner) { }
+    public OverallBestRecommender() {
+      Parameters.Add(new FixedValueParameter<DoubleValue>("NeighborhoodFactor", "Penalize neighbors that are far away.", new DoubleValue(5)));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new OverallBestRecommender(this, cloner);
+    }
+
+    public IRecommendationModel TrainModel(KnowledgeCenter kc, string[] characteristics) {
+      var instances = new List<Tuple<IAlgorithm, double>>();
+      foreach (var relevantRuns in kc.GetKnowledgeBaseByAlgorithm()) {
+        var algorithm = relevantRuns.Key;
+        var pis = relevantRuns.Value.Select(x => ((StringValue)x.Parameters["Problem Name"]).Value).Distinct()
+                              .Select(x => Tuple.Create(x, kc.ProblemInstances.SingleOrDefault(y => ((StringValue)y.Parameters["Problem Name"]).Value == x)))
+                              .Where(x => x.Item2 != null)
+                              .Select(x => Tuple.Create(x.Item1, ((DoubleValue)x.Item2.Parameters["BestKnownQuality"]).Value))
+                              .ToDictionary(x => x.Item1, x => x.Item2);
+        var avgERT = 0.0;
+        var count = 0;
+        foreach (var problemRuns in relevantRuns.Value.GroupBy(x => ((StringValue)x.Parameters["Problem Name"]).Value)) {
+          var bkq = pis[problemRuns.Key];
+          var ert = ExpectedRuntimeHelper.CalculateErt(problemRuns.ToList(), "QualityPerEvaluations", (kc.Maximization ? (1 - kc.MinimumTarget.Value) : (1 + kc.MinimumTarget.Value)) * bkq, kc.Maximization).ExpectedRuntime;
+          if (double.IsNaN(ert)) ert = int.MaxValue;
+          avgERT += ert;
+          count++;
+        }
+        avgERT /= count;
+        instances.Add(Tuple.Create((IAlgorithm)algorithm.Clone(), avgERT));
+      }
+
+      return new FixedRankModel(instances.OrderBy(x => x.Item2));
+    }
+  }
+}
Index: /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/HeuristicLab.OptimizationExpertSystem-3.3.csproj
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/HeuristicLab.OptimizationExpertSystem-3.3.csproj	(revision 13786)
+++ /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/HeuristicLab.OptimizationExpertSystem-3.3.csproj	(revision 13787)
@@ -191,4 +191,5 @@
       <DependentUpon>AlgorithmControlForm.cs</DependentUpon>
     </Compile>
+    <Compile Include="Menu\200_Solving\210_PerformanceModelingMenuItem.cs" />
     <Compile Include="Toolbar\DownloadFromOKBToolbarItem.cs" />
     <Compile Include="Toolbar\ToolbarItemBase.cs" />
@@ -209,5 +210,5 @@
     <Compile Include="Menu\0_Config\30_DownloadFromOkbMenuItem.cs" />
     <Compile Include="Menu\0_Config\10_SetCredentialsMenuItem.cs" />
-    <Compile Include="Menu\200_Solving\210_SolverMenuItem.cs" />
+    <Compile Include="Menu\200_Solving\220_SolverMenuItem.cs" />
     <Compile Include="Menu\300_Learning\310_KnowledgeBaseMenuItem.cs" />
     <Compile Include="Menu\900_Tools\900_CSharpScriptMenuItem.cs" />
@@ -227,4 +228,10 @@
     </Compile>
     <Compile Include="Plugin.cs" />
+    <Compile Include="Views\PerformanceModelingView.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="Views\PerformanceModelingView.Designer.cs">
+      <DependentUpon>PerformanceModelingView.cs</DependentUpon>
+    </Compile>
     <Compile Include="Views\SolverView.cs">
       <SubType>UserControl</SubType>
@@ -297,4 +304,7 @@
     <EmbeddedResource Include="OptimizationKnowledgeCenter.resx">
       <DependentUpon>OptimizationKnowledgeCenter.cs</DependentUpon>
+    </EmbeddedResource>
+    <EmbeddedResource Include="Views\PerformanceModelingView.resx">
+      <DependentUpon>PerformanceModelingView.cs</DependentUpon>
     </EmbeddedResource>
     <EmbeddedResource Include="Views\SolverView.resx">
Index: /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Menu/200_Solving/210_PerformanceModelingMenuItem.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Menu/200_Solving/210_PerformanceModelingMenuItem.cs	(revision 13787)
+++ /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Menu/200_Solving/210_PerformanceModelingMenuItem.cs	(revision 13787)
@@ -0,0 +1,53 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common.Resources;
+using HeuristicLab.MainForm.WindowsForms;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+
+namespace HeuristicLab.OptimizationExpertSystem.Menu {
+  internal class PerformanceModelingMenuItem : MenuItemBase {
+    public override Image Image { get { return VSImageLibrary.Event; } }
+
+    public override string Name {
+      get { return "Performance Modeling"; }
+    }
+
+    public override IEnumerable<string> Structure {
+      get { return new[] { "Solving" }; }
+    }
+
+    public override int Position {
+      get { return 210; }
+    }
+
+    public override string ToolTipText { get { return "Modeling algorithm performance to suggest well-suited instances."; } }
+
+    public override void Execute() {
+      var viewType = typeof(PerformanceModelingView);
+      var view = MainForm.Views.FirstOrDefault(x => viewType == ((x is ViewHost) ? ((ViewHost)x).ActiveView : x).GetType());
+      if (view != null) view.Show();
+      else MainForm.ShowContent(MainForm.ExpertSystem, viewType);
+    }
+  }
+}
Index: anches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Menu/200_Solving/210_SolverMenuItem.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Menu/200_Solving/210_SolverMenuItem.cs	(revision 13786)
+++ 	(revision )
@@ -1,53 +1,0 @@
-﻿#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
- *
- * This file is part of HeuristicLab.
- *
- * HeuristicLab is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * HeuristicLab is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
- */
-#endregion
-
-using HeuristicLab.Common.Resources;
-using HeuristicLab.MainForm.WindowsForms;
-using System.Collections.Generic;
-using System.Drawing;
-using System.Linq;
-
-namespace HeuristicLab.OptimizationExpertSystem.Menu {
-  internal class SolverMenuItem : MenuItemBase {
-    public override Image Image { get { return VSImageLibrary.Event; } }
-
-    public override string Name {
-      get { return "Solver"; }
-    }
-
-    public override IEnumerable<string> Structure {
-      get { return new[] { "Solving" }; }
-    }
-
-    public override int Position {
-      get { return 210; }
-    }
-
-    public override string ToolTipText { get { return "Solve the problem instance."; } }
-
-    public override void Execute() {
-      var viewType = typeof(SolverView);
-      var view = MainForm.Views.FirstOrDefault(x => viewType == ((x is ViewHost) ? ((ViewHost)x).ActiveView : x).GetType());
-      if (view != null) view.Show();
-      else MainForm.ShowContent(MainForm.ExpertSystem, viewType);
-    }
-  }
-}
Index: /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Menu/200_Solving/220_SolverMenuItem.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Menu/200_Solving/220_SolverMenuItem.cs	(revision 13787)
+++ /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Menu/200_Solving/220_SolverMenuItem.cs	(revision 13787)
@@ -0,0 +1,53 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common.Resources;
+using HeuristicLab.MainForm.WindowsForms;
+using System.Collections.Generic;
+using System.Drawing;
+using System.Linq;
+
+namespace HeuristicLab.OptimizationExpertSystem.Menu {
+  internal class SolverMenuItem : MenuItemBase {
+    public override Image Image { get { return VSImageLibrary.Event; } }
+
+    public override string Name {
+      get { return "Solver"; }
+    }
+
+    public override IEnumerable<string> Structure {
+      get { return new[] { "Solving" }; }
+    }
+
+    public override int Position {
+      get { return 220; }
+    }
+
+    public override string ToolTipText { get { return "Solve the problem instance."; } }
+
+    public override void Execute() {
+      var viewType = typeof(SolverView);
+      var view = MainForm.Views.FirstOrDefault(x => viewType == ((x is ViewHost) ? ((ViewHost)x).ActiveView : x).GetType());
+      if (view != null) view.Show();
+      else MainForm.ShowContent(MainForm.ExpertSystem, viewType);
+    }
+  }
+}
Index: /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Views/KnowledgeCenterViewBase.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Views/KnowledgeCenterViewBase.cs	(revision 13786)
+++ /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Views/KnowledgeCenterViewBase.cs	(revision 13787)
@@ -48,7 +48,7 @@
       Content.DownloadStarted += ContentOnDownloadStarted;
       Content.AlgorithmInstanceStarted += ContentOnAlgorithmInstanceStarted;
+      Content.RecommendationModelChanged += ContentOnRecommendationModelChanged;
       RegisterContentProblemEvents();
       RegisterContentProblemInstancesEvents();
-      RegisterContentProblemCharacteristicsEvents();
       RegisterContentSolutionSeedingPoolEvents();
       RegisterContentSuggestedInstancesEvents();
@@ -71,12 +71,4 @@
     }
 
-    private void RegisterContentProblemCharacteristicsEvents() {
-      Content.ProblemCharacteristics.ItemsAdded += ContentOnProblemCharacteristicsChanged;
-      Content.ProblemCharacteristics.ItemsReplaced += ContentOnProblemCharacteristicsChanged;
-      Content.ProblemCharacteristics.ItemsRemoved += ContentOnProblemCharacteristicsChanged;
-      Content.ProblemCharacteristics.CheckedItemsChanged += ContentOnProblemCharacteristicsChanged;
-      Content.ProblemCharacteristics.CollectionReset += ContentOnProblemCharacteristicsChanged;
-    }
-
     private void RegisterContentSolutionSeedingPoolEvents() {
       Content.SolutionSeedingPool.CheckedItemsChanged += ContentOnSolutionSeedingPoolChanged;
@@ -88,9 +80,9 @@
 
     private void RegisterContentSuggestedInstancesEvents() {
-      Content.AlgorithmInstances.CollectionReset += ContentOnSuggestedInstancesChanged;
-      Content.AlgorithmInstances.ItemsAdded += ContentOnSuggestedInstancesChanged;
-      Content.AlgorithmInstances.ItemsMoved += ContentOnSuggestedInstancesChanged;
-      Content.AlgorithmInstances.ItemsRemoved += ContentOnSuggestedInstancesChanged;
-      Content.AlgorithmInstances.ItemsReplaced += ContentOnSuggestedInstancesChanged;
+      Content.AlgorithmInstances.CollectionReset += ContentOnAlgorithmInstancesChanged;
+      Content.AlgorithmInstances.ItemsAdded += ContentOnAlgorithmInstancesChanged;
+      Content.AlgorithmInstances.ItemsMoved += ContentOnAlgorithmInstancesChanged;
+      Content.AlgorithmInstances.ItemsRemoved += ContentOnAlgorithmInstancesChanged;
+      Content.AlgorithmInstances.ItemsReplaced += ContentOnAlgorithmInstancesChanged;
     }
 
@@ -99,7 +91,7 @@
       Content.DownloadStarted -= ContentOnDownloadStarted;
       Content.AlgorithmInstanceStarted -= ContentOnAlgorithmInstanceStarted;
+      Content.RecommendationModelChanged -= ContentOnRecommendationModelChanged;
       DeregisterContentProblemEvents();
       DeregisterContentProblemInstancesEvents();
-      DeregisterContentProblemCharacteristicsEvents();
       DeregisterContentSolutionSeedingPoolEvents();
       DeregisterContentSuggestedInstancesEvents();
@@ -122,12 +114,4 @@
     }
 
-    private void DeregisterContentProblemCharacteristicsEvents() {
-      Content.ProblemCharacteristics.ItemsAdded -= ContentOnProblemCharacteristicsChanged;
-      Content.ProblemCharacteristics.ItemsReplaced -= ContentOnProblemCharacteristicsChanged;
-      Content.ProblemCharacteristics.ItemsRemoved -= ContentOnProblemCharacteristicsChanged;
-      Content.ProblemCharacteristics.CheckedItemsChanged -= ContentOnProblemCharacteristicsChanged;
-      Content.ProblemCharacteristics.CollectionReset -= ContentOnProblemCharacteristicsChanged;
-    }
-
     private void DeregisterContentSolutionSeedingPoolEvents() {
       Content.SolutionSeedingPool.CheckedItemsChanged -= ContentOnSolutionSeedingPoolChanged;
@@ -139,9 +123,9 @@
 
     private void DeregisterContentSuggestedInstancesEvents() {
-      Content.AlgorithmInstances.CollectionReset -= ContentOnSuggestedInstancesChanged;
-      Content.AlgorithmInstances.ItemsAdded -= ContentOnSuggestedInstancesChanged;
-      Content.AlgorithmInstances.ItemsMoved -= ContentOnSuggestedInstancesChanged;
-      Content.AlgorithmInstances.ItemsRemoved -= ContentOnSuggestedInstancesChanged;
-      Content.AlgorithmInstances.ItemsReplaced -= ContentOnSuggestedInstancesChanged;
+      Content.AlgorithmInstances.CollectionReset -= ContentOnAlgorithmInstancesChanged;
+      Content.AlgorithmInstances.ItemsAdded -= ContentOnAlgorithmInstancesChanged;
+      Content.AlgorithmInstances.ItemsMoved -= ContentOnAlgorithmInstancesChanged;
+      Content.AlgorithmInstances.ItemsRemoved -= ContentOnAlgorithmInstancesChanged;
+      Content.AlgorithmInstances.ItemsReplaced -= ContentOnAlgorithmInstancesChanged;
     }
     #endregion
@@ -150,11 +134,11 @@
     protected virtual void OnDownloadEnded() { }
     protected virtual void OnAlgorithmInstanceStarted(IAlgorithm algorithm) { }
+    protected virtual void OnRecommendationModelChanged() { }
     protected virtual void OnPropertyChanged(string propertyName) { }
     protected virtual void OnProblemChanged() { }
     protected virtual void OnProblemSolutionsChanged() { }
     protected virtual void OnProblemInstancesChanged() { }
-    protected virtual void OnProblemCharacteristicsChanged() { }
     protected virtual void OnSolutionSeedingPoolChanged() { }
-    protected virtual void OnSuggestedInstancesChanged() { }
+    protected virtual void OnAlgorithmInstancesChanged() { }
     protected virtual void OnKnowledgeBaseChanged() { }
 
@@ -170,4 +154,9 @@
       if (InvokeRequired) { Invoke((Action<object, EventArgs<IAlgorithm>>)ContentOnAlgorithmInstanceStarted, sender, e); return; }
       OnAlgorithmInstanceStarted(e.Value);
+    }
+
+    private void ContentOnRecommendationModelChanged(object sender, EventArgs e) {
+      if (InvokeRequired) { Invoke((Action<object, EventArgs<IAlgorithm>>)ContentOnRecommendationModelChanged, sender, e); return; }
+      OnRecommendationModelChanged();
     }
 
@@ -194,9 +183,4 @@
     }
 
-    private void ContentOnProblemCharacteristicsChanged(object sender, EventArgs e) {
-      if (InvokeRequired) Invoke((Action)OnProblemCharacteristicsChanged);
-      else OnProblemCharacteristicsChanged();
-    }
-
     private void ContentOnSolutionSeedingPoolChanged(object sender, EventArgs e) {
       if (InvokeRequired) Invoke((Action)OnSolutionSeedingPoolChanged);
@@ -204,7 +188,7 @@
     }
 
-    private void ContentOnSuggestedInstancesChanged(object sender, EventArgs e) {
-      if (InvokeRequired) Invoke((Action)OnSuggestedInstancesChanged);
-      else OnSuggestedInstancesChanged();
+    private void ContentOnAlgorithmInstancesChanged(object sender, EventArgs e) {
+      if (InvokeRequired) Invoke((Action)OnAlgorithmInstancesChanged);
+      else OnAlgorithmInstancesChanged();
     }
     #endregion
Index: /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Views/PerformanceModelingView.Designer.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Views/PerformanceModelingView.Designer.cs	(revision 13787)
+++ /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Views/PerformanceModelingView.Designer.cs	(revision 13787)
@@ -0,0 +1,210 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+namespace HeuristicLab.OptimizationExpertSystem {
+  partial class PerformanceModelingView {
+    /// <summary> 
+    /// Required designer variable.
+    /// </summary>
+    private System.ComponentModel.IContainer components = null;
+
+    /// <summary> 
+    /// Clean up any resources being used.
+    /// </summary>
+    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+    protected override void Dispose(bool disposing) {
+      if (disposing && (components != null)) {
+        components.Dispose();
+      }
+      base.Dispose(disposing);
+    }
+
+    #region Component Designer generated code
+
+    /// <summary> 
+    /// Required method for Designer support - do not modify 
+    /// the contents of this method with the code editor.
+    /// </summary>
+    private void InitializeComponent() {
+      this.recommenderLabel = new System.Windows.Forms.Label();
+      this.recommenderComboBox = new System.Windows.Forms.ComboBox();
+      this.recommendStartButton = new System.Windows.Forms.Button();
+      this.tabControl = new System.Windows.Forms.TabControl();
+      this.characteristicsTabPage = new System.Windows.Forms.TabPage();
+      this.refreshCharacteristicsButton = new System.Windows.Forms.Button();
+      this.parametersTabPage = new System.Windows.Forms.TabPage();
+      this.parameterCollectionView = new HeuristicLab.Core.Views.ParameterCollectionView();
+      this.resultsTabPage = new System.Windows.Forms.TabPage();
+      this.characteristicsViewHost = new HeuristicLab.MainForm.WindowsForms.ViewHost();
+      this.tabControl.SuspendLayout();
+      this.characteristicsTabPage.SuspendLayout();
+      this.parametersTabPage.SuspendLayout();
+      this.SuspendLayout();
+      // 
+      // recommenderLabel
+      // 
+      this.recommenderLabel.AutoSize = true;
+      this.recommenderLabel.Location = new System.Drawing.Point(5, 6);
+      this.recommenderLabel.Name = "recommenderLabel";
+      this.recommenderLabel.Size = new System.Drawing.Size(79, 13);
+      this.recommenderLabel.TabIndex = 12;
+      this.recommenderLabel.Text = "Recommender:";
+      // 
+      // recommenderComboBox
+      // 
+      this.recommenderComboBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.recommenderComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+      this.recommenderComboBox.FormattingEnabled = true;
+      this.recommenderComboBox.Location = new System.Drawing.Point(90, 3);
+      this.recommenderComboBox.Name = "recommenderComboBox";
+      this.recommenderComboBox.Size = new System.Drawing.Size(264, 21);
+      this.recommenderComboBox.TabIndex = 11;
+      this.recommenderComboBox.SelectedIndexChanged += new System.EventHandler(this.RecommenderComboBoxOnSelectedIndexChanged);
+      // 
+      // recommendStartButton
+      // 
+      this.recommendStartButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
+      this.recommendStartButton.Location = new System.Drawing.Point(360, 3);
+      this.recommendStartButton.Name = "recommendStartButton";
+      this.recommendStartButton.Size = new System.Drawing.Size(26, 23);
+      this.recommendStartButton.TabIndex = 13;
+      this.recommendStartButton.Text = "Start";
+      this.recommendStartButton.UseVisualStyleBackColor = true;
+      this.recommendStartButton.Click += new System.EventHandler(this.RecommendStartButtonOnClick);
+      // 
+      // tabControl
+      // 
+      this.tabControl.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
+            | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.tabControl.Controls.Add(this.characteristicsTabPage);
+      this.tabControl.Controls.Add(this.parametersTabPage);
+      this.tabControl.Controls.Add(this.resultsTabPage);
+      this.tabControl.Location = new System.Drawing.Point(0, 30);
+      this.tabControl.Name = "tabControl";
+      this.tabControl.SelectedIndex = 0;
+      this.tabControl.Size = new System.Drawing.Size(700, 350);
+      this.tabControl.TabIndex = 14;
+      // 
+      // characteristicsTabPage
+      // 
+      this.characteristicsTabPage.Controls.Add(this.characteristicsViewHost);
+      this.characteristicsTabPage.Controls.Add(this.refreshCharacteristicsButton);
+      this.characteristicsTabPage.Location = new System.Drawing.Point(4, 22);
+      this.characteristicsTabPage.Name = "characteristicsTabPage";
+      this.characteristicsTabPage.Padding = new System.Windows.Forms.Padding(3);
+      this.characteristicsTabPage.Size = new System.Drawing.Size(692, 324);
+      this.characteristicsTabPage.TabIndex = 2;
+      this.characteristicsTabPage.Text = "Characteristics";
+      this.characteristicsTabPage.UseVisualStyleBackColor = true;
+      // 
+      // refreshCharacteristicsButton
+      // 
+      this.refreshCharacteristicsButton.Location = new System.Drawing.Point(6, 6);
+      this.refreshCharacteristicsButton.Name = "refreshCharacteristicsButton";
+      this.refreshCharacteristicsButton.Size = new System.Drawing.Size(26, 23);
+      this.refreshCharacteristicsButton.TabIndex = 0;
+      this.refreshCharacteristicsButton.Text = "Refresh";
+      this.refreshCharacteristicsButton.UseVisualStyleBackColor = true;
+      this.refreshCharacteristicsButton.Click += new System.EventHandler(this.RefreshCharacteristicsButtonOnClick);
+      // 
+      // parametersTabPage
+      // 
+      this.parametersTabPage.Controls.Add(this.parameterCollectionView);
+      this.parametersTabPage.Location = new System.Drawing.Point(4, 22);
+      this.parametersTabPage.Name = "parametersTabPage";
+      this.parametersTabPage.Padding = new System.Windows.Forms.Padding(3);
+      this.parametersTabPage.Size = new System.Drawing.Size(692, 324);
+      this.parametersTabPage.TabIndex = 0;
+      this.parametersTabPage.Text = "Parameters";
+      this.parametersTabPage.UseVisualStyleBackColor = true;
+      // 
+      // parameterCollectionView
+      // 
+      this.parameterCollectionView.AllowEditingOfHiddenParameters = true;
+      this.parameterCollectionView.Caption = "ParameterCollection View";
+      this.parameterCollectionView.Content = null;
+      this.parameterCollectionView.Dock = System.Windows.Forms.DockStyle.Fill;
+      this.parameterCollectionView.Location = new System.Drawing.Point(3, 3);
+      this.parameterCollectionView.Name = "parameterCollectionView";
+      this.parameterCollectionView.ReadOnly = false;
+      this.parameterCollectionView.ShowDetails = true;
+      this.parameterCollectionView.Size = new System.Drawing.Size(686, 318);
+      this.parameterCollectionView.TabIndex = 0;
+      // 
+      // resultsTabPage
+      // 
+      this.resultsTabPage.Location = new System.Drawing.Point(4, 22);
+      this.resultsTabPage.Name = "resultsTabPage";
+      this.resultsTabPage.Padding = new System.Windows.Forms.Padding(3);
+      this.resultsTabPage.Size = new System.Drawing.Size(692, 324);
+      this.resultsTabPage.TabIndex = 1;
+      this.resultsTabPage.Text = "Results";
+      this.resultsTabPage.UseVisualStyleBackColor = true;
+      // 
+      // characteristicsViewHost
+      // 
+      this.characteristicsViewHost.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
+            | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.characteristicsViewHost.Caption = "View";
+      this.characteristicsViewHost.Content = null;
+      this.characteristicsViewHost.Enabled = false;
+      this.characteristicsViewHost.Location = new System.Drawing.Point(6, 35);
+      this.characteristicsViewHost.Name = "characteristicsViewHost";
+      this.characteristicsViewHost.ReadOnly = false;
+      this.characteristicsViewHost.Size = new System.Drawing.Size(680, 283);
+      this.characteristicsViewHost.TabIndex = 1;
+      this.characteristicsViewHost.ViewsLabelVisible = true;
+      this.characteristicsViewHost.ViewType = null;
+      // 
+      // PerformanceModelingView
+      // 
+      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+      this.Controls.Add(this.tabControl);
+      this.Controls.Add(this.recommenderLabel);
+      this.Controls.Add(this.recommenderComboBox);
+      this.Controls.Add(this.recommendStartButton);
+      this.Name = "PerformanceModelingView";
+      this.tabControl.ResumeLayout(false);
+      this.characteristicsTabPage.ResumeLayout(false);
+      this.parametersTabPage.ResumeLayout(false);
+      this.ResumeLayout(false);
+      this.PerformLayout();
+
+    }
+
+    #endregion
+
+    private System.Windows.Forms.Label recommenderLabel;
+    private System.Windows.Forms.ComboBox recommenderComboBox;
+    private System.Windows.Forms.Button recommendStartButton;
+    private System.Windows.Forms.TabControl tabControl;
+    private System.Windows.Forms.TabPage parametersTabPage;
+    private System.Windows.Forms.TabPage resultsTabPage;
+    private Core.Views.ParameterCollectionView parameterCollectionView;
+    private System.Windows.Forms.TabPage characteristicsTabPage;
+    private System.Windows.Forms.Button refreshCharacteristicsButton;
+    private MainForm.WindowsForms.ViewHost characteristicsViewHost;
+  }
+}
Index: /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Views/PerformanceModelingView.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Views/PerformanceModelingView.cs	(revision 13787)
+++ /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Views/PerformanceModelingView.cs	(revision 13787)
@@ -0,0 +1,126 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2016 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using HeuristicLab.Common.Resources;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.MainForm;
+using HeuristicLab.OptimizationExpertSystem.Common;
+using HeuristicLab.PluginInfrastructure;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace HeuristicLab.OptimizationExpertSystem {
+  [View("Performance Modeling View")]
+  [Content(typeof(KnowledgeCenter), IsDefaultView = false)]
+  public partial class PerformanceModelingView : KnowledgeCenterViewBase {
+    private readonly CheckedItemList<StringValue> characteristics;
+
+    public PerformanceModelingView() {
+      InitializeComponent();
+      characteristics = new CheckedItemList<StringValue>();
+      characteristics.CheckedItemsChanged += CharacteristicsOnCheckedItemsChanged;
+      characteristicsViewHost.Content = characteristics;
+      recommendStartButton.Text = string.Empty;
+      recommendStartButton.Image = VSImageLibrary.Play;
+      refreshCharacteristicsButton.Text = string.Empty;
+      refreshCharacteristicsButton.Image = VSImageLibrary.Refresh;
+      UpdateRecommenderCombobox();
+    }
+
+    protected override void OnContentChanged() {
+      base.OnContentChanged();
+      UpdateCharacteristics();
+    }
+
+    protected override void SetEnabledStateOfControls() {
+      base.SetEnabledStateOfControls();
+      // TODO: up/download state
+      recommendStartButton.Enabled = Content != null && recommenderComboBox.SelectedIndex >= 0 && characteristics.CheckedItems.Any();
+      characteristicsViewHost.Enabled = Content != null;
+    }
+
+    #region Update Controls
+    private void UpdateRecommenderCombobox() {
+      if (InvokeRequired) { Invoke((Action)UpdateRecommenderCombobox); return; }
+      var prevSelection = (IAlgorithmInstanceRecommender)recommenderComboBox.SelectedItem;
+      var prevNewIndex = -1;
+      recommenderComboBox.Items.Clear();
+
+      var i = 0;
+      foreach (var rcmd in ApplicationManager.Manager.GetInstances<IAlgorithmInstanceRecommender>()) {
+        recommenderComboBox.Items.Add(rcmd);
+        if (prevSelection == null || rcmd.GetType() == prevSelection.GetType())
+          prevNewIndex = prevSelection == null ? 0 : i;
+        i++;
+      }
+      
+      recommenderComboBox.SelectedIndex = prevNewIndex;
+    }
+
+    private void UpdateCharacteristics() {
+      if (InvokeRequired) { Invoke((Action)UpdateCharacteristics); return; }
+
+      var @checked = new HashSet<string>(characteristics.CheckedItems.Select(x => x.Value.Value));
+      characteristics.Clear();
+      if (Content == null || Content.ProblemInstances.Count == 0) return;
+
+      foreach (var c in Content.ProblemInstances.ResultNames) {
+        characteristics.Add(new StringValue(c), @checked.Contains(c));
+      }
+    }
+    #endregion
+
+    #region Content Event Handlers
+    protected override void OnProblemInstancesChanged() {
+      base.OnProblemInstancesChanged();
+      UpdateCharacteristics();
+      SetEnabledStateOfControls();
+    }
+    #endregion
+
+    #region Control Event Handlers
+    private void RecommenderComboBoxOnSelectedIndexChanged(object sender, EventArgs e) {
+      if (InvokeRequired) { Invoke((Action<object, EventArgs>)RecommenderComboBoxOnSelectedIndexChanged, sender, e); return; }
+      var rcmd = (IAlgorithmInstanceRecommender)recommenderComboBox.SelectedItem;
+      parameterCollectionView.Content = rcmd != null ? rcmd.Parameters : null;
+      SetEnabledStateOfControls();
+    }
+
+    private void RecommendStartButtonOnClick(object sender, EventArgs e) {
+      var rcmd = (IAlgorithmInstanceRecommender)recommenderComboBox.SelectedItem;
+      Content.RecommendationModel = rcmd.TrainModel(Content, characteristics.CheckedItems.Select(x => x.Value.Value).ToArray());
+    }
+
+    private void RefreshCharacteristicsButtonOnClick(object sender, EventArgs e) {
+      UpdateCharacteristics();
+      SetEnabledStateOfControls();
+    }
+    #endregion
+
+    #region Other Event Handlers
+    private void CharacteristicsOnCheckedItemsChanged(object sender, EventArgs e) {
+      SetEnabledStateOfControls();
+    }
+    #endregion
+  }
+}
Index: /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Views/PerformanceModelingView.resx
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Views/PerformanceModelingView.resx	(revision 13787)
+++ /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Views/PerformanceModelingView.resx	(revision 13787)
@@ -0,0 +1,120 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>
Index: /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Views/SolverView.Designer.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Views/SolverView.Designer.cs	(revision 13786)
+++ /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Views/SolverView.Designer.cs	(revision 13787)
@@ -45,23 +45,29 @@
     /// </summary>
     private void InitializeComponent() {
-      WeifenLuo.WinFormsUI.Docking.DockPanelSkin dockPanelSkin2 = new WeifenLuo.WinFormsUI.Docking.DockPanelSkin();
-      WeifenLuo.WinFormsUI.Docking.AutoHideStripSkin autoHideStripSkin2 = new WeifenLuo.WinFormsUI.Docking.AutoHideStripSkin();
-      WeifenLuo.WinFormsUI.Docking.DockPanelGradient dockPanelGradient4 = new WeifenLuo.WinFormsUI.Docking.DockPanelGradient();
-      WeifenLuo.WinFormsUI.Docking.TabGradient tabGradient8 = new WeifenLuo.WinFormsUI.Docking.TabGradient();
-      WeifenLuo.WinFormsUI.Docking.DockPaneStripSkin dockPaneStripSkin2 = new WeifenLuo.WinFormsUI.Docking.DockPaneStripSkin();
-      WeifenLuo.WinFormsUI.Docking.DockPaneStripGradient dockPaneStripGradient2 = new WeifenLuo.WinFormsUI.Docking.DockPaneStripGradient();
-      WeifenLuo.WinFormsUI.Docking.TabGradient tabGradient9 = new WeifenLuo.WinFormsUI.Docking.TabGradient();
-      WeifenLuo.WinFormsUI.Docking.DockPanelGradient dockPanelGradient5 = new WeifenLuo.WinFormsUI.Docking.DockPanelGradient();
-      WeifenLuo.WinFormsUI.Docking.TabGradient tabGradient10 = new WeifenLuo.WinFormsUI.Docking.TabGradient();
-      WeifenLuo.WinFormsUI.Docking.DockPaneStripToolWindowGradient dockPaneStripToolWindowGradient2 = new WeifenLuo.WinFormsUI.Docking.DockPaneStripToolWindowGradient();
-      WeifenLuo.WinFormsUI.Docking.TabGradient tabGradient11 = new WeifenLuo.WinFormsUI.Docking.TabGradient();
-      WeifenLuo.WinFormsUI.Docking.TabGradient tabGradient12 = new WeifenLuo.WinFormsUI.Docking.TabGradient();
-      WeifenLuo.WinFormsUI.Docking.DockPanelGradient dockPanelGradient6 = new WeifenLuo.WinFormsUI.Docking.DockPanelGradient();
-      WeifenLuo.WinFormsUI.Docking.TabGradient tabGradient13 = new WeifenLuo.WinFormsUI.Docking.TabGradient();
-      WeifenLuo.WinFormsUI.Docking.TabGradient tabGradient14 = new WeifenLuo.WinFormsUI.Docking.TabGradient();
+      WeifenLuo.WinFormsUI.Docking.DockPanelSkin dockPanelSkin4 = new WeifenLuo.WinFormsUI.Docking.DockPanelSkin();
+      WeifenLuo.WinFormsUI.Docking.AutoHideStripSkin autoHideStripSkin4 = new WeifenLuo.WinFormsUI.Docking.AutoHideStripSkin();
+      WeifenLuo.WinFormsUI.Docking.DockPanelGradient dockPanelGradient10 = new WeifenLuo.WinFormsUI.Docking.DockPanelGradient();
+      WeifenLuo.WinFormsUI.Docking.TabGradient tabGradient22 = new WeifenLuo.WinFormsUI.Docking.TabGradient();
+      WeifenLuo.WinFormsUI.Docking.DockPaneStripSkin dockPaneStripSkin4 = new WeifenLuo.WinFormsUI.Docking.DockPaneStripSkin();
+      WeifenLuo.WinFormsUI.Docking.DockPaneStripGradient dockPaneStripGradient4 = new WeifenLuo.WinFormsUI.Docking.DockPaneStripGradient();
+      WeifenLuo.WinFormsUI.Docking.TabGradient tabGradient23 = new WeifenLuo.WinFormsUI.Docking.TabGradient();
+      WeifenLuo.WinFormsUI.Docking.DockPanelGradient dockPanelGradient11 = new WeifenLuo.WinFormsUI.Docking.DockPanelGradient();
+      WeifenLuo.WinFormsUI.Docking.TabGradient tabGradient24 = new WeifenLuo.WinFormsUI.Docking.TabGradient();
+      WeifenLuo.WinFormsUI.Docking.DockPaneStripToolWindowGradient dockPaneStripToolWindowGradient4 = new WeifenLuo.WinFormsUI.Docking.DockPaneStripToolWindowGradient();
+      WeifenLuo.WinFormsUI.Docking.TabGradient tabGradient25 = new WeifenLuo.WinFormsUI.Docking.TabGradient();
+      WeifenLuo.WinFormsUI.Docking.TabGradient tabGradient26 = new WeifenLuo.WinFormsUI.Docking.TabGradient();
+      WeifenLuo.WinFormsUI.Docking.DockPanelGradient dockPanelGradient12 = new WeifenLuo.WinFormsUI.Docking.DockPanelGradient();
+      WeifenLuo.WinFormsUI.Docking.TabGradient tabGradient27 = new WeifenLuo.WinFormsUI.Docking.TabGradient();
+      WeifenLuo.WinFormsUI.Docking.TabGradient tabGradient28 = new WeifenLuo.WinFormsUI.Docking.TabGradient();
       this.minTargetView = new HeuristicLab.Data.Views.StringConvertibleValueView();
       this.maxEvaluationsView = new HeuristicLab.Data.Views.StringConvertibleValueView();
       this.algorithmCloneButton = new System.Windows.Forms.Button();
       this.seedingStrategyPanel = new System.Windows.Forms.Panel();
+      this.algorithmStartButton = new System.Windows.Forms.Button();
+      this.minimumTargetLabel = new System.Windows.Forms.Label();
+      this.seedingStrategyLabel = new System.Windows.Forms.Label();
+      this.evaluationsLimitabel = new System.Windows.Forms.Label();
+      this.suggestedInstancesComboBox = new System.Windows.Forms.ComboBox();
+      this.instanceLabel = new System.Windows.Forms.Label();
       this.solverTabControl = new HeuristicLab.MainForm.WindowsForms.DragOverTabControl();
       this.resultsTabPage = new System.Windows.Forms.TabPage();
@@ -77,15 +83,4 @@
       this.operatorGraphTabPage = new System.Windows.Forms.TabPage();
       this.operatorGraphViewHost = new HeuristicLab.MainForm.WindowsForms.ViewHost();
-      this.algorithmStartButton = new System.Windows.Forms.Button();
-      this.minimumTargetLabel = new System.Windows.Forms.Label();
-      this.seedingStrategyLabel = new System.Windows.Forms.Label();
-      this.evaluationsLimitabel = new System.Windows.Forms.Label();
-      this.recommenderLabel = new System.Windows.Forms.Label();
-      this.suggestedInstancesComboBox = new System.Windows.Forms.ComboBox();
-      this.recommenderComboBox = new System.Windows.Forms.ComboBox();
-      this.solverSplitContainer = new System.Windows.Forms.SplitContainer();
-      this.recommenderViewHost = new HeuristicLab.MainForm.WindowsForms.ViewHost();
-      this.instanceLabel = new System.Windows.Forms.Label();
-      this.recommendRefreshButton = new System.Windows.Forms.Button();
       this.solverTabControl.SuspendLayout();
       this.resultsTabPage.SuspendLayout();
@@ -94,8 +89,4 @@
       this.parametersTabPage.SuspendLayout();
       this.operatorGraphTabPage.SuspendLayout();
-      ((System.ComponentModel.ISupportInitialize)(this.solverSplitContainer)).BeginInit();
-      this.solverSplitContainer.Panel1.SuspendLayout();
-      this.solverSplitContainer.Panel2.SuspendLayout();
-      this.solverSplitContainer.SuspendLayout();
       this.SuspendLayout();
       // 
@@ -124,9 +115,9 @@
       // algorithmCloneButton
       // 
-      this.algorithmCloneButton.Location = new System.Drawing.Point(123, 60);
+      this.algorithmCloneButton.Location = new System.Drawing.Point(518, 56);
       this.algorithmCloneButton.Name = "algorithmCloneButton";
       this.algorithmCloneButton.Size = new System.Drawing.Size(26, 23);
       this.algorithmCloneButton.TabIndex = 15;
-      this.algorithmCloneButton.Text = "Clone";
+      this.algorithmCloneButton.Text = "c";
       this.algorithmCloneButton.UseVisualStyleBackColor = true;
       this.algorithmCloneButton.Click += new System.EventHandler(this.AlgorithmCloneButtonOnClick);
@@ -141,7 +132,65 @@
       this.seedingStrategyPanel.TabIndex = 12;
       // 
+      // algorithmStartButton
+      // 
+      this.algorithmStartButton.Location = new System.Drawing.Point(486, 56);
+      this.algorithmStartButton.Name = "algorithmStartButton";
+      this.algorithmStartButton.Size = new System.Drawing.Size(26, 23);
+      this.algorithmStartButton.TabIndex = 10;
+      this.algorithmStartButton.Text = "Start";
+      this.algorithmStartButton.UseVisualStyleBackColor = true;
+      this.algorithmStartButton.Click += new System.EventHandler(this.AlgorithmStartButtonOnClick);
+      // 
+      // minimumTargetLabel
+      // 
+      this.minimumTargetLabel.AutoSize = true;
+      this.minimumTargetLabel.Location = new System.Drawing.Point(384, 6);
+      this.minimumTargetLabel.Name = "minimumTargetLabel";
+      this.minimumTargetLabel.Size = new System.Drawing.Size(41, 13);
+      this.minimumTargetLabel.TabIndex = 13;
+      this.minimumTargetLabel.Text = "Target:";
+      // 
+      // seedingStrategyLabel
+      // 
+      this.seedingStrategyLabel.AutoSize = true;
+      this.seedingStrategyLabel.Location = new System.Drawing.Point(3, 33);
+      this.seedingStrategyLabel.Name = "seedingStrategyLabel";
+      this.seedingStrategyLabel.Size = new System.Drawing.Size(91, 13);
+      this.seedingStrategyLabel.TabIndex = 8;
+      this.seedingStrategyLabel.Text = "Seeding Strategy:";
+      // 
+      // evaluationsLimitabel
+      // 
+      this.evaluationsLimitabel.AutoSize = true;
+      this.evaluationsLimitabel.Location = new System.Drawing.Point(3, 6);
+      this.evaluationsLimitabel.Name = "evaluationsLimitabel";
+      this.evaluationsLimitabel.Size = new System.Drawing.Size(66, 13);
+      this.evaluationsLimitabel.TabIndex = 13;
+      this.evaluationsLimitabel.Text = "Budget (FE):";
+      // 
+      // suggestedInstancesComboBox
+      // 
+      this.suggestedInstancesComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+      this.suggestedInstancesComboBox.FormattingEnabled = true;
+      this.suggestedInstancesComboBox.Location = new System.Drawing.Point(108, 56);
+      this.suggestedInstancesComboBox.Name = "suggestedInstancesComboBox";
+      this.suggestedInstancesComboBox.Size = new System.Drawing.Size(372, 21);
+      this.suggestedInstancesComboBox.TabIndex = 7;
+      this.suggestedInstancesComboBox.SelectedIndexChanged += new System.EventHandler(this.SuggestedInstancesComboBoxOnSelectedIndexChanged);
+      // 
+      // instanceLabel
+      // 
+      this.instanceLabel.AutoSize = true;
+      this.instanceLabel.Location = new System.Drawing.Point(3, 59);
+      this.instanceLabel.Name = "instanceLabel";
+      this.instanceLabel.Size = new System.Drawing.Size(51, 13);
+      this.instanceLabel.TabIndex = 9;
+      this.instanceLabel.Text = "Instance:";
+      // 
       // solverTabControl
       // 
-      this.solverTabControl.AllowDrop = true;
+      this.solverTabControl.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
+            | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
       this.solverTabControl.Controls.Add(this.resultsTabPage);
       this.solverTabControl.Controls.Add(this.runsTabPage);
@@ -150,10 +199,9 @@
       this.solverTabControl.Controls.Add(this.parametersTabPage);
       this.solverTabControl.Controls.Add(this.operatorGraphTabPage);
-      this.solverTabControl.Dock = System.Windows.Forms.DockStyle.Fill;
-      this.solverTabControl.Location = new System.Drawing.Point(3, 3);
+      this.solverTabControl.Location = new System.Drawing.Point(6, 85);
       this.solverTabControl.Name = "solverTabControl";
       this.solverTabControl.SelectedIndex = 0;
-      this.solverTabControl.Size = new System.Drawing.Size(556, 502);
-      this.solverTabControl.TabIndex = 11;
+      this.solverTabControl.Size = new System.Drawing.Size(843, 479);
+      this.solverTabControl.TabIndex = 17;
       // 
       // resultsTabPage
@@ -164,5 +212,5 @@
       this.resultsTabPage.Name = "resultsTabPage";
       this.resultsTabPage.Padding = new System.Windows.Forms.Padding(3);
-      this.resultsTabPage.Size = new System.Drawing.Size(548, 476);
+      this.resultsTabPage.Size = new System.Drawing.Size(835, 453);
       this.resultsTabPage.TabIndex = 2;
       this.resultsTabPage.Text = "Results";
@@ -189,51 +237,51 @@
       this.resultsDockPanel.Location = new System.Drawing.Point(3, 29);
       this.resultsDockPanel.Name = "resultsDockPanel";
-      this.resultsDockPanel.Size = new System.Drawing.Size(542, 444);
-      dockPanelGradient4.EndColor = System.Drawing.SystemColors.ControlLight;
-      dockPanelGradient4.StartColor = System.Drawing.SystemColors.ControlLight;
-      autoHideStripSkin2.DockStripGradient = dockPanelGradient4;
-      tabGradient8.EndColor = System.Drawing.SystemColors.Control;
-      tabGradient8.StartColor = System.Drawing.SystemColors.Control;
-      tabGradient8.TextColor = System.Drawing.SystemColors.ControlDarkDark;
-      autoHideStripSkin2.TabGradient = tabGradient8;
-      autoHideStripSkin2.TextFont = new System.Drawing.Font("Segoe UI", 9F);
-      dockPanelSkin2.AutoHideStripSkin = autoHideStripSkin2;
-      tabGradient9.EndColor = System.Drawing.SystemColors.ControlLightLight;
-      tabGradient9.StartColor = System.Drawing.SystemColors.ControlLightLight;
-      tabGradient9.TextColor = System.Drawing.SystemColors.ControlText;
-      dockPaneStripGradient2.ActiveTabGradient = tabGradient9;
-      dockPanelGradient5.EndColor = System.Drawing.SystemColors.Control;
-      dockPanelGradient5.StartColor = System.Drawing.SystemColors.Control;
-      dockPaneStripGradient2.DockStripGradient = dockPanelGradient5;
-      tabGradient10.EndColor = System.Drawing.SystemColors.ControlLight;
-      tabGradient10.StartColor = System.Drawing.SystemColors.ControlLight;
-      tabGradient10.TextColor = System.Drawing.SystemColors.ControlText;
-      dockPaneStripGradient2.InactiveTabGradient = tabGradient10;
-      dockPaneStripSkin2.DocumentGradient = dockPaneStripGradient2;
-      dockPaneStripSkin2.TextFont = new System.Drawing.Font("Segoe UI", 9F);
-      tabGradient11.EndColor = System.Drawing.SystemColors.ActiveCaption;
-      tabGradient11.LinearGradientMode = System.Drawing.Drawing2D.LinearGradientMode.Vertical;
-      tabGradient11.StartColor = System.Drawing.SystemColors.GradientActiveCaption;
-      tabGradient11.TextColor = System.Drawing.SystemColors.ActiveCaptionText;
-      dockPaneStripToolWindowGradient2.ActiveCaptionGradient = tabGradient11;
-      tabGradient12.EndColor = System.Drawing.SystemColors.Control;
-      tabGradient12.StartColor = System.Drawing.SystemColors.Control;
-      tabGradient12.TextColor = System.Drawing.SystemColors.ControlText;
-      dockPaneStripToolWindowGradient2.ActiveTabGradient = tabGradient12;
-      dockPanelGradient6.EndColor = System.Drawing.SystemColors.ControlLight;
-      dockPanelGradient6.StartColor = System.Drawing.SystemColors.ControlLight;
-      dockPaneStripToolWindowGradient2.DockStripGradient = dockPanelGradient6;
-      tabGradient13.EndColor = System.Drawing.SystemColors.InactiveCaption;
-      tabGradient13.LinearGradientMode = System.Drawing.Drawing2D.LinearGradientMode.Vertical;
-      tabGradient13.StartColor = System.Drawing.SystemColors.GradientInactiveCaption;
-      tabGradient13.TextColor = System.Drawing.SystemColors.InactiveCaptionText;
-      dockPaneStripToolWindowGradient2.InactiveCaptionGradient = tabGradient13;
-      tabGradient14.EndColor = System.Drawing.Color.Transparent;
-      tabGradient14.StartColor = System.Drawing.Color.Transparent;
-      tabGradient14.TextColor = System.Drawing.SystemColors.ControlDarkDark;
-      dockPaneStripToolWindowGradient2.InactiveTabGradient = tabGradient14;
-      dockPaneStripSkin2.ToolWindowGradient = dockPaneStripToolWindowGradient2;
-      dockPanelSkin2.DockPaneStripSkin = dockPaneStripSkin2;
-      this.resultsDockPanel.Skin = dockPanelSkin2;
+      this.resultsDockPanel.Size = new System.Drawing.Size(829, 421);
+      dockPanelGradient10.EndColor = System.Drawing.SystemColors.ControlLight;
+      dockPanelGradient10.StartColor = System.Drawing.SystemColors.ControlLight;
+      autoHideStripSkin4.DockStripGradient = dockPanelGradient10;
+      tabGradient22.EndColor = System.Drawing.SystemColors.Control;
+      tabGradient22.StartColor = System.Drawing.SystemColors.Control;
+      tabGradient22.TextColor = System.Drawing.SystemColors.ControlDarkDark;
+      autoHideStripSkin4.TabGradient = tabGradient22;
+      autoHideStripSkin4.TextFont = new System.Drawing.Font("Segoe UI", 9F);
+      dockPanelSkin4.AutoHideStripSkin = autoHideStripSkin4;
+      tabGradient23.EndColor = System.Drawing.SystemColors.ControlLightLight;
+      tabGradient23.StartColor = System.Drawing.SystemColors.ControlLightLight;
+      tabGradient23.TextColor = System.Drawing.SystemColors.ControlText;
+      dockPaneStripGradient4.ActiveTabGradient = tabGradient23;
+      dockPanelGradient11.EndColor = System.Drawing.SystemColors.Control;
+      dockPanelGradient11.StartColor = System.Drawing.SystemColors.Control;
+      dockPaneStripGradient4.DockStripGradient = dockPanelGradient11;
+      tabGradient24.EndColor = System.Drawing.SystemColors.ControlLight;
+      tabGradient24.StartColor = System.Drawing.SystemColors.ControlLight;
+      tabGradient24.TextColor = System.Drawing.SystemColors.ControlText;
+      dockPaneStripGradient4.InactiveTabGradient = tabGradient24;
+      dockPaneStripSkin4.DocumentGradient = dockPaneStripGradient4;
+      dockPaneStripSkin4.TextFont = new System.Drawing.Font("Segoe UI", 9F);
+      tabGradient25.EndColor = System.Drawing.SystemColors.ActiveCaption;
+      tabGradient25.LinearGradientMode = System.Drawing.Drawing2D.LinearGradientMode.Vertical;
+      tabGradient25.StartColor = System.Drawing.SystemColors.GradientActiveCaption;
+      tabGradient25.TextColor = System.Drawing.SystemColors.ActiveCaptionText;
+      dockPaneStripToolWindowGradient4.ActiveCaptionGradient = tabGradient25;
+      tabGradient26.EndColor = System.Drawing.SystemColors.Control;
+      tabGradient26.StartColor = System.Drawing.SystemColors.Control;
+      tabGradient26.TextColor = System.Drawing.SystemColors.ControlText;
+      dockPaneStripToolWindowGradient4.ActiveTabGradient = tabGradient26;
+      dockPanelGradient12.EndColor = System.Drawing.SystemColors.ControlLight;
+      dockPanelGradient12.StartColor = System.Drawing.SystemColors.ControlLight;
+      dockPaneStripToolWindowGradient4.DockStripGradient = dockPanelGradient12;
+      tabGradient27.EndColor = System.Drawing.SystemColors.InactiveCaption;
+      tabGradient27.LinearGradientMode = System.Drawing.Drawing2D.LinearGradientMode.Vertical;
+      tabGradient27.StartColor = System.Drawing.SystemColors.GradientInactiveCaption;
+      tabGradient27.TextColor = System.Drawing.SystemColors.InactiveCaptionText;
+      dockPaneStripToolWindowGradient4.InactiveCaptionGradient = tabGradient27;
+      tabGradient28.EndColor = System.Drawing.Color.Transparent;
+      tabGradient28.StartColor = System.Drawing.Color.Transparent;
+      tabGradient28.TextColor = System.Drawing.SystemColors.ControlDarkDark;
+      dockPaneStripToolWindowGradient4.InactiveTabGradient = tabGradient28;
+      dockPaneStripSkin4.ToolWindowGradient = dockPaneStripToolWindowGradient4;
+      dockPanelSkin4.DockPaneStripSkin = dockPaneStripSkin4;
+      this.resultsDockPanel.Skin = dockPanelSkin4;
       this.resultsDockPanel.TabIndex = 0;
       // 
@@ -244,5 +292,5 @@
       this.runsTabPage.Name = "runsTabPage";
       this.runsTabPage.Padding = new System.Windows.Forms.Padding(3);
-      this.runsTabPage.Size = new System.Drawing.Size(548, 476);
+      this.runsTabPage.Size = new System.Drawing.Size(548, 418);
       this.runsTabPage.TabIndex = 4;
       this.runsTabPage.Text = "Runs";
@@ -257,5 +305,5 @@
       this.runsView.Name = "runsView";
       this.runsView.ReadOnly = false;
-      this.runsView.Size = new System.Drawing.Size(542, 470);
+      this.runsView.Size = new System.Drawing.Size(542, 412);
       this.runsView.TabIndex = 0;
       // 
@@ -266,5 +314,5 @@
       this.seededRunsTabPage.Name = "seededRunsTabPage";
       this.seededRunsTabPage.Padding = new System.Windows.Forms.Padding(3);
-      this.seededRunsTabPage.Size = new System.Drawing.Size(548, 476);
+      this.seededRunsTabPage.Size = new System.Drawing.Size(548, 418);
       this.seededRunsTabPage.TabIndex = 5;
       this.seededRunsTabPage.Text = "Seeded Runs";
@@ -279,5 +327,5 @@
       this.seededRunsView.Name = "seededRunsView";
       this.seededRunsView.ReadOnly = false;
-      this.seededRunsView.Size = new System.Drawing.Size(542, 470);
+      this.seededRunsView.Size = new System.Drawing.Size(542, 412);
       this.seededRunsView.TabIndex = 1;
       // 
@@ -287,5 +335,5 @@
       this.solutionSeedingTabPage.Name = "solutionSeedingTabPage";
       this.solutionSeedingTabPage.Padding = new System.Windows.Forms.Padding(3);
-      this.solutionSeedingTabPage.Size = new System.Drawing.Size(548, 476);
+      this.solutionSeedingTabPage.Size = new System.Drawing.Size(548, 418);
       this.solutionSeedingTabPage.TabIndex = 1;
       this.solutionSeedingTabPage.Text = "Seeding Pool";
@@ -298,5 +346,5 @@
       this.parametersTabPage.Name = "parametersTabPage";
       this.parametersTabPage.Padding = new System.Windows.Forms.Padding(3);
-      this.parametersTabPage.Size = new System.Drawing.Size(548, 476);
+      this.parametersTabPage.Size = new System.Drawing.Size(548, 418);
       this.parametersTabPage.TabIndex = 0;
       this.parametersTabPage.Text = "Parameters";
@@ -313,5 +361,5 @@
       this.solverParametersView.ReadOnly = true;
       this.solverParametersView.ShowDetails = true;
-      this.solverParametersView.Size = new System.Drawing.Size(542, 470);
+      this.solverParametersView.Size = new System.Drawing.Size(542, 412);
       this.solverParametersView.TabIndex = 0;
       // 
@@ -322,5 +370,5 @@
       this.operatorGraphTabPage.Name = "operatorGraphTabPage";
       this.operatorGraphTabPage.Padding = new System.Windows.Forms.Padding(3);
-      this.operatorGraphTabPage.Size = new System.Drawing.Size(548, 476);
+      this.operatorGraphTabPage.Size = new System.Drawing.Size(548, 418);
       this.operatorGraphTabPage.TabIndex = 3;
       this.operatorGraphTabPage.Text = "Operator Graph";
@@ -336,150 +384,20 @@
       this.operatorGraphViewHost.Name = "operatorGraphViewHost";
       this.operatorGraphViewHost.ReadOnly = true;
-      this.operatorGraphViewHost.Size = new System.Drawing.Size(542, 470);
+      this.operatorGraphViewHost.Size = new System.Drawing.Size(542, 412);
       this.operatorGraphViewHost.TabIndex = 0;
       this.operatorGraphViewHost.ViewsLabelVisible = true;
       this.operatorGraphViewHost.ViewType = null;
       // 
-      // algorithmStartButton
-      // 
-      this.algorithmStartButton.Location = new System.Drawing.Point(91, 60);
-      this.algorithmStartButton.Name = "algorithmStartButton";
-      this.algorithmStartButton.Size = new System.Drawing.Size(26, 23);
-      this.algorithmStartButton.TabIndex = 10;
-      this.algorithmStartButton.Text = "Start";
-      this.algorithmStartButton.UseVisualStyleBackColor = true;
-      this.algorithmStartButton.Click += new System.EventHandler(this.AlgorithmStartButtonOnClick);
-      // 
-      // minimumTargetLabel
-      // 
-      this.minimumTargetLabel.AutoSize = true;
-      this.minimumTargetLabel.Location = new System.Drawing.Point(384, 6);
-      this.minimumTargetLabel.Name = "minimumTargetLabel";
-      this.minimumTargetLabel.Size = new System.Drawing.Size(41, 13);
-      this.minimumTargetLabel.TabIndex = 13;
-      this.minimumTargetLabel.Text = "Target:";
-      // 
-      // seedingStrategyLabel
-      // 
-      this.seedingStrategyLabel.AutoSize = true;
-      this.seedingStrategyLabel.Location = new System.Drawing.Point(3, 33);
-      this.seedingStrategyLabel.Name = "seedingStrategyLabel";
-      this.seedingStrategyLabel.Size = new System.Drawing.Size(91, 13);
-      this.seedingStrategyLabel.TabIndex = 8;
-      this.seedingStrategyLabel.Text = "Seeding Strategy:";
-      // 
-      // evaluationsLimitabel
-      // 
-      this.evaluationsLimitabel.AutoSize = true;
-      this.evaluationsLimitabel.Location = new System.Drawing.Point(3, 6);
-      this.evaluationsLimitabel.Name = "evaluationsLimitabel";
-      this.evaluationsLimitabel.Size = new System.Drawing.Size(66, 13);
-      this.evaluationsLimitabel.TabIndex = 13;
-      this.evaluationsLimitabel.Text = "Budget (FE):";
-      // 
-      // recommenderLabel
-      // 
-      this.recommenderLabel.AutoSize = true;
-      this.recommenderLabel.Location = new System.Drawing.Point(6, 9);
-      this.recommenderLabel.Name = "recommenderLabel";
-      this.recommenderLabel.Size = new System.Drawing.Size(79, 13);
-      this.recommenderLabel.TabIndex = 9;
-      this.recommenderLabel.Text = "Recommender:";
-      // 
-      // suggestedInstancesComboBox
-      // 
-      this.suggestedInstancesComboBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
-            | System.Windows.Forms.AnchorStyles.Right)));
-      this.suggestedInstancesComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
-      this.suggestedInstancesComboBox.FormattingEnabled = true;
-      this.suggestedInstancesComboBox.Location = new System.Drawing.Point(91, 33);
-      this.suggestedInstancesComboBox.Name = "suggestedInstancesComboBox";
-      this.suggestedInstancesComboBox.Size = new System.Drawing.Size(186, 21);
-      this.suggestedInstancesComboBox.TabIndex = 7;
-      this.suggestedInstancesComboBox.SelectedIndexChanged += new System.EventHandler(this.SuggestedInstancesComboBoxOnSelectedIndexChanged);
-      // 
-      // recommenderComboBox
-      // 
-      this.recommenderComboBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
-            | System.Windows.Forms.AnchorStyles.Right)));
-      this.recommenderComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
-      this.recommenderComboBox.FormattingEnabled = true;
-      this.recommenderComboBox.Location = new System.Drawing.Point(91, 6);
-      this.recommenderComboBox.Name = "recommenderComboBox";
-      this.recommenderComboBox.Size = new System.Drawing.Size(154, 21);
-      this.recommenderComboBox.TabIndex = 7;
-      this.recommenderComboBox.SelectedIndexChanged += new System.EventHandler(this.RecommenderComboBoxOnSelectedIndexChanged);
-      // 
-      // solverSplitContainer
-      // 
-      this.solverSplitContainer.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
-            | System.Windows.Forms.AnchorStyles.Left) 
-            | System.Windows.Forms.AnchorStyles.Right)));
-      this.solverSplitContainer.Location = new System.Drawing.Point(0, 56);
-      this.solverSplitContainer.Name = "solverSplitContainer";
-      // 
-      // solverSplitContainer.Panel1
-      // 
-      this.solverSplitContainer.Panel1.Controls.Add(this.recommenderViewHost);
-      this.solverSplitContainer.Panel1.Controls.Add(this.instanceLabel);
-      this.solverSplitContainer.Panel1.Controls.Add(this.recommenderLabel);
-      this.solverSplitContainer.Panel1.Controls.Add(this.recommenderComboBox);
-      this.solverSplitContainer.Panel1.Controls.Add(this.algorithmCloneButton);
-      this.solverSplitContainer.Panel1.Controls.Add(this.suggestedInstancesComboBox);
-      this.solverSplitContainer.Panel1.Controls.Add(this.recommendRefreshButton);
-      this.solverSplitContainer.Panel1.Controls.Add(this.algorithmStartButton);
-      this.solverSplitContainer.Panel1.Padding = new System.Windows.Forms.Padding(3);
-      // 
-      // solverSplitContainer.Panel2
-      // 
-      this.solverSplitContainer.Panel2.Controls.Add(this.solverTabControl);
-      this.solverSplitContainer.Panel2.Padding = new System.Windows.Forms.Padding(3);
-      this.solverSplitContainer.Size = new System.Drawing.Size(849, 508);
-      this.solverSplitContainer.SplitterDistance = 283;
-      this.solverSplitContainer.TabIndex = 17;
-      // 
-      // recommenderViewHost
-      // 
-      this.recommenderViewHost.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
-            | System.Windows.Forms.AnchorStyles.Left) 
-            | System.Windows.Forms.AnchorStyles.Right)));
-      this.recommenderViewHost.Caption = "View";
-      this.recommenderViewHost.Content = null;
-      this.recommenderViewHost.Enabled = false;
-      this.recommenderViewHost.Location = new System.Drawing.Point(6, 89);
-      this.recommenderViewHost.Name = "recommenderViewHost";
-      this.recommenderViewHost.ReadOnly = false;
-      this.recommenderViewHost.Size = new System.Drawing.Size(271, 412);
-      this.recommenderViewHost.TabIndex = 16;
-      this.recommenderViewHost.ViewsLabelVisible = true;
-      this.recommenderViewHost.ViewType = null;
-      // 
-      // instanceLabel
-      // 
-      this.instanceLabel.AutoSize = true;
-      this.instanceLabel.Location = new System.Drawing.Point(6, 36);
-      this.instanceLabel.Name = "instanceLabel";
-      this.instanceLabel.Size = new System.Drawing.Size(51, 13);
-      this.instanceLabel.TabIndex = 9;
-      this.instanceLabel.Text = "Instance:";
-      // 
-      // recommendRefreshButton
-      // 
-      this.recommendRefreshButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
-      this.recommendRefreshButton.Location = new System.Drawing.Point(251, 6);
-      this.recommendRefreshButton.Name = "recommendRefreshButton";
-      this.recommendRefreshButton.Size = new System.Drawing.Size(26, 23);
-      this.recommendRefreshButton.TabIndex = 10;
-      this.recommendRefreshButton.Text = "Start";
-      this.recommendRefreshButton.UseVisualStyleBackColor = true;
-      this.recommendRefreshButton.Click += new System.EventHandler(this.button1_Click);
-      // 
       // SolverView
       // 
       this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
       this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
-      this.Controls.Add(this.solverSplitContainer);
+      this.Controls.Add(this.solverTabControl);
+      this.Controls.Add(this.algorithmCloneButton);
+      this.Controls.Add(this.instanceLabel);
+      this.Controls.Add(this.algorithmStartButton);
       this.Controls.Add(this.minTargetView);
       this.Controls.Add(this.maxEvaluationsView);
+      this.Controls.Add(this.suggestedInstancesComboBox);
       this.Controls.Add(this.seedingStrategyPanel);
       this.Controls.Add(this.minimumTargetLabel);
@@ -495,9 +413,4 @@
       this.parametersTabPage.ResumeLayout(false);
       this.operatorGraphTabPage.ResumeLayout(false);
-      this.solverSplitContainer.Panel1.ResumeLayout(false);
-      this.solverSplitContainer.Panel1.PerformLayout();
-      this.solverSplitContainer.Panel2.ResumeLayout(false);
-      ((System.ComponentModel.ISupportInitialize)(this.solverSplitContainer)).EndInit();
-      this.solverSplitContainer.ResumeLayout(false);
       this.ResumeLayout(false);
       this.PerformLayout();
@@ -508,6 +421,21 @@
 
     private System.Windows.Forms.Panel seedingStrategyPanel;
+    private System.Windows.Forms.Button algorithmStartButton;
+    private System.Windows.Forms.Label seedingStrategyLabel;
+    private System.Windows.Forms.Label evaluationsLimitabel;
+    private System.Windows.Forms.ComboBox suggestedInstancesComboBox;
+    private System.Windows.Forms.Button algorithmCloneButton;
+    private Data.Views.StringConvertibleValueView maxEvaluationsView;
+    private System.Windows.Forms.Label minimumTargetLabel;
+    private Data.Views.StringConvertibleValueView minTargetView;
+    private System.Windows.Forms.Label instanceLabel;
     private MainForm.WindowsForms.DragOverTabControl solverTabControl;
     private System.Windows.Forms.TabPage resultsTabPage;
+    private System.Windows.Forms.CheckBox showOnlyFinalResultCheckBox;
+    private WeifenLuo.WinFormsUI.Docking.DockPanel resultsDockPanel;
+    private System.Windows.Forms.TabPage runsTabPage;
+    private Optimization.Views.RunCollectionView runsView;
+    private System.Windows.Forms.TabPage seededRunsTabPage;
+    private Optimization.Views.RunCollectionView seededRunsView;
     private System.Windows.Forms.TabPage solutionSeedingTabPage;
     private System.Windows.Forms.TabPage parametersTabPage;
@@ -515,24 +443,4 @@
     private System.Windows.Forms.TabPage operatorGraphTabPage;
     private MainForm.WindowsForms.ViewHost operatorGraphViewHost;
-    private System.Windows.Forms.Button algorithmStartButton;
-    private System.Windows.Forms.Label seedingStrategyLabel;
-    private System.Windows.Forms.Label evaluationsLimitabel;
-    private System.Windows.Forms.Label recommenderLabel;
-    private System.Windows.Forms.ComboBox suggestedInstancesComboBox;
-    private System.Windows.Forms.Button algorithmCloneButton;
-    private System.Windows.Forms.TabPage runsTabPage;
-    private Optimization.Views.RunCollectionView runsView;
-    private Data.Views.StringConvertibleValueView maxEvaluationsView;
-    private WeifenLuo.WinFormsUI.Docking.DockPanel resultsDockPanel;
-    private System.Windows.Forms.CheckBox showOnlyFinalResultCheckBox;
-    private System.Windows.Forms.TabPage seededRunsTabPage;
-    private Optimization.Views.RunCollectionView seededRunsView;
-    private System.Windows.Forms.Label minimumTargetLabel;
-    private Data.Views.StringConvertibleValueView minTargetView;
-    private System.Windows.Forms.ComboBox recommenderComboBox;
-    private System.Windows.Forms.SplitContainer solverSplitContainer;
-    private MainForm.WindowsForms.ViewHost recommenderViewHost;
-    private System.Windows.Forms.Label instanceLabel;
-    private System.Windows.Forms.Button recommendRefreshButton;
   }
 }
Index: /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Views/SolverView.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Views/SolverView.cs	(revision 13786)
+++ /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Views/SolverView.cs	(revision 13787)
@@ -28,4 +28,5 @@
 using HeuristicLab.OptimizationExpertSystem.Common;
 using System;
+using System.Linq;
 using System.Windows.Forms;
 
@@ -44,6 +45,4 @@
       algorithmCloneButton.Text = string.Empty;
       algorithmCloneButton.Image = VSImageLibrary.Clone;
-      recommendRefreshButton.Text = string.Empty;
-      recommendRefreshButton.Image = VSImageLibrary.Refresh;
       seedingStrategyView = new EnumValueView<SeedingStrategyTypes>() {
         Dock = DockStyle.Fill
@@ -68,5 +67,4 @@
           seedingStrategyView.Content = null;
           seedingSolutionsView.Content = null;
-          recommenderViewHost.Content = null;
         } else {
           maxEvaluationsView.Content = Content.MaximumEvaluations;
@@ -76,9 +74,7 @@
           seedingStrategyView.Content = Content.SeedingStrategy;
           seedingSolutionsView.Content = Content.SolutionSeedingPool;
-          recommenderViewHost.Content = Content.AlgorithmInstanceRecommender;
         }
       } finally { SuppressEvents = false; }
       UpdateSuggestedInstancesCombobox();
-      UpdateRecommenderCombobox();
     }
 
@@ -91,4 +87,23 @@
     }
 
+    #region Update Controls
+    private void UpdateSuggestedInstancesCombobox() {
+      var prevSelection = (AlgorithmInstanceItem)suggestedInstancesComboBox.SelectedItem;
+      var prevNewIndex = -1;
+      suggestedInstancesComboBox.Items.Clear();
+      if (Content == null) return;
+
+      var ranking = Content.GetAlgorithmInstanceRanking().ToList();
+
+      for (var i = 0; i < ranking.Count; i++) {
+        suggestedInstancesComboBox.Items.Add(new AlgorithmInstanceItem(ranking[i]));
+        if (prevSelection == null || ranking[i].Item1.Name == prevSelection.Item.Item1.Name)
+          prevNewIndex = prevSelection == null ? 0 : i;
+      }
+      suggestedInstancesComboBox.SelectedIndex = prevNewIndex;
+    }
+    #endregion
+
+    #region Content Event Handlers
     protected override void OnAlgorithmInstanceStarted(IAlgorithm algorithm) {
       base.OnAlgorithmInstanceStarted(algorithm);
@@ -97,54 +112,19 @@
     }
 
-    protected override void OnSuggestedInstancesChanged() {
-      base.OnSuggestedInstancesChanged();
+    protected override void OnRecommendationModelChanged() {
+      base.OnRecommendationModelChanged();
       UpdateSuggestedInstancesCombobox();
     }
+    #endregion
 
-    private void UpdateSuggestedInstancesCombobox() {
-      var prevSelection = (IAlgorithm)suggestedInstancesComboBox.SelectedItem;
-      var prevNewIndex = -1;
-      suggestedInstancesComboBox.Items.Clear();
-      if (Content == null) return;
-
-      for (var i = 0; i < Content.AlgorithmInstances.Count; i++) {
-        suggestedInstancesComboBox.Items.Add(Content.AlgorithmInstances[i]);
-        if (prevSelection == null || Content.AlgorithmInstances[i].Name == prevSelection.Name)
-          prevNewIndex = prevSelection == null ? 0 : i;
-      }
-      if (prevNewIndex >= 0) suggestedInstancesComboBox.SelectedIndex = prevNewIndex;
-    }
-
-    private void UpdateRecommenderCombobox() {
-      var prevSelection = Content.AlgorithmInstanceRecommender;
-      var prevNewIndex = -1;
-      recommenderComboBox.Items.Clear();
-      if (Content == null) return;
-
-      /*var i = 0;
-      foreach (var type in ApplicationManager.Manager.GetTypes(typeof (IAlgorithmInstanceRecommender))) {
-        var r = (IAlgorithmInstanceRecommender)Activator.CreateInstance(type, BindingFlags.CreateInstance, Content);
-        recommenderComboBox.Items.Add(r);
-        if (prevSelection == null || type == prevSelection.GetType())
-          prevNewIndex = prevSelection == null ? 0 : i;
-        i++;
-      }
-      if (prevNewIndex >= 0) recommenderComboBox.SelectedIndex = prevNewIndex;*/
-      recommenderComboBox.Items.Add(new OverallBestRecommender(Content));
-      if (prevSelection is OverallBestRecommender) recommenderComboBox.SelectedIndex = recommenderComboBox.Items.Count - 1;
-      recommenderComboBox.Items.Add(new KNearestNeighborRecommender(Content));
-      if (prevSelection is KNearestNeighborRecommender) recommenderComboBox.SelectedIndex = recommenderComboBox.Items.Count - 1;
-      recommenderComboBox.Items.Add(new DistanceWeightedRecommender(Content));
-      if (prevSelection is DistanceWeightedRecommender) recommenderComboBox.SelectedIndex = recommenderComboBox.Items.Count - 1;
-    }
-
+    #region Control Event Handlers
     private void AlgorithmStartButtonOnClick(object sender, EventArgs e) {
       if (suggestedInstancesComboBox.SelectedIndex >= 0)
-        Content.StartAlgorithmAsync(suggestedInstancesComboBox.SelectedIndex);
+        Content.StartAlgorithmAsync(Content.AlgorithmInstances.Select((a, i) => new { Alg = a, Index = i}).Single(x => x.Alg.Name == ((AlgorithmInstanceItem)suggestedInstancesComboBox.SelectedItem).Item.Item1.Name).Index);
     }
 
     private void AlgorithmCloneButtonOnClick(object sender, EventArgs e) {
       if (suggestedInstancesComboBox.SelectedIndex >= 0)
-        MainForm.ShowContent((IAlgorithm)Content.AlgorithmInstances[suggestedInstancesComboBox.SelectedIndex].Clone());
+        MainForm.ShowContent((IAlgorithm)Content.AlgorithmInstances[Content.AlgorithmInstances.Select((a, i) => new { Alg = a, Index = i }).Single(x => x.Alg.Name == ((AlgorithmInstanceItem)suggestedInstancesComboBox.SelectedItem).Item.Item1.Name).Index].Clone());
     }
 
@@ -152,5 +132,5 @@
       if (InvokeRequired) { Invoke((Action<object, EventArgs>)SuggestedInstancesComboBoxOnSelectedIndexChanged, sender, e); return; }
       if (suggestedInstancesComboBox.SelectedIndex >= 0) {
-        var alg = Content.AlgorithmInstances[suggestedInstancesComboBox.SelectedIndex];
+        var alg = Content.AlgorithmInstances[Content.AlgorithmInstances.Select((a, i) => new { Alg = a, Index = i }).Single(x => x.Alg.Name == ((AlgorithmInstanceItem)suggestedInstancesComboBox.SelectedItem).Item.Item1.Name).Index];
         solverParametersView.Content = alg.Parameters;
         var engineAlg = alg as EngineAlgorithm;
@@ -163,16 +143,20 @@
       SetEnabledStateOfControls();
     }
+    #endregion
 
-    private void RecommenderComboBoxOnSelectedIndexChanged(object sender, EventArgs e) {
-      if (InvokeRequired) { Invoke((Action<object, EventArgs>)RecommenderComboBoxOnSelectedIndexChanged, sender, e); return; }
-      if (recommenderComboBox.SelectedIndex < 0) return;
-      Content.AlgorithmInstanceRecommender = (IAlgorithmInstanceRecommender)recommenderComboBox.SelectedItem;
-      recommenderViewHost.Content = Content.AlgorithmInstanceRecommender;
-      Content.UpdateSuggestions();
+    #region Helper Classes and Methods
+    private class AlgorithmInstanceItem {
+      private readonly Tuple<IAlgorithm, double> item;
+      public Tuple<IAlgorithm, double> Item { get { return item; } }
+
+      public AlgorithmInstanceItem(Tuple<IAlgorithm, double> item) {
+        this.item = item;
+      }
+
+      public override string ToString() {
+        return item.Item2.ToString("F0") + ": " + item.Item1.Name;
+      }
     }
-
-    private void button1_Click(object sender, EventArgs e) {
-      Content.UpdateSuggestions();
-    }
+    #endregion
   }
 }
Index: /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Views/UnderstandingProblemInstanceView.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Views/UnderstandingProblemInstanceView.cs	(revision 13786)
+++ /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Views/UnderstandingProblemInstanceView.cs	(revision 13787)
@@ -22,7 +22,7 @@
 using HeuristicLab.Common.Resources;
 using HeuristicLab.Core;
-using HeuristicLab.Core.Views;
 using HeuristicLab.Data;
 using HeuristicLab.MainForm;
+using HeuristicLab.MainForm.WindowsForms;
 using HeuristicLab.OptimizationExpertSystem.Common;
 using System;
@@ -39,5 +39,5 @@
   public sealed partial class UnderstandingProblemInstanceView : KnowledgeCenterViewBase {
     private bool SuppressEvents { get; set; }
-    private readonly CheckedItemListView<StringValue> characteristicsView;
+    private readonly CheckedItemList<StringValue> characteristics;
  
     public UnderstandingProblemInstanceView() {
@@ -45,20 +45,22 @@
       showCharacteristicsCheckBox.Text = string.Empty;
       showCharacteristicsCheckBox.Image = VSImageLibrary.Properties;
-      characteristicsView = new CheckedItemListView<StringValue>() {
-        Dock = DockStyle.Fill
-      };
-      mapSplitContainer.Panel2.Controls.Add(characteristicsView);
+      characteristics = new CheckedItemList<StringValue>();
+      characteristics.CheckedItemsChanged += CharacteristicsOnCheckedItemsChanged;
+      mapSplitContainer.Panel2.Controls.Add(new ViewHost() {
+        Dock = DockStyle.Fill,
+        Content = characteristics
+      });
     }
 
     protected override void OnContentChanged() {
       base.OnContentChanged();
+      characteristics.Clear();
       if (Content == null) {
         problemInstancesView.Content = null;
-        characteristicsView.Content = null;
         instanceMapChart.Series["InstancesSeries"].Points.Clear();
         instanceMapChart.Series["CurrentInstanceSeries"].Points.Clear();
       } else {
         problemInstancesView.Content = Content.ProblemInstances;
-        characteristicsView.Content = Content.ProblemCharacteristics;
+        UpdateCharacteristics();
         UpdateProjectionComboBox();
         UpdateSizeComboBox();
@@ -67,19 +69,16 @@
     }
 
-    #region Content Event Handlers
-    protected override void OnProblemChanged() {
-      base.OnProblemChanged();
-      SetEnabledStateOfControls();
-    }
-
-    protected override void OnProblemInstancesChanged() {
-      base.OnProblemInstancesChanged();
-      if (Content.ProblemInstances.UpdateOfRunsInProgress) return;
-      UpdateProjectionComboBox();
-      UpdateSizeComboBox();
-      UpdateColorComboBox();
-      UpdateProjection();
-    }
-    #endregion
+    protected override void SetEnabledStateOfControls() {
+      base.SetEnabledStateOfControls();
+    }
+
+    #region Update Controls
+    private void UpdateCharacteristics() {
+      var @checked = new HashSet<string>(characteristics.CheckedItems.Select(x => x.Value.Value));
+      characteristics.Clear();
+      foreach (var c in Content.ProblemInstances.ResultNames) {
+        characteristics.Add(new StringValue(c), @checked.Contains(c));
+      }
+    }
 
     private void UpdateProjectionComboBox() {
@@ -126,11 +125,4 @@
       } finally { SuppressEvents = false; }
     }
-    
-    private IEnumerable<string> GetProjections() {
-      return Content.ProblemInstances
-        .SelectMany(x => x.Results.Where(y => Regex.IsMatch(y.Key, "^Projection[.].*[.][XY]$")))
-        .Select(x => Regex.Match(x.Key, "Projection[.](?<g>.*)[.][XY]").Groups["g"].Value)
-        .Distinct();
-    }
 
     private void UpdateProjection() {
@@ -153,4 +145,67 @@
         size, color, invPropCheckBox.Checked, fromZeroCheckBox.Checked);
     }
+    #endregion
+
+    #region Content Event Handlers
+    protected override void OnProblemChanged() {
+      base.OnProblemChanged();
+      SetEnabledStateOfControls();
+    }
+
+    protected override void OnProblemInstancesChanged() {
+      base.OnProblemInstancesChanged();
+      if (Content.ProblemInstances.UpdateOfRunsInProgress) return;
+      try {
+        SuppressEvents = true;
+        UpdateCharacteristics();
+      } finally { SuppressEvents = false; }
+      UpdateProjectionComboBox();
+      UpdateSizeComboBox();
+      UpdateColorComboBox();
+      UpdateProjection();
+    }
+    #endregion
+
+    #region Control Event Handlers
+    private void ProjectionComboBoxOnSelectedIndexChanged(object sender, EventArgs e) {
+      UpdateProjection();
+    }
+
+    private void SizeComboBoxOnSelectedIndexChanged(object sender, EventArgs e) {
+      UpdateProjection();
+    }
+
+    private void colorComboBox_SelectedIndexChanged(object sender, EventArgs e) {
+      UpdateProjection();
+    }
+
+    private void InvPropCheckBoxOnCheckedChanged(object sender, EventArgs e) {
+      UpdateProjection();
+    }
+
+    private void fromZeroCheckBox_CheckedChanged(object sender, EventArgs e) {
+      UpdateProjection();
+    }
+
+    private void showCharacteristicsCheckBox_CheckedChanged(object sender, EventArgs e) {
+      mapSplitContainer.Panel2Collapsed = !showCharacteristicsCheckBox.Checked;
+    }
+    #endregion
+
+    #region Other Event Handlers
+    private void CharacteristicsOnCheckedItemsChanged(object sender, EventArgs e) {
+      if (SuppressEvents) return;
+      if (characteristics.CheckedItems.Any())
+        Content.UpdateInstanceProjection(characteristics.CheckedItems.Select(x => x.Value.Value).ToArray());
+    }
+    #endregion
+
+    #region Helper Classes and Methods
+    private IEnumerable<string> GetProjections() {
+      return Content.ProblemInstances.ResultNames
+        .Where(x => Regex.IsMatch(x, "^Projection[.].*[.][XY]$"))
+        .Select(x => Regex.Match(x, "Projection[.](?<g>.*)[.][XY]").Groups["g"].Value)
+        .Distinct();
+    }
 
     private void DoProjectProblemInstances(Series instancesSeries, Series currentInstanceSeries, string projection, string size, string color, bool invProp, bool fromZero) {
@@ -160,5 +215,5 @@
       double maxSize = 0, minSize = 0;
       if (!string.IsNullOrEmpty(size)) {
-        var sizes = Content.ProblemInstances.Where(x => x.Results.ContainsKey(size)).Select(x => x.Results[size]).OfType<Data.DoubleValue>().Where(x => !double.IsNaN(x.Value)).ToList();
+        var sizes = Content.ProblemInstances.Where(x => x.Results.ContainsKey(size)).Select(x => x.Results[size]).OfType<DoubleValue>().Where(x => !double.IsNaN(x.Value)).ToList();
         if (sizes.Count > 0) {
           maxSize = sizes.Max(x => x.Value);
@@ -177,7 +232,7 @@
         var yKey = "Projection." + projection + ".Y";
         if (!run.Results.ContainsKey(xKey) || !run.Results.ContainsKey(yKey)
-            || !(run.Results[xKey] is Data.DoubleValue) || !(run.Results[yKey] is Data.DoubleValue)) continue;
-        var x = ((Data.DoubleValue)run.Results[xKey]).Value;
-        var y = ((Data.DoubleValue)run.Results[yKey]).Value;
+            || !(run.Results[xKey] is DoubleValue) || !(run.Results[yKey] is DoubleValue)) continue;
+        var x = ((DoubleValue)run.Results[xKey]).Value;
+        var y = ((DoubleValue)run.Results[yKey]).Value;
         var dataPoint = new DataPoint(x, y) {
           Label = run.Name,
@@ -185,5 +240,5 @@
         IItem item;
         if (maxSize > minSize && run.Results.TryGetValue(size, out item)) {
-          var dItem = item as Data.DoubleValue;
+          var dItem = item as DoubleValue;
           if (dItem == null && item is IntValue) dItem = new DoubleValue(((IntValue)item).Value);
           if (dItem != null) {
@@ -216,29 +271,4 @@
       }
     }
-
-    #region Control Event Handlers
-    private void ProjectionComboBoxOnSelectedIndexChanged(object sender, EventArgs e) {
-      UpdateProjection();
-    }
-
-    private void SizeComboBoxOnSelectedIndexChanged(object sender, EventArgs e) {
-      UpdateProjection();
-    }
-
-    private void colorComboBox_SelectedIndexChanged(object sender, EventArgs e) {
-      UpdateProjection();
-    }
-
-    private void InvPropCheckBoxOnCheckedChanged(object sender, EventArgs e) {
-      UpdateProjection();
-    }
-
-    private void fromZeroCheckBox_CheckedChanged(object sender, EventArgs e) {
-      UpdateProjection();
-    }
-
-    private void showCharacteristicsCheckBox_CheckedChanged(object sender, EventArgs e) {
-      mapSplitContainer.Panel2Collapsed = !showCharacteristicsCheckBox.Checked;
-    }
     #endregion
   }
Index: /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Views/UnderstandingSolutionsView.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Views/UnderstandingSolutionsView.cs	(revision 13786)
+++ /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Views/UnderstandingSolutionsView.cs	(revision 13787)
@@ -54,23 +54,6 @@
       UpdateSolutionVisualization();
     }
-
-    protected override void OnProblemChanged() {
-      base.OnProblemInstancesChanged();
-      UpdateSimilarityCalculators();
-      UpdateNamesComboboxes();
-      UpdateSolutionVisualization();
-    }
-
-    protected override void OnProblemSolutionsChanged() {
-      base.OnProblemSolutionsChanged();
-      UpdateNamesComboboxes();
-      UpdateSolutionVisualization();
-    }
-
-    protected override void OnSolutionSeedingPoolChanged() {
-      base.OnSolutionSeedingPoolChanged();
-      UpdateSolutionNetworkAnalysis(similarityComboBox.SelectedItem as ISolutionSimilarityCalculator, (string)solutionNetworkProjectionComboBox.SelectedItem, linesCheckBox.Checked, contrastTrackBar.Value, minimumTrackBar.Value);
-    }
-
+    
+    #region Update Controls
     private void UpdateSimilarityCalculators() {
       var selected = (ISolutionSimilarityCalculator)(similarityComboBox.SelectedIndex >= 0 ? similarityComboBox.SelectedItem : null);
@@ -280,5 +263,27 @@
       }
     }
-
+    #endregion
+
+    #region Content Event Handlers
+    protected override void OnProblemChanged() {
+      base.OnProblemInstancesChanged();
+      UpdateSimilarityCalculators();
+      UpdateNamesComboboxes();
+      UpdateSolutionVisualization();
+    }
+
+    protected override void OnProblemSolutionsChanged() {
+      base.OnProblemSolutionsChanged();
+      UpdateNamesComboboxes();
+      UpdateSolutionVisualization();
+    }
+
+    protected override void OnSolutionSeedingPoolChanged() {
+      base.OnSolutionSeedingPoolChanged();
+      UpdateSolutionNetworkAnalysis(similarityComboBox.SelectedItem as ISolutionSimilarityCalculator, (string)solutionNetworkProjectionComboBox.SelectedItem, linesCheckBox.Checked, contrastTrackBar.Value, minimumTrackBar.Value);
+    }
+    #endregion
+
+    #region Control Event Handlers
     private void SimilarityComboBoxOnSelectedIndexChanged(object sender, EventArgs e) {
       if (InvokeRequired) { Invoke((Action<object, EventArgs>)SimilarityComboBoxOnSelectedIndexChanged, sender, e); return; }
@@ -370,6 +375,7 @@
       }
     }
-
-    #region Helpers
+    #endregion
+
+    #region Helper Classes and Methods
     private List<IScope> GetSolutionScopes() {
       return Content.Problem.Solutions.Select(x => x.Solution).OfType<IScope>().ToList();
