Ejemplo n.º 1
0
def number_field_to_AA(a):
    r"""
    It is a mess to convert an element of a number field to the algebraic field
    ``AA``. This is a temporary fix.
    """
    try:
        return AA(a)
    except TypeError:
        return AA.polynomial_root(a.minpoly(), RIF(a))
def from_mathematica(a):
    try:
        return QQ(a.sage())
    except Exception:
        pass
    try:
        return AA(a.sage())
    except Exception:
        coefficients = mathematica.CoefficientList(
            mathematica.MinimalPolynomial(a, 'x'), 'x').sage()
        x = polygen(QQ)
        minpoly = x.parent()(coefficients)
        interval = mathematica.IsolatingInterval(a).sage()
        rif_interval = RIF(interval)
        return AA.polynomial_root(minpoly, rif_interval)
Ejemplo n.º 3
0
def flipper_nf_to_sage(K, name='a'):
    r"""
    Convert a flipper number field into a Sage number field

    .. NOTE::

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

    EXAMPLES::

        sage: import flipper  # optional - flipper
        sage: from flatsurf.geometry.similarity_surface_generators import flipper_nf_to_sage
        sage: p = flipper.kernel.Polynomial([-2r] + [0r]*5 + [1r]) # optional - flipper
        sage: r1,r2 = p.real_roots()                               # optional - flipper
        sage: K = flipper.kernel.NumberField(r1)                   # optional - flipper
        sage: K_sage = flipper_nf_to_sage(K)                       # optional - flipper
        sage: K_sage                                               # optional - flipper
        Number Field in a with defining polynomial x^6 - 2
        sage: AA(K_sage.gen())                                     # optional - flipper
        -1.122462048309373?
    """
    from sage.rings.number_field.number_field import NumberField
    from sage.rings.all import QQ,RIF,AA

    r = K.lmbda.interval_approximation()
    l = r.lower * ZZ(10)**(-r.precision)
    u = r.upper * ZZ(10)**(-r.precision)

    p = QQ['x'](K.polynomial.coefficients)
    s = AA.polynomial_root(p, RIF(l,u))
    return NumberField(p, name, embedding=s)
Ejemplo n.º 4
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.subfield import number_field_elements_from_algebraics
        sage: z = QQbar.zeta(5)
        sage: c = z.real()
        sage: s = z.imag()
        sage: number_field_elements_from_algebraics((c,s))
        (Number Field in a with defining polynomial y^4 - 5*y^2 + 5 with a = 1.902113032590308?,
         [1/2*a^2 - 3/2, 1/2*a])

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

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

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

    return K, [x.polynomial()(gen) for x in elts]
Ejemplo n.º 5
0
    def rho(self):
        r"""
        Return the vertex ``rho`` of the basic hyperbolic
        triangle which describes ``self``. ``rho`` has
        absolute value 1 and angle ``pi/n``.

        EXAMPLES::

            sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
            sage: HeckeTriangleGroup(3).rho() == 1/2 + sqrt(3)/2*i
            True
            sage: HeckeTriangleGroup(4).rho() == sqrt(2)/2*(1 + i)
            True
            sage: HeckeTriangleGroup(6).rho() == sqrt(3)/2 + 1/2*i
            True
            sage: HeckeTriangleGroup(10).rho()
            0.95105651629515...? + 0.30901699437494...?*I
            sage: HeckeTriangleGroup(infinity).rho()
            1
        """

        # TODO: maybe rho should be replaced by -rhobar
        if (self._n == infinity):
            return AA(1)
        else:
            return AlgebraicField()(exp(pi/self._n*i))
def flipper_nf_to_sage(K, name='a'):
    r"""
    Convert a flipper number field into a Sage number field

    .. NOTE::

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

    EXAMPLES::

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

    p = QQ['x'](K.coefficients)
    s = AA.polynomial_root(p, RIF(l, u))
    return NumberField(p, name, embedding=s)
Ejemplo n.º 7
0
def number_field_to_AA(a):
    r"""
    It is a mess to convert an element of a number field to the algebraic field
    ``AA``. This is a temporary fix.
    """
    try:
        return AA(a)
    except TypeError:
        return AA.polynomial_root(a.minpoly(), RIF(a))
    def is_elliptic(self):
        r"""
        Return whether ``self`` is an elliptic matrix.

        EXAMPLES::

            sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
            sage: G = HeckeTriangleGroup(n=7)
            sage: [ G.V(k).is_elliptic() for k in range(1,8) ]
            [False, False, False, False, False, False, True]
            sage: G.U().is_elliptic()
            True
        """

        return AA(self.discriminant()) < 0
 def __init__(self, lambda_squared=None, field=None):
     if lambda_squared == None:
         from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
         R = PolynomialRing(ZZ, 'x')
         x = R.gen()
         field = NumberField(x**3 - ZZ(5) * x**2 + ZZ(4) * x - ZZ(1),
                             'r',
                             embedding=AA(ZZ(4)))
         self._l = field.gen()
     else:
         if field is None:
             self._l = lambda_squared
             field = lambda_squared.parent()
         else:
             self._l = field(lambda_squared)
     Surface.__init__(self, field, ZZ.zero(), finite=False)
Ejemplo n.º 10
0
    def lam_minpoly(self):
        r"""
        Return the minimal polynomial of the corresponding lambda parameter of ``self``.

        EXAMPLES::

            sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
            sage: HeckeTriangleGroup(10).lam_minpoly()
            x^4 - 5*x^2 + 5
            sage: HeckeTriangleGroup(17).lam_minpoly()
            x^8 - x^7 - 7*x^6 + 6*x^5 + 15*x^4 - 10*x^3 - 10*x^2 + 4*x + 1
            sage: HeckeTriangleGroup(infinity).lam_minpoly()
            x - 2
        """

        # TODO: Write an explicit (faster) implementation
        lam_symbolic = 2*cos(pi/self._n)
        return AA(lam_symbolic).minpoly()
Ejemplo n.º 11
0
    def __init__(self, n):
        r"""
        Hecke triangle group (2, n, infinity).
        Namely the von Dyck group corresponding to the triangle group
        with angles (pi/2, pi/n, 0).

        INPUT:

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

        OUTPUT:

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

        EXAMPLES::

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

        self._n = n

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

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

        FinitelyGeneratedMatrixGroup_generic.__init__(self, ZZ(2), self._base_ring, [S, T])
Ejemplo n.º 12
0
def homothety_rotation_decomposition(m):
    r"""
    Return a couple composed of the homothety and a rotation matrix.

    The coefficients of the returned pair are either in the ground field of
    ``m`` or in the algebraic field ``AA``.

    EXAMPLES::

        sage: from flatsurf.geometry.matrix_2x2 import homothety_rotation_decomposition

        sage: R.<x> = PolynomialRing(QQ)
        sage: K.<sqrt2> = NumberField(x^2 - 2, embedding=1.4142)
        sage: m = matrix([[sqrt2, -sqrt2],[sqrt2,sqrt2]])
        sage: a,rot = homothety_rotation_decomposition(m)
        sage: a
        2
        sage: rot
        [ 1/2*sqrt2 -1/2*sqrt2]
        [ 1/2*sqrt2  1/2*sqrt2]
    """
    if not is_similarity(m):
        raise ValueError("the matrix must be a similarity")

    det = m.det()

    if not det.is_square():
        if not AA.has_coerce_map_from(m.base_ring()):
            l = map(number_field_to_AA, m.list())
            M = MatrixSpace(AA, 2)
            m = M(l)
        else:
            m = m.change_ring(AA)

    sqrt_det = det.sqrt()

    return sqrt_det, m / sqrt_det
Ejemplo n.º 13
0
def homothety_rotation_decomposition(m):
    r"""
    Return a couple composed of the homothety and a rotation matrix.

    The coefficients of the returned pair are either in the ground field of
    ``m`` or in the algebraic field ``AA``.

    EXAMPLES::

        sage: from flatsurf.geometry.matrix_2x2 import homothety_rotation_decomposition

        sage: R.<x> = PolynomialRing(QQ)
        sage: K.<sqrt2> = NumberField(x^2 - 2, embedding=1.4142)
        sage: m = matrix([[sqrt2, -sqrt2],[sqrt2,sqrt2]])
        sage: a,rot = homothety_rotation_decomposition(m)
        sage: a
        2
        sage: rot
        [ 1/2*sqrt2 -1/2*sqrt2]
        [ 1/2*sqrt2  1/2*sqrt2]
    """
    if not is_similarity(m):
        raise ValueError("the matrix must be a similarity")

    det = m.det()

    if not det.is_square():
        if not AA.has_coerce_map_from(m.base_ring()):
            l = map(number_field_to_AA,m.list())
            M = MatrixSpace(AA,2)
            m = M(l)
        else:
            m = m.change_ring(AA)

    sqrt_det = det.sqrt()

    return sqrt_det, m / sqrt_det
    def mcmullen_genus2_prototype(w, h, t, e, rel=0):
        r"""
        McMullen prototypes in the stratum H(2).

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

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

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

        EXAMPLES::

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

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

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

        An example with some relative homology::

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

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

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

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

        # (lambda,lambda) square on top
        # twisted (w,0), (t,h)
        s = Surface_list(base_ring=K)
        if rel:
            if rel < 0 or rel > w - l:
                raise ValueError("invalid rel argument")
            s.add_polygon(
                polygons(vertices=[(0, 0), (l, 0), (l + rel, l), (rel, l)],
                         ring=K))
            s.add_polygon(
                polygons(vertices=[(0, 0), (rel, 0), (rel + l, 0), (w, 0),
                                   (w + t, h), (l + rel + t, h), (t + l, h),
                                   (t, h)],
                         ring=K))
            s.set_edge_pairing(0, 1, 0, 3)
            s.set_edge_pairing(0, 0, 1, 6)
            s.set_edge_pairing(0, 2, 1, 1)
            s.set_edge_pairing(1, 2, 1, 4)
            s.set_edge_pairing(1, 3, 1, 7)
            s.set_edge_pairing(1, 0, 1, 5)
        else:
            s.add_polygon(
                polygons(vertices=[(0, 0), (l, 0), (l, l), (0, l)], ring=K))
            s.add_polygon(
                polygons(vertices=[(0, 0), (l, 0), (w, 0), (w + t, h),
                                   (l + t, h), (t, h)],
                         ring=K))
            s.set_edge_pairing(0, 1, 0, 3)
            s.set_edge_pairing(0, 0, 1, 4)
            s.set_edge_pairing(0, 2, 1, 0)
            s.set_edge_pairing(1, 1, 1, 3)
            s.set_edge_pairing(1, 2, 1, 5)
        s.set_immutable()
        return TranslationSurface(s)
    def fixed_points(self, embedded=False, order="default"):
        r"""
        Return a pair of (mutually conjugate) fixed points of ``self``
        in a possible quadratic extension of the base field.

        INPUT:

        - ``embedded`` -- If ``True`` the fixed points are embedded into
                          ``AlgebraicRealField`` resp. ``AlgebraicField``.
                          Default: ``False``.

        - ``order``    -- If ``order="none"`` the fixed points are choosen
                          and ordered according to a fixed formula.

                          If ``order="sign"`` the fixed points are always ordered
                          according to the sign in front of the square root.

                          If ``order="default"`` (default) then in case the fixed
                          points are hyperbolic they are ordered according to the
                          sign of the trace of ``self`` instead, such that the
                          attracting fixed point comes first.

                          If ``order="trace"`` the fixed points are always ordered
                          according to the sign of the trace of ``self``.
                          If the trace is zero they are ordered by the sign in
                          front of the square root. In particular the fixed_points
                          in this case remain the same for ``-self``.

        OUTPUT:

        If ``embedded=True`` an element of either ``AlgebraicRealField`` or
        ``AlgebraicField`` is returned. Otherwise an element of a relative field
        extension over the base field of (the parent of) ``self`` is returned.

        Warning: Relative field extensions don't support default embeddings.
        So the correct embedding (which is the positive resp. imaginary positive
        one) has to be choosen.

        EXAMPLES::

            sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
            sage: G = HeckeTriangleGroup(n=infinity)
            sage: (-G.T(-4)).fixed_points()
            [+Infinity, +Infinity]
            sage: (-G.S()).fixed_points()
            [1/2*e, -1/2*e]
            sage: p = (-G.S()).fixed_points(embedded=True)[0]
            sage: p
            1*I
            sage: (-G.S()).acton(p) == p
            True
            sage: (-G.V(2)).fixed_points()
            [1/2*e, -1/2*e]
            sage: (-G.V(2)).fixed_points() == G.V(2).fixed_points()
            True
            sage: p = (-G.V(2)).fixed_points(embedded=True)[1]
            sage: p
            -1.732050807568878?
            sage: (-G.V(2)).acton(p) == p
            True

            sage: G = HeckeTriangleGroup(n=7)
            sage: (-G.S()).fixed_points()
            [1/2*e, -1/2*e]
            sage: p = (-G.S()).fixed_points(embedded=True)[1]
            sage: p
            -1*I
            sage: (-G.S()).acton(p) == p
            True
            sage: (G.U()^4).fixed_points()
            [(1/2*lam^2 - 1/2*lam - 1/2)*e + 1/2*lam, (-1/2*lam^2 + 1/2*lam + 1/2)*e + 1/2*lam]
            sage: pts = (G.U()^4).fixed_points(order="trace")
            sage: (G.U()^4).fixed_points() == [pts[1], pts[0]]
            True
            sage: (G.U()^4).fixed_points(order="trace") == (-G.U()^4).fixed_points(order="trace")
            True
            sage: (G.U()^4).fixed_points() == (G.U()^4).fixed_points(order="none")
            True
            sage: (-G.U()^4).fixed_points() == (G.U()^4).fixed_points()
            True
            sage: (-G.U()^4).fixed_points(order="none") == pts
            True
            sage: p = (G.U()^4).fixed_points(embedded=True)[1]
            sage: p
            0.9009688679024191? - 0.4338837391175581?*I
            sage: (G.U()^4).acton(p) == p
            True
            sage: (-G.V(5)).fixed_points()
            [(1/2*lam^2 - 1/2*lam - 1/2)*e, (-1/2*lam^2 + 1/2*lam + 1/2)*e]
            sage: (-G.V(5)).fixed_points() == G.V(5).fixed_points()
            True
            sage: p = (-G.V(5)).fixed_points(embedded=True)[0]
            sage: p
            0.6671145837954892?
            sage: (-G.V(5)).acton(p) == p
            True
        """

        if self.c() == 0:
            return [infinity, infinity]
        else:
            D = self.discriminant()
            if D.is_square():
                e = D.sqrt()
            else:
                e = self.root_extension_field().gen()

            a = self.a()
            d = self.d()
            c = self.c()

            if order == "none":
                sgn = ZZ(1)
            elif order == "sign":
                sgn = AA(c).sign()
            elif order == "default":
                if self.is_elliptic() or self.trace() == 0:
                    sgn = AA(c).sign()
                else:
                    sgn = AA(self.trace()).sign()
            elif order == "trace":
                if self.trace() == 0:
                    sgn = AA(c).sign()
                else:
                    sgn = AA(self.trace()).sign()
            else:
                raise NotImplementedError

            if embedded:
                e = AA(D).sqrt()
                a = AA(a)
                d = AA(d)
                c = AA(c)

            root1 = (a - d) / (2 * c) + sgn * e / (2 * c)
            root2 = (a - d) / (2 * c) - sgn * e / (2 * c)

            return [root1, root2]
    def decompose_basic(self):
        r"""
        Decompose ``self`` into a product of the generators
        ``S`` and ``T`` of its parent,

        The function returns a tuple ``L`` consisting of either
        ``parent.S()`` or non-trivial integer powers of ``parent.T()``.
        Additionally ``L`` starts with +- the identity.
        It satisfies the property: ``prod(L) == self``.

        If this decomposition is not possible an ``ValueError``
        is raised. In particular this function can be used to
        check the membership in ``parent`` of an arbitrary matrix
        over the base ring.

        EXAMPLES::

            sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
            sage: G = HeckeTriangleGroup(n=17)
            sage: L = (-G.V(2)).decompose_basic()
            sage: L
            (
            [  1 lam]  [ 0 -1]  [  1 lam]  [-1  0]
            [  0   1], [ 1  0], [  0   1], [ 0 -1]
            )
            sage: prod(L) == -G.V(2)
            True
            sage: L = G.U().decompose_basic()
            sage: L
            (
            [  1 lam]  [ 0 -1]  [1 0]
            [  0   1], [ 1  0], [0 1]
            )
            sage: prod(L) == G.U()
            True
        """
        def mshift(A):
            a = A[0][0]
            b = A[0][1]
            c = A[1][0]
            d = A[1][1]

            return (4 * a * c + b * d) / (4 * c * c + d * d)

        def mabs(A):
            a = A[0][0]
            b = A[0][1]
            c = A[1][0]
            d = A[1][1]

            return (4 * a * a + b * b) / (4 * c * c + d * d)

        res = []
        T = self.parent().T()
        S = self.parent().S()
        M = self
        lam = self.parent().lam()

        while True:
            m = (AA(mshift(M) / lam) + ZZ(1) / ZZ(2)).floor()
            M = T**(-m) * M
            if (m != 0):
                res.append(T**m)

            abs_t = mabs(M)
            if AA(abs_t) < 1:
                M = (-S) * M
                res.append(S)
            elif M.is_identity():
                res.append(M)
                return tuple(res)
            else:
                raise ValueError(
                    "The matrix is not an element of {}, up to equivalence it identifies two nonequivalent points."
                    .format(self.parent()))
    def root_extension_embedding(self, K=AlgebraicField()):
        r"""
        Return the correct embedding from the root extension field to ``K`` (default: ``AlgebraicField()``).

        EXAMPLES::

            sage: from sage.modular.modform_hecketriangle.hecke_triangle_groups import HeckeTriangleGroup
            sage: G = HeckeTriangleGroup(n=infinity)

            sage: fp = (-G.S()).fixed_points()[0]
            sage: alg_fp = (-G.S()).root_extension_embedding()(fp)
            sage: alg_fp
            1*I
            sage: alg_fp == (-G.S()).fixed_points(embedded=True)[0]
            True

            sage: fp = (-G.V(2)).fixed_points()[1]
            sage: alg_fp = (-G.V(2)).root_extension_embedding(AA)(fp)
            sage: alg_fp
            -1.732050807568...?
            sage: alg_fp == (-G.V(2)).fixed_points(embedded=True)[1]
            True

            sage: fp = (-G.V(2)).fixed_points()[0]
            sage: alg_fp = (-G.V(2)).root_extension_embedding(AA)(fp)
            sage: alg_fp
            1.732050807568...?
            sage: alg_fp == (-G.V(2)).fixed_points(embedded=True)[0]
            True

            sage: G = HeckeTriangleGroup(n=7)

            sage: fp = (-G.S()).fixed_points()[1]
            sage: alg_fp = (-G.S()).root_extension_embedding()(fp)
            sage: alg_fp
            0.?... - 1.000000000000...?*I
            sage: alg_fp == (-G.S()).fixed_points(embedded=True)[1]
            True

            sage: fp = (-G.U()^4).fixed_points()[0]
            sage: alg_fp = (-G.U()^4).root_extension_embedding()(fp)
            sage: alg_fp
            0.9009688679024...? + 0.4338837391175...?*I
            sage: alg_fp == (-G.U()^4).fixed_points(embedded=True)[0]
            True

            sage: (-G.U()^4).root_extension_embedding(CC)(fp)
            0.900968867902... + 0.433883739117...*I
            sage: (-G.U()^4).root_extension_embedding(CC)(fp).parent()
            Complex Field with 53 bits of precision

            sage: fp = (-G.V(5)).fixed_points()[1]
            sage: alg_fp = (-G.V(5)).root_extension_embedding(AA)(fp)
            sage: alg_fp
            -0.6671145837954...?
            sage: alg_fp == (-G.V(5)).fixed_points(embedded=True)[1]
            True
        """

        G = self.parent()
        D = self.discriminant()
        F = self.root_extension_field()
        n = G.n()

        if D.is_square():
            e = D.sqrt()
            lam = G.lam()
        elif n in [3, infinity]:
            e = F.gen(0)
            lam = G.lam()
        else:
            (e, lam) = F.gens()

        emb_lam = K(G.lam())
        if self.is_elliptic():
            emb_e = K(AlgebraicField()(D).sqrt())
        else:
            emb_e = K(AA(D).sqrt())

        guess = ZZ(0)
        min_value = infinity
        index = ZZ(0)

        for (index,
             emb) in enumerate(self.root_extension_field().embeddings(K)):
            if K.is_exact():
                if emb(lam) == emb_lam and emb(e) == emb_e:
                    return emb
            else:
                value = (emb(lam) - emb_lam).n(
                    K.prec()).abs() + (emb(e) - emb_e).n(K.prec()).abs()
                if (value < min_value):
                    guess = index
                    min_value = value

        if K.is_exact() or min_value == infinity:
            raise ValueError(
                "No suitable embedding is available for K = {}!".format(K))
        else:
            return self.root_extension_field().embeddings(K)[guess]
    def arnoux_yoccoz(genus):
        r"""
        Construct the Arnoux-Yoccoz surface of genus 3 or greater.
        
        This presentation of the surface follows Section 2.3 of 
        Joshua P. Bowman's paper "The Complete Family of Arnoux-Yoccoz 
        Surfaces."
        
        EXAMPLES::

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

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

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

            sage: S4 = translation_surfaces.arnoux_yoccoz(4)
            sage: Jxx, Jyy, Jxy = S4.j_invariant()
            sage: Jxx.is_zero() and Jyy.is_zero()
            True
            sage: Jxy
            [ 0  2  0  0]
            [ 2 -2  0  0]
            [ 0  0  2  2]
            [ 0  0  2  0]
        """
        g=ZZ(genus)
        assert g>=3
        from sage.rings.polynomial.polynomial_ring import polygen
        x = polygen(AA)
        p=sum([x**i for i in xrange(1,g+1)])-1
        cp = AA.common_polynomial(p)
        alpha_AA = AA.polynomial_root(cp, RIF(1/2, 1))
        field=NumberField(alpha_AA.minpoly(),'alpha',embedding=alpha_AA)
        a=field.gen()
        from sage.modules.free_module import VectorSpace
        V=VectorSpace(field,2)
        p=[None for i in xrange(g+1)]
        q=[None for i in xrange(g+1)]
        p[0]=V(( (1-a**g)/2, a**2/(1-a) ))
        q[0]=V(( -a**g/2, a ))
        p[1]=V(( -(a**(g-1)+a**g)/2, (a-a**2+a**3)/(1-a) ))
        p[g]=V(( 1+(a-a**g)/2, (3*a-1-a**2)/(1-a) ))
        for i in xrange(2,g):
            p[i]=V(( (a-a**i)/(1-a) , a/(1-a) ))
        for i in xrange(1,g+1):
            q[i]=V(( (2*a-a**i-a**(i+1))/(2*(1-a)), (a-a**(g-i+2))/(1-a) ))
        from flatsurf.geometry.polygon import Polygons
        P=Polygons(field)
        s = Surface_list(field)
        T = [None] * (2*g+1)
        Tp = [None] * (2*g+1)
        from sage.matrix.constructor import Matrix
        m=Matrix([[1,0],[0,-1]])
        for i in xrange(1,g+1):
            # T_i is (P_0,Q_i,Q_{i-1})
            T[i]=s.add_polygon(P(edges=[ q[i]-p[0], q[i-1]-q[i], p[0]-q[i-1] ]))
            # T_{g+i} is (P_i,Q_{i-1},Q_{i})
            T[g+i]=s.add_polygon(P(edges=[ q[i-1]-p[i], q[i]-q[i-1], p[i]-q[i] ]))
            # T'_i is (P'_0,Q'_{i-1},Q'_i)
            Tp[i]=s.add_polygon(m*s.polygon(T[i]))
            # T'_{g+i} is (P'_i,Q'_i, Q'_{i-1})
            Tp[g+i]=s.add_polygon(m*s.polygon(T[g+i]))
        for i in xrange(1,g):
            s.change_edge_gluing(T[i],0,T[i+1],2)
            s.change_edge_gluing(Tp[i],2,Tp[i+1],0)
        for i in xrange(1,g+1):
            s.change_edge_gluing(T[i],1,T[g+i],1)
            s.change_edge_gluing(Tp[i],1,Tp[g+i],1)
        #P 0 Q 0 is paired with P' 0 Q' 0, ...
        s.change_edge_gluing(T[1],2,Tp[g],2)
        s.change_edge_gluing(Tp[1],0,T[g],0)
        # P1Q1 is paired with P'_g Q_{g-1}
        s.change_edge_gluing(T[g+1],2,Tp[2*g],2)
        s.change_edge_gluing(Tp[g+1],0,T[2*g],0)
        # P1Q0 is paired with P_{g-1} Q_{g-1}
        s.change_edge_gluing(T[g+1],0,T[2*g-1],2)
        s.change_edge_gluing(Tp[g+1],2,Tp[2*g-1],0)
        # PgQg is paired with Q1P2
        s.change_edge_gluing(T[2*g],2,T[g+2],0)
        s.change_edge_gluing(Tp[2*g],0,Tp[g+2],2)
        for i in xrange(2,g-1):
            # PiQi is paired with Q'_i P'_{i+1}
            s.change_edge_gluing(T[g+i],2,Tp[g+i+1],2)
            s.change_edge_gluing(Tp[g+i],0,T[g+i+1],0)
        s.set_immutable()
        return TranslationSurface(s)
Ejemplo n.º 19
0
    def _coerce_map_from_(self, P):
        r"""
        Return whether ``P`` coerces into this symbolic subring.

        INPUT:

        - ``P`` -- a parent.

        OUTPUT:

        A boolean or ``None``.

        TESTS::

            sage: from sage.symbolic.subring import GenericSymbolicSubring
            sage: GenericSymbolicSubring(vars=tuple()).has_coerce_map_from(SR)  # indirect doctest  # not tested see #19231
            False

        ::
            sage: from sage.symbolic.subring import SymbolicSubring
            sage: C = SymbolicSubring(no_variables=True)
            sage: C.has_coerce_map_from(ZZ)  # indirect doctest
            True
            sage: C.has_coerce_map_from(QQ)  # indirect doctest
            True
            sage: C.has_coerce_map_from(RR)  # indirect doctest
            True
            sage: C.has_coerce_map_from(RIF)  # indirect doctest
            True
            sage: C.has_coerce_map_from(CC)  # indirect doctest
            True
            sage: C.has_coerce_map_from(CIF)  # indirect doctest
            True
            sage: C.has_coerce_map_from(AA)  # indirect doctest
            True
            sage: C.has_coerce_map_from(QQbar)  # indirect doctest
            True
            sage: C.has_coerce_map_from(SR)  # indirect doctest
            False
        """
        if P == SR:
            # Workaround; can be deleted once #19231 is fixed
            return False

        from sage.rings.real_mpfr import mpfr_prec_min
        from sage.rings.all import (ComplexField,
                                    RLF, CLF, AA, QQbar, InfinityRing)
        from sage.rings.real_mpfi import is_RealIntervalField
        from sage.rings.complex_interval_field import is_ComplexIntervalField

        if isinstance(P, type):
            return SR._coerce_map_from_(P)

        elif RLF.has_coerce_map_from(P) or \
             CLF.has_coerce_map_from(P) or \
             AA.has_coerce_map_from(P) or \
             QQbar.has_coerce_map_from(P):
            return True

        elif (P is InfinityRing or
              is_RealIntervalField(P) or is_ComplexIntervalField(P)):
            return True

        elif ComplexField(mpfr_prec_min()).has_coerce_map_from(P):
            return P not in (RLF, CLF, AA, QQbar)
Ejemplo n.º 20
0
def angle(u, v, numerical=False, assume_rational=False):
    r"""
    Return the angle between the vectors ``u`` and ``v`` divided by `2 \pi`.

    INPUT:

    - ``u``, ``v`` - vectors

    - ``numerical`` - boolean, whether to return floating point numbers

    - ``assume_rational`` - whether we assume that the angle is a multiple
      rational of ``pi``. By default it is ``False`` but if it is known in
      advance that the result is rational then setting it to ``True`` might be
      much faster.

    EXAMPLES::

        sage: from flatsurf.geometry.matrix_2x2 import angle

    As the implementation is dirty, we at least check that it works for all
    denominator up to 20::

        sage: u = vector((AA(1),AA(0)))
        sage: for n in xsrange(1,20):       # long time  (10 sec)
        ....:     for k in xsrange(1,n):
        ....:         v = vector((AA(cos(2*k*pi/n)), AA(sin(2*k*pi/n))))
        ....:         assert angle(u,v) == k/n

    The numerical version (working over floating point numbers)::

        sage: import math
        sage: u = (1, 0)
        sage: for n in xsrange(1,20):
        ....:     for k in xsrange(1,n):
        ....:         a = 2 * k * math.pi / n
        ....:         v = (math.cos(a), math.sin(a))
        ....:         assert abs(angle(u,v,numerical=True) * 2 * math.pi - a) < 1.e-10

    And we test up to 50 when setting ``assume_rational`` to ``True``::

        sage: for n in xsrange(1,20):       # long time
        ....:     for k in xsrange(1,n):
        ....:         v = vector((AA(cos(2*k*pi/n)), AA(sin(2*k*pi/n))))
        ....:         assert angle(u,v,assume_rational=True) == k/n

    If the angle is not rational, then the method returns an element in the real
    lazy field::

        sage: v = vector((AA(sqrt(2)), AA(sqrt(3))))
        sage: a = angle(u, v)
        sage: a    # abs tol 1e-14
        0.14102355421224375
        sage: exp(2*pi.n()*CC(0,1)*a)
        0.632455532033676 + 0.774596669241483*I
        sage: v / v.norm()
        (0.6324555320336758?, 0.774596669241484?)
    """
    if not assume_rational and not numerical:
        sqnorm_u = u[0] * u[0] + u[1] * u[1]
        sqnorm_v = v[0] * v[0] + v[1] * v[1]

        if sqnorm_u != sqnorm_v:
            uu = vector(AA, u)
            vv = (AA(sqnorm_u) / AA(sqnorm_v)).sqrt() * vector(AA, v)
        else:
            uu = u
            vv = v

        cos_uv = (uu[0] * vv[0] + uu[1] * vv[1]) / sqnorm_u
        sin_uv = (uu[0] * vv[1] - uu[1] * vv[0]) / sqnorm_u

        is_rational = is_cosine_sine_of_rational(cos_uv, sin_uv)
    elif assume_rational:
        is_rational = True

    import math

    u0 = float(u[0])
    u1 = float(u[1])
    v0 = float(v[0])
    v1 = float(v[1])

    cos_uv = (u0 * v0 + u1 * v1) / math.sqrt(
        (u0 * u0 + u1 * u1) * (v0 * v0 + v1 * v1))
    if cos_uv < -1.0:
        assert cos_uv > -1.0000001
        cos_uv = -1.0
    elif cos_uv > 1.0:
        assert cos_uv < 1.0000001
        cos_uv = 1.0
    angle = math.acos(cos_uv) / (2 * math.pi)  # rat number between 0 and 1/2

    if numerical or not is_rational:
        return 1.0 - angle if u0 * v1 - u1 * v0 < 0 else angle
    else:
        # fast and dirty way using floating point approximation
        # (see below for a slow but exact method)
        angle_rat = RR(angle).nearby_rational(0.00000001)
        if angle_rat.denominator() > 100:
            raise NotImplementedError(
                "the numerical method used is not smart enough!")
        return 1 - angle_rat if u0 * v1 - u1 * v0 < 0 else angle_rat
Ejemplo n.º 21
0
    - 251568270025211201955389171860338579171675714868104052152789880989805712726614197574887246767925108246607970007160940134370673529705101398997875679835167365081669374673539993436160000*t**3
    - 141772430429024326881509616736177148212059744813752208473666088996700368688933789363560771135161864201721524861419389136852260702560567771393655430337183040528733205980885277265100800000*t**2
    - 25817606346086956476758470208850883766420383787607030339022713274189365873405154695767797745935894060883806800961601773820707673481632102376182116930107064769426021006200320503617211596800*t
    + 34918206405098505823938790072675572231488655998026261577866691497637535623661745400444768148106948876570405151317417742685700849593772165309178580940805695949542187927076864000)*Dt)
quadric_slice_pol = (
    4980990673427087034113103774848375913397675011396681161337606780457883155824640000000000*t**12
    - 16313074573215242896867677175985719375664055250377801991087546344967331905536000000000*t**9
    - 14852779293587242300314544658084523021409425155052443959294262319432698489552764928000000*t**8
    + 18694126910889886952945780127491545129704079293214429569400282861674612412907520000*t**6
    + 32429224374768702788524801575483580065598417846595577296275963028007688596147404800000*t**5
    + 14763130935033327878568955564665179022508855828282305094488782847988800598441515915673600*t**4
    - 7447056930374930458107131157447569387299331973073657492405996702806537404416000*t**3
    - 18581243794708202636835504417848386599346688512251081679746508518773002589362454528*t**2
    - 16116744082275656666424675660780874575937043631040306492377025123023286892432343685120*t
    - 4891341219838850087826096307272910719484535278552470341569283855964428449539674077056375)
quadric_slice_crit = AA.polynomial_root(quadric_slice_pol, RIF(-0.999,-0.998))

aa = AA.polynomial_root(AA.common_polynomial(t**2 - t - 6256320), RIF(-RR(2500.7637305969961), -RR(2500.7637305969956)))
K, a = NumberField(t**2 - t - 6256320, 'a', embedding=aa).objgen()
DiffOps_x, x, Dx = DifferentialOperators(K, 'x')
iint_quadratic_alg = IVP(
    dop = (
        (8680468749131953125000000000000000000000*x**13 
        + (34722222218750000000000000000000*a 
        - 8680555572048611109375000000000000000000)*x**12 
        - 43419899820094632213834375000000000000000*x**11 
        + (
        -173681336093739466250000000000000*a 
        + 43420334110275534609369733125000000000000)*x**10 
        + 86874920665761352031076792873375000000000*x**9 
        + (347503157694622354347850650000000*a 
Ejemplo n.º 22
0
    def _coerce_map_from_(self, P):
        r"""
        Return whether ``P`` coerces into this symbolic subring.

        INPUT:

        - ``P`` -- a parent.

        OUTPUT:

        A boolean or ``None``.

        TESTS::

            sage: from sage.symbolic.subring import GenericSymbolicSubring
            sage: GenericSymbolicSubring(vars=tuple()).has_coerce_map_from(SR)  # indirect doctest  # not tested see #19231
            False

        ::
            sage: from sage.symbolic.subring import SymbolicSubring
            sage: C = SymbolicSubring(no_variables=True)
            sage: C.has_coerce_map_from(ZZ)  # indirect doctest
            True
            sage: C.has_coerce_map_from(QQ)  # indirect doctest
            True
            sage: C.has_coerce_map_from(RR)  # indirect doctest
            True
            sage: C.has_coerce_map_from(RIF)  # indirect doctest
            True
            sage: C.has_coerce_map_from(CC)  # indirect doctest
            True
            sage: C.has_coerce_map_from(CIF)  # indirect doctest
            True
            sage: C.has_coerce_map_from(AA)  # indirect doctest
            True
            sage: C.has_coerce_map_from(QQbar)  # indirect doctest
            True
            sage: C.has_coerce_map_from(SR)  # indirect doctest
            False
        """
        if P == SR:
            # Workaround; can be deleted once #19231 is fixed
            return False

        from sage.rings.real_mpfr import mpfr_prec_min
        from sage.rings.all import (ComplexField, RLF, CLF, AA, QQbar,
                                    InfinityRing)
        from sage.rings.real_mpfi import is_RealIntervalField
        from sage.rings.complex_interval_field import is_ComplexIntervalField

        if isinstance(P, type):
            return SR._coerce_map_from_(P)

        elif RLF.has_coerce_map_from(P) or \
             CLF.has_coerce_map_from(P) or \
             AA.has_coerce_map_from(P) or \
             QQbar.has_coerce_map_from(P):
            return True

        elif (P is InfinityRing or is_RealIntervalField(P)
              or is_ComplexIntervalField(P)):
            return True

        elif ComplexField(mpfr_prec_min()).has_coerce_map_from(P):
            return P not in (RLF, CLF, AA, QQbar)
    def arnoux_yoccoz(genus):
        r"""
        Construct the Arnoux-Yoccoz surface of genus 3 or greater.

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

        EXAMPLES::

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

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

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

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