Index: /branches/PerformanceComparison/HeuristicLab.Analysis/3.3/HeuristicLab.Analysis-3.3.csproj
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.Analysis/3.3/HeuristicLab.Analysis-3.3.csproj	(revision 12803)
+++ /branches/PerformanceComparison/HeuristicLab.Analysis/3.3/HeuristicLab.Analysis-3.3.csproj	(revision 12804)
@@ -199,4 +199,5 @@
     <Compile Include="MultiObjective\RankBasedParetoFrontAnalyzer.cs" />
     <Compile Include="MultiObjective\ParetoFrontAnalyzer.cs" />
+    <Compile Include="Optimizers\IRRestarter.cs" />
     <Compile Include="Plugin.cs" />
     <Compile Include="PopulationSimilarityAnalysis\PopulationDiversityAnalyzer.cs" />
Index: anches/PerformanceComparison/HeuristicLab.Analysis/3.3/Optimizers/IRRRun.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.Analysis/3.3/Optimizers/IRRRun.cs	(revision 12803)
+++ 	(revision )
@@ -1,560 +1,0 @@
-﻿#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2012 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 System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Drawing;
-using System.Linq;
-using HeuristicLab.Common;
-using HeuristicLab.Common.Resources;
-using HeuristicLab.Core;
-using HeuristicLab.Data;
-using HeuristicLab.Optimization;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-
-namespace HeuristicLab.Analysis {
-  public enum TerminationCriterium { OnlyByTime, OnlyByEvaluations, OnlyByTarget, ByTargetAndTime, ByTargetAndEvaluations, WhicheverHitsFirst, WhicheverHitsLast }
-  /// <summary>
-  /// A run in which an algorithm is executed for a certain maximum time only.
-  /// </summary>
-  [Item("Independent Random Restart Run", "A run in which an optimizer is repeated until either a certain target value is reached or a maximum budget is exceeded.")]
-  [Creatable(CreatableAttribute.Categories.TestingAndAnalysis, Priority = 117)]
-  [StorableClass]
-  public sealed class IndepdentRandomRestartRun : NamedItem, IOptimizer, IStorableContent, INotifyPropertyChanged {
-    public string Filename { get; set; }
-
-    #region ItemImage
-    public static new Image StaticItemImage {
-      get { return VSImageLibrary.Event; }
-    }
-    public override Image ItemImage {
-      get { return (Algorithm != null) ? Algorithm.ItemImage : VSImageLibrary.ExecutableStopped; }
-    }
-    #endregion
-
-    [Storable]
-    private TerminationCriterium terminationCriterium;
-    public TerminationCriterium TerminationCriterium {
-      get { return terminationCriterium; }
-      set {
-        if (terminationCriterium == value) return;
-        terminationCriterium = value;
-        OnPropertyChanged("TerminationCriterium");
-      }
-    }
-
-    [Storable]
-    private TimeSpan maximumExecutionTime;
-    public TimeSpan MaximumExecutionTime {
-      get { return maximumExecutionTime; }
-      set {
-        if (maximumExecutionTime == value) return;
-        maximumExecutionTime = value;
-        OnPropertyChanged("MaximumExecutionTime");
-      }
-    }
-
-    [Storable]
-    private int maximumEvaluations;
-    public int MaximumEvaluations {
-      get { return maximumEvaluations; }
-      set {
-        if (maximumEvaluations == value) return;
-        maximumEvaluations = value;
-        OnPropertyChanged("MaximumEvaluations");
-      }
-    }
-
-    [Storable]
-    private double targetValue;
-    public double TargetValue {
-      get { return targetValue; }
-      set {
-        if (targetValue == value) return;
-        targetValue = value;
-        OnPropertyChanged("TargetValue");
-      }
-    }
-
-    [Storable]
-    private bool maximization;
-    public bool Maximization {
-      get { return maximization; }
-      private set {
-        if (maximization == value) return;
-        maximization = value;
-        OnPropertyChanged("Maximization");
-      }
-    }
-
-    [Storable]
-    private double moveCostPerSolution;
-    public double MoveCostPerSolution {
-      get { return moveCostPerSolution; }
-      set {
-        if (moveCostPerSolution == value) return;
-        moveCostPerSolution = value;
-        OnPropertyChanged("MoveCostPerSolution");
-      }
-    }
-
-
-    public ExecutionState ExecutionState {
-      get { return (Algorithm != null) ? Algorithm.ExecutionState : ExecutionState.Stopped; }
-    }
-
-    private TimeSpan lastAlgorithmExecutionTime;
-    [Storable]
-    private TimeSpan executionTime;
-    public TimeSpan ExecutionTime {
-      get { return executionTime; }
-      set {
-        if (executionTime == value) return;
-        executionTime = value;
-        OnPropertyChanged("ExecutionTime");
-        OnExecutionTimeChanged();
-      }
-    }
-
-    private int lastAlgorithmEvaluatedSolutions;
-    private int lastAlgorithmEvaluatedMoves;
-    [Storable]
-    private double evaluations;
-    public double Evaluations {
-      get { return evaluations; }
-      set {
-        if (evaluations == value) return;
-        evaluations = value;
-        OnPropertyChanged("Evaluations");
-      }
-    }
-
-    [Storable]
-    private double bestSoFar;
-    public double BestSoFar {
-      get { return bestSoFar; }
-      set {
-        if (bestSoFar == value) return;
-        bestSoFar = value;
-        OnPropertyChanged("BestSoFar");
-      }
-    }
-
-    [Storable]
-    private IRun currentRun;
-    public IRun CurrentRun {
-      get { return currentRun; }
-      private set {
-        if (currentRun == value) return;
-        currentRun = value;
-        OnPropertyChanged("CurrentRun");
-      }
-    }
-
-    [Storable]
-    private IAlgorithm algorithm;
-    public IAlgorithm Algorithm {
-      get { return algorithm; }
-      set {
-        if (algorithm == value) return;
-        if (algorithm != null) DeregisterAlgorithmEvents();
-        algorithm = value;
-        if (algorithm != null) {
-          RegisterAlgorithmEvents();
-        }
-        OnPropertyChanged("Algorithm");
-        Prepare();
-      }
-    }
-
-    [Storable]
-    private RunCollection runs;
-    public RunCollection Runs {
-      get { return runs; }
-      private set {
-        if (value == null) throw new ArgumentNullException();
-        if (runs == value) return;
-        runs = value;
-        OnPropertyChanged("Runs");
-      }
-    }
-
-    public IEnumerable<IOptimizer> NestedOptimizers {
-      get {
-        if (Algorithm == null) yield break;
-        yield return Algorithm;
-        foreach (var opt in Algorithm.NestedOptimizers)
-          yield return opt;
-      }
-    }
-
-    private bool IsFinished {
-      get {
-        var timeHit = ExecutionTime >= MaximumExecutionTime;
-        var evalHit = Evaluations >= MaximumEvaluations;
-        var targetHit = (Maximization && BestSoFar >= TargetValue || !Maximization && BestSoFar <= TargetValue);
-
-        return timeHit && evalHit && targetHit
-          || timeHit && (TerminationCriterium == TerminationCriterium.OnlyByTime
-                      || TerminationCriterium == TerminationCriterium.ByTargetAndTime
-                      || TerminationCriterium == TerminationCriterium.WhicheverHitsFirst)
-          || evalHit && (TerminationCriterium == TerminationCriterium.OnlyByEvaluations
-                      || TerminationCriterium == TerminationCriterium.ByTargetAndEvaluations
-                      || TerminationCriterium == TerminationCriterium.WhicheverHitsFirst)
-          || targetHit && (TerminationCriterium == TerminationCriterium.OnlyByTarget
-                        || TerminationCriterium == TerminationCriterium.WhicheverHitsFirst
-                        || TerminationCriterium == TerminationCriterium.ByTargetAndTime
-                        || TerminationCriterium == TerminationCriterium.ByTargetAndEvaluations);
-      }
-    }
-
-    [StorableConstructor]
-    private IndepdentRandomRestartRun(bool deserializing) : base(deserializing) { }
-    private IndepdentRandomRestartRun(IndepdentRandomRestartRun original, Cloner cloner)
-      : base(original, cloner) {
-      terminationCriterium = original.terminationCriterium;
-      maximumExecutionTime = original.maximumExecutionTime;
-      maximumEvaluations = original.maximumEvaluations;
-      targetValue = original.targetValue;
-      executionTime = original.executionTime;
-      evaluations = original.evaluations;
-      bestSoFar = original.bestSoFar;
-      lastAlgorithmExecutionTime = original.lastAlgorithmExecutionTime;
-      lastAlgorithmEvaluatedSolutions = original.lastAlgorithmEvaluatedSolutions;
-      lastAlgorithmEvaluatedMoves = original.lastAlgorithmEvaluatedMoves;
-
-      algorithm = cloner.Clone(original.algorithm);
-      runs = cloner.Clone(original.runs);
-
-      Initialize();
-    }
-    public IndepdentRandomRestartRun()
-      : base() {
-      name = ItemName;
-      description = ItemDescription;
-      terminationCriterium = TerminationCriterium.OnlyByEvaluations;
-      maximumExecutionTime = TimeSpan.FromMinutes(1);
-      maximumEvaluations = 10000000; // 10 mio
-      targetValue = 0;
-      executionTime = TimeSpan.Zero;
-      evaluations = 0;
-      bestSoFar = double.NaN;
-      lastAlgorithmExecutionTime = TimeSpan.Zero;
-      lastAlgorithmEvaluatedSolutions = 0;
-      lastAlgorithmEvaluatedMoves = 0;
-
-      Runs = new RunCollection { OptimizerName = Name };
-      Initialize();
-    }
-    public IndepdentRandomRestartRun(string name)
-      : base(name) {
-      description = ItemDescription;
-      terminationCriterium = TerminationCriterium.OnlyByEvaluations;
-      maximumExecutionTime = TimeSpan.FromMinutes(1);
-      maximumEvaluations = 10000000; // 10 mio
-      targetValue = 0;
-      executionTime = TimeSpan.Zero;
-      evaluations = 0;
-      bestSoFar = double.NaN;
-      lastAlgorithmExecutionTime = TimeSpan.Zero;
-      lastAlgorithmEvaluatedSolutions = 0;
-      lastAlgorithmEvaluatedMoves = 0;
-
-      Runs = new RunCollection { OptimizerName = Name };
-      Initialize();
-    }
-    public IndepdentRandomRestartRun(string name, string description)
-      : base(name, description) {
-      terminationCriterium = TerminationCriterium.OnlyByEvaluations;
-      maximumExecutionTime = TimeSpan.FromMinutes(1);
-      maximumEvaluations = 10000000; // 10 mio
-      targetValue = 0;
-      executionTime = TimeSpan.Zero;
-      evaluations = 0;
-      bestSoFar = double.NaN;
-      lastAlgorithmExecutionTime = TimeSpan.Zero;
-      lastAlgorithmEvaluatedSolutions = 0;
-      lastAlgorithmEvaluatedMoves = 0;
-
-      Runs = new RunCollection { OptimizerName = Name };
-      Initialize();
-    }
-
-    public override IDeepCloneable Clone(Cloner cloner) {
-      if (ExecutionState == ExecutionState.Started) throw new InvalidOperationException(string.Format("Clone not allowed in execution state \"{0}\".", ExecutionState));
-      return new IndepdentRandomRestartRun(this, cloner);
-    }
-
-    [StorableHook(HookType.AfterDeserialization)]
-    private void AfterDeserialization() {
-      Initialize();
-    }
-
-    private void Initialize() {
-      if (algorithm != null) RegisterAlgorithmEvents();
-    }
-
-    public void Prepare() {
-      Prepare(false);
-    }
-    public void Prepare(bool clearRuns) {
-      executionTime = TimeSpan.Zero;
-      evaluations = 0;
-      lastAlgorithmExecutionTime = TimeSpan.Zero;
-      lastAlgorithmEvaluatedSolutions = 0;
-
-      Algorithm.Prepare(clearRuns);
-    }
-    public void Start() {
-      if (ExecutionState == ExecutionState.Prepared) {
-        currentRun = new Run(Algorithm) {
-          Name = Algorithm.Name + " IRRRun" + Runs.Count
-        };
-      }
-      Algorithm.Start();
-    }
-    public void Pause() {
-      Algorithm.Pause();
-    }
-    public void Stop() {
-      Algorithm.Stop();
-    }
-
-    #region Events
-    protected override void OnNameChanged() {
-      base.OnNameChanged();
-      runs.OptimizerName = Name;
-    }
-
-    public event PropertyChangedEventHandler PropertyChanged;
-    private void OnPropertyChanged(string property) {
-      var handler = PropertyChanged;
-      if (handler != null) handler(this, new PropertyChangedEventArgs(property));
-    }
-
-    #region IExecutable Events
-    public event EventHandler ExecutionStateChanged;
-    private void OnExecutionStateChanged() {
-      var handler = ExecutionStateChanged;
-      if (handler != null) handler(this, EventArgs.Empty);
-    }
-    public event EventHandler ExecutionTimeChanged;
-    private void OnExecutionTimeChanged() {
-      var handler = ExecutionTimeChanged;
-      if (handler != null) handler(this, EventArgs.Empty);
-    }
-    public event EventHandler Prepared;
-    private void OnPrepared() {
-      var handler = Prepared;
-      if (handler != null) handler(this, EventArgs.Empty);
-    }
-    public event EventHandler Started;
-    private void OnStarted() {
-      var handler = Started;
-      if (handler != null) handler(this, EventArgs.Empty);
-    }
-    public event EventHandler Paused;
-    private void OnPaused() {
-      var handler = Paused;
-      if (handler != null) handler(this, EventArgs.Empty);
-    }
-    public event EventHandler Stopped;
-    private void OnStopped() {
-      var handler = Stopped;
-      if (handler != null) handler(this, EventArgs.Empty);
-    }
-    public event EventHandler<EventArgs<Exception>> ExceptionOccurred;
-    private void OnExceptionOccurred(Exception exception) {
-      var handler = ExceptionOccurred;
-      if (handler != null) handler(this, new EventArgs<Exception>(exception));
-    }
-    #endregion
-
-    #region Algorithm Events
-    private void RegisterAlgorithmEvents() {
-      algorithm.ExceptionOccurred += Algorithm_ExceptionOccurred;
-      algorithm.ExecutionTimeChanged += Algorithm_ExecutionTimeChanged;
-      algorithm.ExecutionStateChanged += Algorithm_ExecutionStateChanged;
-      algorithm.Paused += Algorithm_Paused;
-      algorithm.Prepared += Algorithm_Prepared;
-      algorithm.Started += Algorithm_Started;
-      algorithm.Stopped += Algorithm_Stopped;
-      algorithm.ProblemChanged += Algorithm_ProblemChanged;
-    }
-    private void DeregisterAlgorithmEvents() {
-      algorithm.ExceptionOccurred -= Algorithm_ExceptionOccurred;
-      algorithm.ExecutionTimeChanged -= Algorithm_ExecutionTimeChanged;
-      algorithm.ExecutionStateChanged -= Algorithm_ExecutionStateChanged;
-      algorithm.Paused -= Algorithm_Paused;
-      algorithm.Prepared -= Algorithm_Prepared;
-      algorithm.Started -= Algorithm_Started;
-      algorithm.Stopped -= Algorithm_Stopped;
-      algorithm.ProblemChanged -= Algorithm_ProblemChanged;
-    }
-    private void Algorithm_ExceptionOccurred(object sender, EventArgs<Exception> e) {
-      OnExceptionOccurred(e.Value);
-    }
-    private void Algorithm_ExecutionTimeChanged(object sender, EventArgs e) {
-      ExecutionTime += Algorithm.ExecutionTime - lastAlgorithmExecutionTime;
-      lastAlgorithmExecutionTime = Algorithm.ExecutionTime;
-
-      UpdateAlgorithmResults();
-
-      if (IsFinished) {
-        Algorithm.Stop();
-      }
-      OnExecutionTimeChanged();
-    }
-
-    private void Algorithm_ExecutionStateChanged(object sender, EventArgs e) {
-      OnExecutionStateChanged();
-    }
-    private void Algorithm_Paused(object sender, EventArgs e) {
-      ExecutionTime += Algorithm.ExecutionTime - lastAlgorithmExecutionTime;
-      lastAlgorithmExecutionTime = Algorithm.ExecutionTime;
-
-      UpdateAlgorithmResults();
-      OnPaused();
-    }
-    private void Algorithm_Prepared(object sender, EventArgs e) {
-      OnPrepared();
-    }
-    private void Algorithm_Started(object sender, EventArgs e) {
-      OnStarted();
-    }
-    private void Algorithm_Stopped(object sender, EventArgs e) {
-      ExecutionTime += Algorithm.ExecutionTime - lastAlgorithmExecutionTime;
-      lastAlgorithmExecutionTime = Algorithm.ExecutionTime;
-
-      var bestQuality = UpdateAlgorithmResults();
-
-      foreach (var result in Algorithm.Results) {
-        if (result.Name == "QualityPerClock") {
-          if (!currentRun.Results.ContainsKey(result.Name))
-            currentRun.Results.Add(result.Name, (IItem)result.Value.Clone());
-          else {
-            var dt = (IndexedDataTable<double>)currentRun.Results[result.Name];
-            var execTime = ((TimeSpanValue)currentRun.Results["ExecutionTime"]).Value.TotalSeconds;
-            var best = dt.Rows.First().Values.Last().Item2;
-            var resultDt = (IndexedDataTable<double>)result.Value;
-            foreach (var tupl in resultDt.Rows.First().Values) {
-              if (Maximization && tupl.Item2 > best || !Maximization && tupl.Item2 < best) {
-                dt.Rows.First().Values.Add(Tuple.Create(execTime + tupl.Item1, tupl.Item2));
-                best = tupl.Item2;
-              }
-            }
-          }
-        } else if (result.Name == "QualityPerEvaluations") {
-          if (!currentRun.Results.ContainsKey(result.Name))
-            currentRun.Results.Add(result.Name, (IItem)result.Value.Clone());
-          else {
-            var dt = (IndexedDataTable<double>)currentRun.Results[result.Name];
-            var evalSols = ((DoubleValue)currentRun.Results["EvaluatedSolutions"]).Value;
-            var evalMoves = ((DoubleValue)currentRun.Results["EvaluatedMoves"]).Value;
-            var best = dt.Rows.First().Values.Last().Item2;
-            var resultDt = (IndexedDataTable<double>)result.Value;
-            foreach (var tupl in resultDt.Rows.First().Values) {
-              if (Maximization && tupl.Item2 > best || !Maximization && tupl.Item2 < best) {
-                dt.Rows.First().Values.Add(Tuple.Create(evalSols + moveCostPerSolution * evalMoves + tupl.Item1, tupl.Item2));
-                best = tupl.Item2;
-              }
-            }
-          }
-        } else if (result.Name == "EvaluatedSolutions") {
-          currentRun.Results.Add(result.Name, (IItem)result.Value.Clone());
-        } else if (result.Name == "EvaluatedMoves") {
-          currentRun.Results.Add(result.Name, (IItem)result.Value.Clone());
-        } else if (result.Name == "ExecutionTime") {
-          currentRun.Results.Add(result.Name, (IItem)result.Value.Clone());
-        } else if (result.Name == "BestQuality") {
-          currentRun.Results.Add(result.Name, (IItem)result.Value.Clone());
-        } else if (result.Name.ToLower().EndsWith("solution") && BestSoFar == bestQuality) {
-          currentRun.Results.Add(result.Name, (IItem)result.Value.Clone());
-        }
-      }
-      foreach (var result in Algorithm.Results) {
-        if (result.Name == "QualityPerClock") {
-
-        } else if (result.Name == "QualityPerEvaluations") {
-        } else if (result.Name == "EvaluatedSolutions") {
-          currentRun.Results.Add(result.Name, (IItem)result.Value.Clone());
-        } else if (result.Name == "EvaluatedMoves") {
-          currentRun.Results.Add(result.Name, (IItem)result.Value.Clone());
-        } else if (result.Name == "ExecutionTime") {
-          currentRun.Results.Add(result.Name, (IItem)result.Value.Clone());
-        } else if (result.Name == "BestQuality") {
-          currentRun.Results.Add(result.Name, (IItem)result.Value.Clone());
-        } else if (result.Name.ToLower().EndsWith("solution") && BestSoFar == bestQuality) {
-          currentRun.Results.Add(result.Name, (IItem)result.Value.Clone());
-        }
-      }
-
-
-      if (IsFinished) {
-
-      }
-
-      // TODO
-      var cloner = new Cloner();
-      var algRun = cloner.Clone(Algorithm.Runs.Last());
-      Runs.Add(algRun);
-      Algorithm.Runs.Clear();
-      OnStopped();
-    }
-
-    private double UpdateAlgorithmResults() {
-      IResult evaluationsResult;
-      if (Algorithm.Results.TryGetValue("EvaluatedSolutions", out evaluationsResult)) {
-        var evals = ((IntValue)evaluationsResult.Value).Value;
-        Evaluations += evals - lastAlgorithmEvaluatedSolutions;
-        lastAlgorithmEvaluatedSolutions = evals;
-      }
-      if (Algorithm.Results.TryGetValue("EvaluatedMoves", out evaluationsResult)) {
-        var evals = ((IntValue)evaluationsResult.Value).Value;
-        Evaluations += moveCostPerSolution * (evals - lastAlgorithmEvaluatedMoves);
-        lastAlgorithmEvaluatedMoves = evals;
-      }
-      if (Algorithm.Results.TryGetValue("BestQuality", out evaluationsResult)) {
-        var bestQuality = ((DoubleValue)evaluationsResult).Value;
-        if (double.IsNaN(BestSoFar)
-            || Maximization && bestQuality > BestSoFar
-            || !Maximization && bestQuality < BestSoFar)
-          BestSoFar = bestQuality;
-        return bestQuality;
-      }
-      return double.NaN;
-    }
-
-    private void Algorithm_ProblemChanged(object sender, EventArgs e) {
-      var soProblem = Algorithm.Problem as ISingleObjectiveHeuristicOptimizationProblem;
-      if (soProblem == null) return;
-      var maxParam = soProblem.MaximizationParameter as IValueParameter<BoolValue>;
-      if (maxParam != null)
-        Maximization = maxParam.Value.Value;
-      var bkParam = soProblem.BestKnownQualityParameter as IValueParameter<DoubleValue>;
-      if (bkParam != null && bkParam.Value != null)
-        TargetValue = bkParam.Value.Value;
-    }
-    #endregion
-    #endregion
-  }
-}
Index: /branches/PerformanceComparison/HeuristicLab.Analysis/3.3/Optimizers/IRRestarter.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.Analysis/3.3/Optimizers/IRRestarter.cs	(revision 12804)
+++ /branches/PerformanceComparison/HeuristicLab.Analysis/3.3/Optimizers/IRRestarter.cs	(revision 12804)
@@ -0,0 +1,673 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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 System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Drawing;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Common.Resources;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Analysis {
+  public enum TerminationCriterium { OnlyByTime, OnlyByEvaluations, OnlyByTarget, ByTargetAndTime, ByTargetAndEvaluations, WhicheverHitsFirst, WhicheverHitsLast }
+  /// <summary>
+  /// A run in which an algorithm is executed for a certain maximum time only.
+  /// </summary>
+  [Item("Independent Random Restarter", "An optimizer that repeats an algorithm until either a certain target value is reached or a maximum budget is exceeded.")]
+  [Creatable(CreatableAttribute.Categories.TestingAndAnalysis, Priority = 117)]
+  [StorableClass]
+  public sealed class IndepdentRandomRestarter : NamedItem, IOptimizer, IStorableContent, INotifyPropertyChanged {
+    private const string ExecutionTimeResultName = "Execution Time";
+    private const string BestQualityResultName = "BestQuality";
+
+    public string Filename { get; set; }
+
+    #region ItemImage
+    public static new Image StaticItemImage {
+      get { return VSImageLibrary.Event; }
+    }
+    public override Image ItemImage {
+      get { return (Algorithm != null) ? Algorithm.ItemImage : VSImageLibrary.ExecutableStopped; }
+    }
+    #endregion
+
+    [Storable]
+    private TerminationCriterium terminationCriterium;
+    public TerminationCriterium TerminationCriterium {
+      get { return terminationCriterium; }
+      set {
+        if (terminationCriterium == value) return;
+        terminationCriterium = value;
+        OnPropertyChanged("TerminationCriterium");
+      }
+    }
+
+    [Storable]
+    private TimeSpan maximumExecutionTime;
+    public TimeSpan MaximumExecutionTime {
+      get { return maximumExecutionTime; }
+      set {
+        if (maximumExecutionTime == value) return;
+        maximumExecutionTime = value;
+        OnPropertyChanged("MaximumExecutionTime");
+      }
+    }
+
+    [Storable]
+    private int maximumEvaluations;
+    public int MaximumEvaluations {
+      get { return maximumEvaluations; }
+      set {
+        if (maximumEvaluations == value) return;
+        maximumEvaluations = value;
+        OnPropertyChanged("MaximumEvaluations");
+      }
+    }
+
+    [Storable]
+    private double targetValue;
+    public double TargetValue {
+      get { return targetValue; }
+      set {
+        if (targetValue == value) return;
+        targetValue = value;
+        OnPropertyChanged("TargetValue");
+      }
+    }
+
+    [Storable]
+    private bool maximization;
+    public bool Maximization {
+      get { return maximization; }
+      set {
+        if (maximization == value) return;
+        maximization = value;
+        OnPropertyChanged("Maximization");
+      }
+    }
+
+    [Storable]
+    private double moveCostPerSolution;
+    public double MoveCostPerSolution {
+      get { return moveCostPerSolution; }
+      set {
+        if (moveCostPerSolution == value) return;
+        moveCostPerSolution = value;
+        perEvaluationsAnalyzer.MoveCostPerSolutionParameter.Value = new DoubleValue(moveCostPerSolution);
+        OnPropertyChanged("MoveCostPerSolution");
+      }
+    }
+
+    [Storable]
+    private QualityPerClockAnalyzer perClockAnalyzer;
+    [Storable]
+    private QualityPerEvaluationsAnalyzer perEvaluationsAnalyzer;
+
+    [Storable]
+    private ExecutionState executionState;
+    public ExecutionState ExecutionState {
+      get { return executionState; }
+      private set {
+        if (executionState != value) {
+          executionState = value;
+          OnExecutionStateChanged();
+          OnItemImageChanged();
+        }
+      }
+    }
+
+    private TimeSpan lastAlgorithmExecutionTime;
+    [Storable]
+    private TimeSpan executionTime;
+    public TimeSpan ExecutionTime {
+      get { return executionTime; }
+      set {
+        if (executionTime == value) return;
+        executionTime = value;
+        OnPropertyChanged("ExecutionTime");
+        OnExecutionTimeChanged();
+      }
+    }
+
+    private int lastAlgorithmEvaluatedSolutions;
+    private int lastAlgorithmEvaluatedMoves;
+    [Storable]
+    private double evaluations;
+    public double Evaluations {
+      get { return evaluations; }
+      set {
+        if (evaluations == value) return;
+        evaluations = value;
+        OnPropertyChanged("Evaluations");
+      }
+    }
+
+    [Storable]
+    private double bestSoFar;
+    public double BestSoFar {
+      get { return bestSoFar; }
+      set {
+        if (bestSoFar == value) return;
+        bestSoFar = value;
+        OnPropertyChanged("BestSoFar");
+      }
+    }
+
+    [Storable]
+    private IRun currentRun;
+    public IRun CurrentRun {
+      get { return currentRun; }
+      private set {
+        if (currentRun == value) return;
+        currentRun = value;
+        OnPropertyChanged("CurrentRun");
+      }
+    }
+
+    [Storable]
+    private IAlgorithm algorithm;
+    public IAlgorithm Algorithm {
+      get { return algorithm; }
+      set {
+        if (value != null && !typeof(ISingleObjectiveHeuristicOptimizationProblem).IsAssignableFrom(value.ProblemType))
+          throw new ArgumentException("Algorithm is not single-objective!");
+        if (algorithm == value) return;
+        if (algorithm != null) {
+          DeregisterAlgorithmEvents();
+          RemoveAlgorithmAnalyzers();
+        }
+        algorithm = value;
+        if (algorithm != null) {
+          RegisterAlgorithmEvents();
+          AddAlgorithmAnalyzers();
+        }
+        OnPropertyChanged("Algorithm");
+        Prepare();
+      }
+    }
+
+    [Storable]
+    private RunCollection runs;
+    public RunCollection Runs {
+      get { return runs; }
+      private set {
+        if (value == null) throw new ArgumentNullException();
+        if (runs == value) return;
+        runs = value;
+        OnPropertyChanged("Runs");
+      }
+    }
+
+    public IEnumerable<IOptimizer> NestedOptimizers {
+      get {
+        if (Algorithm == null) yield break;
+        yield return Algorithm;
+        foreach (var opt in Algorithm.NestedOptimizers)
+          yield return opt;
+      }
+    }
+
+    private bool IsFinished {
+      get {
+        var timeHit = ExecutionTime >= MaximumExecutionTime;
+        var evalHit = Evaluations >= MaximumEvaluations;
+        var targetHit = (Maximization && BestSoFar >= TargetValue || !Maximization && BestSoFar <= TargetValue);
+
+        return timeHit && evalHit && targetHit
+          || timeHit && (TerminationCriterium == TerminationCriterium.OnlyByTime
+                      || TerminationCriterium == TerminationCriterium.ByTargetAndTime
+                      || TerminationCriterium == TerminationCriterium.WhicheverHitsFirst)
+          || evalHit && (TerminationCriterium == TerminationCriterium.OnlyByEvaluations
+                      || TerminationCriterium == TerminationCriterium.ByTargetAndEvaluations
+                      || TerminationCriterium == TerminationCriterium.WhicheverHitsFirst)
+          || targetHit && (TerminationCriterium == TerminationCriterium.OnlyByTarget
+                        || TerminationCriterium == TerminationCriterium.WhicheverHitsFirst
+                        || TerminationCriterium == TerminationCriterium.ByTargetAndTime
+                        || TerminationCriterium == TerminationCriterium.ByTargetAndEvaluations);
+      }
+    }
+
+    private ISingleObjectiveHeuristicOptimizationProblem problem;
+
+    [StorableConstructor]
+    private IndepdentRandomRestarter(bool deserializing) : base(deserializing) { }
+    private IndepdentRandomRestarter(IndepdentRandomRestarter original, Cloner cloner)
+      : base(original, cloner) {
+      terminationCriterium = original.terminationCriterium;
+      maximumExecutionTime = original.maximumExecutionTime;
+      maximumEvaluations = original.maximumEvaluations;
+      moveCostPerSolution = original.moveCostPerSolution;
+      targetValue = original.targetValue;
+      maximization = original.maximization;
+      executionTime = original.executionTime;
+      evaluations = original.evaluations;
+      bestSoFar = original.bestSoFar;
+      lastAlgorithmExecutionTime = original.lastAlgorithmExecutionTime;
+      lastAlgorithmEvaluatedSolutions = original.lastAlgorithmEvaluatedSolutions;
+      lastAlgorithmEvaluatedMoves = original.lastAlgorithmEvaluatedMoves;
+
+      perClockAnalyzer = cloner.Clone(original.perClockAnalyzer);
+      perEvaluationsAnalyzer = cloner.Clone(original.perEvaluationsAnalyzer);
+
+      algorithm = cloner.Clone(original.algorithm);
+      runs = cloner.Clone(original.runs);
+
+      ExecutionState = original.ExecutionState;
+
+      Initialize();
+    }
+    public IndepdentRandomRestarter()
+      : base() {
+      name = ItemName;
+      description = ItemDescription;
+      terminationCriterium = TerminationCriterium.ByTargetAndEvaluations;
+      maximumExecutionTime = TimeSpan.FromMinutes(1);
+      maximumEvaluations = 10000000; // 10 mio
+      moveCostPerSolution = 1;
+      targetValue = 0;
+      maximization = false;
+      executionTime = TimeSpan.Zero;
+      evaluations = 0;
+      bestSoFar = double.NaN;
+      lastAlgorithmExecutionTime = TimeSpan.Zero;
+      lastAlgorithmEvaluatedSolutions = 0;
+      lastAlgorithmEvaluatedMoves = 0;
+
+      perClockAnalyzer = new QualityPerClockAnalyzer();
+      perEvaluationsAnalyzer = new QualityPerEvaluationsAnalyzer();
+
+      Runs = new RunCollection { OptimizerName = Name };
+      Initialize();
+    }
+    public IndepdentRandomRestarter(string name)
+      : base(name) {
+      description = ItemDescription;
+      terminationCriterium = TerminationCriterium.ByTargetAndEvaluations;
+      maximumExecutionTime = TimeSpan.FromMinutes(1);
+      maximumEvaluations = 10000000; // 10 mio
+      moveCostPerSolution = 1;
+      targetValue = 0;
+      maximization = false;
+      executionTime = TimeSpan.Zero;
+      evaluations = 0;
+      bestSoFar = double.NaN;
+      lastAlgorithmExecutionTime = TimeSpan.Zero;
+      lastAlgorithmEvaluatedSolutions = 0;
+      lastAlgorithmEvaluatedMoves = 0;
+
+      perClockAnalyzer = new QualityPerClockAnalyzer();
+      perEvaluationsAnalyzer = new QualityPerEvaluationsAnalyzer();
+
+      Runs = new RunCollection { OptimizerName = Name };
+      Initialize();
+    }
+    public IndepdentRandomRestarter(string name, string description)
+      : base(name, description) {
+      terminationCriterium = TerminationCriterium.ByTargetAndEvaluations;
+      maximumExecutionTime = TimeSpan.FromMinutes(1);
+      maximumEvaluations = 10000000; // 10 mio
+      moveCostPerSolution = 1;
+      targetValue = 0;
+      maximization = false;
+      executionTime = TimeSpan.Zero;
+      evaluations = 0;
+      bestSoFar = double.NaN;
+      lastAlgorithmExecutionTime = TimeSpan.Zero;
+      lastAlgorithmEvaluatedSolutions = 0;
+      lastAlgorithmEvaluatedMoves = 0;
+
+      perClockAnalyzer = new QualityPerClockAnalyzer();
+      perEvaluationsAnalyzer = new QualityPerEvaluationsAnalyzer();
+
+      Runs = new RunCollection { OptimizerName = Name };
+      Initialize();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      if (ExecutionState == ExecutionState.Started) throw new InvalidOperationException(string.Format("Clone not allowed in execution state \"{0}\".", ExecutionState));
+      return new IndepdentRandomRestarter(this, cloner);
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      Initialize();
+    }
+
+    private void Initialize() {
+      if (algorithm != null) RegisterAlgorithmEvents();
+    }
+
+    private void Reset() {
+      ExecutionTime = TimeSpan.Zero;
+      Evaluations = 0;
+      BestSoFar = double.NaN;
+      lastAlgorithmExecutionTime = TimeSpan.Zero;
+      lastAlgorithmEvaluatedSolutions = 0;
+      lastAlgorithmEvaluatedMoves = 0;
+
+      CurrentRun = null;
+    }
+
+    public void Prepare() {
+      Prepare(false);
+    }
+    public void Prepare(bool clearRuns) {
+      if ((ExecutionState != ExecutionState.Prepared) && (ExecutionState != ExecutionState.Paused) && (ExecutionState != ExecutionState.Stopped))
+        throw new InvalidOperationException(string.Format("Prepare not allowed in execution state \"{0}\".", ExecutionState));
+      Reset();
+
+      if (Algorithm != null) {
+        Algorithm.Prepare(clearRuns);
+        ExecutionState = ExecutionState.Prepared;
+        OnPrepared();
+      }
+    }
+    public void Start() {
+      if ((ExecutionState != ExecutionState.Prepared) && (ExecutionState != ExecutionState.Paused))
+        throw new InvalidOperationException(string.Format("Start not allowed in execution state \"{0}\".", ExecutionState));
+
+      if (ExecutionState == ExecutionState.Prepared) {
+        CurrentRun = new Run(Algorithm) {
+          Name = Algorithm.Name + " IRRRun" + Runs.Count
+        };
+        if (!CurrentRun.Results.ContainsKey(ExecutionTimeResultName))
+          CurrentRun.Results.Add(ExecutionTimeResultName, new TimeSpanValue(TimeSpan.Zero));
+        CurrentRun.Results.Add(perEvaluationsAnalyzer.EvaluatedSolutionsParameter.ActualName, new IntValue(0));
+        CurrentRun.Results.Add(perEvaluationsAnalyzer.EvaluatedMovesParameter.ActualName, new IntValue(0));
+        CurrentRun.Results.Add(BestQualityResultName, new DoubleValue(Maximization ? double.MinValue : double.MaxValue));
+      }
+      Algorithm.Start();
+      ExecutionState = ExecutionState.Started;
+      OnStarted();
+    }
+    public void Pause() {
+      if (ExecutionState != ExecutionState.Started)
+        throw new InvalidOperationException(string.Format("Pause not allowed in execution state \"{0}\".", ExecutionState));
+      Algorithm.Pause();
+      ExecutionState = ExecutionState.Paused;
+      OnPaused();
+    }
+
+    private bool forceStop = false;
+    public void Stop() {
+      if ((ExecutionState != ExecutionState.Started) && (ExecutionState != ExecutionState.Paused))
+        throw new InvalidOperationException(string.Format("Stop not allowed in execution state \"{0}\".", ExecutionState));
+      forceStop = true;
+      Algorithm.Stop();
+    }
+
+    private void AddAlgorithmAnalyzers() {
+      if (!Algorithm.Parameters.ContainsKey("Analyzer")) return;
+      var analyzerParam = Algorithm.Parameters["Analyzer"] as IValueParameter<MultiAnalyzer>;
+      if (analyzerParam == null) return;
+      if (!analyzerParam.Value.Operators.Contains(perClockAnalyzer))
+        analyzerParam.Value.Operators.Add(perClockAnalyzer);
+      if (!analyzerParam.Value.Operators.Contains(perEvaluationsAnalyzer))
+        analyzerParam.Value.Operators.Add(perEvaluationsAnalyzer);
+    }
+
+    private void RemoveAlgorithmAnalyzers() {
+      if (!Algorithm.Parameters.ContainsKey("Analyzer")) return;
+      var analyzerParam = Algorithm.Parameters["Analyzer"] as IValueParameter<MultiAnalyzer>;
+      if (analyzerParam == null) return;
+      analyzerParam.Value.Operators.Remove(perClockAnalyzer);
+      analyzerParam.Value.Operators.Remove(perEvaluationsAnalyzer);
+    }
+
+    #region Events
+    protected override void OnNameChanged() {
+      base.OnNameChanged();
+      runs.OptimizerName = Name;
+    }
+
+    public event PropertyChangedEventHandler PropertyChanged;
+    private void OnPropertyChanged(string property) {
+      var handler = PropertyChanged;
+      if (handler != null) handler(this, new PropertyChangedEventArgs(property));
+    }
+
+    #region IExecutable Events
+    public event EventHandler ExecutionStateChanged;
+    private void OnExecutionStateChanged() {
+      var handler = ExecutionStateChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler ExecutionTimeChanged;
+    private void OnExecutionTimeChanged() {
+      var handler = ExecutionTimeChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler Prepared;
+    private void OnPrepared() {
+      var handler = Prepared;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler Started;
+    private void OnStarted() {
+      var handler = Started;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler Paused;
+    private void OnPaused() {
+      var handler = Paused;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler Stopped;
+    private void OnStopped() {
+      var handler = Stopped;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler<EventArgs<Exception>> ExceptionOccurred;
+    private void OnExceptionOccurred(Exception exception) {
+      var handler = ExceptionOccurred;
+      if (handler != null) handler(this, new EventArgs<Exception>(exception));
+    }
+    #endregion
+
+    #region Algorithm Events
+    private void RegisterAlgorithmEvents() {
+      algorithm.ExceptionOccurred += Algorithm_ExceptionOccurred;
+      algorithm.ExecutionTimeChanged += Algorithm_ExecutionTimeChanged;
+      algorithm.ExecutionStateChanged += Algorithm_ExecutionStateChanged;
+      algorithm.Paused += Algorithm_Paused;
+      algorithm.Prepared += Algorithm_Prepared;
+      algorithm.Started += Algorithm_Started;
+      algorithm.Stopped += Algorithm_Stopped;
+      algorithm.ProblemChanged += Algorithm_ProblemChanged;
+      Algorithm_ProblemChanged(algorithm, EventArgs.Empty);
+    }
+    private void DeregisterAlgorithmEvents() {
+      algorithm.ExceptionOccurred -= Algorithm_ExceptionOccurred;
+      algorithm.ExecutionTimeChanged -= Algorithm_ExecutionTimeChanged;
+      algorithm.ExecutionStateChanged -= Algorithm_ExecutionStateChanged;
+      algorithm.Paused -= Algorithm_Paused;
+      algorithm.Prepared -= Algorithm_Prepared;
+      algorithm.Started -= Algorithm_Started;
+      algorithm.Stopped -= Algorithm_Stopped;
+      algorithm.ProblemChanged -= Algorithm_ProblemChanged;
+    }
+    private void Algorithm_ExceptionOccurred(object sender, EventArgs<Exception> e) {
+      OnExceptionOccurred(e.Value);
+    }
+    private void Algorithm_ExecutionTimeChanged(object sender, EventArgs e) {
+      if (Algorithm.ExecutionState != ExecutionState.Started) return;
+
+      if (ExecutionState == ExecutionState.Started)
+        UpdateAlgorithmResults();
+
+      if (IsFinished && ExecutionState != ExecutionState.Stopped) {
+        Algorithm.Stop();
+      }
+      OnExecutionTimeChanged();
+    }
+
+    private void Algorithm_ExecutionStateChanged(object sender, EventArgs e) {
+      //OnExecutionStateChanged();
+    }
+    private void Algorithm_Paused(object sender, EventArgs e) {
+      UpdateAlgorithmResults();
+      OnPaused();
+    }
+    private void Algorithm_Prepared(object sender, EventArgs e) {
+      lastAlgorithmEvaluatedSolutions = 0;
+      lastAlgorithmEvaluatedMoves = 0;
+      lastAlgorithmExecutionTime = TimeSpan.Zero;
+    }
+    private void Algorithm_Started(object sender, EventArgs e) {
+      //OnStarted();
+    }
+    private void Algorithm_Stopped(object sender, EventArgs e) {
+      var bestQuality = UpdateAlgorithmResults();
+
+      var execTime = ((TimeSpanValue)currentRun.Results[ExecutionTimeResultName]).Value;
+      foreach (var result in Algorithm.Results) {
+        if (result.Name == perClockAnalyzer.QualityPerClockParameter.ResultName) {
+          if (!currentRun.Results.ContainsKey(result.Name))
+            currentRun.Results.Add(result.Name, (IItem)result.Value.Clone());
+          else {
+            var dt = (IndexedDataTable<double>)currentRun.Results[result.Name];
+            var best = dt.Rows.First().Values.Last().Item2;
+            var resultDt = (IndexedDataTable<double>)result.Value;
+            foreach (var tupl in resultDt.Rows.First().Values) {
+              if (Maximization && tupl.Item2 > best || !Maximization && tupl.Item2 < best) {
+                dt.Rows.First().Values.Add(Tuple.Create(execTime.TotalSeconds + tupl.Item1, tupl.Item2));
+                best = tupl.Item2;
+              }
+            }
+          }
+        } else if (result.Name == perEvaluationsAnalyzer.QualityPerEvaluationsParameter.ResultName) {
+          if (!currentRun.Results.ContainsKey(result.Name))
+            currentRun.Results.Add(result.Name, (IItem)result.Value.Clone());
+          else {
+            var dt = (IndexedDataTable<double>)currentRun.Results[result.Name];
+            var evalSols = ((IntValue)currentRun.Results[perEvaluationsAnalyzer.EvaluatedSolutionsParameter.ActualName]).Value;
+            var evalMoves = ((IntValue)currentRun.Results[perEvaluationsAnalyzer.EvaluatedMovesParameter.ActualName]).Value;
+            var best = dt.Rows.First().Values.Last().Item2;
+            var resultDt = (IndexedDataTable<double>)result.Value;
+            foreach (var tupl in resultDt.Rows.First().Values) {
+              if (Maximization && tupl.Item2 > best || !Maximization && tupl.Item2 < best) {
+                dt.Rows.First().Values.Add(Tuple.Create(evalSols + moveCostPerSolution * evalMoves + tupl.Item1, tupl.Item2));
+                best = tupl.Item2;
+              }
+            }
+          }
+        } else if (result.Name == perEvaluationsAnalyzer.EvaluatedSolutionsParameter.ActualName) {
+          var evalSols = ((IntValue)currentRun.Results[perEvaluationsAnalyzer.EvaluatedSolutionsParameter.ActualName]);
+          evalSols.Value += ((IntValue)result.Value).Value;
+        } else if (result.Name == perEvaluationsAnalyzer.EvaluatedMovesParameter.ActualName) {
+          var evalMoves = ((IntValue)currentRun.Results[perEvaluationsAnalyzer.EvaluatedMovesParameter.ActualName]);
+          evalMoves.Value += ((IntValue)result.Value).Value;
+        } else if (result.Name == perEvaluationsAnalyzer.BestQualityParameter.ActualName) {
+          var best = ((DoubleValue)currentRun.Results[BestQualityResultName]).Value;
+          if (Maximization && best < bestQuality || !Maximization && best > bestQuality)
+            currentRun.Results[BestQualityResultName] = new DoubleValue(bestQuality);
+        } else if (result.Name.ToLower().EndsWith("solution") && BestSoFar == bestQuality) {
+          if (currentRun.Results.ContainsKey(result.Name))
+            currentRun.Results[result.Name] = (IItem)result.Value.Clone();
+          else currentRun.Results.Add(result.Name, (IItem)result.Value.Clone());
+        }
+      }
+      currentRun.Results[ExecutionTimeResultName] = new TimeSpanValue(execTime + Algorithm.ExecutionTime);
+
+      if (!forceStop && !IsFinished) {
+        Algorithm.Prepare();
+        Algorithm.Start();
+      } else {
+        forceStop = false;
+        Runs.Add(currentRun);
+        currentRun = null;
+        Algorithm.Prepare(true);
+        ExecutionState = ExecutionState.Stopped;
+        OnStopped();
+      }
+    }
+
+    private double UpdateAlgorithmResults() {
+      ExecutionTime += Algorithm.ExecutionTime - lastAlgorithmExecutionTime;
+      lastAlgorithmExecutionTime = Algorithm.ExecutionTime;
+
+      IResult evaluationsResult;
+      if (Algorithm.Results.TryGetValue(perEvaluationsAnalyzer.EvaluatedSolutionsParameter.ActualName, out evaluationsResult)) {
+        var evals = ((IntValue)evaluationsResult.Value).Value;
+        Evaluations += evals - lastAlgorithmEvaluatedSolutions;
+        lastAlgorithmEvaluatedSolutions = evals;
+      }
+      if (Algorithm.Results.TryGetValue(perEvaluationsAnalyzer.EvaluatedMovesParameter.ActualName, out evaluationsResult)) {
+        var evals = ((IntValue)evaluationsResult.Value).Value;
+        Evaluations += moveCostPerSolution * (evals - lastAlgorithmEvaluatedMoves);
+        lastAlgorithmEvaluatedMoves = evals;
+      }
+      if (Algorithm.Results.TryGetValue(perEvaluationsAnalyzer.BestQualityParameter.ActualName, out evaluationsResult)) {
+        var bestQuality = ((DoubleValue)evaluationsResult.Value).Value;
+        if (double.IsNaN(BestSoFar)
+            || Maximization && bestQuality > BestSoFar
+            || !Maximization && bestQuality < BestSoFar)
+          BestSoFar = bestQuality;
+        return bestQuality;
+      }
+      return double.NaN;
+    }
+
+    private void Algorithm_ProblemChanged(object sender, EventArgs e) {
+      if (problem != null) DeregisterProblemEvents();
+
+      problem = Algorithm.Problem as ISingleObjectiveHeuristicOptimizationProblem;
+      if (problem == null) return;
+      RegisterProblemEvents();
+
+      AddAlgorithmAnalyzers();
+
+      var maxParam = problem.MaximizationParameter as IValueParameter<BoolValue>;
+      if (maxParam != null)
+        Maximization = maxParam.Value.Value;
+      var bkParam = problem.BestKnownQualityParameter as IValueParameter<DoubleValue>;
+      if (bkParam != null && bkParam.Value != null)
+        TargetValue = bkParam.Value.Value;
+
+      Reset();
+    }
+
+    private void RegisterProblemEvents() {
+      problem.Reset += ProblemOnReset;
+      problem.OperatorsChanged += ProblemOnOperatorsChanged;
+    }
+
+    private void DeregisterProblemEvents() {
+      problem.Reset -= ProblemOnReset;
+      problem.OperatorsChanged -= ProblemOnOperatorsChanged;
+    }
+
+    private void ProblemOnReset(object sender, EventArgs eventArgs) {
+      AddAlgorithmAnalyzers();
+    }
+
+    private void ProblemOnOperatorsChanged(object sender, EventArgs eventArgs) {
+      AddAlgorithmAnalyzers();
+    }
+    #endregion
+    #endregion
+  }
+}
Index: /branches/PerformanceComparison/HeuristicLab.Analysis/3.3/QualityAnalysis/QualityPerClockAnalyzer.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.Analysis/3.3/QualityAnalysis/QualityPerClockAnalyzer.cs	(revision 12803)
+++ /branches/PerformanceComparison/HeuristicLab.Analysis/3.3/QualityAnalysis/QualityPerClockAnalyzer.cs	(revision 12804)
@@ -75,19 +75,20 @@
 
     public override IOperation Apply() {
-      var lastUpdateTime = LastUpdateTimeParameter.ActualValue;
-      if (lastUpdateTime == null) {
-        lastUpdateTime = new DateTimeValue(DateTime.UtcNow.AddMilliseconds(-1));
-        LastUpdateTimeParameter.ActualValue = lastUpdateTime;
-      }
-      var now = DateTime.UtcNow;
-
       var bestQuality = BestQualityParameter.ActualValue.Value;
-
       var dataTable = QualityPerClockParameter.ResultValue;
       var values = dataTable.Rows["First-hit Graph"].Values;
-      if (values.Count == 0 || values.Last().Item2 != bestQuality)
-        dataTable.Rows["First-hit Graph"].Values.Add(Tuple.Create((now - lastUpdateTime.Value).TotalSeconds, bestQuality));
 
-      lastUpdateTime.Value = now;
+      if (values.Count == 0 || values.Last().Item2 != bestQuality) {
+        var lastUpdateTime = LastUpdateTimeParameter.ActualValue;
+        if (lastUpdateTime == null) {
+          lastUpdateTime = new DateTimeValue(DateTime.UtcNow.AddMilliseconds(-1));
+          LastUpdateTimeParameter.ActualValue = lastUpdateTime;
+        }
+
+        var now = DateTime.UtcNow;
+        var runtimeSoFar = (now - lastUpdateTime.Value).TotalSeconds + (values.Count > 0 ? values.Last().Item1 : 0);
+        dataTable.Rows["First-hit Graph"].Values.Add(Tuple.Create(runtimeSoFar, bestQuality));
+        lastUpdateTime.Value = now;
+      }
       return base.Apply();
     }
Index: /branches/PerformanceComparison/HeuristicLab.Analysis/3.3/QualityAnalysis/QualityPerEvaluationsAnalyzer.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.Analysis/3.3/QualityAnalysis/QualityPerEvaluationsAnalyzer.cs	(revision 12803)
+++ /branches/PerformanceComparison/HeuristicLab.Analysis/3.3/QualityAnalysis/QualityPerEvaluationsAnalyzer.cs	(revision 12804)
@@ -44,4 +44,10 @@
       get { return (ILookupParameter<IntValue>)Parameters["EvaluatedSolutions"]; }
     }
+    public ILookupParameter<IntValue> EvaluatedMovesParameter {
+      get { return (ILookupParameter<IntValue>)Parameters["EvaluatedMoves"]; }
+    }
+    public IValueLookupParameter<DoubleValue> MoveCostPerSolutionParameter {
+      get { return (IValueLookupParameter<DoubleValue>)Parameters["MoveCostPerSolution"]; }
+    }
     public IResultParameter<IndexedDataTable<double>> QualityPerEvaluationsParameter {
       get { return (IResultParameter<IndexedDataTable<double>>)Parameters["QualityPerEvaluations"]; }
@@ -54,5 +60,7 @@
       : base() {
       Parameters.Add(new LookupParameter<DoubleValue>("BestQuality", "The quality value that should be compared."));
-      Parameters.Add(new LookupParameter<IntValue>("EvaluatedSolutions", "The quality value that should be compared."));
+      Parameters.Add(new LookupParameter<IntValue>("EvaluatedSolutions", "The number of evaluated solutions."));
+      Parameters.Add(new LookupParameter<IntValue>("EvaluatedMoves", "The number of evaluated moves."));
+      Parameters.Add(new ValueLookupParameter<DoubleValue>("MoveCostPerSolution", "The cost to evaluate a move as a ratio to the cost of evaluating a solution.", new DoubleValue(1)));
       Parameters.Add(new ResultParameter<IndexedDataTable<double>>("QualityPerEvaluations", "Data table containing the first hitting graph with evaluations as the x-axis."));
       QualityPerEvaluationsParameter.DefaultValue = new IndexedDataTable<double>("Quality per Evaluations") {
@@ -74,8 +82,13 @@
     public override IOperation Apply() {
       var bestQuality = BestQualityParameter.ActualValue.Value;
-      var evaluations = Math.Max(EvaluatedSolutionsParameter.ActualValue.Value, 1);
+      var evalSols = EvaluatedSolutionsParameter.ActualValue;
+      var evalMoves = EvaluatedMovesParameter.ActualValue;
+      var evaluations = 0.0;
+      if (evalSols != null) evaluations += evalSols.Value;
+      if (evalMoves != null) evaluations += evalMoves.Value * MoveCostPerSolutionParameter.ActualValue.Value;
 
       var dataTable = QualityPerEvaluationsParameter.ResultValue;
       var values = dataTable.Rows["First-hit Graph"].Values;
+      if (evaluations == 0 || values.Count > 0 && evaluations < values.Last().Item1) evaluations = 1;
       if (values.Count == 0 || values.Last().Item2 != bestQuality)
         values.Add(Tuple.Create((double)evaluations, bestQuality));
Index: /branches/PerformanceComparison/HeuristicLab.Optimization.Views/3.3/HeuristicLab.Optimization.Views-3.3.csproj
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.Optimization.Views/3.3/HeuristicLab.Optimization.Views-3.3.csproj	(revision 12803)
+++ /branches/PerformanceComparison/HeuristicLab.Optimization.Views/3.3/HeuristicLab.Optimization.Views-3.3.csproj	(revision 12804)
@@ -223,4 +223,10 @@
       <DependentUpon>CreateNewSingleEncodingDialog.cs</DependentUpon>
     </Compile>
+    <Compile Include="IRRestarterView.cs">
+      <SubType>UserControl</SubType>
+    </Compile>
+    <Compile Include="IRRestarterView.Designer.cs">
+      <DependentUpon>IRRestarterView.cs</DependentUpon>
+    </Compile>
     <Compile Include="ISolutionSimilarityCalculatorView.cs">
       <SubType>UserControl</SubType>
Index: /branches/PerformanceComparison/HeuristicLab.Optimization.Views/3.3/IRRestarterView.Designer.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.Optimization.Views/3.3/IRRestarterView.Designer.cs	(revision 12804)
+++ /branches/PerformanceComparison/HeuristicLab.Optimization.Views/3.3/IRRestarterView.Designer.cs	(revision 12804)
@@ -0,0 +1,417 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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.Optimization.Views {
+  partial class IndependentRandomRestarterView {
+    /// <summary> 
+    /// Required designer variable.
+    /// </summary>
+    private System.ComponentModel.IContainer components = null;
+
+    #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() {
+      System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(IndependentRandomRestarterView));
+      this.timeLimitLabel = new System.Windows.Forms.Label();
+      this.maxExecutionTimeTextBox = new System.Windows.Forms.TextBox();
+      this.evaluationsLimitabel = new System.Windows.Forms.Label();
+      this.maxEvaluationsTextBox = new System.Windows.Forms.TextBox();
+      this.tabControl = new HeuristicLab.MainForm.WindowsForms.DragOverTabControl();
+      this.algorithmTabPage = new System.Windows.Forms.TabPage();
+      this.algorithmViewHost = new HeuristicLab.MainForm.WindowsForms.ViewHost();
+      this.openAlgorithmButton = new System.Windows.Forms.Button();
+      this.newAlgorithmButton = new System.Windows.Forms.Button();
+      this.currentRunTabPage = new System.Windows.Forms.TabPage();
+      this.currentRunView = new HeuristicLab.Optimization.Views.RunView();
+      this.runsTabPage = new System.Windows.Forms.TabPage();
+      this.runsView = new HeuristicLab.Optimization.Views.RunCollectionView();
+      this.openFileDialog = new System.Windows.Forms.OpenFileDialog();
+      this.targetValueTextBox = new System.Windows.Forms.TextBox();
+      this.targetValueLabel = new System.Windows.Forms.Label();
+      this.terminationComboBox = new System.Windows.Forms.ComboBox();
+      this.terminationLabel = new System.Windows.Forms.Label();
+      this.moveCostPerSolutionTextBox = new System.Windows.Forms.TextBox();
+      this.moveCostPerSolutionLabel = new System.Windows.Forms.Label();
+      this.maximizationLabel = new System.Windows.Forms.Label();
+      this.maximizationCheckBox = new System.Windows.Forms.CheckBox();
+      ((System.ComponentModel.ISupportInitialize)(this.errorProvider)).BeginInit();
+      this.tabControl.SuspendLayout();
+      this.algorithmTabPage.SuspendLayout();
+      this.currentRunTabPage.SuspendLayout();
+      this.runsTabPage.SuspendLayout();
+      this.SuspendLayout();
+      // 
+      // startButton
+      // 
+      this.startButton.Location = new System.Drawing.Point(0, 440);
+      this.startButton.TabIndex = 9;
+      this.toolTip.SetToolTip(this.startButton, "Start/Resume Optimizer");
+      // 
+      // executionTimeTextBox
+      // 
+      this.executionTimeTextBox.Location = new System.Drawing.Point(412, 444);
+      // 
+      // executionTimeLabel
+      // 
+      this.executionTimeLabel.Location = new System.Drawing.Point(323, 447);
+      // 
+      // pauseButton
+      // 
+      this.pauseButton.Location = new System.Drawing.Point(30, 440);
+      this.pauseButton.TabIndex = 10;
+      this.toolTip.SetToolTip(this.pauseButton, "Pause Optimizer");
+      // 
+      // stopButton
+      // 
+      this.stopButton.Location = new System.Drawing.Point(60, 440);
+      this.stopButton.TabIndex = 11;
+      this.toolTip.SetToolTip(this.stopButton, "Stop Optimizer");
+      // 
+      // resetButton
+      // 
+      this.resetButton.Location = new System.Drawing.Point(90, 440);
+      this.resetButton.TabIndex = 12;
+      this.toolTip.SetToolTip(this.resetButton, "Reset Optimizer");
+      // 
+      // nameTextBox
+      // 
+      this.errorProvider.SetIconAlignment(this.nameTextBox, System.Windows.Forms.ErrorIconAlignment.MiddleLeft);
+      this.errorProvider.SetIconPadding(this.nameTextBox, 2);
+      this.nameTextBox.Location = new System.Drawing.Point(115, 0);
+      this.nameTextBox.Size = new System.Drawing.Size(409, 20);
+      // 
+      // infoLabel
+      // 
+      this.infoLabel.Location = new System.Drawing.Point(530, 3);
+      // 
+      // timeLimitLabel
+      // 
+      this.timeLimitLabel.AutoSize = true;
+      this.timeLimitLabel.Location = new System.Drawing.Point(3, 29);
+      this.timeLimitLabel.Name = "timeLimitLabel";
+      this.timeLimitLabel.Size = new System.Drawing.Size(106, 13);
+      this.timeLimitLabel.TabIndex = 3;
+      this.timeLimitLabel.Text = "Max Execution Time:";
+      // 
+      // maxExecutionTimeTextBox
+      // 
+      this.maxExecutionTimeTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.maxExecutionTimeTextBox.Location = new System.Drawing.Point(115, 26);
+      this.maxExecutionTimeTextBox.Name = "maxExecutionTimeTextBox";
+      this.maxExecutionTimeTextBox.Size = new System.Drawing.Size(409, 20);
+      this.maxExecutionTimeTextBox.TabIndex = 4;
+      this.maxExecutionTimeTextBox.Validating += new System.ComponentModel.CancelEventHandler(this.maxExecutionTimeTextBox_Validating);
+      // 
+      // evaluationsLimitabel
+      // 
+      this.evaluationsLimitabel.AutoSize = true;
+      this.evaluationsLimitabel.Location = new System.Drawing.Point(3, 55);
+      this.evaluationsLimitabel.Name = "evaluationsLimitabel";
+      this.evaluationsLimitabel.Size = new System.Drawing.Size(88, 13);
+      this.evaluationsLimitabel.TabIndex = 5;
+      this.evaluationsLimitabel.Text = "Max Evaluations:";
+      // 
+      // maxEvaluationsTextBox
+      // 
+      this.maxEvaluationsTextBox.Location = new System.Drawing.Point(115, 52);
+      this.maxEvaluationsTextBox.Name = "maxEvaluationsTextBox";
+      this.maxEvaluationsTextBox.Size = new System.Drawing.Size(157, 20);
+      this.maxEvaluationsTextBox.TabIndex = 6;
+      this.maxEvaluationsTextBox.Validating += new System.ComponentModel.CancelEventHandler(this.maxEvaluationsTextBox_Validating);
+      // 
+      // tabControl
+      // 
+      this.tabControl.AllowDrop = true;
+      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.algorithmTabPage);
+      this.tabControl.Controls.Add(this.currentRunTabPage);
+      this.tabControl.Controls.Add(this.runsTabPage);
+      this.tabControl.Location = new System.Drawing.Point(0, 132);
+      this.tabControl.Name = "tabControl";
+      this.tabControl.SelectedIndex = 0;
+      this.tabControl.Size = new System.Drawing.Size(546, 302);
+      this.tabControl.TabIndex = 8;
+      // 
+      // algorithmTabPage
+      // 
+      this.algorithmTabPage.AllowDrop = true;
+      this.algorithmTabPage.Controls.Add(this.algorithmViewHost);
+      this.algorithmTabPage.Controls.Add(this.openAlgorithmButton);
+      this.algorithmTabPage.Controls.Add(this.newAlgorithmButton);
+      this.algorithmTabPage.Location = new System.Drawing.Point(4, 22);
+      this.algorithmTabPage.Name = "algorithmTabPage";
+      this.algorithmTabPage.Padding = new System.Windows.Forms.Padding(3);
+      this.algorithmTabPage.Size = new System.Drawing.Size(538, 276);
+      this.algorithmTabPage.TabIndex = 1;
+      this.algorithmTabPage.Text = "Algorithm";
+      this.algorithmTabPage.UseVisualStyleBackColor = true;
+      this.algorithmTabPage.DragDrop += new System.Windows.Forms.DragEventHandler(this.algorithmTabPage_DragDrop);
+      this.algorithmTabPage.DragEnter += new System.Windows.Forms.DragEventHandler(this.algorithmTabPage_DragEnterOver);
+      this.algorithmTabPage.DragOver += new System.Windows.Forms.DragEventHandler(this.algorithmTabPage_DragEnterOver);
+      // 
+      // algorithmViewHost
+      // 
+      this.algorithmViewHost.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.algorithmViewHost.Caption = "View";
+      this.algorithmViewHost.Content = null;
+      this.algorithmViewHost.Enabled = false;
+      this.algorithmViewHost.Location = new System.Drawing.Point(6, 36);
+      this.algorithmViewHost.Name = "algorithmViewHost";
+      this.algorithmViewHost.ReadOnly = false;
+      this.algorithmViewHost.Size = new System.Drawing.Size(526, 234);
+      this.algorithmViewHost.TabIndex = 2;
+      this.algorithmViewHost.ViewsLabelVisible = true;
+      this.algorithmViewHost.ViewType = null;
+      // 
+      // openAlgorithmButton
+      // 
+      this.openAlgorithmButton.Image = ((System.Drawing.Image)(resources.GetObject("openAlgorithmButton.Image")));
+      this.openAlgorithmButton.Location = new System.Drawing.Point(36, 6);
+      this.openAlgorithmButton.Name = "openAlgorithmButton";
+      this.openAlgorithmButton.Size = new System.Drawing.Size(24, 24);
+      this.openAlgorithmButton.TabIndex = 1;
+      this.toolTip.SetToolTip(this.openAlgorithmButton, "Open Optimizer");
+      this.openAlgorithmButton.UseVisualStyleBackColor = true;
+      this.openAlgorithmButton.Click += new System.EventHandler(this.openAlgorithmButton_Click);
+      // 
+      // newAlgorithmButton
+      // 
+      this.newAlgorithmButton.Image = ((System.Drawing.Image)(resources.GetObject("newAlgorithmButton.Image")));
+      this.newAlgorithmButton.Location = new System.Drawing.Point(6, 6);
+      this.newAlgorithmButton.Name = "newAlgorithmButton";
+      this.newAlgorithmButton.Size = new System.Drawing.Size(24, 24);
+      this.newAlgorithmButton.TabIndex = 0;
+      this.toolTip.SetToolTip(this.newAlgorithmButton, "New Optimizer");
+      this.newAlgorithmButton.UseVisualStyleBackColor = true;
+      this.newAlgorithmButton.Click += new System.EventHandler(this.newAlgorithmButton_Click);
+      // 
+      // currentRunTabPage
+      // 
+      this.currentRunTabPage.Controls.Add(this.currentRunView);
+      this.currentRunTabPage.Location = new System.Drawing.Point(4, 22);
+      this.currentRunTabPage.Name = "currentRunTabPage";
+      this.currentRunTabPage.Padding = new System.Windows.Forms.Padding(6);
+      this.currentRunTabPage.Size = new System.Drawing.Size(538, 276);
+      this.currentRunTabPage.TabIndex = 4;
+      this.currentRunTabPage.Text = "Current Run";
+      this.currentRunTabPage.UseVisualStyleBackColor = true;
+      // 
+      // currentRunView
+      // 
+      this.currentRunView.Caption = "Run View";
+      this.currentRunView.Content = null;
+      this.currentRunView.Dock = System.Windows.Forms.DockStyle.Fill;
+      this.currentRunView.Location = new System.Drawing.Point(6, 6);
+      this.currentRunView.Name = "currentRunView";
+      this.currentRunView.ReadOnly = false;
+      this.currentRunView.Size = new System.Drawing.Size(526, 264);
+      this.currentRunView.TabIndex = 0;
+      // 
+      // runsTabPage
+      // 
+      this.runsTabPage.Controls.Add(this.runsView);
+      this.runsTabPage.Location = new System.Drawing.Point(4, 22);
+      this.runsTabPage.Name = "runsTabPage";
+      this.runsTabPage.Padding = new System.Windows.Forms.Padding(6);
+      this.runsTabPage.Size = new System.Drawing.Size(538, 276);
+      this.runsTabPage.TabIndex = 3;
+      this.runsTabPage.Text = "Runs";
+      this.runsTabPage.UseVisualStyleBackColor = true;
+      // 
+      // runsView
+      // 
+      this.runsView.Caption = "RunCollection View";
+      this.runsView.Content = null;
+      this.runsView.Dock = System.Windows.Forms.DockStyle.Fill;
+      this.runsView.Location = new System.Drawing.Point(6, 6);
+      this.runsView.Name = "runsView";
+      this.runsView.ReadOnly = false;
+      this.runsView.Size = new System.Drawing.Size(526, 264);
+      this.runsView.TabIndex = 1;
+      // 
+      // openFileDialog
+      // 
+      this.openFileDialog.DefaultExt = "hl";
+      this.openFileDialog.FileName = "Optimizer";
+      this.openFileDialog.Filter = "HeuristicLab Files|*.hl|All Files|*.*";
+      this.openFileDialog.Title = "Open Optimizer";
+      // 
+      // targetValueTextBox
+      // 
+      this.targetValueTextBox.Location = new System.Drawing.Point(115, 78);
+      this.targetValueTextBox.Name = "targetValueTextBox";
+      this.targetValueTextBox.Size = new System.Drawing.Size(157, 20);
+      this.targetValueTextBox.TabIndex = 6;
+      this.targetValueTextBox.Validating += new System.ComponentModel.CancelEventHandler(this.targetValueTextBox_Validating);
+      // 
+      // targetValueLabel
+      // 
+      this.targetValueLabel.AutoSize = true;
+      this.targetValueLabel.Location = new System.Drawing.Point(3, 81);
+      this.targetValueLabel.Name = "targetValueLabel";
+      this.targetValueLabel.Size = new System.Drawing.Size(71, 13);
+      this.targetValueLabel.TabIndex = 5;
+      this.targetValueLabel.Text = "Target Value:";
+      // 
+      // terminationComboBox
+      // 
+      this.terminationComboBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.terminationComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+      this.terminationComboBox.FormattingEnabled = true;
+      this.terminationComboBox.Location = new System.Drawing.Point(115, 105);
+      this.terminationComboBox.Name = "terminationComboBox";
+      this.terminationComboBox.Size = new System.Drawing.Size(409, 21);
+      this.terminationComboBox.TabIndex = 16;
+      this.terminationComboBox.SelectedIndexChanged += new System.EventHandler(this.terminationComboBox_SelectedIndexChanged);
+      // 
+      // terminationLabel
+      // 
+      this.terminationLabel.AutoSize = true;
+      this.terminationLabel.Location = new System.Drawing.Point(3, 108);
+      this.terminationLabel.Name = "terminationLabel";
+      this.terminationLabel.Size = new System.Drawing.Size(65, 13);
+      this.terminationLabel.TabIndex = 5;
+      this.terminationLabel.Text = "Termination:";
+      // 
+      // moveCostPerSolutionTextBox
+      // 
+      this.moveCostPerSolutionTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.moveCostPerSolutionTextBox.Location = new System.Drawing.Point(401, 52);
+      this.moveCostPerSolutionTextBox.Name = "moveCostPerSolutionTextBox";
+      this.moveCostPerSolutionTextBox.Size = new System.Drawing.Size(123, 20);
+      this.moveCostPerSolutionTextBox.TabIndex = 6;
+      this.moveCostPerSolutionTextBox.Validating += new System.ComponentModel.CancelEventHandler(this.moveCostPerSolutionTextBox_Validating);
+      // 
+      // moveCostPerSolutionLabel
+      // 
+      this.moveCostPerSolutionLabel.AutoSize = true;
+      this.moveCostPerSolutionLabel.Location = new System.Drawing.Point(278, 55);
+      this.moveCostPerSolutionLabel.Name = "moveCostPerSolutionLabel";
+      this.moveCostPerSolutionLabel.Size = new System.Drawing.Size(117, 13);
+      this.moveCostPerSolutionLabel.TabIndex = 5;
+      this.moveCostPerSolutionLabel.Text = "Move cost per solution:";
+      // 
+      // maximizationLabel
+      // 
+      this.maximizationLabel.AutoSize = true;
+      this.maximizationLabel.Location = new System.Drawing.Point(278, 81);
+      this.maximizationLabel.Name = "maximizationLabel";
+      this.maximizationLabel.Size = new System.Drawing.Size(70, 13);
+      this.maximizationLabel.TabIndex = 5;
+      this.maximizationLabel.Text = "Maximization:";
+      // 
+      // maximizationCheckBox
+      // 
+      this.maximizationCheckBox.AutoSize = true;
+      this.maximizationCheckBox.Location = new System.Drawing.Point(401, 80);
+      this.maximizationCheckBox.Name = "maximizationCheckBox";
+      this.maximizationCheckBox.Size = new System.Drawing.Size(15, 14);
+      this.maximizationCheckBox.TabIndex = 17;
+      this.maximizationCheckBox.UseVisualStyleBackColor = true;
+      this.maximizationCheckBox.CheckedChanged += new System.EventHandler(this.maximizationCheckBox_CheckedChanged);
+      // 
+      // IndependentRandomRestarterView
+      // 
+      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
+      this.Controls.Add(this.maximizationCheckBox);
+      this.Controls.Add(this.terminationComboBox);
+      this.Controls.Add(this.tabControl);
+      this.Controls.Add(this.maxExecutionTimeTextBox);
+      this.Controls.Add(this.timeLimitLabel);
+      this.Controls.Add(this.terminationLabel);
+      this.Controls.Add(this.targetValueLabel);
+      this.Controls.Add(this.maximizationLabel);
+      this.Controls.Add(this.moveCostPerSolutionLabel);
+      this.Controls.Add(this.evaluationsLimitabel);
+      this.Controls.Add(this.moveCostPerSolutionTextBox);
+      this.Controls.Add(this.targetValueTextBox);
+      this.Controls.Add(this.maxEvaluationsTextBox);
+      this.Name = "IndependentRandomRestarterView";
+      this.Size = new System.Drawing.Size(549, 464);
+      this.Controls.SetChildIndex(this.maxEvaluationsTextBox, 0);
+      this.Controls.SetChildIndex(this.targetValueTextBox, 0);
+      this.Controls.SetChildIndex(this.moveCostPerSolutionTextBox, 0);
+      this.Controls.SetChildIndex(this.evaluationsLimitabel, 0);
+      this.Controls.SetChildIndex(this.moveCostPerSolutionLabel, 0);
+      this.Controls.SetChildIndex(this.maximizationLabel, 0);
+      this.Controls.SetChildIndex(this.targetValueLabel, 0);
+      this.Controls.SetChildIndex(this.terminationLabel, 0);
+      this.Controls.SetChildIndex(this.timeLimitLabel, 0);
+      this.Controls.SetChildIndex(this.maxExecutionTimeTextBox, 0);
+      this.Controls.SetChildIndex(this.tabControl, 0);
+      this.Controls.SetChildIndex(this.nameLabel, 0);
+      this.Controls.SetChildIndex(this.nameTextBox, 0);
+      this.Controls.SetChildIndex(this.infoLabel, 0);
+      this.Controls.SetChildIndex(this.resetButton, 0);
+      this.Controls.SetChildIndex(this.stopButton, 0);
+      this.Controls.SetChildIndex(this.pauseButton, 0);
+      this.Controls.SetChildIndex(this.executionTimeLabel, 0);
+      this.Controls.SetChildIndex(this.executionTimeTextBox, 0);
+      this.Controls.SetChildIndex(this.startButton, 0);
+      this.Controls.SetChildIndex(this.terminationComboBox, 0);
+      this.Controls.SetChildIndex(this.maximizationCheckBox, 0);
+      ((System.ComponentModel.ISupportInitialize)(this.errorProvider)).EndInit();
+      this.tabControl.ResumeLayout(false);
+      this.algorithmTabPage.ResumeLayout(false);
+      this.currentRunTabPage.ResumeLayout(false);
+      this.runsTabPage.ResumeLayout(false);
+      this.ResumeLayout(false);
+      this.PerformLayout();
+
+    }
+
+    #endregion
+
+    private System.Windows.Forms.Label timeLimitLabel;
+    private System.Windows.Forms.TextBox maxExecutionTimeTextBox;
+    private System.Windows.Forms.Label evaluationsLimitabel;
+    private System.Windows.Forms.TextBox maxEvaluationsTextBox;
+    private MainForm.WindowsForms.DragOverTabControl tabControl;
+    private System.Windows.Forms.TabPage runsTabPage;
+    private RunCollectionView runsView;
+    private System.Windows.Forms.OpenFileDialog openFileDialog;
+    private System.Windows.Forms.TextBox targetValueTextBox;
+    private System.Windows.Forms.Label targetValueLabel;
+    private System.Windows.Forms.ComboBox terminationComboBox;
+    private System.Windows.Forms.Label terminationLabel;
+    private System.Windows.Forms.TextBox moveCostPerSolutionTextBox;
+    private System.Windows.Forms.Label moveCostPerSolutionLabel;
+    private System.Windows.Forms.Label maximizationLabel;
+    private System.Windows.Forms.CheckBox maximizationCheckBox;
+    private System.Windows.Forms.TabPage algorithmTabPage;
+    private MainForm.WindowsForms.ViewHost algorithmViewHost;
+    private System.Windows.Forms.Button openAlgorithmButton;
+    private System.Windows.Forms.Button newAlgorithmButton;
+    private System.Windows.Forms.TabPage currentRunTabPage;
+    private RunView currentRunView;
+  }
+}
Index: /branches/PerformanceComparison/HeuristicLab.Optimization.Views/3.3/IRRestarterView.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.Optimization.Views/3.3/IRRestarterView.cs	(revision 12804)
+++ /branches/PerformanceComparison/HeuristicLab.Optimization.Views/3.3/IRRestarterView.cs	(revision 12804)
@@ -0,0 +1,298 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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 System;
+using System.ComponentModel;
+using System.Globalization;
+using System.Linq;
+using System.Windows.Forms;
+using HeuristicLab.Analysis;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Core.Views;
+using HeuristicLab.MainForm;
+using HeuristicLab.PluginInfrastructure;
+
+namespace HeuristicLab.Optimization.Views {
+  [View("Independent Random Restarter View")]
+  [Content(typeof(IndepdentRandomRestarter), IsDefaultView = true)]
+  public partial class IndependentRandomRestarterView : IOptimizerView {
+    protected TypeSelectorDialog algorithmTypeSelectorDialog;
+    protected virtual bool SuppressEvents { get; set; }
+
+    public new IndepdentRandomRestarter Content {
+      get { return (IndepdentRandomRestarter)base.Content; }
+      set { base.Content = value; }
+    }
+
+    public IndependentRandomRestarterView() {
+      InitializeComponent();
+      terminationComboBox.Items.AddRange(Enum.GetValues(typeof(TerminationCriterium)).Cast<object>().ToArray());
+    }
+
+    protected override void Dispose(bool disposing) {
+      if (disposing) {
+        if (algorithmTypeSelectorDialog != null) algorithmTypeSelectorDialog.Dispose();
+        if (components != null) components.Dispose();
+      }
+      base.Dispose(disposing);
+    }
+
+    protected override void DeregisterContentEvents() {
+      Content.PropertyChanged -= Content_PropertyChanged;
+      base.DeregisterContentEvents();
+    }
+    protected override void RegisterContentEvents() {
+      base.RegisterContentEvents();
+      Content.PropertyChanged += Content_PropertyChanged;
+    }
+
+    protected override void OnContentChanged() {
+      base.OnContentChanged();
+      SuppressEvents = true;
+      try {
+        if (Content == null) {
+          maxExecutionTimeTextBox.Text = String.Empty;
+          maxEvaluationsTextBox.Text = String.Empty;
+          moveCostPerSolutionTextBox.Text = String.Empty;
+          targetValueTextBox.Text = String.Empty;
+          maximizationCheckBox.CheckState = CheckState.Indeterminate;
+          terminationComboBox.SelectedIndex = -1;
+
+          algorithmViewHost.Content = null;
+          currentRunView.Content = null;
+          runsView.Content = null;
+        } else {
+          maxExecutionTimeTextBox.Text = TimeSpanHelper.FormatNatural(Content.MaximumExecutionTime);
+          maxEvaluationsTextBox.Text = Content.MaximumEvaluations.ToString();
+          moveCostPerSolutionTextBox.Text = Content.MoveCostPerSolution.ToString(CultureInfo.CurrentCulture.NumberFormat);
+          targetValueTextBox.Text = Content.TargetValue.ToString(CultureInfo.CurrentCulture.NumberFormat);
+          maximizationCheckBox.Checked = Content.Maximization;
+          terminationComboBox.SelectedItem = Content.TerminationCriterium;
+
+          algorithmViewHost.Content = Content.Algorithm;
+          currentRunView.Content = Content.CurrentRun;
+          runsView.Content = Content.Runs;
+        }
+      } finally { SuppressEvents = false; }
+    }
+
+    protected override void SetEnabledStateOfControls() {
+      base.SetEnabledStateOfControls();
+      maxExecutionTimeTextBox.Enabled = Content != null && !ReadOnly && !Locked;
+      maxEvaluationsTextBox.Enabled = Content != null && !ReadOnly && !Locked;
+      moveCostPerSolutionTextBox.Enabled = Content != null && !ReadOnly && !Locked;
+      targetValueTextBox.Enabled = Content != null && !ReadOnly && !Locked;
+      maximizationCheckBox.Enabled = Content != null && !ReadOnly && !Locked;
+      terminationComboBox.Enabled = Content != null && !ReadOnly && !Locked;
+      newAlgorithmButton.Enabled = Content != null && !ReadOnly;
+      openAlgorithmButton.Enabled = Content != null && !ReadOnly;
+      algorithmViewHost.Enabled = Content != null;
+      currentRunView.Enabled = Content != null;
+      runsView.Enabled = Content != null;
+    }
+
+    protected override void OnClosed(FormClosedEventArgs e) {
+      if ((Content != null) && (Content.ExecutionState == ExecutionState.Started)) {
+        //The content must be stopped if no other view showing the content is available
+        var optimizers = MainFormManager.MainForm.Views.OfType<IContentView>().Where(v => v != this).Select(v => v.Content).OfType<IAlgorithm>();
+        if (!optimizers.Contains(Content.Algorithm)) {
+          var nestedOptimizers = optimizers.SelectMany(opt => opt.NestedOptimizers);
+          if (!nestedOptimizers.Contains(Content)) Content.Stop();
+        }
+      }
+      base.OnClosed(e);
+    }
+
+    #region Event Handlers
+    #region Content events
+    private void Content_PropertyChanged(object sender, PropertyChangedEventArgs e) {
+      SuppressEvents = true;
+      try {
+        switch (e.PropertyName) {
+          case "TerminationCriterium": terminationComboBox.SelectedItem = Content.TerminationCriterium; break;
+          case "MaximumExecutionTime": maxExecutionTimeTextBox.Text = TimeSpanHelper.FormatNatural(Content.MaximumExecutionTime); break;
+          case "MaximumEvaluations": maxEvaluationsTextBox.Text = Content.MaximumEvaluations.ToString(); break;
+          case "TargetValue": targetValueTextBox.Text = Content.TargetValue.ToString(CultureInfo.CurrentCulture.NumberFormat); break;
+          case "Maximization": maximizationCheckBox.Checked = Content.Maximization; break;
+          case "MoveCostPerSolution": moveCostPerSolutionTextBox.Text = Content.MoveCostPerSolution.ToString(CultureInfo.CurrentCulture.NumberFormat); break;
+          case "Algorithm": algorithmViewHost.Content = Content.Algorithm; break;
+          case "CurrentRun": currentRunView.Content = Content.CurrentRun; break;
+          case "Runs": runsView.Content = Content.Runs; break;
+        }
+      } finally { SuppressEvents = false; }
+    }
+    #endregion
+
+    #region Control events
+    private void maxExecutionTimeTextBox_Validating(object sender, CancelEventArgs e) {
+      if (SuppressEvents) return;
+      if (InvokeRequired) {
+        Invoke((Action<object, CancelEventArgs>)maxExecutionTimeTextBox_Validating, sender, e);
+        return;
+      }
+      TimeSpan ts;
+      if (!TimeSpanHelper.TryGetFromNaturalFormat(maxExecutionTimeTextBox.Text, out ts)) {
+        e.Cancel = !maxExecutionTimeTextBox.ReadOnly && maxExecutionTimeTextBox.Enabled;
+        errorProvider.SetError(maxExecutionTimeTextBox, "Please enter a valid time span, e.g. 20 seconds ; 45s ; 4min ; 1h ; 3 hours ; 2 days ; 4d");
+      } else {
+        Content.MaximumExecutionTime = ts;
+        e.Cancel = false;
+        errorProvider.SetError(maxExecutionTimeTextBox, null);
+      }
+    }
+
+    private void maxEvaluationsTextBox_Validating(object sender, CancelEventArgs e) {
+      if (SuppressEvents) return;
+      if (InvokeRequired) {
+        Invoke((Action<object, CancelEventArgs>)maxEvaluationsTextBox_Validating, sender, e);
+        return;
+      }
+      int value;
+      if (!int.TryParse(maxEvaluationsTextBox.Text, out value)) {
+        e.Cancel = !maxEvaluationsTextBox.ReadOnly && maxEvaluationsTextBox.Enabled;
+        errorProvider.SetError(maxEvaluationsTextBox, "Please enter a valid integer number.");
+      } else {
+        Content.MaximumEvaluations = value;
+        e.Cancel = false;
+        errorProvider.SetError(maxEvaluationsTextBox, null);
+      }
+    }
+
+    private void moveCostPerSolutionTextBox_Validating(object sender, CancelEventArgs e) {
+      if (SuppressEvents) return;
+      if (InvokeRequired) {
+        Invoke((Action<object, CancelEventArgs>)moveCostPerSolutionTextBox_Validating, sender, e);
+        return;
+      }
+      double value;
+      if (!double.TryParse(moveCostPerSolutionTextBox.Text, out value)) {
+        e.Cancel = !moveCostPerSolutionTextBox.ReadOnly && moveCostPerSolutionTextBox.Enabled;
+        errorProvider.SetError(moveCostPerSolutionTextBox, "Please enter a valid integer number.");
+      } else {
+        Content.MoveCostPerSolution = value;
+        e.Cancel = false;
+        errorProvider.SetError(moveCostPerSolutionTextBox, null);
+      }
+    }
+
+    private void targetValueTextBox_Validating(object sender, CancelEventArgs e) {
+      if (SuppressEvents) return;
+      if (InvokeRequired) {
+        Invoke((Action<object, CancelEventArgs>)targetValueTextBox_Validating, sender, e);
+        return;
+      }
+      double value;
+      if (!double.TryParse(targetValueTextBox.Text, out value)) {
+        e.Cancel = !targetValueTextBox.ReadOnly && targetValueTextBox.Enabled;
+        errorProvider.SetError(targetValueTextBox, "Please enter a valid integer number.");
+      } else {
+        Content.TargetValue = value;
+        e.Cancel = false;
+        errorProvider.SetError(targetValueTextBox, null);
+      }
+    }
+
+    private void maximizationCheckBox_CheckedChanged(object sender, EventArgs e) {
+      if (SuppressEvents) return;
+      if (InvokeRequired) {
+        Invoke((Action<object, EventArgs>)maximizationCheckBox_CheckedChanged, sender, e);
+        return;
+      }
+      Content.Maximization = maximizationCheckBox.Checked;
+    }
+
+    private void terminationComboBox_SelectedIndexChanged(object sender, EventArgs e) {
+      if (SuppressEvents) return;
+      if (InvokeRequired) {
+        Invoke((Action<object, EventArgs>)terminationComboBox_SelectedIndexChanged, sender, e);
+        return;
+      }
+      Content.TerminationCriterium = (TerminationCriterium)terminationComboBox.SelectedItem;
+    }
+
+    private void newAlgorithmButton_Click(object sender, EventArgs e) {
+      if (algorithmTypeSelectorDialog == null) {
+        algorithmTypeSelectorDialog = new TypeSelectorDialog { Caption = "Select Algorithm" };
+        algorithmTypeSelectorDialog.TypeSelector.Caption = "Available Algorithms";
+        algorithmTypeSelectorDialog.TypeSelector.Configure(typeof(IAlgorithm)
+          , showNotInstantiableTypes: false, showGenericTypes: false);
+      }
+      if (algorithmTypeSelectorDialog.ShowDialog(this) == DialogResult.OK) {
+        try {
+          Content.Algorithm = (IAlgorithm)algorithmTypeSelectorDialog.TypeSelector.CreateInstanceOfSelectedType();
+        } catch (Exception ex) {
+          ErrorHandling.ShowErrorDialog(this, ex);
+        }
+      }
+    }
+
+    private void openAlgorithmButton_Click(object sender, EventArgs e) {
+      openFileDialog.Title = "Open Algorithm";
+      if (openFileDialog.ShowDialog(this) == DialogResult.OK) {
+        newAlgorithmButton.Enabled = openAlgorithmButton.Enabled = false;
+        algorithmViewHost.Enabled = false;
+
+        ContentManager.LoadAsync(openFileDialog.FileName, delegate(IStorableContent content, Exception error) {
+          try {
+            if (error != null) throw error;
+            var algorithm = content as IAlgorithm;
+            if (algorithm == null)
+              MessageBox.Show(this, "The selected file does not contain an algorithm.", "Invalid File", MessageBoxButtons.OK, MessageBoxIcon.Error);
+            else
+              Content.Algorithm = algorithm;
+          } catch (Exception ex) {
+            ErrorHandling.ShowErrorDialog(this, ex);
+          } finally {
+            Invoke(new Action(delegate() {
+              algorithmViewHost.Enabled = true;
+              newAlgorithmButton.Enabled = openAlgorithmButton.Enabled = true;
+            }));
+          }
+        });
+      }
+    }
+
+    private void algorithmTabPage_DragEnterOver(object sender, DragEventArgs e) {
+      e.Effect = DragDropEffects.None;
+      var alg = e.Data.GetData(Constants.DragDropDataFormat) as IAlgorithm;
+      if (!ReadOnly && alg != null) {
+        if (!typeof(ISingleObjectiveHeuristicOptimizationProblem).IsAssignableFrom(alg.ProblemType))
+          return;
+        if ((e.KeyState & 32) == 32) e.Effect = DragDropEffects.Link;  // ALT key
+        else if ((e.KeyState & 4) == 4) e.Effect = DragDropEffects.Move;  // SHIFT key
+        else if (e.AllowedEffect.HasFlag(DragDropEffects.Copy)) e.Effect = DragDropEffects.Copy;
+        else if (e.AllowedEffect.HasFlag(DragDropEffects.Move)) e.Effect = DragDropEffects.Move;
+        else if (e.AllowedEffect.HasFlag(DragDropEffects.Link)) e.Effect = DragDropEffects.Link;
+      }
+    }
+
+    private void algorithmTabPage_DragDrop(object sender, DragEventArgs e) {
+      if (e.Effect != DragDropEffects.None) {
+        var algorithm = e.Data.GetData(Constants.DragDropDataFormat) as IAlgorithm;
+        if (e.Effect.HasFlag(DragDropEffects.Copy)) algorithm = (IAlgorithm)algorithm.Clone();
+        Content.Algorithm = algorithm;
+      }
+    }
+    #endregion
+    #endregion
+  }
+}
Index: /branches/PerformanceComparison/HeuristicLab.Optimization.Views/3.3/RunCollectionViews/RunCollectionRLDView.Designer.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.Optimization.Views/3.3/RunCollectionViews/RunCollectionRLDView.Designer.cs	(revision 12803)
+++ /branches/PerformanceComparison/HeuristicLab.Optimization.Views/3.3/RunCollectionViews/RunCollectionRLDView.Designer.cs	(revision 12804)
@@ -44,4 +44,5 @@
     /// </summary>
     private void InitializeComponent() {
+      this.components = new System.ComponentModel.Container();
       this.dataTableComboBox = new System.Windows.Forms.ComboBox();
       this.label1 = new System.Windows.Forms.Label();
@@ -50,4 +51,8 @@
       this.groupComboBox = new System.Windows.Forms.ComboBox();
       this.logScalingCheckBox = new System.Windows.Forms.CheckBox();
+      this.targetsTextBox = new System.Windows.Forms.TextBox();
+      this.label3 = new System.Windows.Forms.Label();
+      this.errorProvider = new System.Windows.Forms.ErrorProvider(this.components);
+      ((System.ComponentModel.ISupportInitialize)(this.errorProvider)).BeginInit();
       this.SuspendLayout();
       // 
@@ -81,8 +86,8 @@
       this.viewHost.Content = null;
       this.viewHost.Enabled = false;
-      this.viewHost.Location = new System.Drawing.Point(4, 57);
+      this.viewHost.Location = new System.Drawing.Point(4, 90);
       this.viewHost.Name = "viewHost";
       this.viewHost.ReadOnly = false;
-      this.viewHost.Size = new System.Drawing.Size(520, 291);
+      this.viewHost.Size = new System.Drawing.Size(520, 258);
       this.viewHost.TabIndex = 2;
       this.viewHost.ViewsLabelVisible = true;
@@ -122,15 +127,41 @@
       this.logScalingCheckBox.CheckedChanged += new System.EventHandler(this.logScalingCheckBox_CheckedChanged);
       // 
-      // RunCollectionECDFView
+      // targetsTextBox
+      // 
+      this.targetsTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
+            | System.Windows.Forms.AnchorStyles.Right)));
+      this.targetsTextBox.Location = new System.Drawing.Point(69, 57);
+      this.targetsTextBox.Name = "targetsTextBox";
+      this.targetsTextBox.Size = new System.Drawing.Size(455, 20);
+      this.targetsTextBox.TabIndex = 6;
+      this.targetsTextBox.Validating += new System.ComponentModel.CancelEventHandler(this.targetsTextBox_Validating);
+      // 
+      // label3
+      // 
+      this.label3.AutoSize = true;
+      this.label3.Location = new System.Drawing.Point(3, 60);
+      this.label3.Name = "label3";
+      this.label3.Size = new System.Drawing.Size(46, 13);
+      this.label3.TabIndex = 1;
+      this.label3.Text = "Targets:";
+      // 
+      // errorProvider
+      // 
+      this.errorProvider.ContainerControl = this;
+      // 
+      // RunCollectionRLDView
       // 
       this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Inherit;
+      this.Controls.Add(this.targetsTextBox);
       this.Controls.Add(this.logScalingCheckBox);
       this.Controls.Add(this.groupComboBox);
       this.Controls.Add(this.label2);
       this.Controls.Add(this.viewHost);
+      this.Controls.Add(this.label3);
       this.Controls.Add(this.label1);
       this.Controls.Add(this.dataTableComboBox);
-      this.Name = "RunCollectionECDFView";
+      this.Name = "RunCollectionRLDView";
       this.Size = new System.Drawing.Size(527, 374);
+      ((System.ComponentModel.ISupportInitialize)(this.errorProvider)).EndInit();
       this.ResumeLayout(false);
       this.PerformLayout();
@@ -146,4 +177,7 @@
     private System.Windows.Forms.ComboBox groupComboBox;
     private System.Windows.Forms.CheckBox logScalingCheckBox;
+    private System.Windows.Forms.TextBox targetsTextBox;
+    private System.Windows.Forms.Label label3;
+    protected System.Windows.Forms.ErrorProvider errorProvider;
   }
 }
Index: /branches/PerformanceComparison/HeuristicLab.Optimization.Views/3.3/RunCollectionViews/RunCollectionRLDView.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.Optimization.Views/3.3/RunCollectionViews/RunCollectionRLDView.cs	(revision 12803)
+++ /branches/PerformanceComparison/HeuristicLab.Optimization.Views/3.3/RunCollectionViews/RunCollectionRLDView.cs	(revision 12804)
@@ -42,4 +42,6 @@
     }
 
+    private double[] levels;
+
     private bool suppressUpdates;
     private readonly IndexedDataTable<double> combinedDataTable;
@@ -167,7 +169,12 @@
         var table = (string)dataTableComboBox.SelectedItem;
         if (string.IsNullOrEmpty(table)) return;
-        var maximum = Content.Select(x => ((IndexedDataTable<double>)x.Results[table]).Rows.First().Values.Max(y => y.Item2)).Max();
-        var minimum = Content.Select(x => ((IndexedDataTable<double>)x.Results[table]).Rows.First().Values.Min(y => y.Item2)).Min();
-        var levels = Enumerable.Range(0, 51).Select(x => maximum - (x / 50.0) * (maximum - minimum)).ToArray();
+        if (levels == null) {
+          var worst = Content.Select(x => ((IndexedDataTable<double>)x.Results[table]).Rows.First().Values.Max(y => y.Item2)).First();
+          var best = Content.Select(x => ((IndexedDataTable<double>)x.Results[table]).Rows.First().Values.Min(y => y.Item2)).Last();
+          levels = Enumerable.Range(0, 51).Select(x => worst + (x / 50.0) * (best - worst)).ToArray();
+          suppressTargetsEvents = true;
+          targetsTextBox.Text = string.Join(" ; ", levels);
+          suppressTargetsEvents = false;
+        }
         var selectedGroup = (string)groupComboBox.SelectedItem;
         if (string.IsNullOrEmpty(selectedGroup)) return;
@@ -184,25 +191,23 @@
             var resultsTable = (IndexedDataTable<double>)run.Results[table];
             xAxisTitles.Add(resultsTable.VisualProperties.XAxisTitle);
-            var graph = new LinkedList<Tuple<double, double>>(resultsTable.Rows.First().Values);
-            var current = graph.First.Next;
-            // prune convergence graph to obtain first hit times only
-            while (current != null) {
-              if (current.Value.Item2.IsAlmost(current.Previous.Value.Item2)) {
-                var h = current;
-                current = current.Previous;
-                graph.Remove(h);
-              }
-              current = current.Next;
-            }
+            var values = resultsTable.Rows.First().Values;
+            var maximization = values.First().Item2 < values.Last().Item2;
             var i = 0;
-            current = graph.First;
-            while (i < levels.Length && current != null) {
-              if (current.Value.Item2 < levels[i]) {
-                if (hits.ContainsKey(current.Value.Item1))
-                  hits[current.Value.Item1]++;
-                else hits[current.Value.Item1] = 1;
+            var j = 0;
+            var current = values[j];
+            var prev = Tuple.Create(-1.0, double.NaN);
+            while (i < levels.Length) {
+              if ((double.IsNaN(prev.Item2) || prev.Item2 != current.Item2)
+                  && (maximization && current.Item2 >= levels[i]
+                  || !maximization && current.Item2 <= levels[i])) {
+                if (hits.ContainsKey(current.Item1))
+                  hits[current.Item1]++;
+                else hits[current.Item1] = 1;
                 i++;
               } else {
-                current = current.Next;
+                j++;
+                if (j >= values.Count) break;
+                prev = current;
+                current = values[j];
               }
             }
@@ -266,4 +271,28 @@
       combinedDataTable.VisualProperties.XAxisLogScale = logScalingCheckBox.Checked;
     }
+
+    private bool suppressTargetsEvents;
+    private void targetsTextBox_Validating(object sender, CancelEventArgs e) {
+      if (suppressTargetsEvents) return;
+      var targetStrings = targetsTextBox.Text.Split(new[] { ';', '\t', ' ' }, StringSplitOptions.RemoveEmptyEntries);
+      var targetList = new List<double>();
+      foreach (var ts in targetStrings) {
+        double t;
+        if (!double.TryParse(ts, out t)) {
+          errorProvider.SetError(targetsTextBox, "Not all targets can be parsed: " + ts);
+          e.Cancel = true;
+          return;
+        }
+        targetList.Add(t);
+      }
+      if (targetList.Count == 0) {
+        errorProvider.SetError(targetsTextBox, "Give at least one target value!");
+        e.Cancel = true;
+        return;
+      }
+      e.Cancel = false;
+      errorProvider.SetError(targetsTextBox, null);
+      levels = targetList.ToArray();
+    }
   }
 }
Index: /branches/PerformanceComparison/HeuristicLab.Optimization.Views/3.3/RunView.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.Optimization.Views/3.3/RunView.cs	(revision 12803)
+++ /branches/PerformanceComparison/HeuristicLab.Optimization.Views/3.3/RunView.cs	(revision 12804)
@@ -97,4 +97,8 @@
 
     private void Content_PropertyChanged(object sender, PropertyChangedEventArgs e) {
+      if (InvokeRequired) {
+        Invoke((Action<object, PropertyChangedEventArgs>)Content_PropertyChanged, sender, e);
+        return;
+      }
       if (e.PropertyName == "Color") {
         if (InvokeRequired) this.Invoke((Action)UpdateColor, null);
@@ -112,4 +116,8 @@
 
     private void ParametersOnItemsChanged(object sender, CollectionItemsChangedEventArgs<KeyValuePair<string, IItem>> e) {
+      if (InvokeRequired) {
+        Invoke((Action<object, CollectionItemsChangedEventArgs<KeyValuePair<string, IItem>>>)ParametersOnItemsChanged, sender, e);
+        return;
+      }
       foreach (var item in e.OldItems) {
         listView.Items.Remove(parametersItemToListViewItem[item.Key]);
@@ -124,4 +132,8 @@
 
     private void ParametersOnItemsRemoved(object sender, CollectionItemsChangedEventArgs<KeyValuePair<string, IItem>> e) {
+      if (InvokeRequired) {
+        Invoke((Action<object, CollectionItemsChangedEventArgs<KeyValuePair<string, IItem>>>)ParametersOnItemsRemoved, sender, e);
+        return;
+      }
       foreach (var item in e.Items) {
         listView.Items.Remove(parametersItemToListViewItem[item.Key]);
@@ -131,4 +143,8 @@
 
     private void ResultsOnItemsChanged(object sender, CollectionItemsChangedEventArgs<KeyValuePair<string, IItem>> e) {
+      if (InvokeRequired) {
+        Invoke((Action<object, CollectionItemsChangedEventArgs<KeyValuePair<string, IItem>>>)ResultsOnItemsChanged, sender, e);
+        return;
+      }
       foreach (var item in e.OldItems) {
         listView.Items.Remove(resultsItemToListViewItem[item.Key]);
@@ -143,4 +159,8 @@
 
     private void ResultsOnItemsRemoved(object sender, CollectionItemsChangedEventArgs<KeyValuePair<string, IItem>> e) {
+      if (InvokeRequired) {
+        Invoke((Action<object, CollectionItemsChangedEventArgs<KeyValuePair<string, IItem>>>)ResultsOnItemsRemoved, sender, e);
+        return;
+      }
       foreach (var item in e.Items) {
         listView.Items.Remove(resultsItemToListViewItem[item.Key]);
