diff --git a/src/CTBase.jl b/src/CTBase.jl index 353dcfbf..64dc27ef 100644 --- a/src/CTBase.jl +++ b/src/CTBase.jl @@ -249,12 +249,14 @@ export __OCPModel # redirection to Model to avoid confusion with other Model fun export variable!, time!, constraint!, dynamics!, objective!, state!, control!, remove_constraint!, constraint export is_time_independent, is_time_dependent, is_min, is_max, is_variable_dependent, is_variable_independent export nlp_constraints, constraints_labels +export has_free_final_time, has_free_initial_time, has_lagrange_cost, has_mayer_cost +export dim_boundary_conditions, dim_control_constraints, dim_state_constraints, dim_variable_constraints, dim_mixed_constraints, dim_path_constraints, dim_control_box, dim_state_box, dim_variable_box # solution export OptimalControlSolution # initialization -export OCPInit +export OptimalControlInit # utils export ctgradient, ctjacobian, ctinterpolate, ctindices, ctupperscripts diff --git a/src/init.jl b/src/init.jl index b40e5f17..cb73791f 100644 --- a/src/init.jl +++ b/src/init.jl @@ -5,22 +5,22 @@ Initialization of the OCP solution that can be used when solving the discretized # Constructors: -- `OCPInit()`: default initialization -- `OCPInit(x_init, u_init, v_init)`: constant vector and/or function handles -- `OCPInit(sol)`: from existing solution +- `OptimalControlInit()`: default initialization +- `OptimalControlInit(x_init, u_init, v_init)`: constant vector and/or function handles +- `OptimalControlInit(sol)`: from existing solution # Examples ```julia-repl -julia> init = OCPInit() -julia> init = OCPInit(x_init=[0.1, 0.2], u_init=0.3) -julia> init = OCPInit(x_init=[0.1, 0.2], u_init=0.3, v_init=0.5) -julia> init = OCPInit(x_init=[0.1, 0.2], u_init=t->sin(t), v_init=0.5) -julia> init = OCPInit(sol) +julia> init = OptimalControlInit() +julia> init = OptimalControlInit(x_init=[0.1, 0.2], u_init=0.3) +julia> init = OptimalControlInit(x_init=[0.1, 0.2], u_init=0.3, v_init=0.5) +julia> init = OptimalControlInit(x_init=[0.1, 0.2], u_init=t->sin(t), v_init=0.5) +julia> init = OptimalControlInit(sol) ``` """ -mutable struct OCPInit +mutable struct OptimalControlInit state_init::Function control_init::Function @@ -30,7 +30,7 @@ mutable struct OCPInit info::Symbol # warm start from solution - function OCPInit(sol::OptimalControlSolution) + function OptimalControlInit(sol::OptimalControlSolution) init = new() init.info = :from_solution @@ -43,7 +43,7 @@ mutable struct OCPInit end # constant / functional init with explicit arguments - function OCPInit(; state::Union{Nothing, ctVector, Function}=nothing, control::Union{Nothing, ctVector, Function}=nothing, variable::Union{Nothing, ctVector}=nothing) + function OptimalControlInit(; state::Union{Nothing, ctVector, Function}=nothing, control::Union{Nothing, ctVector, Function}=nothing, variable::Union{Nothing, ctVector}=nothing) init = new() init.info = :constant_or_function @@ -57,13 +57,19 @@ mutable struct OCPInit # version with arguments as collection/iterable # (may be fused with version above ?) - function OCPInit(init) + function OptimalControlInit(init) x_init = :state ∈ keys(init) ? init[:state] : nothing u_init = :control ∈ keys(init) ? init[:control] : nothing v_init = :variable ∈ keys(init) ? init[:variable] : nothing - return OCPInit(state=x_init, control=u_init, variable=v_init) + return OptimalControlInit(state=x_init, control=u_init, variable=v_init) end + # trivial version that just returns its argument + # used for unified syntax in caller functions + function OptimalControlInit(init::OptimalControlInit) + return init + end + end diff --git a/src/model.jl b/src/model.jl index 07170cfc..75b654f9 100644 --- a/src/model.jl +++ b/src/model.jl @@ -106,6 +106,36 @@ Return `true` if the model has been defined as variable independent. """ is_variable_independent(ocp::OptimalControlModel) = !is_variable_dependent(ocp) + +""" +$(TYPEDSIGNATURES) + +Return `true` if the model has been defined with free initial time. +""" +has_free_initial_time(ocp::OptimalControlModel) = (typeof(ocp.initial_time)==Index) + +""" +$(TYPEDSIGNATURES) + +Return `true` if the model has been defined with free final time. +""" +has_free_final_time(ocp::OptimalControlModel) = (typeof(ocp.final_time)==Index) + +""" +$(TYPEDSIGNATURES) + +Return `true` if the model has been defined with lagrange cost. +""" +has_lagrange_cost(ocp::OptimalControlModel) = !isnothing(ocp.lagrange) + +""" +$(TYPEDSIGNATURES) + +Return `true` if the model has been defined with mayer cost. +""" +has_mayer_cost(ocp::OptimalControlModel) = !isnothing(ocp.mayer) + + """ $(TYPEDSIGNATURES) @@ -625,12 +655,14 @@ function constraint!( ". Please choose in [ :initial, :final, :control, :state, :variable ] or check the arguments of the constraint! method.")) end ocp.constraints[label] = (type, fun_rg, lb, ub) - nothing # to force to return nothing end # _ => throw(IncorrectArgument("Provided arguments are inconsistent.")) end + # update constraints dimensions + __set_dim_constraints(ocp) + end """ @@ -775,6 +807,7 @@ function remove_constraint!(ocp::OptimalControlModel, label::Symbol) ". Please check the list of constraints: ocp.constraints.")) end delete!(ocp.constraints, label) + __set_dim_constraints(ocp) # update constraints dimensions nothing end @@ -961,6 +994,34 @@ function nlp_constraints(ocp::OptimalControlModel) return val end + # set specific constraints dimensions + ocp.dim_control_constraints = length(ξl) + ocp.dim_state_constraints = length(ηl) + ocp.dim_mixed_constraints = length(ψl) + ocp.dim_path_constraints = ocp.dim_control_constraints + ocp.dim_state_constraints + ocp.dim_mixed_constraints + ocp.dim_boundary_conditions = length(ϕl) + ocp.dim_variable_constraints = length(θl) + ocp.dim_control_box = length(ul) + ocp.dim_state_box = length(xl) + ocp.dim_variable_box = length(vl) + return (ξl, ξ, ξu), (ηl, η, ηu), (ψl, ψ, ψu), (ϕl, ϕ, ϕu), (θl, θ, θu), (ul, uind, uu), (xl, xind, xu), (vl, vind, vu) end + +# +function __set_dim_constraints(ocp::OptimalControlModel) + nlp_constraints(ocp) + nothing +end + +# getters for constraints dimensions +dim_control_constraints(ocp::OptimalControlModel) = ocp.dim_control_constraints +dim_state_constraints(ocp::OptimalControlModel) = ocp.dim_state_constraints +dim_mixed_constraints(ocp::OptimalControlModel) = ocp.dim_mixed_constraints +dim_path_constraints(ocp::OptimalControlModel) = ocp.dim_path_constraints +dim_boundary_conditions(ocp::OptimalControlModel) = ocp.dim_boundary_conditions +dim_variable_constraints(ocp::OptimalControlModel) = ocp.dim_variable_constraints +dim_control_box(ocp::OptimalControlModel) = ocp.dim_control_box +dim_state_box(ocp::OptimalControlModel) = ocp.dim_state_box +dim_variable_box(ocp::OptimalControlModel) = ocp.dim_variable_box diff --git a/src/print.jl b/src/print.jl index 769ce397..613b6ebb 100644 --- a/src/print.jl +++ b/src/print.jl @@ -190,7 +190,7 @@ function Base.show(io::IO, ::MIME"text/plain", ocp::OptimalControlModel{<: TimeD # println(io) printstyled(io, "Declarations ", bold=true) - printstyled(io, "(* for required):\n", bold=false) + printstyled(io, "(* required):\n", bold=false) #println(io) # print table of settings diff --git a/src/types.jl b/src/types.jl index 04fea379..e886bef7 100644 --- a/src/types.jl +++ b/src/types.jl @@ -1174,6 +1174,17 @@ $(TYPEDFIELDS) criterion::Union{Symbol,Nothing}=nothing dynamics::Union{Dynamics,Nothing}=nothing constraints::Dict{Symbol, Tuple{Vararg{Any}}}=Dict{Symbol, Tuple{Vararg{Any}}}() + + # internal dimensions for constraints + dim_control_constraints::Union{Dimension, Nothing}=nothing + dim_state_constraints::Union{Dimension, Nothing}=nothing + dim_mixed_constraints::Union{Dimension, Nothing}=nothing + dim_path_constraints::Union{Dimension, Nothing}=nothing + dim_boundary_conditions::Union{Dimension, Nothing}=nothing + dim_variable_constraints::Union{Dimension, Nothing}=nothing + dim_control_box::Union{Dimension, Nothing}=nothing + dim_state_box::Union{Dimension, Nothing}=nothing + dim_variable_box::Union{Dimension, Nothing}=nothing end # used for checkings