Data structure for elements projective space as well as in in products of projective spaces.
Type
ProjectiveVectors.PVector
— Type.PVector{T, N} <: AbstractProjectiveVector{T, N}
A PVector
represents a projective vector z
which lives in a product of N
projective spaces $P(T)^{dᵢ}$. The underlying data structure is a Vector{T}
.
PVector(v::AbstractVector, dims::NTuple{N,Int}) where N
Create a projective vector v
living in a product of projective spaces with (projective) dimensions dims
.
PVector(v, w, ...)
Create the product of projective vectors.
Example
julia> PVector([1,2,3], [4, 5])
[1 : 2 : 3] × [4 : 5]
julia> PVector([1, 2, 3, 4, 5], (2, 1))
[1 : 2 : 3] × [4 : 5]
julia> PVector([1,2,3], [4, 5], [6, 7, 8])
[1 : 2 : 3] × [4 : 5] × [6 : 7 : 8]
Informations and manipulations
ProjectiveVectors.dims
— Function.dims(z::PVector)
Dimensions of the projective spaces in which z
lives.
ProjectiveVectors.homvars
— Function.homvars(z::PVector{T,N})
Return the indices of the homogenization variables.
Example
julia> v = PVector([4, 5, 6], [2, 3], [1, 2])
PVector{Int64, 3}:
[4, 5, 6] × [2, 3] × [1, 2]
julia> homvars(v)
(3, 5, 7)
ProjectiveVectors.dimension_indices
— Function.dimension_indices(z::PVector{T, N})
dimension_indices(dims::NTuple{N, Int})
Return a tuple of N
UnitRange
s indexing the underlying data.
Example
julia> v = PVector([4, 5, 6], [2, 3], [1, 2])
PVector{Int64, 3}:
[4, 5, 6] × [2, 3] × [1, 2]
julia> dimension_indices(v)
(1:3, 4:5, 6:7)
ProjectiveVectors.dimension_indices_homvars
— Function.dimension_indices_homvars(z::PVector{T, N})
dimension_indices_homvars(dims::NTuple{N, Int})
Return a tuple of N
(UnitRange, Int)
tuples indexing the underlying data per vector where the last coordinate in each vector is treated separetely.
Example
julia> v = PVector([4, 5, 6], [2, 3], [1, 2])
PVector{Int64, 3}:
[4, 5, 6] × [2, 3] × [1, 2]
julia> dimension_indices_homvars(v)
((1:2, 3), (4:4, 5), (6:6, 7))
ProjectiveVectors.components
— Function.components(v::PVector{T,N})::NTuple{N, PVector{T, 1}}
Decompose the element $v ∈ P(ℂ^n₁) × ... × P(ℂ^nⱼ)$ into $(v₁, …, vⱼ) = v$
Example
julia> v = PVector([1, 2, 3]);
julia> w = PVector([4, 5]);
julia> v × w
[1 : 2 : 3] × [4 : 5]
julia> components(v × w) == (v, w)
true
ProjectiveVectors.component
— Function.component(v::PVector{T,N}, i)::PVector{T,1}
Obtain the i
-th component of $v ∈ P(ℂ^n₁) × ... × P(ℂ^nⱼ)$.
Example
julia> v = PVector([1, 2, 3]);
julia> w = PVector([4, 5]);
julia> v × w
[1 : 2 : 3] × [4 : 5]
julia> component(v × w, 1)
[1 : 2 : 3]
# alternative you can also indexing
julia> (v × w)[1,:]
[1 : 2 : 3]
ProjectiveVectors.combine
— Function.combine(v::PVector, w::PVector...)
Combine the projective vectors v
and wᵢ
to the flattened product. There is also an operator version, ×
(written imes<tab>
).
Example
julia> v = PVector([1, 2, 3]);
julia> w = PVector([4, 5]);
julia> combine(v, w)
[1 : 2 : 3] × [4 : 5]
LinearAlgebra.:×
— Method.×(v::PVector, w::PVector...)
Operator version of combine
.
Example
julia> v = PVector([1, 2, 3]);
julia> w = PVector([4, 5]);
julia> v × w
[1 : 2 : 3] × [4 : 5]
Conversion between affine and projective space
ProjectiveVectors.affine_chart
— Function.affine_chart(z::PVector)
Return the affine chart corresponding to the projective vector. This can be seen as the inverse of embed
.
Example
julia> v = embed([2.0, 3, 4, 5, 6, 7], (2, 3, 1))
PVector{Float64, 3}:
[2.0, 3.0, 1.0] × [4.0, 5.0, 6.0, 1.0] × [7.0, 1.0]
julia> affine_chart(v)
6-element Array{Float64,1}:
2.0
3.0
4.0
5.0
6.0
7.0
ProjectiveVectors.affine_chart!
— Function.affine_chart!(x, z::PVector)
Inplace variant of affine_chart
.
ProjectiveVectors.embed
— Function.embed(xs::AbstractVector...; normalize=false)
embed(x::AbstractVector{T}, dims::NTuple{N, Int}; normalize=false)::PVector{T, N}
Embed an affine vector x
in a product of affine spaces by the map πᵢ: xᵢ -> [xᵢ; 1] for each subset xᵢ
of x
according to dims
. If normalize
is true the vector is normalized.
Examples
julia> embed([2, 3])
PVector{Int64, 1}:
[2, 3, 1]
julia> embed([2, 3], [4, 5, 6])
PVector{Int64, 2}:
[2, 3, 1] × [4, 5, 6, 1]
julia> embed([2.0, 3, 4, 5, 6, 7], (2, 3, 1))
PVector{Float64, 3}:
[2.0, 3.0, 1.0] × [4.0, 5.0, 6.0, 1.0] × [7.0, 1.0]
julia> embed([2.0, 3, 4, 5, 6, 7], (2, 3, 1), normalize=true)
PVector{Float64, 3}:
[0.5345224838248488, 0.8017837257372732, 0.2672612419124244] × [0.45291081365783825, 0.5661385170722978, 0.6793662204867574, 0.11322770341445956] × [0.9899494936611666, 0.1414213562373095]
Other methods
ProjectiveVectors.data
— Function.data(z::AbstractProjectiveVector)
Access the underlying vector of z
. This is useful to pass the vector into some function which does not know the projective structure.
data(z::AbstractVector)
For general AbstractVector
s this is just the identity.
ProjectiveVectors.norm_affine_chart
— Function. norm_affine_chart(z::PVector, p::Real=2) where {T, N}
Compute the p
-norm of z
on it's affine_chart.
LinearAlgebra.norm
— Method.norm(z::PVector{T,N}, p::Real=2)::NTuple{N, real(T)}
Compute the p
-norm of z
per vector space. This always returns a Tuple
.
Example
julia> norm(embed([1, 2, 3, 4, 5], (2, 3)))
(2.449489742783178, 7.14142842854285)
julia> norm(embed([1, 2, 3, 4, 5]))
(7.483314773547883,)
LinearAlgebra.normalize!
— Method.LinearAlgebra.normalize!(z::PVector, p::Real=2)
Normalize each component of z
separetly.
LinearAlgebra.normalize
— Method.LinearAlgebra.normalize(z::PVector{T, N}, p::Real=2)::PVector{T,N}
Normalize each component of z
separetly.
LinearAlgebra.dot
— Method.LinearAlgebra.dot(v::PVector{T, N}, w::PVector{T2, N}) where {T, T2, N}
Compute the component wise dot product. If decorated with @inbounds
the check of the dims
of v
and w
is skipped.
LinearAlgebra.rmul!
— Method.LinearAlgebra.rmul!(z::PVector{T, N}, λ::NTuple{N, <:Number}) where {T, N}
LinearAlgebra.rmul!(z::PVector{T, 1}, λ::Number) where {T}
Multiply each component of zᵢ
of z
by λ[i]
.
ProjectiveVectors.fubini_study
— Function.fubini_study(v::PVector{<:Number,N}, w::PVector{<:Number, N})
Compute the Fubini-Study distance between v
and w
for each component vᵢ
and wᵢ
. This is defined as $\arccos|⟨vᵢ,wᵢ⟩|$.
Base.isreal
— Method.isreal(v::PVector{T}, tol::Real)
Check whether there exists a fully real representative of v
. For this v
is first normalized, and then the largest entry in each component is made real. If after this the imaginary part of every coordinate is less than tol
the vector is considered real.
Example
julia> a, b = rand(ComplexF64, 2);
julia> v = PVector(a .* [1,2,3]) × PVector(b .* [4, 5]);
julia> isreal(v, 1e-6)
true