Browse Source

Optimization: simplification: validate directly instead of through adapter

pull/489/head
Christoph Ruegg 11 years ago
committed by Erik Ovegard
parent
commit
2fcf9c91ee
  1. 4
      src/Numerics/Optimization/Implementation/CheckedObjectiveFunction.cs
  2. 12
      src/Numerics/Optimization/Implementation/WeakWolfeLineSearch.cs
  3. 28
      src/Numerics/Optimization/NewtonMinimizer.cs

4
src/Numerics/Optimization/Implementation/CheckedObjectiveFunction.cs

@ -30,13 +30,15 @@ namespace MathNet.Numerics.Optimization.Implementation
public void EvaluateAt(Vector<double> point) public void EvaluateAt(Vector<double> point)
{ {
InnerObjectiveFunction.EvaluateAt(point); InnerObjectiveFunction.EvaluateAt(point);
_valueChecked = false;
_gradientChecked = false;
_hessianChecked = false;
} }
public double Value public double Value
{ {
get get
{ {
if (!_valueChecked) if (!_valueChecked)
{ {
double tmp; double tmp;

12
src/Numerics/Optimization/Implementation/WeakWolfeLineSearch.cs

@ -22,10 +22,6 @@ namespace MathNet.Numerics.Optimization.Implementation
public LineSearchOutput FindConformingStep(IObjectiveFunctionEvaluation startingPoint, Vector<double> searchDirection, double initialStep) public LineSearchOutput FindConformingStep(IObjectiveFunctionEvaluation startingPoint, Vector<double> searchDirection, double initialStep)
{ {
var objective = startingPoint.Fork(); var objective = startingPoint.Fork();
if (!(objective is CheckedObjectiveFunction))
{
objective = new CheckedObjectiveFunction(objective, ValidateValue, ValidateGradient, null);
}
double lowerBound = 0.0; double lowerBound = 0.0;
double upperBound = Double.PositiveInfinity; double upperBound = Double.PositiveInfinity;
@ -42,6 +38,8 @@ namespace MathNet.Numerics.Optimization.Implementation
for (ii = 0; ii < _maximumIterations; ++ii) for (ii = 0; ii < _maximumIterations; ++ii)
{ {
objective.EvaluateAt(initialPoint + searchDirection * step); objective.EvaluateAt(initialPoint + searchDirection * step);
ValidateGradient(objective);
ValidateValue(objective);
double stepDd = searchDirection * objective.Gradient; double stepDd = searchDirection * objective.Gradient;
@ -98,7 +96,7 @@ namespace MathNet.Numerics.Optimization.Implementation
return step > 0 && sufficientDecrease && notTooSteep; return step > 0 && sufficientDecrease && notTooSteep;
} }
void ValidateValue(IObjectiveFunction eval) static void ValidateValue(IObjectiveFunction eval)
{ {
if (!IsFinite(eval.Value)) 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) 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)); return !(Double.IsNaN(x) || Double.IsInfinity(x));
} }

28
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."); 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 // Check that we're not already done
objective.EvaluateAt(initialGuess); objective.EvaluateAt(initialGuess);
ValidateGradient(objective);
if (ExitCriteriaSatisfied(objective.Gradient)) if (ExitCriteriaSatisfied(objective.Gradient))
{ {
return new MinimizationOutput(objective, 0, MinimizationOutput.ExitCondition.AbsoluteGradient); return new MinimizationOutput(objective, 0, MinimizationOutput.ExitCondition.AbsoluteGradient);
@ -52,6 +48,8 @@ namespace MathNet.Numerics.Optimization
bool tmpLineSearch = false; bool tmpLineSearch = false;
while (!ExitCriteriaSatisfied(objective.Gradient) && iterations < MaximumIterations) while (!ExitCriteriaSatisfied(objective.Gradient) && iterations < MaximumIterations)
{ {
ValidateHessian(objective);
var searchDirection = objective.Hessian.LU().Solve(-objective.Gradient); var searchDirection = objective.Hessian.LU().Solve(-objective.Gradient);
if (searchDirection * objective.Gradient >= 0) if (searchDirection * objective.Gradient >= 0)
{ {
@ -70,6 +68,7 @@ namespace MathNet.Numerics.Optimization
{ {
throw new InnerOptimizationException("Line search failed.", e); throw new InnerOptimizationException("Line search failed.", e);
} }
iterationsWithNontrivialLineSearch += result.Iterations > 0 ? 1 : 0; iterationsWithNontrivialLineSearch += result.Iterations > 0 ? 1 : 0;
totalLineSearchSteps += result.Iterations; totalLineSearchSteps += result.Iterations;
objective = result.FunctionInfoAtMinimum; objective = result.FunctionInfoAtMinimum;
@ -79,8 +78,9 @@ namespace MathNet.Numerics.Optimization
objective.EvaluateAt(objective.Point + searchDirection); objective.EvaluateAt(objective.Point + searchDirection);
} }
tmpLineSearch = false; ValidateGradient(objective);
tmpLineSearch = false;
iterations += 1; iterations += 1;
} }
@ -92,34 +92,32 @@ namespace MathNet.Numerics.Optimization
return new MinimizationWithLineSearchOutput(objective, iterations, MinimizationOutput.ExitCondition.AbsoluteGradient, totalLineSearchSteps, iterationsWithNontrivialLineSearch); return new MinimizationWithLineSearchOutput(objective, iterations, MinimizationOutput.ExitCondition.AbsoluteGradient, totalLineSearchSteps, iterationsWithNontrivialLineSearch);
} }
private bool ExitCriteriaSatisfied(Vector<double> gradient) bool ExitCriteriaSatisfied(Vector<double> gradient)
{ {
return gradient.Norm(2.0) < GradientTolerance; return gradient.Norm(2.0) < GradientTolerance;
} }
private void ValidateGradient(IObjectiveFunction eval) static void ValidateGradient(IObjectiveFunction eval)
{ {
foreach (var x in eval.Gradient) foreach (var x in eval.Gradient)
{ {
if (Double.IsNaN(x) || Double.IsInfinity(x)) if (Double.IsNaN(x) || Double.IsInfinity(x))
{
throw new EvaluationException("Non-finite gradient returned.", eval); throw new EvaluationException("Non-finite gradient returned.", eval);
}
} }
} }
private void ValidateObjective(IObjectiveFunction eval) static void ValidateHessian(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)
{ {
for (int ii = 0; ii < eval.Hessian.RowCount; ++ii) for (int ii = 0; ii < eval.Hessian.RowCount; ++ii)
{ {
for (int jj = 0; jj < eval.Hessian.ColumnCount; ++jj) for (int jj = 0; jj < eval.Hessian.ColumnCount; ++jj)
{ {
if (Double.IsNaN(eval.Hessian[ii, jj]) || Double.IsInfinity(eval.Hessian[ii, jj])) if (Double.IsNaN(eval.Hessian[ii, jj]) || Double.IsInfinity(eval.Hessian[ii, jj]))
{
throw new EvaluationException("Non-finite Hessian returned.", eval); throw new EvaluationException("Non-finite Hessian returned.", eval);
}
} }
} }
} }

Loading…
Cancel
Save