Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Add Householder's method #163

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,14 @@ ChainRulesCore = "d360d2e6-b24c-11e9-a2a3-2a2ae2dbcce4"
ReverseDiff = "37e2e3b7-166d-5795-8a7a-e32c996b4267"
Tracker = "9f7883ad-71c0-57eb-9f7f-b5c9e6d3789c"
Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f"
TaylorDiff = "b36ab563-344f-407b-a36a-4f200bebf99c"

[extensions]
SimpleNonlinearSolveChainRulesCoreExt = "ChainRulesCore"
SimpleNonlinearSolveReverseDiffExt = "ReverseDiff"
SimpleNonlinearSolveTrackerExt = "Tracker"
SimpleNonlinearSolveZygoteExt = "Zygote"
SimpleNonlinearSolveTaylorDiffExt = "TaylorDiff"

[compat]
ADTypes = "1.9"
Expand Down
60 changes: 60 additions & 0 deletions ext/SimpleNonlinearSolveTaylorDiffExt.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
module SimpleNonlinearSolveTaylorDiffExt
using SimpleNonlinearSolve
using SimpleNonlinearSolve: ImmutableNonlinearProblem, ReturnCode, build_solution, check_termination, init_termination_cache
using SimpleNonlinearSolve: __maybe_unaliased, _get_fx, __fixed_parameter_function
using MaybeInplace: @bb
using SciMLBase: isinplace

import TaylorDiff

@inline function __get_higher_order_derivatives(::SimpleHouseholder{N}, prob, f, x, fx) where N
vN = Val(N)
l = map(one, x)
t = TaylorDiff.make_seed(x, l, vN)

if isinplace(prob)
bundle = similar(fx, TaylorDiff.TaylorScalar{eltype(fx), N})
f(bundle, t)
map!(TaylorDiff.primal, fx, bundle)
else
bundle = f(t)
fx = map(TaylorDiff.primal, bundle)
end
bundle = inv.(bundle)
num = TaylorDiff.extract_derivative(bundle, N - 1)
den = TaylorDiff.extract_derivative(bundle, N)
return num, den, fx
end

function SciMLBase.__solve(prob::ImmutableNonlinearProblem, alg::SimpleHouseholder{N},
args...; abstol = nothing, reltol = nothing, maxiters = 1000,
termination_condition = nothing, alias_u0 = false, kwargs...) where N
x = __maybe_unaliased(prob.u0, alias_u0)
length(x) == 1 ||
throw(ArgumentError("SimpleHouseholder only supports scalar problems"))
fx = _get_fx(prob, x)
@bb xo = copy(x)
f = __fixed_parameter_function(prob)

abstol, reltol, tc_cache = init_termination_cache(
prob, abstol, reltol, fx, x, termination_condition)

for i in 1:maxiters
num, den, fx = __get_higher_order_derivatives(alg, prob, f, x, fx)

if i == 1
iszero(fx) && build_solution(prob, alg, x, fx; retcode = ReturnCode.Success)
else
# Termination Checks
tc_sol = check_termination(tc_cache, fx, x, xo, prob, alg)
tc_sol !== nothing && return tc_sol
end

@bb copyto!(xo, x)
@bb x .+= (N - 1) .* num ./ den
end

return build_solution(prob, alg, x, fx; retcode = ReturnCode.MaxIters)
end

end
2 changes: 2 additions & 0 deletions src/SimpleNonlinearSolve.jl
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ include("nlsolve/lbroyden.jl")
include("nlsolve/klement.jl")
include("nlsolve/trustRegion.jl")
include("nlsolve/halley.jl")
include("nlsolve/householder.jl")
include("nlsolve/dfsane.jl")

## Interval Nonlinear Solvers
Expand Down Expand Up @@ -139,6 +140,7 @@ end
export AutoFiniteDiff, AutoForwardDiff, AutoPolyesterForwardDiff
export SimpleBroyden, SimpleDFSane, SimpleGaussNewton, SimpleHalley, SimpleKlement,
SimpleLimitedMemoryBroyden, SimpleNewtonRaphson, SimpleTrustRegion
export SimpleHouseholder
export Alefeld, Bisection, Brent, Falsi, ITP, Ridder

end # module
16 changes: 16 additions & 0 deletions src/nlsolve/householder.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"""
SimpleHouseholder{order}()

A low-overhead implementation of Householder's method to arbitrary order.
This method is non-allocating on scalar and static array problems.

!!! warning

Needs `TaylorDiff.jl` to be explicitly loaded before using this functionality.
Internally, this uses TaylorDiff.jl for automatic differentiation.

### Type Parameters

- `order`: the convergence order of the Householder method. `order = 2` is the same as Newton's method, `order = 3` is the same as Halley's method, etc.
"""
struct SimpleHouseholder{order} <: AbstractNewtonAlgorithm end
25 changes: 25 additions & 0 deletions test/core/rootfind_tests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,31 @@ end
end
end

@testitem "SimpleHouseholder" setup=[RootfindingTesting] tags=[:core] begin
using TaylorDiff
@testset "AutoDiff: TaylorDiff.jl" for order in (2, 3, 4)
@testset "[OOP] u0: $(nameof(typeof(u0)))" for u0 in (
[1.0], @SVector[1.0], 1.0)
sol = benchmark_nlsolve_oop(quadratic_f, u0; solver = SimpleHouseholder{order}())
@test SciMLBase.successful_retcode(sol)
@test all(abs.(sol.u .* sol.u .- 2) .< 1e-9)
end

@testset "[IIP] u0: $(nameof(typeof(u0)))" for u0 in ([1.0],)
sol = benchmark_nlsolve_iip(quadratic_f!, u0; solver = SimpleHouseholder{order}())
@test SciMLBase.successful_retcode(sol)
@test all(abs.(sol.u .* sol.u .- 2) .< 1e-9)
end
end

@testset "Termination condition: $(nameof(typeof(termination_condition))) u0: $(nameof(typeof(u0)))" for termination_condition in TERMINATION_CONDITIONS,
u0 in (1.0, [1.0], @SVector[1.0])

probN = NonlinearProblem(quadratic_f, u0, 2.0)
@test all(solve(probN, SimpleHouseholder{2}(); termination_condition).u .≈ sqrt(2.0))
end
end

@testitem "Derivative Free Metods" setup=[RootfindingTesting] tags=[:core] begin
@testset "$(nameof(typeof(alg)))" for alg in [
SimpleBroyden(), SimpleKlement(), SimpleDFSane(),
Expand Down
Loading