def xseries(self, all_conjugates=True): r"""Returns the corresponding x-series. Parameters ---------- all_conjugates : bool (default: True) If ``True``, returns all conjugates x-representations of this Puiseux t-series. If ``False``, only returns one representative. Returns ------- list List of PuiseuxXSeries representations of this PuiseuxTSeries. """ # obtain relevant rings: # o R = parent ring of curve # o L = parent ring of T-series # o S = temporary polynomial ring over base ring of T-series # o P = Puiseux series ring L = self.ypart.parent() t = L.gen() S = L.base_ring()['z'] z = S.gen() R = self.f.parent() x,y = R.gens() P = PuiseuxSeriesRing(L.base_ring(), str(x)) x = P.gen() # given x = alpha + lambda*t^e solve for t. this involves finding an # e-th root of either (1/lambda) or of lambda, depending on e's sign ## (A sign on a ramification index ? hm) e = self.ramification_index abse = abs(e) lamb = S(self.xcoefficient) order = self.order if e > 0: phi = lamb*z**e - 1 else: phi = z**abse - lamb mu = phi.roots(QQbar, multiplicities=False)[0] if all_conjugates: zeta_e=QQbar.zeta(abse) conjugates = [mu*zeta_e**k for k in range(abse)] else: conjugates = [mu] map(lambda x: x.exactify(), conjugates) # determine the resulting x-series xseries = [] for c in conjugates: t = self.ypart.parent().gen() fconj = self.ypart(c*t) p = P(fconj(x**(QQ(1)/e))) p = p.add_bigoh(QQ(order+1)/abse) xseries.append(p) return xseries
def braid_in_segment(f, x0, x1): """ Return the braid formed by the `y` roots of ``f`` when `x` moves from ``x0`` to ``x1``. INPUT: - ``f`` -- a polynomial in two variables - ``x0`` -- a complex number - ``x1`` -- a complex number OUTPUT: A braid. EXAMPLES:: sage: from sage.schemes.curves.zariski_vankampen import braid_in_segment # optional - sirocco sage: R.<x,y> = QQ[] sage: f = x^2 + y^3 sage: x0 = CC(1,0) sage: x1 = CC(1, 0.5) sage: braid_in_segment(f, x0, x1) # optional - sirocco s1 """ CC = ComplexField(64) (x, y) = f.variables() I = QQbar.gen() X0 = QQ(x0.real()) + I*QQ(x0.imag()) X1 = QQ(x1.real()) + I*QQ(x1.imag()) F0 = QQbar[y](f(X0, y)) y0s = F0.roots(multiplicities=False) strands = [followstrand(f, x0, x1, CC(a)) for a in y0s] complexstrands = [[(a[0], CC(a[1], a[2])) for a in b] for b in strands] centralbraid = braid_from_piecewise(complexstrands) initialstrands = [] y0aps = [c[0][1] for c in complexstrands] used = [] for y0ap in y0aps: distances = [((y0ap - y0).norm(), y0) for y0 in y0s] y0 = sorted(distances)[0][1] if y0 in used: raise ValueError("different roots are too close") used.append(y0) initialstrands.append([(0, CC(y0)), (1, y0ap)]) initialbraid = braid_from_piecewise(initialstrands) F1 = QQbar[y](f(X1,y)) y1s = F1.roots(multiplicities=False) finalstrands = [] y1aps = [c[-1][1] for c in complexstrands] used = [] for y1ap in y1aps: distances = [((y1ap - y1).norm(), y1) for y1 in y1s] y1 = sorted(distances)[0][1] if y1 in used: raise ValueError("different roots are too close") used.append(y1) finalstrands.append([(0, y1ap), (1, CC(y1))]) finallbraid = braid_from_piecewise(finalstrands) return initialbraid * centralbraid * finallbraid
def __init__(self, parent, x, prec=None, dx=[], dx_mode='linear_combination', valuation=None, check=True, reduce=True): r""" TESTS:: sage: R = ZpLC(2) sage: x = R(1, 10) # indirect doctest sage: x 1 + O(2^10) """ self._parent = parent p = parent.prime() pAdicGenericElement.__init__(self, parent) self._precision = parent.precision() if check: if isinstance(x, pAdicGenericElement): if parent.prime() != x.parent().prime(): raise TypeError("conversion between different p-adic rings/fields not supported") if prec is None: prec = x.precision_absolute() else: prec = min(prec, x.precision_absolute()) x = QQ(x) if isinstance(x, pRational): self._value = x else: self._value = pRational(p, QQ(x)) trunc = self._declare_new_element(dx, prec, dx_mode) if reduce: self._value = self._value.reduce(trunc)
def _richcmp_(self, other, op): r""" Compare this element with ``other``. TESTS:: sage: R = ZpLC(2) sage: x = R(1, 5) sage: y = R(128, 10) sage: z = x + y sage: x 1 + O(2^5) sage: z 1 + O(2^5) sage: x == z # Indirect doctest False sage: z - x 2^7 + O(2^10) """ if (self - other).is_zero(): return rich_to_bool(op, 0) else: return richcmp(QQ(self.lift()), QQ(other.lift()), op)
def orbital_angular_velocity(self, r, retrograde=False): r""" Return the angular velocity on a circular orbit. The angular velocity `\Omega` on a circular orbit of Boyer-Lindquist radial coordinate `r` around a Kerr black hole of parameters `(m, a)` is given by the formula .. MATH:: :label: Omega \Omega := \frac{\mathrm{d}\phi}{\mathrm{d}t} = \pm \frac{m^{1/2}}{r^{3/2} \pm a m^{1/2}} where `(t,\phi)` are the Boyer-Lindquist time and azimuthal coordinates and `\pm` is `+` (resp. `-`) for a prograde (resp. retrograde) orbit. INPUT: - ``r`` -- Boyer-Lindquist radial coordinate `r` of the circular orbit - ``retrograde`` -- (default: ``False``) boolean determining whether the orbit is retrograde or prograde OUTPUT: - Angular velocity `\Omega` computed according to Eq. :eq:`Omega` EXAMPLES:: sage: from kerrgeodesic_gw import KerrBH sage: a, m, r = var('a m r') sage: BH = KerrBH(a, m) sage: BH.orbital_angular_velocity(r) sqrt(m)/(a*sqrt(m) + r^(3/2)) sage: BH.orbital_angular_velocity(r, retrograde=True) sqrt(m)/(a*sqrt(m) - r^(3/2)) sage: KerrBH(0.9).orbital_angular_velocity(4.) # tol 1.0e-13 0.112359550561798 Orbital angular velocity around a Schwarzschild black hole:: sage: KerrBH(0, m).orbital_angular_velocity(r) sqrt(m)/r^(3/2) Orbital angular velocity on the prograde ISCO of an extreme Kerr black hole (`a=m`):: sage: EKBH = KerrBH(m, m) sage: EKBH.orbital_angular_velocity(EKBH.isco_radius()) 1/2/m """ m = self._m a = self._a # Eq. (2.16) in Bardeen, Press & Teukolsky, ApJ 178, 347 (1972) three_halves = QQ(3) / QQ(2) sm = sqrt(m) if retrograde: return -sm / (r**three_halves - a * sm) return sm / (r**three_halves + a * sm)
def demo3(): s = SimilaritySurfaceGenerators.right_angle_triangle(QQ(3), QQ(4)) sm, sb = s.get_bundle() sm.set_surface(sb) globals()['s'] = s globals()['sb'] = sb globals()['sm'] = sm
def __init__(self, R): """ Initialize self. TESTS:: sage: V = lie_conformal_algebras.N2(QQ) sage: TestSuite(V).run() """ n2dict =\ {('L','L'):{0:{('L',1):1}, 1:{('L',0): 2}, 3:{('C', 0):R(2).inverse_of_unit()}}, ('L','G1'):{0:{('G1',1):1}, 1:{('G1',0):3*R(2).\ inverse_of_unit()}}, ('L','G2'):{0:{('G2',1):1}, 1:{('G2',0):3*R(2).\ inverse_of_unit()}}, ('G1','G2'): {0:{('L',0):1,('J',1):R(2).inverse_of_unit()}, 1:{('J',0):1}, 2:{('C',0):R(3).inverse_of_unit()}}, ('L','J'): {0:{('J',1):1},1:{('J',0):1}}, ('J','J'): {1:{('C',0):R(3).inverse_of_unit()}}, ('J','G1'): {0:{('G1',0):1}}, ('J','G2'): {0:{('G2',0):-1}}} from sage.rings.rational_field import QQ weights = (2, 1, QQ(3 / 2), QQ(3 / 2)) parity = (0, 0, 1, 1) GradedLieConformalAlgebra.__init__(self, R, n2dict, names=('L', 'J', 'G1', 'G2'), central_elements=('C', ), weights=weights, parity=parity)
def is_hyperbolic(self, p): """ Checks if the quadratic form is a sum of hyperbolic planes over the p-adic numbers Q_p. REFERENCES: This criteria follows from Cassels's "Rational Quadratic Forms": - local invariants for hyperbolic plane (Lemma 2.4, p58) - direct sum formulas (Lemma 2.3 on p58) INPUT: `p` -- a prime number > 0 OUTPUT: boolean EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,1]) sage: Q.is_hyperbolic("infinity") False sage: Q.is_hyperbolic(2) False sage: Q.is_hyperbolic(3) False sage: Q.is_hyperbolic(5) ## Here -1 is a square, so it's true. True sage: Q.is_hyperbolic(7) False sage: Q.is_hyperbolic(13) ## Here -1 is a square, so it's true. True """ ## False for odd-dim'l forms if self.dim() % 2 != 0: return False ## True for the zero form if self.dim == 0: return True ## Compare local invariants ## (Note: since the dimension is even, the extra powers of 2 in ## self.det() := Det(2*Q) don't affect the answer!) m = ZZ(self.dim() // 2) if p == "infinity": return (self.signature() == 0) elif p == 2: return QQ(self.det() * (-1)**m).is_padic_square(p) and ( self.hasse_invariant(p) == (-1)**m ) ## Actually, this -1 is the Hilbert symbol (-1,-1)_p else: return QQ(self.det() * (-1)**m).is_padic_square(p) and (self.hasse_invariant(p) == 1)
def zoom_screen_box(self, x1, y1, x2, y2): r""" Scale picture by a factor fixing the point (xc,yc) in screen coordinates - ``factor`` -- rational scaling factor - ``xc`` -- rational or integer point in screen coordinates - ``yc`` -- rational or integer point in screen coordinates """ width = x2 - x1 height = y2 - y1 screen_width = self._editor.get_width() screen_height = self._editor.get_height() width_change = QQ(screen_width) / width height_change = QQ(screen_height) / height # Commenting this line out seems to have solved the label loss issue: #self.before_zoom_change() # proposed scale change: scale_change = min(width_change, height_change) new_scale = self._s * scale_change screen_center = self._editor.get_center() vertex1 = self.screen_to_math_coordinates(x1, y1) vertex2 = self.screen_to_math_coordinates(x2, y2) math_center_x = (vertex1[0] + vertex2[0]) / 2 math_center_y = (vertex1[1] + vertex2[1]) / 2 tx = screen_center[0] - (new_scale * math_center_x) ty = screen_center[1] + (new_scale * math_center_y) self.set_transform(new_scale, tx, ty)
def test_add_commutes(trials, verbose=False): r""" This is a simple demonstration of the :func:`random_testing` decorator and its recommended usage. We test that addition is commutative over rationals. EXAMPLES:: sage: from sage.misc.random_testing import test_add_commutes sage: test_add_commutes(2, verbose=True, seed=0) a == -4, b == 0 ... Passes! a == -1/2, b == -1/95 ... Passes! sage: test_add_commutes(10) sage: test_add_commutes(1000) # long time """ from sage.rings.rational_field import QQ for _ in range(trials): a = QQ.random_element() b = QQ.random_element() if verbose: print("a == {}, b == {} ...".format(a, b)) assert (a + b == b + a) if verbose: print("Passes!")
def set_transform(self, s, tx, ty): r""" Set the parts of the transformation which convert to screen coordinates. """ s = QQ(s) tx = QQ(tx) ty = QQ(ty) ratio = self._s / s if (ratio > QQ(999) / 1000) and (ratio < QQ(1001) / 1000): # ignore negligible change in scale! self._editor.get_canvas().move(ALL, RDF(tx - self._tx), RDF(ty - self._ty)) self._tx = self._field(tx) self._ty = self._field(ty) else: self.before_zoom_change() scale = 1 / ratio offset_x = ((self._s * tx) - (self._tx * s)) / (self._s - s) offset_y = ((self._s * ty) - (self._ty * s)) / (self._s - s) self._editor.get_canvas().scale(ALL, RDF(offset_x), RDF(offset_y), RDF(scale), RDF(scale)) self._s = self._field(s) self._tx = self._field(tx) self._ty = self._field(ty) self.after_zoom_change()
def strict_inequality_symmetric_choice(k, left, right): r""" TESTS:: sage: from partitioner import strict_inequality_symmetric_choice sage: S = Set(srange(5)) sage: for s in S.subsets(): ....: L = tuple(s) ....: R = tuple(S.difference(s)) ....: a = strict_inequality_symmetric_choice(5, L, R) ....: b = strict_inequality_symmetric_choice(5, R, L) ....: assert a != b sage: strict_inequality_symmetric_choice(1, [], [0]) True """ from sage.rings.rational_field import QQ assert not set(left) & set(right) center = QQ(k - 1) / QQ(2) def weight(t): return -(center + 1 - (t-center).abs()) def total(T): return sum(weight(t) for t in T) def rule(T): return total(T), sorted((weight(t), t) for t in T) return rule(left) > rule(right)
def cyclotomic_to_alpha(cyclo): """ Convert a list of indices of cyclotomic polynomials to a list of rational numbers. The input represents a product of cyclotomic polynomials. The output is the list of arguments of the roots of the given product of cyclotomic polynomials. This is the inverse of :func:`alpha_to_cyclotomic`. EXAMPLES:: sage: from sage.modular.hypergeometric_motive import cyclotomic_to_alpha sage: cyclotomic_to_alpha([1]) [0] sage: cyclotomic_to_alpha([2]) [1/2] sage: cyclotomic_to_alpha([5]) [1/5, 2/5, 3/5, 4/5] sage: cyclotomic_to_alpha([1,2,3,6]) [0, 1/6, 1/3, 1/2, 2/3, 5/6] sage: cyclotomic_to_alpha([2,3]) [1/3, 1/2, 2/3] """ alpha = [] for d in cyclo: if d == 1: alpha.append(QQ.zero()) else: for k in ZZ(d).coprime_integers(d): alpha.append(QQ((k, d))) return sorted(alpha)
def _cmp_(self, other): r""" Compare this element with ``other``. TESTS:: sage: R = ZpLC(2) sage: x = R(1, 5) sage: y = R(128, 10) sage: z = x + y sage: x 1 + O(2^5) sage: z 1 + O(2^5) sage: x == z # Indirect doctest False sage: z - x 2^7 + O(2^10) """ if (self - other).is_zero(): return 0 else: return QQ(self.lift())._cmp_(QQ(other.lift()))
def is_hyperbolic(self, p): r""" Check if the quadratic form is a sum of hyperbolic planes over the `p`-adic numbers `\QQ_p` or over the real numbers `\RR`. REFERENCES: This criteria follows from Cassels's "Rational Quadratic Forms": - local invariants for hyperbolic plane (Lemma 2.4, p58) - direct sum formulas (Lemma 2.3, p58) INPUT: - `p` -- a prime number > 0 or `-1` for the infinite place OUTPUT: boolean EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,1]) sage: Q.is_hyperbolic(-1) False sage: Q.is_hyperbolic(2) False sage: Q.is_hyperbolic(3) False sage: Q.is_hyperbolic(5) ## Here -1 is a square, so it's true. True sage: Q.is_hyperbolic(7) False sage: Q.is_hyperbolic(13) ## Here -1 is a square, so it's true. True """ ## False for odd-dim'l forms if self.dim() % 2: return False ## True for the zero form if not self.dim(): return True ## Compare local invariants ## Note: since the dimension is even, the extra powers of 2 in ## self.det() := Det(2*Q) don't affect the answer! m = ZZ(self.dim() // 2) if p == -1: return self.signature() == 0 if p == 2: return (QQ(self.det() * (-1)**m).is_padic_square(p) and self.hasse_invariant(p) == (-1)**m.binomial(2) ) # here -1 is hilbert_symbol(-1,-1,2) return (QQ(self.det() * (-1)**m).is_padic_square(p) and self.hasse_invariant(p) == 1)
def __init__(self, f, x0, singular_data, order=None): r"""Initialize a PuiseuxTSeries using a set of :math:`\pi = \{\tau\}` data. Parameters ---------- f, x, y : polynomial A plane algebraic curve. x0 : complex The x-center of the Puiseux series expansion. singular_data : list The output of :func:`singular`. t : variable The variable in which the Puiseux t series is represented. """ R = f.parent() x, y = R.gens() extension_polynomial, xpart, ypart = singular_data L = LaurentSeriesRing(ypart.base_ring(), 't') t = L.gen() self.f = f self.t = t self._xpart = xpart self._ypart = ypart # store x-part attributes. handle the centered at infinity case self.x0 = x0 if x0 == infinity: x0 = QQ(0) self.center = x0 # extract and store information about the x-part of the puiseux series xpart = xpart(t, 0) xpartshift = xpart - x0 ramification_index, xcoefficient = xpartshift.laurent_polynomial( ).dict().popitem() self.xcoefficient = xcoefficient self.ramification_index = QQ(ramification_index).numerator() self.xpart = xpart # extract and store information about the y-part of the puiseux series self.ypart = L(ypart(t, 0)) self._initialize_extension(extension_polynomial) # determine the initial order. See the order property val = L(ypart(t, O(t))).prec() self._singular_order = 0 if val == infinity else val self._regular_order = self._p.degree(x) # extend to have at least two elements self.extend(nterms=1) # the curve, x-part, and terms output by puiseux make the puiseux # series unique. any mutability only adds terms self.__parent = self.ypart.parent() self._hash = hash((self.f, self.xpart, self.ypart))
def local_density(self, p, m): """ Gives the local density -- should be called by the user. =) NOTE: This screens for imprimitive forms, and puts the quadratic form in local normal form, which is a *requirement* of the routines performing the computations! INPUT: `p` -- a prime number > 0 `m` -- an integer OUTPUT: a rational number EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1,1]) ## NOTE: This is already in local normal form for *all* primes p! sage: Q.local_density(p=2, m=1) 1 sage: Q.local_density(p=3, m=1) 8/9 sage: Q.local_density(p=5, m=1) 24/25 sage: Q.local_density(p=7, m=1) 48/49 sage: Q.local_density(p=11, m=1) 120/121 """ n = self.dim() if (n == 0): raise TypeError("Oops! We currently don't handle 0-dim'l forms. =(") ## Find the local normal form and p-scale of Q -- Note: This uses the valuation ordering of local_normal_form. ## TO DO: Write a separate p-scale and p-norm routines! Q_local = self.local_normal_form(p) if n == 1: p_valuation = valuation(Q_local[0, 0], p) else: p_valuation = min(valuation(Q_local[0, 0], p), valuation(Q_local[0, 1], p)) ## If m is less p-divisible than the matrix, return zero if ( (m != 0) and (valuation(m, p) < p_valuation) ): ## Note: The (m != 0) condition protects taking the valuation of zero. return QQ(0) ## If the form is imprimitive, rescale it and call the local density routine p_adjustment = QQ(1) / p**p_valuation m_prim = QQ(m) / p**p_valuation Q_prim = Q_local.scale_by_factor(p_adjustment) ## Return the densities for the reduced problem return Q_prim.local_density_congruence(p, m_prim)
def single_right_click(self, event): from sage.rings.rational_field import QQ x = self._editor.get_canvas().canvasx(event.x) y = self._editor.get_canvas().canvasy(event.y) bundle=self._editor.get_surface_bundle() if bundle is None: pass else: bundle.zoom(QQ(7)/QQ(8),x,y)
def gamma__exact(n): """ Evaluates the exact value of the gamma function at an integer or half-integer argument. EXAMPLES:: sage: gamma__exact(4) 6 sage: gamma__exact(3) 2 sage: gamma__exact(2) 1 sage: gamma__exact(1) 1 sage: gamma__exact(1/2) sqrt(pi) sage: gamma__exact(3/2) 1/2*sqrt(pi) sage: gamma__exact(5/2) 3/4*sqrt(pi) sage: gamma__exact(7/2) 15/8*sqrt(pi) sage: gamma__exact(-1/2) -2*sqrt(pi) sage: gamma__exact(-3/2) 4/3*sqrt(pi) sage: gamma__exact(-5/2) -8/15*sqrt(pi) sage: gamma__exact(-7/2) 16/105*sqrt(pi) """ from sage.all import sqrt ## SANITY CHECK if (not n in QQ) or (denominator(n) > 2): raise TypeError, "Oops! You much give an integer or half-integer argument." if (denominator(n) == 1): if n <= 0: return infinity if n > 0: return factorial(n - 1) else: ans = QQ(1) while (n != QQ(1) / 2): if (n < 0): ans *= QQ(1) / n n = n + 1 elif (n > 0): n = n - 1 ans *= n ans *= sqrt(pi) return ans
def test_cuberoot(self): # recenter cuberoot(x) at x+1 G = (y + 1)**3 - (x + 1) S = newton_iteration(G, 9).truncate(x, 10) + 1 z = var('z') series = taylor(z**(QQ(1) / QQ(3)), z, 1, 9) series = R(series.subs({z: x + 1})) self.assertEqual(S, series)
def corrected_voronoi_diagram(points): r""" Compute a Voronoi diagram of a set of points with rational coordinates, such that the given points are granted to lie one in each bounded region. INPUT: - ``points`` -- a list of complex numbers OUTPUT: A VoronoiDiagram constructed from rational approximations of the points, with the guarantee that each bounded region contains exactly one of the input points. EXAMPLES:: sage: from sage.schemes.curves.zariski_vankampen import corrected_voronoi_diagram sage: points = (2, I, 0.000001, 0, 0.000001*I) sage: V = corrected_voronoi_diagram(points) sage: V The Voronoi diagram of 9 points of dimension 2 in the Rational Field sage: V.regions() {P(-7, 0): A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 4 vertices and 2 rays, P(0, -7): A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 4 vertices and 2 rays, P(0, 0): A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 4 vertices, P(0, 1): A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 5 vertices, P(0, 1/1000000): A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 4 vertices, P(0, 7): A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 3 vertices and 2 rays, P(1/1000000, 0): A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 5 vertices, P(2, 0): A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 5 vertices, P(7, 0): A 2-dimensional polyhedron in QQ^2 defined as the convex hull of 2 vertices and 2 rays} """ prec = 53 point_coordinates = [(p.real(), p.imag()) for p in points] while True: RF = RealField(prec) apprpoints = {(QQ(RF(p[0])), QQ(RF(p[1]))): p for p in point_coordinates} added_points = 3 * max(map(abs, flatten(apprpoints))) + 1 configuration = list(apprpoints.keys()) + [(added_points, 0), (-added_points, 0), (0, added_points), (0, -added_points)] V = VoronoiDiagram(configuration) valid = True for r in V.regions().items(): if not r[1].rays() and not r[1].interior_contains( apprpoints[r[0].affine()]): prec += 53 valid = False break if valid: break return V
def newton_data(H, exceptional=False): r"""Determines the "newton data" associated with each side of the polygon. For each side :math:`\Delta` of the Newton polygon of `H` we associate the data :math:`(q,m,l,`phi)` where .. math:: \Delta: qj + mi = l \\ \phi_{\Delta}(t) = \sum_{(i,j) \in \Delta} a_{ij} t^{(i-i_0)/q} Here, :math:`a_ij x^j y_i` is a term in the polynomial :math:`H` and :math:`i_0` is the smallest value of :math:`i` belonging to the polygon side :math:`\Delta`. Parameters ---------- H : sympy.Poly Polynomial in `x` and `y`. Returns ------- list A list of the tuples :math:`(q,m,l,\phi)`. """ R = H.parent() x, y = R.gens() if exceptional: newton = newton_polygon_exceptional(H) else: newton = newton_polygon(H) # special case when the newton polygon is a single point if len(newton[0]) == 1: return [] # for each side dtermine the corresponding newton data: side slope # information and corresponding side characteristic polynomial, phi result = [] for side in newton: i0, j0 = side[0] i1, j1 = side[1] slope = QQ(j1 - j0) / QQ(i1 - i0) q = slope.denom() m = -slope.numer() l = min(q * j0 + m * i0, q * j1 + m * i1) phi = sum( H.coefficient({ y: i, x: j }) * x**((i - i0) / q) for i, j in side) phi = phi.univariate_polynomial() result.append((q, m, l, phi)) return result
def construct_from_file(cls, polyfile): """ Construct an RNAPolytope from a file in polyfile format. Keyword arguments: polyfile -- A file representing the polytope structure """ filebase = os.path.splitext(polyfile)[0] # Construct the polytope try: # If the polytope is available in a pickle, we should use that thepoly = load( filebase) # Attempt to load the polytope from a pickle file # If the pickled polytope is obsolete, however, we need to rebuild it if cls.poly_is_obsolete(thepoly): raise UnpicklingError except (IOError, UnpicklingError, AssertionError): # In any of these exception cases, the load failed, so we generate the polytope from the points # Read the point data from the specified file points = [] with open(polyfile) as f: for line in f: newline = line.split('#')[ 0] # Only use content before the comment symbol if newline.strip() != '': elts = newline.split() structure = elts[1] multiloops = QQ(elts[2]) unpaired = QQ(elts[3]) branches = QQ(elts[4]) w = QQ(elts[5]) energy = QQ(elts[6]) coords = (multiloops, unpaired, branches, w) newpoint = namedtuple( 'RNApoint', ['structure', 'vector', 'energy']) newpoint.vector = coords newpoint.structure = structure newpoint.energy = energy points.append(newpoint) thepoly = RNAPolytope(points) thepoly._pickle_version = pickle_version thepoly._build_normal_fan() thepoly._build_d1_slices() thepoly.dump(filebase, -1) return thepoly
def extract(cls, obj): """ Takes an object extracted by the json parser and decodes the special-formating dictionaries used to store special types. """ if isinstance(obj, dict) and 'data' in obj: if len(obj) == 2 and '__ComplexList__' in obj: return [complex(*v) for v in obj['data']] elif len(obj) == 2 and '__QQList__' in obj: return [QQ(tuple(v)) for v in obj['data']] elif len(obj) == 3 and '__NFList__' in obj and 'base' in obj: base = cls.extract(obj['base']) return [cls._extract(base, c) for c in obj['data']] elif len(obj) == 2 and '__IntDict__' in obj: return {Integer(k): cls.extract(v) for k,v in obj['data']} elif len(obj) == 3 and '__Vector__' in obj and 'base' in obj: base = cls.extract(obj['base']) return vector([cls._extract(base, v) for v in obj['data']]) elif len(obj) == 2 and '__Rational__' in obj: return Rational(*obj['data']) elif len(obj) == 3 and '__RealLiteral__' in obj and 'prec' in obj: return LmfdbRealLiteral(RealField(obj['prec']), obj['data']) elif len(obj) == 2 and '__complex__' in obj: return complex(*obj['data']) elif len(obj) == 3 and '__Complex__' in obj and 'prec' in obj: return ComplexNumber(ComplexField(obj['prec']), *obj['data']) elif len(obj) == 3 and '__NFElt__' in obj and 'parent' in obj: return cls._extract(cls.extract(obj['parent']), obj['data']) elif len(obj) == 3 and ('__NFRelative__' in obj or '__NFAbsolute__' in obj) and 'vname' in obj: poly = cls.extract(obj['data']) return NumberField(poly, name=obj['vname']) elif len(obj) == 2 and '__NFCyclotomic__' in obj: return CyclotomicField(obj['data']) elif len(obj) == 2 and '__IntegerRing__' in obj: return ZZ elif len(obj) == 2 and '__RationalField__' in obj: return QQ elif len(obj) == 3 and '__RationalPoly__' in obj and 'vname' in obj: return QQ[obj['vname']]([QQ(tuple(v)) for v in obj['data']]) elif len(obj) == 4 and '__Poly__' in obj and 'vname' in obj and 'base' in obj: base = cls.extract(obj['base']) return base[obj['vname']]([cls._extract(base, c) for c in obj['data']]) elif len(obj) == 5 and '__PowerSeries__' in obj and 'vname' in obj and 'base' in obj and 'prec' in obj: base = cls.extract(obj['base']) prec = infinity if obj['prec'] == 'inf' else int(obj['prec']) return base[[obj['vname']]]([cls._extract(base, c) for c in obj['data']], prec=prec) elif len(obj) == 2 and '__date__' in obj: return datetime.datetime.strptime(obj['data'], "%Y-%m-%d").date() elif len(obj) == 2 and '__time__' in obj: return datetime.datetime.strptime(obj['data'], "%H:%M:%S.%f").time() elif len(obj) == 2 and '__datetime__' in obj: return datetime.datetime.strptime(obj['data'], "%Y-%m-%d %H:%M:%S.%f") return obj
def num_and_weighted_num(it): from sage.rings.integer_ring import ZZ from sage.rings.rational_field import QQ s = QQ.zero() n = ZZ.zero() for _, aut in it: n += ZZ.one() if aut is None: s += QQ.one() else: s += QQ((1, aut.group_cardinality())) return n, s
def newton_data(H, exceptional=False): r"""Determines the "newton data" associated with each side of the polygon. For each side :math:`\Delta` of the Newton polygon of `H` we associate the data :math:`(q,m,l,`phi)` where .. math:: \Delta: qj + mi = l \\ \phi_{\Delta}(t) = \sum_{(i,j) \in \Delta} a_{ij} t^{(i-i_0)/q} Here, :math:`a_ij x^j y_i` is a term in the polynomial :math:`H` and :math:`i_0` is the smallest value of :math:`i` belonging to the polygon side :math:`\Delta`. Parameters ---------- H : sympy.Poly Polynomial in `x` and `y`. Returns ------- list A list of the tuples :math:`(q,m,l,\phi)`. """ R = H.parent() x,y = R.gens() if exceptional: newton = newton_polygon_exceptional(H) else: newton = newton_polygon(H) # special case when the newton polygon is a single point if len(newton[0]) == 1: return [] # for each side dtermine the corresponding newton data: side slope # information and corresponding side characteristic polynomial, phi result = [] for side in newton: i0,j0 = side[0] i1,j1 = side[1] slope = QQ(j1-j0)/QQ(i1-i0) q = slope.denom() m = -slope.numer() l = min(q*j0 + m*i0, q*j1 + m*i1) phi = sum(H.coefficient({y:i,x:j})*x**((i-i0)/q) for i,j in side) phi = phi.univariate_polynomial() result.append((q,m,l,phi)) return result
def test_bigoh(self): R = PuiseuxSeriesRing(QQ, 'x') x = R.gen() half = QQ(1) / QQ(2) p = x**(3 * half) q = p.add_bigoh(half) self.assertEqual(q.prec(), half) self.assertEqual(q.laurent_part.prec(), 1) p = x**(3 * half) q = p.add_bigoh(4) self.assertEqual(q.prec(), 4) self.assertEqual(q.laurent_part.prec(), 8)
def test_sub(self): R = PuiseuxSeriesRing(QQ, 't') t = R.gen() half = QQ(1) / QQ(2) p = 1 + t q = 1 + t + t**2 r = t**2 self.assertEqual(q - p, r) p = 1 + t**half q = 1 + t**half + t r = t self.assertEqual(q - p, r)
def family_two(n, backend=None): r""" Return the vector configuration of the simplicial arrangement `A(n,1)` from the family `\mathcal R(1)` in Grunbaum's list [Gru]_. The arrangement will have an ``n`` hyperplanes, with ``n`` even, consisting of the edges of the regular `n/2`-gon and the `n/2` lines of mirror symmetry. INPUT: - ``n`` -- integer. ``n`` `\geq 6`. The number of lines in the arrangement. - ``backend`` -- string (default = ``None``). The backend to use. OUTPUT: A vector configuration. EXAMPLES:: sage: from cn_hyperarr.infinite_families import * sage: pf = family_two(8,'normaliz'); pf # optional - pynormaliz Vector configuration of 8 vectors in dimension 3 The number of lines must be even:: sage: pf3 = family_two(3,'normaliz'); # optional - pynormaliz Traceback (most recent call last): ... AssertionError: n must be even The number of lines must be at least 6:: sage: pf4 = family_two(4,'normaliz') # optional - pynormaliz Traceback (most recent call last): ... ValueError: n (=2) must be an integer greater than 2 """ assert n % 2 == 0, "n must be even" reg_poly = polytopes.regular_polygon(n / QQ(2), backend='normaliz') reg_cone = Polyhedron( rays=[list(v.vector()) + [1] for v in reg_poly.vertices()], backend=backend) vecs = [h.A() for h in reg_cone.Hrepresentation()] z = QQbar.zeta(n) vecs += [[(z**k).real(), (z**k).imag(), 0] for k in range(n / QQ(2))] return VectorConfiguration(vecs, backend=backend)
def _test__jacobi_torsion_point(phi, weight, torsion_point): r""" Given a list of power series, which are the corrected Taylor coefficients of a Jacobi form, return the specialization to ``torsion_point``. INPUT: - ``phi`` -- A Fourier expansion of a Jacobi form. - ``weight`` -- An integer. - ``torsion_point`` -- A rational. OUPUT: - A power series. TESTS: See jacobi_form_by_taylor_expansion. sage: from psage.modform.jacobiforms.jacobiformd1nn_fegenerators import * sage: from psage.modform.jacobiforms.jacobiformd1nn_types import * sage: precision = 50 sage: weight = 10; index = 7 sage: phis = [jacobi_form_by_taylor_expansion(i, JacobiFormD1NNFilter(precision, index), weight) for i in range(JacobiFormD1NN_Gamma(weight, index)._rank(QQ))] sage: fs = [JacobiFormD1NNFactory_class._test__jacobi_torsion_point(phi, weight, 2/3) for phi in phis] sage: fs_vec = [vector(f.padded_list(precision)) for f in fs] sage: mf_span = span([vector(b.qexp(precision).padded_list(precision)) for b in ModularForms(GammaH(9, [4]), weight).basis()]) sage: all(f_vec in mf_span for f_vec in fs_vec) True FIXME: The case of torsion points of order 5, which should lead to forms for Gamma1(25) fails even in the simplest case. """ from sage.rings.all import CyclotomicField K = CyclotomicField(QQ(torsion_point).denominator()) zeta = K.gen() R = PowerSeriesRing(K, 'q') q = R.gen(0) ch = JacobiFormD1WeightCharacter(weight) coeffs = dict((n, QQ(0)) for n in range(phi.precision().index())) for (n, r) in phi.precision().monoid_filter(): coeffs[n] += zeta**r * phi[(ch, (n, r))] return PowerSeriesRing(K, 'q')(coeffs)
def _element_constructor_(self, data, *extra_args): r""" Build an element of that field. TESTS:: sage: CFF(1/3) [0; 3] sage: CFF([1,3,2]) [1; 3, 2] sage: CFF(CFF(1/3)) [0; 3] """ if isinstance(data, FieldElement) and data.parent() is self: data = list(data) if extra_args: print "data",data,type(data) print "extra_args",extra_args, type(extra_args[0]) data = list(extra_args[0]) if not isinstance(data, (tuple,list)): from sage.rings.rational_field import QQ data = QQ(data).continued_fraction_list() else: from continued_fraction import check_and_reduce_pair data,_ = check_and_reduce_pair(data, []) return self.element_class(data)
def quadratic_L_function__exact(n, d): r""" Returns the exact value of a quadratic twist of the Riemann Zeta function by `\chi_d(x) = \left(\frac{d}{x}\right)`. The input `n` must be a critical value. EXAMPLES:: sage: quadratic_L_function__exact(1, -4) 1/4*pi sage: quadratic_L_function__exact(-4, -4) 5/2 sage: quadratic_L_function__exact(2, 1) 1/6*pi^2 TESTS:: sage: quadratic_L_function__exact(2, -4) Traceback (most recent call last): ... TypeError: n must be a critical value (i.e. odd > 0 or even <= 0) REFERENCES: - [Iwa1972]_, pp 16-17, Special values of `L(1-n, \chi)` and `L(n, \chi)` - [IR1990]_ - [Was1997]_ """ from sage.all import SR, sqrt if n <= 0: return QuadraticBernoulliNumber(1-n,d)/(n-1) elif n >= 1: # Compute the kind of critical values (p10) if kronecker_symbol(fundamental_discriminant(d), -1) == 1: delta = 0 else: delta = 1 # Compute the positive special values (p17) if ((n - delta) % 2 == 0): f = abs(fundamental_discriminant(d)) if delta == 0: GS = sqrt(f) else: GS = I * sqrt(f) ans = SR(ZZ(-1)**(1+(n-delta)/2)) ans *= (2*pi/f)**n ans *= GS # Evaluate the Gauss sum here! =0 ans *= QQ.one()/(2 * I**delta) ans *= QuadraticBernoulliNumber(n,d)/factorial(n) return ans else: if delta == 0: raise TypeError("n must be a critical value (i.e. even > 0 or odd < 0)") if delta == 1: raise TypeError("n must be a critical value (i.e. odd > 0 or even <= 0)")
def relation_space(v): r""" Relation space of the given vector ``v`` This is the sub vector space of `\QQ^d` given as the kernel of the map `n \mapsto n \cdot \lambda`. The dimension is `d - rank`. EXAMPLES:: sage: from surface_dynamics.misc.linalg import relation_space sage: K.<sqrt2> = QuadraticField(2) sage: v3 = vector([sqrt2, 1, 1+sqrt2]) sage: relation_space(v3) Vector space of degree 3 and dimension 1 over Rational Field Basis matrix: [ 1 1 -1] sage: v4 = vector([sqrt2, 1, 1+sqrt2, 1-sqrt2]) sage: relation_space(v4) Vector space of degree 4 and dimension 2 over Rational Field Basis matrix: [ 1 0 -1/2 1/2] [ 0 1 -1/2 -1/2] sage: v = vector([1,2,5,3]) sage: relation_space(v) Vector space of degree 4 and dimension 3 over Rational Field Basis matrix: [ 1 0 0 -1/3] [ 0 1 0 -2/3] [ 0 0 1 -5/3] The relation space has some covariance relation with respect to matrix actions:: sage: m3 = matrix(3, [1,-1,0,2,-3,4,5,-2,2]) sage: relation_space(v3 * m3) == relation_space(v3) * ~m3.transpose() True sage: relation_space(m3 * v3) == relation_space(v3) * ~m3 True sage: m4 = matrix(4, [1,-1,0,1,2,-3,0,4,5,3,-2,2,1,1,1,1]) sage: relation_space(v4 * m4) == relation_space(v4) * ~m4.transpose() True sage: relation_space(m4 * v4) == relation_space(v4) * ~m4 True """ from sage.matrix.constructor import matrix try: m_lengths = matrix([u.vector() for u in v]) except AttributeError: from sage.rings.rational_field import QQ v = [QQ.coerce(i) for i in v] m_lengths = matrix([[i] for i in v]) return m_lengths.left_kernel()
def deformation_space(lengths): r""" Deformation space of the given ``lengths`` This is the smallest vector space defined over `\QQ` that contains the vector ``lengths``. Its dimension is `rank`. EXAMPLES:: sage: from surface_dynamics.misc.linalg import deformation_space sage: K.<sqrt2> = QuadraticField(2) sage: v3 = vector([sqrt2, 1, 1+sqrt2]) sage: deformation_space(v3) Vector space of degree 3 and dimension 2 over Rational Field Basis matrix: [1 0 1] [0 1 1] sage: v4 = vector([sqrt2, 1, 1+sqrt2, 1-sqrt2]) sage: deformation_space(v4) Vector space of degree 4 and dimension 2 over Rational Field Basis matrix: [ 1 0 1 -1] [ 0 1 1 1] sage: v = vector([1, 5, 2, 9]) sage: deformation_space(v) Vector space of degree 4 and dimension 1 over Rational Field Basis matrix: [1 5 2 9] The deformation space has some covariance relation with respect to matrix actions:: sage: m3 = matrix(3, [1,-1,0,2,-3,4,5,-2,2]) sage: deformation_space(v3 * m3) == deformation_space(v3) * m3 True sage: deformation_space(m3 * v3) == deformation_space(v3) * m3.transpose() True sage: m4 = matrix(4, [1,-1,0,1,2,-3,0,4,5,3,-2,2,1,1,1,1]) sage: deformation_space(v4 * m4) == deformation_space(v4) * m4 True sage: deformation_space(m4 * v4) == deformation_space(v4) * m4.transpose() True """ from sage.matrix.constructor import matrix try: m_lengths = matrix([u.vector() for u in lengths]) except AttributeError: from sage.rings.rational_field import QQ lengths = [QQ.coerce(i) for i in lengths] m_lengths = matrix([[i] for i in lengths]) return m_lengths.column_space()
def charpoly_reverse(self, g, var='x'): r""" Determines the characteristic polynomial `\det(I-gT)` sage: from sage.rings.number_field.galois_group import GaloisGroup_v3 sage: from sage.rings.number_field.artin_representation import ArtinRepresentation sage: K = NumberField(x^3 - 2, 'a') sage: G = GaloisGroup_v3(K, names='b2') sage: chi = ArtinRepresentation(G, [2, 0, -1]) sage: L = G.splitting_field() sage: for p in prime_range(5, 50): ... print p, chi.charpoly_reverse(G.artin_symbol(L.primes_above(p)[0])) 5 -x^2 + 1 7 x^2 + x + 1 11 -x^2 + 1 13 x^2 + x + 1 17 -x^2 + 1 19 x^2 + x + 1 23 -x^2 + 1 29 -x^2 + 1 31 x^2 - 2*x + 1 37 x^2 + x + 1 41 -x^2 + 1 43 x^2 - 2*x + 1 47 -x^2 + 1 """ if self.degree() == 0: return QQ.one() from sage.combinat.sf.sf import SymmetricFunctions S = SymmetricFunctions(QQ) p = S.powersum() e = S.elementary() deg = self.degree() traces = [self(g ** n) for n in range(1, deg+1)] x = PolynomialRing(QQ, var).gen() cp = QQ.one() for n in range(deg): mc = p(e[n+1]).monomial_coefficients() cp += (-1) ** (n+1) * x ** (n+1) * sum(mc[k] * prod(traces[j-1] for j in k) for k in mc.keys()) return cp
def alpha_to_cyclotomic(alpha): """ Convert from a list of rationals arguments to a list of integers. The input represents arguments of some roots of unity. The output represent a product of cyclotomic polynomials with exactly the given roots. Note that the multiplicity of `r/s` in the list must be independent of `r`; otherwise, a ``ValueError`` will be raised. This is the inverse of :func:`cyclotomic_to_alpha`. EXAMPLES:: sage: from sage.modular.hypergeometric_motive import alpha_to_cyclotomic sage: alpha_to_cyclotomic([0]) [1] sage: alpha_to_cyclotomic([1/2]) [2] sage: alpha_to_cyclotomic([1/5,2/5,3/5,4/5]) [5] sage: alpha_to_cyclotomic([1/6, 1/3, 1/2, 2/3, 5/6, 1]) [1, 2, 3, 6] sage: alpha_to_cyclotomic([1/3,2/3,1/2]) [2, 3] """ cyclo = [] Alpha = list(alpha) while Alpha: q = QQ(Alpha.pop()) n = q.numerator() d = q.denominator() for k in d.coprime_integers(d): if k != n: try: Alpha.remove(QQ((k, d))) except ValueError: raise ValueError("multiplicities not balanced") cyclo.append(d) return sorted(cyclo)
def residue(self): r""" denominator: each (1 - mon)^k in denom is replaced with -> mon^k numerator: evaluate at (1,1,...,1) OUTPUT: a pair '(degree, value)` EXAMPLES:: sage: from surface_dynamics.misc.multivariate_generating_series import MultivariateGeneratingSeriesRing sage: M = MultivariateGeneratingSeriesRing(2, 'x') sage: R = M.laurent_polynomial_ring() sage: x0,x1 = R.gens() sage: f = M.term(x0, [((1,1),2)]) sage: f.residue() (2, [(1, {(1, 1): 2})]) sage: f = M.term(x0, [((1,1),2)]) + M.term(1, [((1,0),1),((0,1),1),((1,1),1)]) sage: f.residue() (3, [(1, {(0, 1): 1, (1, 0): 1, (1, 1): 1})]) sage: f = M.term(x0, [((1,1),2)]) + M.term(1, [((1,0),1),((1,1),1)]) sage: f.residue() (2, [(1, {(1, 0): 1, (1, 1): 1}), (1, {(1, 1): 2})]) """ R = self.parent().laurent_polynomial_ring() one = QQ.one() values = {g: one for g in R.gens()} ans = [] d = -1 for den, num in self._data.items(): if den.degree() >= d: if den.degree() > d: ans = [] d = den.degree() num = QQ(num.subs(values)) if num.is_zero(): raise NotImplementedError('zero numerator') ans.append((num, den)) return d, ans
def _delta_invariant(P): r"""Computes the delta invariant of the singularity at :math:`u_0,v_0`. Parameters ---------- P : list A list of PuiseuxTSeries of `g = g(u,v)` centered at some `(u_0,v_0)` where `g` is a complex affine algebraic curve. Returns ------- int The delta invariant of the singularity :math:`(u_0, v_0)`. """ # compute the puiseux series at (u0,v0). get the parametric forms as well # as an x-representative of each parametric form Px = [p.xseries(all_conjugates=False)[0] for p in P] Px_all = [p.xseries(all_conjugates=True) for p in P] Px_all = [item for sublist in Px_all for item in sublist] # for each place compute its contribution to the delta invariant delta = QQ(0) for i in range(len(Px)): # compute Int of each x-representation. note that it's sufficient to # only look at the Puiseux series with the given v0 since, for all # other puiseux series, the contribution to Int() will be zero. Pxi = Px[i] j = Px_all.index(Pxi) IntPxi = Int(j, Px_all) # obtain the ramification index by retreiving the corresponding # parametric form. By definition, this parametric series satisfies # Y(t=0) = v0 ri = Pxi.ramification_index delta += QQ(ri * IntPxi - ri + 1) / 2 return delta.numerator()
def M_value(self): """ Return the `M` coefficient that appears in the trace formula. OUTPUT: a rational .. SEEALSO:: :meth:`canonical_scheme` EXAMPLES:: sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp sage: H = Hyp(alpha_beta=([1/6,1/3,2/3,5/6],[1/8,3/8,5/8,7/8])) sage: H.M_value() 729/4096 sage: Hyp(alpha_beta=(([1/2,1/2,1/2,1/2],[0,0,0,0]))).M_value() 256 sage: Hyp(cyclotomic=([5],[1,1,1,1])).M_value() 3125 """ up = QQ.prod(capital_M(d) for d in self._cyclo_up) down = QQ.prod(capital_M(d) for d in self._cyclo_down) return up / down
def one(self): r""" EXAMPLES:: sage: from surface_dynamics.misc.multivariate_generating_series import MultivariateGeneratingSeriesRing sage: M = MultivariateGeneratingSeriesRing('x', 2) sage: M.zero() 0 sage: M.zero().parent() is M True sage: M.one().is_one() True """ return self._element_constructor_(QQ.one())
def random_element(self, *args, **kwds): """ Return a somewhat random continued fraction (the result is either finite or ultimately periodic). INPUT: - ``args``, ``kwds`` - arguments passed to ``QQ.random_element`` EXAMPLES:: sage: CFF.random_element() # random [0; 4, 7] """ from sage.rings.rational_field import QQ return self(QQ.random_element())
def charpoly(self, g, var='x'): r""" Determines the characteristic polynomial `\det(I-gT)` """ if self.degree() == 0: return QQ.one() from sage.combinat.sf.sf import SymmetricFunctions S = SymmetricFunctions(QQ) p = S.powersum() e = S.elementary() deg = self.degree() traces = [self(g ** n) for n in range(1, deg+1)] x = PolynomialRing(QQ, var).gen() cp = x ** deg for n in range(deg): mc = p(e[n+1]).monomial_coefficients() cp += (-1) ** (n+1) * x ** (deg-1-n) * sum(mc[k] * prod(traces[j-1] for j in k) for k in mc.keys()) return cp
def capital_M(n): """ Auxiliary function, used to describe the canonical scheme. INPUT: - ``n`` -- an integer OUTPUT: a rational EXAMPLES:: sage: from sage.modular.hypergeometric_motive import capital_M sage: [capital_M(i) for i in range(1,8)] [1, 4, 27, 64, 3125, 432, 823543] """ n = ZZ(n) return QQ.prod(d ** (d * moebius(n / d)) for d in divisors(n))
def construct_from_maass_products(ring, weight, products, is_basis = True, provides_maass_spezialschar = False, is_integral = False, lazy_rank_check = True) : r""" Pass the return value of spanning_maass_products of a space of Siegel modular forms of same type. This will return a space using these forms. Whenever ``is_basis`` is False the the products are first filtered to yield a basis. """ assert QQ.has_coerce_map_from(ring.base_ring()) or ring.base_ring() is ZZ, \ "%s doesn't have rational base field" % ring dim = ring.graded_submodule(weight).dimension() ## if the products don't provide a basis, we have to choose one if not is_basis : ## we prefer to use Maass lifts, since they are very cheap maass_forms = []; non_maass_forms = [] for p in products : if len(p[0]) == 1 : maass_forms.append(p) else : non_maass_forms.append(p) monomials = set() lift_polys = [] products = [] for lifts, lift_poly in maass_forms + non_maass_forms : red_poly = ring(ring.relations().ring()(lift_poly))._reduce_polynomial() monomials = monomials.union(set(red_poly.monomials())) M = matrix( QQ, len(lift_polys) + 1, [ poly.monomial_coefficient(m) for poly in lift_polys + [lift_poly] for m in monomials] ) # TODO : Use linbox try : if magma(M).Rank() > len(lift_polys) : break except TypeError : for i in xrange(10) : Mp = matrix(Qp(random_prime(10**10), 10), M) if Mp.rank() > len(lift_polys) : break else : if lazy_rank_check : continue elif M.rank() <= len(lift_polys) : continue lift_polys.append(red_poly) products.append((lifts, red_poly)) if len(products) == dim : break else : raise ValueError, "products don't provide a basis" basis = [] if provides_maass_spezialschar : maass_form_indices = [] for i, (lifts, lift_poly) in enumerate(products) : e = ring(ring.relations().ring()(lift_poly)) if len(lifts) == 1 : l = lifts[0] e._set_fourier_expansion( SiegelModularFormG2MaassLift(l[0], l[1], ring.fourier_expansion_precision(), is_integral = is_integral) ) elif len(lifts) == 2 : (l0, l1) = tuple(lifts) e._set_fourier_expansion( EquivariantMonoidPowerSeries_LazyMultiplication( SiegelModularFormG2MaassLift(l0[0], l0[1], ring.fourier_expansion_precision(), is_integral = is_integral), SiegelModularFormG2MaassLift(l1[0], l1[1], ring.fourier_expansion_precision(), is_integral = is_integral) ) ) else : e._set_fourier_expansion( prod( SiegelModularFormG2MaassLift(l[0], l[1], ring.precision(), is_integral = is_integral) for l in lifts) ) basis.append(e) if provides_maass_spezialschar and len(lifts) == 1 : maass_form_indices.append(i) ss = ring._submodule(basis, grading_indices = (weight,), is_heckeinvariant = True) if provides_maass_spezialschar : maass_coords = [ ss([0]*i + [1] + [0]*(dim-i-1)) for i in maass_form_indices ] ss.maass_space.set_cache( SiegelModularFormG2Submodule_maassspace(ss, map(ss, maass_coords)) ) return ss
def gamma__exact(n): """ Evaluates the exact value of the `\Gamma` function at an integer or half-integer argument. EXAMPLES:: sage: gamma__exact(4) 6 sage: gamma__exact(3) 2 sage: gamma__exact(2) 1 sage: gamma__exact(1) 1 sage: gamma__exact(1/2) sqrt(pi) sage: gamma__exact(3/2) 1/2*sqrt(pi) sage: gamma__exact(5/2) 3/4*sqrt(pi) sage: gamma__exact(7/2) 15/8*sqrt(pi) sage: gamma__exact(-1/2) -2*sqrt(pi) sage: gamma__exact(-3/2) 4/3*sqrt(pi) sage: gamma__exact(-5/2) -8/15*sqrt(pi) sage: gamma__exact(-7/2) 16/105*sqrt(pi) TESTS:: sage: gamma__exact(1/3) Traceback (most recent call last): ... TypeError: you must give an integer or half-integer argument """ from sage.all import sqrt n = QQ(n) if denominator(n) == 1: if n <= 0: return infinity if n > 0: return factorial(n-1) elif denominator(n) == 2: ans = QQ.one() while n != QQ((1, 2)): if n < 0: ans /= n n += 1 elif n > 0: n += -1 ans *= n ans *= sqrt(pi) return ans else: raise TypeError("you must give an integer or half-integer argument")
def Kitaoka_mass_at_2(self): """ Returns the local mass of the quadratic form when `p=2`, according to Theorem 5.6.3 on pp108--9 of Kitaoka's Book "The Arithmetic of Quadratic Forms". INPUT: none OUTPUT: a rational number > 0 EXAMPLES:: sage: Q = DiagonalQuadraticForm(ZZ, [1,1,1]) sage: Q.Kitaoka_mass_at_2() ## WARNING: WE NEED TO CHECK THIS CAREFULLY! 1/2 """ ## Make a 0-dim'l quadratic form (for initialization purposes) Null_Form = copy.deepcopy(self) Null_Form.__init__(ZZ, 0) ## Step 0: Compute Jordan blocks and bounds of the scales to keep track of Jordan_Blocks = self.jordan_blocks_by_scale_and_unimodular(2) scale_list = [B[0] for B in Jordan_Blocks] s_min = min(scale_list) s_max = max(scale_list) ## Step 1: Compute dictionaries of the diagonal block and 2x2 block for each scale diag_dict = dict((i, Null_Form) for i in range(s_min-2, s_max + 4)) ## Initialize with the zero form dim2_dict = dict((i, Null_Form) for i in range(s_min, s_max + 4)) ## Initialize with the zero form for (s,L) in Jordan_Blocks: i = 0 while (i < L.dim()-1) and (L[i,i+1] == 0): ## Find where the 2x2 blocks start i = i + 1 if i < (L.dim() - 1): diag_dict[s] = L.extract_variables(range(i)) ## Diagonal Form dim2_dict[s+1] = L.extract_variables(range(i, L.dim())) ## Non-diagonal Form else: diag_dict[s] = L #print "diag_dict = ", diag_dict #print "dim2_dict = ", dim2_dict #print "Jordan_Blocks = ", Jordan_Blocks ################## START EDITING HERE ################## ## Compute q := sum of the q_j q = 0 for j in range(s_min, s_max + 1): if diag_dict[j].dim() > 0: ## Check that N_j is odd (i.e. rep'ns an odd #) if diag_dict[j+1].dim() == 0: q += Jordan_Blocks[j][1].dim() ## When N_{j+1} is "even", add n_j else: q += Jordan_Blocks[j][1].dim() + 1 ## When N_{j+1} is "odd", add n_j + 1 ## Compute P = product of the P_j P = QQ.one() for j in range(s_min, s_max + 1): tmp_m = dim2_dict[j].dim() // 2 P *= prod(QQ.one() - QQ(4**(-k)) for k in range(1, tmp_m + 1)) ## Compute the product E := prod_j (1 / E_j) E = QQ.one() for j in range(s_min - 1, s_max + 2): if (diag_dict[j-1].dim() == 0) and (diag_dict[j+1].dim() == 0) and \ ((diag_dict[j].dim() != 2) or (((diag_dict[j][0,0] - diag_dict[j][1,1]) % 4) != 0)): ## Deal with the complicated case: tmp_m = dim2_dict[j].dim() // 2 if dim2_dict[j].is_hyperbolic(2): E *= QQ(2) / (1 + 2**(-tmp_m)) else: E *= QQ(2) / (1 - 2**(-tmp_m)) else: E *= 2 ## DIAGNOSTIC #print "\nFinal Summary:" #print "nu =", nu #print "q = ", q #print "P = ", P #print "E = ", E ## Compute the exponent w w = QQ.zero() for j in range(s_min, s_max+1): n_j = Jordan_Blocks[j][1].dim() for k in range(j+1, s_max+1): n_k = Jordan_Blocks[k][1].dim() w += j * n_j * (n_k + QQ(n_j + 1) / 2) ## Step 5: Compute the local mass for the prime 2. mass_at_2 = (QQ(2)**(w - q)) * P * E return mass_at_2
class QQpApprox_element(RingElement,Approximation): # maybe should create a ApproximatedRingElement def __init__(self,parent,x,val=0,normalized=False): RingElement.__init__(self,parent) Approximation.__init__(self,parent) self._x = QQ(x) self._val = val self._normalized = normalized def _normalize(self): if not self._normalized: if self._x == 0: self._val = 0 else: powers = self.parent().uniformizer v = self._x.valuation(powers()) self._val += v if v > 0: self._x /= powers(v) elif v < 0: self._x *= powers(-v) self._normalized = True def parenthesis_level(self): if self._x.denominator() == 1: return 3 else: return 1 def _getitem_by_num(self,i): return self def is_zero(self): return self._x == 0 def _add_(self,other,**kwargs): parent = self.parent() selfval = self._val otherval = other._val if selfval == otherval: return QQpApprox_element(parent, self._x + other._x, selfval) if selfval > otherval: return QQpApprox_element(parent, self._x * parent.uniformizer(selfval-otherval) + other._x, otherval) else: return QQpApprox_element(self.parent(), self._x + other._x * parent.uniformizer(otherval-selfval), selfval) def __neg__(self,**kwargs): return QQpApprox_element(self.parent(), -self._x, self._val) def _sub_(self,other,**kwargs): parent = self.parent() selfval = self._val otherval = other._val if selfval == otherval: return QQpApprox_element(parent, self._x - other._x, selfval) if selfval > otherval: return QQpApprox_element(parent, self._x * parent.uniformizer(selfval-otherval) - other._x, otherval) else: return QQpApprox_element(self.parent(), self._x - other._x * parent.uniformizer(otherval-selfval), selfval) def _mul_(self,other,**kwargs): return QQpApprox_element(self.parent(), self._x * other._x, self._val + other._val, self._normalized and other._normalized) def _rmul_(self,other,**kwargs): return self._mul_(other,**kwargs) def _lmul_(self,other,**kwargs): return self._mul_(other,**kwargs) def __invert__(self,**kwargs): return QQpApprox_element(self.parent(), ~self._x, -self._val, self._normalized) def _div_(self,other,**kwargs): return QQpApprox_element(self.parent(), self._x / other._x, self._val - other._val, self._normalized and other._normalized) def valuation(self,lazylimit=Infinity): self._normalize() if self._x == 0: return Infinity else: return self._val def _repr_(self): self._normalize() if self._x == 0: return "0" elif self._val == 0: return "%s" % self._x else: return "%s*%s^%s" % (self._x, self.parent()._p, self._val) def __pow__(self,exp,**kwargs): return QQpApprox_element(self.parent(), self._x ** exp, self._val * exp, self._normalized) def __cmp__(self,other): v = self._val - other._val return cmp(self._x, other._x * self.parent().uniformizer(v)) def truncate(self,workprec): if workprec == Infinity: return self parent = self.parent() self._normalize() pow = workprec - self._val if pow <= 0: return QQpApprox_element(parent, 0, 0, True) modulo = parent.uniformizer(pow) num = self._x.numerator() % modulo denom = self._x.denominator() % modulo if denom != 1: _,inv,_ = denom.xgcd(modulo) num = (num * inv) % modulo return QQpApprox_element(parent, num, self._val, True) def log(self,workprec=Infinity): from sage.functions.log import log from sage.functions.other import floor if workprec is Infinity: raise ApproximationError("unable to compute log to infinite precision") parent = self.parent() pow = parent(-1) res = parent(0) t = parent(1) - self iter = workprec + floor(log(workprec)/log(parent._p)) + 1 for i in range(1,iter): pow *= t res += pow / parent(i) res = res.truncate(workprec) return res def exp(self,workprec=Infinity): from sage.functions.other import ceil if workprec is Infinity: raise ApproximationError("unable to compute exp to infinite precision") parent = self.parent() pow = parent(1) res = parent(1) val = self.valuation() iter = ceil(workprec / (val - 1/(parent._p-1))) + 1 for i in range(1,iter): pow *= self / parent(i) res += pow res = res.truncate(workprec) return res def teichmuller(self,workprec=Infinity): if workprec is Infinity: raise ApproximationError("unable compute Teichmuller lift to infinite precision") res = self.truncate(1) p = self.parent()._p for i in range(2,workprec+1): res = res ** p res = res.truncate(i) return res
def Min(Fun, p, ubRes, conj): r""" Local loop for Affine_minimal, where we check minimality at the prime p. First we bound the possible k in our transformations A = zp^k + b. See Theorems 3.3.2 and 3.3.3 in [Molnar]_. INPUT: - ``Fun`` -- a projective space morphisms. - ``p`` - a prime. - ``ubRes`` -- integer, the upper bound needed for Th. 3.3.3 in [Molnar]_. - ``conj`` -- a 2x2 matrix keeping track of the conjugation. OUTPUT: - Boolean -- ``True`` if ``Fun`` is minimal at ``p``, ``False`` otherwise. - a projective morphism minimal at ``p``. EXAMPLES:: sage: P.<x,y> = ProjectiveSpace(QQ, 1) sage: H = End(P) sage: f = H([149*x^2 + 39*x*y + y^2, -8*x^2 + 137*x*y + 33*y^2]) sage: from sage.schemes.projective.endPN_minimal_model import Min sage: Min(f, 3, -27000000, matrix(QQ,[[1, 0],[0, 1]])) ( Scheme endomorphism of Projective Space of dimension 1 over Rational Field Defn: Defined on coordinates by sending (x : y) to (181*x^2 + 313*x*y + 81*y^2 : -24*x^2 + 73*x*y + 151*y^2) , [3 4] [0 1] ) """ d = Fun.degree() AffFun = Fun.dehomogenize(1) R = AffFun.coordinate_ring() if R.is_field(): #want the polynomial ring not the fraction field R = R.ring() F = R(AffFun[0].numerator()) G = R(AffFun[0].denominator()) dG = G.degree() if dG > (d+1)/2: lowerBound = (-2*(G[dG]).valuation(p)/(2*dG - d + 1) + 1).floor() else: lowerBound = (-2*(F[d]).valuation(p)/(d-1) + 1).floor() upperBound = 2*(ubRes.valuation(p)) if upperBound < lowerBound: #There are no possible transformations to reduce the resultant. return Fun,conj else: #Looping over each possible k, we search for transformations to reduce the #resultant of F/G k = lowerBound Qb = PolynomialRing(QQ,'b') b = Qb.gen(0) Q = PolynomialRing(Qb,'z') z = Q.gen(0) while k <= upperBound: A = (p**k)*z + b Ft = Q(F(A) - b*G(A)) Gt = Q((p**k)*G(A)) Fcoeffs = Ft.coefficients(sparse=False) Gcoeffs = Gt.coefficients(sparse=False) coeffs = Fcoeffs + Gcoeffs RHS = (d + 1)*k/2 #If there is some b such that Res(phi^A) < Res(phi), we must have ord_p(c) > #RHS for each c in coeffs. #Make sure constant coefficients in coeffs satisfy the inequality. if all( QQ(c).valuation(p) > RHS for c in coeffs if c.degree() ==0 ): #Constant coefficients in coeffs have large enough valuation, so check #the rest. We start by checking if simply picking b=0 works if all(c(0).valuation(p) > RHS for c in coeffs): #A = z*p^k satisfies the inequalities, and F/G is not minimal #"Conjugating by", p,"^", k, "*z +", 0 newconj = matrix(QQ,2,2,[p**k,0,0,1]) minFun = Fun.conjugate(newconj) conj = conj*newconj minFun.normalize_coordinates() return minFun, conj #Otherwise we search if any value of b will work. We start by finding a #minimum bound on the valuation of b that is necessary. See Theorem 3.3.5 #in [Molnar, M.Sc. thesis]. bval = max([bCheck(coeff,RHS,p,b) for coeff in coeffs if coeff.degree() > 0]) #We scale the coefficients in coeffs, so that we may assume ord_p(b) is #at least 0 scaledCoeffs = [coeff(b*(p**bval)) for coeff in coeffs] #We now scale the inequalities, ord_p(coeff) > RHS, so that coeff is in #ZZ[b] scale = QQ(max([coeff.denominator() for coeff in scaledCoeffs])) normalizedCoeffs = [coeff*scale for coeff in scaledCoeffs] scaleRHS = RHS + scale.valuation(p) #We now search for integers that satisfy the inequality ord_p(coeff) > #RHS. See Lemma 3.3.6 in [Molnar, M.Sc. thesis]. bound = (scaleRHS+1).floor() bool,sol = blift(normalizedCoeffs,bound,p) #If bool is true after lifting, we have a solution b, and F/G is not #minimal. if bool: #Rescale, conjugate and return new map bsol = QQ(sol*(p**bval)) #"Conjugating by ", p,"^", k, "*z +", bsol newconj = matrix(QQ,2,2,[p**k,bsol,0,1]) minFun = Fun.conjugate(newconj) conj = conj*newconj minFun.normalize_coordinates() return minFun, conj k = k + 1 return Fun, conj
def test_comparison(ring): """ Check comparison with infinity INPUT: - ``ring`` -- a sub-ring of the real numbers OUTPUT: Various attempts are made to generate elements of ``ring``. An assertion is triggered if one of these elements does not compare correctly with plus/minus infinity. EXAMPLES:: sage: from sage.rings.infinity import test_comparison sage: rings = [ZZ, QQ, RR, RealField(200), RDF, RLF, AA, RIF] sage: for R in rings: ....: print('testing {}'.format(R)) ....: test_comparison(R) testing Integer Ring testing Rational Field testing Real Field with 53 bits of precision testing Real Field with 200 bits of precision testing Real Double Field testing Real Lazy Field testing Algebraic Real Field testing Real Interval Field with 53 bits of precision Comparison with number fields does not work:: sage: K.<sqrt3> = NumberField(x^2-3) sage: (-oo < 1+sqrt3) and (1+sqrt3 < oo) # known bug False The symbolic ring handles its own infinities, but answers ``False`` (meaning: cannot decide) already for some very elementary comparisons:: sage: test_comparison(SR) # known bug Traceback (most recent call last): ... AssertionError: testing -1000.0 in Symbolic Ring: id = ... """ from sage.symbolic.ring import SR from sage.rings.rational_field import QQ elements = [-1e3, 99.9999, -SR(2).sqrt(), 0, 1, 3 ** (-QQ.one()/3), SR.pi(), 100000] elements.append(ring.an_element()) elements.extend(ring.some_elements()) for z in elements: try: z = ring(z) except (ValueError, TypeError): continue # ignore if z is not in ring msg = 'testing {} in {}: id = {}, {}, {}'.format(z, ring, id(z), id(infinity), id(minus_infinity)) assert minus_infinity < z, msg assert z > minus_infinity, msg assert z < infinity, msg assert infinity > z, msg assert minus_infinity <= z, msg assert z >= minus_infinity, msg assert z <= infinity, msg assert infinity >= z, msg
def Min(Fun, p, ubRes, conj, all_orbits=False): r""" Local loop for Affine_minimal, where we check minimality at the prime p. First we bound the possible k in our transformations A = zp^k + b. See Theorems 3.3.2 and 3.3.3 in [Molnar]_. INPUT: - ``Fun`` -- a dynamical system on projective space - ``p`` - a prime - ``ubRes`` -- integer, the upper bound needed for Th. 3.3.3 in [Molnar]_ - ``conj`` -- a 2x2 matrix keeping track of the conjugation - ``all_orbits`` -- boolean; whether or not to use ``==`` in the inequalities to find all orbits OUTPUT: - boolean -- ``True`` if ``Fun`` is minimal at ``p``, ``False`` otherwise - a dynamical system on projective space minimal at ``p`` EXAMPLES:: sage: P.<x,y> = ProjectiveSpace(QQ, 1) sage: f = DynamicalSystem_projective([149*x^2 + 39*x*y + y^2, -8*x^2 + 137*x*y + 33*y^2]) sage: from sage.dynamics.arithmetic_dynamics.endPN_minimal_model import Min sage: Min(f, 3, -27000000, matrix(QQ,[[1, 0],[0, 1]])) [ Dynamical System of Projective Space of dimension 1 over Rational Field Defn: Defined on coordinates by sending (x : y) to (157*x^2 + 72*x*y + 3*y^2 : -24*x^2 + 121*x*y + 54*y^2) , <BLANKLINE> [3 1] [0 1] ] """ d = Fun.degree() AffFun = Fun.dehomogenize(1) R = AffFun.coordinate_ring() if R.is_field(): #want the polynomial ring not the fraction field R = R.ring() F = R(AffFun[0].numerator()) G = R(AffFun[0].denominator()) dG = G.degree() # all_orbits scales bounds for >= and <= if searching for orbits instead of min model if dG > (d+1)/2: lowerBound = (-2*(G[dG]).valuation(p)/(2*dG - d + 1) + 1).floor() - int(all_orbits) else: lowerBound = (-2*(F[d]).valuation(p)/(d-1) + 1).floor() - int(all_orbits) upperBound = 2*(ubRes.valuation(p)) + int(all_orbits) if upperBound < lowerBound: # There are no possible transformations to reduce the resultant. if not all_orbits: return [Fun, conj] return [] # Looping over each possible k, we search for transformations to reduce # the resultant of F/G all_found = [] k = lowerBound Qb = PolynomialRing(QQ,'b') b = Qb.gen(0) Q = PolynomialRing(Qb,'z') z = Q.gen(0) while k <= upperBound: A = (p**k)*z + b Ft = Q(F(A) - b*G(A)) Gt = Q((p**k)*G(A)) Fcoeffs = Ft.coefficients(sparse=False) Gcoeffs = Gt.coefficients(sparse=False) coeffs = Fcoeffs + Gcoeffs RHS = (d + 1) * k / 2 # If there is some b such that Res(phi^A) < Res(phi), we must have # ord_p(c) > RHS for each c in coeffs. # Make sure constant coefficients in coeffs satisfy the inequality. if all(QQ(c).valuation(p) > RHS - int(all_orbits) for c in coeffs if c.degree() == 0): # Constant coefficients in coeffs have large enough valuation, so # check the rest. We start by checking if simply picking b=0 works. if all(c(0).valuation(p) > RHS - int(all_orbits) for c in coeffs): # A = z*p^k satisfies the inequalities, and F/G is not minimal # "Conjugating by", p,"^", k, "*z +", 0 newconj = matrix(QQ, 2, 2, [p**k, 0, 0, 1]) minFun = Fun.conjugate(newconj) minFun.normalize_coordinates() if not all_orbits: return [minFun, conj*newconj] all_found.append([p, k, 0]) # Otherwise we search if any value of b will work. We start by # finding a minimum bound on the valuation of b that is necessary. # See Theorem 3.3.5 in [Molnar, M.Sc. thesis]. bval = max(bCheck(coeff, RHS, p, b) for coeff in coeffs if coeff.degree() > 0) # We scale the coefficients in coeffs, so that we may assume # ord_p(b) is at least 0 scaledCoeffs = [coeff(b*(p**bval)) for coeff in coeffs] # We now scale the inequalities, ord_p(coeff) > RHS, so that # coeff is in ZZ[b] scale = QQ(max(coeff.denominator() for coeff in scaledCoeffs)) normalizedCoeffs = [coeff * scale for coeff in scaledCoeffs] scaleRHS = RHS + scale.valuation(p) # We now search for integers that satisfy the inequality # ord_p(coeff) > RHS. See Lemma 3.3.6 in [Molnar, M.Sc. thesis]. bound = (scaleRHS + 1 - int(all_orbits)).floor() all_blift = blift(normalizedCoeffs, bound, p, k, all_orbits=all_orbits) # If bool is true after lifting, we have a solution b, and F/G # is not minimal. for boolval, sol in all_blift: if boolval: #Rescale, conjugate and return new map bsol = QQ(sol * (p**bval)) #only add 'minimal orbit element' while bsol.abs() >= p**k: if bsol < 0: bsol += p**k else: bsol -= p**k #"Conjugating by ", p,"^", k, "*z +", bsol newconj = matrix(QQ, 2, 2, [p**k, bsol, 0, 1]) minFun = Fun.conjugate(newconj) minFun.normalize_coordinates() if not all_orbits: return [minFun, conj*newconj] if [p,k,bsol] not in all_found: all_found.append([p, k, bsol]) k = k + 1 if not all_orbits: return [Fun, conj] return all_found
def __init__(self,parent,x,val=0,normalized=False): RingElement.__init__(self,parent) Approximation.__init__(self,parent) self._x = QQ(x) self._val = val self._normalized = normalized