def _hyperbolic_arc(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. """ z0, z3 = (CC(z0), CC(z3)) p = (abs(z0)*abs(z0)-abs(z3)*abs(z3))/(z0-z3).real()/2 r = abs(z0-p) if abs(z3-z0)/r < 0.1: self.path.append([(z0.real(),z0.imag()), (z3.real(),z3.imag())]) return if z0.imag() == 0 and z3.imag() == 0: p = (z0.real()+z3.real())/2 zm = CC(p, r) self._hyperbolic_arc(z0, zm, first) self._hyperbolic_arc(zm, z3) return else: 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())) if first: self.path.append([(z0.real(), z0.imag()), (z1.real(), z1.imag()), (z2.real(), z2.imag()), (z3.real(), z3.imag())]) first = False else: self.path.append([(z1.real(), z1.imag()), (z2.real(), z2.imag()), (z3.real(), z3.imag())])
def __init__(self, A, B, options): A, B = (CC(A), CC(B)) if A.imag()<0: raise ValueError("%s is not a valid point in the UHP model"%(A)) if B.imag()<0: raise ValueError("%s is not a valid point in the UHP model"%(B)) self.path = [] self._hyperbolic_arc(A, B, True) BezierPath.__init__(self, self.path, options) self.A, self.B = (A, B)
def boundary_point_in_model(self, p): r""" Check whether a complex number is a real number or ``\infty``. In the ``UHP.model_name_name``, this is the ideal boundary of hyperbolic space. EXAMPLES:: sage: UHP = HyperbolicPlane().UHP() sage: UHP.boundary_point_in_model(1 + I) False sage: UHP.boundary_point_in_model(infinity) True sage: UHP.boundary_point_in_model(CC(infinity)) True sage: UHP.boundary_point_in_model(RR(infinity)) True sage: UHP.boundary_point_in_model(1) True sage: UHP.boundary_point_in_model(12) True sage: UHP.boundary_point_in_model(1 - I) False sage: UHP.boundary_point_in_model(-2*I) False sage: UHP.boundary_point_in_model(0) True sage: UHP.boundary_point_in_model(I) False """ if isinstance(p, HyperbolicPoint): return p.is_boundary() im = abs(imag(CC(p)).n()) return (im < EPSILON) or bool(p == infinity)
def point_in_model(self, p): r""" Check whether a complex number lies in the open upper half plane. EXAMPLES:: sage: UHP = HyperbolicPlane().UHP() sage: UHP.point_in_model(1 + I) True sage: UHP.point_in_model(infinity) False sage: UHP.point_in_model(CC(infinity)) False sage: UHP.point_in_model(RR(infinity)) False sage: UHP.point_in_model(1) False sage: UHP.point_in_model(12) False sage: UHP.point_in_model(1 - I) False sage: UHP.point_in_model(-2*I) False sage: UHP.point_in_model(I) True sage: UHP.point_in_model(0) # Not interior point False """ if isinstance(p, HyperbolicPoint): return p.is_boundary() return bool(imag(CC(p)) > 0)
def fft(self): """ Wraps the gsl ``FastFourierTransform.forward()`` in :mod:`~sage.calculus.transforms.fft`. If the length is a power of 2 then this automatically uses the radix2 method. If the number of sample points in the input is a power of 2 then the wrapper for the GSL function ``gsl_fft_complex_radix2_forward()`` is automatically called. Otherwise, ``gsl_fft_complex_forward()`` is used. EXAMPLES:: sage: J = list(range(5)) sage: A = [RR(1) for i in J] sage: s = IndexedSequence(A,J) sage: t = s.fft(); t Indexed sequence: [5.00000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000] indexed by [0, 1, 2, 3, 4] """ from sage.rings.cc import CC I = CC.gen() # elements must be coercible into RR J = self.index_object() ## must be = range(N) N = len(J) S = self.list() a = FastFourierTransform(N) for i in range(N): a[i] = S[i] a.forward_transform() return IndexedSequence([a[j][0] + I * a[j][1] for j in J], J)
def get_classified_solution_dicts(output_file_contents, input_ring, get_failures=True): """ Return a dictionary of lists of dictionaries of variable:value (key:value) pairs. Only used internally; see the classified_solution_dict function in the PHC_Object class definition for details. INPUT: - output_file_contents -- phc solution output as a string - input_ring -- a PolynomialRing that variable names can be coerced into OUTPUT: - a dictionary of lists if dictionaries of solutions, classifies by type EXAMPLES:: sage: from sage.interfaces.phc import * sage: R2.<x1,x2> = PolynomialRing(QQ,2) sage: test_sys = [(x1-2)^5-x2, (x2-1)^5-1] sage: sol = phc.blackbox(test_sys, R2) # optional -- phc sage: sol_classes = get_classified_solution_dicts(sol.output_file_contents,R2) # optional -- phc sage: len(sol_classes['real']) # optional -- phc 1 """ output_list = output_file_contents.splitlines() solution_dicts = {} solution_types = ['complex', 'real', 'failure'] for sol_type in solution_types: solution_dicts[sol_type] = [] for solution_line in range(len(output_list) - 1, -1, -1): if output_list[solution_line].find('THE SOLUTIONS') == 0: break var_number = int(output_list[solution_line + 2].split(' ')[1]) # sol_number = int(output_list[solution_line+2].split(' ')[0]) for i in range(solution_line + 1, len(output_list)): if output_list[i].count('the solution for t') == 1: phc_type = output_list[i + var_number + 1].split(' = ')[-1] if phc_type.find('complex') != -1: phc_type = 'complex' elif phc_type.find('real') != -1: phc_type = 'real' else: phc_type = 'failure' temp_dict = {} for j in range(1, var_number + 1): rawsplit = output_list[i + j].split(': ')[1].split(' ') for extras in range(rawsplit.count('')): rawsplit.remove('') temp_var = output_list[i + j].split(': ')[0].replace(' ', '') if phc_type == 'real': temp_dict[input_ring(temp_var)] = RR(rawsplit[0]) else: temp_dict[input_ring(temp_var)] = CC( rawsplit[0], rawsplit[1]) solution_dicts[phc_type].append(temp_dict) return solution_dicts
def _evalf_(self, x, **kwargs): """ EXAMPLES:: sage: from sage.functions.airy import airy_ai_simple sage: airy_ai_simple(0.0) 0.355028053887817 sage: airy_ai_simple(1.0 * I) 0.331493305432141 - 0.317449858968444*I We can use several methods for numerical evaluation:: sage: airy_ai_simple(3).n(algorithm='mpmath') 0.00659113935746072 sage: airy_ai_simple(3).n(algorithm='mpmath', prec=100) 0.0065911393574607191442574484080 sage: airy_ai_simple(3).n(algorithm='scipy') # rel tol 1e-10 0.006591139357460719 sage: airy_ai_simple(I).n(algorithm='scipy') # rel tol 1e-10 0.33149330543214117 - 0.3174498589684438*I TESTS:: sage: parent(airy_ai_simple(3).n(algorithm='scipy')) Real Field with 53 bits of precision sage: airy_ai_simple(3).n(algorithm='scipy', prec=200) Traceback (most recent call last): ... NotImplementedError: airy_ai not implemented for precision > 53 """ algorithm = kwargs.get('algorithm', 'mpmath') or 'mpmath' parent = kwargs.get('parent') if algorithm == 'scipy': if hasattr(parent, 'prec') and parent.prec() > 53: raise NotImplementedError("%s not implemented for precision > 53" % self.name()) from sage.rings.real_mpfr import RR from sage.rings.cc import CC from sage.functions.other import real, imag from scipy.special import airy as airy if x in RR: y = airy(real(x))[0] if parent is None: return RR(y) else: y = airy(complex(real(x), imag(x)))[0] if parent is None: return CC(y) return parent(y) elif algorithm == 'mpmath': import mpmath from sage.libs.mpmath import utils as mpmath_utils return mpmath_utils.call(mpmath.airyai, x, parent=parent) else: raise ValueError("unknown algorithm '%s'" % algorithm)
def _evalf_(self, x, **kwargs): """ EXAMPLES:: sage: from sage.functions.airy import airy_bi_simple sage: airy_bi_simple(0.0) 0.614926627446001 sage: airy_bi_simple(1.0 * I) 0.648858208330395 + 0.344958634768048*I We can use several methods for numerical evaluation:: sage: airy_bi_simple(3).n(algorithm='mpmath') 14.0373289637302 sage: airy_bi_simple(3).n(algorithm='mpmath', prec=100) 14.037328963730232031740267314 sage: airy_bi_simple(3).n(algorithm='scipy') # rel tol 1e-10 14.037328963730136 sage: airy_bi_simple(I).n(algorithm='scipy') # rel tol 1e-10 0.648858208330395 + 0.34495863476804844*I TESTS:: sage: parent(airy_bi_simple(3).n(algorithm='scipy')) Real Field with 53 bits of precision sage: airy_bi_simple(3).n(algorithm='scipy', prec=200) Traceback (most recent call last): ... NotImplementedError: airy_bi not implemented for precision > 53 """ algorithm = kwargs.get('algorithm', 'mpmath') or 'mpmath' parent = kwargs.get('parent', None) if algorithm == 'scipy': if hasattr(parent, 'prec') and parent.prec() > 53: raise NotImplementedError("%s not implemented for precision > 53" % self.name()) from sage.rings.real_mpfr import RR from sage.rings.cc import CC from sage.functions.other import real, imag from scipy.special import airy as airy if x in RR: y = airy(real(x))[2] if parent is None: return RR(y) else: y = airy(complex(real(x), imag(x)))[2] if parent is None: return CC(y) return parent(y) elif algorithm == 'mpmath': import mpmath from sage.libs.mpmath import utils as mpmath_utils return mpmath_utils.call(mpmath.airybi, x, parent=parent) else: raise ValueError("unknown algorithm '%s'" % algorithm)
def _evalf_(self, x, **kwargs): """ EXAMPLES:: sage: airy_bi_prime(0.0) 0.448288357353826 We can use several methods for numerical evaluation:: sage: airy_bi_prime(4).n(algorithm='mpmath') 161.926683504613 sage: airy_bi_prime(4).n(algorithm='mpmath', prec=100) 161.92668350461340184309492429 sage: airy_bi_prime(4).n(algorithm='scipy') # rel tol 1e-10 161.92668350461398 sage: airy_bi_prime(I).n(algorithm='scipy') # rel tol 1e-10 0.135026646710819 - 0.1288373867812549*I TESTS:: sage: parent(airy_bi_prime(3).n(algorithm='scipy')) Real Field with 53 bits of precision sage: airy_bi_prime(3).n(algorithm='scipy', prec=200) Traceback (most recent call last): ... NotImplementedError: airy_bi_prime not implemented for precision > 53 """ algorithm = kwargs.get('algorithm', 'mpmath') or 'mpmath' parent = kwargs.get('parent', None) if algorithm == 'scipy': if hasattr(parent, 'prec') and parent.prec() > 53: raise NotImplementedError("%s not implemented for precision > 53" % self.name()) from sage.rings.real_mpfr import RR from sage.rings.cc import CC from sage.functions.other import real, imag from scipy.special import airy as airy if x in RR: y = airy(real(x))[3] if parent is None: return RR(y) else: y = airy(complex(real(x), imag(x)))[3] if parent is None: return CC(y) return parent(y) elif algorithm == 'mpmath': import mpmath from sage.libs.mpmath import utils as mpmath_utils return mpmath_utils.call(mpmath.airybi, x, derivative=1, parent=parent) else: raise ValueError("unknown algorithm '%s'" % algorithm)
def _evalf_(self, x, **kwargs): """ EXAMPLES:: sage: airy_ai_prime(0.0) -0.258819403792807 We can use several methods for numerical evaluation:: sage: airy_ai_prime(4).n(algorithm='mpmath') -0.00195864095020418 sage: airy_ai_prime(4).n(algorithm='mpmath', prec=100) -0.0019586409502041789001381409184 sage: airy_ai_prime(4).n(algorithm='scipy') # rel tol 1e-10 -0.00195864095020418 sage: airy_ai_prime(I).n(algorithm='scipy') # rel tol 1e-10 -0.43249265984180707 + 0.09804785622924324*I TESTS:: sage: parent(airy_ai_prime(3).n(algorithm='scipy')) Real Field with 53 bits of precision sage: airy_ai_prime(3).n(algorithm='scipy', prec=200) Traceback (most recent call last): ... NotImplementedError: airy_ai_prime not implemented for precision > 53 """ algorithm = kwargs.get('algorithm', 'mpmath') or 'mpmath' parent = kwargs.get('parent', None) if algorithm == 'scipy': if hasattr(parent, 'prec') and parent.prec() > 53: raise NotImplementedError("%s not implemented for precision > 53" % self.name()) from sage.rings.real_mpfr import RR from sage.rings.cc import CC from sage.functions.other import real, imag from scipy.special import airy as airy if x in RR: y = airy(real(x))[1] if parent is None: return RR(y) else: y = airy(complex(real(x), imag(x)))[1] if parent is None: return CC(y) return parent(y) elif algorithm == 'mpmath': import mpmath from sage.libs.mpmath import utils as mpmath_utils return mpmath_utils.call(mpmath.airyai, x, derivative=1, parent=parent) else: raise ValueError("unknown algorithm '%s'" % algorithm)
def get_solution_dicts(output_file_contents, input_ring, get_failures=True): """ Return a list of dictionaries of variable:value (key:value) pairs. Only used internally; see the solution_dict function in the PHC_Object class definition for details. INPUT: - output_file_contents -- phc solution output as a string - input_ring -- a PolynomialRing that variable names can be coerced into OUTPUT: a list of dictionaries of solutions EXAMPLES:: sage: from sage.interfaces.phc import * sage: R2.<x1,x2> = PolynomialRing(QQ,2) sage: test_sys = [(x1-1)^5-x2, (x2-1)^5-1] sage: sol = phc.blackbox(test_sys, R2) # optional -- phc sage: test = get_solution_dicts(sol.output_file_contents,R2) # optional -- phc sage: str(sum([q[x1].real() for q in test]))[0:4] # optional -- phc '25.0' """ output_list = output_file_contents.splitlines() solution_dicts = [] for solution_line in range(len(output_list) - 1, -1, -1): if output_list[solution_line].find('THE SOLUTIONS') == 0: break try: var_number = int(output_list[solution_line + 2].split(' ')[1]) # sol_number = int(output_list[solution_line+2].split(' ')[0]) except IndexError: var_number = int(output_list[solution_line + 1].split(' ')[1]) # sol_number = int(output_list[solution_line+1].split(' ')[0]) for i in range(solution_line + 1, len(output_list)): if output_list[i].count('the solution for t') == 1: if output_list[i - 3].count('success') > 0 or get_failures: temp_dict = {} for j in range(1, var_number + 1): rawsplit = output_list[i + j].split(': ')[1].split(' ') for extras in range(rawsplit.count('')): rawsplit.remove('') temp_var = output_list[i + j].split(': ')[0].replace( ' ', '') temp_dict[input_ring(temp_var)] = CC( rawsplit[0], rawsplit[1]) solution_dicts.append(temp_dict) return solution_dicts
def boundary_point_in_model(self, p): r""" Check whether a complex number lies in the open unit disk. EXAMPLES:: sage: PD = HyperbolicPlane().PD() sage: PD.boundary_point_in_model(1.00) True sage: PD.boundary_point_in_model(1/2 + I/2) False sage: PD.boundary_point_in_model(1 + .2*I) False """ if isinstance(p, HyperbolicPoint): return p.is_boundary() return bool(abs(abs(CC(p)) - 1) < EPSILON)
def __init__(self, pts, options): """ Initialize HyperbolicPolygon. EXAMPLES:: sage: from sage.plot.hyperbolic_polygon import HyperbolicPolygon sage: print(HyperbolicPolygon([0, 1/2, I], {})) Hyperbolic polygon (0.000000000000000, 0.500000000000000, 1.00000000000000*I) """ pts = [CC(_) for _ in pts] self.path = [] self._hyperbolic_arc(pts[0], pts[1], True) for i in range(1, len(pts) - 1): self._hyperbolic_arc(pts[i], pts[i + 1]) self._hyperbolic_arc(pts[-1], pts[0]) BezierPath.__init__(self, self.path, options) self._pts = pts
def show(self, boundary=True, **options): r""" Plot ``self``. EXAMPLES:: sage: HyperbolicPlane().PD().get_point(0).show() Graphics object consisting of 2 graphics primitives sage: HyperbolicPlane().KM().get_point((0,0)).show() Graphics object consisting of 2 graphics primitives sage: HyperbolicPlane().HM().get_point((0,0,1)).show() Graphics3d Object """ p = self.coordinates() if p == infinity: raise NotImplementedError("can't draw the point infinity") opts = {'axes': False, 'aspect_ratio': 1} opts.update(self.graphics_options()) opts.update(options) from sage.plot.point import point from sage.misc.functional import numerical_approx if self._bdry: # It is a boundary point p = numerical_approx(p) pic = point((p, 0), **opts) if boundary: bd_pic = self._model.get_background_graphic(bd_min=p - 1, bd_max=p + 1) pic = bd_pic + pic else: # It is an interior point if p in RR: p = CC(p) elif hasattr(p, 'items') or hasattr(p, '__iter__'): p = [numerical_approx(k) for k in p] else: p = numerical_approx(p) pic = point(p, **opts) if boundary: bd_pic = self.parent().get_background_graphic() pic = bd_pic + pic return pic
def __init__(self, sides, i_angle, center, options): """ Initialize HyperbolicRegularPolygon. EXAMPLES:: sage: from sage.plot.hyperbolic_regular_polygon import HyperbolicRegularPolygon sage: print(HyperbolicRegularPolygon(5,pi/2,I, {})) Hyperbolic regular polygon (sides=5, i_angle=1/2*pi, center=1.00000000000000*I) """ self.center = CC(center) if self.center.imag() <= 0: raise ValueError( "center: %s is not a valid point in the upper half plane model of the hyperbolic plane" % (self.center)) if sides < 3: raise ValueError( "degenerated polygons (sides<=2) are not supported") if i_angle <= 0 or i_angle >= pi: raise ValueError("interior angle %s must be in (0, pi) interval" % (i_angle)) if pi * (sides - 2) - sides * i_angle <= 0: raise ValueError( "there exists no hyperbolic regular compact polygon, for sides=%s the interior angle must be less than %s" % (sides, pi * (sides - 2) / sides)) self.sides = sides self.i_angle = i_angle beta = 2 * pi / self.sides # compute the rotation angle to be used ahead alpha = self.i_angle / Integer(2) I = CC(0, 1) # compute using cosine theorem the radius of the circumscribed circle # using the triangle formed by the radius and the three known angles r = arccosh(cot(alpha) * (1 + cos(beta)) / sin(beta)) # The first point will be always on the imaginary axis limited # to 8 digits for efficiency in the subsequent calculations. z_0 = [I * (e**r).n(digits=8)] # Compute the dilation isometry used to move the center # from I to the imaginary part of the given center. scale = self.center.imag() # Compute the parabolic isometry to move the center to the # real part of the given center. h_disp = self.center.real() d_z_k = [z_0[0] * scale + h_disp ] #d_k has the points for the polygon in the given center z_k = z_0 #z_k has the Re(z)>0 vertices for the I centered polygon r_z_k = [] #r_z_k has the Re(z)<0 vertices if is_odd(self.sides): vert = (self.sides - 1) // 2 else: vert = self.sides // 2 - 1 for k in range(vert): # Compute with 8 digits to accelerate calculations new_z_k = self._i_rotation(z_k[-1], beta).n(digits=8) z_k = z_k + [new_z_k] d_z_k = d_z_k + [new_z_k * scale + h_disp] r_z_k = [-(new_z_k).conjugate() * scale + h_disp] + r_z_k if is_odd(self.sides): HyperbolicPolygon.__init__(self, d_z_k + r_z_k, options) else: z_opo = [I * (e**(-r)).n(digits=8) * scale + h_disp] HyperbolicPolygon.__init__(self, d_z_k + z_opo + r_z_k, options)
from sage.rings.integer_ring import ZZ from sage.rings.real_mpfr import RR from sage.rings.real_double import RDF from sage.rings.complex_mpfr import ComplexField, is_ComplexNumber from sage.rings.cc import CC from sage.rings.real_mpfr import (RealField, is_RealNumber) from sage.symbolic.function import GinacFunction, BuiltinFunction import sage.libs.mpmath.utils as mpmath_utils from sage.combinat.combinat import bernoulli_polynomial from .gamma import psi from .other import factorial I = CC.gen(0) class Function_zeta(GinacFunction): def __init__(self): r""" Riemann zeta function at s with s a real or complex number. INPUT: - ``s`` - real or complex number If s is a real number the computation is done using the MPFR library. When the input is not real, the computation is done using the PARI C library.
def smallest_dynamical(f, dynatomic=True, start_n=1, prec=53, emb=None, algorithm='HS', check_minimal=True): r""" Determine the poly with smallest coefficients in `SL(2,\ZZ)` orbit of ``F`` Smallest is in the sense of global height. The method is the algorithm in Hutz-Stoll [HS2018]_. A binary form defining the periodic points is associated to ``f``. From this polynomial a bound on the search space can be determined. ``f`` should already be a minimal model or finding the orbit representatives may give wrong results. INPUT: - ``f`` -- a dynamical system on `P^1` - ``dynatomic`` -- boolean. whether ``F`` is the periodic points or the formal periodic points of period ``m`` for ``f`` - ``start_n`` - positive integer. the period used to start trying to create associate binary form ``F`` - ``prec``-- positive integer. precision to use in CC - ``emb`` -- embedding into CC - ``algorithm`` -- (optional) string; either ``'BM'`` for the Bruin-Molnar algorithm or ``'HS'`` for the Hutz-Stoll algorithm. If not specified, properties of the map are utilized to choose how to compute minimal orbit representatives - ``check_minimal`` -- (default: True), boolean, whether to check if this map is a minimal model OUTPUT: pair [dynamical system, matrix] EXAMPLES:: sage: from sage.dynamics.arithmetic_dynamics.endPN_minimal_model import smallest_dynamical sage: P.<x,y> = ProjectiveSpace(QQ,1) sage: f = DynamicalSystem([50*x^2 + 795*x*y + 2120*y^2, 265*x^2 + 106*y^2]) sage: smallest_dynamical(f) #long time [ Dynamical System of Projective Space of dimension 1 over Rational Field Defn: Defined on coordinates by sending (x : y) to (-480*x^2 - 1125*x*y + 1578*y^2 : 265*x^2 + 1060*x*y + 1166*y^2), <BLANKLINE> [1 2] [0 1] ] """ def insert_item(pts, item, index): # binary insertion to maintain list of points left to consider N = len(pts) if N == 0: return [item] elif N == 1: if item[index] > pts[0][index]: pts.insert(0,item) else: pts.append(item) return pts else: # binary insertion left = 1 right = N mid = (left + right) // 2 # these are ints so this is .floor() if item[index] > pts[mid][index]: # item goes into first half return insert_item(pts[:mid], item, index) + pts[mid:N] else: # item goes into second half return pts[:mid] + insert_item(pts[mid:N], item, index) def coshdelta(z): # The cosh of the hyperbolic distance from z = t+uj to j return (z.norm() + 1)/(2*z.imag()) # can't be smaller if height 0 f.normalize_coordinates() if f.global_height(prec=prec) == 0: return [f, matrix(ZZ,2,2,[1,0,0,1])] all_min = f.all_minimal_models(return_transformation=True, algorithm=algorithm, check_minimal=check_minimal) current_min = None current_size = None # search for minimum over all orbits for g,M in all_min: PS = g.domain() CR = PS.coordinate_ring() x,y = CR.gens() n = start_n # sometimes you get a problem later with 0,infty as roots if dynatomic: pts_poly = g.dynatomic_polynomial(n) else: gn = g.nth_iterate_map(n) pts_poly = y*gn[0] - x*gn[1] d = ZZ(pts_poly.degree()) max_mult = max([ex for p,ex in pts_poly.factor()]) while ((d < 3) or (max_mult >= d/2) and (n < 5)): n = n+1 if dynatomic: pts_poly = g.dynatomic_polynomial(n) else: gn = g.nth_iterate_map(n) pts_poly = y*gn[0] - x*gn[1] d = ZZ(pts_poly.degree()) max_mult = max([ex for p,ex in pts_poly.factor()]) assert(n<=4), "n > 4, failed to find usable poly" R = get_bound_dynamical(pts_poly, g, m=n, dynatomic=dynatomic, prec=prec, emb=emb) # search starts in fundamental domain G,MG = pts_poly.reduced_form(prec=prec, emb=emb, smallest_coeffs=False) red_g = f.conjugate(M*MG) if G != pts_poly: R2 = get_bound_dynamical(G, red_g, m=n, dynatomic=dynatomic, prec=prec, emb=emb) if R2 < R: # use the better bound R = R2 red_g.normalize_coordinates() if red_g.global_height(prec=prec) == 0: return [red_g, M*MG] # height if current_size is None: current_size = e**red_g.global_height(prec=prec) v0, th = covariant_z0(G, prec=prec, emb=emb) rep = 2*CC.gen(0) from math import isnan if isnan(v0.abs()): raise ValueError("invalid covariant: %s"%v0) # get orbit S = matrix(ZZ,2,2,[0,-1,1,0]) T = matrix(ZZ,2,2,[1,1,0,1]) TI = matrix(ZZ,2,2,[1,-1,0,1]) count = 0 pts = [[G, red_g, v0, rep, M*MG, coshdelta(v0), 0]] # label - 0:None, 1:S, 2:T, 3:T^(-1) if current_min is None: current_min = [G, red_g, v0, rep, M*MG, coshdelta(v0)] while pts != []: G, g, v, rep, M, D, label = pts.pop() # apply ST and keep z, Sz if D > R: break #all remaining pts are too far away # check if it is smaller. If so, we can improve the bound count += 1 new_size = e**g.global_height(prec=prec) if new_size < current_size: current_min = [G ,g, v, rep, M, coshdelta(v)] current_size = new_size if new_size == 1: # early exit return [current_min[1], current_min[4]] new_R = get_bound_dynamical(G, g, m=n, dynatomic=dynatomic, prec=prec, emb=emb) if new_R < R: R = new_R # add new points to check if label != 1 and min((rep+1).norm(), (rep-1).norm()) >= 1: # don't undo S # the 2nd condition is equivalent to |\Re(-1/rep)| <= 1/2 # this means that rep can have resulted from an inversion step in # the shift-and-invert procedure, so don't invert # do inversion z = -1/v new_pt = [G.subs({x:-y, y:x}), g.conjugate(S), z, -1/rep, M*S, coshdelta(z), 1] pts = insert_item(pts, new_pt, 5) if label != 3: # don't undo T on g # do right shift z = v-1 new_pt = [G.subs({x:x+y}), g.conjugate(TI), z, rep-1, M*TI, coshdelta(z), 2] pts = insert_item(pts, new_pt, 5) if label != 2: # don't undo TI on g # do left shift z = v+1 new_pt = [G.subs({x:x-y}), g.conjugate(T), z, rep+1, M*T, coshdelta(z), 3] pts = insert_item(pts, new_pt, 5) return [current_min[1], current_min[4]]
def __call__(self, s, prec=53): """ Evaluate this complex `L`-series at `s`. INPUT: - ``s`` -- complex number - ``prec`` -- integer (default: 53) the number of bits of precision used in computing the lseries of the newforms. OUTPUT: a complex number L(A, s). EXAMPLES:: sage: L = J0(23).lseries() sage: L(1) 0.248431866590600 sage: L(1, prec=100) 0.24843186659059968120725033931 sage: L = J0(389)[0].lseries() sage: L(1) # long time (2s) abstol 1e-10 -1.33139759782370e-19 sage: L(1, prec=100) # long time (2s) abstol 1e-20 6.0129758648142797032650287762e-39 sage: L.rational_part() 0 sage: L = J1(23)[0].lseries() sage: L(1) 0.248431866590600 sage: J = J0(11) * J1(11) sage: J.lseries()(1) 0.0644356903227915 sage: L = JH(17,[2]).lseries() sage: L(1) 0.386769938387780 """ abelian_variety = self.abelian_variety() # Check for easy dimension zero case if abelian_variety.dimension() == 0: return CC(1) try: factors = self.__factors[prec] return prod(L(s) for L in factors) except AttributeError: self.__factors = {} except KeyError: pass abelian_variety = self.abelian_variety() newforms = abelian_variety.newform_decomposition('a') factors = [ newform.lseries(embedding=i, prec=prec) for newform in newforms for i in range(newform.base_ring().degree()) ] self.__factors[prec] = factors return prod(L(s) for L in factors)
def _parse_path_file(self, input_filename, verbose=False): """ Takes a phpack output file containing path tracking information and parses it into a list of lists of dictionaries - i.e. a list of solutions paths, where each solution path is a list of dictionaries of variable and homotopy parameter values. INPUT: - input_filename -- file must have path-tracking information OUTPUT: - a list of lists of dictionaries, described above EXAMPLES:: sage: from sage.interfaces.phc import * sage: R2.<x,y> = PolynomialRing(QQ,2) sage: start_sys = [x^5-y^2,y^5-1] sage: sol = phc.blackbox(start_sys, R2) # optional -- phc sage: start_save = sol.save_as_start() # optional -- phc sage: end_sys = [x^5-2,y^5-x^2] # optional -- phc sage: path_track_filename = phc._path_track_file(start_save, end_sys, R2, c_skew = .001) # optional -- phc sage: sol_paths = phc._parse_path_file(path_track_filename) # optional -- phc sage: len(sol_paths) # optional -- phc 25 """ if not os.path.exists(input_filename): raise RuntimeError("The file containing output from phc (" + input_filename + ") cannot be found") fh = open(input_filename) line_idx = 0 begin = 0 count = 0 solutions_dicts = [] steps_dicts = [] # regular expressions for matching certain output types var_cnt_regex = re.compile('^ +([0-9]+)') output_regex = re.compile('^OUTPUT INFORMATION DURING') t_regex = re.compile( r'(^t +: +(-{0,1}[0-9]+\.[0-9]+E[-+][0-9]+) +(-{0,1}[0-9]+\.[0-9]+E[-+][0-9]+)$)', re.IGNORECASE) sols_regex = re.compile( r'(^ *(([a-z]|[0-9])+) +: +(-?[0-9]+\.[0-9]+E[-+][0-9]+) +(-?[0-9]+\.[0-9]+E[-+][0-9]+)$)', re.IGNORECASE) complete_regex = re.compile('^TIMING INFORMATION') breakfast = False a_line = fh.readline() end_test = '' while a_line: # processing.... a_line = a_line.replace("\n", '') if line_idx == 0: m = var_cnt_regex.match(a_line) if m: count = Integer(m.group(1)) if count > 0: m = output_regex.match(a_line) if m: begin = 1 if begin: m = t_regex.match(a_line) if m: # put the t-values into a dict # m.group(2) contains the real val # m.group(3) contains the imaginary val # fh_w.write( "T=> G1(" + m.group(2) + '),G2(' + m.group(3) + ")\n") # read off two lines - this should be 'm' and 'the solution for t :' a_line = fh.readline() end_test = a_line # store this to check for end of solution a_line = fh.readline() t_val = CC(m.group(2), m.group(3)) temp_dict = {} temp_dict["t"] = t_val for i in range(0, count): a_line = fh.readline() m = sols_regex.match(a_line) if m: # m.group(2) contains our var name # m.group(4) contains our real val # m.group(5) contains our imaginary val temp_dict[m.group(2)] = CC( m.group(4), m.group(5)) steps_dicts.append(temp_dict) # check if its the end of a solution if end_test.find('Length of path') != -1: if verbose: print("recording sol") if steps_dicts != []: solutions_dicts.append(steps_dicts) steps_dicts = [] m = complete_regex.match(a_line) if m: breakfast = True if breakfast: break line_idx += 1 a_line = fh.readline() fh.close() return solutions_dicts
def julia_plot(f=None, **kwds): r""" Plots the Julia set of a given polynomial ``f``. Users can specify whether they would like to display the Mandelbrot side by side with the Julia set with the ``mandelbrot`` argument. If ``f`` is not specified, this method defaults to `f(z) = z^2-1`. The Julia set of a polynomial ``f`` is the set of complex numbers `z` for which the function `f(z)` is bounded under iteration. The Julia set can be visualized by plotting each point in the set in the complex plane. Julia sets are examples of fractals when plotted in the complex plane. ALGORITHM: Let `R_c = \bigl(1 + \sqrt{1 + 4|c|}\bigr)/2` if the polynomial is of the form `f(z) = z^2 + c`; otherwise, let `R_c = 2`. For every `p \in \mathbb{C}`, if `|f^{k}(p)| > R_c` for some `k \geq 0`, then `f^{n}(p) \to \infty`. Let `N` be the maximum number of iterations. Compute the first `N` points on the orbit of `p` under `f`. If for any `k < N`, `|f^{k}(p)| > R_c`, we stop the iteration and assign a color to the point `p` based on how quickly `p` escaped to infinity under iteration of `f`. If `|f^{i}(p)| \leq R_c` for all `i \leq N`, we assume `p` is in the Julia set and assign the point `p` the color black. INPUT: - ``f`` -- input polynomial (optional - default: ``z^2 - 1``). - ``period`` -- list (optional - default: ``None``), returns the Julia set for a random `c` value with the given (formal) cycle structure. - ``mandelbrot`` -- boolean (optional - default: ``True``), when set to ``True``, an image of the Mandelbrot set is appended to the right of the Julia set. - ``point_color`` -- RGB color (optional - default: ``'tomato'``), color of the point `c` in the Mandelbrot set (any valid input for Color). - ``x_center`` -- double (optional - default: ``-1.0``), Real part of center point. - ``y_center`` -- double (optional - default: ``0.0``), Imaginary part of center point. - ``image_width`` -- double (optional - default: ``4.0``), width of image in the complex plane. - ``max_iteration`` -- long (optional - default: ``500``), maximum number of iterations the map `f(z)`. - ``pixel_count`` -- long (optional - default: ``500``), side length of image in number of pixels. - ``base_color`` -- hex color (optional - default: ``'steelblue'``), color used to determine the coloring of set (any valid input for Color). - ``level_sep`` -- long (optional - default: 1), number of iterations between each color level. - ``number_of_colors`` -- long (optional - default: 30), number of colors used to plot image. - ``interact`` -- boolean (optional - default: ``False``), controls whether plot will have interactive functionality. OUTPUT: 24-bit RGB image of the Julia set in the complex plane. .. TODO:: Implement the side-by-side Mandelbrot-Julia plots for general one-parameter families of polynomials. EXAMPLES: The default ``f`` is `z^2 - 1`:: sage: julia_plot() 1001x500px 24-bit RGB image To display only the Julia set, set ``mandelbrot`` to ``False``:: sage: julia_plot(mandelbrot=False) 500x500px 24-bit RGB image :: sage: R.<z> = CC[] sage: f = z^3 - z + 1 sage: julia_plot(f) 500x500px 24-bit RGB image To display an interactive plot of the Julia set in the Notebook, set ``interact`` to ``True``. (This is only implemented for polynomials of the form ``f = z^2 + c``):: sage: julia_plot(interact=True) interactive(children=(FloatSlider(value=-1.0, description='Real c'... :: sage: R.<z> = CC[] sage: f = z^2 + 1/2 sage: julia_plot(f,interact=True) interactive(children=(FloatSlider(value=0.5, description='Real c'... To return the Julia set of a random `c` value with (formal) cycle structure `(2,3)`, set ``period = [2,3]``:: sage: julia_plot(period=[2,3]) 1001x500px 24-bit RGB image To return all of the Julia sets of `c` values with (formal) cycle structure `(2,3)`:: sage: period = [2,3] # not tested ....: R.<c> = QQ[] ....: P.<x,y> = ProjectiveSpace(R,1) ....: f = DynamicalSystem([x^2+c*y^2, y^2]) ....: L = f.dynatomic_polynomial(period).subs({x:0,y:1}).roots(ring=CC) ....: c_values = [k[0] for k in L] ....: for c in c_values: ....: julia_plot(c) Polynomial maps can be defined over a polynomial ring or a fraction field, so long as ``f`` is polynomial:: sage: R.<z> = CC[] sage: f = z^2 - 1 sage: julia_plot(f) 1001x500px 24-bit RGB image :: sage: R.<z> = CC[] sage: K = R.fraction_field(); z = K.gen() sage: f = z^2-1 sage: julia_plot(f) 1001x500px 24-bit RGB image Interact functionality is not implemented if the polynomial is not of the form `f = z^2 + c`:: sage: R.<z> = CC[] sage: f = z^3 + 1 sage: julia_plot(f, interact=True) Traceback (most recent call last): ... NotImplementedError: The interactive plot is only implemented for ... """ # extract keyword arguments period = kwds.pop("period", None) mandelbrot = kwds.pop("mandelbrot", True) point_color = kwds.pop("point_color", 'tomato') x_center = kwds.pop("x_center", 0.0) y_center = kwds.pop("y_center", 0.0) image_width = kwds.pop("image_width", 4.0) max_iteration = kwds.pop("max_iteration", 500) pixel_count = kwds.pop("pixel_count", 500) base_color = kwds.pop("base_color", 'steelblue') level_sep = kwds.pop("level_sep", 1) number_of_colors = kwds.pop("number_of_colors", 30) interacts = kwds.pop("interact", False) f_is_default_after_all = None if period: # pick a random c with the specified period R = PolynomialRing(CC, 'c') c = R.gen() x, y = ProjectiveSpace(R, 1, 'x,y').gens() F = DynamicalSystem([x**2 + c * y**2, y**2]) L = F.dynatomic_polynomial(period).subs({x: 0, y: 1}).roots(ring=CC) c = L[randint(0, len(L) - 1)][0] base_color = Color(base_color) point_color = Color(point_color) EPS = 0.00001 if f is not None and period is None: # f user-specified and no period given # try to coerce f to live in a polynomial ring S = PolynomialRing(CC, names='z') z = S.gen() try: f_poly = S(f) except TypeError: R = f.parent() if not (R.is_integral_domain() and (CC.is_subring(R) or CDF.is_subring(R))): raise ValueError('Given `f` must be a complex polynomial.') else: raise NotImplementedError( 'Julia sets not implemented for rational functions.' ) if (f_poly - z*z) in CC: # f is specified and of the form z^2 + c. f_is_default_after_all = True c = f_poly - z*z else: # f is specified and not of the form z^2 + c if interacts: raise NotImplementedError( "The interactive plot is only implemented for " "polynomials of the form f = z^2 + c." ) else: return general_julia(f_poly, x_center, y_center, image_width, max_iteration, pixel_count, level_sep, number_of_colors, base_color) # otherwise we can use fast_julia_plot for z^2 + c if f_is_default_after_all or f is None or period is not None: # specify default c = -1 value if f and period were not specified if not f_is_default_after_all and period is None: c = -1 c = CC(c) c_real = c.real() c_imag = c.imag() if interacts: # set widgets from ipywidgets.widgets import FloatSlider, IntSlider, \ ColorPicker, interact widgets = dict( c_real = FloatSlider(min=-2.0, max=2.0, step=EPS, value=c_real, description="Real c"), c_imag = FloatSlider(min=-2.0, max=2.0, step=EPS, value=c_imag, description="Imag c"), x_center = FloatSlider(min=-1.0, max=1.0, step=EPS, value=x_center, description="Real center"), y_center = FloatSlider(min=-1.0, max=1.0, step=EPS, value=y_center, description="Imag center"), image_width = FloatSlider(min=EPS, max=4.0, step=EPS, value=image_width, description="Width"), max_iteration = IntSlider(min=0, max=1000, value=max_iteration, description="Iterations"), pixel_count = IntSlider(min=10, max=1000, value=pixel_count, description="Pixels"), level_sep = IntSlider(min=1, max=20, value=level_sep, description="Color sep"), color_num = IntSlider(min=1, max=100, value=number_of_colors, description="# Colors"), base_color = ColorPicker(value=base_color.html_color(), description="Base color"), ) if mandelbrot: widgets["point_color"] = ColorPicker(value=point_color.html_color(), description="Point color") return interact(**widgets).widget(julia_helper) else: return interact(**widgets).widget(fast_julia_plot) elif mandelbrot: # non-interactive with mandelbrot return julia_helper(c_real, c_imag, x_center, y_center, image_width, max_iteration, pixel_count, level_sep, number_of_colors, base_color, point_color) else: # non-interactive without mandelbrot return fast_julia_plot(c_real, c_imag, x_center, y_center, image_width, max_iteration, pixel_count, level_sep, number_of_colors, base_color)
def hyperbolic_regular_polygon(sides, i_angle, center=CC(0, 1), **options): r""" Return a hyperbolic regular polygon in the upper half model of Hyperbolic plane given the number of sides, interior angle and possibly a center. Type ``?hyperbolic_regular_polygon`` to see all options. INPUT: - ``sides`` -- number of sides of the polygon - ``i_angle`` -- interior angle of the polygon - ``center`` -- (default: `i`) hyperbolic center point (complex number) of the polygon OPTIONS: - ``alpha`` -- default: 1 - ``fill`` -- default: ``False`` - ``thickness`` -- default: 1 - ``rgbcolor`` -- default: ``'blue'`` - ``linestyle`` -- (default: ``'solid'``) the style of the line, which can be one of the following: * ``'dashed'`` or ``'--'`` * ``'dotted'`` or ``':'`` * ``'solid'`` or ``'-'`` * ``'dashdot'`` or ``'-.'`` EXAMPLES: Show a hyperbolic regular polygon with 6 sides and square angles:: sage: g = hyperbolic_regular_polygon(6, pi/2) sage: g.plot() Graphics object consisting of 1 graphics primitive .. PLOT:: g = hyperbolic_regular_polygon(6, pi/2) sphinx_plot(g.plot()) With more options:: sage: g = hyperbolic_regular_polygon(6, pi/2, center=3+2*I, fill=True, color='red') sage: g.plot() Graphics object consisting of 1 graphics primitive .. PLOT:: g = hyperbolic_regular_polygon(6, pi/2, center=3+2*I, fill=True, color='red') sphinx_plot(g.plot()) The code verifies is there exists a hyperbolic regular polygon with the given data, checking .. MATH:: A(\mathcal{P}) = \pi(s-2) - s \cdot \alpha > 0, where `s` is ``sides`` and `\alpha` is ``i_angle`. This raises an error if the ``i_angle`` is less than the minimum to generate a compact polygon:: sage: hyperbolic_regular_polygon(4, pi/2) Traceback (most recent call last): ... ValueError: there exists no hyperbolic regular compact polygon, for sides=4 the interior angle must be less than 1/2*pi It is an error to give a center outside the upper half plane in this model:: sage: from sage.plot.hyperbolic_regular_polygon import hyperbolic_regular_polygon sage: hyperbolic_regular_polygon(4, pi/4, 1-I) Traceback (most recent call last): ... ValueError: center: 1.00000000000000 - 1.00000000000000*I is not a valid point in the upper half plane model of the hyperbolic plane """ g = Graphics() g._set_extra_kwds(g._extract_kwds_for_show(options)) g.add_primitive(HyperbolicRegularPolygon(sides, i_angle, center, options)) g.set_aspect_ratio(1) return g
class HyperbolicRegularPolygon(HyperbolicPolygon): r""" Primitive class for regular hyperbolic polygon type. See ``hyperbolic_regular_polygon?`` for information about plotting a hyperbolic regular polygon in the upper complex halfplane. INPUT: - ``sides`` -- number of sides of the polygon - ``i_angle`` -- interior angle of the polygon - ``center``-- center point as a complex number of the polygon EXAMPLES: Note that constructions should use :func:`hyperbolic_regular_polygon`:: sage: from sage.plot.hyperbolic_regular_polygon import HyperbolicRegularPolygon sage: print(HyperbolicRegularPolygon(5,pi/2,I, {})) Hyperbolic regular polygon (sides=5, i_angle=1/2*pi, center=1.00000000000000*I) The code verifies is there exists a compact hyperbolic regular polygon with the given data, checking .. MATH:: A(\mathcal{P}) = \pi(s-2) - s \cdot \alpha > 0, where `s` is ``sides`` and `\alpha` is ``i_angle`. This raises an error if the ``i_angle`` is less than the minimum to generate a compact polygon:: sage: from sage.plot.hyperbolic_regular_polygon import HyperbolicRegularPolygon sage: P = HyperbolicRegularPolygon(4, pi/2, I, {}) Traceback (most recent call last): ... ValueError: there exists no hyperbolic regular compact polygon, for sides=4 the interior angle must be less than 1/2*pi It is an error to give a center outside the upper half plane in this model :: sage: from sage.plot.hyperbolic_regular_polygon import HyperbolicRegularPolygon sage: P = HyperbolicRegularPolygon(4, pi/4, 1-I, {}) Traceback (most recent call last): ... ValueError: center: 1.00000000000000 - 1.00000000000000*I is not a valid point in the upper half plane model of the hyperbolic plane TESTS:: sage: from sage.plot.hyperbolic_regular_polygon import HyperbolicRegularPolygon sage: P = HyperbolicRegularPolygon(4, -pi/4, I, {}) Traceback (most recent call last): ... ValueError: interior angle -1/4*pi must be in (0, pi) interval sage: from sage.plot.hyperbolic_regular_polygon import HyperbolicRegularPolygon sage: P=HyperbolicRegularPolygon(16, 3*pi/2, I, {}) Traceback (most recent call last): ... ValueError: interior angle 3/2*pi must be in (0, pi) interval sage: from sage.plot.hyperbolic_regular_polygon import HyperbolicRegularPolygon sage: P = HyperbolicRegularPolygon(2, pi/10, I, {}) Traceback (most recent call last): ... ValueError: degenerated polygons (sides<=2) are not supported """ def __init__(self, sides, i_angle, center, options): """ Initialize HyperbolicRegularPolygon. EXAMPLES:: sage: from sage.plot.hyperbolic_regular_polygon import HyperbolicRegularPolygon sage: print(HyperbolicRegularPolygon(5,pi/2,I, {})) Hyperbolic regular polygon (sides=5, i_angle=1/2*pi, center=1.00000000000000*I) """ self.center = CC(center) if self.center.imag() <= 0: raise ValueError( "center: %s is not a valid point in the upper half plane model of the hyperbolic plane" % (self.center)) if sides < 3: raise ValueError( "degenerated polygons (sides<=2) are not supported") if i_angle <= 0 or i_angle >= pi: raise ValueError("interior angle %s must be in (0, pi) interval" % (i_angle)) if pi * (sides - 2) - sides * i_angle <= 0: raise ValueError( "there exists no hyperbolic regular compact polygon, for sides=%s the interior angle must be less than %s" % (sides, pi * (sides - 2) / sides)) self.sides = sides self.i_angle = i_angle beta = 2 * pi / self.sides # compute the rotation angle to be used ahead alpha = self.i_angle / Integer(2) I = CC(0, 1) # compute using cosine theorem the radius of the circumscribed circle # using the triangle formed by the radius and the three known angles r = arccosh(cot(alpha) * (1 + cos(beta)) / sin(beta)) # The first point will be always on the imaginary axis limited # to 8 digits for efficiency in the subsequent calculations. z_0 = [I * (e**r).n(digits=8)] # Compute the dilation isometry used to move the center # from I to the imaginary part of the given center. scale = self.center.imag() # Compute the parabolic isometry to move the center to the # real part of the given center. h_disp = self.center.real() d_z_k = [z_0[0] * scale + h_disp ] #d_k has the points for the polygon in the given center z_k = z_0 #z_k has the Re(z)>0 vertices for the I centered polygon r_z_k = [] #r_z_k has the Re(z)<0 vertices if is_odd(self.sides): vert = (self.sides - 1) // 2 else: vert = self.sides // 2 - 1 for k in range(vert): # Compute with 8 digits to accelerate calculations new_z_k = self._i_rotation(z_k[-1], beta).n(digits=8) z_k = z_k + [new_z_k] d_z_k = d_z_k + [new_z_k * scale + h_disp] r_z_k = [-(new_z_k).conjugate() * scale + h_disp] + r_z_k if is_odd(self.sides): HyperbolicPolygon.__init__(self, d_z_k + r_z_k, options) else: z_opo = [I * (e**(-r)).n(digits=8) * scale + h_disp] HyperbolicPolygon.__init__(self, d_z_k + z_opo + r_z_k, options) def _repr_(self): """ String representation of HyperbolicRegularPolygon. TESTS:: sage: from sage.plot.hyperbolic_regular_polygon import HyperbolicRegularPolygon sage: HyperbolicRegularPolygon(5,pi/2,I, {})._repr_() 'Hyperbolic regular polygon (sides=5, i_angle=1/2*pi, center=1.00000000000000*I)' """ return ( "Hyperbolic regular polygon (sides=%s, i_angle=%s, center=%s)" % (self.sides, self.i_angle, self.center)) def _i_rotation(self, z, alpha): r""" Return the resulting point after applying a hyperbolic rotation centered at `0 + i` and angle ``alpha`` to ``z``. INPUT: - ``z``-- point in the upper complex halfplane to which apply the isometry - ``alpha``-- angle of rotation (radians,counterwise) OUTPUT: - rotated point in the upper complex halfplane TESTS:: sage: from sage.plot.hyperbolic_regular_polygon import HyperbolicRegularPolygon sage: P = HyperbolicRegularPolygon(4, pi/4, 1+I, {}) sage: P._i_rotation(2+I, pi/2) I - 2 """ _a = alpha / 2 _c = cos(_a) _s = sin(_a) G = matrix([[_c, _s], [-_s, _c]]) return (G[0][0] * z + G[0][1]) / (G[1][0] * z + G[1][1])
def smallest_poly(F, prec=53, norm_type='norm', emb=None): r""" Determine the poly with smallest coefficients in `SL(2,\Z)` orbit of ``F`` Smallest can be in the sense of `L_2` norm or height. The method is the algorithm in Hutz-Stoll [HS2018]_. ``F`` needs to be a binary form with no multiple roots of degree at least 3. It should already be reduced in the sense of Cremona-Stoll [CS2003]_. INPUT: - ``F`` -- binary form of degree at least 3 with no multiple roots - ``norm_type`` -- string - ``norm`` or ``height`` controlling what ``smallest`` means for the coefficients. OUTPUT: pair [poly, matrix] EXAMPLES:: sage: from sage.rings.polynomial.binary_form_reduce import smallest_poly sage: R.<x,y> = QQ[] sage: F = -x^8 + 6*x^7*y - 7*x^6*y^2 - 12*x^5*y^3 + 27*x^4*y^4\ ....: - 4*x^3*y^5 - 19*x^2*y^6 + 10*x*y^7 - 5*y^8 sage: smallest_poly(F, prec=100) #long time [ -x^8 - 2*x^7*y + 7*x^6*y^2 + 16*x^5*y^3 + 2*x^4*y^4 - 2*x^3*y^5 + 4*x^2*y^6 - 5*y^8, <BLANKLINE> [1 1] [0 1] ] :: sage: from sage.rings.polynomial.binary_form_reduce import smallest_poly, get_bound_poly sage: R.<x,y> = QQ[] sage: F = -2*x^3 + 2*x^2*y + 3*x*y^2 + 127*y^3 sage: smallest_poly(F) [ [1 4] -2*x^3 - 22*x^2*y - 77*x*y^2 + 43*y^3, [0 1] ] sage: F0, M = smallest_poly(F, norm_type='height') sage: F0, M # random ( [5 4] -58*x^3 - 47*x^2*y + 52*x*y^2 + 43*y^3, [1 1] ) sage: M in SL2Z, F0 == R.hom(M * vector([x, y]))(F) (True, True) sage: get_bound_poly(F0, norm_type='height') # tol 1e-12 23.3402702199809 An example with a multiple root:: sage: R.<x,y> = QQ[] sage: F = -16*x^7 - 114*x^6*y - 345*x^5*y^2 - 599*x^4*y^3 - 666*x^3*y^4\ ....: - 481*x^2*y^5 - 207*x*y^6 - 40*y^7 sage: F.reduced_form() ( [-1 -1] -x^5*y^2 - 24*x^3*y^4 - 3*x^2*y^5 - 2*x*y^6 + 16*y^7, [ 1 0] ) """ def insert_item(pts, item, index): # binary insertion to maintain list of points left to consider N = len(pts) if N == 0: return [item] elif N == 1: if item[index] > pts[0][index]: pts.insert(0, item) else: pts.append(item) return pts else: # binary insertion left = 1 right = N mid = (left + right) // 2 # these are ints so this is .floor() if item[index] > pts[mid][index]: # item goes into first half return insert_item(pts[:mid], item, index) + pts[mid:N] else: # item goes into second half return pts[:mid] + insert_item(pts[mid:N], item, index) def coshdelta(z): # The cosh of the hyperbolic distance from z = t+uj to j return (z.norm() + 1) / (2 * z.imag() ) # reduce in the sense of Cremona-Stoll G = F MG = matrix(ZZ, 2, 2, [1, 0, 0, 1]) x, y = G.parent().gens() if norm_type == 'norm': current_size = sum([abs(i)**2 for i in G.coefficients() ]) # euclidean norm squared elif norm_type == 'height': # height current_size = exp( max([c.global_height(prec=prec) for c in G.coefficients()])) else: raise ValueError('type must be norm or height') v0, th = covariant_z0(G, prec=prec, emb=emb) rep = 2 * CC.gen(0) # representative point in fundamental domain from math import isnan if isnan(v0.abs()): raise ValueError("invalid covariant: %s" % v0) R = get_bound_poly(G, prec=prec, norm_type=norm_type) # check orbit S = matrix(ZZ, 2, 2, [0, -1, 1, 0]) T = matrix(ZZ, 2, 2, [1, 1, 0, 1]) TI = matrix(ZZ, 2, 2, [1, -1, 0, 1]) count = 0 pts = [[G, v0, rep, MG, coshdelta(v0), 0]] # label - 0:None, 1:S, 2:T, 3:T^(-1) current_min = [G, v0, rep, MG, coshdelta(v0)] while pts: G, v, rep, M, D, label = pts.pop() # apply ST and keep z, Sz if D > R: break # all remaining pts are too far away # check if it is smaller. If so, we can improve the bound count += 1 if norm_type == 'norm': new_size = sum([abs(i)**2 for i in G.coefficients() ]) # euclidean norm squared else: # height new_size = exp( max([c.global_height(prec=prec) for c in G.coefficients()])) if new_size < current_size: current_min = [G, v, rep, M, coshdelta(v)] current_size = new_size R = get_bound_poly(G, norm_type=norm_type, prec=prec, emb=emb) # add new points to check if label != 1 and min((rep + 1).norm(), (rep - 1).norm()) >= 1: # don't undo S # the 2nd condition is equivalent to |\Re(-1/rep)| <= 1/2 # this means that rep can have resulted from an inversion step in # the shift-and-invert procedure, so don't invert # do inversion z = -1 / v new_pt = [ G.subs({ x: -y, y: x }), z, -1 / rep, M * S, coshdelta(z), 1 ] pts = insert_item(pts, new_pt, 4) if label != 3: # don't undo TI # do right shift z = v - 1 new_pt = [G.subs({x: x + y}), z, rep - 1, M * T, coshdelta(z), 2] pts = insert_item(pts, new_pt, 4) if label != 2: # don't undo T # do left shift z = v + 1 new_pt = [G.subs({x: x - y}), z, rep + 1, M * TI, coshdelta(z), 3] pts = insert_item(pts, new_pt, 4) return [current_min[0], current_min[3]]
def contradicts(self, soln): """ Return ``True`` if this assumption is violated by the given variable assignment(s). INPUT: - ``soln`` -- Either a dictionary with variables as keys or a symbolic relation with a variable on the left hand side. EXAMPLES:: sage: from sage.symbolic.assumptions import GenericDeclaration sage: GenericDeclaration(x, 'integer').contradicts(x==4) False sage: GenericDeclaration(x, 'integer').contradicts(x==4.0) False sage: GenericDeclaration(x, 'integer').contradicts(x==4.5) True sage: GenericDeclaration(x, 'integer').contradicts(x==sqrt(17)) True sage: GenericDeclaration(x, 'noninteger').contradicts(x==sqrt(17)) False sage: GenericDeclaration(x, 'noninteger').contradicts(x==17) True sage: GenericDeclaration(x, 'even').contradicts(x==3) True sage: GenericDeclaration(x, 'complex').contradicts(x==3) False sage: GenericDeclaration(x, 'imaginary').contradicts(x==3) True sage: GenericDeclaration(x, 'imaginary').contradicts(x==I) False sage: var('y,z') (y, z) sage: GenericDeclaration(x, 'imaginary').contradicts(x==y+z) False sage: GenericDeclaration(x, 'rational').contradicts(y==pi) False sage: GenericDeclaration(x, 'rational').contradicts(x==pi) True sage: GenericDeclaration(x, 'irrational').contradicts(x!=pi) False sage: GenericDeclaration(x, 'rational').contradicts({x: pi, y: pi}) True sage: GenericDeclaration(x, 'rational').contradicts({z: pi, y: pi}) False """ if isinstance(soln, dict): value = soln.get(self._var) if value is None: return False elif soln.lhs() == self._var: value = soln.rhs() else: return False try: CC(value) except TypeError: return False if self._assumption == 'integer': return value not in ZZ elif self._assumption == 'noninteger': return value in ZZ elif self._assumption == 'even': return value not in ZZ or bool(ZZ(value) % 2) elif self._assumption == 'odd': return value not in ZZ or not (ZZ(value) % 2) elif self._assumption == 'rational': return value not in QQ elif self._assumption == 'irrational': return value in QQ elif self._assumption == 'real': return value not in RR elif self._assumption == 'imaginary': return value not in CC or CC(value).real() != 0 elif self._assumption == 'complex': return value not in CC