Esempio n. 1
0
def is_supersingular(E):
    p = E.base_field().characteristic()
    j = E.j_invariant()
    if not j in GF(p**2):
        return False
    if p <= 3:
        return j == 0
    F = ClassicalModularPolynomialDatabase()[2]
    x = PolynomialRing(GF(p**2), 'x').gen()
    f = F(x, j)
    roots = [i[0] for i in f.roots() for _ in range(i[1])]
    if len(roots) < 3:
        return False
    vertices = [j, j, j]
    m = floor(log(p, 2)) + 1
    for k in range(1, m + 1):
        for i in range(3):
            f = F(x, roots[i])
            g = x - vertices[i]
            a = f.quo_rem(g)[0]
            vertices[i] = roots[i]
            attempt = a.roots()
            if len(attempt) == 0:
                return False
            roots[i] = attempt[0][0]
    return True
Esempio n. 2
0
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)
Esempio n. 3
0
def elkies_walk(E, l, lam, k):
    j_0 = E.j_invariant()
    if k == 0:
        return E
    lam = GF(l)(lam)
    q = E.base_field().order()
    mu = GF(l)(lam ** (-1) * q)
    if k < 0:
        return elkies_walk(E.quadratic_twist(), l, -mu, -k)
    j_1 = elkies_first_step(E, l, lam)
    for i in range(2, k + 1):
        j_0, j_1 = j_1, elkies_next_step(j_0, j_1, l, lam)
    return EllipticCurve_from_j(j_1)
Esempio n. 4
0
def walk_the_crater(E,l,lam):
    k = E.base_field()
    q = k.order()
    lam = GF(l)(lam)
    r = lam.multiplicative_order()
    t = E.trace_of_frobenius()
    order = rec_order(q, t, r)
    cur = extend_field(E, r)
    crater = [E.j_invariant()]
    cur = velu_step(cur, l, lam, order, q)
    while k(cur.j_invariant())!=E.j_invariant():
        crater.append(k(cur.j_invariant()))
        cur = velu_step(cur, l, lam, order, q)
    return crater
def orbits_lines_mod_p(self, p):
    r"""
    Let `(L, q)` be a lattice. This returns representatives of the
    orbits of lines in `L/pL` under the orthogonal group of `q`.

    INPUT:

    - ``p`` -- a prime number

    OUTPUT:

    - a list of vectors over ``GF(p)``

    EXAMPLES::

        sage: from sage.quadratic_forms.quadratic_form__neighbors import orbits_lines_mod_p
        sage: Q = QuadraticForm(ZZ, 3, [1, 0, 0, 2, 1, 3])
        sage: Q.orbits_lines_mod_p(2)
        [(0, 0, 1),
        (0, 1, 0),
        (0, 1, 1),
        (1, 0, 0),
        (1, 0, 1),
        (1, 1, 0),
        (1, 1, 1)]
    """
    from sage.libs.gap.libgap import libgap
    # careful the self.automorphism_group() acts from the left
    # but in gap we act from the right!! --> transpose
    gens = self.automorphism_group().gens()
    gens = [g.matrix().transpose().change_ring(GF(p)) for g in gens]
    orbs = libgap.function_factory(
    """function(gens, p)
        local one, G, reps, V, n, orb;
        one:= One(GF(p));
        G:=Group(List(gens, g -> g*one));
        n:= Size(gens[1]);
        V:= GF(p)^n;
        orb:= OrbitsDomain(G, V, OnLines);
        reps:= List(orb, g->g[1]);
        return reps;
        end;""")
    # run this at startup if you need more memory...
    #from sage.interfaces.gap import get_gap_memory_pool_size, set_gap_memory_pool_size
    #memory_gap = get_gap_memory_pool_size()
    #set_gap_memory_pool_size(1028*memory_gap)
    orbs_reps = orbs(gens, p)
    #set_gap_memory_pool_size(memory_gap)
    M = GF(p)**self.dim()
    return [M(m.sage()) for m in orbs_reps if not m.IsZero()]
Esempio n. 6
0
    def count_points(self, n):
        r"""
        Count points over
        `\GF{q}, \ldots, \GF{q^n}` on a scheme over
        a finite field `\GF{q}`.
        
        .. note::

           This is currently only implemented for schemes over prime
           order finite fields.
        
        EXAMPLES::
        
            sage: P.<x> = PolynomialRing(GF(3))
            sage: C = HyperellipticCurve(x^3+x^2+1)
            sage: C.count_points(4)
            [6, 12, 18, 96]
            sage: C.base_extend(GF(9,'a')).count_points(2)
            Traceback (most recent call last):
            ...
            NotImplementedError: Point counting only implemented for schemes over prime fields
        """

        F = self.base_ring()
        if not F.is_finite():
            raise TypeError, "Point counting only defined for schemes over finite fields"
        q = F.cardinality()
        if not q.is_prime():
            raise NotImplementedError, "Point counting only implemented for schemes over prime fields"
        a = []
        for i in range(1, n + 1):
            F1 = GF(q**i, name='z')
            S1 = self.base_extend(F1)
            a.append(len(S1.rational_points()))
        return (a)
Esempio n. 7
0
def _min_nonsquare(p):
    r"""
    Return the minimal nonsquare modulo the prime `p`.

    INPUT:

    - ``p`` -- a prime number

    OUTPUT:

    - ``a`` -- the minimal nonsquare mod `p`

    EXAMPLES::

        sage: from sage.quadratic_forms.genera.normal_form import _min_nonsquare
        sage: _min_nonsquare(2)
        sage: _min_nonsquare(3)
        2
        sage: _min_nonsquare(5)
        2
        sage: _min_nonsquare(7)
        3
    """
    R = GF(p)
    for i in R:
        if not R(i).is_square():
            return i
Esempio n. 8
0
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)
Esempio n. 9
0
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)
Esempio n. 10
0
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)
Esempio n. 11
0
def SU(n, F, var='a'):
    """
    Return the special unitary group of degree `n` over
    `F`.

    .. note::
        This group is also available via ``groups.matrix.SU()``.

    EXAMPLES::

        sage: SU(3,5)
        Special Unitary Group of degree 3 over Finite Field of size 5
        sage: SU(3,QQ)
        Traceback (most recent call last):
        ...
        NotImplementedError: special unitary group only implemented over finite fields

    TESTS::

        sage: groups.matrix.SU(2, 3)
        Special Unitary Group of degree 2 over Finite Field of size 3
    """
    if isinstance(F, (int, long, Integer)):
        F = GF(F, var)
    if is_FiniteField(F):
        return SpecialUnitaryGroup_finite_field(n, F, var=var)
    else:
        raise NotImplementedError, "special unitary group only implemented over finite fields"
Esempio n. 12
0
def _UG(n, R, special, var='a', invariant_form=None):
    r"""
    This function is commonly used by the functions :func:`GU` and :func:`SU`
    to avoid duplicated code. For documentation and examples
    see the individual functions.

    TESTS::

        sage: GU(3,25).order()  # indirect doctest
        3961191000000
    """
    prefix = 'General'
    latex_prefix = 'G'
    if special:
        prefix = 'Special'
        latex_prefix = 'S'

    degree, ring = normalize_args_vectorspace(n, R, var=var)
    if is_FiniteField(ring):
        q = ring.cardinality()
        ring = GF(q**2, name=var)
        if invariant_form is not None:
            raise NotImplementedError(
                "invariant_form for finite groups is fixed by GAP")

    if invariant_form is not None:
        invariant_form = normalize_args_invariant_form(ring, degree,
                                                       invariant_form)
        if not invariant_form.is_hermitian():
            raise ValueError("invariant_form must be hermitian")

        try:
            if invariant_form.is_positive_definite():
                inserted_text = "with respect to positive definite hermitian form"
            else:
                inserted_text = "with respect to non positive definite hermitian form"
        except ValueError:
            inserted_text = "with respect to hermitian form"

        name = '{0} Unitary Group of degree {1} over {2} {3}\n{4}'.format(
            prefix, degree, ring, inserted_text, invariant_form)
        ltx = r'\text{{{0}U}}_{{{1}}}({2})\text{{ {3} }}{4}'.format(
            latex_prefix, degree, latex(ring), inserted_text,
            latex(invariant_form))
    else:
        name = '{0} Unitary Group of degree {1} over {2}'.format(
            prefix, degree, ring)
        ltx = r'\text{{{0}U}}_{{{1}}}({2})'.format(latex_prefix, degree,
                                                   latex(ring))

    if is_FiniteField(ring):
        cmd = '{0}U({1}, {2})'.format(latex_prefix, degree, q)
        return UnitaryMatrixGroup_gap(degree, ring, special, name, ltx, cmd)
    else:
        return UnitaryMatrixGroup_generic(degree,
                                          ring,
                                          special,
                                          name,
                                          ltx,
                                          invariant_form=invariant_form)
Esempio n. 13
0
def GU(n, F, var='a'):
    """
    Return the general unitary group of degree n over the finite field
    F.

    INPUT:

    -  ``n`` - a positive integer

    -  ``F`` - finite field

    -  ``var`` - variable used to represent generator of
       quadratic extension of F, if needed.

    .. note::
        This group is also available via ``groups.matrix.GU()``.

    EXAMPLES::

        sage: G = GU(3,GF(7)); G
        General Unitary Group of degree 3 over Finite Field of size 7
        sage: G.gens()
        [
        [  a   0   0]
        [  0   1   0]
        [  0   0 5*a],
        [6*a   6   1]
        [  6   6   0]
        [  1   0   0]
        ]
        sage: G = GU(2,QQ)
        Traceback (most recent call last):
        ...
        NotImplementedError: general unitary group only implemented over finite fields

    ::

        sage: G = GU(3,GF(5), var='beta')
        sage: G.gens()
        [
        [  beta      0      0]
        [     0      1      0]
        [     0      0 3*beta],
        [4*beta      4      1]
        [     4      4      0]
        [     1      0      0]
        ]

    TESTS::

        sage: groups.matrix.GU(2, 3)
        General Unitary Group of degree 2 over Finite Field of size 3
    """
    if isinstance(F, (int, long, Integer)):
        F = GF(F, var)
    if is_FiniteField(F):
        return GeneralUnitaryGroup_finite_field(n, F, var)
    else:
        raise NotImplementedError, "general unitary group only implemented over finite fields"
Esempio n. 14
0
    def _compute_q_expansion_basis(self, prec=None):
        """
        Compute q-expansions for a basis of self to precision prec.

        EXAMPLES::

            sage: M = ModularForms(23,2,base_ring=GF(7))
            sage: M._compute_q_expansion_basis(10)
            [q + 6*q^3 + 6*q^4 + 5*q^6 + 2*q^7 + 6*q^8 + 2*q^9 + O(q^10),
            q^2 + 5*q^3 + 6*q^4 + 2*q^5 + q^6 + 2*q^7 + 5*q^8 + O(q^10),
            1 + 5*q^3 + 5*q^4 + 5*q^6 + 3*q^8 + 5*q^9 + O(q^10)]

        TESTS:

        This checks that :trac:`13445` is fixed::

            sage: M = ModularForms(Gamma1(29), base_ring=GF(29))
            sage: S = M.cuspidal_subspace()
            sage: 0 in [f.valuation() for f in S.basis()]
            False
            sage: len(S.basis()) == dimension_cusp_forms(Gamma1(29), 2)
            True
        """
        if prec is None:
            prec = self.prec()
        R = self._q_expansion_ring()
        c = self.base_ring().characteristic()
        if c == 0:
            B = self.__M.q_expansion_basis(prec)
            return [R(f) for f in B]
        elif c.is_prime_power():
            K = self.base_ring()
            p = K.characteristic().prime_factors()[0]
            from sage.rings.all import GF
            Kp = GF(p)
            newB = [f.change_ring(K) for f in list(self.__M.cuspidal_subspace().q_integral_basis(prec))]
            A = Kp**prec
            gens = [f.padded_list(prec) for f in newB]
            V = A.span(gens)
            B = [f.change_ring(K) for f in self.__M.q_integral_basis(prec)]
            for f in B:
                fc = f.padded_list(prec)
                gens.append(fc)
                if not A.span(gens) == V:
                    newB.append(f)
                    V = A.span(gens)
            if len(newB) != self.dimension():
                raise RuntimeError("The dimension of the space is %s but the basis we computed has %s elements"%(self.dimension(), len(newB)))
            lst = [R(f) for f in newB]
            return [f/f[f.valuation()] for f in lst]
        else:
            # this returns a basis of q-expansions, without guaranteeing that 
            # the first vectors form a basis of the cuspidal subspace
            # TODO: bring this in line with the other cases
            # simply using the above code fails because free modules over
            # general rings do not have a .span() method
            B = self.__M.q_integral_basis(prec)
            return [R(f) for f in B]
Esempio n. 15
0
def SU(n, R, var='a'):
    """
    The special unitary group `SU( d, R )` consists of all `d \times d`
    matrices that preserve a nondegenerate sesquilinear form over the
    ring `R` and have determinant one.

    .. note::

        For a finite field the matrices that preserve a sesquilinear
        form over `F_q` live over `F_{q^2}`. So ``SU(n,q)`` for
        integer ``q`` constructs the matrix group over the base ring
        ``GF(q^2)``.

    .. note::

        This group is also available via ``groups.matrix.SU()``.

    INPUT:

    - ``n`` -- a positive integer.

    - ``R`` -- ring or an integer. If an integer is specified, the
      corresponding finite field is used.

    - ``var`` -- variable used to represent generator of the finite
      field, if needed.

    OUTPUT:

    Return the special unitary group.

    EXAMPLES::

        sage: SU(3,5)
        Special Unitary Group of degree 3 over Finite Field in a of size 5^2
        sage: SU(3, GF(5))
        Special Unitary Group of degree 3 over Finite Field in a of size 5^2
        sage: SU(3,QQ)
        Special Unitary Group of degree 3 over Rational Field

    TESTS::

        sage: groups.matrix.SU(2, 3)
        Special Unitary Group of degree 2 over Finite Field in a of size 3^2
    """
    degree, ring = normalize_args_vectorspace(n, R, var=var)
    if is_FiniteField(ring):
        q = ring.cardinality()
        ring = GF(q**2, name=var)
    name = 'Special Unitary Group of degree {0} over {1}'.format(degree, ring)
    ltx = r'\text{{SU}}_{{{0}}}({1})'.format(degree, latex(ring))
    if is_FiniteField(ring):
        cmd = 'SU({0}, {1})'.format(degree, q)
        return UnitaryMatrixGroup_gap(degree, ring, True, name, ltx, cmd)
    else:
        return UnitaryMatrixGroup_generic(degree, ring, True, name, ltx)
Esempio n. 16
0
def matrix_add_GF(n=1000, p=16411, system='sage', times=100):
    """
    Given two n x n matrix over GF(p) with random entries, add them.

    INPUT:

    - ``n`` - matrix dimension (default: 300)
    - ``p`` - prime number (default: ``16411``)
    - ``system`` - either 'magma' or 'sage' (default: 'sage')
    - ``times`` - number of experiments (default: ``100``)

    EXAMPLES::

        sage: import sage.matrix.benchmark as b
        sage: ts = b.matrix_add_GF(500, p=19)
        sage: tm = b.matrix_add_GF(500, p=19, system='magma')  # optional - magma
    """
    if system == 'sage':
        A = random_matrix(GF(p), n, n)
        B = random_matrix(GF(p), n, n)
        t = cputime()
        for n in range(times):
            v = A + B
        return cputime(t)
    elif system == 'magma':
        code = """
n := %s;
A := Random(MatrixAlgebra(GF(%s), n));
B := Random(MatrixAlgebra(GF(%s), n));
t := Cputime();
for z in [1..%s] do
    K := A + B;
end for;
s := Cputime(t);
""" % (n, p, p, times)
        if verbose: print(code)
        magma.eval(code)
        return magma.eval('s')
    else:
        raise ValueError('unknown system "%s"' % system)
Esempio n. 17
0
    def residue_ring(self):
        """
        Return the residue field of this valuation.

        EXAMPLES::

            sage: v = ZZ.valuation(3)
            sage: v.residue_ring()
            Finite Field of size 3

        """
        from sage.rings.all import GF
        return GF(self.p())
Esempio n. 18
0
def elkies_first_step(E, l, lam):
    q = E.base_field().order()
    lam = GF(l)(lam)
    Phi = ClassicalModularPolynomialDatabase()[l]
    x = PolynomialRing(E.base_field(), 'x').gen()
    f = Phi(x, E.j_invariant())
    j_1, j_2 = f.roots()[0][0], f.roots()[1][0]
    E1 = elkies_mod_poly(E, j_1, l)
    try:
        I = EllipticCurveIsogeny(E, None, E1, l)
    except:
        I = l_isogeny(E, E1, l)
    r = lam.multiplicative_order()
    k = GF(q ** r)
    ext = extend_field(E, r)
    try:
        P = ext.lift_x(I.kernel_polynomial().any_root(k))
    except:
        return j_2
    if ext(P[0] ** q, P[1] ** q) == Integer(lam) * P:
        return j_1
    else:
        return j_2
Esempio n. 19
0
    def residue_ring(self):
        """
        Return the residue field of this valuation.

        EXAMPLES::

            sage: sys.path.append(os.getcwd()); from mac_lane import * # optional: standalone
            sage: v = pAdicValuation(ZZ, 3)
            sage: v.residue_ring()
            Finite Field of size 3

        """
        from sage.rings.all import GF
        return GF(self.p())
Esempio n. 20
0
def SU(n, F, var='a'):
    """
    Return the special unitary group of degree `n` over
    `F`.
    
    EXAMPLES::
    
        sage: SU(3,5)
        Special Unitary Group of degree 3 over Finite Field of size 5
        sage: SU(3,QQ)
        Traceback (most recent call last):
        ...
        NotImplementedError: special unitary group only implemented over finite fields
    """
    if isinstance(F, (int, long, Integer)):
        F = GF(F, var)
    if is_FiniteField(F):
        return SpecialUnitaryGroup_finite_field(n, F, var=var)
    else:
        raise NotImplementedError, "special unitary group only implemented over finite fields"
Esempio n. 21
0
def matrix_multiply_GF(n=100, p=16411, system='sage', times=3):
    """
    Given an n x n matrix A over GF(p) with random entries, compute
    A * (A+1).

    INPUT:

    - ``n`` - matrix dimension (default: 100)
    - ``p`` - prime number (default: ``16411``)
    - ``system`` - either 'magma' or 'sage' (default: 'sage')
    - ``times`` - number of experiments (default: ``3``)

    EXAMPLES::

        sage: import sage.matrix.benchmark as b
        sage: ts = b.matrix_multiply_GF(100, p=19)
        sage: tm = b.matrix_multiply_GF(100, p=19, system='magma')  # optional - magma
    """
    if system == 'sage':
        A = random_matrix(GF(p), n)
        B = A + 1
        t = cputime()
        for n in range(times):
            v = A * B
        return cputime(t) / times
    elif system == 'magma':
        code = """
n := %s;
A := Random(MatrixAlgebra(GF(%s), n));
B := A + 1;
t := Cputime();
for z in [1..%s] do
    K := A * B;
end for;
s := Cputime(t);
""" % (n, p, times)
        if verbose: print code
        magma.eval(code)
        return float(magma.eval('s')) / times
    else:
        raise ValueError('unknown system "%s"' % system)
Esempio n. 22
0
 def field_of_definition(self):
     """
     Return the field of definition of this general unity group.
     
     EXAMPLES::
     
         sage: G = GU(3,GF(5))
         sage: G.field_of_definition()
         Finite Field in a of size 5^2
         sage: G.base_field()
         Finite Field of size 5
     """
     try:
         return self._field_of_definition
     except AttributeError:
         if self.base_ring().degree() % 2 == 0:
             k = self.base_ring()
         else:
             k = GF(self.base_ring().order()**2, names=self._var)
         self._field_of_definition = k
         return k
Esempio n. 23
0
def velu_walk(E, l, lam, k):
    q = E.base_field().order()
    lam = GF(l)(lam)
    r = lam.multiplicative_order()
    mu = GF(l)((lam ** (-1)) * q)
    r_mu = mu.multiplicative_order()
    if k < 0:
        return velu_walk(E.quadratic_twist(), l, -mu, -k)
    if r_mu == r:
        print("Invalid parameters")
        return
    if r_mu < r:
        return velu_walk(E.quadratic_twist(), l, -lam, k)
    t = E.trace_of_frobenius()
    order = rec_order(q, t, r)
    cur = extend_field(E, r)
    for i in range(k):
        cur = velu_step(cur, l, lam, order, q)
    cur = EllipticCurve_from_j(GF(q)(cur.j_invariant()))
    return cur
Esempio n. 24
0
def det_GF(n=400, p=16411, system='sage'):
    """
    Dense determinant over GF(p).
    Given an n x n matrix A over GF with random entries compute
    det(A).

    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.det_GF(1000)
        sage: tm = b.det_GF(1000, system='magma')  # optional - magma
    """
    if system == 'sage':
        A = random_matrix(GF(p), n, n)
        t = cputime()
        d = A.determinant()
        return cputime(t)
    elif system == 'magma':
        code = """
n := %s;
A := Random(MatrixAlgebra(GF(%s), n));
t := Cputime();
d := Determinant(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)
Esempio n. 25
0
def convert_to_milnor_matrix(n, basis, p=2, generic='auto'):
    r"""
    Change-of-basis matrix, 'basis' to Milnor, in dimension
    `n`, at the prime `p`.

    INPUT:

    - ``n`` - non-negative integer, the dimension
    - ``basis`` - string, the basis from which to convert
    - ``p`` - positive prime number (optional, default 2)

    OUTPUT:

    ``matrix`` - change-of-basis matrix, a square matrix over ``GF(p)``

    EXAMPLES::

        sage: from sage.algebras.steenrod.steenrod_algebra_bases import convert_to_milnor_matrix
        sage: convert_to_milnor_matrix(5, 'adem') # indirect doctest
        [0 1]
        [1 1]
        sage: convert_to_milnor_matrix(45, 'milnor')
        111 x 111 dense matrix over Finite Field of size 2 (use the '.str()' method to see the entries)
        sage: convert_to_milnor_matrix(12,'wall')
        [1 0 0 1 0 0 0]
        [1 1 0 0 0 1 0]
        [0 1 0 1 0 0 0]
        [0 0 0 1 0 0 0]
        [1 1 0 0 1 0 0]
        [0 0 1 1 1 0 1]
        [0 0 0 0 1 0 1]

    The function takes an optional argument, the prime `p` over
    which to work::

        sage: convert_to_milnor_matrix(17,'adem',3)
        [0 0 1 1]
        [0 0 0 1]
        [1 1 1 1]
        [0 1 0 1]
        sage: convert_to_milnor_matrix(48,'adem',5)
        [0 1]
        [1 1]
        sage: convert_to_milnor_matrix(36,'adem',3)
        [0 0 1]
        [0 1 0]
        [1 2 0]
    """
    from sage.matrix.constructor import matrix
    from sage.rings.all import GF
    from .steenrod_algebra import SteenrodAlgebra
    if generic == 'auto':
        generic = False if p == 2 else True
    if n == 0:
        return matrix(GF(p), 1, 1, [[1]])
    milnor_base = steenrod_algebra_basis(n, 'milnor', p, generic=generic)
    rows = []
    A = SteenrodAlgebra(basis=basis, p=p, generic=generic)
    for poly in A.basis(n):
        d = poly.milnor().monomial_coefficients()
        for v in milnor_base:
            entry = d.get(v, 0)
            rows = rows + [entry]
    d = len(milnor_base)
    return matrix(GF(p), d, d, rows)
Esempio n. 26
0
def lift_map(target):
    """
    Create a lift map, to be used for lifting the cross ratios of a matroid
    representation.

    .. SEEALSO::

        :meth:`lift_cross_ratios() <sage.matroids.utilities.lift_cross_ratios>`

    INPUT:

    - ``target`` -- a string describing the target (partial) field.

    OUTPUT:

    - a dictionary

    Depending on the value of ``target``, the following lift maps will be created:

    - "reg": a lift map from `\GF3` to the regular partial field `(\ZZ, <-1>)`.

    - "sru": a lift map from `\GF7` to the
      sixth-root-of-unity partial field `(\QQ(z), <z>)`, where `z` is a sixth root
      of unity. The map sends 3 to `z`.

    - "dyadic": a lift map from `\GF{11}` to the dyadic partial field `(\QQ, <-1, 2>)`.

    - "gm": a lift map from `\GF{19}` to the golden mean partial field
      `(\QQ(t), <-1,t>)`, where `t` is a root of `t^2-t-1`. The map sends `5` to `t`.

    The example below shows that the latter map satisfies three necessary conditions stated in
    :meth:`lift_cross_ratios() <sage.matroids.utilities.lift_cross_ratios>`

    EXAMPLES::

        sage: from sage.matroids.utilities import lift_map
        sage: lm = lift_map('gm')
        sage: for x in lm:
        ....:     if (x == 1) is not (lm[x] == 1):
        ....:         print('not a proper lift map')
        ....:     for y in lm:
        ....:         if (x+y == 0) and not (lm[x]+lm[y] == 0):
        ....:             print('not a proper lift map')
        ....:         if (x+y == 1) and not (lm[x]+lm[y] == 1):
        ....:             print('not a proper lift map')
        ....:         for z in lm:
        ....:             if (x*y==z) and not (lm[x]*lm[y]==lm[z]):
        ....:                 print('not a proper lift map')

    """
    if target == "reg":
        R = GF(3)
        return {R(1): ZZ(1)}

    if target == "sru":
        R = GF(7)
        z = ZZ['z'].gen()
        S = NumberField(z * z - z + 1, 'z')
        return {R(1): S(1), R(3): S(z), R(3)**(-1): S(z)**5}

    if target == "dyadic":
        R = GF(11)
        return {R(1): QQ(1), R(-1): QQ(-1), R(2): QQ(2), R(6): QQ(1 / 2)}

    if target == "gm":
        R = GF(19)
        t = QQ['t'].gen()
        G = NumberField(t * t - t - 1, 't')
        return {
            R(1): G(1),
            R(5): G(t),
            R(1) / R(5): G(1) / G(t),
            R(-5): G(-t),
            R(-5)**(-1): G(-t)**(-1),
            R(5)**2: G(t)**2,
            R(5)**(-2): G(t)**(-2)
        }

    raise NotImplementedError(target)
Esempio n. 27
0
def GU(n, R, var='a'):
    r"""
    Return the general unitary group.

    The general unitary group `GU( d, R )` consists of all `d \times
    d` matrices that preserve a nondegenerate sesquilinear form over
    the ring `R`.

    .. note::

        For a finite field the matrices that preserve a sesquilinear
        form over `F_q` live over `F_{q^2}`. So ``GU(n,q)`` for
        integer ``q`` constructs the matrix group over the base ring
        ``GF(q^2)``.

    .. note::

        This group is also available via ``groups.matrix.GU()``.

    INPUT:

    - ``n`` -- a positive integer.

    - ``R`` -- ring or an integer. If an integer is specified, the
      corresponding finite field is used.

    - ``var`` -- variable used to represent generator of the finite
      field, if needed.

    OUTPUT:

    Return the general unitary group.

    EXAMPLES::

        sage: G = GU(3, 7); G
        General Unitary Group of degree 3 over Finite Field in a of size 7^2
        sage: G.gens()
        (
        [  a   0   0]  [6*a   6   1]
        [  0   1   0]  [  6   6   0]
        [  0   0 5*a], [  1   0   0]
        )
        sage: GU(2,QQ)
        General Unitary Group of degree 2 over Rational Field

        sage: G = GU(3, 5, var='beta')
        sage: G.base_ring()
        Finite Field in beta of size 5^2
        sage: G.gens()
        (
        [  beta      0      0]  [4*beta      4      1]
        [     0      1      0]  [     4      4      0]
        [     0      0 3*beta], [     1      0      0]
        )

    TESTS::

        sage: groups.matrix.GU(2, 3)
        General Unitary Group of degree 2 over Finite Field in a of size 3^2
    """
    degree, ring = normalize_args_vectorspace(n, R, var=var)
    if is_FiniteField(ring):
        q = ring.cardinality()
        ring = GF(q**2, name=var)
    name = 'General Unitary Group of degree {0} over {1}'.format(degree, ring)
    ltx = r'\text{{GU}}_{{{0}}}({1})'.format(degree, latex(ring))
    if is_FiniteField(ring):
        cmd = 'GU({0}, {1})'.format(degree, q)
        return UnitaryMatrixGroup_gap(degree, ring, False, name, ltx, cmd)
    else:
        return UnitaryMatrixGroup_generic(degree, ring, False, name, ltx)
Esempio n. 28
0
def make_mono_admissible(mono, p=2, generic=None):
    r"""
    Given a tuple ``mono``, view it as a product of Steenrod
    operations, and return a dictionary giving data equivalent to
    writing that product as a linear combination of admissible
    monomials.

    When `p=2`, the sequence (and hence the corresponding monomial)
    `(i_1, i_2, ...)` is admissible if `i_j \geq 2 i_{j+1}` for all
    `j`.

    When `p` is odd, the sequence `(e_1, i_1, e_2, i_2, ...)` is
    admissible if `i_j \geq e_{j+1} + p i_{j+1}` for all `j`.

    INPUT:

    - ``mono`` - a tuple of non-negative integers
    - `p` - prime number, optional (default 2)
    - `generic` - whether to use the generic Steenrod algebra, (default: depends on prime)

    OUTPUT:

    Dictionary of terms of the form (tuple: coeff), where
    'tuple' is an admissible tuple of non-negative integers and
    'coeff' is its coefficient.  This corresponds to a linear
    combination of admissible monomials.  When `p` is odd, each tuple
    must have an odd length: it should be of the form `(e_1, i_1, e_2,
    i_2, ..., e_k)` where each `e_j` is either 0 or 1 and each `i_j`
    is a positive integer: this corresponds to the admissible monomial

    .. math::

       \beta^{e_1} \mathcal{P}^{i_2} \beta^{e_2} \mathcal{P}^{i_2} ...
       \mathcal{P}^{i_k} \beta^{e_k}

    ALGORITHM:

    Given `(i_1, i_2, i_3, ...)`, apply the Adem relations to the first
    pair (or triple when `p` is odd) where the sequence is inadmissible,
    and then apply this function recursively to each of the resulting
    tuples `(i_1, ..., i_{j-1}, NEW, i_{j+2}, ...)`, keeping track of
    the coefficients.

    .. note::

        Users should use :func:`make_mono_admissible` instead of this
        function (which has a trailing underscore in its name):
        :func:`make_mono_admissible` is the cached version of this
        one, and so will be faster.

    EXAMPLES::

        sage: from sage.algebras.steenrod.steenrod_algebra_mult import make_mono_admissible
        sage: make_mono_admissible((12,)) # already admissible, indirect doctest
        {(12,): 1}
        sage: make_mono_admissible((2,1)) # already admissible
        {(2, 1): 1}
        sage: make_mono_admissible((2,2))
        {(3, 1): 1}
        sage: make_mono_admissible((2, 2, 2))
        {(5, 1): 1}
        sage: make_mono_admissible((0, 2, 0, 1, 0), p=7)
        {(0, 3, 0): 3}

    Test the fix from :trac:`13796`::

        sage: SteenrodAlgebra(p=2, basis='adem').Q(2) * (Sq(6) * Sq(2)) # indirect doctest
        Sq^10 Sq^4 Sq^1 + Sq^10 Sq^5 + Sq^12 Sq^3 + Sq^13 Sq^2
    """
    from sage.rings.all import GF
    if generic is None:
        generic = False if p == 2 else True
    F = GF(p)
    if len(mono) == 1:
        return {mono: 1}
    if not generic and len(mono) == 2:
        return adem(*mono, p=p, generic=generic)
    if not generic:
        # check to see if admissible:
        admissible = True
        for j in range(len(mono) - 1):
            if mono[j] < 2 * mono[j + 1]:
                admissible = False
                break
        if admissible:
            return {mono: 1}
        # else j is the first index where admissibility fails
        ans = {}
        y = adem(mono[j], mono[j + 1])
        for x in y:
            new = mono[:j] + x + mono[j + 2:]
            new = make_mono_admissible(new)
            for m in new:
                if m in ans:
                    ans[m] = ans[m] + y[x] * new[m]
                    if F(ans[m]) == 0:
                        del ans[m]
                else:
                    ans[m] = y[x] * new[m]
        return ans
    # p odd
    # check to see if admissible:
    admissible = True
    for j in range(1, len(mono) - 2, 2):
        if mono[j] < mono[j + 1] + p * mono[j + 2]:
            admissible = False
            break
    if admissible:
        return {mono: 1}
    # else j is the first index where admissibility fails
    ans = {}
    y = adem(*mono[j:j + 3], p=p, generic=True)
    for x in y:
        new_x = list(x)
        new_x[0] = mono[j - 1] + x[0]
        if len(mono) >= j + 3:
            new_x[-1] = mono[j + 3] + x[-1]
        if new_x[0] <= 1 and new_x[-1] <= 1:
            new = mono[:j - 1] + tuple(new_x) + mono[j + 4:]
            new = make_mono_admissible(new, p, generic=True)
            for m in new:
                if m in ans:
                    ans[m] = ans[m] + y[x] * new[m]
                    if F(ans[m]) == 0:
                        del ans[m]
                else:
                    ans[m] = y[x] * new[m]
    return ans
Esempio n. 29
0
def multinomial_odd(list, p):
    r"""
    Multinomial coefficient of list, mod p.

    INPUT:

    - list - list of integers
    - p - a prime number

    OUTPUT:

    Associated multinomial coefficient, mod p

    Given the input $[n_1, n_2, n_3, ...]$, this computes the
    multinomial coefficient $(n_1 + n_2 + n_3 + ...)! / (n_1! n_2!
    n_3! ...)$, mod $p$.  The method is this: expand each $n_i$ in
    base $p$: $n_i = \sum_j p^j n_{ij}$.  Do the same for the sum of
    the $n_i$'s, which we call $m$: $m = \sum_j p^j m_j$.  Then the
    multinomial coefficient is congruent, mod $p$, to the product of
    the multinomial coefficients $m_j! / (n_{1j}! n_{2j}! ...)$.

    Furthermore, any multinomial coefficient $m! / (n_1! n_2! ...)$
    can be computed as a product of binomial coefficients: it equals

    .. math::

       \binom{n_1}{n_1} \binom{n_1 + n_2}{n_2} \binom{n_1 + n_2 + n_3}{n_3} ...

    This is convenient because Sage's binomial function returns
    integers, not rational numbers (as would be produced just by
    dividing factorials).

    EXAMPLES::

        sage: from sage.algebras.steenrod.steenrod_algebra_mult import multinomial_odd
        sage: multinomial_odd([1,2,4], 2)
        1
        sage: multinomial_odd([1,2,4], 7)
        0
        sage: multinomial_odd([1,2,4], 11)
        6
        sage: multinomial_odd([1,2,4], 101)
        4
        sage: multinomial_odd([1,2,4], 107)
        105
    """
    from sage.rings.all import GF, Integer
    from sage.rings.arith import binomial
    n = sum(list)
    answer = 1
    F = GF(p)
    n_expansion = Integer(n).digits(p)
    list_expansion = [Integer(k).digits(p) for k in list]
    index = 0
    while answer != 0 and index < len(n_expansion):
        multi = F(1)
        partial_sum = 0
        for exp in list_expansion:
            if index < len(exp):
                partial_sum = partial_sum + exp[index]
                multi = F(multi * binomial(partial_sum, exp[index]))
        answer = F(answer * multi)
        index += 1
    return answer
Esempio n. 30
0
def milnor_multiplication_odd(m1, m2, p):
    r"""
    Product of Milnor basis elements defined by m1 and m2 at the odd prime p.

    INPUT:

    - m1 - pair of tuples (e,r), where e is an increasing tuple of
      non-negative integers and r is a tuple of non-negative integers
    - m2 - pair of tuples (f,s), same format as m1
    - p - odd prime number

    OUTPUT:

    Dictionary of terms of the form (tuple: coeff), where 'tuple' is
    a pair of tuples, as for r and s, and 'coeff' is an integer mod p.

    This computes the product of the Milnor basis elements
    $Q_{e_1} Q_{e_2} ... P(r_1, r_2, ...)$ and
    $Q_{f_1} Q_{f_2} ... P(s_1, s_2, ...)$.

    EXAMPLES::

        sage: from sage.algebras.steenrod.steenrod_algebra_mult import milnor_multiplication_odd
        sage: milnor_multiplication_odd(((0,2),(5,)), ((1,),(1,)), 5)
        {((0, 1, 2), (0, 1)): 4, ((0, 1, 2), (6,)): 4}
        sage: milnor_multiplication_odd(((0,2,4),()), ((1,3),()), 7)
        {((0, 1, 2, 3, 4), ()): 6}
        sage: milnor_multiplication_odd(((0,2,4),()), ((1,5),()), 7)
        {((0, 1, 2, 4, 5), ()): 1}
        sage: milnor_multiplication_odd(((),(6,)), ((),(2,)), 3)
        {((), (4, 1)): 1, ((), (8,)): 1, ((), (0, 2)): 1}

    These examples correspond to the following product computations:

    .. math::

        p=5: \quad Q_0 Q_2 \mathcal{P}(5) Q_1 \mathcal{P}(1) = 4 Q_0 Q_1 Q_2 \mathcal{P}(0,1) + 4 Q_0 Q_1 Q_2 \mathcal{P}(6)

        p=7: \quad (Q_0 Q_2 Q_4) (Q_1 Q_3) = 6 Q_0 Q_1 Q_2 Q_3 Q_4

        p=7: \quad (Q_0 Q_2 Q_4) (Q_1 Q_5) = Q_0 Q_1 Q_2 Q_3 Q_5

        p=3: \quad \mathcal{P}(6) \mathcal{P}(2) = \mathcal{P}(0,2) + \mathcal{P}(4,1) + \mathcal{P}(8)

    The following used to fail until the trailing zeroes were
    eliminated in p_mono::

        sage: A = SteenrodAlgebra(3)
        sage: a = A.P(0,3); b = A.P(12); c = A.Q(1,2)
        sage: (a+b)*c == a*c + b*c
        True

    Test that the bug reported in #7212 has been fixed::

        sage: A.P(36,6)*A.P(27,9,81)
        2 P(13,21,83) + P(14,24,82) + P(17,20,83) + P(25,18,83) + P(26,21,82) + P(36,15,80,1) + P(49,12,83) + 2 P(50,15,82) + 2 P(53,11,83) + 2 P(63,15,81)

    Associativity once failed because of a sign error::

        sage: a,b,c = A.Q_exp(0,1), A.P(3), A.Q_exp(1,1)
        sage: (a*b)*c == a*(b*c)
        True

    This uses the same algorithm Monks does in his Maple package to
    iterate through the possible matrices: see
    http://mathweb.scranton.edu/monks/software/Steenrod/steen.html.
    """
    from sage.rings.all import GF
    F = GF(p)
    (f, s) = m2
    # First compute Q_e0 Q_e1 ... P(r1, r2, ...) Q_f0 Q_f1 ...
    # Store results (as dictionary of pairs of tuples) in 'answer'.
    answer = {m1: F(1)}
    for k in f:
        old_answer = answer
        answer = {}
        for mono in old_answer:
            if k not in mono[0]:
                q_mono = set(mono[0])
                if len(q_mono) > 0:
                    ind = len(q_mono.intersection(range(k, 1 + max(q_mono))))
                else:
                    ind = 0
                coeff = (-1)**ind * old_answer[mono]
                lst = list(mono[0])
                if ind == 0:
                    lst.append(k)
                else:
                    lst.insert(-ind, k)
                q_mono = tuple(lst)
                p_mono = mono[1]
                answer[(q_mono, p_mono)] = F(coeff)
            for i in range(1, 1 + len(mono[1])):
                if (k + i not in mono[0]) and (p**k <= mono[1][i - 1]):
                    q_mono = set(mono[0])
                    if len(q_mono) > 0:
                        ind = len(
                            q_mono.intersection(range(k + i, 1 + max(q_mono))))
                    else:
                        ind = 0
                    coeff = (-1)**ind * old_answer[mono]
                    lst = list(mono[0])
                    if ind == 0:
                        lst.append(k + i)
                    else:
                        lst.insert(-ind, k + i)
                    q_mono = tuple(lst)
                    p_mono = list(mono[1])
                    p_mono[i - 1] = p_mono[i - 1] - p**k

                    # The next two lines were added so that p_mono won't
                    # have trailing zeros. This makes p_mono uniquely
                    # determined by P(*p_mono).

                    while len(p_mono) > 0 and p_mono[-1] == 0:
                        p_mono.pop()

                    answer[(q_mono, tuple(p_mono))] = F(coeff)
    # Now for the Milnor matrices.  For each entry '(e,r): coeff' in answer,
    # multiply r with s.  Record coefficient for matrix and multiply by coeff.
    # Store in 'result'.
    if len(s) == 0:
        result = answer
    else:
        result = {}
        for (e, r) in answer:
            old_coeff = answer[(e, r)]
            # Milnor multiplication for r and s
            rows = len(r) + 1
            cols = len(s) + 1
            diags = len(r) + len(s)
            # initialize matrix
            M = range(rows)
            for i in range(rows):
                M[i] = [0] * cols
            for j in range(1, cols):
                M[0][j] = s[j - 1]
            for i in range(1, rows):
                M[i][0] = r[i - 1]
                for j in range(1, cols):
                    M[i][j] = 0
            found = True
            while found:
                # check diagonals
                n = 1
                coeff = old_coeff
                diagonal = [0] * diags
                while n <= diags and coeff != 0:
                    nth_diagonal = [
                        M[i][n - i]
                        for i in range(max(0, n - cols + 1), min(1 + n, rows))
                    ]
                    coeff = coeff * multinomial_odd(nth_diagonal, p)
                    diagonal[n - 1] = sum(nth_diagonal)
                    n = n + 1
                if F(coeff) != 0:
                    i = diags - 1
                    while i >= 0 and diagonal[i] == 0:
                        i = i - 1
                    t = tuple(diagonal[:i + 1])
                    if (e, t) in result:
                        result[(e, t)] = F(coeff + result[(e, t)])
                    else:
                        result[(e, t)] = F(coeff)
                    # now look for new matrices:
                found = False
                i = 1
                while not found and i < rows:
                    temp_sum = M[i][0]
                    j = 1
                    while not found and j < cols:
                        # check to see if column index j is small enough
                        if temp_sum >= p**j:
                            # now check to see if there's anything above this entry
                            # to add to it
                            temp_col_sum = 0
                            for k in range(i):
                                temp_col_sum += M[k][j]
                            if temp_col_sum != 0:
                                found = True
                                for row in range(1, i):
                                    M[row][0] = r[row - 1]
                                    for col in range(1, cols):
                                        M[0][col] = M[0][col] + M[row][col]
                                        M[row][col] = 0
                                for col in range(1, j):
                                    M[0][col] = M[0][col] + M[i][col]
                                    M[i][col] = 0
                                M[0][j] = M[0][j] - 1
                                M[i][j] = M[i][j] + 1
                                M[i][0] = temp_sum - p**j
                            else:
                                temp_sum += M[i][j] * p**j
                        else:
                            temp_sum += M[i][j] * p**j
                        j = j + 1
                    i = i + 1
    return result