The following is a list of all exported functions in Zauner.

Types

Zauner.AdmissibleTupleType
AdmissibleTuple( 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 )
source

Galois groups

Zauner.centralizer_elementsFunction
centralizer_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
source
Zauner.galois_elementsFunction
galois_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.

source
Zauner.galois_group_structureFunction
galois_group_structure(F::AdmissibleTuple)

Compute the canonical form (decomposition into cyclic groups) for the Galois group using the Smith normal form.

source
Zauner.galois_normal_formFunction
galois_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])
source
Zauner.galois_orbitFunction
galois_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.

source
Zauner.galois_order_orbitFunction
galois_order_orbit(F::AdmissibleTuple)

Compute the orders of the elements of the Galois group and a maximal orbit, output as a tuple.

source
Zauner.stabilizer_elementsFunction
stabilizer_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]
source

Analysis

Zauner.double_sineFunction
double_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.

source
Zauner.eFunction
e(z)

Normalized exponential function, $e(z) = \exp(2 \pi i z)$.

source
Zauner.q_pochhammerFunction
q_pochhammer(a, q, n)

Finite q-Pochhammer symbol, $\prod_{k=0}^{n-1} \bigl(1-a q^k\bigr)$.

source
Zauner.q_pochhammer_expFunction
q_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}\,.\]

source

Binary Quadratic Forms

SL(2,ℤ)

Zauner.is_sl2zFunction
is_sl2z(M)

Returns true if the matrix M is a 2x2 integer matrix with determinant 1.

source
Zauner.psl2wordFunction
psl2word(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.

source
Zauner.rademacherFunction
rademacher(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).

source
Zauner.sl2zorderFunction
sl2zorder(L, d)

Find the order of $L \bmod d$ where $L$ is in $\mathrm{SL}(2,\mathbb{Z})$. Brute force algorithm.

source

Hirzebruch-Jung continued fractions

Zauner.minimal_hj_stabilizerFunction
minimal_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.

source
Zauner.reduced_hj_orbitFunction
reduced_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
source

Ghosts

Zauner.ghostFunction
ghost(F:AdmissibleTuple)

Compute a ghost as a d × d matrix from the admissible tuple F.

Only rank-1 ghosts are supported at this time.

source
Zauner.ghostbasisFunction
ghostbasis(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.

source
Zauner.ghostclassfieldFunction
ghostclassfield( 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.

source
Zauner.ghostelementsFunction
ghostelements(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.

source

Necromancy

Zauner.guess_int_null_vecFunction
guess_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
source
Zauner.matrix_completionFunction
matrix_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.

source
Zauner.necromancyFunction
necromancy( 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
source
Zauner.pow_to_elem_sym_polyFunction
pow_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.

source

Newton's method

Zauner.precision_bumpFunction
precision_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.

source
Zauner.precision_bump!Function
precision_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.

source
Zauner.re_im_projFunction
re_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
source

Validation

Zauner.ghost_frame_testFunction
ghost_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.

source
Zauner.ghost_overlap_testFunction
ghost_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.

source
Zauner.sic_frame_testFunction
sic_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.

source
Zauner.sic_overlap_testFunction
sic_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.

source

Real quadratic orders

Zauner.corediscFunction
coredisc(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.

source
Zauner.pellFunction
pell(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
source
Zauner.pellregFunction
pellreg(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).

Warning

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.

source
Zauner.quadclassunitFunction
quadclassunit(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.
source
Zauner.signswitchFunction
signswitch( 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.

source

Property testing

Zauner.is_admissibleFunction
is_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
source
Zauner.is_antiunitary_with_generatorFunction
is_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.

source

Utilities

Zauner.dqFunction
dq(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 )
source
Zauner.numsicsFunction
numsics(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)
source
Zauner.radixFunction
radix(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
source
Zauner.whFunction
wh( 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
source