feat: improve adapt_step function

main
Francesco Minnocci 1 year ago
parent 03cb1931ce
commit 92fd403ced
Signed by untrusted user: BachoSeven
GPG Key ID: 2BE4AB7FDAD828A4

@ -11,7 +11,7 @@ This is a project for the "Laboratorio Computazionale" exam at the University of
## TODO ## TODO
- Parallelization - Parallelization
- Projective coordinates (maybe) - Homogenization
## Example systems ## Example systems
@ -19,8 +19,8 @@ Here's some tests on 2x2 systems, with the plotted real approximate solutions
$$ $$
\begin{align*} \begin{align*}
x^2 + y^2 - 4 &= 0 \\ x^3 + 5x^2 - y - 10 &= 0 \\
xy - 1 &= 0 \\ 2x^2 - y - 10 &= 0 \\
\end{align*} \end{align*}
$$ $$
@ -32,8 +32,8 @@ $$
$$ $$
\begin{align*} \begin{align*}
x^2 + y^2 - 2 &= 0 \\ x^2 + 2y &= 0 \\
xy - 1 &= 0 \\ y - 3x^3 &= 0 \\
\end{align*} \end{align*}
$$ $$
@ -41,15 +41,26 @@ $$
|-------------------|---------------------------------| |-------------------|---------------------------------|
| ![Solution 2](plots/solutions2.png) | ![Multi-threaded Solution 2](plots/solutions2_8threads.png) | | ![Solution 2](plots/solutions2.png) | ![Multi-threaded Solution 2](plots/solutions2_8threads.png) |
$$
\begin{align*}
x^2 + y^2 - 4 &= 0 \\
xy - 1 &= 0 \\
\end{align*}
$$
| Single-threaded | Multi-threaded (nproc=8) |
|-------------------|---------------------------------|
| ![Solution 3](plots/solutions3.png) | ![Multi-threaded Solution 3](plots/solutions3_8threads.png) |
--- ---
$$ $$
\begin{align*} \begin{align*}
x^3 + 5x^2 - y - 10 &= 0 \\ x^2 + y^2 - 2 &= 0 \\
2x^2 - y - 10 &= 0 \\ xy - 1 &= 0 \\
\end{align*} \end{align*}
$$ $$
| Single-threaded | Multi-threaded (nproc=8) | | Single-threaded | Multi-threaded (nproc=8) |
|-------------------|---------------------------------| |-------------------|---------------------------------|
| ![Solution 3](plots/solutions3.png) | ![Multi-threaded Solution 3](plots/solutions3_8threads.png) | | ![Solution 4](plots/solutions4.png) | ![Multi-threaded Solution 4](plots/solutions4_8threads.png) |

@ -1,17 +1,18 @@
module AdaptStep module AdaptStep
using LinearAlgebra using LinearAlgebra
using TypedPolynomials
export adapt_step export adapt_step
# Adaptive step size # Adaptive step size
function adapt_step(x, x_old, step, m) function adapt_step(H, x, t, step, m)
Δ = LinearAlgebra.norm(x - x_old) Δ = LinearAlgebra.norm([h(variables(H(t))=>x) for h in H(t-step)])
if Δ > 0.1 if Δ > 1e-8
step = 0.5 * step step = 0.5 * step
m = 0 m = 0
else else
m+=1 m+=1
if (m == 5) if (m == 5) && (step < 0.05)
step = 2 * step step = 2 * step
m = 0 m = 0
end end

@ -16,14 +16,11 @@ module EulerNewton
xh = x + Δx * step_size xh = x + Δx * step_size
# Corrector step # Corrector step
JHh=differentiate(H(t+step_size), vars) JHh=differentiate(H(t-step_size), vars)
for _ in 1:10 for _ in 1:5
JH = [jh(vars=>xh) for jh in JHh] JH = [jh(vars=>xh) for jh in JHh]
Δx = JH \ -[h(vars=>xh) for h in H(t+step_size)] Δx = JH \ -[h(vars=>xh) for h in H(t-step_size)]
xh = xh + Δx xh = xh + Δx
if LinearAlgebra.norm([h(vars=>xh) for h in H(t+step_size)]) < 1e-8
break
end
end end
return xh return xh

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

@ -179,19 +179,23 @@ by the sequence of points $(z_i)_{i\in\N}$ defined by the recurrence relation
$$ z_{i+1}=z_i+h\cdot f(z_i,t_i) ,$$ $$ z_{i+1}=z_i+h\cdot f(z_i,t_i) ,$$
where $h$ is the step size. where $h$ is the step size.
In our case, we have $$f(z,t)=-\left(\frac{\partial H}{\partial z}(z,t)\right)^{-1}\frac{\partial H}{\partial t}(z,t)$$ and $t_0=1$, since we track from $1$ to $0$. For the same In our case, we have $$f(z,t)=-\left(\frac{\partial H}{\partial z}(z,t)\right)^{-1}\frac{\partial H}{\partial t}(z,t)$$ and $t_0=1$, since we track from $1$ to $0$. For the same
reason, we set $$t_i=t_{i-1}-h.$$ We will also use a variable step size, based on the output of each iteration. reason, we set $$t_{i+1}=t_i-h.$$
\subsubsection{Corrector: Newton's method} \subsubsection{Corrector: Newton's method}
Since we want to solve $$H(z,t)=0,$$ we can use Newton's method to improve the approximation $\widetilde{z_i}$ obtained by Euler's method to a solution of such equation. Since we want to solve $$H(z,t)=0,$$ we can use Newton's method to improve the approximation $\widetilde{z_i}$ obtained by Euler's method to a solution of such equation.
This is done by moving towards the root of the tangent line of $H$ at the current approximation, or in other words through the iteration This is done by moving towards the root of the tangent line of $H$ at the current approximation, or in other words through the iteration
$$ z_{i+1}=z_i-\left(\frac{\partial H}{\partial z}(z_i,t_i)\right)^{-1}H(z_i,t_i) ,$$ $$ z_{i+1}=z_i-\left(\frac{\partial H}{\partial z}(z_i,t_{i+1})\right)^{-1}H(z_i,t_{i+1}) ,$$
where this time $z_0=\widetilde{z}_i$ and $t_0=t_i$ as obtained in the Euler step. where this time $z_0=\widetilde{z}_i$, with $\widetilde{z}_i$ and $t_{i+1}$ obtained from the $i$-th Euler step.
Usually, only a few steps of Newton's method are needed; we will use a fixed maximum of $10$ steps, Usually, only a few steps of Newton's method are needed; we will use a fixed number of 5 iterations.
stopping the iterations when the desired accuracy is reached, for instance when the norm of $H(z_i,t_i)$ is less than $10^{-8}$.
At this point, we use the final value of the Newton iteration as the starting value for the next Euler step. At this point, we use the final value of the Newton iteration as the starting value for the next Euler step.
\subsubsection{Adaptive step size} \subsubsection{Adaptive step size}
In order to improve the efficiency of the algorithm, we will use an adaptive step size, which will be based on the norm of the residual of the Newton iteration.
If the desired accuracy is not reached, for instance when the norm of $H(z_i,t_i)$ is bigger than $10^{-8}$,
then we halve the step size; if instead we have 5 "successful" iterations in a row, we double the step size.
\section{Parallelization} \section{Parallelization}
\subsection{Multithreading}
\subsection{MPI}
\section{Implementation} \section{Implementation}
\subsection{Julia code} \subsection{Julia code}

@ -4,24 +4,25 @@ using TypedPolynomials
# Local dependencies # Local dependencies
include("start-system.jl") include("start-system.jl")
include("homotopy.jl") include("homotopy.jl")
include("homogenize.jl") # include("homogenize.jl")
include("euler-newton.jl") include("euler-newton.jl")
include("adapt-step.jl") include("adapt-step.jl")
include("plot.jl") include("plot.jl")
using .StartSystem using .StartSystem
using .Homotopy using .Homotopy
using .Homogenize # using .Homogenize
using .EulerNewton using .EulerNewton
using .AdaptStep using .AdaptStep
using .Plot using .Plot
# Main homotopy continuation loop # Main homotopy continuation loop
function solve(F, (G, roots) = start_system(F), maxsteps=10000) function solve(F, (G, roots) = start_system(F), maxsteps = 1000)
# F=homogenize(F) # F=homogenize(F)
H=homotopy(F,G) H=homotopy(F,G)
solutions = [] solutions = []
step_array = []
@time Threads.@threads for r in roots Threads.@threads for r in roots
t = 1.0 t = 1.0
step_size = 0.01 step_size = 0.01
x0 = r x0 = r
@ -29,30 +30,43 @@ function solve(F, (G, roots) = start_system(F), maxsteps=10000)
steps = 0 steps = 0
while t > 0 && steps < maxsteps while t > 0 && steps < maxsteps
x = en_step(H, x0, t, step_size) x0 = en_step(H, x0, t, step_size)
(m, step_size) = adapt_step(x, x0, step_size, m) (m, step_size) = adapt_step(H, x0, t, step_size, m)
x0 = x
t -= step_size t -= step_size
steps += 1 steps += 1
end end
push!(solutions, x0) push!(solutions, x0)
push!(step_array, steps)
end end
return solutions return (solutions, step_array)
end end
# Input polynomial system # Input polynomial system
@polyvar x y @polyvar x y
C = [x^3 - y + 5x^2 - 10, 2x^2 - y - 10]
Q = [x^2 + 2y, y - 3x^3]
F = [x*y - 1, x^2 + y^2 - 4] F = [x*y - 1, x^2 + y^2 - 4]
T = [x*y - 1, x^2 + y^2 - 2] T = [x*y - 1, x^2 + y^2 - 2]
C = [x^3 - y + 5x^2 - 10, 2x^2 - y - 10]
sF = filter(u -> imag(u[1]) < 0.1 && imag(u[2]) < 0.1, solve(F)) (sC, stepsC) = solve(C)
sT = filter(u -> imag(u[1]) < 0.1 && imag(u[2]) < 0.1, solve(T)) (sQ, stepsQ) = solve(Q)
sC = filter(u -> imag(u[1]) < 0.1 && imag(u[2]) < 0.1, solve(C)) (sF, stepsF) = solve(F)
(sT, stepsT) = solve(T)
println("C: ", stepsC)
println("Q: ", stepsQ)
println("F: ", stepsF)
println("T: ", stepsT)
sC = filter(u -> imag(u[1]) < 0.1 && imag(u[2]) < 0.1, sC)
sQ = filter(u -> imag(u[1]) < 0.1 && imag(u[2]) < 0.1, sQ)
sF = filter(u -> imag(u[1]) < 0.1 && imag(u[2]) < 0.1, sF)
sT = filter(u -> imag(u[1]) < 0.1 && imag(u[2]) < 0.1, sT)
# Plotting the system and the real solutions # Plotting the system and the real solutions
ENV["GKSwstype"]="nul" ENV["GKSwstype"]="nul"
plot_real(sF, F, 4, 4, "1") plot_real(sC, C, 6, 12, "1")
plot_real(sT, T, 4, 4, "2") plot_real(sQ, Q, 2, 2, "2")
plot_real(sC, C, 6, 12, "3") plot_real(sF, F, 4, 4, "3")
plot_real(sT, T, 4, 4, "4")

Loading…
Cancel
Save