Index: trunk/sources/HeuristicLab.Algorithms.TS/3.3/HeuristicLab.Algorithms.TS-3.3.csproj
===================================================================
--- trunk/sources/HeuristicLab.Algorithms.TS/3.3/HeuristicLab.Algorithms.TS-3.3.csproj	(revision 2980)
+++ trunk/sources/HeuristicLab.Algorithms.TS/3.3/HeuristicLab.Algorithms.TS-3.3.csproj	(revision 2981)
@@ -83,4 +83,5 @@
     <Compile Include="HeuristicLabAlgorithmsTSPlugin.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="TabuSelector.cs" />
     <Compile Include="TSOperator.cs" />
   </ItemGroup>
@@ -110,11 +111,23 @@
       <Name>HeuristicLab.Operators-3.3</Name>
     </ProjectReference>
+    <ProjectReference Include="..\..\HeuristicLab.Optimization\3.3\HeuristicLab.Optimization-3.3.csproj">
+      <Project>{14AB8D24-25BC-400C-A846-4627AA945192}</Project>
+      <Name>HeuristicLab.Optimization-3.3</Name>
+    </ProjectReference>
     <ProjectReference Include="..\..\HeuristicLab.Parameters\3.3\HeuristicLab.Parameters-3.3.csproj">
       <Project>{56F9106A-079F-4C61-92F6-86A84C2D84B7}</Project>
       <Name>HeuristicLab.Parameters-3.3</Name>
     </ProjectReference>
+    <ProjectReference Include="..\..\HeuristicLab.Persistence\3.3\HeuristicLab.Persistence-3.3.csproj">
+      <Project>{102BC7D3-0EF9-439C-8F6D-96FF0FDB8E1B}</Project>
+      <Name>HeuristicLab.Persistence-3.3</Name>
+    </ProjectReference>
     <ProjectReference Include="..\..\HeuristicLab.PluginInfrastructure\HeuristicLab.PluginInfrastructure.csproj">
       <Project>{94186A6A-5176-4402-AE83-886557B53CCA}</Project>
       <Name>HeuristicLab.PluginInfrastructure</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\HeuristicLab.Selection\3.3\HeuristicLab.Selection-3.3.csproj">
+      <Project>{2C36CD4F-E5F5-43A4-801A-201EA895FE17}</Project>
+      <Name>HeuristicLab.Selection-3.3</Name>
     </ProjectReference>
   </ItemGroup>
Index: trunk/sources/HeuristicLab.Algorithms.TS/3.3/HeuristicLabAlgorithmsTSPlugin.cs.frame
===================================================================
--- trunk/sources/HeuristicLab.Algorithms.TS/3.3/HeuristicLabAlgorithmsTSPlugin.cs.frame	(revision 2980)
+++ trunk/sources/HeuristicLab.Algorithms.TS/3.3/HeuristicLabAlgorithmsTSPlugin.cs.frame	(revision 2981)
@@ -32,11 +32,10 @@
   [PluginDependency("HeuristicLab.Core", "3.3")]
   [PluginDependency("HeuristicLab.Data", "3.3")]
-  //[PluginDependency("HeuristicLab.Evolutionary", "3.3")]
   [PluginDependency("HeuristicLab.Operators", "3.3")]
-  //[PluginDependency("HeuristicLab.Optimization", "3.3")]
+  [PluginDependency("HeuristicLab.Optimization", "3.3")]
   [PluginDependency("HeuristicLab.Parameters", "3.3")]
-  //[PluginDependency("HeuristicLab.Persistence", "3.3")]
+  [PluginDependency("HeuristicLab.Persistence", "3.3")]
   //[PluginDependency("HeuristicLab.Random", "3.3")]
-  //[PluginDependency("HeuristicLab.Selection", "3.3")]
+  [PluginDependency("HeuristicLab.Selection", "3.3")]
   public class HeuristicLabAlgorithmsTSPlugin : PluginBase {
   }
Index: trunk/sources/HeuristicLab.Algorithms.TS/3.3/TSOperator.cs
===================================================================
--- trunk/sources/HeuristicLab.Algorithms.TS/3.3/TSOperator.cs	(revision 2980)
+++ trunk/sources/HeuristicLab.Algorithms.TS/3.3/TSOperator.cs	(revision 2981)
@@ -23,8 +23,6 @@
 using HeuristicLab.Core;
 using HeuristicLab.Data;
-//using HeuristicLab.Evolutionary;
 using HeuristicLab.Operators;
 using HeuristicLab.Parameters;
-//using HeuristicLab.Selection;
 
 namespace HeuristicLab.Algorithms.TS {
@@ -47,4 +45,7 @@
       get { return (ValueLookupParameter<IntData>)Parameters["MaximumIterations"]; }
     }
+    public ValueLookupParameter<IntData> TabuTenureParameter {
+      get { return (ValueLookupParameter<IntData>)Parameters["TabuTenure"]; }
+    }
     public ValueLookupParameter<VariableCollection> ResultsParameter {
       get { return (ValueLookupParameter<VariableCollection>)Parameters["Results"]; }
@@ -66,13 +67,28 @@
       Parameters.Add(new SubScopesLookupParameter<DoubleData>("Quality", "The value which represents the quality of a solution."));
       Parameters.Add(new ValueLookupParameter<IntData>("MaximumIterations", "The maximum number of generations which should be processed."));
+      Parameters.Add(new ValueLookupParameter<IntData>("TabuTenure", "The length of the tabu list, and also means the number of iterations a move is kept tabu"));
       Parameters.Add(new ValueLookupParameter<VariableCollection>("Results", "The variable collection where results should be stored."));
       Parameters.Add(new ScopeParameter("CurrentScope", "The current scope which represents a population of solutions on which the TS should be applied."));
       #endregion
 
-      #region Create operator graph
+      #region Create operators
       VariableCreator variableCreator = new VariableCreator();
       ResultsCollector resultsCollector = new ResultsCollector();
-
-      OperatorGraph.InitialOperator = variableCreator;
+      Placeholder moveGenerator = new Placeholder();
+      UniformSequentialSubScopesProcessor moveEvaluationProcessor = new UniformSequentialSubScopesProcessor();
+      Placeholder moveQualityEvaluator = new Placeholder();
+      Placeholder moveTabuEvaluator = new Placeholder();
+      SubScopesSorter moveQualitySorter = new SubScopesSorter();
+      Placeholder tabuSelector = new Placeholder();
+      SequentialSubScopesProcessor moveMakingProcessor = new SequentialSubScopesProcessor();
+      EmptyOperator emptyOp = new EmptyOperator();
+      UniformSequentialSubScopesProcessor actualMoveMakingProcessor = new UniformSequentialSubScopesProcessor();
+      Placeholder moveMaker = new Placeholder();
+      Placeholder moveTabuMaker = new Placeholder();
+      SubScopesRemover subScopesRemover = new SubScopesRemover();
+      IntCounter iterationsCounter = new IntCounter();
+      Comparator iterationsComparator = new Comparator();
+      ConditionalBranch iterationsTermination = new ConditionalBranch();
+      EmptyOperator finished = new EmptyOperator();
 
       variableCreator.CollectedValues.Add(new ValueParameter<IntData>("Iterations", new IntData(0)));
@@ -83,5 +99,4 @@
       variableCreator.CollectedValues.Add(new ValueParameter<DataTable>("Qualities", new DataTable("Qualities")));
       variableCreator.CollectedValues.Add(new ValueParameter<DataTable>("MoveQualities", new DataTable("MoveQualities")));
-      variableCreator.Successor = resultsCollector;
 
       resultsCollector.CollectedValues.Add(new LookupParameter<IntData>("Iterations"));
@@ -93,5 +108,58 @@
       resultsCollector.CollectedValues.Add(new LookupParameter<DataTable>("MoveQualities"));
       resultsCollector.ResultsParameter.ActualName = "Results";
-      resultsCollector.Successor = null;
+
+      moveGenerator.Name = "MoveGenerator (placeholder)";
+      moveGenerator.OperatorParameter.ActualName = "MoveGenerator";
+
+      moveQualityEvaluator.Name = "MoveQualityEvaluator (placeholder)";
+      moveQualityEvaluator.OperatorParameter.ActualName = "MoveQualityEvaluator";
+
+      moveTabuEvaluator.Name = "MoveTabuEvaluator (placeholder)";
+      moveTabuEvaluator.OperatorParameter.ActualName = "MoveTabuEvaluator";
+
+      moveQualitySorter.DescendingParameter.ActualName = "Maximization";
+      moveQualitySorter.ValueParameter.ActualName = "MoveQuality";
+
+      tabuSelector.Name = "TabuSelector (placeholder)";
+      tabuSelector.OperatorParameter.ActualName = "TabuSelector";
+
+      moveMaker.Name = "MoveMaker (placeholder)";
+      moveMaker.OperatorParameter.ActualName = "MoveMaker";
+
+      moveTabuMaker.Name = "MoveTabuMaker (placeholder)";
+      moveTabuMaker.OperatorParameter.ActualName = "MoveTabuMaker";
+
+      subScopesRemover.RemoveAllSubScopes = true;
+
+      iterationsCounter.Increment = new IntData(1);
+      iterationsCounter.IncrementParameter.ActualName = "Iterations";
+
+      iterationsComparator.Comparison = new ComparisonData(Comparison.Less);
+      iterationsComparator.LeftSideParameter.ActualName = "Iterations";
+      iterationsComparator.RightSideParameter.ActualName = "MaximumIterations";
+      iterationsComparator.ResultParameter.ActualName = "IterationsCondition";
+
+      iterationsTermination.ConditionParameter.ActualName = "IterationsCondition";
+      #endregion
+
+      #region Create operator graph
+      OperatorGraph.InitialOperator = variableCreator;
+      variableCreator.Successor = resultsCollector;
+      resultsCollector.Successor = moveGenerator;
+      moveGenerator.Successor = moveEvaluationProcessor;
+      moveEvaluationProcessor.Operator = moveQualityEvaluator;
+      moveQualityEvaluator.Successor = moveTabuEvaluator;
+      moveEvaluationProcessor.Successor = moveQualitySorter;
+      moveQualitySorter.Successor = tabuSelector;
+      tabuSelector.Successor = moveMakingProcessor;
+      moveMakingProcessor.Operators.AddRange(new Operator[] { emptyOp, actualMoveMakingProcessor });
+      actualMoveMakingProcessor.Operator = moveMaker;
+      moveMaker.Successor = moveTabuMaker;
+      moveMakingProcessor.Successor = subScopesRemover;
+      subScopesRemover.Successor = iterationsCounter;
+      iterationsCounter.Successor = iterationsComparator;
+      iterationsComparator.Successor = iterationsTermination;
+      iterationsTermination.TrueBranch = resultsCollector;
+      iterationsTermination.FalseBranch = finished;
       #endregion
     }
Index: trunk/sources/HeuristicLab.Algorithms.TS/3.3/TabuSelector.cs
===================================================================
--- trunk/sources/HeuristicLab.Algorithms.TS/3.3/TabuSelector.cs	(revision 2981)
+++ trunk/sources/HeuristicLab.Algorithms.TS/3.3/TabuSelector.cs	(revision 2981)
@@ -0,0 +1,136 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2010 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 HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Operators;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Selection;
+
+namespace HeuristicLab.Algorithms.TS {
+  /// <summary>
+  /// The tabu selector is a selection operator that separates the best n moves that are either not tabu or satisfy the default aspiration criterion from the rest. It expects the move subscopes to be sorted.
+  /// </summary>
+  /// <remarks>
+  /// For different aspiration criteria a new operator should be implemented.
+  /// </remarks>
+  [Item("TabuSelector", "An operator that selects the best move that is either not tabu or satisfies the aspiration criterion. It expects the move subscopes to be sorted.")]
+  [EmptyStorableClass]
+  public class TabuSelector : Selector {
+    /// <summary>
+    /// The quality of the current solution.
+    /// </summary>
+    public LookupParameter<DoubleData> QualityParameter {
+      get { return (LookupParameter<DoubleData>)Parameters["Quality"]; }
+    }
+    /// <summary>
+    /// The best found quality so far.
+    /// </summary>
+    public LookupParameter<DoubleData> BestQualityParameter {
+      get { return (LookupParameter<DoubleData>)Parameters["BestQuality"]; }
+    }
+    /// <summary>
+    /// Whether to use the default aspiration criteria or not.
+    /// </summary>
+    public ValueLookupParameter<BoolData> AspirationParameter {
+      get { return (ValueLookupParameter<BoolData>)Parameters["Aspiration"]; }
+    }
+    /// <summary>
+    /// Whether the problem is a maximization problem or not.
+    /// </summary>
+    public IValueLookupParameter<BoolData> MaximizationParameter {
+      get { return (IValueLookupParameter<BoolData>)Parameters["Maximization"]; }
+    }
+    /// <summary>
+    /// The parameter for the move qualities.
+    /// </summary>
+    public ILookupParameter<ItemArray<DoubleData>> MoveQualityParameter {
+      get { return (ILookupParameter<ItemArray<DoubleData>>)Parameters["MoveQuality"]; }
+    }
+    /// <summary>
+    /// The parameter for the tabu status of the moves.
+    /// </summary>
+    public ILookupParameter<ItemArray<BoolData>> MoveTabuParameter {
+      get { return (ILookupParameter<ItemArray<BoolData>>)Parameters["MoveTabu"]; }
+    }
+
+    /// <summary>
+    /// Initializes a new intsance with 6 parameters (<c>Quality</c>, <c>BestQuality</c>,
+    /// <c>Aspiration</c>, <c>Maximization</c>, <c>MoveQuality</c>, and <c>MoveTabu</c>).
+    /// </summary>
+    public TabuSelector()
+      : base() {
+      Parameters.Add(new LookupParameter<DoubleData>("Quality", "The quality of the current solution."));
+      Parameters.Add(new LookupParameter<DoubleData>("BestQuality", "The best found quality so far."));
+      Parameters.Add(new ValueLookupParameter<BoolData>("Aspiration", "Whether the default aspiration criterion should be used or not. The default aspiration criterion accepts a tabu move if it results in a better solution than the best solution found so far.", new BoolData(true)));
+      Parameters.Add(new ValueLookupParameter<BoolData>("Maximization", "Whether the problem is a maximization or minimization problem (used to decide whether a solution is better"));
+      Parameters.Add(new SubScopesLookupParameter<DoubleData>("MoveQuality", "The quality of the move."));
+      Parameters.Add(new SubScopesLookupParameter<BoolData>("MoveTabu", "The tabu status of the move."));
+    }
+
+    /// <summary>
+    /// Implements the tabu selection with the default aspiration criteria (choose a tabu move when it is better than the best so far).
+    /// </summary>
+    /// <param name="scopes">The scopes from which to select.</param>
+    /// <returns>The selected scopes.</returns>
+    protected override IScope[] Select(List<IScope> scopes) {
+      int count = NumberOfSelectedSubScopesParameter.ActualValue.Value;
+      bool copy = CopySelectedParameter.Value.Value;
+      bool aspiration = AspirationParameter.ActualValue.Value;
+      bool maximization = MaximizationParameter.ActualValue.Value;
+      double bestQuality = BestQualityParameter.ActualValue.Value;
+      double quality = QualityParameter.ActualValue.Value;
+      ItemArray<DoubleData> moveQualities = MoveQualityParameter.ActualValue;
+      ItemArray<BoolData> moveTabus = MoveTabuParameter.ActualValue;
+
+      IScope[] selected = new IScope[count];
+
+      // remember scopes that should be removed
+      List<int> scopesToRemove = new List<int>();
+      for (int i = 0; i < scopes.Count; i++) {
+        if (count > 0 && (!moveTabus[i].Value || aspiration &&
+          (maximization && moveQualities[i].Value + quality > bestQuality
+          || !maximization && moveQualities[i].Value + quality < bestQuality))) {
+          scopesToRemove.Add(i);
+          if (copy) selected[selected.Length - count] = (IScope)scopes[i].Clone();
+          else selected[selected.Length - count] = scopes[i];
+          count--;
+          if (count == 0) break;
+        }
+      }
+
+      if (count > 0) throw new InvalidOperationException("TabuSelector: The neighborhood contained no or too little moves that are not tabu.");
+
+      // remove from last to first so that the stored indices remain the same
+      if (!copy) {
+        while (scopesToRemove.Count > 0) {
+          scopes.RemoveAt(scopesToRemove[scopesToRemove.Count - 1]);
+          scopesToRemove.RemoveAt(scopesToRemove.Count - 1);
+        }
+      }
+
+      return selected;
+    }
+  }
+}
