def random_isometry(self, preserve_orientation=True, **kwargs): r""" Return a random isometry in the Upper Half Plane model. INPUT: - ``preserve_orientation`` -- if ``True`` return an orientation-preserving isometry OUTPUT: - a hyperbolic isometry EXAMPLES:: sage: A = HyperbolicPlane().UHP().random_isometry() sage: B = HyperbolicPlane().UHP().random_isometry(preserve_orientation=False) sage: B.preserves_orientation() False """ [a, b, c, d] = [RR.random_element() for k in range(4)] while abs(a * d - b * c) < EPSILON: [a, b, c, d] = [RR.random_element() for k in range(4)] M = matrix(RDF, 2, [a, b, c, d]) M = M / (M.det()).abs().sqrt() if M.det() > 0: if not preserve_orientation: M = M * matrix(2, [0, 1, 1, 0]) elif preserve_orientation: M = M * matrix(2, [0, 1, 1, 0]) return self._Isometry(self, M, check=False)
def _compute_power_series(self, n, abs_prec, cache_ring=None): """ Compute the power series giving Dickman's function on [n, n+1], by recursion in n. For internal use; self.power_series() is a wrapper around this intended for the user. INPUT: - ``n`` - the lower endpoint of the interval for which this power series holds - ``abs_prec`` - the absolute precision of the resulting power series - ``cache_ring`` - for internal use, caches the power series at this precision. EXAMPLES:: sage: f = dickman_rho.power_series(2, 20); f -9.9376e-8*x^11 + 3.7722e-7*x^10 - 1.4684e-6*x^9 + 5.8783e-6*x^8 - 0.000024259*x^7 + 0.00010341*x^6 - 0.00045583*x^5 + 0.0020773*x^4 - 0.0097336*x^3 + 0.045224*x^2 - 0.11891*x + 0.13032 """ if n <= 1: if n <= -1: return PolynomialRealDense(RealField(abs_prec)['x']) if n == 0: return PolynomialRealDense(RealField(abs_prec)['x'], [1]) elif n == 1: nterms = (RDF(abs_prec) * RDF(2).log() / RDF(3).log()).ceil() R = RealField(abs_prec) neg_three = ZZ(-3) coeffs = [1 - R(1.5).log() ] + [neg_three**-k / k for k in range(1, nterms)] f = PolynomialRealDense(R['x'], coeffs) if cache_ring is not None: self._f[n] = f.truncate_abs(f[0] >> ( cache_ring.prec() + 1)).change_ring(cache_ring) return f else: f = self._compute_power_series(n - 1, abs_prec, cache_ring) # integrand = f / (2n+1 + x) # We calculate this way because the most significant term is the constant term, # and so we want to push the error accumulation and remainder out to the least # significant terms. integrand = f.reverse().quo_rem( PolynomialRealDense(f.parent(), [1, 2 * n + 1]))[0].reverse() integrand = integrand.truncate_abs(RR(2)**-abs_prec) iintegrand = integrand.integral() ff = PolynomialRealDense(f.parent(), [f(1) + iintegrand(-1)]) - iintegrand i = 0 while abs(f[i]) < abs(f[i + 1]): i += 1 rel_prec = int(abs_prec + abs(RR(f[i])).log2()) if cache_ring is not None: self._f[n] = ff.truncate_abs( ff[0] >> (cache_ring.prec() + 1)).change_ring(cache_ring) return ff.change_ring(RealField(rel_prec))
def plot_histogram(self, clr=(0, 0, 1), eps=0.4): """ Plots the histogram plot of the sequence, which is assumed to be real or from a finite field, with a real indexing set I coercible into RR. Options are clr, which is an RGB value, and eps, which is the spacing between the bars. EXAMPLES: sage: J = range(3) sage: A = [ZZ(i^2)+1 for i in J] sage: s = IndexedSequence(A,J) sage: P = s.plot_histogram() Now type show(P) to view this in a browser. """ #from sage.plot.misc import text F = self.base_ring() ## elements must be coercible into RR I = self.index_object() N = len(I) S = self.list() P = [ polygon([[RR(I[i]) - eps, 0], [ RR(I[i]) - eps, RR(S[i]) ], [RR(I[i]) + eps, RR(S[i])], [RR(I[i]) + eps, 0], [RR(I[i]), 0]], rgbcolor=clr) for i in range(N) ] T = [ text(str(I[i]), (RR(I[i]), -0.8), fontsize=15, rgbcolor=(1, 0, 0)) for i in range(N) ] return sum(P) + sum(T)
def plot_histogram(self, clr=(0, 0, 1), eps=0.4): r""" Plot the histogram plot of the sequence. The sequence is assumed to be real or from a finite field, with a real indexing set ``I`` coercible into `\RR`. Options are ``clr``, which is an RGB value, and ``eps``, which is the spacing between the bars. EXAMPLES:: sage: J = range(3) sage: A = [ZZ(i^2)+1 for i in J] sage: s = IndexedSequence(A,J) sage: P = s.plot_histogram() sage: show(P) # Not tested """ # elements must be coercible into RR I = self.index_object() N = len(I) S = self.list() P = [ polygon([[RR(I[i]) - eps, 0], [ RR(I[i]) - eps, RR(S[i]) ], [RR(I[i]) + eps, RR(S[i])], [RR(I[i]) + eps, 0], [RR(I[i]), 0]], rgbcolor=clr) for i in range(N) ] T = [ text(str(I[i]), (RR(I[i]), -0.8), fontsize=15, rgbcolor=(1, 0, 0)) for i in range(N) ] return sum(P) + sum(T)
def get_classified_solution_dicts(output_file_contents, input_ring, get_failures=True): """ Returns 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() test = 'False' 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 approximate(self, x, parent=None): r""" Approximate using de Bruijn's formula .. MATH:: \rho(x) \sim \frac{exp(-x \xi + Ei(\xi))}{\sqrt{2\pi x}\xi} which is asymptotically equal to Dickman's function, and is much faster to compute. REFERENCES: - N. De Bruijn, "The Asymptotic behavior of a function occurring in the theory of primes." J. Indian Math Soc. v 15. (1951) EXAMPLES:: sage: dickman_rho.approximate(10) 2.41739196365564e-11 sage: dickman_rho(10) 2.77017183772596e-11 sage: dickman_rho.approximate(1000) 4.32938809066403e-3464 """ log, exp, sqrt, pi = math.log, math.exp, math.sqrt, math.pi x = float(x) xi = log(x) y = (exp(xi) - 1.0) / xi - x while abs(y) > 1e-12: dydxi = (exp(xi) * (xi - 1.0) + 1.0) / (xi * xi) xi -= y / dydxi y = (exp(xi) - 1.0) / xi - x return (-x * xi + RR(xi).eint()).exp() / (sqrt(2 * pi * x) * xi)
def __float__(self): r""" TESTS:: sage: float(E(7) + E(7,6)) 1.246979603717467 """ from sage.rings.real_mpfr import RR return float(RR(self))
def local_coordinates_at_infinity(self, prec=20, name='t'): """ For the genus `g` hyperelliptic curve `y^2 = f(x)`, return `(x(t), y(t))` such that `(y(t))^2 = f(x(t))`, where `t = x^g/y` is the local parameter at infinity INPUT: - ``prec`` -- desired precision of the local coordinates - ``name`` -- generator of the power series ring (default: ``t``) OUTPUT: `(x(t),y(t))` such that `y(t)^2 = f(x(t))` and `t = x^g/y` is the local parameter at infinity EXAMPLES:: sage: R.<x> = QQ['x'] sage: H = HyperellipticCurve(x^5-5*x^2+1) sage: x,y = H.local_coordinates_at_infinity(10) sage: x t^-2 + 5*t^4 - t^8 - 50*t^10 + O(t^12) sage: y t^-5 + 10*t - 2*t^5 - 75*t^7 + 50*t^11 + O(t^12) :: sage: R.<x> = QQ['x'] sage: H = HyperellipticCurve(x^3-x+1) sage: x,y = H.local_coordinates_at_infinity(10) sage: x t^-2 + t^2 - t^4 - t^6 + 3*t^8 + O(t^12) sage: y t^-3 + t - t^3 - t^5 + 3*t^7 - 10*t^11 + O(t^12) AUTHOR: - Jennifer Balakrishnan (2007-12) """ g = self.genus() pol = self.hyperelliptic_polynomials()[0] K = LaurentSeriesRing(self.base_ring(), name, default_prec=prec + 2) t = K.gen() L = PolynomialRing(K, 'x') x = L.gen() i = 0 w = (x**g / t)**2 - pol wprime = w.derivative(x) if pol.degree() == 2 * g + 1: x = t**-2 else: x = t**-1 for i in range((RR(log(prec + 2) / log(2))).ceil()): x = x - w(x) / wprime(x) y = x**g / t return x + O(t**(prec + 2)), y + O(t**(prec + 2))
def plot(self): """ Plot the points of the sequence. Elements of the sequence are assumed to be real or from a finite field, with a real indexing set ``I = range(len(self))``. EXAMPLES:: sage: I = range(3) sage: A = [ZZ(i^2)+1 for i in I] sage: s = IndexedSequence(A,I) sage: P = s.plot() sage: show(P) # Not tested """ # elements must be coercible into RR I = self.index_object() S = self.list() return line([[RR(I[i]),RR(S[i])] for i in range(len(I)-1)])
def random_point(self, **kwargs): r""" Return a random point in the upper half plane. The points are uniformly distributed over the rectangle `[-10, 10] \times [0, 10i]`. EXAMPLES:: sage: p = HyperbolicPlane().UHP().random_point().coordinates() sage: bool((p.imag()) > 0) True """ # TODO: use **kwargs to allow these to be set real_min = -10 real_max = 10 imag_min = 0 imag_max = 10 p = RR.random_element(min=real_min, max=real_max) \ + I * RR.random_element(min=imag_min, max=imag_max) return self.get_point(p)
def dwt(self,other="haar",wavelet_k=2): """ Wraps the gsl WaveletTransform.forward in dwt.pyx (written by Joshua Kantor). Assumes the length of the sample is a power of 2. Uses the GSL function gsl_wavelet_transform_forward. other -- the wavelet_type: the name of the type of wavelet, valid choices are: 'daubechies','daubechies_centered', 'haar' (default),'haar_centered', 'bspline', and 'bspline_centered'. wavelet_k -- For daubechies wavelets, wavelet_k specifies a daubechie wavelet with k/2 vanishing moments. k = 4,6,...,20 for k even are the only ones implemented. For Haar wavelets, wavelet_k must be 2. For bspline wavelets, wavelet_k = 103,105,202,204,206,208,301,305, 307,309 will give biorthogonal B-spline wavelets of order (i,j) where wavelet_k=100*i+j. The wavelet transform uses J=log_2(n) levels. EXAMPLES: sage: J = range(8) sage: A = [RR(1) for i in J] sage: s = IndexedSequence(A,J) sage: t = s.dwt() sage: t # slightly random output Indexed sequence: [2.82842712474999, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000] indexed by [0, 1, 2, 3, 4, 5, 6, 7] """ F = self.base_ring() ## elements must be coercible into RR J = self.index_object() ## must be = range(N) N = len(J) ## must be 1 minus a power of 2 S = self.list() if other=="haar" or other=="haar_centered": if wavelet_k in [2]: a = WaveletTransform(N,other,wavelet_k) else: raise ValueError,"wavelet_k must be = 2" if other=="debauchies" or other=="debauchies_centered": if wavelet_k in [4,6,8,10,12,14,16,18,20]: a = WaveletTransform(N,other,wavelet_k) else: raise ValueError,"wavelet_k must be in {4,6,8,10,12,14,16,18,20}" if other=="bspline" or other=="bspline_centered": if wavelet_k in [103,105,202,204,206,208,301,305,307,309]: a = WaveletTransform(N,other,103) else: raise ValueError,"wavelet_k must be in {103,105,202,204,206,208,301,305,307,309}" for i in range(N): a[i] = S[i] a.forward_transform() return IndexedSequence([RR(a[j]) for j in J],J)
def local_coordinates_at_nonweierstrass(self, P, prec=20, name='t'): """ For a non-Weierstrass point `P = (a,b)` on the hyperelliptic curve `y^2 = f(x)`, return `(x(t), y(t))` such that `(y(t))^2 = f(x(t))`, where `t = x - a` is the local parameter. INPUT: - ``P = (a, b)`` -- a non-Weierstrass point on self - ``prec`` -- desired precision of the local coordinates - ``name`` -- gen of the power series ring (default: ``t``) OUTPUT: `(x(t),y(t))` such that `y(t)^2 = f(x(t))` and `t = x - a` is the local parameter at `P` EXAMPLES:: sage: R.<x> = QQ['x'] sage: H = HyperellipticCurve(x^5-23*x^3+18*x^2+40*x) sage: P = H(1,6) sage: x,y = H.local_coordinates_at_nonweierstrass(P,prec=5) sage: x 1 + t + O(t^5) sage: y 6 + t - 7/2*t^2 - 1/2*t^3 - 25/48*t^4 + O(t^5) sage: Q = H(-2,12) sage: x,y = H.local_coordinates_at_nonweierstrass(Q,prec=5) sage: x -2 + t + O(t^5) sage: y 12 - 19/2*t - 19/32*t^2 + 61/256*t^3 - 5965/24576*t^4 + O(t^5) AUTHOR: - Jennifer Balakrishnan (2007-12) """ d = P[1] if d == 0: raise TypeError( "P = %s is a Weierstrass point. Use local_coordinates_at_weierstrass instead!" % P) pol = self.hyperelliptic_polynomials()[0] L = PowerSeriesRing(self.base_ring(), name) t = L.gen() L.set_default_prec(prec) K = PowerSeriesRing(L, 'x') pol = K(pol) x = K.gen() b = P[0] f = pol(t + b) for i in range((RR(log(prec) / log(2))).ceil()): d = (d + f / d) / 2 return t + b + O(t**(prec)), d + O(t**(prec))
def plot(self): """ Plots the points of the sequence, whose elements are assumed to be real or from a finite field, with a real indexing set I = range(len(self)). EXAMPLES: sage: I = range(3) sage: A = [ZZ(i^2)+1 for i in I] sage: s = IndexedSequence(A,I) sage: P = s.plot() Now type show(P) to view this in a browser. """ F = self.base_ring() ## elements must be coercible into RR I = self.index_object() N = len(I) S = self.list() P = line([[RR(I[i]),RR(S[i])] for i in range(N-1)]) return P
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: 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 __init__(self, parent, value, symbolic=None): FieldElement.__init__( self, parent) ## this is so that canonical_coercion works. if not parent._mutable_values and value is not None: ## Test coercing the value to RR, so that we do not try to build a ParametricRealFieldElement ## from something like a tuple or vector or list or variable of a polynomial ring ## or something else that does not make any sense. # FIXME: parent(value) caused SIGSEGV because of an infinite recursion from sage.structure.coerce import py_scalar_parent if hasattr(value, 'parent'): if not RR.has_coerce_map_from(value.parent()): raise TypeError("Value is of wrong type") else: if not RR.has_coerce_map_from(py_scalar_parent(type(value))): raise TypeError("Value is of wrong type") self._val = value if symbolic is None: self._sym = value # changed to not coerce into SR. -mkoeppe else: self._sym = symbolic
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 __init__(self, parent, value, symbolic=None): FieldElement.__init__( self, parent) ## this is so that canonical_coercion works. if not parent._mutable_values and value is not None: ## Test coercing the value to RR, so that we do not try to build a ParametricRealFieldElement ## from something like a tuple or vector or list or variable of a polynomial ring ## or something else that does not make any sense. from sage.interfaces.mathematica import MathematicaElement if not isinstance(value, MathematicaElement): RR(value) self._val = value if symbolic is None: self._sym = value # changed to not coerce into SR. -mkoeppe else: self._sym = symbolic
def perron_right_eigenvector(M): r""" EXAMPLES:: sage: from slabbe.matrix_cocycle import perron_right_eigenvector sage: m = matrix(2,[-11,14,-26,29]) sage: perron_right_eigenvector(m) # tolerance 0.00001 (15.0000000000000, (0.35, 0.6499999999999999)) """ from sage.modules.free_module_element import vector from sage.rings.real_mpfr import RR from sage.rings.all import CC import numpy eig, vec = numpy.linalg.eig(M) index = abs(eig).argmax() rightv = vec.transpose()[index] if eig[index].imag == 0: eig_sage = RR(eig[index].real) vec_sage = vector(a.real for a in rightv) else: eig_sage = CC(eig[index]) vec_sage = vector(CC, rightv) return eig_sage, vec_sage/sum(vec_sage)
def straight_line_plot(gs, v, directory="/tmp/", pause_time=100, width_in_inches=10, file_offset=0): r""" Produces successively longer plots of a trajectory on the graphical surface gs which starts with the provided SimilaritySurfaceTangentVector, v. The graphical surface gs is used to decide which segments to draw. Only segments drawn in visible polygons will be recorded. The directory given in the parameter will be filled with some data pertaining to the trajectory. A text file named orbit_setup.txt will be produced to record v. Periodically (after drawing pause_time segments), the program will write to a text file, orbitN.txt about the segments and produce orbitN.svg depicting the trajectory. The program will run until you press Control-C (or until your computer dies from an overheated processor :) ). EXAMPLE:: from geometry.chamanara import GraphicalChamanaraSurface s=GraphicalChamanaraSurface(QQ(1)/2,8) from geometry.tangent_bundle import SimilaritySurfaceTangentBundle, SimilaritySurfaceTangentVector K.<sqrt2> = NumberField(x^2 - 2, embedding=AA(2).sqrt()) tb = SimilaritySurfaceTangentBundle(s.get_surface()) from sage.modules.free_module_element import vector v=SimilaritySurfaceTangentVector(tb, 0, vector((0,0)), vector((1,sqrt2))) from graphical.straight_line_plotter import straight_line_plot straight_line_plot(s,v, directory=".", pause_time = 100) """ # Check the directory: from os import path if not path.isdir(directory): ValueError("Provided directory must be a directory") # Get a bounding box for the figure: xmin, ymin, xmax, ymax = gs.bounding_box() width = xmax - xmin height = ymax - ymin height_in_inches = height * width_in_inches / width figsize = [width_in_inches, height_in_inches] # Construct a segment using the tangent vector from geometry.straight_line_trajectory import SegmentInPolygon seg = SegmentInPolygon(v) # Used for drawing segments: from graphical.straight_line_trajectory import GraphicalSegmentInPolygon # Prepare to loop: all = 0 count = 0 # For providing human readable points from sage.rings.real_mpfr import RR # Record the initial conditions to a file: f = open(path.join(directory, "orbit_setup.txt"), 'w') f.write("v: " + str(v) + "\n") f.close() # Plot the surface from sage.plot.graphics import Graphics p = gs.plot() #p.save(path.join(directory,"orbit0.svg"),xmin=xmin,xmax=xmax,ymin=ymin,ymax=ymax, \ # figsize=figsize,axes=False,aspect_ratio=1,dpi=72) plot = p.matplotlib(xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax, axes=False, aspect_ratio=1) plot.set_size_inches(figsize) plot.subplots_adjust(left=0, right=1, top=1, bottom=0) from matplotlib.backends.backend_agg import FigureCanvasAgg plot.set_canvas(FigureCanvasAgg(plot)) plot.savefig(path.join(directory, "orbit0.svg")) #plot.savefig(path.join(directory,"orbit0.svg"),bbox_inches=0) p = Graphics() # Move forward through segments. Pay attention when the segment lies within our list of # polygons we care about. Plot them and print some data about them to a file. # Every 100 times we do this, we move to a new file. while True: filename_f = "orbit" + str(count / pause_time + file_offset) + ".txt" f = open(path.join(directory, filename_f), 'w') count_start = count while (count == count_start) or (count % pause_time != 0): if gs.is_visible(seg.polygon_label()): print("Segment #" + str(all) + " (plotted " + str(count) + ")") f.write("Segment #" + str(all) + " (plotted " + str(count) + ")\n") f.write("Label: " + str(seg.polygon_label()) + "\n") f.write("point: " + str(seg.start_point()) + "\n") f.write("RR point: "+str(RR(seg.start_point()[0]))+", "+\ str(RR(seg.start_point()[1]))+"\n") gseg = GraphicalSegmentInPolygon(gs, seg) p += gseg.plot() count += 1 # Move to next segment under flow: seg = seg.next() all += 1 # Save the plot to a file. f.close() #p.save(path.join(directory,"orbit"+str(count/pause_time)+".svg"),xmin=xmin,xmax=xmax,ymin=ymin,ymax=ymax,fig_tight=True, \ # figsize=figsize,axes=False,aspect_ratio=1,transparent=True) plot = p.matplotlib(xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax, axes=False, aspect_ratio=1) plot.set_size_inches(figsize) plot.subplots_adjust(left=0, right=1, top=1, bottom=0) from matplotlib.backends.backend_agg import FigureCanvasAgg plot.set_canvas(FigureCanvasAgg(plot)) filename_p = "orbit" + str(count / pause_time + file_offset) + ".svg" plot.savefig(path.join( directory, "orbit" + str(count / pause_time + file_offset) + ".svg"), transparent=True) # Write the pile file: filename_a = "orbit_pile" + str(count / pause_time + file_offset) + ".svg" a = open(path.join(directory, filename_a), 'w') a.write('<?xml version="1.0" encoding="utf-8" standalone="no"?>\n') a.write( '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"\n "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n' ) a.write('<svg height="'+str(height_in_inches*72)+'pt" version="1.1" viewBox="0 0 '+ \ str(width_in_inches*72)+' '+str(height_in_inches*72)+'" width="'+ \ str(width_in_inches*72)+'pt" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">\n') for i in range(count / pause_time + 1 + file_offset): a.write('<image x="0" y="0" width="'+str(width_in_inches*72)+'" height="'+str(height_in_inches*72)+\ '" xlink:href="orbit'+str(i)+'.svg" />\n') a.write('</svg>') a.close() p = Graphics() print("Wrote to files '" + filename_f + "', '" + filename_p + "' and '" + filename_a + "'.")
def dwt(self,other="haar",wavelet_k=2): """ Wraps the gsl ``WaveletTransform.forward`` in :mod:`~sage.gsl.dwt` (written by Joshua Kantor). Assumes the length of the sample is a power of 2. Uses the GSL function ``gsl_wavelet_transform_forward()``. INPUT: - ``other`` -- the the name of the type of wavelet; valid choices are: * ``'daubechies'`` * ``'daubechies_centered'`` * ``'haar'`` (default) * ``'haar_centered'`` * ``'bspline'`` * ``'bspline_centered'`` - ``wavelet_k`` -- For daubechies wavelets, ``wavelet_k`` specifies a daubechie wavelet with `k/2` vanishing moments. `k = 4,6,...,20` for `k` even are the only ones implemented. For Haar wavelets, ``wavelet_k`` must be 2. For bspline wavelets, ``wavelet_k`` equal to `103,105,202,204, 206,208,301,305,307,309` will give biorthogonal B-spline wavelets of order `(i,j)` where ``wavelet_k`` equals `100 \cdot i + j`. The wavelet transform uses `J = \log_2(n)` levels. EXAMPLES:: sage: J = range(8) sage: A = [RR(1) for i in J] sage: s = IndexedSequence(A,J) sage: t = s.dwt() sage: t # slightly random output Indexed sequence: [2.82842712474999, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000] indexed by [0, 1, 2, 3, 4, 5, 6, 7] """ # elements must be coercible into RR J = self.index_object() ## must be = range(N) N = len(J) ## must be 1 minus a power of 2 S = self.list() if other == "haar" or other == "haar_centered": if wavelet_k in [2]: a = WaveletTransform(N,other,wavelet_k) else: raise ValueError("wavelet_k must be = 2") if other == "debauchies" or other == "debauchies_centered": if wavelet_k in [4,6,8,10,12,14,16,18,20]: a = WaveletTransform(N,other,wavelet_k) else: raise ValueError("wavelet_k must be in {4,6,8,10,12,14,16,18,20}") if other == "bspline" or other == "bspline_centered": if wavelet_k in [103,105,202,204,206,208,301,305,307,309]: a = WaveletTransform(N,other,103) else: raise ValueError("wavelet_k must be in {103,105,202,204,206,208,301,305,307,309}") for i in range(N): a[i] = S[i] a.forward_transform() return IndexedSequence([RR(a[j]) for j in J],J)
def points(self, **kwds): """ Return some or all rational points of a projective scheme. For dimension 0 subschemes points are determined through a groebner basis calculation. For schemes or subschemes with dimension greater than 1 points are determined through enumeration up to the specified bound. INPUT: kwds: - ``bound`` - real number (optional, default=0). The bound for the coordinates for subschemes with dimension at least 1. - ``precision`` - integer (optional, default=53). The precision to use to compute the elements of bounded height for number fields. - ``point_tolerance`` - positive real number (optional, default=10^(-10)). For numerically inexact fields, two points are considered the same if their coordinates are within tolerance. - ``zero_tolerance`` - positive real number (optional, default=10^(-10)). For numerically inexact fields, points are on the subscheme if they satisfy the equations to within tolerance. - ``tolerance`` - a rational number in (0,1] used in doyle-krumm algorithm-4 for enumeration over number fields. OUTPUT: - a list of rational points of a projective scheme .. WARNING:: For numerically inexact fields such as ComplexField or RealField the list of points returned is very likely to be incomplete. It may also contain repeated points due to tolerances. EXAMPLES:: sage: P.<x,y> = ProjectiveSpace(QQ,1) sage: P(QQ).points(bound=4) [(-4 : 1), (-3 : 1), (-2 : 1), (-3/2 : 1), (-4/3 : 1), (-1 : 1), (-3/4 : 1), (-2/3 : 1), (-1/2 : 1), (-1/3 : 1), (-1/4 : 1), (0 : 1), (1/4 : 1), (1/3 : 1), (1/2 : 1), (2/3 : 1), (3/4 : 1), (1 : 0), (1 : 1), (4/3 : 1), (3/2 : 1), (2 : 1), (3 : 1), (4 : 1)] :: sage: u = QQ['u'].0 sage: K.<v> = NumberField(u^2 + 3) sage: P.<x,y,z> = ProjectiveSpace(K,2) sage: len(P(K).points(bound=1.8)) 381 :: sage: P1 = ProjectiveSpace(GF(2),1) sage: F.<a> = GF(4,'a') sage: P1(F).points() [(0 : 1), (1 : 0), (1 : 1), (a : 1), (a + 1 : 1)] :: sage: P.<x,y,z> = ProjectiveSpace(QQ,2) sage: E = P.subscheme([(y^3-y*z^2) - (x^3-x*z^2),(y^3-y*z^2) + (x^3-x*z^2)]) sage: E(P.base_ring()).points() [(-1 : -1 : 1), (-1 : 0 : 1), (-1 : 1 : 1), (0 : -1 : 1), (0 : 0 : 1), (0 : 1 : 1), (1 : -1 : 1), (1 : 0 : 1), (1 : 1 : 1)] :: sage: P.<x,y,z> = ProjectiveSpace(CC, 2) sage: E = P.subscheme([y^3 - x^3 - x*z^2, x*y*z]) sage: L=E(P.base_ring()).points(); sorted(L, key=str) verbose 0 (...: projective_homset.py, points) Warning: computations in the numerical fields are inexact;points may be computed partially or incorrectly. [(-0.500000000000000 + 0.866025403784439*I : 1.00000000000000 : 0.000000000000000), (-0.500000000000000 - 0.866025403784439*I : 1.00000000000000 : 0.000000000000000), (-1.00000000000000*I : 0.000000000000000 : 1.00000000000000), (0.000000000000000 : 0.000000000000000 : 1.00000000000000), (1.00000000000000 : 1.00000000000000 : 0.000000000000000), (1.00000000000000*I : 0.000000000000000 : 1.00000000000000)] sage: L[0].codomain() Projective Space of dimension 2 over Complex Field with 53 bits of precision :: sage: P.<x,y,z> = ProjectiveSpace(CDF, 2) sage: E = P.subscheme([y^2 + x^2 + z^2, x*y*z]) sage: len(E(P.base_ring()).points()) verbose 0 (...: projective_homset.py, points) Warning: computations in the numerical fields are inexact;points may be computed partially or incorrectly. 6 """ from sage.schemes.projective.projective_space import is_ProjectiveSpace X = self.codomain() if not is_ProjectiveSpace(X) and X.base_ring() in Fields(): if hasattr(X.base_ring(), 'precision'): numerical = True verbose( "Warning: computations in the numerical fields are inexact;points may be computed partially or incorrectly.", level=0) pt_tol = RR(kwds.pop('point_tolerance', 10**(-10))) zero_tol = RR(kwds.pop('zero_tolerance', 10**(-10))) if pt_tol <= 0 or zero_tol <= 0: raise ValueError("tolerance must be positive") else: numerical = False #Then it must be a subscheme dim_ideal = X.defining_ideal().dimension() if dim_ideal < 1: # no points return [] if dim_ideal == 1: # if X zero-dimensional rat_points = set() PS = X.ambient_space() N = PS.dimension_relative() BR = X.base_ring() #need a lexicographic ordering for elimination R = PolynomialRing(BR, N + 1, PS.variable_names(), order='lex') I = R.ideal(X.defining_polynomials()) I0 = R.ideal(0) #Determine the points through elimination #This is much faster than using the I.variety() function on each affine chart. for k in range(N + 1): #create the elimination ideal for the kth affine patch G = I.substitute({R.gen(k): 1}).groebner_basis() if G != [1]: P = {} #keep track that we know the kth coordinate is 1 P.update({R.gen(k): 1}) points = [P] #work backwards from solving each equation for the possible #values of the next coordinate for i in range(len(G) - 1, -1, -1): new_points = [] good = 0 for P in points: #substitute in our dictionary entry that has the values #of coordinates known so far. This results in a single #variable polynomial (by elimination) L = G[i].substitute(P) if R(L).degree() > 0: if numerical: for pol in L.univariate_polynomial( ).roots(multiplicities=False): good = 1 r = L.variables()[0] varindex = R.gens().index(r) P.update({R.gen(varindex): pol}) new_points.append(copy(P)) else: L = L.factor() #the linear factors give the possible rational values of #this coordinate for pol, pow in L: if pol.degree() == 1 and len( pol.variables()) == 1: good = 1 r = pol.variables()[0] varindex = R.gens().index(r) #add this coordinates information to #each dictionary entry P.update({ R.gen(varindex): -pol.constant_coefficient( ) / pol.monomial_coefficient(r) }) new_points.append(copy(P)) else: new_points.append(P) good = 1 if good: points = new_points #the dictionary entries now have values for all coordinates #they are the rational solutions to the equations #make them into projective points for i in range(len(points)): if numerical: if len(points[i]) == N + 1: S = PS([ points[i][R.gen(j)] for j in range(N + 1) ]) S.normalize_coordinates() if all( g(list(S)) < zero_tol for g in X.defining_polynomials()): rat_points.add(S) else: if len(points[i]) == N + 1 and I.subs( points[i]) == I0: S = X([ points[i][R.gen(j)] for j in range(N + 1) ]) S.normalize_coordinates() rat_points.add(S) # remove duplicate element using tolerance if numerical: dupl_points = list(rat_points) for i in range(len(dupl_points)): u = dupl_points[i] for j in range(i + 1, len(dupl_points)): v = dupl_points[j] if all((u[k] - v[k]).abs() < pt_tol for k in range(len(u))): rat_points.remove(u) break rat_points = sorted(rat_points) return rat_points R = self.value_ring() B = kwds.pop('bound', 0) tol = kwds.pop('tolerance', 1e-2) prec = kwds.pop('precision', 53) if is_RationalField(R): if not B > 0: raise TypeError("a positive bound B (= %s) must be specified" % B) if isinstance(X, AlgebraicScheme_subscheme ): # sieve should only be called for subschemes from sage.schemes.projective.projective_rational_point import sieve return sieve(X, B) else: from sage.schemes.projective.projective_rational_point import enum_projective_rational_field return enum_projective_rational_field(self, B) elif R in NumberFields(): if not B > 0: raise TypeError("a positive bound B (= %s) must be specified" % B) from sage.schemes.projective.projective_rational_point import enum_projective_number_field return enum_projective_number_field(self, bound=B, tolerance=tol, precision=prec) elif is_FiniteField(R): from sage.schemes.projective.projective_rational_point import enum_projective_finite_field return enum_projective_finite_field(self.extended_codomain()) else: raise TypeError("unable to enumerate points over %s" % R)
def numerical_points(self, F=None, **kwds): """ Return some or all numerical approximations of rational points of a projective scheme. This is for dimension 0 subschemes only and the points are determined through a groebner calculation over the base ring and then numerically approximating the roots of the resulting polynomials. If the base ring is a number field, the embedding into ``F`` must be known. INPUT: ``F`` - numerical ring kwds: - ``point_tolerance`` - positive real number (optional, default=10^(-10)). For numerically inexact fields, two points are considered the same if their coordinates are within tolerance. - ``zero_tolerance`` - positive real number (optional, default=10^(-10)). For numerically inexact fields, points are on the subscheme if they satisfy the equations to within tolerance. OUTPUT: A list of points in the ambient space. .. WARNING:: For numerically inexact fields the list of points returned may contain repeated or be missing points due to tolerance. EXAMPLES:: sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: E = P.subscheme([y^3 - x^3 - x*z^2, x*y*z]) sage: L = E(QQ).numerical_points(F=RR); L [(0.000000000000000 : 0.000000000000000 : 1.00000000000000), (1.00000000000000 : 1.00000000000000 : 0.000000000000000)] sage: L[0].codomain() Projective Space of dimension 2 over Real Field with 53 bits of precision :: sage: S.<a> = QQ[] sage: K.<v> = NumberField(a^5 - 7, embedding=CC((7)**(1/5))) sage: P.<x,y,z> = ProjectiveSpace(K,2) sage: X = P.subscheme([x^2 - v^2*z^2, y-v*z]) sage: len(X(K).numerical_points(F=CDF)) 2 :: sage: P.<x1, x2, x3> = ProjectiveSpace(QQ, 2) sage: E = P.subscheme([3000*x1^50 + 9875643*x2^2*x3^48 + 12334545*x2^50, x1 + x2]) sage: len(E(P.base_ring()).numerical_points(F=CDF, zero_tolerance=1e-6)) 49 TESTS:: sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: E = P.subscheme([y^3 - x^3 - x*z^2, x*y*z]) sage: E(QQ).numerical_points(F=CDF, point_tolerance=-1) Traceback (most recent call last): ... ValueError: tolerance must be positive :: sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: E = P.subscheme([y^3 - x^3 - x*z^2, x*y*z]) sage: E(QQ).numerical_points(F=CC, zero_tolerance=-1) Traceback (most recent call last): ... ValueError: tolerance must be positive :: sage: P.<x,y,z> = ProjectiveSpace(QQ, 2) sage: E = P.subscheme([y^3 - x^3 - x*z^2, x*y*z]) sage: E(QQ).numerical_points(F=QQbar) Traceback (most recent call last): ... TypeError: F must be a numerical field """ from sage.schemes.projective.projective_space import is_ProjectiveSpace if F is None: F = CC if F not in Fields() or not hasattr(F, 'precision'): raise TypeError('F must be a numerical field') X = self.codomain() if X.base_ring() not in NumberFields(): raise TypeError('base ring must be a number field') PP = X.ambient_space().change_ring(F) if not is_ProjectiveSpace(X) and X.base_ring() in Fields(): #Then it must be a subscheme dim_ideal = X.defining_ideal().dimension() if dim_ideal < 1: # no points return [] if dim_ideal == 1: # if X zero-dimensional pt_tol = RR(kwds.pop('point_tolerance', 10**(-10))) zero_tol = RR(kwds.pop('zero_tolerance', 10**(-10))) if pt_tol <= 0 or zero_tol <= 0: raise ValueError("tolerance must be positive") rat_points = set() PS = X.ambient_space() N = PS.dimension_relative() BR = X.base_ring() #need a lexicographic ordering for elimination R = PolynomialRing(BR, N + 1, PS.variable_names(), order='lex') RF = R.change_ring(F) I = R.ideal(X.defining_polynomials()) #Determine the points through elimination #This is much faster than using the I.variety() function on each affine chart. for k in range(N + 1): #create the elimination ideal for the kth affine patch G = I.substitute({R.gen(k): 1}).groebner_basis() G = [RF(g) for g in G] if G != [1]: P = {} #keep track that we know the kth coordinate is 1 P.update({RF.gen(k): 1}) points = [P] #work backwards from solving each equation for the possible #values of the next coordinate for i in range(len(G) - 1, -1, -1): new_points = [] good = 0 for P in points: #substitute in our dictionary entry that has the values #of coordinates known so far. This results in a single #variable polynomial (by elimination) L = G[i].substitute(P) if len(RF(L).variables()) == 1: for pol in L.univariate_polynomial().roots( ring=F, multiplicities=False): r = L.variables()[0] varindex = RF.gens().index(r) P.update({RF.gen(varindex): pol}) new_points.append(copy(P)) good = 1 else: new_points.append(P) good = 1 if good: points = new_points #the dictionary entries now have values for all coordinates #they are approximate solutions to the equations #make them into projective points polys = [ g.change_ring(F) for g in X.defining_polynomials() ] for i in range(len(points)): if len(points[i]) == N + 1: S = PP([ points[i][RF.gen(j)] for j in range(N + 1) ]) S.normalize_coordinates() if all(g(list(S)) < zero_tol for g in polys): rat_points.add(S) # remove duplicate element using tolerance #since they are normalized we can just compare coefficients dupl_points = list(rat_points) for i in range(len(dupl_points)): u = dupl_points[i] for j in range(i + 1, len(dupl_points)): v = dupl_points[j] if all((u[k] - v[k]).abs() < pt_tol for k in range(len(u))): rat_points.remove(u) break rat_points = sorted(rat_points) return rat_points raise NotImplementedError( 'numerical approximation of points only for dimension 0 subschemes' )
def points(self, **kwds): r""" Return some or all rational points of an affine scheme. For dimension 0 subschemes points are determined through a groebner basis calculation. For schemes or subschemes with dimension greater than 1 points are determined through enumeration up to the specified bound. Over a finite field, all points are returned. Over an infinite field, all points satisfying the bound are returned. For a zero-dimensional subscheme, all points are returned regardless of whether the field is infinite or not. For number fields, this uses the Doyle-Krumm algorithm 4 (algorithm 5 for imaginary quadratic) for computing algebraic numbers up to a given height [DK2013]_. The algorithm requires floating point arithmetic, so the user is allowed to specify the precision for such calculations. Additionally, due to floating point issues, points slightly larger than the bound may be returned. This can be controlled by lowering the tolerance. INPUT: kwds: - ``bound`` - real number (optional, default: 0). The bound for the height of the coordinates. Only used for subschemes with dimension at least 1. - ``zero_tolerance`` - positive real number (optional, default=10^(-10)). For numerically inexact fields, points are on the subscheme if they satisfy the equations to within tolerance. - ``tolerance`` - a rational number in (0,1] used in doyle-krumm algorithm-4 for enumeration over number fields. - ``precision`` - the precision to use for computing the elements of bounded height of number fields. OUTPUT: - a list of rational points of a affine scheme .. WARNING:: For numerically inexact fields such as ComplexField or RealField the list of points returned is very likely to be incomplete. It may also contain repeated points due to tolerance. EXAMPLES: The bug reported at #11526 is fixed:: sage: A2 = AffineSpace(ZZ, 2) sage: F = GF(3) sage: A2(F).points() [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)] :: sage: A.<x,y> = ZZ[] sage: I = A.ideal(x^2-y^2-1) sage: V = AffineSpace(ZZ, 2) sage: X = V.subscheme(I) sage: M = X(ZZ) sage: M.points(bound=1) [(-1, 0), (1, 0)] :: sage: u = QQ['u'].0 sage: K.<v> = NumberField(u^2 + 3) sage: A.<x,y> = AffineSpace(K, 2) sage: len(A(K).points(bound=2)) 1849 :: sage: A.<x,y> = AffineSpace(QQ, 2) sage: E = A.subscheme([x^2 + y^2 - 1, y^2 - x^3 + x^2 + x - 1]) sage: E(A.base_ring()).points() [(-1, 0), (0, -1), (0, 1), (1, 0)] :: sage: A.<x,y> = AffineSpace(CC, 2) sage: E = A.subscheme([y^3 - x^3 - x^2, x*y]) sage: E(A.base_ring()).points() verbose 0 (...: affine_homset.py, points) Warning: computations in the numerical fields are inexact;points may be computed partially or incorrectly. [(-1.00000000000000, 0.000000000000000), (0.000000000000000, 0.000000000000000)] :: sage: A.<x1,x2> = AffineSpace(CDF, 2) sage: E = A.subscheme([x1^2 + x2^2 + x1*x2, x1 + x2]) sage: E(A.base_ring()).points() verbose 0 (...: affine_homset.py, points) Warning: computations in the numerical fields are inexact;points may be computed partially or incorrectly. [(0.0, 0.0)] """ from sage.schemes.affine.affine_space import is_AffineSpace X = self.codomain() if not is_AffineSpace(X) and X.base_ring() in Fields(): if hasattr(X.base_ring(), 'precision'): numerical = True verbose( "Warning: computations in the numerical fields are inexact;points may be computed partially or incorrectly.", level=0) zero_tol = RR(kwds.pop('zero_tolerance', 10**(-10))) if zero_tol <= 0: raise ValueError("tolerance must be positive") else: numerical = False # Then X must be a subscheme dim_ideal = X.defining_ideal().dimension() if dim_ideal < 0: # no points return [] if dim_ideal == 0: # if X zero-dimensional rat_points = [] AS = X.ambient_space() N = AS.dimension_relative() BR = X.base_ring() #need a lexicographic ordering for elimination R = PolynomialRing(BR, N, AS.gens(), order='lex') I = R.ideal(X.defining_polynomials()) I0 = R.ideal(0) #Determine the points through elimination #This is much faster than using the I.variety() function on each affine chart. G = I.groebner_basis() if G != [1]: P = {} points = [P] #work backwards from solving each equation for the possible #values of the next coordinate for i in range(len(G) - 1, -1, -1): new_points = [] good = 0 for P in points: #substitute in our dictionary entry that has the values #of coordinates known so far. This results in a single #variable polynomial (by elimination) L = G[i].substitute(P) if R(L).degree() > 0: if numerical: for pol in L.univariate_polynomial().roots( multiplicities=False): r = L.variables()[0] varindex = R.gens().index(r) P.update({R.gen(varindex): pol}) new_points.append(copy(P)) good = 1 else: L = L.factor() #the linear factors give the possible rational values of #this coordinate for pol, pow in L: if pol.degree() == 1 and len( pol.variables()) == 1: good = 1 r = pol.variables()[0] varindex = R.gens().index(r) #add this coordinates information to #each dictionary entry P.update({ R.gen(varindex): -pol.constant_coefficient() / pol.monomial_coefficient(r) }) new_points.append(copy(P)) else: new_points.append(P) good = 1 if good: points = new_points #the dictionary entries now have values for all coordinates #they are the rational solutions to the equations #make them into affine points for i in range(len(points)): if numerical: if len(points[i]) == N: S = AS([points[i][R.gen(j)] for j in range(N)]) if all( g(list(S)) < zero_tol for g in X.defining_polynomials()): rat_points.append(S) else: if len(points[i]) == N and I.subs(points[i]) == I0: S = X([points[i][R.gen(j)] for j in range(N)]) rat_points.append(S) rat_points = sorted(rat_points) return rat_points R = self.value_ring() B = kwds.pop('bound', 0) tol = kwds.pop('tolerance', 1e-2) prec = kwds.pop('precision', 53) if is_RationalField(R) or R == ZZ: if not B > 0: raise TypeError("a positive bound B (= %s) must be specified" % B) from sage.schemes.affine.affine_rational_point import enum_affine_rational_field return enum_affine_rational_field(self, B) if R in NumberFields(): if not B > 0: raise TypeError("a positive bound B (= %s) must be specified" % B) from sage.schemes.affine.affine_rational_point import enum_affine_number_field return enum_affine_number_field(self, bound=B, tolerance=tol, precision=prec) elif is_FiniteField(R): from sage.schemes.affine.affine_rational_point import enum_affine_finite_field return enum_affine_finite_field(self) else: raise TypeError("unable to enumerate points over %s" % R)
def mega_plot(K, x, y, dx, dy, directory="/tmp/", pause_time=100): r""" Plots a trajectory on the MegaWollmilchsau which starts at (x,y) in the square and moves in direction of the vector (dx,dy). It only plots within three squares surrounding the base square. The directory given in the parameter will be filled with some data pertaining to the trajectory. A text file named orbit_setup.txt will be produced to describe the initial conditions. Periodically (after drawing pause_time segments), the program will write to a text file orbitN.txt about the segments and produce orbitN.svg depicting the trajectory. The program will run until you press Control-C (or until the power is cut to your processor :) ). sage: import flatsurf sage: import flatsurf.demo sage: from flatsurf.demo.mega_wollmilchsau_plotter import mega_plot sage: from sage.calculus.predefined import x sage: from sage.rings.integer_ring import ZZ sage: from sage.rings.number_field.number_field import NumberField sage: K.<sqrt2> = NumberField(x**2-2, embedding=ZZ(1)) sage: x = K.zero() sage: y = K.zero() sage: dx = K.one() sage: dy = sqrt2 sage: mega_plot(K,x,y,dx,dy, directory="/tmp/", pause_time = 10) # not tested: BUG Segment #0 (plotted 0) Segment #1 (plotted 1)... """ # Check the directory: from os import path if not path.isdir(directory): ValueError("Provided directory must be a directory") # Construct the surface: from flatsurf.geometry.mega_wollmilchsau import MegaWollmilchsau s = MegaWollmilchsau() # Get the labels for 3 polygons. l0 = s.base_label() l1 = s.opposite_edge(l0, 1)[0] l2 = s.opposite_edge(l0, 2)[0] labels = [l0, l1, l2] # Setup the portion of the surface we want to draw from flatsurf.graphical.surface import GraphicalSurface gs = GraphicalSurface(s) gs.make_adjacent_and_visible(l0, 1) gs.make_adjacent_and_visible(l0, 2) # Construct a tangent vector from flatsurf.geometry.tangent_bundle import SimilaritySurfaceTangentBundle, SimilaritySurfaceTangentVector tb = SimilaritySurfaceTangentBundle(s) from sage.modules.free_module import VectorSpace V = VectorSpace(K, 2) v = SimilaritySurfaceTangentVector(tb, l0, V((x, y)), V((dx, dy))) # Construct a segment using the tangent vector from flatsurf.geometry.straight_line_trajectory import SegmentInPolygon seg = SegmentInPolygon(v) # Plot the surface p = gs.plot() # Used for drawing segments: from flatsurf.graphical.straight_line_trajectory import GraphicalSegmentInPolygon # Prepare to loop: all = 0 count = 0 # For providing human readable points from sage.rings.real_mpfr import RR # Record the initial conditions to a file: f = open(path.join(directory, "orbit_setup.txt"), 'w') f.write("Field: " + str(K) + "\n") f.write("x: " + str(x) + "\n") f.write("y: " + str(y) + "\n") f.write("dx: " + str(dx) + "\n") f.write("dy: " + str(dy) + "\n") f.close() # Move forward through segments. Pay attention when the segment lies within our list of # polygons we care about. Plot them and print some data about them to a file. # Every 100 times we do this, we move to a new file. while True: f = open( path.join(directory, "orbit" + str(count / pause_time) + ".txt"), 'w') count_start = count while (count == count_start) or (count % pause_time != 0): if seg.polygon_label() in labels: print("Segment #" + str(all) + " (plotted " + str(count) + ")") f.write("Segment #" + str(all) + " (plotted " + str(count) + ")\n") f.write("Label: " + str(seg.polygon_label()) + "\n") f.write("point: " + str(seg.start_point()) + "\n") f.write("RR point: "+str(RR(seg.start_point()[0]))+", "+\ str(RR(seg.start_point()[1]))+"\n") gseg = GraphicalSegmentInPolygon(gs, seg) p += gseg.plot() count += 1 # Move to next segment under flow: seg = seg.next() all += 1 # Save the plot to a file. f.close() p.save( path.join(directory, "orbit" + str(count / pause_time - 1) + ".svg")) print("Wrote to files named 'orbit" + str(count / pause_time - 1) + "' with extension .txt and .svg")
def idwt(self, other="haar", wavelet_k=2): """ Implements the gsl ``WaveletTransform.backward()`` in :mod:`~sage.gsl.dwt`. Assumes the length of the sample is a power of 2. Uses the GSL function ``gsl_wavelet_transform_backward()``. INPUT: - ``other`` -- Must be one of the following: * ``"haar"`` * ``"daubechies"`` * ``"daubechies_centered"`` * ``"haar_centered"`` * ``"bspline"`` * ``"bspline_centered"`` - ``wavelet_k`` -- For daubechies wavelets, ``wavelet_k`` specifies a daubechie wavelet with `k/2` vanishing moments. `k = 4,6,...,20` for `k` even are the only ones implemented. For Haar wavelets, ``wavelet_k`` must be 2. For bspline wavelets, ``wavelet_k`` equal to `103,105,202,204, 206,208,301,305,307,309` will give biorthogonal B-spline wavelets of order `(i,j)` where ``wavelet_k`` equals `100 \cdot i + j`. EXAMPLES:: sage: J = range(8) sage: A = [RR(1) for i in J] sage: s = IndexedSequence(A,J) sage: t = s.dwt() sage: t # random arch dependent output Indexed sequence: [2.82842712474999, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000] indexed by [0, 1, 2, 3, 4, 5, 6, 7] sage: t.idwt() # random arch dependent output Indexed sequence: [1.00000000000000, 1.00000000000000, 1.00000000000000, 1.00000000000000, 1.00000000000000, 1.00000000000000, 1.00000000000000, 1.00000000000000] indexed by [0, 1, 2, 3, 4, 5, 6, 7] sage: t.idwt() == s True sage: J = range(16) sage: A = [RR(1) for i in J] sage: s = IndexedSequence(A,J) sage: t = s.dwt("bspline", 103) sage: t # random arch dependent output Indexed sequence: [4.00000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000, 0.000000000000000] indexed by [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] sage: t.idwt("bspline", 103) == s True """ # elements must be coercible into RR J = self.index_object() ## must be = range(N) N = len(J) ## must be 1 minus a power of 2 S = self.list() k = wavelet_k if other=="haar" or other=="haar_centered": if k in [2]: a = WaveletTransform(N,other,wavelet_k) else: raise ValueError("wavelet_k must be = 2") if other=="debauchies" or other=="debauchies_centered": if k in [4,6,8,10,12,14,16,18,20]: a = WaveletTransform(N,other,wavelet_k) else: raise ValueError("wavelet_k must be in {4,6,8,10,12,14,16,18,20}") if other=="bspline" or other=="bspline_centered": if k in [103,105,202,204,206,208,301,305,307,309]: a = WaveletTransform(N,other,103) else: raise ValueError("wavelet_k must be in {103,105,202,204,206,208,301,305,307,309}") for i in range(N): a[i] = S[i] a.backward_transform() return IndexedSequence([RR(a[j]) for j in J],J)
def numerical_points(self, F=None, **kwds): """ Return some or all numerical approximations of rational points of an affine scheme. This is for dimension 0 subschemes only and the points are determined through a groebner calculation over the base ring and then numerically approximating the roots of the resulting polynomials. If the base ring is a number field, the embedding into ``F`` must be known. INPUT: ``F`` - numerical ring kwds: - ``zero_tolerance`` - positive real number (optional, default=10^(-10)). For numerically inexact fields, points are on the subscheme if they satisfy the equations to within tolerance. OUTPUT: A list of points in the ambient space. .. WARNING:: For numerically inexact fields the list of points returned may contain repeated or be missing points due to tolerance. EXAMPLES:: sage: K.<v> = QuadraticField(3) sage: A.<x,y> = AffineSpace(K, 2) sage: X = A.subscheme([x^3 - v^2*y, y - v*x^2 + 3]) sage: L = X(K).numerical_points(F=RR); L # abs tol 1e-14 [(-1.18738247880014, -0.558021142104134), (1.57693558184861, 1.30713548084184), (4.80659931965815, 37.0162574656220)] sage: L[0].codomain() Affine Space of dimension 2 over Real Field with 53 bits of precision :: sage: A.<x,y> = AffineSpace(QQ, 2) sage: X = A.subscheme([y^2 - x^2 - 3*x, x^2 - 10*y]) sage: len(X(QQ).numerical_points(F=ComplexField(100))) 4 :: sage: A.<x1, x2> = AffineSpace(QQ, 2) sage: E = A.subscheme([30*x1^100 + 1000*x2^2 + 2000*x1*x2 + 1, x1 + x2]) sage: len(E(A.base_ring()).numerical_points(F=CDF, zero_tolerance=1e-9)) 100 TESTS:: sage: A.<x,y> = AffineSpace(QQ, 2) sage: X = A.subscheme([y^2 - x^2 - 3*x, x^2 - 10*y]) sage: X(QQ).numerical_points(F=QQ) Traceback (most recent call last): ... TypeError: F must be a numerical field :: sage: A.<x,y> = AffineSpace(QQ, 2) sage: X = A.subscheme([y^2 - x^2 - 3*x, x^2 - 10*y]) sage: X(QQ).numerical_points(F=CC, zero_tolerance=-1) Traceback (most recent call last): ... ValueError: tolerance must be positive """ from sage.schemes.affine.affine_space import is_AffineSpace if F is None: F = CC if F not in Fields() or not hasattr(F, 'precision'): raise TypeError('F must be a numerical field') X = self.codomain() if X.base_ring() not in NumberFields(): raise TypeError('base ring must be a number field') AA = X.ambient_space().change_ring(F) if not is_AffineSpace(X) and X.base_ring() in Fields(): # Then X must be a subscheme dim_ideal = X.defining_ideal().dimension() if dim_ideal != 0: # no points return [] else: return [] # if X zero-dimensional zero_tol = RR(kwds.pop('zero_tolerance', 10**(-10))) if zero_tol <= 0: raise ValueError("tolerance must be positive") rat_points = [] PS = X.ambient_space() N = PS.dimension_relative() BR = X.base_ring() # need a lexicographic ordering for elimination R = PolynomialRing(BR, N, PS.gens(), order='lex') RF = R.change_ring(F) I = R.ideal(X.defining_polynomials()) # Determine the points through elimination This is much faster # than using the I.variety() function on each affine chart. G = I.groebner_basis() G = [RF(g) for g in G] if G != [1]: P = {} points = [P] # work backwards from solving each equation for the possible # values of the next coordinate for g in reversed(G): new_points = [] good = False for P in points: # substitute in our dictionary entry that has the # values of coordinates known so far. This results # in a single variable polynomial (by elimination) L = g.substitute(P) if len(RF(L).variables()) == 1: r = L.variables()[0] var = RF.gen(RF.gens().index(r)) for pol in L.univariate_polynomial().roots( ring=F, multiplicities=False): P[var] = pol new_points.append(copy(P)) good = True else: new_points.append(P) good = True if good: points = new_points # the dictionary entries now have values for all # coordinates they are the rational solutions to the # equations make them into affine points polys = [g.change_ring(F) for g in X.defining_polynomials()] for P in points: if len(P) == N: S = AA([P[R.gen(j)] for j in range(N)]) if all(g(list(S)) < zero_tol for g in polys): rat_points.append(S) rat_points = sorted(rat_points) return rat_points
def det_given_divisor(A, d, proof=True, stabilize=2): """ Given a divisor d of the determinant of A, compute the determinant of A. INPUT: - ``A`` -- a square integer matrix - ``d`` -- a nonzero integer that is assumed to divide the determinant of A - ``proof`` -- bool (default: True) compute det modulo enough primes so that the determinant is computed provably correctly (via the Hadamard bound). It would be VERY hard for ``det()`` to fail even with proof=False. - ``stabilize`` -- int (default: 2) if proof = False, then compute the determinant modulo `p` until ``stabilize`` successive modulo determinant computations stabilize. OUTPUT: integer -- determinant EXAMPLES:: sage: import sage.matrix.matrix_integer_dense_hnf as matrix_integer_dense_hnf sage: a = matrix(ZZ,3,[-1, -1, -1, -20, 4, 1, -1, 1, 2]) sage: matrix_integer_dense_hnf.det_given_divisor(a, 3) -30 sage: matrix_integer_dense_hnf.det_given_divisor(a, 3, proof=False) -30 sage: matrix_integer_dense_hnf.det_given_divisor(a, 3, proof=False, stabilize=1) -30 sage: a.det() -30 Here we illustrate proof=False giving a wrong answer:: sage: p = matrix_integer_dense_hnf.max_det_prime(2) sage: q = previous_prime(p) sage: a = matrix(ZZ, 2, [p, 0, 0, q]) sage: p * q 70368442188091 sage: matrix_integer_dense_hnf.det_given_divisor(a, 1, proof=False, stabilize=2) 0 This still works, because we do not work modulo primes that divide the determinant bound, which is found using a p-adic algorithm:: sage: a.det(proof=False, stabilize=2) 70368442188091 3 primes is enough:: sage: matrix_integer_dense_hnf.det_given_divisor(a, 1, proof=False, stabilize=3) 70368442188091 sage: matrix_integer_dense_hnf.det_given_divisor(a, 1, proof=False, stabilize=5) 70368442188091 sage: matrix_integer_dense_hnf.det_given_divisor(a, 1, proof=True) 70368442188091 TESTS:: sage: m = diagonal_matrix(ZZ, 68, [2]*66 + [1,1]) sage: m.det() 73786976294838206464 """ p = max_det_prime(A.nrows()) z_mod = [] moduli = [] assert d != 0 z_so_far = 1 N_so_far = 1 if proof: N = 1 B = (2 * 10**A.hadamard_bound()) // d + 1 dd = d # bad verbose statement, since computing the log overflows! est = int(RR(B).log() / RR(p).log()) + 1 cnt = 1 verbose("Multimodular det -- need to use about %s primes." % est, level=1) while N < B: if d % p != 0: tm = cputime() dd, z_so_far, N_so_far = det_from_modp_and_divisor( A, d, p, z_mod, moduli, z_so_far, N_so_far) N *= p verbose( "computed det mod p=%s which is %s (of about %s)" % (p, cnt, est), tm) p = previous_prime(p) cnt += 1 return dd else: val = [] while True: if d % p: tm = cputime() dd, z_so_far, N_so_far = det_from_modp_and_divisor( A, d, p, z_mod, moduli, z_so_far, N_so_far) verbose("computed det mod %s" % p, tm) val.append(dd) if len(val) >= stabilize and len(set(val[-stabilize:])) == 1: return val[-1] p = previous_prime(p)
def vertex_to_angle(v): # v==0 corresponds to pi/2 return -2 * pi * RR(v) / self.r() + 5 * pi / 2