OptimalControl.jl icon indicating copy to clipboard operation
OptimalControl.jl copied to clipboard

Update basic example tutorial functional syntax

Open ocots opened this issue 1 year ago β€’ 14 comments

          When done, update https://control-toolbox.org/OptimalControl.jl/stable/tutorial-basic-example-f.html.

Originally posted by @ocots in https://github.com/control-toolbox/CTBase.jl/issues/204#issuecomment-2268966583

ocots avatar Aug 05 '24 12:08 ocots

Would it be possible to add the functional syntax also to the time minimisation problem? Many thanks

paolo-mgi avatar Aug 08 '24 23:08 paolo-mgi

Would it be possible to add the functional syntax also to the time minimisation problem? Many thanks

Ok I will add it.

We are interested by your feedback. Do you prefer to use the functional syntax rather than the abstract syntax? Could you explain why?

ocots avatar Aug 09 '24 08:08 ocots

Many thanks!

The main reason is that I feel that being able to use both syntaxes gives a better understanding of how the package is working.

Clearly there is something I am not understanding at the moment. Based on the basic example and the API I tried to rewrite the time minimization but I got an error indicatiing that I haven't defined correctly tf (abstract syntax works as expected instead).

Another reaon is that I am used to write notebooks with nteract where latex rendering is somewhat cumbersome (no tab completion). Probably I should move to Pluto but I have some inertia...

Thanks again for the swift reply and the very nice work!

paolo-mgi avatar Aug 09 '24 09:08 paolo-mgi

I was not aware of nteract. I write notebooks with vscode and in this case, you can easily write special characters.

In the next release, there will be a tutorial about the abstract syntax.

One can find some infos about the API of the Model function but it is not well indicated.

ocots avatar Aug 09 '24 12:08 ocots

Pin @jbcaillau.

ocots avatar Aug 12 '24 10:08 ocots

Hi @paolo-mgi thanks for the feedback. As indicated by @ocots the doc for abstract syntax is now available n dev and in a few hours 🀞🏾in the next release of OptimalControl.jl.

More specifically, regarding your points:

  • we're adding non unicode keywords so everything should fine, even within the abstract syntax https://github.com/control-toolbox/CTBase.jl/issues/239
  • you can always have a look at the generated functional code to guess, from the abstract form, what was needed (see example below)
julia> @macroexpand @def ocp begin

           tf ∈ R,          variable
           t ∈ [ 0, tf ],   time
           x = (q, v) ∈ R², state
           u ∈ R,           control

           tf β‰₯ 0
           -1 ≀ u(t) ≀ 1

           q(0)  == 1
           v(0)  == 2
           q(tf) == 0
           v(tf) == 0

            0 ≀ q(t) ≀ 5,          (1)
           -2 ≀ v(t) ≀ 3,          (2)

           ẋ(t) == [ v(t), u(t) ]

           tf β†’ min

       end
quote
    ocp = __OCPModel(variable = true)
    begin
        #= REPL[5]:3 =#
        begin
            #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:46 =#
            local ex
            #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:47 =#
            try
                #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:48 =#
                variable!(ocp, 1, :tf)
            catch ex
                #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:50 =#
                println("Line ", 1, ": ", "(tf ∈ R, variable)")
                #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:51 =#
                throw(ex)
            end
        end
        #= REPL[5]:4 =#
        begin
            #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:46 =#
            local ex
            #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:47 =#
            try
                #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:48 =#
                begin
                    #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:213 =#
                    ocp.variable_dimension β‰  1 && throw(IncorrectArgument("variable must be of dimension one for a time"))
                    #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:215 =#
                    time!(ocp; t0 = 0, indf = 1, name = :t)
                end
            catch ex
                #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:50 =#
                println("Line ", 2, ": ", "(t ∈ [0, tf], time)")
                #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:51 =#
                throw(ex)
            end
        end
        #= REPL[5]:5 =#
        begin
            #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:46 =#
            local ex
            #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:47 =#
            try
                #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:48 =#
                state!(ocp, 2, :x, $(QuoteNode(["q", "v"])))
            catch ex
                #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:50 =#
                println("Line ", 3, ": ", "x = ((q, v) ∈ R ^ 2, state)")
                #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:51 =#
                throw(ex)
            end
        end
        #= REPL[5]:6 =#
        begin
            #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:46 =#
            local ex
            #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:47 =#
            try
                #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:48 =#
                control!(ocp, 1, :u)
            catch ex
                #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:50 =#
                println("Line ", 4, ": ", "(u ∈ R, control)")
                #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:51 =#
                throw(ex)
            end
        end
        #= REPL[5]:8 =#
        begin
            #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:46 =#
            local ex
            #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:47 =#
            try
                #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:48 =#
                constraint!(ocp, :variable; rg = nothing, lb = 0, ub = nothing, label = Symbol("##261"))
            catch ex
                #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:50 =#
                println("Line ", 5, ": ", "tf β‰₯ 0")
                #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:51 =#
                throw(ex)
            end
        end
        #= REPL[5]:9 =#
        begin
            #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:46 =#
            local ex
            #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:47 =#
            try
                #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:48 =#
                constraint!(ocp, :control; rg = nothing, lb = -1, ub = 1, label = Symbol("##262"))
            catch ex
                #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:50 =#
                println("Line ", 6, ": ", "-1 ≀ u(t) ≀ 1")
                #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:51 =#
                throw(ex)
            end
        end
        #= REPL[5]:11 =#
        begin
            #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:46 =#
            local ex
            #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:47 =#
            try
                #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:48 =#
                constraint!(ocp, :initial; rg = 1, lb = 1, ub = 1, label = Symbol("##263"))
            catch ex
                #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:50 =#
                println("Line ", 7, ": ", "q(0) == 1")
                #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:51 =#
                throw(ex)
            end
        end
        #= REPL[5]:12 =#
        begin
            #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:46 =#
            local ex
            #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:47 =#
            try
                #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:48 =#
                constraint!(ocp, :initial; rg = 2, lb = 2, ub = 2, label = Symbol("##264"))
            catch ex
                #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:50 =#
                println("Line ", 8, ": ", "v(0) == 2")
                #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:51 =#
                throw(ex)
            end
        end
        #= REPL[5]:13 =#
        begin
            #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:46 =#
            local ex
            #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:47 =#
            try
                #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:48 =#
                constraint!(ocp, :final; rg = 1, lb = 0, ub = 0, label = Symbol("##265"))
            catch ex
                #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:50 =#
                println("Line ", 9, ": ", "q(tf) == 0")
                #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:51 =#
                throw(ex)
            end
        end
        #= REPL[5]:14 =#
        begin
            #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:46 =#
            local ex
            #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:47 =#
            try
                #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:48 =#
                constraint!(ocp, :final; rg = 2, lb = 0, ub = 0, label = Symbol("##266"))
            catch ex
                #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:50 =#
                println("Line ", 10, ": ", "v(tf) == 0")
                #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:51 =#
                throw(ex)
            end
        end
        #= REPL[5]:16 =#
        begin
            #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:46 =#
            local ex
            #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:47 =#
            try
                #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:48 =#
                constraint!(ocp, :state; rg = 1, lb = 0, ub = 5, label = :eq1)
            catch ex
                #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:50 =#
                println("Line ", 11, ": ", "(0 ≀ q(t) ≀ 5, 1)")
                #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:51 =#
                throw(ex)
            end
        end
        #= REPL[5]:17 =#
        begin
            #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:46 =#
            local ex
            #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:47 =#
            try
                #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:48 =#
                constraint!(ocp, :state; rg = 2, lb = -2, ub = 3, label = :eq2)
            catch ex
                #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:50 =#
                println("Line ", 12, ": ", "(-2 ≀ v(t) ≀ 3, 2)")
                #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:51 =#
                throw(ex)
            end
        end
        #= REPL[5]:19 =#
        begin
            #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:46 =#
            local ex
            #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:47 =#
            try
                #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:48 =#
                begin
                    #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:354 =#
                    function var"##269"(var"##267", var"##268", tf)
                        #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:354 =#
                        #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:355 =#
                        [var"##267"[2], var"##268"]
                    end
                    #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:357 =#
                    dynamics!(ocp, var"##269")
                end
            catch ex
                #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:50 =#
                println("Line ", 13, ": ", "αΊ‹(t) == [v(t), u(t)]")
                #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:51 =#
                throw(ex)
            end
        end
        #= REPL[5]:21 =#
        begin
            #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:46 =#
            local ex
            #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:47 =#
            try
                #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:48 =#
                begin
                    #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:395 =#
                    function var"##270"(var"##271", var"##272", tf)
                        #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:395 =#
                        #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:396 =#
                        tf
                    end
                    #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:398 =#
                    objective!(ocp, :mayer, var"##270", :min)
                end
            catch ex
                #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:50 =#
                println("Line ", 14, ": ", "tf β†’ min")
                #= /home/jcaillau/.julia/packages/CTBase/fDnnG/src/onepass.jl:51 =#
                throw(ex)
            end
        end
    end
    ocp.model_expression = $(QuoteNode(quote
    #= REPL[5]:3 =#
    (tf ∈ R, variable)
    #= REPL[5]:4 =#
    (t ∈ [0, tf], time)
    #= REPL[5]:5 =#
    x = ((q, v) ∈ R², state)
    #= REPL[5]:6 =#
    (u ∈ R, control)
    #= REPL[5]:8 =#
    tf β‰₯ 0
    #= REPL[5]:9 =#
    -1 ≀ u(t) ≀ 1
    #= REPL[5]:11 =#
    q(0) == 1
    #= REPL[5]:12 =#
    v(0) == 2
    #= REPL[5]:13 =#
    q(tf) == 0
    #= REPL[5]:14 =#
    v(tf) == 0
    #= REPL[5]:16 =#
    (0 ≀ q(t) ≀ 5, 1)
    #= REPL[5]:17 =#
    (-2 ≀ v(t) ≀ 3, 2)
    #= REPL[5]:19 =#
    αΊ‹(t) == [v(t), u(t)]
    #= REPL[5]:21 =#
    tf β†’ min
end))
    ocp
end

Many thanks!

The main reason is that I feel that being able to use both syntaxes gives a better understanding of how the package is working.

Clearly there is something I am not understanding at the moment. Based on the basic example and the API I tried to rewrite the time minimization but I got an error indicatiing that I haven't defined correctly tf (abstract syntax works as expected instead).

Another reaon is that I am used to write notebooks with nteract where latex rendering is somewhat cumbersome (no tab completion). Probably I should move to Pluto but I have some inertia...

Thanks again for the swift reply and the very nice work!

jbcaillau avatar Aug 12 '24 10:08 jbcaillau

It is now in the stable doc:

https://control-toolbox.org/OptimalControl.jl

ocots avatar Aug 12 '24 10:08 ocots

Excellent, Thanks! The @macroexpand tip is indeed very useful!

Now I understand. What I was missing was

dynamics!(ocp, (x, u, tf) -> [ x[2], u])

my wrong guess was instead:

dynamics!(ocp, (x, u, tf) -> [ x[2], u ,1])

paolo-mgi avatar Aug 12 '24 11:08 paolo-mgi

We may need to give the mathematical syntax. Here it misses the case with a variable: https://control-toolbox.org/OptimalControl.jl/stable/tutorial-abstract.html#dynamics

ocots avatar Aug 12 '24 12:08 ocots

@ocots well the abstract syntax does not depend on whether there is a variable or not, but I am adding a comment in the doc to complete

IMG_3430

with sth like

$$ \dot{x} = f(t, x(t), u(t), v). $$

We may need to give the mathematical syntax. Here it misses the case with a variable: https://control-toolbox.org/OptimalControl.jl/stable/tutorial-abstract.html#dynamics

jbcaillau avatar Aug 12 '24 14:08 jbcaillau

By the way how to quote the package in a paper?

paolo-mgi avatar Aug 12 '24 14:08 paolo-mgi

By the way how to quote the package in a paper?

good point. Zenodo ref. on its way, will tell you asap in this issue (reopened). https://github.com/control-toolbox/OptimalControl.jl/issues/175

jbcaillau avatar Aug 12 '24 14:08 jbcaillau

Hi @paolo-mgi @jbcaillau!

  • Functional syntax here.
  • Citing us here. We have a DOI from Zenodo now.

ocots avatar Aug 28 '24 14:08 ocots

many thanks. To be used hopefully soon :) KR paolo

On 28. Aug 2024, at 17.20, Olivier Cots @.***> wrote:

Hi @paolo-mgi https://github.com/paolo-mgi @jbcaillau https://github.com/jbcaillau!

Functional syntax here https://control-toolbox.org/OptimalControl.jl/stable/tutorial-functional.html. Citing us here https://control-toolbox.org/OptimalControl.jl/stable/#Citing-us. We have a DOI from Zenodo now. β€” Reply to this email directly, view it on GitHub https://github.com/control-toolbox/OptimalControl.jl/issues/264#issuecomment-2315475946, or unsubscribe https://github.com/notifications/unsubscribe-auth/AMKNHXUESLJUCIWMNUBFRATZTXMDRAVCNFSM6AAAAABMAG3B5SVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDGMJVGQ3TKOJUGY. You are receiving this because you were mentioned.

paolo-mgi avatar Aug 28 '24 14:08 paolo-mgi