Ejemplo n.º 1
0
def lfsr_connection_polynomial(s):
    """
    INPUT:

    - ``s`` -- a sequence of elements of a finite field of even length

    OUTPUT:

    - ``C(x)`` -- the connection polynomial of the minimal LFSR.

    This implements the algorithm in section 3 of J. L. Massey's article
    [Mas1969]_.

    EXAMPLES::

        sage: F = GF(2)
        sage: F
        Finite Field of size 2
        sage: o = F(0); l = F(1)
        sage: key = [l,o,o,l]; fill = [l,l,o,l]; n = 20
        sage: s = lfsr_sequence(key,fill,n); s
        [1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0]
        sage: lfsr_connection_polynomial(s)
        x^4 + x + 1
        sage: from sage.matrix.berlekamp_massey import berlekamp_massey
        sage: berlekamp_massey(s)
        x^4 + x^3 + 1

    Notice that ``berlekamp_massey`` returns the reverse of the connection
    polynomial (and is potentially must faster than this implementation).
    """
    # Initialization:
    FF = s[0].base_ring()
    R = PolynomialRing(FF, "x")
    x = R.gen()
    C = R(1); B = R(1); m = 1; b = FF(1); L = 0; N = 0

    while N < len(s):
        if L > 0:
            r = min(L+1,C.degree()+1)
            d = s[N] + sum([(C.list())[i]*s[N-i] for i in range(1,r)])
        if L == 0:
            d = s[N]
        if d == 0:
            m += 1
            N += 1
        if d > 0:
            if 2*L > N:
                C = C - d*b**(-1)*x**m*B
                m += 1
                N += 1
            else:
                T = C
                C = C - d*b**(-1)*x**m*B
                L = N + 1 - L
                m = 1
                b = d
                B = T
                N += 1
    return C
Ejemplo n.º 2
0
    def __init__(self, R, n, q=None):
        """
        TESTS::
        
            sage: HeckeAlgebraSymmetricGroupT(QQ, 3)
            Hecke algebra of the symmetric group of order 3 on the T basis over Univariate Polynomial Ring in q over Rational Field
        
        ::
        
            sage: HeckeAlgebraSymmetricGroupT(QQ, 3, q=1)
            Hecke algebra of the symmetric group of order 3 with q=1 on the T basis over Rational Field
        """
        self.n = n
        self._basis_keys = permutation.Permutations(n)
        self._name = "Hecke algebra of the symmetric group of order %s"%self.n
        self._one = permutation.Permutation(range(1,n+1))

        if q is None:
            q = PolynomialRing(R, 'q').gen()
            R = q.parent()
        else:
            if q not in R:
                raise ValueError, "q must be in R (= %s)"%R
            self._name += " with q=%s"%q

        self._q = q
        
        CombinatorialAlgebra.__init__(self, R)
        # _repr_ customization: output the basis element indexed by [1,2,3] as [1,2,3]
        self.print_options(prefix="")
Ejemplo n.º 3
0
    def _sage_(self):
        """
        EXAMPLES:
            sage: m = lie('[[1,0,3,3],[12,4,-4,7],[-1,9,8,0],[3,-5,-2,9]]') # optional - lie
            sage: m.sage()  # optional - lie
            [ 1  0  3  3]
            [12  4 -4  7]
            [-1  9  8  0]
            [ 3 -5 -2  9]

        """
        t = self.type()
        if t == "grp":
            raise ValueError, "cannot convert Lie groups to native Sage objects"
        elif t == "mat":
            import sage.matrix.constructor

            return sage.matrix.constructor.matrix(eval(str(self).replace("\n", "").strip()))
        elif t == "pol":
            import sage.misc.misc
            from sage.rings.all import PolynomialRing, QQ

            # Figure out the number of variables
            s = str(self)
            open_bracket = s.find("[")
            close_bracket = s.find("]")
            nvars = len(s[open_bracket:close_bracket].split(","))

            # create the polynomial ring
            R = PolynomialRing(QQ, nvars, "x")
            x = R.gens()
            pol = R(0)

            # Split up the polynomials into terms
            terms = []
            for termgrp in s.split(" - "):
                # The first entry in termgrp has
                # a negative coefficient
                termgrp = "-" + termgrp.strip()
                terms += termgrp.split("+")
            # Make sure we don't accidentally add a negative
            # sign to the first monomial
            if s[0] != "-":
                terms[0] = terms[0][1:]

            # go through all the terms in s
            for term in terms:
                xpos = term.find("X")
                coef = eval(term[:xpos].strip())
                exps = eval(term[xpos + 1 :].strip())
                monomial = sage.misc.misc.prod(map(lambda i: x[i] ** exps[i], range(nvars)))
                pol += coef * monomial

            return pol
        elif t == "tex":
            return repr(self)
        elif t == "vid":
            return None
        else:
            return ExpectElement._sage_(self)
Ejemplo n.º 4
0
def compute_tau0(v0,gamma,wD,return_exact = False):
    r'''
    INPUT:

     - v0: F -> its localization at p
     - gamma: the image of wD (the generator for an order of F) under an optimal embedding

    OUTPUT:

     The element tau_0 such that gamma * [tau_0,1] = wD * [tau_0,1]

    '''
    R = PolynomialRing(QQ,names = 'X')
    X = R.gen()
    F = v0.domain()
    Cp = v0.codomain()
    assert wD.minpoly() == gamma.minpoly()
    a,b,c,d = gamma.list()
    tau0_vec = (c*X**2+(d-a)*X-b).roots(F)
    tau0 = v0(tau0_vec[0][0])
    idx = 0
    if c * tau0 + d != v0(wD):
        tau0 = v0(tau0_vec[1][0])
        idx = 1
    return tau0_vec[idx][0] if return_exact == True else tau0
Ejemplo n.º 5
0
    def weil_representation(self) :
        r"""
        OUTPUT:
        
        - A pair of matrices corresponding to T and S.
        """
        disc_bilinear = lambda a, b: (self._dual_basis * vector(QQ, a.lift())) * self._L * (self._dual_basis * vector(QQ, b.lift()))
        disc_quadratic = lambda a: disc_bilinear(a, a) / ZZ(2)
        
        zeta_order = ZZ(lcm([8, 12, prod(self.invariants())] + map(lambda ed: 2 * ed, self.invariants())))
        K = CyclotomicField(zeta_order); zeta = K.gen()

        R = PolynomialRing(K, 'x'); x = R.gen()
#        sqrt2s = (x**2 - 2).factor()
#        if sqrt2s[0][0][0].complex_embedding().real() > 0 :        
#            sqrt2  = sqrt2s[0][0][0]
#        else : 
#            sqrt2  = sqrt2s[0][1]
        Ldet_rts = (x**2 - prod(self.invariants())).factor()
        if Ldet_rts[0][0][0].complex_embedding().real() > 0 :
            Ldet_rt  = Ldet_rts[0][0][0] 
        else :
            Ldet_rt  = Ldet_rts[0][0][0]
                
        Tmat  = diagonal_matrix( K, [zeta**(zeta_order*disc_quadratic(a)) for a in self] )
        Smat = zeta**(zeta_order / 8 * self._L.nrows()) / Ldet_rt  \
               * matrix( K,  [ [ zeta**ZZ(-zeta_order * disc_bilinear(gamma,delta))
                                 for delta in self ]
                               for gamma in self ])
        
        return (Tmat, Smat)
Ejemplo n.º 6
0
Archivo: cm.py Proyecto: mcognetta/sage
def is_cm_j_invariant(j):
    """
    Return whether or not this is a CM `j`-invariant.

    INPUT:

    - ``j`` -- an element of a number field `K`

    OUTPUT:

    A pair (bool, (d,f)) which is either (False, None) if `j` is not a
    CM j-invariant or (True, (d,f)) if `j` is the `j`-invariant of the
    imaginary quadratic order of discriminant `D=df^2` where `d` is
    the associated fundamental discriminant and `f` the index.

    .. note::

       The current implementation makes use of the classification of
       all orders of class number up to 100, and hence will raise an
       error if `j` is an algebraic integer of degree greater than
       this.  It would be possible to implement a more general
       version, using the fact that `d` must be supported on the
       primes dividing the discriminant of the minimal polynomial of
       `j`.

    EXAMPLES::

        sage: from sage.schemes.elliptic_curves.cm import is_cm_j_invariant
        sage: is_cm_j_invariant(0)
        (True, (-3, 1))
        sage: is_cm_j_invariant(8000)
        (True, (-8, 1))

        sage: K.<a> = QuadraticField(5)
        sage: is_cm_j_invariant(282880*a + 632000)
        (True, (-20, 1))
        sage: K.<a> = NumberField(x^3 - 2)
        sage: is_cm_j_invariant(31710790944000*a^2 + 39953093016000*a + 50337742902000)
        (True, (-3, 6))

    TESTS::

        sage: from sage.schemes.elliptic_curves.cm import is_cm_j_invariant
        sage: all([is_cm_j_invariant(j) == (True, (d,f)) for d,f,j in cm_j_invariants_and_orders(QQ)])
        True

    """
    from sage.rings.all import NumberFieldElement
    if not isinstance(j, NumberFieldElement) and not j in QQ:
        raise NotImplementedError("is_cm_j_invariant() is only implemented for number field elements")
    if not j.is_integral():
        return False, None
    jpol = PolynomialRing(QQ,'x')([-j,1]) if j in QQ else j.absolute_minpoly()
    h = jpol.degree()
    if h>100:
        raise NotImplementedError("CM data only available for class numbers up to 100")
    for d,f in cm_orders(h):
        if jpol == hilbert_class_polynomial(d*f**2):
            return True, (d,f)
    return False, None
Ejemplo n.º 7
0
    def _sage_(self):
        """
        EXAMPLES::

            sage: m = lie('[[1,0,3,3],[12,4,-4,7],[-1,9,8,0],[3,-5,-2,9]]') # optional - lie
            sage: m.sage()  # optional - lie
            [ 1  0  3  3]
            [12  4 -4  7]
            [-1  9  8  0]
            [ 3 -5 -2  9]

        """
        t = self.type()
        if t == 'grp':
            raise ValueError("cannot convert Lie groups to native Sage objects")
        elif t == 'mat':
            import sage.matrix.constructor
            return  sage.matrix.constructor.matrix( eval( str(self).replace('\n','').strip())  )
        elif t == 'pol':
            from sage.rings.all import PolynomialRing, QQ

            #Figure out the number of variables
            s = str(self)
            open_bracket = s.find('[')
            close_bracket = s.find(']')
            nvars = len(s[open_bracket:close_bracket].split(','))

            #create the polynomial ring
            R = PolynomialRing(QQ, nvars, 'x')
            x = R.gens()
            pol = R(0)

            #Split up the polynomials into terms
            terms = []
            for termgrp in s.split(' - '):
                #The first entry in termgrp has
                #a negative coefficient
                termgrp = "-"+termgrp.strip()
                terms += termgrp.split('+')
            #Make sure we don't accidentally add a negative
            #sign to the first monomial
            if s[0] != "-":
                terms[0] = terms[0][1:]

            #go through all the terms in s
            for term in terms:
                xpos = term.find('X')
                coef = eval(term[:xpos].strip())
                exps = eval(term[xpos+1:].strip())
                monomial = prod([x[i]**exps[i] for i in range(nvars)])
                pol += coef * monomial

            return pol
        elif t == 'tex':
            return repr(self)
        elif t == 'vid':
            return None
        else:
            return ExpectElement._sage_(self)
Ejemplo n.º 8
0
def eisenstein_basis(N, k, verbose=False):
    r"""
    Find spanning list of 'easy' generators for the subspace of
    `M_k(\Gamma_0(N))` generated by level 1 Eisenstein series and
    their images of even integer weights up to `k`.

    INPUT:
        - N -- positive integer
        - k -- positive integer
        - ``verbose`` -- bool (default: False)

    OUTPUT:
        - list of monomials in images of level 1 Eisenstein series
        - prec of q-expansions needed to determine element of
          `M_k(\Gamma_0(N))`.

    EXAMPLES::

        sage: from psage.modform.rational.special import eisenstein_basis
        sage: eisenstein_basis(5,4)
        ([E4(q^5)^1, E4(q^1)^1, E2^*(q^5)^2], 3)
        sage: eisenstein_basis(11,2,verbose=True)  # warning below because of verbose
        Warning -- not enough series.
        ([E2^*(q^11)^1], 2)
        sage: eisenstein_basis(11,2,verbose=False)
        ([E2^*(q^11)^1], 2)
    """
    assert N > 1
    if k % 2 != 0:
        return []
    # Make list E of Eisenstein series, to enough precision to
    # determine them, until we span space.
    M = ModularForms(N, k)
    prec = M.echelon_basis()[-1].valuation() + 1
    
    gens = eisenstein_gens(N, k, prec)
    R = PolynomialRing(ZZ, len(gens), ['E%sq%s'%(g[1],g[0]) for g in gens])
    z = [(R.gen(i), g[1]) for i, g in enumerate(gens)]
    m = monomials(z, k)
    
    A = QQ**prec
    V = A.zero_subspace()
    E = []
    for i, z in enumerate(m):
        d = z.degrees()
        f = prod(g[2]**d[i] for i, g in enumerate(gens) if d[i])
        v = A(f.padded_list(prec))
        if v not in V:
            V = V + A.span([v])
            w = [(gens[i][0],gens[i][1],d[i]) for i in range(len(d)) if d[i]]
            E.append(EisensteinMonomial(w))
            if V.dimension() == M.dimension():
                 return E, prec

    if verbose: print "Warning -- not enough series."
    return E, prec
Ejemplo n.º 9
0
    def local_coordinates_at_infinity(self, prec = 20, name = 't'):
        """
        For the genus `g` hyperelliptic curve `y^2 = f(x)`, return
        `(x(t), y(t))` such that `(y(t))^2 = f(x(t))`, where `t = x^g/y` is
        the local parameter at infinity

        INPUT:

        - ``prec`` -- desired precision of the local coordinates
        - ``name`` -- generator of the power series ring (default: ``t``)

        OUTPUT:

        `(x(t),y(t))` such that `y(t)^2 = f(x(t))` and `t = x^g/y`
        is the local parameter at infinity

        EXAMPLES::

            sage: R.<x> = QQ['x']
            sage: H = HyperellipticCurve(x^5-5*x^2+1)
            sage: x,y = H.local_coordinates_at_infinity(10)
            sage: x
            t^-2 + 5*t^4 - t^8 - 50*t^10 + O(t^12)
            sage: y
            t^-5 + 10*t - 2*t^5 - 75*t^7 + 50*t^11 + O(t^12)

        ::

            sage: R.<x> = QQ['x']
            sage: H = HyperellipticCurve(x^3-x+1)
            sage: x,y = H.local_coordinates_at_infinity(10)
            sage: x
            t^-2 + t^2 - t^4 - t^6 + 3*t^8 + O(t^12)
            sage: y
            t^-3 + t - t^3 - t^5 + 3*t^7 - 10*t^11 + O(t^12)

        AUTHOR:
            - Jennifer Balakrishnan (2007-12)
        """
        g = self.genus()
        pol = self.hyperelliptic_polynomials()[0]
        K = LaurentSeriesRing(self.base_ring(), name, default_prec=prec+2)
        t = K.gen()
        L = PolynomialRing(self.base_ring(),'x')
        x = L.gen()
        i = 0
        w = (x**g/t)**2-pol
        wprime = w.derivative(x)
        x = t**-2
        for i in range((RR(log(prec+2)/log(2))).ceil()):
            x = x-w(x)/wprime(x)
        y = x**g/t
        return x+O(t**(prec+2)) , y+O(t**(prec+2))
Ejemplo n.º 10
0
    def local_coordinates_at_infinity(self, prec=20, name="t"):
        """
        For the genus g hyperelliptic curve y^2 = f(x), returns (x(t), y(t)) such that
        (y(t))^2 = f(x(t)), where t = x^g/y is the local parameter at infinity

        INPUT:
            - prec: desired precision of the local coordinates
            - name: gen of the power series ring (default: 't')

        OUTPUT:
        (x(t),y(t)) such that y(t)^2 = f(x(t)) and t = x^g/y
        is the local parameter at infinity


        EXAMPLES:
            sage: R.<x> = QQ['x']
            sage: H = HyperellipticCurve(x^5-5*x^2+1)
            sage: x,y = H.local_coordinates_at_infinity(10)
            sage: x
            t^-2 + 5*t^4 - t^8 - 50*t^10 + O(t^12)
            sage: y 
            t^-5 + 10*t - 2*t^5 - 75*t^7 + 50*t^11 + O(t^12)

            sage: R.<x> = QQ['x']
            sage: H = HyperellipticCurve(x^3-x+1)
            sage: x,y = H.local_coordinates_at_infinity(10)
            sage: x
            t^-2 + t^2 - t^4 - t^6 + 3*t^8 + O(t^12)
            sage: y
            t^-3 + t - t^3 - t^5 + 3*t^7 - 10*t^11 + O(t^12)


        AUTHOR:
            - Jennifer Balakrishnan (2007-12)
        """
        g = self.genus()
        pol = self.hyperelliptic_polynomials()[0]
        K = LaurentSeriesRing(self.base_ring(), name)
        t = K.gen()
        K.set_default_prec(prec + 2)
        L = PolynomialRing(self.base_ring(), "x")
        x = L.gen()
        i = 0
        w = (x ** g / t) ** 2 - pol
        wprime = w.derivative(x)
        x = t ** -2
        for i in range((RR(log(prec + 2) / log(2))).ceil()):
            x = x - w(x) / wprime(x)
        y = x ** g / t
        return x + O(t ** (prec + 2)), y + O(t ** (prec + 2))
Ejemplo n.º 11
0
    def tiny_integrals_on_basis(self, P, Q):
        r"""
        Evaluate the integrals `\{\int_P^Q x^i dx/2y \}_{i=0}^{2g-1}`
        by formally integrating a power series in a local parameter `t`.
        `P` and `Q` MUST be in the same residue disc for this result to make sense.

        INPUT:

        - P a point on self
        - Q a point on self (in the same residue disc as P)

        OUTPUT:

        The integrals `\{\int_P^Q x^i dx/2y \}_{i=0}^{2g-1}`

        EXAMPLES::

            sage: K = pAdicField(17, 5)
            sage: E = EllipticCurve(K, [-31/3, -2501/108]) # 11a
            sage: P = E(K(14/3), K(11/2))
            sage: TP = E.teichmuller(P);
            sage: E.tiny_integrals_on_basis(P, TP)
            (17 + 14*17^2 + 17^3 + 8*17^4 + O(17^5), 16*17 + 5*17^2 + 8*17^3 + 14*17^4 + O(17^5))

        ::

            sage: K = pAdicField(11, 5)
            sage: x = polygen(K)
            sage: C = HyperellipticCurve(x^5 + 33/16*x^4 + 3/4*x^3 + 3/8*x^2 - 1/4*x + 1/16)
            sage: P = C.lift_x(11^(-2))
            sage: Q = C.lift_x(3*11^(-2))
            sage: C.tiny_integrals_on_basis(P,Q)
            (3*11^3 + 7*11^4 + 4*11^5 + 7*11^6 + 5*11^7 + O(11^8), 3*11 + 10*11^2 + 8*11^3 + 9*11^4 + 7*11^5 + O(11^6), 4*11^-1 + 2 + 6*11 + 6*11^2 + 7*11^3 + O(11^4), 11^-3 + 6*11^-2 + 2*11^-1 + 2 + O(11^2))


        Note that this fails if the points are not in the same residue disc::

            sage: S = C(0,1/4)
            sage: C.tiny_integrals_on_basis(P,S)
            Traceback (most recent call last):
            ...
            ValueError: (11^-2 + O(11^3) : 11^-5 + 8*11^-2 + O(11^0) : 1 + O(11^5)) and (0 : 3 + 8*11 + 2*11^2 + 8*11^3 + 2*11^4 + O(11^5) : 1 + O(11^5)) are not in the same residue disc

        """
        if P == Q:
            V = VectorSpace(self.base_ring(), 2*self.genus())
            return V(0)
        R = PolynomialRing(self.base_ring(), ['x', 'y'])
        x, y = R.gens()
        return self.tiny_integrals([x**i for i in range(2*self.genus())], P, Q)
Ejemplo n.º 12
0
    def __init__(self, params, asym=False):

        (self.n, self.q, sigma, self.sigma_prime, self.k) = params

        S, x = PolynomialRing(ZZ, 'x').objgen()
        self.R = S.quotient_ring(S.ideal(x**self.n + 1))

        Sq = PolynomialRing(Zmod(self.q), 'x')
        self.Rq = Sq.quotient_ring(Sq.ideal(x**self.n + 1))

        # draw z_is uniformly from Rq and compute its inverse in Rq
        if asym:
            z = [self.Rq.random_element() for i in range(self.k)]
            self.zinv = [z_i**(-1) for z_i in z]
        else: # or do symmetric version
            z = self.Rq.random_element()
            zinv = z**(-1)
            z, self.zinv = zip(*[(z,zinv) for i in range(self.k)])

        # set up some discrete Gaussians
        DGSL_sigma = DGSL(ZZ**self.n, sigma)
        self.D_sigma = lambda: self.Rq(list(DGSL_sigma()))

        # discrete Gaussian in ZZ^n with stddev sigma_prime, yields random level-0 encodings
        DGSL_sigmap_ZZ = DGSL(ZZ**self.n, self.sigma_prime)
        self.D_sigmap_ZZ = lambda: self.Rq(list(DGSL_sigmap_ZZ()))

        # draw g repeatedly from a Gaussian distribution of Z^n (with param sigma)
        # until g^(-1) in QQ[x]/<x^n + 1> is small (< n^2)
        Sk = PolynomialRing(QQ, 'x')
        K = Sk.quotient_ring(Sk.ideal(x**self.n + 1)) 
        while True:
            l = self.D_sigma()
            ginv_K = K(mod_near_poly(l, self.q))**(-1)
            ginv_size = vector(ginv_K).norm()

            if ginv_size < self.n**2:
                g = self.Rq(l)
                self.ginv = g**(-1)
                break

        # discrete Gaussian in I = <g>, yields random encodings of 0
        short_g = vector(ZZ, mod_near_poly(g,self.q))
        DGSL_sigmap_I = DGSL(short_g, self.sigma_prime)
        self.D_sigmap_I = lambda: self.Rq(list(DGSL_sigmap_I()))

        # compute zero-testing parameter p_zt
        # randomly draw h (in Rq) from a discrete Gaussian with param q^(1/2)
        self.h = self.Rq(list(DGSL(ZZ**self.n, round(sqrt(self.q)))()))

        # create p_zt
        self.p_zt = self.ginv * self.h * prod(z)
Ejemplo n.º 13
0
def _check_muqt(mu, q, t, pi=None):
    """
    EXAMPLES::

        sage: from sage.combinat.sf.ns_macdonald import _check_muqt
        sage: P, q, t, n, R, x = _check_muqt([0,0,1],None,None)
        sage: P
        Fraction Field of Multivariate Polynomial Ring in q, t over Rational Field
        sage: q
        q
        sage: t
        t
        sage: n
        Nonattacking fillings of [0, 0, 1]
        sage: R
        Multivariate Polynomial Ring in x0, x1, x2 over Fraction Field of Multivariate Polynomial Ring in q, t over Rational Field
        sage: x
        (x0, x1, x2)

    ::

        sage: q,t = var('q,t')
        sage: P, q, t, n, R, x = _check_muqt([0,0,1],q,None)
        Traceback (most recent call last):
        ...
        ValueError: you must specify either both q and t or neither of them

    ::

        sage: P, q, t, n, R, x = _check_muqt([0,0,1],q,2)
        Traceback (most recent call last):
        ...
        ValueError: the parents of q and t must be the same
    """
    if q is None and t is None:
        P = PolynomialRing(QQ,'q,t').fraction_field()
        q,t = P.gens()
    elif q is not None and t is not None:
        if q.parent() != t.parent():
            raise ValueError("the parents of q and t must be the same")
        P = q.parent()
    else:
        raise ValueError("you must specify either both q and t or neither of them")
    n = NonattackingFillings(mu, pi)
    R = PolynomialRing(P, len(n._shape), 'x')
    x = R.gens()
    return P, q, t, n, R, x
Ejemplo n.º 14
0
    def __init__(self, group, base_ring, red_hom):
        r"""
        Abstract (Hecke) forms ring.

        INPUT:

        - ``group``       - The Hecke triangle group (default: ``HeckeTriangleGroup(3)``)
        - ``base_ring``   - The base_ring (default: ``ZZ``).
        - ``red_hom``     - If True then results of binary operations are considered
                            homogeneous whenever it makes sense (default: False).
                            This is mainly used by the (Hecke) forms.

        OUTPUT:

        The corresponding abstract (Hecke) forms ring.

        EXAMPLES::

            sage: from graded_ring import ModularFormsRing
            sage: MR = ModularFormsRing(group=5, base_ring=ZZ, red_hom=True)
            sage: MR
            ModularFormsRing(n=5) over Integer Ring
            sage: MR.group()
            Hecke triangle group for n = 5
            sage: MR.base_ring()
            Integer Ring
            sage: MR.has_reduce_hom()
            True
            sage: MR.is_homogeneous()
            False
        """

        from graded_ring import canonical_parameters
        (group, base_ring, red_hom) = canonical_parameters(group, base_ring, red_hom)

        if (group == infinity):
            raise NotImplementedError

        #if (not group.is_arithmetic() and base_ring.characteristic()>0):
        #    raise NotImplementedError
        #if (base_ring.characteristic().divides(2*group.n()*(group.n()-2))):
        #    raise NotImplementedError
        if (base_ring.characteristic() > 0):
            raise NotImplementedError
        self._group               = group
        self._red_hom             = red_hom
        self._base_ring           = base_ring
        self._coeff_ring          = FractionField(PolynomialRing(base_ring,'d'))
        self._pol_ring            = PolynomialRing(base_ring,'x,y,z,d')
        self._rat_field           = FractionField(self._pol_ring)

        # default values
        self._weight              = None
        self._ep                  = None
        self._analytic_type       = self.AT(["quasi", "mero"])

        self.default_prec(10)
        self.disp_prec(5)
        self.default_num_prec(53)
Ejemplo n.º 15
0
    def curve_over_ram_extn(self, deg):
        r"""
        Returns self over $\Q_p(p^(1/deg))$

        INPUT:

        - deg: the degree of the ramified extension

        OUTPUT:

        self over $\Q_p(p^(1/deg))$

        EXAMPLES::

            sage: R.<x> = QQ['x']
            sage: H = HyperellipticCurve(x^5-23*x^3+18*x^2+40*x)
            sage: K = Qp(11,5)
            sage: HK = H.change_ring(K)
            sage: HL = HK.curve_over_ram_extn(2)
            sage: HL
            Hyperelliptic Curve over Eisenstein Extension of 11-adic Field with capped relative precision 5 in a defined by (1 + O(11^5))*x^2 + (O(11^6))*x + (10*11 + 10*11^2 + 10*11^3 + 10*11^4 + 10*11^5 + O(11^6)) defined by (1 + O(a^10))*y^2 = (1 + O(a^10))*x^5 + (10 + 8*a^2 + 10*a^4 + 10*a^6 + 10*a^8 + O(a^10))*x^3 + (7 + a^2 + O(a^10))*x^2 + (7 + 3*a^2 + O(a^10))*x

        AUTHOR:

        - Jennifer Balakrishnan

        """
        from sage.schemes.hyperelliptic_curves.constructor import HyperellipticCurve

        K = self.base_ring()
        p = K.prime()
        A = PolynomialRing(QQ, "x")
        x = A.gen()
        J = K.extension(x ** deg - p, names="a")
        pol = self.hyperelliptic_polynomials()[0]
        H = HyperellipticCurve(A(pol))
        HJ = H.change_ring(J)
        self._curve_over_ram_extn = HJ
        self._curve_over_ram_extn._curve_over_Qp = self
        return HJ
Ejemplo n.º 16
0
def ubs(f):
    r"""
    Given a sextic form `f`, return a dictionary of the invariants of Mestre, p 317 [M]_.

    `f` may be homogeneous in two variables or inhomogeneous in one.

    EXAMPLES::

        sage: from sage.schemes.hyperelliptic_curves.invariants import ubs
        sage: x = QQ['x'].0
        sage: ubs(x^6 + 1)
        {'A': 2, 'C': -2/9, 'B': 2/3, 'D': 0, 'f': x^6 + h^6, 'i': 2*x^2*h^2, 'Delta': -2/3*x^2*h^2, 'y1': 0, 'y3': 0, 'y2': 0}

        sage: R.<u, v> = QQ[]
        sage: ubs(u^6 + v^6)
        {'A': 2, 'C': -2/9, 'B': 2/3, 'D': 0, 'f': u^6 + v^6, 'i': 2*u^2*v^2, 'Delta': -2/3*u^2*v^2, 'y1': 0, 'y3': 0, 'y2': 0}

        sage: R.<t> = GF(31)[]
        sage: ubs(t^6 + 2*t^5 + t^2 + 3*t + 1)
        {'A': 0, 'C': -15, 'B': -12, 'D': -15, 'f': t^6 + 2*t^5*h + t^2*h^4 + 3*t*h^5 + h^6, 'i': -4*t^4 + 10*t^3*h + 2*t^2*h^2 - 9*t*h^3 - 7*h^4, 'Delta': -10*t^4 + 12*t^3*h + 7*t^2*h^2 - 5*t*h^3 + 2*h^4, 'y1': 4*t^2 - 10*t*h - 13*h^2, 'y3': 4*t^2 - 4*t*h - 9*h^2, 'y2': 6*t^2 - 4*t*h + 2*h^2}
    """
    ub = Ueberschiebung
    if f.parent().ngens() == 1:
        f = PolynomialRing(f.parent().base_ring(), 1, f.parent().variable_name())(f)
        x1, x2 = f.homogenize().parent().gens()
        f = sum([ f[i]*x1**i*x2**(6-i) for i in range(7) ])
    U = {}
    U['f'] = f
    U['i'] = ub(f, f, 4)
    U['Delta'] = ub(U['i'], U['i'], 2)
    U['y1'] = ub(f, U['i'], 4)
    U['y2'] = ub(U['i'], U['y1'], 2)
    U['y3'] = ub(U['i'], U['y2'], 2)
    U['A'] = ub(f, f, 6)
    U['B'] = ub(U['i'], U['i'], 4)
    U['C'] = ub(U['i'], U['Delta'], 4)
    U['D'] = ub(U['y3'], U['y1'], 2)
    return U
Ejemplo n.º 17
0
 def generator_relations(self, K) :
     """
     An ideal `I` in a polynomial ring `R` over `K`, such that the
     associated ring is `R / I` surjects onto the ring of modular forms
     with coefficients in `K`.
     
     INPUT:
         - `K` -- A ring.
         
     OUTPUT:
         An ideal in a polynomial ring.
     
     TESTS::
         sage: from psage.modform.fourier_expansion_framework.modularforms.modularform_testtype import *
         sage: t = ModularFormTestType_vectorvalued()
         sage: t.generator_relations(QQ)
         Ideal (g1^2 - g2, g1^3 - g3, g1^4 - g4, g1^5 - g5) of Multivariate Polynomial Ring in g1, g2, g3, g4, g5, v1, v2, v3 over Rational Field
     """
     if K.has_coerce_map_from(ZZ) :
         R = PolynomialRing(K, self.non_vector_valued()._generator_names(K) + self._generator_names(K))
         return R.ideal().parent()(self.non_vector_valued().generator_relations(K))
         
     raise NotImplementedError
Ejemplo n.º 18
0
 def generator_relations(self, K) :
     """
     An ideal `I` in a polynomial ring `R` over `K`, such that the
     associated ring is `R / I` surjects onto the ring of modular forms
     with coefficients in `K`.
     
     INPUT:
         - `K` -- A ring.
         
     OUTPUT:
         An ideal in a polynomial ring.
     
     TESTS::
         sage: from psage.modform.fourier_expansion_framework.modularforms.modularform_testtype import *
         sage: t = ModularFormTestType_scalar()
         sage: t.generator_relations(QQ)
         Ideal (g1^2 - g2, g1^3 - g3, g1^4 - g4, g1^5 - g5) of Multivariate Polynomial Ring in g1, g2, g3, g4, g5 over Rational Field
     """
     if K.has_coerce_map_from(ZZ) :
         R = PolynomialRing(K, self._generator_names(K))
         g1 = R.gen(0)
         return R.ideal([g1**i - g for (i,g) in list(enumerate([None] + list(R.gens())))[2:]])
         
     raise NotImplementedError
Ejemplo n.º 19
0
    def coordinate_ring(self):
        """
        Return the coordinate ring of this scheme, if defined.

        EXAMPLES::

            sage: R = AffineSpace(2, GF(9,'alpha'), 'z').coordinate_ring(); R
            Multivariate Polynomial Ring in z0, z1 over Finite Field in alpha of size 3^2
            sage: AffineSpace(3, R, 'x').coordinate_ring()
            Multivariate Polynomial Ring in x0, x1, x2 over Multivariate Polynomial Ring
            in z0, z1 over Finite Field in alpha of size 3^2
        """
        try:
            return self._coordinate_ring
        except AttributeError:
            self._coordinate_ring = PolynomialRing(self.base_ring(),
            self.dimension_relative(), names=self.variable_names())
            return self._coordinate_ring
Ejemplo n.º 20
0
 def _load(self, path, filename):
     print(filename)
     i = 0
     while filename[i].isalpha():
         i += 1
     j = len(filename) - 1
     while filename[j].isalpha() or filename[j] in [".", "_"]:
         j -= 1
     S = sorted([eval(z) for z in filename[i:j + 1].split("-")])
     data = open(path + "/" + filename).read()
     data = data.replace("^", "**")
     x = PolynomialRing(RationalField(), 'x').gen()
     v = eval(data)
     s = tuple(S)
     if s in self.root:
         self.root[s] += v
         self.root[s].sort()
     else:
         self.root[s] = v
Ejemplo n.º 21
0
    def _init(self, path):
        """
        Create the database from scratch from the PARI files on John Jones's
        web page, downloaded (e.g., via wget) to a local directory, which
        is specified as path above.

        INPUT:


        -  ``path`` - (default works on William Stein install.)
           path must be the path to Jones's Number_Fields directory
           http://hobbes.la.asu.edu/Number_Fields These files should have
           been downloaded using wget.


        EXAMPLES: This is how to create the database from scratch, assuming
        that the number fields are in the default directory above: From a
        cold start of Sage::

                sage: J = JonesDatabase()
                sage: J._init()   # not tested
                ...

        This takes about 5 seconds.
        """
        from sage.misc.misc import sage_makedirs
        n = 0
        x = PolynomialRing(RationalField(), 'x').gen()
        self.root = {}
        self.root[tuple([])] = [x - 1]
        if not os.path.exists(path):
            raise IOError("Path %s does not exist." % path)
        for X in os.listdir(path):
            if X[-4:] == "solo":
                Z = path + "/" + X
                print(X)
                for Y in os.listdir(Z):
                    if Y[-3:] == ".gp":
                        self._load(Z, Y)
        sage_makedirs(JONESDATA)
        save(self.root, JONESDATA + "/jones.sobj")
def _check_muqt(mu, q, t, pi=None):
    """
    EXAMPLES::

        sage: from sage.combinat.sf.ns_macdonald import _check_muqt
        sage: P, q, t, n, R, x = _check_muqt([0,0,1],None,None)
        sage: P
        Fraction Field of Multivariate Polynomial Ring in q, t over Rational Field
        sage: q
        q
        sage: t
        t
        sage: n
        Nonattacking fillings of [0, 0, 1]
        sage: R
        Multivariate Polynomial Ring in x0, x1, x2 over Fraction Field of Multivariate Polynomial Ring in q, t over Rational Field
        sage: x
        (x0, x1, x2)

    ::

        sage: q,t = var('q,t')
        sage: P, q, t, n, R, x = _check_muqt([0,0,1],q,None)
        Traceback (most recent call last):
        ...
        ValueError: you must specify either both q and t or neither of them

    ::

        sage: P, q, t, n, R, x = _check_muqt([0,0,1],q,2)
        Traceback (most recent call last):
        ...
        ValueError: the parents of q and t must be the same
    """
    if q is None and t is None:
        P = PolynomialRing(QQ, 'q,t').fraction_field()
        q, t = P.gens()
    elif q is not None and t is not None:
        if q.parent() != t.parent():
            raise ValueError("the parents of q and t must be the same")
        P = q.parent()
    else:
        raise ValueError(
            "you must specify either both q and t or neither of them")
    n = NonattackingFillings(mu, pi)
    R = PolynomialRing(P, len(n._shape), 'x')
    x = R.gens()
    return P, q, t, n, R, x
Ejemplo n.º 23
0
    def satake_polynomial(self):
        r"""
        Return the Satake polynomial of this representation, i.e.~the polynomial whose roots are `\chi_1(p), \chi_2(p)`
        where this representation is `\pi(\chi_1, \chi_2)`. Concretely, this is the polynomial

        .. math::

            X^2 - p^{(j - k + 2)/2} a_p(f) X + p^{j + 1} \varepsilon(p)`.

        An error will be raised if `j \ne k \bmod 2`.

        EXAMPLES::

            sage: LocalComponent(Newform('11a'), 17).satake_polynomial()
            X^2 + 2*X + 17
            sage: LocalComponent(Newform('11a'), 17, twist_factor = -2).satake_polynomial()
            X^2 + 2/17*X + 1/17
        """
        p = self.prime()
        return PolynomialRing(self.coefficient_field(), 'X')([
            self.central_character()(p) * p, -self.newform()[p] *
            p**((self.twist_factor() - self.newform().weight() + 2) / 2), 1
        ])
Ejemplo n.º 24
0
def elkies_first_step(E, l, lam):
    q = E.base_field().order()
    lam = GF(l)(lam)
    Phi = ClassicalModularPolynomialDatabase()[l]
    x = PolynomialRing(E.base_field(), 'x').gen()
    f = Phi(x, E.j_invariant())
    j_1, j_2 = f.roots()[0][0], f.roots()[1][0]
    E1 = elkies_mod_poly(E, j_1, l)
    try:
        I = EllipticCurveIsogeny(E, None, E1, l)
    except:
        I = l_isogeny(E, E1, l)
    r = lam.multiplicative_order()
    k = GF(q ** r)
    ext = extend_field(E, r)
    try:
        P = ext.lift_x(I.kernel_polynomial().any_root(k))
    except:
        return j_2
    if ext(P[0] ** q, P[1] ** q) == Integer(lam) * P:
        return j_1
    else:
        return j_2
Ejemplo n.º 25
0
    def expand(self):
        """
        EXAMPLES::

            sage: X = SchubertPolynomialRing(ZZ)
            sage: X([2,1,3]).expand()
            x0
            sage: map(lambda x: x.expand(), [X(p) for p in Permutations(3)])
            [1, x0 + x1, x0, x0*x1, x0^2, x0^2*x1]

        TESTS:

        Calling .expand() should always return an element of an
        MPolynomialRing

        ::

            sage: X = SchubertPolynomialRing(ZZ)
            sage: f = X([1]); f
            X[1]
            sage: type(f.expand())
            <type 'sage.rings.polynomial.multi_polynomial_libsingular.MPolynomial_libsingular'>
            sage: f.expand()
            1
            sage: f = X([1,2])
            sage: type(f.expand())
            <type 'sage.rings.polynomial.multi_polynomial_libsingular.MPolynomial_libsingular'>
            sage: f = X([1,3,2,4])
            sage: type(f.expand())
            <type 'sage.rings.polynomial.multi_polynomial_libsingular.MPolynomial_libsingular'>
        """
        p = symmetrica.t_SCHUBERT_POLYNOM(self)
        if not is_MPolynomial(p):
            R = PolynomialRing(self.parent().base_ring(), 1, 'x')
            p = R(p)
        return p
Ejemplo n.º 26
0
def differential_operator(f, g, k):
    r"""
    Return the differential operator `(f g)_k` symbolically in the polynomial ring in ``dfdx, dfdy, dgdx, dgdy``.

    This is defined by Mestre on p 315 [MJ1991]_:

    .. MATH::

        (f g)_k = \frac{(m - k)! (n - k)!}{m! n!} \left(
        \frac{\partial f}{\partial x} \frac{\partial g}{\partial y} -
        \frac{\partial f}{\partial y} \frac{\partial g}{\partial x} \right)^k .

    EXAMPLES::

        sage: from sage.schemes.hyperelliptic_curves.invariants import differential_operator
        sage: R.<x, y> = QQ[]
        sage: differential_operator(x, y, 0)
        1
        sage: differential_operator(x, y, 1)
        -dfdy*dgdx + dfdx*dgdy
        sage: differential_operator(x*y, x*y, 2)
        1/4*dfdy^2*dgdx^2 - 1/2*dfdx*dfdy*dgdx*dgdy + 1/4*dfdx^2*dgdy^2
        sage: differential_operator(x^2*y, x*y^2, 2)
        1/36*dfdy^2*dgdx^2 - 1/18*dfdx*dfdy*dgdx*dgdy + 1/36*dfdx^2*dgdy^2
        sage: differential_operator(x^2*y, x*y^2, 4)
        1/576*dfdy^4*dgdx^4 - 1/144*dfdx*dfdy^3*dgdx^3*dgdy + 1/96*dfdx^2*dfdy^2*dgdx^2*dgdy^2 - 1/144*dfdx^3*dfdy*dgdx*dgdy^3 + 1/576*dfdx^4*dgdy^4
    """
    (x, y) = f.parent().gens()
    n = max(ZZ(f.degree()), ZZ(k))
    m = max(ZZ(g.degree()), ZZ(k))
    R, (fx, fy, gx, gy) = PolynomialRing(f.base_ring(), 4,
                                         'dfdx,dfdy,dgdx,dgdy').objgens()
    const = (m - k).factorial() * (n - k).factorial() / (m.factorial() *
                                                         n.factorial())
    U = f.base_ring()(const) * (fx * gy - fy * gx)**k
    return U
Ejemplo n.º 27
0
class FormsRing_abstract(Parent):
    r"""
    Abstract (Hecke) forms ring.

    This should never be called directly. Instead one should
    instantiate one of the derived classes of this class.
    """

    from graded_ring_element import FormsRingElement
    Element = FormsRingElement

    from analytic_type import AnalyticType
    AT = AnalyticType()

    def __init__(self, group, base_ring, red_hom):
        r"""
        Abstract (Hecke) forms ring.

        INPUT:

        - ``group``       - The Hecke triangle group (default: ``HeckeTriangleGroup(3)``)
        - ``base_ring``   - The base_ring (default: ``ZZ``).
        - ``red_hom``     - If True then results of binary operations are considered
                            homogeneous whenever it makes sense (default: False).
                            This is mainly used by the (Hecke) forms.

        OUTPUT:

        The corresponding abstract (Hecke) forms ring.

        EXAMPLES::

            sage: from graded_ring import ModularFormsRing
            sage: MR = ModularFormsRing(group=5, base_ring=ZZ, red_hom=True)
            sage: MR
            ModularFormsRing(n=5) over Integer Ring
            sage: MR.group()
            Hecke triangle group for n = 5
            sage: MR.base_ring()
            Integer Ring
            sage: MR.has_reduce_hom()
            True
            sage: MR.is_homogeneous()
            False
        """

        from graded_ring import canonical_parameters
        (group, base_ring, red_hom) = canonical_parameters(group, base_ring, red_hom)

        if (group == infinity):
            raise NotImplementedError

        #if (not group.is_arithmetic() and base_ring.characteristic()>0):
        #    raise NotImplementedError
        #if (base_ring.characteristic().divides(2*group.n()*(group.n()-2))):
        #    raise NotImplementedError
        if (base_ring.characteristic() > 0):
            raise NotImplementedError
        self._group               = group
        self._red_hom             = red_hom
        self._base_ring           = base_ring
        self._coeff_ring          = FractionField(PolynomialRing(base_ring,'d'))
        self._pol_ring            = PolynomialRing(base_ring,'x,y,z,d')
        self._rat_field           = FractionField(self._pol_ring)

        # default values
        self._weight              = None
        self._ep                  = None
        self._analytic_type       = self.AT(["quasi", "mero"])

        self.default_prec(10)
        self.disp_prec(5)
        self.default_num_prec(53)

        #super(FormsRing_abstract, self).__init__(self.coeff_ring())

    def _repr_(self):
        r"""
        Return the string representation of ``self``.

        EXAMPLES::

            sage: from graded_ring import QModularFormsRing
            sage: QModularFormsRing(group=4)
            QuasiModularFormsRing(n=4) over Integer Ring
        """

        return "{}FormsRing(n={}) over {}".format(self._analytic_type.analytic_space_name(), self._group.n(), self._base_ring)

    def _latex_(self):
        r"""
        Return the LaTeX representation of ``self``.

        EXAMPLES::

            sage: from graded_ring import QWeakModularFormsRing
            sage: latex(QWeakModularFormsRing())
            \mathcal{ QM^! }_{n=3}(\Bold{Z})
        """

        from sage.misc.latex import latex
        return "\\mathcal{{ {} }}_{{n={}}}({})".format(self._analytic_type.latex_space_name(), self._group.n(), latex(self._base_ring))

    def _element_constructor_(self, x):
        r"""
        Return ``x`` coerced/converted into this forms ring.

        EXAMPLES::

            sage: from graded_ring import ModularFormsRing
            sage: MR = ModularFormsRing()
            sage: (x,y,z,d) = MR.pol_ring().gens()

            sage: MR(x^3)
            f_rho^3

            sage: el = MR.Delta().full_reduce()
            sage: MR(el)
            f_rho^3*d - f_i^2*d
            sage: el.parent() == MR
            False
            sage: MR(el).parent() == MR
            True
        """

        from graded_ring_element import FormsRingElement
        if isinstance(x, FormsRingElement):
            x = self._rat_field(x._rat)
        else:
            x = self._rat_field(x)
        return self.element_class(self, x)

    def _coerce_map_from_(self, S):
        r"""
        Return whether or not there exists a coercion from ``S`` to ``self``.

        EXAMPLES::

            sage: from graded_ring import QWeakModularFormsRing, ModularFormsRing, CuspFormsRing
            sage: MR1 = QWeakModularFormsRing(base_ring=CC)
            sage: MR2 = ModularFormsRing()
            sage: MR3 = CuspFormsRing()
            sage: MR3.has_coerce_map_from(MR2)
            False
            sage: MR1.has_coerce_map_from(MR2)
            True
            sage: MR2.has_coerce_map_from(MR3)
            True
            sage: MR3.has_coerce_map_from(ZZ)
            False
            sage: MR1.has_coerce_map_from(ZZ)
            True

            sage: from space import ModularForms, CuspForms
            sage: MF2 = ModularForms(k=6, ep=-1)
            sage: MF3 = CuspForms(k=12, ep=1)
            sage: MR1.has_coerce_map_from(MF2)
            True
            sage: MR2.has_coerce_map_from(MF3)
            True
        """

        from space import FormsSpace_abstract
        if (    isinstance(S, FormsRing_abstract)\
            and self._group         == S._group\
            and self._analytic_type >= S._analytic_type\
            and self.base_ring().has_coerce_map_from(S.base_ring()) ):
                return True
        # TODO: This case never occurs: remove it?
        elif isinstance(S, FormsSpace_abstract):
            return self._coerce_map_from_(S.graded_ring())
        elif (self.AT("holo") <= self._analytic_type) and (self.coeff_ring().has_coerce_map_from(S)):
            return True
        else:
            return False

    def _an_element_(self):
        r"""
        Return an element of ``self``.

        EXAMPLES::

            sage: from graded_ring import CuspFormsRing
            sage: from space import WeakModularForms
            sage: CuspFormsRing().an_element()
            f_rho^3*d - f_i^2*d
            sage: CuspFormsRing().an_element() == CuspFormsRing().Delta()
            True
            sage: WeakModularForms().an_element()
            O(q^5)
            sage: WeakModularForms().an_element() == WeakModularForms().zero()
            True
        """

        return self(self.Delta())

    def default_prec(self, prec = None):
        r"""
        Set the default precision ``prec`` for the Fourier expansion.
        If ``prec=None`` (default) then the current default precision is returned instead.

        Note: This is also used as the default precision for
        the Fourier expansion when evaluating forms.

        EXAMPLES::

            sage: from graded_ring import ModularFormsRing
            sage: from space import ModularForms
            sage: MR = ModularFormsRing()
            sage: MR.default_prec(3)
            sage: MR.default_prec()
            3
            sage: MR.Delta().q_expansion_fixed_d()
            q - 24*q^2 + O(q^3)
            sage: MF = ModularForms(k=4)
            sage: MF.default_prec(2)
            sage: MF.E4()
            1 + 240*q + O(q^2)
            sage: MF.default_prec()
            2
        """

        if (prec is not None):
            self._prec = ZZ(prec)
        else:
            return self._prec

    def disp_prec(self, prec = None):
        r"""
        Set the maximal display precision to ``prec``.
        If ``prec="max"`` the precision is set to the default precision.
        If ``prec=None`` (default) then the current display precision is returned instead.

        Note: This is used for displaying/representing (elements of)
        ``self`` as Fourier expansions.

        EXAMPLES::

            sage: from space import ModularForms
            sage: MF = ModularForms(k=4)
            sage: MF.default_prec(5)
            sage: MF.disp_prec(3)
            sage: MF.disp_prec()
            3
            sage: MF.E4()
            1 + 240*q + 2160*q^2 + O(q^3)
            sage: MF.disp_prec("max")
            sage: MF.E4()
            1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + O(q^5)
        """

        if (prec == "max"):
            self._disp_prec = self._prec;
        elif (prec is not None):
            self._disp_prec = ZZ(prec)
        else:
            return self._disp_prec

    def default_num_prec(self, prec = None):
        r"""
        Set the default numerical precision to ``prec`` (default: ``53``).
        If ``prec=None`` (default) the current default numerical
        precision is returned instead.

        EXAMPLES::

            sage: from space import ModularForms
            sage: MF = ModularForms(k=6)
            sage: MF.default_prec(20)
            sage: MF.default_num_prec(10)
            sage: MF.default_num_prec()
            10
            sage: E6 = MF.E6()
            sage: E6(i)                                   # rel tol 1e-4
            -0.0020
            sage: MF.default_num_prec(100)
            sage: E6(i)                                   # rel tol 1e-25
            0.00000000000000000000000000000

            sage: MF = ModularForms(group=5, k=4/3)
            sage: F_rho = MF.F_rho()
            sage: F_rho.q_expansion(prec=2)[1]
            7/(100*d)
            sage: MF.default_num_prec(10)
            sage: F_rho.q_expansion_fixed_d(prec=2)[1]    # rel tol 1e-1
            9.9
            sage: MF.default_num_prec(100)
            sage: F_rho.q_expansion_fixed_d(prec=2)[1]    # rel tol 1e-25
            9.9259324351079591527601778294
        """

        if (prec is not None):
            self._num_prec = ZZ(prec)
        else:
            return self._num_prec

    def change_ring(self, new_base_ring):
        r"""
        Return the same space as ``self`` but over a new base ring ``new_base_ring``.

        EXAMPLES::

            sage: from graded_ring import ModularFormsRing
            sage: ModularFormsRing().change_ring(CC)
            ModularFormsRing(n=3) over Complex Field with 53 bits of precision
        """

        return self.__class__.__base__(self._group, new_base_ring, self._red_hom)

    def graded_ring(self):
        r"""
        Return the graded ring containing ``self``.

        EXAMPLES::

            sage: from graded_ring import ModularFormsRing, CuspFormsRing
            sage: from space import CuspForms

            sage: MR = ModularFormsRing(group=5)
            sage: MR.graded_ring() == MR
            True

            sage: CF=CuspForms(k=12)
            sage: CF.graded_ring() == CuspFormsRing()
            False
            sage: CF.graded_ring() == CuspFormsRing(red_hom=True)
            True

            sage: CF.subspace([CF.Delta()]).graded_ring() == CuspFormsRing(red_hom=True)
            True
        """

        return self.extend_type(ring=True)

    def extend_type(self, analytic_type=None, ring=False):
        r"""
        Return a new space which contains (elements of) ``self`` with the analytic type
        of ``self`` extended by ``analytic_type``, possibly extended to a graded ring
        in case ``ring`` is ``True``.

        INPUT:

        - ``analytic_type``   - An ``AnalyticType`` or something which coerces into it (default: ``None``).
        - ``ring``            - Whether to extend to a graded ring (default: ``False``).

        OUTPUT:

        The new extended space.

        EXAMPLES::

            sage: from graded_ring import ModularFormsRing
            sage: from space import CuspForms

            sage: MR = ModularFormsRing(group=5)
            sage: MR.extend_type(["quasi", "weak"])
            QuasiWeakModularFormsRing(n=5) over Integer Ring

            sage: CF=CuspForms(k=12)
            sage: CF.extend_type("holo")
            ModularForms(n=3, k=12, ep=1) over Integer Ring
            sage: CF.extend_type("quasi", ring=True)
            QuasiCuspFormsRing(n=3) over Integer Ring

            sage: CF.subspace([CF.Delta()]).extend_type()
            CuspForms(n=3, k=12, ep=1) over Integer Ring
        """

        if analytic_type == None:
            analytic_type = self._analytic_type
        else:
            analytic_type = self._analytic_type.extend_by(analytic_type)

        if (ring or not self.is_homogeneous()):
            return FormsRing(analytic_type, group=self.group(), base_ring=self.base_ring(), red_hom=self.has_reduce_hom())
        else:
            return FormsSpace(analytic_type, group=self.group(), base_ring=self.base_ring(), k=self.weight(), ep=self.ep())

    def reduce_type(self, analytic_type=None, degree=None):
        r"""
        Return a new space with analytic properties shared by both ``self`` and ``analytic_type``,
        possibly reduced to its homogeneous space of the given ``degree`` (if ``degree`` is set).
        Elements of the new space are contained in ``self``.

        INPUT:

        - ``analytic_type``   - An ``AnalyticType`` or something which coerces into it (default: ``None``).
        - ``degree``          - ``None`` (default) or the degree of the homogeneous component to which
                                ``self`` should be reduced.

        OUTPUT:

        The new reduced space.

        EXAMPLES::

            sage: from graded_ring import QModularFormsRing
            sage: from space import QModularForms

            sage: MR = QModularFormsRing()
            sage: MR.reduce_type(["quasi", "cusp"])
            QuasiCuspFormsRing(n=3) over Integer Ring

            sage: MR.reduce_type("cusp", degree=(12,1))
            CuspForms(n=3, k=12, ep=1) over Integer Ring

            sage: MF=QModularForms(k=6)
            sage: MF.reduce_type("holo")
            ModularForms(n=3, k=6, ep=-1) over Integer Ring

            sage: MF.reduce_type([])
            ZeroForms(n=3, k=6, ep=-1) over Integer Ring
        """

        if analytic_type == None:
            analytic_type = self._analytic_type
        else:
            analytic_type = self._analytic_type.reduce_to(analytic_type)

        if (degree == None and not self.is_homogeneous()):
            return FormsRing(analytic_type, group=self.group(), base_ring=self.base_ring(), red_hom=self.has_reduce_hom())
        elif (degree == None):
            return FormsSpace(analytic_type, group=self.group(), base_ring=self.base_ring(), k=self.weight(), ep=self.ep())
        else:
            (weight, ep) = degree
            if (self.is_homogeneous() and (weight != self.weight() or ep!=self.ep())):
                analytic_type = self._analytic_type.reduce_to([])
            return FormsSpace(analytic_type, group=self.group(), base_ring=self.base_ring(), k=weight, ep=ep)

    def construction(self):
        r"""
        Return a functor that constructs ``self`` (used by the coercion machinery).

        EXAMPLES::

        sage: from graded_ring import ModularFormsRing
        sage: ModularFormsRing().construction()
        (ModularFormsRingFunctor(n=3), BaseFacade(Integer Ring))
        """

        from functors import FormsRingFunctor, BaseFacade
        return FormsRingFunctor(self._analytic_type, self._group, self._red_hom), BaseFacade(self._base_ring)

    @cached_method
    def group(self):
        r"""
        Return the (Hecke triangle) group of ``self``.

        EXAMPLES::

        sage: from graded_ring import ModularFormsRing
        sage: MR = ModularFormsRing(group=7)
        sage: MR.group()
        Hecke triangle group for n = 7

        sage: from space import CuspForms
        sage: CF = CuspForms(group=7, k=4/5)
        sage: CF.group()
        Hecke triangle group for n = 7
        """

        return self._group

    @cached_method
    def hecke_n(self):
        r"""
        Return the parameter ``n`` of the
        (Hecke triangle) group of ``self``.

        EXAMPLES::

        sage: from graded_ring import ModularFormsRing
        sage: MR = ModularFormsRing(group=7)
        sage: MR.hecke_n()
        7

        sage: from space import CuspForms
        sage: CF = CuspForms(group=7, k=4/5)
        sage: CF.hecke_n()
        7
        """

        return self._group.n()

    @cached_method
    def base_ring(self):
        r"""
        Return base ring of ``self``.

        EXAMPLES::

            sage: from graded_ring import ModularFormsRing
            sage: ModularFormsRing().base_ring()
            Integer Ring

            sage: from space import CuspForms
            sage: CuspForms(k=12, base_ring=AA).base_ring()
            Algebraic Real Field
        """

        return self._base_ring

    @cached_method
    def coeff_ring(self):
        r"""
        Return coefficient ring of ``self``.

        EXAMPLES::

            sage: from graded_ring import ModularFormsRing
            sage: ModularFormsRing().coeff_ring()
            Fraction Field of Univariate Polynomial Ring in d over Integer Ring

            sage: from space import CuspForms
            sage: CuspForms(k=12, base_ring=AA).coeff_ring()
            Fraction Field of Univariate Polynomial Ring in d over Algebraic Real Field
        """

        return self._coeff_ring

    @cached_method
    def pol_ring(self):
        r"""
        Return the underlying polynomial ring used
        by ``self``.

        EXAMPLES::

            sage: from graded_ring import ModularFormsRing
            sage: ModularFormsRing().pol_ring()
            Multivariate Polynomial Ring in x, y, z, d over Integer Ring

            sage: from space import CuspForms
            sage: CuspForms(k=12, base_ring=AA).pol_ring()
            Multivariate Polynomial Ring in x, y, z, d over Algebraic Real Field
        """

        return self._pol_ring

    @cached_method
    def rat_field(self):
        r"""
        Return the underlying rational field used by
        ``self`` to construct/represent elements.

        EXAMPLES::

            sage: from graded_ring import ModularFormsRing
            sage: ModularFormsRing().rat_field()
            Fraction Field of Multivariate Polynomial Ring in x, y, z, d over Integer Ring

            sage: from space import CuspForms
            sage: CuspForms(k=12, base_ring=AA).rat_field()
            Fraction Field of Multivariate Polynomial Ring in x, y, z, d over Algebraic Real Field
        """

        return self._rat_field

    @cached_method
    def diff_alg(self):
        r"""
        Return the algebra of differential operators
        (over QQ) which is used on rational functions
        representing elements of ``self``.

        EXAMPLES::

            sage: from graded_ring import ModularFormsRing
            sage: ModularFormsRing().diff_alg()
            Noncommutative Multivariate Polynomial Ring in X, Y, Z, dX, dY, dZ over Rational Field, nc-relations: {dY*Y: Y*dY + 1, dZ*Z: Z*dZ + 1, dX*X: X*dX + 1}

            sage: from space import CuspForms
            sage: CuspForms(k=12, base_ring=AA).diff_alg()
            Noncommutative Multivariate Polynomial Ring in X, Y, Z, dX, dY, dZ over Rational Field, nc-relations: {dY*Y: Y*dY + 1, dZ*Z: Z*dZ + 1, dX*X: X*dX + 1}
        """

        # We only use two operators for now which do not involve 'd', so for performance
        # reason we choose FractionField(base_ring) instead of self.coeff_ring().
        free_alg         = FreeAlgebra(FractionField(ZZ),6,'X,Y,Z,dX,dY,dZ')
        (X,Y,Z,dX,dY,dZ) = free_alg.gens()
        diff_alg         = free_alg.g_algebra({dX*X:1+X*dX,dY*Y:1+Y*dY,dZ*Z:1+Z*dZ})
        
        return diff_alg

    @cached_method
    def _derivative_op(self):
        r"""
        Return the differential operator in ``self.diff_alg()``
        corresponding to the derivative of forms.

        EXAMPLES::

            sage: from graded_ring import ModularFormsRing
            sage: ModularFormsRing(group=7)._derivative_op()
            -1/2*X^6*dY - 5/28*X^5*dZ + 1/7*X*Z*dX + 1/2*Y*Z*dY + 5/28*Z^2*dZ - 1/7*Y*dX
        """

        (X,Y,Z,dX,dY,dZ) = self.diff_alg().gens()
        return   1/self._group.n() * (X*Z-Y)*dX\
               + ZZ(1)/ZZ(2) * (Y*Z-X**(self._group.n()-1))*dY\
               + (self._group.n()-2) / (4*self._group.n()) * (Z**2-X**(self._group.n()-2))*dZ

    @cached_method
    def _serre_derivative_op(self):
        r"""
        Return the differential operator in ``self.diff_alg()``
        corresponding to the serre derivative of forms.

        EXAMPLES::

            sage: from graded_ring import ModularFormsRing
            sage: ModularFormsRing(group=8)._serre_derivative_op()
            -1/2*X^7*dY - 3/16*X^6*dZ - 3/16*Z^2*dZ - 1/8*Y*dX
        """

        (X,Y,Z,dX,dY,dZ) = self.diff_alg().gens()
        return - 1/self._group.n() * Y*dX\
               - ZZ(1)/ZZ(2) * X**(self._group.n()-1)*dY\
               - (self._group.n()-2) / (4*self._group.n()) * (Z**2+X**(self._group.n()-2))*dZ

    @cached_method
    def has_reduce_hom(self):
        r"""
        Return whether the method ``reduce`` should reduce
        homogeneous elements to the corresponding homogeneous space.

        This is mainly used by binary operations on homogeneous
        spaces which temporarily produce an element of ``self``
        but want to consider it as a homogeneous element
        (also see ``reduce``).

        EXAMPLES::

            sage: from graded_ring import ModularFormsRing
            sage: ModularFormsRing().has_reduce_hom()
            False
            sage: ModularFormsRing(red_hom=True).has_reduce_hom()
            True

            sage: from space import ModularForms
            sage: ModularForms(k=6).has_reduce_hom()
            True
            sage: ModularForms(k=6).graded_ring().has_reduce_hom()
            True
        """

        return self._red_hom

    def is_homogeneous(self):
        r"""
        Return whether ``self`` is homogeneous component.

        EXAMPLES::

            sage: from graded_ring import ModularFormsRing
            sage: ModularFormsRing().is_homogeneous()
            False

            sage: from space import ModularForms
            sage: ModularForms(k=6).is_homogeneous()
            True
        """

        return self._weight != None

    def is_modular(self):
        r"""
        Return whether ``self`` only contains modular elements.

        EXAMPLES::

            sage: from graded_ring import QWeakModularFormsRing, CuspFormsRing
            sage: QWeakModularFormsRing().is_modular()
            False
            sage: CuspFormsRing(group=7).is_modular()
            True

            sage: from space import QWeakModularForms, CuspForms
            sage: QWeakModularForms(k=10).is_modular()
            False
            sage: CuspForms(group=7, k=12, base_ring=AA).is_modular()
            True
        """

        return not (self.AT("quasi") <= self._analytic_type)

    def is_weakly_holomorphic(self):
        r"""
        Return whether ``self`` only contains weakly
        holomorphic modular elements.

        EXAMPLES::

            sage: from graded_ring import QMModularFormsRing, QWeakModularFormsRing, CuspFormsRing
            sage: QMModularFormsRing().is_weakly_holomorphic()
            False
            sage: QWeakModularFormsRing().is_weakly_holomorphic()
            True

            sage: from space import MModularForms, CuspForms
            sage: MModularForms(k=10).is_weakly_holomorphic()
            False
            sage: CuspForms(group=7, k=12, base_ring=AA).is_weakly_holomorphic()
            True
        """

        return (self.AT("weak", "quasi") >= self._analytic_type)

    def is_holomorphic(self):
        r"""
        Return whether ``self`` only contains holomorphic
        modular elements.

        EXAMPLES::

            sage: from graded_ring import QWeakModularFormsRing, QModularFormsRing
            sage: QWeakModularFormsRing().is_holomorphic()
            False
            sage: QModularFormsRing().is_holomorphic()
            True

            sage: from space import WeakModularForms, CuspForms
            sage: WeakModularForms(k=10).is_holomorphic()
            False
            sage: CuspForms(group=7, k=12, base_ring=AA).is_holomorphic()
            True
        """

        return (self.AT("holo", "quasi") >= self._analytic_type)

    def is_cuspidal(self):
        r"""
        Return whether ``self`` only contains cuspidal elements.

        EXAMPLES::

            sage: from graded_ring import QModularFormsRing, QCuspFormsRing
            sage: QModularFormsRing().is_cuspidal()
            False
            sage: QCuspFormsRing().is_cuspidal()
            True

            sage: from space import ModularForms, QCuspForms
            sage: ModularForms(k=12).is_cuspidal()
            False
            sage: QCuspForms(k=12).is_cuspidal()
            True
        """

        return (self.AT("cusp", "quasi") >= self._analytic_type)

    def is_zerospace(self):
        r"""
        Return whether ``self`` is the (0-dimensional) zero space.

        EXAMPLES::

            sage: from graded_ring import ModularFormsRing
            sage: ModularFormsRing().is_zerospace()
            False

            sage: from space import ModularForms, CuspForms
            sage: ModularForms(k=12).is_zerospace()
            False
            sage: CuspForms(k=12).reduce_type([]).is_zerospace()
            True
        """

        return (self.AT(["quasi"]) >= self._analytic_type)

    def analytic_type(self):
        r"""
        Return the analytic type of ``self``.

        EXAMPLES::

            sage: from graded_ring import QMModularFormsRing, QWeakModularFormsRing
            sage: QMModularFormsRing().analytic_type()
            quasi meromorphic modular
            sage: QWeakModularFormsRing().analytic_type()
            quasi weakly holomorphic modular

            sage: from space import MModularForms, CuspForms
            sage: MModularForms(k=10).analytic_type()
            meromorphic modular
            sage: CuspForms(group=7, k=12, base_ring=AA).analytic_type()
            cuspidal
        """

        return self._analytic_type

    def homogeneous_space(self, k, ep):
        r"""
        Return the homogeneous component of degree (``k``, ``e``) of ``self``.

        EXAMPLES::

            sage: from graded_ring import QMModularFormsRing, QWeakModularFormsRing
            sage: QMModularFormsRing(group=7).homogeneous_space(k=2, ep=-1)
            QuasiMeromorphicModularForms(n=7, k=2, ep=-1) over Integer Ring
        """

        return self.reduce_type(degree = (k,ep))

    @cached_method
    def J_inv(self):
        r"""
        Return the J-invariant (Hauptmodul) of the group of ``self``.
        It is normalized such that ``J_inv(infinity) = infinity``,
        it has real Fourier coefficients starting with ``d > 0`` and ``J_inv(i) = 1``

        It lies in a (weak) extension of the graded ring of ``self``.
        In case ``has_reduce_hom`` is ``True`` it is given as an element of
        the corresponding homogeneous space.

        EXAMPLES::

            sage: from graded_ring import QMModularFormsRing, WeakModularFormsRing, CuspFormsRing
            sage: MR = WeakModularFormsRing(group=7)
            sage: J_inv = MR.J_inv()
            sage: J_inv in MR
            True
            sage: CuspFormsRing(group=7).J_inv() == J_inv
            True
            sage: J_inv
            f_rho^7/(f_rho^7 - f_i^2)
            sage: QMModularFormsRing(group=7).J_inv() == QMModularFormsRing(group=7)(J_inv)
            True

            sage: from space import WeakModularForms, CuspForms
            sage: MF = WeakModularForms(group=5, k=0)
            sage: J_inv = MF.J_inv()
            sage: J_inv in MF
            True
            sage: WeakModularFormsRing(group=5, red_hom=True).J_inv() == J_inv
            True
            sage: CuspForms(group=5, k=12).J_inv() == J_inv
            True
            sage: MF.disp_prec(3)
            sage: J_inv
            d*q^-1 + 79/200 + 42877/(640000*d)*q + 12957/(2000000*d^2)*q^2 + O(q^3)

            sage: WeakModularForms().J_inv()
            1/1728*q^-1 + 31/72 + 1823/16*q + 335840/27*q^2 + 16005555/32*q^3 + 11716352*q^4 + O(q^5)
        """

        (x,y,z,d) = self._pol_ring.gens()
        return self.extend_type("weak", ring=True)(x**self._group.n()/(x**self._group.n()-y**2)).reduce()

    @cached_method
    def j_inv(self):
        r"""
        Return the j-invariant (Hauptmodul) of the group of ``self``.
        It is normalized such that ``j_inv(infinity) = infinity``,
        and such that it has real Fourier coefficients starting with ``1``.

        It lies in a (weak) extension of the graded ring of ``self``.
        In case ``has_reduce_hom`` is ``True`` it is given as an element of
        the corresponding homogeneous space.

        EXAMPLES::

            sage: from graded_ring import QMModularFormsRing, WeakModularFormsRing, CuspFormsRing
            sage: MR = WeakModularFormsRing(group=7)
            sage: j_inv = MR.j_inv()
            sage: j_inv in MR
            True
            sage: CuspFormsRing(group=7).j_inv() == j_inv
            True
            sage: j_inv
            f_rho^7/(f_rho^7*d - f_i^2*d)
            sage: QMModularFormsRing(group=7).j_inv() == QMModularFormsRing(group=7)(j_inv)
            True

            sage: from space import WeakModularForms, CuspForms
            sage: MF = WeakModularForms(group=5, k=0)
            sage: j_inv = MF.j_inv()
            sage: j_inv in MF
            True
            sage: WeakModularFormsRing(group=5, red_hom=True).j_inv() == j_inv
            True
            sage: CuspForms(group=5, k=12).j_inv() == j_inv
            True
            sage: MF.disp_prec(3)
            sage: j_inv
            q^-1 + 79/(200*d) + 42877/(640000*d^2)*q + 12957/(2000000*d^3)*q^2 + O(q^3)

            sage: WeakModularForms().j_inv()
            q^-1 + 744 + 196884*q + 21493760*q^2 + 864299970*q^3 + 20245856256*q^4 + O(q^5)
        """

        (x,y,z,d) = self._pol_ring.gens()
        return self.extend_type("weak", ring=True)(1/d*x**self._group.n()/(x**self._group.n()-y**2)).reduce()

    @cached_method
    def F_rho(self):
        r"""
        Return the generator ``F_rho`` of the graded ring of ``self``.
        Up to the group action ``F_rho`` has exactly one simple zero at ``rho``. ``F_rho`` is
        normalized such that its first nontrivial Fourier coefficient is ``1``.

        The polynomial variable ``x`` exactly corresponds to ``F_rho``.

        It lies in a (cuspidal) extension of the graded ring of ``self``.
        In case ``has_reduce_hom`` is ``True`` it is given as an element of
        the corresponding homogeneous space.

        EXAMPLES::

            sage: from graded_ring import QMModularFormsRing, ModularFormsRing, CuspFormsRing
            sage: MR = ModularFormsRing(group=7)
            sage: F_rho = MR.F_rho()
            sage: F_rho in MR
            True
            sage: CuspFormsRing(group=7).F_rho() == F_rho
            True
            sage: F_rho
            f_rho
            sage: QMModularFormsRing(group=7).F_rho() == QMModularFormsRing(group=7)(F_rho)
            True

            sage: from space import ModularForms, CuspForms
            sage: MF = ModularForms(group=5, k=4/3)
            sage: F_rho = MF.F_rho()
            sage: F_rho in MF
            True
            sage: ModularFormsRing(group=5, red_hom=True).F_rho() == F_rho
            True
            sage: CuspForms(group=5, k=12).F_rho() == F_rho
            True
            sage: MF.disp_prec(3)
            sage: F_rho
            1 + 7/(100*d)*q + 21/(160000*d^2)*q^2 + O(q^3)

            sage: ModularForms(k=4).F_rho() == ModularForms(k=4).E4()
            True
            sage: ModularForms(k=4).F_rho()
            1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + O(q^5)
        """

        (x,y,z,d) = self._pol_ring.gens()
        return self.extend_type("holo", ring=True)(x).reduce()

    @cached_method
    def F_i(self):
        r"""
        Return the generator ``F_i`` of the graded ring of ``self``.
        Up to the group action ``F_i`` has exactly one simple zero at ``i``. ``F_i`` is
        normalized such that its first nontrivial Fourier coefficient is ``1``.

        The polynomial variable ``y`` exactly corresponds to ``F_i``.

        It lies in a (holomorphic) extension of the graded ring of ``self``.
        In case ``has_reduce_hom`` is ``True`` it is given as an element of
        the corresponding homogeneous space.

        EXAMPLES::

            sage: from graded_ring import QMModularFormsRing, ModularFormsRing, CuspFormsRing
            sage: MR = ModularFormsRing(group=7)
            sage: F_i = MR.F_i()
            sage: F_i in MR
            True
            sage: CuspFormsRing(group=7).F_i() == F_i
            True
            sage: F_i
            f_i
            sage: QMModularFormsRing(group=7).F_i() == QMModularFormsRing(group=7)(F_i)
            True

            sage: from space import ModularForms, CuspForms
            sage: MF = ModularForms(group=5, k=10/3)
            sage: F_i = MF.F_i()
            sage: F_i in MF
            True
            sage: ModularFormsRing(group=5, red_hom=True).F_i() == F_i
            True
            sage: CuspForms(group=5, k=12).F_i() == F_i
            True
            sage: MF.disp_prec(3)
            sage: F_i
            1 - 13/(40*d)*q - 351/(64000*d^2)*q^2 + O(q^3)

            sage: ModularForms(k=6).F_i() == ModularForms(k=4).E6()
            True
            sage: ModularForms(k=6).F_i()
            1 - 504*q - 16632*q^2 - 122976*q^3 - 532728*q^4 + O(q^5)
        """

        (x,y,z,d) = self._pol_ring.gens()
        return self.extend_type("holo", ring=True)(y).reduce()

    @cached_method
    def F_inf(self):
        r"""
        Return the first nontrivial cusp form ``F_inf`` of the graded ring of ``self``.
        Up to the group action ``F_inf`` has exactly one simple zero at ``infinity``.
        ``F_inf`` is normalized such that its first nontrivial Fourier coefficient is ``1``.

        It lies in a (holomorphic) extension of the graded ring of ``self``.
        In case ``has_reduce_hom`` is ``True`` it is given as an element of
        the corresponding homogeneous space.

        EXAMPLES::

            sage: from graded_ring import QMModularFormsRing, CuspFormsRing
            sage: MR = CuspFormsRing(group=7)
            sage: F_inf = MR.F_inf()
            sage: F_inf in MR
            True
            sage: F_inf
            f_rho^7*d - f_i^2*d
            sage: QMModularFormsRing(group=7).F_inf() == QMModularFormsRing(group=7)(F_inf)
            True

            sage: from space import CuspForms
            sage: MF = CuspForms(group=5, k=20/3)
            sage: F_inf = MF.F_inf()
            sage: F_inf in MF
            True
            sage: CuspFormsRing(group=5, red_hom=True).F_inf() == F_inf
            True
            sage: CuspForms(group=5, k=0).F_inf() == F_inf
            True
            sage: MF.disp_prec(3)
            sage: F_inf
            q - 9/(200*d)*q^2 + O(q^3)

            sage: CuspForms(k=12).F_inf() == CuspForms(k=12).Delta()
            True
            sage: CuspForms(k=12).F_inf()
            q - 24*q^2 + 252*q^3 - 1472*q^4 + O(q^5)
        """

        (x,y,z,d) = self._pol_ring.gens()
        return self.extend_type("cusp", ring=True)(d*(x**self._group.n()-y**2)).reduce()

    @cached_method
    def G_inv(self):
        r"""
        If ``2`` divides ``n``: Return the G-invariant of the group of ``self``.

        The G-invariant is analogous to the G-invariant but has multiplier ``-1``.
        I.e. ``G_inv(-1/t) = -G_inv(t)``. It is a holomorphic square root
        of ``J_inv*(J_inv-1)`` with real Fourier coefficients.

        If ``2`` does not divide ``n`` the function doesn't exist and an exception is raised.

        It lies in a (weak) extension of the graded ring of ``self``.
        In case ``has_reduce_hom`` is ``True`` it is given as an element of
        the corresponding homogeneous space.

        EXAMPLES::

            sage: from graded_ring import QMModularFormsRing, WeakModularFormsRing, CuspFormsRing
            sage: MR = WeakModularFormsRing(group=8)
            sage: G_inv = MR.G_inv()
            sage: G_inv in MR
            True
            sage: CuspFormsRing(group=8).G_inv() == G_inv
            True
            sage: G_inv
            f_rho^4*f_i*d/(f_rho^8 - f_i^2)
            sage: QMModularFormsRing(group=8).G_inv() == QMModularFormsRing(group=8)(G_inv)
            True

            sage: from space import WeakModularForms, CuspForms
            sage: MF = WeakModularForms(group=8, k=0, ep=-1)
            sage: G_inv = MF.G_inv()
            sage: G_inv in MF
            True
            sage: WeakModularFormsRing(group=8, red_hom=True).G_inv() == G_inv
            True
            sage: CuspForms(group=8, k=12, ep=1).G_inv() == G_inv
            True
            sage: MF.disp_prec(3)
            sage: G_inv
            d^2*q^-1 - 15*d/128 - 15139/262144*q - 11575/(1572864*d)*q^2 + O(q^3)

            sage: WeakModularForms(group=4, k=0, ep=-1).G_inv()
            1/65536*q^-1 - 3/8192 - 955/16384*q - 49/32*q^2 - 608799/32768*q^3 - 659/4*q^4 + O(q^5)
        """

        if (ZZ(2).divides(self._group.n())):
            (x,y,z,d) = self._pol_ring.gens()
            return self.extend_type("weak", ring=True)(d*y*x**(self._group.n()/ZZ(2))/(x**self._group.n()-y**2)).reduce()
        else:
           raise Exception("G_inv doesn't exists for n={}.".format(self._group.n()))

    @cached_method
    def g_inv(self):
        r"""
        If ``2`` divides ``n``: Return the g-invariant of the group of ``self``.

        The g-invariant is analogous to the j-invariant but has multiplier ``-1``.
        I.e. ``g_inv(-1/t) = -g_inv(t)``. It is a (normalized) holomorphic square root
        of ``J_inv*(J_inv-1)``, normalized such that its first nontrivial Fourier coefficient is ``1``.

        If ``2`` does not divide ``n`` the function doesn't exist and an exception is raised.

        It lies in a (weak) extension of the graded ring of ``self``.
        In case ``has_reduce_hom`` is ``True`` it is given as an element of
        the corresponding homogeneous space.

        EXAMPLES::

            sage: from graded_ring import QMModularFormsRing, WeakModularFormsRing, CuspFormsRing
            sage: MR = WeakModularFormsRing(group=8)
            sage: g_inv = MR.g_inv()
            sage: g_inv in MR
            True
            sage: CuspFormsRing(group=8).g_inv() == g_inv
            True
            sage: g_inv
            f_rho^4*f_i/(f_rho^8*d - f_i^2*d)
            sage: QMModularFormsRing(group=8).g_inv() == QMModularFormsRing(group=8)(g_inv)
            True

            sage: from space import WeakModularForms, CuspForms
            sage: MF = WeakModularForms(group=8, k=0, ep=-1)
            sage: g_inv = MF.g_inv()
            sage: g_inv in MF
            True
            sage: WeakModularFormsRing(group=8, red_hom=True).g_inv() == g_inv
            True
            sage: CuspForms(group=8, k=12, ep=1).g_inv() == g_inv
            True
            sage: MF.disp_prec(3)
            sage: g_inv
            q^-1 - 15/(128*d) - 15139/(262144*d^2)*q - 11575/(1572864*d^3)*q^2 + O(q^3)

            sage: WeakModularForms(group=4, k=0, ep=-1).g_inv()
            q^-1 - 24 - 3820*q - 100352*q^2 - 1217598*q^3 - 10797056*q^4 + O(q^5)
        """

        if (ZZ(2).divides(self._group.n())):
            (x,y,z,d) = self._pol_ring.gens()
            return self.extend_type("weak", ring=True)(1/d*y*x**(self._group.n()/ZZ(2))/(x**self._group.n()-y**2)).reduce()
        else:
           raise Exception("g_inv doesn't exists for n={}.".format(self._group.n()))

    @cached_method
    def E4(self):
        r"""
        Return the normalized Eisenstein series of weight ``4`` of the graded ring of ``self``.
        It is equal to ``F_rho^(n-2)``.

        It lies in a (holomorphic) extension of the graded ring of ``self``.
        In case ``has_reduce_hom`` is ``True`` it is given as an element of
        the corresponding homogeneous space.

        EXAMPLES::

            sage: from graded_ring import QMModularFormsRing, ModularFormsRing, CuspFormsRing
            sage: MR = ModularFormsRing(group=7)
            sage: E4 = MR.E4()
            sage: E4 in MR
            True
            sage: CuspFormsRing(group=7).E4() == E4
            True
            sage: E4
            f_rho^5
            sage: QMModularFormsRing(group=7).E4() == QMModularFormsRing(group=7)(E4)
            True

            sage: from space import ModularForms, CuspForms
            sage: MF = ModularForms(group=5, k=4)
            sage: E4 = MF.E4()
            sage: E4 in MF
            True
            sage: ModularFormsRing(group=5, red_hom=True).E4() == E4
            True
            sage: CuspForms(group=5, k=12).E4() == E4
            True
            sage: MF.disp_prec(3)
            sage: E4
            1 + 21/(100*d)*q + 483/(32000*d^2)*q^2 + O(q^3)

            sage: ModularForms(k=4).F_rho() == ModularForms(k=4).E4()
            True
            sage: ModularForms(k=4).E4()
            1 + 240*q + 2160*q^2 + 6720*q^3 + 17520*q^4 + O(q^5)
        """

        (x,y,z,d) = self._pol_ring.gens()
        return self.extend_type("holo", ring=True)(x**(self._group.n()-2)).reduce()

    @cached_method
    def E6(self):
        r"""
        Return the normalized Eisenstein series of weight ``6`` of the graded ring of ``self``,
        It is equal to ``F_rho^(n-3) * F_i``.

        It lies in a (holomorphic) extension of the graded ring of ``self``.
        In case ``has_reduce_hom`` is ``True`` it is given as an element of
        the corresponding homogeneous space.

        EXAMPLES::

            sage: from graded_ring import QMModularFormsRing, ModularFormsRing, CuspFormsRing
            sage: MR = ModularFormsRing(group=7)
            sage: E6 = MR.E6()
            sage: E6 in MR
            True
            sage: CuspFormsRing(group=7).E6() == E6
            True
            sage: E6
            f_rho^4*f_i
            sage: QMModularFormsRing(group=7).E6() == QMModularFormsRing(group=7)(E6)
            True

            sage: from space import ModularForms, CuspForms
            sage: MF = ModularForms(group=5, k=6)
            sage: E6 = MF.E6()
            sage: E6 in MF
            True
            sage: ModularFormsRing(group=5, red_hom=True).E6() == E6
            True
            sage: CuspForms(group=5, k=12).E6() == E6
            True
            sage: MF.disp_prec(3)
            sage: E6
            1 - 37/(200*d)*q - 14663/(320000*d^2)*q^2 + O(q^3)

            sage: ModularForms(k=6).F_i() == ModularForms(k=6).E6()
            True
            sage: ModularForms(k=6).E6()
            1 - 504*q - 16632*q^2 - 122976*q^3 - 532728*q^4 + O(q^5)
        """

        (x,y,z,d) = self._pol_ring.gens()
        return self.extend_type("holo", ring=True)(x**(self._group.n()-3)*y).reduce()

    @cached_method
    def Delta(self):
        r"""
        Return an analog of the Delta-function of the graded ring of ``self``.
        It is a cusp form of weight ``12`` and is equal to
        ``d*(E4^3 - E6^2)`` or (in terms of the generators) ``d*x^(2*n-6)*(x^n - y^2)``.

        It lies in a (cuspidal) extension of the graded ring of ``self``.
        In case ``has_reduce_hom`` is ``True`` it is given as an element of
        the corresponding homogeneous space.

        EXAMPLES::

            sage: from graded_ring import QMModularFormsRing, CuspFormsRing
            sage: MR = CuspFormsRing(group=7)
            sage: Delta = MR.Delta()
            sage: Delta in MR
            True
            sage: Delta
            f_rho^15*d - f_rho^8*f_i^2*d
            sage: QMModularFormsRing(group=7).Delta() == QMModularFormsRing(group=7)(Delta)
            True

            sage: from space import CuspForms, ModularForms
            sage: MF = CuspForms(group=5, k=12)
            sage: Delta = MF.Delta()
            sage: Delta in MF
            True
            sage: CuspFormsRing(group=5, red_hom=True).Delta() == Delta
            True
            sage: CuspForms(group=5, k=0).Delta() == Delta
            True
            sage: MF.disp_prec(3)
            sage: Delta
            q + 47/(200*d)*q^2 + O(q^3)

            sage: d = ModularForms(group=5).coeff_ring().gen()
            sage: Delta == (d*(ModularForms(group=5).E4()^3-ModularForms(group=5).E6()^2))
            True

            sage: CuspForms(k=12).F_inf() == CuspForms(k=12).Delta()
            True
            sage: CuspForms(k=12).Delta()
            q - 24*q^2 + 252*q^3 - 1472*q^4 + O(q^5)
        """

        (x,y,z,d) = self._pol_ring.gens()
        return self.extend_type("cusp", ring=True)(d*x**(2*self._group.n()-6)*(x**self._group.n()-y**2)).reduce()

    @cached_method
    def E2(self):
        r"""
        Return the normalized quasi holomorphic Eisenstein series of weight ``2`` of the
        graded ring of ``self``. It is also a generator of the graded ring of
        ``self`` and  the polynomial variable ``z`` exactly corresponds to ``E2``.

        It lies in a (quasi holomorphic) extension of the graded ring of ``self``.
        In case ``has_reduce_hom`` is ``True`` it is given as an element of
        the corresponding homogeneous space.

        EXAMPLES::

            sage: from graded_ring import QMModularFormsRing, QModularFormsRing, CuspFormsRing
            sage: MR = QModularFormsRing(group=7)
            sage: E2 = MR.E2()
            sage: E2 in MR
            True
            sage: CuspFormsRing(group=7).E2() == E2
            True
            sage: E2
            E2
            sage: QMModularFormsRing(group=7).E2() == QMModularFormsRing(group=7)(E2)
            True

            sage: from space import QModularForms, CuspForms
            sage: MF = QModularForms(group=5, k=2)
            sage: E2 = MF.E2()
            sage: E2 in MF
            True
            sage: QModularFormsRing(group=5, red_hom=True).E2() == E2
            True
            sage: CuspForms(group=5, k=12, ep=1).E2() == E2
            True
            sage: MF.disp_prec(3)
            sage: E2
            1 - 9/(200*d)*q - 369/(320000*d^2)*q^2 + O(q^3)

            sage: F_inf = MF.F_inf()
            sage: E2 == F_inf.derivative() / F_inf
            True

            sage: QModularForms(k=2).E2()
            1 - 24*q - 72*q^2 - 96*q^3 - 168*q^4 + O(q^5)
        """

        (x,y,z,d) = self._pol_ring.gens()
        return self.extend_type(["holo", "quasi"], ring=True)(z).reduce()
Ejemplo n.º 28
0
    def segre_embedding(self, PP=None, var='u'):
        r"""
        Return the Segre embedding of this space into the appropriate
        projective space.

        INPUT:

        -  ``PP`` -- (default: ``None``) ambient image projective space;
            this is constructed if it is not given.

        - ``var`` -- string, variable name of the image projective space, default `u` (optional).

        OUTPUT:

        Hom -- from this space to the appropriate subscheme of projective space.

        .. TODO::

            Cartesian products with more than two components.

        EXAMPLES::

            sage: X.<y0,y1,y2,y3,y4,y5> = ProductProjectiveSpaces(ZZ, [2, 2])
            sage: phi = X.segre_embedding(); phi
            Scheme morphism:
              From: Product of projective spaces P^2 x P^2 over Integer Ring
              To:   Closed subscheme of Projective Space of dimension 8 over Integer Ring defined by:
              -u5*u7 + u4*u8,
              -u5*u6 + u3*u8,
              -u4*u6 + u3*u7,
              -u2*u7 + u1*u8,
              -u2*u4 + u1*u5,
              -u2*u6 + u0*u8,
              -u1*u6 + u0*u7,
              -u2*u3 + u0*u5,
              -u1*u3 + u0*u4
              Defn: Defined by sending (y0 : y1 : y2 , y3 : y4 : y5) to
                    (y0*y3 : y0*y4 : y0*y5 : y1*y3 : y1*y4 : y1*y5 : y2*y3 : y2*y4 : y2*y5).

            ::

            sage: T = ProductProjectiveSpaces([1, 2], CC, 'z')
            sage: T.segre_embedding()
            Scheme morphism:
              From: Product of projective spaces P^1 x P^2 over Complex Field with 53 bits of precision
              To:   Closed subscheme of Projective Space of dimension 5 over Complex Field with 53 bits of precision defined by:
              -u2*u4 + u1*u5,
              -u2*u3 + u0*u5,
              -u1*u3 + u0*u4
              Defn: Defined by sending (z0 : z1 , z2 : z3 : z4) to
                    (z0*z2 : z0*z3 : z0*z4 : z1*z2 : z1*z3 : z1*z4).

            ::

            sage: T = ProductProjectiveSpaces([1, 2, 1], QQ, 'z')
            sage: T.segre_embedding()
            Scheme morphism:
              From: Product of projective spaces P^1 x P^2 x P^1 over Rational Field
              To:   Closed subscheme of Projective Space of dimension 11 over
            Rational Field defined by:
              -u9*u10 + u8*u11,
              -u7*u10 + u6*u11,
              -u7*u8 + u6*u9,
              -u5*u10 + u4*u11,
              -u5*u8 + u4*u9,
              -u5*u6 + u4*u7,
              -u5*u9 + u3*u11,
              -u5*u8 + u3*u10,
              -u5*u8 + u2*u11,
              -u4*u8 + u2*u10,
              -u3*u8 + u2*u9,
              -u3*u6 + u2*u7,
              -u3*u4 + u2*u5,
              -u5*u7 + u1*u11,
              -u5*u6 + u1*u10,
              -u3*u7 + u1*u9,
              -u3*u6 + u1*u8,
              -u5*u6 + u0*u11,
              -u4*u6 + u0*u10,
              -u3*u6 + u0*u9,
              -u2*u6 + u0*u8,
              -u1*u6 + u0*u7,
              -u1*u4 + u0*u5,
              -u1*u2 + u0*u3
              Defn: Defined by sending (z0 : z1 , z2 : z3 : z4 , z5 : z6) to
                    (z0*z2*z5 : z0*z2*z6 : z0*z3*z5 : z0*z3*z6 : z0*z4*z5 : z0*z4*z6
            : z1*z2*z5 : z1*z2*z6 : z1*z3*z5 : z1*z3*z6 : z1*z4*z5 : z1*z4*z6).
        """
        N = self._dims
        M = prod([n + 1 for n in N]) - 1
        CR = self.coordinate_ring()

        vars = list(self.coordinate_ring().variable_names()) + [
            var + str(i) for i in range(M + 1)
        ]
        R = PolynomialRing(self.base_ring(),
                           self.ngens() + M + 1,
                           vars,
                           order='lex')

        #set-up the elimination for the segre embedding
        mapping = []
        k = self.ngens()
        index = self.num_components() * [0]
        for count in range(M + 1):
            mapping.append(
                R.gen(k + count) -
                prod([CR(self[i].gen(index[i])) for i in range(len(index))]))
            for i in range(len(index) - 1, -1, -1):
                if index[i] == N[i]:
                    index[i] = 0
                else:
                    index[i] += 1
                    break  #only increment once

        #change the defining ideal of the subscheme into the variables
        I = R.ideal(list(self.defining_polynomials()) + mapping)
        J = I.groebner_basis()
        s = set(R.gens()[:self.ngens()])
        n = len(J) - 1
        L = []
        while s.isdisjoint(J[n].variables()):
            L.append(J[n])
            n = n - 1

        #create new subscheme
        if PP is None:
            PS = ProjectiveSpace(self.base_ring(), M,
                                 R.variable_names()[self.ngens():])
            Y = PS.subscheme(L)
        else:
            if PP.dimension_relative() != M:
                raise ValueError(
                    "projective Space %s must be dimension %s") % (PP, M)
            S = PP.coordinate_ring()
            psi = R.hom([0] * k + list(S.gens()), S)
            L = [psi(l) for l in L]
            Y = PP.subscheme(L)

        #create embedding for points
        mapping = []
        index = self.num_components() * [0]
        for count in range(M + 1):
            mapping.append(
                prod([CR(self[i].gen(index[i])) for i in range(len(index))]))
            for i in range(len(index) - 1, -1, -1):
                if index[i] == N[i]:
                    index[i] = 0
                else:
                    index[i] += 1
                    break  #only increment once
        phi = self.hom(mapping, Y)

        return phi
Ejemplo n.º 29
0
    def has_rational_point(self, point = False, read_cache = True, \
                           algorithm = 'default'):
        r"""
        Always returns ``True`` because self has a point defined over
        its finite base field `B`.

        If ``point`` is True, then returns a second output `S`, which is a
        rational point if one exists.

        Points are cached. If ``read_cache`` is True, then cached information
        is used for the output if available. If no cached point is available
        or ``read_cache`` is False, then random `y`-coordinates are tried
        if ``self`` is smooth and a singular point is returned otherwise.

        EXAMPLES::

            sage: Conic(FiniteField(37), [1, 2, 3, 4, 5, 6]).has_rational_point()
            True

            sage: C = Conic(FiniteField(2), [1, 1, 1, 1, 1, 0]); C
            Projective Conic Curve over Finite Field of size 2 defined by x^2 + x*y + y^2 + x*z + y*z
            sage: C.has_rational_point(point = True)  # output is random
            (True, (0 : 0 : 1))

            sage: p = next_prime(10^50)
            sage: F = FiniteField(p)
            sage: C = Conic(F, [1, 2, 3]); C
            Projective Conic Curve over Finite Field of size 100000000000000000000000000000000000000000000000151 defined by x^2 + 2*y^2 + 3*z^2
            sage: C.has_rational_point(point = True)  # output is random
            (True,
             (14971942941468509742682168602989039212496867586852 : 75235465708017792892762202088174741054630437326388 : 1)

            sage: F.<a> = FiniteField(7^20)
            sage: C = Conic([1, a, -5]); C
            Projective Conic Curve over Finite Field in a of size 7^20 defined by x^2 + (a)*y^2 + 2*z^2
            sage: C.has_rational_point(point = True)  # output is random
            (True,
             (a^18 + 2*a^17 + 4*a^16 + 6*a^13 + a^12 + 6*a^11 + 3*a^10 + 4*a^9 + 2*a^8 + 4*a^7 + a^6 + 4*a^4 + 6*a^2 + 3*a + 6 : 5*a^19 + 5*a^18 + 5*a^17 + a^16 + 2*a^15 + 3*a^14 + 4*a^13 + 5*a^12 + a^11 + 3*a^10 + 2*a^8 + 3*a^7 + 4*a^6 + 4*a^5 + 6*a^3 + 5*a^2 + 2*a + 4 : 1))

        TESTS::

            sage: l = Sequence(cartesian_product_iterator([[0, 1] for i in range(6)]))
            sage: bigF = GF(next_prime(2^100))
            sage: bigF2 = GF(next_prime(2^50)^2, 'b')
            sage: m = [[F(b) for b in a] for a in l for F in [GF(2), GF(4, 'a'), GF(5), GF(9, 'a'), bigF, bigF2]]
            sage: m += [[F.random_element() for i in range(6)] for j in range(20) for F in [GF(5), bigF]]
            sage: c = [Conic(a) for a in m if a != [0,0,0,0,0,0]]
            sage: assert all(C.has_rational_point() for C in c)
            sage: r = randrange(0, 5)
            sage: assert all(C.defining_polynomial()(Sequence(C.has_rational_point(point = True)[1])) == 0 for C in c[r::5])  # long time (1.4s on sage.math, 2013)
        """
        if not point:
            return True
        if read_cache:
            if self._rational_point is not None:
                return True, self._rational_point
        B = self.base_ring()
        s, pt = self.has_singular_point(point = True)
        if s:
            return True, pt
        while True:
            x = B.random_element()
            Y = PolynomialRing(B,'Y').gen()
            r = self.defining_polynomial()([x,Y,1]).roots()
            if len(r) > 0:
                return True, self.point([x,r[0][0],B(1)])
Ejemplo n.º 30
0
    def __call__(self, Q, P):
        """
        Compute and return the :class:`ReductionData` corresponding to
        the genus 2 curve `y^2 + Q(x) y = P(x)`.

        EXAMPLES::

            sage: x = polygen(QQ)
            sage: genus2reduction(x^3 - 2*x^2 - 2*x + 1, -5*x^5)
            Reduction data about this proper smooth genus 2 curve:
                    y^2 + (x^3 - 2*x^2 - 2*x + 1)*y = -5*x^5
            A Minimal Equation (away from 2):
                    y^2 = x^6 - 240*x^4 - 2550*x^3 - 11400*x^2 - 24100*x - 19855
            Minimal Discriminant (away from 2):  56675000
            Conductor (away from 2): 1416875
            Local Data:
                    p=2
                    (potential) stable reduction:  (II), j=1
                    p=5
                    (potential) stable reduction:  (I)
                    reduction at p: [V] page 156, (3), f=4
                    p=2267
                    (potential) stable reduction:  (II), j=432
                    reduction at p: [I{1-0-0}] page 170, (1), f=1

        ::

            sage: genus2reduction(x^2 + 1, -5*x^5)
            Reduction data about this proper smooth genus 2 curve:
                    y^2 + (x^2 + 1)*y = -5*x^5
            A Minimal Equation (away from 2):
                    y^2 = -20*x^5 + x^4 + 2*x^2 + 1
            Minimal Discriminant (away from 2):  48838125
            Conductor: 32025
            Local Data:
                    p=3
                    (potential) stable reduction:  (II), j=1
                    reduction at p: [I{1-0-0}] page 170, (1), f=1
                    p=5
                    (potential) stable reduction:  (IV)
                    reduction at p: [I{1-1-2}] page 182, (5), f=2
                    p=7
                    (potential) stable reduction:  (II), j=4
                    reduction at p: [I{1-0-0}] page 170, (1), f=1
                    p=61
                    (potential) stable reduction:  (II), j=57
                    reduction at p: [I{2-0-0}] page 170, (2), f=1

        Verify that we fix :trac:`5573`::

            sage: genus2reduction(x^3 + x^2 + x,-2*x^5 + 3*x^4 - x^3 - x^2 - 6*x - 2)
            Reduction data about this proper smooth genus 2 curve:
                    y^2 + (x^3 + x^2 + x)*y = -2*x^5 + 3*x^4 - x^3 - x^2 - 6*x - 2
            A Minimal Equation (away from 2):
                    y^2 = x^6 + 18*x^3 + 36*x^2 - 27
            Minimal Discriminant (away from 2):  1520984142
            Conductor: 954
            Local Data:
                    p=2
                    (potential) stable reduction:  (II), j=1
                    reduction at p: [I{1-0-0}] page 170, (1), f=1
                    p=3
                    (potential) stable reduction:  (I)
                    reduction at p: [II] page 155, (1), f=2
                    p=53
                    (potential) stable reduction:  (II), j=12
                    reduction at p: [I{1-0-0}] page 170, (1), f=1
        """
        R = PolynomialRing(QQ, 'x')
        P = R(P)
        Q = R(Q)
        if P.degree() > 6:
            raise ValueError("P (=%s) must have degree at most 6" % P)
        if Q.degree() >= 4:
            raise ValueError("Q (=%s) must have degree at most 3" % Q)

        res = pari.genus2red([P, Q])

        conductor = ZZ(res[0])
        minimal_equation = R(res[2])

        minimal_disc = QQ(res[2].poldisc()).abs()
        if minimal_equation.degree() == 5:
            minimal_disc *= minimal_equation[5]**2
        # Multiply with suitable power of 2 of the form 2^(2*(d-1) - 12)
        b = 2 * (minimal_equation.degree() - 1)
        k = QQ((12 - minimal_disc.valuation(2), b)).ceil()
        minimal_disc >>= 12 - b * k
        minimal_disc = ZZ(minimal_disc)

        local_data = {}
        for red in res[3]:
            p = ZZ(red[0])

            t = red[1]
            data = "(potential) stable reduction:  (%s)" % roman_numeral[int(
                t[0])]
            t = t[1]
            if len(t) == 1:
                data += ", j=%s" % t[0].lift()
            elif len(t) == 2:
                data += ", j1+j2=%s, j1*j2=%s" % (t[0].lift(), t[1].lift())

            t = red[2]
            if t:
                data += "\nreduction at p: %s, " % str(t[0]).replace(
                    '"', '').replace("(tame) ", "")
                data += divisors_to_string(t[1]) + ", f=" + str(
                    res[0].valuation(red[0]))

            local_data[p] = data

        prime_to_2_conductor_only = (-1 in res[1].component(2))
        return ReductionData(res, P, Q, minimal_equation, minimal_disc,
                             local_data, conductor, prime_to_2_conductor_only)
Ejemplo n.º 31
0
def Conic(base_field, F=None, names=None, unique=True):
    r"""
    Return the plane projective conic curve defined by ``F``
    over ``base_field``.

    The input form ``Conic(F, names=None)`` is also accepted,
    in which case the fraction field of the base ring of ``F``
    is used as base field.

    INPUT:

    - ``base_field`` -- The base field of the conic.

    - ``names`` -- a list, tuple, or comma separated string
      of three variable names specifying the names
      of the coordinate functions of the ambient
      space `\Bold{P}^3`. If not specified or read
      off from ``F``, then this defaults to ``'x,y,z'``.

    - ``F`` -- a polynomial, list, matrix, ternary quadratic form,
      or list or tuple of 5 points in the plane.

                   If ``F`` is a polynomial or quadratic form,
                   then the output is the curve in the projective plane
                   defined by ``F = 0``.

                   If ``F`` is a polynomial, then it must be a polynomial
                   of degree at most 2 in 2 variables, or a homogeneous
                   polynomial in of degree 2 in 3 variables.

                   If ``F`` is a matrix, then the output is the zero locus
                   of `(x,y,z) F (x,y,z)^t`.

                   If ``F`` is a list of coefficients, then it has
                   length 3 or 6 and gives the coefficients of
                   the monomials `x^2, y^2, z^2` or all 6 monomials
                   `x^2, xy, xz, y^2, yz, z^2` in lexicographic order.

                   If ``F`` is a list of 5 points in the plane, then the output
                   is a conic through those points.

    - ``unique`` -- Used only if ``F`` is a list of points in the plane.
      If the conic through the points is not unique, then
      raise ``ValueError`` if and only if ``unique`` is True

    OUTPUT:

    A plane projective conic curve defined by ``F`` over a field.

    EXAMPLES:

    Conic curves given by polynomials ::

        sage: X,Y,Z = QQ['X,Y,Z'].gens()
        sage: Conic(X^2 - X*Y + Y^2 - Z^2)
        Projective Conic Curve over Rational Field defined by X^2 - X*Y + Y^2 - Z^2
        sage: x,y = GF(7)['x,y'].gens()
        sage: Conic(x^2 - x + 2*y^2 - 3, 'U,V,W')
        Projective Conic Curve over Finite Field of size 7 defined by U^2 + 2*V^2 - U*W - 3*W^2

    Conic curves given by matrices ::

        sage: Conic(matrix(QQ, [[1, 2, 0], [4, 0, 0], [7, 0, 9]]), 'x,y,z')
        Projective Conic Curve over Rational Field defined by x^2 + 6*x*y + 7*x*z + 9*z^2

        sage: x,y,z = GF(11)['x,y,z'].gens()
        sage: C = Conic(x^2+y^2-2*z^2); C
        Projective Conic Curve over Finite Field of size 11 defined by x^2 + y^2 - 2*z^2
        sage: Conic(C.symmetric_matrix(), 'x,y,z')
        Projective Conic Curve over Finite Field of size 11 defined by x^2 + y^2 - 2*z^2

    Conics given by coefficients ::

        sage: Conic(QQ, [1,2,3])
        Projective Conic Curve over Rational Field defined by x^2 + 2*y^2 + 3*z^2
        sage: Conic(GF(7), [1,2,3,4,5,6], 'X')
        Projective Conic Curve over Finite Field of size 7 defined by X0^2 + 2*X0*X1 - 3*X1^2 + 3*X0*X2 - 2*X1*X2 - X2^2

    The conic through a set of points ::

        sage: C = Conic(QQ, [[10,2],[3,4],[-7,6],[7,8],[9,10]]); C
        Projective Conic Curve over Rational Field defined by x^2 + 13/4*x*y - 17/4*y^2 - 35/2*x*z + 91/4*y*z - 37/2*z^2
        sage: C.rational_point()
        (10 : 2 : 1)
        sage: C.point([3,4])
        (3 : 4 : 1)

        sage: a=AffineSpace(GF(13),2)
        sage: Conic([a([x,x^2]) for x in range(5)])
        Projective Conic Curve over Finite Field of size 13 defined by x^2 - y*z
    """
    if not (is_IntegralDomain(base_field) or base_field == None):
        if names is None:
            names = F
        F = base_field
        base_field = None
    if isinstance(F, (list,tuple)):
        if len(F) == 1:
            return Conic(base_field, F[0], names)
        if names == None:
            names = 'x,y,z'
        if len(F) == 5:
            L=[]
            for f in F:
                if isinstance(f, SchemeMorphism_point_affine):
                    C = Sequence(f, universe = base_field)
                    if len(C) != 2:
                        raise TypeError, "points in F (=%s) must be planar"%F
                    C.append(1)
                elif isinstance(f, SchemeMorphism_point_projective_field):
                    C = Sequence(f, universe = base_field)
                elif isinstance(f, (list, tuple)):
                    C = Sequence(f, universe = base_field)
                    if len(C) == 2:
                        C.append(1)
                else:
                    raise TypeError, "F (=%s) must be a sequence of planar " \
                                      "points" % F
                if len(C) != 3:
                    raise TypeError, "points in F (=%s) must be planar" % F
                P = C.universe()
                if not is_IntegralDomain(P):
                    raise TypeError, "coordinates of points in F (=%s) must " \
                                     "be in an integral domain" % F
                L.append(Sequence([C[0]**2, C[0]*C[1], C[0]*C[2], C[1]**2,
                                   C[1]*C[2], C[2]**2], P.fraction_field()))
            M=Matrix(L)
            if unique and M.rank() != 5:
                raise ValueError, "points in F (=%s) do not define a unique " \
                                   "conic" % F
            con = Conic(base_field, Sequence(M.right_kernel().gen()), names)
            con.point(F[0])
            return con
        F = Sequence(F, universe = base_field)
        base_field = F.universe().fraction_field()
        temp_ring = PolynomialRing(base_field, 3, names)
        (x,y,z) = temp_ring.gens()
        if len(F) == 3:
            return Conic(F[0]*x**2 + F[1]*y**2 + F[2]*z**2)
        if len(F) == 6:
            return Conic(F[0]*x**2 + F[1]*x*y + F[2]*x*z + F[3]*y**2 + \
                         F[4]*y*z + F[5]*z**2)
        raise TypeError, "F (=%s) must be a sequence of 3 or 6" \
                         "coefficients" % F
    if is_QuadraticForm(F):
        F = F.matrix()
    if is_Matrix(F) and F.is_square() and F.ncols() == 3:
        if names == None:
            names = 'x,y,z'
        temp_ring = PolynomialRing(F.base_ring(), 3, names)
        F = vector(temp_ring.gens()) * F * vector(temp_ring.gens())

    if not is_MPolynomial(F):
        raise TypeError, "F (=%s) must be a three-variable polynomial or " \
                         "a sequence of points or coefficients" % F

    if F.total_degree() != 2:
        raise TypeError, "F (=%s) must have degree 2" % F

    if base_field == None:
        base_field = F.base_ring()
    if not is_IntegralDomain(base_field):
        raise ValueError, "Base field (=%s) must be a field" % base_field
    base_field = base_field.fraction_field()
    if names == None:
        names = F.parent().variable_names()
    pol_ring = PolynomialRing(base_field, 3, names)

    if F.parent().ngens() == 2:
        (x,y,z) = pol_ring.gens()
        F = pol_ring(F(x/z,y/z)*z**2)

    if F == 0:
        raise ValueError, "F must be nonzero over base field %s" % base_field

    if F.total_degree() != 2:
        raise TypeError, "F (=%s) must have degree 2 over base field %s" % \
                          (F, base_field)

    if F.parent().ngens() == 3:
        P2 = ProjectiveSpace(2, base_field, names)
        if is_PrimeFiniteField(base_field):
            return ProjectiveConic_prime_finite_field(P2, F)
        if is_FiniteField(base_field):
            return ProjectiveConic_finite_field(P2, F)
        if is_RationalField(base_field):
            return ProjectiveConic_rational_field(P2, F)
        if is_NumberField(base_field):
            return ProjectiveConic_number_field(P2, F)
        return ProjectiveConic_field(P2, F)

    raise TypeError, "Number of variables of F (=%s) must be 2 or 3" % F
Ejemplo n.º 32
0
def is_cm_j_invariant(j, method='new'):
    """
    Return whether or not this is a CM `j`-invariant.

    INPUT:

    - ``j`` -- an element of a number field `K`

    OUTPUT:

    A pair (bool, (d,f)) which is either (False, None) if `j` is not a
    CM j-invariant or (True, (d,f)) if `j` is the `j`-invariant of the
    imaginary quadratic order of discriminant `D=df^2` where `d` is
    the associated fundamental discriminant and `f` the index.

    .. note::

       The current implementation makes use of the classification of
       all orders of class number up to 100, and hence will raise an
       error if `j` is an algebraic integer of degree greater than
       this.  It would be possible to implement a more general
       version, using the fact that `d` must be supported on the
       primes dividing the discriminant of the minimal polynomial of
       `j`.

    EXAMPLES::

        sage: from sage.schemes.elliptic_curves.cm import is_cm_j_invariant
        sage: is_cm_j_invariant(0)
        (True, (-3, 1))
        sage: is_cm_j_invariant(8000)
        (True, (-8, 1))

        sage: K.<a> = QuadraticField(5)
        sage: is_cm_j_invariant(282880*a + 632000)
        (True, (-20, 1))
        sage: K.<a> = NumberField(x^3 - 2)
        sage: is_cm_j_invariant(31710790944000*a^2 + 39953093016000*a + 50337742902000)
        (True, (-3, 6))

    TESTS::

        sage: from sage.schemes.elliptic_curves.cm import is_cm_j_invariant
        sage: all([is_cm_j_invariant(j) == (True, (d,f)) for d,f,j in cm_j_invariants_and_orders(QQ)])
        True

    """
    # First we check that j is an algebraic number:

    from sage.rings.all import NumberFieldElement, NumberField
    if not isinstance(j, NumberFieldElement) and not j in QQ:
        raise NotImplementedError(
            "is_cm_j_invariant() is only implemented for number field elements"
        )

    # for j in ZZ we have a lookup-table:

    if j in ZZ:
        j = ZZ(j)
        table = dict([(jj, (d, f))
                      for d, f, jj in cm_j_invariants_and_orders(QQ)])
        if j in table:
            return True, table[j]
        return False, None

    # Otherwise if j is in Q then it is not integral so is not CM:

    if j in QQ:
        return False, None

    # Now j has degree at least 2.  If it is not integral so is not CM:

    if not j.is_integral():
        return False, None

    # Next we find its minimal polynomial and degree h, and if h is
    # less than the degree of j.parent() we recreate j as an element
    # of Q(j):

    jpol = PolynomialRing(QQ, 'x')([-j, 1
                                    ]) if j in QQ else j.absolute_minpoly()
    h = jpol.degree()

    # This will be used as a fall-back if we cannot determine the
    # result using local data.  For this to be necessary there would
    # have to be very few primes of degree 1 and norm under 1000,
    # since we only need to find one prime of degree 1, good
    # reduction for which a_P is nonzero.
    if method == 'old':
        if h > 100:
            raise NotImplementedError(
                "CM data only available for class numbers up to 100")
        for d, f in cm_orders(h):
            if jpol == hilbert_class_polynomial(d * f**2):
                return True, (d, f)
        return False, None

    # replace j by a clone whose parent is Q(j), if necessary:

    K = j.parent()
    if h < K.absolute_degree():
        K = NumberField(jpol, 'j')
        j = K.gen()

    # Construct an elliptic curve with j-invariant j, with
    # integral model:

    from sage.schemes.elliptic_curves.all import EllipticCurve
    E = EllipticCurve(j=j).integral_model()
    D = E.discriminant()
    prime_bound = 1000  # test primes of degree 1 up to this norm
    max_primes = 20  # test at most this many primes
    num_prime = 0
    cmd = 0
    cmf = 0

    # Test primes of good reduction.  If E has CM then for half the
    # primes P we will have a_P=0, and for all other prime P the CM
    # field is Q(sqrt(a_P^2-4N(P))).  Hence if these fields are
    # different for two primes then E does not have CM.  If they are
    # all equal for the primes tested, then we have a candidate CM
    # field.  Moreover the discriminant of the endomorphism ring
    # divides all the values a_P^2-4N(P), since that is the
    # discriminant of the order containing the Frobenius at P.  So we
    # end up with a finite number (usually one) of candidate
    # discriminants to test.  Each is tested by checking that its class
    # number is h, and if so then that j is a root of its Hilbert
    # class polynomial.  In practice non CM curves will be eliminated
    # by the local test at a small number of primes (probably just 2).

    for P in K.primes_of_degree_one_iter(prime_bound):
        if num_prime > max_primes:
            if cmd:  # we have a candidate CM field already
                break
            else:  # we need to try more primes
                max_primes *= 2
        if D.valuation(P) > 0:  # skip bad primes
            continue
        aP = E.reduction(P).trace_of_frobenius()
        if aP == 0:  # skip supersingular primes
            continue
        num_prime += 1
        DP = aP**2 - 4 * P.norm()
        dP = DP.squarefree_part()
        fP = ZZ(DP // dP).isqrt()
        if cmd == 0:  # first one, so store d and f
            cmd = dP
            cmf = fP
        elif cmd != dP:  # inconsistent with previous
            return False, None
        else:  # consistent d, so update f
            cmf = cmf.gcd(fP)

    if cmd == 0:  # no conclusion, we found no degree 1 primes, revert to old method
        return is_cm_j_invariant(j, method='old')

    # it looks like cm by disc cmd * f**2 where f divides cmf

    if cmd % 4 != 1:
        cmd = cmd * 4
        cmf = cmf // 2

    # Now we must check if h(cmd*f**2)==h for f|cmf; if so we check
    # whether j is a root of the associated Hilbert class polynomial.
    for f in cmf.divisors():  # only positive divisors
        d = cmd * f**2
        if h != d.class_number():
            continue
        pol = hilbert_class_polynomial(d)
        if pol(j) == 0:
            return True, (cmd, f)
    return False, None
Ejemplo n.º 33
0
def _normalize_2x2(G):
    r"""
    Normalize this indecomposable `2` by `2` block.

    INPUT:

    ``G`` - a `2` by `2` matrix over `\ZZ_p`
    with ``type = 'fixed-mod'`` of the form::

        [2a  b]
        [ b 2c] * 2^n

    with `b` of valuation 1.

    OUTPUT:

    A unimodular `2` by `2` matrix ``B`` over `\ZZ_p` with
    ``B * G * B.transpose()``
    either::

        [0 1]              [2 1]
        [1 0] * 2^n  or    [1 2] * 2^n

    EXAMPLES::

        sage: from sage.quadratic_forms.genera.normal_form import _normalize_2x2
        sage: R = Zp(2, prec = 15, type = 'fixed-mod', print_mode='series', show_prec=False)
        sage: G = Matrix(R, 2, [-17*2,3,3,23*2])
        sage: B =_normalize_2x2(G)
        sage: B * G * B.T
        [2 1]
        [1 2]

        sage: G = Matrix(R,2,[-17*4,3,3,23*2])
        sage: B = _normalize_2x2(G)
        sage: B*G*B.T
        [0 1]
        [1 0]

        sage: G = 2^3 * Matrix(R, 2, [-17*2,3,3,23*2])
        sage: B = _normalize_2x2(G)
        sage: B * G * B.T
        [2^4 2^3]
        [2^3 2^4]
    """
    from sage.rings.all import PolynomialRing
    from sage.modules.free_module_element import vector
    B = copy(G.parent().identity_matrix())
    R = G.base_ring()
    P = PolynomialRing(R, 'x')
    x = P.gen()

    # The input must be an even block
    odd1 = (G[0, 0].valuation() < G[1, 0].valuation())
    odd2 = (G[1, 1].valuation() < G[1, 0].valuation())
    if  odd1 or odd2:
            raise ValueError("Not a valid 2 x 2 block.")
    scale = 2 ** G[0,1].valuation()
    D = Matrix(R, 2, 2, [d // scale for d in G.list()])
    # now D is of the form
    # [2a b ]
    # [b  2c]
    # where b has valuation 1.
    G = copy(D)

    # Make sure G[1, 1] has valuation 1.
    if D[1, 1].valuation() > D[0, 0].valuation():
        B.swap_columns(0, 1)
        D.swap_columns(0, 1)
        D.swap_rows(0, 1)
    if D[1, 1].valuation() != 1:
        # this works because
        # D[0, 0] has valuation at least 2
        B[1, :] += B[0, :]
        D = B * G * B.transpose()
    assert D[1, 1].valuation() == 1

    if mod(D.det(), 8) == 3:
        #  in this case we can transform D to
        #  2 1
        #  1 2
        # Find a point of norm 2
        # solve: 2 == D[1,1]*x^2 + 2*D[1,0]*x + D[0,0]
        pol = (D[1,1]*x**2 + 2*D[1,0]*x + D[0,0]-2) // 2
        # somehow else pari can get a hickup see `trac`:#24065
        pol = pol // pol.leading_coefficient()
        sol = pol.roots()[0][0]
        B[0, 1] = sol
        D = B * G * B.transpose()
        # make D[0, 1] = 1
        B[1, :] *= D[1, 0].inverse_of_unit()
        D = B * G * B.transpose()

        # solve: v*D*v == 2 with v = (x, -2*x+1)
        if D[1, 1] != 2:
            v = vector([x, -2*x + 1])
            pol = (v*D*v - 2) // 2
            # somehow else pari can get a hickup `trac`:#24065
            pol = pol // pol.leading_coefficient()
            sol = pol.roots()[0][0]
            B[1, :] = sol * B[0,:] + (-2*sol + 1)*B[1, :]
            D = B * G * B.transpose()
        # check the result
        assert D == Matrix(G.parent(), 2, 2, [2, 1, 1, 2]), "D1 \n %r" %D
    elif mod(D.det(), 8) == 7:
        # in this case we can transform D to
        #  0 1
        #  1 0
        # Find a point representing 0
        # solve: 0 == D[1,1]*x^2 + 2*D[1,0]*x + D[0,0]
        pol = (D[1,1]*x**2 + 2*D[1,0]*x + D[0,0])//2
        # somehow else pari can get a hickup, see  `trac`:#24065
        pol = pol // pol.leading_coefficient()
        sol = pol.roots()[0][0]
        B[0,:] += sol*B[1, :]
        D = B * G * B.transpose()
        # make the second basis vector have 0 square as well.
        B[1, :] = B[1, :] - D[1, 1]//(2*D[0, 1])*B[0,:]
        D = B * G * B.transpose()
        # rescale to get D[0,1] = 1
        B[0, :] *= D[1, 0].inverse_of_unit()
        D = B * G * B.transpose()
        # check the result
        assert D == Matrix(G.parent(), 2, 2, [0, 1, 1, 0]), "D2 \n %r" %D
    return B
Ejemplo n.º 34
0
    def parametrization(self, point=None, morphism=True):
        r"""
        Return a parametrization `f` of ``self`` together with the
        inverse of `f`.

        If ``point`` is specified, then that point is used
        for the parametrization. Otherwise, use ``self.rational_point()``
        to find a point.

        If ``morphism`` is True, then `f` is returned in the form
        of a Scheme morphism. Otherwise, it is a tuple of polynomials
        that gives the parametrization.

        ALGORITHM:

        Uses the PARI/GP function ``qfparam``.

        EXAMPLES ::

            sage: c = Conic([1,1,-1])
            sage: c.parametrization()
            (Scheme morphism:
              From: Projective Space of dimension 1 over Rational Field
              To:   Projective Conic Curve over Rational Field defined by x^2 + y^2 - z^2
              Defn: Defined on coordinates by sending (x : y) to
                    (2*x*y : x^2 - y^2 : x^2 + y^2),
             Scheme morphism:
              From: Projective Conic Curve over Rational Field defined by x^2 + y^2 - z^2
              To:   Projective Space of dimension 1 over Rational Field
              Defn: Defined on coordinates by sending (x : y : z) to
                    (1/2*x : -1/2*y + 1/2*z))

        An example with ``morphism = False`` ::

            sage: R.<x,y,z> = QQ[]
            sage: C = Curve(7*x^2 + 2*y*z + z^2)
            sage: (p, i) = C.parametrization(morphism = False); (p, i)
            ([-2*x*y, x^2 + 7*y^2, -2*x^2], [-1/2*x, 1/7*y + 1/14*z])
            sage: C.defining_polynomial()(p)
            0
            sage: i[0](p) / i[1](p)
            x/y

        A ``ValueError`` is raised if ``self`` has no rational point ::

            sage: C = Conic(x^2 + 2*y^2 + z^2)
            sage: C.parametrization()
            Traceback (most recent call last):
            ...
            ValueError: Conic Projective Conic Curve over Rational Field defined by x^2 + 2*y^2 + z^2 has no rational points over Rational Field!

        A ``ValueError`` is raised if ``self`` is not smooth ::

            sage: C = Conic(x^2 + y^2)
            sage: C.parametrization()
            Traceback (most recent call last):
            ...
            ValueError: The conic self (=Projective Conic Curve over Rational Field defined by x^2 + y^2) is not smooth, hence does not have a parametrization.
        """
        if (not self._parametrization is None) and not point:
            par = self._parametrization
        else:
            if not self.is_smooth():
                raise ValueError(
                    "The conic self (=%s) is not smooth, hence does not have a parametrization."
                    % self)
            if point is None:
                point = self.rational_point()
            point = Sequence(point)
            Q = PolynomialRing(QQ, 'x,y')
            [x, y] = Q.gens()
            gens = self.ambient_space().gens()
            M = self.symmetric_matrix()
            M *= lcm([t.denominator() for t in M.list()])
            par1 = qfparam(M, point)
            B = Matrix([[par1[i][j] for j in range(3)] for i in range(3)])
            # self is in the image of B and does not lie on a line,
            # hence B is invertible
            A = B.inverse()
            par2 = [sum([A[i, j] * gens[j] for j in range(3)]) for i in [1, 0]]
            par = ([Q(pol(x / y) * y**2) for pol in par1], par2)
            if self._parametrization is None:
                self._parametrization = par
        if not morphism:
            return par
        P1 = ProjectiveSpace(self.base_ring(), 1, 'x,y')
        return P1.hom(par[0], self), self.Hom(P1)(par[1], check=False)
Ejemplo n.º 35
0
def _load_euler_table(self, n, force=False, verbose=False):
    r"""
    Load the euler table for self over the degree n extension of
    $\mathbb{F}_q$ to disk. If self is the versal j-curve, the table
    is pulled from
    
    SAGE_ROOT/data/jcurve_euler_tables .
    
    Otherwise, the table is pulled from the `user` table

    SAGE_ROOT/data/local_euler_tables .

    This should eventually be implemented using MongoDB.

    It currently doesn't check if the key exist. If the key doesn't
    exist, a RuntimeError is raised by sage.database.db. This
    RuntimeError should be sufficient, so key checking may not be
    necessary.

    INPUT:

        - n -- the degree of the extension of F_q
        - force -- boolean that overwrites self's euler table with
                   one from database

    EXAMPLES::

        sage: import psage
        sage: K.<t> = psage.FunctionField(GF(11))
        sage: E = psage.ellff_EllipticCurve(K,[0,0,0,-27*t/(t-1728),54*t/(t-1728)])
        sage: E._euler_table(1)
        Traceback (most recent call last):
            ...
        RuntimeError: table is empty
        sage: E._load_euler_table(1)
        sage: E._euler_table(1)
        [0, 0, 4, -6, 3, 5, 1, -2, 4, -2, 3, 1]
            
    """
        
    import os
    SAGE_ROOT = os.environ['SAGE_ROOT']
        
    K = self.K
    R = self.R
    t = K.gens()[0]
    p = self.p
    d = self.d
    q = self.q
    R2 = PolynomialRing(GF(q), 's')
    s = R2.gens()[0]
    a1n = R2(0)
    a1d = R2(1)
    a2n = R2(0)
    a2d = R2(1)
    a3n = R2(0)
    a3d = R2(1)
    a4n = R2(self.a4.numerator().coeffs())
    a4d = R2(self.a4.denominator().coeffs())
    a6n = R2(self.a6.numerator().coeffs())
    a6d = R2(self.a6.denominator().coeffs())

    ainvs = [0, 0, 0, self.a4, self.a6]
    ainvs_pairs = ((a1n, a1d), (a2n, a2d), (a3n, a3d), (a4n, a4d), (a6n, a6d))

    # recognize if self is j-curve and use special repository
    if ainvs == [0,0,0,-27*t*(t-1728)**3,54*t*(t-1728)**5]:
        if verbose:
            print 'j-curve recognized; saving euler table to database'
        if not os.path.exists(SAGE_ROOT + '/data/jcurve_euler_tables/jcurve_euler_tables'):
            print 'Database does not exist; cannot load from it'
        else:
            euler_db = jCurveEulerTables()
            # check that keys exist?
            self._set_euler_table(n, euler_db[q][n], force)
            
    # work with user's repository of euler tables
    else:
        if not os.path.exists(SAGE_ROOT + '/data/local_euler_tables/local_euler_tables'):
            print 'Database does not exist; cannot load from it'
        else:                
            local_euler_db = LocalEulerTables()
            # check that keys exist?
            self._set_euler_table(n, local_euler_db[ainvs_pairs][q][n], force)
Ejemplo n.º 36
0
    def segre_embedding(self, PP=None, var='u'):
        r"""
        Return the Segre embedding of ``self`` into the appropriate
        projective space.

        INPUT:

        -  ``PP`` -- (default: ``None``) ambient image projective space;
            this is constructed if it is not given.

        - ``var`` -- string, variable name of the image projective space, default `u` (optional)

        OUTPUT:

        Hom -- from ``self`` to the appropriate subscheme of projective space

        .. TODO::

            Cartesian products with more than two components

        EXAMPLES::

            sage: X.<y0,y1,y2,y3,y4,y5> = ProductProjectiveSpaces(ZZ,[2,2])
            sage: phi = X.segre_embedding(); phi
            Scheme morphism:
              From: Product of projective spaces P^2 x P^2 over Integer Ring
              To:   Closed subscheme of Projective Space of dimension 8 over Integer Ring defined by:
              -u5*u7 + u4*u8,
              -u5*u6 + u3*u8,
              -u4*u6 + u3*u7,
              -u2*u7 + u1*u8,
              -u2*u4 + u1*u5,
              -u2*u6 + u0*u8,
              -u1*u6 + u0*u7,
              -u2*u3 + u0*u5,
              -u1*u3 + u0*u4
              Defn: Defined by sending (y0 : y1 : y2 , y3 : y4 : y5) to
                    (y0*y3 : y0*y4 : y0*y5 : y1*y3 : y1*y4 : y1*y5 : y2*y3 : y2*y4 : y2*y5).

            ::

            sage: T = ProductProjectiveSpaces([1,2],CC,'z')
            sage: T.segre_embedding()
            Scheme morphism:
              From: Product of projective spaces P^1 x P^2 over Complex Field with 53 bits of precision
              To:   Closed subscheme of Projective Space of dimension 5 over Complex Field with 53 bits of precision defined by:
              -u2*u4 + u1*u5,
              -u2*u3 + u0*u5,
              -u1*u3 + u0*u4
              Defn: Defined by sending (z0 : z1 , z2 : z3 : z4) to
                    (z0*z2 : z0*z3 : z0*z4 : z1*z2 : z1*z3 : z1*z4).
        """
        N = self._dims
        if len(N) > 2:
            raise NotImplementedError("Cannot have more than two components.")
        M = (N[0]+1)*(N[1]+1)-1

        vars = list(self.coordinate_ring().variable_names()) + [var + str(i) for i in range(M+1)]
        R = PolynomialRing(self.base_ring(),self.ngens()+M+1, vars, order='lex')

        #set-up the elimination for the segre embedding
        mapping = []
        k = self.ngens()
        for i in range(N[0]+1):
            for j in range(N[0]+1,N[0]+N[1]+2):
                mapping.append(R.gen(k)-R(self.gen(i)*self.gen(j)))
                k+=1

        #change the defining ideal of the subscheme into the variables
        I = R.ideal(list(self.defining_polynomials()) + mapping)
        J = I.groebner_basis()
        s = set(R.gens()[:self.ngens()])
        n = len(J)-1
        L = []
        while s.isdisjoint(J[n].variables()):
            L.append(J[n])
            n = n-1

        #create new subscheme
        if PP is None:
            PS = ProjectiveSpace(self.base_ring(),M,R.gens()[self.ngens():])
            Y = PS.subscheme(L)
        else:
            if PP.dimension_relative()!= M:
                raise ValueError("Projective Space %s must be dimension %s")%(PP, M)
            S = PP.coordinate_ring()
            psi = R.hom([0]*(N[0]+N[1]+2) + list(S.gens()),S)
            L = [psi(l) for l in L]
            Y = PP.subscheme(L)

        #create embedding for points
        mapping = []
        for i in range(N[0]+1):
            for j in range(N[0]+1,N[0]+N[1]+2):
                mapping.append(self.gen(i)*self.gen(j))
        phi = self.hom(mapping,Y)

        return phi
Ejemplo n.º 37
0
    def to_sage(self):
        """
        EXAMPLES:
            sage: macaulay2(ZZ).to_sage()      #optional
            Integer Ring
            sage: macaulay2(QQ).to_sage()      #optional
            Rational Field

            sage: macaulay2(2).to_sage()       #optional
            2
            sage: macaulay2(1/2).to_sage()     #optional
            1/2
            sage: macaulay2(2/1).to_sage()     #optional
            2
            sage: _.parent()                   #optional
            Rational Field
            sage: macaulay2([1,2,3]).to_sage() #optional
            [1, 2, 3]

            sage: m = matrix([[1,2],[3,4]])
            sage: macaulay2(m).to_sage()       #optional
            [1 2]
            [3 4]

            sage: macaulay2(QQ['x,y']).to_sage()    #optional
            Multivariate Polynomial Ring in x, y over Rational Field
            sage: macaulay2(QQ['x']).to_sage()      #optional
            Univariate Polynomial Ring in x over Rational Field
            sage: macaulay2(GF(7)['x,y']).to_sage() #optional
            Multivariate Polynomial Ring in x, y over Finite Field of size 7

            sage: macaulay2(GF(7)).to_sage()       #optional
            Finite Field of size 7
            sage: macaulay2(GF(49, 'a')).to_sage() #optional
            Finite Field in a of size 7^2

            sage: R.<x,y> = QQ[]
            sage: macaulay2(x^2+y^2+1).to_sage()   #optional
            x^2 + y^2 + 1

            sage: R = macaulay2("QQ[x,y]")         #optional
            sage: I = macaulay2("ideal (x,y)")     #optional
            sage: I.to_sage()                      #optional
            Ideal (x, y) of Multivariate Polynomial Ring in x, y over Rational Field

            sage: X = R/I       #optional
            sage: X.to_sage()   #optional
            Quotient of Multivariate Polynomial Ring in x, y over Rational Field by the ideal (x, y)

            sage: R = macaulay2("QQ^2")  #optional
            sage: R.to_sage()            #optional
            Vector space of dimension 2 over Rational Field

            sage: m = macaulay2('"hello"')  #optional
            sage: m.to_sage()               #optional
            'hello'

        """
        repr_str = str(self)
        cls_str = str(self.cls())
        cls_cls_str = str(self.cls().cls())

        if repr_str == "ZZ":
            from sage.rings.all import ZZ
            return ZZ
        elif repr_str == "QQ":
            from sage.rings.all import QQ
            return QQ

        if cls_cls_str == "Type":
            if cls_str == "List":
                return [entry.to_sage() for entry in self]
            elif cls_str == "Matrix":
                from sage.matrix.all import matrix
                base_ring = self.ring().to_sage()
                entries = self.entries().to_sage()
                return matrix(base_ring, entries)
            elif cls_str == "Ideal":
                parent = self.ring().to_sage()
                gens = self.gens().entries().flatten().to_sage()
                return parent.ideal(*gens)
            elif cls_str == "QuotientRing":
                #Handle the ZZ/n case
                if "ZZ" in repr_str and "--" in repr_str:
                    from sage.rings.all import ZZ, GF
                    external_string = self.external_string()
                    zz, n = external_string.split("/")

                    #Note that n must be prime since it is
                    #coming from Macaulay 2
                    return GF(ZZ(n))

                ambient = self.ambient().to_sage()
                ideal = self.ideal().to_sage()
                return ambient.quotient(ideal)
            elif cls_str == "PolynomialRing":
                from sage.rings.all import PolynomialRing
                from sage.rings.polynomial.term_order import inv_macaulay2_name_mapping

                #Get the base ring
                base_ring = self.coefficientRing().to_sage()

                #Get a string list of generators
                gens = str(self.gens())[1:-1]

                # Check that we are dealing with default degrees, i.e. 1's.
                if self.degrees().any("x -> x != {1}").to_sage():
                    raise ValueError, "cannot convert Macaulay2 polynomial ring with non-default degrees to Sage"
                #Handle the term order
                external_string = self.external_string()
                order = None
                if "MonomialOrder" not in external_string:
                    order = "degrevlex"
                else:
                    for order_name in inv_macaulay2_name_mapping:
                        if order_name in external_string:
                            order = inv_macaulay2_name_mapping[order_name]
                if len(gens) > 1 and order is None:
                    raise ValueError, "cannot convert Macaulay2's term order to a Sage term order"

                return PolynomialRing(base_ring, order=order, names=gens)
            elif cls_str == "GaloisField":
                from sage.rings.all import ZZ, GF
                gf, n = repr_str.split(" ")
                n = ZZ(n)
                if n.is_prime():
                    return GF(n)
                else:
                    gen = str(self.gens())[1:-1]
                    return GF(n, gen)
            elif cls_str == "Boolean":
                if repr_str == "true":
                    return True
                elif repr_str == "false":
                    return False
            elif cls_str == "String":
                return str(repr_str)
            elif cls_str == "Module":
                from sage.modules.all import FreeModule
                if self.isFreeModule().to_sage():
                    ring = self.ring().to_sage()
                    rank = self.rank().to_sage()
                    return FreeModule(ring, rank)
        else:
            #Handle the integers and rationals separately
            if cls_str == "ZZ":
                from sage.rings.all import ZZ
                return ZZ(repr_str)
            elif cls_str == "QQ":
                from sage.rings.all import QQ
                repr_str = self.external_string()
                if "/" not in repr_str:
                    repr_str = repr_str + "/1"
                return QQ(repr_str)

            m2_parent = self.cls()
            parent = m2_parent.to_sage()

            if cls_cls_str == "PolynomialRing":
                from sage.misc.sage_eval import sage_eval
                gens_dict = parent.gens_dict()
                return sage_eval(self.external_string(), gens_dict)

        from sage.misc.sage_eval import sage_eval
        try:
            return sage_eval(repr_str)
        except Exception:
            raise NotImplementedError, "cannot convert %s to a Sage object" % repr_str
Ejemplo n.º 38
0
    def parametrization(self, point=None, morphism=True):
        r"""
        Return a parametrization `f` of ``self`` together with the
        inverse of `f`.

        If ``point`` is specified, then that point is used
        for the parametrization. Otherwise, use ``self.rational_point()``
        to find a point.

        If ``morphism`` is True, then `f` is returned in the form
        of a Scheme morphism. Otherwise, it is a tuple of polynomials
        that gives the parametrization.

        EXAMPLES:

        An example over a finite field ::

            sage: c = Conic(GF(2), [1,1,1,1,1,0])
            sage: c.parametrization()
            (Scheme morphism:
              From: Projective Space of dimension 1 over Finite Field of size 2
              To:   Projective Conic Curve over Finite Field of size 2 defined by x^2 + x*y
            + y^2 + x*z + y*z
              Defn: Defined on coordinates by sending (x : y) to
                    (x*y + y^2 : x^2 + x*y : x^2 + x*y + y^2),
             Scheme morphism:
              From: Projective Conic Curve over Finite Field of size 2 defined by x^2 + x*y
            + y^2 + x*z + y*z
              To:   Projective Space of dimension 1 over Finite Field of size 2
              Defn: Defined on coordinates by sending (x : y : z) to
                    (y : x))

        An example with ``morphism = False`` ::

            sage: R.<x,y,z> = QQ[]
            sage: C = Curve(7*x^2 + 2*y*z + z^2)
            sage: (p, i) = C.parametrization(morphism = False); (p, i)
            ([-2*x*y, x^2 + 7*y^2, -2*x^2], [-1/2*x, 1/7*y + 1/14*z])
            sage: C.defining_polynomial()(p)
            0
            sage: i[0](p) / i[1](p)
            x/y

        A ``ValueError`` is raised if ``self`` has no rational point ::

            sage: C = Conic(x^2 + y^2 + 7*z^2)
            sage: C.parametrization()
            Traceback (most recent call last):
            ...
            ValueError: Conic Projective Conic Curve over Rational Field defined by x^2 + y^2 + 7*z^2 has no rational points over Rational Field!

        A ``ValueError`` is raised if ``self`` is not smooth ::

            sage: C = Conic(x^2 + y^2)
            sage: C.parametrization()
            Traceback (most recent call last):
            ...
            ValueError: The conic self (=Projective Conic Curve over Rational Field defined by x^2 + y^2) is not smooth, hence does not have a parametrization.
        """
        if (not self._parametrization is None) and not point:
            par = self._parametrization
        else:
            if not self.is_smooth():
                raise ValueError("The conic self (=%s) is not smooth, hence does not have a parametrization." % self)
            if point is None:
                point = self.rational_point()
            point = Sequence(point)
            B = self.base_ring()
            Q = PolynomialRing(B, 'x,y')
            [x, y] = Q.gens()
            gens = self.ambient_space().gens()
            P = PolynomialRing(B, 4, ['X', 'Y', 'T0', 'T1'])
            [X, Y, T0, T1] = P.gens()
            c3 = [j for j in range(2,-1,-1) if point[j] != 0][0]
            c1 = [j for j in range(3) if j != c3][0]
            c2 = [j for j in range(3) if j != c3 and j != c1][0]
            L = [0,0,0]
            L[c1] = Y*T1*point[c1] + Y*T0
            L[c2] = Y*T1*point[c2] + X*T0
            L[c3] = Y*T1*point[c3]
            bezout = P(self.defining_polynomial()(L) / T0)
            t = [bezout([x,y,0,-1]),bezout([x,y,1,0])]
            par = (tuple([Q(p([x,y,t[0],t[1]])/y) for  p in L]),
                   tuple([gens[m]*point[c3]-gens[c3]*point[m]
                       for m in [c2,c1]]))
            if self._parametrization is None:
                self._parametrization = par
        if not morphism:
            return par
        P1 = ProjectiveSpace(self.base_ring(), 1, 'x,y')
        return P1.hom(par[0],self), self.Hom(P1)(par[1], check = False)
Ejemplo n.º 39
0
 def sage(self, var="x", base_field=RationalField()):
     from sage.rings.all import PolynomialRing, QQ, Integer
     PP = PolynomialRing(QQ, var)
     return PP([Integer(val) for val in self])
Ejemplo n.º 40
0
def Conic(base_field, F=None, names=None, unique=True):
    r"""
    Return the plane projective conic curve defined by ``F``
    over ``base_field``.
    
    The input form ``Conic(F, names=None)`` is also accepted,
    in which case the fraction field of the base ring of ``F``
    is used as base field.

    INPUT:
    
    - ``base_field`` -- The base field of the conic.
    
    - ``names`` -- a list, tuple, or comma separated string
      of three variable names specifying the names
      of the coordinate functions of the ambient
      space `\Bold{P}^3`. If not specified or read
      off from ``F``, then this defaults to ``'x,y,z'``.

    - ``F`` -- a polynomial, list, matrix, ternary quadratic form,
      or list or tuple of 5 points in the plane.
                   
                   If ``F`` is a polynomial or quadratic form,
                   then the output is the curve in the projective plane
                   defined by ``F = 0``.

                   If ``F`` is a polynomial, then it must be a polynomial
                   of degree at most 2 in 2 variables, or a homogeneous
                   polynomial in of degree 2 in 3 variables.
                   
                   If ``F`` is a matrix, then the output is the zero locus
                   of `(x,y,z) F (x,y,z)^t`.
    
                   If ``F`` is a list of coefficients, then it has
                   length 3 or 6 and gives the coefficients of
                   the monomials `x^2, y^2, z^2` or all 6 monomials
                   `x^2, xy, xz, y^2, yz, z^2` in lexicographic order.

                   If ``F`` is a list of 5 points in the plane, then the output
                   is a conic through those points.
      
    - ``unique`` -- Used only if ``F`` is a list of points in the plane.
      If the conic through the points is not unique, then
      raise ``ValueError`` if and only if ``unique`` is True
                    
    OUTPUT:
    
    A plane projective conic curve defined by ``F`` over a field.
    
    EXAMPLES:
    
    Conic curves given by polynomials ::

        sage: X,Y,Z = QQ['X,Y,Z'].gens()
        sage: Conic(X^2 - X*Y + Y^2 - Z^2)
        Projective Conic Curve over Rational Field defined by X^2 - X*Y + Y^2 - Z^2
        sage: x,y = GF(7)['x,y'].gens()
        sage: Conic(x^2 - x + 2*y^2 - 3, 'U,V,W')
        Projective Conic Curve over Finite Field of size 7 defined by U^2 + 2*V^2 - U*W - 3*W^2

    Conic curves given by matrices ::

        sage: Conic(matrix(QQ, [[1, 2, 0], [4, 0, 0], [7, 0, 9]]), 'x,y,z')
        Projective Conic Curve over Rational Field defined by x^2 + 6*x*y + 7*x*z + 9*z^2

        sage: x,y,z = GF(11)['x,y,z'].gens()
        sage: C = Conic(x^2+y^2-2*z^2); C
        Projective Conic Curve over Finite Field of size 11 defined by x^2 + y^2 - 2*z^2
        sage: Conic(C.symmetric_matrix(), 'x,y,z')
        Projective Conic Curve over Finite Field of size 11 defined by x^2 + y^2 - 2*z^2

    Conics given by coefficients ::
    
        sage: Conic(QQ, [1,2,3])
        Projective Conic Curve over Rational Field defined by x^2 + 2*y^2 + 3*z^2
        sage: Conic(GF(7), [1,2,3,4,5,6], 'X')
        Projective Conic Curve over Finite Field of size 7 defined by X0^2 + 2*X0*X1 - 3*X1^2 + 3*X0*X2 - 2*X1*X2 - X2^2
    
    The conic through a set of points ::

        sage: C = Conic(QQ, [[10,2],[3,4],[-7,6],[7,8],[9,10]]); C
        Projective Conic Curve over Rational Field defined by x^2 + 13/4*x*y - 17/4*y^2 - 35/2*x*z + 91/4*y*z - 37/2*z^2
        sage: C.rational_point()
        (10 : 2 : 1)
        sage: C.point([3,4])
        (3 : 4 : 1)

        sage: a=AffineSpace(GF(13),2)
        sage: Conic([a([x,x^2]) for x in range(5)])
        Projective Conic Curve over Finite Field of size 13 defined by x^2 - y*z
    """
    if not (is_IntegralDomain(base_field) or base_field == None):
        if names is None:
            names = F
        F = base_field
        base_field = None
    if isinstance(F, (list,tuple)):
        if len(F) == 1:
            return Conic(base_field, F[0], names)
        if names == None:
            names = 'x,y,z'
        if len(F) == 5:
            L=[]
            for f in F:
                if isinstance(f, SchemeMorphism_point_affine):
                    C = Sequence(f, universe = base_field)
                    if len(C) != 2:
                        raise TypeError, "points in F (=%s) must be planar"%F
                    C.append(1)
                elif isinstance(f, SchemeMorphism_point_projective_field):
                    C = Sequence(f, universe = base_field)
                elif isinstance(f, (list, tuple)):
                    C = Sequence(f, universe = base_field)
                    if len(C) == 2:
                        C.append(1)
                else:
                    raise TypeError, "F (=%s) must be a sequence of planar " \
                                      "points" % F
                if len(C) != 3:
                    raise TypeError, "points in F (=%s) must be planar" % F
                P = C.universe()
                if not is_IntegralDomain(P):
                    raise TypeError, "coordinates of points in F (=%s) must " \
                                     "be in an integral domain" % F
                L.append(Sequence([C[0]**2, C[0]*C[1], C[0]*C[2], C[1]**2,
                                   C[1]*C[2], C[2]**2], P.fraction_field()))
            M=Matrix(L)
            if unique and M.rank() != 5:
                raise ValueError, "points in F (=%s) do not define a unique " \
                                   "conic" % F
            con = Conic(base_field, Sequence(M.right_kernel().gen()), names)
            con.point(F[0])
            return con
        F = Sequence(F, universe = base_field)
        base_field = F.universe().fraction_field()
        temp_ring = PolynomialRing(base_field, 3, names)
        (x,y,z) = temp_ring.gens()
        if len(F) == 3:
            return Conic(F[0]*x**2 + F[1]*y**2 + F[2]*z**2)
        if len(F) == 6:
            return Conic(F[0]*x**2 + F[1]*x*y + F[2]*x*z + F[3]*y**2 + \
                         F[4]*y*z + F[5]*z**2)
        raise TypeError, "F (=%s) must be a sequence of 3 or 6" \
                         "coefficients" % F
    if is_QuadraticForm(F):
        F = F.matrix()
    if is_Matrix(F) and F.is_square() and F.ncols() == 3:
        if names == None:
            names = 'x,y,z'
        temp_ring = PolynomialRing(F.base_ring(), 3, names)
        F = vector(temp_ring.gens()) * F * vector(temp_ring.gens())

    if not is_MPolynomial(F):
        raise TypeError, "F (=%s) must be a three-variable polynomial or " \
                         "a sequence of points or coefficients" % F

    if F.total_degree() != 2:
        raise TypeError, "F (=%s) must have degree 2" % F

    if base_field == None:
        base_field = F.base_ring()
    if not is_IntegralDomain(base_field):
        raise ValueError, "Base field (=%s) must be a field" % base_field
    base_field = base_field.fraction_field()
    if names == None:
        names = F.parent().variable_names()
    pol_ring = PolynomialRing(base_field, 3, names)

    if F.parent().ngens() == 2:
        (x,y,z) = pol_ring.gens()
        F = pol_ring(F(x/z,y/z)*z**2)    

    if F == 0:
        raise ValueError, "F must be nonzero over base field %s" % base_field

    if F.total_degree() != 2:
        raise TypeError, "F (=%s) must have degree 2 over base field %s" % \
                          (F, base_field)

    if F.parent().ngens() == 3:
        P2 = ProjectiveSpace(2, base_field, names)
        if is_PrimeFiniteField(base_field):
            return ProjectiveConic_prime_finite_field(P2, F)
        if is_FiniteField(base_field):
            return ProjectiveConic_finite_field(P2, F)
        if is_RationalField(base_field):
            return ProjectiveConic_rational_field(P2, F)
        if is_NumberField(base_field):
            return ProjectiveConic_number_field(P2, F)
        return ProjectiveConic_field(P2, F)

    raise TypeError, "Number of variables of F (=%s) must be 2 or 3" % F
Ejemplo n.º 41
0
    def segre_embedding(self, PP=None, var='u'):
        r"""
        Return the Segre embedding of this space into the appropriate
        projective space.

        INPUT:

        -  ``PP`` -- (default: ``None``) ambient image projective space;
            this is constructed if it is not given.

        - ``var`` -- string, variable name of the image projective space, default `u` (optional).

        OUTPUT:

        Hom -- from this space to the appropriate subscheme of projective space.

        .. TODO::

            Cartesian products with more than two components.

        EXAMPLES::

            sage: X.<y0,y1,y2,y3,y4,y5> = ProductProjectiveSpaces(ZZ, [2, 2])
            sage: phi = X.segre_embedding(); phi
            Scheme morphism:
              From: Product of projective spaces P^2 x P^2 over Integer Ring
              To:   Closed subscheme of Projective Space of dimension 8 over Integer Ring defined by:
              -u5*u7 + u4*u8,
              -u5*u6 + u3*u8,
              -u4*u6 + u3*u7,
              -u2*u7 + u1*u8,
              -u2*u4 + u1*u5,
              -u2*u6 + u0*u8,
              -u1*u6 + u0*u7,
              -u2*u3 + u0*u5,
              -u1*u3 + u0*u4
              Defn: Defined by sending (y0 : y1 : y2 , y3 : y4 : y5) to
                    (y0*y3 : y0*y4 : y0*y5 : y1*y3 : y1*y4 : y1*y5 : y2*y3 : y2*y4 : y2*y5).

            ::

            sage: T = ProductProjectiveSpaces([1, 2], CC, 'z')
            sage: T.segre_embedding()
            Scheme morphism:
              From: Product of projective spaces P^1 x P^2 over Complex Field with 53 bits of precision
              To:   Closed subscheme of Projective Space of dimension 5 over Complex Field with 53 bits of precision defined by:
              -u2*u4 + u1*u5,
              -u2*u3 + u0*u5,
              -u1*u3 + u0*u4
              Defn: Defined by sending (z0 : z1 , z2 : z3 : z4) to
                    (z0*z2 : z0*z3 : z0*z4 : z1*z2 : z1*z3 : z1*z4).

            ::

            sage: T = ProductProjectiveSpaces([1, 2, 1], QQ, 'z')
            sage: T.segre_embedding()
            Scheme morphism:
              From: Product of projective spaces P^1 x P^2 x P^1 over Rational Field
              To:   Closed subscheme of Projective Space of dimension 11 over
            Rational Field defined by:
              -u9*u10 + u8*u11,
              -u7*u10 + u6*u11,
              -u7*u8 + u6*u9,
              -u5*u10 + u4*u11,
              -u5*u8 + u4*u9,
              -u5*u6 + u4*u7,
              -u5*u9 + u3*u11,
              -u5*u8 + u3*u10,
              -u5*u8 + u2*u11,
              -u4*u8 + u2*u10,
              -u3*u8 + u2*u9,
              -u3*u6 + u2*u7,
              -u3*u4 + u2*u5,
              -u5*u7 + u1*u11,
              -u5*u6 + u1*u10,
              -u3*u7 + u1*u9,
              -u3*u6 + u1*u8,
              -u5*u6 + u0*u11,
              -u4*u6 + u0*u10,
              -u3*u6 + u0*u9,
              -u2*u6 + u0*u8,
              -u1*u6 + u0*u7,
              -u1*u4 + u0*u5,
              -u1*u2 + u0*u3
              Defn: Defined by sending (z0 : z1 , z2 : z3 : z4 , z5 : z6) to
                    (z0*z2*z5 : z0*z2*z6 : z0*z3*z5 : z0*z3*z6 : z0*z4*z5 : z0*z4*z6
            : z1*z2*z5 : z1*z2*z6 : z1*z3*z5 : z1*z3*z6 : z1*z4*z5 : z1*z4*z6).
        """
        N = self._dims
        M = prod([n+1 for n in N]) - 1
        CR = self.coordinate_ring()

        vars = list(self.coordinate_ring().variable_names()) + [var + str(i) for i in range(M+1)]
        R = PolynomialRing(self.base_ring(), self.ngens()+M+1, vars, order='lex')

        #set-up the elimination for the segre embedding
        mapping = []
        k = self.ngens()
        index = self.num_components()*[0]
        for count in range(M + 1):
            mapping.append(R.gen(k+count)-prod([CR(self[i].gen(index[i])) for i in range(len(index))]))
            for i in range(len(index)-1, -1, -1):
                if index[i] == N[i]:
                    index[i] = 0
                else:
                    index[i] += 1
                    break #only increment once

        #change the defining ideal of the subscheme into the variables
        I = R.ideal(list(self.defining_polynomials()) + mapping)
        J = I.groebner_basis()
        s = set(R.gens()[:self.ngens()])
        n = len(J)-1
        L = []
        while s.isdisjoint(J[n].variables()):
            L.append(J[n])
            n = n-1

        #create new subscheme
        if PP is None:
            PS = ProjectiveSpace(self.base_ring(), M, R.variable_names()[self.ngens():])
            Y = PS.subscheme(L)
        else:
            if PP.dimension_relative() != M:
                raise ValueError("projective Space %s must be dimension %s")%(PP, M)
            S = PP.coordinate_ring()
            psi = R.hom([0]*k + list(S.gens()), S)
            L = [psi(l) for l in L]
            Y = PP.subscheme(L)

        #create embedding for points
        mapping = []
        index = self.num_components()*[0]
        for count in range(M + 1):
            mapping.append(prod([CR(self[i].gen(index[i])) for i in range(len(index))]))
            for i in range(len(index)-1, -1, -1):
                if index[i] == N[i]:
                    index[i] = 0
                else:
                    index[i] += 1
                    break #only increment once
        phi = self.hom(mapping, Y)

        return phi
Ejemplo n.º 42
0
    - 82*x^2 + 28*n + 4)/(-720*n^6*x^4 - 1644*n^5*x^4 + 540*n^6*x^2 -
    1320*n^4*x^4 + 1233*n^5*x^2 - 429*n^3*x^4 + 180*n^6 + 980*n^4*x^2 -
    45*n^2*x^4 + 456*n^5 + 311*n^3*x^2 + 449*n^4 + 32*n^2*x^2 + 213*n^3 +
    48*n^2 + 4*n))*Dx + (144*n^5*x^5 - 420*n^4*x^5 - 180*n^5*x^3 - 1584*n^3*x^5
    + 165*n^4*x^3 - 1575*n^2*x^5 - 180*n^5*x + 1163*n^3*x^3 - 633*n*x^5 -
    501*n^4*x + 1303*n^2*x^3 - 90*x^5 - 599*n^3*x + 561*n*x^3 - 388*n^2*x +
    84*x^3 - 132*n*x - 18*x)/(-720*n^6*x^4 - 1644*n^5*x^4 + 540*n^6*x^2 -
    1320*n^4*x^4 + 1233*n^5*x^2 - 429*n^3*x^4 + 180*n^6 + 980*n^4*x^2 -
    45*n^2*x^4 + 456*n^5 + 311*n^3*x^2 + 449*n^4 + 32*n^2*x^2 + 213*n^3 +
    48*n^2 + 4*n)])
"""

from sage.rings.all import PolynomialRing, ZZ
from ore_algebra import OreAlgebra

Pols, (n, x) = PolynomialRing(ZZ, ('n', 'x')).objgens()
Alg, (Sn, Dx) = OreAlgebra(Pols, 'Sn', 'Dx').objgens()

ideal = Alg.ideal([

        -72-904*n-4986*n**2-16020*n**3-33410*n**4-47100*n**5-44172*n**6-25056*n**7-6480*n**8+1008*x**2+13044*n*x**2+71034*n**2*x**2+210375*n**3*x**2+364335*n**4*x**2+365457*n**5*x**2+190179*n**6*x**2+31320*n**7*x**2-6480*n**8*x**2-1800*x**4-25020*n*x**4-150372*n**2*x**4-510048*n**3*x**4-1067184*n**4*x**4-1409472*n**5*x**4-1146816*n**6*x**4-525312*n**7*x**4-103680*n**8*x**4+
        (-632*x-8312*n*x-46742*n**2*x-145356*n**3*x-269478*n**4*x-297432*n**5*x-180792*n**6*x-46656*n**7*x+3816*x**3+47520*n*x**3+250812*n**2*x**3+727164*n**3*x**3+1251180*n**4*x**3+1278180*n**5*x**3+717984*n**6*x**3+171072*n**7*x**3-3600*x**5-42840*n*x**5-216864*n**2*x**5-605088*n**3*x**5-1004544*n**4*x**5-991872*n**5*x**5-539136*n**6*x**5-124416*n**7*x**5)*Dx+
        (64+640*n+2656*n**2+5856*n**3+7236*n**4+4752*n**5+1296*n**6-868*x**2-9316*n*x**2-41149*n**2*x**2-95610*n**3*x**2-123237*n**4*x**2-83592*n**5*x**2-23328*n**6*x**2+1704*x**4+18036*n*x**4+78669*n**2*x**4+180762*n**3*x**4+230625*n**4*x**4+154872*n**5*x**4+42768*n**6*x**4-900*x**6-9360*n*x**6-40176*n**2*x**6-91008*n**3*x**6-114624*n**4*x**6-76032*n**5*x**6-20736*n**6*x**6)*Dx**2+
        (-1824*n*x-21792*n**2*x-108048*n**3*x-288060*n**4*x-445896*n**5*x-400788*n**6*x-193752*n**7*x-38880*n**8*x+5400*n*x**3+64980*n**2*x**3+327600*n**3*x**3+898380*n**4*x**3+1449000*n**5*x**3+1375920*n**6*x**3+712800*n**7*x**3+155520*n**8*x**3)*Sn+
        (96+1296*n+7416*n**2+23340*n**3+43668*n**4+48600*n**5+29808*n**6+7776*n**7+768*n*x**2+8616*n**2*x**2+39324*n**3*x**2+93528*n**4*x**2+122364*n**5*x**2+83592*n**6*x**2+23328*n**7*x**2-1080*n*x**4-11916*n**2*x**4-53604*n**3*x**4-126072*n**4*x**4-163728*n**5*x**4-111456*n**6*x**4-31104*n**7*x**4)*Dx*Sn,

        -5400-105480*n-921894*n**2-4761120*n**3-16159284*n**4-37911216*n**5-62936502*n**6-74364984*n**7-61974504*n**8-35484480*n**9-13242528*n**10-2892672*n**11-279936*n**12+129384*x**2+1892580*n*x**2+12015312*n**2*x**2+43193121*n**3*x**2+95701575*n**4*x**2+131196846*n**5*x**2+98852124*n**6*x**2+10703601*n**7*x**2-56892051*n**8*x**2-60342732*n**9*x**2-30114504*n**10*x**2-7791552*n**11*x**2-839808*n**12*x**2-1359792*x**4-21051288*n*x**4-144751216*n**2*x**4-583851859*n**3*x**4-1537579119*n**4*x**4-2785188713*n**5*x**4-3560012897*n**6*x**4-3237959820*n**7*x**4-2082127284*n**8*x**4-924290676*n**9*x**4-269209656*n**10*x**4-46243872*n**11*x**4-3545856*n**12*x**4+4784400*x**6+76503120*n*x**6+547035412*n**2*x**6+2312068003*n**3*x**6+6433195773*n**4*x**6+12418820978*n**5*x**6+17064655448*n**6*x**6+16828542087*n**7*x**6+11828817747*n**8*x**6+5783182056*n**9*x**6+1867777056*n**10*x**6+357944832*n**11*x**6+30792960*n**12*x**6-6463800*x**8-105459264*n*x**8-771454650*n**2*x**8-3343723785*n**3*x**8-9559454217*n**4*x**8-18985142175*n**5*x**8-26851473837*n**6*x**8-27246680724*n**7*x**8-19685010348*n**8*x**8-9874992096*n**9*x**8-3265152768*n**10*x**8-639000576*n**11*x**8-55987200*n**12*x**8+2910600*x**10+48143340*n*x**10+357510924*n**2*x**10+1574659656*n**3*x**10+4577650848*n**4*x**10+9245867904*n**5*x**10+13295069568*n**6*x**10+13705751808*n**7*x**10+10048822272*n**8*x**10+5108714496*n**9*x**10+1709227008*n**10*x**10+337913856*n**11*x**10+29859840*n**12*x**10+
        (-33000*x-555000*n*x-4110810*n**2*x-17685984*n**3*x-49070892*n**4*x-92127504*n**5*x-119350890*n**6*x-106644168*n**7*x-64400184*n**8*x-25038720*n**9*x-5645376*n**10*x-559872*n**11*x+929184*x**3+14492616*n*x**3+100446642*n**2*x**3+407717712*n**3*x**3+1075419702*n**4*x**3+1932881640*n**5*x**3+2412492228*n**6*x**3+2088674316*n**7*x**3+1228199760*n**8*x**3+466941024*n**9*x**3+103296384*n**10*x**3+10077696*n**11*x**3-6070944*x**5-92314064*n*x**5-624602362*n**2*x**5-2478730156*n**3*x**5-6402603824*n**4*x**5-11288513388*n**5*x**5-13845657870*n**6*x**5-11800443960*n**7*x**5-6842534616*n**8*x**5-2569322592*n**9*x**5-562158144*n**10*x**5-54307584*n**11*x**5+15191760*x**7+226758656*n*x**7+1507085686*n**2*x**7+5879513080*n**3*x**7+14942273834*n**4*x**7+25944633648*n**5*x**7+31369911012*n**6*x**7+26385003396*n**7*x**7+15115595328*n**8*x**7+5613929856*n**9*x**7+1216228608*n**10*x**7+116453376*n**11*x**7-15838200*x**9-233026488*n*x**9-1527463044*n**2*x**9-5880802428*n**3*x**9-14758732548*n**4*x**9-25322095260*n**5*x**9-30275079984*n**6*x**9-25198350480*n**7*x**9-14296383360*n**8*x**9-5262672384*n**9*x**9-1130941440*n**10*x**9-107495424*n**11*x**9+5821200*x**11+84644280*n*x**11+548643888*n**2*x**11+2089987776*n**3*x**11+5192713728*n**4*x**11+8825220864*n**5*x**11+10457685504*n**6*x**11+8631760896*n**7*x**11+4859523072*n**8*x**11+1776162816*n**9*x**11+379219968*n**10*x**11+35831808*n**11*x**11)*Dx+
        (-127116*x**2-1683972*n*x**2-9769107*n**2*x**2-32626704*n**3*x**2-69401658*n**4*x**2-98184600*n**5*x**2-93524139*n**6*x**2-59220396*n**7*x**2-23862600*n**8*x**2-5528736*n**9*x**2-559872*n**10*x**2+1235652*x**4+16340320*n*x**4+94671764*n**2*x**4+315934898*n**3*x**4+671781259*n**4*x**4+950275572*n**5*x**4+905174019*n**6*x**4+573165072*n**7*x**4+230925168*n**8*x**4+53483328*n**9*x**4+5412096*n**10*x**4-4351656*x**6-57385616*n*x**6-331761754*n**2*x**6-1105455826*n**3*x**6-2348151407*n**4*x**6-3319311384*n**5*x**6-3160178217*n**6*x**6-2000166588*n**7*x**6-805459464*n**8*x**6-186429600*n**9*x**6-18849024*n**10*x**6+6960120*x**8+91464280*n*x**8+527278436*n**2*x**8+1753070030*n**3*x**8+3717559717*n**4*x**8+5248348596*n**5*x**8+4991631093*n**6*x**8+3156609528*n**7*x**8+1270139616*n**8*x**8+293746176*n**9*x**8+29673216*n**10*x**8-5172300*x**10-67713132*n*x**10-389113131*n**2*x**10-1290378654*n**3*x**10-2730781959*n**4*x**10-3848942328*n**5*x**10-3655802916*n**6*x**10-2309277600*n**7*x**10-928288512*n**8*x**10-214493184*n**9*x**10-21648384*n**10*x**10+1455300*x**12+18978120*n*x**12+108693792*n**2*x**12+359456256*n**3*x**12+758994048*n**4*x**12+1067814144*n**5*x**12+1012700160*n**6*x**12+638889984*n**7*x**12+256545792*n**8*x**12+59222016*n**9*x**12+5971968*n**10*x**12)*Dx**2+
        (50688*x+721152*n*x+4483584*n**2*x+16102656*n**3*x+37203264*n**4*x+58222944*n**5*x+63169416*n**6*x+47639124*n**7*x+24518700*n**8*x+8209512*n**9*x+1609632*n**10*x+139968*n**11*x+2754792*n*x**3+40133340*n**2*x**3+256857168*n**3*x**3+954119016*n**4*x**3+2288062296*n**5*x**3+3724089648*n**6*x**3+4203524664*n**7*x**3+3294832572*n**8*x**3+1759833864*n**9*x**3+610765920*n**10*x**3+124104960*n**11*x**3+11197440*n**12*x**3-11506824*n*x**5-167233044*n**2*x**5-1069000116*n**3*x**5-3970620108*n**4*x**5-9530229264*n**5*x**5-15535043832*n**6*x**5-17566817004*n**7*x**5-13794112512*n**8*x**5-7379007984*n**9*x**5-2563762752*n**10*x**5-521240832*n**11*x**5-47029248*n**12*x**5+17451000*n*x**7+253133700*n**2*x**7+1616458560*n**3*x**7+6003388332*n**4*x**7+14418672312*n**5*x**7+23531831040*n**6*x**7+26649246528*n**7*x**7+20958160320*n**8*x**7+11226625920*n**9*x**7+3904547328*n**10*x**7+794271744*n**11*x**7+71663616*n**12*x**7-8731800*n*x**9-126384300*n**2*x**9-805886028*n**3*x**9-2990795472*n**4*x**9-7182502416*n**5*x**9-11726815104*n**6*x**9-13289785920*n**7*x**9-10460448000*n**8*x**9-5607823104*n**9*x**9-1951589376*n**10*x**9-397135872*n**11*x**9-35831808*n**12*x**9)*Sn+
        (-46080-761088*n-5602944*n**2-24290688*n**3-69000576*n**4-135145680*n**5-186937800*n**6-183825792*n**7-127461384*n**8-60764256*n**9-18911232*n**10-3452544*n**11-279936*n**12-368640*n*x**2-5247744*n**2*x**2-32684736*n**3*x**2-117586080*n**4*x**2-271573680*n**5*x**2-422997000*n**6*x**2-453713832*n**7*x**2-335454264*n**8*x**2-167741928*n**9*x**2-54105408*n**10*x**2-10147680*n**11*x**2-839808*n**12*x**2+518400*n*x**4+7283520*n**2*x**4+44859168*n**3*x**4+159936048*n**4*x**4+366849864*n**5*x**4+568549728*n**6*x**4+607740264*n**7*x**4+448328736*n**8*x**4+223881408*n**9*x**4+72161280*n**10*x**4+13530240*n**11*x**4+1119744*n**12*x**4)*Sn**2,
Ejemplo n.º 43
0
    def _sage_(self):
        """
        EXAMPLES:
            sage: m = lie('[[1,0,3,3],[12,4,-4,7],[-1,9,8,0],[3,-5,-2,9]]') # optional - lie
            sage: m.sage()  # optional - lie
            [ 1  0  3  3]
            [12  4 -4  7]
            [-1  9  8  0]
            [ 3 -5 -2  9]

        """
        t = self.type()
        if t == 'grp':
            raise ValueError(
                "cannot convert Lie groups to native Sage objects")
        elif t == 'mat':
            import sage.matrix.constructor
            return sage.matrix.constructor.matrix(
                eval(str(self).replace('\n', '').strip()))
        elif t == 'pol':
            import sage.misc.misc
            from sage.rings.all import PolynomialRing, QQ

            #Figure out the number of variables
            s = str(self)
            open_bracket = s.find('[')
            close_bracket = s.find(']')
            nvars = len(s[open_bracket:close_bracket].split(','))

            #create the polynomial ring
            R = PolynomialRing(QQ, nvars, 'x')
            x = R.gens()
            pol = R(0)

            #Split up the polynomials into terms
            terms = []
            for termgrp in s.split(' - '):
                #The first entry in termgrp has
                #a negative coefficient
                termgrp = "-" + termgrp.strip()
                terms += termgrp.split('+')
            #Make sure we don't accidentally add a negative
            #sign to the first monomial
            if s[0] != "-":
                terms[0] = terms[0][1:]

            #go through all the terms in s
            for term in terms:
                xpos = term.find('X')
                coef = eval(term[:xpos].strip())
                exps = eval(term[xpos + 1:].strip())
                monomial = sage.misc.misc.prod(
                    map(lambda i: x[i]**exps[i], range(nvars)))
                pol += coef * monomial

            return pol
        elif t == 'tex':
            return repr(self)
        elif t == 'vid':
            return None
        else:
            return ExpectElement._sage_(self)
Ejemplo n.º 44
0
    def __call__(self, P):
        r"""
        Returns a rational point P in the abstract Homset J(K), given:

        0. A point P in J = Jac(C), returning P; 1. A point P on the curve
        C such that J = Jac(C), where C is an odd degree model, returning
        [P - oo]; 2. A pair of points (P, Q) on the curve C such that J =
        Jac(C), returning [P-Q]; 2. A list of polynomials (a,b) such that
        `b^2 + h*b - f = 0 mod a`, returning [(a(x),y-b(x))].

        EXAMPLES::

            sage: P.<x> = PolynomialRing(QQ)
            sage: f = x^5 - x + 1; h = x
            sage: C = HyperellipticCurve(f,h,'u,v')
            sage: P = C(0,1,1)
            sage: J = C.jacobian()
            sage: Q = J(QQ)(P)
            sage: for i in range(6): i*Q
            (1)
            (u, v - 1)
            (u^2, v + u - 1)
            (u^2, v + 1)
            (u, v + 1)
            (1)

        ::

            sage: F.<a> = GF(3)
            sage: R.<x> = F[]
            sage: f = x^5-1
            sage: C = HyperellipticCurve(f)
            sage: J = C.jacobian()
            sage: X = J(F)
            sage: a = x^2-x+1
            sage: b = -x +1
            sage: c = x-1
            sage: d = 0
            sage: D1 = X([a,b])
            sage: D1
            (x^2 + 2*x + 1, y + x + 2)
            sage: D2 = X([c,d])
            sage: D2
            (x + 2, y)
            sage: D1+D2
            (x^2 + 2*x + 2, y + 2*x + 1)

        """
        if isinstance(P, (int, long, Integer)) and P == 0:
            R = PolynomialRing(self.value_ring(), 'x')
            return JacobianMorphism_divisor_class_field(self, (R(1), R(0)))
        elif isinstance(P, (list, tuple)):
            if len(P) == 1 and P[0] == 0:
                R = PolynomialRing(self.value_ring(), 'x')
                return JacobianMorphism_divisor_class_field(self, (R(1), R(0)))
            elif len(P) == 2:
                P1 = P[0]
                P2 = P[1]
                if is_Integer(P1) and is_Integer(P2):
                    R = PolynomialRing(self.value_ring(), 'x')
                    P1 = R(P1)
                    P2 = R(P2)
                    return JacobianMorphism_divisor_class_field(
                        self, tuple([P1, P2]))
                if is_Integer(P1) and is_Polynomial(P2):
                    R = PolynomialRing(self.value_ring(), 'x')
                    P1 = R(P1)
                    return JacobianMorphism_divisor_class_field(
                        self, tuple([P1, P2]))
                if is_Integer(P2) and is_Polynomial(P1):
                    R = PolynomialRing(self.value_ring(), 'x')
                    P2 = R(P2)
                    return JacobianMorphism_divisor_class_field(
                        self, tuple([P1, P2]))
                if is_Polynomial(P1) and is_Polynomial(P2):
                    return JacobianMorphism_divisor_class_field(self, tuple(P))
                if is_SchemeMorphism(P1) and is_SchemeMorphism(P2):
                    return self(P1) - self(P2)
            raise TypeError("Argument P (= %s) must have length 2." % P)
        elif isinstance(
                P,
                JacobianMorphism_divisor_class_field) and self == P.parent():
            return P
        elif is_SchemeMorphism(P):
            x0 = P[0]
            y0 = P[1]
            R, x = PolynomialRing(self.value_ring(), 'x').objgen()
            return self((x - x0, R(y0)))
        raise TypeError(
            "Argument P (= %s) does not determine a divisor class" % P)
Ejemplo n.º 45
0
def _normalize_2x2(G):
    r"""
    Normalize this indecomposable `2` by `2` block.

    INPUT:

    ``G`` - a `2` by `2` matrix over `\ZZ_p`
    with ``type = 'fixed-mod'`` of the form::

        [2a  b]
        [ b 2c] * 2^n

    with `b` of valuation 1.

    OUTPUT:

    A unimodular `2` by `2` matrix ``B`` over `\ZZ_p` with
    ``B * G * B.transpose()``
    either::

        [0 1]              [2 1]
        [1 0] * 2^n  or    [1 2] * 2^n

    EXAMPLES::

        sage: from sage.quadratic_forms.genera.normal_form import _normalize_2x2
        sage: R = Zp(2, prec = 15, type = 'fixed-mod', print_mode='series', show_prec=False)
        sage: G = Matrix(R, 2, [-17*2,3,3,23*2])
        sage: B =_normalize_2x2(G)
        sage: B * G * B.T
        [2 1]
        [1 2]

        sage: G = Matrix(R,2,[-17*4,3,3,23*2])
        sage: B = _normalize_2x2(G)
        sage: B*G*B.T
        [0 1]
        [1 0]

        sage: G = 2^3 * Matrix(R, 2, [-17*2,3,3,23*2])
        sage: B = _normalize_2x2(G)
        sage: B * G * B.T
        [2^4 2^3]
        [2^3 2^4]
    """
    from sage.rings.all import PolynomialRing
    from sage.modules.free_module_element import vector
    B = copy(G.parent().identity_matrix())
    R = G.base_ring()
    P = PolynomialRing(R, 'x')
    x = P.gen()

    # The input must be an even block
    odd1 = (G[0, 0].valuation() < G[1, 0].valuation())
    odd2 = (G[1, 1].valuation() < G[1, 0].valuation())
    if odd1 or odd2:
        raise ValueError("Not a valid 2 x 2 block.")
    scale = 2**G[0, 1].valuation()
    D = Matrix(R, 2, 2, [d // scale for d in G.list()])
    # now D is of the form
    # [2a b ]
    # [b  2c]
    # where b has valuation 1.
    G = copy(D)

    # Make sure G[1, 1] has valuation 1.
    if D[1, 1].valuation() > D[0, 0].valuation():
        B.swap_columns(0, 1)
        D.swap_columns(0, 1)
        D.swap_rows(0, 1)
    if D[1, 1].valuation() != 1:
        # this works because
        # D[0, 0] has valuation at least 2
        B[1, :] += B[0, :]
        D = B * G * B.transpose()
    assert D[1, 1].valuation() == 1

    if mod(D.det(), 8) == 3:
        #  in this case we can transform D to
        #  2 1
        #  1 2
        # Find a point of norm 2
        # solve: 2 == D[1,1]*x^2 + 2*D[1,0]*x + D[0,0]
        pol = (D[1, 1] * x**2 + 2 * D[1, 0] * x + D[0, 0] - 2) // 2
        # somehow else pari can get a hickup see trac #24065
        pol = pol // pol.leading_coefficient()
        sol = pol.roots()[0][0]
        B[0, 1] = sol
        D = B * G * B.transpose()
        # make D[0, 1] = 1
        B[1, :] *= D[1, 0].inverse_of_unit()
        D = B * G * B.transpose()

        # solve: v*D*v == 2 with v = (x, -2*x+1)
        if D[1, 1] != 2:
            v = vector([x, -2 * x + 1])
            pol = (v * D * v - 2) // 2
            # somehow else pari can get a hickup see trac #24065
            pol = pol // pol.leading_coefficient()
            sol = pol.roots()[0][0]
            B[1, :] = sol * B[0, :] + (-2 * sol + 1) * B[1, :]
            D = B * G * B.transpose()
        # check the result
        assert D == Matrix(G.parent(), 2, 2, [2, 1, 1, 2]), "D1 \n %r" % D
    elif mod(D.det(), 8) == 7:
        # in this case we can transform D to
        #  0 1
        #  1 0
        # Find a point representing 0
        # solve: 0 == D[1,1]*x^2 + 2*D[1,0]*x + D[0,0]
        pol = (D[1, 1] * x**2 + 2 * D[1, 0] * x + D[0, 0]) // 2
        # somehow else pari can get a hickup, see trac #24065
        pol = pol // pol.leading_coefficient()
        sol = pol.roots()[0][0]
        B[0, :] += sol * B[1, :]
        D = B * G * B.transpose()
        # make the second basis vector have 0 square as well.
        B[1, :] = B[1, :] - D[1, 1] // (2 * D[0, 1]) * B[0, :]
        D = B * G * B.transpose()
        # rescale to get D[0,1] = 1
        B[0, :] *= D[1, 0].inverse_of_unit()
        D = B * G * B.transpose()
        # check the result
        assert D == Matrix(G.parent(), 2, 2, [0, 1, 1, 0]), "D2 \n %r" % D
    return B
Ejemplo n.º 46
0
def _biquadratic_syzygy_quartic(quadratic1, quadratic2, variables=None):
    r"""
    Helper function for the Weierstrass form of a biquadratic in $`\mathbb{P}^3$

    The invariants and covariants of a quaternary biquadratic satisfy
    the relation
    :meth:`sage.rings.invariant_theory.TwoQuaternaryQuadratics.syzygy`,
    which is (modulo the two quadratic equations) of the form $J^2 =
    p_4(T, T')$ where

    * $J$, $T$, $T'$ are the covariants of the biquadratic.

    * $p_4$ is some quartic polynomial whose coefficients are
      invariants of the biquadratic.

    INPUT:

    See :func:`WeierstrassForm_P3`

    OUTPUT:

    A triple consisting of

    - The quaternary biquadratic as an algebraic form
      :class:`~sage.rings.invariant_theory.TwoQuaternaryQuadratics`

    - The binary quartic $p_4$ as a
      :class:`~sage.rings.invariant_theory.BinaryQuartic`

    - The dictionary of variable substitutions from the variables of
      the quartic to the variables of the biquadratic.

    EXAMPLES::

        sage: from sage.schemes.toric.weierstrass_higher import _biquadratic_syzygy_quartic
        sage: R.<w,x,y,z> = QQ[]
        sage: _biquadratic_syzygy_quartic(w^2+x^2+y^2, z^2)
        (Joint quaternary quadratic with coefficients (1, 1, 1, 0, 0, 0, 0, 0, 0, 0)
         and quaternary quadratic with coefficients (0, 0, 0, 1, 0, 0, 0, 0, 0, 0),
         Binary quartic with coefficients (0, 0, 0, -1, 0), {aux...})
    """
    w, x, y, z = _check_polynomials_P3(quadratic1, quadratic2, variables)
    biquadratic = invariant_theory.quaternary_biquadratic(
        quadratic1, quadratic2, [w, x, y, z])

    # construct auxiliary polynomial ring to work with the rhs of the syzygy
    R = biquadratic.ring()
    n = R.ngens()
    R_aux = PolynomialRing(R.base_ring(), n + 2, 'aux')
    to_aux = dict()
    from_aux = dict()
    for var, var_aux in zip(R.gens(), R_aux.gens()[0:n]):
        to_aux[var] = var_aux
        from_aux[var_aux] = var
    T, T_prime = R_aux.gens()[n:]
    from_aux[T] = biquadratic.T_covariant()
    from_aux[T_prime] = biquadratic.T_prime_covariant()

    # Syzygy is J^2 = syz_rhs + (terms that vanish on the biquadratic) with
    # J = biquadratic.J_covariant()
    syz_rhs = T**4 * biquadratic.Delta_invariant().subs(to_aux) \
        - T**3*T_prime * biquadratic.Theta_invariant().subs(to_aux) \
        + T**2*T_prime**2 * biquadratic.Phi_invariant().subs(to_aux) \
        - T*T_prime**3 * biquadratic.Theta_prime_invariant().subs(to_aux) \
        + T_prime**4 * biquadratic.Delta_prime_invariant().subs(to_aux)
    quartic = invariant_theory.binary_quartic(syz_rhs, [T, T_prime])
    return (biquadratic, quartic, from_aux)
Ejemplo n.º 47
0
def is_cm_j_invariant(j, method='new'):
    """
    Return whether or not this is a CM `j`-invariant.

    INPUT:

    - ``j`` -- an element of a number field `K`

    OUTPUT:

    A pair (bool, (d,f)) which is either (False, None) if `j` is not a
    CM j-invariant or (True, (d,f)) if `j` is the `j`-invariant of the
    imaginary quadratic order of discriminant `D=df^2` where `d` is
    the associated fundamental discriminant and `f` the index.

    .. note::

       The current implementation makes use of the classification of
       all orders of class number up to 100, and hence will raise an
       error if `j` is an algebraic integer of degree greater than
       this.  It would be possible to implement a more general
       version, using the fact that `d` must be supported on the
       primes dividing the discriminant of the minimal polynomial of
       `j`.

    EXAMPLES::

        sage: from sage.schemes.elliptic_curves.cm import is_cm_j_invariant
        sage: is_cm_j_invariant(0)
        (True, (-3, 1))
        sage: is_cm_j_invariant(8000)
        (True, (-8, 1))

        sage: K.<a> = QuadraticField(5)
        sage: is_cm_j_invariant(282880*a + 632000)
        (True, (-20, 1))
        sage: K.<a> = NumberField(x^3 - 2)
        sage: is_cm_j_invariant(31710790944000*a^2 + 39953093016000*a + 50337742902000)
        (True, (-3, 6))

    TESTS::

        sage: from sage.schemes.elliptic_curves.cm import is_cm_j_invariant
        sage: all([is_cm_j_invariant(j) == (True, (d,f)) for d,f,j in cm_j_invariants_and_orders(QQ)])
        True

    """
    # First we check that j is an algebraic number:

    from sage.rings.all import NumberFieldElement, NumberField
    if not isinstance(j, NumberFieldElement) and not j in QQ:
        raise NotImplementedError("is_cm_j_invariant() is only implemented for number field elements")

    # for j in ZZ we have a lookup-table:

    if j in ZZ:
        j = ZZ(j)
        table = dict([(jj,(d,f)) for d,f,jj in cm_j_invariants_and_orders(QQ)])
        if j in table:
            return True, table[j]
        return False, None

    # Otherwise if j is in Q then it is not integral so is not CM:

    if j in QQ:
        return False, None

    # Now j has degree at least 2.  If it is not integral so is not CM:

    if not j.is_integral():
        return False, None

    # Next we find its minimal polynomial and degree h, and if h is
    # less than the degree of j.parent() we recreate j as an element
    # of Q(j):

    jpol = PolynomialRing(QQ,'x')([-j,1]) if j in QQ else j.absolute_minpoly()
    h = jpol.degree()

    # This will be used as a fall-back if we cannot determine the
    # result using local data.  For this to be necessary there would
    # have to be very few primes of degree 1 and norm under 1000,
    # since we only need to find one prime of degree 1, good
    # reduction for which a_P is nonzero.
    if method=='old':
        if h>100:
            raise NotImplementedError("CM data only available for class numbers up to 100")
        for d,f in cm_orders(h):
            if jpol == hilbert_class_polynomial(d*f**2):
                return True, (d,f)
        return False, None

    # replace j by a clone whose parent is Q(j), if necessary:

    K = j.parent()
    if h < K.absolute_degree():
        K = NumberField(jpol, 'j')
        j = K.gen()

    # Construct an elliptic curve with j-invariant j, with
    # integral model:

    from sage.schemes.elliptic_curves.all import EllipticCurve
    E = EllipticCurve(j=j).integral_model()
    D = E.discriminant()
    prime_bound = 1000 # test primes of degree 1 up to this norm
    max_primes =    20 # test at most this many primes
    num_prime = 0
    cmd = 0
    cmf = 0

    # Test primes of good reduction.  If E has CM then for half the
    # primes P we will have a_P=0, and for all other prime P the CM
    # field is Q(sqrt(a_P^2-4N(P))).  Hence if these fields are
    # different for two primes then E does not have CM.  If they are
    # all equal for the primes tested, then we have a candidate CM
    # field.  Moreover the discriminant of the endomorphism ring
    # divides all the values a_P^2-4N(P), since that is the
    # discriminant of the order containing the Frobenius at P.  So we
    # end up with a finite number (usually one) of candidate
    # discriminats to test.  Each is tested by checking that its class
    # number is h, and if so then that j is a root of its Hilbert
    # class polynomial.  In practice non CM curves will be eliminated
    # by the local test at a small number of primes (probably just 2).

    for P in K.primes_of_degree_one_iter(prime_bound):
        if num_prime > max_primes:
            if cmd: # we have a candidate CM field already
                break
            else:   # we need to try more primes
                max_primes *=2
        if D.valuation(P)>0: # skip bad primes
            continue
        aP = E.reduction(P).trace_of_frobenius()
        if aP == 0: # skip supersingular primes
            continue
        num_prime += 1
        DP = aP**2 - 4*P.norm()
        dP = DP.squarefree_part()
        fP = ZZ(DP//dP).isqrt()
        if cmd==0:      # first one, so store d and f
            cmd = dP
            cmf = fP
        elif cmd != dP: # inconsistent with previous
            return False, None
        else:           # consistent d, so update f
            cmf = cmf.gcd(fP)

    if cmd==0: # no conclusion, we found no degree 1 primes, revert to old method
        return is_cm_j_invariant(j, method='old')

    # it looks like cm by disc cmd * f**2 where f divides cmf

    if cmd%4!=1:
        cmd = cmd*4
        cmf = cmf//2

    # Now we must check if h(cmd*f**2)==h for f|cmf; if so we check
    # whether j is a root of the associated Hilbert class polynomial.
    for f in cmf.divisors(): # only positive divisors
        d = cmd*f**2
        if h != d.class_number():
            continue
        pol = hilbert_class_polynomial(d)
        if pol(j)==0:
            return True, (cmd,f)
    return False, None
Ejemplo n.º 48
0
def _solve_mod_prime_power(eqns, p, m, vars):
    r"""
    Internal help function for solve_mod, does little checking since it expects
    solve_mod to do that

    Return all solutions to an equation or list of equations modulo p^m.
    Each equation must involve only polynomials
    in 1 or many variables.

    The solutions are returned as `n`-tuples, where `n`
    is the number of variables in vars.

    INPUT:


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

    -  ``p`` - a prime

    -  ``i`` - an integer > 0

    -  ``vars`` - a list of variables to solve for


    EXAMPLES::

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

    Fermat's equation modulo 3 with exponent 5::

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

    We solve a simple equation modulo 2::

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


    .. warning::

       Currently this constructs possible solutions by building up
       from the smallest prime factor of the modulus.  The interface
       is good, but the algorithm is horrible if the modulus isn't the
       product of many small primes! Sage *does* have the ability to
       do something much faster in certain cases at least by using the
       Chinese Remainder Theorem, Groebner basis, linear algebra
       techniques, etc. But for a lot of toy problems this function as
       is might be useful. At the very least, it establishes an
       interface.

    TESTS:

    Confirm we can reproduce the first few terms of :oeis:`A187719`::

        sage: from sage.symbolic.relation import _solve_mod_prime_power
        sage: [sorted(_solve_mod_prime_power([x^2==41], 10, i, [x]))[0][0] for i in [1..13]]
        [1, 21, 71, 1179, 2429, 47571, 1296179, 8703821, 26452429, 526452429,
        13241296179, 19473547571, 2263241296179]

    """
    from sage.rings.all import Integers, PolynomialRing
    from sage.modules.all import vector
    from sage.misc.all import cartesian_product_iterator

    mrunning = 1
    ans = []
    for mi in range(m):
        mrunning *= p
        R = Integers(mrunning)
        S = PolynomialRing(R, len(vars), vars)
        eqns_mod = [S(eq) for eq in eqns]
        if mi == 0:
            possibles = cartesian_product_iterator(
                [range(len(R)) for _ in range(len(vars))])
        else:
            shifts = cartesian_product_iterator(
                [range(p) for _ in range(len(vars))])
            pairs = cartesian_product_iterator([shifts, ans])
            possibles = (tuple(vector(t) + vector(shift) * (mrunning // p))
                         for shift, t in pairs)
        ans = list(t for t in possibles if all(e(*t) == 0 for e in eqns_mod))
        if not ans: return ans

    return ans
    def has_rational_point(self, point = False, algorithm = 'default',
        read_cache = True):
        r"""
        Returns True if and only if the conic ``self``
        has a point over its base field `F(t)`, which is a field of rational
        functions.

        If ``point`` is True, then returns a second output, which is
        a rational point if one exists.

        Points are cached whenever they are found. Cached information
        is used if and only if ``read_cache`` is True.
        
        The default algorithm does not (yet) work for all base fields `F`.
        In particular, sage is required to have:
        
        * an algorithm for finding the square root of elements in finite
          extensions of `F`;
        
        * a factorization and gcd algorithm for `F[t]`;
        
        * an algorithm for solving conics over `F`.
        
        ALGORITHM:
        
        The parameter ``algorithm`` specifies the algorithm
        to be used:

        * ``'default'`` -- use a native Sage implementation, based on the
          algorithm Conic in [HC2006]_.

        * ``'magma'`` (requires Magma to be installed) --
          delegates the task to the Magma computer algebra
          system.
        
        EXAMPLES:
        
        We can find points for function fields over (extensions of) `\QQ`
        and finite fields::
        
            sage: K.<t> = FractionField(PolynomialRing(QQ, 't'))
            sage: C = Conic(K, [t^2-2, 2*t^3, -2*t^3-13*t^2-2*t+18])
            sage: C.has_rational_point(point=True)
            (True, (-3 : (t + 1)/t : 1))
            sage: R.<t> = FiniteField(23)[]
            sage: C = Conic([2, t^2+1, t^2+5])
            sage: C.has_rational_point()
            True
            sage: C.has_rational_point(point=True)
            (True, (5*t : 8 : 1))
            sage: F.<i> = QuadraticField(-1)
            sage: R.<t> = F[]
            sage: C = Conic([1,i*t,-t^2+4])
            sage: C.has_rational_point(point = True)
            verbose 0 (3369: multi_polynomial_ideal.py, groebner_basis) Warning: falling back to very slow toy implementation.
            ...
            (True, (-t - 2*i : -2*i : 1))

        It works on non-diagonal conics as well::

            sage: K.<t> = QQ[]
            sage: C = Conic([4, -4, 8, 1, -4, t + 4])
            sage: C.has_rational_point(point=True)
            (True, (1/2 : 1 : 0))

        If no point exists output still depends on the argument ``point``::

            sage: K.<t> = QQ[]
            sage: C = Conic(K, [t^2, (t-1), -2*(t-1)])
            sage: C.has_rational_point()
            False
            sage: C.has_rational_point(point=True)
            (False, None)
        
        Due to limitations in Sage of algorithms we depend on, it is not
        yet possible to find points on conics over multivariate function fields
        (see the requirements above)::
        
            sage: F.<t1> = FractionField(QQ['t1'])
            sage: K.<t2> = FractionField(F['t2'])
            sage: a = K(1)
            sage: b = 2*t2^2+2*t1*t2-t1^2
            sage: c = -3*t2^4-4*t1*t2^3+8*t1^2*t2^2+16*t1^3-t2-48*t1^4
            sage: C = Conic([a,b,c])
            sage: C.has_rational_point()
            ...
            Traceback (most recent call last):
            ...
            NotImplementedError: is_square() not implemented for elements of
            Univariate Quotient Polynomial Ring in tbar over Fraction Field
            of Univariate Polynomial Ring in t1 over Rational Field with
            modulus tbar^2 + t1*tbar - 1/2*t1^2
        
        In some cases, the algorithm requires us to be
        able to solve conics over `F`. In particular, the following does not
        work::

            sage: P.<u> = QQ[]
            sage: E = P.fraction_field()
            sage: Q.<Y> = E[]
            sage: F.<v> = E.extension(Y^2 - u^3 - 1)
            sage: R.<t> = F[]
            sage: K = R.fraction_field()
            sage: C = Conic(K, [u, v, 1])
            sage: C.has_rational_point()
            ...
            Traceback (most recent call last):
            ...
            NotImplementedError: has_rational_point not implemented for conics
            over base field Univariate Quotient Polynomial Ring in v over
            Fraction Field of Univariate Polynomial Ring in u over Rational
            Field with modulus v^2 - u^3 - 1

        ``has_rational_point`` fails for some conics over function fields
        over finite fields, due to :trac:`20003`::

            sage: K.<t> = PolynomialRing(GF(7))
            sage: C = Conic([5*t^2+4, t^2+3*t+3, 6*t^2+3*t+2, 5*t^2+5, 4*t+3, 4*t^2+t+5])
            sage: C.has_rational_point()
            ...
            Traceback (most recent call last):
            ...
            TypeError: self (=Scheme morphism:
              From: Projective Conic Curve over Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 7 defined by (5*t^2 + 4)*x^2 + ((6*t^3 + 3*t^2 + 5*t + 5)/(t + 3))*y^2 + ((6*t^6 + 3*t^5 + t^3 + 6*t^2 + 6*t + 2)/(t^4 + t^3 + 4*t^2 + 3*t + 1))*z^2
              To:   Projective Conic Curve over Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 7 defined by (5*t^2 + 4)*x^2 + (t^2 + 3*t + 3)*x*y + (5*t^2 + 5)*y^2 + (6*t^2 + 3*t + 2)*x*z + (4*t + 3)*y*z + (4*t^2 + t + 5)*z^2
              Defn: Defined on coordinates by sending (x : y : z) to
                    (x + ((2*t + 5)/(t + 3))*y + ((3*t^4 + 2*t^3 + 5*t^2 + 5*t + 3)/(t^4 + t^3 + 4*t^2 + 3*t + 1))*z : y + ((6*t^3 + 6*t^2 + 3*t + 6)/(t^3 + 4*t^2 + 2*t + 2))*z : z)) domain must equal right (=Scheme morphism:
              From: Projective Conic Curve over Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 7 defined by (5*t^3 + 6*t^2 + 3*t + 3)*x^2 + (t + 4)*y^2 + (6*t^7 + 2*t^5 + t^4 + 2*t^3 + 3*t^2 + 6*t + 6)*z^2
              To:   Projective Conic Curve over Fraction Field of Univariate Polynomial Ring in t over Finite Field of size 7 defined by (5/(t^3 + 4*t^2 + 2*t + 2))*x^2 + (1/(t^3 + 3*t^2 + 5*t + 1))*y^2 + ((6*t^6 + 3*t^5 + t^3 + 6*t^2 + 6*t + 2)/(t^9 + 5*t^8 + t^7 + 6*t^6 + 3*t^5 + 4*t^3 + t^2 + 5*t + 3))*z^2
              Defn: Defined on coordinates by sending (x : y : z) to
                    ((t^3 + 4*t^2 + 2*t + 2)*x : (t^2 + 5)*y : (t^5 + 4*t^4 + t^2 + 3*t + 3)*z)) codomain

            
        TESTS::

            sage: K.<t> = FractionField(PolynomialRing(QQ, 't'))
            sage: a = (2*t^2 - 3/2*t + 1)/(37/3*t^2 + t - 1/4)
            sage: b = (1/2*t^2 + 1/3)/(-73*t^2 - 2*t + 11/4)
            sage: c = (6934/3*t^6 + 8798/3*t^5 - 947/18*t^4 + 3949/9*t^3 + 20983/18*t^2 + 28/3*t - 131/3)/(-2701/3*t^4 - 293/3*t^3 + 301/6*t^2 + 13/4*t - 11/16)
            sage: C = Conic([a,b,c])
            sage: C.has_rational_point(point=True)
            (True, (4*t + 4 : 2*t + 2 : 1))

        A long time test::

            sage: K.<t> = FractionField(PolynomialRing(QQ, 't'))
            sage: a = (-1/3*t^6 - 14*t^5 - 1/4*t^4 + 7/2*t^2 - 1/2*t - 1)/(24/5*t^6 - t^5 - 1/4*t^4 + t^3 - 3*t^2 + 8/5*t + 5)
            sage: b = (-3*t^3 + 8*t + 1/2)/(-1/3*t^3 + 3/2*t^2 + 1/12*t + 1/2)
            sage: c = (1232009/225*t^25 - 1015925057/8100*t^24 + 1035477411553/1458000*t^23 + 7901338091/30375*t^22 - 1421379260447/729000*t^21 + 266121260843/972000*t^20 + 80808723191/486000*t^19 - 516656082523/972000*t^18 + 21521589529/40500*t^17 + 4654758997/21600*t^16 - 20064038625227/9720000*t^15 - 173054270347/324000*t^14 + 536200870559/540000*t^13 - 12710739349/50625*t^12 - 197968226971/135000*t^11 - 134122025657/810000*t^10 + 22685316301/120000*t^9 - 2230847689/21600*t^8 - 70624099679/270000*t^7 - 4298763061/270000*t^6 - 41239/216000*t^5 - 13523/36000*t^4 + 493/36000*t^3 + 83/2400*t^2 + 1/300*t + 1/200)/(-27378/125*t^17 + 504387/500*t^16 - 97911/2000*t^15 + 1023531/4000*t^14 + 1874841/8000*t^13 + 865381/12000*t^12 + 15287/375*t^11 + 6039821/6000*t^10 + 599437/1500*t^9 + 18659/250*t^8 + 1218059/6000*t^7 + 2025127/3000*t^6 + 1222759/6000*t^5 + 38573/200*t^4 + 8323/125*t^3 + 15453/125*t^2 + 17031/500*t + 441/10)
            sage: C = Conic([a,b,c])
            sage: C.has_rational_point(point = True) # long time (4 seconds)
            (True,
             ((-2/117*t^8 + 304/1053*t^7 + 40/117*t^6 - 1/27*t^5 - 110/351*t^4 - 2/195*t^3 + 11/351*t^2 + 1/117)/(t^4 + 2/39*t^3 + 4/117*t^2 + 2/39*t + 14/39) : -5/3*t^4 + 19*t^3 : 1))
        """
        from constructor import Conic
        
        if read_cache:
            if self._rational_point is not None:
                return (True, self._rational_point) if point else True
        
        if algorithm != 'default':
            return ProjectiveConic_field.has_rational_point(self, point,
                algorithm, read_cache)
        
        # Default algorithm
        if self.base_ring().characteristic() == 2:
            raise NotImplementedError("has_rational_point not implemented \
for function field of characteristic 2.")
        new_conic, transformation, inverse = self.diagonalization()
        coeff = new_conic.coefficients()
        if coeff[0] == 0:
            return (True, transformation([1,0,0])) if point else True
        elif coeff[3] == 0:
            return (True, transformation([0,1,0])) if point else True
        elif coeff[5] == 0:
            return (True, transformation([0,0,1])) if point else True
        
        # We save the coefficients of the reduced form in coeff
        # A zero of the reduced conic can be multiplied by multipliers
        # to get a zero of the old conic
        (coeff, multipliers) = new_conic._reduce_conic()
        new_conic = Conic(coeff)
        transformation = transformation \
            * new_conic.hom(diagonal_matrix(multipliers))
        if coeff[0].degree() % 2 == coeff[1].degree() % 2 and \
                coeff[1].degree() % 2 == coeff[2].degree() % 2:
            case = 0
        else:
            case = 1
        
        t, = self.base_ring().base().gens() # t in F[t]
        supp = []
        roots = [[], [], []]
        remove = None
        # loop through the coefficients and find a root of f_i (as in
        # [HC2006]) modulo each element in the coefficients' support
        for i in (0,1,2):
            supp.append(list(coeff[i].factor()))
            for p in supp[i]:
                if p[1] != 1:
                    raise ValueError("Expected factor of exponent 1.")
                # Convert to monic factor
                x = p[0]/list(p[0])[-1]
                N = p[0].base_ring().extension(x, 'tbar')
                R = PolynomialRing(N, 'u')
                u, = R.gens()
                # If p[0] has degree 1, sage might forget the "defining
                # polynomial" of N, so we define our own modulo operation
                if p[0].degree() == 1:
                    mod = t.parent().hom([-x[0]])
                else:
                    mod = N
                if i == 0:
                    x = -mod(coeff[2])/mod(coeff[1])
                elif i == 1:
                    x = -mod(coeff[0])/mod(coeff[2])
                else:
                    x = -mod(coeff[1])/mod(coeff[0])
                if x.is_square():
                    root = N(x.sqrt())
                else:
                    return (False, None) if point else False
                # if case == 0 and p[0] has degree 1, we switch to case
                # 1 and remove this factor out of the support. In [HC2006]
                # this is done later, in FindPoint.
                if case == 0 and p[0].degree() == 1:
                    case = 1
                    # remove later so the loop iterator stays in place.
                    remove = (i,p)
                else:
                    roots[i].append(root)
        if remove:
            supp[remove[0]].remove(remove[1])
        supp = [[p[0] for p in supp[i]] for i in (0,1,2)]

        if case == 0:
        # Find a solution of (5) in [HC2006]
            leading_conic = Conic(self.base_ring().base_ring(),
                        [coeff[0].leading_coefficient(),
                        coeff[1].leading_coefficient(),
                        coeff[2].leading_coefficient()])
            has_point = leading_conic.has_rational_point(True)
            if has_point[0]:
                if point:
                    pt = new_conic.find_point(supp, roots, case,
                        has_point[1])
                else:
                    pt = True
                return (True, transformation(pt)) if point else True
            else:
                return (False, None) if point else False
        # case == 1:
        if point:
            pt = new_conic.find_point(supp, roots, case)
        else:
            pt = True
        return (True, transformation(pt)) if point else True
Ejemplo n.º 50
0
    def root_extension_field(self, D):
        r"""
        Return the quadratic extension field of the base field by
        the square root of the given discriminant ``D``.

        INPUT:

        - ``D`` -- An element of the base ring of ``self``
                   corresponding to a discriminant.

        OUTPUT:

        A relative (at most quadratic) extension to the base field
        of self in the variable ``e`` which corresponds to ``sqrt(D)``.
        If the extension degree is ``1`` then the base field is returned.

        The correct embedding is the positive resp. positive imaginary one.
        Unfortunately no default embedding can be specified for relative
        number fields yet.

        EXAMPLES::

            sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
            sage: G = HeckeTriangleGroup(n=infinity)
            sage: G.root_extension_field(32)
            Number Field in e with defining polynomial x^2 - 32
            sage: G.root_extension_field(-4)
            Number Field in e with defining polynomial x^2 + 4
            sage: G.root_extension_field(4) == G.base_field()
            True

            sage: G = HeckeTriangleGroup(n=7)
            sage: lam = G.lam()
            sage: D = 4*lam^2 + 4*lam - 4
            sage: G.root_extension_field(D)
            Number Field in e with defining polynomial x^2 - 4*lam^2 - 4*lam + 4 over its base field
            sage: G.root_extension_field(4) == G.base_field()
            True
            sage: D = lam^2 - 4
            sage: G.root_extension_field(D)
            Number Field in e with defining polynomial x^2 - lam^2 + 4 over its base field
        """

        K = self.base_field()
        x = PolynomialRing(K, 'x').gen()
        D = self.base_ring()(D)

        if D.is_square():
            return K
        else:
            # unfortunately we can't set embeddings for relative extensions :-(
            # return K.extension(x**2 - D, 'e', embedding=AA(D).sqrt())

            L = K.extension(x**2 - D, 'e')

            #e = AA(D).sqrt()
            #emb = L.hom([e])
            #L._unset_embedding()
            #L.register_embedding(emb)

            #return NumberField(L.absolute_polynomial(), 'e', structure=AbsoluteFromRelative(L), embedding=(???))
            return L
Ejemplo n.º 51
0
    def parametrization(self, point=None, morphism=True):
        r"""
        Return a parametrization `f` of ``self`` together with the
        inverse of `f`.

        If ``point`` is specified, then that point is used
        for the parametrization. Otherwise, use ``self.rational_point()``
        to find a point.

        If ``morphism`` is True, then `f` is returned in the form
        of a Scheme morphism. Otherwise, it is a tuple of polynomials
        that gives the parametrization.

        EXAMPLES:

        An example over a finite field ::

            sage: c = Conic(GF(2), [1,1,1,1,1,0])
            sage: c.parametrization()
            (Scheme morphism:
              From: Projective Space of dimension 1 over Finite Field of size 2
              To:   Projective Conic Curve over Finite Field of size 2 defined by x^2 + x*y
            + y^2 + x*z + y*z
              Defn: Defined on coordinates by sending (x : y) to
                    (x*y + y^2 : x^2 + x*y : x^2 + x*y + y^2),
             Scheme morphism:
              From: Projective Conic Curve over Finite Field of size 2 defined by x^2 + x*y
            + y^2 + x*z + y*z
              To:   Projective Space of dimension 1 over Finite Field of size 2
              Defn: Defined on coordinates by sending (x : y : z) to
                    (y : x))

        An example with ``morphism = False`` ::

            sage: R.<x,y,z> = QQ[]
            sage: C = Curve(7*x^2 + 2*y*z + z^2)
            sage: (p, i) = C.parametrization(morphism = False); (p, i)
            ([-2*x*y, 7*x^2 + y^2, -2*y^2], [-1/2*x, -1/2*z])
            sage: C.defining_polynomial()(p)
            0
            sage: i[0](p) / i[1](p)
            x/y

        A ``ValueError`` is raised if ``self`` has no rational point ::

            sage: C = Conic(x^2 + y^2 + 7*z^2)
            sage: C.parametrization()
            Traceback (most recent call last):
            ...
            ValueError: Conic Projective Conic Curve over Rational Field defined by x^2 + y^2 + 7*z^2 has no rational points over Rational Field!

        A ``ValueError`` is raised if ``self`` is not smooth ::

            sage: C = Conic(x^2 + y^2)
            sage: C.parametrization()
            Traceback (most recent call last):
            ...
            ValueError: The conic self (=Projective Conic Curve over Rational Field defined by x^2 + y^2) is not smooth, hence does not have a parametrization.
        """
        if (not self._parametrization is None) and not point:
            par = self._parametrization
        else:
            if not self.is_smooth():
                raise ValueError, "The conic self (=%s) is not smooth, hence does not have a parametrization." % self
            if point == None:
                point = self.rational_point()
            point = Sequence(point)
            B = self.base_ring()
            Q = PolynomialRing(B, 'x,y')
            [x, y] = Q.gens()
            gens = self.ambient_space().gens()
            P = PolynomialRing(B, 4, ['X', 'Y', 'T0', 'T1'])
            [X, Y, T0, T1] = P.gens()
            c3 = [j for j in range(2,-1,-1) if point[j] != 0][0]
            c1 = [j for j in range(3) if j != c3][0]
            c2 = [j for j in range(3) if j != c3 and j != c1][0]
            L = [0,0,0]
            L[c1] = Y*T1*point[c1] + Y*T0
            L[c2] = Y*T1*point[c2] + X*T0
            L[c3] = Y*T1*point[c3]
            bezout = P(self.defining_polynomial()(L) / T0)
            t = [bezout([x,y,0,-1]),bezout([x,y,1,0])]
            par = (tuple([Q(p([x,y,t[0],t[1]])/y) for  p in L]),
                   tuple([gens[m]*point[c3]-gens[c3]*point[m]
                       for m in [c2,c1]]))
            if self._parametrization is None:
                self._parametrization = par
        if not morphism:
            return par
        P1 = ProjectiveSpace(self.base_ring(), 1, 'x,y')
        return P1.hom(par[0],self), self.Hom(P1)(par[1], check = False)
Ejemplo n.º 52
0
def ubs(f):
    r"""
    Given a sextic form `f`, return a dictionary of the invariants of Mestre, p 317 [MJ1991]_.

    `f` may be homogeneous in two variables or inhomogeneous in one.

    EXAMPLES::

        sage: from sage.schemes.hyperelliptic_curves.invariants import ubs
        sage: x = QQ['x'].0
        sage: ubs(x^6 + 1)
        {'A': 2,
         'B': 2/3,
         'C': -2/9,
         'D': 0,
         'Delta': -2/3*x^2*h^2,
         'f': x^6 + h^6,
         'i': 2*x^2*h^2,
         'y1': 0,
         'y2': 0,
         'y3': 0}

        sage: R.<u, v> = QQ[]
        sage: ubs(u^6 + v^6)
        {'A': 2,
         'B': 2/3,
         'C': -2/9,
         'D': 0,
         'Delta': -2/3*u^2*v^2,
         'f': u^6 + v^6,
         'i': 2*u^2*v^2,
         'y1': 0,
         'y2': 0,
         'y3': 0}

        sage: R.<t> = GF(31)[]
        sage: ubs(t^6 + 2*t^5 + t^2 + 3*t + 1)
        {'A': 0,
         'B': -12,
         'C': -15,
         'D': -15,
         'Delta': -10*t^4 + 12*t^3*h + 7*t^2*h^2 - 5*t*h^3 + 2*h^4,
         'f': t^6 + 2*t^5*h + t^2*h^4 + 3*t*h^5 + h^6,
         'i': -4*t^4 + 10*t^3*h + 2*t^2*h^2 - 9*t*h^3 - 7*h^4,
         'y1': 4*t^2 - 10*t*h - 13*h^2,
         'y2': 6*t^2 - 4*t*h + 2*h^2,
         'y3': 4*t^2 - 4*t*h - 9*h^2}
    """
    ub = Ueberschiebung
    if f.parent().ngens() == 1:
        f = PolynomialRing(f.parent().base_ring(), 1,
                           f.parent().variable_name())(f)
        x1, x2 = f.homogenize().parent().gens()
        f = sum([f[i] * x1**i * x2**(6 - i) for i in range(7)])
    U = {}
    U['f'] = f
    U['i'] = ub(f, f, 4)
    U['Delta'] = ub(U['i'], U['i'], 2)
    U['y1'] = ub(f, U['i'], 4)
    U['y2'] = ub(U['i'], U['y1'], 2)
    U['y3'] = ub(U['i'], U['y2'], 2)
    U['A'] = ub(f, f, 6)
    U['B'] = ub(U['i'], U['i'], 4)
    U['C'] = ub(U['i'], U['Delta'], 4)
    U['D'] = ub(U['y3'], U['y1'], 2)
    return U
Ejemplo n.º 53
0
    def parametrization(self, point=None, morphism=True):
        r"""
        Return a parametrization `f` of ``self`` together with the
        inverse of `f`.

        If ``point`` is specified, then that point is used
        for the parametrization. Otherwise, use ``self.rational_point()``
        to find a point.

        If ``morphism`` is True, then `f` is returned in the form
        of a Scheme morphism. Otherwise, it is a tuple of polynomials
        that gives the parametrization.

        ALGORITHM:

        Uses the PARI/GP function ``qfparam``.

        EXAMPLES ::

            sage: c = Conic([1,1,-1])
            sage: c.parametrization()
            (Scheme morphism:
              From: Projective Space of dimension 1 over Rational Field
              To:   Projective Conic Curve over Rational Field defined by x^2 + y^2 - z^2
              Defn: Defined on coordinates by sending (x : y) to
                    (2*x*y : x^2 - y^2 : x^2 + y^2),
             Scheme morphism:
              From: Projective Conic Curve over Rational Field defined by x^2 + y^2 - z^2
              To:   Projective Space of dimension 1 over Rational Field
              Defn: Defined on coordinates by sending (x : y : z) to
                    (1/2*x : -1/2*y + 1/2*z))

        An example with ``morphism = False`` ::

            sage: R.<x,y,z> = QQ[]
            sage: C = Curve(7*x^2 + 2*y*z + z^2)
            sage: (p, i) = C.parametrization(morphism = False); (p, i)
            ([-2*x*y, x^2 + 7*y^2, -2*x^2], [-1/2*x, 1/7*y + 1/14*z])
            sage: C.defining_polynomial()(p)
            0
            sage: i[0](p) / i[1](p)
            x/y

        A ``ValueError`` is raised if ``self`` has no rational point ::

            sage: C = Conic(x^2 + 2*y^2 + z^2)
            sage: C.parametrization()
            Traceback (most recent call last):
            ...
            ValueError: Conic Projective Conic Curve over Rational Field defined by x^2 + 2*y^2 + z^2 has no rational points over Rational Field!

        A ``ValueError`` is raised if ``self`` is not smooth ::

            sage: C = Conic(x^2 + y^2)
            sage: C.parametrization()
            Traceback (most recent call last):
            ...
            ValueError: The conic self (=Projective Conic Curve over Rational Field defined by x^2 + y^2) is not smooth, hence does not have a parametrization.
        """
        if (not self._parametrization is None) and not point:
            par = self._parametrization
        else:
            if not self.is_smooth():
                raise ValueError("The conic self (=%s) is not smooth, hence does not have a parametrization." % self)
            if point is None:
                point = self.rational_point()
            point = Sequence(point)
            Q = PolynomialRing(QQ, 'x,y')
            [x, y] = Q.gens()
            gens = self.ambient_space().gens()
            M = self.symmetric_matrix()
            M *= lcm([ t.denominator() for t in M.list() ])
            par1 = qfparam(M, point)
            B = Matrix([[par1[i][j] for j in range(3)] for i in range(3)])
            # self is in the image of B and does not lie on a line,
            # hence B is invertible
            A = B.inverse()
            par2 = [sum([A[i,j]*gens[j] for j in range(3)]) for i in [1,0]]
            par = ([Q(pol(x/y)*y**2) for pol in par1], par2)
            if self._parametrization is None:
                self._parametrization = par
        if not morphism:
            return par
        P1 = ProjectiveSpace(self.base_ring(), 1, 'x,y')
        return P1.hom(par[0],self), self.Hom(P1)(par[1], check = False)
Ejemplo n.º 54
0
def mod5family(a, b):
    """
    Formulas for computing the family of elliptic curves with
    congruent mod-5 representation.

    EXAMPLES::

        sage: from sage.schemes.elliptic_curves.mod5family import mod5family
        sage: mod5family(0,1)
        Elliptic Curve defined by y^2 = x^3 + (t^30+30*t^29+435*t^28+4060*t^27+27405*t^26+142506*t^25+593775*t^24+2035800*t^23+5852925*t^22+14307150*t^21+30045015*t^20+54627300*t^19+86493225*t^18+119759850*t^17+145422675*t^16+155117520*t^15+145422675*t^14+119759850*t^13+86493225*t^12+54627300*t^11+30045015*t^10+14307150*t^9+5852925*t^8+2035800*t^7+593775*t^6+142506*t^5+27405*t^4+4060*t^3+435*t^2+30*t+1) over Fraction Field of Univariate Polynomial Ring in t over Rational Field
    """
    J = 4 * a**3 / (4 * a**3 + 27 * b**2)

    alpha = [0 for _ in range(21)]
    alpha[0] = 1
    alpha[1] = 0
    alpha[2] = 190 * (J - 1)
    alpha[3] = -2280 * (J - 1)**2
    alpha[4] = 855 * (J - 1)**2 * (-17 + 16 * J)
    alpha[5] = 3648 * (J - 1)**3 * (17 - 9 * J)
    alpha[6] = 11400 * (J - 1)**3 * (17 - 8 * J)
    alpha[7] = -27360 * (J - 1)**4 * (17 + 26 * J)
    alpha[8] = 7410 * (J - 1)**4 * (-119 - 448 * J + 432 * J**2)
    alpha[9] = 79040 * (J - 1)**5 * (17 + 145 * J - 108 * J**2)
    alpha[10] = 8892 * (J - 1)**5 * (187 + 2640 * J - 5104 * J**2 +
                                     1152 * J**3)
    alpha[11] = 98800 * (J - 1)**6 * (-17 - 388 * J + 864 * J**2)
    alpha[12] = 7410 * (J - 1)**6 * (-187 - 6160 * J + 24464 * J**2 -
                                     24192 * J**3)
    alpha[13] = 54720 * (J - 1)**7 * (17 + 795 * J - 3944 * J**2 + 9072 * J**3)
    alpha[14] = 2280 * (J - 1)**7 * (221 + 13832 * J - 103792 * J**2 +
                                     554112 * J**3 - 373248 * J**4)
    alpha[15] = 1824 * (J - 1)**8 * (-119 - 9842 * J + 92608 * J**2 -
                                     911520 * J**3 + 373248 * J**4)
    alpha[16] = 4275 * (J - 1)**8 * (-17 - 1792 * J + 23264 * J**2 -
                                     378368 * J**3 + 338688 * J**4)
    alpha[17] = 18240 * (J - 1)**9 * (1 + 133 * J - 2132 * J**2 +
                                      54000 * J**3 - 15552 * J**4)
    alpha[18] = 190 * (J - 1)**9 * (17 + 2784 * J - 58080 * J**2 + 2116864 *
                                    J**3 - 946944 * J**4 + 2985984 * J**5)
    alpha[19] = 360 * (J - 1)**10 * (-1 + 28 * J - 1152 * J**2) * (
        1 + 228 * J + 176 * J**2 + 1728 * J**3)
    alpha[20] = (J - 1)**10 * (-19 - 4560 * J + 144096 * J**2 -
                               9859328 * J**3 - 8798976 * J**4 -
                               226934784 * J**5 + 429981696 * J**6)

    beta = [0 for _ in range(31)]
    beta[0] = 1
    beta[1] = 30
    beta[2] = -435 * (J - 1)
    beta[3] = 580 * (J - 1) * (-7 + 9 * J)
    beta[4] = 3915 * (J - 1)**2 * (7 - 8 * J)
    beta[5] = 1566 * (J - 1)**2 * (91 - 78 * J + 48 * J**2)
    beta[6] = -84825 * (J - 1)**3 * (7 + 16 * J)
    beta[7] = 156600 * (J - 1)**3 * (-13 - 91 * J + 92 * J**2)
    beta[8] = 450225 * (J - 1)**4 * (13 + 208 * J - 144 * J**2)
    beta[9] = 100050 * (J - 1)**4 * (143 + 4004 * J - 5632 * J**2 +
                                     1728 * J**3)
    beta[10] = 30015 * (J - 1)**5 * (-1001 - 45760 * J + 44880 * J**2 -
                                     6912 * J**3)
    beta[11] = 600300 * (J - 1)**5 * (-91 - 6175 * J + 9272 * J**2 -
                                      2736 * J**3)
    beta[12] = 950475 * (J - 1)**6 * (91 + 8840 * J - 7824 * J**2)
    beta[13] = 17108550 * (J - 1)**6 * (7 + 926 * J - 1072 * J**2 + 544 * J**3)
    beta[14] = 145422675 * (J - 1)**7 * (-1 - 176 * J + 48 * J**2 - 384 * J**3)
    beta[15] = 155117520 * (J - 1)**8 * (1 + 228 * J + 176 * J**2 +
                                         1728 * J**3)
    beta[16] = 145422675 * (J - 1)**8 * (1 + 288 * J + 288 * J**2 +
                                         5120 * J**3 - 6912 * J**4)
    beta[17] = 17108550 * (J - 1)**8 * (7 + 2504 * J + 3584 * J**2 + 93184 *
                                        J**3 - 283392 * J**4 + 165888 * J**5)
    beta[18] = 950475 * (J - 1)**9 * (-91 - 39936 * J - 122976 * J**2 -
                                      2960384 * J**3 + 11577600 * J**4 -
                                      5971968 * J**5)
    beta[19] = 600300 * (J - 1)**9 * (-91 - 48243 * J - 191568 * J**2 -
                                      6310304 * J**3 + 40515072 * J**4 -
                                      46455552 * J**5 + 11943936 * J**6)
    beta[20] = 30015 * (J - 1)**10 * (1001 + 634920 * J + 3880800 * J**2 +
                                      142879744 * J**3 - 1168475904 * J**4 +
                                      1188919296 * J**5 - 143327232 * J**6)
    beta[21] = 100050 * (J - 1)**10 * (143 + 107250 * J + 808368 * J**2 +
                                       38518336 * J**3 - 451953408 * J**4 +
                                       757651968 * J**5 - 367276032 * J**6)
    beta[22] = 450225 * (J - 1)**11 * (-13 - 11440 * J - 117216 * J**2 -
                                       6444800 * J**3 + 94192384 * J**4 -
                                       142000128 * J**5 + 95551488 * J**6)
    beta[23] = 156600 * (J - 1)**11 * (
        -13 - 13299 * J - 163284 * J**2 - 11171552 * J**3 + 217203840 * J**4 -
        474406656 * J**5 + 747740160 * J**6 - 429981696 * J**7)
    beta[24] = 6525*(J - 1)**12*(91 + 107536*J + 1680624*J**2 + 132912128*J**3 -\
          3147511552*J**4 + 6260502528*J**5 - 21054173184*J**6 + 10319560704*J**7)
    beta[25] = 1566*(J - 1)**12*(91 + 123292*J + 2261248*J**2 + 216211904*J**3 - \
          6487793920*J**4 + 17369596928*J**5 - 97854234624*J**6 + 96136740864*J**7 - 20639121408*J**8)
    beta[26] = 3915*(J - 1)**13*(-7 - 10816*J - 242352*J**2 - 26620160*J**3 + 953885440*J**4 - \
          2350596096*J**5 + 26796552192*J**6 - 13329432576*J**7)
    beta[27] = 580*(J - 1)**13*(-7 - 12259*J - 317176*J**2 - 41205008*J**3 + \
          1808220160*J**4 - 5714806016*J**5 + 93590857728*J**6 - 70131806208*J**7 - 36118462464*J**8)
    beta[28] = 435*(J - 1)**14*(1 + 1976*J + 60720*J**2 + 8987648*J**3 - 463120640*J**4 + 1359157248*J**5 - \
          40644882432*J**6 - 5016453120*J**7 + 61917364224*J**8)
    beta[29] = 30*(J - 1)**14*(1 + 2218*J + 77680*J**2 + 13365152*J**3 - \
          822366976*J**4 + 2990693888*J**5 - 118286217216*J**6 - 24514928640*J**7 + 509958291456*J**8 - 743008370688*J**9)
    beta[30] = (J - 1)**15*(-1 - 2480*J - 101040*J**2 - 19642496*J**3 + 1399023872*J**4 - \
          4759216128*J**5 + 315623485440*J**6 + 471904911360*J**7 - 2600529297408*J**8 + 8916100448256*J**9)

    R = PolynomialRing(QQ, 't')
    b4 = a * R(alpha)
    b6 = b * R(beta)

    c2 = b4
    c3 = b6
    d = lcm(c2.denominator(), c3.denominator())
    F = FractionField(R)

    E = EllipticCurve(F, [c2 * d**4, c3 * d**6])
    return E
Ejemplo n.º 55
0
def gauss_sum(a, p, f, prec=20, factored=False, algorithm='pari', parent=None):
    r"""
    Return the Gauss sum `g_q(a)` as a `p`-adic number.

    The Gauss sum `g_q(a)` is defined by

    .. MATH::

        g_q(a)= \sum_{u\in F_q^*} \omega(u)^{-a} \zeta_q^u,

    where `q = p^f`, `\omega` is the Teichmüller character and
    `\zeta_q` is some arbitrary choice of primitive `q`-th root of
    unity. The computation is adapted from the main theorem in Alain
    Robert's paper *The Gross-Koblitz formula revisited*,
    Rend. Sem. Mat. Univ. Padova 105 (2001), 157--170.

    Let `p` be a prime, `f` a positive integer, `q=p^f`, and `\pi` be
    the unique root of `f(x) = x^{p-1}+p` congruent to `\zeta_p - 1` modulo
    `(\zeta_p - 1)^2`. Let `0\leq a < q-1`. Then the
    Gross-Koblitz formula gives us the value of the Gauss sum `g_q(a)`
    as a product of `p`-adic Gamma functions as follows:

    .. MATH::

        g_q(a) = -\pi^s \prod_{0\leq i < f} \Gamma_p(a^{(i)}/(q-1)),

    where `s` is the sum of the digits of `a` in base `p` and the
    `a^{(i)}` have `p`-adic expansions obtained from cyclic
    permutations of that of `a`.

    INPUT:

    - ``a`` -- integer

    - ``p`` -- prime

    - ``f`` -- positive integer

    - ``prec`` -- positive integer (optional, 20 by default)

    - ``factored`` - boolean (optional, False by default)

    - ``algorithm`` - flag passed to p-adic Gamma function (optional, "pari" by default)

    OUTPUT:

    If ``factored`` is ``False``, returns a `p`-adic number in an Eisenstein extension of `\QQ_p`.
    This number has the form `pi^e * z` where `pi` is as above, `e` is some nonnegative
    integer, and `z` is an element of `\ZZ_p`; if ``factored`` is ``True``, the pair `(e,z)`
    is returned instead, and the Eisenstein extension is not formed.

    .. NOTE::

        This is based on GP code written by Adriana Salerno.

    EXAMPLES:

    In this example, we verify that `g_3(0) = -1`::

        sage: from sage.rings.padics.misc import gauss_sum
        sage: -gauss_sum(0,3,1)
        1 + O(pi^40)

    Next, we verify that `g_5(a) g_5(-a) = 5 (-1)^a`::

        sage: from sage.rings.padics.misc import gauss_sum
        sage: gauss_sum(2,5,1)^2-5
        O(pi^84)
        sage: gauss_sum(1,5,1)*gauss_sum(3,5,1)+5
        O(pi^84)

    Finally, we compute a non-trivial value::

        sage: from sage.rings.padics.misc import gauss_sum
        sage: gauss_sum(2,13,2)
        6*pi^2 + 7*pi^14 + 11*pi^26 + 3*pi^62 + 6*pi^74 + 3*pi^86 + 5*pi^98 +
        pi^110 + 7*pi^134 + 9*pi^146 + 4*pi^158 + 6*pi^170 + 4*pi^194 +
        pi^206 + 6*pi^218 + 9*pi^230 + O(pi^242)
        sage: gauss_sum(2,13,2,prec=5,factored=True)
        (2, 6 + 6*13 + 10*13^2 + O(13^5))

    .. SEEALSO::

        - :func:`sage.arith.misc.gauss_sum` for general finite fields
        - :meth:`sage.modular.dirichlet.DirichletCharacter.gauss_sum`
          for prime finite fields
        - :meth:`sage.modular.dirichlet.DirichletCharacter.gauss_sum_numerical`
          for prime finite fields
    """
    from sage.rings.padics.factory import Zp
    from sage.rings.all import PolynomialRing

    q = p**f
    a = a % (q - 1)
    if parent is None:
        R = Zp(p, prec)
    else:
        R = parent
    out = -R.one()
    if a != 0:
        t = R(1 / (q - 1))
        for i in range(f):
            out *= (a * t).gamma(algorithm)
            a = (a * p) % (q - 1)
    s = sum(a.digits(base=p))
    if factored:
        return s, out
    X = PolynomialRing(R, name='X').gen()
    pi = R.ext(X**(p - 1) + p, names='pi').gen()
    out *= pi**s
    return out
    def coleman_integrals_on_basis(self, P, Q, algorithm=None):
        r"""
        Computes the Coleman integrals `\{\int_P^Q x^i dx/2y \}_{i=0}^{2g-1}`

        INPUT:

        - P point on self
        - Q point on self
        - algorithm (optional) = None (uses Frobenius) or teichmuller (uses Teichmuller points)

        OUTPUT:

        the Coleman integrals `\{\int_P^Q x^i dx/2y \}_{i=0}^{2g-1}`

        EXAMPLES::

            sage: K = pAdicField(11, 5)
            sage: x = polygen(K)
            sage: C = HyperellipticCurve(x^5 + 33/16*x^4 + 3/4*x^3 + 3/8*x^2 - 1/4*x + 1/16)
            sage: P = C.lift_x(2)
            sage: Q = C.lift_x(3)
            sage: C.coleman_integrals_on_basis(P, Q)
            (10*11 + 6*11^3 + 2*11^4 + O(11^5), 11 + 9*11^2 + 7*11^3 + 9*11^4 + O(11^5), 3 + 10*11 + 5*11^2 + 9*11^3 + 4*11^4 + O(11^5), 3 + 11 + 5*11^2 + 4*11^4 + O(11^5))
            sage: C.coleman_integrals_on_basis(P, Q, algorithm='teichmuller')
            (10*11 + 6*11^3 + 2*11^4 + O(11^5), 11 + 9*11^2 + 7*11^3 + 9*11^4 + O(11^5), 3 + 10*11 + 5*11^2 + 9*11^3 + 4*11^4 + O(11^5), 3 + 11 + 5*11^2 + 4*11^4 + O(11^5))

        ::

            sage: K = pAdicField(11,5)
            sage: x = polygen(K)
            sage: C = HyperellipticCurve(x^5 + 33/16*x^4 + 3/4*x^3 + 3/8*x^2 - 1/4*x + 1/16)
            sage: P = C.lift_x(11^(-2))
            sage: Q = C.lift_x(3*11^(-2))
            sage: C.coleman_integrals_on_basis(P, Q)
            (3*11^3 + 7*11^4 + 4*11^5 + 7*11^6 + 5*11^7 + O(11^8), 3*11 + 10*11^2 + 8*11^3 + 9*11^4 + 7*11^5 + O(11^6), 4*11^-1 + 2 + 6*11 + 6*11^2 + 7*11^3 + O(11^4), 11^-3 + 6*11^-2 + 2*11^-1 + 2 + O(11^2))

        ::

            sage: R = C(0,1/4)
            sage: a = C.coleman_integrals_on_basis(P,R)  # long time (7s on sage.math, 2011)
            sage: b = C.coleman_integrals_on_basis(R,Q)  # long time (9s on sage.math, 2011)
            sage: c = C.coleman_integrals_on_basis(P,Q)  # long time
            sage: a+b == c  # long time
            True

        ::

            sage: R.<x> = QQ['x']
            sage: H = HyperellipticCurve(x^3-10*x+9)
            sage: K = Qp(5,8)
            sage: HK = H.change_ring(K)
            sage: S = HK(1,0)
            sage: P = HK(0,3)
            sage: T = HK(0,1,0)
            sage: Q = HK.lift_x(5^-2)
            sage: R = HK.lift_x(4*5^-2)
            sage: HK.coleman_integrals_on_basis(S,P)
            (2*5^2 + 5^4 + 5^5 + 3*5^6 + 3*5^7 + 2*5^8 + O(5^9), 5 + 2*5^2 + 4*5^3 + 2*5^4 + 3*5^6 + 4*5^7 + 2*5^8 + O(5^9))
            sage: HK.coleman_integrals_on_basis(T,P)
            (2*5^2 + 5^4 + 5^5 + 3*5^6 + 3*5^7 + 2*5^8 + O(5^9), 5 + 2*5^2 + 4*5^3 + 2*5^4 + 3*5^6 + 4*5^7 + 2*5^8 + O(5^9))
            sage: HK.coleman_integrals_on_basis(P,S) == -HK.coleman_integrals_on_basis(S,P)
            True
            sage: HK.coleman_integrals_on_basis(S,Q)
            (4*5 + 4*5^2 + 4*5^3 + O(5^4), 5^-1 + O(5^3))
            sage: HK.coleman_integrals_on_basis(Q,R)
            (4*5 + 2*5^2 + 2*5^3 + 2*5^4 + 5^5 + 5^6 + 5^7 + 3*5^8 + O(5^9), 2*5^-1 + 4 + 4*5 + 4*5^2 + 4*5^3 + 2*5^4 + 3*5^5 + 2*5^6 + O(5^7))
            sage: HK.coleman_integrals_on_basis(S,R) == HK.coleman_integrals_on_basis(S,Q) + HK.coleman_integrals_on_basis(Q,R)
            True
            sage: HK.coleman_integrals_on_basis(T,T)
            (0, 0)
            sage: HK.coleman_integrals_on_basis(S,T)
            (0, 0)

        AUTHORS:

        - Robert Bradshaw (2007-03): non-Weierstrass points
        - Jennifer Balakrishnan and Robert Bradshaw (2010-02): Weierstrass points
        """
        import sage.schemes.hyperelliptic_curves.monsky_washnitzer as monsky_washnitzer
        from sage.misc.profiler import Profiler
        prof = Profiler()
        prof("setup")
        K = self.base_ring()
        p = K.prime()
        prec = K.precision_cap()
        g = self.genus()
        dim = 2 * g
        V = VectorSpace(K, dim)
        #if P or Q is Weierstrass, use the Frobenius algorithm
        if self.is_weierstrass(P):
            if self.is_weierstrass(Q):
                return V(0)
            else:
                PP = None
                QQ = Q
                TP = None
                TQ = self.frobenius(Q)
        elif self.is_weierstrass(Q):
            PP = P
            QQ = None
            TQ = None
            TP = self.frobenius(P)
        elif self.is_same_disc(P, Q):
            return self.tiny_integrals_on_basis(P, Q)
        elif algorithm == 'teichmuller':
            prof("teichmuller")
            PP = TP = self.teichmuller(P)
            QQ = TQ = self.teichmuller(Q)
            evalP, evalQ = TP, TQ
        else:
            prof("frobPQ")
            TP = self.frobenius(P)
            TQ = self.frobenius(Q)
            PP, QQ = P, Q
        prof("tiny integrals")
        if TP is None:
            P_to_TP = V(0)
        else:
            if TP is not None:
                TPv = (TP[0]**g / TP[1]).valuation()
                xTPv = TP[0].valuation()
            else:
                xTPv = TPv = +Infinity
            if TQ is not None:
                TQv = (TQ[0]**g / TQ[1]).valuation()
                xTQv = TQ[0].valuation()
            else:
                xTQv = TQv = +Infinity
            offset = (2 * g - 1) * max(TPv, TQv)
            if offset == +Infinity:
                offset = (2 * g - 1) * min(TPv, TQv)
            if (offset > prec and (xTPv < 0 or xTQv < 0) and
                (self.residue_disc(P) == self.change_ring(GF(p))(0, 1, 0)
                 or self.residue_disc(Q) == self.change_ring(GF(p))(0, 1, 0))):
                newprec = offset + prec
                K = pAdicField(p, newprec)
                A = PolynomialRing(RationalField(), 'x')
                f = A(self.hyperelliptic_polynomials()[0])
                from sage.schemes.hyperelliptic_curves.constructor import HyperellipticCurve
                self = HyperellipticCurve(f).change_ring(K)
                xP = P[0]
                xPv = xP.valuation()
                xPnew = K(
                    sum(c * p**(xPv + i)
                        for i, c in enumerate(xP.expansion())))
                PP = P = self.lift_x(xPnew)
                TP = self.frobenius(P)
                xQ = Q[0]
                xQv = xQ.valuation()
                xQnew = K(
                    sum(c * p**(xQv + i)
                        for i, c in enumerate(xQ.expansion())))
                QQ = Q = self.lift_x(xQnew)
                TQ = self.frobenius(Q)
                V = VectorSpace(K, dim)
            P_to_TP = V(self.tiny_integrals_on_basis(P, TP))
        if TQ is None:
            TQ_to_Q = V(0)
        else:
            TQ_to_Q = V(self.tiny_integrals_on_basis(TQ, Q))
        prof("mw calc")
        try:
            M_frob, forms = self._frob_calc
        except AttributeError:
            M_frob, forms = self._frob_calc = monsky_washnitzer.matrix_of_frobenius_hyperelliptic(
                self)
        prof("eval f")
        R = forms[0].base_ring()
        try:
            prof("eval f %s" % R)
            if PP is None:
                L = [-f(R(QQ[0]), R(QQ[1])) for f in forms]  ##changed
            elif QQ is None:
                L = [f(R(PP[0]), R(PP[1])) for f in forms]
            else:
                L = [
                    f(R(PP[0]), R(PP[1])) - f(R(QQ[0]), R(QQ[1]))
                    for f in forms
                ]
        except ValueError:
            prof("changing rings")
            forms = [f.change_ring(self.base_ring()) for f in forms]
            prof("eval f %s" % self.base_ring())
            if PP is None:
                L = [-f(QQ[0], QQ[1]) for f in forms]  ##changed
            elif QQ is None:
                L = [f(PP[0], PP[1]) for f in forms]
            else:
                L = [f(PP[0], PP[1]) - f(QQ[0], QQ[1]) for f in forms]
        b = V(L)
        if PP is None:
            b -= TQ_to_Q
        elif QQ is None:
            b -= P_to_TP
        elif algorithm != 'teichmuller':
            b -= P_to_TP + TQ_to_Q
        prof("lin alg")
        M_sys = matrix(K, M_frob).transpose() - 1
        TP_to_TQ = M_sys**(-1) * b
        prof("done")
        #        print prof
        if algorithm == 'teichmuller':
            return P_to_TP + TP_to_TQ + TQ_to_Q
        else:
            return TP_to_TQ
Ejemplo n.º 57
0
def _biquadratic_syzygy_quartic(quadratic1, quadratic2, variables=None):
    r"""
    Helper function for the Weierstrass form of a biquadratic in $`\mathbb{P}^3$

    The invariants and covariants of a quaternary biquadratic satisfy
    the relation
    :meth:`sage.rings.invariant_theory.TwoQuaternaryQuadratics.syzygy`,
    which is (modulo the two quadratic equations) of the form $J^2 =
    p_4(T, T')$ where

    * $J$, $T$, $T'$ are the covariants of the biquadratic.
    
    * $p_4$ is some quartic polynomial whose coefficients are
      invariants of the biquadratic.
  
    INPUT:

    See :func:`WeierstrassForm_P3`

    OUTPUT:

    A triple consisting of 

    - The quaternary biquadratic as an algebraic form
      :class:`~sage.rings.invariant_theory.TwoQuaternaryQuadratics`
      
    - The binary quartic $p_4$ as a
      :class:`~sage.rings.invariant_theory.BinaryQuartic`
      
    - The dictionary of variable substitutions from the variables of
      the quartic to the variables of the biquadratic.

    EXAMPLES::

        sage: from sage.schemes.toric.weierstrass_higher import _biquadratic_syzygy_quartic
        sage: R.<w,x,y,z> = QQ[]
        sage: _biquadratic_syzygy_quartic(w^2+x^2+y^2, z^2)
        (Joint quaternary quadratic with coefficients (1, 1, 1, 0, 0, 0, 0, 0, 0, 0) 
         and quaternary quadratic with coefficients (0, 0, 0, 1, 0, 0, 0, 0, 0, 0), 
         Binary quartic with coefficients (0, 0, 0, -1, 0), {aux...})
    """
    w, x, y, z = _check_polynomials_P3(quadratic1, quadratic2, variables)
    biquadratic = invariant_theory.quaternary_biquadratic(quadratic1, quadratic2, [w, x, y, z])
    
    # construct auxiliary polynomial ring to work with the rhs of the syzygy
    R = biquadratic.ring()
    n = R.ngens()
    R_aux = PolynomialRing(R.base_ring(), n+2, 'aux')
    to_aux = dict()
    from_aux = dict()
    for var, var_aux in zip(R.gens(), R_aux.gens()[0:n]):
        to_aux[var] = var_aux
        from_aux[var_aux] = var
    T, T_prime = R_aux.gens()[n:]
    from_aux[T] = biquadratic.T_covariant()
    from_aux[T_prime] = biquadratic.T_prime_covariant()

    # Syzygy is J^2 = syz_rhs + (terms that vanish on the biquadratic) with
    # J = biquadratic.J_covariant()
    syz_rhs = T**4 * biquadratic.Delta_invariant().subs(to_aux) \
        - T**3*T_prime * biquadratic.Theta_invariant().subs(to_aux) \
        + T**2*T_prime**2 * biquadratic.Phi_invariant().subs(to_aux) \
        - T*T_prime**3 * biquadratic.Theta_prime_invariant().subs(to_aux) \
        + T_prime**4 * biquadratic.Delta_prime_invariant().subs(to_aux)
    quartic = invariant_theory.binary_quartic(syz_rhs, [T, T_prime])
    return (biquadratic, quartic, from_aux)
Ejemplo n.º 58
0
        t, = self.base_ring().base().gens()  # t in F[t]
        supp = []
        roots = [[], [], []]
        remove = None
        # loop through the coefficients and find a root of f_i (as in
        # [HC2006]) modulo each element in the coefficients' support
        for i in (0, 1, 2):
            supp.append(list(coeff[i].factor()))
            for p in supp[i]:
                if p[1] != 1:
                    raise ValueError("Expected factor of exponent 1.")
                # Convert to monic factor
                x = p[0] / list(p[0])[-1]
                N = p[0].base_ring().extension(x, 'tbar')
                R = PolynomialRing(N, 'u')
                u, = R.gens()
                # If p[0] has degree 1, sage might forget the "defining
                # polynomial" of N, so we define our own modulo operation
                if p[0].degree() == 1:
                    mod = t.parent().hom([-x[0]])
                else:
                    mod = N
                if i == 0:
                    x = -mod(coeff[2]) / mod(coeff[1])
                elif i == 1:
                    x = -mod(coeff[0]) / mod(coeff[2])
                else:
                    x = -mod(coeff[1]) / mod(coeff[0])
                if x.is_square():
                    root = N(x.sqrt())
Ejemplo n.º 59
0
    def _sage_(self):
        """
        Convert self to a Sage object.

        EXAMPLES::
        
            sage: a = axiom(1/2); a #optional - axiom
              1
              -
              2
            sage: a.sage()          #optional - axiom
            1/2
            sage: _.parent()        #optional - axiom
            Rational Field

            sage: gp(axiom(1/2))    #optional - axiom
            1/2

            sage: fricas(1/2).sage() #optional - fricas
            1/2

        DoubleFloat's in Axiom are converted to be in RDF in Sage.

        ::
        
            sage: axiom(2.0).as_type('DoubleFloat').sage()  #optional - axiom
            2.0
            sage: _.parent() #optional - axiom
            Real Double Field


            sage: axiom(2.1234)._sage_() #optional - axiom
            2.12340000000000
            sage: _.parent()             #optional - axiom
            Real Field with 53 bits of precision
            sage: a = RealField(100)(pi)
            sage: axiom(a)._sage_()      #optional - axiom 
            3.1415926535897932384626433833
            sage: _.parent()             #optional - axiom
            Real Field with 100 bits of precision
            sage: axiom(a)._sage_() == a #optional - axiom
            True
            sage: axiom(2.0)._sage_() #optional - axiom
            2.00000000000000
            sage: _.parent() #optional  - axiom
            Real Field with 53 bits of precision


        We can also convert Axiom's polynomials to Sage polynomials.
            sage: a = axiom(x^2 + 1)   #optional - axiom
            sage: a.type()             #optional - axiom
            Polynomial Integer
            sage: a.sage()             #optional - axiom
            x^2 + 1
            sage: _.parent()           #optional - axiom
            Univariate Polynomial Ring in x over Integer Ring
            sage: axiom('x^2 + y^2 + 1/2').sage()    #optional - axiom
            y^2 + x^2 + 1/2
            sage: _.parent()                         #optional - axiom
            Multivariate Polynomial Ring in y, x over Rational Field

        
        """
        P = self._check_valid()
        type = str(self.type())

        if type in ["Type", "Domain"]:
            return self._sage_domain()

        if type == "Float":
            from sage.rings.all import RealField, ZZ
            prec = max(self.mantissa().length()._sage_(), 53)
            R = RealField(prec)
            x, e, b = self.unparsed_input_form().lstrip('float(').rstrip(
                ')').split(',')
            return R(ZZ(x) * ZZ(b)**ZZ(e))
        elif type == "DoubleFloat":
            from sage.rings.all import RDF
            return RDF(repr(self))
        elif type.startswith('Polynomial'):
            from sage.rings.all import PolynomialRing
            base_ring = P(type.lstrip('Polynomial '))._sage_domain()
            vars = str(self.variables())[1:-1]
            R = PolynomialRing(base_ring, vars)
            return R(self.unparsed_input_form())

        #If all else fails, try using the unparsed input form
        try:
            import sage.misc.sage_eval
            return sage.misc.sage_eval.sage_eval(self.unparsed_input_form())
        except:
            raise NotImplementedError
Ejemplo n.º 60
0
def rational_type(f, n=ZZ(3), base_ring=ZZ):
    r"""
    Return the basic analytic properties that can be determined
    directly from the specified rational function ``f``
    which is interpreted as a representation of an
    element of a FormsRing for the Hecke Triangle group
    with parameter ``n`` and the specified ``base_ring``.

    In particular the following degree of the generators is assumed:

    `deg(1) := (0, 1)`
    `deg(x) := (4/(n-2), 1)`
    `deg(y) := (2n/(n-2), -1)`
    `deg(z) := (2, -1)`

    The meaning of homogeneous elements changes accordingly.

    INPUT:

    - ``f``               - A rational function in ``x,y,z,d`` over ``base_ring``.
    - ``n``               - An integer greater or equal to ``3`` corresponding
                           to the ``HeckeTriangleGroup`` with that parameter
                           (default: ``3``).
    - ``base_ring```      - The base ring of the corresponding forms ring, resp.
                            polynomial ring (default: ``ZZ``).

    OUTPUT:
    
    A tuple ``(elem, h**o, k, ep, analytic_type)`` describing the basic
    analytic properties of ``f`` (with the interpretation indicated above).
    
    - ``elem``            - ``True`` if ``f`` has a homogeneous denominator.
    - ``h**o``            - ``True`` if ``f`` also has a homogeneous numerator.
    - ``k``               - ``None`` if ``f`` is not homogeneneous, otherwise
                            the weight of ``f`` (which is the first component
                            of its degree).
    - ``ep``              - ``None`` if ``f`` is not homogeneous, otherwise
                            the multiplier of ``f`` (which is the second component
                            of its degree)
    - ``analytic_type``   - The ``AnalyticType`` of ``f``.

    For the zero function the degree ``(0, 1)`` is choosen.

    This function is (heavily) used to determine the type of elements
    and to check if the element really is contained in its parent.


    EXAMPLES::

        sage: (x,y,z,d) = var("x,y,z,d")

        sage: rational_type(0, n=4)
        (True, True, 0, 1, zero)

        sage: rational_type(1, n=12)
        (True, True, 0, 1, modular)

        sage: rational_type(x^3 - y^2)
        (True, True, 12, 1, cuspidal)

        sage: rational_type(x * z, n=7)
        (True, True, 14/5, -1, quasi modular)

        sage: rational_type(1/(x^3 - y^2) + z/d)
        (True, False, None, None, quasi weakly holomorphic modular)

        sage: rational_type(x^3/(x^3 - y^2))
        (True, True, 0, 1, weakly holomorphic modular)

        sage: rational_type(1/(x + z))
        (False, False, None, None, None)

        sage: rational_type(1/x + 1/z)
        (True, False, None, None, quasi meromorphic modular)

        sage: rational_type(d/x, n=10)
        (True, True, -1/2, 1, meromorphic modular)

        sage: rational_type(1.1 * z * (x^8-y^2), n=8, base_ring=CC)
        (True, True, 22/3, -1, quasi cuspidal)
    """

    from analytic_type import AnalyticType
    AT = AnalyticType()

    # Determine whether f is zero
    if (f == 0):
        #       elem, h**o, k,     ep,    analytic_type
        return (True, True, QQ(0), ZZ(1), AT([]))
 
    analytic_type = AT(["quasi", "mero"])

    R          = PolynomialRing(base_ring,'x,y,z,d')
    F          = FractionField(R)
    (x,y,z,d)  = R.gens()
    R2         = PolynomialRing(PolynomialRing(base_ring, 'd'), 'x,y,z')
    dhom       = R.hom( R2.gens() + (R2.base().gen(),), R2)

    f          = F(f)
    n          = ZZ(n)

    num        = R(f.numerator())
    denom      = R(f.denominator())
    hom_num    = R(   num.subs(x=x**4, y=y**(2*n), z=z**(2*(n-2))) )
    hom_denom  = R( denom.subs(x=x**4, y=y**(2*n), z=z**(2*(n-2))) )
    ep_num     = set([ZZ(1) - 2*(( sum([g.exponents()[0][m] for m in [1,2]]) )%2) for g in   dhom(num).monomials()])
    ep_denom   = set([ZZ(1) - 2*(( sum([g.exponents()[0][m] for m in [1,2]]) )%2) for g in dhom(denom).monomials()])

    # Determine whether the denominator of f is homogeneous
    if (len(ep_denom) == 1 and dhom(hom_denom).is_homogeneous()):
        elem = True
    else:
        #       elem,  h**o,  k,    ep,   analytic_type
        return (False, False, None, None, None)


    # Determine whether f is homogeneous
    if (len(ep_num) == 1 and dhom(hom_num).is_homogeneous()):
        h**o   = True
        weight = (dhom(hom_num).degree() - dhom(hom_denom).degree()) / (n-2)
        ep     = ep_num.pop() / ep_denom.pop()
    # TODO: decompose f (resp. its degrees) into homogeneous parts
    else:
        h**o   = False
        weight = None
        ep     = None

    # Note that we intentially leave out the d-factor!
    finf_pol = x**n-y**2

    # Determine whether f is modular
    if not ( (num.degree(z) > 0) or (denom.degree(z) > 0) ):
        analytic_type = analytic_type.reduce_to("mero")

    # Determine whether f is holomorphic
    if (dhom(denom).is_constant()):
        analytic_type = analytic_type.reduce_to(["quasi", "holo"])
        # Determine whether f is cuspidal in the sense that finf divides it...
        # Bug in singular: finf_pol.dividess(1.0) fails over RR
        if (not dhom(num).is_constant()) and finf_pol.divides(num):
            analytic_type = analytic_type.reduce_to(["quasi", "cusp"])
    else:
        # -> because of a bug with singular in case some cases
        try:
            while (finf_pol.divides(denom)):
                # a simple "denom /= finf_pol" is strangely not enough for non-exact rings
                denom = denom.quo_rem(finf_pol)[0]
                denom = R(denom)
        except TypeError:
            pass

        # Determine whether f is weakly holomorphic in the sense that at most powers of finf occur in denom
        if (dhom(denom).is_constant()):
            analytic_type = analytic_type.reduce_to(["quasi", "weak"])

    return (elem, h**o, weight, ep, analytic_type)