Index: unk/sources/HeuristicLab.Optimization/3.3/Calculator.cs
===================================================================
--- /trunk/sources/HeuristicLab.Optimization/3.3/Calculator.cs	(revision 7227)
+++ 	(revision )
@@ -1,224 +1,0 @@
-﻿using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.Linq;
-using System.Text.RegularExpressions;
-using HeuristicLab.Common;
-using HeuristicLab.Core;
-using HeuristicLab.Data;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-
-namespace HeuristicLab.Optimization {
-
-  [StorableClass]
-  public class Calculator : IDeepCloneable {
-
-    #region Fields & Properties
-
-    private List<string> tokens;
-
-    [Storable]
-    public string Formula {
-      get { return string.Join(" ", tokens); }
-      set { tokens = Tokenize(value).ToList(); }
-    }
-
-    private static readonly Regex TokenRegex =
-      new Regex(@"""(\\""|[^""])*""|'(\\'|[^'])*'|[^\s]+");
-
-    #endregion
-
-    #region Construction & Cloning
-
-    [StorableConstructor]
-    protected Calculator(bool deserializing) { }
-    public Calculator() { }
-    protected Calculator(Calculator original, Cloner cloner) {
-      cloner.RegisterClonedObject(original, this);
-      if (original.tokens != null)
-        tokens = original.tokens.ToList();
-    }
-    public IDeepCloneable Clone(Cloner cloner) {
-      return new Calculator(this, cloner);
-    }
-    public object Clone() {
-      return Clone(new Cloner());
-    }
-    #endregion
-
-    private static IEnumerable<string> Tokenize(string s) {
-      return TokenRegex.Matches(s).Cast<Match>().Select(m => m.Value);
-    }
-
-    public IItem GetValue(IDictionary<string, IItem> variables) {
-      var stack = new Stack<object>();
-      int i = 0;
-      try {
-        for (; i<tokens.Count; i++) {
-          var token = tokens[i];
-          double d;
-          if (TryParse(token, out d)) {
-            stack.Push(d);
-          } else if (token.StartsWith("\"")) {
-            stack.Push(GetVariableValue(variables, token.Substring(1, token.Length - 2).Replace("\\\"", "\"")));
-          } else if (token.StartsWith("'")) {
-            stack.Push(token.Substring(1, token.Length-2).Replace("\\'", "'"));
-          } else {
-            Apply(token, stack, variables);
-          }
-        }
-      } catch (Exception x) {
-        throw new Exception(string.Format(
-          "Calculation of '{1}'{0}failed at token #{2}: '{3}' {0}current stack is: {0}{4}", Environment.NewLine,
-          Formula, i, tokens[i],
-          string.Join(Environment.NewLine, stack.Select(AsString))),
-          x);
-      }
-      if (stack.Count != 1)
-        throw new Exception(
-          string.Format("Invalid final evaluation stack size {0} (should be 1) in formula '{1}'",
-          stack.Count, Formula));
-      var result = stack.Pop();
-      if (result is string) return new StringValue((string)result);
-      if (result is double) return new DoubleValue((double)result);
-      if (result is bool) return new BoolValue((bool)result);
-      return null;
-    }
-
-    private static void Apply(string token, Stack<object> stack, IDictionary<string, IItem> variables) {
-      switch (token) {
-        case "null":  stack.Push(null); break;
-        case "true":  stack.Push(true); break;
-        case "false": stack.Push(false); break;
-
-        case "drop": stack.Pop(); break;
-        case "dup": stack.Push(stack.Peek()); break;
-        case "swap":
-          var top = stack.Pop();
-          var next = stack.Pop();
-          stack.Push(top);
-          stack.Push(next);
-          break;
-
-        case "log": Apply(stack, x => Math.Log((double)x)); break;
-        case "+": Apply(stack, (x, y) => (double)x + (double)y); break;
-        case "-": Apply(stack, (x, y) => (double)x - (double)y); break;
-        case "*": Apply(stack, (x, y) => (double)x * (double)y); break;
-        case "/": Apply(stack, (x, y) => (double)x / (double)y); break;
-        case "^": Apply(stack, (x, y) => Math.Pow((double)x, (double)y)); break;
-        case "<": Apply(stack, (x, y) => (double)x < (double)y); break;
-        case ">": Apply(stack, (x, y) => (double)x > (double)y); break;
-
-        case "==": Apply(stack, (x, y) => Equal(x, y)); break;
-        case "not": Apply(stack, x => !(bool)x); break;
-        case "isnull": Apply(stack, x => x == null); break;
-        case "if": Apply(stack, (then, else_, cond) => (bool)cond ? then : else_); break;
-
-        case "ismatch": Apply(stack, (s, p) => new Regex((string)p).IsMatch((string)s)); break;
-        case "rename": Apply(stack, (s, p, r) => new Regex((string)p).Replace((string)s, (string)r)); break;
-
-        default: stack.Push(GetVariableValue(variables, token)); break;
-      }
-    }
-
-    #region Auxiliary Functions
-
-    #region IItem value conversion
-    private static object GetIntValue(IItem value) {
-      var v = value as IntValue;
-      if (v != null) return (double)v.Value;
-      return null;
-    }
-
-    private static object GetDoubleValue(IItem value) {
-      var v = value as DoubleValue;
-      if (v != null) return v.Value;
-      return null;
-    }
-
-    private static object GetBoolValue(IItem value) {
-      var v = value as BoolValue;
-      if (v != null) return v.Value;
-      return null;
-    }
-
-    private static object GetVariableValue(IDictionary<string, IItem> variables, string name) {
-      if (variables.ContainsKey(name)) {
-        var item = variables[name];
-        return
-          GetIntValue(item) ??
-          GetDoubleValue(item) ??
-          GetBoolValue(item) ??
-          item.ToString();
-      }
-      return null;
-    }
-    #endregion
-
-    #region variadic equality
-    private static bool Equal(object a, object b) { return EqualNumber(a, b) || EqualBool(a, b) || EqualString(a, b) || a == b; }
-    private static bool EqualNumber(object a, object b) { return a is double && b is double && (double)a == (double)b; }
-    private static bool EqualBool(object a, object b) { return a is bool && b is bool && (bool)a == (bool)b; }
-    private static bool EqualString(object a, object b) { return a is string && b is string && ((string)a).Equals((string)b); }
-    #endregion
-
-    #region stack calculation
-    private static void Apply(Stack<object> stack, Func<object, object> func) {
-      if (stack.Count < 1)
-        throw new InvalidOperationException("Stack is empty");
-      var a = stack.Pop();
-      try {
-        stack.Push(func(a));
-      } catch (Exception) {
-        stack.Push(a);
-        throw;
-      }
-    }
-
-    private static void Apply(Stack<object> stack, Func<object, object, object> func) {
-      if (stack.Count < 2)
-        throw new InvalidOperationException("Stack contains less than two elements");
-      var b = stack.Pop();
-      var a = stack.Pop();
-      try {
-        stack.Push(func(a, b));
-      } catch (Exception) {
-        stack.Push(b);
-        stack.Push(a);
-        throw;
-      }
-    }
-
-    private static void Apply(Stack<object> stack, Func<object, object, object, object> func) {
-      if (stack.Count < 3)
-        throw new InvalidOperationException("Stack contains less than three elements");
-      var c = stack.Pop();
-      var b = stack.Pop();
-      var a = stack.Pop();
-      try {
-        stack.Push(func(a, b, c));
-      } catch (Exception) {
-        stack.Push(a);
-        stack.Push(b);
-        stack.Push(c);
-        throw;
-      }
-    }
-    #endregion
-
-    private static bool TryParse(string token, out double d) {
-      return double.TryParse(token,
-                             NumberStyles.AllowDecimalPoint |
-                             NumberStyles.AllowExponent |
-                             NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture, out d);
-    }
-
-    private static string AsString(object o) {
-      if (o == null) return "null";
-      if (o is string) return string.Format("'{0}'", o);
-      return o.ToString();
-    }
-
-    #endregion
-  }
-}
Index: /trunk/sources/HeuristicLab.Optimization/3.3/HeuristicLab.Optimization-3.3.csproj
===================================================================
--- /trunk/sources/HeuristicLab.Optimization/3.3/HeuristicLab.Optimization-3.3.csproj	(revision 7227)
+++ /trunk/sources/HeuristicLab.Optimization/3.3/HeuristicLab.Optimization-3.3.csproj	(revision 7228)
@@ -114,15 +114,15 @@
   </ItemGroup>
   <ItemGroup>
-    <Compile Include="RunCollectionRunRemover.cs" />
+    <Compile Include="RunCollectionModification\RunCollectionRunRemover.cs" />
     <Compile Include="Plugin.cs" />
-    <Compile Include="RunCollectionDiscretizer.cs" />
-    <Compile Include="RunCollectionGroupCreater.cs" />
-    <Compile Include="RunCollectionSorter.cs" />
-    <Compile Include="RunCollectionValueRemover.cs" />
-    <Compile Include="IRunCollectionModifier.cs" />
+    <Compile Include="RunCollectionModification\RunCollectionDiscretizer.cs" />
+    <Compile Include="RunCollectionModification\RunCollectionGroupCreater.cs" />
+    <Compile Include="RunCollectionModification\RunCollectionSorter.cs" />
+    <Compile Include="RunCollectionModification\RunCollectionValueRemover.cs" />
+    <Compile Include="Interfaces\IRunCollectionModifier.cs" />
     <None Include="Plugin.cs.frame" />
     <Compile Include="Algorithms\Algorithm.cs" />
     <Compile Include="BatchRun.cs" />
-    <Compile Include="Calculator.cs" />
+    <Compile Include="RunCollectionModification\Calculator.cs" />
     <Compile Include="Interfaces\IDiscreteDoubleMatrixModifier.cs" />
     <Compile Include="Algorithms\HeuristicOptimizationEngineAlgorithm.cs" />
@@ -147,5 +147,5 @@
     <Compile Include="Interfaces\ISingleObjectiveHeuristicOptimizationProblem.cs" />
     <Compile Include="Problems\Problem.cs" />
-    <Compile Include="RunCollectionFormulaModifer.cs" />
+    <Compile Include="RunCollectionModification\RunCollectionFormulaModifer.cs" />
     <Compile Include="RunCollectionConstraints\RunCollectionComparisonConstraint.cs" />
     <Compile Include="RunCollectionConstraints\RunCollectionConstraintCollection.cs" />
Index: unk/sources/HeuristicLab.Optimization/3.3/IRunCollectionModifier.cs
===================================================================
--- /trunk/sources/HeuristicLab.Optimization/3.3/IRunCollectionModifier.cs	(revision 7227)
+++ 	(revision )
@@ -1,11 +1,0 @@
-﻿using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using HeuristicLab.Core;
-
-namespace HeuristicLab.Optimization {
-  public interface IRunCollectionModifier : IItem {    
-    void Modify(List<IRun> runs);
-  }
-}
Index: /trunk/sources/HeuristicLab.Optimization/3.3/Interfaces/IRunCollectionModifier.cs
===================================================================
--- /trunk/sources/HeuristicLab.Optimization/3.3/Interfaces/IRunCollectionModifier.cs	(revision 7228)
+++ /trunk/sources/HeuristicLab.Optimization/3.3/Interfaces/IRunCollectionModifier.cs	(revision 7228)
@@ -0,0 +1,11 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using HeuristicLab.Core;
+
+namespace HeuristicLab.Optimization {
+  public interface IRunCollectionModifier : IItem {    
+    void Modify(List<IRun> runs);
+  }
+}
Index: unk/sources/HeuristicLab.Optimization/3.3/RunCollectionDiscretizer.cs
===================================================================
--- /trunk/sources/HeuristicLab.Optimization/3.3/RunCollectionDiscretizer.cs	(revision 7227)
+++ 	(revision )
@@ -1,175 +1,0 @@
-﻿using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using HeuristicLab.Common;
-using HeuristicLab.Core;
-using HeuristicLab.Data;
-using HeuristicLab.Parameters;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-
-namespace HeuristicLab.Optimization {
-  [Item("RunCollection Discretizer",
-    "Creates several levels from the distribution of a certain result accross a run collection and " +
-    "assigns a discretized value. Non-existing numbers as well as NaN and infinities are excluded from the caluclation.")]
-  [StorableClass]
-  public class RunCollectionDiscretizer : ParameterizedNamedItem, IRunCollectionModifier {
-
-    public override bool CanChangeName { get { return false; } }
-    public override bool CanChangeDescription { get { return false; } }
-
-    #region Parameters
-    public ValueParameter<StringValue> SourceParameter {
-      get { return (ValueParameter<StringValue>)Parameters["Source"]; }
-    }
-    public ValueParameter<StringValue> TargetParameter {
-      get { return (ValueParameter<StringValue>)Parameters["Target"]; }
-    }
-    public ValueParameter<DoubleValue> SpreadParameter {
-      get { return (ValueParameter<DoubleValue>)Parameters["Spread"]; }
-    }
-    public ValueParameter<StringValue> GroupByParameter {
-      get { return (ValueParameter<StringValue>)Parameters["GroupBy"]; }
-    }    
-    public ValueParameter<ItemList<StringValue>> LevelsParameter {
-      get { return (ValueParameter<ItemList<StringValue>>)Parameters["Levels"]; }
-    }    
-    #endregion
-
-    private string Source { get { return SourceParameter.Value.Value; } }
-    private string Target { get { return TargetParameter.Value.Value; } }    
-    private double Spread { get { return SpreadParameter.Value.Value; } }
-    private string GroupBy { get { return GroupByParameter.Value.Value; } }
-    private List<string> Levels { get { return LevelsParameter.Value.Select(v => v.Value).ToList(); } }
-
-      #region Construction & Cloning
-    [StorableConstructor]
-    protected RunCollectionDiscretizer(bool deserializing) : base(deserializing) { }
-    protected RunCollectionDiscretizer(RunCollectionDiscretizer original, Cloner cloner)
-      : base(original, cloner) {
-      RegisterEvents();
-    }
-    public RunCollectionDiscretizer() {
-      Parameters.Add(new ValueParameter<StringValue>("Source", "Source value name to be fuzzified.", new StringValue("Value")));
-      Parameters.Add(new ValueParameter<StringValue>("Target", "Target value name. The new, fuzzified variable to be created.", new StringValue("Calc.Value")));
-      Parameters.Add(new ValueParameter<DoubleValue>("Spread", "The number of standard deviations considered one additional level. Set to zero to use empirical distribution instead.", new DoubleValue(1)));
-      Parameters.Add(new ValueParameter<StringValue>("GroupBy", "Create separate analyzes for different values of this variable.", new StringValue("")));
-      Parameters.Add(new ValueParameter<ItemList<StringValue>>("Levels", "The list of levels to be assigned.",
-        new ItemList<StringValue> {
-          new StringValue("Very Low"),
-          new StringValue("Low"),
-          new StringValue("Average"),
-          new StringValue("High"),
-          new StringValue("Very High"),
-        }));     
-      RegisterEvents();
-      UpdateName();
-    }
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new RunCollectionDiscretizer(this, cloner);
-    }
-    [StorableHook(HookType.AfterDeserialization)]
-    private void AfterDeserialization() {
-      RegisterEvents();
-    }
-    #endregion
-
-    private void RegisterEvents() {
-      SourceParameter.ToStringChanged += Parameter_NameChanged;
-      TargetParameter.ToStringChanged += Parameter_NameChanged;      
-      GroupByParameter.ToStringChanged += Parameter_NameChanged;
-    }
-
-    private void Parameter_NameChanged(object sender, EventArgs e) {
-      UpdateName();
-    }
-
-    private void UpdateName() {
-      name = string.Format("{0} := Discrete({1}{2})",
-        Target,
-        Source,
-        string.IsNullOrWhiteSpace(GroupBy) ? "" : string.Format("/{0}", GroupBy));        
-      OnNameChanged();
-    }
-
-    #region IRunCollectionModifier Members
-
-    public void Modify(List<IRun> runs) {
-      foreach (var group in runs
-        .Select(r => new {Run=r, Value=GetSourceValue(r)})
-        .Where(r => r.Value.HasValue && !double.IsNaN(r.Value.Value) && !double.IsInfinity(r.Value.Value))
-        .Select(r => new {r.Run, r.Value.Value, Bin=GetGroupByValue(r.Run)})
-        .GroupBy(r => r.Bin).ToList()) {
-        var values = group.Select(r => r.Value).ToList();
-        if (values.Count > 0) {
-          if (Spread > 0) {
-            var avg = values.Average();
-            var stdDev = values.StandardDeviation();
-            foreach (var r in group) {
-              r.Run.Results[Target] = new StringValue(Discretize(r.Value, avg, stdDev));
-            }
-          } else {
-            values.Sort();
-            var a = values.ToArray();
-            foreach (var r in group) {
-              r.Run.Results[Target] = new StringValue(Discretize(r.Value, a));
-            }
-          }
-        }
-      }      
-    }
-
-    private double? GetSourceValue(IRun run) {
-      return CastSourceValue(run.Results) ?? CastSourceValue(run.Parameters);
-    }
-
-    private string GetGroupByValue(IRun run) {
-      if (string.IsNullOrWhiteSpace(GroupBy))
-        return String.Empty;
-      IItem value;
-      run.Results.TryGetValue(GroupBy, out value);
-      if (value == null)
-        run.Parameters.TryGetValue(GroupBy, out value);
-      if (value != null)
-        return value.ToString();
-      else
-        return String.Empty;
-    }
-
-    private double? CastSourceValue(IDictionary<string, IItem> variables) {
-      IItem value;
-      variables.TryGetValue(Source, out value);
-      var intValue = value as IntValue;
-      if (intValue != null) 
-        return intValue.Value;
-      var doubleValue = value as DoubleValue;
-      if (doubleValue != null)
-        return doubleValue.Value;
-      return null;
-    }
-
-    private string Discretize(double value, double avg, double stdDev) {
-      double dev = (value - avg)/(stdDev*Spread);
-      int index;
-      if (Levels.Count % 2 == 1) {
-        index = (int) Math.Floor(Math.Abs(dev));
-        index = (Levels.Count - 1)/2 + Math.Sign(dev) * index;
-      } else {
-        index = (int) Math.Ceiling(Math.Abs(dev));
-        if (dev > 0)
-          index = Levels.Count/2 + index;
-        else
-          index = Levels.Count/2 + 1 - index;
-      }
-      return Levels[Math.Min(Levels.Count - 1, Math.Max(0, index))];
-    }
-
-    private string Discretize(double value, double[] values) {
-      var index = Array.BinarySearch(values, value);
-      var pos = 1.0*(index < 0 ? ~index : index)/(values.Length-1);
-      return Levels[Math.Min(Levels.Count - 1, Math.Max(0, (int) Math.Round(pos*(Levels.Count-1))))];
-    }
-
-    #endregion
-  }
-}
Index: unk/sources/HeuristicLab.Optimization/3.3/RunCollectionFormulaModifer.cs
===================================================================
--- /trunk/sources/HeuristicLab.Optimization/3.3/RunCollectionFormulaModifer.cs	(revision 7227)
+++ 	(revision )
@@ -1,107 +1,0 @@
-﻿using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using HeuristicLab.Common;
-using HeuristicLab.Core;
-using HeuristicLab.Data;
-using HeuristicLab.Parameters;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-
-namespace HeuristicLab.Optimization {
-
-  [Item("RunCollection Formula Modifier", "Modifies a RunCollection by adding results using the given formula.")]
-  [StorableClass]
-  public class RunCollectionFormulaModifer : ParameterizedNamedItem, IRunCollectionModifier {
-
-    public override bool CanChangeName { get { return false; } }
-    public override bool CanChangeDescription { get { return false; } }
-
-    public ValueParameter<StringValue> ResultNameParameter {
-      get { return (ValueParameter<StringValue>)Parameters["ResultName"]; }
-    }
-
-    public ValueParameter<StringValue> FormulaParameter {
-      get { return (ValueParameter<StringValue>)Parameters["Formula"]; }
-    }
-
-    private string ResultName { get { return ResultNameParameter.Value.Value; } }
-    private string Formula { get { return FormulaParameter.Value.Value; } }
-
-    #region Construction & Cloning
-    [StorableConstructor]
-    protected RunCollectionFormulaModifer(bool deserializing) : base(deserializing) { }
-    protected RunCollectionFormulaModifer(RunCollectionFormulaModifer original, Cloner cloner)
-      : base(original, cloner) {
-      RegisterEvents();
-    }
-    public RunCollectionFormulaModifer() {
-      Parameters.Add(new ValueParameter<StringValue>("ResultName", "The name of the result to be generated by this formula.", new StringValue("Calc.Value")));
-      Parameters.Add(new ValueParameter<StringValue>("Formula",
-@"RPN formula for new value in postfix notation.
-
-This can contain the following elements:
-
-literals:
-  numbers, true, false, null and strings in single quotes
-variables (run parameters or results):
-  unquoted or in double quotes if they contain special characters or whitespace
-mathematical functions:
-  +, -, /, ^ (power), log
-predicates:
-  ==, <, >, isnull, not
-stack manipulation:
-  drop swap dup
-string matching:
-  <string> <pattern> ismatch
-string replacing:
-  <string> <pattern> <replacement> rename
-conditionals:
-  <then> <else> <condition> if
-
-If the final value is null, the result variable is removed if it exists.",
-        new StringValue("1 1 +")));
-      UpdateName();
-      RegisterEvents();
-    }
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new RunCollectionFormulaModifer(this, cloner);
-    }
-    [StorableHook(HookType.AfterDeserialization)]
-    private void AfterDeserialization() {
-      RegisterEvents();
-    }
-    #endregion
-
-    private void RegisterEvents() {
-      ResultNameParameter.ToStringChanged += Parameter_NameChanged;
-      FormulaParameter.ToStringChanged += Parameter_NameChanged;
-    }
-
-    void Parameter_NameChanged(object sender, EventArgs e) {
-      UpdateName();
-    }
-
-    private void UpdateName() {
-      name = string.Format("{0} := {1}", ResultName, Formula);
-      OnNameChanged();
-    }
-
-    public void Modify(List<IRun> runs) {
-      var calc = new Calculator { Formula = Formula };
-      foreach (var run in runs) {
-        var variables = new Dictionary<string, IItem>();
-        foreach (var param in run.Parameters)
-          variables[param.Key] = param.Value;
-        foreach (var result in run.Results)
-          variables[result.Key] = result.Value;
-        var value = calc.GetValue(variables);
-        if (value != null)
-          run.Results[ResultName] = value;
-        else
-          run.Results.Remove(ResultName);
-      }
-    }
-
-  }
-}
Index: unk/sources/HeuristicLab.Optimization/3.3/RunCollectionGroupCreater.cs
===================================================================
--- /trunk/sources/HeuristicLab.Optimization/3.3/RunCollectionGroupCreater.cs	(revision 7227)
+++ 	(revision )
@@ -1,84 +1,0 @@
-﻿using System;
-using System.Collections.Generic;
-using System.Linq;
-using HeuristicLab.Common;
-using HeuristicLab.Core;
-using HeuristicLab.Data;
-using HeuristicLab.Parameters;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-
-namespace HeuristicLab.Optimization {
-
-  [Item("RunCollection Group Creater", "Regroups existing runs according to equal values in GroupBy and prefixes them according to their value in Prefix.")]
-  [StorableClass]
-  public class RunCollectionGroupCreater : ParameterizedNamedItem, IRunCollectionModifier {
-    
-    public ValueParameter<ItemCollection<StringValue>> GroupByParameter {
-      get { return (ValueParameter<ItemCollection<StringValue>>)Parameters["GroupBy"]; }
-    }
-
-    public ValueParameter<StringValue> PrefixParameter {
-      get { return (ValueParameter<StringValue>)Parameters["Prefix"]; }
-    }
-
-    private IEnumerable<string> GroupBy { get { return GroupByParameter.Value.Select(v => v.Value); } }
-    private string Prefix { get { return PrefixParameter.Value.Value; } }
-
-    #region Construction & Cloning
-    [StorableConstructor]
-    protected RunCollectionGroupCreater(bool deserializing) : base(deserializing) { }
-    protected RunCollectionGroupCreater(RunCollectionGroupCreater original, Cloner cloner) : base(original, cloner) { }
-    public RunCollectionGroupCreater() {
-      Parameters.Add(new ValueParameter<ItemCollection<StringValue>>("GroupBy", "The variable that has to be the same for all members of a group.",
-        new ItemCollection<StringValue>(new[] { new StringValue("Problem Name") })));
-      Parameters.Add(new ValueParameter<StringValue>("Prefix", "The distinguishing prefix values for the individual runs.",
-        new StringValue("Algorithm Name")));      
-    }
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new RunCollectionGroupCreater(this, cloner);
-    }
-    #endregion    
-
-    private static string GetStringValue(string name, IRun r) {
-      IItem item;
-      r.Results.TryGetValue(name, out item);
-      if (item != null)
-        return item.ToString();
-      r.Parameters.TryGetValue(name, out item);
-      return item != null ? item.ToString() : "<none>";
-    }
-
-    private static string GetValues(IEnumerable<string> names, IRun r) {
-      return string.Join("/", names.Select(n => GetStringValue(n, r)));
-    }
-
-    public void Modify(List<IRun> runs) {
-      var groups = runs.GroupBy(r => GetValues(GroupBy, r).ToString()).ToList();
-      runs.Clear();
-      foreach (var group in groups) {
-        var run = new Run { Name = string.Format(group.Key) };
-        foreach (var r in group) {
-          var prefix = GetStringValue(Prefix, r);
-          foreach (var result in r.Results) {
-            InsertNew(run.Results, prefix, result.Key, result.Value);
-          }
-          foreach (var parameter in r.Parameters) {
-            InsertNew(run.Parameters, prefix, parameter.Key, parameter.Value);
-          }
-        }
-        runs.Add(run);
-      }
-    }
-
-    private static void InsertNew(IDictionary<string, IItem> dict, string prefix, string key, IItem value) {
-      if (prefix == null)
-        prefix = "<null>";
-      var n = 0;
-      var name = string.Format("{0}.{1}", prefix, key);
-      while (dict.ContainsKey(name)) {
-        name = string.Format("{0}_{1}.{2}", prefix, ++n, key);
-      }
-      dict.Add(name, value);      
-    }
-  }
-}
Index: /trunk/sources/HeuristicLab.Optimization/3.3/RunCollectionModification/Calculator.cs
===================================================================
--- /trunk/sources/HeuristicLab.Optimization/3.3/RunCollectionModification/Calculator.cs	(revision 7228)
+++ /trunk/sources/HeuristicLab.Optimization/3.3/RunCollectionModification/Calculator.cs	(revision 7228)
@@ -0,0 +1,240 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text.RegularExpressions;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using System.Text;
+
+namespace HeuristicLab.Optimization {
+
+  [StorableClass]
+  public class Calculator : IDeepCloneable {
+
+    #region Fields & Properties
+
+    private List<string> tokens;
+
+    [Storable]
+    public string Formula {
+      get { return string.Join(" ", tokens); }
+      set { tokens = Tokenize(value).ToList(); }
+    }
+
+    private static readonly Regex TokenRegex =
+      new Regex(@"""(\\""|[^""])*""|'(\\'|[^'])*'|[^\s]+");
+
+    #endregion
+
+    #region Construction & Cloning
+
+    [StorableConstructor]
+    protected Calculator(bool deserializing) { }
+    public Calculator() { }
+    protected Calculator(Calculator original, Cloner cloner) {
+      cloner.RegisterClonedObject(original, this);
+      if (original.tokens != null)
+        tokens = original.tokens.ToList();
+    }
+    public IDeepCloneable Clone(Cloner cloner) {
+      return new Calculator(this, cloner);
+    }
+    public object Clone() {
+      return Clone(new Cloner());
+    }
+    #endregion
+
+    private static IEnumerable<string> Tokenize(string s) {
+      return TokenRegex.Matches(s).Cast<Match>().Select(m => m.Value);
+    }
+
+    public IItem GetValue(IDictionary<string, IItem> variables) {
+      var stack = new Stack<object>();
+      int i = 0;
+      try {
+        for (; i<tokens.Count; i++) {
+          var token = tokens[i];
+          double d;
+          if (TryParse(token, out d)) {
+            stack.Push(d);
+          } else if (token.StartsWith("\"")) {
+            stack.Push(GetVariableValue(variables, token.Substring(1, token.Length - 2).Replace("\\\"", "\"")));
+          } else if (token.StartsWith("'")) {
+            stack.Push(token.Substring(1, token.Length-2).Replace("\\'", "'"));
+          } else {
+            Apply(token, stack, variables);
+          }
+        }
+      } catch (Exception x) {
+        throw new Exception(string.Format(
+          "Calculation of '{1}'{0}failed at token #{2}: {3} {0}current stack is: {0}{4}", Environment.NewLine,
+          Formula, i, TokenWithContext(tokens, i, 3), 
+          string.Join(Environment.NewLine, stack.Select(AsString))),
+          x);
+      }
+      if (stack.Count != 1)
+        throw new Exception(
+          string.Format("Invalid final evaluation stack size {0} (should be 1) in formula '{1}'",
+          stack.Count, Formula));
+      var result = stack.Pop();
+      if (result is string) return new StringValue((string)result);
+      if (result is double) return new DoubleValue((double)result);
+      if (result is bool) return new BoolValue((bool)result);
+      return null;
+    }
+
+    private string TokenWithContext(List<string> tokens, int i, int context) {
+      var sb = new StringBuilder();
+      if (i > context+1)
+        sb.Append("... ");
+      int prefix = Math.Max(0, i - context);
+      sb.Append(string.Join(" ", tokens.GetRange(prefix, i - prefix)));
+      sb.Append("   ---> ").Append(tokens[i]).Append(" <---   ");
+      int postfix = Math.Min(tokens.Count, i + 1 + context);
+      sb.Append(string.Join(" ", tokens.GetRange(i + 1, postfix - (i + 1))));
+      if (postfix < tokens.Count)
+        sb.Append(" ...");
+      return sb.ToString();
+    }
+
+
+    private static void Apply(string token, Stack<object> stack, IDictionary<string, IItem> variables) {
+      switch (token) {
+        case "null":  stack.Push(null); break;
+        case "true":  stack.Push(true); break;
+        case "false": stack.Push(false); break;
+
+        case "drop": stack.Pop(); break;
+        case "dup": stack.Push(stack.Peek()); break;
+        case "swap":
+          var top = stack.Pop();
+          var next = stack.Pop();
+          stack.Push(top);
+          stack.Push(next);
+          break;
+
+        case "log": Apply(stack, x => Math.Log((double)x)); break;
+        case "+": Apply(stack, (x, y) => (double)x + (double)y); break;
+        case "-": Apply(stack, (x, y) => (double)x - (double)y); break;
+        case "*": Apply(stack, (x, y) => (double)x * (double)y); break;
+        case "/": Apply(stack, (x, y) => (double)x / (double)y); break;
+        case "^": Apply(stack, (x, y) => Math.Pow((double)x, (double)y)); break;
+        case "<": Apply(stack, (x, y) => (double)x < (double)y); break;
+        case ">": Apply(stack, (x, y) => (double)x > (double)y); break;
+
+        case "==": Apply(stack, (x, y) => Equal(x, y)); break;
+        case "not": Apply(stack, x => !(bool)x); break;
+        case "isnull": Apply(stack, x => x == null); break;
+        case "if": Apply(stack, (then, else_, cond) => (bool)cond ? then : else_); break;
+
+        case "ismatch": Apply(stack, (s, p) => new Regex((string)p).IsMatch((string)s)); break;
+        case "rename": Apply(stack, (s, p, r) => new Regex((string)p).Replace((string)s, (string)r)); break;
+
+        default: stack.Push(GetVariableValue(variables, token)); break;
+      }
+    }
+
+    #region Auxiliary Functions
+
+    #region IItem value conversion
+    private static object GetIntValue(IItem value) {
+      var v = value as IntValue;
+      if (v != null) return (double)v.Value;
+      return null;
+    }
+
+    private static object GetDoubleValue(IItem value) {
+      var v = value as DoubleValue;
+      if (v != null) return v.Value;
+      return null;
+    }
+
+    private static object GetBoolValue(IItem value) {
+      var v = value as BoolValue;
+      if (v != null) return v.Value;
+      return null;
+    }
+
+    private static object GetVariableValue(IDictionary<string, IItem> variables, string name) {
+      if (variables.ContainsKey(name)) {
+        var item = variables[name];
+        return
+          GetIntValue(item) ??
+          GetDoubleValue(item) ??
+          GetBoolValue(item) ??
+          item.ToString();
+      }
+      return null;
+    }
+    #endregion
+
+    #region variadic equality
+    private static bool Equal(object a, object b) { return EqualNumber(a, b) || EqualBool(a, b) || EqualString(a, b) || a == b; }
+    private static bool EqualNumber(object a, object b) { return a is double && b is double && (double)a == (double)b; }
+    private static bool EqualBool(object a, object b) { return a is bool && b is bool && (bool)a == (bool)b; }
+    private static bool EqualString(object a, object b) { return a is string && b is string && ((string)a).Equals((string)b); }
+    #endregion
+
+    #region stack calculation
+    private static void Apply(Stack<object> stack, Func<object, object> func) {
+      if (stack.Count < 1)
+        throw new InvalidOperationException("Stack is empty");
+      var a = stack.Pop();
+      try {
+        stack.Push(func(a));
+      } catch (Exception) {
+        stack.Push(a);
+        throw;
+      }
+    }
+
+    private static void Apply(Stack<object> stack, Func<object, object, object> func) {
+      if (stack.Count < 2)
+        throw new InvalidOperationException("Stack contains less than two elements");
+      var b = stack.Pop();
+      var a = stack.Pop();
+      try {
+        stack.Push(func(a, b));
+      } catch (Exception) {
+        stack.Push(b);
+        stack.Push(a);
+        throw;
+      }
+    }
+
+    private static void Apply(Stack<object> stack, Func<object, object, object, object> func) {
+      if (stack.Count < 3)
+        throw new InvalidOperationException("Stack contains less than three elements");
+      var c = stack.Pop();
+      var b = stack.Pop();
+      var a = stack.Pop();
+      try {
+        stack.Push(func(a, b, c));
+      } catch (Exception) {
+        stack.Push(a);
+        stack.Push(b);
+        stack.Push(c);
+        throw;
+      }
+    }
+    #endregion
+
+    private static bool TryParse(string token, out double d) {
+      return double.TryParse(token,
+                             NumberStyles.AllowDecimalPoint |
+                             NumberStyles.AllowExponent |
+                             NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture, out d);
+    }
+
+    private static string AsString(object o) {
+      if (o == null) return "null";
+      if (o is string) return string.Format("'{0}'", o);
+      return o.ToString();
+    }
+
+    #endregion
+  }
+}
Index: /trunk/sources/HeuristicLab.Optimization/3.3/RunCollectionModification/RunCollectionDiscretizer.cs
===================================================================
--- /trunk/sources/HeuristicLab.Optimization/3.3/RunCollectionModification/RunCollectionDiscretizer.cs	(revision 7228)
+++ /trunk/sources/HeuristicLab.Optimization/3.3/RunCollectionModification/RunCollectionDiscretizer.cs	(revision 7228)
@@ -0,0 +1,182 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Optimization {
+  [Item("RunCollection Discretizer",
+    "Creates several levels from the distribution of a certain result accross a run collection and " +
+    "assigns a discretized value. Non-existing numbers as well as NaN and infinities are excluded from the caluclation.")]
+  [StorableClass]
+  public class RunCollectionDiscretizer : ParameterizedNamedItem, IRunCollectionModifier {
+
+    public override bool CanChangeName { get { return false; } }
+    public override bool CanChangeDescription { get { return false; } }
+
+    #region Parameters
+    public ValueParameter<StringValue> SourceParameter {
+      get { return (ValueParameter<StringValue>)Parameters["Source"]; }
+    }
+    public ValueParameter<StringValue> TargetParameter {
+      get { return (ValueParameter<StringValue>)Parameters["Target"]; }
+    }
+    public ValueParameter<DoubleValue> SpreadParameter {
+      get { return (ValueParameter<DoubleValue>)Parameters["Spread"]; }
+    }
+    public ValueParameter<StringValue> GroupByParameter {
+      get { return (ValueParameter<StringValue>)Parameters["GroupBy"]; }
+    }    
+    public ValueParameter<ItemList<StringValue>> LevelsParameter {
+      get { return (ValueParameter<ItemList<StringValue>>)Parameters["Levels"]; }
+    }    
+    #endregion
+
+    private string Source { get { return SourceParameter.Value.Value; } }
+    private string Target {
+      get { return TargetParameter.Value.Value; }
+      set { TargetParameter.Value.Value = value; }
+    }    
+    private double Spread { get { return SpreadParameter.Value.Value; } }
+    private string GroupBy { get { return GroupByParameter.Value.Value; } }
+    private List<string> Levels { get { return LevelsParameter.Value.Select(v => v.Value).ToList(); } }
+
+      #region Construction & Cloning
+    [StorableConstructor]
+    protected RunCollectionDiscretizer(bool deserializing) : base(deserializing) { }
+    protected RunCollectionDiscretizer(RunCollectionDiscretizer original, Cloner cloner)
+      : base(original, cloner) {
+      RegisterEvents();
+    }
+    public RunCollectionDiscretizer() {
+      Parameters.Add(new ValueParameter<StringValue>("Source", "Source value name to be fuzzified.", new StringValue("Value")));
+      Parameters.Add(new ValueParameter<StringValue>("Target", "Target value name. The new, fuzzified variable to be created.", new StringValue("Calc.Value")));
+      Parameters.Add(new ValueParameter<DoubleValue>("Spread", "The number of standard deviations considered one additional level. Set to zero to use empirical distribution instead.", new DoubleValue(1)));
+      Parameters.Add(new ValueParameter<StringValue>("GroupBy", "Create separate analyzes for different values of this variable.", new StringValue("")));
+      Parameters.Add(new ValueParameter<ItemList<StringValue>>("Levels", "The list of levels to be assigned.",
+        new ItemList<StringValue> {
+          new StringValue("Very Low"),
+          new StringValue("Low"),
+          new StringValue("Average"),
+          new StringValue("High"),
+          new StringValue("Very High"),
+        }));     
+      RegisterEvents();
+      UpdateName();
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new RunCollectionDiscretizer(this, cloner);
+    }
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      RegisterEvents();
+    }
+    #endregion
+
+    private void RegisterEvents() {
+      SourceParameter.ToStringChanged += SourceParameter_NameChanged;
+      TargetParameter.ToStringChanged += Parameter_NameChanged;
+      GroupByParameter.ToStringChanged += Parameter_NameChanged;
+    }
+
+    private void SourceParameter_NameChanged(object sender, EventArgs e) {
+      Target = string.Format("{0}/Level", Source);
+    }
+
+    private void Parameter_NameChanged(object sender, EventArgs e) {
+      UpdateName();
+    }
+
+    private void UpdateName() {
+      name = string.Format("{0} := Discrete({1}{2})",
+        Target,
+        Source,
+        string.IsNullOrWhiteSpace(GroupBy) ? "" : string.Format("/{0}", GroupBy));        
+      OnNameChanged();
+    }
+
+    #region IRunCollectionModifier Members
+
+    public void Modify(List<IRun> runs) {
+      foreach (var group in runs
+        .Select(r => new {Run=r, Value=GetSourceValue(r)})
+        .Where(r => r.Value.HasValue && !double.IsNaN(r.Value.Value) && !double.IsInfinity(r.Value.Value))
+        .Select(r => new {r.Run, r.Value.Value, Bin=GetGroupByValue(r.Run)})
+        .GroupBy(r => r.Bin).ToList()) {
+        var values = group.Select(r => r.Value).ToList();
+        if (values.Count > 0) {
+          if (Spread > 0) {
+            var avg = values.Average();
+            var stdDev = values.StandardDeviation();
+            foreach (var r in group) {
+              r.Run.Results[Target] = new StringValue(Discretize(r.Value, avg, stdDev));
+            }
+          } else {
+            values.Sort();
+            var a = values.ToArray();
+            foreach (var r in group) {
+              r.Run.Results[Target] = new StringValue(Discretize(r.Value, a));
+            }
+          }
+        }
+      }      
+    }
+
+    private double? GetSourceValue(IRun run) {
+      return CastSourceValue(run.Results) ?? CastSourceValue(run.Parameters);
+    }
+
+    private string GetGroupByValue(IRun run) {
+      if (string.IsNullOrWhiteSpace(GroupBy))
+        return String.Empty;
+      IItem value;
+      run.Results.TryGetValue(GroupBy, out value);
+      if (value == null)
+        run.Parameters.TryGetValue(GroupBy, out value);
+      if (value != null)
+        return value.ToString();
+      else
+        return String.Empty;
+    }
+
+    private double? CastSourceValue(IDictionary<string, IItem> variables) {
+      IItem value;
+      variables.TryGetValue(Source, out value);
+      var intValue = value as IntValue;
+      if (intValue != null) 
+        return intValue.Value;
+      var doubleValue = value as DoubleValue;
+      if (doubleValue != null)
+        return doubleValue.Value;
+      return null;
+    }
+
+    private string Discretize(double value, double avg, double stdDev) {
+      double dev = (value - avg)/(stdDev*Spread);
+      int index;
+      if (Levels.Count % 2 == 1) {
+        index = (int) Math.Floor(Math.Abs(dev));
+        index = (Levels.Count - 1)/2 + Math.Sign(dev) * index;
+      } else {
+        index = (int) Math.Ceiling(Math.Abs(dev));
+        if (dev > 0)
+          index = Levels.Count/2 + index;
+        else
+          index = Levels.Count/2 + 1 - index;
+      }
+      return Levels[Math.Min(Levels.Count - 1, Math.Max(0, index))];
+    }
+
+    private string Discretize(double value, double[] values) {
+      var index = Array.BinarySearch(values, value);
+      var pos = 1.0*(index < 0 ? ~index : index)/(values.Length-1);
+      return Levels[Math.Min(Levels.Count - 1, Math.Max(0, (int) Math.Round(pos*(Levels.Count-1))))];
+    }
+
+    #endregion
+  }
+}
Index: /trunk/sources/HeuristicLab.Optimization/3.3/RunCollectionModification/RunCollectionFormulaModifer.cs
===================================================================
--- /trunk/sources/HeuristicLab.Optimization/3.3/RunCollectionModification/RunCollectionFormulaModifer.cs	(revision 7228)
+++ /trunk/sources/HeuristicLab.Optimization/3.3/RunCollectionModification/RunCollectionFormulaModifer.cs	(revision 7228)
@@ -0,0 +1,111 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Optimization {
+
+  [Item("RunCollection Formula Modifier", "Modifies a RunCollection by adding results using the given formula.")]
+  [StorableClass]
+  public class RunCollectionFormulaModifer : ParameterizedNamedItem, IRunCollectionModifier {
+
+    public override bool CanChangeName { get { return false; } }
+    public override bool CanChangeDescription { get { return false; } }
+
+    public ValueParameter<StringValue> ResultNameParameter {
+      get { return (ValueParameter<StringValue>)Parameters["ResultName"]; }
+    }
+
+    public ValueParameter<StringValue> FormulaParameter {
+      get { return (ValueParameter<StringValue>)Parameters["Formula"]; }
+    }
+
+    private string ResultName { get { return ResultNameParameter.Value.Value; } }
+    private string Formula { get { return FormulaParameter.Value.Value; } }
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    protected RunCollectionFormulaModifer(bool deserializing) : base(deserializing) { }
+    protected RunCollectionFormulaModifer(RunCollectionFormulaModifer original, Cloner cloner)
+      : base(original, cloner) {
+      RegisterEvents();
+    }
+    public RunCollectionFormulaModifer() {
+      Parameters.Add(new ValueParameter<StringValue>("ResultName", "The name of the result to be generated by this formula.", new StringValue("Calc.Value")));
+      Parameters.Add(new ValueParameter<StringValue>("Formula",
+@"RPN formula for new value in postfix notation.
+
+This can contain the following elements:
+
+literals:
+  numbers, true, false, null and strings in single quotes
+variables (run parameters or results):
+  unquoted or in double quotes if they contain special characters or whitespace
+mathematical functions:
+  +, -, /, ^ (power), log
+predicates:
+  ==, <, >, isnull, not
+stack manipulation:
+  drop swap dup
+string matching:
+  <string> <pattern> ismatch
+string replacing:
+  <string> <pattern> <replacement> rename
+conditionals:
+  <then> <else> <condition> if
+
+If the final value is null, the result variable is removed if it exists.",
+        new StringValue("1 1 +")));
+      UpdateName();
+      RegisterEvents();
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new RunCollectionFormulaModifer(this, cloner);
+    }
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      RegisterEvents();
+    }
+    #endregion
+
+    private void RegisterEvents() {
+      ResultNameParameter.ToStringChanged += Parameter_NameChanged;
+      FormulaParameter.ToStringChanged += Parameter_NameChanged;
+    }
+
+    void Parameter_NameChanged(object sender, EventArgs e) {
+      UpdateName();
+    }
+
+    private void UpdateName() {
+      name = string.Format("{0} := {1}", ResultName, Formula);
+      OnNameChanged();
+    }
+
+    public void Modify(List<IRun> runs) {
+      var calc = new Calculator { Formula = Formula };
+      foreach (var run in runs) {
+        var variables = new Dictionary<string, IItem>();
+        foreach (var param in run.Parameters)
+          variables[param.Key] = param.Value;
+        foreach (var result in run.Results)
+          variables[result.Key] = result.Value;
+        try {
+          var value = calc.GetValue(variables);
+          if (value != null)
+            run.Results[ResultName] = value;
+          else
+            run.Results.Remove(ResultName);
+        } catch (Exception x) {
+          throw new Exception(string.Format("Calculation failed at Run {0}", run.Name), x);
+        }
+      }
+    }
+
+  }
+}
Index: /trunk/sources/HeuristicLab.Optimization/3.3/RunCollectionModification/RunCollectionGroupCreater.cs
===================================================================
--- /trunk/sources/HeuristicLab.Optimization/3.3/RunCollectionModification/RunCollectionGroupCreater.cs	(revision 7228)
+++ /trunk/sources/HeuristicLab.Optimization/3.3/RunCollectionModification/RunCollectionGroupCreater.cs	(revision 7228)
@@ -0,0 +1,84 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Optimization {
+
+  [Item("RunCollection Group Creater", "Regroups existing runs according to equal values in GroupBy and prefixes them according to their value in Prefix.")]
+  [StorableClass]
+  public class RunCollectionGroupCreater : ParameterizedNamedItem, IRunCollectionModifier {
+    
+    public ValueParameter<ItemCollection<StringValue>> GroupByParameter {
+      get { return (ValueParameter<ItemCollection<StringValue>>)Parameters["GroupBy"]; }
+    }
+
+    public ValueParameter<StringValue> PrefixParameter {
+      get { return (ValueParameter<StringValue>)Parameters["Prefix"]; }
+    }
+
+    private IEnumerable<string> GroupBy { get { return GroupByParameter.Value.Select(v => v.Value); } }
+    private string Prefix { get { return PrefixParameter.Value.Value; } }
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    protected RunCollectionGroupCreater(bool deserializing) : base(deserializing) { }
+    protected RunCollectionGroupCreater(RunCollectionGroupCreater original, Cloner cloner) : base(original, cloner) { }
+    public RunCollectionGroupCreater() {
+      Parameters.Add(new ValueParameter<ItemCollection<StringValue>>("GroupBy", "The variable that has to be the same for all members of a group.",
+        new ItemCollection<StringValue>(new[] { new StringValue("Problem Name") })));
+      Parameters.Add(new ValueParameter<StringValue>("Prefix", "The distinguishing prefix values for the individual runs.",
+        new StringValue("Algorithm Name")));      
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new RunCollectionGroupCreater(this, cloner);
+    }
+    #endregion    
+
+    private static string GetStringValue(string name, IRun r) {
+      IItem item;
+      r.Results.TryGetValue(name, out item);
+      if (item != null)
+        return item.ToString();
+      r.Parameters.TryGetValue(name, out item);
+      return item != null ? item.ToString() : "<none>";
+    }
+
+    private static string GetValues(IEnumerable<string> names, IRun r) {
+      return string.Join("/", names.Select(n => GetStringValue(n, r)));
+    }
+
+    public void Modify(List<IRun> runs) {
+      var groups = runs.GroupBy(r => GetValues(GroupBy, r).ToString()).ToList();
+      runs.Clear();
+      foreach (var group in groups) {
+        var run = new Run { Name = string.Format(group.Key) };
+        foreach (var r in group) {
+          var prefix = GetStringValue(Prefix, r);
+          foreach (var result in r.Results) {
+            InsertNew(run.Results, prefix, result.Key, result.Value);
+          }
+          foreach (var parameter in r.Parameters) {
+            InsertNew(run.Parameters, prefix, parameter.Key, parameter.Value);
+          }
+        }
+        runs.Add(run);
+      }
+    }
+
+    private static void InsertNew(IDictionary<string, IItem> dict, string prefix, string key, IItem value) {
+      if (prefix == null)
+        prefix = "<null>";
+      var n = 0;
+      var name = string.Format("{0}.{1}", prefix, key);
+      while (dict.ContainsKey(name)) {
+        name = string.Format("{0}_{1}.{2}", prefix, ++n, key);
+      }
+      dict.Add(name, value);      
+    }
+  }
+}
Index: /trunk/sources/HeuristicLab.Optimization/3.3/RunCollectionModification/RunCollectionRunRemover.cs
===================================================================
--- /trunk/sources/HeuristicLab.Optimization/3.3/RunCollectionModification/RunCollectionRunRemover.cs	(revision 7228)
+++ /trunk/sources/HeuristicLab.Optimization/3.3/RunCollectionModification/RunCollectionRunRemover.cs	(revision 7228)
@@ -0,0 +1,28 @@
+﻿using System.Collections.Generic;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Optimization {
+  [Item("RunCollection Run Remover", "Removes all currently visible runs. Use the filtering tab to selectively remove runs.")]
+  [StorableClass]
+  public class RunCollectionRunRemover : ParameterizedNamedItem, IRunCollectionModifier {
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    protected RunCollectionRunRemover(bool deserializing) : base(deserializing) { }
+    protected RunCollectionRunRemover(RunCollectionRunRemover original, Cloner cloner) : base(original, cloner) {}
+    public RunCollectionRunRemover() {}
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new RunCollectionRunRemover(this, cloner);
+    }
+    #endregion
+
+    #region IRunCollectionModifier Members
+    public void Modify(List<IRun> runs) {
+      runs.Clear();
+    }
+    #endregion
+
+  }
+}
Index: /trunk/sources/HeuristicLab.Optimization/3.3/RunCollectionModification/RunCollectionSorter.cs
===================================================================
--- /trunk/sources/HeuristicLab.Optimization/3.3/RunCollectionModification/RunCollectionSorter.cs	(revision 7228)
+++ /trunk/sources/HeuristicLab.Optimization/3.3/RunCollectionModification/RunCollectionSorter.cs	(revision 7228)
@@ -0,0 +1,108 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Optimization {
+  [Item("RunCollection Sorter", "Sorts a run collection according the specified key variable.")]
+  [StorableClass]
+  public class RunCollectionSorter : ParameterizedNamedItem, IRunCollectionModifier {
+
+    public override bool CanChangeName { get { return false; } }
+    public override bool CanChangeDescription { get { return false; } }
+
+    #region Parameters
+    public ValueParameter<StringValue> ValueParameter {
+      get { return (ValueParameter<StringValue>)Parameters["Value"]; }
+    }
+    #endregion
+
+    private string Value { get { return ValueParameter.Value.Value; } }
+
+    #region Construction & Cloning
+    [StorableConstructor]
+    protected RunCollectionSorter(bool deserializing) : base(deserializing) { }
+    protected RunCollectionSorter(RunCollectionSorter original, Cloner cloner)
+      : base(original, cloner) {
+      RegisterEvents();
+    }
+    public RunCollectionSorter() {
+      Parameters.Add(new ValueParameter<StringValue>("Value", "The variable name used as sorting key.", new StringValue("Value")));
+      RegisterEvents();
+      UpdateName();
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new RunCollectionSorter(this, cloner);
+    }
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      RegisterEvents();
+    }
+    #endregion
+
+    private void RegisterEvents() {
+      ValueParameter.ToStringChanged += Parameter_NameChanged;
+    }
+
+    private void Parameter_NameChanged(object sender, EventArgs e) {
+      UpdateName();
+    }
+
+    private void UpdateName() {
+      name = string.Format("Sort by {0}", Value);
+      OnNameChanged();
+    }
+
+    private class ValueComparer : IComparer<IComparable> {
+
+      #region IComparer<IComparable> Members
+
+      public int Compare(IComparable x, IComparable y) {
+        if (x == null && y == null) return 0;
+        if (x == null) return -1;
+        if (y == null) return 1;
+        return x.CompareTo(y);
+      }
+
+      #endregion
+    }
+
+    private static readonly ValueComparer Comparer = new ValueComparer();
+
+    #region IRunCollectionModifier Members
+
+    public void Modify(List<IRun> runs) {
+      var sortedRuns = runs
+        .Select(r => new {Run = r, Key = GetValue(r)})
+        .OrderBy(r => r.Key, Comparer)
+        .Select(r => r.Run).ToList();
+      runs.Clear();
+      runs.AddRange(sortedRuns);
+    }
+
+    private IComparable GetValue(IRun run) {
+      return GetValue(run.Results) ?? GetValue(run.Parameters);
+    }
+
+    private IComparable GetValue(IDictionary<string, IItem> variables) {
+      IItem value;
+      variables.TryGetValue(Value, out value);
+      var intValue = value as IntValue;
+      if (intValue != null)
+        return intValue;
+      var doubleValue = value as DoubleValue;
+      if (doubleValue != null)
+        return doubleValue;
+      if (value != null)
+        return value.ToString();
+      return null;
+    }
+
+    #endregion
+  }
+}
Index: /trunk/sources/HeuristicLab.Optimization/3.3/RunCollectionModification/RunCollectionValueRemover.cs
===================================================================
--- /trunk/sources/HeuristicLab.Optimization/3.3/RunCollectionModification/RunCollectionValueRemover.cs	(revision 7228)
+++ /trunk/sources/HeuristicLab.Optimization/3.3/RunCollectionModification/RunCollectionValueRemover.cs	(revision 7228)
@@ -0,0 +1,49 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Optimization {
+
+  [Item("RunCollection Value Remover", "Modifies a RunCollection by removing results or parameters.")]
+  [StorableClass]
+  public class RunCollectionValueRemover : ParameterizedNamedItem, IRunCollectionModifier {
+    
+    public ValueParameter<CheckedItemCollection<StringValue>> ValuesParameter {
+      get { return (ValueParameter<CheckedItemCollection<StringValue>>)Parameters["Values"]; }
+    }
+
+    public IEnumerable<string> Values {
+      get { return ValuesParameter.Value.CheckedItems.Select(v => v.Value); }
+    }
+
+    #region Construction & Cloning    
+    [StorableConstructor]
+    protected RunCollectionValueRemover(bool deserializing) : base(deserializing) { }
+    protected RunCollectionValueRemover(RunCollectionValueRemover original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public RunCollectionValueRemover() {
+      Parameters.Add(new ValueParameter<CheckedItemCollection<StringValue>>("Values", "The result or parameter values to be removed from each run."));      
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new RunCollectionValueRemover(this, cloner);
+    }    
+    #endregion    
+
+    public void Modify(List<IRun> runs) {      
+      foreach (var run in runs) {
+        foreach (var value in Values) {
+          run.Parameters.Remove(value);
+          run.Results.Remove(value);
+        }        
+      }      
+    }
+    
+  }
+}
Index: unk/sources/HeuristicLab.Optimization/3.3/RunCollectionRunRemover.cs
===================================================================
--- /trunk/sources/HeuristicLab.Optimization/3.3/RunCollectionRunRemover.cs	(revision 7227)
+++ 	(revision )
@@ -1,28 +1,0 @@
-﻿using System.Collections.Generic;
-using HeuristicLab.Common;
-using HeuristicLab.Core;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-
-namespace HeuristicLab.Optimization {
-  [Item("RunCollection Run Remover", "Removes all currently visible runs. Use the filtering tab to selectively remove runs.")]
-  [StorableClass]
-  public class RunCollectionRunRemover : ParameterizedNamedItem, IRunCollectionModifier {
-
-    #region Construction & Cloning
-    [StorableConstructor]
-    protected RunCollectionRunRemover(bool deserializing) : base(deserializing) { }
-    protected RunCollectionRunRemover(RunCollectionRunRemover original, Cloner cloner) : base(original, cloner) {}
-    public RunCollectionRunRemover() {}
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new RunCollectionRunRemover(this, cloner);
-    }
-    #endregion
-
-    #region IRunCollectionModifier Members
-    public void Modify(List<IRun> runs) {
-      runs.Clear();
-    }
-    #endregion
-
-  }
-}
Index: unk/sources/HeuristicLab.Optimization/3.3/RunCollectionSorter.cs
===================================================================
--- /trunk/sources/HeuristicLab.Optimization/3.3/RunCollectionSorter.cs	(revision 7227)
+++ 	(revision )
@@ -1,108 +1,0 @@
-﻿using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using HeuristicLab.Common;
-using HeuristicLab.Core;
-using HeuristicLab.Data;
-using HeuristicLab.Parameters;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-
-namespace HeuristicLab.Optimization {
-  [Item("RunCollection Sorter", "Sorts a run collection according the specified key variable.")]
-  [StorableClass]
-  public class RunCollectionSorter : ParameterizedNamedItem, IRunCollectionModifier {
-
-    public override bool CanChangeName { get { return false; } }
-    public override bool CanChangeDescription { get { return false; } }
-
-    #region Parameters
-    public ValueParameter<StringValue> ValueParameter {
-      get { return (ValueParameter<StringValue>)Parameters["Value"]; }
-    }
-    #endregion
-
-    private string Value { get { return ValueParameter.Value.Value; } }
-
-    #region Construction & Cloning
-    [StorableConstructor]
-    protected RunCollectionSorter(bool deserializing) : base(deserializing) { }
-    protected RunCollectionSorter(RunCollectionSorter original, Cloner cloner)
-      : base(original, cloner) {
-      RegisterEvents();
-    }
-    public RunCollectionSorter() {
-      Parameters.Add(new ValueParameter<StringValue>("Value", "The variable name used as sorting key.", new StringValue("Value")));
-      RegisterEvents();
-      UpdateName();
-    }
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new RunCollectionSorter(this, cloner);
-    }
-    [StorableHook(HookType.AfterDeserialization)]
-    private void AfterDeserialization() {
-      RegisterEvents();
-    }
-    #endregion
-
-    private void RegisterEvents() {
-      ValueParameter.ToStringChanged += Parameter_NameChanged;
-    }
-
-    private void Parameter_NameChanged(object sender, EventArgs e) {
-      UpdateName();
-    }
-
-    private void UpdateName() {
-      name = string.Format("Sort by {0}", Value);
-      OnNameChanged();
-    }
-
-    private class ValueComparer : IComparer<IComparable> {
-
-      #region IComparer<IComparable> Members
-
-      public int Compare(IComparable x, IComparable y) {
-        if (x == null && y == null) return 0;
-        if (x == null) return -1;
-        if (y == null) return 1;
-        return x.CompareTo(y);
-      }
-
-      #endregion
-    }
-
-    private static readonly ValueComparer Comparer = new ValueComparer();
-
-    #region IRunCollectionModifier Members
-
-    public void Modify(List<IRun> runs) {
-      var sortedRuns = runs
-        .Select(r => new {Run = r, Key = GetValue(r)})
-        .OrderBy(r => r.Key, Comparer)
-        .Select(r => r.Run).ToList();
-      runs.Clear();
-      runs.AddRange(sortedRuns);
-    }
-
-    private IComparable GetValue(IRun run) {
-      return GetValue(run.Results) ?? GetValue(run.Parameters);
-    }
-
-    private IComparable GetValue(IDictionary<string, IItem> variables) {
-      IItem value;
-      variables.TryGetValue(Value, out value);
-      var intValue = value as IntValue;
-      if (intValue != null)
-        return intValue;
-      var doubleValue = value as DoubleValue;
-      if (doubleValue != null)
-        return doubleValue;
-      if (value != null)
-        return value.ToString();
-      return null;
-    }
-
-    #endregion
-  }
-}
Index: unk/sources/HeuristicLab.Optimization/3.3/RunCollectionValueRemover.cs
===================================================================
--- /trunk/sources/HeuristicLab.Optimization/3.3/RunCollectionValueRemover.cs	(revision 7227)
+++ 	(revision )
@@ -1,49 +1,0 @@
-﻿using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using HeuristicLab.Common;
-using HeuristicLab.Core;
-using HeuristicLab.Data;
-using HeuristicLab.Parameters;
-using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
-
-namespace HeuristicLab.Optimization {
-
-  [Item("RunCollection Value Remover", "Modifies a RunCollection by removing results or parameters.")]
-  [StorableClass]
-  public class RunCollectionValueRemover : ParameterizedNamedItem, IRunCollectionModifier {
-    
-    public ValueParameter<CheckedItemCollection<StringValue>> ValuesParameter {
-      get { return (ValueParameter<CheckedItemCollection<StringValue>>)Parameters["Values"]; }
-    }
-
-    public IEnumerable<string> Values {
-      get { return ValuesParameter.Value.CheckedItems.Select(v => v.Value); }
-    }
-
-    #region Construction & Cloning    
-    [StorableConstructor]
-    protected RunCollectionValueRemover(bool deserializing) : base(deserializing) { }
-    protected RunCollectionValueRemover(RunCollectionValueRemover original, Cloner cloner)
-      : base(original, cloner) {
-    }
-    public RunCollectionValueRemover() {
-      Parameters.Add(new ValueParameter<CheckedItemCollection<StringValue>>("Values", "The result or parameter values to be removed from each run."));      
-    }
-    public override IDeepCloneable Clone(Cloner cloner) {
-      return new RunCollectionValueRemover(this, cloner);
-    }    
-    #endregion    
-
-    public void Modify(List<IRun> runs) {      
-      foreach (var run in runs) {
-        foreach (var value in Values) {
-          run.Parameters.Remove(value);
-          run.Results.Remove(value);
-        }        
-      }      
-    }
-    
-  }
-}
