control-toolbox / OptimalControl.jl

Model and solve optimal control problems in Julia
http://control-toolbox.org/OptimalControl.jl/
MIT License
70 stars 8 forks source link

Update basic example tutorial functional syntax #264

Open ocots opened 3 months ago

ocots commented 3 months ago
          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

paolo-mgi commented 3 months ago

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

ocots commented 2 months ago

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?

paolo-mgi commented 2 months ago

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!

ocots commented 2 months ago

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 commented 2 months ago

Pin @jbcaillau.

jbcaillau commented 2 months ago

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:

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!

ocots commented 2 months ago

It is now in the stable doc:

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

paolo-mgi commented 2 months ago

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])

ocots commented 2 months ago

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 commented 2 months ago

@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

paolo-mgi commented 2 months ago

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

jbcaillau commented 2 months ago

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

ocots commented 2 months ago

Hi @paolo-mgi @jbcaillau!

paolo-mgi commented 2 months ago

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.