Index: branches/2994-AutoDiffForIntervals/HeuristicLab 3.3.sln
===================================================================
--- branches/2994-AutoDiffForIntervals/HeuristicLab 3.3.sln	(revision 16673)
+++ branches/2994-AutoDiffForIntervals/HeuristicLab 3.3.sln	(revision 16674)
@@ -462,4 +462,6 @@
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HeuristicLab.Algorithms.MOCMAEvolutionStrategy-3.3", "HeuristicLab.Algorithms.MOCMAEvolutionStrategy\3.3\HeuristicLab.Algorithms.MOCMAEvolutionStrategy-3.3.csproj", "{0E2E224F-E9B2-41F3-B510-09183EEBA2AF}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{792B51DB-F5AC-4EED-B165-8E57057413B4}"
 EndProject
 Global
@@ -2249,4 +2251,16 @@
 		{0E2E224F-E9B2-41F3-B510-09183EEBA2AF}.Release|x86.ActiveCfg = Release|x86
 		{0E2E224F-E9B2-41F3-B510-09183EEBA2AF}.Release|x86.Build.0 = Release|x86
+		{792B51DB-F5AC-4EED-B165-8E57057413B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{792B51DB-F5AC-4EED-B165-8E57057413B4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{792B51DB-F5AC-4EED-B165-8E57057413B4}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{792B51DB-F5AC-4EED-B165-8E57057413B4}.Debug|x64.Build.0 = Debug|Any CPU
+		{792B51DB-F5AC-4EED-B165-8E57057413B4}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{792B51DB-F5AC-4EED-B165-8E57057413B4}.Debug|x86.Build.0 = Debug|Any CPU
+		{792B51DB-F5AC-4EED-B165-8E57057413B4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{792B51DB-F5AC-4EED-B165-8E57057413B4}.Release|Any CPU.Build.0 = Release|Any CPU
+		{792B51DB-F5AC-4EED-B165-8E57057413B4}.Release|x64.ActiveCfg = Release|Any CPU
+		{792B51DB-F5AC-4EED-B165-8E57057413B4}.Release|x64.Build.0 = Release|Any CPU
+		{792B51DB-F5AC-4EED-B165-8E57057413B4}.Release|x86.ActiveCfg = Release|Any CPU
+		{792B51DB-F5AC-4EED-B165-8E57057413B4}.Release|x86.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
Index: branches/2994-AutoDiffForIntervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4.csproj
===================================================================
--- branches/2994-AutoDiffForIntervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4.csproj	(revision 16673)
+++ branches/2994-AutoDiffForIntervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/HeuristicLab.Problems.DataAnalysis.Symbolic-3.4.csproj	(revision 16674)
@@ -167,4 +167,5 @@
     <Compile Include="Interpreter\BatchInstruction.cs" />
     <Compile Include="Interpreter\BatchOperations.cs" />
+    <Compile Include="Interpreter\Interpreter.cs" />
     <Compile Include="Interpreter\IntervalInterpreter.cs" />
     <Compile Include="Interpreter\SymbolicDataAnalysisExpressionCompiledTreeInterpreter.cs" />
Index: branches/2994-AutoDiffForIntervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/Interpreter.cs
===================================================================
--- branches/2994-AutoDiffForIntervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/Interpreter.cs	(revision 16674)
+++ branches/2994-AutoDiffForIntervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/Interpreter.cs	(revision 16674)
@@ -0,0 +1,818 @@
+﻿using System;
+using System.Collections.Generic;
+using System.Linq;
+using HeuristicLab.Common;
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
+using HEAL.Attic;
+
+namespace HeuristicLab.Problems.DataAnalysis.Symbolic {
+  public abstract class Interpreter<T> where T : IAlgebraicType<T> {
+    public struct Instruction {
+      public byte opcode;
+      public ushort narg;
+      public int childIndex;
+      public double dblVal;
+      public object data; // any kind of data you want to store in instructions
+      public T value;
+    }
+
+    public T Evaluate(Instruction[] code) {
+      for (int i = code.Length - 1; i >= 0; --i) {
+        var instr = code[i];
+        var c = instr.childIndex;
+        var n = instr.narg;
+
+        switch (instr.opcode) {
+          case OpCodes.Variable: {
+              LoadVariable(instr);
+              break;
+            }
+          // case OpCodes.Constant: we initialize constants in Compile. The value never changes afterwards
+          case OpCodes.Add: {
+              instr.value.Assign(code[c].value);
+              for (int j = 1; j < n; ++j) {
+                instr.value.Add(code[c + j].value);
+              }
+              break;
+            }
+
+          case OpCodes.Sub: {
+              if (n == 1) {
+                instr.value.AssignNeg(code[c].value);
+              } else {
+                instr.value.Assign(code[c].value);
+                for (int j = 1; j < n; ++j) {
+                  instr.value.Sub(code[c + j].value);
+                }
+              }
+              break;
+            }
+
+          case OpCodes.Mul: {
+              instr.value.Assign(code[c].value);
+              for (int j = 1; j < n; ++j) {
+                instr.value.Mul(code[c + j].value);
+              }
+              break;
+            }
+
+          case OpCodes.Div: {
+              if (n == 1) {
+                instr.value.AssignInv(code[c].value);
+              } else {
+                instr.value.Assign(code[c].value);
+                for (int j = 1; j < n; ++j) {
+                  instr.value.Div(code[c + j].value);
+                }
+              }
+              break;
+            }
+
+          case OpCodes.Exp: {
+              instr.value.AssignExp(code[c].value);
+              break;
+            }
+
+          case OpCodes.Log: {
+              instr.value.AssignLog(code[c].value);
+              break;
+            }
+        }
+      }
+      return code[0].value;
+    }
+
+    protected Instruction[] Compile(ISymbolicExpressionTree tree) {
+      var root = tree.Root.GetSubtree(0).GetSubtree(0);
+      var code = new Instruction[root.GetLength()];
+      if (root.SubtreeCount > ushort.MaxValue) throw new ArgumentException("Number of subtrees is too big (>65.535)");
+      int c = 1, i = 0;
+      foreach (var node in root.IterateNodesBreadth()) {
+        if (node.SubtreeCount > ushort.MaxValue) throw new ArgumentException("Number of subtrees is too big (>65.535)");
+        code[i] = new Instruction {
+          opcode = OpCodes.MapSymbolToOpCode(node),
+          narg = (ushort)node.SubtreeCount,
+          childIndex = c
+        };
+        if (node is VariableTreeNode variable) {
+          InitializeTerminalInstruction(ref code[i], variable);
+        } else if (node is ConstantTreeNode constant) {
+          InitializeTerminalInstruction(ref code[i], constant);
+        } else {
+          InitializeInternalInstruction(ref code[i], node);
+        }
+        c += node.SubtreeCount;
+        ++i;
+      }
+      return code;
+    }
+
+    protected abstract void InitializeTerminalInstruction(ref Instruction instruction, ConstantTreeNode constant);
+    protected abstract void InitializeTerminalInstruction(ref Instruction instruction, VariableTreeNode variable);
+    protected abstract void InitializeInternalInstruction(ref Instruction instruction, ISymbolicExpressionTreeNode node);
+
+    protected abstract void LoadVariable(Instruction a);
+
+  }
+
+
+  public class VectorEvaluator : Interpreter<DoubleVector> {
+    private const int BATCHSIZE = 128;
+    [ThreadStatic]
+    private Dictionary<string, double[]> cachedData;
+
+    [ThreadStatic]
+    private IDataset dataset;
+
+    [ThreadStatic]
+    private int rowIndex;
+
+    [ThreadStatic]
+    private int[] rows;
+
+    private void InitCache(IDataset dataset) {
+      this.dataset = dataset;
+      cachedData = new Dictionary<string, double[]>();
+      foreach (var v in dataset.DoubleVariables) {
+        cachedData[v] = dataset.GetReadOnlyDoubleValues(v).ToArray();
+      }
+    }
+
+    public double[] Evaluate(ISymbolicExpressionTree tree, IDataset dataset, int[] rows) {
+      if (cachedData == null || this.dataset != dataset) {
+        InitCache(dataset);
+      }
+
+      this.rows = rows;
+      var code = Compile(tree);
+      var remainingRows = rows.Length % BATCHSIZE;
+      var roundedTotal = rows.Length - remainingRows;
+
+      var result = new double[rows.Length];
+
+      for (rowIndex = 0; rowIndex < roundedTotal; rowIndex += BATCHSIZE) {
+        Evaluate(code);
+        code[0].value.CopyTo(result, rowIndex, BATCHSIZE);
+      }
+
+      if (remainingRows > 0) {
+        Evaluate(code);
+        code[0].value.CopyTo(result, roundedTotal, remainingRows);
+      }
+
+      return result;
+    }
+
+    protected override void InitializeTerminalInstruction(ref Instruction instruction, ConstantTreeNode constant) {
+      instruction.dblVal = constant.Value;
+      instruction.value = new DoubleVector(BATCHSIZE);
+      instruction.value.AssignConstant(instruction.dblVal);
+    }
+
+    protected override void InitializeTerminalInstruction(ref Instruction instruction, VariableTreeNode variable) {
+      instruction.dblVal = variable.Weight;
+      instruction.value = new DoubleVector(BATCHSIZE);
+      if (cachedData.ContainsKey(variable.VariableName)) {
+        instruction.data = cachedData[variable.VariableName];
+      } else {
+        instruction.data = dataset.GetDoubleValues(variable.VariableName).ToArray();
+        cachedData[variable.VariableName] = (double[])instruction.data;
+      }
+    }
+
+    protected override void InitializeInternalInstruction(ref Instruction instruction, ISymbolicExpressionTreeNode node) {
+      instruction.value = new DoubleVector(BATCHSIZE);
+    }
+
+    protected override void LoadVariable(Instruction a) {
+      var data = (double[])a.data;
+      for (int i = rowIndex; i < rows.Length && i - rowIndex < BATCHSIZE; i++) a.value[i - rowIndex] = data[rows[i]];
+      a.value.Scale(a.dblVal);
+    }
+  }
+
+  public class VectorAutoDiffEvaluator : Interpreter<VectorDual<DoubleVector>> {
+    private const int BATCHSIZE = 128;
+    [ThreadStatic]
+    private Dictionary<string, double[]> cachedData;
+
+    [ThreadStatic]
+    private IDataset dataset;
+
+    [ThreadStatic]
+    private int rowIndex;
+
+    [ThreadStatic]
+    private int[] rows;
+
+    [ThreadStatic]
+    private Dictionary<ISymbolicExpressionTreeNode, int> node2paramIdx;
+
+    private void InitCache(IDataset dataset) {
+      this.dataset = dataset;
+      cachedData = new Dictionary<string, double[]>();
+      foreach (var v in dataset.DoubleVariables) {
+        cachedData[v] = dataset.GetDoubleValues(v).ToArray();
+      }
+    }
+
+    public void Evaluate(ISymbolicExpressionTree tree, IDataset dataset, int[] rows, ISymbolicExpressionTreeNode[] parameterNodes, out double[] fi, out double[,] jac) {
+      if (cachedData == null || this.dataset != dataset) {
+        InitCache(dataset);
+      }
+
+      int nParams = parameterNodes.Length;
+      node2paramIdx = new Dictionary<ISymbolicExpressionTreeNode, int>();
+      for (int i = 0; i < parameterNodes.Length; i++) node2paramIdx.Add(parameterNodes[i], i);
+
+      var code = Compile(tree);
+
+      var remainingRows = rows.Length % BATCHSIZE;
+      var roundedTotal = rows.Length - remainingRows;
+
+      fi = new double[rows.Length];
+      jac = new double[rows.Length, nParams];
+
+      this.rows = rows;
+
+      for (rowIndex = 0; rowIndex < roundedTotal; rowIndex += BATCHSIZE) {
+        Evaluate(code);
+        code[0].value.Value.CopyTo(fi, rowIndex, BATCHSIZE);
+
+        // TRANSPOSE into JAC
+        // here we assume that we usually calculate the gradient over _all_ parameters (otherwise it would be better to propagate only relevant vectors in evaluation)
+        for (int j = 0; j < nParams; ++j) 
+          code[0].value.Gradient[j].CopyColumnTo(jac, j, rowIndex, BATCHSIZE); XXX CONTINUE HERE
+      }
+
+      if (remainingRows > 0) {
+        Evaluate(code);
+        code[0].value.Value.CopyTo(fi, roundedTotal, remainingRows);
+        for (int j = 0; j < nParams; ++j)
+          code[0].value.Gradient[j].CopyColumnTo(jac, j, roundedTotal, remainingRows);
+      }
+    }
+
+    protected override void InitializeInternalInstruction(ref Instruction instruction, ISymbolicExpressionTreeNode node) {
+      var zero = new DoubleVector(BATCHSIZE);
+      //       var g = new Vector<DoubleVector>(node2paramIdx.Count);
+      //       for (int i = 0; i < BATCHSIZE; ++i) g[i] = new DoubleVector(BATCHSIZE);
+      instruction.value = new VectorDual<DoubleVector>(zero, null);
+    }
+
+    protected override void InitializeTerminalInstruction(ref Instruction instruction, ConstantTreeNode constant) {
+      instruction.dblVal = constant.Value;
+
+      var g_arr = new double[BATCHSIZE];
+      if (node2paramIdx.ContainsKey(constant)) {
+        for (int i = 0; i < BATCHSIZE; i++) g_arr[i] = 1.0;
+      }
+      var g = new DoubleVector(g_arr);
+
+      instruction.value = new VectorDual<DoubleVector>(new DoubleVector(BATCHSIZE), new Vector<DoubleVector>(new[] { g })); // only a single column for the gradient
+      instruction.value.Value.AssignConstant(instruction.dblVal);
+    }
+
+    protected override void InitializeTerminalInstruction(ref Instruction instruction, VariableTreeNode variable) {
+      double[] data;
+      if (cachedData.ContainsKey(variable.VariableName)) {
+        data = cachedData[variable.VariableName];
+      } else {
+        data = dataset.GetReadOnlyDoubleValues(variable.VariableName).ToArray();
+        cachedData[variable.VariableName] = (double[])instruction.data;
+      }
+
+      var paramIdx = -1;
+      if (node2paramIdx.ContainsKey(variable)) {
+        paramIdx = node2paramIdx[variable];
+      }
+
+      instruction.dblVal = variable.Weight;
+      instruction.data = new object[] { data, paramIdx };
+
+      var f = new DoubleVector(BATCHSIZE);
+      var g = new DoubleVector(BATCHSIZE);
+      instruction.value = new VectorDual<DoubleVector>(f, new Vector<DoubleVector>(new[] { g }));
+    }
+
+    protected override void LoadVariable(Instruction a) {
+      var paramIdx = (int)((object[])a.data)[1];
+      var data = (double[])((object[])a.data)[0];
+
+      for (int i = rowIndex; i < rows.Length && i - rowIndex < BATCHSIZE; i++) a.value.Value[i - rowIndex] = data[rows[i]];
+      a.value.Scale(a.dblVal);
+
+      if (paramIdx >= 0) {
+        // update gradient with variable values
+        var g = a.value.Gradient[0];
+        for (int i = rowIndex; i < rows.Length && i - rowIndex < BATCHSIZE; i++) {
+          g[i] = data[rows[i]];
+        }
+      }
+    }
+  }
+
+
+  public class IntervalEvaluator : Interpreter<AlgebraicInterval> {
+    [ThreadStatic]
+    private Dictionary<string, AlgebraicInterval> intervals;
+
+    public AlgebraicInterval Evaluate(ISymbolicExpressionTree tree, Dictionary<string, AlgebraicInterval> intervals) {
+      this.intervals = intervals;
+      var code = Compile(tree);
+      Evaluate(code);
+      return code[0].value;
+    }
+
+
+    protected override void InitializeInternalInstruction(ref Instruction instruction, ISymbolicExpressionTreeNode node) {
+      instruction.value = new AlgebraicInterval(0, 0);
+    }
+
+
+    protected override void InitializeTerminalInstruction(ref Instruction instruction, ConstantTreeNode constant) {
+      instruction.dblVal = constant.Value;
+      instruction.value = new AlgebraicInterval(constant.Value, constant.Value);
+    }
+
+    protected override void InitializeTerminalInstruction(ref Instruction instruction, VariableTreeNode variable) {
+      instruction.dblVal = variable.Weight;
+      instruction.value = intervals[variable.VariableName];
+    }
+
+    protected override void LoadVariable(Instruction a) {
+      // nothing to do
+    }
+  }
+
+  public interface IAlgebraicType<T> {
+    T Assign(T a); // assign this to same value as a (copy!)
+    T AssignNeg(T a); // set this to negative(a)
+    T AssignInv(T a); // set this to inv(a);
+    T Scale(double s); // scale this with s
+    T Add(T a); // add a to this
+    T Sub(T a); // subtract a from this
+    T Mul(T a); // multiply this with a
+    T Div(T a); // divide this by a
+    T AssignLog(T a); // set this to log a
+    T AssignExp(T a); // set this to exp(a)
+    T AssignSin(T a); // set this to sin(a)
+    T AssignCos(T a); // set this to cos(a)
+    T AssignIntPower(T a, int p);
+    T AssignIntRoot(T a, int r);
+    T Clone();
+  }
+
+
+  // a simple vector as an algebraic type
+  public class DoubleVector : IAlgebraicType<DoubleVector> {
+    private double[] arr;
+
+    public double this[int idx] { get { return arr[idx]; } set { arr[idx] = value; } }
+
+    public DoubleVector(int length) {
+      arr = new double[length];
+    }
+
+    /// <summary>
+    /// 
+    /// </summary>
+    /// <param name="arr">array is not copied</param>
+    public DoubleVector(double[] arr) {
+      this.arr = arr;
+    }
+
+    public DoubleVector(int length, double constantValue) : this(length) {
+      for (int i = 0; i < length; ++i) arr[i] = constantValue;
+    }
+
+    public void CopyTo(double[] dest, int idx, int length) {
+      Array.Copy(arr, 0, dest, idx, length);
+    }
+
+    public void CopyRowTo(double[,] dest, int row) {
+      for (int j = 0; j < arr.Length; ++j) dest[row, j] = arr[j];
+    }
+    internal void CopyColumnTo(double[,] dest, int column, int row, int len) {
+      for (int j = 0; j < len; ++j) dest[row + j, column] = arr[j];
+    }
+
+
+    public DoubleVector Add(DoubleVector a) {
+      for (int i = 0; i < arr.Length; ++i) {
+        arr[i] += a.arr[i];
+      }
+      return this;
+    }
+
+    public void AssignConstant(double constantValue) {
+      for (int i = 0; i < arr.Length; ++i) {
+        arr[i] = constantValue;
+      }
+    }
+
+    public DoubleVector Assign(DoubleVector a) { for (int i = 0; i < arr.Length; ++i) { arr[i] = a.arr[i]; } return this; }
+    public DoubleVector AssignCos(DoubleVector a) { for (int i = 0; i < arr.Length; ++i) { arr[i] = Math.Cos(a.arr[i]); } return this; }
+    public DoubleVector Div(DoubleVector a) { for (int i = 0; i < arr.Length; ++i) { arr[i] /= a.arr[i]; } return this; }
+    public DoubleVector AssignExp(DoubleVector a) { for (int i = 0; i < arr.Length; ++i) { arr[i] = Math.Exp(a.arr[i]); } return this; }
+    public DoubleVector AssignIntPower(DoubleVector a, int p) { throw new NotImplementedException(); }
+    public DoubleVector AssignIntRoot(DoubleVector a, int r) { throw new NotImplementedException(); }
+    public DoubleVector AssignInv(DoubleVector a) { for (int i = 0; i < arr.Length; ++i) { arr[i] = 1.0 / a.arr[i]; } return this; }
+    public DoubleVector AssignLog(DoubleVector a) { for (int i = 0; i < arr.Length; ++i) { arr[i] = Math.Log(a.arr[i]); } return this; }
+    public DoubleVector Mul(DoubleVector a) { for (int i = 0; i < arr.Length; ++i) { arr[i] *= a.arr[i]; } return this; }
+    public DoubleVector AssignNeg(DoubleVector a) { for (int i = 0; i < arr.Length; ++i) { arr[i] = -a.arr[i]; } return this; }
+    public DoubleVector Scale(double s) { for (int i = 0; i < arr.Length; ++i) { arr[i] *= s; } return this; }
+    public DoubleVector AssignSin(DoubleVector a) { for (int i = 0; i < arr.Length; ++i) { arr[i] = Math.Sin(a.arr[i]); } return this; }
+    public DoubleVector Sub(DoubleVector a) { for (int i = 0; i < arr.Length; ++i) { arr[i] -= a.arr[i]; } return this; }
+
+    public DoubleVector Clone() {
+      var v = new DoubleVector(this.arr.Length);
+      Array.Copy(arr, v.arr, v.arr.Length);
+      return v;
+    }
+
+    public void CopyFrom(double[] data, int rowIndex) {
+      Array.Copy(data, rowIndex, arr, 0, Math.Min(arr.Length, data.Length - rowIndex));
+    }
+
+  }
+
+
+  // vectors of algebraic types
+  public class Vector<T> : IAlgebraicType<Vector<T>> where T : IAlgebraicType<T> {
+    private T[] elems;
+
+    public T this[int idx] { get { return elems[idx]; } set { elems[idx] = value; } }
+
+    public int Length => elems.Length;
+
+    private Vector() { }
+
+    public Vector(int len) {
+      elems = new T[len];
+    }
+
+    /// <summary>
+    /// 
+    /// </summary>
+    /// <param name="elems">The array is copied</param>
+    public Vector(T[] elems) {
+      this.elems = new T[elems.Length];
+      for (int i = 0; i < elems.Length; ++i) { this.elems[i] = elems[i].Clone(); }
+    }
+
+    /// <summary>
+    /// 
+    /// </summary>
+    /// <param name="elems">Array is not copied!</param>
+    /// <returns></returns>
+    public Vector<T> FromArray(T[] elems) {
+      var v = new Vector<T>();
+      v.elems = elems;
+      return v;
+    }
+
+    public void CopyTo(T[] dest) {
+      if (dest.Length != elems.Length) throw new InvalidOperationException("arr lengths do not match in Vector<T>.Copy");
+      Array.Copy(elems, dest, dest.Length);
+    }
+
+    public Vector<T> Clone() {
+      return new Vector<T>(elems);
+    }
+
+    public Vector<T> Concat(Vector<T> other) {
+      var oldLen = Length;
+      Array.Resize(ref this.elems, oldLen + other.Length);
+      for (int i = oldLen; i < Length; i++) {
+        elems[i] = other.elems[i - oldLen].Clone();
+      }
+      return this;
+    }
+
+    public Vector<T> Add(Vector<T> a) { for (int i = 0; i < elems.Length; ++i) { elems[i].Add(a.elems[i]); } return this; }
+    public Vector<T> Assign(Vector<T> a) { for (int i = 0; i < elems.Length; ++i) { elems[i].Assign(a.elems[i]); } return this; }
+    public Vector<T> AssignCos(Vector<T> a) { for (int i = 0; i < elems.Length; ++i) { elems[i].AssignCos(a.elems[i]); } return this; }
+    public Vector<T> AssignExp(Vector<T> a) { for (int i = 0; i < elems.Length; ++i) { elems[i].AssignExp(a.elems[i]); } return this; }
+    public Vector<T> AssignIntPower(Vector<T> a, int p) { for (int i = 0; i < elems.Length; ++i) { elems[i].AssignIntPower(a.elems[i], p); } return this; }
+    public Vector<T> AssignIntRoot(Vector<T> a, int r) { for (int i = 0; i < elems.Length; ++i) { elems[i].AssignIntRoot(a.elems[i], r); } return this; }
+    public Vector<T> AssignInv(Vector<T> a) { for (int i = 0; i < elems.Length; ++i) { elems[i].AssignInv(a.elems[i]); } return this; }
+    public Vector<T> AssignLog(Vector<T> a) { for (int i = 0; i < elems.Length; ++i) { elems[i].AssignLog(a.elems[i]); } return this; }
+    public Vector<T> AssignNeg(Vector<T> a) { for (int i = 0; i < elems.Length; ++i) { elems[i].AssignNeg(a.elems[i]); } return this; }
+    public Vector<T> AssignSin(Vector<T> a) { for (int i = 0; i < elems.Length; ++i) { elems[i].AssignSin(a.elems[i]); } return this; }
+    public Vector<T> Div(Vector<T> a) { for (int i = 0; i < elems.Length; ++i) { elems[i].Div(a.elems[i]); } return this; }
+    public Vector<T> Mul(Vector<T> a) { for (int i = 0; i < elems.Length; ++i) { elems[i].Mul(a.elems[i]); } return this; }
+    public Vector<T> Scale(double s) { for (int i = 0; i < elems.Length; ++i) { elems[i].Scale(s); } return this; }
+    public Vector<T> Scale(T s) { for (int i = 0; i < elems.Length; ++i) { elems[i].Mul(s); } return this; }
+    public Vector<T> Sub(Vector<T> a) { for (int i = 0; i < elems.Length; ++i) { elems[i].Sub(a.elems[i]); } return this; }
+  }
+
+
+  public class AlgebraicInterval : IAlgebraicType<AlgebraicInterval> {
+    private double low;
+    private double high;
+
+    public double LowerBound => low;
+    public double UpperBound => high;
+
+    public AlgebraicInterval() : this(double.NegativeInfinity, double.PositiveInfinity) { }
+
+    public AlgebraicInterval(double low, double high) {
+      this.low = low;
+      this.high = high;
+    }
+
+    public AlgebraicInterval Add(AlgebraicInterval a) {
+      low += a.low;
+      high += a.high;
+      return this;
+    }
+
+    public AlgebraicInterval Assign(AlgebraicInterval a) {
+      low = a.low;
+      high = a.high;
+      return this;
+    }
+
+    public AlgebraicInterval AssignCos(AlgebraicInterval a) {
+      throw new NotImplementedException();
+    }
+
+    public AlgebraicInterval Div(AlgebraicInterval a) {
+      if (Contains(0.0)) {
+        if (a.low.IsAlmost(0.0))
+          Mul(new AlgebraicInterval(1.0 / a.high, double.PositiveInfinity));
+        else if (a.high.IsAlmost(0.0))
+          Mul(new AlgebraicInterval(double.NegativeInfinity, 1.0 / a.low));
+        else {
+          low = double.NegativeInfinity;
+          high = double.PositiveInfinity;
+        }
+      } else {
+        Mul(new AlgebraicInterval(1.0 / a.high, 1.0 / a.low));
+      }
+      return this;
+    }
+
+    public AlgebraicInterval AssignExp(AlgebraicInterval a) {
+      low = Math.Exp(a.low);
+      high = Math.Exp(a.high);
+      return this;
+    }
+
+    public AlgebraicInterval AssignIntPower(AlgebraicInterval a, int p) {
+      throw new NotImplementedException();
+    }
+
+    public AlgebraicInterval AssignIntRoot(AlgebraicInterval a, int r) {
+      throw new NotImplementedException();
+    }
+
+    public AlgebraicInterval AssignInv(AlgebraicInterval a) {
+      low = 1.0;
+      high = 1.0;
+      return Div(a);
+    }
+
+    public AlgebraicInterval AssignLog(AlgebraicInterval a) {
+      low = Math.Log(a.low);
+      high = Math.Log(a.high);
+      return this;
+    }
+
+    public AlgebraicInterval Mul(AlgebraicInterval a) {
+      double v1 = low * a.low;
+      double v2 = low * a.high;
+      double v3 = high * a.low;
+      double v4 = high * a.high;
+
+      low = Math.Min(Math.Min(v1, v2), Math.Min(v3, v4));
+      high = Math.Max(Math.Max(v1, v2), Math.Max(v3, v4));
+      return this;
+    }
+
+    public AlgebraicInterval AssignNeg(AlgebraicInterval a) {
+      low = 0;
+      high = 0;
+      return Sub(a);
+    }
+
+    public AlgebraicInterval Scale(double s) {
+      if (s < 0) {
+        low = s * high;
+        high = s * low;
+      } else {
+        low = s * low;
+        high = s * high;
+      }
+      return this;
+    }
+
+    public AlgebraicInterval AssignSin(AlgebraicInterval a) {
+      throw new NotImplementedException();
+    }
+
+    public AlgebraicInterval Sub(AlgebraicInterval a) {
+      low -= a.high;
+      high -= a.low;
+      return this;
+    }
+
+    public AlgebraicInterval Clone() {
+      return new AlgebraicInterval(low, high);
+    }
+
+    public bool Contains(double val) {
+      return low <= val && val <= high;
+    }
+  }
+
+  public class Dual<V> : IAlgebraicType<Dual<V>>
+    where V : IAlgebraicType<V> {
+    private V v;
+    private V dv;
+
+    public Dual(V v, V dv) {
+      this.v = v;
+      this.dv = dv;
+    }
+
+    public Dual<V> Clone() {
+      return new Dual<V>(v.Clone(), dv.Clone());
+    }
+
+    public Dual<V> Add(Dual<V> a) {
+      v.Add(a.v);
+      dv.Add(a.dv);
+      return this;
+    }
+
+    public Dual<V> Assign(Dual<V> a) {
+      v.Assign(a.v);
+      dv.Assign(a.dv);
+      return this;
+    }
+
+    public Dual<V> AssignCos(Dual<V> a) {
+      v.AssignCos(a.v);
+      dv.AssignNeg(dv.AssignSin(a.v));
+      return this;
+    }
+
+    public Dual<V> Div(Dual<V> a) {
+      throw new NotImplementedException();
+    }
+
+    public Dual<V> AssignExp(Dual<V> a) {
+      v.AssignExp(a.v);
+      dv.Assign(a.dv).Mul(v); // exp(f(x)) = exp(f(x))*f(x)'
+      return this;
+    }
+
+    public Dual<V> AssignIntPower(Dual<V> a, int p) {
+      throw new NotImplementedException();
+    }
+
+    public Dual<V> AssignIntRoot(Dual<V> a, int r) {
+      throw new NotImplementedException();
+    }
+
+    public Dual<V> AssignInv(Dual<V> a) {
+      throw new NotImplementedException();
+    }
+
+    public Dual<V> AssignLog(Dual<V> a) {
+      v.AssignLog(a.v);
+      dv.Assign(a.dv).Div(a.v); // log(x)' = 1/f(x) * f(x)'
+      return this;
+    }
+
+    public Dual<V> Mul(Dual<V> a) {
+      // (a(x) * b(x))' = b(x)*a(x)' + b(x)'*a(x);
+
+      V t1 = default(V);
+      t1.Assign(a.dv).Mul(v);
+
+      var t2 = default(V);
+      t2.Assign(dv).Mul(a.v);
+
+      dv.Assign(t1).Add(t2);
+
+      v.Mul(a.v);
+      return this;
+    }
+
+    public Dual<V> AssignNeg(Dual<V> a) {
+      throw new NotImplementedException();
+    }
+
+    public Dual<V> Scale(double s) {
+      v.Scale(s);
+      dv.Scale(s);
+      return this;
+    }
+
+    public Dual<V> AssignSin(Dual<V> a) {
+      throw new NotImplementedException();
+    }
+
+    public Dual<V> Sub(Dual<V> a) {
+      throw new NotImplementedException();
+    }
+  }
+
+  public class VectorDual<V> : IAlgebraicType<VectorDual<V>> where V : IAlgebraicType<V> {
+    private V v;
+    public V Value => v;
+
+    private Vector<V> dv;
+    public Vector<V> Gradient => dv; // column-oriented (dv[0] is the vector for the first parameter)
+
+
+    public VectorDual(V v, Vector<V> dv) {
+      this.v = v;
+      this.dv = dv;
+    }
+
+    public VectorDual<V> Clone() {
+      return new VectorDual<V>(v.Clone(), dv.Clone());
+    }
+
+    public VectorDual<V> Add(VectorDual<V> a) {
+      v.Add(a.v);
+      dv.Concat(a.dv);
+      return this;
+    }
+
+    public VectorDual<V> Assign(VectorDual<V> a) {
+      v.Assign(a.v);
+      dv = a.dv.Clone();
+      return this;
+    }
+
+    public VectorDual<V> AssignCos(VectorDual<V> a) {
+      v.AssignCos(a.v);
+      V t = default(V);
+      t.AssignNeg(t.AssignSin(a.v));
+      dv = a.dv.Clone().Scale(t);
+      return this;
+    }
+
+    public VectorDual<V> AssignExp(VectorDual<V> a) {
+      v.AssignExp(a.v);
+      dv = a.dv.Clone().Scale(v);
+      return this;
+    }
+
+    public VectorDual<V> AssignIntPower(VectorDual<V> a, int p) {
+      throw new NotImplementedException();
+    }
+
+    public VectorDual<V> AssignIntRoot(VectorDual<V> a, int r) {
+      throw new NotImplementedException();
+    }
+
+    public VectorDual<V> AssignInv(VectorDual<V> a) {
+      throw new NotImplementedException();
+    }
+
+    public VectorDual<V> AssignLog(VectorDual<V> a) {
+      throw new NotImplementedException();
+    }
+
+    public VectorDual<V> AssignNeg(VectorDual<V> a) {
+      throw new NotImplementedException();
+    }
+
+    public VectorDual<V> AssignSin(VectorDual<V> a) {
+      throw new NotImplementedException();
+    }
+
+    public VectorDual<V> Div(VectorDual<V> a) {
+      throw new NotImplementedException();
+    }
+
+    public VectorDual<V> Mul(VectorDual<V> a) {
+      // (a(x) * b(x))' = b(x)*a(x)' + b(x)'*a(x);
+
+      var t1 = a.dv.Clone().Scale(v);
+      var t2 = dv.Clone().Scale(a.v);
+      dv.Assign(t1).Concat(t2); // TODO: CHECK ORDER
+
+      v.Mul(a.v);
+      return this;
+    }
+
+    public VectorDual<V> Scale(double s) {
+      v.Scale(s);
+      dv.Scale(s);
+      return this;
+    }
+
+    public VectorDual<V> Sub(VectorDual<V> a) {
+      v.Sub(a.v);
+      dv.Concat(a.dv.AssignNeg(a.dv));
+      return this;
+    }
+  }
+}
Index: branches/2994-AutoDiffForIntervals/Tests/AutoDiffTest.cs
===================================================================
--- branches/2994-AutoDiffForIntervals/Tests/AutoDiffTest.cs	(revision 16674)
+++ branches/2994-AutoDiffForIntervals/Tests/AutoDiffTest.cs	(revision 16674)
@@ -0,0 +1,102 @@
+﻿using System;
+using System.Collections.Generic;
+using HeuristicLab.Problems.DataAnalysis;
+using HeuristicLab.Problems.DataAnalysis.Symbolic;
+using Microsoft.VisualStudio.TestTools.UnitTesting;
+using System.Linq;
+using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
+
+namespace Tests {
+  [TestClass]
+  public class AutoDiffTest {
+    [TestMethod]
+    public void TestMethod1() {
+      {
+        var parser = new InfixExpressionParser();
+        var t = parser.Parse("2.0*x+y");
+
+        var evaluator = new IntervalEvaluator();
+        var intervals = new Dictionary<string, AlgebraicInterval>();
+        intervals.Add("x", new AlgebraicInterval(-1.0, 1.0));
+        intervals.Add("y", new AlgebraicInterval(2.0, 10.0));
+        var resultInterval = evaluator.Evaluate(t, intervals);
+        Assert.AreEqual(0, resultInterval.LowerBound);
+        Assert.AreEqual(12, resultInterval.UpperBound);
+      }
+
+      {
+        var parser = new InfixExpressionParser();
+        var t = parser.Parse("2.0*x+y");
+
+        var evaluator = new VectorEvaluator();
+        var vars = new string[] { "x", "y", "f(x)" };
+        var values = new double[,] {
+          { 1,  1, 0 },
+          { 2,  1, 0 },
+          { 3, -1, 0 },
+          { 4, -1, 0 },
+          { 5, -1, 0 },
+        };
+
+        var ds = new Dataset(vars, values);
+        var problemData = new RegressionProblemData(ds, vars, "f(x)");
+        var train = evaluator.Evaluate(t, ds, problemData.TrainingIndices.ToArray());
+        Assert.AreEqual(2, train.Length);
+        Assert.AreEqual(3, train[0]);
+        Assert.AreEqual(5, train[1]);
+
+        var test = evaluator.Evaluate(t, ds, problemData.TestIndices.ToArray());
+        Assert.AreEqual(3, test.Length);
+        Assert.AreEqual(5, test[0]);
+        Assert.AreEqual(7, test[1]);
+        Assert.AreEqual(9, test[2]);
+      }
+
+      {
+        var parser = new InfixExpressionParser();
+        var t = parser.Parse("2.0*x+y");
+        var p0 = t.IterateNodesPostfix().First(n => n is ConstantTreeNode);
+        var p1 = t.IterateNodesPostfix().First(n => (n is VariableTreeNode var) && var.VariableName == "y");
+        var paramNodes = new ISymbolicExpressionTreeNode[] { p0, p1 };
+
+        var evaluator = new VectorAutoDiffEvaluator();
+        var vars = new string[] { "x", "y", "f(x)" };
+        var values = new double[,] {
+          { 1,  1, 0 },
+          { 2,  1, 0 },
+          { 3, -1, 0 },
+          { 4, -1, 0 },
+          { 5, -1, 0 },
+        };
+
+        var ds = new Dataset(vars, values);
+        var problemData = new RegressionProblemData(ds, vars, "f(x)");
+        evaluator.Evaluate(t, ds, problemData.TrainingIndices.ToArray(), paramNodes, out double[] train, out double[,] trainJac);
+        Assert.AreEqual(2, train.Length);
+        Assert.AreEqual(3, train[0]);
+        Assert.AreEqual(5, train[1]);
+        // check jac
+        Assert.AreEqual(1, trainJac[0, 0]);
+        Assert.AreEqual(1, trainJac[0, 1]);
+        Assert.AreEqual(2, trainJac[1, 0]);
+        Assert.AreEqual(1, trainJac[1, 1]);
+
+        evaluator.Evaluate(t, ds, problemData.TestIndices.ToArray(), paramNodes, out double[] test, out double[,] testJac);
+        Assert.AreEqual(3, test.Length);
+        Assert.AreEqual(5, test[0]);
+        Assert.AreEqual(7, test[1]);
+        Assert.AreEqual(9, test[2]);
+
+        // check jac
+        Assert.AreEqual(3, testJac[0, 0]);
+        Assert.AreEqual(-1, testJac[0, 1]);
+        Assert.AreEqual(4, testJac[1, 0]);
+        Assert.AreEqual(-1, testJac[1, 1]);
+        Assert.AreEqual(5, testJac[2, 0]);
+        Assert.AreEqual(-1, testJac[2, 1]);
+
+      }
+
+    }
+  }
+}
Index: branches/2994-AutoDiffForIntervals/Tests/Properties/AssemblyInfo.cs
===================================================================
--- branches/2994-AutoDiffForIntervals/Tests/Properties/AssemblyInfo.cs	(revision 16674)
+++ branches/2994-AutoDiffForIntervals/Tests/Properties/AssemblyInfo.cs	(revision 16674)
@@ -0,0 +1,20 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+[assembly: AssemblyTitle("Tests")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("FH-Hagenberg")]
+[assembly: AssemblyProduct("Tests")]
+[assembly: AssemblyCopyright("Copyright Â© FH-Hagenberg 2019")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+[assembly: ComVisible(false)]
+
+[assembly: Guid("792b51db-f5ac-4eed-b165-8e57057413b4")]
+
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
Index: branches/2994-AutoDiffForIntervals/Tests/Tests.csproj
===================================================================
--- branches/2994-AutoDiffForIntervals/Tests/Tests.csproj	(revision 16674)
+++ branches/2994-AutoDiffForIntervals/Tests/Tests.csproj	(revision 16674)
@@ -0,0 +1,94 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="..\packages\MSTest.TestAdapter.1.3.2\build\net45\MSTest.TestAdapter.props" Condition="Exists('..\packages\MSTest.TestAdapter.1.3.2\build\net45\MSTest.TestAdapter.props')" />
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{792B51DB-F5AC-4EED-B165-8E57057413B4}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Tests</RootNamespace>
+    <AssemblyName>Tests</AssemblyName>
+    <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">15.0</VisualStudioVersion>
+    <VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
+    <ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
+    <IsCodedUITest>False</IsCodedUITest>
+    <TestProjectType>UnitTest</TestProjectType>
+    <NuGetPackageImportStamp>
+    </NuGetPackageImportStamp>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+      <HintPath>..\packages\MSTest.TestFramework.1.3.2\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions, Version=14.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+      <HintPath>..\packages\MSTest.TestFramework.1.3.2\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="AutoDiffTest.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\HeuristicLab.Common\3.3\HeuristicLab.Common-3.3.csproj">
+      <Project>{A9AD58B9-3EF9-4CC1-97E5-8D909039FF5C}</Project>
+      <Name>HeuristicLab.Common-3.3</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\HeuristicLab.Core\3.3\HeuristicLab.Core-3.3.csproj">
+      <Project>{C36BD924-A541-4A00-AFA8-41701378DDC5}</Project>
+      <Name>HeuristicLab.Core-3.3</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\HeuristicLab.Data\3.3\HeuristicLab.Data-3.3.csproj">
+      <Project>{BBAB9DF5-5EF3-4BA8-ADE9-B36E82114937}</Project>
+      <Name>HeuristicLab.Data-3.3</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\HeuristicLab.Encodings.SymbolicExpressionTreeEncoding\3.4\HeuristicLab.Encodings.SymbolicExpressionTreeEncoding-3.4.csproj">
+      <Project>{06d4a186-9319-48a0-bade-a2058d462eea}</Project>
+      <Name>HeuristicLab.Encodings.SymbolicExpressionTreeEncoding-3.4</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\HeuristicLab.Problems.DataAnalysis.Symbolic\3.4\HeuristicLab.Problems.DataAnalysis.Symbolic-3.4.csproj">
+      <Project>{3d28463f-ec96-4d82-afee-38be91a0ca00}</Project>
+      <Name>HeuristicLab.Problems.DataAnalysis.Symbolic-3.4</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\HeuristicLab.Problems.DataAnalysis\3.4\HeuristicLab.Problems.DataAnalysis-3.4.csproj">
+      <Project>{df87c13e-a889-46ff-8153-66dcaa8c5674}</Project>
+      <Name>HeuristicLab.Problems.DataAnalysis-3.4</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
+    <PropertyGroup>
+      <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
+    </PropertyGroup>
+    <Error Condition="!Exists('..\packages\MSTest.TestAdapter.1.3.2\build\net45\MSTest.TestAdapter.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.1.3.2\build\net45\MSTest.TestAdapter.props'))" />
+    <Error Condition="!Exists('..\packages\MSTest.TestAdapter.1.3.2\build\net45\MSTest.TestAdapter.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\MSTest.TestAdapter.1.3.2\build\net45\MSTest.TestAdapter.targets'))" />
+  </Target>
+  <Import Project="..\packages\MSTest.TestAdapter.1.3.2\build\net45\MSTest.TestAdapter.targets" Condition="Exists('..\packages\MSTest.TestAdapter.1.3.2\build\net45\MSTest.TestAdapter.targets')" />
+</Project>
Index: branches/2994-AutoDiffForIntervals/Tests/packages.config
===================================================================
--- branches/2994-AutoDiffForIntervals/Tests/packages.config	(revision 16674)
+++ branches/2994-AutoDiffForIntervals/Tests/packages.config	(revision 16674)
@@ -0,0 +1,5 @@
+﻿<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="MSTest.TestAdapter" version="1.3.2" targetFramework="net461" />
+  <package id="MSTest.TestFramework" version="1.3.2" targetFramework="net461" />
+</packages>
