def number_field_elements_from_algebraics(elts, name='a'):
    r"""
    The native Sage function ``number_field_elements_from_algebraics`` currently
    returns number field *without* embedding. This function return field with
    embedding!

    EXAMPLES::

        sage: from flatsurf.geometry.subfield import number_field_elements_from_algebraics
        sage: z = QQbar.zeta(5)
        sage: c = z.real()
        sage: s = z.imag()
        sage: number_field_elements_from_algebraics((c,s))
        (Number Field in a with defining polynomial y^4 - 5*y^2 + 5 with a = 1.902113032590308?,
         [1/2*a^2 - 3/2, 1/2*a])

         sage: number_field_elements_from_algebraics([AA(1), AA(2/3)])
         (Rational Field, [1, 2/3])
    """
    # case when all elements are rationals
    if all(x in QQ for x in elts):
        return QQ, [QQ(x) for x in elts]

    # general case
    from sage.rings.qqbar import number_field_elements_from_algebraics
    field, elts, phi = number_field_elements_from_algebraics(elts,
                                                             minimal=True)

    polys = [x.polynomial() for x in elts]
    K = NumberField(field.polynomial(), name, embedding=AA(phi(field.gen())))
    gen = K.gen()

    return K, [x.polynomial()(gen) for x in elts]
 def endomorphism_ring(self):
     k = NumberField(self._domain.frobenius().minpoly(), 'c')
     self._field = k
     self.endomorphism_index()
     basis = k.maximal_order().basis()
     basis = [basis[0] * self._index, basis[1] * self._index]
     self._order = k.order(basis)
 def __init__(self,lambda_squared=None, field=None):
     if lambda_squared==None:
         from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
         R=PolynomialRing(ZZ,'x')
         x = R.gen()
         field=NumberField(x**3-ZZ(5)*x**2+ZZ(4)*x-ZZ(1), 'r', embedding=AA(ZZ(4)))
         self._l=field.gen()
     else:
         if field is None:
             self._l=lambda_squared
             field=lambda_squared.parent()
         else:
             self._l=field(lambda_squared)
     Surface.__init__(self,field, ZZ.zero(), finite=False)
 def __init__(self, lambda_squared=None, field=None):
     if lambda_squared == None:
         from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
         R = PolynomialRing(ZZ, 'x')
         x = R.gen()
         field = NumberField(x**3 - ZZ(5) * x**2 + ZZ(4) * x - ZZ(1),
                             'r',
                             embedding=AA(ZZ(4)))
         self._l = field.gen()
     else:
         if field is None:
             self._l = lambda_squared
             field = lambda_squared.parent()
         else:
             self._l = field(lambda_squared)
     Surface.__init__(self, field, ZZ.zero(), finite=False)
def flipper_nf_to_sage(K, name='a'):
    r"""
    Convert a flipper number field into a Sage number field

    .. NOTE::

        Currently, the code is not careful at all with root isolation.

    EXAMPLES::

        sage: import flipper  # optional - flipper
        sage: import realalg  # optional - flipper
        sage: from flatsurf.geometry.similarity_surface_generators import flipper_nf_to_sage
        sage: K = realalg.RealNumberField([-2r] + [0r]*5 + [1r])   # optional - flipper
        sage: K_sage = flipper_nf_to_sage(K)                       # optional - flipper
        sage: K_sage                                               # optional - flipper
        Number Field in a with defining polynomial x^6 - 2 with a = 1.122462048309373?
        sage: AA(K_sage.gen())                                     # optional - flipper
        1.122462048309373?
    """
    r = K.lmbda.interval()
    l = r.lower * ZZ(10)**(-r.precision)
    u = r.upper * ZZ(10)**(-r.precision)

    p = QQ['x'](K.coefficients)
    s = AA.polynomial_root(p, RIF(l, u))
    return NumberField(p, name, embedding=s)
Exemple #6
0
    def __init__(self, n):
        r"""
        Hecke triangle group (2, n, infinity).
        Namely the von Dyck group corresponding to the triangle group
        with angles (pi/2, pi/n, 0).

        INPUT:

        - ``n``   - ``infinity`` or an integer greater or equal to ``3``.

        OUTPUT:

        The Hecke triangle group for the given parameter ``n``.

        EXAMPLES::

            sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
            sage: G = HeckeTriangleGroup(12)
            sage: G
            Hecke triangle group for n = 12
            sage: G.category()
            Category of groups
        """

        self._n = n
        self.element_repr_method("default")

        if n in [3, infinity]:
            self._base_ring = ZZ
            self._lam = ZZ(1) if n == 3 else ZZ(2)
        else:
            lam_symbolic = 2 * cos(pi / n)
            K = NumberField(self.lam_minpoly(),
                            'lam',
                            embedding=coerce_AA(lam_symbolic))
            #self._base_ring = K.order(K.gens())
            self._base_ring = K.maximal_order()
            self._lam = self._base_ring.gen(1)

        T = matrix(self._base_ring, [[1, self._lam], [0, 1]])
        S = matrix(self._base_ring, [[0, -1], [1, 0]])

        FinitelyGeneratedMatrixGroup_generic.__init__(self, ZZ(2),
                                                      self._base_ring, [S, T])
    def __init__(self, n):
        r"""
        Hecke triangle group (2, n, infinity).
        Namely the von Dyck group corresponding to the triangle group
        with angles (pi/2, pi/n, 0).

        INPUT:

        - ``n``   - ``infinity`` or an integer greater or equal to ``3``.

        OUTPUT:

        The Hecke triangle group for the given parameter ``n``.

        EXAMPLES::

            sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
            sage: G = HeckeTriangleGroup(12)
            sage: G
            Hecke triangle group for n = 12
            sage: G.category()
            Category of groups
        """

        self._n = n
        self.element_repr_method("default")

        if n in [3, infinity]:
            self._base_ring = ZZ
            self._lam = ZZ(1) if n==3 else ZZ(2)
        else:
            lam_symbolic = 2*cos(pi/n)
            K = NumberField(self.lam_minpoly(), 'lam', embedding = coerce_AA(lam_symbolic))
            #self._base_ring = K.order(K.gens())
            self._base_ring = K.maximal_order()
            self._lam = self._base_ring.gen(1)

        T = matrix(self._base_ring, [[1,self._lam],[0,1]])
        S = matrix(self._base_ring, [[0,-1],[1,0]])

        FinitelyGeneratedMatrixGroup_generic.__init__(self, ZZ(2), self._base_ring, [S, T])
Exemple #8
0
    def get(self, S, var='a'):
        """
        Return all fields in the database ramified exactly at
        the primes in S.

        INPUT:

        -  ``S`` - list or set of primes, or a single prime

        -  ``var`` - the name used for the generator of the number fields (default 'a').

        EXAMPLES::

            sage: J = JonesDatabase()              # optional - database_jones_numfield
            sage: J.get(163, var='z')              # optional - database_jones_numfield
            [Number Field in z with defining polynomial x^2 + 163,
             Number Field in z with defining polynomial x^3 - x^2 - 54*x + 169,
             Number Field in z with defining polynomial x^4 - x^3 - 7*x^2 + 2*x + 9]
            sage: J.get([3, 4])                    # optional - database_jones_numfield
            Traceback (most recent call last):
            ...
            ValueError: S must be a list of primes
        """
        if self.root is None:
            if os.path.exists(JONESDATA + "/jones.sobj"):
                self.root = load(JONESDATA + "/jones.sobj")
            else:
                raise RuntimeError(
                    "You must install the Jones database optional package.")
        try:
            S = list(S)
        except TypeError:
            S = [S]
        if not all([p.is_prime() for p in S]):
            raise ValueError("S must be a list of primes")
        S.sort()
        s = tuple(S)
        if s not in self.root:
            return []
        return [NumberField(f, var, check=False) for f in self.root[s]]
    def mcmullen_genus2_prototype(w, h, t, e, rel=0):
        r"""
        McMullen prototypes in the stratum H(2).

        These prototype appear at least in McMullen "Teichmüller curves in genus
        two: Discriminant and spin" (2004). The notation from that paper are
        quadruple ``(a, b, c, e)`` which translates in our notation as
        ``w = b``, ``h = c``, ``t = a`` (and ``e = e``).

        The associated discriminant is `D = e^2 + 4 wh`.

        If ``rel`` is a positive parameter (less than w-lambda) the surface belongs
        to the eigenform locus in H(1,1).

        EXAMPLES::

            sage: from flatsurf import translation_surfaces
            sage: from surface_dynamics import AbelianStratum

            sage: prototypes = {
            ....:      5: [(1,1,0,-1)],
            ....:      8: [(1,1,0,-2), (2,1,0,0)],
            ....:      9: [(2,1,0,-1)],
            ....:     12: [(1,2,0,-2), (2,1,0,-2), (3,1,0,0)],
            ....:     13: [(1,1,0,-3), (3,1,0,-1), (3,1,0,1)],
            ....:     16: [(3,1,0,-2), (4,1,0,0)],
            ....:     17: [(1,2,0,-3), (2,1,0,-3), (2,2,0,-1), (2,2,1,-1), (4,1,0,-1), (4,1,0,1)],
            ....:     20: [(1,1,0,-4), (2,2,1,-2), (4,1,0,-2), (4,1,0,2)],
            ....:     21: [(1,3,0,-3), (3,1,0,-3)],
            ....:     24: [(1,2,0,-4), (2,1,0,-4), (3,2,0,0)],
            ....:     25: [(2,2,0,-3), (2,2,1,-3), (3,2,0,-1), (4,1,0,-3)]}

            sage: for D in sorted(prototypes):
            ....:     for w,h,t,e in prototypes[D]:
            ....:          T = translation_surfaces.mcmullen_genus2_prototype(w,h,t,e)
            ....:          assert T.stratum() == AbelianStratum(2)
            ....:          assert (D.is_square() and T.base_ring() is QQ) or (T.base_ring().polynomial().discriminant() == D)

        An example with some relative homology::

            sage: U8 = translation_surfaces.mcmullen_genus2_prototype(2,1,0,0,1/4)    # discriminant 8
            sage: U12 = translation_surfaces.mcmullen_genus2_prototype(3,1,0,0,3/10)   # discriminant 12

            sage: U8.stratum()
            H_2(1^2)
            sage: U8.base_ring().polynomial().discriminant()
            8
            sage: U8.j_invariant()
            (
                      [4 0]
            (0), (0), [0 2]
            )

            sage: U12.stratum()
            H_2(1^2)
            sage: U12.base_ring().polynomial().discriminant()
            12
            sage: U12.j_invariant()
            (
                      [6 0]
            (0), (0), [0 2]
            )
        """
        w = ZZ(w)
        h = ZZ(h)
        t = ZZ(t)
        e = ZZ(e)
        g = w.gcd(h)
        gg = g.gcd(t).gcd(e)
        if w <= 0 or h <= 0 or t < 0 or t >= g or not g.gcd(t).gcd(
                e).is_one() or e + h >= w:
            raise ValueError("invalid parameters")

        x = polygen(QQ)
        poly = x**2 - e * x - w * h
        if poly.is_irreducible():
            emb = AA.polynomial_root(poly, RIF(0, w))
            K = NumberField(poly, 'l', embedding=emb)
            l = K.gen()
        else:
            K = QQ
            D = e**2 + 4 * w * h
            d = D.sqrt()
            l = (e + d) / 2
        rel = K(rel)

        # (lambda,lambda) square on top
        # twisted (w,0), (t,h)
        s = Surface_list(base_ring=K)
        if rel:
            if rel < 0 or rel > w - l:
                raise ValueError("invalid rel argument")
            s.add_polygon(
                polygons(vertices=[(0, 0), (l, 0), (l + rel, l), (rel, l)],
                         ring=K))
            s.add_polygon(
                polygons(vertices=[(0, 0), (rel, 0), (rel + l, 0), (w, 0),
                                   (w + t, h), (l + rel + t, h), (t + l, h),
                                   (t, h)],
                         ring=K))
            s.set_edge_pairing(0, 1, 0, 3)
            s.set_edge_pairing(0, 0, 1, 6)
            s.set_edge_pairing(0, 2, 1, 1)
            s.set_edge_pairing(1, 2, 1, 4)
            s.set_edge_pairing(1, 3, 1, 7)
            s.set_edge_pairing(1, 0, 1, 5)
        else:
            s.add_polygon(
                polygons(vertices=[(0, 0), (l, 0), (l, l), (0, l)], ring=K))
            s.add_polygon(
                polygons(vertices=[(0, 0), (l, 0), (w, 0), (w + t, h),
                                   (l + t, h), (t, h)],
                         ring=K))
            s.set_edge_pairing(0, 1, 0, 3)
            s.set_edge_pairing(0, 0, 1, 4)
            s.set_edge_pairing(0, 2, 1, 0)
            s.set_edge_pairing(1, 1, 1, 3)
            s.set_edge_pairing(1, 2, 1, 5)
        s.set_immutable()
        return TranslationSurface(s)
    def arnoux_yoccoz(genus):
        r"""
        Construct the Arnoux-Yoccoz surface of genus 3 or greater.
        
        This presentation of the surface follows Section 2.3 of 
        Joshua P. Bowman's paper "The Complete Family of Arnoux-Yoccoz 
        Surfaces."
        
        EXAMPLES::

            sage: from flatsurf import *
            sage: s = translation_surfaces.arnoux_yoccoz(4)
            sage: TestSuite(s).run()
            sage: s.is_delaunay_decomposed()
            True
            sage: s = s.canonicalize()
            sage: field=s.base_ring()
            sage: a = field.gen()
            sage: from sage.matrix.constructor import Matrix
            sage: m = Matrix([[a,0],[0,~a]])
            sage: ss = m*s
            sage: ss = ss.canonicalize()
            sage: s.cmp_translation_surface(ss)==0
            True

        The Arnoux-Yoccoz pseudo-Anosov are known to have (minimal) invariant
        foliations with SAF=0::

            sage: S3 = translation_surfaces.arnoux_yoccoz(3)
            sage: Jxx, Jyy, Jxy = S3.j_invariant()
            sage: Jxx.is_zero() and Jyy.is_zero()
            True
            sage: Jxy
            [ 0  2  0]
            [ 2 -2  0]
            [ 0  0  2]

            sage: S4 = translation_surfaces.arnoux_yoccoz(4)
            sage: Jxx, Jyy, Jxy = S4.j_invariant()
            sage: Jxx.is_zero() and Jyy.is_zero()
            True
            sage: Jxy
            [ 0  2  0  0]
            [ 2 -2  0  0]
            [ 0  0  2  2]
            [ 0  0  2  0]
        """
        g=ZZ(genus)
        assert g>=3
        from sage.rings.polynomial.polynomial_ring import polygen
        x = polygen(AA)
        p=sum([x**i for i in xrange(1,g+1)])-1
        cp = AA.common_polynomial(p)
        alpha_AA = AA.polynomial_root(cp, RIF(1/2, 1))
        field=NumberField(alpha_AA.minpoly(),'alpha',embedding=alpha_AA)
        a=field.gen()
        from sage.modules.free_module import VectorSpace
        V=VectorSpace(field,2)
        p=[None for i in xrange(g+1)]
        q=[None for i in xrange(g+1)]
        p[0]=V(( (1-a**g)/2, a**2/(1-a) ))
        q[0]=V(( -a**g/2, a ))
        p[1]=V(( -(a**(g-1)+a**g)/2, (a-a**2+a**3)/(1-a) ))
        p[g]=V(( 1+(a-a**g)/2, (3*a-1-a**2)/(1-a) ))
        for i in xrange(2,g):
            p[i]=V(( (a-a**i)/(1-a) , a/(1-a) ))
        for i in xrange(1,g+1):
            q[i]=V(( (2*a-a**i-a**(i+1))/(2*(1-a)), (a-a**(g-i+2))/(1-a) ))
        from flatsurf.geometry.polygon import Polygons
        P=Polygons(field)
        s = Surface_list(field)
        T = [None] * (2*g+1)
        Tp = [None] * (2*g+1)
        from sage.matrix.constructor import Matrix
        m=Matrix([[1,0],[0,-1]])
        for i in xrange(1,g+1):
            # T_i is (P_0,Q_i,Q_{i-1})
            T[i]=s.add_polygon(P(edges=[ q[i]-p[0], q[i-1]-q[i], p[0]-q[i-1] ]))
            # T_{g+i} is (P_i,Q_{i-1},Q_{i})
            T[g+i]=s.add_polygon(P(edges=[ q[i-1]-p[i], q[i]-q[i-1], p[i]-q[i] ]))
            # T'_i is (P'_0,Q'_{i-1},Q'_i)
            Tp[i]=s.add_polygon(m*s.polygon(T[i]))
            # T'_{g+i} is (P'_i,Q'_i, Q'_{i-1})
            Tp[g+i]=s.add_polygon(m*s.polygon(T[g+i]))
        for i in xrange(1,g):
            s.change_edge_gluing(T[i],0,T[i+1],2)
            s.change_edge_gluing(Tp[i],2,Tp[i+1],0)
        for i in xrange(1,g+1):
            s.change_edge_gluing(T[i],1,T[g+i],1)
            s.change_edge_gluing(Tp[i],1,Tp[g+i],1)
        #P 0 Q 0 is paired with P' 0 Q' 0, ...
        s.change_edge_gluing(T[1],2,Tp[g],2)
        s.change_edge_gluing(Tp[1],0,T[g],0)
        # P1Q1 is paired with P'_g Q_{g-1}
        s.change_edge_gluing(T[g+1],2,Tp[2*g],2)
        s.change_edge_gluing(Tp[g+1],0,T[2*g],0)
        # P1Q0 is paired with P_{g-1} Q_{g-1}
        s.change_edge_gluing(T[g+1],0,T[2*g-1],2)
        s.change_edge_gluing(Tp[g+1],2,Tp[2*g-1],0)
        # PgQg is paired with Q1P2
        s.change_edge_gluing(T[2*g],2,T[g+2],0)
        s.change_edge_gluing(Tp[2*g],0,Tp[g+2],2)
        for i in xrange(2,g-1):
            # PiQi is paired with Q'_i P'_{i+1}
            s.change_edge_gluing(T[g+i],2,Tp[g+i+1],2)
            s.change_edge_gluing(Tp[g+i],0,T[g+i+1],0)
        s.set_immutable()
        return TranslationSurface(s)
Exemple #11
0
    + 34918206405098505823938790072675572231488655998026261577866691497637535623661745400444768148106948876570405151317417742685700849593772165309178580940805695949542187927076864000)*Dt)
quadric_slice_pol = (
    4980990673427087034113103774848375913397675011396681161337606780457883155824640000000000*t**12
    - 16313074573215242896867677175985719375664055250377801991087546344967331905536000000000*t**9
    - 14852779293587242300314544658084523021409425155052443959294262319432698489552764928000000*t**8
    + 18694126910889886952945780127491545129704079293214429569400282861674612412907520000*t**6
    + 32429224374768702788524801575483580065598417846595577296275963028007688596147404800000*t**5
    + 14763130935033327878568955564665179022508855828282305094488782847988800598441515915673600*t**4
    - 7447056930374930458107131157447569387299331973073657492405996702806537404416000*t**3
    - 18581243794708202636835504417848386599346688512251081679746508518773002589362454528*t**2
    - 16116744082275656666424675660780874575937043631040306492377025123023286892432343685120*t
    - 4891341219838850087826096307272910719484535278552470341569283855964428449539674077056375)
quadric_slice_crit = AA.polynomial_root(quadric_slice_pol, RIF(-0.999,-0.998))

aa = AA.polynomial_root(AA.common_polynomial(t**2 - t - 6256320), RIF(-RR(2500.7637305969961), -RR(2500.7637305969956)))
K, a = NumberField(t**2 - t - 6256320, 'a', embedding=aa).objgen()
DiffOps_x, x, Dx = DifferentialOperators(K, 'x')
iint_quadratic_alg = IVP(
    dop = (
        (8680468749131953125000000000000000000000*x**13 
        + (34722222218750000000000000000000*a 
        - 8680555572048611109375000000000000000000)*x**12 
        - 43419899820094632213834375000000000000000*x**11 
        + (
        -173681336093739466250000000000000*a 
        + 43420334110275534609369733125000000000000)*x**10 
        + 86874920665761352031076792873375000000000*x**9 
        + (347503157694622354347850650000000*a 
        - 86875789597407167434273839673925325000000)*x**8 
        - 86910050568035794059326480970966757245000*x**7 
        + (
Exemple #12
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
Exemple #13
0
from sage.rings.all import NumberField, QQ

R = QQ['x']
x = R.gen()
F = NumberField(x*x - x- 1, 'a')
a = F.gen()
Exemple #14
0
from sage.rings.all import NumberField, QQ

R = QQ['x']
x = R.gen()
F = NumberField(x * x - x - 1, 'a')
a = F.gen()
Exemple #15
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
def is_geom_trivial_when_field(C, bad_primes, B=200):
    r"""
    Determine if the geometric endomorphism ring is trivial assuming the
    geometric endomorphism algebra is a field.

    This is Algorithm 4.15 in [Lom2019]_.

    INPUT:

    - ``C`` -- the hyperelliptic curve.

    - ``bad_primes`` -- the list of odd primes of bad reduction.

    - ``B`` -- (default: 200) the bound which appears in the statement of
      the algorithm from [Lom2019]_

    OUTPUT:

    Boolean indicating whether or not the geometric endomorphism
    algebra is the field of rational numbers.

    WARNING:

    There is a very small chance that this algorithm returns ``False`` when in
    fact it is ``True``. In this case, as explained in the discussion
    immediately preceding Algorithm 4.15 of [Lom2019]_, this can be established
    by increasing the optional `B` parameter. Mathematically, this algorithm
    gives the correct answer only in the limit as `B \to \infty`, although in
    practice `B = 200` was sufficient to correctly verify every single entry
    in the LMFDB. However, strictly speaking, a ``False`` returned by this
    function is not provably ``False``.

    EXAMPLES:

    This is LMFDB curve 461.a.461.2::

        sage: from sage.schemes.hyperelliptic_curves.jacobian_endomorphism_utils import is_geom_trivial_when_field
        sage: R.<x> = QQ[]
        sage: f = 4*x^5 - 4*x^4 - 156*x^3 + 40*x^2 + 1088*x - 1223
        sage: C = HyperellipticCurve(f)
        sage: is_geom_trivial_when_field(C,[461])
        True

    This is LMFDB curve 4489.a.4489.1::

        sage: f = x^6 + 4*x^5 + 2*x^4 + 2*x^3 + x^2 - 2*x + 1
        sage: C = HyperellipticCurve(f)
        sage: is_geom_trivial_when_field(C,[67])
        False
    """

    running_gcd = 0
    R = PolynomialRing(ZZ,2,"xv")
    x,v = R.gens()
    T = PolynomialRing(QQ,'v')
    g = v - x**4

    for p in prime_range(3,B):
        if p not in bad_primes:
            Cp = C.change_ring(FiniteField(p))
            fp = Cp.frobenius_polynomial()
            if satisfies_coefficient_condition(fp, p):
                # This defines the polynomial f_v**[4] from the paper
                fp4 = T(R(fp).resultant(g))
                if fp4.is_irreducible():
                    running_gcd = gcd(running_gcd, NumberField(fp,'a').discriminant())
                    if running_gcd <= 24:
                        return True
    return False
    def arnoux_yoccoz(genus):
        r"""
        Construct the Arnoux-Yoccoz surface of genus 3 or greater.

        This presentation of the surface follows Section 2.3 of
        Joshua P. Bowman's paper "The Complete Family of Arnoux-Yoccoz
        Surfaces."

        EXAMPLES::

            sage: from flatsurf import *
            sage: s = translation_surfaces.arnoux_yoccoz(4)
            sage: TestSuite(s).run()
            sage: s.is_delaunay_decomposed()
            True
            sage: s = s.canonicalize()
            sage: field=s.base_ring()
            sage: a = field.gen()
            sage: from sage.matrix.constructor import Matrix
            sage: m = Matrix([[a,0],[0,~a]])
            sage: ss = m*s
            sage: ss = ss.canonicalize()
            sage: s.cmp(ss) == 0
            True

        The Arnoux-Yoccoz pseudo-Anosov are known to have (minimal) invariant
        foliations with SAF=0::

            sage: S3 = translation_surfaces.arnoux_yoccoz(3)
            sage: Jxx, Jyy, Jxy = S3.j_invariant()
            sage: Jxx.is_zero() and Jyy.is_zero()
            True
            sage: Jxy
            [ 0  2  0]
            [ 2 -2  0]
            [ 0  0  2]

            sage: S4 = translation_surfaces.arnoux_yoccoz(4)
            sage: Jxx, Jyy, Jxy = S4.j_invariant()
            sage: Jxx.is_zero() and Jyy.is_zero()
            True
            sage: Jxy
            [ 0  2  0  0]
            [ 2 -2  0  0]
            [ 0  0  2  2]
            [ 0  0  2  0]
        """
        g = ZZ(genus)
        assert g >= 3
        x = polygen(AA)
        p = sum([x**i for i in range(1, g + 1)]) - 1
        cp = AA.common_polynomial(p)
        alpha_AA = AA.polynomial_root(cp, RIF(1 / 2, 1))
        field = NumberField(alpha_AA.minpoly(), 'alpha', embedding=alpha_AA)
        a = field.gen()
        V = VectorSpace(field, 2)
        p = [None for i in range(g + 1)]
        q = [None for i in range(g + 1)]
        p[0] = V(((1 - a**g) / 2, a**2 / (1 - a)))
        q[0] = V((-a**g / 2, a))
        p[1] = V((-(a**(g - 1) + a**g) / 2, (a - a**2 + a**3) / (1 - a)))
        p[g] = V((1 + (a - a**g) / 2, (3 * a - 1 - a**2) / (1 - a)))
        for i in range(2, g):
            p[i] = V(((a - a**i) / (1 - a), a / (1 - a)))
        for i in range(1, g + 1):
            q[i] = V(((2 * a - a**i - a**(i + 1)) / (2 * (1 - a)),
                      (a - a**(g - i + 2)) / (1 - a)))
        P = ConvexPolygons(field)
        s = Surface_list(field)
        T = [None] * (2 * g + 1)
        Tp = [None] * (2 * g + 1)
        from sage.matrix.constructor import Matrix
        m = Matrix([[1, 0], [0, -1]])
        for i in range(1, g + 1):
            # T_i is (P_0,Q_i,Q_{i-1})
            T[i] = s.add_polygon(
                P(edges=[q[i] - p[0], q[i - 1] - q[i], p[0] - q[i - 1]]))
            # T_{g+i} is (P_i,Q_{i-1},Q_{i})
            T[g + i] = s.add_polygon(
                P(edges=[q[i - 1] - p[i], q[i] - q[i - 1], p[i] - q[i]]))
            # T'_i is (P'_0,Q'_{i-1},Q'_i)
            Tp[i] = s.add_polygon(m * s.polygon(T[i]))
            # T'_{g+i} is (P'_i,Q'_i, Q'_{i-1})
            Tp[g + i] = s.add_polygon(m * s.polygon(T[g + i]))
        for i in range(1, g):
            s.change_edge_gluing(T[i], 0, T[i + 1], 2)
            s.change_edge_gluing(Tp[i], 2, Tp[i + 1], 0)
        for i in range(1, g + 1):
            s.change_edge_gluing(T[i], 1, T[g + i], 1)
            s.change_edge_gluing(Tp[i], 1, Tp[g + i], 1)
        #P 0 Q 0 is paired with P' 0 Q' 0, ...
        s.change_edge_gluing(T[1], 2, Tp[g], 2)
        s.change_edge_gluing(Tp[1], 0, T[g], 0)
        # P1Q1 is paired with P'_g Q_{g-1}
        s.change_edge_gluing(T[g + 1], 2, Tp[2 * g], 2)
        s.change_edge_gluing(Tp[g + 1], 0, T[2 * g], 0)
        # P1Q0 is paired with P_{g-1} Q_{g-1}
        s.change_edge_gluing(T[g + 1], 0, T[2 * g - 1], 2)
        s.change_edge_gluing(Tp[g + 1], 2, Tp[2 * g - 1], 0)
        # PgQg is paired with Q1P2
        s.change_edge_gluing(T[2 * g], 2, T[g + 2], 0)
        s.change_edge_gluing(Tp[2 * g], 0, Tp[g + 2], 2)
        for i in range(2, g - 1):
            # PiQi is paired with Q'_i P'_{i+1}
            s.change_edge_gluing(T[g + i], 2, Tp[g + i + 1], 2)
            s.change_edge_gluing(Tp[g + i], 0, T[g + i + 1], 0)
        s.set_immutable()
        return TranslationSurface(s)