Exemplo n.º 1
0
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.polygon 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,
         [1/2*a^2 - 3/2, 1/2*a])
    """
    from sage.rings.qqbar import number_field_elements_from_algebraics
    from sage.rings.number_field.number_field import NumberField
    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]
Exemplo n.º 2
0
def platonic_dodecahedron():
    r"""Produce a triple consisting of a polyhedral version of the platonic dodecahedron,
    the associated cone surface, and a ConeSurfaceToPolyhedronMap from the surface
    to the polyhedron.

    EXAMPLES::

    sage: from flatsurf.geometry.polyhedra import platonic_dodecahedron
    sage: polyhedron,surface,surface_to_polyhedron = platonic_dodecahedron()
    sage: TestSuite(surface).run()
    r"""
    vertices = []
    phi = AA(1 + sqrt(5)) / 2
    F = NumberField(phi.minpoly(), "phi", embedding=phi)
    phi = F.gen()
    for x in range(-1, 3, 2):
        for y in range(-1, 3, 2):
            for z in range(-1, 3, 2):
                vertices.append(vector(F, (x, y, z)))
    for x in range(-1, 3, 2):
        for y in range(-1, 3, 2):
            vertices.append(vector(F, (0, x * phi, y / phi)))
            vertices.append(vector(F, (y / phi, 0, x * phi)))
            vertices.append(vector(F, (x * phi, y / phi, 0)))
    scale = AA(2 / sqrt(1 + (phi - 1)**2 + (1 / phi - 1)**2))
    p = Polyhedron(vertices=vertices)
    s, m = polyhedron_to_cone_surface(p, scaling_factor=scale)
    return p, s, m
Exemplo n.º 3
0
def platonic_dodecahedron():
    r"""Produce a triple consisting of a polyhedral version of the platonic dodecahedron,
    the associated cone surface, and a ConeSurfaceToPolyhedronMap from the surface
    to the polyhedron.

    EXAMPLES::

    sage: from flatsurf.geometry.polyhedra import platonic_dodecahedron
    sage: polyhedron,surface,surface_to_polyhedron = platonic_dodecahedron()
    sage: TestSuite(surface).run()
    r"""
    vertices=[]
    phi=AA(1+sqrt(5))/2
    F=NumberField(phi.minpoly(),"phi",embedding=phi)
    phi=F.gen()
    for x in xrange(-1,3,2):
        for y in xrange(-1,3,2):
            for z in xrange(-1,3,2):
                vertices.append(vector(F,(x,y,z)))
    for x in xrange(-1,3,2):
        for y in xrange(-1,3,2):
            vertices.append(vector(F,(0,x*phi,y/phi)))
            vertices.append(vector(F,(y/phi,0,x*phi)))
            vertices.append(vector(F,(x*phi,y/phi,0)))
    scale=AA(2/sqrt(1+(phi-1)**2+(1/phi-1)**2))
    p=Polyhedron(vertices=vertices)
    s,m = polyhedron_to_cone_surface(p,scaling_factor=scale)
    return p,s,m
Exemplo n.º 4
0
def platonic_icosahedron():
    r"""Produce a triple consisting of a polyhedral version of the platonic icosahedron,
    the associated cone surface, and a ConeSurfaceToPolyhedronMap from the surface
    to the polyhedron.

    EXAMPLES::

    sage: from flatsurf.geometry.polyhedra import platonic_icosahedron
    sage: polyhedron,surface,surface_to_polyhedron = platonic_icosahedron()
    sage: TestSuite(surface).run()
    r"""
    vertices=[]
    phi=AA(1+sqrt(5))/2
    F=NumberField(phi.minpoly(),"phi",embedding=phi)
    phi=F.gen()
    for i in xrange(3):
        for s1 in xrange(-1,3,2):
            for s2 in xrange(-1,3,2):
                p=3*[None]
                p[i]=s1*phi
                p[(i+1)%3]=s2
                p[(i+2)%3]=0
                vertices.append(vector(F,p))
    p=Polyhedron(vertices=vertices)
    
    s,m = polyhedron_to_cone_surface(p)
    return p,s,m
Exemplo n.º 5
0
def platonic_icosahedron():
    r"""Produce a triple consisting of a polyhedral version of the platonic icosahedron,
    the associated cone surface, and a ConeSurfaceToPolyhedronMap from the surface
    to the polyhedron.

    EXAMPLES::

    sage: from flatsurf.geometry.polyhedra import platonic_icosahedron
    sage: polyhedron,surface,surface_to_polyhedron = platonic_icosahedron()
    sage: TestSuite(surface).run()
    r"""
    vertices = []
    phi = AA(1 + sqrt(5)) / 2
    F = NumberField(phi.minpoly(), "phi", embedding=phi)
    phi = F.gen()
    for i in range(3):
        for s1 in range(-1, 3, 2):
            for s2 in range(-1, 3, 2):
                p = 3 * [None]
                p[i] = s1 * phi
                p[(i + 1) % 3] = s2
                p[(i + 2) % 3] = 0
                vertices.append(vector(F, p))
    p = Polyhedron(vertices=vertices)

    s, m = polyhedron_to_cone_surface(p)
    return p, s, m
Exemplo n.º 6
0
def test_type_2_primes(f, class_number):
    K = NumberField(f, "a")
    Kgal = K.galois_closure("b")
    embeddings = K.embeddings(Kgal)

    type_two_not_momose = get_type_2_not_momose(K, embeddings)
    _ = type_2_primes(K, embeddings, **TEST_SETTINGS)

    if class_number == 1:
        assert type_two_not_momose == set()
Exemplo n.º 7
0
    def _number_field_from_algebraics(self):
        r"""
        Given a projective point defined over ``QQbar``, return the same point, but defined
        over a number field.

        This is only implemented for points of projective space.

        OUTPUT: scheme point

        EXAMPLES::

            sage: R.<x> = PolynomialRing(QQ)
            sage: P.<x,y> = ProjectiveSpace(QQbar,1)
            sage: Q = P([-1/2*QQbar(sqrt(2)) + QQbar(I), 1])
            sage: S = Q._number_field_from_algebraics(); S
            (1/2*a^3 + a^2 - 1/2*a : 1)
            sage: S.codomain()
            Projective Space of dimension 1 over Number Field in a with defining polynomial y^4 + 1 with a = 0.7071067811865475? + 0.7071067811865475?*I

        The following was fixed in :trac:`23808`::

            sage: R.<x> = PolynomialRing(QQ)
            sage: P.<x,y> = ProjectiveSpace(QQbar,1)
            sage: Q = P([-1/2*QQbar(sqrt(2)) + QQbar(I), 1]);Q
            (-0.7071067811865475? + 1*I : 1)
            sage: S = Q._number_field_from_algebraics(); S
            (1/2*a^3 + a^2 - 1/2*a : 1)
            sage: T = S.change_ring(QQbar) # Used to fail
            sage: T
            (-0.7071067811865475? + 1.000000000000000?*I : 1)
            sage: Q[0] == T[0]
            True
        """
        from sage.schemes.projective.projective_space import is_ProjectiveSpace
        if not is_ProjectiveSpace(self.codomain()):
            raise NotImplementedError("not implemented for subschemes")

        # Trac #23808: Keep the embedding info associated with the number field K
        # used below, instead of in the separate embedding map phi which is
        # forgotten.
        K_pre, P, phi = number_field_elements_from_algebraics(list(self))
        if K_pre is QQ:
            K = QQ
        else:
            from sage.rings.number_field.number_field import NumberField
            K = NumberField(K_pre.polynomial(),
                            embedding=phi(K_pre.gen()),
                            name='a')
            psi = K_pre.hom([K.gen()], K)  # Identification of K_pre with K
            P = [psi(p) for p in P]  # The elements of P were elements of K_pre
        from sage.schemes.projective.projective_space import ProjectiveSpace
        PS = ProjectiveSpace(K, self.codomain().dimension_relative(), 'z')
        return PS(P)
Exemplo n.º 8
0
def as_embedded_number_field_element(alg):
    from sage.rings.number_field.number_field import NumberField
    nf, elt, emb = alg.as_number_field_element()
    if nf is QQ:
        res = elt
    else:
        embnf = NumberField(nf.polynomial(),
                            nf.variable_name(),
                            embedding=emb(nf.gen()))
        res = elt.polynomial()(embnf.gen())
    # assert QQbar.coerce(res) == alg
    return res
def test_type_three_not_momose(f, class_number, strong_L_count):
    K = NumberField(f, "a")
    Kgal = K.galois_closure("b")
    embeddings = K.embeddings(Kgal)

    strong_type_3_epsilons = get_strong_type_3_epsilons(K, embeddings)

    assert len(strong_type_3_epsilons) == 2 * strong_L_count

    type_3_not_momose_primes, _ = type_three_not_momose(
        K, embeddings, strong_type_3_epsilons)

    if class_number == 1:
        assert type_3_not_momose_primes == []
Exemplo n.º 10
0
    def get_cocycle_from_elliptic_curve(self,E,sign = 1,use_magma = True):
        if sign == 0:
            return self.get_cocycle_from_elliptic_curve(E,1,use_magma) + self.get_cocycle_from_elliptic_curve(E,-1,use_magma)
        if not sign in [1, -1]:
            raise NotImplementedError
        F = self.group().base_ring()
        if F.signature()[1] == 0 or (F.signature() == (0,1) and 'G' not in self.group()._grouptype):
            K = (self.hecke_matrix(oo).transpose()-sign).kernel().change_ring(QQ)
        else:
            K = Matrix(QQ,self.dimension(),self.dimension(),0).kernel()
        disc = self.S_arithgroup().Gpn._O_discriminant
        discnorm = disc.norm()
        try:
            N = ZZ(discnorm.gen())
        except AttributeError:
            N = ZZ(discnorm)

        if F == QQ:
            x = QQ['x'].gen()
            F = NumberField(x,names='a')
            E = E.change_ring(F)

        def getap(q):
            if F == QQ:
                return E.ap(q)
            else:
                Q = F.ideal(q).factor()[0][0]
                return ZZ(Q.norm() + 1 - E.reduction(Q).count_points())

        q = ZZ(1)
        g0 = None
        while K.dimension() > 1:
            q = q.next_prime()
            for qq,e in F.ideal(q).factor():
                if  ZZ(qq.norm()).is_prime() and not qq.divides(F.ideal(disc.gens_reduced()[0])):
                    try:
                        ap = getap(qq)
                    except (ValueError,ArithmeticError):
                        continue
                    try:
                        K1 = (self.hecke_matrix(qq.gens_reduced()[0],g0 = g0,use_magma = use_magma).transpose()-ap).kernel()
                    except RuntimeError:
                        continue
                    K = K.intersection(K1)
        if K.dimension() != 1:
            raise ValueError,'Did not obtain a one-dimensional space corresponding to E'
        col = [ZZ(o) for o in (K.denominator()*K.matrix()).list()]
        return sum([a * self.gen(i) for i,a in enumerate(col) if a != 0],self(0))
Exemplo n.º 11
0
def number_field_with_integer_gen(K):
    r"""
    TESTS::

        sage: from ore_algebra.analytic.utilities import number_field_with_integer_gen
        sage: K = NumberField(6*x^2 + (2/3)*x - 9/17, 'a')
        sage: number_field_with_integer_gen(K)[0]
        Number Field in x306a with defining polynomial x^2 + 34*x - 8262 ...
    """
    if K is QQ:
        return QQ, ZZ
    den = K.polynomial().monic().denominator()
    if den.is_one():
        # Ensure that we return the same number field object (coercions can be
        # slow!)
        intNF = K
    else:
        intgen = K.gen() * den
        ### Attempt to work around various problems with embeddings
        emb = K.coerce_embedding()
        embgen = emb(intgen) if emb else intgen
        intNF = NumberField(intgen.minpoly(), "x" + str(den) + str(K.gen()),
                            embedding=embgen)
        assert intNF != K
    intNF, _ = good_number_field(intNF)
    # Work around weaknesses in coercions involving order elements,
    # including #14982 (fixed). Used to trigger #14989 (fixed).
    #return intNF, intNF.order(intNF.gen())
    return intNF, intNF
Exemplo n.º 12
0
 def __init__(self,lambda_squared=None, field=None):
     if lambda_squared==None:
         from sage.rings.number_field.number_field import NumberField
         from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
         R=PolynomialRing(ZZ,'x')
         x = R.gen()
         from sage.rings.qqbar import AA
         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)
Exemplo n.º 13
0
def test_galois_action_on_embeddings(f, gal_deg):
    K = NumberField(f, "a")
    G_K = K.galois_group()
    G_K_emb, to_emb, from_emb, Kgal, embeddings = galois_action_on_embeddings(
        G_K)
    # test that to_emb and from_emb are isomorphism
    assert G_K.hom(G_K) == from_emb * to_emb
    assert G_K_emb.hom(G_K_emb) == to_emb * from_emb
    assert to_emb.domain() == G_K
    assert to_emb.codomain() == G_K_emb
    assert from_emb.domain() == G_K_emb
    assert from_emb.codomain() == G_K
    assert embeddings[0] == G_K.gen(0).as_hom() * embeddings[G_K_emb.gen(0)
                                                             (1) - 1]
    assert Kgal.degree() == G_K_emb.cardinality() == gal_deg
    assert G_K_emb.degree() == len(embeddings) == K.degree()
Exemplo n.º 14
0
def _over_numberfield(E):
    r"""Return `E`, defined over a NumberField object. This is necessary
    since if `E` is defined over `\QQ`, then we cannot use SAGE commands
    available for number fields.

    INPUT:

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

    OUTPUT:

    - If `E` is defined over a NumberField, returns E.

    - If `E` is defined over QQ, returns E defined over the NumberField QQ.

    EXAMPLES::

        sage: E = EllipticCurve([1, 2])
        sage: sage.schemes.elliptic_curves.gal_reps_number_field._over_numberfield(E)
        Elliptic Curve defined by y^2 = x^3 + x + 2 over Number Field in a with defining polynomial x
    """

    K = E.base_field()

    if K == QQ:
        x = QQ['x'].gen()
        K = NumberField(x, 'a')
        E = E.change_ring(K)

    return E
Exemplo n.º 15
0
    def self_similar_interval_exchange_transformation(self):
        r"""
        Return the dilatation and the self-similar interval exchange
        transformation associated to this path.

        EXAMPLES::

            sage: from surface_dynamics import iet

        The golden rotation::

            sage: p = iet.Permutation('a b', 'b a')
            sage: g = iet.FlipSequence(p, ['t', 'b'])
            sage: a, T = g.self_similar_iet()
            sage: T.lengths().parent()
            Vector space of dimension 2 over Number Field ...
            sage: T.lengths().n()
            (1.00000000000000, 1.61803398874989)

        An example from Do-Schmidt::

            sage: code = [1,0,1,0,1,0,0,0,1,0,0,1,1,1,0,0,0,0,1,1,1,1,1,0,0,0,0,0,1,1,1,0]
            sage: p = iet.Permutation([0,1,2,3,4,5,6],[6,5,4,3,2,1,0])
            sage: g = iet.FlipSequence(p, code)
            sage: a, T = g.self_similar_iet()
            sage: T.sah_arnoux_fathi_invariant()
            (0, 0, 0)
        """
        if not self.is_complete():
            raise ValueError('not a complete loop')
        from sage.rings.qqbar import AA
        m = self.matrix()
        poly = m.charpoly()
        rho = max(poly.roots(AA, False))
        try:
            K, a, _ = rho.as_number_field_element(minimal=True, embedded=True)
        except TypeError:
            # NOTE: the embedded option appeared in sage 8.8
            from sage.rings.number_field.number_field import NumberField
            L, b, _ = rho.as_number_field_element(minimal=True)
            K = NumberField(L.polynomial(), str(L.gen()), embedding=rho)
            a = K(b.polynomial())

        lengths = (m - a).right_kernel().basis()[0]
        if lengths[0] < 0:
            lengths = -lengths
        if any(x <= 0 for x in lengths):
            raise RuntimeError(
                "wrong Perron-Frobenius eigenvector: {}".format(lengths))

        # NOTE: the above code makes "lengths" with parent being the right kernel (that is
        # a submodule of R^d)
        lengths = lengths.parent().ambient_vector_space()(lengths)

        from .iet import IntervalExchangeTransformation
        return a, IntervalExchangeTransformation(self._start, lengths)
Exemplo n.º 16
0
def is_algebraic_integer(x):
    """
    Determine whether a number is an algebraic integer,
    or whether the given minimal polynomial defines one.
    """
    if x is None:
        return None
    if not isinstance(x, Polynomial):
        x = SR(x).minpoly()
    return NumberField(x, names=('a', )).gen().is_integral()
def test_cm_type_2(f, extra_isogenies, potenial_isogenies):
    K = NumberField(f, "a")

    superset, _ = get_isogeny_primes(K, **TEST_SETTINGS)
    assert set(EC_Q_ISOGENY_PRIMES).difference(superset) == set()
    # for p in extra_isogenies:
    #     assert satisfies_condition_CC(K, p), "Not of type 2"
    pnip = sorted(superset.difference(set(EC_Q_ISOGENY_PRIMES)))
    print("f = {}  disc = {} pnip = {}".format(f, K.discriminant(), pnip))
    assert (extra_isogenies.difference(superset) == set()
            ), "Known CM isogenies are filtered out!"
    upperbound = potenial_isogenies.union(EC_Q_ISOGENY_PRIMES).union(
        extra_isogenies)
    upperbound = upperbound.union(bad_cubic_formal_immersion_primes)
    unlisted_potential_isogenies = superset.difference(upperbound)
    assert len(unlisted_potential_isogenies) <= 2, "We got worse at filtering"
    if unlisted_potential_isogenies:
        assert max(
            unlisted_potential_isogenies) <= 109, "We got worse at filtering"
Exemplo n.º 18
0
 def extract(cls, obj):
     """
     Takes an object extracted by the json parser and decodes the
     special-formating dictionaries used to store special types.
     """
     if isinstance(obj, dict) and 'data' in obj:
         if len(obj) == 2 and '__ComplexList__' in obj:
             return [complex(*v) for v in obj['data']]
         elif len(obj) == 2 and '__QQList__' in obj:
             return [QQ(tuple(v)) for v in obj['data']]
         elif len(obj) == 3 and '__NFList__' in obj and 'base' in obj:
             base = cls.extract(obj['base'])
             return [cls._extract(base, c) for c in obj['data']]
         elif len(obj) == 2 and '__IntDict__' in obj:
             return {Integer(k): cls.extract(v) for k,v in obj['data']}
         elif len(obj) == 3 and '__Vector__' in obj and 'base' in obj:
             base = cls.extract(obj['base'])
             return vector([cls._extract(base, v) for v in obj['data']])
         elif len(obj) == 2 and '__Rational__' in obj:
             return Rational(*obj['data'])
         elif len(obj) == 3 and '__RealLiteral__' in obj and 'prec' in obj:
             return LmfdbRealLiteral(RealField(obj['prec']), obj['data'])
         elif len(obj) == 2 and '__complex__' in obj:
             return complex(*obj['data'])
         elif len(obj) == 3 and '__Complex__' in obj and 'prec' in obj:
             return ComplexNumber(ComplexField(obj['prec']), *obj['data'])
         elif len(obj) == 3 and '__NFElt__' in obj and 'parent' in obj:
             return cls._extract(cls.extract(obj['parent']), obj['data'])
         elif len(obj) == 3 and ('__NFRelative__' in obj or '__NFAbsolute__' in obj) and 'vname' in obj:
             poly = cls.extract(obj['data'])
             return NumberField(poly, name=obj['vname'])
         elif len(obj) == 2 and '__NFCyclotomic__' in obj:
             return CyclotomicField(obj['data'])
         elif len(obj) == 2 and '__IntegerRing__' in obj:
             return ZZ
         elif len(obj) == 2 and '__RationalField__' in obj:
             return QQ
         elif len(obj) == 3 and '__RationalPoly__' in obj and 'vname' in obj:
             return QQ[obj['vname']]([QQ(tuple(v)) for v in obj['data']])
         elif len(obj) == 4 and '__Poly__' in obj and 'vname' in obj and 'base' in obj:
             base = cls.extract(obj['base'])
             return base[obj['vname']]([cls._extract(base, c) for c in obj['data']])
         elif len(obj) == 5 and '__PowerSeries__' in obj and 'vname' in obj and 'base' in obj and 'prec' in obj:
             base = cls.extract(obj['base'])
             prec = infinity if obj['prec'] == 'inf' else int(obj['prec'])
             return base[[obj['vname']]]([cls._extract(base, c) for c in obj['data']], prec=prec)
         elif len(obj) == 2 and '__date__' in obj:
             return datetime.datetime.strptime(obj['data'], "%Y-%m-%d").date()
         elif len(obj) == 2 and '__time__' in obj:
             return datetime.datetime.strptime(obj['data'], "%H:%M:%S.%f").time()
         elif len(obj) == 2 and '__datetime__' in obj:
             return datetime.datetime.strptime(obj['data'], "%Y-%m-%d %H:%M:%S.%f")
     return obj
Exemplo n.º 19
0
def test_galois(f, extra_isogenies, potenial_isogenies):
    K = NumberField(f, "a")

    superset, _ = get_isogeny_primes(K, **TEST_SETTINGS)
    assert set(EC_Q_ISOGENY_PRIMES).difference(superset) == set()
    assert (
        extra_isogenies.difference(superset) == set()
    ), "Known isogenies are filtered out!"
    upperbound = potenial_isogenies.union(EC_Q_ISOGENY_PRIMES).union(extra_isogenies)
    unlisted_potential_isogenies = superset.difference(upperbound)
    assert unlisted_potential_isogenies == set(), "We got worse at filtering"
    assert set(upperbound.difference(superset)) == set(), "We got better at filtering"
Exemplo n.º 20
0
    def get_rational_cocycle_from_ap(self,getap,sign = 1,use_magma = True):
        F = self.group().base_ring()
        if F.signature()[1] == 0 or (F.signature() == (0,1) and 'G' not in self.group()._grouptype):
            K = (self.hecke_matrix(oo).transpose()-sign).kernel().change_ring(QQ)
        else:
            K = Matrix(QQ,self.dimension(),self.dimension(),0).kernel()

        disc = self.S_arithgroup().Gpn._O_discriminant
        discnorm = disc.norm()
        try:
            N = ZZ(discnorm.gen())
        except AttributeError:
            N = ZZ(discnorm)

        if F == QQ:
            x = QQ['x'].gen()
            F = NumberField(x,names='a')
        q = ZZ(1)
        g0 = None
        while K.dimension() > 1:
            q = q.next_prime()
            for qq,e in F.ideal(q).factor():
                if  ZZ(qq.norm()).is_prime() and not qq.divides(F.ideal(disc.gens_reduced()[0])):
                    try:
                        ap = getap(qq)
                    except (ValueError,ArithmeticError):
                        continue
                    try:
                        K1 = (self.hecke_matrix(qq.gens_reduced()[0],g0 = g0,use_magma = use_magma).transpose()-ap).kernel()
                    except RuntimeError:
                        continue
                    K = K.intersection(K1)
        if K.dimension() != 1:
            raise ValueError,'Group does not have the required system of eigenvalues'

        col = [ZZ(o) for o in (K.denominator()*K.matrix()).list()]
        return sum([ a * self.gen(i) for i,a in enumerate(col) if a != 0], self(0))
Exemplo n.º 21
0
    def field(self):
        r"""
        EXAMPLES::

            sage: from EkEkstar import GeoSub
            sage: sub = {1:[1,2], 2:[1,3], 3:[1]}
            sage: E = GeoSub(sub,2)
            sage: E.field()
            Number Field in b with defining polynomial x^3 - x^2 - x - 1
        """
        M = self._sigma.incidence_matrix()
        b1 = max(M.eigenvalues(), key=abs)
        f = b1.minpoly()
        K = NumberField(f, 'b')
        return K
 def __init__(self,lambda_squared=None, field=None):
     TranslationSurface_generic.__init__(self)
     if lambda_squared==None:
         from sage.rings.number_field.number_field import NumberField
         from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
         R=PolynomialRing(ZZ,'x')
         x = R.gen()
         from sage.rings.qqbar import AA
         self._field=NumberField(x**3-ZZ(5)*x**2+ZZ(4)*x-ZZ(1), 'r', embedding=AA(ZZ(4)))
         self._l=self._field.gen()
     else:
         if field is None:
             self._l=lambda_squared
             self._field=lambda_squared.parent()
         else:
             self._field=field
             self._l=field(lambda_squared)
Exemplo n.º 23
0
def as_embedded_number_field_elements(algs):
    # number_field_elements_from_algebraics() now takes an embedded=...
    # argument, but doesn't yet support all cases we need
    nf, elts, emb = number_field_elements_from_algebraics(algs)
    if nf is not QQ:
        nf = NumberField(nf.polynomial(), nf.variable_name(),
                    embedding=emb(nf.gen()))
        elts = [elt.polynomial()(nf.gen()) for elt in elts]
        nf, hom = good_number_field(nf)
        elts = [hom(elt) for elt in elts]
    # assert [QQbar.coerce(elt) == alg for alg, elt in zip(algs, elts)]
    return nf, elts
Exemplo n.º 24
0
def as_embedded_number_field_elements(algs):
    try:
        nf, elts, _ = number_field_elements_from_algebraics(algs, embedded=True)
    except NotImplementedError: # compatibility with Sage <= 9.3
        nf, elts, emb = number_field_elements_from_algebraics(algs)
        if nf is not QQ:
            nf = NumberField(nf.polynomial(), nf.variable_name(),
                        embedding=emb(nf.gen()))
            elts = [elt.polynomial()(nf.gen()) for elt in elts]
            nf, hom = good_number_field(nf)
            elts = [hom(elt) for elt in elts]
        assert [QQbar.coerce(elt) == alg for alg, elt in zip(algs, elts)]
    return nf, elts
Exemplo n.º 25
0
def _number_field_with_integer_gen(K):
    if K is QQ:
        return QQ, ZZ
    den = K.defining_polynomial().denominator()
    if den.is_one():
        # Ensure that we return the same number field object (coercions can be
        # slow!)
        intNF = K
    else:
        intgen = K.gen() * den
        ### Attempt to work around various problems with embeddings
        emb = K.coerce_embedding()
        embgen = emb(intgen) if emb else intgen
        intNF = NumberField(intgen.minpoly(),
                            str(K.gen) + str(den),
                            embedding=embgen)
        assert intNF != K
    # Work around weaknesses in coercions involving order elements,
    # including #14982 (fixed). Used to trigger #14989 (fixed).
    #return intNF, intNF.order(intNF.gen())
    return intNF, intNF
Exemplo n.º 26
0
def enumerate_totallyreal_fields_all(n,
                                     B,
                                     verbose=0,
                                     return_seqs=False,
                                     return_pari_objects=True):
    r"""
    Enumerates *all* totally real fields of degree ``n`` with discriminant
    at most ``B``, primitive or otherwise.

    INPUT:

    - ``n`` -- integer, the degree
    - ``B`` -- integer, the discriminant bound
    - ``verbose`` -- boolean or nonnegative integer or string (default: 0)
      give a verbose description of the computations being performed. If
      ``verbose`` is set to ``2`` or more then it outputs some extra
      information. If ``verbose`` is a string then it outputs to a file
      specified by ``verbose``
    - ``return_seqs`` -- (boolean, default False) If ``True``, then return
      the polynomials as sequences (for easier exporting to a file). This
      also returns a list of four numbers, as explained in the OUTPUT
      section below.
    - ``return_pari_objects`` -- (boolean, default: True) if both
      ``return_seqs`` and ``return_pari_objects`` are ``False`` then it
      returns the elements as Sage objects; otherwise it returns pari
      objects.

    EXAMPLES::

        sage: enumerate_totallyreal_fields_all(4, 2000)
        [[725, x^4 - x^3 - 3*x^2 + x + 1],
        [1125, x^4 - x^3 - 4*x^2 + 4*x + 1],
        [1600, x^4 - 6*x^2 + 4],
        [1957, x^4 - 4*x^2 - x + 1],
        [2000, x^4 - 5*x^2 + 5]]
        sage: enumerate_totallyreal_fields_all(1, 10)
        [[1, x - 1]]

    TESTS:

    Each of the outputs must be elements of Sage if ``return_pari_objects``
    is set to ``False``::

        sage: enumerate_totallyreal_fields_all(2, 10)
        [[5, x^2 - x - 1], [8, x^2 - 2]]
        sage: type(enumerate_totallyreal_fields_all(2, 10)[0][1])
        <type 'cypari2.gen.Gen'>
        sage: enumerate_totallyreal_fields_all(2, 10, return_pari_objects=False)[0][1].parent()
        Univariate Polynomial Ring in x over Rational Field


    In practice most of these will be found by
    :func:`~sage.rings.number_field.totallyreal.enumerate_totallyreal_fields_prim`,
    which is guaranteed to return all primitive fields but often returns
    many non-primitive ones as well. For instance, only one of the five
    fields in the example above is primitive, but
    :func:`~sage.rings.number_field.totallyreal.enumerate_totallyreal_fields_prim`
    finds four out of the five (the exception being `x^4 - 6x^2 + 4`).

    The following was fixed in :trac:`13101`::

        sage: enumerate_totallyreal_fields_all(8, 10^6)  # long time (about 2 s)
        []
    """

    S = []
    counts = [0, 0, 0, 0]
    if len(divisors(n)) > 4:
        raise ValueError("Only implemented for n = p*q with p,q prime")
    for d in divisors(n):
        if d > 1 and d < n:
            Sds = enumerate_totallyreal_fields_prim(
                d, int(math.floor((1. * B)**(1. * d / n))), verbose=verbose)
            for i in range(len(Sds)):
                if verbose:
                    print("=" * 80)
                    print("Taking F =", Sds[i][1])
                F = NumberField(ZZx(Sds[i][1]), 't')
                T = enumerate_totallyreal_fields_rel(F,
                                                     n / d,
                                                     B,
                                                     verbose=verbose,
                                                     return_seqs=return_seqs)
                if return_seqs:
                    for i in range(4):
                        counts[i] += T[0][i]
                    S += [[t[0], pari(t[1]).Polrev()] for t in T[1]]
                else:
                    S += [[t[0], t[1]] for t in T]
                for E in enumerate_totallyreal_fields_prim(
                        n / d,
                        int(
                            math.floor((1. * B)**(1. / d) /
                                       (1. * Sds[i][0])**(n * 1. / d**2)))):
                    for EF in F.composite_fields(NumberField(ZZx(E[1]), 'u')):
                        if EF.degree() == n and EF.disc() <= B:
                            S.append(
                                [EF.disc(),
                                 pari(EF.absolute_polynomial())])
    S += enumerate_totallyreal_fields_prim(n, B, verbose=verbose)
    S.sort(key=lambda x: (x[0], [QQ(cf) for cf in x[1].polrecip().Vec()]))
    weed_fields(S)

    # Output.
    if verbose:
        saveout = sys.stdout
        if isinstance(verbose, str):
            fsock = open(verbose, 'w')
            sys.stdout = fsock
        # Else, print to screen
        print("=" * 80)
        print("Polynomials tested: {}".format(counts[0]))
        print("Polynomials with discriminant with large enough square"
              " divisor: {}".format(counts[1]))
        print("Irreducible polynomials: {}".format(counts[2]))
        print("Polynomials with nfdisc <= B: {}".format(counts[3]))
        for i in range(len(S)):
            print(S[i])
        if isinstance(verbose, str):
            fsock.close()
        sys.stdout = saveout

    # Make sure to return elements that belong to Sage
    if return_seqs:
        return [[ZZ(_) for _ in counts],
                [[ZZ(s[0]), [QQ(_) for _ in s[1].polrecip().Vec()]]
                 for s in S]]
    elif return_pari_objects:
        return S
    else:
        Px = PolynomialRing(QQ, 'x')
        return [[ZZ(s[0]), Px([QQ(_) for _ in s[1].list()])] for s in S]
Exemplo n.º 27
0
    def get_rational_cocycle(self,sign = 1,use_magma = True,bound = 3, return_all = False):
        F = self.group().base_ring()
        if F.signature()[1] == 0 or (F.signature()[1] == 1 and 'G' not in self.group()._grouptype):
            K = (self.hecke_matrix(oo).transpose()-sign).kernel().change_ring(QQ)
        else:
            K = Matrix(QQ,self.dimension(),self.dimension(),0).kernel()

        component_list = []
        good_components = []
        if K.dimension() == 1:
            good_components.append(K)
        else:
            component_list.append(K)

        disc = self.S_arithgroup().Gpn._O_discriminant
        discnorm = disc.norm()
        try:
            N = ZZ(discnorm.gen())
        except AttributeError:
            N = ZZ(discnorm)

        if F == QQ:
            x = QQ['x'].gen()
            F = NumberField(x,names='a')
        q = ZZ(1)
        g0 = None
        num_hecke_operators = 0
        while len(component_list) > 0 and num_hecke_operators < bound:
            verbose('num_hecke_ops = %s'%num_hecke_operators)
            verbose('len(components_list) = %s'%len(component_list))
            q = q.next_prime()
            for qq,e in F.ideal(q).factor():
                if  ZZ(qq.norm()).is_prime() and not qq.divides(F.ideal(disc.gens_reduced()[0])):
                    try:
                        Aq = self.hecke_matrix(qq.gens_reduced()[0],g0 = g0,use_magma = use_magma).transpose().change_ring(QQ)
                    except (RuntimeError,TypeError) as e:
                        continue
                    verbose('Computed hecke matrix at qq = %s'%qq)
                    old_component_list = component_list
                    component_list = []
                    num_hecke_operators += 1
                    for U in old_component_list:
                        V = Aq.decomposition_of_subspace(U)
                        for U0,is_irred in V:
                            if Aq.restrict(U0).eigenvalues()[0] == ZZ(qq.norm()) + 1:
                                continue # Do not take Eisenstein classes.
                            if U0.dimension() == 1:
                                good_components.append(U0)
                            elif is_irred:
                                # Bad
                                continue
                            else: # U0.dimension() > 1 and not is_irred
                                component_list.append(U0)
                    if len(good_components) > 0 and not return_all:
                        K = good_components[0]
                        col = [ZZ(o) for o in (K.denominator()*K.matrix()).list()]
                        return sum([a*self.gen(i) for i,a in enumerate(col) if a != 0],self(0))
                    if len(component_list) == 0 or num_hecke_operators >= bound:
                        break

        if len(good_components) == 0:
            raise ValueError('Group does not seem to be attached to an elliptic curve')
        else:
            if return_all:
                ans = []
                for K in good_components:
                    col = [ZZ(o) for o in (K.denominator()*K.matrix()).list()]
                    ans.append( sum([a*self.gen(i) for i,a in enumerate(col) if a != 0],self(0)))
                return ans
            else:
                K = good_components[0]
                col = [ZZ(o) for o in (K.denominator()*K.matrix()).list()]
                return sum([ a * self.gen(i) for i,a in enumerate(col) if a != 0], self(0))
Exemplo n.º 28
0
def enumerate_totallyreal_fields_all(n, B, verbose=0, return_seqs=False):
    r"""
    Enumerates *all* totally real fields of degree `n` with discriminant `\le B`,
    primitive or otherwise.
    
    EXAMPLES::
    
        sage: enumerate_totallyreal_fields_all(4, 2000)
        [[725, x^4 - x^3 - 3*x^2 + x + 1], 
        [1125, x^4 - x^3 - 4*x^2 + 4*x + 1], 
        [1600, x^4 - 6*x^2 + 4], 
        [1957, x^4 - 4*x^2 - x + 1], 
        [2000, x^4 - 5*x^2 + 5]]
    
    In practice most of these will be found by :func:`~sage.rings.number_field.totallyreal.enumerate_totallyreal_fields_prim`, which is guaranteed to return all primitive fields but often returns many non-primitive ones as well. For instance, only one of the five fields in the example above is primitive, but :func:`~sage.rings.number_field.totallyreal.enumerate_totallyreal_fields_prim` finds four out of the five (the exception being `x^4 - 6x^2 + 4`).
    """

    S = []
    counts = [0, 0, 0]
    if len(divisors(n)) > 4:
        raise ValueError, "Only implemented for n = p*q with p,q prime"
    for d in divisors(n):
        if d > 1 and d < n:
            Sds = enumerate_totallyreal_fields_prim(d, int(math.floor((1.0 * B) ** (1.0 * d / n))), verbose=verbose)
            for i in range(len(Sds)):
                if verbose:
                    print "=" * 80
                    print "Taking F =", Sds[i][1]
                F = NumberField(ZZx(Sds[i][1]), "t")
                T = enumerate_totallyreal_fields_rel(F, n / d, B, verbose=verbose, return_seqs=return_seqs)
                if return_seqs:
                    for i in range(3):
                        counts[i] += T[0][i]
                    S += [[t[0], pari(t[1]).Polrev()] for t in T[1]]
                else:
                    S += [[t[0], t[1]] for t in T]
                j = i + 1
                for E in enumerate_totallyreal_fields_prim(
                    n / d, int(math.floor((1.0 * B) ** (1.0 / d) / (1.0 * Sds[i][0]) ** (n * 1.0 / d ** 2)))
                ):
                    for EF in F.composite_fields(NumberField(ZZx(E[1]), "u")):
                        if EF.degree() == n and EF.disc() <= B:
                            S.append([EF.disc(), pari(EF.absolute_polynomial())])
    S += enumerate_totallyreal_fields_prim(n, B, verbose=verbose)
    S.sort()
    weed_fields(S)

    # Output.
    if verbose:
        saveout = sys.stdout
        if type(verbose) == str:
            fsock = open(verbose, "w")
            sys.stdout = fsock
        # Else, print to screen
        print "=" * 80
        print "Polynomials tested:", counts[0]
        print "Irreducible polynomials:", counts[1]
        print "Polynomials with nfdisc <= B:", counts[2]
        for i in range(len(S)):
            print S[i]
        if type(verbose) == str:
            fsock.close()
        sys.stdout = saveout

    if return_seqs:
        return [counts, [[s[0], s[1].reverse().Vec()] for s in S]]
    else:
        return S
Exemplo n.º 29
0
def _semistable_reducible_primes(E):
    r"""Find a list containing all semistable primes l unramified in K/QQ
    for which the Galois image for E could be reducible.

    INPUT:

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

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

    EXAMPLES::

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

    E = _over_numberfield(E)
    K = E.base_field()
    deg_one_primes = K.primes_of_degree_one_iter()

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

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

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

    while len(precomp) < 2:
        P = deg_one_primes.next()

        if not P.is_principal():
            continue

        det = P.norm()
        if det == last_char:
            continue

        if P.ramification_index() != 1:
            continue

        try:
            tr = E.change_ring(P.residue_field()).trace_of_frobenius()
        except ArithmeticError: # Bad reduction at P.
            continue

        x = P.gens_reduced()[0]

        precomp.append((x, _tr12(tr, det)))
        last_char = det

    x, tx = precomp[0]
    y, ty = precomp[1]

    Kgal = K.galois_closure('b')
    maps = K.embeddings(Kgal)

    for i in xrange(2 ** (K.degree() - 1)):
        ## We iterate through all possible characters. ##

        # Here, if i = i_{l-1} i_{l-2} cdots i_1 i_0 in binary, then i
        # corresponds to the character prod sigma_j^{i_j}.

        phi1x = 1
        phi2x = 1
        phi1y = 1
        phi2y = 1

        # We compute the two algebraic characters at x and y:
        for j in xrange(K.degree()):
            if i % 2 == 1:
                phi1x *= maps[j](x)
                phi1y *= maps[j](y)
            else:
                phi2x *= maps[j](x)
                phi2y *= maps[j](y)
            i = int(i/2)

        # Any prime with reducible image must divide both of:
        gx = phi1x**12 + phi2x**12 - tx
        gy = phi1y**12 + phi2y**12 - ty

        if (gx != 0) or (gy != 0):
            for prime in Integer(Kgal.ideal([gx, gy]).norm()).prime_factors():
                bad_primes.add(prime)

            continue

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

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

        a = (Integer(phi1x + phi2x)**2 - 4 * x.norm()).squarefree_part()

        y = QQ['y'].gen()
        F = NumberField(y**2 - a, 'a')

        # Next, we turn K into relative number field over F.

        K = K.relativize(F.embeddings(K)[0], 'b')
        E = E.change_ring(K.structure()[1])

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

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

        while True:
            P = deg_one_primes.next()

            if not P.is_principal():
                continue

            try:
                tr = E.change_ring(P.residue_field()).trace_of_frobenius()
            except ArithmeticError: # Bad reduction at P.
                continue

            x = P.gens_reduced()[0].norm(F)
            div = (x**12).trace() - _tr12(tr, x.norm())

            patience -= 1

            if div != 0:
                # We found our divisibility constraint.

                for prime in Integer(div).prime_factors():
                    bad_primes.add(prime)

                # Turn K back into an absolute number field.

                E = E.change_ring(K.structure()[0])
                K = K.structure()[0].codomain()

                break

            if patience == 0:
                # We suspect that E has CM, so we check:
                f = K.structure()[0]
                if f(E.j_invariant()) in cm_j_invariants(f.codomain()):
                    raise ValueError("The curve E should not have CM.")

    L = sorted(bad_primes)
    return L
    along with this program.  If not, see <https://www.gnu.org/licenses/>.

    The authors can be reached at: [email protected] and
    [email protected].

    ====================================================================

"""

from sage.all import QQ, prime_range
from sage.arith.misc import next_prime, gcd
from sage.rings.number_field.number_field import NumberField
from sage.rings.polynomial.polynomial_ring import polygen

x = polygen(QQ)
K = NumberField(x**2 - 11 * 17 * 9011 * 23629, "b")
test_cases_true = [(K, int(q), q, False) for q in prime_range(1000)]
test_cases_false = [(K, int(q), next_prime(q), True)
                    for q in prime_range(1000)]


def test_warmup():
    for K, q, p, result in test_cases_true + test_cases_false:
        qq = (q * K).factor()[0][0]
        assert qq.is_coprime(p) == (not qq.divides(p)) == result


def test_is_coprime():
    for K, q, p, result in test_cases_true + test_cases_false:
        qq = (q * K).factor()[0][0]
        is_coprime = qq.is_coprime(p)
Exemplo n.º 31
0
def lift_map(target):
    """
    Create a lift map, to be used for lifting the cross ratios of a matroid
    representation.

    .. SEEALSO::

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

    INPUT:

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

    OUTPUT:

    - a dictionary

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

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

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

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

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

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

    EXAMPLES::

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

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

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

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

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

    raise NotImplementedError(target)
Exemplo n.º 32
0
    def get_twodim_cocycle(self,sign = 1,use_magma = True,bound = 5, hecke_data = None, return_all = False, outfile = None):
        F = self.group().base_ring()
        if F == QQ:
            F = NumberField(PolynomialRing(QQ,'x').gen(),names='r')
        component_list = []
        good_components = []
        if F.signature()[1] == 0 or (F.signature() == (0,1) and 'G' not in self.group()._grouptype):
            Tinf = self.hecke_matrix(oo).transpose()
            K = (Tinf-sign).kernel().change_ring(QQ)
            if K.dimension() >= 2:
                component_list.append((K, [(oo,Tinf)]))
            fwrite('Too charpoly = %s'%Tinf.charpoly().factor(),outfile)
        else:
            K = Matrix(QQ,self.dimension(),self.dimension(),0).kernel()
            if K.dimension() >= 2:
                component_list.append((K, []))
        disc = self.S_arithgroup().Gpn._O_discriminant
        discnorm = disc.norm()
        try:
            N = ZZ(discnorm.gen())
        except AttributeError:
            N = ZZ(discnorm)

        if F == QQ:
            x = QQ['x'].gen()
            F = NumberField(x,names='a')
        q = ZZ(1)
        g0 = None
        num_hecke_operators = 0
        if hecke_data is not None:
            qq = F.ideal(hecke_data[0])
            pol = hecke_data[1]
            Aq = self.hecke_matrix(qq.gens_reduced()[0], use_magma = use_magma).transpose().change_ring(QQ)
            fwrite('ell = (%s,%s), T_ell charpoly = %s'%(qq.norm(), qq.gens_reduced()[0], Aq.charpoly().factor()),outfile)
            U0 = component_list[0][0].intersection(pol.subs(Aq).left_kernel())
            if U0.dimension() != 2:
                raise ValueError('Hecke data does not suffice to cut out space')
            good_component = (U0.denominator() * U0,component_list[0][1] + [(qq.gens_reduced()[0],Aq)])
            row0 = good_component[0].matrix().rows()[0]
            col0 = [QQ(o) for o in row0.list()]
            clcm = lcm([o.denominator() for o in col0])
            col0 = [ZZ(clcm * o ) for o in col0]
            # phi1 = sum([a * phi for a,phi in zip(col0,self.gens())],self(0))
            # phi2 = self.apply_hecke_operator(phi1,qq.gens_reduced()[0], use_magma = use_magma)
            # return [phi1, phi2], [(ell, o.restrict(good_component[0])) for ell, o in good_component[1]]
            flist = []
            for row0 in good_component[0].matrix().rows():
                col0 = [QQ(o) for o in row0.list()]
                clcm = lcm([o.denominator() for o in col0])
                col0 = [ZZ(clcm * o ) for o in col0]
                flist.append(sum([a * phi for a,phi in zip(col0,self.gens())],self(0)))
            return flist,[(ell, o.restrict(good_component[0])) for ell, o in good_component[1]]
        while len(component_list) > 0 and num_hecke_operators < bound:
            verbose('num_hecke_ops = %s'%num_hecke_operators)
            verbose('len(components_list) = %s'%len(component_list))
            q = q.next_prime()
            verbose('q = %s'%q)
            fact = F.ideal(q).factor()
            dfact = F.ideal(disc.gens_reduced()[0]).factor()
            for qq,e in fact:
                verbose('Trying qq = %s'%qq)
                if qq in [o for o,_ in dfact]:
                    verbose('Skipping because qq divides D...')
                    continue
                if  ZZ(qq.norm()).is_prime() and not qq.divides(F.ideal(disc.gens_reduced()[0])):
                    try:
                        Aq = self.hecke_matrix(qq.gens_reduced()[0],g0 = g0,use_magma = use_magma).transpose().change_ring(QQ)
                    except (RuntimeError,TypeError) as e:
                        verbose('Skipping qq (=%s) because Hecke matrix could not be computed...'%qq.gens_reduced()[0])
                        continue
                    except KeyboardInterrupt:
                        verbose('Skipping qq (=%s) by user request...'%qq.gens_reduced()[0])
                        num_hecke_operators += 1
                        sleep(1)
                        continue
                    verbose('Computed hecke matrix at qq = %s'%qq)
                    fwrite('ell = (%s,%s), T_ell charpoly = %s'%(qq.norm(), qq.gens_reduced()[0], Aq.charpoly().factor()),outfile)
                    old_component_list = component_list
                    component_list = []
                    num_hecke_operators += 1
                    for U,hecke_data in old_component_list:
                        V = Aq.decomposition_of_subspace(U)
                        for U0,is_irred in V:
                            if U0.dimension() == 1:
                                continue
                            if U0.dimension() == 2 and is_irred:
                                good_components.append((U0.denominator() * U0,hecke_data+[(qq.gens_reduced()[0],Aq)]))
                            else: # U0.dimension() > 2 or not is_irred
                                component_list.append((U0.denominator() * U0,hecke_data + [(qq.gens_reduced()[0],Aq)]))
                    if len(good_components) > 0 and not return_all:
                        flist = []
                        for row0 in good_components[0][0].matrix().rows():
                            col0 = [QQ(o) for o in row0.list()]
                            clcm = lcm([o.denominator() for o in col0])
                            col0 = [ZZ(clcm * o ) for o in col0]
                            flist.append(sum([a * phi for a,phi in zip(col0,self.gens())],self(0)))
                        return flist,[(ell, o.restrict(good_components[0][0])) for ell, o in good_components[0][1]]
                    if len(component_list) == 0 or num_hecke_operators >= bound:
                        break

        if len(good_components) == 0:
            if not return_all:
                raise ValueError('Group does not seem to be attached to an abelian surface')
            else:
                return []
        if return_all:
            ans = []
            for K,hecke_data in good_components:
                flist = []
                for row0 in K.matrix().rows():
                    col0 = [QQ(o) for o in row0.list()]
                    clcm = lcm([o.denominator() for o in col0])
                    col0 = [ZZ(clcm * o ) for o in col0]
                    flist.append(sum([a * phi for a,phi in zip(col0,self.gens())],self(0)))
                ans.append((flist,[(ell, o.restrict(K)) for ell, o in hecke_data]))
            return ans
        else:
            flist = []
            for row0 in good_components[0][0].matrix().rows():
                col0 = [QQ(o) for o in row0.list()]
                clcm = lcm([o.denominator() for o in col0])
                col0 = [ZZ(clcm * o ) for o in col0]
                flist.append(sum([a * phi for a,phi in zip(col0,self.gens())],self(0)))
            return flist,[(ell, o.restrict(good_components[0][0])) for ell, o in good_components[0][1]]
Exemplo n.º 33
0
def enumerate_totallyreal_fields_all(n, B, verbose=0, return_seqs=False,
                                     return_pari_objects=True):
    r"""
    Enumerates *all* totally real fields of degree ``n`` with discriminant
    at most ``B``, primitive or otherwise.

    INPUT:

    - ``n`` -- integer, the degree
    - ``B`` -- integer, the discriminant bound
    - ``verbose`` -- boolean or nonnegative integer or string (default: 0)
      give a verbose description of the computations being performed. If
      ``verbose`` is set to ``2`` or more then it outputs some extra
      information. If ``verbose`` is a string then it outputs to a file
      specified by ``verbose``
    - ``return_seqs`` -- (boolean, default False) If ``True``, then return
      the polynomials as sequences (for easier exporting to a file). This
      also returns a list of four numbers, as explained in the OUTPUT
      section below.
    - ``return_pari_objects`` -- (boolean, default: True) if both
      ``return_seqs`` and ``return_pari_objects`` are ``False`` then it
      returns the elements as Sage objects; otherwise it returns pari
      objects.

    EXAMPLES::

        sage: enumerate_totallyreal_fields_all(4, 2000)
        [[725, x^4 - x^3 - 3*x^2 + x + 1],
        [1125, x^4 - x^3 - 4*x^2 + 4*x + 1],
        [1600, x^4 - 6*x^2 + 4],
        [1957, x^4 - 4*x^2 - x + 1],
        [2000, x^4 - 5*x^2 + 5]]
        sage: enumerate_totallyreal_fields_all(1, 10)
        [[1, x - 1]]

    TESTS:

    Each of the outputs must be elements of Sage if ``return_pari_objects``
    is set to ``False``::

        sage: enumerate_totallyreal_fields_all(2, 10)
        [[5, x^2 - x - 1], [8, x^2 - 2]]
        sage: enumerate_totallyreal_fields_all(2, 10)[0][1].parent()
        Interface to the PARI C library
        sage: enumerate_totallyreal_fields_all(2, 10, return_pari_objects=False)[0][1].parent()
        Univariate Polynomial Ring in x over Rational Field


    In practice most of these will be found by
    :func:`~sage.rings.number_field.totallyreal.enumerate_totallyreal_fields_prim`,
    which is guaranteed to return all primitive fields but often returns
    many non-primitive ones as well. For instance, only one of the five
    fields in the example above is primitive, but
    :func:`~sage.rings.number_field.totallyreal.enumerate_totallyreal_fields_prim`
    finds four out of the five (the exception being `x^4 - 6x^2 + 4`).

    The following was fixed in :trac:`13101`::

        sage: enumerate_totallyreal_fields_all(8, 10^6)  # long time (about 2 s)
        []
    """

    S = []
    counts = [0,0,0,0]
    if len(divisors(n)) > 4:
        raise ValueError("Only implemented for n = p*q with p,q prime")
    for d in divisors(n):
        if d > 1 and d < n:
            Sds = enumerate_totallyreal_fields_prim(d, int(math.floor((1.*B)**(1.*d/n))), verbose=verbose)
            for i in range(len(Sds)):
                if verbose:
                    print "="*80
                    print "Taking F =", Sds[i][1]
                F = NumberField(ZZx(Sds[i][1]), 't')
                T = enumerate_totallyreal_fields_rel(F, n/d, B, verbose=verbose, return_seqs=return_seqs)
                if return_seqs:
                    for i in range(4):
                        counts[i] += T[0][i]
                    S += [[t[0],pari(t[1]).Polrev()] for t in T[1]]
                else:
                    S += [[t[0],t[1]] for t in T]
                j = i+1
                for E in enumerate_totallyreal_fields_prim(n/d, int(math.floor((1.*B)**(1./d)/(1.*Sds[i][0])**(n*1./d**2)))):
                    for EF in F.composite_fields(NumberField(ZZx(E[1]), 'u')):
                        if EF.degree() == n and EF.disc() <= B:
                            S.append([EF.disc(), pari(EF.absolute_polynomial())])
    S += enumerate_totallyreal_fields_prim(n, B, verbose=verbose)
    S.sort(cmp=lambda x, y: cmp(x[0], y[0]) or cmp(x[1], y[1]))
    weed_fields(S)

    # Output.
    if verbose:
        saveout = sys.stdout
        if isinstance(verbose, str):
            fsock = open(verbose, 'w')
            sys.stdout = fsock
        # Else, print to screen
        print "="*80
        print "Polynomials tested: {}".format(counts[0])
        print ( "Polynomials with discriminant with large enough square"
                " divisor: {}".format(counts[1]))
        print "Irreducible polynomials: {}".format(counts[2])
        print "Polynomials with nfdisc <= B: {}".format(counts[3])
        for i in range(len(S)):
            print S[i]
        if isinstance(verbose, str):
            fsock.close()
        sys.stdout = saveout

    # Make sure to return elements that belong to Sage
    if return_seqs:
        return [[ZZ(_) for _ in counts],
                [[ZZ(s[0]), [QQ(_) for _ in s[1].polrecip().Vec()]] for s in S]]
    elif return_pari_objects:
        return S
    else:
        Px = PolynomialRing(QQ, 'x')
        return [[ZZ(s[0]), Px([QQ(_) for _ in s[1].list()])]
                for s in S]
Exemplo n.º 34
0
def _solve_two_equations(eqn1, eqn2, x_val, y_val):
    """
    Given two polynomial equations with rational coefficients in 'x' and 'y'
    and real intervals for x and y to isolate a solution to the system of
    equations, return the number field generated by x and the value of y in
    that number field. If y is not contained in the number field generated
    by x, return None.
    """

    # Ring we work in Q[x][y]
    Rx = PolynomialRing(RationalField(), 'x')
    R = PolynomialRing(Rx, 'y')
    Reqn1 = R(eqn1)

    # Compute the resultant in Q[x]
    resultant = Reqn1.resultant(R(eqn2))

    # Factorize the resultant. Find the unique factor that has the given value
    # for x as a root.
    def eval_factor_res(p):
        """
        Evaluation method for the factors of the resultant. Apply polynomial
        to the given interval for x.
        """
        return p(x_val)

    resultant_factor = _find_unique_good_factor(resultant, eval_factor_res)

    resultant_factor = Rx(resultant_factor)

    # The number field generated by x.
    #
    # (The embedding passed to the NumberField is a real number, so sage
    # will raise an exception if the resultant_factor has no real roots.
    # However, such a factor should not make it through
    #    _find_unique_good_factor)

    result_number_field = NumberField(resultant_factor,
                                      'x',
                                      embedding=x_val.center())

    # Get one of the equations and think of it as an element in NumberField[y]
    yEqn = Reqn1.change_ring(result_number_field)

    # Factorize that equation over the NumberField. Find the unique factor
    # such that the given value y is a root when setting x to the given value
    # for x.
    def eval_factor_yEqn(p):
        """
        Evaluation method for the factors of the equation factored over the
        number field. We take the factor and turn it into a polynomial in
        Q[x][y]. We then put in the given intervals for x and y.
        """

        lift = p.map_coefficients(lambda c: c.lift('x'), Rx)
        return lift.substitute(x=x_val, y=y_val)

    yEqn_factor = _find_unique_good_factor(yEqn, eval_factor_yEqn)

    # If the equation for y in x is not of degree 1, then y is in a field
    # extension of the number field generated by x.
    # Bail if this happens.
    if not yEqn_factor.degree() == 1:
        return None

    # The equation of y is of the form
    #     linear_term * y + constant_term = 0
    constant_term, linear_term = yEqn_factor.coefficients(sparse=False)

    # Thus, y is given by - constant_term / linear_term
    return result_number_field, -constant_term / linear_term
Exemplo n.º 35
0
from sage.rings.integer_ring import ZZ
from sage.rings.number_field.number_field import NumberField
from sage.misc.sage_eval import sage_eval

R = ZZ['x']
x = R.gen()
path = Path(__file__).parent

CM_FIELDS = {}

for fn in [
        fn for fn in listdir(path)
        if isfile(path / fn) and fn.startswith("cm_fields_")
]:
    with open(path / fn) as f:
        s = "\n".join(l for l in f.read().splitlines()
                      if not l.startswith("#"))
        for g in sage_eval(s, locals={"x": x}):
            d = g.degree()
            if d not in CM_FIELDS:
                CM_FIELDS[d] = []
            CM_FIELDS[d].append(NumberField(g, f"a_{d}_{len(CM_FIELDS[d])+1}"))

assert len(CM_FIELDS[2]) == 9
assert len(CM_FIELDS[4]) == 91
assert len(CM_FIELDS[6]) == 403
#for d,arr in CM_FIELDS.items():
#    assert all(K.is_CM() and K.class_number() == 1 for K in arr)
#    assert all(not L1.is_isomorphic(L2) for L1,L2 in Subsets(arr,2))
Exemplo n.º 36
0
def polyhedron_to_cone_surface(polyhedron, use_AA=False, scaling_factor=ZZ(1)):
    r"""Construct the Euclidean Cone Surface associated to the surface of a polyhedron and a map
    from the cone surface to the polyhedron.
    
    INPUT:

    - ``polyhedron`` -- A 3-dimensional polyhedron, which should be define over something that coerces into AA

    - ``use_AA`` -- If True, the surface returned will be defined over AA. If false, the algorithm will find the smallest NumberField and write the field there.
    
    - ``scaling_factor`` -- The surface returned will have a metric scaled by multiplication by this factor (compared with the original polyhendron). This can be used to produce a surface defined over a smaller NumberField.
    
    OUTPUT:
    
    A pair consisting of a ConeSurface and a ConeSurfaceToPolyhedronMap.

    EXAMPLES::

    sage: from flatsurf.geometry.polyhedra import *
    sage: vertices=[]
    sage: for i in xrange(3):
    ....:     temp=vector([1 if k==i else 0 for k in xrange(3)])
    ....:     for j in xrange(-1,3,2):
    ....:         vertices.append(j*temp)
    sage: octahedron=Polyhedron(vertices=vertices)
    sage: surface,surface_to_octahedron = \
    ....:     polyhedron_to_cone_surface(octahedron,scaling_factor=AA(1/sqrt(2)))
    sage: TestSuite(surface).run()
    sage: TestSuite(surface_to_octahedron).run(skip="_test_pickling")
    sage: surface.num_polygons()
    8
    sage: surface.base_ring()
    Number Field in a with defining polynomial y^2 - 3
    sage: sqrt3=surface.base_ring().gen()
    sage: tangent_bundle=surface.tangent_bundle()
    sage: v=tangent_bundle(0,(0,0),(sqrt3,2))
    sage: traj=v.straight_line_trajectory()
    sage: traj.flow(10)
    sage: traj.is_saddle_connection()
    True
    sage: traj.combinatorial_length()
    8
    sage: surface_to_octahedron(traj)
    [(-1, 0, 0),
     (0.?e-18, -0.8000000000000000?, -0.2000000000000000?),
     (0.2500000000000000?, -0.750000000000000?, 0.?e-18),
     (0.4000000000000000?, 0.?e-19, 0.6000000000000000?),
     (0.?e-19, 0.500000000000000?, 0.500000000000000?),
     (-2/5, 3/5, 0),
     (-0.2500000000000000?, 0.?e-18, -0.750000000000000?),
     (0.?e-18, -0.2000000000000000?, -0.8000000000000000?),
     (1, 0, 0)]
    sage: surface_to_octahedron(traj.segment(0))
    ((-1, 0, 0), (0.?e-18, -0.8000000000000000?, -0.2000000000000000?))
    sage: surface_to_octahedron(traj.segment(0).start())
    ((-1, 0, 0), (2.886751345948129?, -2.309401076758503?, -0.5773502691896258?))
    sage: # octahedron.plot(wireframe=None,frame=False)+line3d(surface_to_octahedron(traj),radius=0.01)

    """
    assert polyhedron.dim()==3
    c=polyhedron.center()
    vertices=polyhedron.vertices()
    vertex_order={}
    for i,v in enumerate(vertices):
        vertex_order[v]=i
    faces=polyhedron.faces(2)
    face_order={}
    face_edges=[]
    face_vertices=[]
    face_map_data=[]
    for i,f in enumerate(faces):
        face_order[f]=i
        edges=f.as_polyhedron().faces(1)
        face_edges_temp = set()
        for edge in edges:
            edge_temp=set()
            for vertex in edge.vertices():
                v=vertex.vector()
                v.set_immutable()
                edge_temp.add(v)
            face_edges_temp.add(frozenset(edge_temp))

            
        last_edge = next(iter(face_edges_temp))
        v = next(iter(last_edge))
        face_vertices_temp=[v]
        for j in xrange(len(face_edges_temp)-1):
            for edge in face_edges_temp:
                if v in edge and edge!=last_edge:
                    # bingo
                    last_edge=edge
                    for vv in edge:
                        if vv!=v:
                            v=vv
                            face_vertices_temp.append(vv)
                            break
                    break


        v0=face_vertices_temp[0]
        v1=face_vertices_temp[1]
        v2=face_vertices_temp[2]
        n=(v1-v0).cross_product(v2-v0)
        if (v0-c).dot_product(n)<0:
            n=-n
            face_vertices_temp.reverse()
            v0=face_vertices_temp[0]
            v1=face_vertices_temp[1]
            v2=face_vertices_temp[2]

        face_vertices.append(face_vertices_temp)    
        n=n/AA(n.norm())
        w=v1-v0
        w=w/AA(w.norm())
        m=1/scaling_factor*matrix(AA,[w,n.cross_product(w),n]).transpose()
        mi=~m
        mis=mi.submatrix(0,0,2,3)
        face_map_data.append((
            v0, # translation to bring origin in plane to v0
            m.submatrix(0,0,3,2),
            -mis*v0,
            mis
        ))

        it=iter(face_vertices_temp)    
        v_last=next(it)
        face_edge_dict={}
        j=0
        for v in it:
            edge=frozenset([v_last,v])
            face_edge_dict[edge]=j
            j+=1
            v_last=v
        v=next(iter(face_vertices_temp))
        edge=frozenset([v_last,v])
        face_edge_dict[edge]=j
        face_edges.append(face_edge_dict)
        
    gluings={}
    for p1,face_edge_dict1 in enumerate(face_edges):
        for edge, e1 in face_edge_dict1.items():
            found=False
            for p2, face_edge_dict2 in enumerate(face_edges):
                if p1!=p2 and edge in face_edge_dict2:
                    e2=face_edge_dict2[edge]
                    gluings[(p1,e1)]=(p2,e2)
                    found=True
                    break
            if not found:
                print(p1)
                print(e1)
                print(edge)
                raise RuntimeError("Failed to find glued edge")
    polygon_vertices_AA=[]
    for p,vs in enumerate(face_vertices):
        trans=face_map_data[p][2]
        m=face_map_data[p][3]
        polygon_vertices_AA.append([trans+m*v for v in vs])
        
    
    if use_AA==True:
        Polys=Polygons(AA)
        polygons=[]
        for vs in polygon_vertices_AA:
            polygons.append(Polys(vertices=vs))
        S=ConeSurface(surface_list_from_polygons_and_gluings(polygons,gluings))
        return S, \
            ConeSurfaceToPolyhedronMap(S,polyhedron,face_map_data)
    else:
        elts=[]
        for vs in polygon_vertices_AA:
            for v in vs:
                elts.append(v[0])
                elts.append(v[1])
                
        # Find the best number field:
        field,elts2,hom = number_field_elements_from_algebraics(elts,minimal=True)
        if field==QQ:
            # Defined over the rationals!
            polygon_vertices_field2=[]
            j=0
            for vs in polygon_vertices_AA:
                vs2=[]
                for v in vs:
                    vs2.append(vector(field,[elts2[j],elts2[j+1]]))
                    j=j+2
                polygon_vertices_field2.append(vs2)
            Polys=Polygons(field)
            polygons=[]
            for vs in polygon_vertices_field2:
                polygons.append(Polys(vertices=vs))
            S=ConeSurface(surface_list_from_polygons_and_gluings(polygons,gluings))
            return S, \
                ConeSurfaceToPolyhedronMap(S,polyhedron,face_map_data)

        else:        
            # Unfortunately field doesn't come with an real embedding (which is given by hom!)
            # So, we make a copy of the field, and add the embedding.
            field2=NumberField(field.polynomial(),name="a",embedding=hom(field.gen()))
            # The following converts from field to field2:
            hom2=field.hom(im_gens=[field2.gen()])

            polygon_vertices_field2=[]
            j=0
            for vs in polygon_vertices_AA:
                vs2=[]
                for v in vs:
                    vs2.append(vector(field2,[hom2(elts2[j]),hom2(elts2[j+1])]))
                    j=j+2
                polygon_vertices_field2.append(vs2)
            Polys=Polygons(field2)
            polygons=[]
            for vs in polygon_vertices_field2:
                polygons.append(Polys(vertices=vs))
            S=ConeSurface(surface_list_from_polygons_and_gluings(polygons,gluings))
            return S, \
                ConeSurfaceToPolyhedronMap(S,polyhedron,face_map_data)
Exemplo n.º 37
0
def _semistable_reducible_primes(E):
    r"""Find a list containing all semistable primes l unramified in K/QQ
    for which the Galois image for E could be reducible.

    INPUT:

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

    OUTPUT:

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

    EXAMPLES::

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

    E = _over_numberfield(E)
    K = E.base_field()
    deg_one_primes = K.primes_of_degree_one_iter()

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

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

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

    while len(precomp) < 2:
        P = next(deg_one_primes)

        if not P.is_principal():
            continue

        det = P.norm()
        if det == last_char:
            continue

        if P.ramification_index() != 1:
            continue

        try:
            tr = E.change_ring(P.residue_field()).trace_of_frobenius()
        except ArithmeticError:  # Bad reduction at P.
            continue

        x = P.gens_reduced()[0]

        precomp.append((x, _tr12(tr, det)))
        last_char = det

    x, tx = precomp[0]
    y, ty = precomp[1]

    Kgal = K.galois_closure('b')
    maps = K.embeddings(Kgal)

    for i in xrange(2**(K.degree() - 1)):
        ## We iterate through all possible characters. ##

        # Here, if i = i_{l-1} i_{l-2} cdots i_1 i_0 in binary, then i
        # corresponds to the character prod sigma_j^{i_j}.

        phi1x = 1
        phi2x = 1
        phi1y = 1
        phi2y = 1

        # We compute the two algebraic characters at x and y:
        for j in xrange(K.degree()):
            if i % 2 == 1:
                phi1x *= maps[j](x)
                phi1y *= maps[j](y)
            else:
                phi2x *= maps[j](x)
                phi2y *= maps[j](y)
            i = int(i / 2)

        # Any prime with reducible image must divide both of:
        gx = phi1x**12 + phi2x**12 - tx
        gy = phi1y**12 + phi2y**12 - ty

        if (gx != 0) or (gy != 0):
            for prime in Integer(Kgal.ideal([gx, gy]).norm()).prime_factors():
                bad_primes.add(prime)

            continue

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

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

        a = (Integer(phi1x + phi2x)**2 - 4 * x.norm()).squarefree_part()

        y = QQ['y'].gen()
        F = NumberField(y**2 - a, 'a')

        # Next, we turn K into relative number field over F.

        K = K.relativize(F.embeddings(K)[0], 'b')
        E = E.change_ring(K.structure()[1])

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

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

        while True:
            P = next(deg_one_primes)

            if not P.is_principal():
                continue

            try:
                tr = E.change_ring(P.residue_field()).trace_of_frobenius()
            except ArithmeticError:  # Bad reduction at P.
                continue

            x = P.gens_reduced()[0].norm(F)
            div = (x**12).trace() - _tr12(tr, x.norm())

            patience -= 1

            if div != 0:
                # We found our divisibility constraint.

                for prime in Integer(div).prime_factors():
                    bad_primes.add(prime)

                # Turn K back into an absolute number field.

                E = E.change_ring(K.structure()[0])
                K = K.structure()[0].codomain()

                break

            if patience == 0:
                # We suspect that E has CM, so we check:
                f = K.structure()[0]
                if f(E.j_invariant()) in cm_j_invariants(f.codomain()):
                    raise ValueError("The curve E should not have CM.")

    L = sorted(bad_primes)
    return L
Exemplo n.º 38
0
def is_Q_curve(E, maxp=100, certificate=False, verbose=False):
    r"""
    Return whether ``E`` is a `\QQ`-curve, with optional certificate.

    INPUT:

    - ``E`` (elliptic curve) -- an elliptic curve over a number field.

    - ``maxp`` (int, default 100): bound on primes used for checking
      necessary local conditions.  The result will not depend on this,
      but using a larger value may return ``False`` faster.

    - ``certificate`` (bool, default ``False``): if ``True`` then a
      second value is returned giving a certificate for the
      `\QQ`-curve property.

    OUTPUT:

    If ``certificate`` is ``False``: either ``True`` (if `E` is a
    `\QQ`-curve), or ``False``.

    If ``certificate`` is ``True``: a tuple consisting of a boolean
    flag as before and a certificate, defined as follows:

    - when the flag is ``True``, so `E` is a `\QQ`-curve:

        - either {'CM':`D`} where `D` is a negative discriminant, when
          `E` has potential CM with discriminant `D`;

        - otherwise {'CM': `0`, 'core_poly': `f`, 'rho': `\rho`, 'r':
          `r`, 'N': `N`}, when `E` is a non-CM `\QQ`-curve, where the
          core polynomial `f` is an irreducible monic polynomial over
          `QQ` of degree `2^\rho`, all of whose roots are
          `j`-invariants of curves isogenous to `E`, the core level
          `N` is a square-free integer with `r` prime factors which is
          the LCM of the degrees of the isogenies between these
          conjugates.  For example, if there exists a curve `E'`
          isogenous to `E` with `j(E')=j\in\QQ`, then the certificate
          is {'CM':0, 'r':0, 'rho':0, 'core_poly': x-j, 'N':1}.

    - when the flag is ``False``, so `E` is not a `\QQ`-curve, the
      certificate is a prime `p` such that the reductions of `E` at
      the primes dividing `p` are inconsistent with the property of
      being a `\QQ`-curve.  See the ALGORITHM section for details.

    ALGORITHM:

    See [CrNa2020]_ for details.

    1. If `E` has rational `j`-invariant, or has CM, then return
    ``True``.

    2. Replace `E` by a curve defined over `K=\QQ(j(E))`. Let `N` be
    the conductor norm.

    3. For all primes `p\mid N` check that the valuations of `j` at
    all `P\mid p` are either all negative or all non-negative; if not,
    return ``False``.

    4. For `p\le maxp`, `p\not\mid N`, check that either `E` is
    ordinary mod `P` for all `P\mid p`, or `E` is supersingular mod
    `P` for all `P\mid p`; if neither, return ``False``.  If all are
    ordinary, check that the integers `a_P(E)^2-4N(P)` have the same
    square-free part; if not, return ``False``.

    5. Compute the `K`-isogeny class of `E` using the "heuristic"
    option (which is faster, but not guaranteed to be complete).
    Check whether the set of `j`-invariants of curves in the class of
    `2`-power degree contains a complete Galois orbit.  If so, return
    ``True``.

    6. Otherwise repeat step 4 for more primes, and if still
    undecided, repeat Step 5 without the "heuristic" option, to get
    the complete `K`-isogeny class (which will probably be no bigger
    than before).  Now return ``True`` if the set of `j`-invariants of
    curves in the class contains a complete Galois orbit, otherwise
    return ``False``.

    EXAMPLES:

    A non-CM curve over `\QQ` and a CM curve over `\QQ` are both
    trivially `\QQ`-curves::

        sage: from sage.schemes.elliptic_curves.Qcurves import is_Q_curve
        sage: E = EllipticCurve([1,2,3,4,5])
        sage: flag, cert = is_Q_curve(E, certificate=True)
        sage: flag
        True
        sage: cert
        {'CM': 0, 'N': 1, 'core_poly': x, 'r': 0, 'rho': 0}

        sage: E = EllipticCurve(j=8000)
        sage: flag, cert = is_Q_curve(E, certificate=True)
        sage: flag
        True
        sage: cert
        {'CM': -8}

    A non-`\QQ`-curve over a quartic field.  The local data at bad
    primes above `3` is inconsistent::

        sage: from sage.schemes.elliptic_curves.Qcurves import is_Q_curve
        sage: R.<x> = PolynomialRing(QQ)
        sage: K.<a> = NumberField(R([3, 0, -5, 0, 1]))
        sage: E = EllipticCurve([K([-3,-4,1,1]),K([4,-1,-1,0]),K([-2,0,1,0]),K([-621,778,138,-178]),K([9509,2046,-24728,10380])])
        sage: is_Q_curve(E, certificate=True, verbose=True)
        Checking whether Elliptic Curve defined by y^2 + (a^3+a^2-4*a-3)*x*y + (a^2-2)*y = x^3 + (-a^2-a+4)*x^2 + (-178*a^3+138*a^2+778*a-621)*x + (10380*a^3-24728*a^2+2046*a+9509) over Number Field in a with defining polynomial x^4 - 5*x^2 + 3 is a Q-curve
        No: inconsistency at the 2 primes dividing 3
        - potentially multiplicative: [True, False]
        (False, 3)

    A non-`\QQ`-curve over a quadratic field.  The local data at bad
    primes is consistent, but the local test at good primes above `13`
    is not::

        sage: K.<a> = NumberField(R([-10, 0, 1]))
        sage: E = EllipticCurve([K([0,1]),K([-1,-1]),K([0,0]),K([-236,40]),K([-1840,464])])
        sage: is_Q_curve(E, certificate=True, verbose=True)
        Checking whether Elliptic Curve defined by y^2 + a*x*y = x^3 + (-a-1)*x^2 + (40*a-236)*x + (464*a-1840) over Number Field in a with defining polynomial x^2 - 10 is a Q-curve
        Applying local tests at good primes above p<=100
        No: inconsistency at the 2 ordinary primes dividing 13
        - Frobenius discriminants mod squares: [-1, -3]
        No: local test at p=13 failed
        (False, 13)

    A quadratic `\QQ`-curve with CM discriminant `-15` (`j`-invariant not in `\QQ`)::

        sage: from sage.schemes.elliptic_curves.Qcurves import is_Q_curve
        sage: R.<x> = PolynomialRing(QQ)
        sage: K.<a> = NumberField(R([-1, -1, 1]))
        sage: E = EllipticCurve([K([1,0]),K([-1,0]),K([0,1]),K([0,-2]),K([0,1])])
        sage: is_Q_curve(E, certificate=True, verbose=True)
        Checking whether Elliptic Curve defined by y^2 + x*y + a*y = x^3 + (-1)*x^2 + (-2*a)*x + a over Number Field in a with defining polynomial x^2 - x - 1 is a Q-curve
        Yes: E is CM (discriminant -15)
        (True, {'CM': -15})

    An example over `\QQ(\sqrt{2},\sqrt{3})`.  The `j`-invariant is in
    `\QQ(\sqrt{6})`, so computations will be done over that field, and
    in fact there is an isogenous curve with rational `j`, so we have
    a so-called rational `\QQ`-curve::

        sage: K.<a> = NumberField(R([1, 0, -4, 0, 1]))
        sage: E = EllipticCurve([K([-2,-4,1,1]),K([0,1,0,0]),K([0,1,0,0]),K([-4780,9170,1265,-2463]),K([163923,-316598,-43876,84852])])
        sage: flag, cert = is_Q_curve(E, certificate=True)
        sage: flag
        True
        sage: cert
        {'CM': 0, 'N': 1, 'core_degs': [1], 'core_poly': x - 85184/3, 'r': 0, 'rho': 0}

    Over the same field, a so-called strict `\QQ`-curve which is not
    isogenous to one with rational `j`, but whose core field is
    quadratic. In fact the isogeny class over `K` consists of `6`
    curves, four with conjugate quartic `j`-invariants and `2` with
    quadratic conjugate `j`-invariants in `\QQ(\sqrt{3})` (but which
    are not base-changes from the quadratic subfield)::

        sage: E = EllipticCurve([K([0,-3,0,1]),K([1,4,0,-1]),K([0,0,0,0]),K([-2,-16,0,4]),K([-19,-32,4,8])])
        sage: flag, cert = is_Q_curve(E, certificate=True)
        sage: flag
        True
        sage: cert
        {'CM': 0,
        'N': 2,
        'core_degs': [1, 2],
        'core_poly': x^2 - 840064*x + 1593413632,
        'r': 1,
        'rho': 1}

    """
    from sage.rings.number_field.number_field_base import is_NumberField

    if verbose:
        print("Checking whether {} is a Q-curve".format(E))

    try:
        assert is_NumberField(E.base_field())
    except (AttributeError, AssertionError):
        raise TypeError(
            "{} must be an elliptic curve defined over a number field in is_Q_curve()"
        )

    from sage.rings.integer_ring import ZZ
    from sage.arith.functions import lcm
    from sage.libs.pari import pari
    from sage.rings.number_field.number_field import NumberField
    from sage.schemes.elliptic_curves.constructor import EllipticCurve
    from sage.schemes.elliptic_curves.cm import cm_j_invariants_and_orders, is_cm_j_invariant

    # Step 1

    # all curves with rational j-invariant are Q-curves:
    jE = E.j_invariant()
    if jE in QQ:
        if verbose:
            print("Yes: j(E) is in QQ")
        if certificate:
            # test for CM
            for d, f, j in cm_j_invariants_and_orders(QQ):
                if jE == j:
                    return True, {'CM': d * f**2}
            # else not CM
            return True, {
                'CM': ZZ(0),
                'r': ZZ(0),
                'rho': ZZ(0),
                'N': ZZ(1),
                'core_poly': polygen(QQ)
            }
        else:
            return True

    # CM curves are Q-curves:
    flag, df = is_cm_j_invariant(jE)
    if flag:
        d, f = df
        D = d * f**2
        if verbose:
            print("Yes: E is CM (discriminant {})".format(D))
        if certificate:
            return True, {'CM': D}
        else:
            return True

    # Step 2: replace E by a curve defined over Q(j(E)):

    K = E.base_field()
    jpoly = jE.minpoly()
    if jpoly.degree() < K.degree():
        if verbose:
            print("switching to smaller base field: j's minpoly is {}".format(
                jpoly))
        f = pari(jpoly).polredbest().sage({'x': jpoly.parent().gen()})
        K2 = NumberField(f, 'b')
        jE = jpoly.roots(K2)[0][0]
        if verbose:
            print("New j is {} over {}, with minpoly {}".format(
                jE, K2, jE.minpoly()))
        #assert jE.minpoly()==jpoly
        E = EllipticCurve(j=jE)
        K = K2
        if verbose:
            print("New test curve is {}".format(E))

    # Step 3: check primes of bad reduction

    NN = E.conductor().norm()
    for p in NN.support():
        Plist = K.primes_above(p)
        if len(Plist) < 2:
            continue
        # pot_mult = potential multiplicative reduction
        pot_mult = [jE.valuation(P) < 0 for P in Plist]
        consistent = all(pot_mult) or not any(pot_mult)
        if not consistent:
            if verbose:
                print("No: inconsistency at the {} primes dividing {}".format(
                    len(Plist), p))
                print("  - potentially multiplicative: {}".format(pot_mult))
            if certificate:
                return False, p
            else:
                return False

    # Step 4 check: primes P of good reduction above p<=B:

    if verbose:
        print("Applying local tests at good primes above p<={}".format(maxp))

    res4, p = Step4Test(E, B=maxp, oldB=0, verbose=verbose)
    if not res4:
        if verbose:
            print("No: local test at p={} failed".format(p))
        if certificate:
            return False, p
        else:
            return False

    if verbose:
        print("...all local tests pass for p<={}".format(maxp))

    # Step 5: compute the (partial) K-isogeny class of E and test the
    # set of j-invariants in the class:

    C = E.isogeny_class(algorithm='heuristic', minimal_models=False)
    jC = [E2.j_invariant() for E2 in C]
    centrejpols = conjugacy_test(jC, verbose=verbose)
    if centrejpols:
        if verbose:
            print(
                "Yes: the isogeny class contains a complete conjugacy class of j-invariants"
            )
        if certificate:
            for f in centrejpols:
                rho = f.degree().valuation(2)
                centre_indices = [i for i, j in enumerate(jC) if f(j) == 0]
                M = C.matrix()
                core_degs = [M[centre_indices[0], i] for i in centre_indices]
                level = lcm(core_degs)
                if level.is_squarefree():
                    r = len(level.prime_divisors())
                    cert = {
                        'CM': ZZ(0),
                        'core_poly': f,
                        'rho': rho,
                        'r': r,
                        'N': level,
                        'core_degs': core_degs
                    }
                    return True, cert
            print("No central curve found")
        else:
            return True

    # Now we are undecided.  This can happen if either (1) E is not a
    # Q-curve but we did not use enough primes in Step 4 to detect
    # this, or (2) E is a Q-curve but in Step 5 we did not compute the
    # complete isogeny class.  Case (2) is most unlikely since the
    # heuristic bound used in computing isogeny classes means that we
    # have all isogenous curves linked to E by an isogeny of degree
    # supported on primes<1000.

    # We first rerun Step 4 with a larger bound.

    xmaxp = 10 * maxp
    if verbose:
        print(
            "Undecided after first round, so we apply more local tests, up to {}"
            .format(xmaxp))

    res4, p = Step4Test(E, B=xmaxp, oldB=maxp, verbose=verbose)
    if not res4:
        if verbose:
            print("No: local test at p={} failed".format(p))
        if certificate:
            return False, p
        else:
            return False

    # Now we rerun Step 5 using a rigorous computation of the complete
    # isogeny class.  This will probably contain no more curves than
    # before, in which case -- since we already tested that the set of
    # j-invariants does not contain a complete Galois conjugacy class
    # -- we can deduce that E is not a Q-curve.

    if verbose:
        print("...all local tests pass for p<={}".format(xmaxp))
        print("We now compute the complete isogeny class...")

    Cfull = E.isogeny_class(minimal_models=False)
    jCfull = [E2.j_invariant() for E2 in Cfull]

    if len(jC) == len(jCfull):
        if verbose:
            print("...and find that we already had the complete class:so No")
        if certificate:
            return False, 0
        else:
            return False
    if verbose:
        print(
            "...and find that the class contains {} curves, not just the {} we computed originally"
            .format(len(jCfull), len(jC)))
    centrejpols = conjugacy_test(jCfull, verbose=verbose)
    if cert:
        if verbose:
            print(
                "Yes: the isogeny class contains a complete conjugacy class of j-invariants"
            )
        if certificate:
            return True, centrejpols
        else:
            return True
    if verbose:
        print(
            "No: the isogeny class does *not* contain a complete conjugacy class of j-invariants"
        )
    if certificate:
        return False, 0
    else:
        return False
Exemplo n.º 39
0
#!/usr/bin/env sage

from __future__ import print_function

from sage import *
from sage.rings.number_field.number_field import NumberField

#import sys
#print(sys.argv)

if 1:
    K = NumberField(x ^ 4 + 1)

    r2 = e8 + e8 ^ 7
    assert r2**2 == 2

    G = K.galois_group()
    assert len(G) == 4
Exemplo n.º 40
0
def polyhedron_to_cone_surface(polyhedron, use_AA=False, scaling_factor=ZZ(1)):
    r"""Construct the Euclidean Cone Surface associated to the surface of a polyhedron and a map
    from the cone surface to the polyhedron.
    
    INPUT:

    - ``polyhedron`` -- A 3-dimensional polyhedron, which should be define over something that coerces into AA

    - ``use_AA`` -- If True, the surface returned will be defined over AA. If false, the algorithm will find the smallest NumberField and write the field there.
    
    - ``scaling_factor`` -- The surface returned will have a metric scaled by multiplication by this factor (compared with the original polyhendron). This can be used to produce a surface defined over a smaller NumberField.
    
    OUTPUT:
    
    A pair consisting of a ConeSurface and a ConeSurfaceToPolyhedronMap.

    EXAMPLES::

    sage: from flatsurf.geometry.polyhedra import *
    sage: vertices=[]
    sage: for i in range(3):
    ....:     temp=vector([1 if k==i else 0 for k in range(3)])
    ....:     for j in range(-1,3,2):
    ....:         vertices.append(j*temp)
    sage: octahedron=Polyhedron(vertices=vertices)
    sage: surface,surface_to_octahedron = \
    ....:     polyhedron_to_cone_surface(octahedron,scaling_factor=AA(1/sqrt(2)))
    sage: TestSuite(surface).run()
    sage: TestSuite(surface_to_octahedron).run(skip="_test_pickling")
    sage: surface.num_polygons()
    8
    sage: surface.base_ring()
    Number Field in a with defining polynomial y^2 - 3 with a = 1.732050807568878?
    sage: sqrt3=surface.base_ring().gen()
    sage: tangent_bundle=surface.tangent_bundle()
    sage: v=tangent_bundle(0,(0,0),(sqrt3,2))
    sage: traj=v.straight_line_trajectory()
    sage: traj.flow(10)
    sage: traj.is_saddle_connection()
    True
    sage: traj.combinatorial_length()
    8
    sage: path3d = surface_to_octahedron(traj)
    sage: len(path3d)
    9
    sage: # We will show that the length of the path is sqrt(42):
    sage: total_length = 0
    sage: for i in range(8):
    ....:     start = path3d[i]
    ....:     end = path3d[i+1]
    ....:     total_length += (vector(end)-vector(start)).norm()
    sage: ZZ(total_length**2)
    42
    """
    assert polyhedron.dim() == 3
    c = polyhedron.center()
    vertices = polyhedron.vertices()
    vertex_order = {}
    for i, v in enumerate(vertices):
        vertex_order[v] = i
    faces = polyhedron.faces(2)
    face_order = {}
    face_edges = []
    face_vertices = []
    face_map_data = []
    for i, f in enumerate(faces):
        face_order[f] = i
        edges = f.as_polyhedron().faces(1)
        face_edges_temp = set()
        for edge in edges:
            edge_temp = set()
            for vertex in edge.vertices():
                v = vertex.vector()
                v.set_immutable()
                edge_temp.add(v)
            face_edges_temp.add(frozenset(edge_temp))

        last_edge = next(iter(face_edges_temp))
        v = next(iter(last_edge))
        face_vertices_temp = [v]
        for j in range(len(face_edges_temp) - 1):
            for edge in face_edges_temp:
                if v in edge and edge != last_edge:
                    # bingo
                    last_edge = edge
                    for vv in edge:
                        if vv != v:
                            v = vv
                            face_vertices_temp.append(vv)
                            break
                    break

        v0 = face_vertices_temp[0]
        v1 = face_vertices_temp[1]
        v2 = face_vertices_temp[2]
        n = (v1 - v0).cross_product(v2 - v0)
        if (v0 - c).dot_product(n) < 0:
            n = -n
            face_vertices_temp.reverse()
            v0 = face_vertices_temp[0]
            v1 = face_vertices_temp[1]
            v2 = face_vertices_temp[2]

        face_vertices.append(face_vertices_temp)
        n = n / AA(n.norm())
        w = v1 - v0
        w = w / AA(w.norm())
        m = 1 / scaling_factor * matrix(
            AA, [w, n.cross_product(w), n]).transpose()
        mi = ~m
        mis = mi.submatrix(0, 0, 2, 3)
        face_map_data.append((
            v0,  # translation to bring origin in plane to v0
            m.submatrix(0, 0, 3, 2),
            -mis * v0,
            mis))

        it = iter(face_vertices_temp)
        v_last = next(it)
        face_edge_dict = {}
        j = 0
        for v in it:
            edge = frozenset([v_last, v])
            face_edge_dict[edge] = j
            j += 1
            v_last = v
        v = next(iter(face_vertices_temp))
        edge = frozenset([v_last, v])
        face_edge_dict[edge] = j
        face_edges.append(face_edge_dict)

    gluings = {}
    for p1, face_edge_dict1 in enumerate(face_edges):
        for edge, e1 in face_edge_dict1.items():
            found = False
            for p2, face_edge_dict2 in enumerate(face_edges):
                if p1 != p2 and edge in face_edge_dict2:
                    e2 = face_edge_dict2[edge]
                    gluings[(p1, e1)] = (p2, e2)
                    found = True
                    break
            if not found:
                print(p1)
                print(e1)
                print(edge)
                raise RuntimeError("Failed to find glued edge")
    polygon_vertices_AA = []
    for p, vs in enumerate(face_vertices):
        trans = face_map_data[p][2]
        m = face_map_data[p][3]
        polygon_vertices_AA.append([trans + m * v for v in vs])

    if use_AA == True:
        Polys = ConvexPolygons(AA)
        polygons = []
        for vs in polygon_vertices_AA:
            polygons.append(Polys(vertices=vs))
        S = ConeSurface(
            surface_list_from_polygons_and_gluings(polygons, gluings))
        return S, \
            ConeSurfaceToPolyhedronMap(S,polyhedron,face_map_data)
    else:
        elts = []
        for vs in polygon_vertices_AA:
            for v in vs:
                elts.append(v[0])
                elts.append(v[1])

        # Find the best number field:
        field, elts2, hom = number_field_elements_from_algebraics(elts,
                                                                  minimal=True)
        if field == QQ:
            # Defined over the rationals!
            polygon_vertices_field2 = []
            j = 0
            for vs in polygon_vertices_AA:
                vs2 = []
                for v in vs:
                    vs2.append(vector(field, [elts2[j], elts2[j + 1]]))
                    j = j + 2
                polygon_vertices_field2.append(vs2)
            Polys = ConvexPolygons(field)
            polygons = []
            for vs in polygon_vertices_field2:
                polygons.append(Polys(vertices=vs))
            S = ConeSurface(
                surface_list_from_polygons_and_gluings(polygons, gluings))
            return S, \
                ConeSurfaceToPolyhedronMap(S,polyhedron,face_map_data)

        else:
            # Unfortunately field doesn't come with an real embedding (which is given by hom!)
            # So, we make a copy of the field, and add the embedding.
            field2 = NumberField(field.polynomial(),
                                 name="a",
                                 embedding=hom(field.gen()))
            # The following converts from field to field2:
            hom2 = field.hom(im_gens=[field2.gen()])

            polygon_vertices_field2 = []
            j = 0
            for vs in polygon_vertices_AA:
                vs2 = []
                for v in vs:
                    vs2.append(
                        vector(field2, [hom2(elts2[j]),
                                        hom2(elts2[j + 1])]))
                    j = j + 2
                polygon_vertices_field2.append(vs2)
            Polys = ConvexPolygons(field2)
            polygons = []
            for vs in polygon_vertices_field2:
                polygons.append(Polys(vertices=vs))
            S = ConeSurface(
                surface_list_from_polygons_and_gluings(polygons, gluings))
            return S, \
                ConeSurfaceToPolyhedronMap(S,polyhedron,face_map_data)
Exemplo n.º 41
0
 def sage_object(self):
     X = PolynomialRing(QQ, "x")
     from sage.rings.number_field.number_field import NumberField
     return NumberField(X(map(str, self.polynomial())), "x")
Exemplo n.º 42
0
def enumerate_totallyreal_fields_all(n, B, verbose=0, return_seqs=False):
    r"""
    Enumerates *all* totally real fields of degree `n` with discriminant `\le B`,
    primitive or otherwise.

    EXAMPLES::

        sage: enumerate_totallyreal_fields_all(4, 2000)
        [[725, x^4 - x^3 - 3*x^2 + x + 1],
        [1125, x^4 - x^3 - 4*x^2 + 4*x + 1],
        [1600, x^4 - 6*x^2 + 4],
        [1957, x^4 - 4*x^2 - x + 1],
        [2000, x^4 - 5*x^2 + 5]]

    In practice most of these will be found by :func:`~sage.rings.number_field.totallyreal.enumerate_totallyreal_fields_prim`, which is guaranteed to return all primitive fields but often returns many non-primitive ones as well. For instance, only one of the five fields in the example above is primitive, but :func:`~sage.rings.number_field.totallyreal.enumerate_totallyreal_fields_prim` finds four out of the five (the exception being `x^4 - 6x^2 + 4`).

    TESTS:

    The following was fixed in :trac:`13101`::

        sage: enumerate_totallyreal_fields_all(8, 10^6)  # long time (about 2 s)
        []
    """

    S = []
    counts = [0,0,0]
    if len(divisors(n)) > 4:
        raise ValueError, "Only implemented for n = p*q with p,q prime"
    for d in divisors(n):
        if d > 1 and d < n:
            Sds = enumerate_totallyreal_fields_prim(d, int(math.floor((1.*B)**(1.*d/n))), verbose=verbose)
            for i in range(len(Sds)):
                if verbose:
                    print "="*80
                    print "Taking F =", Sds[i][1]
                F = NumberField(ZZx(Sds[i][1]), 't')
                T = enumerate_totallyreal_fields_rel(F, n/d, B, verbose=verbose, return_seqs=return_seqs)
                if return_seqs:
                    for i in range(3):
                        counts[i] += T[0][i]
                    S += [[t[0],pari(t[1]).Polrev()] for t in T[1]]
                else:
                    S += [[t[0],t[1]] for t in T]
                j = i+1
                for E in enumerate_totallyreal_fields_prim(n/d, int(math.floor((1.*B)**(1./d)/(1.*Sds[i][0])**(n*1./d**2)))):
                    for EF in F.composite_fields(NumberField(ZZx(E[1]), 'u')):
                        if EF.degree() == n and EF.disc() <= B:
                            S.append([EF.disc(), pari(EF.absolute_polynomial())])
    S += enumerate_totallyreal_fields_prim(n, B, verbose=verbose)
    S.sort()
    weed_fields(S)

    # Output.
    if verbose:
        saveout = sys.stdout
        if type(verbose) == str:
            fsock = open(verbose, 'w')
            sys.stdout = fsock
        # Else, print to screen
        print "="*80
        print "Polynomials tested:", counts[0]
        print "Irreducible polynomials:", counts[1]
        print "Polynomials with nfdisc <= B:", counts[2]
        for i in range(len(S)):
            print S[i]
        if type(verbose) == str:
            fsock.close()
        sys.stdout = saveout

    if return_seqs:
        return [counts,[[s[0],s[1].reverse().Vec()] for s in S]]
    else:
        return S
class EInfinitySurface(Surface):
    r"""
    The surface based on the $E_\infinity$ graph.

     The biparite graph is shown below, with edges numbered:

      0   1   2  -2   3  -3   4  -4 
    *---o---*---o---*---o---*---o---*...
            |
            |-1
            o

    Here, black vertices are colored *, and white o. 
    Black nodes represent vertical cylinders and white nodes
    represent horizontal cylinders.
    """
    def __init__(self,lambda_squared=None, field=None):
        TranslationSurface_generic.__init__(self)
        if lambda_squared==None:
            from sage.rings.number_field.number_field import NumberField
            from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
            R=PolynomialRing(ZZ,'x')
            x = R.gen()
            from sage.rings.qqbar import AA
            self._field=NumberField(x**3-ZZ(5)*x**2+ZZ(4)*x-ZZ(1), 'r', embedding=AA(ZZ(4)))
            self._l=self._field.gen()
        else:
            if field is None:
                self._l=lambda_squared
                self._field=lambda_squared.parent()
            else:
                self._field=field
                self._l=field(lambda_squared)
        Surface.__init__(self)

    def _repr_(self):
        r"""
        String representation.
        """
        return "The E-infinity surface"

    def base_ring(self):
        r"""
        Return the rational field.
        """
        return self._field

    def base_label(self):
        return ZZ.zero()

    @cached_method
    def get_white(self,n):
        r"""Get the weight of the white endpoint of edge n."""
        l=self._l
        if n==0 or n==1:
            return l
        if n==-1:
            return l-1
        if n==2:
            return 1-3*l+l**2
        if n>2:
            x=self.get_white(n-1)
            y=self.get_black(n)
            return l*y-x
        return self.get_white(-n)

    @cached_method
    def get_black(self,n):
        r"""Get the weight of the black endpoint of edge n."""
        l=self._l
        if n==0:
            return self._field(1)
        if n==1 or n==-1 or n==2:
            return l-1
        if n>2:
            x=self.get_black(n-1)
            y=self.get_white(n-1)
            return y-x
        return self.get_black(1-n)

    def polygon(self, lab):
        r"""
        Return the polygon labeled by ``lab``.
        """
        if lab not in self.polygon_labels():
            raise ValueError("lab (=%s) not a valid label"%lab)
        from flatsurf.geometry.polygon import rectangle
        return rectangle(2*self.get_black(lab),self.get_white(lab))

    def polygon_labels(self):
        r"""
        The set of labels used for the polygons.
        """
        return ZZ

    def opposite_edge(self, p, e):
        r"""
        Return the pair ``(pp,ee)`` to which the edge ``(p,e)`` is glued to.
        """
        if p==0:
            if e==0:
                return (0,2)
            if e==1:
                return (1,3)
            if e==2:
                return (0,0)
            if e==3:
                return (1,1)
        if p==1:
            if e==0:
                return (-1,2)
            if e==1:
                return (0,3)
            if e==2:
                return (2,0)
            if e==3:
                return (0,1)
        if p==-1:
            if e==0:
                return (2,2)
            if e==1:
                return (-1,3)
            if e==2:
                return (1,0)
            if e==3:
                return (-1,1)
        if p==2:
            if e==0:
                return (1,2)
            if e==1:
                return (-2,3)
            if e==2:
                return (-1,0)
            if e==3:
                return (-2,1)
        if p>2:
            if e%2:
                return -p,(e+2)%4
            else:
                return 1-p,(e+2)%4
        else:
            if e%2:
                return -p,(e+2)%4
            else:
                return 1-p,(e+2)%4

    def is_finite(self):
        return False