Skip to content

Commit c827e9d

Browse files
authored
Add example: Stabilization of nl systems (#177)
* Add example: Stabilization of nl systems * Fixes
1 parent b6e750f commit c827e9d

7 files changed

+115
-21
lines changed

docs/Project.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
[deps]
22
CSDP = "0a46da34-8e4b-519e-b418-48813639ff34"
33
Cyclotomics = "da8f5974-afbb-4dc8-91d8-516d5257c83b"
4-
DynamicPolynomials = "7c1d4256-1411-5781-91ec-d7bc3513ac07"
4+
DifferentialEquations = "0c46a032-eb83-5123-abaf-570d42b7fbaa"
55
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
6+
DynamicPolynomials = "7c1d4256-1411-5781-91ec-d7bc3513ac07"
67
Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306"
78
MultivariateBases = "be282fd4-ad43-11e9-1d11-8bd9d7e43378"
89
MultivariatePolynomials = "102ac46a-7ee4-5c85-9060-abc95bfdeaa3"
910
MutableArithmetics = "d8a4904e-b15c-11e9-3269-09a3773c0cb0"
1011
PermutationGroups = "8bc5a954-2dfc-11e9-10e6-cd969bffa420"
12+
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
1113
SumOfSquares = "4b9e565b-77fc-50a5-a571-1244f986bda1"

docs/make.jl

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,9 @@ using Documenter, Literate
44
const EXAMPLES_DIR = joinpath(@__DIR__, "..", "examples")
55
const OUTPUT_DIR = joinpath(@__DIR__, "src/generated")
66

7-
const EXAMPLES = [
8-
"sos_decomposition.jl",
9-
"Bound on Global Extremum.jl",
10-
"Lyapunov Function Search.jl",
11-
"Sum-of-Squares Matrices.jl",
12-
"Noncommutative variables.jl",
13-
"Sums of Hermitian squares.jl",
14-
"Symmetry reduction.jl",
15-
]
7+
include(joinpath(EXAMPLES_DIR, "all_examples.jl"))
8+
deleteat!(EXAMPLES, findfirst(isequal("chordal_sparsity.jl"), EXAMPLES))
9+
deleteat!(EXAMPLES, findfirst(isequal("chordal_sparsity_with_domain.jl"), EXAMPLES))
1610

1711
for example in EXAMPLES
1812
example_filepath = joinpath(EXAMPLES_DIR, example)
@@ -32,15 +26,11 @@ makedocs(
3226
"Sum-of-Squares Programming" => "sumofsquares.md",
3327
"Variables" => "variables.md",
3428
"Constraints" => "constraints.md",
35-
"Examples" => Any[
36-
"SOS decomposition" => "generated/sos_decomposition.md",
37-
"Bound on Global Extremum" => "generated/Bound on Global Extremum.md",
38-
"Lyapunov Function Search" => "generated/Lyapunov Function Search.md",
39-
"Sum-of-Squares Matrices" => "generated/Sum-of-Squares Matrices.md",
40-
"Noncommutative variables" => "generated/Noncommutative variables.md",
41-
"Sums of Hermitian squares" => "generated/Sums of Hermitian squares.md",
42-
"Symmetry reduction" => "generated/Symmetry reduction.md",
43-
]
29+
"Examples" => map(EXAMPLES) do jl_file
30+
# Need `string` as Documenter fails if `name` is a `SubString{String}`.
31+
name = string(split(jl_file, ".")[1])
32+
return name => "generated/$name.md"
33+
end
4434
],
4535
# The following ensures that we only include the docstrings from
4636
# this module for functions define in Base that we overwrite.
@@ -49,4 +39,5 @@ makedocs(
4939

5040
deploydocs(
5141
repo = "github.com/jump-dev/SumOfSquares.jl.git",
42+
push_preview = true,
5243
)

examples/Project.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
[deps]
22
CSDP = "0a46da34-8e4b-519e-b418-48813639ff34"
33
Cyclotomics = "da8f5974-afbb-4dc8-91d8-516d5257c83b"
4+
DifferentialEquations = "0c46a032-eb83-5123-abaf-570d42b7fbaa"
45
DynamicPolynomials = "7c1d4256-1411-5781-91ec-d7bc3513ac07"
56
IJulia = "7073ff75-c697-5162-941a-fcdaad2a7d2a"
67
JuMP = "4076af6c-e467-56ae-b986-b466b2749572"
78
MultivariateBases = "be282fd4-ad43-11e9-1d11-8bd9d7e43378"
89
MultivariatePolynomials = "102ac46a-7ee4-5c85-9060-abc95bfdeaa3"
910
MutableArithmetics = "d8a4904e-b15c-11e9-3269-09a3773c0cb0"
1011
PermutationGroups = "8bc5a954-2dfc-11e9-10e6-cd969bffa420"
12+
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
1113
SumOfSquares = "4b9e565b-77fc-50a5-a571-1244f986bda1"
File renamed without changes.
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
# # Stabilization of nonlinear systems
2+
3+
#md # [![](https://mybinder.org/badge_logo.svg)](@__BINDER_ROOT_URL__/generated/Stabilization of nonlinear systems.ipynb)
4+
#md # [![](https://img.shields.io/badge/show-nbviewer-579ACA.svg)](@__NBVIEWER_ROOT_URL__/generated/Stabilization of nonlinear systems.ipynb)
5+
# **Adapted from**: Examples 1, 2 and 3 of [PPA04]
6+
#
7+
# [PPA04] Prajna, Stephen, Pablo A. Parrilo, and Anders Rantzer.
8+
# *Nonlinear control synthesis by convex optimization*.
9+
# IEEE Transactions on Automatic Control 49.2 (2004): 310-314.
10+
11+
using Test #src
12+
using DynamicPolynomials
13+
@polyvar x[1:2]
14+
15+
using SumOfSquares
16+
using CSDP
17+
using LinearAlgebra # for ⋅
18+
using MultivariatePolynomials
19+
divergence(f) = sum(differentiate.(f, x))
20+
function controller(f, g, b, α, degs)
21+
solver = optimizer_with_attributes(CSDP.Optimizer, MOI.Silent() => true)
22+
model = SOSModel(solver)
23+
a = 1
24+
monos = monomials(x, degs)
25+
N = length(monos) + 1
26+
@variable(model, c[1:N] in MOI.NormOneCone(N))
27+
c_poly = polynomial(c[2:end], monos)
28+
fagc = f * a + g * c_poly
29+
@constraint(model, b * divergence(fagc) - α * differentiate(b, x) fagc in SOSCone())
30+
@objective(model, Min, c[1])
31+
optimize!(model)
32+
if termination_status(model) != MOI.OPTIMAL
33+
@warn("Termination status $(termination_status(model)): $(raw_status(model))")
34+
end
35+
u = value(c_poly) / value(a)
36+
return MultivariatePolynomials.mapcoefficientsnz(coef -> abs(coef) < 1e-6 ? 0.0 : coef, u)
37+
end
38+
39+
import DifferentialEquations, Plots
40+
function phase_plot(f, quiver_scaling, Δt, X0, solver = DifferentialEquations.Tsit5())
41+
(vx, vy) = [fi(x[1] => vx, x[2] => vy) for fi in f]
42+
∇pt(v, p, t) = (v[1], v[2])
43+
function traj(v0)
44+
tspan = (0.0, Δt)
45+
prob = DifferentialEquations.ODEProblem(∇pt, v0, tspan)
46+
return DifferentialEquations.solve(prob, solver, reltol=1e-8, abstol=1e-8)
47+
end
48+
ticks = -5:0.5:5
49+
X = repeat(ticks, 1, length(ticks))
50+
Y = X'
51+
Plots.quiver(X, Y, quiver = (x, y) -> (x, y) / quiver_scaling, linewidth=0.5)
52+
for x0 in X0
53+
Plots.plot!(traj(x0), vars=(1, 2), label = nothing)
54+
end
55+
Plots.plot!(xlims = (-5, 5), ylims = (-5, 5))
56+
end
57+
58+
# ## Example 1
59+
60+
g = [0, 1]
61+
f = [x[2] - x[1]^3 + x[1]^2, 0]
62+
b = 3x[1]^2 + 2x[1]*x[2] + 2x[2]^2
63+
u = controller(f, g, b, 4, 0:3)
64+
@test monomials(u) == [x[2]^3, x[1], x[2]] #src
65+
66+
# We find the controller above which gives the following phase plot.
67+
68+
phase_plot(f + g * u, 200, 10.0, [[x1, x2] for x1 in -5:5:5, x2 in -5:5:5 if x1 != 0 || x2 != 0])
69+
70+
# ## Example 2
71+
72+
g = [0, 1]
73+
f = [2x[1]^3 + x[1]^2*x[2] - 6x[1]*x[2]^2 + 5x[2]^3, 0]
74+
b = x[1]^2 + x[2]^2
75+
u = controller(f, g, b, 2.5, 0:3)
76+
@test monomials(u) == [x[1]^3, x[1]^2*x[2], x[1]*x[2]^2, x[2]^3] #src
77+
78+
# We find the controller above which gives the following phase plot.
79+
80+
phase_plot(f + g * u, 2000, 5.0, [[-1.0, -5.0], [1.0, 5.0]])
81+
82+
# ## Example 3
83+
84+
g = [0, x[2]]
85+
f = [-6x[1]*x[2]^2 - x[1]^2*x[2] + 2x[2]^3, 0]
86+
b = x[1]^2 + x[2]^2
87+
u = controller(f, g, b, 3, 0:2)
88+
@test monomials(u) == [x[1]^2, x[2]^2] #src
89+
90+
# We find the controller above which gives the following phase plot.
91+
92+
X0 = [Float64[x1, x2] for x1 in -5:5:5, x2 in -5:5:5 if x2 != 0]
93+
ε = 1e-4 # We separate the starting point slightly from the hyperplane `x2 = 0` which is invariant.
94+
push!(X0, [-4, ε])
95+
push!(X0, [-3, -ε])
96+
push!(X0, [ 3, ε])
97+
push!(X0, [ 4, -ε])
98+
phase_plot(f + g * u, 2000, 10.0, X0)

examples/all_examples.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
const EXAMPLES = filter(ex -> endswith(ex, ".jl") && ex != "run_examples.jl" && ex != "all_examples.jl" && ex != "goldsteinprice.jl" && ex != "sparse_polynomials.jl",
2+
readdir(@__DIR__))

examples/run_examples.jl

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using Test
22

3-
const EXAMPLES = filter(ex -> endswith(ex, ".jl") && ex != "run_examples.jl" && ex != "goldsteinprice.jl" && ex != "sparse_polynomials.jl",
4-
readdir(@__DIR__))
3+
include("all_examples.jl")
54

65
@testset "run_examples.jl" begin
76
@testset "$(example)" for example in EXAMPLES

0 commit comments

Comments
 (0)