diff --git a/src/Numerics/Optimization/Implementation/CheckedObjectiveFunction.cs b/src/Numerics/Optimization/Implementation/CheckedObjectiveFunction.cs index 04159fc7..9b5ef05e 100644 --- a/src/Numerics/Optimization/Implementation/CheckedObjectiveFunction.cs +++ b/src/Numerics/Optimization/Implementation/CheckedObjectiveFunction.cs @@ -30,13 +30,15 @@ namespace MathNet.Numerics.Optimization.Implementation public void EvaluateAt(Vector point) { InnerObjectiveFunction.EvaluateAt(point); + _valueChecked = false; + _gradientChecked = false; + _hessianChecked = false; } public double Value { get { - if (!_valueChecked) { double tmp; diff --git a/src/Numerics/Optimization/Implementation/WeakWolfeLineSearch.cs b/src/Numerics/Optimization/Implementation/WeakWolfeLineSearch.cs index cc6e3c44..656e764a 100644 --- a/src/Numerics/Optimization/Implementation/WeakWolfeLineSearch.cs +++ b/src/Numerics/Optimization/Implementation/WeakWolfeLineSearch.cs @@ -22,10 +22,6 @@ namespace MathNet.Numerics.Optimization.Implementation public LineSearchOutput FindConformingStep(IObjectiveFunctionEvaluation startingPoint, Vector searchDirection, double initialStep) { var objective = startingPoint.Fork(); - if (!(objective is CheckedObjectiveFunction)) - { - objective = new CheckedObjectiveFunction(objective, ValidateValue, ValidateGradient, null); - } double lowerBound = 0.0; double upperBound = Double.PositiveInfinity; @@ -42,6 +38,8 @@ namespace MathNet.Numerics.Optimization.Implementation for (ii = 0; ii < _maximumIterations; ++ii) { objective.EvaluateAt(initialPoint + searchDirection * step); + ValidateGradient(objective); + ValidateValue(objective); double stepDd = searchDirection * objective.Gradient; @@ -98,7 +96,7 @@ namespace MathNet.Numerics.Optimization.Implementation return step > 0 && sufficientDecrease && notTooSteep; } - void ValidateValue(IObjectiveFunction eval) + static void ValidateValue(IObjectiveFunction eval) { if (!IsFinite(eval.Value)) { @@ -106,7 +104,7 @@ namespace MathNet.Numerics.Optimization.Implementation } } - void ValidateGradient(IObjectiveFunction eval) + static void ValidateGradient(IObjectiveFunction eval) { foreach (double x in eval.Gradient) { @@ -117,7 +115,7 @@ namespace MathNet.Numerics.Optimization.Implementation } } - bool IsFinite(double x) + static bool IsFinite(double x) { return !(Double.IsNaN(x) || Double.IsInfinity(x)); } diff --git a/src/Numerics/Optimization/NewtonMinimizer.cs b/src/Numerics/Optimization/NewtonMinimizer.cs index b419b7c7..cf3d3459 100644 --- a/src/Numerics/Optimization/NewtonMinimizer.cs +++ b/src/Numerics/Optimization/NewtonMinimizer.cs @@ -30,13 +30,9 @@ namespace MathNet.Numerics.Optimization throw new IncompatibleObjectiveException("Hessian not supported in objective function, but required for Newton minimization."); } - if (!(objective is CheckedObjectiveFunction)) - { - objective = new CheckedObjectiveFunction(objective, ValidateObjective, ValidateGradient, ValidateHessian); - } - // Check that we're not already done objective.EvaluateAt(initialGuess); + ValidateGradient(objective); if (ExitCriteriaSatisfied(objective.Gradient)) { return new MinimizationOutput(objective, 0, MinimizationOutput.ExitCondition.AbsoluteGradient); @@ -52,6 +48,8 @@ namespace MathNet.Numerics.Optimization bool tmpLineSearch = false; while (!ExitCriteriaSatisfied(objective.Gradient) && iterations < MaximumIterations) { + ValidateHessian(objective); + var searchDirection = objective.Hessian.LU().Solve(-objective.Gradient); if (searchDirection * objective.Gradient >= 0) { @@ -70,6 +68,7 @@ namespace MathNet.Numerics.Optimization { throw new InnerOptimizationException("Line search failed.", e); } + iterationsWithNontrivialLineSearch += result.Iterations > 0 ? 1 : 0; totalLineSearchSteps += result.Iterations; objective = result.FunctionInfoAtMinimum; @@ -79,8 +78,9 @@ namespace MathNet.Numerics.Optimization objective.EvaluateAt(objective.Point + searchDirection); } - tmpLineSearch = false; + ValidateGradient(objective); + tmpLineSearch = false; iterations += 1; } @@ -92,34 +92,32 @@ namespace MathNet.Numerics.Optimization return new MinimizationWithLineSearchOutput(objective, iterations, MinimizationOutput.ExitCondition.AbsoluteGradient, totalLineSearchSteps, iterationsWithNontrivialLineSearch); } - private bool ExitCriteriaSatisfied(Vector gradient) + bool ExitCriteriaSatisfied(Vector gradient) { return gradient.Norm(2.0) < GradientTolerance; } - private void ValidateGradient(IObjectiveFunction eval) + static void ValidateGradient(IObjectiveFunction eval) { foreach (var x in eval.Gradient) { if (Double.IsNaN(x) || Double.IsInfinity(x)) + { throw new EvaluationException("Non-finite gradient returned.", eval); + } } } - private void ValidateObjective(IObjectiveFunction eval) - { - if (Double.IsNaN(eval.Value) || Double.IsInfinity(eval.Value)) - throw new EvaluationException("Non-finite objective function returned.", eval); - } - - private void ValidateHessian(IObjectiveFunction eval) + static void ValidateHessian(IObjectiveFunction eval) { for (int ii = 0; ii < eval.Hessian.RowCount; ++ii) { for (int jj = 0; jj < eval.Hessian.ColumnCount; ++jj) { if (Double.IsNaN(eval.Hessian[ii, jj]) || Double.IsInfinity(eval.Hessian[ii, jj])) + { throw new EvaluationException("Non-finite Hessian returned.", eval); + } } } }