Index: /branches/TSMemory/HeuristicLab.Algorithms.TabuSearch/3.3/HeuristicLab.Algorithms.TabuSearch-3.3.csproj
===================================================================
--- /branches/TSMemory/HeuristicLab.Algorithms.TabuSearch/3.3/HeuristicLab.Algorithms.TabuSearch-3.3.csproj	(revision 5120)
+++ /branches/TSMemory/HeuristicLab.Algorithms.TabuSearch/3.3/HeuristicLab.Algorithms.TabuSearch-3.3.csproj	(revision 5120)
@@ -0,0 +1,214 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>9.0.30729</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{D58A232D-04BA-4186-B73E-0EC86FD31ABE}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>HeuristicLab.Algorithms.TabuSearch</RootNamespace>
+    <AssemblyName>HeuristicLab.Algorithms.TabuSearch-3.3</AssemblyName>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <SignAssembly>true</SignAssembly>
+    <AssemblyOriginatorKeyFile>HeuristicLab.snk</AssemblyOriginatorKeyFile>
+    <FileUpgradeFlags>
+    </FileUpgradeFlags>
+    <OldToolsVersion>3.5</OldToolsVersion>
+    <UpgradeBackupLocation />
+    <PublishUrl>publish\</PublishUrl>
+    <Install>true</Install>
+    <InstallFrom>Disk</InstallFrom>
+    <UpdateEnabled>false</UpdateEnabled>
+    <UpdateMode>Foreground</UpdateMode>
+    <UpdateInterval>7</UpdateInterval>
+    <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+    <UpdatePeriodically>false</UpdatePeriodically>
+    <UpdateRequired>false</UpdateRequired>
+    <MapFileExtensions>true</MapFileExtensions>
+    <ApplicationRevision>0</ApplicationRevision>
+    <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+    <IsWebBootstrapper>false</IsWebBootstrapper>
+    <UseApplicationTrust>false</UseApplicationTrust>
+    <BootstrapperEnabled>true</BootstrapperEnabled>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>bin\x64\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
+    <OutputPath>bin\x64\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>bin\x86\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+    <OutputPath>bin\x86\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Xml.Linq">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data.DataSetExtensions">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="HeuristicLabAlgorithmsTabuSearchPlugin.cs.frame" />
+    <Compile Include="HeuristicLabAlgorithmsTabuSearchPlugin.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="TabuListCreator.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="TabuNeighborhoodAnalyzer.cs" />
+    <Compile Include="TabuSelector.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="TabuSearch.cs" />
+    <Compile Include="TabuSearchMainLoop.cs">
+      <SubType>Code</SubType>
+    </Compile>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="HeuristicLab.snk" />
+    <None Include="Properties\AssemblyInfo.frame" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\HeuristicLab.Analysis\3.3\HeuristicLab.Analysis-3.3.csproj">
+      <Project>{887425B4-4348-49ED-A457-B7D2C26DDBF9}</Project>
+      <Name>HeuristicLab.Analysis-3.3</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\HeuristicLab.Collections\3.3\HeuristicLab.Collections-3.3.csproj">
+      <Project>{958B43BC-CC5C-4FA2-8628-2B3B01D890B6}</Project>
+      <Name>HeuristicLab.Collections-3.3</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\HeuristicLab.Common\3.3\HeuristicLab.Common-3.3.csproj">
+      <Project>{A9AD58B9-3EF9-4CC1-97E5-8D909039FF5C}</Project>
+      <Name>HeuristicLab.Common-3.3</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\HeuristicLab.Core\3.3\HeuristicLab.Core-3.3.csproj">
+      <Project>{C36BD924-A541-4A00-AFA8-41701378DDC5}</Project>
+      <Name>HeuristicLab.Core-3.3</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\HeuristicLab.Data\3.3\HeuristicLab.Data-3.3.csproj">
+      <Project>{BBAB9DF5-5EF3-4BA8-ADE9-B36E82114937}</Project>
+      <Name>HeuristicLab.Data-3.3</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\HeuristicLab.Operators\3.3\HeuristicLab.Operators-3.3.csproj">
+      <Project>{23DA7FF4-D5B8-41B6-AA96-F0561D24F3EE}</Project>
+      <Name>HeuristicLab.Operators-3.3</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\HeuristicLab.Optimization.Operators\3.3\HeuristicLab.Optimization.Operators-3.3.csproj">
+      <Project>{25087811-F74C-4128-BC86-8324271DA13E}</Project>
+      <Name>HeuristicLab.Optimization.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\3.3\HeuristicLab.PluginInfrastructure-3.3.csproj">
+      <Project>{94186A6A-5176-4402-AE83-886557B53CCA}</Project>
+      <Name>HeuristicLab.PluginInfrastructure-3.3</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\..\HeuristicLab.Random\3.3\HeuristicLab.Random-3.3.csproj">
+      <Project>{F4539FB6-4708-40C9-BE64-0A1390AEA197}</Project>
+      <Name>HeuristicLab.Random-3.3</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>
+  <ItemGroup>
+    <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
+      <Visible>False</Visible>
+      <ProductName>Windows Installer 3.1</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+  <PropertyGroup>
+    <PreBuildEvent>set Path=%25Path%25;$(ProjectDir);$(SolutionDir)
+set ProjectDir=$(ProjectDir)
+set SolutionDir=$(SolutionDir)
+set Outdir=$(Outdir)
+
+call PreBuildEvent.cmd
+SubWCRev "%25ProjectDir%25\" "%25ProjectDir%25\HeuristicLabAlgorithmsTabuSearchPlugin.cs.frame" "%25ProjectDir%25\HeuristicLabAlgorithmsTabuSearchPlugin.cs"</PreBuildEvent>
+  </PropertyGroup>
+</Project>
Index: /branches/TSMemory/HeuristicLab.Algorithms.TabuSearch/3.3/HeuristicLabAlgorithmsTabuSearchPlugin.cs.frame
===================================================================
--- /branches/TSMemory/HeuristicLab.Algorithms.TabuSearch/3.3/HeuristicLabAlgorithmsTabuSearchPlugin.cs.frame	(revision 5120)
+++ /branches/TSMemory/HeuristicLab.Algorithms.TabuSearch/3.3/HeuristicLabAlgorithmsTabuSearchPlugin.cs.frame	(revision 5120)
@@ -0,0 +1,44 @@
+﻿#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 HeuristicLab.PluginInfrastructure;
+
+namespace HeuristicLab.Algorithms.TabuSearch {
+  /// <summary>
+  /// Plugin class for HeuristicLab.Algorithms.TabuSearch plugin.
+  /// </summary>
+  [Plugin("HeuristicLab.Algorithms.TabuSearch", "3.3.2.$WCREV$")]
+  [PluginFile("HeuristicLab.Algorithms.TabuSearch-3.3.dll", PluginFileType.Assembly)]
+  [PluginDependency("HeuristicLab.Analysis", "3.3")]
+  [PluginDependency("HeuristicLab.Collections", "3.3")]
+  [PluginDependency("HeuristicLab.Common", "3.3")]
+  [PluginDependency("HeuristicLab.Core", "3.3")]
+  [PluginDependency("HeuristicLab.Data", "3.3")]
+  [PluginDependency("HeuristicLab.Operators", "3.3")]
+  [PluginDependency("HeuristicLab.Optimization", "3.3")]
+  [PluginDependency("HeuristicLab.Optimization.Operators", "3.3")]
+  [PluginDependency("HeuristicLab.Parameters", "3.3")]
+  [PluginDependency("HeuristicLab.Persistence", "3.3")]
+  [PluginDependency("HeuristicLab.Random", "3.3")]
+  [PluginDependency("HeuristicLab.Selection", "3.3")]
+  public class HeuristicLabAlgorithmsTabuSearchPlugin : PluginBase {
+  }
+}
Index: /branches/TSMemory/HeuristicLab.Algorithms.TabuSearch/3.3/Properties/AssemblyInfo.frame
===================================================================
--- /branches/TSMemory/HeuristicLab.Algorithms.TabuSearch/3.3/Properties/AssemblyInfo.frame	(revision 5120)
+++ /branches/TSMemory/HeuristicLab.Algorithms.TabuSearch/3.3/Properties/AssemblyInfo.frame	(revision 5120)
@@ -0,0 +1,55 @@
+﻿#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.Reflection;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("HeuristicLab.Algorithms.TabuSearch")]
+[assembly: AssemblyDescription("HeuristicLab tabu search (TS)")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("HeuristicLab")]
+[assembly: AssemblyCopyright("(c) 2002-2010 HEAL")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("e40b1d0f-b746-41b9-a1a9-67fe8d13edd3")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+[assembly: AssemblyVersion("3.3.0.0")]
+[assembly: AssemblyFileVersion("3.3.2.$WCREV$")]
Index: /branches/TSMemory/HeuristicLab.Algorithms.TabuSearch/3.3/TabuListCreator.cs
===================================================================
--- /branches/TSMemory/HeuristicLab.Algorithms.TabuSearch/3.3/TabuListCreator.cs	(revision 5120)
+++ /branches/TSMemory/HeuristicLab.Algorithms.TabuSearch/3.3/TabuListCreator.cs	(revision 5120)
@@ -0,0 +1,67 @@
+﻿#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 HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Operators;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.TabuSearch {
+  [Item("TabuListCreator", "An operator that creates a new empty tabu list. It can also replace an existing tabu list with a new empty one.")]
+  [StorableClass]
+  public class TabuListCreator : SingleSuccessorOperator {
+    public ValueLookupParameter<ItemList<IItem>> TabuListParameter {
+      get { return (ValueLookupParameter<ItemList<IItem>>)Parameters["TabuList"]; }
+    }
+    protected ScopeParameter CurrentScopeParameter {
+      get { return (ScopeParameter)Parameters["CurrentScope"]; }
+    }
+    public IScope CurrentScope {
+      get { return CurrentScopeParameter.ActualValue; }
+    }
+
+    [StorableConstructor]
+    protected TabuListCreator(bool deserializing) : base(deserializing) { }
+    protected TabuListCreator(TabuListCreator original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new TabuListCreator(this, cloner);
+    }
+
+    public TabuListCreator()
+      : base() {
+      Parameters.Add(new ValueLookupParameter<ItemList<IItem>>("TabuList", "The tabu list.", new ItemList<IItem>()));
+      Parameters.Add(new ScopeParameter("CurrentScope", "The current scope."));
+    }
+
+    public override IOperation Apply() {
+      IVariable var;
+      CurrentScope.Variables.TryGetValue(TabuListParameter.ActualName, out var);
+      if (var != null)
+        var.Value = (IItem)TabuListParameter.ActualValue.Clone();
+      else
+        CurrentScope.Variables.Add(new Variable(TabuListParameter.ActualName, (IItem)TabuListParameter.ActualValue.Clone()));
+      return base.Apply();
+    }
+  }
+}
Index: /branches/TSMemory/HeuristicLab.Algorithms.TabuSearch/3.3/TabuNeighborhoodAnalyzer.cs
===================================================================
--- /branches/TSMemory/HeuristicLab.Algorithms.TabuSearch/3.3/TabuNeighborhoodAnalyzer.cs	(revision 5120)
+++ /branches/TSMemory/HeuristicLab.Algorithms.TabuSearch/3.3/TabuNeighborhoodAnalyzer.cs	(revision 5120)
@@ -0,0 +1,82 @@
+﻿#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.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.TabuSearch {
+  [StorableClass]
+  [Item("TabuNeighborhoodAnalyzer", "Analyzes the tabu neighborhood")]
+  public class TabuNeighborhoodAnalyzer : SingleSuccessorOperator, IAnalyzer {
+    public ScopeTreeLookupParameter<BoolValue> IsTabuParameter {
+      get { return (ScopeTreeLookupParameter<BoolValue>)Parameters["IsTabu"]; }
+    }
+    public LookupParameter<PercentValue> PercentTabuParameter {
+      get { return (LookupParameter<PercentValue>)Parameters["PercentTabu"]; }
+    }
+    public LookupParameter<ResultCollection> ResultsParameter {
+      get { return (LookupParameter<ResultCollection>)Parameters["Results"]; }
+    }
+
+    [StorableConstructor]
+    protected TabuNeighborhoodAnalyzer(bool deserializing) : base(deserializing) { }
+    protected TabuNeighborhoodAnalyzer(TabuNeighborhoodAnalyzer original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new TabuNeighborhoodAnalyzer(this, cloner);
+    }
+    public TabuNeighborhoodAnalyzer()
+      : base() {
+      Parameters.Add(new ScopeTreeLookupParameter<BoolValue>("IsTabu", "A value that determines if a move is tabu or not."));
+      Parameters.Add(new LookupParameter<PercentValue>("PercentTabu", "Indicates how much of the neighborhood is tabu."));
+      Parameters.Add(new LookupParameter<ResultCollection>("Results", "The result collection where the value should be stored."));
+    }
+
+    public override IOperation Apply() {
+      ItemArray<BoolValue> tabu = IsTabuParameter.ActualValue;
+      if (tabu.Length > 0) {
+        PercentValue value = PercentTabuParameter.ActualValue;
+        if (value == null) {
+          value = new PercentValue();
+          PercentTabuParameter.ActualValue = value;
+        }
+        value.Value = tabu.Where(x => x.Value).Count() / (double)tabu.Length;
+        ResultCollection results = ResultsParameter.ActualValue;
+        if (results != null) {
+          IResult result = null;
+          results.TryGetValue(PercentTabuParameter.ActualName, out result);
+          if (result != null)
+            result.Value = value;
+          else
+            results.Add(new Result(PercentTabuParameter.ActualName, "Indicates how much of the neighborhood is tabu.", (IItem)value.Clone()));
+        }
+      }
+      return base.Apply();
+    }
+  }
+}
Index: /branches/TSMemory/HeuristicLab.Algorithms.TabuSearch/3.3/TabuSearch.cs
===================================================================
--- /branches/TSMemory/HeuristicLab.Algorithms.TabuSearch/3.3/TabuSearch.cs	(revision 5120)
+++ /branches/TSMemory/HeuristicLab.Algorithms.TabuSearch/3.3/TabuSearch.cs	(revision 5120)
@@ -0,0 +1,478 @@
+﻿#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 System.Linq;
+using HeuristicLab.Analysis;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Optimization.Operators;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Random;
+
+namespace HeuristicLab.Algorithms.TabuSearch {
+  [Item("Tabu Search", "A tabu search algorithm.")]
+  [Creatable("Algorithms")]
+  [StorableClass]
+  public sealed class TabuSearch : EngineAlgorithm, IStorableContent {
+    public string Filename { get; set; }
+
+    #region Problem Properties
+    public override Type ProblemType {
+      get { return typeof(ISingleObjectiveProblem); }
+    }
+    public new ISingleObjectiveProblem Problem {
+      get { return (ISingleObjectiveProblem)base.Problem; }
+      set { base.Problem = value; }
+    }
+    #endregion
+
+    #region Parameter Properties
+    private ValueParameter<IntValue> SeedParameter {
+      get { return (ValueParameter<IntValue>)Parameters["Seed"]; }
+    }
+    private ValueParameter<BoolValue> SetSeedRandomlyParameter {
+      get { return (ValueParameter<BoolValue>)Parameters["SetSeedRandomly"]; }
+    }
+    private ConstrainedValueParameter<IMoveGenerator> MoveGeneratorParameter {
+      get { return (ConstrainedValueParameter<IMoveGenerator>)Parameters["MoveGenerator"]; }
+    }
+    private ConstrainedValueParameter<IMoveMaker> MoveMakerParameter {
+      get { return (ConstrainedValueParameter<IMoveMaker>)Parameters["MoveMaker"]; }
+    }
+    private ConstrainedValueParameter<ISingleObjectiveMoveEvaluator> MoveEvaluatorParameter {
+      get { return (ConstrainedValueParameter<ISingleObjectiveMoveEvaluator>)Parameters["MoveEvaluator"]; }
+    }
+    private ConstrainedValueParameter<ITabuChecker> TabuCheckerParameter {
+      get { return (ConstrainedValueParameter<ITabuChecker>)Parameters["TabuChecker"]; }
+    }
+    private ConstrainedValueParameter<ITabuMaker> TabuMakerParameter {
+      get { return (ConstrainedValueParameter<ITabuMaker>)Parameters["TabuMaker"]; }
+    }
+    private ValueParameter<IntValue> TabuTenureParameter {
+      get { return (ValueParameter<IntValue>)Parameters["TabuTenure"]; }
+    }
+    private ValueParameter<IntValue> MaximumIterationsParameter {
+      get { return (ValueParameter<IntValue>)Parameters["MaximumIterations"]; }
+    }
+    private ValueParameter<IntValue> SampleSizeParameter {
+      get { return (ValueParameter<IntValue>)Parameters["SampleSize"]; }
+    }
+    private ValueParameter<MultiAnalyzer> AnalyzerParameter {
+      get { return (ValueParameter<MultiAnalyzer>)Parameters["Analyzer"]; }
+    }
+    #endregion
+
+    #region Properties
+    public IntValue Seed {
+      get { return SeedParameter.Value; }
+      set { SeedParameter.Value = value; }
+    }
+    public BoolValue SetSeedRandomly {
+      get { return SetSeedRandomlyParameter.Value; }
+      set { SetSeedRandomlyParameter.Value = value; }
+    }
+    public IMoveGenerator MoveGenerator {
+      get { return MoveGeneratorParameter.Value; }
+      set { MoveGeneratorParameter.Value = value; }
+    }
+    public IMoveMaker MoveMaker {
+      get { return MoveMakerParameter.Value; }
+      set { MoveMakerParameter.Value = value; }
+    }
+    public ISingleObjectiveMoveEvaluator MoveEvaluator {
+      get { return MoveEvaluatorParameter.Value; }
+      set { MoveEvaluatorParameter.Value = value; }
+    }
+    public ITabuChecker TabuChecker {
+      get { return TabuCheckerParameter.Value; }
+      set { TabuCheckerParameter.Value = value; }
+    }
+    public ITabuMaker TabuMaker {
+      get { return TabuMakerParameter.Value; }
+      set { TabuMakerParameter.Value = value; }
+    }
+    public IntValue TabuTenure {
+      get { return TabuTenureParameter.Value; }
+      set { TabuTenureParameter.Value = value; }
+    }
+    public IntValue MaximumIterations {
+      get { return MaximumIterationsParameter.Value; }
+      set { MaximumIterationsParameter.Value = value; }
+    }
+    public MultiAnalyzer Analyzer {
+      get { return AnalyzerParameter.Value; }
+      set { AnalyzerParameter.Value = value; }
+    }
+    private RandomCreator RandomCreator {
+      get { return (RandomCreator)OperatorGraph.InitialOperator; }
+    }
+    private SolutionsCreator SolutionsCreator {
+      get { return (SolutionsCreator)RandomCreator.Successor; }
+    }
+    private TabuSearchMainLoop MainLoop {
+      get { return (TabuSearchMainLoop)SolutionsCreator.Successor; }
+    }
+    [Storable]
+    private BestAverageWorstQualityAnalyzer moveQualityAnalyzer;
+    [Storable]
+    private TabuNeighborhoodAnalyzer tabuNeighborhoodAnalyzer;
+    #endregion
+
+    public TabuSearch()
+      : base() {
+      Parameters.Add(new ValueParameter<IntValue>("Seed", "The random seed used to initialize the new pseudo random number generator.", new IntValue(0)));
+      Parameters.Add(new ValueParameter<BoolValue>("SetSeedRandomly", "True if the random seed should be set to a random value, otherwise false.", new BoolValue(true)));
+      Parameters.Add(new ConstrainedValueParameter<IMoveGenerator>("MoveGenerator", "The operator used to generate moves to the neighborhood of the current solution."));
+      Parameters.Add(new ConstrainedValueParameter<IMoveMaker>("MoveMaker", "The operator used to perform a move."));
+      Parameters.Add(new ConstrainedValueParameter<ISingleObjectiveMoveEvaluator>("MoveEvaluator", "The operator used to evaluate a move."));
+      Parameters.Add(new ConstrainedValueParameter<ITabuChecker>("TabuChecker", "The operator to check whether a move is tabu or not."));
+      Parameters.Add(new ConstrainedValueParameter<ITabuMaker>("TabuMaker", "The operator used to insert attributes of a move into the tabu list."));
+      Parameters.Add(new ValueParameter<IntValue>("TabuTenure", "The length of the tabu list.", new IntValue(10)));
+      Parameters.Add(new ValueParameter<IntValue>("MaximumIterations", "The maximum number of generations which should be processed.", new IntValue(1000)));
+      Parameters.Add(new ValueParameter<IntValue>("SampleSize", "The neighborhood size for stochastic sampling move generators", new IntValue(100)));
+      Parameters.Add(new ValueParameter<MultiAnalyzer>("Analyzer", "The operator used to analyze the solution.", new MultiAnalyzer()));
+
+      RandomCreator randomCreator = new RandomCreator();
+      SolutionsCreator solutionsCreator = new SolutionsCreator();
+      TabuSearchMainLoop tsMainLoop = new TabuSearchMainLoop();
+      OperatorGraph.InitialOperator = randomCreator;
+
+      randomCreator.RandomParameter.ActualName = "Random";
+      randomCreator.SeedParameter.ActualName = SeedParameter.Name;
+      randomCreator.SeedParameter.Value = null;
+      randomCreator.SetSeedRandomlyParameter.ActualName = SetSeedRandomlyParameter.Name;
+      randomCreator.SetSeedRandomlyParameter.Value = null;
+      randomCreator.Successor = solutionsCreator;
+
+      solutionsCreator.NumberOfSolutions = new IntValue(1);
+      solutionsCreator.Successor = tsMainLoop;
+
+      tsMainLoop.MoveGeneratorParameter.ActualName = MoveGeneratorParameter.Name;
+      tsMainLoop.MoveMakerParameter.ActualName = MoveMakerParameter.Name;
+      tsMainLoop.MoveEvaluatorParameter.ActualName = MoveEvaluatorParameter.Name;
+      tsMainLoop.TabuCheckerParameter.ActualName = TabuCheckerParameter.Name;
+      tsMainLoop.TabuMakerParameter.ActualName = TabuMakerParameter.Name;
+      tsMainLoop.MaximumIterationsParameter.ActualName = MaximumIterationsParameter.Name;
+      tsMainLoop.RandomParameter.ActualName = RandomCreator.RandomParameter.ActualName;
+      tsMainLoop.ResultsParameter.ActualName = "Results";
+      tsMainLoop.AnalyzerParameter.ActualName = AnalyzerParameter.Name;
+
+      moveQualityAnalyzer = new BestAverageWorstQualityAnalyzer();
+      tabuNeighborhoodAnalyzer = new TabuNeighborhoodAnalyzer();
+      ParameterizeAnalyzers();
+      UpdateAnalyzers();
+
+      Initialize();
+    }
+    [StorableConstructor]
+    private TabuSearch(bool deserializing) : base(deserializing) { }
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      Initialize();
+    }
+    private TabuSearch(TabuSearch original, Cloner cloner)
+      : base(original, cloner) {
+      moveQualityAnalyzer = cloner.Clone(original.moveQualityAnalyzer);
+      tabuNeighborhoodAnalyzer = cloner.Clone(original.tabuNeighborhoodAnalyzer);
+      Initialize();
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new TabuSearch(this, cloner);
+    }
+
+    public override void Prepare() {
+      if (Problem != null && MoveGenerator != null && MoveMaker != null && MoveEvaluator != null &&
+          TabuChecker != null && TabuMaker != null)
+        base.Prepare();
+    }
+
+    #region Events
+    protected override void OnProblemChanged() {
+      ParameterizeStochasticOperator(Problem.SolutionCreator);
+      ParameterizeStochasticOperator(Problem.Evaluator);
+      foreach (IOperator op in Problem.Operators) ParameterizeStochasticOperator(op);
+      foreach (ISingleObjectiveMoveEvaluator op in Problem.Operators.OfType<ISingleObjectiveMoveEvaluator>()) {
+        op.MoveQualityParameter.ActualNameChanged += new EventHandler(MoveEvaluator_MoveQualityParameter_ActualNameChanged);
+      }
+      foreach (ITabuChecker op in Problem.Operators.OfType<ITabuChecker>()) {
+        op.MoveTabuParameter.ActualNameChanged += new EventHandler(TabuChecker_MoveTabuParameter_ActualNameChanged);
+      }
+      ParameterizeSolutionsCreator();
+      ParameterizeMainLoop();
+      UpdateMoveGenerator();
+      UpdateMoveParameters();
+      UpdateAnalyzers();
+      ParameterizeMoveGenerators();
+      ParameterizeMoveEvaluator();
+      ParameterizeMoveMaker();
+      ParameterizeTabuMaker();
+      ParameterizeTabuChecker();
+      ParameterizeAnalyzers();
+      ParameterizeIterationBasedOperators();
+      Problem.Evaluator.QualityParameter.ActualNameChanged += new EventHandler(Evaluator_QualityParameter_ActualNameChanged);
+      base.OnProblemChanged();
+    }
+    protected override void Problem_SolutionCreatorChanged(object sender, EventArgs e) {
+      ParameterizeStochasticOperator(Problem.SolutionCreator);
+      ParameterizeSolutionsCreator();
+      base.Problem_SolutionCreatorChanged(sender, e);
+    }
+    protected override void Problem_EvaluatorChanged(object sender, EventArgs e) {
+      ParameterizeStochasticOperator(Problem.Evaluator);
+      ParameterizeSolutionsCreator();
+      ParameterizeMainLoop();
+      ParameterizeMoveEvaluator();
+      ParameterizeMoveMaker();
+      ParameterizeTabuMaker();
+      ParameterizeTabuChecker();
+      ParameterizeAnalyzers();
+      Problem.Evaluator.QualityParameter.ActualNameChanged += new EventHandler(Evaluator_QualityParameter_ActualNameChanged);
+      base.Problem_EvaluatorChanged(sender, e);
+    }
+    protected override void Problem_OperatorsChanged(object sender, EventArgs e) {
+      foreach (IOperator op in Problem.Operators) ParameterizeStochasticOperator(op);
+      // This may seem pointless, but some operators already have the eventhandler registered, others don't
+      // FIXME: Is there another way to solve this problem?
+      foreach (ISingleObjectiveMoveEvaluator op in Problem.Operators.OfType<ISingleObjectiveMoveEvaluator>()) {
+        op.MoveQualityParameter.ActualNameChanged -= new EventHandler(MoveEvaluator_MoveQualityParameter_ActualNameChanged);
+        op.MoveQualityParameter.ActualNameChanged += new EventHandler(MoveEvaluator_MoveQualityParameter_ActualNameChanged);
+      }
+      foreach (ITabuChecker op in Problem.Operators.OfType<ITabuChecker>()) {
+        op.MoveTabuParameter.ActualNameChanged -= new EventHandler(TabuChecker_MoveTabuParameter_ActualNameChanged);
+        op.MoveTabuParameter.ActualNameChanged += new EventHandler(TabuChecker_MoveTabuParameter_ActualNameChanged);
+      }
+      UpdateMoveGenerator();
+      UpdateMoveParameters();
+      UpdateAnalyzers();
+      ParameterizeMainLoop();
+      ParameterizeMoveGenerators();
+      ParameterizeMoveEvaluator();
+      ParameterizeMoveMaker();
+      ParameterizeTabuMaker();
+      ParameterizeTabuChecker();
+      ParameterizeAnalyzers();
+      ParameterizeIterationBasedOperators();
+      base.Problem_OperatorsChanged(sender, e);
+    }
+    private void Evaluator_QualityParameter_ActualNameChanged(object sender, EventArgs e) {
+      ParameterizeMainLoop();
+      ParameterizeMoveEvaluator();
+      ParameterizeMoveMaker();
+      ParameterizeTabuMaker();
+      ParameterizeTabuChecker();
+    }
+    private void MoveGeneratorParameter_ValueChanged(object sender, EventArgs e) {
+      UpdateMoveParameters();
+    }
+    private void MoveEvaluatorParameter_ValueChanged(object sender, EventArgs e) {
+      ParameterizeMainLoop();
+      ParameterizeMoveEvaluator();
+      ParameterizeMoveMaker();
+      ParameterizeTabuMaker();
+      ParameterizeTabuChecker();
+      ParameterizeAnalyzers();
+    }
+    private void MoveEvaluator_MoveQualityParameter_ActualNameChanged(object sender, EventArgs e) {
+      ParameterizeMainLoop();
+      ParameterizeMoveEvaluator();
+      ParameterizeMoveMaker();
+      ParameterizeTabuMaker();
+      ParameterizeTabuChecker();
+      ParameterizeAnalyzers();
+    }
+    private void TabuCheckerParameter_ValueChanged(object sender, EventArgs e) {
+      ParameterizeMainLoop();
+      ParameterizeAnalyzers();
+    }
+    private void TabuChecker_MoveTabuParameter_ActualNameChanged(object sender, EventArgs e) {
+      ParameterizeMainLoop();
+      ParameterizeAnalyzers();
+    }
+    private void SampleSizeParameter_NameChanged(object sender, EventArgs e) {
+      ParameterizeMoveGenerators();
+    }
+    #endregion
+
+    #region Helpers
+    private void Initialize() {
+      if (Problem != null) {
+        Problem.Evaluator.QualityParameter.ActualNameChanged += new EventHandler(Evaluator_QualityParameter_ActualNameChanged);
+        foreach (ISingleObjectiveMoveEvaluator op in Problem.Operators.OfType<ISingleObjectiveMoveEvaluator>()) {
+          op.MoveQualityParameter.ActualNameChanged += new EventHandler(MoveEvaluator_MoveQualityParameter_ActualNameChanged);
+        }
+      }
+      MoveGeneratorParameter.ValueChanged += new EventHandler(MoveGeneratorParameter_ValueChanged);
+      MoveEvaluatorParameter.ValueChanged += new EventHandler(MoveEvaluatorParameter_ValueChanged);
+      TabuCheckerParameter.ValueChanged += new EventHandler(TabuCheckerParameter_ValueChanged);
+      SampleSizeParameter.NameChanged += new EventHandler(SampleSizeParameter_NameChanged);
+    }
+    private void UpdateMoveGenerator() {
+      IMoveGenerator oldMoveGenerator = MoveGenerator;
+      MoveGeneratorParameter.ValidValues.Clear();
+      if (Problem != null) {
+        foreach (IMoveGenerator generator in Problem.Operators.OfType<IMoveGenerator>().OrderBy(x => x.Name)) {
+          MoveGeneratorParameter.ValidValues.Add(generator);
+        }
+      }
+      if (oldMoveGenerator != null && MoveGeneratorParameter.ValidValues.Any(x => x.GetType() == oldMoveGenerator.GetType()))
+        MoveGenerator = MoveGeneratorParameter.ValidValues.FirstOrDefault(x => x.GetType() == oldMoveGenerator.GetType());
+      if (MoveGenerator == null) {
+        ClearMoveParameters();
+      }
+    }
+    private void UpdateMoveParameters() {
+      IMoveMaker oldMoveMaker = MoveMaker;
+      ISingleObjectiveMoveEvaluator oldMoveEvaluator = MoveEvaluator;
+      ITabuChecker oldTabuMoveEvaluator = TabuChecker;
+      ITabuMaker oldTabuMoveMaker = TabuMaker;
+      ClearMoveParameters();
+      if (MoveGenerator != null) {
+        List<Type> moveTypes = MoveGenerator.GetType().GetInterfaces().Where(x => typeof(IMoveOperator).IsAssignableFrom(x)).ToList();
+        foreach (Type type in moveTypes.ToList()) {
+          if (moveTypes.Any(t => t != type && type.IsAssignableFrom(t)))
+            moveTypes.Remove(type);
+        }
+        foreach (Type type in moveTypes) {
+          var operators = Problem.Operators.Where(x => type.IsAssignableFrom(x.GetType())).OrderBy(x => x.Name);
+          foreach (IMoveMaker moveMaker in operators.OfType<IMoveMaker>())
+            MoveMakerParameter.ValidValues.Add(moveMaker);
+          foreach (ISingleObjectiveMoveEvaluator moveEvaluator in operators.OfType<ISingleObjectiveMoveEvaluator>())
+            MoveEvaluatorParameter.ValidValues.Add(moveEvaluator);
+          foreach (ITabuChecker tabuMoveEvaluator in operators.OfType<ITabuChecker>())
+            TabuCheckerParameter.ValidValues.Add(tabuMoveEvaluator);
+          foreach (ITabuMaker tabuMoveMaker in operators.OfType<ITabuMaker>())
+            TabuMakerParameter.ValidValues.Add(tabuMoveMaker);
+        }
+        if (oldMoveMaker != null) {
+          IMoveMaker mm = MoveMakerParameter.ValidValues.FirstOrDefault(x => x.GetType() == oldMoveMaker.GetType());
+          if (mm != null) MoveMaker = mm;
+        }
+        if (oldMoveEvaluator != null) {
+          ISingleObjectiveMoveEvaluator me = MoveEvaluatorParameter.ValidValues.FirstOrDefault(x => x.GetType() == oldMoveEvaluator.GetType());
+          if (me != null) MoveEvaluator = me;
+        }
+        if (oldTabuMoveMaker != null) {
+          ITabuMaker tmm = TabuMakerParameter.ValidValues.FirstOrDefault(x => x.GetType() == oldTabuMoveMaker.GetType());
+          if (tmm != null) TabuMaker = tmm;
+        }
+        if (oldTabuMoveEvaluator != null) {
+          ITabuChecker tme = TabuCheckerParameter.ValidValues.FirstOrDefault(x => x.GetType() == oldTabuMoveEvaluator.GetType());
+          if (tme != null) TabuChecker = tme;
+        }
+      }
+    }
+    private void UpdateAnalyzers() {
+      Analyzer.Operators.Clear();
+      if (Problem != null) {
+        foreach (IAnalyzer analyzer in Problem.Operators.OfType<IAnalyzer>()) {
+          foreach (IScopeTreeLookupParameter param in analyzer.Parameters.OfType<IScopeTreeLookupParameter>())
+            param.Depth = 0;
+          Analyzer.Operators.Add(analyzer);
+        }
+      }
+      Analyzer.Operators.Add(moveQualityAnalyzer);
+      Analyzer.Operators.Add(tabuNeighborhoodAnalyzer);
+    }
+    private void ClearMoveParameters() {
+      MoveMakerParameter.ValidValues.Clear();
+      MoveEvaluatorParameter.ValidValues.Clear();
+      TabuCheckerParameter.ValidValues.Clear();
+      TabuMakerParameter.ValidValues.Clear();
+    }
+    private void ParameterizeSolutionsCreator() {
+      SolutionsCreator.EvaluatorParameter.ActualName = Problem.EvaluatorParameter.Name;
+      SolutionsCreator.SolutionCreatorParameter.ActualName = Problem.SolutionCreatorParameter.Name;
+    }
+    private void ParameterizeMainLoop() {
+      MainLoop.BestKnownQualityParameter.ActualName = Problem.BestKnownQualityParameter.Name;
+      MainLoop.MaximizationParameter.ActualName = Problem.MaximizationParameter.Name;
+      MainLoop.QualityParameter.ActualName = Problem.Evaluator.QualityParameter.ActualName;
+      if (MoveEvaluator != null)
+        MainLoop.MoveQualityParameter.ActualName = MoveEvaluator.MoveQualityParameter.ActualName;
+      if (TabuChecker != null)
+        MainLoop.MoveTabuParameter.ActualName = TabuChecker.MoveTabuParameter.ActualName;
+    }
+    private void ParameterizeStochasticOperator(IOperator op) {
+      if (op is IStochasticOperator)
+        ((IStochasticOperator)op).RandomParameter.ActualName = RandomCreator.RandomParameter.ActualName;
+    }
+    private void ParameterizeMoveGenerators() {
+      if (Problem != null) {
+        foreach (IMultiMoveGenerator generator in Problem.Operators.OfType<IMultiMoveGenerator>())
+          generator.SampleSizeParameter.ActualName = SampleSizeParameter.Name;
+      }
+    }
+    private void ParameterizeMoveEvaluator() {
+      foreach (ISingleObjectiveMoveEvaluator op in Problem.Operators.OfType<ISingleObjectiveMoveEvaluator>()) {
+        op.QualityParameter.ActualName = Problem.Evaluator.QualityParameter.ActualName;
+      }
+    }
+    private void ParameterizeMoveMaker() {
+      foreach (IMoveMaker op in Problem.Operators.OfType<IMoveMaker>()) {
+        op.QualityParameter.ActualName = Problem.Evaluator.QualityParameter.ActualName;
+        if (MoveEvaluator != null)
+          op.MoveQualityParameter.ActualName = MoveEvaluator.MoveQualityParameter.ActualName;
+      }
+    }
+    private void ParameterizeTabuMaker() {
+      foreach (ITabuMaker op in Problem.Operators.OfType<ITabuMaker>()) {
+        op.QualityParameter.ActualName = Problem.Evaluator.QualityParameter.ActualName;
+        if (MoveEvaluator != null)
+          op.MoveQualityParameter.ActualName = MoveEvaluator.MoveQualityParameter.ActualName;
+      }
+    }
+    private void ParameterizeTabuChecker() {
+      foreach (ITabuChecker op in Problem.Operators.OfType<ITabuChecker>()) {
+        if (MoveEvaluator != null)
+          op.MoveQualityParameter.ActualName = MoveEvaluator.MoveQualityParameter.ActualName;
+        if (TabuChecker != null)
+          op.MoveTabuParameter.ActualName = TabuChecker.MoveTabuParameter.ActualName;
+      }
+    }
+    private void ParameterizeAnalyzers() {
+      moveQualityAnalyzer.ResultsParameter.ActualName = "Results";
+      tabuNeighborhoodAnalyzer.ResultsParameter.ActualName = "Results";
+      tabuNeighborhoodAnalyzer.PercentTabuParameter.ActualName = "PercentTabu";
+      if (Problem != null) {
+        moveQualityAnalyzer.MaximizationParameter.ActualName = Problem.MaximizationParameter.Name;
+        if (MoveEvaluator != null)
+          moveQualityAnalyzer.QualityParameter.ActualName = MoveEvaluator.MoveQualityParameter.ActualName;
+        moveQualityAnalyzer.BestKnownQualityParameter.ActualName = Problem.BestKnownQualityParameter.Name;
+        if (TabuChecker != null)
+          tabuNeighborhoodAnalyzer.IsTabuParameter.ActualName = TabuChecker.MoveTabuParameter.ActualName;
+      }
+    }
+    private void ParameterizeIterationBasedOperators() {
+      if (Problem != null) {
+        foreach (IIterationBasedOperator op in Problem.Operators.OfType<IIterationBasedOperator>()) {
+          op.IterationsParameter.ActualName = "Iterations";
+          op.MaximumIterationsParameter.ActualName = MaximumIterationsParameter.Name;
+        }
+      }
+    }
+    #endregion
+  }
+}
Index: /branches/TSMemory/HeuristicLab.Algorithms.TabuSearch/3.3/TabuSearchMainLoop.cs
===================================================================
--- /branches/TSMemory/HeuristicLab.Algorithms.TabuSearch/3.3/TabuSearchMainLoop.cs	(revision 5120)
+++ /branches/TSMemory/HeuristicLab.Algorithms.TabuSearch/3.3/TabuSearchMainLoop.cs	(revision 5120)
@@ -0,0 +1,289 @@
+﻿#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 HeuristicLab.Analysis;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization.Operators;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Selection;
+
+namespace HeuristicLab.Algorithms.TabuSearch {
+  /// <summary>
+  /// An operator which represents a tabu search.
+  /// </summary>
+  [Item("TabuSearchMainLoop", "An operator which represents the main loop of a tabu search.")]
+  [StorableClass]
+  public sealed class TabuSearchMainLoop : AlgorithmOperator {
+    #region Parameter properties
+    public ValueLookupParameter<IRandom> RandomParameter {
+      get { return (ValueLookupParameter<IRandom>)Parameters["Random"]; }
+    }
+    public ValueLookupParameter<BoolValue> MaximizationParameter {
+      get { return (ValueLookupParameter<BoolValue>)Parameters["Maximization"]; }
+    }
+    public LookupParameter<DoubleValue> QualityParameter {
+      get { return (LookupParameter<DoubleValue>)Parameters["Quality"]; }
+    }
+    public ValueLookupParameter<DoubleValue> BestKnownQualityParameter {
+      get { return (ValueLookupParameter<DoubleValue>)Parameters["BestKnownQuality"]; }
+    }
+    public LookupParameter<DoubleValue> MoveQualityParameter {
+      get { return (LookupParameter<DoubleValue>)Parameters["MoveQuality"]; }
+    }
+    public LookupParameter<BoolValue> MoveTabuParameter {
+      get { return (LookupParameter<BoolValue>)Parameters["MoveTabu"]; }
+    }
+    public ValueLookupParameter<IntValue> MaximumIterationsParameter {
+      get { return (ValueLookupParameter<IntValue>)Parameters["MaximumIterations"]; }
+    }
+    public ValueLookupParameter<IntValue> TabuTenureParameter {
+      get { return (ValueLookupParameter<IntValue>)Parameters["TabuTenure"]; }
+    }
+    public ValueLookupParameter<IOperator> MoveGeneratorParameter {
+      get { return (ValueLookupParameter<IOperator>)Parameters["MoveGenerator"]; }
+    }
+    public ValueLookupParameter<IOperator> MoveEvaluatorParameter {
+      get { return (ValueLookupParameter<IOperator>)Parameters["MoveEvaluator"]; }
+    }
+    public ValueLookupParameter<IOperator> MoveMakerParameter {
+      get { return (ValueLookupParameter<IOperator>)Parameters["MoveMaker"]; }
+    }
+    public ValueLookupParameter<IOperator> TabuCheckerParameter {
+      get { return (ValueLookupParameter<IOperator>)Parameters["TabuChecker"]; }
+    }
+    public ValueLookupParameter<IOperator> TabuMakerParameter {
+      get { return (ValueLookupParameter<IOperator>)Parameters["TabuMaker"]; }
+    }
+    public ValueLookupParameter<IOperator> AnalyzerParameter {
+      get { return (ValueLookupParameter<IOperator>)Parameters["Analyzer"]; }
+    }
+    public ValueLookupParameter<VariableCollection> ResultsParameter {
+      get { return (ValueLookupParameter<VariableCollection>)Parameters["Results"]; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    private TabuSearchMainLoop(bool deserializing) : base(deserializing) { }
+    public TabuSearchMainLoop()
+      : base() {
+      Initialize();
+    }
+    private TabuSearchMainLoop(TabuSearchMainLoop original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new TabuSearchMainLoop(this, cloner);
+    }
+
+    private void Initialize() {
+      #region Create parameters
+      Parameters.Add(new ValueLookupParameter<IRandom>("Random", "A pseudo random number generator."));
+      Parameters.Add(new ValueLookupParameter<BoolValue>("Maximization", "True if the problem is a maximization problem, otherwise false."));
+      Parameters.Add(new LookupParameter<DoubleValue>("Quality", "The value which represents the quality of a solution."));
+      Parameters.Add(new ValueLookupParameter<DoubleValue>("BestKnownQuality", "The best known quality value found so far."));
+      Parameters.Add(new LookupParameter<DoubleValue>("MoveQuality", "The value which represents the quality of a move."));
+      Parameters.Add(new LookupParameter<BoolValue>("MoveTabu", "The value that indicates if a move is tabu or not."));
+      Parameters.Add(new ValueLookupParameter<IntValue>("MaximumIterations", "The maximum number of generations which should be processed."));
+      Parameters.Add(new ValueLookupParameter<IntValue>("TabuTenure", "The length of the tabu list, and also means the number of iterations a move is kept tabu"));
+
+      Parameters.Add(new ValueLookupParameter<IOperator>("MoveGenerator", "The operator that generates the moves."));
+      Parameters.Add(new ValueLookupParameter<IOperator>("MoveMaker", "The operator that performs a move and updates the quality."));
+      Parameters.Add(new ValueLookupParameter<IOperator>("MoveEvaluator", "The operator that evaluates a move."));
+      Parameters.Add(new ValueLookupParameter<IOperator>("TabuChecker", "The operator that checks whether a move is tabu."));
+      Parameters.Add(new ValueLookupParameter<IOperator>("TabuMaker", "The operator that declares a move tabu."));
+
+      Parameters.Add(new ValueLookupParameter<IOperator>("Analyzer", "The operator used to analyze the solution and moves."));
+      Parameters.Add(new ValueLookupParameter<VariableCollection>("Results", "The variable collection where results should be stored."));
+      #endregion
+
+      #region Create operators
+      VariableCreator variableCreator = new VariableCreator();
+      SubScopesProcessor subScopesProcessor0 = new SubScopesProcessor();
+      Assigner bestQualityInitializer = new Assigner();
+      Placeholder analyzer1 = new Placeholder();
+      ResultsCollector resultsCollector1 = new ResultsCollector();
+      ResultsCollector resultsCollector2 = new ResultsCollector();
+      SubScopesProcessor solutionProcessor = new SubScopesProcessor();
+      Placeholder moveGenerator = new Placeholder();
+      UniformSubScopesProcessor moveEvaluationProcessor = new UniformSubScopesProcessor();
+      Placeholder moveEvaluator = new Placeholder();
+      IntCounter evaluatedMovesCounter = new IntCounter();
+      Placeholder tabuChecker = new Placeholder();
+      SubScopesSorter moveQualitySorter = new SubScopesSorter();
+      TabuSelector tabuSelector = new TabuSelector();
+      ConditionalBranch emptyNeighborhoodBranch1 = new ConditionalBranch();
+      SubScopesProcessor moveMakingProcessor = new SubScopesProcessor();
+      UniformSubScopesProcessor selectedMoveMakingProcesor = new UniformSubScopesProcessor();
+      Placeholder tabuMaker = new Placeholder();
+      Placeholder moveMaker = new Placeholder();
+      MergingReducer mergingReducer = new MergingReducer();
+      Placeholder analyzer2 = new Placeholder();
+      SubScopesRemover subScopesRemover = new SubScopesRemover();
+      ConditionalBranch emptyNeighborhoodBranch2 = new ConditionalBranch();
+      BestQualityMemorizer bestQualityUpdater = new BestQualityMemorizer();
+      IntCounter iterationsCounter = new IntCounter();
+      Comparator iterationsComparator = new Comparator();
+      ResultsCollector resultsCollector3 = new ResultsCollector();
+      ConditionalBranch iterationsTermination = new ConditionalBranch();
+
+      variableCreator.CollectedValues.Add(new ValueParameter<IntValue>("Iterations", new IntValue(0))); // Class TabuSearch expects this to be called Iterations
+      variableCreator.CollectedValues.Add(new ValueParameter<IntValue>("EvaluatedMoves", new IntValue(0)));
+      variableCreator.CollectedValues.Add(new ValueParameter<BoolValue>("EmptyNeighborhood", new BoolValue(false)));
+      variableCreator.CollectedValues.Add(new ValueParameter<ItemList<IItem>>("TabuList", new ItemList<IItem>()));
+      variableCreator.CollectedValues.Add(new ValueParameter<DoubleValue>("BestQuality", new DoubleValue(0)));
+
+      bestQualityInitializer.Name = "Initialize BestQuality";
+      bestQualityInitializer.LeftSideParameter.ActualName = "BestQuality";
+      bestQualityInitializer.RightSideParameter.ActualName = QualityParameter.Name;
+
+      analyzer1.Name = "Analyzer (placeholder)";
+      analyzer1.OperatorParameter.ActualName = AnalyzerParameter.Name;
+
+      resultsCollector1.CopyValue = new BoolValue(false);
+      resultsCollector1.CollectedValues.Add(new LookupParameter<IntValue>("Iterations"));
+      resultsCollector1.CollectedValues.Add(new LookupParameter<DoubleValue>("Best Quality", null, "BestQuality"));
+      resultsCollector1.ResultsParameter.ActualName = ResultsParameter.Name;
+
+      resultsCollector2.CopyValue = new BoolValue(true);
+      resultsCollector2.CollectedValues.Add(new LookupParameter<IntValue>("Evaluated Moves", null, "EvaluatedMoves"));
+      resultsCollector2.ResultsParameter.ActualName = ResultsParameter.Name;
+
+      moveGenerator.Name = "MoveGenerator (placeholder)";
+      moveGenerator.OperatorParameter.ActualName = MoveGeneratorParameter.Name;
+
+      moveEvaluator.Name = "MoveEvaluator (placeholder)";
+      moveEvaluator.OperatorParameter.ActualName = MoveEvaluatorParameter.Name;
+
+      evaluatedMovesCounter.Name = "EvaluatedMoves + 1";
+      evaluatedMovesCounter.ValueParameter.ActualName = "EvaluatedMoves";
+      evaluatedMovesCounter.Increment = new IntValue(1);
+
+      tabuChecker.Name = "TabuChecker (placeholder)";
+      tabuChecker.OperatorParameter.ActualName = TabuCheckerParameter.Name;
+
+      moveQualitySorter.DescendingParameter.ActualName = MaximizationParameter.Name;
+      moveQualitySorter.ValueParameter.ActualName = MoveQualityParameter.Name;
+
+      tabuSelector.AspirationParameter.Value = new BoolValue(true);
+      tabuSelector.BestQualityParameter.ActualName = "BestQuality";
+      tabuSelector.CopySelected = new BoolValue(false);
+      tabuSelector.EmptyNeighborhoodParameter.ActualName = "EmptyNeighborhood";
+      tabuSelector.MaximizationParameter.ActualName = MaximizationParameter.Name;
+      tabuSelector.MoveQualityParameter.ActualName = MoveQualityParameter.Name;
+      tabuSelector.MoveTabuParameter.ActualName = MoveTabuParameter.Name;
+
+      moveMakingProcessor.Name = "MoveMaking processor (UniformSubScopesProcessor)";
+
+      emptyNeighborhoodBranch1.Name = "Neighborhood empty?";
+      emptyNeighborhoodBranch1.ConditionParameter.ActualName = "EmptyNeighborhood";
+
+      tabuMaker.Name = "TabuMaker (placeholder)";
+      tabuMaker.OperatorParameter.ActualName = TabuMakerParameter.Name;
+
+      moveMaker.Name = "MoveMaker (placeholder)";
+      moveMaker.OperatorParameter.ActualName = MoveMakerParameter.Name;
+
+      analyzer2.Name = "Analyzer (placeholder)";
+      analyzer2.OperatorParameter.ActualName = AnalyzerParameter.Name;
+
+      subScopesRemover.RemoveAllSubScopes = true;
+
+      bestQualityUpdater.Name = "Update BestQuality";
+      bestQualityUpdater.MaximizationParameter.ActualName = MaximizationParameter.Name;
+      bestQualityUpdater.QualityParameter.ActualName = QualityParameter.Name;
+      bestQualityUpdater.BestQualityParameter.ActualName = "BestQuality";
+
+      iterationsCounter.Name = "Iterations Counter";
+      iterationsCounter.Increment = new IntValue(1);
+      iterationsCounter.ValueParameter.ActualName = "Iterations";
+
+      iterationsComparator.Name = "Iterations >= MaximumIterations";
+      iterationsComparator.Comparison = new Comparison(ComparisonType.GreaterOrEqual);
+      iterationsComparator.LeftSideParameter.ActualName = "Iterations";
+      iterationsComparator.RightSideParameter.ActualName = MaximumIterationsParameter.Name;
+      iterationsComparator.ResultParameter.ActualName = "Terminate";
+
+      resultsCollector3.CopyValue = new BoolValue(true);
+      resultsCollector3.CollectedValues.Add(new LookupParameter<IntValue>("Evaluated Moves", null, "EvaluatedMoves"));
+      resultsCollector3.ResultsParameter.ActualName = ResultsParameter.Name;
+
+      emptyNeighborhoodBranch2.Name = "Neighborhood empty?";
+      emptyNeighborhoodBranch2.ConditionParameter.ActualName = "EmptyNeighborhood";
+
+      iterationsTermination.Name = "Iterations Termination Condition";
+      iterationsTermination.ConditionParameter.ActualName = "Terminate";
+      #endregion
+
+      #region Create operator graph
+      OperatorGraph.InitialOperator = variableCreator;
+      variableCreator.Successor = subScopesProcessor0;
+      subScopesProcessor0.Operators.Add(bestQualityInitializer);
+      subScopesProcessor0.Successor = resultsCollector1;
+      bestQualityInitializer.Successor = analyzer1;
+      analyzer1.Successor = null;
+      resultsCollector1.Successor = resultsCollector2;
+      resultsCollector2.Successor = solutionProcessor;
+      solutionProcessor.Operators.Add(moveGenerator);
+      solutionProcessor.Successor = iterationsCounter;
+      moveGenerator.Successor = moveEvaluationProcessor;
+      moveEvaluationProcessor.Operator = moveEvaluator;
+      moveEvaluationProcessor.Successor = moveQualitySorter;
+      moveEvaluator.Successor = evaluatedMovesCounter;
+      evaluatedMovesCounter.Successor = tabuChecker;
+      tabuChecker.Successor = null;
+      moveQualitySorter.Successor = tabuSelector;
+      tabuSelector.Successor = emptyNeighborhoodBranch1;
+      emptyNeighborhoodBranch1.FalseBranch = moveMakingProcessor;
+      emptyNeighborhoodBranch1.TrueBranch = null;
+      emptyNeighborhoodBranch1.Successor = subScopesRemover;
+      moveMakingProcessor.Operators.Add(new EmptyOperator());
+      moveMakingProcessor.Operators.Add(selectedMoveMakingProcesor);
+      moveMakingProcessor.Successor = mergingReducer;
+      selectedMoveMakingProcesor.Operator = tabuMaker;
+      selectedMoveMakingProcesor.Successor = null;
+      tabuMaker.Successor = moveMaker;
+      moveMaker.Successor = null;
+      mergingReducer.Successor = analyzer2;
+      analyzer2.Successor = null;
+      subScopesRemover.Successor = null;
+      iterationsCounter.Successor = iterationsComparator;
+      iterationsComparator.Successor = resultsCollector3;
+      resultsCollector3.Successor = emptyNeighborhoodBranch2;
+      emptyNeighborhoodBranch2.TrueBranch = null;
+      emptyNeighborhoodBranch2.FalseBranch = iterationsTermination;
+      emptyNeighborhoodBranch2.Successor = null;
+      iterationsTermination.TrueBranch = null;
+      iterationsTermination.FalseBranch = solutionProcessor;
+      #endregion
+    }
+
+    public override IOperation Apply() {
+      if (MoveGeneratorParameter.ActualValue == null || MoveEvaluatorParameter.ActualValue == null || MoveMakerParameter.ActualValue == null
+        || TabuCheckerParameter.ActualValue == null || TabuMakerParameter.ActualValue == null)
+        return null;
+      return base.Apply();
+    }
+  }
+}
Index: /branches/TSMemory/HeuristicLab.Algorithms.TabuSearch/3.3/TabuSelector.cs
===================================================================
--- /branches/TSMemory/HeuristicLab.Algorithms.TabuSearch/3.3/TabuSelector.cs	(revision 5120)
+++ /branches/TSMemory/HeuristicLab.Algorithms.TabuSearch/3.3/TabuSelector.cs	(revision 5120)
@@ -0,0 +1,155 @@
+﻿#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.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Selection;
+
+namespace HeuristicLab.Algorithms.TabuSearch {
+  /// <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 by the qualities of the moves (the best move is first).")]
+  [StorableClass]
+  public class TabuSelector : Selector {
+    /// <summary>
+    /// The best found quality so far.
+    /// </summary>
+    public LookupParameter<DoubleValue> BestQualityParameter {
+      get { return (LookupParameter<DoubleValue>)Parameters["BestQuality"]; }
+    }
+    /// <summary>
+    /// Whether to use the default aspiration criteria or not.
+    /// </summary>
+    public ValueLookupParameter<BoolValue> AspirationParameter {
+      get { return (ValueLookupParameter<BoolValue>)Parameters["Aspiration"]; }
+    }
+    /// <summary>
+    /// Whether the problem is a maximization problem or not.
+    /// </summary>
+    public IValueLookupParameter<BoolValue> MaximizationParameter {
+      get { return (IValueLookupParameter<BoolValue>)Parameters["Maximization"]; }
+    }
+    /// <summary>
+    /// The parameter for the move qualities.
+    /// </summary>
+    public ILookupParameter<ItemArray<DoubleValue>> MoveQualityParameter {
+      get { return (ILookupParameter<ItemArray<DoubleValue>>)Parameters["MoveQuality"]; }
+    }
+    /// <summary>
+    /// The parameter for the tabu status of the moves.
+    /// </summary>
+    public ILookupParameter<ItemArray<BoolValue>> MoveTabuParameter {
+      get { return (ILookupParameter<ItemArray<BoolValue>>)Parameters["MoveTabu"]; }
+    }
+    public IValueLookupParameter<BoolValue> CopySelectedParameter {
+      get { return (IValueLookupParameter<BoolValue>)Parameters["CopySelected"]; }
+    }
+    public ILookupParameter<BoolValue> EmptyNeighborhoodParameter {
+      get { return (ILookupParameter<BoolValue>)Parameters["EmptyNeighborhood"]; }
+    }
+
+    public BoolValue CopySelected {
+      get { return CopySelectedParameter.Value; }
+      set { CopySelectedParameter.Value = value; }
+    }
+
+    [StorableConstructor]
+    protected TabuSelector(bool deserializing) : base(deserializing) { }
+    protected TabuSelector(TabuSelector original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new TabuSelector(this, cloner);
+    }
+
+    /// <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<DoubleValue>("BestQuality", "The best found quality so far."));
+      Parameters.Add(new ValueLookupParameter<BoolValue>("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 BoolValue(true)));
+      Parameters.Add(new ValueLookupParameter<BoolValue>("Maximization", "Whether the problem is a maximization or minimization problem (used to decide whether a solution is better"));
+      Parameters.Add(new ScopeTreeLookupParameter<DoubleValue>("MoveQuality", "The quality of the move."));
+      Parameters.Add(new ScopeTreeLookupParameter<BoolValue>("MoveTabu", "The tabu status of the move."));
+      Parameters.Add(new ValueLookupParameter<BoolValue>("CopySelected", "True if the selected move should be copied.", new BoolValue(false)));
+      Parameters.Add(new LookupParameter<BoolValue>("EmptyNeighborhood", "Will be set to true if the neighborhood didn't contain any non-tabu moves, otherwise it is set to false."));
+    }
+
+    /// <summary>
+    /// Implements the tabu selection with the default aspiration criteria (choose a tabu move when it is better than the best so far).
+    /// </summary>
+    /// <exception cref="InvalidOperationException">Thrown when the neighborhood contained too little moves which are not tabu.</exception>
+    /// <param name="scopes">The scopes from which to select.</param>
+    /// <returns>The selected scopes.</returns>
+    protected override IScope[] Select(List<IScope> scopes) {
+      bool copy = CopySelectedParameter.Value.Value;
+      bool aspiration = AspirationParameter.ActualValue.Value;
+      bool maximization = MaximizationParameter.ActualValue.Value;
+      double bestQuality = BestQualityParameter.ActualValue.Value;
+      ItemArray<DoubleValue> moveQualities = MoveQualityParameter.ActualValue;
+      ItemArray<BoolValue> moveTabus = MoveTabuParameter.ActualValue;
+
+      IScope[] selected = new IScope[1];
+
+      // remember scopes that should be removed
+      List<int> scopesToRemove = new List<int>();
+      for (int i = 0; i < scopes.Count; i++) {
+        if (!moveTabus[i].Value
+          || aspiration && IsBetter(maximization, moveQualities[i].Value, bestQuality)) {
+          scopesToRemove.Add(i);
+          if (copy) selected[0] = (IScope)scopes[i].Clone();
+          else selected[0] = scopes[i];
+          break;
+        }
+      }
+
+      if (selected[0] == null) {
+        EmptyNeighborhoodParameter.ActualValue = new BoolValue(true);
+        selected[0] = new Scope("All moves are tabu.");
+      } else EmptyNeighborhoodParameter.ActualValue = new BoolValue(false);
+
+      // 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;
+    }
+
+    private bool IsBetter(bool maximization, double moveQuality, double bestQuality) {
+      return (maximization && moveQuality > bestQuality || !maximization && moveQuality < bestQuality);
+    }
+  }
+}
