Index: trunk/sources/HeuristicLab.Problems.DataAnalysis/3.3/Symbolic/SimpleArithmeticExpressionInterpreter.cs
===================================================================
--- trunk/sources/HeuristicLab.Problems.DataAnalysis/3.3/Symbolic/SimpleArithmeticExpressionInterpreter.cs	(revision 5222)
+++ trunk/sources/HeuristicLab.Problems.DataAnalysis/3.3/Symbolic/SimpleArithmeticExpressionInterpreter.cs	(revision 5223)
@@ -33,5 +33,4 @@
   [StorableClass]
   [Item("SimpleArithmeticExpressionInterpreter", "Interpreter for arithmetic symbolic expression trees including function calls.")]
-  // not thread safe!
   public sealed class SimpleArithmeticExpressionInterpreter : NamedItem, ISymbolicExpressionTreeInterpreter {
     private class OpCodes {
@@ -93,11 +92,4 @@
     private const int ARGUMENT_STACK_SIZE = 1024;
 
-    private Dataset dataset;
-    private int row;
-    private Instruction[] code;
-    private int pc;
-    private double[] argumentStack = new double[ARGUMENT_STACK_SIZE];
-    private int argStackPointer;
-
     public override bool CanChangeName {
       get { return false; }
@@ -110,5 +102,4 @@
     private SimpleArithmeticExpressionInterpreter(bool deserializing) : base(deserializing) { }
     private SimpleArithmeticExpressionInterpreter(SimpleArithmeticExpressionInterpreter original, Cloner cloner) : base(original, cloner) { }
-
     public override IDeepCloneable Clone(Cloner cloner) {
       return new SimpleArithmeticExpressionInterpreter(this, cloner);
@@ -120,25 +111,171 @@
 
     public IEnumerable<double> GetSymbolicExpressionTreeValues(SymbolicExpressionTree tree, Dataset dataset, IEnumerable<int> rows) {
-      this.dataset = dataset;
       var compiler = new SymbolicExpressionTreeCompiler();
-      compiler.AddInstructionPostProcessingHook(PostProcessInstruction);
-      code = compiler.Compile(tree, MapSymbolToOpCode);
-      foreach (var row in rows) {
-        this.row = row;
-        pc = 0;
-        argStackPointer = 0;
-        yield return Evaluate();
-      }
-    }
-
-    private Instruction PostProcessInstruction(Instruction instr) {
-      if (instr.opCode == OpCodes.Variable) {
-        var variableTreeNode = instr.dynamicNode as VariableTreeNode;
-        instr.iArg0 = (ushort)dataset.GetVariableIndex(variableTreeNode.VariableName);
-      } else if (instr.opCode == OpCodes.LagVariable) {
-        var variableTreeNode = instr.dynamicNode as LaggedVariableTreeNode;
-        instr.iArg0 = (ushort)dataset.GetVariableIndex(variableTreeNode.VariableName);
-      }
-      return instr;
+      Instruction[] code = compiler.Compile(tree, MapSymbolToOpCode);
+
+      for (int i = 0; i < code.Length; i++) {
+        Instruction instr = code[i];
+        if (instr.opCode == OpCodes.Variable) {
+          var variableTreeNode = instr.dynamicNode as VariableTreeNode;
+          instr.iArg0 = (ushort)dataset.GetVariableIndex(variableTreeNode.VariableName);
+          code[i] = instr;
+        } else if (instr.opCode == OpCodes.LagVariable) {
+          var variableTreeNode = instr.dynamicNode as LaggedVariableTreeNode;
+          instr.iArg0 = (ushort)dataset.GetVariableIndex(variableTreeNode.VariableName);
+          code[i] = instr;
+        }
+      }
+
+      double[] argumentStack = new double[ARGUMENT_STACK_SIZE];
+      foreach (var rowEnum in rows) {
+        int row = rowEnum;
+        int pc = 0;
+        int argStackPointer = 0;
+        yield return Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer);
+      }
+    }
+
+    private double Evaluate(Dataset dataset, ref int row, Instruction[] code, ref int pc, double[] argumentStack, ref int argStackPointer) {
+      Instruction currentInstr = code[pc++];
+      switch (currentInstr.opCode) {
+        case OpCodes.Add: {
+            double s = Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer);
+            for (int i = 1; i < currentInstr.nArguments; i++) {
+              s += Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer);
+            }
+            return s;
+          }
+        case OpCodes.Sub: {
+            double s = Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer);
+            for (int i = 1; i < currentInstr.nArguments; i++) {
+              s -= Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer);
+            }
+            if (currentInstr.nArguments == 1) s = -s;
+            return s;
+          }
+        case OpCodes.Mul: {
+            double p = Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer);
+            for (int i = 1; i < currentInstr.nArguments; i++) {
+              p *= Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer);
+            }
+            return p;
+          }
+        case OpCodes.Div: {
+            double p = Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer);
+            for (int i = 1; i < currentInstr.nArguments; i++) {
+              p /= Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer);
+            }
+            if (currentInstr.nArguments == 1) p = 1.0 / p;
+            return p;
+          }
+        case OpCodes.Average: {
+            double sum = Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer);
+            for (int i = 1; i < currentInstr.nArguments; i++) {
+              sum += Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer);
+            }
+            return sum / currentInstr.nArguments;
+          }
+        case OpCodes.Cos: {
+            return Math.Cos(Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer));
+          }
+        case OpCodes.Sin: {
+            return Math.Sin(Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer));
+          }
+        case OpCodes.Tan: {
+            return Math.Tan(Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer));
+          }
+        case OpCodes.Exp: {
+            return Math.Exp(Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer));
+          }
+        case OpCodes.Log: {
+            return Math.Log(Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer));
+          }
+        case OpCodes.IfThenElse: {
+            double condition = Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer);
+            double result;
+            if (condition > 0.0) {
+              result = Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer); SkipBakedCode(code, ref pc);
+            } else {
+              SkipBakedCode(code, ref pc); result = Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer);
+            }
+            return result;
+          }
+        case OpCodes.AND: {
+            double result = Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer);
+            for (int i = 1; i < currentInstr.nArguments; i++) {
+              if (result <= 0.0) SkipBakedCode(code, ref pc);
+              else {
+                result = Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer);
+              }
+            }
+            return result <= 0.0 ? -1.0 : 1.0;
+          }
+        case OpCodes.OR: {
+            double result = Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer);
+            for (int i = 1; i < currentInstr.nArguments; i++) {
+              if (result > 0.0) SkipBakedCode(code, ref pc);
+              else {
+                result = Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer);
+              }
+            }
+            return result > 0.0 ? 1.0 : -1.0;
+          }
+        case OpCodes.NOT: {
+            return -Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer);
+          }
+        case OpCodes.GT: {
+            double x = Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer);
+            double y = Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer);
+            if (x > y) return 1.0;
+            else return -1.0;
+          }
+        case OpCodes.LT: {
+            double x = Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer);
+            double y = Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer);
+            if (x < y) return 1.0;
+            else return -1.0;
+          }
+        case OpCodes.Call: {
+            // evaluate sub-trees
+            // push on argStack in reverse order 
+            for (int i = 0; i < currentInstr.nArguments; i++) {
+              argumentStack[argStackPointer + currentInstr.nArguments - i] = Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer);
+            }
+            argStackPointer += currentInstr.nArguments;
+
+            // save the pc
+            int nextPc = pc;
+            // set pc to start of function  
+            pc = currentInstr.iArg0;
+            // evaluate the function
+            double v = Evaluate(dataset, ref row, code, ref pc, argumentStack, ref argStackPointer);
+
+            // decrease the argument stack pointer by the number of arguments pushed
+            // to set the argStackPointer back to the original location
+            argStackPointer -= currentInstr.nArguments;
+
+            // restore the pc => evaluation will continue at point after my subtrees  
+            pc = nextPc;
+            return v;
+          }
+        case OpCodes.Arg: {
+            return argumentStack[argStackPointer - currentInstr.iArg0];
+          }
+        case OpCodes.Variable: {
+            var variableTreeNode = currentInstr.dynamicNode as VariableTreeNode;
+            return dataset[row, currentInstr.iArg0] * variableTreeNode.Weight;
+          }
+        case OpCodes.LagVariable: {
+            var laggedVariableTreeNode = currentInstr.dynamicNode as LaggedVariableTreeNode;
+            int actualRow = row + laggedVariableTreeNode.Lag;
+            if (actualRow < 0 || actualRow >= dataset.Rows) throw new ArgumentException("Out of range access to dataset row: " + row);
+            return dataset[actualRow, currentInstr.iArg0] * laggedVariableTreeNode.Weight;
+          }
+        case OpCodes.Constant: {
+            var constTreeNode = currentInstr.dynamicNode as ConstantTreeNode;
+            return constTreeNode.Value;
+          }
+        default: throw new NotSupportedException();
+      }
     }
 
@@ -150,150 +287,6 @@
     }
 
-    private double Evaluate() {
-      Instruction currentInstr = code[pc++];
-      switch (currentInstr.opCode) {
-        case OpCodes.Add: {
-            double s = Evaluate();
-            for (int i = 1; i < currentInstr.nArguments; i++) {
-              s += Evaluate();
-            }
-            return s;
-          }
-        case OpCodes.Sub: {
-            double s = Evaluate();
-            for (int i = 1; i < currentInstr.nArguments; i++) {
-              s -= Evaluate();
-            }
-            if (currentInstr.nArguments == 1) s = -s;
-            return s;
-          }
-        case OpCodes.Mul: {
-            double p = Evaluate();
-            for (int i = 1; i < currentInstr.nArguments; i++) {
-              p *= Evaluate();
-            }
-            return p;
-          }
-        case OpCodes.Div: {
-            double p = Evaluate();
-            for (int i = 1; i < currentInstr.nArguments; i++) {
-              p /= Evaluate();
-            }
-            if (currentInstr.nArguments == 1) p = 1.0 / p;
-            return p;
-          }
-        case OpCodes.Average: {
-            double sum = Evaluate();
-            for (int i = 1; i < currentInstr.nArguments; i++) {
-              sum += Evaluate();
-            }
-            return sum / currentInstr.nArguments;
-          }
-        case OpCodes.Cos: {
-            return Math.Cos(Evaluate());
-          }
-        case OpCodes.Sin: {
-            return Math.Sin(Evaluate());
-          }
-        case OpCodes.Tan: {
-            return Math.Tan(Evaluate());
-          }
-        case OpCodes.Exp: {
-            return Math.Exp(Evaluate());
-          }
-        case OpCodes.Log: {
-            return Math.Log(Evaluate());
-          }
-        case OpCodes.IfThenElse: {
-            double condition = Evaluate();
-            double result;
-            if (condition > 0.0) {
-              result = Evaluate(); SkipBakedCode();
-            } else {
-              SkipBakedCode(); result = Evaluate();
-            }
-            return result;
-          }
-        case OpCodes.AND: {
-            double result = Evaluate();
-            for (int i = 1; i < currentInstr.nArguments; i++) {
-              if (result <= 0.0) SkipBakedCode();
-              else {
-                result = Evaluate();
-              }
-            }
-            return result <= 0.0 ? -1.0 : 1.0;
-          }
-        case OpCodes.OR: {
-            double result = Evaluate();
-            for (int i = 1; i < currentInstr.nArguments; i++) {
-              if (result > 0.0) SkipBakedCode();
-              else {
-                result = Evaluate();
-              }
-            }
-            return result > 0.0 ? 1.0 : -1.0;
-          }
-        case OpCodes.NOT: {
-            return -Evaluate();
-          }
-        case OpCodes.GT: {
-            double x = Evaluate();
-            double y = Evaluate();
-            if (x > y) return 1.0;
-            else return -1.0;
-          }
-        case OpCodes.LT: {
-            double x = Evaluate();
-            double y = Evaluate();
-            if (x < y) return 1.0;
-            else return -1.0;
-          }
-        case OpCodes.Call: {
-            // evaluate sub-trees
-            // push on argStack in reverse order 
-            for (int i = 0; i < currentInstr.nArguments; i++) {
-              argumentStack[argStackPointer + currentInstr.nArguments - i] = Evaluate();
-            }
-            argStackPointer += currentInstr.nArguments;
-
-            // save the pc
-            int nextPc = pc;
-            // set pc to start of function  
-            pc = currentInstr.iArg0;
-            // evaluate the function
-            double v = Evaluate();
-
-            // decrease the argument stack pointer by the number of arguments pushed
-            // to set the argStackPointer back to the original location
-            argStackPointer -= currentInstr.nArguments;
-
-            // restore the pc => evaluation will continue at point after my subtrees  
-            pc = nextPc;
-            return v;
-          }
-        case OpCodes.Arg: {
-            return argumentStack[argStackPointer - currentInstr.iArg0];
-          }
-        case OpCodes.Variable: {
-            var variableTreeNode = currentInstr.dynamicNode as VariableTreeNode;
-            return dataset[row, currentInstr.iArg0] * variableTreeNode.Weight;
-          }
-        case OpCodes.LagVariable: {
-            var lagVariableTreeNode = currentInstr.dynamicNode as LaggedVariableTreeNode;
-            int actualRow = row + lagVariableTreeNode.Lag;
-            if (actualRow < 0 || actualRow >= dataset.Rows) throw new ArgumentException("Out of range access to dataset row: " + row);
-            return dataset[actualRow, currentInstr.iArg0] * lagVariableTreeNode.Weight;
-          }
-        case OpCodes.Constant: {
-            var constTreeNode = currentInstr.dynamicNode as ConstantTreeNode;
-            return constTreeNode.Value;
-          }
-        default: throw new NotSupportedException();
-      }
-    }
-
     // skips a whole branch
-    private void SkipBakedCode() {
+    private void SkipBakedCode(Instruction[] code, ref int pc) {
       int i = 1;
       while (i > 0) {
