Index: /branches/PerformanceComparison/HeuristicLab.Analysis/3.3/Optimizers/IteratedAlgorithm.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.Analysis/3.3/Optimizers/IteratedAlgorithm.cs	(revision 13563)
+++ /branches/PerformanceComparison/HeuristicLab.Analysis/3.3/Optimizers/IteratedAlgorithm.cs	(revision 13564)
@@ -23,4 +23,6 @@
 using System.Linq;
 using System.Threading;
+using System.Threading.Tasks;
+using HeuristicLab.Collections;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
@@ -29,5 +31,4 @@
 using HeuristicLab.Parameters;
 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-using System.Threading.Tasks;
 
 namespace HeuristicLab.Analysis {
@@ -51,12 +52,4 @@
 
     public override Type ProblemType { get { return typeof(ISingleObjectiveHeuristicOptimizationProblem); } }
-    public new ISingleObjectiveHeuristicOptimizationProblem Problem {
-      get { return (ISingleObjectiveHeuristicOptimizationProblem)base.Problem; }
-      set {
-        base.Problem = value;
-        if (Algorithm != null) Algorithm.Problem = Problem;
-        if (Problem != null) UpdateTargetValueFromBestKnownQuality();
-      }
-    }
 
     public IValueParameter<TimeSpanValue> MaximumExecutionTimeParameter {
@@ -82,4 +75,8 @@
     private IValueParameter<IAlgorithm> AlgorithmParameter {
       get { return (IValueParameter<IAlgorithm>)Parameters["Algorithm"]; }
+    }
+
+    private IFixedValueParameter<MultiAnalyzer> AnalyzerParameter {
+      get { return (IFixedValueParameter<MultiAnalyzer>)Parameters["Analyzer"]; }
     }
 
@@ -92,6 +89,17 @@
     [Storable]
     private QualityPerClockAnalyzer perClockAnalyzer;
+    public QualityPerClockAnalyzer PerClockAnalyzer {
+      get { return perClockAnalyzer; }
+    }
     [Storable]
     private QualityPerEvaluationsAnalyzer perEvaluationsAnalyzer;
+    public QualityPerEvaluationsAnalyzer PerEvaluationsAnalyzer {
+      get { return perEvaluationsAnalyzer; }
+    }
+    [Storable]
+    private BestScopeSolutionAnalyzer bestSolutionAnalyzer;
+    public BestScopeSolutionAnalyzer BestSolutionAnalyzer {
+      get { return bestSolutionAnalyzer; }
+    }
 
     public double MoveCostPerSolution {
@@ -105,4 +113,5 @@
     }
 
+    // algorithm will be set in AfterDeserialization to the value of the parameter
     private IAlgorithm algorithm;
     public IAlgorithm Algorithm {
@@ -118,5 +127,6 @@
           if (algorithm.ExecutionState != ExecutionState.Prepared)
             algorithm.Prepare(true);
-          algorithm.Problem = Problem;
+          if (Problem != null)
+            algorithm.Problem = Problem;
           RegisterAlgorithmEvents();
           AddAlgorithmAnalyzers();
@@ -128,6 +138,10 @@
     }
 
+    public MultiAnalyzer Analyzer {
+      get { return AnalyzerParameter.Value; }
+    }
+
     private bool Maximization {
-      get { return Problem != null && ((IValueParameter<BoolValue>)Problem.MaximizationParameter).Value.Value; }
+      get { return Problem != null && ((IValueParameter<BoolValue>)((ISingleObjectiveHeuristicOptimizationProblem)Problem).MaximizationParameter).Value.Value; }
     }
 
@@ -145,5 +159,5 @@
         var targetHit = Maximization && bestQuality >= targetValue || !Maximization && bestQuality <= targetValue;
 
-        return timeHit || evalHit || targetHit;
+        return forceStop || timeHit || evalHit || targetHit;
       }
     }
@@ -156,4 +170,5 @@
       perClockAnalyzer = cloner.Clone(original.perClockAnalyzer);
       perEvaluationsAnalyzer = cloner.Clone(original.perEvaluationsAnalyzer);
+      bestSolutionAnalyzer = cloner.Clone(original.bestSolutionAnalyzer);
       algorithm = cloner.Clone(original.algorithm);
       RegisterEventHandlers();
@@ -162,4 +177,5 @@
       : base() {
       results = new ResultCollection();
+      Parameters.Add(new FixedValueParameter<MultiAnalyzer>("Analyzer", "Analyzers that should be called in addition to the default algorithm analyzers.", new MultiAnalyzer()));
       Parameters.Add(new OptionalValueParameter<TimeSpanValue>("MaximumExecutionTime", "The maximum wall-clock time that the algorithm should run."));
       Parameters.Add(new OptionalValueParameter<IntValue>("MaximumEvaluations", "The maximum number of function evaluations that the algorithm should run.", new IntValue(100000000)));
@@ -171,4 +187,8 @@
       perClockAnalyzer = new QualityPerClockAnalyzer();
       perEvaluationsAnalyzer = new QualityPerEvaluationsAnalyzer();
+      bestSolutionAnalyzer = new BestScopeSolutionAnalyzer();
+      Analyzer.Operators.Add(perClockAnalyzer, true);
+      Analyzer.Operators.Add(perEvaluationsAnalyzer, true);
+      Analyzer.Operators.Add(bestSolutionAnalyzer, StoreSolutionInRun);
 
       RegisterEventHandlers();
@@ -183,4 +203,23 @@
     private void AfterDeserialization() {
       algorithm = AlgorithmParameter.Value;
+      if (!Parameters.ContainsKey("Analyzer")) {
+        Parameters.Add(new FixedValueParameter<MultiAnalyzer>("Analyzer", "Analyzers that should be called in addition to the default algorithm analyzers.", new MultiAnalyzer()));
+        Analyzer.Operators.Add(perClockAnalyzer, true);
+        Analyzer.Operators.Add(perEvaluationsAnalyzer, true);
+        if (Algorithm != null && Algorithm.Parameters.ContainsKey("Analyzer")) {
+          var analyzerParam = Algorithm.Parameters["Analyzer"] as IValueParameter<MultiAnalyzer>;
+          if (analyzerParam != null) {
+            analyzerParam.Value.Operators.Remove(perClockAnalyzer);
+            analyzerParam.Value.Operators.Remove(perEvaluationsAnalyzer);
+          } else {
+            var analyzerParam2 = Algorithm.Parameters["Analyzer"] as IValueParameter<IMultiAnalyzer>;
+            if (analyzerParam2 != null) {
+              analyzerParam2.Value.Operators.Remove(perClockAnalyzer);
+              analyzerParam2.Value.Operators.Remove(perEvaluationsAnalyzer);
+            }
+          }
+          AddAlgorithmAnalyzers();
+        }
+      }
       RegisterEventHandlers();
     }
@@ -188,5 +227,5 @@
     #region Register Event Handlers
     protected override void RegisterProblemEvents() {
-      var bkParam = Problem.BestKnownQualityParameter as IValueParameter<DoubleValue>;
+      var bkParam = ((ISingleObjectiveHeuristicOptimizationProblem)Problem).BestKnownQualityParameter as IValueParameter<DoubleValue>;
       if (bkParam != null) {
         bkParam.ValueChanged += Problem_BestKnownQualityParameter_ValueChanged;
@@ -196,5 +235,5 @@
     protected override void DeregisterProblemEvents() {
       base.DeregisterProblemEvents();
-      var bkParam = Problem.BestKnownQualityParameter as IValueParameter<DoubleValue>;
+      var bkParam = ((ISingleObjectiveHeuristicOptimizationProblem)Problem).BestKnownQualityParameter as IValueParameter<DoubleValue>;
       if (bkParam != null) {
         bkParam.ValueChanged -= Problem_BestKnownQualityParameter_ValueChanged;
@@ -219,4 +258,31 @@
       if (Problem != null) RegisterProblemEvents();
       AlgorithmParameter.ValueChanged += AlgorithmParameterOnValueChanged;
+      StoreSolutionInRunParameter.Value.ValueChanged += StoreSolutionInRunOnValueChanged;
+      Analyzer.Operators.CollectionReset += AnalyzerOperatorsChanged;
+      Analyzer.Operators.ItemsAdded += AnalyzerOperatorsChanged;
+      Analyzer.Operators.ItemsRemoved += AnalyzerOperatorsChanged;
+      Analyzer.Operators.ItemsReplaced += AnalyzerOperatorsChanged;
+    }
+
+    private bool suppressAnalyzerOperatorEvents = false;
+
+    private void AnalyzerOperatorsChanged(object sender, CollectionItemsChangedEventArgs<IndexedItem<IAnalyzer>> e) {
+      if (suppressAnalyzerOperatorEvents) return;
+      if (!Analyzer.Operators.Contains(perClockAnalyzer)) {
+        suppressAnalyzerOperatorEvents = true;
+        try { Analyzer.Operators.Add(perClockAnalyzer, false); } finally { suppressAnalyzerOperatorEvents = false; }
+      }
+      if (!Analyzer.Operators.Contains(perEvaluationsAnalyzer)) {
+        suppressAnalyzerOperatorEvents = true;
+        try { Analyzer.Operators.Add(perEvaluationsAnalyzer, false); } finally { suppressAnalyzerOperatorEvents = false; }
+      }
+      if (!Analyzer.Operators.Contains(bestSolutionAnalyzer)) {
+        suppressAnalyzerOperatorEvents = true;
+        try { Analyzer.Operators.Add(bestSolutionAnalyzer, false); } finally { suppressAnalyzerOperatorEvents = false; }
+      }
+    }
+
+    private void StoreSolutionInRunOnValueChanged(object sender, EventArgs eventArgs) {
+      Analyzer.Operators.SetItemCheckedState(bestSolutionAnalyzer, StoreSolutionInRun);
     }
 
@@ -238,6 +304,5 @@
       base.Start();
       OnStarted();
-      var task = Task.Factory.StartNew(Run, null);
-      task.ContinueWith(t => {
+      Task.Factory.StartNew(Run, null).ContinueWith(t => {
         try {
           t.Wait();
@@ -252,4 +317,5 @@
         if (Algorithm.ExecutionState == ExecutionState.Paused) OnPaused();
         else OnStopped();
+        forceStop = false;
       });
     }
@@ -260,7 +326,15 @@
     }
 
+    private bool forceStop = false;
     public override void Stop() {
       base.Stop();
-      Algorithm.Stop();
+      if (ExecutionState == ExecutionState.Started) {
+        forceStop = true;
+        Algorithm.Stop();
+      } else if (ExecutionState == ExecutionState.Paused) {
+        RoundupResults();
+        Algorithm.Prepare(true);
+        OnStopped();
+      }
     }
     #endregion
@@ -299,52 +373,53 @@
         if (Algorithm.ExecutionState == ExecutionState.Paused) return;
 
-        var execTime = ((TimeSpanValue)Results[ExecutionTimeResultName].Value);
-        var solEvals = ((DoubleValue)Results[EvaluatedSolutionsResultName].Value);
-        var movEvals = ((DoubleValue)Results[EvaluatedMovesResultName].Value);
-        var restarts = ((IntValue)Results[RandomRestartsResultName].Value);
-        var evaluations = ((DoubleValue)Results[EvaluationsResultName].Value);
-        var bestQuality = ((DoubleValue)Results[BestQualityResultName].Value);
-        var improvement = false;
-
-        IResult result;
-        if (Algorithm.Results.TryGetValue(perEvaluationsAnalyzer.EvaluatedSolutionsParameter.ActualName, out result)) {
-          var evals = ((IntValue)result.Value).Value;
-          evaluations.Value += evals;
-          solEvals.Value += evals;
-        }
-        if (Algorithm.Results.TryGetValue(perEvaluationsAnalyzer.EvaluatedMovesParameter.ActualName, out result)) {
-          var evals = ((IntValue)result.Value).Value;
-          evaluations.Value += MoveCostPerSolution * evals;
-          movEvals.Value += evals;
-        }
-        if (Algorithm.Results.TryGetValue(perEvaluationsAnalyzer.BestQualityParameter.ActualName, out result)) {
-          var newBestQuality = ((DoubleValue)result.Value).Value;
-          if (double.IsNaN(bestQuality.Value)
-              || Maximization && newBestQuality > bestQuality.Value
-              || !Maximization && newBestQuality < bestQuality.Value) {
-            bestQuality.Value = newBestQuality;
-            improvement = true;
-          }
-        }
-        if (Algorithm.Results.TryGetValue(perClockAnalyzer.QualityPerClockParameter.ResultName, out result)) {
-          UpdateQualityPerClockResult((IndexedDataTable<double>)result.Value, restarts.Value);
-        }
-        if (Algorithm.Results.TryGetValue(perEvaluationsAnalyzer.QualityPerEvaluationsParameter.ResultName, out result)) {
-          UpdateQualityPerEvaluationsResult((IndexedDataTable<double>)result.Value, restarts.Value);
-        }
-        if (StoreSolutionInRun) {
-          foreach (var r in Algorithm.Results) {
-            if (r.Name.ToLower().EndsWith("solution") && improvement) {
-              if (!Results.TryGetValue(r.Name, out result))
-                Results.Add(new Result(r.Name, (IItem)r.Value.Clone()));
-              else result.Value = (IItem)r.Value.Clone();
-            }
-          }
-        }
-
-        execTime.Value = ExecutionTime;
+        RoundupResults();
 
         Algorithm.Prepare(true);
       } while (!IsFinished);
+    }
+
+    private void RoundupResults() {
+      if (Algorithm == null) return;
+      var execTime = ((TimeSpanValue)Results[ExecutionTimeResultName].Value);
+      var solEvals = ((DoubleValue)Results[EvaluatedSolutionsResultName].Value);
+      var movEvals = ((DoubleValue)Results[EvaluatedMovesResultName].Value);
+      var restarts = ((IntValue)Results[RandomRestartsResultName].Value);
+      var evaluations = ((DoubleValue)Results[EvaluationsResultName].Value);
+      var bestQuality = ((DoubleValue)Results[BestQualityResultName].Value);
+      var improvement = false;
+
+      IResult result;
+      if (Algorithm.Results.TryGetValue(perEvaluationsAnalyzer.EvaluatedSolutionsParameter.ActualName, out result)) {
+        var evals = ((IntValue)result.Value).Value;
+        evaluations.Value += evals;
+        solEvals.Value += evals;
+      }
+      if (Algorithm.Results.TryGetValue(perEvaluationsAnalyzer.EvaluatedMovesParameter.ActualName, out result)) {
+        var evals = ((IntValue)result.Value).Value;
+        evaluations.Value += MoveCostPerSolution * evals;
+        movEvals.Value += evals;
+      }
+      if (Algorithm.Results.TryGetValue(perEvaluationsAnalyzer.BestQualityParameter.ActualName, out result)) {
+        var newBestQuality = ((DoubleValue)result.Value).Value;
+        if (double.IsNaN(bestQuality.Value)
+            || Maximization && newBestQuality > bestQuality.Value
+            || !Maximization && newBestQuality < bestQuality.Value) {
+          bestQuality.Value = newBestQuality;
+          improvement = true;
+        }
+      }
+      if (Algorithm.Results.TryGetValue(perClockAnalyzer.QualityPerClockParameter.ResultName, out result)) UpdateQualityPerClockResult((IndexedDataTable<double>)result.Value, restarts.Value);
+      if (Algorithm.Results.TryGetValue(perEvaluationsAnalyzer.QualityPerEvaluationsParameter.ResultName, out result)) UpdateQualityPerEvaluationsResult((IndexedDataTable<double>)result.Value, restarts.Value);
+      if (StoreSolutionInRun) {
+        foreach (var r in Algorithm.Results) {
+          if (r.Name == bestSolutionAnalyzer.BestSolutionResultName || r.Name.ToLower().EndsWith("solution") && improvement) {
+            if (!Results.TryGetValue(r.Name, out result))
+              Results.Add(new Result(r.Name, (IItem)r.Value.Clone()));
+            else result.Value = (IItem)r.Value.Clone();
+          }
+        }
+      }
+
+      execTime.Value = ExecutionTime;
     }
 
@@ -439,5 +514,5 @@
 
     private void UpdateTargetValueFromBestKnownQuality() {
-      var bkParam = Problem.BestKnownQualityParameter as IValueParameter<DoubleValue>;
+      var bkParam = ((ISingleObjectiveHeuristicOptimizationProblem)Problem).BestKnownQualityParameter as IValueParameter<DoubleValue>;
       if (bkParam != null && bkParam.Value != null)
         TargetValueParameter.Value = new DoubleValue(bkParam.Value.Value);
@@ -451,19 +526,11 @@
       var analyzerParam = Algorithm.Parameters["Analyzer"] as IValueParameter<MultiAnalyzer>;
       if (analyzerParam != null) {
-        foreach (var analyzer in analyzerParam.Value.Operators.OfType<QualityPerClockAnalyzer>().ToList())
-          analyzerParam.Value.Operators.Remove(analyzer);
-        analyzerParam.Value.Operators.Add(perClockAnalyzer);
-        foreach (var analyzer in analyzerParam.Value.Operators.OfType<QualityPerEvaluationsAnalyzer>().ToList())
-          analyzerParam.Value.Operators.Remove(analyzer);
-        analyzerParam.Value.Operators.Add(perEvaluationsAnalyzer);
+        if (analyzerParam.Value.Operators.Contains(Analyzer)) return;
+        analyzerParam.Value.Operators.Add(Analyzer, true);
       } else {
         var analyzerParam2 = Algorithm.Parameters["Analyzer"] as IValueParameter<IMultiAnalyzer>;
         if (analyzerParam2 == null) return;
-        foreach (var analyzer in analyzerParam2.Value.Operators.OfType<QualityPerClockAnalyzer>().ToList())
-          analyzerParam2.Value.Operators.Remove(analyzer);
-        analyzerParam2.Value.Operators.Add(perClockAnalyzer);
-        foreach (var analyzer in analyzerParam2.Value.Operators.OfType<QualityPerEvaluationsAnalyzer>().ToList())
-          analyzerParam2.Value.Operators.Remove(analyzer);
-        analyzerParam2.Value.Operators.Add(perEvaluationsAnalyzer);
+        if (analyzerParam2.Value.Operators.Contains(Analyzer)) return;
+        analyzerParam2.Value.Operators.Add(Analyzer, true);
       }
     }
@@ -474,11 +541,9 @@
       var analyzerParam = Algorithm.Parameters["Analyzer"] as IValueParameter<MultiAnalyzer>;
       if (analyzerParam != null) {
-        analyzerParam.Value.Operators.Remove(perClockAnalyzer);
-        analyzerParam.Value.Operators.Remove(perEvaluationsAnalyzer);
+        analyzerParam.Value.Operators.Remove(Analyzer);
       } else {
         var analyzerParam2 = Algorithm.Parameters["Analyzer"] as IValueParameter<IMultiAnalyzer>;
         if (analyzerParam2 != null) {
-          analyzerParam2.Value.Operators.Remove(perClockAnalyzer);
-          analyzerParam2.Value.Operators.Remove(perEvaluationsAnalyzer);
+          analyzerParam2.Value.Operators.Remove(Analyzer);
         }
       }
@@ -490,7 +555,9 @@
     }
     private void Algorithm_Paused(object sender, EventArgs e) {
+      if (ExecutionState == ExecutionState.Paused) return;
       algorithmWaitHandle.Set();
     }
     private void Algorithm_Stopped(object sender, EventArgs e) {
+      if (ExecutionState == ExecutionState.Paused) return;
       algorithmWaitHandle.Set();
     }
@@ -519,4 +586,10 @@
     protected override void Problem_OperatorsChanged(object sender, EventArgs eventArgs) {
       if (Algorithm != null) AddAlgorithmAnalyzers();
+    }
+
+    protected override void OnProblemChanged() {
+      base.OnProblemChanged();
+      if (Algorithm != null) Algorithm.Problem = Problem;
+      if (Problem != null) UpdateTargetValueFromBestKnownQuality();
     }
 
Index: /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Views/3.3/ExpertSystemView.cs
===================================================================
--- /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Views/3.3/ExpertSystemView.cs	(revision 13563)
+++ /branches/PerformanceComparison/HeuristicLab.OptimizationExpertSystem.Views/3.3/ExpertSystemView.cs	(revision 13564)
@@ -208,5 +208,5 @@
 
     private void OkbDownloadButtonOnClick(object sender, EventArgs e) {
-      if (Content.Problem.ProblemId < 0) {
+      if (Content.Problem.ProblemId != -1) {
         MessageBox.Show("Please select a problem instance first.");
         return;
