The following is a list of all exported functions in Zauner
.
Types
Zauner.AdmissibleTuple
— TypeAdmissibleTuple( d::Integer [, Q::QuadBin])
AdmissibleTuple( d::Integer, r::Integer [, Q::QuadBin])
AdmissibleTuple( D::Integer, j::Integer, m::Integer [, Q::QuadBin])
AdmissibleTuple( dQ::Tuple{Integer, QuadBin{ZZRingElem}})
AdmissibleTuple( drQ::Tuple{Integer, Integer, QuadBin{ZZRingElem}})
Data type for the arithmetic data defining a set of ghost overlaps.
If only one integer is given, it is interpreted as a dimension and assumed that the rank is r = 1
. The syntax that takes three integers (D,j,m)
requires that D
is a fundamental discriminant for a real quadratic field.
In all three cases, if the optional argument Q
is left unspecified, then it defaults to a principal form given by Q = binary_quadratic_form( 1, 2-n, 1)
, where n
is the integer (d^2-1)/(r(d-r))
, since this has $\mathrm{disc}(Q) = n(n-4)$.
The final way to specify an input is as a tuple (d,Q)
or (d,r,Q)
.
The defined (and precomputed) fields in an AdmissibleTuple
are given by:
d ::Integer # dimension
r ::Integer # rank
n ::Integer # (d^2-1)/(r*(d-r))
K ::AbsSimpleNumField # associated field K = ℚ(√n(n-4))
D ::Integer # fundamental discriminant of K
f ::Integer # conductor, where n*(n-4) = D*f^2
q ::Integer # conductor of Q
j ::Integer # grid vertical position
m ::Integer # grid horozontal position
a ::AbsSimpleNumFieldElem # associated field generator √D
u ::AbsSimpleNumFieldOrderElem # Zauner unit
H ::AbsSimpleNumField # (lazy) ring class field for q*Z(K)
g ::NumFieldAut # (lazy) Galois automorphism in H s.t. g(√D) = -√D
h ::Integer # class number, or degree of H/K
G ::Vector{Integer} # orders of class group generators
c ::Vector{QuadBin} # basis of generator Q's for the class group
Q ::QuadBin # binary quadratic form
L ::Matrix{ZZRingElem} # S(Q) generator
k ::Integer # L^k = I mod d
A ::Matrix{ZZRingElem} # S_d(Q) generator
x ::BigFloat # positive root of Q
R ::BigFloat # log of u
The fields marked '(lazy)', namely 'H' and 'g', are not initialized at first since their computation is substantially more expensive than the other fields. Once they have been computed their values are memoized and do not have to be recomputed.
From the way that H
is computed currently, K
is not recognized as a subfield. This could lead to some non-intuitive results. For example, the quadratic generator a
is an element of K
, but not a recognized element of H
. If an explicit embedding is needed, it can be obtained using is_subfield(K,H)
.
Examples
julia> AdmissibleTuple(5)
AdmissibleTuple( d = 5, K = ℚ(√12), q = 1, Q = ⟨1,-4,1⟩, h = 1 )
julia> AdmissibleTuple(11,3)
AdmissibleTuple( d = 11, r = 3, K = ℚ(√5), q = 1, Q = ⟨1,-3,1⟩, h = 1 )
julia> AdmissibleTuple(5,1,1)
AdmissibleTuple( d = 4, K = ℚ(√5), q = 1, Q = ⟨1,-3,1⟩, h = 1 )
julia> AdmissibleTuple(11,binary_quadratic_form(3,-12,4))
AdmissibleTuple( d = 11, K = ℚ(√24), q = 2, Q = ⟨3,-12,4⟩, h = 2 )
Galois groups
Zauner.centralizer_elements
— Functioncentralizer_elements(F::AdmissibleTuple)
Compute the elements of $\mathrm{GL}(2,\mathbb{Z}/d')$ that are in the centralizer of the stability group for F
.
Examples
The centralizer for $d=5$ has 24 elements.
julia> F = AdmissibleTuple(5);
julia> cent = centralizer_elements(F);
julia> length(cent)
24
Zauner.galois_elements
— Functiongalois_elements(F::AdmissibleTuple)
galois_elements(d::Integer, gens::Vector{Matrix{ZZRingElem}}, ords::Vector{Integer})
Compute one element from each coset of $\mathcal{M}/\mathcal{S}$ where $\mathcal{M}$ is a maximal abelian subgroup of $\mathrm{GL}(2,\mathbb{Z}/d')$ and $\mathcal{S}$ is the stabilizer of F
. The second form takes the dimension d
and the generators and orders of generators for the galois group, as is computed by galois_normal_form
. The output is an array of Matrix{ZZRingElem}
elements whose size is the the same as ords
.
Zauner.galois_group_structure
— Functiongalois_group_structure(F::AdmissibleTuple)
Compute the canonical form (decomposition into cyclic groups) for the Galois group using the Smith normal form.
Zauner.galois_normal_form
— Functiongalois_normal_form(F::AdmissibleTuple)
Compute the normal form of the group $\mathcal{M}/\mathcal{S}$ where $\mathcal{M}$ is a maximal abelian subgroup of $\mathrm{GL}(2,\mathbb{Z}/d')$ and $\mathcal{S}$ is the stabilizer of F
. This is group is (conjecturally) isomorphic to the Galois group. The output is a tuple (g,n)
where g
is a vector of generator matrices and n
is a vector of the orders of those matrices in $\mathcal{M}/\mathcal{S}$. This corresponds to the canonical decomposition $\mathbb{Z}/n_1 ⊕ \mathbb{Z}/n_2 ⊕ ... ⊕ \mathbb{Z}/n_k$ where the $n_j$ are each prime powers. The factors are canonical up to permutation (though the generators are not).
Examples
julia> F = AdmissibleTuple( 7, QuadBin(2,-4,1))
AdmissibleTuple( d = 7, K = ℚ(√8), q = 1, Q = ⟨2,-4,1⟩, h = 1 )
julia> g, n = galois_normal_form(F)
(Matrix{ZZRingElem}[[6 0; 0 6], [2 0; 0 2]], [2, 3])
julia> F = AdmissibleTuple(9)
AdmissibleTuple( d = 9, K = ℚ(√60), q = 1, Q = ⟨1,-8,1⟩, h = 2 )
julia> g, n = galois_normal_form(F)
(Matrix{ZZRingElem}[[8 5; 4 3], [8 0; 0 8], [7 0; 0 7]], [3, 2, 3])
Zauner.galois_orbit
— Functiongalois_orbit(F::AdmissibleTuple)
galois_orbit(F::AdmissibleTuple, T::Matrix{ZZRingElem}, n::Integer)
Compute a maximal Galois orbit. Output is a vector of Vector{Integer}
elements lying on a maximal orbit for the tuple F
. The second form computes the Galois orbit with the centralizer subgroup generated by T
of order n
removed.
Zauner.galois_order_orbit
— Functiongalois_order_orbit(F::AdmissibleTuple)
Compute the orders of the elements of the Galois group and a maximal orbit, output as a tuple.
Zauner.stabilizer_elements
— Functionstabilizer_elements(F::AdmissibleTuple)
Compute the elements of $\mathrm{GL}(2,\mathbb{Z}/d')$ that are in the complete stabilizer for F
, including the extra antiunitary symmetry (if present). The elements are ordered so that the identity element is first.
Examples
julia> F = AdmissibleTuple(7)
AdmissibleTuple( d = 7, K = ℚ(√8), q = 2, Q = ⟨1,-6,1⟩, h = 1 )
julia> stabilizer_elements(F)
3-element Vector{Matrix{ZZRingElem}}:
[1 0; 0 1]
[6 6; 1 0]
[0 1; 6 6]
Analysis
Zauner.double_sine
— Functiondouble_sine(x,ω1,ω2 [; points=21])
The double sine function, defined in terms of the double gamma function following Shintani's convention:
\[S_2(x,\boldsymbol{\omega}) = \frac{\Gamma_2(x,\boldsymbol{\omega})}{\Gamma_2(\omega_1+\omega_2-x,\boldsymbol{\omega})}\]
This is currently implemented for real values only.
When $0 < x < ω_1 + ω_2$, $\log S_2$ has the integral representation
\[ \log S_2(x,\boldsymbol{ω}) = \frac12 \int_0^\infty \left(\frac{\sinh\bigl((ω_1 + ω_2 - 2x)t\bigr)}{\sinh(ω_1 t)\sinh(ω_2 t)} - \frac{ω_1 + ω_2 - 2 x}{ω_1 ω_2 t}\right) \frac{\mathrm{d}t}{t}\]
Evaluation proceeds via numerical integration using adaptive Gauss quadrature using the optional keyword argument points
set to 21 by default.
If $x$ is outside this fundamental domain, then the following period shift formulas can be applied until the integral formula can be applied. We have
\[ S_2(x,\boldsymbol{ω}) = S_2(x + ω_1,\boldsymbol{ω}) / \bigl(2 \sin(\pi x / ω_2) \bigr)\]
and similarly with $ω_1$ and $ω_2$ exchanged. Note that $S_2(x,\boldsymbol{ω})$ is symmetric with respect to $ω_1, ω_2$. In our implementation, we recursively shift by $ω_2$ until the fundamental domain is reached.
Note: Many authors, including Koyama & Kurokawa, Kurokawa & Koyama, and Tangedal, use a convention which replaces $S_2$ by $1/S_2$ relative to our convention.
Zauner.e
— Functione(z)
Normalized exponential function, $e(z) = \exp(2 \pi i z)$.
Zauner.q_pochhammer
— Functionq_pochhammer(a, q, n)
Finite q-Pochhammer symbol, $\prod_{k=0}^{n-1} \bigl(1-a q^k\bigr)$.
Zauner.q_pochhammer_exp
— Functionq_pochhammer_exp(z, τ, n)
Finite exponential-variant q-Pochhammer symbol, extended to include $n < 0$. Defined as
\[\varpi_n(z,\tau) = \begin{cases} \prod_{j=0}^{n-1}\bigl(1-\mathrm{e}^{2 \pi i (z+j \tau)}\bigr) \qquad & n>0 \\ 1 \qquad & n=0 \\ \prod_{j=n}^{-1}\bigl(1-\mathrm{e}^{2 \pi i (z+j \tau)}\bigr)^{-1} \qquad & n<0 \end{cases}\,.\]
Binary Quadratic Forms
Zauner.qmat
— Functionqmat(Q::QuadBin)
The matrix of a quadratic form Q
.
Zauner.quadbinid
— Functionquadbinid(D)
The principal reduced form with discriminant D.
SL(2,ℤ)
Zauner.is_sl2z
— Functionis_sl2z(M)
Returns true
if the matrix M
is a 2x2 integer matrix with determinant 1.
Zauner.psl2word
— Functionpsl2word(v::Vector)
psl2word(A::Matrix)
Return the product $T^{v_1} S T^{v_2} S...S T^{v_n}$ where $S$ and $T$ are the standard generators of $\mathrm{SL}(2,\mathbb{Z})$.
Decompose a matrix A
in $\mathrm{SL}(2,\mathbb{Z})$ into a product of $S$ and $T$ generators, modulo $-I$. Reduction is done using rounding up with ceiling (Hirzebruch-Jung or negative regular continued fraction reduction) and returning a product strictly in terms of $S$ and $T$ except for the first or final element, which might be negative.
Zauner.rademacher
— Functionrademacher(M)
Rademacher invariant of the $\mathrm{SL}(2,\mathbb{Z})$ matrix M
. Reference: Hans Rademacher Zur Theorie der Dedekindschen Summen Mathematische Zeitschriften vol 63, pp. 445–463 (1955).
Zauner.sl2zorder
— Functionsl2zorder(L, d)
Find the order of $L \bmod d$ where $L$ is in $\mathrm{SL}(2,\mathbb{Z})$. Brute force algorithm.
Hirzebruch-Jung continued fractions
Zauner.minimal_hj_stabilizer
— Functionminimal_hj_stabilizer(V::Vector{QuadBin{ZZRingElem}},d)
Returns a minimal form Q
among those in V
. Specifically, if V
is a reduced HJ orbit then the output Q
minimizes the length of the HJ expansion of the stabilizer of Q
modulo d
. The function assumes that Q.a > 0 for each form in V. To break ties on length, the algorithm further chooses a minimal form by minimizing according first to the sum of the absolute coefficients, then by the maximum absolute coefficient. See the internal function _quadcompare_sum_then_max
for details of the comparison function used for sorting.
Zauner.reduced_hj_orbit
— Functionreduced_hj_orbit(q::QuadBin{ZZRingElem})
Returns the reduced orbit under HJ reduction.
Examples
julia> reduced_hj_orbit(binary_quadratic_form(1,-4,1))
3-element Vector{QuadBin{ZZRingElem}}:
Binary quadratic form over ZZ: x^2 - 4*x*y + y^2
Binary quadratic form over ZZ: 3*x^2 - 6*x*y + 2*y^2
Binary quadratic form over ZZ: 2*x^2 - 6*x*y + 3*y^2
Ghosts
Zauner.ghost
— Functionghost(F:AdmissibleTuple)
Compute a ghost as a d × d matrix from the admissible tuple F
.
Only rank-1 ghosts are supported at this time.
Zauner.ghostbasis
— Functionghostbasis(d)
Compute a generating set (under Gauss composition) for the allowed quadratic forms in dimension d.
This returns a dictionary where each key is a divisor f
of the conductor of D = (d+1)*(d-3)
and each value is the tuple (c,Q)
where c[k]
is the order of Q[k]
under Gauss composition.
Examples
julia> ghostbasis(15)
Dict{ZZRingElem, Tuple{Vector{ZZRingElem}, Vector{QuadBin}}} with 3 entries:
4 => ([2], [Binary quadratic form over ZZ: 3*x^2 + 12*x*y - 4*y^2])
2 => ([1], [Binary quadratic form over ZZ: x^2 + 6*x*y - 3*y^2])
1 => ([1], [Binary quadratic form over ZZ: x^2 + 2*x*y - 2*y^2])
In this example, Q = QuadBin(3,12,-4)
has order 2, so we have Q^2 == QuadBin(1,12,-12)
since this is the principal form with the same discriminant.
Zauner.ghostclassfield
— Functionghostclassfield( K::AbsSimpleNumField, q)
ghostclassfield( F::AdmissibleTuple)
Compute the ring class field for the order q*ℤ(K) where ℤ(K) is the maximal order in K. The output is an LLL-reduced AbsSimpleNumField
, and so is an absolute field rather than a relative extension.
Given an AdmissibleTuple
F
it initializes the field F.H
to be this ring class field.
Zauner.ghostelements
— Functionghostelements(d)
Compute a representative quadratic form for each ghost class in dimension d
. There are a total of numsics(d)
such forms. These forms are merely Euclidean reduced, not Hirzebruch-Jung reduced.
Necromancy
Zauner.guess_int_null_vec
— Functionguess_int_null_vec( x::Vector{BigFloat})
Use LLL to find an integer relation among the elements of x
.
Examples
julia> guess_int_null_vec(BigFloat.([1; sin(big(pi)/8)^2; sin(big(pi)/4)]))
3-element Vector{BigInt}:
-1
2
1
Zauner.matrix_completion
— Functionmatrix_completion( nu::AbstractArray, F::AdmissibleTuple
[; verbose::Bool = false, shift::Integer = 0, test::Bool = false,
max_iters = 1e5, eps_abs = 1e-7, eps_infeas = 1e-7, eps_rel = 1e-7])
Given the SIC phase overlaps nu
on a maximal galois orbit, compute the associated SIC fiducial vector ψ
. If the input does not correspond to a valid SIC with admissible data F
, then the output is unpredictable.
Zauner.necromancy
— Functionnecromancy( F::AdmissibleTuple [; max_prec = 2^20, verbose = false])
Compute a numerical approximations to a SIC associated to the AdmissibleTuple
F
. The maximum number of bits used in integer relation finding is set to max_prec
(default of 1 Mb) and verbose
can be toggled true
or false
.
Examples
Check that the principal SIC in $d=7$ satisfies the equiangularity conditions.
julia> d = 7; F = AdmissibleTuple(d)
AdmissibleTuple( d = 7, K = ℚ(√8), q = 2, Q = ⟨1,-6,1⟩, h = 1 )
julia> ψ = necromancy(F);
julia> all([ abs2(ψ'wh(p,ψ)) for p=1:d^2-1] .≈ 1/(d+1))
true
Zauner.pow_to_elem_sym_poly
— Functionpow_to_elem_sym_poly( p::AbstractVector)
Convert a vector of power sums to elementary symmetric polynomials. Assumes that that p[k]
is the power sum of degree k
. No check is done to ensure that the input is a valid collection of power sums, it simply applies the relevant recursion relation. Output e
is indexed so that e[1] == 1
is the zeroth elementary symmetric polynomial and length(e) == length(p)+1
.
Newton's method
Zauner.precision_bump
— Functionprecision_bump(ψ::Vector{Complex{BigFloat}}, prec::Integer [; base::Integer = 10, verbose::Bool = true])
precision_bump(ψ::Vector{Complex{BigFloat}}, f::Function, prec::Integer [; base::Integer = 10, verbose::Bool = true])
Attempt to use Newton's method to improve the precision of ψ
to at least prec
digits in base base
. In the second version, the function f
is used for root finding.
Zauner.precision_bump!
— Functionprecision_bump!(z::Vector{BigFloat}, prec::Integer [; base::Integer = 10, verbose::Bool = true])
precision_bump!(z::Vector{BigFloat}, f::Function, prec::Integer [; base::Integer = 10, verbose::Bool = true])
Attempt to use Newton's method to improve the precision of z
to at least prec
digits in base base
, where z
is the real projective representation of ψ
. In the second version, the function f
is used for root finding.
Zauner.re_im_proj
— Functionre_im_proj(ψ::Vector{Complex{BigFloat}})
re_im_proj(z::Vector{BigFloat})
Stack the real and imaginary parts of the vector ψ
and normalize so that the first coordinate, assumed nonzero, is normalized to 1 and then dropped.
If called with type Vector{BigFloat}
then it does the inverse transformation, taking an even-length real vector to a complex one with unit first coordinate.
Examples
A simple example:
v = Complex{BigFloat}.([ 1; im; -1; -im])
re_im_proj(v)
# output
6-element Vector{BigFloat}:
0.0
-1.0
0.0
1.0
0.0
-1.0
Validation
Zauner.ghost_frame_test
— Functionghost_frame_test(ψ::AbstractVector)
Return the maximum absolute deviation of the pointwise frame conditions. This is the ghost analog of eq. 8 of arXiv:0707.2071.
Zauner.ghost_overlap_test
— Functionghost_overlap_test(ψ::AbstractVector)
Check the ghost overlap conditions. If all ghost overlaps are approximately real, it returns
\[\max_{\boldsymbol{p} \not=\boldsymbol{0}} \bigl|\nu_{\boldsymbol{p}} \nu_{-\boldsymbol{p}} - \tfrac{1}{d+1}\bigr|\,.\]
If they aren't approximately real it throws an error.
Zauner.sic_frame_test
— Functionsic_frame_test(ψ::AbstractVector)
Return the absolute deviation of the pointwise conditions on the frame potential from eq. 8 of arXiv:0707.2071. Let $T(k,l) = \sum_j \psi_{j}\psi_{j+k}^* \psi_{j+l}^* \psi_{j+k+l}$, and recall that $\psi$ is a SIC if and only if $T(k,l) - \frac{\delta_{k,0}+\delta_{l,0}}{d+1} = 0$. The function returns the maximum absolute deviation from these conditions.
Zauner.sic_overlap_test
— Functionsic_overlap_test(ψ::AbstractVector)
Check the SIC equiangularity conditions by returning
\[\max_{\boldsymbol{p} \not=\boldsymbol{0}} \bigl|\nu_{\boldsymbol{p}} \nu_{-\boldsymbol{p}} - \tfrac{1}{d+1}\bigr|\,,\]
where $\nu_{\boldsymbol{p}} = \langle\psi|D_{\boldsymbol{p}}|\psi\rangle$ are the SIC overlaps.
Real quadratic orders
Zauner.class_group_structure
— Functionclass_group_structure(D)
Returns class group structure for the quadratic order with disciminant D
.
Zauner.coredisc
— Functioncoredisc(D)
coredisc(Q::QuadBin)
Outputs a tuple (Δ,f)
of the fundamental discriminant Δ
and conductor f
of D
, or of a binary quadratic form with discriminant D
.
Examples
Here are two examples with fundamental discriminant 5 and conductor 3.
julia> coredisc(45) # 45 = 3^2 * 5
(5, 3)
julia> coredisc( binary_quadratic_form(1,-7,1) ) # -4*det( [1 -7//2; -7//2 1]) == 3^2 * 5
(5, 3)
See also conductor
.
Zauner.pell
— Functionpell(D)
pell(Q::QuadBin)
pell(Zω::AbsSimpleNumFieldOrder)
Finds the least unit > 1 having norm 1 for the discriminant D
, for the binary quadratic form with discriminant D
, or the quadratic order ℤ(ω) where $ω = \frac{1}{2}\bigl( (D \mod 4) + \sqrt{D}\bigr)$.
Example
The fundamental unit for $ℚ(\sqrt{5})$ is $(\sqrt{5}+1)/2$, but this has norm -1, so we return the square of this.
julia> pell(5)
1//2*sqrt(5) + 3//2
Zauner.pellreg
— Functionpellreg(D)
pellreg(Q::QuadBin)
pellreg(Zω::AbsSimpleNumFieldOrder)
Finds the least unit > 1 having norm 1 for the discriminant D
, for the binary quadratic form with discriminant D
, or the quadratic order ℤ(ω) where $ω = \frac{1}{2}\bigl( (D \mod 4) + \sqrt{D}\bigr)$. The output is a tuple with the unit and a BigFloat
of the log of that unit (which is just the regulator of ℤ(ω), or twice that if the fundamental unit has norm -1).
A limitation of the current implementation is that the regulator is only correct to about 128 bits, even though it returns a number to the current precision of BigFloat
.
See also pell
.
Zauner.quadclassunit
— Functionquadclassunit(D)
Returns class group and unit group data for the quadratic order with disciminant D
. Let $\omega = \bigl(\Delta\bmod 4 + \sqrt{\Delta}\bigr)/2$, so that a $\mathbb{Z}$-basis is $\mathbb{Z}+\omega\mathbb{Z}$. Then the output is a tuple (h,c,b,u)
, where
h
is the class number,c
is an integer vector for the cycle stucture of the class group, $\mathbb{Z}/{n_1} + \ldots + \mathbb{Z}/{n_r}$.b
is a vector of binary quadratic forms that generate the corresponding factor in the class group,u
is the totally positive fundamental unit with norm 1, written as[x,y]
in the above basis.
Zauner.signswitch
— Functionsignswitch( H::AbsSimpleNumField, D::Integer)
signswitch( F::AdmissibleTuple)
If H
is the (absolute) ring class field for a ghost with fundamental discriminant D
with some conductor, then this finds a sign-switching Galois automorphism g
on H
, that is $g\bigl(\sqrt{D}\bigr) = -\sqrt{D}$.
If F
is an AdmissibleTuple
then is initializes the field F.g
. This requires that the field F.H
has already been initialized with ghostclassfield
.
Property testing
Zauner.has_fa_symmetry
— Functionhas_fa_symmetry(F::AdmissibleTuple)
Test for $F_a$ symmetry as opposed to Zauner ($F_z$) symmetry.
Zauner.is_admissible
— Functionis_admissible( d::Integer [, Q::QuadBin])
is_admissible( d::Integer, r::Integer [, Q::QuadBin])
is_admissible( D::Integer, j::Integer, m::Integer [, Q::QuadBin])
Test whether the arguments form an admissible tuple.
Examples
julia> is_admissible(5,1)
true
julia> is_admissible(5,2)
false
julia> is_admissible(5,1,1)
true
julia> is_admissible(5,2,1,binary_quadratic_form(1,-7,1))
true
julia> is_admissible(11,1,binary_quadratic_form(3,-12,4))
true
Zauner.is_antiunitary
— Functionis_antiunitary(F::AdmissibleTuple)
Test if the tuple F
has antiunitary symmetry.
Zauner.is_antiunitary_with_generator
— Functionis_antiunitary_with_generator(F::AdmissibleTuple)
Test if the tuple F
has antiunitary symmetry and return a tuple: if the first output is true
, the second element of the tuple is a symmetry generator, and if false
, the second output is the zero matrix.
Utilities
Zauner.dq
— Functiondq(k)
Precomputed values of admissible tuples (d,Q)
with d ≤ 256
, comprising the first 3292 such inequivalent tuples when ordered by dimension. The forms Q
have been chosen (non-uniquely) to minimize the period of the Hirzebruch-Jung continued fraction expansion of their positive root.
Examples
julia> dq(1)
(4, Binary quadratic form over ZZ: x^2 - 3*x*y + y^2)
It can also be called with collections to access multiple tuples.
julia> dq(20:23)
4-element Vector{Tuple{Int64, QuadBin{ZZRingElem}}}:
(15, Binary quadratic form over ZZ: x^2 - 4*x*y + y^2)
(15, Binary quadratic form over ZZ: 4*x^2 - 8*x*y + y^2)
(15, Binary quadratic form over ZZ: x^2 - 14*x*y + y^2)
(15, Binary quadratic form over ZZ: 11*x^2 - 18*x*y + 3*y^2)
The associated AdmissibleTuple
can be obtained directly.
julia> AdmissibleTuple(dq(2))
AdmissibleTuple( d = 5, K = ℚ(√12), q = 1, Q = ⟨1,-4,1⟩, h = 1 )
Zauner.numsics
— Functionnumsics(d)
Number of WH 1-SICs in dimension d, modulo EC orbits.
Example
Here are the number of inequivalent 1-SICs for dimensions 4-15:
julia> foreach(d -> println( (d, numsics(d)) ), 4:15)
(4, 1)
(5, 1)
(6, 1)
(7, 2)
(8, 2)
(9, 2)
(10, 1)
(11, 3)
(12, 2)
(13, 2)
(14, 2)
(15, 4)
Zauner.radix
— Functionradix(n,r)
The length(r)
least significant digits of the integer n
in mixed radix r = [r1; r2; ...; rk]
.
Examples
julia> radix(5,[2; 2; 2; 2; 2])
5-element Vector{Int64}:
0
0
1
0
1
julia> radix(86400,[7; 24; 60; 60])
4-element Vector{Int64}:
1
0
0
0
Zauner.wh
— Functionwh( p::Vector{<:Integer}, d::Integer [, T::Type = BigFloat])
wh( m::Integer, n::Integer, d::Integer [, T::Type = BigFloat])
wh( p::Vector{<:Integer}, v::Vector)
wh( m::Integer, n::Integer, v::Vector)
wh( n::Integer, v::Vector)
Weyl-Heisenberg displacement operators. We have wh(p,q,d) == wh([p,q],d)
acts on the standard basis as $|k\rangle \to v_d^{p q} ω_d^{q}|k+p\rangle$, where arithmetic inside the ket is modulo $d$ and where $ω_d = v_d^2$ and $v_d = -\mathrm{e}^{i π/d}$. These forms explicitly construct the matrix that acts this way where 0
is the first element of the basis.
The forms wh(p,v)
or wh(m,n,v)
give the action onto the vector v
without explicitly forming the matrix. This is much faster when working with high dimensions or high precision. The form wh(n,v)
with d = length(v)
simply converts the integer n
into the base-d
expansion $n = n_1 d + n_0$ and calls wh([n1,n0],v)
. Tuples can also be used in place of vectors in these function calls.
Examples
julia> wh(2,3,4)
4×4 Matrix{Complex{BigFloat}}:
0.0-0.0im -0.0+0.0im 0.0+1.0im 0.0-0.0im
0.0-0.0im -0.0+0.0im 0.0+0.0im 1.0-0.0im
0.0-1.0im -0.0+0.0im 0.0+0.0im 0.0-0.0im
0.0-0.0im -1.0+0.0im 0.0+0.0im 0.0-0.0im
julia> v = [1; 0; 0; 0];
julia> wh(1,2,v) ≈ [0.0; 1.0im; 0.0; 0.0]
true