Skip to content

Commit

Permalink
Pull in MINPACK
Browse files Browse the repository at this point in the history
  • Loading branch information
avik-pal committed Dec 7, 2023
1 parent a0788dd commit 6b58f42
Showing 18 changed files with 439 additions and 59 deletions.
12 changes: 10 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -33,12 +33,16 @@ UnPack = "3a884ed6-31ef-47d7-9d2a-63182c4928ed"
BandedMatrices = "aae01518-5342-5314-be14-df237901396f"
FastLevenbergMarquardt = "7a0df574-e128-4d35-8cbd-3d84502bf7ce"
LeastSquaresOptim = "0fc2ff8b-aaa3-5acd-a817-1944a5e08891"
MINPACK = "4854310b-de5a-5eb6-a2a5-c1dee2bd17f9"
NLsolve = "2774e3e8-f4cf-5e23-947b-6d7e65073b56"
Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f"

[extensions]
NonlinearSolveBandedMatricesExt = "BandedMatrices"
NonlinearSolveFastLevenbergMarquardtExt = "FastLevenbergMarquardt"
NonlinearSolveLeastSquaresOptimExt = "LeastSquaresOptim"
NonlinearSolveMINPACKExt = "MINPACK"
NonlinearSolveNLsolveExt = "NLsolve"
NonlinearSolveZygoteExt = "Zygote"

[compat]
@@ -60,7 +64,9 @@ LeastSquaresOptim = "0.8"
LineSearches = "7"
LinearAlgebra = "<0.0.1, 1"
LinearSolve = "2.12"
MINPACK = "1.2"
MaybeInplace = "0.1"
NLsolve = "4.5"
NaNMath = "1"
NonlinearProblemLibrary = "0.1"
Pkg = "1"
@@ -94,17 +100,19 @@ ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
LeastSquaresOptim = "0fc2ff8b-aaa3-5acd-a817-1944a5e08891"
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
LinearSolve = "7ed4a6bd-45f5-4d41-b270-4a48e9bafcae"
MINPACK = "4854310b-de5a-5eb6-a2a5-c1dee2bd17f9"
NLsolve = "2774e3e8-f4cf-5e23-947b-6d7e65073b56"
NaNMath = "77ba4419-2d1f-58cd-9bb1-8ffee604a2e3"
NonlinearProblemLibrary = "b7050fa9-e91f-4b37-bcee-a89a063da141"
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f"
StableRNGs = "860ef19b-820b-49d6-a774-d7a799459cd3"
SparseDiffTools = "47a9eef4-7e08-11e9-0b38-333d64bd3804"
StableRNGs = "860ef19b-820b-49d6-a774-d7a799459cd3"
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
Symbolics = "0c5d862f-8b57-4792-8d23-62f2024744c7"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f"

[targets]
test = ["Aqua", "Enzyme", "BenchmarkTools", "SafeTestsets", "Pkg", "Test", "ForwardDiff", "StaticArrays", "Symbolics", "LinearSolve", "Random", "LinearAlgebra", "Zygote", "SparseDiffTools", "NonlinearProblemLibrary", "LeastSquaresOptim", "FastLevenbergMarquardt", "NaNMath", "BandedMatrices", "DiffEqBase", "StableRNGs"]
test = ["Aqua", "Enzyme", "BenchmarkTools", "SafeTestsets", "Pkg", "Test", "ForwardDiff", "StaticArrays", "Symbolics", "LinearSolve", "Random", "LinearAlgebra", "Zygote", "SparseDiffTools", "NonlinearProblemLibrary", "LeastSquaresOptim", "FastLevenbergMarquardt", "NaNMath", "BandedMatrices", "DiffEqBase", "StableRNGs", "MINPACK", "NLsolve"]
3 changes: 0 additions & 3 deletions docs/Project.toml
Original file line number Diff line number Diff line change
@@ -8,10 +8,8 @@ IncompleteLU = "40713840-3770-5561-ab4c-a76e7d0d7895"
LinearSolve = "7ed4a6bd-45f5-4d41-b270-4a48e9bafcae"
ModelingToolkit = "961ee093-0014-501f-94e3-6117800e7a78"
NonlinearSolve = "8913a72c-1f9b-4ce2-8d82-65094dcecaec"
NonlinearSolveMINPACK = "c100e077-885d-495a-a2ea-599e143bf69d"
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
SciMLBase = "0bca4576-84f4-4d90-8ffe-ffa030f20462"
SciMLNLSolve = "e9a6253c-8580-4d32-9898-8661bb511710"
SimpleNonlinearSolve = "727e6d20-b764-4bd8-a329-72de5adea6c7"
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
SteadyStateDiffEq = "9672c7b4-1e72-59bd-8a11-6ac3964bc41f"
@@ -31,7 +29,6 @@ NonlinearSolve = "3"
NonlinearSolveMINPACK = "0.1"
Random = "<0.0.1, 1"
SciMLBase = "2.4"
SciMLNLSolve = "0.1"
SimpleNonlinearSolve = "1"
StaticArrays = "1"
SteadyStateDiffEq = "2"
7 changes: 4 additions & 3 deletions docs/make.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Documenter, NonlinearSolve, SimpleNonlinearSolve, Sundials, SciMLNLSolve,
NonlinearSolveMINPACK, SteadyStateDiffEq, SciMLBase, DiffEqBase
using Documenter,
NonlinearSolve, SimpleNonlinearSolve, Sundials,
SteadyStateDiffEq, SciMLBase, DiffEqBase

cp("./docs/Manifest.toml", "./docs/src/assets/Manifest.toml", force = true)
cp("./docs/Project.toml", "./docs/src/assets/Project.toml", force = true)
@@ -9,7 +10,7 @@ include("pages.jl")
makedocs(sitename = "NonlinearSolve.jl",
authors = "Chris Rackauckas",
modules = [NonlinearSolve, SciMLBase, DiffEqBase, SimpleNonlinearSolve, Sundials,
SciMLNLSolve, NonlinearSolveMINPACK, SteadyStateDiffEq],
SteadyStateDiffEq],
clean = true, doctest = false, linkcheck = true,
linkcheck_ignore = ["https://twitter.com/ChrisRackauckas/status/1544743542094020615"],
warnonly = [:missing_docs, :cross_references],
10 changes: 4 additions & 6 deletions docs/src/api/fastlevenbergmarquardt.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
# FastLevenbergMarquardt.jl

This is a wrapper package for importing solvers from FastLevenbergMarquardt.jl into the
SciML interface. Note that these solvers do not come by default, and thus one needs to
install the package before using these solvers:
This is a extension for importing solvers from FastLevenbergMarquardt.jl into the SciML
interface. Note that these solvers do not come by default, and thus one needs to install
the package before using these solvers:

```julia
using Pkg
Pkg.add("FastLevenbergMarquardt")
using FastLevenbergMarquardt
using FastLevenbergMarquardt, NonlinearSolve
```

These methods can be used independently of the rest of NonlinearSolve.jl

## Solver API

```@docs
6 changes: 2 additions & 4 deletions docs/src/api/leastsquaresoptim.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
# LeastSquaresOptim.jl

This is a wrapper package for importing solvers from LeastSquaresOptim.jl into the SciML
This is a extension for importing solvers from LeastSquaresOptim.jl into the SciML
interface. Note that these solvers do not come by default, and thus one needs to install
the package before using these solvers:

```julia
using Pkg
Pkg.add("LeastSquaresOptim")
using LeastSquaresOptim
using LeastSquaresOptim, NonlinearSolve
```

These methods can be used independently of the rest of NonlinearSolve.jl

## Solver API

```@docs
12 changes: 5 additions & 7 deletions docs/src/api/minpack.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
# MINPACK.jl

This is a wrapper package for importing solvers from Sundials into the SciML interface.
Note that these solvers do not come by default, and thus one needs to install the package
before using these solvers:
This is a extension for importing solvers from MINPACK into the SciML interface. Note that
these solvers do not come by default, and thus one needs to install the package before using
these solvers:

```julia
using Pkg
Pkg.add("NonlinearSolveMINPACK")
using NonlinearSolveMINPACK
Pkg.add("MINPACK")
using MINPACK, NonlinearSolve
```

These methods can be used independently of the rest of NonlinearSolve.jl

## Solver API

```@docs
10 changes: 5 additions & 5 deletions docs/src/api/nlsolve.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# NLsolve.jl

This is a wrapper package for importing solvers from NLsolve.jl into the SciML interface.
Note that these solvers do not come by default, and thus one needs to install the package
before using these solvers:
This is a extension for importing solvers from NLsolve.jl into the SciML interface. Note
that these solvers do not come by default, and thus one needs to install the package before
using these solvers:

```julia
using Pkg
Pkg.add("SciMLNLSolve")
using SciMLNLSolve
Pkg.add("NLsolve")
using NLSolve, NonlinearSolve
```

## Solver API
17 changes: 17 additions & 0 deletions docs/src/solvers/NonlinearLeastSquaresSolvers.md
Original file line number Diff line number Diff line change
@@ -58,6 +58,23 @@ And the choices for `linsolve` are:
- `:cholesky`
- `:lsmr` a conjugate gradient method (LSMR with diagonal preconditioner).

### MINPACK.jl

MINPACK.jl methods are fine for medium-sized nonlinear solves. They are the FORTRAN
standard methods which are used in many places, such as SciPy. However, our benchmarks
demonstrate that these methods are not robust or stable. In addition, they are slower
than the standard methods and do not scale due to lack of sparse Jacobian support.
Thus they are only recommended for benchmarking and testing code conversions.

- `CMINPACK()`: A wrapper for using the classic MINPACK method through [MINPACK.jl](https://github.com/sglyon/MINPACK.jl)

Submethod choices for this algorithm include:

- `:hybr`: Modified version of Powell's algorithm.
- `:lm`: Levenberg-Marquardt.
- `:lmdif`: Advanced Levenberg-Marquardt
- `:hybrd`: Advanced modified version of Powell's algorithm

### Optimization.jl

`NonlinearLeastSquaresProblem`s can be converted into an `OptimizationProblem` and used
2 changes: 1 addition & 1 deletion docs/src/solvers/NonlinearSystemSolvers.md
Original file line number Diff line number Diff line change
@@ -110,7 +110,7 @@ computationally expensive than direct methods.
close to the steady state.
- `SSRootfind()`: Uses a NonlinearSolve compatible solver to find the steady state.

### SciMLNLSolve.jl
### NLsolve.jl

This is a wrapper package for importing solvers from NLsolve.jl into the SciML interface.

73 changes: 73 additions & 0 deletions ext/NonlinearSolveMINPACKExt.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
module NonlinearSolveMINPACKExt

using NonlinearSolve, SciMLBase
using MINPACK

function SciMLBase.__solve(prob::Union{NonlinearProblem{uType, iip},

Check warning on line 6 in ext/NonlinearSolveMINPACKExt.jl

Codecov / codecov/patch

ext/NonlinearSolveMINPACKExt.jl#L6

Added line #L6 was not covered by tests
NonlinearLeastSquaresProblem{uType, iip}}, alg::CMINPACK, args...;
abstol = 1e-6, maxiters = 100000, alias_u0::Bool = false,
kwargs...) where {uType, iip}
if prob.u0 isa Number
u0 = [prob.u0]

Check warning on line 11 in ext/NonlinearSolveMINPACKExt.jl

Codecov / codecov/patch

ext/NonlinearSolveMINPACKExt.jl#L10-L11

Added lines #L10 - L11 were not covered by tests
else
u0 = NonlinearSolve.__maybe_unaliased(prob.u0, alias_u0)

Check warning on line 13 in ext/NonlinearSolveMINPACKExt.jl

Codecov / codecov/patch

ext/NonlinearSolveMINPACKExt.jl#L13

Added line #L13 was not covered by tests
end

sizeu = size(prob.u0)
p = prob.p

Check warning on line 17 in ext/NonlinearSolveMINPACKExt.jl

Codecov / codecov/patch

ext/NonlinearSolveMINPACKExt.jl#L16-L17

Added lines #L16 - L17 were not covered by tests

# unwrapping alg params
show_trace = alg.show_trace
tracing = alg.tracing
io = alg.io

Check warning on line 22 in ext/NonlinearSolveMINPACKExt.jl

Codecov / codecov/patch

ext/NonlinearSolveMINPACKExt.jl#L20-L22

Added lines #L20 - L22 were not covered by tests

if !iip && prob.u0 isa Number
f! = (du, u) -> (du .= prob.f(first(u), p); Cint(0))
elseif !iip && prob.u0 isa Vector{Float64}
f! = (du, u) -> (du .= prob.f(u, p); Cint(0))
elseif !iip && prob.u0 isa AbstractArray
f! = (du, u) -> (du .= vec(prob.f(reshape(u, sizeu), p)); Cint(0))
elseif prob.u0 isa Vector{Float64}
f! = (du, u) -> prob.f(du, u, p)

Check warning on line 31 in ext/NonlinearSolveMINPACKExt.jl

Codecov / codecov/patch

ext/NonlinearSolveMINPACKExt.jl#L24-L31

Added lines #L24 - L31 were not covered by tests
else # Then it's an in-place function on an abstract array
f! = (du, u) -> (prob.f(reshape(du, sizeu), reshape(u, sizeu), p); du = vec(du); 0)

Check warning on line 33 in ext/NonlinearSolveMINPACKExt.jl

Codecov / codecov/patch

ext/NonlinearSolveMINPACKExt.jl#L33

Added line #L33 was not covered by tests
end

u = zero(u0)
resid = NonlinearSolve.evaluate_f(prob, u)
m = length(resid)

Check warning on line 38 in ext/NonlinearSolveMINPACKExt.jl

Codecov / codecov/patch

ext/NonlinearSolveMINPACKExt.jl#L36-L38

Added lines #L36 - L38 were not covered by tests

method = ifelse(alg.method === :auto,

Check warning on line 40 in ext/NonlinearSolveMINPACKExt.jl

Codecov / codecov/patch

ext/NonlinearSolveMINPACKExt.jl#L40

Added line #L40 was not covered by tests
ifelse(prob isa NonlinearLeastSquaresProblem, :lm, :hydr), alg.method)

if SciMLBase.has_jac(prob.f)
if !iip && prob.u0 isa Number
g! = (du, u) -> (du .= prob.f.jac(first(u), p); Cint(0))
elseif !iip && prob.u0 isa Vector{Float64}
g! = (du, u) -> (du .= prob.f.jac(u, p); Cint(0))
elseif !iip && prob.u0 isa AbstractArray
g! = (du, u) -> (du .= vec(prob.f.jac(reshape(u, sizeu), p)); Cint(0))
elseif prob.u0 isa Vector{Float64}
g! = (du, u) -> prob.f.jac(du, u, p)

Check warning on line 51 in ext/NonlinearSolveMINPACKExt.jl

Codecov / codecov/patch

ext/NonlinearSolveMINPACKExt.jl#L43-L51

Added lines #L43 - L51 were not covered by tests
else # Then it's an in-place function on an abstract array
g! = function (du, u)
prob.f.jac(reshape(du, sizeu), reshape(u, sizeu), p)
du = vec(du)
return CInt(0)

Check warning on line 56 in ext/NonlinearSolveMINPACKExt.jl

Codecov / codecov/patch

ext/NonlinearSolveMINPACKExt.jl#L53-L56

Added lines #L53 - L56 were not covered by tests
end
end
original = MINPACK.fsolve(f!, g!, u0, m; tol = abstol, show_trace, tracing, method,

Check warning on line 59 in ext/NonlinearSolveMINPACKExt.jl

Codecov / codecov/patch

ext/NonlinearSolveMINPACKExt.jl#L59

Added line #L59 was not covered by tests
iterations = maxiters, kwargs...)
else
original = MINPACK.fsolve(f!, u0, m; tol = abstol, show_trace, tracing, method,

Check warning on line 62 in ext/NonlinearSolveMINPACKExt.jl

Codecov / codecov/patch

ext/NonlinearSolveMINPACKExt.jl#L62

Added line #L62 was not covered by tests
iterations = maxiters, kwargs...)
end

u = reshape(original.x, size(u))
resid = original.f
retcode = original.converged ? ReturnCode.Success : ReturnCode.Failure

Check warning on line 68 in ext/NonlinearSolveMINPACKExt.jl

Codecov / codecov/patch

ext/NonlinearSolveMINPACKExt.jl#L66-L68

Added lines #L66 - L68 were not covered by tests

return SciMLBase.build_solution(prob, alg, u, resid; retcode, original)

Check warning on line 70 in ext/NonlinearSolveMINPACKExt.jl

Codecov / codecov/patch

ext/NonlinearSolveMINPACKExt.jl#L70

Added line #L70 was not covered by tests
end

end
3 changes: 3 additions & 0 deletions ext/NonlinearSolveNLsolveExt.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module NonlinearSolveNLsolveExt

end
2 changes: 1 addition & 1 deletion src/NonlinearSolve.jl
Original file line number Diff line number Diff line change
@@ -236,7 +236,7 @@ export RadiusUpdateSchemes

export NewtonRaphson, TrustRegion, LevenbergMarquardt, DFSane, GaussNewton, PseudoTransient,
Broyden, Klement, LimitedMemoryBroyden
export LeastSquaresOptimJL, FastLevenbergMarquardtJL
export LeastSquaresOptimJL, FastLevenbergMarquardtJL, CMINPACK, NLsolveJL
export NonlinearSolvePolyAlgorithm,
RobustMultiNewton, FastShortcutNonlinearPolyalg, FastShortcutNLLSPolyalg

32 changes: 11 additions & 21 deletions src/default.jl
Original file line number Diff line number Diff line change
@@ -243,32 +243,22 @@ function FastShortcutNonlinearPolyalg(; concrete_jac = nothing, linsolve = nothi
prefer_simplenonlinearsolve::Val{SA} = Val(false),
autodiff = nothing) where {JAC, SA}
if JAC
if SA
algs = (SimpleNewtonRaphson(;
autodiff = ifelse(autodiff === nothing, AutoForwardDiff(), autodiff)),
SimpleTrustRegion(;
autodiff = ifelse(autodiff === nothing, AutoForwardDiff(), autodiff)),
NewtonRaphson(; concrete_jac, linsolve, precs, linesearch = BackTracking(),
autodiff),
TrustRegion(; concrete_jac, linsolve, precs,
radius_update_scheme = RadiusUpdateSchemes.Bastin, autodiff))
else
algs = (NewtonRaphson(; concrete_jac, linsolve, precs, autodiff),
NewtonRaphson(; concrete_jac, linsolve, precs, linesearch = BackTracking(),
autodiff),
TrustRegion(; concrete_jac, linsolve, precs, autodiff),
TrustRegion(; concrete_jac, linsolve, precs,
radius_update_scheme = RadiusUpdateSchemes.Bastin, autodiff))
end
algs = (NewtonRaphson(; concrete_jac, linsolve, precs, autodiff),

Check warning on line 246 in src/default.jl

Codecov / codecov/patch

src/default.jl#L246

Added line #L246 was not covered by tests
NewtonRaphson(; concrete_jac, linsolve, precs, linesearch = BackTracking(),
autodiff),
TrustRegion(; concrete_jac, linsolve, precs, autodiff),
TrustRegion(; concrete_jac, linsolve, precs,
radius_update_scheme = RadiusUpdateSchemes.Bastin, autodiff))
else
# SimpleNewtonRaphson and SimpleTrustRegion are not robust to singular Jacobians
# and thus are not included in the polyalgorithm
if SA
algs = (SimpleBroyden(),

Check warning on line 256 in src/default.jl

Codecov / codecov/patch

src/default.jl#L255-L256

Added lines #L255 - L256 were not covered by tests
Broyden(; init_jacobian = Val(:true_jacobian)),
SimpleKlement(),
SimpleNewtonRaphson(;
autodiff = ifelse(autodiff === nothing, AutoForwardDiff(), autodiff)),
SimpleTrustRegion(;
autodiff = ifelse(autodiff === nothing, AutoForwardDiff(), autodiff)),
NewtonRaphson(; concrete_jac, linsolve, precs, autodiff),
NewtonRaphson(; concrete_jac, linsolve, precs, linesearch = BackTracking(),
autodiff),
NewtonRaphson(; concrete_jac, linsolve, precs, linesearch = BackTracking(),
autodiff),
TrustRegion(; concrete_jac, linsolve, precs,
Loading

0 comments on commit 6b58f42

Please sign in to comment.