Skip to content

Commit 35a20ff

Browse files
committed
Remake Halley example
1 parent 998db88 commit 35a20ff

File tree

8 files changed

+137
-369
lines changed

8 files changed

+137
-369
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
<br />
1313
<a href="https://github.com/SciML/ColPrac"><img src="https://img.shields.io/badge/contributor's%20guide-ColPrac-blueviolet" alt="ColPrac: Contributor's Guide on Collaborative Practices for Community Packages" /></a>
1414
<a href="https://github.com/SciML/SciMLStyle"><img src="https://img.shields.io/badge/code%20style-SciML-blueviolet" alt="SciML Code Style" /></a>
15+
<a href="https://doi.org/10.5281/zenodo.14226430"><img src="https://zenodo.org/badge/563952901.svg" alt="DOI" /></a>
1516
</p>
1617

1718
<p align=center>

docs/Project.toml

+3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
[deps]
22
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
3+
ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210"
34
TaylorDiff = "b36ab563-344f-407b-a36a-4f200bebf99c"
5+
TaylorIntegration = "92b13dbe-c966-51a2-8445-caca9f8a7d42"
6+
TaylorSeries = "6aa5eb33-94cf-58f4-a9d0-e4b2c4fc25ea"

docs/make.jl

+5-1
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,13 @@ makedocs(;
1212
prettyurls = get(ENV, "CI", "false") == "true",
1313
canonical = "https://juliadiff.org/TaylorDiff.jl",
1414
edit_link = "main",
15-
assets = String[]),
15+
assets = String[]
16+
),
1617
pages = [
1718
"Home" => "index.md",
19+
"Examples" => [
20+
"Efficient Halley's method for nonlinear solving" => "examples/halley.md"
21+
],
1822
"Theory" => "theory.md",
1923
"API" => "api.md"
2024
])

docs/src/examples/halley.md

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# Efficient Halley's method for nonlinear solving
2+
3+
## Introduction
4+
5+
Say we have a system of $n$ equations with $n$ unknowns $f(x)=0$, and $f\in \mathbb R^n\to\mathbb R^n$ is sufficiently smooth.
6+
7+
Given a initial guess $x_0$, Newton's method finds a solution by iterating like
8+
9+
$$x_{i+1}=x_i-J(x_i)^{-1}f(x_i)$$
10+
11+
and this method converges quadratically.
12+
13+
We can make it converge faster using higher-order derivative information. For example, Halley's method iterates like
14+
15+
$$x_{i+1}=x_i-(a_i\odot a_i)\oslash(a_i-b_i/2)$$
16+
17+
where the vector multiplication and division $\odot,\oslash$ are defined element-wise, and term $a_i$ and $b_i$ are defined by $J(x_i)a_i = f(x_i)$ and $J(x_i)b_i = H(x_i)a_ia_i$.
18+
19+
Halley's method is proved to converge cubically, which is faster than Newton's method. Here, we demonstrate that with TaylorDiff.jl, you can compute the Hessian-vector-vector product $H(x_i)a_ia_i$ very efficiently, such that the Halley's method is almost as cheap as Newton's method per iteration.
20+
21+
## Implementation
22+
23+
We first define the two iteration schemes mentioned above:
24+
25+
```@example 1
26+
using TaylorDiff, LinearAlgebra
27+
import ForwardDiff
28+
29+
function newton(f, x, p; tol = 1e-12, maxiter = 100)
30+
fp = Base.Fix2(f, p)
31+
for i in 1:maxiter
32+
fx = fp(x)
33+
error = norm(fx)
34+
println("Iteration $i: x = $x, f(x) = $fx, error = $error")
35+
error < tol && return
36+
J = ForwardDiff.jacobian(fp, x)
37+
a = J \ fx
38+
@. x -= a
39+
end
40+
end
41+
42+
function halley(f, x, p; tol = 1e-12, maxiter = 100)
43+
fp = Base.Fix2(f, p)
44+
for i in 1:maxiter
45+
fx = f(x, p)
46+
error = norm(fx)
47+
println("Iteration $i: x = $x, f(x) = $fx, error = $error")
48+
error < tol && return
49+
J = ForwardDiff.jacobian(fp, x)
50+
a = J \ fx
51+
hvvp = derivative(fp, x, a, Val(2))
52+
b = J \ hvvp
53+
@. x -= (a * a) / (a - b / 2)
54+
end
55+
end
56+
```
57+
58+
Note that in Halley's method, the hessian-vector-vector product is computed with `derivative(fp, x, a, Val(2))`. It is guaranteed that asymptotically this is only taking 2x more time compared to evaluating `fp(x)` itself.
59+
60+
Now we define some test function:
61+
62+
```@example 1
63+
f(x, p) = x .* x - p
64+
```
65+
66+
The Newton's method takes 6 iterations to converge:
67+
68+
```@example 1
69+
newton(f, [1., 1.], [2., 2.])
70+
```
71+
72+
While the Halley's method takes 4 iterations to converge:
73+
74+
```@example 1
75+
halley(f, [1., 1.], [2., 2.])
76+
```

examples/halley.ipynb

-264
This file was deleted.

0 commit comments

Comments
 (0)