Parameter continuation for the cubic root
In this example, we prove the existence of a one-parameter family of solutions to
\[0 = f(u, \lambda) \bydef u^3 - \lambda - 2, \qquad \lambda \in [-1, 1].\]
Step 1: Problem definition
The map $f$ and its derivative $D_u f$ are implemented as follows:
f(u, λ) = u^3 - λ - exact(2)
Duf(u, λ) = exact(3) * u^2Consider the fixed-point operator $T : \mathbb{R} \times [-1,1] \to \mathbb{R}$ given by
\[T(u, \lambda) \bydef u - A(\lambda) f(u, \lambda),\]
where $A(\lambda) : \mathbb{R} \to \mathbb{R}$ is an injective operator corresponding to a numerical approximation of $D_u f(\bar{u}(\lambda), \lambda)^{-1}$, for some approximate zero $\bar{u}(\lambda) \in \mathbb{R}$ of $f$, for all $\lambda \in [-1, 1]$.
Step 2: Approximate zero (floating-point arithmetic)
We use the numerical continuation method to retrieve a numerical approximation of the curve.
We construct a grid of parameters and iterate Newton's method for each step, using the previous approximate zero as the predictor of the solution at the next step.
using RadiiPolynomial
K = 10
K_fft = fft_size(Chebyshev(K))
npts = K_fft ÷ 2 + 1
λ_grid = [-cospi(2j/K_fft) for j = 0:npts-1]
u_grid = Vector{Float64}(undef, npts)
# initialize
u_init = 1.0
u_init, success_newton = newton(u -> (f(u, λ_grid[1]), Duf(u, λ_grid[1])), u_init)
u_grid[1] = u_init
# run continuation scheme
for j = 2:npts
w = u_grid[j-1] # predictor
u_bar, success_newton_j = newton(u -> (f(u, λ_grid[j]), Duf(u, λ_grid[j])), w; verbose = true)
success_newton_j || error()
u_grid[j] = u_bar
end
# construct the approximation
u_fft = [reverse(u_grid) ; u_grid[begin+1:end-1]]
u_cheb = real(to_seq(u_fft, Chebyshev(K)))Sequence in Chebyshev(10) with coefficients Vector{Float64}:
1.2410369149251503
0.10907140054331423
-0.009688555942083859
0.0014382541523247298
-0.0002564899825927712
5.0342871589922137e-5
-1.0483288779396366e-5
2.2725722957282205e-6
-5.072065108469026e-7
1.1572783048626124e-7
-2.6866343460769933e-8Step 3: Approximate inverse (floating-point arithmetic)
We construct the approximate inverse $A(\lambda) \approx D_u f(\bar{u}(\lambda), \lambda)^{-1}$ across the continuation branch using standard floating-point arithmetic.
A_grid = inv.(Duf.(u_grid, λ_grid))
A_fft = [reverse(A_grid) ; A_grid[begin+1:end-1]]
A_cheb = real(to_seq(A_fft, Chebyshev(K)))Sequence in Chebyshev(10) with coefficients Vector{Float64}:
0.22730980307522403
-0.040940634508741705
0.009167001988608968
-0.002186410740412038
0.0005374770746072676
-0.00013449087973091016
3.404835870885278e-5
-8.691414303604028e-6
2.2323466863233277e-6
-5.761101173660076e-7
1.4924567912798963e-7Step 4: Bounds estimation (interval arithmetic)
To apply the Radii Polynomial Theorem, we need to theoretically derive and rigorously evaluate the bounds $Y, Z_1, Z_2$. The computer-assisted proof is completed by evaluating these bounds with interval arithmetic:
λ_cheb_interval = interval(Sequence(Chebyshev(1), [0, 0.5]))
u_cheb_interval = interval(u_cheb)
A_cheb_interval = interval(A_cheb)
#- Y bound
Y = norm(A_cheb_interval * f(u_cheb_interval, λ_cheb_interval), 1)
#- Z₁ bound
Z₁ = norm(exact(1) - A_cheb_interval * Duf(u_cheb_interval, λ_cheb_interval), 1)
#- Z₂ bound
R = 10 * sup(Y)
Z₂ = exact(3) * norm(A_cheb_interval, 1) * (norm(u_cheb_interval, 1) + exact(2 * R))
# verify the contraction
ie, contraction_success = interval_of_existence(Y, Z₁, Z₂, R; verbose = true)┌ Info: success: interval found
│ Y = [1.66179e-8, 1.66179e-8]_com
│ Z₁ = [4.19304e-7, 4.19304e-7]_com
│ Z₂ = [1.48207, 1.48207]_com
│ R = 1.6617944662661552e-7
│ Δ = [0.999999, 0.999999]_com
└ roots = ([1.66179e-8, 1.6618e-8]_com, [1.34946, 1.34946]_com)inf(ie) # smallest error1.6617954922205423e-8The following figure[1] shows the numerical approximation of the proven branch of the cubic root.
using GLMakie
fig = Figure()
ax = Axis(fig[1,1], xticks = -3:3)
lines!(ax, [Point2f(λ, cbrt(λ + 2)) for λ = LinRange(-3, 2, 501)];
color = :black, label = L"(λ+2)^{1/3}")
lines!(ax, [Point2f(λ, u_cheb(λ)) for λ = LinRange(-1, 1, 501)];
color = :blue, label = L"\bar{u}(λ)")
scatter!(ax, [Point2f(λ_grid[j], u_grid[j]) for j = 1:npts];
color = :red)
axislegend(ax; position = :lt)
fig- 1S. Danisch and J. Krumbiegel, Makie.jl: Flexible high-performance data visualization for Julia, Journal of Open Source Software, 6 (2021), 3349.