Skip to content

Commit 2798385

Browse files
authored
Merge pull request #169 from control-toolbox/167-update-nlp_constraints
167 update nlp constraints
2 parents 6f49f3f + f2dccec commit 2798385

File tree

5 files changed

+164
-41
lines changed

5 files changed

+164
-41
lines changed

src/CTBase.jl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -248,8 +248,9 @@ export Model
248248
export __OCPModel # redirection to Model to avoid confusion with other Model functions from other packages. Due to @def macro
249249
export variable!, time!, constraint!, dynamics!, objective!, state!, control!, remove_constraint!, constraint
250250
export is_autonomous, is_fixed, is_time_independent, is_time_dependent, is_min, is_max, is_variable_dependent, is_variable_independent
251-
export nlp_constraints, constraints_labels
251+
export nlp_constraints!, constraints_labels
252252
export has_free_final_time, has_free_initial_time, has_lagrange_cost, has_mayer_cost
253+
export dim_control_constraints, dim_state_constraints, dim_mixed_constraints, dim_path_constraints, dim_boundary_constraints, dim_variable_constraints, dim_control_range, dim_state_range, dim_variable_range, dim_control_box, dim_state_box, dim_variable_box
253254

254255
# solution
255256
export OptimalControlSolution
@@ -273,4 +274,4 @@ export @def
273274
export ct_repl, ct_repl_update_model
274275
isdefined(Base, :active_repl) && ct_repl()
275276

276-
end
277+
end

src/model.jl

Lines changed: 99 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# todo: use design pattern to generate functions in nlp_constraints!
12
"""
23
$(TYPEDSIGNATURES)
34
@@ -865,18 +866,21 @@ Return a 6-tuple of tuples:
865866
- `(xl, xind, xu)` are state linear constraints of a subset of indices
866867
- `(vl, vind, vu)` are variable linear constraints of a subset of indices
867868
869+
and update information about constraints dimensions of `ocp`.
870+
868871
!!! note
869872
870-
- The dimensions of the state and control must be set before calling `nlp_constraints`.
873+
- The dimensions of the state and control must be set before calling `nlp_constraints!`.
874+
- For a `Fixed` problem, dimensions associated with constraints on the variable are set to zero.
871875
872876
# Example
873877
874878
```jldoctest
875879
julia> (ξl, ξ, ξu), (ηl, η, ηu), (ψl, ψ, ψu), (ϕl, ϕ, ϕu), (θl, θ, θu),
876-
(ul, uind, uu), (xl, xind, xu), (vl, vind, vu) = nlp_constraints(ocp)
880+
(ul, uind, uu), (xl, xind, xu), (vl, vind, vu) = nlp_constraints!(ocp)
877881
```
878882
"""
879-
function nlp_constraints(ocp::OptimalControlModel)
883+
function nlp_constraints!(ocp::OptimalControlModel)
880884

881885
# we check if the dimensions and times have been set
882886
__check_all_set(ocp)
@@ -965,12 +969,6 @@ function nlp_constraints(ocp::OptimalControlModel)
965969
return val
966970
end
967971

968-
function (t, x, v) # nonlinear state constraints
969-
val = Vector{ctNumber}()
970-
for i 1:length(ηf) append!(val, ηf[i](t, x, v)) end
971-
return val
972-
end
973-
974972
function ψ(t, x, u, v) # nonlinear mixed constraints
975973
dim = length(ψl)
976974
val = zeros(ctNumber, dim)
@@ -984,13 +982,7 @@ function nlp_constraints(ocp::OptimalControlModel)
984982
return val
985983
end
986984

987-
function (t, x, u, v) # nonlinear mixed constraints
988-
val = Vector{ctNumber}()
989-
for i 1:length(ψf) append!(val, ψf[i](t, x, u, v)) end
990-
return val
991-
end
992-
993-
function ϕ(x0, xf, v) # nonlinear mixed constraints
985+
function ϕ(x0, xf, v) # nonlinear boundary constraints
994986
dim = length(ϕl)
995987
val = zeros(ctNumber, dim)
996988
j = 1
@@ -1003,13 +995,7 @@ function nlp_constraints(ocp::OptimalControlModel)
1003995
return val
1004996
end
1005997

1006-
function (x0, xf, v) # nonlinear boundary constraints
1007-
val = Vector{ctNumber}()
1008-
for i 1:length(ϕf) append!(val, ϕf[i](x0, xf, v)) end
1009-
return val
1010-
end
1011-
1012-
function θ(v) # nonlinear mixed constraints
998+
function θ(v) # nonlinear variable constraints
1013999
dim = length(θl)
10141000
val = zeros(ctNumber, dim)
10151001
j = 1
@@ -1022,12 +1008,96 @@ function nlp_constraints(ocp::OptimalControlModel)
10221008
return val
10231009
end
10241010

1025-
function (v) # nonlinear variable constraints
1026-
val = Vector{ctNumber}()
1027-
for i 1:length(θf) append!(val, θf[i](v)) end
1028-
return val
1029-
end
1011+
ocp.dim_control_constraints = length(ξl)
1012+
ocp.dim_state_constraints = length(ηl)
1013+
ocp.dim_mixed_constraints = length(ψl)
1014+
ocp.dim_boundary_constraints = length(ϕl)
1015+
ocp.dim_variable_constraints = length(θl)
1016+
ocp.dim_control_range = length(ul)
1017+
ocp.dim_state_range = length(xl)
1018+
ocp.dim_variable_range = length(vl)
10301019

10311020
return (ξl, ξ, ξu), (ηl, η, ηu), (ψl, ψ, ψu), (ϕl, ϕ, ϕu), (θl, θ, θu), (ul, uind, uu), (xl, xind, xu), (vl, vind, vu)
10321021

1033-
end
1022+
end
1023+
1024+
1025+
"""
1026+
$(TYPEDSIGNATURES)
1027+
1028+
Return the dimension of nonlinear state constraints (`nothing` if not knonw).
1029+
Information is updated after `nlp_constraints!` is called.
1030+
"""
1031+
dim_state_constraints(ocp::OptimalControlModel) = ocp.dim_state_constraints
1032+
1033+
"""
1034+
$(TYPEDSIGNATURES)
1035+
1036+
Return the dimension of nonlinear control constraints (`nothing` if not knonw).
1037+
Information is updated after `nlp_constraints!` is called.
1038+
"""
1039+
dim_control_constraints(ocp::OptimalControlModel) = ocp.dim_control_constraints
1040+
1041+
"""
1042+
$(TYPEDSIGNATURES)
1043+
1044+
Return the dimension of nonlinear mixed constraints (`nothing` if not knonw).
1045+
Information is updated after `nlp_constraints!` is called.
1046+
"""
1047+
dim_mixed_constraints(ocp::OptimalControlModel) = ocp.dim_mixed_constraints
1048+
1049+
"""
1050+
$(TYPEDSIGNATURES)
1051+
1052+
Return the dimension of nonlinear path (state + control + mixed) constraints (`nothing` if one of them is not knonw).
1053+
Information is updated after `nlp_constraints!` is called.
1054+
"""
1055+
function dim_path_constraints(ocp::OptimalControlModel)
1056+
isnothing(ocp.dim_control_constraints) && return nothing
1057+
isnothing(ocp.dim_state_constraints) && return nothing
1058+
isnothing(ocp.dim_mixed_constraints) && return nothing
1059+
return ocp.dim_state_constraints + ocp.dim_control_constraints + ocp.dim_mixed_constraints
1060+
end
1061+
1062+
"""
1063+
$(TYPEDSIGNATURES)
1064+
1065+
Return the dimension of the boundary constraints (`nothing` if not knonw).
1066+
Information is updated after `nlp_constraints!` is called.
1067+
"""
1068+
dim_boundary_constraints(ocp::OptimalControlModel) = ocp.dim_boundary_constraints
1069+
1070+
"""
1071+
$(TYPEDSIGNATURES)
1072+
1073+
Return the dimension of nonlinear variable constraints (`nothing` if not knonw).
1074+
Information is updated after `nlp_constraints!` is called.
1075+
"""
1076+
dim_variable_constraints(ocp::OptimalControlModel) = ocp.dim_variable_constraints
1077+
1078+
"""
1079+
$(TYPEDSIGNATURES)
1080+
1081+
Return the dimension of range constraints on state (`nothing` if not knonw).
1082+
Information is updated after `nlp_constraints!` is called.
1083+
"""
1084+
dim_state_range(ocp::OptimalControlModel) = ocp.dim_state_range
1085+
dim_state_box = dim_state_range # alias, CTDirect.jl compatibility
1086+
1087+
"""
1088+
$(TYPEDSIGNATURES)
1089+
1090+
Return the dimension of range constraints on control (`nothing` if not knonw).
1091+
Information is updated after `nlp_constraints!` is called.
1092+
"""
1093+
dim_control_range(ocp::OptimalControlModel) = ocp.dim_control_range
1094+
dim_control_box = dim_control_range # alias, CTDirect.jl compatibility
1095+
1096+
"""
1097+
$(TYPEDSIGNATURES)
1098+
1099+
Return the dimension of range constraints on variable (`nothing` if not knonw).
1100+
Information is updated after `nlp_constraints!` is called.
1101+
"""
1102+
dim_variable_range(ocp::OptimalControlModel) = ocp.dim_variable_range
1103+
dim_variable_box = dim_variable_range # alias, CTDirect.jl compatibility

src/print.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ function Base.show(io::IO, ::MIME"text/plain", ocp::OptimalControlModel{<: TimeD
104104
println(io, "")
105105

106106
# other constraints: control, state, mixed, boundary, bounds on u, bounds on x
107-
(ξl, ξ, ξu), (ηl, η, ηu), (ψl, ψ, ψu), (ϕl, ϕ, ϕu), (ulb, uind, uub), (xlb, xind, xub) = nlp_constraints(ocp)
107+
(ξl, ξ, ξu), (ηl, η, ηu), (ψl, ψ, ψu), (ϕl, ϕ, ϕu), (ulb, uind, uub), (xlb, xind, xub) = nlp_constraints!(ocp)
108108
has_constraints = false
109109
if !isempty(ξl) || !isempty(ulb)
110110
has_constraints = true

src/types.jl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1174,6 +1174,14 @@ $(TYPEDFIELDS)
11741174
criterion::Union{Symbol,Nothing}=nothing
11751175
dynamics::Union{Dynamics,Nothing}=nothing
11761176
constraints::Dict{Symbol, Tuple{Vararg{Any}}}=Dict{Symbol, Tuple{Vararg{Any}}}()
1177+
dim_control_constraints::Union{Dimension,Nothing}=nothing
1178+
dim_state_constraints::Union{Dimension,Nothing}=nothing
1179+
dim_mixed_constraints::Union{Dimension,Nothing}=nothing
1180+
dim_boundary_constraints::Union{Dimension,Nothing}=nothing
1181+
dim_variable_constraints::Union{Dimension,Nothing}=nothing
1182+
dim_control_range::Union{Dimension,Nothing}=nothing
1183+
dim_state_range::Union{Dimension,Nothing}=nothing
1184+
dim_variable_range::Union{Dimension,Nothing}=nothing
11771185
end
11781186

11791187
# used for checkings

test/test_model.jl

Lines changed: 53 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -859,7 +859,7 @@ end
859859

860860
end
861861

862-
@testset "nlp_constraints without variable" begin
862+
@testset "nlp_constraints! without variable" begin
863863

864864
ocp = Model(); __time!(ocp, 0, 1); state!(ocp, 2); control!(ocp, 1)
865865
__constraint!(ocp, :initial, Index(2), 10, 10, :ci)
@@ -871,8 +871,19 @@ end
871871
__constraint!(ocp, :state, x->x, [0, 1], [1, 2], :css)
872872
__constraint!(ocp, :mixed, (x,u)->x[1]+u, 1, 1, :cm)
873873

874+
# dimensions (not yet set)
875+
@test dim_control_constraints(ocp) == nothing
876+
@test dim_state_constraints(ocp) == nothing
877+
@test dim_mixed_constraints(ocp) == nothing
878+
@test dim_path_constraints(ocp) == nothing
879+
@test dim_boundary_constraints(ocp) == nothing
880+
@test dim_variable_constraints(ocp) == nothing
881+
@test dim_control_range(ocp) == nothing
882+
@test dim_state_range(ocp) == nothing
883+
@test dim_variable_range(ocp) == nothing
884+
874885
(ξl, ξ, ξu), (ηl, η, ηu), (ψl, ψ, ψu), (ϕl, ϕ, ϕu), (θl, θ, θu),
875-
(ul, uind, uu), (xl, xind, xu), (vl, vind, vu) = nlp_constraints(ocp)
886+
(ul, uind, uu), (xl, xind, xu), (vl, vind, vu) = nlp_constraints!(ocp)
876887

877888
v = Real[]
878889

@@ -912,9 +923,20 @@ end
912923
@test sort(θu) == sort([ ])
913924
@test sort(θ(v)) == sort([ ])
914925

926+
# dimensions (set)
927+
@test dim_control_constraints(ocp) == 1
928+
@test dim_state_constraints(ocp) == 2
929+
@test dim_mixed_constraints(ocp) == 1
930+
@test dim_path_constraints(ocp) == 4
931+
@test dim_boundary_constraints(ocp) == 3
932+
@test dim_variable_constraints(ocp) == 0
933+
@test dim_control_range(ocp) == 1
934+
@test dim_state_range(ocp) == 2
935+
@test dim_variable_range(ocp) == 0
936+
915937
end
916938

917-
@testset "nlp_constraints with variable" begin
939+
@testset "nlp_constraints! with variable" begin
918940

919941
ocp = Model(variable=true)
920942
__time!(ocp, 0, 1)
@@ -934,8 +956,19 @@ end
934956
__constraint!(ocp, :variable, Index(3), 2, 3, :cv3)
935957
__constraint!(ocp, :variable, v -> v[3]^2, 0, 1, :cv4)
936958

959+
# dimensions (not yet set)
960+
@test dim_control_constraints(ocp) == nothing
961+
@test dim_state_constraints(ocp) == nothing
962+
@test dim_mixed_constraints(ocp) == nothing
963+
@test dim_path_constraints(ocp) == nothing
964+
@test dim_boundary_constraints(ocp) == nothing
965+
@test dim_variable_constraints(ocp) == nothing
966+
@test dim_control_range(ocp) == nothing
967+
@test dim_state_range(ocp) == nothing
968+
@test dim_variable_range(ocp) == nothing
969+
937970
(ξl, ξ, ξu), (ηl, η, ηu), (ψl, ψ, ψu), (ϕl, ϕ, ϕu), (θl, θ, θu),
938-
(ul, uind, uu), (xl, xind, xu), (vl, vind, vu) = nlp_constraints(ocp)
971+
(ul, uind, uu), (xl, xind, xu), (vl, vind, vu) = nlp_constraints!(ocp)
939972

940973
v = [ 1, 2, 3, 4 ]
941974

@@ -959,21 +992,32 @@ end
959992
@test sort(ϕu) == sort([10, 1, 1])
960993
@test sort(ϕ([1, 3], [4, 100], v)) == sort([ 3, 4, 103+v[1] ])
961994

995+
# variable
996+
@test sort(θl) == sort([ 0 ])
997+
@test sort(θu) == sort([ 1 ])
998+
@test sort(θ(v)) == sort([ v[3]^2 ])
999+
9621000
# box constraint
9631001
@test sort(ul) == sort([0])
9641002
@test sort(uind) == sort([1])
9651003
@test sort(uu) == sort([1])
9661004
@test sort(xl) == sort([0, 1])
9671005
@test sort(xind) == sort([1, 2])
9681006
@test sort(xu) == sort([1, 2])
969-
970-
# variable
9711007
@test sort(vl) == sort([ 0, 0, 0, 0, 1, 2, 2 ])
9721008
@test sort(vind) == sort([ 1, 2, 3, 4, 1, 2, 3 ])
9731009
@test sort(vu) == sort([ 5, 5, 5, 5, 3, 4, 3 ])
974-
@test sort(θl) == sort([ 0 ])
975-
@test sort(θu) == sort([ 1 ])
976-
@test sort(θ(v)) == sort([ v[3]^2 ])
1010+
1011+
# dimensions
1012+
@test dim_control_constraints(ocp) == 1
1013+
@test dim_state_constraints(ocp) == 2
1014+
@test dim_mixed_constraints(ocp) == 1
1015+
@test dim_path_constraints(ocp) == 4
1016+
@test dim_boundary_constraints(ocp) == 3
1017+
@test dim_variable_constraints(ocp) == 1
1018+
@test dim_control_range(ocp) == 1
1019+
@test dim_state_range(ocp) == 2
1020+
@test dim_variable_range(ocp) == 7
9771021

9781022
end
9791023

0 commit comments

Comments
 (0)