Chaos Detection
Being able to detect and distinguish chaotic from regular behavior is crucial in the study of dynamical systems. Most of the time a positive maximum lyapunov
exponent and a bounded system indicate chaos.
However, the convergence of the Lyapunov exponent is often very slow and the computation costly. There are many alternatives that are both more efficient and more accurate in characterizing chaotic and regular motion, some of which are included in DynamicalSystems.jl.
Generalized Alignment Index
"GALI" for sort, is a method that relies on the fact that initially orthogonal deviation vectors tend to align towards the direction of the maximum Lyapunov exponent for chaotic motion. It is one of the most recent and cheapest methods for distinguishing chaos, introduced first in 2007 by Skokos, Bountis & Antonopoulos.
#ChaosTools.gali
— Function.
gali(ds::DynamicalSystem, k::Int, tmax [, ws]; kwargs...) -> GALI_k, t
Compute \text{GALI}_k [1] for a given k
up to time tmax
. Return \text{GALI}_k(t) and time vector t.
ws
is an optional argument containing the deviation vectors w_i for i \in [1,k], expected either as a matrix with each column a deviation vector, or as a vector of vectors. If not given, random orthonormal vectors are chosen.
Keyword Arguments
threshold
: IfGALI_k
falls below thethreshold
iteration is terminated. Default value is1e-12
.dt=1.0
: Time step between variational vector normalizations for continuous systems.diff_eq_kwargs
: Seetrajectory
.
Description
The Generalized Alignment Index, \text{GALI}_k, is an efficient (and very fast) indicator of chaotic or regular behavior type in D-dimensional Hamiltonian systems (D is number of variables). The assymptotic behavior of \text{GALI}_k(t) depends critically of the type of orbit resulting from the initial condition ds.state
. If it is a chaotic orbit, then
with \lambda_1 being the maximum lyapunov
exponent. If on the other hand the orbit is regular, corresponding to movement in d-dimensional torus with 1 \le d \le D/2 then it holds
Traditionally, if \text{GALI}_k(t) does not become less than the threshold
until tmax
the given orbit is said to be chaotic, otherwise it is regular.
The entirety of our implementation is not based on the original paper, but rather in the method described in [2], which uses the product of the singular values of A, a matrix that has as columns the deviation vectors.
Performance Notes
If you want to do repeated evaluations of gali
for many initial conditions and for continuous systems, you can take advantage of the function:
gali(integrator, k, W, tmax, dt, threshold)
in conjuction with reinit!(integrator, W)
for various W=cat(2, state, ws)
. See the source code on how to set-up the integrator
and W
for the first time.
References
[1] : Skokos, C. H. et al., Physica D 231, pp 30–54 (2007)
[2] : Skokos, C. H. et al., Chaos Detection and Predictability - Chapter 5 (section 5.3.1 and ref. [85] therein), Lecture Notes in Physics 915, Springer (2016)
Discrete Example
We will use 3 coupled standard maps as an example for a discrete system:
using DynamicalSystems using PyPlot; figure() M = 3; ks = 3ones(M); Γ = 0.1; stable = [π, π, π, 0.01, 0, 0] .+ 0.1 chaotic = rand(2M) ds = Systems.coupledstandardmaps(M, stable; ks=ks, Γ = Γ) tr = trajectory(ds, 100000) subplot(2,2,1) plot(tr[:,1], tr[:,1+M], alpha = 0.5, label="stable",marker="o", ms=1, linewidth=0) legend() # subplot(2,2,2) for k in [2,3,4, 5, 6] g, t = gali(ds, k, 1e5; threshold=1e-12) lt = log10.(t); lg = log10.(g) plot(lt, lg, label="GALI_$(k)") end lt = 2:0.5:5.5 plot(lt, zeros(lt), label="const") plot(lt, -2(lt - 3), label="slope -2") plot(lt, -4(lt - 3), label="slope -4") plot(lt, -6(lt - 3), label="slope -6") xlim(2, 5.5) ylim(-12, 1) legend(fontsize=12) tight_layout() ds = Systems.coupledstandardmaps(M, chaotic; ks=ks, Γ = Γ) tr = trajectory(ds, 100000) subplot(2,2,3) plot(tr[:,1], tr[:,1+M], alpha = 0.5, label="chaotic",marker="o", ms=1, linewidth=0) legend() subplot(2,2,4) ls = lyapunovs(ds, 100000) for k in [2,3,4,5 ,6] ex = sum(ls[1] - ls[j] for j in 2:k) g, t = gali(ds, k, 1000) semilogy(t, exp.(-ex.*t), label="exp. k=$k") semilogy(t, g, label="GALI_$(k)") end legend(fontsize=12) xlim(0,50) ylim(1e-12, 1)
Continuous Example
As an example of a continuous system, let's see the henonhelies
:
using DynamicalSystems using PyPlot figure(figsize=(10, 12)) sp = [0, .295456, .407308431, 0] #stable periodic orbit: 1D torus qp = [0, .483000, .278980390, 0] #quasiperiodic orbit: 2D torus ch = [0, -0.25, 0.42081, 0] # chaotic orbit dt = 1.0 subplot(3,2,1) ds = Systems.henonhelies(sp) diffeq = Dict(:abstol=>1e-9, :reltol=>1e-9, :solver => Tsit5()) tr = trajectory(ds, 10000.0, dt=dt, diff_eq_kwargs = diffeq) plot(tr[:,1], tr[:,3], alpha = 0.5, label="sp",marker="o",markersize=2, linewidth=0) legend() subplot(3,2,2) for k in [2,3,4] g, t = gali(ds, k, 50000.0; dt = dt, diff_eq_kwargs = diffeq) if k < 4 loglog(t, 1./t.^(k-1), label="slope -$(k-1)") else loglog(t, 1./t.^(2k-4), label="slope -$(2k-4)") end loglog(t, g, label="GALI_$(k)") end legend(fontsize=12) subplot(3,2,3) ds = Systems.henonhelies(qp) diffeq = Dict(:abstol=>1e-9, :reltol=>1e-9, :solver => Tsit5()) tr = trajectory(ds, 10000.0, dt=dt, diff_eq_kwargs = diffeq) plot(tr[:,1], tr[:,3], alpha = 0.5, label="qp",marker="o",markersize=2, linewidth=0) legend() subplot(3,2,4) for k in [2,3,4] g, t = gali(ds, k, 10000.0; dt = dt, diff_eq_kwargs = diffeq) loglog(t, 1./t.^(2k-4), label="slope -$(2k-4)") loglog(t, g, label="GALI_$(k)") end legend(fontsize=12) tight_layout() ds = Systems.henonhelies(ch) diffeq = Dict(:abstol=>1e-6, :reltol=>1e-6, :solver => Tsit5()) tr = trajectory(ds, 50000.0, dt=dt, diff_eq_kwargs = diffeq) subplot(3,2,5) plot(tr[:,1], tr[:,3], alpha = 0.5, label="ch",marker="o",markersize=2, linewidth=0) legend() subplot(3,2,6) ls = lyapunovs(ds, 5000.0, dt=dt) for k in [2,3,4] ex = sum(ls[1] - ls[j] for j in 2:k) g, t = gali(ds, k, 1000; dt = dt) semilogy(t, exp.(-ex.*t), label="exp. k=$k") semilogy(t, g, label="GALI_$(k)") end legend(fontsize=12) tight_layout()
As you can see, the results of both discrete and continuous match very well the theory described in
gali
.
Using GALI
No-one in their right mind would try to fit power-laws in order to distinguish between chaotic and regular behavior, like the above examples. These were just demonstrations.
The most common usage of \text{GALI}_k is to define a (sufficiently) small amount of time and a (sufficiently) small threshold and see whether \text{GALI}_k stays below it, for a (sufficiently) big k.
For example one could do
using DynamicalSystems using PyPlot chaoticness(ds) = gali(ds, 2, 500.0)[2][end] function main(k) dens = 201 chaoticity = zeros(dens,dens) θs = ps = linspace(0, 2π, dens+1) ds = Systems.standardmap(k = k) for (i, θ) ∈ enumerate(θs[1:dens]) for (j, p) ∈ enumerate(ps[1:dens]) ds.state = SVector{2}(θ, p) chaoticity[i, j] = chaoticness(ds) end end pcolormesh(θs .- (θs[2] - θs[1])/2, ps .- (ps[2] - ps[1])/2, chaoticity') colorbar() end main(0.9)
and after about two minutes you will get: