From 1d2fcc357663f7315ee2f32659e557f6a0857c58 Mon Sep 17 00:00:00 2001 From: Amiel Date: Sat, 7 Feb 2026 23:25:26 +0100 Subject: [PATCH 01/24] test implement --- ext/Descriptions/brachistochrone.md | 55 ++++++++ ext/JuMPModels/brachistochrone.jl | 127 ++++++++++++++++++ ext/MetaData/brachistochrone.jl | 12 ++ ext/OptimalControlModels/brachistochrone.jl | 77 +++++++++++ .../brachistochrone_s.jl | 95 +++++++++++++ src/OptimalControlProblems.jl | 11 ++ 6 files changed, 377 insertions(+) create mode 100644 ext/Descriptions/brachistochrone.md create mode 100644 ext/JuMPModels/brachistochrone.jl create mode 100644 ext/MetaData/brachistochrone.jl create mode 100644 ext/OptimalControlModels/brachistochrone.jl create mode 100644 ext/OptimalControlModels_s/brachistochrone_s.jl diff --git a/ext/Descriptions/brachistochrone.md b/ext/Descriptions/brachistochrone.md new file mode 100644 index 00000000..da388cf9 --- /dev/null +++ b/ext/Descriptions/brachistochrone.md @@ -0,0 +1,55 @@ +The **Brachistochrone problem** is a classical benchmark in the history of calculus of variations and optimal control.   +It seeks the shape of a curve (or wire) connecting two points $A$ and $B$ within a vertical plane, such that a bead sliding frictionlessly under the influence of uniform gravity travels from $A$ to $B$ in the shortest possible time.   +Originating from the challenge posed by Johann Bernoulli in 1696 [Bernoulli 1696](https://doi.org/10.1002/andp.19163551307), it marks the birth of modern optimal control theory.   +The problem involves nonlinear dynamics where the state includes position and velocity, and the control is the path's angle, with the final time $t_f$ being a decision variable to be minimised. + +### Mathematical formulation + +The problem can be stated as a free final time optimal control problem: + +```math +\begin{aligned} +\min_{u(\cdot), t_f} \quad & J = t_f = \int_0^{t_f} 1 \,\mathrm{d}t \\[1em] +\text{s.t.} \quad & \dot{x}(t) = v(t) \sin u(t), \\[0.5em] +& \dot{y}(t) = v(t) \cos u(t), \\[0.5em] +& \dot{v}(t) = g \cos u(t), \\[0.5em] +& x(0) = x_0, \; y(0) = y_0, \; v(0) = v_0, \\[0.5em] +& x(t_f) = x_f, \; y(t_f) = y_f, +\end{aligned} +``` + +where $u(t)$ represents the angle of the tangent to the curve with respect to the vertical axis, and $g$ is the gravitational acceleration. + +### Qualitative behaviour + +This problem is a classic example of **minimum time control** with nonlinear dynamics.   +Unlike the shortest path problem (a straight line), the optimal trajectory balances the need to minimize path length with the need to maximize velocity. + +The analytical solution to this problem is a **cycloid**—the curve traced by a point on the rim of a circular wheel as the wheel rolls along a straight line without slipping.   +Specifically: + +- **Energy Conservation**: Since the system is conservative and frictionless, the speed at any height $h$ is given by $v = \sqrt{2gh}$ (assuming start from rest). This implies that maximizing vertical drop early in the trajectory increases velocity for the remainder of the path. +- **Concavity**: The optimal curve is concave up. It starts steeply (vertical tangent if $v_0=0$) to gain speed quickly, then flattens out near the bottom before potentially rising again to reach the target. +- **Singularity**: At the initial point, if $v_0=0$, the control is theoretically singular as the bead has no velocity to direct. Numerical solvers often require a small non-zero initial velocity or a robust initial guess to handle this start. + +The control $u(t)$ is continuous and varies smoothly to trace the cycloidal arc. + +### Characteristics + +- **Nonlinear dynamics** involving trigonometric functions of the control. +- **Free final time** problem (time-optimal). +- Analytical solution is a **Cycloid**. +- Historically significant as the first problem solved using techniques that evolved into the Calculus of Variations. + +### References + +- Bernoulli, J. (1696). *Problema novum ad cujus solutionem Mathematici invitantur*.   +  Acta Eruditorum.   +  The original publication posing the challenge to the mathematicians of Europe, solved by Newton, Leibniz, L'Hôpital, and the Bernoulli brothers. + +- Sussmann, H. J., & Willems, J. C. (1997). *300 years of optimal control: from the brachystochrone to the maximum principle*.   +  IEEE Control Systems Magazine. [doi.org/10.1109/37.588108](https://doi.org/10.1109/37.588108)   +  A comprehensive historical review linking the classical Brachistochrone problem to modern optimal control theory and Pontryagin's Maximum Principle. + +- Dymos Examples: Brachistochrone. [OpenMDAO/Dymos](https://openmdao.github.io/dymos/examples/brachistochrone/brachistochrone.html)   +  The numerical implementation serving as the basis for the current benchmark formulation. \ No newline at end of file diff --git a/ext/JuMPModels/brachistochrone.jl b/ext/JuMPModels/brachistochrone.jl new file mode 100644 index 00000000..6678cc7c --- /dev/null +++ b/ext/JuMPModels/brachistochrone.jl @@ -0,0 +1,127 @@ +""" +$(TYPEDSIGNATURES) + +Constructs a JuMP model representing the **Brachistochrone optimal control problem**. +The objective is to minimize the final time `tf` to travel between two points under gravity. +The problem uses a direct transcription (trapezoidal rule) manually implemented in JuMP. + +# Arguments + +- `::JuMPBackend`: Placeholder type to specify the JuMP backend or solver interface. +- `grid_size::Int=50`: (Keyword) Number of discretisation steps for the time grid. + +# Returns + +- `model::JuMP.Model`: A JuMP model containing the decision variables (including final time), dynamics constraints, and boundary conditions. + +# Example + +```julia-repl +julia> using OptimalControlProblems +julia> using JuMP +julia> model = OptimalControlProblems.brachistochrone(JuMPBackend(); N=100) +``` + +# References + +- Dymos Brachistochrone: [https://openmdao.github.io/dymos/examples/brachistochrone/brachistochrone.html](https://openmdao.github.io/dymos/examples/brachistochrone/brachistochrone.html) +""" +function OptimalControlProblems.brachistochrone( + ::JuMPBackend, + args...; + grid_size::Int=grid_size_data(Val(:brachistochrone)), + parameters::Union{Nothing,NamedTuple}=nothing, + kwargs..., +) + + # parameters + params = parameters_data(Val(:brachistochrone), parameters) + g = params[:g] + t0 = params[:t0] + x0 = params[:x0] + y0 = params[:y0] + v0 = params[:v0] + xf = params[:xf] + yf = params[:yf] + + # model + model = JuMP.Model(args...; kwargs...) + + # N = grid_size + @expression(model, N, grid_size) + + @variables( + model, + begin + 0.1 <= tf <= 20.0, (start = 2.0) + x[0:N] + y[0:N] + v[0:N] + u[0:N] + end + ) + + + model[:time_grid] = () -> range(t0, value(tf), N+1) + model[:state_components] = ["x", "y", "v"] + model[:control_components] = ["u"] + model[:variable_components] = ["tf"] + + for i in 0:N + alpha = i / N + set_start_value(x[i], x0 + alpha * (xf - x0)) + set_start_value(y[i], y0 + alpha * (yf - y0)) + set_start_value(v[i], v0 + alpha * 10.0) # Estimate speed + set_start_value(u[i], 1.57) # ~90 degrees + end + + # boundary constraints + @constraints( + model, + begin + # Start + x[0] == x0 + y[0] == y0 + v[0] == v0 + + # End + x[N] == xf + y[N] == yf + # v[N] is free + end + ) + + # dynamics + @expressions( + model, + begin + # Time step is variable: dt = (tf - t0) / N + dt, (tf - t0) / N + + # Dynamics expressions (Dymos formulation) + # dx/dt = v * sin(u) + dx[i = 0:N], v[i] * sin(u[i]) + + # dy/dt = v * cos(u) + dy[i = 0:N], v[i] * cos(u[i]) + + # dv/dt = g * cos(u) + dv[i = 0:N], g * cos(u[i]) + end + ) + + # Trapezoidal rule integration (Implicit) + @constraints( + model, + begin + ∂x[i = 1:N], x[i] == x[i - 1] + 0.5 * dt * (dx[i] + dx[i - 1]) + ∂y[i = 1:N], y[i] == y[i - 1] + 0.5 * dt * (dy[i] + dy[i - 1]) + ∂v[i = 1:N], v[i] == v[i - 1] + 0.5 * dt * (dv[i] + dv[i - 1]) + end + ) + + # objective: Minimize final time + @objective(model, Min, tf) + + return model +end \ No newline at end of file diff --git a/ext/MetaData/brachistochrone.jl b/ext/MetaData/brachistochrone.jl new file mode 100644 index 00000000..17d700d0 --- /dev/null +++ b/ext/MetaData/brachistochrone.jl @@ -0,0 +1,12 @@ +brachistochrone_meta = OrderedDict( + :grid_size => 500, + :parameters => ( + g = 9.80665, + t0 = 0.0, + x0 = 0.0, + y0 = 10.0, + v0 = 0.0, + xf = 10.0, + yf = 5.0, + ), +) \ No newline at end of file diff --git a/ext/OptimalControlModels/brachistochrone.jl b/ext/OptimalControlModels/brachistochrone.jl new file mode 100644 index 00000000..fd71ea1b --- /dev/null +++ b/ext/OptimalControlModels/brachistochrone.jl @@ -0,0 +1,77 @@ +""" +$(TYPEDSIGNATURES) + +Constructs the **Brachistochrone** optimal control problem. +The goal is to move from point A to point B in minimum time under gravity. + +# Arguments +- `::OptimalControlBackend`: The backend type. +- `grid_size`: Number of time steps. +- `parameters`: Optional parameter overrides. + +```julia-repl +julia> using OptimalControlProblems + +julia> docp = OptimalControlProblems.brachistochrone(OptimalControlBackend(); N=100); +``` +""" +function OptimalControlProblems.brachistochrone( + ::OptimalControlBackend, + description::Symbol...; + grid_size::Int=grid_size_data(Val(:brachistochrone)), + parameters::Union{Nothing,NamedTuple}=nothing, + kwargs..., +) + + params = parameters_data(Val(:brachistochrone), parameters) + g = params[:g] + t0 = params[:t0] + x0 = params[:x0] + y0 = params[:y0] + v0 = params[:v0] + xf = params[:xf] + yf = params[:yf] + + ocp = @def begin + tf ∈ R, variable + t ∈ [t0, tf], time + + x ∈ R, state + y ∈ R, state + v ∈ R, state + + u ∈ R, control + + x(t0) == x0 + y(t0) == y0 + v(t0) == v0 + + x(tf) == xf + y(tf) == yf + + 0.1 ≤ tf ≤ 20.0 + + ẋ(t) == v(t) * sin(u(t)) + ẏ(t) == v(t) * cos(u(t)) + v̇(t) == g * cos(u(t)) + + tf → min + end + + + init = ( + state = [5.0, 7.5, 5.0], + control = 1.5, + variable = 1.0 + ) + + docp = direct_transcription( + ocp, + description...; + init = init, + grid_size = grid_size, + kwargs... + ) + + return docp +end diff --git a/ext/OptimalControlModels_s/brachistochrone_s.jl b/ext/OptimalControlModels_s/brachistochrone_s.jl new file mode 100644 index 00000000..a8ca2fe2 --- /dev/null +++ b/ext/OptimalControlModels_s/brachistochrone_s.jl @@ -0,0 +1,95 @@ +""" +$(TYPEDSIGNATURES) + +Constructs an **OptimalControl problem** representing the Brachistochrone problem using the OptimalControl backend. +The function sets up the state and control variables, boundary conditions, dynamics, and the objective functional. +It then performs direct transcription to generate a discrete optimal control problem (DOCP). + +# Arguments + +- `::OptimalControlBackend`: Placeholder type to specify the OptimalControl backend or solver interface. +- `grid_size::Int=grid_size_data(:brachistochrone)`: (Keyword) Number of discretisation points for the direct transcription grid. +- `parameters::Union{Nothing,NamedTuple}=nothing`: (Keyword) Custom parameters to override defaults. + +# Returns + +- `docp`: The direct optimal control problem object, representing the discretised problem. + +# Example + +```julia-repl +julia> using OptimalControlProblems + +julia> docp = OptimalControlProblems.brachistochrone(OptimalControlBackend(); N=100); +``` + +# References + +- Dymos Brachistochrone: https://openmdao.github.io/dymos/examples/brachistochrone/brachistochrone.html +""" +function OptimalControlProblems.brachistochrone( + ::OptimalControlBackend, + description::Symbol...; + grid_size::Int=grid_size_data(Val(:brachistochrone)), + parameters::Union{Nothing,NamedTuple}=nothing, + kwargs..., +) + + + params = parameters_data(Val(:brachistochrone), parameters) + g = params[:g] + t0 = params[:t0] + x0 = params[:x0] + y0 = params[:y0] + v0 = params[:v0] + xf = params[:xf] + yf = params[:yf] + + # model + ocp = @def begin + + tf ∈ R, variable + t ∈ [t0, tf], time + + x ∈ R, state + y ∈ R, state + v ∈ R, state + + u ∈ R, control + + x(t0) == x0 + y(t0) == y0 + v(t0) == v0 + + x(tf) == xf + y(tf) == yf + + 0.1 ≤ tf ≤ 20.0 + + ∂(x)(t) == v(t) * sin(u(t)) + ∂(y)(t) == v(t) * cos(u(t)) + ∂(v)(t) == g * cos(u(t)) + + tf → min + end + + # initial guess + init = ( + state = [5.0, 7.5, 5.0], + control = 1.57, + variable = 2.0 + ) + + # discretise the optimal control problem + docp = direct_transcription( + ocp, + description...; + lagrange_to_mayer=false, + init=init, + grid_size=grid_size, + disc_method=:trapeze, + kwargs..., + ) + + return docp +end \ No newline at end of file diff --git a/src/OptimalControlProblems.jl b/src/OptimalControlProblems.jl index 9729407d..2a27ad5c 100644 --- a/src/OptimalControlProblems.jl +++ b/src/OptimalControlProblems.jl @@ -72,6 +72,17 @@ function make_list_of_problems() :robot, :space_shuttle, :steering, + :beam, + :cart_pendulum, + :chain, + :dielectrophoretic_particle, + :double_oscillator, + :electric_vehicle, + :glider, + :jackson, + :robbins, + :rocket, + :vanderpol, ] list_of_problems = setdiff(list_of_problems, problems_to_exclude) From 949511361fa5086396686c40882614de4a8d6b44 Mon Sep 17 00:00:00 2001 From: Amiel Date: Sat, 7 Feb 2026 23:33:33 +0100 Subject: [PATCH 02/24] fix bug --- ext/JuMPModels/brachistochrone.jl | 2 +- ext/OptimalControlModels/brachistochrone.jl | 2 +- ext/OptimalControlModels_s/brachistochrone_s.jl | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ext/JuMPModels/brachistochrone.jl b/ext/JuMPModels/brachistochrone.jl index 6678cc7c..ea646624 100644 --- a/ext/JuMPModels/brachistochrone.jl +++ b/ext/JuMPModels/brachistochrone.jl @@ -29,7 +29,7 @@ julia> model = OptimalControlProblems.brachistochrone(JuMPBackend(); N=100) function OptimalControlProblems.brachistochrone( ::JuMPBackend, args...; - grid_size::Int=grid_size_data(Val(:brachistochrone)), + grid_size::Int=grid_size_data(:brachistochrone), parameters::Union{Nothing,NamedTuple}=nothing, kwargs..., ) diff --git a/ext/OptimalControlModels/brachistochrone.jl b/ext/OptimalControlModels/brachistochrone.jl index fd71ea1b..4d319c25 100644 --- a/ext/OptimalControlModels/brachistochrone.jl +++ b/ext/OptimalControlModels/brachistochrone.jl @@ -18,7 +18,7 @@ julia> docp = OptimalControlProblems.brachistochrone(OptimalControlBackend(); N= function OptimalControlProblems.brachistochrone( ::OptimalControlBackend, description::Symbol...; - grid_size::Int=grid_size_data(Val(:brachistochrone)), + grid_size::Int=grid_size_data(:brachistochrone), parameters::Union{Nothing,NamedTuple}=nothing, kwargs..., ) diff --git a/ext/OptimalControlModels_s/brachistochrone_s.jl b/ext/OptimalControlModels_s/brachistochrone_s.jl index a8ca2fe2..41de40d0 100644 --- a/ext/OptimalControlModels_s/brachistochrone_s.jl +++ b/ext/OptimalControlModels_s/brachistochrone_s.jl @@ -30,7 +30,7 @@ julia> docp = OptimalControlProblems.brachistochrone(OptimalControlBackend(); N= function OptimalControlProblems.brachistochrone( ::OptimalControlBackend, description::Symbol...; - grid_size::Int=grid_size_data(Val(:brachistochrone)), + grid_size::Int=grid_size_data(:brachistochrone), parameters::Union{Nothing,NamedTuple}=nothing, kwargs..., ) From ee2036d3e9e5a3ecd24d6d4e83c4db34282a45cf Mon Sep 17 00:00:00 2001 From: Amiel Date: Sat, 7 Feb 2026 23:38:52 +0100 Subject: [PATCH 03/24] bug 2 --- ext/OptimalControlModels_s/brachistochrone_s.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/OptimalControlModels_s/brachistochrone_s.jl b/ext/OptimalControlModels_s/brachistochrone_s.jl index 41de40d0..ad448b26 100644 --- a/ext/OptimalControlModels_s/brachistochrone_s.jl +++ b/ext/OptimalControlModels_s/brachistochrone_s.jl @@ -27,7 +27,7 @@ julia> docp = OptimalControlProblems.brachistochrone(OptimalControlBackend(); N= - Dymos Brachistochrone: https://openmdao.github.io/dymos/examples/brachistochrone/brachistochrone.html """ -function OptimalControlProblems.brachistochrone( +function OptimalControlProblems.brachistochrone_s( ::OptimalControlBackend, description::Symbol...; grid_size::Int=grid_size_data(:brachistochrone), From e2e1290453e27948fbeeb7019518193e1e4884d4 Mon Sep 17 00:00:00 2001 From: Amiel Date: Sat, 7 Feb 2026 23:43:51 +0100 Subject: [PATCH 04/24] BUG 3 --- ext/JuMPModels/brachistochrone.jl | 2 +- ext/OptimalControlModels/brachistochrone.jl | 2 +- ext/OptimalControlModels_s/brachistochrone_s.jl | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ext/JuMPModels/brachistochrone.jl b/ext/JuMPModels/brachistochrone.jl index ea646624..a68f7293 100644 --- a/ext/JuMPModels/brachistochrone.jl +++ b/ext/JuMPModels/brachistochrone.jl @@ -35,7 +35,7 @@ function OptimalControlProblems.brachistochrone( ) # parameters - params = parameters_data(Val(:brachistochrone), parameters) + params = parameters_data(:brachistochrone, parameters) g = params[:g] t0 = params[:t0] x0 = params[:x0] diff --git a/ext/OptimalControlModels/brachistochrone.jl b/ext/OptimalControlModels/brachistochrone.jl index 4d319c25..25110d04 100644 --- a/ext/OptimalControlModels/brachistochrone.jl +++ b/ext/OptimalControlModels/brachistochrone.jl @@ -23,7 +23,7 @@ function OptimalControlProblems.brachistochrone( kwargs..., ) - params = parameters_data(Val(:brachistochrone), parameters) + params = parameters_data(:brachistochrone, parameters) g = params[:g] t0 = params[:t0] x0 = params[:x0] diff --git a/ext/OptimalControlModels_s/brachistochrone_s.jl b/ext/OptimalControlModels_s/brachistochrone_s.jl index ad448b26..dd706690 100644 --- a/ext/OptimalControlModels_s/brachistochrone_s.jl +++ b/ext/OptimalControlModels_s/brachistochrone_s.jl @@ -36,7 +36,7 @@ function OptimalControlProblems.brachistochrone_s( ) - params = parameters_data(Val(:brachistochrone), parameters) + params = parameters_data(:brachistochrone, parameters) g = params[:g] t0 = params[:t0] x0 = params[:x0] From c9366b2ffc4a556873dc2b3343c7d02c4300674f Mon Sep 17 00:00:00 2001 From: Amiel Date: Sat, 7 Feb 2026 23:54:22 +0100 Subject: [PATCH 05/24] bug 4 --- ext/JuMPModels/brachistochrone.jl | 6 ++++++ ext/OptimalControlModels/brachistochrone.jl | 13 +++++++------ ext/OptimalControlModels_s/brachistochrone_s.jl | 11 ++++++----- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/ext/JuMPModels/brachistochrone.jl b/ext/JuMPModels/brachistochrone.jl index a68f7293..cfde278e 100644 --- a/ext/JuMPModels/brachistochrone.jl +++ b/ext/JuMPModels/brachistochrone.jl @@ -64,6 +64,12 @@ function OptimalControlProblems.brachistochrone( model[:time_grid] = () -> range(t0, value(tf), N+1) model[:state_components] = ["x", "y", "v"] + + # --- CORRECTION ICI --- + # Il faut déclarer la liste des costates (vide ici) pour satisfaire les tests + model[:costate_components] = String[] + # ---------------------- + model[:control_components] = ["u"] model[:variable_components] = ["tf"] diff --git a/ext/OptimalControlModels/brachistochrone.jl b/ext/OptimalControlModels/brachistochrone.jl index 25110d04..ab1778fb 100644 --- a/ext/OptimalControlModels/brachistochrone.jl +++ b/ext/OptimalControlModels/brachistochrone.jl @@ -36,9 +36,9 @@ function OptimalControlProblems.brachistochrone( tf ∈ R, variable t ∈ [t0, tf], time - x ∈ R, state - y ∈ R, state - v ∈ R, state + + [x, y, v] ∈ R³, state + # ---------------------- u ∈ R, control @@ -51,8 +51,9 @@ function OptimalControlProblems.brachistochrone( 0.1 ≤ tf ≤ 20.0 - ẋ(t) == v(t) * sin(u(t)) - ẏ(t) == v(t) * cos(u(t)) + + ẋ(t) == v(t) * sin(u(t)) + ẏ(t) == v(t) * cos(u(t)) v̇(t) == g * cos(u(t)) tf → min @@ -74,4 +75,4 @@ function OptimalControlProblems.brachistochrone( ) return docp -end +end \ No newline at end of file diff --git a/ext/OptimalControlModels_s/brachistochrone_s.jl b/ext/OptimalControlModels_s/brachistochrone_s.jl index dd706690..c8710680 100644 --- a/ext/OptimalControlModels_s/brachistochrone_s.jl +++ b/ext/OptimalControlModels_s/brachistochrone_s.jl @@ -51,9 +51,9 @@ function OptimalControlProblems.brachistochrone_s( tf ∈ R, variable t ∈ [t0, tf], time - x ∈ R, state - y ∈ R, state - v ∈ R, state + + [x, y, v] ∈ R³, state + # ------------------ u ∈ R, control @@ -66,6 +66,7 @@ function OptimalControlProblems.brachistochrone_s( 0.1 ≤ tf ≤ 20.0 + ∂(x)(t) == v(t) * sin(u(t)) ∂(y)(t) == v(t) * cos(u(t)) ∂(v)(t) == g * cos(u(t)) @@ -73,14 +74,14 @@ function OptimalControlProblems.brachistochrone_s( tf → min end - # initial guess + init = ( state = [5.0, 7.5, 5.0], control = 1.57, variable = 2.0 ) - # discretise the optimal control problem + docp = direct_transcription( ocp, description...; From f5ddb9ac0c7ac94a87996c19fcff7bde77259cfd Mon Sep 17 00:00:00 2001 From: Amiel Date: Sun, 8 Feb 2026 00:01:42 +0100 Subject: [PATCH 06/24] bug 6 --- ext/JuMPModels/brachistochrone.jl | 2 -- ext/OptimalControlModels/brachistochrone.jl | 24 +++++++---------- .../brachistochrone_s.jl | 27 +++++++++---------- 3 files changed, 22 insertions(+), 31 deletions(-) diff --git a/ext/JuMPModels/brachistochrone.jl b/ext/JuMPModels/brachistochrone.jl index cfde278e..7d56ff07 100644 --- a/ext/JuMPModels/brachistochrone.jl +++ b/ext/JuMPModels/brachistochrone.jl @@ -65,8 +65,6 @@ function OptimalControlProblems.brachistochrone( model[:time_grid] = () -> range(t0, value(tf), N+1) model[:state_components] = ["x", "y", "v"] - # --- CORRECTION ICI --- - # Il faut déclarer la liste des costates (vide ici) pour satisfaire les tests model[:costate_components] = String[] # ---------------------- diff --git a/ext/OptimalControlModels/brachistochrone.jl b/ext/OptimalControlModels/brachistochrone.jl index ab1778fb..a7b988ad 100644 --- a/ext/OptimalControlModels/brachistochrone.jl +++ b/ext/OptimalControlModels/brachistochrone.jl @@ -36,30 +36,26 @@ function OptimalControlProblems.brachistochrone( tf ∈ R, variable t ∈ [t0, tf], time - - [x, y, v] ∈ R³, state - # ---------------------- + q ∈ R³, state # q[1]=x, q[2]=y, q[3]=v + # ------------------------------------------ u ∈ R, control - x(t0) == x0 - y(t0) == y0 - v(t0) == v0 + q(t0) == [x0, y0, v0] - x(tf) == xf - y(tf) == yf - + + q(tf)[1] == xf + q(tf)[2] == yf + 0.1 ≤ tf ≤ 20.0 - - ẋ(t) == v(t) * sin(u(t)) - ẏ(t) == v(t) * cos(u(t)) - v̇(t) == g * cos(u(t)) + q̇(t) == [ q(t)[3] * sin(u(t)), + q(t)[3] * cos(u(t)), + g * cos(u(t)) ] tf → min end - init = ( state = [5.0, 7.5, 5.0], control = 1.5, diff --git a/ext/OptimalControlModels_s/brachistochrone_s.jl b/ext/OptimalControlModels_s/brachistochrone_s.jl index c8710680..82676868 100644 --- a/ext/OptimalControlModels_s/brachistochrone_s.jl +++ b/ext/OptimalControlModels_s/brachistochrone_s.jl @@ -35,7 +35,6 @@ function OptimalControlProblems.brachistochrone_s( kwargs..., ) - params = parameters_data(:brachistochrone, parameters) g = params[:g] t0 = params[:t0] @@ -51,37 +50,35 @@ function OptimalControlProblems.brachistochrone_s( tf ∈ R, variable t ∈ [t0, tf], time - - [x, y, v] ∈ R³, state - # ------------------ + + q ∈ R³, state + # ------------------------------------------ u ∈ R, control - x(t0) == x0 - y(t0) == y0 - v(t0) == v0 + q(t0) == [x0, y0, v0] - x(tf) == xf - y(tf) == yf + q(tf)[1] == xf + q(tf)[2] == yf 0.1 ≤ tf ≤ 20.0 - - ∂(x)(t) == v(t) * sin(u(t)) - ∂(y)(t) == v(t) * cos(u(t)) - ∂(v)(t) == g * cos(u(t)) + + ∂(q)(t) == [ q(t)[3] * sin(u(t)), + q(t)[3] * cos(u(t)), + g * cos(u(t)) ] tf → min end - + # initial guess init = ( state = [5.0, 7.5, 5.0], control = 1.57, variable = 2.0 ) - + # discretise the optimal control problem docp = direct_transcription( ocp, description...; From 83748ba75932bdafd323f9ebe5e06d67550068a4 Mon Sep 17 00:00:00 2001 From: Amiel Date: Sun, 8 Feb 2026 00:07:06 +0100 Subject: [PATCH 07/24] bug 7 --- ext/OptimalControlModels/brachistochrone.jl | 12 +++++------- ext/OptimalControlModels_s/brachistochrone_s.jl | 11 ++++------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/ext/OptimalControlModels/brachistochrone.jl b/ext/OptimalControlModels/brachistochrone.jl index a7b988ad..7fd5ba44 100644 --- a/ext/OptimalControlModels/brachistochrone.jl +++ b/ext/OptimalControlModels/brachistochrone.jl @@ -37,21 +37,19 @@ function OptimalControlProblems.brachistochrone( t ∈ [t0, tf], time q ∈ R³, state # q[1]=x, q[2]=y, q[3]=v - # ------------------------------------------ u ∈ R, control q(t0) == [x0, y0, v0] - - q(tf)[1] == xf q(tf)[2] == yf - + # q(tf)[3] libre + 0.1 ≤ tf ≤ 20.0 - q̇(t) == [ q(t)[3] * sin(u(t)), - q(t)[3] * cos(u(t)), - g * cos(u(t)) ] + q̇(t)[1] == q(t)[3] * sin(u(t)) # dx/dt + q̇(t)[2] == q(t)[3] * cos(u(t)) # dy/dt + q̇(t)[3] == g * cos(u(t)) # dv/dt tf → min end diff --git a/ext/OptimalControlModels_s/brachistochrone_s.jl b/ext/OptimalControlModels_s/brachistochrone_s.jl index 82676868..58c0d27b 100644 --- a/ext/OptimalControlModels_s/brachistochrone_s.jl +++ b/ext/OptimalControlModels_s/brachistochrone_s.jl @@ -50,9 +50,7 @@ function OptimalControlProblems.brachistochrone_s( tf ∈ R, variable t ∈ [t0, tf], time - - q ∈ R³, state - # ------------------------------------------ + q ∈ R³, state u ∈ R, control @@ -63,10 +61,9 @@ function OptimalControlProblems.brachistochrone_s( 0.1 ≤ tf ≤ 20.0 - - ∂(q)(t) == [ q(t)[3] * sin(u(t)), - q(t)[3] * cos(u(t)), - g * cos(u(t)) ] + ∂(q)(t)[1] == q(t)[3] * sin(u(t)) + ∂(q)(t)[2] == q(t)[3] * cos(u(t)) + ∂(q)(t)[3] == g * cos(u(t)) tf → min end From b2e1fade83fead8a1a18b483c358c77dad9a4053 Mon Sep 17 00:00:00 2001 From: Amiel Date: Sun, 8 Feb 2026 00:17:03 +0100 Subject: [PATCH 08/24] BUG 7 --- ext/OptimalControlModels/brachistochrone.jl | 20 +++++++++++-------- .../brachistochrone_s.jl | 14 ++++++------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/ext/OptimalControlModels/brachistochrone.jl b/ext/OptimalControlModels/brachistochrone.jl index 7fd5ba44..71bf3f41 100644 --- a/ext/OptimalControlModels/brachistochrone.jl +++ b/ext/OptimalControlModels/brachistochrone.jl @@ -36,20 +36,24 @@ function OptimalControlProblems.brachistochrone( tf ∈ R, variable t ∈ [t0, tf], time - q ∈ R³, state # q[1]=x, q[2]=y, q[3]=v + + z ∈ R³, state u ∈ R, control - q(t0) == [x0, y0, v0] - q(tf)[1] == xf - q(tf)[2] == yf - # q(tf)[3] libre + + z(t0) == [x0, y0, v0] + + z(tf)[1] == xf + z(tf)[2] == yf + 0.1 ≤ tf ≤ 20.0 - q̇(t)[1] == q(t)[3] * sin(u(t)) # dx/dt - q̇(t)[2] == q(t)[3] * cos(u(t)) # dy/dt - q̇(t)[3] == g * cos(u(t)) # dv/dt + + z'(t)[1] == z(t)[3] * sin(u(t)) # dx/dt + z'(t)[2] == z(t)[3] * cos(u(t)) # dy/dt + z'(t)[3] == g * cos(u(t)) # dv/dt tf → min end diff --git a/ext/OptimalControlModels_s/brachistochrone_s.jl b/ext/OptimalControlModels_s/brachistochrone_s.jl index 58c0d27b..96912f62 100644 --- a/ext/OptimalControlModels_s/brachistochrone_s.jl +++ b/ext/OptimalControlModels_s/brachistochrone_s.jl @@ -50,20 +50,20 @@ function OptimalControlProblems.brachistochrone_s( tf ∈ R, variable t ∈ [t0, tf], time - q ∈ R³, state + z ∈ R³, state u ∈ R, control - q(t0) == [x0, y0, v0] + z(t0) == [x0, y0, v0] - q(tf)[1] == xf - q(tf)[2] == yf + z(tf)[1] == xf + z(tf)[2] == yf 0.1 ≤ tf ≤ 20.0 - ∂(q)(t)[1] == q(t)[3] * sin(u(t)) - ∂(q)(t)[2] == q(t)[3] * cos(u(t)) - ∂(q)(t)[3] == g * cos(u(t)) + ∂(z)(t)[1] == z(t)[3] * sin(u(t)) + ∂(z)(t)[2] == z(t)[3] * cos(u(t)) + ∂(z)(t)[3] == g * cos(u(t)) tf → min end From ed3a8c32956fa4c74fd9e5e747571e7c2ae260af Mon Sep 17 00:00:00 2001 From: Amiel Date: Sun, 8 Feb 2026 10:56:06 +0100 Subject: [PATCH 09/24] fix bug 8 --- ext/OptimalControlModels/brachistochrone.jl | 19 ++++++------------- .../brachistochrone_s.jl | 13 +++++-------- 2 files changed, 11 insertions(+), 21 deletions(-) diff --git a/ext/OptimalControlModels/brachistochrone.jl b/ext/OptimalControlModels/brachistochrone.jl index 71bf3f41..1c9645c7 100644 --- a/ext/OptimalControlModels/brachistochrone.jl +++ b/ext/OptimalControlModels/brachistochrone.jl @@ -36,24 +36,17 @@ function OptimalControlProblems.brachistochrone( tf ∈ R, variable t ∈ [t0, tf], time - - z ∈ R³, state - + A ∈ R³, state u ∈ R, control - - z(t0) == [x0, y0, v0] - - z(tf)[1] == xf - z(tf)[2] == yf - + A(t0) == [x0, y0, v0] + + A(tf)[1] == xf + A(tf)[2] == yf 0.1 ≤ tf ≤ 20.0 - - z'(t)[1] == z(t)[3] * sin(u(t)) # dx/dt - z'(t)[2] == z(t)[3] * cos(u(t)) # dy/dt - z'(t)[3] == g * cos(u(t)) # dv/dt + A'(t) == [ A(t)[3] * sin(u(t)), A(t)[3] * cos(u(t)), g * cos(u(t)) ] tf → min end diff --git a/ext/OptimalControlModels_s/brachistochrone_s.jl b/ext/OptimalControlModels_s/brachistochrone_s.jl index 96912f62..9d73bf87 100644 --- a/ext/OptimalControlModels_s/brachistochrone_s.jl +++ b/ext/OptimalControlModels_s/brachistochrone_s.jl @@ -50,20 +50,17 @@ function OptimalControlProblems.brachistochrone_s( tf ∈ R, variable t ∈ [t0, tf], time - z ∈ R³, state - + A ∈ R³, state u ∈ R, control - z(t0) == [x0, y0, v0] + A(t0) == [x0, y0, v0] - z(tf)[1] == xf - z(tf)[2] == yf + A(tf)[1] == xf + A(tf)[2] == yf 0.1 ≤ tf ≤ 20.0 - ∂(z)(t)[1] == z(t)[3] * sin(u(t)) - ∂(z)(t)[2] == z(t)[3] * cos(u(t)) - ∂(z)(t)[3] == g * cos(u(t)) + ∂(A)(t) == [ A(t)[3] * sin(u(t)), A(t)[3] * cos(u(t)), g * cos(u(t)) ] tf → min end From eaa014a7e8349e3e90325b2ec62c9bd613d2a889 Mon Sep 17 00:00:00 2001 From: Amiel Date: Sun, 8 Feb 2026 11:01:30 +0100 Subject: [PATCH 10/24] fix bug 9 --- ext/OptimalControlModels/brachistochrone.jl | 12 ++++++------ ext/OptimalControlModels_s/brachistochrone_s.jl | 10 +++++----- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/ext/OptimalControlModels/brachistochrone.jl b/ext/OptimalControlModels/brachistochrone.jl index 1c9645c7..f59519b7 100644 --- a/ext/OptimalControlModels/brachistochrone.jl +++ b/ext/OptimalControlModels/brachistochrone.jl @@ -36,17 +36,17 @@ function OptimalControlProblems.brachistochrone( tf ∈ R, variable t ∈ [t0, tf], time - A ∈ R³, state + x ∈ R³, state u ∈ R, control - A(t0) == [x0, y0, v0] + x(t0) == [x0, y0, v0] + + x₁(tf) == xf + x₂(tf) == yf - A(tf)[1] == xf - A(tf)[2] == yf - 0.1 ≤ tf ≤ 20.0 - A'(t) == [ A(t)[3] * sin(u(t)), A(t)[3] * cos(u(t)), g * cos(u(t)) ] + ẋ(t) == [ x₃(t) * sin(u(t)), x₃(t) * cos(u(t)), g * cos(u(t)) ] tf → min end diff --git a/ext/OptimalControlModels_s/brachistochrone_s.jl b/ext/OptimalControlModels_s/brachistochrone_s.jl index 9d73bf87..66d74692 100644 --- a/ext/OptimalControlModels_s/brachistochrone_s.jl +++ b/ext/OptimalControlModels_s/brachistochrone_s.jl @@ -50,17 +50,17 @@ function OptimalControlProblems.brachistochrone_s( tf ∈ R, variable t ∈ [t0, tf], time - A ∈ R³, state + x ∈ R³, state u ∈ R, control - A(t0) == [x0, y0, v0] + x(t0) == [x0, y0, v0] - A(tf)[1] == xf - A(tf)[2] == yf + x₁(tf) == xf + x₂(tf) == yf 0.1 ≤ tf ≤ 20.0 - ∂(A)(t) == [ A(t)[3] * sin(u(t)), A(t)[3] * cos(u(t)), g * cos(u(t)) ] + ∂(x)(t) == [ x₃(t) * sin(u(t)), x₃(t) * cos(u(t)), g * cos(u(t)) ] tf → min end From 8bbfbd877f31413f9308183895af53f0495cbafd Mon Sep 17 00:00:00 2001 From: Amiel Date: Sun, 8 Feb 2026 11:07:05 +0100 Subject: [PATCH 11/24] bug fix 9 --- ext/OptimalControlModels/brachistochrone.jl | 4 ++-- ext/OptimalControlModels_s/brachistochrone_s.jl | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ext/OptimalControlModels/brachistochrone.jl b/ext/OptimalControlModels/brachistochrone.jl index f59519b7..717d0bdf 100644 --- a/ext/OptimalControlModels/brachistochrone.jl +++ b/ext/OptimalControlModels/brachistochrone.jl @@ -36,14 +36,14 @@ function OptimalControlProblems.brachistochrone( tf ∈ R, variable t ∈ [t0, tf], time - x ∈ R³, state + x ∈ R³, state u ∈ R, control x(t0) == [x0, y0, v0] x₁(tf) == xf x₂(tf) == yf - + 0.1 ≤ tf ≤ 20.0 ẋ(t) == [ x₃(t) * sin(u(t)), x₃(t) * cos(u(t)), g * cos(u(t)) ] diff --git a/ext/OptimalControlModels_s/brachistochrone_s.jl b/ext/OptimalControlModels_s/brachistochrone_s.jl index 66d74692..43035c12 100644 --- a/ext/OptimalControlModels_s/brachistochrone_s.jl +++ b/ext/OptimalControlModels_s/brachistochrone_s.jl @@ -60,7 +60,7 @@ function OptimalControlProblems.brachistochrone_s( 0.1 ≤ tf ≤ 20.0 - ∂(x)(t) == [ x₃(t) * sin(u(t)), x₃(t) * cos(u(t)), g * cos(u(t)) ] + ẋ(t) == [ x₃(t) * sin(u(t)), x₃(t) * cos(u(t)), g * cos(u(t)) ] tf → min end From 3db0289263382f8ff88dd35e659f8855b0d86f82 Mon Sep 17 00:00:00 2001 From: Amiel Date: Sun, 8 Feb 2026 11:19:23 +0100 Subject: [PATCH 12/24] vsy claude ! --- ext/OptimalControlModels/brachistochrone.jl | 4 +++- ext/OptimalControlModels_s/brachistochrone_s.jl | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/ext/OptimalControlModels/brachistochrone.jl b/ext/OptimalControlModels/brachistochrone.jl index 717d0bdf..912d0161 100644 --- a/ext/OptimalControlModels/brachistochrone.jl +++ b/ext/OptimalControlModels/brachistochrone.jl @@ -46,7 +46,9 @@ function OptimalControlProblems.brachistochrone( 0.1 ≤ tf ≤ 20.0 - ẋ(t) == [ x₃(t) * sin(u(t)), x₃(t) * cos(u(t)), g * cos(u(t)) ] + ẋ₁(t) == x₃(t) * sin(u(t)) + ẋ₂(t) == x₃(t) * cos(u(t)) + ẋ₃(t) == g * cos(u(t)) tf → min end diff --git a/ext/OptimalControlModels_s/brachistochrone_s.jl b/ext/OptimalControlModels_s/brachistochrone_s.jl index 43035c12..89f77018 100644 --- a/ext/OptimalControlModels_s/brachistochrone_s.jl +++ b/ext/OptimalControlModels_s/brachistochrone_s.jl @@ -60,7 +60,9 @@ function OptimalControlProblems.brachistochrone_s( 0.1 ≤ tf ≤ 20.0 - ẋ(t) == [ x₃(t) * sin(u(t)), x₃(t) * cos(u(t)), g * cos(u(t)) ] + ẋ₁(t) == x₃(t) * sin(u(t)) + ẋ₂(t) == x₃(t) * cos(u(t)) + ẋ₃(t) == g * cos(u(t)) tf → min end From 6364334b0291e020eae10974ec8e6c3a14de9418 Mon Sep 17 00:00:00 2001 From: Amiel Date: Sun, 8 Feb 2026 11:25:25 +0100 Subject: [PATCH 13/24] claude 2 --- ext/OptimalControlModels/brachistochrone.jl | 8 ++++++-- ext/OptimalControlModels_s/brachistochrone_s.jl | 9 ++++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/ext/OptimalControlModels/brachistochrone.jl b/ext/OptimalControlModels/brachistochrone.jl index 912d0161..deb7c9de 100644 --- a/ext/OptimalControlModels/brachistochrone.jl +++ b/ext/OptimalControlModels/brachistochrone.jl @@ -36,10 +36,14 @@ function OptimalControlProblems.brachistochrone( tf ∈ R, variable t ∈ [t0, tf], time - x ∈ R³, state + x₁ ∈ R, state + x₂ ∈ R, state + x₃ ∈ R, state u ∈ R, control - x(t0) == [x0, y0, v0] + x₁(t0) == x0 + x₂(t0) == y0 + x₃(t0) == v0 x₁(tf) == xf x₂(tf) == yf diff --git a/ext/OptimalControlModels_s/brachistochrone_s.jl b/ext/OptimalControlModels_s/brachistochrone_s.jl index 89f77018..dc7e536b 100644 --- a/ext/OptimalControlModels_s/brachistochrone_s.jl +++ b/ext/OptimalControlModels_s/brachistochrone_s.jl @@ -16,7 +16,6 @@ It then performs direct transcription to generate a discrete optimal control pro - `docp`: The direct optimal control problem object, representing the discretised problem. # Example - ```julia-repl julia> using OptimalControlProblems @@ -50,10 +49,14 @@ function OptimalControlProblems.brachistochrone_s( tf ∈ R, variable t ∈ [t0, tf], time - x ∈ R³, state + x₁ ∈ R, state + x₂ ∈ R, state + x₃ ∈ R, state u ∈ R, control - x(t0) == [x0, y0, v0] + x₁(t0) == x0 + x₂(t0) == y0 + x₃(t0) == v0 x₁(tf) == xf x₂(tf) == yf From a4b81193beee495268a7c8e91beba1bddcaa0b3d Mon Sep 17 00:00:00 2001 From: Amiel Date: Wed, 11 Feb 2026 09:53:29 +0100 Subject: [PATCH 14/24] test --- ext/OptimalControlModels/brachistochrone.jl | 9 ++------- ext/OptimalControlModels_s/brachistochrone_s.jl | 8 ++------ 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/ext/OptimalControlModels/brachistochrone.jl b/ext/OptimalControlModels/brachistochrone.jl index deb7c9de..de089445 100644 --- a/ext/OptimalControlModels/brachistochrone.jl +++ b/ext/OptimalControlModels/brachistochrone.jl @@ -8,7 +8,6 @@ The goal is to move from point A to point B in minimum time under gravity. - `::OptimalControlBackend`: The backend type. - `grid_size`: Number of time steps. - `parameters`: Optional parameter overrides. - ```julia-repl julia> using OptimalControlProblems @@ -36,14 +35,10 @@ function OptimalControlProblems.brachistochrone( tf ∈ R, variable t ∈ [t0, tf], time - x₁ ∈ R, state - x₂ ∈ R, state - x₃ ∈ R, state + x = (x₁, x₂, x₃) ∈ R³, state u ∈ R, control - x₁(t0) == x0 - x₂(t0) == y0 - x₃(t0) == v0 + x(t0) == [x0, y0, v0] x₁(tf) == xf x₂(tf) == yf diff --git a/ext/OptimalControlModels_s/brachistochrone_s.jl b/ext/OptimalControlModels_s/brachistochrone_s.jl index dc7e536b..a7decf85 100644 --- a/ext/OptimalControlModels_s/brachistochrone_s.jl +++ b/ext/OptimalControlModels_s/brachistochrone_s.jl @@ -49,14 +49,10 @@ function OptimalControlProblems.brachistochrone_s( tf ∈ R, variable t ∈ [t0, tf], time - x₁ ∈ R, state - x₂ ∈ R, state - x₃ ∈ R, state + x = (x₁, x₂, x₃) ∈ R³, state u ∈ R, control - x₁(t0) == x0 - x₂(t0) == y0 - x₃(t0) == v0 + x(t0) == [x0, y0, v0] x₁(tf) == xf x₂(tf) == yf From 88113301d99a2f885d34ed3849dbe8f24402d1df Mon Sep 17 00:00:00 2001 From: Amiel Date: Wed, 11 Feb 2026 10:16:46 +0100 Subject: [PATCH 15/24] test 2 --- ext/OptimalControlModels/brachistochrone.jl | 2 +- ext/OptimalControlModels_s/brachistochrone_s.jl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/OptimalControlModels/brachistochrone.jl b/ext/OptimalControlModels/brachistochrone.jl index de089445..43437767 100644 --- a/ext/OptimalControlModels/brachistochrone.jl +++ b/ext/OptimalControlModels/brachistochrone.jl @@ -35,7 +35,7 @@ function OptimalControlProblems.brachistochrone( tf ∈ R, variable t ∈ [t0, tf], time - x = (x₁, x₂, x₃) ∈ R³, state + x ∈ R³, state u ∈ R, control x(t0) == [x0, y0, v0] diff --git a/ext/OptimalControlModels_s/brachistochrone_s.jl b/ext/OptimalControlModels_s/brachistochrone_s.jl index a7decf85..e078fb95 100644 --- a/ext/OptimalControlModels_s/brachistochrone_s.jl +++ b/ext/OptimalControlModels_s/brachistochrone_s.jl @@ -49,7 +49,7 @@ function OptimalControlProblems.brachistochrone_s( tf ∈ R, variable t ∈ [t0, tf], time - x = (x₁, x₂, x₃) ∈ R³, state + x ∈ R³, state u ∈ R, control x(t0) == [x0, y0, v0] From 8fc7ca56a7416a5e5da77bc19edffe96cc996f24 Mon Sep 17 00:00:00 2001 From: Amiel Date: Wed, 11 Feb 2026 10:26:23 +0100 Subject: [PATCH 16/24] test 3 --- ext/OptimalControlModels/brachistochrone.jl | 12 +++++++----- ext/OptimalControlModels_s/brachistochrone_s.jl | 12 +++++++----- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/ext/OptimalControlModels/brachistochrone.jl b/ext/OptimalControlModels/brachistochrone.jl index 43437767..850c43cf 100644 --- a/ext/OptimalControlModels/brachistochrone.jl +++ b/ext/OptimalControlModels/brachistochrone.jl @@ -35,23 +35,25 @@ function OptimalControlProblems.brachistochrone( tf ∈ R, variable t ∈ [t0, tf], time - x ∈ R³, state + z = (x₁, x₂, x₃) ∈ R³, state u ∈ R, control - x(t0) == [x0, y0, v0] + z(t0) == [x0, y0, v0] x₁(tf) == xf x₂(tf) == yf 0.1 ≤ tf ≤ 20.0 - ẋ₁(t) == x₃(t) * sin(u(t)) - ẋ₂(t) == x₃(t) * cos(u(t)) - ẋ₃(t) == g * cos(u(t)) + ż(t) == dynamics(x₃(t), u(t), g) tf → min end + function dynamics(x₃, u, g) + return [x₃ * sin(u), x₃ * cos(u), g * cos(u)] + end + init = ( state = [5.0, 7.5, 5.0], control = 1.5, diff --git a/ext/OptimalControlModels_s/brachistochrone_s.jl b/ext/OptimalControlModels_s/brachistochrone_s.jl index e078fb95..e9888425 100644 --- a/ext/OptimalControlModels_s/brachistochrone_s.jl +++ b/ext/OptimalControlModels_s/brachistochrone_s.jl @@ -49,23 +49,25 @@ function OptimalControlProblems.brachistochrone_s( tf ∈ R, variable t ∈ [t0, tf], time - x ∈ R³, state + z = (x₁, x₂, x₃) ∈ R³, state u ∈ R, control - x(t0) == [x0, y0, v0] + z(t0) == [x0, y0, v0] x₁(tf) == xf x₂(tf) == yf 0.1 ≤ tf ≤ 20.0 - ẋ₁(t) == x₃(t) * sin(u(t)) - ẋ₂(t) == x₃(t) * cos(u(t)) - ẋ₃(t) == g * cos(u(t)) + ż(t) == dynamics(x₃(t), u(t), g) tf → min end + function dynamics(x₃, u, g) + return [x₃ * sin(u), x₃ * cos(u), g * cos(u)] + end + # initial guess init = ( state = [5.0, 7.5, 5.0], From 2f13b0d75043b21b4d6701b02c30c94fc04496bd Mon Sep 17 00:00:00 2001 From: Amiel Date: Wed, 11 Feb 2026 10:33:22 +0100 Subject: [PATCH 17/24] test 4 --- ext/OptimalControlModels/brachistochrone.jl | 4 +++- ext/OptimalControlModels_s/brachistochrone_s.jl | 7 ++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/ext/OptimalControlModels/brachistochrone.jl b/ext/OptimalControlModels/brachistochrone.jl index 850c43cf..4204cf15 100644 --- a/ext/OptimalControlModels/brachistochrone.jl +++ b/ext/OptimalControlModels/brachistochrone.jl @@ -45,7 +45,9 @@ function OptimalControlProblems.brachistochrone( 0.1 ≤ tf ≤ 20.0 - ż(t) == dynamics(x₃(t), u(t), g) + ẋ₁(t) == x₃(t) * sin(u(t)) + ẋ₂(t) == x₃(t) * cos(u(t)) + ẋ₃(t) == g * cos(u(t)) tf → min end diff --git a/ext/OptimalControlModels_s/brachistochrone_s.jl b/ext/OptimalControlModels_s/brachistochrone_s.jl index e9888425..891aa4fd 100644 --- a/ext/OptimalControlModels_s/brachistochrone_s.jl +++ b/ext/OptimalControlModels_s/brachistochrone_s.jl @@ -45,7 +45,6 @@ function OptimalControlProblems.brachistochrone_s( # model ocp = @def begin - tf ∈ R, variable t ∈ [t0, tf], time @@ -57,9 +56,11 @@ function OptimalControlProblems.brachistochrone_s( x₁(tf) == xf x₂(tf) == yf - 0.1 ≤ tf ≤ 20.0 + 0.1 ≤ tf ≤ 20.0 - ż(t) == dynamics(x₃(t), u(t), g) + ẋ₁(t) == x₃(t) * sin(u(t)) + ẋ₂(t) == x₃(t) * cos(u(t)) + ẋ₃(t) == g * cos(u(t)) tf → min end From f1c2edf601988b9e54d65b5fbeec40c4e49e7fff Mon Sep 17 00:00:00 2001 From: Amiel Date: Wed, 11 Feb 2026 10:37:25 +0100 Subject: [PATCH 18/24] test 5 --- ext/OptimalControlModels/brachistochrone.jl | 8 ++------ ext/OptimalControlModels_s/brachistochrone_s.jl | 11 ++++------- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/ext/OptimalControlModels/brachistochrone.jl b/ext/OptimalControlModels/brachistochrone.jl index 4204cf15..de089445 100644 --- a/ext/OptimalControlModels/brachistochrone.jl +++ b/ext/OptimalControlModels/brachistochrone.jl @@ -35,10 +35,10 @@ function OptimalControlProblems.brachistochrone( tf ∈ R, variable t ∈ [t0, tf], time - z = (x₁, x₂, x₃) ∈ R³, state + x = (x₁, x₂, x₃) ∈ R³, state u ∈ R, control - z(t0) == [x0, y0, v0] + x(t0) == [x0, y0, v0] x₁(tf) == xf x₂(tf) == yf @@ -52,10 +52,6 @@ function OptimalControlProblems.brachistochrone( tf → min end - function dynamics(x₃, u, g) - return [x₃ * sin(u), x₃ * cos(u), g * cos(u)] - end - init = ( state = [5.0, 7.5, 5.0], control = 1.5, diff --git a/ext/OptimalControlModels_s/brachistochrone_s.jl b/ext/OptimalControlModels_s/brachistochrone_s.jl index 891aa4fd..a7decf85 100644 --- a/ext/OptimalControlModels_s/brachistochrone_s.jl +++ b/ext/OptimalControlModels_s/brachistochrone_s.jl @@ -45,18 +45,19 @@ function OptimalControlProblems.brachistochrone_s( # model ocp = @def begin + tf ∈ R, variable t ∈ [t0, tf], time - z = (x₁, x₂, x₃) ∈ R³, state + x = (x₁, x₂, x₃) ∈ R³, state u ∈ R, control - z(t0) == [x0, y0, v0] + x(t0) == [x0, y0, v0] x₁(tf) == xf x₂(tf) == yf - 0.1 ≤ tf ≤ 20.0 + 0.1 ≤ tf ≤ 20.0 ẋ₁(t) == x₃(t) * sin(u(t)) ẋ₂(t) == x₃(t) * cos(u(t)) @@ -65,10 +66,6 @@ function OptimalControlProblems.brachistochrone_s( tf → min end - function dynamics(x₃, u, g) - return [x₃ * sin(u), x₃ * cos(u), g * cos(u)] - end - # initial guess init = ( state = [5.0, 7.5, 5.0], From c3d34108bc9dc764bb2d7dc7be4cc127fcd61afb Mon Sep 17 00:00:00 2001 From: Amiel Date: Wed, 11 Feb 2026 10:42:04 +0100 Subject: [PATCH 19/24] test 6 --- ext/OptimalControlModels/brachistochrone.jl | 14 +++++++------- ext/OptimalControlModels_s/brachistochrone_s.jl | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/ext/OptimalControlModels/brachistochrone.jl b/ext/OptimalControlModels/brachistochrone.jl index de089445..ebef9787 100644 --- a/ext/OptimalControlModels/brachistochrone.jl +++ b/ext/OptimalControlModels/brachistochrone.jl @@ -35,19 +35,19 @@ function OptimalControlProblems.brachistochrone( tf ∈ R, variable t ∈ [t0, tf], time - x = (x₁, x₂, x₃) ∈ R³, state + z = (px, py, v) ∈ R³, state u ∈ R, control - x(t0) == [x0, y0, v0] + z(t0) == [x0, y0, v0] - x₁(tf) == xf - x₂(tf) == yf + px(tf) == xf + py(tf) == yf 0.1 ≤ tf ≤ 20.0 - ẋ₁(t) == x₃(t) * sin(u(t)) - ẋ₂(t) == x₃(t) * cos(u(t)) - ẋ₃(t) == g * cos(u(t)) + ṗx(t) == v(t) * sin(u(t)) + ṗy(t) == v(t) * cos(u(t)) + v̇(t) == g * cos(u(t)) tf → min end diff --git a/ext/OptimalControlModels_s/brachistochrone_s.jl b/ext/OptimalControlModels_s/brachistochrone_s.jl index a7decf85..fdaafff4 100644 --- a/ext/OptimalControlModels_s/brachistochrone_s.jl +++ b/ext/OptimalControlModels_s/brachistochrone_s.jl @@ -49,19 +49,19 @@ function OptimalControlProblems.brachistochrone_s( tf ∈ R, variable t ∈ [t0, tf], time - x = (x₁, x₂, x₃) ∈ R³, state + z = (px, py, v) ∈ R³, state u ∈ R, control - x(t0) == [x0, y0, v0] + z(t0) == [x0, y0, v0] - x₁(tf) == xf - x₂(tf) == yf + px(tf) == xf + py(tf) == yf 0.1 ≤ tf ≤ 20.0 - ẋ₁(t) == x₃(t) * sin(u(t)) - ẋ₂(t) == x₃(t) * cos(u(t)) - ẋ₃(t) == g * cos(u(t)) + ṗx(t) == v(t) * sin(u(t)) + ṗy(t) == v(t) * cos(u(t)) + v̇(t) == g * cos(u(t)) tf → min end From 31f0be7ea03283edb2c20718b31c67c6ac307464 Mon Sep 17 00:00:00 2001 From: Amiel Date: Thu, 12 Feb 2026 09:23:25 +0100 Subject: [PATCH 20/24] normalement c'est bon ! --- ext/OptimalControlModels/brachistochrone.jl | 43 +++++++++++++------ .../brachistochrone_s.jl | 11 +++-- 2 files changed, 36 insertions(+), 18 deletions(-) diff --git a/ext/OptimalControlModels/brachistochrone.jl b/ext/OptimalControlModels/brachistochrone.jl index ebef9787..4be0533f 100644 --- a/ext/OptimalControlModels/brachistochrone.jl +++ b/ext/OptimalControlModels/brachistochrone.jl @@ -1,18 +1,30 @@ """ $(TYPEDSIGNATURES) -Constructs the **Brachistochrone** optimal control problem. -The goal is to move from point A to point B in minimum time under gravity. +Constructs an **OptimalControl problem** representing the Brachistochrone problem using the OptimalControl backend. +The function sets up the state and control variables, boundary conditions, dynamics, and the objective functional. +It then performs direct transcription to generate a discrete optimal control problem (DOCP). # Arguments -- `::OptimalControlBackend`: The backend type. -- `grid_size`: Number of time steps. -- `parameters`: Optional parameter overrides. + +- `::OptimalControlBackend`: Placeholder type to specify the OptimalControl backend or solver interface. +- `grid_size::Int=grid_size_data(:brachistochrone)`: (Keyword) Number of discretisation points for the direct transcription grid. +- `parameters::Union{Nothing,NamedTuple}=nothing`: (Keyword) Custom parameters to override defaults. + +# Returns + +- `docp`: The direct optimal control problem object, representing the discretised problem. + +# Example ```julia-repl julia> using OptimalControlProblems julia> docp = OptimalControlProblems.brachistochrone(OptimalControlBackend(); N=100); ``` + +# References + +- Dymos Brachistochrone: https://openmdao.github.io/dymos/examples/brachistochrone/brachistochrone.html """ function OptimalControlProblems.brachistochrone( ::OptimalControlBackend, @@ -34,27 +46,30 @@ function OptimalControlProblems.brachistochrone( ocp = @def begin tf ∈ R, variable t ∈ [t0, tf], time - + z = (px, py, v) ∈ R³, state u ∈ R, control - z(t0) == [x0, y0, v0] + 0.1 ≤ tf ≤ 20.0 + + px(t0) == x0 + py(t0) == y0 + v(t0) == v0 px(tf) == xf py(tf) == yf - 0.1 ≤ tf ≤ 20.0 - - ṗx(t) == v(t) * sin(u(t)) - ṗy(t) == v(t) * cos(u(t)) - v̇(t) == g * cos(u(t)) + ∂(px)(t) == v(t) * sin(u(t)) + ∂(py)(t) == v(t) * cos(u(t)) + ∂(v)(t) == g * cos(u(t)) + # Objectif tf → min end init = ( - state = [5.0, 7.5, 5.0], - control = 1.5, + state = [x0, y0, v0], + control = 0.0, variable = 1.0 ) diff --git a/ext/OptimalControlModels_s/brachistochrone_s.jl b/ext/OptimalControlModels_s/brachistochrone_s.jl index fdaafff4..73b1d900 100644 --- a/ext/OptimalControlModels_s/brachistochrone_s.jl +++ b/ext/OptimalControlModels_s/brachistochrone_s.jl @@ -49,26 +49,29 @@ function OptimalControlProblems.brachistochrone_s( tf ∈ R, variable t ∈ [t0, tf], time + z = (px, py, v) ∈ R³, state u ∈ R, control + z(t0) == [x0, y0, v0] + px(tf) == xf py(tf) == yf 0.1 ≤ tf ≤ 20.0 - ṗx(t) == v(t) * sin(u(t)) - ṗy(t) == v(t) * cos(u(t)) - v̇(t) == g * cos(u(t)) + ∂(px)(t) == v(t) * sin(u(t)) + ∂(py)(t) == v(t) * cos(u(t)) + ∂(v)(t) == g * cos(u(t)) tf → min end # initial guess init = ( - state = [5.0, 7.5, 5.0], + state = [x0, y0, v0], control = 1.57, variable = 2.0 ) From 82493ebc4ca00083b1d289c5595f6d6c61707263 Mon Sep 17 00:00:00 2001 From: Amiel Date: Thu, 12 Feb 2026 11:57:02 +0100 Subject: [PATCH 21/24] gemini cli --- ext/JuMPModels/brachistochrone.jl | 4 ++-- ext/OptimalControlModels/brachistochrone.jl | 2 +- ext/OptimalControlModels_s/brachistochrone_s.jl | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ext/JuMPModels/brachistochrone.jl b/ext/JuMPModels/brachistochrone.jl index 7d56ff07..acfc36ca 100644 --- a/ext/JuMPModels/brachistochrone.jl +++ b/ext/JuMPModels/brachistochrone.jl @@ -106,8 +106,8 @@ function OptimalControlProblems.brachistochrone( # dx/dt = v * sin(u) dx[i = 0:N], v[i] * sin(u[i]) - # dy/dt = v * cos(u) - dy[i = 0:N], v[i] * cos(u[i]) + # dy/dt = -v * cos(u) + dy[i = 0:N], -v[i] * cos(u[i]) # dv/dt = g * cos(u) dv[i = 0:N], g * cos(u[i]) diff --git a/ext/OptimalControlModels/brachistochrone.jl b/ext/OptimalControlModels/brachistochrone.jl index 4be0533f..42cc77e9 100644 --- a/ext/OptimalControlModels/brachistochrone.jl +++ b/ext/OptimalControlModels/brachistochrone.jl @@ -60,7 +60,7 @@ function OptimalControlProblems.brachistochrone( py(tf) == yf ∂(px)(t) == v(t) * sin(u(t)) - ∂(py)(t) == v(t) * cos(u(t)) + ∂(py)(t) == -v(t) * cos(u(t)) ∂(v)(t) == g * cos(u(t)) # Objectif diff --git a/ext/OptimalControlModels_s/brachistochrone_s.jl b/ext/OptimalControlModels_s/brachistochrone_s.jl index 73b1d900..27374799 100644 --- a/ext/OptimalControlModels_s/brachistochrone_s.jl +++ b/ext/OptimalControlModels_s/brachistochrone_s.jl @@ -63,7 +63,7 @@ function OptimalControlProblems.brachistochrone_s( 0.1 ≤ tf ≤ 20.0 ∂(px)(t) == v(t) * sin(u(t)) - ∂(py)(t) == v(t) * cos(u(t)) + ∂(py)(t) == -v(t) * cos(u(t)) ∂(v)(t) == g * cos(u(t)) tf → min From ad0f6d43ccdef449ef9099ba49d4dce4d29528f6 Mon Sep 17 00:00:00 2001 From: Amiel Date: Thu, 12 Feb 2026 18:20:00 +0100 Subject: [PATCH 22/24] bug jump --- ext/JuMPModels/brachistochrone.jl | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/ext/JuMPModels/brachistochrone.jl b/ext/JuMPModels/brachistochrone.jl index acfc36ca..32f54b76 100644 --- a/ext/JuMPModels/brachistochrone.jl +++ b/ext/JuMPModels/brachistochrone.jl @@ -64,10 +64,7 @@ function OptimalControlProblems.brachistochrone( model[:time_grid] = () -> range(t0, value(tf), N+1) model[:state_components] = ["x", "y", "v"] - - model[:costate_components] = String[] - # ---------------------- - + model[:costate_components] = ["∂x", "∂y", "∂v"] model[:control_components] = ["u"] model[:variable_components] = ["tf"] From a379ed5f90bba2ca122f9a12f1d01330be2a7178 Mon Sep 17 00:00:00 2001 From: Amiel Date: Thu, 12 Feb 2026 18:39:01 +0100 Subject: [PATCH 23/24] c'est bon ! --- ext/JuMPModels/brachistochrone.jl | 32 ++++++++++----------- ext/OptimalControlModels/brachistochrone.jl | 6 ++-- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/ext/JuMPModels/brachistochrone.jl b/ext/JuMPModels/brachistochrone.jl index 32f54b76..71319d34 100644 --- a/ext/JuMPModels/brachistochrone.jl +++ b/ext/JuMPModels/brachistochrone.jl @@ -54,8 +54,8 @@ function OptimalControlProblems.brachistochrone( model, begin 0.1 <= tf <= 20.0, (start = 2.0) - x[0:N] - y[0:N] + px[0:N] + py[0:N] v[0:N] u[0:N] end @@ -63,15 +63,15 @@ function OptimalControlProblems.brachistochrone( model[:time_grid] = () -> range(t0, value(tf), N+1) - model[:state_components] = ["x", "y", "v"] - model[:costate_components] = ["∂x", "∂y", "∂v"] + model[:state_components] = ["px", "py", "v"] + model[:costate_components] = ["∂px", "∂py", "∂v"] model[:control_components] = ["u"] model[:variable_components] = ["tf"] for i in 0:N alpha = i / N - set_start_value(x[i], x0 + alpha * (xf - x0)) - set_start_value(y[i], y0 + alpha * (yf - y0)) + set_start_value(px[i], x0 + alpha * (xf - x0)) + set_start_value(py[i], y0 + alpha * (yf - y0)) set_start_value(v[i], v0 + alpha * 10.0) # Estimate speed set_start_value(u[i], 1.57) # ~90 degrees end @@ -81,13 +81,13 @@ function OptimalControlProblems.brachistochrone( model, begin # Start - x[0] == x0 - y[0] == y0 + px[0] == x0 + py[0] == y0 v[0] == v0 # End - x[N] == xf - y[N] == yf + px[N] == xf + py[N] == yf # v[N] is free end ) @@ -100,11 +100,11 @@ function OptimalControlProblems.brachistochrone( dt, (tf - t0) / N # Dynamics expressions (Dymos formulation) - # dx/dt = v * sin(u) - dx[i = 0:N], v[i] * sin(u[i]) + # dpx/dt = v * sin(u) + dpx[i = 0:N], v[i] * sin(u[i]) - # dy/dt = -v * cos(u) - dy[i = 0:N], -v[i] * cos(u[i]) + # dpy/dt = -v * cos(u) + dpy[i = 0:N], -v[i] * cos(u[i]) # dv/dt = g * cos(u) dv[i = 0:N], g * cos(u[i]) @@ -115,8 +115,8 @@ function OptimalControlProblems.brachistochrone( @constraints( model, begin - ∂x[i = 1:N], x[i] == x[i - 1] + 0.5 * dt * (dx[i] + dx[i - 1]) - ∂y[i = 1:N], y[i] == y[i - 1] + 0.5 * dt * (dy[i] + dy[i - 1]) + ∂px[i = 1:N], px[i] == px[i - 1] + 0.5 * dt * (dpx[i] + dpx[i - 1]) + ∂py[i = 1:N], py[i] == py[i - 1] + 0.5 * dt * (dpy[i] + dpy[i - 1]) ∂v[i = 1:N], v[i] == v[i - 1] + 0.5 * dt * (dv[i] + dv[i - 1]) end ) diff --git a/ext/OptimalControlModels/brachistochrone.jl b/ext/OptimalControlModels/brachistochrone.jl index 42cc77e9..4994fae7 100644 --- a/ext/OptimalControlModels/brachistochrone.jl +++ b/ext/OptimalControlModels/brachistochrone.jl @@ -69,15 +69,17 @@ function OptimalControlProblems.brachistochrone( init = ( state = [x0, y0, v0], - control = 0.0, - variable = 1.0 + control = 1.57, + variable = 2.0 ) docp = direct_transcription( ocp, description...; + lagrange_to_mayer=false, init = init, grid_size = grid_size, + disc_method=:trapeze, kwargs... ) From e47616a32e2d543fdb19f9d449cc31a3017933e5 Mon Sep 17 00:00:00 2001 From: Amiel Date: Thu, 12 Feb 2026 18:47:43 +0100 Subject: [PATCH 24/24] ok --- ext/OptimalControlModels/brachistochrone.jl | 12 +++++++++--- ext/OptimalControlModels_s/brachistochrone_s.jl | 11 ++++++++--- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/ext/OptimalControlModels/brachistochrone.jl b/ext/OptimalControlModels/brachistochrone.jl index 4994fae7..860ea7eb 100644 --- a/ext/OptimalControlModels/brachistochrone.jl +++ b/ext/OptimalControlModels/brachistochrone.jl @@ -67,10 +67,16 @@ function OptimalControlProblems.brachistochrone( tf → min end + # initial guess: linear interpolation to match JuMP + tf_guess = 2.0 init = ( - state = [x0, y0, v0], - control = 1.57, - variable = 2.0 + state = t -> [ + x0 + (t - t0) / (tf_guess - t0) * (xf - x0), + y0 + (t - t0) / (tf_guess - t0) * (yf - y0), + v0 + (t - t0) / (tf_guess - t0) * 10.0 + ], + control = 1.57, + variable = tf_guess ) docp = direct_transcription( diff --git a/ext/OptimalControlModels_s/brachistochrone_s.jl b/ext/OptimalControlModels_s/brachistochrone_s.jl index 27374799..8d46e45f 100644 --- a/ext/OptimalControlModels_s/brachistochrone_s.jl +++ b/ext/OptimalControlModels_s/brachistochrone_s.jl @@ -69,11 +69,16 @@ function OptimalControlProblems.brachistochrone_s( tf → min end - # initial guess + # initial guess: linear interpolation to match JuMP + tf_guess = 2.0 init = ( - state = [x0, y0, v0], + state = t -> [ + x0 + (t - t0) / (tf_guess - t0) * (xf - x0), + y0 + (t - t0) / (tf_guess - t0) * (yf - y0), + v0 + (t - t0) / (tf_guess - t0) * 10.0 + ], control = 1.57, - variable = 2.0 + variable = tf_guess ) # discretise the optimal control problem