Skip to content

Commit

Permalink
Merge pull request #38 from control-toolbox/15-flow-with-variables-no…
Browse files Browse the repository at this point in the history
…nfixed-ocp

fix t0, tf variable
  • Loading branch information
ocots authored Aug 6, 2024
2 parents 7560c45 + 12fd3e3 commit ba0c63d
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 4 deletions.
2 changes: 1 addition & 1 deletion src/CTFlows.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ module CTFlows
import Base: *

# to be placed in CTBase
include("exceptions.jl")
include("ctbase.jl")

# --------------------------------------------------------------------------------------------------
# Aliases for types
Expand Down
5 changes: 5 additions & 0 deletions src/exceptions.jl → src/ctbase.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@

#
variable_dimension(ocp::OptimalControlModel) = ocp.variable_dimension


#
"""
$(TYPEDEF)
Expand Down
16 changes: 16 additions & 0 deletions src/default.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,22 @@
# --------------------------------------------------------------------------------------------
# Default options for flows
# --------------------------------------------------------------------------------------------
function __variable(t0, x0, p0, tf, ocp)
# if tf is free and ocp has only one variable, then return tf
CTBase.has_free_final_time(ocp) && variable_dimension(ocp)==1 && return tf

# if t0 is free and ocp has only one variable, then return t0
CTBase.has_free_initial_time(ocp) && variable_dimension(ocp)==1 && return t0

# if t0 and tf are free and ocp has only two variables, then return [t0, tf]
CTBase.has_free_final_time(ocp) && CTBase.has_free_initial_time(ocp) && variable_dimension(ocp)==2 && return [t0, tf]

# otherwise return an empty vector of right type to avoid warning performance message from OrdinaryDiffEq
z0 = [x0; p0]
T = eltype(z0)
return Vector{T}()
end

function __variable(x0, p0)
z0 = [x0; p0]
T = eltype(z0)
Expand Down
15 changes: 12 additions & 3 deletions src/types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -120,12 +120,21 @@ struct OptimalControlFlow <: AbstractFlow{DCoTangent, CoTangent}
end

# call F.f
(F::OptimalControlFlow)(args...; kwargs...) = begin
F.f(args...; jumps=F.jumps, _t_stops_interne=F.tstops, DiffEqRHS=F.rhs!, kwargs...)
function (F::OptimalControlFlow)(
t0::Time,
x0::State,
p0::Costate,
tf::Time,
v::Variable=__variable(t0, x0, p0, tf, F.ocp); kwargs...)
F.f(t0, x0, p0, tf, v; jumps=F.jumps, _t_stops_interne=F.tstops, DiffEqRHS=F.rhs!, kwargs...)
end

# call F.f and then, construct an optimal control solution
function (F::OptimalControlFlow)(tspan::Tuple{Time,Time}, x0::State, p0::Costate, v::Variable=__variable(x0, p0); kwargs...)
function (F::OptimalControlFlow)(
tspan::Tuple{Time,Time},
x0::State,
p0::Costate,
v::Variable=__variable(tspan[1], x0, p0, tspan[2], F.ocp); kwargs...)
ode_sol = F.f(tspan, x0, p0, v; jumps=F.jumps, _t_stops_interne=F.tstops, DiffEqRHS=F.rhs!, kwargs...)
flow_sol = OptimalControlFlowSolution(ode_sol, F.feedback_control, F.ocp, v)
return CTFlows.OptimalControlSolution(flow_sol)
Expand Down
103 changes: 103 additions & 0 deletions test/test_optimal_control_problem.jl
Original file line number Diff line number Diff line change
Expand Up @@ -144,4 +144,107 @@ function test_optimal_control_problem()

end

@testset "tf variable" begin

t0 = 0
x0 = 0
xf = 1

@def ocp begin
tf R, variable
t [t0, tf], time
x R, state
u R, control
(t) == tf * u(t)
x(t0) == x0
x(tf) == xf
tf + 0.5(u(t)^2) min
end

u = (x, p, tf) -> tf*p
F = Flow(ocp, u)

# solution
tf = (3/2)^(1/4)
p0 = 2tf/3

# tf is provided twice
xf_, pf_ = F(t0, x0, p0, tf, tf)
Test.@test xf xf_ atol=1e-6

# tf is provided once
xf_, pf_ = F(t0, x0, p0, tf)
Test.@test xf xf_ atol=1e-6

end

@testset "t0 variable" begin

t0 = 0
x0 = 0
xf = 1

@def ocp begin
tf R, variable
s [tf, t0], time
x R, state
u R, control
(s) == - tf * u(s)
x(tf) == xf
x(t0) == x0
tf - 0.5(u(s)^2) min
end

u = (x, p, tf) -> tf*p
F = Flow(ocp, u)

# solution
tf = (3/2)^(1/4)
p0 = -2tf/3

# tf is provided twice: it plays the role of the initial time
x0_, pf_ = F(tf, xf, p0, t0, tf)
Test.@test x0 x0_ atol=1e-6

# tf is provided once
x0_, pf_ = F(tf, xf, p0, t0)
Test.@test x0 x0_ atol=1e-6

end


@testset "t0 and tf variable" begin

x0 = 0
xf = 1

@def ocp begin
v = (t0, tf) R^2, variable
t [t0, tf], time
x R, state
u R, control
(t) == tf * u(t) + t0
x(t0) == x0
x(tf) == xf
(t0^2 + tf) + 0.5(u(t)^2) min
end

u = (x, p, v) -> v[2]*p
F = Flow(ocp, u)

# solution
t0 = 0
tf = (3/2)^(1/4)
p0 = 2tf/3

# t0, tf are provided twice
xf_, pf_ = F(t0, x0, p0, tf, [t0, tf])
Test.@test xf xf_ atol=1e-6

# t0, tf are provided once
xf_, pf_ = F(t0, x0, p0, tf)
Test.@test xf xf_ atol=1e-6

end

end

0 comments on commit ba0c63d

Please sign in to comment.