Index: /branches/CFSAP/HeuristicLab.Problems.Scheduling.CFSAP/3.3/CFSAP.cs
===================================================================
--- /branches/CFSAP/HeuristicLab.Problems.Scheduling.CFSAP/3.3/CFSAP.cs	(revision 15532)
+++ /branches/CFSAP/HeuristicLab.Problems.Scheduling.CFSAP/3.3/CFSAP.cs	(revision 15533)
@@ -112,5 +112,5 @@
 
     public int Evaluate(Permutation order, BinaryVector assignment) {
-      return EvaluateAssignement(order, assignment, ProcessingTimes, SetupTimes);
+      return EvaluateAssignment(order, assignment, ProcessingTimes, SetupTimes);
     }
 
@@ -147,5 +147,5 @@
 
     //Function to evaluate individual with the specified assignment
-    public static int EvaluateAssignement(Permutation order, BinaryVector assignment, IntMatrix processingTimes, ItemList<IntMatrix> setupTimes) {
+    public static int EvaluateAssignment(Permutation order, BinaryVector assignment, IntMatrix processingTimes, ItemList<IntMatrix> setupTimes) {
       if (processingTimes.Rows != 2) throw new ArgumentException("Method can only be used when there are two machines.", "assignment");
       var N = order.Length;
Index: /branches/CFSAP/HeuristicLab.Problems.Scheduling.CFSAP/3.3/GeneticAlgorithm.cs
===================================================================
--- /branches/CFSAP/HeuristicLab.Problems.Scheduling.CFSAP/3.3/GeneticAlgorithm.cs	(revision 15532)
+++ /branches/CFSAP/HeuristicLab.Problems.Scheduling.CFSAP/3.3/GeneticAlgorithm.cs	(revision 15533)
@@ -35,4 +35,6 @@
 
 namespace HeuristicLab.Problems.Scheduling.CFSAP {
+  public enum OptimalAssignmentType { None, Polynomial, OneOpt, Both };
+
   [Item("Genetic Algorithm (CFSAP)", "")]
   [StorableClass]
@@ -79,4 +81,9 @@
       get { return pauseAfterGenerationParameter; }
     }
+    [Storable]
+    private IFixedValueParameter<EnumValue<OptimalAssignmentType>> optimalAssignmentParameter;
+    public IFixedValueParameter<EnumValue<OptimalAssignmentType>> OptimalAssignmentParameter {
+      get { return optimalAssignmentParameter; }
+    }
 
     public int PopulationSize {
@@ -103,4 +110,8 @@
       get { return pauseAfterGenerationParameter.Value.Value; }
       set { pauseAfterGenerationParameter.Value.Value = value; }
+    }
+    public OptimalAssignmentType OptimalAssignment {
+      get { return optimalAssignmentParameter.Value.Value; }
+      set { optimalAssignmentParameter.Value.Value = value; }
     }
 
@@ -115,7 +126,10 @@
       maximumEvaluatedSolutionsParameter = cloner.Clone(original.maximumEvaluatedSolutionsParameter);
       pauseAfterGenerationParameter = cloner.Clone(original.pauseAfterGenerationParameter);
+      optimalAssignmentParameter = cloner.Clone(original.optimalAssignmentParameter);
+
       generation = original.generation;
       evaluatedSolutions = original.evaluatedSolutions;
       bestQuality = original.bestQuality;
+
       if (original.population != null)
         population = original.population.Select(cloner.Clone).ToArray();
@@ -126,5 +140,5 @@
     }
     public GeneticAlgorithm() {
-      Parameters.Add(populationSizeParameter = new FixedValueParameter<IntValue>("PopulationSize", "The size of the population, each individual of the population is a solution with a permutation and a binary vector.", new IntValue(100)));
+      Parameters.Add(populationSizeParameter = new FixedValueParameter<IntValue>("PopulationSize", "The size of the population, each individual of the population is a solution with a permutation and a binary vector.", new IntValue(500)));
       Parameters.Add(elitesParameter = new FixedValueParameter<IntValue>("Elites", "The number of best individuals from the previous population that will continue to the next generation.", new IntValue(1)));
       Parameters.Add(mutationProbabilityParameter = new FixedValueParameter<PercentValue>("MutationProbability", "The probability that an individual should be mutated after it has been created through crossover.", new PercentValue(0.05)));
@@ -132,4 +146,5 @@
       Parameters.Add(maximumEvaluatedSolutionsParameter = new FixedValueParameter<IntValue>("MaximumEvaluatedSolutions", "The number of evaluated solutions before the algorithm terminates.", new IntValue(100000000)));
       Parameters.Add(pauseAfterGenerationParameter = new FixedValueParameter<BoolValue>("PauseAfterGeneration", "Whether the algorithm should pause after each generation.", new BoolValue(true)));
+      Parameters.Add(optimalAssignmentParameter = new FixedValueParameter<EnumValue<OptimalAssignmentType>>("OptimalAssignment", "Which optimal assignment strategy should be used.", new EnumValue<OptimalAssignmentType>(OptimalAssignmentType.Polynomial)));
     }
 
@@ -194,4 +209,5 @@
             Assignment = CrossAssignment(parent1.Assignment, parent2.Assignment)
           };
+
           var mutProb = random.NextDouble();
           if (mutProb < MutationProbability) {
@@ -199,17 +215,26 @@
             MutateAssignment(nextGeneration[p].Assignment);
           }
+
           nextGeneration[p].Quality = Problem.Evaluate(nextGeneration[p].Sequence, nextGeneration[p].Assignment);
           evaluatedSolutions++;
 
           if (nextGeneration[p].Quality <= bestQuality) {
-            if (!optimalSequences.Contains(nextGeneration[p].Sequence)) {
-              int cycleTime;
-              var assignment = OptimalAssignment.MakeAssignment(nextGeneration[p].Sequence, Problem.ProcessingTimes, Problem.SetupTimes, out cycleTime);
-              evaluatedSolutions++;
-              nextGeneration[p].Assignment = new BinaryVector(assignment.Select(x => x == 1).ToArray());
-              nextGeneration[p].Quality = cycleTime;
-              optimalSequences.Add(nextGeneration[p].Sequence);
+            switch (OptimalAssignment) {
+              case OptimalAssignmentType.None:
+                break;
+              case OptimalAssignmentType.Polynomial:
+                OptimalPolynomialAssignment(nextGeneration[p]);
+                break;
+              case OptimalAssignmentType.OneOpt:
+                OneOptAssignment(nextGeneration[p]);
+                break;
+              case OptimalAssignmentType.Both:
+                HybridAssignment(nextGeneration[p]);
+                break;
+              default:
+                throw new InvalidOperationException("Optimal assignment strategy not defined.");
             }
-            if (nextGeneration[p].Quality < bestQuality) {
+
+          if (nextGeneration[p].Quality < bestQuality) {
               bestQuality = nextGeneration[p].Quality;
               ((DoubleValue)Results["BestQuality"].Value).Value = bestQuality;
@@ -232,4 +257,30 @@
           break;
         }
+      }
+    }
+
+    private void OptimalPolynomialAssignment(EncodedSolution generation) {
+      if (!optimalSequences.Contains(generation.Sequence)) {
+        var assignment = Scheduling.CFSAP.OptimalPolynomialAssignment.MakeAssignment(generation.Sequence, Problem.ProcessingTimes, Problem.SetupTimes, out var cycleTime);
+        evaluatedSolutions++;
+        generation.Assignment = new BinaryVector(assignment.Select(x => x == 1).ToArray());
+        generation.Quality = cycleTime;
+        optimalSequences.Add(generation.Sequence);
+      }
+    }
+
+    private void OneOptAssignment(EncodedSolution generation) {
+      var assignment = Scheduling.CFSAP.OneOptAssignment.MakeAssignment(generation.Sequence, generation.Assignment, Problem.ProcessingTimes, Problem.SetupTimes, out var cycleTime);
+      evaluatedSolutions++;
+      generation.Assignment = assignment;
+      generation.Quality = cycleTime;
+    }
+
+    private void HybridAssignment(EncodedSolution generation) {
+      var a = random.Next(2);
+      switch (a) {
+        case 0: OptimalPolynomialAssignment(generation); break;
+        case 1: OneOptAssignment(generation); break;
+        default: throw new InvalidOperationException("Assignment not defined.");
       }
     }
@@ -257,6 +308,6 @@
 
     private void MutateSequence(Permutation sequence) {
-      var cx = random.Next(7);
-      switch (cx) {
+      var m = random.Next(7);
+      switch (m) {
         case 0: InversionManipulator.Apply(random, sequence); break;
         case 1: InsertionManipulator.Apply(random, sequence); break;
@@ -266,5 +317,5 @@
         case 5: TranslocationInversionManipulator.Apply(random, sequence); break;
         case 6: ScrambleManipulator.Apply(random, sequence); break;
-        default: throw new InvalidOperationException("Crossover not defined.");
+        default: throw new InvalidOperationException("Manipulator not defined.");
       }
     }
@@ -284,19 +335,26 @@
     }
 
-    private class EncodedSolution : IDeepCloneable, IComparable<EncodedSolution> {
+    [StorableClass]
+    private class EncodedSolution : DeepCloneable, IComparable<EncodedSolution> {
+      [Storable]
       public Permutation Sequence { get; set; }
+      [Storable]
       public BinaryVector Assignment { get; set; }
+      [Storable]
       public double Quality { get; set; }
 
-      public IDeepCloneable Clone(Cloner cloner) {
-        return new EncodedSolution() {
-          Sequence = cloner.Clone(this.Sequence),
-          Assignment = cloner.Clone(this.Assignment),
-          Quality = this.Quality
-        };
-      }
-
-      public object Clone() {
-        return Clone(new Cloner());
+      [StorableConstructor]
+      private EncodedSolution(bool deserializing) { }
+
+      private EncodedSolution(EncodedSolution original, Cloner cloner) : base(original, cloner) {
+        Sequence = cloner.Clone(original.Sequence);
+        Assignment = cloner.Clone(original.Assignment);
+        Quality = original.Quality;
+      }
+
+      public EncodedSolution() { }
+
+      public override IDeepCloneable Clone(Cloner cloner) {
+        return new EncodedSolution(this, cloner);
       }
 
Index: /branches/CFSAP/HeuristicLab.Problems.Scheduling.CFSAP/3.3/HeuristicLab.Problems.Scheduling.CFSAP-3.3.csproj
===================================================================
--- /branches/CFSAP/HeuristicLab.Problems.Scheduling.CFSAP/3.3/HeuristicLab.Problems.Scheduling.CFSAP-3.3.csproj	(revision 15532)
+++ /branches/CFSAP/HeuristicLab.Problems.Scheduling.CFSAP/3.3/HeuristicLab.Problems.Scheduling.CFSAP-3.3.csproj	(revision 15533)
@@ -130,5 +130,6 @@
     <Compile Include="MultiNestCFSAP.cs" />
     <Compile Include="MultiNestCFSAPSolvingStrategy.cs" />
-    <Compile Include="OptimalAssignment.cs" />
+    <Compile Include="OneOptAssignment.cs" />
+    <Compile Include="OptimalPolynomialAssignment.cs" />
     <Compile Include="Plugin.cs" />
     <None Include="Properties\AssemblyInfo.cs.frame" />
Index: /branches/CFSAP/HeuristicLab.Problems.Scheduling.CFSAP/3.3/MultiNestCFSAPSolvingStrategy.cs
===================================================================
--- /branches/CFSAP/HeuristicLab.Problems.Scheduling.CFSAP/3.3/MultiNestCFSAPSolvingStrategy.cs	(revision 15532)
+++ /branches/CFSAP/HeuristicLab.Problems.Scheduling.CFSAP/3.3/MultiNestCFSAPSolvingStrategy.cs	(revision 15533)
@@ -12,5 +12,5 @@
 
 namespace HeuristicLab.Problems.Scheduling.CFSAP {
-  [Item("MultiNest CFSAP Solver", "Solving strategy that applies an algorithm instace to the worst nest.")]
+  [Item("MultiNest CFSAP Solver", "Solving strategy that applies an algorithm instance to the worst nest.")]
   [StorableClass]
   [Creatable(CreatableAttribute.Categories.Algorithms)]
@@ -33,7 +33,18 @@
     }
 
-
     public IFixedValueParameter<StringValue> EvaluatedSolutionsNameParameter {
       get { return (IFixedValueParameter<StringValue>)Parameters["EvaluatedSolutionsName"]; }
+    }
+
+    public IValueParameter<BoolValue> RestartParameter {
+      get { return (IValueParameter<BoolValue>)Parameters["Restart"]; }
+    }
+
+    public IValueParameter<IntValue> MinTriesParameter {
+      get { return (IValueParameter<IntValue>)Parameters["Restart.MinTries"]; }
+    }
+
+    public IValueParameter<DoubleValue> LastSuccessPercentageParameter {
+      get { return (IValueParameter<DoubleValue>)Parameters["Restart.LastSuccessPercentage"]; }
     }
 
@@ -53,6 +64,22 @@
     }
 
+    public bool Restart {
+      get => RestartParameter.Value.Value;
+      set => RestartParameter.Value.Value = value;
+    }
+
+    public int MinTries {
+      get => MinTriesParameter.Value.Value;
+      set => MinTriesParameter.Value.Value = value;
+    }
+
+    public double LastSuccessPercentage {
+      get => LastSuccessPercentageParameter.Value.Value;
+      set => LastSuccessPercentageParameter.Value.Value = value;
+    }
+
     [StorableConstructor]
     protected MultiNestCFSAPSolvingStrategy(bool deserializing) : base(deserializing) { }
+
     protected MultiNestCFSAPSolvingStrategy(MultiNestCFSAPSolvingStrategy original, Cloner cloner)
       : base(original, cloner) {
@@ -67,15 +94,22 @@
       if (original.qualityPerEvaluations != null)
         qualityPerEvaluations = cloner.Clone(original.qualityPerEvaluations);
-    }
+
+      restart = original.restart;
+      minTries = original.minTries;
+      lastSuccessPercentage = original.lastSuccessPercentage;
+    }
+
     public MultiNestCFSAPSolvingStrategy() {
       Parameters.Add(new ValueParameter<IAlgorithm>("Solver", "The actual solver template.") { GetsCollected = false });
       Parameters.Add(new FixedValueParameter<TimeSpanValue>("MaximumRuntime", "The maximum time that the strategy should run.", new TimeSpanValue(TimeSpan.FromSeconds(60))));
       Parameters.Add(new FixedValueParameter<StringValue>("EvaluatedSolutionsName", "The name of the result that shows the number of evaluated solutions by the actual solver.", new StringValue("EvaluatedSolutions")));
-    }
-    
+      Parameters.Add(new ValueParameter<BoolValue>("Restart", "Whether the worst algorithm should be restarted, if it doesn't find any better solutions.", new BoolValue(restart)));
+      Parameters.Add(new ValueParameter<IntValue>("Restart.MinTries", "The minimum number of tries before the worst algorithm is restarted.", new IntValue(minTries)));
+      Parameters.Add(new ValueParameter<DoubleValue>("Restart.LastSuccessPercentage", "Only if the last found best solution is older than x percent of the total number of tries, the worst algorithm is restarted.", new DoubleValue(lastSuccessPercentage)));
+    }
+
     public override IDeepCloneable Clone(Cloner cloner) {
       return new MultiNestCFSAPSolvingStrategy(this, cloner);
     }
-
 
     [StorableHook(HookType.AfterDeserialization)]
@@ -83,4 +117,10 @@
       if (!Parameters.ContainsKey("EvaluatedSolutionsName"))
         Parameters.Add(new FixedValueParameter<StringValue>("EvaluatedSolutionsName", "The name of the result that shows the number of evaluated solutions by the actual solver.", new StringValue("EvaluatedSolutions")));
+      if (!Parameters.ContainsKey("Restart"))
+        Parameters.Add(new ValueParameter<BoolValue>(nameof(Restart), "Whether the worst algorithm should be restarted, if it doesn't find any better solutions.", new BoolValue(restart)));
+      if (!Parameters.ContainsKey("Restart.MinTries"))
+        Parameters.Add(new ValueParameter<IntValue>("Restart.MinTries", "The minimum number of tries before the worst algorithm is restarted.", new IntValue(minTries)));
+      if (!Parameters.ContainsKey("Restart.LastSuccessPercentage"))
+        Parameters.Add(new ValueParameter<DoubleValue>("Restart.LastSuccessPercentage", "Only if the last found best solution is older than x percent of the total number of tries, the worst algorithm is restarted.", new DoubleValue(lastSuccessPercentage)));
     }
 
@@ -95,4 +135,10 @@
     [Storable]
     private IndexedDataTable<double> qualityPerEvaluations;
+    [Storable]
+    private bool restart = true;
+    [Storable]
+    private int minTries = 10000;
+    [Storable]
+    private double lastSuccessPercentage = 0.1;
 
     protected override void OnPrepared() {
@@ -117,5 +163,5 @@
         cfsap.UpdateEncoding();
         algorithms.Add(clone);
-        algorithmsResults.Add(new Result("Nest " + (n + 1), clone.Results));
+        algorithmsResults.Add(new Result($"Nest {n + 1}", clone.Results));
         clone.Start();
       }
@@ -133,10 +179,11 @@
       qualityPerEvaluations.Rows.Add(qpeRow);
       double evaluations = GetEvaluatedSolutions();
-      qpeRow.Values.Add(Tuple.Create((double)evaluations, (double)min));
-      qpeRow.Values.Add(Tuple.Create((double)evaluations, (double)min));
+      qpeRow.Values.Add(Tuple.Create(evaluations, (double)min));
+      qpeRow.Values.Add(Tuple.Create(evaluations, (double)min));
 
       Results.Add(new Result("Nest with maximum T", new IntValue(worst.Index + 1)));
       Results.Add(new Result("Maximum T", new IntValue(min)));
       Results.Add(new Result("BestQuality", new DoubleValue(min)));
+      Results.Add(new Result("Best Solution Found After Evaluated Solutions", new DoubleValue(evaluations)));
       Results.Add(new Result("Best Solution Found At", new TimeSpanValue(ExecutionTime)));
       Results.Add(new Result("Delta T", new PercentValue((min - Problem.BestKnownQuality) / Problem.BestKnownQuality)));
@@ -144,4 +191,7 @@
       Results.Add(new Result("QualityPerClock", qualityPerClock));
       Results.Add(new Result("QualityPerEvaluations", qualityPerEvaluations));
+      Results.Add(new Result("Tries", new IntValue(nests)));
+      Results.Add(new Result("Nests", new IntValue(nests)));
+      Results.Add(new Result("Jobs", new IntValue(Problem.ProcessingTimes.First().Count() / Problem.SetupTimes.First().Count())));
 
       base.Initialize(cancellationToken);
@@ -149,44 +199,82 @@
 
     private double GetEvaluatedSolutions() {
-      if (algorithmsResults == null) throw new InvalidOperationException("Strategy has not been started yet.");
+      if (algorithmsResults == null)
+        throw new InvalidOperationException("Strategy has not been started yet.");
       return algorithmsResults.Select(x => {
-        IResult res;
-        if (((ResultCollection)x.Value).TryGetValue(EvaluatedSolutionsName, out res)) {
+        if (((ResultCollection)x.Value).TryGetValue(EvaluatedSolutionsName, out var res)) {
           var itm = res.Value;
-          if (itm is IntValue) return ((IntValue)itm).Value;
-          else if (itm is DoubleValue) return ((DoubleValue)itm).Value;
+          if (itm is IntValue)
+            return ((IntValue)itm).Value;
+          else if (itm is DoubleValue)
+            return ((DoubleValue)itm).Value;
         }
-        throw new InvalidOperationException("No result " + EvaluatedSolutionsName + " in the collection of " + x.Name);
+        throw new InvalidOperationException($"No result {EvaluatedSolutionsName} in the collection of {x.Name}");
       }).Sum();
     }
 
     protected override void Run(CancellationToken cancellationToken) {
+      var evaluationsPrevTries = 0.0;
       var worst = qualities.Select((v, i) => new { Index = i, Quality = v }).MaxItems(x => x.Quality).First();
       var min = worst.Quality;
 
-      while (ExecutionTime < MaximumRuntime) {
-        algorithms[worst.Index].Start(cancellationToken);
-        qualities[worst.Index] = (int)((DoubleValue)algorithms[worst.Index].Results["BestQuality"].Value).Value;
-        worst = qualities.Select((v, i) => new { Index = i, Quality = v }).MaxItems(x => x.Quality).First();
-
-        var evaluations = GetEvaluatedSolutions();
-        var time = ExecutionTime.TotalSeconds;
-        var qpcRow = qualityPerClock.Rows.First();
-        var qpeRow = qualityPerEvaluations.Rows.First();
-        qpcRow.Values[qpcRow.Values.Count - 1] = Tuple.Create(time, (double)min);
-        qpeRow.Values[qpeRow.Values.Count - 1] = Tuple.Create(evaluations, (double)min);
-
-        if (worst.Quality < min) {
-          min = worst.Quality;
-          ((IntValue)Results["Nest with maximum T"].Value).Value = worst.Index + 1;
-          ((IntValue)Results["Maximum T"].Value).Value = min;
-          ((DoubleValue)Results["BestQuality"].Value).Value = min;
-          ((TimeSpanValue)Results["Best Solution Found At"].Value).Value = TimeSpan.FromSeconds(time);
-          ((PercentValue)Results["Delta T"].Value).Value = (min - Problem.BestKnownQuality) / Problem.BestKnownQuality;
-          qpcRow.Values.Add(Tuple.Create(time, (double)min));
-          qpeRow.Values.Add(Tuple.Create(evaluations, (double)min));
+      var overallBestQualities = algorithms.Select(a => ((DoubleValue)a.Results["BestQuality"].Value).Value).ToArray();
+
+      do {
+        var tries = 0;
+        var lastSuccess = 0;
+
+        while (ExecutionTime < MaximumRuntime && !cancellationToken.IsCancellationRequested &&
+            (!Restart || (tries < MinTries || (tries - lastSuccess) < tries * LastSuccessPercentage))) {
+          ++tries;
+          ++((IntValue)Results["Tries"].Value).Value;
+
+          algorithms[worst.Index].Start(cancellationToken);
+          qualities[worst.Index] = (int)((DoubleValue)algorithms[worst.Index].Results["BestQuality"].Value).Value;
+          worst = qualities.Select((v, i) => new { Index = i, Quality = v }).MaxItems(x => x.Quality).First();
+
+          var evaluations = evaluationsPrevTries + GetEvaluatedSolutions();
+          var time = ExecutionTime.TotalSeconds;
+          var qpcRow = qualityPerClock.Rows.First();
+          var qpeRow = qualityPerEvaluations.Rows.First();
+          qpcRow.Values[qpcRow.Values.Count - 1] = Tuple.Create(time, (double)Math.Min(worst.Quality, min));
+          qpeRow.Values[qpeRow.Values.Count - 1] = Tuple.Create(evaluations, (double)Math.Min(worst.Quality, min));
+
+          if (worst.Quality < min) {
+            min = worst.Quality;
+            overallBestQualities[worst.Index] = min;
+            ((IntValue)Results["Nest with maximum T"].Value).Value = worst.Index + 1;
+            ((IntValue)Results["Maximum T"].Value).Value = min;
+            ((DoubleValue)Results["BestQuality"].Value).Value = min;
+            ((DoubleValue)Results["Best Solution Found After Evaluated Solutions"].Value).Value = evaluations;
+            ((TimeSpanValue)Results["Best Solution Found At"].Value).Value = TimeSpan.FromSeconds(time);
+            ((PercentValue)Results["Delta T"].Value).Value = (min - Problem.BestKnownQuality) / Problem.BestKnownQuality;
+            qpcRow.Values.Add(Tuple.Create(time, (double)min));
+            qpeRow.Values.Add(Tuple.Create(evaluations, (double)min));
+            lastSuccess = tries;
+          }
         }
 
-        if (cancellationToken.IsCancellationRequested) return;
+        if (cancellationToken.IsCancellationRequested || ExecutionTime >= MaximumRuntime || !Restart)
+          break;
+
+        evaluationsPrevTries += GetEvaluatedSolutions();
+
+        // restart worst algorithm
+        var worstAlgorithm = algorithms[worst.Index];
+        var prevGenerations = ((IntValue)worstAlgorithm.Results["Generation"].Value).Value;
+        var prevEvaluatedSolutions = ((IntValue)worstAlgorithm.Results["EvaluatedSolutions"].Value).Value;
+
+        worstAlgorithm.Prepare();
+        worstAlgorithm.Start(cancellationToken);
+        ++((IntValue)Results["Tries"].Value).Value;
+
+        ((IntValue)worstAlgorithm.Results["Generation"].Value).Value += prevGenerations;
+        ((IntValue)worstAlgorithm.Results["EvaluatedSolutions"].Value).Value += prevEvaluatedSolutions;
+      } while (Restart);
+
+      for (var i = 0; i < algorithms.Count(); ++i) {
+        if (overallBestQualities[i] < ((DoubleValue)algorithms[i].Results["BestQuality"].Value).Value) {
+          ((DoubleValue)algorithms[i].Results["BestQuality"].Value).Value = overallBestQualities[i];
+        }
       }
     }
Index: /branches/CFSAP/HeuristicLab.Problems.Scheduling.CFSAP/3.3/OneOptAssignment.cs
===================================================================
--- /branches/CFSAP/HeuristicLab.Problems.Scheduling.CFSAP/3.3/OneOptAssignment.cs	(revision 15533)
+++ /branches/CFSAP/HeuristicLab.Problems.Scheduling.CFSAP/3.3/OneOptAssignment.cs	(revision 15533)
@@ -0,0 +1,55 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2017 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.Linq;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.BinaryVectorEncoding;
+using HeuristicLab.Encodings.PermutationEncoding;
+
+namespace HeuristicLab.Problems.Scheduling.CFSAP {
+  public static class OneOptAssignment {
+
+    public static BinaryVector MakeAssignment(Permutation order, BinaryVector assignment, IntMatrix processingTimes, ItemList<IntMatrix> setupTimes, out int T) {
+      var oneOptAssignment = (BinaryVector)assignment.Clone();
+      T = CFSAP.EvaluateAssignment(order, assignment, processingTimes, setupTimes);
+
+      while (true) {
+        var foundBetterSolution = false;
+
+        for (var i = 0; i < oneOptAssignment.Length; ++i) {
+          var newAssignment = (BinaryVector)oneOptAssignment.Clone();
+          newAssignment[i] = !newAssignment[i];
+          int newT = CFSAP.EvaluateAssignment(order, newAssignment, processingTimes, setupTimes);
+          if (newT < T) { // new best solution has been found
+            oneOptAssignment = newAssignment;
+            T = newT;
+            foundBetterSolution = true;
+            break;
+          }
+        }
+
+        if (!foundBetterSolution)
+          return oneOptAssignment;
+      }
+    }
+  }
+}
Index: anches/CFSAP/HeuristicLab.Problems.Scheduling.CFSAP/3.3/OptimalAssignment.cs
===================================================================
--- /branches/CFSAP/HeuristicLab.Problems.Scheduling.CFSAP/3.3/OptimalAssignment.cs	(revision 15532)
+++ 	(revision )
@@ -1,137 +1,0 @@
-﻿#region License Information
-/* HeuristicLab
- * Copyright (C) 2002-2017 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.Linq;
-using HeuristicLab.Core;
-using HeuristicLab.Data;
-using HeuristicLab.Encodings.PermutationEncoding;
-
-namespace HeuristicLab.Problems.Scheduling.CFSAP {
-  public static class OptimalAssignment {
-
-    public static int[] MakeAssignment(Permutation order, IntMatrix processingTimes, ItemList<IntMatrix> setupTimes, out int T) {
-      var N = order.Length;
-
-      int[,,] weights = new int[2, 2 * N, 2 * N];
-      int[,] graph = new int[2, N];
-      int[,] prevPath = new int[2, N + 1];                     //Only for optimal assignment evaluation
-      int[] optimalAssignment = new int[N];                //Only for optimal assignment evaluation
-
-      //Calculate weights in the graph
-      for (int S = 0; S < N; S++) { //Starting point of the arc
-        for (int sM = 0; sM < 2; sM++) {    //Starting point machine
-          int eM = sM == 0 ? 1 : 0;
-          weights[sM, S, S + 1] = 0;
-
-          for (int E = S + 2; E < S + N; E++)
-            weights[sM, S, E] =
-              weights[sM, S, E - 1] +
-              processingTimes[eM, order[(E - 1) % N]] +
-              setupTimes[eM][order[(E - 1) % N], order[E % N]];
-
-          for (int E = S + 1; E < S + N; E++)
-            weights[sM, S, E] += (
-              processingTimes[sM, order[S % N]] +
-              setupTimes[sM][order[S % N], order[(E + 1) % N]]
-            );
-        }
-      }
-
-      //Determine the shortest path in the graph
-      T = int.MaxValue / 2;
-      for (int S = 0; S < N - 1; S++)      //Start node in graph			    O(N)
-        for (int SM = 0; SM < 2; SM++) {   //Start node machine in graph	O(1)
-          graph[SM, S] = 0;
-          graph[SM == 0 ? 1 : 0, S] = int.MaxValue / 2;
-          prevPath[SM, 0] = -1;
-          for (int E = S + 1; E < N; E++)      //Currently calculated node			    O(N)
-            for (int EM = 0; EM < 2; EM++) {   //Currently calculated node machine	O(1)
-              graph[EM, E] = int.MaxValue / 2;
-              for (int EC = S; EC < E; EC++) { //Nodes connected to node E		      O(N)
-                int newWeight = graph[EM == 0 ? 1 : 0, EC] + weights[EM == 0 ? 1 : 0, EC, E];
-                if (newWeight < graph[EM, E]) {
-                  graph[EM, E] = newWeight;
-                  prevPath[EM, E] = EC;
-                }
-              }
-            }
-
-          int EP = S + N; //End point.
-          int newT = int.MaxValue / 2;
-          for (int EC = S + 1; EC < N; EC++) { //Nodes connected to EP O(N)
-            int newWeight = graph[SM == 0 ? 1 : 0, EC] + weights[SM == 0 ? 1 : 0, EC, EP];
-            if (newWeight < newT) {
-              newT = newWeight;
-              prevPath[SM, S] = EC;
-            }
-          }
-
-          if (newT < T) {
-            T = newT;
-            optimalAssignment = MakeAssignement(S, SM, prevPath, order);
-          }
-        }
-
-      //Omitted solutions
-      for (int machine = 0; machine < 2; machine++) {
-        int[] assignment = Enumerable.Repeat(machine, N).ToArray();
-        int newT = CFSAP.EvaluateAssignement(order, assignment, processingTimes, setupTimes);
-        if (newT < T) { //New best solution has been found
-          T = newT;
-          optimalAssignment = assignment;
-        }
-      }
-
-      return optimalAssignment;
-    }
-
-    private static int[] MakeAssignement(int start, int startMach, int[,] prevPath, Permutation order) {
-      var N = order.Length;
-      int[] assignment = Enumerable.Repeat(-1, N).ToArray();
-      var inverseOrder = new int[N];
-
-      for (int i = 0; i < N; i++)
-        inverseOrder[order[i]] = i;
-
-      int end = start + N;
-
-      int currMach = startMach;
-      int currNode = start;
-      while (true) {
-        assignment[inverseOrder[currNode]] = currMach;
-        currNode = prevPath[currMach, currNode];
-        currMach = currMach == 0 ? 1 : 0;
-        if (currNode == start)
-          break;
-      }
-
-      currMach = startMach;
-      for (int i = 0; i < N; i++) {
-        if (assignment[inverseOrder[i]] != -1)
-          currMach = currMach == 0 ? 1 : 0;
-        else
-          assignment[inverseOrder[i]] = currMach;
-      }
-
-      return assignment;
-    }
-  }
-}
Index: /branches/CFSAP/HeuristicLab.Problems.Scheduling.CFSAP/3.3/OptimalPolynomialAssignment.cs
===================================================================
--- /branches/CFSAP/HeuristicLab.Problems.Scheduling.CFSAP/3.3/OptimalPolynomialAssignment.cs	(revision 15533)
+++ /branches/CFSAP/HeuristicLab.Problems.Scheduling.CFSAP/3.3/OptimalPolynomialAssignment.cs	(revision 15533)
@@ -0,0 +1,137 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2017 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.Linq;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.PermutationEncoding;
+
+namespace HeuristicLab.Problems.Scheduling.CFSAP {
+  public static class OptimalPolynomialAssignment {
+
+    public static int[] MakeAssignment(Permutation order, IntMatrix processingTimes, ItemList<IntMatrix> setupTimes, out int T) {
+      var N = order.Length;
+
+      int[,,] weights = new int[2, 2 * N, 2 * N];
+      int[,] graph = new int[2, N];
+      int[,] prevPath = new int[2, N + 1];    //Only for optimal assignment evaluation
+      int[] optimalAssignment = new int[N];   //Only for optimal assignment evaluation
+
+      //Calculate weights in the graph
+      for (int S = 0; S < N; S++) {        //Starting point of the arc
+        for (int sM = 0; sM < 2; sM++) {   //Starting point machine
+          int eM = sM == 0 ? 1 : 0;
+          weights[sM, S, S + 1] = 0;
+
+          for (int E = S + 2; E < S + N; E++)
+            weights[sM, S, E] =
+              weights[sM, S, E - 1] +
+              processingTimes[eM, order[(E - 1) % N]] +
+              setupTimes[eM][order[(E - 1) % N], order[E % N]];
+
+          for (int E = S + 1; E < S + N; E++)
+            weights[sM, S, E] += (
+              processingTimes[sM, order[S % N]] +
+              setupTimes[sM][order[S % N], order[(E + 1) % N]]
+            );
+        }
+      }
+
+      //Determine the shortest path in the graph
+      T = int.MaxValue / 2;
+      for (int S = 0; S < N - 1; S++)      //Start node in graph			    O(N)
+        for (int SM = 0; SM < 2; SM++) {   //Start node machine in graph	O(1)
+          graph[SM, S] = 0;
+          graph[SM == 0 ? 1 : 0, S] = int.MaxValue / 2;
+          prevPath[SM, 0] = -1;
+          for (int E = S + 1; E < N; E++)      //Currently calculated node			    O(N)
+            for (int EM = 0; EM < 2; EM++) {   //Currently calculated node machine	O(1)
+              graph[EM, E] = int.MaxValue / 2;
+              for (int EC = S; EC < E; EC++) { //Nodes connected to node E		      O(N)
+                int newWeight = graph[EM == 0 ? 1 : 0, EC] + weights[EM == 0 ? 1 : 0, EC, E];
+                if (newWeight < graph[EM, E]) {
+                  graph[EM, E] = newWeight;
+                  prevPath[EM, E] = EC;
+                }
+              }
+            }
+
+          int EP = S + N; //End point.
+          int newT = int.MaxValue / 2;
+          for (int EC = S + 1; EC < N; EC++) { //Nodes connected to EP O(N)
+            int newWeight = graph[SM == 0 ? 1 : 0, EC] + weights[SM == 0 ? 1 : 0, EC, EP];
+            if (newWeight < newT) {
+              newT = newWeight;
+              prevPath[SM, S] = EC;
+            }
+          }
+
+          if (newT < T) {
+            T = newT;
+            optimalAssignment = MakeAssignment(S, SM, prevPath, order);
+          }
+        }
+
+      //Omitted solutions
+      for (int machine = 0; machine < 2; machine++) {
+        int[] assignment = Enumerable.Repeat(machine, N).ToArray();
+        int newT = CFSAP.EvaluateAssignement(order, assignment, processingTimes, setupTimes);
+        if (newT < T) { //New best solution has been found
+          T = newT;
+          optimalAssignment = assignment;
+        }
+      }
+
+      return optimalAssignment;
+    }
+
+    private static int[] MakeAssignment(int start, int startMach, int[,] prevPath, Permutation order) {
+      var N = order.Length;
+      int[] assignment = Enumerable.Repeat(-1, N).ToArray();
+      var inverseOrder = new int[N];
+
+      for (int i = 0; i < N; i++)
+        inverseOrder[order[i]] = i;
+
+      int end = start + N;
+
+      int currMach = startMach;
+      int currNode = start;
+      while (true) {
+        assignment[inverseOrder[currNode]] = currMach;
+        currNode = prevPath[currMach, currNode];
+        currMach = currMach == 0 ? 1 : 0;
+        if (currNode == start)
+          break;
+      }
+
+      currMach = startMach;
+      for (int i = 0; i < N; i++) {
+        if (assignment[inverseOrder[i]] != -1)
+          currMach = currMach == 0 ? 1 : 0;
+        else
+          assignment[inverseOrder[i]] = currMach;
+      }
+
+      return assignment;
+    }
+  }
+}
