Skip to content

Commit ad57000

Browse files
Add SciPy wrapper documentation and fix doc build
1 parent 5317b49 commit ad57000

File tree

5 files changed

+99
-3
lines changed

5 files changed

+99
-3
lines changed

docs/make.jl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
using Documenter, DocumenterCitations, DocumenterInterLinks
22
import DiffEqBase
3+
import Pkg
4+
5+
# Make sure the local solver sub-package is available inside the docs environment
6+
Pkg.develop(path = joinpath(@__DIR__, "..", "lib", "NonlinearSolveSciPy"))
37

48
using Sundials
59
using NonlinearSolveBase, SciMLBase, DiffEqBase
610
using SimpleNonlinearSolve, BracketingNonlinearSolve
711
using NonlinearSolveFirstOrder, NonlinearSolveQuasiNewton, NonlinearSolveSpectralMethods
812
using NonlinearSolveHomotopyContinuation
13+
using NonlinearSolveSciPy
914
using SciMLJacobianOperators
1015
using NonlinearSolve, SteadyStateDiffEq
1116

@@ -37,6 +42,7 @@ makedocs(;
3742
SimpleNonlinearSolve, BracketingNonlinearSolve,
3843
NonlinearSolveFirstOrder, NonlinearSolveQuasiNewton, NonlinearSolveSpectralMethods,
3944
NonlinearSolveHomotopyContinuation,
45+
NonlinearSolveSciPy,
4046
Sundials,
4147
SciMLJacobianOperators,
4248
NonlinearSolve, SteadyStateDiffEq

docs/pages.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ pages = [
4848
"api/nlsolve.md",
4949
"api/nlsolvers.md",
5050
"api/petsc.md",
51+
"api/scipy.md",
5152
"api/siamfanlequations.md",
5253
"api/speedmapping.md",
5354
"api/sundials.md",

docs/src/api/scipy.md

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# SciPy Wrappers
2+
3+
NonlinearSolve provides thin wrappers around selected algorithms from the
4+
[SciPy](https://scipy.org/) Python library via
5+
[`PythonCall.jl`](https://github.com/cjdoris/PythonCall.jl). They allow you to
6+
call the original `scipy.optimize` routines while keeping the standard
7+
`SciMLBase`‐style problem / solution interface.
8+
9+
!!! note "Python dependency"
10+
These algorithms require a working Python installation with the `scipy`
11+
package available. When the wrapper is first used, `PythonCall` will
12+
automatically create a private Conda environment and install SciPy via
13+
`CondaPkg`. No manual setup is necessary on typical CI or end‐user
14+
systems.
15+
16+
## Algorithms
17+
18+
| Julia type | SciPy function | Problem type |
19+
|--------------------------------|------------------------------------|--------------|
20+
| `SciPyLeastSquares` (default) | `scipy.optimize.least_squares` | nonlinear least-squares |
21+
| `SciPyLeastSquaresTRF` | `scipy.optimize.least_squares` with `method="trf"` | nonlinear least-squares |
22+
| `SciPyRoot` | `scipy.optimize.root` | vector root-finding |
23+
| `SciPyRootScalar` | `scipy.optimize.root_scalar` | scalar bracketing root |
24+
25+
!!! warning "Single-process restriction"
26+
SciPy itself is written in C/Fortran and **is not thread-safe across
27+
multiple embedded Python interpreters**. For that reason the
28+
`NonlinearSolveSciPy` test suite runs single-process; you should avoid
29+
launching many Julia processes that each call SciPy in parallel.
30+
31+
## Basic usage
32+
33+
```julia
34+
using NonlinearSolve, NonlinearSolveSciPy
35+
36+
# --- nonlinear least-squares ---------------------------------------------
37+
38+
xdata = 0:0.1:1
39+
ydata = 2 .* xdata .+ 1 # exact line, no noise
40+
41+
residuals(p, _) = ydata .- (p[1] .* xdata .+ p[2])
42+
prob = NonlinearLeastSquaresProblem(residuals, [1.0, 0.0])
43+
44+
sol = solve(prob, SciPyLeastSquares()) # defaults to method="trf"
45+
```
46+
47+
```julia
48+
# --- vector root-finding --------------------------------------------------
49+
50+
f(u, p) = [2 - 2u[1]; u[1] - 4u[2]]
51+
prob_vec = NonlinearProblem(f, zeros(2))
52+
sol_vec = solve(prob_vec, SciPyRoot())
53+
```
54+
55+
```julia
56+
# --- scalar bracketing root ----------------------------------------------
57+
58+
g(x, p) = x^2 - 2
59+
prob_scalar = IntervalNonlinearProblem(g, (1.0, 2.0))
60+
sol_scalar = solve(prob_scalar, SciPyRootScalar())
61+
```
62+
63+
All three calls return a standard `SciMLBase.NonlinearSolution` with the usual
64+
`u`, `resid`, `retcode`, etc. If SciPy raises an error the wrapper translates
65+
it to an appropriate `ReturnCode` and propagates the original Python message
66+
through `solution.message`.
67+
68+
## Keyword options
69+
70+
The constructors forward most keywords verbatim to the underlying SciPy
71+
functions. Refer to the [SciPy documentation](https://docs.scipy.org/doc/) for
72+
exhaustive lists.
73+
74+
Examples:
75+
76+
```julia
77+
# switch least-squares loss function
78+
solve(prob, SciPyLeastSquares(loss="soft_l1"))
79+
80+
# change the scalar root solver method
81+
solve(prob_scalar, SciPyRootScalar(method="brentq"))
82+
```
83+
84+
## Implementation notes
85+
86+
The wrapper lives in the standalone sub-package `NonlinearSolveSciPy` rather
87+
than as a conditional extension. This lets its code be developed and tested
88+
independently while still integrating smoothly with the main
89+
`NonlinearSolve.jl` umbrella package.

docs/src/solvers/nonlinear_least_squares_solvers.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ Submethod choices for this algorithm include:
8484
A wrapper over `scipy.optimize.least_squares`. Requires that the Python
8585
package `scipy` is available to PythonCall.
8686

87-
- [`SciPyLeastSquares()`](@ref) with convenience constructors
87+
- [SciPyLeastSquares](../api/scipy.md#algorithms) (wrapper around `scipy.optimize.least_squares`) with convenience constructors
8888
`SciPyLeastSquaresTRF()`, `SciPyLeastSquaresDogbox()`, and
8989
`SciPyLeastSquaresLM()` for the common method choices.
9090

docs/src/solvers/nonlinear_system_solvers.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,5 +194,5 @@ These wrappers let you use the algorithms from
194194
without leaving Julia. SciPy is loaded lazily through PythonCall, so these
195195
methods are available whenever the `scipy` Python package can be imported.
196196

197-
- [`SciPyRoot()`](@ref): wrapper for `scipy.optimize.root` (vector problems)
198-
- [`SciPyRootScalar()`](@ref): wrapper for `scipy.optimize.root_scalar` (scalar/bracketed problems)
197+
- [SciPyRoot](../api/scipy.md#algorithms): wrapper for `scipy.optimize.root` (vector problems)
198+
- [SciPyRootScalar](../api/scipy.md#algorithms): wrapper for `scipy.optimize.root_scalar` (scalar/bracketed problems)

0 commit comments

Comments
 (0)