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

fix t0, tf variable #38

Merged
merged 3 commits into from
Aug 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading