Index: branches/symbreg-factors-2650/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Importer/SymbolicExpressionImporter.cs
===================================================================
--- branches/symbreg-factors-2650/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Importer/SymbolicExpressionImporter.cs	(revision 14534)
+++ branches/symbreg-factors-2650/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Importer/SymbolicExpressionImporter.cs	(revision 14535)
@@ -77,5 +77,5 @@
         {"MAIN", new StartSymbol()},
         {"FACTOR", new FactorVariable() },
-        {"BINARYFACTOR", new BinaryFactorVariable()}
+        {"BINFACTOR", new BinaryFactorVariable()}
       };
 
@@ -144,5 +144,5 @@
         } else if(tokens.Peek().StringValue.StartsWith("FACTOR")) {
           tree = ParseFactor(tokens);
-        } else if(tokens.Peek().StringValue.StartsWith("BINARYFACTOR")) {
+        } else if(tokens.Peek().StringValue.StartsWith("BINFACTOR")) {
           tree = ParseBinaryFactor(tokens);
         } else {
@@ -242,5 +242,5 @@
       var varValTok = tokens.Dequeue();
       Debug.Assert(tok.Symbol == TokenSymbol.SYMB);
-      t.VariableValue = varNameTok.StringValue;
+      t.VariableValue = varValTok.StringValue;
 
       var weightTok = tokens.Dequeue();
Index: branches/symbreg-factors-2650/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisExpressionTreeSimplifier.cs
===================================================================
--- branches/symbreg-factors-2650/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisExpressionTreeSimplifier.cs	(revision 14534)
+++ branches/symbreg-factors-2650/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisExpressionTreeSimplifier.cs	(revision 14535)
@@ -71,14 +71,14 @@
       IList<ISymbolicExpressionTreeNode> argumentTrees) {
       List<ISymbolicExpressionTreeNode> subtrees = new List<ISymbolicExpressionTreeNode>(node.Subtrees);
-      while (node.SubtreeCount > 0) node.RemoveSubtree(0);
-      if (node.Symbol is InvokeFunction) {
+      while(node.SubtreeCount > 0) node.RemoveSubtree(0);
+      if(node.Symbol is InvokeFunction) {
         var invokeSym = node.Symbol as InvokeFunction;
         var defunNode = FindFunctionDefinition(root, invokeSym.FunctionName);
         var macroExpandedArguments = new List<ISymbolicExpressionTreeNode>();
-        foreach (var subtree in subtrees) {
+        foreach(var subtree in subtrees) {
           macroExpandedArguments.Add(MacroExpand(root, subtree, argumentTrees));
         }
         return MacroExpand(root, defunNode, macroExpandedArguments);
-      } else if (node.Symbol is Argument) {
+      } else if(node.Symbol is Argument) {
         var argSym = node.Symbol as Argument;
         // return the correct argument sub-tree (already macro-expanded)
@@ -86,5 +86,5 @@
       } else {
         // recursive application
-        foreach (var subtree in subtrees) {
+        foreach(var subtree in subtrees) {
           node.AddSubtree(MacroExpand(root, subtree, argumentTrees));
         }
@@ -94,6 +94,6 @@
 
     private ISymbolicExpressionTreeNode FindFunctionDefinition(ISymbolicExpressionTreeNode root, string functionName) {
-      foreach (var subtree in root.Subtrees.OfType<DefunTreeNode>()) {
-        if (subtree.FunctionName == functionName) return subtree.GetSubtree(0);
+      foreach(var subtree in root.Subtrees.OfType<DefunTreeNode>()) {
+        if(subtree.FunctionName == functionName) return subtree.GetSubtree(0);
       }
 
@@ -209,4 +209,8 @@
     }
 
+    private bool IsBinFactor(ISymbolicExpressionTreeNode node) {
+      return node is BinaryFactorVariableTreeNode;
+    }
+
     private bool IsConstant(ISymbolicExpressionTreeNode node) {
       return node.Symbol is Constant;
@@ -230,49 +234,49 @@
     /// <returns></returns>
     public ISymbolicExpressionTreeNode GetSimplifiedTree(ISymbolicExpressionTreeNode original) {
-      if (IsConstant(original) || IsVariableBase(original)) {
+      if(IsConstant(original) || IsVariableBase(original)) {
         return (ISymbolicExpressionTreeNode)original.Clone();
-      } else if (IsAddition(original)) {
+      } else if(IsAddition(original)) {
         return SimplifyAddition(original);
-      } else if (IsSubtraction(original)) {
+      } else if(IsSubtraction(original)) {
         return SimplifySubtraction(original);
-      } else if (IsMultiplication(original)) {
+      } else if(IsMultiplication(original)) {
         return SimplifyMultiplication(original);
-      } else if (IsDivision(original)) {
+      } else if(IsDivision(original)) {
         return SimplifyDivision(original);
-      } else if (IsAverage(original)) {
+      } else if(IsAverage(original)) {
         return SimplifyAverage(original);
-      } else if (IsLog(original)) {
+      } else if(IsLog(original)) {
         return SimplifyLog(original);
-      } else if (IsExp(original)) {
+      } else if(IsExp(original)) {
         return SimplifyExp(original);
-      } else if (IsSquare(original)) {
+      } else if(IsSquare(original)) {
         return SimplifySquare(original);
-      } else if (IsSquareRoot(original)) {
+      } else if(IsSquareRoot(original)) {
         return SimplifySquareRoot(original);
-      } else if (IsPower(original)) {
+      } else if(IsPower(original)) {
         return SimplifyPower(original);
-      } else if (IsRoot(original)) {
+      } else if(IsRoot(original)) {
         return SimplifyRoot(original);
-      } else if (IsSine(original)) {
+      } else if(IsSine(original)) {
         return SimplifySine(original);
-      } else if (IsCosine(original)) {
+      } else if(IsCosine(original)) {
         return SimplifyCosine(original);
-      } else if (IsTangent(original)) {
+      } else if(IsTangent(original)) {
         return SimplifyTangent(original);
-      } else if (IsIfThenElse(original)) {
+      } else if(IsIfThenElse(original)) {
         return SimplifyIfThenElse(original);
-      } else if (IsGreaterThan(original)) {
+      } else if(IsGreaterThan(original)) {
         return SimplifyGreaterThan(original);
-      } else if (IsLessThan(original)) {
+      } else if(IsLessThan(original)) {
         return SimplifyLessThan(original);
-      } else if (IsAnd(original)) {
+      } else if(IsAnd(original)) {
         return SimplifyAnd(original);
-      } else if (IsOr(original)) {
+      } else if(IsOr(original)) {
         return SimplifyOr(original);
-      } else if (IsNot(original)) {
+      } else if(IsNot(original)) {
         return SimplifyNot(original);
-      } else if (IsTimeLag(original)) {
+      } else if(IsTimeLag(original)) {
         return SimplifyTimeLag(original);
-      } else if (IsIntegral(original)) {
+      } else if(IsIntegral(original)) {
         return SimplifyIntegral(original);
       } else {
@@ -286,15 +290,15 @@
       // can't simplify this function but simplify all subtrees 
       List<ISymbolicExpressionTreeNode> subtrees = new List<ISymbolicExpressionTreeNode>(original.Subtrees);
-      while (original.Subtrees.Count() > 0) original.RemoveSubtree(0);
+      while(original.Subtrees.Count() > 0) original.RemoveSubtree(0);
       var clone = (SymbolicExpressionTreeNode)original.Clone();
       List<ISymbolicExpressionTreeNode> simplifiedSubtrees = new List<ISymbolicExpressionTreeNode>();
-      foreach (var subtree in subtrees) {
+      foreach(var subtree in subtrees) {
         simplifiedSubtrees.Add(GetSimplifiedTree(subtree));
         original.AddSubtree(subtree);
       }
-      foreach (var simplifiedSubtree in simplifiedSubtrees) {
+      foreach(var simplifiedSubtree in simplifiedSubtrees) {
         clone.AddSubtree(simplifiedSubtree);
       }
-      if (simplifiedSubtrees.TrueForAll(t => IsConstant(t))) {
+      if(simplifiedSubtrees.TrueForAll(t => IsConstant(t))) {
         SimplifyConstantExpression(clone);
       }
@@ -308,5 +312,5 @@
 
     private ISymbolicExpressionTreeNode SimplifyAverage(ISymbolicExpressionTreeNode original) {
-      if (original.Subtrees.Count() == 1) {
+      if(original.Subtrees.Count() == 1) {
         return GetSimplifiedTree(original.GetSubtree(0));
       } else {
@@ -321,5 +325,5 @@
 
     private ISymbolicExpressionTreeNode SimplifyDivision(ISymbolicExpressionTreeNode original) {
-      if (original.Subtrees.Count() == 1) {
+      if(original.Subtrees.Count() == 1) {
         return Invert(GetSimplifiedTree(original.GetSubtree(0)));
       } else {
@@ -336,5 +340,5 @@
 
     private ISymbolicExpressionTreeNode SimplifyMultiplication(ISymbolicExpressionTreeNode original) {
-      if (original.Subtrees.Count() == 1) {
+      if(original.Subtrees.Count() == 1) {
         return GetSimplifiedTree(original.GetSubtree(0));
       } else {
@@ -346,5 +350,5 @@
 
     private ISymbolicExpressionTreeNode SimplifySubtraction(ISymbolicExpressionTreeNode original) {
-      if (original.Subtrees.Count() == 1) {
+      if(original.Subtrees.Count() == 1) {
         return Negate(GetSimplifiedTree(original.GetSubtree(0)));
       } else {
@@ -358,5 +362,5 @@
 
     private ISymbolicExpressionTreeNode SimplifyAddition(ISymbolicExpressionTreeNode original) {
-      if (original.Subtrees.Count() == 1) {
+      if(original.Subtrees.Count() == 1) {
         return GetSimplifiedTree(original.GetSubtree(0));
       } else {
@@ -437,5 +441,5 @@
       var laggedTreeNode = original as ILaggedTreeNode;
       var simplifiedSubtree = GetSimplifiedTree(original.GetSubtree(0));
-      if (!ContainsVariableCondition(simplifiedSubtree)) {
+      if(!ContainsVariableCondition(simplifiedSubtree)) {
         return AddLagToDynamicNodes(simplifiedSubtree, laggedTreeNode.Lag);
       } else {
@@ -447,5 +451,5 @@
       var laggedTreeNode = original as ILaggedTreeNode;
       var simplifiedSubtree = GetSimplifiedTree(original.GetSubtree(0));
-      if (IsConstant(simplifiedSubtree)) {
+      if(IsConstant(simplifiedSubtree)) {
         return GetSimplifiedTree(MakeProduct(simplifiedSubtree, MakeConstant(-laggedTreeNode.Lag)));
       } else {
@@ -459,6 +463,6 @@
 
     private ISymbolicExpressionTreeNode MakeTimeLag(ISymbolicExpressionTreeNode subtree, int lag) {
-      if (lag == 0) return subtree;
-      if (IsConstant(subtree)) return subtree;
+      if(lag == 0) return subtree;
+      if(IsConstant(subtree)) return subtree;
       var lagNode = (LaggedTreeNode)timeLagSymbol.CreateTreeNode();
       lagNode.Lag = lag;
@@ -468,6 +472,6 @@
 
     private ISymbolicExpressionTreeNode MakeIntegral(ISymbolicExpressionTreeNode subtree, int lag) {
-      if (lag == 0) return subtree;
-      else if (lag == -1 || lag == 1) {
+      if(lag == 0) return subtree;
+      else if(lag == -1 || lag == 1) {
         return MakeSum(subtree, AddLagToDynamicNodes((ISymbolicExpressionTreeNode)subtree.Clone(), lag));
       } else {
@@ -480,11 +484,11 @@
 
     private ISymbolicExpressionTreeNode MakeNot(ISymbolicExpressionTreeNode t) {
-      if (IsConstant(t)) {
+      if(IsConstant(t)) {
         var constNode = t as ConstantTreeNode;
-        if (constNode.Value > 0) return MakeConstant(-1.0);
+        if(constNode.Value > 0) return MakeConstant(-1.0);
         else return MakeConstant(1.0);
-      } else if (IsNot(t)) {
+      } else if(IsNot(t)) {
         return t.GetSubtree(0);
-      } else if (!IsBoolean(t)) {
+      } else if(!IsBoolean(t)) {
         var gtNode = gtSymbol.CreateTreeNode();
         gtNode.AddSubtree(t);
@@ -501,17 +505,17 @@
 
     private ISymbolicExpressionTreeNode MakeOr(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
-      if (IsConstant(a) && IsConstant(b)) {
+      if(IsConstant(a) && IsConstant(b)) {
         var constA = a as ConstantTreeNode;
         var constB = b as ConstantTreeNode;
-        if (constA.Value > 0.0 || constB.Value > 0.0) {
+        if(constA.Value > 0.0 || constB.Value > 0.0) {
           return MakeConstant(1.0);
         } else {
           return MakeConstant(-1.0);
         }
-      } else if (IsConstant(a)) {
+      } else if(IsConstant(a)) {
         return MakeOr(b, a);
-      } else if (IsConstant(b)) {
+      } else if(IsConstant(b)) {
         var constT = b as ConstantTreeNode;
-        if (constT.Value > 0.0) {
+        if(constT.Value > 0.0) {
           // boolean expression is necessarily true
           return MakeConstant(1.0);
@@ -531,17 +535,17 @@
 
     private ISymbolicExpressionTreeNode MakeAnd(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
-      if (IsConstant(a) && IsConstant(b)) {
+      if(IsConstant(a) && IsConstant(b)) {
         var constA = a as ConstantTreeNode;
         var constB = b as ConstantTreeNode;
-        if (constA.Value > 0.0 && constB.Value > 0.0) {
+        if(constA.Value > 0.0 && constB.Value > 0.0) {
           return MakeConstant(1.0);
         } else {
           return MakeConstant(-1.0);
         }
-      } else if (IsConstant(a)) {
+      } else if(IsConstant(a)) {
         return MakeAnd(b, a);
-      } else if (IsConstant(b)) {
+      } else if(IsConstant(b)) {
         var constB = b as ConstantTreeNode;
-        if (constB.Value > 0.0) {
+        if(constB.Value > 0.0) {
           // the constant value has no effect on the result of the boolean condition so we can drop the constant term
           var andNode = andSymbol.CreateTreeNode();
@@ -562,8 +566,8 @@
     private ISymbolicExpressionTreeNode MakeLessThan(ISymbolicExpressionTreeNode leftSide,
       ISymbolicExpressionTreeNode rightSide) {
-      if (IsConstant(leftSide) && IsConstant(rightSide)) {
+      if(IsConstant(leftSide) && IsConstant(rightSide)) {
         var lsConst = leftSide as ConstantTreeNode;
         var rsConst = rightSide as ConstantTreeNode;
-        if (lsConst.Value < rsConst.Value) return MakeConstant(1.0);
+        if(lsConst.Value < rsConst.Value) return MakeConstant(1.0);
         else return MakeConstant(-1.0);
       } else {
@@ -577,8 +581,8 @@
     private ISymbolicExpressionTreeNode MakeGreaterThan(ISymbolicExpressionTreeNode leftSide,
       ISymbolicExpressionTreeNode rightSide) {
-      if (IsConstant(leftSide) && IsConstant(rightSide)) {
+      if(IsConstant(leftSide) && IsConstant(rightSide)) {
         var lsConst = leftSide as ConstantTreeNode;
         var rsConst = rightSide as ConstantTreeNode;
-        if (lsConst.Value > rsConst.Value) return MakeConstant(1.0);
+        if(lsConst.Value > rsConst.Value) return MakeConstant(1.0);
         else return MakeConstant(-1.0);
       } else {
@@ -592,11 +596,11 @@
     private ISymbolicExpressionTreeNode MakeIfThenElse(ISymbolicExpressionTreeNode condition,
       ISymbolicExpressionTreeNode trueBranch, ISymbolicExpressionTreeNode falseBranch) {
-      if (IsConstant(condition)) {
+      if(IsConstant(condition)) {
         var constT = condition as ConstantTreeNode;
-        if (constT.Value > 0.0) return trueBranch;
+        if(constT.Value > 0.0) return trueBranch;
         else return falseBranch;
       } else {
         var ifNode = ifThenElseSymbol.CreateTreeNode();
-        if (IsBoolean(condition)) {
+        if(IsBoolean(condition)) {
           ifNode.AddSubtree(condition);
         } else {
@@ -613,7 +617,13 @@
 
     private ISymbolicExpressionTreeNode MakeSine(ISymbolicExpressionTreeNode node) {
-      if (IsConstant(node)) {
+      if(IsConstant(node)) {
         var constT = node as ConstantTreeNode;
         return MakeConstant(Math.Sin(constT.Value));
+      } else if(IsFactor(node)) {
+        var factor = node as FactorVariableTreeNode;
+        return MakeFactor(factor.Symbol, factor.VariableName, factor.Weights.Select(Math.Sin));
+      } else if(IsBinFactor(node)) {
+        var binFactor = node as BinaryFactorVariableTreeNode;
+        return MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Sin(binFactor.Weight));
       } else {
         var sineNode = sineSymbol.CreateTreeNode();
@@ -624,7 +634,13 @@
 
     private ISymbolicExpressionTreeNode MakeTangent(ISymbolicExpressionTreeNode node) {
-      if (IsConstant(node)) {
+      if(IsConstant(node)) {
         var constT = node as ConstantTreeNode;
         return MakeConstant(Math.Tan(constT.Value));
+      } else if(IsFactor(node)) {
+        var factor = node as FactorVariableTreeNode;
+        return MakeFactor(factor.Symbol, factor.VariableName, factor.Weights.Select(Math.Tan));
+      } else if(IsBinFactor(node)) {
+        var binFactor = node as BinaryFactorVariableTreeNode;
+        return MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Tan(binFactor.Weight));
       } else {
         var tanNode = tanSymbol.CreateTreeNode();
@@ -635,7 +651,13 @@
 
     private ISymbolicExpressionTreeNode MakeCosine(ISymbolicExpressionTreeNode node) {
-      if (IsConstant(node)) {
+      if(IsConstant(node)) {
         var constT = node as ConstantTreeNode;
         return MakeConstant(Math.Cos(constT.Value));
+      } else if(IsFactor(node)) {
+        var factor = node as FactorVariableTreeNode;
+        return MakeFactor(factor.Symbol, factor.VariableName, factor.Weights.Select(Math.Cos));
+      } else if(IsBinFactor(node)) {
+        var binFactor = node as BinaryFactorVariableTreeNode;
+        return MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Cos(binFactor.Weight));
       } else {
         var cosNode = cosineSymbol.CreateTreeNode();
@@ -646,15 +668,18 @@
 
     private ISymbolicExpressionTreeNode MakeExp(ISymbolicExpressionTreeNode node) {
-      if (IsConstant(node)) {
+      if(IsConstant(node)) {
         var constT = node as ConstantTreeNode;
         return MakeConstant(Math.Exp(constT.Value));
-      } else if (IsFactor(node)) {
+      } else if(IsFactor(node)) {
         var factNode = node as FactorVariableTreeNode;
         return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Exp(w)));
-      } else if (IsLog(node)) {
+      } else if(IsBinFactor(node)) {
+        var binFactor = node as BinaryFactorVariableTreeNode;
+        return MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Exp(binFactor.Weight));
+      } else if(IsLog(node)) {
         return node.GetSubtree(0);
-      } else if (IsAddition(node)) {
+      } else if(IsAddition(node)) {
         return node.Subtrees.Select(s => MakeExp(s)).Aggregate((s, t) => MakeProduct(s, t));
-      } else if (IsSubtraction(node)) {
+      } else if(IsSubtraction(node)) {
         return node.Subtrees.Select(s => MakeExp(s)).Aggregate((s, t) => MakeProduct(s, Negate(t)));
       } else {
@@ -664,13 +689,36 @@
       }
     }
+    private ISymbolicExpressionTreeNode MakeLog(ISymbolicExpressionTreeNode node) {
+      if(IsConstant(node)) {
+        var constT = node as ConstantTreeNode;
+        return MakeConstant(Math.Log(constT.Value));
+      } else if(IsFactor(node)) {
+        var factNode = node as FactorVariableTreeNode;
+        return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Log(w)));
+      } else if(IsBinFactor(node)) {
+        var binFactor = node as BinaryFactorVariableTreeNode;
+        return MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Log(binFactor.Weight));
+      } else if(IsExp(node)) {
+        return node.GetSubtree(0);
+      } else if(IsSquareRoot(node)) {
+        return MakeFraction(MakeLog(node.GetSubtree(0)), MakeConstant(2.0));
+      } else {
+        var logNode = logSymbol.CreateTreeNode();
+        logNode.AddSubtree(node);
+        return logNode;
+      }
+    }
 
     private ISymbolicExpressionTreeNode MakeSquare(ISymbolicExpressionTreeNode node) {
-      if (IsConstant(node)) {
+      if(IsConstant(node)) {
         var constT = node as ConstantTreeNode;
         return MakeConstant(constT.Value * constT.Value);
-      } else if (IsFactor(node)) {
+      } else if(IsFactor(node)) {
         var factNode = node as FactorVariableTreeNode;
         return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => w * w));
-      } else if (IsSquareRoot(node)) {
+      } else if(IsBinFactor(node)) {
+        var binFactor = node as BinaryFactorVariableTreeNode;
+        return MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, binFactor.Weight * binFactor.Weight);
+      } else if(IsSquareRoot(node)) {
         return node.GetSubtree(0);
       } else {
@@ -682,11 +730,14 @@
 
     private ISymbolicExpressionTreeNode MakeSquareRoot(ISymbolicExpressionTreeNode node) {
-      if (IsConstant(node)) {
+      if(IsConstant(node)) {
         var constT = node as ConstantTreeNode;
         return MakeConstant(Math.Sqrt(constT.Value));
-      } else if (IsFactor(node)) {
+      } else if(IsFactor(node)) {
         var factNode = node as FactorVariableTreeNode;
         return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Sqrt(w)));
-      } else if (IsSquare(node)) {
+      } else if(IsBinFactor(node)) {
+        var binFactor = node as BinaryFactorVariableTreeNode;
+        return MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Sqrt(binFactor.Weight));
+      } else if(IsSquare(node)) {
         return node.GetSubtree(0);
       } else {
@@ -697,50 +748,40 @@
     }
 
-    private ISymbolicExpressionTreeNode MakeLog(ISymbolicExpressionTreeNode node) {
-      if (IsConstant(node)) {
-        var constT = node as ConstantTreeNode;
-        return MakeConstant(Math.Log(constT.Value));
-      } else if (IsFactor(node)) {
-        var factNode = node as FactorVariableTreeNode;
-        return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Log(w)));
-      } else if (IsExp(node)) {
-        return node.GetSubtree(0);
-      } else if (IsSquareRoot(node)) {
-        return MakeFraction(MakeLog(node.GetSubtree(0)), MakeConstant(2.0));
-      } else {
-        var logNode = logSymbol.CreateTreeNode();
-        logNode.AddSubtree(node);
-        return logNode;
-      }
-    }
-
     private ISymbolicExpressionTreeNode MakeRoot(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
-      if (IsConstant(a) && IsConstant(b)) {
+      if(IsConstant(a) && IsConstant(b)) {
         var constA = a as ConstantTreeNode;
         var constB = b as ConstantTreeNode;
         return MakeConstant(Math.Pow(constA.Value, 1.0 / Math.Round(constB.Value)));
-      } else if (IsFactor(a) && IsConstant(b)) {
+      } else if(IsFactor(a) && IsConstant(b)) {
         var factNode = a as FactorVariableTreeNode;
         var constNode = b as ConstantTreeNode;
         return MakeFactor(factNode.Symbol, factNode.VariableName,
           factNode.Weights.Select(w => Math.Pow(w, 1.0 / Math.Round(constNode.Value))));
-      } else if (IsConstant(a) && IsFactor(b)) {
+      } else if(IsBinFactor(a) && IsConstant(b)) {
+        var binFactor = a as BinaryFactorVariableTreeNode;
+        var constNode = b as ConstantTreeNode;
+        return MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Pow(binFactor.Weight, 1.0 / Math.Round(constNode.Value)));
+      } else if(IsConstant(a) && IsFactor(b)) {
         var constNode = a as ConstantTreeNode;
         var factNode = b as FactorVariableTreeNode;
         return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Pow(constNode.Value, 1.0 / Math.Round(w))));
-      } else if (IsFactor(a) && IsFactor(b) && AreSameVariable(a, b)) {
+      } else if(IsConstant(a) && IsBinFactor(b)) {
+        var constNode = a as ConstantTreeNode;
+        var factNode = b as BinaryFactorVariableTreeNode;
+        return MakeBinFactor(factNode.Symbol, factNode.VariableName, factNode.VariableValue, Math.Pow(constNode.Value, 1.0 / Math.Round(factNode.Weight)));
+      } else if(IsFactor(a) && IsFactor(b) && AreSameTypeAndVariable(a, b)) {
         var node0 = a as FactorVariableTreeNode;
         var node1 = b as FactorVariableTreeNode;
         return MakeFactor(node0.Symbol, node0.VariableName, node0.Weights.Zip(node1.Weights, (u, v) => Math.Pow(u, 1.0 / Math.Round(v))));
-      } else if (IsConstant(b)) {
+      } else if(IsConstant(b)) {
         var constB = b as ConstantTreeNode;
         var constBValue = Math.Round(constB.Value);
-        if (constBValue.IsAlmost(1.0)) {
+        if(constBValue.IsAlmost(1.0)) {
           return a;
-        } else if (constBValue.IsAlmost(0.0)) {
+        } else if(constBValue.IsAlmost(0.0)) {
           return MakeConstant(1.0);
-        } else if (constBValue.IsAlmost(-1.0)) {
+        } else if(constBValue.IsAlmost(-1.0)) {
           return MakeFraction(MakeConstant(1.0), a);
-        } else if (constBValue < 0) {
+        } else if(constBValue < 0) {
           var rootNode = rootSymbol.CreateTreeNode();
           rootNode.AddSubtree(a);
@@ -763,30 +804,38 @@
 
     private ISymbolicExpressionTreeNode MakePower(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
-      if (IsConstant(a) && IsConstant(b)) {
+      if(IsConstant(a) && IsConstant(b)) {
         var constA = a as ConstantTreeNode;
         var constB = b as ConstantTreeNode;
         return MakeConstant(Math.Pow(constA.Value, Math.Round(constB.Value)));
-      } else if (IsFactor(a) && IsConstant(b)) {
+      } else if(IsFactor(a) && IsConstant(b)) {
         var factNode = a as FactorVariableTreeNode;
         var constNode = b as ConstantTreeNode;
         return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Pow(w, Math.Round(constNode.Value))));
-      } else if (IsConstant(a) && IsFactor(b)) {
+      } else if(IsBinFactor(a) && IsConstant(b)) {
+        var binFactor = a as BinaryFactorVariableTreeNode;
+        var constNode = b as ConstantTreeNode;
+        return MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Pow(binFactor.Weight, Math.Round(constNode.Value)));
+      } else if(IsConstant(a) && IsFactor(b)) {
         var constNode = a as ConstantTreeNode;
         var factNode = b as FactorVariableTreeNode;
         return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Pow(constNode.Value, Math.Round(w))));
-      } else if (IsFactor(a) && IsFactor(b) && AreSameVariable(a, b)) {
+      } else if(IsConstant(a) && IsBinFactor(b)) {
+        var constNode = a as ConstantTreeNode;
+        var factNode = b as BinaryFactorVariableTreeNode;
+        return MakeBinFactor(factNode.Symbol, factNode.VariableName, factNode.VariableValue, Math.Pow(constNode.Value, Math.Round(factNode.Weight)));
+      } else if(IsFactor(a) && IsFactor(b) && AreSameTypeAndVariable(a, b)) {
         var node0 = a as FactorVariableTreeNode;
         var node1 = b as FactorVariableTreeNode;
         return MakeFactor(node0.Symbol, node0.VariableName, node0.Weights.Zip(node1.Weights, (u, v) => Math.Pow(u, Math.Round(v))));
-      } else if (IsConstant(b)) {
+      } else if(IsConstant(b)) {
         var constB = b as ConstantTreeNode;
         double exponent = Math.Round(constB.Value);
-        if (exponent.IsAlmost(0.0)) {
+        if(exponent.IsAlmost(0.0)) {
           return MakeConstant(1.0);
-        } else if (exponent.IsAlmost(1.0)) {
+        } else if(exponent.IsAlmost(1.0)) {
           return a;
-        } else if (exponent.IsAlmost(-1.0)) {
+        } else if(exponent.IsAlmost(-1.0)) {
           return MakeFraction(MakeConstant(1.0), a);
-        } else if (exponent < 0) {
+        } else if(exponent < 0) {
           var powNode = powSymbol.CreateTreeNode();
           powNode.AddSubtree(a);
@@ -810,46 +859,50 @@
     // MakeFraction, MakeProduct and MakeSum take two already simplified trees and create a new simplified tree
     private ISymbolicExpressionTreeNode MakeFraction(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
-      if (IsConstant(a) && IsConstant(b)) {
+      if(IsConstant(a) && IsConstant(b)) {
         // fold constants
         return MakeConstant(((ConstantTreeNode)a).Value / ((ConstantTreeNode)b).Value);
-      } else if ((IsConstant(a) && !((ConstantTreeNode)a).Value.IsAlmost(1.0))) {
+      } else if((IsConstant(a) && !((ConstantTreeNode)a).Value.IsAlmost(1.0))) {
         return MakeFraction(MakeConstant(1.0), MakeProduct(b, Invert(a)));
-      } else if (IsVariableBase(a) && IsConstant(b)) {
+      } else if(IsVariableBase(a) && IsConstant(b)) {
         // merge constant values into variable weights
         var constB = ((ConstantTreeNode)b).Value;
         ((VariableTreeNodeBase)a).Weight /= constB;
         return a;
-      } else if (IsFactor(a) && IsConstant(b)) {
+      } else if(IsFactor(a) && IsConstant(b)) {
         var factNode = a as FactorVariableTreeNode;
         var constNode = b as ConstantTreeNode;
         return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => w / constNode.Value));
-      } else if (IsFactor(a) && IsFactor(b) && AreSameVariable(a, b)) {
+      } else if(IsBinFactor(a) && IsConstant(b)) {
+        var factNode = a as BinaryFactorVariableTreeNode;
+        var constNode = b as ConstantTreeNode;
+        return MakeBinFactor(factNode.Symbol, factNode.VariableName, factNode.VariableValue, factNode.Weight / constNode.Value);
+      } else if(IsFactor(a) && IsFactor(b) && AreSameTypeAndVariable(a, b)) {
         var node0 = a as FactorVariableTreeNode;
         var node1 = b as FactorVariableTreeNode;
         return MakeFactor(node0.Symbol, node0.VariableName, node0.Weights.Zip(node1.Weights, (u, v) => u / v));
-      } else if (IsFactor(a)) {
+      } else if(IsFactor(a)) {
         return MakeFraction(MakeConstant(1.0), MakeProduct(b, Invert(a)));
-      } else if (IsVariableBase(a) && IsVariableBase(b) && AreSameVariable(a, b)) {
-        // cancel variables
+      } else if(IsVariableBase(a) && IsVariableBase(b) && AreSameTypeAndVariable(a, b) && !IsBinFactor(b)) {
+        // cancel variables (not allowed for bin factors because of division by zero)
         var aVar = a as VariableTreeNode;
         var bVar = b as VariableTreeNode;
         return MakeConstant(aVar.Weight / bVar.Weight);
-      } else if (IsAddition(a) && IsConstant(b)) {
+      } else if(IsAddition(a) && IsConstant(b)) {
         return a.Subtrees
           .Select(x => GetSimplifiedTree(x))
           .Select(x => MakeFraction(x, b))
           .Aggregate((c, d) => MakeSum(c, d));
-      } else if (IsMultiplication(a) && IsConstant(b)) {
+      } else if(IsMultiplication(a) && IsConstant(b)) {
         return MakeProduct(a, Invert(b));
-      } else if (IsDivision(a) && IsConstant(b)) {
+      } else if(IsDivision(a) && IsConstant(b)) {
         // (a1 / a2) / c => (a1 / (a2 * c))
         return MakeFraction(a.GetSubtree(0), MakeProduct(a.GetSubtree(1), b));
-      } else if (IsDivision(a) && IsDivision(b)) {
+      } else if(IsDivision(a) && IsDivision(b)) {
         // (a1 / a2) / (b1 / b2) => 
         return MakeFraction(MakeProduct(a.GetSubtree(0), b.GetSubtree(1)), MakeProduct(a.GetSubtree(1), b.GetSubtree(0)));
-      } else if (IsDivision(a)) {
+      } else if(IsDivision(a)) {
         // (a1 / a2) / b => (a1 / (a2 * b))
         return MakeFraction(a.GetSubtree(0), MakeProduct(a.GetSubtree(1), b));
-      } else if (IsDivision(b)) {
+      } else if(IsDivision(b)) {
         // a / (b1 / b2) => (a * b2) / b1
         return MakeFraction(MakeProduct(a, b.GetSubtree(1)), b.GetSubtree(0));
@@ -863,32 +916,32 @@
 
     private ISymbolicExpressionTreeNode MakeSum(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
-      if (IsConstant(a) && IsConstant(b)) {
+      if(IsConstant(a) && IsConstant(b)) {
         // fold constants
         ((ConstantTreeNode)a).Value += ((ConstantTreeNode)b).Value;
         return a;
-      } else if (IsConstant(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)) {
+      } else if(IsConstant(b) && ((ConstantTreeNode)b).Value.IsAlmost(0.0)) {
         // x + 0 => x
         return a;
-      } else if (IsFactor(a) && IsConstant(b)) {
+      } else if(IsFactor(a) && IsConstant(b)) {
         var factNode = a as FactorVariableTreeNode;
         var constNode = b as ConstantTreeNode;
         return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select((w) => w + constNode.Value));
-      } else if (IsFactor(a) && IsFactor(b) && AreSameVariable(a, b)) {
+      } else if(IsFactor(a) && IsFactor(b) && AreSameTypeAndVariable(a, b)) {
         var node0 = a as FactorVariableTreeNode;
         var node1 = b as FactorVariableTreeNode;
         return MakeFactor(node0.Symbol, node0.VariableName, node0.Weights.Zip(node1.Weights, (u, v) => u + v));
-      } else if (IsAddition(a) && IsAddition(b)) {
+      } else if(IsAddition(a) && IsAddition(b)) {
         // merge additions
         var add = addSymbol.CreateTreeNode();
         // add all sub trees except for the last
-        for (int i = 0; i < a.Subtrees.Count() - 1; i++) add.AddSubtree(a.GetSubtree(i));
-        for (int i = 0; i < b.Subtrees.Count() - 1; i++) add.AddSubtree(b.GetSubtree(i));
-        if (IsConstant(a.Subtrees.Last()) && IsConstant(b.Subtrees.Last())) {
+        for(int i = 0; i < a.Subtrees.Count() - 1; i++) add.AddSubtree(a.GetSubtree(i));
+        for(int i = 0; i < b.Subtrees.Count() - 1; i++) add.AddSubtree(b.GetSubtree(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())) {
+        } else if(IsConstant(a.Subtrees.Last())) {
           add.AddSubtree(b.Subtrees.Last());
           add.AddSubtree(a.Subtrees.Last());
@@ -898,17 +951,17 @@
         }
         MergeVariablesInSum(add);
-        if (add.Subtrees.Count() == 1) {
+        if(add.Subtrees.Count() == 1) {
           return add.GetSubtree(0);
         } else {
           return add;
         }
-      } else if (IsAddition(b)) {
+      } else if(IsAddition(b)) {
         return MakeSum(b, a);
-      } else if (IsAddition(a) && IsConstant(b)) {
+      } 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();
         // add all sub trees except for the last
-        for (int i = 0; i < a.Subtrees.Count() - 1; i++) add.AddSubtree(a.GetSubtree(i));
-        if (IsConstant(a.Subtrees.Last()))
+        for(int i = 0; i < a.Subtrees.Count() - 1; i++) add.AddSubtree(a.GetSubtree(i));
+        if(IsConstant(a.Subtrees.Last()))
           add.AddSubtree(MakeSum(a.Subtrees.Last(), b));
         else {
@@ -917,13 +970,13 @@
         }
         return add;
-      } else if (IsAddition(a)) {
+      } else if(IsAddition(a)) {
         // a is already an addition => append b
         var add = addSymbol.CreateTreeNode();
         add.AddSubtree(b);
-        foreach (var subtree in a.Subtrees) {
+        foreach(var subtree in a.Subtrees) {
           add.AddSubtree(subtree);
         }
         MergeVariablesInSum(add);
-        if (add.Subtrees.Count() == 1) {
+        if(add.Subtrees.Count() == 1) {
           return add.GetSubtree(0);
         } else {
@@ -935,5 +988,5 @@
         add.AddSubtree(b);
         MergeVariablesInSum(add);
-        if (add.Subtrees.Count() == 1) {
+        if(add.Subtrees.Count() == 1) {
           return add.GetSubtree(0);
         } else {
@@ -944,16 +997,10 @@
 
     // makes sure variable symbols in sums are combined
-    // possible improvement: combine sums of products where the products only reference the same variable
     private void MergeVariablesInSum(ISymbolicExpressionTreeNode sum) {
       var subtrees = new List<ISymbolicExpressionTreeNode>(sum.Subtrees);
-      while (sum.Subtrees.Any()) sum.RemoveSubtree(0);
+      while(sum.Subtrees.Any()) sum.RemoveSubtree(0);
       var groupedVarNodes = from node in subtrees.OfType<IVariableTreeNode>()
                             where node.SubtreeCount == 0
-                            // only consider terminal nodes
-                            let lag = (node is LaggedVariableTreeNode) ? ((LaggedVariableTreeNode)node).Lag : 0
-                            let cat =
-                              (node is BinaryFactorVariableTreeNode) ? ((BinaryFactorVariableTreeNode)node).VariableValue : string.Empty
-                            group node by node.VariableName + cat + lag
-        into g
+                            group node by GroupId(node) into g
                             select g;
       var constant = (from node in subtrees.OfType<ConstantTreeNode>()
@@ -961,19 +1008,19 @@
       var unchangedSubtrees = subtrees.Where(t => t.SubtreeCount > 0 || !(t is IVariableTreeNode) && !(t is ConstantTreeNode));
 
-      foreach (var variableNodeGroup in groupedVarNodes) {
+      foreach(var variableNodeGroup in groupedVarNodes) {
         var firstNode = variableNodeGroup.First();
-        if (firstNode is VariableTreeNodeBase) {
+        if(firstNode is VariableTreeNodeBase) {
           var representative = firstNode as VariableTreeNodeBase;
           var weightSum = variableNodeGroup.Cast<VariableTreeNodeBase>().Select(t => t.Weight).Sum();
           representative.Weight = weightSum;
           sum.AddSubtree(representative);
-        } else if (firstNode is FactorVariableTreeNode) {
+        } else if(firstNode is FactorVariableTreeNode) {
           var representative = firstNode as FactorVariableTreeNode;
-          foreach (var node in variableNodeGroup.Skip(1).Cast<FactorVariableTreeNode>()) {
-            for (int j = 0; j < representative.Weights.Length; j++) {
+          foreach(var node in variableNodeGroup.Skip(1).Cast<FactorVariableTreeNode>()) {
+            for(int j = 0; j < representative.Weights.Length; j++) {
               representative.Weights[j] += node.Weights[j];
             }
           }
-          for (int j = 0; j < representative.Weights.Length; j++) {
+          for(int j = 0; j < representative.Weights.Length; j++) {
             representative.Weights[j] += constant;
           }
@@ -981,58 +1028,85 @@
         }
       }
-      foreach (var unchangedSubtree in unchangedSubtrees)
+      foreach(var unchangedSubtree in unchangedSubtrees)
         sum.AddSubtree(unchangedSubtree);
-      if (!constant.IsAlmost(0.0)) {
+      if(!constant.IsAlmost(0.0)) {
         sum.AddSubtree(MakeConstant(constant));
       }
     }
 
+    // nodes referencing variables can be grouped if they have
+    private string GroupId(IVariableTreeNode node) {
+      var binaryFactorNode = node as BinaryFactorVariableTreeNode;
+      var factorNode = node as FactorVariableTreeNode;
+      var variableNode = node as VariableTreeNode;
+      var laggedVarNode = node as LaggedVariableTreeNode;
+      if(variableNode != null) {
+        return "var " + variableNode.VariableName;
+      } else if(binaryFactorNode != null) {
+        return "binfactor " + binaryFactorNode.VariableName + " " + binaryFactorNode.VariableValue;
+      } else if(factorNode != null) {
+        return "factor " + factorNode.VariableName;
+      } else if(laggedVarNode != null) {
+        return "lagged " + laggedVarNode.VariableName + " " + laggedVarNode.Lag;
+      } else {
+        throw new NotSupportedException();
+      }
+    }
+
 
     private ISymbolicExpressionTreeNode MakeProduct(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
-      if (IsConstant(a) && IsConstant(b)) {
+      if(IsConstant(a) && IsConstant(b)) {
         // fold constants
         ((ConstantTreeNode)a).Value *= ((ConstantTreeNode)b).Value;
         return a;
-      } else if (IsConstant(a)) {
+      } else if(IsConstant(a)) {
         // a * $ => $ * a
         return MakeProduct(b, a);
-      } else if (IsFactor(a) && IsFactor(b) && AreSameVariable(a, b)) {
+      } else if(IsFactor(a) && IsFactor(b) && AreSameTypeAndVariable(a, b)) {
         var node0 = a as FactorVariableTreeNode;
         var node1 = b as FactorVariableTreeNode;
         return MakeFactor(node0.Symbol, node0.VariableName, node0.Weights.Zip(node1.Weights, (u, v) => u * v));
-      } else if (IsFactor(a) && IsConstant(b)) {
+      } else if(IsBinFactor(a) && IsBinFactor(b) && AreSameTypeAndVariable(a, b)) {
+        var node0 = a as BinaryFactorVariableTreeNode;
+        var node1 = b as BinaryFactorVariableTreeNode;
+        return MakeBinFactor(node0.Symbol, node0.VariableName, node0.VariableValue, node0.Weight * node1.Weight);
+      } else if(IsFactor(a) && IsConstant(b)) {
         var node0 = a as FactorVariableTreeNode;
         var node1 = b as ConstantTreeNode;
         return MakeFactor(node0.Symbol, node0.VariableName, node0.Weights.Select(w => w * node1.Value));
-      } else if (IsConstant(b) && ((ConstantTreeNode)b).Value.IsAlmost(1.0)) {
+      } else if(IsBinFactor(a) && IsConstant(b)) {
+        var node0 = a as BinaryFactorVariableTreeNode;
+        var node1 = b as ConstantTreeNode;
+        return MakeBinFactor(node0.Symbol, node0.VariableName, node0.VariableValue, node0.Weight * node1.Value);
+      } else if(IsConstant(b) && ((ConstantTreeNode)b).Value.IsAlmost(1.0)) {
         // $ * 1.0 => $
         return a;
-      } else if (IsConstant(b) && IsVariableBase(a)) {
+      } else if(IsConstant(b) && IsVariableBase(a)) {
         // multiply constants into variables weights
         ((VariableTreeNodeBase)a).Weight *= ((ConstantTreeNode)b).Value;
         return a;
-      } else if (IsConstant(b) && IsAddition(a) ||
+      } else if(IsConstant(b) && IsAddition(a) ||
           IsFactor(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)) {
+      } else if(IsDivision(a) && IsDivision(b)) {
         // (a1 / a2) * (b1 / b2) => (a1 * b1) / (a2 * b2)
         return MakeFraction(MakeProduct(a.GetSubtree(0), b.GetSubtree(0)), MakeProduct(a.GetSubtree(1), b.GetSubtree(1)));
-      } else if (IsDivision(a)) {
+      } else if(IsDivision(a)) {
         // (a1 / a2) * b => (a1 * b) / a2
         return MakeFraction(MakeProduct(a.GetSubtree(0), b), a.GetSubtree(1));
-      } else if (IsDivision(b)) {
+      } else if(IsDivision(b)) {
         // a * (b1 / b2) => (b1 * a) / b2
         return MakeFraction(MakeProduct(b.GetSubtree(0), a), b.GetSubtree(1));
-      } else if (IsMultiplication(a) && IsMultiplication(b)) {
+      } 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.GetSubtree(i));
-        for (int i = 0; i < b.Subtrees.Count(); i++) mul.AddSubtree(b.GetSubtree(i));
+        for(int i = 0; i < a.Subtrees.Count(); i++) mul.AddSubtree(a.GetSubtree(i));
+        for(int i = 0; i < b.Subtrees.Count(); i++) mul.AddSubtree(b.GetSubtree(i));
         MergeVariablesAndConstantsInProduct(mul);
         return mul;
-      } else if (IsMultiplication(b)) {
+      } else if(IsMultiplication(b)) {
         return MakeProduct(b, a);
-      } else if (IsMultiplication(a)) {
+      } else if(IsMultiplication(a)) {
         // a is already an multiplication => append b
         a.AddSubtree(b);
@@ -1053,7 +1127,7 @@
 
     private bool ContainsVariableCondition(ISymbolicExpressionTreeNode node) {
-      if (node.Symbol is VariableCondition) return true;
-      foreach (var subtree in node.Subtrees)
-        if (ContainsVariableCondition(subtree)) return true;
+      if(node.Symbol is VariableCondition) return true;
+      foreach(var subtree in node.Subtrees)
+        if(ContainsVariableCondition(subtree)) return true;
       return false;
     }
@@ -1063,17 +1137,17 @@
       var variableNode = node as VariableTreeNode;
       var variableConditionNode = node as VariableConditionTreeNode;
-      if (laggedTreeNode != null)
+      if(laggedTreeNode != null)
         laggedTreeNode.Lag += lag;
-      else if (variableNode != null) {
+      else if(variableNode != null) {
         var laggedVariableNode = (LaggedVariableTreeNode)laggedVariableSymbol.CreateTreeNode();
         laggedVariableNode.Lag = lag;
         laggedVariableNode.VariableName = variableNode.VariableName;
         return laggedVariableNode;
-      } else if (variableConditionNode != null) {
+      } else if(variableConditionNode != null) {
         throw new NotSupportedException("Removal of time lags around variable condition symbols is not allowed.");
       }
       var subtrees = new List<ISymbolicExpressionTreeNode>(node.Subtrees);
-      while (node.SubtreeCount > 0) node.RemoveSubtree(0);
-      foreach (var subtree in subtrees) {
+      while(node.SubtreeCount > 0) node.RemoveSubtree(0);
+      foreach(var subtree in subtrees) {
         node.AddSubtree(AddLagToDynamicNodes(subtree, lag));
       }
@@ -1081,28 +1155,6 @@
     }
 
-    private bool AreSameVariable(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
-      var aLaggedVar = a as LaggedVariableTreeNode;
-      var bLaggedVar = b as LaggedVariableTreeNode;
-      if (aLaggedVar != null && bLaggedVar != null) {
-        return aLaggedVar.VariableName == bLaggedVar.VariableName &&
-               aLaggedVar.Lag == bLaggedVar.Lag;
-      }
-      var aVar = a as VariableTreeNode;
-      var bVar = b as VariableTreeNode;
-      if (aVar != null && bVar != null) {
-        return aVar.VariableName == bVar.VariableName;
-      }
-      var aFactor = a as FactorVariableTreeNode;
-      var bFactor = b as FactorVariableTreeNode;
-      if (aFactor != null && bFactor != null) {
-        return aFactor.VariableName == bFactor.VariableName;
-      }
-      var aBinFactor = a as BinaryFactorVariableTreeNode;
-      var bBinFactor = b as BinaryFactorVariableTreeNode;
-      if (aBinFactor != null && bBinFactor != null) {
-        return aBinFactor.VariableName == bBinFactor.VariableName &&
-               aBinFactor.VariableValue == bBinFactor.VariableValue;
-      }
-      return false;
+    private bool AreSameTypeAndVariable(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
+      return GroupId((IVariableTreeNode)a) == GroupId((IVariableTreeNode)b);
     }
 
@@ -1110,12 +1162,8 @@
     private void MergeVariablesAndConstantsInProduct(ISymbolicExpressionTreeNode prod) {
       var subtrees = new List<ISymbolicExpressionTreeNode>(prod.Subtrees);
-      while (prod.Subtrees.Any()) prod.RemoveSubtree(0);
+      while(prod.Subtrees.Any()) prod.RemoveSubtree(0);
       var groupedVarNodes = from node in subtrees.OfType<IVariableTreeNode>()
                             where node.SubtreeCount == 0
-                            let lag = (node is LaggedVariableTreeNode) ? ((LaggedVariableTreeNode)node).Lag : 0
-                            let cat =
-                              (node is BinaryFactorVariableTreeNode) ? ((BinaryFactorVariableTreeNode)node).VariableValue : string.Empty
-                            group node by node.VariableName + cat + lag
-        into g
+                            group node by GroupId(node) into g
                             orderby g.Count()
                             select g;
@@ -1131,12 +1179,12 @@
                               select tree;
 
-      foreach (var variableNodeGroup in groupedVarNodes) {
+      foreach(var variableNodeGroup in groupedVarNodes) {
         var firstNode = variableNodeGroup.First();
-        if (firstNode is VariableTreeNodeBase) {
+        if(firstNode is VariableTreeNodeBase) {
           var representative = (VariableTreeNodeBase)firstNode;
           representative.Weight = 1.0;
-          if (variableNodeGroup.Count() > 1) {
+          if(variableNodeGroup.Count() > 1) {
             var poly = mulSymbol.CreateTreeNode();
-            for (int p = 0; p < variableNodeGroup.Count(); p++) {
+            for(int p = 0; p < variableNodeGroup.Count(); p++) {
               poly.AddSubtree((ISymbolicExpressionTreeNode)representative.Clone());
             }
@@ -1145,12 +1193,12 @@
             prod.AddSubtree(representative);
           }
-        } else if (firstNode is FactorVariableTreeNode) {
+        } else if(firstNode is FactorVariableTreeNode) {
           var representative = (FactorVariableTreeNode)firstNode;
-          foreach (var node in variableNodeGroup.Skip(1).Cast<FactorVariableTreeNode>()) {
-            for (int j = 0; j < representative.Weights.Length; j++) {
+          foreach(var node in variableNodeGroup.Skip(1).Cast<FactorVariableTreeNode>()) {
+            for(int j = 0; j < representative.Weights.Length; j++) {
               representative.Weights[j] *= node.Weights[j];
             }
           }
-          for (int j = 0; j < representative.Weights.Length; j++) {
+          for(int j = 0; j < representative.Weights.Length; j++) {
             representative.Weights[j] *= constantProduct;
           }
@@ -1161,8 +1209,8 @@
       }
 
-      foreach (var unchangedSubtree in unchangedSubtrees)
+      foreach(var unchangedSubtree in unchangedSubtrees)
         prod.AddSubtree(unchangedSubtree);
 
-      if (!constantProduct.IsAlmost(1.0)) {
+      if(!constantProduct.IsAlmost(1.0)) {
         prod.AddSubtree(MakeConstant(constantProduct));
       }
@@ -1177,20 +1225,23 @@
     /// <returns>-x</returns>
     private ISymbolicExpressionTreeNode Negate(ISymbolicExpressionTreeNode x) {
-      if (IsConstant(x)) {
+      if(IsConstant(x)) {
         ((ConstantTreeNode)x).Value *= -1;
-      } else if (IsVariableBase(x)) {
+      } else if(IsVariableBase(x)) {
         var variableTree = (VariableTreeNodeBase)x;
         variableTree.Weight *= -1.0;
-      } else if (IsFactor(x)) {
+      } else if(IsFactor(x)) {
         var factorNode = (FactorVariableTreeNode)x;
-        for (int i = 0; i < factorNode.Weights.Length; i++) factorNode.Weights[i] *= -1;
-      } else if (IsAddition(x)) {
+        for(int i = 0; i < factorNode.Weights.Length; i++) factorNode.Weights[i] *= -1;
+      } else if(IsBinFactor(x)) {
+        var factorNode = (BinaryFactorVariableTreeNode)x;
+        factorNode.Weight *= -1;
+      } else if(IsAddition(x)) {
         // (x0 + x1 + .. + xn) * -1 => (-x0 + -x1 + .. + -xn)        
         var subtrees = new List<ISymbolicExpressionTreeNode>(x.Subtrees);
-        while (x.Subtrees.Any()) x.RemoveSubtree(0);
-        foreach (var subtree in subtrees) {
+        while(x.Subtrees.Any()) x.RemoveSubtree(0);
+        foreach(var subtree in subtrees) {
           x.AddSubtree(Negate(subtree));
         }
-      } else if (IsMultiplication(x) || IsDivision(x)) {
+      } else if(IsMultiplication(x) || IsDivision(x)) {
         // x0 * x1 * .. * xn * -1 => x0 * x1 * .. * -xn
         var lastSubTree = x.Subtrees.Last();
@@ -1211,11 +1262,11 @@
     /// <returns></returns>
     private ISymbolicExpressionTreeNode Invert(ISymbolicExpressionTreeNode x) {
-      if (IsConstant(x)) {
+      if(IsConstant(x)) {
         return MakeConstant(1.0 / ((ConstantTreeNode)x).Value);
-      } else if (IsFactor(x)) {
+      } else if(IsFactor(x)) {
         var factorNode = (FactorVariableTreeNode)x;
-        for (int i = 0; i < factorNode.Weights.Length; i++) factorNode.Weights[i] = 1.0 / factorNode.Weights[i];
+        for(int i = 0; i < factorNode.Weights.Length; i++) factorNode.Weights[i] = 1.0 / factorNode.Weights[i];
         return factorNode;
-      } else if (IsDivision(x)) {
+      } else if(IsDivision(x)) {
         return MakeFraction(x.GetSubtree(1), x.GetSubtree(0));
       } else {
@@ -1231,10 +1282,4 @@
     }
 
-    private ISymbolicExpressionTreeNode MakeVariable(double weight, string name) {
-      var tree = (VariableTreeNode)varSymbol.CreateTreeNode();
-      tree.Weight = weight;
-      tree.VariableName = name;
-      return tree;
-    }
     private ISymbolicExpressionTreeNode MakeFactor(FactorVariable sy, string variableName, IEnumerable<double> weights) {
       var tree = (FactorVariableTreeNode)sy.CreateTreeNode();
@@ -1243,4 +1288,11 @@
       return tree;
     }
+    private ISymbolicExpressionTreeNode MakeBinFactor(BinaryFactorVariable sy, string variableName, string variableValue, double weight) {
+      var tree = (BinaryFactorVariableTreeNode)sy.CreateTreeNode();
+      tree.VariableName = variableName;
+      tree.VariableValue = variableValue;
+      tree.Weight = weight;
+      return tree;
+    }
 
 
Index: branches/symbreg-factors-2650/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/BinaryFactorVariableTreeNode.cs
===================================================================
--- branches/symbreg-factors-2650/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/BinaryFactorVariableTreeNode.cs	(revision 14534)
+++ branches/symbreg-factors-2650/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/BinaryFactorVariableTreeNode.cs	(revision 14535)
@@ -26,5 +26,5 @@
 namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
   [StorableClass]
-  public class BinaryFactorVariableTreeNode : VariableTreeNodeBase {
+  public sealed class BinaryFactorVariableTreeNode : VariableTreeNodeBase {
     public new BinaryFactorVariable Symbol {
       get { return (BinaryFactorVariable)base.Symbol; }
Index: branches/symbreg-factors-2650/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/FactorVariableTreeNode.cs
===================================================================
--- branches/symbreg-factors-2650/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/FactorVariableTreeNode.cs	(revision 14534)
+++ branches/symbreg-factors-2650/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/FactorVariableTreeNode.cs	(revision 14535)
@@ -29,5 +29,5 @@
 namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
   [StorableClass]
-  public class FactorVariableTreeNode : SymbolicExpressionTreeTerminalNode, IVariableTreeNode {
+  public sealed class FactorVariableTreeNode : SymbolicExpressionTreeTerminalNode, IVariableTreeNode {
     public new FactorVariable Symbol {
       get { return (FactorVariable)base.Symbol; }
Index: branches/symbreg-factors-2650/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/VariableTreeNode.cs
===================================================================
--- branches/symbreg-factors-2650/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/VariableTreeNode.cs	(revision 14534)
+++ branches/symbreg-factors-2650/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/VariableTreeNode.cs	(revision 14535)
@@ -24,5 +24,5 @@
 namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
   [StorableClass]
-  public class VariableTreeNode : VariableTreeNodeBase {
+  public sealed class VariableTreeNode : VariableTreeNodeBase {
     public new Variable Symbol {
       get { return (Variable)base.Symbol; }
Index: branches/symbreg-factors-2650/HeuristicLab.Tests/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4/SymbolicDataAnalysisExpressionTreeSimplifierTest.cs
===================================================================
--- branches/symbreg-factors-2650/HeuristicLab.Tests/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4/SymbolicDataAnalysisExpressionTreeSimplifierTest.cs	(revision 14534)
+++ branches/symbreg-factors-2650/HeuristicLab.Tests/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4/SymbolicDataAnalysisExpressionTreeSimplifierTest.cs	(revision 14535)
@@ -161,5 +161,5 @@
       AssertEqualAfterSimplification("(* 2.0 (factor a 4.0 6.0))", "(factor a 8.0 12.0)");
       AssertEqualAfterSimplification("(* (factor a 4.0 6.0) 2.0)", "(factor a 8.0 12.0)");
-      AssertEqualAfterSimplification("(* (factor a 4.0 6.0) (variable 2.0 a))", "(* (factor a 4.0 6.0) (variable 2.0 a))");   // not possible
+      AssertEqualAfterSimplification("(* (factor a 4.0 6.0) (variable 2.0 a))", "(* (factor a 8.0 12.0) (variable 1.0 a))"); // not possible (a is used as factor and double variable)
       AssertEqualAfterSimplification(
         "(log (factor a 10.0 100.0))",
@@ -171,5 +171,5 @@
       AssertEqualAfterSimplification("(sqr (factor a 2.0 3.0))", "(factor a 4.0 9.0))");
       AssertEqualAfterSimplification("(root (factor a 8.0 27.0) 3)", "(factor a 2.0 3.0))");
-      AssertEqualAfterSimplification("(power (factor a 2.0 3.0) 3)", "(factor a 8.0 27.0))");
+      AssertEqualAfterSimplification("(pow (factor a 2.0 3.0) 3)", "(factor a 8.0 27.0))");
 
       AssertEqualAfterSimplification("(sin (factor a 1.0 2.0) )",
@@ -188,17 +188,36 @@
       AssertEqualAfterSimplification("(- (binfactor a val 1.0) (binfactor a val 2.0))", "(binfactor a val -1.0)");
       AssertEqualAfterSimplification("(* (binfactor a val 2.0) (binfactor a val 3.0))", "(binfactor a val 6.0)");
-      AssertEqualAfterSimplification("(/ (binfactor a val 6.0) (binfactor a val 3.0))", "(binfactor a val 2.0)");
-      AssertEqualAfterSimplification("(/ (binfactor a val 4.0))", "(binfactor a val 0.25)");
-
-      AssertEqualAfterSimplification("(+ 3.0 (binfactor a val 4.0 ))", "(binfactor a val 7.0 )");
-      AssertEqualAfterSimplification("(+ (binfactor a val 4.0 ) 3.0)", "(binfactor a val 7.0 )");
+      AssertEqualAfterSimplification("(/ (binfactor a val 6.0) (binfactor a val 3.0))", "(/ (binfactor a val 6.0) (binfactor a val 3.0))"); // not allowed! 0/0 for other values than 'val'
+      AssertEqualAfterSimplification("(/ (binfactor a val 4.0))", "(/ 1.0 (binfactor a val 4.0))"); // not allowed!
+
+      AssertEqualAfterSimplification("(+ 3.0 (binfactor a val 4.0 ))", "(+ (binfactor a val 4.0 ) 3.0))"); // not allowed
+      AssertEqualAfterSimplification("(- 3.0 (binfactor a val 4.0 ))", "(- 3.0 (binfactor a val 4.0 ))"); // not allowed
+      AssertEqualAfterSimplification("(+ (binfactor a val 4.0 ) 3.0)", "(+ (binfactor a val 4.0 ) 3.0)");  // not allowed
+      AssertEqualAfterSimplification("(- (binfactor a val 4.0 ) 3.0)", "(- (binfactor a val 4.0 ) 3.0)");  // not allowed
       AssertEqualAfterSimplification("(* 2.0 (binfactor a val 4.0))", "(binfactor a val 8.0 )");
       AssertEqualAfterSimplification("(* (binfactor a val 4.0) 2.0)", "(binfactor a val 8.0 )");
-
-      // TODO same set of functions as for factor symbols
+      AssertEqualAfterSimplification("(* (binfactor a val 4.0) (variable 2.0 a))", "(* (binfactor a val 8.0) (variable 1.0 a))");  // not possible (a is used as factor and double variable)
+      AssertEqualAfterSimplification("(log (binfactor a val 10.0))", "(log (binfactor a val 10.0))"); // not allowed
+      AssertEqualAfterSimplification("(exp (binfactor a val 3.0))", "(exp (binfactor a val 3.0))"); // not allowed
+      AssertEqualAfterSimplification("(sqrt (binfactor a val 16.0))", "(binfactor a val 4.0))"); // sqrt(0) = 0
+      AssertEqualAfterSimplification("(sqr (binfactor a val 3.0))", "(binfactor a val 9.0))"); // 0*0 = 0
+      AssertEqualAfterSimplification("(root (binfactor a val 27.0) 3)", "(binfactor a val 3.0))");
+      AssertEqualAfterSimplification("(pow (binfactor a val 3.0) 3)", "(binfactor a val 27.0))");
+
+      AssertEqualAfterSimplification("(sin (binfactor a val 2.0) )",
+        string.Format(CultureInfo.InvariantCulture, "(binfactor a val {0}))", Math.Sin(2.0))); // sin(0) = 0
+      AssertEqualAfterSimplification("(cos (binfactor a val 2.0) )", "(cos (binfactor a val 2.0) )"); // not allowed
+      AssertEqualAfterSimplification("(tan (binfactor a val 2.0) )",
+        string.Format(CultureInfo.InvariantCulture, "(binfactor a val {0}))", Math.Tan(2.0))); // tan(0) = 0
 
       // combination of factor and binfactor
-      // TODO: should we support this?
+      // TODO
       AssertEqualAfterSimplification("(+ (binfactor a x0 2.0) (factor a 2.0 3.0))", "(factor a 4.0 3.0)");
+      AssertEqualAfterSimplification("(* (binfactor a x1 2.0) (factor a 2.0 3.0))", "(binfactor a x1 4.0)"); // all other values have weight zero in binfactor
+      AssertEqualAfterSimplification("(/ (binfactor a x0 2.0) (factor a 2.0 3.0))", "(binfactor a x0 1.0)");
+      AssertEqualAfterSimplification("(/ (factor a 2.0 3.0) (binfactor a x0 2.0))",
+        string.Format(CultureInfo.InvariantCulture, "(factor a 1.0 {0})", 3.0 / 0.0));
+      AssertEqualAfterSimplification("(- (binfactor a x0 2.0) (factor a 2.0 3.0))", "(factor a 0.0 -3.0)");
+      AssertEqualAfterSimplification("(- (factor a 2.0 3.0) (binfactor a x0 2.0))", "(factor a 0.0 3.0)");
       #endregion
     }
