From 73c61e7e4f141d61375f3b959348248e7174bd32 Mon Sep 17 00:00:00 2001 From: joemoorhouse Date: Sun, 10 Nov 2013 20:45:18 +0000 Subject: [PATCH] NonLinearLeastSquaresMinimizer change API --- .../NonLinearLeastSquaresMinimizer.cs | 105 ++++++++++-------- .../Optimization/IOptimizationProvider.cs | 4 +- .../Mkl/MklOptimizationProvider.cs | 24 ++-- .../NonLinearLeastSquaresTest.cs | 7 +- 4 files changed, 77 insertions(+), 63 deletions(-) diff --git a/src/Numerics/Optimization/NonLinearLeastSquaresMinimizer.cs b/src/Numerics/Optimization/NonLinearLeastSquaresMinimizer.cs index 5611477c..bec4f902 100644 --- a/src/Numerics/Optimization/NonLinearLeastSquaresMinimizer.cs +++ b/src/Numerics/Optimization/NonLinearLeastSquaresMinimizer.cs @@ -6,66 +6,77 @@ using MathNet.Numerics.Providers.Optimization; using MathNet.Numerics.Providers.Optimization.Mkl; namespace MathNet.Numerics.Optimization -{ +{ /// - /// This class is a special function minimizer that minimizes functions of the form - /// f(p) = |r(p)|^2 where r is a vector of residuals and p is a vector of model parameters. + /// Options for Non-Linear Least Squares Minimization. /// - public class NonLinearLeastSquaresMinimizer + public class NonLinearLeastSquaresOptions { - public class Options - { - public int MaximumIterations = 1000; + public int MaximumIterations = 1000; - public int MaximumTrialStepIterations = 100; + public int MaximumTrialStepIterations = 100; - public ConvergenceType ConvergenceType; + public NonLinearLeastSquaresConvergenceType ConvergenceType; - /// - /// Convergence if Δ < Criterion0, Δ is trust region size. - /// - public double Criterion0 = 1e-7; + /// + /// Convergence if Δ < Criterion0, Δ is trust region size. + /// + public double Criterion0 = 1e-7; - /// - /// Convergence if |r|2 < Criterion1, r is residuals vector. - /// - public double Criterion1 = 1e-7; + /// + /// Convergence if |r|2 < Criterion1, r is residuals vector. + /// + public double Criterion1 = 1e-7; - /// - /// Jacobian considered singular if |J(:,j)|2 < Criterion2 for any j. - /// - public double Criterion2 = 1e-7; + /// + /// Jacobian considered singular if |J(:,j)|2 < Criterion2 for any j. + /// + public double Criterion2 = 1e-7; - /// - /// Jacobian considered singular if |s|2 < Criterion3. s is trial step. - /// - public double Criterion3 = 1e-7; + /// + /// Jacobian considered singular if |s|2 < Criterion3. s is trial step. + /// + public double Criterion3 = 1e-7; - /// - /// |r|2 - |r - Js|2 < Criterion4 - /// - public double Criterion4 = 1e-7; + /// + /// |r|2 - |r - Js|2 < Criterion4 + /// + public double Criterion4 = 1e-7; - public double TrialStepPrecision = 1e-10; + public double TrialStepPrecision = 1e-10; - /// - /// Only if Jacobian calculated by central differences. - /// - public double JacobianPrecision = 1e-8; - } - /// - /// For details of convergence criteria, see Options. + /// Only if Jacobian calculated by central differences. /// - public enum ConvergenceType { NoneMaxIterationExceeded, Criterion0, Criterion1, Criterion2, Criterion3, Criterion4, Error }; - - public class Result - { - public int NumberOfIterations; + public double JacobianPrecision = 1e-8; + } + + /// + /// For details of convergence criteria, see Options. + /// + public enum NonLinearLeastSquaresConvergenceType { NoneMaxIterationExceeded, Criterion0, Criterion1, Criterion2, Criterion3, Criterion4, Error }; + + /// + /// Result of Non-Linear Least Squares Minimization. + /// + public class NonLinearLeastSquaresResult + { + public int NumberOfIterations; + + public NonLinearLeastSquaresConvergenceType ConvergenceType; + } + + + /// + /// This class is a special function minimizer that minimizes functions of the form + /// f(p) = |r(p)|^2 where r is a vector of residuals and p is a vector of model parameters. + /// + public class NonLinearLeastSquaresMinimizer + { + public NonLinearLeastSquaresResult Result { get; private set; } + + public readonly NonLinearLeastSquaresOptions Options = new NonLinearLeastSquaresOptions(); - public ConvergenceType ConvergenceType; - } - /// /// Non-Linear Least-Squares fitting the points (x,y) to a specified function of y : x -> f(x, p), p being a vector of parameters. /// returning its best fitting parameters p. @@ -76,7 +87,7 @@ namespace MathNet.Numerics.Optimization /// Initial guess of parameters, p. /// jac_j(x, p) = df / dp_j /// - public static double[] CurveFit(double[] x, double[] y, Func f, + public double[] CurveFit(double[] x, double[] y, Func f, double[] pStart, Func jacobian = null) { if (x.Length != y.Length) throw new ArgumentException("x and y lengths different"); @@ -101,7 +112,7 @@ namespace MathNet.Numerics.Optimization }; double[] parameters; - Result result = provider.NonLinearLeastSquaresUnboundedMinimize(y.Length, pStart, function, out parameters, jacobianFunction); + Result = provider.NonLinearLeastSquaresUnboundedMinimize(y.Length, pStart, function, out parameters, jacobianFunction); return parameters; } } diff --git a/src/Numerics/Providers/Optimization/IOptimizationProvider.cs b/src/Numerics/Providers/Optimization/IOptimizationProvider.cs index 3e2400ba..fc137554 100644 --- a/src/Numerics/Providers/Optimization/IOptimizationProvider.cs +++ b/src/Numerics/Providers/Optimization/IOptimizationProvider.cs @@ -56,8 +56,8 @@ namespace MathNet.Numerics.Providers.Optimization public interface IOptimizationProvider where T : struct { - NonLinearLeastSquaresMinimizer.Result NonLinearLeastSquaresUnboundedMinimize( + NonLinearLeastSquaresResult NonLinearLeastSquaresUnboundedMinimize( int residualsLength, T[] initialGuess, LeastSquaresForwardModel function, - out T[] parameters, Jacobian jacobianFunction = null, NonLinearLeastSquaresMinimizer.Options options = null); + out T[] parameters, Jacobian jacobianFunction = null, NonLinearLeastSquaresOptions options = null); } } diff --git a/src/Numerics/Providers/Optimization/Mkl/MklOptimizationProvider.cs b/src/Numerics/Providers/Optimization/Mkl/MklOptimizationProvider.cs index eeac095e..b5530720 100644 --- a/src/Numerics/Providers/Optimization/Mkl/MklOptimizationProvider.cs +++ b/src/Numerics/Providers/Optimization/Mkl/MklOptimizationProvider.cs @@ -42,9 +42,9 @@ namespace MathNet.Numerics.Providers.Optimization.Mkl { const int TR_SUCCESS = 1501; - public NonLinearLeastSquaresMinimizer.Result NonLinearLeastSquaresUnboundedMinimize(int residualsLength, double[] initialGuess, LeastSquaresForwardModel function, out double[] parameters, Jacobian jacobianFunction = null, NonLinearLeastSquaresMinimizer.Options options = null) + public NonLinearLeastSquaresResult NonLinearLeastSquaresUnboundedMinimize(int residualsLength, double[] initialGuess, LeastSquaresForwardModel function, out double[] parameters, Jacobian jacobianFunction = null, NonLinearLeastSquaresOptions options = null) { - if (options == null) options = new NonLinearLeastSquaresMinimizer.Options(); + if (options == null) options = new NonLinearLeastSquaresOptions(); bool analyticJacobian = jacobianFunction != null; double[] residuals = new double[residualsLength]; double[] residualsMinus = new double[residualsLength]; @@ -176,30 +176,30 @@ namespace MathNet.Numerics.Providers.Optimization.Mkl SafeNativeMethods.FreeBuffers(); - NonLinearLeastSquaresMinimizer.ConvergenceType convergenceType = NonLinearLeastSquaresMinimizer.ConvergenceType.Error; + NonLinearLeastSquaresConvergenceType convergenceType = NonLinearLeastSquaresConvergenceType.Error; switch (rciRequest) { case -1: - convergenceType = NonLinearLeastSquaresMinimizer.ConvergenceType.NoneMaxIterationExceeded; break; + convergenceType = NonLinearLeastSquaresConvergenceType.NoneMaxIterationExceeded; break; case -2: - convergenceType = NonLinearLeastSquaresMinimizer.ConvergenceType.Criterion0; break; + convergenceType = NonLinearLeastSquaresConvergenceType.Criterion0; break; case -3: - convergenceType = NonLinearLeastSquaresMinimizer.ConvergenceType.Criterion1; break; + convergenceType = NonLinearLeastSquaresConvergenceType.Criterion1; break; case -4: - convergenceType = NonLinearLeastSquaresMinimizer.ConvergenceType.Criterion2; break; + convergenceType = NonLinearLeastSquaresConvergenceType.Criterion2; break; case -5: - convergenceType = NonLinearLeastSquaresMinimizer.ConvergenceType.Criterion3; break; + convergenceType = NonLinearLeastSquaresConvergenceType.Criterion3; break; case -6: - convergenceType = NonLinearLeastSquaresMinimizer.ConvergenceType.Criterion4; break; + convergenceType = NonLinearLeastSquaresConvergenceType.Criterion4; break; } // no errors, find reason for stopping; - return new NonLinearLeastSquaresMinimizer.Result() { ConvergenceType = convergenceType, NumberOfIterations = iterations }; + return new NonLinearLeastSquaresResult() { ConvergenceType = convergenceType, NumberOfIterations = iterations }; } - public static NonLinearLeastSquaresMinimizer.Result ErrorResult() + public static NonLinearLeastSquaresResult ErrorResult() { - return new NonLinearLeastSquaresMinimizer.Result() { ConvergenceType = NonLinearLeastSquaresMinimizer.ConvergenceType.Error }; + return new NonLinearLeastSquaresResult() { ConvergenceType = NonLinearLeastSquaresConvergenceType.Error }; } } } diff --git a/src/UnitTests/OptimizationTests/NonLinearLeastSquaresTest.cs b/src/UnitTests/OptimizationTests/NonLinearLeastSquaresTest.cs index 17cf12d7..325275ef 100644 --- a/src/UnitTests/OptimizationTests/NonLinearLeastSquaresTest.cs +++ b/src/UnitTests/OptimizationTests/NonLinearLeastSquaresTest.cs @@ -40,17 +40,20 @@ namespace MathNet.Numerics.UnitTests.OptimizationTests [Test] public void CurveFit() { + var minimizer = new NonLinearLeastSquaresMinimizer(); + minimizer.Options.MaximumIterations = 1010; + minimizer.Options.Criterion4 = 1e-8; // y = b1*(1-exp[-b2*x]) + e var xin = new double[] { 1, 2, 3, 5, 7, 10 }; var yin = new double[] { 109, 149, 149, 191, 213, 224 }; - var popt = NonLinearLeastSquaresMinimizer.CurveFit(xin, yin, (x, p) => p[0] * (1 - Math.Exp(-p[1] * x)), new double[] { 1, 1 }); + var popt = minimizer.CurveFit(xin, yin, (x, p) => p[0] * (1 - Math.Exp(-p[1] * x)), new double[] { 1, 1 }); Func function = (x, p) => p[0] * (1 - Math.Exp(-p[1] * x)); Func jacobian = (x, p) => new double[] { 1 - Math.Exp(-p[1] * x), p[0] * x * Math.Exp(-p[1] * x) }; - popt = NonLinearLeastSquaresMinimizer.CurveFit(xin, yin, function, new double[] { 1, 1 }, jacobian); // 100, 0.75 + popt = minimizer.CurveFit(xin, yin, function, new double[] { 1, 1 }, jacobian); // 100, 0.75 double[] expected = new double[] { 2.1380940889E+02, 5.4723748542E-01 };