Index: branches/PerformanceComparison/HeuristicLab.Analysis/3.3/QualityAnalysis/ExpectedRuntimeHelper.cs
===================================================================
--- branches/PerformanceComparison/HeuristicLab.Analysis/3.3/QualityAnalysis/ExpectedRuntimeHelper.cs	(revision 13767)
+++ branches/PerformanceComparison/HeuristicLab.Analysis/3.3/QualityAnalysis/ExpectedRuntimeHelper.cs	(revision 13774)
@@ -53,5 +53,5 @@
 
     public override string ToString() {
-      return SuccessfulRuns == 0 ? "\u221e"
+      return SuccessfulRuns == 0 ? "\u221e" // infinity symbol
                                  : ExpectedRuntime.ToString("##,0.0", CultureInfo.CurrentCulture.NumberFormat);
     }
Index: branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/DistanceWeightedRecommender.cs
===================================================================
--- branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/DistanceWeightedRecommender.cs	(revision 13774)
+++ branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/DistanceWeightedRecommender.cs	(revision 13774)
@@ -0,0 +1,118 @@
+﻿#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/HeuristicLab.OptimizationExpertSystem.Common-3.3.csproj
===================================================================
--- branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/HeuristicLab.OptimizationExpertSystem.Common-3.3.csproj	(revision 13767)
+++ branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/HeuristicLab.OptimizationExpertSystem.Common-3.3.csproj	(revision 13774)
@@ -78,4 +78,9 @@
       <Private>False</Private>
     </Reference>
+    <Reference Include="HeuristicLab.Algorithms.DataAnalysis-3.4, Version=3.4.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Algorithms.DataAnalysis-3.4.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
     <Reference Include="HeuristicLab.Clients.OKB-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
       <SpecificVersion>False</SpecificVersion>
@@ -120,4 +125,9 @@
     <Reference Include="HeuristicLab.PluginInfrastructure-3.3">
       <HintPath>..\..\..\trunk\sources\bin\HeuristicLab.PluginInfrastructure-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Problems.DataAnalysis-3.4, Version=3.4.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\sources\bin\HeuristicLab.Problems.DataAnalysis-3.4.dll</HintPath>
       <Private>False</Private>
     </Reference>
@@ -148,4 +158,8 @@
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="OverallBestRecommender.cs" />
+    <Compile Include="DistanceWeightedRecommender.cs" />
+    <Compile Include="IAlgorithmInstanceRecommender.cs" />
+    <Compile Include="KNearestNeighborRecommender.cs" />
     <Compile Include="KnowledgeCenter.cs" />
     <Compile Include="Plugin.cs" />
Index: branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/IAlgorithmInstanceRecommender.cs
===================================================================
--- branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/IAlgorithmInstanceRecommender.cs	(revision 13774)
+++ branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/IAlgorithmInstanceRecommender.cs	(revision 13774)
@@ -0,0 +1,30 @@
+﻿#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/KNearestNeighborRecommender.cs
===================================================================
--- branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/KNearestNeighborRecommender.cs	(revision 13774)
+++ branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/KNearestNeighborRecommender.cs	(revision 13774)
@@ -0,0 +1,95 @@
+﻿#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 13767)
+++ branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/KnowledgeCenter.cs	(revision 13774)
@@ -30,4 +30,5 @@
 using HeuristicLab.Optimization;
 using HeuristicLab.Persistence.Default.Xml;
+using HeuristicLab.Problems.DataAnalysis;
 using HeuristicLab.Random;
 using System;
@@ -50,5 +51,5 @@
     public string Filename { get; set; }
 
-    public static new Image StaticItemImage {
+    public static Image StaticItemImage {
       get { return VSImageLibrary.Library; }
     }
@@ -84,8 +85,8 @@
     }
 
-    private readonly ItemList<IAlgorithm> suggestedInstances;
-    private readonly ReadOnlyItemList<IAlgorithm> readOnlySuggestedInstances;
-    public ReadOnlyItemList<IAlgorithm> SuggestedInstances {
-      get { return readOnlySuggestedInstances; }
+    private readonly ItemList<IAlgorithm> algorithmInstances;
+    private readonly ReadOnlyItemList<IAlgorithm> readonlyAlgorithmInstances;
+    public ReadOnlyItemList<IAlgorithm> AlgorithmInstances {
+      get { return readonlyAlgorithmInstances; }
     }
 
@@ -101,12 +102,8 @@
     }
 
-    private readonly EnumValue<ProblemInstanceProximityType> problemInstanceProximity;
-    public EnumValue<ProblemInstanceProximityType> ProblemInstanceProximity {
-      get { return problemInstanceProximity; }
-    }
-
-    private readonly DoubleValue problemInstanceNeighborhoodFactor;
-    public DoubleValue ProblemInstanceNeighborhoodFactor {
-      get { return problemInstanceNeighborhoodFactor; }
+    private IAlgorithmInstanceRecommender algorithmInstanceRecommender;
+    public IAlgorithmInstanceRecommender AlgorithmInstanceRecommender {
+      get { return algorithmInstanceRecommender; }
+      set { algorithmInstanceRecommender = value; }
     }
 
@@ -125,5 +122,5 @@
     private BidirectionalDictionary<long, IRun> problemId2ProblemInstanceMapping;
     
-    private bool Maximization {
+    public bool Maximization {
       get { return Problem != null && Problem.ProblemId >= 0 && ((IValueParameter<BoolValue>)Problem.MaximizationParameter).Value.Value; }
     }
@@ -135,11 +132,10 @@
       seededRuns = new RunCollection();
       knowledgeBase = new RunCollection();
-      suggestedInstances = new ItemList<IAlgorithm>();
-      readOnlySuggestedInstances = suggestedInstances.AsReadOnly();
+      algorithmInstances = new ItemList<IAlgorithm>();
+      readonlyAlgorithmInstances = algorithmInstances.AsReadOnly();
       problemInstances = new RunCollection();
       problemCharacteristics = new CheckedItemList<StringValue>();
-      problemInstanceProximity = new EnumValue<ProblemInstanceProximityType>(ProblemInstanceProximityType.FeatureSpace);
-      problemInstanceNeighborhoodFactor = new DoubleValue(5);
       readonlyProblemCharacteristics = problemCharacteristics.AsReadOnly();
+      algorithmInstanceRecommender = new OverallBestRecommender(this);
       problem = new SingleObjectiveOKBProblem();
       algorithmId2RunMapping = new BidirectionalLookup<long, IRun>();
@@ -176,6 +172,4 @@
       problemCharacteristics.CollectionReset += CharacteristicChanged;
       problemCharacteristics.CheckedItemsChanged += CharacteristicChanged;
-      problemInstanceProximity.ValueChanged += ProblemInstanceProximityChanged;
-      problemInstanceNeighborhoodFactor.ValueChanged += ProblemInstanceProximityChanged;
     }
 
@@ -205,9 +199,5 @@
       UpdateInstanceProjection();
     }
-
-    private void ProblemInstanceProximityChanged(object sender, EventArgs e) {
-      UpdateSuggestions();
-    }
-
+    
     public bool IsCurrentInstance(IRun run) {
       if (!problemId2ProblemInstanceMapping.ContainsSecond(run)) return false;
@@ -339,5 +329,5 @@
 
     public Task<ResultCollection> StartAlgorithmAsync(int index, CancellationToken cancellation) {
-      var selectedInstance = suggestedInstances[index];
+      var selectedInstance = algorithmInstances[index];
       var algorithmClone = (IAlgorithm)selectedInstance.Clone();
       var problemClone = Problem.CloneProblem() as ISingleObjectiveHeuristicOptimizationProblem;
@@ -627,62 +617,72 @@
     }
 
-    private void UpdateSuggestions() {
-      if (Problem == null) return;
-      var piDistances = GetProblemDistances();
-      var maxDist = piDistances.Max(x => x.Value);
-      var instances = new SortedList<double, IAlgorithm>();
+    public void UpdateSuggestions() {
+      // TODO: Maintain a separate list of suggested instances
+      // TODO: expose expected expected run time
+      algorithmInstances.Replace(AlgorithmInstanceRecommender.GetRanking());
+    }
+
+    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);
+      return knowledgeBase.Where(x => ((StringValue)x.Parameters["Problem Name"]).Value == ((StringValue)problemInstance.Parameters["Problem Name"]).Value)
+                          .GroupBy(x => algorithmId2AlgorithmInstanceMapping.GetByFirst(algorithmId2RunMapping.GetBySecond(x).Single()))
+                          .ToDictionary(x => x.Key, x => ExpectedRuntimeHelper.CalculateErt(x.ToList(), "QualityPerEvaluations", target, Maximization).ExpectedRuntime);
+    }
+
+    public Dictionary<IAlgorithm, List<IRun>> GetKnowledgeBaseByAlgorithm() {
+      return KnowledgeBase.GroupBy(x => algorithmId2AlgorithmInstanceMapping.GetByFirst(algorithmId2RunMapping.GetBySecond(x).Single()))
+                          .ToDictionary(x => x.Key, x => x.ToList());
+    }
+
+    public IEnumerable<IRegressionProblem> GetDataAnalysisProblem(double target) {
+      if (Problem == null) yield break;
+      var characteristics = GetProblemCharacteristics();
+      // TODO: knowledgebase only stores problem name as a string
+      // this doesn't work if there are two equally named problem instances
+      var problemMap = ProblemInstances.Select(x => new { Key = ((StringValue)x.Parameters["Problem Name"]).Value, Value = x })
+                                       .ToDictionary(x => x.Key, x => x.Value);
       foreach (var relevantRuns in knowledgeBase.GroupBy(x => algorithmId2RunMapping.GetBySecond(x).Single())) {
-        var algorithm = algorithmId2AlgorithmInstanceMapping.GetByFirst(relevantRuns.Key);
-        Func<double, double> distFunc = (d) => Math.Exp(ProblemInstanceNeighborhoodFactor.Value * (-d / maxDist));
-        var pis = relevantRuns.Select(x => ((StringValue)x.Parameters["Problem Name"]).Value).Distinct()
-                              .Select(x => Tuple.Create(x, ProblemInstances.SingleOrDefault(y => ((StringValue)y.Parameters["Problem Name"]).Value == x)))
-                              .Where(x => x.Item2 != null)
-                              .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.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 < MaximumEvaluations.Value));
-            if (current.Count > 0) {
-              current.Add(Tuple.Create((double)MaximumEvaluations.Value, current.Last().Item2));
-              convGraph.Add(current);
-            }
-          }
-          var ert = ExpectedRuntimeHelper.CalculateErt(convGraph, (Maximization ? (1 - MinimumTarget.Value) : (1 + MinimumTarget.Value)) * info.Item2, Maximization).ExpectedRuntime;
-          if (double.IsNaN(ert)) {
-            ert = ExpectedRuntimeHelper.CalculateErt(problemRuns.ToList(), "QualityPerEvaluations", (Maximization ? (1 - MinimumTarget.Value) : (1 + MinimumTarget.Value)) * info.Item2, 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);
-      }
-
-      var instanceLadder = instances.Select(x => (IAlgorithm)x.Value.Clone()).ToList();
-      suggestedInstances.Replace(instanceLadder);
-    }
-
-    private Dictionary<IRun, double> GetProblemDistances() {
+        var problemRuns = relevantRuns.GroupBy(x => ((StringValue)x.Parameters["Problem Name"]).Value).ToList();
+        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>());
+        ds.AddVariable("ERT", new List<double>());
+        var max = Maximization;
+        foreach (var pr in problemRuns) {
+          var prob = problemMap[pr.Key];
+          var features = characteristics[prob];
+          var bkq = ((DoubleValue)prob.Parameters["BestKnownQuality"]).Value;
+          var ert = ExpectedRuntimeHelper.CalculateErt(pr.ToList(), "QualityPerEvaluations", GetTarget(bkq), 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");
+        var result = new RegressionProblem() {
+          Name = algorithmId2AlgorithmInstanceMapping.GetByFirst(relevantRuns.Key).Name
+        };
+        result.ProblemDataParameter.Value = datAnalysisData;
+        yield return result;
+      }
+    }
+
+    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>(); 
       var currentInstance = problemId2ProblemInstanceMapping.GetByFirst(Problem.ProblemId);
-      switch (ProblemInstanceProximity.Value) {
+      switch (proximityType) {
         case ProblemInstanceProximityType.MDS:
         case ProblemInstanceProximityType.PCA:
         case ProblemInstanceProximityType.SOM:
           double xa, ya;
-          GetProjectionCoordinates(currentInstance, out xa, out ya);
+          GetProjectionCoordinates(currentInstance, proximityType, out xa, out ya);
           foreach (var b in ProblemInstances) {
+            if (b == currentInstance) continue;
             double xb, yb;
-            GetProjectionCoordinates(b, out xb, out yb);
+            GetProjectionCoordinates(b, proximityType, out xb, out yb);
             var d = Math.Sqrt((xa - xb) * (xa - xb) + (ya - yb) * (ya - yb));
             result[b] = d;
@@ -693,17 +693,18 @@
           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}", ProblemInstanceProximity.Value));
+        default: throw new InvalidOperationException(string.Format("Unkonwn proximity type {0}", proximityType));
       }
       return result;
     }
 
-    private void GetProjectionCoordinates(IRun problemInstance, out double x, out double y) {
-      x = ((DoubleValue)problemInstance.Results["Projection." + ProblemInstanceProximity.Value + ".X"]).Value;
-      y = ((DoubleValue)problemInstance.Results["Projection." + ProblemInstanceProximity.Value + ".Y"]).Value;
-      if (ProblemInstanceProximity.Value == ProblemInstanceProximityType.SOM) {
+    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);
Index: branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/OverallBestRecommender.cs
===================================================================
--- branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/OverallBestRecommender.cs	(revision 13774)
+++ branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Common/3.3/OverallBestRecommender.cs	(revision 13774)
@@ -0,0 +1,99 @@
+﻿#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/3.3/Docking/AlgorithmControlForm.cs
===================================================================
--- branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Docking/AlgorithmControlForm.cs	(revision 13767)
+++ branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Docking/AlgorithmControlForm.cs	(revision 13774)
@@ -119,5 +119,6 @@
 
     #region Algorithm Events
-    private void AlgorithmOnExecutionStateChanged(object sender, EventArgs eventArgs) {
+    private void AlgorithmOnExecutionStateChanged(object sender, EventArgs e) {
+      if (InvokeRequired) { Invoke((Action<object, EventArgs>)AlgorithmOnExecutionStateChanged, sender, e); return; }
       if (ShowOnlyFinalResult && (Algorithm.ExecutionState == ExecutionState.Stopped
         || Algorithm.ExecutionState == ExecutionState.Paused))
Index: branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Plugin.cs.frame
===================================================================
--- branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Plugin.cs.frame	(revision 13767)
+++ branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Plugin.cs.frame	(revision 13774)
@@ -20,7 +20,9 @@
 #endregion
 
+using HeuristicLab.Clients.Access;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.PluginInfrastructure;
 using System.Windows.Forms;
-using HeuristicLab.Clients.Access;
-using HeuristicLab.PluginInfrastructure;
 
 namespace HeuristicLab.OptimizationExpertSystem {
@@ -50,5 +52,5 @@
       ClientInformation.InitializeAsync();
       UserInformation.InitializeAsync();
-
+      ContentManager.Initialize(new PersistenceContentManager());
       mainForm.ShowContentInViewHost = true;
       Application.Run(mainForm);
Index: branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Views/KnowledgeCenterAllinOneView.cs
===================================================================
--- branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Views/KnowledgeCenterAllinOneView.cs	(revision 13767)
+++ branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Views/KnowledgeCenterAllinOneView.cs	(revision 13774)
@@ -78,9 +78,9 @@
     #region Event Registration
     protected override void DeregisterContentEvents() {
-      Content.SuggestedInstances.CollectionReset -= SuggestedInstancesOnChanged;
-      Content.SuggestedInstances.ItemsAdded -= SuggestedInstancesOnChanged;
-      Content.SuggestedInstances.ItemsMoved -= SuggestedInstancesOnChanged;
-      Content.SuggestedInstances.ItemsRemoved -= SuggestedInstancesOnChanged;
-      Content.SuggestedInstances.ItemsReplaced -= SuggestedInstancesOnChanged;
+      Content.AlgorithmInstances.CollectionReset -= SuggestedInstancesOnChanged;
+      Content.AlgorithmInstances.ItemsAdded -= SuggestedInstancesOnChanged;
+      Content.AlgorithmInstances.ItemsMoved -= SuggestedInstancesOnChanged;
+      Content.AlgorithmInstances.ItemsRemoved -= SuggestedInstancesOnChanged;
+      Content.AlgorithmInstances.ItemsReplaced -= SuggestedInstancesOnChanged;
       Content.SolutionSeedingPool.CollectionReset -= SeedingPoolOnChanged;
       Content.SolutionSeedingPool.ItemsAdded -= SeedingPoolOnChanged;
@@ -94,9 +94,9 @@
     protected override void RegisterContentEvents() {
       base.RegisterContentEvents();
-      Content.SuggestedInstances.CollectionReset += SuggestedInstancesOnChanged;
-      Content.SuggestedInstances.ItemsAdded += SuggestedInstancesOnChanged;
-      Content.SuggestedInstances.ItemsMoved += SuggestedInstancesOnChanged;
-      Content.SuggestedInstances.ItemsRemoved += SuggestedInstancesOnChanged;
-      Content.SuggestedInstances.ItemsReplaced += SuggestedInstancesOnChanged;
+      Content.AlgorithmInstances.CollectionReset += SuggestedInstancesOnChanged;
+      Content.AlgorithmInstances.ItemsAdded += SuggestedInstancesOnChanged;
+      Content.AlgorithmInstances.ItemsMoved += SuggestedInstancesOnChanged;
+      Content.AlgorithmInstances.ItemsRemoved += SuggestedInstancesOnChanged;
+      Content.AlgorithmInstances.ItemsReplaced += SuggestedInstancesOnChanged;
       Content.SolutionSeedingPool.CollectionReset += SeedingPoolOnChanged;
       Content.SolutionSeedingPool.ItemsAdded += SeedingPoolOnChanged;
@@ -248,5 +248,5 @@
     private void AlgorithmCloneButtonOnClick(object sender, EventArgs e) {
       if (suggestedInstancesComboBox.SelectedIndex >= 0)
-        MainFormManager.MainForm.ShowContent((IAlgorithm)Content.SuggestedInstances[suggestedInstancesComboBox.SelectedIndex].Clone());
+        MainFormManager.MainForm.ShowContent((IAlgorithm)Content.AlgorithmInstances[suggestedInstancesComboBox.SelectedIndex].Clone());
     }
 
@@ -279,5 +279,5 @@
       if (InvokeRequired) { Invoke((Action<object, EventArgs>)SuggestedInstancesComboBoxOnSelectedIndexChanged, sender, e); return; }
       if (suggestedInstancesComboBox.SelectedIndex >= 0) {
-        var alg = Content.SuggestedInstances[suggestedInstancesComboBox.SelectedIndex];
+        var alg = Content.AlgorithmInstances[suggestedInstancesComboBox.SelectedIndex];
         solverParametersView.Content = alg.Parameters;
         var engineAlg = alg as EngineAlgorithm;
@@ -328,7 +328,7 @@
       if (Content == null) return;
 
-      for (var i = 0; i < Content.SuggestedInstances.Count; i++) {
-        suggestedInstancesComboBox.Items.Add(Content.SuggestedInstances[i]);
-        if (prevSelection == null || Content.SuggestedInstances[i].Name == prevSelection.Name)
+      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;
       }
Index: branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Views/KnowledgeCenterViewBase.cs
===================================================================
--- branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Views/KnowledgeCenterViewBase.cs	(revision 13767)
+++ branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Views/KnowledgeCenterViewBase.cs	(revision 13774)
@@ -88,9 +88,9 @@
 
     private void RegisterContentSuggestedInstancesEvents() {
-      Content.SuggestedInstances.CollectionReset += ContentOnSuggestedInstancesChanged;
-      Content.SuggestedInstances.ItemsAdded += ContentOnSuggestedInstancesChanged;
-      Content.SuggestedInstances.ItemsMoved += ContentOnSuggestedInstancesChanged;
-      Content.SuggestedInstances.ItemsRemoved += ContentOnSuggestedInstancesChanged;
-      Content.SuggestedInstances.ItemsReplaced += ContentOnSuggestedInstancesChanged;
+      Content.AlgorithmInstances.CollectionReset += ContentOnSuggestedInstancesChanged;
+      Content.AlgorithmInstances.ItemsAdded += ContentOnSuggestedInstancesChanged;
+      Content.AlgorithmInstances.ItemsMoved += ContentOnSuggestedInstancesChanged;
+      Content.AlgorithmInstances.ItemsRemoved += ContentOnSuggestedInstancesChanged;
+      Content.AlgorithmInstances.ItemsReplaced += ContentOnSuggestedInstancesChanged;
     }
 
@@ -139,9 +139,9 @@
 
     private void DeregisterContentSuggestedInstancesEvents() {
-      Content.SuggestedInstances.CollectionReset -= ContentOnSuggestedInstancesChanged;
-      Content.SuggestedInstances.ItemsAdded -= ContentOnSuggestedInstancesChanged;
-      Content.SuggestedInstances.ItemsMoved -= ContentOnSuggestedInstancesChanged;
-      Content.SuggestedInstances.ItemsRemoved -= ContentOnSuggestedInstancesChanged;
-      Content.SuggestedInstances.ItemsReplaced -= ContentOnSuggestedInstancesChanged;
+      Content.AlgorithmInstances.CollectionReset -= ContentOnSuggestedInstancesChanged;
+      Content.AlgorithmInstances.ItemsAdded -= ContentOnSuggestedInstancesChanged;
+      Content.AlgorithmInstances.ItemsMoved -= ContentOnSuggestedInstancesChanged;
+      Content.AlgorithmInstances.ItemsRemoved -= ContentOnSuggestedInstancesChanged;
+      Content.AlgorithmInstances.ItemsReplaced -= ContentOnSuggestedInstancesChanged;
     }
     #endregion
Index: branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Views/SolverView.Designer.cs
===================================================================
--- branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Views/SolverView.Designer.cs	(revision 13767)
+++ branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Views/SolverView.Designer.cs	(revision 13774)
@@ -45,19 +45,19 @@
     /// </summary>
     private void InitializeComponent() {
-      WeifenLuo.WinFormsUI.Docking.DockPanelSkin dockPanelSkin1 = new WeifenLuo.WinFormsUI.Docking.DockPanelSkin();
-      WeifenLuo.WinFormsUI.Docking.AutoHideStripSkin autoHideStripSkin1 = new WeifenLuo.WinFormsUI.Docking.AutoHideStripSkin();
-      WeifenLuo.WinFormsUI.Docking.DockPanelGradient dockPanelGradient1 = new WeifenLuo.WinFormsUI.Docking.DockPanelGradient();
-      WeifenLuo.WinFormsUI.Docking.TabGradient tabGradient1 = new WeifenLuo.WinFormsUI.Docking.TabGradient();
-      WeifenLuo.WinFormsUI.Docking.DockPaneStripSkin dockPaneStripSkin1 = new WeifenLuo.WinFormsUI.Docking.DockPaneStripSkin();
-      WeifenLuo.WinFormsUI.Docking.DockPaneStripGradient dockPaneStripGradient1 = new WeifenLuo.WinFormsUI.Docking.DockPaneStripGradient();
-      WeifenLuo.WinFormsUI.Docking.TabGradient tabGradient2 = new WeifenLuo.WinFormsUI.Docking.TabGradient();
-      WeifenLuo.WinFormsUI.Docking.DockPanelGradient dockPanelGradient2 = new WeifenLuo.WinFormsUI.Docking.DockPanelGradient();
-      WeifenLuo.WinFormsUI.Docking.TabGradient tabGradient3 = new WeifenLuo.WinFormsUI.Docking.TabGradient();
-      WeifenLuo.WinFormsUI.Docking.DockPaneStripToolWindowGradient dockPaneStripToolWindowGradient1 = new WeifenLuo.WinFormsUI.Docking.DockPaneStripToolWindowGradient();
-      WeifenLuo.WinFormsUI.Docking.TabGradient tabGradient4 = new WeifenLuo.WinFormsUI.Docking.TabGradient();
-      WeifenLuo.WinFormsUI.Docking.TabGradient tabGradient5 = new WeifenLuo.WinFormsUI.Docking.TabGradient();
-      WeifenLuo.WinFormsUI.Docking.DockPanelGradient dockPanelGradient3 = new WeifenLuo.WinFormsUI.Docking.DockPanelGradient();
-      WeifenLuo.WinFormsUI.Docking.TabGradient tabGradient6 = new WeifenLuo.WinFormsUI.Docking.TabGradient();
-      WeifenLuo.WinFormsUI.Docking.TabGradient tabGradient7 = new WeifenLuo.WinFormsUI.Docking.TabGradient();
+      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();
       this.minTargetView = new HeuristicLab.Data.Views.StringConvertibleValueView();
       this.maxEvaluationsView = new HeuristicLab.Data.Views.StringConvertibleValueView();
@@ -81,6 +81,11 @@
       this.seedingStrategyLabel = new System.Windows.Forms.Label();
       this.evaluationsLimitabel = new System.Windows.Forms.Label();
-      this.algorithmSuggestionLabel = 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();
@@ -89,4 +94,8 @@
       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();
       // 
@@ -115,6 +124,5 @@
       // algorithmCloneButton
       // 
-      this.algorithmCloneButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
-      this.algorithmCloneButton.Location = new System.Drawing.Point(823, 56);
+      this.algorithmCloneButton.Location = new System.Drawing.Point(123, 60);
       this.algorithmCloneButton.Name = "algorithmCloneButton";
       this.algorithmCloneButton.Size = new System.Drawing.Size(26, 23);
@@ -136,7 +144,4 @@
       // 
       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);
@@ -145,8 +150,9 @@
       this.solverTabControl.Controls.Add(this.parametersTabPage);
       this.solverTabControl.Controls.Add(this.operatorGraphTabPage);
-      this.solverTabControl.Location = new System.Drawing.Point(0, 84);
+      this.solverTabControl.Dock = System.Windows.Forms.DockStyle.Fill;
+      this.solverTabControl.Location = new System.Drawing.Point(3, 3);
       this.solverTabControl.Name = "solverTabControl";
       this.solverTabControl.SelectedIndex = 0;
-      this.solverTabControl.Size = new System.Drawing.Size(849, 480);
+      this.solverTabControl.Size = new System.Drawing.Size(556, 502);
       this.solverTabControl.TabIndex = 11;
       // 
@@ -158,5 +164,5 @@
       this.resultsTabPage.Name = "resultsTabPage";
       this.resultsTabPage.Padding = new System.Windows.Forms.Padding(3);
-      this.resultsTabPage.Size = new System.Drawing.Size(841, 454);
+      this.resultsTabPage.Size = new System.Drawing.Size(548, 476);
       this.resultsTabPage.TabIndex = 2;
       this.resultsTabPage.Text = "Results";
@@ -166,4 +172,6 @@
       // 
       this.showOnlyFinalResultCheckBox.AutoSize = true;
+      this.showOnlyFinalResultCheckBox.Checked = true;
+      this.showOnlyFinalResultCheckBox.CheckState = System.Windows.Forms.CheckState.Checked;
       this.showOnlyFinalResultCheckBox.Location = new System.Drawing.Point(6, 6);
       this.showOnlyFinalResultCheckBox.Name = "showOnlyFinalResultCheckBox";
@@ -181,51 +189,51 @@
       this.resultsDockPanel.Location = new System.Drawing.Point(3, 29);
       this.resultsDockPanel.Name = "resultsDockPanel";
-      this.resultsDockPanel.Size = new System.Drawing.Size(835, 422);
-      dockPanelGradient1.EndColor = System.Drawing.SystemColors.ControlLight;
-      dockPanelGradient1.StartColor = System.Drawing.SystemColors.ControlLight;
-      autoHideStripSkin1.DockStripGradient = dockPanelGradient1;
-      tabGradient1.EndColor = System.Drawing.SystemColors.Control;
-      tabGradient1.StartColor = System.Drawing.SystemColors.Control;
-      tabGradient1.TextColor = System.Drawing.SystemColors.ControlDarkDark;
-      autoHideStripSkin1.TabGradient = tabGradient1;
-      autoHideStripSkin1.TextFont = new System.Drawing.Font("Segoe UI", 9F);
-      dockPanelSkin1.AutoHideStripSkin = autoHideStripSkin1;
-      tabGradient2.EndColor = System.Drawing.SystemColors.ControlLightLight;
-      tabGradient2.StartColor = System.Drawing.SystemColors.ControlLightLight;
-      tabGradient2.TextColor = System.Drawing.SystemColors.ControlText;
-      dockPaneStripGradient1.ActiveTabGradient = tabGradient2;
-      dockPanelGradient2.EndColor = System.Drawing.SystemColors.Control;
-      dockPanelGradient2.StartColor = System.Drawing.SystemColors.Control;
-      dockPaneStripGradient1.DockStripGradient = dockPanelGradient2;
-      tabGradient3.EndColor = System.Drawing.SystemColors.ControlLight;
-      tabGradient3.StartColor = System.Drawing.SystemColors.ControlLight;
-      tabGradient3.TextColor = System.Drawing.SystemColors.ControlText;
-      dockPaneStripGradient1.InactiveTabGradient = tabGradient3;
-      dockPaneStripSkin1.DocumentGradient = dockPaneStripGradient1;
-      dockPaneStripSkin1.TextFont = new System.Drawing.Font("Segoe UI", 9F);
-      tabGradient4.EndColor = System.Drawing.SystemColors.ActiveCaption;
-      tabGradient4.LinearGradientMode = System.Drawing.Drawing2D.LinearGradientMode.Vertical;
-      tabGradient4.StartColor = System.Drawing.SystemColors.GradientActiveCaption;
-      tabGradient4.TextColor = System.Drawing.SystemColors.ActiveCaptionText;
-      dockPaneStripToolWindowGradient1.ActiveCaptionGradient = tabGradient4;
-      tabGradient5.EndColor = System.Drawing.SystemColors.Control;
-      tabGradient5.StartColor = System.Drawing.SystemColors.Control;
-      tabGradient5.TextColor = System.Drawing.SystemColors.ControlText;
-      dockPaneStripToolWindowGradient1.ActiveTabGradient = tabGradient5;
-      dockPanelGradient3.EndColor = System.Drawing.SystemColors.ControlLight;
-      dockPanelGradient3.StartColor = System.Drawing.SystemColors.ControlLight;
-      dockPaneStripToolWindowGradient1.DockStripGradient = dockPanelGradient3;
-      tabGradient6.EndColor = System.Drawing.SystemColors.InactiveCaption;
-      tabGradient6.LinearGradientMode = System.Drawing.Drawing2D.LinearGradientMode.Vertical;
-      tabGradient6.StartColor = System.Drawing.SystemColors.GradientInactiveCaption;
-      tabGradient6.TextColor = System.Drawing.SystemColors.InactiveCaptionText;
-      dockPaneStripToolWindowGradient1.InactiveCaptionGradient = tabGradient6;
-      tabGradient7.EndColor = System.Drawing.Color.Transparent;
-      tabGradient7.StartColor = System.Drawing.Color.Transparent;
-      tabGradient7.TextColor = System.Drawing.SystemColors.ControlDarkDark;
-      dockPaneStripToolWindowGradient1.InactiveTabGradient = tabGradient7;
-      dockPaneStripSkin1.ToolWindowGradient = dockPaneStripToolWindowGradient1;
-      dockPanelSkin1.DockPaneStripSkin = dockPaneStripSkin1;
-      this.resultsDockPanel.Skin = dockPanelSkin1;
+      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.TabIndex = 0;
       // 
@@ -236,5 +244,5 @@
       this.runsTabPage.Name = "runsTabPage";
       this.runsTabPage.Padding = new System.Windows.Forms.Padding(3);
-      this.runsTabPage.Size = new System.Drawing.Size(841, 454);
+      this.runsTabPage.Size = new System.Drawing.Size(548, 476);
       this.runsTabPage.TabIndex = 4;
       this.runsTabPage.Text = "Runs";
@@ -249,5 +257,5 @@
       this.runsView.Name = "runsView";
       this.runsView.ReadOnly = false;
-      this.runsView.Size = new System.Drawing.Size(835, 448);
+      this.runsView.Size = new System.Drawing.Size(542, 470);
       this.runsView.TabIndex = 0;
       // 
@@ -258,5 +266,5 @@
       this.seededRunsTabPage.Name = "seededRunsTabPage";
       this.seededRunsTabPage.Padding = new System.Windows.Forms.Padding(3);
-      this.seededRunsTabPage.Size = new System.Drawing.Size(841, 454);
+      this.seededRunsTabPage.Size = new System.Drawing.Size(548, 476);
       this.seededRunsTabPage.TabIndex = 5;
       this.seededRunsTabPage.Text = "Seeded Runs";
@@ -271,5 +279,5 @@
       this.seededRunsView.Name = "seededRunsView";
       this.seededRunsView.ReadOnly = false;
-      this.seededRunsView.Size = new System.Drawing.Size(835, 448);
+      this.seededRunsView.Size = new System.Drawing.Size(542, 470);
       this.seededRunsView.TabIndex = 1;
       // 
@@ -279,5 +287,5 @@
       this.solutionSeedingTabPage.Name = "solutionSeedingTabPage";
       this.solutionSeedingTabPage.Padding = new System.Windows.Forms.Padding(3);
-      this.solutionSeedingTabPage.Size = new System.Drawing.Size(841, 454);
+      this.solutionSeedingTabPage.Size = new System.Drawing.Size(548, 476);
       this.solutionSeedingTabPage.TabIndex = 1;
       this.solutionSeedingTabPage.Text = "Seeding Pool";
@@ -290,5 +298,5 @@
       this.parametersTabPage.Name = "parametersTabPage";
       this.parametersTabPage.Padding = new System.Windows.Forms.Padding(3);
-      this.parametersTabPage.Size = new System.Drawing.Size(841, 454);
+      this.parametersTabPage.Size = new System.Drawing.Size(548, 476);
       this.parametersTabPage.TabIndex = 0;
       this.parametersTabPage.Text = "Parameters";
@@ -305,5 +313,5 @@
       this.solverParametersView.ReadOnly = true;
       this.solverParametersView.ShowDetails = true;
-      this.solverParametersView.Size = new System.Drawing.Size(835, 448);
+      this.solverParametersView.Size = new System.Drawing.Size(542, 470);
       this.solverParametersView.TabIndex = 0;
       // 
@@ -314,5 +322,5 @@
       this.operatorGraphTabPage.Name = "operatorGraphTabPage";
       this.operatorGraphTabPage.Padding = new System.Windows.Forms.Padding(3);
-      this.operatorGraphTabPage.Size = new System.Drawing.Size(841, 454);
+      this.operatorGraphTabPage.Size = new System.Drawing.Size(548, 476);
       this.operatorGraphTabPage.TabIndex = 3;
       this.operatorGraphTabPage.Text = "Operator Graph";
@@ -328,5 +336,5 @@
       this.operatorGraphViewHost.Name = "operatorGraphViewHost";
       this.operatorGraphViewHost.ReadOnly = true;
-      this.operatorGraphViewHost.Size = new System.Drawing.Size(835, 448);
+      this.operatorGraphViewHost.Size = new System.Drawing.Size(542, 470);
       this.operatorGraphViewHost.TabIndex = 0;
       this.operatorGraphViewHost.ViewsLabelVisible = true;
@@ -335,6 +343,5 @@
       // algorithmStartButton
       // 
-      this.algorithmStartButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
-      this.algorithmStartButton.Location = new System.Drawing.Point(791, 55);
+      this.algorithmStartButton.Location = new System.Drawing.Point(91, 60);
       this.algorithmStartButton.Name = "algorithmStartButton";
       this.algorithmStartButton.Size = new System.Drawing.Size(26, 23);
@@ -371,12 +378,12 @@
       this.evaluationsLimitabel.Text = "Budget (FE):";
       // 
-      // algorithmSuggestionLabel
-      // 
-      this.algorithmSuggestionLabel.AutoSize = true;
-      this.algorithmSuggestionLabel.Location = new System.Drawing.Point(3, 59);
-      this.algorithmSuggestionLabel.Name = "algorithmSuggestionLabel";
-      this.algorithmSuggestionLabel.Size = new System.Drawing.Size(99, 13);
-      this.algorithmSuggestionLabel.TabIndex = 9;
-      this.algorithmSuggestionLabel.Text = "Suggested Solvers:";
+      // 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
@@ -386,25 +393,97 @@
       this.suggestedInstancesComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
       this.suggestedInstancesComboBox.FormattingEnabled = true;
-      this.suggestedInstancesComboBox.Location = new System.Drawing.Point(108, 56);
+      this.suggestedInstancesComboBox.Location = new System.Drawing.Point(91, 33);
       this.suggestedInstancesComboBox.Name = "suggestedInstancesComboBox";
-      this.suggestedInstancesComboBox.Size = new System.Drawing.Size(677, 21);
+      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.minTargetView);
       this.Controls.Add(this.maxEvaluationsView);
-      this.Controls.Add(this.algorithmCloneButton);
       this.Controls.Add(this.seedingStrategyPanel);
-      this.Controls.Add(this.solverTabControl);
-      this.Controls.Add(this.algorithmStartButton);
       this.Controls.Add(this.minimumTargetLabel);
       this.Controls.Add(this.seedingStrategyLabel);
       this.Controls.Add(this.evaluationsLimitabel);
-      this.Controls.Add(this.algorithmSuggestionLabel);
-      this.Controls.Add(this.suggestedInstancesComboBox);
       this.Name = "SolverView";
       this.Size = new System.Drawing.Size(849, 564);
@@ -416,4 +495,9 @@
       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();
@@ -434,5 +518,5 @@
     private System.Windows.Forms.Label seedingStrategyLabel;
     private System.Windows.Forms.Label evaluationsLimitabel;
-    private System.Windows.Forms.Label algorithmSuggestionLabel;
+    private System.Windows.Forms.Label recommenderLabel;
     private System.Windows.Forms.ComboBox suggestedInstancesComboBox;
     private System.Windows.Forms.Button algorithmCloneButton;
@@ -446,4 +530,9 @@
     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 13767)
+++ branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem/3.3/Views/SolverView.cs	(revision 13774)
@@ -44,4 +44,6 @@
       algorithmCloneButton.Text = string.Empty;
       algorithmCloneButton.Image = VSImageLibrary.Clone;
+      recommendRefreshButton.Text = string.Empty;
+      recommendRefreshButton.Image = VSImageLibrary.Refresh;
       seedingStrategyView = new EnumValueView<SeedingStrategyTypes>() {
         Dock = DockStyle.Fill
@@ -66,4 +68,5 @@
           seedingStrategyView.Content = null;
           seedingSolutionsView.Content = null;
+          recommenderViewHost.Content = null;
         } else {
           maxEvaluationsView.Content = Content.MaximumEvaluations;
@@ -73,7 +76,9 @@
           seedingStrategyView.Content = Content.SeedingStrategy;
           seedingSolutionsView.Content = Content.SolutionSeedingPool;
+          recommenderViewHost.Content = Content.AlgorithmInstanceRecommender;
         }
       } finally { SuppressEvents = false; }
       UpdateSuggestedInstancesCombobox();
+      UpdateRecommenderCombobox();
     }
 
@@ -103,12 +108,33 @@
       if (Content == null) return;
 
-      for (var i = 0; i < Content.SuggestedInstances.Count; i++) {
-        suggestedInstancesComboBox.Items.Add(Content.SuggestedInstances[i]);
-        if (prevSelection == null || Content.SuggestedInstances[i].Name == prevSelection.Name)
+      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;
+      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;
     }
 
@@ -120,5 +146,5 @@
     private void AlgorithmCloneButtonOnClick(object sender, EventArgs e) {
       if (suggestedInstancesComboBox.SelectedIndex >= 0)
-        MainForm.ShowContent((IAlgorithm)Content.SuggestedInstances[suggestedInstancesComboBox.SelectedIndex].Clone());
+        MainForm.ShowContent((IAlgorithm)Content.AlgorithmInstances[suggestedInstancesComboBox.SelectedIndex].Clone());
     }
 
@@ -126,5 +152,5 @@
       if (InvokeRequired) { Invoke((Action<object, EventArgs>)SuggestedInstancesComboBoxOnSelectedIndexChanged, sender, e); return; }
       if (suggestedInstancesComboBox.SelectedIndex >= 0) {
-        var alg = Content.SuggestedInstances[suggestedInstancesComboBox.SelectedIndex];
+        var alg = Content.AlgorithmInstances[suggestedInstancesComboBox.SelectedIndex];
         solverParametersView.Content = alg.Parameters;
         var engineAlg = alg as EngineAlgorithm;
@@ -137,4 +163,16 @@
       SetEnabledStateOfControls();
     }
+
+    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();
+    }
+
+    private void button1_Click(object sender, EventArgs e) {
+      Content.UpdateSuggestions();
+    }
   }
 }
