-
Notifications
You must be signed in to change notification settings - Fork 1
add brachistochrone #207
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
add brachistochrone #207
Changes from 1 commit
Commits
Show all changes
46 commits
Select commit
Hold shift + click to select a range
461afdf
add brachistochrone
AmielMetier ad28d77
fix bug brachistochrone
AmielMetier dbdc30a
fix bug again
AmielMetier 38d1fdf
fix
AmielMetier 02dde16
add bryson problem
AmielMetier 20c5624
add balanced field problem
AmielMetier a022661
add moutain car problem
AmielMetier e986951
add glider, robot, space shuttle, steering , insurance problems
AmielMetier 6375ddc
remove exclude problem
AmielMetier c7ff089
fix moutain car 2000
AmielMetier 63e6a35
add cannonball problem
HediChennoufi 2e2dc52
Merge branch '206-dev-test-all-new-problems-with-gpu' of https://gith…
HediChennoufi d98cd48
Add water rocket problem
AmielMetier d7f905b
Merge branch '206-dev-test-all-new-problems-with-gpu' of https://gith…
AmielMetier 5f9ddd0
fix bug
AmielMetier 97276e3
fix bug 2
AmielMetier 59a9013
add ssto earth launch problem
HediChennoufi 921ae19
Merge branch '206-dev-test-all-new-problems-with-gpu' of https://gith…
HediChennoufi 89640fa
buf fix 3
AmielMetier 83d350d
Merge branch '206-dev-test-all-new-problems-with-gpu' of https://gith…
AmielMetier 4fc2cd0
fix
AmielMetier cb01381
fix
AmielMetier 590a790
fix ssto
HediChennoufi b16df7e
fix 2
AmielMetier bbf259f
refactor cannonball and water rocket models for consistency; update v…
HediChennoufi 6e3484b
fix 4
AmielMetier 5ac7f0b
test
HediChennoufi 33a5003
test
HediChennoufi 8bda115
test 2
HediChennoufi 3f7f979
derniere chance
AmielMetier 687df26
add to p2exclude
HediChennoufi f04e9ee
add2 to p2excl
HediChennoufi c38db15
Merge branches '206-dev-test-all-new-problems-with-gpu' and '206-dev-…
AmielMetier bdeebed
remove problem to exclude
AmielMetier 91122c0
new test ssto earth
HediChennoufi 92e5e22
new test ssto
HediChennoufi af6b0fd
olala ssto
HediChennoufi 7eb91c4
retest ssto
HediChennoufi db28e10
test new ssto
HediChennoufi 4498dc7
test f ssto
HediChennoufi f91f10c
remove problems no run
AmielMetier 4946430
Merge branch '206-dev-test-all-new-problems-with-gpu' of https://gith…
AmielMetier ffdb175
Add contributors AmielMetier and HediChennoufi
jbcaillau 8f6d361
Fix formatting issues in balanced_field.md
jbcaillau 423d9d9
Update mathematical optimization problem in markdown
jbcaillau f33ddf4
Refactor math problem statement in mountain_car.md
jbcaillau File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,128 @@ | ||
| """ | ||
| $(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(:brachistochrone), | ||
| parameters::Union{Nothing,NamedTuple}=nothing, | ||
| kwargs..., | ||
| ) | ||
|
|
||
| # parameters | ||
| params = parameters_data(: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) | ||
| px[0:N] | ||
| py[0:N] | ||
| v[0:N] | ||
| u[0:N] | ||
| end | ||
| ) | ||
|
|
||
|
|
||
| model[:time_grid] = () -> range(t0, value(tf), N+1) | ||
| 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(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 | ||
|
|
||
| # boundary constraints | ||
| @constraints( | ||
| model, | ||
| begin | ||
| # Start | ||
| px[0] == x0 | ||
| py[0] == y0 | ||
| v[0] == v0 | ||
|
|
||
| # End | ||
| px[N] == xf | ||
| py[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) | ||
| # dpx/dt = v * sin(u) | ||
| dpx[i = 0:N], v[i] * sin(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]) | ||
| end | ||
| ) | ||
|
|
||
| # Trapezoidal rule integration (Implicit) | ||
| @constraints( | ||
| model, | ||
| begin | ||
| ∂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 | ||
| ) | ||
|
|
||
| # objective: Minimize final time | ||
| @objective(model, Min, tf) | ||
|
|
||
| return model | ||
| end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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, | ||
| ), | ||
| ) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,93 @@ | ||
| """ | ||
| $(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(:brachistochrone), | ||
| parameters::Union{Nothing,NamedTuple}=nothing, | ||
| kwargs..., | ||
| ) | ||
|
|
||
| params = parameters_data(: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 | ||
|
|
||
| z = (px, py, v) ∈ R³, state | ||
| u ∈ R, control | ||
|
|
||
| 0.1 ≤ tf ≤ 20.0 | ||
|
|
||
| px(t0) == x0 | ||
| py(t0) == y0 | ||
| v(t0) == v0 | ||
|
|
||
| px(tf) == xf | ||
| py(tf) == yf | ||
|
|
||
| ∂(px)(t) == v(t) * sin(u(t)) | ||
| ∂(py)(t) == -v(t) * cos(u(t)) | ||
| ∂(v)(t) == g * cos(u(t)) | ||
|
|
||
| # Objectif | ||
| tf → min | ||
| end | ||
|
|
||
| # initial guess: linear interpolation to match JuMP | ||
| tf_guess = 2.0 | ||
| init = ( | ||
| 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( | ||
| ocp, | ||
| description...; | ||
| lagrange_to_mayer=false, | ||
| init = init, | ||
| grid_size = grid_size, | ||
| disc_method=:trapeze, | ||
| kwargs... | ||
| ) | ||
|
|
||
| return docp | ||
| end | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| """ | ||
| $(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_s( | ||
| ::OptimalControlBackend, | ||
| description::Symbol...; | ||
| grid_size::Int=grid_size_data(:brachistochrone), | ||
| parameters::Union{Nothing,NamedTuple}=nothing, | ||
| kwargs..., | ||
| ) | ||
|
|
||
| params = parameters_data(: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 | ||
|
|
||
|
|
||
| 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 | ||
|
|
||
| ∂(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: linear interpolation to match JuMP | ||
| tf_guess = 2.0 | ||
| init = ( | ||
| 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 | ||
| ) | ||
|
|
||
| # 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 |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The initial state guess divides by
tf_guess - t0, so overridingparameterswitht0 = 2.0(which the API allows) makes this denominator zero and yieldsNaN/Infin the initialization passed todirect_transcription. In that scenario the problem setup can fail before optimization starts; the same pattern appears in the_svariant too, so both backends are affected for this input.Useful? React with 👍 / 👎.