From ba8cae2abb3e92b3fbacec866675f5a3120a8be6 Mon Sep 17 00:00:00 2001 From: Scott Stephens Date: Thu, 13 Jun 2013 17:25:58 -0500 Subject: [PATCH] Optimization: Add the point which was being evaluated to EvaluationError (updated by cdrnet) --- src/Numerics/Optimization/BfgsMinimizer.cs | 73 ++++++++++++++----- .../ConjugateGradientMinimizer.cs | 10 +-- src/Numerics/Optimization/Exceptions.cs | 25 +++++-- src/Numerics/Optimization/ExitCondition.cs | 7 ++ .../Optimization/GoldenSectionMinimizer.cs | 2 +- src/Numerics/Optimization/LineSearchOutput.cs | 4 +- .../LineSearchingMinimizerOutput.cs | 4 +- .../Optimization/MinimizationOutput.cs | 6 +- src/Numerics/Optimization/NewtonMinimizer.cs | 12 +-- src/Numerics/Optimization/ObjectiveChecker.cs | 8 +- .../Optimization/ObjectiveChecker1D.cs | 9 ++- .../Optimization/ObjectiveFunction.cs | 44 ++++++++++- .../Optimization/WeakWolfeLineSearch.cs | 33 +++++++-- 13 files changed, 179 insertions(+), 58 deletions(-) create mode 100644 src/Numerics/Optimization/ExitCondition.cs diff --git a/src/Numerics/Optimization/BfgsMinimizer.cs b/src/Numerics/Optimization/BfgsMinimizer.cs index 8068a3cf..45ed0209 100644 --- a/src/Numerics/Optimization/BfgsMinimizer.cs +++ b/src/Numerics/Optimization/BfgsMinimizer.cs @@ -6,14 +6,17 @@ using MathNet.Numerics.LinearAlgebra; namespace MathNet.Numerics.Optimization { + public class BfgsMinimizer { public double GradientTolerance { get; set; } + public double ParameterTolerance { get; set; } public int MaximumIterations { get; set; } - public BfgsMinimizer(double gradient_tolerance, int maximum_iterations) + public BfgsMinimizer(double gradient_tolerance, double parameter_tolerance, int maximum_iterations) { this.GradientTolerance = gradient_tolerance; + this.ParameterTolerance = parameter_tolerance; this.MaximumIterations = maximum_iterations; } @@ -28,16 +31,17 @@ namespace MathNet.Numerics.Optimization IEvaluation initial_eval = objective.Evaluate(initial_guess); // Check that we're not already done - if (this.ExitCriteriaSatisfied(initial_guess, initial_eval.Gradient)) - return new MinimizationOutput(initial_eval, 0); + ExitCondition current_exit_condition = this.ExitCriteriaSatisfied(initial_eval, null); + if (current_exit_condition != ExitCondition.None) + return new MinimizationOutput(initial_eval, 0, current_exit_condition); // Set up line search algorithm - var line_searcher = new WeakWolfeLineSearch(1e-4, 0.9, 1000); + var line_searcher = new WeakWolfeLineSearch(1e-4, 0.9,this.ParameterTolerance, max_iterations:1000); // Declare state variables - IEvaluation candidate_point; + IEvaluation candidate_point, previous_point; double step_size; - Vector gradient, previous_gradient, step, search_direction; + Vector gradient, step, search_direction; Matrix inverse_pseudo_hessian; // First step @@ -55,27 +59,27 @@ namespace MathNet.Numerics.Optimization throw new InnerOptimizationException("Line search failed.", e); } + previous_point = initial_eval; candidate_point = result.FunctionInfoAtMinimum; - gradient = candidate_point.Gradient; - previous_gradient = initial_eval.Gradient; + gradient = candidate_point.Gradient; step = candidate_point.Point - initial_guess; step_size = result.FinalStep; // Subsequent steps - int iterations = 1; + int iterations; int total_line_search_steps = result.Iterations; int iterations_with_nontrivial_line_search = result.Iterations > 0 ? 0 : 1; int steepest_descent_resets = 0; - while (!this.ExitCriteriaSatisfied(candidate_point.Point, candidate_point.Gradient) && iterations < this.MaximumIterations) + for (iterations = 1; iterations < this.MaximumIterations; ++iterations) { - var y = candidate_point.Gradient - previous_gradient; + var y = candidate_point.Gradient - previous_point.Gradient; double sy = step * y; inverse_pseudo_hessian = inverse_pseudo_hessian + ((sy + y * inverse_pseudo_hessian * y) / Math.Pow(sy, 2.0)) * step.OuterProduct(step) - ( (inverse_pseudo_hessian * y.ToColumnMatrix())*step.ToRowMatrix() + step.ToColumnMatrix()*(y.ToRowMatrix() * inverse_pseudo_hessian)) * (1.0 / sy); - search_direction = -inverse_pseudo_hessian * candidate_point.Gradient; + search_direction = -inverse_pseudo_hessian * candidate_point.Gradient; - if (search_direction * candidate_point.Gradient >= 0) + if (search_direction * candidate_point.Gradient >= -this.GradientTolerance*this.GradientTolerance) { search_direction = -candidate_point.Gradient; inverse_pseudo_hessian = Matrix.Build.DiagonalIdentity(initial_guess.Count); @@ -96,21 +100,50 @@ namespace MathNet.Numerics.Optimization step_size = result.FinalStep; step = result.FunctionInfoAtMinimum.Point - candidate_point.Point; - previous_gradient = candidate_point.Gradient; + previous_point = candidate_point; candidate_point = result.FunctionInfoAtMinimum; - iterations += 1; + current_exit_condition = this.ExitCriteriaSatisfied(candidate_point, previous_point); + if (current_exit_condition != ExitCondition.None) + break; } if (iterations == this.MaximumIterations) throw new MaximumIterationsException(String.Format("Maximum iterations ({0}) reached.", this.MaximumIterations)); - return new MinimizationWithLineSearchOutput(candidate_point, iterations, total_line_search_steps, iterations_with_nontrivial_line_search); + return new MinimizationWithLineSearchOutput(candidate_point, iterations, current_exit_condition, total_line_search_steps, iterations_with_nontrivial_line_search); } - private bool ExitCriteriaSatisfied(Vector candidate_point, Vector gradient) + private ExitCondition ExitCriteriaSatisfied(IEvaluation candidate_point, IEvaluation last_point) { - return gradient.Norm(2.0) < this.GradientTolerance; + Vector rel_grad = new MathNet.Numerics.LinearAlgebra.Double.DenseVector(candidate_point.Point.Count); + double relative_gradient = 0.0; + double normalizer = Math.Max(Math.Abs(candidate_point.Value),1.0); + for (int ii = 0; ii < rel_grad.Count; ++ii) + { + double tmp = candidate_point.Gradient[ii]*Math.Max(Math.Abs(candidate_point.Point[ii]), 1.0) / normalizer; + relative_gradient = Math.Max(relative_gradient, Math.Abs(tmp)); + } + if (relative_gradient < this.GradientTolerance) + { + return ExitCondition.RelativeGradient; + } + + if (last_point != null) + { + double most_progress = 0.0; + for (int ii = 0; ii < candidate_point.Point.Count; ++ii) + { + var tmp = Math.Abs(candidate_point.Point[ii] - last_point.Point[ii])/Math.Max(Math.Abs(last_point.Point[ii]),1.0); + most_progress = Math.Max(most_progress, tmp); + } + if ( most_progress < this.ParameterTolerance ) + { + return ExitCondition.LackOfProgress; + } + } + + return ExitCondition.None; } private void ValidateGradient(Vector gradient, Vector input) @@ -118,14 +151,14 @@ namespace MathNet.Numerics.Optimization foreach (var x in gradient) { if (Double.IsNaN(x) || Double.IsInfinity(x)) - throw new EvaluationException("Non-finite gradient returned."); + throw new EvaluationException("Non-finite gradient returned.",input); } } private void ValidateObjective(double objective, Vector input) { if (Double.IsNaN(objective) || Double.IsInfinity(objective)) - throw new EvaluationException("Non-finite objective function returned."); + throw new EvaluationException("Non-finite objective function returned.", input); } } } diff --git a/src/Numerics/Optimization/ConjugateGradientMinimizer.cs b/src/Numerics/Optimization/ConjugateGradientMinimizer.cs index 34758ad6..bd123256 100644 --- a/src/Numerics/Optimization/ConjugateGradientMinimizer.cs +++ b/src/Numerics/Optimization/ConjugateGradientMinimizer.cs @@ -31,10 +31,10 @@ namespace MathNet.Numerics.Optimization // Check that we're not already done if (this.ExitCriteriaSatisfied(initial_guess, gradient)) - return new MinimizationOutput(initial_eval, 0); + return new MinimizationOutput(initial_eval, 0, ExitCondition.AbsoluteGradient); // Set up line search algorithm - var line_searcher = new WeakWolfeLineSearch(1e-4, 0.1,1000); + var line_searcher = new WeakWolfeLineSearch(1e-4, 0.1, 1e-4, max_iterations:1000); // Declare state variables IEvaluation candidate_point; @@ -106,7 +106,7 @@ namespace MathNet.Numerics.Optimization if (iterations == this.MaximumIterations) throw new MaximumIterationsException(String.Format("Maximum iterations ({0}) reached.", this.MaximumIterations)); - return new MinimizationWithLineSearchOutput(candidate_point, iterations, total_line_search_steps, iterations_with_nontrivial_line_search); + return new MinimizationWithLineSearchOutput(candidate_point, iterations, ExitCondition.AbsoluteGradient, total_line_search_steps, iterations_with_nontrivial_line_search); } private bool ExitCriteriaSatisfied(Vector candidate_point, Vector gradient) @@ -119,14 +119,14 @@ namespace MathNet.Numerics.Optimization foreach (var x in gradient) { if (Double.IsNaN(x) || Double.IsInfinity(x)) - throw new EvaluationException("Non-finite gradient returned."); + throw new EvaluationException("Non-finite gradient returned.", input); } } private void ValidateObjective(double objective, Vector input) { if (Double.IsNaN(objective) || Double.IsInfinity(objective)) - throw new EvaluationException("Non-finite objective function returned."); + throw new EvaluationException("Non-finite objective function returned.", input); } } } diff --git a/src/Numerics/Optimization/Exceptions.cs b/src/Numerics/Optimization/Exceptions.cs index fcb0f758..841f97cb 100644 --- a/src/Numerics/Optimization/Exceptions.cs +++ b/src/Numerics/Optimization/Exceptions.cs @@ -2,6 +2,8 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using MathNet.Numerics.LinearAlgebra; +using MathNet.Numerics.LinearAlgebra.Double; namespace MathNet.Numerics.Optimization { @@ -22,11 +24,24 @@ namespace MathNet.Numerics.Optimization public class EvaluationException : OptimizationException { - public EvaluationException(string message) - : base(message) {} - - public EvaluationException(string message, Exception inner_exception) - : base(message, inner_exception) { } + public Vector Point { get; private set; } + public EvaluationException(string message, Vector point) + : base(message) + { + this.Point = point; + } + + public EvaluationException(string message, double point) + : base(message) + { + this.Point = new DenseVector(1, point); + } + + public EvaluationException(string message, Exception inner_exception, Vector point) + : base(message, inner_exception) + { + this.Point = point; + } } public class InnerOptimizationException : OptimizationException diff --git a/src/Numerics/Optimization/ExitCondition.cs b/src/Numerics/Optimization/ExitCondition.cs new file mode 100644 index 00000000..44477294 --- /dev/null +++ b/src/Numerics/Optimization/ExitCondition.cs @@ -0,0 +1,7 @@ +using System; + +namespace MathNet.Numerics +{ + public enum ExitCondition { None, RelativeGradient, LackOfProgress, AbsoluteGradient, WeakWolfeCriteria } +} + diff --git a/src/Numerics/Optimization/GoldenSectionMinimizer.cs b/src/Numerics/Optimization/GoldenSectionMinimizer.cs index a43fda08..9f9cd81b 100644 --- a/src/Numerics/Optimization/GoldenSectionMinimizer.cs +++ b/src/Numerics/Optimization/GoldenSectionMinimizer.cs @@ -66,7 +66,7 @@ namespace MathNet.Numerics.Optimization private void ValueChecker(double value, double point) { if (Double.IsNaN(value) || Double.IsInfinity(value)) - throw new EvaluationException("Objective function returned non-finite value."); + throw new EvaluationException("Objective function returned non-finite value.", point); } private static double _golden_ratio = (1.0 + Math.Sqrt(5)) / 2.0; } diff --git a/src/Numerics/Optimization/LineSearchOutput.cs b/src/Numerics/Optimization/LineSearchOutput.cs index bf2db97d..0659f60e 100644 --- a/src/Numerics/Optimization/LineSearchOutput.cs +++ b/src/Numerics/Optimization/LineSearchOutput.cs @@ -9,8 +9,8 @@ namespace MathNet.Numerics.Optimization { public double FinalStep { get; private set; } - public LineSearchOutput(IEvaluation function_info, int iterations, double final_step) - : base(function_info, iterations) + public LineSearchOutput(IEvaluation function_info, int iterations, double final_step, ExitCondition reason_for_exit) + : base(function_info, iterations, reason_for_exit) { this.FinalStep = final_step; } diff --git a/src/Numerics/Optimization/LineSearchingMinimizerOutput.cs b/src/Numerics/Optimization/LineSearchingMinimizerOutput.cs index a6890a1d..2cd00ad9 100644 --- a/src/Numerics/Optimization/LineSearchingMinimizerOutput.cs +++ b/src/Numerics/Optimization/LineSearchingMinimizerOutput.cs @@ -10,8 +10,8 @@ namespace MathNet.Numerics.Optimization public int TotalLineSearchIterations { get; private set; } public int IterationsWithNonTrivialLineSearch { get; private set; } - public MinimizationWithLineSearchOutput(IEvaluation function_info, int iterations, int total_line_search_iterations, int iterations_with_non_trivial_line_search) - : base(function_info, iterations) + public MinimizationWithLineSearchOutput(IEvaluation function_info, int iterations, ExitCondition reason_for_exit, int total_line_search_iterations, int iterations_with_non_trivial_line_search) + : base(function_info, iterations, reason_for_exit) { this.TotalLineSearchIterations = total_line_search_iterations; this.IterationsWithNonTrivialLineSearch = iterations_with_non_trivial_line_search; diff --git a/src/Numerics/Optimization/MinimizationOutput.cs b/src/Numerics/Optimization/MinimizationOutput.cs index 25a09cc4..d4ef5104 100644 --- a/src/Numerics/Optimization/MinimizationOutput.cs +++ b/src/Numerics/Optimization/MinimizationOutput.cs @@ -11,12 +11,14 @@ namespace MathNet.Numerics.Optimization { public Vector MinimizingPoint { get { return FunctionInfoAtMinimum.Point; } } public IEvaluation FunctionInfoAtMinimum { get; private set; } - public int Iterations { get; private set; } + public int Iterations { get; private set; } + public ExitCondition ReasonForExit { get; private set; } - public MinimizationOutput(IEvaluation function_info, int iterations) + public MinimizationOutput(IEvaluation function_info, int iterations, ExitCondition reason_for_exit) { this.FunctionInfoAtMinimum = function_info; this.Iterations = iterations; + this.ReasonForExit = reason_for_exit; } } } diff --git a/src/Numerics/Optimization/NewtonMinimizer.cs b/src/Numerics/Optimization/NewtonMinimizer.cs index 901b5ecc..3e10affa 100644 --- a/src/Numerics/Optimization/NewtonMinimizer.cs +++ b/src/Numerics/Optimization/NewtonMinimizer.cs @@ -35,10 +35,10 @@ namespace MathNet.Numerics.Optimization // Check that we're not already done if (this.ExitCriteriaSatisfied(initial_guess, initial_eval.Gradient)) - return new MinimizationOutput(initial_eval, 0); + return new MinimizationOutput(initial_eval, 0, ExitCondition.AbsoluteGradient); // Set up line search algorithm - var line_searcher = new WeakWolfeLineSearch(1e-4, 0.9, 1000); + var line_searcher = new WeakWolfeLineSearch(1e-4, 0.9, 1e-4, max_iterations:1000); // Declare state variables IEvaluation candidate_point = initial_eval; @@ -90,7 +90,7 @@ namespace MathNet.Numerics.Optimization if (iterations == this.MaximumIterations) throw new MaximumIterationsException(String.Format("Maximum iterations ({0}) reached.", this.MaximumIterations)); - return new MinimizationWithLineSearchOutput(candidate_point, iterations, total_line_search_steps, iterations_with_nontrivial_line_search); + return new MinimizationWithLineSearchOutput(candidate_point, iterations, ExitCondition.AbsoluteGradient, total_line_search_steps, iterations_with_nontrivial_line_search); } private bool ExitCriteriaSatisfied(Vector candidate_point, Vector gradient) @@ -103,14 +103,14 @@ namespace MathNet.Numerics.Optimization foreach (var x in gradient) { if (Double.IsNaN(x) || Double.IsInfinity(x)) - throw new EvaluationException("Non-finite gradient returned."); + throw new EvaluationException("Non-finite gradient returned.", input); } } private void ValidateObjective(double objective, Vector input) { if (Double.IsNaN(objective) || Double.IsInfinity(objective)) - throw new EvaluationException("Non-finite objective function returned."); + throw new EvaluationException("Non-finite objective function returned.", input); } private void ValidateHessian(Matrix hessian, Vector input) @@ -120,7 +120,7 @@ namespace MathNet.Numerics.Optimization for (int jj = 0; jj < hessian.ColumnCount; ++jj) { if (Double.IsNaN(hessian[ii,jj]) || Double.IsInfinity(hessian[ii,jj])) - throw new EvaluationException("Non-finite Hessian returned."); + throw new EvaluationException("Non-finite Hessian returned.", input); } } } diff --git a/src/Numerics/Optimization/ObjectiveChecker.cs b/src/Numerics/Optimization/ObjectiveChecker.cs index d0d6c42b..f80c5881 100644 --- a/src/Numerics/Optimization/ObjectiveChecker.cs +++ b/src/Numerics/Optimization/ObjectiveChecker.cs @@ -39,7 +39,7 @@ namespace MathNet.Numerics.Optimization } catch (Exception e) { - throw new EvaluationException("Objective function evaluation failed.", e); + throw new EvaluationException("Objective function evaluation failed.", e, this.Point); } this.Checker.ValueChecker(tmp,this.InnerEvaluation.Point); } @@ -61,7 +61,7 @@ namespace MathNet.Numerics.Optimization } catch (Exception e) { - throw new EvaluationException("Objective gradient evaluation failed.", e); + throw new EvaluationException("Objective gradient evaluation failed.", e, this.Point); } this.Checker.GradientChecker(tmp, this.InnerEvaluation.Point); } @@ -83,7 +83,7 @@ namespace MathNet.Numerics.Optimization } catch (Exception e) { - throw new EvaluationException("Objective hessian evaluation failed.", e); + throw new EvaluationException("Objective hessian evaluation failed.", e, this.Point); } this.Checker.HessianChecker(tmp, this.InnerEvaluation.Point); } @@ -125,7 +125,7 @@ namespace MathNet.Numerics.Optimization } catch (Exception e) { - throw new EvaluationException("Objective evaluation failed.", e); + throw new EvaluationException("Objective evaluation failed.", e, point); } } } diff --git a/src/Numerics/Optimization/ObjectiveChecker1D.cs b/src/Numerics/Optimization/ObjectiveChecker1D.cs index 6ba0a7db..ebd3ccc6 100644 --- a/src/Numerics/Optimization/ObjectiveChecker1D.cs +++ b/src/Numerics/Optimization/ObjectiveChecker1D.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using MathNet.Numerics.LinearAlgebra.Double; namespace MathNet.Numerics.Optimization { @@ -38,7 +39,7 @@ namespace MathNet.Numerics.Optimization } catch (Exception e) { - throw new EvaluationException("Objective function evaluation failed.", e); + throw new EvaluationException("Objective function evaluation failed.", e, new DenseVector(1, this.Point)); } this.Checker.ValueChecker(tmp, this.InnerEvaluation.Point); } @@ -60,7 +61,7 @@ namespace MathNet.Numerics.Optimization } catch (Exception e) { - throw new EvaluationException("Objective derivative evaluation failed.", e); + throw new EvaluationException("Objective derivative evaluation failed.", e, new DenseVector(1, this.Point)); } this.Checker.DerivativeChecker(tmp, this.InnerEvaluation.Point); } @@ -82,7 +83,7 @@ namespace MathNet.Numerics.Optimization } catch (Exception e) { - throw new EvaluationException("Objective second derivative evaluation failed.", e); + throw new EvaluationException("Objective second derivative evaluation failed.", e, new DenseVector(1,this.Point)); } this.Checker.SecondDerivativeChecker(tmp, this.InnerEvaluation.Point); } @@ -124,7 +125,7 @@ namespace MathNet.Numerics.Optimization } catch (Exception e) { - throw new EvaluationException("Objective evaluation failed.", e); + throw new EvaluationException("Objective evaluation failed.", e, new DenseVector(1,point)); } } } diff --git a/src/Numerics/Optimization/ObjectiveFunction.cs b/src/Numerics/Optimization/ObjectiveFunction.cs index 969d6858..342c69a3 100644 --- a/src/Numerics/Optimization/ObjectiveFunction.cs +++ b/src/Numerics/Optimization/ObjectiveFunction.cs @@ -9,7 +9,7 @@ namespace MathNet.Numerics.Optimization { public interface IEvaluation { - Vector Point { get; } + Vector Point { get; } double Value { get; } Vector Gradient { get; } Matrix Hessian { get; } @@ -22,6 +22,48 @@ namespace MathNet.Numerics.Optimization IEvaluation Evaluate(Vector point); } + public abstract class BaseEvaluation : IEvaluation + { + protected double? _value; + protected Vector _gradient; + protected Matrix _hessian; + protected Vector _point; + + public Vector Point { get { return _point; } } + public double Value + { + get + { + if (!_value.HasValue) + setValue(); + return _value.Value; + } + } + public Vector Gradient + { + get + { + if (_gradient == null) + setGradient(); + return _gradient; + } + } + public Matrix Hessian + { + get + { + if (_hessian == null) + setHessian(); + return _hessian; + } + } + + protected abstract void setValue(); + protected abstract void setGradient(); + protected abstract void setHessian(); + } + + public class CachedEvaluation : IEvaluation { private double? _value; diff --git a/src/Numerics/Optimization/WeakWolfeLineSearch.cs b/src/Numerics/Optimization/WeakWolfeLineSearch.cs index 809a3068..40133403 100644 --- a/src/Numerics/Optimization/WeakWolfeLineSearch.cs +++ b/src/Numerics/Optimization/WeakWolfeLineSearch.cs @@ -11,12 +11,14 @@ namespace MathNet.Numerics.Optimization { public double C1 { get; set; } public double C2 { get; set; } + public double ParameterTolerance { get; set; } public int MaximumIterations { get; set; } - public WeakWolfeLineSearch(double c1, double c2, int max_iterations=10) + public WeakWolfeLineSearch(double c1, double c2, double parameter_tolerance, int max_iterations=10) { this.C1 = c1; this.C2 = c2; + this.ParameterTolerance = parameter_tolerance; this.MaximumIterations = max_iterations; } @@ -38,6 +40,7 @@ namespace MathNet.Numerics.Optimization int ii; IEvaluation candidate_eval = null; + ExitCondition reason_for_exit = ExitCondition.None; for (ii = 0; ii < this.MaximumIterations; ++ii) { candidate_eval = objective.Evaluate(starting_point.Point + search_direction * step); @@ -56,14 +59,32 @@ namespace MathNet.Numerics.Optimization } else { + reason_for_exit = ExitCondition.WeakWolfeCriteria; break; } + + if (!Double.IsInfinity(upper_bound)) + { + double max_rel_change = 0.0; + for (int jj = 0; jj < candidate_eval.Point.Count; ++jj) + { + double tmp = Math.Abs (search_direction[jj]*(upper_bound - lower_bound)) / Math.Max(Math.Abs(candidate_eval.Point[jj]),1.0); + max_rel_change = Math.Max(max_rel_change, tmp); + } + if (max_rel_change < this.ParameterTolerance) + { + reason_for_exit = ExitCondition.LackOfProgress; + break; + } + } } - if (ii == this.MaximumIterations) - throw new MaximumIterationsException(String.Format("Maximum iterations ({0}) reached. Function may be unbounded in search direction.",this.MaximumIterations)); + if (ii == this.MaximumIterations && Double.IsPositiveInfinity(upper_bound)) + throw new MaximumIterationsException(String.Format("Maximum iterations ({0}) reached. Function appears to be unbounded in search direction.",this.MaximumIterations)); + else if (ii == this.MaximumIterations) + throw new MaximumIterationsException(String.Format("Maximum iterations ({0}) reached.",this.MaximumIterations)); else - return new LineSearchOutput(candidate_eval, ii, step); + return new LineSearchOutput(candidate_eval, ii, step, reason_for_exit); } private bool Conforms(IEvaluation starting_point, Vector search_direction, double step, IEvaluation ending_point) @@ -78,7 +99,7 @@ namespace MathNet.Numerics.Optimization private void ValidateValue(double value, Vector input) { if (!this.IsFinite(value)) - throw new EvaluationException(String.Format("Non-finite value returned by objective function: {0}", value)); + throw new EvaluationException(String.Format("Non-finite value returned by objective function: {0}", value),input); } private void ValidateGradient(Vector gradient, Vector input) @@ -86,7 +107,7 @@ namespace MathNet.Numerics.Optimization foreach (double x in gradient) if (!this.IsFinite(x)) { - throw new EvaluationException(String.Format("Non-finite value returned by gradient: {0}", x)); + throw new EvaluationException(String.Format("Non-finite value returned by gradient: {0}", x),input); } }