
Generating the Mandelbrot Set - scionofbytes
https://scionofbytes.me/misc/generating-mandelbrot-fractals/
======
ipython
It’s a right of passage to generate the Mandelbrot set. I have fond memories
of being handed the scientific American article introducing it- apparently you
can download a pdf version here:
[https://static.scientificamerican.com/sciam/assets/media/inl...](https://static.scientificamerican.com/sciam/assets/media/inline/blog/File/Dewdney_Mandelbrot.pdf)

As a high school student I was fascinated and implemented it on any machine I
had access to. I remember being bored in math class and coding it on my TI-81
calculator. That took a while to render in black and white but it did work!

Great memories. Thanks for posting.

~~~
manifestsilence
Me too! I think I used a TI85 or 89 but yup! It was awesome learning how to
make them after years of playing with them on Fractint, just zooming around.

~~~
jackfraser
I miss Fractint. I spent hours playing with that thing as a kid, with no idea
about the math behind it (and no Numberphile to help explain it). So I just
zoomed and plotted and got really familiar with which particular SVGA modes I
could use and which I couldn't.

I still remember discovering Render To Disk and realizing I could save stuff
out and open it up in Rainbow Paint... which has been lost in the sands of
internet.

------
YjSe2GMQ
I once wrote a PostScript program that generates Mandelbrot, tuned it so that
it finishes up in reasonable time, and sent to some old laser printer. On next
day morning the machine finished up churning numbers and spat out a known
picture.

BTW: .ps (PostScript) is a fun little stack based language, similar to JVM.
Document is simply the result of the program execution. You can program it by
hand, though I do not recommend anything large.

~~~
RBerenguel
It's a very fun exercise when you are starting with PostScript... and indeed,
unless you are familiar with Forth or any other stack based language, it's a
big pain to write. A long time ago I wrote a very short "tutorial" [1] on my
blog (which right now looks very bad due to change in stylesheets that don't
have translated well... The code for the Mandelbrot set there is broken (due
to googlecode dying), but I just moved from my local copy to a gist [2]. And
the code for the Christmas postcard (with Koch snowflakes and Gosper curves)
is here [3]. It is commented, but not sure how useful it can be.

[1] [https://www.mostlymaths.net/2008/12/quick-postscript-
program...](https://www.mostlymaths.net/2008/12/quick-postscript-programming-
tutorial.html)

[2]
[https://gist.github.com/rberenguel/9a5239034cafdeaabdf665444...](https://gist.github.com/rberenguel/9a5239034cafdeaabdf6654446521254)

[3]
[https://gist.github.com/rberenguel/38f5106fee2a795be45d6a335...](https://gist.github.com/rberenguel/38f5106fee2a795be45d6a33532fd0e4)

Edit: having a blog with posts from 10 years ago you want to reference is
painful... Broken links, grammar errors, unclear writing, typos...

------
sorenjan
If you want to use a browser to generate the Mandelbrot set I think the best
option is a WebGL shader. I found this, but there should be plenty of variants
out there as it's a classic example of a parallel problem that benefits
immensely from using the GPU.

[https://www.shadertoy.com/view/4df3Rn](https://www.shadertoy.com/view/4df3Rn)

~~~
jerf
As the comments on that page indicate, you have problems with float precision
pretty quickly. It's hard to intuit just how fast you're shedding bits when
you zoom in.

Some quick DDG-ing around suggests that there isn't a great solution for
arbitrary-precision GPU numbers, and that trying to force it on to GPUs either
loses all the speed advantages it has over CPUs or even just loses to CPUs.
Corrections solicited.

(Remember... GPUs aren't "faster" than CPUs. They're _different_. There are
things GPUs are much faster than CPUs, but there's also plenty of tasks...
indeed, it's _most_ of them that we actually perform... where CPUs are faster.
You can get differentials of 100x-1000x in _either direction_. That's why we
use CPUs.)

~~~
sorenjan
I know GPUs aren't necessarily faster than CPUs, but they are more parallel.
The article's graphics didn't work in my browser so I haven't looked at the
results other than the rendered images, but there's no arbitrary precision in
the linked code. It's an attempt to speed up the rendering using threads, when
the GPU would be faster.

I found this version [0] that uses perturbation theory to get deep zoom on the
GPU. I haven't seen it before and haven't looked into it, but it seems neat.

[0] [https://github.com/munrocket/deep-
fractal](https://github.com/munrocket/deep-fractal)

~~~
jerf
"they are more parallel"

They are more parallel for _very specific things_ , most of which go flying
out the window when you try to use arbitrary precision floats. GPUs are not
parallel arrays of CPUs; they're parallel arrays of what are very stupid and
unoptimized execution units from a CPU's point of view. (The "stupid and
unoptimized" is to some extent a feature; you can control them deeply, unlike
the high performance CPUs, which are to the point where they're not just
second-guessing you, they're second-guessing their second guesses. But they
don't have a lot of caches, they don't reorder things themselves, etc.)

From the linked project: "Using the perturbation method, we can calculate only
one point with an arbitrary precision in CPU and restore the rest of the
picture with float precision in GPU."

Now that's where the big wins really are. I Have A Dream (which will never
happen) of writing a programming language that makes it easier to mix CPU and
GPU execution in some sensible manner.

~~~
sorenjan
> They are more parallel for very specific things

And the Mandelbrot set is one of those things, at least when you're not doing
arbitrary precision which the article isn't doing anyway.

> I Have A Dream (which will never happen) of writing a programming language
> that makes it easier to mix CPU and GPU execution in some sensible manner.

You need to take care so the synchronization isn't eating your performance
wins though. I know you wrote "in a sensible manner", so you probably already
thought of that. I don't know if another programming language is what the
world needs, but there are libraries available to at least ease the pain.

I recently found Vulkan compute for people. I haven't tried it yet, maybe
you'll find it interesting.

[https://github.com/Glavnokoman/vuh](https://github.com/Glavnokoman/vuh)

~~~
jerf
"You need to take care so the synchronization isn't eating your performance
wins though. I know you wrote "in a sensible manner", so you probably already
thought of that."

Like I said, I haven't gotten too far into it, but one of the other ideas that
keeps coming to mind is to have some sort of cost model in the language,
because one of my other I Have A Dream elements of a new language is the
ability to make assertions about blocks of code like "this code is inlined" or
(in a GC'ed language) "this variable is stack allocated", or in the case of
crypto code, "this code is optimized only to constant-time operations". These
assertions wouldn't make the thing they are asserting happen, because
experience over the decades shows that that doesn't work (witness the way that
inline pragmas have gotten consistently weaker over the years to the point
that I believe they're no-ops in many environments), but they'd be signs to
the compiler to say back to the user that if the constraint is violated,
here's a clear message explaining why.

The idea could be adapted to something like "this block of code only copies
the data to the GPU once" or some variant of that claim (a given byte only
copied once).

I think a similar thing could be used for some interesting network/cloud
transparency, too, where the language permits wiring up function
calls/messages/whatever transparently, but you can use labeling to make
compile-time (or possibly start-up time) assertions about how expensive the
result is going to be. I've tossed around the idea of making a function call
not necessarily be the fundamental primitive, but maybe have something weaker
than that be the cross-module default, like an Erlang message pass. One of the
reasons networks are such a pain to work with in conventional programming
languages is the mismatch between function calls and network operations; it
would be interesting to expand on Erlang and see if we might be able to
address that via weakening the function call across modules.

Anyhow, like I said, I'll never get to any of this, but I do sort of feel like
there's a surprising amount of room for a new language out there that doesn't
get explored very well because people keep remaking Python or something like D
over and over again, just with slightly different spelling.

~~~
ghusbands
You probably already know of it, but you might find Halide interesting. It
aims to separate computation strategy and dataflow, in a performant fashion.

Also, potentially pyCUDA and other things that google autocompletes when you
type "pyCUDA vs".

None of them are exactly what you're talking about, of course.

~~~
sorenjan
This is one of those things I have in my list of things to try out one of
these days. If I'm not mistaken, this is what Google use to implement their
image algorithms in their Google Camera Android app. Marc Levoy is one of the
co-authors of the Halide paper [0] and is now working at Google, so it's
natural. Do you happen to know how widely used it is in industry?

[0] [http://graphics.stanford.edu/papers/halide-cacm18/halide-
cac...](http://graphics.stanford.edu/papers/halide-cacm18/halide-cacm18.pdf)

[https://halide-lang.org/](https://halide-lang.org/)

~~~
ghusbands
If you mean me (and I guess others aren't likely to come across this
conversation):

I was very impressed by Halide but I'm not involved and have no idea how
widely it is used, sorry. I could imagine that a lot of potential users enjoy
tweaking GPU and SIMD code enough, or have enough confidence in their results,
that they don't give it a good look.

------
dghf
Picky point:

> Let’s just say that for our purposes we can think of complex numbers
> existing on a line perpindicular to our regular number line. If you take a
> piece of graph paper and mark a line from left to right, and then another
> line that crosses that line at 90 degrees, from top to bottom, you can
> imagine that the horizontal line represents the real number line, and the
> vertical line represents the complex number line.

The vertical line is the _imaginary_ number line. 2 is as much a complex
number as 3 _i_ is (2 + 0 _i_ vs 0 + 3 _i_ ).

------
graycat
The Mandelbrot set is _bizarre_ , astoundingly so. E.g., since it is a
fractal, it is astoundingly irregular.

Mandelbrot argued that commonly shapes in nature are fractals. So, we could go
to a mountain range, find a lake, and then suspect that the surface is a 2D
fractal.

Well, as bizarre as the Mandelbrot set is, actually it is a _closed_ set in
the usual topology for the plane. Then there is a theorem that there is a
function from the plane to the line that is 0 on the Mandelbrot set, strictly
positive otherwise, and infinitely differentiable. Similarly there is a
function that is 0 on the boundary of that set, negative in the interior, and
positive otherwise.

So, in general, with the Mandelbrot set just an example, these results hold
for any closed set in the plane. And the result generalizes to dimension 1 and
all finite dimensions greater than 2. So, a set is closed if and only it it is
the level set of an infinitely differentiable function 0 on the boundary of
the set, negative in the interior, and positive otherwise.

This result can be used to show that in the constraint qualifications for the
Karush-Kuhn-Tucker conditions, the (i) Zangwill and (ii) Kuhn-Tucker
constraint qualifications are independent. For a while that fact was an
outstanding unanswered question about constraint qualifications.

Somewhere in one of the papers of Arrow, Hurwicz, and Uzawa on mathematical
economics there is a similar question about constraint qualifications asked
but not answered that is easily answered with an example based on these
results about infinitely differentiable functions and closed sets.

Back to the mountains, we can argue that the surface of the land, above, at
the boundary, and on the bottom of the lake can be infinitely differentiable
while the lake is the Mandelbrot set or any closed set.

Bizarre stuff!

------
ocfnash
Here's a fun fact about the Mandelbrot set, which I will communicate in Python
in the hope that you can have a little fun witnessing the results:

    
    
      def N(eps):
        c = -0.75 + eps*1j
        n = 0
        z = 0
        while abs(z) < 2:
          z = z*z + c
          n += 1
        return n
    
      [N(eps) for eps in [0.1, 0.01, 0.001, 0.0001, 0.00001, 0.000001]]

~~~
Twirrim
That was interesting. It continues for a little bit, but it soon falls apart:

    
    
        $ pypy3 man.py
        [33, 315, 3143, 31417, 314160, 3141593, 31415927, 7853981629]

~~~
ocfnash
It continues forever! See here for example:
[https://mathoverflow.net/questions/215187/is-there-a-
referen...](https://mathoverflow.net/questions/215187/is-there-a-reference-
for-computing-pi-using-external-rays-of-the-mandelbrot)

I believe you are just running into the limits of double precision arithmetic;
indeed log_2((10^8)^2) > 53.

------
jrockway
What I like about generating this picture is that the color of every pixel is
completely independent. If you have 2 cores, you can generate it twice as
fast. If you have a million cores, you can generate it a million times faster.

Apparently I attempted this in Haskell 10 years ago:
[https://gist.github.com/jrockway/291074](https://gist.github.com/jrockway/291074).
I seem to recall adding things to that GTK image builder the slowest part by
far. I bet things are better 10 years later though.

------
eb0la
Take a look at Fractint (fractint.org) and all kind of fractals it can
generate.

I became obsessed with IFS (iterated function systems) a looooong time ago.
Take a look at the colage theorem and try to make your own ;-)

Cheers

~~~
trollied
Oh, me too. I was obsessed with Fractint when I was a teenager - It's what got
me into coding. Wrote some Pascal that morphed one IFS pattern into another &
was soooo pleased with myself :-)

Some modern fractal things that I appreciate:

Example IFS generator: [http://sirxemic.github.io/ifs-
animator/](http://sirxemic.github.io/ifs-animator/) Mandelbulb 3D ( _amazing_
): [http://www.mandelbulb.com](http://www.mandelbulb.com)

If anyone wants to start with something simple, try and write a Sierpinski
Gasket generator. Very very simple, yet infinitely complicated.

~~~
ghaff
Fractint was one of a number of programs that were very popular for a period
because they really showed off graphics cards that, for the first time on
consumer hardware, could display reasonably high resolution graphics (EGA then
VGA).

------
Nursie
I have a python fractal drawer here -
[https://github.com/starnose/fract](https://github.com/starnose/fract)

That can do a load of different types (Pickover Biomorphs, Newton-Raphson
approximations, burning ships, Mandel-drops etc). Always loved drawing
fractals. One day I'll get around to implementing Ray-marching and draw the
mandelbulb!

------
cr0sh
Hah - s/he's complaining about "slow" being 2-7 seconds...

...I remember back when I was in high school making a generator for this in
BASIC on an Apple IIe, running 16 colors in the "double high res mode" (needed
the 80-column card for it - only machine that had it) - and having it run for
hours just to generate one image.

Slow...sigh.

~~~
ChrisGranger
I have those memories as well, only it was a Commodore 64. I believe I found
the program used to generate the set in Compute! magazine and had to type it
manually. Good times.

------
doodpants
Pardon the off-topic comment, but is anyone else finding the discussed web
page to be sluggish to the point of unusability? (This is on Firefox 67, on
Windows 7.) I'm not talking about page load time; once the page has finished
loading:

\- trying to scroll the page using arrow keys or Page Up/Down keys takes
several seconds between key press and response

\- when dragging the scroll bar manually, the new scrolled-in area is blank
white for several seconds before finally filling in with content

\- even right-click, or click-drag to select text, takes a few seconds to
respond

I tried disabling javascript on the page, but it makes no difference, so it's
not some runaway script. I'm guessing that maybe there are some very high
resolution Mandelbrot images that are being scaled in the browser?

~~~
stan_rogers
FF 67.0 on Win10 w/uBlock Origin, i3 7100/8 GB, snappy. Scrolling back up
reloads/regens images, so there's a sub-second flash of empty in the image
locations, but otherwise it's not misbehaving for me at all.

------
liveoneggs
[https://www.sqlite.org/lang_with.html](https://www.sqlite.org/lang_with.html)
scroll down to the bottom to see a sqlite mandelbrot

------
manifestsilence
It gives me warm fuzzies being surrounded by fellow Mandelbrot lovers on this
thread. I've been enchanted by fractals ever since seeing IFS ferns that
someone made in BASIC on a green monochrome screen.

I've wanted for a long time to get around to generating the Mandelbrot as a 3D
height map (Fractint could do that from a static viewpoint), and make it
explorable. Ideally where you can change size to explore it all...

~~~
scionofbytes
That sounds like a cool idea. Do you mean the height would be based on color
with the blackness being either a deep point or a high plateau?

~~~
manifestsilence
Yeah, pretty much, though really the colors are based on how long it takes a
point to "escape" the set, if it does, with the blackness being ones that
never do (to whatever level of diligence you have time to compute "never"). I
was thinking the center black bug would be a deep crevasse or the "floor",
with mountains rising on either side, so you could wander around in the
canyons around a giant flat lowland, surrounded by mountain ridges.

------
jjar
I always found implementing fractals very satisfying, so this was a good read.
Shameless plug for my own subpar Julia set viewer (Julia set results "make up"
the Mandlebrot set):
[http://thejamespaterson.com/scripts/julia/](http://thejamespaterson.com/scripts/julia/)

~~~
scionofbytes
Your website hurt my brain but I enjoyed the Julia Fractal generator.

------
lovasoa
I made a pull request with large performance improvements, and compatibility
with all modern browsers: [https://github.com/ScionOfBytes/smooth-
mandelbrot/pull/1](https://github.com/ScionOfBytes/smooth-mandelbrot/pull/1)

------
melling
I’ve got some Mandelbrot resources at the bottom of this Github page:

[https://github.com/melling/ComputerGraphics](https://github.com/melling/ComputerGraphics)

------
Damogran6
It took 4 Amiga 500s about 3 days to render the mandelbrot set at 320x200 when
I was in High School. In case anyone is plotting out the increase in computer
power over the years.

~~~
yodsanklai
you had to code it in assembly! I believe it took about a few minutes on my
Amiga.

~~~
zimpenfish
I wrote a version in False[1] (sadly lost to the sands of time) which was
pretty nippy on my A5000.

[1] [http://strlen.com/false-language/](http://strlen.com/false-language/)

------
Tempest1981
Also popular around that time in the 80s:

[https://en.wikipedia.org/wiki/Bifurcation_diagram](https://en.wikipedia.org/wiki/Bifurcation_diagram)

And the book Chaos, by James Gleick

Oh, and The Cuckoo's Egg, by Clifford Stoll

------
joseph8th
Invariably when learning a new language, making a Mandelbrot generator is my
first project (after tutorials). Added benefit: I can compare benchmarks since
Mandelbrot algorithm is CPU heavy.

------
ctoth
As I was reading this I just kept hearing in my head...

Take a point called Z in the complex plane,

let z[1] be z^2+C...

let z[2] be z[1]^2+c...

let z[3] be z[2]^2+c

And so on.

[https://www.youtube.com/watch?v=QrztrxV9OtQ](https://www.youtube.com/watch?v=QrztrxV9OtQ)

------
ryanmercer
Mandelbrot is of the devil Bobby Boucer! It is entirely too easy to lose a
Saturday on YouTube just watching these videos.

------
lozf
Whilst we're on the subject, let's not forget ffmpeg:

    
    
         ffplay -f lavfi -i mandelbrot

