def szekeres_difference_set_pair(m, check=True): r""" Construct Szekeres `(2m+1,m,1)`-cyclic difference family Let `4m+3` be a prime power. Theorem 3 in [Sz69]_ contains a construction of a pair of *complementary difference sets* `A`, `B` in the subgroup `G` of the quadratic residues in `F_{4m+3}^*`. Namely `|A|=|B|=m`, `a\in A` whenever `a-1\in G`, `b\in B` whenever `b+1 \in G`. See also Theorem 2.6 in [SWW72]_ (there the formula for `B` is correct, as opposed to (4.2) in [Sz69]_, where the sign before `1` is wrong. In modern terminology, for `m>1` the sets `A` and `B` form a :func:`difference family<sage.combinat.designs.difference_family>` with parameters `(2m+1,m,1)`. I.e. each non-identity `g \in G` can be expressed uniquely as `xy^{-1}` for `x,y \in A` or `x,y \in B`. Other, specific to this construction, properties of `A` and `B` are: for `a` in `A` one has `a^{-1}` not in `A`, whereas for `b` in `B` one has `b^{-1}` in `B`. INPUT: - ``m`` (integer) -- dimension of the matrix - ``check`` (default: ``True``) -- whether to check `A` and `B` for correctness EXAMPLES:: sage: from sage.combinat.matrices.hadamard_matrix import szekeres_difference_set_pair sage: G,A,B=szekeres_difference_set_pair(6) sage: G,A,B=szekeres_difference_set_pair(7) REFERENCE: .. [Sz69] \G. Szekeres, Tournaments and Hadamard matrices, Enseignement Math. (2) 15(1969), 269-278 """ from sage.rings.finite_rings.finite_field_constructor import GF F = GF(4 * m + 3) t = F.multiplicative_generator()**2 G = F.cyclotomic_cosets(t, cosets=[F.one()])[0] sG = set(G) A = [a for a in G if a - F.one() in sG] B = [b for b in G if b + F.one() in sG] if check: from itertools import product, chain assert (len(A) == len(B) == m) if m > 1: assert (sG == set( [xy[0] / xy[1] for xy in chain(product(A, A), product(B, B))])) assert (all(F.one() / b + F.one() in sG for b in B)) assert (not any(F.one() / a - F.one() in sG for a in A)) return G, A, B
def find_traces(k, r, l, rl = None): ''' Compute traces such that the charpoly of the Frobenius has a root of order n modulo l. INPUT: - ``k`` -- the base field. - ``r`` -- the degree of the extension. - ``l`` -- a prime number. EXAMPLES:: sage: from ellrains import find_traces sage: r = 281 sage: l = 3373 sage: k = GF(1747) sage: find_traces(k, r, l) [4, 14, 18, 43, 57, 3325, 3337, 3348, 3354, 3357, 3364] ''' L = GF(l) q = L(k.order()) bound = 4*k.characteristic() if rl is None: rl = ZZ((l-1)/r) # Primitive root of unity of order r zeta = L.multiplicative_generator()**rl # Candidate eigenvalue lmbd = L(1) # Traces T = [] for i in xrange(1, r): lmbd *= zeta # Ensure that the order is r if r.gcd(i) != 1: continue if not lmbd.multiplicative_order() == r: print l, r, i trc = lmbd + q/lmbd # Check Hasse bound if trc.lift_centered()**2 < bound: T.append(trc) return T
def H_value(self, p, f, t, ring=None): """ Return the trace of the Frobenius, computed in terms of Gauss sums using the hypergeometric trace formula. INPUT: - `p` -- a prime number - `f` -- an integer such that `q = p^f` - `t` -- a rational parameter - ``ring`` -- optional (default ``UniversalCyclotomicfield``) The ring could be also ``ComplexField(n)`` or ``QQbar``. OUTPUT: an integer .. WARNING:: This is apparently working correctly as can be tested using ComplexField(70) as value ring. Using instead UniversalCyclotomicfield, this is much slower than the `p`-adic version :meth:`padic_H_value`. EXAMPLES: With values in the UniversalCyclotomicField (slow):: sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp sage: H = Hyp(alpha_beta=([1/2]*4,[0]*4)) sage: [H.H_value(3,i,-1) for i in range(1,3)] [0, -12] sage: [H.H_value(5,i,-1) for i in range(1,3)] [-4, 276] sage: [H.H_value(7,i,-1) for i in range(1,3)] # not tested [0, -476] sage: [H.H_value(11,i,-1) for i in range(1,3)] # not tested [0, -4972] sage: [H.H_value(13,i,-1) for i in range(1,3)] # not tested [-84, -1420] With values in ComplexField:: sage: [H.H_value(5,i,-1, ComplexField(60)) for i in range(1,3)] [-4, 276] Check issue from :trac:`28404`:: sage: H1 = Hyp(cyclotomic=([1,1,1],[6,2])) sage: H2 = Hyp(cyclotomic=([6,2],[1,1,1])) sage: [H1.H_value(5,1,i) for i in range(2,5)] [1, -4, -4] sage: [H2.H_value(5,1,QQ(i)) for i in range(2,5)] [-4, 1, -4] REFERENCES: - [BeCoMe]_ (Theorem 1.3) - [Benasque2009]_ """ alpha = self._alpha beta = self._beta t = QQ(t) if 0 in alpha: return self._swap.H_value(p, f, ~t, ring) if ring is None: ring = UniversalCyclotomicField() gamma = self.gamma_array() q = p ** f m = {r: beta.count(QQ((r, q - 1))) for r in range(q - 1)} D = -min(self.zigzag(x, flip_beta=True) for x in alpha + beta) # also: D = (self.weight() + 1 - m[0]) // 2 M = self.M_value() Fq = GF(q) gen = Fq.multiplicative_generator() zeta_q = ring.zeta(q - 1) tM = Fq(M / t) for k in range(q - 1): if gen ** k == tM: teich = zeta_q ** k break gauss_table = [gauss_sum(zeta_q ** r, Fq) for r in range(q - 1)] sigma = sum(q**(D + m[0] - m[r]) * prod(gauss_table[(-v * r) % (q - 1)]**gv for v, gv in gamma.items()) * teich ** r for r in range(q - 1)) resu = ZZ(-1) ** m[0] / (1 - q) * sigma if not ring.is_exact(): resu = resu.real_part().round() return resu
K1MASK = 2**m1 - 1 K1HIGHBIT = 2**(m1-1) K0MASK = 2**m0 - 1 K0HIGHBIT = 2**(m0-1) NECKLACES = 1/m1*sum(euler_phi(d)*2**(ZZ(m1/d)) for d in m1.divisors()) # 9*2*2*2 > 64 if m2 > 8: USE_DWORD = 1 else: USE_DWORD = 0 GF2 = GF(2) x = polygen(GF2) K2 = GF(2**m2, name='g2', modulus=modulus) g2 = K2.gen() z2 = K2.multiplicative_generator() K1 = GF(2**m1, name='g1', modulus=modulus) g1 = K1.gen() z1 = K1.multiplicative_generator() Z1 = z1.polynomial().change_ring(ZZ)(2) K0 = GF(2**m0, name='g0', modulus=modulus) g0 = K0.gen() z0 = K0.multiplicative_generator() L = [K0, K1, K2] moduli = [k.modulus() for k in L] F = [f.change_ring(ZZ)(2) for f in moduli] weights = [f.hamming_weight()-2 for f in moduli] degrees = [(f-x**f.degree()-1).exponents() for f in moduli] FWEIGHTS = weights F0D = degrees[0] if F0D == [1]:
def H_value(self, p, f, t, ring=None): """ Return the trace of the Frobenius, computed in terms of Gauss sums using the hypergeometric trace formula. INPUT: - `p` -- a prime number - `f` -- an integer such that `q = p^f` - `t` -- a rational parameter - ``ring`` -- optional (default ``UniversalCyclotomicfield``) The ring could be also ``ComplexField(n)`` or ``QQbar``. OUTPUT: an integer .. WARNING:: This is apparently working correctly as can be tested using ComplexField(70) as value ring. Using instead UniversalCyclotomicfield, this is much slower than the `p`-adic version :meth:`padic_H_value`. EXAMPLES: With values in the UniversalCyclotomicField (slow):: sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp sage: H = Hyp(alpha_beta=([1/2]*4,[0]*4)) sage: [H.H_value(3,i,-1) for i in range(1,3)] [0, -12] sage: [H.H_value(5,i,-1) for i in range(1,3)] [-4, 276] sage: [H.H_value(7,i,-1) for i in range(1,3)] # not tested [0, -476] sage: [H.H_value(11,i,-1) for i in range(1,3)] # not tested [0, -4972] sage: [H.H_value(13,i,-1) for i in range(1,3)] # not tested [-84, -1420] With values in ComplexField:: sage: [H.H_value(5,i,-1, ComplexField(60)) for i in range(1,3)] [-4, 276] REFERENCES: - [BeCoMe]_ (Theorem 1.3) - [Benasque2009]_ """ alpha = self._alpha beta = self._beta if 0 in alpha: H = self.swap_alpha_beta() return(H.H_value(p, f, ~t, ring)) if ring is None: ring = UniversalCyclotomicField() t = QQ(t) gamma = self.gamma_array() q = p ** f m = {r: beta.count(QQ((r, q - 1))) for r in range(q - 1)} D = -min(self.zigzag(x, flip_beta=True) for x in alpha + beta) # also: D = (self.weight() + 1 - m[0]) // 2 M = self.M_value() Fq = GF(q) gen = Fq.multiplicative_generator() zeta_q = ring.zeta(q - 1) tM = Fq(M / t) for k in range(q - 1): if gen ** k == tM: teich = zeta_q ** k break gauss_table = [gauss_sum(zeta_q ** r, Fq) for r in range(q - 1)] sigma = sum(q**(D + m[0] - m[r]) * prod(gauss_table[(-v * r) % (q - 1)] ** gv for v, gv in gamma.items()) * teich ** r for r in range(q - 1)) resu = ZZ(-1) ** m[0] / (1 - q) * sigma if not ring.is_exact(): resu = resu.real_part().round() return resu