forked from tsai/mathnet-numerics
committed by
Christoph Ruegg
3 changed files with 166 additions and 3 deletions
@ -1,6 +1,70 @@ |
|||||
namespace MathNet.Numerics.Optimization |
using System; |
||||
|
|
||||
|
namespace MathNet.Numerics.Optimization |
||||
{ |
{ |
||||
class GoldenSectionMinimizer |
public class GoldenSectionMinimizer |
||||
{ |
{ |
||||
|
public double XTolerance { get; set; } |
||||
|
public int MaximumIterations { get; set; } |
||||
|
|
||||
|
public GoldenSectionMinimizer(double xTolerance=1e-5, int maxIterations=1000) |
||||
|
{ |
||||
|
XTolerance = xTolerance; |
||||
|
MaximumIterations = maxIterations; |
||||
|
} |
||||
|
|
||||
|
public MinimizationResult FindMinimum(IObjectiveFunction1D objective, double lowerBound, double upperBound) |
||||
|
{ |
||||
|
double middlePointX = lowerBound + (upperBound - lowerBound) / (1 + Constants.GoldenRatio); |
||||
|
IEvaluation1D lower = objective.Evaluate(lowerBound); |
||||
|
IEvaluation1D middle = objective.Evaluate(middlePointX); |
||||
|
IEvaluation1D upper = objective.Evaluate(upperBound); |
||||
|
|
||||
|
ValueChecker(lower.Value, lowerBound); |
||||
|
ValueChecker(middle.Value, middlePointX); |
||||
|
ValueChecker(upper.Value, upperBound); |
||||
|
|
||||
|
if (upperBound <= lowerBound) |
||||
|
throw new OptimizationException("Lower bound must be lower than upper bound."); |
||||
|
|
||||
|
if (upper.Value < middle.Value || lower.Value < middle.Value) |
||||
|
throw new OptimizationException("Lower and upper bounds do not necessarily bound a minimum."); |
||||
|
|
||||
|
int iterations = 0; |
||||
|
while (Math.Abs(upper.Point - lower.Point) > XTolerance && iterations < MaximumIterations) |
||||
|
{ |
||||
|
double testX = lower.Point + (upper.Point - middle.Point); |
||||
|
var test = objective.Evaluate(testX); |
||||
|
ValueChecker(test.Value, testX); |
||||
|
|
||||
|
if (test.Value > middle.Value) |
||||
|
{ |
||||
|
if (test.Point < middle.Point) |
||||
|
lower = test; |
||||
|
else |
||||
|
upper = test; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
if (test.Point < middle.Point) |
||||
|
upper = middle; |
||||
|
else |
||||
|
lower = middle; |
||||
|
} |
||||
|
|
||||
|
iterations += 1; |
||||
|
} |
||||
|
|
||||
|
if (iterations == MaximumIterations) |
||||
|
throw new MaximumIterationsException("Max iterations reached."); |
||||
|
|
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
private void ValueChecker(double value, double point) |
||||
|
{ |
||||
|
if (Double.IsNaN(value) || Double.IsInfinity(value)) |
||||
|
throw new Exception("Objective function returned non-finite value."); |
||||
|
} |
||||
} |
} |
||||
} |
} |
||||
|
|||||
@ -0,0 +1,98 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace MathNet.Numerics.Optimization |
||||
|
{ |
||||
|
public interface IEvaluation1D |
||||
|
{ |
||||
|
double Point { get; } |
||||
|
double Value { get; } |
||||
|
double Derivative { get; } |
||||
|
double SecondDerivative { get; } |
||||
|
} |
||||
|
|
||||
|
public interface IObjectiveFunction1D |
||||
|
{ |
||||
|
bool DerivativeSupported { get; } |
||||
|
bool SecondDerivativeSupported { get; } |
||||
|
IEvaluation1D Evaluate(double point); |
||||
|
} |
||||
|
|
||||
|
public class CachedEvaluation1D : IEvaluation1D |
||||
|
{ |
||||
|
private double? _value; |
||||
|
private double? _derivative; |
||||
|
private double? _secondDerivative; |
||||
|
private readonly SimpleObjectiveFunction1D _objectiveObject; |
||||
|
private readonly double _point; |
||||
|
|
||||
|
public CachedEvaluation1D(SimpleObjectiveFunction1D f, double point) |
||||
|
{ |
||||
|
_objectiveObject = f; |
||||
|
_point = point; |
||||
|
} |
||||
|
private double SetValue() |
||||
|
{ |
||||
|
_value = _objectiveObject.Objective(_point); |
||||
|
return _value.Value; |
||||
|
} |
||||
|
private double SetDerivative() |
||||
|
{ |
||||
|
_derivative = _objectiveObject.Derivative(_point); |
||||
|
return _derivative.Value; |
||||
|
} |
||||
|
private double SetSecondDerivative() |
||||
|
{ |
||||
|
_secondDerivative = _objectiveObject.SecondDerivative(_point); |
||||
|
return _secondDerivative.Value; |
||||
|
} |
||||
|
|
||||
|
public double Point { get { return _point; } } |
||||
|
public double Value { get { return _value ?? SetValue(); } } |
||||
|
public double Derivative { get { return _derivative ?? SetDerivative(); } } |
||||
|
public double SecondDerivative { get { return _secondDerivative ?? SetSecondDerivative(); } } |
||||
|
|
||||
|
} |
||||
|
|
||||
|
public class SimpleObjectiveFunction1D : IObjectiveFunction1D |
||||
|
{ |
||||
|
public Func<double, double> Objective { get; private set; } |
||||
|
public Func<double, double> Derivative { get; private set; } |
||||
|
public Func<double, double> SecondDerivative { get; private set; } |
||||
|
|
||||
|
public SimpleObjectiveFunction1D(Func<double, double> objective) |
||||
|
{ |
||||
|
Objective = objective; |
||||
|
Derivative = null; |
||||
|
SecondDerivative = null; |
||||
|
} |
||||
|
|
||||
|
public SimpleObjectiveFunction1D(Func<double, double> objective, Func<double, double> derivative) |
||||
|
{ |
||||
|
Objective = objective; |
||||
|
Derivative = derivative; |
||||
|
SecondDerivative = null; |
||||
|
} |
||||
|
|
||||
|
public SimpleObjectiveFunction1D(Func<double, double> objective, Func<double, double> derivative, Func<double,double> secondDerivative) |
||||
|
{ |
||||
|
Objective = objective; |
||||
|
Derivative = derivative; |
||||
|
SecondDerivative = secondDerivative; |
||||
|
} |
||||
|
|
||||
|
public bool DerivativeSupported |
||||
|
{ |
||||
|
get { return Derivative != null; } |
||||
|
} |
||||
|
|
||||
|
public bool SecondDerivativeSupported |
||||
|
{ |
||||
|
get { return SecondDerivative != null; } |
||||
|
} |
||||
|
|
||||
|
public IEvaluation1D Evaluate(double point) |
||||
|
{ |
||||
|
return new CachedEvaluation1D(this, point); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue