From edbab552eb59569b0dc7b6a5f32b77e643a757c7 Mon Sep 17 00:00:00 2001 From: Scott Stephens Date: Thu, 31 Jan 2013 14:52:54 -0600 Subject: [PATCH] Very minimally tested ConjugateGradient minimizer is complete. --- .../ConjugateGradientMinimizer.cs | 26 +++++++++++++++---- .../TestConjugateGradientMinimizer.cs | 24 +++++++++-------- src/UnitTests/UnitTests.csproj | 4 --- 3 files changed, 34 insertions(+), 20 deletions(-) diff --git a/src/Numerics/Optimization/ConjugateGradientMinimizer.cs b/src/Numerics/Optimization/ConjugateGradientMinimizer.cs index 44611707..d2aa1049 100644 --- a/src/Numerics/Optimization/ConjugateGradientMinimizer.cs +++ b/src/Numerics/Optimization/ConjugateGradientMinimizer.cs @@ -34,25 +34,41 @@ namespace MathNet.Numerics.Optimization // First step var steepestDirection = -gradient; var searchDirection = steepestDirection; - var result = lineSearcher.FindConformingStep(objective, searchDirection, 1.0); + double initialStepSize = 100 * GradientTolerance / (gradient * gradient); + var result = lineSearcher.FindConformingStep(objective, searchDirection, initialStepSize); objective = result.FunctionInfoAtMinimum; ValidateGradient(objective.Gradient, objective.Point); + double stepSize = (objective.Point - initialGuess).Norm(2.0); // Subsequent steps int iterations = 1; + int totalLineSearchSteps = result.Iterations; + int noLineSearchIterations = result.Iterations > 0 ? 0 : 1; + int steepestDescentResets = 0; 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); + var searchDirectionAdjuster = Math.Max(0, steepestDirection*(steepestDirection - previousSteepestDirection)/(previousSteepestDirection*previousSteepestDirection)); + searchDirection = steepestDirection + searchDirectionAdjuster * searchDirection; + if (searchDirection * objective.Gradient >= 0) + { + searchDirection = steepestDirection; + steepestDescentResets += 1; + } + + + result = lineSearcher.FindConformingStep(objective, searchDirection, stepSize); + + noLineSearchIterations += result.Iterations == 0 ? 1 : 0; + totalLineSearchSteps += result.Iterations; + stepSize = (result.FunctionInfoAtMinimum.Point - objective.Point).Norm(2.0); objective = result.FunctionInfoAtMinimum; iterations += 1; } - return new MinimizationResult(objective, iterations, MinimizationResult.ExitCondition.AbsoluteGradient); + return new MinimizationWithLineSearchResult(objective, iterations, MinimizationResult.ExitCondition.AbsoluteGradient, totalLineSearchSteps, noLineSearchIterations); } private bool ExitCriteriaSatisfied(Vector candidatePoint, Vector gradient) diff --git a/src/UnitTests/OptimizationTests/TestConjugateGradientMinimizer.cs b/src/UnitTests/OptimizationTests/TestConjugateGradientMinimizer.cs index b06f410c..083e56b4 100644 --- a/src/UnitTests/OptimizationTests/TestConjugateGradientMinimizer.cs +++ b/src/UnitTests/OptimizationTests/TestConjugateGradientMinimizer.cs @@ -1,11 +1,7 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -using NUnit.Framework; - +using MathNet.Numerics.LinearAlgebra.Double; using MathNet.Numerics.Optimization; +using NUnit.Framework; namespace MathNet.Numerics.UnitTests.OptimizationTests { @@ -16,17 +12,23 @@ namespace MathNet.Numerics.UnitTests.OptimizationTests [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)); + var obj = ObjectiveFunction.Gradient(RosenbrockFunction.Value, RosenbrockFunction.Gradient); + var solver = new ConjugateGradientMinimizer(1e-5, 1000); + var result = solver.FindMinimum(obj, new DenseVector(new[]{1.2,1.2})); + + Assert.That(Math.Abs(result.MinimizingPoint[0]-1.0), Is.LessThan(1e-3)); + Assert.That(Math.Abs(result.MinimizingPoint[1] - 1.0), Is.LessThan(1e-3)); } [Test] public void FindMinimum_Rosenbrock_Hard() { + var obj = ObjectiveFunction.Gradient(RosenbrockFunction.Value, RosenbrockFunction.Gradient); + var solver = new ConjugateGradientMinimizer(1e-5, 1000); + var result = solver.FindMinimum(obj, new DenseVector(new[] { -1.2, 1.0 })); + Assert.That(Math.Abs(result.MinimizingPoint[0] - 1.0), Is.LessThan(1e-3)); + Assert.That(Math.Abs(result.MinimizingPoint[1] - 1.0), Is.LessThan(1e-3)); } } } diff --git a/src/UnitTests/UnitTests.csproj b/src/UnitTests/UnitTests.csproj index ee83191f..b7f7e374 100644 --- a/src/UnitTests/UnitTests.csproj +++ b/src/UnitTests/UnitTests.csproj @@ -349,10 +349,6 @@ - - - -