Mandelbrot set: Difference between revisions
Content deleted Content added
→Normalized Counting, Distance Estimation, Mercator Maps and Perturbation Theory: Added reasons for choosing the rebasing condition abs(z) < abs(epsilon). |
→Normalized Counting, Distance Estimation, Mercator Maps and Perturbation Theory: Section final revised. |
||
Line 6,551:
savefig("Mandelbrot_set_3.png")</lang>
A small change in the code above creates Mercator maps and zoom images of the Mandelbrot set. The
<lang julia>using Plots
gr(aspect_ratio=:equal, axis=true, ticks=true, legend=false, dpi=200)
Line 6,578:
savefig("Mercator_Mandelbrot_map.png")
X, Y = real(C), imag(C) # zoom images (adjust circle size
R, c, z =
gr(aspect_ratio=:equal, axis=false, ticks=false, legend=false, markerstrokewidth=0, dpi=200)
Line 6,589:
savefig("Mercator_Mandelbrot_plot.png")</lang>
For deep zoom images it is sufficient to calculate a single point with high accuracy. A good approximation can then be found for all other points by means of a perturbation calculation with standard accuracy. Placing the iteration in a separate function speeds up the calculation. See [https://en.wikipedia.org/wiki/Plotting_algorithms_for_the_Mandelbrot_set#Perturbation_theory_and_series_approximation Perturbation theory] (Wikipedia) and [https://gbillotey.github.io/Fractalshades-doc/math.html Mathematical background] (Fractalshades) for more details
<lang julia>using Plots
gr(aspect_ratio=:equal, axis=true, ticks=true, legend=false, dpi=200)
Line 6,607:
S = zeros(Complex{Float64}, n+1)
for k in 1:n+1
error("n is too large (reference sequence diverges for reference point c)!")
end
Line 6,636 ⟶ 6,637:
savefig("Mandelbrot_deep_zoom.png")</lang>
Of course, deep Mercator maps can also be created. See also the image [https://www.flickr.com/photos/arenamontanus/3430921497/in/album-72157615740829949/ Deeper Mercator Mandelbrot] by Anders Sandberg. To reduce glitches, an additional reference sequence for the derivation (dS) is recorded with high precision
<lang julia>using Plots
gr(aspect_ratio=:equal, axis=true, ticks=true, legend=false, dpi=200)
Line 6,654 ⟶ 6,655:
S, dS = zeros(Complex{Float64}, n+1), zeros(Complex{Float64}, n+1)
for k in 1:n+1
z, dz = z ^ 2 + c, 2 * z * dz + 1
if abs2(z) > abs2(r)▼
else
error("n is too large (reference sequence diverges for reference point c)!")
end
Line 6,670 ⟶ 6,672:
D = zeros(size(C))
iteration(S, dS, E, dE, C) = (2 .* S .+ E) .* E .+ C, 2 .* ((S .+ E) .* dE .+
for k in 1:n
M = abs2.(Z) .< abs2(r)
Line 6,683 ⟶ 6,685:
savefig("Mercator_Mandelbrot_deep_map.png")</lang>
Another approach to reducing glitches is rebasing. See [https://gbillotey.github.io/Fractalshades-doc/math.html#avoiding-loss-of-precision Avoiding loss of precision] (Fractalshades) and [https://fractalforums.org/fractal-mathematics-and-new-theories/28/another-solution-to-perturbation-glitches/4360 Another solution to perturbation glitches] (Fractalforums) for details.
Another approach to reduce the glitches is the so-called ''rebasing''. See [https://gbillotey.github.io/Fractalshades-doc/math.html#avoiding-loss-of-precision Avoiding loss of precision] (Fractalshades) and [https://fractalforums.org/fractal-mathematics-and-new-theories/28/another-solution-to-perturbation-glitches/4360 Another solution to perturbation glitches] (Fractalforums) for details. Remarkably, the condition for the rebasing abs2(z) < abs2(epsilon) or abs(z) < abs(epsilon) does not define a circular area but a half-plane. If you want a circular area, you can insert a factor. For 0 < gamma < 1 the condition abs(z) < gamma * abs(epsilon) defines a circular area containing the origin. For gamma = 1/2 and below, the circle lies entirely within the rescue circle around the origin O(0, 0) with escape radius r > 2, even if the associated reference point S is on the edge of the rescue circle. For example, if the reference point is at S(6, 0), the equation abs(z) = abs(epsilon) defines the set of all points that have the same distance from the origin and the reference point. This is exactly the perpendicular bisector x = 3. Considering instead the equation abs(z) = 1/2 * abs(epsilon), one finds all points half as far from the origin as from the reference point. All these points lie on a circle with center M(-2, 0) and radius R = 4. This circle lies completely in a rescue circle around the origin with escape radius r = 6. If you choose a factor gamma > 1, you will get corresponding circles containing the reference point. However, the condition abs(z) < abs(epsilon) or abs2(z) < abs2(epsilon) is optimal because it keeps the differences epsilon to the reference sequence as small as possible. Rebasing occurs if and only if the distance abs(epsilon) to the reference sequence becomes smaller as a result.▼
<lang julia>using Plots
gr(aspect_ratio=:equal, axis=true, ticks=true, legend=false, dpi=200)
Line 6,701 ⟶ 6,703:
S = zeros(Complex{Float64}, n+1)
for k in 1:n+1
else
error("n is too large (reference sequence diverges for reference point c)!")
end
Line 6,714 ⟶ 6,717:
C = (.- 4.0) .* exp.((A' .+ B .* im) .* im)
Z, dZ
D = zeros(size(C))
for i in 1:h+1, j in 1:d+1
z, dz,
for k in 1:n
▲ epsilon = (2 * S[index] + epsilon) * epsilon + delta
index = index + 1
break
▲ end
▲ epsilon, index = z, 1
▲ else
▲ index = index + 1
end
end
Z[i, j], dZ
end
Line 6,741 ⟶ 6,743:
heatmap(D' .^ 0.025, c=:nipy_spectral)
savefig("
▲
<lang julia>using Plots
gr(aspect_ratio=:equal, axis=true, ticks=true, legend=false, dpi=200)
Line 6,776 ⟶ 6,778:
heatmap(D' .^ 0.025, c=:nipy_spectral)
savefig("
=={{header|Kotlin}}==
|