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

foo #17

Merged
merged 4 commits into from
Jun 20, 2024
Merged

foo #17

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
8 changes: 2 additions & 6 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,13 @@ on:
- develop
tags: '*'
pull_request:
branches:
- main
tags: '*'
jobs:
test:
name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }}
runs-on: ${{ matrix.os }}
strategy:
matrix:
version:
- '1.8'
- '1.9'
- '1.10'
os:
Expand All @@ -27,12 +23,12 @@ jobs:
arch:
- x64
steps:
- uses: actions/checkout@v1
- uses: actions/checkout@v4
- uses: julia-actions/setup-julia@latest
with:
version: ${{ matrix.version }}
arch: ${{ matrix.arch }}
- uses: julia-actions/add-julia-registry@v1
- uses: julia-actions/add-julia-registry@v2
with:
key: ${{ secrets.SSH_KEY }}
registry: control-toolbox/ct-registry
Expand Down
10 changes: 8 additions & 2 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,18 @@ version = "0.3.7"
CTBase = "54762871-cc72-4466-b8e8-f6c8b58076cd"
DocStringExtensions = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae"
MLStyle = "d8e11817-5142-5d16-987a-aa16d5891078"
OrdinaryDiffEq = "1dea7af3-3e70-54e6-95c3-0bf5283fa5ed"

[weakdeps]
DifferentialEquations = "0c46a032-eb83-5123-abaf-570d42b7fbaa"
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"

[extensions]
CTFlowsODE = "DifferentialEquations"
CTFlowsPlots = "Plots"

[compat]
CTBase = "0.9"
DifferentialEquations = "7.13"
DocStringExtensions = "0.9"
OrdinaryDiffEq = "6.44"
Plots = "1.38"
julia = "1.8"
43 changes: 43 additions & 0 deletions ext/CTFlowsODE.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
module CTFlowsODE

using CTBase
using CTFlows
using DifferentialEquations
using DocStringExtensions
using MLStyle
#
import CTFlows: Flow

# --------------------------------------------------------------------------------------------------
# Aliases
const CoTangent = ctVector
const DCoTangent = ctVector
const ctgradient = CTBase.ctgradient

# from CTFlows
const __variable = CTFlows.__variable
const __abstol = CTFlows.__abstol
const __reltol = CTFlows.__reltol
const __saveat = CTFlows.__saveat
const __alg = CTFlows.__alg
const __tstops = CTFlows.__tstops
const __callback = CTFlows.__callback
const __create_hamiltonian = CTFlows.__create_hamiltonian
const HamiltonianFlow = CTFlows.HamiltonianFlow
const VectorFieldFlow = CTFlows.VectorFieldFlow
const ODEFlow = CTFlows.ODEFlow
const OptimalControlFlow = CTFlows.OptimalControlFlow
const rg = CTFlows.rg

# default
CTFlows.set_default_algorithm(Tsit5())

# --------------------------------------------------------------------------------------------
include("utils.jl")
#
include("vector_field.jl")
include("hamiltonian.jl")
include("optimal_control_problem.jl")
include("function.jl")

end
41 changes: 41 additions & 0 deletions ext/CTFlowsPlots.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
module CTFlowsPlots

using CTBase
using CTFlows: CTFlows
using Plots: plot, Plots
#
import Plots: plot, plot!

# --------------------------------------------------------------------------------------------------
# Aliases
const OptimalControlFlowSolution = CTFlows.OptimalControlFlowSolution
const OptimalControlSolution = CTFlows.OptimalControlSolution

# --------------------------------------------------------------------------------------------------
function Plots.plot(sol::OptimalControlFlowSolution; style::Symbol=:ocp, kwargs...)
ocp_sol = OptimalControlSolution(sol) # from a flow (from ocp and control) solution to an OptimalControlSolution
if style==:ocp
CTBase.plot(ocp_sol; kwargs...)
else
Plots.plot(sol.ode_sol; kwargs...)
end
end

function Plots.plot!(p::Plots.Plot, sol::OptimalControlFlowSolution; style::Symbol=:ocp, kwargs...)
ocp_sol = OptimalControlSolution(sol) # from a flow (from ocp and control) solution to an OptimalControlSolution
if style==:ocp
CTBase.plot!(p, ocp_sol; kwargs...)
else
Plots.plot!(p, sol.ode_sol; kwargs...)
end
end

function Plots.plot(sol::OptimalControlFlowSolution, args...; kwargs...)
Plots.plot(sol.ode_sol, args...; kwargs...)
end

function Plots.plot!(p::Plots.Plot, sol::OptimalControlFlowSolution, args...; kwargs...)
Plots.plot!(p, sol.ode_sol, args...; kwargs...)
end

end
23 changes: 3 additions & 20 deletions src/function.jl → ext/function.jl
Original file line number Diff line number Diff line change
@@ -1,24 +1,7 @@
# ---------------------------------------------------------------------------------------------------
struct ODEFlow <: AbstractFlow{Any, Any}
f::Function # f(args..., rhs): compute the flow
rhs::Function # OrdinaryDiffEq rhs
tstops::Times # stopping times
jumps::Vector{Tuple{Time, Any}} # specific jumps the integrator must perform
function ODEFlow(f, rhs!,
tstops::Times=Vector{Time}(),
jumps::Vector{Tuple{Time, Any}}=Vector{Tuple{Time, Any}}())
return new(f, rhs!, tstops, jumps)
end
end

(F::ODEFlow)(args...; kwargs...) = begin
F.f(args...; jumps=F.jumps, _t_stops_interne=F.tstops, DiffEqRHS=F.rhs, kwargs...)
end

"""
$(TYPEDSIGNATURES)

Returns a function that solves any ODE problem with OrdinaryDiffEq.
Returns a function that solves any ODE problem with DifferentialEquations.
"""
function ode_usage(alg, abstol, reltol, saveat; kwargs_Flow...)

Expand All @@ -27,13 +10,13 @@ function ode_usage(alg, abstol, reltol, saveat; kwargs_Flow...)
jumps, _t_stops_interne, DiffEqRHS, tstops=__tstops(), callback=__callback(), kwargs...)

# ode
ode = isnothing(v) ? OrdinaryDiffEq.ODEProblem(DiffEqRHS, x0, tspan) : OrdinaryDiffEq.ODEProblem(DiffEqRHS, x0, tspan, v)
ode = isnothing(v) ? DifferentialEquations.ODEProblem(DiffEqRHS, x0, tspan) : DifferentialEquations.ODEProblem(DiffEqRHS, x0, tspan, v)

# jumps and callbacks
cb, t_stops_all = __callbacks(callback, jumps, nothing, _t_stops_interne, tstops)

# solve
sol = OrdinaryDiffEq.solve(ode,
sol = DifferentialEquations.solve(ode,
alg=alg, abstol=abstol, reltol=reltol, saveat=saveat, tstops=t_stops_all, callback=cb;
kwargs_Flow..., kwargs...)

Expand Down
23 changes: 2 additions & 21 deletions src/hamiltonian.jl → ext/hamiltonian.jl
Original file line number Diff line number Diff line change
@@ -1,22 +1,3 @@
# ---------------------------------------------------------------------------------------------------
# This is the flow returned by the function Flow
# The call to the flow is given after.
struct HamiltonianFlow <: AbstractFlow{DCoTangent, CoTangent}
f::Function # f(args..., rhs): compute the flow
rhs!::Function # OrdinaryDiffEq rhs
tstops::Times # stopping times
jumps::Vector{Tuple{Time, Costate}} # specific jumps the integrator must perform
function HamiltonianFlow(f, rhs!,
tstops::Times=Vector{Time}(),
jumps::Vector{Tuple{Time, Costate}}=Vector{Tuple{Time, Costate}}())
return new(f, rhs!, tstops, jumps)
end
end

# call F.f
(F::HamiltonianFlow)(args...; kwargs...) = begin
F.f(args...; jumps=F.jumps, _t_stops_interne=F.tstops, DiffEqRHS=F.rhs!, kwargs...)
end

"""
$(TYPEDSIGNATURES)
Expand All @@ -29,14 +10,14 @@ function hamiltonian_usage(alg, abstol, reltol, saveat; kwargs_Flow...)
jumps, _t_stops_interne, DiffEqRHS, tstops=__tstops(), callback=__callback(), kwargs...)

# ode
ode = OrdinaryDiffEq.ODEProblem(DiffEqRHS, [x0; p0], tspan, v)
ode = DifferentialEquations.ODEProblem(DiffEqRHS, [x0; p0], tspan, v)

# jumps and callbacks
n = size(x0, 1)
cb, t_stops_all = __callbacks(callback, jumps, rg(n+1, 2n), _t_stops_interne, tstops)

# solve
sol = OrdinaryDiffEq.solve(ode,
sol = DifferentialEquations.solve(ode,
alg=alg, abstol=abstol, reltol=reltol, saveat=saveat, tstops=t_stops_all, callback=cb;
kwargs_Flow..., kwargs...)

Expand Down
59 changes: 59 additions & 0 deletions ext/optimal_control_problem.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# ---------------------------------------------------------------------------------------------------
"""
$(TYPEDSIGNATURES)

Flow from an optimal control problem and a control function in feedback form.

# Example
```jldoctest
julia> f = Flow(ocp, (x, p) -> p)
```

!!! warning

The time dependence of the control function must be consistent with the time dependence of the optimal control problem.
The dimension of the output of the control function must be consistent with the dimension usage of the control of the optimal control problem.
"""
function Flow(ocp::OptimalControlModel{T, V}, u_::Union{Function, ControlLaw{T, V}}; alg=__alg(), abstol=__abstol(),
reltol=__reltol(), saveat=__saveat(), kwargs_Flow...) where {T, V}
#
h, u = __create_hamiltonian(ocp, u_) # construction of the Hamiltonian
return __ocp_Flow(ocp, h, u, alg, abstol, reltol, saveat; kwargs_Flow...)
end

# ---------------------------------------------------------------------------------------------------
"""
$(TYPEDSIGNATURES)

Flow from an optimal control problem, a control function in feedback form, a state constraint and its
associated multiplier in feedback form.

# Example
```jldoctest
julia> ocp = Model(autonomous=false)
julia> f = Flow(ocp, (t, x, p) -> p[1], (t, x, u) -> x[1] - 1, (t, x, p) -> x[1]+p[1])
```

!!! warning

The time dependence of the control function must be consistent with the time dependence of the optimal control problem.
The dimension of the output of the control function must be consistent with the dimension usage of the control of the optimal control problem.
"""
function Flow(ocp::OptimalControlModel{T, V},
u_::Union{Function, ControlLaw{T, V}, FeedbackControl{T, V}},
g_::Union{Function, MixedConstraint{T, V}, StateConstraint{T, V}},
μ_::Union{Function, Multiplier{T, V}};
alg=__alg(), abstol=__abstol(),
reltol=__reltol(), saveat=__saveat(), kwargs_Flow...) where {T, V}
#
h, u = __create_hamiltonian(ocp, u_, g_, μ_) # construction of the Hamiltonian
return __ocp_Flow(ocp, h, u, alg, abstol, reltol, saveat; kwargs_Flow...)
end

# ---------------------------------------------------------------------------------------------------
function __ocp_Flow(ocp::OptimalControlModel{T, V}, h::Hamiltonian, u::ControlLaw,
alg, abstol, reltol, saveat; kwargs_Flow...) where {T, V}
rhs! = rhs(h) # right and side: same as for a flow from a Hamiltonian
f = hamiltonian_usage(alg, abstol, reltol, saveat; kwargs_Flow...) # flow function
return OptimalControlFlow(f, rhs!, u, ocp)
end
1 change: 0 additions & 1 deletion src/utils.jl → ext/utils.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

# ---------------------------------------------------------------------------------------------------
function __callbacks(callback, jumps, _rg, _t_stops_interne, tstops)

Expand Down
22 changes: 2 additions & 20 deletions src/vector_field.jl → ext/vector_field.jl
Original file line number Diff line number Diff line change
@@ -1,21 +1,3 @@
# ---------------------------------------------------------------------------------------------------
struct VectorFieldFlow <: AbstractFlow{DState, State}
f::Function # f(args..., rhs): compute the flow
rhs::Function # OrdinaryDiffEq rhs
tstops::Times # stopping times
jumps::Vector{Tuple{Time, State}} # specific jumps the integrator must perform
function VectorFieldFlow(f, rhs,
tstops::Times=Vector{Time}(),
jumps::Vector{Tuple{Time, State}}=Vector{Tuple{Time, State}}())
return new(f, rhs, tstops, jumps)
end
end

# call F.f
(F::VectorFieldFlow)(args...; kwargs...) = begin
F.f(args...; jumps=F.jumps, _t_stops_interne=F.tstops, DiffEqRHS=F.rhs, kwargs...)
end

"""
$(TYPEDSIGNATURES)

Expand All @@ -28,13 +10,13 @@ function vector_field_usage(alg, abstol, reltol, saveat; kwargs_Flow...)
jumps, _t_stops_interne, DiffEqRHS, tstops=__tstops(), callback=__callback(), kwargs...)

# ode
ode = OrdinaryDiffEq.ODEProblem(DiffEqRHS, x0, tspan, v)
ode = DifferentialEquations.ODEProblem(DiffEqRHS, x0, tspan, v)

# jumps and callbacks
cb, t_stops_all = __callbacks(callback, jumps, nothing, _t_stops_interne, tstops)

# solve
sol = OrdinaryDiffEq.solve(ode,
sol = DifferentialEquations.solve(ode,
alg=alg, abstol=abstol, reltol=reltol, saveat=saveat, tstops=t_stops_all, callback=cb;
kwargs_Flow..., kwargs...)

Expand Down
Loading
Loading