Index: /branches/HeuristicLab.BottomUpTreeDistance/HeuristicLab.BottomUpTreeDistance.sln
===================================================================
--- /branches/HeuristicLab.BottomUpTreeDistance/HeuristicLab.BottomUpTreeDistance.sln	(revision 11218)
+++ /branches/HeuristicLab.BottomUpTreeDistance/HeuristicLab.BottomUpTreeDistance.sln	(revision 11219)
@@ -10,4 +10,6 @@
 		Performance1.psess = Performance1.psess
 	EndProjectSection
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.Tests", "HeuristicLab.Tests\HeuristicLab.Tests.csproj", "{07C05C8F-0769-4607-96C6-D90A219F4C85}"
 EndProject
 Global
@@ -33,4 +35,12 @@
 		{3D28463F-EC96-4D82-AFEE-38BE91A0CA00}.Release|x86.ActiveCfg = Release|x86
 		{3D28463F-EC96-4D82-AFEE-38BE91A0CA00}.Release|x86.Build.0 = Release|x86
+		{07C05C8F-0769-4607-96C6-D90A219F4C85}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{07C05C8F-0769-4607-96C6-D90A219F4C85}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{07C05C8F-0769-4607-96C6-D90A219F4C85}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{07C05C8F-0769-4607-96C6-D90A219F4C85}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{07C05C8F-0769-4607-96C6-D90A219F4C85}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{07C05C8F-0769-4607-96C6-D90A219F4C85}.Release|Any CPU.Build.0 = Release|Any CPU
+		{07C05C8F-0769-4607-96C6-D90A219F4C85}.Release|x64.ActiveCfg = Release|Any CPU
+		{07C05C8F-0769-4607-96C6-D90A219F4C85}.Release|x86.ActiveCfg = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
Index: /branches/HeuristicLab.BottomUpTreeDistance/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4.csproj
===================================================================
--- /branches/HeuristicLab.BottomUpTreeDistance/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4.csproj	(revision 11218)
+++ /branches/HeuristicLab.BottomUpTreeDistance/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4.csproj	(revision 11219)
@@ -197,5 +197,4 @@
   </ItemGroup>
   <ItemGroup>
-    <Compile Include="Analyzers\SymbolicDataAnalysisPopulationDiversityAnalyzer.cs" />
     <Compile Include="Analyzers\SymbolicDataAnalysisSingleObjectivePruningAnalyzer.cs" />
     <Compile Include="Analyzers\SymbolicDataAnalysisSingleObjectiveValidationParetoBestSolutionAnalyzer.cs" />
@@ -219,5 +218,4 @@
     <Compile Include="DirectedGraph\Vertex.cs" />
     <Compile Include="Interfaces\IModelBacktransformator.cs" />
-    <Compile Include="Interfaces\ISymbolicExpressionTreeDistanceCalculator.cs" />
     <Compile Include="Matching\SymbolicExpressionTreeCanonicalSorter.cs" />
     <Compile Include="Matching\SymbolicExpressionTreeEqualityComparer.cs" />
@@ -226,5 +224,6 @@
     <Compile Include="Matching\SymbolicExpressionTreeNodeComparer.cs" />
     <Compile Include="Matching\SymbolicExpressionTreeNodeSimilarityComparer.cs" />
-    <Compile Include="SymbolicDataAnalysisExpressionTreeSimilarityCalculator.cs" />
+    <Compile Include="SimilarityCalculators\BottomUpSimilarityCalculator.cs" />
+    <Compile Include="SimilarityCalculators\MaxCommonSubtreeSimilarityCalculator.cs" />
     <Compile Include="SymbolicExpressionTreeBacktransformator.cs" />
     <Compile Include="SymbolicDataAnalysisExpressionPruningOperator.cs" />
@@ -325,6 +324,4 @@
     <Compile Include="Symbols\VariableTreeNode.cs" />
     <Compile Include="TransformationToSymbolicTreeMapper.cs" />
-    <Compile Include="TreeDistance\BottomUpTreeDistanceCalculator.cs" />
-    <Compile Include="TreeDistance\IsomorphicTreeDistanceCalculator.cs" />
     <None Include="HeuristicLab.snk" />
     <None Include="Plugin.cs.frame" />
Index: anches/HeuristicLab.BottomUpTreeDistance/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interfaces/ISymbolicExpressionTreeDistanceCalculator.cs
===================================================================
--- /branches/HeuristicLab.BottomUpTreeDistance/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interfaces/ISymbolicExpressionTreeDistanceCalculator.cs	(revision 11218)
+++ 	(revision )
@@ -1,8 +1,0 @@
-﻿using HeuristicLab.Core;
-using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
-
-namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
-  public interface ISymbolicExpressionTreeDistanceCalculator : IItem {
-    double CalculateDistance(ISymbolicExpressionTree t1, ISymbolicExpressionTree t2);
-  }
-}
Index: /branches/HeuristicLab.BottomUpTreeDistance/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SimilarityCalculators/BottomUpSimilarityCalculator.cs
===================================================================
--- /branches/HeuristicLab.BottomUpTreeDistance/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SimilarityCalculators/BottomUpSimilarityCalculator.cs	(revision 11219)
+++ /branches/HeuristicLab.BottomUpTreeDistance/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SimilarityCalculators/BottomUpSimilarityCalculator.cs	(revision 11219)
@@ -0,0 +1,205 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2014 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
+using HeuristicLab.Optimization.Operators;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic.SimilarityCalculators {
+  [StorableClass]
+  [Item("BottomUpSimilarityCalculator", "A similarity calculator which uses the tree bottom-up distance as a similarity metric.")]
+  public class BottomUpSimilarityCalculator : SingleObjectiveSolutionSimilarityCalculator {
+    private readonly HashSet<string> commutativeSymbols = new HashSet<string> { "Addition", "Multiplication", "Average", "And", "Or", "Xor" };
+
+    public BottomUpSimilarityCalculator() { }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new BottomUpSimilarityCalculator(this, cloner);
+    }
+
+    protected BottomUpSimilarityCalculator(BottomUpSimilarityCalculator original, Cloner cloner)
+      : base(original, cloner) {
+    }
+
+    public override double CalculateSolutionSimilarity(IScope leftSolution, IScope rightSolution) {
+      var t1 = leftSolution.Variables[SolutionVariableName].Value as ISymbolicExpressionTree;
+      var t2 = rightSolution.Variables[SolutionVariableName].Value as ISymbolicExpressionTree;
+
+      if (t1 == null || t2 == null)
+        throw new ArgumentException("Cannot calculate similarity when one of the arguments is null.");
+
+      return CalculateSolutionSimilarity(t1, t2);
+    }
+
+    public double CalculateSolutionSimilarity(ISymbolicExpressionTree t1, ISymbolicExpressionTree t2) {
+      if (t1 == t2)
+        return 1;
+
+      var map = ComputeBottomUpMapping(t1, t2);
+      return 2.0 * map.Count / (t1.Length + t2.Length);
+    }
+
+
+    public Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode> ComputeBottomUpMapping(ISymbolicExpressionTree t1, ISymbolicExpressionTree t2) {
+      var compactedGraph = Compact(t1, t2);
+
+      var forwardMap = new Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode>(); // nodes of t1 => nodes of t2
+      var reverseMap = new Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode>(); // nodes of t2 => nodes of t1
+
+      foreach (var v in t1.IterateNodesBreadth()) {
+        if (forwardMap.ContainsKey(v)) continue;
+        var kv = compactedGraph[v];
+        ISymbolicExpressionTreeNode w = null;
+        foreach (var t in t2.IterateNodesBreadth()) {
+          if (reverseMap.ContainsKey(t) || compactedGraph[t] != kv) continue;
+          w = t;
+          break;
+        }
+        if (w == null) continue;
+
+        // at this point we know that v and w are isomorphic, however, the mapping cannot be done directly (as in the paper) because the trees are unordered (subtree order might differ)
+        // the solution is to sort subtrees by label using IterateBreadthOrdered (this will work because the subtrees are isomorphic!) and simultaneously iterate over the two subtrees
+        var eV = IterateBreadthOrdered(v).GetEnumerator();
+        var eW = IterateBreadthOrdered(w).GetEnumerator();
+
+        while (eV.MoveNext() && eW.MoveNext()) {
+          var s = eV.Current;
+          var t = eW.Current;
+          forwardMap[s] = t;
+          reverseMap[t] = s;
+        }
+      }
+
+      return forwardMap;
+    }
+
+    /// <summary>
+    /// Creates a compact representation of the two trees as a directed acyclic graph
+    /// </summary>
+    /// <param name="t1">The first tree</param>
+    /// <param name="t2">The second tree</param>
+    /// <returns>The compacted DAG representing the two trees</returns>
+    private Dictionary<ISymbolicExpressionTreeNode, IVertex> Compact(ISymbolicExpressionTree t1, ISymbolicExpressionTree t2) {
+      var nodesToVertices = new Dictionary<ISymbolicExpressionTreeNode, IVertex>(); // K
+      var labelsToVertices = new Dictionary<string, IVertex>(); // L
+      var childrenCount = new Dictionary<ISymbolicExpressionTreeNode, int>(); // Children
+      var vertices = new List<IVertex>(); // G
+
+      var nodes = t1.IterateNodesPostfix().Concat(t2.IterateNodesPostfix()); // the disjoint union F
+      var queue = new Queue<ISymbolicExpressionTreeNode>();
+
+      foreach (var n in nodes) {
+        if (n.SubtreeCount == 0) {
+          var label = n.ToString();
+          var z = new Vertex { Content = n, Label = label };
+          labelsToVertices[z.Label] = z;
+          vertices.Add(z);
+          queue.Enqueue(n);
+        } else {
+          childrenCount[n] = n.SubtreeCount;
+        }
+      }
+
+      while (queue.Any()) {
+        var v = queue.Dequeue();
+        string label;
+        if (v.SubtreeCount == 0) {
+          label = v.ToString();
+          nodesToVertices[v] = labelsToVertices[label]; // 18
+        } else {
+          label = v.Symbol.Name;
+          bool found = false;
+          var height = v.GetDepth();
+
+          bool sort = commutativeSymbols.Contains(label);
+          var vSubtrees = v.Subtrees.Select(x => nodesToVertices[x]).ToList();
+          if (sort) vSubtrees.Sort((a, b) => String.Compare(a.Label, b.Label, StringComparison.Ordinal));
+
+          // for all nodes w in G in reverse order
+          for (int i = vertices.Count - 1; i >= 0; --i) {
+            var w = vertices[i];
+            var n = (ISymbolicExpressionTreeNode)w.Content;
+            if (n.SubtreeCount == 0) continue; // v is a function node so w will have to be a function node as well
+            if (height != (int)w.Weight || v.SubtreeCount != n.SubtreeCount || label != w.Label)
+              continue;
+
+            // sort V and W when the symbol is commutative because we are dealing with unordered trees
+            var wSubtrees = sort ? w.OutArcs.Select(x => x.Target).OrderBy(x => x.Label)
+                                 : w.OutArcs.Select(x => x.Target);
+
+            if (vSubtrees.SequenceEqual(wSubtrees)) {
+              nodesToVertices[v] = w;
+              found = true;
+              break;
+            }
+          } // 32: end for
+
+          if (!found) {
+            var w = new Vertex { Content = v, Label = label, Weight = height };
+            vertices.Add(w);
+            nodesToVertices[v] = w;
+
+            foreach (var u in v.Subtrees) {
+              AddArc(w, nodesToVertices[u]);
+            } // 40: end for
+          } // 41: end if
+        } // 42: end if
+
+        var p = v.Parent;
+        if (p == null)
+          continue;
+
+        childrenCount[p]--;
+
+        if (childrenCount[p] == 0)
+          queue.Enqueue(p);
+      };
+
+      return nodesToVertices;
+    }
+
+    private IEnumerable<ISymbolicExpressionTreeNode> IterateBreadthOrdered(ISymbolicExpressionTreeNode node) {
+      var list = new List<ISymbolicExpressionTreeNode> { node };
+      int i = 0;
+      while (i < list.Count) {
+        var n = list[i];
+        if (n.SubtreeCount > 0) {
+          var subtrees = commutativeSymbols.Contains(node.Symbol.Name) ? n.Subtrees.OrderBy(s => s.ToString()) : n.Subtrees;
+          list.AddRange(subtrees);
+        }
+        i++;
+      }
+      return list;
+    }
+
+    private static IArc AddArc(IVertex source, IVertex target) {
+      var arc = new Arc(source, target);
+      source.AddForwardArc(arc);
+      target.AddReverseArc(arc);
+      return arc;
+    }
+  }
+}
Index: /branches/HeuristicLab.BottomUpTreeDistance/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SimilarityCalculators/MaxCommonSubtreeSimilarityCalculator.cs
===================================================================
--- /branches/HeuristicLab.BottomUpTreeDistance/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SimilarityCalculators/MaxCommonSubtreeSimilarityCalculator.cs	(revision 11219)
+++ /branches/HeuristicLab.BottomUpTreeDistance/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SimilarityCalculators/MaxCommonSubtreeSimilarityCalculator.cs	(revision 11219)
@@ -0,0 +1,75 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2014 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
+using HeuristicLab.Optimization.Operators;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic.SimilarityCalculators {
+  [StorableClass]
+  [Item("MaxCommonSubtreeSimilarityCalculator", "A similarity calculator based on the size of the maximum common subtree between two trees")]
+  public class MaxCommonSubtreeSimilarityCalculator : SingleObjectiveSolutionSimilarityCalculator {
+    public MaxCommonSubtreeSimilarityCalculator() { }
+
+    protected MaxCommonSubtreeSimilarityCalculator(MaxCommonSubtreeSimilarityCalculator original, Cloner cloner)
+      : base(original, cloner) {
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new MaxCommonSubtreeSimilarityCalculator(this, cloner);
+    }
+
+    public override double CalculateSolutionSimilarity(IScope leftSolution, IScope rightSolution) {
+      var t1 = leftSolution.Variables[SolutionVariableName].Value as ISymbolicExpressionTree;
+      var t2 = rightSolution.Variables[SolutionVariableName].Value as ISymbolicExpressionTree;
+
+      if (t1 == null || t2 == null)
+        throw new ArgumentException("Cannot calculate similarity when one of the arguments is null.");
+      var comparer = new SymbolicExpressionTreeNodeSimilarityComparer {
+        MatchConstantValues = true,
+        MatchVariableNames = true,
+        MatchVariableWeights = true
+      };
+
+      return MaxCommonSubtreeSimilarity(t1, t2, comparer);
+    }
+
+    public static double MaxCommonSubtreeSimilarity(ISymbolicExpressionTree a, ISymbolicExpressionTree b, SymbolicExpressionTreeNodeSimilarityComparer comparer) {
+      int max = 0;
+      var rootA = a.Root.GetSubtree(0).GetSubtree(0);
+      var rootB = b.Root.GetSubtree(0).GetSubtree(0);
+      foreach (var aa in rootA.IterateNodesBreadth()) {
+        int lenA = aa.GetLength();
+        if (lenA <= max) continue;
+        foreach (var bb in rootB.IterateNodesBreadth()) {
+          int lenB = bb.GetLength();
+          if (lenB <= max) continue;
+          int matches = SymbolicExpressionTreeMatching.Match(aa, bb, comparer);
+          if (max < matches) max = matches;
+        }
+      }
+      return 2.0 * max / (rootA.GetLength() + rootB.GetLength());
+    }
+  }
+}
Index: /branches/HeuristicLab.BottomUpTreeDistance/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisProblem.cs
===================================================================
--- /branches/HeuristicLab.BottomUpTreeDistance/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisProblem.cs	(revision 11218)
+++ /branches/HeuristicLab.BottomUpTreeDistance/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisProblem.cs	(revision 11219)
@@ -23,4 +23,5 @@
 using System.Drawing;
 using System.Linq;
+using HeuristicLab.Analysis;
 using HeuristicLab.Common;
 using HeuristicLab.Common.Resources;
@@ -29,7 +30,9 @@
 using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
 using HeuristicLab.Optimization;
+using HeuristicLab.Optimization.Operators;
 using HeuristicLab.Parameters;
 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
 using HeuristicLab.PluginInfrastructure;
+using HeuristicLab.Problems.DataAnalysis.Symbolic.SimilarityCalculators;
 using HeuristicLab.Problems.Instances;
 
@@ -231,4 +234,6 @@
       Operators.Add(new MinAverageMaxSymbolicExpressionTreeLengthAnalyzer());
       Operators.Add(new SymbolicExpressionTreeLengthAnalyzer());
+      Operators.Add(new SingleObjectivePopulationDiversityAnalyzer());
+      Operators.Add(new BottomUpSimilarityCalculator());
       ParameterizeOperators();
     }
@@ -350,4 +355,11 @@
         op.EvaluatorParameter.ActualName = EvaluatorParameter.Name;
       }
+      foreach (var op in operators.OfType<SingleObjectiveSolutionSimilarityCalculator>()) {
+        op.QualityVariableName = "Quality";
+        op.SolutionVariableName = SolutionCreator.SymbolicExpressionTreeParameter.ActualName;
+      }
+      foreach (var op in operators.OfType<SingleObjectivePopulationDiversityAnalyzer>()) {
+        op.SimilarityCalculator = operators.OfType<BottomUpSimilarityCalculator>().SingleOrDefault();
+      }
     }
 
Index: /branches/HeuristicLab.BottomUpTreeDistance/HeuristicLab.Tests/BottomUpSimilarityCalculatorTest.cs
===================================================================
--- /branches/HeuristicLab.BottomUpTreeDistance/HeuristicLab.Tests/BottomUpSimilarityCalculatorTest.cs	(revision 11219)
+++ /branches/HeuristicLab.BottomUpTreeDistance/HeuristicLab.Tests/BottomUpSimilarityCalculatorTest.cs	(revision 11219)
@@ -0,0 +1,161 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Drawing;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views;
+using HeuristicLab.Problems.DataAnalysis.Symbolic.SimilarityCalculators;
+using HeuristicLab.Random;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic.Tests {
+  [TestClass]
+  public class BottomUpSimilarityCalculatorTest {
+    private readonly BottomUpSimilarityCalculator busCalculator;
+    private readonly SymbolicExpressionImporter importer;
+
+    private const int N = 100;
+    private const int Rows = 1;
+    private const int Columns = 10;
+
+    public BottomUpSimilarityCalculatorTest() {
+      busCalculator = new BottomUpSimilarityCalculator();
+      importer = new SymbolicExpressionImporter();
+    }
+
+    [TestMethod]
+    [TestCategory("Problems.DataAnalysis.Symbolic")]
+    [TestProperty("Time", "short")]
+    public void TestBottomUpMatching() {
+      TestMatchedNodes("(+ 1 2)", "(+ 2 1)", 5);
+      TestMatchedNodes("(- 2 1)", "(- 1 2)", 2);
+
+      TestMatchedNodes(
+        "(* (+ 2.84 (exp (+ (log (/ (variable 2.0539 X5) (variable -9.2452e-1 X6))) (/ (variable 2.0539 X5) (variable -9.2452e-1 X6))))) 2.9081)",
+        "(* (- (variable 9.581e-1 X6) (+ (- (variable 5.1491e-1 X5) 1.614e+1) (+ (/ (variable 2.0539 X5) (variable -9.2452e-1 X6)) (log (/ (variable 2.0539 X5) (variable -9.2452e-1 X6)))))) 2.9081)",
+        9);
+
+      TestMatchedNodes("(+ (exp 2.1033) (/ -4.3072 (variable 2.4691 X7)))", "(/ 1 (+ (/ -4.3072 (variable 2.4691 X7)) (exp 2.1033)))", 6);
+      TestMatchedNodes("(+ (exp 2.1033) (/ -4.3072 (variable 2.4691 X7)))", "(/ 1 (+ (/ (variable 2.4691 X7) -4.3072) (exp 2.1033)))", 4);
+    }
+
+    private void TestMatchedNodes(string expr1, string expr2, int expected) {
+      var t1 = importer.Import(expr1);
+      var t2 = importer.Import(expr2);
+
+      var mapping = busCalculator.ComputeBottomUpMapping(t1, t2);
+      var c = mapping.Count;
+
+      if (c != expected) {
+        throw new Exception("Match count " + c + " is different than expected value " + expected);
+      }
+    }
+
+    [TestMethod]
+    [TestCategory("Problems.DataAnalysis.Symbolic")]
+    [TestProperty("Time", "long")]
+    public void TestBottomUpSimilarityCalculatorPerformance() {
+      var grammar = new TypeCoherentExpressionGrammar();
+      grammar.ConfigureAsDefaultRegressionGrammar();
+      var twister = new MersenneTwister(31415);
+      var ds = Util.CreateRandomDataset(twister, Rows, Columns);
+      var trees = Util.CreateRandomTrees(twister, ds, grammar, N, 1, 100, 0, 0);
+
+      double s = 0;
+      var sw = new Stopwatch();
+
+      sw.Start();
+      for (int i = 0; i < trees.Length - 1; ++i) {
+        for (int j = i + 1; j < trees.Length; ++j) {
+          s += busCalculator.CalculateSolutionSimilarity(trees[i], trees[j]);
+        }
+      }
+      sw.Stop();
+      Console.WriteLine("Elapsed time: " + sw.ElapsedMilliseconds / 1000.0 + ", Avg. similarity: " + s);
+      Console.WriteLine(N * (N + 1) / (2 * sw.ElapsedMilliseconds / 1000.0) + " similarity calculations per second.");
+    }
+
+    private static string FormatMapping(ISymbolicExpressionTree t1, ISymbolicExpressionTree t2, Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode> map) {
+      var symbolNameMap = new Dictionary<string, string>
+    {
+      {"ProgramRootSymbol", "Prog"},
+      {"StartSymbol","RPB"},
+      {"Multiplication", "$\\times$"},
+      {"Division", "$\\div$"},
+      {"Addition", "$+$"},
+      {"Subtraction", "$-$"},
+      {"Exponential", "$\\exp$"},
+      {"Logarithm", "$\\log$"}
+    };
+
+      var sb = new StringBuilder();
+      var nodeIds = new Dictionary<ISymbolicExpressionTreeNode, string>();
+      int offset = 0;
+      var layoutEngine = new ReingoldTilfordLayoutEngine<ISymbolicExpressionTreeNode>(x => x.Subtrees);
+      var nodeCoordinates = layoutEngine.CalculateLayout(t1.Root).ToDictionary(n => n.Content, n => new PointF(n.X, n.Y));
+
+      double ws = 0.5;
+      double hs = 0.5;
+
+      var nl = Environment.NewLine;
+      sb.Append("\\documentclass[class=minimal,border=0pt]{standalone}" + nl +
+                 "\\usepackage{tikz}" + nl +
+                 "\\begin{document}" + nl +
+                 "\\begin{tikzpicture}" + nl +
+                 "\\def\\ws{1}" + nl +
+                 "\\def\\hs{0.7}" + nl +
+                 "\\def\\offs{" + offset + "}" + nl);
+
+      foreach (var node in t1.IterateNodesBreadth()) {
+        var id = Guid.NewGuid().ToString();
+        nodeIds[node] = id;
+        var coord = nodeCoordinates[node];
+        var nodeName = symbolNameMap.ContainsKey(node.Symbol.Name) ? symbolNameMap[node.Symbol.Name] : node.ToString();
+        sb.AppendLine(string.Format(CultureInfo.InvariantCulture, "\\node ({0}) at (\\ws*{1} + \\offs,\\hs*{2}) {{{3}}};", nodeIds[node], ws * coord.X, -hs * coord.Y, EscapeLatexString(nodeName)));
+      }
+
+      foreach (ISymbolicExpressionTreeNode t in t1.IterateNodesBreadth()) {
+        var n = t;
+        foreach (var s in t.Subtrees) {
+          sb.AppendLine(string.Format(CultureInfo.InvariantCulture, "\\draw ({0}) -- ({1});", nodeIds[n], nodeIds[s]));
+        }
+      }
+
+      nodeCoordinates = layoutEngine.CalculateLayout(t2.Root).ToDictionary(n => n.Content, n => new PointF(n.X, n.Y));
+
+      offset = 20;
+      sb.Append("\\def\\offs{" + offset + "}" + nl);
+      foreach (var node in t2.IterateNodesBreadth()) {
+        var id = Guid.NewGuid().ToString();
+        nodeIds[node] = id;
+        var coord = nodeCoordinates[node];
+        var nodeName = symbolNameMap.ContainsKey(node.Symbol.Name) ? symbolNameMap[node.Symbol.Name] : node.ToString();
+        sb.AppendLine(string.Format(CultureInfo.InvariantCulture, "\\node ({0}) at (\\ws*{1} + \\offs,\\hs*{2}) {{{3}}};", nodeIds[node], ws * coord.X, -hs * coord.Y, EscapeLatexString(nodeName)));
+      }
+
+      foreach (ISymbolicExpressionTreeNode t in t2.IterateNodesBreadth()) {
+        var n = t;
+        foreach (var s in t.Subtrees) {
+          sb.AppendLine(string.Format(CultureInfo.InvariantCulture, "\\draw ({0}) -- ({1});", nodeIds[n], nodeIds[s]));
+        }
+      }
+
+      foreach (var p in map) {
+        var id1 = nodeIds[p.Key];
+        var id2 = nodeIds[p.Value];
+
+        sb.Append(string.Format(CultureInfo.InvariantCulture, "\\path[draw,->,color=gray] ({0}) edge[bend left,dashed] ({1});" + Environment.NewLine, id1, id2));
+      }
+      sb.Append("\\end{tikzpicture}" + nl +
+                "\\end{document}" + nl);
+      return sb.ToString();
+    }
+
+    private static string EscapeLatexString(string s) {
+      return s.Replace("\\", "\\\\").Replace("{", "\\{").Replace("}", "\\}").Replace("_", "\\_");
+    }
+  }
+}
Index: /branches/HeuristicLab.BottomUpTreeDistance/HeuristicLab.Tests/HeuristicLab.Tests.csproj
===================================================================
--- /branches/HeuristicLab.BottomUpTreeDistance/HeuristicLab.Tests/HeuristicLab.Tests.csproj	(revision 11219)
+++ /branches/HeuristicLab.BottomUpTreeDistance/HeuristicLab.Tests/HeuristicLab.Tests.csproj	(revision 11219)
@@ -0,0 +1,138 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{07C05C8F-0769-4607-96C6-D90A219F4C85}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>HeuristicLab.Tests</RootNamespace>
+    <AssemblyName>HeuristicLab.Tests</AssemblyName>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
+    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+    <ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
+    <IsCodedUITest>False</IsCodedUITest>
+    <TestProjectType>UnitTest</TestProjectType>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\..\..\trunk\sources\bin\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>..\..\..\trunk\sources\bin\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="HeuristicLab.Common-3.3">
+      <HintPath>..\..\..\trunk\sources\bin\HeuristicLab.Common-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Core-3.3">
+      <HintPath>..\..\..\trunk\sources\bin\HeuristicLab.Core-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Data-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\trunk\sources\bin\HeuristicLab.Data-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Encodings.SymbolicExpressionTreeEncoding-3.4">
+      <HintPath>..\..\..\trunk\sources\bin\HeuristicLab.Encodings.SymbolicExpressionTreeEncoding-3.4.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views-3.4, Version=3.4.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\trunk\sources\bin\HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.Views-3.4.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Operators-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\trunk\sources\bin\HeuristicLab.Operators-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Optimization-3.3">
+      <HintPath>..\..\..\trunk\sources\bin\HeuristicLab.Optimization-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Optimization.Operators-3.3">
+      <HintPath>..\..\..\trunk\sources\bin\HeuristicLab.Optimization.Operators-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Problems.DataAnalysis-3.4, Version=3.4.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\trunk\sources\bin\HeuristicLab.Problems.DataAnalysis-3.4.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="HeuristicLab.Random-3.3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\..\trunk\sources\bin\HeuristicLab.Random-3.3.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Drawing" />
+  </ItemGroup>
+  <Choose>
+    <When Condition="('$(VisualStudioVersion)' == '10.0' or '$(VisualStudioVersion)' == '') and '$(TargetFrameworkVersion)' == 'v3.5'">
+      <ItemGroup>
+        <Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
+      </ItemGroup>
+    </When>
+    <Otherwise>
+      <ItemGroup>
+        <Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework" />
+      </ItemGroup>
+    </Otherwise>
+  </Choose>
+  <ItemGroup>
+    <Compile Include="BottomUpSimilarityCalculatorTest.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="SymbolicExpressionImporter.cs" />
+    <Compile Include="Util.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\HeuristicLab.Problems.DataAnalysis.Symbolic\3.4\HeuristicLab.Problems.DataAnalysis.Symbolic-3.4.csproj">
+      <Project>{3d28463f-ec96-4d82-afee-38be91a0ca00}</Project>
+      <Name>HeuristicLab.Problems.DataAnalysis.Symbolic-3.4</Name>
+      <Private>False</Private>
+    </ProjectReference>
+  </ItemGroup>
+  <Choose>
+    <When Condition="'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'">
+      <ItemGroup>
+        <Reference Include="Microsoft.VisualStudio.QualityTools.CodedUITestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+          <Private>False</Private>
+        </Reference>
+        <Reference Include="Microsoft.VisualStudio.TestTools.UITest.Common, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+          <Private>False</Private>
+        </Reference>
+        <Reference Include="Microsoft.VisualStudio.TestTools.UITest.Extension, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+          <Private>False</Private>
+        </Reference>
+        <Reference Include="Microsoft.VisualStudio.TestTools.UITesting, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+          <Private>False</Private>
+        </Reference>
+      </ItemGroup>
+    </When>
+  </Choose>
+  <Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
Index: /branches/HeuristicLab.BottomUpTreeDistance/HeuristicLab.Tests/Properties/AssemblyInfo.cs
===================================================================
--- /branches/HeuristicLab.BottomUpTreeDistance/HeuristicLab.Tests/Properties/AssemblyInfo.cs	(revision 11219)
+++ /branches/HeuristicLab.BottomUpTreeDistance/HeuristicLab.Tests/Properties/AssemblyInfo.cs	(revision 11219)
@@ -0,0 +1,36 @@
+﻿using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("HeuristicLab.Tests")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("FH-Hagenberg")]
+[assembly: AssemblyProduct("HeuristicLab.Tests")]
+[assembly: AssemblyCopyright("Copyright © FH-Hagenberg 2014")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("7ed97492-aea8-4baf-b7a3-24ecfd1f8519")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers 
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
Index: /branches/HeuristicLab.BottomUpTreeDistance/HeuristicLab.Tests/SymbolicExpressionImporter.cs
===================================================================
--- /branches/HeuristicLab.BottomUpTreeDistance/HeuristicLab.Tests/SymbolicExpressionImporter.cs	(revision 11219)
+++ /branches/HeuristicLab.BottomUpTreeDistance/HeuristicLab.Tests/SymbolicExpressionImporter.cs	(revision 11219)
@@ -0,0 +1,267 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2014 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Globalization;
+using System.Linq;
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
+
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic.Tests {
+  internal class SymbolicExpressionImporter {
+    private const string VARSTART = "VAR";
+    private const string LAGGEDVARSTART = "LAGVARIABLE";
+    private const string INTEGRALSTART = "INTEG";
+    private const string DEFUNSTART = "DEFUN";
+    private const string ARGSTART = "ARG";
+    private const string INVOKESTART = "CALL";
+    private const string TIMELAGSTART = "LAG";
+    private Dictionary<string, Symbol> knownSymbols = new Dictionary<string, Symbol>() 
+      {
+        {"+", new Addition()},
+        {"/", new Division()},
+        {"*", new Multiplication()},
+        {"-", new Subtraction()},
+        {"EXP", new Exponential()},
+        {"LOG", new Logarithm()},
+        {"POW", new Power()},
+        {"ROOT", new Root()},
+        {"SIN",new Sine()},
+        {"COS", new Cosine()},
+        {"TAN", new Tangent()},
+        {"AIRYA", new AiryA()},
+        {"AIRYB", new AiryB()},
+        {"BESSEL", new Bessel()},
+        {"COSINT", new CosineIntegral()},
+        {"SININT", new SineIntegral()},
+        {"HYPCOSINT", new HyperbolicCosineIntegral()},
+        {"HYPSININT", new HyperbolicSineIntegral()},
+        {"FRESNELSININT", new FresnelSineIntegral()},
+        {"FRESNELCOSINT", new FresnelCosineIntegral()},
+        {"NORM", new Norm()},
+        {"ERF", new Erf()},
+        {"GAMMA", new Gamma()},
+        {"PSI", new Psi()},
+        {"DAWSON", new Dawson()},
+        {"EXPINT", new ExponentialIntegralEi()},
+        {"MEAN", new Average()},
+        {"IF", new IfThenElse()},
+        {">", new GreaterThan()},
+        {"<", new LessThan()},
+        {"AND", new And()},
+        {"OR", new Or()},
+        {"NOT", new Not()},
+        {"XOR", new Xor()},
+        {"DIFF", new Derivative()},
+        {"PROG", new ProgramRootSymbol()},
+        {"MAIN", new StartSymbol()},
+      };
+
+    Constant constant = new Constant();
+    Variable variable = new Variable();
+    LaggedVariable laggedVariable = new LaggedVariable();
+    Defun defun = new Defun();
+    TimeLag timeLag = new TimeLag();
+    Integral integral = new Integral();
+
+    ProgramRootSymbol programRootSymbol = new ProgramRootSymbol();
+    StartSymbol startSymbol = new StartSymbol();
+
+    internal ISymbolicExpressionTree Import(string str) {
+      str = str.Replace("(", " ( ").Replace(")", " ) ");
+      ISymbolicExpressionTreeNode root = programRootSymbol.CreateTreeNode();
+      ISymbolicExpressionTreeNode start = startSymbol.CreateTreeNode();
+      ISymbolicExpressionTreeNode mainBranch = ParseSexp(new Queue<Token>(GetTokenStream(str)));
+      if (mainBranch.Symbol is ProgramRootSymbol) {
+        // when a root symbol was parsed => use main branch as root
+        root = mainBranch;
+      } else {
+        // only a main branch was given => insert the main branch into the default tree template
+        root.AddSubtree(start);
+        start.AddSubtree(mainBranch);
+      }
+      return new SymbolicExpressionTree(root);
+    }
+
+    private IEnumerable<Token> GetTokenStream(string str) {
+      return
+             from strToken in str.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries).AsEnumerable()
+             let t = Token.Parse(strToken)
+             where t != null
+             select t;
+    }
+
+    private ISymbolicExpressionTreeNode ParseSexp(Queue<Token> tokens) {
+      if (tokens.Peek().Symbol == TokenSymbol.LPAR) {
+        ISymbolicExpressionTreeNode tree;
+        Expect(Token.LPAR, tokens);
+        if (tokens.Peek().StringValue.StartsWith(VARSTART)) {
+          tree = ParseVariable(tokens);
+        } else if (tokens.Peek().StringValue.StartsWith(LAGGEDVARSTART)) {
+          tree = ParseLaggedVariable(tokens);
+        } else if (tokens.Peek().StringValue.StartsWith(TIMELAGSTART)) {
+          tree = ParseTimeLag(tokens);
+          tree.AddSubtree(ParseSexp(tokens));
+        } else if (tokens.Peek().StringValue.StartsWith(INTEGRALSTART)) {
+          tree = ParseIntegral(tokens);
+          tree.AddSubtree(ParseSexp(tokens));
+        } else if (tokens.Peek().StringValue.StartsWith(DEFUNSTART)) {
+          tree = ParseDefun(tokens);
+          while (!tokens.Peek().Equals(Token.RPAR)) {
+            tree.AddSubtree(ParseSexp(tokens));
+          }
+        } else if (tokens.Peek().StringValue.StartsWith(ARGSTART)) {
+          tree = ParseArgument(tokens);
+        } else if (tokens.Peek().StringValue.StartsWith(INVOKESTART)) {
+          tree = ParseInvoke(tokens);
+          while (!tokens.Peek().Equals(Token.RPAR)) {
+            tree.AddSubtree(ParseSexp(tokens));
+          }
+        } else {
+          Token curToken = tokens.Dequeue();
+          tree = CreateTree(curToken);
+          while (!tokens.Peek().Equals(Token.RPAR)) {
+            tree.AddSubtree(ParseSexp(tokens));
+          }
+        }
+        Expect(Token.RPAR, tokens);
+        return tree;
+      } else if (tokens.Peek().Symbol == TokenSymbol.NUMBER) {
+        ConstantTreeNode t = (ConstantTreeNode)constant.CreateTreeNode();
+        t.Value = tokens.Dequeue().DoubleValue;
+        return t;
+      } else throw new FormatException("Expected function or constant symbol");
+    }
+
+    private ISymbolicExpressionTreeNode ParseInvoke(Queue<Token> tokens) {
+      Token invokeTok = tokens.Dequeue();
+      Debug.Assert(invokeTok.StringValue == "CALL");
+      InvokeFunction invokeSym = new InvokeFunction(tokens.Dequeue().StringValue);
+      ISymbolicExpressionTreeNode invokeNode = invokeSym.CreateTreeNode();
+      return invokeNode;
+    }
+
+    private ISymbolicExpressionTreeNode ParseArgument(Queue<Token> tokens) {
+      Token argTok = tokens.Dequeue();
+      Debug.Assert(argTok.StringValue == "ARG");
+      Argument argument = new Argument((int)tokens.Dequeue().DoubleValue);
+      ISymbolicExpressionTreeNode argNode = argument.CreateTreeNode();
+      return argNode;
+    }
+
+    private ISymbolicExpressionTreeNode ParseDefun(Queue<Token> tokens) {
+      Token defTok = tokens.Dequeue();
+      Debug.Assert(defTok.StringValue == "DEFUN");
+      DefunTreeNode t = (DefunTreeNode)defun.CreateTreeNode();
+      t.FunctionName = tokens.Dequeue().StringValue;
+      return t;
+    }
+
+    private ISymbolicExpressionTreeNode ParseTimeLag(Queue<Token> tokens) {
+      Token varTok = tokens.Dequeue();
+      Debug.Assert(varTok.StringValue == "LAG");
+      LaggedTreeNode t = (LaggedTreeNode)timeLag.CreateTreeNode();
+      t.Lag = (int)tokens.Dequeue().DoubleValue;
+      return t;
+    }
+
+    private ISymbolicExpressionTreeNode ParseIntegral(Queue<Token> tokens) {
+      Token varTok = tokens.Dequeue();
+      Debug.Assert(varTok.StringValue == "INTEGRAL");
+      LaggedTreeNode t = (LaggedTreeNode)integral.CreateTreeNode();
+      t.Lag = (int)tokens.Dequeue().DoubleValue;
+      return t;
+    }
+
+    private ISymbolicExpressionTreeNode ParseVariable(Queue<Token> tokens) {
+      Token varTok = tokens.Dequeue();
+      Debug.Assert(varTok.StringValue == "VARIABLE");
+      VariableTreeNode t = (VariableTreeNode)variable.CreateTreeNode();
+      t.Weight = tokens.Dequeue().DoubleValue;
+      t.VariableName = tokens.Dequeue().StringValue;
+      return t;
+    }
+
+    private ISymbolicExpressionTreeNode ParseLaggedVariable(Queue<Token> tokens) {
+      Token varTok = tokens.Dequeue();
+      Debug.Assert(varTok.StringValue == "LAGVARIABLE");
+      LaggedVariableTreeNode t = (LaggedVariableTreeNode)laggedVariable.CreateTreeNode();
+      t.Weight = tokens.Dequeue().DoubleValue;
+      t.VariableName = tokens.Dequeue().StringValue;
+      t.Lag = (int)tokens.Dequeue().DoubleValue;
+      return t;
+    }
+
+    private ISymbolicExpressionTreeNode CreateTree(Token token) {
+      if (token.Symbol != TokenSymbol.SYMB) throw new FormatException("Expected function symbol, but got: " + token.StringValue);
+      return knownSymbols[token.StringValue].CreateTreeNode();
+    }
+
+    private void Expect(Token token, Queue<Token> tokens) {
+      Token cur = tokens.Dequeue();
+      if (!token.Equals(cur)) throw new FormatException("Expected: " + token.StringValue + ", but got: " + cur.StringValue);
+    }
+  }
+
+  internal enum TokenSymbol { LPAR, RPAR, SYMB, NUMBER };
+  internal class Token {
+    public static readonly Token LPAR = Token.Parse("(");
+    public static readonly Token RPAR = Token.Parse(")");
+
+    public TokenSymbol Symbol { get; set; }
+    public string StringValue { get; set; }
+    public double DoubleValue { get; set; }
+    public Token() { }
+
+    public override bool Equals(object obj) {
+      Token other = (obj as Token);
+      if (other == null) return false;
+      if (other.Symbol != Symbol) return false;
+      return other.StringValue == this.StringValue;
+    }
+
+    public override int GetHashCode() {
+      return Symbol.GetHashCode() & StringValue.GetHashCode();
+    }
+
+    public static Token Parse(string strToken) {
+      strToken = strToken.Trim();
+      Token t = new Token();
+      t.StringValue = strToken.Trim();
+      double temp;
+      if (strToken == "") {
+        t = null;
+      } else if (strToken == "(") {
+        t.Symbol = TokenSymbol.LPAR;
+      } else if (strToken == ")") {
+        t.Symbol = TokenSymbol.RPAR;
+      } else if (double.TryParse(strToken, NumberStyles.Float, CultureInfo.InvariantCulture.NumberFormat, out temp)) {
+        t.Symbol = TokenSymbol.NUMBER;
+        t.DoubleValue = double.Parse(strToken, CultureInfo.InvariantCulture.NumberFormat);
+      } else {
+        t.Symbol = TokenSymbol.SYMB;
+        t.StringValue = t.StringValue.ToUpper();
+      }
+      return t;
+    }
+  }
+}
Index: /branches/HeuristicLab.BottomUpTreeDistance/HeuristicLab.Tests/Util.cs
===================================================================
--- /branches/HeuristicLab.BottomUpTreeDistance/HeuristicLab.Tests/Util.cs	(revision 11219)
+++ /branches/HeuristicLab.BottomUpTreeDistance/HeuristicLab.Tests/Util.cs	(revision 11219)
@@ -0,0 +1,104 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2014 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
+using HeuristicLab.Random;
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic.Tests {
+  internal class Util {
+
+    public static void InitTree(ISymbolicExpressionTree tree, MersenneTwister twister, List<string> varNames) {
+      foreach (var node in tree.IterateNodesPostfix()) {
+        if (node is VariableTreeNode) {
+          var varNode = node as VariableTreeNode;
+          varNode.Weight = twister.NextDouble() * 20.0 - 10.0;
+          varNode.VariableName = varNames[twister.Next(varNames.Count)];
+        } else if (node is ConstantTreeNode) {
+          var constantNode = node as ConstantTreeNode;
+          constantNode.Value = twister.NextDouble() * 20.0 - 10.0;
+        }
+      }
+    }
+
+
+    public static ISymbolicExpressionTree[] CreateRandomTrees(MersenneTwister twister, Dataset dataset, ISymbolicExpressionGrammar grammar, int popSize) {
+      return CreateRandomTrees(twister, dataset, grammar, popSize, 1, 200, 3, 3);
+    }
+
+    public static ISymbolicExpressionTree[] CreateRandomTrees(MersenneTwister twister, Dataset dataset, ISymbolicExpressionGrammar grammar,
+      int popSize, int minSize, int maxSize,
+      int maxFunctionDefinitions, int maxFunctionArguments) {
+      foreach (Variable variableSymbol in grammar.Symbols.OfType<Variable>()) {
+        variableSymbol.VariableNames = dataset.VariableNames.Skip(1);
+      }
+      ISymbolicExpressionTree[] randomTrees = new ISymbolicExpressionTree[popSize];
+      for (int i = 0; i < randomTrees.Length; i++) {
+        randomTrees[i] = ProbabilisticTreeCreator.Create(twister, grammar, maxSize, 10);
+      }
+      return randomTrees;
+    }
+
+
+    public static Dataset CreateRandomDataset(MersenneTwister twister, int rows, int columns) {
+      double[,] data = new double[rows, columns];
+      for (int i = 0; i < rows; i++) {
+        for (int j = 0; j < columns; j++) {
+          data[i, j] = twister.NextDouble() * 2.0 - 1.0;
+        }
+      }
+      IEnumerable<string> variableNames = new string[] { "y" }.Concat(Enumerable.Range(0, columns - 1).Select(x => "x" + x.ToString()));
+      Dataset ds = new Dataset(variableNames, data);
+      return ds;
+    }
+
+    public static double NodesPerSecond(long nNodes, Stopwatch watch) {
+      return nNodes / (watch.ElapsedMilliseconds / 1000.0);
+    }
+
+    public static double CalculateEvaluatedNodesPerSec(ISymbolicExpressionTree[] trees, ISymbolicDataAnalysisExpressionTreeInterpreter interpreter, Dataset dataset, int repetitions) {
+      // warm up
+      IEnumerable<int> rows = Enumerable.Range(0, dataset.Rows);
+      long nNodes = 0;
+      double c = 0;
+      for (int i = 0; i < trees.Length; i++) {
+        nNodes += trees[i].Length * (dataset.Rows - 1);
+        c = interpreter.GetSymbolicExpressionTreeValues(trees[i], dataset, rows).Count(); // count needs to evaluate all rows
+      }
+
+      Stopwatch watch = new Stopwatch();
+      for (int rep = 0; rep < repetitions; rep++) {
+        watch.Start();
+        c = 0;
+        for (int i = 0; i < trees.Length; i++) {
+          interpreter.GetSymbolicExpressionTreeValues(trees[i], dataset, rows).Count(); // count needs to evaluate all rows
+        }
+        watch.Stop();
+      }
+      Console.WriteLine("Random tree evaluation performance of " + interpreter.GetType() + ": " +
+        watch.ElapsedMilliseconds + "ms " +
+        Util.NodesPerSecond(nNodes * repetitions, watch) + " nodes/sec");
+      return Util.NodesPerSecond(nNodes * repetitions, watch);
+    }
+  }
+}
