/
transformations.jl
131 lines (95 loc) · 3.57 KB
/
transformations.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
using LinearAlgebra
export transform,
backtransform
"""
backtransform(Rsets::ReachSolution, options::Options)
Undo a coordinate transformation.
### Input
- `Rsets` -- flowpipe
- `option` -- problem options containing an `:transformation_matrix` entry
### Output
A new flowpipe where each reach set has been transformed.
### Notes
The transformation is implemented with a lazy `LinearMap`.
"""
function backtransform(Rsets, options::Options)
transformation_matrix = options[:transformation_matrix]
if transformation_matrix == nothing
return Rsets
end
return project(Rsets, transformation_matrix)
end
"""
transform(problem::InitialValueProblem, options::Options)
Interface function that calls the respective transformation function.
### Input
- `problem` -- discrete or continuous initial-value problem
- `option` -- problem options
### Output
A tuple containing the transformed problem and the transformed options.
### Notes
The functions that are called in the background should return a the transformed
system components `A`, `X0`, and `U`, and also an inverse transformation matrix `M`.
If the system has an invariant, it is transformed as well.
"""
function transform(problem::InitialValueProblem, options::Options)
method = options[:coordinate_transformation]
if method == ""
nothing # no-op
elseif method == "schur"
problem, T_inverse = schur_transform(problem)
options[:transformation_matrix] = T_inverse
else
error("the transformation method $method is undefined")
end
return (problem, options)
end
"""
schur_transform(problem::InitialValueProblem)
Applies a Schur transformation to a discrete or continuous initial-value problem.
### Input
- `problem` -- discrete or continuous initial-value problem
### Output
Transformed problem.
### Algorithm
We use Julia's default `schurfact` function to compute a
[Schur decomposition](https://en.wikipedia.org/wiki/Schur_decomposition)
of the coefficients matrix ``A``.
"""
function schur_transform(problem::InitialValueProblem{PT, ST}
) where {PT <: Union{ConstrainedLinearControlDiscreteSystem, ConstrainedLinearControlContinuousSystem}, ST<:LazySet}
n = size(problem.s.A, 1)
# full (dense) matrix is required by schur
# result S is a struct such that
# - S.Schur is in Schur form and
# - A == S.vectors * S.Schur * S.vectors'
S = schur(Matrix(problem.s.A))
# recall that for Schur matrices, inv(T) == T'
Z_inverse = copy(transpose(S.vectors))
# obtain transformed system matrix
A_new = S.Schur
# apply transformation to the initial states
X0_new = Z_inverse * problem.x0
# apply transformation to the inputs
B_new = Z_inverse * problem.s.B
U_new = problem.s.U
# matrix for reverting the transformation again
T_inverse = S.vectors
# apply transformation to the invariant
if hasmethod(stateset, Tuple{typeof(problem.s)})
invariant_new = T_inverse * problem.s.X
else
invariant_new = Universe(n)
end
system_new = _wrap_system(PT, A_new, B_new, invariant_new, U_new)
problem_new = InitialValueProblem(system_new, X0_new)
return problem_new, T_inverse
end
function _wrap_system(PT::Type{<:ConstrainedLinearControlDiscreteSystem},
A, B, invariant, U)
return ConstrainedLinearControlDiscreteSystem(A, B, invariant, U)
end
function _wrap_system(PT::Type{<:ConstrainedLinearControlContinuousSystem},
A, B, invariant, U)
return ConstrainedLinearControlContinuousSystem(A, B, invariant, U)
end