Special operators
In this section, we present several operations common to dynamical systems.
Projection
When working with SequenceSpace
, one frequently needs to adjust the order of truncation of the chosen basis. This operation is implemented as the project
and project!
functions. In fact, these functions provide a general mechanism to retrieve a finite part of the infinite dimensional operators introduced later in this section.
Each project
or project!
call verifies a compatibility criterion between spaces. For Sequence
and LinearOperator
, two VectorSpace
are compatible if:
- all comprised
SequenceSpace
only differ from their order. For instance,Taylor(n)
andTaylor(m)
are compatible for any positiven::Int
andm::Int
. However,Taylor(n)
andTensorSpace(Taylor(m), Fourier(k, 1.0))
are not compatible for any positiven::Int
,m::Int
andk::Int
. - all comprised
CartesianSpace
have the same number of cartesian products. For instance,CartesianPower(a, 2)
andCartesianProduct(a, a)
are compatible for anya::VectorSpace
. However,CartesianProduct(a, b)
andCartesianProduct(CartesianPower(a, 1), b)
are not compatible for anya::VectorSpace
andb::VectorSpace
.
julia> A = LinearOperator(Taylor(1) ⊗ Chebyshev(1), Taylor(1) ⊗ Chebyshev(1), [1 0 0 0 ; 0 1 0 0 ; 0 0 1 0 ; 0 0 0 1]) # project(I, Taylor(1) ⊗ Chebyshev(1), Taylor(1) ⊗ Chebyshev(1))
LinearOperator : Taylor(1) ⊗ Chebyshev(1) → Taylor(1) ⊗ Chebyshev(1) with coefficients Matrix{Int64}: 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1
julia> project(A, Taylor(1) ⊗ Chebyshev(2), Taylor(2) ⊗ Chebyshev(1))
LinearOperator : Taylor(1) ⊗ Chebyshev(2) → Taylor(2) ⊗ Chebyshev(1) with coefficients Matrix{Int64}: 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0
Moreover, the following identifications are permitted:
julia> a = Sequence(Taylor(1), [1, 1]) # 1 + x
Sequence in Taylor(1) with coefficients Vector{Int64}: 1 1
julia> A = project(a, ParameterSpace(), Taylor(2))
LinearOperator : 𝕂 → Taylor(2) with coefficients Matrix{Int64}: 1 1 0
julia> project(A, space(a))
Sequence in Taylor(1) with coefficients Vector{Int64}: 1 1
Multiplication
Let $V$ be a SequenceSpace
with discrete convolution $*$ and $a \in V$. The multiplication operator Multiplication
represents the mapping $\mathcal{M}_a : V \to V$ defined by
\[\mathcal{M}_a (b) \bydef a * b, \qquad \text{for all } b \in V.\]
The action of Multiplication
is performed by the right product *
of a Multiplication
with a Sequence{<:SequenceSpace}
; alternatively, Multiplication
defines a method on a Sequence{<:SequenceSpace}
representing *
.
julia> a = Sequence(Taylor(1), [1, 1]); # 1 + x
julia> b = Sequence(Taylor(2), [0, 0, 1]); # x^2
julia> a * b
Sequence in Taylor(3) with coefficients Vector{Int64}: 0 0 1 1
julia> ℳ = Multiplication(a)
Multiplication{Sequence{Taylor, Vector{Int64}}}(Sequence(Taylor(1), [1, 1]))
julia> ℳ * b # ℳ(b)
Sequence in Taylor(3) with coefficients Vector{Int64}: 0 0 1 1
A finite dimensional truncation of Multiplication
may be obtained via project
or project!
.
julia> project(ℳ, Taylor(2), codomain(*, Taylor(1), Taylor(2)))
LinearOperator : Taylor(2) → Taylor(3) with coefficients Matrix{Float64}: 1.0 0.0 0.0 1.0 1.0 0.0 0.0 1.0 1.0 0.0 0.0 1.0
Derivation and integration
Both Derivative
and Integral
have a field order::Union{Int,Tuple{Vararg{Int}}}
to specify how many times the operator is composed with itself. No derivation or integration is performed whenever a value of 0
is given.
julia> a = Sequence(Taylor(2), [1, 1, 1]); # 1 + x + x^2
julia> differentiate(a)
Sequence in Taylor(1) with coefficients Vector{Int64}: 1 2
julia> 𝒟 = Derivative(1)
Derivative{Int64}(1)
julia> 𝒟 * a # 𝒟(a)
Sequence in Taylor(1) with coefficients Vector{Int64}: 1 2
A finite dimensional truncation of Derivative
and Integral
may be obtained via project
or project!
:
julia> project(Derivative(1), Taylor(2), codomain(Derivative(1), Taylor(2)), Float64)
LinearOperator : Taylor(2) → Taylor(1) with coefficients Matrix{Float64}: 0.0 1.0 0.0 0.0 0.0 2.0
julia> project(Integral(1), Taylor(2), codomain(Integral(1), Taylor(2)), Float64)
LinearOperator : Taylor(2) → Taylor(3) with coefficients Matrix{Float64}: 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.5 0.0 0.0 0.0 0.3333333333333333
Evaluation
The evaluation operator Evaluation
has a field value::Union{Number,Nothing,Tuple{Vararg{Union{Number,Nothing}}}}
representing the evaluation point. No scaling is performed whenever a value of nothing
is given.
julia> a = Sequence(Taylor(2), [1, 1, 1]); # 1 + x + x^2
julia> evaluate(a, 0.1)
1.11
julia> ℰ = Evaluation(0.1)
Evaluation{Float64}(0.1)
julia> ℰ * a # ℰ(a)
1.11
julia> b = Sequence(Taylor(1) ⊗ Fourier(1, 1.0), [0.5, 0.5, 0.0, 0.0, 0.5, 0.5]); # (1 + x) cos(y)
julia> evaluate(b, (0.1, nothing)) # Evaluation(0.1, nothing) * b
Sequence in Taylor(0) ⊗ Fourier(1, 1.0) with coefficients Vector{Float64}: 0.55 0.0 0.55
Moreover, Evaluation
is defined on CartesianSpace
by acting component-wise.
julia> c = Sequence(Taylor(1)^2, [1, 1, 2, 2]); # 1 + x, 2 + 2x
julia> evaluate(c, 0.1) # Evaluation(0.1) * c
2-element Vector{Float64}: 1.1 2.2
A finite dimensional truncation of Evaluation
may be obtained via project
or project!
:
julia> project(Evaluation(0.1), Taylor(2), codomain(Evaluation(0.1), Taylor(2)), Float64)
LinearOperator : Taylor(2) → Taylor(0) with coefficients Matrix{Float64}: 1.0 0.1 0.010000000000000002
Furthermore, in the context of Evaluation
, the concept of compatibility between two VectorSpace
is more permissive to allow manipulating Evaluation
more like a functional:
julia> project(Evaluation(0.1), Taylor(2), ParameterSpace(), Float64)
LinearOperator : Taylor(2) → 𝕂 with coefficients Matrix{Float64}: 1.0 0.1 0.010000000000000002
Scale
The scale operator Scale
has a field value::Union{Number,Tuple{Vararg{Number}}}
representing the scaling factor. No scaling is performed whenever a value of 1
is given.
julia> a = Sequence(Taylor(2), [1, 1, 1]) # 1 + x + x^2
Sequence in Taylor(2) with coefficients Vector{Int64}: 1 1 1
julia> scale(a, 2)
Sequence in Taylor(2) with coefficients Vector{Int64}: 1 2 4
julia> 𝒮 = Scale(2)
Scale{Int64}(2)
julia> 𝒮 * a # 𝒮(a)
Sequence in Taylor(2) with coefficients Vector{Int64}: 1 2 4
A finite dimensional truncation of Scale
may be obtained via project
or project!
:
julia> project(Scale(2), Taylor(2), codomain(Scale(2), Taylor(2)), Float64)
LinearOperator : Taylor(2) → Taylor(2) with coefficients Matrix{Float64}: 1.0 0.0 0.0 0.0 2.0 0.0 0.0 0.0 4.0
Shift
The shift operator Shift
has a field value::Union{Number,Tuple{Vararg{Number}}}
representing the shift. No shift is performed whenever a value of 0
is given.
Currently, only Fourier
space allows values different than 0
.
julia> a = Sequence(Fourier(1, 1.0), [0.5, 0.0, 0.5]) # cos(x)
Sequence in Fourier(1, 1.0) with coefficients Vector{Float64}: 0.5 0.0 0.5
julia> shift(a, π)
Sequence in Fourier(1, 1.0) with coefficients Vector{ComplexF64}: -0.5 - 6.123233995736766e-17im 0.0 + 0.0im -0.5 + 6.123233995736766e-17im
julia> 𝒮 = Shift(π)
Shift{Irrational{:π}}(π)
julia> 𝒮 * a # 𝒮(a)
Sequence in Fourier(1, 1.0) with coefficients Vector{ComplexF64}: -0.5 - 6.123233995736766e-17im 0.0 + 0.0im -0.5 + 6.123233995736766e-17im
A finite dimensional truncation of Shift
may be obtained via project
or project!
:
julia> project(Shift(π), Fourier(1, 1.0), codomain(Shift(π), Fourier(1, 1.0)), Complex{Float64})
LinearOperator : Fourier(1, 1.0) → Fourier(1, 1.0) with coefficients Matrix{ComplexF64}: -1.0 - 1.2246467991473532e-16im … 0.0 + 0.0im 0.0 + 0.0im 0.0 + 0.0im 0.0 + 0.0im -1.0 + 1.2246467991473532e-16im