Index: stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Analyzers/SymbolicDataAnalysisPopulationDiversityAnalyzer.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Analyzers/SymbolicDataAnalysisPopulationDiversityAnalyzer.cs	(revision 11947)
+++ stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Analyzers/SymbolicDataAnalysisPopulationDiversityAnalyzer.cs	(revision 11947)
@@ -0,0 +1,185 @@
+﻿#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.Linq;
+using HeuristicLab.Analysis;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
+using HeuristicLab.Operators;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+// type definitions for ease of use
+
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
+  /// <summary>
+  /// Population diversity analyzer
+  /// </summary>
+  [Item("SymbolicDataAnalysisPopulationDiversityAnalyzer", "An operator that tracks population diversity")]
+  [StorableClass]
+  public sealed class SymbolicDataAnalysisPopulationDiversityAnalyzer : SingleSuccessorOperator, IAnalyzer {
+    #region Parameter names
+    private const string MaximumSymbolicExpressionTreeDepthParameterName = "MaximumSymbolicExpressionTreeDepth";
+    private const string SymbolicExpressionTreeParameterName = "SymbolicExpressionTree";
+    private const string UpdateIntervalParameterName = "UpdateInterval";
+    private const string UpdateCounterParameterName = "UpdateCounter";
+    private const string ResultsParameterName = "Results";
+    private const string GenerationsParameterName = "Generations";
+    private const string StoreHistoryParameterName = "StoreHistory";
+    // comparer parameters
+    private const string SimilarityValuesParmeterName = "Similarity";
+
+    private const string DistanceCalculatorParameterName = "DistanceCalculator";
+
+    #endregion
+
+    #region Parameters
+    public IValueLookupParameter<IntValue> MaximumSymbolicExpressionTreeDepthParameter {
+      get { return (IValueLookupParameter<IntValue>)Parameters[MaximumSymbolicExpressionTreeDepthParameterName]; }
+    }
+    public ValueParameter<IntValue> UpdateIntervalParameter {
+      get { return (ValueParameter<IntValue>)Parameters[UpdateIntervalParameterName]; }
+    }
+    public ValueParameter<IntValue> UpdateCounterParameter {
+      get { return (ValueParameter<IntValue>)Parameters[UpdateCounterParameterName]; }
+    }
+    public LookupParameter<ResultCollection> ResultsParameter {
+      get { return (LookupParameter<ResultCollection>)Parameters[ResultsParameterName]; }
+    }
+    public LookupParameter<IntValue> GenerationsParameter {
+      get { return (LookupParameter<IntValue>)Parameters[GenerationsParameterName]; }
+    }
+    public ValueParameter<BoolValue> StoreHistoryParameter {
+      get { return (ValueParameter<BoolValue>)Parameters[StoreHistoryParameterName]; }
+    }
+    public IScopeTreeLookupParameter<ISymbolicExpressionTree> SymbolicExpressionTreeParameter {
+      get { return (IScopeTreeLookupParameter<ISymbolicExpressionTree>)Parameters[SymbolicExpressionTreeParameterName]; }
+    }
+    public ILookupParameter<DoubleValue> SimilarityParameter {
+      get { return (ILookupParameter<DoubleValue>)Parameters[SimilarityValuesParmeterName]; }
+    }
+    public IValueParameter<ISymbolicExpressionTreeDistanceCalculator> DistanceCalculatorParameter {
+      get { return (IValueParameter<ISymbolicExpressionTreeDistanceCalculator>)Parameters[DistanceCalculatorParameterName]; }
+    }
+    #endregion
+
+    #region Parameter properties
+    public IntValue MaximumSymbolicExpressionTreeDepth { get { return MaximumSymbolicExpressionTreeDepthParameter.ActualValue; } }
+    public IntValue UpdateInterval { get { return UpdateIntervalParameter.Value; } }
+    public IntValue UpdateCounter { get { return UpdateCounterParameter.Value; } }
+    public ResultCollection Results { get { return ResultsParameter.ActualValue; } }
+    public IntValue Generations { get { return GenerationsParameter.ActualValue; } }
+    public BoolValue StoreHistory { get { return StoreHistoryParameter.Value; } }
+    #endregion
+
+    [StorableConstructor]
+    private SymbolicDataAnalysisPopulationDiversityAnalyzer(bool deserializing)
+      : base(deserializing) {
+    }
+
+    private SymbolicDataAnalysisPopulationDiversityAnalyzer(
+      SymbolicDataAnalysisPopulationDiversityAnalyzer original, Cloner cloner)
+      : base(original, cloner) {
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new SymbolicDataAnalysisPopulationDiversityAnalyzer(this, cloner);
+    }
+
+    public SymbolicDataAnalysisPopulationDiversityAnalyzer() {
+      // add parameters
+      Parameters.Add(new ScopeTreeLookupParameter<ISymbolicExpressionTree>(SymbolicExpressionTreeParameterName, "The symbolic expression trees to analyze."));
+      Parameters.Add(new ValueParameter<IntValue>(UpdateIntervalParameterName, "The interval in which the tree length analysis should be applied.", new IntValue(1)));
+      Parameters.Add(new ValueParameter<IntValue>(UpdateCounterParameterName, "The value which counts how many times the operator was called since the last update", new IntValue(0)));
+      Parameters.Add(new ValueLookupParameter<ResultCollection>(ResultsParameterName, "The results collection where the analysis values should be stored."));
+      Parameters.Add(new LookupParameter<IntValue>(GenerationsParameterName, "The number of generations so far."));
+      Parameters.Add(new ValueParameter<BoolValue>(StoreHistoryParameterName, "True if the tree lengths history of the population should be stored.", new BoolValue(false)));
+      Parameters.Add(new LookupParameter<DoubleValue>(SimilarityValuesParmeterName, ""));
+      Parameters.Add(new ValueLookupParameter<IntValue>(MaximumSymbolicExpressionTreeDepthParameterName, "The maximal depth of the symbolic expression tree (a tree with one node has depth = 0)."));
+      Parameters.Add(new ValueParameter<ISymbolicExpressionTreeDistanceCalculator>(DistanceCalculatorParameterName, "The distance calculator between trees.", new BottomUpTreeDistanceCalculator()));
+      UpdateCounterParameter.Hidden = true;
+      UpdateIntervalParameter.Hidden = true;
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      if (!Parameters.ContainsKey(MaximumSymbolicExpressionTreeDepthParameterName)) {
+        Parameters.Add(new ValueLookupParameter<IntValue>(MaximumSymbolicExpressionTreeDepthParameterName, "The maximal depth of the symbolic expression tree (a tree with one node has depth = 0)."));
+      }
+    }
+
+    #region IStatefulItem members
+    public override void InitializeState() {
+      UpdateCounter.Value = 0;
+      base.InitializeState();
+    }
+    #endregion
+
+    public bool EnabledByDefault {
+      get { return true; }
+    }
+
+    public override IOperation Apply() {
+      if (SimilarityParameter.ActualValue == null || SimilarityParameter.ActualValue.Value.IsAlmost(-1.0)) {
+        UpdateCounter.Value++;
+        if (UpdateCounter.Value != UpdateInterval.Value) return base.Apply();
+        UpdateCounter.Value = 0;
+        var trees = SymbolicExpressionTreeParameter.ActualValue.ToList();
+
+        SimilarityParameter.ActualValue = new DoubleValue();
+
+        var operations = new OperationCollection { Parallel = true };
+        foreach (var tree in trees) {
+          var op = new SymbolicDataAnalysisExpressionTreeSimilarityCalculator(DistanceCalculatorParameter.Value) {
+            CurrentSymbolicExpressionTree = tree,
+            MaximumTreeDepth = MaximumSymbolicExpressionTreeDepth.Value
+          };
+          var operation = ExecutionContext.CreateChildOperation(op, ExecutionContext.Scope);
+          operations.Add(operation);
+        }
+        return new OperationCollection { operations, ExecutionContext.CreateOperation(this) };
+      }
+
+      var results = ResultsParameter.ActualValue;
+      // population diversity
+      DataTable populationDiversityTable;
+      if (!results.ContainsKey("PopulationDiversity")) {
+        populationDiversityTable = new DataTable("PopulationDiversity") { VisualProperties = { YAxisTitle = "Diversity" } };
+        results.Add(new Result("PopulationDiversity", populationDiversityTable));
+      }
+      populationDiversityTable = (DataTable)results["PopulationDiversity"].Value;
+      if (!populationDiversityTable.Rows.ContainsKey("Diversity"))
+        populationDiversityTable.Rows.Add(new DataRow("Diversity") { VisualProperties = { StartIndexZero = true } });
+
+      int length = SymbolicExpressionTreeParameter.ActualValue.Length;
+      var similarity = SimilarityParameter.ActualValue.Value / (length * (length - 1) / 2.0);
+      var diversity = 1 - similarity;
+      SimilarityParameter.ActualValue.Value = -1.0;
+
+      populationDiversityTable.Rows["Diversity"].Values.Add(diversity);
+
+      return base.Apply();
+    }
+  }
+}
Index: stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4.csproj
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4.csproj	(revision 11943)
+++ stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4.csproj	(revision 11947)
@@ -135,10 +135,4 @@
     <Compile Include="Importer\Token.cs" />
     <Compile Include="Interfaces\IModelBacktransformator.cs" />
-    <Compile Include="Matching\SymbolicExpressionTreeCanonicalSorter.cs" />
-    <Compile Include="Matching\SymbolicExpressionTreeEqualityComparer.cs" />
-    <Compile Include="Matching\SymbolicExpressionTreeMatching.cs" />
-    <Compile Include="Matching\SymbolicExpressionTreeMaxCommonSequenceCalculator.cs" />
-    <Compile Include="Matching\SymbolicExpressionTreeNodeComparer.cs" />
-    <Compile Include="Matching\SymbolicExpressionTreeNodeSimilarityComparer.cs" />
     <Compile Include="SymbolicExpressionTreeBacktransformator.cs" />
     <Compile Include="SymbolicDataAnalysisExpressionPruningOperator.cs" />
@@ -239,4 +233,11 @@
     <Compile Include="Symbols\VariableTreeNode.cs" />
     <Compile Include="TransformationToSymbolicTreeMapper.cs" />
+    <Compile Include="TreeMatching\SymbolicExpressionTreeBottomUpSimilarityCalculator.cs" />
+    <Compile Include="TreeMatching\SymbolicExpressionTreeCanonicalSorter.cs" />
+    <Compile Include="TreeMatching\SymbolicExpressionTreeEqualityComparer.cs" />
+    <Compile Include="TreeMatching\SymbolicExpressionTreeMatching.cs" />
+    <Compile Include="TreeMatching\SymbolicExpressionTreeMaxCommonSubtreeSimilarityCalculator.cs" />
+    <Compile Include="TreeMatching\SymbolicExpressionTreeNodeComparer.cs" />
+    <Compile Include="TreeMatching\SymbolicExpressionTreeNodeEqualityComparer.cs" />
     <None Include="HeuristicLab.snk" />
     <None Include="Plugin.cs.frame" />
Index: stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeLinearInterpreter.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeLinearInterpreter.cs	(revision 11943)
+++ stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeLinearInterpreter.cs	(revision 11947)
@@ -352,5 +352,5 @@
     }
 
-    private static void PrepareInstructions(LinearInstruction[] code, Dataset dataset) {
+    public static void PrepareInstructions(LinearInstruction[] code, Dataset dataset) {
       for (int i = 0; i != code.Length; ++i) {
         var instr = code[i];
Index: stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisExpressionTreeSimilarityCalculator.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisExpressionTreeSimilarityCalculator.cs	(revision 11947)
+++ stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisExpressionTreeSimilarityCalculator.cs	(revision 11947)
@@ -0,0 +1,114 @@
+﻿#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 HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
+using HeuristicLab.Operators;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
+  [StorableClass]
+  public class SymbolicDataAnalysisExpressionTreeSimilarityCalculator : SingleSuccessorOperator {
+    private const string SymbolicExpressionTreeParameterName = "SymbolicExpressionTree";
+    private const string CurrentSymbolicExpressionTreeParameterName = "CurrentSymbolicExpressionTree";
+    private const string SimilarityValuesParmeterName = "Similarity";
+    // comparer parameters
+    private const string MatchVariablesParameterName = "MatchVariableNames";
+    private const string MatchVariableWeightsParameterName = "MatchVariableWeights";
+    private const string MatchConstantValuesParameterName = "MatchConstantValues";
+
+    private readonly ISymbolicExpressionTreeDistanceCalculator distanceCalculator;
+
+    public IScopeTreeLookupParameter<ISymbolicExpressionTree> SymbolicExpressionTreeParameter {
+      get { return (IScopeTreeLookupParameter<ISymbolicExpressionTree>)Parameters[SymbolicExpressionTreeParameterName]; }
+    }
+    public IValueParameter<ISymbolicExpressionTree> CurrentSymbolicExpressionTreeParameter {
+      get { return (IValueParameter<ISymbolicExpressionTree>)Parameters[CurrentSymbolicExpressionTreeParameterName]; }
+    }
+
+    public ILookupParameter<DoubleValue> SimilarityParameter {
+      get { return (ILookupParameter<DoubleValue>)Parameters[SimilarityValuesParmeterName]; }
+    }
+    public ISymbolicExpressionTree CurrentSymbolicExpressionTree {
+      get { return CurrentSymbolicExpressionTreeParameter.Value; }
+      set { CurrentSymbolicExpressionTreeParameter.Value = value; }
+    }
+
+    public int MaximumTreeDepth { get; set; }
+
+    protected SymbolicDataAnalysisExpressionTreeSimilarityCalculator(
+      SymbolicDataAnalysisExpressionTreeSimilarityCalculator original, Cloner cloner)
+      : base(original, cloner) {
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new SymbolicDataAnalysisExpressionTreeSimilarityCalculator(this, cloner);
+    }
+
+    [StorableConstructor]
+    protected SymbolicDataAnalysisExpressionTreeSimilarityCalculator(bool deserializing)
+      : base(deserializing) {
+    }
+
+    private SymbolicDataAnalysisExpressionTreeSimilarityCalculator() {
+    }
+
+    public SymbolicDataAnalysisExpressionTreeSimilarityCalculator(ISymbolicExpressionTreeDistanceCalculator distanceCalculator)
+      : base() {
+      this.distanceCalculator = distanceCalculator;
+
+      Parameters.Add(new ScopeTreeLookupParameter<ISymbolicExpressionTree>(SymbolicExpressionTreeParameterName, "The symbolic expression trees to analyze."));
+      Parameters.Add(new ValueParameter<ISymbolicExpressionTree>(CurrentSymbolicExpressionTreeParameterName, ""));
+      Parameters.Add(new LookupParameter<BoolValue>(MatchVariablesParameterName, "Specify if the symbolic expression tree comparer should match variable names."));
+      Parameters.Add(new LookupParameter<BoolValue>(MatchVariableWeightsParameterName, "Specify if the symbolic expression tree comparer should match variable weghts."));
+      Parameters.Add(new LookupParameter<BoolValue>(MatchConstantValuesParameterName, "Specify if the symbolic expression tree comparer should match constant values."));
+      Parameters.Add(new LookupParameter<DoubleValue>(SimilarityValuesParmeterName, ""));
+    }
+
+    public override IOperation Apply() {
+      var trees = SymbolicExpressionTreeParameter.ActualValue;
+
+      double similarity = 0.0;
+      var current = CurrentSymbolicExpressionTree;
+
+      bool found = false;
+      foreach (var tree in trees) {
+        if (tree == current) {
+          found = true;
+          continue;
+        }
+
+        if (found) {
+          var distance = distanceCalculator.CalculateDistance(current, tree);
+          similarity += 1 - distance;
+        }
+      }
+
+      lock (SimilarityParameter.ActualValue) {
+        SimilarityParameter.ActualValue.Value += similarity;
+      }
+      return base.Apply();
+    }
+  }
+}
Index: stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisProblem.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisProblem.cs	(revision 11943)
+++ stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisProblem.cs	(revision 11947)
@@ -23,4 +23,5 @@
 using System.Drawing;
 using System.Linq;
+using HeuristicLab.Analysis;
 using HeuristicLab.Common;
 using HeuristicLab.Common.Resources;
@@ -29,4 +30,5 @@
 using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
 using HeuristicLab.Optimization;
+using HeuristicLab.Optimization.Operators;
 using HeuristicLab.Parameters;
 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
@@ -231,4 +233,5 @@
       Operators.Add(new MinAverageMaxSymbolicExpressionTreeLengthAnalyzer());
       Operators.Add(new SymbolicExpressionTreeLengthAnalyzer());
+      Operators.Add(new SingleObjectivePopulationDiversityAnalyzer());
       ParameterizeOperators();
     }
@@ -350,4 +353,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 = new SymbolicExpressionTreeBottomUpSimilarityCalculator();
+      }
     }
 
Index: stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/TreeMatching/SymbolicExpressionTreeBottomUpSimilarityCalculator.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/TreeMatching/SymbolicExpressionTreeBottomUpSimilarityCalculator.cs	(revision 11947)
+++ stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/TreeMatching/SymbolicExpressionTreeBottomUpSimilarityCalculator.cs	(revision 11947)
@@ -0,0 +1,238 @@
+﻿#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.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
+using HeuristicLab.Optimization.Operators;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
+  [StorableClass]
+  [Item("SymbolicExpressionTreeBottomUpSimilarityCalculator", "A similarity calculator which uses the tree bottom-up distance as a similarity metric.")]
+  public class SymbolicExpressionTreeBottomUpSimilarityCalculator : SingleObjectiveSolutionSimilarityCalculator {
+    private readonly HashSet<string> commutativeSymbols = new HashSet<string> { "Addition", "Multiplication", "Average", "And", "Or", "Xor" };
+    public bool MatchVariableWeights { get; set; }
+    public bool MatchConstantValues { get; set; }
+
+    public SymbolicExpressionTreeBottomUpSimilarityCalculator() { }
+
+    [StorableConstructor]
+    protected SymbolicExpressionTreeBottomUpSimilarityCalculator(bool deserializing)
+      : base(deserializing) {
+    }
+
+    protected SymbolicExpressionTreeBottomUpSimilarityCalculator(SymbolicExpressionTreeBottomUpSimilarityCalculator original, Cloner cloner)
+      : base(original, cloner) {
+      MatchVariableWeights = original.MatchVariableWeights;
+      MatchConstantValues = original.MatchConstantValues;
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new SymbolicExpressionTreeBottomUpSimilarityCalculator(this, cloner);
+    }
+
+    public double CalculateSimilarity(ISymbolicExpressionTree t1, ISymbolicExpressionTree t2) {
+      if (t1 == t2)
+        return 1;
+
+      var map = ComputeBottomUpMapping(t1.Root, t2.Root);
+      return 2.0 * map.Count / (t1.Length + t2.Length);
+    }
+
+    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 similarity = CalculateSimilarity(t1, t2);
+      if (similarity > 1.0)
+        throw new Exception("Similarity value cannot be greater than 1");
+
+      return similarity;
+    }
+
+    public Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode> ComputeBottomUpMapping(ISymbolicExpressionTreeNode n1, ISymbolicExpressionTreeNode n2) {
+      var comparer = new SymbolicExpressionTreeNodeComparer(); // use a node comparer because it's faster than calling node.ToString() (strings are expensive) and comparing strings
+      var compactedGraph = Compact(n1, n2);
+
+      var forwardMap = new Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode>(); // nodes of t1 => nodes of t2
+      var reverseMap = new Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode>(); // nodes of t2 => nodes of t1
+
+      // visit nodes in order of decreasing height to ensure correct mapping
+      var nodes1 = n1.IterateNodesPrefix().ToList();
+      var nodes2 = n2.IterateNodesPrefix().ToList();
+      for (int i = 0; i < nodes1.Count; ++i) {
+        var v = nodes1[i];
+        if (forwardMap.ContainsKey(v))
+          continue;
+        var kv = compactedGraph[v];
+        ISymbolicExpressionTreeNode w = null;
+        for (int j = 0; j < nodes2.Count; ++j) {
+          var t = nodes2[j];
+          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 vv = IterateBreadthOrdered(v, comparer).ToList();
+        var ww = IterateBreadthOrdered(w, comparer).ToList();
+        int len = Math.Min(vv.Count, ww.Count);
+        for (int j = 0; j < len; ++j) {
+          var s = vv[j];
+          var t = ww[j];
+          Debug.Assert(!reverseMap.ContainsKey(t));
+
+          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="n1">The root of the first tree</param>
+    /// <param name="n2">The root of the second tree</param>
+    /// <returns>The compacted DAG representing the two trees</returns>
+    private Dictionary<ISymbolicExpressionTreeNode, GraphNode> Compact(ISymbolicExpressionTreeNode n1, ISymbolicExpressionTreeNode n2) {
+      var nodeMap = new Dictionary<ISymbolicExpressionTreeNode, GraphNode>(); // K
+      var labelMap = new Dictionary<string, GraphNode>(); // L
+      var childrenCount = new Dictionary<ISymbolicExpressionTreeNode, int>(); // Children
+
+      var nodes = n1.IterateNodesPostfix().Concat(n2.IterateNodesPostfix()); // the disjoint union F
+      var list = new List<GraphNode>();
+      var queue = new Queue<ISymbolicExpressionTreeNode>();
+
+      foreach (var n in nodes) {
+        if (n.SubtreeCount == 0) {
+          var label = Label(n);
+          if (!labelMap.ContainsKey(label)) {
+            var z = new GraphNode { SymbolicExpressionTreeNode = n, Label = label };
+            labelMap[z.Label] = z;
+          }
+          nodeMap[n] = labelMap[label];
+          queue.Enqueue(n);
+        } else {
+          childrenCount[n] = n.SubtreeCount;
+        }
+      }
+      while (queue.Any()) {
+        var n = queue.Dequeue();
+        if (n.SubtreeCount > 0) {
+          bool found = false;
+          var label = n.Symbol.Name;
+          var depth = n.GetDepth();
+
+          bool sort = n.SubtreeCount > 1 && commutativeSymbols.Contains(label);
+          var nSubtrees = n.Subtrees.Select(x => nodeMap[x]).ToList();
+          if (sort) nSubtrees.Sort((a, b) => string.CompareOrdinal(a.Label, b.Label));
+
+          for (int i = list.Count - 1; i >= 0; --i) {
+            var w = list[i];
+            if (!(n.SubtreeCount == w.SubtreeCount && label == w.Label && depth == w.Depth))
+              continue;
+
+            // sort V and W when the symbol is commutative because we are dealing with unordered trees
+            var m = w.SymbolicExpressionTreeNode;
+            var mSubtrees = m.Subtrees.Select(x => nodeMap[x]).ToList();
+            if (sort) mSubtrees.Sort((a, b) => string.CompareOrdinal(a.Label, b.Label));
+
+            found = nSubtrees.SequenceEqual(mSubtrees);
+            if (found) {
+              nodeMap[n] = w;
+              break;
+            }
+          }
+
+          if (!found) {
+            var w = new GraphNode { SymbolicExpressionTreeNode = n, Label = label, Depth = depth };
+            list.Add(w);
+            nodeMap[n] = w;
+          }
+        }
+
+        if (n == n1 || n == n2)
+          continue;
+
+        var p = n.Parent;
+        if (p == null)
+          continue;
+
+        childrenCount[p]--;
+
+        if (childrenCount[p] == 0)
+          queue.Enqueue(p);
+      }
+
+      return nodeMap;
+    }
+
+    private IEnumerable<ISymbolicExpressionTreeNode> IterateBreadthOrdered(ISymbolicExpressionTreeNode node, ISymbolicExpressionTreeNodeComparer comparer) {
+      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(x => x, comparer) : n.Subtrees;
+          list.AddRange(subtrees);
+        }
+        i++;
+      }
+      return list;
+    }
+
+    private string Label(ISymbolicExpressionTreeNode node) {
+      if (node.SubtreeCount > 0)
+        return node.Symbol.Name;
+
+      var constant = node as ConstantTreeNode;
+      if (constant != null)
+        return MatchConstantValues ? constant.Value.ToString(CultureInfo.InvariantCulture) : constant.Symbol.Name;
+      var variable = node as VariableTreeNode;
+      if (variable != null) {
+        return MatchVariableWeights ? variable.Weight + variable.VariableName : variable.VariableName;
+      }
+
+      return node.ToString();
+    }
+
+    private class GraphNode {
+      public ISymbolicExpressionTreeNode SymbolicExpressionTreeNode;
+      public string Label;
+      public int Depth;
+      public int SubtreeCount { get { return SymbolicExpressionTreeNode.SubtreeCount; } }
+    }
+  }
+}
Index: stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/TreeMatching/SymbolicExpressionTreeCanonicalSorter.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/TreeMatching/SymbolicExpressionTreeCanonicalSorter.cs	(revision 11947)
+++ stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/TreeMatching/SymbolicExpressionTreeCanonicalSorter.cs	(revision 11947)
@@ -0,0 +1,30 @@
+﻿
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
+
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
+  public class SymbolicExpressionTreeCanonicalSorter {
+    private readonly HashSet<Type> nonSymmetricSymbols = new HashSet<Type> { typeof(Subtraction), typeof(Division) };
+
+    public void SortSubtrees(ISymbolicExpressionTree tree) {
+      SortSubtrees(tree.Root);
+    }
+
+    public void SortSubtrees(ISymbolicExpressionTreeNode node) {
+      if (node.SubtreeCount == 0) return;
+      var subtrees = node.Subtrees as List<ISymbolicExpressionTreeNode> ?? node.Subtrees.ToList();
+      if (IsSymmetric(node.Symbol)) {
+        var comparer = new SymbolicExpressionTreeNodeComparer();
+        subtrees.Sort(comparer);
+      }
+      foreach (var s in subtrees)
+        SortSubtrees(s);
+    }
+
+    private bool IsSymmetric(ISymbol s) {
+      return !nonSymmetricSymbols.Contains(s.GetType());
+    }
+  }
+}
Index: stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/TreeMatching/SymbolicExpressionTreeEqualityComparer.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/TreeMatching/SymbolicExpressionTreeEqualityComparer.cs	(revision 11947)
+++ stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/TreeMatching/SymbolicExpressionTreeEqualityComparer.cs	(revision 11947)
@@ -0,0 +1,18 @@
+﻿using System;
+using System.Collections.Generic;
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
+
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
+  public class SymbolicExpressionTreeEqualityComparer : IEqualityComparer<ISymbolicExpressionTree> {
+    public SymbolicExpressionTreeNodeEqualityComparer SimilarityComparer { get; set; }
+
+    public bool Equals(ISymbolicExpressionTree a, ISymbolicExpressionTree b) {
+      if (SimilarityComparer == null) throw new Exception("SimilarityComparer needs to be initialized first.");
+      return a.Length == b.Length && SymbolicExpressionTreeMatching.Match(a.Root, b.Root, SimilarityComparer) == Math.Min(a.Length, b.Length);
+    }
+
+    public int GetHashCode(ISymbolicExpressionTree tree) {
+      return (tree.Length << 8) % 12345;
+    }
+  }
+}
Index: stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/TreeMatching/SymbolicExpressionTreeMatching.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/TreeMatching/SymbolicExpressionTreeMatching.cs	(revision 11947)
+++ stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/TreeMatching/SymbolicExpressionTreeMatching.cs	(revision 11947)
@@ -0,0 +1,125 @@
+﻿#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.Encodings.SymbolicExpressionTreeEncoding;
+//using HeuristicLab.EvolutionTracking;
+
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
+  public static class SymbolicExpressionTreeMatching {
+    public static bool ContainsSubtree(this ISymbolicExpressionTreeNode root, ISymbolicExpressionTreeNode subtree, SymbolicExpressionTreeNodeEqualityComparer comparer) {
+      return FindMatches(root, subtree, comparer).Any();
+    }
+    public static IEnumerable<ISymbolicExpressionTreeNode> FindMatches(ISymbolicExpressionTree tree, ISymbolicExpressionTreeNode subtree, SymbolicExpressionTreeNodeEqualityComparer comparer) {
+      return FindMatches(tree.Root, subtree, comparer);
+    }
+
+    public static IEnumerable<ISymbolicExpressionTreeNode> FindMatches(ISymbolicExpressionTreeNode root, ISymbolicExpressionTreeNode subtree, SymbolicExpressionTreeNodeEqualityComparer comp) {
+      var fragmentLength = subtree.GetLength();
+      // below, we use ">=" for Match(n, subtree, comp) >= fragmentLength because in case of relaxed conditions, 
+      // we can have multiple matches of the same node
+
+      return root.IterateNodesBreadth().Where(n => n.GetLength() >= fragmentLength && Match(n, subtree, comp) == fragmentLength);
+    }
+
+    ///<summary>
+    /// Finds the longest common subsequence in quadratic time and linear space
+    /// Variant of:
+    /// D. S. Hirschberg. A linear space algorithm for or computing maximal common subsequences. 1975.
+    /// http://dl.acm.org/citation.cfm?id=360861
+    /// </summary>
+    /// <returns>Number of pairs that were matched</returns>
+    public static int Match(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b, ISymbolicExpressionTreeNodeSimilarityComparer comp) {
+      if (!comp.Equals(a, b)) return 0;
+      int m = a.SubtreeCount;
+      int n = b.SubtreeCount;
+      if (m == 0 || n == 0) return 1;
+      var matrix = new int[m + 1, n + 1];
+      for (int i = 1; i <= m; ++i) {
+        var ai = a.GetSubtree(i - 1);
+        for (int j = 1; j <= n; ++j) {
+          var bj = b.GetSubtree(j - 1);
+          int match = Match(ai, bj, comp);
+          matrix[i, j] = Math.Max(Math.Max(matrix[i, j - 1], matrix[i - 1, j]), matrix[i - 1, j - 1] + match);
+        }
+      }
+      return matrix[m, n] + 1;
+    }
+
+    /// <summary>
+    /// Calculates the difference between two symbolic expression trees.
+    /// </summary>
+    /// <param name="tree">The first symbolic expression tree</param>
+    /// <param name="other">The second symbolic expression tree</param>
+    /// <returns>Returns the root of the subtree (from T1) by which T1 differs from T2, or null if no difference is found.</returns>
+    public static ISymbolicExpressionTreeNode Difference(this ISymbolicExpressionTree tree, ISymbolicExpressionTree other) {
+      return Difference(tree.Root, other.Root);
+    }
+
+    public static ISymbolicExpressionTreeNode Difference(this ISymbolicExpressionTreeNode node, ISymbolicExpressionTreeNode other) {
+      var a = node.IterateNodesPrefix().ToList();
+      var b = other.IterateNodesPrefix().ToList();
+      var list = new List<ISymbolicExpressionTreeNode>();
+      for (int i = 0, j = 0; i < a.Count && j < b.Count; ++i, ++j) {
+        var s1 = a[i].ToString();
+        var s2 = b[j].ToString();
+        if (s1 == s2) continue;
+        list.Add(a[i]);
+        // skip subtrees since the parents are already different
+        i += a[i].SubtreeCount;
+        j += b[j].SubtreeCount;
+      }
+      ISymbolicExpressionTreeNode result = list.Count > 0 ? LowestCommonAncestor(node, list) : null;
+      return result;
+    }
+
+    private static ISymbolicExpressionTreeNode LowestCommonAncestor(ISymbolicExpressionTreeNode root, List<ISymbolicExpressionTreeNode> nodes) {
+      if (nodes.Count == 0)
+        throw new ArgumentException("The nodes list should contain at least one element.");
+
+      if (nodes.Count == 1)
+        return nodes[0];
+
+      int minLevel = nodes.Min(x => root.GetBranchLevel(x));
+
+      // bring the nodes in the nodes to the same level (relative to the root)
+      for (int i = 0; i < nodes.Count; ++i) {
+        var node = nodes[i];
+        var level = root.GetBranchLevel(node);
+        for (int j = minLevel; j < level; ++j)
+          node = node.Parent;
+        nodes[i] = node;
+      }
+
+      // while not all the elements in the nodes are equal, go one level up
+      while (nodes.Any(x => x != nodes[0])) {
+        for (int i = 0; i < nodes.Count; ++i)
+          nodes[i] = nodes[i].Parent;
+      }
+
+      return nodes[0];
+    }
+  }
+}
Index: stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/TreeMatching/SymbolicExpressionTreeMaxCommonSubtreeSimilarityCalculator.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/TreeMatching/SymbolicExpressionTreeMaxCommonSubtreeSimilarityCalculator.cs	(revision 11947)
+++ stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/TreeMatching/SymbolicExpressionTreeMaxCommonSubtreeSimilarityCalculator.cs	(revision 11947)
@@ -0,0 +1,105 @@
+﻿#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 {
+  [StorableClass]
+  [Item("SymbolicExpressionTreeMaxCommonSubtreeSimilarityCalculator", "A similarity calculator based on the size of the maximum common subtree between two trees")]
+  public class SymbolicExpressionTreeMaxCommonSubtreeSimilarityCalculator : SingleObjectiveSolutionSimilarityCalculator {
+    [Storable]
+    private readonly SymbolicExpressionTreeNodeEqualityComparer comparer;
+    public bool MatchVariableWeights {
+      get { return comparer.MatchVariableWeights; }
+      set { comparer.MatchVariableWeights = value; }
+    }
+
+    public bool MatchConstantValues {
+      get { return comparer.MatchConstantValues; }
+      set { comparer.MatchConstantValues = value; }
+    }
+
+    [StorableConstructor]
+    protected SymbolicExpressionTreeMaxCommonSubtreeSimilarityCalculator(bool deserializing) : base(deserializing) { }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new SymbolicExpressionTreeMaxCommonSubtreeSimilarityCalculator(this, cloner);
+    }
+
+    protected SymbolicExpressionTreeMaxCommonSubtreeSimilarityCalculator(SymbolicExpressionTreeMaxCommonSubtreeSimilarityCalculator original, Cloner cloner)
+      : base(original, cloner) {
+      comparer = cloner.Clone(original.comparer);
+    }
+
+    public SymbolicExpressionTreeMaxCommonSubtreeSimilarityCalculator() {
+      comparer = new SymbolicExpressionTreeNodeEqualityComparer {
+        MatchConstantValues = true,
+        MatchVariableNames = true,
+        MatchVariableWeights = true
+      };
+    }
+
+    public SymbolicExpressionTreeMaxCommonSubtreeSimilarityCalculator(bool matchVariableWeights, bool matchConstantValues) {
+      comparer = new SymbolicExpressionTreeNodeEqualityComparer {
+        MatchConstantValues = matchConstantValues,
+        MatchVariableNames = true,
+        MatchVariableWeights = matchVariableWeights
+      };
+    }
+
+    public double CalculateSimilarity(ISymbolicExpressionTree t1, ISymbolicExpressionTree t2) {
+      return MaxCommonSubtreeSimilarity(t1, t2, comparer);
+    }
+
+    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 MaxCommonSubtreeSimilarity(t1, t2, comparer);
+    }
+
+    public static double MaxCommonSubtreeSimilarity(ISymbolicExpressionTree a, ISymbolicExpressionTree b, ISymbolicExpressionTreeNodeSimilarityComparer 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: stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/TreeMatching/SymbolicExpressionTreeNodeComparer.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/TreeMatching/SymbolicExpressionTreeNodeComparer.cs	(revision 11947)
+++ stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/TreeMatching/SymbolicExpressionTreeNodeComparer.cs	(revision 11947)
@@ -0,0 +1,72 @@
+﻿#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.Encodings.SymbolicExpressionTreeEncoding;
+
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
+  // this comparer considers that a < b if the type of a is "greater" than the type of b, for example:
+  // - A function node is "greater" than a terminal node
+  // - A variable terminal is "greater" than a constant terminal
+  // - used for bringing subtrees to a "canonical" form when the operation allows reordering of arguments
+  public class SymbolicExpressionTreeNodeComparer : ISymbolicExpressionTreeNodeComparer {
+    public static int CompareNodes(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
+      var ta = a as SymbolicExpressionTreeTerminalNode;
+      var tb = b as SymbolicExpressionTreeTerminalNode;
+
+      if (ta == null)
+        return tb == null ? String.CompareOrdinal(a.Symbol.Name, b.Symbol.Name) : -1;
+
+      if (tb == null)
+        return 1;
+
+      // at this point we know a and b are both terminals
+      var va = a as VariableTreeNode;
+      var vb = b as VariableTreeNode;
+
+      if (va != null)
+        return vb == null ? -1 : CompareVariables(va, vb);
+
+      if (vb != null)
+        return 1;
+
+      // at this point we know a and b are not variables
+      var ca = a as ConstantTreeNode;
+      var cb = b as ConstantTreeNode;
+
+      if (ca != null && cb != null)
+        return ca.Value.CompareTo(cb.Value);
+
+      // for other unknown terminal types, compare strings
+      return string.CompareOrdinal(a.ToString(), b.ToString());
+    }
+
+    private static int CompareVariables(VariableTreeNode a, VariableTreeNode b) {
+      int result = string.CompareOrdinal(a.VariableName, b.VariableName);
+      return result == 0 ? a.Weight.CompareTo(b.Weight) : result;
+    }
+
+    public int Compare(ISymbolicExpressionTreeNode x, ISymbolicExpressionTreeNode y) {
+      return CompareNodes(x, y);
+    }
+  }
+
+}
Index: stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/TreeMatching/SymbolicExpressionTreeNodeEqualityComparer.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/TreeMatching/SymbolicExpressionTreeNodeEqualityComparer.cs	(revision 11947)
+++ stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/TreeMatching/SymbolicExpressionTreeNodeEqualityComparer.cs	(revision 11947)
@@ -0,0 +1,97 @@
+﻿#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 HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
+  [Item("SymbolicExpressionTreeNodeEqualityComparer", "An operator that checks node equality based on different similarity measures.")]
+  [StorableClass]
+  public class SymbolicExpressionTreeNodeEqualityComparer : Item, ISymbolicExpressionTreeNodeSimilarityComparer {
+    [StorableConstructor]
+    protected SymbolicExpressionTreeNodeEqualityComparer(bool deserializing) : base(deserializing) { }
+    protected SymbolicExpressionTreeNodeEqualityComparer(SymbolicExpressionTreeNodeEqualityComparer original, Cloner cloner)
+      : base(original, cloner) {
+      matchConstantValues = original.matchConstantValues;
+      matchVariableNames = original.matchVariableNames;
+      matchVariableWeights = original.matchVariableWeights;
+    }
+    public override IDeepCloneable Clone(Cloner cloner) { return new SymbolicExpressionTreeNodeEqualityComparer(this, cloner); }
+
+    // more flexible matching criteria 
+    [Storable]
+    private bool matchConstantValues;
+    public bool MatchConstantValues {
+      get { return matchConstantValues; }
+      set { matchConstantValues = value; }
+    }
+
+    [Storable]
+    private bool matchVariableNames;
+    public bool MatchVariableNames {
+      get { return matchVariableNames; }
+      set { matchVariableNames = value; }
+    }
+
+    [Storable]
+    private bool matchVariableWeights;
+    public bool MatchVariableWeights {
+      get { return matchVariableWeights; }
+      set { matchVariableWeights = value; }
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+    }
+
+    public SymbolicExpressionTreeNodeEqualityComparer() {
+      matchConstantValues = true;
+      matchVariableNames = true;
+      matchVariableWeights = true;
+    }
+
+    public int GetHashCode(ISymbolicExpressionTreeNode n) {
+      return n.ToString().ToLower().GetHashCode();
+    }
+
+    public bool Equals(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
+      if (!(a is SymbolicExpressionTreeTerminalNode))
+        // if a and b are non terminal nodes, check equality of symbol names
+        return !(b is SymbolicExpressionTreeTerminalNode) && a.Symbol.Name.Equals(b.Symbol.Name);
+      var va = a as VariableTreeNode;
+      if (va != null) {
+        var vb = b as VariableTreeNode;
+        if (vb == null) return false;
+
+        return (!MatchVariableNames || va.VariableName.Equals(vb.VariableName)) && (!MatchVariableWeights || va.Weight.Equals(vb.Weight));
+      }
+      var ca = a as ConstantTreeNode;
+      if (ca != null) {
+        var cb = b as ConstantTreeNode;
+        if (cb == null) return false;
+        return (!MatchConstantValues || ca.Value.Equals(cb.Value));
+      }
+      return false;
+    }
+  }
+}
Index: stable/HeuristicLab.Tests/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4/SymbolicExpressionTreeBottomUpSimilarityCalculatorTest.cs
===================================================================
--- stable/HeuristicLab.Tests/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4/SymbolicExpressionTreeBottomUpSimilarityCalculatorTest.cs	(revision 11947)
+++ stable/HeuristicLab.Tests/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4/SymbolicExpressionTreeBottomUpSimilarityCalculatorTest.cs	(revision 11947)
@@ -0,0 +1,86 @@
+﻿using System;
+using System.Diagnostics;
+using HeuristicLab.Random;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic.Tests {
+  [TestClass]
+  public class BottomUpSimilarityCalculatorTest {
+    private readonly SymbolicExpressionTreeBottomUpSimilarityCalculator busCalculator;
+    private readonly SymbolicExpressionImporter importer;
+
+    private const int N = 150;
+    private const int Rows = 1;
+    private const int Columns = 10;
+
+    public BottomUpSimilarityCalculatorTest() {
+      busCalculator = new SymbolicExpressionTreeBottomUpSimilarityCalculator { MatchConstantValues = true, MatchVariableWeights = true };
+      importer = new SymbolicExpressionImporter();
+    }
+
+    [TestMethod]
+    [TestCategory("Problems.DataAnalysis.Symbolic")]
+    [TestProperty("Time", "short")]
+    public void BottomUpTreeSimilarityCalculatorTestMapping() {
+      TestMatchedNodes("(+ 1 2)", "(+ 2 1)", 5);
+      TestMatchedNodes("(- 2 1)", "(- 1 2)", 2);
+      TestMatchedNodes("(* (variable 1 X1) (variable 1 X2))", "(* (+ (variable 1 X1) 1) (+ (variable 1 X2) 1))", 2);
+
+      TestMatchedNodes("(* (variable 1 X1) (variable 1 X2))", "(* (+ (variable 1 X1) 1) (variable 1 X2))", 2);
+
+      TestMatchedNodes("(+ (variable 1 a) (variable 1 b))", "(+ (variable 1 a) (variable 1 a))", 1);
+      TestMatchedNodes("(+ (+ (variable 1 a) (variable 1 b)) (variable 1 b))", "(+ (* (+ (variable 1 a) (variable 1 b)) (variable 1 b)) (+ (+ (variable 1 a) (variable 1 b)) (variable 1 b)))", 5);
+
+      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);
+
+      const string expr1 = "(* (- 1.2175e+1 (+ (/ (exp -1.4134e+1) (exp 9.2013)) (exp (log (exp (/ (exp (- (* -4.2461 (variable 2.2634 X5)) (- -9.6267e-1 3.3243))) (- (/ (/ (variable 1.0883 X1) (variable 6.9620e-1 X2)) (log 1.3011e+1)) (variable -4.3098e-1 X7)))))))) (log 1.3011e+1))";
+      const string expr2 = "(* (- 1.2175e+1 (+ (/ (/ (+ (variable 3.0140 X9) (variable 1.3430 X8)) -1.0864e+1) (exp 9.2013)) (exp (log (exp (/ (exp (- (* -4.2461 (variable 2.2634 X5)) (- -9.6267e-1 3.3243))) (- (/ (/ (variable 1.0883 X1) (variable 6.9620e-1 X2)) (log 1.3011e+1)) (variable -4.3098e-1 X7)))))))) (exp (variable 4.0899e-1 X7)))";
+
+      TestMatchedNodes(expr1, expr2, 23);
+
+    }
+
+    private void TestMatchedNodes(string expr1, string expr2, int expected) {
+      var t1 = importer.Import(expr1);
+      var t2 = importer.Import(expr2);
+
+      var mapping = busCalculator.ComputeBottomUpMapping(t1.Root, t2.Root);
+      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 BottomUpTreeSimilarityCalculatorTestPerformance() {
+      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.CalculateSimilarity(trees[i], trees[j]);
+        }
+      }
+
+      sw.Stop();
+      Console.WriteLine("Elapsed time: " + sw.ElapsedMilliseconds / 1000.0 + ", Avg. similarity: " + s / (N * (N - 1) / 2));
+      Console.WriteLine(N * (N + 1) / (2 * sw.ElapsedMilliseconds / 1000.0) + " similarity calculations per second.");
+    }
+  }
+}
Index: stable/HeuristicLab.Tests/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4/SymbolicExpressionTreeMaxCommonSubtreeSimilarityCalculatorTest.cs
===================================================================
--- stable/HeuristicLab.Tests/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4/SymbolicExpressionTreeMaxCommonSubtreeSimilarityCalculatorTest.cs	(revision 11947)
+++ stable/HeuristicLab.Tests/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4/SymbolicExpressionTreeMaxCommonSubtreeSimilarityCalculatorTest.cs	(revision 11947)
@@ -0,0 +1,71 @@
+﻿using System;
+using System.Diagnostics;
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
+using HeuristicLab.Problems.DataAnalysis.Symbolic;
+using HeuristicLab.Problems.DataAnalysis.Symbolic.Tests;
+using HeuristicLab.Random;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+
+namespace HeuristicLab.Tests {
+  /// <summary>
+  /// Summary description for MaxCommonSubtreeSimilarityCalculatorTest
+  /// </summary>
+  [TestClass]
+  public class SymbolicExpressionTreeMaxCommonSubtreeSimilarityCalculatorTest {
+    private readonly ISymbolicExpressionTreeNodeSimilarityComparer comparer;
+
+    private const int N = 100;
+    private const int Rows = 1;
+    private const int Columns = 10;
+
+    public SymbolicExpressionTreeMaxCommonSubtreeSimilarityCalculatorTest() {
+      comparer = new SymbolicExpressionTreeNodeEqualityComparer();
+    }
+
+    #region Additional test attributes
+    //
+    // You can use the following additional attributes as you write your tests:
+    //
+    // Use ClassInitialize to run code before running the first test in the class
+    // [ClassInitialize()]
+    // public static void MyClassInitialize(TestContext testContext) { }
+    //
+    // Use ClassCleanup to run code after all tests in a class have run
+    // [ClassCleanup()]
+    // public static void MyClassCleanup() { }
+    //
+    // Use TestInitialize to run code before running each test 
+    // [TestInitialize()]
+    // public void MyTestInitialize() { }
+    //
+    // Use TestCleanup to run code after each test has run
+    // [TestCleanup()]
+    // public void MyTestCleanup() { }
+    //
+    #endregion
+
+    [TestMethod]
+    [TestCategory("Problems.DataAnalysis.Symbolic")]
+    [TestProperty("Time", "long")]
+    public void MaxCommonSubtreeSimilarityCalculatorTestPerformance() {
+      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 += SymbolicExpressionTreeMaxCommonSubtreeSimilarityCalculator.MaxCommonSubtreeSimilarity(trees[i], trees[j], comparer);
+        }
+      }
+      sw.Stop();
+      Console.WriteLine("Elapsed time: " + sw.ElapsedMilliseconds / 1000.0 + ", Avg. similarity: " + s / (N * (N - 1) / 2));
+      Console.WriteLine(N * (N + 1) / (2 * sw.ElapsedMilliseconds / 1000.0) + " similarity calculations per second.");
+    }
+  }
+}
Index: stable/HeuristicLab.Tests/HeuristicLab.Tests.csproj
===================================================================
--- stable/HeuristicLab.Tests/HeuristicLab.Tests.csproj	(revision 11943)
+++ stable/HeuristicLab.Tests/HeuristicLab.Tests.csproj	(revision 11947)
@@ -492,4 +492,6 @@
     <Compile Include="HeuristicLab.Problems.DataAnalysis-3.4\OnlineCalculatorPerformanceTest.cs" />
     <Compile Include="HeuristicLab.Problems.DataAnalysis-3.4\StatisticCalculatorsTest.cs" />
+    <Compile Include="HeuristicLab.Problems.DataAnalysis.Symbolic-3.4\SymbolicExpressionTreeBottomUpSimilarityCalculatorTest.cs" />
+    <Compile Include="HeuristicLab.Problems.DataAnalysis.Symbolic-3.4\SymbolicExpressionTreeMaxCommonSubtreeSimilarityCalculatorTest.cs" />
     <Compile Include="HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis-3.4\SymbolicDataAnalysisExpressionTreeInterpreterTest.cs" />
     <Compile Include="HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis-3.4\Util.cs" />
