Skip to content

Commit 87702fe

Browse files
committed
Add Halley and Householder to SimpleNonlinearSolve
1 parent 1e29383 commit 87702fe

5 files changed

Lines changed: 97 additions & 1 deletion

File tree

lib/SimpleNonlinearSolve/Project.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ StaticArraysCore = "1e83bf80-4336-4d27-bf5d-d5a4f845583c"
2626
[weakdeps]
2727
ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
2828
ReverseDiff = "37e2e3b7-166d-5795-8a7a-e32c996b4267"
29+
TaylorDiff = "b36ab563-344f-407b-a36a-4f200bebf99c"
2930
Tracker = "9f7883ad-71c0-57eb-9f7f-b5c9e6d3789c"
3031

3132
[sources.BracketingNonlinearSolve]
@@ -37,6 +38,7 @@ path = "../NonlinearSolveBase"
3738
[extensions]
3839
SimpleNonlinearSolveChainRulesCoreExt = "ChainRulesCore"
3940
SimpleNonlinearSolveReverseDiffExt = "ReverseDiff"
41+
SimpleNonlinearSolveTaylorDiffExt = "TaylorDiff"
4042
SimpleNonlinearSolveTrackerExt = "Tracker"
4143

4244
[compat]
@@ -69,6 +71,7 @@ SciMLBase = "2.153, 3"
6971
Setfield = "1.1.1"
7072
StaticArrays = "1.9"
7173
StaticArraysCore = "1.4.3"
74+
TaylorDiff = "0.3"
7275
Test = "1.10"
7376
TestItemRunner = "1"
7477
Tracker = "0.2.35"
@@ -86,6 +89,7 @@ PolyesterForwardDiff = "98d1487c-24ca-40b6-b7ab-df2af84e126b"
8689
Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
8790
ReverseDiff = "37e2e3b7-166d-5795-8a7a-e32c996b4267"
8891
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
92+
TaylorDiff = "b36ab563-344f-407b-a36a-4f200bebf99c"
8993
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
9094
TestItemRunner = "f8b46487-2199-4994-9208-9a1283c18c0a"
9195
Tracker = "9f7883ad-71c0-57eb-9f7f-b5c9e6d3789c"
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
module SimpleNonlinearSolveTaylorDiffExt
2+
using SimpleNonlinearSolve: SimpleNonlinearSolve, SimpleHouseholder, Utils
3+
using NonlinearSolveBase: NonlinearSolveBase, ImmutableNonlinearProblem,
4+
AbstractNonlinearSolveAlgorithm
5+
using MaybeInplace: @bb
6+
using FastClosures: @closure
7+
import SciMLBase
8+
import TaylorDiff
9+
10+
SimpleNonlinearSolve.is_extension_loaded(::Val{:TaylorDiff}) = true
11+
12+
const NLBUtils = NonlinearSolveBase.Utils
13+
14+
@inline function __get_higher_order_derivatives(
15+
::SimpleHouseholder{N}, prob, x, fx) where {N}
16+
vN = Val(N)
17+
l = map(one, x)
18+
t = TaylorDiff.make_seed(x, l, vN)
19+
20+
if SciMLBase.isinplace(prob)
21+
bundle = similar(fx, TaylorDiff.TaylorScalar{eltype(fx), N})
22+
prob.f(bundle, t, prob.p)
23+
map!(TaylorDiff.value, fx, bundle)
24+
else
25+
bundle = prob.f(t, prob.p)
26+
fx = map(TaylorDiff.value, bundle)
27+
end
28+
invbundle = inv.(bundle)
29+
num = N == 1 ? map(TaylorDiff.value, invbundle) :
30+
TaylorDiff.extract_derivative(invbundle, Val(N - 1))
31+
den = TaylorDiff.extract_derivative(invbundle, vN)
32+
return num, den, fx
33+
end
34+
35+
function SciMLBase.__solve(prob::ImmutableNonlinearProblem, alg::SimpleHouseholder{N},
36+
args...; abstol = nothing, reltol = nothing, maxiters = 1000,
37+
termination_condition = nothing, alias_u0 = false, kwargs...) where {N}
38+
length(prob.u0) == 1 ||
39+
throw(ArgumentError("SimpleHouseholder only supports scalar problems"))
40+
x = NLBUtils.maybe_unaliased(prob.u0, alias_u0)
41+
fx = NLBUtils.evaluate_f(prob, x)
42+
43+
iszero(fx) &&
44+
return SciMLBase.build_solution(prob, alg, x, fx; retcode = ReturnCode.Success)
45+
46+
abstol, reltol, tc_cache = NonlinearSolveBase.init_termination_cache(
47+
prob, abstol, reltol, fx, x, termination_condition, Val(:simple))
48+
49+
@bb xo = similar(x)
50+
51+
for i in 1:maxiters
52+
@bb copyto!(xo, x)
53+
num, den, fx = __get_higher_order_derivatives(alg, prob, x, fx)
54+
@bb x .+= N .* num ./ den
55+
solved, retcode, fx_sol, x_sol = Utils.check_termination(tc_cache, fx, x, xo, prob)
56+
solved && return SciMLBase.build_solution(prob, alg, x_sol, fx_sol; retcode)
57+
end
58+
59+
return SciMLBase.build_solution(prob, alg, x, fx; retcode = ReturnCode.MaxIters)
60+
end
61+
62+
function SimpleNonlinearSolve.evaluate_hvvp_internal(
63+
hvvp, prob::ImmutableNonlinearProblem, u, a)
64+
if SciMLBase.isinplace(prob)
65+
binary_f = @closure (y, x) -> prob.f(y, x, prob.p)
66+
TaylorDiff.derivative!(hvvp, binary_f, cache.fu, u, a, Val(2))
67+
else
68+
unary_f = Base.Fix2(prob.f, prob.p)
69+
hvvp = TaylorDiff.derivative(unary_f, u, a, Val(2))
70+
end
71+
hvvp
72+
end
73+
74+
end

lib/SimpleNonlinearSolve/src/SimpleNonlinearSolve.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ include("utils.jl")
4949
include("broyden.jl")
5050
include("dfsane.jl")
5151
include("halley.jl")
52+
include("householder.jl")
5253
include("klement.jl")
5354
include("lbroyden.jl")
5455
include("raphson.jl")
@@ -165,7 +166,7 @@ end
165166
export SimpleBroyden, SimpleKlement, SimpleLimitedMemoryBroyden
166167
export SimpleDFSane
167168
export SimpleGaussNewton, SimpleNewtonRaphson, SimpleTrustRegion
168-
export SimpleHalley
169+
export SimpleHalley, SimpleHouseholder
169170

170171
export solve
171172

lib/SimpleNonlinearSolve/src/halley.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ A low-overhead implementation of Halley's Method.
1515
- `autodiff`: determines the backend used for the Jacobian. Defaults to `nothing` (i.e.
1616
automatic backend selection). Valid choices include jacobian backends from
1717
`DifferentiationInterface.jl`.
18+
In addition, `AutoTaylorDiff` can be used to enable Taylor mode for computing the Hessian-vector-vector product more efficiently; in this case, the Jacobian would still be calculated using the default backend. You need to have `TaylorDiff.jl` loaded to use this option.
1819
"""
1920
@kwdef @concrete struct SimpleHalley <: AbstractSimpleNonlinearSolveAlgorithm
2021
autodiff = nothing
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
"""
2+
SimpleHouseholder{order}()
3+
4+
A low-overhead implementation of Householder's method to arbitrary order.
5+
This method is non-allocating on scalar and static array problems.
6+
7+
!!! warning
8+
9+
Needs `TaylorDiff.jl` to be explicitly loaded before using this functionality.
10+
Internally, this uses TaylorDiff.jl for automatic differentiation.
11+
12+
### Type Parameters
13+
14+
- `order`: the order of the Householder method. `order = 1` is the same as Newton's method, `order = 2` is the same as Halley's method, etc.
15+
"""
16+
struct SimpleHouseholder{order} <: AbstractSimpleNonlinearSolveAlgorithm end

0 commit comments

Comments
 (0)