Index: branches/2987_MOEAD_Algorithm/HeuristicLab.Algorithms.MOEAD-3.4.sln
===================================================================
--- branches/2987_MOEAD_Algorithm/HeuristicLab.Algorithms.MOEAD-3.4.sln	(revision 16560)
+++ branches/2987_MOEAD_Algorithm/HeuristicLab.Algorithms.MOEAD-3.4.sln	(revision 16560)
@@ -0,0 +1,37 @@
+﻿
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.28307.329
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.Algorithms.MOEAD-3.4", "HeuristicLab.Algorithms.MOEAD\3.4\HeuristicLab.Algorithms.MOEAD-3.4.csproj", "{15452B9F-A436-4139-8EE7-DA72FB8D3664}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Debug|x64 = Debug|x64
+		Debug|x86 = Debug|x86
+		Release|Any CPU = Release|Any CPU
+		Release|x64 = Release|x64
+		Release|x86 = Release|x86
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{15452B9F-A436-4139-8EE7-DA72FB8D3664}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{15452B9F-A436-4139-8EE7-DA72FB8D3664}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{15452B9F-A436-4139-8EE7-DA72FB8D3664}.Debug|x64.ActiveCfg = Debug|x64
+		{15452B9F-A436-4139-8EE7-DA72FB8D3664}.Debug|x64.Build.0 = Debug|x64
+		{15452B9F-A436-4139-8EE7-DA72FB8D3664}.Debug|x86.ActiveCfg = Debug|x86
+		{15452B9F-A436-4139-8EE7-DA72FB8D3664}.Debug|x86.Build.0 = Debug|x86
+		{15452B9F-A436-4139-8EE7-DA72FB8D3664}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{15452B9F-A436-4139-8EE7-DA72FB8D3664}.Release|Any CPU.Build.0 = Release|Any CPU
+		{15452B9F-A436-4139-8EE7-DA72FB8D3664}.Release|x64.ActiveCfg = Release|x64
+		{15452B9F-A436-4139-8EE7-DA72FB8D3664}.Release|x64.Build.0 = Release|x64
+		{15452B9F-A436-4139-8EE7-DA72FB8D3664}.Release|x86.ActiveCfg = Release|x86
+		{15452B9F-A436-4139-8EE7-DA72FB8D3664}.Release|x86.Build.0 = Release|x86
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {869173B1-B417-4ED0-9A2F-8F42578EA993}
+	EndGlobalSection
+EndGlobal
Index: branches/2987_MOEAD_Algorithm/HeuristicLab.Algorithms.MOEAD/3.4/HeuristicLab.Algorithms.MOEAD-3.4.csproj
===================================================================
--- branches/2987_MOEAD_Algorithm/HeuristicLab.Algorithms.MOEAD/3.4/HeuristicLab.Algorithms.MOEAD-3.4.csproj	(revision 16560)
+++ branches/2987_MOEAD_Algorithm/HeuristicLab.Algorithms.MOEAD/3.4/HeuristicLab.Algorithms.MOEAD-3.4.csproj	(revision 16560)
@@ -0,0 +1,207 @@
+﻿<?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>{15452B9F-A436-4139-8EE7-DA72FB8D3664}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>HeuristicLab.Algorithms.MOEAD</RootNamespace>
+    <AssemblyName>HeuristicLab.Algorithms.MOEAD-3.4</AssemblyName>
+    <TargetFrameworkVersion>v4.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>
+    <TargetFrameworkProfile />
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\..\..\..\trunk\bin\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>..\..\..\..\trunk\bin\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>..\..\..\..\trunk\bin\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+    <OutputPath>..\..\..\..\trunk\bin\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x86</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x64' ">
+    <DebugSymbols>true</DebugSymbols>
+    <OutputPath>..\..\..\..\trunk\bin\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <DebugType>full</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
+    <OutputPath>..\..\..\..\trunk\bin\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <Optimize>true</Optimize>
+    <DebugType>pdbonly</DebugType>
+    <PlatformTarget>x64</PlatformTarget>
+    <ErrorReport>prompt</ErrorReport>
+    <CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
+    <Prefer32Bit>false</Prefer32Bit>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="HeuristicLab.Analysis-3.3">
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Analysis-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Collections-3.3">
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Collections-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Common-3.3">
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Common-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Core-3.3">
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Core-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Data-3.3">
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Data-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Operators-3.3">
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Operators-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Optimization-3.3">
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Optimization-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Parameters-3.3">
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Parameters-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Persistence-3.3">
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Persistence-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.PluginInfrastructure-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.PluginInfrastructure-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Random-3.3">
+      <HintPath>..\..\..\..\trunk\bin\HeuristicLab.Random-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="HeuristicLab.snk" />
+    <None Include="Plugin.cs.frame" />
+    <Compile Include="MOEADAlgorithm.cs" />
+    <Compile Include="MOEADAlgorithmBase.cs" />
+    <Compile Include="MOEADSolution.cs" />
+    <Compile Include="MOEADUtil.cs" />
+    <Compile Include="Plugin.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <None Include="Properties\AssemblyInfo.cs.frame" />
+  </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 Condition=" '$(OS)' == 'Windows_NT' ">set Path=%25Path%25;$(ProjectDir);$(SolutionDir)
+set ProjectDir=$(ProjectDir)
+set SolutionDir=$(SolutionDir)
+set Outdir=$(Outdir)
+
+call PreBuildEvent.cmd
+</PreBuildEvent>
+    <PreBuildEvent Condition=" '$(OS)' != 'Windows_NT' ">
+export ProjectDir=$(ProjectDir)
+export SolutionDir=$(SolutionDir)
+
+$SolutionDir/PreBuildEvent.sh
+</PreBuildEvent>
+  </PropertyGroup>
+  <PropertyGroup>
+    <PostBuildEvent>
+    </PostBuildEvent>
+  </PropertyGroup>
+</Project>
Index: branches/2987_MOEAD_Algorithm/HeuristicLab.Algorithms.MOEAD/3.4/MOEADAlgorithm.cs
===================================================================
--- branches/2987_MOEAD_Algorithm/HeuristicLab.Algorithms.MOEAD/3.4/MOEADAlgorithm.cs	(revision 16560)
+++ branches/2987_MOEAD_Algorithm/HeuristicLab.Algorithms.MOEAD/3.4/MOEADAlgorithm.cs	(revision 16560)
@@ -0,0 +1,102 @@
+﻿using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Random;
+using System.Linq;
+using CancellationToken = System.Threading.CancellationToken;
+
+namespace HeuristicLab.Algorithms.MOEAD {
+  [Item("Multi-objective Evolutionary Algorithm based on Decomposition (MOEA/D)", "MOEA/D implementation adapted from jMetal.")]
+  [StorableClass]
+  [Creatable(CreatableAttribute.Categories.PopulationBasedAlgorithms, Priority = 125)]
+  public class MOEADAlgorithm : MOEADAlgorithmBase {
+    public MOEADAlgorithm() { }
+
+    protected MOEADAlgorithm(MOEADAlgorithm original, Cloner cloner) : base(original, cloner) { }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new MOEADAlgorithm(this, cloner);
+    }
+
+    [StorableConstructor]
+    protected MOEADAlgorithm(bool deserializing) : base(deserializing) { }
+
+    protected override void Run(CancellationToken cancellationToken) {
+      var populationSize = PopulationSize.Value;
+      bool[] maximization = ((BoolArray)Problem.MaximizationParameter.ActualValue).CloneAsArray();
+      var maximumEvaluatedSolutions = MaximumEvaluatedSolutions.Value;
+      var crossover = Crossover;
+      var crossoverProbability = CrossoverProbability.Value;
+      var mutator = Mutator;
+      var mutationProbability = MutationProbability.Value;
+      var evaluator = Problem.Evaluator;
+      var analyzer = Analyzer;
+      var neighbourhoodSelectionProbability = NeighbourhoodSelectionProbability;
+      var rand = RandomParameter.Value;
+
+      // cancellation token for the inner operations which should not be immediately cancelled
+      var innerToken = new CancellationToken();
+
+      while (evaluatedSolutions < maximumEvaluatedSolutions && !cancellationToken.IsCancellationRequested) {
+        foreach (var subProblemId in Enumerable.Range(0, populationSize).Shuffle(rand)) {
+          var neighbourType = ChooseNeighborType(rand, neighbourhoodSelectionProbability);
+          var mates = MatingSelection(rand, subProblemId, 2, neighbourType); // select parents
+          var s1 = (IScope)population[mates[0]].Individual.Clone();
+          var s2 = (IScope)population[mates[1]].Individual.Clone();
+          s1.Parent = s2.Parent = globalScope;
+
+          IScope childScope = null;
+          // crossover
+          if (rand.NextDouble() < crossoverProbability) {
+            childScope = new Scope($"{mates[0]}+{mates[1]}") { Parent = executionContext.Scope };
+            childScope.SubScopes.Add(s1);
+            childScope.SubScopes.Add(s2);
+            var op = executionContext.CreateChildOperation(crossover, childScope);
+            ExecuteOperation(executionContext, innerToken, op);
+            childScope.SubScopes.Clear();
+          }
+
+          // mutation
+          if (rand.NextDouble() < mutationProbability) {
+            childScope = childScope ?? s1;
+            var op = executionContext.CreateChildOperation(mutator, childScope);
+            ExecuteOperation(executionContext, innerToken, op);
+          }
+
+          // evaluation
+          if (childScope != null) {
+            var op = executionContext.CreateChildOperation(evaluator, childScope);
+            ExecuteOperation(executionContext, innerToken, op);
+            var qualities = (DoubleArray)childScope.Variables["Qualities"].Value;
+            var childSolution = new MOEADSolution(childScope, maximization.Length, 0);
+            // set child qualities
+            for (int j = 0; j < maximization.Length; ++j) {
+              childSolution.Qualities[j] = maximization[j] ? 1 - qualities[j] : qualities[j];
+            }
+            IdealPoint.UpdateIdeal(childSolution.Qualities);
+            NadirPoint.UpdateNadir(childSolution.Qualities);
+            // update neighbourhood will insert the child into the population
+            UpdateNeighbourHood(rand, childSolution, subProblemId, neighbourType);
+
+            ++evaluatedSolutions;
+          } else {
+            // no crossover or mutation were applied, a child was not produced, do nothing
+          }
+
+          if (evaluatedSolutions >= maximumEvaluatedSolutions) {
+            break;
+          }
+        }
+        // run analyzer
+        var analyze = executionContext.CreateChildOperation(analyzer, globalScope);
+        ExecuteOperation(executionContext, innerToken, analyze);
+
+        UpdateParetoFronts();
+        Results.AddOrUpdateResult("Evaluated Solutions", new IntValue(evaluatedSolutions));
+
+        globalScope.SubScopes.Replace(population.Select(x => (IScope)x.Individual));
+      }
+    }
+  }
+}
Index: branches/2987_MOEAD_Algorithm/HeuristicLab.Algorithms.MOEAD/3.4/MOEADAlgorithmBase.cs
===================================================================
--- branches/2987_MOEAD_Algorithm/HeuristicLab.Algorithms.MOEAD/3.4/MOEADAlgorithmBase.cs	(revision 16560)
+++ branches/2987_MOEAD_Algorithm/HeuristicLab.Algorithms.MOEAD/3.4/MOEADAlgorithmBase.cs	(revision 16560)
@@ -0,0 +1,627 @@
+﻿using HeuristicLab.Analysis;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Random;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+using CancellationToken = System.Threading.CancellationToken;
+
+namespace HeuristicLab.Algorithms.MOEAD {
+  [Item("MOEADAlgorithmBase", "Base class for all MOEA/D algorithm variants.")]
+  [StorableClass]
+  public abstract class MOEADAlgorithmBase : BasicAlgorithm {
+    #region data members
+    protected enum NeighborType { NEIGHBOR, POPULATION }
+    // TCHE = Chebyshev (Tchebyshev)
+    // PBI  = Penalty-based boundary intersection
+    // AGG  = Weighted sum
+    public enum FunctionType { TCHE, PBI, AGG }
+
+    [Storable]
+    protected double[] IdealPoint { get; set; }
+    [Storable]
+    protected double[] NadirPoint { get; set; } // potentially useful for objective normalization
+
+    [Storable]
+    protected double[][] lambda;
+
+    [Storable]
+    protected int[][] neighbourhood;
+
+    [Storable]
+    protected IList<IMOEADSolution> solutions;
+
+    [Storable]
+    protected FunctionType functionType;
+
+    [Storable]
+    protected IList<IMOEADSolution> population;
+
+    [Storable]
+    protected IList<IMOEADSolution> offspringPopulation;
+
+    [Storable]
+    protected IList<IMOEADSolution> jointPopulation;
+
+    [Storable]
+    protected int evaluatedSolutions;
+
+    [Storable]
+    protected ExecutionContext executionContext;
+
+    [Storable]
+    protected IScope globalScope;
+    #endregion
+
+    #region parameters
+    private const string SeedParameterName = "Seed";
+    private const string SetSeedRandomlyParameterName = "SetSeedRandomly";
+    private const string PopulationSizeParameterName = "PopulationSize";
+    private const string ResultPopulationSizeParameterName = "ResultPopulationSize";
+    private const string CrossoverProbabilityParameterName = "CrossoverProbability";
+    private const string CrossoverParameterName = "Crossover";
+    private const string MutationProbabilityParameterName = "MutationProbability";
+    private const string MutatorParameterName = "Mutator";
+    private const string MaximumEvaluatedSolutionsParameterName = "MaximumEvaluatedSolutions";
+    private const string RandomParameterName = "Random";
+    private const string AnalyzerParameterName = "Analyzer";
+    // MOEA-D parameters
+    private const string NeighbourSizeParameterName = "NeighbourSize";
+    private const string NeighbourhoodSelectionProbabilityParameterName = "NeighbourhoodSelectionProbability";
+    private const string MaximumNumberOfReplacedSolutionsParameterName = "MaximumNumberOfReplacedSolutions";
+    private const string FunctionTypeParameterName = "FunctionType";
+
+    public IValueParameter<MultiAnalyzer> AnalyzerParameter {
+      get { return (ValueParameter<MultiAnalyzer>)Parameters[AnalyzerParameterName]; }
+    }
+
+    public IConstrainedValueParameter<StringValue> FunctionTypeParameter {
+      get { return (IConstrainedValueParameter<StringValue>)Parameters[FunctionTypeParameterName]; }
+    }
+    public IFixedValueParameter<IntValue> NeighbourSizeParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[NeighbourSizeParameterName]; }
+    }
+    public IFixedValueParameter<IntValue> MaximumNumberOfReplacedSolutionsParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[MaximumNumberOfReplacedSolutionsParameterName]; }
+    }
+    public IFixedValueParameter<DoubleValue> NeighbourhoodSelectionProbabilityParameter {
+      get { return (IFixedValueParameter<DoubleValue>)Parameters[NeighbourhoodSelectionProbabilityParameterName]; }
+    }
+    public IFixedValueParameter<IntValue> SeedParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[SeedParameterName]; }
+    }
+    public IFixedValueParameter<BoolValue> SetSeedRandomlyParameter {
+      get { return (IFixedValueParameter<BoolValue>)Parameters[SetSeedRandomlyParameterName]; }
+    }
+    private IValueParameter<IntValue> PopulationSizeParameter {
+      get { return (IValueParameter<IntValue>)Parameters[PopulationSizeParameterName]; }
+    }
+    private IValueParameter<IntValue> ResultPopulationSizeParameter {
+      get { return (IValueParameter<IntValue>)Parameters[ResultPopulationSizeParameterName]; }
+    }
+    public IValueParameter<PercentValue> CrossoverProbabilityParameter {
+      get { return (IValueParameter<PercentValue>)Parameters[CrossoverProbabilityParameterName]; }
+    }
+    public IConstrainedValueParameter<ICrossover> CrossoverParameter {
+      get { return (IConstrainedValueParameter<ICrossover>)Parameters[CrossoverParameterName]; }
+    }
+    public IValueParameter<PercentValue> MutationProbabilityParameter {
+      get { return (IValueParameter<PercentValue>)Parameters[MutationProbabilityParameterName]; }
+    }
+    public IConstrainedValueParameter<IManipulator> MutatorParameter {
+      get { return (IConstrainedValueParameter<IManipulator>)Parameters[MutatorParameterName]; }
+    }
+    public IValueParameter<IntValue> MaximumEvaluatedSolutionsParameter {
+      get { return (IValueParameter<IntValue>)Parameters[MaximumEvaluatedSolutionsParameterName]; }
+    }
+    public IValueParameter<IRandom> RandomParameter {
+      get { return (IValueParameter<IRandom>)Parameters[RandomParameterName]; }
+    }
+    #endregion
+
+    #region parameter properties
+    public new IMultiObjectiveHeuristicOptimizationProblem Problem {
+      get { return (IMultiObjectiveHeuristicOptimizationProblem)base.Problem; }
+    }
+    public int Seed {
+      get { return SeedParameter.Value.Value; }
+      set { SeedParameter.Value.Value = value; }
+    }
+    public bool SetSeedRandomly {
+      get { return SetSeedRandomlyParameter.Value.Value; }
+      set { SetSeedRandomlyParameter.Value.Value = value; }
+    }
+    public IntValue PopulationSize {
+      get { return PopulationSizeParameter.Value; }
+      set { PopulationSizeParameter.Value = value; }
+    }
+    public IntValue ResultPopulationSize {
+      get { return ResultPopulationSizeParameter.Value; }
+      set { ResultPopulationSizeParameter.Value = value; }
+    }
+    public PercentValue CrossoverProbability {
+      get { return CrossoverProbabilityParameter.Value; }
+      set { CrossoverProbabilityParameter.Value = value; }
+    }
+    public ICrossover Crossover {
+      get { return CrossoverParameter.Value; }
+      set { CrossoverParameter.Value = value; }
+    }
+    public PercentValue MutationProbability {
+      get { return MutationProbabilityParameter.Value; }
+      set { MutationProbabilityParameter.Value = value; }
+    }
+    public IManipulator Mutator {
+      get { return MutatorParameter.Value; }
+      set { MutatorParameter.Value = value; }
+    }
+    public MultiAnalyzer Analyzer {
+      get { return AnalyzerParameter.Value; }
+      set { AnalyzerParameter.Value = value; }
+    }
+    public IntValue MaximumEvaluatedSolutions {
+      get { return MaximumEvaluatedSolutionsParameter.Value; }
+      set { MaximumEvaluatedSolutionsParameter.Value = value; }
+    }
+    public int NeighbourSize {
+      get { return NeighbourSizeParameter.Value.Value; }
+      set { NeighbourSizeParameter.Value.Value = value; }
+    }
+    public int MaximumNumberOfReplacedSolutions {
+      get { return MaximumNumberOfReplacedSolutionsParameter.Value.Value; }
+      set { MaximumNumberOfReplacedSolutionsParameter.Value.Value = value; }
+    }
+    public double NeighbourhoodSelectionProbability {
+      get { return NeighbourhoodSelectionProbabilityParameter.Value.Value; }
+      set { NeighbourhoodSelectionProbabilityParameter.Value.Value = value; }
+    }
+    #endregion
+
+    #region constructors
+    public MOEADAlgorithmBase() {
+      Parameters.Add(new FixedValueParameter<IntValue>(SeedParameterName, "The random seed used to initialize the new pseudo random number generator.", new IntValue(0)));
+      Parameters.Add(new FixedValueParameter<BoolValue>(SetSeedRandomlyParameterName, "True if the random seed should be set to a random value, otherwise false.", new BoolValue(true)));
+      Parameters.Add(new ValueParameter<IntValue>(PopulationSizeParameterName, "The size of the population of solutions.", new IntValue(100)));
+      Parameters.Add(new ValueParameter<IntValue>(ResultPopulationSizeParameterName, "The size of the population of solutions.", new IntValue(100)));
+      Parameters.Add(new ValueParameter<PercentValue>(CrossoverProbabilityParameterName, "The probability that the crossover operator is applied.", new PercentValue(0.9)));
+      Parameters.Add(new ConstrainedValueParameter<ICrossover>(CrossoverParameterName, "The operator used to cross solutions."));
+      Parameters.Add(new ValueParameter<PercentValue>(MutationProbabilityParameterName, "The probability that the mutation operator is applied on a solution.", new PercentValue(0.25)));
+      Parameters.Add(new ConstrainedValueParameter<IManipulator>(MutatorParameterName, "The operator used to mutate solutions."));
+      Parameters.Add(new ValueParameter<MultiAnalyzer>("Analyzer", "The operator used to analyze each generation.", new MultiAnalyzer()));
+      Parameters.Add(new ValueParameter<IntValue>(MaximumEvaluatedSolutionsParameterName, "The maximum number of evaluated solutions (approximately).", new IntValue(100_000)));
+      Parameters.Add(new ValueParameter<IRandom>(RandomParameterName, new MersenneTwister()));
+      Parameters.Add(new FixedValueParameter<IntValue>(NeighbourSizeParameterName, new IntValue(20)));
+      Parameters.Add(new FixedValueParameter<IntValue>(MaximumNumberOfReplacedSolutionsParameterName, new IntValue(2)));
+      Parameters.Add(new FixedValueParameter<DoubleValue>(NeighbourhoodSelectionProbabilityParameterName, new DoubleValue(0.1)));
+
+      var functionTypeParameter = new ConstrainedValueParameter<StringValue>(FunctionTypeParameterName);
+      foreach (var s in new[] { "Chebyshev", "PBI", "Weighted Sum" }) {
+        functionTypeParameter.ValidValues.Add(new StringValue(s));
+      }
+      Parameters.Add(functionTypeParameter);
+    }
+
+    protected MOEADAlgorithmBase(MOEADAlgorithmBase original, Cloner cloner) : base(original, cloner) {
+      functionType = original.functionType;
+      evaluatedSolutions = original.evaluatedSolutions;
+
+      if (original.IdealPoint != null) {
+        IdealPoint = (double[])original.IdealPoint.Clone();
+      }
+
+      if (original.NadirPoint != null) {
+        NadirPoint = (double[])original.NadirPoint.Clone();
+      }
+
+      if (original.lambda != null) {
+        lambda = (double[][])original.lambda.Clone();
+      }
+
+      if (original.neighbourhood != null) {
+        neighbourhood = (int[][])original.neighbourhood.Clone();
+      }
+
+      if (original.solutions != null) {
+        solutions = original.solutions.Select(cloner.Clone).ToArray();
+      }
+
+      if (original.population != null) {
+        population = original.population.Select(cloner.Clone).ToArray();
+      }
+
+      if (original.offspringPopulation != null) {
+        offspringPopulation = original.offspringPopulation.Select(cloner.Clone).ToArray();
+      }
+
+      if (original.jointPopulation != null) {
+        jointPopulation = original.jointPopulation.Select(x => cloner.Clone(x)).ToArray();
+      }
+
+      if (original.executionContext != null) {
+        executionContext = cloner.Clone(original.executionContext);
+      }
+
+      if (original.globalScope != null) {
+        globalScope = cloner.Clone(original.globalScope);
+      }
+    }
+
+    [StorableConstructor]
+    protected MOEADAlgorithmBase(bool deserializing) : base(deserializing) { }
+    #endregion
+
+    private void InitializePopulation(ExecutionContext executionContext, CancellationToken cancellationToken, IRandom random, bool[] maximization) {
+      var creator = Problem.SolutionCreator;
+      var evaluator = Problem.Evaluator;
+
+      var dimensions = maximization.Length;
+      var populationSize = PopulationSize.Value;
+      population = new MOEADSolution[populationSize];
+
+      var parentScope = executionContext.Scope;
+      // first, create all individuals
+      for (int i = 0; i < populationSize; ++i) {
+        var childScope = new Scope(i.ToString()) { Parent = parentScope };
+        ExecuteOperation(executionContext, cancellationToken, executionContext.CreateChildOperation(creator, childScope));
+        parentScope.SubScopes.Add(childScope);
+      }
+
+      // then, evaluate them and update qualities
+      for (int i = 0; i < populationSize; ++i) {
+        var childScope = parentScope.SubScopes[i];
+        ExecuteOperation(executionContext, cancellationToken, executionContext.CreateChildOperation(evaluator, childScope));
+
+        var qualities = (DoubleArray)childScope.Variables["Qualities"].Value;
+        var solution = new MOEADSolution(childScope, dimensions, 0);
+        for (int j = 0; j < dimensions; ++j) {
+          solution.Qualities[j] = maximization[j] ? 1 - qualities[j] : qualities[j];
+        }
+        population[i] = solution;
+      }
+    }
+
+    public override void Prepare() {
+      base.Prepare();
+    }
+
+    protected override void Initialize(CancellationToken cancellationToken) {
+      globalScope = new Scope("Global Scope");
+      executionContext = new ExecutionContext(null, this, globalScope);
+
+      // set the execution context for parameters to allow lookup
+      foreach (var parameter in Problem.Parameters.OfType<IValueParameter>()) {
+        // we need all of these in order for the wiring of the operators to work
+        globalScope.Variables.Add(new Variable(parameter.Name, parameter.Value));
+      }
+      globalScope.Variables.Add(new Variable("Results", Results)); // make results available as a parameter for analyzers etc.
+
+      var rand = RandomParameter.Value;
+      if (SetSeedRandomly) Seed = RandomSeedGenerator.GetSeed();
+      rand.Reset(Seed);
+
+      bool[] maximization = ((BoolArray)Problem.MaximizationParameter.ActualValue).CloneAsArray();
+      var dimensions = maximization.Length;
+
+      var populationSize = PopulationSize.Value;
+
+      InitializePopulation(executionContext, cancellationToken, rand, maximization);
+      InitializeUniformWeights(rand, populationSize, dimensions);
+      InitializeNeighbourHood(lambda, populationSize, NeighbourSize);
+
+      IdealPoint = new double[dimensions];
+      IdealPoint.UpdateIdeal(population);
+
+      NadirPoint = new double[dimensions];
+      NadirPoint.UpdateNadir(population);
+
+      var functionTypeString = FunctionTypeParameter.Value.Value;
+      switch (functionTypeString) {
+        case "Chebyshev":
+          functionType = FunctionType.TCHE;
+          break;
+        case "PBI":
+          functionType = FunctionType.PBI;
+          break;
+        case "Weighted Sum":
+          functionType = FunctionType.AGG;
+          break;
+      }
+
+      evaluatedSolutions = populationSize;
+
+      base.Initialize(cancellationToken);
+    }
+
+    public override bool SupportsPause => true;
+
+    protected void InitializeUniformWeights(IRandom random, int populationSize, int dimensions) {
+      if (dimensions > 2) {
+        throw new ArgumentException("The current implementation doesn't support more than 2 dimensions.");
+      }
+
+      lambda = new double[populationSize][];
+      var values = SequenceGenerator.GenerateSteps(0m, 1m, 1m / populationSize).ToArray();
+
+      for (int i = 0; i < populationSize; ++i) {
+        var w = (double)values[i];
+        lambda[i] = new[] { w, 1 - w };
+      }
+      lambda.ShuffleInPlace(random);
+    }
+
+    protected void InitializeNeighbourHood(double[][] lambda, int populationSize, int neighbourSize) {
+      neighbourhood = new int[populationSize][];
+
+      var x = new double[populationSize];
+      var idx = new int[populationSize];
+
+      for (int i = 0; i < populationSize; ++i) {
+        for (int j = 0; j < populationSize; ++j) {
+          x[j] = MOEADUtil.EuclideanDistance(lambda[i], lambda[j]);
+          idx[j] = j;
+        }
+
+        MOEADUtil.MinFastSort(x, idx, populationSize, neighbourSize);
+        neighbourhood[i] = (int[])idx.Clone();
+      }
+    }
+
+    protected NeighborType ChooseNeighborType(IRandom random, double neighbourhoodSelectionProbability) {
+      return random.NextDouble() < neighbourhoodSelectionProbability
+        ? NeighborType.NEIGHBOR
+        : NeighborType.POPULATION;
+    }
+
+    protected IList<IMOEADSolution> ParentSelection(IRandom random, int subProblemId, NeighborType neighbourType) {
+      List<int> matingPool = MatingSelection(random, subProblemId, 2, neighbourType);
+
+      var parents = new IMOEADSolution[3];
+
+      parents[0] = population[matingPool[0]];
+      parents[1] = population[matingPool[1]];
+      parents[2] = population[subProblemId];
+
+      return parents;
+    }
+
+    protected List<int> MatingSelection(IRandom random, int subproblemId, int numberOfSolutionsToSelect, NeighborType neighbourType) {
+      int populationSize = PopulationSize.Value;
+
+      var listOfSolutions = new List<int>(numberOfSolutionsToSelect);
+
+      int neighbourSize = neighbourhood[subproblemId].Length;
+      while (listOfSolutions.Count < numberOfSolutionsToSelect) {
+        var selectedSolution = neighbourType == NeighborType.NEIGHBOR
+          ? neighbourhood[subproblemId][random.Next(neighbourSize)]
+          : random.Next(populationSize);
+
+        bool flag = true;
+        foreach (int individualId in listOfSolutions) {
+          if (individualId == selectedSolution) {
+            flag = false;
+            break;
+          }
+        }
+
+        if (flag) {
+          listOfSolutions.Add(selectedSolution);
+        }
+      }
+
+      return listOfSolutions;
+    }
+
+    protected void UpdateNeighbourHood(IRandom random, IMOEADSolution individual, int subProblemId, NeighborType neighbourType) {
+      int replacedSolutions = 0;
+      int size = neighbourType == NeighborType.NEIGHBOR ? NeighbourSize : population.Count;
+
+      foreach (var i in Enumerable.Range(0, size).Shuffle(random)) {
+        int k = neighbourType == NeighborType.NEIGHBOR
+          ? neighbourhood[subProblemId][i]
+          : i;
+
+        double f1 = CalculateFitness(population[k].Qualities, lambda[k]);
+        double f2 = CalculateFitness(individual.Qualities, lambda[k]);
+
+        if (f2 < f1) {
+          population[k] = (IMOEADSolution)individual.Clone();
+          replacedSolutions++;
+        }
+
+        if (replacedSolutions >= MaximumNumberOfReplacedSolutions) {
+          return;
+        }
+      }
+    }
+
+    private double CalculateFitness(double[] qualities, double[] lambda) {
+      double fitness;
+      int dim = qualities.Length;
+      switch (functionType) {
+        case FunctionType.TCHE: {
+            double maxFun = -1.0e+30;
+
+            for (int n = 0; n < dim; n++) {
+              double diff = Math.Abs(qualities[n] - IdealPoint[n]);
+
+              double feval = lambda[n] == 0 ? 0.0001 * diff : diff * lambda[n];
+              if (feval > maxFun) {
+                maxFun = feval;
+              }
+            }
+
+            fitness = maxFun;
+            return fitness;
+          }
+        case FunctionType.AGG: {
+            double sum = 0.0;
+            for (int n = 0; n < dim; n++) {
+              sum += lambda[n] * qualities[n];
+            }
+
+            fitness = sum;
+            return fitness;
+          }
+        case FunctionType.PBI: {
+            double d1, d2, nl;
+            double theta = 5.0;
+            int dimensions = dim;
+
+            d1 = d2 = nl = 0.0;
+
+            for (int i = 0; i < dimensions; i++) {
+              d1 += (qualities[i] - IdealPoint[i]) * lambda[i];
+              nl += Math.Pow(lambda[i], 2.0);
+            }
+            nl = Math.Sqrt(nl);
+            d1 = Math.Abs(d1) / nl;
+
+            for (int i = 0; i < dimensions; i++) {
+              d2 += Math.Pow((qualities[i] - IdealPoint[i]) - d1 * (lambda[i] / nl), 2.0);
+            }
+            d2 = Math.Sqrt(d2);
+
+            fitness = (d1 + theta * d2);
+            return fitness;
+          }
+        default: {
+            throw new ArgumentException($"Unknown function type: {functionType}");
+          }
+      }
+    }
+
+    public IList<IMOEADSolution> GetResult(IRandom random) {
+      var populationSize = PopulationSize.Value;
+      var resultPopulationSize = ResultPopulationSize.Value;
+
+      if (populationSize > resultPopulationSize) {
+        return MOEADUtil.GetSubsetOfEvenlyDistributedSolutions(random, population, resultPopulationSize);
+      } else {
+        return population;
+      }
+    }
+
+    protected void UpdateParetoFronts() {
+      bool dominates(Point2D<double> x, Point2D<double> y) => x.X <= y.X && x.Y <= y.Y;
+      // get all non-dominated points
+      var points = population.Select(x => new Point2D<double>(Math.Round(x.Qualities[0], 6), Math.Round(x.Qualities[1], 6))).OrderBy(_ => _.X).ThenBy(_ => _.Y).ToArray();
+      var dominated = new bool[points.Length];
+
+      for (int i = 0; i < points.Length; ++i) {
+        if (dominated[i]) { continue; }
+        for (int j = 0; j < points.Length; ++j) {
+          if (i == j) { continue; }
+          if (dominated[j]) { continue; }
+          dominated[j] = dominates(points[i], points[j]);
+        }
+      }
+
+      var pf = Enumerable.Range(0, dominated.Length).Where(x => !dominated[x]).Select(x => points[x]);
+
+      ScatterPlot sp;
+      if (!Results.ContainsKey("Pareto Front")) {
+        sp = new ScatterPlot();
+        sp.Rows.Add(new ScatterPlotDataRow("Pareto Front", "", pf) { VisualProperties = { PointSize = 5 } });
+        Results.AddOrUpdateResult("Pareto Front", sp);
+      } else {
+        sp = (ScatterPlot)Results["Pareto Front"].Value;
+        sp.Rows["Pareto Front"].Points.Replace(pf);
+      }
+    }
+
+    #region operator wiring and events
+    protected void ExecuteOperation(ExecutionContext executionContext, CancellationToken cancellationToken, IOperation operation) {
+      Stack<IOperation> executionStack = new Stack<IOperation>();
+      executionStack.Push(operation);
+      while (executionStack.Count > 0) {
+        cancellationToken.ThrowIfCancellationRequested();
+        IOperation next = executionStack.Pop();
+        if (next is OperationCollection) {
+          OperationCollection coll = (OperationCollection)next;
+          for (int i = coll.Count - 1; i >= 0; i--)
+            if (coll[i] != null) executionStack.Push(coll[i]);
+        } else if (next is IAtomicOperation) {
+          IAtomicOperation op = (IAtomicOperation)next;
+          next = op.Operator.Execute((IExecutionContext)op, cancellationToken);
+          if (next != null) executionStack.Push(next);
+        }
+      }
+    }
+
+    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 = 1;
+          Analyzer.Operators.Add(analyzer, analyzer.EnabledByDefault);
+        }
+      }
+    }
+
+    private void UpdateCrossovers() {
+      ICrossover oldCrossover = CrossoverParameter.Value;
+      CrossoverParameter.ValidValues.Clear();
+      ICrossover defaultCrossover = Problem.Operators.OfType<ICrossover>().FirstOrDefault();
+
+      foreach (ICrossover crossover in Problem.Operators.OfType<ICrossover>().OrderBy(x => x.Name))
+        CrossoverParameter.ValidValues.Add(crossover);
+
+      if (oldCrossover != null) {
+        ICrossover crossover = CrossoverParameter.ValidValues.FirstOrDefault(x => x.GetType() == oldCrossover.GetType());
+        if (crossover != null) CrossoverParameter.Value = crossover;
+        else oldCrossover = null;
+      }
+      if (oldCrossover == null && defaultCrossover != null)
+        CrossoverParameter.Value = defaultCrossover;
+    }
+
+    private void UpdateMutators() {
+      IManipulator oldMutator = MutatorParameter.Value;
+      MutatorParameter.ValidValues.Clear();
+      IManipulator defaultMutator = Problem.Operators.OfType<IManipulator>().FirstOrDefault();
+
+      foreach (IManipulator mutator in Problem.Operators.OfType<IManipulator>().OrderBy(x => x.Name))
+        MutatorParameter.ValidValues.Add(mutator);
+
+      if (oldMutator != null) {
+        IManipulator mutator = MutatorParameter.ValidValues.FirstOrDefault(x => x.GetType() == oldMutator.GetType());
+        if (mutator != null) MutatorParameter.Value = mutator;
+        else oldMutator = null;
+      }
+
+      if (oldMutator == null && defaultMutator != null)
+        MutatorParameter.Value = defaultMutator;
+    }
+
+    protected override void OnProblemChanged() {
+      UpdateCrossovers();
+      UpdateMutators();
+      UpdateAnalyzers();
+      base.OnProblemChanged();
+    }
+
+    protected override void OnStopped() {
+      if (solutions != null) {
+        solutions.Clear();
+      }
+      if (population != null) {
+        population.Clear();
+      }
+      if (offspringPopulation != null) {
+        offspringPopulation.Clear();
+      }
+      if (jointPopulation != null) {
+        jointPopulation.Clear();
+      }
+      base.OnStopped();
+    }
+    #endregion
+  }
+}
Index: branches/2987_MOEAD_Algorithm/HeuristicLab.Algorithms.MOEAD/3.4/MOEADSolution.cs
===================================================================
--- branches/2987_MOEAD_Algorithm/HeuristicLab.Algorithms.MOEAD/3.4/MOEADSolution.cs	(revision 16560)
+++ branches/2987_MOEAD_Algorithm/HeuristicLab.Algorithms.MOEAD/3.4/MOEADSolution.cs	(revision 16560)
@@ -0,0 +1,79 @@
+﻿using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.MOEAD {
+  public interface IMOEADSolution : IItem {
+    IItem Individual { get; set; }
+    double[] Qualities { get; set; }
+    double[] Constraints { get; set; }
+    int Dimensions { get; }
+  }
+
+  [Item("MOEADSolution", "Represents a solution inside the MOEA/D population")]
+  [StorableClass]
+  public class MOEADSolution : Item, IMOEADSolution {
+    [Storable]
+    public IItem Individual { get; set; }
+
+    [Storable]
+    public double[] Qualities { get; set; }
+
+    [Storable]
+    public double[] Constraints { get; set; }
+
+    public MOEADSolution(int nObjectives, int nConstraints) {
+      Qualities = new double[nObjectives];
+      Constraints = new double[nConstraints];
+    }
+
+    public MOEADSolution(IItem individual, int nObjectives, int nConstraints) : this(nObjectives, nConstraints) {
+      Individual = individual;
+    }
+
+    public MOEADSolution(IItem individual, double[] qualities, double[] constraints) {
+      Individual = individual;
+      Qualities = qualities;
+      Constraints = constraints;
+    }
+
+    public MOEADSolution(double[] qualities) {
+      Qualities = (double[])qualities.Clone();
+    }
+
+    public int Dimensions => Qualities == null ? 0 : Qualities.Length;
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new MOEADSolution(this, cloner);
+    }
+
+    protected MOEADSolution(MOEADSolution original, Cloner cloner) : base(original, cloner) {
+      Qualities = (double[])original.Qualities.Clone();
+      Constraints = (double[])original.Qualities.Clone();
+      Individual = (IItem)original.Individual.Clone(cloner);
+    }
+
+    [StorableConstructor]
+    protected MOEADSolution(bool deserializing) : base(deserializing) { }
+  }
+
+  [Item("MOEADSolution", "Represents a solution inside the MOEA/D population")]
+  [StorableClass]
+  public class MOEADSolution<T> : MOEADSolution where T : class, IItem {
+    public new T Individual {
+      get { return (T)base.Individual; }
+      set { base.Individual = value; }
+    }
+
+    public MOEADSolution(T individual, int nObjectives, int nConstraints) : base(individual, nObjectives, nConstraints) { }
+
+    protected MOEADSolution(MOEADSolution<T> original, Cloner cloner) : base(original, cloner) { }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new MOEADSolution<T>(this, cloner);
+    }
+
+    [StorableConstructor]
+    protected MOEADSolution(bool deserializing) : base(deserializing) { }
+  }
+}
Index: branches/2987_MOEAD_Algorithm/HeuristicLab.Algorithms.MOEAD/3.4/MOEADUtil.cs
===================================================================
--- branches/2987_MOEAD_Algorithm/HeuristicLab.Algorithms.MOEAD/3.4/MOEADUtil.cs	(revision 16560)
+++ branches/2987_MOEAD_Algorithm/HeuristicLab.Algorithms.MOEAD/3.4/MOEADUtil.cs	(revision 16560)
@@ -0,0 +1,203 @@
+﻿using HeuristicLab.Common;
+using HeuristicLab.Core;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace HeuristicLab.Algorithms.MOEAD {
+  public static class MOEADUtil {
+    public static void QuickSort(double[] array, int[] idx, int from, int to) {
+      if (from < to) {
+        double temp = array[to];
+        int tempIdx = idx[to];
+        int i = from - 1;
+        for (int j = from; j < to; j++) {
+          if (array[j] <= temp) {
+            i++;
+            double tempValue = array[j];
+            array[j] = array[i];
+            array[i] = tempValue;
+            int tempIndex = idx[j];
+            idx[j] = idx[i];
+            idx[i] = tempIndex;
+          }
+        }
+        array[to] = array[i + 1];
+        array[i + 1] = temp;
+        idx[to] = idx[i + 1];
+        idx[i + 1] = tempIdx;
+        QuickSort(array, idx, from, i);
+        QuickSort(array, idx, i + 1, to);
+      }
+    }
+
+    public static void MinFastSort(double[] x, int[] idx, int n, int m) {
+      for (int i = 0; i < m; i++) {
+        for (int j = i + 1; j < n; j++) {
+          if (x[i] > x[j]) {
+            double temp = x[i];
+            x[i] = x[j];
+            x[j] = temp;
+            int id = idx[i];
+            idx[i] = idx[j];
+            idx[j] = id;
+          }
+        }
+      }
+    }
+
+    public static IList<IMOEADSolution> GetSubsetOfEvenlyDistributedSolutions(IRandom random, IList<IMOEADSolution> solutionList, int newSolutionListSize) {
+      if (solutionList == null || solutionList.Count == 0) {
+        throw new ArgumentException("Solution list is null or empty.");
+      }
+
+      return solutionList[0].Dimensions == 2
+        ? TwoObjectivesCase(solutionList, newSolutionListSize)
+        : MoreThanTwoObjectivesCase(random, solutionList, newSolutionListSize);
+    }
+
+    private static IList<IMOEADSolution> TwoObjectivesCase(IList<IMOEADSolution> solutionList, int newSolutionListSize) {
+      var resultSolutionList = new IMOEADSolution[newSolutionListSize];
+
+      // compute weight vectors
+      double[][] lambda = new double[newSolutionListSize][];
+      var values = SequenceGenerator.GenerateSteps(0m, 1m, 1m / newSolutionListSize).ToArray();
+      for (int i = 0; i < newSolutionListSize; ++i) {
+        var weights = new double[newSolutionListSize];
+        weights[0] = (double)values[i];
+        weights[1] = 1 - weights[0];
+
+        lambda[i] = weights;
+      }
+
+      var idealPoint = new double[2];
+      foreach (var solution in solutionList) {
+        // update ideal point
+        idealPoint.UpdateIdeal(solution.Qualities);
+      }
+
+      // Select the best solution for each weight vector
+      for (int i = 0; i < newSolutionListSize; i++) {
+        var currentBest = solutionList[0];
+        double value = ScalarizingFitnessFunction(currentBest, lambda[i], idealPoint);
+        for (int j = 1; j < solutionList.Count; j++) {
+          double aux = ScalarizingFitnessFunction(solutionList[j], lambda[i], idealPoint); // we are looking for the best for the weight i
+          if (aux < value) { // solution in position j is better!
+            value = aux;
+            currentBest = solutionList[j];
+          }
+        }
+        resultSolutionList[i] = (MOEADSolution)currentBest.Clone();
+      }
+
+      return resultSolutionList;
+    }
+
+    private static IList<IMOEADSolution> MoreThanTwoObjectivesCase(IRandom random, IList<IMOEADSolution> solutionList, int newSolutionListSize) {
+      var resultSolutionList = new List<IMOEADSolution>();
+
+      int randomIndex = random.Next(0, solutionList.Count);
+
+      var candidate = new List<IMOEADSolution>();
+      resultSolutionList.Add(solutionList[randomIndex]);
+
+      for (int i = 0; i < solutionList.Count; ++i) {
+        if (i != randomIndex) {
+          candidate.Add(solutionList[i]);
+        }
+      }
+
+      while (resultSolutionList.Count < newSolutionListSize) {
+        int index = 0;
+        var selected = candidate[0]; // it should be a next! (n <= population size!)
+        double aux = CalculateBestDistance(selected, solutionList);
+        int i = 1;
+        while (i < candidate.Count) {
+          var nextCandidate = candidate[i];
+          double distanceValue = CalculateBestDistance(nextCandidate, solutionList);
+          if (aux < distanceValue) {
+            index = i;
+            aux = distanceValue;
+          }
+          i++;
+        }
+
+        // add the selected to res and remove from candidate list
+        var removedSolution = candidate[index];
+        candidate.RemoveAt(index);
+        resultSolutionList.Add((MOEADSolution)removedSolution.Clone());
+      }
+
+      return resultSolutionList;
+    }
+
+    private static double ScalarizingFitnessFunction(IMOEADSolution currentBest, double[] lambda, double[] idealPoint) {
+      double maxFun = -1.0e+30;
+
+      for (int n = 0; n < idealPoint.Length; n++) {
+        double diff = Math.Abs(currentBest.Qualities[n] - idealPoint[n]);
+
+        double functionValue;
+        if (lambda[n] == 0) {
+          functionValue = 0.0001 * diff;
+        } else {
+          functionValue = diff * lambda[n];
+        }
+        if (functionValue > maxFun) {
+          maxFun = functionValue;
+        }
+      }
+
+      return maxFun;
+    }
+
+    public static void UpdateIdeal(this double[] idealPoint, double[] point) {
+      for (int i = 0; i < point.Length; ++i) {
+        if (idealPoint[i] > point[i]) {
+          idealPoint[i] = point[i];
+        }
+      }
+    }
+
+    public static void UpdateNadir(this double[] nadirPoint, double[] point) {
+      for (int i = 0; i < point.Length; ++i) {
+        if (nadirPoint[i] < point[i]) {
+          nadirPoint[i] = point[i];
+        }
+      }
+    }
+
+    public static void UpdateIdeal(this double[] idealPoint, IList<IMOEADSolution> solutions) {
+      foreach (var s in solutions) {
+        idealPoint.UpdateIdeal(s.Qualities);
+      }
+    }
+
+    public static void UpdateNadir(this double[] nadirPoint, IList<IMOEADSolution> solutions) {
+      foreach (var s in solutions) {
+        nadirPoint.UpdateNadir(s.Qualities);
+      }
+    }
+
+    private static double CalculateBestDistance(IMOEADSolution solution, IList<IMOEADSolution> solutionList) {
+      var best = solutionList.Min(x => EuclideanDistance(solution.Qualities, x.Qualities));
+      if (double.IsNaN(best) || double.IsInfinity(best)) {
+        best = double.MaxValue;
+      }
+      return best;
+    }
+
+    public static double EuclideanDistance(double[] a, double[] b) {
+      if (a.Length != b.Length) {
+        throw new ArgumentException("Euclidean distance: the arrays have different lengths.");
+      }
+
+      var distance = 0d;
+      for (int i = 0; i < a.Length; ++i) {
+        var d = a[i] - b[i];
+        distance += d * d;
+      }
+      return Math.Sqrt(distance);
+    }
+  }
+}
Index: branches/2987_MOEAD_Algorithm/HeuristicLab.Algorithms.MOEAD/3.4/Plugin.cs
===================================================================
--- branches/2987_MOEAD_Algorithm/HeuristicLab.Algorithms.MOEAD/3.4/Plugin.cs	(revision 16560)
+++ branches/2987_MOEAD_Algorithm/HeuristicLab.Algorithms.MOEAD/3.4/Plugin.cs	(revision 16560)
@@ -0,0 +1,39 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2018 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.MOEAD {
+  [Plugin("HeuristicLab.Algorithms.MOEAD", "Provides the multi-objective evolutonary algorithm based on decomposition (MOEA/D) as described by Zhang and Li: MOEA/D: A Multiobjective Evolutionary Algorithm Based on Decomposition, IEEE Transactions on Evolutionary Computation, Volume 11, Issue 6, Dec. 2007, pp. 712-731", "3.4.25.0")]
+  [PluginFile("HeuristicLab.Algorithms.MOEAD-3.4.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.Parameters", "3.3")]
+  [PluginDependency("HeuristicLab.Persistence", "3.3")]
+  [PluginDependency("HeuristicLab.Random", "3.3")]
+  public class HeuristicLabAlgorithmsMOEADPlugin : PluginBase {
+  }
+}
Index: branches/2987_MOEAD_Algorithm/HeuristicLab.Algorithms.MOEAD/3.4/Plugin.cs.frame
===================================================================
--- branches/2987_MOEAD_Algorithm/HeuristicLab.Algorithms.MOEAD/3.4/Plugin.cs.frame	(revision 16560)
+++ branches/2987_MOEAD_Algorithm/HeuristicLab.Algorithms.MOEAD/3.4/Plugin.cs.frame	(revision 16560)
@@ -0,0 +1,39 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2018 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.MOEAD {
+  [Plugin("HeuristicLab.Algorithms.MOEAD", "Provides the multi-objective evolutonary algorithm based on decomposition (MOEA/D) as described by Zhang and Li: MOEA/D: A Multiobjective Evolutionary Algorithm Based on Decomposition, IEEE Transactions on Evolutionary Computation, Volume 11, Issue 6, Dec. 2007, pp. 712-731", "3.4.25.$WCREV$")]
+  [PluginFile("HeuristicLab.Algorithms.MOEAD-3.4.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.Parameters", "3.3")]
+  [PluginDependency("HeuristicLab.Persistence", "3.3")]
+  [PluginDependency("HeuristicLab.Random", "3.3")]
+  public class HeuristicLabAlgorithmsMOEADPlugin : PluginBase {
+  }
+}
Index: branches/2987_MOEAD_Algorithm/HeuristicLab.Algorithms.MOEAD/3.4/Properties/AssemblyInfo.cs
===================================================================
--- branches/2987_MOEAD_Algorithm/HeuristicLab.Algorithms.MOEAD/3.4/Properties/AssemblyInfo.cs	(revision 16560)
+++ branches/2987_MOEAD_Algorithm/HeuristicLab.Algorithms.MOEAD/3.4/Properties/AssemblyInfo.cs	(revision 16560)
@@ -0,0 +1,57 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2018 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.CompilerServices;
+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.NSGA2")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("HEAL")]
+[assembly: AssemblyProduct("HeuristicLab")]
+[assembly: AssemblyCopyright("(c) 2002-2018 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("7d0fdb00-8511-45a2-ae51-c830b0c9b548")]
+
+// 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("1.0.*")]
+[assembly: AssemblyVersion("3.3.0.0")]
+[assembly: AssemblyFileVersion("3.3.15.0")]
Index: branches/2987_MOEAD_Algorithm/HeuristicLab.Algorithms.MOEAD/3.4/Properties/AssemblyInfo.cs.frame
===================================================================
--- branches/2987_MOEAD_Algorithm/HeuristicLab.Algorithms.MOEAD/3.4/Properties/AssemblyInfo.cs.frame	(revision 16560)
+++ branches/2987_MOEAD_Algorithm/HeuristicLab.Algorithms.MOEAD/3.4/Properties/AssemblyInfo.cs.frame	(revision 16560)
@@ -0,0 +1,57 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2018 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.CompilerServices;
+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.NSGA2")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("HEAL")]
+[assembly: AssemblyProduct("HeuristicLab")]
+[assembly: AssemblyCopyright("(c) 2002-2018 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("7d0fdb00-8511-45a2-ae51-c830b0c9b548")]
+
+// 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("1.0.*")]
+[assembly: AssemblyVersion("3.3.0.0")]
+[assembly: AssemblyFileVersion("3.3.15.$WCREV$")]
Index: branches/2987_MOEAD_Algorithm/MOEAD_Algorithm.sln
===================================================================
--- branches/2987_MOEAD_Algorithm/MOEAD_Algorithm.sln	(revision 16559)
+++ 	(revision )
@@ -1,37 +1,0 @@
-﻿
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.28307.271
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.Algorithms.DataAnalysis-3.4", "HeuristicLab.Algorithms.DataAnalysis\3.4\HeuristicLab.Algorithms.DataAnalysis-3.4.csproj", "{2E782078-FA81-4B70-B56F-74CE38DAC6C8}"
-EndProject
-Global
-	GlobalSection(SolutionConfigurationPlatforms) = preSolution
-		Debug|Any CPU = Debug|Any CPU
-		Debug|x64 = Debug|x64
-		Debug|x86 = Debug|x86
-		Release|Any CPU = Release|Any CPU
-		Release|x64 = Release|x64
-		Release|x86 = Release|x86
-	EndGlobalSection
-	GlobalSection(ProjectConfigurationPlatforms) = postSolution
-		{2E782078-FA81-4B70-B56F-74CE38DAC6C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{2E782078-FA81-4B70-B56F-74CE38DAC6C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{2E782078-FA81-4B70-B56F-74CE38DAC6C8}.Debug|x64.ActiveCfg = Debug|x64
-		{2E782078-FA81-4B70-B56F-74CE38DAC6C8}.Debug|x64.Build.0 = Debug|x64
-		{2E782078-FA81-4B70-B56F-74CE38DAC6C8}.Debug|x86.ActiveCfg = Debug|x86
-		{2E782078-FA81-4B70-B56F-74CE38DAC6C8}.Debug|x86.Build.0 = Debug|x86
-		{2E782078-FA81-4B70-B56F-74CE38DAC6C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{2E782078-FA81-4B70-B56F-74CE38DAC6C8}.Release|Any CPU.Build.0 = Release|Any CPU
-		{2E782078-FA81-4B70-B56F-74CE38DAC6C8}.Release|x64.ActiveCfg = Release|x64
-		{2E782078-FA81-4B70-B56F-74CE38DAC6C8}.Release|x64.Build.0 = Release|x64
-		{2E782078-FA81-4B70-B56F-74CE38DAC6C8}.Release|x86.ActiveCfg = Release|x86
-		{2E782078-FA81-4B70-B56F-74CE38DAC6C8}.Release|x86.Build.0 = Release|x86
-	EndGlobalSection
-	GlobalSection(SolutionProperties) = preSolution
-		HideSolutionNode = FALSE
-	EndGlobalSection
-	GlobalSection(ExtensibilityGlobals) = postSolution
-		SolutionGuid = {F7397391-0DB4-4978-9C01-1CBB53D604A7}
-	EndGlobalSection
-EndGlobal
