diff --git a/.gitignore b/.gitignore index b16eb018..ec2f89bc 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ *.jld2 *.json !.zenodo.json +!.markdownlint.json # System-specific files and directories generated by the BinaryProvider and BinDeps packages # They contain absolute paths specific to the host computer, and so should not be committed diff --git a/.markdownlint.json b/.markdownlint.json new file mode 100644 index 00000000..c4960442 --- /dev/null +++ b/.markdownlint.json @@ -0,0 +1,4 @@ +{ + "MD046": false, + "MD013": false +} \ No newline at end of file diff --git a/docs/make.jl b/docs/make.jl index f69c1704..fc08a7e9 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -129,8 +129,6 @@ Draft = false =# makedocs(; draft=false, - #draft=true, - #warnonly=[:cross_references, :autodocs_block], sitename="OptimalControl.jl", format=Documenter.HTML(; repolink="https://" * repo_url, @@ -141,6 +139,7 @@ makedocs(; assets=[ asset("https://control-toolbox.org/assets/css/documentation.css"), asset("https://control-toolbox.org/assets/js/documentation.js"), + "assets/custom.css", ], ), pages=[ diff --git a/docs/src/assets/Manifest.toml b/docs/src/assets/Manifest.toml index 38d140e8..5b99b680 100644 --- a/docs/src/assets/Manifest.toml +++ b/docs/src/assets/Manifest.toml @@ -1677,7 +1677,7 @@ version = "0.5.6+0" deps = ["ADNLPModels", "CTBase", "CTDirect", "CTFlows", "CTModels", "CTParser", "CommonSolve", "DocStringExtensions", "ExaModels"] path = "/Users/ocots/Research/logiciels/dev/control-toolbox/OptimalControl" uuid = "5f98b655-cc9a-415a-b60e-744165666948" -version = "1.1.2" +version = "1.1.3" [[deps.Opus_jll]] deps = ["Artifacts", "JLLWrappers", "Libdl"] diff --git a/docs/src/assets/custom.css b/docs/src/assets/custom.css new file mode 100644 index 00000000..4bc1dbcf --- /dev/null +++ b/docs/src/assets/custom.css @@ -0,0 +1,36 @@ +/* Responsive layout for two-column content */ +.responsive-columns-left-priority { + display: flex; + gap: 1rem; + align-items: flex-start; + margin-bottom: 1em; +} + +.responsive-columns-left-priority > div { + flex: 1; + min-width: 0; + transition: opacity 0.5s ease-in-out, flex 0.5s ease-in-out, max-width 0.5s ease-in-out, max-height 0.5s ease-in-out; +} + +.responsive-columns-left-priority > div:last-child { + opacity: 1; + max-width: 100%; + max-height: none; +} + +/* Media query for screens smaller than 700px */ +@media (max-width: 700px) { + .responsive-columns-left-priority > div:last-child { + opacity: 0; + max-width: 0; + max-height: 0; + flex: 0 0 0; + overflow: hidden; + margin: 0; + padding: 0; + } + + .responsive-columns-left-priority > div:first-child { + flex: 1 1 100%; + } +} \ No newline at end of file diff --git a/docs/src/example-double-integrator-energy.md b/docs/src/example-double-integrator-energy.md index c6b078ec..98857b88 100644 --- a/docs/src/example-double-integrator-energy.md +++ b/docs/src/example-double-integrator-energy.md @@ -13,8 +13,7 @@ We assume that the mass is constant and equal to one, and that there is no frict \dot x_1(t) = x_2(t), \quad \dot x_2(t) = u(t),\quad u(t) \in \R, ``` -which is simply the [double integrator](https://en.wikipedia.org/w/index.php?title=Double_integrator&oldid=1071399674) system. -Let us consider a transfer starting at time $t_0 = 0$ and ending at time $t_f = 1$, for which we want to minimise the transfer energy +which is simply the [double integrator](https://en.wikipedia.org/w/index.php?title=Double_integrator&oldid=1071399674) system. Let us consider a transfer starting at time $t_0 = 0$ and ending at time $t_f = 1$, for which we want to minimise the transfer energy ```math \frac{1}{2}\int_{0}^{1} u^2(t) \, \mathrm{d}t @@ -22,9 +21,7 @@ Let us consider a transfer starting at time $t_0 = 0$ and ending at time $t_f = starting from $x(0) = (-1, 0)$ and aiming to reach the target $x(1) = (0, 0)$. -First, we need to import the [OptimalControl.jl](https://control-toolbox.org/OptimalControl.jl) package to define the -optimal control problem, [NLPModelsIpopt.jl](https://jso.dev/NLPModelsIpopt.jl) to solve it, -and [Plots.jl](https://docs.juliaplots.org) to visualise the solution. +First, we need to import the [OptimalControl.jl](https://control-toolbox.org/OptimalControl.jl) package to define the optimal control problem, [NLPModelsIpopt.jl](https://jso.dev/NLPModelsIpopt.jl) to solve it, and [Plots.jl](https://docs.juliaplots.org) to visualise the solution. ```@example main using OptimalControl @@ -36,6 +33,11 @@ using Plots Let us define the problem with the [`@def`](@ref) macro: +```@raw html +
+
+``` + ```@example main t0 = 0 tf = 1 @@ -47,12 +49,35 @@ ocp = @def begin u ∈ R, control x(t0) == x0 x(tf) == xf - ẋ(t) == [x₂(t), u(t)] + ẋ(t) == [x₂(t), u(t)] 0.5∫( u(t)^2 ) → min end nothing # hide ``` +```@raw html +
+
+``` + +### Mathematical formulation + +```math + \begin{aligned} + & \text{Minimise} && \frac{1}{2}\int_0^1 u^2(t) \,\mathrm{d}t \\ + & \text{subject to} \\ + & && \dot{x}_1(t) = x_2(t), \\[0.5em] + & && \dot{x}_2(t) = u(t), \\[1.0em] + & && x(0) = (-1,0), \\[0.5em] + & && x(1) = (0,0). + \end{aligned} +``` + +```@raw html +
+
+``` + !!! note "Nota bene" For a comprehensive introduction to the syntax used above to define the optimal control problem, see [this abstract syntax tutorial](@ref manual-abstract-syntax). In particular, non-Unicode alternatives are available for derivatives, integrals, *etc.* @@ -142,12 +167,12 @@ plot(sol) ## State constraint -### Direct method +### Direct method: constrained case We add the path constraint ```math -x_2(t) \le 1.2. + x_2(t) \le 1.2. ``` Let us model, solve and plot the optimal control problem with this constraint. @@ -175,7 +200,7 @@ sol = solve(ocp) plt = plot(sol; label="Direct", size=(800, 600)) ``` -### Indirect method +### Indirect method: constrained case The pseudo-Hamiltonian is (considering the normal case): @@ -186,13 +211,13 @@ H(x, p, u, \mu) = p_1 x_2 + p_2 u - \frac{u^2}{2} + \mu\, c(x), with $c(x) = x_2 - a$. Along a boundary arc we have $c(x(t)) = 0$. Differentiating, we obtain: ```math - \frac{\mathrm{d}}{\mathrm{d}t}c(x(t)) = \dot{x}_2(t) = u(t) = 0. + \frac{\mathrm{d}}{\mathrm{d}t}c(x(t)) = \dot{x}_2(t) = u(t) = 0. ``` -The zero control is maximising; hence, $p_2(t) = 0$ along the boundary arc. +The zero control is maximising; hence, $p_2(t) = 0$ along the boundary arc. ```math - \dot{p}_2(t) = -p_1(t) - \mu(t) \quad \Rightarrow \mu(t) = -p_1(t). + \dot{p}_2(t) = -p_1(t) - \mu(t) \quad \Rightarrow \mu(t) = -p_1(t). ``` Since the adjoint vector is continuous at the entry time $t_1$ and the exit time $t_2$, we have four unknowns: the initial costate $p_0 \in \mathbb{R}^2$ and the times $t_1$ and $t_2$. We need four equations: the target condition provides two, reaching the constraint at time $t_1$ gives $c(x(t_1)) = 0$, and finally $p_2(t_1) = 0$. @@ -253,4 +278,4 @@ flow_sol = φ((t0, tf), x0, p0; saveat=range(t0, tf, 100)) # plot the solution on the previous plot plot!(plt, flow_sol; label="Indirect", color=2, linestyle=:dash) -``` \ No newline at end of file +``` diff --git a/docs/src/example-double-integrator-time.md b/docs/src/example-double-integrator-time.md index f1b9116a..55ba357b 100644 --- a/docs/src/example-double-integrator-time.md +++ b/docs/src/example-double-integrator-time.md @@ -32,6 +32,60 @@ using Plots Let us define the problem: +```@raw html +
+
+``` + +```@example main +ocp = @def begin + + tf ∈ R, variable + t ∈ [0, tf], time + x = (q, v) ∈ R², state + u ∈ R, control + + -1 ≤ u(t) ≤ 1 + + q(0) == -1 + v(0) == 0 + q(tf) == 0 + v(tf) == 0 + + ẋ(t) == [v(t), u(t)] + + tf → min + +end +nothing # hide +``` + +```@raw html +
+
+``` + +### Mathematical formulation + +```math + \begin{aligned} + & \text{Minimise} && t_f \\[0.5em] + & \text{subject to} \\[0.5em] + & && \dot q(t) = v(t), \\ + & && \dot v(t) = u(t), \\[0.5em] + & && -1 \le u(t) \le 1, \\[0.5em] + & && q(0) = -1, \\[0.5em] + & && v(0) = 0, \\[0.5em] + & && q(t_f) = 0, \\[0.5em] + & && v(t_f) = 0. + \end{aligned} +``` + +```@raw html +
+
+``` + ```@example main ocp = @def begin