Index: /branches/2994-AutoDiffForIntervals/HeuristicLab.Algorithms.DataAnalysis.ConstrainedNonlinearRegression/3.4/ConstrainedNonlinearRegression.cs
===================================================================
--- /branches/2994-AutoDiffForIntervals/HeuristicLab.Algorithms.DataAnalysis.ConstrainedNonlinearRegression/3.4/ConstrainedNonlinearRegression.cs	(revision 16726)
+++ /branches/2994-AutoDiffForIntervals/HeuristicLab.Algorithms.DataAnalysis.ConstrainedNonlinearRegression/3.4/ConstrainedNonlinearRegression.cs	(revision 16727)
@@ -248,12 +248,4 @@
         }
       }
-
-      // var interpreter = new SymbolicDataAnalysisExpressionTreeLinearInterpreter();
-      // 
-      // SymbolicRegressionConstantOptimizationEvaluator.OptimizeConstants(interpreter, tree, problemData, problemData.TrainingIndices,
-      //   applyLinearScaling: applyLinearScaling, maxIterations: maxIterations,
-      //   updateVariableWeights: false, updateConstantsInTree: true);
-
-
       var intervals = problemData.IntervalConstraints;
       var constraintsParser = new IntervalConstraintsParser();
@@ -315,4 +307,5 @@
       }
 
+      // local function
       void UpdateThetaValues(double[] theta) {
         for (int i = 0; i < theta.Length; ++i) {
@@ -321,6 +314,12 @@
       }
 
+      // buffers for calculate_jacobian
+      var target = problemData.TargetVariableTrainingValues.ToArray();
+      var fi_eval = new double[target.Length];
+      var jac_eval = new double[target.Length, thetaValues.Count];
+
       // define the callback used by the alglib optimizer
       // the x argument for this callback represents our theta
+      // local function
       void calculate_jacobian(double[] x, double[] fi, double[,] jac, object obj) {
         UpdateThetaValues(x);
@@ -328,6 +327,5 @@
         var autoDiffEval = new VectorAutoDiffEvaluator();
         autoDiffEval.Evaluate(preparedTree, problemData.Dataset, problemData.TrainingIndices.ToArray(),
-          GetParameterNodes(preparedTree, allThetaNodes), out double[] fi_eval, out double[,] jac_eval);
-        var target = problemData.TargetVariableTrainingValues.ToArray();
+          GetParameterNodes(preparedTree, allThetaNodes), fi_eval, jac_eval);
 
         // calc sum of squared errors and gradient
@@ -336,12 +334,12 @@
         for (int i = 0; i < target.Length; i++) {
           var res = target[i] - fi_eval[i];
-          sse += res * res;
+          sse += 0.5 * res * res;
           for (int j = 0; j < g.Length; j++) {
-            g[j] += -2.0 * res * jac_eval[i, j];
-          }
-        }
-
-        fi[0] = sse;
-        for (int j = 0; j < x.Length; j++) { jac[0, j] = g[j]; }
+            g[j] -= res * jac_eval[i, j];
+          }
+        }
+
+        fi[0] = sse / target.Length;
+        for (int j = 0; j < x.Length; j++) { jac[0, j] = g[j] / target.Length; }
 
         var intervalEvaluator = new IntervalEvaluator();
@@ -358,26 +356,27 @@
       }
 
+
+
       // prepare alglib
       alglib.minnlcstate state;
       alglib.minnlcreport rep;
+      alglib.optguardreport optGuardRep;
       var x0 = thetaValues.ToArray();
 
       alglib.minnlccreate(x0.Length, x0, out state);
-      double epsx = 1e-6;
-      int maxits = 0;
-      alglib.minnlcsetalgoslp(state);
-      alglib.minnlcsetcond(state, 0, maxits);
+      alglib.minnlcsetalgoslp(state);        // SLP is more robust but slower
+      alglib.minnlcsetcond(state, 0, maxIterations);
       var s = Enumerable.Repeat(1d, x0.Length).ToArray();  // scale is set to unit scale
       alglib.minnlcsetscale(state, s);
 
-      // set boundary constraints
-      // var boundaryLower = Enumerable.Repeat(-10d, n).ToArray();
-      // var boundaryUpper = Enumerable.Repeat(10d, n).ToArray();
-      // alglib.minnlcsetbc(state, boundaryLower, boundaryUpper);
       // set non-linear constraints: 0 equality constraints, 1 inequality constraint
       alglib.minnlcsetnlc(state, 0, constraintTrees.Count);
 
+      alglib.minnlcoptguardsmoothness(state);
+      alglib.minnlcoptguardgradient(state, 0.001);
+
       alglib.minnlcoptimize(state, calculate_jacobian, null, null);
       alglib.minnlcresults(state, out double[] xOpt, out rep);
+      alglib.minnlcoptguardresults(state, out optGuardRep);
 
       var interpreter = new SymbolicDataAnalysisExpressionTreeLinearInterpreter();
@@ -416,5 +415,5 @@
             var parent = n.Parent;
             if(thetaNodes[thetaIdx].Any()) {
-              // HACKY: REUSE CONSTANT TREE NODE IN SEVERAL TREES
+              // HACK: REUSE CONSTANT TREE NODE IN SEVERAL TREES
               // we use this trick to allow autodiff over thetas when thetas occurr multiple times in the tree (e.g. in derived trees)
               var constNode = thetaNodes[thetaIdx].First();
@@ -444,21 +443,5 @@
       for (int i = 0; i < nodes.Count; ++i) {
         var node = nodes[i];
-        /*if (node is VariableTreeNode variableTreeNode) {
-          var thetaVar = (VariableTreeNode)new Problems.DataAnalysis.Symbolic.Variable().CreateTreeNode();
-          thetaVar.Weight = 1;
-          thetaVar.VariableName = $"θ{n++}";
-
-          thetaNames.Add(thetaVar.VariableName);
-          thetaValues.Add(variableTreeNode.Weight);
-          variableTreeNode.Weight = 1; // set to unit weight
-
-          var parent = variableTreeNode.Parent;
-          var prod = MakeNode<Multiplication>(thetaVar, variableTreeNode);
-          if (parent != null) {
-            var index = parent.IndexOfSubtree(variableTreeNode);
-            parent.RemoveSubtree(index);
-            parent.InsertSubtree(index, prod);
-          }
-        } else*/ if (node is ConstantTreeNode constantTreeNode) {
+        if (node is ConstantTreeNode constantTreeNode) {
           var thetaVar = (VariableTreeNode)new Problems.DataAnalysis.Symbolic.Variable().CreateTreeNode();
           thetaVar.Weight = 1;
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 16726)
+++ /branches/2994-AutoDiffForIntervals/HeuristicLab.Problems.DataAnalysis.Symbolic/3.4/Interpreter/Interpreter.cs	(revision 16727)
@@ -72,11 +72,43 @@
               break;
             }
+          case OpCodes.SquareRoot: {
+              instr.value.AssignIntRoot(code[c].value, 2);
+              break;
+            }
+          case OpCodes.Cube: {
+              instr.value.AssignIntPower(code[c].value, 3);
+              break;
+            }
+          case OpCodes.CubeRoot: {
+              instr.value.AssignIntRoot(code[c].value, 3);
+              break;
+            }
           case OpCodes.Exp: {
               instr.value.AssignExp(code[c].value);
               break;
             }
-
           case OpCodes.Log: {
               instr.value.AssignLog(code[c].value);
+              break;
+            }
+          case OpCodes.Sin: {
+              instr.value.AssignSin(code[c].value);
+              break;
+            }
+          case OpCodes.Cos: {
+              instr.value.AssignCos(code[c].value);
+              break;
+            }
+          case OpCodes.Absolute: {
+              instr.value.AssignAbs(code[c].value);
+              break;
+            }
+          case OpCodes.AnalyticQuotient: {
+              instr.value.Assign(code[c].value);
+              for (int j = 1; j < n; ++j) {
+                var t = instr.value.One;
+                t.Add(code[c + j].value.Clone().IntPower(2));
+                instr.value.Div(t.IntRoot(2));
+              }
               break;
             }
@@ -221,5 +253,14 @@
     }
 
-    public void Evaluate(ISymbolicExpressionTree tree, IDataset dataset, int[] rows, ISymbolicExpressionTreeNode[] parameterNodes, out double[] fi, out double[,] jac) {
+    /// <summary>
+    /// 
+    /// </summary>
+    /// <param name="tree"></param>
+    /// <param name="dataset"></param>
+    /// <param name="rows"></param>
+    /// <param name="parameterNodes"></param>
+    /// <param name="fi">Function output. Must be allocated by the caller.</param>
+    /// <param name="jac">Jacobian matrix. Must be allocated by the caller.</param>
+    public void Evaluate(ISymbolicExpressionTree tree, IDataset dataset, int[] rows, ISymbolicExpressionTreeNode[] parameterNodes, double[] fi, double[,] jac) {
       if (cachedData == null || this.dataset != dataset) {
         InitCache(dataset);
@@ -235,7 +276,4 @@
       var roundedTotal = rows.Length - remainingRows;
 
-      fi = new double[rows.Length];
-      jac = new double[rows.Length, nParams];
-
       this.rows = rows;
 
@@ -247,5 +285,9 @@
         var g = code[0].value.Gradient;
         for (int j = 0; j < nParams; ++j) {
-          g.Elements[j].CopyColumnTo(jac, j, rowIndex, BATCHSIZE);
+          if(g.Elements.TryGetValue(j, out AlgebraicDoubleVector v)) {
+            v.CopyColumnTo(jac, j, rowIndex, BATCHSIZE);
+          } else {
+            for (int r = 0; r < BATCHSIZE; r++) jac[rowIndex + r, j] = 0.0;
+          }
         }
       }
@@ -257,5 +299,9 @@
         var g = code[0].value.Gradient;
         for (int j = 0; j < nParams; ++j)
-          g.Elements[j].CopyColumnTo(jac, j, roundedTotal, remainingRows);
+          if (g.Elements.TryGetValue(j, out AlgebraicDoubleVector v)) {
+            v.CopyColumnTo(jac, j, roundedTotal, remainingRows);
+          } else {
+            for (int r = 0; r < remainingRows; r++) jac[roundedTotal + r, j] = 0.0;
+          }
       }
     }
@@ -315,5 +361,5 @@
         var g = a.value.Gradient.Elements[paramIdx];
         for (int i = rowIndex; i < rows.Length && i - rowIndex < BATCHSIZE; i++) {
-          g[i] = data[rows[i]];
+          g[i - rowIndex] = data[rows[i]];
         }
       }
@@ -377,4 +423,5 @@
   public interface IAlgebraicType<T> {
     T Zero { get; }
+    T One { get; }
 
     T AssignAbs(T a); // set this to assign abs(a)
@@ -429,4 +476,6 @@
     [DebuggerBrowsable(DebuggerBrowsableState.Never)]
     public AlgebraicDouble Zero => new AlgebraicDouble(0.0);
+    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
+    public AlgebraicDouble One => new AlgebraicDouble(1.0);
     public AlgebraicDouble() { }
     public AlgebraicDouble(double value) { this.Value = value; }
@@ -441,10 +490,10 @@
     public AlgebraicDouble AssignSin(AlgebraicDouble a) { Value = Math.Sin(a.Value); return this; }
     public AlgebraicDouble AssignCos(AlgebraicDouble a) { Value = Math.Cos(a.Value); return this; }
-    public AlgebraicDouble AssignLog(AlgebraicDouble a) { Value = Math.Log(a.Value); return this; }
+    public AlgebraicDouble AssignLog(AlgebraicDouble a) { Value = a.Value <= 0?double.NegativeInfinity : Math.Log(a.Value); return this; } // alternative definiton of log to prevent NaN
     public AlgebraicDouble AssignExp(AlgebraicDouble a) { Value = Math.Exp(a.Value); return this; }
     public AlgebraicDouble AssignIntPower(AlgebraicDouble a, int p) { Value = Math.Pow(a.Value, p); return this; }
     public AlgebraicDouble AssignIntRoot(AlgebraicDouble a, int r) { Value = Math.Pow(a.Value, 1.0 / r); return this; }
     public AlgebraicDouble AssignAbs(AlgebraicDouble a) { Value = Math.Abs(a.Value); return this; }
-    public AlgebraicDouble AssignSgn(AlgebraicDouble a) { Value = Math.Sign(a.Value); return this; }
+    public AlgebraicDouble AssignSgn(AlgebraicDouble a) { Value = double.IsNaN(a.Value)? double.NaN : Math.Sign(a.Value); return this; }
     public AlgebraicDouble Clone() { return new AlgebraicDouble(Value); }
 
@@ -473,4 +522,6 @@
     [DebuggerBrowsable(DebuggerBrowsableState.Never)]
     public AlgebraicDoubleVector Zero => new AlgebraicDoubleVector(new double[this.Length]); // must return vector of same length as this (therefore Zero is not static)
+    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
+    public AlgebraicDoubleVector One => new AlgebraicDoubleVector(new double[this.Length]).AssignConstant(1.0); // must return vector of same length as this (therefore Zero is not static)
     public AlgebraicDoubleVector Assign(AlgebraicDoubleVector a) { for (int i = 0; i < arr.Length; ++i) { arr[i] = a.arr[i]; } return this; }
     public AlgebraicDoubleVector Add(AlgebraicDoubleVector a) { for (int i = 0; i < arr.Length; ++i) { arr[i] += a.arr[i]; } return this; }
@@ -496,8 +547,9 @@
     }
 
-    public void AssignConstant(double constantValue) {
+    public AlgebraicDoubleVector AssignConstant(double constantValue) {
       for (int i = 0; i < arr.Length; ++i) {
         arr[i] = constantValue;
       }
+      return this;
     }
 
@@ -522,6 +574,8 @@
   }
 
+
+  /*
   // vectors of algebraic types
-  public sealed class AlgebraicVector<T> : IAlgebraicType<AlgebraicVector<T>> where T : IAlgebraicType<T> {
+  public sealed class AlgebraicVector<T> : IAlgebraicType<AlgebraicVector<T>> where T : IAlgebraicType<T>, new() {
     private T[] elems;
 
@@ -561,15 +615,9 @@
     public AlgebraicVector<T> Clone() { return new AlgebraicVector<T>(elems); }
 
-    public AlgebraicVector<T> Concat(AlgebraicVector<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;
-    }
 
     [DebuggerBrowsable(DebuggerBrowsableState.Never)]
     public AlgebraicVector<T> Zero => new AlgebraicVector<T>(Length);
+    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
+    public AlgebraicVector<T> One { get { var v = new AlgebraicVector<T>(Length); for (int i = 0; i < elems.Length; ++i) elems[i] = new T().One; return v; } }
     public AlgebraicVector<T> Assign(AlgebraicVector<T> a) { for (int i = 0; i < elems.Length; ++i) { elems[i].Assign(a.elems[i]); } return this; }
     public AlgebraicVector<T> Add(AlgebraicVector<T> a) { for (int i = 0; i < elems.Length; ++i) { elems[i].Add(a.elems[i]); } return this; }
@@ -591,4 +639,6 @@
   }
 
+  */
+
 
   /// <summary>
@@ -625,40 +675,4 @@
     }
 
-
-
-    // combined elements from both vectors
-    private void UnionAssign(AlgebraicSparseVector<K, T> a, Func<T, T, T> mapAssign) {
-      // elements from a
-      foreach (var kvp in a.elems) {
-        // this = f(a, this)
-        if (elems.TryGetValue(kvp.Key, out T value))
-          mapAssign(kvp.Value, value);
-        else {
-          // this = f(a, 0)
-          var newValue = kvp.Value.Zero;
-          elems.Add(kvp.Key, newValue);
-          mapAssign(kvp.Value, newValue);
-        }
-      }
-      // elements from this (without a)
-      foreach (var kvp in elems) {
-        if (a.elems.ContainsKey(kvp.Key)) continue; // already processed above
-                                                    // this = f(0, this)
-        mapAssign(kvp.Value.Zero, kvp.Value);
-      }
-    }
-
-    // keep only elements in both vectors
-    private void IntersectAssign(AlgebraicSparseVector<K, T> a, Func<T, T, T> mapAssign) {
-      List<K> keysToRemove = new List<K>();
-      foreach (var kvp in elems) {
-        if (a.elems.TryGetValue(kvp.Key, out T value))
-          mapAssign(value, kvp.Value);
-        else
-          keysToRemove.Add(kvp.Key);
-      }
-      foreach (var o in keysToRemove) elems.Remove(o); // -> zero
-    }
-
     // keep only elements from a
     private void AssignFromSource(AlgebraicSparseVector<K, T> a, Func<T, T, T> mapAssign) {
@@ -680,4 +694,6 @@
     [DebuggerBrowsable(DebuggerBrowsableState.Never)]
     public AlgebraicSparseVector<K, T> Zero => new AlgebraicSparseVector<K, T>();
+    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
+    public AlgebraicSparseVector<K, T> One => throw new NotSupportedException();
 
     public AlgebraicSparseVector<K, T> Scale(T s) { foreach (var kvp in elems) { kvp.Value.Mul(s); } return this; }
@@ -685,8 +701,4 @@
 
     public AlgebraicSparseVector<K, T> Assign(AlgebraicSparseVector<K, T> a) { elems.Clear(); AssignFromSource(a, (src, dest) => dest.Assign(src)); return this; }
-    public AlgebraicSparseVector<K, T> Add(AlgebraicSparseVector<K, T> a) { UnionAssign(a, (src, dest) => dest.Add(src)); return this; }
-    public AlgebraicSparseVector<K, T> Sub(AlgebraicSparseVector<K, T> a) { UnionAssign(a, (src, dest) => dest.Sub(src)); return this; }
-    public AlgebraicSparseVector<K, T> Mul(AlgebraicSparseVector<K, T> a) { IntersectAssign(a, (src, dest) => dest.Mul(src)); return this; }
-    public AlgebraicSparseVector<K, T> Div(AlgebraicSparseVector<K, T> a) { UnionAssign(a, (src, dest) => dest.Div(src)); return this; }
     public AlgebraicSparseVector<K, T> AssignInv(AlgebraicSparseVector<K, T> a) { AssignFromSource(a, (src, dest) => dest.AssignInv(src)); return this; }
     public AlgebraicSparseVector<K, T> AssignNeg(AlgebraicSparseVector<K, T> a) { AssignFromSource(a, (src, dest) => dest.AssignNeg(src)); return this; }
@@ -699,4 +711,37 @@
     public AlgebraicSparseVector<K, T> AssignAbs(AlgebraicSparseVector<K, T> a) { AssignFromSource(a, (src, dest) => dest.AssignAbs(src)); return this; }
     public AlgebraicSparseVector<K, T> AssignSgn(AlgebraicSparseVector<K, T> a) { AssignFromSource(a, (src, dest) => dest.AssignSgn(src)); return this; }
+    public AlgebraicSparseVector<K, T> Add(AlgebraicSparseVector<K, T> a) {
+      foreach (var kvp in a.elems) {
+        if (elems.TryGetValue(kvp.Key, out T value))
+          value.Add(kvp.Value);
+        else
+          elems.Add(kvp.Key, kvp.Value.Clone()); // 0 + a
+      }
+      return this;
+    }
+
+    public AlgebraicSparseVector<K, T> Sub(AlgebraicSparseVector<K, T> a) {
+      foreach (var kvp in a.elems) {
+        if (elems.TryGetValue(kvp.Key, out T value))
+          value.Sub(kvp.Value);
+        else
+          elems.Add(kvp.Key, kvp.Value.Zero.Sub(kvp.Value)); // 0 - a
+      }
+      return this;
+    }
+
+    public AlgebraicSparseVector<K, T> Mul(AlgebraicSparseVector<K, T> a) {
+      var keys = elems.Keys.ToArray();
+      foreach (var k in keys) if (!a.elems.ContainsKey(k)) elems.Remove(k); // 0 * a => 0
+      foreach (var kvp in a.elems) {
+        if (elems.TryGetValue(kvp.Key, out T value))
+          value.Mul(kvp.Value); // this * a
+      }
+      return this;
+    }
+
+    public AlgebraicSparseVector<K, T> Div(AlgebraicSparseVector<K, T> a) {
+      return Mul(a.Clone().Inv());
+    }
 
     public AlgebraicSparseVector<K, T> Clone() {
@@ -734,4 +779,5 @@
     [DebuggerBrowsable(DebuggerBrowsableState.Never)]
     public AlgebraicInterval Zero => new AlgebraicInterval(0.0, 0.0);
+    public AlgebraicInterval One => new AlgebraicInterval(1.0, 1.0);
     public AlgebraicInterval Add(AlgebraicInterval a) {
       low.Add(a.low);
@@ -799,8 +845,8 @@
           if (a.Contains(0.0)) {
             low = new MultivariateDual<AlgebraicDouble>(0.0);
-            high = Algebraic.Max(low.Clone().IntPower(p), high.Clone().IntPower(p));
+            high = Algebraic.Max(a.low.IntPower(p), a.high.IntPower(p));
           } else {
-            var lowPower = low.Clone().IntPower(p);
-            var highPower = high.Clone().IntPower(p);
+            var lowPower = a.low.IntPower(p);
+            var highPower = a.high.IntPower(p);
             low = Algebraic.Min(lowPower, highPower);
             high = Algebraic.Max(lowPower, highPower);
@@ -808,6 +854,6 @@
         } else {
           // p is uneven
-          var lowPower = low.Clone().IntPower(p);
-          var highPower = high.Clone().IntPower(p);
+          var lowPower = a.low.IntPower(p);
+          var highPower = a.high.IntPower(p);
           low = Algebraic.Min(lowPower, highPower);
           high = Algebraic.Max(lowPower, highPower);
@@ -951,4 +997,6 @@
     [DebuggerBrowsable(DebuggerBrowsableState.Never)]
     public Dual<V> Zero => new Dual<V>(Value.Zero, Derivative.Zero);
+    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
+    public Dual<V> One => new Dual<V>(Value.One, Derivative.Zero);
 
     public Dual<V> Assign(Dual<V> a) { v.Assign(a.v); dv.Assign(a.dv); return this; }
@@ -1034,4 +1082,5 @@
 
     public MultivariateDual<V> Zero => new MultivariateDual<V>(Value.Zero, Gradient.Zero);
+    public MultivariateDual<V> One => new MultivariateDual<V>(Value.One, Gradient.Zero);
 
     public MultivariateDual<V> Scale(double s) { v.Scale(s); dv.Scale(s); return this; }
Index: /branches/2994-AutoDiffForIntervals/Tests/AutoDiffTest.cs
===================================================================
--- /branches/2994-AutoDiffForIntervals/Tests/AutoDiffTest.cs	(revision 16726)
+++ /branches/2994-AutoDiffForIntervals/Tests/AutoDiffTest.cs	(revision 16727)
@@ -76,5 +76,7 @@
         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);
+        var train = new double[problemData.TrainingIndices.Count()];
+        var trainJac = new double[train.Length, 2];
+        evaluator.Evaluate(t, ds, problemData.TrainingIndices.ToArray(), paramNodes, train, trainJac);
         Assert.AreEqual(2, train.Length);
         Assert.AreEqual(3, train[0]);
@@ -86,5 +88,7 @@
         Assert.AreEqual(1, trainJac[1, 1]);
 
-        evaluator.Evaluate(t, ds, problemData.TestIndices.ToArray(), paramNodes, out double[] test, out double[,] testJac);
+        var test = new double[problemData.TestIndices.Count()];
+        var testJac = new double[test.Length, 2];
+        evaluator.Evaluate(t, ds, problemData.TestIndices.ToArray(), paramNodes, test, testJac);
         Assert.AreEqual(3, test.Length);
         Assert.AreEqual(5, test[0]);
@@ -124,4 +128,65 @@
       }
 
+      {
+        // as discussed with Fabrício
+        var intervals = new Dictionary<string, Interval>();
+        intervals.Add("x1", new Interval(60.0, 65.0));
+        intervals.Add("x2", new Interval(30.0, 40.0));
+        intervals.Add("x3", new Interval(5.0, 10.0));
+        intervals.Add("x4", new Interval(0.5, 0.8));
+        intervals.Add("x5", new Interval(0.2, 0.5));
+
+        var parser = new InfixExpressionParser();
+
+        var t1 = parser.Parse("x5/x4");
+        var t2 = parser.Parse("log(x5/x4)");
+        var t3 = parser.Parse("x3 * log(x5/x4)");
+        var t4 = parser.Parse("x1*x2*x5");
+        var t5 = parser.Parse("x4/x5");
+        var t6 = parser.Parse("sqr(x4/x5)");
+        var t7 = parser.Parse("(1 - sqr(x4/x5)) ");
+        var t8 = parser.Parse("x1*x2*x5 *(1 - sqr(x4/x5))");
+        var t9 = parser.Parse("x1*x2*x5 *(1 - sqr(x4/x5)) + x3 * log(x5/x4)");
+
+        var evaluator = new IntervalEvaluator();
+        var result = evaluator.Evaluate(t1, intervals);
+        Assert.AreEqual(0.25, result.LowerBound);
+        Assert.AreEqual(1, result.UpperBound);
+
+        result = evaluator.Evaluate(t2, intervals);
+        Assert.AreEqual(-1.386294361, result.LowerBound, 1e-6);
+        Assert.AreEqual(0, result.UpperBound);
+
+        result = evaluator.Evaluate(t3, intervals);
+        Assert.AreEqual(-13.86294361, result.LowerBound, 1e-6);
+        Assert.AreEqual(0, result.UpperBound);
+
+        result = evaluator.Evaluate(t4, intervals);
+        Assert.AreEqual(360, result.LowerBound);
+        Assert.AreEqual(1300, result.UpperBound);
+
+        result = evaluator.Evaluate(t5, intervals);
+        Assert.AreEqual(1, result.LowerBound, 1e-6);
+        Assert.AreEqual(4, result.UpperBound);
+
+        result = evaluator.Evaluate(t6, intervals);
+        Assert.AreEqual(1, result.LowerBound);
+        Assert.AreEqual(16, result.UpperBound);
+
+        result = evaluator.Evaluate(t7, intervals);
+        Assert.AreEqual(-15, result.LowerBound);
+        Assert.AreEqual(0, result.UpperBound);
+
+        result = evaluator.Evaluate(t8, intervals);
+        Assert.AreEqual(-19500, result.LowerBound);
+        Assert.AreEqual(0, result.UpperBound);
+
+        result = evaluator.Evaluate(t9, intervals);
+        Assert.AreEqual(-19513.86294, result.LowerBound, 1e-3);
+        Assert.AreEqual(0, result.UpperBound);
+
+
+      }
+
     }
   }
