Frames Numerically
Working with frames exactly is often very slow, and not possible. Instead it may often be benificial to work with frames defined numerically. Here frames are defined with the Julia Matrix types with entries being any subtype of Number. Functionality for computing spectrums over matricies wiht entries of BigFloat is provided by GenericLinearAlgebra.jl.
Basic Functionality
FrameTheory.is_frame — Method
is_frame(gram) -> Tuple{Bool,Int}Arguments
gram::Matrix{Number}: A square matrix defined over any sub type of Number
Returns
frame_bool::Boold::Int
Determines if the matrix gram is the Gram matrix for some frame. Returns a boolean frame_bool if the provided matrix is the Gram matrix of a frame for some d-dimensional space. If frame_bool' is 'false then d would be nothing.
Examples
julia> ζ = exp(2*pi*im/7);
julia> Phi = [1.0 ζ ζ^2 ζ^3 ζ^4 ζ^5 ζ^6;
1 ζ^2 ζ^4 ζ^6 ζ ζ^3 ζ^5;
1 ζ^4 ζ ζ^5 ζ^2 ζ^6 ζ^3];
julia> gram = Phi'*Phi;
julia> is_frame(gram)
(true, 3)FrameTheory.is_equiangular — Method
is_equiangular(gram) -> Tuple{Bool,Number,Number}Arguments
gram::Matrix{Number}: A square matrix.
Returns
equiangular_bool::Boola::Numberb::Number
Determines if the matrix gram is the Gram matrix for some collection of equiangular vectors. Returns a boolean equiangular_bool if the provided matrix is the Gram matrix of a collection of equiangular lines. With a being the vectors common 'magnatudes' and b the 'angle'. If equiangular_bool is False, then a and b will be nothing.
Examples
julia> ζ = exp(2*pi*im/7);
julia> Phi = [1.0 ζ ζ^2 ζ^3 ζ^4 ζ^5 ζ^6;
1 ζ^2 ζ^4 ζ^6 ζ ζ^3 ζ^5;
1 ζ^4 ζ ζ^5 ζ^2 ζ^6 ζ^3];
julia> gram = Phi'*Phi;
julia> is_equiangular(gram)
(true, 3.0, 2.0000000000000004)FrameTheory.is_frame_tight — Method
is_frame_tight(gram) -> Tuple{Bool,Number}Arguments
gram::Matrix{Number}: A square matrix which is the Gram matrix for a frame.
Returns
tight_bool::Boolc::Number
Determines if the matrix gram is the Gram matrix for frame which is tight. If so returns c being the constant such that gram^2=c*gram. If tight_bool is False, then c will be nothing.
Examples
julia> ζ = exp(2*pi*im/7);
julia> Phi = [1.0 ζ ζ^2 ζ^3 ζ^4 ζ^5 ζ^6;
1 ζ^2 ζ^4 ζ^6 ζ ζ^3 ζ^5;
1 ζ^4 ζ ζ^5 ζ^2 ζ^6 ζ^3];
julia> gram = Phi'*Phi;
julia> is_frame_tight(gram)
(true, 7.000000000000001)FrameTheory.is_ETF — Method
is_ETF(gram) -> Tuple{Bool,Number,Number,Number}Arguments
gram::Matrix{Number}: A square matrix defined over the Reals or Complexes
Returns
etf_bool::Boola::Numberb::Numberc::Numberd::Int
Determines if the matrix gram is the Gram matrix for some collection of vectors which form an equiangular tight frame (ETF). Calls and returns the same parameters from is_frame, is_equiangular, and is_frame_tight.
Examples
A 3x7 Paley (3,2,7)-ETF.
julia> ζ = exp(2*pi*im/7);
julia> Phi = [1.0 ζ ζ^2 ζ^3 ζ^4 ζ^5 ζ^6;
1 ζ^2 ζ^4 ζ^6 ζ ζ^3 ζ^5;
1 ζ^4 ζ ζ^5 ζ^2 ζ^6 ζ^3];
julia> gram = Phi'*Phi;
julia> is_ETF(gram)
(true, 3.0, 2.0000000000000004, 7.000000000000001, 3)Constructions
A common method for numerically constructing ETFs is by the method of Alternating Projections. This method is not guaranteed to converge but can be used to try and determine if such an ETF exists.
FrameTheory.NumCons.rand_etf_from_alt_proj — Function
NumCons.rand_etf_from_alt_proj(T, d, n[; iters]) -> Matrix{T}Arguments
T::Type: A Type for a number such as Float64, Complex{Float64}d::Int: dimension.n::Int: number of vectors.iters::Int=1000: number of iterations to try and converge.
Returns
gram::Matrix{T}: The Gram matrix, if one exists, of adbynETF. Or non-sense if the algorithm failed to converege
This doesnt seem to be working for T=Complex{BigFloat}
Examples
A real 3x6 ETF
julia> gram = NumCons.rand_etf_from_alt_proj(Float64, 3, 6);
julia> is_ETF(gram)
(true, 1.0, 0.19999999999999998, 1.9999999999999998, 3)A complex 2x4 ETF
julia> gram = NumCons.rand_etf_from_alt_proj(Complex{Float64}, 2, 4);
julia> is_ETF(gram)
(true, 1.0, 0.3333333333333331, 1.9999999999999996, 2)No real 2x4 ETF exists A complex 2x4 ETF
julia> gram = NumCons.rand_etf_from_alt_proj(Float64, 2, 4);
julia> is_ETF(gram)
(false, nothing, nothing, nothing, 4)Binder Finder
FrameTheory.binder_finder — Method
binder_finder(gram) -> Matrix{Int}Arguments
gram::Matrix{Number}: The Gram matrix of an ETF.
Returns
binder::Matrix{Int}: The Binder of the provided frame, where each row denotes a simplex.
Examples
julia> ζ = exp(2*pi*im/3);
julia> hessa_sic = [
1 1 1 -1 -1 -1 0 0 0;
0 0 0 1 ζ ζ^2 -1 -1*ζ -1*ζ^2;
-1 -1*ζ^2 -1*ζ 0 0 0 1 ζ^2 ζ
];
julia> hessa_gram = hessa_sic'*hessa_sic;
julia> is_ETF(hessa_gram)
(true, 2.0, 0.9999999999999992, 6.0, 3)
julia> binder_finder(hessa_gram)
12×9 Matrix{Int64}:
1 1 1 0 0 0 0 0 0
1 0 0 1 0 0 1 0 0
1 0 0 0 1 0 0 0 1
1 0 0 0 0 1 0 1 0
0 1 0 1 0 0 0 0 1
0 1 0 0 1 0 0 1 0
0 1 0 0 0 1 1 0 0
0 0 1 1 0 0 0 1 0
0 0 1 0 1 0 1 0 0
0 0 1 0 0 1 0 0 1
0 0 0 1 1 1 0 0 0
0 0 0 0 0 0 1 1 1The Projective Symmetry Group of an ETF
FrameTheory.projective_symmetry_group — Method
projective_symmetry_group(gram) -> PermGroupArguments
gram::Matrix{Number}: A square matrix which is the Gram matrix of some ETF.verbose::Bool: (Defaultfalse).
Returns
G::PermGroup: The group of permutations of the vector of the frame, that correspond to switching equivalences.
BFS backen Adapted from the following Gap code by Joey Iverson: https://github.com/jwiverson/frame-symmetries/blob/main/symp.gap both backends implement the algorithm from section 4 of [7]. Over R or C this algorithm utilizes Proposition 3.3 from the same paper.
Examples
The following is an example of a 2x4 ETF with S4 its symmetry group.
julia> gram = numericalize(ExactCons.dx2d_etf_from_prime_power(3));
julia> typeof(gram)
Matrix{Complex{BigFloat}}
julia> G = projective_symmetry_group(gram)
Permutation group of degree 4
julia> transitivity(G, 1:4)
2
julia> describe(G)
"A4"