Mandelbrot set: Difference between revisions

m
→‎Normal Map Effect, Mercator Projection and Deep Zoom Images: Used math tags and shortened explanation for rebasing.
m (→‎Normal Map Effect, Mercator Projection and Deep Zoom Images: Used math tags and shortened explanation for rebasing.)
Line 10,931:
plt.savefig("Mandelbrot_normal_map_2.png", dpi=200)</syntaxhighlight>
 
A small change in the code above creates Mercator maps of the Mandelbrot set (see David Madore: [http://www.madore.org/~david/math/mandelbrot.html ''Mandelbrot set images and videos''] and Anders Sandberg: [https://www.flickr.com/photos/arenamontanus/sets/72157615740829949 ''Mercator Mandelbrot Maps'']). The maximum magnification is <math>e ^ {2 \pi \cdot h / d} = e ^ {2 \pi \cdot 5.5} = 535.5 ^ {5.5} = 10 ^ {15}</math>, which is also the maximum for 64-bit arithmetic. Note that Anders Sandberg uses a different scaling. He uses <math>10 ^ {3 \cdot h / d} = 1000 ^ {h / d}</math> instead of <math>e ^ {2 \pi \cdot h / d} = 535.5 ^ {h / d}</math>, so his images appear somewhat compressed in comparison (but not much, because <math>1000 ^ {5} = 10 ^ {15} = 535.5 ^ {5.5}</math>). With the same pixel density and the same maximum magnification, the difference in height between the maps is only about 10 percent. By misusing a scatter plot, it is possible to create zoom images of the Mandelbrot set.
The maximum magnification is exp(2*pi*h/d) = exp(2*pi*5.5) = 535.5^5.5 = 10^15, which is also the maximum for 64-bit arithmetic.
Note that Anders Sandberg uses a different scaling.
He uses 10^(3*h/d) = 1000^(h/d) instead of exp(2*pi*h/d) = 535.5^(h/d), so his images appear somewhat compressed in comparison (but not much, because 1000^5 = 10^15 = 535.5^5.5).
With the same pixel density and the same maximum magnification, the difference in height between the maps is only about 10 percent.
By misusing a scatter plot, it is possible to create zoom images of the Mandelbrot set.
<syntaxhighlight lang="python">import numpy as np
import matplotlib.pyplot as plt
Line 11,005 ⟶ 11,000:
D, I, J = np.zeros(C.shape), np.zeros(C.shape, dtype=np.int64), np.zeros(C.shape, dtype=np.int64)
 
for k in range(n): # you can also try range(2*n) or range(5*n) due to rebasing
Z2 = Z.real ** 2 + Z.imag ** 2
M, R = Z2 < r ** 2, Z2 < E.real ** 2 + E.imag ** 2
Line 11,019 ⟶ 11,014:
plt.savefig("Mercator_Mandelbrot_deep_map.png", dpi=200)</syntaxhighlight>
 
TheYou rebasingcan conditiononly <math>|z|rebase < |\epsilon_i|</math> does not define a circular area but a half-plane. If you insert a factor,to the conditionbeginning <math>|z| < \gamma |\epsilon_i|</math> with <math>0 < \gamma < 1</math> defines a circular area containingof the origin <math>(0, 0)</math>. For example, if the current reference point <math>S_i</math> is at <math>(1, 0)</math>, the equation <math>|z| = |\epsilon_i|</math> defines the set of all points that are equidistant from <math>(0, 0)</math> and <math>(1, 0)</math>. This is exactly the perpendicular bisector at point <math>(\tfrac{1}{2}, 0)</math>. Considering the equation <math>|z| = \tfrac{1}{2} |\epsilon_i|</math> instead, one finds all points half as far from <math>(0, 0)</math> as from <math>(1, 0)</math>. All these points lie on a circle, which has center <math>(- \tfrac{1}{3}, 0)</math> and radius <math>\tfrac{2}{3}</math>sequence. If you choose a factor <math>\gamma > 1</math>, you get corresponding circles containing the reference point <math>S_i</math>. However, the rebasing condition <math>|z| < |\epsilon_i|</math> with <math>\gamma = 1</math> is optimal because it keeps the differenceswant to therebase reference sequence <math>S</math> as small as possible. A rebasing takes place exactly when the distance <math>|\epsilon_0| = |z - s_0|</math> to the reference point <math>S_0</math> is smaller as the distance <math>|\epsilon_i| = |z - s_i|</math> tofrom the current reference point <math>S_i</math>. You can only rebase to the beginning of the reference sequence. If you want to rebase to reference point <math>S_j</math>, the difference <math>\epsilon_j = z - s_j</math> must be calculated. With this subtraction, however, the entire precision is lost due to [https://en.wikipedia.org/wiki/Catastrophic_cancellation catastrophic cancellation]. Only at the first reference point <math>S_0</math> at= <math>(0, 0)</math> there is no cancellation because <math>\epsilon_0 = z - s_0 = z - 0 = z</math>. Therefore, the rebaserebasing condition <math>|z| < |\epsilon_i|</math> can also be written as <math>|\epsilon_0| < |\epsilon_i|</math> or as <math>|z - s_0| < |z - s_i|</math>. This keeps the differences to the reference points as small as possible: rebasing takes place when the distance to reference point <math>S_0</math> is smaller than to the current reference point <math>S_i</math>.
 
===Python - "One liner"===
305

edits