Skip to content
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

Box constraints for the direct method & more #4

Closed
ocots opened this issue Mar 3, 2023 · 40 comments
Closed

Box constraints for the direct method & more #4

ocots opened this issue Mar 3, 2023 · 40 comments
Assignees

Comments

@ocots
Copy link
Member

ocots commented Mar 3, 2023

The constraints have to be added in the CTBase package. Then, it will be possible to update the CTDirect package.

Remarks.

  • The ipopt solver is more efficient if the box constraints are taken into account.
  • See also Issue 63.
@jbcaillau
Copy link
Member

Doing, on this base (see this issue in the last sprint):

  • (pure) control and state constraints can be provided through boxes (including boxes on index ranges, this is the linear case) or functions (nonlinear case)
  • the range / function alternative does not make sense for mixed constraints (only functions)
  • for both range / function, one value means equality, two means (boxed) inequality
  • in some cases (e.g. range for control/state constraint) equality does not make sense
  • API change: in case of inequalities, only one function returned by the getter (not two), which is the mere computation (without substracting the lower/upper bound); the user has then to use properly

A296BDE1-EDED-4B29-9E6A-4AF3BBB49AD9

@jbcaillau
Copy link
Member

jbcaillau commented Mar 8, 2023

Updates are in order for the NLP construction as

  • the dictionary storing constraints now has functions (computing the constraint) but also ranges for boxes (see above)
  • in the case of functions, only the original function is stored in the dictionary (not a function substracting the value in the case of an equality)
  • similarly the constraint getter returns the mere function (also in the case of a range - just a projector, then)
  • this provides a coherent treatment for equalities and inequalities
  • in particular, in the case of inequalities, only one constraint is available through the getter (no more lower/upper thing)

Testing whether there is a range of a function allows to decide whether the constraint is linear (a box) or not when constructing the NLP model.

NB. The current version of the code factorises several kind of constraints which is hard to maintain / update 😬

@jbcaillau
Copy link
Member

jbcaillau commented Mar 8, 2023

@PierreMartinon @joseph-gergaud any idea of the format you would like to retrieve box constraints on state and control

  • at t0 / tf
  • for all times?

@jbcaillau
Copy link
Member

jbcaillau commented Mar 9, 2023

@PierreMartinon @joseph-gergaud nlp_constraints now returns two additional triples:

  • (vector of lower bounds, vector of indices of box constraints, vector of upper bounds)
  • one triple for control, one triple for state

Check this commit. Should be ready for CTDirect.jl update 🤞🏾

@PierreMartinon @joseph-gergaud any idea of the format you would like to retrieve box constraints on state and control

  • at t0 / tf
  • for all times?

@jbcaillau
Copy link
Member

@ocots Some minor changes in CTBase.jl (undergoing tests)

  • using pattern matching (see MLStyle.jl)
  • as constraints have an :eq / :ineq field, I have systematically put two values (lower and upper bounds), even for eqs (more coherent + simpler code)

Check this commit

@ocots
Copy link
Member Author

ocots commented Mar 9, 2023

At this line, we have

function constraint!(ocp::OptimalControlModel, type::Symbol, lb::Real, ub::Real, label::Symbol=gensym(:anonymous))
    if type  [ :initial, :final ]
        ocp.constraints[label] = (type, :ineq, x -> x, ub, lb)
    elseif type  [ :control, :state ]
        ocp.constraints[label] = (type, :ineq, 1:state_dimension(ocp), ub, lb)
    else
        throw(IncorrectArgument("the following type of constraint is not valid: " * String(type) *
        ". Please choose in [ :initial, :final ] or check the arguments of the constraint! method."))
    end
end

Isn't?

function constraint!(ocp::OptimalControlModel, type::Symbol, lb::Real, ub::Real, label::Symbol=gensym(:anonymous))
    if type  [ :initial, :final ]
        ocp.constraints[label] = (type, :ineq, x -> x, ub, lb)
    elseif type  [ :control]
        ocp.constraints[label] = (type, :ineq, 1:control_dimension(ocp), ub, lb)
    elseif type  [ :state ]
        ocp.constraints[label] = (type, :ineq, 1:state_dimension(ocp), ub, lb)
    else
        throw(IncorrectArgument("the following type of constraint is not valid: " * String(type) *
        ". Please choose in [ :initial, :final ] or check the arguments of the constraint! method."))
    end
end

@jbcaillau
Copy link
Member

Indeed! fixed 🙏🏽

@jbcaillau jbcaillau changed the title Box and pure constraints for the direct method Box constraints for the direct method & more Mar 9, 2023
@jbcaillau jbcaillau transferred this issue from control-toolbox/OptimalControl.jl Mar 9, 2023
@PierreMartinon
Copy link
Member

I'll start integrating the box constraints in the direct part next week !

@joseph-gergaud
Copy link
Member

Je voulais aussi m'y remettre la semaine prochaine. On pourrait travaille ensemble comme à Nice (voir mes dispo en pièce jointe).

Calendrier — semaine — de 12:03:2023 à 18:03:2023.pdf

@PierreMartinon
Copy link
Member

PierreMartinon commented Mar 10, 2023 via email

@joseph-gergaud
Copy link
Member

joseph-gergaud commented Mar 10, 2023 via email

@ocots
Copy link
Member Author

ocots commented Mar 10, 2023

Of course, before integrating the changes from CTBase.jl a new release of it has to be done.

@jbcaillau
Copy link
Member

jbcaillau commented Mar 10, 2023

@ocots Looks like these functions are only used in the test: correct? With the additional type of constraints, these computations must be updated (and might not completely make sense: case of inequalities...) My first guess would be to suppress them ☠️.

function initial_condition(ocp::OptimalControlModel)
function final_condition(ocp::OptimalControlModel)
function initial_constraint(ocp::OptimalControlModel)
function final_constraint(ocp::OptimalControlModel)

Note that labelled constraint can be retrieved:

constraint!(ocp, :initial, x0, :eq1)
x -> constraint(ocp, :eq1) - x0 === x -> x - x0

constraint!(ocp, :initial, 3:5, y0, :eq2)
x -> constraint(ocp, :eq2) - y0 === x -> x[3:5] - y0

etc.

@jbcaillau
Copy link
Member

jbcaillau commented Mar 10, 2023

@ocots At least used in CTDirectShooting.jl. I am:

  • checking this
  • updating test_model.jl

@ocots
Copy link
Member Author

ocots commented Mar 10, 2023

The functionsfinal_constraint and initial_condition are used in CTDirectShooting/src/utils.jl in the following function.

function parse_ocp_direct_shooting(ocp::OptimalControlModel)
    # parsing ocp
    dy = dynamics(ocp)
    co = lagrange(ocp)
    cf = final_constraint(ocp)
    x0 = initial_condition(ocp)
    n = state_dimension(ocp)
    m = control_dimension(ocp)
    return dy, co, cf, x0, n, m
end

This function parse_ocp_direct_shooting is used to define the direct shooting problem which is given to the unconstrained optimization solver CTOptimization.jl and is also used to build the solution.

Remark. The functionsfinal_constraint and initial_condition are not used to check the validity of the optimal control problem like I have said. It is true than with the direct shooting method we cannot solve problems with constraints for the moment, but the checking is done simply by:

    # check validity
    ξ, ψ, ϕ = nlp_constraints(ocp)
    dim_ξ = length(ξ[1])      # dimension of the boundary constraints
    dim_ψ = length(ψ[1])
    if dim_ξ != 0 && dim_ψ != 0
        error("direct shooting is implemented for problems without constraints")
    end

@jbcaillau
Copy link
Member

@ocots OK I if simply move the two functions initial_condition and final_constraint (that assume the simple form you used for the problem) into CTDirectShooting/src/utils.jl? Will it suffice?

@ocots
Copy link
Member Author

ocots commented Mar 14, 2023

We can write the functions here to keep them in mind and you can remove them from CTBase.jl. If you have a better way to get the initial / final conditions / constraints, you can give it below.

function initial_condition(ocp::OptimalControlModel) 
    cs = constraints(ocp)
    x0 = nothing
    for (_, c)  cs
        type, _, _, val = c
        if type == :initial
             x0 = val
        end
    end
    return x0
end
function final_condition(ocp::OptimalControlModel) 
    cs = constraints(ocp)
    xf = nothing
    for (_, c)  cs
        type, _, _, val = c
        if type == :final
             xf = val
        end
    end
    return xf
end
function initial_constraint(ocp::OptimalControlModel) 
    cs = constraints(ocp)
    c0 = nothing
    for (_, c)  cs
        type, _, f, val = c
        if type == :initial
            c0 = x -> f(x) - val
        end
    end
    return c0
end
function final_constraint(ocp::OptimalControlModel) 
    cs = constraints(ocp)
    cf = nothing
    for (_, c)  cs
        type, _, f, val = c
        if type == :final
            cf = x -> f(x) - val
        end
    end
    return cf
end

@PierreMartinon
Copy link
Member

PierreMartinon commented Mar 15, 2023

@jbcaillau
A bit late to the party, but with Joseph we started a branch in CTDirect that is compatible with the new nlp_constraints function including the pure state constraints and boxes

Concerning your question about the boxes at t0 / tf and all t, there is no distinction in the NLP: the time grid includes t0 and tf so there is only boxes 'for all t' and no specific boxes for t0/tf (there are however the generic boundary conditions at t0/tf)

For the format, the triple (LB,IND,UB) could be a triple of flattened values or use vectors of vectors.
Example: assume the boxes

$$-1 <= x[1,3] <= 2 , 0 <= x[2] <= Inf$$

Flat format: (no need for ordering)

LB = (-1,-1,0) IND = (1,3,2) UB = (2,2,Inf)

Nested format:

LB = (-1,0) IND = ((1,3),2)  UB=(2,Inf)

Either form works for us.

@ocots
Copy link
Member Author

ocots commented Mar 15, 2023

@jbcaillau Not sure that this should be a Vector{Int} since you append some range: https://github.com/control-toolbox/CTBase.jl/blob/constraints/src/model.jl#L229

@jbcaillau
Copy link
Member

OK: we can

  • @jbcaillau add both in abstract and functional form the case of a single constant for a whole range (= same value for all indices, e.g. zero)

@ocots
Copy link
Member Author

ocots commented Mar 15, 2023

For me it was ok to give a vector of the same size as the range. Still, the most important for @PierreMartinon and @joseph-gergaud is just in which format we give them the constraints, via nlp_constraints function.

Remark. the name nlp_constraints is pas terrible terrible :-)

@PierreMartinon
Copy link
Member

Flat non-ordered is ok for us.

Remark. the name nlp_constraints is pas terrible terrible :-)
ocp_constraints ?

@jbcaillau
Copy link
Member

jbcaillau commented Mar 16, 2023

@PierreMartinon @joseph-gergaud For the record:

  • infos on the format in this previous post
  • tests on CTBase.jl: doing 🤞🏾

@jbcaillau
Copy link
Member

jbcaillau commented Mar 16, 2023

@ocots tests passed in branch constraints:

  • check this PR
  • I have suppressed initial_condition, etc. (see here) but not yet moved them into CTDirectShooting
  • some error messages in model.jl have to be updated
  • some comments are in order regarding the scalar / vectorial thing for state and control (to be discussed), and on typing in Julia in general

@ocots
Copy link
Member Author

ocots commented Mar 17, 2023

I will handle CTDirectShooting. No problemo.
I have made the review but I prefer not to change the code myself.

@jbcaillau
Copy link
Member

jbcaillau commented Mar 17, 2023

@ocots Cannot see the review...?

I have made the review but I prefer not to change the code myself.

@ocots
Copy link
Member Author

ocots commented Mar 18, 2023

You should see comments directly in the PR: #10

@jbcaillau
Copy link
Member

@ocots please merge this PR after checking comments in review

@jbcaillau
Copy link
Member

jbcaillau commented Mar 25, 2023

@ocots @joseph-gergaud @PierreMartinon OK for a meeting next Thursday (30/3)?

/polls "10:00" "15:00" "17:00"

@ocots
Copy link
Member Author

ocots commented Mar 25, 2023

Any time.

@jbcaillau
Copy link
Member

Any time.

good. installed this poll app, does not seem to work 💩

@jbcaillau
Copy link
Member

@ocots have you eventually moved this somewhere in CTDirect.jl?

@ocots
Copy link
Member Author

ocots commented Mar 26, 2023

I didn't move it but you have something similar here:

I will replace these pieces of code (piece of codes / piece of code) when I will have something good.

@ocots
Copy link
Member Author

ocots commented Mar 26, 2023

Test:

/polls Option1 'Option 2' "Option 3"

@ocots
Copy link
Member Author

ocots commented Mar 26, 2023

Maybe poll is only in the description of a new issue.

@jbcaillau
Copy link
Member

@PierreMartinon
Copy link
Member

PierreMartinon commented Mar 27, 2023 via email

@control-toolbox control-toolbox deleted a comment from jbcaillau Mar 27, 2023
@control-toolbox control-toolbox deleted a comment from jbcaillau Mar 27, 2023
@control-toolbox control-toolbox deleted a comment from jbcaillau Mar 27, 2023
@joseph-gergaud
Copy link
Member

C'est ok pour moi jeudi à 10h00

@jbcaillau
Copy link
Member

@ocots @PierreMartinon @joseph-gergaud 10:00 it is, this Thursday
webex

@ocots ocots closed this as completed May 9, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants