Linear Optimization Solution
Linear Optimization solution
uses JuMP.jl
to solve the Problems. Build the problem and call generateJuMPcodes
, work done!
OptControl.generateJuMPcodes
— FunctiongenerateJuMPcodes(L, F, state, u, tspan, t0, tf) -> Any
generateJuMPcodes(L, F, state, u, tspan, t0, tf, Φ) -> Any
generateJuMPcodes(
L,
F,
state,
u,
tspan,
t0,
tf,
Φ,
tf_constraint;
state_ub,
state_lb,
u_ub,
u_lb,
N,
discretization,
model_name,
writeFilePath,
tolerance
) -> Any
generateJuMPcodes
will generate the solution code that using JuMP.jl
to solve problem
A general form of optimal control problem:
\[min (\Phi(\boldsymbol{x}(t_f),t_f)+\int_{t_0}^{t_f} L[\boldsymbol{x}(t),\boldsymbol{u}(t),t]dt) \\ s.t. \hspace{0.4cm} \dot{\boldsymbol{x}} =f[\boldsymbol{x}(t),\boldsymbol{u}(t),t]\]
args:
L
: above L
\[L[\boldsymbol{x}(t),\boldsymbol{u}(t),t]\]
F
: above f
\[f[\boldsymbol{x}(t),\boldsymbol{u}(t),t]\]
state
: states(variable) inF
u
: control variable u inF
tspan
: time fieldt0
: initial value attspan[1]
, length oft0
must be equal to length of statetf
: final(end) value attspan[2]
, length oftf
must be equal to length of stateΦ
: above Φ, default: nothing
\[\Phi(\boldsymbol{x}(t_f),t_f)\]
tf_constraint
: special requirements for end time, default: nothing. Example:
\[x_{1}+x_{2}=0\]
state_ub
: state's upper limit, length ofstate_ub
must be equal to length of state, default: nothingstate_lb
: state's lower limit, length ofstate_lb
must be equal to length of state, default: nothingu_ub
: u's upper limit, length ofu_ub
must be equal to length of u, default: nothingu_lb
: u's lower limit, length ofu_lb
must be equal to length of u, default: nothingN
: Number of discrete, default: 1000
\[dt = (endTime - startTime) / N\]
discretization
: discretization methods, default: "trapezoidal"model_name
: name of JuMP model, default: "model"writeFilePath
: path of generated code, default: nothingtolerance
: acceptable_tol of Ipopt, default: 1.0e-6
Example:
using OptControl
@variables t u x[1:2]
f = [0 1; 0 0] * x + [0, 1] * u
L = 0.5 * u^2
t0 = [1.0, 1.0]
tf = [0.0, 0.0]
tspan = (0.0, 2.0)
N = 100
sol = generateJuMPcodes(L, f, x, u, tspan, t0, tf; N=N)
Let's see some examples. If you are not familar with ModelingToolkit.jl, you can see the Symbolics.jl document (which ModelingToolkit.jl based on) and try some tests about symbolic computation
using OptControl,ModelingToolkit
@variables x[1:2] y[1:2]
print(scalarize(rand(1:10,2,2)*x+rand(1:10,2,2)*y))
Num[6x[1] + 6x[2] + 9y[1] + y[2], 3y[1] + 5x[2] + 8x[1] + 10y[2]]
PS: scalarize is from Symbolics.jl
If you need, pass a name to writeFilePath
and do some changes in script.
Example 1: Fixed value
To solve:
\[min \int_{0}^{2} u^2dt \newline s.t. ~~~~~ \dot{\boldsymbol{x}} =\begin{bmatrix}0&1 \newline 0&0\end{bmatrix}\boldsymbol{x}+ \begin{bmatrix}0 \newline 1 \end{bmatrix}u \newline \boldsymbol{x}(0) = \begin{bmatrix} 1 \newline 1 \end{bmatrix}, \boldsymbol{x}(2)=\begin{bmatrix} 0 \newline 0 \end{bmatrix}\]
Just define variables and build functions. Call generateJuMPcodes
and get the results.
The analytical solution of $x_1$ is
\[x_1(t) = 0.5*t^3-1.75*t^2+t+1\]
and we can campare the difference between them by using Mean Square Error(MSE).
using OptControl, Statistics, ModelingToolkit
@variables t u x[1:2]
f = [0 1; 0 0] * x + [0, 1] * u
L = 0.5 * u^2
t0 = [1.0, 1.0]
tf = [0.0, 0.0]
tspan = (0.0, 2.0)
N = 100
sol = generateJuMPcodes(L, f, x, u, tspan, t0, tf; N=N)
xs = collect(range(tspan[1], tspan[2], length=N))
an = @.(0.5 * xs^3 - 1.75 * xs^2 + xs + 1)
mean((an - sol[1][:, 1]).^2)
2.696022442477049e-6
Example 2: Free End
To solve:
\[min \int_{0}^{2} u^2dt \newline s.t. ~~~~~ \dot{\boldsymbol{x}} =\begin{bmatrix}0&1 \newline 0&0\end{bmatrix}\boldsymbol{x}+ \begin{bmatrix}0 \newline 1 \end{bmatrix}u \newline \boldsymbol{x}(0) = \begin{bmatrix} 1 \newline 1 \end{bmatrix}, \boldsymbol{x}(1)=\begin{bmatrix} 0 \newline free \end{bmatrix}\]
If variable is free, use nothing
.
The analytical solution of $x_1$ is
\[x_1(t) = t^3-3.0*t^2+t+1\]
and get MSE.
using OptControl, Statistics, ModelingToolkit, ModelingToolkit
@variables t u x[1:2]
f = [0 1; 0 0] * x + [0, 1] * u
L = 0.5 * u^2
t0 = [1.0, 1.0]
tf = [0.0, nothing]
tspan = (0.0, 1.0)
N = 100
sol = generateJuMPcodes(L, f, x, u, tspan, t0, tf; N=N)
xs = collect(range(tspan[1], tspan[2], length=N))
an = @.(xs^3 - 3.0 * xs^2 + xs + 1)
mean((an - sol[1][:, 1]).^2)
4.6689960309698826e-7
Example 3: End Constraint
To solve:
\[min \int_{0}^{2} u^2dt \newline s.t. ~~~~~ \dot{\boldsymbol{x}} =\begin{bmatrix}0&1 \newline 0&0\end{bmatrix}\boldsymbol{x}+ \begin{bmatrix}0 \newline 1 \end{bmatrix}u \newline \boldsymbol{x}(0) = \begin{bmatrix} 1 \newline 1 \end{bmatrix}, \boldsymbol{x}(1)=\begin{bmatrix} free \newline free \end{bmatrix} \\ x_1(1)+x_2(1)=0\]
Passing special end constraint to parameter tf_constraint
.
The analytical solution of $x_1$ is
\[x_1(t) = -1/14*t^2*(t - 6)\]
and get MSE.
using OptControl, Statistics, ModelingToolkit
@variables t u x[1:2]
f = [0 1; 0 0] * x + [0, 1] * u
L = 0.5 * u^2
t0 = [0.0, 0.0]
tf = [nothing, nothing]
tspan = (0.0, 1.0)
tf_con = x[1] + x[2] - 1.0
N = 100
sol = generateJuMPcodes(L, f, x, u, tspan, t0, tf, nothing, tf_con; N=N)
xs = collect(range(tspan[1], tspan[2], length=N))
an = @.(-1 / 14 * xs^2 * (xs - 6))
mean((an - sol[1][:, 1]).^2)
2.3177456677511903e-6
PS:x[1] + x[2] - 1.0
above is $x_1+x_2-1.0$. There nothing to do with independent variable $t$, because tf_constraint
means constraint at the end time.
Example 4: Multiple End Constraint
To solve:
\[min \int_{0}^{2} u^2dt \newline s.t. ~~~~~ \dot{\boldsymbol{x}} =\begin{bmatrix}0&1 \newline 0&0\end{bmatrix}\boldsymbol{x}+ \begin{bmatrix}0 \newline 1 \end{bmatrix}u \newline \boldsymbol{x}(0) = \begin{bmatrix} 1 \newline 1 \end{bmatrix}, \boldsymbol{x}(2)=\begin{bmatrix} free \newline free \end{bmatrix} \\ x_1(2)+x_2(2)=0\\ x_1(2)-x_2(2)=0 \]
Actually, solution of those two constraint equations are $x_1=0,x_2=0$Essentially, it's the same as Example 1
.
The analytical solution of $x_1$ is
\[x_1(t) = 0.5*t^3-1.75*t^2+t+1\]
and get MSE.
using OptControl, Statistics, ModelingToolkit
@variables t u x[1:2]
f = [0 1; 0 0] * x + [0, 1] * u
L = 0.5 * u^2
t0 = [1.0, 1.0]
tf = [nothing, nothing]
tspan = (0.0, 2.0)
tf_con = [x[1] + x[2], x[1] - x[2]]
N = 100
sol = generateJuMPcodes(L, f, x, u, tspan, t0, tf, nothing, tf_con; N=N)
xs = collect(range(tspan[1], tspan[2], length=N))
an = @.(0.5 * xs^3 - 1.75 * xs^2 + xs + 1)
mean((an - sol[1][:, 1]).^2)
2.696022442477024e-6
Example 5: Multiple x
and u
To solve:
\[min \int_{0}^{2} u^2dt \newline s.t. ~~~~~ \dot{\boldsymbol{x}} =\begin{bmatrix}0&1 \newline 0&0\end{bmatrix}\boldsymbol{x}+ \begin{bmatrix}1&0 \newline 0&1 \end{bmatrix}\boldsymbol{u} \newline \boldsymbol{x}(0) = \begin{bmatrix} 1 \newline 1 \end{bmatrix}, \boldsymbol{x}(2)=\begin{bmatrix} 0.0 \newline free \end{bmatrix} \]
The analytical solution of $u_1,u_2$ is
\[\begin{matrix} u_1=-\frac{9}{14}\\u_2=\frac{9}{14}*t-\frac{9}{7} \end{matrix} \]
and get MSE.
using OptControl, Statistics, ModelingToolkit
@variables t u[1:2] x[1:2]
f = [0 1; 0 0] * x + [1 0; 0 1] * u
L = 0.5 * (u[1]^2 + u[2]^2)
t0 = [1.0, 1.0]
tf = [0.0, nothing]
tspan = (0.0, 2.0)
N = 100
sol = generateJuMPcodes(L, f, x, u, tspan, t0, tf; N=N)
xs = collect(range(tspan[1], tspan[2], length=N))
an_u2 = @.(9 / 14 * xs - 9 / 7)
res1 = mean((-9 / 14 .- sol[2][:, 1]).^2)
res2 = mean((an_u2 - sol[2][:, 2]).^2)
(res1,res2)
(0.002166218961534756, 0.004150451971114561)
Example 6: Add variable limit
To solve:
\[min ~~x_2(1) \newline s.t. ~~~~~ \dot{\boldsymbol{x}} =\begin{bmatrix}-1&0 \newline 1&0\end{bmatrix}\boldsymbol{x}+ \begin{bmatrix}1 \newline 0 \end{bmatrix}u \newline \boldsymbol{x}(0) = \begin{bmatrix} 1 \newline 1 \end{bmatrix}, \boldsymbol{x}(1)=\begin{bmatrix} free \newline free \end{bmatrix} \\ -1.0 \leqslant\boldsymbol{u}\leqslant1.0\]
The analytical solution of $x_1$ is
\[x_1(t) = 2*e^{-t} - 1\]
and get MSE.
using OptControl, Statistics, ModelingToolkit
@variables t u x[1:2]
f = [-1 0; 1 0] * x + [1, 0] * u
L = 0
t0 = [1.0, 0.0]
tf = [nothing, nothing]
tspan = (0.0, 1.0)
N = 100
Φ = x[2]
uub = [1.0]
ulb = [-1.0]
sol = generateJuMPcodes(L, f, x, u, tspan, t0, tf, Φ, nothing;N=N, u_ub=uub, u_lb=ulb)
xs = collect(range(tspan[1], tspan[2], length=N))
an = @.(2 * exp(-xs) - 1)
mean((an - sol[1][:, 1]).^2)
3.244295042930682e-5
In this example, give L
a value 0. Because L
has nothing to do with optimization objective.