-3

How I can make my Python program faster? This program calculates the Mandelbrot set and draws it with turtle. I think the problem is in the for loop. Maybe the steps are taking too much time.

import numpy as np
import turtle
turtle.ht()
turtle.pu()
turtle.speed(0)
turtle.delay(0) turtle.colormode(255)

i= int(input("iteration = "))
g = int(input("accuracy  = "))
xmin = float(input("X-min: "))
xmax = float(input("X-max: "))
ymin = float(input("Y-min: "))
ymax = float(input("Y-max: "))
cmode = int(255/i)

input("PRESS TO START")
for x in np.arange(xmin,xmax,1/g):
    for y in np.arange(ymin,ymax,1/g):
        c = x + y * 1j
        z = 0
        t = 1
        for e in range(i):
            z = z * z + c
            if abs(z) > 3:
                turtle.setx(g*c.real)
                turtle.sety(g*c.imag)
                turtle.dot(2,e*cmode,e*cmode,e*cmode)
                t = 0

        if t == 1:
            turtle.setx(g*c.real)
            turtle.sety(g*c.imag)
            turtle.dot(2,"black")

input("Calculated!")
turtle.mainloop()

Here is an example

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
akinoioi
  • 21
  • 2
  • 3
    Questions regarding performance are more likely to be answered on the [Code Review](https://codereview.stackexchange.com/). – Badda Jun 09 '17 at 14:08
  • Thank you! I am a new user here so thanks for your help. Did not know that. @Badda – akinoioi Jun 09 '17 at 14:21
  • First speed-up would be to add `break` following `t = 0` (if the draw routine is triggered, you don't need to continue calculations for this point). Beyond that, Python just isn't terribly fast; you could try to push the calculations into Numpy like https://thesamovar.wordpress.com/2009/03/22/fast-fractals-with-python-and-numpy/ (claims a 3x speed-up) or you could switch to a faster compiled language like Julia https://julialang.org/ (even the name is appropriate ;-) and they include a 20x speed-up on mandelbrot set as one of their benchmarks) – Hugh Bothwell Jun 09 '17 at 14:36
  • Do you continue to iterate after the function value has escaped? – Weather Vane Jun 09 '17 at 16:02
  • 1
    ... one more intermediate step before switching languages: you could try Cython http://cython.org/ which lets you compile (statically typed) Python directly to native code. – Hugh Bothwell Jun 09 '17 at 16:12
  • thanks @HughBothwell :) – akinoioi Jun 10 '17 at 09:23
  • @HughBothwell I will take a look at them – akinoioi Jun 10 '17 at 09:26

1 Answers1

1

The following rework should be a hundred times faster than your original:

import numpy as np
import turtle

i = int(input("iteration = "))
g = int(input("accuracy  = "))
xmin = float(input("X-min: "))
xmax = float(input("X-max: "))
ymin = float(input("Y-min: "))
ymax = float(input("Y-max: "))

cmode = int(255 / i)

input("PRESS TO START")

turtle.hideturtle()
turtle.penup()
turtle.speed('fastest')
turtle.colormode(255)
turtle.setundobuffer(None)  # turn off saving undo information

turtle.tracer(0, 0)

for x in np.arange(xmin, xmax, 1 / g):
    for y in np.arange(ymin, ymax, 1 / g):
        c = x + y * 1j
        z = 0
        t = True

        for e in range(i):
            z = z * z + c

            if abs(z) > 3.0:
                turtle.setposition(g * c.real, g * c.imag)
                rgb = e * cmode
                turtle.dot(2, rgb, rgb, rgb)
                t = False
                break

        if t:
            turtle.setposition(g * c.real, g * c.imag)
            turtle.dot(2, "black")

    turtle.update()

print("Calculated!")

turtle.mainloop()

The significant change is the use of the combination of tracer() and update() to avoid visually plotting every dot for the user and just drawing as each vertical column completes.

cdlane
  • 40,441
  • 5
  • 32
  • 81
  • Also of major significance is you terminate the iteration when the function value escapes, athough `2.0` is the usual value used - once the function value (magnitude) exceeds that, it never recovers. – Weather Vane Jun 09 '17 at 21:02
  • @WeatherVane, I timed a vertical stripe and the `tracer()` / `update()` made about a 20 x improvement and the `break` made about 2 x. My guess is the `tracer()` improvement is of fixed value whereas the `break` improvement is dependent on the data and could be larger at times. Also the `break` cleans up some annoying `RuntimeWarning` messages about `cdouble_scalars`. – cdlane Jun 10 '17 at 05:27
  • @WeatherVane thank you! Its thousand times faster now :) – akinoioi Jun 10 '17 at 09:41