Index: branches/CFSAP/CFSAP.sln
===================================================================
--- branches/CFSAP/CFSAP.sln	(revision 15459)
+++ branches/CFSAP/CFSAP.sln	(revision 15460)
@@ -1,6 +1,6 @@
 ﻿
 Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 14
-VisualStudioVersion = 14.0.25420.1
+# Visual Studio 15
+VisualStudioVersion = 15.0.27004.2002
 MinimumVisualStudioVersion = 10.0.40219.1
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.Problems.Scheduling.CFSAP-3.3", "HeuristicLab.Problems.Scheduling.CFSAP\3.3\HeuristicLab.Problems.Scheduling.CFSAP-3.3.csproj", "{93609034-D1EE-4DC6-A381-E4CDB55E4261}"
@@ -60,3 +60,6 @@
 		HideSolutionNode = FALSE
 	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {1DA298F0-1917-4ED1-8495-507A39302C34}
+	EndGlobalSection
 EndGlobal
Index: branches/CFSAP/HeuristicLab.Problems.Instances.CFSAP/3.3/BozejkoCFSAPInstanceProvider.cs
===================================================================
--- branches/CFSAP/HeuristicLab.Problems.Instances.CFSAP/3.3/BozejkoCFSAPInstanceProvider.cs	(revision 15459)
+++ branches/CFSAP/HeuristicLab.Problems.Instances.CFSAP/3.3/BozejkoCFSAPInstanceProvider.cs	(revision 15460)
@@ -89,4 +89,7 @@
         instance.Name = id.Name;
         instance.Description = id.Description;
+        int bkct;
+        if (bestKnownCycleTimes.TryGetValue(id.Name, out bkct))
+          instance.BestKnownCycleTime = bkct;
         return instance;
       }
@@ -103,4 +106,126 @@
     }
 
+    private static readonly Dictionary<string, int> bestKnownCycleTimes = new Dictionary<string, int>() {
+{ "gi_001", 608 },
+{ "gi_002", 623 },
+{ "gi_003", 500 },
+{ "gi_004", 585 },
+{ "gi_005", 549 },
+{ "gi_006", 629 },
+{ "gi_007", 603 },
+{ "gi_008", 506 },
+{ "gi_009", 588 },
+{ "gi_010", 493 },
+{ "gi_011", 597 },
+{ "gi_012", 554 },
+{ "gi_013", 594 },
+{ "gi_014", 505 },
+{ "gi_015", 631 },
+{ "gi_016", 626 },
+{ "gi_017", 585 },
+{ "gi_018", 529 },
+{ "gi_019", 649 },
+{ "gi_020", 561 },
+{ "gi_021", 535 },
+{ "gi_022", 586 },
+{ "gi_023", 602 },
+{ "gi_024", 607 },
+{ "gi_025", 598 },
+{ "gi_026", 572 },
+{ "gi_027", 605 },
+{ "gi_028", 619 },
+{ "gi_029", 646 },
+{ "gi_030", 591 },
+{ "gi_031", 958 },
+{ "gi_032", 838 },
+{ "gi_033", 974 },
+{ "gi_034", 904 },
+{ "gi_035", 1002 },
+{ "gi_036", 998 },
+{ "gi_037", 988 },
+{ "gi_038", 872 },
+{ "gi_039", 1009 },
+{ "gi_040", 1000 },
+{ "gi_041", 992 },
+{ "gi_042", 1097 },
+{ "gi_043", 989 },
+{ "gi_044", 1038 },
+{ "gi_045", 998 },
+{ "gi_046", 1077 },
+{ "gi_047", 997 },
+{ "gi_048", 921 },
+{ "gi_049", 902 },
+{ "gi_050", 1035 },
+{ "gi_051", 914 },
+{ "gi_052", 1019 },
+{ "gi_053", 997 },
+{ "gi_054", 928 },
+{ "gi_055", 973 },
+{ "gi_056", 1011 },
+{ "gi_057", 943 },
+{ "gi_058", 959 },
+{ "gi_059", 1079 },
+{ "gi_060", 940 },
+{ "gi_061", 2176 },
+{ "gi_062", 2100 },
+{ "gi_063", 2147 },
+{ "gi_064", 2289 },
+{ "gi_065", 2171 },
+{ "gi_066", 2185 },
+{ "gi_067", 2152 },
+{ "gi_068", 2321 },
+{ "gi_069", 2173 },
+{ "gi_070", 2242 },
+{ "gi_071", 2222 },
+{ "gi_072", 2403 },
+{ "gi_073", 2305 },
+{ "gi_074", 2279 },
+{ "gi_075", 2283 },
+{ "gi_076", 2014 },
+{ "gi_077", 2185 },
+{ "gi_078", 2236 },
+{ "gi_079", 2223 },
+{ "gi_080", 2136 },
+{ "gi_081", 2147 },
+{ "gi_082", 2285 },
+{ "gi_083", 2270 },
+{ "gi_084", 2264 },
+{ "gi_085", 2192 },
+{ "gi_086", 2052 },
+{ "gi_087", 2130 },
+{ "gi_088", 2172 },
+{ "gi_089", 2530 },
+{ "gi_090", 2498 },
+{ "gi_091", 4465 },
+{ "gi_092", 4269 },
+{ "gi_093", 4201 },
+{ "gi_094", 4330 },
+{ "gi_095", 4158 },
+{ "gi_096", 4355 },
+{ "gi_097", 4363 },
+{ "gi_098", 4268 },
+{ "gi_099", 4143 },
+{ "gi_100", 4313 },
+{ "gi_101", 4285 },
+{ "gi_102", 4421 },
+{ "gi_103", 4288 },
+{ "gi_104", 4295 },
+{ "gi_105", 4295 },
+{ "gi_106", 4257 },
+{ "gi_107", 4610 },
+{ "gi_108", 4579 },
+{ "gi_109", 4578 },
+{ "gi_110", 4219 },
+{ "gi_111", 4472 },
+{ "gi_112", 4460 },
+{ "gi_113", 4446 },
+{ "gi_114", 4504 },
+{ "gi_115", 4417 },
+{ "gi_116", 4503 },
+{ "gi_117", 4442 },
+{ "gi_118", 4411 },
+{ "gi_119", 4506 },
+{ "gi_120", 4556 }
+    };
   }
 }
Index: branches/CFSAP/HeuristicLab.Problems.Instances.CFSAP/3.3/BozejkoCFSAPParser.cs
===================================================================
--- branches/CFSAP/HeuristicLab.Problems.Instances.CFSAP/3.3/BozejkoCFSAPParser.cs	(revision 15459)
+++ branches/CFSAP/HeuristicLab.Problems.Instances.CFSAP/3.3/BozejkoCFSAPParser.cs	(revision 15460)
@@ -64,6 +64,6 @@
               }
             }
-            SetupTimes.Add(sp);
           }
+          SetupTimes.Add(sp);
         }
         reader.Close();
Index: branches/CFSAP/HeuristicLab.Problems.Instances/3.3/Types/CFSAPData.cs
===================================================================
--- branches/CFSAP/HeuristicLab.Problems.Instances/3.3/Types/CFSAPData.cs	(revision 15459)
+++ branches/CFSAP/HeuristicLab.Problems.Instances/3.3/Types/CFSAPData.cs	(revision 15460)
@@ -33,4 +33,8 @@
     public string Description { get; set; }
     /// <summary>
+    /// Optional! The best known cycle time.
+    /// </summary>
+    public int? BestKnownCycleTime { get; set; }
+    /// <summary>
     /// The number of jobs.
     /// </summary>
Index: branches/CFSAP/HeuristicLab.Problems.Scheduling.CFSAP/3.3/CFSAP.cs
===================================================================
--- branches/CFSAP/HeuristicLab.Problems.Scheduling.CFSAP/3.3/CFSAP.cs	(revision 15460)
+++ branches/CFSAP/HeuristicLab.Problems.Scheduling.CFSAP/3.3/CFSAP.cs	(revision 15460)
@@ -0,0 +1,185 @@
+﻿#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;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.BinaryVectorEncoding;
+using HeuristicLab.Encodings.PermutationEncoding;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.Instances;
+
+namespace HeuristicLab.Problems.Scheduling.CFSAP {
+  [Item("Cyclic flow shop with two machines and a single nest (CFSAP)", "Non-permutational cyclic flow shop scheduling problem with a single nest of two machine from W. Bozejko.")]
+  [Creatable(CreatableAttribute.Categories.CombinatorialProblems)]
+  [StorableClass]
+  public class CFSAP : SingleObjectiveBasicProblem<MultiEncoding>, ICFSAP, IProblemInstanceConsumer<CFSAPData> {
+    public override bool Maximization { get { return false; } }
+
+    public IValueParameter<IntMatrix> ProcessingTimesParameter {
+      get { return (IValueParameter<IntMatrix>)Parameters["ProcessingTimes"]; }
+    }
+
+    public IntMatrix ProcessingTimes {
+      get { return ProcessingTimesParameter.Value; }
+      set { ProcessingTimesParameter.Value = value; }
+    }
+
+    public IValueParameter<ItemList<IntMatrix>> SetupTimesParameter {
+      get { return (IValueParameter<ItemList<IntMatrix>>)Parameters["SetupTimes"]; }
+    }
+
+    public ItemList<IntMatrix> SetupTimes {
+      get { return SetupTimesParameter.Value; }
+      set { SetupTimesParameter.Value = value; }
+    }
+
+    [StorableConstructor]
+    protected CFSAP(bool deserializing) : base(deserializing) {}
+    protected CFSAP(CFSAP original, Cloner cloner)
+      : base(original, cloner) {}
+    public CFSAP() {
+      Parameters.Add(new ValueParameter<IntMatrix>("ProcessingTimes", "The processing times of each machine and each job."));
+      Parameters.Add(new ValueParameter<ItemList<IntMatrix>>("SetupTimes", "The sequence dependent set up times of each machine and between all jobs."));
+
+      ProcessingTimesParameter.Value = new IntMatrix(new int[,] {
+        { 5, 4, 3, 2, 1 },
+        { 1, 2, 3, 4, 5 }
+      });
+
+      SetupTimesParameter.Value = new ItemList<IntMatrix>(2);
+      SetupTimesParameter.Value.Add(new IntMatrix(new int[,] {
+        { 3, 4, 5, 4, 3 },
+        { 3, 4, 5, 4, 3 },
+        { 3, 4, 5, 4, 3 },
+        { 3, 4, 5, 4, 3 },
+        { 3, 4, 5, 4, 3 },
+      }));
+      SetupTimesParameter.Value.Add(new IntMatrix(new int[,] {
+        { 5, 4, 3, 4, 5 },
+        { 5, 4, 3, 4, 5 },
+        { 5, 4, 3, 4, 5 },
+        { 5, 4, 3, 4, 5 },
+        { 5, 4, 3, 4, 5 },
+      }));
+
+      Encoding.Add(new PermutationEncoding("sequence", 5, PermutationTypes.RelativeDirected));
+      Encoding.Add(new BinaryVectorEncoding("assignment", 5));
+
+      Operators.RemoveAll(x => x is SingleObjectiveMoveGenerator);
+      Operators.RemoveAll(x => x is SingleObjectiveMoveEvaluator);
+      Operators.RemoveAll(x => x is SingleObjectiveMoveMaker);
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new CFSAP(this, cloner);
+    }
+
+    public override double Evaluate(Individual individual, IRandom random) {
+      var order = individual.Permutation("sequence");
+      var assignment = individual.BinaryVector("assignment");
+      int T = EvaluateAssignement(order, assignment.Select(x => x ? 1 : 0).ToArray(),
+        ProcessingTimesParameter.Value, SetupTimesParameter.Value);
+      return T;
+    }
+
+    //Function to evaluate individual with the specified assignment
+    public static int EvaluateAssignement(Permutation order, int[] assignment, IntMatrix processingTimes, ItemList<IntMatrix> setupTimes) {
+      var N = order.Length;
+      int T = 0;
+
+      for (int i = 0; i < N; i++) {
+        int operation = order[i];
+        int machine = assignment[operation];
+        T += processingTimes[machine, operation];
+      }
+
+      for (int machine = 0; machine < 2; machine++) {
+        int first = -1;
+        int last = -1;
+        for (int i = 0; i < N; i++) {
+          int operation = order[i];
+          if (assignment[operation] == machine) {
+            if (first == -1)
+              first = operation;
+            else
+              T += setupTimes[machine][last, operation];
+            last = operation;
+          }
+        }
+        if (last != -1 && first != -1)
+          T += setupTimes[machine][last, first];
+      }
+
+      return T;
+    }
+
+    public void UpdateEncoding() {
+      Encoding.Encodings.OfType<PermutationEncoding>().Single().Length = ProcessingTimes.Columns;
+      Encoding.Encodings.OfType<BinaryVectorEncoding>().Single().Length = ProcessingTimes.Columns;
+    }
+
+    /// <summary>
+    /// Imports the first nest (index 0) given in the CFSAPData.
+    /// This is the same as calling Load(data, 0).
+    /// </summary>
+    /// <param name="data">The data of all nests.</param>
+    public void Load(CFSAPData data) {
+      Load(data, 0);
+    }
+
+    /// <summary>
+    /// Imports a specific nest given in the CFSAPData.
+    /// </summary>
+    /// <param name="data">The data of all nests.</param>
+    /// <param name="nest">The zero-based index of the nest that should be imported.</param>
+    public void Load(CFSAPData data, int nest) {
+      if (data.Machines[nest] != 2) throw new ArgumentException("Currently only two machines per nest are supported.");
+      if (nest < 0 || nest >= data.Nests) throw new ArgumentException("Nest must be a zero-based index.");
+      var pr = new int[data.Machines[nest], data.Jobs];
+      for (var i = 0; i < data.Machines[nest]; i++)
+        for (var j = 0; j < data.Jobs; j++)
+          pr[i, j] = data.ProcessingTimes[nest][i][j];
+      ProcessingTimesParameter.Value = new IntMatrix(pr);
+      var setups = new ItemList<IntMatrix>(data.Machines[nest]);
+      for (var m = 0; m < data.SetupTimes[nest].GetLength(0); m++) {
+        var setupTimes = new int[data.Jobs, data.Jobs];
+        for (var i = 0; i < data.Jobs; i++)
+          for (var j = 0; j < data.Jobs; j++)
+            setupTimes[i, j] = data.SetupTimes[nest][m][i][j];
+        setups.Add(new IntMatrix(setupTimes));
+      }
+      SetupTimesParameter.Value = setups;
+      UpdateEncoding();
+      Name = data.Name + "-nest" + nest;
+      Description = data.Description;
+      if (data.BestKnownCycleTime.HasValue)
+        BestKnownQuality = data.BestKnownCycleTime.Value;
+      else BestKnownQualityParameter.Value = null;
+    }
+  }
+}
Index: branches/CFSAP/HeuristicLab.Problems.Scheduling.CFSAP/3.3/CFSAPSequenceOnly.cs
===================================================================
--- branches/CFSAP/HeuristicLab.Problems.Scheduling.CFSAP/3.3/CFSAPSequenceOnly.cs	(revision 15459)
+++ branches/CFSAP/HeuristicLab.Problems.Scheduling.CFSAP/3.3/CFSAPSequenceOnly.cs	(revision 15460)
@@ -44,6 +44,16 @@
     }
 
+    public IntMatrix ProcessingTimes {
+      get { return ProcessingTimesParameter.Value; }
+      set { ProcessingTimesParameter.Value = value; }
+    }
+
     public IValueParameter<ItemList<IntMatrix>> SetupTimesParameter {
       get { return (IValueParameter<ItemList<IntMatrix>>)Parameters["SetupTimes"]; }
+    }
+
+    public ItemList<IntMatrix> SetupTimes {
+      get { return SetupTimesParameter.Value; }
+      set { SetupTimesParameter.Value = value; }
     }
 
@@ -162,40 +172,9 @@
       for (int machine = 0; machine < 2; machine++) {
         int[] assignment = Enumerable.Repeat(machine, N).ToArray();
-        int newT = EvaluateAssignement(order, assignment, processingTimes, setupTimes);
+        int newT = CFSAP.EvaluateAssignement(order, assignment, processingTimes, setupTimes);
         if (newT < T) { //New best solution has been found
           T = newT;
-          assignment.CopyTo(optimalAssignment, N);
+          optimalAssignment = assignment;
         }
-      }
-
-      return T;
-    }
-
-    //Function to evaluate individual with the specified assignment
-    public static int EvaluateAssignement(Permutation order, int[] assignment, IntMatrix processingTimes, ItemList<IntMatrix> setupTimes) {
-      var N = order.Length;
-      int T = 0;
-
-      for (int i = 0; i < N; i++) {
-        int operation = order[i];
-        int machine = assignment[operation];
-        T += processingTimes[machine, operation];
-      }
-
-      for (int machine = 0; machine < 2; machine++) {
-        int first = -1;
-        int last = -1;
-        for (int i = 0; i < N; i++) {
-          int operation = order[i];
-          if (assignment[operation] == machine) {
-            if (first == -1)
-              first = operation;
-            else
-              T += setupTimes[machine][last, operation];
-            last = operation;
-          }
-        }
-        if (last != -1 && first != -1)
-          T += setupTimes[machine][last, first];
       }
 
@@ -232,4 +211,8 @@
 
       return assignment;
+    }
+
+    public void UpdateEncoding() {
+      Encoding.Length = ProcessingTimes.Columns;
     }
 
@@ -265,7 +248,10 @@
       }
       SetupTimesParameter.Value = setups;
-      Encoding.Length = data.Jobs;
+      UpdateEncoding();
       Name = data.Name + "-nest" + nest;
       Description = data.Description;
+      if (data.BestKnownCycleTime.HasValue)
+        BestKnownQuality = data.BestKnownCycleTime.Value;
+      else BestKnownQualityParameter.Value = null;
     }
   }
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 15459)
+++ branches/CFSAP/HeuristicLab.Problems.Scheduling.CFSAP/3.3/HeuristicLab.Problems.Scheduling.CFSAP-3.3.csproj	(revision 15460)
@@ -114,5 +114,9 @@
   <ItemGroup>
     <None Include="Plugin.cs.frame" />
+    <Compile Include="CFSAP.cs" />
     <Compile Include="CFSAPSequenceOnly.cs" />
+    <Compile Include="ICFSAP.cs" />
+    <Compile Include="MultiNestCFSAP.cs" />
+    <Compile Include="MultiNestCFSAPSolvingStrategy.cs" />
     <Compile Include="Plugin.cs" />
     <None Include="Properties\AssemblyInfo.cs.frame" />
Index: branches/CFSAP/HeuristicLab.Problems.Scheduling.CFSAP/3.3/ICFSAP.cs
===================================================================
--- branches/CFSAP/HeuristicLab.Problems.Scheduling.CFSAP/3.3/ICFSAP.cs	(revision 15460)
+++ branches/CFSAP/HeuristicLab.Problems.Scheduling.CFSAP/3.3/ICFSAP.cs	(revision 15460)
@@ -0,0 +1,14 @@
+﻿using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+
+namespace HeuristicLab.Problems.Scheduling.CFSAP {
+  public interface ICFSAP : IProblem {
+    IValueParameter<IntMatrix> ProcessingTimesParameter { get; }
+    IntMatrix ProcessingTimes { get; set; }
+    IValueParameter<ItemList<IntMatrix>> SetupTimesParameter { get; }
+    ItemList<IntMatrix> SetupTimes { get; set; }
+
+    void UpdateEncoding();
+  }
+}
Index: branches/CFSAP/HeuristicLab.Problems.Scheduling.CFSAP/3.3/MultiNestCFSAP.cs
===================================================================
--- branches/CFSAP/HeuristicLab.Problems.Scheduling.CFSAP/3.3/MultiNestCFSAP.cs	(revision 15460)
+++ branches/CFSAP/HeuristicLab.Problems.Scheduling.CFSAP/3.3/MultiNestCFSAP.cs	(revision 15460)
@@ -0,0 +1,133 @@
+﻿using System;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.BinaryVectorEncoding;
+using HeuristicLab.Encodings.PermutationEncoding;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.Instances;
+
+namespace HeuristicLab.Problems.Scheduling.CFSAP {
+  [Item("Cyclic flow shop with two machines and multiple nests (multi-CFSAP)", "Non-permutational cyclic flow shop scheduling problem with multiple nests of two machines each from W. Bozejko.")]
+  [Creatable(CreatableAttribute.Categories.CombinatorialProblems)]
+  [StorableClass]
+  public class MultiNestCFSAP : SingleObjectiveBasicProblem<MultiEncoding>, IProblemInstanceConsumer<CFSAPData> {
+    public override bool Maximization { get { return false; } }
+
+    public IValueParameter<ItemList<IntMatrix>> ProcessingTimesParameter {
+      get { return (IValueParameter<ItemList<IntMatrix>>)Parameters["ProcessingTimes"]; }
+    }
+
+    public ItemList<IntMatrix> ProcessingTimes {
+      get { return ProcessingTimesParameter.Value; }
+      set { ProcessingTimesParameter.Value = value; }
+    }
+
+    public IValueParameter<ItemList<ItemList<IntMatrix>>> SetupTimesParameter {
+      get { return (IValueParameter<ItemList<ItemList<IntMatrix>>>)Parameters["SetupTimes"]; }
+    }
+
+    public ItemList<ItemList<IntMatrix>> SetupTimes {
+      get { return SetupTimesParameter.Value; }
+      set { SetupTimesParameter.Value = value; }
+    }
+
+    [StorableConstructor]
+    protected MultiNestCFSAP(bool deserializing) : base(deserializing) { }
+    protected MultiNestCFSAP(MultiNestCFSAP original, Cloner cloner)
+      : base(original, cloner) { }
+    public MultiNestCFSAP() {
+      Parameters.Add(new ValueParameter<ItemList<IntMatrix>>("ProcessingTimes", "The processing times of each nest, each machine, each job."));
+      Parameters.Add(new ValueParameter<ItemList<ItemList<IntMatrix>>>("SetupTimes", "The sequence dependent set up times for each nest, each machine, and each job to each other."));
+
+      ProcessingTimesParameter.Value = new ItemList<IntMatrix>() {
+        new IntMatrix(new int[,] {
+          { 5, 4, 3, 2, 1 },
+          { 1, 2, 3, 4, 5 }
+        })
+      };
+
+      SetupTimesParameter.Value = new ItemList<ItemList<IntMatrix>>() { new ItemList<IntMatrix>() };
+      SetupTimesParameter.Value[0].Add(new IntMatrix(new int[,] {
+        { 3, 4, 5, 4, 3 },
+        { 3, 4, 5, 4, 3 },
+        { 3, 4, 5, 4, 3 },
+        { 3, 4, 5, 4, 3 },
+        { 3, 4, 5, 4, 3 },
+      }));
+      SetupTimesParameter.Value[0].Add(new IntMatrix(new int[,] {
+        { 5, 4, 3, 4, 5 },
+        { 5, 4, 3, 4, 5 },
+        { 5, 4, 3, 4, 5 },
+        { 5, 4, 3, 4, 5 },
+        { 5, 4, 3, 4, 5 },
+      }));
+
+      Encoding.Add(new PermutationEncoding("seq0", 5, PermutationTypes.RelativeDirected));
+      Encoding.Add(new BinaryVectorEncoding("assign0", 5));
+
+      Operators.RemoveAll(x => x is SingleObjectiveMoveGenerator);
+      Operators.RemoveAll(x => x is SingleObjectiveMoveEvaluator);
+      Operators.RemoveAll(x => x is SingleObjectiveMoveMaker);
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new MultiNestCFSAP(this, cloner);
+    }
+
+    public override double Evaluate(Individual individual, IRandom random) {
+      var nests = ProcessingTimesParameter.Value.Count;
+      var maxT = int.MinValue;
+      for (var i = 0; i < nests; i++) {
+        var order = individual.Permutation("seq" + i);
+        var assignment = individual.BinaryVector("assign" + i);
+        int T = CFSAP.EvaluateAssignement(order, assignment.Select(x => x ? 1 : 0).ToArray(),
+          ProcessingTimesParameter.Value[i], SetupTimesParameter.Value[i]);
+        if (T > maxT) maxT = T;
+      }
+      return maxT;
+    }
+
+    /// <summary>
+    /// Imports the all nests given in the CFSAPData.
+    /// </summary>
+    /// <param name="data">The data of all nests.</param>
+    public void Load(CFSAPData data) {
+      if (data.Machines.Any(x => x != 2)) throw new ArgumentException("Currently only two machines per nest are supported.");
+      ProcessingTimesParameter.Value = new ItemList<IntMatrix>();
+      for (var n = 0; n < data.Nests; n++) {
+        var pr = new int[data.Machines[n], data.Jobs];
+        for (var i = 0; i < data.Machines[n]; i++)
+          for (var j = 0; j < data.Jobs; j++)
+            pr[i, j] = data.ProcessingTimes[n][i][j];
+        ProcessingTimesParameter.Value.Add(new IntMatrix(pr));
+      }
+      SetupTimesParameter.Value = new ItemList<ItemList<IntMatrix>>();
+      for (var n = 0; n < data.Nests; n++) {
+        var setups = new ItemList<IntMatrix>(data.Machines[n]);
+        for (var m = 0; m < data.SetupTimes[n].GetLength(0); m++) {
+          var setupTimes = new int[data.Jobs, data.Jobs];
+          for (var i = 0; i < data.Jobs; i++)
+            for (var j = 0; j < data.Jobs; j++)
+              setupTimes[i, j] = data.SetupTimes[n][m][i][j];
+          setups.Add(new IntMatrix(setupTimes));
+        }
+        SetupTimesParameter.Value.Add(setups);
+      }
+      foreach (var enc in Encoding.Encodings.ToList())
+        Encoding.Remove(enc);
+      for (var n = 0; n < data.Nests; n++) {
+        Encoding.Add(new PermutationEncoding("seq" + n, data.Jobs, PermutationTypes.RelativeDirected));
+        Encoding.Add(new BinaryVectorEncoding("assign" + n, data.Jobs));
+      }
+      Name = data.Name;
+      Description = data.Description;
+      if (data.BestKnownCycleTime.HasValue)
+        BestKnownQuality = data.BestKnownCycleTime.Value;
+      else BestKnownQualityParameter.Value = null;
+    }
+  }
+}
Index: branches/CFSAP/HeuristicLab.Problems.Scheduling.CFSAP/3.3/MultiNestCFSAPSolvingStrategy.cs
===================================================================
--- branches/CFSAP/HeuristicLab.Problems.Scheduling.CFSAP/3.3/MultiNestCFSAPSolvingStrategy.cs	(revision 15460)
+++ branches/CFSAP/HeuristicLab.Problems.Scheduling.CFSAP/3.3/MultiNestCFSAPSolvingStrategy.cs	(revision 15460)
@@ -0,0 +1,119 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.Scheduling.CFSAP {
+  [Item("MultiNest CFSAP Solver", "Solving strategy that applies an algorithm instace to the worst nest.")]
+  [StorableClass]
+  [Creatable(CreatableAttribute.Categories.Algorithms)]
+  public class MultiNestCFSAPSolvingStrategy : BasicAlgorithm {
+    public override bool SupportsPause => true;
+
+    public override Type ProblemType => typeof(MultiNestCFSAP);
+
+    public new MultiNestCFSAP Problem {
+      get { return (MultiNestCFSAP)base.Problem; }
+      set { base.Problem = value; }
+    }
+
+    public IValueParameter<IAlgorithm> SolverParameter {
+      get { return (IValueParameter<IAlgorithm>)Parameters["Solver"]; }
+    }
+
+    public IFixedValueParameter<TimeSpanValue> MaximumRuntimeParameter {
+      get { return (IFixedValueParameter<TimeSpanValue>)Parameters["MaximumRuntime"]; }
+    }
+
+    public TimeSpan MaximumRuntime {
+      get { return MaximumRuntimeParameter.Value.Value; }
+      set { MaximumRuntimeParameter.Value.Value = value; }
+    }
+
+    [StorableConstructor]
+    protected MultiNestCFSAPSolvingStrategy(bool deserializing) : base(deserializing) { }
+    protected MultiNestCFSAPSolvingStrategy(MultiNestCFSAPSolvingStrategy original, Cloner cloner)
+      : base(original, cloner) {
+      if (original.algorithms != null)
+        algorithms = original.algorithms.Select(x => cloner.Clone(x)).ToList();
+      if (original.qualities != null)
+        qualities = original.qualities.ToArray();
+      if (original.algorithmsResults != null)
+        algorithmsResults = cloner.Clone(original.algorithmsResults);
+    }
+    public MultiNestCFSAPSolvingStrategy() {
+      Parameters.Add(new ValueParameter<IAlgorithm>("Solver", "The actual solver template."));
+      Parameters.Add(new FixedValueParameter<TimeSpanValue>("MaximumRuntime", "The maximum time that the strategy should run.", new TimeSpanValue(TimeSpan.FromSeconds(60))));
+    }
+    
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new MultiNestCFSAPSolvingStrategy(this, cloner);
+    }
+
+    [Storable]
+    private List<IAlgorithm> algorithms;
+    [Storable]
+    private int[] qualities;
+    [Storable]
+    private ResultCollection algorithmsResults;
+
+    protected override void OnPrepared() {
+      base.OnPrepared();
+      algorithms = null;
+      qualities = null;
+    }
+
+    protected override void Initialize(CancellationToken cancellationToken) {
+      var nests = Problem.ProcessingTimesParameter.Value.Count;
+      algorithms = new List<IAlgorithm>(nests);
+      algorithmsResults = new ResultCollection();
+      for (var n = 0; n < nests; n++) {
+        var clone = (IAlgorithm)SolverParameter.Value.Clone();
+        clone.Prepare();
+        var cfsap = (ICFSAP)clone.Problem;
+        cfsap.ProcessingTimes = Problem.ProcessingTimes[n];
+        cfsap.SetupTimes = Problem.SetupTimes[n];
+        cfsap.UpdateEncoding();
+        algorithms.Add(clone);
+        algorithmsResults.Add(new Result("Nest " + (n + 1), clone.Results));
+        clone.Start();
+      }
+      qualities = algorithms.Select(x => (int)((DoubleValue)x.Results["BestQuality"].Value).Value).ToArray();
+      var worst = qualities.Select((v, i) => new { Index = i, Quality = v }).MaxItems(x => x.Quality).First();
+      var min = worst.Quality;
+
+      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("Best Solution Found At", new TimeSpanValue(ExecutionTime)));
+      Results.Add(new Result("Delta T", new PercentValue((min - Problem.BestKnownQuality) / Problem.BestKnownQuality)));
+      Results.Add(new Result("Nest Results", algorithmsResults));
+
+      base.Initialize(cancellationToken);
+    }
+
+    protected override void Run(CancellationToken cancellationToken) {
+      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();
+        if (worst.Quality < min) {
+          min = worst.Quality;
+          Results["Nest with maximum T"].Value = new IntValue(worst.Index + 1);
+          Results["Maximum T"].Value = new IntValue(min);
+          Results["Best Solution Found At"].Value = new TimeSpanValue(ExecutionTime);
+          Results["Delta T"].Value = new PercentValue((min - Problem.BestKnownQuality) / Problem.BestKnownQuality);
+        }
+        if (cancellationToken.IsCancellationRequested) return;
+      }
+    }
+  }
+}
