Index: /trunk/sources/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding/3.4/Compiler/Instruction.cs
===================================================================
--- /trunk/sources/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding/3.4/Compiler/Instruction.cs	(revision 9827)
+++ /trunk/sources/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding/3.4/Compiler/Instruction.cs	(revision 9828)
@@ -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: /trunk/sources/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding/3.4/Compiler/LinearInstruction.cs
===================================================================
--- /trunk/sources/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding/3.4/Compiler/LinearInstruction.cs	(revision 9828)
+++ /trunk/sources/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding/3.4/Compiler/LinearInstruction.cs	(revision 9828)
@@ -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: /trunk/sources/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding/3.4/Compiler/SymbolicExpressionTreeCompiler.cs
===================================================================
--- /trunk/sources/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding/3.4/Compiler/SymbolicExpressionTreeCompiler.cs	(revision 9827)
+++ /trunk/sources/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding/3.4/Compiler/SymbolicExpressionTreeCompiler.cs	(revision 9828)
@@ -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: /trunk/sources/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding/3.4/Compiler/SymbolicExpressionTreeLinearCompiler.cs
===================================================================
--- /trunk/sources/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding/3.4/Compiler/SymbolicExpressionTreeLinearCompiler.cs	(revision 9828)
+++ /trunk/sources/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding/3.4/Compiler/SymbolicExpressionTreeLinearCompiler.cs	(revision 9828)
@@ -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: /trunk/sources/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding/3.4/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding-3.4.csproj
===================================================================
--- /trunk/sources/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding/3.4/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding-3.4.csproj	(revision 9827)
+++ /trunk/sources/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding/3.4/HeuristicLab.Encodings.SymbolicExpressionTreeEncoding-3.4.csproj	(revision 9828)
@@ -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: /trunk/sources/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis/3.4/SymbolicTimeSeriesPrognosisExpressionTreeInterpreter.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis/3.4/SymbolicTimeSeriesPrognosisExpressionTreeInterpreter.cs	(revision 9827)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis/3.4/SymbolicTimeSeriesPrognosisExpressionTreeInterpreter.cs	(revision 9828)
@@ -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: /trunk/sources/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4.csproj
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4.csproj	(revision 9827)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4.csproj	(revision 9828)
@@ -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: /trunk/sources/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeILEmittingInterpreter.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeILEmittingInterpreter.cs	(revision 9827)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeILEmittingInterpreter.cs	(revision 9828)
@@ -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: /trunk/sources/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeInterpreter.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeInterpreter.cs	(revision 9827)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeInterpreter.cs	(revision 9828)
@@ -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: /trunk/sources/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeLinearInterpreter.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeLinearInterpreter.cs	(revision 9828)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeLinearInterpreter.cs	(revision 9828)
@@ -0,0 +1,467 @@
+﻿#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 switch
+        var instr = code[i];
+        switch (instr.opCode) {
+          case 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;
+            }
+            break;
+          case 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;
+            }
+            break;
+          case 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);
+            }
+            break;
+          case 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;
+            }
+            break;
+          case 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;
+            }
+            break;
+          case 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;
+            }
+            break;
+          case 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;
+            }
+            break;
+          case 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;
+            }
+            break;
+          case OpCodes.Cos: {
+              instr.value = Math.Cos(code[instr.childIndex].value);
+            }
+            break;
+          case OpCodes.Sin: {
+              instr.value = Math.Sin(code[instr.childIndex].value);
+            }
+            break;
+          case OpCodes.Tan: {
+              instr.value = Math.Tan(code[instr.childIndex].value);
+            }
+            break;
+          case OpCodes.Square: {
+              instr.value = Math.Pow(code[instr.childIndex].value, 2);
+            }
+            break;
+          case OpCodes.Power: {
+              double x = code[instr.childIndex].value;
+              double y = Math.Round(code[instr.childIndex + 1].value);
+              instr.value = Math.Pow(x, y);
+            }
+            break;
+          case OpCodes.SquareRoot: {
+              instr.value = Math.Sqrt(code[instr.childIndex].value);
+            }
+            break;
+          case OpCodes.Root: {
+              double x = code[instr.childIndex].value;
+              double y = code[instr.childIndex + 1].value;
+              instr.value = Math.Pow(x, 1 / y);
+            }
+            break;
+          case OpCodes.Exp: {
+              instr.value = Math.Exp(code[instr.childIndex].value);
+            }
+            break;
+          case OpCodes.Log: {
+              instr.value = Math.Log(code[instr.childIndex].value);
+            }
+            break;
+          case OpCodes.Gamma: {
+              var x = code[instr.childIndex].value;
+              instr.value = double.IsNaN(x) ? double.NaN : alglib.gammafunction(x);
+            }
+            break;
+          case 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);
+            }
+            break;
+          case OpCodes.Dawson: {
+              var x = code[instr.childIndex].value;
+              instr.value = double.IsNaN(x) ? double.NaN : alglib.dawsonintegral(x);
+            }
+            break;
+          case OpCodes.ExponentialIntegralEi: {
+              var x = code[instr.childIndex].value;
+              instr.value = double.IsNaN(x) ? double.NaN : alglib.exponentialintegralei(x);
+            }
+            break;
+          case 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;
+              }
+            }
+            break;
+          case 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;
+              }
+            }
+            break;
+          case 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;
+              }
+            }
+            break;
+          case 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;
+              }
+            }
+            break;
+          case 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;
+              }
+            }
+            break;
+          case 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;
+              }
+            }
+            break;
+          case 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;
+              }
+            }
+            break;
+          case 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;
+              }
+            }
+            break;
+          case OpCodes.Norm: {
+              var x = code[instr.childIndex].value;
+              if (double.IsNaN(x)) instr.value = double.NaN;
+              else instr.value = alglib.normaldistribution(x);
+            }
+            break;
+          case OpCodes.Erf: {
+              var x = code[instr.childIndex].value;
+              if (double.IsNaN(x)) instr.value = double.NaN;
+              else instr.value = alglib.errorfunction(x);
+            }
+            break;
+          case OpCodes.Bessel: {
+              var x = code[instr.childIndex].value;
+              if (double.IsNaN(x)) instr.value = double.NaN;
+              else instr.value = alglib.besseli0(x);
+            }
+            break;
+          case 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;
+            }
+            break;
+          case 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;
+            }
+            break;
+          case 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;
+            }
+            break;
+          case OpCodes.NOT: {
+              instr.value = code[instr.childIndex].value > 0.0 ? -1.0 : 1.0;
+            }
+            break;
+          case OpCodes.GT: {
+              double x = code[instr.childIndex].value;
+              double y = code[instr.childIndex + 1].value;
+              instr.value = x > y ? 1.0 : -1.0;
+            }
+            break;
+          case OpCodes.LT: {
+              double x = code[instr.childIndex].value;
+              double y = code[instr.childIndex + 1].value;
+              instr.value = x < y ? 1.0 : -1.0;
+            }
+            break;
+          case OpCodes.TimeLag:
+          case OpCodes.Integral:
+          case OpCodes.Derivative: {
+              var state = (InterpreterState)instr.data;
+              state.Reset();
+              instr.value = interpreter.Evaluate(dataset, ref row, state);
+            }
+            break;
+          default:
+            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 list = new List<LinearInstruction>();
+      int i = startIndex;
+      while (i != code.Length) {
+        var instr = code[i];
+        list.Add(instr);
+        i = instr.nArguments > 0 ? instr.childIndex : i + 1;
+      }
+      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: /trunk/sources/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisSolutionValuesCalculator.cs
===================================================================
--- /trunk/sources/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisSolutionValuesCalculator.cs	(revision 9828)
+++ /trunk/sources/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/SymbolicDataAnalysisSolutionValuesCalculator.cs	(revision 9828)
@@ -0,0 +1,67 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2012 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.Collections.Generic;
+using HeuristicLab.Common;
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
+
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
+  public abstract class SymbolicDataAnalysisSolutionValuesCalculator {
+    protected readonly ISymbolicExpressionTree tempTree;
+    protected readonly ConstantTreeNode constantNode;
+
+    public SymbolicDataAnalysisSolutionValuesCalculator() {
+      constantNode = ((ConstantTreeNode)new Constant().CreateTreeNode());
+      ISymbolicExpressionTreeNode root = new ProgramRootSymbol().CreateTreeNode();
+      ISymbolicExpressionTreeNode start = new StartSymbol().CreateTreeNode();
+      root.AddSubtree(start);
+      tempTree = new SymbolicExpressionTree(root);
+    }
+
+    // should be moved to an interface, then un-abstract the class
+    public abstract Dictionary<ISymbolicExpressionTreeNode, double> CalculateReplacementValues(ISymbolicExpressionTree tree, ISymbolicDataAnalysisExpressionTreeInterpreter interpreter, IDataAnalysisProblemData problemData);
+    public abstract Dictionary<ISymbolicExpressionTreeNode, double> CalculateImpactValues(ISymbolicExpressionTree tree, ISymbolicDataAnalysisExpressionTreeInterpreter interpreter, IDataAnalysisProblemData problemData, double lowerEstimationLimit, double upperEstimationLimit);
+
+    protected void SwitchNode(ISymbolicExpressionTreeNode root, ISymbolicExpressionTreeNode oldBranch, ISymbolicExpressionTreeNode newBranch) {
+      for (int i = 0; i < root.SubtreeCount; i++) {
+        if (root.GetSubtree(i) == oldBranch) {
+          root.RemoveSubtree(i);
+          root.InsertSubtree(i, newBranch);
+          return;
+        }
+      }
+    }
+
+    protected double CalculateReplacementValue(ISymbolicExpressionTreeNode node, ISymbolicExpressionTree sourceTree, ISymbolicDataAnalysisExpressionTreeInterpreter interpreter, IDataAnalysisProblemData problemData) {
+      // remove old ADFs
+      while (tempTree.Root.SubtreeCount > 1) tempTree.Root.RemoveSubtree(1);
+      // clone ADFs of source tree
+      for (int i = 1; i < sourceTree.Root.SubtreeCount; i++) {
+        tempTree.Root.AddSubtree((ISymbolicExpressionTreeNode)sourceTree.Root.GetSubtree(i).Clone());
+      }
+      var start = tempTree.Root.GetSubtree(0);
+      while (start.SubtreeCount > 0) start.RemoveSubtree(0);
+      start.AddSubtree((ISymbolicExpressionTreeNode)node.Clone());
+      var rows = problemData.TrainingIndices;
+      return interpreter.GetSymbolicExpressionTreeValues(tempTree, problemData.Dataset, rows).Median();
+    }
+  }
+}
Index: /trunk/sources/HeuristicLab.Tests/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4/SymbolicDataAnalysisExpressionTreeInterpreterTest.cs
===================================================================
--- /trunk/sources/HeuristicLab.Tests/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4/SymbolicDataAnalysisExpressionTreeInterpreterTest.cs	(revision 9827)
+++ /trunk/sources/HeuristicLab.Tests/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4/SymbolicDataAnalysisExpressionTreeInterpreterTest.cs	(revision 9828)
@@ -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: /trunk/sources/HeuristicLab.Tests/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis-3.4/SymbolicDataAnalysisExpressionTreeInterpreterTest.cs
===================================================================
--- /trunk/sources/HeuristicLab.Tests/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis-3.4/SymbolicDataAnalysisExpressionTreeInterpreterTest.cs	(revision 9827)
+++ /trunk/sources/HeuristicLab.Tests/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis-3.4/SymbolicDataAnalysisExpressionTreeInterpreterTest.cs	(revision 9828)
@@ -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 },
