Index: /branches/2994-AutoDiffForIntervals/HeuristicLab.Problems.DataAnalysis.Regression.Symbolic.Extensions/ConstrainedConstantOptimizationEvaluator.cs
===================================================================
--- /branches/2994-AutoDiffForIntervals/HeuristicLab.Problems.DataAnalysis.Regression.Symbolic.Extensions/ConstrainedConstantOptimizationEvaluator.cs	(revision 17005)
+++ /branches/2994-AutoDiffForIntervals/HeuristicLab.Problems.DataAnalysis.Regression.Symbolic.Extensions/ConstrainedConstantOptimizationEvaluator.cs	(revision 17006)
@@ -74,4 +74,7 @@
       get { return (IFixedValueParameter<BoolValue>)Parameters[CountEvaluationsParameterName]; }
     }
+    public IConstrainedValueParameter<StringValue> SolverParameter {
+      get { return (IConstrainedValueParameter<StringValue>)Parameters["Solver"]; }
+    }
 
 
@@ -103,4 +106,7 @@
     }
 
+    public string Solver {
+      get { return SolverParameter.Value.Value; }
+    }
     public override bool Maximization {
       get { return false; }
@@ -122,4 +128,6 @@
 
       Parameters.Add(new FixedValueParameter<BoolValue>(CountEvaluationsParameterName, "Determines if function and gradient evaluation should be counted.", new BoolValue(false)));
+      var validSolvers = new ItemSet<StringValue>(new[] { "non-smooth (minns)", "sequential linear programming (minnlc)" }.Select(s => new StringValue(s).AsReadOnly()));
+      Parameters.Add(new ConstrainedValueParameter<StringValue>("Solver", "The solver algorithm", validSolvers, validSolvers.First()));
       Parameters.Add(new ResultParameter<IntValue>(FunctionEvaluationsResultParameterName, "The number of function evaluations performed by the constants optimization evaluator", "Results", new IntValue()));
       Parameters.Add(new ResultParameter<IntValue>(GradientEvaluationsResultParameterName, "The number of gradient evaluations performed by the constants optimization evaluator", "Results", new IntValue()));
@@ -142,5 +150,5 @@
         var counter = new EvaluationsCounter();
         quality = OptimizeConstants(SymbolicDataAnalysisTreeInterpreterParameter.ActualValue, solution, ProblemDataParameter.ActualValue,
-           constantOptimizationRows, ApplyLinearScalingParameter.ActualValue.Value, ConstantOptimizationIterations.Value, updateVariableWeights: UpdateVariableWeights, lowerEstimationLimit: EstimationLimitsParameter.ActualValue.Lower, upperEstimationLimit: EstimationLimitsParameter.ActualValue.Upper, updateConstantsInTree: UpdateConstantsInTree, counter: counter);
+           constantOptimizationRows, ApplyLinearScalingParameter.ActualValue.Value, Solver, ConstantOptimizationIterations.Value, updateVariableWeights: UpdateVariableWeights, lowerEstimationLimit: EstimationLimitsParameter.ActualValue.Lower, upperEstimationLimit: EstimationLimitsParameter.ActualValue.Upper, updateConstantsInTree: UpdateConstantsInTree, counter: counter);
 
         if (ConstantOptimizationRowsPercentage.Value != RelativeNumberOfEvaluatedSamplesParameter.ActualValue.Value) {
@@ -210,4 +218,5 @@
     public static double OptimizeConstants(ISymbolicDataAnalysisExpressionTreeInterpreter interpreter,
       ISymbolicExpressionTree tree, IRegressionProblemData problemData, IEnumerable<int> rows, bool applyLinearScaling,
+      string solver,
       int maxIterations, bool updateVariableWeights = true,
       double lowerEstimationLimit = double.MinValue, double upperEstimationLimit = double.MaxValue,
@@ -323,49 +332,98 @@
       }
 
-
-
-      alglib.minnsstate state;
-      alglib.minnsreport rep;
-      try {
-        alglib.minnscreate(thetaValues.Count, thetaValues.ToArray(), out state);
-        // alglib.minnssetalgoslp(state);        // SLP is more robust but slower
-        alglib.minnssetbc(state, thetaValues.Select(_ => -10000.0).ToArray(), thetaValues.Select(_ => +10000.0).ToArray());
-        alglib.minnssetcond(state, 1E-7, maxIterations);
-        var s = Enumerable.Repeat(1d, thetaValues.Count).ToArray();  // scale is set to unit scale
-        alglib.minnssetscale(state, s);
-
-        // set non-linear constraints: 0 equality constraints, constraintTrees inequality constraints
-        alglib.minnssetnlc(state, 0, constraintTrees.Count);
-
-        alglib.minnsoptimize(state, calculate_jacobian, null, null);
-        alglib.minnsresults(state, out double[] xOpt, out rep);
-
-
-        // counter.FunctionEvaluations += rep.nfev; TODO
-        counter.GradientEvaluations += rep.nfev;
-
-        if (rep.terminationtype != -8) {
-          // update parameters in tree
-          var pIdx = 0;
-          foreach (var node in tree.IterateNodesPostfix()) {
-            if(node is ConstantTreeNode constTreeNode) {
-              constTreeNode.Value = xOpt[pIdx++];
-            } else if(node is VariableTreeNode varTreeNode) {
-              varTreeNode.Weight = xOpt[pIdx++];
+      if (solver.Contains("minns")) {
+        alglib.minnsstate state;
+        alglib.minnsreport rep;
+        try {
+          alglib.minnscreate(thetaValues.Count, thetaValues.ToArray(), out state);
+          // alglib.minnssetalgoslp(state);        // SLP is more robust but slower
+          alglib.minnssetbc(state, thetaValues.Select(_ => -10000.0).ToArray(), thetaValues.Select(_ => +10000.0).ToArray());
+          alglib.minnssetcond(state, 1E-7, maxIterations);
+          var s = Enumerable.Repeat(1d, thetaValues.Count).ToArray();  // scale is set to unit scale
+          alglib.minnssetscale(state, s);
+
+          // set non-linear constraints: 0 equality constraints, constraintTrees inequality constraints
+          alglib.minnssetnlc(state, 0, constraintTrees.Count);
+
+          alglib.minnsoptimize(state, calculate_jacobian, null, null);
+          alglib.minnsresults(state, out double[] xOpt, out rep);
+
+
+          // counter.FunctionEvaluations += rep.nfev; TODO
+          counter.GradientEvaluations += rep.nfev;
+
+          if (rep.terminationtype != -8) {
+            // update parameters in tree
+            var pIdx = 0;
+            foreach (var node in tree.IterateNodesPostfix()) {
+              if (node is ConstantTreeNode constTreeNode) {
+                constTreeNode.Value = xOpt[pIdx++];
+              } else if (node is VariableTreeNode varTreeNode) {
+                varTreeNode.Weight = xOpt[pIdx++];
+              }
             }
-          }
-
-          // note: we keep the optimized constants even when the tree is worse.
-        }
-
-      } catch (ArithmeticException) {
-        // eval MSE of original tree
-        return SymbolicRegressionSingleObjectiveMeanSquaredErrorEvaluator.Calculate(interpreter, tree, lowerEstimationLimit, upperEstimationLimit, problemData, rows, applyLinearScaling: false);
-
-      } catch (alglib.alglibexception) {
-        // eval MSE of original tree
-        return SymbolicRegressionSingleObjectiveMeanSquaredErrorEvaluator.Calculate(interpreter, tree, lowerEstimationLimit, upperEstimationLimit, problemData, rows, applyLinearScaling: false);
-      }
-
+
+            // note: we keep the optimized constants even when the tree is worse.
+          }
+
+        } catch (ArithmeticException) {
+          // eval MSE of original tree
+          return SymbolicRegressionSingleObjectiveMeanSquaredErrorEvaluator.Calculate(interpreter, tree, lowerEstimationLimit, upperEstimationLimit, problemData, rows, applyLinearScaling: false);
+
+        } catch (alglib.alglibexception) {
+          // eval MSE of original tree
+          return SymbolicRegressionSingleObjectiveMeanSquaredErrorEvaluator.Calculate(interpreter, tree, lowerEstimationLimit, upperEstimationLimit, problemData, rows, applyLinearScaling: false);
+        }
+      } else if (solver.Contains("minnlc")) {
+        alglib.minnlcstate state;
+        alglib.minnlcreport rep;
+        alglib.optguardreport optGuardRep;
+        try {
+          alglib.minnlccreate(thetaValues.Count, thetaValues.ToArray(), out state);
+          alglib.minnlcsetalgoslp(state);        // SLP is more robust but slower
+          alglib.minnlcsetbc(state, thetaValues.Select(_ => -10000.0).ToArray(), thetaValues.Select(_ => +10000.0).ToArray());
+          alglib.minnlcsetcond(state, 1E-7, maxIterations);
+          var s = Enumerable.Repeat(1d, thetaValues.Count).ToArray();  // scale is set to unit scale
+          alglib.minnlcsetscale(state, s);
+
+          // set non-linear constraints: 0 equality constraints, constraintTrees inequality constraints
+          alglib.minnlcsetnlc(state, 0, constraintTrees.Count);
+          alglib.minnlcoptguardsmoothness(state, 1);
+
+          alglib.minnlcoptimize(state, calculate_jacobian, null, null);
+          alglib.minnlcresults(state, out double[] xOpt, out rep);
+          alglib.minnlcoptguardresults(state, out optGuardRep);
+          if (optGuardRep.nonc0suspected) throw new InvalidProgramException("optGuardRep.nonc0suspected");
+          if (optGuardRep.nonc1suspected) throw new InvalidProgramException("optGuardRep.nonc1suspected");
+
+          // counter.FunctionEvaluations += rep.nfev; TODO
+          counter.GradientEvaluations += rep.nfev;
+
+          if (rep.terminationtype != -8) {
+            // update parameters in tree
+            var pIdx = 0;
+            foreach (var node in tree.IterateNodesPostfix()) {
+              if (node is ConstantTreeNode constTreeNode) {
+                constTreeNode.Value = xOpt[pIdx++];
+              } else if (node is VariableTreeNode varTreeNode) {
+                varTreeNode.Weight = xOpt[pIdx++];
+              }
+            }
+
+            // note: we keep the optimized constants even when the tree is worse.
+          }
+
+        } catch (ArithmeticException) {
+          // eval MSE of original tree
+          return SymbolicRegressionSingleObjectiveMeanSquaredErrorEvaluator.Calculate(interpreter, tree, lowerEstimationLimit, upperEstimationLimit, problemData, rows, applyLinearScaling: false);
+
+        } catch (alglib.alglibexception) {
+          // eval MSE of original tree
+          return SymbolicRegressionSingleObjectiveMeanSquaredErrorEvaluator.Calculate(interpreter, tree, lowerEstimationLimit, upperEstimationLimit, problemData, rows, applyLinearScaling: false);
+        }
+      } else {
+        throw new ArgumentException($"Unknown solver {solver}");
+      }
+    
 
       // evaluate tree with updated constants
