A
A
Artyom Innokentiev2015-12-05 11:09:14
Python
Artyom Innokentiev, 2015-12-05 11:09:14

How to increase the speed of this script?

Script:

from sys import argv
from math import cos, sin, pi, fmod, fabs, ceil
from tkinter import Canvas, Tk, mainloop
from decimal import *
from time import time

getcontext().prec = 5

start = time()
class Turtle:
    def __init__(self, x=250, y=0, angle=0):
        self.x = Decimal(x)
        self.y = Decimal(y)
        self.angle = Decimal(angle)
        self.angle_incr = Decimal(pi/6)
        self.step = Decimal(20)
        self.old_x = Decimal(x)
        self.old_y = Decimal(y)
        self.stack_x = []
        self.stack_y = []
        self.stack_angle = []

    def plus_angle(self):
        self.angle += self.angle_incr

    def minus_angle(self):
        self.angle -= self.angle_incr

    def get_nextx(self):
        if self.get_quarter() == 1:
            x = self.x - self.step*Decimal(fabs(sin(self.angle)))
        elif self.get_quarter() == 2:
            x = self.x - self.step*Decimal(fabs(sin(self.angle)))
        elif self.get_quarter() == 3:
            x = self.x + self.step*Decimal(fabs(sin(self.angle)))
        elif self.get_quarter() == 4:
            x = self.x + self.step*Decimal(fabs(sin(self.angle)))
        return x


    def get_nexty(self):
        if self.get_quarter() == 1:
            y = self.y + self.step*Decimal(fabs(cos(self.angle)))
        elif self.get_quarter() == 2:
            y = self.y - self.step*Decimal(fabs(cos(self.angle)))
        elif self.get_quarter() == 3:
            y = self.y - self.step*Decimal(fabs(cos(self.angle)))
        elif self.get_quarter() == 4:
            y = self.y + self.step*Decimal(fabs(cos(self.angle)))
        return y

    def F(self):
        self.old_x = self.x
        self.old_y = self.y
        self.x = self.get_nextx()
        self.y = self.get_nexty()

    def open_branch(self):
        self.stack_x.append(self.x)
        self.stack_y.append(self.y)
        self.stack_angle.append(self.angle)

    def close_branch(self):
        last = len(self.stack_x) - 1
        self.x = Decimal(self.stack_x.pop(last))
        self.y = Decimal(self.stack_y.pop(last))
        self.angle = Decimal(self.stack_angle.pop(last))

    def get_quarter(self):
        angle = fmod(self.angle, 2*pi)
        if angle < 0:
            angle += 2*pi
        if (0 <= angle) and (angle < pi/2):
            return 1
        elif (pi/2 <= angle) and (angle < pi):
            return 2
        elif (pi <= angle) and (angle < 3*pi/2):
            return 3
        elif (3*pi/2 <= angle) and (angle <= 2*pi):
            return 4

turtle = Turtle()
text = argv[1]
count = int(argv[2])

tk = Tk()
canv = Canvas(tk, width=500, height=500)


for i in range(count-1):
    print(text)
    data = text
    text = text.replace('F', data)

for item in text:
    if item == 'F':
        turtle.F()
        print(turtle.old_x, turtle.old_y, turtle.x, turtle.y)
        canv.create_line(turtle.old_x, turtle.old_y, turtle.x, turtle.y)
    elif item == '-':
        turtle.minus_angle()
    elif item == '+':
        turtle.plus_angle()
    elif item == '[':
        turtle.open_branch()
    elif item == ']':
        turtle.close_branch()

canv.pack()
finish = time()
print((finish-start)/60)
mainloop()

Python version - 3.4.3 It is
run from the command line like this:
python script.py F[-F][+F] N
where N is the number of iterations
The script works fine with N 1-4, but with N = 5 it takes an unacceptably long time to calculate and does not build a drawing.
How to optimize it?
PS I tried to use Decimal so that calculations occur with a given precision (we do not need excessive precision, because it reduces performance)

Answer the question

In order to leave comments, you need to log in

1 answer(s)
C
Cobalt the Terrible, 2015-12-05
@artinnok

It can't be optimized.
Your L-system contains such a production rule that with N=5 the line with the instruction consists of 172186881 characters. I suspect that even the terminal emulator crashes for you, because this is 160 megabytes that the script outputs to the terminal.
For comparison, with N=4, the line with the instruction contains 26241 characters. As far as I can see, the code that makes the drawing has linear complexity. Those. even if for N=4 the execution of the program takes 1 second, then for N=5, according to the optimistic estimate (linear complexity without a large constant in front), it will take 6562 seconds.

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question