def rotation_matrix_angle(r, check=False): r""" Return the angle of the rotation matrix ``r`` divided by ``2 pi``. EXAMPLES:: sage: from flatsurf.geometry.matrix_2x2 import rotation_matrix_angle sage: def rot_matrix(p, q): ....: z = QQbar.zeta(q) ** p ....: c = z.real() ....: s = z.imag() ....: return matrix(AA, 2, [c,-s,s,c]) sage: [rotation_matrix_angle(rot_matrix(i, 5)) for i in range(1,5)] [1/5, 2/5, 3/5, 4/5] sage: [rotation_matrix_angle(rot_matrix(i, 5)) for i in range(1,5)] [1/5, 2/5, 3/5, 4/5] sage: [rotation_matrix_angle(rot_matrix(i,7)) for i in range(1,7)] [1/7, 2/7, 3/7, 4/7, 5/7, 6/7] Some random tests:: sage: for _ in range(100): ....: r = QQ.random_element(x=0,y=500) ....: r -= r.floor() ....: m = rot_matrix(r.numerator(), r.denominator()) ....: assert rotation_matrix_angle(m) == r .. NOTE:: This is using floating point arithmetic and might be wrong. """ e0, e1 = r.change_ring(CDF).eigenvalues() m0 = (e0.log() / 2 / CDF.pi()).imag() m1 = (e1.log() / 2 / CDF.pi()).imag() r0 = RR(m0).nearby_rational(max_denominator=10000) r1 = RR(m1).nearby_rational(max_denominator=10000) if r0 != -r1: raise RuntimeError r0 = r0.abs() if r[0][1] > 0: return QQ.one() - r0 else: return r0 if check: e = r.change_ring(AA).eigenvalues()[0] if e.minpoly() != ZZ['x'].cyclotomic_polynomial()(r.denominator()): raise RuntimeError z = QQbar.zeta(r.denominator()) if z**r.numerator() != e: raise RuntimeError return r
def rotation_matrix_angle(r, check=False): r""" Return the angle of the rotation matrix ``r`` divided by ``2 pi``. EXAMPLES:: sage: from flatsurf.geometry.matrix_2x2 import rotation_matrix_angle sage: def rot_matrix(p, q): ....: z = QQbar.zeta(q) ** p ....: c = z.real() ....: s = z.imag() ....: return matrix(AA, 2, [c,-s,s,c]) sage: [rotation_matrix_angle(rot_matrix(i, 5)) for i in range(1,5)] [1/5, 2/5, 3/5, 4/5] sage: [rotation_matrix_angle(rot_matrix(i,7)) for i in range(1,7)] [1/7, 2/7, 3/7, 4/7, 5/7, 6/7] Some random tests:: sage: for _ in range(100): ....: r = QQ.random_element(x=0,y=500) ....: r -= r.floor() ....: m = rot_matrix(r.numerator(), r.denominator()) ....: assert rotation_matrix_angle(m) == r .. NOTE:: This is using floating point arithmetic and might be wrong. """ e0,e1 = r.change_ring(CDF).eigenvalues() m0 = (e0.log() / 2 / CDF.pi()).imag() m1 = (e1.log() / 2 / CDF.pi()).imag() r0 = RR(m0).nearby_rational(max_denominator=10000) r1 = RR(m1).nearby_rational(max_denominator=10000) if r0 != -r1: raise RuntimeError r0 = r0.abs() if r[0][1] > 0: return QQ.one() - r0 else: return r0 if check: e = r.change_ring(AA).eigenvalues()[0] if e.minpoly() != ZZ['x'].cyclotomic_polynomial()(r.denominator()): raise RuntimeError z = QQbar.zeta(r.denominator()) if z**r.numerator() != e: raise RuntimeError return r
def spherical_bessel_Y(n,var, algorithm="maxima"): r""" Returns the spherical Bessel function of the second kind for integers n -1. Reference: AS 10.1.9 page 437 and AS 10.1.15 page 439. EXAMPLES:: sage: x = PolynomialRing(QQ, 'x').gen() sage: spherical_bessel_Y(2,x) -((3/x^2 - 1)*cos(x) + 3*sin(x)/x)/x """ if algorithm == "scipy": import scipy.special return CDF(scipy.special.sph_yn(int(n),float(var))) elif algorithm == 'maxima': _init() return meval("spherical_bessel_y(%s,%s)"%(ZZ(n),var)) else: raise ValueError("unknown algorithm '%s'"%algorithm)
def spherical_bessel_J(n, var, algorithm="maxima"): r""" Returns the spherical Bessel function of the first kind for integers n >= 1. Reference: AS 10.1.8 page 437 and AS 10.1.15 page 439. EXAMPLES:: sage: spherical_bessel_J(2,x) ((3/x^2 - 1)*sin(x) - 3*cos(x)/x)/x sage: spherical_bessel_J(1, 5.2, algorithm='scipy') -0.12277149950007... sage: spherical_bessel_J(1, 3, algorithm='scipy') 0.345677499762355... """ if algorithm == "scipy": from scipy.special.specfun import sphj return CDF(sphj(int(n), float(var))[1][-1]) elif algorithm == 'maxima': _init() return meval("spherical_bessel_j(%s,%s)"%(ZZ(n),var)) else: raise ValueError("unknown algorithm '%s'"%algorithm)
def _eigenvectors(self): r""" Find numerical approximations to simultaneous eigenvectors in self.modular_symbols() for all T_p in self._tp. EXAMPLES:: sage: n = numerical_eigenforms(61) sage: n._eigenvectors() # random order [ 1.0 0.289473640239 0.176788851952 0.336707726757 2.4182243084e-16] [ 0 -0.0702748344418 0.491416161212 0.155925712173 0.707106781187] [ 0 0.413171180356 0.141163094698 0.0923242547901 0.707106781187] [ 0 0.826342360711 0.282326189397 0.18464850958 6.79812569682e-16] [ 0 0.2402380858 0.792225196393 0.905370774276 4.70805946682e-16] TESTS: This tests if this routine selects only eigenvectors with multiplicity one. Two of the eigenvalues are (roughly) -92.21 and -90.30 so if we set ``eps = 2.0`` then they should compare as equal, causing both eigenvectors to be absent from the matrix returned. The remaining eigenvalues (ostensibly unique) are visible in the test, which should be independent of which eigenvectors are returned, but it does presume an ordering of these eigenvectors for the test to succeed. This exercises a correction in :trac:`8018`. :: sage: n = numerical_eigenforms(61, eps=2.0) sage: evectors = n._eigenvectors() sage: evalues = diagonal_matrix(CDF, [-283.0, 108.522012456, 142.0]) sage: diff = n._hecke_matrix*evectors - evectors*evalues sage: sum([abs(diff[i,j]) for i in range(5) for j in range(3)]) < 1.0e-9 True """ try: return self.__eigenvectors except AttributeError: pass verbose('Finding eigenvector basis') M = self.modular_symbols() tp = self._tp p = tp[0] t = M.T(p).matrix() for p in tp[1:]: t += randint(-50,50)*M.T(p).matrix() self._hecke_matrix = t global scipy if scipy is None: import scipy import scipy.linalg evals,eig = scipy.linalg.eig(self._hecke_matrix.numpy(), right=True, left=False) B = matrix(eig) v = [CDF(evals[i]) for i in range(len(evals))] # Determine the eigenvectors with eigenvalues of multiplicity # one, with equality controlled by the value of eps # Keep just these eigenvectors eps = self._eps w = [] for i in range(len(v)): e = v[i] uniq = True for j in range(len(v)): if uniq and i != j and abs(e-v[j]) < eps: uniq = False if uniq: w.append(i) self.__eigenvectors = B.matrix_from_columns(w) return self.__eigenvectors
def julia_plot(f=None, **kwds): r""" Plots the Julia set of a given polynomial ``f``. Users can specify whether they would like to display the Mandelbrot side by side with the Julia set with the ``mandelbrot`` argument. If ``f`` is not specified, this method defaults to `f(z) = z^2-1`. The Julia set of a polynomial ``f`` is the set of complex numbers `z` for which the function `f(z)` is bounded under iteration. The Julia set can be visualized by plotting each point in the set in the complex plane. Julia sets are examples of fractals when plotted in the complex plane. ALGORITHM: Let `R_c = \bigl(1 + \sqrt{1 + 4|c|}\bigr)/2` if the polynomial is of the form `f(z) = z^2 + c`; otherwise, let `R_c = 2`. For every `p \in \mathbb{C}`, if `|f^{k}(p)| > R_c` for some `k \geq 0`, then `f^{n}(p) \to \infty`. Let `N` be the maximum number of iterations. Compute the first `N` points on the orbit of `p` under `f`. If for any `k < N`, `|f^{k}(p)| > R_c`, we stop the iteration and assign a color to the point `p` based on how quickly `p` escaped to infinity under iteration of `f`. If `|f^{i}(p)| \leq R_c` for all `i \leq N`, we assume `p` is in the Julia set and assign the point `p` the color black. INPUT: - ``f`` -- input polynomial (optional - default: ``z^2 - 1``). - ``period`` -- list (optional - default: ``None``), returns the Julia set for a random `c` value with the given (formal) cycle structure. - ``mandelbrot`` -- boolean (optional - default: ``True``), when set to ``True``, an image of the Mandelbrot set is appended to the right of the Julia set. - ``point_color`` -- RGB color (optional - default: ``'tomato'``), color of the point `c` in the Mandelbrot set (any valid input for Color). - ``x_center`` -- double (optional - default: ``-1.0``), Real part of center point. - ``y_center`` -- double (optional - default: ``0.0``), Imaginary part of center point. - ``image_width`` -- double (optional - default: ``4.0``), width of image in the complex plane. - ``max_iteration`` -- long (optional - default: ``500``), maximum number of iterations the map `f(z)`. - ``pixel_count`` -- long (optional - default: ``500``), side length of image in number of pixels. - ``base_color`` -- hex color (optional - default: ``'steelblue'``), color used to determine the coloring of set (any valid input for Color). - ``level_sep`` -- long (optional - default: 1), number of iterations between each color level. - ``number_of_colors`` -- long (optional - default: 30), number of colors used to plot image. - ``interact`` -- boolean (optional - default: ``False``), controls whether plot will have interactive functionality. OUTPUT: 24-bit RGB image of the Julia set in the complex plane. .. TODO:: Implement the side-by-side Mandelbrot-Julia plots for general one-parameter families of polynomials. EXAMPLES: The default ``f`` is `z^2 - 1`:: sage: julia_plot() 1001x500px 24-bit RGB image To display only the Julia set, set ``mandelbrot`` to ``False``:: sage: julia_plot(mandelbrot=False) 500x500px 24-bit RGB image :: sage: R.<z> = CC[] sage: f = z^3 - z + 1 sage: julia_plot(f) 500x500px 24-bit RGB image To display an interactive plot of the Julia set in the Notebook, set ``interact`` to ``True``. (This is only implemented for polynomials of the form ``f = z^2 + c``):: sage: julia_plot(interact=True) interactive(children=(FloatSlider(value=-1.0, description=u'Real c'... :: sage: R.<z> = CC[] sage: f = z^2 + 1/2 sage: julia_plot(f,interact=True) interactive(children=(FloatSlider(value=0.5, description=u'Real c'... To return the Julia set of a random `c` value with (formal) cycle structure `(2,3)`, set ``period = [2,3]``:: sage: julia_plot(period=[2,3]) 1001x500px 24-bit RGB image To return all of the Julia sets of `c` values with (formal) cycle structure `(2,3)`:: sage: period = [2,3] # not tested ....: R.<c> = QQ[] ....: P.<x,y> = ProjectiveSpace(R,1) ....: f = DynamicalSystem([x^2+c*y^2, y^2]) ....: L = f.dynatomic_polynomial(period).subs({x:0,y:1}).roots(ring=CC) ....: c_values = [k[0] for k in L] ....: for c in c_values: ....: julia_plot(c) Polynomial maps can be defined over a polynomial ring or a fraction field, so long as ``f`` is polynomial:: sage: R.<z> = CC[] sage: f = z^2 - 1 sage: julia_plot(f) 1001x500px 24-bit RGB image :: sage: R.<z> = CC[] sage: K = R.fraction_field(); z = K.gen() sage: f = z^2-1 sage: julia_plot(f) 1001x500px 24-bit RGB image Interact functionality is not implemented if the polynomial is not of the form `f = z^2 + c`:: sage: R.<z> = CC[] sage: f = z^3 + 1 sage: julia_plot(f, interact=True) Traceback (most recent call last): ... NotImplementedError: The interactive plot is only implemented for ... """ # extract keyword arguments period = kwds.pop("period", None) mandelbrot = kwds.pop("mandelbrot", True) point_color = kwds.pop("point_color", 'tomato') x_center = kwds.pop("x_center", 0.0) y_center = kwds.pop("y_center", 0.0) image_width = kwds.pop("image_width", 4.0) max_iteration = kwds.pop("max_iteration", 500) pixel_count = kwds.pop("pixel_count", 500) base_color = kwds.pop("base_color", 'steelblue') level_sep = kwds.pop("level_sep", 1) number_of_colors = kwds.pop("number_of_colors", 30) interacts = kwds.pop("interact", False) f_is_default_after_all = None if period: # pick a random c with the specified period R = PolynomialRing(CC, 'c') c = R.gen() x, y = ProjectiveSpace(R, 1, 'x,y').gens() F = DynamicalSystem([x**2 + c * y**2, y**2]) L = F.dynatomic_polynomial(period).subs({x: 0, y: 1}).roots(ring=CC) c = L[randint(0, len(L) - 1)][0] base_color = Color(base_color) point_color = Color(point_color) EPS = 0.00001 if f is not None and period is None: # f user-specified and no period given # try to coerce f to live in a polynomial ring S = PolynomialRing(CC, names='z') z = S.gen() try: f_poly = S(f) except TypeError: R = f.parent() if not (R.is_integral_domain() and (CC.is_subring(R) or CDF.is_subring(R))): raise ValueError('Given `f` must be a complex polynomial.') else: raise NotImplementedError( 'Julia sets not implemented for rational functions.') if (f_poly - z * z) in CC: # f is specified and of the form z^2 + c. f_is_default_after_all = True c = f_poly - z * z else: # f is specified and not of the form z^2 + c if interacts: raise NotImplementedError( "The interactive plot is only implemented for " "polynomials of the form f = z^2 + c.") else: return general_julia(f_poly, x_center, y_center, image_width, max_iteration, pixel_count, level_sep, number_of_colors, base_color) # otherwise we can use fast_julia_plot for z^2 + c if f_is_default_after_all or f is None or period is not None: # specify default c = -1 value if f and period were not specified if not f_is_default_after_all and period is None: c = -1 c = CC(c) c_real = c.real() c_imag = c.imag() if interacts: # set widgets from ipywidgets.widgets import FloatSlider, IntSlider, \ ColorPicker, interact widgets = dict( c_real=FloatSlider(min=-2.0, max=2.0, step=EPS, value=c_real, description="Real c"), c_imag=FloatSlider(min=-2.0, max=2.0, step=EPS, value=c_imag, description="Imag c"), x_center=FloatSlider(min=-1.0, max=1.0, step=EPS, value=x_center, description="Real center"), y_center=FloatSlider(min=-1.0, max=1.0, step=EPS, value=y_center, description="Imag center"), image_width=FloatSlider(min=EPS, max=4.0, step=EPS, value=image_width, description="Width"), max_iteration=IntSlider(min=0, max=1000, value=max_iteration, description="Iterations"), pixel_count=IntSlider(min=10, max=1000, value=pixel_count, description="Pixels"), level_sep=IntSlider(min=1, max=20, value=level_sep, description="Color sep"), color_num=IntSlider(min=1, max=100, value=number_of_colors, description="# Colors"), base_color=ColorPicker(value=base_color.html_color(), description="Base color"), ) if mandelbrot: widgets["point_color"] = ColorPicker( value=point_color.html_color(), description="Point color") return interact(**widgets).widget(julia_helper) else: return interact(**widgets).widget(fast_julia_plot) elif mandelbrot: # non-interactive with mandelbrot return julia_helper(c_real, c_imag, x_center, y_center, image_width, max_iteration, pixel_count, level_sep, number_of_colors, base_color, point_color) else: # non-interactive without mandelbrot return fast_julia_plot(c_real, c_imag, x_center, y_center, image_width, max_iteration, pixel_count, level_sep, number_of_colors, base_color)