passagemath-symbolics 10.6.43__cp314-cp314t-musllinux_1_2_x86_64.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.

Potentially problematic release.


This version of passagemath-symbolics might be problematic. Click here for more details.

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