Index: stable/HeuristicLab.Common/3.3/Cloner.cs
===================================================================
--- stable/HeuristicLab.Common/3.3/Cloner.cs	(revision 9961)
+++ stable/HeuristicLab.Common/3.3/Cloner.cs	(revision 9976)
@@ -67,4 +67,15 @@
     }
 
+    /// <summary>
+    /// Returns the clone of an deeply cloned item, if it was already cloned.
+    /// </summary>
+    /// <param name="original">The original object.</param>
+    /// <returns>The clone of the given object, if it was already cloned; null otherwise</returns>
+    public IDeepCloneable GetClone(IDeepCloneable original) {
+      IDeepCloneable clone = null;
+      mapping.TryGetValue(original, out clone);
+      return clone;
+    }
+
   }
 }
Index: stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding/3.4/Compiler/Instruction.cs
===================================================================
--- stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding/3.4/Compiler/Instruction.cs	(revision 9961)
+++ stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding/3.4/Compiler/Instruction.cs	(revision 9976)
@@ -31,5 +31,5 @@
     public byte nArguments;
     // an optional object value (addresses for calls, argument index for arguments)
-    public object iArg0;
+    public object data;
   }
 }
Index: stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding/3.4/Compiler/LinearInstruction.cs
===================================================================
--- stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding/3.4/Compiler/LinearInstruction.cs	(revision 9976)
+++ stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding/3.4/Compiler/LinearInstruction.cs	(revision 9976)
@@ -0,0 +1,30 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2013 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
+
+
+namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding {
+  // total size of this class should be small to improve cache access while executing the code
+  public class LinearInstruction : Instruction {
+    public double value;
+    public byte childIndex;
+    public bool skip;
+  }
+}
Index: stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding/3.4/Compiler/SymbolicExpressionTreeCompiler.cs
===================================================================
--- stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding/3.4/Compiler/SymbolicExpressionTreeCompiler.cs	(revision 9961)
+++ stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding/3.4/Compiler/SymbolicExpressionTreeCompiler.cs	(revision 9976)
@@ -52,5 +52,5 @@
         if (instr.dynamicNode.Symbol is InvokeFunction) {
           var invokeNode = (InvokeFunctionTreeNode)instr.dynamicNode;
-          instr.iArg0 = entryPoint[invokeNode.Symbol.FunctionName];
+          instr.data = entryPoint[invokeNode.Symbol.FunctionName];
         }
       }
@@ -68,5 +68,5 @@
         if (node.Symbol is Argument) {
           var argNode = (ArgumentTreeNode)node;
-          instr.iArg0 = (ushort)argNode.Symbol.ArgumentIndex;
+          instr.data = (ushort)argNode.Symbol.ArgumentIndex;
         }
         instr.dynamicNode = node;
Index: stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding/3.4/Compiler/SymbolicExpressionTreeLinearCompiler.cs
===================================================================
--- stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding/3.4/Compiler/SymbolicExpressionTreeLinearCompiler.cs	(revision 9976)
+++ stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding/3.4/Compiler/SymbolicExpressionTreeLinearCompiler.cs	(revision 9976)
@@ -0,0 +1,43 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2013 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;
+
+namespace HeuristicLab.Encodings.SymbolicExpressionTreeEncoding {
+  public static class SymbolicExpressionTreeLinearCompiler {
+    public static LinearInstruction[] Compile(ISymbolicExpressionTree tree, Func<ISymbolicExpressionTreeNode, byte> opCodeMapper) {
+      var root = tree.Root.GetSubtree(0).GetSubtree(0);
+      var code = new LinearInstruction[root.GetLength()];
+      code[0] = new LinearInstruction { dynamicNode = root, nArguments = (byte)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);
+          code[c + j] = new LinearInstruction { dynamicNode = s, nArguments = (byte)s.SubtreeCount, opCode = opCodeMapper(s) };
+        }
+        code[i].childIndex = (byte)c;
+        c += node.SubtreeCount;
+        ++i;
+      }
+      return code;
+    }
+  }
+}
Index: stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding/3.4/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding-3.4.csproj
===================================================================
--- stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding/3.4/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding-3.4.csproj	(revision 9961)
+++ stable/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding/3.4/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding-3.4.csproj	(revision 9976)
@@ -124,5 +124,7 @@
     <Compile Include="ArchitectureManipulators\SymbolicExpressionTreeArchitectureManipulator.cs" />
     <Compile Include="Compiler\Instruction.cs" />
+    <Compile Include="Compiler\LinearInstruction.cs" />
     <Compile Include="Compiler\SymbolicExpressionTreeCompiler.cs" />
+    <Compile Include="Compiler\SymbolicExpressionTreeLinearCompiler.cs" />
     <Compile Include="Creators\FullTreeCreator.cs">
       <SubType>Code</SubType>
Index: stable/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/SymbolicRegressionSolutionImpactValuesCalculator.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/SymbolicRegressionSolutionImpactValuesCalculator.cs	(revision 9961)
+++ stable/HeuristicLab.Problems.DataAnalysis.Symbolic.Regression/3.4/SymbolicRegressionSolutionImpactValuesCalculator.cs	(revision 9976)
@@ -49,7 +49,13 @@
       var replacementValue = CalculateReplacementValue(regressionModel, node, regressionProblemData, rows);
       var constantNode = new ConstantTreeNode(new Constant()) { Value = replacementValue };
+
       var cloner = new Cloner();
-      cloner.RegisterClonedObject(node, constantNode);
       var tempModel = cloner.Clone(regressionModel);
+      var tempModelNode = (ISymbolicExpressionTreeNode)cloner.GetClone(node);
+
+      var tempModelParentNode = tempModelNode.Parent;
+      int i = tempModelParentNode.IndexOfSubtree(tempModelNode);
+      tempModelParentNode.RemoveSubtree(i);
+      tempModelParentNode.InsertSubtree(i, constantNode);
 
       var estimatedValues = tempModel.GetEstimatedValues(dataset, rows);
Index: stable/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis/3.4/SymbolicTimeSeriesPrognosisExpressionTreeInterpreter.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis/3.4/SymbolicTimeSeriesPrognosisExpressionTreeInterpreter.cs	(revision 9961)
+++ stable/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis/3.4/SymbolicTimeSeriesPrognosisExpressionTreeInterpreter.cs	(revision 9976)
@@ -123,19 +123,19 @@
           var variableTreeNode = (VariableTreeNode)instr.dynamicNode;
           if (variableTreeNode.VariableName == targetVariable)
-            instr.iArg0 = targetVariableCache;
+            instr.data = targetVariableCache;
           else
-            instr.iArg0 = dataset.GetReadOnlyDoubleValues(variableTreeNode.VariableName);
+            instr.data = dataset.GetReadOnlyDoubleValues(variableTreeNode.VariableName);
         } else if (instr.opCode == OpCodes.LagVariable) {
           var variableTreeNode = (LaggedVariableTreeNode)instr.dynamicNode;
           if (variableTreeNode.VariableName == targetVariable)
-            instr.iArg0 = targetVariableCache;
+            instr.data = targetVariableCache;
           else
-            instr.iArg0 = dataset.GetReadOnlyDoubleValues(variableTreeNode.VariableName);
+            instr.data = dataset.GetReadOnlyDoubleValues(variableTreeNode.VariableName);
         } else if (instr.opCode == OpCodes.VariableCondition) {
           var variableTreeNode = (VariableConditionTreeNode)instr.dynamicNode;
           if (variableTreeNode.VariableName == targetVariable)
-            instr.iArg0 = targetVariableCache;
+            instr.data = targetVariableCache;
           else
-            instr.iArg0 = dataset.GetReadOnlyDoubleValues(variableTreeNode.VariableName);
+            instr.data = dataset.GetReadOnlyDoubleValues(variableTreeNode.VariableName);
         } else if (instr.opCode == OpCodes.Call) {
           necessaryArgStackSize += instr.nArguments + 1;
Index: stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4.csproj
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4.csproj	(revision 9961)
+++ stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4.csproj	(revision 9976)
@@ -147,4 +147,5 @@
     <Compile Include="Interpreter\SymbolicDataAnalysisExpressionTreeILEmittingInterpreter.cs" />
     <Compile Include="Interpreter\SymbolicDataAnalysisExpressionTreeInterpreter.cs" />
+    <Compile Include="Interpreter\SymbolicDataAnalysisExpressionTreeLinearInterpreter.cs" />
     <Compile Include="Plugin.cs" />
     <Compile Include="Formatters\SymbolicDataAnalysisExpressionLatexFormatter.cs" />
Index: stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeILEmittingInterpreter.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeILEmittingInterpreter.cs	(revision 9961)
+++ stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeILEmittingInterpreter.cs	(revision 9976)
@@ -168,11 +168,11 @@
         if (instr.opCode == OpCodes.Variable) {
           var variableTreeNode = (VariableTreeNode)instr.dynamicNode;
-          instr.iArg0 = doubleVariableNames[variableTreeNode.VariableName];
+          instr.data = doubleVariableNames[variableTreeNode.VariableName];
         } else if (instr.opCode == OpCodes.LagVariable) {
           var laggedVariableTreeNode = (LaggedVariableTreeNode)instr.dynamicNode;
-          instr.iArg0 = doubleVariableNames[laggedVariableTreeNode.VariableName];
+          instr.data = doubleVariableNames[laggedVariableTreeNode.VariableName];
         } else if (instr.opCode == OpCodes.VariableCondition) {
           var variableConditionTreeNode = (VariableConditionTreeNode)instr.dynamicNode;
-          instr.iArg0 = doubleVariableNames[variableConditionTreeNode.VariableName];
+          instr.data = doubleVariableNames[variableConditionTreeNode.VariableName];
         } else if (instr.opCode == OpCodes.Call) {
           necessaryArgStackSize += instr.nArguments + 1;
@@ -566,5 +566,5 @@
             VariableTreeNode varNode = (VariableTreeNode)currentInstr.dynamicNode;
             il.Emit(System.Reflection.Emit.OpCodes.Ldarg_1); // load columns array
-            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, (int)currentInstr.iArg0);
+            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, (int)currentInstr.data);
             // load correct column of the current variable
             il.Emit(System.Reflection.Emit.OpCodes.Ldelem_Ref);
@@ -600,5 +600,5 @@
             LaggedVariableTreeNode varNode = (LaggedVariableTreeNode)currentInstr.dynamicNode;
             il.Emit(System.Reflection.Emit.OpCodes.Ldarg_1); // load columns array
-            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, (int)currentInstr.iArg0);
+            il.Emit(System.Reflection.Emit.OpCodes.Ldc_I4, (int)currentInstr.data);
             // load correct column of the current variable
             il.Emit(System.Reflection.Emit.OpCodes.Ldelem_Ref);
Index: stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeInterpreter.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeInterpreter.cs	(revision 9961)
+++ stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeInterpreter.cs	(revision 9976)
@@ -117,11 +117,11 @@
         if (instr.opCode == OpCodes.Variable) {
           var variableTreeNode = (VariableTreeNode)instr.dynamicNode;
-          instr.iArg0 = dataset.GetReadOnlyDoubleValues(variableTreeNode.VariableName);
+          instr.data = dataset.GetReadOnlyDoubleValues(variableTreeNode.VariableName);
         } else if (instr.opCode == OpCodes.LagVariable) {
           var laggedVariableTreeNode = (LaggedVariableTreeNode)instr.dynamicNode;
-          instr.iArg0 = dataset.GetReadOnlyDoubleValues(laggedVariableTreeNode.VariableName);
+          instr.data = dataset.GetReadOnlyDoubleValues(laggedVariableTreeNode.VariableName);
         } else if (instr.opCode == OpCodes.VariableCondition) {
           var variableConditionTreeNode = (VariableConditionTreeNode)instr.dynamicNode;
-          instr.iArg0 = dataset.GetReadOnlyDoubleValues(variableConditionTreeNode.VariableName);
+          instr.data = dataset.GetReadOnlyDoubleValues(variableConditionTreeNode.VariableName);
         } else if (instr.opCode == OpCodes.Call) {
           necessaryArgStackSize += instr.nArguments + 1;
@@ -132,5 +132,5 @@
 
 
-    protected virtual double Evaluate(Dataset dataset, ref int row, InterpreterState state) {
+    public virtual double Evaluate(Dataset dataset, ref int row, InterpreterState state) {
       Instruction currentInstr = state.NextInstruction();
       switch (currentInstr.opCode) {
@@ -406,5 +406,5 @@
             int savedPc = state.ProgramCounter;
             // set pc to start of function  
-            state.ProgramCounter = (ushort)currentInstr.iArg0;
+            state.ProgramCounter = (ushort)currentInstr.data;
             // evaluate the function
             double v = Evaluate(dataset, ref row, state);
@@ -418,10 +418,10 @@
           }
         case OpCodes.Arg: {
-            return state.GetStackFrameValue((ushort)currentInstr.iArg0);
+            return state.GetStackFrameValue((ushort)currentInstr.data);
           }
         case OpCodes.Variable: {
             if (row < 0 || row >= dataset.Rows) return double.NaN;
             var variableTreeNode = (VariableTreeNode)currentInstr.dynamicNode;
-            return ((IList<double>)currentInstr.iArg0)[row] * variableTreeNode.Weight;
+            return ((IList<double>)currentInstr.data)[row] * variableTreeNode.Weight;
           }
         case OpCodes.LagVariable: {
@@ -429,5 +429,5 @@
             int actualRow = row + laggedVariableTreeNode.Lag;
             if (actualRow < 0 || actualRow >= dataset.Rows) return double.NaN;
-            return ((IList<double>)currentInstr.iArg0)[actualRow] * laggedVariableTreeNode.Weight;
+            return ((IList<double>)currentInstr.data)[actualRow] * laggedVariableTreeNode.Weight;
           }
         case OpCodes.Constant: {
@@ -441,5 +441,5 @@
             if (row < 0 || row >= dataset.Rows) return double.NaN;
             var variableConditionTreeNode = (VariableConditionTreeNode)currentInstr.dynamicNode;
-            double variableValue = ((IList<double>)currentInstr.iArg0)[row];
+            double variableValue = ((IList<double>)currentInstr.data)[row];
             double x = variableValue - variableConditionTreeNode.Threshold;
             double p = 1 / (1 + Math.Exp(-variableConditionTreeNode.Slope * x));
Index: stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeLinearInterpreter.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeLinearInterpreter.cs	(revision 9976)
+++ stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeLinearInterpreter.cs	(revision 9976)
@@ -0,0 +1,389 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2013 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ *
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
+  [StorableClass]
+  [Item("SymbolicDataAnalysisExpressionTreeLinearInterpreter", "Fast linear (non-recursive) interpreter for symbolic expression trees. Does not support ADFs.")]
+  public sealed class SymbolicDataAnalysisExpressionTreeLinearInterpreter : ParameterizedNamedItem, ISymbolicDataAnalysisExpressionTreeInterpreter {
+    private const string CheckExpressionsWithIntervalArithmeticParameterName = "CheckExpressionsWithIntervalArithmetic";
+    private const string EvaluatedSolutionsParameterName = "EvaluatedSolutions";
+
+    private SymbolicDataAnalysisExpressionTreeInterpreter interpreter;
+
+    public override bool CanChangeName {
+      get { return false; }
+    }
+
+    public override bool CanChangeDescription {
+      get { return false; }
+    }
+
+    #region parameter properties
+    public IValueParameter<BoolValue> CheckExpressionsWithIntervalArithmeticParameter {
+      get { return (IValueParameter<BoolValue>)Parameters[CheckExpressionsWithIntervalArithmeticParameterName]; }
+    }
+
+    public IValueParameter<IntValue> EvaluatedSolutionsParameter {
+      get { return (IValueParameter<IntValue>)Parameters[EvaluatedSolutionsParameterName]; }
+    }
+    #endregion
+
+    #region properties
+    public BoolValue CheckExpressionsWithIntervalArithmetic {
+      get { return CheckExpressionsWithIntervalArithmeticParameter.Value; }
+      set { CheckExpressionsWithIntervalArithmeticParameter.Value = value; }
+    }
+    public IntValue EvaluatedSolutions {
+      get { return EvaluatedSolutionsParameter.Value; }
+      set { EvaluatedSolutionsParameter.Value = value; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    private SymbolicDataAnalysisExpressionTreeLinearInterpreter(bool deserializing)
+      : base(deserializing) {
+    }
+
+    private SymbolicDataAnalysisExpressionTreeLinearInterpreter(SymbolicDataAnalysisExpressionTreeLinearInterpreter original, Cloner cloner)
+      : base(original, cloner) {
+      interpreter = cloner.Clone(original.interpreter);
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new SymbolicDataAnalysisExpressionTreeLinearInterpreter(this, cloner);
+    }
+
+    public SymbolicDataAnalysisExpressionTreeLinearInterpreter()
+      : base("SymbolicDataAnalysisExpressionTreeLinearInterpreter", "Linear (non-recursive) interpreter for symbolic expression trees (does not support ADFs).") {
+      Parameters.Add(new ValueParameter<BoolValue>(CheckExpressionsWithIntervalArithmeticParameterName, "Switch that determines if the interpreter checks the validity of expressions with interval arithmetic before evaluating the expression.", new BoolValue(false)));
+      Parameters.Add(new ValueParameter<IntValue>(EvaluatedSolutionsParameterName, "A counter for the total number of solutions the interpreter has evaluated", new IntValue(0)));
+      interpreter = new SymbolicDataAnalysisExpressionTreeInterpreter();
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+      if (interpreter == null) interpreter = new SymbolicDataAnalysisExpressionTreeInterpreter();
+    }
+
+    #region IStatefulItem
+    public void InitializeState() {
+      EvaluatedSolutions.Value = 0;
+    }
+
+    public void ClearState() { }
+    #endregion
+
+    public IEnumerable<double> GetSymbolicExpressionTreeValues(ISymbolicExpressionTree tree, Dataset dataset, IEnumerable<int> rows) {
+      if (CheckExpressionsWithIntervalArithmetic.Value)
+        throw new NotSupportedException("Interval arithmetic is not yet supported in the symbolic data analysis interpreter.");
+
+      lock (EvaluatedSolutions) {
+        EvaluatedSolutions.Value++; // increment the evaluated solutions counter
+      }
+
+      var code = SymbolicExpressionTreeLinearCompiler.Compile(tree, OpCodes.MapSymbolToOpCode);
+      PrepareInstructions(code, dataset);
+      return rows.Select(row => Evaluate(dataset, row, code));
+    }
+
+    private double Evaluate(Dataset dataset, int row, LinearInstruction[] code) {
+      for (int i = code.Length - 1; i >= 0; --i) {
+        if (code[i].skip) continue;
+        #region opcode if
+        var instr = code[i];
+        if (instr.opCode == OpCodes.Variable) {
+          if (row < 0 || row >= dataset.Rows) instr.value = double.NaN;
+          var variableTreeNode = (VariableTreeNode)instr.dynamicNode;
+          instr.value = ((IList<double>)instr.data)[row] * variableTreeNode.Weight;
+        } else if (instr.opCode == OpCodes.LagVariable) {
+          var laggedVariableTreeNode = (LaggedVariableTreeNode)instr.dynamicNode;
+          int actualRow = row + laggedVariableTreeNode.Lag;
+          if (actualRow < 0 || actualRow >= dataset.Rows)
+            instr.value = double.NaN;
+          else
+            instr.value = ((IList<double>)instr.data)[actualRow] * laggedVariableTreeNode.Weight;
+        } else if (instr.opCode == OpCodes.VariableCondition) {
+          if (row < 0 || row >= dataset.Rows) instr.value = double.NaN;
+          var variableConditionTreeNode = (VariableConditionTreeNode)instr.dynamicNode;
+          double variableValue = ((IList<double>)instr.data)[row];
+          double x = variableValue - variableConditionTreeNode.Threshold;
+          double p = 1 / (1 + Math.Exp(-variableConditionTreeNode.Slope * x));
+
+          double trueBranch = code[instr.childIndex].value;
+          double falseBranch = code[instr.childIndex + 1].value;
+
+          instr.value = trueBranch * p + falseBranch * (1 - p);
+        } else if (instr.opCode == OpCodes.Add) {
+          double s = code[instr.childIndex].value;
+          for (int j = 1; j != instr.nArguments; ++j) {
+            s += code[instr.childIndex + j].value;
+          }
+          instr.value = s;
+        } else if (instr.opCode == OpCodes.Sub) {
+          double s = code[instr.childIndex].value;
+          for (int j = 1; j != instr.nArguments; ++j) {
+            s -= code[instr.childIndex + j].value;
+          }
+          if (instr.nArguments == 1) s = -s;
+          instr.value = s;
+        } else if (instr.opCode == OpCodes.Mul) {
+          double p = code[instr.childIndex].value;
+          for (int j = 1; j != instr.nArguments; ++j) {
+            p *= code[instr.childIndex + j].value;
+          }
+          instr.value = p;
+        } else if (instr.opCode == OpCodes.Div) {
+          double p = code[instr.childIndex].value;
+          for (int j = 1; j != instr.nArguments; ++j) {
+            p /= code[instr.childIndex + j].value;
+          }
+          if (instr.nArguments == 1) p = 1.0 / p;
+          instr.value = p;
+        } else if (instr.opCode == OpCodes.Average) {
+          double s = code[instr.childIndex].value;
+          for (int j = 1; j != instr.nArguments; ++j) {
+            s += code[instr.childIndex + j].value;
+          }
+          instr.value = s / instr.nArguments;
+        } else if (instr.opCode == OpCodes.Cos) {
+          instr.value = Math.Cos(code[instr.childIndex].value);
+        } else if (instr.opCode == OpCodes.Sin) {
+          instr.value = Math.Sin(code[instr.childIndex].value);
+        } else if (instr.opCode == OpCodes.Tan) {
+          instr.value = Math.Tan(code[instr.childIndex].value);
+        } else if (instr.opCode == OpCodes.Square) {
+          instr.value = Math.Pow(code[instr.childIndex].value, 2);
+        } else if (instr.opCode == OpCodes.Power) {
+          double x = code[instr.childIndex].value;
+          double y = Math.Round(code[instr.childIndex + 1].value);
+          instr.value = Math.Pow(x, y);
+        } else if (instr.opCode == OpCodes.SquareRoot) {
+          instr.value = Math.Sqrt(code[instr.childIndex].value);
+        } else if (instr.opCode == OpCodes.Root) {
+          double x = code[instr.childIndex].value;
+          double y = code[instr.childIndex + 1].value;
+          instr.value = Math.Pow(x, 1 / y);
+        } else if (instr.opCode == OpCodes.Exp) {
+          instr.value = Math.Exp(code[instr.childIndex].value);
+        } else if (instr.opCode == OpCodes.Log) {
+          instr.value = Math.Log(code[instr.childIndex].value);
+        } else if (instr.opCode == OpCodes.Gamma) {
+          var x = code[instr.childIndex].value;
+          instr.value = double.IsNaN(x) ? double.NaN : alglib.gammafunction(x);
+        } else if (instr.opCode == OpCodes.Psi) {
+          var x = code[instr.childIndex].value;
+          if (double.IsNaN(x)) instr.value = double.NaN;
+          else if (x <= 0 && (Math.Floor(x) - x).IsAlmost(0)) instr.value = double.NaN;
+          else instr.value = alglib.psi(x);
+        } else if (instr.opCode == OpCodes.Dawson) {
+          var x = code[instr.childIndex].value;
+          instr.value = double.IsNaN(x) ? double.NaN : alglib.dawsonintegral(x);
+        } else if (instr.opCode == OpCodes.ExponentialIntegralEi) {
+          var x = code[instr.childIndex].value;
+          instr.value = double.IsNaN(x) ? double.NaN : alglib.exponentialintegralei(x);
+        } else if (instr.opCode == OpCodes.SineIntegral) {
+          double si, ci;
+          var x = code[instr.childIndex].value;
+          if (double.IsNaN(x)) instr.value = double.NaN;
+          else {
+            alglib.sinecosineintegrals(x, out si, out ci);
+            instr.value = si;
+          }
+        } else if (instr.opCode == OpCodes.CosineIntegral) {
+          double si, ci;
+          var x = code[instr.childIndex].value;
+          if (double.IsNaN(x)) instr.value = double.NaN;
+          else {
+            alglib.sinecosineintegrals(x, out si, out ci);
+            instr.value = ci;
+          }
+        } else if (instr.opCode == OpCodes.HyperbolicSineIntegral) {
+          double shi, chi;
+          var x = code[instr.childIndex].value;
+          if (double.IsNaN(x)) instr.value = double.NaN;
+          else {
+            alglib.hyperbolicsinecosineintegrals(x, out shi, out chi);
+            instr.value = shi;
+          }
+        } else if (instr.opCode == OpCodes.HyperbolicCosineIntegral) {
+          double shi, chi;
+          var x = code[instr.childIndex].value;
+          if (double.IsNaN(x)) instr.value = double.NaN;
+          else {
+            alglib.hyperbolicsinecosineintegrals(x, out shi, out chi);
+            instr.value = chi;
+          }
+        } else if (instr.opCode == OpCodes.FresnelCosineIntegral) {
+          double c = 0, s = 0;
+          var x = code[instr.childIndex].value;
+          if (double.IsNaN(x)) instr.value = double.NaN;
+          else {
+            alglib.fresnelintegral(x, ref c, ref s);
+            instr.value = c;
+          }
+        } else if (instr.opCode == OpCodes.FresnelSineIntegral) {
+          double c = 0, s = 0;
+          var x = code[instr.childIndex].value;
+          if (double.IsNaN(x)) instr.value = double.NaN;
+          else {
+            alglib.fresnelintegral(x, ref c, ref s);
+            instr.value = s;
+          }
+        } else if (instr.opCode == OpCodes.AiryA) {
+          double ai, aip, bi, bip;
+          var x = code[instr.childIndex].value;
+          if (double.IsNaN(x)) instr.value = double.NaN;
+          else {
+            alglib.airy(x, out ai, out aip, out bi, out bip);
+            instr.value = ai;
+          }
+        } else if (instr.opCode == OpCodes.AiryB) {
+          double ai, aip, bi, bip;
+          var x = code[instr.childIndex].value;
+          if (double.IsNaN(x)) instr.value = double.NaN;
+          else {
+            alglib.airy(x, out ai, out aip, out bi, out bip);
+            instr.value = bi;
+          }
+        } else if (instr.opCode == OpCodes.Norm) {
+          var x = code[instr.childIndex].value;
+          if (double.IsNaN(x)) instr.value = double.NaN;
+          else instr.value = alglib.normaldistribution(x);
+        } else if (instr.opCode == OpCodes.Erf) {
+          var x = code[instr.childIndex].value;
+          if (double.IsNaN(x)) instr.value = double.NaN;
+          else instr.value = alglib.errorfunction(x);
+        } else if (instr.opCode == OpCodes.Bessel) {
+          var x = code[instr.childIndex].value;
+          if (double.IsNaN(x)) instr.value = double.NaN;
+          else instr.value = alglib.besseli0(x);
+        } else if (instr.opCode == OpCodes.IfThenElse) {
+          double condition = code[instr.childIndex].value;
+          double result;
+          if (condition > 0.0) {
+            result = code[instr.childIndex + 1].value;
+          } else {
+            result = code[instr.childIndex + 2].value;
+          }
+          instr.value = result;
+        } else if (instr.opCode == OpCodes.AND) {
+          double result = code[instr.childIndex].value;
+          for (int j = 1; j < instr.nArguments; j++) {
+            if (result > 0.0) result = code[instr.childIndex + j].value;
+            else break;
+          }
+          instr.value = result > 0.0 ? 1.0 : -1.0;
+        } else if (instr.opCode == OpCodes.OR) {
+          double result = code[instr.childIndex].value;
+          for (int j = 1; j < instr.nArguments; j++) {
+            if (result <= 0.0) result = code[instr.childIndex + j].value;
+            else break;
+          }
+          instr.value = result > 0.0 ? 1.0 : -1.0;
+        } else if (instr.opCode == OpCodes.NOT) {
+          instr.value = code[instr.childIndex].value > 0.0 ? -1.0 : 1.0;
+        } else if (instr.opCode == OpCodes.GT) {
+          double x = code[instr.childIndex].value;
+          double y = code[instr.childIndex + 1].value;
+          instr.value = x > y ? 1.0 : -1.0;
+        } else if (instr.opCode == OpCodes.LT) {
+          double x = code[instr.childIndex].value;
+          double y = code[instr.childIndex + 1].value;
+          instr.value = x < y ? 1.0 : -1.0;
+        } else if (instr.opCode == OpCodes.TimeLag || instr.opCode == OpCodes.Derivative || instr.opCode == OpCodes.Integral) {
+          var state = (InterpreterState)instr.data;
+          state.Reset();
+          instr.value = interpreter.Evaluate(dataset, ref row, state);
+        } else {
+          var errorText = string.Format("The {0} symbol is not supported by the linear interpreter. To support this symbol, please use the SymbolicDataAnalysisExpressionTreeInterpreter.", instr.dynamicNode.Symbol.Name);
+          throw new NotSupportedException(errorText);
+        }
+        #endregion
+      }
+      return code[0].value;
+    }
+
+    private static LinearInstruction[] GetPrefixSequence(LinearInstruction[] code, int startIndex) {
+      var s = new Stack<int>();
+      var list = new List<LinearInstruction>();
+      s.Push(startIndex);
+      while (s.Any()) {
+        int i = s.Pop();
+        var instr = code[i];
+        // push instructions in reverse execution order
+        for (int j = instr.nArguments - 1; j >= 0; j--) s.Push(instr.childIndex + j);
+        list.Add(instr);
+      }
+      return list.ToArray();
+    }
+
+    private static void PrepareInstructions(LinearInstruction[] code, Dataset dataset) {
+      for (int i = 0; i != code.Length; ++i) {
+        var instr = code[i];
+        #region opcode switch
+        switch (instr.opCode) {
+          case OpCodes.Constant: {
+              var constTreeNode = (ConstantTreeNode)instr.dynamicNode;
+              instr.value = constTreeNode.Value;
+              instr.skip = true; // the value is already set so this instruction should be skipped in the evaluation phase
+            }
+            break;
+          case OpCodes.Variable: {
+              var variableTreeNode = (VariableTreeNode)instr.dynamicNode;
+              instr.data = dataset.GetReadOnlyDoubleValues(variableTreeNode.VariableName);
+            }
+            break;
+          case OpCodes.LagVariable: {
+              var laggedVariableTreeNode = (LaggedVariableTreeNode)instr.dynamicNode;
+              instr.data = dataset.GetReadOnlyDoubleValues(laggedVariableTreeNode.VariableName);
+            }
+            break;
+          case OpCodes.VariableCondition: {
+              var variableConditionTreeNode = (VariableConditionTreeNode)instr.dynamicNode;
+              instr.data = dataset.GetReadOnlyDoubleValues(variableConditionTreeNode.VariableName);
+            }
+            break;
+          case OpCodes.TimeLag:
+          case OpCodes.Integral:
+          case OpCodes.Derivative: {
+              var seq = GetPrefixSequence(code, i);
+              var interpreterState = new InterpreterState(seq, 0);
+              instr.data = interpreterState;
+              for (int j = 1; j != seq.Length; ++j)
+                seq[j].skip = true;
+            }
+            break;
+        }
+        #endregion
+      }
+    }
+  }
+}
Index: stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisProblem.cs
===================================================================
--- stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisProblem.cs	(revision 9961)
+++ stable/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisProblem.cs	(revision 9976)
@@ -196,5 +196,5 @@
 
       SymbolicExpressionTreeGrammar = new TypeCoherentExpressionGrammar();
-      SymbolicExpressionTreeInterpreter = new SymbolicDataAnalysisExpressionTreeInterpreter();
+      SymbolicExpressionTreeInterpreter = new SymbolicDataAnalysisExpressionTreeLinearInterpreter();
 
       FitnessCalculationPartition.Start = ProblemData.TrainingPartition.Start;
Index: stable/HeuristicLab.Tests/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4/SymbolicDataAnalysisExpressionTreeInterpreterTest.cs
===================================================================
--- stable/HeuristicLab.Tests/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4/SymbolicDataAnalysisExpressionTreeInterpreterTest.cs	(revision 9961)
+++ stable/HeuristicLab.Tests/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4/SymbolicDataAnalysisExpressionTreeInterpreterTest.cs	(revision 9976)
@@ -30,67 +30,85 @@
 
 
-  [TestClass()]
+  [TestClass]
   public class SymbolicDataAnalysisExpressionTreeInterpreterTest {
     private const int N = 1000;
     private const int Rows = 1000;
     private const int Columns = 50;
-    private TestContext testContextInstance;
-
-    /// <summary>
-    ///Gets or sets the test context which provides
-    ///information about and functionality for the current test run.
-    ///</summary>
-    public TestContext TestContext {
-      get {
-        return testContextInstance;
-      }
-      set {
-        testContextInstance = value;
-      }
-    }
-
-    [TestMethod]
-    [TestCategory("Problems.DataAnalysis")]
-    [TestProperty("Time", "long")]
-    public void SymbolicDataAnalysisExpressionTreeInterpreterTypeCoherentGrammarPerformanceTest() {
-      TypeCoherentGrammarPerformanceTest(new SymbolicDataAnalysisExpressionTreeInterpreter(), 12.5e6);
-    }
-
-    [TestMethod]
-    [TestCategory("Problems.DataAnalysis")]
-    [TestProperty("Time", "long")]
-    public void SymbolicDataAnalysisExpressionTreeInterpreterFullGrammarPerformanceTest() {
-      FullGrammarPerformanceTest(new SymbolicDataAnalysisExpressionTreeInterpreter(), 12.5e6);
-    }
-
-    [TestMethod]
-    [TestCategory("Problems.DataAnalysis")]
-    [TestProperty("Time", "long")]
-    public void SymbolicDataAnalysisExpressionTreeInterpreterArithmeticGrammarPerformanceTest() {
-      ArithmeticGrammarPerformanceTest(new SymbolicDataAnalysisExpressionTreeInterpreter(), 12.5e6);
-    }
-
-    [TestMethod]
-    [TestCategory("Problems.DataAnalysis")]
-    [TestProperty("Time", "long")]
-    public void SymbolicDataAnalysisExpressionTreeILEmittingInterpreterTypeCoherentGrammarPerformanceTest() {
-      TypeCoherentGrammarPerformanceTest(new SymbolicDataAnalysisExpressionTreeILEmittingInterpreter(), 7.5e6);
-    }
-
-    [TestMethod]
-    [TestCategory("Problems.DataAnalysis")]
-    [TestProperty("Time", "long")]
-    public void SymbolicDataAnalysisExpressionTreeILEmittingInterpreterFullGrammarPerformanceTest() {
-      FullGrammarPerformanceTest(new SymbolicDataAnalysisExpressionTreeILEmittingInterpreter(), 7.5e6);
-    }
-
-    [TestCategory("Problems.DataAnalysis")]
-    [TestProperty("Time", "long")]
-    [TestMethod]
-    public void SymbolicDataAnalysisExpressionTreeILEmittingInterpreterArithmeticGrammarPerformanceTest() {
-      ArithmeticGrammarPerformanceTest(new SymbolicDataAnalysisExpressionTreeILEmittingInterpreter(), 7.5e6);
-    }
-
-    private void TypeCoherentGrammarPerformanceTest(ISymbolicDataAnalysisExpressionTreeInterpreter interpreter, double nodesPerSecThreshold) {
+
+    private static Dataset ds = new Dataset(new string[] { "Y", "A", "B" }, new double[,] {
+        { 1.0, 1.0, 1.0 },
+        { 2.0, 2.0, 2.0 },
+        { 3.0, 1.0, 2.0 },
+        { 4.0, 1.0, 1.0 },
+        { 5.0, 2.0, 2.0 },
+        { 6.0, 1.0, 2.0 },
+        { 7.0, 1.0, 1.0 },
+        { 8.0, 2.0, 2.0 },
+        { 9.0, 1.0, 2.0 },
+        { 10.0, 1.0, 1.0 },
+        { 11.0, 2.0, 2.0 },
+        { 12.0, 1.0, 2.0 }
+      });
+
+    [TestMethod]
+    [TestCategory("Problems.DataAnalysis.Symbolic")]
+    [TestProperty("Time", "long")]
+    public void StandardInterpreterTestTypeCoherentGrammarPerformance() {
+      TestTypeCoherentGrammarPerformance(new SymbolicDataAnalysisExpressionTreeInterpreter(), 12.5e6);
+    }
+    [TestMethod]
+    [TestCategory("Problems.DataAnalysis.Symbolic")]
+    [TestProperty("Time", "long")]
+    public void StandardInterpreterTestFullGrammarPerformance() {
+      TestFullGrammarPerformance(new SymbolicDataAnalysisExpressionTreeInterpreter(), 12.5e6);
+    }
+    [TestMethod]
+    [TestCategory("Problems.DataAnalysis.Symbolic")]
+    [TestProperty("Time", "long")]
+    public void StandardInterpreterTestArithmeticGrammarPerformance() {
+      TestArithmeticGrammarPerformance(new SymbolicDataAnalysisExpressionTreeInterpreter(), 12.5e6);
+    }
+
+
+    [TestMethod]
+    [TestCategory("Problems.DataAnalysis.Symbolic")]
+    [TestProperty("Time", "long")]
+    public void ILEmittingInterpreterTestTypeCoherentGrammarPerformance() {
+      TestTypeCoherentGrammarPerformance(new SymbolicDataAnalysisExpressionTreeILEmittingInterpreter(), 7.5e6);
+    }
+    [TestMethod]
+    [TestCategory("Problems.DataAnalysis.Symbolic")]
+    [TestProperty("Time", "long")]
+    public void ILEmittingInterpreterTestFullGrammarPerformance() {
+      TestFullGrammarPerformance(new SymbolicDataAnalysisExpressionTreeILEmittingInterpreter(), 7.5e6);
+    }
+    [TestMethod]
+    [TestCategory("Problems.DataAnalysis.Symbolic")]
+    [TestProperty("Time", "long")]
+    public void ILEmittingInterpreterTestArithmeticGrammarPerformance() {
+      TestArithmeticGrammarPerformance(new SymbolicDataAnalysisExpressionTreeILEmittingInterpreter(), 7.5e6);
+    }
+
+
+    [TestMethod]
+    [TestCategory("Problems.DataAnalysis.Symbolic")]
+    [TestProperty("Time", "long")]
+    public void LinearInterpreterTestTypeCoherentGrammarPerformance() {
+      TestTypeCoherentGrammarPerformance(new SymbolicDataAnalysisExpressionTreeLinearInterpreter(), 12.5e6);
+    }
+    [TestMethod]
+    [TestCategory("Problems.DataAnalysis.Symbolic")]
+    [TestProperty("Time", "long")]
+    public void LinearInterpreterTestFullGrammarPerformance() {
+      TestFullGrammarPerformance(new SymbolicDataAnalysisExpressionTreeLinearInterpreter(), 12.5e6);
+    }
+    [TestMethod]
+    [TestCategory("Problems.DataAnalysis.Symbolic")]
+    [TestProperty("Time", "long")]
+    public void LinearInterpreterTestArithmeticGrammarPerformance() {
+      TestArithmeticGrammarPerformance(new SymbolicDataAnalysisExpressionTreeLinearInterpreter(), 12.5e6);
+    }
+
+    private void TestTypeCoherentGrammarPerformance(ISymbolicDataAnalysisExpressionTreeInterpreter interpreter, double nodesPerSecThreshold) {
       var twister = new MersenneTwister(31415);
       var dataset = Util.CreateRandomDataset(twister, Rows, Columns);
@@ -110,5 +128,5 @@
     }
 
-    private void FullGrammarPerformanceTest(ISymbolicDataAnalysisExpressionTreeInterpreter interpreter, double nodesPerSecThreshold) {
+    private void TestFullGrammarPerformance(ISymbolicDataAnalysisExpressionTreeInterpreter interpreter, double nodesPerSecThreshold) {
       var twister = new MersenneTwister(31415);
       var dataset = Util.CreateRandomDataset(twister, Rows, Columns);
@@ -127,5 +145,5 @@
     }
 
-    private void ArithmeticGrammarPerformanceTest(ISymbolicDataAnalysisExpressionTreeInterpreter interpreter, double nodesPerSecThreshold) {
+    private void TestArithmeticGrammarPerformance(ISymbolicDataAnalysisExpressionTreeInterpreter interpreter, double nodesPerSecThreshold) {
       var twister = new MersenneTwister(31415);
       var dataset = Util.CreateRandomDataset(twister, Rows, Columns);
@@ -150,22 +168,7 @@
     ///</summary>
     [TestMethod]
-    [TestCategory("Problems.DataAnalysis")]
+    [TestCategory("Problems.DataAnalysis.Symbolic")]
     [TestProperty("Time", "short")]
-    public void SymbolicDataAnalysisExpressionTreeInterpreterEvaluateTest() {
-      Dataset ds = new Dataset(new string[] { "Y", "A", "B" }, new double[,] {
-        { 1.0, 1.0, 1.0 },
-        { 2.0, 2.0, 2.0 },
-        { 3.0, 1.0, 2.0 },
-        { 4.0, 1.0, 1.0 },
-        { 5.0, 2.0, 2.0 },
-        { 6.0, 1.0, 2.0 },
-        { 7.0, 1.0, 1.0 },
-        { 8.0, 2.0, 2.0 },
-        { 9.0, 1.0, 2.0 },
-        { 10.0, 1.0, 1.0 },
-        { 11.0, 2.0, 2.0 },
-        { 12.0, 1.0, 2.0 }
-      });
-
+    public void StandardInterpreterTestEvaluation() {
       var interpreter = new SymbolicDataAnalysisExpressionTreeInterpreter();
       EvaluateTerminals(interpreter, ds);
@@ -175,23 +178,19 @@
 
     [TestMethod]
-    [TestCategory("Problems.DataAnalysis")]
+    [TestCategory("Problems.DataAnalysis.Symbolic")]
     [TestProperty("Time", "short")]
-    public void SymbolicDataAnalysisExpressionILEmittingTreeInterpreterEvaluateTest() {
-      Dataset ds = new Dataset(new string[] { "Y", "A", "B" }, new double[,] {
-        { 1.0, 1.0, 1.0 },
-        { 2.0, 2.0, 2.0 },
-        { 3.0, 1.0, 2.0 },
-        { 4.0, 1.0, 1.0 },
-        { 5.0, 2.0, 2.0 },
-        { 6.0, 1.0, 2.0 },
-        { 7.0, 1.0, 1.0 },
-        { 8.0, 2.0, 2.0 },
-        { 9.0, 1.0, 2.0 },
-        { 10.0, 1.0, 1.0 },
-        { 11.0, 2.0, 2.0 },
-        { 12.0, 1.0, 2.0 }
-      });
-
+    public void ILEmittingInterpreterTestEvaluation() {
       var interpreter = new SymbolicDataAnalysisExpressionTreeILEmittingInterpreter();
+      EvaluateTerminals(interpreter, ds);
+      EvaluateOperations(interpreter, ds);
+    }
+
+    [TestMethod]
+    [TestCategory("Problems.DataAnalysis.Symbolic")]
+    [TestProperty("Time", "short")]
+    public void LinearInterpreterTestEvaluation() {
+      var interpreter = new SymbolicDataAnalysisExpressionTreeLinearInterpreter();
+
+      //ADFs are not supported by the linear interpreter
       EvaluateTerminals(interpreter, ds);
       EvaluateOperations(interpreter, ds);
@@ -430,5 +429,6 @@
           try {
             Evaluate(interpreter, ds, "(psi " + x + ")", 0, alglib.psi(x));
-          } catch (alglib.alglibexception) { // ignore cases where alglib throws an exception
+          }
+          catch (alglib.alglibexception) { // ignore cases where alglib throws an exception
           }
         };
Index: stable/HeuristicLab.Tests/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis-3.4/SymbolicDataAnalysisExpressionTreeInterpreterTest.cs
===================================================================
--- stable/HeuristicLab.Tests/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis-3.4/SymbolicDataAnalysisExpressionTreeInterpreterTest.cs	(revision 9961)
+++ stable/HeuristicLab.Tests/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis-3.4/SymbolicDataAnalysisExpressionTreeInterpreterTest.cs	(revision 9976)
@@ -37,25 +37,25 @@
 
     [TestMethod]
-    [TestCategory("Problems.DataAnalysis")]
+    [TestCategory("Problems.DataAnalysis.Symbolic")]
     [TestProperty("Time", "long")]
-    public void SymbolicTimeSeriesPrognosisTreeInterpreterTypeCoherentGrammarPerformanceTest() {
-      TypeCoherentGrammarPerformanceTest(new SymbolicTimeSeriesPrognosisExpressionTreeInterpreter("y"), 12.5e6);
+    public void TimeSeriesPrognosisInterpreterTestTypeCoherentGrammarPerformance() {
+      TestTypeCoherentGrammarPerformance(new SymbolicTimeSeriesPrognosisExpressionTreeInterpreter("y"), 12.5e6);
     }
 
     [TestMethod]
-    [TestCategory("Problems.DataAnalysis")]
+    [TestCategory("Problems.DataAnalysis.Symbolic")]
     [TestProperty("Time", "long")]
-    public void SymbolicTimeSeriesPrognosisTreeInterpreterFullGrammarPerformanceTest() {
-      FullGrammarPerformanceTest(new SymbolicTimeSeriesPrognosisExpressionTreeInterpreter("y"), 12.5e6);
+    public void TimeSeriesPrognosisInterpreterTestFullGrammarPerformance() {
+      TestFullGrammarPerformance(new SymbolicTimeSeriesPrognosisExpressionTreeInterpreter("y"), 12.5e6);
     }
 
     [TestMethod]
-    [TestCategory("Problems.DataAnalysis")]
+    [TestCategory("Problems.DataAnalysis.Symbolic")]
     [TestProperty("Time", "long")]
-    public void SymbolicTimeSeriesPrognosisTreeInterpreterArithmeticGrammarPerformanceTest() {
-      ArithmeticGrammarPerformanceTest(new SymbolicTimeSeriesPrognosisExpressionTreeInterpreter("y"), 12.5e6);
-    }
-
-    private void TypeCoherentGrammarPerformanceTest(ISymbolicTimeSeriesPrognosisExpressionTreeInterpreter interpreter, double nodesPerSecThreshold) {
+    public void TimeSeriesPrognosisInterpreterTestArithmeticGrammarPerformance() {
+      TestArithmeticGrammarPerformance(new SymbolicTimeSeriesPrognosisExpressionTreeInterpreter("y"), 12.5e6);
+    }
+
+    private void TestTypeCoherentGrammarPerformance(ISymbolicTimeSeriesPrognosisExpressionTreeInterpreter interpreter, double nodesPerSecThreshold) {
       var twister = new MersenneTwister(31415);
       var dataset = Util.CreateRandomDataset(twister, Rows, Columns);
@@ -75,5 +75,5 @@
     }
 
-    private void FullGrammarPerformanceTest(ISymbolicTimeSeriesPrognosisExpressionTreeInterpreter interpreter, double nodesPerSecThreshold) {
+    private void TestFullGrammarPerformance(ISymbolicTimeSeriesPrognosisExpressionTreeInterpreter interpreter, double nodesPerSecThreshold) {
       var twister = new MersenneTwister(31415);
       var dataset = Util.CreateRandomDataset(twister, Rows, Columns);
@@ -92,5 +92,5 @@
     }
 
-    private void ArithmeticGrammarPerformanceTest(ISymbolicTimeSeriesPrognosisExpressionTreeInterpreter interpreter, double nodesPerSecThreshold) {
+    private void TestArithmeticGrammarPerformance(ISymbolicTimeSeriesPrognosisExpressionTreeInterpreter interpreter, double nodesPerSecThreshold) {
       var twister = new MersenneTwister(31415);
       var dataset = Util.CreateRandomDataset(twister, Rows, Columns);
@@ -115,7 +115,7 @@
     ///</summary>
     [TestMethod]
-    [TestCategory("Problems.DataAnalysis")]
+    [TestCategory("Problems.DataAnalysis.Symbolic")]
     [TestProperty("Time", "short")]
-    public void SymbolicDataAnalysisExpressionTreeInterpreterEvaluateTest() {
+    public void TimeSeriesPrognosisInterpreterTestEvaluation() {
       Dataset ds = new Dataset(new string[] { "Y", "A", "B" }, new double[,] {
         { 1.0, 1.0, 1.0 },
