Index: branches/HeuristicLab.TimeSeries/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis/3.4/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis-3.4.csproj
===================================================================
--- branches/HeuristicLab.TimeSeries/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis/3.4/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis-3.4.csproj	(revision 7886)
+++ branches/HeuristicLab.TimeSeries/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis/3.4/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis-3.4.csproj	(revision 7989)
@@ -123,4 +123,5 @@
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="Interfaces\ISymbolicTimeSeriesPrognogisExpressionTreeInterpreter.cs" />
     <Compile Include="Interfaces\ISymbolicTimeSeriesPrognosisInterpreterOperator.cs" />
     <Compile Include="Interfaces\ISymbolicTimeSeriesPrognosisEvaluator.cs" />
@@ -137,4 +138,5 @@
     <Compile Include="SingleObjective\SymbolicTimeSeriesPrognosisSingleObjectiveTrainingBestSolutionAnalyzer.cs" />
     <Compile Include="SingleObjective\SymbolicTimeSeriesPrognosisSingleObjectiveValidationBestSolutionAnalyzer.cs" />
+    <Compile Include="SymbolicTimeSeriesPrognosisExpressionTreeInterpreter.cs" />
     <Compile Include="SymbolicTimeSeriesPrognosisModel.cs" />
     <Compile Include="SymbolicTimeSeriesPrognosisSolution.cs" />
Index: branches/HeuristicLab.TimeSeries/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis/3.4/Interfaces/ISymbolicTimeSeriesPrognogisExpressionTreeInterpreter.cs
===================================================================
--- branches/HeuristicLab.TimeSeries/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis/3.4/Interfaces/ISymbolicTimeSeriesPrognogisExpressionTreeInterpreter.cs	(revision 7989)
+++ branches/HeuristicLab.TimeSeries/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis/3.4/Interfaces/ISymbolicTimeSeriesPrognogisExpressionTreeInterpreter.cs	(revision 7989)
@@ -0,0 +1,30 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 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.Encodings.SymbolicExpressionTreeEncoding;
+
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
+  public interface ISymbolicTimeSeriesPrognosisExpressionTreeInterpreter : ISymbolicDataAnalysisExpressionTreeInterpreter {
+    string TargetVariable { get; set; }
+    IEnumerable<IEnumerable<double>> GetSymbolicExpressionTreeValues(ISymbolicExpressionTree tree, Dataset dataset, IEnumerable<int> rows, int horizon);
+  }
+}
Index: branches/HeuristicLab.TimeSeries/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis/3.4/SingleObjective/SymbolicTimeSeriesPrognosisSingleObjectiveEvaluator.cs
===================================================================
--- branches/HeuristicLab.TimeSeries/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis/3.4/SingleObjective/SymbolicTimeSeriesPrognosisSingleObjectiveEvaluator.cs	(revision 7886)
+++ branches/HeuristicLab.TimeSeries/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis/3.4/SingleObjective/SymbolicTimeSeriesPrognosisSingleObjectiveEvaluator.cs	(revision 7989)
@@ -21,4 +21,6 @@
 
 
+using System;
+using System.Collections.Generic;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
@@ -27,7 +29,16 @@
 using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
 namespace HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis {
+  [StorableClass]
   public abstract class SymbolicTimeSeriesPrognosisSingleObjectiveEvaluator : SymbolicDataAnalysisSingleObjectiveEvaluator<ITimeSeriesPrognosisProblemData>, ISymbolicTimeSeriesPrognosisSingleObjectiveEvaluator {
     private const string HorizonParameterName = "Horizon";
+    private const string ApplyLinearScalingParameterName = "ApplyLinearScaling";
 
+    public IFixedValueParameter<BoolValue> ApplyLinearScalingParameter {
+      get { return (IFixedValueParameter<BoolValue>)Parameters[ApplyLinearScalingParameterName]; }
+    }
+    public bool ApplyLinearScaling {
+      get { return ApplyLinearScalingParameter.Value.Value; }
+      set { ApplyLinearScalingParameter.Value.Value = value; }
+    }
     public IValueLookupParameter<IntValue> HorizonParameter {
       get { return (IValueLookupParameter<IntValue>)Parameters[HorizonParameterName]; }
@@ -42,5 +53,43 @@
     protected SymbolicTimeSeriesPrognosisSingleObjectiveEvaluator()
       : base() {
+      Parameters.Add(new FixedValueParameter<BoolValue>(ApplyLinearScalingParameterName, "Flag that indicates if the individual should be linearly scaled before evaluating.", new BoolValue(true)));
       Parameters.Add(new ValueLookupParameter<IntValue>(HorizonParameterName, "The time interval for which the prognosis should be calculated.", new IntValue(1)));
+      ApplyLinearScalingParameter.Hidden = true;
+    }
+
+
+    [ThreadStatic]
+    private static double[] cache;
+    protected static void CalculateWithScaling(IEnumerable<double> targetValues, IEnumerable<double> estimatedValues, IOnlineCalculator calculator, int maxRows) {
+      if (cache == null || cache.GetLength(0) < maxRows) {
+        cache = new double[maxRows];
+      }
+
+      //calculate linear scaling
+      //the static methods of the calculator could not be used as it performs a check if the enumerators have an equal amount of elements
+      //this is not true if the cache is used
+      int i = 0;
+      var linearScalingCalculator = new OnlineLinearScalingParameterCalculator();
+      var targetValuesEnumerator = targetValues.GetEnumerator();
+      var estimatedValuesEnumerator = estimatedValues.GetEnumerator();
+      while (targetValuesEnumerator.MoveNext() && estimatedValuesEnumerator.MoveNext()) {
+        double target = targetValuesEnumerator.Current;
+        double estimated = estimatedValuesEnumerator.Current;
+        linearScalingCalculator.Add(estimated, target);
+        cache[i] = estimated;
+        i++;
+      }
+      double alpha = linearScalingCalculator.Alpha;
+      double beta = linearScalingCalculator.Beta;
+
+      //calculate the quality by using the passed online calculator
+      targetValuesEnumerator = targetValues.GetEnumerator();
+      i = 0;
+      while (targetValuesEnumerator.MoveNext()) {
+        double target = targetValuesEnumerator.Current;
+        double estimated = cache[i] * beta + alpha;
+        calculator.Add(target, estimated);
+        i++;
+      }
     }
   }
Index: branches/HeuristicLab.TimeSeries/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis/3.4/SingleObjective/SymbolicTimeSeriesPrognosisSingleObjectiveMeanSquaredErrorEvaluator.cs
===================================================================
--- branches/HeuristicLab.TimeSeries/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis/3.4/SingleObjective/SymbolicTimeSeriesPrognosisSingleObjectiveMeanSquaredErrorEvaluator.cs	(revision 7886)
+++ branches/HeuristicLab.TimeSeries/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis/3.4/SingleObjective/SymbolicTimeSeriesPrognosisSingleObjectiveMeanSquaredErrorEvaluator.cs	(revision 7989)
@@ -22,5 +22,4 @@
 using System;
 using System.Collections.Generic;
-using System.Drawing.Printing;
 using System.Linq;
 using HeuristicLab.Common;
@@ -51,9 +50,10 @@
       IEnumerable<int> rows = GenerateRowsToEvaluate();
 
-      double quality = Calculate(SymbolicDataAnalysisTreeInterpreterParameter.ActualValue,
-        solution,
+      var interpreter = (ISymbolicTimeSeriesPrognosisExpressionTreeInterpreter)SymbolicDataAnalysisTreeInterpreterParameter.ActualValue;
+
+      double quality = Calculate(interpreter, solution,
         EstimationLimitsParameter.ActualValue.Lower, EstimationLimitsParameter.ActualValue.Upper,
         ProblemDataParameter.ActualValue,
-        rows, HorizonParameter.ActualValue.Value);
+        rows, HorizonParameter.ActualValue.Value, ApplyLinearScaling);
       QualityParameter.ActualValue = new DoubleValue(quality);
 
@@ -61,105 +61,23 @@
     }
 
-    public static double Calculate(ISymbolicTimeSeriesPrognosisExpressionTreeInterpreter interpreter, ISymbolicExpressionTree solution, double lowerEstimationLimit, double upperEstimationLimit, ITimeSeriesPrognosisProblemData problemData, IEnumerable<int> rows, int horizon) {
-      double[] alpha;
-      double[] beta;
-      DetermineScalingFactors(solution, problemData, interpreter, rows, out alpha, out beta);
-      var scaledSolution = Scale(solution, alpha, beta);
-      string[] targetVariables = problemData.TargetVariables.ToArray();
-      var meanSquaredErrorCalculators = Enumerable.Range(0, problemData.TargetVariables.Count())
-        .Select(i => new OnlineMeanSquaredErrorCalculator()).ToArray();
+    public static double Calculate(ISymbolicTimeSeriesPrognosisExpressionTreeInterpreter interpreter, ISymbolicExpressionTree solution, double lowerEstimationLimit, double upperEstimationLimit, ITimeSeriesPrognosisProblemData problemData, IEnumerable<int> rows, int horizon, bool applyLinearScaling) {
+      IEnumerable<double> targetValues = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, rows.SelectMany(r => Enumerable.Range(r, horizon)));
+      IEnumerable<double> estimatedValues = interpreter.GetSymbolicExpressionTreeValues(solution, problemData.Dataset, rows, horizon).SelectMany(x => x);
+      IEnumerable<double> boundedEstimatedValues = estimatedValues.LimitToRange(lowerEstimationLimit, upperEstimationLimit);
+      OnlineCalculatorError errorState;
 
-      var allContinuationsEnumerator = interpreter.GetSymbolicExpressionTreeValues(scaledSolution, problemData.Dataset,
-                                                                                  targetVariables,
-                                                                                  rows, horizon).GetEnumerator();
-      allContinuationsEnumerator.MoveNext();
-      // foreach row
-      foreach (var row in rows) {
-        // foreach horizon
-        for (int h = 0; h < horizon; h++) {
-          // foreach component
-          for (int i = 0; i < meanSquaredErrorCalculators.Length; i++) {
-            double e = Math.Min(upperEstimationLimit, Math.Max(lowerEstimationLimit, allContinuationsEnumerator.Current));
-            meanSquaredErrorCalculators[i].Add(problemData.Dataset.GetDoubleValue(targetVariables[i], row + h), e);
-            if (meanSquaredErrorCalculators[i].ErrorState == OnlineCalculatorError.InvalidValueAdded)
-              return double.MaxValue;
-            allContinuationsEnumerator.MoveNext();
-          }
-        }
-      }
-      var meanCalculator = new OnlineMeanAndVarianceCalculator();
-      foreach (var calc in meanSquaredErrorCalculators) {
-        if (calc.ErrorState != OnlineCalculatorError.None) return double.MaxValue;
-        meanCalculator.Add(calc.MeanSquaredError);
-      }
+      double mse;
+      if (applyLinearScaling) {
+        var mseCalculator = new OnlineMeanSquaredErrorCalculator();
+        CalculateWithScaling(targetValues, boundedEstimatedValues, mseCalculator, problemData.Dataset.Rows);
+        errorState = mseCalculator.ErrorState;
+        mse = mseCalculator.MeanSquaredError;
+      } else
+        mse = OnlineMeanSquaredErrorCalculator.Calculate(targetValues, boundedEstimatedValues, out errorState);
 
-      return meanCalculator.MeanErrorState == OnlineCalculatorError.None ? meanCalculator.Mean : double.MaxValue;
+      if (errorState != OnlineCalculatorError.None) return Double.NaN;
+      else return mse;
     }
 
-    private static ISymbolicExpressionTree Scale(ISymbolicExpressionTree solution, double[] alpha, double[] beta) {
-      var clone = (ISymbolicExpressionTree)solution.Clone();
-      int n = alpha.Length;
-      for (int i = 0; i < n; i++) {
-        var parent = clone.Root.GetSubtree(0);
-        var rpb = clone.Root.GetSubtree(0).GetSubtree(i);
-        var scaledRpb = MakeSum(
-          MakeProduct(rpb,
-            MakeConstant(beta[i], clone.Root.Grammar), clone.Root.Grammar),
-            MakeConstant(alpha[i], clone.Root.Grammar), clone.Root.Grammar);
-        parent.RemoveSubtree(i);
-        parent.InsertSubtree(i, scaledRpb);
-      }
-      return clone;
-    }
-
-    private static ISymbolicExpressionTreeNode MakeSum(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b, ISymbolicExpressionTreeGrammar grammar) {
-      var sum = grammar.Symbols.Where(s => s is Addition).First().CreateTreeNode();
-      sum.AddSubtree(a);
-      sum.AddSubtree(b);
-      return sum;
-    }
-
-    private static ISymbolicExpressionTreeNode MakeProduct(ISymbolicExpressionTreeNode a, ISymbolicExpressionTreeNode b, ISymbolicExpressionTreeGrammar grammar) {
-      var prod = grammar.Symbols.Where(s => s is Multiplication).First().CreateTreeNode();
-      prod.AddSubtree(a);
-      prod.AddSubtree(b);
-      return prod;
-    }
-
-    private static ISymbolicExpressionTreeNode MakeConstant(double c, ISymbolicExpressionTreeGrammar grammar) {
-      var node = (ConstantTreeNode)grammar.Symbols.Where(s => s is Constant).First().CreateTreeNode();
-      node.Value = c;
-      return node;
-    }
-
-    private static void DetermineScalingFactors(ISymbolicExpressionTree solution, ITimeSeriesPrognosisProblemData problemData, ISymbolicTimeSeriesPrognosisExpressionTreeInterpreter interpreter, IEnumerable<int> rows, out double[] alpha, out double[] beta) {
-      string[] targetVariables = problemData.TargetVariables.ToArray();
-      int nComponents = targetVariables.Length;
-      alpha = new double[nComponents];
-      beta = new double[nComponents];
-      var oneStepPredictionsEnumerator = interpreter.GetSymbolicExpressionTreeValues(solution, problemData.Dataset, targetVariables, rows).GetEnumerator();
-      var scalingParameterCalculators =
-        Enumerable.Repeat(0, nComponents).Select(x => new OnlineLinearScalingParameterCalculator()).ToArray();
-      var targetValues = problemData.Dataset.GetVectorEnumerable(targetVariables, rows);
-      var targetValueEnumerator = targetValues.GetEnumerator();
-
-      var more = oneStepPredictionsEnumerator.MoveNext() & targetValueEnumerator.MoveNext();
-      while (more) {
-        for (int i = 0; i < nComponents; i++) {
-          scalingParameterCalculators[i].Add(oneStepPredictionsEnumerator.Current, targetValueEnumerator.Current);
-          more = oneStepPredictionsEnumerator.MoveNext() & targetValueEnumerator.MoveNext();
-        }
-      }
-
-      for (int i = 0; i < nComponents; i++) {
-        if (scalingParameterCalculators[i].ErrorState == OnlineCalculatorError.None) {
-          alpha[i] = scalingParameterCalculators[i].Alpha;
-          beta[i] = scalingParameterCalculators[i].Beta;
-        } else {
-          alpha[i] = 0.0;
-          beta[i] = 1.0;
-        }
-      }
-    }
 
     public override double Evaluate(IExecutionContext context, ISymbolicExpressionTree tree, ITimeSeriesPrognosisProblemData problemData, IEnumerable<int> rows) {
@@ -168,5 +86,5 @@
       HorizonParameter.ExecutionContext = context;
 
-      double mse = Calculate(SymbolicDataAnalysisTreeInterpreterParameter.ActualValue, tree, EstimationLimitsParameter.ActualValue.Lower, EstimationLimitsParameter.ActualValue.Upper, problemData, rows, HorizonParameter.ActualValue.Value);
+      double mse = Calculate(SymbolicDataAnalysisTreeInterpreterParameter.ActualValue as ISymbolicTimeSeriesPrognosisExpressionTreeInterpreter, tree, EstimationLimitsParameter.ActualValue.Lower, EstimationLimitsParameter.ActualValue.Upper, problemData, rows, HorizonParameter.ActualValue.Value, ApplyLinearScaling);
 
       HorizonParameter.ExecutionContext = null;
Index: branches/HeuristicLab.TimeSeries/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis/3.4/SingleObjective/SymbolicTimeSeriesPrognosisSingleObjectiveProblem.cs
===================================================================
--- branches/HeuristicLab.TimeSeries/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis/3.4/SingleObjective/SymbolicTimeSeriesPrognosisSingleObjectiveProblem.cs	(revision 7886)
+++ branches/HeuristicLab.TimeSeries/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis/3.4/SingleObjective/SymbolicTimeSeriesPrognosisSingleObjectiveProblem.cs	(revision 7989)
@@ -54,5 +54,4 @@
       : base(new TimeSeriesPrognosisProblemData(), new SymbolicTimeSeriesPrognosisSingleObjectiveMeanSquaredErrorEvaluator(), new SymbolicDataAnalysisExpressionTreeCreator()) {
       Parameters.Add(new FixedValueParameter<DoubleLimit>(EstimationLimitsParameterName, EstimationLimitsParameterDescription));
-
       EstimationLimitsParameter.Hidden = true;
 
@@ -61,6 +60,9 @@
       MaximumSymbolicExpressionTreeLength.Value = InitialMaximumTreeLength;
 
+      var interpeter = new SymbolicTimeSeriesPrognosisExpressionTreeInterpreter();
+      interpeter.TargetVariable = ProblemData.TargetVariable;
+      SymbolicExpressionTreeInterpreter = interpeter;
+
       SymbolicExpressionTreeGrammarParameter.ValueChanged += (o, e) => ConfigureGrammarSymbols();
-
       ConfigureGrammarSymbols();
 
@@ -88,5 +90,10 @@
     protected override void OnProblemDataChanged() {
       base.OnProblemDataChanged();
+      var interpreter = SymbolicExpressionTreeInterpreter as ISymbolicTimeSeriesPrognosisExpressionTreeInterpreter;
+      if (interpreter != null) {
+        interpreter.TargetVariable = ProblemData.TargetVariable;
+      }
       UpdateEstimationLimits();
+
     }
 
@@ -107,5 +114,4 @@
       }
     }
-
   }
 }
Index: branches/HeuristicLab.TimeSeries/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis/3.4/SingleObjective/SymbolicTimeSeriesPrognosisSingleObjectiveTrainingBestSolutionAnalyzer.cs
===================================================================
--- branches/HeuristicLab.TimeSeries/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis/3.4/SingleObjective/SymbolicTimeSeriesPrognosisSingleObjectiveTrainingBestSolutionAnalyzer.cs	(revision 7886)
+++ branches/HeuristicLab.TimeSeries/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis/3.4/SingleObjective/SymbolicTimeSeriesPrognosisSingleObjectiveTrainingBestSolutionAnalyzer.cs	(revision 7989)
@@ -20,5 +20,4 @@
 #endregion
 
-using System.Linq;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
@@ -76,5 +75,5 @@
 
     protected override ISymbolicTimeSeriesPrognosisSolution CreateSolution(ISymbolicExpressionTree bestTree, double bestQuality) {
-      var model = new SymbolicTimeSeriesPrognosisModel((ISymbolicExpressionTree)bestTree.Clone(), SymbolicDataAnalysisTreeInterpreterParameter.ActualValue, ProblemDataParameter.ActualValue.TargetVariables.ToArray(), EstimationLimitsParameter.ActualValue.Lower, EstimationLimitsParameter.ActualValue.Upper);
+      var model = new SymbolicTimeSeriesPrognosisModel((ISymbolicExpressionTree)bestTree.Clone(), SymbolicDataAnalysisTreeInterpreterParameter.ActualValue as ISymbolicTimeSeriesPrognosisExpressionTreeInterpreter, EstimationLimitsParameter.ActualValue.Lower, EstimationLimitsParameter.ActualValue.Upper);
       if (ApplyLinearScaling.Value)
         SymbolicTimeSeriesPrognosisModel.Scale(model, ProblemDataParameter.ActualValue);
Index: branches/HeuristicLab.TimeSeries/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis/3.4/SingleObjective/SymbolicTimeSeriesPrognosisSingleObjectiveValidationBestSolutionAnalyzer.cs
===================================================================
--- branches/HeuristicLab.TimeSeries/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis/3.4/SingleObjective/SymbolicTimeSeriesPrognosisSingleObjectiveValidationBestSolutionAnalyzer.cs	(revision 7886)
+++ branches/HeuristicLab.TimeSeries/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis/3.4/SingleObjective/SymbolicTimeSeriesPrognosisSingleObjectiveValidationBestSolutionAnalyzer.cs	(revision 7989)
@@ -20,5 +20,4 @@
 #endregion
 
-using System.Linq;
 using HeuristicLab.Common;
 using HeuristicLab.Core;
@@ -65,5 +64,5 @@
 
     protected override ISymbolicTimeSeriesPrognosisSolution CreateSolution(ISymbolicExpressionTree bestTree, double bestQuality) {
-      var model = new SymbolicTimeSeriesPrognosisModel((ISymbolicExpressionTree)bestTree.Clone(), SymbolicDataAnalysisTreeInterpreterParameter.ActualValue, ProblemDataParameter.ActualValue.TargetVariables.ToArray(), EstimationLimitsParameter.ActualValue.Lower, EstimationLimitsParameter.ActualValue.Upper);
+      var model = new SymbolicTimeSeriesPrognosisModel((ISymbolicExpressionTree)bestTree.Clone(), SymbolicDataAnalysisTreeInterpreterParameter.ActualValue as ISymbolicTimeSeriesPrognosisExpressionTreeInterpreter, EstimationLimitsParameter.ActualValue.Lower, EstimationLimitsParameter.ActualValue.Upper);
       if (ApplyLinearScaling.Value)
         SymbolicTimeSeriesPrognosisModel.Scale(model, ProblemDataParameter.ActualValue);
Index: branches/HeuristicLab.TimeSeries/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis/3.4/SymbolicTimeSeriesPrognosisExpressionTreeInterpreter.cs
===================================================================
--- branches/HeuristicLab.TimeSeries/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis/3.4/SymbolicTimeSeriesPrognosisExpressionTreeInterpreter.cs	(revision 7989)
+++ branches/HeuristicLab.TimeSeries/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis/3.4/SymbolicTimeSeriesPrognosisExpressionTreeInterpreter.cs	(revision 7989)
@@ -0,0 +1,136 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2011 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.TimeSeriesPrognosis {
+  [StorableClass]
+  [Item("SymbolicTimeSeriesPrognosisInterpreter", "Interpreter for symbolic expression trees including automatically defined functions.")]
+  public sealed class SymbolicTimeSeriesPrognosisExpressionTreeInterpreter : SymbolicDataAnalysisExpressionTreeInterpreter, ISymbolicTimeSeriesPrognosisExpressionTreeInterpreter {
+    private const string TargetVariableParameterName = "TargetVariable";
+
+    public IFixedValueParameter<StringValue> TargetVariableParameter {
+      get { return (IFixedValueParameter<StringValue>)Parameters[TargetVariableParameterName]; }
+    }
+
+    public string TargetVariable {
+      get { return TargetVariableParameter.Value.Value; }
+      set { TargetVariableParameter.Value.Value = value; }
+    }
+
+    [ThreadStatic]
+    private static double[] targetVariableCache;
+    [ThreadStatic]
+    private static List<int> invalidateCacheIndexes;
+
+    [StorableConstructor]
+    private SymbolicTimeSeriesPrognosisExpressionTreeInterpreter(bool deserializing) : base(deserializing) { }
+    private SymbolicTimeSeriesPrognosisExpressionTreeInterpreter(SymbolicTimeSeriesPrognosisExpressionTreeInterpreter original, Cloner cloner) : base(original, cloner) { }
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new SymbolicTimeSeriesPrognosisExpressionTreeInterpreter(this, cloner);
+    }
+
+    public SymbolicTimeSeriesPrognosisExpressionTreeInterpreter()
+      : base("SymbolicTimeSeriesPrognosisInterpreter", "Interpreter for symbolic expression trees including automatically defined functions.") {
+      Parameters.Add(new FixedValueParameter<StringValue>(TargetVariableParameterName));
+      TargetVariableParameter.Hidden = true;
+    }
+
+    // for each row several (=#horizon) future predictions
+    public IEnumerable<IEnumerable<double>> GetSymbolicExpressionTreeValues(ISymbolicExpressionTree tree, Dataset dataset, IEnumerable<int> rows, int horizon) {
+      return GetSymbolicExpressionTreeValues(tree, dataset, rows, rows.Select(row => horizon));
+    }
+
+    public IEnumerable<IEnumerable<double>> GetSymbolicExpressionTreeValues(ISymbolicExpressionTree tree, Dataset dataset, IEnumerable<int> rows, IEnumerable<int> horizons) {
+      if (CheckExpressionsWithIntervalArithmetic.Value)
+        throw new NotSupportedException("Interval arithmetic is not yet supported in the symbolic data analysis interpreter.");
+      if (targetVariableCache == null || targetVariableCache.GetLength(0) < dataset.Rows)
+        targetVariableCache = dataset.GetDoubleValues(TargetVariable).ToArray();
+      if (invalidateCacheIndexes == null)
+        invalidateCacheIndexes = new List<int>(10);
+
+      string targetVariable = TargetVariable;
+      EvaluatedSolutions.Value++; // increment the evaluated solutions counter
+      var state = PrepareInterpreterState(tree, dataset, targetVariableCache);
+      var rowsEnumerator = rows.GetEnumerator();
+      var horizonsEnumerator = horizons.GetEnumerator();
+
+      // produce a n-step forecast for all rows
+      while (rowsEnumerator.MoveNext() & horizonsEnumerator.MoveNext()) {
+        int row = rowsEnumerator.Current;
+        int horizon = horizonsEnumerator.Current;
+
+        double[] vProgs = new double[horizon];
+        for (int i = 0; i < horizon; i++) {
+          int localRow = i + row; // create a local variable for the ref parameter
+          vProgs[i] = Evaluate(dataset, ref localRow, state);
+          targetVariableCache[localRow] = vProgs[i];
+          invalidateCacheIndexes.Add(localRow);
+          state.Reset();
+        }
+
+        yield return vProgs;
+
+        int j = 0;
+        foreach (var targetValue in dataset.GetDoubleValues(TargetVariable, invalidateCacheIndexes)) {
+          targetVariableCache[invalidateCacheIndexes[j]] = targetValue;
+          j++;
+        }
+        invalidateCacheIndexes.Clear();
+      }
+
+      if (rowsEnumerator.MoveNext() || horizonsEnumerator.MoveNext())
+        throw new ArgumentException("Number of elements in rows and horizon enumerations doesn't match.");
+    }
+
+    private InterpreterState PrepareInterpreterState(ISymbolicExpressionTree tree, Dataset dataset, double[] targetVariableCache) {
+      Instruction[] code = SymbolicExpressionTreeCompiler.Compile(tree, OpCodes.MapSymbolToOpCode);
+      int necessaryArgStackSize = 0;
+      foreach (Instruction instr in code) {
+        if (instr.opCode == OpCodes.Variable) {
+          var variableTreeNode = (VariableTreeNode)instr.dynamicNode;
+          if (variableTreeNode.VariableName == TargetVariable)
+            instr.iArg0 = targetVariableCache;
+          else
+            instr.iArg0 = dataset.GetReadOnlyDoubleValues(variableTreeNode.VariableName);
+        } else if (instr.opCode == OpCodes.LagVariable) {
+          var laggedVariableTreeNode = (LaggedVariableTreeNode)instr.dynamicNode;
+          instr.iArg0 = dataset.GetReadOnlyDoubleValues(laggedVariableTreeNode.VariableName);
+        } else if (instr.opCode == OpCodes.VariableCondition) {
+          var variableConditionTreeNode = (VariableConditionTreeNode)instr.dynamicNode;
+          instr.iArg0 = dataset.GetReadOnlyDoubleValues(variableConditionTreeNode.VariableName);
+        } else if (instr.opCode == OpCodes.Call) {
+          necessaryArgStackSize += instr.nArguments + 1;
+        }
+      }
+
+      return new InterpreterState(code, necessaryArgStackSize);
+    }
+  }
+}
Index: branches/HeuristicLab.TimeSeries/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis/3.4/SymbolicTimeSeriesPrognosisModel.cs
===================================================================
--- branches/HeuristicLab.TimeSeries/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis/3.4/SymbolicTimeSeriesPrognosisModel.cs	(revision 7886)
+++ branches/HeuristicLab.TimeSeries/HeuristicLab.Problems.DataAnalysis.Symbolic.TimeSeriesPrognosis/3.4/SymbolicTimeSeriesPrognosisModel.cs	(revision 7989)
@@ -20,5 +20,4 @@
 #endregion
 
-using System;
 using System.Collections.Generic;
 using System.Drawing;
@@ -64,8 +63,4 @@
     #endregion
 
-    [Storable]
-    private string[] targetVariables;
-
-
     [StorableConstructor]
     protected SymbolicTimeSeriesPrognosisModel(bool deserializing) : base(deserializing) { }
@@ -74,15 +69,13 @@
       this.symbolicExpressionTree = cloner.Clone(original.symbolicExpressionTree);
       this.interpreter = cloner.Clone(original.interpreter);
-      this.targetVariables = new string[original.targetVariables.Length];
-      Array.Copy(original.targetVariables, this.targetVariables, this.targetVariables.Length);
       this.lowerEstimationLimit = original.lowerEstimationLimit;
       this.upperEstimationLimit = original.upperEstimationLimit;
     }
-    public SymbolicTimeSeriesPrognosisModel(ISymbolicExpressionTree tree, ISymbolicTimeSeriesPrognosisExpressionTreeInterpreter interpreter, IEnumerable<string> targetVariables, double lowerLimit = double.MinValue, double upperLimit = double.MaxValue)
+    public SymbolicTimeSeriesPrognosisModel(ISymbolicExpressionTree tree, ISymbolicTimeSeriesPrognosisExpressionTreeInterpreter interpreter, double lowerLimit = double.MinValue, double upperLimit = double.MaxValue)
       : base() {
       this.name = ItemName;
       this.description = ItemDescription;
       this.symbolicExpressionTree = tree;
-      this.interpreter = interpreter; this.targetVariables = targetVariables.ToArray();
+      this.interpreter = interpreter;
       this.lowerEstimationLimit = lowerLimit;
       this.upperEstimationLimit = upperLimit;
@@ -93,20 +86,7 @@
     }
 
-    public IEnumerable<IEnumerable<IEnumerable<double>>> GetPrognosedValues(Dataset dataset, IEnumerable<int> rows, int horizon) {
-      var enumerator =
-        Interpreter.GetSymbolicExpressionTreeValues(SymbolicExpressionTree, dataset, targetVariables, rows, horizon).
-          GetEnumerator();
-      foreach (var r in rows) {
-        var l = new List<double[]>();
-        for (int h = 0; h < horizon; h++) {
-          double[] components = new double[targetVariables.Length];
-          for (int c = 0; c < components.Length; c++) {
-            enumerator.MoveNext();
-            components[c] = Math.Min(upperEstimationLimit, Math.Max(lowerEstimationLimit, enumerator.Current));
-          }
-          l.Add(components);
-        }
-        yield return l;
-      }
+    public IEnumerable<IEnumerable<double>> GetPrognosedValues(Dataset dataset, IEnumerable<int> rows, int horizon) {
+      var estimatedValues = Interpreter.GetSymbolicExpressionTreeValues(SymbolicExpressionTree, dataset, rows, horizon);
+      return estimatedValues.Select(predictionPerRow => predictionPerRow.LimitToRange(lowerEstimationLimit, upperEstimationLimit));
     }
 
@@ -120,54 +100,39 @@
     public static void Scale(SymbolicTimeSeriesPrognosisModel model, ITimeSeriesPrognosisProblemData problemData) {
       var dataset = problemData.Dataset;
-      var targetVariables = problemData.TargetVariables.ToArray();
+      var targetVariable = problemData.TargetVariable;
       var rows = problemData.TrainingIndizes;
-      var estimatedValuesEnumerator = model.Interpreter.GetSymbolicExpressionTreeValues(model.SymbolicExpressionTree, dataset,
-                                                                              targetVariables,
-                                                                              rows).GetEnumerator();
-      var scalingParameterCalculators =
-        problemData.TargetVariables.Select(v => new OnlineLinearScalingParameterCalculator()).ToArray();
-      var targetValuesEnumerator = problemData.Dataset.GetVectorEnumerable(targetVariables, rows).GetEnumerator();
+      var estimatedValuesEnumerator = model.Interpreter.GetSymbolicExpressionTreeValues(model.SymbolicExpressionTree, dataset, rows);
+      var targetValuesEnumerator = problemData.Dataset.GetDoubleValues(targetVariable, rows);
 
-      var more = targetValuesEnumerator.MoveNext() & estimatedValuesEnumerator.MoveNext();
-      // foreach row
-      while (more) {
-        // foreach component
-        for (int i = 0; i < targetVariables.Length; i++) {
-          scalingParameterCalculators[i].Add(estimatedValuesEnumerator.Current, targetValuesEnumerator.Current);
-          more = estimatedValuesEnumerator.MoveNext() & targetValuesEnumerator.MoveNext();
+      double alpha, beta;
+      OnlineCalculatorError error;
+      OnlineLinearScalingParameterCalculator.Calculate(estimatedValuesEnumerator, targetValuesEnumerator, out alpha, out beta, out error);
+      if (error != OnlineCalculatorError.None) return;
+
+      ConstantTreeNode alphaTreeNode = null;
+      ConstantTreeNode betaTreeNode = null;
+      // check if model has been scaled previously by analyzing the structure of the tree
+      var startNode = model.SymbolicExpressionTree.Root.GetSubtree(0);
+      if (startNode.GetSubtree(0).Symbol is Addition) {
+        var addNode = startNode.GetSubtree(0);
+        if (addNode.SubtreeCount == 2 && addNode.GetSubtree(0).Symbol is Multiplication && addNode.GetSubtree(1).Symbol is Constant) {
+          alphaTreeNode = addNode.GetSubtree(1) as ConstantTreeNode;
+          var mulNode = addNode.GetSubtree(0);
+          if (mulNode.SubtreeCount == 2 && mulNode.GetSubtree(1).Symbol is Constant) {
+            betaTreeNode = mulNode.GetSubtree(1) as ConstantTreeNode;
+          }
         }
       }
-
-      for (int i = 0; i < targetVariables.Count(); i++) {
-        if (scalingParameterCalculators[i].ErrorState != OnlineCalculatorError.None) continue;
-        double alpha = scalingParameterCalculators[i].Alpha;
-        double beta = scalingParameterCalculators[i].Beta;
-        ConstantTreeNode alphaTreeNode = null;
-        ConstantTreeNode betaTreeNode = null;
-        // check if model has been scaled previously by analyzing the structure of the tree
-        var startNode = model.SymbolicExpressionTree.Root.GetSubtree(0);
-        if (startNode.GetSubtree(i).Symbol is Addition) {
-          var addNode = startNode.GetSubtree(i);
-          if (addNode.SubtreeCount == 2 && addNode.GetSubtree(0).Symbol is Multiplication &&
-              addNode.GetSubtree(1).Symbol is Constant) {
-            alphaTreeNode = addNode.GetSubtree(1) as ConstantTreeNode;
-            var mulNode = addNode.GetSubtree(0);
-            if (mulNode.SubtreeCount == 2 && mulNode.GetSubtree(1).Symbol is Constant) {
-              betaTreeNode = mulNode.GetSubtree(1) as ConstantTreeNode;
-            }
-          }
-        }
-        // if tree structure matches the structure necessary for linear scaling then reuse the existing tree nodes
-        if (alphaTreeNode != null && betaTreeNode != null) {
-          betaTreeNode.Value *= beta;
-          alphaTreeNode.Value *= beta;
-          alphaTreeNode.Value += alpha;
-        } else {
-          var mainBranch = startNode.GetSubtree(i);
-          startNode.RemoveSubtree(i);
-          var scaledMainBranch = MakeSum(MakeProduct(mainBranch, beta), alpha);
-          startNode.InsertSubtree(i, scaledMainBranch);
-        }
-      } // foreach
+      // if tree structure matches the structure necessary for linear scaling then reuse the existing tree nodes
+      if (alphaTreeNode != null && betaTreeNode != null) {
+        betaTreeNode.Value *= beta;
+        alphaTreeNode.Value *= beta;
+        alphaTreeNode.Value += alpha;
+      } else {
+        var mainBranch = startNode.GetSubtree(0);
+        startNode.RemoveSubtree(0);
+        var scaledMainBranch = MakeSum(MakeProduct(mainBranch, beta), alpha);
+        startNode.AddSubtree(scaledMainBranch);
+      }
     }
 
