Skip to content

Commit 75bef75

Browse files
Merge pull request #74 from DaniGlez/main
Backport ITP bugfixes from DiffEqBase in high precision contexts
2 parents 2c9323b + fbd4f68 commit 75bef75

File tree

2 files changed

+23
-18
lines changed

2 files changed

+23
-18
lines changed

lib/SimpleNonlinearSolve/src/itp.jl

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,9 @@ function SciMLBase.solve(prob::IntervalNonlinearProblem, alg::ITP,
7878
k1 = alg.k1
7979
k2 = alg.k2
8080
n0 = alg.n0
81-
n_h = ceil(log2((right - left) / (2 * ϵ)))
81+
n_h = ceil(log2(abs(right - left) / (2 * ϵ)))
8282
mid = (left + right) / 2
83-
x_f = (fr * left - fl * right) / (fr - fl)
83+
x_f = left + (right - left) * (fl/(fl - fr))
8484
xt = left
8585
xp = left
8686
r = zero(left) #minmax radius
@@ -89,12 +89,12 @@ function SciMLBase.solve(prob::IntervalNonlinearProblem, alg::ITP,
8989
ϵ_s = ϵ * 2^(n_h + n0)
9090
i = 0 #iteration
9191
while i <= maxiters
92-
#mid = (left + right) / 2
93-
r = ϵ_s - ((right - left) / 2)
94-
δ = k1 * ((right - left)^k2)
92+
span = abs(right - left)
93+
r = ϵ_s - (span / 2)
94+
δ = k1 * (span^k2)
9595

9696
## Interpolation step ##
97-
x_f = (fr * left - fl * right) / (fr - fl)
97+
x_f = left + (right - left) * (fl/(fl - fr))
9898

9999
## Truncation step ##
100100
σ = sign(mid - x_f)
@@ -112,6 +112,9 @@ function SciMLBase.solve(prob::IntervalNonlinearProblem, alg::ITP,
112112
end
113113

114114
## Update ##
115+
tmin, tmax = minmax(left, right)
116+
xp >= tmax && (xp = prevfloat(tmax))
117+
xp <= tmin && (xp = nextfloat(tmin))
115118
yp = f(xp)
116119
yps = yp * sign(fr)
117120
if yps > 0
@@ -121,16 +124,17 @@ function SciMLBase.solve(prob::IntervalNonlinearProblem, alg::ITP,
121124
left = xp
122125
fl = yp
123126
else
124-
left = xp
125-
right = xp
127+
return SciMLBase.build_solution(prob, alg, xp, yps;
128+
retcode = ReturnCode.Success, left = xp,
129+
right = xp)
126130
end
127131
i += 1
128132
mid = (left + right) / 2
129133
ϵ_s /= 2
130134

131-
if (right - left < 2 * ϵ)
132-
return SciMLBase.build_solution(prob, alg, mid, f(mid);
133-
retcode = ReturnCode.Success, left = left,
135+
if nextfloat_tdir(left, prob.tspan...) == right
136+
return SciMLBase.build_solution(prob, alg, left, fl;
137+
retcode = ReturnCode.FloatingPointLimit, left = left,
134138
right = right)
135139
end
136140
end

lib/SimpleNonlinearSolve/test/basictests.jl

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -540,18 +540,19 @@ for alg in (SimpleNewtonRaphson(), SimpleTrustRegion())
540540
@test abs.(sol.u) sqrt.(p)
541541
end
542542

543-
# Flipped signs test
543+
# Flipped signs & reversed tspan test for bracketing algorithms
544544
f1(u, p) = u * u - p
545545
f2(u, p) = p - u * u
546546

547-
for Alg in (Alefeld, Bisection, Falsi, Brent, ITP, Ridder)
548-
alg = Alg()
547+
for alg in (Alefeld(), Bisection(), Falsi(), Brent(), ITP(), Ridder())
549548
for p in 1:4
550549
inp1 = IntervalNonlinearProblem(f1, (1.0, 2.0), p)
551550
inp2 = IntervalNonlinearProblem(f2, (1.0, 2.0), p)
552-
sol = solve(inp1, alg)
553-
@test abs.(sol.u) sqrt.(p)
554-
sol = solve(inp2, alg)
555-
@test abs.(sol.u) sqrt.(p)
551+
inp3 = IntervalNonlinearProblem(f1, (2.0, 1.0), p)
552+
inp4 = IntervalNonlinearProblem(f2, (2.0, 1.0), p)
553+
@test abs.(solve(inp1, alg).u) sqrt.(p)
554+
@test abs.(solve(inp2, alg).u) sqrt.(p)
555+
@test abs.(solve(inp3, alg).u) sqrt.(p)
556+
@test abs.(solve(inp4, alg).u) sqrt.(p)
556557
end
557558
end

0 commit comments

Comments
 (0)