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

Update transformation to canonical form #542

Merged
merged 5 commits into from
Mar 15, 2019
Merged
Changes from 2 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
127 changes: 89 additions & 38 deletions src/Utils/normalization.jl
Original file line number Diff line number Diff line change
@@ -1,68 +1,119 @@
# linear ivp in canonical form x' = Ax
const LCF = LCS{N, AN} where {N, AN<:AbstractMatrix{N}}

# affine ivp with constraints in canonical form x' = Ax + u, u ∈ U, x ∈ X
const ACF = CLCCS{N, AN, IdentityMultiple{N}, XT, UT} where {N, AN<:AbstractMatrix{N}, XT<:LazySet{N}, UT<:AbstractInput}

# type union of canonical forms
const CF = Union{<:LCF, <:ACF}

# accepted types of non-deterministic inputs (non-canonical form)
const UNCF = Union{<:LazySet{N}, Vector{<:LazySet{N}}, <:AbstractInput} where {N}

# accepted types for the state constraints (non-canonical form)
const XNCF = Union{<:LazySet{N}, Nothing} where {N}

"""
normalize(system)
normalize(system::AbstractContinuousSystem)

Normalize a continuous system.
Transform a continuous system to a normalized or canonical form.

### Input

- `system` -- continuous system

### Output

Either the same system if it already conforms to our required structure, or a
new system otherwise.
Either the same system if it already conforms to a canonical form, or a new
system otherwise.

### Algorithm
### Notes

We apply the following normalization steps.
The normalization procedure consists of transforming a given system type into a
"canonical" format that is used internally. The implementation of `normalize`
exploits `MathematicalSystems`'s' types, which carry information about the problem
as a type parameter.
mforets marked this conversation as resolved.
Show resolved Hide resolved

* [`normalize_inputs`](@ref)
"""
function normalize(system::InitialValueProblem{<:Union{AbstractContinuousSystem,
AbstractDiscreteSystem}})
return normalize_inputs(system)
end
The type union `CF` defines the initial value problems considered canonical,
i.e. which do not require normalization. More details are given below.

"""
normalize_inputs(system)
Homogeneous ODEs of the form ``x' = Ax`` are canonical if the associated
problem is a `LinearContinuousSystem` and `A` is a matrix.
Note that it does not consider constraints on the state-space (such as an
mforets marked this conversation as resolved.
Show resolved Hide resolved
invariant); in this case you may have to use a
mforets marked this conversation as resolved.
Show resolved Hide resolved
`ConstrainedLinearControlContinuousSystem`. Moreover, this type does not handle
non-deterministic inputs.

Normalize the inputs of a continuous system.
The generalization to canonical systems with constraints and possibly time-varying
non-deterministic inputs is considered next. These systems are of the form
``x' = Ax + u, u ∈ \\mathcal{U}, x ∈ \\mathcal{X}``. The system type is
`ConstrainedLinearControlContinuousSystem`, where `A` is a matrix, `X` is a set
and `U` is an input, that is, any concrete subtype of `AbstractInput`.

### Input

- `system` -- continuous system
If `U` is not given as an input, normalization accepts either as `LazySet`, or
mforets marked this conversation as resolved.
Show resolved Hide resolved
a vector of `LazySet`'s. In these cases, the sets are wrapped around an appropriate
mforets marked this conversation as resolved.
Show resolved Hide resolved
concrete input type.

### Output

Either the same system if the inputs are of type `AbstractInput`, or a new
system that wraps the inputs in a `ConstantInput`.
If the system does not conform to a canonical form, the implementation tries
to make the transformation; otherwise an error is thrown. In particular, ODEs
of the form ``x' = Ax + Bu`` are mapped into ``x' = Ax + u, u ∈ B\\mathcal{U}``,
where now ``u`` has the same dimensions as ``x``.
"""
function normalize_inputs(system)
inputdim(system) == 0 && return system
U = inputset(system)
U isa AbstractInput && return system
if !(U isa LazySet)
throw(ArgumentError("inputs of type $(typeof(U)) are not supported"))
end
return IVP(wrap_inputs(system.s, U), system.x0)
function normalize(system::AbstractSystem)
throw(ArgumentError("the system type $(typeof(system)) is currently not supported"))
end

function wrap_inputs(system::CLCCS, U::LazySet)
return CLCCS(system.A, system.B, system.X, ConstantInput(U))
# initial value problems in canonical form, i.e. which don't need normalization
normalize(system::CF) = system

# x' = Ax + Bu, x ∈ X, u ∈ U
function normalize(system::CLCCS{N, AN, BN, XT, UT}) where {N, AN<:AbstractMatrix{N}, BN<:AbstractMatrix{N}, XT<:XNCF, UT<:UNCF}
n = statedim(system)
X = _wrap_invariant(system.X, n)
U = _wrap_inputs(system.U, system.B)
CLCCS(system.A, I(n, N), X, U)
end

function wrap_inputs(system::CLCDS, U::LazySet)
return CLCDS(system.A, system.B, system.X, ConstantInput(U))
# x' = Ax + Bu, x ∈ X, u ∈ U
function normalize(system::CLCDS{N, AN, BN, XT, UT}) where {N, AN<:AbstractMatrix{N}, BN<:AbstractMatrix{N}, XT<:XNCF, UT<:UNCF}
n = statedim(system)
X = _wrap_invariant(system.X, n)
U = _wrap_inputs(system.U, system.B)
CLCDS(system.A, I(n, N), X, U)
end

function wrap_inputs(system::CACCS, U::LazySet)
return CACCS(system.A, system.B, system.c, system.X, ConstantInput(U))
# x' = Ax + Bu + c, x ∈ X, u ∈ U
function normalize(system::CACCS{N, AN, BN, VN, XT, UT}) where {N, AN<:AbstractMatrix{N}, BN<:AbstractMatrix{N}, VN<:AbstractVector{N}, XT<:XNCF, UT<:UNCF}
n = statedim(system)
X = _wrap_invariant(system.X, n)
U = _wrap_inputs(system.U, system.B, system.c)
CACCS(system.A, I(n, N), X, U)
end

function wrap_inputs(system::CACDS, U::LazySet)
return CACDS(system.A, system.B, system.c, system.X, ConstantInput(U))
function normalize(system::CACDS{N, AN, BN, VN, XT, UT}) where {N, AN<:AbstractMatrix{N}, BN<:AbstractMatrix{N}, VN<:AbstractVector{N}, XT<:XNCF, UT<:UNCF}
n = statedim(system)
X = _wrap_invariant(system.X, n)
U = _wrap_inputs(system.U, system.B, system.c)
CACDS(system.A, I(n, N), X, U)
end

_wrap_invariant(X::LazySet, n::Int) = X
_wrap_invariant(X::Nothing, n::Int) = Universe(n)

_wrap_inputs(U::AbstractInput, B::IdentityMultiple) = U
_wrap_inputs(U::AbstractInput, B::AbstractMatrix) = map(u -> B*u, U)
schillic marked this conversation as resolved.
Show resolved Hide resolved
_wrap_inputs(U::LazySet, B::IdentityMultiple) = ConstantInput(U)
_wrap_inputs(U::LazySet, B::AbstractMatrix) = ConstantInput(B*U)
_wrap_inputs(U::Vector{<:LazySet}, B::IdentityMultiple) = VaryingInput(U)
_wrap_inputs(U::Vector{<:LazySet}, B::AbstractMatrix) = VaryingInput(map(u -> B*u, U))

_wrap_inputs(U::AbstractInput, B::IdentityMultiple, c::AbstractVector) = U ⊕ c
_wrap_inputs(U::AbstractInput, B::AbstractMatrix, c::AbstractVector) = map(u -> B*u ⊕ c, U)
_wrap_inputs(U::LazySet, B::IdentityMultiple, c::AbstractVector) = ConstantInput(U ⊕ c)
_wrap_inputs(U::LazySet, B::AbstractMatrix, c::AbstractVector) = ConstantInput(B*U ⊕ c)
_wrap_inputs(U::Vector{<:LazySet}, B::IdentityMultiple, c::AbstractVector) = VaryingInput(map(u -> u ⊕ c, U))
_wrap_inputs(U::Vector{<:LazySet}, B::AbstractMatrix, c::AbstractVector) = VaryingInput(map(u -> B*u ⊕ c, U))

"""
distribute_initial_set(system::InitialValueProblem{<:HybridSystem, <:LazySet)

15 changes: 8 additions & 7 deletions src/solve.jl
Original file line number Diff line number Diff line change
@@ -56,25 +56,26 @@ end
solve(system::AbstractSystem, options::Pair{Symbol,<:Any}...) =
solve(system, Options(Dict{Symbol,Any}(options)))

function solve!(system::InitialValueProblem{<:Union{AbstractContinuousSystem,
AbstractDiscreteSystem}},
function solve!(problem::InitialValueProblem,
schillic marked this conversation as resolved.
Show resolved Hide resolved
options_input::Options;
op::ContinuousPost=default_operator(system),
invariant::Union{LazySet, Nothing}=nothing
)::AbstractSolution
system = normalize(system)
options = init!(op, system, options_input)

system = normalize(problem.s)
problem = IVP(system, problem.x0)
options = init!(op, problem, options_input)

# coordinate transformation
if options[:coordinate_transformation] != ""
info("Transformation...")
(system, transformation_matrix) =
@timing transform(system, options[:coordinate_transformation])
(problem, transformation_matrix) =
@timing transform(problem, options[:coordinate_transformation])
options[:transformation_matrix] = transformation_matrix
invariant = options[:coordinate_transformation] * invariant
end

post(op, system, invariant, options)
post(op, problem, invariant, options)
end

"""
11 changes: 4 additions & 7 deletions test/Reachability/solve_continuous.jl
Original file line number Diff line number Diff line change
@@ -120,7 +120,7 @@ s = solve(system, Options(:T=>0.1),
# =======================================================
# Affine ODE with a nondeterministic input, x' = Ax + Bu
# =======================================================
# linear ODE: x' = Ax + Bu
# linear ODE: x' = Ax + Bu, u ∈ U
A = [ 0.0509836 0.168159 0.95246 0.33644
0.42377 0.67972 0.129232 0.126662
0.518654 0.981313 0.489854 0.588326
@@ -137,16 +137,13 @@ U = Interval(0.99, 1.01) × Interval(0.99, 1.01)
# initial set
X0 = BallInf(ones(4), 0.1)

# dense identity matrix
E = Matrix(1.0I, size(A))

# inputs
U1 = ConstantInput(B*U)
U2 = B*U # use internal conversion
U1 = ConstantInput(U)
U2 = U # use internal wrapping

for inputs in [U1, U2]
# instantiate system
Δ = CLCCS(A, E, nothing, inputs)
Δ = CLCCS(A, B, nothing, U)
𝒮 = InitialValueProblem(Δ, X0)

# default options (computes all variables)