Beispiel #1
0
    def test_hyperelliptic_regular_places(self):
        R = QQ['x,y']
        x, y = R.gens()
        X = RiemannSurface(y**2 - (x + 1) * (x - 1) * (x - 2) * (x + 2))
        omegas = differentials(X)

        # the places above x=0 are regular
        places = X(0)
        for P in places:
            a, b = P.x, P.y
            for omega in omegas:
                omega_P = omega.centered_at_place(P)
                val1 = omega(a, b)
                val2 = omega_P(CC(0))
                self.assertLess(abs(val1 - val2), 1e-8)

        # the places above x=oo are regular: P = (1/t, \pm 1/t**2 + O(1))
        # (however, all places at infinity are treated as discriminant)
        #
        # in this particular example, omega[0] = 1/(2*y). At the places at
        # infinity, these are equal to \mp 0.5, respectively. (the switch in
        # sign comes from the derivative dxdt = -1/t**2)
        places = X('oo')
        for P in places:
            sign = P.puiseux_series.ypart[-2]
            for omega in omegas:
                omega_P = omega.centered_at_place(P)
                val1 = -sign * 0.5
                val2 = omega_P(CC(0))
                self.assertLess(abs(val1 - val2), 1e-8)
    def analytically_continue(self, xi, yi, xip1):
        r"""Analytically continue the y-fibre `yi` lying above `xi` to the y-fibre lying
        above `xip1`.

        We analytically continue by simply evaluating the ordered puiseux
        series computed during initialization of the Riemann surface path.

        Parameters
        ----------
        xi : complex
            The starting complex x-value.
        yi: complex[:]
            The starting complex y-fibre lying above `xi`.
        xip1: complex
            The target complex x-value.

        Returns
        -------
        yi : complex[:]
            The corresponding y-fibre lying above `xi`.
        """
        # XXX HACK - need to coerce input to CC for puiseux series to evaluate
        xi = CC(xi)
        xip1 = CC(xip1)

        # return the current fibre if the step size is too small
        if numpy.abs(xip1 - xi) < 1e-15:
            return yi

        # simply evaluate the ordered puiseux series at xip1
        alpha = CC(0) if self.target_point == infinity else CC(
            self.target_point)
        yip1 = [pj(xip1 - alpha) for pj in self.puiseux_series]
        yip1 = numpy.array(yip1, dtype=complex)
        return yip1
Beispiel #3
0
    def __init__(self, A, B, C, options):
        """
        Initialize HyperbolicTriangle:

        Examples::

            sage: from sage.plot.hyperbolic_triangle import HyperbolicTriangle
            sage: print HyperbolicTriangle(0, 1/2, I, {})
            Hyperbolic triangle (0.000000000000000, 0.500000000000000, 1.00000000000000*I)

        """
        A, B, C = (CC(A), CC(B), CC(C))
        self.path = []
        sides = options.pop('sides', [1, 2, 3])
        verbose = options.pop('verbose', 0)
        sides.sort()
        if sides == [1]:
            if verbose > 0:
                print "Drawing A - B!"
            self._hyperbolic_arc(A, B, True)
        elif sides == [2]:
            if verbose > 0:
                print "Drawing B - C!"
            self._hyperbolic_arc(B, C, True)
        elif sides == [3]:
            if verbose > 0:
                print "Drawing C - A!"
            self._hyperbolic_arc(C, A, True)
        elif sides == [1, 2]:
            if verbose > 0:
                print "Drawing A - B! & B - C!"
            self._hyperbolic_arc(A, B, True)
            self._hyperbolic_arc(B, C, False)
        elif sides == [1, 3]:
            if verbose > 0:
                print "Drawing C - A! & A - B"
            self._hyperbolic_arc(C, A, True)
            self._hyperbolic_arc(A, B, False)
        elif sides == [2, 3]:
            if verbose > 0:
                print "Drawing B - C! & C - A"
            self._hyperbolic_arc(B, C, True)
            self._hyperbolic_arc(C, A, False)
        else:
            self._hyperbolic_arc(A, B, True)
            self._hyperbolic_arc(B, C, False)
            self._hyperbolic_arc(C, A, False)

        BezierPath.__init__(self, self.path, options)
        self.A, self.B, self.C = (A, B, C)
        self._pts = [A, B, C]
Beispiel #4
0
def check_ap2_slow(rec):
    # Check a_{p^2} = a_p^2 - chi(p) for primes up to 31
    ls = rec['lfunction_label'].split('.')
    level, weight, chi = map(int, [ls[0], ls[1], ls[-2]])
    char = DirichletGroup_conrey(level, CC)[chi]
    Z = rec['an_normalized[0:1000]']
    for p in prime_range(31+1):
        if level % p != 0:
            # a_{p^2} = a_p^2 - chi(p)
            charval = CC(2*char.logvalue(int(p)) * CC.pi()*CC.gens()[0]).exp()
        else:
            charval = 0
        if  (CC(*Z[p**2 - 1]) - (CC(*Z[p-1])**2 - charval)).abs() > 1e-11:
            return False
    return True
def test_elliptic_curve(a, b, alpha=7, angles=12):
    from sage.all import cos, sin, pi
    E = EllipticCurve(QQ, [a, b])
    rationalpoints = E.point_search(10)
    EQbar = EllipticCurve(QQbar, [a, b])
    infx, infy, _ = rationalpoints[0]
    inf = EQbar(infx, infy)
    print inf
    R = PolynomialRing(QQ, "w")
    w = R.gen()
    f = w**3 + a * w + b
    iaj = InvertAJlocal(f, 256, method='gauss-legendre')
    iaj.set_basepoints([(mpmath.mpf(infx), mpmath.mpf(infy))])
    for eps in [
            cos(theta * 2 * pi / angles) + I * sin(theta * 2 * pi / angles)
            for theta in range(0, angles)
    ]:
        px = infx + eps
        py = iaj.sign * sqrt(-E.defining_polynomial().subs(x=px, y=0, z=1))
        P = EQbar(px, py)
        try:
            (v, errorv) = iaj.to_J(px, infx)
            qx = (alpha * P - (alpha - 1) * inf).xy()[0]
            qxeps = CC(qx) + (mpmath.rand() + I * mpmath.rand()) / 1000
            (t1, errort1) = iaj.solve(alpha * v, 100, iaj.error, [qxeps])
            qxguess = t1[0, 0]
            print mpmath.fabs(qxguess - qx) < 2**(-mpmath.mp.prec / 2)
        except RuntimeWarning as detail:
            print detail
Beispiel #6
0
 def value(self, z, embedding=0):
     if self.prec == 0:
         return 0
     else:
         q = exp(2 * CC.pi() * CC(0, 1) * z)
         return sum(
             self.coefficient_embedding(n, embedding) * q**n
             for n in range(self.prec))
Beispiel #7
0
def _circ_arc(t0, t1, c, r, num_pts=5000):
    r""" Circular arc
    INPUTS:
    - ''t0'' -- starting parameter
    - ''t1'' -- ending parameter
    - ''c''  -- center point of the circle
    - ''r''  -- radius of circle
    - ''num_pts''  -- (default 100) number of points on polygon
    OUTPUT:
    - ''ca'' -- a polygonal approximation of a circular arc centered
    at c and radius r, starting at t0 and ending at t1

    
    EXAMPLES::

        sage: ca=_circ_arc(0.1,0.2,0.0,1.0,100)
    
    """
    from sage.plot.plot import line, parametric_plot
    from sage.functions.trig import (cos, sin)
    from sage.all import var
    t00 = t0
    t11 = t1
    ## To make sure the line is correct we reduce all arguments to the same branch,
    ## e.g. [0,2pi]
    pi = RR.pi()
    while (t00 < 0.0):
        t00 = t00 + RR(2.0 * pi)
    while (t11 < 0):
        t11 = t11 + RR(2.0 * pi)
    while (t00 > 2 * pi):
        t00 = t00 - RR(2.0 * pi)
    while (t11 > 2 * pi):
        t11 = t11 - RR(2.0 * pi)

    xc = CC(c).real()
    yc = CC(c).imag()
    num_pts = 3
    t = var('t')
    if t11 > t00:
        ca = parametric_plot((r * cos(t) + xc, r * sin(t) + yc), (t, t00, t11))
    else:
        ca = parametric_plot((r * cos(t) + xc, r * sin(t) + yc), (t, t11, t00))
    #L0 = [[RR(r*cos(t00+i*(t11-t00)/num_pts))+xc,RR(r*sin(t00+i*(t11-t00)/num_pts))+yc] for i in range(0 ,num_pts)]
    #ca=line(L0)
    return ca
    def parameterize(self, omega):
        r"""Returns the differential omega parameterized on the path.

        Given a differential math:`\omega = \omega(x,y)dx`, `parameterize`
        returns the differential

        .. math::

            \omega_\gamma(s) = \omega(\gamma_x(s),\gamma_y(s)) \gamma_x'(s)

        where :math:`s \in [0,1]` and :math:`\gamma_x,\gamma_y` and the x- and
        y-components of the path `\gamma` using this analytic continuator.

        Parameters
        ----------
        omega : Differential
            A differential (one-form) on the Riemann surface.

        Returns
        -------
        omega_gamma : function
            The differential parameterized on the curve for s in the interval
            [0,1].
        """
        # localize the differential at the discriminant place
        P = self.target_place
        omega_local = omega.localize(P)
        omega_local = omega_local.laurent_polynomial().change_ring(CC)

        # extract relevant information about the Puiseux series
        p = P.puiseux_series
        x0 = complex(self.gamma.x0)
        y0 = complex(self.gamma.y0[0])
        alpha = 0 if self.target_point == infinity else self.target_point
        xcoefficient = complex(p.xcoefficient)
        e = numpy.int(p.ramification_index)

        # the parameter of the path s \in [0,1] does not necessarily match with
        # the local coordinate t of the place. perform the appropriate scaling
        # on the integral.
        tprim = complex((x0 - alpha) / xcoefficient)**(1. / e)
        unity = [numpy.exp(2.j * numpy.pi * k / abs(e)) for k in range(abs(e))]
        tall = [unity[k] * tprim for k in range(abs(e))]
        ytprim = numpy.array([p.eval_y(tk) for tk in tall],
                             dtype=numpy.complex)
        k = numpy.argmin(numpy.abs(ytprim - y0))
        tcoefficient = tall[k]

        # XXX HACK - CC coercion
        tcoefficient = CC(tcoefficient)

        def omega_gamma(s):
            s = CC(s)
            dtds = -tcoefficient
            val = omega_local(tcoefficient * (1 - s)) * dtds
            return complex(val)

        return numpy.vectorize(omega_gamma, otypes=[complex])
Beispiel #9
0
def signtocolour(sign):
    """
    Assigns an rgb string colour to a complex number based on its argument.
    """
    argument = cmath.phase(CC(str(sign)))
    r = int(255.0 * (math.cos((1.0 * math.pi / 3.0) - (argument / 2.0))) ** 2)
    g = int(255.0 * (math.cos((2.0 * math.pi / 3.0) - (argument / 2.0))) ** 2)
    b = int(255.0 * (math.cos(argument / 2.0)) ** 2)
    return("rgb(" + str(r) + "," + str(g) + "," + str(b) + ")")
Beispiel #10
0
 def embedding_maker(self, rec, lang):
     emb_list = []
     embeddings = rec["embeddings"]
     if lang == "magma":
         for z in embeddings:
             z_str = "ComplexField(15)!%s" % z
             emb_list.append(z_str)
         return "[%s]" % ", ".join(emb_list)
     if lang == "sage":
         return "%s" % [CC(z) for z in embeddings]
Beispiel #11
0
 def check_ap2_slow(self, rec, verbose=False):
     """
     Check a_{p^2} = a_p^2 - chi(p) for primes up to 31
     """
     ls = rec['label'].split('.')
     level, weight, chi = map(int, [ls[0], ls[1], ls[-2]])
     char = DirichletGroup_conrey(level, CC)[chi]
     Z = rec['an_normalized']
     for p in prime_range(31+1):
         if level % p != 0:
             # a_{p^2} = a_p^2 - chi(p)
             charval = CC(2*char.logvalue(int(p)) * CC.pi()*CC.gens()[0]).exp()
         else:
             charval = 0
         if (CC(*Z[p**2 - 1]) - (CC(*Z[p-1])**2 - charval)).abs() > 1e-13:
             if verbose:
                 print "ap2 failure", p, CC(*Z[p**2 - 1]), CC(*Z[p-1])**2 - charval
             return False
     return True
def parse_complex_number(z):
    """convert a string representing a complex number to another string looking like "(x,y)"
    """
    from sage.all import CC
    try:
        # need to convert from unicode to orginary string type
        x, y = CC(string2number(str(z)))
        return "({},{})".format(x, y)
    except (TypeError, SyntaxError):
        print("Unable to parse {} as complex number".format(z))
        return "(0,0)"
Beispiel #13
0
 def check_amn_slow(self, rec, verbose=False):
     """
     Check that a_{pn} = a_p * a_n for p < 32 prime, n prime to p
     """
     Z = [0] + [CC(*elt) for elt in rec['an_normalized']]
     for pp in prime_range(len(Z)-1):
         for k in range(1, (len(Z) - 1)//pp + 1):
             if gcd(k, pp) == 1:
                 if (Z[pp*k] - Z[pp]*Z[k]).abs() > 1e-13:
                     if verbose:
                         print "amn failure", k, pp, Z[pp*k], Z[pp]*Z[k]
                     return False
     return True
Beispiel #14
0
    def test_f2_regular_places(self):
        X = self.X2
        omegas = differentials(X)

        # the places above x=1 are regular
        places = X(1)
        for P in places:
            a, b = P.x, P.y
            for omega in omegas:
                omega_P = omega.centered_at_place(P)
                val1 = omega(a, b)
                val2 = omega_P(CC(0))
                self.assertLess(abs(val1 - val2), 1e-8)
    def __init__(self, riemann_surface, complex_path, y0, ncheckpoints=16):
        # if the complex path leads to a discriminant point then get the exact
        # representation of said discrimimant point
        target_point = complex_path(1)
        if target_point in [numpy.Infinity, infinity]:
            target_point = infinity
        elif abs(CC(target_point)) > 1e12:
            target_point = infinity
        else:
            discriminant_point = riemann_surface.path_factory.closest_discriminant_point(
                target_point)
            if abs(CC(target_point - discriminant_point)) < 1e-12:
                target_point = discriminant_point
            else:
                # if it's not discriminant then try to coerce to QQ or QQbar
                try:
                    target_point = QQ(target_point)
                except TypeError:
                    try:
                        target_point = QQbar(target_point)
                    except TypeError:
                        pass

        # compute and store the ordered puiseux series needed to analytically
        # continue as well as the target place for parameterization purposes
        puiseux_series, target_place = ordered_puiseux_series(
            riemann_surface, complex_path, y0, target_point)
        self.puiseux_series = puiseux_series
        self.target_point = target_point
        self.target_place = target_place

        # now that the machinery is set up we can instantiate the base object
        RiemannSurfacePathPrimitive.__init__(self,
                                             riemann_surface,
                                             complex_path,
                                             y0,
                                             ncheckpoints=ncheckpoints)
    def _path_to_infinite_place(self, P):
        r"""Returns a path to a place at an infintiy of the surface.

        A place at infinity is one where the `x`-projection of the place is the
        point `x = \infty` of the complex Riemann sphere. An infinite place is
        a type of discirminant place.

        Parameters
        ----------
        P : Place
            The target infinite place.

        Returns
        -------
        gamma : RiemannSurfacePath
            A path from the base place to the place at infinity.

        """
        # determine a place Q from where we can reach the target place P. first,
        # pick an appropriate x-point over which a Q is chosen
        x0 = self.base_point
        if numpy.real(x0) < 0:
            xa = 5 * x0  # move away from the origin
        else:
            xa = -5  # arbitrary choice away from the origin

        # next, determine an appropriate y-part from where we can reach the
        # place at infinity
        p = P.puiseux_series
        center, coefficient, ramification_index = p.xdata
        ta = CC(xa / coefficient).nth_root(abs(ramification_index))
        ta = ta if ramification_index > 0 else 1 / ta
        p.extend_to_t(ta)
        ya = complex(p.eval_y(ta))

        # construct the place Q and compute the path going from P0 to Q
        Q = self.riemann_surface(xa, ya)
        gamma_P0_to_Q = self.path_to_place(Q)

        # construct the path going from Q to P
        xend = complex(gamma_P0_to_Q.get_x(1.0))
        yend = array(gamma_P0_to_Q.get_y(1.0), dtype=complex)
        gamma_x = ComplexRay(xend)
        gamma_Q_to_P = RiemannSurfacePathPuiseux(self.riemann_surface, gamma_x,
                                                 yend)
        gamma = gamma_P0_to_Q + gamma_Q_to_P
        return gamma
def insert_dirichlet_L_functions(start, end):
    print "Putting Dirichlet L-functions into database."
    start = max(3, start)
    for q in range(start, end):
        print "Working on modulus", q
        sys.stdout.flush()
        G = DirichletGroup(q)
        for n in range(len(G)):
            chi = G[n]
            if chi.is_primitive():
                L = lc.Lfunction_from_character(chi)
                z = L.find_zeros_via_N(1)[0]
                Lfunction_data = {}
                Lfunction_data['first_zero'] = float(z)
                Lfunction_data[
                    'description'] = "Dirichlet L-function for character number " + str(
                        n) + " modulo " + str(q)
                Lfunction_data['degree'] = 1
                Lfunction_data['signature'] = (1, 0)
                if chi.is_odd():
                    Lfunction_data['mu'] = [
                        (1.0, 0.0),
                    ]
                else:
                    Lfunction_data['mu'] = [
                        (0.0, 0.0),
                    ]

                Lfunction_data['level'] = q

                coeffs = []

                for k in range(0, 10):
                    coeffs.append(CC(chi(k)))

                Lfunction_data['coeffs'] = [(float(x.real()), float(x.imag()))
                                            for x in coeffs]
                Lfunction_data['special'] = {
                    'type': 'dirichlet',
                    'modulus': q,
                    'number': n
                }

                Lfunctions.insert(Lfunction_data)
Beispiel #18
0
def specialValueTriple(L, s, sLatex_analytic, sLatex_arithmetic):
    ''' Returns [L_arithmetic, L_analytic, L_val]
        Currently only used for genus 2 curves
        and Dirichlet characters.
        Eventually want to use for all L-functions.
    '''
    number_of_decimals = 10
    val = None
    if hasattr(L, "lfunc_data"):
        s_alg = s + p2sage(L.lfunc_data['analytic_normalization'])
        if 'values' in L.lfunc_data.keys():
            for x in p2sage(L.lfunc_data['values']):
                # the numbers here are always half integers
                # so this comparison is exact
                if x[0] == s_alg:
                    val = x[1]
                    break
    if val is None:
        if L.fromDB:
            val = "not computed"
        else:
            val = L.sageLfunction.value(s)
    # We must test for NaN first, since it would show as zero otherwise
    # Try "RR(NaN) < float(1e-10)" in sage -- GT

    lfunction_value_tex_arithmetic = L.texname_arithmetic.replace(
        's)', sLatex_arithmetic + ')')
    lfunction_value_tex_analytic = L.texname.replace('(s',
                                                     '(' + sLatex_analytic)

    try:
        if CC(val).real().is_NaN():
            Lval = "\\infty"
        elif val.abs() < 1e-10:
            Lval = "0"
        else:
            Lval = latex(
                round(val.real(), number_of_decimals) +
                round(val.imag(), number_of_decimals) * I)
    except (TypeError, NameError):
        Lval = val  # if val is text

    return [lfunction_value_tex_analytic, lfunction_value_tex_arithmetic, Lval]
def insert_EC_L_functions(start=1, end=100):
    curves = C.ellcurves.curves
    for N in range(start, end):
        print("Processing conductor", N)
        sys.stdout.flush()
        query = curves.find({'conductor': N, 'number': 1})
        for curve in query:
            E = EllipticCurve([int(x) for x in curve['ainvs']])
            L = lc.Lfunction_from_elliptic_curve(E)
            first_zeros = L.find_zeros_via_N(curve['rank'] + 1)
            if len(first_zeros) > 1:
                if not first_zeros[-2] == 0:
                    print("problem")

            z = float(first_zeros[-1])

            Lfunction_data = {}
            Lfunction_data['first_zero'] = z
            Lfunction_data[
                'description'] = 'Elliptic curve L-function for curve ' + str(
                    curve['label'][:-1])
            Lfunction_data['degree'] = 2
            Lfunction_data['signature'] = [0, 1]
            Lfunction_data['eta'] = [
                (1.0, 0),
            ]

            Lfunction_data['level'] = N
            Lfunction_data['special'] = {
                'type': 'elliptic',
                'label': curve['label'][:-1]
            }

            coeffs = []

            for k in range(1, 11):
                coeffs.append(CC(E.an(k) / sqrt(k)))

            Lfunction_data['coeffs'] = [(float(x.real()), float(x.imag()))
                                        for x in coeffs]

            Lfunctions.insert(Lfunction_data)
Beispiel #20
0
def specialValueString(L, s, sLatex, normalization="analytic"):
    ''' Returns the LaTex to dislpay for L(s)
        Will eventually be replaced by specialValueTriple.
    '''
    number_of_decimals = 10
    val = None
    if hasattr(L, "lfunc_data"):
        s_alg = s + p2sage(L.lfunc_data['analytic_normalization'])
        for x in p2sage(L.lfunc_data['values']):
            # the numbers here are always half integers
            # so this comparison is exact
            if x[0] == s_alg:
                val = x[1]
                break
    if val is None:
        if L.fromDB:
            val = "not computed"
        else:
            val = L.sageLfunction.value(s)
    if normalization == "arithmetic":
        lfunction_value_tex = L.texname_arithmetic.replace('s)', sLatex + ')')
    else:
        lfunction_value_tex = L.texname.replace('(s', '(' + sLatex)
    # We must test for NaN first, since it would show as zero otherwise
    # Try "RR(NaN) < float(1e-10)" in sage -- GT
    if CC(val).real().is_NaN():
        return "\\[{0}=\\infty\\]".format(lfunction_value_tex)
    elif val.abs() < 1e-10:
        return "\\[{0}=0\\]".format(lfunction_value_tex)
    elif normalization == "arithmetic":
        return (lfunction_value_tex,
                latex(
                    round(val.real(), number_of_decimals) +
                    round(val.imag(), number_of_decimals) * I))
    else:
        return "\\[{0} \\approx {1}\\]".format(
            lfunction_value_tex,
            latex(
                round(val.real(), number_of_decimals) +
                round(val.imag(), number_of_decimals) * I))
Beispiel #21
0
class HyperbolicTriangleDisc(object):  #]GraphicPrimitive):
    r"""
    Hyperbolic triangles in the disc model of the hyperbolic plane.
    Note that we are given coordinates in the upper half-plane and map them to the disc.
    
    """
    @options(center=CC(0, 1))
    def __init__(self, A, B, C, **options):
        """
        Initialize HyperbolicTriangle under the map (z-z0)/(z-\bar(z0)):
        
        Examples::
        
            sage: from sage.plot.hyperbolic_triangle import HyperbolicTriangle
            sage: print HyperbolicTriangle(0, 1/2, I, {})
            Hyperbolic triangle (0.000000000000000, 0.500000000000000, 1.00000000000000*I)
        """
        A, B, C = (CC(A), CC(B), CC(C))
        self.path = []
        self._options = {}
        self._graphics = Graphics()
        self._verbose = options.pop('verbose', None)
        Z0 = options['center']  #.get('center',C(0,1))
        options.pop('center', None)
        self._npts = options.pop('npts', 10)
        sides = options.pop('sides', [1, 2, 3])
        #options.pop('fill',None)
        self._options.update(options)
        self._z0 = CC(Z0)
        self._z0bar = CC(Z0).conjugate()
        verbose = self._verbose
        sides.sort()
        if sides == [1]:
            if verbose > 0:
                print "Drawing A - B!"
            self._hyperbolic_arc_d(A, B, True)
        elif sides == [2]:
            if verbose > 0:
                print "Drawing B - C!"
            self._hyperbolic_arc_d(B, C, True)
        elif sides == [3]:
            if verbose > 0:
                print "Drawing C - A!"
            self._hyperbolic_arc_d(C, A, True)
        elif sides == [1, 2]:
            if verbose > 0:
                print "Drawing A - B! & B - C!"
            self._hyperbolic_arc_d(A, B, True)
            self._hyperbolic_arc_d(B, C, False)
        elif sides == [1, 3]:
            if verbose > 0:
                print "Drawing C - A! & A - B"
            self._hyperbolic_arc_d(C, A, True)
            self._hyperbolic_arc_d(A, B, False)
        elif sides == [2, 3]:
            if verbose > 0:
                print "Drawing B - C! & C - A"
            self._hyperbolic_arc_d(B, C, True)
            self._hyperbolic_arc_d(C, A, False)
        else:
            self._hyperbolic_arc_d(A, B, True)
            self._hyperbolic_arc_d(B, C, False)
            self._hyperbolic_arc_d(C, A, False)
        #self._hyperbolic_arc_d(A, B, True);
        #self._hyperbolic_arc_d(B, C);
        #self._hyperbolic_arc_d(C, A);
        #BezierPath.__init__(self, self.path, options)

        #super(HyperbolicTriangleDisc,self).__init__(options)
        self.A, self.B, self.C = (A, B, C)

    def _cayley_transform(self, z):
        #print "z=",z,z==infyinity,type(z),type(infinity)
        if z == infinity or z == CC(infinity):
            return CC(1, 0)
        return (CC(z) - self._z0) / (CC(z) - self._z0bar)

    def _hyperbolic_arc_d(self, z0, z3, first=False):
        """
        Function to construct Bezier path as an approximation to
        the hyperbolic arc between the complex numbers z0 and z3 in the
        hyperbolic plane.
        """

        w0 = self._cayley_transform(z0)
        w3 = self._cayley_transform(z3)
        if self._verbose > 0:
            print "in plane z0,z3=", z0, z3
            print "in disc: ", w0, w3
        npts = self._npts
        if z0 == infinity or z0 == CC(infinity):
            zm = [z3 + CC(0, j + 0.5) for j in range(npts - 2)]
            wm = [self._cayley_transform(x) for x in zm]
            pts = [w3]
            pts.extend(wm)
            pts.append(w0)
            opt = self._options
            opt['fill'] = False
            self._graphics.add_primitive(
                BezierPath([[(x.real(), x.imag()) for x in pts]], opt))
            return
        if z3 == infinity or z3 == CC(infinity):
            zm = [z0 + CC(0, j + 0.5) for j in range(npts - 2)]
            wm = [self._cayley_transform(x) for x in zm]
            pts = [w0]
            pts.extend(wm)
            pts.append(w3)
            opt = self._options
            opt['fill'] = False
            self._graphics.add_primitive(
                BezierPath([[(x.real(), x.imag()) for x in pts]], opt))
            #self._graphics.add_primitive(Line([w1.real(),w2.real()],[w1.imag(),w2.imag()],self._options))
            #self.path.append([(0,w0.imag()),CC(0,y), (0,w3.imag())])
            return
        x0 = z0.real()
        y0 = z0.imag()
        x3 = z3.real()
        y3 = z3.imag()
        if y0 == 0 and y3 == 0:
            p = (z0.real() + z3.real()) / 2
            r = abs(z0 - p)
            zm = CC(p, r)
            self._hyperbolic_arc_d(z0, zm, first)
            self._hyperbolic_arc_d(zm, z3)
            return
        else:
            if abs(x0 - x3) < 1e-10:  ## on the same vertical line
                xmid = (x0 + x3) * 0.5
                h = y3 - y0
                zm = [CC(xmid, y0 + t * h / (npts - 1)) for t in range(npts)]
            else:
                p = RR((x0 + x3) * (x3 - x0) + (y0 + y3) *
                       (y3 - y0)) / (2 * (x3 - x0))
                r = RR((p - x0)**2 + y0**2).sqrt()  # radius of the circle in H
                zm = ((z0 + z3) / 2 - p) / abs(
                    (z0 + z3) / 2 - p
                ) * r + p  # midpoint (at least approximately) of geodesic between z0 and z3
                t0 = CC(z0 - p).argument()
                t3 = CC(z3 - p).argument()
                if self._verbose > 1:
                    print "x0,x3=", x0, x3
                    print "t0,t3=", t0, t3
                    print "r=", r
                    print "opt=", self._options
                if x0 <= x3:
                    zm = [
                        p + r * CC(0, (t0 + t * (t3 - t0) / (npts - 1))).exp()
                        for t in range(npts)
                    ]
                else:
                    zm = [
                        p + r * CC(0, (t0 + t * (t3 - t0) / (npts - 1))).exp()
                        for t in range(npts)
                    ]
                #print "zm=",zm
                #zm.insert(0,z0)
                #zm.append(z3)
            pts = [self._cayley_transform(x) for x in zm]
            opt = self._options
            opt['fill'] = False
            #w0 = self._cayley_transform(z0)
            #w3 = self._cayley_transform(z3)

            if self._verbose > 2:
                print "pts=", pts
            self._graphics.add_primitive(
                BezierPath([[(x.real(), x.imag()) for x in pts]], opt))
            return
            #print "z0_test=",(p+r*exp(t0*I))
            #print "z3_test=",(p+r*exp(t3*I))
            #t = (8*zm-4*(z0+z3)).imag()/3/(z3-z0).real()
            # I have no idea what these points should represent....
            #z1 = z0 + t*CC(z0.imag(), (p-z0.real()))
            #z2 = z3 - t*CC(z3.imag(), (p-z3.real()))
            wm = [self._cayley_transform(x) for x in zm]
            pp = self._cayley_transform(CC(p, 0))
            w1 = self._cayley_transform(z0)
            w2 = self._cayley_transform(z3)
            c = self._cayley_transform(CC(
                p, 0))  # center of circle on the unit disk.
            if self._verbose > 2:
                print "p,r=", p, r
                print "zm=", zm
                #print "t=",t
                #print "tt=",(8*zm-4*(z0+z3)).imag()/3/(z3-z0).real()

                print "C(c)=", pp
                print "C(zm)=", wm
                print "C(z0)=", w1
                print "C(z3)=", w2
                #print "z2=",z2

            r = abs(w1 - c)  # radius
            t0 = CC(w0 - pp).argument()
            t3 = CC(w3 - pp).argument()
            t = abs(t0 - t3)
        if self._verbose > 0:
            print "adding a:rc ", zm.real(), zm.imag(), r, r, t, t0, t3
        self._graphics.add_primitive(
            Line([w1.real(), w2.real(), wm.real()],
                 [w1.imag(), w2.imag(), wm.imag()], {
                     'thickness': 2,
                     'alpha': 1,
                     'rgbcolor': 'blue',
                     'legend_label': ""
                 }))
        self._graphics.add_primitive(
            Point(
                [w1.real(), w2.real(), wm.real()],
                [w1.imag(), w2.imag(), wm.imag()], {
                    'size': 10,
                    'alpha': 1,
                    'faceted': True,
                    'rgbcolor': 'red',
                    'legend_label': ""
                }))

        #self._graphics.add_primitive(Arc(pp.real(),pp.imag(),r,r,t,t0,t3,self._options))
        #self._graphics. Arc(zm.real(),zm.imag(),r,r,abs(t),-abs(t),abs(t),self._options)

    def __call__(self):
        return self._graphics
Beispiel #22
0
def signtocolour(sign):
    argument = cmath.phase(CC(str(sign)))
    r = int(255.0 * (math.cos((1.0 * math.pi / 3.0) - (argument / 2.0))) ** 2)
    g = int(255.0 * (math.cos((2.0 * math.pi / 3.0) - (argument / 2.0))) ** 2)
    b = int(255.0 * (math.cos(argument / 2.0)) ** 2)
    return("rgb(" + str(r) + "," + str(g) + "," + str(b) + ")")
def add_trace_and_norm_ladic(g, D, alpha_geo, verbose=True):
    if verbose:
        print "add_trace_and_norm_ladic()"
    #load Fields
    L = D['L']
    if L is QQ:
        QQx = PolynomialRing(QQ, "x")
        L = NumberField(QQx.gen(), "b")

    prec = D['prec']
    CCap = ComplexField(prec)

    # load endo
    alpha = D['alpha']
    rosati = bound_rosati(alpha_geo)

    if alpha.base_ring() is not L:
        alpha_K = copy(alpha)
        alpha = Matrix(L, 2, 2)
        #shift alpha field from K to L
        for i, row in enumerate(alpha_K.rows()):
            for j, elt in enumerate(row):
                if elt not in L:
                    assert elt.base_ring().absolute_polynomial(
                    ) == L.absolute_polynomial()
                    alpha[i, j] = L(elt.list())
                else:
                    alpha[i, j] = L(elt)

    # load algx_poly
    algx_poly_coeff = D['algx_poly']

    #sometimes, by mistake the algx_poly is defined over K where K == L, but with a different name
    for i, elt in enumerate(algx_poly_coeff):
        if elt not in L:
            assert elt.base_ring().absolute_polynomial(
            ) == L.absolute_polynomial()
            algx_poly_coeff[i] = L(elt.list())
        else:
            algx_poly_coeff[i] = L(elt)

    x_poly = vector(CCap, D['x_poly'])
    for i in [0, 1]:
        assert almost_equal(
            x_poly[i],
            algx_poly_coeff[i]), "%s != %s" % (algx_poly_coeff[i], x_poly[i])

    # load P
    P0 = vector(L, [D['P'][0], D['P'][1]])
    for i, elt in enumerate(P0):
        if elt not in L:
            assert elt.base_ring().absolute_polynomial(
            ) == L.absolute_polynomial()
            P0[i] = L(elt.list())
        else:
            P0[i] = L(elt)
    if verbose:
        print "P0 = %s" % (P0, )

    # load image points, P1 and P2

    L_poly = PolynomialRing(L, "xL")
    xL = L_poly.gen()

    Xpoly = L_poly(algx_poly_coeff)
    if Xpoly.is_irreducible():
        M = Xpoly.root_field("c")
    else:
        # this avoids bifurcation later on in the code, we don't want to be always checking if M is L
        M = NumberField(xL, "c")

    # trying to be sure that we keep the same complex_embedding...
    M_complex_embedding = 0
    if L.gen() not in QQ:
        M_complex_embedding = None
        Lgen_CC = toCCap(L.gen(), prec=prec)
        for i, _ in enumerate(M.complex_embeddings()):
            if norm(Lgen_CC - M(L.gen()).complex_embedding(prec=prec, i=i)
                    ) < CCap(2)**(-0.7 * Lgen_CC.prec()) * Lgen_CC.abs():
                M_complex_embedding = i

        assert M_complex_embedding is not None, "\nL = %s\n%s = %s\n%s" % (
            L, L.gen(), Lgen_CC, M.complex_embeddings())

    M_poly = PolynomialRing(M, "xM")
    xM = M_poly.gen()

    # convert everything to M
    P0_M = vector(M, [elt for elt in P0])
    alpha_M = Matrix(M, [[elt for elt in row] for row in alpha.rows()])
    Xpoly_M = M_poly(Xpoly)

    for i in [0, 1]:
        assert almost_equal(x_poly[i],
                            Xpoly_M.list()[i],
                            ithcomplex_embedding=M_complex_embedding
                            ), "%s != %s" % (Xpoly_M.list()[i], x_poly[i])

    P1 = vector(M, 2)
    P1_ap = vector(CCap, D['R'][0])
    P2 = vector(M, 2)
    P2_ap = vector(CCap, D['R'][1])

    M_Xpoly_roots = Xpoly_M.roots()
    assert len(M_Xpoly_roots) > 0

    Ypoly_M = prod([xM**2 - g(root)
                    for root, _ in M_Xpoly_roots])  # also \in L_poly

    assert sum(m for _, m in Ypoly_M.roots(M)) == Ypoly_M.degree(
    ), "%s != %s\n%s\n%s" % (sum(m for _, m in Ypoly_M.roots(M)),
                             Ypoly_M.degree(), Ypoly_M, Ypoly_M.roots(M))

    if len(M_Xpoly_roots) == 1:
        # we have a double root
        P1[0] = M_Xpoly_roots[0][0]
        P2[0] = M_Xpoly_roots[0][0]
        ae_prec = prec * 0.4
    else:
        assert len(M_Xpoly_roots) == 2
        ae_prec = prec
        # we have two distinct roots
        P1[0] = M_Xpoly_roots[0][0]
        P2[0] = M_Xpoly_roots[1][0]
        if not_equal(P1_ap[0], P1[0],
                     ithcomplex_embedding=M_complex_embedding):
            P1[0] = M_Xpoly_roots[1][0]
            P2[0] = M_Xpoly_roots[0][0]

    assert almost_equal(
        P1_ap[0],
        P1[0],
        ithcomplex_embedding=M_complex_embedding,
        prec=ae_prec), "\n%s = %s \n != %s" % (
            P1[0], toCCap(
                P1[0], ithcomplex_embedding=M_complex_embedding), CC(P1_ap[0]))
    assert almost_equal(
        P2_ap[0],
        P2[0],
        ithcomplex_embedding=M_complex_embedding,
        prec=ae_prec), "\n%s = %s \n != %s" % (
            P2[0], toCCap(
                P2[0], ithcomplex_embedding=M_complex_embedding), CC(P2_ap[0]))

    # figure out the right square root

    # pick the default branch
    P1[1] = sqrt(g(P1[0]))
    P2[1] = sqrt(g(P2[0]))

    if 0 in [P1[1], P2[1]]:
        print "one of image points is a Weirstrass point"
        print P1
        print P2
        raise ZeroDivisionError

    #switch if necessary
    if not_equal(P1_ap[1],
                 P1[1],
                 ithcomplex_embedding=M_complex_embedding,
                 prec=ae_prec):
        P1[1] *= -1

    if not_equal(P2_ap[1],
                 P2[1],
                 ithcomplex_embedding=M_complex_embedding,
                 prec=ae_prec):
        P2[1] *= -1

    # double check
    for i in [0, 1]:
        assert almost_equal(P1_ap[i],
                            P1[i],
                            ithcomplex_embedding=M_complex_embedding,
                            prec=ae_prec), "%s != %s" % (P1_ap[i], P1[i])
        assert almost_equal(P2_ap[i],
                            P2[i],
                            ithcomplex_embedding=M_complex_embedding,
                            prec=ae_prec), "%s != %s" % (P2_ap[i], P2[i])

    # now alpha, P0 \in L
    # P1, P2 \in L

    if verbose:
        print "P1 = %s\nP2 = %s" % (P1, P2)
        print "Computing the trace and the norm ladically\n"
        trace_and_norm = trace_and_norm_ladic(L,
                                              M,
                                              P0_M,
                                              P1,
                                              P2,
                                              g,
                                              2 * alpha_M,
                                              16 * rosati,
                                              primes=ceil(prec * L.degree() /
                                                          61))
    else:
        trace_and_norm = trace_and_norm_ladic(L,
                                              M,
                                              P0_M,
                                              P1,
                                              P2,
                                              g,
                                              2 * alpha_M,
                                              16 * rosati,
                                              primes=ceil(prec * L.degree() /
                                                          61))

    # Convert the coefficients to polynomials
    trace_numerator, trace_denominator, norm_numerator, norm_denominator = [
        L_poly(coeff) for coeff in trace_and_norm
    ]

    assert trace_numerator(P0[0]) == trace_denominator(
        P0[0]) * -algx_poly_coeff[1], "%s/%s (%s) != %s" % (
            trace_numerator, trace_denominator, P0[0], -algx_poly_coeff[1])
    assert norm_numerator(P0[0]) == norm_denominator(
        P0[0]) * algx_poly_coeff[0], "%s/%s (%s) != %s" % (
            norm_numerator, norm_denominator, P0[0], algx_poly_coeff[0])
    buffer = "# x1 + x2 = degree %d/ degree %d\n" % (
        trace_numerator.degree(), trace_denominator.degree())
    buffer += "# = (%s) / (%s) \n" % (trace_numerator, trace_denominator)
    buffer += "# max(%d, %d) <= %d\n\n" % (
        trace_numerator.degree(), trace_denominator.degree(), 16 * rosati)

    buffer += "# x1 * x2 = degree %d/ degree %d\n" % (
        norm_numerator.degree(), norm_denominator.degree())
    buffer += "# = (%s) / (%s) \n" % (norm_numerator, norm_denominator)
    buffer += "# max(%d, %d) <= %d\n" % (
        norm_numerator.degree(), norm_denominator.degree(), 16 * rosati)

    if verbose:
        print buffer
        print "\n"
    assert max(trace_numerator.degree(),
               trace_denominator.degree()) <= 16 * rosati
    assert max(norm_numerator.degree(),
               norm_denominator.degree()) <= 16 * rosati

    if verbose:
        print "Veritfying if x1*x2 and x1 + x2 are correct..."

    verified = verify_algebraically(g,
                                    P0,
                                    alpha,
                                    trace_and_norm,
                                    verbose=verbose)
    if verbose:
        print "\nDoes it act on the tangent space as expected? %s\n" % verified
        print "Done add_trace_and_norm_ladic()"

    return verified, [
        trace_numerator.list(),
        trace_denominator.list(),
        norm_numerator.list(),
        norm_denominator.list()
    ]
Beispiel #24
0
 def set_table(self, fnr=-1, cusp=0, prec=9):
     r"""
     Setup a table with coefficients for function nr. fnr in self,
     at cusp nr. cusp. If the real or imaginary parts are less than
     1e-`prec`, then set them to zero.
     """
     table = {'nrows': self.num_coeff}
     if fnr < 0:
         colrange = range(self.dim)
         table['ncols'] = self.dim + 1
     elif fnr < self.dim:
         colrange = [fnr]
         table['ncols'] = 2
     table['data'] = []
     table['negc'] = 0
     realnumc = 0
     if self.num_coeff == 0:
         self.table = table
         return
     if self.symmetry != -1:
         for n in range(self.num_coeff):
             row = [n]
             for k in colrange:
                 if self.dim == 1:
                     c = None
                     try:
                         c = self.coeffs[k][cusp].get(n, None)
                     except (KeyError, IndexError):
                         mwf_logger.critical(
                             "Got coefficient in wrong format for id={0}".format(self._maassid))
                     # mwf_logger.debug("{0},{1}".format(k,c))
                     if c is not None:
                         realnumc += 1
                         row.append(pretty_coeff(c, prec=prec))
                 else:
                     for j in range(self.dim):
                         c = ((self.coeffs.get(j, {})).get(0, {})).get(n, None)
                         if c is not None:
                             row.append(pretty_coeff(c, prec=prec))
                             realnumc += 1
             table['data'].append(row)
     else:
         table['negc'] = 1
         # in this case we need to have coeffs as dict.
         if not isinstance(self.coeffs, dict):
             self.table = {}
             return
         for n in range(len(self.coeffs.keys() / 2)):
             row = [n]
             if self.dim == 1:
                 for k in range(table['ncols']):
                     #cpositive and cnegative
                     cp = self.coeffs.get(n, 0)
                     cn = self.coeffs.get(-n, 0)
                     row.append((cp, cn))
                     realnumc += 1
             else:
                 for j in range(self.dim):
                     c = (self.coeffs.get(j, {})).get(n, None)
                     if c is not None:
                         c1 = c.get(n, None)
                         cn1 = c.get(-n, None)
                         c1 = CC(c1)
                         cn1 = CC(cn1)
                         row.append((c1, cn1))
                         realnumc += 1
                     table['data'].append(row)
     self.table = table
     mwf_logger.debug("realnumc={0}".format(realnumc))
Beispiel #25
0
def build_connected_path(P, **kwds):
    from sage.all import deepcopy, hyperbolic_arc
    paths = []
    ymax = P._axes_range.get('ymax', kwds.get('ymax', 10000))
    xmax = P._axes_range.get('xmax', kwds.get('xmax', 0))
    xmin = P._axes_range.get('xmin', kwds.get('xmin', 0))
    new_paths = []
    if len(P) == 1:  ### SL2Z
        A = P[0].A
        B = P[0].B
        C = P[0].C
        new_paths = [
            hyperbolic_arc(CC(A), CC(B))[0],
            hyperbolic_arc(CC(B), CC(C))[0],
            hyperbolic_arc(CC(C), CC(A))[0]
        ]
    else:
        for x in P:
            if x.A.imag() >= 10000:
                ### these have to be treated specially..
                ### We truncate to the maximum y height
                ### and set the x-coordinate to the same as the other endpoint.
                A = CC(x.B.real(), ymax)
                B = CC(x.B.real(), x.B.imag())
                paths.append(hyperbolic_arc(A, B)[0])
                xmin = x.B.real()
            elif x.B.imag() >= 10000:
                ### these have to be treated specially..
                ### We truncate to the maximum y height
                ### and set the x-coordinate to the same as the other endpoint.
                A = CC(x.A.real(), x.A.imag())
                B = CC(x.A.real(), ymax)
                paths.append(hyperbolic_arc(A, B)[0])
                xmax = x.A.real()
            else:
                paths.append(x)
        ## Add a 'closing' path between the two vertical sides.
        paths.append(hyperbolic_arc(CC(xmin, ymax), CC(xmax, ymax))[0])
        ## first find the left most:
        ## an arc has a .A and .B
        As = [x.A for x in P]
        minA = min(As)
        mini = As.index(minA)
        new_paths = [P[mini]]
        paths.remove(P[mini])
        eps = 1e-15
        current = P[mini].B
        while paths != []:
            current = new_paths[-1].B
            #print "current=",current
            try:
                for p in paths:
                    #print "p.A=",p.A
                    #print "p.B=",p.B
                    if abs(p.A - current) < eps:
                        #print "appending p"
                        new_paths.append(p)
                        paths.remove(p)
                        raise StopIteration
                    elif abs(p.B - current) < eps:  ## we reverse it
                        #print "appending p reversed"
                        pnew = hyperbolic_arc(p.B, p.A)
                        new_paths.append(pnew[0])
                        paths.remove(p)
                        raise StopIteration
                    else:
                        continue

                print paths
                raise ArithmeticError(
                    "Could not connect from {0}".format(current))
            except StopIteration:
                pass
    ### new paths is now a list of hyperbolic arcs
    res = []
    import matplotlib.patches as patches
    from matplotlib.path import Path
    import numpy
    i = 0
    vertices = []
    codes = []
    for p in new_paths:
        new_codes = p.codes
        if i > 0:
            new_codes[0] = 2
        i += 1
        if i == len(new_paths):
            new_codes[-1] = 79
        for v in p.vertices:
            vertices.append(v)
        codes = codes + new_codes
        #pt = patches.Path(p.vertices,codes)
        #res.append(pt)
    vertices = numpy.array(vertices, float)
    res = path = Path(vertices, codes)

    #    res = patches.Path.make_compound_path(*res)
    return res
Beispiel #26
0
 def _cayley_transform(self, z):
     #print "z=",z,z==infyinity,type(z),type(infinity)
     if z == infinity or z == CC(infinity):
         return CC(1, 0)
     return (CC(z) - self._z0) / (CC(z) - self._z0bar)
Beispiel #27
0
def _geodesic_between_two_points_d(x1, y1, x2, y2, z0=I):
    r""" Geodesic path between two points represented in the unit disc
         by the map w = (z-I)/(z+I)
    INPUTS:
    - ''(x1,y1)'' -- starting point (0<y1<=infinity)
    - ''(x2,y2)'' -- ending point   (0<y2<=infinity)
    - ''z0''  -- (default I) the point in the upper corresponding
                 to the point 0 in the disc. I.e. the transform is
                 w -> (z-I)/(z+I)
    OUTPUT:
    - ''ca'' -- a polygonal approximation of a circular arc centered
    at c and radius r, starting at t0 and ending at t1

    
    EXAMPLES::

        sage: l=_geodesic_between_two_points_d(0.1,0.2,0.0,0.5)
    
    """
    pi = RR.pi()
    from sage.plot.plot import line
    from sage.functions.trig import (cos, sin)
    # First compute the points
    if (y1 < 0 or y2 < 0):
        raise ValueError, "Need points in the upper half-plane! Got y1=%s, y2=%s" % (
            y1, y2)
    if (y1 == infinity):
        P1 = CC(1)
    else:
        P1 = CC((x1 + I * y1 - z0) / (x1 + I * y1 - z0.conjugate()))
    if (y2 == infinity):
        P2 = CC(1)
    else:
        P2 = CC((x2 + I * y2 - z0) / (x2 + I * y2 - z0.conjugate()))
        # First find the endpoints of the completed geodesic in D
    if (x1 == x2):
        a = CC((x1 - z0) / (x1 - z0.conjugate()))
        b = CC(1)
    else:
        c = RR(y1**2 - y2**2 + x1**2 - x2**2) / RR(2 * (x1 - x2))
        r = RR(sqrt(y1**2 + (x1 - c)**2))
        a = c - r
        b = c + r
        a = CC((a - z0) / (a - z0.conjugate()))
        b = CC((b - z0) / (b - z0.conjugate()))
    if (abs(a + b) < 1E-10):  # On a diagonal
        return line([[P1.real(), P1.imag()], [P2.real(), P2.imag()]])
    th_a = a.argument()
    th_b = b.argument()
    # Compute the center of the circle in the disc model
    if (min(abs(b - 1), abs(b + 1)) < 1E-10
            and min(abs(a - 1), abs(a + 1)) > 1E-10):
        c = b + I * (1 - b * cos(th_a)) / sin(th_a)
    elif (min(abs(b - 1), abs(b + 1)) > 1E-10
          and min(abs(a - 1), abs(a + 1)) < 1E-10):
        c = a + I * (1 - a * cos(th_b)) / RR(sin(th_b))
    else:
        cx = (sin(th_b) - sin(th_a)) / sin(th_b - th_a)
        c = cx + I * (1 - cx * cos(th_b)) / RR(sin(th_b))
    # First find the endpoints of the completed geodesic
    r = abs(c - a)
    t1 = CC(P1 - c).argument()
    t2 = CC(P2 - c).argument()
    #print "t1,t2=",t1,t2
    return _circ_arc(t1, t2, c, r)
Beispiel #28
0
    def _hyperbolic_arc_d(self, z0, z3, first=False):
        """
        Function to construct Bezier path as an approximation to
        the hyperbolic arc between the complex numbers z0 and z3 in the
        hyperbolic plane.
        """

        w0 = self._cayley_transform(z0)
        w3 = self._cayley_transform(z3)
        if self._verbose > 0:
            print "in plane z0,z3=", z0, z3
            print "in disc: ", w0, w3
        npts = self._npts
        if z0 == infinity or z0 == CC(infinity):
            zm = [z3 + CC(0, j + 0.5) for j in range(npts - 2)]
            wm = [self._cayley_transform(x) for x in zm]
            pts = [w3]
            pts.extend(wm)
            pts.append(w0)
            opt = self._options
            opt['fill'] = False
            self._graphics.add_primitive(
                BezierPath([[(x.real(), x.imag()) for x in pts]], opt))
            return
        if z3 == infinity or z3 == CC(infinity):
            zm = [z0 + CC(0, j + 0.5) for j in range(npts - 2)]
            wm = [self._cayley_transform(x) for x in zm]
            pts = [w0]
            pts.extend(wm)
            pts.append(w3)
            opt = self._options
            opt['fill'] = False
            self._graphics.add_primitive(
                BezierPath([[(x.real(), x.imag()) for x in pts]], opt))
            #self._graphics.add_primitive(Line([w1.real(),w2.real()],[w1.imag(),w2.imag()],self._options))
            #self.path.append([(0,w0.imag()),CC(0,y), (0,w3.imag())])
            return
        x0 = z0.real()
        y0 = z0.imag()
        x3 = z3.real()
        y3 = z3.imag()
        if y0 == 0 and y3 == 0:
            p = (z0.real() + z3.real()) / 2
            r = abs(z0 - p)
            zm = CC(p, r)
            self._hyperbolic_arc_d(z0, zm, first)
            self._hyperbolic_arc_d(zm, z3)
            return
        else:
            if abs(x0 - x3) < 1e-10:  ## on the same vertical line
                xmid = (x0 + x3) * 0.5
                h = y3 - y0
                zm = [CC(xmid, y0 + t * h / (npts - 1)) for t in range(npts)]
            else:
                p = RR((x0 + x3) * (x3 - x0) + (y0 + y3) *
                       (y3 - y0)) / (2 * (x3 - x0))
                r = RR((p - x0)**2 + y0**2).sqrt()  # radius of the circle in H
                zm = ((z0 + z3) / 2 - p) / abs(
                    (z0 + z3) / 2 - p
                ) * r + p  # midpoint (at least approximately) of geodesic between z0 and z3
                t0 = CC(z0 - p).argument()
                t3 = CC(z3 - p).argument()
                if self._verbose > 1:
                    print "x0,x3=", x0, x3
                    print "t0,t3=", t0, t3
                    print "r=", r
                    print "opt=", self._options
                if x0 <= x3:
                    zm = [
                        p + r * CC(0, (t0 + t * (t3 - t0) / (npts - 1))).exp()
                        for t in range(npts)
                    ]
                else:
                    zm = [
                        p + r * CC(0, (t0 + t * (t3 - t0) / (npts - 1))).exp()
                        for t in range(npts)
                    ]
                #print "zm=",zm
                #zm.insert(0,z0)
                #zm.append(z3)
            pts = [self._cayley_transform(x) for x in zm]
            opt = self._options
            opt['fill'] = False
            #w0 = self._cayley_transform(z0)
            #w3 = self._cayley_transform(z3)

            if self._verbose > 2:
                print "pts=", pts
            self._graphics.add_primitive(
                BezierPath([[(x.real(), x.imag()) for x in pts]], opt))
            return
            #print "z0_test=",(p+r*exp(t0*I))
            #print "z3_test=",(p+r*exp(t3*I))
            #t = (8*zm-4*(z0+z3)).imag()/3/(z3-z0).real()
            # I have no idea what these points should represent....
            #z1 = z0 + t*CC(z0.imag(), (p-z0.real()))
            #z2 = z3 - t*CC(z3.imag(), (p-z3.real()))
            wm = [self._cayley_transform(x) for x in zm]
            pp = self._cayley_transform(CC(p, 0))
            w1 = self._cayley_transform(z0)
            w2 = self._cayley_transform(z3)
            c = self._cayley_transform(CC(
                p, 0))  # center of circle on the unit disk.
            if self._verbose > 2:
                print "p,r=", p, r
                print "zm=", zm
                #print "t=",t
                #print "tt=",(8*zm-4*(z0+z3)).imag()/3/(z3-z0).real()

                print "C(c)=", pp
                print "C(zm)=", wm
                print "C(z0)=", w1
                print "C(z3)=", w2
                #print "z2=",z2

            r = abs(w1 - c)  # radius
            t0 = CC(w0 - pp).argument()
            t3 = CC(w3 - pp).argument()
            t = abs(t0 - t3)
        if self._verbose > 0:
            print "adding a:rc ", zm.real(), zm.imag(), r, r, t, t0, t3
        self._graphics.add_primitive(
            Line([w1.real(), w2.real(), wm.real()],
                 [w1.imag(), w2.imag(), wm.imag()], {
                     'thickness': 2,
                     'alpha': 1,
                     'rgbcolor': 'blue',
                     'legend_label': ""
                 }))
        self._graphics.add_primitive(
            Point(
                [w1.real(), w2.real(), wm.real()],
                [w1.imag(), w2.imag(), wm.imag()], {
                    'size': 10,
                    'alpha': 1,
                    'faceted': True,
                    'rgbcolor': 'red',
                    'legend_label': ""
                }))
Beispiel #29
0
def check_amn_slow(rec):
    Z = [0] + [CC(*elt) for elt in rec['an_normalized[0:1000]']]
    for m, n in pairs:
        if (Z[m * n] - Z[m] * Z[n]).abs() > 1e-11:
            return False
    return True
Beispiel #30
0
    def __init__(self, A, B, C, **options):
        """
        Initialize HyperbolicTriangle under the map (z-z0)/(z-\bar(z0)):
        
        Examples::
        
            sage: from sage.plot.hyperbolic_triangle import HyperbolicTriangle
            sage: print HyperbolicTriangle(0, 1/2, I, {})
            Hyperbolic triangle (0.000000000000000, 0.500000000000000, 1.00000000000000*I)
        """
        A, B, C = (CC(A), CC(B), CC(C))
        self.path = []
        self._options = {}
        self._graphics = Graphics()
        self._verbose = options.pop('verbose', None)
        Z0 = options['center']  #.get('center',C(0,1))
        options.pop('center', None)
        self._npts = options.pop('npts', 10)
        sides = options.pop('sides', [1, 2, 3])
        #options.pop('fill',None)
        self._options.update(options)
        self._z0 = CC(Z0)
        self._z0bar = CC(Z0).conjugate()
        verbose = self._verbose
        sides.sort()
        if sides == [1]:
            if verbose > 0:
                print "Drawing A - B!"
            self._hyperbolic_arc_d(A, B, True)
        elif sides == [2]:
            if verbose > 0:
                print "Drawing B - C!"
            self._hyperbolic_arc_d(B, C, True)
        elif sides == [3]:
            if verbose > 0:
                print "Drawing C - A!"
            self._hyperbolic_arc_d(C, A, True)
        elif sides == [1, 2]:
            if verbose > 0:
                print "Drawing A - B! & B - C!"
            self._hyperbolic_arc_d(A, B, True)
            self._hyperbolic_arc_d(B, C, False)
        elif sides == [1, 3]:
            if verbose > 0:
                print "Drawing C - A! & A - B"
            self._hyperbolic_arc_d(C, A, True)
            self._hyperbolic_arc_d(A, B, False)
        elif sides == [2, 3]:
            if verbose > 0:
                print "Drawing B - C! & C - A"
            self._hyperbolic_arc_d(B, C, True)
            self._hyperbolic_arc_d(C, A, False)
        else:
            self._hyperbolic_arc_d(A, B, True)
            self._hyperbolic_arc_d(B, C, False)
            self._hyperbolic_arc_d(C, A, False)
        #self._hyperbolic_arc_d(A, B, True);
        #self._hyperbolic_arc_d(B, C);
        #self._hyperbolic_arc_d(C, A);
        #BezierPath.__init__(self, self.path, options)

        #super(HyperbolicTriangleDisc,self).__init__(options)
        self.A, self.B, self.C = (A, B, C)