From 2a8ccfea579d2de04b0f7b6133d64e3b386e218d Mon Sep 17 00:00:00 2001 From: Scott Stephens Date: Thu, 31 Jan 2013 09:23:50 -0600 Subject: [PATCH] First commit working on optimization tools --- src/Numerics/Numerics.csproj | 7 +- src/Numerics/Optimization/BFGS.cs | 11 +++ .../ConjugateGradientMinimizer.cs | 78 +++++++++++++++++++ .../Optimization/GoldenSectionMinimizer.cs | 6 ++ .../LineSearch/StrongWolfeLineSearch.cs | 11 +++ .../Optimization/OptimizationResult.cs | 8 ++ .../TestConjugateGradientMinimizer.cs | 32 ++++++++ src/UnitTests/UnitTests.csproj | 11 +++ 8 files changed, 163 insertions(+), 1 deletion(-) create mode 100644 src/Numerics/Optimization/BFGS.cs create mode 100644 src/Numerics/Optimization/ConjugateGradientMinimizer.cs create mode 100644 src/Numerics/Optimization/GoldenSectionMinimizer.cs create mode 100644 src/Numerics/Optimization/LineSearch/StrongWolfeLineSearch.cs create mode 100644 src/Numerics/Optimization/OptimizationResult.cs create mode 100644 src/UnitTests/OptimizationTests/TestConjugateGradientMinimizer.cs diff --git a/src/Numerics/Numerics.csproj b/src/Numerics/Numerics.csproj index 77e1579d..27b0246a 100644 --- a/src/Numerics/Numerics.csproj +++ b/src/Numerics/Numerics.csproj @@ -121,7 +121,6 @@ - @@ -263,6 +262,12 @@ + + + + + + diff --git a/src/Numerics/Optimization/BFGS.cs b/src/Numerics/Optimization/BFGS.cs new file mode 100644 index 00000000..7b9942d2 --- /dev/null +++ b/src/Numerics/Optimization/BFGS.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace MathNet.Numerics.Optimization +{ + class BFGS + { + } +} diff --git a/src/Numerics/Optimization/ConjugateGradientMinimizer.cs b/src/Numerics/Optimization/ConjugateGradientMinimizer.cs new file mode 100644 index 00000000..44611707 --- /dev/null +++ b/src/Numerics/Optimization/ConjugateGradientMinimizer.cs @@ -0,0 +1,78 @@ +using System; +using MathNet.Numerics.LinearAlgebra; +using MathNet.Numerics.Optimization.LineSearch; + +namespace MathNet.Numerics.Optimization +{ + public class ConjugateGradientMinimizer + { + public double GradientTolerance { get; set; } + public int MaximumIterations { get; set; } + + public ConjugateGradientMinimizer(double gradientTolerance, int maximumIterations) + { + this.GradientTolerance = gradientTolerance; + this.MaximumIterations = maximumIterations; + } + + public MinimizationResult FindMinimum(IObjectiveFunction objective, Vector initialGuess) + { + if (!objective.IsGradientSupported) + throw new Exception("Gradient not supported in objective function, but required for ConjugateGradient minimization."); + + objective.EvaluateAt(initialGuess); + var gradient = objective.Gradient; + ValidateGradient(gradient, initialGuess); + + // Check that we're not already done + if (ExitCriteriaSatisfied(initialGuess, gradient)) + return new MinimizationResult(objective, 0, MinimizationResult.ExitCondition.AbsoluteGradient); + + // Set up line search algorithm + var lineSearcher = new WeakWolfeLineSearch(1e-4, 0.1, 1e-4, 1000); + + // First step + var steepestDirection = -gradient; + var searchDirection = steepestDirection; + var result = lineSearcher.FindConformingStep(objective, searchDirection, 1.0); + objective = result.FunctionInfoAtMinimum; + ValidateGradient(objective.Gradient, objective.Point); + + // Subsequent steps + int iterations = 1; + while (!ExitCriteriaSatisfied(objective.Point, objective.Gradient) && iterations < MaximumIterations) + { + var previousSteepestDirection = steepestDirection; + steepestDirection = -objective.Gradient; + var searchDirectionAdjuster = steepestDirection * (steepestDirection - previousSteepestDirection) / (previousSteepestDirection * previousSteepestDirection); + searchDirection = steepestDirection + searchDirectionAdjuster * previousSteepestDirection; + result = lineSearcher.FindConformingStep(objective, searchDirection, 1.0); + + objective = result.FunctionInfoAtMinimum; + iterations += 1; + } + + return new MinimizationResult(objective, iterations, MinimizationResult.ExitCondition.AbsoluteGradient); + } + + private bool ExitCriteriaSatisfied(Vector candidatePoint, Vector gradient) + { + return gradient.Norm(2.0) < GradientTolerance; + } + + private void ValidateGradient(Vector gradient, Vector input) + { + foreach (var x in gradient) + { + if (Double.IsNaN(x) || Double.IsInfinity(x)) + throw new Exception("Non-finite gradient returned."); + } + } + + private void ValidateObjective(double objective, Vector input) + { + if (Double.IsNaN(objective) || Double.IsInfinity(objective)) + throw new Exception("Non-finite objective function returned."); + } + } +} diff --git a/src/Numerics/Optimization/GoldenSectionMinimizer.cs b/src/Numerics/Optimization/GoldenSectionMinimizer.cs new file mode 100644 index 00000000..516cceeb --- /dev/null +++ b/src/Numerics/Optimization/GoldenSectionMinimizer.cs @@ -0,0 +1,6 @@ +namespace MathNet.Numerics.Optimization +{ + class GoldenSectionMinimizer + { + } +} diff --git a/src/Numerics/Optimization/LineSearch/StrongWolfeLineSearch.cs b/src/Numerics/Optimization/LineSearch/StrongWolfeLineSearch.cs new file mode 100644 index 00000000..236c63c9 --- /dev/null +++ b/src/Numerics/Optimization/LineSearch/StrongWolfeLineSearch.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace MathNet.Numerics.Optimization +{ + class StrongWolfeLineSearch + { + } +} diff --git a/src/Numerics/Optimization/OptimizationResult.cs b/src/Numerics/Optimization/OptimizationResult.cs new file mode 100644 index 00000000..512e11d9 --- /dev/null +++ b/src/Numerics/Optimization/OptimizationResult.cs @@ -0,0 +1,8 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace MathNet.Numerics.Optimization +{ +} diff --git a/src/UnitTests/OptimizationTests/TestConjugateGradientMinimizer.cs b/src/UnitTests/OptimizationTests/TestConjugateGradientMinimizer.cs new file mode 100644 index 00000000..b06f410c --- /dev/null +++ b/src/UnitTests/OptimizationTests/TestConjugateGradientMinimizer.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using NUnit.Framework; + +using MathNet.Numerics.Optimization; + +namespace MathNet.Numerics.UnitTests.OptimizationTests +{ + [TestFixture] + public class TestConjugateGradientMinimizer + { + + [Test] + public void FindMinimum_Rosenbrock_Easy() + { + var obj = new SimpleObjectiveFunction(RosenbrockFunction.Value, RosenbrockFunction.Gradient); + var solver = new ConjugateGradientMinimizer(1e-5, 100); + var result = solver.FindMinimum(obj, new MathNet.Numerics.LinearAlgebra.Double.DenseVector(new double[]{1.2,1.2})); + Assert.That(result.MinimizingPoint[0], Is.EqualTo(1.0)); + Assert.That(result.MinimizingPoint[1], Is.EqualTo(1.0)); + } + + [Test] + public void FindMinimum_Rosenbrock_Hard() + { + + } + } +} diff --git a/src/UnitTests/UnitTests.csproj b/src/UnitTests/UnitTests.csproj index 92d33f59..455b070b 100644 --- a/src/UnitTests/UnitTests.csproj +++ b/src/UnitTests/UnitTests.csproj @@ -371,6 +371,12 @@ + + + + + + @@ -423,6 +429,11 @@ + + + + +