def __init__(self, base_field, extended=True): r""" TESTS: If ``base_field`` is not ``GF(2)`` or ``GF(3)``, an error is raised:: sage: C = codes.GolayCode(ZZ, true) Traceback (most recent call last): ... ValueError: finite_field must be either GF(2) or GF(3) """ if base_field not in [GF(2), GF(3)]: raise ValueError("finite_field must be either GF(2) or GF(3)") if extended not in [True, False]: raise ValueError("extension must be either True or False") if base_field is GF(2): length = 23 self._dimension = 12 else: length = 11 self._dimension = 6 if extended: length += 1 super(GolayCode, self).__init__(base_field, length, "GeneratorMatrix", "Syndrome")
def find_gen_with_data(k, r, o, G, use_lucas = True, verbose = False): p = k.characteristic() n = k.degree() q = k.order() ro = r*o o = ro // ro.gcd(n) m = G[0][0].parent().order() use_lucas = use_lucas and ((q+1) % m == 0) if (use_lucas and o > 2) or (o > 1): if verbose: print "Using auxiliary extension of degree {}".format(o) P = GF(p**o, 'z').polynomial() from embed import computeR Pext = computeR(k.polynomial(), P) kext = GF(p**(n*o), 'zext', modulus=Pext) #kext = k.extension(P) # Compute the unique (up to Galois action) elements, descended to # k, if needed. if o == 1: u = find_unique_orbit(k, G) elif use_lucas and o == 2: u = find_unique_orbit_lucas(k, G) else: u = find_unique_orbit(kext, G) R = k.polynomial_ring() from embed import inverse_embed u = k(inverse_embed(R(u), k.polynomial(), R(P), R(kext.polynomial()))) return u
def convert_to_vector(I, L): r""" Convert ``I`` to a bit vector of length ``L``. INPUT: - ``I`` -- integer or bit list-like - ``L`` -- integer; the desired bit length of the ouput OUTPUT: - the ``L``-bit vector representation of ``I`` EXAMPLES:: sage: from sage.crypto.block_cipher.present import convert_to_vector sage: convert_to_vector(0x1F, 8) (1, 1, 1, 1, 1, 0, 0, 0) sage: v = vector(GF(2), 4, [1,0,1,0]) sage: convert_to_vector(v, 4) (1, 0, 1, 0) """ try: state = vector(GF(2), L, ZZ(I).digits(2, padto=L)) return state except TypeError: # ignore the error and try list-like types pass state = vector(GF(2), L, ZZ(list(I), 2).digits(2, padto=L)) return state
def find_gen_with_data(k, r, o, G, use_lucas=True, verbose=False): p = k.characteristic() n = k.degree() q = k.order() ro = r * o o = ro // ro.gcd(n) m = G[0][0].parent().order() use_lucas = use_lucas and ((q + 1) % m == 0) if (use_lucas and o > 2) or (o > 1): if verbose: print "Using auxiliary extension of degree {}".format(o) P = GF(p**o, 'z').polynomial() from embed import computeR Pext = computeR(k.polynomial(), P) kext = GF(p**(n * o), 'zext', modulus=Pext) #kext = k.extension(P) # Compute the unique (up to Galois action) elements, descended to # k, if needed. if o == 1: u = find_unique_orbit(k, G) elif use_lucas and o == 2: u = find_unique_orbit_lucas(k, G) else: u = find_unique_orbit(kext, G) R = k.polynomial_ring() from embed import inverse_embed u = k(inverse_embed(R(u), k.polynomial(), R(P), R(kext.polynomial()))) return u
def walsh_matrix(m0): """ This is the generator matrix of a Walsh code. The matrix of codewords correspond to a Hadamard matrix. EXAMPLES:: sage: walsh_matrix(2) [0 0 1 1] [0 1 0 1] sage: walsh_matrix(3) [0 0 0 0 1 1 1 1] [0 0 1 1 0 0 1 1] [0 1 0 1 0 1 0 1] sage: C = LinearCode(walsh_matrix(4)); C [16, 4] linear code over GF(2) sage: C.spectrum() [1, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 0] This last code has minimum distance 8. REFERENCES: - :wikipedia:`Hadamard_matrix` """ m = int(m0) if m == 1: return matrix(GF(2), 1, 2, [ 0, 1]) if m > 1: row2 = [x.list() for x in walsh_matrix(m-1).augment(walsh_matrix(m-1)).rows()] return matrix(GF(2), m, 2**m, [[0]*2**(m-1) + [1]*2**(m-1)] + row2) raise ValueError("%s must be an integer > 0."%m0)
def _pc1(self, key): r""" Return Permuted Choice 1 of ``key``. EXAMPLES:: sage: from sage.crypto.block_cipher.des import DES_KS sage: ks = DES_KS() sage: K = vector(GF(2),[0,0,0,1,0,0,1,1,0,0,1,1,0,1,0,0,0,1,0,1,0, ....: 1,1,1,0,1,1,1,1,0,0,1,1,0,0,1,1,0,1,1,1,0, ....: 1,1,1,1,0,0,1,1,0,1,1,1,1,1,1,1,1,1,0,0,0,1]) sage: C, D = ks._pc1(K) sage: C (1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1) sage: D (0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1) """ PC1_C = [ 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36 ] PC1_D = [ 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4 ] C = vector(GF(2), 28, [key[i - 1] for i in PC1_C]) D = vector(GF(2), 28, [key[i - 1] for i in PC1_D]) return C, D
def encrypt(self, plaintext, key): r""" Return the ciphertext corresponding to ``plaintext``, using DES encryption with ``key``. INPUT: - ``plaintext`` -- integer or bit list-like; the plaintext that will be encrypted. - ``key`` -- integer or bit list-like; the key OUTPUT: - The ciphertext corresponding to ``plaintext``, obtained using ``key``. If ``plaintext`` is an integer the output will be too. If ``plaintext`` is list-like the output will be a bit vector. EXAMPLES: Encrypt a message:: sage: from sage.crypto.block_cipher.des import DES sage: des = DES() sage: K64 = 0x133457799BBCDFF1 sage: P = 0x0123456789ABCDEF sage: C = des.encrypt(P, K64); C.hex() '85e813540f0ab405' You can also use 56 bit keys i.e. you can leave out the parity bits:: sage: K56 = 0x12695BC9B7B7F8 sage: des = DES(keySize=56) sage: des.encrypt(P, K56) == C True """ if isinstance(plaintext, (list, tuple, Vector_mod2_dense)): inputType = 'vector' elif isinstance(plaintext, (Integer, int)): inputType = 'integer' state = convert_to_vector(plaintext, self._blocksize) key = convert_to_vector(key, self._keySize) if self._keySize == 56: # insert 'parity' bits key = list(key) for i in range(7, 64, 8): key.insert(i, 0) key = vector(GF(2), 64, key) roundKeys = self.keySchedule(key) state = self._ip(state) for k in roundKeys[:self._rounds]: state = self.round(state, k) if self._doFinalRound: state = vector(GF(2), 64, list(state[32:64]) + list(state[0:32])) state = self._inv_ip(state) return state if inputType == 'vector' else ZZ(list(state)[::-1], 2)
def reduction(E: EllipticCurve_number_field, p: NumberFieldFractionalIdeal): if not E.has_good_reduction(p): raise ValueError(f"The curve must have good reduction at the place.") Ep = E.local_data(p).minimal_model() K = E.base_ring() Fp = K.residue_field(p) Fp2 = GF(Fp.order(), "abar", modulus=Fp.modulus()) iso = Fp.hom([Fp2.gen(0)], Fp2) Ebar = EllipticCurve([iso(Fp(ai)) for ai in Ep.ainvs()]) return Ebar
def __init__(self, f, n, N, a, ext): self.f = f self.n = n self.N = N self.p = 2**n*N*f - 1 self.Fp = GF(self.p) self.Fpx = self.Fp['x']; x = self.Fpx.gen() self.Fp2 = self.Fp.extension(x**2+ext, 'u') self.a = self.Fp2(a) self.cof_P = (self.p+1)//self.N
def __call__(self, K): r""" Return all round keys in a list. INPUT: - ``K`` -- integer or bit list-like; the key OUTPUT: - A list containing ``rounds + 1`` round keys. Since addRoundkey takes place in every round and after the last round there must be ``rounds + 1`` round keys. If ``K`` is an integer the elements of the output list will be too. If ``K`` is list-like the element of the output list will be bit vectors. EXAMPLES:: sage: from sage.crypto.block_cipher.present import PRESENT_KS sage: ks = PRESENT_KS() sage: ks(0)[31] == 0x6dab31744f41d700 True .. NOTE:: If you want to use a PRESENT_KS object as an iterable you have to pass a ``master_key`` value on initialisation. Otherwise you can omit ``master_key`` and pass a key when you call the object. """ if isinstance(K, (list, tuple, Vector_mod2_dense)): inputType = 'vector' elif isinstance(K, (Integer, int)): inputType = 'integer' K = convert_to_vector(K, self._keysize) roundKeys = [] if self._keysize == 80: for i in range(1, self._rounds + 1): roundKeys.append(K[16:]) K[0:] = list(K[19:]) + list(K[:19]) K[76:] = self.sbox(K[76:][::-1])[::-1] rc = vector(GF(2), ZZ(i).digits(2, padto=5)) K[15:20] = K[15:20] + rc roundKeys.append(K[16:]) elif self._keysize == 128: for i in range(1, self._rounds + 1): roundKeys.append(K[64:]) K[0:] = list(K[67:]) + list(K[:67]) K[124:] = self.sbox(K[124:][::-1])[::-1] K[120:124] = self.sbox(K[120:124][::-1])[::-1] rc = vector(GF(2), ZZ(i).digits(2, padto=5)) K[62:67] = K[62:67] + rc roundKeys.append(K[64:]) return roundKeys if inputType == 'vector' else [ ZZ(list(k), 2) for k in roundKeys ]
def decrypt(self, ciphertext, key): r""" Return the plaintext corresponding to ``ciphertext``, using DES decryption with ``key``. INPUT: - ``ciphertext`` -- integer or bit list-like; the ciphertext that will be decrypted - ``key`` -- integer or bit list-like; the key OUTPUT: - The plaintext corresponding to ``ciphertext``, obtained using ``key``. If ``ciphertext`` is an integer the output will be too. If ``ciphertext`` is list-like the output will be a bit vector. EXAMPLES: Decrypt a message:: sage: from sage.crypto.block_cipher.des import DES sage: des = DES() sage: K64 = 0x7CA110454A1A6E57 sage: C = 0x690F5B0D9A26939B sage: P = des.decrypt(C, K64).hex(); P '1a1d6d039776742' You can also use 56 bit keys i.e. you can leave out the parity bits:: sage: K56 = 0x7D404224A35BAB sage: des = DES(keySize=56) sage: des.decrypt(C, K56).hex() == P True """ if isinstance(ciphertext, (list, tuple, Vector_mod2_dense)): inputType = 'vector' elif isinstance(ciphertext, (Integer, int)): inputType = 'integer' state = convert_to_vector(ciphertext, 64) key = convert_to_vector(key, self._keySize) if self._keySize == 56: # insert 'parity' bits key = list(key) for i in range(7, 64, 8): key.insert(i, 0) key = vector(GF(2), 64, key) roundKeys = self.keySchedule(key) state = self._ip(state) for k in roundKeys[:self._rounds][::-1]: state = self.round(state, k) state = vector(GF(2), 64, list(state[32:64]) + list(state[0:32])) state = self._inv_ip(state) return state if inputType == 'vector' else ZZ(list(state)[::-1], 2)
def p_saturation(A, p, proof=True): """ INPUT: - A -- a matrix over ZZ - p -- a prime - proof -- bool (default: True) OUTPUT: The p-saturation of the matrix A, i.e., a new matrix in Hermite form whose row span a ZZ-module that is p-saturated. EXAMPLES:: sage: from sage.matrix.matrix_integer_dense_saturation import p_saturation sage: A = matrix(ZZ, 2, 2, [3,2,3,4]); B = matrix(ZZ, 2,3,[1,2,3,4,5,6]) sage: A.det() 6 sage: C = A*B; C [11 16 21] [19 26 33] sage: C2 = p_saturation(C, 2); C2 [ 1 8 15] [ 0 9 18] sage: C2.index_in_saturation() 9 sage: C3 = p_saturation(C, 3); C3 [ 1 0 -1] [ 0 2 4] sage: C3.index_in_saturation() 2 """ tm = verbose("%s-saturating a %sx%s matrix" % (p, A.nrows(), A.ncols())) H = A.hermite_form(include_zero_rows=False, proof=proof) while True: if p == 2: A = H.change_ring(GF(p)) else: try: # Faster than change_ring A = H._reduce(p) except OverflowError: # fall back to generic GF(p) matrices A = H.change_ring(GF(p)) assert A.nrows() <= A.ncols() K = A.kernel() if K.dimension() == 0: verbose("done saturating", tm) return H B = K.basis_matrix().lift() C = ((B * H) / p).change_ring(ZZ) H = H.stack(C).hermite_form(include_zero_rows=False, proof=proof) verbose("done saturating", tm)
def test_homological_dimension(self): from sage.rings.finite_rings.finite_field_constructor import GF g = self._get_random_cylinder_diagram() C = g.to_ribbon_graph().chain_complex(GF(2)) Z1 = C.cycle_space(1) B1 = C.boundary_space(1) V = Z1.submodule(g.circumferences_of_cylinders(GF(2))) assert g.homological_dimension_of_cylinders( ) == V.rank() - V.intersection(B1).rank()
def __init__(self, prime, exponents, maxn=None): """ TESTS:: sage: from yacop.utils.admissible_matrices import AdmissibleMatrices sage: X = AdmissibleMatrices(3, (4,0,3)) ; X admissible matrices for prime 3, exponents [4, 0, 3] sage: for (cf,x,colsums,diagsums) in X: ....: print("-- cf=%d, colsums=%s, diagsums=%s"%(cf,colsums,diagsums)) ....: print(x.str(zero='.')) -- cf=1, colsums=[1, 2], diagsums=[1, 1, 0, 1] [1 1] [. .] [. 1] -- cf=1, colsums=[4, 1], diagsums=[4, 0, 0, 1] [4 .] [. .] [. 1] -- cf=1, colsums=[4, 1], diagsums=[1, 1, 3, 0] [1 1] [. .] [3 .] -- cf=1, colsums=[7, 0], diagsums=[4, 0, 3, 0] [4 .] [. .] [3 .] """ self.p = prime self.one = GF(self.p).one() self.exp = list(exponents) self.maxn = 99999 if maxn is None else maxn me = max([ 0, ] + self.exp) self.powers = [ 1, ] pow = self.p i = 0 while pow <= me: self.powers.append(pow) pow *= self.p i += 1 if i > self.maxn: break self.ncols = len(self.powers) self.nrows = len(exponents) self.max = matrix(GF(self.p), self.nrows, self.ncols) for i in range(self.nrows): for j in range(self.ncols): self.max[i, j] = self.exp[i] // self.powers[j] Parent.__init__(self, category=FiniteEnumeratedSets())
def __init__(self, f, n, N, a, ext, Delta, strategy): self.f = f self.n = n self.N = N self.p = 2**n * N * f - 1 self.Fp = GF(self.p) self.Fpx = self.Fp['x'] x = self.Fpx.gen() self.Fp2 = self.Fp.extension(x**2 + ext, 'u') self.a = self.Fp2(a) self.Delta = Delta self.cof_P = (self.p + 1) // self.N self.strategy = strategy
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 __init__(self, p, a=0, b=0): """ Assumes p is prime. Gives an error if p ≠ 3 mod 4. """ assert p % 4 == 3 # Internally, we represent our element as a Sage field element. # # Rewrite your own implementation, of GF(p²) on top of Python integers I = SageGF(p)['I'].gen() base = SageGF(p**2, 'i', modulus=I**2 + 1) i = base.gen() self.elt = a + b * i
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 rank2_GF(n=500, p=16411, system='sage'): """ Rank over GF(p): Given a (n + 10) x n matrix over GF(p) with random entries, compute the rank. INPUT: - ``n`` - matrix dimension (default: 300) - ``p`` - prime number (default: ``16411``) - ``system`` - either 'magma' or 'sage' (default: 'sage') EXAMPLES:: sage: import sage.matrix.benchmark as b sage: ts = b.rank2_GF(500) sage: tm = b.rank2_GF(500, system='magma') # optional - magma """ if system == 'sage': A = random_matrix(GF(p), n+10, n) t = cputime() v = A.rank() return cputime(t) elif system == 'magma': code = """ n := %s; A := Random(MatrixAlgebra(GF(%s), n)); t := Cputime(); K := Rank(A); s := Cputime(t); """%(n,p) if verbose: print(code) magma.eval(code) return float(magma.eval('s')) else: raise ValueError('unknown system "%s"'%system)
def charpoly_GF(n=100, p=16411, system='sage'): """ Given a n x n matrix over GF with random entries, compute the charpoly. INPUT: - ``n`` - matrix dimension (default: 100) - ``p`` - prime number (default: ``16411``) - ``system`` - either 'magma' or 'sage' (default: 'sage') EXAMPLES:: sage: import sage.matrix.benchmark as b sage: ts = b.charpoly_GF(100) sage: tm = b.charpoly_GF(100, system='magma') # optional - magma """ if system == 'sage': A = random_matrix(GF(p), n, n) t = cputime() v = A.charpoly() return cputime(t) elif system == 'magma': code = """ n := %s; A := Random(MatrixAlgebra(GF(%s), n)); t := Cputime(); K := CharacteristicPolynomial(A); s := Cputime(t); """%(n,p) if verbose: print(code) magma.eval(code) return magma.eval('s') else: raise ValueError('unknown system "%s"'%system)
def nullspace_GF(n=300, p=16411, system='sage'): """ Given a n+1 x n matrix over GF(p) with random entries, compute the nullspace. INPUT: - ``n`` - matrix dimension (default: 300) - ``p`` - prime number (default: ``16411``) - ``system`` - either 'magma' or 'sage' (default: 'sage') EXAMPLES:: sage: import sage.matrix.benchmark as b sage: ts = b.nullspace_GF(300) sage: tm = b.nullspace_GF(300, system='magma') # optional - magma """ if system == 'sage': A = random_matrix(GF(p), n, n+1) t = cputime() v = A.kernel() return cputime(t) elif system == 'magma': code = """ n := %s; A := Random(RMatrixSpace(GF(%s), n, n+1)); t := Cputime(); K := Kernel(A); s := Cputime(t); """%(n,p) if verbose: print(code) magma.eval(code) return magma.eval('s') else: raise ValueError('unknown system "%s"'%system)
def __init__(self, order, num_of_var): r""" TESTS: If the order given is greater than the number of variables an error is raised:: sage: C = codes.BinaryReedMullerCode(5, 4) Traceback (most recent call last): ... ValueError: The order must be less than or equal to 4 The order and the number of variable must be integers:: sage: C = codes.BinaryReedMullerCode(1.1,4) Traceback (most recent call last): ... ValueError: The order of the code must be an integer """ # input sanitization if not (isinstance(order, (Integer, int))): raise ValueError("The order of the code must be an integer") if not (isinstance(num_of_var, (Integer, int))): raise ValueError("The number of variables must be an integer") if (num_of_var < order): raise ValueError("The order must be less than or equal to %s" % num_of_var) super(BinaryReedMullerCode, self).__init__(GF(2), 2**num_of_var, "EvaluationVector", "Syndrome") self._order = order self._num_of_var = num_of_var self._dimension = _binomial_sum(num_of_var, order)
def test_python(p, i1, i2, number=0, repeat=3): import compositum as c K = GF(p) P = K.extension(i1, 'x') R, phi, phinv = c.ffext(P, i2) a = P.random_element() c = R.random_element() d = R.random_element() context = globals() context.update(locals()) tembed = sage_timeit('phi(a)', context, number=number, repeat=repeat, seconds=True) tproject = sage_timeit('phinv(c)', context, number=number, repeat=repeat, seconds=True) tmul = sage_timeit('c*d', context, number=number, repeat=repeat, seconds=True) return tembed, tproject, tmul
def __init__(self, space, number_errors, number_erasures): r""" TESTS: If the sum of number of errors and number of erasures exceeds (or may exceed, in the case of tuples) the dimension of the input space, it will return an error:: sage: n_err, n_era = 21, 21 sage: Chan = channels.ErrorErasureChannel(GF(59)^40, n_err, n_era) Traceback (most recent call last): ... ValueError: The total number of errors and erasures can not exceed the dimension of the input space """ if isinstance(number_errors, (Integer, int)): number_errors = (number_errors, number_errors) if not isinstance(number_errors, (tuple, list)): raise ValueError("number_errors must be a tuple, a list, an Integer or a Python int") if isinstance(number_erasures, (Integer, int)): number_erasures = (number_erasures, number_erasures) if not isinstance(number_erasures, (tuple, list)): raise ValueError("number_erasures must be a tuple, a list, an Integer or a Python int") output_space = cartesian_product([space, VectorSpace(GF(2), space.dimension())]) super(ErrorErasureChannel, self).__init__(space, output_space) if number_errors[1] + number_erasures[1] > space.dimension(): raise ValueError("The total number of errors and erasures can not exceed the dimension of the input space") self._number_errors = number_errors self._number_erasures = number_erasures
def DuadicCodeOddPair(F, S1, S2): """ Constructs the "odd pair" of duadic codes associated to the "splitting" S1, S2 of n. .. warning:: Maybe the splitting should be associated to a sum of q-cyclotomic cosets mod n, where q is a *prime*. EXAMPLES:: sage: from sage.coding.code_constructions import _is_a_splitting 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: codes.DuadicCodeOddPair(GF(q),S1,S2) ([11, 6] Cyclic Code over GF(3), [11, 6] Cyclic Code over GF(3)) This is consistent with Theorem 6.1.3 in [HP2003]_. """ from sage.misc.stopgap import stopgap stopgap( "The function DuadicCodeOddPair has several issues which may cause wrong results", 25896) from .cyclic_code import CyclicCode n = len(S1) + len(S2) + 1 if not _is_a_splitting(S1, S2, n): raise TypeError("%s, %s must be a splitting of %s." % (S1, S2, n)) q = F.order() k = Mod(q, n).multiplicative_order() FF = GF(q**k, "z") z = FF.gen() zeta = z**((q**k - 1) / n) P1 = PolynomialRing(FF, "x") x = P1.gen() g1 = prod([x - zeta**i for i in S1 + [0]]) g2 = prod([x - zeta**i for i in S2 + [0]]) j = sum([x**i / n for i in range(n)]) P2 = PolynomialRing(F, "x") x = P2.gen() coeffs1 = [ _lift2smallest_field(c)[0] for c in (g1 + j).coefficients(sparse=False) ] coeffs2 = [ _lift2smallest_field(c)[0] for c in (g2 + j).coefficients(sparse=False) ] gg1 = P2(coeffs1) gg2 = P2(coeffs2) gg1 = gcd(gg1, x**n - 1) gg2 = gcd(gg2, x**n - 1) C1 = CyclicCode(length=n, generator_pol=gg1) C2 = CyclicCode(length=n, generator_pol=gg2) return C1, C2
def padic_H_values(self, t): res = self.amortized_padic_H_values(t) is_tame = self.is_tame_prime(t) for p in prime_range(self._pbound + 1): if not is_tame(p): res[p] = GF(p)(self.padic_H_value(p=p, f=1, t=t)) return res
def dicksons(self): """ TESTS:: sage: from yacop.modules.dickson import PetersonPolynomials sage: P=PetersonPolynomials(2,3) sage: for p in P.dicksons(): ....: print(p) x1^4*x2^2*x3 + x1^2*x2^4*x3 + x1^4*x2*x3^2 + x1*x2^4*x3^2 + x1^2*x2*x3^4 + x1*x2^2*x3^4 x1^4*x2^2 + x1^2*x2^4 + x1^4*x2*x3 + x1*x2^4*x3 + x1^4*x3^2 + x1^2*x2^2*x3^2 + x2^4*x3^2 + x1^2*x3^4 + x1*x2*x3^4 + x2^2*x3^4 x1^4 + x1^2*x2^2 + x2^4 + x1^2*x2*x3 + x1*x2^2*x3 + x1^2*x3^2 + x1*x2*x3^2 + x2^2*x3^2 + x3^4 sage: P=PetersonPolynomials(5,2) sage: for p in P.dicksons(): ....: print(p) x1^20*x2^4 + x1^16*x2^8 + x1^12*x2^12 + x1^8*x2^16 + x1^4*x2^20 x1^20 + x1^16*x2^4 + x1^12*x2^8 + x1^8*x2^12 + x1^4*x2^16 + x2^20 """ xi = self.Q.gens()[:-1] t = self.Q.gens()[self.n] pol = self.Q.prod(t + self.Q.sum(a * x for (a, x) in zip(cf, xi)) for cf in GF(self.p)**self.n) return [ pol.coefficient(t**(self.p**i)) * (-1)**(self.n - i) for i in range(self.n) ]
def _lift2smallest_field(a): """ INPUT: a is an element of a finite field GF(q) OUTPUT: the element b of the smallest subfield F of GF(q) for which F(b)=a. EXAMPLES:: sage: from sage.coding.code_constructions import _lift2smallest_field sage: FF.<z> = GF(3^4,"z") sage: a = z^10 sage: _lift2smallest_field(a) (2*z + 1, Finite Field in z of size 3^2) sage: a = z^40 sage: _lift2smallest_field(a) (2, Finite Field of size 3) AUTHORS: - John Cremona """ FF = a.parent() k = FF.degree() if k == 1: return a, FF pol = a.minimal_polynomial() d = pol.degree() if d == k: return a, FF p = FF.characteristic() F = GF(p**d, "z") b = pol.roots(F, multiplicities=False)[0] return b, F
def zeta(self, n=None): r""" Returns a generator of the group of roots of unity. INPUT: - ``self`` -- a `p`-adic ring - ``n`` -- an integer or ``None`` (default: ``None``) OUTPUT: - ``element`` -- a generator of the `n^{th}` roots of unity, or a generator of the full group of roots of unity if ``n`` is ``None`` EXAMPLES:: sage: R = Zp(37,5) sage: R.zeta(12) 8 + 24*37 + 37^2 + 29*37^3 + 23*37^4 + O(37^5) """ if (self.prime() == 2): if (n is None) or (n == 2): return self(-1) if n == 1: return self(1) else: raise ValueError("No, %sth root of unity in self" % n) else: from sage.rings.finite_rings.finite_field_constructor import GF return self.teichmuller(GF(self.prime()).zeta(n).lift())
def __init__(self, p, n): """ TESTS:: sage: from yacop.modules.dickson import PetersonPolynomials sage: P=PetersonPolynomials(3,2) ; P Peterson element factory for prime 3, index 2 sage: for idx in range(20): ....: print("%-3d : %s" % (idx,P.omega(idx))) 0 : 1 1 : x1^2 + x2^2 2 : x1^4 + x1^2*x2^2 + x2^4 3 : x1^6 + x1^4*x2^2 + x1^2*x2^4 + x2^6 4 : x1^6*x2^2 + x1^4*x2^4 + x1^2*x2^6 5 : -x1^10 + x1^6*x2^4 + x1^4*x2^6 - x2^10 6 : x1^12 - x1^10*x2^2 + x1^6*x2^6 - x1^2*x2^10 + x2^12 7 : x1^12*x2^2 - x1^10*x2^4 - x1^4*x2^10 + x1^2*x2^12 8 : x1^12*x2^4 - x1^10*x2^6 - x1^6*x2^10 + x1^4*x2^12 9 : x1^18 + x1^12*x2^6 + x1^6*x2^12 + x2^18 10 : x1^18*x2^2 + x1^10*x2^10 + x1^2*x2^18 11 : x1^18*x2^4 - x1^12*x2^10 - x1^10*x2^12 + x1^4*x2^18 12 : x1^18*x2^6 + x1^12*x2^12 + x1^6*x2^18 13 : 0 14 : x1^28 - x1^18*x2^10 - x1^10*x2^18 + x2^28 15 : -x1^30 + x1^28*x2^2 + x1^18*x2^12 + x1^12*x2^18 + x1^2*x2^28 - x2^30 16 : -x1^30*x2^2 + x1^28*x2^4 + x1^4*x2^28 - x1^2*x2^30 17 : -x1^30*x2^4 + x1^28*x2^6 + x1^6*x2^28 - x1^4*x2^30 18 : x1^36 - x1^30*x2^6 + x1^18*x2^18 - x1^6*x2^30 + x2^36 19 : x1^36*x2^2 - x1^28*x2^10 - x1^10*x2^28 + x1^2*x2^36 """ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing from yacop.modules.classifying_spaces import BZpGeneric from sage.categories.tensor import tensor self.p = p self.n = n self.B = BZpGeneric(p) factors = tuple([ self.B, ] * n) self.BT = tensor(factors) self.tc = self.BT.tensor_constructor(factors) deg = -1 fac = 2 # if p>2 else 1 self.b = self.B.monomial(fac * deg) self.binv = self.B.monomial(-fac * deg) self.bt = tensor([ self.b, ] * n) self.bti = tensor([ self.binv, ] * n) self.P = SteenrodAlgebra(p, generic=True).P self.Q = PolynomialRing( GF(p), ["x%d" % (i + 1) for i in range(n)] + [ "t", ], )
def __init__(self, poly, prec, print_mode, names, element_class): """ Initializes self INPUT: - poly -- Polynomial defining this extension. - prec -- The precision cap - print_mode -- a dictionary with print options - names -- a 4-tuple, (variable_name, residue_name, unramified_subextension_variable_name, uniformizer_name) - element_class -- the class for elements of this unramified extension. EXAMPLES:: sage: R.<a> = Zq(27) #indirect doctest """ #base = poly.base_ring() #if base.is_field(): # self._PQR = pqr.PolynomialQuotientRing_field(poly.parent(), poly, name = names) #else: # self._PQR = pqr.PolynomialQuotientRing_domain(poly.parent(), poly, name = names) pAdicExtensionGeneric.__init__(self, poly, prec, print_mode, names, element_class) self._res_field = GF(self.prime_pow.pow_Integer_Integer(poly.degree()), name=names[1], modulus=poly.change_ring( poly.base_ring().residue_field()))
def present_llayer(n, x): dim = 4*n y = [0]*dim for i in range(dim-1): y[i] = x[(n * i) % (dim - 1)] y[dim-1] = x[dim-1] return vector(GF(2), y)
def test_ellrains(pbound = 2**62, nbound = 100): import sys from sage.sets.primes import Primes for p in Primes(): if p < 4: continue if p > pbound: break for n in xrange(2, nbound): k = GF(p**n, name='z') K = FiniteField_flint_fq_nmod(p, k.modulus(), name='z') try: a, b = find_gens(K, K) print "Testing p = {} and n = {}".format(p, n) print "Computing minpol...", sys.stdout.flush() f = a.minpoly() assert f.degree() == n g = b.minpoly() assert f == g print "done" except RuntimeError: pass
def benchmark(pbound = [3, 2**10], nbound = [3, 2**8], cbound = [1, Infinity], obound = [1, Infinity], loops = 10, tloop = Infinity, tmax = Infinity, prime = False, even = False, check = False, fname = None, write = False, overwrite = False, verbose = True, skip_pari = False, skip_magma = False, skip_rains = False, skip_kummer = False): if write: mode = 'w' if overwrite else 'a' f = open(fname, mode, 0) else: f = sys.stdout pmin, pmax = pbound nmin, nmax = nbound omin, omax = obound cmin, cmax = cbound M = Magma() for p in xrange(pmin, pmax): p = ZZ(p) if not p.is_prime(): continue for n in xrange(nmin, nmax): n = ZZ(n) if (prime == 1 and not is_prime(n)) or (prime == 2 and not is_prime_power(n)): continue if n < 2: continue if n % p == 0: continue if (not even) and (n % 2 == 0): continue o, G = find_root_order(p, [n, n], n, verbose=False) m = G[0][0].parent().order() c = Mod(p,n).multiplicative_order() if verbose: sys.stdout.write("\r"+" "*79) print("\rp = {}, n = {}, (o = {}, c = {})".format(p, n, o, c)) if verbose: t = mytime() sys.stdout.write("Constructing fields ({})".format(time.strftime("%c"))) sys.stdout.flush() q = p**n k = GF(q, name='z') k_rand = GF(q, modulus='random', name='z') k_flint = GF_flint(p, k.modulus(), name='z') if verbose > 1: sys.stdout.write("\ntotal: {}s\n".format(mytime(t))) sys.stdout.flush() # Magma if verbose: sys.stdout.write("\r"+" "*79) sys.stdout.write("\rMagma ({})".format(time.strftime("%c"))) sys.stdout.flush() tloops = 0 for l in xrange(loops): if skip_magma: break if (o > omax) or (o == p): break # let's assume that launching a new Magma instance is cheaper # than computing random irreducible polynomials try: M._start() except OSError as err: # but it can also cause fork issues... # let's accept this # and fail as the situation will only worsen # unless it is "just" a memory issue # which should be mitigated by COW but is not #print(err) if err.errno == errno.ENOMEM: break else: raise try: k_magma = M(k) k_rand_magma = M(k_rand) if tloop is not Infinity: alarm(tloop) t = mytime() k_magma.Embed(k_rand_magma, nvals=0) #M._eval_line("Embed(k_magma, k_rand_magma);", wait_for_prompt=False) tloops += mytime(t) except TypeError: # sage/magma interface sometimes gets confused pass except (KeyboardInterrupt, AlarmInterrupt): # sage interface eats KeyboardInterrupt # and AlarmInterrupt derives from it tloops = 0 break finally: if tloop is not Infinity: cancel_alarm() M.quit() # sage pexpect interface leaves zombies around try: while os.waitpid(-1, os.WNOHANG)[0]: pass # but sometimes every child is already buried # and we get an ECHILD error... except OSError: pass if tloops > tmax: break tmagma = tloops / (l+1) if verbose > 1: sys.stdout.write("\ntotal: {}s, per loop: {}s\n".format(tloops, tloops/(l+1))) sys.stdout.flush() # Rains algorithms if verbose: sys.stdout.write("\r"+" "*79) sys.stdout.write("\rCyclotomic Rains ({})".format(time.strftime("%c"))) sys.stdout.flush() trains = [] tloops = 0 for l in xrange(loops): if skip_rains: break if (o > omax) or (o == p): break try: if tloop is not Infinity: alarm(tloop) t = mytime() a, b = find_gens_cyclorains(k_flint, k_flint, use_lucas = False) tloops += mytime(t) except (KeyboardInterrupt, AlarmInterrupt): tloops = 0 break finally: if tloop is not Infinity: cancel_alarm() if check and (l == 0 or check > 1): g = a.minpoly() if g.degree() != n: raise RuntimeError("wrong degree") if g != b.minpoly(): raise RuntimeError("different minpolys") if tloops > tmax: break trains.append(tloops / (l+1)) if verbose > 1: sys.stdout.write("\ntotal: {}s, per loop: {}s\n".format(tloops, tloops/(l+1))) sys.stdout.flush() # Conic Rains if verbose: sys.stdout.write("\r"+" "*79) sys.stdout.write("\rConic Rains ({})".format(time.strftime("%c"))) sys.stdout.flush() tloops = 0 for l in xrange(loops): if skip_rains: break if (o != 2) or (o > omax) or (o == p): break try: if tloop is not Infinity: alarm(tloop) t = mytime() a, b = find_gens_cyclorains(k_flint, k_flint, use_lucas = True) tloops += mytime(t) except (KeyboardInterrupt, AlarmInterrupt): tloops = 0 break finally: if tloop is not Infinity: cancel_alarm() if check and (l == 0 or check > 1): g = a.minpoly() if g.degree() != n: raise RuntimeError("wrong degree") if g != b.minpoly(): raise RuntimeError("different minpolys") if tloops > tmax: break trains.append(tloops / (l+1)) if verbose > 1: sys.stdout.write("\ntotal: {}s, per loop: {}s\n".format(tloops, tloops/(l+1))) sys.stdout.flush() # Elliptic Rains if verbose: sys.stdout.write("\r"+" "*79) sys.stdout.write("\rElliptic Rains ({})".format(time.strftime("%c"))) sys.stdout.flush() tloops = 0 for l in xrange(loops): if skip_rains: break try: if tloop is not Infinity: alarm(tloop) t = mytime() a, b = find_gens_ellrains(k_flint, k_flint) tloops += mytime(t) except RuntimeError: # sometimes no suitable elliptic curve exists pass except (KeyboardInterrupt, AlarmInterrupt): tloops = 0 break finally: if tloop is not Infinity: cancel_alarm() if check and (l == 0 or check > 1): g = a.minpoly() if g.degree() != n: raise RuntimeError("wrong degree") if g != b.minpoly(): raise RuntimeError("different minpolys") if tloops > tmax: break trains.append(tloops / (l+1)) if verbose > 1: sys.stdout.write("\ntotal: {}s, per loop: {}s\n".format(tloops, tloops/(l+1))) sys.stdout.flush() # PARI/GP if verbose: sys.stdout.write("\r"+" "*79) sys.stdout.write("\rPARI/GP ({})".format(time.strftime("%c"))) sys.stdout.flush() tloops = 0 for l in xrange(loops): if skip_pari: break if c < cmin or c > cmax: break try: if tloop is not Infinity: alarm(tloop) t = mytime() a, b = find_gens_pari(k, k) tloops += mytime(t) except (KeyboardInterrupt, AlarmInterrupt): tloops = 0 break finally: if tloop is not Infinity: cancel_alarm() if check and (l == 0 or check > 1): g = a.minpoly() if g.degree() != n: raise RuntimeError("wrong degree") if g != b.minpoly(): raise RuntimeError("different minpolys") if tloops > tmax: break tpari = tloops / (l+1) # Kummer algorithms tkummer = [] # only linalg and modcomp implemented for c==1 for i, algo in enumerate(kummer_algolist[2*(c==1):-2*(c==1)-1]): if verbose: sys.stdout.write("\r"+" "*79) sys.stdout.write("\rKummer {} ({})".format(kummer_namelist[2*(c==1)+i], time.strftime("%c"))) sys.stdout.flush() tloops = 0 for l in xrange(loops): if skip_kummer: break if c < cmin or c > cmax: break try: if tloop is not Infinity: alarm(tloop) t = mytime() a, b = find_gens_kummer(k_flint, k_flint, n, algo) tloops += mytime(t) except (KeyboardInterrupt, AlarmInterrupt): tloops = 0 break finally: if tloop is not Infinity: cancel_alarm() if check and (l == 0 or check > 1): g = a.minpoly() if g.degree() != n: raise RuntimeError("wrong degree") if g != b.minpoly(): raise RuntimeError("different minpolys") if tloops > tmax: break tkummer.append(tloops / (l+1)) if verbose > 1: sys.stdout.write("\ntotal: {}s, per loop: {}s\n".format(tloops, tloops/(l+1))) sys.stdout.flush() tkummer = 2*(c == 1)*[0] + tkummer + 2*(c == 1)*[0] if verbose: sys.stdout.write("\r") sys.stdout.flush() f.write(("{} {} ({}, {})" + " {}" + " {}"*len(trains) + " {}" + " {}"*len(tkummer)+"\n").format(p, n, o, c, *([tmagma] + trains + [tpari] + tkummer))) if write: f.close()
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
POWM2M2D3 = ZZ((2**m2-2)/3) POWM2P1D3 = ZZ((2**m2+1)/3) 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
def ProjectiveGeometryDesign(n, d, F, algorithm=None, point_coordinates=True, check=True): r""" Return a projective geometry design. The projective geometry design `PG_d(n,q)` has for points the lines of `\GF{q}^{n+1}`, and for blocks the `d+1`-dimensional subspaces of `\GF{q}^{n+1}`, each of which contains `\frac {|\GF{q}|^{d+1}-1} {|\GF{q}|-1}` lines. It is a `2`-design with parameters .. MATH:: v = \binom{n+1}{1}_q,\ k = \binom{d+1}{1}_q,\ \lambda = \binom{n-1}{d-1}_q where the `q`-binomial coefficient `\binom{m}{r}_q` is defined by .. MATH:: \binom{m}{r}_q = \frac{(q^m - 1)(q^{m-1} - 1) \cdots (q^{m-r+1}-1)} {(q^r-1)(q^{r-1}-1)\cdots (q-1)} .. SEEALSO:: :func:`AffineGeometryDesign` INPUT: - ``n`` is the projective dimension - ``d`` is the dimension of the subspaces which make up the blocks. - ``F`` -- a finite field or a prime power. - ``algorithm`` -- set to ``None`` by default, which results in using Sage's own implementation. In order to use GAP's implementation instead (i.e. its ``PGPointFlatBlockDesign`` function) set ``algorithm="gap"``. Note that GAP's "design" package must be available in this case, and that it can be installed with the ``gap_packages`` spkg. - ``point_coordinates`` -- ``True`` by default. Ignored and assumed to be ``False`` if ``algorithm="gap"``. If ``True``, the ground set is indexed by coordinates in `\GF{q}^{n+1}`. Otherwise the ground set is indexed by integers. - ``check`` -- (optional, default to ``True``) whether to check the output. EXAMPLES: The set of `d`-dimensional subspaces in a `n`-dimensional projective space forms `2`-designs (or balanced incomplete block designs):: sage: PG = designs.ProjectiveGeometryDesign(4, 2, GF(2)) sage: PG Incidence structure with 31 points and 155 blocks sage: PG.is_t_design(return_parameters=True) (True, (2, 31, 7, 7)) sage: PG = designs.ProjectiveGeometryDesign(3, 1, GF(4)) sage: PG.is_t_design(return_parameters=True) (True, (2, 85, 5, 1)) Check with ``F`` being a prime power:: sage: PG = designs.ProjectiveGeometryDesign(3, 2, 4) sage: PG Incidence structure with 85 points and 85 blocks Use coordinates:: sage: PG = designs.ProjectiveGeometryDesign(2, 1, GF(3)) sage: PG.blocks()[0] [(1, 0, 0), (1, 0, 1), (1, 0, 2), (0, 0, 1)] Use indexing by integers:: sage: PG = designs.ProjectiveGeometryDesign(2,1,GF(3),point_coordinates=0) sage: PG.blocks()[0] [0, 1, 2, 12] Check that the constructor using gap also works:: sage: BD = designs.ProjectiveGeometryDesign(2, 1, GF(2), algorithm="gap") # optional - gap_packages (design package) sage: BD.is_t_design(return_parameters=True) # optional - gap_packages (design package) (True, (2, 7, 3, 1)) """ try: q = int(F) except TypeError: q = F.cardinality() else: from sage.rings.finite_rings.finite_field_constructor import GF F = GF(q) if algorithm is None: from sage.matrix.echelon_matrix import reduced_echelon_matrix_iterator points = {p:i for i,p in enumerate(reduced_echelon_matrix_iterator(F,1,n+1,copy=True,set_immutable=True))} blocks = [] for m1 in reduced_echelon_matrix_iterator(F,d+1,n+1,copy=False): b = [] for m2 in reduced_echelon_matrix_iterator(F,1,d+1,copy=False): m = m2*m1 m.echelonize() m.set_immutable() b.append(points[m]) blocks.append(b) B = BlockDesign(len(points), blocks, name="ProjectiveGeometryDesign", check=check) if point_coordinates: B.relabel({i:p[0] for p,i in points.iteritems()}) elif algorithm == "gap": # Requires GAP's Design from sage.interfaces.gap import gap gap.load_package("design") gap.eval("D := PGPointFlatBlockDesign( %s, %s, %d )"%(n,F.order(),d)) v = eval(gap.eval("D.v")) gblcks = eval(gap.eval("D.blocks")) gB = [] for b in gblcks: gB.append([x-1 for x in b]) B = BlockDesign(v, gB, name="ProjectiveGeometryDesign", check=check) if check: from sage.combinat.q_analogues import q_binomial q = F.cardinality() if not B.is_t_design(t=2, v=q_binomial(n+1,1,q), k=q_binomial(d+1,1,q), l=q_binomial(n-1, d-1, q)): raise RuntimeError("error in ProjectiveGeometryDesign " "construction. Please e-mail [email protected]") return B