Browse Source

Optimization: Improve error handling and reporting.

(Updated by cdrnet)
optimization-2
Scott Stephens 14 years ago
committed by Christoph Ruegg
parent
commit
54e8feee56
  1. 2
      src/Numerics/Numerics.csproj
  2. 40
      src/Numerics/Optimization/ConjugateGradientMinimizer.cs
  3. 48
      src/Numerics/Optimization/Exceptions.cs
  4. 132
      src/Numerics/Optimization/ObjectiveChecker.cs
  5. 2
      src/Numerics/Optimization/WeakWolfeLineSearch.cs

2
src/Numerics/Numerics.csproj

@ -198,10 +198,12 @@
<Compile Include="Optimization\BFGS.cs" />
<Compile Include="Optimization\BisectionRootFinder.cs" />
<Compile Include="Optimization\ConjugateGradientMinimizer.cs" />
<Compile Include="Optimization\Exceptions.cs" />
<Compile Include="Optimization\GoldenSectionMinimizer.cs" />
<Compile Include="Optimization\LineSearchingMinimizerOutput.cs" />
<Compile Include="Optimization\LineSearchOutput.cs" />
<Compile Include="Optimization\MinimizationOutput.cs" />
<Compile Include="Optimization\ObjectiveChecker.cs" />
<Compile Include="Optimization\ObjectiveFunction.cs" />
<Compile Include="Optimization\OptimizationResult.cs" />
<Compile Include="Optimization\StrongWolfeLineSearch.cs" />

40
src/Numerics/Optimization/ConjugateGradientMinimizer.cs

@ -21,11 +21,12 @@ namespace MathNet.Numerics.Optimization
public MinimizationOutput FindMinimum(IObjectiveFunction objective, Vector<double> initial_guess)
{
if (!objective.GradientSupported)
throw new Exception("Gradient not supported in objective function, but required for ConjugateGradient minimization.");
throw new IncompatibleObjectiveException("Gradient not supported in objective function, but required for ConjugateGradient minimization.");
objective = new ObjectiveChecker(objective, this.ValidateObjective, this.ValidateGradient, null);
IEvaluation initial_eval = objective.Evaluate(initial_guess);
var gradient = initial_eval.Gradient;
this.ValidateGradient(gradient, initial_guess);
var gradient = initial_eval.Gradient;
// Check that we're not already done
if (this.ExitCriteriaSatisfied(initial_guess, gradient))
@ -42,11 +43,20 @@ namespace MathNet.Numerics.Optimization
steepest_direction = -gradient;
search_direction = steepest_direction;
double initial_step_size = 100 * this.GradientTolerance / (gradient * gradient);
var result = line_searcher.FindConformingStep(objective, initial_eval, search_direction, initial_step_size);
candidate_point = result.FunctionInfoAtMinimum;
this.ValidateGradient(candidate_point.Gradient, candidate_point.Point);
LineSearchOutput result;
try
{
result = line_searcher.FindConformingStep(objective, initial_eval, search_direction, initial_step_size);
}
catch (Exception e)
{
throw new InnerOptimizationException("Line search failed.", e);
}
candidate_point = result.FunctionInfoAtMinimum;
double step_size = (candidate_point.Point - initial_guess).Norm(2.0);
// Subsequent steps
int iterations = 1;
int total_line_search_steps = result.Iterations;
@ -73,8 +83,15 @@ namespace MathNet.Numerics.Optimization
search_direction = steepest_direction;
steepest_descent_resets += 1;
}
result = line_searcher.FindConformingStep(objective, candidate_point, search_direction, step_size);
try
{
result = line_searcher.FindConformingStep(objective, candidate_point, search_direction, step_size);
}
catch (Exception e)
{
throw new InnerOptimizationException("Line search failed.", e);
}
no_line_search_iterations += result.Iterations == 0 ? 1 : 0;
total_line_search_steps += result.Iterations;
@ -85,6 +102,9 @@ namespace MathNet.Numerics.Optimization
iterations += 1;
}
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, no_line_search_iterations);
}
@ -98,14 +118,14 @@ namespace MathNet.Numerics.Optimization
foreach (var x in gradient)
{
if (Double.IsNaN(x) || Double.IsInfinity(x))
throw new Exception("Non-finite gradient returned.");
throw new EvaluationException("Non-finite gradient returned.");
}
}
private void ValidateObjective(double objective, Vector<double> input)
{
if (Double.IsNaN(objective) || Double.IsInfinity(objective))
throw new Exception("Non-finite objective function returned.");
throw new EvaluationException("Non-finite objective function returned.");
}
}
}

48
src/Numerics/Optimization/Exceptions.cs

@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MathNet.Numerics.Optimization
{
public class OptimizationException : Exception
{
public OptimizationException(string message)
: base(message) {}
public OptimizationException(string message, Exception inner_exception)
: base(message, inner_exception) { }
}
public class MaximumIterationsException : OptimizationException
{
public MaximumIterationsException(string message)
: base(message) {}
}
public class EvaluationException : OptimizationException
{
public EvaluationException(string message)
: base(message) {}
public EvaluationException(string message, Exception inner_exception)
: base(message, inner_exception) { }
}
public class InnerOptimizationException : OptimizationException
{
public InnerOptimizationException(string message)
: base(message) {}
public InnerOptimizationException(string message, Exception inner_exception)
: base(message, inner_exception) { }
}
public class IncompatibleObjectiveException : OptimizationException
{
public IncompatibleObjectiveException(string message)
: base(message) {}
}
}

132
src/Numerics/Optimization/ObjectiveChecker.cs

@ -0,0 +1,132 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MathNet.Numerics.LinearAlgebra;
namespace MathNet.Numerics.Optimization
{
public class CheckedEvaluation : IEvaluation
{
private ObjectiveChecker Checker;
private IEvaluation InnerEvaluation;
private bool ValueChecked;
private bool GradientChecked;
private bool HessianChecked;
public CheckedEvaluation(ObjectiveChecker checker, IEvaluation evaluation)
{
this.Checker = checker;
this.InnerEvaluation = evaluation;
}
public Vector<double> Point
{
get { return this.InnerEvaluation.Point; }
}
public double Value
{
get
{
if (!this.ValueChecked)
{
double tmp;
try
{
tmp = this.InnerEvaluation.Value;
}
catch (Exception e)
{
throw new EvaluationException("Objective function evaluation failed.", e);
}
this.Checker.ValueChecker(tmp,this.InnerEvaluation.Point);
}
return this.InnerEvaluation.Value;
}
}
public Vector<double> Gradient
{
get
{
if (!this.GradientChecked)
{
Vector<double> tmp;
try
{
tmp = this.InnerEvaluation.Gradient;
}
catch (Exception e)
{
throw new EvaluationException("Objective gradient evaluation failed.", e);
}
this.Checker.GradientChecker(tmp, this.InnerEvaluation.Point);
}
return this.InnerEvaluation.Gradient;
}
}
public Matrix<double> Hessian
{
get
{
if (!this.HessianChecked)
{
Matrix<double> tmp;
try
{
tmp = this.InnerEvaluation.Hessian;
}
catch (Exception e)
{
throw new EvaluationException("Objective hessian evaluation failed.", e);
}
this.Checker.HessianChecker(tmp, this.InnerEvaluation.Point);
}
return this.InnerEvaluation.Hessian;
}
}
}
public class ObjectiveChecker : IObjectiveFunction
{
public IObjectiveFunction InnerObjective { get; private set; }
public Action<double, Vector<double>> ValueChecker { get; private set; }
public Action<Vector<double>, Vector<double>> GradientChecker { get; private set; }
public Action<Matrix<double>, Vector<double>> HessianChecker { get; private set; }
public ObjectiveChecker(IObjectiveFunction objective, Action<double, Vector<double>> value_checker, Action<Vector<double>, Vector<double>> gradient_checker, Action<Matrix<double>, Vector<double>> hessian_checker)
{
this.InnerObjective = objective;
this.ValueChecker = value_checker;
this.GradientChecker = gradient_checker;
this.HessianChecker = hessian_checker;
}
public bool GradientSupported
{
get { return this.InnerObjective.GradientSupported; }
}
public bool HessianSupported
{
get { return this.InnerObjective.HessianSupported; }
}
public IEvaluation Evaluate(Vector<double> point)
{
try
{
return new CheckedEvaluation(this, this.InnerObjective.Evaluate(point));
}
catch (Exception e)
{
throw new EvaluationException("Objective evaluation failed.", e);
}
}
}
}

2
src/Numerics/Optimization/WeakWolfeLineSearch.cs

@ -57,7 +57,7 @@ namespace MathNet.Numerics.Optimization
}
if (ii == this.MaximumIterations)
throw new Exception("Line search failed with max iterations. Function is likely unbounded in search direction.");
throw new MaximumIterationsException(String.Format("Maximum iterations ({0}) reached. Function may be unbounded in search direction.",this.MaximumIterations));
else
return new LineSearchOutput(candidate_eval, ii, step);
}

Loading…
Cancel
Save