Browse Source

Optimization: interface segregation: don't ask for function if only evaluation is needed

v3
Christoph Ruegg 10 years ago
parent
commit
2159e3c596
  1. 10
      src/Numerics/Optimization/BfgsBMinimizer.cs
  2. 6
      src/Numerics/Optimization/BfgsMinimizerBase.cs
  3. 4
      src/Numerics/Optimization/ConjugateGradientMinimizer.cs
  4. 6
      src/Numerics/Optimization/Exceptions.cs
  5. 5
      src/Numerics/Optimization/LineSearch/StrongWolfeLineSearch.cs
  6. 4
      src/Numerics/Optimization/LineSearch/WeakWolfeLineSearch.cs
  7. 16
      src/Numerics/Optimization/LineSearch/WolfeLineSearch.cs
  8. 18
      src/Numerics/Optimization/NelderMeadSimplex.cs
  9. 6
      src/Numerics/Optimization/NewtonMinimizer.cs
  10. 22
      src/Numerics/Optimization/ObjectiveFunctions/ForwardDifferenceGradientObjectiveFunction.cs
  11. 2
      src/Numerics/Optimization/ObjectiveFunctions/GradientHessianObjectiveFunction.cs
  12. 2
      src/Numerics/Optimization/ObjectiveFunctions/GradientObjectiveFunction.cs
  13. 2
      src/Numerics/Optimization/ObjectiveFunctions/HessianObjectiveFunction.cs
  14. 2
      src/Numerics/Optimization/ObjectiveFunctions/LazyObjectiveFunction.cs
  15. 2
      src/Numerics/Optimization/ObjectiveFunctions/ValueObjectiveFunction.cs

10
src/Numerics/Optimization/BfgsBMinimizer.cs

@ -158,9 +158,9 @@ namespace MathNet.Numerics.Optimization
protected override Vector<double> CalculateSearchDirection(ref Matrix<double> pseudoHessian, protected override Vector<double> CalculateSearchDirection(ref Matrix<double> pseudoHessian,
out double maxLineSearchStep, out double maxLineSearchStep,
out double startingStepSize, out double startingStepSize,
IObjectiveFunction previousPoint, IObjectiveFunction previousPoint,
IObjectiveFunction candidatePoint, IObjectiveFunction candidatePoint,
Vector<double> step) Vector<double> step)
{ {
Vector<double> lineSearchDirection; Vector<double> lineSearchDirection;
@ -170,7 +170,7 @@ namespace MathNet.Numerics.Optimization
if (sy > 0.0) // only do update if it will create a positive definite matrix if (sy > 0.0) // only do update if it will create a positive definite matrix
{ {
double sts = step * step; double sts = step * step;
var Hs = pseudoHessian * step; var Hs = pseudoHessian * step;
var sHs = step * pseudoHessian * step; var sHs = step * pseudoHessian * step;
pseudoHessian = pseudoHessian + y.OuterProduct(y) * (1.0 / sy) - Hs.OuterProduct(Hs) * (1.0 / sHs); pseudoHessian = pseudoHessian + y.OuterProduct(y) * (1.0 / sy) - Hs.OuterProduct(Hs) * (1.0 / sHs);
@ -285,7 +285,7 @@ namespace MathNet.Numerics.Optimization
} }
} }
protected override double GetProjectedGradient(IObjectiveFunction candidatePoint, int ii) protected override double GetProjectedGradient(IObjectiveFunctionEvaluation candidatePoint, int ii)
{ {
double projectedGradient; double projectedGradient;
bool atLowerBound = candidatePoint.Point[ii] - _lowerBound[ii] < VerySmall; bool atLowerBound = candidatePoint.Point[ii] - _lowerBound[ii] < VerySmall;

6
src/Numerics/Optimization/BfgsMinimizerBase.cs

@ -59,7 +59,7 @@ namespace MathNet.Numerics.Optimization
MaximumIterations = maximumIterations; MaximumIterations = maximumIterations;
} }
protected MinimizationResult.ExitCondition ExitCriteriaSatisfied(IObjectiveFunction candidatePoint, IObjectiveFunction lastPoint, int iterations) protected MinimizationResult.ExitCondition ExitCriteriaSatisfied(IObjectiveFunctionEvaluation candidatePoint, IObjectiveFunctionEvaluation lastPoint, int iterations)
{ {
Vector<double> relGrad = new DenseVector(candidatePoint.Point.Count); Vector<double> relGrad = new DenseVector(candidatePoint.Point.Count);
double relativeGradient = 0.0; double relativeGradient = 0.0;
@ -99,12 +99,12 @@ namespace MathNet.Numerics.Optimization
return MinimizationResult.ExitCondition.None; return MinimizationResult.ExitCondition.None;
} }
protected virtual double GetProjectedGradient(IObjectiveFunction candidatePoint, int ii) protected virtual double GetProjectedGradient(IObjectiveFunctionEvaluation candidatePoint, int ii)
{ {
return candidatePoint.Gradient[ii]; return candidatePoint.Gradient[ii];
} }
protected void ValidateGradientAndObjective(IObjectiveFunction eval) protected void ValidateGradientAndObjective(IObjectiveFunctionEvaluation eval)
{ {
foreach (var x in eval.Gradient) foreach (var x in eval.Gradient)
{ {

4
src/Numerics/Optimization/ConjugateGradientMinimizer.cs

@ -127,7 +127,7 @@ namespace MathNet.Numerics.Optimization
return gradient.Norm(2.0) < GradientTolerance; return gradient.Norm(2.0) < GradientTolerance;
} }
void ValidateGradient(IObjectiveFunction objective) void ValidateGradient(IObjectiveFunctionEvaluation objective)
{ {
foreach (var x in objective.Gradient) foreach (var x in objective.Gradient)
{ {
@ -136,7 +136,7 @@ namespace MathNet.Numerics.Optimization
} }
} }
void ValidateObjective(IObjectiveFunction objective) void ValidateObjective(IObjectiveFunctionEvaluation objective)
{ {
if (Double.IsNaN(objective.Value) || Double.IsInfinity(objective.Value)) if (Double.IsNaN(objective.Value) || Double.IsInfinity(objective.Value))
throw new EvaluationException("Non-finite objective function returned.", objective); throw new EvaluationException("Non-finite objective function returned.", objective);

6
src/Numerics/Optimization/Exceptions.cs

@ -49,15 +49,15 @@ namespace MathNet.Numerics.Optimization
public class EvaluationException : OptimizationException public class EvaluationException : OptimizationException
{ {
public IObjectiveFunction ObjectiveFunction { get; private set; } public IObjectiveFunctionEvaluation ObjectiveFunction { get; private set; }
public EvaluationException(string message, IObjectiveFunction eval) public EvaluationException(string message, IObjectiveFunctionEvaluation eval)
: base(message) : base(message)
{ {
ObjectiveFunction = eval; ObjectiveFunction = eval;
} }
public EvaluationException(string message, IObjectiveFunction eval, Exception innerException) public EvaluationException(string message, IObjectiveFunctionEvaluation eval, Exception innerException)
: base(message, innerException) : base(message, innerException)
{ {
ObjectiveFunction = eval; ObjectiveFunction = eval;

5
src/Numerics/Optimization/LineSearch/StrongWolfeLineSearch.cs

@ -40,7 +40,10 @@ namespace MathNet.Numerics.Optimization.LineSearch
// Argument validation in base class // Argument validation in base class
} }
protected override MinimizationResult.ExitCondition WolfeExitCondition { get { return MinimizationResult.ExitCondition.StrongWolfeCriteria; } } protected override MinimizationResult.ExitCondition WolfeExitCondition
{
get { return MinimizationResult.ExitCondition.StrongWolfeCriteria; }
}
protected override bool WolfeCondition(double stepDd, double initialDd) protected override bool WolfeCondition(double stepDd, double initialDd)
{ {

4
src/Numerics/Optimization/LineSearch/WeakWolfeLineSearch.cs

@ -64,7 +64,7 @@ namespace MathNet.Numerics.Optimization.LineSearch
return stepDd < C2 * initialDd; return stepDd < C2 * initialDd;
} }
protected override void ValidateValue(IObjectiveFunction eval) protected override void ValidateValue(IObjectiveFunctionEvaluation eval)
{ {
if (!IsFinite(eval.Value)) if (!IsFinite(eval.Value))
{ {
@ -78,7 +78,7 @@ namespace MathNet.Numerics.Optimization.LineSearch
throw new ArgumentException("objective function does not support gradient"); throw new ArgumentException("objective function does not support gradient");
} }
protected override void ValidateGradient(IObjectiveFunction eval) protected override void ValidateGradient(IObjectiveFunctionEvaluation eval)
{ {
foreach (double x in eval.Gradient) foreach (double x in eval.Gradient)
{ {

16
src/Numerics/Optimization/LineSearch/WolfeLineSearch.cs

@ -87,8 +87,8 @@ namespace MathNet.Numerics.Optimization.LineSearch
for (ii = 0; ii < MaximumIterations; ++ii) for (ii = 0; ii < MaximumIterations; ++ii)
{ {
objective.EvaluateAt(startingPoint.Point + searchDirection * step); objective.EvaluateAt(startingPoint.Point + searchDirection * step);
ValidateGradient(objective); ValidateGradient(objective);
ValidateValue(objective); ValidateValue(objective);
double stepDd = searchDirection * objective.Gradient; double stepDd = searchDirection * objective.Gradient;
@ -104,7 +104,7 @@ namespace MathNet.Numerics.Optimization.LineSearch
} }
else else
{ {
reasonForExit = WolfeExitCondition; reasonForExit = WolfeExitCondition;
break; break;
} }
@ -136,23 +136,21 @@ namespace MathNet.Numerics.Optimization.LineSearch
return new LineSearchResult(objective, ii, step, reasonForExit); return new LineSearchResult(objective, ii, step, reasonForExit);
} }
protected abstract MinimizationResult.ExitCondition WolfeExitCondition { get; } protected abstract MinimizationResult.ExitCondition WolfeExitCondition { get; }
protected abstract bool WolfeCondition(double stepDd, double initialDd); protected abstract bool WolfeCondition(double stepDd, double initialDd);
protected virtual void ValidateGradient(IObjectiveFunction objective) protected virtual void ValidateGradient(IObjectiveFunctionEvaluation objective)
{ {
} }
protected virtual void ValidateValue(IObjectiveFunction objective)
protected virtual void ValidateValue(IObjectiveFunctionEvaluation objective)
{ {
} }
protected virtual void ValidateInputArguments(IObjectiveFunctionEvaluation startingPoint, Vector<double> searchDirection, double initialStep, double upperBound) protected virtual void ValidateInputArguments(IObjectiveFunctionEvaluation startingPoint, Vector<double> searchDirection, double initialStep, double upperBound)
{ {
} }
} }
} }

18
src/Numerics/Optimization/NelderMeadSimplex.cs

@ -32,15 +32,12 @@
using MathNet.Numerics.LinearAlgebra; using MathNet.Numerics.LinearAlgebra;
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MathNet.Numerics.Optimization namespace MathNet.Numerics.Optimization
{ {
/// <summary> /// <summary>
/// Class implementing the Nelder-Mead simplex algorithm, used to find a minima when no gradient is available. /// Class implementing the Nelder-Mead simplex algorithm, used to find a minima when no gradient is available.
/// Called fminsearch() in Matlab. A description of the algorithm can be found at /// Called fminsearch() in Matlab. A description of the algorithm can be found at
/// http://se.mathworks.com/help/matlab/math/optimizing-nonlinear-functions.html#bsgpq6p-11 /// http://se.mathworks.com/help/matlab/math/optimizing-nonlinear-functions.html#bsgpq6p-11
/// or /// or
/// https://en.wikipedia.org/wiki/Nelder%E2%80%93Mead_method /// https://en.wikipedia.org/wiki/Nelder%E2%80%93Mead_method
@ -68,7 +65,7 @@ namespace MathNet.Numerics.Optimization
/// <returns>The minimum point</returns> /// <returns>The minimum point</returns>
public MinimizationResult FindMinimum(IObjectiveFunction objectiveFunction, Vector<double> initialGuess) public MinimizationResult FindMinimum(IObjectiveFunction objectiveFunction, Vector<double> initialGuess)
{ {
var initalPertubation = new MathNet.Numerics.LinearAlgebra.Double.DenseVector(initialGuess.Count); var initalPertubation = new LinearAlgebra.Double.DenseVector(initialGuess.Count);
for (int i = 0; i < initialGuess.Count; i++) for (int i = 0; i < initialGuess.Count; i++)
{ {
initalPertubation[i] = initialGuess[i] == 0.0 ? 0.00025 : initialGuess[i] * 0.05; initalPertubation[i] = initialGuess[i] == 0.0 ? 0.00025 : initialGuess[i] * 0.05;
@ -249,7 +246,7 @@ namespace MathNet.Numerics.Optimization
Vector<double>[] vertices = new Vector<double>[numDimensions + 1]; Vector<double>[] vertices = new Vector<double>[numDimensions + 1];
// define one point of the simplex as the given initial guesses // define one point of the simplex as the given initial guesses
var p0 = new MathNet.Numerics.LinearAlgebra.Double.DenseVector(numDimensions); var p0 = new LinearAlgebra.Double.DenseVector(numDimensions);
for (int i = 0; i < numDimensions; i++) for (int i = 0; i < numDimensions; i++)
{ {
p0[i] = simplexConstants[i].Value; p0[i] = simplexConstants[i].Value;
@ -261,7 +258,7 @@ namespace MathNet.Numerics.Optimization
for (int i = 0; i < numDimensions; i++) for (int i = 0; i < numDimensions; i++)
{ {
double scale = simplexConstants[i].InitialPerturbation; double scale = simplexConstants[i].InitialPerturbation;
Vector<double> unitVector = new MathNet.Numerics.LinearAlgebra.Double.DenseVector(numDimensions); Vector<double> unitVector = new LinearAlgebra.Double.DenseVector(numDimensions);
unitVector[i] = 1; unitVector[i] = 1;
vertices[i + 1] = p0.Add(unitVector.Multiply(scale)); vertices[i + 1] = p0.Add(unitVector.Multiply(scale));
} }
@ -335,7 +332,7 @@ namespace MathNet.Numerics.Optimization
{ {
int numVertices = vertices.Length; int numVertices = vertices.Length;
// find the centroid of all points except the worst one // find the centroid of all points except the worst one
Vector<double> centroid = new MathNet.Numerics.LinearAlgebra.Double.DenseVector(numVertices - 1); Vector<double> centroid = new LinearAlgebra.Double.DenseVector(numVertices - 1);
for (int i = 0; i < numVertices; i++) for (int i = 0; i < numVertices; i++)
{ {
if (i != errorProfile.HighestIndex) if (i != errorProfile.HighestIndex)
@ -409,7 +406,4 @@ namespace MathNet.Numerics.Optimization
} }
} }
} }
} }

6
src/Numerics/Optimization/NewtonMinimizer.cs

@ -126,7 +126,7 @@ namespace MathNet.Numerics.Optimization
return gradient.Norm(2.0) < GradientTolerance; return gradient.Norm(2.0) < GradientTolerance;
} }
static void ValidateGradient(IObjectiveFunction eval) static void ValidateGradient(IObjectiveFunctionEvaluation eval)
{ {
foreach (var x in eval.Gradient) foreach (var x in eval.Gradient)
{ {
@ -137,13 +137,13 @@ namespace MathNet.Numerics.Optimization
} }
} }
private void ValidateObjective(IObjectiveFunction eval) private void ValidateObjective(IObjectiveFunctionEvaluation eval)
{ {
if (Double.IsNaN(eval.Value) || Double.IsInfinity(eval.Value)) if (Double.IsNaN(eval.Value) || Double.IsInfinity(eval.Value))
throw new EvaluationException("Non-finite objective function returned.", eval); throw new EvaluationException("Non-finite objective function returned.", eval);
} }
private void ValidateHessian(IObjectiveFunction eval) private void ValidateHessian(IObjectiveFunctionEvaluation eval)
{ {
for (int ii = 0; ii < eval.Hessian.RowCount; ++ii) for (int ii = 0; ii < eval.Hessian.RowCount; ++ii)
{ {

22
src/Numerics/Optimization/ObjectiveFunctions/ForwardDifferenceGradientObjectiveFunction.cs

@ -76,23 +76,23 @@ namespace MathNet.Numerics.Optimization.ObjectiveFunctions
if (!ValueEvaluated) if (!ValueEvaluated)
EvaluateValue(); EvaluateValue();
var tmp_point = Point.Clone(); var tmpPoint = Point.Clone();
var tmp_obj = InnerObjectiveFunction.CreateNew(); var tmpObj = InnerObjectiveFunction.CreateNew();
for (int ii = 0; ii < _gradient.Count; ++ii) for (int ii = 0; ii < _gradient.Count; ++ii)
{ {
var orig_point = tmp_point[ii]; var origPoint = tmpPoint[ii];
var rel_incr = orig_point * RelativeIncrement; var relIncr = origPoint * RelativeIncrement;
var h = Math.Max(rel_incr, MinimumIncrement); var h = Math.Max(relIncr, MinimumIncrement);
var mult = 1; var mult = 1;
if (orig_point + h > UpperBound[ii]) if (origPoint + h > UpperBound[ii])
mult = -1; mult = -1;
tmp_point[ii] = orig_point + mult*h; tmpPoint[ii] = origPoint + mult*h;
tmp_obj.EvaluateAt(tmp_point); tmpObj.EvaluateAt(tmpPoint);
double bumped_value = tmp_obj.Value; double bumpedValue = tmpObj.Value;
_gradient[ii] = (mult * bumped_value - mult * InnerObjectiveFunction.Value) / h; _gradient[ii] = (mult * bumpedValue - mult * InnerObjectiveFunction.Value) / h;
tmp_point[ii] = orig_point; tmpPoint[ii] = origPoint;
} }
GradientEvaluated = true; GradientEvaluated = true;
} }

2
src/Numerics/Optimization/ObjectiveFunctions/GradientHessianObjectiveFunction.cs

@ -84,4 +84,4 @@ namespace MathNet.Numerics.Optimization.ObjectiveFunctions
public Vector<double> Gradient { get; private set; } public Vector<double> Gradient { get; private set; }
public Matrix<double> Hessian { get; private set; } public Matrix<double> Hessian { get; private set; }
} }
} }

2
src/Numerics/Optimization/ObjectiveFunctions/GradientObjectiveFunction.cs

@ -86,4 +86,4 @@ namespace MathNet.Numerics.Optimization.ObjectiveFunctions
get { throw new NotSupportedException(); } get { throw new NotSupportedException(); }
} }
} }
} }

2
src/Numerics/Optimization/ObjectiveFunctions/HessianObjectiveFunction.cs

@ -86,4 +86,4 @@ namespace MathNet.Numerics.Optimization.ObjectiveFunctions
get { throw new NotSupportedException(); } get { throw new NotSupportedException(); }
} }
} }
} }

2
src/Numerics/Optimization/ObjectiveFunctions/LazyObjectiveFunction.cs

@ -139,4 +139,4 @@ namespace MathNet.Numerics.Optimization.ObjectiveFunctions
} }
} }
} }
} }

2
src/Numerics/Optimization/ObjectiveFunctions/ValueObjectiveFunction.cs

@ -86,4 +86,4 @@ namespace MathNet.Numerics.Optimization.ObjectiveFunctions
get { throw new NotSupportedException(); } get { throw new NotSupportedException(); }
} }
} }
} }

Loading…
Cancel
Save