Exemplo n.º 1
0
def factorize_matrix(m,M):
    #assert is_in_Gamma_1(m,M,determinant_condition = False)
    assert m.det().abs() == 1
    a,b,c,d = m.list()
    if QQ(a).denominator() != 1:
        raise RuntimeError
        #return [m]
    assert a % M == 1
    aabs = ZZ(a).abs()
    Zm = Zmod(M)
    for alphamul in sorted(range(-aabs.sqrt(50)/M,aabs.sqrt(50)/M),key = lambda x: ZZ(x).abs()):
        alpha = 1 + M*alphamul
        if alpha.abs() >= aabs:
            continue
        delta0 = (Zm(alpha)**(-1)).lift()
        for delta in xrange(delta0-10*M,delta0+10*M,M):
            if alpha * delta == 1:
                continue
            gamma0 = ZZ( (alpha*delta -1) / M)
            c1vec = gamma0.divisors()
            for c1 in c1vec:
                ulentry = (a*delta-b*c1*M).abs()
                urentry = (b*alpha-a*gamma0/c1).abs()
                if ulentry < aabs and urentry < b.abs():
                    gamma = c1*M
                    beta = ZZ(gamma0/c1)
                    r1 = Matrix(QQ,2,2,[alpha,beta,gamma,delta])
                    r2 = m*r1.adjugate()
                    assert r1.determinant() == 1
                    assert is_in_Gamma_1(r1,M,determinant_condition = False)
                    assert is_in_Gamma_1(r1,M,determinant_condition = False)
                    V1 = factorize_matrix(r1,M)
                    V2 = factorize_matrix(r2,M)
                    return V2 + V1
    return [m]
Exemplo n.º 2
0
    def get_Up_reps_bianchi(self, pi, pi_bar):
        B = self.small_group().B
        Upreps0 = [
            Matrix(self.F, 2, 2, [pi, a, 0, 1]) for a in range(self.prime())
        ]
        Upreps_bar0 = [
            Matrix(self.F, 2, 2, [pi_bar, a, 0, 1])
            for a in range(self.prime())
        ]
        Upreps = [
            B([(o[0, 0] + o[1, 1]) / 2, (o[0, 0] - o[1, 1]) / 2,
               (-o[0, 1] - o[1, 0]) / 2, (-o[0, 1] + o[1, 0]) / 2])
            for o in Upreps0
        ]
        Upreps_bar = [
            B([(o[0, 0] + o[1, 1]) / 2, (o[0, 0] - o[1, 1]) / 2,
               (-o[0, 1] - o[1, 0]) / 2, (-o[0, 1] + o[1, 0]) / 2])
            for o in Upreps_bar0
        ]

        for o in Upreps:
            set_immutable(o)
        for o in Upreps_bar:
            set_immutable(o)
        return Upreps, Upreps_bar
Exemplo n.º 3
0
def find_optimal_embeddings(F,use_magma = False,extra_conductor = 1,magma = None):
    w=F.maximal_order().ring_generators()[0]
    D = F.discriminant()
    ## this matrix gives an optimal embedding of conductor 1
    if use_magma == True or extra_conductor != 1:
        if magma is None:
            from sage.interfaces.magma import magma
        tmp = magma.ReducedForms(str(D*extra_conductor**2),nvals = 1)
        G = [[tmp[i+1][j]._sage_() for j in [1,2,3]] for i in range(len(tmp))]
    elif F.class_number() == 1:
        assert extra_conductor == 1
        return [Matrix(QQ,2,2,[w.trace(),-w.norm(),1,0])]
    else:
        assert extra_conductor == 1
        fact = F(1) if D > 0 else w - 1/2 * w.trace()
        G = []
        for I in [F.ideal(cl.gens()) for cl in F.class_group()]:
            alpha,beta = I.integral_basis()
            if QQ((alpha*beta.conjugate() - beta*alpha.conjugate())/fact) < 0:
                alpha,beta = beta,alpha
            nrm = I.norm()
            a = ZZ(alpha.norm()/nrm)
            c = ZZ(beta.norm()/nrm)
            b = ZZ((alpha+beta).norm()/nrm) - a - c
            G.append((a,b,c))
    delta = extra_conductor * F.gen() if D%4 == 1 else 2*extra_conductor * F.gen() # delta = sqrt{discriminant}
    r,s = delta.coordinates_in_terms_of_powers()(w) # w = r + s*delta
    return [Matrix(QQ,2,2,[r-s*B,-2*s*C,2*s*A,r+s*B]) for A,B,C in G] # There's a typo in Darmon-Pollack pg.12, fixed by Juan Restrepo
Exemplo n.º 4
0
 def space(self):
     r'''
     Calculates the homology space as a Z-module.
     '''
     verb = get_verbose()
     set_verbose(0)
     V = self.coefficient_module()
     R = V.base_ring()
     Vdim = V.dimension()
     G = self.group()
     gens = G.gens()
     ambient = R**(Vdim * len(gens))
     if self.trivial_action():
         cycles = ambient
     else:
         # Now find the subspace of cycles
         A = Matrix(R, Vdim, 0)
         for g in gens:
             for v in V.gens():
                 A = A.augment(matrix(R,Vdim,1,list(vector(g**-1 * v - v))))
         K = A.right_kernel_matrix()
         cycles = ambient.submodule([ambient(list(o)) for o in K.rows()])
     boundaries = []
     for r in G.get_relation_words():
         grad = self.twisted_fox_gradient(G(r).word_rep)
         for v in V.gens():
             boundaries.append(cycles(ambient(sum([list(a * vector(v)) for a in grad],[]))))
     boundaries = cycles.submodule(boundaries)
     ans = cycles.quotient(boundaries)
     set_verbose(verb)
     return ans
Exemplo n.º 5
0
def factorize_matrix(m,M):
    #assert is_in_Gamma_1(m,M,determinant_condition = False)
    assert m.det().abs() == 1
    a,b,c,d = m.list()
    if QQ(a).denominator() != 1:
        raise RuntimeError
        #return [m]
    assert a % M == 1
    aabs = ZZ(a).abs()
    Zm = Zmod(M)
    for alphamul in sorted(range(-aabs.sqrt(50)/M,aabs.sqrt(50)/M),key = lambda x: ZZ(x).abs()):
        alpha = 1 + M*alphamul
        if alpha.abs() >= aabs:
            continue
        delta0 = (Zm(alpha)**(-1)).lift()
        for delta in xrange(delta0-10*M,delta0+10*M,M):
            if alpha * delta == 1:
                continue
            gamma0 = ZZ( (alpha*delta -1) / M)
            c1vec = gamma0.divisors()
            for c1 in c1vec:
                ulentry = (a*delta-b*c1*M).abs()
                urentry = (b*alpha-a*gamma0/c1).abs()
                if ulentry < aabs and urentry < b.abs():
                    gamma = c1*M
                    beta = ZZ(gamma0/c1)
                    r1 = Matrix(QQ,2,2,[alpha,beta,gamma,delta])
                    r2 = m*r1.adjoint()
                    assert r1.determinant() == 1
                    assert is_in_Gamma_1(r1,M,determinant_condition = False)
                    assert is_in_Gamma_1(r1,M,determinant_condition = False)
                    V1 = factorize_matrix(r1,M)
                    V2 = factorize_matrix(r2,M)
                    return V2 + V1
    return [m]
Exemplo n.º 6
0
def _convert_matrix_from_modsyms(symbs, T):
    r"""
    Given a space of modular symbols and a matrix T acting on it, calculate the
    matrix of the corresponding operator on the echelon-form basis of the
    corresponding space of modular forms.

    The matrix T *must* commute with the Hecke operators! We use this when T is
    either a Hecke operator, or a diamond operator. This will *not work* for
    the Atkin-Lehner operators, for instance, when there are oldforms present.

    OUTPUT:
        A pair `(T_e, ps)` with `T_e` the converted matrix and `ps` a list
        of pivot elements of the echelon basis.

    EXAMPLE::

        sage: CuspForms(Gamma1(5), 6).diamond_bracket_matrix(3) # indirect doctest
        [ -1   0   0]
        [  3   5 -12]
        [  1   2  -5]
    """
    d = symbs.rank()

    # create a vector space of appropriate dimension to
    # contain our q-expansions
    A = symbs.base_ring()
    r = symbs.sturm_bound()
    X = A ** r
    Y = X.zero_submodule()
    basis = []
    basis_images = []

    # we repeatedly use these matrices below, so we store them
    # once as lists to save time.
    hecke_matrix_ls = [symbs.hecke_matrix(m).list() for m in range(1, r + 1)]
    hecke_image_ls = [(T * symbs.hecke_matrix(m)).list() for m in range(1, r + 1)]

    # compute the q-expansions of some cusp forms and their
    # images under T_n
    for i in xrange(d ** 2):
        v = X([hecke_matrix_ls[m][i] for m in xrange(r)])
        Ynew = Y.span(Y.basis() + [v])
        if Ynew.rank() > Y.rank():
            basis.append(v)
            basis_images.append(X([hecke_image_ls[m][i] for m in xrange(r)]))
            Y = Ynew
            if len(basis) == d:
                break

    # now we can compute the matrix acting on the echelonized space of mod forms
    # need to pass A as base ring since otherwise there are problems when the
    # space has dimension 0
    bigmat = Matrix(A, basis).augment(Matrix(A, basis_images))
    bigmat.echelonize()
    pivs = bigmat.pivots()
    return bigmat.matrix_from_rows_and_columns(range(d), [r + x for x in pivs]), pivs
Exemplo n.º 7
0
def decompose(gtau,lmb,uu):
    if uu == 0:
        return [gtau]
    E_lambda = Matrix(QQ,2,2,[1,lmb,0,1])
    #we know that E_lambda*gtau is a matrix [a,b,c,d] such that c=uu+ta for some unit uu; now we find uu and t
    MM=(E_lambda*gtau).change_ring(QQ)
    a,b,c,d=MM.list()
    t = QQ(c-uu)/QQ(a)
    E1i=Matrix(QQ,2,2,[1,0,uu*(1-a),1])
    E2i=Matrix(QQ,2,2,[1,-1/uu,0,1])
    E34i=Matrix(QQ,2,2,[1,0,c+t*(1-a),1])
    E_x=(E34i*E2i*E1i)**(-1)*MM
    return [E_lambda**(-1), E34i,E2i,E1i,E_x]
Exemplo n.º 8
0
def _find_initial_embedding_list(v0, M, W, orientation, OD, u):
    r'''
    .
    '''
    F = v0.domain()
    p = v0.codomain().base_ring().prime()
    emblist = []
    wD = OD.ring_generators()[0]
    u0vec = wD.coordinates_in_terms_of_powers()(u)
    u0vec_inv = wD.coordinates_in_terms_of_powers()(u**-1)
    assert wD.minpoly() == W.minpoly()
    Blist = [M2Z([1, 0, 0, 1])] + [
        M2Z([ZZ(M / d1), i, 0, d1]) for d1 in ZZ(M).divisors()
        for i in range(-2 * ZZ(QQ(d1 / 2).ceil()), 2 * ZZ(QQ(d1 / 2).ceil()) +
                       1)
    ]
    for B in Blist:
        W_M = B * W * B**-1
        if all([x.is_integral()
                for x in W_M.list()]) and ZZ(W_M[1, 0]) % M == 0:
            if orientation is not None:
                for ell, r in ZZ(M).factor():
                    if W_M[0, 0] % ell != orientation % ell:
                        Wl = Matrix(ZZ, 2, 2, [0, -1, ell, 0])
                        W_M = Wl**(-1) * W_M * Wl
                assert all([
                    W_M[0, 0] % ell == orientation % ell
                    for ell, r in ZZ(M).factor()
                ])
            # Computation of tau_0: it's one of the roots of the minimal polynomial of W.
            tau0 = compute_tau0(v0, W_M, wD, return_exact=True)
            if F.class_number() > 1 and find_containing_affinoid(
                    p, v0(tau0)).determinant().valuation(
                        p) % 2 == 1 and orientation is not None:
                Wp = Matrix(ZZ, 2, 2, [0, -1, p, 0])
                W_M = Wp**(-1) * W_M * Wp
                assert all([
                    W_M[0, 0] % ell == orientation % ell
                    for ell, r in ZZ(M).factor()
                ])
                tau0 = compute_tau0(v0, W_M, wD, return_exact=True)
                assert find_containing_affinoid(
                    p, v0(tau0)).determinant().valuation(p) % 2 == 0
            gtau_orig_1 = u0vec[0] + u0vec[1] * W_M
            gtau_orig_2 = u0vec_inv[0] + u0vec_inv[1] * W_M
            emblist.extend([(tau0, gtau_orig_1), (tau0, gtau_orig_2)])
    if len(emblist) == 0:
        raise RuntimeError('No embeddings found !')
    verbose("Found %s initial embeddings." % len(emblist))
    return emblist
Exemplo n.º 9
0
 def __init__(self, G, V, trivial_action = False):
     self._group = G
     self._coeffmodule = V
     self._trivial_action = trivial_action
     self._gen_pows = []
     self._gen_pows_neg = []
     if trivial_action:
         self._acting_matrix = lambda x, y: matrix(V.base_ring(),V.dimension(),V.dimension(),1)
         gens_local = [ (None, None) for g in G.gens() ]
     else:
         def acting_matrix(x,y):
             try:
                 return V.acting_matrix(x,y)
             except:
                 return V.acting_matrix(G.embed(x.quaternion_rep,V.base_ring().precision_cap()), y)
         self._acting_matrix = acting_matrix
         gens_local = [ (g, g**-1) for g in G.gens() ]
     onemat = G(1)
     try:
         dim = V.dimension()
     except AttributeError:
         dim = len(V.basis())
     one = Matrix(V.base_ring(),dim,dim,1)
     for g, ginv in gens_local:
         A = self._acting_matrix(g, dim)
         self._gen_pows.append([one, A])
         Ainv = self._acting_matrix(ginv, dim)
         self._gen_pows_neg.append([one, Ainv])
     Parent.__init__(self)
     return
Exemplo n.º 10
0
    def get_Up_reps(self):
        if self._hardcode_matrices:
            B = self.small_group().B
            try:
                pi = self.ideal_p.gens_reduced()[0]
                pinorm = pi.norm()
                alist = list(self.ideal_p.residues())
            except AttributeError:
                pi = self.prime()
                pinorm = pi
                alist = [a for a in range(pinorm)]

            Upreps0 = [Matrix(self.F, 2, 2, [pi, a, 0, 1]) for a in alist]
            Upreps = [
                self.small_group().matrix_to_quaternion(o) for o in Upreps0
            ]
            for o in Upreps:
                set_immutable(o)
            return Upreps

        wp = self.wp()
        if self.F == QQ and self.discriminant == 1:
            lam = -wp.determinant()
        else:
            lam = -wp.reduced_norm()
        tmp = [lam * o**-1 * wp**-1 for o in self.get_BT_reps()[1:]]
        for o in tmp:
            set_immutable(o)
        return tmp
Exemplo n.º 11
0
    def _convert_matrix_from_modsyms_eis(self, A):
        r"""
        Given a matrix acting on the space of modular symbols corresponding to
        this space, calculate the matrix of the operator it induces on this
        space itself. Used for Hecke and diamond operators.

        This is a minor modification of the code used for cusp forms, which is
        required because modular symbols "don't see the constant term": the
        modular symbol method calculates the matrix of the operator with
        respect to the unique basis of the modular forms space for which the
        *non-constant* coefficients are in echelon form, and we need to modify
        this to get a matrix with respect to the basis we're actually using.

        EXAMPLES::

            sage: EisensteinForms(Gamma1(6), 3).hecke_matrix(3) # indirect doctest
            [ 1  0 72  0]
            [ 0  0 36 -9]
            [ 0  0  9  0]
            [ 0  1 -4 10]
        """
        from .cuspidal_submodule import _convert_matrix_from_modsyms
        symbs = self.modular_symbols(sign=0)
        d = self.rank()
        wrong_mat, pivs = _convert_matrix_from_modsyms(symbs, A)
        c = Matrix(self.base_ring(), d,
                   [self.basis()[i][j + 1] for i in range(d) for j in pivs])
        return c * wrong_mat * ~c
Exemplo n.º 12
0
 def get_action_data(self, g, K=None):
     a, b, c, d = g.list()
     prec = self._prec
     if K is None:
         if hasattr(a, 'lift'):
             a, b, c, d = a.lift(), b.lift(), c.lift(), d.lift()
             p = g.parent().base_ring().prime()
             K = ZpCA(p, prec)
         else:
             K = g.parent().base_ring()
     Ps = PowerSeriesRing(K, 't', default_prec=prec)
     z = Ps.gen()
     zz = (d * z - b) / (-c * z + a)
     zz_ps0 = Ps(zz).add_bigoh(prec)
     if self._dlog:
         zz_ps = ((a * d - b * c) * (-c * z + a)**-2).add_bigoh(prec)
     else:
         zz_ps = Ps(1).add_bigoh(prec)
     if self.is_additive():
         M = Matrix(ZZ, prec, prec, 0)
         for j in range(prec):
             for i, aij in enumerate(zz_ps.list()):
                 M[i, j] = aij
             if j < prec - 1:  # Don't need the last multiplication
                 zz_ps = (zz_ps0 * zz_ps).add_bigoh(prec)
             else:
                 return M
     else:
         ans = [Ps(1), zz_ps]
         for _ in range(prec - 1):
             zz_ps = (zz_ps0 * zz_ps).add_bigoh(prec)
             ans.append(zz_ps)
         return ans
Exemplo n.º 13
0
    def _compute_hecke_matrix(self, n):
        r"""
        EXAMPLES::

            sage: CuspForms(GammaH(31, [7]), 1).hecke_matrix(7)
            [-1]
            sage: C = CuspForms(GammaH(124, [33]), 1) # long time
            sage: C.hecke_matrix(2) # long time
            [ 0  0 -1 -1  0  1  0]
            [ 1  0  0 -1 -1 -1  0]
            [ 0  0  0 -1  1  1 -1]
            [ 0  1  0 -1  0  0  0]
            [ 0  0 -1  0  0  1  1]
            [ 0  0  0 -1  0  0 -1]
            [ 0  0  0  0  0  1  0]
            sage: C.hecke_matrix(7) # long time
            [ 0  1  0 -1  0  0  1]
            [ 0 -1  0  0  0  0  0]
            [ 0  1 -1  0  0  0  1]
            [ 0  0  0 -1  0  0  0]
            [ 0  1  1  0  0 -1  0]
            [ 1  0 -1 -1 -1  0  1]
            [ 0  1  0  0  1  0  0]
            sage: C.hecke_matrix(23) == 0 # long time
            True

        """
        chars = self.group().characters_mod_H(sign=-1, galois_orbits=True)
        A = Matrix(QQ, 0, 0)
        for c in chars:
            chi = c.minimize_base_ring()
            d = weight1.dimension_wt1_cusp_forms(chi)
            e = chi.base_ring().degree()
            H = Matrix(QQ, d * e, d * e)
            from .constructor import CuspForms
            M = CuspForms(chi, 1).hecke_matrix(n)
            if e == 1:
                H = M
            else:
                for i in range(d):
                    for j in range(d):
                        H[e * i:e * (i + 1),
                          e * j:e * (j + 1)] = M[i, j].matrix().transpose()
            A = A.block_sum(H)
        t = self._transformation_matrix()
        return t * A * ~t
Exemplo n.º 14
0
 def get_Up_reps_bianchi(self, pi, pi_bar):
     if not self._hardcode_matrices:
         raise NotImplementedError('For Bianchi, need to hardcode matrices')
     B = self.small_group().B
     # alist = range(self.prime())
     alist = list(self.ideal_p.residues())
     Upreps0 = [Matrix(self.F, 2, 2, [pi, a, 0, 1]) for a in alist]
     Upreps_bar0 = [Matrix(self.F, 2, 2, [pi_bar, a, 0, 1]) for a in alist]
     Upreps = [self.small_group().matrix_to_quaternion(o) for o in Upreps0]
     Upreps_bar = [
         self.small_group().matrix_to_quaternion(o) for o in Upreps_bar0
     ]
     for o in Upreps:
         set_immutable(o)
     for o in Upreps_bar:
         set_immutable(o)
     return Upreps, Upreps_bar
Exemplo n.º 15
0
    def find_matrix_from_cusp(self, cusp):
        r'''
        Returns a matrix gamma and a cusp representative modulo Gamma0(N) (c2:d2),
        represented as a matrix (a,b;c,d), such that gamma * cusp = (c2:d2).
        '''
        a, c = cusp
        reduction_table, _ = self.cusp_reduction_table()
        P = self.get_P1List()
        if hasattr(P.N(),'number_field'):
            K = P.N().number_field()
        else:
            K = QQ

        # Find a matrix g = [a,b,c,d] in SL2(O_K) such that g * a/c = oo
        # Define (c1:d1) to be the rep in P1(O_K/N) such that (c1:d1) == (c:d).
        if c == 0: ## case cusp infinity: (a,c) should equal (1,0)
            a = 1
            g = Matrix(2,2,[1,0,0,1])
            c1, d1 = P.normalize(0, 1)
        else:
            if K == QQ:
                g0, d, b = ZZ(a).xgcd(-c)
                if g0 != 1:
                    a /= g0
                    c /= g0
            else:
                """
                Compute gcd if a,c are coprime in F, and x,y such that
                    ax + cy = 1.
                """
                if a.parent() != c.parent():
                    raise ValueError('a,c not in the same field.')
                if a.gcd(c) != 1:
                    raise ValueError('a,c not coprime.')

                d = next(o for o in K.ideal(c).residues() if a * o - 1 in K.ideal(c))
                b = (a * d - 1) / c

            g = Matrix(2,2,[[d,-b],[-c,a]]) # the inverse
            c1, d1 = P.normalize(c, d)
        assert g.determinant() == 1

        A, T = reduction_table[(c1,d1)]
        gamma = A.parent()(A * T * g)
        return gamma, A
Exemplo n.º 16
0
 def make_twoadic_data(self):
     if not self.cm:
         self.twoadicdata = twoadicdata = db.ec_2adic.lookup(
             self.lmfdb_label)
         from sage.matrix.all import Matrix
         twoadicdata['gen_matrices'] = ','.join(
             latex(Matrix(2, 2, M)) for M in twoadicdata['twoadic_gens'])
         twoadicdata['rouse_url'] = ''.join(
             [ROUSE_URL_PREFIX, twoadicdata['twoadic_label'], ".html"])
Exemplo n.º 17
0
def _convert_matrix_from_modsyms(symbs, T):
    r"""
    Given a space of modular symbols and a matrix T acting on it, calculate the
    matrix of the corresponding operator on the echelon-form basis of the
    corresponding space of modular forms.

    The matrix T *must* commute with the Hecke operators! We use this when T is
    either a Hecke operator, or a diamond operator. This will *not work* for
    the Atkin-Lehner operators, for instance, when there are oldforms present.

    OUTPUT:
        A pair `(T_e, ps)` with `T_e` the converted matrix and `ps` a list
        of pivot elements of the echelon basis.

    EXAMPLE::

        sage: CuspForms(Gamma1(5), 6).diamond_bracket_matrix(3) # indirect doctest
        [ -1   0   0]
        [  3   5 -12]
        [  1   2  -5]
    """
    d = symbs.rank()

    # create a vector space of appropriate dimension to
    # contain our q-expansions
    A = symbs.base_ring()
    r = symbs.sturm_bound()
    X = A**r
    Y = X.zero_submodule()
    basis = []
    basis_images = []

    # we repeatedly use these matrices below, so we store them
    # once as lists to save time.
    hecke_matrix_ls = [symbs.hecke_matrix(m).list() for m in range(1, r + 1)]
    hecke_image_ls = [(T * symbs.hecke_matrix(m)).list()
                      for m in range(1, r + 1)]

    # compute the q-expansions of some cusp forms and their
    # images under T_n
    for i in xrange(d**2):
        v = X([hecke_matrix_ls[m][i] for m in xrange(r)])
        Ynew = Y.span(Y.basis() + [v])
        if Ynew.rank() > Y.rank():
            basis.append(v)
            basis_images.append(X([hecke_image_ls[m][i] for m in xrange(r)]))
            Y = Ynew
            if len(basis) == d: break

    # now we can compute the matrix acting on the echelonized space of mod forms
    # need to pass A as base ring since otherwise there are problems when the
    # space has dimension 0
    bigmat = Matrix(A, basis).augment(Matrix(A, basis_images))
    bigmat.echelonize()
    pivs = bigmat.pivots()
    return bigmat.matrix_from_rows_and_columns(range(d),
                                               [r + x for x in pivs]), pivs
Exemplo n.º 18
0
    def get_BT_reps(self):
        reps = [self.Gn.B(1)] + [None for i in xrange(self.p)]
        emb = self.get_embedding(20)
        matrices = [(i + 1, matrix(QQ, 2, 2, [i, 1, -1, 0]))
                    for i in xrange(self.p)]
        if self._matrix_group:
            verbose('Using hard-coded matrices for BT (Bianchi)')
            if F == QQ:
                wp = self.wp()
                return [self.Gn(1).quaternion_rep] + [
                    1 / self.p * wp * matrix(QQ, 2, 2, [1, -i, 0, self.p])
                    for i in xrange(self.p)
                ]

            else:
                pi = self.ideal_p.gens_reduced()[0]
                B = self.Gn.B
                BTreps0 = [
                    Matrix(self.F, 2, 2, [0, -1, 1, -i])
                    for a in range(self.prime())
                ]
                BTreps = [self.Gn(1).quaternion_rep] + [
                    self.Gn(
                        B([(o[0, 0] + o[1, 1]) / 2, (o[0, 0] - o[1, 1]) / 2,
                           (-o[0, 1] - o[1, 0]) / 2,
                           (-o[0, 1] + o[1, 0]) / 2])).quaternion_rep
                    for o in BTreps0
                ]
                return BTreps

        for n_iters, elt in enumerate(self.Gn.enumerate_elements()):
            new_inv = elt**(-1)
            embelt = emb(elt)
            if (embelt[0, 0] - 1).valuation() > 0 and all([
                    not self.is_in_Gpn_order(o * new_inv)
                    for o in reps if o is not None
            ]):
                if hasattr(self.Gpn, 'nebentypus'):
                    tmp = self.do_tilde(embelt)**-1
                    tmp = tmp[0, 0] / (self.p**tmp[0, 0].valuation())
                    tmp = ZZ(tmp.lift()) % self.Gpn.level
                    if tmp not in self.Gpn.nebentypus:
                        continue
                for idx, o1 in enumerate(matrices):
                    i, mat = o1
                    if is_in_Gamma0loc(embelt * mat, det_condition=False):
                        reps[i] = set_immutable(elt)
                        del matrices[idx]
                        verbose(
                            '%s, len = %s/%s' %
                            (n_iters, self.p + 1 - len(matrices), self.p + 1))
                        if len(matrices) == 0:
                            return reps
                        break
Exemplo n.º 19
0
    def _compute_diamond_matrix(self, d):
        r"""
        EXAMPLES::

            sage: CuspForms(GammaH(31, [7]), 1).diamond_bracket_matrix(3)
            [-1]

            sage: C = CuspForms(GammaH(124, [33]), 1)   # long time
            sage: D = C.diamond_bracket_matrix(3); D    # long time
            [ 0  0  0 -1  1  0  0]
            [ 0 -1  0  0  0  0  0]
            [ 2  1  1 -2 -1 -2 -1]
            [ 0  0  0 -1  0  0  0]
            [-1  0  0  1  1  0  0]
            [ 2  0  0 -2 -1 -1  0]
            [ 0  2  1  0  0 -1  0]
            sage: t = C._transformation_matrix(); ~t * D * t   # long time
            [ 1  1  0  0  0  0  0]
            [-1  0  0  0  0  0  0]
            [ 0  0  1  1  0  0  0]
            [ 0  0 -1  0  0  0  0]
            [ 0  0  0  0 -1  0  0]
            [ 0  0  0  0  0 -1  0]
            [ 0  0  0  0  0  0 -1]
        """
        chars=self.group().characters_mod_H(sign=-1, galois_orbits=True)
        A = Matrix(QQ, 0, 0)
        for c in chars:
            chi = c.minimize_base_ring()
            dim = weight1.dimension_wt1_cusp_forms(chi)
            if chi.base_ring() == QQ:
                m = Matrix(QQ, 1, 1, [chi(d)])
            else:
                m = chi(d).matrix().transpose()
            for i in range(dim):
                A = A.block_sum(m)
        t = self._transformation_matrix()
        return t * A * ~t
    def is_irred_rep(self, image, n, force=False):
        """
        Returns `True` if the map generated by mapping the generators to the matrices defined in
        `image` is an `n`-dimensional irreducible representation of `self`, and `False` otherwise.
        Like above, the entries of `image` must be `n`-by-`n` matrices with entries in the
        algebraic closure of the base field of `self`. Its length must match the number of
        generators of `self.`

        Use `force=True` if the function does not recognize the base field as computable, but the
        field is computable.
        """
        if (not force and self.base_field() not in NumberFields
                and self.base_field() not in FiniteFields):
            raise TypeError(
                'Base field must be computable. If %s is computable' %
                self.base_field() + ' then use force=True to bypass this.')

        if n not in ZZ or n < 1:
            raise ValueError('Dimension must be a positive integer.')

        if not self.is_rep(image, n): return False

        from sage.matrix.all import Matrix
        from sage.rings.number_field.number_field import is_NumberField
        import math

        M = MatrixSpace(self.base_field().algebraic_closure(), n, sparse=True)
        image = [M(image[i]).list() for i in range(len(image))]

        if n <= 6 and is_NumberField(self.base_field()): p = 2 * n
        else:
            p = int(
                math.floor(n *
                           math.sqrt(2 * n**2 / float(n - 1) + 1 / float(4)) +
                           n / float(2) - 3))

        prod_set = list(self._create_prod_set(image, n, p))
        prod_set.append(M.one())
        vector = [mat.list() for mat in prod_set]
        return 0 not in Matrix(vector).echelon_form().diagonal()
Exemplo n.º 21
0
        def base_change_matrix(self):
            r"""
            Return the base change from the standard basis of the vector
            space of ``self`` to the basis given by the independent roots of
            ``self``.

            .. TODO::

                For non-well-generated groups there is a conflict with
                construction of the matrix for an element.

            EXAMPLES::

                sage: W = ReflectionGroup((1,1,3))                          # optional - gap3
                sage: W.base_change_matrix()                                # optional - gap3
                [1 0]
                [0 1]

                sage: W = ReflectionGroup(23)                               # optional - gap3
                sage: W.base_change_matrix()                                # optional - gap3
                [1 0 0]
                [0 1 0]
                [0 0 1]

                sage: W = ReflectionGroup((3,1,2))                          # optional - gap3
                sage: W.base_change_matrix()                                # optional - gap3
                [1 0]
                [1 1]

                sage: W = ReflectionGroup((4,2,2))                          # optional - gap3
                sage: W.base_change_matrix()                                # optional - gap3
                [   1    0]
                [E(4)    1]
            """
            from sage.matrix.all import Matrix
            return Matrix(list(self.independent_roots())).inverse()
Exemplo n.º 22
0
    def make_class(self):
        # Extract the size of the isogeny class from the database
        classdata = db.ec_classdata.lucky({'lmfdb_iso': self.lmfdb_iso})
        self.class_size = ncurves = classdata['class_size']

        # Create a list of the curves in the class from the database
        number_key = 'Cnumber' if self.label_type == 'Cremona' else 'lmfdb_number'
        self.curves = [
            db.ec_curvedata.lucky({
                'lmfdb_iso': self.lmfdb_iso,
                number_key: i + 1
            }) for i in range(ncurves)
        ]

        # Set optimality flags.  The optimal curve is conditionally
        # number 1 except in one case which is labeled differently in
        # the Cremona tables.  We know which curve is optimal iff the
        # optimality code for curve #1 is 1 (except for class 990h).

        # Note that self is actually an elliptic curve, with number=1.

        # The code here allows us to update the display correctly by
        # changing one line in this file (defining OPTIMALITY_BOUND)
        # without changing the data.

        self.cremona_bound = CREMONA_BOUND
        self.optimality_bound = OPTIMALITY_BOUND
        self.optimality_known = (self.conductor < OPTIMALITY_BOUND) or (
            (self.conductor < CREMONA_BOUND) and ((self.optimality == 1) or
                                                  (self.Ciso == '990h')))
        self.optimal_label = self.Clabel if self.label_type == 'Cremona' else self.lmfdb_label

        if self.conductor < OPTIMALITY_BOUND:
            for c in self.curves:
                c['optimal'] = (c['Cnumber'] == (3 if self.Ciso == '990h' else
                                                 1))
                c['optimality_known'] = True
        elif self.conductor < CREMONA_BOUND:
            for c in self.curves:
                c['optimal'] = (c['optimality'] > 0
                                )  # this curve possibly optimal
                c['optimality_known'] = (c['optimality'] == 1
                                         )  # this curve certainly optimal
        else:
            for c in self.curves:
                c['optimal'] = None
                c['optimality_known'] = False

        for c in self.curves:
            c['ai'] = c['ainvs']
            c['curve_url_lmfdb'] = url_for(".by_triple_label",
                                           conductor=self.conductor,
                                           iso_label=self.iso_label,
                                           number=c['lmfdb_number'])
            c['curve_url_cremona'] = url_for(
                ".by_ec_label",
                label=c['Clabel']) if self.conductor < CREMONA_BOUND else "N/A"
            if self.label_type == 'Cremona':
                c['curve_label'] = c['Clabel']
                _, c_iso, c_number = split_cremona_label(c['Clabel'])
            else:
                c['curve_label'] = c['lmfdb_label']
                _, c_iso, c_number = split_lmfdb_label(c['lmfdb_label'])
            c['short_label'] = "{}{}".format(c_iso, c_number)

        from sage.matrix.all import Matrix
        M = classdata['isogeny_matrix']

        # permute rows/cols to match labelling: the rows/cols in the
        # ec_classdata table are with respect to LMFDB ordering.
        if self.label_type == 'Cremona':
            perm = lambda i: next(c for c in self.curves
                                  if c['Cnumber'] == i + 1)['lmfdb_number'] - 1
            M = [[M[perm(i)][perm(j)] for i in range(ncurves)]
                 for j in range(ncurves)]

        M = Matrix(M)

        self.isogeny_matrix_str = latex(M)

        # Create isogeny graph with appropriate vertex labels:

        self.graph = make_graph(M, [c['short_label'] for c in self.curves])
        P = self.graph.plot(edge_labels=True, vertex_size=1000)
        self.graph_img = encode_plot(P)
        self.graph_link = '<img src="%s" width="200" height="150"/>' % self.graph_img

        self.newform = raw_typeset(
            PowerSeriesRing(QQ, 'q')(classdata['anlist'], 20, check=True))
        self.newform_label = ".".join(
            [str(self.conductor),
             str(2), 'a', self.iso_label])
        self.newform_exists_in_db = db.mf_newforms.label_exists(
            self.newform_label)
        if self.newform_exists_in_db:
            char_orbit, hecke_orbit = self.newform_label.split('.')[2:]
            self.newform_link = url_for("cmf.by_url_newform_label",
                                        level=self.conductor,
                                        weight=2,
                                        char_orbit_label=char_orbit,
                                        hecke_orbit=hecke_orbit)

        self.lfunction_link = url_for("l_functions.l_function_ec_page",
                                      conductor_label=self.conductor,
                                      isogeny_class_label=self.iso_label)

        self.friends = [('L-function', self.lfunction_link)]

        if self.cm:
            # set CM field for Properties box.
            D = ZZ(self.cm).squarefree_part()
            coeffs = [(1 - D) // 4, -1, 1] if D % 4 == 1 else [-D, 0, 1]
            lab = db.nf_fields.lucky({'coeffs': coeffs}, projection='label')
            self.CMfield = field_pretty(lab)
        else:
            self.CMfield = "no"
            if self.conductor <= 300:
                self.friends += [('Symmetric square L-function',
                                  url_for("l_functions.l_function_ec_sym_page",
                                          power='2',
                                          conductor=self.conductor,
                                          isogeny=self.iso_label))]
            if self.conductor <= 50:
                self.friends += [('Symmetric cube L-function',
                                  url_for("l_functions.l_function_ec_sym_page",
                                          power='3',
                                          conductor=self.conductor,
                                          isogeny=self.iso_label))]
        if self.newform_exists_in_db:
            self.friends += [('Modular form ' + self.newform_label,
                              self.newform_link)]

        if self.label_type == 'Cremona':
            self.title = "Elliptic curve isogeny class with Cremona label {} (LMFDB label {})".format(
                self.Ciso, self.lmfdb_iso)
        elif self.conductor < CREMONA_BOUND:
            self.title = "Elliptic curve isogeny class with LMFDB label {} (Cremona label {})".format(
                self.lmfdb_iso, self.Ciso)
        else:
            self.title = "Elliptic curve isogeny class with LMFDB label {}".format(
                self.lmfdb_iso)

        self.properties = [
            ('Label',
             self.Ciso if self.label_type == 'Cremona' else self.lmfdb_iso),
            ('Number of curves', prop_int_pretty(ncurves)),
            ('Conductor', prop_int_pretty(self.conductor)),
            ('CM', '%s' % self.CMfield), ('Rank', prop_int_pretty(self.rank))
        ]
        if ncurves > 1:
            self.properties += [('Graph', ''), (None, self.graph_link)]

        self.downloads = [('q-expansion to text',
                           url_for(".download_EC_qexp",
                                   label=self.iso_label,
                                   limit=1000)),
                          ('All stored data to text',
                           url_for(".download_EC_all", label=self.iso_label))]

        self.bread = [('Elliptic curves', url_for("ecnf.index")),
                      (r'$\Q$', url_for(".rational_elliptic_curves")),
                      ('%s' % self.conductor,
                       url_for(".by_conductor", conductor=self.conductor)),
                      ('%s' % self.iso_label, ' ')]
        self.code = {}
        self.code['show'] = {'sage': ''}  # use default show names
        self.code['class'] = {
            'sage':
            'E = EllipticCurve("%s1")\n' % (self.iso_label) +
            'E.isogeny_class()\n'
        }
        self.code['curves'] = {'sage': 'E.isogeny_class().curves'}
        self.code['rank'] = {'sage': 'E.rank()'}
        self.code['q_eigenform'] = {'sage': 'E.q_eigenform(10)'}
        self.code['matrix'] = {'sage': 'E.isogeny_class().matrix()'}
        self.code['plot'] = {
            'sage': 'E.isogeny_graph().plot(edge_labels=True)'
        }
Exemplo n.º 23
0
    def make_curve(self):
        # To start with the data fields of self are just those from
        # the database.  We need to reformat these.

        # Old version: required constructing the actual elliptic curve
        # E, and computing some further data about it.

        # New version (May 2016): extra data fields now in the
        # database so we do not have to construct the curve or do any
        # computation with it on the fly.  As a failsafe the old way
        # is still included.

        data = self.data = {}
        data['ainvs'] = [ZZ(ai) for ai in self.ainvs]
        data['conductor'] = N = ZZ(self.conductor)
        data['j_invariant'] = QQ(str(self.jinv))
        data['j_inv_factor'] = latex(0)
        if data['j_invariant']:  # don't factor 0
            data['j_inv_factor'] = latex(data['j_invariant'].factor())
        data['j_inv_str'] = unicode(str(data['j_invariant']))
        data['j_inv_latex'] = web_latex(data['j_invariant'])

        # extract data about MW rank, generators, heights and torsion:
        self.make_mw()

        # get more data from the database entry

        data['equation'] = self.equation
        local_data = self.local_data
        D = self.signD * prod([ld['p']**ld['ord_disc'] for ld in local_data])
        for ld in local_data:
            ld['kod'] = ld['kod'].replace("\\\\", "\\")
        data['disc'] = D
        Nfac = Factorization([(ZZ(ld['p']), ld['ord_cond'])
                              for ld in local_data])
        Dfac = Factorization([(ZZ(ld['p']), ld['ord_disc'])
                              for ld in local_data],
                             unit=ZZ(self.signD))

        data['minq_D'] = minqD = self.min_quad_twist['disc']
        data['minq_label'] = self.min_quad_twist[
            'lmfdb_label'] if self.label_type == 'LMFDB' else self.min_quad_twist[
                'label']
        data['minq_info'] = '(itself)' if minqD == 1 else '(by {})'.format(
            minqD)

        if self.degree is None:
            data['degree'] = 0  # invalid, but will be displayed nicely
        else:
            data['degree'] = self.degree

        try:
            data['an'] = self.anlist
            data['ap'] = self.aplist
        except AttributeError:
            r = db.ec_curves.lucky({'lmfdb_iso': self.lmfdb_iso, 'number': 1})
            data['an'] = r['anlist']
            data['ap'] = r['aplist']

        data['disc_factor'] = latex(Dfac)
        data['cond_factor'] = latex(Nfac)
        data['disc_latex'] = web_latex(D)
        data['cond_latex'] = web_latex(N)

        data['galois_images'] = [
            trim_galois_image_code(s) for s in self.mod_p_images
        ]
        data['non_maximal_primes'] = self.non_maximal_primes
        data['galois_data'] = [{
            'p': p,
            'image': im
        } for p, im in zip(data['non_maximal_primes'], data['galois_images'])]

        data['CMD'] = self.cm
        data['CM'] = "no"
        data['EndE'] = "\(\Z\)"
        if self.cm:
            data['cm_ramp'] = [
                p for p in ZZ(self.cm).support()
                if not p in self.non_maximal_primes
            ]
            data['cm_nramp'] = len(data['cm_ramp'])
            if data['cm_nramp'] == 1:
                data['cm_ramp'] = data['cm_ramp'][0]
            else:
                data['cm_ramp'] = ", ".join([str(p) for p in data['cm_ramp']])
            data['cm_sqf'] = ZZ(self.cm).squarefree_part()

            data['CM'] = "yes (\(D=%s\))" % data['CMD']
            if data['CMD'] % 4 == 0:
                d4 = ZZ(data['CMD']) // 4
                data['EndE'] = "\(\Z[\sqrt{%s}]\)" % d4
            else:
                data['EndE'] = "\(\Z[(1+\sqrt{%s})/2]\)" % data['CMD']
            data['ST'] = st_link_by_name(1, 2, 'N(U(1))')
        else:
            data['ST'] = st_link_by_name(1, 2, 'SU(2)')

        data['p_adic_primes'] = [
            p for i, p in enumerate(prime_range(5, 100))
            if (N * data['ap'][i]) % p != 0
        ]

        cond, iso, num = split_lmfdb_label(self.lmfdb_label)
        self.one_deg = ZZ(self.class_deg).is_prime()
        isodegs = [str(d) for d in self.isogeny_degrees if d > 1]
        if len(isodegs) < 3:
            data['isogeny_degrees'] = " and ".join(isodegs)
        else:
            data['isogeny_degrees'] = " and ".join(
                [", ".join(isodegs[:-1]), isodegs[-1]])

        if self.twoadic_gens:
            from sage.matrix.all import Matrix
            data['twoadic_gen_matrices'] = ','.join(
                [latex(Matrix(2, 2, M)) for M in self.twoadic_gens])
            data[
                'twoadic_rouse_url'] = ROUSE_URL_PREFIX + self.twoadic_label + ".html"

        # Leading term of L-function & other BSD data
        self.make_bsd()

        # Optimality (the optimal curve in the class is the curve
        # whose Cremona label ends in '1' except for '990h' which was
        # labelled wrongly long ago): this is proved for N up to
        # OPTIMALITY_BOUND (and when there is only one curve in an
        # isogeny class, obviously) and expected for all N.

        # Column 'optimality' is 1 for certainly optimal curves, 0 for
        # certainly non-optimal curves, and is n>1 if the curve is one
        # of n in the isogeny class which may be optimal given current
        # knowledge.

        # Column "manin_constant' is the correct Manin constant
        # assuming that the optimal curve in the class is known, or
        # otherwise if it is the curve with (Cremona) number 1.

        # The code here allows us to update the display correctly by
        # changing one line in this file (defining OPTIMALITY_BOUND)
        # without changing the data.

        data['optimality_bound'] = OPTIMALITY_BOUND
        data[
            'manin_constant'] = self.manin_constant  # (conditional on data['optimality_known'])

        if N < OPTIMALITY_BOUND:

            data['optimality_code'] = int(
                self.number == (3 if self.iso == '990h' else 1))
            data['optimality_known'] = True
            data['manin_known'] = True
            if self.label_type == 'Cremona':
                data[
                    'optimal_label'] = '990h3' if self.iso == '990h' else self.iso + '1'
            else:
                data[
                    'optimal_label'] = '990.i3' if self.lmfdb_iso == '990.i' else self.lmfdb_iso + '1'

        else:

            data['optimality_code'] = self.optimality
            data['optimality_known'] = (self.optimality < 2)

            if self.optimality == 1:
                data['manin_known'] = True
                data[
                    'optimal_label'] = self.label if self.label_type == 'Cremona' else self.lmfdb_label
            else:
                if self.number == 1:
                    data['manin_known'] = False
                    data[
                        'optimal_label'] = self.label if self.label_type == 'Cremona' else self.lmfdb_label
                else:
                    # find curve #1 in this class and its optimailty code:
                    opt_curve = db.ec_curves.lucky(
                        {
                            'iso': self.iso,
                            'number': 1
                        },
                        projection=['label', 'lmfdb_label', 'optimality'])
                    data['manin_known'] = (opt_curve['optimality'] == 1)
                    data['optimal_label'] = opt_curve[
                        'label' if self.label_type ==
                        'Cremona' else 'lmfdb_label']

        data['p_adic_data_exists'] = False
        if data['optimality_code'] == 1:
            data['p_adic_data_exists'] = db.ec_padic.exists(
                {'lmfdb_iso': self.lmfdb_iso})

        # Iwasawa data (where present)

        self.make_iwasawa()

        # Torsion growth data (where present)

        self.make_torsion_growth()

        data['newform'] = web_latex(
            PowerSeriesRing(QQ, 'q')(data['an'], 20, check=True))
        data['newform_label'] = self.newform_label = ".".join(
            [str(cond), str(2), 'a', iso])
        self.newform_link = url_for("cmf.by_url_newform_label",
                                    level=cond,
                                    weight=2,
                                    char_orbit_label='a',
                                    hecke_orbit=iso)
        self.newform_exists_in_db = db.mf_newforms.label_exists(
            self.newform_label)
        self._code = None

        if self.label_type == 'Cremona':
            self.class_url = url_for(".by_ec_label", label=self.iso)
            self.class_name = self.iso
        else:
            self.class_url = url_for(".by_double_iso_label",
                                     conductor=N,
                                     iso_label=iso)
            self.class_name = self.lmfdb_iso
        data['class_name'] = self.class_name
        data['number'] = self.number

        self.friends = [('Isogeny class ' + self.class_name, self.class_url),
                        ('Minimal quadratic twist %s %s' %
                         (data['minq_info'], data['minq_label']),
                         url_for(".by_ec_label", label=data['minq_label'])),
                        ('All twists ',
                         url_for(".rational_elliptic_curves", jinv=self.jinv))]

        lfun_url = url_for("l_functions.l_function_ec_page",
                           conductor_label=N,
                           isogeny_class_label=iso)
        origin_url = lfun_url.lstrip('/L/').rstrip('/')

        if db.lfunc_instances.exists({'url': origin_url}):
            self.friends += [('L-function', lfun_url)]
        else:
            self.friends += [('L-function not available', "")]

        if not self.cm:
            if N <= 300:
                self.friends += [('Symmetric square L-function',
                                  url_for("l_functions.l_function_ec_sym_page",
                                          power='2',
                                          conductor=N,
                                          isogeny=iso))]
            if N <= 50:
                self.friends += [('Symmetric cube L-function',
                                  url_for("l_functions.l_function_ec_sym_page",
                                          power='3',
                                          conductor=N,
                                          isogeny=iso))]
        if self.newform_exists_in_db:
            self.friends += [('Modular form ' + self.newform_label,
                              self.newform_link)]

        self.downloads = [('q-expansion to text',
                           url_for(".download_EC_qexp",
                                   label=self.lmfdb_label,
                                   limit=1000)),
                          ('All stored data to text',
                           url_for(".download_EC_all",
                                   label=self.lmfdb_label)),
                          ('Code to Magma',
                           url_for(".ec_code_download",
                                   conductor=cond,
                                   iso=iso,
                                   number=num,
                                   label=self.lmfdb_label,
                                   download_type='magma')),
                          ('Code to SageMath',
                           url_for(".ec_code_download",
                                   conductor=cond,
                                   iso=iso,
                                   number=num,
                                   label=self.lmfdb_label,
                                   download_type='sage')),
                          ('Code to GP',
                           url_for(".ec_code_download",
                                   conductor=cond,
                                   iso=iso,
                                   number=num,
                                   label=self.lmfdb_label,
                                   download_type='gp'))]

        try:
            self.plot = encode_plot(self.E.plot())
        except AttributeError:
            self.plot = encode_plot(EllipticCurve(data['ainvs']).plot())

        self.plot_link = '<a href="{0}"><img src="{0}" width="200" height="150"/></a>'.format(
            self.plot)
        self.properties = [
            ('Label',
             self.label if self.label_type == 'Cremona' else self.lmfdb_label),
            (None, self.plot_link), ('Conductor', '%s' % data['conductor']),
            ('Discriminant', '%s' % data['disc']),
            ('j-invariant', '%s' % data['j_inv_latex']),
            ('CM', '%s' % data['CM']), ('Rank', '%s' % self.mw['rank']),
            ('Torsion Structure', '\(%s\)' % self.mw['tor_struct'])
        ]

        if self.label_type == 'Cremona':
            self.title = "Elliptic Curve with Cremona label {} (LMFDB label {})".format(
                self.label, self.lmfdb_label)
        else:
            self.title = "Elliptic Curve with LMFDB label {} (Cremona label {})".format(
                self.lmfdb_label, self.label)

        self.bread = [('Elliptic Curves', url_for("ecnf.index")),
                      ('$\Q$', url_for(".rational_elliptic_curves")),
                      ('%s' % N, url_for(".by_conductor", conductor=N)),
                      ('%s' % iso,
                       url_for(".by_double_iso_label",
                               conductor=N,
                               iso_label=iso)), ('%s' % num, ' ')]
Exemplo n.º 24
0
    def make_curve(self):
        # To start with the data fields of self are just those from
        # the database.  We need to reformat these.

        # Old version: required constructing the actual elliptic curve
        # E, and computing some further data about it.

        # New version (May 2016): extra data fields now in the
        # database so we do not have to construct the curve or do any
        # computation with it on the fly.  As a failsafe the old way
        # is still included.

        data = self.data = {}
        try:
            data['ainvs'] = [int(c) for c in self.xainvs[1:-1].split(',')]
        except AttributeError:
            data['ainvs'] = [int(ai) for ai in self.ainvs]
        data['conductor'] = N = ZZ(self.conductor)
        data['j_invariant'] = QQ(str(self.jinv))
        data['j_inv_factor'] = latex(0)
        if data['j_invariant']:  # don't factor 0
            data['j_inv_factor'] = latex(data['j_invariant'].factor())
        data['j_inv_str'] = unicode(str(data['j_invariant']))
        data['j_inv_latex'] = web_latex(data['j_invariant'])
        mw = self.mw = {}
        mw['rank'] = self.rank
        mw['int_points'] = ''
        if self.xintcoords:
            a1, a2, a3, a4, a6 = [ZZ(a) for a in data['ainvs']]

            def lift_x(x):
                f = ((x + a2) * x + a4) * x + a6
                b = (a1 * x + a3)
                d = (b * b + 4 * f).sqrt()
                return (x, (-b + d) / 2)

            mw['int_points'] = ', '.join(
                web_latex(lift_x(x)) for x in self.xintcoords)

        mw['generators'] = ''
        mw['heights'] = []
        if self.gens:
            mw['generators'] = [
                web_latex(tuple(P)) for P in parse_points(self.gens)
            ]

        mw['tor_order'] = self.torsion
        tor_struct = [int(c) for c in self.torsion_structure]
        if mw['tor_order'] == 1:
            mw['tor_struct'] = '\mathrm{Trivial}'
            mw['tor_gens'] = ''
        else:
            mw['tor_struct'] = ' \\times '.join(
                ['\Z/{%s}\Z' % n for n in tor_struct])
            mw['tor_gens'] = ', '.join(
                web_latex(tuple(P))
                for P in parse_points(self.torsion_generators))

        # try to get all the data we need from the database entry (now in self)
        try:
            data['equation'] = self.equation
            local_data = self.local_data
            D = self.signD * prod(
                [ld['p']**ld['ord_disc'] for ld in local_data])
            data['disc'] = D
            Nfac = Factorization([(ZZ(ld['p']), ld['ord_cond'])
                                  for ld in local_data])
            Dfac = Factorization([(ZZ(ld['p']), ld['ord_disc'])
                                  for ld in local_data],
                                 unit=ZZ(self.signD))

            data['minq_D'] = minqD = self.min_quad_twist['disc']
            minq_label = self.min_quad_twist['label']
            data['minq_label'] = db_ec().find_one(
                {'label': minq_label}, ['lmfdb_label'])['lmfdb_label']
            data['minq_info'] = '(itself)' if minqD == 1 else '(by %s)' % minqD
            try:
                data['degree'] = self.degree
            except AttributeError:
                data['degree'] = 0  # invalid, but will be displayed nicely
            mw['heights'] = self.heights
            if self.number == 1:
                data['an'] = self.anlist
                data['ap'] = self.aplist
            else:
                r = db_ec().find_one({
                    'lmfdb_iso': self.lmfdb_iso,
                    'number': 1
                }, ['anlist', 'aplist'])
                data['an'] = r['anlist']
                data['ap'] = r['aplist']

        # otherwise fall back to computing it from the curve
        except AttributeError:
            print("Falling back to constructing E")
            self.E = EllipticCurve(data['ainvs'])
            data['equation'] = web_latex(self.E)
            data['disc'] = D = self.E.discriminant()
            Nfac = N.factor()
            Dfac = D.factor()
            bad_primes = [p for p, e in Nfac]
            try:
                data['degree'] = self.degree
            except AttributeError:
                try:
                    data['degree'] = self.E.modular_degree()
                except RuntimeError:
                    data['degree'] = 0  # invalid, but will be displayed nicely
            minq, minqD = self.E.minimal_quadratic_twist()
            data['minq_D'] = minqD
            if minqD == 1:
                data['minq_label'] = self.lmfdb_label
                data['minq_info'] = '(itself)'
            else:
                # This relies on the minimal twist being in the
                # database, which is true when the database only
                # contains the Cremona database.  It would be a good
                # idea if, when the database is extended, we ensured
                # that for any curve included, all twists of smaller
                # conductor are also included.
                minq_ainvs = [str(c) for c in minq.ainvs()]
                data['minq_label'] = db_ec().find_one(
                    {
                        'jinv': str(self.E.j_invariant()),
                        'ainvs': minq_ainvs
                    }, ['lmfdb_label'])['lmfdb_label']
                data['minq_info'] = '(by %s)' % minqD

            if self.gens:
                self.generators = [self.E(g) for g in parse_points(self.gens)]
                mw['heights'] = [P.height() for P in self.generators]

            data['an'] = self.E.anlist(20, python_ints=True)
            data['ap'] = self.E.aplist(100, python_ints=True)
            self.local_data = local_data = []
            for p in bad_primes:
                ld = self.E.local_data(p, algorithm="generic")
                local_data_p = {}
                local_data_p['p'] = p
                local_data_p['cp'] = ld.tamagawa_number()
                local_data_p['kod'] = web_latex(ld.kodaira_symbol()).replace(
                    '$', '')
                local_data_p['red'] = ld.bad_reduction_type()
                rootno = -ld.bad_reduction_type()
                if rootno == 0:
                    rootno = self.E.root_number(p)
                local_data_p['rootno'] = rootno
                local_data_p['ord_cond'] = ld.conductor_valuation()
                local_data_p['ord_disc'] = ld.discriminant_valuation()
                local_data_p['ord_den_j'] = max(
                    0, -self.E.j_invariant().valuation(p))
                local_data.append(local_data_p)

        # If we got the data from the database, the root numbers may
        # not have been stored there, so we have to compute them.  If
        # there are additive primes this means constructing the curve.
        for ld in self.local_data:
            if not 'rootno' in ld:
                rootno = -ld['red']
                if rootno == 0:
                    try:
                        E = self.E
                    except AttributeError:
                        self.E = E = EllipticCurve(data['ainvs'])
                    rootno = E.root_number(ld['p'])
                ld['rootno'] = rootno

        minq_N, minq_iso, minq_number = split_lmfdb_label(data['minq_label'])

        data['disc_factor'] = latex(Dfac)
        data['cond_factor'] = latex(Nfac)
        data['disc_latex'] = web_latex(D)
        data['cond_latex'] = web_latex(N)

        data['CMD'] = self.cm
        data['CM'] = "no"
        data['EndE'] = "\(\Z\)"
        if self.cm:
            data['CM'] = "yes (\(D=%s\))" % data['CMD']
            if data['CMD'] % 4 == 0:
                d4 = ZZ(data['CMD']) // 4
                data['EndE'] = "\(\Z[\sqrt{%s}]\)" % d4
            else:
                data['EndE'] = "\(\Z[(1+\sqrt{%s})/2]\)" % data['CMD']
            data['ST'] = st_link_by_name(1, 2, 'N(U(1))')
        else:
            data['ST'] = st_link_by_name(1, 2, 'SU(2)')

        data['p_adic_primes'] = [
            p for i, p in enumerate(prime_range(5, 100))
            if (N * data['ap'][i]) % p != 0
        ]

        try:
            data['galois_images'] = [
                trim_galois_image_code(s) for s in self.galois_images
            ]
            data['non_surjective_primes'] = self.non_surjective_primes
        except AttributeError:
            #print "No Galois image data"
            data['galois_images'] = []
            data['non_surjective_primes'] = []

        data['galois_data'] = [{
            'p': p,
            'image': im
        } for p, im in zip(data['non_surjective_primes'],
                           data['galois_images'])]

        cond, iso, num = split_lmfdb_label(self.lmfdb_label)
        self.class_url = url_for(".by_double_iso_label",
                                 conductor=N,
                                 iso_label=iso)
        self.ncurves = db_ec().count({'lmfdb_iso': self.lmfdb_iso})
        isodegs = [str(d) for d in self.isogeny_degrees if d > 1]
        if len(isodegs) < 3:
            data['isogeny_degrees'] = " and ".join(isodegs)
        else:
            data['isogeny_degrees'] = " and ".join(
                [", ".join(isodegs[:-1]), isodegs[-1]])

        if self.twoadic_gens:
            from sage.matrix.all import Matrix
            data['twoadic_gen_matrices'] = ','.join(
                [latex(Matrix(2, 2, M)) for M in self.twoadic_gens])
            data[
                'twoadic_rouse_url'] = ROUSE_URL_PREFIX + self.twoadic_label + ".html"

        # Leading term of L-function & BSD data
        bsd = self.bsd = {}
        r = self.rank
        if r >= 2:
            bsd['lder_name'] = "L^{(%s)}(E,1)/%s!" % (r, r)
        elif r:
            bsd['lder_name'] = "L'(E,1)"
        else:
            bsd['lder_name'] = "L(E,1)"

        bsd['reg'] = self.regulator
        bsd['omega'] = self.real_period
        bsd['sha'] = int(0.1 + self.sha_an)
        bsd['lder'] = self.special_value

        # Optimality (the optimal curve in the class is the curve
        # whose Cremona label ends in '1' except for '990h' which was
        # labelled wrongly long ago)

        if self.iso == '990h':
            data['Gamma0optimal'] = bool(self.number == 3)
        else:
            data['Gamma0optimal'] = bool(self.number == 1)

        data['p_adic_data_exists'] = False
        if data['Gamma0optimal']:
            data['p_adic_data_exists'] = (padic_db().find({
                'lmfdb_iso':
                self.lmfdb_iso
            }).count()) > 0

        tamagawa_numbers = [ZZ(ld['cp']) for ld in local_data]
        cp_fac = [cp.factor() for cp in tamagawa_numbers]
        cp_fac = [
            latex(cp) if len(cp) < 2 else '(' + latex(cp) + ')'
            for cp in cp_fac
        ]
        bsd['tamagawa_factors'] = r'\cdot'.join(cp_fac)
        bsd['tamagawa_product'] = prod(tamagawa_numbers)

        data['newform'] = web_latex(
            PowerSeriesRing(QQ, 'q')(data['an'], 20, check=True))
        data['newform_label'] = self.newform_label = newform_label(
            cond, 2, 1, iso)
        self.newform_link = url_for("emf.render_elliptic_modular_forms",
                                    level=cond,
                                    weight=2,
                                    character=1,
                                    label=iso)
        self.newform_exists_in_db = is_newform_in_db(self.newform_label)
        self._code = None

        self.class_url = url_for(".by_double_iso_label",
                                 conductor=N,
                                 iso_label=iso)
        self.friends = [('Isogeny class ' + self.lmfdb_iso, self.class_url),
                        ('Minimal quadratic twist %s %s' %
                         (data['minq_info'], data['minq_label']),
                         url_for(".by_triple_label",
                                 conductor=minq_N,
                                 iso_label=minq_iso,
                                 number=minq_number)),
                        ('All twists ',
                         url_for(".rational_elliptic_curves", jinv=self.jinv)),
                        ('L-function',
                         url_for("l_functions.l_function_ec_page",
                                 label=self.lmfdb_label))]
        if not self.cm:
            if N <= 300:
                self.friends += [('Symmetric square L-function',
                                  url_for("l_functions.l_function_ec_sym_page",
                                          power='2',
                                          label=self.lmfdb_iso))]
            if N <= 50:
                self.friends += [('Symmetric cube L-function',
                                  url_for("l_functions.l_function_ec_sym_page",
                                          power='3',
                                          label=self.lmfdb_iso))]
        if self.newform_exists_in_db:
            self.friends += [('Modular form ' + self.newform_label,
                              self.newform_link)]

        self.downloads = [('Download coefficients of q-expansion',
                           url_for(".download_EC_qexp",
                                   label=self.lmfdb_label,
                                   limit=1000)),
                          ('Download all stored data',
                           url_for(".download_EC_all",
                                   label=self.lmfdb_label)),
                          ('Download Magma code',
                           url_for(".ec_code_download",
                                   conductor=cond,
                                   iso=iso,
                                   number=num,
                                   label=self.lmfdb_label,
                                   download_type='magma')),
                          ('Download Sage code',
                           url_for(".ec_code_download",
                                   conductor=cond,
                                   iso=iso,
                                   number=num,
                                   label=self.lmfdb_label,
                                   download_type='sage')),
                          ('Download GP code',
                           url_for(".ec_code_download",
                                   conductor=cond,
                                   iso=iso,
                                   number=num,
                                   label=self.lmfdb_label,
                                   download_type='gp'))]

        try:
            self.plot = encode_plot(self.E.plot())
        except AttributeError:
            self.plot = encode_plot(EllipticCurve(data['ainvs']).plot())

        self.plot_link = '<img src="%s" width="200" height="150"/>' % self.plot
        self.properties = [('Label', self.lmfdb_label), (None, self.plot_link),
                           ('Conductor', '\(%s\)' % data['conductor']),
                           ('Discriminant', '\(%s\)' % data['disc']),
                           ('j-invariant', '%s' % data['j_inv_latex']),
                           ('CM', '%s' % data['CM']),
                           ('Rank', '\(%s\)' % mw['rank']),
                           ('Torsion Structure', '\(%s\)' % mw['tor_struct'])]

        self.title = "Elliptic Curve %s (Cremona label %s)" % (
            self.lmfdb_label, self.label)

        self.bread = [('Elliptic Curves', url_for("ecnf.index")),
                      ('$\Q$', url_for(".rational_elliptic_curves")),
                      ('%s' % N, url_for(".by_conductor", conductor=N)),
                      ('%s' % iso,
                       url_for(".by_double_iso_label",
                               conductor=N,
                               iso_label=iso)), ('%s' % num, ' ')]
Exemplo n.º 25
0
    def is_Gamma0_equivalent(self, other, N, Transformation=False):
        r"""
        Checks if cusps ``self`` and ``other`` are `\Gamma_0(N)`- equivalent.

        INPUT:

        - ``other`` -- a number field cusp or a list of two number field
          elements which define a cusp.

        - ``N`` -- an ideal of the number field (level)

        OUTPUT:

        - bool -- ``True`` if the cusps are equivalent.

        - a transformation matrix -- (if ``Transformation=True``) a list of
          integral elements [a, b, c, d] which are the entries of a 2x2 matrix
          M in `\Gamma_0(N)` such that M * ``self`` = ``other`` if ``other``
          and ``self`` are `\Gamma_0(N)`- equivalent. If ``self`` and ``other``
          are not equivalent it returns zero.

        EXAMPLES:

        ::

            sage: K.<a> = NumberField(x^3-10)
            sage: N = K.ideal(a-1)
            sage: alpha = NFCusp(K, 0)
            sage: beta = NFCusp(K, oo)
            sage: alpha.is_Gamma0_equivalent(beta, N)
            False
            sage: alpha.is_Gamma0_equivalent(beta, K.ideal(1))
            True
            sage: b, M = alpha.is_Gamma0_equivalent(beta, K.ideal(1),Transformation=True)
            sage: alpha.apply(M)
            Cusp Infinity of Number Field in a with defining polynomial x^3 - 10

        ::

            sage: k.<a> = NumberField(x^2+23)
            sage: N = k.ideal(3)
            sage: alpha1 = NFCusp(k, a+1, 4)
            sage: alpha2 = NFCusp(k, a-8, 29)
            sage: alpha1.is_Gamma0_equivalent(alpha2, N)
            True
            sage: b, M = alpha1.is_Gamma0_equivalent(alpha2, N, Transformation=True)
            sage: alpha1.apply(M) == alpha2
            True
            sage: M[2] in N
            True
        """
        k = self.number_field()
        other = NFCusp(k, other)
        if not (self.ideal() / other.ideal()).is_principal():
            if not Transformation:
                return False
            else:
                return False, 0

        reps = list_of_representatives(N)
        alpha1 = NFCusp(k, self, lreps=reps)
        alpha2 = NFCusp(k, other, lreps=reps)

        delta = k.ideal(alpha1.__b) + N
        if (k.ideal(alpha2.__b) + N) != delta:
            if not Transformation:
                return False
            else:
                return False, 0

        M1 = alpha1.ABmatrix()
        M2 = alpha2.ABmatrix()

        A = alpha1.ideal()
        B = k.ideal(M1[1], M1[3])

        ABdelta = A * B * delta * delta

        units = units_mod_ideal(ABdelta)
        for u in units:
            if (M2[2] * M1[3] - u * M1[2] * M2[3]) in ABdelta:
                if not Transformation:
                    return True
                else:
                    AuxCoeff = [1, 0, 0, 1]
                    Aux = M2[2] * M1[3] - u * M1[2] * M2[3]
                    if Aux in A * B * N:
                        if not u == 1:
                            AuxCoeff[3] = u
                    else:
                        A1 = (A * B * N) / ABdelta
                        A2 = B * k.ideal(M1[2] * M2[2]) / (A * ABdelta)
                        f = A1.element_1_mod(A2)
                        w = ((1 - f) * Aux) / (M1[2] * M2[2])
                        AuxCoeff[3] = u
                        AuxCoeff[1] = w
                    from sage.matrix.all import Matrix
                    Maux = Matrix(k, 2, AuxCoeff)
                    M1inv = Matrix(k, 2, M1).inverse()
                    Mtrans = Matrix(k, 2, M2) * Maux * M1inv
                    assert Mtrans[1][0] in N
                    return True, Mtrans.list()
        if not Transformation:
            return False
        else:
            return False, 0
Exemplo n.º 26
0
    def make_class(self):
        self.CM = self.cm
        N, iso, number = split_lmfdb_label(self.lmfdb_iso)

        # Extract the size of the isogeny class from the database
        ncurves = self.class_size
        # Create a list of the curves in the class from the database
        self.curves = [db_ec().find_one({'iso':self.iso, 'lmfdb_number': i+1})
                          for i in range(ncurves)]

        # Set optimality flags.  The optimal curve is number 1 except
        # in one case which is labeled differently in the Cremona tables
        for c in self.curves:
            c['optimal'] = (c['number']==(3 if self.label == '990h' else 1))
            c['ai'] = parse_ainvs(c['xainvs'])
            c['url'] = url_for(".by_triple_label", conductor=N, iso_label=iso, number=c['lmfdb_number'])

        from sage.matrix.all import Matrix
        self.isogeny_matrix = Matrix(self.isogeny_matrix)
        self.isogeny_matrix_str = latex(matrix(self.isogeny_matrix))

        # Create isogeny graph:
        self.graph = make_graph(self.isogeny_matrix)
        P = self.graph.plot(edge_labels=True)
        self.graph_img = encode_plot(P)
        self.graph_link = '<img src="%s" width="200" height="150"/>' % self.graph_img


        self.newform =  web_latex(PowerSeriesRing(QQ, 'q')(self.anlist, 20, check=True))
        self.newform_label = newform_label(N,2,1,iso)
        self.newform_link = url_for("emf.render_elliptic_modular_forms", level=N, weight=2, character=1, label=iso)
        self.newform_exists_in_db = is_newform_in_db(self.newform_label)

        self.lfunction_link = url_for("l_functions.l_function_ec_page", conductor_label = N, isogeny_class_label = iso)

        self.friends =  [('L-function', self.lfunction_link)]
        if not self.CM:
            self.CM = "no"
            if int(N)<=300:
                self.friends += [('Symmetric square L-function', url_for("l_functions.l_function_ec_sym_page", power='2', conductor = N, isogeny = iso))]
            if int(N)<=50:
                self.friends += [('Symmetric cube L-function', url_for("l_functions.l_function_ec_sym_page", power='3', conductor = N, isogeny = iso))]
        if self.newform_exists_in_db:
            self.friends +=  [('Modular form ' + self.newform_label, self.newform_link)]

        self.properties = [('Label', self.lmfdb_iso),
                           ('Number of curves', str(ncurves)),
                           ('Conductor', '\(%s\)' % N),
                           ('CM', '%s' % self.CM),
                           ('Rank', '\(%s\)' % self.rank),
                           ('Graph', ''),(None, self.graph_link)
                           ]


        self.downloads = [('Download coefficients of newform', url_for(".download_EC_qexp", label=self.lmfdb_iso, limit=1000)),
                         ('Download stored data for all curves', url_for(".download_EC_all", label=self.lmfdb_iso))]

        if self.lmfdb_iso == self.iso:
            self.title = "Elliptic Curve Isogeny Class %s" % self.lmfdb_iso
        else:
            self.title = "Elliptic Curve Isogeny Class %s (Cremona label %s)" % (self.lmfdb_iso, self.iso)

        self.bread = [('Elliptic Curves', url_for("ecnf.index")),
                      ('$\Q$', url_for(".rational_elliptic_curves")),
                      ('%s' % N, url_for(".by_conductor", conductor=N)),
                      ('%s' % iso, ' ')]
        self.code = {}
        self.code['show'] = {'sage':''} # use default show names
        self.code['class'] = {'sage':'E = EllipticCurve("%s1")\n'%(self.lmfdb_iso) + 'E.isogeny_class()\n'}
        self.code['curves'] = {'sage':'E.isogeny_class().curves'}
        self.code['rank'] = {'sage':'E.rank()'}
        self.code['q_eigenform'] = {'sage':'E.q_eigenform(10)'}
        self.code['matrix'] = {'sage':'E.isogeny_class().matrix()'}
        self.code['plot'] = {'sage':'E.isogeny_graph().plot(edge_labels=True)'}
Exemplo n.º 27
0
def berlekamp_welsh(deg, points):
    r"""
    Reconstruct polynomial with Berlekamp-Welsh algorithm.

    INPUT:

    - ``deg``    --  degree of polynomial to reconstruct.
    - ``points`` --  array of points (list of (x,y)-tuples).

    OUTPUT:

    Reconstructed polynomial.

    EXAMPLES::

        sage: from sage.crypto.smc.berlekamp_welsh import berlekamp_welsh
        sage: from sage.rings.finite_rings.constructor import FiniteField
        sage: from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing

    Reconstruction with errors::

        sage: order = 2**8
        sage: F = FiniteField(order, 'a')
        sage: P = PolynomialRing(F, 'x')
        sage: n = 7
        sage: deg = 2
        sage: poly = F.fetch_int(42)
        sage: for i in range(1, deg+1): poly += F.random_element() * P.gen()**i

        sage: # evaluate polynomial at different points (shares)
        sage: points = [(F.fetch_int(i), poly(F.fetch_int(i))) for i in range(1, n+1)]
        sage: poly == berlekamp_welsh(deg, points)
        True

        sage: # introduce error
        sage: points[0] = (points[0][0], points[0][1] + F.fetch_int(9))
        sage: poly == berlekamp_welsh(deg, points)
        True

    """
    # check input vector
    F = points[0][0].parent()
    if not F.is_field():
        raise TypeError("points must be of field type.")
    for x, y in points:
        if x.parent() != F or y.parent() != F:
            raise TypeError("all points must be from same field.")
        
    # generate and solve system of linear equations
    from sage.functions.all import floor
    deg_E = floor((len(points) - (deg + 1)) / 2.)
    deg_Q = deg_E + deg
    from sage.matrix.all import Matrix
    from sage.all import vector
    sys_size = deg_Q + 1 + deg_E
    A = Matrix(F, sys_size)
    b = vector(F, sys_size)
    for n, (x, y) in enumerate(points):
        A[n] = ([x**i for i in range(deg_Q+1)]+[-y * x**i for i in range(deg_E)])
        b[n] = (y * x**deg_E)
    QE = A.solve_right(b)

    # reconstruct polynomial
    from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
    P = PolynomialRing(F, 'x')
    Q = sum([coeff * P.gen()**i for i, coeff in enumerate(QE[:deg_Q+1])]);
    E = P.gen()**deg_E
    E += sum([coeff * P.gen()**i for i, coeff in enumerate(QE[deg_Q+1:])]);
    P = Q.quo_rem(E)[0]
    return P
Exemplo n.º 28
0
    def make_class(self):
        self.ainvs_str = self.ainvs
        self.ainvs = [int(a) for a in self.ainvs_str]
        self.E = EllipticCurve(self.ainvs)
        self.CM = self.E.has_cm()

        try:
            # Extract the isogeny degree matrix from the database
            size = len(self.isogeny_matrix)
            from sage.matrix.all import Matrix
            self.isogeny_matrix = Matrix(self.isogeny_matrix)
        except AttributeError:
            # Failsafe: construct it from scratch
            self.isogeny_matrix = self.E.isogeny_class(order="lmfdb").matrix()
            size = self.isogeny_matrix.nrows()
        self.ncurves = size

        # Create isogeny graph:
        self.graph = make_graph(self.isogeny_matrix)
        P = self.graph.plot(edge_labels=True)
        self.graph_img = encode_plot(P)
        self.graph_link = '<img src="%s" width="200" height="150"/>' % self.graph_img

        # Create a list of the curves in the class from the database
        self.db_curves = [self.E]
        self.optimal_flags = [False] * size
        self.degrees = [0] * size
        if self.degree:
            self.degrees[0] = self.degree
        else:
            try:
                self.degrees[0] = self.E.modular_degree()
            except RuntimeError:
                pass

        # Fill in the curves in the class by looking each one up in the db:

        self.cremona_labels = [self.label] + [0] * (size - 1)
        if self.number == 1:
            self.optimal_flags[0] = True
        for i in range(2, size + 1):
            Edata = db_ec().find_one({'lmfdb_label': self.lmfdb_iso + str(i)})
            Ei = EllipticCurve([int(a) for a in Edata['ainvs']])
            self.cremona_labels[i - 1] = Edata['label']
            if Edata['number'] == 1:
                self.optimal_flags[i - 1] = True
            if 'degree' in Edata:
                self.degrees[i - 1] = Edata['degree']
            else:
                try:
                    self.degrees[i - 1] = Ei.modular_degree()
                except RuntimeError:
                    pass
            self.db_curves.append(Ei)

        if self.iso == '990h':  # this isogeny class is labeled wrong in Cremona's tables
            self.optimal_flags = [False, False, True, False]

        self.isogeny_matrix_str = latex(matrix(self.isogeny_matrix))

        N, iso, number = split_lmfdb_label(self.lmfdb_iso)

        self.newform = web_latex(self.E.q_eigenform(10))
        self.newform_label = newform_label(N, 2, 1, iso)
        self.newform_link = url_for("emf.render_elliptic_modular_forms",
                                    level=N,
                                    weight=2,
                                    character=1,
                                    label=iso)
        newform_exists_in_db = is_newform_in_db(self.newform_label)

        self.lfunction_link = url_for("l_functions.l_function_ec_page",
                                      label=self.lmfdb_iso)

        self.curves = [
            dict([('label', self.lmfdb_iso + str(i + 1)),
                  ('url',
                   url_for(".by_triple_label",
                           conductor=N,
                           iso_label=iso,
                           number=i + 1)),
                  ('cremona_label', self.cremona_labels[i]),
                  ('ainvs', str(list(c.ainvs()))),
                  ('torsion', c.torsion_order()), ('degree', self.degrees[i]),
                  ('optimal', self.optimal_flags[i])])
            for i, c in enumerate(self.db_curves)
        ]

        self.friends = [('L-function', self.lfunction_link)]
        if not self.CM:
            if int(N) <= 300:
                self.friends += [('Symmetric square L-function',
                                  url_for("l_functions.l_function_ec_sym_page",
                                          power='2',
                                          label=self.lmfdb_iso))]
            if int(N) <= 50:
                self.friends += [('Symmetric cube L-function',
                                  url_for("l_functions.l_function_ec_sym_page",
                                          power='3',
                                          label=self.lmfdb_iso))]
        if newform_exists_in_db:
            self.friends += [('Modular form ' + self.newform_label,
                              self.newform_link)]

        self.properties = [('Label', self.lmfdb_iso),
                           ('Number of curves', str(self.ncurves)),
                           ('Conductor', '\(%s\)' % N), ('CM', '%s' % self.CM),
                           ('Rank', '\(%s\)' % self.rank), ('Graph', ''),
                           (None, self.graph_link)]

        self.downloads = [('Download coefficients of newform',
                           url_for(".download_EC_qexp",
                                   label=self.lmfdb_iso,
                                   limit=100)),
                          ('Download stored data for all curves',
                           url_for(".download_EC_all", label=self.lmfdb_iso))]

        if self.lmfdb_iso == self.iso:
            self.title = "Elliptic Curve Isogeny Class %s" % self.lmfdb_iso
        else:
            self.title = "Elliptic Curve Isogeny Class %s (Cremona label %s)" % (
                self.lmfdb_iso, self.iso)

        self.bread = [('Elliptic Curves', url_for("ecnf.index")),
                      ('$\Q$', url_for(".rational_elliptic_curves")),
                      ('%s' % N, url_for(".by_conductor", conductor=N)),
                      ('%s' % iso, ' ')]
Exemplo n.º 29
0
    def make_curve(self):
        # To start with the data fields of self are just those from
        # the database.  We need to reformat these.

        # Old version: required constructing the actual elliptic curve
        # E, and computing some further data about it.

        # New version (May 2016): extra data fields now in the
        # database so we do not have to construct the curve or do any
        # computation with it on the fly.  As a failsafe the old way
        # is still included.

        data = self.data = {}
        data['ainvs'] = self.ainvs
        data['conductor'] = N = ZZ(self.conductor)
        data['j_invariant'] = QQ(str(self.jinv))
        data['j_inv_factor'] = latex(0)
        if data['j_invariant']:  # don't factor 0
            data['j_inv_factor'] = latex(data['j_invariant'].factor())
        data['j_inv_str'] = unicode(str(data['j_invariant']))
        data['j_inv_latex'] = web_latex(data['j_invariant'])

        # extract data about MW rank, generators, heights and torsion:
        self.make_mw()

        # get more data from the database entry

        data['equation'] = self.equation
        local_data = self.local_data
        D = self.signD * prod([ld['p']**ld['ord_disc'] for ld in local_data])
        data['disc'] = D
        Nfac = Factorization([(ZZ(ld['p']), ld['ord_cond'])
                              for ld in local_data])
        Dfac = Factorization([(ZZ(ld['p']), ld['ord_disc'])
                              for ld in local_data],
                             unit=ZZ(self.signD))

        data['minq_D'] = minqD = self.min_quad_twist['disc']
        minq_label = self.min_quad_twist['label']
        data['minq_label'] = db.ec_curves.lucky({'label': minq_label},
                                                'lmfdb_label')
        data['minq_info'] = '(itself)' if minqD == 1 else '(by %s)' % minqD
        if self.degree is None:
            data['degree'] = 0  # invalid, but will be displayed nicely
        else:
            data['degree'] = self.degree
        if self.number == 1:
            data['an'] = self.anlist
            data['ap'] = self.aplist
        else:
            r = db.ec_curves.lucky({'lmfdb_iso': self.lmfdb_iso, 'number': 1})
            data['an'] = r['anlist']
            data['ap'] = r['aplist']

        minq_N, minq_iso, minq_number = split_lmfdb_label(data['minq_label'])

        data['disc_factor'] = latex(Dfac)
        data['cond_factor'] = latex(Nfac)
        data['disc_latex'] = web_latex(D)
        data['cond_latex'] = web_latex(N)

        data['galois_images'] = [
            trim_galois_image_code(s) for s in self.mod_p_images
        ]
        data['non_maximal_primes'] = self.non_maximal_primes
        data['galois_data'] = [{
            'p': p,
            'image': im
        } for p, im in zip(data['non_maximal_primes'], data['galois_images'])]

        data['CMD'] = self.cm
        data['CM'] = "no"
        data['EndE'] = "\(\Z\)"
        if self.cm:
            data['cm_ramp'] = [
                p for p in ZZ(self.cm).support()
                if not p in self.non_maximal_primes
            ]
            data['cm_nramp'] = len(data['cm_ramp'])
            if data['cm_nramp'] == 1:
                data['cm_ramp'] = data['cm_ramp'][0]
            else:
                data['cm_ramp'] = ", ".join([str(p) for p in data['cm_ramp']])
            data['cm_sqf'] = ZZ(self.cm).squarefree_part()

            data['CM'] = "yes (\(D=%s\))" % data['CMD']
            if data['CMD'] % 4 == 0:
                d4 = ZZ(data['CMD']) // 4
                data['EndE'] = "\(\Z[\sqrt{%s}]\)" % d4
            else:
                data['EndE'] = "\(\Z[(1+\sqrt{%s})/2]\)" % data['CMD']
            data['ST'] = st_link_by_name(1, 2, 'N(U(1))')
        else:
            data['ST'] = st_link_by_name(1, 2, 'SU(2)')

        data['p_adic_primes'] = [
            p for i, p in enumerate(prime_range(5, 100))
            if (N * data['ap'][i]) % p != 0
        ]

        cond, iso, num = split_lmfdb_label(self.lmfdb_label)
        self.class_url = url_for(".by_double_iso_label",
                                 conductor=N,
                                 iso_label=iso)
        self.one_deg = ZZ(self.class_deg).is_prime()
        self.ncurves = db.ec_curves.count({'lmfdb_iso': self.lmfdb_iso})
        isodegs = [str(d) for d in self.isogeny_degrees if d > 1]
        if len(isodegs) < 3:
            data['isogeny_degrees'] = " and ".join(isodegs)
        else:
            data['isogeny_degrees'] = " and ".join(
                [", ".join(isodegs[:-1]), isodegs[-1]])

        if self.twoadic_gens:
            from sage.matrix.all import Matrix
            data['twoadic_gen_matrices'] = ','.join(
                [latex(Matrix(2, 2, M)) for M in self.twoadic_gens])
            data[
                'twoadic_rouse_url'] = ROUSE_URL_PREFIX + self.twoadic_label + ".html"

        # Leading term of L-function & other BSD data
        self.make_bsd()

        # Optimality (the optimal curve in the class is the curve
        # whose Cremona label ends in '1' except for '990h' which was
        # labelled wrongly long ago)

        if self.iso == '990h':
            data['Gamma0optimal'] = bool(self.number == 3)
        else:
            data['Gamma0optimal'] = bool(self.number == 1)

        data['p_adic_data_exists'] = False
        if data['Gamma0optimal']:
            data['p_adic_data_exists'] = db.ec_padic.exists(
                {'lmfdb_iso': self.lmfdb_iso})

        # Iwasawa data (where present)

        self.make_iwasawa()

        # Torsion growth data (where present)

        self.make_torsion_growth()

        data['newform'] = web_latex(
            PowerSeriesRing(QQ, 'q')(data['an'], 20, check=True))
        data['newform_label'] = self.newform_label = newform_label(
            cond, 2, 1, iso)
        self.newform_link = url_for("emf.render_elliptic_modular_forms",
                                    level=cond,
                                    weight=2,
                                    character=1,
                                    label=iso)
        self.newform_exists_in_db = is_newform_in_db(self.newform_label)
        self._code = None

        self.class_url = url_for(".by_double_iso_label",
                                 conductor=N,
                                 iso_label=iso)
        self.friends = [('Isogeny class ' + self.lmfdb_iso, self.class_url),
                        ('Minimal quadratic twist %s %s' %
                         (data['minq_info'], data['minq_label']),
                         url_for(".by_triple_label",
                                 conductor=minq_N,
                                 iso_label=minq_iso,
                                 number=minq_number)),
                        ('All twists ',
                         url_for(".rational_elliptic_curves", jinv=self.jinv)),
                        ('L-function',
                         url_for("l_functions.l_function_ec_page",
                                 conductor_label=N,
                                 isogeny_class_label=iso))]

        if not self.cm:
            if N <= 300:
                self.friends += [('Symmetric square L-function',
                                  url_for("l_functions.l_function_ec_sym_page",
                                          power='2',
                                          conductor=N,
                                          isogeny=iso))]
            if N <= 50:
                self.friends += [('Symmetric cube L-function',
                                  url_for("l_functions.l_function_ec_sym_page",
                                          power='3',
                                          conductor=N,
                                          isogeny=iso))]
        if self.newform_exists_in_db:
            self.friends += [('Modular form ' + self.newform_label,
                              self.newform_link)]

        self.downloads = [('Download coefficients of q-expansion',
                           url_for(".download_EC_qexp",
                                   label=self.lmfdb_label,
                                   limit=1000)),
                          ('Download all stored data',
                           url_for(".download_EC_all",
                                   label=self.lmfdb_label)),
                          ('Download Magma code',
                           url_for(".ec_code_download",
                                   conductor=cond,
                                   iso=iso,
                                   number=num,
                                   label=self.lmfdb_label,
                                   download_type='magma')),
                          ('Download SageMath code',
                           url_for(".ec_code_download",
                                   conductor=cond,
                                   iso=iso,
                                   number=num,
                                   label=self.lmfdb_label,
                                   download_type='sage')),
                          ('Download GP code',
                           url_for(".ec_code_download",
                                   conductor=cond,
                                   iso=iso,
                                   number=num,
                                   label=self.lmfdb_label,
                                   download_type='gp'))]

        try:
            self.plot = encode_plot(self.E.plot())
        except AttributeError:
            self.plot = encode_plot(EllipticCurve(data['ainvs']).plot())

        self.plot_link = '<a href="{0}"><img src="{0}" width="200" height="150"/></a>'.format(
            self.plot)
        self.properties = [('Label', self.lmfdb_label), (None, self.plot_link),
                           ('Conductor', '\(%s\)' % data['conductor']),
                           ('Discriminant', '\(%s\)' % data['disc']),
                           ('j-invariant', '%s' % data['j_inv_latex']),
                           ('CM', '%s' % data['CM']),
                           ('Rank', '\(%s\)' % self.mw['rank']),
                           ('Torsion Structure',
                            '\(%s\)' % self.mw['tor_struct'])]

        self.title = "Elliptic Curve %s (Cremona label %s)" % (
            self.lmfdb_label, self.label)

        self.bread = [('Elliptic Curves', url_for("ecnf.index")),
                      ('$\Q$', url_for(".rational_elliptic_curves")),
                      ('%s' % N, url_for(".by_conductor", conductor=N)),
                      ('%s' % iso,
                       url_for(".by_double_iso_label",
                               conductor=N,
                               iso_label=iso)), ('%s' % num, ' ')]
Exemplo n.º 30
0
    def is_Gamma0_equivalent(self, other, N, Transformation=False):
        r"""
        Checks if cusps ``self`` and ``other`` are `\Gamma_0(N)`- equivalent.

        INPUT:

        - ``other`` -- a number field cusp or a list of two number field
          elements which define a cusp.

        - ``N`` -- an ideal of the number field (level)

        OUTPUT:

        - bool -- ``True`` if the cusps are equivalent.

        - a transformation matrix -- (if ``Transformation=True``) a list of
          integral elements [a, b, c, d] which are the entries of a 2x2 matrix
          M in `\Gamma_0(N)` such that M * ``self`` = ``other`` if ``other``
          and ``self`` are `\Gamma_0(N)`- equivalent. If ``self`` and ``other``
          are not equivalent it returns zero.

        EXAMPLES:

        ::

            sage: K.<a> = NumberField(x^3-10)
            sage: N = K.ideal(a-1)
            sage: alpha = NFCusp(K, 0)
            sage: beta = NFCusp(K, oo)
            sage: alpha.is_Gamma0_equivalent(beta, N)
            False
            sage: alpha.is_Gamma0_equivalent(beta, K.ideal(1))
            True
            sage: b, M = alpha.is_Gamma0_equivalent(beta, K.ideal(1),Transformation=True)
            sage: alpha.apply(M)
            Cusp Infinity of Number Field in a with defining polynomial x^3 - 10

        ::

            sage: k.<a> = NumberField(x^2+23)
            sage: N = k.ideal(3)
            sage: alpha1 = NFCusp(k, a+1, 4)
            sage: alpha2 = NFCusp(k, a-8, 29)
            sage: alpha1.is_Gamma0_equivalent(alpha2, N)
            True
            sage: b, M = alpha1.is_Gamma0_equivalent(alpha2, N, Transformation=True)
            sage: alpha1.apply(M) == alpha2
            True
            sage: M[2] in N
            True
        """
        k = self.number_field()
        other = NFCusp(k, other)
        if not (self.ideal()/other.ideal()).is_principal():
            if not Transformation:
                return False
            else:
                return False, 0

        reps = list_of_representatives(N)
        alpha1 = NFCusp(k, self, lreps=reps)
        alpha2 = NFCusp(k, other, lreps=reps)

        delta = k.ideal(alpha1.__b) + N
        if (k.ideal(alpha2.__b) + N)!= delta:
            if not Transformation:
                return False
            else:
                return False, 0

        M1 = alpha1.ABmatrix()
        M2 = alpha2.ABmatrix()

        A = alpha1.ideal()
        B = k.ideal(M1[1], M1[3])

        ABdelta = A*B*delta*delta

        units = units_mod_ideal(ABdelta)
        for u in units:
            if (M2[2]*M1[3] - u*M1[2]*M2[3]) in ABdelta:
                if not Transformation:
                    return True
                else:
                    AuxCoeff = [1, 0, 0, 1]
                    Aux = M2[2]*M1[3] - u*M1[2]*M2[3]
                    if Aux in A*B*N:
                        if not u==1:
                            AuxCoeff[3] = u
                    else:
                        A1 = (A*B*N)/ABdelta
                        A2 = B*k.ideal(M1[2]*M2[2])/(A*ABdelta)
                        f = A1.element_1_mod(A2)
                        w = ((1 - f)*Aux)/(M1[2]*M2[2])
                        AuxCoeff[3] = u
                        AuxCoeff[1] = w
                    from sage.matrix.all import Matrix
                    Maux = Matrix(k, 2, AuxCoeff)
                    M1inv = Matrix(k, 2, M1).inverse()
                    Mtrans = Matrix(k, 2, M2)*Maux*M1inv
                    assert Mtrans[1][0] in N
                    return True, Mtrans.list()
        if not Transformation:
            return False
        else:
            return False, 0
Exemplo n.º 31
0
class ECisog_class(object):
    """
    Class for an isogeny class of elliptic curves over Q
    """
    def __init__(self, dbdata):
        """
        Arguments:

            - dbdata: the data from the database
        """
        logger.debug("Constructing an instance of ECisog_class")
        self.__dict__.update(dbdata)
        self.make_class()

    @staticmethod
    def by_label(label):
        """
        Searches for a specific elliptic curve isogeny class in the
        curves collection by its label, which can be either a curve
        label (e.g. "11.a1") or a class label (e.g. "11.a") in either
        LMFDB or Cremona format.
        """
        #print "label = %s" % label
        try:
            N, iso, number = split_lmfdb_label(label)
            if number:
                data = db_ec().find_one({"lmfdb_label" : label})
            else:
                data = db_ec().find_one({"lmfdb_label" : label+"1"})
        except AttributeError:
            try:
                N, iso, number = split_cremona_label(label)
                if number:
                    data = db_ec().find_one({"label" : label})
                else:
                    data = db_ec().find_one({"label" : label+"1"})
            except AttributeError:
                return "Invalid label" # caller must catch this and raise an error

        if data:
            return ECisog_class(data)
        return "Class not found" # caller must catch this and raise an error

    def make_class(self):
        self.ainvs_str = self.ainvs
        self.ainvs = [int(a) for a in self.ainvs_str]
        self.E = EllipticCurve(self.ainvs)
        self.CM = self.E.has_cm()

        try:
            # Extract the isogeny degree matrix from the database
            size = len(self.isogeny_matrix)
            from sage.matrix.all import Matrix
            self.isogeny_matrix = Matrix(self.isogeny_matrix)
        except AttributeError:
            # Failsafe: construct it from scratch
            self.isogeny_matrix = self.E.isogeny_class(order="lmfdb").matrix()
            size = self.isogeny_matrix.nrows()
        self.ncurves = size

        # Create isogeny graph:
        self.graph = make_graph(self.isogeny_matrix)
        P = self.graph.plot(edge_labels=True)
        self.graph_img = encode_plot(P)
        self.graph_link = '<img src="%s" width="200" height="150"/>' % self.graph_img

        # Create a list of the curves in the class from the database
        self.db_curves = [self.E]
        self.optimal_flags = [False] * size
        self.degrees = [0] * size
        if self.degree:
            self.degrees[0] = self.degree
        else:
            try:
                self.degrees[0] = self.E.modular_degree()
            except RuntimeError:
                pass

        # Fill in the curves in the class by looking each one up in the db:

        self.cremona_labels = [self.label] + [0] * (size - 1)
        if self.number == 1:
            self.optimal_flags[0] = True
        for i in range(2, size + 1):
            Edata = db_ec().find_one({'lmfdb_label': self.lmfdb_iso + str(i)})
            Ei = EllipticCurve([int(a) for a in Edata['ainvs']])
            self.cremona_labels[i - 1] = Edata['label']
            if Edata['number'] == 1:
                self.optimal_flags[i - 1] = True
            if 'degree' in Edata:
                self.degrees[i - 1] = Edata['degree']
            else:
                try:
                    self.degrees[i - 1] = Ei.modular_degree()
                except RuntimeError:
                    pass
            self.db_curves.append(Ei)


        if self.iso == '990h':  # this isogeny class is labeled wrong in Cremona's tables
            self.optimal_flags = [False, False, True, False]

        self.isogeny_matrix_str = latex(matrix(self.isogeny_matrix))

        N, iso, number = split_lmfdb_label(self.lmfdb_iso)

        self.newform = web_latex(self.E.q_eigenform(10))
        self.newform_label = self.lmfdb_iso.replace('.', '.2')
        self.newform_link = url_for("emf.render_elliptic_modular_forms", level=N, weight=2, character=0, label=iso)

        self.lfunction_link = url_for("l_functions.l_function_ec_page", label=self.lmfdb_iso)

        self.curves = [dict([('label',self.lmfdb_iso + str(i + 1)),
                             ('url',url_for(".by_triple_label", conductor=N, iso_label=iso, number=i+1)),
                             ('cremona_label',self.cremona_labels[i]),
                             ('ainvs',str(list(c.ainvs()))),
                             ('torsion',c.torsion_order()),
                             ('degree',self.degrees[i]),
                             ('optimal',self.optimal_flags[i])])
                       for i, c in enumerate(self.db_curves)]

        self.friends = [
        ('L-function', self.lfunction_link),
        ('Symmetric square L-function', url_for("l_functions.l_function_ec_sym_page", power='2', label=self.lmfdb_iso)),
        ('Symmetric 4th power L-function', url_for("l_functions.l_function_ec_sym_page", power='4', label=self.lmfdb_iso)),
        ('Modular form ' + self.newform_label, self.newform_link)]

        self.properties = [('Label', self.lmfdb_iso),
                           ('Number of curves', str(self.ncurves)),
                           ('Conductor', '\(%s\)' % N),
                           ('CM', '%s' % self.CM),
                           ('Rank', '\(%s\)' % self.rank),
                           ('Graph', ''),(None, self.graph_link)
                           ]


        self.downloads = [('Download coeffients of newform', url_for(".download_EC_qexp", label=self.lmfdb_iso, limit=100)),
                         ('Download stored data for all curves', url_for(".download_EC_all", label=self.lmfdb_iso))]

        if self.lmfdb_iso == self.iso:
            self.title = "Elliptic Curve Isogeny Class %s" % self.lmfdb_iso
        else:
            self.title = "Elliptic Curve Isogeny Class %s (Cremona label %s)" % (self.lmfdb_iso, self.iso)

        self.bread = [('Elliptic Curves', url_for("ecnf.index")),
                      ('$\Q$', url_for(".rational_elliptic_curves")),
                      ('%s' % N, url_for(".by_conductor", conductor=N)),
                      ('%s' % iso, ' ')]
Exemplo n.º 32
0
        def to_matrix(self, side="right", on_space="primal"):
            r"""
            Return ``self`` as a matrix acting on the underlying vector
            space.

            - ``side`` -- optional (default: ``"right"``) whether the
              action of ``self`` is on the ``"left"`` or on the ``"right"``

            - ``on_space`` -- optional (default: ``"primal"``) whether
              to act as the reflection representation on the given
              basis, or to act on the dual reflection representation
              on the dual basis

            EXAMPLES::

                sage: W = ReflectionGroup(['A',2])           # optional - gap3
                sage: for w in W:                            # optional - gap3
                ....:     w.reduced_word()                   # optional - gap3
                ....:     [w.to_matrix(), w.to_matrix(on_space="dual")] # optional - gap3
                []
                [
                [1 0]  [1 0]
                [0 1], [0 1]
                ]
                [2]
                [
                [ 1  1]  [ 1  0]
                [ 0 -1], [ 1 -1]
                ]
                [1]
                [
                [-1  0]  [-1  1]
                [ 1  1], [ 0  1]
                ]
                [1, 2]
                [
                [-1 -1]  [ 0 -1]
                [ 1  0], [ 1 -1]
                ]
                [2, 1]
                [
                [ 0  1]  [-1  1]
                [-1 -1], [-1  0]
                ]
                [1, 2, 1]
                [
                [ 0 -1]  [ 0 -1]
                [-1  0], [-1  0]
                ]

            TESTS::

                sage: W = ReflectionGroup(['F',4])           # optional - gap3
                sage: all(w.to_matrix(side="left") == W.from_reduced_word(reversed(w.reduced_word())).to_matrix(side="right").transpose() for w in W) # optional - gap3
                True
                sage: all(w.to_matrix(side="right") == W.from_reduced_word(reversed(w.reduced_word())).to_matrix(side="left").transpose() for w in W) # optional - gap3
                True
            """
            W = self.parent()
            if W._reflection_representation is None:
                if side == "left":
                    w = ~self
                elif side == "right":
                    w = self
                else:
                    raise ValueError('side must be "left" or "right"')

                Delta = W.independent_roots()
                Phi = W.roots()
                M = Matrix([Phi[w(Phi.index(alpha)+1)-1] for alpha in Delta])
                mat = W.base_change_matrix() * M
            else:
                refl_repr = W._reflection_representation
                id_mat = identity_matrix(QQ, refl_repr[W.index_set()[0]].nrows())
                mat = prod([refl_repr[i] for i in self.reduced_word()], id_mat)

            if on_space == "primal":
                if side == "left":
                    mat = mat.transpose()
            elif on_space == "dual":
                if side == "left":
                    mat = mat.inverse()
                else:
                    mat = mat.inverse().transpose()
            else:
                raise ValueError('on_space must be "primal" or "dual"')

            mat.set_immutable()
            return mat
Exemplo n.º 33
0
    def bilinear_form(self, R=None):
        """
        Return the bilinear form over ``R`` associated to ``self``.

        INPUT:

        - ``R`` -- (default: universal cyclotomic field) a ring used to
          compute the bilinear form

        EXAMPLES::

            sage: CoxeterType(['A', 2, 1]).bilinear_form()
            [   1 -1/2 -1/2]
            [-1/2    1 -1/2]
            [-1/2 -1/2    1]
            sage: CoxeterType(['H', 3]).bilinear_form()
            [                      1                    -1/2                       0]
            [                   -1/2                       1 1/2*E(5)^2 + 1/2*E(5)^3]
            [                      0 1/2*E(5)^2 + 1/2*E(5)^3                       1]
            sage: C = CoxeterMatrix([[1,-1,-1],[-1,1,-1],[-1,-1,1]])
            sage: C.bilinear_form()
            [ 1 -1 -1]
            [-1  1 -1]
            [-1 -1  1]
        """

        n = self.rank()
        mat = self.coxeter_matrix()._matrix

        from sage.rings.universal_cyclotomic_field import UniversalCyclotomicField
        UCF = UniversalCyclotomicField()

        if R is None:
            R = UCF
        # if UCF.has_coerce_map_from(base_ring):
        #     R = UCF
        # else:
        #     R = base_ring

        # Compute the matrix with entries `- \cos( \pi / m_{ij} )`.
        E = UCF.gen
        if R is UCF:

            def val(x):
                if x > -1:
                    return (E(2 * x) + ~E(2 * x)) / R(-2)
                else:
                    return R(x)
        elif is_QuadraticField(R):

            def val(x):
                if x > -1:
                    return R(
                        (E(2 * x) + ~E(2 * x)).to_cyclotomic_field()) / R(-2)
                else:
                    return R(x)
        else:
            from sage.functions.trig import cos
            from sage.symbolic.constants import pi

            def val(x):
                if x > -1:
                    return -R(cos(pi / SR(x)))
                else:
                    return R(x)

        entries = [
            SparseEntry(i, j, val(mat[i, j])) for i in range(n)
            for j in range(n) if mat[i, j] != 2
        ]
        bilinear = Matrix(R, n, entries)
        bilinear.set_immutable()
        return bilinear
Exemplo n.º 34
0
    def make_class(self):
        self.ainvs_str = self.ainvs
        self.ainvs = [int(a) for a in self.ainvs_str]
        self.E = EllipticCurve(self.ainvs)
        self.CM = self.E.has_cm()

        try:
            # Extract the isogeny degree matrix from the database
            size = len(self.isogeny_matrix)
            from sage.matrix.all import Matrix

            self.isogeny_matrix = Matrix(self.isogeny_matrix)
        except AttributeError:
            # Failsafe: construct it from scratch
            self.isogeny_matrix = self.E.isogeny_class(order="lmfdb").matrix()
            size = self.isogeny_matrix.nrows()
        self.ncurves = size

        # Create isogeny graph:
        self.graph = make_graph(self.isogeny_matrix)
        P = self.graph.plot(edge_labels=True)
        self.graph_img = encode_plot(P)
        self.graph_link = '<img src="%s" width="200" height="150"/>' % self.graph_img

        # Create a list of the curves in the class from the database
        self.db_curves = [self.E]
        self.optimal_flags = [False] * size
        self.degrees = [0] * size
        if self.degree:
            self.degrees[0] = self.degree
        else:
            try:
                self.degrees[0] = self.E.modular_degree()
            except RuntimeError:
                pass

        # Fill in the curves in the class by looking each one up in the db:

        self.cremona_labels = [self.label] + [0] * (size - 1)
        if self.number == 1:
            self.optimal_flags[0] = True
        for i in range(2, size + 1):
            Edata = db_ec().find_one({"lmfdb_label": self.lmfdb_iso + str(i)})
            Ei = EllipticCurve([int(a) for a in Edata["ainvs"]])
            self.cremona_labels[i - 1] = Edata["label"]
            if Edata["number"] == 1:
                self.optimal_flags[i - 1] = True
            if "degree" in Edata:
                self.degrees[i - 1] = Edata["degree"]
            else:
                try:
                    self.degrees[i - 1] = Ei.modular_degree()
                except RuntimeError:
                    pass
            self.db_curves.append(Ei)

        if self.iso == "990h":  # this isogeny class is labeled wrong in Cremona's tables
            self.optimal_flags = [False, False, True, False]

        self.isogeny_matrix_str = latex(matrix(self.isogeny_matrix))

        N, iso, number = split_lmfdb_label(self.lmfdb_iso)

        self.newform = web_latex(self.E.q_eigenform(10))
        self.newform_label = newform_label(N, 2, 1, iso)
        self.newform_link = url_for("emf.render_elliptic_modular_forms", level=N, weight=2, character=1, label=iso)
        newform_exists_in_db = is_newform_in_db(self.newform_label)

        self.lfunction_link = url_for("l_functions.l_function_ec_page", label=self.lmfdb_iso)

        self.curves = [
            dict(
                [
                    ("label", self.lmfdb_iso + str(i + 1)),
                    ("url", url_for(".by_triple_label", conductor=N, iso_label=iso, number=i + 1)),
                    ("cremona_label", self.cremona_labels[i]),
                    ("ainvs", str(list(c.ainvs()))),
                    ("torsion", c.torsion_order()),
                    ("degree", self.degrees[i]),
                    ("optimal", self.optimal_flags[i]),
                ]
            )
            for i, c in enumerate(self.db_curves)
        ]

        self.friends = [("L-function", self.lfunction_link)]
        if not self.CM:
            self.friends += [
                (
                    "Symmetric square L-function",
                    url_for("l_functions.l_function_ec_sym_page", power="2", label=self.lmfdb_iso),
                ),
                (
                    "Symmetric 4th power L-function",
                    url_for("l_functions.l_function_ec_sym_page", power="4", label=self.lmfdb_iso),
                ),
            ]
        if newform_exists_in_db:
            self.friends += [("Modular form " + self.newform_label, self.newform_link)]

        self.properties = [
            ("Label", self.lmfdb_iso),
            ("Number of curves", str(self.ncurves)),
            ("Conductor", "\(%s\)" % N),
            ("CM", "%s" % self.CM),
            ("Rank", "\(%s\)" % self.rank),
            ("Graph", ""),
            (None, self.graph_link),
        ]

        self.downloads = [
            ("Download coefficients of newform", url_for(".download_EC_qexp", label=self.lmfdb_iso, limit=100)),
            ("Download stored data for all curves", url_for(".download_EC_all", label=self.lmfdb_iso)),
        ]

        if self.lmfdb_iso == self.iso:
            self.title = "Elliptic Curve Isogeny Class %s" % self.lmfdb_iso
        else:
            self.title = "Elliptic Curve Isogeny Class %s (Cremona label %s)" % (self.lmfdb_iso, self.iso)

        self.bread = [
            ("Elliptic Curves", url_for("ecnf.index")),
            ("$\Q$", url_for(".rational_elliptic_curves")),
            ("%s" % N, url_for(".by_conductor", conductor=N)),
            ("%s" % iso, " "),
        ]
Exemplo n.º 35
0
    def make_class(self):
        self.ainvs_str = self.ainvs
        self.ainvs = [int(a) for a in self.ainvs_str]
        self.E = EllipticCurve(self.ainvs)
        self.CM = self.E.has_cm()

        try:
            # Extract the isogeny degree matrix from the database
            size = len(self.isogeny_matrix)
            from sage.matrix.all import Matrix
            self.isogeny_matrix = Matrix(self.isogeny_matrix)
        except AttributeError:
            # Failsafe: construct it from scratch
            self.isogeny_matrix = self.E.isogeny_class(order="lmfdb").matrix()
            size = self.isogeny_matrix.nrows()

        # Create isogeny graph:
        self.graph = make_graph(self.isogeny_matrix)
        P = self.graph.plot(edge_labels=True)
        self.graph_img = encode_plot(P)
        self.graph_link = '<img src="%s" width="200" height="150"/>' % self.graph_img

        # Create a list of the curves in the class from the database
        self.db_curves = [self.E]
        self.optimal_flags = [False] * size
        self.degrees = [0] * size
        if self.degree:
            self.degrees[0] = self.degree
        else:
            try:
                self.degrees[0] = self.E.modular_degree()
            except RuntimeError:
                pass

        # Fill in the curves in the class by looking each one up in the db:

        self.cremona_labels = [self.label] + [0] * (size - 1)
        if self.number == 1:
            self.optimal_flags[0] = True
        for i in range(2, size + 1):
            Edata = db_ec().find_one({'lmfdb_label': self.lmfdb_iso + str(i)})
            Ei = EllipticCurve([int(a) for a in Edata['ainvs']])
            self.cremona_labels[i - 1] = Edata['label']
            if Edata['number'] == 1:
                self.optimal_flags[i - 1] = True
            if 'degree' in Edata:
                self.degrees[i - 1] = Edata['degree']
            else:
                try:
                    self.degrees[i - 1] = Ei.modular_degree()
                except RuntimeError:
                    pass
            self.db_curves.append(Ei)


        if self.iso == '990h':  # this isogeny class is labeled wrong in Cremona's tables
            self.optimal_flags = [False, False, True, False]

        self.isogeny_matrix_str = latex(matrix(self.isogeny_matrix))

        N, iso, number = lmfdb_label_regex.match(self.lmfdb_iso).groups()

        self.newform = web_latex(self.E.q_eigenform(10))
        self.newform_label = self.lmfdb_iso.replace('.', '.2')
        self.newform_link = url_for("emf.render_elliptic_modular_forms", level=N, weight=2, character=0, label=iso)

        self.lfunction_link = url_for("l_functions.l_function_ec_page", label=self.lmfdb_iso)

        self.curves = [[self.lmfdb_iso + str(i + 1),
                        self.cremona_labels[i],
                        str(list(c.ainvs())),
                        c.torsion_order(),
                        self.degrees[i],
                        self.optimal_flags[i]]
                       for i, c in enumerate(self.db_curves)]

        self.friends = [
        ('L-function', self.lfunction_link),
        ('Symmetric square L-function', url_for("l_functions.l_function_ec_sym_page", power='2', label=self.lmfdb_iso)),
        ('Symmetric 4th power L-function', url_for("l_functions.l_function_ec_sym_page", power='4', label=self.lmfdb_iso)),
        ('Modular form ' + self.newform_label, self.newform_link)]

        self.properties = [('Label', self.lmfdb_iso),
                           (None, self.graph_link),
                           ('Conductor', '\(%s\)' % N),
                           ('CM', '%s' % self.CM),
                           ('Rank', '\(%s\)' % self.rank)
                           ]


        self.downloads = [('Download coeffients of newform', url_for(".download_EC_qexp", label=self.lmfdb_iso, limit=100)),
                         ('Download stored data for all curves', url_for(".download_EC_all", label=self.lmfdb_iso))]

        if self.lmfdb_iso == self.iso:
            self.title = "Elliptic Curve Isogeny Class %s" % self.lmfdb_iso
        else:
            self.title = "Elliptic Curve Isogeny Class %s (Cremona label %s)" % (self.lmfdb_iso, self.iso)

        self.bread = [('Elliptic Curves ', url_for(".rational_elliptic_curves")), ('isogeny class %s' % self.lmfdb_iso, ' ')]
Exemplo n.º 36
0
def Mestre_conic(i, xyz=False, names='u,v,w'):
    r"""
    Return the conic equation from Mestre's algorithm given the Igusa-Clebsch
    invariants.

    It has a rational point if and only if a hyperelliptic curve
    corresponding to the invariants exists.

    INPUT:

    - ``i`` - list or tuple of length 4 containing the four Igusa-Clebsch
      invariants: I2, I4, I6, I10
    - ``xyz`` - Boolean (default: False) if True, the algorithm also
      returns three invariants x,y,z used in Mestre's algorithm
    - ``names`` (default: 'u,v,w') - the variable names for the Conic

    OUTPUT:

    A Conic object

    EXAMPLES:

    A standard example::

        sage: Mestre_conic([1,2,3,4])
        Projective Conic Curve over Rational Field defined by -2572155000*u^2 - 317736000*u*v + 1250755459200*v^2 + 2501510918400*u*w + 39276887040*v*w + 2736219686912*w^2

    Note that the algorithm works over number fields as well::

        sage: k = NumberField(x^2-41,'a')
        sage: a = k.an_element()
        sage: Mestre_conic([1,2+a,a,4+a])
        Projective Conic Curve over Number Field in a with defining polynomial x^2 - 41 defined by (-801900000*a + 343845000)*u^2 + (855360000*a + 15795864000)*u*v + (312292800000*a + 1284808579200)*v^2 + (624585600000*a + 2569617158400)*u*w + (15799910400*a + 234573143040)*v*w + (2034199306240*a + 16429854656512)*w^2

    And over finite fields::

        sage: Mestre_conic([GF(7)(10),GF(7)(1),GF(7)(2),GF(7)(3)])
        Projective Conic Curve over Finite Field of size 7 defined by -2*u*v - v^2 - 2*u*w + 2*v*w - 3*w^2

    An example with xyz::

        sage: Mestre_conic([5,6,7,8], xyz=True)
        (Projective Conic Curve over Rational Field defined by -415125000*u^2 + 608040000*u*v + 33065136000*v^2 + 66130272000*u*w + 240829440*v*w + 10208835584*w^2, 232/1125, -1072/16875, 14695616/2109375)

    ALGORITHM:

    The formulas are taken from pages 956 - 957 of [LY2001]_ and based on pages
    321 and 332 of [M1991]_.

    See the code or [LY2001]_ for the detailed formulae defining x, y, z and L.

    """
    from sage.structure.sequence import Sequence
    k = Sequence(i).universe()
    try:
        k = k.fraction_field()
    except (TypeError, AttributeError, NotImplementedError):
        pass

    I2, I4, I6, I10 = i

    #Setting x,y,z as in Mestre's algorithm (Using Lauter and Yang's formulas)
    x = 8*(1 + 20*I4/(I2**2))/225
    y = 16*(1 + 80*I4/(I2**2) - 600*I6/(I2**3))/3375
    z = -64*(-10800000*I10/(I2**5) - 9 - 700*I4/(I2**2) + 3600*I6/(I2**3) +
              12400*I4**2/(I2**4) - 48000*I4*I6/(I2**5))/253125

    L = Matrix([[x+6*y     , 6*x**2+2*y         , 2*z                      ],
                [6*x**2+2*y, 2*z                , 9*x**3 + 4*x*y + 6*y**2  ],
                [2*z       , 9*x**3+4*x*y+6*y**2, 6*x**2*y + 2*y**2 + 3*x*z]])

    try:
        L = L*L.denominator()  # clears the denominator
    except (AttributeError, TypeError):
        pass

    u, v, w = PolynomialRing(k, names).gens()
    MConic = Conic(k, L, names)
    if xyz:
        return MConic, x, y, z
    return MConic
Exemplo n.º 37
0
    def make_class(self):
        self.CM = self.cm
        N, iso, number = split_lmfdb_label(self.lmfdb_iso)
        self.conductor = int(N)
        # Extract the size of the isogeny class from the database
        self.ncurves = ncurves = self.class_size
        # Create a list of the curves in the class from the database
        number_key = 'number' if self.label_type == 'Cremona' else 'lmfdb_number'
        self.curves = [
            db.ec_curves.lucky({
                'iso': self.iso,
                number_key: i + 1
            }) for i in range(ncurves)
        ]

        # Set optimality flags.  The optimal curve is number 1 except
        # in one case which is labeled differently in the Cremona tables
        self.optimality_known = (self.ncurves
                                 == 1) or (self.conductor < OPTIMALITY_BOUND)
        self.optimality_bound = OPTIMALITY_BOUND
        for c in self.curves:
            c['optimal'] = (c['number'] == (3 if self.iso == '990h' else 1))
            c['ai'] = c['ainvs']
            c['curve_url_lmfdb'] = url_for(".by_triple_label",
                                           conductor=N,
                                           iso_label=iso,
                                           number=c['lmfdb_number'])
            c['curve_url_cremona'] = url_for(".by_ec_label", label=c['label'])
            if self.label_type == 'Cremona':
                c['curve_label'] = c['label']
                _, c_iso, c_number = split_cremona_label(c['label'])
            else:
                c['curve_label'] = c['lmfdb_label']
                _, c_iso, c_number = split_lmfdb_label(c['lmfdb_label'])
            c['short_label'] = "{}{}".format(c_iso, c_number)

        from sage.matrix.all import Matrix
        if self.label_type == 'Cremona':
            # permute rows/cols
            perm = lambda i: (c for c in self.curves if c['number'] == i + 1
                              ).next()['lmfdb_number'] - 1
            self.isogeny_matrix = [[
                self.isogeny_matrix[perm(i)][perm(j)] for i in range(ncurves)
            ] for j in range(ncurves)]

        self.isogeny_matrix = Matrix(self.isogeny_matrix)

        self.isogeny_matrix_str = latex(matrix(self.isogeny_matrix))

        # Create isogeny graph with appropriate vertex labels:

        self.graph = make_graph(self.isogeny_matrix,
                                [c['short_label'] for c in self.curves])
        P = self.graph.plot(edge_labels=True, vertex_size=1000)
        self.graph_img = encode_plot(P)
        self.graph_link = '<img src="%s" width="200" height="150"/>' % self.graph_img

        self.newform = web_latex(
            PowerSeriesRing(QQ, 'q')(self.anlist, 20, check=True))
        self.newform_label = db.mf_newforms.lucky(
            {
                'level': N,
                'weight': 2,
                'related_objects': {
                    '$contains': 'EllipticCurve/Q/%s/%s' % (N, iso)
                }
            }, 'label')
        self.newform_exists_in_db = self.newform_label is not None
        if self.newform_label is not None:
            char_orbit, hecke_orbit = self.newform_label.split('.')[2:]
            self.newform_link = url_for("cmf.by_url_newform_label",
                                        level=N,
                                        weight=2,
                                        char_orbit_label=char_orbit,
                                        hecke_orbit=hecke_orbit)

        self.lfunction_link = url_for("l_functions.l_function_ec_page",
                                      conductor_label=N,
                                      isogeny_class_label=iso)

        self.friends = [('L-function', self.lfunction_link)]
        if not self.CM:
            self.CM = "no"
            if int(N) <= 300:
                self.friends += [('Symmetric square L-function',
                                  url_for("l_functions.l_function_ec_sym_page",
                                          power='2',
                                          conductor=N,
                                          isogeny=iso))]
            if int(N) <= 50:
                self.friends += [('Symmetric cube L-function',
                                  url_for("l_functions.l_function_ec_sym_page",
                                          power='3',
                                          conductor=N,
                                          isogeny=iso))]
        if self.newform_exists_in_db:
            self.friends += [('Modular form ' + self.newform_label,
                              self.newform_link)]

        if self.label_type == 'Cremona':
            self.title = "Elliptic Curve Isogeny Class with Cremona label {} (LMFDB label {})".format(
                self.iso, self.lmfdb_iso)
            self.iso_label = self.iso
        else:
            self.title = "Elliptic Curve Isogeny Class with LMFDB label {} (Cremona label {})".format(
                self.lmfdb_iso, self.iso)
            self.iso_label = self.lmfdb_iso

        self.properties = [
            ('Label',
             self.iso if self.label_type == 'Cremona' else self.lmfdb_iso),
            ('Number of curves', str(ncurves)), ('Conductor', '%s' % N),
            ('CM', '%s' % self.CM), ('Rank', '%s' % self.rank)
        ]
        if self.ncurves > 1:
            self.properties += [('Graph', ''), (None, self.graph_link)]

        self.downloads = [('q-expansion to text',
                           url_for(".download_EC_qexp",
                                   label=self.lmfdb_iso,
                                   limit=1000)),
                          ('All stored data to text',
                           url_for(".download_EC_all", label=self.lmfdb_iso))]

        self.bread = [('Elliptic Curves', url_for("ecnf.index")),
                      ('$\Q$', url_for(".rational_elliptic_curves")),
                      ('%s' % N, url_for(".by_conductor", conductor=N)),
                      ('%s' % iso, ' ')]
        self.code = {}
        self.code['show'] = {'sage': ''}  # use default show names
        self.code['class'] = {
            'sage':
            'E = EllipticCurve("%s1")\n' % (self.lmfdb_iso) +
            'E.isogeny_class()\n'
        }
        self.code['curves'] = {'sage': 'E.isogeny_class().curves'}
        self.code['rank'] = {'sage': 'E.rank()'}
        self.code['q_eigenform'] = {'sage': 'E.q_eigenform(10)'}
        self.code['matrix'] = {'sage': 'E.isogeny_class().matrix()'}
        self.code['plot'] = {
            'sage': 'E.isogeny_graph().plot(edge_labels=True)'
        }
Exemplo n.º 38
0
    def _compute_q_expansion_basis(self, prec=None):
        r"""
        Compute q-expansion basis using Schaeffer's algorithm.

        EXAMPLES::

            sage: CuspForms(GammaH(31, [7]), 1).q_expansion_basis() # indirect doctest
            [
            q - q^2 - q^5 + O(q^6)
            ]

        A more elaborate example (two Galois-conjugate characters each giving a
        2-dimensional space)::

            sage: CuspForms(GammaH(124, [85]), 1).q_expansion_basis()
            [
            q - q^4 - q^6 + O(q^7),
            q^2 + O(q^7),
            q^3 + O(q^7),
            q^5 - q^6 + O(q^7)
            ]
        """
        if prec is None:
            prec = self.prec()
        else:
            prec = Integer(prec)

        chars=self.group().characters_mod_H(sign=-1, galois_orbits=True)

        B = []
        dim = 0
        for c in chars:
            chi = c.minimize_base_ring()
            Bchi = [weight1.modular_ratio_to_prec(chi, f, prec)
                for f in weight1.hecke_stable_subspace(chi) ]
            if Bchi == []:
                continue
            if chi.base_ring() == QQ:
                B += [f.padded_list(prec) for f in Bchi]
                dim += len(Bchi)
            else:
                d = chi.base_ring().degree()
                dim += d * len(Bchi)
                for f in Bchi:
                    w = f.padded_list(prec)
                    for i in range(d):
                        B.append([x[i] for x in w])

        basis_mat = Matrix(QQ, B)
        if basis_mat.is_zero():
            return []
        # Daft thing: "transformation=True" parameter to echelonize
        # is ignored for rational matrices!
        big_mat = basis_mat.augment(identity_matrix(dim))
        big_mat.echelonize()
        c = big_mat.pivots()[-1]

        echelon_basis_mat = big_mat[:, :prec]

        R = self._q_expansion_ring()

        if c >= prec:
            verbose("Precision %s insufficient to determine basis" % prec, level=1)
        else:
            verbose("Minimal precision for basis: %s" % (c+1), level=1)
            t = big_mat[:, prec:]
            assert echelon_basis_mat == t * basis_mat
            self.__transformation_matrix = t
            self._char_basis = [R(f.list(), c+1) for f in basis_mat.rows()]

        return [R(f.list(), prec) for f in echelon_basis_mat.rows() if f != 0]
Exemplo n.º 39
0
    def make_class(self):
        self.ainvs_str = self.ainvs
        self.ainvs = [int(a) for a in self.ainvs_str]
        self.E = EllipticCurve(self.ainvs)
        self.CM = self.E.has_cm()

        try:
            # Extract the isogeny degree matrix from the database
            size = len(self.isogeny_matrix)
            from sage.matrix.all import Matrix
            self.isogeny_matrix = Matrix(self.isogeny_matrix)
        except AttributeError:
            # Failsafe: construct it from scratch
            self.isogeny_matrix = self.E.isogeny_class(order="lmfdb").matrix()
            size = self.isogeny_matrix.nrows()
        self.ncurves = size

        # Create isogeny graph:
        self.graph = make_graph(self.isogeny_matrix)
        P = self.graph.plot(edge_labels=True)
        self.graph_img = encode_plot(P)
        self.graph_link = '<img src="%s" width="200" height="150"/>' % self.graph_img

        # Create a list of the curves in the class from the database
        self.db_curves = [self.E]
        self.optimal_flags = [False] * size
        self.degrees = [0] * size
        if self.degree:
            self.degrees[0] = self.degree
        else:
            try:
                self.degrees[0] = self.E.modular_degree()
            except RuntimeError:
                pass

        # Fill in the curves in the class by looking each one up in the db:

        self.cremona_labels = [self.label] + [0] * (size - 1)
        if self.number == 1:
            self.optimal_flags[0] = True
        for i in range(2, size + 1):
            Edata = db_ec().find_one({'lmfdb_label': self.lmfdb_iso + str(i)})
            Ei = EllipticCurve([int(a) for a in Edata['ainvs']])
            self.cremona_labels[i - 1] = Edata['label']
            if Edata['number'] == 1:
                self.optimal_flags[i - 1] = True
            if 'degree' in Edata:
                self.degrees[i - 1] = Edata['degree']
            else:
                try:
                    self.degrees[i - 1] = Ei.modular_degree()
                except RuntimeError:
                    pass
            self.db_curves.append(Ei)


        if self.iso == '990h':  # this isogeny class is labeled wrong in Cremona's tables
            self.optimal_flags = [False, False, True, False]

        self.isogeny_matrix_str = latex(matrix(self.isogeny_matrix))

        N, iso, number = split_lmfdb_label(self.lmfdb_iso)

        self.newform = web_latex(self.E.q_eigenform(10))
        self.newform_label = newform_label(N,2,1,iso)
        self.newform_link = url_for("emf.render_elliptic_modular_forms", level=N, weight=2, character=1, label=iso)
        self.newform_exists_in_db = is_newform_in_db(self.newform_label)

        self.lfunction_link = url_for("l_functions.l_function_ec_page", label=self.lmfdb_iso)

        self.curves = [dict([('label',self.lmfdb_iso + str(i + 1)),
                             ('url',url_for(".by_triple_label", conductor=N, iso_label=iso, number=i+1)),
                             ('cremona_label',self.cremona_labels[i]),
                             ('ainvs',str(list(c.ainvs()))),
                             ('torsion',c.torsion_order()),
                             ('degree',self.degrees[i]),
                             ('optimal',self.optimal_flags[i])])
                       for i, c in enumerate(self.db_curves)]

        self.friends =  [('L-function', self.lfunction_link)]
        if not self.CM:
            if int(N)<=300:
                self.friends += [('Symmetric square L-function', url_for("l_functions.l_function_ec_sym_page", power='2', label=self.lmfdb_iso))]
            if int(N)<=50:
                self.friends += [('Symmetric cube L-function', url_for("l_functions.l_function_ec_sym_page", power='3', label=self.lmfdb_iso))]
        if self.newform_exists_in_db:
            self.friends +=  [('Modular form ' + self.newform_label, self.newform_link)]

        self.properties = [('Label', self.lmfdb_iso),
                           ('Number of curves', str(self.ncurves)),
                           ('Conductor', '\(%s\)' % N),
                           ('CM', '%s' % self.CM),
                           ('Rank', '\(%s\)' % self.rank),
                           ('Graph', ''),(None, self.graph_link)
                           ]


        self.downloads = [('Download coefficients of newform', url_for(".download_EC_qexp", label=self.lmfdb_iso, limit=1000)),
                         ('Download stored data for all curves', url_for(".download_EC_all", label=self.lmfdb_iso))]

        if self.lmfdb_iso == self.iso:
            self.title = "Elliptic Curve Isogeny Class %s" % self.lmfdb_iso
        else:
            self.title = "Elliptic Curve Isogeny Class %s (Cremona label %s)" % (self.lmfdb_iso, self.iso)

        self.bread = [('Elliptic Curves', url_for("ecnf.index")),
                      ('$\Q$', url_for(".rational_elliptic_curves")),
                      ('%s' % N, url_for(".by_conductor", conductor=N)),
                      ('%s' % iso, ' ')]
        self.code = {}
        self.code['show'] = {'sage':''} # use default show names
        self.code['class'] = {'sage':'E = EllipticCurve("%s1")\n'%(self.lmfdb_iso) + 'E.isogeny_class()\n'}
        self.code['curves'] = {'sage':'E.isogeny_class().curves'}
        self.code['rank'] = {'sage':'E.rank()'}
        self.code['q_eigenform'] = {'sage':'E.q_eigenform(10)'}
        self.code['matrix'] = {'sage':'E.isogeny_class().matrix()'}
        self.code['plot'] = {'sage':'E.isogeny_graph().plot(edge_labels=True)'}