Index: /trunk/sources/HeuristicLab.Optimization.Operators/3.3/HeuristicLab.Optimization.Operators-3.3.csproj
===================================================================
--- /trunk/sources/HeuristicLab.Optimization.Operators/3.3/HeuristicLab.Optimization.Operators-3.3.csproj	(revision 3870)
+++ /trunk/sources/HeuristicLab.Optimization.Operators/3.3/HeuristicLab.Optimization.Operators-3.3.csproj	(revision 3871)
@@ -81,4 +81,9 @@
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="UserDefinedCrossover.cs" />
+    <Compile Include="UserDefinedEvaluator.cs" />
+    <Compile Include="UserDefinedManipulator.cs" />
+    <Compile Include="UserDefinedOperator.cs" />
+    <Compile Include="UserDefinedSolutionCreator.cs" />
     <Compile Include="ProbabilisticQualityComparator.cs" />
     <Compile Include="ResultsCollector.cs" />
Index: /trunk/sources/HeuristicLab.Optimization.Operators/3.3/UserDefinedCrossover.cs
===================================================================
--- /trunk/sources/HeuristicLab.Optimization.Operators/3.3/UserDefinedCrossover.cs	(revision 3871)
+++ /trunk/sources/HeuristicLab.Optimization.Operators/3.3/UserDefinedCrossover.cs	(revision 3871)
@@ -0,0 +1,30 @@
+﻿#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.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Optimization.Operators {
+  [Item("UserDefinedCrossover", "A crossover that can be customized with operators which it will execute one after another.")]
+  [StorableClass]
+  public class UserDefinedCrossover : UserDefinedOperator, ICrossover {
+  }
+}
Index: /trunk/sources/HeuristicLab.Optimization.Operators/3.3/UserDefinedEvaluator.cs
===================================================================
--- /trunk/sources/HeuristicLab.Optimization.Operators/3.3/UserDefinedEvaluator.cs	(revision 3871)
+++ /trunk/sources/HeuristicLab.Optimization.Operators/3.3/UserDefinedEvaluator.cs	(revision 3871)
@@ -0,0 +1,40 @@
+﻿#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.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Optimization.Operators {
+  [Item("UserDefinedEvaluator", "An evaluator that can be customized with operators which it will execute one after another.")]
+  [StorableClass]
+  public class UserDefinedEvaluator : UserDefinedOperator, ISingleObjectiveEvaluator {
+    public ILookupParameter<DoubleValue> QualityParameter {
+      get { return (ILookupParameter<DoubleValue>)Parameters["Quality"]; }
+    }
+
+    public UserDefinedEvaluator()
+      : base() {
+      Parameters.Add(new LookupParameter<DoubleValue>("Quality", "The quality value of the solution."));
+    }
+  }
+}
Index: /trunk/sources/HeuristicLab.Optimization.Operators/3.3/UserDefinedManipulator.cs
===================================================================
--- /trunk/sources/HeuristicLab.Optimization.Operators/3.3/UserDefinedManipulator.cs	(revision 3871)
+++ /trunk/sources/HeuristicLab.Optimization.Operators/3.3/UserDefinedManipulator.cs	(revision 3871)
@@ -0,0 +1,30 @@
+﻿#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.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Optimization.Operators {
+  [Item("UserDefinedManipulator", "A manipulator that can be customized with operators which it will execute one after another.")]
+  [StorableClass]
+  public class UserDefinedManipulator : UserDefinedOperator, IManipulator {
+  }
+}
Index: /trunk/sources/HeuristicLab.Optimization.Operators/3.3/UserDefinedOperator.cs
===================================================================
--- /trunk/sources/HeuristicLab.Optimization.Operators/3.3/UserDefinedOperator.cs	(revision 3871)
+++ /trunk/sources/HeuristicLab.Optimization.Operators/3.3/UserDefinedOperator.cs	(revision 3871)
@@ -0,0 +1,40 @@
+﻿#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.Core;
+using HeuristicLab.Operators;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Optimization.Operators {
+  [Item("UserDefinedOperator", "An operator that can be parameterized with multiple operators which will be executed one after another.")]
+  [StorableClass]
+  public abstract class UserDefinedOperator : CheckedMultiOperator<IOperator> {
+    public override IOperation Apply() {
+      OperationCollection result = new OperationCollection();
+      foreach (IOperator op in Operators.CheckedItems.OrderBy(x => x.Index).Select(x => x.Value)) {
+        result.Add(ExecutionContext.CreateOperation(op));
+      }
+      result.Add(base.Apply());
+      return result;
+    }
+  }
+}
Index: /trunk/sources/HeuristicLab.Optimization.Operators/3.3/UserDefinedSolutionCreator.cs
===================================================================
--- /trunk/sources/HeuristicLab.Optimization.Operators/3.3/UserDefinedSolutionCreator.cs	(revision 3871)
+++ /trunk/sources/HeuristicLab.Optimization.Operators/3.3/UserDefinedSolutionCreator.cs	(revision 3871)
@@ -0,0 +1,30 @@
+﻿#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.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Optimization.Operators {
+  [Item("UserDefinedSolutionCreator", "A solution creator that can be customized with operators which it will execute one after another.")]
+  [StorableClass]
+  public class UserDefinedSolutionCreator : UserDefinedOperator, ISolutionCreator {
+  }
+}
Index: /trunk/sources/HeuristicLab.Optimization/3.3/HeuristicLab.Optimization-3.3.csproj
===================================================================
--- /trunk/sources/HeuristicLab.Optimization/3.3/HeuristicLab.Optimization-3.3.csproj	(revision 3870)
+++ /trunk/sources/HeuristicLab.Optimization/3.3/HeuristicLab.Optimization-3.3.csproj	(revision 3871)
@@ -143,4 +143,5 @@
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="ResultCollection.cs" />
+    <Compile Include="UserDefinedProblem.cs" />
   </ItemGroup>
   <ItemGroup>
Index: /trunk/sources/HeuristicLab.Optimization/3.3/UserDefinedProblem.cs
===================================================================
--- /trunk/sources/HeuristicLab.Optimization/3.3/UserDefinedProblem.cs	(revision 3871)
+++ /trunk/sources/HeuristicLab.Optimization/3.3/UserDefinedProblem.cs	(revision 3871)
@@ -0,0 +1,214 @@
+﻿#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.Drawing;
+using System.Linq;
+using HeuristicLab.Collections;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Optimization {
+  /// <summary>
+  /// A problem which can be defined by the user.
+  /// </summary>
+  [Item("User-Defined Problem", "A problem which can be defined by the user.")]
+  [Creatable("Problems")]
+  [StorableClass]
+  public sealed class UserDefinedProblem : ParameterizedNamedItem, ISingleObjectiveProblem {
+    public override Image ItemImage {
+      get { return HeuristicLab.Common.Resources.VS2008ImageLibrary.Type; }
+    }
+    public new ParameterCollection Parameters {
+      get { return base.Parameters; }
+    }
+    IKeyedItemCollection<string, IParameter> IParameterizedItem.Parameters {
+      get { return Parameters; }
+    }
+
+    #region Parameters
+    public IValueParameter<ISingleObjectiveEvaluator> EvaluatorParameter {
+      get { return (IValueParameter<ISingleObjectiveEvaluator>)Parameters["Evaluator"]; }
+    }
+    public ValueParameter<BoolValue> MaximizationParameter {
+      get { return (ValueParameter<BoolValue>)Parameters["Maximization"]; }
+    }
+    IParameter ISingleObjectiveProblem.MaximizationParameter {
+      get { return MaximizationParameter; }
+    }
+    public ValueParameter<ISolutionCreator> SolutionCreatorParameter {
+      get { return (ValueParameter<ISolutionCreator>)Parameters["SolutionCreator"]; }
+    }
+    IParameter IProblem.SolutionCreatorParameter {
+      get { return SolutionCreatorParameter; }
+    }
+    IParameter IProblem.EvaluatorParameter {
+      get { return EvaluatorParameter; }
+    }
+    public OptionalValueParameter<DoubleValue> BestKnownQualityParameter {
+      get { return (OptionalValueParameter<DoubleValue>)Parameters["BestKnownQuality"]; }
+    }
+    IParameter ISingleObjectiveProblem.BestKnownQualityParameter {
+      get { return BestKnownQualityParameter; }
+    }
+    public OptionalValueParameter<IScope> BestKnownSolutionParameter {
+      get { return (OptionalValueParameter<IScope>)Parameters["BestKnownSolution"]; }
+    }
+    public ValueParameter<ItemList<IOperator>> OperatorsParameter {
+      get { return (ValueParameter<ItemList<IOperator>>)Parameters["Operators"]; }
+    }
+    #endregion
+
+    #region Properties
+    public BoolValue Maximization {
+      get { return MaximizationParameter.Value; }
+      set { MaximizationParameter.Value = value; }
+    }
+    public ISolutionCreator SolutionCreator {
+      get { return SolutionCreatorParameter.Value; }
+      set { SolutionCreatorParameter.Value = value; }
+    }
+    ISolutionCreator IProblem.SolutionCreator {
+      get { return SolutionCreatorParameter.Value; }
+    }
+    public ISingleObjectiveEvaluator Evaluator {
+      get { return EvaluatorParameter.Value; }
+      set { EvaluatorParameter.Value = value; }
+    }
+    ISingleObjectiveEvaluator ISingleObjectiveProblem.Evaluator {
+      get { return EvaluatorParameter.Value; }
+    }
+    IEvaluator IProblem.Evaluator {
+      get { return EvaluatorParameter.Value; }
+    }
+    public DoubleValue BestKnownQuality {
+      get { return BestKnownQualityParameter.Value; }
+      set { BestKnownQualityParameter.Value = value; }
+    }
+    public IEnumerable<IOperator> Operators {
+      get { return OperatorsParameter.Value; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    private UserDefinedProblem(bool deserializing) : base(deserializing) { }
+    public UserDefinedProblem()
+      : base() {
+      Parameters.Add(new ValueParameter<ISingleObjectiveEvaluator>("Evaluator", "The evaluator that collects the values to exchange."));
+      Parameters.Add(new ValueParameter<ISolutionCreator>("SolutionCreator", "An operator to create the solution components."));
+      Parameters.Add(new ValueParameter<BoolValue>("Maximization", "Set to false as most test functions are minimization problems.", new BoolValue(false)));
+      Parameters.Add(new OptionalValueParameter<DoubleValue>("BestKnownQuality", "The quality of the best known solution of this problem."));
+      Parameters.Add(new OptionalValueParameter<IScope>("BestKnownSolution", "The best known solution for this external evaluation problem."));
+      Parameters.Add(new ValueParameter<ItemList<IOperator>>("Operators", "The operators that are passed to the algorithm.", new ItemList<IOperator>()));
+
+      AttachEventHandlers();
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      UserDefinedProblem clone = (UserDefinedProblem)base.Clone(cloner);
+      clone.AttachEventHandlers();
+      return clone;
+    }
+
+    #region Events
+    public event EventHandler SolutionCreatorChanged;
+    private void OnSolutionCreatorChanged() {
+      EventHandler handler = SolutionCreatorChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler EvaluatorChanged;
+    private void OnEvaluatorChanged() {
+      EventHandler handler = EvaluatorChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler OperatorsChanged;
+    private void OnOperatorsChanged() {
+      EventHandler handler = OperatorsChanged;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    public event EventHandler Reset;
+    private void OnReset() {
+      EventHandler handler = Reset;
+      if (handler != null) handler(this, EventArgs.Empty);
+    }
+    #endregion
+
+    #region Event handlers
+    private void SolutionCreatorParameter_ValueChanged(object sender, EventArgs e) {
+      OnSolutionCreatorChanged();
+    }
+    private void EvaluatorParameter_ValueChanged(object sender, EventArgs e) {
+      if (Evaluator != null)
+        Evaluator.QualityParameter.ActualNameChanged += new EventHandler(Evaluator_QualityParameter_ActualNameChanged);
+      ParameterizeOperators();
+      OnEvaluatorChanged();
+    }
+    private void Evaluator_QualityParameter_ActualNameChanged(object sender, EventArgs e) {
+      ParameterizeOperators();
+    }
+    private void OperatorsParameter_ValueChanged(object sender, EventArgs e) {
+      OnOperatorsChanged();
+    }
+    private void OperatorsParameter_Value_ItemsAdded(object sender, EventArgs e) {
+      OnOperatorsChanged();
+    }
+    private void OperatorsParameter_Value_ItemsRemoved(object sender, EventArgs e) {
+      OnOperatorsChanged();
+    }
+    private void OperatorsParameter_Value_CollectionReset(object sender, EventArgs e) {
+      OnOperatorsChanged();
+    }
+    #endregion
+
+    #region Helpers
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AttachEventHandlers() {
+      SolutionCreatorParameter.ValueChanged += new EventHandler(SolutionCreatorParameter_ValueChanged);
+      EvaluatorParameter.ValueChanged += new EventHandler(EvaluatorParameter_ValueChanged);
+      if (Evaluator != null)
+        Evaluator.QualityParameter.ActualNameChanged += new EventHandler(Evaluator_QualityParameter_ActualNameChanged);
+      OperatorsParameter.ValueChanged += new EventHandler(OperatorsParameter_ValueChanged);
+      OperatorsParameter.Value.ItemsAdded += new CollectionItemsChangedEventHandler<IndexedItem<IOperator>>(OperatorsParameter_Value_ItemsAdded);
+      OperatorsParameter.Value.ItemsRemoved += new CollectionItemsChangedEventHandler<IndexedItem<IOperator>>(OperatorsParameter_Value_ItemsRemoved);
+      OperatorsParameter.Value.CollectionReset += new CollectionItemsChangedEventHandler<IndexedItem<IOperator>>(OperatorsParameter_Value_CollectionReset);
+    }
+
+    private void ParameterizeOperators() {
+      // A best effort approach to wiring
+      if (Evaluator != null) {
+        string qualityName = Evaluator.QualityParameter.ActualName;
+        foreach (IOperator op in OperatorsParameter.Value) {
+          foreach (ILookupParameter<DoubleValue> param in op.Parameters.OfType<ILookupParameter<DoubleValue>>()) {
+            if (param.Name.Equals("Quality")) param.ActualName = qualityName;
+          }
+          foreach (IScopeTreeLookupParameter<DoubleValue> param in op.Parameters.OfType<IScopeTreeLookupParameter<DoubleValue>>()) {
+            if (param.Name.Equals("Quality")) param.ActualName = qualityName;
+          }
+        }
+      }
+    }
+    #endregion
+  }
+}
