Skip to content

Commit 4416689

Browse files
committed
Implement prox for MPC problems
1 parent 1b94e9e commit 4416689

25 files changed

+183
-19
lines changed

Project.toml

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,7 @@ authors = ["tylerhanks <teh.hanks@gmail.com>"]
44
version = "0.1.0"
55

66
[deps]
7-
Catlab = "134e5e36-593f-5add-ad60-77f754baafbe"
7+
AlgebraicOptimization = "a72ceada-00ec-4ad9-90d3-37b40eaed052"
88
Convex = "f65535da-76fb-5f13-bab9-19810c17039a"
9-
GLPK = "60bf3e95-4087-53dc-ae20-288a0d20c6a6"
109
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
11-
Revise = "295af30f-e4ad-537b-8983-00126c2a3abe"
1210
SCS = "c946c3f1-0d1f-5ce8-9dea-7daa1f7e2d13"
13-
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
14-
Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f"

examples/single_agent.jl

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using AlgebraicControl
2+
using LinearAlgebra
3+
using Convex
4+
5+
# Set up each agent's dynamics: x' = Ax + Bu
6+
dt = 0.1 # Discretization step size
7+
A = [1 dt 0 0; 0 1 0 0; 0 0 1 dt; 0 0 0 1]
8+
B = [0 0; dt 0; 0 0; 0 dt]
9+
Q = Matrix{Float64}(I(4))
10+
R = Matrix{Float64}(I(2))
11+
12+
sys = LinearSystem(A, B)
13+
14+
# Stage cost function: minimize control effort and deviation from origin
15+
stage_cost(u, x) = quadform(x, Q) + quadform(u, R)
16+
stage_constraints = Function[]
17+
# Create a multi-stage program for a horizon of N steps
18+
N = 100
19+
mpc_program = multi_stage_program(stage_cost, stage_constraints, sys, N)
20+
21+
# Create a proxable MPC program
22+
proxable_mpc = ProxableMPCProgram(mpc_program)
23+
24+
set_x0!(proxable_mpc, [5.0; 0.0; 5.0; 0.0]) # Initial state
25+
26+
xf = prox(proxable_mpc, zeros(4)) # Proximal step towards target state [10; 0; 10; 0]
27+

src/AlgebraicControl.jl

Lines changed: 86 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,88 @@
11
module AlgebraicControl
22

3-
include("Categories.jl")
4-
include("MonoidalCats.jl")
5-
include("ParaCats.jl")
6-
include("BasicCats.jl")
7-
include("LensCats.jl")
8-
include("Problems.jl")
9-
include("Optimizers.jl")
10-
include("ParaProbs.jl")
11-
include("ParaOptimizers.jl")
12-
include("LQR.jl")
13-
include("ParaConvCat.jl")
14-
include("CMPC.jl")
15-
16-
end # module AlgebraicControl
3+
include("ConvexPrograms.jl")
4+
5+
export ConvexProgram, OpenConvexProgram, LinearSystem, single_stage_program, multi_stage_program,
6+
ProxableMPCProgram, ProxableMPCProgram, set_x0!, prox, prox!
7+
8+
using Convex
9+
using SCS
10+
using LinearAlgebra
11+
12+
struct LinearSystem
13+
A::Matrix{Float64}
14+
B::Matrix{Float64}
15+
LinearSystem(A::Matrix{Float64}, B::Matrix{Float64}) =
16+
size(A, 1) == size(B, 1) ? new(A, B) : error("Inconsistent dimensions between A and B matrices.")
17+
end
18+
19+
state_dim(sys::LinearSystem) = size(sys.A, 1)
20+
control_dim(sys::LinearSystem) = size(sys.B, 2)
21+
22+
23+
function (sys::LinearSystem)(x, u)
24+
return sys.A * x + sys.B * u
25+
end
26+
27+
function single_stage_program(stage_cost::Function, stage_constraints::Vector{Function}, sys::LinearSystem)::OpenConvexProgram
28+
n = state_dim(sys)
29+
m = control_dim(sys)
30+
impl = (u1, x1, x2) -> ConvexProgram(
31+
stage_cost(u1[1], x1),
32+
vcat([c(u1[1], x1) for c in stage_constraints]..., x2 == sys(x1, u1[1]))
33+
)
34+
return OpenConvexProgram(n, n, [m], impl)
35+
end
36+
37+
function multi_stage_program(stage_cost::Function, stage_constraints::Vector{Function}, sys::LinearSystem, n::Int)::OpenConvexProgram
38+
one_step = single_stage_program(stage_cost, stage_constraints, sys)
39+
return compose(one_step, n)
40+
end
41+
42+
struct ProxableMPCProgram
43+
control_vars::Vector{Variable}
44+
input_var::Variable
45+
output_var::Variable
46+
program
47+
end
48+
49+
ProxableMPCProgram(F::OpenConvexProgram) = begin
50+
# Make variables of the right dimensions
51+
x0 = Variable(dom(F))
52+
xf = Variable(codom(F))
53+
#y = Variable(codom(F))
54+
us = [Variable(d) for d in F.internal_vars]
55+
#γ = Variable(1)
56+
mpc_program = F(us, x0, xf)
57+
# Once Convex.jl is fixed, we can make γ and y real variables and fix! them
58+
# in the prox function instead of rebuilding the program each time. But for now,
59+
# we suffer....
60+
proxable_program(y, γ) = minimize( # This is stupid but Convex.jl is broken...
61+
mpc_program.objective + (1 / (2 * γ)) * LinearAlgebra.dot(xf - y, xf - y),
62+
mpc_program.constraints
63+
)
64+
return ProxableMPCProgram(us, x0, xf, proxable_program)
65+
end
66+
67+
function set_x0!(P::ProxableMPCProgram, x0_val::Vector{Float64})
68+
fix!(P.input_var, x0_val)
69+
end
70+
71+
function prox(P::ProxableMPCProgram, x::Vector{Float64}, γ=1.0)
72+
#fix!(P.y, x)
73+
#fix!(P.γ, γ)
74+
prob = P.program(x, γ)
75+
solve!(prob, SCS.Optimizer; silent=true)
76+
return evaluate(P.output_var)
77+
end
78+
79+
function prox!(y, P::ProxableMPCProgram, x::Vector{Float64}, γ=1.0)
80+
#fix!(P.y, x)
81+
#fix!(P.γ[], γ)
82+
prob = P.program(x, γ)
83+
solve!(prob, SCS.Optimizer; silent_solver=true)
84+
copy!(y, evaluate(P.output_var))
85+
end
86+
87+
88+
end

src/ConvexPrograms.jl

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
using Convex
2+
3+
struct ConvexProgram
4+
objective::Convex.AbstractExpr
5+
constraints::Vector{Convex.Constraint}
6+
end
7+
8+
struct OpenConvexProgram
9+
dom_var::Int # Dimension of the domain decision variable
10+
codom_var::Int # Dimension of the codomain decision variable
11+
internal_vars::Vector{Int} # Dimensions of any internal variables
12+
impl::Function # internal_vars × dom_var × codom_var ⇢ ConvexProgram
13+
end
14+
15+
(F::OpenConvexProgram)(ps::Vector{Variable}, x::Variable, y::Variable) =
16+
F.impl(ps, x, y)
17+
18+
dom(F::OpenConvexProgram) = F.dom_var
19+
codom(F::OpenConvexProgram) = F.codom_var
20+
21+
function close_program(F::OpenConvexProgram, input_val::Vector{Float64}, output_val::Vector{Float64}, ivs::Vector{Variable})::ConvexProgram
22+
x_var = Variable(length(input_val))
23+
fix!(x_var, input_val)
24+
y_var = Variable(length(output_val))
25+
fix!(y_var, output_val)
26+
return F(ivs, x_var, y_var)
27+
end
28+
29+
function compose(F::OpenConvexProgram, G::OpenConvexProgram)
30+
@assert codom(F) == dom(G)
31+
y = Variable(codom(F))
32+
F_nparams = length(F.internal_vars)
33+
impl = (ps, x, z) -> begin
34+
if F_nparams > 0
35+
FCB = F(ps[1:F_nparams], x, y)
36+
else
37+
FCB = F(Variable[], x, y)
38+
end
39+
GCB = G(ps[F_nparams+1:end], y, z)
40+
return ConvexProgram(FCB.objective + GCB.objective, vcat(FCB.constraints, GCB.constraints))
41+
end
42+
return OpenConvexProgram(dom(F), codom(G), vcat(F.internal_vars, G.internal_vars), impl)
43+
end
44+
45+
# Compose an endomorphism with itself n times
46+
function compose(F::OpenConvexProgram, n::Int)
47+
@assert dom(F) == codom(F)
48+
res = F
49+
for i in 1:n-1
50+
res = compose(res, F)
51+
end
52+
return res
53+
end

src/archive/AlgebraicControl.jl

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
module AlgebraicControl
2+
3+
include("Categories.jl")
4+
include("MonoidalCats.jl")
5+
include("ParaCats.jl")
6+
include("BasicCats.jl")
7+
include("LensCats.jl")
8+
include("Problems.jl")
9+
include("Optimizers.jl")
10+
include("ParaProbs.jl")
11+
include("ParaOptimizers.jl")
12+
include("LQR.jl")
13+
include("ParaConvCat.jl")
14+
include("CMPC.jl")
15+
16+
end # module AlgebraicControl
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)