def __init__(self, field = None): """ Create a linear feedback shift cryptosystem. INPUT: A string monoid over a binary alphabet. OUTPUT: EXAMPLES:: sage: E = LFSRCryptosystem(FiniteField(2)) sage: E LFSR cryptosystem over Finite Field of size 2 TESTS:: sage: E = LFSRCryptosystem(FiniteField(2)) sage: E == loads(dumps(E)) True TODO: Implement LFSR cryptosystem for arbitrary rings. The current implementation is limited to the finite field of 2 elements only because of the dependence on binary strings. """ if field is None: field = FiniteField(2) if field.cardinality() != 2: raise NotImplementedError("Not yet implemented.") S = BinaryStrings() P = PolynomialRing(FiniteField(2),'x') SymmetricKeyCryptosystem.__init__(self, S, S, None) self._field = field
def twin_prime_powers_difference_set(p, check=True): r""" Return a difference set on `GF(p) \times GF(p+2)`. The difference set is built from the following element of the Cartesian product of finite fields `GF(p) \times GF(p+2)`: - `(x,0)` with any `x` - `(x,y)` with `x` and `y` squares - `(x,y)` with `x` and `y` non-squares For more information see :wikipedia:`Difference_set`. INPUT: - ``check`` -- boolean (default: ``True``). If ``True`` then the result of the computation is checked before being returned. This should not be needed but ensures that the output is correct. EXAMPLES:: sage: from sage.combinat.designs.difference_family import twin_prime_powers_difference_set sage: G,D = twin_prime_powers_difference_set(3) sage: G The Cartesian product of (Finite Field of size 3, Finite Field of size 5) sage: D [[(1, 1), (1, 4), (2, 2), (2, 3), (0, 0), (1, 0), (2, 0)]] """ from sage.rings.finite_rings.finite_field_constructor import FiniteField from sage.categories.cartesian_product import cartesian_product from itertools import product Fp = FiniteField(p, 'x') Fq = FiniteField(p + 2, 'x') Fpset = set(Fp) Fqset = set(Fq) Fp_squares = set(x**2 for x in Fpset) Fq_squares = set(x**2 for x in Fqset) # Pairs of squares, pairs of non-squares d = [] d.extend(product(Fp_squares.difference([0]), Fq_squares.difference([0]))) d.extend( product(Fpset.difference(Fp_squares), Fqset.difference(Fq_squares))) # All (x,0) d.extend((x, 0) for x in Fpset) G = cartesian_product([Fp, Fq]) if check and not is_difference_family(G, [d]): raise RuntimeError("twin_prime_powers_difference_set produced a wrong " "difference set with p={}. Please contact " "*****@*****.**".format(p)) return G, [d]
def __init__(self, p, use_database=True): """ TESTS:: sage: from sage.rings.finite_rings.conway_polynomials import PseudoConwayLattice sage: PCL = PseudoConwayLattice(3) sage: PCL.polynomial(3) x^3 + 2*x + 1 sage: PCL = PseudoConwayLattice(5, use_database=False) sage: PCL.polynomial(12) x^12 + 4*x^11 + 2*x^10 + 4*x^9 + 2*x^8 + 2*x^7 + 4*x^6 + x^5 + 2*x^4 + 2*x^2 + x + 2 sage: PCL.polynomial(6) x^6 + x^5 + 4*x^4 + 3*x^3 + 3*x^2 + 2*x + 2 sage: PCL.polynomial(11) x^11 + x^6 + 3*x^3 + 4*x + 3 """ self.p = p from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing self.ring = PolynomialRing(FiniteField(p), 'x') if use_database: C = sage.databases.conway.ConwayPolynomials() self.nodes = { n: self.ring(C.polynomial(p, n)) for n in C.degrees(p) } else: self.nodes = {}
def _test_category_contains(self, tester=None, **options): """ Test the implicit __contains__ method of this category:: sage: from yacop.modules.projective_spaces import RealProjectiveSpace sage: M=RealProjectiveSpace() sage: M.category() Category of yacop left module algebras over mod 2 Steenrod algebra, milnor basis sage: M in M.category() True sage: M._test_category_contains() """ from sage.misc.lazy_format import LazyFormat from sage.rings.finite_rings.finite_field_constructor import FiniteField tester = self._tester(**options) tester.assertTrue( self in self.category(), LazyFormat("%s not contained in its category %s" % (self, self.category())), ) M = ModulesWithBasis(FiniteField(self.base_ring().characteristic())) tester.assertTrue(self in M, LazyFormat("%s not contained in %s" % (self, M)))
def __init__(self, prime=2, level=1, base_ring=ZZ): r""" Create a supersingular module. EXAMPLES:: sage: SupersingularModule(3) Module of supersingular points on X_0(1)/F_3 over Integer Ring """ if not prime.is_prime(): raise ValueError("the argument prime must be a prime number") if prime.divides(level): raise ValueError( "the argument level must be coprime to the argument prime") if level != 1: raise NotImplementedError( "supersingular modules of level > 1 not yet implemented") self.__prime = prime self.__finite_field = FiniteField(prime**2, 'a') self.__level = level self.__hecke_matrices = {} hecke.HeckeModule_free_module.__init__(self, base_ring, prime * level, weight=2)
def __classcall__(cls, *args, **kwds): """ Normalize input to ensure a unique representation. EXAMPLES:: sage: A = AffineSpace(2, GF(4,'a')) sage: AffineGroup(A) is AffineGroup(2,4) True sage: AffineGroup(A) is AffineGroup(2, GF(4,'a')) True sage: A = AffineGroup(2, QQ) sage: V = QQ^2 sage: A is AffineGroup(V) True """ if len(args) == 1: V = args[0] if isinstance(V, AffineGroup): return V try: degree = V.dimension_relative() except AttributeError: degree = V.dimension() ring = V.base_ring() if len(args) == 2: degree, ring = args from sage.rings.integer import is_Integer if is_Integer(ring): from sage.rings.finite_rings.finite_field_constructor import FiniteField var = kwds.get('var', 'a') ring = FiniteField(ring, var) return super(AffineGroup, cls).__classcall__(cls, degree, ring)
def __init__(this, p, category=None): """ TESTS:: sage: from yacop.testing.testalgebra import Testclass1 sage: X=Testclass1(5) sage: X.monomial((2,1,8,0)) x^2*a*y^8 sage: X.monomial((3,0,-17,1)) x^3*b/y^17 sage: from yacop.utils.region import region sage: X._manual_test_left_action(region(tmax=20)) 1126 non-zero multiplications checked sage: X._manual_test_left_conj_action(region(tmax=20)) # long time 1148 non-zero multiplications checked """ # must admit the "category" keyword for suspendability R = PolynomialRing(FiniteField(p), "x,a,y,b") x, a, y, b = R.gens() I = R.ideal([a**2, b**2]) degs = lambda idx: (1, -1, 0) if (idx & 1) else (2, 0, 0) SteenrodAlgebraBase.__init__(this, R, [degs(n) for n in range(4)], I, SteenrodAlgebra(p), category=category)
def upper_bound_on_elliptic_factors(self, p=None, ellmax=2): r""" Return an upper bound (provably correct) on the number of elliptic curves of conductor equal to the level of this supersingular module. INPUT: - ``p`` -- (default: 997) prime to work modulo ALGORITHM: Currently we only use `T_2`. Function will be extended to use more Hecke operators later. The prime p is replaced by the smallest prime that does not divide the level. EXAMPLES:: sage: SupersingularModule(37).upper_bound_on_elliptic_factors() 2 (There are 4 elliptic curves of conductor 37, but only 2 isogeny classes.) """ from sage.misc.verbose import verbose # NOTE: The heuristic runtime is *very* roughly `p^2/(2\cdot 10^6)`. # ellmax -- (default: 2) use Hecke operators T_ell with ell <= ellmax if p is None: p = 997 while self.level() % p == 0: p = next_prime(p) ell = 2 t = self.hecke_matrix(ell).change_ring(FiniteField(p)) # TODO: temporarily try using sparse=False # turn this off when sparse rank is optimized. t = t.dense_matrix() B = ZZ(4 * ell).isqrt() bnd = 0 lower = -B upper = B + 1 for a in range(lower, upper): tm = verbose("computing T_%s - %s" % (ell, a)) if a == lower: c = a else: c = 1 for i in range(t.nrows()): t[i, i] += c tm = verbose("computing kernel", tm) # dim = t.kernel().dimension() dim = t.nullity() bnd += dim verbose('got dimension = %s; new bound = %s' % (dim, bnd), tm) return bnd
def steenrod_algebra_intersect(algebras): """ TESTS:: sage: from yacop.categories.utils import steenrod_algebra_intersect sage: A = SteenrodAlgebra(3) sage: B = SteenrodAlgebra(3,profile=((1,),(2,2))) sage: C = SteenrodAlgebra(3,profile=((),(1,2))) sage: steenrod_algebra_intersect((A,B)) sub-Hopf algebra of mod 3 Steenrod algebra, milnor basis, profile function ([1], [2, 2]) sage: steenrod_algebra_intersect((A,GF(3),A)) Finite Field of size 3 """ from sage.algebras.steenrod.steenrod_algebra import SteenrodAlgebra for dummy in (0,): A0 = algebras[0] if not all(A.characteristic() == A0.characteristic() for A in algebras): break for A in algebras: if not hasattr(A, "is_generic"): # this algebra is not a Steenrod algebra return FiniteField(A.characteristic()) if not all(A.is_generic() == A0.is_generic() for A in algebras): break rtrunc = +Infinity if all(A._truncation_type > 0 for A in algebras) else 0 isgen = A0.is_generic() profiles = ( [A._profile for A in algebras] if isgen else [(A._profile, ()) for A in algebras] ) proflen = max( [ 0, ] + [len(p[0]) for p in profiles] + [len(p[1]) for p in profiles] ) nprof0 = [ min(A.profile(i, component=0) for A in algebras) for i in range(1, proflen + 1) ] nprof1 = [ min(A.profile(i, component=1) for A in algebras) for i in range(0, proflen) ] prof = (nprof0, nprof1) if isgen else nprof0 # return prof res = SteenrodAlgebra( A0.prime(), generic=isgen, profile=prof, truncation_type=rtrunc ) return res raise ValueError("algebras not compatible")
def category_meet(self, other): """ TESTS:: sage: from yacop.categories.utils import category_meet sage: from yacop.categories.left_modules import YacopLeftModules sage: from yacop.categories.right_modules import YacopRightModules sage: A3=YacopLeftModules(SteenrodAlgebra(3)) sage: category_meet(A3,A3) Category of yacop left modules over mod 3 Steenrod algebra, milnor basis sage: category_meet(A3,Modules(GF(3))) Category of vector spaces over Finite Field of size 3 sage: A2=YacopLeftModules(SteenrodAlgebra(2)) sage: B2=YacopLeftModules(SteenrodAlgebra(2,profile=(2,1,1))) sage: category_meet(A2,B2) Category of yacop left modules over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [2, 1, 1] sage: A2=YacopRightModules(SteenrodAlgebra(2)) sage: B2=YacopRightModules(SteenrodAlgebra(2,profile=(2,1,1))) sage: category_meet(A2,B2) Category of yacop right modules over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [2, 1, 1] """ import yacop.categories oR = other.base_ring() B = steenrod_algebra_intersect((self.base_ring(), oR)) if not hasattr(B, "is_generic"): return Modules(FiniteField(B.characteristic())) is_algebra = self._yacop_has_multiplication() and other._yacop_has_multiplication() is_right = self._yacop_has_right_action() and other._yacop_has_right_action() is_left = self._yacop_has_left_action() and other._yacop_has_left_action() is_bimod = is_left and is_right if is_algebra: if is_bimod: return yacop.categories.bimodules.YacopBimoduleAlgebras(B) elif is_right: return yacop.categories.right_modules.YacopRightModuleAlgebras(B) else: return yacop.categories.left_modules.YacopLeftModuleAlgebras(B) else: if is_bimod: return yacop.categories.bimodules.YacopBimodules(B) elif is_right: return yacop.categories.right_modules.YacopRightModules(B) else: return yacop.categories.left_modules.YacopLeftModules(B)
def check_consistency(self, n): """ Check that the pseudo-Conway polynomials of degree dividing `n` in this lattice satisfy the required compatibility conditions. EXAMPLES:: sage: from sage.rings.finite_rings.conway_polynomials import PseudoConwayLattice sage: PCL = PseudoConwayLattice(2, use_database=False) sage: PCL.check_consistency(6) sage: PCL.check_consistency(60) # long time """ p = self.p K = FiniteField(p**n, modulus = self.polynomial(n), names='a') a = K.gen() for m in n.divisors(): assert (a**((p**n-1)//(p**m-1))).minimal_polynomial() == self.polynomial(m)
def conway_polynomial(p, n): """ Return the Conway polynomial of degree `n` over ``GF(p)``. If the requested polynomial is not known, this function raises a ``RuntimeError`` exception. INPUT: - ``p`` -- prime number - ``n`` -- positive integer OUTPUT: - the Conway polynomial of degree `n` over the finite field ``GF(p)``, loaded from a table. .. NOTE:: The first time this function is called a table is read from disk, which takes a fraction of a second. Subsequent calls do not require reloading the table. See also the ``ConwayPolynomials()`` object, which is the table of Conway polynomials used by this function. EXAMPLES:: sage: conway_polynomial(2,5) x^5 + x^2 + 1 sage: conway_polynomial(101,5) x^5 + 2*x + 99 sage: conway_polynomial(97,101) Traceback (most recent call last): ... RuntimeError: requested Conway polynomial not in database. """ (p, n) = (int(p), int(n)) R = FiniteField(p)['x'] try: return R(sage.databases.conway.ConwayPolynomials()[p][n]) except KeyError: raise RuntimeError("requested Conway polynomial not in database.")
def _subfield(self, n): """ Return the unique subfield of degree `n` of ``self``. EXAMPLES:: sage: F = GF(3).algebraic_closure() sage: F._subfield(4) Finite Field in z4 of size 3^4 """ if n == 1: return self.base_ring() else: from sage.rings.finite_rings.finite_field_constructor import FiniteField return FiniteField(self.base_ring().cardinality()**n, name=self.variable_name() + str(n), modulus=self._get_polynomial(n), check_irreducible=False)
def generate_wp_candidates(self, p, ideal_p, **kwargs): eps = self.eps q = self.q for a, b in product(range(q), repeat=2): if (p**2 * a**2 - b**2 * eps - p) % (q) == 0: verbose('Found a=%s, b=%s' % (a, b)) break c = (self.GFq(p)**-1 * b * eps).lift() d = a a, b, c, d = lift(matrix(ZZ, 2, 2, [p * a, b, c, d]), q).list() Fp = FiniteField(p) if c % p == 0: c += a * q d += b * q assert c % p != 0 r = (Fp(-a) * Fp(c * q)**-1).lift() a += q * c * r b += q * d * r ans = matrix(ZZ, 2, 2, [a, b, p * c, p * d]) ans.set_immutable() yield ans
def __init__(self, field=None): """ Create a shrinking generator cryptosystem. INPUT: A string monoid over a binary alphabet. OUTPUT: EXAMPLES:: sage: E = ShrinkingGeneratorCryptosystem() sage: E Shrinking generator cryptosystem over Finite Field of size 2 """ if field is None: field = FiniteField(2) if field.cardinality() != 2: raise NotImplementedError("Not yet implemented.") S = BinaryStrings() SymmetricKeyCryptosystem.__init__(self, S, S, None) self._field = field
def polynomial(self, name=None): """ Returns the polynomial ``name``. EXAMPLES:: sage: k.<a> = GF(3) sage: k.polynomial() x """ if name is None: name = self.variable_name() try: return self.__polynomial[name] except AttributeError: from sage.rings.finite_rings.finite_field_constructor import FiniteField R = FiniteField(self.characteristic())[name] f = self[name]([0, 1]) try: self.__polynomial[name] = f except (KeyError, AttributeError): self.__polynomial = {} self.__polynomial[name] = f return f
def normalize_args_vectorspace(*args, **kwds): """ Normalize the arguments that relate to a vector space. INPUT: Something that defines an affine space. For example * An affine space itself: - ``A`` -- affine space * A vector space: - ``V`` -- a vector space * Degree and base ring: - ``degree`` -- integer. The degree of the affine group, that is, the dimension of the affine space the group is acting on. - ``ring`` -- a ring or an integer. The base ring of the affine space. If an integer is given, it must be a prime power and the corresponding finite field is constructed. - ``var='a'`` -- optional keyword argument to specify the finite field generator name in the case where ``ring`` is a prime power. OUTPUT: A pair ``(degree, ring)``. TESTS:: sage: from sage.groups.matrix_gps.named_group import normalize_args_vectorspace sage: A = AffineSpace(2, GF(4,'a')); A Affine Space of dimension 2 over Finite Field in a of size 2^2 sage: normalize_args_vectorspace(A) (2, Finite Field in a of size 2^2) sage: normalize_args_vectorspace(2,4) # shorthand (2, Finite Field in a of size 2^2) sage: V = ZZ^3; V Ambient free module of rank 3 over the principal ideal domain Integer Ring sage: normalize_args_vectorspace(V) (3, Integer Ring) sage: normalize_args_vectorspace(2, QQ) (2, Rational Field) """ from sage.rings.all import ZZ if len(args) == 1: V = args[0] try: degree = V.dimension_relative() except AttributeError: degree = V.dimension() ring = V.base_ring() if len(args) == 2: degree, ring = args try: ring = ZZ(ring) from sage.rings.finite_rings.finite_field_constructor import FiniteField var = kwds.get('var', 'a') ring = FiniteField(ring, var) except (ValueError, TypeError): pass return (ZZ(degree), ring)
def HughesPlane(q2, check=True): r""" Return the Hughes projective plane of order ``q2``. Let `q` be an odd prime, the Hughes plane of order `q^2` is a finite projective plane of order `q^2` introduced by D. Hughes in [Hu57]_. Its construction is as follows. Let `K = GF(q^2)` be a finite field with `q^2` elements and `F = GF(q) \subset K` be its unique subfield with `q` elements. We define a twisted multiplication on `K` as .. MATH:: x \circ y = \begin{cases} x\ y & \text{if y is a square in K}\\ x^q\ y & \text{otherwise} \end{cases} The points of the Hughes plane are the triples `(x, y, z)` of points in `K^3 \backslash \{0,0,0\}` up to the equivalence relation `(x,y,z) \sim (x \circ k, y \circ k, z \circ k)` where `k \in K`. For `a = 1` or `a \in (K \backslash F)` we define a block `L(a)` as the set of triples `(x,y,z)` so that `x + a \circ y + z = 0`. The rest of the blocks are obtained by letting act the group `GL(3, F)` by its standard action. For more information, see :wikipedia:`Hughes_plane` and [We07]. .. SEEALSO:: :func:`DesarguesianProjectivePlaneDesign` to build the Desarguesian projective planes INPUT: - ``q2`` -- an even power of an odd prime number - ``check`` -- (boolean) Whether to check that output is correct before returning it. As this is expected to be useless (but we are cautious guys), you may want to disable it whenever you want speed. Set to ``True`` by default. EXAMPLES:: sage: H = designs.HughesPlane(9) sage: H (91,10,1)-Balanced Incomplete Block Design We prove in the following computations that the Desarguesian plane ``H`` is not Desarguesian. Let us consider the two triangles `(0,1,10)` and `(57, 70, 59)`. We show that the intersection points `D_{0,1} \cap D_{57,70}`, `D_{1,10} \cap D_{70,59}` and `D_{10,0} \cap D_{59,57}` are on the same line while `D_{0,70}`, `D_{1,59}` and `D_{10,57}` are not concurrent:: sage: blocks = H.blocks() sage: line = lambda p,q: next(b for b in blocks if p in b and q in b) sage: b_0_1 = line(0, 1) sage: b_1_10 = line(1, 10) sage: b_10_0 = line(10, 0) sage: b_57_70 = line(57, 70) sage: b_70_59 = line(70, 59) sage: b_59_57 = line(59, 57) sage: set(b_0_1).intersection(b_57_70) {2} sage: set(b_1_10).intersection(b_70_59) {73} sage: set(b_10_0).intersection(b_59_57) {60} sage: line(2, 73) == line(73, 60) True sage: b_0_57 = line(0, 57) sage: b_1_70 = line(1, 70) sage: b_10_59 = line(10, 59) sage: p = set(b_0_57).intersection(b_1_70) sage: q = set(b_1_70).intersection(b_10_59) sage: p == q False TESTS: Some wrong input:: sage: designs.HughesPlane(5) Traceback (most recent call last): ... EmptySetError: No Hughes plane of non-square order exists. sage: designs.HughesPlane(16) Traceback (most recent call last): ... EmptySetError: No Hughes plane of even order exists. Check that it works for non-prime `q`:: sage: designs.HughesPlane(3**4) # not tested - 10 secs (6643,82,1)-Balanced Incomplete Block Design """ if not q2.is_square(): raise EmptySetError("No Hughes plane of non-square order exists.") if q2 % 2 == 0: raise EmptySetError("No Hughes plane of even order exists.") q = q2.sqrt() K = FiniteField(q2, prefix='x') F = FiniteField(q, prefix='y') A = q3_minus_one_matrix(F) A = A.change_ring(K) m = K.list() V = VectorSpace(K, 3) zero = K.zero() one = K.one() points = [(x, y, one) for x in m for y in m] + \ [(x, one, zero) for x in m] + \ [(one, zero, zero)] relabel = {tuple(p): i for i, p in enumerate(points)} blcks = [] for a in m: if a not in F or a == 1: # build L(a) aa = ~a l = [] l.append(V((-a, one, zero))) for x in m: y = -aa * (x + one) if not y.is_square(): y *= aa**(q - 1) l.append(V((x, y, one))) # compute the orbit of L(a) blcks.append( [relabel[normalize_hughes_plane_point(p, q)] for p in l]) for i in range(q2 + q): l = [A * j for j in l] blcks.append( [relabel[normalize_hughes_plane_point(p, q)] for p in l]) from .bibd import BalancedIncompleteBlockDesign return BalancedIncompleteBlockDesign(q2**2 + q2 + 1, blcks, check=check)
def DesarguesianProjectivePlaneDesign(n, point_coordinates=True, check=True): r""" Return the Desarguesian projective plane of order ``n`` as a 2-design. The Desarguesian projective plane of order `n` can also be defined as the projective plane over a field of order `n`. For more information, have a look at :wikipedia:`Projective_plane`. INPUT: - ``n`` -- an integer which must be a power of a prime number - ``point_coordinates`` (boolean) -- whether to label the points with their homogeneous coordinates (default) or with integers. - ``check`` -- (boolean) Whether to check that output is correct before returning it. As this is expected to be useless (but we are cautious guys), you may want to disable it whenever you want speed. Set to ``True`` by default. .. SEEALSO:: :func:`ProjectiveGeometryDesign` EXAMPLES:: sage: designs.DesarguesianProjectivePlaneDesign(2) (7,3,1)-Balanced Incomplete Block Design sage: designs.DesarguesianProjectivePlaneDesign(3) (13,4,1)-Balanced Incomplete Block Design sage: designs.DesarguesianProjectivePlaneDesign(4) (21,5,1)-Balanced Incomplete Block Design sage: designs.DesarguesianProjectivePlaneDesign(5) (31,6,1)-Balanced Incomplete Block Design sage: designs.DesarguesianProjectivePlaneDesign(6) Traceback (most recent call last): ... ValueError: the order of a finite field must be a prime power """ K = FiniteField(n, 'a') n2 = n**2 relabel = {x: i for i, x in enumerate(K)} Kiter = relabel # it is much faster to iterate through a dict than through # the finite field K # we decompose the (equivalence class) of points [x:y:z] of the projective # plane into an affine plane, an affine line and a point. At the same time, # we relabel the points with the integers from 0 to n^2 + n as follows: # - the affine plane is the set of points [x:y:1] (i.e. the third coordinate # is non-zero) and gets relabeled from 0 to n^2-1 affine_plane = lambda x, y: relabel[x] + n * relabel[y] # - the affine line is the set of points [x:1:0] (i.e. the third coordinate is # zero but not the second one) and gets relabeled from n^2 to n^2 + n - 1 line_infinity = lambda x: n2 + relabel[x] # - the point is [1:0:0] and gets relabeled n^2 + n point_infinity = n2 + n blcks = [] # the n^2 lines of the form "x = sy + az" for s in Kiter: for a in Kiter: # points in the affine plane blcks.append([affine_plane(s * y + a, y) for y in Kiter]) # point at infinity blcks[-1].append(line_infinity(s)) # the n horizontals of the form "y = az" for a in Kiter: # points in the affine plane blcks.append([affine_plane(x, a) for x in Kiter]) # point at infinity blcks[-1].append(point_infinity) # the line at infinity "z = 0" blcks.append(range(n2, n2 + n + 1)) if check: from .designs_pyx import is_projective_plane if not is_projective_plane(blcks): raise RuntimeError( 'There is a problem in the function DesarguesianProjectivePlane' ) from .bibd import BalancedIncompleteBlockDesign B = BalancedIncompleteBlockDesign(n2 + n + 1, blcks, check=check) if point_coordinates: zero = K.zero() one = K.one() d = {affine_plane(x, y): (x, y, one) for x in Kiter for y in Kiter} d.update({line_infinity(x): (x, one, zero) for x in Kiter}) d[n2 + n] = (one, zero, zero) B.relabel(d) return B
def self_orthogonal_binary_codes(n, k, b=2, parent=None, BC=None, equal=False, in_test=None): """ Returns a Python iterator which generates a complete set of representatives of all permutation equivalence classes of self-orthogonal binary linear codes of length in ``[1..n]`` and dimension in ``[1..k]``. INPUT: - ``n`` - Integer, maximal length - ``k`` - Integer, maximal dimension - ``b`` - Integer, requires that the generators all have weight divisible by ``b`` (if ``b=2``, all self-orthogonal codes are generated, and if ``b=4``, all doubly even codes are generated). Must be an even positive integer. - ``parent`` - Used in recursion (default: ``None``) - ``BC`` - Used in recursion (default: ``None``) - ``equal`` - If ``True`` generates only [n, k] codes (default: ``False``) - ``in_test`` - Used in recursion (default: ``None``) EXAMPLES: Generate all self-orthogonal codes of length up to 7 and dimension up to 3:: sage: for B in codes.databases.self_orthogonal_binary_codes(7,3): ....: print(B) [2, 1] linear code over GF(2) [4, 2] linear code over GF(2) [6, 3] linear code over GF(2) [4, 1] linear code over GF(2) [6, 2] linear code over GF(2) [6, 2] linear code over GF(2) [7, 3] linear code over GF(2) [6, 1] linear code over GF(2) Generate all doubly-even codes of length up to 7 and dimension up to 3:: sage: for B in codes.databases.self_orthogonal_binary_codes(7,3,4): ....: print(B); print(B.generator_matrix()) [4, 1] linear code over GF(2) [1 1 1 1] [6, 2] linear code over GF(2) [1 1 1 1 0 0] [0 1 0 1 1 1] [7, 3] linear code over GF(2) [1 0 1 1 0 1 0] [0 1 0 1 1 1 0] [0 0 1 0 1 1 1] Generate all doubly-even codes of length up to 7 and dimension up to 2:: sage: for B in codes.databases.self_orthogonal_binary_codes(7,2,4): ....: print(B); print(B.generator_matrix()) [4, 1] linear code over GF(2) [1 1 1 1] [6, 2] linear code over GF(2) [1 1 1 1 0 0] [0 1 0 1 1 1] Generate all self-orthogonal codes of length equal to 8 and dimension equal to 4:: sage: for B in codes.databases.self_orthogonal_binary_codes(8, 4, equal=True): ....: print(B); print(B.generator_matrix()) [8, 4] linear code over GF(2) [1 0 0 1 0 0 0 0] [0 1 0 0 1 0 0 0] [0 0 1 0 0 1 0 0] [0 0 0 0 0 0 1 1] [8, 4] linear code over GF(2) [1 0 0 1 1 0 1 0] [0 1 0 1 1 1 0 0] [0 0 1 0 1 1 1 0] [0 0 0 1 0 1 1 1] Since all the codes will be self-orthogonal, b must be divisible by 2:: sage: list(codes.databases.self_orthogonal_binary_codes(8, 4, 1, equal=True)) Traceback (most recent call last): ... ValueError: b (1) must be a positive even integer. """ from sage.rings.finite_rings.finite_field_constructor import FiniteField from sage.matrix.constructor import Matrix d = int(b) if d != b or d % 2 == 1 or d <= 0: raise ValueError("b (%s) must be a positive even integer." % b) from .linear_code import LinearCode from .binary_code import BinaryCode, BinaryCodeClassifier if k < 1 or n < 2: return if equal: in_test = lambda M: (M.ncols() - M.nrows()) <= (n - k) out_test = lambda C: (C.dimension() == k) and (C.length() == n) else: in_test = lambda M: True out_test = lambda C: True if BC is None: BC = BinaryCodeClassifier() if parent is None: for j in range(d, n + 1, d): M = Matrix(FiniteField(2), [[1] * j]) if in_test(M): for N in self_orthogonal_binary_codes(n, k, d, M, BC, in_test=in_test): if out_test(N): yield N else: C = LinearCode(parent) if out_test(C): yield C if k == parent.nrows(): return for nn in range(parent.ncols() + 1, n + 1): if in_test(parent): for child in BC.generate_children(BinaryCode(parent), nn, d): for N in self_orthogonal_binary_codes(n, k, d, child, BC, in_test=in_test): if out_test(N): yield N
def __init__(self, q, level, info_magma=None, grouptype=None, magma=None, compute_presentation=True): from sage.modular.arithgroup.congroup_gamma import Gamma_constructor assert grouptype in ['SL2', 'PSL2'] self._grouptype = grouptype self._compute_presentation = compute_presentation self.magma = magma self.F = QQ self.q = ZZ(q) self.discriminant = ZZ(1) self.level = ZZ(level / self.q) if self.level != 1 and compute_presentation: raise NotImplementedError self._Gamma = Gamma_constructor(self.q) self._Gamma_farey = self._Gamma.farey_symbol() self.F_units = [] self._prec_inf = -1 self.B = MatrixSpace(QQ, 2, 2) # Here we initialize the non-split Cartan, properly self.GFq = FiniteField(self.q) if not self.GFq(-1).is_square(): self.eps = ZZ(-1) else: self.eps = ZZ(2) while self.GFq(self.eps).is_square(): self.eps += 1 epsinv = (self.GFq(self.eps)**-1).lift() N = self.level q = self.q self.Obasis = [ matrix(ZZ, 2, 2, v) for v in [[1, 0, 0, 1], [0, q, 0, 0], [0, N * epsinv, N, 0], [0, 0, 0, q]] ] x = QQ['x'].gen() K = FiniteField(self.q**2, 'z', modulus=x * x - self.eps) x = K.primitive_element() x1 = x while x1.multiplicative_order() != self.q + 1 or x1.norm() != 1: x1 *= x a, b = x1.polynomial().list() # represents a+b*sqrt(eps) a = a.lift() b = b.lift() self.extra_matrix = self.B( lift(matrix(ZZ, 2, 2, [a, b, b * self.eps, a]), self.q)) self.extra_matrix_inverse = ~self.extra_matrix if compute_presentation: self.Ugens = [] self._gens = [] temp_relation_words = [] I = SL2Z([1, 0, 0, 1]) E = SL2Z([-1, 0, 0, -1]) minus_one = [] for i, g in enumerate(self._Gamma_farey.generators()): newg = self.B([g.a(), g.b(), g.c(), g.d()]) if newg == I: continue self.Ugens.append(newg) self._gens.append( self.element_class(self, quaternion_rep=newg, word_rep=[i + 1], check=False)) if g.matrix()**2 == I.matrix(): temp_relation_words.append([i + 1, i + 1]) if minus_one is not None: temp_relation_words.append([-i - 1] + minus_one) else: minus_one = [i + 1] elif g.matrix()**2 == E.matrix(): temp_relation_words.append([i + 1, i + 1, i + 1, i + 1]) if minus_one is not None: temp_relation_words.append([-i - 1, -i - 1] + minus_one) else: minus_one = [i + 1, i + 1] elif g.matrix()**3 == I.matrix(): temp_relation_words.append([i + 1, i + 1, i + 1]) elif g.matrix()**3 == E.matrix(): temp_relation_words.append( [i + 1, i + 1, i + 1, i + 1, i + 1, i + 1]) if minus_one is not None: temp_relation_words.append([-i - 1, -i - 1, -i - 1] + minus_one) else: minus_one = [i + 1, i + 1, i + 1] else: assert g.matrix()**24 != I.matrix() # The extra matrix is added i = len(self.Ugens) self.extra_matrix_index = i self.Ugens.append(self.extra_matrix) self._gens.append( self.element_class(self, quaternion_rep=self.Ugens[i], word_rep=[i + 1], check=False)) # The new relations are also added w = self._get_word_rep_initial(self.extra_matrix**(self.q + 1)) temp_relation_words.append(w + ([-i - 1] * (self.q + 1))) for j, g in enumerate(self.Ugens[:-1]): g1 = self.extra_matrix_inverse * g * self.extra_matrix w = self._get_word_rep_initial(g1) new_rel = w + [-i - 1, -j - 1, i + 1] temp_relation_words.append(new_rel) self.F_unit_offset = len(self.Ugens) if minus_one is not None: self.minus_one_long = syllables_to_tietze(minus_one) self._relation_words = [] for rel in temp_relation_words: sign = multiply_out(rel, self.Ugens, self.B(1)) if sign == self.B(1) or 'P' in grouptype: self._relation_words.append(rel) else: assert sign == self.B(-1) newrel = rel + self.minus_one sign = multiply_out(newrel, self.Ugens, self.B(1)) assert sign == self.B(1) self._relation_words.append(newrel) ArithGroup_generic.__init__(self) Parent.__init__(self)
def QuaternionMatrixGroupGF3(): r""" The quaternion group as a set of `2\times 2` matrices over `GF(3)`. OUTPUT: A matrix group consisting of `2\times 2` matrices with elements from the finite field of order 3. The group is the quaternion group, the nonabelian group of order 8 that is not isomorphic to the group of symmetries of a square (the dihedral group `D_4`). .. note:: This group is most easily available via ``groups.matrix.QuaternionGF3()``. EXAMPLES: The generators are the matrix representations of the elements commonly called `I` and `J`, while `K` is the product of `I` and `J`. :: sage: from sage.groups.matrix_gps.finitely_generated import QuaternionMatrixGroupGF3 sage: Q = QuaternionMatrixGroupGF3() sage: Q.order() 8 sage: aye = Q.gens()[0]; aye [1 1] [1 2] sage: jay = Q.gens()[1]; jay [2 1] [1 1] sage: kay = aye*jay; kay [0 2] [1 0] TESTS:: sage: groups.matrix.QuaternionGF3() Matrix group over Finite Field of size 3 with 2 generators ( [1 1] [2 1] [1 2], [1 1] ) sage: Q = QuaternionMatrixGroupGF3() sage: QP = Q.as_permutation_group() sage: QP.is_isomorphic(QuaternionGroup()) True sage: H = DihedralGroup(4) sage: H.order() 8 sage: QP.is_abelian(), H.is_abelian() (False, False) sage: QP.is_isomorphic(H) False """ from sage.rings.finite_rings.finite_field_constructor import FiniteField from sage.matrix.matrix_space import MatrixSpace MS = MatrixSpace(FiniteField(3), 2) aye = MS([1, 1, 1, 2]) jay = MS([2, 1, 1, 1]) return MatrixGroup([aye, jay])
def hadamard_matrix_paleyI(n, normalize=True): """ Implements the Paley type I construction. The Paley type I case corresponds to the case `p \cong 3 \mod{4}` for a prime `p` (see [Hora]_). INPUT: - ``n`` -- the matrix size - ``normalize`` (boolean) -- whether to normalize the result. EXAMPLES: We note that this method by default returns a normalised Hadamard matrix :: sage: from sage.combinat.matrices.hadamard_matrix import hadamard_matrix_paleyI sage: hadamard_matrix_paleyI(4) [ 1 1 1 1] [ 1 -1 1 -1] [ 1 -1 -1 1] [ 1 1 -1 -1] Otherwise, it returns a skew Hadamard matrix `H`, i.e. `H=S+I`, with `S=-S^\top` :: sage: M=hadamard_matrix_paleyI(4, normalize=False); M [ 1 1 1 1] [-1 1 1 -1] [-1 -1 1 1] [-1 1 -1 1] sage: S=M-identity_matrix(4); -S==S.T True TESTS:: sage: from sage.combinat.matrices.hadamard_matrix import is_hadamard_matrix sage: test_cases = [x+1 for x in range(100) if is_prime_power(x) and x%4==3] sage: all(is_hadamard_matrix(hadamard_matrix_paleyI(n),normalized=True,verbose=True) ....: for n in test_cases) True sage: all(is_hadamard_matrix(hadamard_matrix_paleyI(n,normalize=False),verbose=True) ....: for n in test_cases) True """ p = n - 1 if not (is_prime_power(p) and (p % 4 == 3)): raise ValueError( "The order %s is not covered by the Paley type I construction." % n) from sage.rings.finite_rings.finite_field_constructor import FiniteField K = FiniteField(p, 'x') K_list = list(K) K_list.insert(0, K.zero()) H = matrix(ZZ, [[(1 if (x - y).is_square() else -1) for x in K_list] for y in K_list]) for i in range(n): H[i, 0] = -1 H[0, i] = 1 if normalize: for i in range(n): H[i, i] = -1 H = normalise_hadamard(H) return H
def polynomial(self, n): r""" Return the pseudo-Conway polynomial of degree `n` in this lattice. INPUT: - ``n`` -- positive integer OUTPUT: - a pseudo-Conway polynomial of degree `n` for the prime `p`. ALGORITHM: Uses an algorithm described in [HL1999]_, modified to find pseudo-Conway polynomials rather than Conway polynomials. The major difference is that we stop as soon as we find a primitive polynomial. EXAMPLES:: sage: from sage.rings.finite_rings.conway_polynomials import PseudoConwayLattice sage: PCL = PseudoConwayLattice(2, use_database=False) sage: PCL.polynomial(3) x^3 + x + 1 sage: PCL.polynomial(4) x^4 + x^3 + 1 sage: PCL.polynomial(60) x^60 + x^59 + x^58 + x^55 + x^54 + x^53 + x^52 + x^51 + x^48 + x^46 + x^45 + x^42 + x^41 + x^39 + x^38 + x^37 + x^35 + x^32 + x^31 + x^30 + x^28 + x^24 + x^22 + x^21 + x^18 + x^17 + x^16 + x^15 + x^14 + x^10 + x^8 + x^7 + x^5 + x^3 + x^2 + x + 1 """ if n in self.nodes: return self.nodes[n] p = self.p n = Integer(n) if n == 1: f = self.ring.gen() - FiniteField(p).multiplicative_generator() self.nodes[1] = f return f # Work in an arbitrary field K of order p**n. K = FiniteField(p**n, names='a') # TODO: something like the following # gcds = [n.gcd(d) for d in self.nodes.keys()] # xi = { m: (...) for m in gcds } xi = { q: self.polynomial(n // q).any_root(K, -n // q, assume_squarefree=True) for q in n.prime_divisors() } # The following is needed to ensure that in the concrete instantiation # of the "new" extension all previous choices are compatible. _frobenius_shift(K, xi) # Construct a compatible element having order the lcm of orders q, x = xi.popitem() v = p**(n // q) - 1 for q, xitem in xi.items(): w = p**(n // q) - 1 g, alpha, beta = v.xgcd(w) x = x**beta * xitem**alpha v = v.lcm(w) r = p**n - 1 # Get the missing part of the order to be primitive g = r // v # Iterate through g-th roots of x until a primitive one is found z = x.nth_root(g) root = K.multiplicative_generator()**v while z.multiplicative_order() != r: z *= root # The following should work but tries to create a huge list # whose length overflows Python's ints for large parameters #Z = x.nth_root(g, all=True) #for z in Z: # if z.multiplicative_order() == r: # break f = z.minimal_polynomial() self.nodes[n] = f return f
def _helper_payley_matrix(n, zero_position=True): r""" Return the matrix constructed in Lemma 1.19 page 291 of [SWW72]_. This function return a `n^2` matrix `M` whose rows/columns are indexed by the element of a finite field on `n` elements `x_1,...,x_n`. The value `M_{i,j}` is equal to `\chi(x_i-x_j)`. The elements `x_1,...,x_n` are ordered in such a way that the matrix (respectively, its submatrix obtained by removing first row and first column in the case ``zero_position=False``) is symmetric with respect to its second diagonal. The matrix is symmetric if `n=4k+1`, and skew-symmetric otherwise. INPUT: - ``n`` -- an odd prime power. - ``zero_position`` -- if it is true (default), place 0 of ``F_n`` in the middle, otherwise place it first. .. SEEALSO:: :func:`rshcd_from_close_prime_powers` EXAMPLES:: sage: from sage.combinat.matrices.hadamard_matrix import _helper_payley_matrix sage: _helper_payley_matrix(5) [ 0 1 1 -1 -1] [ 1 0 -1 1 -1] [ 1 -1 0 -1 1] [-1 1 -1 0 1] [-1 -1 1 1 0] TESTS:: sage: _helper_payley_matrix(11,zero_position=True) [ 0 -1 1 -1 -1 1 -1 1 1 1 -1] [ 1 0 -1 1 -1 -1 -1 -1 1 1 1] [-1 1 0 -1 1 1 -1 -1 -1 1 1] [ 1 -1 1 0 -1 1 1 -1 -1 -1 1] [ 1 1 -1 1 0 1 -1 1 -1 -1 -1] [-1 1 -1 -1 -1 0 1 1 1 -1 1] [ 1 1 1 -1 1 -1 0 -1 1 -1 -1] [-1 1 1 1 -1 -1 1 0 -1 1 -1] [-1 -1 1 1 1 -1 -1 1 0 -1 1] [-1 -1 -1 1 1 1 1 -1 1 0 -1] [ 1 -1 -1 -1 1 -1 1 1 -1 1 0] sage: _helper_payley_matrix(11,zero_position=False) [ 0 -1 1 -1 -1 -1 1 1 1 -1 1] [ 1 0 -1 1 -1 -1 -1 1 1 1 -1] [-1 1 0 -1 1 -1 -1 -1 1 1 1] [ 1 -1 1 0 -1 1 -1 -1 -1 1 1] [ 1 1 -1 1 0 -1 1 -1 -1 -1 1] [ 1 1 1 -1 1 0 -1 1 -1 -1 -1] [-1 1 1 1 -1 1 0 -1 1 -1 -1] [-1 -1 1 1 1 -1 1 0 -1 1 -1] [-1 -1 -1 1 1 1 -1 1 0 -1 1] [ 1 -1 -1 -1 1 1 1 -1 1 0 -1] [-1 1 -1 -1 -1 1 1 1 -1 1 0] """ from sage.rings.finite_rings.finite_field_constructor import FiniteField K = FiniteField(n, prefix='x') # Order the elements of K in K_list # so that K_list[i] = -K_list[n - i - 1] K_pairs = set(tuple(sorted([x, -x])) for x in K if x) K_list = [K.zero()] * n shift = 0 if zero_position else 1 for i, (x, y) in enumerate(sorted(K_pairs)): K_list[i + shift] = x K_list[-i - 1] = y M = matrix(ZZ, n, n, [(1 if (x - y).is_square() else -1) for x in K_list for y in K_list]) M -= I(n) assert (M * J(n)).is_zero() assert M * M.transpose() == n * I(n) - J(n) return M
def difference_matrix(g, k, lmbda=1, existence=False, check=True): r""" Return a `(g,k,\lambda)`-difference matrix A matrix `M` is a `(g,k,\lambda)`-difference matrix if it has size `\lambda g\times k`, its entries belong to the group `G` of cardinality `g`, and for any two rows `R,R'` of `M` and `x\in G` there are exactly `\lambda` values `i` such that `R_i-R'_i=x`. INPUT: - ``k`` -- (integer) number of columns. If ``k=None`` it is set to the largest value available. - ``g`` -- (integer) cardinality of the group `G` - ``lmbda`` -- (integer; default: 1) -- number of times each element of `G` appears as a difference. - ``check`` -- (boolean) Whether to check that output is correct before returning it. As this is expected to be useless (but we are cautious guys), you may want to disable it whenever you want speed. Set to ``True`` by default. - ``existence`` (boolean) -- instead of building the design, return: - ``True`` -- meaning that Sage knows how to build the design - ``Unknown`` -- meaning that Sage does not know how to build the design, but that the design may exist (see :mod:`sage.misc.unknown`). - ``False`` -- meaning that the design does not exist. .. NOTE:: When ``k=None`` and ``existence=True`` the function returns an integer, i.e. the largest `k` such that we can build a `(g,k,\lambda)`-DM. EXAMPLES:: sage: G,M = designs.difference_matrix(25,10); G Finite Field in x of size 5^2 sage: designs.difference_matrix(993,None,existence=1) 32 Here we print for each `g` the maximum possible `k` for which Sage knows how to build a `(g,k,1)`-difference matrix:: sage: for g in range(2,30): ....: k_max = designs.difference_matrix(g=g,k=None,existence=True) ....: print("{:2} {}".format(g, k_max)) ....: _ = designs.difference_matrix(g,k_max) 2 2 3 3 4 4 5 5 6 2 7 7 8 8 9 9 10 2 11 11 12 6 13 13 14 2 15 3 16 16 17 17 18 2 19 19 20 4 21 6 22 2 23 23 24 8 25 25 26 2 27 27 28 6 29 29 TESTS:: sage: designs.difference_matrix(10,12,1,existence=True) False sage: designs.difference_matrix(10,12,1) Traceback (most recent call last): ... EmptySetError: No (10,12,1)-Difference Matrix exists as k(=12)>g(=10) sage: designs.difference_matrix(10,9,1,existence=True) Unknown sage: designs.difference_matrix(10,9,1) Traceback (most recent call last): ... NotImplementedError: I don't know how to build a (10,9,1)-Difference Matrix! """ if lmbda == 1 and k is not None and k > g: if existence: return False raise EmptySetError( "No ({},{},{})-Difference Matrix exists as k(={})>g(={})".format( g, k, lmbda, k, g)) # Prime powers elif lmbda == 1 and is_prime_power(g): if k is None: if existence: return g else: k = g elif existence: return True F = FiniteField(g, 'x') F_set = list(F) F_k_set = F_set[:k] G = F M = [[x * y for y in F_k_set] for x in F_set] # Treat the case k=None # (find the max k such that there exists a DM) elif k is None: i = 2 while difference_matrix(g=g, k=i, lmbda=lmbda, existence=True): i += 1 return i - 1 # From the database elif (g, lmbda) in DM_constructions and DM_constructions[g, lmbda][0] >= k: if existence: return True _, f = DM_constructions[g, lmbda] G, M = f() M = [R[:k] for R in M] # Product construction elif find_product_decomposition(g, k, lmbda): if existence: return True (g1, lmbda1), (g2, lmbda2) = find_product_decomposition(g, k, lmbda) G1, M1 = difference_matrix(g1, k, lmbda1) G2, M2 = difference_matrix(g2, k, lmbda2) G, M = difference_matrix_product(k, M1, G1, lmbda1, M2, G2, lmbda2, check=False) else: if existence: return Unknown raise NotImplementedError( "I don't know how to build a ({},{},{})-Difference Matrix!".format( g, k, lmbda)) if check and not is_difference_matrix(M, G, k, lmbda, 1): raise RuntimeError( "Sage built something which is not a ({},{},{})-DM!".format( g, k, lmbda)) return G, M
def hadamard_matrix_paleyII(n): """ Implements the Paley type II construction. The Paley type II case corresponds to the case `p \cong 1 \mod{4}` for a prime `p` (see [Hora]_). EXAMPLES:: sage: sage.combinat.matrices.hadamard_matrix.hadamard_matrix_paleyII(12).det() 2985984 sage: 12^6 2985984 We note that the method returns a normalised Hadamard matrix :: sage: sage.combinat.matrices.hadamard_matrix.hadamard_matrix_paleyII(12) [ 1 1| 1 1| 1 1| 1 1| 1 1| 1 1] [ 1 -1|-1 1|-1 1|-1 1|-1 1|-1 1] [-----+-----+-----+-----+-----+-----] [ 1 -1| 1 -1| 1 1|-1 -1|-1 -1| 1 1] [ 1 1|-1 -1| 1 -1|-1 1|-1 1| 1 -1] [-----+-----+-----+-----+-----+-----] [ 1 -1| 1 1| 1 -1| 1 1|-1 -1|-1 -1] [ 1 1| 1 -1|-1 -1| 1 -1|-1 1|-1 1] [-----+-----+-----+-----+-----+-----] [ 1 -1|-1 -1| 1 1| 1 -1| 1 1|-1 -1] [ 1 1|-1 1| 1 -1|-1 -1| 1 -1|-1 1] [-----+-----+-----+-----+-----+-----] [ 1 -1|-1 -1|-1 -1| 1 1| 1 -1| 1 1] [ 1 1|-1 1|-1 1| 1 -1|-1 -1| 1 -1] [-----+-----+-----+-----+-----+-----] [ 1 -1| 1 1|-1 -1|-1 -1| 1 1| 1 -1] [ 1 1| 1 -1|-1 1|-1 1| 1 -1|-1 -1] TESTS:: sage: from sage.combinat.matrices.hadamard_matrix import (hadamard_matrix_paleyII, is_hadamard_matrix) sage: test_cases = [2*(x+1) for x in range(50) if is_prime_power(x) and x%4==1] sage: all(is_hadamard_matrix(hadamard_matrix_paleyII(n),normalized=True,verbose=True) ....: for n in test_cases) True """ q = n // 2 - 1 if not (n % 2 == 0 and is_prime_power(q) and (q % 4 == 1)): raise ValueError( "The order %s is not covered by the Paley type II construction." % n) from sage.rings.finite_rings.finite_field_constructor import FiniteField K = FiniteField(q, 'x') K_list = list(K) K_list.insert(0, K.zero()) H = matrix(ZZ, [[(1 if (x - y).is_square() else -1) for x in K_list] for y in K_list]) for i in range(q + 1): H[0, i] = 1 H[i, 0] = 1 H[i, i] = 0 tr = { 0: matrix(2, 2, [1, -1, -1, -1]), 1: matrix(2, 2, [1, 1, 1, -1]), -1: matrix(2, 2, [-1, -1, -1, 1]) } H = block_matrix(q + 1, q + 1, [tr[v] for r in H for v in r]) return normalise_hadamard(H)
def __init__(self, resolution, module, filename=":memory:", tempdb=False, debug=False): import os if os.getenv("YACOP_FORCE_PRIVATE_CACHE") == "Y": # used for parallel doctesting to avoid conflicts # between doctest processes filename = filename.replace("cache=shared", "cache=private") self.reference_resolution = resolution resolution = resolution._worker if not isinstance(resolution, GFR): raise ValueError("first argument is not a resolution") self._resolution = resolution self._viewtype = resolution._viewtype self._module = module self._filename = filename self._tempdb = tempdb self._prime = self._resolution._prime self._gf = FiniteField(self._prime) self._errorhandler = None self.tcl = Yacop.Interpreter() modbbox = module.bbox() self._msmin = modbbox.smin self._mtmin = modbbox.tmin self._memin = modbbox.emin if self._msmin is -Infinity: raise ValueError("module not bounded from below: smin=%s" % self._msmin) if self._mtmin is -Infinity: raise ValueError("module not bounded from below: tmin=%s" % self._mtmin) if self._memin is -Infinity: raise ValueError("module not bounded from below: emin=%s" % self._memin) if self._viewtype == "even": self._tfactor = 2 else: self._tfactor = 1 # link the resolution into our Tcl interpreter self._resip = resolution.tcl.eval("namespace current") self.tcl.createcommand("sagemod", self._tclmodule) self.tcl.createcommand("errorCallback", self._errorcallback) spolyfunc = "sagepoly_%s" % resolution._viewtype self.tcl.eval(""" yacop::smashres create smashprod {%s::resolution} {%s} [namespace current]::sagemod [namespace current]::errorCallback {%s} smashprod setDebug %s proc smashprod_fragment_iterator query { yield "start" set q [subst { select pydict('s',sg.sdeg,'i',sg.ideg,'e',sg.edeg, 'srcrgen',sg.resgen, 'srcmod', m.sagename, 'data', %s(%d,group_concat(frag_decode(f.format, f.data), ' ')), 'tarmod', tm.sagename, 'tarrgen', tg.resgen) as p from smash_generators sg join module_generators m on m.rowid = sg.modgen join smash_fragments f on f.srcgen = sg.rowid join smash_generators tg on tg.rowid = f.targen join module_generators tm on tm.rowid = tg.modgen $query group by f.srcgen, f.targen order by sg.ideg-sg.sdeg, sg.edeg, sg.sdeg }] smashprod db eval $q { yield $p } } """ % ( self._resip, self._module, self._filename, debug, spolyfunc, resolution._prime, ))