Index: branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Analyzers/SymbolicDataAnalysisBuildingBlockAnalyzer.cs
===================================================================
--- branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Analyzers/SymbolicDataAnalysisBuildingBlockAnalyzer.cs	(revision 16388)
+++ branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Analyzers/SymbolicDataAnalysisBuildingBlockAnalyzer.cs	(revision 16388)
@@ -0,0 +1,222 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2018 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 System.Text;
+using HeuristicLab.Analysis;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using static HeuristicLab.Problems.DataAnalysis.Symbolic.SymbolicExpressionHashExtensions;
+
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic.Analyzers {
+  [Item("SymbolicDataAnalysisBuildingBlockAnalyzer", "An analyzer that uses tree hashing to identify the most common subtrees (building blocks) in the population")]
+  [StorableClass]
+  public sealed class SymbolicDataAnalysisBuildingBlockAnalyzer : SymbolicDataAnalysisAnalyzer {
+    private const string BuildingBlocksResultName = "BuildingBlocks";
+    private const string SolutionUniquenessResultName = "SolutionUniqueness";
+    private const string MinimumSubtreeLengthParameterName = "MinimumSubtreeLength";
+    private const string SimplifyTreesParameterName = "SimplifyTrees";
+
+    private Dictionary<ulong, DataRow> hashToRow = new Dictionary<ulong, DataRow>();
+
+    #region parameters
+    public IValueLookupParameter<IntValue> MinimumSubtreeLengthParameter {
+      get { return (IValueLookupParameter<IntValue>)Parameters[MinimumSubtreeLengthParameterName]; }
+    }
+
+    public IValueLookupParameter<BoolValue> SimplifyTreesParameter {
+      get { return (IValueLookupParameter<BoolValue>)Parameters[SimplifyTreesParameterName]; }
+    }
+    #endregion
+
+    #region parameter properties
+    public IntValue MinimumSubtreeLength {
+      get { return MinimumSubtreeLengthParameter.ActualValue; }
+    }
+
+    public BoolValue SimplifyTrees {
+      get { return SimplifyTreesParameter.ActualValue; }
+    }
+    #endregion
+
+    public override void InitializeState() {
+      base.InitializeState();
+
+      hashToRow = new Dictionary<ulong, DataRow>();
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      if (!Parameters.ContainsKey(SimplifyTreesParameterName)) {
+        Parameters.Add(new ValueLookupParameter<BoolValue>(SimplifyTreesParameterName, new BoolValue(false)));
+      }
+    }
+
+    public SymbolicDataAnalysisBuildingBlockAnalyzer() {
+      Parameters.Add(new ValueLookupParameter<IntValue>(MinimumSubtreeLengthParameterName, new IntValue(3)));
+      Parameters.Add(new ValueLookupParameter<BoolValue>(SimplifyTreesParameterName, new BoolValue(false)));
+    }
+
+    private SymbolicDataAnalysisBuildingBlockAnalyzer(SymbolicDataAnalysisBuildingBlockAnalyzer original, Cloner cloner) : base(original, cloner) {
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new SymbolicDataAnalysisBuildingBlockAnalyzer(this, cloner);
+    }
+
+    [StorableConstructor]
+    private SymbolicDataAnalysisBuildingBlockAnalyzer(bool deserializing) : base(deserializing) { }
+
+    private readonly Func<byte[], ulong> hashFunction = HashUtil.JSHash;
+
+    public override IOperation Apply() {
+      DataTable dt;
+
+      if (!ResultCollection.ContainsKey(BuildingBlocksResultName)) {
+        dt = new DataTable(BuildingBlocksResultName);
+        ResultCollection.Add(new Result(BuildingBlocksResultName, dt));
+      } else {
+        dt = (DataTable)ResultCollection[BuildingBlocksResultName].Value;
+      }
+
+      var minLength = MinimumSubtreeLength.Value - 1; // -1 because the HashNode.Size property returns the size without current node (-1)
+      var simplify = SimplifyTrees.Value;
+
+      var expressions = new Dictionary<ulong, string>();
+      var expressionCounts = new Dictionary<ulong, int>();
+
+      int totalCount = 0; // total number of examined subtrees
+
+      var hashes = new List<ulong>();
+      // count hashes
+      foreach (var tree in SymbolicExpressionTree) {
+        var hashNodes = tree.Root.GetSubtree(0).GetSubtree(0).MakeNodes();
+        var simplified = simplify ? hashNodes.Simplify(hashFunction) : hashNodes.Sort(hashFunction);
+        hashes.Add(simplified.Last().CalculatedHashValue); // maybe calculate aggregate hash instead
+
+        for (int i = 0; i < simplified.Length; i++) {
+          HashNode<ISymbolicExpressionTreeNode> s = simplified[i];
+          if (s.IsLeaf || s.Size < minLength) {
+            continue;
+          }
+          ++totalCount;
+          var hash = s.CalculatedHashValue;
+          if (expressions.ContainsKey(hash)) {
+            expressionCounts[hash]++;
+            continue;
+          }
+
+          var sb = new StringBuilder();
+          for (int j = i - s.Size; j < i; ++j) {
+            sb.Append(GetLabel(simplified[j].Data)).Append(" ");
+          }
+          sb.Append(GetLabel(simplified[i].Data));
+          expressions[hash] = sb.ToString();
+          expressionCounts[hash] = 1;
+        }
+      }
+
+      // fill in values for existing rows
+      foreach (var t in hashToRow) {
+        var hash = t.Key;
+        var row = t.Value;
+
+        expressionCounts.TryGetValue(hash, out int count);
+        row.Values.Add(count);
+      }
+
+      var nValues = dt.Rows.Any() ? dt.Rows.Max(x => x.Values.Count) : 0;
+
+      // check if we have new rows
+      foreach (var t in expressionCounts.OrderByDescending(x => x.Value).Take(10)) {
+        var hash = t.Key;
+        var count = t.Value;
+        var label = expressions[hash];
+
+        if (hashToRow.ContainsKey(hash)) {
+          continue;
+        }
+        var row = new DataRow(label) { VisualProperties = { StartIndexZero = true } };
+        if (nValues > 0) {
+          row.Values.AddRange(Enumerable.Repeat<double>(0, nValues - 1)); // pad with zeroes
+        }
+        row.Values.Add(count);
+        dt.Rows.Add(row);
+        hashToRow[hash] = row;
+      }
+
+      // compute solution uniqueness
+      DataTableHistory dth;
+      var counts = hashes.GroupBy(x => x).ToDictionary(x => x.Key, x => x.Count());
+      if (!ResultCollection.ContainsKey(SolutionUniquenessResultName)) {
+        dth = new DataTableHistory();
+        ResultCollection.Add(new Result(SolutionUniquenessResultName, dth));
+      } else {
+        dth = (DataTableHistory)ResultCollection[SolutionUniquenessResultName].Value;
+      }
+
+      var ct = new DataTable("Unique Solutions");
+      var ctr = new DataRow { VisualProperties = { StartIndexZero = true, ChartType = DataRowVisualProperties.DataRowChartType.Columns } };
+      ctr.Values.AddRange(hashes.Select(x => (double)counts[x]).OrderByDescending(x => x));
+      ct.Rows.Add(ctr);
+      dth.Add(ct);
+
+      var max = dth.Max(x => x.Rows.First().Values.Max());
+      foreach (var table in dth) {
+        table.VisualProperties.YAxisMinimumAuto = false;
+        table.VisualProperties.YAxisMaximumAuto = false;
+        table.VisualProperties.YAxisMinimumFixedValue = 0;
+        table.VisualProperties.YAxisMaximumFixedValue = max;
+      }
+
+      return base.Apply();
+    }
+
+    private static string GetLabel(ISymbolicExpressionTreeNode node) {
+      if (node is ConstantTreeNode constant) {
+        return "C";
+      }
+      if (node is VariableTreeNode variable) {
+        return variable.VariableName;
+      }
+      if (node.Symbol is Addition) {
+        return "+";
+      }
+      if (node.Symbol is Subtraction) {
+        return "-";
+      }
+      if (node.Symbol is Multiplication) {
+        return "*";
+      }
+      if (node.Symbol is Division) {
+        return "/";
+      }
+      return node.Symbol.ToString();
+    }
+  }
+}
Index: branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Converters/DerivativeCalculator.cs
===================================================================
--- branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Converters/DerivativeCalculator.cs	(revision 16388)
+++ branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Converters/DerivativeCalculator.cs	(revision 16388)
@@ -0,0 +1,231 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2018 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;
+
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
+  public static class DerivativeCalculator {
+    public static ISymbolicExpressionTree Derive(ISymbolicExpressionTree tree, string variableName) {
+      if (tree.Root.SubtreeCount != 1)
+        throw new NotImplementedException("Derive is not implemented for symbolic expressions with automatically defined functions (ADF)");
+      if (tree.Root.GetSubtree(0).SubtreeCount != 1)
+        throw new NotImplementedException("Derive is not implemented for multi-variate symbolic expressions");
+      var mainBranch = tree.Root.GetSubtree(0).GetSubtree(0);
+      var root = new ProgramRootSymbol().CreateTreeNode();
+      root.AddSubtree(new StartSymbol().CreateTreeNode());
+      var dTree = TreeSimplifier.GetSimplifiedTree(Derive(mainBranch, variableName));
+      //var dTree = Derive(mainBranch, variableName);
+      root.GetSubtree(0).AddSubtree(dTree);
+      return new SymbolicExpressionTree(root);
+    }
+
+    private static readonly Constant constantSy = new Constant();
+    private static readonly Addition addSy = new Addition();
+    private static readonly Subtraction subSy = new Subtraction();
+    private static readonly Multiplication mulSy = new Multiplication();
+    private static readonly Division divSy = new Division();
+    private static readonly Cosine cosSy = new Cosine();
+    private static readonly Square sqrSy = new Square();
+
+    public static ISymbolicExpressionTreeNode Derive(ISymbolicExpressionTreeNode branch, string variableName) {
+      if (branch.Symbol is Constant) {
+        return CreateConstant(0.0);
+      }
+      if (branch.Symbol is Variable) {
+        var varNode = branch as VariableTreeNode;
+        if (varNode.VariableName == variableName) {
+          return CreateConstant(varNode.Weight);
+        } else {
+          return CreateConstant(0.0);
+        }
+      }
+      if (branch.Symbol is Addition) {
+        var sum = addSy.CreateTreeNode();
+        foreach (var subTree in branch.Subtrees) {
+          sum.AddSubtree(Derive(subTree, variableName));
+        }
+        return sum;
+      }
+      if (branch.Symbol is Subtraction) {
+        var sum = subSy.CreateTreeNode();
+        foreach (var subTree in branch.Subtrees) {
+          sum.AddSubtree(Derive(subTree, variableName));
+        }
+        return sum;
+      }
+      if (branch.Symbol is Multiplication) {
+        // (f * g)' = f'*g + f*g'
+        // for multiple factors: (f * g * h)' = ((f*g) * h)' = (f*g)' * h + (f*g) * h' 
+
+        if (branch.SubtreeCount >= 2) {
+          var f = (ISymbolicExpressionTreeNode)branch.GetSubtree(0).Clone();
+          var g = (ISymbolicExpressionTreeNode)branch.GetSubtree(1).Clone();
+          var fprime = Derive(f, variableName);
+          var gprime = Derive(g, variableName);
+          var fgPrime = Sum(Product(f, gprime), Product(fprime, g));
+          for (int i = 2; i < branch.SubtreeCount; i++) {
+            var fg = Product((ISymbolicExpressionTreeNode)f.Clone(), (ISymbolicExpressionTreeNode)g.Clone());
+            var h = (ISymbolicExpressionTreeNode)branch.GetSubtree(i).Clone();
+            var hPrime = Derive(h, variableName);
+            fgPrime = Sum(Product(fgPrime, h), Product(fg, hPrime));
+          }
+          return fgPrime;
+        } else
+          // multiplication with only one argument has no effect -> derive the argument
+          return Derive(branch.GetSubtree(0), variableName);
+      }
+      if (branch.Symbol is Division) {
+        // (f/g)' = (f'g - g'f) / g²
+        if (branch.SubtreeCount == 1) {
+          var g = (ISymbolicExpressionTreeNode)branch.GetSubtree(0).Clone();
+          var gPrime = Product(CreateConstant(-1.0), Derive(g, variableName));
+          var sqrNode = new Square().CreateTreeNode();
+          sqrNode.AddSubtree(g);
+          return Div(gPrime, sqrNode);
+        } else {
+          // for two subtrees:
+          // (f/g)' = (f'g - fg')/g²
+
+          // if there are more than 2 subtrees
+          // div(x,y,z) is interpretered as (x/y)/z
+          // which is the same as x / (y*z)
+
+          // --> make a product of all but the first subtree and differentiate as for the 2-argument case above
+          var f = (ISymbolicExpressionTreeNode)branch.GetSubtree(0).Clone();
+          var g = Product(branch.Subtrees.Skip(1).Select(n => (ISymbolicExpressionTreeNode)n.Clone()));
+          var fprime = Derive(f, variableName);
+          var gprime = Derive(g, variableName);
+          var gSqr = Square(g);
+          return Div(Subtract(Product(fprime, g), Product(f, gprime)), gSqr);
+        }
+      }
+      if (branch.Symbol is Logarithm) {
+        var f = (ISymbolicExpressionTreeNode)branch.GetSubtree(0).Clone();
+        return Product(Div(CreateConstant(1.0), f), Derive(f, variableName));
+      }
+      if (branch.Symbol is Exponential) {
+        var f = (ISymbolicExpressionTreeNode)branch.Clone();
+        return Product(f, Derive(branch.GetSubtree(0), variableName));
+      }
+      if (branch.Symbol is Square) {
+        var f = (ISymbolicExpressionTreeNode)branch.GetSubtree(0).Clone();
+        return Product(Product(CreateConstant(2.0), f), Derive(f, variableName));
+      }
+      if (branch.Symbol is SquareRoot) {
+        var f = (ISymbolicExpressionTreeNode)branch.Clone();
+        var u = (ISymbolicExpressionTreeNode)branch.GetSubtree(0).Clone();
+        return Product(Div(CreateConstant(1.0), Product(CreateConstant(2.0), f)), Derive(u, variableName));
+      }
+      if (branch.Symbol is Sine) {
+        var u = (ISymbolicExpressionTreeNode)branch.GetSubtree(0).Clone();
+        var cos = (new Cosine()).CreateTreeNode();
+        cos.AddSubtree(u);
+        return Product(cos, Derive(u, variableName));
+      }
+      if (branch.Symbol is Cosine) {
+        var u = (ISymbolicExpressionTreeNode)branch.GetSubtree(0).Clone();
+        var sin = (new Sine()).CreateTreeNode();
+        sin.AddSubtree(u);
+        return Product(CreateConstant(-1.0), Product(sin, Derive(u, variableName)));
+      }
+      if (branch.Symbol is Tangent) {
+        // tan(x)' = 1 / cos²(x)
+        var fxp = Derive(branch.GetSubtree(0), variableName);
+        var u = (ISymbolicExpressionTreeNode)branch.GetSubtree(0).Clone();
+        return Div(fxp, Square(Cosine(u)));
+      }
+      throw new NotSupportedException(string.Format("Symbol {0} is not supported.", branch.Symbol));
+    }
+
+
+    private static ISymbolicExpressionTreeNode Product(ISymbolicExpressionTreeNode f, ISymbolicExpressionTreeNode g) {
+      var product = mulSy.CreateTreeNode();
+      product.AddSubtree(f);
+      product.AddSubtree(g);
+      return product;
+    }
+    private static ISymbolicExpressionTreeNode Product(IEnumerable<ISymbolicExpressionTreeNode> fs) {
+      var product = mulSy.CreateTreeNode();
+      foreach (var f in fs) product.AddSubtree(f);
+      return product;
+    }
+    private static ISymbolicExpressionTreeNode Div(ISymbolicExpressionTreeNode f, ISymbolicExpressionTreeNode g) {
+      var div = divSy.CreateTreeNode();
+      div.AddSubtree(f);
+      div.AddSubtree(g);
+      return div;
+    }
+
+    private static ISymbolicExpressionTreeNode Sum(ISymbolicExpressionTreeNode f, ISymbolicExpressionTreeNode g) {
+      var sum = addSy.CreateTreeNode();
+      sum.AddSubtree(f);
+      sum.AddSubtree(g);
+      return sum;
+    }
+    private static ISymbolicExpressionTreeNode Subtract(ISymbolicExpressionTreeNode f, ISymbolicExpressionTreeNode g) {
+      var sum = subSy.CreateTreeNode();
+      sum.AddSubtree(f);
+      sum.AddSubtree(g);
+      return sum;
+    }
+    private static ISymbolicExpressionTreeNode Cosine(ISymbolicExpressionTreeNode f) {
+      var cos = cosSy.CreateTreeNode();
+      cos.AddSubtree(f);
+      return cos;
+    }
+    private static ISymbolicExpressionTreeNode Square(ISymbolicExpressionTreeNode f) {
+      var sqr = sqrSy.CreateTreeNode();
+      sqr.AddSubtree(f);
+      return sqr;
+    }
+
+    private static ISymbolicExpressionTreeNode CreateConstant(double v) {
+      var constNode = (ConstantTreeNode)constantSy.CreateTreeNode();
+      constNode.Value = v;
+      return constNode;
+    }
+
+    public static bool IsCompatible(ISymbolicExpressionTree tree) {
+      var containsUnknownSymbol = (
+        from n in tree.Root.GetSubtree(0).IterateNodesPrefix()
+        where
+          !(n.Symbol is Variable) &&
+          !(n.Symbol is Constant) &&
+          !(n.Symbol is Addition) &&
+          !(n.Symbol is Subtraction) &&
+          !(n.Symbol is Multiplication) &&
+          !(n.Symbol is Division) &&
+          !(n.Symbol is Logarithm) &&
+          !(n.Symbol is Exponential) &&
+          !(n.Symbol is Square) &&
+          !(n.Symbol is SquareRoot) &&
+          !(n.Symbol is Sine) &&
+          !(n.Symbol is Cosine) &&
+          !(n.Symbol is Tangent) &&
+          !(n.Symbol is StartSymbol)
+        select n).Any();
+      return !containsUnknownSymbol;
+    }
+  }
+}
Index: branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Converters/LinearModelToTreeConverter.cs
===================================================================
--- branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Converters/LinearModelToTreeConverter.cs	(revision 15743)
+++ branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Converters/LinearModelToTreeConverter.cs	(revision 16388)
@@ -37,21 +37,27 @@
       string[] variableNames, double[] coefficients,
       double @const = 0) {
+
       if (factorCoefficients.Length == 0 && coefficients.Length == 0) throw new ArgumentException();
-      ISymbolicExpressionTree p1 = null;
+
+      // Create tree for double variables
+      ISymbolicExpressionTree tree = null;      
       if (coefficients.Length > 0) {
-        p1 = CreateTree(variableNames, new int[variableNames.Length], coefficients, @const);
-        if (factorCoefficients.Length == 0)
-          return p1;
+        tree = CreateTree(variableNames, new int[variableNames.Length], coefficients, @const);
+        if (factorCoefficients.Length == 0) return tree;
       }
+
+      // Create tree for string variables
+      ISymbolicExpressionTree factorTree = null;      
       if (factorCoefficients.Length > 0) {
-        var p2 = CreateTree(factors, factorCoefficients);
-        if (p1 == null) return p2;
+        factorTree = CreateTree(factors, factorCoefficients, @const);
+        if (tree == null) return factorTree;  
+      }
 
-        // combine
-        ISymbolicExpressionTreeNode add = p1.Root.GetSubtree(0).GetSubtree(0);
-        foreach (var binFactorNode in p2.IterateNodesPrefix().OfType<BinaryFactorVariableTreeNode>())
-          add.AddSubtree(binFactorNode);
-        return p1;
-      }
+      // Combine both trees
+      ISymbolicExpressionTreeNode add = tree.Root.GetSubtree(0).GetSubtree(0);
+      foreach (var binFactorNode in factorTree.IterateNodesPrefix().OfType<BinaryFactorVariableTreeNode>())
+        add.InsertSubtree(add.SubtreeCount - 1, binFactorNode);
+      return tree;
+
       throw new ArgumentException();
     }
Index: branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Converters/TreeSimplifier.cs
===================================================================
--- branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Converters/TreeSimplifier.cs	(revision 15743)
+++ branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Converters/TreeSimplifier.cs	(revision 16388)
@@ -37,4 +37,5 @@
     private static readonly Division divSymbol = new Division();
     private static readonly Constant constSymbol = new Constant();
+    private static readonly Absolute absSymbol = new Absolute();
     private static readonly Logarithm logSymbol = new Logarithm();
     private static readonly Exponential expSymbol = new Exponential();
@@ -42,4 +43,7 @@
     private static readonly Square sqrSymbol = new Square();
     private static readonly SquareRoot sqrtSymbol = new SquareRoot();
+    private static readonly AnalyticQuotient aqSymbol = new AnalyticQuotient();
+    private static readonly Cube cubeSymbol = new Cube();
+    private static readonly CubeRoot cubeRootSymbol = new CubeRoot();
     private static readonly Power powSymbol = new Power();
     private static readonly Sine sineSymbol = new Sine();
@@ -131,4 +135,8 @@
     }
 
+    private static bool IsAbsolute(ISymbolicExpressionTreeNode node) {
+      return node.Symbol is Absolute;
+    }
+
     // exponential
     private static bool IsLog(ISymbolicExpressionTreeNode node) {
@@ -152,4 +160,12 @@
     }
 
+    private static bool IsCube(ISymbolicExpressionTreeNode node) {
+      return node.Symbol is Cube;
+    }
+
+    private static bool IsCubeRoot(ISymbolicExpressionTreeNode node) {
+      return node.Symbol is CubeRoot;
+    }
+
     private static bool IsPower(ISymbolicExpressionTreeNode node) {
       return node.Symbol is Power;
@@ -167,4 +183,8 @@
     private static bool IsTangent(ISymbolicExpressionTreeNode node) {
       return node.Symbol is Tangent;
+    }
+
+    private static bool IsAnalyticalQuotient(ISymbolicExpressionTreeNode node) {
+      return node.Symbol is AnalyticQuotient;
     }
 
@@ -243,4 +263,6 @@
       if (IsConstant(original) || IsVariableBase(original)) {
         return (ISymbolicExpressionTreeNode)original.Clone();
+      } else if (IsAbsolute(original)) {
+        return SimplifyAbsolute(original);
       } else if (IsAddition(original)) {
         return SimplifyAddition(original);
@@ -261,4 +283,8 @@
       } else if (IsSquareRoot(original)) {
         return SimplifySquareRoot(original);
+      } else if (IsCube(original)) {
+        return SimplifyCube(original);
+      } else if (IsCubeRoot(original)) {
+        return SimplifyCubeRoot(original);
       } else if (IsPower(original)) {
         return SimplifyPower(original);
@@ -271,4 +297,6 @@
       } else if (IsTangent(original)) {
         return SimplifyTangent(original);
+      } else if (IsAnalyticalQuotient(original)) {
+        return SimplifyAnalyticalQuotient(original);
       } else if (IsIfThenElse(original)) {
         return SimplifyIfThenElse(original);
@@ -380,4 +408,8 @@
     }
 
+    private static ISymbolicExpressionTreeNode SimplifyAbsolute(ISymbolicExpressionTreeNode original) {
+      return MakeAbs(GetSimplifiedTree(original.GetSubtree(0)));
+    }
+
     private static ISymbolicExpressionTreeNode SimplifyNot(ISymbolicExpressionTreeNode original) {
       return MakeNot(GetSimplifiedTree(original.GetSubtree(0)));
@@ -432,4 +464,11 @@
       return MakeSquareRoot(GetSimplifiedTree(original.GetSubtree(0)));
     }
+    private static ISymbolicExpressionTreeNode SimplifyCube(ISymbolicExpressionTreeNode original) {
+      return MakeCube(GetSimplifiedTree(original.GetSubtree(0)));
+    }
+
+    private static ISymbolicExpressionTreeNode SimplifyCubeRoot(ISymbolicExpressionTreeNode original) {
+      return MakeCubeRoot(GetSimplifiedTree(original.GetSubtree(0)));
+    }
 
     private static ISymbolicExpressionTreeNode SimplifyLog(ISymbolicExpressionTreeNode original) {
@@ -443,4 +482,8 @@
     private static ISymbolicExpressionTreeNode SimplifyPower(ISymbolicExpressionTreeNode original) {
       return MakePower(GetSimplifiedTree(original.GetSubtree(0)), GetSimplifiedTree(original.GetSubtree(1)));
+    }
+
+    private static ISymbolicExpressionTreeNode SimplifyAnalyticalQuotient(ISymbolicExpressionTreeNode original) {
+      return MakeAnalyticalQuotient(GetSimplifiedTree(original.GetSubtree(0)), GetSimplifiedTree(original.GetSubtree(1)));
     }
 
@@ -730,8 +773,94 @@
       } else if (IsSquareRoot(node)) {
         return node.GetSubtree(0);
+      } else if (IsMultiplication(node)) {
+        // sqr( x * y ) = sqr(x) * sqr(y)
+        var mulNode = mulSymbol.CreateTreeNode();
+        foreach (var subtree in node.Subtrees) {
+          mulNode.AddSubtree(MakeSquare(subtree));
+        }
+        return mulNode;
+      } else if (IsAbsolute(node)) {
+        return MakeSquare(node.GetSubtree(0)); // sqr(abs(x)) = sqr(x)
+      } else if (IsExp(node)) {
+        return MakeExp(MakeProduct(node.GetSubtree(0), MakeConstant(2.0))); // sqr(exp(x)) = exp(2x)
+      } else if (IsCube(node)) {
+        return MakePower(node.GetSubtree(0), MakeConstant(6));
       } else {
         var sqrNode = sqrSymbol.CreateTreeNode();
         sqrNode.AddSubtree(node);
         return sqrNode;
+      }
+    }
+
+    private static ISymbolicExpressionTreeNode MakeCube(ISymbolicExpressionTreeNode node) {
+      if (IsConstant(node)) {
+        var constT = node as ConstantTreeNode;
+        return MakeConstant(constT.Value * constT.Value * constT.Value);
+      } else if (IsFactor(node)) {
+        var factNode = node as FactorVariableTreeNode;
+        return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => w * w * w));
+      } else if (IsBinFactor(node)) {
+        var binFactor = node as BinaryFactorVariableTreeNode;
+        return MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, binFactor.Weight * binFactor.Weight * binFactor.Weight);
+      } else if (IsCubeRoot(node)) {
+        return node.GetSubtree(0); // NOTE: not really accurate because cuberoot(x) with negative x is evaluated to NaN and after this simplification we evaluate as x
+      } else if (IsExp(node)) {
+        return MakeExp(MakeProduct(node.GetSubtree(0), MakeConstant(3)));
+      } else if (IsSquare(node)) {
+        return MakePower(node.GetSubtree(0), MakeConstant(6));
+      } else {
+        var cubeNode = cubeSymbol.CreateTreeNode();
+        cubeNode.AddSubtree(node);
+        return cubeNode;
+      }
+    }
+
+    private static ISymbolicExpressionTreeNode MakeAbs(ISymbolicExpressionTreeNode node) {
+      if (IsConstant(node)) {
+        var constT = node as ConstantTreeNode;
+        return MakeConstant(Math.Abs(constT.Value));
+      } else if (IsFactor(node)) {
+        var factNode = node as FactorVariableTreeNode;
+        return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Abs(w)));
+      } else if (IsBinFactor(node)) {
+        var binFactor = node as BinaryFactorVariableTreeNode;
+        return MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Abs(binFactor.Weight));
+      } else if (IsSquare(node) || IsExp(node) || IsSquareRoot(node) || IsCubeRoot(node)) {
+        return node; // abs(sqr(x)) = sqr(x), abs(exp(x)) = exp(x) ...
+      } else if (IsMultiplication(node)) {
+        var mul = mulSymbol.CreateTreeNode();
+        foreach (var st in node.Subtrees) {
+          mul.AddSubtree(MakeAbs(st));
+        }
+        return mul;
+      } else if (IsDivision(node)) {
+        var div = divSymbol.CreateTreeNode();
+        foreach (var st in node.Subtrees) {
+          div.AddSubtree(MakeAbs(st));
+        }
+        return div;
+      } else {
+        var absNode = absSymbol.CreateTreeNode();
+        absNode.AddSubtree(node);
+        return absNode;
+      }
+    }
+
+    // constant folding only
+    private static ISymbolicExpressionTreeNode MakeAnalyticalQuotient(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b) {
+      if (IsConstant(b)) {
+        var c = b as ConstantTreeNode;
+        return MakeFraction(a, MakeConstant(Math.Sqrt(1.0 + c.Value * c.Value)));
+      } else if (IsFactor(b)) {
+        var factNode = b as FactorVariableTreeNode;
+        return MakeFraction(a, MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Sqrt(1.0 + w * w))));
+      } else if (IsBinFactor(b)) {
+        var binFactor = b as BinaryFactorVariableTreeNode;
+        return MakeFraction(a, MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Sqrt(1.0 + binFactor.Weight * binFactor.Weight)));
+      } else {
+        var aqNode = aqSymbol.CreateTreeNode();
+        aqNode.AddSubtree(a);
+        aqNode.AddSubtree(b);
+        return aqNode;
       }
     }
@@ -748,9 +877,28 @@
         return MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Sqrt(binFactor.Weight));
       } else if (IsSquare(node)) {
-        return node.GetSubtree(0);
+        return node.GetSubtree(0); // NOTE: not really accurate because sqrt(x) with negative x is evaluated to NaN and after this simplification we evaluate as x
       } else {
         var sqrtNode = sqrtSymbol.CreateTreeNode();
         sqrtNode.AddSubtree(node);
         return sqrtNode;
+      }
+    }
+
+    private static ISymbolicExpressionTreeNode MakeCubeRoot(ISymbolicExpressionTreeNode node) {
+      if (IsConstant(node)) {
+        var constT = node as ConstantTreeNode;
+        return MakeConstant(Math.Pow(constT.Value, 1.0 / 3.0));
+      } else if (IsFactor(node)) {
+        var factNode = node as FactorVariableTreeNode;
+        return MakeFactor(factNode.Symbol, factNode.VariableName, factNode.Weights.Select(w => Math.Pow(w, 1.0 / 3.0)));
+      } else if (IsBinFactor(node)) {
+        var binFactor = node as BinaryFactorVariableTreeNode;
+        return MakeBinFactor(binFactor.Symbol, binFactor.VariableName, binFactor.VariableValue, Math.Sqrt(Math.Pow(binFactor.Weight, 1.0 / 3.0)));
+      } else if (IsCube(node)) {
+        return node.GetSubtree(0);
+      } else {
+        var cubeRootNode = cubeRootSymbol.CreateTreeNode();
+        cubeRootNode.AddSubtree(node);
+        return cubeRootNode;
       }
     }
@@ -927,4 +1075,6 @@
         // a / (b1 / b2) => (a * b2) / b1
         return MakeFraction(MakeProduct(a, b.GetSubtree(1)), b.GetSubtree(0));
+      } else if (IsAnalyticalQuotient(a)) {
+        return MakeAnalyticalQuotient(a.GetSubtree(0), MakeProduct(a.GetSubtree(1), b));
       } else {
         var div = divSymbol.CreateTreeNode();
@@ -1121,4 +1271,6 @@
         // $ * 1.0 => $
         return a;
+      } else if (IsConstant(b) && ((ConstantTreeNode)b).Value.IsAlmost(0.0)) {
+        return MakeConstant(0);
       } else if (IsConstant(b) && IsVariableBase(a)) {
         // multiply constants into variables weights
@@ -1153,4 +1305,19 @@
         MergeVariablesAndConstantsInProduct(a);
         return a;
+      } else if (IsAbsolute(a) && IsAbsolute(b)) {
+        return MakeAbs(MakeProduct(a.GetSubtree(0), b.GetSubtree(0)));
+      } else if (IsAbsolute(a) && IsConstant(b)) {
+        var constNode = b as ConstantTreeNode;
+        var posF = Math.Abs(constNode.Value);
+        if (constNode.Value > 0) {
+          return MakeAbs(MakeProduct(a.GetSubtree(0), MakeConstant(posF)));
+        } else {
+          var mul = mulSymbol.CreateTreeNode();
+          mul.AddSubtree(MakeAbs(MakeProduct(a.GetSubtree(0), MakeConstant(posF))));
+          mul.AddSubtree(MakeConstant(-1.0));
+          return mul;
+        }
+      } else if (IsAnalyticalQuotient(a)) {
+        return MakeAnalyticalQuotient(MakeProduct(a.GetSubtree(0), b), a.GetSubtree(1));
       } else {
         var mul = mulSymbol.CreateTreeNode();
Index: branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Converters/TreeToAutoDiffTermConverter.cs
===================================================================
--- branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Converters/TreeToAutoDiffTermConverter.cs	(revision 15743)
+++ branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Converters/TreeToAutoDiffTermConverter.cs	(revision 16388)
@@ -85,4 +85,9 @@
       diff: x => -(Math.Exp(-(x * x)) * Math.Sqrt(Math.Exp(x * x)) * x) / Math.Sqrt(2 * Math.PI));
 
+    private static readonly Func<Term, UnaryFunc> abs = UnaryFunc.Factory(
+      eval: Math.Abs,
+      diff: x => Math.Sign(x)
+      );
+
     #endregion
 
@@ -213,4 +218,13 @@
         else return terms.Aggregate((a, b) => new AutoDiff.Product(a, 1.0 / b));
       }
+      if (node.Symbol is Absolute) {
+        var x1 = ConvertToAutoDiff(node.GetSubtree(0));
+        return abs(x1);
+      }
+      if (node.Symbol is AnalyticQuotient) {
+        var x1 = ConvertToAutoDiff(node.GetSubtree(0));
+        var x2 = ConvertToAutoDiff(node.GetSubtree(1));
+        return x1 / (TermBuilder.Power(1 + x2 * x2, 0.5));
+      }
       if (node.Symbol is Logarithm) {
         return AutoDiff.TermBuilder.Log(
@@ -228,4 +242,12 @@
         return AutoDiff.TermBuilder.Power(
           ConvertToAutoDiff(node.GetSubtree(0)), 0.5);
+      }
+      if (node.Symbol is Cube) {
+        return AutoDiff.TermBuilder.Power(
+          ConvertToAutoDiff(node.GetSubtree(0)), 3.0);
+      }
+      if (node.Symbol is CubeRoot) {
+        return AutoDiff.TermBuilder.Power(
+          ConvertToAutoDiff(node.GetSubtree(0)), 1.0/3.0);
       }
       if (node.Symbol is Sine) {
@@ -301,5 +323,9 @@
           !(n.Symbol is Erf) &&
           !(n.Symbol is Norm) &&
-          !(n.Symbol is StartSymbol)
+          !(n.Symbol is StartSymbol) &&
+          !(n.Symbol is Absolute) &&
+          !(n.Symbol is AnalyticQuotient) &&
+          !(n.Symbol is Cube) &&
+          !(n.Symbol is CubeRoot)
         select n).Any();
       return !containsUnknownSymbol;
Index: branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Crossovers/SymbolicDataAnalysisExpressionDiversityPreservingCrossover.cs
===================================================================
--- branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Crossovers/SymbolicDataAnalysisExpressionDiversityPreservingCrossover.cs	(revision 16388)
+++ branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Crossovers/SymbolicDataAnalysisExpressionDiversityPreservingCrossover.cs	(revision 16388)
@@ -0,0 +1,146 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Linq;
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Random;
+using static HeuristicLab.Problems.DataAnalysis.Symbolic.SymbolicExpressionHashExtensions;
+
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
+  [Item("DiversityCrossover", "Simple crossover operator prioritizing internal nodes according to the given probability.")]
+  [StorableClass]
+  public sealed class SymbolicDataAnalysisExpressionDiversityPreservingCrossover<T> : SymbolicDataAnalysisExpressionCrossover<T> where T : class, IDataAnalysisProblemData {
+
+    private const string InternalCrossoverPointProbabilityParameterName = "InternalCrossoverPointProbability";
+    private const string WindowingParameterName = "Windowing";
+    private const string ProportionalSamplingParameterName = "ProportionalSampling";
+
+    private static readonly Func<byte[], ulong> hashFunction = HashUtil.JSHash;
+
+    #region Parameter Properties
+    public IValueLookupParameter<PercentValue> InternalCrossoverPointProbabilityParameter {
+      get { return (IValueLookupParameter<PercentValue>)Parameters[InternalCrossoverPointProbabilityParameterName]; }
+    }
+
+    public IValueLookupParameter<BoolValue> WindowingParameter {
+      get { return (IValueLookupParameter<BoolValue>)Parameters[WindowingParameterName]; }
+    }
+
+    public IValueLookupParameter<BoolValue> ProportionalSamplingParameter {
+      get { return (IValueLookupParameter<BoolValue>)Parameters[ProportionalSamplingParameterName]; }
+    }
+    #endregion
+
+    #region Properties
+    public PercentValue InternalCrossoverPointProbability {
+      get { return InternalCrossoverPointProbabilityParameter.ActualValue; }
+    }
+
+    public BoolValue Windowing {
+      get { return WindowingParameter.ActualValue; }
+    }
+
+    public BoolValue ProportionalSampling {
+      get { return ProportionalSamplingParameter.ActualValue; }
+    }
+    #endregion
+
+    public SymbolicDataAnalysisExpressionDiversityPreservingCrossover() {
+      name = "DiversityCrossover";
+      Parameters.Add(new ValueLookupParameter<PercentValue>(InternalCrossoverPointProbabilityParameterName, "The probability to select an internal crossover point (instead of a leaf node).", new PercentValue(0.9)));
+      Parameters.Add(new ValueLookupParameter<BoolValue>(WindowingParameterName, "Use proportional sampling with windowing for cutpoint selection.", new BoolValue(false)));
+      Parameters.Add(new ValueLookupParameter<BoolValue>(ProportionalSamplingParameterName, "Select cutpoints proportionally using probabilities as weights instead of randomly.", new BoolValue(true)));
+    }
+
+    private SymbolicDataAnalysisExpressionDiversityPreservingCrossover(SymbolicDataAnalysisExpressionDiversityPreservingCrossover<T> original, Cloner cloner) : base(original, cloner) {
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new SymbolicDataAnalysisExpressionDiversityPreservingCrossover<T>(this, cloner);
+    }
+
+    [StorableConstructor]
+    private SymbolicDataAnalysisExpressionDiversityPreservingCrossover(bool deserializing) : base(deserializing) { }
+
+    private static ISymbolicExpressionTreeNode ActualRoot(ISymbolicExpressionTree tree) {
+      return tree.Root.GetSubtree(0).GetSubtree(0);
+    }
+
+    public static ISymbolicExpressionTree Cross(IRandom random, ISymbolicExpressionTree parent0, ISymbolicExpressionTree parent1, double internalCrossoverPointProbability, int maxLength, int maxDepth, bool windowing, bool proportionalSampling = false) {
+      var leafCrossoverPointProbability = 1 - internalCrossoverPointProbability;
+
+      var nodes0 = ActualRoot(parent0).MakeNodes().Sort(hashFunction);
+      var nodes1 = ActualRoot(parent1).MakeNodes().Sort(hashFunction);
+
+      IList<HashNode<ISymbolicExpressionTreeNode>> sampled0;
+      IList<HashNode<ISymbolicExpressionTreeNode>> sampled1;
+
+      if (proportionalSampling) {
+        var p = internalCrossoverPointProbability;
+        var weights0 = nodes0.Select(x => x.IsLeaf ? 1 - p : p);
+        sampled0 = nodes0.SampleProportionalWithoutRepetition(random, nodes0.Length, weights0, windowing: windowing).ToArray();
+
+        var weights1 = nodes1.Select(x => x.IsLeaf ? 1 - p : p);
+        sampled1 = nodes1.SampleProportionalWithoutRepetition(random, nodes1.Length, weights1, windowing: windowing).ToArray();
+      } else {
+        sampled0 = ChooseNodes(random, nodes0, internalCrossoverPointProbability).ShuffleInPlace(random);
+        sampled1 = ChooseNodes(random, nodes1, internalCrossoverPointProbability).ShuffleInPlace(random);
+      }
+
+      foreach (var selected in sampled0) {
+        var cutpoint = new CutPoint(selected.Data.Parent, selected.Data);
+
+        var maxAllowedDepth = maxDepth - parent0.Root.GetBranchLevel(selected.Data);
+        var maxAllowedLength = maxLength - (parent0.Length - selected.Data.GetLength());
+
+        foreach (var candidate in sampled1) {
+          if (candidate.CalculatedHashValue == selected.CalculatedHashValue
+            || candidate.Data.GetDepth() > maxAllowedDepth
+            || candidate.Data.GetLength() > maxAllowedLength
+            || !cutpoint.IsMatchingPointType(candidate.Data)) {
+            continue;
+          }
+
+          Swap(cutpoint, candidate.Data);
+          return parent0;
+        }
+      }
+      return parent0;
+    }
+
+    public override ISymbolicExpressionTree Crossover(IRandom random, ISymbolicExpressionTree parent0, ISymbolicExpressionTree parent1) {
+      if (this.ExecutionContext == null) {
+        throw new InvalidOperationException("ExecutionContext not set.");
+      }
+
+      var maxDepth = MaximumSymbolicExpressionTreeDepth.Value;
+      var maxLength = MaximumSymbolicExpressionTreeLength.Value;
+
+      var internalCrossoverPointProbability = InternalCrossoverPointProbability.Value;
+      var windowing = Windowing.Value;
+      var proportionalSampling = ProportionalSampling.Value;
+
+      return Cross(random, parent0, parent1, internalCrossoverPointProbability, maxLength, maxDepth, windowing, proportionalSampling);
+    }
+
+    private static List<HashNode<ISymbolicExpressionTreeNode>> ChooseNodes(IRandom random, IEnumerable<HashNode<ISymbolicExpressionTreeNode>> nodes, double internalCrossoverPointProbability) {
+      var list = new List<HashNode<ISymbolicExpressionTreeNode>>();
+
+      var chooseInternal = random.NextDouble() < internalCrossoverPointProbability;
+
+      if (chooseInternal) {
+        list.AddRange(nodes.Where(x => !x.IsLeaf && x.Data.Parent != null));
+      }
+      if (!chooseInternal || list.Count == 0) {
+        list.AddRange(nodes.Where(x => x.IsLeaf && x.Data.Parent != null));
+      }
+
+      return list;
+    }
+  }
+}
Index: branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Formatters/InfixExpressionFormatter.cs
===================================================================
--- branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Formatters/InfixExpressionFormatter.cs	(revision 15743)
+++ branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Formatters/InfixExpressionFormatter.cs	(revision 16388)
@@ -62,15 +62,8 @@
       if (node.SubtreeCount > 1) {
         var token = GetToken(node.Symbol);
-        if (token == "+" || token == "-" || token == "OR" || token == "XOR") {
-          strBuilder.Append("(");
-          FormatRecursively(node.Subtrees.First(), strBuilder);
-
-          foreach (var subtree in node.Subtrees.Skip(1)) {
-            strBuilder.Append(" ").Append(token).Append(" ");
-            FormatRecursively(subtree, strBuilder);
-          }
-          strBuilder.Append(")");
-
-        } else if (token == "*" || token == "/" || token == "AND") {
+        // operators
+        if (token == "+" || token == "-" || token == "OR" || token == "XOR" ||
+            token == "*" || token == "/" || token == "AND" ||
+            token == "^") {
           strBuilder.Append("(");
           FormatRecursively(node.Subtrees.First(), strBuilder);
@@ -184,5 +177,5 @@
 
     private string GetToken(ISymbol symbol) {
-      var tok = InfixExpressionParser.knownSymbols.GetBySecond(symbol).SingleOrDefault();
+      var tok = InfixExpressionParser.knownSymbols.GetBySecond(symbol).FirstOrDefault();
       if (tok == null)
         throw new ArgumentException(string.Format("Unknown symbol {0} found.", symbol.Name));
Index: branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Formatters/TSQLExpressionFormatter.cs
===================================================================
--- branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Formatters/TSQLExpressionFormatter.cs	(revision 16388)
+++ branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Formatters/TSQLExpressionFormatter.cs	(revision 16388)
@@ -0,0 +1,278 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2018 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.Globalization;
+using System.Linq;
+using System.Text;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
+  internal static class StringBuilderExtensions {
+    internal static void AppendIndented(this StringBuilder strBuilder, int level, string text) {
+      strBuilder.Append(new string(' ', level * 2));
+      strBuilder.Append(text);
+    }
+    internal static void AppendLineIndented(this StringBuilder strBuilder, int level, string text) {
+      strBuilder.Append(new string(' ', level * 2));
+      strBuilder.AppendLine(text);
+    }
+  }
+
+  [Item("TSQL String Formatter", "String formatter for string representations of symbolic data analysis expressions in TSQL syntax.")]
+  [StorableClass]
+  public sealed class TSQLExpressionFormatter : NamedItem, ISymbolicExpressionTreeStringFormatter {
+    [StorableConstructor]
+    private TSQLExpressionFormatter(bool deserializing) : base(deserializing) { }
+    private TSQLExpressionFormatter(TSQLExpressionFormatter original, Cloner cloner) : base(original, cloner) { }
+    public TSQLExpressionFormatter()
+      : base() {
+      Name = ItemName;
+      Description = ItemDescription;
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new TSQLExpressionFormatter(this, cloner);
+    }
+
+    public string Format(ISymbolicExpressionTree symbolicExpressionTree) {
+      // skip root and start symbols
+      StringBuilder strBuilder = new StringBuilder();
+      GenerateHeader(strBuilder, symbolicExpressionTree);
+
+      //generate function body
+      FormatRecursively(1, symbolicExpressionTree.Root.GetSubtree(0).GetSubtree(0), strBuilder);
+
+      GenerateFooter(strBuilder);
+      return strBuilder.ToString();
+    }
+
+    private void GenerateHeader(StringBuilder strBuilder, ISymbolicExpressionTree symbolicExpressionTree) {
+      HashSet<string> floatVarNames = new HashSet<string>();
+      foreach (var node in symbolicExpressionTree.IterateNodesPostfix().Where(x => x is VariableTreeNode || x is VariableConditionTreeNode)) {
+        floatVarNames.Add(((IVariableTreeNode)node).VariableName);
+      }
+      var sortedFloatIdentifiers = floatVarNames.OrderBy(n => n, new NaturalStringComparer()).Select(n => VariableName2Identifier(n)).ToList();
+
+      HashSet<string> varcharVarNames = new HashSet<string>();
+      foreach (var node in symbolicExpressionTree.IterateNodesPostfix().Where(x => x is BinaryFactorVariableTreeNode || x is FactorVariableTreeNode)) {
+        varcharVarNames.Add(((IVariableTreeNode)node).VariableName);
+      }
+      var sortedVarcharIdentifiers = varcharVarNames.OrderBy(n => n, new NaturalStringComparer()).Select(n => VariableName2Identifier(n)).ToList();
+
+      //Generate comment and instructions
+      strBuilder.Append("-- generated. created function can be used like 'SELECT dbo.REGRESSIONMODEL(");
+      strBuilder.Append(string.Join(", ", sortedVarcharIdentifiers));
+      if (varcharVarNames.Any() && floatVarNames.Any())
+        strBuilder.Append(",");
+      strBuilder.Append(string.Join(", ", sortedFloatIdentifiers));
+      strBuilder.AppendLine(")'");
+      strBuilder.AppendLine("-- use the expression after the RETURN statement if you want to incorporate the model in a query without creating a function.");
+
+      //Generate function header
+      strBuilder.Append("CREATE FUNCTION dbo.REGRESSIONMODEL(");
+      strBuilder.Append(string.Join(", ", sortedVarcharIdentifiers.Select(n => string.Format("{0} NVARCHAR(max)",n))));
+      if (varcharVarNames.Any() && floatVarNames.Any())
+        strBuilder.Append(",");
+      strBuilder.Append(string.Join(", ", sortedFloatIdentifiers.Select(n => string.Format("{0} FLOAT",n))));
+      strBuilder.AppendLine(")");
+
+      //start function body
+      strBuilder.AppendLine("RETURNS FLOAT");
+      strBuilder.AppendLine("BEGIN");
+
+      //add variable declaration for convenience
+      strBuilder.AppendLineIndented(1, "-- added variable declaration for convenience");
+      foreach (var name in sortedVarcharIdentifiers)
+        strBuilder.AppendLineIndented(1, string.Format("-- DECLARE {0} NVARCHAR(max) = ''", name));
+      foreach (var name in sortedFloatIdentifiers)
+        strBuilder.AppendLineIndented(1, string.Format("-- DECLARE {0} FLOAT = 0.0", name));
+      strBuilder.AppendLineIndented(1, "-- SELECT");
+      strBuilder.AppendLine("RETURN ");
+    }
+
+    private void FormatRecursively(int level, ISymbolicExpressionTreeNode node, StringBuilder strBuilder) {
+      if (node.Subtrees.Any()) {
+        if (node.Symbol is Addition) {
+          FormatOperator(level, node, "+", strBuilder);
+        } else if (node.Symbol is And) {
+          FormatOperator(level, node, "AND", strBuilder);
+        } else if (node.Symbol is Average) {
+          FormatAverage(level, node, strBuilder);
+        } else if (node.Symbol is Cosine) {
+          FormatFunction(level, node, "COS", strBuilder);
+        } else if (node.Symbol is Division) {
+          FormatDivision(level, node, strBuilder);
+        } else if (node.Symbol is Exponential) {
+          FormatFunction(level, node, "EXP", strBuilder);
+        } else if (node.Symbol is GreaterThan) {
+          FormatOperator(level, node, ">", strBuilder);
+        } else if (node.Symbol is IfThenElse) {
+          FormatIfThenElse(level, node, strBuilder);
+        } else if (node.Symbol is LessThan) {
+          FormatOperator(level, node, "<", strBuilder);
+        } else if (node.Symbol is Logarithm) {
+          FormatFunction(level, node, "LOG", strBuilder);
+        } else if (node.Symbol is Multiplication) {
+          FormatOperator(level, node, "*", strBuilder);
+        } else if (node.Symbol is Not) {
+          FormatOperator(level, node, "NOT LIKE", strBuilder);
+        } else if (node.Symbol is Or) {
+          FormatOperator(level, node, "OR", strBuilder);
+        } else if (node.Symbol is Xor) {
+          throw new NotSupportedException(string.Format("Symbol {0} not yet supported.", node.Symbol.GetType().Name));
+        } else if (node.Symbol is Sine) {
+          FormatFunction(level, node, "SIN", strBuilder);
+        } else if (node.Symbol is Subtraction) {
+          FormatSubtraction(level, node, strBuilder);
+        } else if (node.Symbol is Tangent) {
+          FormatFunction(level, node, "TAN", strBuilder);
+        } else if (node.Symbol is Square) {
+          FormatFunction(level, node, "SQUARE", strBuilder);
+        } else if (node.Symbol is SquareRoot) {
+          FormatFunction(level, node, "SQRT", strBuilder);
+        } else if (node.Symbol is Power) {
+          FormatFunction(level, node, "POWER", strBuilder);
+        } else if (node.Symbol is Root) {
+          FormatRoot(level, node, strBuilder);
+        } else {
+          throw new NotSupportedException("Formatting of symbol: " + node.Symbol + " not supported for TSQL symbolic expression tree formatter.");
+        }
+      } else {
+        if (node is VariableTreeNode) {
+          var varNode = node as VariableTreeNode;
+          strBuilder.AppendFormat("{0} * {1}", VariableName2Identifier(varNode.VariableName), varNode.Weight.ToString("g17", CultureInfo.InvariantCulture));
+        } else if (node is ConstantTreeNode) {
+          var constNode = node as ConstantTreeNode;
+          strBuilder.Append(constNode.Value.ToString("g17", CultureInfo.InvariantCulture));
+        } else if (node.Symbol is FactorVariable) {
+          var factorNode = node as FactorVariableTreeNode;
+          FormatFactor(level, factorNode, strBuilder);
+        } else if (node.Symbol is BinaryFactorVariable) {
+          var binFactorNode = node as BinaryFactorVariableTreeNode;
+          throw new NotSupportedException(string.Format("Symbol {0} not yet supported.", node.Symbol.GetType().Name));
+        } else {
+          throw new NotSupportedException("Formatting of symbol: " + node.Symbol + " not supported for TSQL symbolic expression tree formatter.");
+        }
+      }
+    }
+
+    private void FormatIfThenElse(int level, ISymbolicExpressionTreeNode node, StringBuilder strBuilder) {
+      strBuilder.Append("CASE ISNULL((SELECT 1 WHERE");
+      FormatRecursively(level,node.GetSubtree(0), strBuilder);
+      strBuilder.AppendLine("),0)");
+      strBuilder.AppendIndented(level,"WHEN 1 THEN ");
+      FormatRecursively(level, node.GetSubtree(1), strBuilder);
+      strBuilder.AppendLine();
+      strBuilder.AppendIndented(level, "WHEN 0 THEN ");
+      FormatRecursively(level, node.GetSubtree(2), strBuilder);
+      strBuilder.AppendLine();
+      strBuilder.AppendIndented(level, "END");
+    }
+
+    private void FormatAverage(int level, ISymbolicExpressionTreeNode node, StringBuilder strBuilder) {
+      strBuilder.Append("(");
+      foreach (var child in node.Subtrees) {
+        FormatRecursively(level, child, strBuilder);
+        if (child != node.Subtrees.Last())
+          strBuilder.Append(" + ");
+      }
+      strBuilder.AppendFormat(") / {0}", node.Subtrees.Count());
+    }
+
+    private string VariableName2Identifier(string variableName) {
+      return "@"+variableName.Replace(' ', '_');
+    }
+
+    private void GenerateFooter(StringBuilder strBuilder) {
+      strBuilder.Append(Environment.NewLine);
+      strBuilder.AppendLine("END");
+    }
+
+
+    private void FormatOperator(int level, ISymbolicExpressionTreeNode node, string symbol, StringBuilder strBuilder) {
+      strBuilder.Append("(");
+      foreach (var child in node.Subtrees) {
+        FormatRecursively(level, child, strBuilder);
+        if (child != node.Subtrees.Last())
+          strBuilder.Append(" " + symbol + " ");
+      }
+      strBuilder.Append(")");
+    }
+
+    private void FormatFunction(int level, ISymbolicExpressionTreeNode node, string function, StringBuilder strBuilder) {
+      strBuilder.Append(function + "(");
+      foreach (var child in node.Subtrees) {
+        FormatRecursively(level++, child, strBuilder);
+        if (child != node.Subtrees.Last())
+          strBuilder.Append(", ");
+      }
+      strBuilder.Append(")");
+    }
+
+    private void FormatDivision(int level, ISymbolicExpressionTreeNode node, StringBuilder strBuilder) {
+      if (node.SubtreeCount == 1) {
+        strBuilder.Append("1.0 / ");
+        FormatRecursively(level, node.GetSubtree(0), strBuilder);
+      } else {
+        FormatRecursively(level, node.GetSubtree(0), strBuilder);
+        strBuilder.Append("/ (");
+        for (int i = 1; i < node.SubtreeCount; i++) {
+          if (i > 1) strBuilder.Append(" * ");
+          FormatRecursively(level, node.GetSubtree(i), strBuilder);
+        }
+        strBuilder.Append(")");
+      }
+    }
+
+    private void FormatSubtraction(int level, ISymbolicExpressionTreeNode node, StringBuilder strBuilder) {
+      if (node.SubtreeCount == 1) {
+        strBuilder.Append("-");
+        FormatRecursively(level, node.GetSubtree(0), strBuilder);
+        return;
+      }
+      //Default case: more than 1 child
+      FormatOperator(level, node, "-", strBuilder);
+    }
+
+    private void FormatRoot(int level, ISymbolicExpressionTreeNode node, StringBuilder strBuilder) {
+      strBuilder.AppendLine("POWER(");
+      FormatRecursively(level, node.GetSubtree(0), strBuilder);
+      strBuilder.AppendLineIndented(level, " , 1.0 / (");
+      FormatRecursively(level, node.GetSubtree(1), strBuilder);
+      strBuilder.AppendLineIndented(level, "))");
+    }
+
+    private void FormatFactor(int level, FactorVariableTreeNode node, StringBuilder strBuilder) {
+      strBuilder.AppendLine("( ");
+      strBuilder.AppendLineIndented(level + 1, string.Format("CASE {0}", VariableName2Identifier(node.VariableName)));
+      foreach (var name in node.Symbol.GetVariableValues(node.VariableName)) {
+        strBuilder.AppendLineIndented(level + 2, string.Format("WHEN '{0}' THEN {1}", name, node.GetValue(name).ToString(CultureInfo.InvariantCulture)));
+      }
+      strBuilder.AppendLineIndented(level + 1, "ELSE NULL END");
+      strBuilder.AppendIndented(level, ")");
+    }
+
+  }
+}
Index: branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Grammars/FullFunctionalExpressionGrammar.cs
===================================================================
--- branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Grammars/FullFunctionalExpressionGrammar.cs	(revision 15743)
+++ branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Grammars/FullFunctionalExpressionGrammar.cs	(revision 16388)
@@ -48,4 +48,5 @@
       var mul = new Multiplication();
       var div = new Division();
+      var aq = new AnalyticQuotient();
       var mean = new Average();
       var sin = new Sine();
@@ -53,12 +54,17 @@
       var tan = new Tangent();
       var log = new Logarithm();
+      var abs = new Absolute();
       var pow = new Power();
       pow.InitialFrequency = 0.0;
       var square = new Square();
       square.InitialFrequency = 0.0;
+      var cube = new Cube();
+      cube.InitialFrequency = 0.0;
       var root = new Root();
       root.InitialFrequency = 0.0;
       var sqrt = new SquareRoot();
       sqrt.InitialFrequency = 0.0;
+      var cubeRoot = new CubeRoot();
+      cubeRoot.InitialFrequency = 0.0;
       var airyA = new AiryA();
       airyA.InitialFrequency = 0.0;
@@ -123,12 +129,12 @@
       autoregressiveVariable.Enabled = false;
 
-      var allSymbols = new List<Symbol>() { add, sub, mul, div, mean, sin, cos, tan, log, square, pow, sqrt, root, exp,
+      var allSymbols = new List<Symbol>() { add, sub, mul, div, aq, mean, abs, sin, cos, tan, log, square, cube, pow, sqrt, cubeRoot, root, exp,
         airyA, airyB, bessel, cosineIntegral, dawson, erf, expIntegralEi, fresnelCosineIntegral, fresnelSineIntegral, gamma, hypCosineIntegral, hypSineIntegral, norm, psi, sineIntegral,
         @if, gt, lt, and, or, not,xor, timeLag, integral, derivative, constant, variableSymbol, binFactorVariable, factorVariable, laggedVariable,autoregressiveVariable, variableCondition };
-      var unaryFunctionSymbols = new List<Symbol>() { square, sqrt, sin, cos, tan, log, exp, not, timeLag, integral, derivative,
+      var unaryFunctionSymbols = new List<Symbol>() { abs, square, sqrt, cube, cubeRoot, sin, cos, tan, log, exp, not, timeLag, integral, derivative,
         airyA, airyB, bessel, cosineIntegral, dawson, erf, expIntegralEi, fresnelCosineIntegral, fresnelSineIntegral, gamma, hypCosineIntegral, hypSineIntegral, norm, psi, sineIntegral
       };
 
-      var binaryFunctionSymbols = new List<Symbol>() { pow, root, gt, lt, variableCondition };
+      var binaryFunctionSymbols = new List<Symbol>() { pow, root, gt, lt, aq, variableCondition };
       var ternarySymbols = new List<Symbol>() { add, sub, mul, div, mean, and, or, xor };
       var terminalSymbols = new List<Symbol>() { variableSymbol, binFactorVariable, factorVariable, constant, laggedVariable, autoregressiveVariable };
Index: branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Grammars/TypeCoherentExpressionGrammar.cs
===================================================================
--- branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Grammars/TypeCoherentExpressionGrammar.cs	(revision 15743)
+++ branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Grammars/TypeCoherentExpressionGrammar.cs	(revision 16388)
@@ -69,5 +69,8 @@
       var root = new Root();
       var sqrt = new SquareRoot();
+      var cube = new Cube();
+      var cubeRoot = new CubeRoot();
       var exp = new Exponential();
+      var abs = new Absolute();
 
       var airyA = new AiryA();
@@ -86,4 +89,5 @@
       var psi = new Psi();
       var sineIntegral = new SineIntegral();
+      var analyticalQuotient = new AnalyticQuotient();
 
       var @if = new IfThenElse();
@@ -114,10 +118,10 @@
       var trigonometricSymbols = new GroupSymbol(TrigonometricFunctionsName, new List<ISymbol>() { sin, cos, tan });
       var exponentialAndLogarithmicSymbols = new GroupSymbol(ExponentialFunctionsName, new List<ISymbol> { exp, log });
-      var specialFunctions = new GroupSymbol(SpecialFunctionsName, new List<ISymbol> { airyA, airyB, bessel, cosineIntegral, dawson, erf, expIntegralEi,
-        fresnelCosineIntegral,fresnelSineIntegral,gamma,hypCosineIntegral,hypSineIntegral,norm, psi, sineIntegral});
+      var specialFunctions = new GroupSymbol(SpecialFunctionsName, new List<ISymbol> { abs, airyA, airyB, bessel, cosineIntegral, dawson, erf, expIntegralEi,
+        fresnelCosineIntegral,fresnelSineIntegral,gamma,hypCosineIntegral,hypSineIntegral,norm, psi, sineIntegral, analyticalQuotient});
       var terminalSymbols = new GroupSymbol(TerminalsName, new List<ISymbol> { constant, variableSymbol, binFactorVariable, factorVariable });
       var realValuedSymbols = new GroupSymbol(RealValuedSymbolsName, new List<ISymbol>() { arithmeticSymbols, trigonometricSymbols, exponentialAndLogarithmicSymbols, specialFunctions, terminalSymbols });
 
-      var powerSymbols = new GroupSymbol(PowerFunctionsName, new List<ISymbol> { square, pow, sqrt, root });
+      var powerSymbols = new GroupSymbol(PowerFunctionsName, new List<ISymbol> { square, pow, sqrt, root, cube, cubeRoot });
 
       var conditionSymbols = new GroupSymbol(ConditionsName, new List<ISymbol> { @if, variableCondition });
@@ -140,7 +144,13 @@
       SetSubtreeCount(root, 2, 2);
       SetSubtreeCount(square, 1, 1);
+      SetSubtreeCount(cube, 1, 1);
       SetSubtreeCount(sqrt, 1, 1);
+      SetSubtreeCount(cubeRoot, 1, 1);
       SetSubtreeCount(exponentialAndLogarithmicSymbols, 1, 1);
-      SetSubtreeCount(specialFunctions, 1, 1);
+      foreach(var sy in specialFunctions.Symbols.Except(new[] { analyticalQuotient})) {
+        SetSubtreeCount(sy, 1, 1);
+      }
+      SetSubtreeCount(analyticalQuotient, 2, 2);
+
       SetSubtreeCount(terminalSymbols, 0, 0);
 
@@ -231,4 +241,5 @@
     public void ConfigureAsDefaultRegressionGrammar() {
       Symbols.First(s => s is Average).Enabled = false;
+      Symbols.First(s => s is Absolute).Enabled = false;
       Symbols.First(s => s.Name == TrigonometricFunctionsName).Enabled = false;
       Symbols.First(s => s.Name == PowerFunctionsName).Enabled = false;
@@ -242,4 +253,5 @@
       Symbols.First(s => s is VariableCondition).Enabled = false;
       Symbols.First(s => s is Xor).Enabled = false;
+      Symbols.First(s => s is Absolute).Enabled = false;
       Symbols.First(s => s.Name == TrigonometricFunctionsName).Enabled = false;
       Symbols.First(s => s.Name == ExponentialFunctionsName).Enabled = false;
@@ -251,4 +263,5 @@
     public void ConfigureAsDefaultTimeSeriesPrognosisGrammar() {
       Symbols.First(s => s is Average).Enabled = false;
+      Symbols.First(s => s is Absolute).Enabled = false;
       Symbols.First(s => s.Name == TrigonometricFunctionsName).Enabled = false;
       Symbols.First(s => s.Name == PowerFunctionsName).Enabled = false;
Index: branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Hashing/HashExtensions.cs
===================================================================
--- branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Hashing/HashExtensions.cs	(revision 16388)
+++ branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Hashing/HashExtensions.cs	(revision 16388)
@@ -0,0 +1,237 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2018 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;
+
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
+  public static class SymbolicExpressionHashExtensions {
+    public sealed class HashNode<T> : IComparable<HashNode<T>>, IEquatable<HashNode<T>> where T : class {
+      public T Data;
+      public int Arity;
+      public int Size;
+      public bool IsCommutative;
+
+      public bool Enabled;
+      public ulong HashValue;           // the initial (fixed) hash value for this individual node/data
+      public ulong CalculatedHashValue; // the calculated hash value (taking into account the children hash values)
+
+      public delegate void SimplifyAction(ref HashNode<T>[] nodes, int i);
+      public SimplifyAction Simplify;
+
+      public IComparer<T> Comparer;
+
+      public bool IsLeaf => Arity == 0;
+
+      public HashNode(IComparer<T> comparer) {
+        Comparer = comparer;
+      }
+
+      private HashNode() { }
+
+      public int CompareTo(HashNode<T> other) {
+        var res = Comparer.Compare(Data, other.Data);
+        return res == 0 ? CalculatedHashValue.CompareTo(other.CalculatedHashValue) : res;
+      }
+
+      public override string ToString() {
+        return $"{Data} {Arity} {Size} {CalculatedHashValue} {Enabled}";
+      }
+
+      public bool Equals(HashNode<T> other) {
+        return CalculatedHashValue.Equals(other.CalculatedHashValue);
+      }
+
+      public override bool Equals(object obj) {
+        var other = obj as HashNode<T>;
+        if (other != null)
+          return Equals(other);
+        return base.Equals(obj);
+      }
+
+      public override int GetHashCode() {
+        return (int)CalculatedHashValue;
+      }
+
+      public static bool operator ==(HashNode<T> a, HashNode<T> b) {
+        return a.Equals(b);
+      }
+
+      public static bool operator !=(HashNode<T> a, HashNode<T> b) {
+        return !a.Equals(b);
+      }
+    }
+
+    public static ulong ComputeHash<T>(this HashNode<T>[] nodes, int i, Func<byte[], ulong> hashFunction) where T : class {
+      var node = nodes[i];
+      const int size = sizeof(ulong);
+      var hashes = new ulong[node.Arity + 1];
+      var bytes = new byte[(node.Arity + 1) * size];
+
+      for (int j = i - 1, k = 0; k < node.Arity; ++k, j -= 1 + nodes[j].Size) {
+        hashes[k] = nodes[j].CalculatedHashValue;
+      }
+      hashes[node.Arity] = node.HashValue;
+      Buffer.BlockCopy(hashes, 0, bytes, 0, bytes.Length);
+      return hashFunction(bytes);
+    }
+
+    // set the enabled state for the whole subtree rooted at this node 
+    public static void SetEnabled<T>(this HashNode<T>[] nodes, int i, bool enabled) where T : class {
+      nodes[i].Enabled = enabled;
+      for (int j = i - nodes[i].Size; j < i; ++j)
+        nodes[j].Enabled = enabled;
+    }
+
+    public static HashNode<T>[] Simplify<T>(this HashNode<T>[] nodes, Func<byte[], ulong> hashFunction) where T : class {
+      var reduced = nodes.UpdateNodeSizes().Reduce().Sort(hashFunction);
+
+      for (int i = 0; i < reduced.Length; ++i) {
+        var node = reduced[i];
+        if (node.IsLeaf) {
+          continue;
+        }
+        node.Simplify?.Invoke(ref reduced, i);
+      }
+      // detect if anything was simplified
+      var count = 0;
+      foreach (var node in reduced) {
+        if (!node.Enabled) { ++count; }
+      }
+      if (count == 0) {
+        return reduced;
+      }
+
+      var simplified = new HashNode<T>[reduced.Length - count];
+      int j = 0;
+      foreach (var node in reduced) {
+        if (node.Enabled) {
+          simplified[j++] = node;
+        }
+      }
+      return simplified.UpdateNodeSizes().Reduce().Sort(hashFunction);
+    }
+
+    public static HashNode<T>[] Sort<T>(this HashNode<T>[] nodes, Func<byte[], ulong> hashFunction) where T : class {
+      int sort(int a, int b) => nodes[a].CompareTo(nodes[b]);
+
+      for (int i = 0; i < nodes.Length; ++i) {
+        var node = nodes[i];
+
+        if (node.IsLeaf) {
+          continue;
+        }
+
+        if (node.IsCommutative) { // only sort when the argument order does not matter
+          var arity = node.Arity;
+          var size = node.Size;
+
+          if (arity == size) { // all child nodes are terminals
+            Array.Sort(nodes, i - size, size);
+          } else { // i have some non-terminal children
+            var sorted = new HashNode<T>[size];
+            var indices = new int[node.Arity];
+            for (int j = i - 1, k = 0; k < node.Arity; j -= 1 + nodes[j].Size, ++k) {
+              indices[k] = j;
+            }
+            Array.Sort(indices, sort);
+
+            int idx = 0;
+            foreach (var j in indices) {
+              var child = nodes[j];
+              if (!child.IsLeaf) { // must copy complete subtree
+                Array.Copy(nodes, j - child.Size, sorted, idx, child.Size);
+                idx += child.Size;
+              }
+              sorted[idx++] = nodes[j];
+            }
+            Array.Copy(sorted, 0, nodes, i - size, size);
+          }
+        }
+        node.CalculatedHashValue = nodes.ComputeHash(i, hashFunction);
+      }
+      return nodes;
+    }
+
+    /// <summary>
+    /// Get a function node's child indicest
+    /// </summary>
+    /// <typeparam name="T">The data type encapsulated by a hash node</typeparam>
+    /// <param name="nodes">An array of hash nodes with up-to-date node sizes</param>
+    /// <param name="i">The index in the array of hash nodes of the node whose children we want to iterate</param>
+    /// <returns>An array containing child indices</returns>
+    public static int[] IterateChildren<T>(this HashNode<T>[] nodes, int i) where T : class {
+      var node = nodes[i];
+      var arity = node.Arity;
+      var children = new int[arity];
+      var idx = i - 1;
+      for (int j = 0; j < arity; ++j) {
+        children[j] = idx;
+        idx -= 1 + nodes[idx].Size;
+      }
+      return children;
+    }
+
+    public static HashNode<T>[] UpdateNodeSizes<T>(this HashNode<T>[] nodes) where T : class {
+      for (int i = 0; i < nodes.Length; ++i) {
+        var node = nodes[i];
+        if (node.IsLeaf) {
+          node.Size = 0;
+          continue;
+        }
+        node.Size = node.Arity;
+
+        for (int j = i - 1, k = 0; k < node.Arity; j -= 1 + nodes[j].Size, ++k) {
+          node.Size += nodes[j].Size;
+        }
+      }
+      return nodes;
+    }
+
+    private static HashNode<T>[] Reduce<T>(this HashNode<T>[] nodes) where T : class {
+      int count = 0;
+      for (int i = 0; i < nodes.Length; ++i) {
+        var node = nodes[i];
+        if (node.IsLeaf || !node.IsCommutative) {
+          continue;
+        }
+
+        var arity = node.Arity;
+        for (int j = i - 1, k = 0; k < arity; j -= 1 + nodes[j].Size, ++k) {
+          if (node.HashValue == nodes[j].HashValue) {
+            nodes[j].Enabled = false;
+            node.Arity += nodes[j].Arity - 1;
+            ++count;
+          }
+        }
+      }
+      if (count == 0)
+        return nodes;
+
+      var reduced = new HashNode<T>[nodes.Length - count];
+      var idx = 0;
+      foreach (var node in nodes) {
+        if (node.Enabled) { reduced[idx++] = node; }
+      }
+      return reduced.UpdateNodeSizes();
+    }
+  }
+}
Index: branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Hashing/HashUtil.cs
===================================================================
--- branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Hashing/HashUtil.cs	(revision 16388)
+++ branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Hashing/HashUtil.cs	(revision 16388)
@@ -0,0 +1,92 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2018 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.Security.Cryptography;
+
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
+  public static class HashUtil {
+    // This class contains some hash functions adapted from http://partow.net/programming/hashfunctions/index.html#AvailableHashFunctions
+
+    // A simple hash function from Robert Sedgwicks Algorithms in C book.I've added some simple optimizations to the algorithm in order to speed up its hashing process. 
+    public static ulong RSHash(byte[] input) {
+      const int b = 378551;
+      ulong a = 63689;
+      ulong hash = 0;
+
+      foreach (var v in input) {
+        hash = (hash * a) + v;
+        a *= b;
+      }
+      return hash;
+    }
+
+    // A bitwise hash function written by Justin Sobel
+    public static ulong JSHash(byte[] input) {
+      ulong hash = 1315423911;
+      for (int i = 0; i < input.Length; ++i)
+        hash ^= (hash << 5) + input[i] + (hash >> 2);
+      return hash;
+    }
+
+    // This hash function comes from Brian Kernighan and Dennis Ritchie's book "The C Programming Language". It is a simple hash function using a strange set of possible seeds which all constitute a pattern of 31....31...31 etc, it seems to be very similar to the DJB hash function. 
+    public static ulong BKDRHash(byte[] input) {
+      ulong seed = 131;
+      ulong hash = 0;
+      foreach (var v in input) {
+        hash = (hash * seed) + v;
+      }
+      return hash;
+    }
+
+    // This is the algorithm of choice which is used in the open source SDBM project. The hash function seems to have a good over-all distribution for many different data sets. It seems to work well in situations where there is a high variance in the MSBs of the elements in a data set. 
+    public static ulong SDBMHash(byte[] input) {
+      ulong hash = 0;
+      foreach (var v in input) {
+        hash = v + (hash << 6) + (hash << 16) - hash;
+      }
+      return hash;
+    }
+
+    // An algorithm produced by Professor Daniel J. Bernstein and shown first to the world on the usenet newsgroup comp.lang.c. It is one of the most efficient hash functions ever published. 
+    public static ulong DJBHash(byte[] input) {
+      ulong hash = 5381;
+      foreach (var v in input) {
+        hash = (hash << 5) + hash + v;
+      }
+      return hash;
+    }
+
+    // An algorithm proposed by Donald E.Knuth in The Art Of Computer Programming Volume 3, under the topic of sorting and search chapter 6.4. 
+    public static ulong DEKHash(byte[] input) {
+      ulong hash = (ulong)input.Length;
+      foreach (var v in input) {
+        hash = (hash << 5) ^ (hash >> 27) ^ v;
+      }
+      return hash;
+    }
+
+    public static ulong CryptoHash(HashAlgorithm ha, byte[] input) {
+      return BitConverter.ToUInt64(ha.ComputeHash(input), 0);
+    }
+  }
+}
Index: branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Hashing/SymbolicExpressionTreeHash.cs
===================================================================
--- branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Hashing/SymbolicExpressionTreeHash.cs	(revision 16388)
+++ branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Hashing/SymbolicExpressionTreeHash.cs	(revision 16388)
@@ -0,0 +1,364 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2018 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 static HeuristicLab.Problems.DataAnalysis.Symbolic.SymbolicExpressionHashExtensions;
+
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
+  public static class SymbolicExpressionTreeHash {
+    private static readonly Addition add = new Addition();
+    private static readonly Subtraction sub = new Subtraction();
+    private static readonly Multiplication mul = new Multiplication();
+    private static readonly Division div = new Division();
+    private static readonly Logarithm log = new Logarithm();
+    private static readonly Exponential exp = new Exponential();
+    private static readonly Sine sin = new Sine();
+    private static readonly Cosine cos = new Cosine();
+    private static readonly Constant constant = new Constant();
+
+    private static readonly ISymbolicExpressionTreeNodeComparer comparer = new SymbolicExpressionTreeNodeComparer();
+
+    public static ulong ComputeHash(this ISymbolicExpressionTree tree) {
+      return ComputeHash(tree.Root.GetSubtree(0).GetSubtree(0));
+    }
+
+    public static double ComputeSimilarity(ISymbolicExpressionTree t1, ISymbolicExpressionTree t2, bool simplify = false) {
+      return ComputeSimilarity(t1.Root.GetSubtree(0).GetSubtree(0), t2.Root.GetSubtree(0).GetSubtree(0), simplify);
+    }
+
+    public static double ComputeSimilarity(ISymbolicExpressionTreeNode t1, ISymbolicExpressionTreeNode t2, bool simplify = false) {
+      HashNode<ISymbolicExpressionTreeNode>[] lhs;
+      HashNode<ISymbolicExpressionTreeNode>[] rhs;
+
+      ulong hashFunction(byte[] input) => HashUtil.DJBHash(input);
+
+      if (simplify) {
+        lhs = t1.MakeNodes().Simplify(hashFunction);
+        rhs = t2.MakeNodes().Simplify(hashFunction);
+      } else {
+        lhs = t1.MakeNodes().Sort(hashFunction); // sort calculates hash values
+        rhs = t2.MakeNodes().Sort(hashFunction);
+      }
+
+      var lh = lhs.Select(x => x.CalculatedHashValue).ToArray();
+      var rh = rhs.Select(x => x.CalculatedHashValue).ToArray();
+
+      Array.Sort(lh);
+      Array.Sort(rh);
+
+      return ComputeSimilarity(lh, rh);
+    }
+
+    // this will only work if lh and rh are sorted
+    private static double ComputeSimilarity(ulong[] lh, ulong[] rh) {
+      double count = 0;
+      for (int i = 0, j = 0; i < lh.Length && j < rh.Length;) {
+        var h1 = lh[i];
+        var h2 = rh[j];
+        if (h1 == h2) {
+          ++count;
+          ++i;
+          ++j;
+        } else if (h1 < h2) {
+          ++i;
+        } else if (h1 > h2) {
+          ++j;
+        }
+      }
+
+      return 2d * count / (lh.Length + rh.Length);
+    }
+
+    public static double ComputeAverageSimilarity(IList<ISymbolicExpressionTree> trees, bool simplify = false, bool strict = false) {
+      var total = (double)trees.Count * (trees.Count - 1) / 2;
+      double avg = 0;
+      var hashes = new ulong[trees.Count][];
+      // build hash arrays
+      for (int i = 0; i < trees.Count; ++i) {
+        var nodes = trees[i].MakeNodes(strict);
+        hashes[i] = (simplify ? nodes.Simplify(HashUtil.DJBHash) : nodes.Sort(HashUtil.DJBHash)).Select(x => x.CalculatedHashValue).ToArray();
+        Array.Sort(hashes[i]);
+      }
+      // compute similarity matrix
+      for (int i = 0; i < trees.Count - 1; ++i) {
+        for (int j = i + 1; j < trees.Count; ++j) {
+          avg += ComputeSimilarity(hashes[i], hashes[j]);
+        }
+      }
+      return avg / total;
+    }
+
+    public static double[,] ComputeSimilarityMatrix(IList<ISymbolicExpressionTree> trees, bool simplify = false, bool strict = false) {
+      var sim = new double[trees.Count, trees.Count];
+      var hashes = new ulong[trees.Count][];
+      // build hash arrays
+      for (int i = 0; i < trees.Count; ++i) {
+        var nodes = trees[i].MakeNodes(strict);
+        hashes[i] = (simplify ? nodes.Simplify(HashUtil.DJBHash) : nodes.Sort(HashUtil.DJBHash)).Select(x => x.CalculatedHashValue).ToArray();
+        Array.Sort(hashes[i]);
+      }
+      // compute similarity matrix
+      for (int i = 0; i < trees.Count - 1; ++i) {
+        for (int j = i + 1; j < trees.Count; ++j) {
+          sim[i, j] = sim[j, i] = ComputeSimilarity(hashes[i], hashes[j]);
+        }
+      }
+      return sim;
+    }
+
+    public static ulong ComputeHash(this ISymbolicExpressionTreeNode treeNode, bool strict = false) {
+      ulong hashFunction(byte[] input) => HashUtil.JSHash(input);
+      var hashNodes = treeNode.MakeNodes(strict);
+      var simplified = hashNodes.Simplify(hashFunction);
+      return simplified.Last().CalculatedHashValue;
+    }
+
+    public static HashNode<ISymbolicExpressionTreeNode> ToHashNode(this ISymbolicExpressionTreeNode node, bool strict = false) {
+      var symbol = node.Symbol;
+      var name = symbol.Name;
+      if (node is ConstantTreeNode constantNode) {
+        name = strict ? constantNode.Value.ToString() : symbol.Name;
+      } else if (node is VariableTreeNode variableNode) {
+        name = strict ? variableNode.Weight.ToString() + variableNode.VariableName : variableNode.VariableName;
+      }
+      var hash = (ulong)name.GetHashCode();
+      var hashNode = new HashNode<ISymbolicExpressionTreeNode>(comparer) {
+        Data = node,
+        Arity = node.SubtreeCount,
+        Size = node.SubtreeCount,
+        IsCommutative = node.Symbol is Addition || node.Symbol is Multiplication,
+        Enabled = true,
+        HashValue = hash,
+        CalculatedHashValue = hash
+      };
+      if (symbol is Addition) {
+        hashNode.Simplify = SimplifyAddition;
+      } else if (symbol is Multiplication) {
+        hashNode.Simplify = SimplifyMultiplication;
+      } else if (symbol is Division) {
+        hashNode.Simplify = SimplifyDivision;
+      } else if (symbol is Logarithm || symbol is Exponential || symbol is Sine || symbol is Cosine) {
+        hashNode.Simplify = SimplifyUnaryNode;
+      } else if (symbol is Subtraction) {
+        hashNode.Simplify = SimplifyBinaryNode;
+      }
+      return hashNode;
+    }
+
+    public static HashNode<ISymbolicExpressionTreeNode>[] MakeNodes(this ISymbolicExpressionTree tree, bool strict = false) {
+      return MakeNodes(tree.Root.GetSubtree(0).GetSubtree(0), strict);
+    }
+
+    public static HashNode<ISymbolicExpressionTreeNode>[] MakeNodes(this ISymbolicExpressionTreeNode node, bool strict = false) {
+      return node.IterateNodesPostfix().Select(x => x.ToHashNode(strict)).ToArray().UpdateNodeSizes();
+    }
+
+    #region parse a nodes array back into a tree
+    public static ISymbolicExpressionTree ToTree(this HashNode<ISymbolicExpressionTreeNode>[] nodes) {
+      var root = new ProgramRootSymbol().CreateTreeNode();
+      var start = new StartSymbol().CreateTreeNode();
+      root.AddSubtree(start);
+      start.AddSubtree(nodes.ToSubtree());
+      return new SymbolicExpressionTree(root);
+    }
+
+    public static ISymbolicExpressionTreeNode ToSubtree(this HashNode<ISymbolicExpressionTreeNode>[] nodes) {
+      var treeNodes = nodes.Select(x => x.Data.Symbol.CreateTreeNode()).ToArray();
+
+      for (int i = nodes.Length - 1; i >= 0; --i) {
+        var node = nodes[i];
+
+        if (node.IsLeaf) {
+          if (node.Data is VariableTreeNode variable) {
+            var variableTreeNode = (VariableTreeNode)treeNodes[i];
+            variableTreeNode.VariableName = variable.VariableName;
+            variableTreeNode.Weight = variable.Weight;
+          } else if (node.Data is ConstantTreeNode @const) {
+            var constantTreeNode = (ConstantTreeNode)treeNodes[i];
+            constantTreeNode.Value = @const.Value;
+          }
+          continue;
+        }
+
+        var treeNode = treeNodes[i];
+
+        foreach (var j in nodes.IterateChildren(i)) {
+          treeNode.AddSubtree(treeNodes[j]);
+        }
+      }
+
+      return treeNodes.Last();
+    }
+
+    private static T CreateTreeNode<T>(this ISymbol symbol) where T : class, ISymbolicExpressionTreeNode {
+      return (T)symbol.CreateTreeNode();
+    }
+    #endregion
+
+    #region tree simplification
+    // these simplification methods rely on the assumption that child nodes of the current node have already been simplified
+    // (in other words simplification should be applied in a bottom-up fashion)
+    public static ISymbolicExpressionTree Simplify(ISymbolicExpressionTree tree) {
+      ulong hashFunction(byte[] bytes) => HashUtil.JSHash(bytes);
+      var root = tree.Root.GetSubtree(0).GetSubtree(0);
+      var nodes = root.MakeNodes();
+      var simplified = nodes.Simplify(hashFunction);
+      return simplified.ToTree();
+    }
+
+    public static void SimplifyAddition(ref HashNode<ISymbolicExpressionTreeNode>[] nodes, int i) {
+      // simplify additions of terms by eliminating terms with the same symbol and hash
+      var children = nodes.IterateChildren(i);
+
+      // we always assume the child nodes are sorted
+      var curr = children[0];
+      var node = nodes[i];
+
+      foreach (var j in children.Skip(1)) {
+        if (nodes[j] == nodes[curr]) {
+          nodes.SetEnabled(j, false);
+          node.Arity--;
+        } else {
+          curr = j;
+        }
+      }
+      if (node.Arity == 1) { // if the arity is 1 we don't need the addition node at all
+        node.Enabled = false;
+      }
+    }
+
+    // simplify multiplications by reducing constants and div terms
+    public static void SimplifyMultiplication(ref HashNode<ISymbolicExpressionTreeNode>[] nodes, int i) {
+      var node = nodes[i];
+      var children = nodes.IterateChildren(i);
+
+      for (int j = 0; j < children.Length; ++j) {
+        var c = children[j];
+        var child = nodes[c];
+
+        if (!child.Enabled)
+          continue;
+
+        var symbol = child.Data.Symbol;
+        if (symbol is Constant) {
+          for (int k = j + 1; k < children.Length; ++k) {
+            var d = children[k];
+            if (nodes[d].Data.Symbol is Constant) {
+              nodes[d].Enabled = false;
+              node.Arity--;
+            } else {
+              break;
+            }
+          }
+        } else if (symbol is Division) {
+          var div = nodes[c];
+          var denominator =
+            div.Arity == 1 ?
+            nodes[c - 1] :                    // 1 / x is expressed as div(x) (with a single child)
+            nodes[c - nodes[c - 1].Size - 2]; // assume division always has arity 1 or 2
+
+          foreach (var d in children) {
+            if (nodes[d].Enabled && nodes[d] == denominator) {
+              nodes[c].Enabled = nodes[d].Enabled = denominator.Enabled = false;
+              node.Arity -= 2; // matching child + division node
+              break;
+            }
+          }
+        }
+
+        if (node.Arity == 0) { // if everything is simplified this node becomes constant
+          var constantTreeNode = constant.CreateTreeNode<ConstantTreeNode>();
+          constantTreeNode.Value = 1;
+          nodes[i] = constantTreeNode.ToHashNode();
+        } else if (node.Arity == 1) { // when i have only 1 arg left i can skip this node
+          node.Enabled = false;
+        }
+      }
+    }
+
+    public static void SimplifyDivision(ref HashNode<ISymbolicExpressionTreeNode>[] nodes, int i) {
+      var node = nodes[i];
+      var children = nodes.IterateChildren(i);
+
+      var tmp = nodes;
+
+      if (children.All(x => tmp[x].Data.Symbol is Constant)) {
+        var v = ((ConstantTreeNode)nodes[children.First()].Data).Value;
+        if (node.Arity == 1) {
+          v = 1 / v;
+        } else if (node.Arity > 1) {
+          foreach (var j in children.Skip(1)) {
+            v /= ((ConstantTreeNode)nodes[j].Data).Value;
+          }
+        }
+        var constantTreeNode = constant.CreateTreeNode<ConstantTreeNode>();
+        constantTreeNode.Value = v;
+        nodes[i] = constantTreeNode.ToHashNode();
+        return;
+      }
+
+      var nominator = nodes[children[0]];
+      foreach (var j in children.Skip(1)) {
+        var denominator = nodes[j];
+        if (nominator == denominator) {
+          // disable all the children of the division node (nominator and children + denominator and children)
+          nominator.Enabled = denominator.Enabled = false;
+          node.Arity -= 2; // nominator + denominator
+        }
+        if (node.Arity == 0) {
+          var constantTreeNode = constant.CreateTreeNode<ConstantTreeNode>();
+          constantTreeNode.Value = 1; // x / x = 1
+          nodes[i] = constantTreeNode.ToHashNode();
+        }
+      }
+    }
+
+    public static void SimplifyUnaryNode(ref HashNode<ISymbolicExpressionTreeNode>[] nodes, int i) {
+      // check if the child of the unary node is a constant, then the whole node can be simplified
+      var parent = nodes[i];
+      var child = nodes[i - 1];
+
+      var parentSymbol = parent.Data.Symbol;
+      var childSymbol = child.Data.Symbol;
+
+      if (childSymbol is Constant) {
+        nodes[i].Enabled = false;
+      } else if ((parentSymbol is Exponential && childSymbol is Logarithm) || (parentSymbol is Logarithm && childSymbol is Exponential)) {
+        child.Enabled = parent.Enabled = false;
+      }
+    }
+
+    public static void SimplifyBinaryNode(ref HashNode<ISymbolicExpressionTreeNode>[] nodes, int i) {
+      var children = nodes.IterateChildren(i);
+      var tmp = nodes;
+      if (children.All(x => tmp[x].Data.Symbol is Constant)) {
+        foreach (var j in children) {
+          nodes[j].Enabled = false;
+        }
+        nodes[i] = constant.CreateTreeNode().ToHashNode();
+      }
+    }
+    #endregion
+  }
+}
Index: branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4.csproj
===================================================================
--- branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4.csproj	(revision 15743)
+++ branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4.csproj	(revision 16388)
@@ -107,4 +107,9 @@
       <Private>False</Private>
     </Reference>
+    <Reference Include="HeuristicLab.Problems.DataAnalysis.Symbolic.NativeInterpreter-0.1, Version=0.0.0.1, Culture=neutral, PublicKeyToken=ba48961d6f65dcec, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\..\bin\HeuristicLab.Problems.DataAnalysis.Symbolic.NativeInterpreter-0.1.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
     <Reference Include="System" />
     <Reference Include="System.Core">
@@ -123,4 +128,5 @@
   <ItemGroup>
     <Compile Include="Analyzers\SymbolicDataAnalysisBottomUpDiversityAnalyzer.cs" />
+    <Compile Include="Analyzers\SymbolicDataAnalysisBuildingBlockAnalyzer.cs" />
     <Compile Include="Analyzers\SymbolicDataAnalysisSingleObjectivePruningAnalyzer.cs" />
     <Compile Include="Analyzers\SymbolicDataAnalysisSingleObjectiveValidationParetoBestSolutionAnalyzer.cs" />
@@ -139,8 +145,14 @@
     <Compile Include="Converters\LinearModelToTreeConverter.cs" />
     <Compile Include="Converters\TreeSimplifier.cs" />
+    <Compile Include="Converters\DerivativeCalculator.cs" />
     <Compile Include="Converters\TreeToAutoDiffTermConverter.cs" />
+    <Compile Include="Crossovers\SymbolicDataAnalysisExpressionDiversityPreservingCrossover.cs" />
     <Compile Include="Formatters\InfixExpressionFormatter.cs" />
+    <Compile Include="Formatters\TSQLExpressionFormatter.cs" />
     <Compile Include="Formatters\SymbolicDataAnalysisExpressionMathematicaFormatter.cs" />
     <Compile Include="Formatters\SymbolicDataAnalysisExpressionCSharpFormatter.cs" />
+    <Compile Include="Hashing\HashExtensions.cs" />
+    <Compile Include="Hashing\HashUtil.cs" />
+    <Compile Include="Hashing\SymbolicExpressionTreeHash.cs" />
     <Compile Include="Importer\InfixExpressionParser.cs" />
     <Compile Include="Importer\SymbolicExpressionImporter.cs" />
@@ -149,5 +161,9 @@
     <Compile Include="Interfaces\IVariableTreeNode.cs" />
     <Compile Include="Interfaces\IVariableSymbol.cs" />
+    <Compile Include="Interpreter\BatchInstruction.cs" />
+    <Compile Include="Interpreter\BatchOperations.cs" />
     <Compile Include="Interpreter\SymbolicDataAnalysisExpressionCompiledTreeInterpreter.cs" />
+    <Compile Include="Interpreter\SymbolicDataAnalysisExpressionTreeBatchInterpreter.cs" />
+    <Compile Include="Interpreter\SymbolicDataAnalysisExpressionTreeNativeInterpreter.cs" />
     <Compile Include="SymbolicDataAnalysisExpressionTreeSimplificationOperator.cs" />
     <Compile Include="SymbolicDataAnalysisModelComplexityCalculator.cs" />
@@ -197,4 +213,5 @@
     <Compile Include="SymbolicDataAnalysisSolutionImpactValuesCalculator.cs" />
     <Compile Include="Symbols\Addition.cs" />
+    <Compile Include="Symbols\AnalyticQuotient.cs" />
     <Compile Include="Symbols\And.cs" />
     <Compile Include="Symbols\AutoregressiveVariable.cs" />
@@ -207,6 +224,9 @@
     <Compile Include="Symbols\BinaryFactorVariable.cs" />
     <Compile Include="Symbols\BinaryFactorVariableTreeNode.cs" />
+    <Compile Include="Symbols\Cube.cs" />
     <Compile Include="Symbols\FactorVariableTreeNode.cs" />
     <Compile Include="Symbols\FactorVariable.cs" />
+    <Compile Include="Symbols\Absolute.cs" />
+    <Compile Include="Symbols\CubeRoot.cs" />
     <Compile Include="Symbols\VariableBase.cs" />
     <Compile Include="Symbols\VariableTreeNodeBase.cs" />
Index: branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Importer/InfixExpressionParser.cs
===================================================================
--- branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Importer/InfixExpressionParser.cs	(revision 15743)
+++ branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Importer/InfixExpressionParser.cs	(revision 16388)
@@ -42,8 +42,11 @@
   /// Expr          = ['-' | '+'] Term { '+' Term | '-' Term }
   /// Term          = Fact { '*' Fact | '/' Fact }
-  /// Fact          = '(' Expr ')' 
-  ///                 | 'LAG' '(' varId ',' ['+' | '-' ] number ')' 
-  ///                 | funcId '(' ArgList ')' 
-  ///                 | VarExpr | number
+  /// Fact          = SimpleFact [ '^' SimpleFact ]
+  /// SimpleFact    = '(' Expr ')'
+  ///                 | '{' Expr '}'
+  ///                 | 'LAG' '(' varId ',' ['+' | '-' ] number ')
+  ///                 | funcId '(' ArgList ')'
+  ///                 | VarExpr
+  ///                 | number
   /// ArgList       = Expr { ',' Expr }
   /// VarExpr       = varId OptFactorPart
@@ -95,10 +98,14 @@
         { "*", new Multiplication()},
         { "-", new Subtraction()},
+        { "^", new Power() },
+        { "ABS", new Absolute() },
         { "EXP", new Exponential()},
         { "LOG", new Logarithm()},
-        { "POW", new Power()},
+        { "POW", new Power() },
         { "ROOT", new Root()},
         { "SQR", new Square() },
         { "SQRT", new SquareRoot() },
+        { "CUBE", new Cube() },
+        { "CUBEROOT", new CubeRoot() },
         { "SIN",new Sine()},
         { "COS", new Cosine()},
@@ -119,4 +126,5 @@
         { "DAWSON", new Dawson()},
         { "EXPINT", new ExponentialIntegralEi()},
+        { "AQ", new AnalyticQuotient() },
         { "MEAN", new Average()},
         { "IF", new IfThenElse()},
@@ -167,6 +175,8 @@
             && str[pos] != '*'
             && str[pos] != '/'
+            && str[pos] != '^'
             && str[pos] != ')'
             && str[pos] != ']'
+            && str[pos] != '}'
             && str[pos] != ',') {
             sb.Append(str[pos]);
@@ -227,4 +237,7 @@
           pos++;
           yield return new Token { TokenType = TokenType.Operator, strVal = "*" };
+        } else if (str[pos] == '^') {
+          pos++;
+          yield return new Token { TokenType = TokenType.Operator, strVal = "^" };
         } else if (str[pos] == '(') {
           pos++;
@@ -239,4 +252,10 @@
           pos++;
           yield return new Token { TokenType = TokenType.RightBracket, strVal = "]" };
+        } else if (str[pos] == '{') {
+          pos++;
+          yield return new Token { TokenType = TokenType.LeftPar, strVal = "{" };
+        } else if (str[pos] == '}') {
+          pos++;
+          yield return new Token { TokenType = TokenType.RightPar, strVal = "}" };
         } else if (str[pos] == '=') {
           pos++;
@@ -360,8 +379,26 @@
     }
 
-    /// Fact          = '(' Expr ')' 
-    ///                 | 'LAG' '(' varId ',' ['+' | '-' ] number ')' 
-    ///                 | funcId '(' ArgList ')' 
-    ///                 | VarExpr | number
+    // Fact = SimpleFact ['^' SimpleFact]
+    private ISymbolicExpressionTreeNode ParseFact(Queue<Token> tokens) {
+      var expr = ParseSimpleFact(tokens);
+      var next = tokens.Peek();
+      if (next.TokenType == TokenType.Operator && next.strVal == "^") {
+        tokens.Dequeue(); // skip;
+
+        var p = GetSymbol("^").CreateTreeNode();
+        p.AddSubtree(expr);
+        p.AddSubtree(ParseSimpleFact(tokens));
+        expr = p;
+      }
+      return expr;
+    }
+
+
+    /// SimpleFact   = '(' Expr ')' 
+    ///                 | '{' Expr '}'
+    ///                 | 'LAG' '(' varId ',' ['+' | '-' ] number ')'
+    ///                 | funcId '(' ArgList ')
+    ///                 | VarExpr
+    ///                 | number
     /// ArgList       = Expr { ',' Expr }
     /// VarExpr       = varId OptFactorPart
@@ -370,12 +407,16 @@
     /// varVal        =  ident | ' ident ' | " ident "
     /// ident         =  '_' | letter { '_' | letter | digit }
-    private ISymbolicExpressionTreeNode ParseFact(Queue<Token> tokens) {
+    private ISymbolicExpressionTreeNode ParseSimpleFact(Queue<Token> tokens) {
       var next = tokens.Peek();
       if (next.TokenType == TokenType.LeftPar) {
-        tokens.Dequeue();
+        var initPar = tokens.Dequeue(); // match par type
         var expr = ParseExpr(tokens);
         var rPar = tokens.Dequeue();
         if (rPar.TokenType != TokenType.RightPar)
-          throw new ArgumentException("expected )");
+          throw new ArgumentException("expected closing parenthesis");
+        if (initPar.strVal == "(" && rPar.strVal == "}")
+          throw new ArgumentException("expected closing )");
+        if (initPar.strVal == "{" && rPar.strVal == ")")
+          throw new ArgumentException("expected closing }");
         return expr;
       } else if (next.TokenType == TokenType.Identifier) {
@@ -424,4 +465,5 @@
           if (rPar.TokenType != TokenType.RightPar)
             throw new ArgumentException("expected )");
+
 
           return funcNode;
Index: branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Importer/SymbolicExpressionImporter.cs
===================================================================
--- branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Importer/SymbolicExpressionImporter.cs	(revision 15743)
+++ branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Importer/SymbolicExpressionImporter.cs	(revision 16388)
@@ -41,4 +41,5 @@
         {"*", new Multiplication()},
         {"-", new Subtraction()},
+        {"ABS", new Absolute() },
         {"EXP", new Exponential()},
         {"LOG", new Logarithm()},
@@ -47,4 +48,6 @@
         {"SQR", new Square()},
         {"SQRT", new SquareRoot()},
+        {"CUBE", new Cube()},
+        {"CUBEROOT", new CubeRoot()},
         {"SIN",new Sine()},
         {"COS", new Cosine()},
@@ -65,4 +68,5 @@
         {"DAWSON", new Dawson()},
         {"EXPINT", new ExponentialIntegralEi()},
+        {"AQ", new AnalyticQuotient() },
         {"MEAN", new Average()},
         {"IF", new IfThenElse()},
Index: branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/BatchInstruction.cs
===================================================================
--- branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/BatchInstruction.cs	(revision 16388)
+++ branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/BatchInstruction.cs	(revision 16388)
@@ -0,0 +1,12 @@
+﻿namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
+  public struct BatchInstruction {
+    public byte opcode;
+    public ushort narg;
+    public int childIndex;
+
+    public double value; // for constants
+    public double weight; // for variables
+    public double[] buf;
+    public double[] data; // to hold dataset data
+  }
+}
Index: branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/BatchOperations.cs
===================================================================
--- branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/BatchOperations.cs	(revision 16388)
+++ branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/BatchOperations.cs	(revision 16388)
@@ -0,0 +1,112 @@
+﻿using System;
+
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
+  public static class BatchOperations {
+    public const int BATCHSIZE = 64;
+
+    public static void Load(double[] a, double[] b) {
+      Array.Copy(b, a, BATCHSIZE);
+    }
+
+    public static void Add(double[] a, double[] b) {
+      for (int i = 0; i < BATCHSIZE; ++i) {
+        a[i] += b[i];
+      }
+    }
+
+    public static void Sub(double[] a, double[] b) {
+      for (int i = 0; i < BATCHSIZE; ++i) {
+        a[i] -= b[i];
+      }
+    }
+
+    public static void Div(double[] a, double[] b) {
+      for (int i = 0; i < BATCHSIZE; ++i) {
+        a[i] /= b[i];
+      }
+    }
+
+    public static void Mul(double[] a, double[] b) {
+      for (int i = 0; i < BATCHSIZE; ++i) {
+        a[i] *= b[i];
+      }
+    }
+
+    public static void Neg(double[] a, double[] b) {
+      for (int i = 0; i < BATCHSIZE; ++i) {
+        a[i] = -b[i];
+      }
+    }
+
+    public static void Inv(double[] a, double[] b) {
+      for (int i = 0; i < BATCHSIZE; ++i) {
+        a[i] = 1 / b[i];
+      }
+    }
+
+    public static void Log(double[] a, double[] b) {
+      for (int i = 0; i < BATCHSIZE; ++i)
+        a[i] = Math.Log(b[i]);
+    }
+
+    public static void Exp(double[] a, double[] b) {
+      for (int i = 0; i < BATCHSIZE; ++i)
+        a[i] = Math.Exp(b[i]);
+    }
+
+    public static void Sin(double[] a, double[] b) {
+      for (int i = 0; i < BATCHSIZE; ++i)
+        a[i] = Math.Sin(b[i]);
+    }
+
+    public static void Cos(double[] a, double[] b) {
+      for (int i = 0; i < BATCHSIZE; ++i)
+        a[i] = Math.Cos(b[i]);
+    }
+
+    public static void Tan(double[] a, double[] b) {
+      for (int i = 0; i < BATCHSIZE; ++i)
+        a[i] = Math.Tan(b[i]);
+    }
+
+    public static void Pow(double[] a, double[] b) {
+      for (int i = 0; i < BATCHSIZE; ++i)
+        a[i] = Math.Pow(a[i], Math.Round(b[i]));
+    }
+
+    public static void Root(double[] a, double[] b) {
+      for (int i = 0; i < BATCHSIZE; ++i)
+        a[i] = Math.Pow(a[i], 1 / Math.Round(b[i]));
+    }
+
+    public static void Square(double[] a, double[] b) {
+      for (int i = 0; i < BATCHSIZE; ++i)
+        a[i] = Math.Pow(b[i], 2d);
+    }
+
+    public static void Sqrt(double[] a, double[] b) {
+      for (int i = 0; i < BATCHSIZE; ++i)
+        a[i] = Math.Sqrt(b[i]);
+    }
+
+    public static void Cube(double[] a, double[] b) {
+      for (int i = 0; i < BATCHSIZE; ++i)
+        a[i] = Math.Pow(b[i], 3d);
+    }
+
+    public static void CubeRoot(double[] a, double[] b) {
+      for (int i = 0; i < BATCHSIZE; ++i)
+        a[i] = Math.Pow(b[i], 1d / 3d);
+    }
+
+    public static void Absolute(double[] a, double[] b) {
+      for (int i = 0; i < BATCHSIZE; ++i)
+        a[i] = Math.Abs(b[i]);
+    }
+
+    public static void AnalyticQuotient(double[] a, double[] b) {
+      for (int i = 0; i < BATCHSIZE; ++i)
+        a[i] = a[i] / Math.Sqrt(1d + b[i] * b[i]);
+    }
+  }
+}
Index: branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/OpCodes.cs
===================================================================
--- branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/OpCodes.cs	(revision 15743)
+++ branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/OpCodes.cs	(revision 16388)
@@ -46,5 +46,4 @@
     public const byte OR = 14;
     public const byte NOT = 15;
-    public const byte XOR = 45;
 
 
@@ -83,6 +82,11 @@
     public const byte Erf = 43;
     public const byte Bessel = 44;
+    public const byte XOR = 45;
     public const byte FactorVariable = 46;
     public const byte BinaryFactorVariable = 47;
+    public const byte Absolute = 48;
+    public const byte AnalyticQuotient = 49;
+    public const byte Cube = 50;
+    public const byte CubeRoot = 51;
 
 
@@ -113,5 +117,5 @@
       { typeof(Power),OpCodes.Power},
       { typeof(Root),OpCodes.Root},
-      { typeof(TimeLag), OpCodes.TimeLag}, 
+      { typeof(TimeLag), OpCodes.TimeLag},
       { typeof(Integral), OpCodes.Integral},
       { typeof(Derivative), OpCodes.Derivative},
@@ -135,5 +139,9 @@
       { typeof(Bessel), OpCodes.Bessel},
       { typeof(FactorVariable), OpCodes.FactorVariable },
-      { typeof(BinaryFactorVariable), OpCodes.BinaryFactorVariable }
+      { typeof(BinaryFactorVariable), OpCodes.BinaryFactorVariable },
+      { typeof(Absolute), OpCodes.Absolute },
+      { typeof(AnalyticQuotient), OpCodes.AnalyticQuotient },
+      { typeof(Cube), OpCodes.Cube },
+      { typeof(CubeRoot), OpCodes.CubeRoot }
     };
 
Index: branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionCompiledTreeInterpreter.cs
===================================================================
--- branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionCompiledTreeInterpreter.cs	(revision 15743)
+++ branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionCompiledTreeInterpreter.cs	(revision 16388)
@@ -41,4 +41,5 @@
 
     #region method info for the commonly called functions
+    private static readonly MethodInfo Abs = typeof(Math).GetMethod("Abs", new[] { typeof(double) });
     private static readonly MethodInfo Sin = typeof(Math).GetMethod("Sin", new[] { typeof(double) });
     private static readonly MethodInfo Cos = typeof(Math).GetMethod("Cos", new[] { typeof(double) });
@@ -207,4 +208,8 @@
             return Expression.Divide(result, Expression.Constant((double)node.SubtreeCount));
           }
+        case OpCodes.Absolute: {
+            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
+            return Expression.Call(Abs, arg);
+          }
         case OpCodes.Cos: {
             var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
@@ -222,4 +227,8 @@
             var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
             return Expression.Power(arg, Expression.Constant(2.0));
+          }
+        case OpCodes.Cube: {
+            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
+            return Expression.Power(arg, Expression.Constant(3.0));
           }
         case OpCodes.Power: {
@@ -231,4 +240,8 @@
             var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
             return Expression.Call(Sqrt, arg);
+          }
+        case OpCodes.CubeRoot: {
+            var arg = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
+            return Expression.Power(arg, Expression.Constant(1.0 / 3.0));
           }
         case OpCodes.Root: {
@@ -493,4 +506,13 @@
                 Expression.Assign(result, Expression.Call(Bessel, arg))),
               result);
+          }
+        case OpCodes.AnalyticQuotient: {
+            var x1 = MakeExpr(node.GetSubtree(0), variableIndices, row, columns);
+            var x2 = MakeExpr(node.GetSubtree(1), variableIndices, row, columns);
+            return Expression.Divide(x1, 
+              Expression.Call(Sqrt, 
+              Expression.Add(
+                Expression.Constant(1.0),
+                Expression.Multiply(x2, x2))));
           }
         case OpCodes.IfThenElse: {
Index: branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeBatchInterpreter.cs
===================================================================
--- branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeBatchInterpreter.cs	(revision 16388)
+++ branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeBatchInterpreter.cs	(revision 16388)
@@ -0,0 +1,267 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Linq;
+
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+using static HeuristicLab.Problems.DataAnalysis.Symbolic.BatchOperations;
+
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
+  [Item("SymbolicDataAnalysisExpressionTreeBatchInterpreter", "An interpreter that uses batching and vectorization techniques to achieve faster performance.")]
+  [StorableClass]
+  public class SymbolicDataAnalysisExpressionTreeBatchInterpreter : ParameterizedNamedItem, ISymbolicDataAnalysisExpressionTreeInterpreter {
+    private const string EvaluatedSolutionsParameterName = "EvaluatedSolutions";
+
+    #region parameters
+    public IFixedValueParameter<IntValue> EvaluatedSolutionsParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[EvaluatedSolutionsParameterName]; }
+    }
+    #endregion
+
+    #region properties
+    public int EvaluatedSolutions {
+      get { return EvaluatedSolutionsParameter.Value.Value; }
+      set { EvaluatedSolutionsParameter.Value.Value = value; }
+    }
+    #endregion
+
+    public void ClearState() { }
+
+    public SymbolicDataAnalysisExpressionTreeBatchInterpreter() {
+      Parameters.Add(new FixedValueParameter<IntValue>(EvaluatedSolutionsParameterName, "A counter for the total number of solutions the interpreter has evaluated", new IntValue(0)));
+    }
+
+    [StorableConstructor]
+    protected SymbolicDataAnalysisExpressionTreeBatchInterpreter(bool deserializing) : base(deserializing) { }
+    protected SymbolicDataAnalysisExpressionTreeBatchInterpreter(SymbolicDataAnalysisExpressionTreeBatchInterpreter original, Cloner cloner) : base(original, cloner) {
+    }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new SymbolicDataAnalysisExpressionTreeBatchInterpreter(this, cloner);
+    }
+
+    private void LoadData(BatchInstruction instr, int[] rows, int rowIndex, int batchSize) {
+      for (int i = 0; i < batchSize; ++i) {
+        var row = rows[rowIndex] + i;
+        instr.buf[i] = instr.weight * instr.data[row];
+      }
+    }
+
+    private void Evaluate(BatchInstruction[] code, int[] rows, int rowIndex, int batchSize) {
+      for (int i = code.Length - 1; i >= 0; --i) {
+        var instr = code[i];
+        var c = instr.childIndex;
+        var n = instr.narg;
+
+        switch (instr.opcode) {
+          case OpCodes.Variable: {
+              LoadData(instr, rows, rowIndex, batchSize);
+              break;
+            }
+
+          case OpCodes.Add: {
+              Load(instr.buf, code[c].buf);
+              for (int j = 1; j < n; ++j) {
+                Add(instr.buf, code[c + j].buf);
+              }
+              break;
+            }
+
+          case OpCodes.Sub: {
+              if (n == 1) {
+                Neg(instr.buf, code[c].buf);
+              } else {
+                Load(instr.buf, code[c].buf);
+                for (int j = 1; j < n; ++j) {
+                  Sub(instr.buf, code[c + j].buf);
+                }
+              }
+              break;
+            }
+
+          case OpCodes.Mul: {
+              Load(instr.buf, code[c].buf);
+              for (int j = 1; j < n; ++j) {
+                Mul(instr.buf, code[c + j].buf);
+              }
+              break;
+            }
+
+          case OpCodes.Div: {
+              if (n == 1) {
+                Inv(instr.buf, code[c].buf);
+              } else {
+                Load(instr.buf, code[c].buf);
+                for (int j = 1; j < n; ++j) {
+                  Div(instr.buf, code[c + j].buf);
+                }
+              }
+              break;
+            }
+
+          case OpCodes.Square: {
+              Square(instr.buf, code[c].buf);
+              break;
+            }
+
+          case OpCodes.Root: {
+              Load(instr.buf, code[c].buf);
+              Root(instr.buf, code[c + 1].buf);
+              break;
+            }
+
+          case OpCodes.SquareRoot: {
+              Sqrt(instr.buf, code[c].buf);
+              break;
+            }
+
+          case OpCodes.Cube: {
+              Cube(instr.buf, code[c].buf);
+              break;
+            }
+          case OpCodes.CubeRoot: {
+              CubeRoot(instr.buf, code[c].buf);
+              break;
+            }
+
+          case OpCodes.Power: {
+              Load(instr.buf, code[c].buf);
+              Pow(instr.buf, code[c + 1].buf);
+              break;
+            }
+
+          case OpCodes.Exp: {
+              Exp(instr.buf, code[c].buf);
+              break;
+            }
+
+          case OpCodes.Log: {
+              Log(instr.buf, code[c].buf);
+              break;
+            }
+
+          case OpCodes.Sin: {
+              Sin(instr.buf, code[c].buf);
+              break;
+            }
+
+          case OpCodes.Cos: {
+              Cos(instr.buf, code[c].buf);
+              break;
+            }
+
+          case OpCodes.Tan: {
+              Tan(instr.buf, code[c].buf);
+              break;
+            }
+
+          case OpCodes.Absolute: {
+              Absolute(instr.buf, code[c].buf);
+              break;
+            }
+
+          case OpCodes.AnalyticQuotient: {
+              Load(instr.buf, code[c].buf);
+              AnalyticQuotient(instr.buf, code[c + 1].buf);
+              break;
+            }
+        }
+      }
+    }
+
+    private readonly object syncRoot = new object();
+
+    [ThreadStatic]
+    private Dictionary<string, double[]> cachedData;
+
+    [ThreadStatic]
+    private IDataset dataset;
+
+    private void InitCache(IDataset dataset) {
+      this.dataset = dataset;
+      cachedData = new Dictionary<string, double[]>();
+      foreach (var v in dataset.DoubleVariables) {
+        cachedData[v] = dataset.GetDoubleValues(v).ToArray();
+      }
+    }
+
+    public void InitializeState() {
+      cachedData = null;
+      dataset = null;
+      EvaluatedSolutions = 0;
+    }
+
+    private double[] GetValues(ISymbolicExpressionTree tree, IDataset dataset, int[] rows) {
+      if (cachedData == null || this.dataset != dataset) {
+        InitCache(dataset);
+      }
+
+      var code = Compile(tree, dataset, OpCodes.MapSymbolToOpCode);
+      var remainingRows = rows.Length % BATCHSIZE;
+      var roundedTotal = rows.Length - remainingRows;
+
+      var result = new double[rows.Length];
+
+      for (int rowIndex = 0; rowIndex < roundedTotal; rowIndex += BATCHSIZE) {
+        Evaluate(code, rows, rowIndex, BATCHSIZE);
+        Array.Copy(code[0].buf, 0, result, rowIndex, BATCHSIZE);
+      }
+
+      if (remainingRows > 0) {
+        Evaluate(code, rows, roundedTotal, remainingRows);
+        Array.Copy(code[0].buf, 0, result, roundedTotal, remainingRows);
+      }
+
+      // when evaluation took place without any error, we can increment the counter
+      lock (syncRoot) {
+        EvaluatedSolutions++;
+      }
+
+      return result;
+    }
+
+    public IEnumerable<double> GetSymbolicExpressionTreeValues(ISymbolicExpressionTree tree, IDataset dataset, int[] rows) {
+      return GetValues(tree, dataset, rows);
+    }
+
+    public IEnumerable<double> GetSymbolicExpressionTreeValues(ISymbolicExpressionTree tree, IDataset dataset, IEnumerable<int> rows) {
+      return GetSymbolicExpressionTreeValues(tree, dataset, rows.ToArray());
+    }
+
+    private BatchInstruction[] Compile(ISymbolicExpressionTree tree, IDataset dataset, Func<ISymbolicExpressionTreeNode, byte> opCodeMapper) {
+      var root = tree.Root.GetSubtree(0).GetSubtree(0);
+      var code = new BatchInstruction[root.GetLength()];
+      if (root.SubtreeCount > ushort.MaxValue) throw new ArgumentException("Number of subtrees is too big (>65.535)");
+      int c = 1, i = 0;
+      foreach (var node in root.IterateNodesBreadth()) {
+        if (node.SubtreeCount > ushort.MaxValue) throw new ArgumentException("Number of subtrees is too big (>65.535)");
+        code[i] = new BatchInstruction {
+          opcode = opCodeMapper(node),
+          narg = (ushort)node.SubtreeCount,
+          buf = new double[BATCHSIZE],
+          childIndex = c
+        };
+        if (node is VariableTreeNode variable) {
+          code[i].weight = variable.Weight;
+          if (cachedData.ContainsKey(variable.VariableName)) {
+            code[i].data = cachedData[variable.VariableName];
+          } else {
+            code[i].data = dataset.GetReadOnlyDoubleValues(variable.VariableName).ToArray();
+            cachedData[variable.VariableName] = code[i].data;
+          }
+        } else if (node is ConstantTreeNode constant) {
+          code[i].value = constant.Value;
+          for (int j = 0; j < BATCHSIZE; ++j)
+            code[i].buf[j] = code[i].value;
+        }
+        c += node.SubtreeCount;
+        ++i;
+      }
+      return code;
+    }
+  }
+}
Index: branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeILEmittingInterpreter.cs
===================================================================
--- branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeILEmittingInterpreter.cs	(revision 15743)
+++ branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeILEmittingInterpreter.cs	(revision 16388)
@@ -50,4 +50,5 @@
     private static MethodInfo round = typeof(Math).GetMethod("Round", new Type[] { typeof(double) });
     private static MethodInfo sqrt = typeof(Math).GetMethod("Sqrt", new Type[] { typeof(double) });
+    private static MethodInfo abs = typeof(Math).GetMethod("Abs", new Type[] { typeof(double) });
 
     private static MethodInfo airyA = thisType.GetMethod("AiryA", new Type[] { typeof(double) });
@@ -264,4 +265,9 @@
             return;
           }
+        case OpCodes.Absolute: {
+            CompileInstructions(il, state, ds);
+            il.Emit(System.Reflection.Emit.OpCodes.Call, abs);
+            return;
+          }
         case OpCodes.Cos: {
             CompileInstructions(il, state, ds);
@@ -311,4 +317,10 @@
             return;
           }
+        case OpCodes.Cube: {
+            CompileInstructions(il, state, ds);
+            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 3.0);
+            il.Emit(System.Reflection.Emit.OpCodes.Call, power);
+            return;
+          }
         case OpCodes.SquareRoot: {
             CompileInstructions(il, state, ds);
@@ -316,4 +328,10 @@
             return;
           }
+        case OpCodes.CubeRoot: {
+            CompileInstructions(il, state, ds);
+            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0 / 3.0);
+            il.Emit(System.Reflection.Emit.OpCodes.Call, power);
+            return;
+          }
         case OpCodes.AiryA: {
             CompileInstructions(il, state, ds);
@@ -389,4 +407,16 @@
             CompileInstructions(il, state, ds);
             il.Emit(System.Reflection.Emit.OpCodes.Call, sinIntegral);
+            return;
+          }
+        case OpCodes.AnalyticQuotient: {
+            CompileInstructions(il, state, ds); // x1
+            CompileInstructions(il, state, ds); // x2
+
+            il.Emit(System.Reflection.Emit.OpCodes.Dup);
+            il.Emit(System.Reflection.Emit.OpCodes.Mul); // x2*x2
+            il.Emit(System.Reflection.Emit.OpCodes.Ldc_R8, 1.0);
+            il.Emit(System.Reflection.Emit.OpCodes.Mul); // 1+x2*x2
+            il.Emit(System.Reflection.Emit.OpCodes.Call, sqrt);
+            il.Emit(System.Reflection.Emit.OpCodes.Div);
             return;
           }
Index: branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeInterpreter.cs
===================================================================
--- branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeInterpreter.cs	(revision 15743)
+++ branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeInterpreter.cs	(revision 16388)
@@ -203,4 +203,7 @@
             return sum / currentInstr.nArguments;
           }
+        case OpCodes.Absolute: {
+            return Math.Abs(Evaluate(dataset, ref row, state));
+          }
         case OpCodes.Cos: {
             return Math.Cos(Evaluate(dataset, ref row, state));
@@ -214,4 +217,7 @@
         case OpCodes.Square: {
             return Math.Pow(Evaluate(dataset, ref row, state), 2);
+          }
+        case OpCodes.Cube: {
+            return Math.Pow(Evaluate(dataset, ref row, state), 3);
           }
         case OpCodes.Power: {
@@ -223,4 +229,7 @@
             return Math.Sqrt(Evaluate(dataset, ref row, state));
           }
+        case OpCodes.CubeRoot: {
+            return Math.Pow(Evaluate(dataset, ref row, state), 1.0 / 3.0);
+          }
         case OpCodes.Root: {
             double x = Evaluate(dataset, ref row, state);
@@ -340,4 +349,10 @@
             if (double.IsNaN(x)) return double.NaN;
             else return alglib.besseli0(x);
+          }
+
+        case OpCodes.AnalyticQuotient: {
+            var x1 = Evaluate(dataset, ref row, state);
+            var x2 = Evaluate(dataset, ref row, state);
+            return x1 / Math.Pow(1 + x2 * x2, 0.5);
           }
         case OpCodes.IfThenElse: {
Index: branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeLinearInterpreter.cs
===================================================================
--- branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeLinearInterpreter.cs	(revision 15743)
+++ branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeLinearInterpreter.cs	(revision 16388)
@@ -215,4 +215,8 @@
           if (instr.nArguments == 1) p = 1.0 / p;
           instr.value = p;
+        } else if (instr.opCode == OpCodes.AnalyticQuotient) {
+          var x1 = code[instr.childIndex].value;
+          var x2 = code[instr.childIndex + 1].value;
+          instr.value = x1 / Math.Sqrt(1 + x2 * x2);
         } else if (instr.opCode == OpCodes.Average) {
           double s = code[instr.childIndex].value;
@@ -221,4 +225,6 @@
           }
           instr.value = s / instr.nArguments;
+        } else if (instr.opCode == OpCodes.Absolute) {
+          instr.value = Math.Abs(code[instr.childIndex].value);
         } else if (instr.opCode == OpCodes.Cos) {
           instr.value = Math.Cos(code[instr.childIndex].value);
@@ -229,4 +235,6 @@
         } else if (instr.opCode == OpCodes.Square) {
           instr.value = Math.Pow(code[instr.childIndex].value, 2);
+        } else if (instr.opCode == OpCodes.Cube) {
+          instr.value = Math.Pow(code[instr.childIndex].value, 3);
         } else if (instr.opCode == OpCodes.Power) {
           double x = code[instr.childIndex].value;
@@ -235,4 +243,6 @@
         } else if (instr.opCode == OpCodes.SquareRoot) {
           instr.value = Math.Sqrt(code[instr.childIndex].value);
+        } else if (instr.opCode == OpCodes.CubeRoot) {
+          instr.value = Math.Pow(code[instr.childIndex].value, 1.0 / 3.0);
         } else if (instr.opCode == OpCodes.Root) {
           double x = code[instr.childIndex].value;
Index: branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeNativeInterpreter.cs
===================================================================
--- branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeNativeInterpreter.cs	(revision 16388)
+++ branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeNativeInterpreter.cs	(revision 16388)
@@ -0,0 +1,156 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2018 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 System.Runtime.InteropServices;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
+  [StorableClass]
+  [Item("SymbolicDataAnalysisExpressionTreeNativeInterpreter", "An interpreter that wraps a native dll")]
+  public class SymbolicDataAnalysisExpressionTreeNativeInterpreter : ParameterizedNamedItem, ISymbolicDataAnalysisExpressionTreeInterpreter {
+    private const string EvaluatedSolutionsParameterName = "EvaluatedSolutions";
+
+    #region parameters
+    public IFixedValueParameter<IntValue> EvaluatedSolutionsParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[EvaluatedSolutionsParameterName]; }
+    }
+    #endregion
+
+    #region properties
+    public int EvaluatedSolutions {
+      get { return EvaluatedSolutionsParameter.Value.Value; }
+      set { EvaluatedSolutionsParameter.Value.Value = value; }
+    }
+    #endregion
+
+    public void ClearState() { }
+
+    public SymbolicDataAnalysisExpressionTreeNativeInterpreter() {
+      Parameters.Add(new FixedValueParameter<IntValue>(EvaluatedSolutionsParameterName, "A counter for the total number of solutions the interpreter has evaluated", new IntValue(0)));
+    }
+
+    [StorableConstructor]
+    protected SymbolicDataAnalysisExpressionTreeNativeInterpreter(bool deserializing) : base(deserializing) { }
+
+    protected SymbolicDataAnalysisExpressionTreeNativeInterpreter(SymbolicDataAnalysisExpressionTreeNativeInterpreter original, Cloner cloner) : base(original, cloner) {
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new SymbolicDataAnalysisExpressionTreeNativeInterpreter(this, cloner);
+    }
+
+    private NativeInstruction[] Compile(ISymbolicExpressionTree tree, Func<ISymbolicExpressionTreeNode, byte> opCodeMapper) {
+      var root = tree.Root.GetSubtree(0).GetSubtree(0);
+      var code = new NativeInstruction[root.GetLength()];
+      if (root.SubtreeCount > ushort.MaxValue) throw new ArgumentException("Number of subtrees is too big (>65.535)");
+      code[0] = new NativeInstruction { narg = (ushort)root.SubtreeCount, opcode = opCodeMapper(root) };
+      int c = 1, i = 0;
+      foreach (var node in root.IterateNodesBreadth()) {
+        for (int j = 0; j < node.SubtreeCount; ++j) {
+          var s = node.GetSubtree(j);
+          if (s.SubtreeCount > ushort.MaxValue) throw new ArgumentException("Number of subtrees is too big (>65.535)");
+          code[c + j] = new NativeInstruction { narg = (ushort)s.SubtreeCount, opcode = opCodeMapper(s) };
+        }
+
+        if (node is VariableTreeNode variable) {
+          code[i].weight = variable.Weight;
+          code[i].data = cachedData[variable.VariableName].AddrOfPinnedObject();
+        } else if (node is ConstantTreeNode constant) {
+          code[i].value = constant.Value;
+        }
+
+        code[i].childIndex = c;
+        c += node.SubtreeCount;
+        ++i;
+      }
+      return code;
+    }
+
+    private readonly object syncRoot = new object();
+
+    [ThreadStatic]
+    private static Dictionary<string, GCHandle> cachedData;
+
+    [ThreadStatic]
+    private IDataset dataset;
+
+    public IEnumerable<double> GetSymbolicExpressionTreeValues(ISymbolicExpressionTree tree, IDataset dataset, IEnumerable<int> rows) {
+      if (!rows.Any()) return Enumerable.Empty<double>();
+
+      if (cachedData == null || this.dataset != dataset) {
+        InitCache(dataset);
+      }
+
+      var code = Compile(tree, OpCodes.MapSymbolToOpCode);
+
+      var rowsArray = rows.ToArray();
+      var result = new double[rowsArray.Length];
+
+      NativeWrapper.GetValuesVectorized(code, code.Length, rowsArray, rowsArray.Length, result);
+
+      // when evaluation took place without any error, we can increment the counter
+      lock (syncRoot) {
+        EvaluatedSolutions++;
+      }
+
+      return result;
+    }
+
+    private void InitCache(IDataset dataset) {
+      this.dataset = dataset;
+
+      // free handles to old data
+      if (cachedData != null) {
+        foreach (var gch in cachedData.Values) {
+          gch.Free();
+        }
+        cachedData = null;
+      }
+
+      // cache new data
+      cachedData = new Dictionary<string, GCHandle>();
+      foreach (var v in dataset.DoubleVariables) {
+        var values = dataset.GetDoubleValues(v).ToArray();
+        var gch = GCHandle.Alloc(values, GCHandleType.Pinned);
+        cachedData[v] = gch;
+      }
+    }
+
+    public void InitializeState() {
+      if (cachedData != null) {
+        foreach (var gch in cachedData.Values) {
+          gch.Free();
+        }
+        cachedData = null;
+      }
+      dataset = null;
+      EvaluatedSolutions = 0;
+    }
+  }
+}
Index: branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Plugin.cs.frame
===================================================================
--- branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Plugin.cs.frame	(revision 15743)
+++ branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Plugin.cs.frame	(revision 16388)
@@ -37,4 +37,5 @@
   [PluginDependency("HeuristicLab.Data", "3.3")]
   [PluginDependency("HeuristicLab.Encodings.SymbolicExpressionTreeEncoding", "3.4")]
+  [PluginDependency("HeuristicLab.NativeInterpreter", "0.1")]
   [PluginDependency("HeuristicLab.Operators", "3.3")]
   [PluginDependency("HeuristicLab.Optimization", "3.3")]
Index: branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisModel.cs
===================================================================
--- branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisModel.cs	(revision 15743)
+++ branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisModel.cs	(revision 16388)
@@ -34,5 +34,5 @@
   /// </summary>
   [StorableClass]
-  public abstract class SymbolicDataAnalysisModel : NamedItem, ISymbolicDataAnalysisModel {
+  public abstract class SymbolicDataAnalysisModel : DataAnalysisModel, ISymbolicDataAnalysisModel {
     public static new Image StaticItemImage {
       get { return HeuristicLab.Common.Resources.VSImageLibrary.Function; }
@@ -59,5 +59,5 @@
     }
 
-    public IEnumerable<string> VariablesUsedForPrediction {
+    public override IEnumerable<string> VariablesUsedForPrediction {
       get {
         var variables =
@@ -118,14 +118,12 @@
       ConstantTreeNode alphaTreeNode = null;
       ConstantTreeNode betaTreeNode = null;
-      // check if model has been scaled previously by analyzing the structure of the tree
+      // check if model has a structure that can be re-used for scaling
       var startNode = SymbolicExpressionTree.Root.GetSubtree(0);
-      if (startNode.GetSubtree(0).Symbol is Addition) {
-        var addNode = startNode.GetSubtree(0);
-        if (addNode.SubtreeCount == 2 && addNode.GetSubtree(0).Symbol is Multiplication && addNode.GetSubtree(1).Symbol is Constant) {
-          alphaTreeNode = addNode.GetSubtree(1) as ConstantTreeNode;
-          var mulNode = addNode.GetSubtree(0);
-          if (mulNode.SubtreeCount == 2 && mulNode.GetSubtree(1).Symbol is Constant) {
-            betaTreeNode = mulNode.GetSubtree(1) as ConstantTreeNode;
-          }
+      var addNode = startNode.GetSubtree(0);
+      if (addNode.Symbol is Addition && addNode.SubtreeCount == 2) {
+        alphaTreeNode = (ConstantTreeNode)addNode.Subtrees.LastOrDefault(n => n is ConstantTreeNode);
+        var mulNode = addNode.Subtrees.FirstOrDefault(n => n.Symbol is Multiplication);
+        if (mulNode != null) {
+          betaTreeNode = (ConstantTreeNode)mulNode.Subtrees.LastOrDefault(n => n is ConstantTreeNode);
         }
       }
Index: branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisSolutionImpactValuesCalculator.cs
===================================================================
--- branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisSolutionImpactValuesCalculator.cs	(revision 15743)
+++ branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisSolutionImpactValuesCalculator.cs	(revision 16388)
@@ -40,11 +40,13 @@
         out double impactValue, out double replacementValue, out double newQualityForImpactsCalculation,
         double qualityForImpactsCalculation = double.NaN) {
-      if (double.IsNaN(qualityForImpactsCalculation))
-        qualityForImpactsCalculation = CalculateQualityForImpacts(model, problemData, rows);
 
       var cloner = new Cloner();
       var tempModel = cloner.Clone(model);
+
+      if (double.IsNaN(qualityForImpactsCalculation)) {
+        qualityForImpactsCalculation = CalculateQualityForImpacts(tempModel, problemData, rows);
+      }
+
       var tempModelNode = (ISymbolicExpressionTreeNode)cloner.GetClone(node);
-
       var tempModelParentNode = tempModelNode.Parent;
       int i = tempModelParentNode.IndexOfSubtree(tempModelNode);
@@ -54,5 +56,5 @@
       newQualityForImpactsCalculation = qualityForImpactsCalculation; // initialize
       // try the potentially reasonable replacement values and use the best one
-      foreach (var repValue in CalculateReplacementValues(node, model.SymbolicExpressionTree, model.Interpreter, problemData.Dataset, problemData.TrainingIndices)) {
+      foreach (var repValue in CalculateReplacementValues(node, model.SymbolicExpressionTree, model.Interpreter, problemData.Dataset, rows)) {
         tempModelParentNode.RemoveSubtree(i);
 
Index: branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/Absolute.cs
===================================================================
--- branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/Absolute.cs	(revision 16388)
+++ branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/Absolute.cs	(revision 16388)
@@ -0,0 +1,48 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2018 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 {
+  [StorableClass]
+  [Item("Absolute", "Symbol that represents the absolute value function abs(x).")]
+  public sealed class Absolute : Symbol {
+    private const int minimumArity = 1;
+    private const int maximumArity = 1;
+
+    public override int MinimumArity {
+      get { return minimumArity; }
+    }
+    public override int MaximumArity {
+      get { return maximumArity; }
+    }
+
+    [StorableConstructor]
+    private Absolute(bool deserializing) : base(deserializing) { }
+    private Absolute(Absolute original, Cloner cloner) : base(original, cloner) { }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new Absolute(this, cloner);
+    }
+    public Absolute() : base("Absolute", "Symbol that represents the absolute value function.") { }
+  }
+}
Index: branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/AnalyticQuotient.cs
===================================================================
--- branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/AnalyticQuotient.cs	(revision 16388)
+++ branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/AnalyticQuotient.cs	(revision 16388)
@@ -0,0 +1,52 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2018 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 {
+  [StorableClass]
+  [Item("Analytic Quotient", "The analytic quotient function aq(a,b) = a / sqrt(b²+1) can be used as an " +
+    "alternative to protected division. See H. Drieberg and P. Rocket, The Use of an Analytic Quotient Operator" +
+    " in Genetic Programming. IEEE Transactions on Evolutionary Computation, Vol. 17, No. 1, February 2013, pp. 146 -- 152")]
+  public sealed class AnalyticQuotient : Symbol {
+    private const int minimumArity = 2;
+    private const int maximumArity = 2;
+
+    public override int MinimumArity {
+      get { return minimumArity; }
+    }
+    public override int MaximumArity {
+      get { return maximumArity; }
+    }
+
+    [StorableConstructor]
+    private AnalyticQuotient(bool deserializing) : base(deserializing) { }
+    private AnalyticQuotient(AnalyticQuotient original, Cloner cloner) : base(original, cloner) { }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new AnalyticQuotient(this, cloner);
+    }
+    public AnalyticQuotient() : base("AnalyticQuotient", "The analytic quotient function aq(a,b) = a / sqrt(b²+1) can be used as an " +
+    "alternative to protected division. See H. Drieberg and P. Rocket, The Use of an Analytic Quotient Operator" +
+    " in Genetic Programming. IEEE Transactions on Evolutionary Computation, Vol. 17, No. 1, February 2013, pp. 146 -- 152") { }
+  }
+}
Index: branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/Cube.cs
===================================================================
--- branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/Cube.cs	(revision 16388)
+++ branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/Cube.cs	(revision 16388)
@@ -0,0 +1,48 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2018 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 {
+  [StorableClass]
+  [Item("Cube", "Symbol that represents the cube function.")]
+  public sealed class Cube : Symbol {
+    private const int minimumArity = 1;
+    private const int maximumArity = 1;
+
+    public override int MinimumArity {
+      get { return minimumArity; }
+    }
+    public override int MaximumArity {
+      get { return maximumArity; }
+    }
+
+    [StorableConstructor]
+    private Cube(bool deserializing) : base(deserializing) { }
+    private Cube(Cube original, Cloner cloner) : base(original, cloner) { }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new Cube(this, cloner);
+    }
+    public Cube() : base("Cube", "Symbol that represents the cube function.") { }
+  }
+}
Index: branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/CubeRoot.cs
===================================================================
--- branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/CubeRoot.cs	(revision 16388)
+++ branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Symbols/CubeRoot.cs	(revision 16388)
@@ -0,0 +1,48 @@
+#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2018 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 {
+  [StorableClass]
+  [Item("CubeRoot", "Symbol that represents the cube root function.")]
+  public sealed class CubeRoot : Symbol {
+    private const int minimumArity = 1;
+    private const int maximumArity = 1;
+
+    public override int MinimumArity {
+      get { return minimumArity; }
+    }
+    public override int MaximumArity {
+      get { return maximumArity; }
+    }
+
+    [StorableConstructor]
+    private CubeRoot(bool deserializing) : base(deserializing) { }
+    private CubeRoot(CubeRoot original, Cloner cloner) : base(original, cloner) { }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new CubeRoot(this, cloner);
+    }
+    public CubeRoot() : base("CubeRoot", "Symbol that represents the cube root function.") { }
+  }
+}
Index: branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/TreeMatching/SymbolicExpressionTreeBottomUpSimilarityCalculator.cs
===================================================================
--- branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/TreeMatching/SymbolicExpressionTreeBottomUpSimilarityCalculator.cs	(revision 15743)
+++ branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/TreeMatching/SymbolicExpressionTreeBottomUpSimilarityCalculator.cs	(revision 16388)
@@ -22,5 +22,4 @@
 using System;
 using System.Collections.Generic;
-using System.Diagnostics;
 using System.Globalization;
 using System.Linq;
@@ -31,4 +30,6 @@
 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
 
+using NodeMap = System.Collections.Generic.Dictionary<HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.ISymbolicExpressionTreeNode, HeuristicLab.Encodings.SymbolicExpressionTreeEncoding.ISymbolicExpressionTreeNode>;
+
 namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
   [StorableClass]
@@ -40,4 +41,7 @@
     protected override bool IsCommutative { get { return true; } }
 
+    public bool MatchConstantValues { get; set; }
+    public bool MatchVariableWeights { get; set; }
+
     [StorableConstructor]
     protected SymbolicExpressionTreeBottomUpSimilarityCalculator(bool deserializing)
@@ -53,10 +57,39 @@
     }
 
+    #region static methods
+    private static ISymbolicExpressionTreeNode ActualRoot(ISymbolicExpressionTree tree) {
+      return tree.Root.GetSubtree(0).GetSubtree(0);
+    }
+
+    public static double CalculateSimilarity(ISymbolicExpressionTree t1, ISymbolicExpressionTree t2, bool strict = false) {
+      return CalculateSimilarity(ActualRoot(t1), ActualRoot(t2), strict);
+    }
+
+    public static double CalculateSimilarity(ISymbolicExpressionTreeNode n1, ISymbolicExpressionTreeNode n2, bool strict = false) {
+      var calculator = new SymbolicExpressionTreeBottomUpSimilarityCalculator { MatchConstantValues = strict, MatchVariableWeights = strict };
+      return CalculateSimilarity(n1, n2, strict);
+    }
+
+    public static Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode> ComputeBottomUpMapping(ISymbolicExpressionTree t1, ISymbolicExpressionTree t2, bool strict = false) {
+      return ComputeBottomUpMapping(ActualRoot(t1), ActualRoot(t2), strict);
+    }
+
+    public static Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode> ComputeBottomUpMapping(ISymbolicExpressionTreeNode n1, ISymbolicExpressionTreeNode n2, bool strict = false) {
+      var calculator = new SymbolicExpressionTreeBottomUpSimilarityCalculator { MatchConstantValues = strict, MatchVariableWeights = strict };
+      return calculator.ComputeBottomUpMapping(n1, n2);
+    }
+    #endregion
+
     public double CalculateSimilarity(ISymbolicExpressionTree t1, ISymbolicExpressionTree t2) {
-      if (t1 == t2)
+      return CalculateSimilarity(t1, t2, out Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode> map);
+    }
+
+    public double CalculateSimilarity(ISymbolicExpressionTree t1, ISymbolicExpressionTree t2, out NodeMap map) {
+      if (t1 == t2) {
+        map = null;
         return 1;
-
-      var map = ComputeBottomUpMapping(t1.Root, t2.Root);
-      return 2.0 * map.Count / (t1.Length + t2.Length);
+      }
+      map = ComputeBottomUpMapping(t1, t2);
+      return 2.0 * map.Count / (t1.Length + t2.Length - 4); // -4 for skipping root and start symbols in the two trees
     }
 
@@ -78,47 +111,44 @@
     }
 
+    public Dictionary<ISymbolicExpressionTreeNode, ISymbolicExpressionTreeNode> ComputeBottomUpMapping(ISymbolicExpressionTree t1, ISymbolicExpressionTree t2) {
+      return ComputeBottomUpMapping(t1.Root.GetSubtree(0).GetSubtree(0), t2.Root.GetSubtree(0).GetSubtree(0));
+    }
+
     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().OrderByDescending(x => x.GetDepth()).ToList();
-      var nodes2 = n2.IterateNodesPrefix().ToList();
-      for (int i = 0; i < nodes1.Count; ++i) {
-        var v = nodes1[i];
-        if (forwardMap.ContainsKey(v))
+      IEnumerable<ISymbolicExpressionTreeNode> Subtrees(ISymbolicExpressionTreeNode node, bool commutative) {
+        var subtrees = node.IterateNodesPrefix();
+        return commutative ? subtrees.OrderBy(x => compactedGraph[x].Hash) : subtrees;
+      }
+
+      var nodes1 = n1.IterateNodesPostfix().OrderByDescending(x => x.GetLength()); // by descending length so that largest subtrees are mapped first
+      var nodes2 = (List<ISymbolicExpressionTreeNode>)n2.IterateNodesPostfix();
+
+      var forward = new NodeMap();
+      var reverse = new NodeMap();
+
+      foreach (ISymbolicExpressionTreeNode v in nodes1) {
+        if (forward.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)
+        var commutative = v.SubtreeCount > 1 && commutativeSymbols.Contains(kv.Label);
+
+        foreach (ISymbolicExpressionTreeNode w in nodes2) {
+          if (w.GetLength() != kv.Length || w.GetDepth() != kv.Depth || reverse.ContainsKey(w) || compactedGraph[w] != kv)
             continue;
-          w = t;
+
+          // map one whole subtree to the other
+          foreach (var t in Subtrees(v, commutative).Zip(Subtrees(w, commutative), Tuple.Create)) {
+            forward[t.Item1] = t.Item2;
+            reverse[t.Item2] = t.Item1;
+          }
+
           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 from under commutative labels (this will work because the subtrees are isomorphic!)
-        // while iterating 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;
+      }
+
+      return forward;
     }
 
@@ -132,99 +162,59 @@
       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 = GetLabel(n);
+      var graph = new List<GraphNode>();
+
+      IEnumerable<GraphNode> Subtrees(GraphNode g, bool commutative) {
+        var subtrees = g.SymbolicExpressionTreeNode.Subtrees.Select(x => nodeMap[x]);
+        return commutative ? subtrees.OrderBy(x => x.Hash) : subtrees;
+      }
+
+      foreach (var node in nodes) {
+        var label = GetLabel(node);
+
+        if (node.SubtreeCount == 0) {
           if (!labelMap.ContainsKey(label)) {
-            var z = new GraphNode { SymbolicExpressionTreeNode = n, Label = label };
-            labelMap[z.Label] = z;
-          }
-          nodeMap[n] = labelMap[label];
-          queue.Enqueue(n);
+            labelMap[label] = new GraphNode(node, label);
+          }
+          nodeMap[node] = labelMap[label];
         } else {
-          childrenCount[n] = n.SubtreeCount;
-        }
-      }
-      while (queue.Any()) {
-        var n = queue.Dequeue();
-        if (n.SubtreeCount > 0) {
+          var v = new GraphNode(node, label);
           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))
+          var commutative = node.SubtreeCount > 1 && commutativeSymbols.Contains(label);
+
+          var vv = Subtrees(v, commutative);
+
+          foreach (var w in graph) {
+            if (v.Depth != w.Depth || v.SubtreeCount != w.SubtreeCount || v.Length != w.Length || v.Label != w.Label) {
               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);
+            }
+
+            var ww = Subtrees(w, commutative);
+            found = vv.SequenceEqual(ww);
+
             if (found) {
-              nodeMap[n] = w;
+              nodeMap[node] = w;
               break;
             }
           }
-
           if (!found) {
-            var w = new GraphNode { SymbolicExpressionTreeNode = n, Label = label, Depth = depth };
-            list.Add(w);
-            nodeMap[n] = w;
+            nodeMap[node] = v;
+            graph.Add(v);
           }
         }
-
-        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 static string GetLabel(ISymbolicExpressionTreeNode node) {
+    private string GetLabel(ISymbolicExpressionTreeNode node) {
       if (node.SubtreeCount > 0)
         return node.Symbol.Name;
 
-      var constant = node as ConstantTreeNode;
-      if (constant != null)
-        return constant.Value.ToString(CultureInfo.InvariantCulture);
-
-      var variable = node as VariableTreeNode;
-      if (variable != null)
-        return variable.Weight + variable.VariableName;
+      if (node is ConstantTreeNode constant)
+        return MatchConstantValues ? constant.Value.ToString(CultureInfo.InvariantCulture) : constant.Symbol.Name;
+
+      if (node is VariableTreeNode variable)
+        return MatchVariableWeights ? variable.Weight + variable.VariableName : variable.VariableName;
 
       return node.ToString();
@@ -232,8 +222,20 @@
 
     private class GraphNode {
-      public ISymbolicExpressionTreeNode SymbolicExpressionTreeNode;
-      public string Label;
-      public int Depth;
+      private GraphNode() { }
+
+      public GraphNode(ISymbolicExpressionTreeNode node, string label) {
+        SymbolicExpressionTreeNode = node;
+        Label = label;
+        Hash = GetHashCode();
+        Depth = node.GetDepth();
+        Length = node.GetLength();
+      }
+
+      public int Hash { get; }
+      public ISymbolicExpressionTreeNode SymbolicExpressionTreeNode { get; }
+      public string Label { get; }
+      public int Depth { get; }
       public int SubtreeCount { get { return SymbolicExpressionTreeNode.SubtreeCount; } }
+      public int Length { get; }
     }
   }
Index: branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/packages.config
===================================================================
--- branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/packages.config	(revision 16388)
+++ branches/2892_LR-prediction-intervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/packages.config	(revision 16388)
@@ -0,0 +1,4 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net45" />
+</packages>
