Skip to content
This repository has been archived by the owner on Oct 31, 2024. It is now read-only.

Add Muller's method #139

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
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
3 changes: 2 additions & 1 deletion src/SimpleNonlinearSolve.jl
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ include("nlsolve/klement.jl")
include("nlsolve/trustRegion.jl")
include("nlsolve/halley.jl")
include("nlsolve/dfsane.jl")
include("nlsolve/muller.jl")

## Interval Nonlinear Solvers
include("bracketing/bisection.jl")
Expand Down Expand Up @@ -115,7 +116,7 @@ end
end

export SimpleBroyden, SimpleDFSane, SimpleGaussNewton, SimpleHalley, SimpleKlement,
SimpleLimitedMemoryBroyden, SimpleNewtonRaphson, SimpleTrustRegion
SimpleLimitedMemoryBroyden, SimpleNewtonRaphson, SimpleTrustRegion, Muller
export Alefeld, Bisection, Brent, Falsi, ITP, Ridder

end # module
48 changes: 48 additions & 0 deletions src/nlsolve/muller.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
"""
Muller()

Muller's method.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make the documentation a bit more detailed. References, restrictions like only scalars and such

"""
struct Muller <: AbstractSimpleNonlinearSolveAlgorithm end
fgittins marked this conversation as resolved.
Show resolved Hide resolved

function SciMLBase.solve(prob::NonlinearProblem, alg::Muller, args...;
abstol = nothing, maxiters = 1000, kwargs...)
@assert !isinplace(prob) "`Muller` only supports OOP problems."
xᵢ₋₂, xᵢ₋₁, xᵢ = prob.u0
@assert xᵢ₋₂ ≠ xᵢ₋₁ ≠ xᵢ ≠ xᵢ₋₂
avik-pal marked this conversation as resolved.
Show resolved Hide resolved
f = Base.Fix2(prob.f, prob.p)
fxᵢ₋₂, fxᵢ₋₁, fxᵢ = f(xᵢ₋₂), f(xᵢ₋₁), f(xᵢ)

abstol = __get_tolerance(nothing, abstol,
promote_type(eltype(fxᵢ₋₂), eltype(xᵢ₋₂)))

for _ ∈ 1:maxiters
q = (xᵢ - xᵢ₋₁)/(xᵢ₋₁ - xᵢ₋₂)
A = q*fxᵢ - q*(1 + q)*fxᵢ₋₁ + q^2*fxᵢ₋₂
B = (2*q + 1)*fxᵢ - (1 + q)^2*fxᵢ₋₁ + q^2*fxᵢ₋₂
C = (1 + q)*fxᵢ

denom₊ = B + √(B^2 - 4*A*C)
denom₋ = B - √(B^2 - 4*A*C)

if abs(denom₊) ≥ abs(denom₋)
xᵢ₊₁ = xᵢ - (xᵢ - xᵢ₋₁)*2*C/denom₊
else
xᵢ₊₁ = xᵢ - (xᵢ - xᵢ₋₁)*2*C/denom₋
end

fxᵢ₊₁ = f(xᵢ₊₁)

# Termination Check
if abstol ≥ abs(fxᵢ₊₁)
return build_solution(prob, alg, xᵢ₊₁, fxᵢ₊₁;
retcode = ReturnCode.Success)
fgittins marked this conversation as resolved.
Show resolved Hide resolved
end

xᵢ₋₂, xᵢ₋₁, xᵢ = xᵢ₋₁, xᵢ, xᵢ₊₁
fxᵢ₋₂, fxᵢ₋₁, fxᵢ = fxᵢ₋₁, fxᵢ, fxᵢ₊₁
end

return build_solution(prob, alg, xᵢ₊₁, fxᵢ₊₁;
retcode = ReturnCode.MaxIters)
end
56 changes: 56 additions & 0 deletions test/core/muller_tests.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
@testitem "Muller" begin
@testset "Quadratic function" begin
f(u, p) = u^2 - p

u0 = (10, 20, 30)
p = 612
prob = NonlinearProblem{false}(f, u0, p)
sol = solve(prob, Muller())

@test sol.u ≈ √612

u0 = (-10, -20, -30)
prob = NonlinearProblem{false}(f, u0, p)
sol = solve(prob, Muller())

@test sol.u ≈ -√612
end

@testset "Sine function" begin
f(u, p) = sin(u)

u0 = (1, 2, 3)
prob = NonlinearProblem{false}(f, u0)
sol = solve(prob, Muller())

@test sol.u ≈ π

u0 = (2, 4, 6)
prob = NonlinearProblem{false}(f, u0)
sol = solve(prob, Muller())

@test sol.u ≈ 2*π
end

@testset "Exponential-sine function" begin
f(u, p) = exp(-u)*sin(u)

u0 = (-2, -3, -4)
prob = NonlinearProblem{false}(f, u0)
sol = solve(prob, Muller())

@test sol.u ≈ -π

u0 = (-1, 0, 1/2)
prob = NonlinearProblem{false}(f, u0)
sol = solve(prob, Muller())

@test sol.u ≈ 0

u0 = (-1, 0, 1)
prob = NonlinearProblem{false}(f, u0)
sol = solve(prob, Muller())

@test sol.u ≈ π
end
end