def __init__(self, m, n): """ Initialize ``self``. EXAMPLES:: sage: C = ColoredPermutations(4, 3) sage: TestSuite(C).run() sage: C = ColoredPermutations(2, 3) sage: TestSuite(C).run() sage: C = ColoredPermutations(1, 3) sage: TestSuite(C).run() """ if m <= 0: raise ValueError("m must be a positive integer") self._m = ZZ(m) self._n = ZZ(n) self._C = IntegerModRing(self._m) self._P = Permutations(self._n) if self._m == 1 or self._m == 2: from sage.categories.finite_coxeter_groups import FiniteCoxeterGroups category = FiniteCoxeterGroups().Irreducible() else: from sage.categories.complex_reflection_groups import ComplexReflectionGroups category = ComplexReflectionGroups().Finite().Irreducible( ).WellGenerated() Parent.__init__(self, category=category)
def _denominator(): R = PolynomialRing(ZZ, "T") T = R.gen() denom = R(1) lc = self._f.list()[-1] if lc == 1: # MONIC for i in range(2, self._delta + 1): if self._delta % i == 0: phi = euler_phi(i) G = IntegerModRing(i) ki = G(self._q).multiplicative_order() denom = denom * (T**ki - 1)**(phi // ki) return denom else: # Non-monic x = PolynomialRing(self._Fq, "x").gen() f = x**self._delta - lc L = f.splitting_field("a") roots = [r for r, _ in f.change_ring(L).roots()] roots_dict = dict([(r, i) for i, r in enumerate(roots)]) rootsfrob = [ L.frobenius_endomorphism(self._Fq.degree())(r) for r in roots ] m = zero_matrix(len(roots)) for i, r in enumerate(roots): m[i, roots_dict[rootsfrob[i]]] = 1 return R(R(m.characteristic_polynomial()) // (T - 1))
def mass_at_two_by_counting_mod_power(self, k): """ Computes the local mass at `p=2` assuming that it's stable `(mod 2^k)`. Note: This is **way** too slow to be useful, even when k=1!!! TO DO: Remove this routine, or try to compile it! INPUT: k -- an integer >= 1 OUTPUT: a rational number EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) sage: Q.mass_at_two_by_counting_mod_power(1) 4 """ R = IntegerModRing(2**k) Q1 = self.base_change_to(R) n = self.dim() MS = MatrixSpace(R, n) ct = sum([1 for x in mrange([2**k] * (n**2)) if Q1(MS(x)) == Q1]) ## Count the solutions mod 2^k two_mass = ZZ(1) / 2 * (ZZ(ct) / ZZ(2)**(k * n * (n - 1) / 2)) return two_mass
def __init__(self, m, n): """ Initialize ``self``. EXAMPLES:: sage: C = ColoredPermutations(4, 3) sage: TestSuite(C).run() sage: C = ColoredPermutations(2, 3) sage: TestSuite(C).run() sage: C = ColoredPermutations(1, 3) sage: TestSuite(C).run() """ if m <= 0: raise ValueError("m must be a positive integer") self._m = ZZ(m) self._n = ZZ(n) self._C = IntegerModRing(self._m) self._P = Permutations(self._n) if self._m == 1 or self._m == 2: from sage.categories.finite_coxeter_groups import FiniteCoxeterGroups category = FiniteCoxeterGroups().Irreducible() else: from sage.categories.complex_reflection_groups import ComplexReflectionGroups category = ComplexReflectionGroups().Finite().Irreducible().WellGenerated() Parent.__init__(self, category=category)
def __init__(self, m, n, category=None): """ Initialize ``self``. EXAMPLES:: sage: C = ColoredPermutations(4, 3) sage: TestSuite(C).run() sage: C = ColoredPermutations(2, 3) sage: TestSuite(C).run() sage: C = ColoredPermutations(1, 3) sage: TestSuite(C).run() """ if m <= 0: raise ValueError("m must be a positive integer") self._m = m self._n = n self._C = IntegerModRing(self._m) self._P = Permutations(self._n) if category is None: category = (Groups(), FiniteEnumeratedSets()) Parent.__init__(self, category=category)
def degree_on_basis(self, i): r""" Return the degree of the basis element indexed by ``i``, which is ``i`` mod `p`. EXAMPLES:: sage: L = lie_algebras.pwitt(Zmod(5), 5) sage: L.degree_on_basis(7) 2 sage: L.degree_on_basis(2).parent() Ring of integers modulo 5 """ return IntegerModRing(self._p)(i)
def __init__(self, n): """ Initialize ``self``. EXAMPLES:: sage: B = crystals.infinity.Multisegments(2) sage: TestSuite(B).run() """ self._cartan_type = CartanType(['A', n, 1]) self._Zn = IntegerModRing(n + 1) Parent.__init__(self, category=(HighestWeightCrystals(), InfiniteEnumeratedSets())) self.module_generators = (self.highest_weight_vector(), )
def example(self): """ EXAMPLES:: sage: M = Semigroups().SetsWithAction().example() sage: TestSuite(M).run(skip = ["_test_pickling"]) """ from sage.monoids.representations import SetWithAction from sage.rings.finite_rings.integer_mod_ring import IntegerModRing from sage.sets.finite_set_maps import FiniteSetMaps from sage.combinat.automatic_monoid import AutomaticMonoid from sage.sets.family import Family from sage.combinat.j_trivial_monoids import SubFiniteMonoidsOfFunctions Z = IntegerModRing(10) ambient = FiniteSetMaps(Z) S = AutomaticMonoid(Family({2: ambient(lambda x: 2*x), 3: ambient(lambda x: 3*x) }), category=SubFiniteMonoidsOfFunctions()) M = SetWithAction(S, Z, action = lambda f,m: f(m)) M.rename("Representation of the monoid generated by <2,3> acting on Z/10 Z by multiplication") return M
def __init__(self, e, multicharge=(0,)): r""" Initialise the parent class for residue sequences. EXAMPLES:: sage: from sage.combinat.tableau_residues import ResidueSequences sage: ResidueSequences(e=0, multicharge=(0,1,2)) 0-residue sequences with multicharge (0, 1, 2) sage: ResidueSequences(e=0, multicharge=(0,1,2)) == ResidueSequences(e=0, multicharge=(0,1,2)) True sage: ResidueSequences(e=0, multicharge=(0,1,2)) == ResidueSequences(e=3, multicharge=(0,1,2)) False The TestSuite fails ``_test_pickling` because ``__getitem__`` does not support slices, so we skip this:: sage: R = ResidueSequences(e=0, multicharge=(0,1,2)) sage: TestSuite(R).run(skip='_test_elements') """ self._quantum_characteristic = e self._base_ring = IntegerModRing(self._quantum_characteristic) self._multicharge = tuple(self._base_ring(i) for i in multicharge) super(ResidueSequences, self).__init__(category=Sets())
def gen_lattice(type='modular', n=4, m=8, q=11, seed=None, quotient=None, dual=False, ntl=False, lattice=False): r""" This function generates different types of integral lattice bases of row vectors relevant in cryptography. Randomness can be set either with ``seed``, or by using :func:`sage.misc.randstate.set_random_seed`. INPUT: - ``type`` -- one of the following strings - ``'modular'`` (default) -- A class of lattices for which asymptotic worst-case to average-case connections hold. For more refer to [Aj1996]_. - ``'random'`` -- Special case of modular (n=1). A dense class of lattice used for testing basis reduction algorithms proposed by Goldstein and Mayer [GM2002]_. - ``'ideal'`` -- Special case of modular. Allows for a more compact representation proposed by [LM2006]_. - ``'cyclotomic'`` -- Special case of ideal. Allows for efficient processing proposed by [LM2006]_. - ``n`` -- Determinant size, primal:`det(L) = q^n`, dual:`det(L) = q^{m-n}`. For ideal lattices this is also the degree of the quotient polynomial. - ``m`` -- Lattice dimension, `L \subseteq Z^m`. - ``q`` -- Coefficient size, `q-Z^m \subseteq L`. - ``seed`` -- Randomness seed. - ``quotient`` -- For the type ideal, this determines the quotient polynomial. Ignored for all other types. - ``dual`` -- Set this flag if you want a basis for `q-dual(L)`, for example for Regev's LWE bases [Reg2005]_. - ``ntl`` -- Set this flag if you want the lattice basis in NTL readable format. - ``lattice`` -- Set this flag if you want a :class:`FreeModule_submodule_with_basis_integer` object instead of an integer matrix representing the basis. OUTPUT: ``B`` a unique size-reduced triangular (primal: lower_left, dual: lower_right) basis of row vectors for the lattice in question. EXAMPLES: Modular basis:: sage: sage.crypto.gen_lattice(m=10, seed=42) [11 0 0 0 0 0 0 0 0 0] [ 0 11 0 0 0 0 0 0 0 0] [ 0 0 11 0 0 0 0 0 0 0] [ 0 0 0 11 0 0 0 0 0 0] [ 2 4 3 5 1 0 0 0 0 0] [ 1 -5 -4 2 0 1 0 0 0 0] [-4 3 -1 1 0 0 1 0 0 0] [-2 -3 -4 -1 0 0 0 1 0 0] [-5 -5 3 3 0 0 0 0 1 0] [-4 -3 2 -5 0 0 0 0 0 1] Random basis:: sage: sage.crypto.gen_lattice(type='random', n=1, m=10, q=11^4, seed=42) [14641 0 0 0 0 0 0 0 0 0] [ 431 1 0 0 0 0 0 0 0 0] [-4792 0 1 0 0 0 0 0 0 0] [ 1015 0 0 1 0 0 0 0 0 0] [-3086 0 0 0 1 0 0 0 0 0] [-5378 0 0 0 0 1 0 0 0 0] [ 4769 0 0 0 0 0 1 0 0 0] [-1159 0 0 0 0 0 0 1 0 0] [ 3082 0 0 0 0 0 0 0 1 0] [-4580 0 0 0 0 0 0 0 0 1] Ideal bases with quotient x^n-1, m=2*n are NTRU bases:: sage: sage.crypto.gen_lattice(type='ideal', seed=42, quotient=x^4-1) [11 0 0 0 0 0 0 0] [ 0 11 0 0 0 0 0 0] [ 0 0 11 0 0 0 0 0] [ 0 0 0 11 0 0 0 0] [-2 -3 -3 4 1 0 0 0] [ 4 -2 -3 -3 0 1 0 0] [-3 4 -2 -3 0 0 1 0] [-3 -3 4 -2 0 0 0 1] Ideal bases also work with polynomials:: sage: R.<t> = PolynomialRing(ZZ) sage: sage.crypto.gen_lattice(type='ideal', seed=1234, quotient=t^4-1) [11 0 0 0 0 0 0 0] [ 0 11 0 0 0 0 0 0] [ 0 0 11 0 0 0 0 0] [ 0 0 0 11 0 0 0 0] [ 1 4 -3 3 1 0 0 0] [ 3 1 4 -3 0 1 0 0] [-3 3 1 4 0 0 1 0] [ 4 -3 3 1 0 0 0 1] Cyclotomic bases with n=2^k are SWIFFT bases:: sage: sage.crypto.gen_lattice(type='cyclotomic', seed=42) [11 0 0 0 0 0 0 0] [ 0 11 0 0 0 0 0 0] [ 0 0 11 0 0 0 0 0] [ 0 0 0 11 0 0 0 0] [-2 -3 -3 4 1 0 0 0] [-4 -2 -3 -3 0 1 0 0] [ 3 -4 -2 -3 0 0 1 0] [ 3 3 -4 -2 0 0 0 1] Dual modular bases are related to Regev's famous public-key encryption [Reg2005]_:: sage: sage.crypto.gen_lattice(type='modular', m=10, seed=42, dual=True) [ 0 0 0 0 0 0 0 0 0 11] [ 0 0 0 0 0 0 0 0 11 0] [ 0 0 0 0 0 0 0 11 0 0] [ 0 0 0 0 0 0 11 0 0 0] [ 0 0 0 0 0 11 0 0 0 0] [ 0 0 0 0 11 0 0 0 0 0] [ 0 0 0 1 -5 -2 -1 1 -3 5] [ 0 0 1 0 -3 4 1 4 -3 -2] [ 0 1 0 0 -4 5 -3 3 5 3] [ 1 0 0 0 -2 -1 4 2 5 4] Relation of primal and dual bases:: sage: B_primal=sage.crypto.gen_lattice(m=10, q=11, seed=42) sage: B_dual=sage.crypto.gen_lattice(m=10, q=11, seed=42, dual=True) sage: B_dual_alt=transpose(11*B_primal.inverse()).change_ring(ZZ) sage: B_dual_alt.hermite_form() == B_dual.hermite_form() True TESTS: Test some bad quotient polynomials:: sage: sage.crypto.gen_lattice(type='ideal', seed=1234, quotient=cos(x)) Traceback (most recent call last): ... TypeError: unable to convert cos(x) to an integer sage: sage.crypto.gen_lattice(type='ideal', seed=1234, quotient=x^23-1) Traceback (most recent call last): ... ValueError: ideal basis requires n = quotient.degree() sage: R.<u,v> = ZZ[] sage: sage.crypto.gen_lattice(type='ideal', seed=1234, quotient=u+v) Traceback (most recent call last): ... TypeError: quotient should be a univariate polynomial We are testing output format choices:: sage: sage.crypto.gen_lattice(m=10, q=11, seed=42) [11 0 0 0 0 0 0 0 0 0] [ 0 11 0 0 0 0 0 0 0 0] [ 0 0 11 0 0 0 0 0 0 0] [ 0 0 0 11 0 0 0 0 0 0] [ 2 4 3 5 1 0 0 0 0 0] [ 1 -5 -4 2 0 1 0 0 0 0] [-4 3 -1 1 0 0 1 0 0 0] [-2 -3 -4 -1 0 0 0 1 0 0] [-5 -5 3 3 0 0 0 0 1 0] [-4 -3 2 -5 0 0 0 0 0 1] sage: sage.crypto.gen_lattice(m=10, q=11, seed=42, ntl=True) [ [11 0 0 0 0 0 0 0 0 0] [0 11 0 0 0 0 0 0 0 0] [0 0 11 0 0 0 0 0 0 0] [0 0 0 11 0 0 0 0 0 0] [2 4 3 5 1 0 0 0 0 0] [1 -5 -4 2 0 1 0 0 0 0] [-4 3 -1 1 0 0 1 0 0 0] [-2 -3 -4 -1 0 0 0 1 0 0] [-5 -5 3 3 0 0 0 0 1 0] [-4 -3 2 -5 0 0 0 0 0 1] ] sage: sage.crypto.gen_lattice(m=10, q=11, seed=42, lattice=True) Free module of degree 10 and rank 10 over Integer Ring User basis matrix: [ 0 0 1 1 0 -1 -1 -1 1 0] [-1 1 0 1 0 1 1 0 1 1] [-1 0 0 0 -1 1 1 -2 0 0] [-1 -1 0 1 1 0 0 1 1 -1] [ 1 0 -1 0 0 0 -2 -2 0 0] [ 2 -1 0 0 1 0 1 0 0 -1] [-1 1 -1 0 1 -1 1 0 -1 -2] [ 0 0 -1 3 0 0 0 -1 -1 -1] [ 0 -1 0 -1 2 0 -1 0 0 2] [ 0 1 1 0 1 1 -2 1 -1 -2] """ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing from sage.matrix.constructor import identity_matrix, block_matrix from sage.matrix.matrix_space import MatrixSpace from sage.rings.integer_ring import IntegerRing if seed is not None: from sage.misc.randstate import set_random_seed set_random_seed(seed) if type == 'random': if n != 1: raise ValueError('random bases require n = 1') ZZ = IntegerRing() ZZ_q = IntegerModRing(q) A = identity_matrix(ZZ_q, n) if type == 'random' or type == 'modular': R = MatrixSpace(ZZ_q, m-n, n) A = A.stack(R.random_element()) elif type == 'ideal': if quotient is None: raise ValueError('ideal bases require a quotient polynomial') try: quotient = quotient.change_ring(ZZ_q) except (AttributeError, TypeError): quotient = quotient.polynomial(base_ring=ZZ_q) P = quotient.parent() # P should be a univariate polynomial ring over ZZ_q if not is_PolynomialRing(P): raise TypeError("quotient should be a univariate polynomial") assert P.base_ring() is ZZ_q if quotient.degree() != n: raise ValueError('ideal basis requires n = quotient.degree()') R = P.quotient(quotient) for i in range(m//n): A = A.stack(R.random_element().matrix()) elif type == 'cyclotomic': from sage.arith.all import euler_phi from sage.misc.functional import cyclotomic_polynomial # we assume that n+1 <= min( euler_phi^{-1}(n) ) <= 2*n found = False for k in range(2*n,n,-1): if euler_phi(k) == n: found = True break if not found: raise ValueError("cyclotomic bases require that n " "is an image of Euler's totient function") R = ZZ_q['x'].quotient(cyclotomic_polynomial(k, 'x'), 'x') for i in range(m//n): A = A.stack(R.random_element().matrix()) # switch from representatives 0,...,(q-1) to (1-q)/2,....,(q-1)/2 def minrep(a): if abs(a-q) < abs(a): return a-q else: return a A_prime = A[n:m].lift().apply_map(minrep) if not dual: B = block_matrix([[ZZ(q), ZZ.zero()], [A_prime, ZZ.one()] ], subdivide=False) else: B = block_matrix([[ZZ.one(), -A_prime.transpose()], [ZZ.zero(), ZZ(q)]], subdivide=False) for i in range(m//2): B.swap_rows(i,m-i-1) if ntl and lattice: raise ValueError("Cannot specify ntl=True and lattice=True " "at the same time") if ntl: return B._ntl_() elif lattice: from sage.modules.free_module_integer import IntegerLattice return IntegerLattice(B) else: return B
def BCHCode(n,delta,F,b=0): r""" A 'Bose-Chaudhuri-Hockenghem code' (or BCH code for short) is the largest possible cyclic code of length n over field F=GF(q), whose generator polynomial has zeros (which contain the set) `Z = \{a^{b},a^{b+1}, ..., a^{b+delta-2}\}`, where a is a primitive `n^{th}` root of unity in the splitting field `GF(q^m)`, b is an integer `0\leq b\leq n-delta+1` and m is the multiplicative order of q modulo n. (The integers `b,...,b+delta-2` typically lie in the range `1,...,n-1`.) The integer `delta \geq 1` is called the "designed distance". The length n of the code and the size q of the base field must be relatively prime. The generator polynomial is equal to the least common multiple of the minimal polynomials of the elements of the set `Z` above. Special cases are b=1 (resulting codes are called 'narrow-sense' BCH codes), and `n=q^m-1` (known as 'primitive' BCH codes). It may happen that several values of delta give rise to the same BCH code. The largest one is called the Bose distance of the code. The true minimum distance, d, of the code is greater than or equal to the Bose distance, so `d\geq delta`. EXAMPLES:: sage: FF.<a> = GF(3^2,"a") sage: x = PolynomialRing(FF,"x").gen() sage: L = [b.minpoly() for b in [a,a^2,a^3]]; g = LCM(L) sage: f = x^(8)-1 sage: g.divides(f) True sage: C = codes.CyclicCode(8,g); C Linear code of length 8, dimension 4 over Finite Field of size 3 sage: C.minimum_distance() 4 sage: C = codes.BCHCode(8,3,GF(3),1); C Linear code of length 8, dimension 4 over Finite Field of size 3 sage: C.minimum_distance() 4 sage: C = codes.BCHCode(8,3,GF(3)); C Linear code of length 8, dimension 5 over Finite Field of size 3 sage: C.minimum_distance() 3 sage: C = codes.BCHCode(26, 5, GF(5), b=1); C Linear code of length 26, dimension 10 over Finite Field of size 5 """ from sage.misc.misc import srange q = F.order() R = IntegerModRing(n) m = R(q).multiplicative_order() FF = GF(q**m,"z") z = FF.gen() e = z.multiplicative_order()/n a = z**e # order n P = PolynomialRing(F,"x") x = P.gen() cosets = Set([]) for i in srange(b,b+delta-1): cosets = cosets.union(Set(cyclotomic_cosets(q, n, i))) L0 = [a**j for j in cosets] L1 = [P(ai.minpoly()) for ai in L0] g = P(LCM(L1)) #print cosets, "\n", g, "\n", (x**n-1).factor(), "\n", L1, "\n", g.divides(x**n-1) if not(g.divides(x**n-1)): raise ValueError, "BCH codes does not exist with the given input." return CyclicCodeFromGeneratingPolynomial(n,g)
def gen_lattice(type='modular', n=4, m=8, q=11, seed=None, \ quotient=None, dual=False, ntl=False): """ This function generates different types of integral lattice bases of row vectors relevant in cryptography. Randomness can be set either with ``seed``, or by using :func:`sage.misc.randstate.set_random_seed`. INPUT: * ``type`` - one of the following strings * ``'modular'`` (default). A class of lattices for which asymptotic worst-case to average-case connections hold. For more refer to [A96]_. * ``'random'`` - Special case of modular (n=1). A dense class of lattice used for testing basis reduction algorithms proposed by Goldstein and Mayer [GM02]_. * ``'ideal'`` - Special case of modular. Allows for a more compact representation proposed by [LM06]_. * ``'cyclotomic'`` - Special case of ideal. Allows for efficient processing proposed by [LM06]_. * ``n`` - Determinant size, primal:`det(L) = q^n`, dual:`det(L) = q^{m-n}`. For ideal lattices this is also the degree of the quotient polynomial. * ``m`` - Lattice dimension, `L \subseteq Z^m`. * ``q`` - Coefficent size, `q*Z^m \subseteq L`. * ``seed`` - Randomness seed. * ``quotient`` - For the type ideal, this determines the quotient polynomial. Ignored for all other types. * ``dual`` - Set this flag if you want a basis for `q*dual(L)`, for example for Regev's LWE bases [R05]_. * ``ntl`` - Set this flag if you want the lattice basis in NTL readable format. OUTPUT: ``B`` a unique size-reduced triangular (primal: lower_left, dual: lower_right) basis of row vectors for the lattice in question. EXAMPLES: * Modular basis :: sage: sage.crypto.gen_lattice(m=10, seed=42) [11 0 0 0 0 0 0 0 0 0] [ 0 11 0 0 0 0 0 0 0 0] [ 0 0 11 0 0 0 0 0 0 0] [ 0 0 0 11 0 0 0 0 0 0] [ 2 4 3 5 1 0 0 0 0 0] [ 1 -5 -4 2 0 1 0 0 0 0] [-4 3 -1 1 0 0 1 0 0 0] [-2 -3 -4 -1 0 0 0 1 0 0] [-5 -5 3 3 0 0 0 0 1 0] [-4 -3 2 -5 0 0 0 0 0 1] * Random basis :: sage: sage.crypto.gen_lattice(type='random', n=1, m=10, q=11^4, seed=42) [14641 0 0 0 0 0 0 0 0 0] [ 431 1 0 0 0 0 0 0 0 0] [-4792 0 1 0 0 0 0 0 0 0] [ 1015 0 0 1 0 0 0 0 0 0] [-3086 0 0 0 1 0 0 0 0 0] [-5378 0 0 0 0 1 0 0 0 0] [ 4769 0 0 0 0 0 1 0 0 0] [-1159 0 0 0 0 0 0 1 0 0] [ 3082 0 0 0 0 0 0 0 1 0] [-4580 0 0 0 0 0 0 0 0 1] * Ideal bases with quotient x^n-1, m=2*n are NTRU bases :: sage: sage.crypto.gen_lattice(type='ideal', seed=42, quotient=x^4-1) [11 0 0 0 0 0 0 0] [ 0 11 0 0 0 0 0 0] [ 0 0 11 0 0 0 0 0] [ 0 0 0 11 0 0 0 0] [ 4 -2 -3 -3 1 0 0 0] [-3 4 -2 -3 0 1 0 0] [-3 -3 4 -2 0 0 1 0] [-2 -3 -3 4 0 0 0 1] * Cyclotomic bases with n=2^k are SWIFFT bases :: sage: sage.crypto.gen_lattice(type='cyclotomic', seed=42) [11 0 0 0 0 0 0 0] [ 0 11 0 0 0 0 0 0] [ 0 0 11 0 0 0 0 0] [ 0 0 0 11 0 0 0 0] [ 4 -2 -3 -3 1 0 0 0] [ 3 4 -2 -3 0 1 0 0] [ 3 3 4 -2 0 0 1 0] [ 2 3 3 4 0 0 0 1] * Dual modular bases are related to Regev's famous public-key encryption [R05]_ :: sage: sage.crypto.gen_lattice(type='modular', m=10, seed=42, dual=True) [ 0 0 0 0 0 0 0 0 0 11] [ 0 0 0 0 0 0 0 0 11 0] [ 0 0 0 0 0 0 0 11 0 0] [ 0 0 0 0 0 0 11 0 0 0] [ 0 0 0 0 0 11 0 0 0 0] [ 0 0 0 0 11 0 0 0 0 0] [ 0 0 0 1 -5 -2 -1 1 -3 5] [ 0 0 1 0 -3 4 1 4 -3 -2] [ 0 1 0 0 -4 5 -3 3 5 3] [ 1 0 0 0 -2 -1 4 2 5 4] * Relation of primal and dual bases :: sage: B_primal=sage.crypto.gen_lattice(m=10, q=11, seed=42) sage: B_dual=sage.crypto.gen_lattice(m=10, q=11, seed=42, dual=True) sage: B_dual_alt=transpose(11*B_primal.inverse()).change_ring(ZZ) sage: B_dual_alt.hermite_form() == B_dual.hermite_form() True REFERENCES: .. [A96] Miklos Ajtai. Generating hard instances of lattice problems (extended abstract). STOC, pp. 99--108, ACM, 1996. .. [GM02] Daniel Goldstein and Andrew Mayer. On the equidistribution of Hecke points. Forum Mathematicum, 15:2, pp. 165--189, De Gruyter, 2003. .. [LM06] Vadim Lyubashevsky and Daniele Micciancio. Generalized compact knapsacks are collision resistant. ICALP, pp. 144--155, Springer, 2006. .. [R05] Oded Regev. On lattices, learning with errors, random linear codes, and cryptography. STOC, pp. 84--93, ACM, 2005. """ from sage.rings.finite_rings.integer_mod_ring \ import IntegerModRing from sage.matrix.constructor import matrix, \ identity_matrix, block_matrix from sage.matrix.matrix_space import MatrixSpace from sage.rings.integer_ring import IntegerRing if seed != None: from sage.misc.randstate import set_random_seed set_random_seed(seed) if type == 'random': if n != 1: raise ValueError('random bases require n = 1') ZZ = IntegerRing() ZZ_q = IntegerModRing(q) A = identity_matrix(ZZ_q, n) if type == 'random' or type == 'modular': R = MatrixSpace(ZZ_q, m-n, n) A = A.stack(R.random_element()) elif type == 'ideal': if quotient == None: raise \ ValueError('ideal bases require a quotient polynomial') x = quotient.default_variable() if n != quotient.degree(x): raise \ ValueError('ideal bases require n = quotient.degree()') R = ZZ_q[x].quotient(quotient, x) for i in range(m//n): A = A.stack(R.random_element().matrix()) elif type == 'cyclotomic': from sage.rings.arith import euler_phi from sage.misc.functional import cyclotomic_polynomial # we assume that n+1 <= min( euler_phi^{-1}(n) ) <= 2*n found = False for k in range(2*n,n,-1): if euler_phi(k) == n: found = True break if not found: raise \ ValueError('cyclotomic bases require that n is an image of' + \ 'Euler\'s totient function') R = ZZ_q['x'].quotient(cyclotomic_polynomial(k, 'x'), 'x') for i in range(m//n): A = A.stack(R.random_element().matrix()) # switch from representatives 0,...,(q-1) to (1-q)/2,....,(q-1)/2 def minrep(a): if abs(a-q) < abs(a): return a-q else: return a A_prime = A[n:m].lift().apply_map(minrep) if not dual: B = block_matrix([[ZZ(q), ZZ.zero()], [A_prime, ZZ.one()] ], \ subdivide=False) else: B = block_matrix([[ZZ.one(), -A_prime.transpose()], [ZZ.zero(), \ ZZ(q)]], subdivide=False) for i in range(m//2): B.swap_rows(i,m-i-1) if not ntl: return B else: return B._ntl_()
def basis(self, reduce=True): r""" Produce a basis for the free abelian group of eta-products of level N (under multiplication), attempting to find basis vectors of the smallest possible degree. INPUT: - ``reduce`` - a boolean (default True) indicating whether or not to apply LLL-reduction to the calculated basis EXAMPLES:: sage: EtaGroup(5).basis() [Eta product of level 5 : (eta_1)^6 (eta_5)^-6] sage: EtaGroup(12).basis() [Eta product of level 12 : (eta_1)^2 (eta_2)^1 (eta_3)^2 (eta_4)^-1 (eta_6)^-7 (eta_12)^3, Eta product of level 12 : (eta_1)^-4 (eta_2)^2 (eta_3)^4 (eta_6)^-2, Eta product of level 12 : (eta_1)^-1 (eta_2)^3 (eta_3)^3 (eta_4)^-2 (eta_6)^-9 (eta_12)^6, Eta product of level 12 : (eta_1)^1 (eta_2)^-1 (eta_3)^-3 (eta_4)^-2 (eta_6)^7 (eta_12)^-2, Eta product of level 12 : (eta_1)^-6 (eta_2)^9 (eta_3)^2 (eta_4)^-3 (eta_6)^-3 (eta_12)^1] sage: EtaGroup(12).basis(reduce=False) # much bigger coefficients [Eta product of level 12 : (eta_2)^24 (eta_12)^-24, Eta product of level 12 : (eta_1)^-336 (eta_2)^576 (eta_3)^696 (eta_4)^-216 (eta_6)^-576 (eta_12)^-144, Eta product of level 12 : (eta_1)^-8 (eta_2)^-2 (eta_6)^2 (eta_12)^8, Eta product of level 12 : (eta_1)^1 (eta_2)^9 (eta_3)^13 (eta_4)^-4 (eta_6)^-15 (eta_12)^-4, Eta product of level 12 : (eta_1)^15 (eta_2)^-24 (eta_3)^-29 (eta_4)^9 (eta_6)^24 (eta_12)^5] ALGORITHM: An eta product of level `N` is uniquely determined by the integers `r_d` for `d | N` with `d < N`, since `\sum_{d | N} r_d = 0`. The valid `r_d` are those that satisfy two congruences modulo 24, and one congruence modulo 2 for every prime divisor of N. We beef up the congruences modulo 2 to congruences modulo 24 by multiplying by 12. To calculate the kernel of the ensuing map `\ZZ^m \to (\ZZ/24\ZZ)^n` we lift it arbitrarily to an integer matrix and calculate its Smith normal form. This gives a basis for the lattice. This lattice typically contains "large" elements, so by default we pass it to the reduce_basis() function which performs LLL-reduction to give a more manageable basis. """ from six.moves import range N = self.level() divs = divisors(N)[:-1] s = len(divs) primedivs = prime_divisors(N) rows = [] for i in range(s): # generate a row of relation matrix row = [ Mod(divs[i], 24) - Mod(N, 24), Mod(N / divs[i], 24) - Mod(1, 24) ] for p in primedivs: row.append(Mod(12 * (N / divs[i]).valuation(p), 24)) rows.append(row) M = matrix(IntegerModRing(24), rows) Mlift = M.change_ring(ZZ) # now we compute elementary factors of Mlift S, U, V = Mlift.smith_form() good_vects = [] for i in range(U.nrows()): vect = U.row(i) nf = (i < S.ncols() and S[i, i]) or 0 good_vects.append((vect * 24 / gcd(nf, 24)).list()) for v in good_vects: v.append(-sum([r for r in v])) dicts = [] for v in good_vects: dicts.append({}) for i in range(s): dicts[-1][divs[i]] = v[i] dicts[-1][N] = v[-1] if reduce: return self.reduce_basis([self(d) for d in dicts]) else: return [self(d) for d in dicts]
""" from sage.rings.finite_rings.integer_mod_ring import IntegerModRing from sage.matrix.constructor import identity_matrix, block_matrix from sage.matrix.matrix_space import MatrixSpace from sage.rings.integer_ring import IntegerRing from sage.modules.free_module_integer import IntegerLattice if seed is not None: from sage.misc.randstate import set_random_seed set_random_seed(seed) m=n+1 ZZ = IntegerRing() ZZ_q = IntegerModRing(q) from sage.arith.all import euler_phi from sage.misc.functional import cyclotomic_polynomial # we assume that n+1 <= min( euler_phi^{-1}(n) ) <= 2*n found = False for k in range(2*n,n,-1): if euler_phi(k) == n: found = True break if not found: raise ValueError("cyclotomic bases require that n " "is an image of Euler's totient function")
def BCHCode(n,delta,F,b=0): r""" A 'Bose-Chaudhuri-Hockenghem code' (or BCH code for short) is the largest possible cyclic code of length n over field F=GF(q), whose generator polynomial has zeros (which contain the set) `Z = \{a^{b},a^{b+1}, ..., a^{b+delta-2}\}`, where a is a primitive `n^{th}` root of unity in the splitting field `GF(q^m)`, b is an integer `0\leq b\leq n-delta+1` and m is the multiplicative order of q modulo n. (The integers `b,...,b+delta-2` typically lie in the range `1,...,n-1`.) The integer `delta \geq 1` is called the "designed distance". The length n of the code and the size q of the base field must be relatively prime. The generator polynomial is equal to the least common multiple of the minimal polynomials of the elements of the set `Z` above. Special cases are b=1 (resulting codes are called 'narrow-sense' BCH codes), and `n=q^m-1` (known as 'primitive' BCH codes). It may happen that several values of delta give rise to the same BCH code. The largest one is called the Bose distance of the code. The true minimum distance, d, of the code is greater than or equal to the Bose distance, so `d\geq delta`. EXAMPLES:: sage: FF.<a> = GF(3^2,"a") sage: x = PolynomialRing(FF,"x").gen() sage: L = [b.minpoly() for b in [a,a^2,a^3]]; g = LCM(L) sage: f = x^(8)-1 sage: g.divides(f) True sage: C = codes.CyclicCode(8,g); C Linear code of length 8, dimension 4 over Finite Field of size 3 sage: C.minimum_distance() 4 sage: C = codes.BCHCode(8,3,GF(3),1); C Linear code of length 8, dimension 4 over Finite Field of size 3 sage: C.minimum_distance() 4 sage: C = codes.BCHCode(8,3,GF(3)); C Linear code of length 8, dimension 5 over Finite Field of size 3 sage: C.minimum_distance() 3 sage: C = codes.BCHCode(26, 5, GF(5), b=1); C Linear code of length 26, dimension 10 over Finite Field of size 5 """ q = F.order() R = IntegerModRing(n) m = R(q).multiplicative_order() FF = GF(q**m,"z") z = FF.gen() e = z.multiplicative_order()/n a = z**e # order n P = PolynomialRing(F,"x") x = P.gen() L1 = [] for coset in R.cyclotomic_cosets(q, range(b,b+delta-1)): L1.extend(P((a**j).minpoly()) for j in coset) g = P(LCM(L1)) #print cosets, "\n", g, "\n", (x**n-1).factor(), "\n", L1, "\n", g.divides(x**n-1) if not(g.divides(x**n-1)): raise ValueError("BCH codes does not exist with the given input.") return CyclicCodeFromGeneratingPolynomial(n,g)
def padic_H_value(self, p, f, t, prec=None): """ Return the `p`-adic trace of Frobenius, computed using the Gross-Koblitz formula. INPUT: - `p` -- a prime number - `f` -- an integer such that `q = p^f` - `t` -- a rational parameter - ``prec`` -- precision (optional, default 20) OUTPUT: an integer EXAMPLES: From Benasque report [Benasque2009]_, page 8:: sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp sage: H = Hyp(alpha_beta=([1/2]*4,[0]*4)) sage: [H.padic_H_value(3,i,-1) for i in range(1,3)] [0, -12] sage: [H.padic_H_value(5,i,-1) for i in range(1,3)] [-4, 276] sage: [H.padic_H_value(7,i,-1) for i in range(1,3)] [0, -476] sage: [H.padic_H_value(11,i,-1) for i in range(1,3)] [0, -4972] From [Roberts2015]_ (but note conventions regarding `t`):: sage: H = Hyp(gamma_list=[-6,-1,4,3]) sage: t = 189/125 sage: H.padic_H_value(13,1,1/t) 0 REFERENCES: - [MagmaHGM]_ """ alpha = self._alpha beta = self._beta if 0 in alpha: H = self.swap_alpha_beta() return H.padic_H_value(p, f, ~t, prec) t = QQ(t) gamma = self.gamma_array() q = p ** f # m = {r: beta.count(QQ((r, q - 1))) for r in range(q - 1)} m = defaultdict(lambda: 0) for r in range(q-1): u = QQ((r, q-1)) if u in beta: m[r] = beta.count(u) M = self.M_value() D = -min(self.zigzag(x, flip_beta=True) for x in alpha + beta) # also: D = (self.weight() + 1 - m[0]) // 2 if prec is None: prec = (self.weight()*f)//2 + ceil(log(self.degree(),p)) + 1 # For some reason, working in Qp instead of Zp is much faster; # it appears to avoid some costly conversions. p_ring = Qp(p, prec=prec) teich = p_ring.teichmuller(M / t) gauss_table = [padic_gauss_sum(r, p, f, prec, factored=True, algorithm='sage', parent=p_ring) for r in range(q-1)] sigma = sum( ((-p)**(sum(gauss_table[(v * r) % (q - 1)][0] * gv for v, gv in gamma.items()) // (p - 1)) * prod(gauss_table[(v * r) % (q - 1)][1] ** gv for v, gv in gamma.items()) * teich ** r) << (f*(D+m[0]-m[r])) for r in range(q-1)) resu = ZZ(-1) ** m[0] / (1 - q) * sigma return IntegerModRing(p**prec)(resu).lift_centered()
sage: verifier.interact_once(prover) True Repeat the testing protocol 100 times (if the prover is not genuine, it would a chance of less than 10^(-12) of getting away): sage: verifier.interact(prover, 100) True """ import hashlib import random from sage.rings.finite_rings.integer_mod_ring import IntegerModRing from sage.modules.free_module import VectorSpace from sage.quadratic_forms.quadratic_form import QuadraticForm from sage.structure.sage_object import dumps ZZ2 = IntegerModRing(2) def hash_sage_object(x): return hashlib.sha512(dumps(x)).digest() class Instance(object): def __init__(self, n, quad_forms, results): self.quad_forms = quad_forms self.domain_space = VectorSpace(ZZ2, n) self.range_space = VectorSpace(ZZ2, len(results)) self.results = self.range_space(results) def __call__(self, vector): result = []
def _is_a_splitting(S1, S2, n, return_automorphism=False): r""" Check wether ``(S1,S2)`` is a splitting of `\ZZ/n\ZZ`. A splitting of `R = \ZZ/n\ZZ` is a pair of subsets of `R` which is a partition of `R \\backslash \{0\}` and such that there exists an element `r` of `R` such that `r S_1 = S_2` and `r S_2 = S_1` (where `r S` is the point-wise multiplication of the elements of `S` by `r`). Splittings are useful for computing idempotents in the quotient ring `Q = GF(q)[x]/(x^n-1)`. INPUT: - ``S1, S2`` -- disjoint sublists partitioning ``[1, 2, ..., n-1]`` - ``n`` (integer) - ``return_automorphism`` (boolean) -- whether to return the automorphism exchanging `S_1` and `S_2`. OUTPUT: If ``return_automorphism is False`` (default) the function returns boolean values. Otherwise, it returns a pair ``(b, r)`` where ``b`` is a boolean indicating whether `S1`, `S2` is a splitting of `n`, and `r` is such that `r S_1 = S_2` and `r S_2 = S_1` (if `b` is ``False``, `r` is equal to ``None``). EXAMPLES:: sage: from sage.coding.code_constructions import _is_a_splitting sage: _is_a_splitting([1,2],[3,4],5) True sage: _is_a_splitting([1,2],[3,4],5,return_automorphism=True) (True, 4) sage: _is_a_splitting([1,3],[2,4,5,6],7) False sage: _is_a_splitting([1,3,4],[2,5,6],7) False sage: for P in SetPartitions(6,[3,3]): ....: res,aut= _is_a_splitting(P[0],P[1],7,return_automorphism=True) ....: if res: ....: print((aut, P)) (3, {{1, 2, 4}, {3, 5, 6}}) (6, {{1, 2, 3}, {4, 5, 6}}) (6, {{1, 3, 5}, {2, 4, 6}}) (6, {{1, 4, 5}, {2, 3, 6}}) We illustrate now how to find idempotents in quotient rings:: sage: n = 11; q = 3 sage: C = Zmod(n).cyclotomic_cosets(q); C [[0], [1, 3, 4, 5, 9], [2, 6, 7, 8, 10]] sage: S1 = C[1] sage: S2 = C[2] sage: _is_a_splitting(S1,S2,11) True sage: F = GF(q) sage: P.<x> = PolynomialRing(F,"x") sage: I = Ideal(P,[x^n-1]) sage: Q.<x> = QuotientRing(P,I) sage: i1 = -sum([x^i for i in S1]); i1 2*x^9 + 2*x^5 + 2*x^4 + 2*x^3 + 2*x sage: i2 = -sum([x^i for i in S2]); i2 2*x^10 + 2*x^8 + 2*x^7 + 2*x^6 + 2*x^2 sage: i1^2 == i1 True sage: i2^2 == i2 True sage: (1-i1)^2 == 1-i1 True sage: (1-i2)^2 == 1-i2 True We return to dealing with polynomials (rather than elements of quotient rings), so we can construct cyclic codes:: sage: P.<x> = PolynomialRing(F,"x") sage: i1 = -sum([x^i for i in S1]) sage: i2 = -sum([x^i for i in S2]) sage: i1_sqrd = (i1^2).quo_rem(x^n-1)[1] sage: i1_sqrd == i1 True sage: i2_sqrd = (i2^2).quo_rem(x^n-1)[1] sage: i2_sqrd == i2 True sage: C1 = codes.CyclicCode(length = n, generator_pol = gcd(i1, x^n - 1)) sage: C2 = codes.CyclicCode(length = n, generator_pol = gcd(1-i2, x^n - 1)) sage: C1.dual_code().systematic_generator_matrix() == C2.systematic_generator_matrix() True This is a special case of Theorem 6.4.3 in [HP2003]_. """ R = IntegerModRing(n) S1 = set(R(x) for x in S1) S2 = set(R(x) for x in S2) # we first check whether (S1,S2) is a partition of R - {0} if (len(S1) + len(S2) != n - 1 or len(S1) != len(S2) or R.zero() in S1 or R.zero() in S2 or not S1.isdisjoint(S2)): if return_automorphism: return False, None else: return False # now that we know that (S1,S2) is a partition, we look for an invertible # element b that maps S1 to S2 by multiplication for b in Integer(n).coprime_integers(n): if b >= 2 and all(b * x in S2 for x in S1): if return_automorphism: return True, b else: return True if return_automorphism: return False, None else: return False
################################################################################ from sage.misc.cachefunc import cached_method from sage.misc.misc import prod from congroup_generic import is_CongruenceSubgroup from congroup_gammaH import GammaH_class, is_GammaH, GammaH_constructor #from congroup_gamma0 import Gamma0_constructor -- circular! from arithgroup_element import ArithmeticSubgroupElement from sage.rings.all import ZZ, euler_phi as phi, moebius, divisors from sage.modular.dirichlet import DirichletGroup # Just for now until we make an SL_2 group type. from sage.rings.finite_rings.integer_mod_ring import IntegerModRing from sage.matrix.matrix_space import MatrixSpace Mat2Z = MatrixSpace(IntegerModRing(0), 2) def is_Gamma1(x): """ Return True if x is a congruence subgroup of type Gamma1. EXAMPLES:: sage: from sage.modular.arithgroup.all import is_Gamma1 sage: is_Gamma1(SL2Z) False sage: is_Gamma1(Gamma1(13)) True sage: is_Gamma1(Gamma0(6)) False
def _init_frob(self, desired_prec=None): """ Initialise everything for Frobenius polynomial computation. TESTS:: sage: p = 4999 sage: x = PolynomialRing(GF(p),"x").gen() sage: C = CyclicCover(3, x^4 + 4*x^3 + 9*x^2 + 3*x + 1) sage: C._init_frob() sage: C._init_frobQ True sage: C._plarge True sage: C._sqrtp True """ def _N0_RH(): return ceil( log(2 * binomial(2 * self._genus, self._genus), self._p) + self._genus * self._n / ZZ(2)) def _find_N0(): if self._nodenominators: return _N0_nodenominators(self._p, self._genus, self._n) else: return _N0_RH() + self._extraprec def _find_N_43(): """ Find the precision used for thm 4.3 in Goncalves for p >> 0, N = N0 + 2 """ p = self._p r = self._r d = self._d delta = self._delta N0 = self._N0 left_side = N0 + floor(log((d * p * (r - 1) + r) / delta) / log(p)) def right_side_log(n): return floor(log(p * (r * n - 1) - r) / log(p)) n = left_side while n <= left_side + right_side_log(n): n += 1 return n if not self._init_frobQ or self._N0 != desired_prec: if self._r < 2 or self._d < 2: raise NotImplementedError( "Only implemented for r, f.degree() >= 2") self._init_frobQ = True self._Fq = self._f.base_ring() self._p = self._Fq.characteristic() self._q = self._Fq.cardinality() self._n = self._Fq.degree() self._epsilon = 0 if self._delta == 1 else 1 # our basis choice doesn't always give an integral matrix if self._epsilon == 0: self._extraprec = floor( log(self._r, self._p) + log((2 * self._genus + (self._delta - 2)) / self._delta, self._p)) else: self._extraprec = floor(log(self._r * 2 - 1, self._p)) self._nodenominators = self._extraprec == 0 if desired_prec is None: self._N0 = _find_N0() else: self._N0 = desired_prec self._plarge = self._p > self._d * self._r * (self._N0 + self._epsilon) # working prec if self._plarge: self._N = self._N0 + 1 else: self._N = _find_N_43() # we will use the sqrt(p) version? self._sqrtp = self._plarge and self._p == self._q self._extraworkingprec = self._extraprec if not self._plarge: # we might have some denominators showing up during horizontal # and vertical reductions self._extraworkingprec += 2 * ceil( log(self._d * self._r * (self._N0 + self._epsilon), self._p)) # Rings if self._plarge and self._nodenominators: if self._n == 1: # IntegerModRing is significantly faster than Zq self._Zq = IntegerModRing(self._p**self._N) if self._sqrtp: self._Zq0 = IntegerModRing(self._p**(self._N - 1)) self._Qq = Qq(self._p, prec=self._N, type="capped-rel") self._w = 1 else: self._Zq = Zq( self._q, names="w", modulus=self._Fq.polynomial(), prec=self._N, type="capped-abs", ) self._w = self._Zq.gen() self._Qq = self._Zq.fraction_field() else: self._Zq = Qq( self._q, names="w", modulus=self._Fq.polynomial(), prec=self._N + self._extraworkingprec, ) self._w = self._Zq.gen() self._Qq = self._Zq self._Zp = Zp(self._p, prec=self._N + self._extraworkingprec) self._Zqx = PolynomialRing(self._Zq, "x") # Want to take a lift of f from Fq to Zq if self._n == 1: # When n = 1, can lift from Fp[x] to Z[x] and then to Zp[x] self._flift = self._Zqx([elt.lift() for elt in self._f.list()]) self._frobf = self._Zqx(self._flift.list()) else: # When n > 1, need to be more careful with the lift self._flift = self._Zqx([ elt.polynomial().change_ring(ZZ)(self._Zq.gen()) for elt in self._f.list() ]) self._frobf = self._Zqx( [elt.frobenius() for elt in self._flift.list()]) self._dflift = self._flift.derivative() # Set up local cache for Frob(f)^s # This variable will store the powers of frob(f) frobpow = [None] * (self._N0 + 2) frobpow[0] = self._Zqx(1) for k in range(self._N0 + 1): frobpow[k + 1] = self._frobf * frobpow[k] # We don't make it a polynomials as we need to keep track that the # ith coefficient represents (i*p)-th self._frobpow_list = [elt.list() for elt in frobpow] if self._sqrtp: # precision of self._Zq0 N = self._N - 1 vandermonde = matrix(self._Zq0, N, N) for i in range(N): vandermonde[i, 0] = 1 for j in range(1, N): vandermonde[i, j] = vandermonde[i, j - 1] * (i + 1) self._vandermonde = vandermonde.inverse() self._horizontal_fat_s = {} self._vertical_fat_s = {}
def discrete_log_rho(a, base, ord=None, operation='*', hash_function=hash): """ Pollard Rho algorithm for computing discrete logarithm in cyclic group of prime order. If the group order is very small it falls back to the baby step giant step algorithm. INPUT: - ``a`` -- a group element - ``base`` -- a group element - ``ord`` -- the order of ``base`` or ``None``, in this case we try to compute it - ``operation`` -- a string (default: ``'*'``) denoting whether we are in an additive group or a multiplicative one - ``hash_function`` -- having an efficient hash function is critical for this algorithm (see examples) OUTPUT: an integer `n` such that `a = base^n` (or `a = n*base`) ALGORITHM: Pollard rho for discrete logarithm, adapted from the article of Edlyn Teske, 'A space efficient algorithm for group structure computation'. EXAMPLES:: sage: F.<a> = GF(2^13) sage: g = F.gen() sage: discrete_log_rho(g^1234, g) 1234 sage: F.<a> = GF(37^5) sage: E = EllipticCurve(F, [1,1]) sage: G = (3*31*2^4)*E.lift_x(a) sage: discrete_log_rho(12345*G, G, ord=46591, operation='+') 12345 It also works with matrices:: sage: A = matrix(GF(50021),[[10577,23999,28893],[14601,41019,30188],[3081,736,27092]]) sage: discrete_log_rho(A^1234567, A) 1234567 Beware, the order must be prime:: sage: I = IntegerModRing(171980) sage: discrete_log_rho(I(2), I(3)) Traceback (most recent call last): ... ValueError: for Pollard rho algorithm the order of the group must be prime If it fails to find a suitable logarithm, it raises a ``ValueError``:: sage: I = IntegerModRing(171980) sage: discrete_log_rho(I(31002),I(15501)) Traceback (most recent call last): ... ValueError: Pollard rho algorithm failed to find a logarithm The main limitation on the hash function is that we don't want to have `hash(x*y) = hash(x) + hash(y)`:: sage: I = IntegerModRing(next_prime(2^23)) sage: def test(): ....: try: ....: discrete_log_rho(I(123456),I(1),operation='+') ....: except Exception: ....: print("FAILURE") sage: test() # random failure FAILURE If this happens, we can provide a better hash function:: sage: discrete_log_rho(I(123456),I(1),operation='+', hash_function=lambda x: hash(x*x)) 123456 AUTHOR: - Yann Laigle-Chapuy (2009-09-05) """ from sage.rings.integer import Integer from sage.rings.finite_rings.integer_mod_ring import IntegerModRing from operator import mul, add, pow # should be reasonable choices partition_size = 20 memory_size = 4 if operation in addition_names: mult = add power = mul if ord is None: ord = base.additive_order() elif operation in multiplication_names: mult = mul power = pow if ord is None: ord = base.multiplicative_order() else: raise ValueError ord = Integer(ord) if not ord.is_prime(): raise ValueError("for Pollard rho algorithm the order of the group must be prime") # check if we need to set immutable before hashing mut = hasattr(base,'set_immutable') isqrtord=ord.isqrt() if isqrtord < partition_size: #setup to costly, use bsgs return bsgs(base,a, bounds=(0,ord), operation=operation) reset_bound = 8*isqrtord # we take some margin I=IntegerModRing(ord) for s in xrange(10): # to avoid infinite loops # random walk function setup m=[I.random_element() for i in xrange(partition_size)] n=[I.random_element() for i in xrange(partition_size)] M=[mult(power(base,Integer(m[i])),power(a,Integer(n[i]))) for i in xrange(partition_size)] ax = I.random_element() x = power(base,Integer(ax)) if mut: x.set_immutable() bx = I(0) sigma=[(0,None)]*memory_size H={} # memory i0=0 nextsigma = 0 for i in xrange(reset_bound): #random walk, we need an efficient hash s=hash_function(x) % partition_size (x,ax,bx) = (mult(M[s],x), ax+m[s], bx+n[s]) if mut: x.set_immutable() # look for collisions if x in H: ay,by=H[x] if bx == by: break else: res = sage.rings.integer.Integer((ay-ax)/(bx-by)) if power(base,res) == a: return res else: break # should we remember this value? elif i >= nextsigma: if sigma[i0][1] is not None: H.pop(sigma[i0][1]) sigma[i0]=(i,x) i0 = (i0+1) % memory_size nextsigma = 3*sigma[i0][0] #3 seems a good choice H[x]=(ax,bx) raise ValueError("Pollard rho algorithm failed to find a logarithm")
class ColoredPermutations(Parent, UniqueRepresentation): r""" The group of `m`-colored permutations on `\{1, 2, \ldots, n\}`. Let `S_n` be the symmetric group on `n` letters and `C_m` be the cyclic group of order `m`. The `m`-colored permutation group on `n` letters is given by `P_n^m = C_m \wr S_n`. This is also the complex reflection group `G(m, 1, n)`. We define our multiplication by .. MATH:: ((s_1, \ldots s_n), \sigma) \cdot ((t_1, \ldots, t_n), \tau) = ((s_1 t_{\sigma(1)}, \ldots, s_n t_{\sigma(n)}), \tau \sigma). EXAMPLES:: sage: C = ColoredPermutations(4, 3); C 4-colored permutations of size 3 sage: s1,s2,t = C.gens() sage: (s1, s2, t) ([[0, 0, 0], [2, 1, 3]], [[0, 0, 0], [1, 3, 2]], [[0, 0, 1], [1, 2, 3]]) sage: s1*s2 [[0, 0, 0], [3, 1, 2]] sage: s1*s2*s1 == s2*s1*s2 True sage: t^4 == C.one() True sage: s2*t*s2 [[0, 1, 0], [1, 2, 3]] We can also create a colored permutation by passing either a list of tuples consisting of ``(color, element)``:: sage: x = C([(2,1), (3,3), (3,2)]); x [[2, 3, 3], [1, 3, 2]] or a list of colors and a permutation:: sage: C([[3,3,1], [1,3,2]]) [[3, 3, 1], [1, 3, 2]] There is also the natural lift from permutations:: sage: P = Permutations(3) sage: C(P.an_element()) [[0, 0, 0], [3, 1, 2]] REFERENCES: - :wikipedia:`Generalized_symmetric_group` - :wikipedia:`Complex_reflection_group` """ def __init__(self, m, n): """ Initialize ``self``. EXAMPLES:: sage: C = ColoredPermutations(4, 3) sage: TestSuite(C).run() sage: C = ColoredPermutations(2, 3) sage: TestSuite(C).run() sage: C = ColoredPermutations(1, 3) sage: TestSuite(C).run() """ if m <= 0: raise ValueError("m must be a positive integer") self._m = ZZ(m) self._n = ZZ(n) self._C = IntegerModRing(self._m) self._P = Permutations(self._n) if self._m == 1 or self._m == 2: from sage.categories.finite_coxeter_groups import FiniteCoxeterGroups category = FiniteCoxeterGroups().Irreducible() else: from sage.categories.complex_reflection_groups import ComplexReflectionGroups category = ComplexReflectionGroups().Finite().Irreducible( ).WellGenerated() Parent.__init__(self, category=category) def _repr_(self): """ Return a string representation of ``self``. EXAMPLES:: sage: ColoredPermutations(4, 3) 4-colored permutations of size 3 """ return "{}-colored permutations of size {}".format(self._m, self._n) @cached_method def index_set(self): """ Return the index set of ``self``. EXAMPLES:: sage: C = ColoredPermutations(3, 4) sage: C.index_set() (1, 2, 3, 4) sage: C = ColoredPermutations(1, 4) sage: C.index_set() (1, 2, 3) TESTS:: sage: S = SignedPermutations(4) sage: S.index_set() (1, 2, 3, 4) """ n = self._n if self._m != 1: n += 1 return tuple(range(1, n)) def coxeter_matrix(self): """ Return the Coxeter matrix of ``self``. EXAMPLES:: sage: C = ColoredPermutations(3, 4) sage: C.coxeter_matrix() [1 3 2 2] [3 1 3 2] [2 3 1 4] [2 2 4 1] sage: C = ColoredPermutations(1, 4) sage: C.coxeter_matrix() [1 3 2] [3 1 3] [2 3 1] TESTS:: sage: S = SignedPermutations(4) sage: S.coxeter_matrix() [1 3 2 2] [3 1 3 2] [2 3 1 4] [2 2 4 1] """ from sage.combinat.root_system.cartan_type import CartanType if self._m == 1: return CartanType(['A', self._n - 1]).coxeter_matrix() return CartanType(['B', self._n]).coxeter_matrix() @cached_method def one(self): """ Return the identity element of ``self``. EXAMPLES:: sage: C = ColoredPermutations(4, 3) sage: C.one() [[0, 0, 0], [1, 2, 3]] """ return self.element_class(self, [self._C.zero()] * self._n, self._P.identity()) def simple_reflection(self, i): r""" Return the ``i``-th simple reflection of ``self``. EXAMPLES:: sage: C = ColoredPermutations(4, 3) sage: C.gens() ([[0, 0, 0], [2, 1, 3]], [[0, 0, 0], [1, 3, 2]], [[0, 0, 1], [1, 2, 3]]) sage: C.simple_reflection(2) [[0, 0, 0], [1, 3, 2]] sage: C.simple_reflection(3) [[0, 0, 1], [1, 2, 3]] sage: S = SignedPermutations(4) sage: S.simple_reflection(1) [2, 1, 3, 4] sage: S.simple_reflection(4) [1, 2, 3, -4] """ if i not in self.index_set(): raise ValueError("i must be in the index set") colors = [self._C.zero()] * self._n if i < self._n: p = list(range(1, self._n + 1)) p[i - 1] = i + 1 p[i] = i return self.element_class(self, colors, self._P(p)) colors[-1] = self._C.one() return self.element_class(self, colors, self._P.identity()) @cached_method def _inverse_simple_reflections(self): """ Return the inverse of the simple reflections of ``self``. .. WARNING:: This returns a ``dict`` that should not be mutated since the result is cached. EXAMPLES:: sage: C = ColoredPermutations(4, 3) sage: C._inverse_simple_reflections() {1: [[0, 0, 0], [2, 1, 3]], 2: [[0, 0, 0], [1, 3, 2]], 3: [[0, 0, 3], [1, 2, 3]]} """ s = self.simple_reflections() return {i: ~s[i] for i in self.index_set()} @cached_method def gens(self): """ Return the generators of ``self``. EXAMPLES:: sage: C = ColoredPermutations(4, 3) sage: C.gens() ([[0, 0, 0], [2, 1, 3]], [[0, 0, 0], [1, 3, 2]], [[0, 0, 1], [1, 2, 3]]) sage: S = SignedPermutations(4) sage: S.gens() ([2, 1, 3, 4], [1, 3, 2, 4], [1, 2, 4, 3], [1, 2, 3, -4]) """ return tuple(self.simple_reflection(i) for i in self.index_set()) def matrix_group(self): """ Return the matrix group corresponding to ``self``. EXAMPLES:: sage: C = ColoredPermutations(4, 3) sage: C.matrix_group() Matrix group over Cyclotomic Field of order 4 and degree 2 with 3 generators ( [0 1 0] [1 0 0] [ 1 0 0] [1 0 0] [0 0 1] [ 0 1 0] [0 0 1], [0 1 0], [ 0 0 zeta4] ) """ from sage.groups.matrix_gps.finitely_generated import MatrixGroup return MatrixGroup([g.to_matrix() for g in self.gens()]) def as_permutation_group(self): r""" Return the permutation group corresponding to ``self``. EXAMPLES:: sage: C = ColoredPermutations(4, 3) sage: C.as_permutation_group() Complex reflection group G(4, 1, 3) as a permutation group """ from sage.groups.perm_gps.permgroup_named import ComplexReflectionGroup return ComplexReflectionGroup(self._m, 1, self._n) def _element_constructor_(self, x): """ Construct an element of ``self`` from ``x``. INPUT: Either a list of pairs (color, element) or a pair of lists (colors, elements). TESTS:: sage: C = ColoredPermutations(4, 3) sage: x = C([(2,1), (3,3), (3,2)]); x [[2, 3, 3], [1, 3, 2]] sage: x == C([[2,3,3], [1,3,2]]) True """ if isinstance(x, list): if isinstance(x[0], tuple): c = [] p = [] for k in x: if len(k) != 2: raise ValueError( "input must be pairs (color, element)") c.append(self._C(k[0])) p.append(k[1]) return self.element_class(self, c, self._P(p)) if len(x) != 2: raise ValueError( "input must be a pair of a list of colors and a permutation" ) return self.element_class(self, [self._C(v) for v in x[0]], self._P(x[1])) def _coerce_map_from_(self, C): """ Return a coerce map from ``C`` if it exists and ``None`` otherwise. EXAMPLES:: sage: C = ColoredPermutations(2, 3) sage: S = SignedPermutations(3) sage: C.has_coerce_map_from(S) True sage: C = ColoredPermutations(4, 3) sage: C.has_coerce_map_from(S) False sage: S = SignedPermutations(4) sage: C.has_coerce_map_from(S) False sage: P = Permutations(3) sage: C.has_coerce_map_from(P) True sage: P = Permutations(4) sage: C.has_coerce_map_from(P) False """ if isinstance(C, Permutations) and C.n == self._n: return lambda P, x: P.element_class(P, [P._C.zero()] * P._n, x) if self._m == 2 and isinstance(C, SignedPermutations) and C._n == self._n: return lambda P, x: P.element_class( P, [P._C.zero() if v == 1 else P._C.one() for v in x._colors], x._perm) return super(ColoredPermutations, self)._coerce_map_from_(C) def __iter__(self): """ Iterate over ``self``. EXAMPLES:: sage: C = ColoredPermutations(2, 2) sage: [x for x in C] [[[0, 0], [1, 2]], [[0, 1], [1, 2]], [[1, 0], [1, 2]], [[1, 1], [1, 2]], [[0, 0], [2, 1]], [[0, 1], [2, 1]], [[1, 0], [2, 1]], [[1, 1], [2, 1]]] """ for p in self._P: for c in itertools.product(self._C, repeat=self._n): yield self.element_class(self, c, p) def cardinality(self): """ Return the cardinality of ``self``. EXAMPLES:: sage: C = ColoredPermutations(4, 3) sage: C.cardinality() 384 sage: C.cardinality() == 4**3 * factorial(3) True """ return self._m**self._n * self._P.cardinality() order = cardinality def rank(self): """ Return the rank of ``self``. The rank of a complex reflection group is equal to the dimension of the complex vector space the group acts on. EXAMPLES:: sage: C = ColoredPermutations(4, 12) sage: C.rank() 12 sage: C = ColoredPermutations(7, 4) sage: C.rank() 4 sage: C = ColoredPermutations(1, 4) sage: C.rank() 3 """ if self._m == 1: return self._n - 1 return self._n def degrees(self): r""" Return the degrees of ``self``. The degrees of a complex reflection group are the degrees of the fundamental invariants of the ring of polynomial invariants. If `m = 1`, then we are in the special case of the symmetric group and the degrees are `(2, 3, \ldots, n, n+1)`. Otherwise the degrees are `(m, 2m, \ldots, nm)`. EXAMPLES:: sage: C = ColoredPermutations(4, 3) sage: C.degrees() (4, 8, 12) sage: S = ColoredPermutations(1, 3) sage: S.degrees() (2, 3) We now check that the product of the degrees is equal to the cardinality of ``self``:: sage: prod(C.degrees()) == C.cardinality() True sage: prod(S.degrees()) == S.cardinality() True """ # For the usual symmetric group (self._m=1) we need to start at 2 start = 2 if self._m == 1 else 1 return tuple(self._m * i for i in range(start, self._n + 1)) def codegrees(self): r""" Return the codegrees of ``self``. Let `G` be a complex reflection group. The codegrees `d_1^* \leq d_2^* \leq \cdots \leq d_{\ell}^*` of `G` can be defined by: .. MATH:: \prod_{i=1}^{\ell} (q - d_i^* - 1) = \sum_{g \in G} \det(g) q^{\dim(V^g)}, where `V` is the natural complex vector space that `G` acts on and `\ell` is the :meth:`rank`. If `m = 1`, then we are in the special case of the symmetric group and the codegrees are `(n-2, n-3, \ldots 1, 0)`. Otherwise the degrees are `((n-1)m, (n-2)m, \ldots, m, 0)`. EXAMPLES:: sage: C = ColoredPermutations(4, 3) sage: C.codegrees() (8, 4, 0) sage: S = ColoredPermutations(1, 3) sage: S.codegrees() (1, 0) TESTS: We check the polynomial identity:: sage: R.<q> = ZZ[] sage: C = ColoredPermutations(3, 2) sage: f = prod(q - ds - 1 for ds in C.codegrees()) sage: d = lambda x: sum(1 for e in x.to_matrix().eigenvalues() if e == 1) sage: g = sum(det(x.to_matrix()) * q**d(x) for x in C) sage: f == g True """ # Special case for the usual symmetric group last = self._n - 1 if self._m == 1 else self._n return tuple(self._m * i for i in reversed(range(last))) def number_of_reflection_hyperplanes(self): """ Return the number of reflection hyperplanes of ``self``. The number of reflection hyperplanes of a complex reflection group is equal to the sum of the codegrees plus the rank. EXAMPLES:: sage: C = ColoredPermutations(1, 2) sage: C.number_of_reflection_hyperplanes() 1 sage: C = ColoredPermutations(1, 3) sage: C.number_of_reflection_hyperplanes() 3 sage: C = ColoredPermutations(4, 12) sage: C.number_of_reflection_hyperplanes() 276 """ return sum(self.codegrees()) + self.rank() def fixed_point_polynomial(self, q=None): r""" The fixed point polynomial of ``self``. The fixed point polynomial `f_G` of a complex reflection group `G` is counting the dimensions of fixed points subspaces: .. MATH:: f_G(q) = \sum_{w \in W} q^{\dim V^w}. Furthermore, let `d_1, d_2, \ldots, d_{\ell}` be the degrees of `G`, where `\ell` is the :meth:`rank`. Then the fixed point polynomial is given by .. MATH:: f_G(q) = \prod_{i=1}^{\ell} (q + d_i - 1). INPUT: - ``q`` -- (default: the generator of ``ZZ['q']``) the parameter `q` EXAMPLES:: sage: C = ColoredPermutations(4, 3) sage: C.fixed_point_polynomial() q^3 + 21*q^2 + 131*q + 231 sage: S = ColoredPermutations(1, 3) sage: S.fixed_point_polynomial() q^2 + 3*q + 2 TESTS: We check the against the degrees and codegrees:: sage: R.<q> = ZZ[] sage: C = ColoredPermutations(4, 3) sage: C.fixed_point_polynomial(q) == prod(q + d - 1 for d in C.degrees()) True """ if q is None: q = PolynomialRing(ZZ, 'q').gen(0) return prod(q + d - 1 for d in self.degrees()) def is_well_generated(self): r""" Return if ``self`` is a well-generated complex reflection group. A complex reflection group `G` is well-generated if it is generated by `\ell` reflections. Equivalently, `G` is well-generated if `d_i + d_i^* = d_{\ell}` for all `1 \leq i \leq \ell`. EXAMPLES:: sage: C = ColoredPermutations(4, 3) sage: C.is_well_generated() True sage: C = ColoredPermutations(2, 8) sage: C.is_well_generated() True sage: C = ColoredPermutations(1, 4) sage: C.is_well_generated() True """ deg = self.degrees() dstar = self.codegrees() return all(deg[-1] == d + dstar[i] for i, d in enumerate(deg)) Element = ColoredPermutation
def Watson_mass_at_2(self): """ Returns the local mass of the quadratic form when `p=2`, according to Watson's Theorem 1 of "The 2-adic density of a quadratic form" in Mathematika 23 (1976), pp 94--106. INPUT: none OUTPUT: a rational number EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) sage: Q.Watson_mass_at_2() ## WARNING: WE NEED TO CHECK THIS CAREFULLY! 384 """ ## Make a 0-dim'l quadratic form (for initialization purposes) Null_Form = copy.deepcopy(self) Null_Form.__init__(ZZ, 0) ## Step 0: Compute Jordan blocks and bounds of the scales to keep track of Jordan_Blocks = self.jordan_blocks_by_scale_and_unimodular(2) scale_list = [B[0] for B in Jordan_Blocks] s_min = min(scale_list) s_max = max(scale_list) ## Step 1: Compute dictionaries of the diagonal block and 2x2 block for each scale diag_dict = dict( (i, Null_Form) for i in range(s_min - 2, s_max + 4)) ## Initialize with the zero form dim2_dict = dict( (i, Null_Form) for i in range(s_min, s_max + 4)) ## Initialize with the zero form for (s, L) in Jordan_Blocks: i = 0 while (i < L.dim() - 1) and (L[i, i + 1] == 0): ## Find where the 2x2 blocks start i = i + 1 if i < (L.dim() - 1): diag_dict[s] = L.extract_variables(range(i)) ## Diagonal Form dim2_dict[s + 1] = L.extract_variables(range( i, L.dim())) ## Non-diagonal Form else: diag_dict[s] = L #print "diag_dict = ", diag_dict #print "dim2_dict = ", dim2_dict #print "Jordan_Blocks = ", Jordan_Blocks ## Step 2: Compute three dictionaries of invariants (for n_j, m_j, nu_j) n_dict = dict((j, 0) for j in range(s_min + 1, s_max + 2)) m_dict = dict((j, 0) for j in range(s_min, s_max + 4)) for (s, L) in Jordan_Blocks: n_dict[s + 1] = L.dim() if diag_dict[s].dim() == 0: m_dict[s + 1] = ZZ.one() / ZZ(2) * L.dim() else: m_dict[s + 1] = floor(ZZ(L.dim() - 1) / ZZ(2)) #print " ==>", ZZ(L.dim() - 1) / ZZ(2), floor(ZZ(L.dim() - 1) / ZZ(2)) nu_dict = dict((j, n_dict[j + 1] - 2 * m_dict[j + 1]) for j in range(s_min, s_max + 1)) nu_dict[s_max + 1] = 0 #print "n_dict = ", n_dict #print "m_dict = ", m_dict #print "nu_dict = ", nu_dict ## Step 3: Compute the e_j dictionary eps_dict = {} for j in range(s_min, s_max + 3): two_form = (diag_dict[j - 2] + diag_dict[j] + dim2_dict[j]).scale_by_factor(2) j_form = (two_form + diag_dict[j - 1]).base_change_to( IntegerModRing(4)) if j_form.dim() == 0: eps_dict[j] = 1 else: iter_vec = [4] * j_form.dim() alpha = sum([True for x in mrange(iter_vec) if j_form(x) == 0]) beta = sum([True for x in mrange(iter_vec) if j_form(x) == 2]) if alpha > beta: eps_dict[j] = 1 elif alpha == beta: eps_dict[j] = 0 else: eps_dict[j] = -1 #print "eps_dict = ", eps_dict ## Step 4: Compute the quantities nu, q, P, E for the local mass at 2 nu = sum([j * n_dict[j] * (ZZ(n_dict[j] + 1) / ZZ(2) + \ sum([n_dict[r] for r in range(j+1, s_max+2)])) for j in range(s_min+1, s_max+2)]) q = sum([ sgn(nu_dict[j - 1] * (n_dict[j] + sgn(nu_dict[j]))) for j in range(s_min + 1, s_max + 2) ]) P = prod([ prod([1 - QQ(4)**(-i) for i in range(1, m_dict[j] + 1)]) for j in range(s_min + 1, s_max + 2) ]) E = prod([ ZZ(1) / ZZ(2) * (1 + eps_dict[j] * QQ(2)**(-m_dict[j])) for j in range(s_min, s_max + 3) ]) #print "\nFinal Summary:" #print "nu =", nu #print "q = ", q #print "P = ", P #print "E = ", E ## Step 5: Compute the local mass for the prime 2. mass_at_2 = QQ(2)**(nu - q) * P / E return mass_at_2
def my_gen_lattice2(n=4, q=11, seed=None, quotient=None, dual=False, ntl=False, lattice=False, GuessStuff=True): """ This is a modification of the code for the gen_lattice function from Sage Randomness can be set either with ``seed``, or by using :func:`sage.misc.randstate.set_random_seed`. INPUT: - ``type`` -- one of the following strings - ``'cyclotomic'`` -- Special case of ideal. Allows for efficient processing proposed by [LM2006]_. - ``n`` -- Determinant size, primal:`det(L) = q^n`, dual:`det(L) = q^{m-n}`. For ideal lattices this is also the degree of the quotient polynomial. - ``m`` -- Lattice dimension, `L \subseteq Z^m`. - ``q`` -- Coefficient size, `q-Z^m \subseteq L`. - ``t`` -- BKZ Block Size - ``seed`` -- Randomness seed. - ``quotient`` -- For the type ideal, this determines the quotient polynomial. Ignored for all other types. - ``dual`` -- Set this flag if you want a basis for `q-dual(L)`, for example for Regev's LWE bases [Reg2005]_. - ``ntl`` -- Set this flag if you want the lattice basis in NTL readable format. - ``lattice`` -- Set this flag if you want a :class:`FreeModule_submodule_with_basis_integer` object instead of an integer matrix representing the basis. OUTPUT: ``B`` a unique size-reduced triangular (primal: lower_left, dual: lower_right) basis of row vectors for the lattice in question. EXAMPLES: Cyclotomic bases with n=2^k are SWIFFT bases:: sage: sage.crypto.gen_lattice(type='cyclotomic', seed=42) [11 0 0 0 0 0 0 0] [ 0 11 0 0 0 0 0 0] [ 0 0 11 0 0 0 0 0] [ 0 0 0 11 0 0 0 0] [ 4 -2 -3 -3 1 0 0 0] [ 3 4 -2 -3 0 1 0 0] [ 3 3 4 -2 0 0 1 0] [ 2 3 3 4 0 0 0 1] Dual modular bases are related to Regev's famous public-key encryption [Reg2005]_:: sage: sage.crypto.gen_lattice(type='modular', m=10, seed=42, dual=True) [ 0 0 0 0 0 0 0 0 0 11] [ 0 0 0 0 0 0 0 0 11 0] [ 0 0 0 0 0 0 0 11 0 0] [ 0 0 0 0 0 0 11 0 0 0] [ 0 0 0 0 0 11 0 0 0 0] [ 0 0 0 0 11 0 0 0 0 0] [ 0 0 0 1 -5 -2 -1 1 -3 5] [ 0 0 1 0 -3 4 1 4 -3 -2] [ 0 1 0 0 -4 5 -3 3 5 3] [ 1 0 0 0 -2 -1 4 2 5 4] """ from sage.rings.finite_rings.integer_mod_ring import IntegerModRing from sage.matrix.constructor import identity_matrix, block_matrix from sage.matrix.matrix_space import MatrixSpace from sage.rings.integer_ring import IntegerRing from sage.modules.free_module_integer import IntegerLattice if seed is not None: from sage.misc.randstate import set_random_seed set_random_seed(seed) m=n+1 ZZ = IntegerRing() ZZ_q = IntegerModRing(q) from sage.arith.all import euler_phi from sage.misc.functional import cyclotomic_polynomial # we assume that n+1 <= min( euler_phi^{-1}(n) ) <= 2*n found = False for k in range(2*n,n,-1): if euler_phi(k) == n: found = True break if not found: raise ValueError("cyclotomic bases require that n " "is an image of Euler's totient function") R = ZZ_q['x'].quotient(cyclotomic_polynomial(2*n, 'x'), 'x') g=x**(n/2)+1 T=ZZ_q['x'].quotient(x**(n/2)+1) a_pol=R.random_element() s_pol=sample_noise(R) e_pol=sample_noise(R) s_pol2=T((s_pol)) e_pol2=T((e_pol)) print("s={0},e={1}".format(T(s_pol),T(e_pol))) Z_mat=e_pol2.matrix().augment(s_pol2.matrix()) Z_mattop=Z_mat[0:1].augment(matrix(1,1,[ZZ.one()*-1])) b_pol=(a_pol*s_pol+e_pol) print("s_pol={0}\ne_pol={1}".format((s_pol2).list(),(e_pol2).list())) # Does a linear mapping change the shortest vector size for the rest?/ a_pol=a_pol#*x_pol b_pol=b_pol#*x_pol a_pol2 = T(a_pol.list())# % S(g.list()) b_pol2 = T((b_pol).list())# % S(g.list()) # print("a={0}\nb={1}".format(a_pol2,b_pol2)) A=identity_matrix(ZZ_q,n/2) A=A.stack(a_pol2.matrix()) b_prime=b_pol2.matrix()[0:1] b_prime=b_prime - 11*A[8:9] A=A.stack(b_pol2.matrix()[0:1]) # print("X=\n{0}".format(X)) # A = A.stack(identity_matrix(ZZ_q, n/2)) print("A=\n{0}\n".format(A)) # switch from representatives 0,...,(q-1) to (1-q)/2,....,(q-1)/2 def minrepnegative(a): if abs(a-q) < abs(a): return (a-q)*-1 else: return a*-1 def minrep(a): if abs(a-q) < abs(a): return (a-q) else: return a A_prime = A[(n/2):(n+1)].lift().apply_map(minrep) # b_neg= A[(n):(n+1)].lift().apply_map(minrepnegative) Z_fixed=Z_mattop.lift().apply_map(minrep) print("Z_fixed={0}\n||Z_fixed||={1}".format(Z_fixed,float(Z_fixed[0].norm()))) print('Z_fixed*A={0}\n\n'.format(Z_fixed*A)) print("z_fixed[0].norm()={0}".format(float(Z_fixed[0].norm()))) # B=block_matrix([[ZZ(q),ZZ.zero()],[A_neg,ZZ.one()]], subdivide=False) # B = block_matrix([[ZZ.one(), -A_prime.transpose()], # [ZZ.zero(), ZZ(q)]], subdivide=False) B = block_matrix([[ZZ(q), ZZ.zero()], [-A_prime, ZZ.one()]], subdivide=False) # for i in range(m//2): # B.swap_rows(i,m-i-1) # print("{0}\n".format(A_neg)) # B=block_matrix([[ZZ(q), ZZ.zero(),ZZ.zero()],[ZZ.one(),A_neg,ZZ.zero() ],[ZZ.zero(),b_neg,ZZ.one()]], # subdivide=False) #print("B=\n{0}".format(B)) print("B*A=\n{0}\n\n".format(B*A)) #print("A=\n{0}\n".format(A)) def remap(x): return minrep((x*251)%251) BL=B.BKZ(block_size=n/2.) y=(BL.solve_left(Z_fixed))#.apply_map(remap)) # print("y*B={0}".format(y*B)) print("y:=B.solve_left(Z_fixed)={0}".format(y)) # BL=B.BKZ(block_size=n/2.) print(BL[0]) print("shortest norm={0}".format(float(BL[0].norm()))) # L = IntegerLattice(B) # p # v=L.shortest_vector() # print("L.shortest_vector={0}, norm={1}".format(v,float(v.norm()))) if ntl and lattice: raise ValueError("Cannot specify ntl=True and lattice=True ") if ntl: return B._ntl_() elif lattice: from sage.modules.free_module_integer import IntegerLattice return IntegerLattice(B) else: return B
def discrete_log_rho(a, base, ord=None, operation='*', hash_function=hash): """ Pollard Rho algorithm for computing discrete logarithm in cyclic group of prime order. If the group order is very small it falls back to the baby step giant step algorithm. INPUT: - ``a`` -- a group element - ``base`` -- a group element - ``ord`` -- the order of ``base`` or ``None``, in this case we try to compute it - ``operation`` -- a string (default: ``'*'``) denoting whether we are in an additive group or a multiplicative one - ``hash_function`` -- having an efficient hash function is critical for this algorithm (see examples) OUTPUT: an integer `n` such that `a = base^n` (or `a = n*base`) ALGORITHM: Pollard rho for discrete logarithm, adapted from the article of Edlyn Teske, 'A space efficient algorithm for group structure computation'. EXAMPLES:: sage: F.<a> = GF(2^13) sage: g = F.gen() sage: discrete_log_rho(g^1234, g) 1234 sage: F.<a> = GF(37^5) sage: E = EllipticCurve(F, [1,1]) sage: G = (3*31*2^4)*E.lift_x(a) sage: discrete_log_rho(12345*G, G, ord=46591, operation='+') 12345 It also works with matrices:: sage: A = matrix(GF(50021),[[10577,23999,28893],[14601,41019,30188],[3081,736,27092]]) sage: discrete_log_rho(A^1234567, A) 1234567 Beware, the order must be prime:: sage: I = IntegerModRing(171980) sage: discrete_log_rho(I(2), I(3)) Traceback (most recent call last): ... ValueError: for Pollard rho algorithm the order of the group must be prime If it fails to find a suitable logarithm, it raises a ``ValueError``:: sage: I = IntegerModRing(171980) sage: discrete_log_rho(I(31002),I(15501)) Traceback (most recent call last): ... ValueError: Pollard rho algorithm failed to find a logarithm The main limitation on the hash function is that we don't want to have `hash(x*y) = hash(x) + hash(y)`:: sage: I = IntegerModRing(next_prime(2^23)) sage: def test(): ....: try: ....: discrete_log_rho(I(123456),I(1),operation='+') ....: except Exception: ....: print("FAILURE") sage: test() # random failure FAILURE If this happens, we can provide a better hash function:: sage: discrete_log_rho(I(123456),I(1),operation='+', hash_function=lambda x: hash(x*x)) 123456 AUTHOR: - Yann Laigle-Chapuy (2009-09-05) """ from six.moves import range from sage.rings.integer import Integer from sage.rings.finite_rings.integer_mod_ring import IntegerModRing from operator import mul, add, pow # should be reasonable choices partition_size = 20 memory_size = 4 if operation in addition_names: mult = add power = mul if ord is None: ord = base.additive_order() elif operation in multiplication_names: mult = mul power = pow if ord is None: ord = base.multiplicative_order() else: raise ValueError ord = Integer(ord) if not ord.is_prime(): raise ValueError( "for Pollard rho algorithm the order of the group must be prime") # check if we need to set immutable before hashing mut = hasattr(base, 'set_immutable') isqrtord = ord.isqrt() if isqrtord < partition_size: #setup to costly, use bsgs return bsgs(base, a, bounds=(0, ord), operation=operation) reset_bound = 8 * isqrtord # we take some margin I = IntegerModRing(ord) for s in range(10): # to avoid infinite loops # random walk function setup m = [I.random_element() for i in range(partition_size)] n = [I.random_element() for i in range(partition_size)] M = [ mult(power(base, Integer(m[i])), power(a, Integer(n[i]))) for i in range(partition_size) ] ax = I.random_element() x = power(base, Integer(ax)) if mut: x.set_immutable() bx = I(0) sigma = [(0, None)] * memory_size H = {} # memory i0 = 0 nextsigma = 0 for i in range(reset_bound): #random walk, we need an efficient hash s = hash_function(x) % partition_size (x, ax, bx) = (mult(M[s], x), ax + m[s], bx + n[s]) if mut: x.set_immutable() # look for collisions if x in H: ay, by = H[x] if bx == by: break else: res = sage.rings.integer.Integer((ay - ax) / (bx - by)) if power(base, res) == a: return res else: break # should we remember this value? elif i >= nextsigma: if sigma[i0][1] is not None: H.pop(sigma[i0][1]) sigma[i0] = (i, x) i0 = (i0 + 1) % memory_size nextsigma = 3 * sigma[i0][0] #3 seems a good choice H[x] = (ax, bx) raise ValueError("Pollard rho algorithm failed to find a logarithm")
def padic_H_value(self, p, f, t, prec=None, cache_p=False): """ Return the `p`-adic trace of Frobenius, computed using the Gross-Koblitz formula. If left unspecified, `prec` is set to the minimum `p`-adic precision needed to recover the Euler factor. If `cache_p` is True, then the function caches an intermediate result which depends only on `p` and `f`. This leads to a significant speedup when iterating over `t`. INPUT: - `p` -- a prime number - `f` -- an integer such that `q = p^f` - `t` -- a rational parameter - ``prec`` -- precision (optional) - ``cache_p`` - a boolean OUTPUT: an integer EXAMPLES: From Benasque report [Benasque2009]_, page 8:: sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp sage: H = Hyp(alpha_beta=([1/2]*4,[0]*4)) sage: [H.padic_H_value(3,i,-1) for i in range(1,3)] [0, -12] sage: [H.padic_H_value(5,i,-1) for i in range(1,3)] [-4, 276] sage: [H.padic_H_value(7,i,-1) for i in range(1,3)] [0, -476] sage: [H.padic_H_value(11,i,-1) for i in range(1,3)] [0, -4972] From [Roberts2015]_ (but note conventions regarding `t`):: sage: H = Hyp(gamma_list=[-6,-1,4,3]) sage: t = 189/125 sage: H.padic_H_value(13,1,1/t) 0 TESTS: 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.padic_H_value(5,1,i) for i in range(2,5)] [1, -4, -4] sage: [H2.padic_H_value(5,1,i) for i in range(2,5)] [-4, 1, -4] Check for potential overflow:: sage: H = Hyp(cyclotomic=[[10,6],[5,4]]) sage: H.padic_H_value(101, 2, 2) -1560629 REFERENCES: - [MagmaHGM]_ """ alpha = self._alpha beta = self._beta t = QQ(t) if 0 in alpha: return self._swap.padic_H_value(p, f, ~t, prec) q = p ** f if q > 2 ** 31: return ValueError("p^f cannot exceed 2^31") m = array.array('i', [0]) * int(q - 1) for b in beta: u = b * (q - 1) if u.is_integer(): m[u] += 1 M = self.M_value() D = -min(self.zigzag(x, flip_beta=True) for x in alpha + beta) # also: D = (self.weight() + 1 - m[0]) // 2 if prec is None: prec = ceil((self.weight() * f) / 2 + log(2*self.degree()+1, p)) use_longs = (p ** prec < 2 ** 31) gamma = self._gamma_array if cache_p: try: trcoeffs = self._trace_coeffs[p, f] except KeyError: gtab_prec, gtab = self.gauss_table(p, f, prec) trcoeffs = hgm_coeffs(p, f, prec, gamma, m, D, gtab, gtab_prec, use_longs) self._trace_coeffs[p, f] = trcoeffs else: gtab = gauss_table(p, f, prec, use_longs) trcoeffs = hgm_coeffs(p, f, prec, gamma, m, D, gtab, prec, use_longs) sigma = trcoeffs[q-2] p_ring = sigma.parent() teich = p_ring.teichmuller(M/t) for i in range(q-3, -1, -1): sigma = sigma * teich + trcoeffs[i] resu = ZZ(-1) ** m[0] * sigma / (1 - q) return IntegerModRing(p**prec)(resu).lift_centered()
class ColoredPermutations(Parent, UniqueRepresentation): r""" The group of `m`-colored permutations on `\{1, 2, \ldots, n\}`. Let `S_n` be the symmetric group on `n` letters and `C_m` be the cyclic group of order `m`. The `m`-colored permutation group on `n` letters is given by `P_n^m = C_m \wr S_n`. This is also the complex reflection group `G(m, 1, n)`. We define our multiplication by .. MATH:: ((s_1, \ldots s_n), \sigma) \cdot ((t_1, \ldots, t_n), \tau) = ((s_1 t_{\sigma(1)}, \ldots, s_n t_{\sigma(n)}), \tau \sigma). EXAMPLES:: sage: C = ColoredPermutations(4, 3); C 4-colored permutations of size 3 sage: s1,s2,t = C.gens() sage: (s1, s2, t) ([[0, 0, 0], [2, 1, 3]], [[0, 0, 0], [1, 3, 2]], [[0, 0, 1], [1, 2, 3]]) sage: s1*s2 [[0, 0, 0], [3, 1, 2]] sage: s1*s2*s1 == s2*s1*s2 True sage: t^4 == C.one() True sage: s2*t*s2 [[0, 1, 0], [1, 2, 3]] We can also create a colored permutation by passing either a list of tuples consisting of ``(color, element)``:: sage: x = C([(2,1), (3,3), (3,2)]); x [[2, 3, 3], [1, 3, 2]] or a list of colors and a permutation:: sage: C([[3,3,1], [1,3,2]]) [[3, 3, 1], [1, 3, 2]] There is also the natural lift from permutations:: sage: P = Permutations(3) sage: C(P.an_element()) [[0, 0, 0], [3, 1, 2]] REFERENCES: - :wikipedia:`Generalized_symmetric_group` - :wikipedia:`Complex_reflection_group` """ def __init__(self, m, n): """ Initialize ``self``. EXAMPLES:: sage: C = ColoredPermutations(4, 3) sage: TestSuite(C).run() sage: C = ColoredPermutations(2, 3) sage: TestSuite(C).run() sage: C = ColoredPermutations(1, 3) sage: TestSuite(C).run() """ if m <= 0: raise ValueError("m must be a positive integer") self._m = ZZ(m) self._n = ZZ(n) self._C = IntegerModRing(self._m) self._P = Permutations(self._n) if self._m == 1 or self._m == 2: from sage.categories.finite_coxeter_groups import FiniteCoxeterGroups category = FiniteCoxeterGroups().Irreducible() else: from sage.categories.complex_reflection_groups import ComplexReflectionGroups category = ComplexReflectionGroups().Finite().Irreducible().WellGenerated() Parent.__init__(self, category=category) def _repr_(self): """ Return a string representation of ``self``. EXAMPLES:: sage: ColoredPermutations(4, 3) 4-colored permutations of size 3 """ return "{}-colored permutations of size {}".format(self._m, self._n) @cached_method def index_set(self): """ Return the index set of ``self``. EXAMPLES:: sage: C = ColoredPermutations(3, 4) sage: C.index_set() (1, 2, 3, 4) sage: C = ColoredPermutations(1, 4) sage: C.index_set() (1, 2, 3) TESTS:: sage: S = SignedPermutations(4) sage: S.index_set() (1, 2, 3, 4) """ n = self._n if self._m != 1: n += 1 return tuple(range(1, n)) def coxeter_matrix(self): """ Return the Coxeter matrix of ``self``. EXAMPLES:: sage: C = ColoredPermutations(3, 4) sage: C.coxeter_matrix() [1 3 2 2] [3 1 3 2] [2 3 1 4] [2 2 4 1] sage: C = ColoredPermutations(1, 4) sage: C.coxeter_matrix() [1 3 2] [3 1 3] [2 3 1] TESTS:: sage: S = SignedPermutations(4) sage: S.coxeter_matrix() [1 3 2 2] [3 1 3 2] [2 3 1 4] [2 2 4 1] """ from sage.combinat.root_system.cartan_type import CartanType if self._m == 1: return CartanType(['A', self._n-1]).coxeter_matrix() return CartanType(['B', self._n]).coxeter_matrix() @cached_method def one(self): """ Return the identity element of ``self``. EXAMPLES:: sage: C = ColoredPermutations(4, 3) sage: C.one() [[0, 0, 0], [1, 2, 3]] """ return self.element_class(self, [self._C.zero()] * self._n, self._P.identity()) def simple_reflection(self, i): r""" Return the ``i``-th simple reflection of ``self``. EXAMPLES:: sage: C = ColoredPermutations(4, 3) sage: C.gens() ([[0, 0, 0], [2, 1, 3]], [[0, 0, 0], [1, 3, 2]], [[0, 0, 1], [1, 2, 3]]) sage: C.simple_reflection(2) [[0, 0, 0], [1, 3, 2]] sage: C.simple_reflection(3) [[0, 0, 1], [1, 2, 3]] sage: S = SignedPermutations(4) sage: S.simple_reflection(1) [2, 1, 3, 4] sage: S.simple_reflection(4) [1, 2, 3, -4] """ if i not in self.index_set(): raise ValueError("i must be in the index set") colors = [self._C.zero()] * self._n if i < self._n: p = list(range(1, self._n + 1)) p[i - 1] = i + 1 p[i] = i return self.element_class(self, colors, self._P(p)) colors[-1] = self._C.one() return self.element_class(self, colors, self._P.identity()) @cached_method def _inverse_simple_reflections(self): """ Return the inverse of the simple reflections of ``self``. .. WARNING:: This returns a ``dict`` that should not be mutated since the result is cached. EXAMPLES:: sage: C = ColoredPermutations(4, 3) sage: C._inverse_simple_reflections() {1: [[0, 0, 0], [2, 1, 3]], 2: [[0, 0, 0], [1, 3, 2]], 3: [[0, 0, 3], [1, 2, 3]]} """ s = self.simple_reflections() return {i: ~s[i] for i in self.index_set()} @cached_method def gens(self): """ Return the generators of ``self``. EXAMPLES:: sage: C = ColoredPermutations(4, 3) sage: C.gens() ([[0, 0, 0], [2, 1, 3]], [[0, 0, 0], [1, 3, 2]], [[0, 0, 1], [1, 2, 3]]) sage: S = SignedPermutations(4) sage: S.gens() ([2, 1, 3, 4], [1, 3, 2, 4], [1, 2, 4, 3], [1, 2, 3, -4]) """ return tuple(self.simple_reflection(i) for i in self.index_set()) def matrix_group(self): """ Return the matrix group corresponding to ``self``. EXAMPLES:: sage: C = ColoredPermutations(4, 3) sage: C.matrix_group() Matrix group over Cyclotomic Field of order 4 and degree 2 with 3 generators ( [0 1 0] [1 0 0] [ 1 0 0] [1 0 0] [0 0 1] [ 0 1 0] [0 0 1], [0 1 0], [ 0 0 zeta4] ) """ from sage.groups.matrix_gps.finitely_generated import MatrixGroup return MatrixGroup([g.to_matrix() for g in self.gens()]) def _element_constructor_(self, x): """ Construct an element of ``self`` from ``x``. INPUT: Either a list of pairs (color, element) or a pair of lists (colors, elements). TESTS:: sage: C = ColoredPermutations(4, 3) sage: x = C([(2,1), (3,3), (3,2)]); x [[2, 3, 3], [1, 3, 2]] sage: x == C([[2,3,3], [1,3,2]]) True """ if isinstance(x, list): if isinstance(x[0], tuple): c = [] p = [] for k in x: if len(k) != 2: raise ValueError("input must be pairs (color, element)") c.append(self._C(k[0])) p.append(k[1]) return self.element_class(self, c, self._P(p)) if len(x) != 2: raise ValueError("input must be a pair of a list of colors and a permutation") return self.element_class(self, [self._C(v) for v in x[0]], self._P(x[1])) def _coerce_map_from_(self, C): """ Return a coerce map from ``C`` if it exists and ``None`` otherwise. EXAMPLES:: sage: C = ColoredPermutations(2, 3) sage: S = SignedPermutations(3) sage: C.has_coerce_map_from(S) True sage: C = ColoredPermutations(4, 3) sage: C.has_coerce_map_from(S) False sage: S = SignedPermutations(4) sage: C.has_coerce_map_from(S) False sage: P = Permutations(3) sage: C.has_coerce_map_from(P) True sage: P = Permutations(4) sage: C.has_coerce_map_from(P) False """ if isinstance(C, Permutations) and C.n == self._n: return lambda P, x: P.element_class(P, [P._C.zero()]*P._n, x) if self._m == 2 and isinstance(C, SignedPermutations) and C._n == self._n: return lambda P, x: P.element_class(P, [P._C.zero() if v == 1 else P._C.one() for v in x._colors], x._perm) return super(ColoredPermutations, self)._coerce_map_from_(C) def __iter__(self): """ Iterate over ``self``. EXAMPLES:: sage: C = ColoredPermutations(2, 2) sage: [x for x in C] [[[0, 0], [1, 2]], [[0, 1], [1, 2]], [[1, 0], [1, 2]], [[1, 1], [1, 2]], [[0, 0], [2, 1]], [[0, 1], [2, 1]], [[1, 0], [2, 1]], [[1, 1], [2, 1]]] """ for p in self._P: for c in itertools.product(self._C, repeat=self._n): yield self.element_class(self, c, p) def cardinality(self): """ Return the cardinality of ``self``. EXAMPLES:: sage: C = ColoredPermutations(4, 3) sage: C.cardinality() 384 sage: C.cardinality() == 4**3 * factorial(3) True """ return self._m ** self._n * self._P.cardinality() order = cardinality def rank(self): """ Return the rank of ``self``. The rank of a complex reflection group is equal to the dimension of the complex vector space the group acts on. EXAMPLES:: sage: C = ColoredPermutations(4, 12) sage: C.rank() 12 sage: C = ColoredPermutations(7, 4) sage: C.rank() 4 sage: C = ColoredPermutations(1, 4) sage: C.rank() 3 """ if self._m == 1: return self._n - 1 return self._n def degrees(self): """ Return the degrees of ``self``. The degrees of a complex reflection group are the degrees of the fundamental invariants of the ring of polynomial invariants. If `m = 1`, then we are in the special case of the symmetric group and the degrees are `(2, 3, \ldots, n, n+1)`. Otherwise the degrees are `(m, 2m, \ldots, nm)`. EXAMPLES:: sage: C = ColoredPermutations(4, 3) sage: C.degrees() (4, 8, 12) sage: S = ColoredPermutations(1, 3) sage: S.degrees() (2, 3) We now check that the product of the degrees is equal to the cardinality of ``self``:: sage: prod(C.degrees()) == C.cardinality() True sage: prod(S.degrees()) == S.cardinality() True """ # For the usual symmetric group (self._m=1) we need to start at 2 start = 2 if self._m == 1 else 1 return tuple(self._m * i for i in range(start, self._n + 1)) def codegrees(self): r""" Return the codegrees of ``self``. Let `G` be a complex reflection group. The codegrees `d_1^* \leq d_2^* \leq \cdots \leq d_{\ell}^*` of `G` can be defined by: .. MATH:: \prod_{i=1}^{\ell} (q - d_i^* - 1) = \sum_{g \in G} \det(g) q^{\dim(V^g)}, where `V` is the natural complex vector space that `G` acts on and `\ell` is the :meth:`rank`. If `m = 1`, then we are in the special case of the symmetric group and the codegrees are `(n-2, n-3, \ldots 1, 0)`. Otherwise the degrees are `((n-1)m, (n-2)m, \ldots, m, 0)`. EXAMPLES:: sage: C = ColoredPermutations(4, 3) sage: C.codegrees() (8, 4, 0) sage: S = ColoredPermutations(1, 3) sage: S.codegrees() (1, 0) TESTS: We check the polynomial identity:: sage: R.<q> = ZZ[] sage: C = ColoredPermutations(3, 2) sage: f = prod(q - ds - 1 for ds in C.codegrees()) sage: d = lambda x: sum(1 for e in x.to_matrix().eigenvalues() if e == 1) sage: g = sum(det(x.to_matrix()) * q**d(x) for x in C) sage: f == g True """ # Special case for the usual symmetric group last = self._n-1 if self._m == 1 else self._n return tuple(self._m * i for i in reversed(range(last))) def number_of_reflection_hyperplanes(self): """ Return the number of reflection hyperplanes of ``self``. The number of reflection hyperplanes of a complex reflection group is equal to the sum of the codegrees plus the rank. EXAMPLES:: sage: C = ColoredPermutations(1, 2) sage: C.number_of_reflection_hyperplanes() 1 sage: C = ColoredPermutations(1, 3) sage: C.number_of_reflection_hyperplanes() 3 sage: C = ColoredPermutations(4, 12) sage: C.number_of_reflection_hyperplanes() 276 """ return sum(self.codegrees()) + self.rank() def fixed_point_polynomial(self, q=None): r""" The fixed point polynomial of ``self``. The fixed point polynomial `f_G` of a complex reflection group `G` is counting the dimensions of fixed points subspaces: .. MATH:: f_G(q) = \sum_{w \in W} q^{\dim V^w}. Furthermore, let `d_1, d_2, \ldots, d_{\ell}` be the degrees of `G`, where `\ell` is the :meth:`rank`. Then the fixed point polynomial is given by .. MATH:: f_G(q) = \prod_{i=1}^{\ell} (q + d_i - 1). INPUT: - ``q`` -- (default: the generator of ``ZZ['q']``) the parameter `q` EXAMPLES:: sage: C = ColoredPermutations(4, 3) sage: C.fixed_point_polynomial() q^3 + 21*q^2 + 131*q + 231 sage: S = ColoredPermutations(1, 3) sage: S.fixed_point_polynomial() q^2 + 3*q + 2 TESTS: We check the against the degrees and codegrees:: sage: R.<q> = ZZ[] sage: C = ColoredPermutations(4, 3) sage: C.fixed_point_polynomial(q) == prod(q + d - 1 for d in C.degrees()) True """ if q is None: q = PolynomialRing(ZZ, 'q').gen(0) return prod(q + d - 1 for d in self.degrees()) def is_well_generated(self): """ Return if ``self`` is a well-generated complex reflection group. A complex reflection group `G` is well-generated if it is generated by `\ell` reflections. Equivalently, `G` is well-generated if `d_i + d_i^* = d_{\ell}` for all `1 \leq i \leq \ell`. EXAMPLES:: sage: C = ColoredPermutations(4, 3) sage: C.is_well_generated() True sage: C = ColoredPermutations(2, 8) sage: C.is_well_generated() True sage: C = ColoredPermutations(1, 4) sage: C.is_well_generated() True """ deg = self.degrees() dstar = self.codegrees() return all(deg[-1] == d + dstar[i] for i, d in enumerate(deg)) Element = ColoredPermutation
def padic_H_value(self, p, f, t, prec=None): """ Return the `p`-adic trace of Frobenius, computed using the Gross-Koblitz formula. If left unspecified, `prec` is set to the minimum `p`-adic precision needed to recover the Euler factor. INPUT: - `p` -- a prime number - `f` -- an integer such that `q = p^f` - `t` -- a rational parameter - ``prec`` -- precision (optional) OUTPUT: an integer EXAMPLES: From Benasque report [Benasque2009]_, page 8:: sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp sage: H = Hyp(alpha_beta=([1/2]*4,[0]*4)) sage: [H.padic_H_value(3,i,-1) for i in range(1,3)] [0, -12] sage: [H.padic_H_value(5,i,-1) for i in range(1,3)] [-4, 276] sage: [H.padic_H_value(7,i,-1) for i in range(1,3)] [0, -476] sage: [H.padic_H_value(11,i,-1) for i in range(1,3)] [0, -4972] From [Roberts2015]_ (but note conventions regarding `t`):: sage: H = Hyp(gamma_list=[-6,-1,4,3]) sage: t = 189/125 sage: H.padic_H_value(13,1,1/t) 0 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.padic_H_value(5,1,i) for i in range(2,5)] [1, -4, -4] sage: [H2.padic_H_value(5,1,i) for i in range(2,5)] [-4, 1, -4] REFERENCES: - [MagmaHGM]_ """ alpha = self._alpha beta = self._beta t = QQ(t) if 0 in alpha: return self._swap.padic_H_value(p, f, ~t, prec) gamma = self.gamma_array() q = p**f # m = {r: beta.count(QQ((r, q - 1))) for r in range(q - 1)} m = array.array('i', [0] * (q - 1)) for b in beta: u = b * (q - 1) if u.is_integer(): m[u] += 1 M = self.M_value() D = -min(self.zigzag(x, flip_beta=True) for x in alpha + beta) # also: D = (self.weight() + 1 - m[0]) // 2 if prec is None: prec = (self.weight() * f) // 2 + ceil(log(self.degree(), p)) + 1 # For some reason, working in Qp instead of Zp is much faster; # it appears to avoid some costly conversions. p_ring = Qp(p, prec=prec) teich = p_ring.teichmuller(M / t) gauss_table = [None] * (q - 1) for r in range(q - 1): if gauss_table[r] is None: gauss_table[r] = padic_gauss_sum(r, p, f, prec, factored=True, algorithm='sage', parent=p_ring) r1 = (r * p) % (q - 1) while r1 != r: gauss_table[r1] = gauss_table[r] r1 = (r1 * p) % (q - 1) sigma = p_ring.zero() u1 = p_ring.one() for r in range(q - 1): i = int(0) u = u1 u1 *= teich for v, gv in gamma.items(): r1 = (v * r) % (q - 1) i += gauss_table[r1][0] * gv u *= gauss_table[r1][1]**gv sigma += (-p)**(i // (p - 1)) * u << (f * (D + m[0] - m[r])) resu = ZZ(-1)**m[0] / (1 - q) * sigma return IntegerModRing(p**prec)(resu).lift_centered()
def _is_a_splitting(S1, S2, n, return_automorphism=False): """ Check wether ``(S1,S2)`` is a splitting of `\ZZ/n\ZZ`. A splitting of `R = \ZZ/n\ZZ` is a pair of subsets of `R` which is a partition of `R \\backslash \{0\}` and such that there exists an element `r` of `R` such that `r S_1 = S_2` and `r S_2 = S_1` (where `r S` is the point-wise multiplication of the elements of `S` by `r`). Splittings are useful for computing idempotents in the quotient ring `Q = GF(q)[x]/(x^n-1)`. INPUT: - ``S1, S2`` -- disjoint sublists partitioning ``[1, 2, ..., n-1]`` - ``n`` (integer) - ``return_automorphism`` (boolean) -- whether to return the automorphism exchanging `S_1` and `S_2`. OUTPUT: If ``return_automorphism is False`` (default) the function returns boolean values. Otherwise, it returns a pair ``(b, r)`` where ``b`` is a boolean indicating whether `S1`, `S2` is a splitting of `n`, and `r` is such that `r S_1 = S_2` and `r S_2 = S_1` (if `b` is ``False``, `r` is equal to ``None``). EXAMPLES:: sage: from sage.coding.code_constructions import _is_a_splitting sage: _is_a_splitting([1,2],[3,4],5) True sage: _is_a_splitting([1,2],[3,4],5,return_automorphism=True) (True, 4) sage: _is_a_splitting([1,3],[2,4,5,6],7) False sage: _is_a_splitting([1,3,4],[2,5,6],7) False sage: for P in SetPartitions(6,[3,3]): ....: res,aut= _is_a_splitting(P[0],P[1],7,return_automorphism=True) ....: if res: ....: print((aut, P[0], P[1])) (6, {1, 2, 3}, {4, 5, 6}) (3, {1, 2, 4}, {3, 5, 6}) (6, {1, 3, 5}, {2, 4, 6}) (6, {1, 4, 5}, {2, 3, 6}) We illustrate now how to find idempotents in quotient rings:: sage: n = 11; q = 3 sage: C = Zmod(n).cyclotomic_cosets(q); C [[0], [1, 3, 4, 5, 9], [2, 6, 7, 8, 10]] sage: S1 = C[1] sage: S2 = C[2] sage: _is_a_splitting(S1,S2,11) True sage: F = GF(q) sage: P.<x> = PolynomialRing(F,"x") sage: I = Ideal(P,[x^n-1]) sage: Q.<x> = QuotientRing(P,I) sage: i1 = -sum([x^i for i in S1]); i1 2*x^9 + 2*x^5 + 2*x^4 + 2*x^3 + 2*x sage: i2 = -sum([x^i for i in S2]); i2 2*x^10 + 2*x^8 + 2*x^7 + 2*x^6 + 2*x^2 sage: i1^2 == i1 True sage: i2^2 == i2 True sage: (1-i1)^2 == 1-i1 True sage: (1-i2)^2 == 1-i2 True We return to dealing with polynomials (rather than elements of quotient rings), so we can construct cyclic codes:: sage: P.<x> = PolynomialRing(F,"x") sage: i1 = -sum([x^i for i in S1]) sage: i2 = -sum([x^i for i in S2]) sage: i1_sqrd = (i1^2).quo_rem(x^n-1)[1] sage: i1_sqrd == i1 True sage: i2_sqrd = (i2^2).quo_rem(x^n-1)[1] sage: i2_sqrd == i2 True sage: C1 = codes.CyclicCode(length = n, generator_pol = gcd(i1, x^n - 1)) sage: C2 = codes.CyclicCode(length = n, generator_pol = gcd(1-i2, x^n - 1)) sage: C1.dual_code().systematic_generator_matrix() == C2.systematic_generator_matrix() True This is a special case of Theorem 6.4.3 in [HP2003]_. """ R = IntegerModRing(n) S1 = set(R(x) for x in S1) S2 = set(R(x) for x in S2) # we first check whether (S1,S2) is a partition of R - {0} if (len(S1) + len(S2) != n-1 or len(S1) != len(S2) or R.zero() in S1 or R.zero() in S2 or not S1.isdisjoint(S2)): if return_automorphism: return False, None else: return False # now that we know that (S1,S2) is a partition, we look for an invertible # element b that maps S1 to S2 by multiplication for b in range(2,n): if GCD(b,n) == 1 and all(b*x in S2 for x in S1): if return_automorphism: return True, b else: return True if return_automorphism: return False, None else: return False
def padic_H_value(self, p, f, t, prec=20): """ Return the `p`-adic trace of Frobenius, computed using the Gross-Koblitz formula. INPUT: - `p` -- a prime number - `f` -- an integer such that `q = p^f` - `t` -- a rational parameter - ``prec`` -- precision (optional, default 20) OUTPUT: an integer EXAMPLES: From Benasque report [Benasque2009]_, page 8:: sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp sage: H = Hyp(alpha_beta=([1/2]*4,[0]*4)) sage: [H.padic_H_value(3,i,-1) for i in range(1,3)] [0, -12] sage: [H.padic_H_value(5,i,-1) for i in range(1,3)] [-4, 276] sage: [H.padic_H_value(7,i,-1) for i in range(1,3)] [0, -476] sage: [H.padic_H_value(11,i,-1) for i in range(1,3)] [0, -4972] From [Roberts2015]_ (but note conventions regarding `t`):: sage: H = Hyp(gamma_list=[-6,-1,4,3]) sage: t = 189/125 sage: H.padic_H_value(13,1,1/t) 0 REFERENCES: - [MagmaHGM]_ """ alpha = self._alpha beta = self._beta if 0 in alpha: H = self.swap_alpha_beta() return (H.padic_H_value(p, f, ~t, prec)) t = QQ(t) gamma = self.gamma_array() q = p**f m = {r: beta.count(QQ((r, q - 1))) for r in range(q - 1)} M = self.M_value() D = -min(self.zigzag(x, flip_beta=True) for x in alpha + beta) # also: D = (self.weight() + 1 - m[0]) // 2 gauss_table = [ padic_gauss_sum(r, p, f, prec, factored=True) for r in range(q - 1) ] p_ring = Zp(p, prec=prec) teich = p_ring.teichmuller(M / t) sigma = sum(q**(D + m[0] - m[r]) * (-p)**(sum(gauss_table[(v * r) % (q - 1)][0] * gv for v, gv in gamma.items()) // (p - 1)) * prod(gauss_table[(v * r) % (q - 1)][1]**gv for v, gv in gamma.items()) * teich**r for r in range(q - 1)) resu = ZZ(-1)**m[0] / (1 - q) * sigma return IntegerModRing(p**prec)(resu).lift_centered()