diff --git a/src/Numerics/Numerics.csproj b/src/Numerics/Numerics.csproj index eef975c3..588fd070 100644 --- a/src/Numerics/Numerics.csproj +++ b/src/Numerics/Numerics.csproj @@ -116,6 +116,7 @@ + diff --git a/src/Numerics/Optimization/BfgsBMinimizer.cs b/src/Numerics/Optimization/BfgsBMinimizer.cs index d3ee586b..f1dd98fa 100644 --- a/src/Numerics/Optimization/BfgsBMinimizer.cs +++ b/src/Numerics/Optimization/BfgsBMinimizer.cs @@ -74,8 +74,8 @@ namespace MathNet.Numerics.Optimization ValidateGradientAndObjective(objective); // Check that we're not already done - MinimizationResult.ExitCondition currentExitCondition = ExitCriteriaSatisfied(objective, null, 0); - if (currentExitCondition != MinimizationResult.ExitCondition.None) + ExitCondition currentExitCondition = ExitCriteriaSatisfied(objective, null, 0); + if (currentExitCondition != ExitCondition.None) return new MinimizationResult(objective, 0, currentExitCondition); // Set up line search algorithm @@ -149,13 +149,13 @@ namespace MathNet.Numerics.Optimization int iterations = DoBfgsUpdate(ref currentExitCondition, lineSearcher, ref pseudoHessian, ref lineSearchDirection, ref previousPoint, ref lineSearchResult, ref candidatePoint, ref step, ref totalLineSearchSteps, ref iterationsWithNontrivialLineSearch); - if (iterations == MaximumIterations && currentExitCondition == MinimizationResult.ExitCondition.None) + if (iterations == MaximumIterations && currentExitCondition == ExitCondition.None) throw new MaximumIterationsException(string.Format("Maximum iterations ({0}) reached.", MaximumIterations)); return new MinimizationWithLineSearchResult(candidatePoint, iterations, currentExitCondition, totalLineSearchSteps, iterationsWithNontrivialLineSearch); } - protected override Vector CalculateSearchDirection(ref Matrix pseudoHessian, + protected override Vector CalculateSearchDirection(ref Matrix pseudoHessian, out double maxLineSearchStep, out double startingStepSize, IObjectiveFunction previousPoint, diff --git a/src/Numerics/Optimization/BfgsMinimizer.cs b/src/Numerics/Optimization/BfgsMinimizer.cs index 376d5e21..f16ab494 100644 --- a/src/Numerics/Optimization/BfgsMinimizer.cs +++ b/src/Numerics/Optimization/BfgsMinimizer.cs @@ -65,8 +65,8 @@ namespace MathNet.Numerics.Optimization ValidateGradientAndObjective(objective); // Check that we're not already done - MinimizationResult.ExitCondition currentExitCondition = ExitCriteriaSatisfied(objective, null, 0); - if (currentExitCondition != MinimizationResult.ExitCondition.None) + ExitCondition currentExitCondition = ExitCriteriaSatisfied(objective, null, 0); + if (currentExitCondition != ExitCondition.None) return new MinimizationResult(objective, 0, currentExitCondition); // Set up line search algorithm @@ -106,17 +106,17 @@ namespace MathNet.Numerics.Optimization int iterationsWithNontrivialLineSearch = lineSearchResult.Iterations > 0 ? 0 : 1; iterations = DoBfgsUpdate(ref currentExitCondition, lineSearcher, ref inversePseudoHessian, ref lineSearchDirection, ref previousPoint, ref lineSearchResult, ref candidate, ref step, ref totalLineSearchSteps, ref iterationsWithNontrivialLineSearch); - if (iterations == MaximumIterations && currentExitCondition == MinimizationResult.ExitCondition.None) + if (iterations == MaximumIterations && currentExitCondition == ExitCondition.None) throw new MaximumIterationsException(String.Format("Maximum iterations ({0}) reached.", MaximumIterations)); - return new MinimizationWithLineSearchResult(candidate, iterations, MinimizationResult.ExitCondition.AbsoluteGradient, totalLineSearchSteps, iterationsWithNontrivialLineSearch); + return new MinimizationWithLineSearchResult(candidate, iterations, ExitCondition.AbsoluteGradient, totalLineSearchSteps, iterationsWithNontrivialLineSearch); } protected override Vector CalculateSearchDirection(ref Matrix inversePseudoHessian, out double maxLineSearchStep, out double startingStepSize, IObjectiveFunction previousPoint, - IObjectiveFunction candidate, + IObjectiveFunction candidate, Vector step) { startingStepSize = 1.0; diff --git a/src/Numerics/Optimization/BfgsMinimizerBase.cs b/src/Numerics/Optimization/BfgsMinimizerBase.cs index 40ab08c7..a9b5a975 100644 --- a/src/Numerics/Optimization/BfgsMinimizerBase.cs +++ b/src/Numerics/Optimization/BfgsMinimizerBase.cs @@ -58,7 +58,7 @@ namespace MathNet.Numerics.Optimization MaximumIterations = maximumIterations; } - protected MinimizationResult.ExitCondition ExitCriteriaSatisfied(IObjectiveFunctionEvaluation candidatePoint, IObjectiveFunctionEvaluation lastPoint, int iterations) + protected ExitCondition ExitCriteriaSatisfied(IObjectiveFunctionEvaluation candidatePoint, IObjectiveFunctionEvaluation lastPoint, int iterations) { Vector relGrad = new DenseVector(candidatePoint.Point.Count); double relativeGradient = 0.0; @@ -67,13 +67,13 @@ namespace MathNet.Numerics.Optimization { double projectedGradient = GetProjectedGradient(candidatePoint, ii); - double tmp = projectedGradient * + double tmp = projectedGradient * Math.Max(Math.Abs(candidatePoint.Point[ii]), 1.0) / normalizer; relativeGradient = Math.Max(relativeGradient, Math.Abs(tmp)); } if (relativeGradient < GradientTolerance) { - return MinimizationResult.ExitCondition.RelativeGradient; + return ExitCondition.RelativeGradient; } if (lastPoint != null) @@ -81,21 +81,21 @@ namespace MathNet.Numerics.Optimization double mostProgress = 0.0; for (int ii = 0; ii < candidatePoint.Point.Count; ++ii) { - var tmp = Math.Abs(candidatePoint.Point[ii] - lastPoint.Point[ii]) / + var tmp = Math.Abs(candidatePoint.Point[ii] - lastPoint.Point[ii]) / Math.Max(Math.Abs(lastPoint.Point[ii]), 1.0); mostProgress = Math.Max(mostProgress, tmp); } if (mostProgress < ParameterTolerance) { - return MinimizationResult.ExitCondition.LackOfProgress; + return ExitCondition.LackOfProgress; } double functionChange = candidatePoint.Value - lastPoint.Value; if (iterations > 500 && functionChange < 0 && Math.Abs(functionChange) < FunctionProgressTolerance) - return MinimizationResult.ExitCondition.LackOfProgress; + return ExitCondition.LackOfProgress; } - return MinimizationResult.ExitCondition.None; + return ExitCondition.None; } protected virtual double GetProjectedGradient(IObjectiveFunctionEvaluation candidatePoint, int ii) @@ -114,7 +114,7 @@ namespace MathNet.Numerics.Optimization throw new EvaluationException("Non-finite objective function returned.", eval); } - protected int DoBfgsUpdate(ref MinimizationResult.ExitCondition currentExitCondition, WolfeLineSearch lineSearcher, ref Matrix inversePseudoHessian, ref Vector lineSearchDirection, ref IObjectiveFunction previousPoint, ref LineSearchResult lineSearchResult, ref IObjectiveFunction candidate, ref Vector step, ref int totalLineSearchSteps, ref int iterationsWithNontrivialLineSearch) + protected int DoBfgsUpdate(ref ExitCondition currentExitCondition, WolfeLineSearch lineSearcher, ref Matrix inversePseudoHessian, ref Vector lineSearchDirection, ref IObjectiveFunction previousPoint, ref LineSearchResult lineSearchResult, ref IObjectiveFunction candidate, ref Vector step, ref int totalLineSearchSteps, ref int iterationsWithNontrivialLineSearch) { int iterations; for (iterations = 1; iterations < MaximumIterations; ++iterations) @@ -140,7 +140,7 @@ namespace MathNet.Numerics.Optimization candidate = lineSearchResult.FunctionInfoAtMinimum; currentExitCondition = ExitCriteriaSatisfied(candidate, previousPoint, iterations); - if (currentExitCondition != MinimizationResult.ExitCondition.None) + if (currentExitCondition != ExitCondition.None) break; } diff --git a/src/Numerics/Optimization/ConjugateGradientMinimizer.cs b/src/Numerics/Optimization/ConjugateGradientMinimizer.cs index 554e705f..8a7d6d4d 100644 --- a/src/Numerics/Optimization/ConjugateGradientMinimizer.cs +++ b/src/Numerics/Optimization/ConjugateGradientMinimizer.cs @@ -55,7 +55,7 @@ namespace MathNet.Numerics.Optimization // Check that we're not already done if (ExitCriteriaSatisfied(initialGuess, gradient)) - return new MinimizationResult(objective, 0, MinimizationResult.ExitCondition.AbsoluteGradient); + return new MinimizationResult(objective, 0, ExitCondition.AbsoluteGradient); // Set up line search algorithm var lineSearcher = new WeakWolfeLineSearch(1e-4, 0.1, 1e-4, 1000); @@ -118,7 +118,7 @@ namespace MathNet.Numerics.Optimization throw new MaximumIterationsException(String.Format("Maximum iterations ({0}) reached.", MaximumIterations)); } - return new MinimizationWithLineSearchResult(objective, iterations, MinimizationResult.ExitCondition.AbsoluteGradient, totalLineSearchSteps, iterationsWithNontrivialLineSearch); + return new MinimizationWithLineSearchResult(objective, iterations, ExitCondition.AbsoluteGradient, totalLineSearchSteps, iterationsWithNontrivialLineSearch); } bool ExitCriteriaSatisfied(Vector candidatePoint, Vector gradient) diff --git a/src/Numerics/Optimization/ExitCondition.cs b/src/Numerics/Optimization/ExitCondition.cs new file mode 100644 index 00000000..90f30714 --- /dev/null +++ b/src/Numerics/Optimization/ExitCondition.cs @@ -0,0 +1,43 @@ +// +// Math.NET Numerics, part of the Math.NET Project +// http://numerics.mathdotnet.com +// http://github.com/mathnet/mathnet-numerics +// +// Copyright (c) 2009-2017 Math.NET +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// + +namespace MathNet.Numerics.Optimization +{ + public enum ExitCondition + { + None, + RelativeGradient, + LackOfProgress, + AbsoluteGradient, + WeakWolfeCriteria, + BoundTolerance, + StrongWolfeCriteria, + Converged + } +} diff --git a/src/Numerics/Optimization/GoldenSectionMinimizer.cs b/src/Numerics/Optimization/GoldenSectionMinimizer.cs index 1e33f042..f156d7a7 100644 --- a/src/Numerics/Optimization/GoldenSectionMinimizer.cs +++ b/src/Numerics/Optimization/GoldenSectionMinimizer.cs @@ -124,7 +124,7 @@ namespace MathNet.Numerics.Optimization if (iterations == MaximumIterations) throw new MaximumIterationsException("Max iterations reached."); - return new MinimizationResult1D(middle, iterations, MinimizationResult.ExitCondition.BoundTolerance); + return new MinimizationResult1D(middle, iterations, ExitCondition.BoundTolerance); } void ValueChecker(double value, double point) diff --git a/src/Numerics/Optimization/LineSearch/StrongWolfeLineSearch.cs b/src/Numerics/Optimization/LineSearch/StrongWolfeLineSearch.cs index b2fee562..17de657a 100644 --- a/src/Numerics/Optimization/LineSearch/StrongWolfeLineSearch.cs +++ b/src/Numerics/Optimization/LineSearch/StrongWolfeLineSearch.cs @@ -39,9 +39,9 @@ namespace MathNet.Numerics.Optimization.LineSearch // Argument validation in base class } - protected override MinimizationResult.ExitCondition WolfeExitCondition + protected override ExitCondition WolfeExitCondition { - get { return MinimizationResult.ExitCondition.StrongWolfeCriteria; } + get { return ExitCondition.StrongWolfeCriteria; } } protected override bool WolfeCondition(double stepDd, double initialDd) diff --git a/src/Numerics/Optimization/LineSearch/WeakWolfeLineSearch.cs b/src/Numerics/Optimization/LineSearch/WeakWolfeLineSearch.cs index 1e0cb58c..5048fdee 100644 --- a/src/Numerics/Optimization/LineSearch/WeakWolfeLineSearch.cs +++ b/src/Numerics/Optimization/LineSearch/WeakWolfeLineSearch.cs @@ -38,9 +38,9 @@ namespace MathNet.Numerics.Optimization.LineSearch /// i) Armijo Rule: f(x_k + alpha_k p_k) <= f(x_k) + c1 alpha_k p_k^T g(x_k) /// ii) Curvature Condition: p_k^T g(x_k + alpha_k p_k) >= c2 p_k^T g(x_k) /// where g(x) is the gradient of f(x), 0 < c1 < c2 < 1. - /// + /// /// Implementation is based on http://www.math.washington.edu/~burke/crs/408/lectures/L9-weak-Wolfe.pdf - /// + /// /// references: /// http://en.wikipedia.org/wiki/Wolfe_conditions /// http://www.math.washington.edu/~burke/crs/408/lectures/L9-weak-Wolfe.pdf @@ -53,9 +53,9 @@ namespace MathNet.Numerics.Optimization.LineSearch // Validation in base class } - protected override MinimizationResult.ExitCondition WolfeExitCondition + protected override ExitCondition WolfeExitCondition { - get { return MinimizationResult.ExitCondition.WeakWolfeCriteria; } + get { return ExitCondition.WeakWolfeCriteria; } } protected override bool WolfeCondition(double stepDd, double initialDd) diff --git a/src/Numerics/Optimization/LineSearch/WolfeLineSearch.cs b/src/Numerics/Optimization/LineSearch/WolfeLineSearch.cs index a84b52cd..aad4d726 100644 --- a/src/Numerics/Optimization/LineSearch/WolfeLineSearch.cs +++ b/src/Numerics/Optimization/LineSearch/WolfeLineSearch.cs @@ -82,7 +82,7 @@ namespace MathNet.Numerics.Optimization.LineSearch IObjectiveFunction objective = startingPoint.CreateNew(); int ii; - MinimizationResult.ExitCondition reasonForExit = MinimizationResult.ExitCondition.None; + ExitCondition reasonForExit = ExitCondition.None; for (ii = 0; ii < MaximumIterations; ++ii) { objective.EvaluateAt(startingPoint.Point + searchDirection * step); @@ -117,7 +117,7 @@ namespace MathNet.Numerics.Optimization.LineSearch } if (maxRelChange < ParameterTolerance) { - reasonForExit = MinimizationResult.ExitCondition.LackOfProgress; + reasonForExit = ExitCondition.LackOfProgress; break; } } @@ -136,7 +136,7 @@ namespace MathNet.Numerics.Optimization.LineSearch return new LineSearchResult(objective, ii, step, reasonForExit); } - protected abstract MinimizationResult.ExitCondition WolfeExitCondition { get; } + protected abstract ExitCondition WolfeExitCondition { get; } protected abstract bool WolfeCondition(double stepDd, double initialDd); diff --git a/src/Numerics/Optimization/MinimizationResult.cs b/src/Numerics/Optimization/MinimizationResult.cs index f9b09298..ead9c371 100644 --- a/src/Numerics/Optimization/MinimizationResult.cs +++ b/src/Numerics/Optimization/MinimizationResult.cs @@ -33,19 +33,6 @@ namespace MathNet.Numerics.Optimization { public class MinimizationResult { - public enum ExitCondition - { - None, - RelativeGradient, - LackOfProgress, - AbsoluteGradient, - WeakWolfeCriteria, - BoundTolerance, - StrongWolfeCriteria, - LackOfFunctionImprovement, - Converged - } - public Vector MinimizingPoint { get { return FunctionInfoAtMinimum.Point; } } public IObjectiveFunction FunctionInfoAtMinimum { get; private set; } public int Iterations { get; private set; } diff --git a/src/Numerics/Optimization/MinimizationResult1D.cs b/src/Numerics/Optimization/MinimizationResult1D.cs index ac2aa869..6319fdc2 100644 --- a/src/Numerics/Optimization/MinimizationResult1D.cs +++ b/src/Numerics/Optimization/MinimizationResult1D.cs @@ -34,9 +34,9 @@ namespace MathNet.Numerics.Optimization public double MinimizingPoint { get { return FunctionInfoAtMinimum.Point; } } public IEvaluation1D FunctionInfoAtMinimum { get; private set; } public int Iterations { get; private set; } - public MinimizationResult.ExitCondition ReasonForExit { get; private set; } + public ExitCondition ReasonForExit { get; private set; } - public MinimizationResult1D(IEvaluation1D functionInfo, int iterations, MinimizationResult.ExitCondition reasonForExit) + public MinimizationResult1D(IEvaluation1D functionInfo, int iterations, ExitCondition reasonForExit) { FunctionInfoAtMinimum = functionInfo; Iterations = iterations; diff --git a/src/Numerics/Optimization/NelderMeadSimplex.cs b/src/Numerics/Optimization/NelderMeadSimplex.cs index 29afc3bb..c9dbb636 100644 --- a/src/Numerics/Optimization/NelderMeadSimplex.cs +++ b/src/Numerics/Optimization/NelderMeadSimplex.cs @@ -100,7 +100,7 @@ namespace MathNet.Numerics.Optimization double[] errorValues = new double[numVertices]; int evaluationCount = 0; - MinimizationResult.ExitCondition exitCondition = MinimizationResult.ExitCondition.None; + ExitCondition exitCondition = ExitCondition.None; ErrorProfile errorProfile; errorValues = InitializeErrorValues(vertices, objectiveFunction); @@ -113,7 +113,7 @@ namespace MathNet.Numerics.Optimization // see if the range in point heights is small enough to exit if (HasConverged(ConvergenceTolerance, errorProfile, errorValues)) { - exitCondition = MinimizationResult.ExitCondition.Converged; + exitCondition = ExitCondition.Converged; break; } @@ -135,7 +135,7 @@ namespace MathNet.Numerics.Optimization ++evaluationCount; if (contractionPointValue >= currentWorst) { - // that would be even worse, so let's try to contract uniformly towards the low point; + // that would be even worse, so let's try to contract uniformly towards the low point; // don't bother to update the error profile, we'll do it at the start of the // next iteration ShrinkSimplex(errorProfile, vertices, errorValues, objectiveFunction); diff --git a/src/Numerics/Optimization/NewtonMinimizer.cs b/src/Numerics/Optimization/NewtonMinimizer.cs index 2f5112a1..8ca0c384 100644 --- a/src/Numerics/Optimization/NewtonMinimizer.cs +++ b/src/Numerics/Optimization/NewtonMinimizer.cs @@ -63,7 +63,7 @@ namespace MathNet.Numerics.Optimization ValidateGradient(objective); if (ExitCriteriaSatisfied(objective.Gradient)) { - return new MinimizationResult(objective, 0, MinimizationResult.ExitCondition.AbsoluteGradient); + return new MinimizationResult(objective, 0, ExitCondition.AbsoluteGradient); } // Set up line search algorithm @@ -117,7 +117,7 @@ namespace MathNet.Numerics.Optimization throw new MaximumIterationsException(String.Format("Maximum iterations ({0}) reached.", MaximumIterations)); } - return new MinimizationWithLineSearchResult(objective, iterations, MinimizationResult.ExitCondition.AbsoluteGradient, totalLineSearchSteps, iterationsWithNontrivialLineSearch); + return new MinimizationWithLineSearchResult(objective, iterations, ExitCondition.AbsoluteGradient, totalLineSearchSteps, iterationsWithNontrivialLineSearch); } bool ExitCriteriaSatisfied(Vector gradient)