passagemath-symbolics 10.8.1a1__cp311-cp311-macosx_13_0_arm64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) hide show
  1. passagemath_symbolics/.dylibs/libgmp.10.dylib +0 -0
  2. passagemath_symbolics/__init__.py +3 -0
  3. passagemath_symbolics-10.8.1a1.dist-info/METADATA +186 -0
  4. passagemath_symbolics-10.8.1a1.dist-info/RECORD +182 -0
  5. passagemath_symbolics-10.8.1a1.dist-info/WHEEL +6 -0
  6. passagemath_symbolics-10.8.1a1.dist-info/top_level.txt +3 -0
  7. sage/all__sagemath_symbolics.py +17 -0
  8. sage/calculus/all.py +14 -0
  9. sage/calculus/calculus.py +2838 -0
  10. sage/calculus/desolvers.py +1864 -0
  11. sage/calculus/predefined.py +51 -0
  12. sage/calculus/tests.py +225 -0
  13. sage/calculus/var.cpython-311-darwin.so +0 -0
  14. sage/calculus/var.pyx +401 -0
  15. sage/dynamics/all__sagemath_symbolics.py +6 -0
  16. sage/dynamics/complex_dynamics/all.py +5 -0
  17. sage/dynamics/complex_dynamics/mandel_julia.py +765 -0
  18. sage/dynamics/complex_dynamics/mandel_julia_helper.cpython-311-darwin.so +0 -0
  19. sage/dynamics/complex_dynamics/mandel_julia_helper.pyx +1034 -0
  20. sage/ext/all__sagemath_symbolics.py +1 -0
  21. sage/ext_data/kenzo/CP2.txt +45 -0
  22. sage/ext_data/kenzo/CP3.txt +349 -0
  23. sage/ext_data/kenzo/CP4.txt +4774 -0
  24. sage/ext_data/kenzo/README.txt +49 -0
  25. sage/ext_data/kenzo/S4.txt +20 -0
  26. sage/ext_data/magma/latex/latex.m +1021 -0
  27. sage/ext_data/magma/latex/latex.spec +1 -0
  28. sage/ext_data/magma/sage/basic.m +356 -0
  29. sage/ext_data/magma/sage/sage.spec +1 -0
  30. sage/ext_data/magma/spec +9 -0
  31. sage/geometry/all__sagemath_symbolics.py +8 -0
  32. sage/geometry/hyperbolic_space/all.py +5 -0
  33. sage/geometry/hyperbolic_space/hyperbolic_coercion.py +755 -0
  34. sage/geometry/hyperbolic_space/hyperbolic_constants.py +5 -0
  35. sage/geometry/hyperbolic_space/hyperbolic_geodesic.py +2419 -0
  36. sage/geometry/hyperbolic_space/hyperbolic_interface.py +206 -0
  37. sage/geometry/hyperbolic_space/hyperbolic_isometry.py +1083 -0
  38. sage/geometry/hyperbolic_space/hyperbolic_model.py +1502 -0
  39. sage/geometry/hyperbolic_space/hyperbolic_point.py +621 -0
  40. sage/geometry/riemannian_manifolds/all.py +7 -0
  41. sage/geometry/riemannian_manifolds/parametrized_surface3d.py +1632 -0
  42. sage/geometry/riemannian_manifolds/surface3d_generators.py +461 -0
  43. sage/interfaces/all__sagemath_symbolics.py +1 -0
  44. sage/interfaces/magma.py +2991 -0
  45. sage/interfaces/magma_free.py +90 -0
  46. sage/interfaces/maple.py +1402 -0
  47. sage/interfaces/mathematica.py +1345 -0
  48. sage/interfaces/mathics.py +1312 -0
  49. sage/interfaces/sympy.py +1398 -0
  50. sage/interfaces/sympy_wrapper.py +197 -0
  51. sage/interfaces/tides.py +938 -0
  52. sage/libs/all__sagemath_symbolics.py +6 -0
  53. sage/manifolds/all.py +7 -0
  54. sage/manifolds/calculus_method.py +553 -0
  55. sage/manifolds/catalog.py +437 -0
  56. sage/manifolds/chart.py +4010 -0
  57. sage/manifolds/chart_func.py +3416 -0
  58. sage/manifolds/continuous_map.py +2183 -0
  59. sage/manifolds/continuous_map_image.py +155 -0
  60. sage/manifolds/differentiable/affine_connection.py +2475 -0
  61. sage/manifolds/differentiable/all.py +1 -0
  62. sage/manifolds/differentiable/automorphismfield.py +1383 -0
  63. sage/manifolds/differentiable/automorphismfield_group.py +604 -0
  64. sage/manifolds/differentiable/bundle_connection.py +1445 -0
  65. sage/manifolds/differentiable/characteristic_cohomology_class.py +1840 -0
  66. sage/manifolds/differentiable/chart.py +1241 -0
  67. sage/manifolds/differentiable/curve.py +1028 -0
  68. sage/manifolds/differentiable/de_rham_cohomology.py +541 -0
  69. sage/manifolds/differentiable/degenerate.py +559 -0
  70. sage/manifolds/differentiable/degenerate_submanifold.py +1668 -0
  71. sage/manifolds/differentiable/diff_form.py +1660 -0
  72. sage/manifolds/differentiable/diff_form_module.py +1062 -0
  73. sage/manifolds/differentiable/diff_map.py +1315 -0
  74. sage/manifolds/differentiable/differentiable_submanifold.py +291 -0
  75. sage/manifolds/differentiable/examples/all.py +1 -0
  76. sage/manifolds/differentiable/examples/euclidean.py +2517 -0
  77. sage/manifolds/differentiable/examples/real_line.py +897 -0
  78. sage/manifolds/differentiable/examples/sphere.py +1186 -0
  79. sage/manifolds/differentiable/examples/symplectic_space.py +187 -0
  80. sage/manifolds/differentiable/examples/symplectic_space_test.py +40 -0
  81. sage/manifolds/differentiable/integrated_curve.py +4035 -0
  82. sage/manifolds/differentiable/levi_civita_connection.py +841 -0
  83. sage/manifolds/differentiable/manifold.py +4254 -0
  84. sage/manifolds/differentiable/manifold_homset.py +1826 -0
  85. sage/manifolds/differentiable/metric.py +3032 -0
  86. sage/manifolds/differentiable/mixed_form.py +1507 -0
  87. sage/manifolds/differentiable/mixed_form_algebra.py +559 -0
  88. sage/manifolds/differentiable/multivector_module.py +800 -0
  89. sage/manifolds/differentiable/multivectorfield.py +1522 -0
  90. sage/manifolds/differentiable/poisson_tensor.py +268 -0
  91. sage/manifolds/differentiable/pseudo_riemannian.py +755 -0
  92. sage/manifolds/differentiable/pseudo_riemannian_submanifold.py +1839 -0
  93. sage/manifolds/differentiable/scalarfield.py +1343 -0
  94. sage/manifolds/differentiable/scalarfield_algebra.py +472 -0
  95. sage/manifolds/differentiable/symplectic_form.py +912 -0
  96. sage/manifolds/differentiable/symplectic_form_test.py +220 -0
  97. sage/manifolds/differentiable/tangent_space.py +412 -0
  98. sage/manifolds/differentiable/tangent_vector.py +616 -0
  99. sage/manifolds/differentiable/tensorfield.py +4665 -0
  100. sage/manifolds/differentiable/tensorfield_module.py +963 -0
  101. sage/manifolds/differentiable/tensorfield_paral.py +2450 -0
  102. sage/manifolds/differentiable/tensorfield_paral_test.py +16 -0
  103. sage/manifolds/differentiable/vector_bundle.py +1725 -0
  104. sage/manifolds/differentiable/vectorfield.py +1717 -0
  105. sage/manifolds/differentiable/vectorfield_module.py +2445 -0
  106. sage/manifolds/differentiable/vectorframe.py +1832 -0
  107. sage/manifolds/family.py +270 -0
  108. sage/manifolds/local_frame.py +1490 -0
  109. sage/manifolds/manifold.py +3090 -0
  110. sage/manifolds/manifold_homset.py +452 -0
  111. sage/manifolds/operators.py +359 -0
  112. sage/manifolds/point.py +994 -0
  113. sage/manifolds/scalarfield.py +3718 -0
  114. sage/manifolds/scalarfield_algebra.py +629 -0
  115. sage/manifolds/section.py +3111 -0
  116. sage/manifolds/section_module.py +831 -0
  117. sage/manifolds/structure.py +229 -0
  118. sage/manifolds/subset.py +2721 -0
  119. sage/manifolds/subsets/all.py +1 -0
  120. sage/manifolds/subsets/closure.py +131 -0
  121. sage/manifolds/subsets/pullback.py +883 -0
  122. sage/manifolds/topological_submanifold.py +891 -0
  123. sage/manifolds/trivialization.py +733 -0
  124. sage/manifolds/utilities.py +1348 -0
  125. sage/manifolds/vector_bundle.py +1347 -0
  126. sage/manifolds/vector_bundle_fiber.py +332 -0
  127. sage/manifolds/vector_bundle_fiber_element.py +111 -0
  128. sage/matrix/all__sagemath_symbolics.py +1 -0
  129. sage/matrix/matrix_symbolic_dense.cpython-311-darwin.so +0 -0
  130. sage/matrix/matrix_symbolic_dense.pxd +6 -0
  131. sage/matrix/matrix_symbolic_dense.pyx +1030 -0
  132. sage/matrix/matrix_symbolic_sparse.cpython-311-darwin.so +0 -0
  133. sage/matrix/matrix_symbolic_sparse.pxd +6 -0
  134. sage/matrix/matrix_symbolic_sparse.pyx +1038 -0
  135. sage/modules/all__sagemath_symbolics.py +1 -0
  136. sage/modules/vector_callable_symbolic_dense.py +105 -0
  137. sage/modules/vector_symbolic_dense.py +116 -0
  138. sage/modules/vector_symbolic_sparse.py +118 -0
  139. sage/rings/all__sagemath_symbolics.py +4 -0
  140. sage/rings/asymptotic/all.py +6 -0
  141. sage/rings/asymptotic/asymptotic_expansion_generators.py +1485 -0
  142. sage/rings/asymptotic/asymptotic_ring.py +4858 -0
  143. sage/rings/asymptotic/asymptotics_multivariate_generating_functions.py +4106 -0
  144. sage/rings/asymptotic/growth_group.py +5373 -0
  145. sage/rings/asymptotic/growth_group_cartesian.py +1400 -0
  146. sage/rings/asymptotic/term_monoid.py +5205 -0
  147. sage/rings/function_field/all__sagemath_symbolics.py +2 -0
  148. sage/rings/polynomial/all__sagemath_symbolics.py +1 -0
  149. sage/symbolic/all.py +15 -0
  150. sage/symbolic/assumptions.py +987 -0
  151. sage/symbolic/benchmark.py +93 -0
  152. sage/symbolic/callable.py +456 -0
  153. sage/symbolic/callable.pyi +66 -0
  154. sage/symbolic/comparison_impl.pyi +38 -0
  155. sage/symbolic/complexity_measures.py +35 -0
  156. sage/symbolic/constants.py +1286 -0
  157. sage/symbolic/constants_c_impl.pyi +10 -0
  158. sage/symbolic/expression_conversion_algebraic.py +310 -0
  159. sage/symbolic/expression_conversion_sympy.py +317 -0
  160. sage/symbolic/expression_conversions.py +1727 -0
  161. sage/symbolic/function_factory.py +355 -0
  162. sage/symbolic/function_factory.pyi +41 -0
  163. sage/symbolic/getitem_impl.pyi +24 -0
  164. sage/symbolic/integration/all.py +1 -0
  165. sage/symbolic/integration/external.py +271 -0
  166. sage/symbolic/integration/integral.py +1075 -0
  167. sage/symbolic/maxima_wrapper.py +162 -0
  168. sage/symbolic/operators.py +267 -0
  169. sage/symbolic/operators.pyi +61 -0
  170. sage/symbolic/pynac_constant_impl.pyi +13 -0
  171. sage/symbolic/pynac_function_impl.pyi +8 -0
  172. sage/symbolic/random_tests.py +461 -0
  173. sage/symbolic/relation.py +2062 -0
  174. sage/symbolic/ring.cpython-311-darwin.so +0 -0
  175. sage/symbolic/ring.pxd +5 -0
  176. sage/symbolic/ring.pyi +110 -0
  177. sage/symbolic/ring.pyx +1393 -0
  178. sage/symbolic/series_impl.pyi +10 -0
  179. sage/symbolic/subring.py +1025 -0
  180. sage/symbolic/symengine.py +19 -0
  181. sage/symbolic/tests.py +40 -0
  182. sage/symbolic/units.py +1468 -0
@@ -0,0 +1,1034 @@
1
+ # sage_setup: distribution = sagemath-symbolics
2
+ # sage.doctest: needs sage.plot
3
+ r"""
4
+ Mandelbrot and Julia sets (Cython helper)
5
+
6
+ This is the helper file providing functionality for mandel_julia.py.
7
+
8
+ AUTHORS:
9
+
10
+ - Ben Barros
11
+ """
12
+ # ****************************************************************************
13
+ # Copyright (C) 2017 BEN BARROS <bbarros@slu.edu>
14
+ #
15
+ # This program is free software: you can redistribute it and/or modify
16
+ # it under the terms of the GNU General Public License as published by
17
+ # the Free Software Foundation, either version 2 of the License, or
18
+ # (at your option) any later version.
19
+ # https://www.gnu.org/licenses/
20
+ # ****************************************************************************
21
+
22
+ from sage.plot.colors import Color
23
+ from sage.repl.image import Image
24
+ from copy import copy
25
+ from cysignals.signals cimport sig_check
26
+ from sage.rings.complex_mpfr import ComplexField
27
+ from sage.functions.log import exp
28
+ from sage.symbolic.relation import solve
29
+ from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
30
+ from sage.rings.cc import CC
31
+ from sage.rings.real_double import RDF
32
+ from sage.rings.complex_double import CDF
33
+ from sage.ext.fast_callable import fast_callable
34
+ from sage.calculus.expr import symbolic_expression
35
+ from sage.symbolic.ring import SR
36
+ from sage.calculus.var import var
37
+ from sage.rings.fraction_field import FractionField_generic
38
+ from sage.categories.function_fields import FunctionFields
39
+ from cypari2.handle_error import PariError
40
+ from math import sqrt
41
+
42
+
43
+ def _color_to_RGB(color):
44
+ """
45
+ Convert a color to an RGB triple with values in the interval [0,255].
46
+
47
+ EXAMPLES::
48
+
49
+ sage: from sage.dynamics.complex_dynamics.mandel_julia_helper import _color_to_RGB
50
+ sage: _color_to_RGB("aquamarine")
51
+ (127, 255, 212)
52
+ sage: _color_to_RGB(Color([0, 1/2, 1]))
53
+ (0, 127, 255)
54
+ sage: _color_to_RGB([0, 100, 200])
55
+ (0, 100, 200)
56
+ """
57
+ if not isinstance(color, (list, tuple)):
58
+ color = [int(255.0 * k) for k in Color(color)]
59
+ return tuple(color)
60
+
61
+
62
+ cpdef fast_mandelbrot_plot(double x_center, double y_center,
63
+ double image_width, long max_iteration,
64
+ long pixel_count,
65
+ long level_sep, long color_num, base_color):
66
+ r"""
67
+ Plot the Mandelbrot set in the complex plane for the map `Q_c(z) = z^2 + c`.
68
+
69
+ ALGORITHM:
70
+
71
+ Let each pixel in the image be a point `c \in \mathbb{C}` and define the
72
+ map `Q_c(z) = z^2 + c`. If `|Q_{c}^{k}(c)| > 2` for some `k \geq 0`, it
73
+ follows that `Q_{c}^{n}(c) \to \infty`. Let `N` be the maximum number of
74
+ iterations. Compute the first `N` points on the orbit of `0` under `Q_c`.
75
+ If for any `k < N`, `|Q_{c}^{k}(0)| > 2`, we stop the iteration and assign
76
+ a color to the point `c` based on how quickly `0` escaped to infinity under
77
+ iteration of `Q_c`. If `|Q_{c}^{i}(0)| \leq 2` for all `i \leq N`, we assume
78
+ `c` is in the Mandelbrot set and assign the point `c` the color black.
79
+
80
+ INPUT:
81
+
82
+ - ``x_center`` -- double; real part of the center point in the complex plane
83
+
84
+ - ``y_center`` -- double; imaginary part of the center point in the complex
85
+ plane
86
+
87
+ - ``image_width`` -- double; width of the image in the complex plane
88
+
89
+ - ``max_iteration`` -- long; maximum number of iterations the map `Q_c(z)`
90
+ considered
91
+
92
+ - ``pixel_count`` -- long; side length of image in number of pixels
93
+
94
+ - ``level_sep`` -- long; number of iterations between each color level
95
+
96
+ - ``color_num`` -- long; number of colors used to plot image
97
+
98
+ - ``base_color`` -- list; RGB color used to determine the coloring of set
99
+
100
+ OUTPUT: 24-bit RGB image of the Mandelbrot set in the complex plane
101
+
102
+ EXAMPLES:
103
+
104
+ Plot the Mandelbrot set with the center point `-1 + 0i`::
105
+
106
+ sage: from sage.dynamics.complex_dynamics.mandel_julia_helper import fast_mandelbrot_plot
107
+ sage: fast_mandelbrot_plot(-1, 0, 4, 500, 600, 1, 20, [40, 40, 40])
108
+ 600x600px 24-bit RGB image
109
+
110
+ We can focus on smaller parts of the set by adjusting image_width::
111
+
112
+ sage: from sage.dynamics.complex_dynamics.mandel_julia_helper import fast_mandelbrot_plot
113
+ sage: fast_mandelbrot_plot(-1.11, 0.2283, 1/128, 2000, 500, 1, 500, [40, 100, 100])
114
+ 500x500px 24-bit RGB image
115
+ """
116
+
117
+ cdef:
118
+ M, pixel, color_list
119
+ long i, j, col, row, level, iteration
120
+ double x_corner, y_corner, step_size, x_coor, y_coor, new_x, new_y
121
+
122
+ # Make sure image_width is positive
123
+ image_width = abs(image_width)
124
+
125
+ # Initialize an image to the color black and access the pixels
126
+ M = Image("RGB", (pixel_count, pixel_count), 'black')
127
+ pixel = M.pixels()
128
+
129
+ # Take the given base color and create a list of evenly spaced
130
+ # colors between the given base color and white. The number of
131
+ # colors in the list depends on the variable color_num.
132
+ base_color = _color_to_RGB(base_color)
133
+ color_list = []
134
+ for i in range(color_num):
135
+ sig_check()
136
+ color = [base_color[j] + i * (255 - base_color[j]) // color_num
137
+ for j in range(3)]
138
+ color_list.append(tuple(color))
139
+
140
+ # First, we determine the complex coordinates of the point in the top left
141
+ # corner of the image. Then, we loop through each pixel in the image and
142
+ # assign it complex coordinates relative to the image's top left corner.
143
+ x_corner = x_center - image_width/2
144
+ y_corner = y_center + image_width/2
145
+ step_size = image_width / pixel_count
146
+ for col in range(pixel_count):
147
+ x_coor = x_corner + col*step_size
148
+ for row in range(pixel_count):
149
+ sig_check()
150
+ y_coor = y_corner - row*step_size
151
+
152
+ # We compute the orbit of 0 under the map Q(z) = z^2 + c
153
+ # until we either reach the maximum number of iterations
154
+ # or find a point in the orbit with modulus greater than 2
155
+ new_x, new_y = 0.0, 0.0
156
+ iteration = 0
157
+ while (new_x**2 + new_y**2 <= 4.0 and iteration < max_iteration):
158
+ sig_check()
159
+ new_x, new_y = new_x**2 - new_y**2 + x_coor, \
160
+ 2*new_x*new_y + y_coor
161
+ iteration += 1
162
+
163
+ # If the point escapes to infinity, assign the point a color
164
+ # based on how fast it escapes. The more iterations it takes for
165
+ # a point to escape to infinity, the lighter its color will be.
166
+ # Otherwise, assume the point is in the Mandelbrot set and leave
167
+ # it black.
168
+ if iteration != max_iteration:
169
+ # Assign each point a level based on its number of iterations.
170
+ level = iteration // level_sep
171
+ # Assign the pixel a color based on it's level. If we run out
172
+ # of colors, assign it the last color in the list.
173
+ if level < color_num:
174
+ pixel[col, row] = color_list[level]
175
+ else:
176
+ pixel[col, row] = color_list[-1]
177
+ return M
178
+
179
+
180
+ cpdef fast_external_ray(double theta, long D=30, long S=10, long R=100,
181
+ long pixel_count=500, double image_width=4,
182
+ long prec=300):
183
+ r"""
184
+ Return a list of points that approximate the external ray for a given angle.
185
+
186
+ INPUT:
187
+
188
+ - ``theta`` -- double; angle between 0 and 1 inclusive
189
+
190
+ - ``D`` -- long (default: ``25``); depth of the approximation.
191
+ As ``D`` increases, the external ray gets closer to the boundary of the
192
+ Mandelbrot set.
193
+
194
+ - ``S`` -- long (default: ``10``); sharpness of the approximation.
195
+ Adjusts the number of points used to approximate the external ray (number
196
+ of points is equal to ``S*D``).
197
+
198
+ - ``R`` -- long (default: ``100``); radial parameter. If ``R`` is
199
+ sufficiently large, the external ray reaches enough close to infinity.
200
+
201
+ - ``pixel_count`` -- long (default: ``500``); side length of image
202
+ in number of pixels
203
+
204
+ - ``image_width`` -- double (default: ``4``); width of the image
205
+ in the complex plane
206
+
207
+ - ``prec`` -- long (default: ``300``); specifies the bits of
208
+ precision used by the Complex Field when using Newton's method to compute
209
+ points on the external ray
210
+
211
+ OUTPUT: list of tuples of Real Interval Field Elements
212
+
213
+ EXAMPLES::
214
+
215
+ sage: from sage.dynamics.complex_dynamics.mandel_julia_helper import fast_external_ray
216
+ sage: fast_external_ray(0,S=1,D=1)
217
+ [(100.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,
218
+ 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000),
219
+ (9.51254777713729174697578576623132297117784691109499464854806785133621315075854778426714908,
220
+ 0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000)]
221
+
222
+
223
+ ::
224
+
225
+ sage: from sage.dynamics.complex_dynamics.mandel_julia_helper import fast_external_ray
226
+ sage: fast_external_ray(1/3,S=1,D=1)
227
+ [(-49.9999999999999786837179271969944238662719726562500000000000000000000000000000000000000000,
228
+ 86.6025403784438765342201804742217063903808593750000000000000000000000000000000000000000000),
229
+ (-5.50628047023173006234970878097113901879832542655926629309001652388544528575532346900138516,
230
+ 8.64947510053972513843999918917106032664030380426885745306040284140385975750462108180377187)]
231
+
232
+ ::
233
+
234
+ sage: from sage.dynamics.complex_dynamics.mandel_julia_helper import fast_external_ray
235
+ sage: fast_external_ray(0.75234,S=1,D=1)
236
+ [(1.47021239172637052661229972727596759796142578125000000000000000000000000000000000000000000,
237
+ -99.9891917935294287644865107722580432891845703125000000000000000000000000000000000000000000),
238
+ (-0.352790406744857508500937144524776555433184352559852962308757189778284058275081335121601384,
239
+ -9.98646630765023514178761177926164047797465369576787921409326037870837930920646860774032363)]
240
+ """
241
+
242
+ cdef:
243
+ CF = ComplexField(prec)
244
+ PI = CF.pi()
245
+ I = CF.gen()
246
+ r_m, t_m, temp_c, C_k, D_k, old_c, x, y, dist
247
+ int k, j, t
248
+ double difference, m
249
+ double error = pixel_count * 0.0001
250
+
251
+ double pixel_width = image_width / pixel_count
252
+
253
+ # initialize list with c_0
254
+ c_list = [CF(R*exp(2*PI*I*theta))]
255
+
256
+ # Loop through each subinterval and approximate point on external ray.
257
+ for k in range(1, D+1):
258
+ for j in range(1, S+1):
259
+ m = (k-1)*S + j
260
+ r_m = CF(R**(2**(-m/S)))
261
+ t_m = CF(r_m**(2**k) * exp(2*PI*I*theta * 2**k))
262
+ temp_c = c_list[-1]
263
+ difference = error
264
+
265
+ # Repeat Newton's method until points are close together.
266
+ while error <= difference:
267
+ sig_check()
268
+ old_c = temp_c
269
+ # Recursive formula for iterates of q(z) = z^2 + c
270
+ C_k, D_k = CF(old_c), CF(1)
271
+ for t in range(k):
272
+ C_k, D_k = C_k**2 + old_c, CF(2)*D_k*C_k + CF(1)
273
+ temp_c = old_c - (C_k - t_m) / D_k # Newton map
274
+ difference = abs(old_c) - abs(temp_c)
275
+
276
+ dist = (2*C_k.abs()*(C_k.abs()).log()) / D_k.abs()
277
+ if dist < pixel_width:
278
+ break
279
+ c_list.append(CF(temp_c))
280
+ if dist < pixel_width:
281
+ break
282
+
283
+ # Convert Complex Field elements into tuples.
284
+ for k in range(len(c_list)):
285
+ x, y = c_list[k].real(), c_list[k].imag()
286
+ c_list[k] = (x, y)
287
+
288
+ return c_list
289
+
290
+ cpdef convert_to_pixels(point_list, double x_0, double y_0, double width,
291
+ long number_of_pixels):
292
+ r"""
293
+ Convert cartesian coordinates to pixels within a specified window.
294
+
295
+ INPUT:
296
+
297
+ - ``point_list`` -- list of tuples; points in cartesian coordinates
298
+
299
+ - ``x_0`` -- double; x-coordinate of the center of the image
300
+
301
+ - ``y_0`` -- double; y-coordinate of the center of the image
302
+
303
+ - ``width`` -- double; width of visible window in cartesian coordinates
304
+
305
+ - ``number_of_pixels`` -- long; width of image in pixels
306
+
307
+ OUTPUT: list of tuples of integers representing pixels
308
+
309
+ EXAMPLES::
310
+
311
+ sage: from sage.dynamics.complex_dynamics.mandel_julia_helper import convert_to_pixels
312
+ sage: convert_to_pixels([(-1,3),(0,-4),(5,0)], 0, 0, 12, 100)
313
+ [(42, 25), (50, 83), (92, 50)]
314
+ """
315
+ cdef:
316
+ k, pixel_list, x_corner, y_corner, step_size
317
+ long x_pixel, y_pixel
318
+ pixel_list = []
319
+
320
+ # Compute top left corner of window and step size
321
+ x_corner = x_0 - width/2
322
+ y_corner = y_0 + width/2
323
+ step_size = number_of_pixels / width
324
+
325
+ # Convert each point in list to pixel coordinates
326
+ for k in point_list:
327
+ sig_check()
328
+ x_pixel = round((k[0] - x_corner) * step_size)
329
+ y_pixel = round((y_corner - k[1]) * step_size)
330
+ pixel_list.append((x_pixel, y_pixel))
331
+ return pixel_list
332
+
333
+ cpdef get_line(start, end):
334
+ r"""
335
+ Produce a list of pixel coordinates approximating a line from a starting
336
+ point to an ending point using the Bresenham's Line Algorithm.
337
+
338
+ REFERENCE:
339
+
340
+ [Br2016]_
341
+
342
+ INPUT:
343
+
344
+ - ``start`` -- tuple; starting point of line
345
+
346
+ - ``end`` -- tuple; ending point of line
347
+
348
+ OUTPUT: list of tuples of integers approximating the line between two pixels
349
+
350
+ EXAMPLES::
351
+
352
+ sage: from sage.dynamics.complex_dynamics.mandel_julia_helper import get_line
353
+ sage: get_line((0, 0), (3, 4))
354
+ [(0, 0), (1, 1), (1, 2), (2, 3), (3, 4)]
355
+
356
+ ::
357
+
358
+ sage: from sage.dynamics.complex_dynamics.mandel_julia_helper import get_line
359
+ sage: get_line((3, 4), (0, 0))
360
+ [(3, 4), (2, 3), (1, 2), (1, 1), (0, 0)]
361
+ """
362
+ # Setup initial conditions
363
+ cdef:
364
+ long x1, x2, y1, y2, dx, dy, error, ystep, y
365
+ is_steep, swapped, points
366
+ x1, y1 = start
367
+ x2, y2 = end
368
+ dx, dy = x2 - x1, y2 - y1
369
+
370
+ # Determine how steep the line is
371
+ is_steep = abs(dy) > abs(dx)
372
+
373
+ # Rotate line
374
+ if is_steep:
375
+ x1, y1 = y1, x1
376
+ x2, y2 = y2, x2
377
+
378
+ # Swap start and end points if necessary and store swap state
379
+ swapped = False
380
+ if x1 > x2:
381
+ x1, x2 = x2, x1
382
+ y1, y2 = y2, y1
383
+ swapped = True
384
+
385
+ # Recalculate differentials
386
+ dx, dy = x2 - x1, y2 - y1
387
+
388
+ # Calculate error
389
+ error = int(dx / 2.0)
390
+ ystep = 1 if y1 < y2 else -1
391
+
392
+ # Iterate over bounding box generating points between start and end
393
+ y = y1
394
+ points = []
395
+ for x in range(x1, x2 + 1):
396
+ sig_check()
397
+ coord = (y, x) if is_steep else (x, y)
398
+ points.append(coord)
399
+ error -= abs(dy)
400
+ if error < 0:
401
+ y += ystep
402
+ error += dx
403
+
404
+ # Reverse the list if the coordinates were swapped
405
+ if swapped:
406
+ points.reverse()
407
+ return points
408
+
409
+ # Commented out temporarily for safekeeping, but probably should be deleted
410
+ # def fast_julia_plot(double c_real, double c_imag,
411
+ # double x_center, double y_center, double image_width,
412
+ # long max_iteration, long pixel_count, long level_sep,
413
+ # long color_num, base_color):
414
+
415
+ cpdef fast_julia_plot(double c_real, double c_imag,
416
+ double x_center=0, double y_center=0,
417
+ double image_width=4,
418
+ long max_iteration=500, long pixel_count=500,
419
+ long level_sep=2,
420
+ long color_num=40, base_color=[50, 50, 50]):
421
+ r"""
422
+ Plot the Julia set for a given `c` value in the complex plane for the map `Q_c(z) = z^2 + c`.
423
+
424
+ INPUT:
425
+
426
+ - ``c_real`` -- double; Real part of `c` value that determines Julia set
427
+
428
+ - ``c_imag`` -- double; Imaginary part of `c` value that determines Julia
429
+ set
430
+
431
+ - ``x_center`` -- double (default: ``0.0``); real part of center
432
+ point
433
+
434
+ - ``y_center`` -- double (default: ``0.0``); imaginary part of
435
+ center point
436
+
437
+ - ``image_width`` -- double (default: ``4.0``); width of image
438
+ in the complex plane
439
+
440
+ - ``max_iteration`` -- long (default: ``500``); maximum number of
441
+ iterations the map ``Q_c(z)``
442
+
443
+ - ``pixel_count`` -- long (default: ``500``); side length of
444
+ image in number of pixels
445
+
446
+ - ``level_sep`` -- long (default: ``2``); number of iterations
447
+ between each color level
448
+
449
+ - ``color_num`` -- long (default: ``40``); number of colors used
450
+ to plot image
451
+
452
+ - ``base_color`` -- RGB color (default: ``[50, 50, 50]``); color
453
+ used to determine the coloring of set
454
+
455
+ OUTPUT: 24-bit RGB image of the Julia set in the complex plane
456
+
457
+ EXAMPLES:
458
+
459
+ Plot the Julia set for `c=-1+0i`::
460
+
461
+ sage: from sage.dynamics.complex_dynamics.mandel_julia_helper import fast_julia_plot
462
+ sage: fast_julia_plot(-1, 0, 0, 0, 4, 500, 200, 1, 20, [40, 40, 40])
463
+ 200x200px 24-bit RGB image
464
+ """
465
+
466
+ cdef:
467
+ color_list
468
+ long i, j, col, row, level, iteration
469
+ double x_corner, y_corner, step_size, x_coor, y_coor, new_x, new_y, escape_radius_squared
470
+
471
+ # Make sure image_width is positive
472
+ image_width = abs(image_width)
473
+
474
+ # Calculate the escape radius. (Actually, we store the square of this radius.) If any
475
+ # iterate is farther from the origin than this distance, then the orbit goes to infinity.
476
+ escape_radius_squared = ((1.0 + sqrt(1.0 + 4.0*sqrt(c_real**2 + c_imag**2))))**2/4.0
477
+
478
+ # Initialize an image to the color black and access the pixels
479
+ J = Image("RGB", (pixel_count, pixel_count), 'black')
480
+ Jp = J.pixels()
481
+
482
+ # Take the given base color and create a list of evenly spaced
483
+ # colors between the given base color and white. The number of
484
+ # colors in the list depends on the variable color_num.
485
+ base_color = _color_to_RGB(base_color)
486
+ color_list = []
487
+ for i in range(color_num):
488
+ sig_check()
489
+ color = [base_color[j] + i * (255 - base_color[j]) // color_num
490
+ for j in range(3)]
491
+ color_list.append(tuple(color))
492
+
493
+ # First, we determine the complex coordinates of the point in the top left
494
+ # corner of the image. Then, we loop through each pixel in the image and
495
+ # assign it complex coordinates relative to the image's top left corner.
496
+ x_corner = x_center - image_width/2
497
+ y_corner = y_center + image_width/2
498
+ step_size = image_width / pixel_count
499
+ for col in range(pixel_count):
500
+ x_coor = x_corner + col*step_size
501
+ for row in range(pixel_count):
502
+ sig_check()
503
+ y_coor = y_corner - row*step_size
504
+
505
+ # We compute the orbit of each pixel under the map Q(z) = z^2 + c
506
+ # until we either reach the maximum number of iterations
507
+ # or find a point in the orbit with modulus greater than
508
+ # the escape radius.
509
+ new_x, new_y = x_coor, y_coor
510
+ iteration = 0
511
+ while (new_x**2 + new_y**2 <= escape_radius_squared and iteration < max_iteration):
512
+ sig_check()
513
+ new_x, new_y = new_x**2 - new_y**2 + c_real, \
514
+ 2*new_x*new_y + c_imag
515
+ iteration += 1
516
+
517
+ # If the point escapes to infinity, assign the point a color
518
+ # based on how fast it escapes. The more iterations it takes for
519
+ # a point to escape to infinity, the lighter its color will be.
520
+ # Otherwise, assume the point is in the Julia set and leave
521
+ # it black.
522
+ if iteration != max_iteration:
523
+ # Assign each point a level based on its number of iterations.
524
+ level = iteration // level_sep
525
+ # Assign the pixel a color based on it's level. If we run out
526
+ # of colors, assign it the last color in the list.
527
+ if level < color_num:
528
+ Jp[col, row] = color_list[level]
529
+ else:
530
+ Jp[col, row] = color_list[-1]
531
+
532
+ return J
533
+
534
+ cpdef julia_helper(double c_real, double c_imag, double x_center=0,
535
+ double y_center=0, double image_width=4,
536
+ long max_iteration=500,
537
+ long pixel_count=500, long level_sep=2, long color_num=40,
538
+ base_color=[50, 50, 50], point_color=[255, 0, 0]):
539
+ r"""
540
+ Helper function that returns the image of a Julia set for a given
541
+ `c` value side by side with the Mandelbrot set with a point denoting
542
+ the `c` value.
543
+
544
+ INPUT:
545
+
546
+ - ``c_real`` -- double; Real part of `c` value that determines Julia set
547
+
548
+ - ``c_imag`` -- double; Imaginary part of `c` value that determines Julia
549
+ set
550
+
551
+ - ``x_center`` -- double (default: ``0.0``); Real part of center
552
+ point
553
+
554
+ - ``y_center`` -- double (default: ``0.0``); Imaginary part of
555
+ center point
556
+
557
+ - ``image_width`` -- double (default: ``4.0``); width of image in
558
+ the complex plane
559
+
560
+ - ``max_iteration`` -- long (default: ``500``); maximum number of
561
+ iterations the map ``Q_c(z)``
562
+
563
+ - ``pixel_count`` -- long (default: ``500``); side length of
564
+ image in number of pixels
565
+
566
+ - ``level_sep`` -- long (default: ``2``); number of iterations
567
+ between each color level
568
+
569
+ - ``color_num`` -- long (default: ``40``); number of colors used
570
+ to plot image
571
+
572
+ - ``base_color`` -- RGB color (default: ``[50, 50, 50]``); color
573
+ used to determine the coloring of set
574
+
575
+ - ``point_color`` -- RGB color (default: ``[255, 0, 0]``); color
576
+ of the point `c` in the Mandelbrot set
577
+
578
+ OUTPUT: 24-bit RGB image of the Julia and Mandelbrot sets in the complex plane
579
+
580
+ EXAMPLES:
581
+
582
+ Plot the Julia set for `c=-1+0i`::
583
+
584
+ sage: from sage.dynamics.complex_dynamics.mandel_julia_helper import julia_helper
585
+ sage: julia_helper(-1, 0, 0, 0, 4, 500, 200, 1, 20, [40, 40, 40], [255, 0, 0])
586
+ 401x200px 24-bit RGB image
587
+ """
588
+ cdef int i, j
589
+
590
+ # Initialize the Julia set
591
+ J = fast_julia_plot(c_real, c_imag, x_center, y_center, image_width,
592
+ max_iteration, pixel_count, level_sep,
593
+ color_num, base_color)
594
+ Jp = J.pixels()
595
+
596
+ # Initialize the image with Julia set on left side
597
+ # Add white border between images
598
+ G = Image("RGB", (2*pixel_count+1, pixel_count), 'white')
599
+ Gp = G.pixels()
600
+ for i in range(pixel_count):
601
+ for j in range(pixel_count):
602
+ Gp[i, j] = Jp[i, j]
603
+
604
+ # Plot the Mandelbrot set on the right side
605
+ M = fast_mandelbrot_plot(-1, 0, 4, 500, pixel_count, 1, 30, base_color)
606
+ Mp = M.pixels()
607
+ for i in range(pixel_count+1, 2*pixel_count):
608
+ for j in range(pixel_count):
609
+ Gp[i, j] = Mp[int(i-pixel_count), j]
610
+
611
+ point_color = _color_to_RGB(point_color)
612
+
613
+ # Add a cross representing c-value to the Mandelbrot set.
614
+ CP = convert_to_pixels([(c_real, c_imag)], -1, 0, 4, pixel_count)
615
+ for i in range(-3, 4):
616
+ # Loop through x and y coordinates and check if they are in image
617
+ if min(CP[0][0]+i, CP[0][1]) >= 0 and \
618
+ max(CP[0][0]+i, CP[0][1]) < pixel_count:
619
+ Gp[CP[0][0]+i+pixel_count+1, CP[0][1]] = tuple(point_color)
620
+ if min(CP[0][0], CP[0][1]+i) >= 0 and \
621
+ max(CP[0][0], CP[0][1]+i) < pixel_count:
622
+ Gp[CP[0][0]+pixel_count+1, CP[0][1]+i] = tuple(point_color)
623
+
624
+ return G
625
+
626
+ cpdef polynomial_mandelbrot(f, parameter=None, double x_center=0,
627
+ double y_center=0, image_width=4,
628
+ int max_iteration=50, int pixel_count=500,
629
+ int level_sep=1, int color_num=30,
630
+ base_color=Color('red')):
631
+ r"""
632
+ Plot the Mandelbrot set in the complex plane for a family of polynomial maps.
633
+
634
+ INPUT:
635
+
636
+ - ``f`` -- a one parameter family of polynomial maps defined over the
637
+ multivariate polynomial ring in z, c over the Complex field
638
+
639
+ - ``parameter`` -- designates which variable is used as the parameter
640
+ If no parameter is provided, ``c`` will be used as the parameter
641
+
642
+ - ``x_center`` -- double, real part of the center point in the complex plane
643
+
644
+ - ``y_center`` -- double, imaginary part of the center point in the complex
645
+ plane
646
+
647
+ - ``image_width`` -- double, width of the image in the complex plane
648
+
649
+ - ``max_iteration`` -- long, maximum number of iterations the map `f(z)`
650
+ considered
651
+
652
+ - ``pixel_count`` -- long, side length of image in number of pixels
653
+
654
+ - ``level_sep`` -- long, number of iterations between each color level
655
+
656
+ - ``color_num`` -- long, number of colors used to plot image
657
+
658
+ - ``base_color`` -- list; RGB color used to determine the coloring of set
659
+
660
+ OUTPUT: 24-bit RGB image of a Mandelbrot set in the complex plane
661
+
662
+ EXAMPLES::
663
+
664
+ sage: from sage.dynamics.complex_dynamics.mandel_julia_helper import polynomial_mandelbrot
665
+ sage: R.<z,c> = CC[]
666
+ sage: f = z^5 + c
667
+ sage: polynomial_mandelbrot(f, pixel_count=100)
668
+ 100x100px 24-bit RGB image
669
+
670
+ ::
671
+
672
+ sage: from sage.dynamics.complex_dynamics.mandel_julia_helper import polynomial_mandelbrot
673
+ sage: B.<c> = CC[]
674
+ sage: R.<z> = B[]
675
+ sage: f = z^4 - z + c
676
+ sage: polynomial_mandelbrot(f, pixel_count=100)
677
+ 100x100px 24-bit RGB image
678
+
679
+ ::
680
+
681
+ sage: from sage.dynamics.complex_dynamics.mandel_julia_helper import polynomial_mandelbrot
682
+ sage: B.<c> = CC[]
683
+ sage: R.<z> = B[]
684
+ sage: f = z^2*(z-c) + c
685
+ sage: polynomial_mandelbrot(f, pixel_count=100)
686
+ 100x100px 24-bit RGB image
687
+ """
688
+
689
+ cdef:
690
+ z, c, x, y, w, cr, ci, J, M, S, S2, R, P, phi, t, im, re, a_n, df
691
+ pt, c_pts, cp_real, cp_imag, pixel, color_list, critical_pts
692
+ f_real, f_imag, f_temp, escape_time, cf_list, cf
693
+ int i, j, d, k, col, row, iteration
694
+ double C, L, Rad, x_corner, y_corner, x_coor, y_coor, \
695
+ step_size, new_x, new_y
696
+ I = CDF.gen()
697
+ constant_c = True
698
+
699
+ if parameter is None:
700
+ c = var('c')
701
+ parameter = c
702
+
703
+ P = f.parent()
704
+
705
+ if P.base_ring() is CC:
706
+ if isinstance(P, FractionField_generic):
707
+ raise NotImplementedError("coefficients must be polynomials in the parameter")
708
+ gen_list = list(P.gens())
709
+ parameter = gen_list.pop(gen_list.index(parameter))
710
+ variable = gen_list.pop()
711
+
712
+ elif P.base_ring().base_ring() is CC:
713
+ if isinstance(P.base_ring(), FractionField_generic):
714
+ raise NotImplementedError("coefficients must be polynomials in the parameter")
715
+ phi = P.flattening_morphism()
716
+ f = phi(f)
717
+ gen_list = list(f.parent().gens())
718
+ parameter = gen_list.pop(gen_list.index(parameter))
719
+ variable = gen_list.pop()
720
+
721
+ elif P.base_ring() in FunctionFields():
722
+ raise NotImplementedError("coefficients must be polynomials in the parameter")
723
+
724
+ else:
725
+ raise ValueError("base ring must be a complex field")
726
+
727
+ # Make sure image_width is positive
728
+ image_width = abs(image_width)
729
+
730
+ # Initialize an image to the color black and access the pixels
731
+ M = Image("RGB", (pixel_count, pixel_count), 'black')
732
+ pixel = M.pixels()
733
+
734
+ # Take the given base color and create a list of evenly spaced
735
+ # colors between the given base color and white. The number of
736
+ # colors in the list depends on the variable color_num.
737
+ if isinstance(base_color, Color):
738
+ # Convert Color to RGB list
739
+ base_color = [int(k*255) for k in base_color]
740
+ color_list = []
741
+ for i in range(color_num):
742
+ sig_check()
743
+ color_list.append(copy(base_color))
744
+ for j in range(3):
745
+ color_list[i][j] += i * (255 - color_list[i][j]) // color_num
746
+ color_list[i] = tuple(color_list[i])
747
+
748
+ # Split function into real and imaginary parts
749
+ R = PolynomialRing(CC, [variable, parameter])
750
+ if len(R.gens()) > 2:
751
+ raise NotImplementedError("base ring must have only 2 variables")
752
+ z, c = R.gens()
753
+ f = R(str(f))
754
+ S = PolynomialRing(f.base_ring(), 'x,y,J,cr,ci')
755
+ x, y, J, cr, ci = S.gens()
756
+ S2 = S.quotient_ring(J**2+1)
757
+ phi = R.hom([x+y*J, cr+ci*J], S2)
758
+ t = phi(f).lift()
759
+ im = t.coefficient(J)
760
+ re = t - im*J
761
+
762
+ f_real = fast_callable(re, vars=[x, y, cr, ci, J], domain=RDF)
763
+ f_imag = fast_callable(im, vars=[x, y, cr, ci, J], domain=RDF)
764
+
765
+ # Compute critical points
766
+ try:
767
+ df = f.derivative(z).univariate_polynomial()
768
+ critical_pts = df.roots(multiplicities=False)
769
+ constant_c = True
770
+ except (PariError, TypeError):
771
+ constant_c = False
772
+
773
+ # If c is in the constant term of the polynomial, then the critical points
774
+ # will be independent of c.
775
+ if constant_c:
776
+ c_pts = [[pt.real(), pt.imag()] for pt in critical_pts]
777
+
778
+ # Calculate escape condition
779
+ d = f.degree(z)
780
+ cf_list = f.coefficients()
781
+ a_n = cf_list.pop(0).abs()
782
+ C = 0
783
+ for cf in cf_list:
784
+ C += cf.abs()
785
+ L = 1.00000000000001
786
+ if d >= 2:
787
+ Rad = max(1, 2*C / a_n, (2*L / a_n**(1/(d-1))))
788
+ else:
789
+ Rad = max(1, 2*C / a_n)
790
+
791
+ # First, we determine the complex coordinates of the point in the top
792
+ # left corner of the image. Then, we loop through each pixel in the
793
+ # image and assign it complex coordinates relative to the image's top
794
+ # left corner.
795
+ x_corner = x_center - image_width/2
796
+ y_corner = y_center + image_width/2
797
+ step_size = image_width*1.0 / pixel_count
798
+ for col in range(pixel_count):
799
+ x_coor = x_corner + col*step_size
800
+ for row in range(pixel_count):
801
+ sig_check()
802
+ y_coor = y_corner - row*step_size
803
+
804
+ # Initialize escape_time to be maximum number of iterations.
805
+ escape_time = max_iteration
806
+
807
+ # Loop though each critical point. If all of the critical
808
+ # points are bounded for a particular c value, then c is in
809
+ # the mandelbrot set.
810
+ for pt in c_pts:
811
+ cp_real = pt[0]
812
+ cp_imag = pt[1]
813
+
814
+ # Iterate the map f using the critical point as the initial
815
+ # value.
816
+ new_x, new_y = cp_real, cp_imag
817
+ iteration = 0
818
+ while new_x**2 + new_y**2 <= Rad**2 and iteration < escape_time:
819
+ sig_check()
820
+ new_x, new_y = f_real(new_x, new_y, x_coor, y_coor, 1), \
821
+ f_imag(new_x, new_y, x_coor, y_coor, 1)
822
+ iteration += 1
823
+
824
+ # For each point, we take the minimum number of iterations
825
+ # over all the critical points and use this minimum to
826
+ # color the point.
827
+ if iteration < escape_time:
828
+ escape_time = iteration
829
+
830
+ # If the point escapes to infinity, assign the point a color
831
+ # based on how fast it escapes. The more iterations it takes for
832
+ # a point to escape to infinity, the lighter its color will be.
833
+ # Otherwise, assume the point is in the Mandelbrot set and leave
834
+ # it black.
835
+ if iteration != max_iteration:
836
+ # Assign each point a level based on its number of iterations.
837
+ level = iteration // level_sep
838
+ # Assign the pixel a color based on it's level. If we run out
839
+ # of colors, assign it the last color in the list.
840
+ if level < color_num:
841
+ pixel[col, row] = color_list[level]
842
+ else:
843
+ pixel[col, row] = color_list[-1]
844
+
845
+ # If the critical points of f depend on c, we must compute the different
846
+ # critical points for each c.
847
+ else:
848
+ # Solve for critical points symbollically.
849
+ with SR.temp_var() as w:
850
+ df = f.derivative(z).polynomial(z).subs({z: w})
851
+ critical_pts = solve(symbolic_expression(df) == 0, w)
852
+ c_pts = []
853
+ for pt in critical_pts:
854
+ c_pts.append(fast_callable(pt.rhs(), vars=[c], domain=CDF))
855
+
856
+ # Calculate degree of f
857
+ d = f.degree(z)
858
+
859
+ # First, we determine the complex coordinates of the point in the top
860
+ # left corner of the image. Then, we loop through each pixel in the
861
+ # image and assign it complex coordinates relative to the image's top
862
+ # left corner.
863
+ x_corner = x_center - image_width/2
864
+ y_corner = y_center + image_width/2
865
+ step_size = image_width*1.0 / pixel_count
866
+ for col in range(pixel_count):
867
+ x_coor = x_corner + col*step_size
868
+ for row in range(pixel_count):
869
+
870
+ sig_check()
871
+ y_coor = y_corner - row*step_size
872
+
873
+ # Initialize escape time to be maximum number of iterations
874
+ escape_time = max_iteration
875
+
876
+ # Calculate escape condition for each c value
877
+ f_temp = f.subs({c: x_coor+y_coor*I})
878
+ cf_list = f_temp.coefficients()
879
+ a_n = cf_list.pop(0).abs()
880
+ C = 0
881
+ for cf in cf_list:
882
+ C += cf.abs()
883
+ L = 1.00000000000001
884
+ if d >= 2:
885
+ Rad = max(1, 2*C / a_n, (2*L / a_n**(1/(d-1))))
886
+ else:
887
+ Rad = max(1, 2*C / a_n)
888
+
889
+ for f_cp in c_pts:
890
+
891
+ # Compute real and imaginary critical point
892
+ cp_real = f_cp(x_coor + y_coor*I).real()
893
+ cp_imag = f_cp(x_coor + y_coor*I).imag()
894
+
895
+ # Iterate the map f using the critical point as the initial
896
+ # value.
897
+ new_x, new_y = cp_real, cp_imag
898
+ iteration = 0
899
+ while new_x**2 + new_y**2 <= Rad**2 and iteration < escape_time:
900
+ sig_check()
901
+ new_x, new_y = f_real(new_x, new_y, x_coor, y_coor, 1), \
902
+ f_imag(new_x, new_y, x_coor, y_coor, 1)
903
+ iteration += 1
904
+
905
+ # For each point, we take the minimum number of iterations
906
+ # over all the critical points and use this minimum to
907
+ # color the point.
908
+ if iteration < escape_time:
909
+ escape_time = iteration
910
+
911
+ # If the point escapes to infinity, assign the point a color
912
+ # based on how fast it escapes. The more iterations it takes for
913
+ # a point to escape to infinity, the lighter its color will be.
914
+ # Otherwise, assume the point is in the Mandelbrot set and leave
915
+ # it black.
916
+ if iteration != max_iteration:
917
+ # Assign each point a level based on its number of iterations.
918
+ level = iteration // level_sep
919
+ # Assign the pixel a color based on it's level. If we run out
920
+ # of colors, assign it the last color in the list.
921
+ if level < color_num:
922
+ pixel[col, row] = color_list[level]
923
+ else:
924
+ pixel[col, row] = color_list[-1]
925
+ return M
926
+
927
+ cpdef general_julia(f, double x_center=0, double y_center=0, image_width=4,
928
+ int max_iteration=50, int pixel_count=500,
929
+ int level_sep=1, int color_num=30,
930
+ base_color=[50, 50, 50]):
931
+ r"""
932
+ Plot Julia sets for general polynomials.
933
+
934
+ EXAMPLES::
935
+
936
+ sage: from sage.dynamics.complex_dynamics.mandel_julia_helper import general_julia
937
+ sage: from sage.plot.colors import Color
938
+ sage: R.<z> = CC[]
939
+ sage: f = z^3 - z + 1
940
+ sage: general_julia(f)
941
+ 500x500px 24-bit RGB image
942
+
943
+ ::
944
+
945
+ sage: from sage.dynamics.complex_dynamics.mandel_julia_helper import general_julia
946
+ sage: from sage.plot.colors import Color
947
+ sage: R.<z> = CC[]
948
+ sage: f = z^5 - 1
949
+ sage: general_julia(f)
950
+ 500x500px 24-bit RGB image
951
+ """
952
+
953
+ cdef:
954
+ M, pixel, color_list, z, a_n
955
+ int i, j, d, k, col, row, iteration
956
+ double C, L, Rad, x_corner, y_corner, x_coor, y_coor, step_size
957
+ I = CDF.gen()
958
+
959
+ # Make sure image_width is positive
960
+ image_width = abs(image_width)
961
+
962
+ # Initialize an image to the color black and access the pixels
963
+ M = Image("RGB", (pixel_count, pixel_count), 'black')
964
+ pixel = M.pixels()
965
+
966
+ # Take the given base color and create a list of evenly spaced
967
+ # colors between the given base color and white. The number of
968
+ # colors in the list depends on the variable color_num.
969
+ if isinstance(base_color, Color):
970
+ # Convert Color to RGB list
971
+ base_color = [int(k*255) for k in base_color]
972
+ color_list = []
973
+ for i in range(color_num):
974
+ sig_check()
975
+ color_list.append(copy(base_color))
976
+ for j in range(3):
977
+ color_list[i][j] += i * (255 - color_list[i][j]) // color_num
978
+ color_list[i] = tuple(color_list[i])
979
+
980
+ z = f.variables()[0]
981
+ f_fast = fast_callable(f, vars=[z], domain=CDF)
982
+
983
+ # Calculate escape condition for each c value
984
+ d = f.degree(z)
985
+ cf_list = f.coefficients(sparse=False)
986
+ a_n = cf_list.pop(-1).abs()
987
+ C = 0
988
+ for cf in cf_list:
989
+ C += cf.abs()
990
+ L = 1.00000000000001
991
+ if d >= 2:
992
+ Rad = max(1, 2*C / a_n, (2*L / a_n**(1/(d-1))))
993
+ else:
994
+ Rad = max(1, 2*C / a_n)
995
+
996
+ # First, we determine the complex coordinates of the point in the top left
997
+ # corner of the image. Then, we loop through each pixel in the image and
998
+ # assign it complex coordinates relative to the image's top left corner.
999
+ x_corner = x_center - image_width/2
1000
+ y_corner = y_center + image_width/2
1001
+ step_size = image_width*1.0 / pixel_count
1002
+ for col in range(pixel_count):
1003
+ x_coor = x_corner + col*step_size
1004
+ for row in range(pixel_count):
1005
+ sig_check()
1006
+ y_coor = y_corner - row*step_size
1007
+
1008
+ # We compute the orbit of c under the map f
1009
+ # until we either reach the maximum number of iterations
1010
+ # or find a point in the orbit with modulus greater than
1011
+ # some the escape condition (Rad)
1012
+
1013
+ new_z = x_coor + y_coor*I
1014
+ iteration = 0
1015
+ while new_z.abs() <= Rad**2 and iteration < max_iteration:
1016
+ sig_check()
1017
+ new_z = f_fast(new_z)
1018
+ iteration += 1
1019
+
1020
+ # If the point escapes to infinity, assign the point a color
1021
+ # based on how fast it escapes. The more iterations it takes for
1022
+ # a point to escape to infinity, the lighter its color will be.
1023
+ # Otherwise, assume the point is in the Mandelbrot set and leave
1024
+ # it black.
1025
+ if iteration != max_iteration:
1026
+ # Assign each point a level based on its number of iterations.
1027
+ level = iteration // level_sep
1028
+ # Assign the pixel a color based on it's level. If we run out
1029
+ # of colors, assign it the last color in the list.
1030
+ if level < color_num:
1031
+ pixel[col, row] = color_list[level]
1032
+ else:
1033
+ pixel[col, row] = color_list[-1]
1034
+ return M