TFC-343/Mandelbrot

Implementation Issues

Closed this issue ยท 5 comments

Came here from the Reddit thread. Running it now so I can see if I'm seeing the same issue on my machine. I've written down the big issues that I can see. Are you looking for any pull requests or suggestions?

Complex Number Parsing

Regarding your comment from the Readme, it looks like your problem with scientific notation has a few factors. For one, yes, you are throwing away data if the numbers get too large or too small. Also, if the real component is too small, you are tossing out the imaginary component altogether since the string split operation on the complex number splits on the negative sign of the exponent of the real term. I set a breakpoint in the except statement on line 46 of complex_maths.py to grab an example:

-3.200000000092018e-05+6.754176000000001i

Since the code is splitting on any occurrence of + or -, the above gets split into 3 terms. The real component gets changed to -3.2 when its actual value is -0.000032. The imaginary component is 6.8i, but the code grabs term "[1]", which is -05. The code then strips the last character off of the "imaginary component", which results in the code continuing with a brand new complex number -3.2+0i when the actual value was closer to 0+6.8i.

The custom complex_maths handling is really neat and it's cool that it's working as well as it does, but you're probably better off throwing it out and using Python's builtins for complex numbers. The built-in complex number system doesn't support the < or > operators so you'll still need some code to do that, but it does support complex number construction and all of the arithmetic operations that you're using.

Escape Time Algorithm

It looks like your check function could use some edits. The Wikipedia article on Mandelbrot sets mentions:

Because no complex number with a real or imaginary part greater than 2 can be part of the set, a common bailout is to escape when either coefficient exceeds 2.

(https://en.wikipedia.org/wiki/Mandelbrot_set#Escape_time_algorithm)

Your code is checking to see if either term exceeds 2500 or 1000, which is a few orders of magnitude above what you need to be checking. If you improve the check function, you should see considerable gains in performance as well. There are also a lot of other performance considerations that the article makes reference to, if you're interested in using this code to make any Mandelbrot animations.

Suggestion

I made a quick edit to check(r, f) with these changes, which

  1. improved the performance (I didn't let your code run to completion since it was taking too long. My last execution with the altered function took 91.5 seconds)
  2. deprecates your complex number library, and
  3. resulted in a correct display of the Mandelbrot set (below).
def check(r, f):
    z = 0+0j
    loops = 0
    # this loop iterated the code untill it either gets to big or we hit 500 loops
    while (z.real*z.real) + (z.imag*z.imag) <= 4 and loops < 500:
        z = (z*z) + complex(r/100, f/100)
        loops += 1
    if (z.real*z.real) + (z.imag*z.imag) > 4:
        return 'black'  # sets it to black if the sequence does not tend towards infinity (is more than 2 after
                        # 500 iterations)
    else:
        return 'white'  # sets it to white

image

Edit: Flipping the > to a <= when deciding on the color reverses the colors in the image. Sorry for that mistake. The colors are wrong, but the shape is right.

I added a grayscale gradient effect in place of the return 'black' if inside and return 'white' if outside, if you're interested in that code as well. Looks pretty nice when max iterations is set to 100 instead of 500.

image

thanks! I really appreciate you looking at and fixing my code - making it work so well.
I would love to see the code to make that last fractal.

I didn't know that python had in-built complex maths, I probably should have checked before I made that entire piece of code. + doing more research into the Mandelbrot fractal before jumping in to coding it.

Happy to help!

I probably should have checked before I made that entire piece of code. + doing more research into the Mandelbrot fractal before jumping in to coding it.

I mean, sometimes you just have to dive right into something and see what you learn along the way. Most of the code works pretty well on its own, albeit it could use a bit of cleanup, especially since the check function has to be aware of the UI scaling, since you need to divide the input by 100. Other than that, I really didn't have to change or think about much to get it working correctly!

I've pushed a commit to a fork containing the code that generated the last image. Feel free to pull the changes into your project, but I can make a pull request if you'd prefer.

https://github.com/AustinTSchaffer/Mandelbrot

The principles behind the second image are surprisingly simple. The convention is to color pixels based on how long it took for the pixel to escape the iteration loop. All you need to do is decide what colors you want to use and come up with a way to map "number of iterations" to "the colors you want to use". I accomplished that by

  1. returning the number of iterations from check, instead of returning a single color
  2. re-scaling the number of iterations to the range 0-255, resulting in 256 possible colors in the output image. Since you know that check iterates somewhere between 0 and MAX_ITERATIONS times, you can use a fairly simple formula to accomplish that. The only weird part was that the range needs to be reversed in order to make the center black instead of white.
  3. formatting the re-scaled number into hex notation, repeating the value 3 times, which always results in gray.

You can get much more interesting images if you remap the range 0 to MAX_ITERATIONS to a more interesting color palette, but gray is easy.

thanks, that works great, if you could do the pull request as I'm not very good at using github.

whoops