Index: branches/2521_ProblemRefactoring/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/IntervalArithBoundsEstimator.cs
===================================================================
--- branches/2521_ProblemRefactoring/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/IntervalArithBoundsEstimator.cs	(revision 18086)
+++ branches/2521_ProblemRefactoring/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/IntervalArithBoundsEstimator.cs	(revision 18086)
@@ -0,0 +1,349 @@
+﻿#region License Information
+
+/* HeuristicLab
+ * Copyright (C) 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 HEAL.Attic;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
+using HeuristicLab.Parameters;
+
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
+  [StorableType("C8539434-6FB0-47D0-9F5A-2CAE5D8B8B4F")]
+  [Item("Interval Arithmetic Bounds Estimator", "Interpreter for calculation of intervals of symbolic models.")]
+  public sealed class IntervalArithBoundsEstimator : ParameterizedNamedItem, IBoundsEstimator {
+    #region Parameters
+
+    private const string EvaluatedSolutionsParameterName = "EvaluatedSolutions";
+
+    public IFixedValueParameter<IntValue> EvaluatedSolutionsParameter =>
+      (IFixedValueParameter<IntValue>)Parameters[EvaluatedSolutionsParameterName];
+
+    public int EvaluatedSolutions {
+      get => EvaluatedSolutionsParameter.Value.Value;
+      set => EvaluatedSolutionsParameter.Value.Value = value;
+    }
+    #endregion
+
+    #region Constructors
+
+    [StorableConstructor]
+    private IntervalArithBoundsEstimator(StorableConstructorFlag _) : base(_) { }
+
+    protected IntervalArithBoundsEstimator(IntervalArithBoundsEstimator original, Cloner cloner) : base(original, cloner) { }
+
+    public IntervalArithBoundsEstimator() : base("Interval Arithmetic Bounds Estimator",
+      "Estimates the bounds of the model with interval arithmetic") {
+      Parameters.Add(new FixedValueParameter<IntValue>(EvaluatedSolutionsParameterName,
+        "A counter for the total number of solutions the estimator has evaluated.", new IntValue(0)));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new IntervalArithBoundsEstimator(this, cloner);
+    }
+
+    #endregion
+
+    #region IStatefulItem Members
+
+    private readonly object syncRoot = new object();
+
+    public void InitializeState() {
+      EvaluatedSolutions = 0;
+    }
+
+    public void ClearState() { }
+
+    #endregion
+
+    #region Evaluation
+
+    private static Instruction[] PrepareInterpreterState(
+      ISymbolicExpressionTree tree,
+      IDictionary<string, Interval> variableRanges) {
+      if (variableRanges == null)
+        throw new ArgumentNullException("No variable ranges are present!", nameof(variableRanges));
+
+      // Check if all variables used in the tree are present in the dataset
+      foreach (var variable in tree.IterateNodesPrefix().OfType<VariableTreeNode>().Select(n => n.VariableName)
+                                   .Distinct())
+        if (!variableRanges.ContainsKey(variable))
+          throw new InvalidOperationException($"No ranges for variable {variable} is present");
+
+      var code = SymbolicExpressionTreeCompiler.Compile(tree, OpCodes.MapSymbolToOpCode);
+      foreach (var instr in code.Where(i => i.opCode == OpCodes.Variable)) {
+        var variableTreeNode = (VariableTreeNode)instr.dynamicNode;
+        instr.data = variableRanges[variableTreeNode.VariableName];
+      }
+
+      return code;
+    }
+
+    // Use ref parameter, because the tree will be iterated through recursively from the left-side branch to the right side
+    // Update instructionCounter, whenever Evaluate is called
+    public static Interval Evaluate(
+      Instruction[] instructions, ref int instructionCounter,
+      IDictionary<ISymbolicExpressionTreeNode, Interval> nodeIntervals = null,
+      IDictionary<string, Interval> variableIntervals = null) {
+      var currentInstr = instructions[instructionCounter];
+      instructionCounter++;
+      Interval result;
+
+      switch (currentInstr.opCode) {
+        case OpCodes.Variable: {
+            var variableTreeNode = (VariableTreeNode)currentInstr.dynamicNode;
+            var weightInterval = new Interval(variableTreeNode.Weight, variableTreeNode.Weight);
+
+            Interval variableInterval;
+            if (variableIntervals != null && variableIntervals.ContainsKey(variableTreeNode.VariableName))
+              variableInterval = variableIntervals[variableTreeNode.VariableName];
+            else
+              variableInterval = (Interval)currentInstr.data;
+
+            result = Interval.Multiply(variableInterval, weightInterval);
+            break;
+          }
+        case OpCodes.Constant: {
+            var constTreeNode = (ConstantTreeNode)currentInstr.dynamicNode;
+            result = new Interval(constTreeNode.Value, constTreeNode.Value);
+            break;
+          }
+        case OpCodes.Add: {
+            result = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
+            for (var i = 1; i < currentInstr.nArguments; i++) {
+              var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
+              result = Interval.Add(result, argumentInterval);
+            }
+
+            break;
+          }
+        case OpCodes.Sub: {
+            result = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
+            if (currentInstr.nArguments == 1)
+              result = Interval.Multiply(new Interval(-1, -1), result);
+
+            for (var i = 1; i < currentInstr.nArguments; i++) {
+              var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
+              result = Interval.Subtract(result, argumentInterval);
+            }
+
+            break;
+          }
+        case OpCodes.Mul: {
+            result = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
+            for (var i = 1; i < currentInstr.nArguments; i++) {
+              var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
+              result = Interval.Multiply(result, argumentInterval);
+            }
+
+            break;
+          }
+        case OpCodes.Div: {
+            result = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
+            if (currentInstr.nArguments == 1)
+              result = Interval.Divide(new Interval(1, 1), result);
+
+            for (var i = 1; i < currentInstr.nArguments; i++) {
+              var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
+              result = Interval.Divide(result, argumentInterval);
+            }
+
+            break;
+          }
+        case OpCodes.Sin: {
+            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
+            result = Interval.Sine(argumentInterval);
+            break;
+          }
+        case OpCodes.Cos: {
+            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
+            result = Interval.Cosine(argumentInterval);
+            break;
+          }
+        case OpCodes.Tan: {
+            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
+            result = Interval.Tangens(argumentInterval);
+            break;
+          }
+        case OpCodes.Tanh: {
+            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
+            result = Interval.HyperbolicTangent(argumentInterval);
+            break;
+          }
+        case OpCodes.Log: {
+            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
+            result = Interval.Logarithm(argumentInterval);
+            break;
+          }
+        case OpCodes.Exp: {
+            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
+            result = Interval.Exponential(argumentInterval);
+            break;
+          }
+        case OpCodes.Square: {
+            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
+            result = Interval.Square(argumentInterval);
+            break;
+          }
+        case OpCodes.SquareRoot: {
+            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
+            result = Interval.SquareRoot(argumentInterval);
+            break;
+          }
+        case OpCodes.Cube: {
+            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
+            result = Interval.Cube(argumentInterval);
+            break;
+          }
+        case OpCodes.CubeRoot: {
+            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
+            result = Interval.CubicRoot(argumentInterval);
+            break;
+          }
+        case OpCodes.Power: {
+          var a = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
+          var b = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
+          // support only integer powers
+          if (b.LowerBound == b.UpperBound && Math.Truncate(b.LowerBound) == b.LowerBound) {
+            result = Interval.Power(a, (int)b.LowerBound);
+          } else {
+            throw new NotSupportedException("Interval is only supported for integer powers");
+          }
+          break;
+        }
+        case OpCodes.Absolute: {
+            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
+            result = Interval.Absolute(argumentInterval);
+            break;
+          }
+        case OpCodes.AnalyticQuotient: {
+            result = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
+            for (var i = 1; i < currentInstr.nArguments; i++) {
+              var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
+              result = Interval.AnalyticQuotient(result, argumentInterval);
+            }
+
+            break;
+          }
+        default:
+          throw new NotSupportedException(
+            $"The tree contains the unknown symbol {currentInstr.dynamicNode.Symbol}");
+      }
+
+      if (!(nodeIntervals == null || nodeIntervals.ContainsKey(currentInstr.dynamicNode)))
+        nodeIntervals.Add(currentInstr.dynamicNode, result);
+
+      return result;
+    }
+
+    #endregion
+
+    #region Helpers
+
+    private static IDictionary<string, Interval> GetOccurringVariableRanges(
+      ISymbolicExpressionTree tree, IntervalCollection variableRanges) {
+      var variables = tree.IterateNodesPrefix().OfType<VariableTreeNode>().Select(v => v.VariableName).Distinct()
+                          .ToList();
+
+      return variables.ToDictionary(x => x, x => variableRanges.GetReadonlyDictionary()[x]);
+    }
+
+    #endregion
+  
+    public Interval GetModelBound(ISymbolicExpressionTree tree, IntervalCollection variableRanges) {
+      lock (syncRoot) {
+        EvaluatedSolutions++;
+      }
+
+      var occuringVariableRanges = GetOccurringVariableRanges(tree, variableRanges);
+      var instructions = PrepareInterpreterState(tree, occuringVariableRanges);
+      Interval resultInterval;
+      var instructionCounter = 0;
+      resultInterval = Evaluate(instructions, ref instructionCounter, variableIntervals: occuringVariableRanges);
+
+      // because of numerical errors the bounds might be incorrect
+      if (resultInterval.IsInfiniteOrUndefined || resultInterval.LowerBound <= resultInterval.UpperBound)
+        return resultInterval;
+
+      return new Interval(resultInterval.UpperBound, resultInterval.LowerBound);
+    }
+
+    public IDictionary<ISymbolicExpressionTreeNode, Interval> GetModelNodeBounds(
+      ISymbolicExpressionTree tree, IntervalCollection variableRanges) {
+      throw new NotImplementedException();
+    }
+
+    public double GetConstraintViolation(
+      ISymbolicExpressionTree tree, IntervalCollection variableRanges, ShapeConstraint constraint) {
+      var occuringVariableRanges = GetOccurringVariableRanges(tree, variableRanges);
+      var instructions = PrepareInterpreterState(tree, occuringVariableRanges);
+      var instructionCounter = 0;
+      var modelBound = Evaluate(instructions, ref instructionCounter, variableIntervals: occuringVariableRanges);
+      if (constraint.Interval.Contains(modelBound)) return 0.0;
+
+
+      var error = 0.0;
+
+      if (!constraint.Interval.Contains(modelBound.LowerBound)) {
+        error += Math.Abs(modelBound.LowerBound - constraint.Interval.LowerBound);
+      }
+
+      if (!constraint.Interval.Contains(modelBound.UpperBound)) {
+        error += Math.Abs(modelBound.UpperBound - constraint.Interval.UpperBound);
+      }
+
+      return error;
+    }
+
+
+    public bool IsCompatible(ISymbolicExpressionTree tree) {
+      var containsUnknownSymbols = (
+        from n in tree.Root.GetSubtree(0).IterateNodesPrefix()
+        where
+          !(n.Symbol is Variable) &&
+          !(n.Symbol is Constant) &&
+          !(n.Symbol is StartSymbol) &&
+          !(n.Symbol is Addition) &&
+          !(n.Symbol is Subtraction) &&
+          !(n.Symbol is Multiplication) &&
+          !(n.Symbol is Division) &&
+          !(n.Symbol is Sine) &&
+          !(n.Symbol is Cosine) &&
+          !(n.Symbol is Tangent) &&
+          !(n.Symbol is HyperbolicTangent) &&
+          !(n.Symbol is Logarithm) &&
+          !(n.Symbol is Exponential) &&
+          !(n.Symbol is Square) &&
+          !(n.Symbol is SquareRoot) &&
+          !(n.Symbol is Cube) &&
+          !(n.Symbol is CubeRoot) &&
+          !(n.Symbol is Power) &&
+          !(n.Symbol is Absolute) &&
+          !(n.Symbol is AnalyticQuotient)
+        select n).Any();
+      return !containsUnknownSymbols;
+    }
+  }
+}
Index: branches/2521_ProblemRefactoring/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/IntervalArithCompiledExpressionBoundsEstimator.cs
===================================================================
--- branches/2521_ProblemRefactoring/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/IntervalArithCompiledExpressionBoundsEstimator.cs	(revision 18086)
+++ branches/2521_ProblemRefactoring/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/IntervalArithCompiledExpressionBoundsEstimator.cs	(revision 18086)
@@ -0,0 +1,260 @@
+﻿#region License Information
+
+/* HeuristicLab
+ * Copyright (C) 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 HEAL.Attic;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
+using HeuristicLab.Parameters;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Linq.Expressions;
+
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
+  [StorableType("60015D64-5D8B-408A-90A1-E4111BC114D4")]
+  [Item("Interval Arithmetic Compiled Expression Bounds Estimator", "Compile a symbolic model into a lambda and use it to evaluate model bounds.")]
+  public class IntervalArithCompiledExpressionBoundsEstimator : ParameterizedNamedItem, IBoundsEstimator {
+    // interval method names
+    private static readonly Dictionary<byte, string> methodName = new Dictionary<byte, string>() {
+      { OpCodes.Add, "Add" },
+      { OpCodes.Sub, "Subtract" },
+      { OpCodes.Mul, "Multiply" },
+      { OpCodes.Div, "Divide" },
+      { OpCodes.Sin, "Sine" },
+      { OpCodes.Cos, "Cosine" },
+      { OpCodes.Tan, "Tangens" },
+      { OpCodes.Tanh, "HyperbolicTangent" },
+      { OpCodes.Log, "Logarithm" },
+      { OpCodes.Exp, "Exponential" },
+      { OpCodes.Square, "Square" },
+      { OpCodes.Cube, "Cube" },
+      { OpCodes.SquareRoot, "SquareRoot" },
+      { OpCodes.CubeRoot, "CubicRoot" },
+      { OpCodes.Absolute, "Absolute" },
+      { OpCodes.AnalyticQuotient, "AnalyticalQuotient" },
+    };
+
+    private const string EvaluatedSolutionsParameterName = "EvaluatedSolutions";
+    public IFixedValueParameter<IntValue> EvaluatedSolutionsParameter {
+      get => (IFixedValueParameter<IntValue>)Parameters[EvaluatedSolutionsParameterName];
+    }
+    public int EvaluatedSolutions {
+      get => EvaluatedSolutionsParameter.Value.Value;
+      set => EvaluatedSolutionsParameter.Value.Value = value;
+    }
+
+    private readonly object syncRoot = new object();
+
+    public IntervalArithCompiledExpressionBoundsEstimator() : base("Interval Arithmetic Compiled Expression Bounds Estimator",
+      "Estimates the bounds of the model with interval arithmetic, by first compiling the model into a lambda.") {
+      Parameters.Add(new FixedValueParameter<IntValue>(EvaluatedSolutionsParameterName,
+        "A counter for the total number of solutions the estimator has evaluated.", new IntValue(0)));
+    }
+
+    [StorableConstructor]
+    protected IntervalArithCompiledExpressionBoundsEstimator(StorableConstructorFlag _) : base(_) { }
+
+    protected IntervalArithCompiledExpressionBoundsEstimator(IntervalArithCompiledExpressionBoundsEstimator original, Cloner cloner) : base(original, cloner) { }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new IntervalArithCompiledExpressionBoundsEstimator(this, cloner);
+    }
+
+    public double GetConstraintViolation(ISymbolicExpressionTree tree, IntervalCollection variableRanges, ShapeConstraint constraint) {
+      var modelBound = GetModelBound(tree, variableRanges);
+      if (constraint.Interval.Contains(modelBound)) return 0.0;
+      return Math.Abs(modelBound.LowerBound - constraint.Interval.LowerBound) +
+             Math.Abs(modelBound.UpperBound - constraint.Interval.UpperBound);
+    }
+
+    public void ClearState() {
+      EvaluatedSolutions = 0;
+    }
+
+    public Interval GetModelBound(ISymbolicExpressionTree tree, IntervalCollection variableRanges) {
+      lock (syncRoot) { EvaluatedSolutions++; }
+      var resultInterval = EstimateBounds(tree, variableRanges.GetReadonlyDictionary());
+
+      if (resultInterval.IsInfiniteOrUndefined || resultInterval.LowerBound <= resultInterval.UpperBound)
+        return resultInterval;
+      return new Interval(resultInterval.UpperBound, resultInterval.LowerBound);
+    }
+
+    public IDictionary<ISymbolicExpressionTreeNode, Interval> GetModelNodeBounds(ISymbolicExpressionTree tree, IntervalCollection variableRanges) {
+      throw new NotSupportedException("Model nodes bounds are not supported.");
+    }
+
+    public void InitializeState() {
+      EvaluatedSolutions = 0;
+    }
+
+    public bool IsCompatible(ISymbolicExpressionTree tree) {
+      var containsUnknownSymbols = (
+        from n in tree.Root.GetSubtree(0).IterateNodesPrefix()
+        where
+          !(n.Symbol is Variable) &&
+          !(n.Symbol is Constant) &&
+          !(n.Symbol is StartSymbol) &&
+          !(n.Symbol is Addition) &&
+          !(n.Symbol is Subtraction) &&
+          !(n.Symbol is Multiplication) &&
+          !(n.Symbol is Division) &&
+          !(n.Symbol is Sine) &&
+          !(n.Symbol is Cosine) &&
+          !(n.Symbol is Tangent) &&
+          !(n.Symbol is HyperbolicTangent) &&
+          !(n.Symbol is Logarithm) &&
+          !(n.Symbol is Exponential) &&
+          !(n.Symbol is Square) &&
+          !(n.Symbol is SquareRoot) &&
+          !(n.Symbol is Cube) &&
+          !(n.Symbol is CubeRoot) &&
+          !(n.Symbol is Absolute) &&
+          !(n.Symbol is AnalyticQuotient)
+        select n).Any();
+      return !containsUnknownSymbols;
+    }
+
+    #region compile a tree into a IA arithmetic lambda and estimate bounds
+    static Expression MakeExpr(ISymbolicExpressionTreeNode node, IReadOnlyDictionary<string, Interval> variableRanges, IReadOnlyDictionary<string, int> variableIndices, Expression args) {
+      Expression expr(ISymbolicExpressionTreeNode n) => MakeExpr(n, variableRanges, variableIndices, args);
+      var opCode = OpCodes.MapSymbolToOpCode(node);
+
+      switch (opCode) {
+        case OpCodes.Variable: {
+            var name = (node as VariableTreeNode).VariableName;
+            var weight = (node as VariableTreeNode).Weight;
+            var index = variableIndices[name];
+            return Expression.Multiply(
+              Expression.Constant(weight, typeof(double)),
+              Expression.ArrayIndex(args, Expression.Constant(index, typeof(int)))
+            );
+          }
+        case OpCodes.Constant: {
+            var v = (node as ConstantTreeNode).Value;
+            // we have to make an interval out of the constant because this may be the root of the tree (and we are expected to return an Interval)
+            return Expression.Constant(new Interval(v, v), typeof(Interval));
+          }
+        case OpCodes.Add: {
+            var e = expr(node.GetSubtree(0));
+            foreach (var s in node.Subtrees.Skip(1)) {
+              e = Expression.Add(e, expr(s));
+            }
+            return e;
+          }
+        case OpCodes.Sub: {
+            var e = expr(node.GetSubtree(0));
+            if (node.SubtreeCount == 1) {
+              return Expression.Subtract(Expression.Constant(0.0, typeof(double)), e);
+            }
+            foreach (var s in node.Subtrees.Skip(1)) {
+              e = Expression.Subtract(e, expr(s));
+            }
+            return e;
+          }
+        case OpCodes.Mul: {
+            var e = expr(node.GetSubtree(0));
+            foreach (var s in node.Subtrees.Skip(1)) {
+              e = Expression.Multiply(e, expr(s));
+            }
+            return e;
+          }
+        case OpCodes.Div: {
+            var e1 = expr(node.GetSubtree(0));
+            if (node.SubtreeCount == 1) {
+              return Expression.Divide(Expression.Constant(1.0, typeof(double)), e1);
+            }
+            // division is more expensive than multiplication so we use this construct
+            var e2 = expr(node.GetSubtree(1));
+            foreach (var s in node.Subtrees.Skip(2)) {
+              e2 = Expression.Multiply(e2, expr(s));
+            }
+            return Expression.Divide(e1, e2);
+          }
+        case OpCodes.AnalyticQuotient: {
+            var a = expr(node.GetSubtree(0));
+            var b = expr(node.GetSubtree(1));
+            var fun = typeof(Interval).GetMethod(methodName[opCode], new[] { a.Type, b.Type });
+            return Expression.Call(fun, a, b);
+          }
+        // all these cases share the same code: get method info by name, emit call expression
+        case OpCodes.Exp:
+        case OpCodes.Log:
+        case OpCodes.Sin:
+        case OpCodes.Cos:
+        case OpCodes.Tan:
+        case OpCodes.Tanh:
+        case OpCodes.Square:
+        case OpCodes.Cube:
+        case OpCodes.SquareRoot:
+        case OpCodes.CubeRoot:
+        case OpCodes.Absolute: {
+            var arg = expr(node.GetSubtree(0));
+            var fun = typeof(Interval).GetMethod(methodName[opCode], new[] { arg.Type });
+            return Expression.Call(fun, arg);
+          }
+        default: {
+            throw new Exception($"Unsupported OpCode {opCode} encountered.");
+          }
+      }
+    }
+
+    public static IReadOnlyDictionary<string, int> GetVariableIndices(ISymbolicExpressionTree tree, IReadOnlyDictionary<string, Interval> variableIntervals, out Interval[] inputIntervals) {
+      var variableIndices = new Dictionary<string, int>();
+      var root = tree.Root;
+      while (root.Symbol is ProgramRootSymbol || root.Symbol is StartSymbol) {
+        root = root.GetSubtree(0);
+      }
+      inputIntervals = new Interval[variableIntervals.Count];
+      int count = 0;
+      foreach (var node in root.IterateNodesPrefix()) {
+        if (node is VariableTreeNode varNode) {
+          var name = varNode.VariableName;
+          if (!variableIndices.ContainsKey(name)) {
+            variableIndices[name] = count;
+            inputIntervals[count] = variableIntervals[name];
+            ++count;
+          }
+        }
+      }
+      Array.Resize(ref inputIntervals, count);
+      return variableIndices;
+    }
+
+    public static Func<Interval[], Interval> Compile(ISymbolicExpressionTree tree, IReadOnlyDictionary<string, Interval> variableRanges, IReadOnlyDictionary<string, int> variableIndices) {
+      var root = tree.Root.GetSubtree(0).GetSubtree(0);
+      var args = Expression.Parameter(typeof(Interval[]));
+      var expr = MakeExpr(root, variableRanges, variableIndices, args);
+      return Expression.Lambda<Func<Interval[], Interval>>(expr, args).Compile();
+    }
+
+    public static Interval EstimateBounds(ISymbolicExpressionTree tree, IReadOnlyDictionary<string, Interval> variableRanges) {
+      var variableIndices = GetVariableIndices(tree, variableRanges, out Interval[] x);
+      var f = Compile(tree, variableRanges, variableIndices);
+      return f(x);
+    }
+    #endregion
+  }
+}
Index: branches/2521_ProblemRefactoring/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/IntervalInterpreter.cs
===================================================================
--- branches/2521_ProblemRefactoring/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/IntervalInterpreter.cs	(revision 17586)
+++ branches/2521_ProblemRefactoring/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/IntervalInterpreter.cs	(revision 18086)
@@ -1,3 +1,4 @@
 ﻿#region License Information
+
 /* HeuristicLab
  * Copyright (C) Heuristic and Evolutionary Algorithms Laboratory (HEAL)
@@ -18,4 +19,5 @@
  * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
  */
+
 #endregion
 
@@ -32,26 +34,25 @@
 namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
   [StorableType("DE6C1E1E-D7C1-4070-847E-63B68562B10C")]
-  [Item("IntervalInterpreter", "Intperter for calculation of intervals of symbolic models.")]
+  [Item("IntervalInterpreter", "Interpreter for calculation of intervals of symbolic models.")]
   public sealed class IntervalInterpreter : ParameterizedNamedItem, IStatefulItem {
-
     private const string EvaluatedSolutionsParameterName = "EvaluatedSolutions";
-
-    public IFixedValueParameter<IntValue> EvaluatedSolutionsParameter {
-      get { return (IFixedValueParameter<IntValue>)Parameters[EvaluatedSolutionsParameterName]; }
-    }
+    public IFixedValueParameter<IntValue> EvaluatedSolutionsParameter =>
+      (IFixedValueParameter<IntValue>)Parameters[EvaluatedSolutionsParameterName];
 
     public int EvaluatedSolutions {
-      get { return EvaluatedSolutionsParameter.Value.Value; }
-      set { EvaluatedSolutionsParameter.Value.Value = value; }
+      get => EvaluatedSolutionsParameter.Value.Value;
+      set => EvaluatedSolutionsParameter.Value.Value = value;
     }
 
     [StorableConstructor]
     private IntervalInterpreter(StorableConstructorFlag _) : base(_) { }
+
     private IntervalInterpreter(IntervalInterpreter original, Cloner cloner)
-        : base(original, cloner) { }
+      : base(original, cloner) { }
 
     public IntervalInterpreter()
-        : base("IntervalInterpreter", "Intperter for calculation of intervals of symbolic models.") {
-      Parameters.Add(new FixedValueParameter<IntValue>(EvaluatedSolutionsParameterName, "A counter for the total number of solutions the interpreter has evaluated", new IntValue(0)));
+      : base("IntervalInterpreter", "Interpreter for calculation of intervals of symbolic models.") {
+      Parameters.Add(new FixedValueParameter<IntValue>(EvaluatedSolutionsParameterName,
+        "A counter for the total number of solutions the interpreter has evaluated", new IntValue(0)));
     }
 
@@ -63,48 +64,63 @@
 
     #region IStatefulItem Members
+
     public void InitializeState() {
       EvaluatedSolutions = 0;
     }
+
     public void ClearState() { }
+
     #endregion
 
-    public Interval GetSymbolicExpressionTreeInterval(ISymbolicExpressionTree tree, IDataset dataset, IEnumerable<int> rows = null) {
+    public Interval GetSymbolicExpressionTreeInterval(
+      ISymbolicExpressionTree tree, IDataset dataset,
+      IEnumerable<int> rows = null) {
       var variableRanges = DatasetUtil.GetVariableRanges(dataset, rows);
       return GetSymbolicExpressionTreeInterval(tree, variableRanges);
     }
 
-    public Interval GetSymbolicExpressionTreeIntervals(ISymbolicExpressionTree tree, IDataset dataset,
-      out IDictionary<ISymbolicExpressionTreeNode, Interval> nodeIntervals, IEnumerable<int> rows = null) {
+    public Interval GetSymbolicExpressionTreeIntervals(
+      ISymbolicExpressionTree tree, IDataset dataset,
+      out IDictionary<ISymbolicExpressionTreeNode, Interval>
+        nodeIntervals, IEnumerable<int> rows = null) {
       var variableRanges = DatasetUtil.GetVariableRanges(dataset, rows);
       return GetSymbolicExpressionTreeIntervals(tree, variableRanges, out nodeIntervals);
     }
 
-    public Interval GetSymbolicExpressionTreeInterval(ISymbolicExpressionTree tree, IReadOnlyDictionary<string, Interval> variableRanges) {
+    public Interval GetSymbolicExpressionTreeInterval(
+      ISymbolicExpressionTree tree,
+      IReadOnlyDictionary<string, Interval> variableRanges) {
       lock (syncRoot) {
         EvaluatedSolutions++;
       }
-      int instructionCount = 0;
+
+      Interval outputInterval;
+
+      var instructionCount = 0;
       var instructions = PrepareInterpreterState(tree, variableRanges);
-      var outputInterval = Evaluate(instructions, ref instructionCount);
-
-      // because of numerical errors the bounds might be incorrect
-      if (outputInterval.LowerBound <= outputInterval.UpperBound)
-        return outputInterval;
-      else
-        return new Interval(outputInterval.UpperBound, outputInterval.LowerBound);
-    }
-
-
-    public Interval GetSymbolicExpressionTreeIntervals(ISymbolicExpressionTree tree,
-      IReadOnlyDictionary<string, Interval> variableRanges, out IDictionary<ISymbolicExpressionTreeNode, Interval> nodeIntervals) {
+      outputInterval = Evaluate(instructions, ref instructionCount);
+
+      return outputInterval.LowerBound <= outputInterval.UpperBound
+        ? outputInterval
+        : new Interval(outputInterval.UpperBound, outputInterval.LowerBound);
+    }
+
+
+    public Interval GetSymbolicExpressionTreeIntervals(
+      ISymbolicExpressionTree tree,
+      IReadOnlyDictionary<string, Interval> variableRanges,
+      out IDictionary<ISymbolicExpressionTreeNode, Interval>
+        nodeIntervals) {
       lock (syncRoot) {
         EvaluatedSolutions++;
       }
-      int instructionCount = 0;
+
       var intervals = new Dictionary<ISymbolicExpressionTreeNode, Interval>();
       var instructions = PrepareInterpreterState(tree, variableRanges);
-      var outputInterval = Evaluate(instructions, ref instructionCount, intervals);
-
-      // fix incorrect intervals if necessary (could occur because of numerical errors)
+
+      Interval outputInterval;
+      var instructionCount = 0;
+      outputInterval = Evaluate(instructions, ref instructionCount, intervals);
+
       nodeIntervals = new Dictionary<ISymbolicExpressionTreeNode, Interval>();
       foreach (var kvp in intervals) {
@@ -119,39 +135,51 @@
       if (outputInterval.IsInfiniteOrUndefined || outputInterval.LowerBound <= outputInterval.UpperBound)
         return outputInterval;
-      else
-        return new Interval(outputInterval.UpperBound, outputInterval.LowerBound);
-    }
-
-
-    private static Instruction[] PrepareInterpreterState(ISymbolicExpressionTree tree, IReadOnlyDictionary<string, Interval> variableRanges) {
+
+      return new Interval(outputInterval.UpperBound, outputInterval.LowerBound);
+    }
+
+
+    private static Instruction[] PrepareInterpreterState(
+      ISymbolicExpressionTree tree,
+      IReadOnlyDictionary<string, Interval> variableRanges) {
       if (variableRanges == null)
         throw new ArgumentNullException("No variablew ranges are present!", nameof(variableRanges));
 
-      //Check if all variables used in the tree are present in the dataset
-      foreach (var variable in tree.IterateNodesPrefix().OfType<VariableTreeNode>().Select(n => n.VariableName).Distinct()) {
-        if (!variableRanges.ContainsKey(variable)) throw new InvalidOperationException($"No ranges for variable {variable} is present");
-      }
-
-      Instruction[] code = SymbolicExpressionTreeCompiler.Compile(tree, OpCodes.MapSymbolToOpCode);
-      foreach (Instruction instr in code.Where(i => i.opCode == OpCodes.Variable)) {
+      // Check if all variables used in the tree are present in the dataset
+      foreach (var variable in tree.IterateNodesPrefix().OfType<VariableTreeNode>().Select(n => n.VariableName)
+                                   .Distinct())
+        if (!variableRanges.ContainsKey(variable))
+          throw new InvalidOperationException($"No ranges for variable {variable} is present");
+
+      var code = SymbolicExpressionTreeCompiler.Compile(tree, OpCodes.MapSymbolToOpCode);
+      foreach (var instr in code.Where(i => i.opCode == OpCodes.Variable)) {
         var variableTreeNode = (VariableTreeNode)instr.dynamicNode;
         instr.data = variableRanges[variableTreeNode.VariableName];
       }
+
       return code;
     }
 
-    private Interval Evaluate(Instruction[] instructions, ref int instructionCounter, IDictionary<ISymbolicExpressionTreeNode, Interval> nodeIntervals = null) {
-      Instruction currentInstr = instructions[instructionCounter];
-      //Use ref parameter, because the tree will be iterated through recursively from the left-side branch to the right side
-      //Update instructionCounter, whenever Evaluate is called
+    // Use ref parameter, because the tree will be iterated through recursively from the left-side branch to the right side
+    // Update instructionCounter, whenever Evaluate is called
+    public static Interval Evaluate(
+    Instruction[] instructions, ref int instructionCounter,
+      IDictionary<ISymbolicExpressionTreeNode, Interval> nodeIntervals = null,
+      IReadOnlyDictionary<string, Interval> variableIntervals = null) {
+      var currentInstr = instructions[instructionCounter];
+
       instructionCounter++;
-      Interval result = null;
+      Interval result;
 
       switch (currentInstr.opCode) {
-        //Variables, Constants, ...
         case OpCodes.Variable: {
             var variableTreeNode = (VariableTreeNode)currentInstr.dynamicNode;
             var weightInterval = new Interval(variableTreeNode.Weight, variableTreeNode.Weight);
-            var variableInterval = (Interval)currentInstr.data;
+
+            Interval variableInterval;
+            if (variableIntervals != null && variableIntervals.ContainsKey(variableTreeNode.VariableName))
+              variableInterval = variableIntervals[variableTreeNode.VariableName];
+            else
+              variableInterval = (Interval)currentInstr.data;
 
             result = Interval.Multiply(variableInterval, weightInterval);
@@ -163,105 +191,118 @@
             break;
           }
-        //Elementary arithmetic rules
         case OpCodes.Add: {
-            result = Evaluate(instructions, ref instructionCounter, nodeIntervals);
-            for (int i = 1; i < currentInstr.nArguments; i++) {
-              var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
+            result = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
+            for (var i = 1; i < currentInstr.nArguments; i++) {
+              var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
               result = Interval.Add(result, argumentInterval);
             }
+
             break;
           }
         case OpCodes.Sub: {
-            result = Evaluate(instructions, ref instructionCounter, nodeIntervals);
+            result = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
             if (currentInstr.nArguments == 1)
               result = Interval.Multiply(new Interval(-1, -1), result);
 
-            for (int i = 1; i < currentInstr.nArguments; i++) {
-              var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
+            for (var i = 1; i < currentInstr.nArguments; i++) {
+              var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
               result = Interval.Subtract(result, argumentInterval);
             }
+
             break;
           }
         case OpCodes.Mul: {
-            result = Evaluate(instructions, ref instructionCounter, nodeIntervals);
-            for (int i = 1; i < currentInstr.nArguments; i++) {
-              var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
+            result = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
+            for (var i = 1; i < currentInstr.nArguments; i++) {
+              var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
               result = Interval.Multiply(result, argumentInterval);
             }
+
             break;
           }
         case OpCodes.Div: {
-            result = Evaluate(instructions, ref instructionCounter, nodeIntervals);
+            result = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
             if (currentInstr.nArguments == 1)
               result = Interval.Divide(new Interval(1, 1), result);
 
-            for (int i = 1; i < currentInstr.nArguments; i++) {
-              var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
+            for (var i = 1; i < currentInstr.nArguments; i++) {
+              var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
               result = Interval.Divide(result, argumentInterval);
             }
-            break;
-          }
-        //Trigonometric functions
+
+            break;
+          }
         case OpCodes.Sin: {
-            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
+            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
             result = Interval.Sine(argumentInterval);
             break;
           }
         case OpCodes.Cos: {
-            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
+            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
             result = Interval.Cosine(argumentInterval);
             break;
           }
         case OpCodes.Tan: {
-            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
+            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
             result = Interval.Tangens(argumentInterval);
             break;
           }
         case OpCodes.Tanh: {
-            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
+            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
             result = Interval.HyperbolicTangent(argumentInterval);
             break;
           }
-        //Exponential functions
         case OpCodes.Log: {
-            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
+            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
             result = Interval.Logarithm(argumentInterval);
             break;
           }
         case OpCodes.Exp: {
-            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
+            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
             result = Interval.Exponential(argumentInterval);
             break;
           }
         case OpCodes.Square: {
-            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
+            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
             result = Interval.Square(argumentInterval);
             break;
           }
         case OpCodes.SquareRoot: {
-            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
+            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
             result = Interval.SquareRoot(argumentInterval);
             break;
           }
         case OpCodes.Cube: {
-            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
+            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
             result = Interval.Cube(argumentInterval);
             break;
           }
         case OpCodes.CubeRoot: {
-            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
+            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
             result = Interval.CubicRoot(argumentInterval);
             break;
           }
+        case OpCodes.Power: {
+            var a = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
+            var b = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
+            // support only integer powers
+            if (b.LowerBound == b.UpperBound && Math.Truncate(b.LowerBound) == b.LowerBound) {
+              result = Interval.Power(a, (int)b.LowerBound);
+            } else {
+              throw new NotSupportedException("Interval is only supported for integer powers");
+            }
+            break;
+          }
+
         case OpCodes.Absolute: {
-            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
+            var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
             result = Interval.Absolute(argumentInterval);
             break;
           }
         case OpCodes.AnalyticQuotient: {
-            result = Evaluate(instructions, ref instructionCounter, nodeIntervals);
-            for (var i = 1; i < currentInstr.nArguments; i++) {
-              var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals);
-              result = Interval.AnalyticalQuotient(result, argumentInterval);
+            result = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
+            for (var i = 1; i < currentInstr.nArguments; i++) {
+              var argumentInterval = Evaluate(instructions, ref instructionCounter, nodeIntervals, variableIntervals);
+              result = Interval.AnalyticQuotient(result, argumentInterval);
             }
 
@@ -272,5 +313,5 @@
       }
 
-      if (nodeIntervals != null)
+      if (!(nodeIntervals == null || nodeIntervals.ContainsKey(currentInstr.dynamicNode)))
         nodeIntervals.Add(currentInstr.dynamicNode, result);
 
@@ -278,9 +319,9 @@
     }
 
+
     public static bool IsCompatible(ISymbolicExpressionTree tree) {
-      var containsUnknownSyumbol = (
-        from n in tree.Root.GetSubtree(0).IterateNodesPrefix()
-        where
-          !(n.Symbol is Problems.DataAnalysis.Symbolic.Variable) &&
+      foreach (var n in tree.Root.GetSubtree(0).IterateNodesPrefix()) {
+        if (
+          !(n.Symbol is Variable) &&
           !(n.Symbol is Constant) &&
           !(n.Symbol is StartSymbol) &&
@@ -292,4 +333,5 @@
           !(n.Symbol is Cosine) &&
           !(n.Symbol is Tangent) &&
+          !(n.Symbol is HyperbolicTangent) &&
           !(n.Symbol is Logarithm) &&
           !(n.Symbol is Exponential) &&
@@ -298,8 +340,15 @@
           !(n.Symbol is Cube) &&
           !(n.Symbol is CubeRoot) &&
+          !(n.Symbol is Power) &&
           !(n.Symbol is Absolute) &&
-          !(n.Symbol is AnalyticQuotient)
-        select n).Any();
-      return !containsUnknownSyumbol;
+          !(n.Symbol is AnalyticQuotient)) return false;
+
+        else if (n.Symbol is Power) {
+          // only integer exponents are supported
+          var exp = n.GetSubtree(1) as ConstantTreeNode;
+          if (exp == null || exp.Value != Math.Truncate(exp.Value)) return false;
+        }
+      }
+      return true;
     }
   }
Index: branches/2521_ProblemRefactoring/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/OpCodes.cs
===================================================================
--- branches/2521_ProblemRefactoring/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/OpCodes.cs	(revision 17586)
+++ branches/2521_ProblemRefactoring/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/OpCodes.cs	(revision 18086)
@@ -144,5 +144,5 @@
       { typeof(Cosine), OpCodes.Cos },
       { typeof(Tangent), OpCodes.Tan },
-      { typeof (HyperbolicTangent), OpCodes.Tanh},
+      { typeof(HyperbolicTangent), OpCodes.Tanh},
       { typeof(Logarithm), OpCodes.Log },
       { typeof(Exponential), OpCodes.Exp },
Index: branches/2521_ProblemRefactoring/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeBatchInterpreter.cs
===================================================================
--- branches/2521_ProblemRefactoring/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeBatchInterpreter.cs	(revision 17586)
+++ branches/2521_ProblemRefactoring/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeBatchInterpreter.cs	(revision 18086)
@@ -222,5 +222,5 @@
 
     private double[] GetValues(ISymbolicExpressionTree tree, IDataset dataset, int[] rows) {
-      if (cachedData == null || cachedDataset != dataset) {
+      if (cachedData == null || cachedDataset != dataset || cachedDataset is ModifiableDataset) {
         InitCache(dataset);
       }
Index: branches/2521_ProblemRefactoring/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeNativeInterpreter.cs
===================================================================
--- branches/2521_ProblemRefactoring/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeNativeInterpreter.cs	(revision 17586)
+++ branches/2521_ProblemRefactoring/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/SymbolicDataAnalysisExpressionTreeNativeInterpreter.cs	(revision 18086)
@@ -127,5 +127,5 @@
       if (!rows.Any()) return Enumerable.Empty<double>();
 
-      if (cachedData == null || cachedDataset != dataset) {
+      if (cachedData == null || cachedDataset != dataset || cachedDataset is ModifiableDataset) {
         InitCache(dataset);
       }
