Skip to content

Commit f476632

Browse files
authored
Merge pull request #2 from Mohit-coder-droid/main
Adding Julia and PyTorch Scripts
2 parents 1bb0f4a + cd802e7 commit f476632

File tree

18 files changed

+13784
-0
lines changed

18 files changed

+13784
-0
lines changed

Autoencoder Neural Networks/PyTorch Code/Gissinger_conj.ipynb

+720
Large diffs are not rendered by default.

Autoencoder Neural Networks/PyTorch Code/Global_Linearization.ipynb

+723
Large diffs are not rendered by default.

Autoencoder Neural Networks/PyTorch Code/NormalForm_pd.ipynb

+5,423
Large diffs are not rendered by default.

Autoencoder Neural Networks/PyTorch Code/NormalForm_sn.ipynb

+1,339
Large diffs are not rendered by default.

Autoencoder Neural Networks/PyTorch Code/Rossler_conj.ipynb

+948
Large diffs are not rendered by default.

Autoencoder Neural Networks/PyTorch Code/Tent2Logistic.ipynb

+1,108
Large diffs are not rendered by default.

Autoencoder Neural Networks/PyTorch Code/Tent2Sine.ipynb

+451
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
# -------------------------------------------------------------------------
2+
# Identifying Lyapunov Functions from Data with EDMD
3+
#
4+
# The goal of this script is to use EDMD and semidefinite programming to
5+
# identify a Lyapunov function for the planar discrete-time system
6+
# x1 --> 0.3*x1 ,
7+
# x2 --> -x1 + 0.5*x2 + (7/18)*x1^2,
8+
# using only data gathered from the system.
9+
#
10+
# To run this notebook one requires paths to the freely available software
11+
# package MOSEK, which can be downloaded at:
12+
# https://www.mosek.com/downloads/
13+
#
14+
# This script accompanies Section 4.3 of Data-Driven Methods for
15+
# Dynamic Systems.
16+
#
17+
# This script was adapted from the MATLAB version by Jason J. Bramburger
18+
#
19+
# Author: Mohit Sahu
20+
# -------------------------------------------------------------------------
21+
22+
23+
using DynamicPolynomials, SumOfSquares, MosekTools, LinearAlgebra
24+
include("utils.jl")
25+
26+
# Method parameters
27+
# Dpₘₐₓ = max degree of Dp dictionary of obserables
28+
# Dqₘₐₓ = max degree of Dq dictionary of obserables
29+
# ϵ = hyperparameter specific to Lyapunov function for sharp bounds
30+
# cleanVal = remove coefficients smaller than this value from Lyap function
31+
32+
Dpₘₐₓ = 4;
33+
Dqₘₐₓ = Dpₘₐₓ + 2;
34+
ϵ = 1;
35+
cleanVal = 1e-4;
36+
37+
# Generate Synthetic Data
38+
# Number of data points
39+
N = 100;
40+
41+
# Random points in [-2,2]x[-2,2]
42+
xdat = 2 .*rand(N,2) .- 1;
43+
ydat = zeros(N,2);
44+
45+
# Images of random points under map dynamics
46+
ydat[:,1] = 0.3*xdat[:,1];
47+
ydat[:,2] = -xdat[:,1] + 0.5*xdat[:,2] + (7/18)*xdat[:,1].^2;
48+
49+
# Create Q matrix
50+
pow = monpowers(2, Dqₘₐₓ)
51+
ell = size(pow)[1] # number of nontrivial monomials in Q
52+
Q = zeros(ell, N)
53+
for i = 1:ell
54+
zx = xdat.^permutedims(pow[i]);
55+
Q[i,:] = prod(zx,dims=2);
56+
end
57+
58+
# Create P matrix
59+
pow = monpowers(2, Dpₘₐₓ)
60+
ell = size(pow)[1] # number of nontrivial monomials in P
61+
P = zeros(ell, N)
62+
for i = 1:ell
63+
zy = ydat.^permutedims(pow[i]);
64+
P[i,:] = prod(zy,dims=2);
65+
end
66+
67+
# Create Koopman and Lie derivative matrix approximations
68+
# Koopman approximations
69+
K = P * pinv(Q)
70+
71+
# Symbolic variables
72+
@polyvar x[1:2] # 2d state variables
73+
74+
z = monomials(x, 0:Dpₘₐₓ) # monomials that make up span(Dp)
75+
w = monomials(x, 0:Dqₘₐₓ) # monomials that make up span(Dq)
76+
77+
model = SOSModel(Mosek.Optimizer)
78+
79+
@variable(model, c[1:length(z)]) # coeffs to build Lyapunov function in span(Dp)
80+
81+
# As julia doesn't handle L1 norm, so t here is a dummy variable to solve this problem
82+
# See Tutorials/Linear programs/Tips and Tricks of Jump.jl documentation to know more about this
83+
@variable(model, t)
84+
85+
# Lie approximation
86+
# ---> Lyapunov function = c.'*z in span(Dp)
87+
L = c'*(K*w) - c'*z;
88+
89+
# Identify Lyapunov function with SOS programming
90+
# Inequality constraints posed relaxed to SOS conditions
91+
@constraints(model, begin
92+
c'*z - ϵ*dot(x,x) in SOSCone()
93+
-L - ϵ*dot(x, x) in SOSCone()
94+
[t; c] in MOI.NormOneCone(1+length(c)) # Minimizing L1 Norm of c
95+
end)
96+
97+
# Objective function
98+
@objective(model, Min, t)
99+
100+
# Solve SOS problem
101+
optimize!(model)
102+
103+
# Remove coefficients smaller than cleanVal
104+
c = [abs(c_)>cleanVal ? c_ : zero(c_) for c_ in value.(c)]
105+
106+
# Check identified Lyapunov function is a real Lyapunov function
107+
# This time we maximize ϵ and check if it is positive
108+
model = SOSModel(Mosek.Optimizer)
109+
@variable(model, ϵ) # ϵ is now a variable to be maximized
110+
111+
# Discovered Lyapunov function
112+
v = c'*z
113+
114+
# Reverse the order of x₁ and x₂ to match the theory, as julia create polynomials in lexical order, so it's necessary to do to get to right answer
115+
v = subs(v, x[1]=>x[2], x[2]=>x[1])
116+
117+
# True RHS of map
118+
f = [0.3*x[1]; -x[1] + 0.5*x[2] + (7/18)*x[1]^2]
119+
120+
# True Lie Derivative
121+
Lie_exact = subs(v, x=>f)
122+
123+
# Find Lyapunov function
124+
@constraints(model, begin
125+
(v - ϵ * dot(x,x)) in SOSCone()
126+
(-(Lie_exact - v) - ϵ*dot(x,x)) in SOSCone()
127+
end)
128+
129+
@objective(model, Max, ϵ)
130+
optimize!(model)
131+
solution_summary(model)
132+
println("Maximized value of ϵ is $(value(ϵ))")
133+
134+
if value(ϵ) > 0
135+
println("We have discovered a true Lyapunov function from the data! \n")
136+
else
137+
println("Something went wrong - we cannot verify that this is a Lyapunov function. \n")
138+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
# -------------------------------------------------------------------------
2+
# Identifying Lyapunov Functions with Semidefinite Programming
3+
#
4+
# The goal of this script is to use semidefinite programming to identify a
5+
# Lyapunov function for the planar Moore-Greitzer system
6+
# x1' = -x2 - 1.5x1^2 - 0.5x1^3,
7+
# x2' = 3x1 - x2.
8+
# The script expands the unknown Lyapunov function as a polynomial up to a
9+
# given degree and tunes the coefficients in order to satisfy both of the
10+
# constraints:
11+
# V - x1^2 - x2^2 is SOS
12+
# -LV - x1^2 - x1^2 is SOS
13+
# where LV is the Lie derivative associated to the Moore-Greitzer system.
14+
#
15+
# To run this notebook one requires paths to the freely available software
16+
# package MOSEK, which can be downloaded at:
17+
# https://www.mosek.com/downloads/
18+
#
19+
# This script accompanies Section 4.2 of Data-Driven Methods for
20+
# Dynamic Systems.
21+
#
22+
# This script was adapted from the MATLAB version by Jason J. Bramburger
23+
#
24+
# Author: Mohit Sahu
25+
# -------------------------------------------------------------------------
26+
27+
28+
using DynamicPolynomials, SumOfSquares
29+
using MosekTools
30+
using CSDP
31+
32+
@polyvar x[1:2]
33+
34+
f = [-x[2] - 1.5*x[1]^2 - 0.5*x[1]^3;
35+
3*x[1] - x[2]]
36+
37+
# solver = optimizer_with_attributes(CSDP.Optimizer, MOI.Silent() => true)
38+
model = Model(Mosek.Optimizer)
39+
V_basis = monomials(x, 0:6) # monomials for polynomial V
40+
@variable(model, c[1:length(V_basis)])
41+
42+
# As julia doesn't handle L1 norm, so t here is a dummy variable to solve this problem
43+
# See Tutorials/Linear programs/Tips and Tricks of Jump.jl documentation to know more about this
44+
@variable(model, t)
45+
46+
V = c'*V_basis
47+
48+
using LinearAlgebra
49+
Dv = differentiate(V, x)
50+
Lie = dot(Dv, f)
51+
52+
# Add SOS constraints
53+
@constraints(model, begin
54+
V .- sum(x.^2) in SOSCone()
55+
-Lie - sum(x.^2) in SOSCone()
56+
[t; c] in MOI.NormOneCone(1+length(c)) # L1 Norm
57+
end)
58+
59+
@objective(model, Min, t)
60+
optimize!(model)
61+
62+
# Check if a solution was found
63+
if termination_status(model) == MOI.OPTIMAL
64+
println("Lyapunov function identified!")
65+
V_sol = value(V)
66+
threshold = 1e-1
67+
filtered_coeffs = [abs(c) > threshold ? c : zero(c) for c in coefficients(V_sol)]
68+
println("Filtered V(x1, x2) = ", sum(filtered_coeffs .* monomials(V_sol)))
69+
else
70+
println("Sorry, unable to identify a Lyapunov function")
71+
end
72+
73+
# Plot the Lyapunov function
74+
using Plots
75+
plotlyjs()
76+
N = 1000;
77+
x1_range = LinRange(-5, 5, N)
78+
79+
x = x1_range' .* ones(length(x1_range))
80+
y = ones(length(x1_range))' .* x1_range
81+
V_discovered = value.(c)'*V_basis;
82+
83+
plot(x, y, V_discovered.(x,y), st=:surface)
84+
xlabel!("x1")
85+
ylabel!("x2")
86+
zlabel!("V(x1, x2)")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# -------------------------------------------------------------------------
2+
# Plotting upper and lower bounds on heteroclinic existence
3+
#
4+
# This script plots the upper and lower bounds over a range of the
5+
# hyperparameter lambda for the existence of heteroclinic orbit. Data is
6+
# loaded in from the .mat files heteroclinic_lambda_ + 'upper' or 'lower' for
7+
# upper or lower bounds + 'm2' or 'm3' for m = 2 or 3, respectively. Each
8+
# file containts the lambda values, the value of m for reference, and
9+
# arrays c2, c3, c4, c5 representing the values of upper or lower bounds
10+
# on mu for degree 2,3,4, or 5 auxiliary functions, respectively.
11+
#
12+
# This script accompanies Section 4.2 of Data-Driven Methods for
13+
# Dynamic Systems.
14+
#
15+
# This script was adapted from the MATLAB version by Jason J. Bramburger
16+
#
17+
# Author: Mohit Sahu
18+
# -------------------------------------------------------------------------
19+
20+
21+
using MAT, Plots, Parameters
22+
23+
# Upper Bound Data
24+
# m = 2 data
25+
file_path = "DataDrivenDynSyst/data_driven_poly_optimiazation/"
26+
vars = matread("$(file_path)heteroclinic_lambda_upper_m2.mat")
27+
@unpack c2, c3, c4, c5, lambda, m = vars
28+
vars2 = matread("$(file_path)heteroclinic_lambda_upper_m2_part2.mat")
29+
@unpack c3_2, c4_2, c5_2, lambda_2, m = vars2
30+
31+
# m = 3 data
32+
# vars = matread("$(file_path)heteroclinic_lambda_upper_m3.mat")
33+
# @unpack c2, c3, c4, c5, lambda, m = vars
34+
# vars2 = matread("$(file_path)heteroclinic_lambda_upper_m3_part2.mat")
35+
# @unpack c2_2,c3_2, c4_2, c5_2, lambda_2, m = vars2
36+
37+
# Unpack data and aggregate
38+
λ = [lambda lambda_2]
39+
c3 = [c3 c3_2]
40+
c4 = [c4 c4_2]
41+
c5 = [c5[:,1:181] c5_2]
42+
43+
# Move failures off the figure
44+
if m == 2
45+
c2 = [c2 2*ones(1,length(lambda_2))];
46+
c2[1:46] .= 2;
47+
c2[174:end] .= 2;
48+
c3[260:end] .= 2;
49+
else
50+
c2 = [c2 c2_2];
51+
end
52+
53+
# Plot Upper bounds
54+
figure1 = plot()
55+
56+
plot!(λ[1:3:end], c2[1:3:end], c=RGB(1, 69/255, 79/255), lw=4, label="c2")
57+
plot!(λ[1:3:end], c3[1:3:end], ls=:dash, c=RGB(36/255, 122/255, 254/255), lw=4, label="c3")
58+
plot!(λ[1:3:end], c4[1:3:end], ls=:dot, c=RGB(0, 168/255, 0), lw=4, label="c4")
59+
plot!(λ[1:3:end], c5[1:3:end], ls=:dashdot, c=RGB(255/255, 66/255, 161/255), lw=4, label="c5")
60+
61+
display(figure1)
62+
63+
# Load Lower bound data
64+
if m == 2
65+
vars = matread("$(file_path)heteroclinic_lambda_lower_m2.mat")
66+
@unpack c3, c4, c5, lambda, m = vars
67+
elseif m == 3
68+
vars = matread("$(file_path)heteroclinic_lambda_lower_m3.mat")
69+
@unpack c3, c4, c5, lambda, m = vars
70+
end
71+
72+
# Plot Lower Bounds
73+
figure2 = plot()
74+
if m == 2
75+
plot!(lambda[7:37], c3[7:37], ls=:dash, c=RGB(36/255, 122/255, 254/255), lw=4, label="c3")
76+
plot!(lambda[7:37], c4[7:37], ls=:dashdot, c=RGB(0, 168/255, 0), lw=4, label="c4")
77+
plot!(lambda[7:2:39], c5[7:2:39], ls=:dot, c=RGB(255/255, 66/255, 161/255), lw=4, label="c5")
78+
xlims!(0, lambda[37])
79+
ylims!(0.5, 1)
80+
yticks!(0.5:0.1:1)
81+
elseif m == 3
82+
plot!(lambda[7:end], c3[7:end], ls=:dash, c=RGB(36/255, 122/255, 254/255), lw=4, label="c3")
83+
plot!(lambda[7:end], c4[7:end], ls=:dashdot, c=RGB(0, 168/255, 0), lw=4, label="c4")
84+
plot!(lambda[7:2:end], c5[7:2:end], ls=:dot, c=RGB(255/255, 66/255, 161/255), lw=4, label="c5")
85+
xlims!(0, lambda[37])
86+
ylims!(0.30, 0.7)
87+
yticks!(0.3:0.1:0.765)
88+
end
89+
90+
xlabel!("λ", fontsize=24, fontweight=:bold)
91+
ylabel!("μ", fontsize=24, fontweight=:bold)
92+
93+
display(figure2)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
using DynamicPolynomials, SumOfSquares, MosekTools
2+
include("utils.jl")
3+
4+
# ODE mu parameter
5+
m = 2
6+
7+
# Bounding method parameters
8+
degV = 20 # Degree of auxiliary function
9+
λ = 10^3
10+
11+
# Bisection Method for Finding Upper Bound
12+
function volume(μ, m, d, λ)
13+
@polyvar u v
14+
15+
ϵ = 1e-4;
16+
17+
model = SOSModel(Mosek.Optimizer)
18+
set_silent(model)
19+
20+
#Auxiliary function
21+
@variable(model, V, createPoly([u,v], d))
22+
23+
# S procedure
24+
d2 = d + m
25+
@variables(model, begin
26+
s1, createPoly([u,v], d2)
27+
s2 ,createPoly([u,v], d2)
28+
s3 , createPoly(u, d2)
29+
end)
30+
31+
# Derivatives
32+
dVdu = differentiate(V, u)
33+
dVdv = differentiate(V, v)
34+
35+
# Replacements
36+
Vv0 = subs(V, v=>0)
37+
38+
@constraints(model, begin
39+
subs(V,u=>0, v=>-ϵ) == 0
40+
subs(V,u=>1,v=>0) == 0
41+
λ*(dVdu*v - μ*dVdv*v - dVdv*(1-u)*u^m) -V -u*(1-u)*s1 + v*s2 in SOSCone()
42+
-Vv0 -ϵ*(1-u) -u*(1-u)*s3 in SOSCone()
43+
s1 in SOSCone()
44+
s2 in SOSCone()
45+
s3 in SOSCone()
46+
end)
47+
48+
optimize!(model)
49+
50+
# Return whether we are able to solve the problem or not
51+
return primal_status(model)
52+
end
53+
54+
#Bisection method
55+
μ_left = 0
56+
μ_right = 2
57+
μ_mid = 0
58+
59+
while abs((μ_right - μ_left)) >= 1e-5
60+
μ_mid = 0.5 * (μ_left + μ_right)
61+
flag = volume(μ_mid, m, degV, λ)
62+
63+
if flag==FEASIBLE_POINT
64+
μ_left = μ_mid
65+
else
66+
μ_right = μ_mid
67+
end
68+
end
69+
70+
println("The lower bound on the minimum speed for m = $m is $μ_mid found using degree $degV polynomials.\n")

0 commit comments

Comments
 (0)