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
SequenceSpaceonly differ from their order. For instance,Taylor(n)andTaylor(m)are compatible for any positiven::Intandm::Int. However,Taylor(n)andTensorSpace(Taylor(m), Fourier(k, 1.0))are not compatible for any positiven::Int,m::Intandk::Int. - all comprised
CartesianSpacehave 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::VectorSpaceandb::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 1julia> project(A, Taylor(1) ⊗ Chebyshev(2), Taylor(2) ⊗ Chebyshev(1))LinearOperator : Taylor(1) ⊗ Chebyshev(2) → Taylor(2) ⊗ Chebyshev(1) with coefficients Matrix{Float64}: 1.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
Moreover, the following identifications are permitted:
julia> a = Sequence(Taylor(1), [1, 1]) # 1 + xSequence in Taylor(1) with coefficients Vector{Int64}: 1 1julia> A = project(a, ParameterSpace(), Taylor(2))LinearOperator : 𝕂 → Taylor(2) with coefficients Matrix{Int64}: 1 1 0julia> 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 + xjulia> b = Sequence(Taylor(2), [0, 0, 1]); # x^2julia> a * bSequence in Taylor(3) with coefficients Vector{Int64}: 0 0 1 1julia> ℳ = 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^2julia> differentiate(a)Sequence in Taylor(1) with coefficients Vector{Int64}: 1 2julia> 𝒟 = 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.0julia> 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^2julia> evaluate(a, 0.1)1.11julia> ℰ = Evaluation(0.1)Evaluation{Float64}(0.1)julia> ℰ * a # ℰ(a)1.11julia> 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) * bSequence 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 + 2xjulia> evaluate(c, 0.1) # Evaluation(0.1) * c2-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^2Sequence in Taylor(2) with coefficients Vector{Int64}: 1 1 1julia> scale(a, 2)Sequence in Taylor(2) with coefficients Vector{Int64}: 1 2 4julia> 𝒮 = 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.5julia> 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-17imjulia> 𝒮 = 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