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
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))
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]
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
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])
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) + ")")
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]
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)"
def is_number(a): if isinstance(a, (int, float, long, complex, sage.rings.all.CommutativeRingElement)): return True elif hasattr(a, 'parent'): numgen = sage.rings.number_field.number_field.NumberField_generic parent = a.parent() return CC.has_coerce_map_from(parent) or \ isinstance(parent, numgen) or \ (hasattr(parent, "is_field") and hasattr(parent, "is_finite") and parent.is_field() and parent.is_finite()) else: return False
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 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
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)
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)
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 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))
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 w0.real()==0 and w3.real() == 0: y = (w0.imag() + w0.imag())/2 #self.path.append([(0,w0.imag()),CC(0,y), (0,w3.imag())]) self._graphics.add_primitive(BezierPath([(0,w0.imag()),CC(0,y), (0,w3.imag())],self._options)) return z0,z3 = CC(z0), CC(z3) if z0.imag() == 0 and z3.imag() == 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: p = (abs(z0)*abs(z0)-abs(z3)*abs(z3))/(z0-z3).real()/2 # center of the circle in H r = abs(z0-p) # radius of the circle in H zm = ((z0+z3)/2-p)/abs((z0+z3)/2-p)*r+p t = (8*zm-4*(z0+z3)).imag()/3/(z3-z0).real() z1 = z0 + t*CC(z0.imag(), (p-z0.real())) z2 = z3 - t*CC(z3.imag(), (p-z3.real())) zm = self._cayley_transform(zm) w1 = self._cayley_transform(z1) w2 = self._cayley_transform(z2) c = self._cayley_transform(CC(p,0)) # center of circle on the unit disk. r = abs(w1-c) # radius theta = t self._graphics.add_primitive(Arc((zm.real(),zm.imag()),r,sector=(-t,t),options=self._options))
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
def gaussum(n, N, prec=53): CC = ComplexField(prec) return sum(CC(exp(2 * CC.pi() * CC(0, 1) * n * m ** 2 / N)) for m in range(N))
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() ]
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)
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':""}))
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 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))
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
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
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))
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)
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': "" }))
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)