From f21d3e209c7e0e94627df02ce66482f268bf55f1 Mon Sep 17 00:00:00 2001 From: Qingyu Qu <52615090+ErikQQY@users.noreply.github.com> Date: Wed, 26 Apr 2023 10:01:33 +0800 Subject: [PATCH] Add noncommensurate lyapunov exponents (#66) * Add noncommensurate lyapunov exponents Signed-off-by: ErikQQY <2283984853@qq.com> * Fix comparing function Signed-off-by: ErikQQY <2283984853@qq.com> * Delete test file Signed-off-by: ErikQQY <2283984853@qq.com> * Fix CI failing Signed-off-by: ErikQQY <2283984853@qq.com> --------- Signed-off-by: ErikQQY <2283984853@qq.com> --- examples/RF.jl | 2 - .../lyapunov/rabinovich_fabrikant_lyapunov.jl | 30 +++++ src/lyapunov.jl | 118 +++++++++++++++++- test/FOLEtest.jl | 17 ++- 4 files changed, 162 insertions(+), 5 deletions(-) create mode 100644 examples/lyapunov/rabinovich_fabrikant_lyapunov.jl diff --git a/examples/RF.jl b/examples/RF.jl index 73fe610c..74f741c1 100644 --- a/examples/RF.jl +++ b/examples/RF.jl @@ -1,7 +1,5 @@ using FractionalDiffEq, Plots -plotlyjs() - function RF(du, u, t, p) du[1] = u[2]*(u[3]-1+u[1]*u[1])+0.1*u[1]; du[2] = u[1]*(3*u[3]+1-u[1]*u[1])+0.1*u[2]; diff --git a/examples/lyapunov/rabinovich_fabrikant_lyapunov.jl b/examples/lyapunov/rabinovich_fabrikant_lyapunov.jl new file mode 100644 index 00000000..cceb1f7e --- /dev/null +++ b/examples/lyapunov/rabinovich_fabrikant_lyapunov.jl @@ -0,0 +1,30 @@ +# Commensurate case + +using FractionalDiffEq, Plots + +function RF(du, u, t) + du[1] = u[2]*(u[3]-1+u[1]*u[1])+0.1*u[1] + du[2] = u[1]*(3*u[3]+1-u[1]*u[1])+0.1*u[2] + du[3] = -2*u[3]*(0.98+u[1]*u[2]) +end + +(LE, tspan)=FOLyapunov(RF, 0.999, 0, 0.02, 300, [0.1; 0.1; 0.1], 0.005, 1000) +plot(tspan, LE[1, :]) +plot!(tspan, LE[2, :]) +plot!(tspan, LE[3, :]) + + + +# Noncommensurate case + +using FractionalDiffEq, Plots + +function LE_RF_TEST(du, u, p, t) + du[1] = u[2]*(u[3]-1+u[1]^2) + 0.1*u[1] + du[2] = u[1]*(3*u[3]+1-u[1]^2) + 0.1*u[2] + du[3] = -2*u[3]*(0.98+u[1]*u[2]) +end +(LE, tspan) = FOLyapunov(LE_RF_TEST, [0.995, 0.992, 0.996], 0, 0.1, 1000, [1,1,1], 0.01, 1000) +plot(tspan, LE[1, :]) +plot!(tspan, LE[2, :]) +plot!(tspan, LE[3, :]) \ No newline at end of file diff --git a/src/lyapunov.jl b/src/lyapunov.jl index 4e3e1c69..8b5c02c3 100644 --- a/src/lyapunov.jl +++ b/src/lyapunov.jl @@ -14,8 +14,124 @@ Computing fractional order Lyapunov exponent of a fractionl order system. } ``` """ -function FOLyapunov(fun, order, t_start, h_norm, t_end, u0, h, out)# TODO: Generate the Lyapunov exponent plot +function FOLyapunov(fun, order, t_start, h_norm, t_end, u0, h, out) + if is_all_equal(order) + LE, tspan = commensurate_lyapunov(fun, order, t_start, h_norm, t_end, u0, h, out) + else + LE, tspan = noncommensurate_lyapunov(fun, order, t_start, h_norm, t_end, u0, h, out) + end + return LE, tspan +end + +@inline function is_all_equal(order::AbstractArray) + length(order) < 2 && return true + element1 = order[1] + i = 2 + @inbounds for i=2:length(order) + order[i] == element1 || return false + end + return true +end + +function noncommensurate_lyapunov(fun, order, t_start, h_norm, t_end, u0, h, out)# TODO: Generate the Lyapunov exponent plot + ne::Int = length(u0) # System dimension + + tspan = Float64[] + LE = Float64[] + + # Generate extend system with jacobian + function extend_fun(du, u, p, t) + current_du = zeros(ne) + fun(current_du, u[1:ne], p, t) + extend_du = jacobian_of_fdefun(fun, t, u[1:ne], p) + extend_du_mul_u = extend_du*reshape(u[ne+1:end], ne, ne) + du[:] = [current_du[:]; extend_du_mul_u[:]] + end + + x = zeros(Float64, ne*(ne+1)) + x0 = zeros(Float64, ne*(ne+1)) + c = zeros(Float64, ne) + gsc = zeros(Float64, ne) + zn = zeros(Float64, ne) + n_it = round(Int, (t_end-t_start)/h_norm) + x[1:ne] = u0 + q = repeat(order, ne+1, 1) # fractional order of the extend system + for i=1:ne + x[(ne+1)*i]=1.0 + end + t = t_start + LExp = zeros(ne) + for it=1:n_it + prob = FODESystem(extend_fun, q[:], x[:], (t, t+h_norm)) + sol = solve(prob, h, PECE()) + Y = sol.u + t = t+h_norm + Y = Y' + + x = Y[size(Y, 1), :] + for i=1:ne + for j=1:ne + x0[ne*i+j]=x[ne*j+i] + end + end + zn[1] = 0.0 + for j=1:ne + zn[1] = zn[1]+x0[ne*j+1]^2 + end + zn[1] = sqrt(zn[1]) + for j=1:ne + x0[ne*j+1] = x0[ne*j+1]/zn[1] + end + for j=2:ne + for k=1:(j-1) + gsc[k] = 0.0 + for l=1:ne + gsc[k] = gsc[k]+x0[ne*l+j]*x0[ne*l+k] + end + end + for k=1:ne + for l=1:j-1 + x0[ne*k+j]=x0[ne*k+j]-gsc[l]*x0[ne*k+l] + end + end + zn[j]=0.0 + for k=1:ne + zn[j]=zn[j]+x0[ne*k+j]^2 + end + zn[j]=sqrt(zn[j]) + for k=1:ne + x0[ne*k+j]=x0[ne*k+j]/zn[j] + end + end + for k=1:ne + c[k]=c[k]+log(zn[k]) + LExp[k]=c[k]/(t-t_start) + end + for i=1:ne + for j=1:ne + x[ne*j+i]=x0[ne*i+j] + end + end + x=transpose(x) + mod(it, out)==0 ? println(LExp) : nothing + LE = [LE; LExp] + tspan = [tspan; t] + end + LE = reshape(LE, ne, :) + return LE, tspan +end + +function jacobian_of_fdefun(f, t, y, p) + ForwardDiff.jacobian(y) do y + du = similar(y) + f(du, y, p, t) + du + end +end + +function commensurate_lyapunov(fun, order, t_start, h_norm, t_end, u0, h, out)# TODO: Generate the Lyapunov exponent plot ne::Int = length(u0) # System dimension + order = order[1] # Since this is the commensurate case, we only need one element in order array Jfdefun(t, u) = jacobian_of_fdefun(fun, t, u) diff --git a/test/FOLEtest.jl b/test/FOLEtest.jl index f73994f4..c54f5ac4 100644 --- a/test/FOLEtest.jl +++ b/test/FOLEtest.jl @@ -1,17 +1,30 @@ using FractionalDiffEq using Test -@testset "Test Lyapunov exponents" begin +@testset "Test Commensurate Lyapunov exponents" begin function RF(du, u, t) du[1] = u[2]*(u[3]-1+u[1]*u[1])+0.1*u[1] du[2] = u[1]*(3*u[3]+1-u[1]*u[1])+0.1*u[2] du[3] = -2*u[3]*(0.98+u[1]*u[2]) end - (LE, tspan)=FOLyapunov(RF, 0.999, 0, 0.02, 300, [0.1; 0.1; 0.1], 0.005, 1000) + (LE, tspan)=FOLyapunov(RF, [0.999, 0.999, 0.999], 0, 0.02, 300, [0.1; 0.1; 0.1], 0.005, 1000) # Test the latest computed(final) Lyapunov exponents @test isapprox(LE[end-2:end], [0.06111650166568285 0.0038981396237095034 -1.8324646820425692]; atol=1e-3) end + +@testset "Test Noncommensurate Lyapunov exponents" begin + function LE_RF_TEST(du, u, p, t) + du[1] = u[2]*(u[3]-1+u[1]^2) + 0.1*u[1] + du[2] = u[1]*(3*u[3]+1-u[1]^2) + 0.1*u[2] + du[3] = -2*u[3]*(0.98+u[1]*u[2]) + end + (LE, tspan) = FOLyapunov(LE_RF_TEST, [0.995, 0.992, 0.996], 0, 0.1, 1000, [1,1,1], 0.01, 1000) + + @test isapprox(LE[end-2:end], [-0.0033493403496077058 + -0.0050780674255360226 + -1.774132087623718]; atol=1e-3) +end \ No newline at end of file