Index: /branches/DataAnalysis/HeuristicLab.Problems.DataAnalysis/3.3/Symbolic/SymbolicSimplifier.cs
===================================================================
--- /branches/DataAnalysis/HeuristicLab.Problems.DataAnalysis/3.3/Symbolic/SymbolicSimplifier.cs	(revision 4219)
+++ /branches/DataAnalysis/HeuristicLab.Problems.DataAnalysis/3.3/Symbolic/SymbolicSimplifier.cs	(revision 4220)
@@ -32,7 +32,4 @@
   /// <summary>
   /// Simplistic simplifier for arithmetic expressions
-  /// Rules:
-  ///  * Constants are always the last argument to any function
-  ///  * f(c1, c2) => c3 (constant expression folding)
   /// </summary>
   public class SymbolicSimplifier {
@@ -85,4 +82,38 @@
     }
 
+
+    #region symbol predicates
+    private bool IsDivision(SymbolicExpressionTreeNode original) {
+      return original.Symbol is Division;
+    }
+
+    private bool IsMultiplication(SymbolicExpressionTreeNode original) {
+      return original.Symbol is Multiplication;
+    }
+
+    private bool IsSubtraction(SymbolicExpressionTreeNode original) {
+      return original.Symbol is Subtraction;
+    }
+
+    private bool IsAddition(SymbolicExpressionTreeNode original) {
+      return original.Symbol is Addition;
+    }
+
+    private bool IsVariable(SymbolicExpressionTreeNode original) {
+      return original.Symbol is Variable;
+    }
+
+    private bool IsConstant(SymbolicExpressionTreeNode original) {
+      return original.Symbol is Constant;
+    }
+
+    private bool IsAverage(SymbolicExpressionTreeNode original) {
+      return original.Symbol is Average;
+    }
+    private bool IsLog(SymbolicExpressionTreeNode original) {
+      return original.Symbol is Logarithm;
+    }
+    #endregion
+
     /// <summary>
     /// Creates a new simplified tree
@@ -94,72 +125,337 @@
         return (SymbolicExpressionTreeNode)original.Clone();
       } else if (IsAddition(original)) {
-        if (original.SubTrees.Count == 1) {
-          return GetSimplifiedTree(original.SubTrees[0]);
+        return SimplifyAddition(original);
+      } else if (IsSubtraction(original)) {
+        return SimplifySubtraction(original);
+      } else if (IsMultiplication(original)) {
+        return SimplifyMultiplication(original);
+      } else if (IsDivision(original)) {
+        return SimplifyDivision(original);
+      } else if (IsAverage(original)) {
+        return SimplifyAverage(original);
+      } else if (IsLog(original)) {
+        // TODO simplify logarditm
+        return SimplifyAny(original);
+      } else if (IsAverage(original)) {
+        return SimplifyAverage(original);
+      } else {
+        return SimplifyAny(original);
+      }
+    }
+
+    #region specific simplification routines
+    private SymbolicExpressionTreeNode SimplifyAny(SymbolicExpressionTreeNode original) {
+      // can't simplify this function but simplify all subtrees 
+      List<SymbolicExpressionTreeNode> subTrees = new List<SymbolicExpressionTreeNode>(original.SubTrees);
+      while (original.SubTrees.Count > 0) original.RemoveSubTree(0);
+      var clone = (SymbolicExpressionTreeNode)original.Clone();
+      List<SymbolicExpressionTreeNode> simplifiedSubTrees = new List<SymbolicExpressionTreeNode>();
+      foreach (var subTree in subTrees) {
+        simplifiedSubTrees.Add(GetSimplifiedTree(subTree));
+        original.AddSubTree(subTree);
+      }
+      foreach (var simplifiedSubtree in simplifiedSubTrees) {
+        clone.AddSubTree(simplifiedSubtree);
+      }
+      if (simplifiedSubTrees.TrueForAll(t => IsConstant(t))) {
+        SimplifyConstantExpression(clone);
+      }
+      return clone;
+    }
+
+    private SymbolicExpressionTreeNode SimplifyConstantExpression(SymbolicExpressionTreeNode original) {
+      // not yet implemented
+      return original;
+    }
+
+    private SymbolicExpressionTreeNode SimplifyAverage(SymbolicExpressionTreeNode original) {
+      if (original.SubTrees.Count == 1) {
+        return GetSimplifiedTree(original.SubTrees[0]);
+      } else {
+        // simplify expressions x0..xn
+        // make sum(x0..xn) / n
+        Trace.Assert(original.SubTrees.Count > 1);
+        var sum = original.SubTrees
+          .Select(x => GetSimplifiedTree(x))
+          .Aggregate((a, b) => MakeSum(a, b));
+        return MakeFraction(sum, MakeConstant(original.SubTrees.Count));
+      }
+    }
+
+    private SymbolicExpressionTreeNode SimplifyDivision(SymbolicExpressionTreeNode original) {
+      if (original.SubTrees.Count == 1) {
+        return Invert(GetSimplifiedTree(original.SubTrees[0]));
+      } else {
+        // simplify expressions x0..xn
+        // make multiplication (x0 * 1/(x1 * x1 * .. * xn))
+        Trace.Assert(original.SubTrees.Count > 1);
+        var simplifiedTrees = original.SubTrees.Select(x => GetSimplifiedTree(x));
+        return
+          MakeProduct(simplifiedTrees.First(), Invert(simplifiedTrees.Skip(1).Aggregate((a, b) => MakeProduct(a, b))));
+      }
+    }
+
+    private SymbolicExpressionTreeNode SimplifyMultiplication(SymbolicExpressionTreeNode original) {
+      if (original.SubTrees.Count == 1) {
+        return GetSimplifiedTree(original.SubTrees[0]);
+      } else {
+        Trace.Assert(original.SubTrees.Count > 1);
+        return original.SubTrees
+          .Select(x => GetSimplifiedTree(x))
+          .Aggregate((a, b) => MakeProduct(a, b));
+      }
+    }
+
+    private SymbolicExpressionTreeNode SimplifySubtraction(SymbolicExpressionTreeNode original) {
+      if (original.SubTrees.Count == 1) {
+        return Negate(GetSimplifiedTree(original.SubTrees[0]));
+      } else {
+        // simplify expressions x0..xn
+        // make addition (x0,-x1..-xn)
+        Trace.Assert(original.SubTrees.Count > 1);
+        var simplifiedTrees = original.SubTrees.Select(x => GetSimplifiedTree(x));
+        return simplifiedTrees.Take(1)
+          .Concat(simplifiedTrees.Skip(1).Select(x => Negate(x)))
+          .Aggregate((a, b) => MakeSum(a, b));
+      }
+    }
+
+    private SymbolicExpressionTreeNode SimplifyAddition(SymbolicExpressionTreeNode original) {
+      if (original.SubTrees.Count == 1) {
+        return GetSimplifiedTree(original.SubTrees[0]);
+      } else {
+        // simplify expression x0..xn
+        // make addition (x0..xn)
+        Trace.Assert(original.SubTrees.Count > 1);
+        return original.SubTrees
+          .Select(x => GetSimplifiedTree(x))
+          .Aggregate((a, b) => MakeSum(a, b));
+      }
+    }
+    #endregion
+
+
+
+    #region low level tree restructuring
+    // each make* method must return a simplified tree
+
+    private SymbolicExpressionTreeNode MakeFraction(SymbolicExpressionTreeNode a, SymbolicExpressionTreeNode b) {
+      if (IsConstant(a) && IsConstant(b)) {
+        // fold constants
+        return MakeConstant(((ConstantTreeNode)a).Value / ((ConstantTreeNode)b).Value);
+      } if (IsConstant(a) && !((ConstantTreeNode)a).Value.IsAlmost(1.0)) {
+        return MakeFraction(MakeConstant(1.0), MakeProduct(b, Invert(a)));
+      } else if (IsVariable(a) && IsConstant(b)) {
+        // merge constant values into variable weights
+        var constB = ((ConstantTreeNode)b).Value;
+        ((VariableTreeNode)a).Weight /= constB;
+        return a;
+      } else if (IsAddition(a) && IsConstant(b)) {
+        return a.SubTrees
+         .Select(x => MakeFraction(x, b))
+         .Aggregate((c, d) => MakeSum(c, d));
+      } else if (IsMultiplication(a) && IsConstant(b)) {
+        return MakeProduct(a, Invert(b));
+      } else if (IsDivision(a) && IsConstant(b)) {
+        // (a1 / a2) / c => (a1 / (a2 * c))
+        Trace.Assert(a.SubTrees.Count == 2);
+        return MakeFraction(a.SubTrees[0], MakeProduct(a.SubTrees[1], b));
+      } else if (IsDivision(a) && IsDivision(b)) {
+        // (a1 / a2) / (b1 / b2) => 
+        Trace.Assert(a.SubTrees.Count == 2);
+        Trace.Assert(b.SubTrees.Count == 2);
+        return MakeFraction(MakeProduct(a.SubTrees[0], b.SubTrees[1]), MakeProduct(a.SubTrees[1], b.SubTrees[0]));
+      } else if (IsDivision(a)) {
+        // (a1 / a2) / b => (a1 / (a2 * b))
+        Trace.Assert(a.SubTrees.Count == 2);
+        return MakeFraction(a.SubTrees[0], MakeProduct(a.SubTrees[1], b));
+      } else if (IsDivision(b)) {
+        // a / (b1 / b2) => (a * b2) / b1
+        Trace.Assert(b.SubTrees.Count == 2);
+        return MakeFraction(MakeProduct(a, b.SubTrees[1]), b.SubTrees[0]);
+      } else {
+        var div = divSymbol.CreateTreeNode();
+        div.AddSubTree(a);
+        div.AddSubTree(b);
+        return div;
+      }
+    }
+
+    private SymbolicExpressionTreeNode MakeSum(SymbolicExpressionTreeNode a, SymbolicExpressionTreeNode b) {
+      if (IsConstant(a) && IsConstant(b)) {
+        // fold constants
+        ((ConstantTreeNode)a).Value += ((ConstantTreeNode)b).Value;
+        return a;
+      } else if (IsConstant(a)) {
+        // c + x => x + c
+        // b is not constant => make sure constant is on the right
+        return MakeSum(b, a);
+      } else if (IsConstant(b) && ((ConstantTreeNode)b).Value.IsAlmost(0.0)) {
+        // x + 0 => x
+        return a;
+      } else if (IsAddition(a) && IsAddition(b)) {
+        // merge additions
+        var add = addSymbol.CreateTreeNode();
+        for (int i = 0; i < a.SubTrees.Count - 1; i++) add.AddSubTree(a.SubTrees[i]);
+        for (int i = 0; i < b.SubTrees.Count - 1; i++) add.AddSubTree(b.SubTrees[i]);
+        if (IsConstant(a.SubTrees.Last()) && IsConstant(b.SubTrees.Last())) {
+          add.AddSubTree(MakeSum(a.SubTrees.Last(), b.SubTrees.Last()));
+        } else if (IsConstant(a.SubTrees.Last())) {
+          add.AddSubTree(b.SubTrees.Last());
+          add.AddSubTree(a.SubTrees.Last());
         } else {
-          // simplify expression x0..xn
-          // make addition (x0..xn)
-          Trace.Assert(original.SubTrees.Count > 1);
-          return original.SubTrees
-            .Select(x => GetSimplifiedTree(x))
-            .Aggregate((a, b) => MakeAddition(a, b));
-        }
-      } else if (IsSubtraction(original)) {
-        if (original.SubTrees.Count == 1) {
-          return Negate(GetSimplifiedTree(original.SubTrees[0]));
+          add.AddSubTree(a.SubTrees.Last());
+          add.AddSubTree(b.SubTrees.Last());
+        }
+        MergeVariablesInSum(add);
+        return add;
+      } else if (IsAddition(b)) {
+        return MakeSum(b, a);
+      } else if (IsAddition(a) && IsConstant(b)) {
+        // a is an addition and b is a constant => append b to a and make sure the constants are merged
+        var add = addSymbol.CreateTreeNode();
+        for (int i = 0; i < a.SubTrees.Count - 1; i++) add.AddSubTree(a.SubTrees[i]);
+        if (IsConstant(a.SubTrees.Last()))
+          add.AddSubTree(MakeSum(a.SubTrees.Last(), b));
+        else {
+          add.AddSubTree(a.SubTrees.Last());
+          add.AddSubTree(b);
+        }
+        return add;
+      } else if (IsAddition(a)) {
+        // a is already an addition => append b
+        var add = addSymbol.CreateTreeNode();
+        add.AddSubTree(b);
+        foreach (var subTree in a.SubTrees) {
+          add.AddSubTree(subTree);
+        }
+        MergeVariablesInSum(add);
+        return add;
+      } else {
+        var add = addSymbol.CreateTreeNode();
+        add.AddSubTree(a);
+        add.AddSubTree(b);
+        MergeVariablesInSum(add);
+        return add;
+      }
+    }
+
+    private void MergeVariablesInSum(SymbolicExpressionTreeNode sum) {
+      var subtrees = new List<SymbolicExpressionTreeNode>(sum.SubTrees);
+      while (sum.SubTrees.Count > 0) sum.RemoveSubTree(0);
+      var groupedVarNodes = from node in subtrees.OfType<VariableTreeNode>()
+                            group node by node.VariableName into g
+                            select g;
+      var unchangedSubTrees = subtrees.Where(t => !(t is VariableTreeNode));
+
+      foreach (var variableNodeGroup in groupedVarNodes) {
+        var weightSum = variableNodeGroup.Select(t => t.Weight).Sum();
+        var representative = variableNodeGroup.First();
+        representative.Weight = weightSum;
+        sum.AddSubTree(representative);
+      }
+      foreach (var unchangedSubtree in unchangedSubTrees)
+        sum.AddSubTree(unchangedSubtree);
+    }
+
+
+    private SymbolicExpressionTreeNode MakeProduct(SymbolicExpressionTreeNode a, SymbolicExpressionTreeNode b) {
+      if (IsConstant(a) && IsConstant(b)) {
+        // fold constants
+        ((ConstantTreeNode)a).Value *= ((ConstantTreeNode)b).Value;
+        return a;
+      } else if (IsConstant(a)) {
+        // a * $ => $ * a
+        return MakeProduct(b, a);
+      } else if (IsConstant(b) && ((ConstantTreeNode)b).Value.IsAlmost(1.0)) {
+        // $ * 1.0 => $
+        return a;
+      } else if (IsConstant(b) && IsVariable(a)) {
+        // multiply constants into variables weights
+        ((VariableTreeNode)a).Weight *= ((ConstantTreeNode)b).Value;
+        return a;
+      } else if (IsConstant(b) && IsAddition(a)) {
+        // multiply constants into additions
+        return a.SubTrees.Select(x => MakeProduct(x, b)).Aggregate((c, d) => MakeSum(c, d));
+      } else if (IsDivision(a) && IsDivision(b)) {
+        // (a1 / a2) * (b1 / b2) => (a1 * b1) / (a2 * b2)
+        Trace.Assert(a.SubTrees.Count == 2);
+        Trace.Assert(b.SubTrees.Count == 2);
+        return MakeFraction(MakeProduct(a.SubTrees[0], b.SubTrees[0]), MakeProduct(a.SubTrees[1], b.SubTrees[1]));
+      } else if (IsDivision(a)) {
+        // (a1 / a2) * b => (a1 * b) / a2
+        Trace.Assert(a.SubTrees.Count == 2);
+        return MakeFraction(MakeProduct(a.SubTrees[0], b), a.SubTrees[1]);
+      } else if (IsDivision(b)) {
+        // a * (b1 / b2) => (b1 * a) / b2
+        Trace.Assert(b.SubTrees.Count == 2);
+        return MakeFraction(MakeProduct(b.SubTrees[0], a), b.SubTrees[1]);
+      } else if (IsMultiplication(a) && IsMultiplication(b)) {
+        // merge multiplications (make sure constants are merged)
+        var mul = mulSymbol.CreateTreeNode();
+        for (int i = 0; i < a.SubTrees.Count; i++) mul.AddSubTree(a.SubTrees[i]);
+        for (int i = 0; i < b.SubTrees.Count; i++) mul.AddSubTree(b.SubTrees[i]);
+        MergeVariablesAndConstantsInProduct(mul);
+        return mul;
+      } else if (IsMultiplication(b)) {
+        return MakeProduct(b, a);
+      } else if (IsMultiplication(a)) {
+        // a is already an multiplication => append b
+        a.AddSubTree(b);
+        MergeVariablesAndConstantsInProduct(a);
+        return a;
+      } else {
+        var mul = mulSymbol.CreateTreeNode();
+        mul.SubTrees.Add(a);
+        mul.SubTrees.Add(b);
+        MergeVariablesAndConstantsInProduct(mul);
+        return mul;
+      }
+    }
+    #endregion
+
+    private void MergeVariablesAndConstantsInProduct(SymbolicExpressionTreeNode prod) {
+      var subtrees = new List<SymbolicExpressionTreeNode>(prod.SubTrees);
+      while (prod.SubTrees.Count > 0) prod.RemoveSubTree(0);
+      var groupedVarNodes = from node in subtrees.OfType<VariableTreeNode>()
+                            group node by node.VariableName into g
+                            orderby g.Count()
+                            select g;
+      var constantProduct = (from node in subtrees.OfType<VariableTreeNode>()
+                             select node.Weight)
+                            .Concat(from node in subtrees.OfType<ConstantTreeNode>()
+                                    select node.Value)
+                            .DefaultIfEmpty(1.0)
+                            .Aggregate((c1, c2) => c1 * c2);
+
+      var unchangedSubTrees = from tree in subtrees
+                              where !(tree is VariableTreeNode)
+                              where !(tree is ConstantTreeNode)
+                              select tree;
+
+      foreach (var variableNodeGroup in groupedVarNodes) {
+        var representative = variableNodeGroup.First();
+        representative.Weight = 1.0;
+        if (variableNodeGroup.Count() > 1) {
+          var poly = mulSymbol.CreateTreeNode();
+          for (int p = 0; p < variableNodeGroup.Count(); p++) {
+            poly.AddSubTree((SymbolicExpressionTreeNode)representative.Clone());
+          }
+          prod.AddSubTree(poly);
         } else {
-          // simplify expressions x0..xn
-          // make addition (x0,-x1..-xn)
-          Trace.Assert(original.SubTrees.Count > 1);
-          var simplifiedTrees = original.SubTrees.Select(x => GetSimplifiedTree(x));
-          return simplifiedTrees.Take(1)
-            .Concat(simplifiedTrees.Skip(1).Select(x => Negate(x)))
-            .Aggregate((a, b) => MakeAddition(a, b));
-        }
-      } else if (IsMultiplication(original)) {
-        if (original.SubTrees.Count == 1) {
-          return GetSimplifiedTree(original.SubTrees[0]);
-        } else {
-          Trace.Assert(original.SubTrees.Count > 1);
-          return original.SubTrees
-            .Select(x => GetSimplifiedTree(x))
-            .Aggregate((a, b) => MakeMultiplication(a, b));
-        }
-      } else if (IsDivision(original)) {
-        if (original.SubTrees.Count == 1) {
-          return Invert(GetSimplifiedTree(original.SubTrees[0]));
-        } else {
-          // simplify expressions x0..xn
-          // make multiplication (x0 * 1/(x1 * x1 * .. * xn))
-          Trace.Assert(original.SubTrees.Count > 1);
-          var simplifiedTrees = original.SubTrees.Select(x => GetSimplifiedTree(x));
-          return
-            MakeMultiplication(simplifiedTrees.First(), Invert(simplifiedTrees.Skip(1).Aggregate((a, b) => MakeMultiplication(a, b))));
-        }
-      } else if (IsAverage(original)) {
-        if (original.SubTrees.Count == 1) {
-          return GetSimplifiedTree(original.SubTrees[0]);
-        } else {
-          // simpliy expressions x0..xn
-          // make sum(x0..xn) / n
-          Trace.Assert(original.SubTrees.Count > 1);
-          var sum = original.SubTrees
-            .Select(x => GetSimplifiedTree(x))
-            .Aggregate((a, b) => MakeAddition(a, b));
-          return MakeDivision(sum, MakeConstant(original.SubTrees.Count));
-        }
-      } else {
-        // can't simplify this function but simplify all subtrees 
-        // TODO evaluate the function if original is a constant expression
-        List<SymbolicExpressionTreeNode> subTrees = new List<SymbolicExpressionTreeNode>(original.SubTrees);
-        while (original.SubTrees.Count > 0) original.RemoveSubTree(0);
-        var clone = (SymbolicExpressionTreeNode)original.Clone();
-        foreach (var subTree in subTrees) {
-          clone.AddSubTree(GetSimplifiedTree(subTree));
-          original.AddSubTree(subTree);
-        }
-        return clone;
-      }
-    }
-
+          prod.AddSubTree(representative);
+        }
+      }
+
+      foreach (var unchangedSubtree in unchangedSubTrees)
+        prod.AddSubTree(unchangedSubtree);
+
+      if (!constantProduct.IsAlmost(1.0)) {
+        prod.AddSubTree(MakeConstant(constantProduct));
+      }
+    }
+
+
+    #region helper functions
     /// <summary>
     /// x => x * -1
@@ -184,5 +480,5 @@
       } else {
         // any other function
-        return MakeMultiplication(x, MakeConstant(-1));
+        return MakeProduct(x, MakeConstant(-1));
       }
       return x;
@@ -198,175 +494,13 @@
       if (IsConstant(x)) {
         ((ConstantTreeNode)x).Value = 1.0 / ((ConstantTreeNode)x).Value;
+      } else if (IsDivision(x)) {
+        Trace.Assert(x.SubTrees.Count == 2);
+        return MakeFraction(x.SubTrees[1], x.SubTrees[0]);
       } else {
         // any other function
-        return MakeDivision(MakeConstant(1), x);
+        return MakeFraction(MakeConstant(1), x);
       }
       return x;
     }
-
-    private SymbolicExpressionTreeNode MakeDivision(SymbolicExpressionTreeNode a, SymbolicExpressionTreeNode b) {
-      if (IsConstant(a) && IsConstant(b)) {
-        return MakeConstant(((ConstantTreeNode)a).Value / ((ConstantTreeNode)b).Value);
-      } else if (IsVariable(a) && IsConstant(b)) {
-        var constB = ((ConstantTreeNode)b).Value;
-        ((VariableTreeNode)a).Weight /= constB;
-        return a;
-      } else {
-        var div = divSymbol.CreateTreeNode();
-        div.AddSubTree(a);
-        div.AddSubTree(b);
-        return div;
-      }
-    }
-
-    private SymbolicExpressionTreeNode MakeAddition(SymbolicExpressionTreeNode a, SymbolicExpressionTreeNode b) {
-      if (IsConstant(a) && IsConstant(b)) {
-        // merge constants
-        ((ConstantTreeNode)a).Value += ((ConstantTreeNode)b).Value;
-        return a;
-      } else if (IsConstant(a)) {
-        // c + x => x + c
-        // b is not constant => make sure constant is on the right
-        return MakeAddition(b, a);
-      } else if (IsConstant(b) && ((ConstantTreeNode)b).Value.IsAlmost(0.0)) {
-        // x + 0 => x
-        return a;
-      } else if (IsAddition(a) && IsAddition(b)) {
-        // merge additions
-        var add = addSymbol.CreateTreeNode();
-        for (int i = 0; i < a.SubTrees.Count - 1; i++) add.AddSubTree(a.SubTrees[i]);
-        for (int i = 0; i < b.SubTrees.Count - 1; i++) add.AddSubTree(b.SubTrees[i]);
-        if (IsConstant(a.SubTrees.Last()) && IsConstant(b.SubTrees.Last())) {
-          add.AddSubTree(MakeAddition(a.SubTrees.Last(), b.SubTrees.Last()));
-        } else if (IsConstant(a.SubTrees.Last())) {
-          add.AddSubTree(b.SubTrees.Last());
-          add.AddSubTree(a.SubTrees.Last());
-        } else {
-          add.AddSubTree(a.SubTrees.Last());
-          add.AddSubTree(b.SubTrees.Last());
-        }
-        MergeVariables(add);
-        return add;
-      } else if (IsAddition(b)) {
-        return MakeAddition(b, a);
-      } else if (IsAddition(a) && IsConstant(b)) {
-        var add = addSymbol.CreateTreeNode();
-        for (int i = 0; i < a.SubTrees.Count - 1; i++) add.AddSubTree(a.SubTrees[i]);
-        if (IsConstant(a.SubTrees.Last()))
-          add.AddSubTree(MakeAddition(a.SubTrees.Last(), b));
-        else {
-          add.AddSubTree(a.SubTrees.Last());
-          add.AddSubTree(b);
-        }
-        return add;
-      } else if (IsAddition(a)) {
-        var add = addSymbol.CreateTreeNode();
-        add.AddSubTree(b);
-        foreach (var subTree in a.SubTrees) {
-          add.AddSubTree(subTree);
-        }
-        MergeVariables(add);
-        return add;
-      } else {
-        var add = addSymbol.CreateTreeNode();
-        add.AddSubTree(a);
-        add.AddSubTree(b);
-        MergeVariables(add);
-        return add;
-      }
-    }
-
-    private void MergeVariables(SymbolicExpressionTreeNode add) {
-      var subtrees = new List<SymbolicExpressionTreeNode>(add.SubTrees);
-      while (add.SubTrees.Count > 0) add.RemoveSubTree(0);
-      var groupedVarNodes = from node in subtrees.OfType<VariableTreeNode>()
-                            group node by node.VariableName into g
-                            select g;
-      var unchangedSubTrees = subtrees.Where(t => !(t is VariableTreeNode));
-
-      foreach (var variableNodeGroup in groupedVarNodes) {
-        var weightSum = variableNodeGroup.Select(t => t.Weight).Sum();
-        var representative = variableNodeGroup.First();
-        representative.Weight = weightSum;
-        add.AddSubTree(representative);
-      }
-      foreach (var unchangedSubtree in unchangedSubTrees)
-        add.AddSubTree(unchangedSubtree);
-    }
-
-    private SymbolicExpressionTreeNode MakeMultiplication(SymbolicExpressionTreeNode a, SymbolicExpressionTreeNode b) {
-      if (IsConstant(a) && IsConstant(b)) {
-        ((ConstantTreeNode)a).Value *= ((ConstantTreeNode)b).Value;
-        return a;
-      } else if (IsConstant(a)) {
-        return MakeMultiplication(b, a);
-      } else if (IsConstant(b) && ((ConstantTreeNode)b).Value.IsAlmost(1.0)) {
-        return a;
-      } else if (IsConstant(b) && IsVariable(a)) {
-        ((VariableTreeNode)a).Weight *= ((ConstantTreeNode)b).Value;
-        return a;
-      } else if (IsConstant(b) && IsAddition(a)) {
-        return a.SubTrees.Select(x => MakeMultiplication(x, b)).Aggregate((c, d) => MakeAddition(c, d));
-      } else if (IsDivision(a) && IsDivision(b)) {
-        return MakeDivision(MakeMultiplication(a.SubTrees[0], b.SubTrees[0]), MakeMultiplication(a.SubTrees[1], b.SubTrees[1]));
-      } else if (IsDivision(a)) {
-        Trace.Assert(a.SubTrees.Count == 2);
-        return MakeDivision(MakeMultiplication(a.SubTrees[0], b), a.SubTrees[1]);
-      } else if (IsDivision(b)) {
-        Trace.Assert(b.SubTrees.Count == 2);
-        return MakeDivision(MakeMultiplication(b.SubTrees[0], a), b.SubTrees[1]);
-      } else if (IsMultiplication(a) && IsMultiplication(b)) {
-        var mul = mulSymbol.CreateTreeNode();
-        for (int i = 0; i < a.SubTrees.Count - 1; i++) mul.AddSubTree(a.SubTrees[i]);
-        for (int i = 0; i < b.SubTrees.Count - 1; i++) mul.AddSubTree(b.SubTrees[i]);
-        mul.AddSubTree(MakeMultiplication(a.SubTrees.Last(), b.SubTrees.Last()));
-        return mul;
-      } else if (IsMultiplication(a)) {
-        var mul = mulSymbol.CreateTreeNode();
-        for (int i = 0; i < a.SubTrees.Count - 1; i++) mul.AddSubTree(a.SubTrees[i]);
-        mul.AddSubTree(MakeMultiplication(a.SubTrees.Last(), b));
-        return mul;
-      } else if (IsMultiplication(b)) {
-        var mul = mulSymbol.CreateTreeNode();
-        for (int i = 0; i < b.SubTrees.Count - 1; i++) mul.AddSubTree(b.SubTrees[i]);
-        mul.AddSubTree(MakeMultiplication(b.SubTrees.Last(), a));
-        return mul;
-      } else {
-        var mul = mulSymbol.CreateTreeNode();
-        mul.SubTrees.Add(a);
-        mul.SubTrees.Add(b);
-        return mul;
-      }
-    }
-
-    #region is symbol ?
-    private bool IsDivision(SymbolicExpressionTreeNode original) {
-      return original.Symbol is Division;
-    }
-
-    private bool IsMultiplication(SymbolicExpressionTreeNode original) {
-      return original.Symbol is Multiplication;
-    }
-
-    private bool IsSubtraction(SymbolicExpressionTreeNode original) {
-      return original.Symbol is Subtraction;
-    }
-
-    private bool IsAddition(SymbolicExpressionTreeNode original) {
-      return original.Symbol is Addition;
-    }
-
-    private bool IsVariable(SymbolicExpressionTreeNode original) {
-      return original.Symbol is Variable;
-    }
-
-    private bool IsConstant(SymbolicExpressionTreeNode original) {
-      return original.Symbol is Constant;
-    }
-
-    private bool IsAverage(SymbolicExpressionTreeNode original) {
-      return original.Symbol is Average;
-    }
-    #endregion
 
     private SymbolicExpressionTreeNode MakeConstant(double value) {
@@ -382,4 +516,5 @@
       return tree;
     }
+    #endregion
   }
 }
Index: /branches/DataAnalysis/HeuristicLab.Problems.DataAnalysis/3.3/Symbolic/Symbols/VariableTreeNode.cs
===================================================================
--- /branches/DataAnalysis/HeuristicLab.Problems.DataAnalysis/3.3/Symbolic/Symbols/VariableTreeNode.cs	(revision 4219)
+++ /branches/DataAnalysis/HeuristicLab.Problems.DataAnalysis/3.3/Symbolic/Symbols/VariableTreeNode.cs	(revision 4220)
@@ -21,4 +21,5 @@
 
 using HeuristicLab.Core;
+using HeuristicLab.Common;
 using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
@@ -80,5 +81,6 @@
 
     public override string ToString() {
-      return weight.ToString("E4") + " " + variableName;
+      if (weight.IsAlmost(1.0)) return variableName;
+      else return weight.ToString("E4") + " " + variableName;
     }
   }
