Index: stable/HeuristicLab.Algorithms.DataAnalysis/3.4/HeuristicLab.Algorithms.DataAnalysis-3.4.csproj
===================================================================
--- stable/HeuristicLab.Algorithms.DataAnalysis/3.4/HeuristicLab.Algorithms.DataAnalysis-3.4.csproj	(revision 14999)
+++ stable/HeuristicLab.Algorithms.DataAnalysis/3.4/HeuristicLab.Algorithms.DataAnalysis-3.4.csproj	(revision 15060)
@@ -253,4 +253,20 @@
     <Compile Include="Linear\MultinomialLogitClassificationSolution.cs" />
     <Compile Include="Linear\MultinomialLogitModel.cs" />
+    <Compile Include="MctsSymbolicRegression\Automaton.cs" />
+    <Compile Include="MctsSymbolicRegression\CodeGenerator.cs" />
+    <Compile Include="MctsSymbolicRegression\ConstraintHandler.cs" />
+    <Compile Include="MctsSymbolicRegression\Disassembler.cs" />
+    <Compile Include="MctsSymbolicRegression\ExpressionEvaluator.cs" />
+    <Compile Include="MctsSymbolicRegression\MctsSymbolicRegressionAlgorithm.cs" />
+    <Compile Include="MctsSymbolicRegression\MctsSymbolicRegressionStatic.cs" />
+    <Compile Include="MctsSymbolicRegression\OpCodes.cs" />
+    <Compile Include="MctsSymbolicRegression\Policies\EpsGreedy.cs" />
+    <Compile Include="MctsSymbolicRegression\Policies\UcbTuned.cs" />
+    <Compile Include="MctsSymbolicRegression\Policies\IActionStatistics.cs" />
+    <Compile Include="MctsSymbolicRegression\Policies\IPolicy.cs" />
+    <Compile Include="MctsSymbolicRegression\Policies\PolicyBase.cs" />
+    <Compile Include="MctsSymbolicRegression\Policies\Ucb.cs" />
+    <Compile Include="MctsSymbolicRegression\SymbolicExpressionGenerator.cs" />
+    <Compile Include="MctsSymbolicRegression\Tree.cs" />
     <Compile Include="Nca\Initialization\INcaInitializer.cs" />
     <Compile Include="Nca\Initialization\LdaInitializer.cs" />
Index: stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Automaton.cs
===================================================================
--- stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Automaton.cs	(revision 15060)
+++ stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Automaton.cs	(revision 15060)
@@ -0,0 +1,407 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.IO;
+
+namespace HeuristicLab.Algorithms.DataAnalysis.MctsSymbolicRegression {
+  // this is the core class for generating expressions. 
+  // it represents a finite state automaton, each state transition can be associated with an action (e.g. to produce code).
+  // the automaton determines the possible structures for expressions.
+  // 
+  // to understand this code it is worthwile to generate a graphical visualization of the automaton (see PrintAutomaton).
+  // If the code is compiled in debug mode the automaton produces a Graphviz file into the folder of the application
+  // whenever an instance of the automaton is constructed.
+  //
+  // This class relies on two other classes: 
+  // - CodeGenerator to produce code for a stack-based evaluator and
+  // - ConstraintHandler to restrict the allowed set of expressions. 
+  //
+  // The ConstraintHandler extends the automaton and adds semantic restrictions for expressions produced by the automaton.
+  // 
+  // 
+  internal class Automaton {
+    public const int StateExpr = 1;
+    public const int StateExprEnd = 2;
+    public const int StateTermStart = 3;
+    public const int StateTermEnd = 4;
+    public const int StateFactorStart = 5;
+    public const int StateFactorEnd = 6;
+    public const int StateVariableFactorStart = 7;
+    public const int StateVariableFactorEnd = 8;
+    public const int StateExpFactorStart = 9;
+    public const int StateExpFactorEnd = 10;
+    public const int StateLogFactorStart = 11;
+    public const int StateLogFactorEnd = 12;
+    public const int StateInvFactorStart = 13;
+    public const int StateInvFactorEnd = 14;
+    public const int StateExpFStart = 15;
+    public const int StateExpFEnd = 16;
+    public const int StateLogTStart = 17;
+    public const int StateLogTEnd = 18;
+    public const int StateLogTFStart = 19;
+    public const int StateLogTFEnd = 20;
+    public const int StateInvTStart = 21;
+    public const int StateInvTEnd = 22;
+    public const int StateInvTFStart = 23;
+    public const int StateInvTFEnd = 24;
+    public const int FirstDynamicState = 25;
+    // more states for individual variables are created dynamically
+
+    private const int StartState = StateExpr;
+    public int CurrentState { get; private set; }
+
+    public readonly List<string> stateNames;
+    private List<int>[] followStates;
+    private List<Action>[,] actions; // not every follow state is possible but this representation should be efficient
+    private List<string>[,] actionStrings; // just for printing 
+    private readonly CodeGenerator codeGenerator;
+    private readonly ConstraintHandler constraintHandler;
+
+    public Automaton(double[][] vars, int maxVarsInExpression = 100,
+       bool allowProdOfVars = true,
+       bool allowExp = true,
+       bool allowLog = true,
+       bool allowInv = true,
+       bool allowMultipleTerms = false) {
+      int nVars = vars.Length;
+      stateNames = new List<string>() { string.Empty, "Expr", "ExprEnd", "TermStart", "TermEnd", "FactorStart", "FactorEnd", "VarFactorStart", "VarFactorEnd", "ExpFactorStart", "ExpFactorEnd", "LogFactorStart", "LogFactorEnd", "InvFactorStart", "InvFactorEnd", "ExpFStart", "ExpFEnd", "LogTStart", "LogTEnd", "LogTFStart", "LogTFEnd", "InvTStart", "InvTEnd", "InvTFStart", "InvTFEnd" };
+      codeGenerator = new CodeGenerator();
+      constraintHandler = new ConstraintHandler(maxVarsInExpression);
+      BuildAutomaton(nVars, allowProdOfVars, allowExp, allowLog, allowInv, allowMultipleTerms);
+
+      Reset();
+#if DEBUG
+      PrintAutomaton();
+#endif
+    }
+
+    // reverse notation ops
+    // Expr -> c 0 Term { '+' Term } '+' '*' c '+' 'exit'
+    // Term -> c Fact { '*' Fact } '*'
+    // Fact -> VarFact | ExpFact | LogFact | InvFact
+    // VarFact -> var_1 ... var_n
+    // ExpFact -> 1 ExpF { '*' ExpF } '*' c '*' 'exp' // c must be at end to allow scaling in evaluator
+    // ExpF    -> var_1 ... var_n 
+    // LogFact -> 0 LogT { '+' LogT } '+' c '+' 'log' // c must be at end to allow scaling in evaluator
+    // LogT    -> c LogTF { '*' LogTF } '*' 
+    // LogTF   -> var_1 ... var_n 
+    // InvFact -> 1 InvT { '+' InvT } '+' 'inv'
+    // InvT    -> (var_1 ... var_n) c '*' 
+    private void BuildAutomaton(int nVars,
+      bool allowProdOfVars = true,
+       bool allowExp = true,
+       bool allowLog = true,
+       bool allowInv = true,
+       bool allowMultipleTerms = false) {
+
+      int nStates = FirstDynamicState + 4 * nVars;
+      followStates = new List<int>[nStates];
+      actions = new List<Action>[nStates, nStates];
+      actionStrings = new List<string>[nStates, nStates];
+
+      // Expr -> c 0 Term { '+' Term } '+' '*' c '+' 'exit'
+      AddTransition(StateExpr, StateTermStart, () => {
+        codeGenerator.Reset();
+        codeGenerator.Emit1(OpCodes.LoadParamN);
+        codeGenerator.Emit1(OpCodes.LoadConst0);
+        constraintHandler.Reset();
+      }, "c 0, Reset");
+      AddTransition(StateTermEnd, StateExprEnd, () => {
+        codeGenerator.Emit1(OpCodes.Add);
+        codeGenerator.Emit1(OpCodes.Mul);
+        codeGenerator.Emit1(OpCodes.LoadParamN);
+        codeGenerator.Emit1(OpCodes.Add);
+        codeGenerator.Emit1(OpCodes.Exit);
+      }, "+*c+ exit");
+      if (allowMultipleTerms)
+        AddTransition(StateTermEnd, StateTermStart, () => {
+          codeGenerator.Emit1(OpCodes.Add);
+        }, "+");
+
+      // Term -> c Fact { '*' Fact } '*'
+      AddTransition(StateTermStart, StateFactorStart,
+        () => {
+          codeGenerator.Emit1(OpCodes.LoadParamN);
+          constraintHandler.StartTerm();
+        },
+        "c, StartTerm");
+      AddTransition(StateFactorEnd, StateTermEnd,
+        () => {
+          codeGenerator.Emit1(OpCodes.Mul);
+          constraintHandler.EndTerm();
+        },
+        "*, EndTerm");
+
+      AddTransition(StateFactorEnd, StateFactorStart,
+        () => { codeGenerator.Emit1(OpCodes.Mul); },
+        "*");
+
+
+      // Fact -> VarFact | ExpFact | LogFact | InvFact
+      if (allowProdOfVars)
+        AddTransition(StateFactorStart, StateVariableFactorStart, () => {
+          constraintHandler.StartFactor(StateVariableFactorStart);
+        }, "StartFactor");
+      if (allowExp)
+        AddTransition(StateFactorStart, StateExpFactorStart, () => {
+          constraintHandler.StartFactor(StateExpFactorStart);
+        }, "StartFactor");
+      if (allowLog)
+        AddTransition(StateFactorStart, StateLogFactorStart, () => {
+          constraintHandler.StartFactor(StateLogFactorStart);
+        }, "StartFactor");
+      if (allowInv)
+        AddTransition(StateFactorStart, StateInvFactorStart, () => {
+          constraintHandler.StartFactor(StateInvFactorStart);
+        }, "StartFactor");
+      AddTransition(StateVariableFactorEnd, StateFactorEnd, () => { constraintHandler.EndFactor(); }, "EndFactor");
+      AddTransition(StateExpFactorEnd, StateFactorEnd, () => { constraintHandler.EndFactor(); }, "EndFactor");
+      AddTransition(StateLogFactorEnd, StateFactorEnd, () => { constraintHandler.EndFactor(); }, "EndFactor");
+      AddTransition(StateInvFactorEnd, StateFactorEnd, () => { constraintHandler.EndFactor(); }, "EndFactor");
+
+      // VarFact -> var_1 ... var_n
+      // add dynamic states for each variable 
+      int curDynVarState = FirstDynamicState;
+      for (int i = 0; i < nVars; i++) {
+        short varIdx = (short)i;
+        var varState = curDynVarState;
+        stateNames.Add("var_1");
+        AddTransition(StateVariableFactorStart, curDynVarState,
+          () => {
+            codeGenerator.Emit2(OpCodes.LoadVar, varIdx);
+            constraintHandler.AddVarToCurrentFactor(varState);
+          },
+          "var_" + varIdx + ", AddVar");
+        AddTransition(curDynVarState, StateVariableFactorEnd);
+        curDynVarState++;
+      }
+
+      // ExpFact -> 1 ExpF { '*' ExpF } '*' c '*' 'exp' 
+      AddTransition(StateExpFactorStart, StateExpFStart,
+        () => {
+          codeGenerator.Emit1(OpCodes.LoadConst1);
+        },
+        "1");
+      AddTransition(StateExpFEnd, StateExpFactorEnd,
+        () => {
+          codeGenerator.Emit1(OpCodes.Mul);
+          codeGenerator.Emit1(OpCodes.LoadParamN);
+          codeGenerator.Emit1(OpCodes.Mul);
+          codeGenerator.Emit1(OpCodes.Exp);
+        },
+        "*c*exp");
+      AddTransition(StateExpFEnd, StateExpFStart,
+        () => { codeGenerator.Emit1(OpCodes.Mul); },
+        "*");
+
+      // ExpF    -> var_1 ... var_n 
+      for (int i = 0; i < nVars; i++) {
+        short varIdx = (short)i;
+        int varState = curDynVarState;
+        stateNames.Add("var_2");
+        AddTransition(StateExpFStart, curDynVarState,
+          () => {
+            codeGenerator.Emit2(OpCodes.LoadVar, varIdx);
+            constraintHandler.AddVarToCurrentFactor(varState);
+          },
+          "var_" + varIdx + ", AddVar");
+        AddTransition(curDynVarState, StateExpFEnd);
+        curDynVarState++;
+      }
+
+      // must have c at end because of adjustment of c in evaluator
+      // LogFact -> 0 LogT { '+' LogT } '+' c '+' 'log'
+      AddTransition(StateLogFactorStart, StateLogTStart,
+        () => {
+          codeGenerator.Emit1(OpCodes.LoadConst0);
+          constraintHandler.StartNewTermInPoly();
+        },
+        "0, StartTermInPoly");
+      AddTransition(StateLogTEnd, StateLogFactorEnd,
+        () => {
+          codeGenerator.Emit1(OpCodes.Add);
+          codeGenerator.Emit1(OpCodes.LoadParamN);
+          codeGenerator.Emit1(OpCodes.Add);
+          codeGenerator.Emit1(OpCodes.Log);
+        },
+        "+c+log");
+      AddTransition(StateLogTEnd, StateLogTStart,
+        () => { codeGenerator.Emit1(OpCodes.Add); },
+        "+");
+
+      // LogT    -> c LogTF { '*' LogTF } '*' 
+      AddTransition(StateLogTStart, StateLogTFStart,
+        () => {
+          codeGenerator.Emit1(OpCodes.LoadParamN);
+        },
+        "c");
+      AddTransition(StateLogTFEnd, StateLogTEnd,
+        () => {
+          codeGenerator.Emit1(OpCodes.Mul);
+        },
+        "*");
+      AddTransition(StateLogTFEnd, StateLogTFStart,
+        () => {
+          codeGenerator.Emit1(OpCodes.Mul);
+        },
+        "*");
+
+      // LogTF   -> var_1 ... var_n
+      for (int i = 0; i < nVars; i++) {
+        short varIdx = (short)i;
+        int varState = curDynVarState;
+        stateNames.Add("var_3");
+        AddTransition(StateLogTFStart, curDynVarState,
+          () => {
+            codeGenerator.Emit2(OpCodes.LoadVar, varIdx);
+            constraintHandler.AddVarToCurrentFactor(varState);
+          },
+          "var_" + varIdx + ", AddVar");
+        AddTransition(curDynVarState, StateLogTFEnd);
+        curDynVarState++;
+      }
+
+      // InvFact -> 1 InvT { '+' InvT } '+' 'inv'
+      AddTransition(StateInvFactorStart, StateInvTStart,
+        () => {
+          codeGenerator.Emit1(OpCodes.LoadConst1);
+          constraintHandler.StartNewTermInPoly();
+        },
+        "c, StartTermInPoly");
+      AddTransition(StateInvTEnd, StateInvFactorEnd,
+        () => {
+          codeGenerator.Emit1(OpCodes.Add);
+          codeGenerator.Emit1(OpCodes.Inv);
+        },
+        "+inv");
+      AddTransition(StateInvTEnd, StateInvTStart,
+        () => { codeGenerator.Emit1(OpCodes.Add); },
+        "+");
+
+      // InvT    -> c InvTF { '*' InvTF } '*' 
+      AddTransition(StateInvTStart, StateInvTFStart,
+        () => {
+          codeGenerator.Emit1(OpCodes.LoadParamN);
+        },
+        "c");
+      AddTransition(StateInvTFEnd, StateInvTEnd,
+        () => {
+          codeGenerator.Emit1(OpCodes.Mul);
+        },
+        "*");
+      AddTransition(StateInvTFEnd, StateInvTFStart,
+        () => {
+          codeGenerator.Emit1(OpCodes.Mul);
+        },
+        "*");
+
+      // InvTF    -> (var_1 ... var_n) c '*' 
+      for (int i = 0; i < nVars; i++) {
+        short varIdx = (short)i;
+        int varState = curDynVarState;
+        stateNames.Add("var_4");
+        AddTransition(StateInvTFStart, curDynVarState,
+          () => {
+            codeGenerator.Emit2(OpCodes.LoadVar, varIdx);
+            constraintHandler.AddVarToCurrentFactor(varState);
+          },
+          "var_" + varIdx + ", AddVar");
+        AddTransition(curDynVarState, StateInvTFEnd);
+        curDynVarState++;
+      }
+
+      followStates[StateExprEnd] = new List<int>(); // no follow states
+    }
+
+    private void AddTransition(int fromState, int toState) {
+      if (followStates[fromState] == null) followStates[fromState] = new List<int>();
+      followStates[fromState].Add(toState);
+    }
+    private void AddTransition(int fromState, int toState, Action action, string str) {
+      if (followStates[fromState] == null) followStates[fromState] = new List<int>();
+      followStates[fromState].Add(toState);
+
+      if (actions[fromState, toState] == null) {
+        actions[fromState, toState] = new List<Action>();
+        actionStrings[fromState, toState] = new List<string>();
+      }
+
+      actions[fromState, toState].Add(action);
+      actionStrings[fromState, toState].Add(str);
+    }
+
+    private readonly int[] followStatesBuf = new int[1000];
+    public void FollowStates(int state, out int[] buf, out int nElements) {
+      // for loop instead of where iterator
+      var fs = followStates[state];
+      int j = 0;
+      for (int i = 0; i < fs.Count; i++) {
+        var s = fs[i];
+        if (constraintHandler.IsAllowedFollowState(state, s)) {
+          followStatesBuf[j++] = s;
+        }
+      }
+      buf = followStatesBuf;
+      nElements = j;
+    }
+
+
+    public void Goto(int targetState) {
+      if (actions[CurrentState, targetState] != null)
+        actions[CurrentState, targetState].ForEach(a => a()); // execute all actions
+      CurrentState = targetState;
+    }
+
+    public bool IsFinalState(int s) {
+      return s == StateExprEnd && !constraintHandler.IsInvalidExpression;
+    }
+
+    public void GetCode(out byte[] code, out int nParams) {
+      codeGenerator.GetCode(out code, out nParams);
+    }
+
+    public void Reset() {
+      CurrentState = StartState;
+      codeGenerator.Reset();
+      constraintHandler.Reset();
+    }
+
+#if DEBUG
+    public void PrintAutomaton() {
+      using (var writer = new StreamWriter("automaton.gv")) {
+        writer.WriteLine("digraph {");
+        // writer.WriteLine("rankdir=LR");
+        for (int s = StartState; s < stateNames.Count; s++) {
+          for (int i = 0; i < followStates[s].Count; i++) {
+            if (followStates[s][i] <= 0) continue;
+            var followS = followStates[s][i];
+            var label = actionStrings[s, followS] != null ? string.Join(" , ", actionStrings[s, followS]) : "";
+            writer.WriteLine("{0} -> {1} [ label = \"{2}\" ];", stateNames[s], stateNames[followS], label);
+          }
+        }
+        writer.WriteLine("}");
+      }
+    }
+#endif
+  }
+}
Index: stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/CodeGenerator.cs
===================================================================
--- stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/CodeGenerator.cs	(revision 15060)
+++ stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/CodeGenerator.cs	(revision 15060)
@@ -0,0 +1,56 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Diagnostics.Contracts;
+
+namespace HeuristicLab.Algorithms.DataAnalysis.MctsSymbolicRegression {
+  internal class CodeGenerator {
+
+    public const int MaxCodeLength = 10000;
+    public const int MaxConstants = 100;
+
+    private readonly byte[] codeArray = new byte[MaxCodeLength];
+    private int pc;
+    private int nParams;
+
+    public void Reset() {
+      pc = 0;
+      nParams = 0;
+    }
+
+    public void Emit1(OpCodes code) {
+      codeArray[pc++] = (byte)code;
+      if (code == OpCodes.LoadParamN) nParams++;
+    }
+
+    public void Emit2(OpCodes code, short arg) {
+      Contract.Assert(code == OpCodes.LoadVar); // only loadVar opcode has params
+      Emit1(code);
+      codeArray[pc++] = (byte)(arg >> 8);
+      codeArray[pc++] = (byte)(arg & 0xFF);
+    }
+
+    public void GetCode(out byte[] code, out int nParams) {
+      code = codeArray;
+      nParams = this.nParams;
+    }
+  }
+}
Index: stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/ConstraintHandler.cs
===================================================================
--- stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/ConstraintHandler.cs	(revision 15060)
+++ stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/ConstraintHandler.cs	(revision 15060)
@@ -0,0 +1,417 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Diagnostics.Contracts;
+using System.Linq;
+
+namespace HeuristicLab.Algorithms.DataAnalysis.MctsSymbolicRegression {
+
+  // This class restricts the set of allowed transitions of the automaton to prevent exploration of duplicate expressions.
+  // It would be possible to implement this class in such a way that the search never visits a duplicate expression. However,
+  // it seems very intricate to detect this robustly and in all cases while generating an expression because 
+  // some for of lookahead is necessary. 
+  // Instead the constraint handler only catches the obvious duplicates directly, but does not guarantee that the search always produces a valid expression.
+  // The ratio of the number of unsuccessful searches, that need backtracking should be tracked in the MCTS alg (MctsSymbolicRegressionStatic)
+
+  // All changes to this class should be tested through unit tests. It is important that the ConstraintHandler is not too restrictive.
+
+  // the constraints are derived from a canonical form for expressions.
+  // overall we can enforce a limited number of variable references
+  // 
+  // an expression is a sum of terms t_1 ... t_n where terms are ordered according to a relation t_i (<=)_term t_j for each pair t_i, t_j and i <= j
+  // a term is a product of factors where factors are ordered according to relation f_i (<=)_factor f_j for each pair f_i,f_j and i <= j
+
+  // we want to enforce lower-order terms before higher-order terms in expressions (based on number of variable references)
+  // factors can have different types (variable, exp, log, inverse)
+
+  // (<=)_term  [IsSmallerOrEqualTerm(t_i, t_j)]
+  //   1.  NumberOfVarRefs(t_i) < NumberOfVarRefs(t_j)  --> true           enforce terms with non-decreasing number of var refs
+  //   2.  NumberOfVarRefs(t_i) > NumberOfVarRefs(t_j)  --> false
+  //   3.  NumFactors(t_i) > NumFactors(t_j)            --> true           enforce terms with non-increasing number of factors
+  //   4.  NumFactors(t_i) < NumFactors(t_j)            --> false
+  //   5.  for all k factors: Factor(k, t_i) (<=)_factor  Factor(k, t_j) --> true // factors must be non-decreasing
+  //   6.  all factors are (=)_factor                   --> true
+  //   7.  else false
+
+  // (<=)_factor  [IsSmallerOrEqualFactor(f_i, f_j)]
+  //   1.  FactorType(t_i) < FactorType(t_j)  --> true           enforce terms with non-decreasing factor type (var < exp < log < inv)
+  //   2.  FactorType(t_i) > FactorType(t_j)  --> false
+  //   3.  Compare the two factors specifically
+  //     - variables: varIdx_i <= varIdx_j (only one var reference)
+  //     - exp: number of variable references and then varIdx_i <= varIdx_j for each position
+  //     - log: number of variable references and ...
+  //     - inv: number of variable references and ...
+  //
+
+  // for log and inverse factors we allow all polynomials as argument
+  // a polynomial is a sum of terms t_1 ... t_n where terms are ordered according to a relation t_i (<=)_poly t_j for each pair t_i, t_j and i <= j
+
+  // (<=)_poly  [IsSmallerOrEqualPoly(t_i, t_j)]
+  //  1. NumberOfVarRefs(t_i) < NumberOfVarRefs(t_j)         --> true // enforce non-decreasing number of var refs
+  //  2. NumberOfVarRefs(t_i) > NumberOfVarRefs(t_j)         --> false // enforce non-decreasing number of var refs
+  //  3. for all k variables: VarIdx(k,t_i) > VarIdx(k, t_j) --> false // enforce non-decreasing variable idx
+
+
+  // we store the following to make comparsions:
+  // - prevTerm (complete & containing all factors)
+  // - curTerm  (incomplete & containing all completed factors)
+  // - curFactor (incomplete)
+  internal class ConstraintHandler {
+    private int nVars;
+    private readonly int maxVariables;
+    private bool invalidExpression;
+
+    public bool IsInvalidExpression {
+      get { return invalidExpression; }
+    }
+
+
+    private TermInformation prevTerm;
+    private TermInformation curTerm;
+    private FactorInformation curFactor;
+
+
+    private class TermInformation {
+      public int numVarReferences { get { return factors.Sum(f => f.numVarReferences); } }
+      public List<FactorInformation> factors = new List<FactorInformation>();
+    }
+
+    private class FactorInformation {
+      public int numVarReferences = 0;
+      public int factorType; // use the state number to represent types
+
+      // for variable factors
+      public int variableState = -1;
+
+      // for exp  factors
+      public List<int> expVariableStates = new List<int>();
+
+      // for log and inv factors
+      public List<List<int>> polyVariableStates = new List<List<int>>();
+    }
+
+
+    public ConstraintHandler(int maxVars) {
+      this.maxVariables = maxVars;
+    }
+
+    // the order relations for terms and factors
+
+    private static int CompareTerms(TermInformation a, TermInformation b) {
+      if (a.numVarReferences < b.numVarReferences) return -1;
+      if (a.numVarReferences > b.numVarReferences) return 1;
+
+      if (a.factors.Count > b.factors.Count) return -1;  // terms with more factors should be ordered first
+      if (a.factors.Count < b.factors.Count) return +1;
+
+      var aFactors = a.factors.GetEnumerator();
+      var bFactors = b.factors.GetEnumerator();
+      while (aFactors.MoveNext() & bFactors.MoveNext()) {
+        var c = CompareFactors(aFactors.Current, bFactors.Current);
+        if (c < 0) return -1;
+        if (c > 0) return 1;
+      }
+      // all factors are the same => terms are the same
+      return 0;
+    }
+
+    private static int CompareFactors(FactorInformation a, FactorInformation b) {
+      if (a.factorType < b.factorType) return -1;
+      if (a.factorType > b.factorType) return +1;
+      // same factor types
+      if (a.factorType == Automaton.StateVariableFactorStart) {
+        return a.variableState.CompareTo(b.variableState);
+      } else if (a.factorType == Automaton.StateExpFactorStart) {
+        return CompareStateLists(a.expVariableStates, b.expVariableStates);
+      } else {
+        if (a.numVarReferences < b.numVarReferences) return -1;
+        if (a.numVarReferences > b.numVarReferences) return +1;
+        if (a.polyVariableStates.Count > b.polyVariableStates.Count) return -1; // more terms in the poly should be ordered first
+        if (a.polyVariableStates.Count < b.polyVariableStates.Count) return +1;
+        // log and inv
+        var aTerms = a.polyVariableStates.GetEnumerator();
+        var bTerms = b.polyVariableStates.GetEnumerator();
+        while (aTerms.MoveNext() & bTerms.MoveNext()) {
+          var c = CompareStateLists(aTerms.Current, bTerms.Current);
+          if (c != 0) return c;
+        }
+        return 0; // all terms in the polynomial are the same
+      }
+    }
+
+    private static int CompareStateLists(List<int> a, List<int> b) {
+      if (a.Count < b.Count) return -1;
+      if (a.Count > b.Count) return +1;
+      for (int i = 0; i < a.Count; i++) {
+        if (a[i] < b[i]) return -1;
+        if (a[i] > b[i]) return +1;
+      }
+      return 0; // all states are the same
+    }
+
+
+    private bool IsNewTermAllowed() {
+      // next term must have at least as many variable references as the previous term
+      return prevTerm == null || nVars + prevTerm.numVarReferences <= maxVariables;
+    }
+
+    private bool IsNewFactorAllowed() {
+      // next factor must have a larger or equal type compared to the previous factor.
+      // if the types are the same it must have at least as many variable references.
+      // so if the prevFactor is any other than invFactor (last possible type) then we only need to be able to add one variable
+      // otherwise we need to be able to add at least as many variables as the previous factor
+      return !curTerm.factors.Any() ||
+             (nVars + curTerm.factors.Last().numVarReferences <= maxVariables);
+    }
+
+    private bool IsAllowedAsNextFactorType(int followState) {
+      // IsNewTermAllowed already ensures that we can add a term with enough variable references
+
+      // enforce constraints within terms (compare to prev factor)
+      if (curTerm.factors.Any()) {
+        // enforce non-decreasing factor types
+        if (curTerm.factors.Last().factorType > followState) return false;
+        // when the factor type is the same, starting a new factor is only allowed if we can add at least the number of variables of the prev factor
+        if (curTerm.factors.Last().factorType == followState && nVars + curTerm.factors.Last().numVarReferences > maxVariables) return false;
+      }
+
+      // enforce constraints on terms (compare to prev term)
+      // meaning that we must ensure non-decreasing terms
+      if (prevTerm != null) {
+        // a factor type is only allowed if we can then produce a term that is larger or equal to the prev term
+        // (1) if we the number of variable references still remaining is larger than the number of variable references in the prev term 
+        //     then it is always possible to build a larger term
+        // (2) otherwise we try to build the largest possible term starting from current factors in the term.
+        //     
+
+        var numVarRefsRemaining = maxVariables - nVars;
+        Contract.Assert(!curTerm.factors.Any() || curTerm.factors.Last().numVarReferences <= numVarRefsRemaining);
+
+        if (prevTerm.numVarReferences < numVarRefsRemaining) return true;
+
+        // variable factors must be handled differently because they can only contain one variable reference
+        if (followState == Automaton.StateVariableFactorStart) {
+          // append the variable factor and the maximum possible state from the previous factor to create a larger factor
+          var varF = CreateLargestPossibleFactor(Automaton.StateVariableFactorStart, 1);
+          var maxF = CreateLargestPossibleFactor(prevTerm.factors.Max(f => f.factorType), numVarRefsRemaining - 1);
+          var origFactorCount = curTerm.factors.Count;
+          // add this factor to the current term
+          curTerm.factors.Add(varF);
+          curTerm.factors.Add(maxF);
+          var c = CompareTerms(prevTerm, curTerm);
+          // restore term
+          curTerm.factors.RemoveRange(origFactorCount, 2);
+          // if the prev term is still larger then this followstate is not allowed
+          if (c > 0) {
+            return false;
+          }
+        } else {
+          var newF = CreateLargestPossibleFactor(followState, numVarRefsRemaining);
+
+          var origFactorCount = curTerm.factors.Count;
+          // add this factor to the current term
+          curTerm.factors.Add(newF);
+          var c = CompareTerms(prevTerm, curTerm);
+          // restore term
+          curTerm.factors.RemoveAt(origFactorCount);
+          // if the prev term is still larger then this followstate is not allowed
+          if (c > 0) {
+            return false;
+          }
+        }
+      }
+      return true;
+    }
+
+    // largest possible factor of the given kind
+    private FactorInformation CreateLargestPossibleFactor(int factorType, int numVarRefs) {
+      var newF = new FactorInformation();
+      newF.factorType = factorType;
+      if (factorType == Automaton.StateVariableFactorStart) {
+        newF.variableState = int.MaxValue;
+        newF.numVarReferences = 1;
+      } else if (factorType == Automaton.StateExpFactorStart) {
+        for (int i = 0; i < numVarRefs; i++)
+          newF.expVariableStates.Add(int.MaxValue);
+        newF.numVarReferences = numVarRefs;
+      } else if (factorType == Automaton.StateInvFactorStart || factorType == Automaton.StateLogFactorStart) {
+        for (int i = 0; i < numVarRefs; i++) {
+          newF.polyVariableStates.Add(new List<int>());
+          newF.polyVariableStates[i].Add(int.MaxValue);
+        }
+        newF.numVarReferences = numVarRefs;
+      }
+      return newF;
+    }
+
+    private bool IsAllowedAsNextVariableFactor(int variableState) {
+      Contract.Assert(variableState >= Automaton.FirstDynamicState);
+      return !curTerm.factors.Any() || curTerm.factors.Last().variableState <= variableState;
+    }
+
+    private bool IsAllowedAsNextInExp(int variableState) {
+      Contract.Assert(variableState >= Automaton.FirstDynamicState);
+      if (curFactor.expVariableStates.Any() && curFactor.expVariableStates.Last() > variableState) return false;
+      if (curTerm.factors.Any()) {
+        // try and compare with prev factor      
+        curFactor.numVarReferences++;
+        curFactor.expVariableStates.Add(variableState);
+        var c = CompareFactors(curTerm.factors.Last(), curFactor);
+        curFactor.numVarReferences--;
+        curFactor.expVariableStates.RemoveAt(curFactor.expVariableStates.Count - 1);
+        return c <= 0;
+      }
+      return true;
+    }
+
+    private bool IsNewTermAllowedInPoly() {
+      return nVars + curFactor.polyVariableStates.Last().Count() <= maxVariables;
+    }
+
+    private bool IsAllowedAsNextInPoly(int variableState) {
+      Contract.Assert(variableState >= Automaton.FirstDynamicState);
+      return !curFactor.polyVariableStates.Any() ||
+             !curFactor.polyVariableStates.Last().Any() ||
+              curFactor.polyVariableStates.Last().Last() <= variableState;
+    }
+    private bool IsTermCompleteInPoly() {
+      var nTerms = curFactor.polyVariableStates.Count;
+      return nTerms == 1 ||
+             curFactor.polyVariableStates[nTerms - 2].Count <= curFactor.polyVariableStates[nTerms - 1].Count;
+
+    }
+    private bool IsCompleteExp() {
+      return !curTerm.factors.Any() || CompareFactors(curTerm.factors.Last(), curFactor) <= 0;
+    }
+
+    public bool IsAllowedFollowState(int currentState, int followState) {
+      // an invalid action was taken earlier on => nothing can be done anymore
+      if (invalidExpression) return false;
+      // states that have no alternative are always allowed
+      // some ending states are only allowed if enough variables have been used in the term
+      if (
+        currentState == Automaton.StateTermStart ||           // no alternative
+        currentState == Automaton.StateExpFactorStart ||
+        currentState == Automaton.StateLogFactorStart ||
+        currentState == Automaton.StateInvFactorStart ||
+        followState == Automaton.StateVariableFactorEnd ||    // no alternative
+        followState == Automaton.StateExpFEnd ||              // no alternative
+        followState == Automaton.StateLogTFEnd ||             // no alternative
+        followState == Automaton.StateInvTFEnd ||             // no alternative
+        followState == Automaton.StateFactorEnd ||            // always allowed because no alternative
+        followState == Automaton.StateExprEnd                 // we could also constrain the minimum number of terms here
+      ) return true;
+
+
+      // starting a new term is only allowed if we can add a term with at least the number of variables of the prev term
+      if (followState == Automaton.StateTermStart && !IsNewTermAllowed()) return false;
+      if (followState == Automaton.StateFactorStart && !IsNewFactorAllowed()) return false;
+      if (currentState == Automaton.StateFactorStart && !IsAllowedAsNextFactorType(followState)) return false;
+      if (followState == Automaton.StateTermEnd && prevTerm != null && CompareTerms(prevTerm, curTerm) > 0) return false;
+
+      // all of these states add at least one variable
+      if (
+          followState == Automaton.StateVariableFactorStart ||
+          followState == Automaton.StateExpFactorStart || followState == Automaton.StateExpFStart ||
+          followState == Automaton.StateLogFactorStart || followState == Automaton.StateLogTStart ||
+          followState == Automaton.StateLogTFStart ||
+          followState == Automaton.StateInvFactorStart || followState == Automaton.StateInvTStart ||
+          followState == Automaton.StateInvTFStart) {
+        if (nVars + 1 > maxVariables) return false;
+      }
+
+      if (currentState == Automaton.StateVariableFactorStart && !IsAllowedAsNextVariableFactor(followState)) return false;
+      else if (currentState == Automaton.StateExpFStart && !IsAllowedAsNextInExp(followState)) return false;
+      else if (followState == Automaton.StateLogTStart && !IsNewTermAllowedInPoly()) return false;
+      else if (currentState == Automaton.StateLogTFStart && !IsAllowedAsNextInPoly(followState)) return false;
+      else if (followState == Automaton.StateInvTStart && !IsNewTermAllowedInPoly()) return false;
+      else if (currentState == Automaton.StateInvTFStart && !IsAllowedAsNextInPoly(followState)) return false;
+      // finishing an exponential factor is only allowed when the number of variable references is large enough
+      else if (followState == Automaton.StateExpFactorEnd && !IsCompleteExp()) return false;
+      // finishing a polynomial (in log or inv) is only allowed when the number of variable references is large enough
+      else if (followState == Automaton.StateInvTEnd && !IsTermCompleteInPoly()) return false;
+      else if (followState == Automaton.StateLogTEnd && !IsTermCompleteInPoly()) return false;
+
+      else if (nVars > maxVariables) return false;
+      else return true;
+    }
+
+
+    public void Reset() {
+      nVars = 0;
+      prevTerm = null;
+      curTerm = null;
+      curFactor = null;
+      invalidExpression = false;
+    }
+
+    public void StartTerm() {
+      curTerm = new TermInformation();
+    }
+
+    public void StartFactor(int state) {
+      curFactor = new FactorInformation();
+      curFactor.factorType = state;
+    }
+
+
+    public void AddVarToCurrentFactor(int state) {
+      Contract.Assert(Automaton.FirstDynamicState <= state);
+      Contract.Assert(curTerm != null);
+      Contract.Assert(curFactor != null);
+
+      nVars++;
+      curFactor.numVarReferences++;
+
+      if (curFactor.factorType == Automaton.StateVariableFactorStart) {
+        Contract.Assert(curFactor.variableState < 0); // not set before
+        curFactor.variableState = state;
+      } else if (curFactor.factorType == Automaton.StateExpFactorStart) {
+        curFactor.expVariableStates.Add(state);
+      } else if (curFactor.factorType == Automaton.StateLogFactorStart ||
+                 curFactor.factorType == Automaton.StateInvFactorStart) {
+        curFactor.polyVariableStates.Last().Add(state);
+      } else throw new InvalidProgramException();
+    }
+
+    public void StartNewTermInPoly() {
+      curFactor.polyVariableStates.Add(new List<int>());
+    }
+
+    public void EndFactor() {
+      // enforce non-decreasing factors 
+      if (curTerm.factors.Any() && CompareFactors(curTerm.factors.Last(), curFactor) > 0)
+        invalidExpression = true;
+      curTerm.factors.Add(curFactor);
+      curFactor = null;
+    }
+
+    public void EndTerm() {
+      // enforce non-decreasing terms (TODO: equal terms should not be allowed)
+      if (prevTerm != null && CompareTerms(prevTerm, curTerm) > 0)
+        invalidExpression = true;
+      prevTerm = curTerm;
+      curTerm = null;
+    }
+  }
+}
Index: stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Disassembler.cs
===================================================================
--- stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Disassembler.cs	(revision 15060)
+++ stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Disassembler.cs	(revision 15060)
@@ -0,0 +1,52 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Text;
+
+namespace HeuristicLab.Algorithms.DataAnalysis.MctsSymbolicRegression {
+  internal class Disassembler {
+    public static string CodeToString(byte[] code, double[] consts) {
+      var sb = new StringBuilder();
+      int pc = 0;
+      int nextParamIdx = -1;
+      while (code[pc] != (byte)OpCodes.Exit) {
+        var op = code[pc++];
+        switch (op) {
+          case (byte)OpCodes.Add: sb.Append(" + "); break;
+          case (byte)OpCodes.Mul: sb.Append(" * "); break;
+          case (byte)OpCodes.LoadConst1: sb.Append(" 1 "); break;
+          case (byte)OpCodes.LoadConst0: sb.Append(" 0 "); break;
+          case (byte)OpCodes.LoadParamN: sb.AppendFormat(" {0:N3} ", consts[++nextParamIdx]); break;
+          case (byte)OpCodes.LoadVar:
+          {
+              short arg = (short)((code[pc] << 8) | code[pc + 1]);
+              pc += 2;
+            sb.AppendFormat(" var{0} ", arg); break;
+          }
+          case (byte)OpCodes.Exp: sb.Append(" exp "); break;
+          case (byte)OpCodes.Log: sb.Append(" log "); break;
+          case (byte)OpCodes.Inv: sb.Append(" inv "); break;          
+        }
+      }
+      return sb.ToString();
+    }
+  }
+}
Index: stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/ExpressionEvaluator.cs
===================================================================
--- stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/ExpressionEvaluator.cs	(revision 15060)
+++ stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/ExpressionEvaluator.cs	(revision 15060)
@@ -0,0 +1,519 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Diagnostics.Contracts;
+using System.Linq;
+
+namespace HeuristicLab.Algorithms.DataAnalysis.MctsSymbolicRegression {
+  // evalutes expressions (on vectors)
+  internal class ExpressionEvaluator {
+    // manages it's own vector buffers
+    private readonly double[][] vectorBuffers;
+    private readonly double[][] scalarBuffers; // scalars are vectors of length 1 (to allow mixing scalars and vectors on the same stack)
+    private int lastVecBufIdx;
+    private int lastScalarBufIdx;
+
+
+    private double[] GetVectorBuffer() {
+      return vectorBuffers[--lastVecBufIdx];
+    }
+    private double[] GetScalarBuffer() {
+      return scalarBuffers[--lastScalarBufIdx];
+    }
+
+    private void ReleaseBuffer(double[] buf) {
+      if (buf.Length == 1) {
+        scalarBuffers[lastScalarBufIdx++] = buf;
+      } else {
+        vectorBuffers[lastVecBufIdx++] = buf;
+      }
+    }
+
+    public const int MaxStackSize = 100;
+    public const int MaxParams = 50;
+    private readonly int vLen;
+    private readonly double lowerEstimationLimit;
+    private readonly double upperEstimationLimit;
+    private readonly double nanReplacementValue;
+
+    private readonly double[][] stack;
+    private readonly double[][][] gradientStack;
+
+    // preallocate stack and gradient stack 
+    public ExpressionEvaluator(int vLen, double lowerEstimationLimit = double.MinValue, double upperEstimationLimit = double.MaxValue) {
+      if (vLen <= 1) throw new ArgumentException("number of elements in a variable must be > 1", "vlen");
+      this.vLen = vLen;
+      this.lowerEstimationLimit = lowerEstimationLimit;
+      this.upperEstimationLimit = upperEstimationLimit;
+      this.nanReplacementValue = (upperEstimationLimit - lowerEstimationLimit) / 2.0 + lowerEstimationLimit;
+
+      stack = new double[MaxStackSize][];
+      gradientStack = new double[MaxParams][][];
+
+      for (int k = 0; k < MaxParams; k++) {
+        gradientStack[k] = new double[MaxStackSize][];
+      }
+
+      // preallocate buffers 
+      vectorBuffers = new double[MaxStackSize * (1 + MaxParams)][];
+      scalarBuffers = new double[MaxStackSize * (1 + MaxParams)][];
+      for (int i = 0; i < MaxStackSize; i++) {
+        ReleaseBuffer(new double[vLen]);
+        ReleaseBuffer(new double[1]);
+
+        for (int k = 0; k < MaxParams; k++) {
+          ReleaseBuffer(new double[vLen]);
+          ReleaseBuffer(new double[1]);
+        }
+      }
+    }
+
+    // pred must be allocated by the caller
+    // if adjustOffsetForLogAndExp is set to true we determine c in log(c + f(x)) to make sure that c + f(x) is positive
+    public void Exec(byte[] code, double[][] vars, double[] consts, double[] pred, bool adjustOffsetForLogAndExp = false) {
+      Contract.Assert(pred != null && pred.Length >= vLen);
+      int topOfStack = -1;
+      int pc = 0;
+      int curParamIdx = -1;
+      byte op;
+      short arg;
+      // checked at the end to make sure we do not leak buffers
+      int initialScalarCount = lastScalarBufIdx;
+      int initialVectorCount = lastVecBufIdx;
+
+      while (true) {
+        ReadNext(code, ref pc, out op, out arg);
+        switch (op) {
+          case (byte)OpCodes.Nop: throw new InvalidProgramException(); // not allowed
+          case (byte)OpCodes.LoadConst0: {
+              ++topOfStack;
+              var z = GetScalarBuffer();
+              z[0] = 0;
+              stack[topOfStack] = z;
+              break;
+            }
+          case (byte)OpCodes.LoadConst1: {
+              ++topOfStack;
+              var z = GetScalarBuffer();
+              z[0] = 1.0;
+              stack[topOfStack] = z;
+              break;
+            }
+          case (byte)OpCodes.LoadParamN: {
+              ++topOfStack;
+              var c = consts[++curParamIdx];
+              var z = GetScalarBuffer();
+              z[0] = c;
+              stack[topOfStack] = z;
+              break;
+            }
+          case (byte)OpCodes.LoadVar: {
+              ++topOfStack;
+              var z = GetVectorBuffer();
+              Array.Copy(vars[arg], z, vars[arg].Length);
+              stack[topOfStack] = z;
+              break;
+            }
+          case (byte)OpCodes.Add: {
+              topOfStack--;
+              var a = stack[topOfStack + 1];
+              var b = stack[topOfStack];
+              stack[topOfStack] = Add(a, b);
+              ReleaseBuffer(a);
+              ReleaseBuffer(b);
+              break;
+            }
+          case (byte)OpCodes.Mul: {
+              topOfStack--;
+              var a = stack[topOfStack + 1];
+              var b = stack[topOfStack];
+              stack[topOfStack] = Mul(a, b);
+              ReleaseBuffer(a);
+              ReleaseBuffer(b);
+              break;
+            }
+          case (byte)OpCodes.Log: {
+              if (adjustOffsetForLogAndExp) {
+                // here we assume that the last used parameter is c in log(f(x) + c)
+                // this must match actions for producing code in the automaton!
+
+                // we can easily adjust c to make sure that f(x) + c is positive because at this point we all values for f(x)
+                var fxc = stack[topOfStack];
+                var minFx = fxc.Min() - consts[curParamIdx]; // stack[topOfStack] is f(x) + c
+
+                var delta = 1.0 - minFx - consts[curParamIdx];
+                // adjust c so that minFx + c = 1 ... log(minFx + c) = 0
+                consts[curParamIdx] += delta;
+
+                // also adjust values on stack
+                for (int i = 0; i < fxc.Length; i++) fxc[i] += delta;
+              }
+              var x = stack[topOfStack];
+              for (int i = 0; i < x.Length; i++)
+                x[i] = Math.Log(x[i]);
+              break;
+            }
+          case (byte)OpCodes.Exp: {
+              if (adjustOffsetForLogAndExp) {
+                // here we assume that the last used parameter is c in exp(f(x) * c)
+                // this must match actions for producing code in the automaton!
+
+                // adjust c to make sure that exp(f(x) * c) is not too large
+                var fxc = stack[topOfStack];
+                var maxFx = fxc.Max() / consts[curParamIdx]; // stack[topOfStack] is f(x) * c
+
+                var f = 1.0 / (maxFx * consts[curParamIdx]);
+                // adjust c so that maxFx*c = 1 TODO: this is not ideal as it enforces positive arguments to exp()
+                consts[curParamIdx] *= f;
+
+                // also adjust values on stack
+                for (int i = 0; i < fxc.Length; i++) fxc[i] *= f;
+              }
+
+              var x = stack[topOfStack];
+              for (int i = 0; i < x.Length; i++)
+                x[i] = Math.Exp(x[i]);
+              break;
+            }
+          case (byte)OpCodes.Inv: {
+              var x = stack[topOfStack];
+              for (int i = 0; i < x.Length; i++)
+                x[i] = 1.0 / (x[i]);
+              break;
+            }
+          case (byte)OpCodes.Exit:
+            Contract.Assert(topOfStack == 0);
+            var r = stack[topOfStack];
+            if (r.Length == 1) {
+              var v = double.IsNaN(r[0]) ? nanReplacementValue : Math.Min(upperEstimationLimit, Math.Max(lowerEstimationLimit, r[0]));
+              for (int i = 0; i < vLen; i++)
+                pred[i] = v;
+            } else {
+              for (int i = 0; i < vLen; i++) {
+                var v = double.IsNaN(r[i]) ? nanReplacementValue : Math.Min(upperEstimationLimit, Math.Max(lowerEstimationLimit, r[i]));
+                pred[i] = v;
+              }
+            }
+            ReleaseBuffer(r);
+            Contract.Assert(lastVecBufIdx == initialVectorCount);
+            Contract.Assert(lastScalarBufIdx == initialScalarCount);
+            return;
+        }
+      }
+    }
+
+
+    // evaluation with forward autodiff
+    // pred and gradients must be allocated by the caller
+    public void ExecGradient(byte[] code, double[][] vars, double[] consts, double[] pred, double[][] gradients) {
+      Contract.Assert(pred != null && pred.Length >= vLen);
+      int topOfStack = -1;
+      int pc = 0;
+      int curParamIdx = -1;
+      byte op;
+      short arg;
+      int nParams = consts.Length;
+      Contract.Assert(gradients != null && gradients.Length >= nParams && gradients.All(g => g.Length >= vLen));
+
+      // checked at the end to make sure we do not leak buffers
+      int initialScalarCount = lastScalarBufIdx;
+      int initialVectorCount = lastVecBufIdx;
+
+      while (true) {
+        ReadNext(code, ref pc, out op, out arg);
+        switch (op) {
+          case (byte)OpCodes.Nop: throw new InvalidProgramException(); // not allowed
+          case (byte)OpCodes.LoadConst0: {
+              ++topOfStack;
+              var z = GetScalarBuffer();
+              z[0] = 0;
+              stack[topOfStack] = z;
+              for (int k = 0; k < nParams; ++k) {
+                var b = GetScalarBuffer();
+                b[0] = 0.0;
+                gradientStack[k][topOfStack] = b;
+              }
+              break;
+            }
+          case (byte)OpCodes.LoadConst1: {
+              ++topOfStack;
+              var z = GetScalarBuffer();
+              z[0] = 1.0;
+              stack[topOfStack] = z;
+              for (int k = 0; k < nParams; ++k) {
+                var b = GetScalarBuffer();
+                b[0] = 0.0;
+                gradientStack[k][topOfStack] = b;
+              }
+              break;
+            }
+          case (byte)OpCodes.LoadParamN: {
+              var c = consts[++curParamIdx];
+              ++topOfStack;
+              var z = GetScalarBuffer();
+              z[0] = c;
+              stack[topOfStack] = z;
+              for (int k = 0; k < nParams; ++k) {
+                var b = GetScalarBuffer();
+                b[0] = k == curParamIdx ? 1.0 : 0.0;
+                gradientStack[k][topOfStack] = b;
+              }
+              break;
+            }
+          case (byte)OpCodes.LoadVar: {
+              ++topOfStack;
+              var z = GetVectorBuffer();
+              Array.Copy(vars[arg], z, vars[arg].Length);
+              stack[topOfStack] = z;
+              for (int k = 0; k < nParams; ++k) {
+                var b = GetScalarBuffer();
+                b[0] = 0.0;
+                gradientStack[k][topOfStack] = b;
+              }
+            }
+            break;
+          case (byte)OpCodes.Add: {
+              topOfStack--;
+              var a = stack[topOfStack + 1];
+              var b = stack[topOfStack];
+              stack[topOfStack] = Add(a, b);
+              ReleaseBuffer(a);
+              ReleaseBuffer(b);
+
+              // same for gradient
+              for (int k = 0; k < nParams; ++k) {
+                var ag = gradientStack[k][topOfStack + 1];
+                var bg = gradientStack[k][topOfStack];
+                gradientStack[k][topOfStack] = Add(ag, bg);
+                ReleaseBuffer(ag);
+                ReleaseBuffer(bg);
+              }
+              break;
+            }
+          case (byte)OpCodes.Mul: {
+              topOfStack--;
+              var a = stack[topOfStack + 1];
+              var b = stack[topOfStack];
+              stack[topOfStack] = Mul(a, b);
+
+              // same for gradient
+              // f(x) g(x)	f '(x) g(x) + f(x) g'(x)
+              for (int k = 0; k < nParams; ++k) {
+                var ag = gradientStack[k][topOfStack + 1];
+                var bg = gradientStack[k][topOfStack];
+                var t1 = Mul(ag, b);
+                var t2 = Mul(a, bg);
+                gradientStack[k][topOfStack] = Add(t1, t2);
+                ReleaseBuffer(ag);
+                ReleaseBuffer(bg);
+                ReleaseBuffer(t1);
+                ReleaseBuffer(t2);
+              }
+
+              ReleaseBuffer(a);
+              ReleaseBuffer(b);
+
+              break;
+            }
+          case (byte)OpCodes.Log: {
+              var x = stack[topOfStack];
+              // calc gradients first before destroying x
+              // log(f(x))' = f(x)'/f(x)
+              for (int k = 0; k < nParams; k++) {
+                var xg = gradientStack[k][topOfStack];
+                gradientStack[k][topOfStack] = Frac(xg, x);
+                ReleaseBuffer(xg);
+              }
+
+              for (int i = 0; i < x.Length; i++)
+                x[i] = Math.Log(x[i]);
+
+              break;
+            }
+          case (byte)OpCodes.Exp: {
+              var x = stack[topOfStack];
+              for (int i = 0; i < x.Length; i++)
+                x[i] = Math.Exp(x[i]);
+
+              for (int k = 0; k < nParams; k++) {
+                var xg = gradientStack[k][topOfStack];
+                gradientStack[k][topOfStack] = Mul(x, xg);  // e(f(x))' = e(f(x)) * f(x)'
+                ReleaseBuffer(xg);
+              }
+              break;
+            }
+          case (byte)OpCodes.Inv: {
+              var x = stack[topOfStack];
+              for (int i = 0; i < x.Length; i++)
+                x[i] = 1.0 / x[i];
+
+              for (int k = 0; k < nParams; k++) {
+                var xg = gradientStack[k][topOfStack];
+                // x has already been inverted above
+                // (1/f)' = -f' / f²
+                var invF = Mul(xg, x);
+                gradientStack[k][topOfStack] = Mul(invF, x, factor: -1.0);
+                ReleaseBuffer(xg);
+                ReleaseBuffer(invF);
+              }
+              break;
+            }
+          case (byte)OpCodes.Exit:
+            Contract.Assert(topOfStack == 0);
+            var r = stack[topOfStack];
+            if (r.Length == 1) {
+              var v = double.IsNaN(r[0]) ? nanReplacementValue : Math.Min(upperEstimationLimit, Math.Max(lowerEstimationLimit, r[0]));
+              for (int i = 0; i < vLen; i++)
+                pred[i] = v;
+            } else {
+              for (int i = 0; i < vLen; i++) {
+                var v = double.IsNaN(r[i]) ? nanReplacementValue : Math.Min(upperEstimationLimit, Math.Max(lowerEstimationLimit, r[i]));
+                pred[i] = v;
+              }
+            }
+            ReleaseBuffer(r);
+
+            // same for gradients
+            for (int k = 0; k < nParams; k++) {
+              var g = gradientStack[k][topOfStack];
+              if (g.Length == 1) {
+                for (int i = 0; i < vLen; i++)
+                  gradients[k][i] = g[0];
+              } else
+                Array.Copy(g, gradients[k], vLen);
+              ReleaseBuffer(g);
+            }
+
+            Contract.Assert(lastVecBufIdx == initialVectorCount);
+            Contract.Assert(lastScalarBufIdx == initialScalarCount);
+            return; // break loop
+        }
+      }
+    }
+
+    private double[] Add(double[] a, double[] b) {
+      double[] target = null;
+      if (a.Length > 1) {
+        target = GetVectorBuffer();
+        if (b.Length > 1) {
+          for (int i = 0; i < vLen; i++)
+            target[i] = a[i] + b[i];
+        } else {
+          // b == scalar
+          for (int i = 0; i < vLen; i++)
+            target[i] = a[i] + b[0];
+        }
+      } else {
+        // a == scalar
+        if (b.Length > 1) {
+          target = GetVectorBuffer();
+          for (int i = 0; i < vLen; i++)
+            target[i] = a[0] + b[i];
+        } else {
+          // b == scalar
+          target = GetScalarBuffer();
+          target[0] = a[0] + b[0];
+        }
+      }
+      return target;
+    }
+
+    private double[] Mul(double[] a, double[] b, double factor = 1.0) {
+      double[] target = null;
+      if (a.Length > 1) {
+        if (b.Length > 1) {
+          target = GetVectorBuffer();
+          for (int i = 0; i < vLen; i++)
+            target[i] = factor * a[i] * b[i];
+        } else {
+          // b == scalar
+          if (Math.Abs(b[0]) < 1E-12 /* == 0 */) {
+            target = GetScalarBuffer();
+            target[0] = 0.0;
+          } else {
+            target = GetVectorBuffer();
+            for (int i = 0; i < vLen; i++)
+              target[i] = factor * a[i] * b[0];
+          }
+        }
+      } else {
+        // a == scalar
+        if (b.Length > 1) {
+          if (Math.Abs(a[0]) < 1E-12 /* == 0 */) {
+            target = GetScalarBuffer();
+            target[0] = 0.0;
+          } else {
+            target = GetVectorBuffer();
+            for (int i = 0; i < vLen; i++)
+              target[i] = factor * a[0] * b[i];
+          }
+        } else {
+          // b == scalar
+          target = GetScalarBuffer();
+          target[0] = factor * a[0] * b[0];
+        }
+      }
+      return target;
+    }
+
+    private double[] Frac(double[] a, double[] b) {
+      double[] target = null;
+      if (a.Length > 1) {
+        target = GetVectorBuffer();
+        if (b.Length > 1) {
+          for (int i = 0; i < vLen; i++)
+            target[i] = a[i] / b[i];
+        } else {
+          // b == scalar
+          for (int i = 0; i < vLen; i++)
+            target[i] = a[i] / b[0];
+        }
+      } else {
+        // a == scalar
+        if (b.Length > 1) {
+          if (Math.Abs(a[0]) < 1E-12 /* == 0 */) {
+            target = GetScalarBuffer();
+            target[0] = 0.0;
+          } else {
+            target = GetVectorBuffer();
+            for (int i = 0; i < vLen; i++)
+              target[i] = a[0] / b[i];
+          }
+        } else {
+          // b == scalar
+          target = GetScalarBuffer();
+          target[0] = a[0] / b[0];
+        }
+      }
+      return target;
+    }
+
+    private void ReadNext(byte[] code, ref int pc, out byte op, out short s) {
+      op = code[pc++];
+      s = 0;
+      if (op == (byte)OpCodes.LoadVar) {
+        s = (short)((code[pc] << 8) | code[pc + 1]);
+        pc += 2;
+      }
+    }
+  }
+}
Index: stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/MctsSymbolicRegressionAlgorithm.cs
===================================================================
--- stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/MctsSymbolicRegressionAlgorithm.cs	(revision 15060)
+++ stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/MctsSymbolicRegressionAlgorithm.cs	(revision 15060)
@@ -0,0 +1,335 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Linq;
+using System.Runtime.CompilerServices;
+using System.Threading;
+using HeuristicLab.Algorithms.DataAnalysis.MctsSymbolicRegression.Policies;
+using HeuristicLab.Analysis;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Optimization;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+using HeuristicLab.Problems.DataAnalysis;
+
+namespace HeuristicLab.Algorithms.DataAnalysis.MctsSymbolicRegression {
+  [Item("MCTS Symbolic Regression", "Monte carlo tree search for symbolic regression. Useful mainly as a base learner in gradient boosting.")]
+  [StorableClass]
+  [Creatable(CreatableAttribute.Categories.DataAnalysisRegression, Priority = 250)]
+  public class MctsSymbolicRegressionAlgorithm : BasicAlgorithm {
+    public override Type ProblemType {
+      get { return typeof(IRegressionProblem); }
+    }
+    public new IRegressionProblem Problem {
+      get { return (IRegressionProblem)base.Problem; }
+      set { base.Problem = value; }
+    }
+
+    #region ParameterNames
+    private const string IterationsParameterName = "Iterations";
+    private const string MaxVariablesParameterName = "Maximum variables";
+    private const string ScaleVariablesParameterName = "Scale variables";
+    private const string AllowedFactorsParameterName = "Allowed factors";
+    private const string ConstantOptimizationIterationsParameterName = "Iterations (constant optimization)";
+    private const string PolicyParameterName = "Policy";
+    private const string SeedParameterName = "Seed";
+    private const string SetSeedRandomlyParameterName = "SetSeedRandomly";
+    private const string UpdateIntervalParameterName = "UpdateInterval";
+    private const string CreateSolutionParameterName = "CreateSolution";
+    private const string PunishmentFactorParameterName = "PunishmentFactor";
+
+    private const string VariableProductFactorName = "product(xi)";
+    private const string ExpFactorName = "exp(c * product(xi))";
+    private const string LogFactorName = "log(c + sum(c*product(xi))";
+    private const string InvFactorName = "1 / (1 + sum(c*product(xi))";
+    private const string FactorSumsName = "sum of multiple terms";
+    #endregion
+
+    #region ParameterProperties
+    public IFixedValueParameter<IntValue> IterationsParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[IterationsParameterName]; }
+    }
+    public IFixedValueParameter<IntValue> MaxVariableReferencesParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[MaxVariablesParameterName]; }
+    }
+    public IFixedValueParameter<BoolValue> ScaleVariablesParameter {
+      get { return (IFixedValueParameter<BoolValue>)Parameters[ScaleVariablesParameterName]; }
+    }
+    public IFixedValueParameter<IntValue> ConstantOptimizationIterationsParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[ConstantOptimizationIterationsParameterName]; }
+    }
+    public IValueParameter<IPolicy> PolicyParameter {
+      get { return (IValueParameter<IPolicy>)Parameters[PolicyParameterName]; }
+    }
+    public IFixedValueParameter<DoubleValue> PunishmentFactorParameter {
+      get { return (IFixedValueParameter<DoubleValue>)Parameters[PunishmentFactorParameterName]; }
+    }
+    public IValueParameter<ICheckedItemList<StringValue>> AllowedFactorsParameter {
+      get { return (IValueParameter<ICheckedItemList<StringValue>>)Parameters[AllowedFactorsParameterName]; }
+    }
+    public IFixedValueParameter<IntValue> SeedParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[SeedParameterName]; }
+    }
+    public FixedValueParameter<BoolValue> SetSeedRandomlyParameter {
+      get { return (FixedValueParameter<BoolValue>)Parameters[SetSeedRandomlyParameterName]; }
+    }
+    public IFixedValueParameter<IntValue> UpdateIntervalParameter {
+      get { return (IFixedValueParameter<IntValue>)Parameters[UpdateIntervalParameterName]; }
+    }
+    public IFixedValueParameter<BoolValue> CreateSolutionParameter {
+      get { return (IFixedValueParameter<BoolValue>)Parameters[CreateSolutionParameterName]; }
+    }
+    #endregion
+
+    #region Properties
+    public int Iterations {
+      get { return IterationsParameter.Value.Value; }
+      set { IterationsParameter.Value.Value = value; }
+    }
+    public int Seed {
+      get { return SeedParameter.Value.Value; }
+      set { SeedParameter.Value.Value = value; }
+    }
+    public bool SetSeedRandomly {
+      get { return SetSeedRandomlyParameter.Value.Value; }
+      set { SetSeedRandomlyParameter.Value.Value = value; }
+    }
+    public int MaxVariableReferences {
+      get { return MaxVariableReferencesParameter.Value.Value; }
+      set { MaxVariableReferencesParameter.Value.Value = value; }
+    }
+    public IPolicy Policy {
+      get { return PolicyParameter.Value; }
+      set { PolicyParameter.Value = value; }
+    }
+    public double PunishmentFactor {
+      get { return PunishmentFactorParameter.Value.Value; }
+      set { PunishmentFactorParameter.Value.Value = value; }
+    }
+    public ICheckedItemList<StringValue> AllowedFactors {
+      get { return AllowedFactorsParameter.Value; }
+    }
+    public int ConstantOptimizationIterations {
+      get { return ConstantOptimizationIterationsParameter.Value.Value; }
+      set { ConstantOptimizationIterationsParameter.Value.Value = value; }
+    }
+    public bool ScaleVariables {
+      get { return ScaleVariablesParameter.Value.Value; }
+      set { ScaleVariablesParameter.Value.Value = value; }
+    }
+    public bool CreateSolution {
+      get { return CreateSolutionParameter.Value.Value; }
+      set { CreateSolutionParameter.Value.Value = value; }
+    }
+    #endregion
+
+    [StorableConstructor]
+    protected MctsSymbolicRegressionAlgorithm(bool deserializing) : base(deserializing) { }
+
+    protected MctsSymbolicRegressionAlgorithm(MctsSymbolicRegressionAlgorithm original, Cloner cloner)
+      : base(original, cloner) {
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new MctsSymbolicRegressionAlgorithm(this, cloner);
+    }
+
+    public MctsSymbolicRegressionAlgorithm() {
+      Problem = new RegressionProblem(); // default problem
+
+      var defaultFactorsList = new CheckedItemList<StringValue>(
+        new string[] { VariableProductFactorName, ExpFactorName, LogFactorName, InvFactorName, FactorSumsName }
+        .Select(s => new StringValue(s).AsReadOnly())
+        ).AsReadOnly();
+      defaultFactorsList.SetItemCheckedState(defaultFactorsList.First(s => s.Value == FactorSumsName), false);
+
+      Parameters.Add(new FixedValueParameter<IntValue>(IterationsParameterName,
+        "Number of iterations", new IntValue(100000)));
+      Parameters.Add(new FixedValueParameter<IntValue>(SeedParameterName,
+        "The random seed used to initialize the new pseudo random number generator.", new IntValue(0)));
+      Parameters.Add(new FixedValueParameter<BoolValue>(SetSeedRandomlyParameterName,
+        "True if the random seed should be set to a random value, otherwise false.", new BoolValue(true)));
+      Parameters.Add(new FixedValueParameter<IntValue>(MaxVariablesParameterName,
+        "Maximal number of variables references in the symbolic regression models (multiple usages of the same variable are counted)", new IntValue(5)));
+      // Parameters.Add(new FixedValueParameter<DoubleValue>(CParameterName,
+      //   "Balancing parameter in UCT formula (0 < c < 1000). Small values: greedy search. Large values: enumeration. Default: 1.0", new DoubleValue(1.0)));
+      Parameters.Add(new ValueParameter<IPolicy>(PolicyParameterName,
+        "The policy to use for selecting nodes in MCTS (e.g. Ucb)", new Ucb()));
+      PolicyParameter.Hidden = true;
+      Parameters.Add(new ValueParameter<ICheckedItemList<StringValue>>(AllowedFactorsParameterName,
+        "Choose which expressions are allowed as factors in the model.", defaultFactorsList));
+
+      Parameters.Add(new FixedValueParameter<IntValue>(ConstantOptimizationIterationsParameterName,
+        "Number of iterations for constant optimization. A small number of iterations should be sufficient for most models. " +
+        "Set to 0 to disable constants optimization.", new IntValue(10)));
+      Parameters.Add(new FixedValueParameter<BoolValue>(ScaleVariablesParameterName,
+        "Set to true to scale all input variables to the range [0..1]", new BoolValue(false)));
+      Parameters[ScaleVariablesParameterName].Hidden = true;
+      Parameters.Add(new FixedValueParameter<DoubleValue>(PunishmentFactorParameterName, "Estimations of models can be bounded. The estimation limits are calculated in the following way (lb = mean(y) - punishmentFactor*range(y), ub = mean(y) + punishmentFactor*range(y))", new DoubleValue(10)));
+      Parameters[PunishmentFactorParameterName].Hidden = true;
+      Parameters.Add(new FixedValueParameter<IntValue>(UpdateIntervalParameterName,
+        "Number of iterations until the results are updated", new IntValue(100)));
+      Parameters[UpdateIntervalParameterName].Hidden = true;
+      Parameters.Add(new FixedValueParameter<BoolValue>(CreateSolutionParameterName,
+        "Flag that indicates if a solution should be produced at the end of the run", new BoolValue(true)));
+      Parameters[CreateSolutionParameterName].Hidden = true;
+    }
+
+    [StorableHook(HookType.AfterDeserialization)]
+    private void AfterDeserialization() {
+    }
+
+    protected override void Run(CancellationToken cancellationToken) {
+      // Set up the algorithm
+      if (SetSeedRandomly) Seed = new System.Random().Next();
+
+      // Set up the results display
+      var iterations = new IntValue(0);
+      Results.Add(new Result("Iterations", iterations));
+
+      var bestSolutionIteration = new IntValue(0);
+      Results.Add(new Result("Best solution iteration", bestSolutionIteration));
+
+      var table = new DataTable("Qualities");
+      table.Rows.Add(new DataRow("Best quality"));
+      table.Rows.Add(new DataRow("Current best quality"));
+      table.Rows.Add(new DataRow("Average quality"));
+      Results.Add(new Result("Qualities", table));
+
+      var bestQuality = new DoubleValue();
+      Results.Add(new Result("Best quality", bestQuality));
+
+      var curQuality = new DoubleValue();
+      Results.Add(new Result("Current best quality", curQuality));
+
+      var avgQuality = new DoubleValue();
+      Results.Add(new Result("Average quality", avgQuality));
+
+      var totalRollouts = new IntValue();
+      Results.Add(new Result("Total rollouts", totalRollouts));
+      var effRollouts = new IntValue();
+      Results.Add(new Result("Effective rollouts", effRollouts));
+      var funcEvals = new IntValue();
+      Results.Add(new Result("Function evaluations", funcEvals));
+      var gradEvals = new IntValue();
+      Results.Add(new Result("Gradient evaluations", gradEvals));
+
+
+      // same as in SymbolicRegressionSingleObjectiveProblem
+      var y = Problem.ProblemData.Dataset.GetDoubleValues(Problem.ProblemData.TargetVariable,
+        Problem.ProblemData.TrainingIndices);
+      var avgY = y.Average();
+      var minY = y.Min();
+      var maxY = y.Max();
+      var range = maxY - minY;
+      var lowerLimit = avgY - PunishmentFactor * range;
+      var upperLimit = avgY + PunishmentFactor * range;
+
+      // init
+      var problemData = (IRegressionProblemData)Problem.ProblemData.Clone();
+      if (!AllowedFactors.CheckedItems.Any()) throw new ArgumentException("At least on type of factor must be allowed");
+      var state = MctsSymbolicRegressionStatic.CreateState(problemData, (uint)Seed, MaxVariableReferences, ScaleVariables, ConstantOptimizationIterations,
+        Policy,
+        lowerLimit, upperLimit,
+        allowProdOfVars: AllowedFactors.CheckedItems.Any(s => s.Value.Value == VariableProductFactorName),
+        allowExp: AllowedFactors.CheckedItems.Any(s => s.Value.Value == ExpFactorName),
+        allowLog: AllowedFactors.CheckedItems.Any(s => s.Value.Value == LogFactorName),
+        allowInv: AllowedFactors.CheckedItems.Any(s => s.Value.Value == InvFactorName),
+        allowMultipleTerms: AllowedFactors.CheckedItems.Any(s => s.Value.Value == FactorSumsName)
+        );
+
+      var updateInterval = UpdateIntervalParameter.Value.Value;
+      double sumQ = 0.0;
+      double bestQ = 0.0;
+      double curBestQ = 0.0;
+      int n = 0;
+      // Loop until iteration limit reached or canceled.
+      for (int i = 0; i < Iterations && !state.Done; i++) {
+        cancellationToken.ThrowIfCancellationRequested();
+
+        var q = MctsSymbolicRegressionStatic.MakeStep(state);
+        sumQ += q; // sum of qs in the last updateinterval iterations
+        curBestQ = Math.Max(q, curBestQ); // the best q in the last updateinterval iterations
+        bestQ = Math.Max(q, bestQ); // the best q overall
+        n++;
+        // iteration results
+        if (n == updateInterval) {
+          if (bestQ > bestQuality.Value) {
+            bestSolutionIteration.Value = i;
+          }
+          bestQuality.Value = bestQ;
+          curQuality.Value = curBestQ;
+          avgQuality.Value = sumQ / n;
+          sumQ = 0.0;
+          curBestQ = 0.0;
+
+          funcEvals.Value = state.FuncEvaluations;
+          gradEvals.Value = state.GradEvaluations;
+          effRollouts.Value = state.EffectiveRollouts;
+          totalRollouts.Value = state.TotalRollouts;
+
+          table.Rows["Best quality"].Values.Add(bestQuality.Value);
+          table.Rows["Current best quality"].Values.Add(curQuality.Value);
+          table.Rows["Average quality"].Values.Add(avgQuality.Value);
+          iterations.Value += n;
+          n = 0;
+        }
+      }
+
+      // final results
+      if (n > 0) {
+        if (bestQ > bestQuality.Value) {
+          bestSolutionIteration.Value = iterations.Value + n;
+        }
+        bestQuality.Value = bestQ;
+        curQuality.Value = curBestQ;
+        avgQuality.Value = sumQ / n;
+
+        funcEvals.Value = state.FuncEvaluations;
+        gradEvals.Value = state.GradEvaluations;
+        effRollouts.Value = state.EffectiveRollouts;
+        totalRollouts.Value = state.TotalRollouts;
+
+        table.Rows["Best quality"].Values.Add(bestQuality.Value);
+        table.Rows["Current best quality"].Values.Add(curQuality.Value);
+        table.Rows["Average quality"].Values.Add(avgQuality.Value);
+        iterations.Value = iterations.Value + n;
+
+      }
+
+
+      Results.Add(new Result("Best solution quality (train)", new DoubleValue(state.BestSolutionTrainingQuality)));
+      Results.Add(new Result("Best solution quality (test)", new DoubleValue(state.BestSolutionTestQuality)));
+
+
+      // produce solution 
+      if (CreateSolution) {
+        var model = state.BestModel;
+
+        // otherwise we produce a regression solution
+        Results.Add(new Result("Solution", model.CreateRegressionSolution(problemData)));
+      }
+    }
+  }
+}
Index: stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/MctsSymbolicRegressionStatic.cs
===================================================================
--- stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/MctsSymbolicRegressionStatic.cs	(revision 15060)
+++ stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/MctsSymbolicRegressionStatic.cs	(revision 15060)
@@ -0,0 +1,474 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Diagnostics.Contracts;
+using System.Linq;
+using HeuristicLab.Algorithms.DataAnalysis.MctsSymbolicRegression.Policies;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
+using HeuristicLab.Problems.DataAnalysis;
+using HeuristicLab.Problems.DataAnalysis.Symbolic;
+using HeuristicLab.Problems.DataAnalysis.Symbolic.Regression;
+using HeuristicLab.Random;
+
+namespace HeuristicLab.Algorithms.DataAnalysis.MctsSymbolicRegression {
+  public static class MctsSymbolicRegressionStatic {
+    // TODO: SGD with adagrad instead of lbfgs?
+    // TODO: check Taylor expansion capabilities (ln(x), sqrt(x), exp(x)) in combination with GBT
+    // TODO: optimize for 3 targets concurrently (y, 1/y, exp(y), and log(y))? Would simplify the number of possible expressions again
+    #region static API
+
+    public interface IState {
+      bool Done { get; }
+      ISymbolicRegressionModel BestModel { get; }
+      double BestSolutionTrainingQuality { get; }
+      double BestSolutionTestQuality { get; }
+      int TotalRollouts { get; }
+      int EffectiveRollouts { get; }
+      int FuncEvaluations { get; }
+      int GradEvaluations { get; } // number of gradient evaluations (* num parameters) to get a value representative of the effort comparable to the number of function evaluations
+      // TODO other stats on LM optimizer might be interesting here
+    }
+
+    // created through factory method
+    private class State : IState {
+      private const int MaxParams = 100;
+
+      // state variables used by MCTS
+      internal readonly Automaton automaton;
+      internal IRandom random { get; private set; }
+      internal readonly Tree tree;
+      internal readonly Func<byte[], int, double> evalFun;
+      internal readonly IPolicy treePolicy;
+      // MCTS might get stuck. Track statistics on the number of effective rollouts
+      internal int totalRollouts;
+      internal int effectiveRollouts;
+
+
+      // state variables used only internally (for eval function)
+      private readonly IRegressionProblemData problemData;
+      private readonly double[][] x;
+      private readonly double[] y;
+      private readonly double[][] testX;
+      private readonly double[] testY;
+      private readonly double[] scalingFactor;
+      private readonly double[] scalingOffset;
+      private readonly int constOptIterations;
+      private readonly double lowerEstimationLimit, upperEstimationLimit;
+
+      private readonly ExpressionEvaluator evaluator, testEvaluator;
+
+      // values for best solution
+      private double bestRSq;
+      private byte[] bestCode;
+      private int bestNParams;
+      private double[] bestConsts;
+
+      // stats
+      private int funcEvaluations;
+      private int gradEvaluations;
+
+      // buffers
+      private readonly double[] ones; // vector of ones (as default params)
+      private readonly double[] constsBuf;
+      private readonly double[] predBuf, testPredBuf;
+      private readonly double[][] gradBuf;
+
+      public State(IRegressionProblemData problemData, uint randSeed, int maxVariables, bool scaleVariables, int constOptIterations,
+        IPolicy treePolicy = null,
+        double lowerEstimationLimit = double.MinValue, double upperEstimationLimit = double.MaxValue,
+        bool allowProdOfVars = true,
+        bool allowExp = true,
+        bool allowLog = true,
+        bool allowInv = true,
+        bool allowMultipleTerms = false) {
+
+        this.problemData = problemData;
+        this.constOptIterations = constOptIterations;
+        this.evalFun = this.Eval;
+        this.lowerEstimationLimit = lowerEstimationLimit;
+        this.upperEstimationLimit = upperEstimationLimit;
+
+        random = new MersenneTwister(randSeed);
+
+        // prepare data for evaluation
+        double[][] x;
+        double[] y;
+        double[][] testX;
+        double[] testY;
+        double[] scalingFactor;
+        double[] scalingOffset;
+        // get training and test datasets (scale linearly based on training set if required)
+        GenerateData(problemData, scaleVariables, problemData.TrainingIndices, out x, out y, out scalingFactor, out scalingOffset);
+        GenerateData(problemData, problemData.TestIndices, scalingFactor, scalingOffset, out testX, out testY);
+        this.x = x;
+        this.y = y;
+        this.testX = testX;
+        this.testY = testY;
+        this.scalingFactor = scalingFactor;
+        this.scalingOffset = scalingOffset;
+        this.evaluator = new ExpressionEvaluator(y.Length, lowerEstimationLimit, upperEstimationLimit);
+        // we need a separate evaluator because the vector length for the test dataset might differ 
+        this.testEvaluator = new ExpressionEvaluator(testY.Length, lowerEstimationLimit, upperEstimationLimit);
+
+        this.automaton = new Automaton(x, maxVariables, allowProdOfVars, allowExp, allowLog, allowInv, allowMultipleTerms);
+        this.treePolicy = treePolicy ?? new Ucb();
+        this.tree = new Tree() { state = automaton.CurrentState, actionStatistics = treePolicy.CreateActionStatistics() };
+
+        // reset best solution
+        this.bestRSq = 0;
+        // code for default solution (constant model)
+        this.bestCode = new byte[] { (byte)OpCodes.LoadConst0, (byte)OpCodes.Exit };
+        this.bestNParams = 0;
+        this.bestConsts = null;
+
+        // init buffers
+        this.ones = Enumerable.Repeat(1.0, MaxParams).ToArray();
+        constsBuf = new double[MaxParams];
+        this.predBuf = new double[y.Length];
+        this.testPredBuf = new double[testY.Length];
+
+        this.gradBuf = Enumerable.Range(0, MaxParams).Select(_ => new double[y.Length]).ToArray();
+      }
+
+      #region IState inferface
+      public bool Done { get { return tree != null && tree.Done; } }
+
+      public double BestSolutionTrainingQuality {
+        get {
+          evaluator.Exec(bestCode, x, bestConsts, predBuf);
+          return RSq(y, predBuf);
+        }
+      }
+
+      public double BestSolutionTestQuality {
+        get {
+          testEvaluator.Exec(bestCode, testX, bestConsts, testPredBuf);
+          return RSq(testY, testPredBuf);
+        }
+      }
+
+      // takes the code of the best solution and creates and equivalent symbolic regression model
+      public ISymbolicRegressionModel BestModel {
+        get {
+          var treeGen = new SymbolicExpressionTreeGenerator(problemData.AllowedInputVariables.ToArray());
+          var interpreter = new SymbolicDataAnalysisExpressionTreeLinearInterpreter();
+
+          var t = new SymbolicExpressionTree(treeGen.Exec(bestCode, bestConsts, bestNParams, scalingFactor, scalingOffset));
+          var model = new SymbolicRegressionModel(t, interpreter, lowerEstimationLimit, upperEstimationLimit);
+
+          // model has already been scaled linearly in Eval
+          return model;
+        }
+      }
+
+      public int TotalRollouts { get { return totalRollouts; } }
+      public int EffectiveRollouts { get { return effectiveRollouts; } }
+      public int FuncEvaluations { get { return funcEvaluations; } }
+      public int GradEvaluations { get { return gradEvaluations; } } // number of gradient evaluations (* num parameters) to get a value representative of the effort comparable to the number of function evaluations
+
+      #endregion
+
+      private double Eval(byte[] code, int nParams) {
+        double[] optConsts;
+        double q;
+        Eval(code, nParams, out q, out optConsts);
+
+        if (q > bestRSq) {
+          bestRSq = q;
+          bestNParams = nParams;
+          this.bestCode = new byte[code.Length];
+          this.bestConsts = new double[bestNParams];
+
+          Array.Copy(code, bestCode, code.Length);
+          Array.Copy(optConsts, bestConsts, bestNParams);
+        }
+
+        return q;
+      }
+
+      private void Eval(byte[] code, int nParams, out double rsq, out double[] optConsts) {
+        // we make a first pass to determine a valid starting configuration for all constants
+        // constant c in log(c + f(x)) is adjusted to guarantee that x is positive (see expression evaluator)
+        // scale and offset are set to optimal starting configuration
+        // assumes scale is the first param and offset is the last param
+        double alpha;
+        double beta;
+
+        // reset constants
+        Array.Copy(ones, constsBuf, nParams);
+        evaluator.Exec(code, x, constsBuf, predBuf, adjustOffsetForLogAndExp: true);
+        funcEvaluations++;
+
+        // calc opt scaling (alpha*f(x) + beta)
+        OnlineCalculatorError error;
+        OnlineLinearScalingParameterCalculator.Calculate(predBuf, y, out alpha, out beta, out error);
+        if (error == OnlineCalculatorError.None) {
+          constsBuf[0] *= beta;
+          constsBuf[nParams - 1] = constsBuf[nParams - 1] * beta + alpha;
+        }
+        if (nParams <= 2 || constOptIterations <= 0) {
+          // if we don't need to optimize parameters then we are done
+          // changing scale and offset does not influence r²
+          rsq = RSq(y, predBuf);
+          optConsts = constsBuf;
+        } else {
+          // optimize constants using the starting point calculated above
+          OptimizeConstsLm(code, constsBuf, nParams, 0.0, nIters: constOptIterations);
+
+          evaluator.Exec(code, x, constsBuf, predBuf);
+          funcEvaluations++;
+
+          rsq = RSq(y, predBuf);
+          optConsts = constsBuf;
+        }
+      }
+
+
+
+      #region helpers
+      private static double RSq(IEnumerable<double> x, IEnumerable<double> y) {
+        OnlineCalculatorError error;
+        double r = OnlinePearsonsRCalculator.Calculate(x, y, out error);
+        return error == OnlineCalculatorError.None ? r * r : 0.0;
+      }
+
+
+      private void OptimizeConstsLm(byte[] code, double[] consts, int nParams, double epsF = 0.0, int nIters = 100) {
+        double[] optConsts = new double[nParams]; // allocate a smaller buffer for constants opt (TODO perf?)
+        Array.Copy(consts, optConsts, nParams);
+
+        alglib.minlmstate state;
+        alglib.minlmreport rep = null;
+        alglib.minlmcreatevj(y.Length, optConsts, out state);
+        alglib.minlmsetcond(state, 0.0, epsF, 0.0, nIters);
+        //alglib.minlmsetgradientcheck(state, 0.000001);
+        alglib.minlmoptimize(state, Func, FuncAndJacobian, null, code);
+        alglib.minlmresults(state, out optConsts, out rep);
+        funcEvaluations += rep.nfunc;
+        gradEvaluations += rep.njac * nParams;
+
+        if (rep.terminationtype < 0) throw new ArgumentException("lm failed: termination type = " + rep.terminationtype);
+
+        // only use optimized constants if successful
+        if (rep.terminationtype >= 0) {
+          Array.Copy(optConsts, consts, optConsts.Length);
+        }
+      }
+
+      private void Func(double[] arg, double[] fi, object obj) {
+        var code = (byte[])obj;
+        evaluator.Exec(code, x, arg, predBuf); // gradients are nParams x vLen
+        for (int r = 0; r < predBuf.Length; r++) {
+          var res = predBuf[r] - y[r];
+          fi[r] = res;
+        }
+      }
+      private void FuncAndJacobian(double[] arg, double[] fi, double[,] jac, object obj) {
+        int nParams = arg.Length;
+        var code = (byte[])obj;
+        evaluator.ExecGradient(code, x, arg, predBuf, gradBuf); // gradients are nParams x vLen
+        for (int r = 0; r < predBuf.Length; r++) {
+          var res = predBuf[r] - y[r];
+          fi[r] = res;
+
+          for (int k = 0; k < nParams; k++) {
+            jac[r, k] = gradBuf[k][r];
+          }
+        }
+      }
+      #endregion
+    }
+
+    public static IState CreateState(IRegressionProblemData problemData, uint randSeed, int maxVariables = 3,
+      bool scaleVariables = true, int constOptIterations = 0,
+      IPolicy policy = null,
+      double lowerEstimationLimit = double.MinValue, double upperEstimationLimit = double.MaxValue,
+      bool allowProdOfVars = true,
+      bool allowExp = true,
+      bool allowLog = true,
+      bool allowInv = true,
+      bool allowMultipleTerms = false
+      ) {
+      return new State(problemData, randSeed, maxVariables, scaleVariables, constOptIterations,
+        policy,
+        lowerEstimationLimit, upperEstimationLimit,
+        allowProdOfVars, allowExp, allowLog, allowInv, allowMultipleTerms);
+    }
+
+    // returns the quality of the evaluated solution
+    public static double MakeStep(IState state) {
+      var mctsState = state as State;
+      if (mctsState == null) throw new ArgumentException("state");
+      if (mctsState.Done) throw new NotSupportedException("The tree search has enumerated all possible solutions.");
+
+      return TreeSearch(mctsState);
+    }
+    #endregion
+
+    private static double TreeSearch(State mctsState) {
+      var automaton = mctsState.automaton;
+      var tree = mctsState.tree;
+      var eval = mctsState.evalFun;
+      var rand = mctsState.random;
+      var treePolicy = mctsState.treePolicy;
+      double q = 0;
+      bool success = false;
+      do {
+        automaton.Reset();
+        success = TryTreeSearchRec(rand, tree, automaton, eval, treePolicy, out q);
+        mctsState.totalRollouts++;
+      } while (!success && !tree.Done);
+      mctsState.effectiveRollouts++;
+      return q;
+    }
+
+    // tree search might fail because of constraints for expressions
+    // in this case we get stuck we just restart
+    // see ConstraintHandler.cs for more info
+    private static bool TryTreeSearchRec(IRandom rand, Tree tree, Automaton automaton, Func<byte[], int, double> eval, IPolicy treePolicy,
+      out double q) {
+      Tree selectedChild = null;
+      Contract.Assert(tree.state == automaton.CurrentState);
+      Contract.Assert(!tree.Done);
+      if (tree.children == null) {
+        if (automaton.IsFinalState(tree.state)) {
+          // final state
+          tree.Done = true;
+
+          // EVALUATE
+          byte[] code; int nParams;
+          automaton.GetCode(out code, out nParams);
+          q = eval(code, nParams);
+
+          treePolicy.Update(tree.actionStatistics, q);
+          return true; // we reached a final state
+        } else {
+          // EXPAND 
+          int[] possibleFollowStates;
+          int nFs;
+          automaton.FollowStates(automaton.CurrentState, out possibleFollowStates, out nFs);
+          if (nFs == 0) {
+            // stuck in a dead end (no final state and no allowed follow states)
+            q = 0;
+            tree.Done = true;
+            tree.children = null;
+            return false;
+          }
+          tree.children = new Tree[nFs];
+          for (int i = 0; i < tree.children.Length; i++)
+            tree.children[i] = new Tree() { children = null, state = possibleFollowStates[i], actionStatistics = treePolicy.CreateActionStatistics() };
+
+          selectedChild = nFs > 1 ? SelectFinalOrRandom(automaton, tree, rand) : tree.children[0];
+        }
+      } else {
+        // tree.children != null
+        // UCT selection within tree
+        int selectedIdx = 0;
+        if (tree.children.Length > 1) {
+          selectedIdx = treePolicy.Select(tree.children.Select(ch => ch.actionStatistics), rand);
+        }
+        selectedChild = tree.children[selectedIdx];
+      }
+      // make selected step and recurse
+      automaton.Goto(selectedChild.state);
+      var success = TryTreeSearchRec(rand, selectedChild, automaton, eval, treePolicy, out q);
+      if (success) {
+        // only update if successful
+        treePolicy.Update(tree.actionStatistics, q);
+      }
+
+      tree.Done = tree.children.All(ch => ch.Done);
+      if (tree.Done) {
+        tree.children = null; // cut off the sub-branch if it has been fully explored
+      }
+      return success;
+    }
+
+    private static Tree SelectFinalOrRandom(Automaton automaton, Tree tree, IRandom rand) {
+      // if one of the new children leads to a final state then go there
+      // otherwise choose a random child
+      int selectedChildIdx = -1;
+      // find first final state if there is one
+      for (int i = 0; i < tree.children.Length; i++) {
+        if (automaton.IsFinalState(tree.children[i].state)) {
+          selectedChildIdx = i;
+          break;
+        }
+      }
+      // no final state -> select a the first child
+      if (selectedChildIdx == -1) {
+        selectedChildIdx = 0;
+      }
+      return tree.children[selectedChildIdx];
+    }
+
+    // scales data and extracts values from dataset into arrays
+    private static void GenerateData(IRegressionProblemData problemData, bool scaleVariables, IEnumerable<int> rows,
+      out double[][] xs, out double[] y, out double[] scalingFactor, out double[] scalingOffset) {
+      xs = new double[problemData.AllowedInputVariables.Count()][];
+
+      var i = 0;
+      if (scaleVariables) {
+        scalingFactor = new double[xs.Length];
+        scalingOffset = new double[xs.Length];
+      } else {
+        scalingFactor = null;
+        scalingOffset = null;
+      }
+      foreach (var var in problemData.AllowedInputVariables) {
+        if (scaleVariables) {
+          var minX = problemData.Dataset.GetDoubleValues(var, rows).Min();
+          var maxX = problemData.Dataset.GetDoubleValues(var, rows).Max();
+          var range = maxX - minX;
+
+          // scaledX = (x - min) / range
+          var sf = 1.0 / range;
+          var offset = -minX / range;
+          scalingFactor[i] = sf;
+          scalingOffset[i] = offset;
+          i++;
+        }
+      }
+
+      GenerateData(problemData, rows, scalingFactor, scalingOffset, out xs, out y);
+    }
+
+    // extract values from dataset into arrays
+    private static void GenerateData(IRegressionProblemData problemData, IEnumerable<int> rows, double[] scalingFactor, double[] scalingOffset,
+     out double[][] xs, out double[] y) {
+      xs = new double[problemData.AllowedInputVariables.Count()][];
+
+      int i = 0;
+      foreach (var var in problemData.AllowedInputVariables) {
+        var sf = scalingFactor == null ? 1.0 : scalingFactor[i];
+        var offset = scalingFactor == null ? 0.0 : scalingOffset[i];
+        xs[i++] =
+          problemData.Dataset.GetDoubleValues(var, rows).Select(xi => xi * sf + offset).ToArray();
+      }
+
+      y = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, rows).ToArray();
+    }
+  }
+}
Index: stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/OpCodes.cs
===================================================================
--- stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/OpCodes.cs	(revision 15060)
+++ stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/OpCodes.cs	(revision 15060)
@@ -0,0 +1,36 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
+ * 
+ * This file is part of HeuristicLab.
+ *
+ * HeuristicLab is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * HeuristicLab is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
+ */
+#endregion
+
+namespace HeuristicLab.Algorithms.DataAnalysis.MctsSymbolicRegression {
+  internal enum OpCodes : byte {
+    Nop,
+    LoadConst0,
+    LoadConst1, // load the constant 1
+    LoadParamN, // load next parameter 
+    LoadVar,    // + 2 byte parameters
+    Mul,
+    Add,
+    Log,
+    Exp,
+    Inv,
+    Exit
+  }
+}
Index: stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Policies/EpsGreedy.cs
===================================================================
--- stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Policies/EpsGreedy.cs	(revision 15060)
+++ stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Policies/EpsGreedy.cs	(revision 15060)
@@ -0,0 +1,93 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Diagnostics.Contracts;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.DataAnalysis.MctsSymbolicRegression.Policies {
+  [StorableClass]
+  [Item("EpsilonGreedy", "Epsilon greedy policy with parameter eps to balance between exploitation and exploration")]
+  public class EpsilonGreedy : PolicyBase {
+    private class ActionStatistics : IActionStatistics {
+      public double SumQuality { get; set; }
+      public double AverageQuality { get { return SumQuality / Tries; } }
+      public int Tries { get; set; }
+      public bool Done { get; set; }
+    }
+    private List<int> buf = new List<int>();
+
+    public IFixedValueParameter<DoubleValue> EpsParameter {
+      get { return (IFixedValueParameter<DoubleValue>)Parameters["Eps"]; }
+    }
+
+    public double Eps {
+      get { return EpsParameter.Value.Value; }
+      set { EpsParameter.Value.Value = value; }
+    }
+
+    [StorableConstructor]
+    protected EpsilonGreedy(bool deserializing) : base(deserializing) { }
+    protected EpsilonGreedy(EpsilonGreedy original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public EpsilonGreedy()
+      : base() {
+      Parameters.Add(new FixedValueParameter<DoubleValue>("Eps", "Rate of random selection 0 (greedy) <= eps <= 1 (random)", new DoubleValue(0.1)));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new EpsilonGreedy(this, cloner);
+    }
+
+    public override int Select(IEnumerable<IActionStatistics> actions, IRandom random) {
+      return Select(actions, random, Eps, buf);
+    }
+
+    public override void Update(IActionStatistics action, double q) {
+      var a = action as ActionStatistics;
+      a.SumQuality += q;
+      a.Tries++;
+    }
+
+    public override IActionStatistics CreateActionStatistics() {
+      return new ActionStatistics();
+    }
+
+    private static int Select(IEnumerable<IActionStatistics> actions, IRandom rand, double c, IList<int> buf) {
+      buf.Clear();
+      if (rand.NextDouble() >= c) {
+        // select best
+        var bestQ = double.NegativeInfinity;
+        int aIdx = -1;
+        foreach (var a in actions) {
+          ++aIdx;
+          if (a.Done) continue;
+          var actionQ = a.Tries > 0 ? a.AverageQuality : double.PositiveInfinity; // always try unvisited actions first
+          if (actionQ > bestQ) {
+            buf.Clear();
+            buf.Add(aIdx);
+            bestQ = actionQ;
+          } else if (actionQ >= bestQ) {
+            buf.Add(aIdx);
+          }
+        }
+        return buf[rand.Next(buf.Count)];
+      } else {
+        // random selection
+        int aIdx = -1;
+        foreach (var a in actions) {
+          ++aIdx;
+          if (a.Done) continue;
+          buf.Add(aIdx);
+        }
+        return buf[rand.Next(buf.Count)];
+      }
+    }
+  }
+}
Index: stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Policies/IActionStatistics.cs
===================================================================
--- stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Policies/IActionStatistics.cs	(revision 15060)
+++ stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Policies/IActionStatistics.cs	(revision 15060)
@@ -0,0 +1,13 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace HeuristicLab.Algorithms.DataAnalysis.MctsSymbolicRegression.Policies {
+  public interface IActionStatistics {
+    double AverageQuality { get; }
+    int Tries { get; }
+    bool Done { get; set; }
+  }
+}
Index: stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Policies/IPolicy.cs
===================================================================
--- stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Policies/IPolicy.cs	(revision 15060)
+++ stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Policies/IPolicy.cs	(revision 15060)
@@ -0,0 +1,14 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using HeuristicLab.Core;
+
+namespace HeuristicLab.Algorithms.DataAnalysis.MctsSymbolicRegression.Policies {
+  public interface IPolicy : IItem {
+    int Select(IEnumerable<IActionStatistics> actions, IRandom random);
+    void Update(IActionStatistics action, double q);
+    IActionStatistics CreateActionStatistics();
+  }
+}
Index: stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Policies/PolicyBase.cs
===================================================================
--- stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Policies/PolicyBase.cs	(revision 15060)
+++ stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Policies/PolicyBase.cs	(revision 15060)
@@ -0,0 +1,36 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Diagnostics.Contracts;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.DataAnalysis.MctsSymbolicRegression.Policies {
+  [StorableClass]
+  public abstract class PolicyBase : Item, IParameterizedItem, IPolicy {
+    [Storable]
+    public IKeyedItemCollection<string, IParameter> Parameters { get; private set; }
+
+    [StorableConstructor]
+    protected PolicyBase(bool deserializing) : base(deserializing) { }
+    protected PolicyBase(PolicyBase original, Cloner cloner)
+      : base(original, cloner) {
+      Parameters = cloner.Clone(original.Parameters);
+    }
+    protected PolicyBase()
+      : base() {
+      Parameters = new ParameterCollection();
+    }
+
+    public void CollectParameterValues(IDictionary<string, IItem> values) {
+      foreach (var p in Parameters) values.Add(this.ItemName + "." + p.Name, p.ActualValue);
+    }
+
+    public abstract int Select(IEnumerable<IActionStatistics> actions, IRandom random);
+    public abstract void Update(IActionStatistics action, double q);
+    public abstract IActionStatistics CreateActionStatistics();
+  }
+}
Index: stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Policies/Ucb.cs
===================================================================
--- stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Policies/Ucb.cs	(revision 15060)
+++ stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Policies/Ucb.cs	(revision 15060)
@@ -0,0 +1,97 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Diagnostics.Contracts;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.DataAnalysis.MctsSymbolicRegression.Policies {
+  [StorableClass]
+  [Item("Ucb Policy", "Ucb with parameter c to balance between exploitation and exploration")]
+  public class Ucb : PolicyBase {
+    private class ActionStatistics : IActionStatistics {
+      public double SumQuality { get; set; }
+      public double AverageQuality { get { return SumQuality / Tries; } }
+      public int Tries { get; set; }
+      public bool Done { get; set; }
+    }
+    private List<int> buf = new List<int>();
+
+    public IFixedValueParameter<DoubleValue> CParameter {
+      get { return (IFixedValueParameter<DoubleValue>)Parameters["C"]; }
+    }
+
+    public double C {
+      get { return CParameter.Value.Value; }
+      set { CParameter.Value.Value = value; }
+    }
+
+    [StorableConstructor]
+    protected Ucb(bool deserializing) : base(deserializing) { }
+    protected Ucb(Ucb original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public Ucb()
+      : base() {
+      Parameters.Add(new FixedValueParameter<DoubleValue>("C", "Parameter to balance between exploration and exploitation 0 <= c < 100", new DoubleValue(Math.Sqrt(2))));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new Ucb(this, cloner);
+    }
+
+    public override int Select(IEnumerable<IActionStatistics> actions, IRandom random) {
+      return Select(actions, random, C, buf);
+    }
+
+    public override void Update(IActionStatistics action, double q) {
+      var a = action as ActionStatistics;
+      a.SumQuality += q;
+      a.Tries++;
+    }
+
+    public override IActionStatistics CreateActionStatistics() {
+      return new ActionStatistics();
+    }
+
+    private static int Select(IEnumerable<IActionStatistics> actions, IRandom rand, double c, IList<int> buf) {
+      // determine total tries of still active actions
+      int totalTries = 0;
+      buf.Clear();
+      int aIdx = -1;
+      foreach (var a in actions) {
+        ++aIdx;
+        if (a.Done) continue;
+        if (a.Tries == 0) buf.Add(aIdx);
+        else totalTries += a.Tries;
+      }
+      // if there are unvisited actions select a random action
+      if (buf.Any()) {
+        return buf[rand.Next(buf.Count)];
+      }
+      Contract.Assert(totalTries > 0);
+      double logTotalTries = Math.Log(totalTries);
+      var bestQ = double.NegativeInfinity;
+      aIdx = -1;
+      foreach (var a in actions) {
+        ++aIdx;
+        if (a.Done) continue;
+        var actionQ = a.AverageQuality + c * Math.Sqrt(logTotalTries / a.Tries);
+        if (actionQ > bestQ) {
+          buf.Clear();
+          buf.Add(aIdx);
+          bestQ = actionQ;
+        } else if (actionQ >= bestQ) {
+          buf.Add(aIdx);
+        }
+      }
+      return buf[rand.Next(buf.Count)];
+    }
+
+  }
+}
Index: stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Policies/UcbTuned.cs
===================================================================
--- stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Policies/UcbTuned.cs	(revision 15060)
+++ stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Policies/UcbTuned.cs	(revision 15060)
@@ -0,0 +1,101 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Diagnostics.Contracts;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using HeuristicLab.Common;
+using HeuristicLab.Core;
+using HeuristicLab.Data;
+using HeuristicLab.Parameters;
+using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
+
+namespace HeuristicLab.Algorithms.DataAnalysis.MctsSymbolicRegression.Policies {
+  [StorableClass]
+  [Item("UcbTuned Policy", "UcbTuned is similar to Ucb but tracks empirical variance. Use parameter c to balance between exploitation and exploration")]
+  public class UcbTuned : PolicyBase {
+    private class ActionStatistics : IActionStatistics {
+      public double SumQuality { get; set; }
+      public double SumSqrQuality { get; set; }
+      public double AverageQuality { get { return SumQuality / Tries; } }
+      public double QualityVariance { get { return SumSqrQuality / Tries - AverageQuality * AverageQuality; } }
+      public int Tries { get; set; }
+      public bool Done { get; set; }
+    }
+    private List<int> buf = new List<int>();
+
+    public IFixedValueParameter<DoubleValue> CParameter {
+      get { return (IFixedValueParameter<DoubleValue>)Parameters["C"]; }
+    }
+
+    public double C {
+      get { return CParameter.Value.Value; }
+      set { CParameter.Value.Value = value; }
+    }
+
+    [StorableConstructor]
+    protected UcbTuned(bool deserializing) : base(deserializing) { }
+    protected UcbTuned(UcbTuned original, Cloner cloner)
+      : base(original, cloner) {
+    }
+    public UcbTuned()
+      : base() {
+      Parameters.Add(new FixedValueParameter<DoubleValue>("C", "Parameter to balance between exploration and exploitation 0 <= c < 100", new DoubleValue(Math.Sqrt(2))));
+    }
+
+    public override IDeepCloneable Clone(Cloner cloner) {
+      return new UcbTuned(this, cloner);
+    }
+
+    public override int Select(IEnumerable<IActionStatistics> actions, IRandom random) {
+      return Select(actions, random, C, buf);
+    }
+
+    public override void Update(IActionStatistics action, double q) {
+      var a = action as ActionStatistics;
+      a.SumQuality += q;
+      a.SumSqrQuality += q * q;
+      a.Tries++;
+    }
+
+    public override IActionStatistics CreateActionStatistics() {
+      return new ActionStatistics();
+    }
+
+    private static int Select(IEnumerable<IActionStatistics> actions, IRandom rand, double c, IList<int> buf) {
+      // determine total tries of still active actions
+      int totalTries = 0;
+      buf.Clear();
+      int aIdx = -1;
+      foreach (var a in actions) {
+        ++aIdx;
+        if (a.Done) continue;
+        if (a.Tries == 0) buf.Add(aIdx);
+        else totalTries += a.Tries;
+      }
+      // if there are unvisited actions select a random action
+      if (buf.Any()) {
+        return buf[rand.Next(buf.Count)];
+      }
+      Contract.Assert(totalTries > 0);
+      double logTotalTries = Math.Log(totalTries);
+      var bestQ = double.NegativeInfinity;
+      aIdx = -1;
+      foreach (var a in actions.Cast<ActionStatistics>()) {
+        ++aIdx;
+        if (a.Done) continue;
+        var varianceBound = a.QualityVariance + Math.Sqrt(2.0 * logTotalTries / a.Tries);
+        if (varianceBound > 0.25) varianceBound = 0.25;
+        var actionQ = a.AverageQuality + c * Math.Sqrt(logTotalTries / a.Tries * varianceBound);
+        if (actionQ > bestQ) {
+          buf.Clear();
+          buf.Add(aIdx);
+          bestQ = actionQ;
+        } else if (actionQ >= bestQ) {
+          buf.Add(aIdx);
+        }
+      }
+      return buf[rand.Next(buf.Count)];
+    }
+  }
+}
Index: stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/SymbolicExpressionGenerator.cs
===================================================================
--- stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/SymbolicExpressionGenerator.cs	(revision 15060)
+++ stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/SymbolicExpressionGenerator.cs	(revision 15060)
@@ -0,0 +1,183 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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.Diagnostics.Contracts;
+using System.Linq;
+
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
+using HeuristicLab.Problems.DataAnalysis.Symbolic;
+
+namespace HeuristicLab.Algorithms.DataAnalysis.MctsSymbolicRegression {
+
+  // translates byte code to a symbolic expression tree
+  internal class SymbolicExpressionTreeGenerator {
+    const int MaxStackSize = 100;
+    private readonly ISymbolicExpressionTreeNode[] stack;
+    private readonly ConstantTreeNode const0;
+    private readonly ConstantTreeNode const1;
+    private readonly Addition addSy;
+    private readonly Multiplication mulSy;
+    private readonly Exponential expSy;
+    private readonly Logarithm logSy;
+    private readonly Division divSy;
+    private readonly VariableTreeNode varNode;
+    private readonly string[] variableNames;
+    private readonly StartSymbol startSy;
+    private readonly ProgramRootSymbol progRootSy;
+
+    public SymbolicExpressionTreeGenerator(string[] variableNames) {
+      stack = new ISymbolicExpressionTreeNode[MaxStackSize];
+      var grammar = new TypeCoherentExpressionGrammar();
+      this.variableNames = variableNames;
+
+      grammar.ConfigureAsDefaultRegressionGrammar();
+      const0 = (ConstantTreeNode)grammar.Symbols.OfType<Constant>().First().CreateTreeNode();
+      const0.Value = 0;
+      const1 = (ConstantTreeNode)grammar.Symbols.OfType<Constant>().First().CreateTreeNode();
+      const1.Value = 1;
+      varNode = (VariableTreeNode)grammar.Symbols.OfType<Variable>().First().CreateTreeNode();
+
+      addSy = grammar.AllowedSymbols.OfType<Addition>().First();
+      mulSy = grammar.AllowedSymbols.OfType<Multiplication>().First();
+      logSy = grammar.AllowedSymbols.OfType<Logarithm>().First();
+      expSy = grammar.AllowedSymbols.OfType<Exponential>().First();
+      divSy = grammar.AllowedSymbols.OfType<Division>().First();
+
+      progRootSy = grammar.AllowedSymbols.OfType<ProgramRootSymbol>().First();
+      startSy = grammar.AllowedSymbols.OfType<StartSymbol>().First();
+    }
+
+    public ISymbolicExpressionTreeNode Exec(byte[] code, double[] consts, int nParams, double[] scalingFactor, double[] scalingOffset) {
+      int topOfStack = -1;
+      int pc = 0;
+      int nextParamIdx = -1;
+      OpCodes op;
+      short arg;
+      while (true) {
+        ReadNext(code, ref pc, out op, out arg);
+        switch (op) {
+          case OpCodes.Nop: break;
+          case OpCodes.LoadConst0: {
+              ++topOfStack;
+              stack[topOfStack] = (ISymbolicExpressionTreeNode)const0.Clone();
+              break;
+            }
+          case OpCodes.LoadConst1: {
+              ++topOfStack;
+              stack[topOfStack] = (ISymbolicExpressionTreeNode)const1.Clone();
+              break;
+            }
+          case OpCodes.LoadParamN: {
+              ++topOfStack;
+              var p = (ConstantTreeNode)const1.Clone(); // value will be tuned later (evaluator and tree generator both use 1 as initial values)
+              p.Value = consts[++nextParamIdx];
+              stack[topOfStack] = p;
+              break;
+            }
+          case OpCodes.LoadVar:
+            ++topOfStack;
+            if (scalingOffset != null) {
+              var sumNode = addSy.CreateTreeNode();
+              var varNode = (VariableTreeNode)this.varNode.Clone();
+              var constNode = (ConstantTreeNode)const0.Clone();
+              varNode.Weight = scalingFactor[arg];
+              varNode.VariableName = variableNames[arg];
+              constNode.Value = scalingOffset[arg];
+              sumNode.AddSubtree(varNode);
+              sumNode.AddSubtree(constNode);
+              stack[topOfStack] = sumNode;
+            } else {
+              var varNode = (VariableTreeNode)this.varNode.Clone();
+              varNode.Weight = 1.0;
+              varNode.VariableName = variableNames[arg];
+              stack[topOfStack] = varNode;
+            }
+            break;
+          case OpCodes.Add: {
+              var t1 = stack[topOfStack - 1];
+              var t2 = stack[topOfStack];
+              topOfStack--;
+              if (t1.Symbol is Addition) {
+                t1.AddSubtree(t2);
+              } else {
+                var addNode = addSy.CreateTreeNode();
+                addNode.AddSubtree(t1);
+                addNode.AddSubtree(t2);
+                stack[topOfStack] = addNode;
+              }
+              break;
+            }
+          case OpCodes.Mul: {
+              var t1 = stack[topOfStack - 1];
+              var t2 = stack[topOfStack];
+              topOfStack--;
+              if (t1.Symbol is Multiplication) {
+                t1.AddSubtree(t2);
+              } else {
+                var mulNode = mulSy.CreateTreeNode();
+                mulNode.AddSubtree(t1);
+                mulNode.AddSubtree(t2);
+                stack[topOfStack] = mulNode;
+              }
+              break;
+            }
+          case OpCodes.Log: {
+              var v1 = stack[topOfStack];
+              var logNode = logSy.CreateTreeNode();
+              logNode.AddSubtree(v1);
+              stack[topOfStack] = logNode;
+              break;
+            }
+          case OpCodes.Exp: {
+              var v1 = stack[topOfStack];
+              var expNode = expSy.CreateTreeNode();
+              expNode.AddSubtree(v1);
+              stack[topOfStack] = expNode;
+              break;
+            }
+          case OpCodes.Inv: {
+              var v1 = stack[topOfStack];
+              var divNode = divSy.CreateTreeNode();
+              divNode.AddSubtree(v1);
+              stack[topOfStack] = divNode;
+              break;
+            }
+          case OpCodes.Exit:
+            Contract.Assert(topOfStack == 0);
+            var rootNode = progRootSy.CreateTreeNode();
+            var startNode = startSy.CreateTreeNode();
+            startNode.AddSubtree(stack[topOfStack]);
+            rootNode.AddSubtree(startNode);
+            return rootNode;
+        }
+      }
+    }
+
+    private void ReadNext(byte[] code, ref int pc, out OpCodes op, out short s) {
+      op = (OpCodes)Enum.ToObject(typeof(OpCodes), code[pc++]);
+      s = 0;
+      if (op == OpCodes.LoadVar) {
+        s = (short)((code[pc] << 8) | code[pc + 1]);
+        pc += 2;
+      }
+    }
+  }
+}
Index: stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Tree.cs
===================================================================
--- stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Tree.cs	(revision 15060)
+++ stable/HeuristicLab.Algorithms.DataAnalysis/3.4/MctsSymbolicRegression/Tree.cs	(revision 15060)
@@ -0,0 +1,35 @@
+﻿#region License Information
+/* HeuristicLab
+ * Copyright (C) 2002-2015 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 HeuristicLab.Algorithms.DataAnalysis.MctsSymbolicRegression.Policies;
+
+namespace HeuristicLab.Algorithms.DataAnalysis.MctsSymbolicRegression {
+  // represents tree nodes for the search tree in MCTS
+  internal class Tree {
+    public int state;
+    public bool Done {
+      get { return actionStatistics.Done; }
+      set { actionStatistics.Done = value; }
+    }
+    public IActionStatistics actionStatistics;
+    public Tree[] children;
+  }
+}
