forked from tsai/mathnet-numerics
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
119 lines
4.6 KiB
119 lines
4.6 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
|
|
using MathNet.Numerics.LinearAlgebra;
|
|
|
|
namespace MathNet.Numerics.Optimization
|
|
{
|
|
public class WeakWolfeLineSearch
|
|
{
|
|
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, double parameter_tolerance, int max_iterations=10)
|
|
{
|
|
this.C1 = c1;
|
|
this.C2 = c2;
|
|
this.ParameterTolerance = parameter_tolerance;
|
|
this.MaximumIterations = max_iterations;
|
|
}
|
|
|
|
// Implemented following http://www.math.washington.edu/~burke/crs/408/lectures/L9-weak-Wolfe.pdf
|
|
public LineSearchOutput FindConformingStep(IObjectiveFunction objective, IEvaluation starting_point, Vector<double> search_direction, double initial_step)
|
|
{
|
|
|
|
if (!(objective is ObjectiveChecker))
|
|
objective = new ObjectiveChecker(objective, this.ValidateValue, this.ValidateGradient, null);
|
|
|
|
double lower_bound = 0.0;
|
|
double upper_bound = Double.PositiveInfinity;
|
|
double step = initial_step;
|
|
|
|
double initial_value = starting_point.Value;
|
|
Vector<double> initial_gradient = starting_point.Gradient;
|
|
|
|
double initial_dd = search_direction*initial_gradient;
|
|
|
|
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);
|
|
|
|
double step_dd = search_direction * candidate_eval.Gradient;
|
|
|
|
if (candidate_eval.Value > initial_value + this.C1 * step * initial_dd)
|
|
{
|
|
upper_bound = step;
|
|
step = 0.5 * (lower_bound + upper_bound);
|
|
}
|
|
else if (step_dd < this.C2*initial_dd)
|
|
{
|
|
lower_bound = step;
|
|
step = Double.IsPositiveInfinity(upper_bound) ? 2 * lower_bound : 0.5 * (lower_bound + upper_bound);
|
|
}
|
|
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 && 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, reason_for_exit);
|
|
}
|
|
|
|
private bool Conforms(IEvaluation starting_point, Vector<double> search_direction, double step, IEvaluation ending_point)
|
|
{
|
|
|
|
bool sufficient_decrease = ending_point.Value <= starting_point.Value + this.C1 * step * (starting_point.Gradient * search_direction);
|
|
bool not_too_steep = ending_point.Gradient * search_direction >= this.C2 * starting_point.Gradient * search_direction;
|
|
|
|
return step > 0 && sufficient_decrease && not_too_steep;
|
|
}
|
|
|
|
private void ValidateValue(double value, Vector<double> input)
|
|
{
|
|
if (!this.IsFinite(value))
|
|
throw new EvaluationException(String.Format("Non-finite value returned by objective function: {0}", value),input);
|
|
}
|
|
|
|
private void ValidateGradient(Vector<double> gradient, Vector<double> input)
|
|
{
|
|
foreach (double x in gradient)
|
|
if (!this.IsFinite(x))
|
|
{
|
|
throw new EvaluationException(String.Format("Non-finite value returned by gradient: {0}", x),input);
|
|
}
|
|
}
|
|
|
|
private bool IsFinite(double x)
|
|
{
|
|
return !(Double.IsNaN(x) || Double.IsInfinity(x));
|
|
}
|
|
}
|
|
}
|
|
|