I'm writing some code in Julia so that I can zoom in on a Mandelbrot set. Performance is taking a hit, so I'm trying to parallelize it. This is what I got:
using Interact, DynamicalSystems
using LinearAlgebra
using Images, ImageView
using ImageTransformations
using CairoMakie, Colors, ColorSchemes
using FileIO
using Cairo
using FixedPointNumbers
using MiniFB
using Plots
using Distributed
@everywhere begin
using Pkg; Pkg.activate(@__DIR__)
Pkg.instantiate(); Pkg.precompile()
end
addprocs(8)
@everywhere begin
function mandelbrot(xmin, xmax, ymin, ymax, width, height, max_iter, threshold,exponent)
img = zeros(RGB{Float64}, height, width)
#C(g::ColorGradient) = RGB[g[zz] for zz=LinRange(0,1,30)]
#gg = :inferno
#gg = cgrad(gg)
@distributed for j in UnitRange(1:height)
for i in 1:width
x = range(xmin, stop=xmax, length=width)
x = x[i]
y = range(ymin, stop = ymax, length = height)
y = y[j]
c = x + y * im
z = c
for iter in 1:max_iter
if abs(z)<= threshold
img[j,i] = RGB(0,0,0)
elseif abs(z) > threshold
idx = iter / max_iter
img[j,i] = RGB(j/height,i/width,idx)
#img[j, i] = RGB(gg[idx].r, gg[idx].g, gg[idx].b)
break
end
az = real(z)
bz = imag(z)
z = (az+bz)*(az-bz) + (az+az)*bz*im + c
#z = (z^4+im*z^2+1)/(z^2+1) + c
end
end
end
return img
end
end
function convert_to_n0f8(rgb::RGB{Float64})
r = clamp01(rgb.r)
g = clamp01(rgb.g)
b = clamp01(rgb.b)
return RGB{N0f8}(r, g, b)
end
function range_mod(val_min, val_max, length)
return range(val_min, val_max, length)
end
function convert_matrix_to_n0f8(matrix::Matrix{RGB{Float64}})
return [convert_to_n0f8(rgb) for rgb in matrix]
end
function coords_calc(mouse_x, mouse_y, xrange, yrange, factor)
x_click = xrange[mouse_x]
y_click = yrange[mouse_y]
xcen, ycen = x_click, y_click
xmin, xmax = xcen-factor*(xrange[end]-xrange[1]), xcen+factor*(xrange[end]-xrange[1])
ymin, ymax = ycen-factor*(yrange[end]-yrange[1]), ycen+factor*(yrange[end]-yrange[1])
return xcen, ycen, xmin, xmax, ymin, ymax
end
max_iter = 200
xmin, xmax = -2., 2.
ymin, ymax = -2., 2.
exponent = 2
threshold = 2
# Set the size of the window
global const WIDTHh = 800
global const HEIGHTh = 600
global ni = 1
global num_images = 1
function onclick(window, button, mod, isPressed)::Cvoid
global xmin, xmax, ymin, ymax, images, ni
if Bool(isPressed)
x_mouse = mfb_get_mouse_x(window)
y_mouse = mfb_get_mouse_y(window)
x_range = range(xmin, stop = xmax, length = WIDTHh)
y_range = range(ymin, stop = ymax, length = HEIGHTh)
_, _, xmin, xmax, ymin, ymax = coords_calc(x_mouse, y_mouse, x_range, y_range, 0.1)
push!(images,mandelbrot(xmin, xmax, ymin, ymax, WIDTHh, HEIGHTh, max_iter, threshold, exponent))
#images = vcat(images,mandelbrot(xmin, xmax, ymin, ymax, WIDTHh, HEIGHTh, max_iter, 2, 2, 0))
ni += 1
end
return nothing
end
function populate_buffer!(buffer, img)
global WIDTHh, HEIGHTh
buffer[:] = zeros(UInt32, HEIGHTh*WIDTHh)
h, w = size(img)
ratio = min(1, HEIGHTh/h, WIDTHh/w)
nimg = imresize(img, ratio=ratio)
nh, nw = size(nimg)
oh = (HEIGHTh-nh) ÷ 2
ow = (WIDTHh-nw) ÷ 2
for i in 1:nh
for j in 1:nw
buffer[(oh+i-1)*WIDTHh + ow+j] = mfb_rgb(nimg[i,j])
end
end
end
function imageview(dir::String=".")
global xmin, xmax, ymin, ymax, images
images = Vector{Matrix{RGB{Float64}}}()
img2 = mandelbrot(xmin, xmax, ymin, ymax, WIDTHh, HEIGHTh, max_iter, threshold, exponent)
push!(images,convert_matrix_to_n0f8(img2))
num_images = length(images)
buffer = zeros(UInt32, HEIGHTh*WIDTHh)
mfb_set_target_fps(2)
window = mfb_open_ex("Image Viewer", WIDTHh, HEIGHTh, MiniFB.WF_RESIZABLE);
mfb_set_mouse_button_callback(window, onclick);
old_ni=0
while mfb_wait_sync(window)
if ni != old_ni
populate_buffer!(buffer, images[ni])
old_ni = ni
end
state = mfb_update(window, buffer);
if state != MiniFB.STATE_OK
break;
end
end
mfb_close(window)
end
# Finally, call the main method to display the application
imageview(joinpath(dirname(pathof(MiniFB)),"..", "example"))
But what happens is that, if I run this code as it is, it doesn't run the @distributed loop. It returns a black image (corresponding to the mandelbrot() function without the loop). What can I do to fix this?