Exemple #1
0
 def __pow__(self, n):
     """
     Returns this species to the power n. This uses a binary
     exponentiation algorithm to perform the powering.
     
     EXAMPLES::
     
         sage: X = species.SingletonSpecies()
         sage: (X^2).generating_series().coefficients(4)
         [0, 0, 1, 0]
         sage: X^1 is X
         True
         sage: A = X^32
         sage: A.digraph()
         Multi-digraph on 6 vertices
     """
     from sage.rings.all import Integer
     import operator
     n = Integer(n)
     if n <= 0:
         raise ValueError, "only positive exponents are currently supported"
     digits = n.digits(2)
     squares = [self]
     for i in range(len(digits)-1):
         squares.append(squares[-1]*squares[-1])
     return reduce(operator.add, (s for i,s in zip(digits, squares) if i != 0))
    def _element_constructor_(self, x) :
        """
        TESTS::
            sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *
            sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import MonoidPowerSeriesRing_generic
            sage: mps = MonoidPowerSeriesRing_generic(QQ, NNMonoid(False))
            sage: h = mps(1) # indirect doctest
            sage: h = mps(mps.monoid().zero_element())
            sage: h = mps.zero_element()
            sage: K.<rho> = CyclotomicField(6)
            sage: mps = MonoidPowerSeriesRing_generic(K, NNMonoid(False))
            sage: h = mps(rho)
            sage: h = mps(1)
        """
        if isinstance(x, int) :
            x = Integer(x)
            
        if isinstance(x, Element) :
            P = x.parent()

            if P is self.coefficient_domain() :
                return self._element_class( self, {self.monoid().zero_element(): x},
                                                self.monoid().filter_all() )
            elif self.coefficient_domain().has_coerce_map_from(P) :
                return self._element_class( self, {self.monoid().zero_element(): self.coefficient_domain()(x)},
                                                self.monoid().filter_all() )
            elif P is self.monoid() :
                return self._element_class( self, {x: self.base_ring().one_element},
                                                self.monoid().filter_all() )
                
        return MonoidPowerSeriesAmbient_abstract._element_constructor_(self, x)
Exemple #3
0
    def duke_imamoglu_lift(self, f, f_k, precision, half_integral_weight = False) :
        """
        INPUT:
        
        - ``half_integral_weight``   -- If ``False`` we assume that `f` is the Fourier expansion of a
                                        Jacobi form. Otherwise we assume it is the Fourier expansion
                                        of a half integral weight elliptic modular form.
        """
        
        if half_integral_weight :
            coeff_index = lambda d : d
        else :
            coeff_index = lambda d : ((d + (-d % 4)) // 4, (-d) % 4)
        
        coeffs = dict()
        
        for t in precision.iter_positive_forms() :
            dt = (-1)**(precision.genus() // 2) * t.det()
            d = fundamental_discriminant(dt)
            eps = Integer(isqrt(dt / d))
    
            coeffs[t] = 0 
            for a in eps.divisors() :
                d_a = abs(d * (eps // a)**2)
                 
                coeffs[t] = coeffs[t] + a**(f_k - 1) * self._kohnen_phi(a, t) \
                                        * f[coeff_index(d_a)]

        return coeffs
Exemple #4
0
    def __pow__(self, n):
        r"""
        Returns this species to the power `n`.

        This uses a binary exponentiation algorithm to perform the
        powering.

        EXAMPLES::

            sage: One = species.EmptySetSpecies()
            sage: X = species.SingletonSpecies()
            sage: X^2
            Product of (Singleton species) and (Singleton species)
            sage: X^5
            Product of (Singleton species) and (Product of (Product of
            (Singleton species) and (Singleton species)) and (Product
            of (Singleton species) and (Singleton species)))

            sage: (X^2).generating_series().coefficients(4)
            [0, 0, 1, 0]
            sage: (X^3).generating_series().coefficients(4)
            [0, 0, 0, 1]
            sage: ((One+X)^3).generating_series().coefficients(4)
            [1, 3, 3, 1]
            sage: ((One+X)^7).generating_series().coefficients(8)
            [1, 7, 21, 35, 35, 21, 7, 1]

            sage: x = QQ[['x']].gen()
            sage: coeffs = ((1+x+x+x**2)**25+O(x**10)).padded_list()
            sage: T = ((One+X+X+X^2)^25)
            sage: T.generating_series().coefficients(10) == coeffs
            True
            sage: X^1 is X
            True
            sage: A = X^32
            sage: A.digraph()
            Multi-digraph on 6 vertices

        TESTS::

            sage: X**(-1)
            Traceback (most recent call last):
            ...
            ValueError: only positive exponents are currently supported
        """
        from sage.rings.all import Integer
        import operator
        n = Integer(n)
        if n <= 0:
            raise ValueError("only positive exponents are currently supported")
        digits = n.digits(2)
        squares = [self]
        for i in range(len(digits) - 1):
            squares.append(squares[-1] * squares[-1])
        return reduce(operator.mul, (s for i, s in zip(digits, squares)
                                     if i != 0))
Exemple #5
0
    def __init__(self, abvar, p):
        """
        Create a `p`-adic `L`-series.

        EXAMPLES::

            sage: J0(37)[0].padic_lseries(389)
            389-adic L-series attached to Simple abelian subvariety 37a(1,37) of dimension 1 of J0(37)
        """
        Lseries.__init__(self, abvar)
        p = Integer(p)
        if not p.is_prime():
            raise ValueError("p (=%s) must be prime"%p)
        self.__p = p
Exemple #6
0
def validate_label(label):
    parts = label.split('.')
    if len(parts) != 3:
        raise ValueError("it must be of the form g.q.iso, with g a dimension and q a prime power")
    g, q, iso = parts
    try:
        g = int(g)
    except ValueError:
        raise ValueError("it must be of the form g.q.iso, where g is an integer")
    try:
        q = Integer(q)
        if not q.is_prime_power(): raise ValueError
    except ValueError:
        raise ValueError("it must be of the form g.q.iso, where g is a prime power")
    coeffs = iso.split("_")
    if len(coeffs) != g:
        raise ValueError("the final part must be of the form c1_c2_..._cg, with g=%s components"%(g))
    if not all(c.isalpha() and c==c.lower() for c in coeffs):
        raise ValueError("the final part must be of the form c1_c2_..._cg, with each ci consisting of lower case letters")
Exemple #7
0
    def apply_T(self, j):
        """
        Apply the matrix `T=[0,1,-1,-1]` to the `j`-th Manin symbol.

        INPUT:

        - ``j`` - (int) a symbol index

        OUTPUT: see documentation for apply()

        EXAMPLE::

            sage: from sage.modular.modsym.manin_symbol_list import ManinSymbolList_gamma0
            sage: m = ManinSymbolList_gamma0(5,8)
            sage: m.apply_T(4)
            [(3, 1), (9, -6), (15, 15), (21, -20), (27, 15), (33, -6), (39, 1)]
            sage: [m.apply_T(i) for i in xrange(10)]
            [[(5, 1), (11, -6), (17, 15), (23, -20), (29, 15), (35, -6), (41, 1)],
            [(0, 1), (6, -6), (12, 15), (18, -20), (24, 15), (30, -6), (36, 1)],
            [(4, 1), (10, -6), (16, 15), (22, -20), (28, 15), (34, -6), (40, 1)],
            [(2, 1), (8, -6), (14, 15), (20, -20), (26, 15), (32, -6), (38, 1)],
            [(3, 1), (9, -6), (15, 15), (21, -20), (27, 15), (33, -6), (39, 1)],
            [(1, 1), (7, -6), (13, 15), (19, -20), (25, 15), (31, -6), (37, 1)],
            [(5, 1), (11, -5), (17, 10), (23, -10), (29, 5), (35, -1)],
            [(0, 1), (6, -5), (12, 10), (18, -10), (24, 5), (30, -1)],
            [(4, 1), (10, -5), (16, 10), (22, -10), (28, 5), (34, -1)],
            [(2, 1), (8, -5), (14, 10), (20, -10), (26, 5), (32, -1)]]
        """
        k = self._weight
        i, u, v = self._symbol_list[j]
        u, v = self.__syms.normalize(v,-u-v)
        if (k-2) % 2 == 0:
            s = 1
        else:
            s = -1
        z = []
        a = Integer(k-2-i)
        for j in range(k-2-i+1):
            m = self.index((j, u, v))
            z.append((m, s * a.binomial(j)))
            s *= -1
        return z
Exemple #8
0
    def apply_TT(self, j):
        """
        Apply the matrix `TT=[-1,-1,0,1]` to the `j`-th Manin symbol.

        INPUT:

        - ``j`` - (int) a symbol index

        OUTPUT: see documentation for apply()

        EXAMPLE::

            sage: from sage.modular.modsym.manin_symbol_list import ManinSymbolList_gamma0
            sage: m = ManinSymbolList_gamma0(5,8)
            sage: m.apply_TT(4)
            [(38, 1)]
            sage: [m.apply_TT(i) for i in xrange(10)]
            [[(37, 1)],
            [(41, 1)],
            [(39, 1)],
            [(40, 1)],
            [(38, 1)],
            [(36, 1)],
            [(31, -1), (37, 1)],
            [(35, -1), (41, 1)],
            [(33, -1), (39, 1)],
            [(34, -1), (40, 1)]]
        """
        k = self._weight
        i, u, v = self._symbol_list[j]
        u, v = self.__syms.normalize(-u-v,u)
        if (k-2-i) % 2 == 0:
            s = 1
        else:
            s = -1
        z = []
        a = Integer(i)
        for j in range(i+1):
            m = self.index((k-2-i+j, u, v))
            z.append((m, s * a.binomial(j)))
            s *= -1
        return z
Exemple #9
0
    def apply_TT(self, j):
        """
        Apply the matrix `TT=[-1,-1,0,1]` to the `j`-th Manin symbol.

        INPUT:

        - ``j`` - (integer) a symbol index

        OUTPUT:

        A list of pairs `(j, c_i)`, where each `c_i` is an
        integer, `j` is an integer (the `j`-th Manin symbol), and the
        sum `c_i*x_i` is the image of self under the right action
        of the matrix `T^2`.

        EXAMPLE::

            sage: eps = DirichletGroup(4).gen(0)
            sage: from sage.modular.modsym.manin_symbol_list import ManinSymbolList_character
            sage: m = ManinSymbolList_character(eps,2); m
            Manin Symbol List of weight 2 for Gamma1(4) with character [-1]
            sage: m.apply_TT(4)
            [(0, 1)]
            sage: [m.apply_TT(i) for i in xrange(len(m))]
            [[(1, -1)], [(4, -1)], [(5, 1)], [(2, 1)], [(0, 1)], [(3, 1)]]
        """
        k = self._weight
        i, u, v = self._symbol_list[j]
        u, v, r = self.__P1.normalize_with_scalar(-u-v,u)
        r = self.__character(r)
        if (k-2-i) % 2 == 0:
            s = r
        else:
            s = -r
        z = []
        a = Integer(i)
        for j in range(i+1):
            m, r = self.index((k-2-i+j, u, v))
            z.append((m, s * r * a.binomial(j)))
            s *= -1
        return z
Exemple #10
0
    def ap(self, p):
        """
        Return a list of the eigenvalues of the Hecke operator `T_p`
        on all the computed eigenforms.  The eigenvalues match up
        between one prime and the next.

        INPUT:

        - ``p`` - integer, a prime number

        OUTPUT:

        - ``list`` - a list of double precision complex numbers

        EXAMPLES::

            sage: n = numerical_eigenforms(11,4)
            sage: n.ap(2) # random order
            [9.0, 9.0, 2.73205080757, -0.732050807569]
            sage: n.ap(3) # random order
            [28.0, 28.0, -7.92820323028, 5.92820323028]
            sage: m = n.modular_symbols()
            sage: x = polygen(QQ, 'x')
            sage: m.T(2).charpoly('x').factor()
            (x - 9)^2 * (x^2 - 2*x - 2)
            sage: m.T(3).charpoly('x').factor()
            (x - 28)^2 * (x^2 + 2*x - 47)
        """
        p = Integer(p)
        if not p.is_prime():
            raise ValueError("p must be a prime")
        try:
            return self._ap[p]
        except AttributeError:
            self._ap = {}
        except KeyError:
            pass
        a = Sequence(self.eigenvalues([p])[0], immutable=True)
        self._ap[p] = a
        return a
Exemple #11
0
def xi_degrees(n,p=2, reverse=True):
    r"""
    Decreasing list of degrees of the xi_i's, starting in degree n.

    INPUT:

    - `n` - integer
    - `p` - prime number, optional (default 2)
    - ``reverse`` - bool, optional (default True)

    OUTPUT: ``list`` - list of integers

    When `p=2`: decreasing list of the degrees of the `\xi_i`'s with
    degree at most n.

    At odd primes: decreasing list of these degrees, each divided by
    `2(p-1)`.

    If ``reverse`` is False, then return an increasing list rather
    than a decreasing one.

    EXAMPLES::

        sage: sage.algebras.steenrod.steenrod_algebra_bases.xi_degrees(17)
        [15, 7, 3, 1]
        sage: sage.algebras.steenrod.steenrod_algebra_bases.xi_degrees(17, reverse=False)
        [1, 3, 7, 15]
        sage: sage.algebras.steenrod.steenrod_algebra_bases.xi_degrees(17,p=3)
        [13, 4, 1]
        sage: sage.algebras.steenrod.steenrod_algebra_bases.xi_degrees(400,p=17)
        [307, 18, 1]
    """
    from sage.rings.all import Integer
    if n <= 0: return []
    N = Integer(n*(p-1) + 1)
    l = [int((p**d-1)/(p-1)) for d in range(1,N.exact_log(p)+1)]
    if not reverse:
        return l
    l.reverse()
    return l
    def _element_constructor_(self, x) :
        """
        TESTS::
            sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_basicmonoids import *
            sage: from psage.modform.fourier_expansion_framework.monoidpowerseries.monoidpowerseries_ring import EquivariantMonoidPowerSeriesRing_generic
            sage: emps = EquivariantMonoidPowerSeriesRing_generic(NNMonoid(True), TrivialCharacterMonoid("1", QQ), TrivialRepresentation("1", QQ))
            sage: h = emps(1)
            sage: h = emps(emps.monoid().zero_element())
            sage: h = emps.zero_element()
            sage: K.<rho> = CyclotomicField(6)
            sage: emps = EquivariantMonoidPowerSeriesRing_generic(NNMonoid(True), TrivialCharacterMonoid("1", QQ), TrivialRepresentation("1", K))
            sage: h = emps(rho)
            sage: h = emps(1)
        """
        if isinstance(x, int) :
            x = Integer(x)
        
        if isinstance(x, Element) :
            P = x.parent()

            if P is self.coefficient_domain() :
                return self._element_class( self,
                        {self.characters().one_element():
                                {self.monoid().zero_element(): x}},
                        self.action().filter_all() )
            elif self.coefficient_domain().has_coerce_map_from(P) :
                return self._element_class( self,
                        {self.characters().one_element():
                                {self.monoid().zero_element(): self.coefficient_domain()(x)}},
                        self.action().filter_all() )                
            elif P is self.monoid() :
                return self._element_class( self,
                        {self.characters().one_element():
                                {x: self.base_ring().one_element()}},
                        self.action().filter_all(),
                        symmetrise = True  )
            
        return EquivariantMonoidPowerSeriesAmbient_abstract._element_constructor_(self, x)
Exemple #13
0
    def cuboctahedron(self):
        """
        An Archimedean solid with 12 vertices and 14 faces.  Dual to
        the rhombic dodecahedron.

        EXAMPLES::

            sage: co = polytopes.cuboctahedron()
            sage: co.n_vertices()
            12
            sage: co.n_inequalities()
            14
        """
        one = Integer(1)
        v = [[0, -one / 2, -one / 2], [0, one / 2, -one / 2],
             [one / 2, -one / 2, 0], [one / 2, one / 2, 0],
             [one / 2, 0, one / 2], [one / 2, 0, -one / 2],
             [0, one / 2, one / 2], [0, -one / 2, one / 2],
             [-one / 2, 0, one / 2], [-one / 2, one / 2, 0],
             [-one / 2, 0, -one / 2], [-one / 2, -one / 2, 0]]
        return Polyhedron(vertices=v)
Exemple #14
0
    def num_coeffs(self, T=1):
        """
        Return number of coefficients `a_n` that are needed in
        order to perform most relevant `L`-function computations to
        the desired precision.

        EXAMPLES::

            sage: E = EllipticCurve('11a')
            sage: L = E.lseries().dokchitser()
            sage: L.num_coeffs()
            26
            sage: E = EllipticCurve('5077a')
            sage: L = E.lseries().dokchitser()
            sage: L.num_coeffs()
            568
            sage: L = Dokchitser(conductor=1, gammaV=[0], weight=1, eps=1, poles=[1], residues=[-1], init='1')
            sage: L.num_coeffs()
            4
        """
        return Integer(self._gp_call_inst('cflength', T))
Exemple #15
0
def lfsr_autocorrelation(L, p, k):
    """
    INPUT:


    -  ``L`` - is a periodic sequence of elements of ZZ or
       GF(2). L must have length = p

    -  ``p`` - the period of L

    -  ``k`` - k is an integer (0 k p)


    OUTPUT: autocorrelation sequence of L

    EXAMPLES::

        sage: F = GF(2)
        sage: o = F(0)
        sage: l = F(1)
        sage: key = [l,o,o,l]; fill = [l,l,o,l]; n = 20
        sage: s = lfsr_sequence(key,fill,n)
        sage: lfsr_autocorrelation(s,15,7)
        4/15
        sage: lfsr_autocorrelation(s,int(15),7)
        4/15

    AUTHORS:

    - Timothy Brock (2006-04-17)
    """
    if not isinstance(L, list):
        raise TypeError("L (=%s) must be a list" % L)
    p = Integer(p)
    _p = int(p)
    k = int(k)
    L0 = L[:_p]  # slices makes a copy
    L0 = L0 + L0[:k]
    L1 = [int(L0[i]) * int(L0[i + k]) / p for i in range(_p)]
    return sum(L1)
Exemple #16
0
    def _induced_flags(self, n, tg, type_edges):

        flag_counts = {}
        flags = []
        total = 0

        for p in Tuples([0, 1], binomial(n, 2) - binomial(tg.n, 2)):

            edges = list(type_edges)

            c = 0
            for i in range(tg.n + 1, n + 1):
                for j in range(1, i):
                    if p[c] == 1:
                        edges.append((j, i))
                    c += 1

            ig = ThreeGraphFlag()
            ig.n = n
            ig.t = tg.n

            for s in Combinations(list(range(1, n + 1)), 3):
                ind_edges = [e for e in edges if e[0] in s and e[1] in s]
                if len(ind_edges) == 1 or len(ind_edges) == 3:
                    ig.add_edge(s)

            it = ig.induced_subgraph(list(range(1, tg.n + 1)))
            if tg.is_labelled_isomorphic(it):
                ig.make_minimal_isomorph()

                ghash = hash(ig)
                if ghash in flag_counts:
                    flag_counts[ghash] += 1
                else:
                    flags.append(ig)
                    flag_counts[ghash] = 1

            total += 1

        return [(f, flag_counts[hash(f)] / Integer(total)) for f in flags]
Exemple #17
0
def _cl_term(n, R = RationalField()):
    r"""
    Compute the order-n term of the cycle index series of the virtual species `\Omega`,
    the compositional inverse of the species `E^{+}` of nonempty sets.

    EXAMPLES::

        sage: from sage.combinat.species.generating_series import _cl_term
        sage: [_cl_term(i) for i in range(4)]
        [0, p[1], -1/2*p[1, 1] - 1/2*p[2], 1/3*p[1, 1, 1] - 1/3*p[3]]
    """
    n = Integer(n)  # check that n is an integer

    p = SymmetricFunctions(R).power()

    res = p.zero()
    if n == 1:
        res = p([1])
    elif n > 1:
        res = 1/n * ((-1)**(n-1) * p([1])**n - sum(d * p([n // d]).plethysm(_cl_term(d, R)) for d in divisors(n)[:-1]))

    return res
Exemple #18
0
    def additive_order(self):
        """
        Return the additive order of this element.

        EXAMPLES::

            sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1, 4*V.2])
            sage: Q = V/W; Q
            Finitely generated module V/W over Integer Ring with invariants (4, 12)
            sage: Q.0.additive_order()
            4
            sage: Q.1.additive_order()
            12
            sage: (Q.0+Q.1).additive_order()
            12
            sage: V = span([[1/2,1,1],[3/2,2,1],[0,0,1]],ZZ); W = V.span([2*V.0+4*V.1, 9*V.0+12*V.1])
            sage: Q = V/W; Q
            Finitely generated module V/W over Integer Ring with invariants (12, 0)
            sage: Q.0.additive_order()
            12
            sage: type(Q.0.additive_order())
            <type 'sage.rings.integer.Integer'>
            sage: Q.1.additive_order()
            +Infinity
        """
        Q = self.parent()
        I = Q.invariants()
        v = self.vector()

        from sage.rings.all import infinity, Mod, Integer
        from sage.arith.all import lcm
        n = Integer(1)
        for i, a in enumerate(I):
            if a == 0:
                if v[i] != 0:
                    return infinity
            else:
                n = lcm(n, Mod(v[i],a).additive_order())
        return n
Exemple #19
0
 def __init__(self, parent, val=0, quick=False):
     ModuleElement.__init__(self, parent)
     self._parent = parent
     self._n = self._parent._n
     self._nhalf = Integer(self._n / 2)
     self._depth = self._parent._depth
     if quick:
         self._val = val
     else:
         if isinstance(val, self.__class__):
             d = min([val._parent._depth, parent._depth])
             assert (val._parent.weight() == parent.weight())
             self._val = Matrix(self._parent._R, self._depth, 1, 0)
             for ii in range(d):
                 self._val[ii, 0] = val._val[ii, 0]
         else:
             try:
                 self._val = MatrixSpace(self._parent._R, self._depth,
                                         1)(val)
             except:
                 self._val = val * ones_matrix(self._parent._R, self._depth,
                                               1)
Exemple #20
0
class ParamodularFormD2_classical ( ParamodularFormD2_generic, ModularForm_generic ) :

    def is_gritsenko_form(self) :
        raise NotImplementedError    

    def atkin_lehner_eigenvalue_numerical(self, (tau1, z, tau2)) :
        from sage.libs.mpmath import mp
        from sage.libs.mpmath.mp import exp, pi
        from sage.libs.mpmath.mp import j as i
        
        if not Integer(self.__level()).is_prime() :
            raise ValueError, "The Atkin Lehner involution is only unique if the level is a prime"
        
        precision = ParamodularFormD2Filter_trace(self.precision())
        
        s = Sequence([tau1, z, tau2])
        if not is_ComplexField(s) :
            mp_precision = 30
        else :
            mp_precision = ceil(3.33 * s.universe().precision() ) 
        mp.dps = mp_precision
                
        (tau1, z, tau2) = tuple(s)
        (tau1p, zp, tau2p) = (self.level()*tau1, self.level()*z, self.level()*tau2)
        
        (e_tau1, e_z, e_tau2) = (exp(2 * pi * i * tau1), exp(2 * pi * i * z), exp(2 * pi * i * tau2))
        (e_tau1p, e_zp, e_tau2p) = (exp(2 * pi * i * tau1p), exp(2 * pi * i * zp), exp(2 * pi * i * tau2p))
        
        self_value = s.universe().zero()
        trans_value = s.universe().zero()
        
        for k in precision :
            (a,b,c) = apply_GL_to_form(self._P1List()(k[1]), k[0])
            
            self_value = self_value + self[k] * (e_tau1**a * e_z**b * e_tau2**c)
            trans_value = trans_value + self[k] * (e_tau1p**a * e_zp**b * e_tau2p**c)
        
        return trans_value / self_value
    def symm_subgraph_densities(self, n):

        sharp_graph_counts = {}
        sharp_graphs = []

        total, orb_reps = self.tuple_orbit_reps(n)

        sys.stdout.write("Found %d orbits.\n" % len(orb_reps))

        for P, factor in orb_reps.iteritems():

            ig = self._graph.degenerate_induced_subgraph(P)
            ig.make_minimal_isomorph()

            ghash = hash(ig)
            if ghash in sharp_graph_counts:
                sharp_graph_counts[ghash] += factor
            else:
                sharp_graphs.append(ig)
                sharp_graph_counts[ghash] = factor

        return [(g, sharp_graph_counts[hash(g)] / Integer(total))
                for g in sharp_graphs]
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
Exemple #23
0
def DihedralPresentation(n):
    r"""
    Build the Dihedral group of order `2n` as a finitely presented group.

    INPUT:

    - ``n`` -- The size of the set that `D_n` is acting on.

    OUTPUT:

    Dihedral group of order `2n`.

    EXAMPLES::

        sage: D = groups.presentation.Dihedral(7); D
        Finitely presented group < a, b | a^7, b^2, (a*b)^2 >
        sage: D.as_permutation_group().is_isomorphic(DihedralGroup(7))
        True

    TESTS::

        sage: n = 9
        sage: D = groups.presentation.Dihedral(n)
        sage: D.ngens() == 2
        True
        sage: groups.presentation.Dihedral(0)
        Traceback (most recent call last):
        ...
        ValueError: finitely presented group order must be positive
    """
    n = Integer(n)
    if n < 1:
        raise ValueError('finitely presented group order must be positive')
    F = FreeGroup(['a', 'b'])
    rls = F([1])**n, F([2])**2, (F([1]) * F([2]))**2
    return FinitelyPresentedGroup(F, rls)
Exemple #24
0
    def hecke_matrix(self, n):
        """
        Return the matrix of the n-th Hecke operator acting on this
        homology group.

        EXAMPLES::

            sage: t = J1(13).homology(QQ).hecke_matrix(3); t
            [-2  2  2 -2]
            [-2  0  2  0]
            [ 0  0  0 -2]
            [ 0  0  2 -2]
            sage: t.base_ring()
            Rational Field
            sage: t = J1(13).homology(GF(3)).hecke_matrix(3); t
            [1 2 2 1]
            [1 0 2 0]
            [0 0 0 1]
            [0 0 2 1]
            sage: t.base_ring()
            Finite Field of size 3
        """
        n = Integer(n)
        return self.abelian_variety()._rational_hecke_matrix(n)
Exemple #25
0
 def r(self):
     q = Integer(self.q)
     _, r = q.is_prime_power(get_data=True)
     return r
def _semistable_reducible_primes(E, verbose=False):
    r"""Find a list containing all semistable primes l unramified in K/QQ
    for which the Galois image for E could be reducible.

    INPUT:

    - ``E`` - EllipticCurve - over a number field.

    OUTPUT:

    A list of primes, which contains all primes `l` unramified in
    `K/\mathbb{QQ}`, such that `E` is semistable at all primes lying
    over `l`, and the Galois image at `l` is reducible. If `E` has CM
    defined over its ground field, a ``ValueError`` is raised.

    EXAMPLES::

        sage: E = EllipticCurve([0, -1, 1, -10, -20]) # X_0(11)
        sage: 5 in sage.schemes.elliptic_curves.gal_reps_number_field._semistable_reducible_primes(E)
        True

    This example, over a quintic field with Galois group `S_5`, took a
    very long time before :trac:`22343`::

        sage: K.<a> = NumberField(x^5 - 6*x^3 + 8*x - 1)
        sage: E = EllipticCurve(K, [a^3 - 2*a, a^4 - 2*a^3 - 4*a^2 + 6*a + 1, a + 1, -a^3 + a + 1, -a])
        sage: from sage.schemes.elliptic_curves.gal_reps_number_field import _semistable_reducible_primes
        sage: _semistable_reducible_primes(E)
        [2, 5, 53, 1117]
    """
    if verbose: print("In _semistable_reducible_primes with E={}".format(E.ainvs()))
    K = E.base_field()
    d = K.degree()

    deg_one_primes = deg_one_primes_iter(K, principal_only=True)

    bad_primes = set([]) # This will store the output.

    # We find two primes (of distinct residue characteristics) which are
    # of degree 1, unramified in K/Q, and at which E has good reduction.
    # Each of these primes will give us a nontrivial divisibility constraint
    # on the exceptional primes l. For both of these primes P, we precompute
    # a generator and the characteristic polynomial of Frob_P^12.

    precomp = []
    last_p = 0 # The residue characteristic of the most recent prime.

    while len(precomp) < 2:
        P = next(deg_one_primes)
        p = P.norm()
        if p != last_p and (d==1 or P.ramification_index() == 1) and E.has_good_reduction(P):
            precomp.append(P)
            last_p = p

    Px, Py = precomp
    x, y = [P.gens_reduced()[0] for P in precomp]
    EmodPx = E.reduction(Px) if d>1 else E.reduction(x)
    EmodPy = E.reduction(Py) if d>1 else E.reduction(y)
    fxpol = EmodPx.frobenius_polynomial()
    fypol = EmodPy.frobenius_polynomial()
    fx12pol = fxpol.adams_operator(12) # roots are 12th powers of those of fxpol
    fy12pol = fypol.adams_operator(12)
    px = x.norm() if d>1 else x
    py = y.norm() if d>1 else x
    Zx = fxpol.parent()
    xpol = x.charpoly() if d>1 else Zx([-x,1])
    ypol = y.charpoly() if d>1 else Zx([-y,1])

    if verbose: print("Finished precomp, x={} (p={}), y={} (p={})".format(x,px,y,py))

    for w in range(1+d/2):
        if verbose: print("w = {}".format(w))
        gx = xpol.symmetric_power(w).adams_operator(12).resultant(fx12pol)
        gy = ypol.symmetric_power(w).adams_operator(12).resultant(fy12pol)
        if verbose: print("computed gx and gy")

        gxn = Integer(gx.absolute_norm()) if d>1 else gx
        gyn = Integer(gy.absolute_norm()) if d>1 else gy
        gxyn = gxn.gcd(gyn)
        if gxyn:
            xprimes = gxyn.prime_factors()
            if verbose: print("adding prime factors {} of {} to {}".format(xprimes, gxyn, sorted(bad_primes)))
            bad_primes.update(xprimes)
            if verbose: print("...done, bad_primes now {}".format(sorted(bad_primes)))
            continue
        else:
            if verbose: print("gx and gy both 0!")


        ## It is possible that our curve has CM. ##

        # Our character must be of the form Nm^K_F for an imaginary
        # quadratic subfield F of K (which is the CM field if E has CM).

        # Note that this can only happen when d is even, w=d/2, and K
        # contains (or the Galois closure of K contains?) the
        # imaginary quadratic field F = Q(sqrt(a)) which is the
        # splitting field of both fx12pol and fy12pol.  We compute a
        # and relativise K over F:

        a = fx12pol.discriminant().squarefree_part()

        # Construct a field isomorphic to K but a relative extension over QQ(sqrt(a)).

        # See #19229: the names given here, which are not used, should
        # not be the name of the generator of the base field.

        rootsa = K(a).sqrt(all=True) # otherwise if a is not a square the
                                     # returned result is in the symbolic ring!
        try:
            roota = rootsa[0]
        except IndexError:
            raise RuntimeError("error in _semistable_reducible_primes: K={} does not contain sqrt({})".format(K,a))
        K_rel = K.relativize(roota, ['name1','name2'])
        iso = K_rel.structure()[1] # an isomorphism from K to K_rel
        E_rel = E.change_ring(iso) # same as E but over K_rel

        ## We try again to find a nontrivial divisibility condition. ##

        div = 0
        patience = 5 * K.absolute_degree()
        # Number of Frobenius elements to check before suspecting that E
        # has CM and computing the set of CM j-invariants of K to check.
        # TODO: Is this the best value for this parameter?

        while div==0 and patience>0:
            P = next(deg_one_primes) # a prime of K not K_rel
            while E.has_bad_reduction(P):
                P = next(deg_one_primes)

            if verbose: print("trying P = {}...".format(P))
            EmodP = E.reduction(P)
            fpol = EmodP.frobenius_polynomial()
            if verbose: print("...good reduction, frobenius poly = {}".format(fpol))
            x = iso(P.gens_reduced()[0]).relative_norm()
            xpol = x.charpoly().adams_operator(12)
            div2 = Integer(xpol.resultant(fpol.adams_operator(12)) // x.norm()**12)
            if div2:
                div = div2.isqrt()
                assert div2==div**2
                if verbose: print("...div = {}".format(div))
            else:
                if verbose: print("...div = 0, continuing")
                patience -= 1

        if patience == 0:
            # We suspect that E has CM, so we check:
            if E.has_cm():
                raise ValueError("In _semistable_reducible_primes, the curve E should not have CM.")

        assert div != 0
        # We found our divisibility constraint.

        xprimes = div.prime_factors()
        if verbose: print("...adding prime factors {} of {} to {}...".format(xprimes,div, sorted(bad_primes)))
        bad_primes.update(xprimes)
        if verbose: print("...done, bad_primes now {}".format(sorted(bad_primes)))

    L = sorted(bad_primes)
    return L
Exemple #27
0
    def _tate(self, proof = None, globally = False):
        r"""
        Tate's algorithm for an elliptic curve over a number field.

        Computes both local reduction data at a prime ideal and a
        local minimal model.

        The model is not required to be integral on input.  If `P` is
        principal, uses a generator as uniformizer, so it will not
        affect integrality or minimality at other primes.  If `P` is not
        principal, the minimal model returned will preserve
        integrality at other primes, but not minimality.

        The optional argument globally, when set to True, tells the algorithm to use the generator of the prime ideal if it is principal. Otherwise just any uniformizer will be used.

        .. note:: 

           Called only by ``EllipticCurveLocalData.__init__()``.

        OUTPUT:

        (tuple) ``(Emin, p, val_disc, fp, KS, cp)`` where:

        - ``Emin`` (EllipticCurve) is a model (integral and) minimal at P
        - ``p`` (int) is the residue characteristic
        - ``val_disc`` (int) is the valuation of the local minimal discriminant
        - ``fp`` (int) is the valuation of the conductor
        - ``KS`` (string) is the Kodaira symbol
        - ``cp`` (int) is the Tamagawa number


        EXAMPLES (this raised a type error in sage prior to 4.4.4, see :trac:`7930`) ::

            sage: E = EllipticCurve('99d1')

            sage: R.<X> = QQ[]
            sage: K.<t> = NumberField(X^3 + X^2 - 2*X - 1)
            sage: L.<s> = NumberField(X^3 + X^2 - 36*X - 4)

            sage: EK = E.base_extend(K)
            sage: toK = EK.torsion_order()
            sage: da = EK.local_data()  # indirect doctest

            sage: EL = E.base_extend(L)
            sage: da = EL.local_data()  # indirect doctest

        EXAMPLES:

        The following example shows that the bug at :trac:`9324` is fixed::

            sage: K.<a> = NumberField(x^2-x+6)
            sage: E = EllipticCurve([0,0,0,-53160*a-43995,-5067640*a+19402006])
            sage: E.conductor() # indirect doctest
            Fractional ideal (18, 6*a)

        The following example shows that the bug at :trac:`9417` is fixed::

            sage: K.<a> = NumberField(x^2+18*x+1)
            sage: E = EllipticCurve(K, [0, -36, 0, 320, 0])
            sage: E.tamagawa_number(K.ideal(2))
            4

        This is to show that the bug :trac:`11630` is fixed. (The computation of the class group would produce a warning)::
        
            sage: K.<t> = NumberField(x^7-2*x+177)
            sage: E = EllipticCurve([0,1,0,t,t])
            sage: P = K.ideal(2,t^3 + t + 1)
            sage: E.local_data(P).kodaira_symbol()
            II

        """
        E = self._curve
        P = self._prime
        K = E.base_ring()
        OK = K.maximal_order()
        t = verbose("Running Tate's algorithm with P = %s"%P, level=1)
        F = OK.residue_field(P)
        p = F.characteristic()

        # In case P is not principal we mostly use a uniformiser which
        # is globally integral (with positive valuation at some other
        # primes); for this to work, it is essential that we can
        # reduce (mod P) elements of K which are not integral (but are
        # P-integral).  However, if the model is non-minimal and we
        # end up dividing a_i by pi^i then at that point we use a
        # uniformiser pi which has non-positive valuation at all other
        # primes, so that we can divide by it without losing
        # integrality at other primes.
           
        if globally:
            principal_flag = P.is_principal()
        else: 
            principal_flag = False
            
        if (K is QQ) or principal_flag :
            pi = P.gens_reduced()[0]
            verbose("P is principal, generator pi = %s"%pi, t, 1)
        else:
            pi = K.uniformizer(P, 'positive')
            verbose("uniformizer pi = %s"%pi, t, 1)
        pi2 = pi*pi; pi3 = pi*pi2; pi4 = pi*pi3
        pi_neg = None
        prime = pi if K is QQ else P

        pval = lambda x: x.valuation(prime)
        pdiv = lambda x: x.is_zero() or pval(x) > 0
        # Since ResidueField is cached in a way that
        # does not care much about embeddings of number
        # fields, it can happen that F.p.ring() is different
        # from K. This is a problem: If F.p.ring() has no
        # embedding but K has, then there is no coercion
        # from F.p.ring().maximal_order() to K. But it is
        # no problem to do an explicit conversion in that
        # case (Simon King, trac ticket #8800).

        from sage.categories.pushout import pushout, CoercionException
        try:
            if hasattr(F.p.ring(), 'maximal_order'): # it is not ZZ
                _tmp_ = pushout(F.p.ring().maximal_order(),K)
            pinv = lambda x: F.lift(~F(x))
            proot = lambda x,e: F.lift(F(x).nth_root(e, extend = False, all = True)[0])
            preduce = lambda x: F.lift(F(x))
        except CoercionException: # the pushout does not exist, we need conversion
            pinv = lambda x: K(F.lift(~F(x)))
            proot = lambda x,e: K(F.lift(F(x).nth_root(e, extend = False, all = True)[0]))
            preduce = lambda x: K(F.lift(F(x)))

        def _pquadroots(a, b, c):
            r"""
            Local function returning True iff `ax^2 + bx + c` has roots modulo `P`
            """
            (a, b, c) = (F(a), F(b), F(c))
            if a == 0:
                return (b != 0) or (c == 0)
            elif p == 2:
                return len(PolynomialRing(F, "x")([c,b,a]).roots()) > 0
            else:
                return (b**2 - 4*a*c).is_square()
        def _pcubicroots(b, c, d):
            r"""
            Local function returning the number of roots of `x^3 +
            b*x^2 + c*x + d` modulo `P`, counting multiplicities
            """

            return sum([rr[1] for rr in PolynomialRing(F, 'x')([F(d), F(c), F(b), F(1)]).roots()],0)

        if p == 2:
            halfmodp = OK(Integer(0))
        else:
            halfmodp = pinv(Integer(2))

        A = E.a_invariants()
        A = [0, A[0], A[1], A[2], A[3], 0, A[4]]
        indices = [1,2,3,4,6]
        if min([pval(a) for a in A if a != 0]) < 0:
            verbose("Non-integral model at P: valuations are %s; making integral"%([pval(a) for a in A if a != 0]), t, 1)
            e = 0
            for i in range(7):
                if A[i] != 0:
                    e = max(e, (-pval(A[i])/i).ceil())
            pie = pi**e
            for i in range(7):
                if A[i] != 0:
                    A[i] *= pie**i
            verbose("P-integral model is %s, with valuations %s"%([A[i] for i in indices], [pval(A[i]) for i in indices]), t, 1)

        split = None # only relevant for multiplicative reduction

        (a1, a2, a3, a4, a6) = (A[1], A[2], A[3], A[4], A[6])
        while True:
            C = EllipticCurve([a1, a2, a3, a4, a6]);
            (b2, b4, b6, b8) = C.b_invariants()
            (c4, c6) = C.c_invariants()
            delta = C.discriminant()
            val_disc = pval(delta)

            if val_disc == 0:
                ## Good reduction already
                cp = 1
                fp = 0
                KS = KodairaSymbol("I0")
                break #return

            # Otherwise, we change coordinates so that p | a3, a4, a6
            if p == 2:
                if pdiv(b2):
                    r = proot(a4, 2)
                    t = proot(((r + a2)*r + a4)*r + a6, 2)
                else:
                    temp = pinv(a1)
                    r = temp * a3
                    t = temp * (a4 + r*r)
            elif p == 3:
                if pdiv(b2):
                    r = proot(-b6, 3)
                else:
                    r = -pinv(b2) * b4
                t = a1 * r + a3
            else:
                if pdiv(c4):
                    r = -pinv(12) * b2
                else:
                    r = -pinv(12*c4) * (c6 + b2 * c4)
                t = -halfmodp * (a1 * r + a3)
            r = preduce(r)
            t = preduce(t)
            verbose("Before first transform C = %s"%C)
            verbose("[a1,a2,a3,a4,a6] = %s"%([a1, a2, a3, a4, a6]))
            C = C.rst_transform(r, 0, t)
            (a1, a2, a3, a4, a6) = C.a_invariants()
            (b2, b4, b6, b8) = C.b_invariants()
            if min([pval(a) for a in (a1, a2, a3, a4, a6) if a != 0]) < 0:
                raise RuntimeError("Non-integral model after first transform!")
            verbose("After first transform %s\n, [a1,a2,a3,a4,a6] = %s\n, valuations = %s"%([r, 0, t], [a1, a2, a3, a4, a6], [pval(a1), pval(a2), pval(a3), pval(a4), pval(a6)]), t, 2)
            if pval(a3) == 0:
                raise RuntimeError("p does not divide a3 after first transform!")
            if pval(a4) == 0:
                raise RuntimeError("p does not divide a4 after first transform!")
            if pval(a6) == 0:
                raise RuntimeError("p does not divide a6 after first transform!")

            # Now we test for Types In, II, III, IV
            # NB the c invariants never change.

            if not pdiv(c4):
                # Multiplicative reduction: Type In (n = val_disc)
                split = False
                if _pquadroots(1, a1, -a2):
                    cp = val_disc
                    split = True
                elif Integer(2).divides(val_disc):
                    cp = 2
                else:
                    cp = 1
                KS = KodairaSymbol("I%s"%val_disc)
                fp = 1
                break #return

            # Additive reduction

            if pval(a6) < 2:
                ## Type II
                KS = KodairaSymbol("II")
                fp = val_disc
                cp = 1
                break #return
            if pval(b8) < 3:
                ## Type III
                KS = KodairaSymbol("III")
                fp = val_disc - 1
                cp = 2
                break #return
            if pval(b6) < 3:
                ## Type IV
                cp = 1
                a3t = preduce(a3/pi)
                a6t = preduce(a6/pi2)
                if _pquadroots(1, a3t, -a6t): cp = 3
                KS = KodairaSymbol("IV")
                fp = val_disc - 2
                break #return

            # If our curve is none of these types, we change coords so that
            # p | a1, a2;  p^2 | a3, a4;  p^3 | a6
            if p == 2:
                s = proot(a2, 2)        # so s^2=a2 (mod pi)
                t = pi*proot(a6/pi2, 2) # so t^2=a6 (mod pi^3)
            elif p == 3:
                s = a1       # so a1'=2s+a1=3a1=0 (mod pi)
                t = a3       # so a3'=2t+a3=3a3=0 (mod pi^2)
            else:
                s = -a1*halfmodp   # so a1'=2s+a1=0 (mod pi)
                t = -a3*halfmodp   # so a3'=2t+a3=0 (mod pi^2)
            C = C.rst_transform(0, s, t)
            (a1, a2, a3, a4, a6) = C.a_invariants()
            (b2, b4, b6, b8) = C.b_invariants()
            verbose("After second transform %s\n[a1, a2, a3, a4, a6] = %s\nValuations: %s"%([0, s, t], [a1,a2,a3,a4,a6],[pval(a1),pval(a2),pval(a3),pval(a4),pval(a6)]), t, 2)
            if pval(a1) == 0:
                raise RuntimeError("p does not divide a1 after second transform!")
            if pval(a2) == 0:
                raise RuntimeError("p does not divide a2 after second transform!")
            if pval(a3) < 2:
                raise RuntimeError("p^2 does not divide a3 after second transform!")
            if pval(a4) < 2:
                raise RuntimeError("p^2 does not divide a4 after second transform!")
            if pval(a6) < 3:
                raise RuntimeError("p^3 does not divide a6 after second transform!")
            if min(pval(a1), pval(a2), pval(a3), pval(a4), pval(a6)) < 0:
                raise RuntimeError("Non-integral model after second transform!")

            # Analyze roots of the cubic T^3 + bT^2 + cT + d = 0 mod P, where
            # b = a2/p, c = a4/p^2, d = a6/p^3
            b = preduce(a2/pi)
            c = preduce(a4/pi2)
            d = preduce(a6/pi3)
            bb = b*b
            cc = c*c
            bc = b*c
            w = 27*d*d - bb*cc + 4*b*bb*d - 18*bc*d + 4*c*cc
            x = 3*c - bb
            if pdiv(w):
                if pdiv(x):
                    sw = 3
                else:
                    sw = 2
            else:
                sw = 1
            verbose("Analyzing roots of cubic T^3 + %s*T^2 + %s*T + %s, case %s"%(b, c, d, sw), t, 1)
            if sw == 1:
                ## Three distinct roots - Type I*0
                verbose("Distinct roots", t, 1)
                KS = KodairaSymbol("I0*")
                cp = 1 + _pcubicroots(b, c, d)
                fp = val_disc - 4
                break #return
            elif sw == 2:
                ## One double root - Type I*m for some m
                verbose("One double root", t, 1)
                ## Change coords so that the double root is T = 0 mod p
                if p == 2:
                    r = proot(c, 2)
                elif p == 3:
                    r = c * pinv(b)
                else:
                    r = (bc - 9*d)*pinv(2*x)
                r = pi * preduce(r)
                C = C.rst_transform(r, 0, 0)
                (a1, a2, a3, a4, a6) = C.a_invariants()
                (b2, b4, b6, b8) = C.b_invariants()
                # The rest of this branch is just to compute cp, fp, KS.
                # We use pi to keep transforms integral.
                ix = 3; iy = 3; mx = pi2; my = mx
                while True:
                    a2t = preduce(a2 / pi)
                    a3t = preduce(a3 / my)
                    a4t = preduce(a4 / (pi*mx))
                    a6t = preduce(a6 / (mx*my))
                    if pdiv(a3t*a3t + 4*a6t):
                        if p == 2:
                            t = my*proot(a6t, 2)
                        else:
                            t = my*preduce(-a3t*halfmodp)
                        C = C.rst_transform(0, 0, t)
                        (a1, a2, a3, a4, a6) = C.a_invariants()
                        (b2, b4, b6, b8) = C.b_invariants()
                        my *= pi
                        iy += 1
                        a2t = preduce(a2 / pi)
                        a3t = preduce(a3/my)
                        a4t = preduce(a4/(pi*mx))
                        a6t = preduce(a6/(mx*my))
                        if pdiv(a4t*a4t - 4*a6t*a2t):
                            if p == 2:
                                r = mx*proot(a6t*pinv(a2t), 2)
                            else:
                                r = mx*preduce(-a4t*pinv(2*a2t))
                            C = C.rst_transform(r, 0, 0)
                            (a1, a2, a3, a4, a6) = C.a_invariants()
                            (b2, b4, b6, b8) = C.b_invariants()
                            mx *= pi
                            ix += 1 # and stay in loop
                        else:
                            if _pquadroots(a2t, a4t, a6t):
                                cp = 4
                            else:
                                cp = 2
                            break # exit loop
                    else:
                        if _pquadroots(1, a3t, -a6t):
                            cp = 4
                        else:
                            cp = 2
                        break
                KS = KodairaSymbol("I%s*"%(ix+iy-5))
                fp = val_disc - ix - iy + 1
                break #return
            else: # sw == 3
                ## The cubic has a triple root
                verbose("Triple root", t, 1)
                ## First we change coordinates so that T = 0 mod p
                if p == 2:
                    r = b
                elif p == 3:
                    r = proot(-d, 3)
                else:
                    r = -b * pinv(3)
                r = pi*preduce(r)
                C = C.rst_transform(r, 0, 0)
                (a1, a2, a3, a4, a6) = C.a_invariants()
                (b2, b4, b6, b8) = C.b_invariants()
                verbose("After third transform %s\n[a1,a2,a3,a4,a6] = %s\nValuations: %s"%([r,0,0],[a1,a2,a3,a4,a6],[pval(ai) for ai in [a1,a2,a3,a4,a6]]), t, 2)
                if min(pval(ai) for ai in [a1,a2,a3,a4,a6]) < 0:
                    raise RuntimeError("Non-integral model after third transform!")
                if pval(a2) < 2 or pval(a4) < 3 or pval(a6) < 4:
                    raise RuntimeError("Cubic after transform does not have a triple root at 0")
                a3t = preduce(a3/pi2)
                a6t = preduce(a6/pi4)
                # We test for Type IV*
                if not pdiv(a3t*a3t + 4*a6t):
                    cp = 3 if _pquadroots(1, a3t, -a6t) else 1
                    KS = KodairaSymbol("IV*")
                    fp = val_disc - 6
                    break #return
                # Now change coordinates so that p^3|a3, p^5|a6
                if p==2:
                    t = -pi2*proot(a6t, 2)
                else:
                    t = pi2*preduce(-a3t*halfmodp)
                C = C.rst_transform(0, 0, t)
                (a1, a2, a3, a4, a6) = C.a_invariants()
                (b2, b4, b6, b8) = C.b_invariants()
                # We test for types III* and II*
                if pval(a4) < 4:
                    ## Type III*
                    KS = KodairaSymbol("III*")
                    fp = val_disc - 7
                    cp = 2
                    break #return
                if pval(a6) < 6:
                    ## Type II*
                    KS = KodairaSymbol("II*")
                    fp = val_disc - 8
                    cp = 1
                    break #return
                if pi_neg is None:
                    if principal_flag:
                        pi_neg = pi
                    else:
                        pi_neg = K.uniformizer(P, 'negative')
                    pi_neg2 = pi_neg*pi_neg
                    pi_neg3 = pi_neg*pi_neg2
                    pi_neg4 = pi_neg*pi_neg3
                    pi_neg6 = pi_neg4*pi_neg2
                a1 /= pi_neg
                a2 /= pi_neg2
                a3 /= pi_neg3
                a4 /= pi_neg4
                a6 /= pi_neg6
                verbose("Non-minimal equation, dividing out...\nNew model is %s"%([a1, a2, a3, a4, a6]), t, 1)
        return (C, p, val_disc, fp, KS, cp, split)
Exemple #28
0
 def p(self):
     q = Integer(self.q)
     p, _ = q.is_prime_power(get_data=True)
     return p
Exemple #29
0
def hilbert_class_polynomial(D, algorithm=None):
    r"""
    Return the Hilbert class polynomial for discriminant `D`.

    INPUT:

    - ``D`` (int) -- a negative integer congruent to 0 or 1 modulo 4.

    - ``algorithm`` (string, default None).

    OUTPUT:

    (integer polynomial) The Hilbert class polynomial for the
    discriminant `D`.

    ALGORITHM:

    - If ``algorithm`` = "arb" (default): Use Arb's implementation which uses complex interval arithmetic.

    - If ``algorithm`` = "sage": Use complex approximations to the roots.

    - If ``algorithm`` = "magma": Call the appropriate Magma function (if available).

    AUTHORS:

    - Sage implementation originally by Eduardo Ocampo Alvarez and
      AndreyTimofeev

    - Sage implementation corrected by John Cremona (using corrected precision bounds from Andreas Enge)

    - Magma implementation by David Kohel

    EXAMPLES::

        sage: hilbert_class_polynomial(-4)
        x - 1728
        sage: hilbert_class_polynomial(-7)
        x + 3375
        sage: hilbert_class_polynomial(-23)
        x^3 + 3491750*x^2 - 5151296875*x + 12771880859375
        sage: hilbert_class_polynomial(-37*4)
        x^2 - 39660183801072000*x - 7898242515936467904000000
        sage: hilbert_class_polynomial(-37*4, algorithm="magma") # optional - magma
        x^2 - 39660183801072000*x - 7898242515936467904000000
        sage: hilbert_class_polynomial(-163)
        x + 262537412640768000
        sage: hilbert_class_polynomial(-163, algorithm="sage")
        x + 262537412640768000
        sage: hilbert_class_polynomial(-163, algorithm="magma") # optional - magma
        x + 262537412640768000

    TESTS::

        sage: all([hilbert_class_polynomial(d, algorithm="arb") == \
        ....:      hilbert_class_polynomial(d, algorithm="sage") \
        ....:        for d in range(-1,-100,-1) if d%4 in [0,1]])
        True

    """
    if algorithm is None:
        algorithm = "arb"

    D = Integer(D)
    if D >= 0:
        raise ValueError("D (=%s) must be negative" % D)
    if not (D % 4 in [0, 1]):
        raise ValueError("D (=%s) must be a discriminant" % D)

    if algorithm == "arb":
        import sage.libs.arb.arith
        return sage.libs.arb.arith.hilbert_class_polynomial(D)

    if algorithm == "magma":
        magma.eval("R<x> := PolynomialRing(IntegerRing())")
        f = str(magma.eval("HilbertClassPolynomial(%s)" % D))
        return IntegerRing()['x'](f)

    if algorithm != "sage":
        raise ValueError("%s is not a valid algorithm" % algorithm)

    from sage.quadratic_forms.binary_qf import BinaryQF_reduced_representatives
    from sage.rings.all import RR, ComplexField
    from sage.functions.all import elliptic_j

    # get all primitive reduced quadratic forms, (necessary to exclude
    # imprimitive forms when D is not a fundamental discriminant):

    rqf = BinaryQF_reduced_representatives(D, primitive_only=True)

    # compute needed precision
    #
    # NB: [https://arxiv.org/abs/0802.0979v1], quoting Enge (2006), is
    # incorrect.  Enge writes (2009-04-20 email to John Cremona) "The
    # source is my paper on class polynomials
    # [https://hal.inria.fr/inria-00001040] It was pointed out to me by
    # the referee after ANTS that the constant given there was
    # wrong. The final version contains a corrected constant on p.7
    # which is consistent with your example. It says:

    # "The logarithm of the absolute value of the coefficient in front
    # of X^j is bounded above by
    #
    # log (2*k_2) * h + pi * sqrt(|D|) * sum (1/A_i)
    #
    # independently of j", where k_2 \approx 10.163.

    h = len(rqf)  # class number
    c1 = 3.05682737291380  # log(2*10.63)
    c2 = sum([1 / RR(qf[0]) for qf in rqf], RR(0))
    prec = c2 * RR(3.142) * RR(D).abs().sqrt() + h * c1  # bound on log
    prec = prec * 1.45  # bound on log_2 (1/log(2) = 1.44..)
    prec = 10 + prec.ceil()  # allow for rounding error

    # set appropriate precision for further computing

    Dsqrt = D.sqrt(prec=prec)
    R = ComplexField(prec)['t']
    t = R.gen()
    pol = R(1)
    for qf in rqf:
        a, b, c = list(qf)
        tau = (b + Dsqrt) / (a << 1)
        pol *= (t - elliptic_j(tau))

    coeffs = [cof.real().round() for cof in pol.coefficients(sparse=False)]
    return IntegerRing()['x'](coeffs)
Exemple #30
0
 def r(self):
     q = Integer(self.q)
     _, r = q.is_prime_power(get_data=True)
     return r
Exemple #31
0
def check_prime(K, P):
    r"""
    Function to check that `P` determines a prime of `K`, and return that ideal.

    INPUT:

    - ``K`` -- a number field (including `\QQ`).

    - ``P`` -- an element of ``K`` or a (fractional) ideal of ``K``.

    OUTPUT:

    - If ``K`` is `\QQ`: the prime integer equal to or which generates `P`.

    - If ``K`` is not `\QQ`: the prime ideal equal to or generated by `P`.

    .. NOTE::

        If `P` is not a prime and does not generate a prime, a ``TypeError``
        is raised.

    EXAMPLES::

        sage: from sage.schemes.elliptic_curves.ell_local_data import check_prime
        sage: check_prime(QQ,3)
        3
        sage: check_prime(QQ,QQ(3))
        3
        sage: check_prime(QQ,ZZ.ideal(31))
        31
        sage: K.<a> = NumberField(x^2-5)
        sage: check_prime(K,a)
        Fractional ideal (a)
        sage: check_prime(K,a+1)
        Fractional ideal (a + 1)
        sage: [check_prime(K,P) for P in K.primes_above(31)]
        [Fractional ideal (5/2*a + 1/2), Fractional ideal (5/2*a - 1/2)]
        sage: L.<b> = NumberField(x^2+3)
        sage: check_prime(K, L.ideal(5))
        Traceback (most recent call last):
        ...
        TypeError: The ideal Fractional ideal (5) is not a prime ideal of Number Field in a with defining polynomial x^2 - 5
        sage: check_prime(K, L.ideal(b))
        Traceback (most recent call last):
        ...
        TypeError: No compatible natural embeddings found for Number Field in a with defining polynomial x^2 - 5 and Number Field in b with defining polynomial x^2 + 3
    """
    if K is QQ:
        if P in ZZ or isinstance(P, integer_types + (Integer,)):
            P = Integer(P)
            if P.is_prime():
                return P
            else:
                raise TypeError("The element %s is not prime" % (P,))
        elif P in QQ:
            raise TypeError("The element %s is not prime" % (P,))
        elif is_Ideal(P) and P.base_ring() is ZZ:
            if P.is_prime():
                return P.gen()
            else:
                raise TypeError("The ideal %s is not a prime ideal of %s" % (P, ZZ))
        else:
            raise TypeError("%s is neither an element of QQ or an ideal of %s" % (P, ZZ))

    if not is_NumberField(K):
        raise TypeError("%s is not a number field" % (K,))

    if is_NumberFieldFractionalIdeal(P) or P in K:
        # if P is an ideal, making sure it is an fractional ideal of K
        P = K.fractional_ideal(P)
        if P.is_prime():
            return P
        else:
            raise TypeError("The ideal %s is not a prime ideal of %s" % (P, K))

    raise TypeError("%s is not a valid prime of %s" % (P, K))
Exemple #32
0
def discriminants_with_bounded_class_number(hmax, B=None, proof=None):
    """
    Return dictionary with keys class numbers `h\le hmax` and values the
    list of all pairs `(D, f)`, with `D<0` a fundamental discriminant such
    that `Df^2` has class number `h`.  If the optional bound `B` is given,
    return only those pairs with fundamental `|D| \le B`, though `f` can
    still be arbitrarily large.

    INPUT:

    - ``hmax`` -- integer
    - `B` -- integer or None; if None returns all pairs
    - ``proof`` -- this code calls the PARI function ``qfbclassno``, so it
      could give wrong answers when ``proof``==``False``.  The default is
      whatever ``proof.number_field()`` is.  If ``proof==False`` and `B` is
      ``None``, at least the number of discriminants is correct, since it
      is double checked with Watkins's table.

    OUTPUT:

    - dictionary

    In case `B` is not given, we use Mark Watkins's: "Class numbers of
    imaginary quadratic fields" to compute a `B` that captures all `h`
    up to `hmax` (only available for `hmax\le100`).

    EXAMPLES::

        sage: v = sage.schemes.elliptic_curves.cm.discriminants_with_bounded_class_number(3)
        sage: list(v)
        [1, 2, 3]
        sage: v[1]
        [(-3, 3), (-3, 2), (-3, 1), (-4, 2), (-4, 1), (-7, 2), (-7, 1), (-8, 1), (-11, 1), (-19, 1), (-43, 1), (-67, 1), (-163, 1)]
        sage: v[2]
        [(-3, 7), (-3, 5), (-3, 4), (-4, 5), (-4, 4), (-4, 3), (-7, 4), (-8, 3), (-8, 2), (-11, 3), (-15, 2), (-15, 1), (-20, 1), (-24, 1), (-35, 1), (-40, 1), (-51, 1), (-52, 1), (-88, 1), (-91, 1), (-115, 1), (-123, 1), (-148, 1), (-187, 1), (-232, 1), (-235, 1), (-267, 1), (-403, 1), (-427, 1)]
        sage: v[3]
        [(-3, 9), (-3, 6), (-11, 2), (-19, 2), (-23, 2), (-23, 1), (-31, 2), (-31, 1), (-43, 2), (-59, 1), (-67, 2), (-83, 1), (-107, 1), (-139, 1), (-163, 2), (-211, 1), (-283, 1), (-307, 1), (-331, 1), (-379, 1), (-499, 1), (-547, 1), (-643, 1), (-883, 1), (-907, 1)]
        sage: v = sage.schemes.elliptic_curves.cm.discriminants_with_bounded_class_number(8, proof=False)
        sage: [len(v[h]) for h in v]
        [13, 29, 25, 84, 29, 101, 38, 208]

    Find all class numbers for discriminant up to 50::

        sage: sage.schemes.elliptic_curves.cm.discriminants_with_bounded_class_number(hmax=5, B=50)
        {1: [(-3, 3), (-3, 2), (-3, 1), (-4, 2), (-4, 1), (-7, 2), (-7, 1), (-8, 1), (-11, 1), (-19, 1), (-43, 1)], 2: [(-3, 7), (-3, 5), (-3, 4), (-4, 5), (-4, 4), (-4, 3), (-7, 4), (-8, 3), (-8, 2), (-11, 3), (-15, 2), (-15, 1), (-20, 1), (-24, 1), (-35, 1), (-40, 1)], 3: [(-3, 9), (-3, 6), (-11, 2), (-19, 2), (-23, 2), (-23, 1), (-31, 2), (-31, 1), (-43, 2)], 4: [(-3, 13), (-3, 11), (-3, 8), (-4, 10), (-4, 8), (-4, 7), (-4, 6), (-7, 8), (-7, 6), (-7, 3), (-8, 6), (-8, 4), (-11, 5), (-15, 4), (-19, 5), (-19, 3), (-20, 3), (-20, 2), (-24, 2), (-35, 3), (-39, 2), (-39, 1), (-40, 2), (-43, 3)], 5: [(-47, 2), (-47, 1)]}
    """
    # imports that are needed only for this function
    from sage.structure.proof.proof import get_flag
    import math
    from sage.misc.functional import round

    # deal with input defaults and type checking
    proof = get_flag(proof, 'number_field')
    hmax = Integer(hmax)

    # T stores the output
    T = {}

    # Easy case -- instead of giving error, give meaningful output
    if hmax < 1:
        return T

    if B is None:
        # Determine how far we have to go by applying Watkins's theorem.
        v = [largest_fundamental_disc_with_class_number(h) for h in range(1, hmax+1)]
        B = max([b for b,_ in v])
        fund_count = [0] + [cnt for _,cnt in v]
    else:
        # Nothing to do -- set to None so we can use this later to know not
        # to do a double check about how many we find.
        fund_count = None
        B = Integer(B)

    if B <= 2:
        # This is an easy special case, since there are no fundamental discriminants
        # this small.
        return T

    # This lower bound gets used in an inner loop below.
    from math import log
    def lb(f):
        """Lower bound on euler_phi."""
        # 1.79 > e^gamma = 1.7810724...
        if f <= 1: return 0  # don't do log(log(1)) = log(0)
        return f/(1.79*log(log(f)) + 3.0/log(log(f)))

    for D in range(-B, -2):
        D = Integer(D)
        if is_fundamental_discriminant(D):
            h_D = D.class_number(proof)
            # For each fundamental discriminant D, loop through the f's such
            # that h(D*f^2) could possibly be <= hmax.  As explained to me by Cremona,
            # we have h(D*f^2) >= (1/c)*h(D)*phi_D(f) >= (1/c)*h(D)*euler_phi(f), where
            # phi_D(f) is like euler_phi(f) but the factor (1-1/p) is replaced
            # by a factor of (1-kr(D,p)*p), where kr(D/p) is the Kronecker symbol.
            # The factor c is 1 unless D=-4 and f>1 (when c=2) or D=-3 and f>1 (when c=3).
            # Since (1-1/p) <= 1 and (1-1/p) <= (1+1/p), we see that
            #     euler_phi(f) <= phi_D(f).
            #
            # We have the following analytic lower bound on euler_phi:
            #
            #     euler_phi(f) >= lb(f) = f / (exp(euler_gamma)*log(log(n)) + 3/log(log(n))).
            #
            # See Theorem 8 of Peter Clark's
            #   http://math.uga.edu/~pete/4400arithmeticorders.pdf
            # which is a consequence of Theorem 15 of
            # [Rosser and Schoenfeld, 1962].
            #
            # By Calculus, we see that the lb(f) is an increasing function of f >= 2.
            #
            # NOTE: You can visibly "see" that it is a lower bound in Sage with
            #   lb(n) = n/(exp(euler_gamma)*log(log(n)) + 3/log(log(n)))
            #   plot(lb, (n, 1, 10^4), color='red') + plot(lambda x: euler_phi(int(x)), 1, 10^4).show()
            #
            # So we consider f=1,2,..., until the first f with lb(f)*h_D > c*h_max.
            # (Note that lb(f) is <= 0 for f=1,2, so nothing special is needed there.)
            #
            # TODO: Maybe we could do better using a bound for for phi_D(f).
            #
            f = Integer(1)
            chmax=hmax
            if D==-3:
                chmax*=3
            else:
                if D==-4:
                    chmax*=2
            while lb(f)*h_D <= chmax:
                if f == 1:
                    h = h_D
                else:
                    h = (D*f*f).class_number(proof)
                # If the class number of this order is within the range, then
                # use it.  (NOTE: In some cases there is a simple relation between
                # the class number for D and D*f^2, and this could be used to
                # optimize this inner loop a little.)
                if h <= hmax:
                    z = (D, f)
                    if h in T:
                        T[h].append(z)
                    else:
                        T[h] = [z]
                f += 1

    for h in T:
        T[h] = list(reversed(T[h]))

    if fund_count is not None:
        # Double check that we found the right number of fundamental
        # discriminants; we might as well, since Watkins provides this
        # data.
        for h in T:
            if len([D for D,f in T[h] if f==1]) != fund_count[h]:
                raise RuntimeError("number of discriminants inconsistent with Watkins's table")

    return T
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
Exemple #34
0
def check_prime(K,P):
    r"""
    Function to check that `P` determines a prime of `K`, and return that ideal.

    INPUT:

    - ``K`` -- a number field (including `\QQ`).

    - ``P`` -- an element of ``K`` or a (fractional) ideal of ``K``.

    OUTPUT:

    - If ``K`` is `\QQ`: the prime integer equal to or which generates `P`.

    - If ``K`` is not `\QQ`: the prime ideal equal to or generated by `P`.

    .. note::

       If `P` is not a prime and does not generate a prime, a TypeError is raised.

    EXAMPLES::

        sage: from sage.schemes.elliptic_curves.ell_local_data import check_prime
        sage: check_prime(QQ,3)
        3
        sage: check_prime(QQ,ZZ.ideal(31))
        31
        sage: K.<a>=NumberField(x^2-5)
        sage: check_prime(K,a)
        Fractional ideal (a)
        sage: check_prime(K,a+1)
        Fractional ideal (a + 1)
        sage: [check_prime(K,P) for P in K.primes_above(31)]
        [Fractional ideal (5/2*a + 1/2), Fractional ideal (5/2*a - 1/2)]
    """
    if K is QQ:
        if isinstance(P, (int,long,Integer)):
            P = Integer(P)
            if P.is_prime():
                return P
            else:
                raise TypeError("%s is not prime"%P)
        else:
            if is_Ideal(P) and P.base_ring() is ZZ and P.is_prime():
                return P.gen()
        raise TypeError("%s is not a prime ideal of %s"%(P,ZZ))

    if not is_NumberField(K):
        raise TypeError("%s is not a number field"%K)

    if is_NumberFieldFractionalIdeal(P):
        if P.is_prime():
            return P
        else:
            raise TypeError("%s is not a prime ideal of %s"%(P,K))

    if is_NumberFieldElement(P):
        if P in K:
            P = K.ideal(P)
        else:
            raise TypeError("%s is not an element of %s"%(P,K))
        if P.is_prime():
            return P
        else:
            raise TypeError("%s is not a prime ideal of %s"%(P,K))

    raise TypeError("%s is not a valid prime of %s"%(P,K))
Exemple #35
0
    def p_primary_bound(self, p):
        r"""
        Returns a provable upper bound for the order of `Sha(E)(p)`. In particular,
        if this algorithm does not fail, then it proves that the `p`-primary
        part of `Sha` is finite.

        INPUT: ``p`` -- a prime > 2

        OUTPUT:  integer -- power of `p` that bounds the order of `Sha(E)(p)` from above

        The result is a proven upper bound on the order of `Sha(E)(p)`.
        So in particular it proves it finiteness even if the rank of
        the curve is larger than 1. Note also that this bound is sharp
        if one assumes the main conjecture of Iwasawa theory of
        elliptic curves (and this is known in certain cases).

        Currently the algorithm is only implemented when certain conditions are verified.

        - The mod `p` Galois representation must be surjective.
        - The reduction at `p` is not allowed to be additive.
        - If the reduction at `p` is non-split multiplicative, then the rank has to be 0.
        - If `p=3` then the reduction at 3 must be good ordinary or split multiplicative and the rank must be 0.


        EXAMPLES::

            sage: e = EllipticCurve('11a3')
            sage: e.sha().p_primary_bound(3)
            0
            sage: e.sha().p_primary_bound(7)
            0
            sage: e.sha().p_primary_bound(11)
            0
            sage: e.sha().p_primary_bound(13)
            0

            sage: e = EllipticCurve('389a1')
            sage: e.sha().p_primary_bound(5)
            0
            sage: e.sha().p_primary_bound(7)
            0
            sage: e.sha().p_primary_bound(11)
            0
            sage: e.sha().p_primary_bound(13)
            0

            sage: e = EllipticCurve('858k2')
            sage: e.sha().p_primary_bound(3)  # long time (10s on sage.math, 2011)
            Traceback (most recent call last):                           # 32-bit (see :trac: `11211`)
            ...                                                          # 32-bit
            OverflowError: Python int too large to convert to C long     # 32-bit
            0                                                            # 64-bit

        Some checks for :trac:`6406`::

            sage: e.sha().p_primary_bound(7)
            Traceback (most recent call last):
            ...
            ValueError: The mod-p Galois representation is not surjective. Current knowledge about Euler systems does not provide an upper bound in this case. Try an_padic for a conjectural bound.

            sage: e.sha().an_padic(7)  # long time (depends on "e.sha().p_primary_bound(3)" above)
            Traceback (most recent call last):                           # 32-bit
            ...                                                          # 32-bit
            OverflowError: Python int too large to convert to C long     # 32-bit
            7^2 + O(7^6)                                                 # 64-bit

            sage: e = EllipticCurve('11a3')
            sage: e.sha().p_primary_bound(5)
            Traceback (most recent call last):
            ...
            ValueError: The mod-p Galois representation is not surjective. Current knowledge about Euler systems does not provide an upper bound in this case. Try an_padic for a conjectural bound.
            sage: e.sha().an_padic(5)
            1 + O(5^2)
        """
        p = Integer(p)
        E = self.Emin
        if E.is_ordinary(p) or E.is_good(p):
            su = E.galois_representation().is_surjective(p)
            if not su :
                raise ValueError("The mod-p Galois representation is not surjective. Current knowledge about Euler systems does not provide an upper bound in this case. Try an_padic for a conjectural bound.")
            shan = self.an_padic(p,prec = 0,use_twists=True)
            if shan == 0:
                raise RuntimeError("There is a bug in an_padic.")
            S = shan.valuation()
        else:
            raise ValueError("The curve has to have semi-stable reduction at p.")

        return S
Exemple #36
0
    def galois_action(self, t, N):
        r"""
        Suppose this cusp is `\alpha`, `G` is the congruence subgroup
        `\Gamma_0(N)` of level `N`, and `\sigma` is the automorphism in
        the Galois group of `\QQ(\zeta_N)/\QQ` that sends `\zeta_N` to
        `\zeta_N^t`.  Then this function computes a cusp `\beta` such
        that `\sigma([\alpha]) = [\beta]`, where `[\alpha]` is the
        equivalence class of `\alpha` modulo `G`.

        BIG WARNING: Despite its general name, this function only
        computes something that defines an action on `\Gamma_0(N)`
        equivalence classes; it does not compute the action on
        `\Gamma_1(N)` classes (see trac 8998).

        INPUT:

           - `t` -- integer that is coprime to N

           - `N` -- positive integer (level)

        OUTPUT:

           - a cusp

        EXAMPLES::
        
            sage: Cusp(1/10).galois_action(3, 50)
            1/170
            sage: Cusp(oo).galois_action(3, 50)
            Infinity
            sage: Cusp(0).galois_action(3, 50)
            0
            
        Here we compute explicitly the permutations of the action for
        t=3 on cusps for Gamma0(50)::
        
            sage: N = 50; t=3; G = Gamma0(N); C = G.cusps()
            sage: cl = lambda z: exists(C, lambda y:y.is_gamma0_equiv(z, N))[1]
            sage: for i in range(5): print i, t^i, [cl(alpha.galois_action(t^i,N)) for alpha in C]
            0 1 [0, 1/25, 1/10, 1/5, 3/10, 2/5, 1/2, 3/5, 7/10, 4/5, 9/10, Infinity]
            1 3 [0, 1/25, 7/10, 2/5, 1/10, 4/5, 1/2, 1/5, 9/10, 3/5, 3/10, Infinity]
            2 9 [0, 1/25, 9/10, 4/5, 7/10, 3/5, 1/2, 2/5, 3/10, 1/5, 1/10, Infinity]
            3 27 [0, 1/25, 3/10, 3/5, 9/10, 1/5, 1/2, 4/5, 1/10, 2/5, 7/10, Infinity]
            4 81 [0, 1/25, 1/10, 1/5, 3/10, 2/5, 1/2, 3/5, 7/10, 4/5, 9/10, Infinity]

        REFERENCES:

            - Section 1.3 of Glenn Stevens, "Arithmetic on Modular Curves"
            
            - There is a long comment about our algorithm in the source code for this function.

        WARNING: In some cases `N` must fit in a long long, i.e., there
                 are cases where this algorithm isn't fully implemented.

        AUTHORS:
        
            - William Stein, 2009-04-18

        """
        if self.is_infinity() or not self.__a: return self
        if not isinstance(t, Integer): t = Integer(t)

        # Our algorithm for computing the Galois action works as
        # follows (see Section 1.3 of Glenn Stevens "Arithmetic on
        # Modular Curves" for a proof that the action given below is
        # correct).  We alternatively view the set of cusps as the
        # Gamma-equivalence classes of column vectors [a;b] with
        # gcd(a,b,N)=1, and the left action of Gamma by matrix
        # multiplication.  The action of t is induced by [a;b] |-->
        # [a;t'*b], where t' is an inverse mod N of t.  For [a;t'*b]
        # with gcd(a,t'*b)==1, the cusp corresponding to [a;t'*b] is
        # just the rational number a/(t'*b).  Thus in this case, to
        # compute the action of t we just do a/b <--> [a;b] |--->
        # [a;t'*b] <--> a/(t'*b).  IN the other case when we get
        # [a;t'*b] with gcd(a,t'*b) != 1, which can and does happen,
        # we have to work a bit harder.  We need to find [c;d] such
        # that [c;d] is congruent to [a;t'*b] modulo N, and
        # gcd(c,d)=1.  There is a standard lifting algorithm that is
        # implemented for working with P^1(Z/NZ) [it is needed for
        # modular symbols algorithms], so we just apply it to lift
        # [a,t'*b] to a matrix [A,B;c,d] in SL_2(Z) with lower two
        # entries congruent to [a,t'*b] modulo N.  This exactly solves
        # our problem, since gcd(c,d)=1.

        a = self.__a
        b = self.__b * t.inverse_mod(N)
        if b.gcd(a) != 1:
            _,_,a,b = lift_to_sl2z_llong(a,b,N)
            a = Integer(a); b = Integer(b)

        # Now that we've computed the Galois action, we efficiently
        # construct the corresponding cusp as a Cusp object.
        return Cusp(a,b,check=False)
Exemple #37
0
def solve_mod(eqns, modulus, solution_dict=False):
    r"""
    Return all solutions to an equation or list of equations modulo the
    given integer modulus. Each equation must involve only polynomials
    in 1 or many variables.

    By default the solutions are returned as `n`-tuples, where `n`
    is the number of variables appearing anywhere in the given
    equations. The variables are in alphabetical order.

    INPUT:


    -  ``eqns`` - equation or list of equations

    -  ``modulus`` - an integer

    -  ``solution_dict`` - bool (default: False); if True or non-zero,
       return a list of dictionaries containing the solutions. If there
       are no solutions, return an empty list (rather than a list containing
       an empty dictionary). Likewise, if there's only a single solution,
       return a list containing one dictionary with that solution.


    EXAMPLES::

        sage: var('x,y')
        (x, y)
        sage: solve_mod([x^2 + 2 == x, x^2 + y == y^2], 14)
        [(4, 2), (4, 6), (4, 9), (4, 13)]
        sage: solve_mod([x^2 == 1, 4*x  == 11], 15)
        [(14,)]

    Fermat's equation modulo 3 with exponent 5::

        sage: var('x,y,z')
        (x, y, z)
        sage: solve_mod([x^5 + y^5 == z^5], 3)
        [(0, 0, 0), (0, 1, 1), (0, 2, 2), (1, 0, 1), (1, 1, 2), (1, 2, 0), (2, 0, 2), (2, 1, 0), (2, 2, 1)]

    We can solve with respect to a bigger modulus if it consists only of small prime factors::

        sage: [d] = solve_mod([5*x + y == 3, 2*x - 3*y == 9], 3*5*7*11*19*23*29, solution_dict = True)
        sage: d[x]
        12915279
        sage: d[y]
        8610183

    For cases where there are relatively few solutions and the prime
    factors are small, this can be efficient even if the modulus itself
    is large::

        sage: sorted(solve_mod([x^2 == 41], 10^20))
        [(4538602480526452429,), (11445932736758703821,), (38554067263241296179,),
        (45461397519473547571,), (54538602480526452429,), (61445932736758703821,),
        (88554067263241296179,), (95461397519473547571,)]

    We solve a simple equation modulo 2::

        sage: x,y = var('x,y')
        sage: solve_mod([x == y], 2)
        [(0, 0), (1, 1)]

    .. warning::

       The current implementation splits the modulus into prime
       powers, then naively enumerates all possible solutions
       (starting modulo primes and then working up through prime
       powers), and finally combines the solution using the Chinese
       Remainder Theorem.  The interface is good, but the algorithm is
       very inefficient if the modulus has some larger prime factors! Sage
       *does* have the ability to do something much faster in certain
       cases at least by using Groebner basis, linear algebra
       techniques, etc. But for a lot of toy problems this function as
       is might be useful. At least it establishes an interface.


    TESTS:

    Make sure that we short-circuit in at least some cases::

        sage: solve_mod([2*x==1], 2*next_prime(10^50))
        []

    Try multi-equation cases::

        sage: x, y, z = var("x y z")
        sage: solve_mod([2*x^2 + x*y, -x*y+2*y^2+x-2*y, -2*x^2+2*x*y-y^2-x-y], 12)
        [(0, 0), (4, 4), (0, 3), (4, 7)]
        sage: eqs = [-y^2+z^2, -x^2+y^2-3*z^2-z-1, -y*z-z^2-x-y+2, -x^2-12*z^2-y+z]
        sage: solve_mod(eqs, 11)
        [(8, 5, 6)]

    Confirm that modulus 1 now behaves as it should::

        sage: x, y = var("x y")
        sage: solve_mod([x==1], 1)
        [(0,)]
        sage: solve_mod([2*x^2+x*y, -x*y+2*y^2+x-2*y, -2*x^2+2*x*y-y^2-x-y], 1)
        [(0, 0)]


    """
    from sage.rings.all import Integer, Integers, crt_basis
    from sage.symbolic.expression import is_Expression
    from sage.misc.all import cartesian_product_iterator
    from sage.modules.all import vector
    from sage.matrix.all import matrix

    if not isinstance(eqns, (list, tuple)):
        eqns = [eqns]
    eqns = [eq if is_Expression(eq) else (eq.lhs() - eq.rhs()) for eq in eqns]
    modulus = Integer(modulus)
    if modulus < 1:
        raise ValueError("the modulus must be a positive integer")
    vars = list(set(sum([list(e.variables()) for e in eqns], [])))
    vars.sort(key=repr)

    if modulus == 1:  # degenerate case
        ans = [tuple(Integers(1)(0) for v in vars)]
        return ans

    factors = modulus.factor()
    crt_basis = vector(Integers(modulus),
                       crt_basis([p**i for p, i in factors]))
    solutions = []

    has_solution = True
    for p, i in factors:
        solution = _solve_mod_prime_power(eqns, p, i, vars)
        if len(solution) > 0:
            solutions.append(solution)
        else:
            has_solution = False
            break

    ans = []
    if has_solution:
        for solution in cartesian_product_iterator(solutions):
            solution_mat = matrix(Integers(modulus), solution)
            ans.append(
                tuple(
                    c.dot_product(crt_basis) for c in solution_mat.columns()))

    # if solution_dict == True:
    # Relaxed form suggested by Mike Hansen (#8553):
    if solution_dict:
        sol_dict = [dict(zip(vars, solution)) for solution in ans]
        return sol_dict
    else:
        return ans
Exemple #38
0
def hecke_operator_on_qexp(f, n, k, eps = None,
                           prec=None, check=True, _return_list=False):
    r"""
    Given the `q`-expansion `f` of a modular form with character
    `\varepsilon`, this function computes the image of `f` under the
    Hecke operator `T_{n,k}` of weight `k`.

    EXAMPLES::

        sage: M = ModularForms(1,12)
        sage: hecke_operator_on_qexp(M.basis()[0], 3, 12)
        252*q - 6048*q^2 + 63504*q^3 - 370944*q^4 + O(q^5)
        sage: hecke_operator_on_qexp(M.basis()[0], 1, 12, prec=7)
        q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 - 6048*q^6 + O(q^7)
        sage: hecke_operator_on_qexp(M.basis()[0], 1, 12)
        q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 - 6048*q^6 - 16744*q^7 + 84480*q^8 - 113643*q^9 - 115920*q^10 + 534612*q^11 - 370944*q^12 - 577738*q^13 + O(q^14)

        sage: M.prec(20)
        20
        sage: hecke_operator_on_qexp(M.basis()[0], 3, 12)
        252*q - 6048*q^2 + 63504*q^3 - 370944*q^4 + 1217160*q^5 - 1524096*q^6 + O(q^7)
        sage: hecke_operator_on_qexp(M.basis()[0], 1, 12)
        q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 - 6048*q^6 - 16744*q^7 + 84480*q^8 - 113643*q^9 - 115920*q^10 + 534612*q^11 - 370944*q^12 - 577738*q^13 + 401856*q^14 + 1217160*q^15 + 987136*q^16 - 6905934*q^17 + 2727432*q^18 + 10661420*q^19 - 7109760*q^20 + O(q^21)

        sage: (hecke_operator_on_qexp(M.basis()[0], 1, 12)*252).add_bigoh(7)
        252*q - 6048*q^2 + 63504*q^3 - 370944*q^4 + 1217160*q^5 - 1524096*q^6 + O(q^7)

        sage: hecke_operator_on_qexp(M.basis()[0], 6, 12)
        -6048*q + 145152*q^2 - 1524096*q^3 + O(q^4)

    An example on a formal power series::

        sage: R.<q> = QQ[[]]
        sage: f = q + q^2 + q^3 + q^7 + O(q^8)
        sage: hecke_operator_on_qexp(f, 3, 12)
        q + O(q^3)
        sage: hecke_operator_on_qexp(delta_qexp(24), 3, 12).prec()
        8
        sage: hecke_operator_on_qexp(delta_qexp(25), 3, 12).prec()
        9

    An example of computing `T_{p,k}` in characteristic `p`::

        sage: p = 199
        sage: fp = delta_qexp(prec=p^2+1, K=GF(p))
        sage: tfp = hecke_operator_on_qexp(fp, p, 12)
        sage: tfp == fp[p] * fp
        True
        sage: tf = hecke_operator_on_qexp(delta_qexp(prec=p^2+1), p, 12).change_ring(GF(p))
        sage: tfp == tf
        True
    """
    if eps is None:
        # Need to have base_ring=ZZ to work over finite fields, since
        # ZZ can coerce to GF(p), but QQ can't.
        eps = DirichletGroup(1, base_ring=ZZ)[0]
    if check:
        if not (is_PowerSeries(f) or is_ModularFormElement(f)):
            raise TypeError("f (=%s) must be a power series or modular form"%f)
        if not is_DirichletCharacter(eps):
            raise TypeError("eps (=%s) must be a Dirichlet character"%eps)
        k = Integer(k)
        n = Integer(n)
    v = []

    if prec is None:
        if is_ModularFormElement(f):
            # always want at least three coefficients, but not too many, unless
            # requested
            pr = max(f.prec(), f.parent().prec(), (n+1)*3)
            pr = min(pr, 100*(n+1))
            prec = pr // n + 1
        else:
            prec = (f.prec() / ZZ(n)).ceil()
            if prec == Infinity: prec = f.parent().default_prec() // n + 1

    if f.prec() < prec:
        f._compute_q_expansion(prec)

    p = Integer(f.base_ring().characteristic())
    if k != 1 and p.is_prime() and n.is_power_of(p):
        # if computing T_{p^a} in characteristic p, use the simpler (and faster)
        # formula
        v = [f[m*n] for m in range(prec)]
    else:
        l = k-1
        for m in range(prec):
            am = sum([eps(d) * d**l * f[m*n//(d*d)] for \
                      d in divisors(gcd(n, m)) if (m*n) % (d*d) == 0])
            v.append(am)
    if _return_list:
        return v
    if is_ModularFormElement(f):
        R = f.parent()._q_expansion_ring()
    else:
        R = f.parent()
    return R(v, prec)
Exemple #39
0
def victor_miller_basis(k, prec=10, cusp_only=False, var='q'):
    r"""
    Compute and return the Victor Miller basis for modular forms of
    weight `k` and level 1 to precision `O(q^{prec})`.  If
    ``cusp_only`` is True, return only a basis for the cuspidal
    subspace.

    INPUT:

    - ``k`` -- an integer

    - ``prec`` -- (default: 10) a positive integer

    - ``cusp_only`` -- bool (default: False)

    - ``var`` -- string (default: 'q')

    OUTPUT:

        A sequence whose entries are power series in ``ZZ[[var]]``.

    EXAMPLES::

        sage: victor_miller_basis(1, 6)
        []
        sage: victor_miller_basis(0, 6)
        [
        1 + O(q^6)
        ]
        sage: victor_miller_basis(2, 6)
        []
        sage: victor_miller_basis(4, 6)
        [
        1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + 30240*q^5 + O(q^6)
        ]

        sage: victor_miller_basis(6, 6, var='w')
        [
        1 - 504*w - 16632*w^2 - 122976*w^3 - 532728*w^4 - 1575504*w^5 + O(w^6)
        ]

        sage: victor_miller_basis(6, 6)
        [
        1 - 504*q - 16632*q^2 - 122976*q^3 - 532728*q^4 - 1575504*q^5 + O(q^6)
        ]
        sage: victor_miller_basis(12, 6)
        [
        1 + 196560*q^2 + 16773120*q^3 + 398034000*q^4 + 4629381120*q^5 + O(q^6),
        q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 + O(q^6)
        ]

        sage: victor_miller_basis(12, 6, cusp_only=True)
        [
        q - 24*q^2 + 252*q^3 - 1472*q^4 + 4830*q^5 + O(q^6)
        ]
        sage: victor_miller_basis(24, 6, cusp_only=True)
        [
        q + 195660*q^3 + 12080128*q^4 + 44656110*q^5 + O(q^6),
        q^2 - 48*q^3 + 1080*q^4 - 15040*q^5 + O(q^6)
        ]
        sage: victor_miller_basis(24, 6)
        [
        1 + 52416000*q^3 + 39007332000*q^4 + 6609020221440*q^5 + O(q^6),
        q + 195660*q^3 + 12080128*q^4 + 44656110*q^5 + O(q^6),
        q^2 - 48*q^3 + 1080*q^4 - 15040*q^5 + O(q^6)
        ]
        sage: victor_miller_basis(32, 6)
        [
        1 + 2611200*q^3 + 19524758400*q^4 + 19715347537920*q^5 + O(q^6),
        q + 50220*q^3 + 87866368*q^4 + 18647219790*q^5 + O(q^6),
        q^2 + 432*q^3 + 39960*q^4 - 1418560*q^5 + O(q^6)
        ]

        sage: victor_miller_basis(40,200)[1:] == victor_miller_basis(40,200,cusp_only=True)
        True
        sage: victor_miller_basis(200,40)[1:] == victor_miller_basis(200,40,cusp_only=True)
        True

    AUTHORS:

    - William Stein, Craig Citro: original code

    - Martin Raum (2009-08-02): use FLINT for polynomial arithmetic (instead of NTL)
    """
    k = Integer(k)
    if k%2 == 1 or k==2:
        return Sequence([])
    elif k < 0:
        raise ValueError("k must be non-negative")
    elif k == 0:
        return Sequence([PowerSeriesRing(ZZ,var)(1).add_bigoh(prec)], cr=True)
    e = k.mod(12)
    if e == 2: e += 12
    n = (k-e) // 12

    if n == 0 and cusp_only:
        return Sequence([])

    # If prec is less than or equal to the dimension of the space of
    # cusp forms, which is just n, then we know the answer, and we
    # simply return it.
    if prec <= n:
        q = PowerSeriesRing(ZZ,var).gen(0)
        err = bigO(q**prec)
        ls = [0] * (n+1)
        if not cusp_only:
            ls[0] = 1 + err
        for i in range(1,prec):
            ls[i] = q**i + err
        for i in range(prec,n+1):
            ls[i] = err
        return Sequence(ls, cr=True)

    F6 = eisenstein_series_poly(6,prec)

    if e == 0:
        A = Fmpz_poly(1)
    elif e == 4:
        A = eisenstein_series_poly(4,prec)
    elif e == 6:
        A = F6
    elif e == 8:
        A = eisenstein_series_poly(8,prec)
    elif e == 10:
        A = eisenstein_series_poly(10,prec)
    else: # e == 14
        A = eisenstein_series_poly(14,prec)

    if A[0] == -1 :
        A = -A

    if n == 0:
        return Sequence([PowerSeriesRing(ZZ,var)(A.list()).add_bigoh(prec)],cr=True)

    F6_squared = F6**2
    F6_squared._unsafe_mutate_truncate(prec)
    D = _delta_poly(prec)
    Fprod = F6_squared
    Dprod = D

    if cusp_only:
        ls = [Fmpz_poly(0)] + [A] * n
    else:
        ls = [A] * (n+1)

    for i in xrange(1,n+1):
        ls[n-i] *= Fprod
        ls[i] *= Dprod
        ls[n-i]._unsafe_mutate_truncate(prec)
        ls[i]._unsafe_mutate_truncate(prec)

        Fprod *= F6_squared
        Dprod *= D
        Fprod._unsafe_mutate_truncate(prec)
        Dprod._unsafe_mutate_truncate(prec)


    P = PowerSeriesRing(ZZ,var)
    if cusp_only :
        for i in xrange(1,n+1) :
            for j in xrange(1, i) :
                ls[j] = ls[j] - ls[j][i]*ls[i]

        return Sequence(map(lambda l: P(l.list()).add_bigoh(prec), ls[1:]),cr=True)
    else :
        for i in xrange(1,n+1) :
            for j in xrange(i) :
                ls[j] = ls[j] - ls[j][i]*ls[i]

        return Sequence(map(lambda l: P(l.list()).add_bigoh(prec), ls), cr=True)
        def coproduct_iterated(self, n=1):
            r"""
            Apply ``n`` coproducts to ``self``.

            .. TODO::

                Remove dependency on ``modules_with_basis`` methods.

            EXAMPLES::

                sage: Psi = NonCommutativeSymmetricFunctions(QQ).Psi()
                sage: Psi[2,2].coproduct_iterated(0)
                Psi[2, 2]
                sage: Psi[2,2].coproduct_iterated(2)
                Psi[] # Psi[] # Psi[2, 2] + 2*Psi[] # Psi[2] # Psi[2]
                 + Psi[] # Psi[2, 2] # Psi[] + 2*Psi[2] # Psi[] # Psi[2]
                 + 2*Psi[2] # Psi[2] # Psi[] + Psi[2, 2] # Psi[] # Psi[]

            TESTS::

                sage: p = SymmetricFunctions(QQ).p()
                sage: p[5,2,2].coproduct_iterated()
                p[] # p[5, 2, 2] + 2*p[2] # p[5, 2] + p[2, 2] # p[5]
                 + p[5] # p[2, 2] + 2*p[5, 2] # p[2] + p[5, 2, 2] # p[]
                sage: p([]).coproduct_iterated(3)
                p[] # p[] # p[] # p[]

            ::

                sage: Psi = NonCommutativeSymmetricFunctions(QQ).Psi()
                sage: Psi[2,2].coproduct_iterated(0)
                Psi[2, 2]
                sage: Psi[2,2].coproduct_iterated(3)
                Psi[] # Psi[] # Psi[] # Psi[2, 2] + 2*Psi[] # Psi[] # Psi[2] # Psi[2]
                 + Psi[] # Psi[] # Psi[2, 2] # Psi[] + 2*Psi[] # Psi[2] # Psi[] # Psi[2]
                 + 2*Psi[] # Psi[2] # Psi[2] # Psi[] + Psi[] # Psi[2, 2] # Psi[] # Psi[]
                 + 2*Psi[2] # Psi[] # Psi[] # Psi[2] + 2*Psi[2] # Psi[] # Psi[2] # Psi[]
                 + 2*Psi[2] # Psi[2] # Psi[] # Psi[] + Psi[2, 2] # Psi[] # Psi[] # Psi[]

            ::

                sage: m = SymmetricFunctionsNonCommutingVariables(QQ).m()
                sage: m[[1,3],[2]].coproduct_iterated(2)
                m{} # m{} # m{{1, 3}, {2}} + m{} # m{{1}} # m{{1, 2}}
                 + m{} # m{{1, 2}} # m{{1}} + m{} # m{{1, 3}, {2}} # m{}
                 + m{{1}} # m{} # m{{1, 2}} + m{{1}} # m{{1, 2}} # m{}
                 + m{{1, 2}} # m{} # m{{1}} + m{{1, 2}} # m{{1}} # m{}
                 + m{{1, 3}, {2}} # m{} # m{}
                sage: m[[]].coproduct_iterated(3), m[[1,3],[2]].coproduct_iterated(0)
                (m{} # m{} # m{} # m{}, m{{1, 3}, {2}})
            """
            if n < 0:
                raise ValueError(
                    "cannot take fewer than 0 coproduct iterations: %s < 0" %
                    str(n))
            if n == 0:
                return self
            if n == 1:
                return self.coproduct()
            from sage.functions.all import floor, ceil
            from sage.rings.all import Integer

            # Use coassociativity of `\Delta` to perform many coproducts simultaneously.
            fn = floor(Integer(n - 1) / 2)
            cn = ceil(Integer(n - 1) / 2)
            split = lambda a, b: tensor(
                [a.coproduct_iterated(fn),
                 b.coproduct_iterated(cn)])
            return self.coproduct().apply_multilinear_morphism(split)
Exemple #41
0
    def an_numerical(self, prec = None,
                         use_database=True, proof=None):
        r"""
        Return the numerical analytic order of `Sha`, which is
        a floating point number in all cases.

        INPUT:

        - ``prec`` - integer (default: 53) bits precision -- used
          for the L-series computation, period,  regulator, etc.
        - ``use_database`` - whether the rank and generators should
          be looked up in the database if possible. Default is ``True``
        - ``proof`` - bool or ``None`` (default: ``None``, see proof.[tab] or
          sage.structure.proof) proof option passed
          onto regulator and rank computation.

        .. note::

            See also the :meth:`an` command, which will return a
            provably correct integer when the rank is 0 or 1.

        .. WARNING::

            If the curve's generators are not known, computing
            them may be very time-consuming.  Also, computation of the
            L-series derivative will be time-consuming for large rank and
            large conductor, and the computation time for this may
            increase substantially at greater precision.  However, use of
            very low precision less than about 10 can cause the underlying
            PARI library functions to fail.

        EXAMPLES::

            sage: EllipticCurve('11a').sha().an_numerical()
            1.00000000000000
            sage: EllipticCurve('37a').sha().an_numerical()
            1.00000000000000
            sage: EllipticCurve('389a').sha().an_numerical()
            1.00000000000000
            sage: EllipticCurve('66b3').sha().an_numerical()
            4.00000000000000
            sage: EllipticCurve('5077a').sha().an_numerical()
            1.00000000000000

        A rank 4 curve::

            sage: EllipticCurve([1, -1, 0, -79, 289]).sha().an_numerical()  # long time (3s on sage.math, 2011)
            1.00000000000000

        A rank 5 curve::

            sage: EllipticCurve([0, 0, 1, -79, 342]).sha().an_numerical(prec=10, proof=False)  # long time (22s on sage.math, 2011)
            1.0

        See :trac:`1115`::

            sage: sha=EllipticCurve('37a1').sha()
            sage: [sha.an_numerical(prec) for prec in xrange(40,100,10)]  # long time (3s on sage.math, 2013)
            [1.0000000000,
            1.0000000000000,
            1.0000000000000000,
            1.0000000000000000000,
            1.0000000000000000000000,
            1.0000000000000000000000000]
        """
        if prec is None:
            prec = RealField().precision()
        RR = RealField(prec)
        prec2 = prec+2
        RR2 = RealField(prec2)
        try:
            an = self.__an_numerical
            if an.parent().precision() >= prec:
                return RR(an)
            else: # cached precision too low
                pass
        except AttributeError:
            pass
        # it's critical to switch to the minimal model.
        E = self.Emin
        r = Integer(E.rank(use_database=use_database, proof=proof))
        L = E.lseries().dokchitser(prec=prec2)
        Lr= RR2(L.derivative(1,r))  # L.derivative() returns a Complex
        Om = RR2(E.period_lattice().omega(prec2))
        Reg = E.regulator(use_database=use_database, proof=proof, precision=prec2)
        T = E.torsion_order()
        cp = E.tamagawa_product()
        Sha = RR((Lr*T*T)/(r.factorial()*Om*cp*Reg))
        self.__an_numerical = Sha
        return Sha
Exemple #42
0
def hilbert_class_polynomial(D, algorithm=None):
    r"""
    Returns the Hilbert class polynomial for discriminant `D`.

    INPUT:

    - ``D`` (int) -- a negative integer congruent to 0 or 1 modulo 4.

    - ``algorithm`` (string, default None).

    OUTPUT:

    (integer polynomial) The Hilbert class polynomial for the
    discriminant `D`.

    ALGORITHM:

    - If ``algorithm`` = "arb" (default): Use Arb's implementation which uses complex interval arithmetic.

    - If ``algorithm`` = "sage": Use complex approximations to the roots.

    - If ``algorithm`` = "magma": Call the appropriate Magma function (if available).

    AUTHORS:

    - Sage implementation originally by Eduardo Ocampo Alvarez and
      AndreyTimofeev

    - Sage implementation corrected by John Cremona (using corrected precision bounds from Andreas Enge)

    - Magma implementation by David Kohel

    EXAMPLES::

        sage: hilbert_class_polynomial(-4)
        x - 1728
        sage: hilbert_class_polynomial(-7)
        x + 3375
        sage: hilbert_class_polynomial(-23)
        x^3 + 3491750*x^2 - 5151296875*x + 12771880859375
        sage: hilbert_class_polynomial(-37*4)
        x^2 - 39660183801072000*x - 7898242515936467904000000
        sage: hilbert_class_polynomial(-37*4, algorithm="magma") # optional - magma
        x^2 - 39660183801072000*x - 7898242515936467904000000
        sage: hilbert_class_polynomial(-163)
        x + 262537412640768000
        sage: hilbert_class_polynomial(-163, algorithm="sage")
        x + 262537412640768000
        sage: hilbert_class_polynomial(-163, algorithm="magma") # optional - magma
        x + 262537412640768000

    TESTS::

        sage: all([hilbert_class_polynomial(d, algorithm="arb") == \
        ....:      hilbert_class_polynomial(d, algorithm="sage") \
        ....:        for d in range(-1,-100,-1) if d%4 in [0,1]])
        True

    """
    if algorithm is None:
        algorithm = "arb"

    D = Integer(D)
    if D >= 0:
        raise ValueError("D (=%s) must be negative"%D)
    if not (D%4 in [0,1]):
         raise ValueError("D (=%s) must be a discriminant"%D)

    if algorithm == "arb":
        import sage.libs.arb.arith
        return sage.libs.arb.arith.hilbert_class_polynomial(D)

    if algorithm == "magma":
        magma.eval("R<x> := PolynomialRing(IntegerRing())")
        f = str(magma.eval("HilbertClassPolynomial(%s)"%D))
        return IntegerRing()['x'](f)

    if algorithm != "sage":
        raise ValueError("%s is not a valid algorithm"%algorithm)

    from sage.quadratic_forms.binary_qf import BinaryQF_reduced_representatives
    from sage.rings.all import RR, ZZ, ComplexField
    from sage.functions.all import elliptic_j

    # get all primitive reduced quadratic forms, (necessary to exclude
    # imprimitive forms when D is not a fundamental discriminant):

    rqf = BinaryQF_reduced_representatives(D, primitive_only=True)

    # compute needed precision
    #
    # NB: [http://arxiv.org/abs/0802.0979v1], quoting Enge (2006), is
    # incorrect.  Enge writes (2009-04-20 email to John Cremona) "The
    # source is my paper on class polynomials
    # [http://hal.inria.fr/inria-00001040] It was pointed out to me by
    # the referee after ANTS that the constant given there was
    # wrong. The final version contains a corrected constant on p.7
    # which is consistent with your example. It says:

    # "The logarithm of the absolute value of the coefficient in front
    # of X^j is bounded above by
    #
    # log (2*k_2) * h + pi * sqrt(|D|) * sum (1/A_i)
    #
    # independently of j", where k_2 \approx 10.163.

    h = len(rqf) # class number
    c1 = 3.05682737291380 # log(2*10.63)
    c2 = sum([1/RR(qf[0]) for qf in rqf], RR(0))
    prec =  c2*RR(3.142)*RR(D).abs().sqrt() + h*c1  # bound on log
    prec = prec * 1.45   # bound on log_2 (1/log(2) = 1.44..)
    prec = 10 + prec.ceil()  # allow for rounding error

    # set appropriate precision for further computing

    Dsqrt = D.sqrt(prec=prec)
    R = ComplexField(prec)['t']
    t = R.gen()
    pol = R(1)
    for qf in rqf:
        a, b, c = list(qf)
        tau = (b+Dsqrt)/(a<<1)
        pol *=  (t - elliptic_j(tau))

    coeffs = [cof.real().round() for cof in pol.coefficients(sparse=False)]
    return IntegerRing()['x'](coeffs)
Exemple #43
0
def FinitelyGeneratedAbelianPresentation(int_list):
    r"""
    Return canonical presentation of finitely generated abelian group.

    INPUT:

    - ``int_list`` -- List of integers defining the group to be returned, the defining list
      is reduced to the invariants of the input list before generating the corresponding
      group.

    OUTPUT:

    Finitely generated abelian group, `\ZZ_{n_1} \times \ZZ_{n_2} \times \cdots \times \ZZ_{n_k}`
    as a finite presentation, where `n_i` forms the invariants of the input list.

    EXAMPLES::

        sage: groups.presentation.FGAbelian([2,2])
        Finitely presented group < a, b | a^2, b^2, a^-1*b^-1*a*b >
        sage: groups.presentation.FGAbelian([2,3])
        Finitely presented group < a | a^6 >
        sage: groups.presentation.FGAbelian([2,4])
        Finitely presented group < a, b | a^2, b^4, a^-1*b^-1*a*b >

    You can create free abelian groups::

        sage: groups.presentation.FGAbelian([0])
        Finitely presented group < a |  >
        sage: groups.presentation.FGAbelian([0,0])
        Finitely presented group < a, b | a^-1*b^-1*a*b >
        sage: groups.presentation.FGAbelian([0,0,0])
        Finitely presented group < a, b, c | a^-1*b^-1*a*b, a^-1*c^-1*a*c, b^-1*c^-1*b*c >

    And various infinite abelian groups::

        sage: groups.presentation.FGAbelian([0,2])
        Finitely presented group < a, b | a^2, a^-1*b^-1*a*b >
        sage: groups.presentation.FGAbelian([0,2,2])
        Finitely presented group < a, b, c | a^2, b^2, a^-1*b^-1*a*b, a^-1*c^-1*a*c, b^-1*c^-1*b*c >

    Outputs are reduced to minimal generators and relations::

        sage: groups.presentation.FGAbelian([3,5,2,7,3])
        Finitely presented group < a, b | a^3, b^210, a^-1*b^-1*a*b >
        sage: groups.presentation.FGAbelian([3,210])
        Finitely presented group < a, b | a^3, b^210, a^-1*b^-1*a*b >

    The trivial group is an acceptable output::

        sage: groups.presentation.FGAbelian([])
        Finitely presented group <  |  >
        sage: groups.presentation.FGAbelian([1])
        Finitely presented group <  |  >
        sage: groups.presentation.FGAbelian([1,1,1,1,1,1,1,1,1,1])
        Finitely presented group <  |  >

    Input list must consist of positive integers::

        sage: groups.presentation.FGAbelian([2,6,3,9,-4])
        Traceback (most recent call last):
        ...
        ValueError: input list must contain nonnegative entries
        sage: groups.presentation.FGAbelian([2,'a',4])
        Traceback (most recent call last):
        ...
        TypeError: unable to convert 'a' to an integer

    TESTS::

        sage: ag = groups.presentation.FGAbelian([2,2])
        sage: ag.as_permutation_group().is_isomorphic(groups.permutation.KleinFour())
        True
        sage: G = groups.presentation.FGAbelian([2,4,8])
        sage: C2 = CyclicPermutationGroup(2)
        sage: C4 = CyclicPermutationGroup(4)
        sage: C8 = CyclicPermutationGroup(8)
        sage: gg = (C2.direct_product(C4)[0]).direct_product(C8)[0]
        sage: gg.is_isomorphic(G.as_permutation_group())
        True
        sage: all(groups.presentation.FGAbelian([i]).as_permutation_group().is_isomorphic(groups.presentation.Cyclic(i).as_permutation_group()) for i in [2..35])
        True
    """
    from sage.groups.free_group import _lexi_gen
    check_ls = [Integer(x) for x in int_list if Integer(x) >= 0]
    if len(check_ls) != len(int_list):
        raise ValueError('input list must contain nonnegative entries')

    col_sp = diagonal_matrix(int_list).column_space()
    invariants = FGP_Module(ZZ**(len(int_list)), col_sp).invariants()
    name_gen = _lexi_gen()
    F = FreeGroup([next(name_gen) for i in invariants])
    ret_rls = [
        F([i + 1])**invariants[i] for i in range(len(invariants))
        if invariants[i] != 0
    ]

    # Build commutator relations
    gen_pairs = [[F.gen(i), F.gen(j)] for i in range(F.ngens() - 1)
                 for j in range(i + 1, F.ngens())]
    ret_rls = ret_rls + [
        x[0]**(-1) * x[1]**(-1) * x[0] * x[1] for x in gen_pairs
    ]
    return FinitelyPresentedGroup(F, tuple(ret_rls))
Exemple #44
0
def discriminants_with_bounded_class_number(hmax, B=None, proof=None):
    r"""
    Return dictionary with keys class numbers `h\le hmax` and values the
    list of all pairs `(D, f)`, with `D<0` a fundamental discriminant such
    that `Df^2` has class number `h`.  If the optional bound `B` is given,
    return only those pairs with fundamental `|D| \le B`, though `f` can
    still be arbitrarily large.

    INPUT:

    - ``hmax`` -- integer
    - `B` -- integer or None; if None returns all pairs
    - ``proof`` -- this code calls the PARI function ``qfbclassno``, so it
      could give wrong answers when ``proof``==``False``.  The default is
      whatever ``proof.number_field()`` is.  If ``proof==False`` and `B` is
      ``None``, at least the number of discriminants is correct, since it
      is double checked with Watkins's table.

    OUTPUT:

    - dictionary

    In case `B` is not given, we use Mark Watkins's: "Class numbers of
    imaginary quadratic fields" to compute a `B` that captures all `h`
    up to `hmax` (only available for `hmax\le100`).

    EXAMPLES::

        sage: v = sage.schemes.elliptic_curves.cm.discriminants_with_bounded_class_number(3)
        sage: sorted(v)
        [1, 2, 3]
        sage: v[1]
        [(-3, 3), (-3, 2), (-3, 1), (-4, 2), (-4, 1), (-7, 2), (-7, 1), (-8, 1), (-11, 1), (-19, 1), (-43, 1), (-67, 1), (-163, 1)]
        sage: v[2]
        [(-3, 7), (-3, 5), (-3, 4), (-4, 5), (-4, 4), (-4, 3), (-7, 4), (-8, 3), (-8, 2), (-11, 3), (-15, 2), (-15, 1), (-20, 1), (-24, 1), (-35, 1), (-40, 1), (-51, 1), (-52, 1), (-88, 1), (-91, 1), (-115, 1), (-123, 1), (-148, 1), (-187, 1), (-232, 1), (-235, 1), (-267, 1), (-403, 1), (-427, 1)]
        sage: v[3]
        [(-3, 9), (-3, 6), (-11, 2), (-19, 2), (-23, 2), (-23, 1), (-31, 2), (-31, 1), (-43, 2), (-59, 1), (-67, 2), (-83, 1), (-107, 1), (-139, 1), (-163, 2), (-211, 1), (-283, 1), (-307, 1), (-331, 1), (-379, 1), (-499, 1), (-547, 1), (-643, 1), (-883, 1), (-907, 1)]
        sage: v = sage.schemes.elliptic_curves.cm.discriminants_with_bounded_class_number(8, proof=False)
        sage: sorted(len(v[h]) for h in v)
        [13, 25, 29, 29, 38, 84, 101, 208]

    Find all class numbers for discriminant up to 50::

        sage: sage.schemes.elliptic_curves.cm.discriminants_with_bounded_class_number(hmax=5, B=50)
        {1: [(-3, 3), (-3, 2), (-3, 1), (-4, 2), (-4, 1), (-7, 2), (-7, 1), (-8, 1), (-11, 1), (-19, 1), (-43, 1)], 2: [(-3, 7), (-3, 5), (-3, 4), (-4, 5), (-4, 4), (-4, 3), (-7, 4), (-8, 3), (-8, 2), (-11, 3), (-15, 2), (-15, 1), (-20, 1), (-24, 1), (-35, 1), (-40, 1)], 3: [(-3, 9), (-3, 6), (-11, 2), (-19, 2), (-23, 2), (-23, 1), (-31, 2), (-31, 1), (-43, 2)], 4: [(-3, 13), (-3, 11), (-3, 8), (-4, 10), (-4, 8), (-4, 7), (-4, 6), (-7, 8), (-7, 6), (-7, 3), (-8, 6), (-8, 4), (-11, 5), (-15, 4), (-19, 5), (-19, 3), (-20, 3), (-20, 2), (-24, 2), (-35, 3), (-39, 2), (-39, 1), (-40, 2), (-43, 3)], 5: [(-47, 2), (-47, 1)]}
    """
    # imports that are needed only for this function
    from sage.structure.proof.proof import get_flag

    # deal with input defaults and type checking
    proof = get_flag(proof, 'number_field')
    hmax = Integer(hmax)

    # T stores the output
    T = {}

    # Easy case -- instead of giving error, give meaningful output
    if hmax < 1:
        return T

    if B is None:
        # Determine how far we have to go by applying Watkins's theorem.
        v = [
            largest_fundamental_disc_with_class_number(h)
            for h in range(1, hmax + 1)
        ]
        B = max([b for b, _ in v])
        fund_count = [0] + [cnt for _, cnt in v]
    else:
        # Nothing to do -- set to None so we can use this later to know not
        # to do a double check about how many we find.
        fund_count = None
        B = Integer(B)

    if B <= 2:
        # This is an easy special case, since there are no fundamental discriminants
        # this small.
        return T

    # This lower bound gets used in an inner loop below.
    from math import log

    def lb(f):
        """Lower bound on euler_phi."""
        # 1.79 > e^gamma = 1.7810724...
        if f <= 1: return 0  # don't do log(log(1)) = log(0)
        return f / (1.79 * log(log(f)) + 3.0 / log(log(f)))

    for D in range(-B, -2):
        D = Integer(D)
        if is_fundamental_discriminant(D):
            h_D = D.class_number(proof)
            # For each fundamental discriminant D, loop through the f's such
            # that h(D*f^2) could possibly be <= hmax.  As explained to me by Cremona,
            # we have h(D*f^2) >= (1/c)*h(D)*phi_D(f) >= (1/c)*h(D)*euler_phi(f), where
            # phi_D(f) is like euler_phi(f) but the factor (1-1/p) is replaced
            # by a factor of (1-kr(D,p)*p), where kr(D/p) is the Kronecker symbol.
            # The factor c is 1 unless D=-4 and f>1 (when c=2) or D=-3 and f>1 (when c=3).
            # Since (1-1/p) <= 1 and (1-1/p) <= (1+1/p), we see that
            #     euler_phi(f) <= phi_D(f).
            #
            # We have the following analytic lower bound on euler_phi:
            #
            #     euler_phi(f) >= lb(f) = f / (exp(euler_gamma)*log(log(n)) + 3/log(log(n))).
            #
            # See Theorem 8 of Peter Clark's
            #   http://math.uga.edu/~pete/4400arithmeticorders.pdf
            # which is a consequence of Theorem 15 of
            # [Rosser and Schoenfeld, 1962].
            #
            # By Calculus, we see that the lb(f) is an increasing function of f >= 2.
            #
            # NOTE: You can visibly "see" that it is a lower bound in Sage with
            #   lb(n) = n/(exp(euler_gamma)*log(log(n)) + 3/log(log(n)))
            #   plot(lb, (n, 1, 10^4), color='red') + plot(lambda x: euler_phi(int(x)), 1, 10^4).show()
            #
            # So we consider f=1,2,..., until the first f with lb(f)*h_D > c*h_max.
            # (Note that lb(f) is <= 0 for f=1,2, so nothing special is needed there.)
            #
            # TODO: Maybe we could do better using a bound for phi_D(f).
            #
            f = Integer(1)
            chmax = hmax
            if D == -3:
                chmax *= 3
            else:
                if D == -4:
                    chmax *= 2
            while lb(f) * h_D <= chmax:
                if f == 1:
                    h = h_D
                else:
                    h = (D * f * f).class_number(proof)
                # If the class number of this order is within the range, then
                # use it.  (NOTE: In some cases there is a simple relation between
                # the class number for D and D*f^2, and this could be used to
                # optimize this inner loop a little.)
                if h <= hmax:
                    z = (D, f)
                    if h in T:
                        T[h].append(z)
                    else:
                        T[h] = [z]
                f += 1

    for h in T:
        T[h] = list(reversed(T[h]))

    if fund_count is not None:
        # Double check that we found the right number of fundamental
        # discriminants; we might as well, since Watkins provides this
        # data.
        for h in T:
            if len([DD for DD, ff in T[h] if ff == 1]) != fund_count[h]:
                raise RuntimeError(
                    "number of discriminants inconsistent with Watkins's table"
                )

    return T
Exemple #45
0
def FinitelyGeneratedHeisenbergPresentation(n=1, p=0):
    r"""
    Return a finite presentation of the Heisenberg group.

    The Heisenberg group is the group of `(n+2) \times (n+2)` matrices
    over a ring `R` with diagonal elements equal to 1, first row and
    last column possibly nonzero, and all the other entries equal to zero.

    INPUT:

    - ``n`` -- the degree of the Heisenberg group

    - ``p`` -- (optional) a prime number, where we construct the
      Heisenberg group over the finite field `\ZZ/p\ZZ`
 
    OUTPUT:

    Finitely generated Heisenberg group over the finite field
    of order ``p`` or over the integers.

    .. SEEALSO::

        :class:`~sage.groups.matrix_gps.heisenberg.HeisenbergGroup`

    EXAMPLES::

        sage: H = groups.presentation.Heisenberg(); H
        Finitely presented group < x1, y1, z |
         x1*y1*x1^-1*y1^-1*z^-1, z*x1*z^-1*x1^-1, z*y1*z^-1*y1^-1 >
        sage: H.order()
        +Infinity
        sage: r1, r2, r3 = H.relations()
        sage: A = matrix([[1, 1, 0], [0, 1, 0], [0, 0, 1]])
        sage: B = matrix([[1, 0, 0], [0, 1, 1], [0, 0, 1]])
        sage: C = matrix([[1, 0, 1], [0, 1, 0], [0, 0, 1]])
        sage: r1(A, B, C)
        [1 0 0]
        [0 1 0]
        [0 0 1]
        sage: r2(A, B, C)
        [1 0 0]
        [0 1 0]
        [0 0 1]
        sage: r3(A, B, C)
        [1 0 0]
        [0 1 0]
        [0 0 1]
        sage: p = 3
        sage: Hp = groups.presentation.Heisenberg(p=3)
        sage: Hp.order() == p**3 
        True
        sage: Hnp = groups.presentation.Heisenberg(n=2, p=3)
        sage: len(Hnp.relations())
        13

    REFERENCES:

    - :wikipedia:`Heisenberg_group`
    """
    n = Integer(n)
    if n < 1:
        raise ValueError('n must be a positive integer')

    # generators' names are x1, .., xn, y1, .., yn, z
    vx = ['x' + str(i) for i in range(1, n + 1)]
    vy = ['y' + str(i) for i in range(1, n + 1)]
    str_generators = ', '.join(vx + vy + ['z'])

    F = FreeGroup(str_generators)
    x = F.gens()[0:n]  # list of generators x1, x2, ..., xn
    y = F.gens()[n:2 * n]  # list of generators x1, x2, ..., xn
    z = F.gen(n * 2)

    def commutator(a, b):
        return a * b * a**-1 * b**-1

    # First set of relations: [xi, yi] = z
    r1 = [commutator(x[i], y[i]) * z**-1 for i in range(n)]
    # Second set of relations: [z, xi] = 1
    r2 = [commutator(z, x[i]) for i in range(n)]
    # Third set of relations: [z, yi] = 1
    r3 = [commutator(z, y[i]) for i in range(n)]
    # Fourth set of relations: [xi, yi] = 1 for i != j
    r4 = [commutator(x[i], y[j]) for i in range(n) for j in range(n) if i != j]
    rls = r1 + r2 + r3 + r4

    from sage.sets.primes import Primes
    if p not in Primes() and p != 0:
        raise ValueError("p must be 0 or a prime number")
    if p > 0:
        rls += [w**p for w in F.gens()]
    return FinitelyPresentedGroup(F, tuple(rls))
Exemple #46
0
def check_prime(K,P):
    r"""
    Function to check that `P` determines a prime of `K`, and return that ideal.

    INPUT:

    - ``K`` -- a number field (including `\QQ`).

    - ``P`` -- an element of ``K`` or a (fractional) ideal of ``K``.

    OUTPUT:

    - If ``K`` is `\QQ`: the prime integer equal to or which generates `P`.

    - If ``K`` is not `\QQ`: the prime ideal equal to or generated by `P`.

    .. note::

       If `P` is not a prime and does not generate a prime, a TypeError is raised.

    EXAMPLES::

        sage: from sage.schemes.elliptic_curves.ell_local_data import check_prime
        sage: check_prime(QQ,3)
        3
        sage: check_prime(QQ,ZZ.ideal(31))
        31
        sage: K.<a>=NumberField(x^2-5)
        sage: check_prime(K,a)
        Fractional ideal (a)
        sage: check_prime(K,a+1)
        Fractional ideal (a + 1)
        sage: [check_prime(K,P) for P in K.primes_above(31)]
        [Fractional ideal (5/2*a + 1/2), Fractional ideal (5/2*a - 1/2)]
    """
    if K is QQ:
        if isinstance(P, (int,long,Integer)):
            P = Integer(P)
            if P.is_prime():
                return P
            else:
                raise TypeError("%s is not prime"%P)
        else:
            if is_Ideal(P) and P.base_ring() is ZZ and P.is_prime():
                return P.gen()
        raise TypeError("%s is not a prime ideal of %s"%(P,ZZ))

    if not is_NumberField(K):
        raise TypeError("%s is not a number field"%K)

    if is_NumberFieldFractionalIdeal(P):
        if P.is_prime():
            return P
        else:
            raise TypeError("%s is not a prime ideal of %s"%(P,K))

    if is_NumberFieldElement(P):
        if P in K:
            P = K.ideal(P)
        else:
            raise TypeError("%s is not an element of %s"%(P,K))
        if P.is_prime():
            return P
        else:
            raise TypeError("%s is not a prime ideal of %s"%(P,K))

    raise TypeError("%s is not a valid prime of %s"%(P,K))
Exemple #47
0
    def galois_action(self, t, N):
        r"""
        Suppose this cusp is `\alpha`, `G` a congruence subgroup of level `N`
        and `\sigma` is the automorphism in the Galois group of
        `\QQ(\zeta_N)/\QQ` that sends `\zeta_N` to `\zeta_N^t`. Then this
        function computes a cusp `\beta` such that `\sigma([\alpha]) = [\beta]`,
        where `[\alpha]` is the equivalence class of `\alpha` modulo `G`.

        This code only needs as input the level and not the group since the
        action of galois for a congruence group `G` of level `N` is compatible
        with the action of the full congruence group `\Gamma(N)`.


        INPUT:

           - `t` -- integer that is coprime to N

           - `N` -- positive integer (level)

        OUTPUT:

           - a cusp


        .. WARNING::

            In some cases `N` must fit in a long long, i.e., there
            are cases where this algorithm isn't fully implemented.

        .. NOTE::

            Modular curves can have multiple non-isomorphic models over `\QQ`.
            The action of galois depends on such a model. The model over `\QQ`
            of `X(G)` used here is the model where the function field
            `\QQ(X(G))` is given by the functions whose fourier expansion at
            `\infty` have their coefficients in `\QQ`. For `X(N):=X(\Gamma(N))`
            the corresponding moduli interpretation over `\ZZ[1/N]` is that
            `X(N)` parametrizes pairs `(E,a)` where `E` is a (generalized)
            elliptic curve and `a: \ZZ / N\ZZ \times \mu_N \to E` is a closed
            immersion such that the weil pairing of `a(1,1)` and `a(0,\zeta_N)`
            is `\zeta_N`. In this parameterisation the point `z \in H`
            corresponds to the pair `(E_z,a_z)` with `E_z=\CC/(z \ZZ+\ZZ)` and
            `a_z: \ZZ / N\ZZ \times \mu_N \to E` given by `a_z(1,1) = z/N` and
            `a_z(0,\zeta_N) = 1/N`.
            Similarly `X_1(N):=X(\Gamma_1(N))` parametrizes pairs `(E,a)` where
            `a: \mu_N \to E` is a closed immersion.

        EXAMPLES::

            sage: Cusp(1/10).galois_action(3, 50)
            1/170
            sage: Cusp(oo).galois_action(3, 50)
            Infinity
            sage: c=Cusp(0).galois_action(3, 50); c
            50/67
            sage: Gamma0(50).reduce_cusp(c)
            0

        Here we compute the permutations of the action for t=3 on cusps for
        Gamma0(50). ::

            sage: N = 50; t=3; G = Gamma0(N); C = G.cusps()
            sage: cl = lambda z: exists(C, lambda y:y.is_gamma0_equiv(z, N))[1]
            sage: for i in range(5): print i, t^i, [cl(alpha.galois_action(t^i,N)) for alpha in C]
            0 1 [0, 1/25, 1/10, 1/5, 3/10, 2/5, 1/2, 3/5, 7/10, 4/5, 9/10, Infinity]
            1 3 [0, 1/25, 7/10, 2/5, 1/10, 4/5, 1/2, 1/5, 9/10, 3/5, 3/10, Infinity]
            2 9 [0, 1/25, 9/10, 4/5, 7/10, 3/5, 1/2, 2/5, 3/10, 1/5, 1/10, Infinity]
            3 27 [0, 1/25, 3/10, 3/5, 9/10, 1/5, 1/2, 4/5, 1/10, 2/5, 7/10, Infinity]
            4 81 [0, 1/25, 1/10, 1/5, 3/10, 2/5, 1/2, 3/5, 7/10, 4/5, 9/10, Infinity]

        TESTS:

        Here we check that the galois action is indeed a permutation on the
        cusps of Gamma1(48) and check that :trac:`13253` is fixed. ::

            sage: G=Gamma1(48)
            sage: C=G.cusps()
            sage: for i in Integers(48).unit_gens():
            ...     C_permuted = [G.reduce_cusp(c.galois_action(i,48)) for c in C]
            ...     assert len(set(C_permuted))==len(C)

        We test that Gamma1(19) has 9 rational cusps and check that :trac:`8998`
        is fixed. ::

            sage: G = Gamma1(19)
            sage: [c for c in G.cusps() if c.galois_action(2,19).is_gamma1_equiv(c,19)[0]]
            [2/19, 3/19, 4/19, 5/19, 6/19, 7/19, 8/19, 9/19, Infinity]


        REFERENCES:

            - Section 1.3 of Glenn Stevens, "Arithmetic on Modular Curves"

            - There is a long comment about our algorithm in the source code for this function.

        AUTHORS:

            - William Stein, 2009-04-18

        """
        if self.is_infinity(): return self
        if not isinstance(t, Integer): t = Integer(t)

        # Our algorithm for computing the Galois action works as
        # follows (see Section 1.3 of Glenn Stevens "Arithmetic on
        # Modular Curves" for a proof that the action given below is
        # correct).  We alternatively view the set of cusps as the
        # Gamma-equivalence classes of column vectors [a;b] with
        # gcd(a,b,N)=1, and the left action of Gamma by matrix
        # multiplication.  The action of t is induced by [a;b] |-->
        # [a;t'*b], where t' is an inverse mod N of t.  For [a;t'*b]
        # with gcd(a,t'*b)==1, the cusp corresponding to [a;t'*b] is
        # just the rational number a/(t'*b).  Thus in this case, to
        # compute the action of t we just do a/b <--> [a;b] |--->
        # [a;t'*b] <--> a/(t'*b).  IN the other case when we get
        # [a;t'*b] with gcd(a,t'*b) != 1, which can and does happen,
        # we have to work a bit harder.  We need to find [c;d] such
        # that [c;d] is congruent to [a;t'*b] modulo N, and
        # gcd(c,d)=1.  There is a standard lifting algorithm that is
        # implemented for working with P^1(Z/NZ) [it is needed for
        # modular symbols algorithms], so we just apply it to lift
        # [a,t'*b] to a matrix [A,B;c,d] in SL_2(Z) with lower two
        # entries congruent to [a,t'*b] modulo N.  This exactly solves
        # our problem, since gcd(c,d)=1.

        a = self.__a
        b = self.__b * t.inverse_mod(N)
        if b.gcd(a) != 1:
            _,_,a,b = lift_to_sl2z_llong(a,b,N)
            a = Integer(a); b = Integer(b)

        # Now that we've computed the Galois action, we efficiently
        # construct the corresponding cusp as a Cusp object.
        return Cusp(a,b,check=False)
Exemple #48
0
    def intersection(self, other):
        """
        Return the intersection of the finite subgroups self and other.

        INPUT:

        -  ``other`` - a finite group

        OUTPUT: a finite group

        EXAMPLES::

            sage: E11a0, E11a1, B = J0(33)
            sage: G = E11a0.torsion_subgroup(6); H = E11a0.torsion_subgroup(9)
            sage: G.intersection(H)
            Finite subgroup with invariants [3, 3] over QQ of Simple abelian subvariety 11a(1,33) of dimension 1 of J0(33)
            sage: W = E11a1.torsion_subgroup(15)
            sage: G.intersection(W)
            Finite subgroup with invariants [] over QQ of Simple abelian subvariety 11a(1,33) of dimension 1 of J0(33)
            sage: E11a0.intersection(E11a1)[0]
            Finite subgroup with invariants [5] over QQ of Simple abelian subvariety 11a(1,33) of dimension 1 of J0(33)

        We intersect subgroups of different abelian varieties.

        ::

            sage: E11a0, E11a1, B = J0(33)
            sage: G = E11a0.torsion_subgroup(5); H = E11a1.torsion_subgroup(5)
            sage: G.intersection(H)
            Finite subgroup with invariants [5] over QQ of Simple abelian subvariety 11a(1,33) of dimension 1 of J0(33)
            sage: E11a0.intersection(E11a1)[0]
            Finite subgroup with invariants [5] over QQ of Simple abelian subvariety 11a(1,33) of dimension 1 of J0(33)

        We intersect abelian varieties with subgroups::

            sage: t = J0(33).hecke_operator(7)
            sage: G = t.kernel()[0]; G
            Finite subgroup with invariants [2, 2, 2, 2, 4, 4] over QQ of Abelian variety J0(33) of dimension 3
            sage: A = J0(33).old_subvariety()
            sage: A.intersection(G)
            Finite subgroup with invariants [2, 2, 2, 2] over QQ of Abelian subvariety of dimension 2 of J0(33)
            sage: A.hecke_operator(7).kernel()[0]
            Finite subgroup with invariants [2, 2, 2, 2] over QQ of Abelian subvariety of dimension 2 of J0(33)
            sage: B = J0(33).new_subvariety()
            sage: B.intersection(G)
            Finite subgroup with invariants [4, 4] over QQ of Abelian subvariety of dimension 1 of J0(33)
            sage: B.hecke_operator(7).kernel()[0]
            Finite subgroup with invariants [4, 4] over QQ of Abelian subvariety of dimension 1 of J0(33)
            sage: A.intersection(B)[0]
            Finite subgroup with invariants [3, 3] over QQ of Abelian subvariety of dimension 2 of J0(33)
        """
        A = self.abelian_variety()
        if abelian_variety.is_ModularAbelianVariety(other):
            amb = other
            B = other
            M = B.lattice().scale(Integer(1) / self.exponent())
            K = composite_field(self.field_of_definition(), other.base_field())
        else:
            amb = A
            if not isinstance(other, FiniteSubgroup):
                raise TypeError, "only addition of two finite subgroups is defined"
            B = other.abelian_variety()
            if A.ambient_variety() != B.ambient_variety():
                raise TypeError, "finite subgroups must be in the same ambient product Jacobian"
            M = other.lattice()
            K = composite_field(self.field_of_definition(),
                                other.field_of_definition())

        L = self.lattice()
        if A != B:
            # TODO: This might be way slower than what we could do if
            # we think more carefully.
            C = A + B
            L = L + C.lattice()
            M = M + C.lattice()
        W = L.intersection(M).intersection(amb.vector_space())
        return FiniteSubgroup_lattice(amb, W, field_of_definition=K)
Exemple #49
0
def solve_mod(eqns, modulus, solution_dict = False):
    r"""
    Return all solutions to an equation or list of equations modulo the
    given integer modulus. Each equation must involve only polynomials
    in 1 or many variables.

    By default the solutions are returned as `n`-tuples, where `n`
    is the number of variables appearing anywhere in the given
    equations. The variables are in alphabetical order.

    INPUT:


    -  ``eqns`` - equation or list of equations

    -  ``modulus`` - an integer

    -  ``solution_dict`` - bool (default: False); if True or non-zero,
       return a list of dictionaries containing the solutions. If there
       are no solutions, return an empty list (rather than a list containing
       an empty dictionary). Likewise, if there's only a single solution,
       return a list containing one dictionary with that solution.


    EXAMPLES::

        sage: var('x,y')
        (x, y)
        sage: solve_mod([x^2 + 2 == x, x^2 + y == y^2], 14)
        [(4, 2), (4, 6), (4, 9), (4, 13)]
        sage: solve_mod([x^2 == 1, 4*x  == 11], 15)
        [(14,)]

    Fermat's equation modulo 3 with exponent 5::

        sage: var('x,y,z')
        (x, y, z)
        sage: solve_mod([x^5 + y^5 == z^5], 3)
        [(0, 0, 0), (0, 1, 1), (0, 2, 2), (1, 0, 1), (1, 1, 2), (1, 2, 0), (2, 0, 2), (2, 1, 0), (2, 2, 1)]

    We can solve with respect to a bigger modulus if it consists only of small prime factors::

        sage: [d] = solve_mod([5*x + y == 3, 2*x - 3*y == 9], 3*5*7*11*19*23*29, solution_dict = True)
        sage: d[x]
        12915279
        sage: d[y]
        8610183

    For cases where there are relatively few solutions and the prime
    factors are small, this can be efficient even if the modulus itself
    is large::

        sage: sorted(solve_mod([x^2 == 41], 10^20))
        [(4538602480526452429,), (11445932736758703821,), (38554067263241296179,),
        (45461397519473547571,), (54538602480526452429,), (61445932736758703821,),
        (88554067263241296179,), (95461397519473547571,)]

    We solve a simple equation modulo 2::

        sage: x,y = var('x,y')
        sage: solve_mod([x == y], 2)
        [(0, 0), (1, 1)]

    .. warning::

       The current implementation splits the modulus into prime
       powers, then naively enumerates all possible solutions
       (starting modulo primes and then working up through prime
       powers), and finally combines the solution using the Chinese
       Remainder Theorem.  The interface is good, but the algorithm is
       very inefficient if the modulus has some larger prime factors! Sage
       *does* have the ability to do something much faster in certain
       cases at least by using Groebner basis, linear algebra
       techniques, etc. But for a lot of toy problems this function as
       is might be useful. At least it establishes an interface.


    TESTS:

    Make sure that we short-circuit in at least some cases::

        sage: solve_mod([2*x==1], 2*next_prime(10^50))
        []

    Try multi-equation cases::

        sage: x, y, z = var("x y z")
        sage: solve_mod([2*x^2 + x*y, -x*y+2*y^2+x-2*y, -2*x^2+2*x*y-y^2-x-y], 12)
        [(0, 0), (4, 4), (0, 3), (4, 7)]
        sage: eqs = [-y^2+z^2, -x^2+y^2-3*z^2-z-1, -y*z-z^2-x-y+2, -x^2-12*z^2-y+z]
        sage: solve_mod(eqs, 11)
        [(8, 5, 6)]

    Confirm that modulus 1 now behaves as it should::

        sage: x, y = var("x y")
        sage: solve_mod([x==1], 1)
        [(0,)]
        sage: solve_mod([2*x^2+x*y, -x*y+2*y^2+x-2*y, -2*x^2+2*x*y-y^2-x-y], 1)
        [(0, 0)]


    """
    from sage.rings.all import Integer, Integers, crt_basis
    from sage.symbolic.expression import is_Expression
    from sage.misc.all import cartesian_product_iterator
    from sage.modules.all import vector
    from sage.matrix.all import matrix

    if not isinstance(eqns, (list, tuple)):
        eqns = [eqns]
    eqns = [eq if is_Expression(eq) else (eq.lhs()-eq.rhs()) for eq in eqns]
    modulus = Integer(modulus)
    if modulus < 1:
        raise ValueError("the modulus must be a positive integer")
    vars = list(set(sum([list(e.variables()) for e in eqns], [])))
    vars.sort(key=repr)

    if modulus == 1: # degenerate case
        ans = [tuple(Integers(1)(0) for v in vars)]
        return ans

    factors = modulus.factor()
    crt_basis = vector(Integers(modulus), crt_basis([p**i for p,i in factors]))
    solutions = []

    has_solution = True
    for p,i in factors:
        solution =_solve_mod_prime_power(eqns, p, i, vars)
        if len(solution) > 0:
            solutions.append(solution)
        else:
            has_solution = False
            break


    ans = []
    if has_solution:
        for solution in cartesian_product_iterator(solutions):
            solution_mat = matrix(Integers(modulus), solution)
            ans.append(tuple(c.dot_product(crt_basis) for c in solution_mat.columns()))

    # if solution_dict == True:
    # Relaxed form suggested by Mike Hansen (#8553):
    if solution_dict:
        sol_dict = [dict(zip(vars, solution)) for solution in ans]
        return sol_dict
    else:
        return ans
Exemple #50
0
 def p(self):
     q = Integer(self.q)
     p, _ = q.is_prime_power(get_data=True)
     return p
Exemple #51
0
    def nth_iterate_map(self, n):
        r"""
        This function returns the ``n``-th iterate of the map.

        ALGORITHM:

        Uses a form of successive squaring to reducing computations.

        .. TODO::

        This could be improved.

        INPUT:

        - ``n`` - a positive integer.

        OUTPUT:

        - A map between Affine spaces.

        EXAMPLES::

            sage: A.<x,y> = AffineSpace(ZZ, 2)
            sage: H = Hom(A, A)
            sage: f = H([(x^2-2)/(2*y), y^2-3*x])
            sage: f.nth_iterate_map(2)
            Scheme endomorphism of Affine Space of dimension 2 over Integer Ring
              Defn: Defined on coordinates by sending (x, y) to
                    ((x^4 - 4*x^2 - 8*y^2 + 4)/(8*y^4 - 24*x*y^2), (2*y^5 - 12*x*y^3
            + 18*x^2*y - 3*x^2 + 6)/(2*y))

        ::

            sage: A.<x> = AffineSpace(QQ, 1)
            sage: H = Hom(A, A)
            sage: f = H([(3*x^2-2)/(x)])
            sage: f.nth_iterate_map(3)
            Scheme endomorphism of Affine Space of dimension 1 over Rational Field
              Defn: Defined on coordinates by sending (x) to
                    ((2187*x^8 - 6174*x^6 + 6300*x^4 - 2744*x^2 + 432)/(81*x^7 -
            168*x^5 + 112*x^3 - 24*x))

        ::

            sage: A.<x,y> = AffineSpace(ZZ, 2)
            sage: X = A.subscheme([x-y^2])
            sage: H = Hom(X, X)
            sage: f = H([9*x^2, 3*y])
            sage: f.nth_iterate_map(2)
            Scheme endomorphism of Closed subscheme of Affine Space of dimension 2
            over Integer Ring defined by:
              -y^2 + x
              Defn: Defined on coordinates by sending (x, y) to
                    (729*x^4, 9*y)
        """
        if self.domain() != self.codomain():
            raise TypeError("domain and codomain of function not equal")
        N = self.codomain().ambient_space().dimension_relative()
        F = list(self._polys)
        R = F[0].parent()
        Coord_ring = self.codomain().ambient_space().coordinate_ring()
        D = Integer(n).digits(2)
        PHI = [Coord_ring.gen(i) for i in range(N)]
        for i in range(len(D)):
            T = [F[j] for j in range(N)]
            for k in range(D[i]):
                PHI = [PHI[j](T) for j in range(N)]
            if i != len(D) - 1:  #avoid extra iterate
                F = [R(F[j](T)) for j in range(N)]  #'square'
        H = Hom(self.domain(), self.codomain())
        return (H(PHI))
Exemple #52
0
 def relevant_degs(self):
     return Integer(self.geometric_extension_degree).divisors()[1:-1]
def check_prime(K,P):
    r"""
    Function to check that `P` determines a prime of `K`, and return that ideal.

    INPUT:

    - ``K`` -- a number field (including `\QQ`).

    - ``P`` -- an element of ``K`` or a (fractional) ideal of ``K``.

    OUTPUT:

    - If ``K`` is `\QQ`: the prime integer equal to or which generates `P`.

    - If ``K`` is not `\QQ`: the prime ideal equal to or generated by `P`.

    .. note::

       If `P` is not a prime and does not generate a prime, a TypeError is raised.

    EXAMPLES::

        sage: from sage.schemes.elliptic_curves.ell_local_data import check_prime
        sage: check_prime(QQ,3)
        3
        sage: check_prime(QQ,QQ(3))
        3
        sage: check_prime(QQ,ZZ.ideal(31))
        31
        sage: K.<a>=NumberField(x^2-5)
        sage: check_prime(K,a)
        Fractional ideal (a)
        sage: check_prime(K,a+1)
        Fractional ideal (a + 1)
        sage: [check_prime(K,P) for P in K.primes_above(31)]
        [Fractional ideal (5/2*a + 1/2), Fractional ideal (5/2*a - 1/2)]
        sage: L.<b> = NumberField(x^2+3)
        sage: check_prime(K, L.ideal(5))
        Traceback (most recent call last):
        ..
        TypeError: The ideal Fractional ideal (5) is not a prime ideal of Number Field in a with defining polynomial x^2 - 5
        sage: check_prime(K, L.ideal(b))
        Traceback (most recent call last):
        TypeError: No compatible natural embeddings found for Number Field in a with defining polynomial x^2 - 5 and Number Field in b with defining polynomial x^2 + 3
    """
    if K is QQ:
        if P in ZZ or isinstance(P, integer_types + (Integer,)):
            P = Integer(P)
            if P.is_prime():
                return P
            else:
                raise TypeError("The element %s is not prime" % (P,) )
        elif P in QQ:
            raise TypeError("The element %s is not prime" % (P,) )
        elif is_Ideal(P) and P.base_ring() is ZZ:
            if P.is_prime():
                return P.gen()
            else:
                raise TypeError("The ideal %s is not a prime ideal of %s" % (P, ZZ))
        else:
            raise TypeError("%s is neither an element of QQ or an ideal of %s" % (P, ZZ))

    if not is_NumberField(K):
        raise TypeError("%s is not a number field" % (K,) )

    if is_NumberFieldFractionalIdeal(P) or P in K:
        # if P is an ideal, making sure it is an fractional ideal of K
        P = K.fractional_ideal(P)
        if P.is_prime():
            return P
        else:
            raise TypeError("The ideal %s is not a prime ideal of %s" % (P, K))

    raise TypeError("%s is not a valid prime of %s" % (P, K))
Exemple #54
0
def atomic_basis_odd(n, basis, p, **kwds):
    r"""
    `P^s_t`-bases and commutator basis in dimension `n` at odd primes.

    This function is called ``atomic_basis_odd`` in analogy with
    :func:`atomic_basis`.

    INPUT:

    - ``n`` - non-negative integer
    - ``basis`` - string, the name of the basis
    - ``p`` - positive prime number

    - ``profile`` - profile function (optional, default None).
      Together with ``truncation_type``, specify the profile function
      to be used; None means the profile function for the entire
      Steenrod algebra.  See
      :mod:`sage.algebras.steenrod.steenrod_algebra` and
      :func:`SteenrodAlgebra` for information on profile functions.

    - ``truncation_type`` - truncation type, either 0 or Infinity
      (optional, default Infinity if no profile function is specified,
      0 otherwise).

    OUTPUT: tuple of basis elements in dimension n

    The only possible difference in the implementations for `P^s_t`
    bases and commutator bases is that the former make sense, and
    require filtering, if there is a nontrivial profile function.
    This function is called by :func:`steenrod_algebra_basis`, and it
    will not be called for commutator bases if there is a profile
    function, so we treat the two bases exactly the same.

    EXAMPLES::

        sage: from sage.algebras.steenrod.steenrod_algebra_bases import atomic_basis_odd
        sage: atomic_basis_odd(8, 'pst_rlex', 3)
        (((), (((0, 1), 2),)),)

        sage: atomic_basis_odd(18, 'pst_rlex', 3)
        (((0, 2), ()), ((0, 1), (((1, 1), 1),)))
        sage: atomic_basis_odd(18, 'pst_rlex', 3, profile=((), (2,2,2)))
        (((0, 2), ()),)
    """
    def sorting_pair(s, t, basis):  # pair used for sorting the basis
        if basis.find('rlex') >= 0:
            return (t, s)
        elif basis.find('llex') >= 0:
            return (s, t)
        elif basis.find('deg') >= 0:
            return (s + t, t)
        elif basis.find('revz') >= 0:
            return (s + t, s)

    generic = kwds.get('generic', False if p == 2 else True)
    if n == 0:
        if not generic:
            return ((), )
        else:
            return (((), ()), )

    from sage.rings.all import Integer
    from sage.rings.infinity import Infinity
    from sage.combinat.integer_vector_weighted import WeightedIntegerVectors
    profile = kwds.get("profile", None)
    trunc = kwds.get("truncation_type", 0)

    result = []
    for dim in range(n // (2 * p - 2) + 1):
        P_result = []
        for v in WeightedIntegerVectors(dim, xi_degrees(dim,
                                                        p=p,
                                                        reverse=False)):
            mono = []
            for t, a in enumerate(v):
                for s, pow in enumerate(Integer(a).digits(p)):
                    if pow > 0:
                        mono.append(((s, t + 1), pow))
            P_result.append(mono)
        for p_mono in P_result:
            p_mono.sort(key=lambda x: sorting_pair(x[0][0], x[0][1], basis))
            deg = n - 2 * dim * (p - 1)
            q_degrees = [
                1 + 2 * (p - 1) * d
                for d in xi_degrees((deg - 1) // (2 * (p - 1)), p)
            ] + [1]
            q_degrees_decrease = q_degrees
            q_degrees.reverse()
            if deg % (2 * (p - 1)) <= len(q_degrees):
                # if this inequality fails, no way to have a partition
                # with distinct parts.
                for sigma in restricted_partitions(deg,
                                                   q_degrees_decrease,
                                                   no_repeats=True):
                    index = 0
                    q_mono = []
                    for q in q_degrees:
                        if q in sigma:
                            q_mono.append(index)
                        index += 1
                    # check profile:
                    okay = True
                    if profile is not None and profile != ((), ()):
                        # check profile function for q_mono
                        for i in q_mono:
                            if ((len(profile[1]) > i and profile[1][i] == 1)
                                    or (len(profile[1]) <= i and trunc == 0)):
                                okay = False
                                break

                        for ((s, t), exp) in p_mono:
                            if ((len(profile[0]) > t - 1
                                 and profile[0][t - 1] <= s)
                                    or (len(profile[0]) <= t - 1
                                        and trunc < Infinity)):
                                okay = False
                                break

                    if okay:
                        if list(p_mono) == [0]:
                            p_mono = []
                        result.append((tuple(q_mono), tuple(p_mono)))
    return tuple(result)
Exemple #55
0
    def an(self, use_database=False, descent_second_limit=12):
        r"""
        Returns the Birch and Swinnerton-Dyer conjectural order of `Sha`
        as a provably correct integer, unless the analytic rank is > 1,
        in which case this function returns a numerical value.

        INPUT:

            - ``use_database`` -- bool (default: ``False``); if ``True``, try to use any
              databases installed to lookup the analytic order of `Sha`, if
              possible.  The order of `Sha` is computed if it cannot be looked up.

            - ``descent_second_limit`` -- int (default: 12); limit to use on
              point searching for the quartic twist in the hard case

        This result is proved correct if the order of vanishing is 0
        and the Manin constant is <= 2.

        If the optional parameter ``use_database`` is ``True`` (default:
        ``False``), this function returns the analytic order of `Sha` as
        listed in Cremona's tables, if this curve appears in Cremona's
        tables.

        NOTE:

        If you come across the following error::

            sage: E = EllipticCurve([0, 0, 1, -34874, -2506691])
            sage: E.sha().an()
            Traceback (most recent call last):
            ...
            RuntimeError: Unable to compute the rank, hence generators, with certainty (lower bound=0, generators found=[]).  This could be because Sha(E/Q)[2] is nontrivial.
            Try increasing descent_second_limit then trying this command again.

        You can increase the ``descent_second_limit`` (in the above example,
        set to the default, 12) option to try again::

            sage: E.sha().an(descent_second_limit=16)  # long time (2s on sage.math, 2011)
            1

        EXAMPLES::

            sage: E = EllipticCurve([0, -1, 1, -10, -20])   # 11A  = X_0(11)
            sage: E.sha().an()
            1
            sage: E = EllipticCurve([0, -1, 1, 0, 0])       # X_1(11)
            sage: E.sha().an()
            1

            sage: EllipticCurve('14a4').sha().an()
            1
            sage: EllipticCurve('14a4').sha().an(use_database=True)   # will be faster if you have large Cremona database installed
            1

        The smallest conductor curve with nontrivial `Sha`::

            sage: E = EllipticCurve([1,1,1,-352,-2689])     # 66b3
            sage: E.sha().an()
            4

        The four optimal quotients with nontrivial `Sha` and conductor <= 1000::

            sage: E = EllipticCurve([0, -1, 1, -929, -10595])       # 571A
            sage: E.sha().an()
            4
            sage: E = EllipticCurve([1, 1, 0, -1154, -15345])       # 681B
            sage: E.sha().an()
            9
            sage: E = EllipticCurve([0, -1, 0, -900, -10098])       # 960D
            sage: E.sha().an()
            4
            sage: E = EllipticCurve([0, 1, 0, -20, -42])            # 960N
            sage: E.sha().an()
            4

        The smallest conductor curve of rank > 1::

            sage: E = EllipticCurve([0, 1, 1, -2, 0])       # 389A (rank 2)
            sage: E.sha().an()
            1.00000000000000

        The following are examples that require computation of the Mordell-Weil
        group and regulator::

            sage: E = EllipticCurve([0, 0, 1, -1, 0])                     # 37A  (rank 1)
            sage: E.sha().an()
            1

            sage: E = EllipticCurve("1610f3")
            sage: E.sha().an()
            4

        In this case the input curve is not minimal, and if this function did not
        transform it to be minimal, it would give nonsense::

            sage: E = EllipticCurve([0,-432*6^2])
            sage: E.sha().an()
            1

        See :trac:`10096`: this used to give the wrong result 6.0000
        before since the minimal model was not used::

            sage: E = EllipticCurve([1215*1216,0]) # non-minimal model
            sage: E.sha().an()  # long time (2s on sage.math, 2011)
            1.00000000000000
            sage: E.minimal_model().sha().an()  # long time (1s on sage.math, 2011)
            1.00000000000000
        """
        if hasattr(self, '__an'):
            return self.__an
        if use_database:
            d = self.Emin.database_curve()
            if hasattr(d, 'db_extra'):
                self.__an = Integer(round(float(d.db_extra[4])))
                return self.__an

        # it's critical to switch to the minimal model.
        E = self.Emin
        eps = E.root_number()
        if eps == 1:
            L1_over_omega = E.lseries().L_ratio()
            if L1_over_omega == 0: # order of vanishing is at least 2
                return self.an_numerical(use_database=use_database)
            T = E.torsion_subgroup().order()
            Sha = (L1_over_omega * T * T) / Q(E.tamagawa_product())
            try:
                Sha = Integer(Sha)
            except ValueError:
                raise RuntimeError("There is a bug in an, since the computed conjectural order of Sha is %s, which is not an integer."%Sha)
            if not arith.is_square(Sha):
                raise RuntimeError("There is a bug in an, since the computed conjectural order of Sha is %s, which is not a square."%Sha)
            E.__an = Sha
            self.__an = Sha
            return Sha

        else:  # rank > 0  (Not provably correct)
            L1, error_bound = E.lseries().deriv_at1(10*sqrt(E.conductor()) + 10)
            if abs(L1) < error_bound:
                s = self.an_numerical()
                E.__an = s
                self.__an = s
                return s

            regulator = E.regulator(use_database=use_database, descent_second_limit=descent_second_limit)
            T = E.torsion_subgroup().order()
            omega = E.period_lattice().omega()
            Sha = Integer(round ( (L1 * T * T) / (E.tamagawa_product() * regulator * omega) ))
            try:
                Sha = Integer(Sha)
            except ValueError:
                raise RuntimeError("There is a bug in an, since the computed conjectural order of Sha is %s, which is not an integer."%Sha)
            if not arith.is_square(Sha):
                raise RuntimeError("There is a bug in an, since the computed conjectural order of Sha is %s, which is not a square."%Sha)
            E.__an = Sha
            self.__an = Sha
            return Sha