@artinnok
бекенд-программист

Как увеличить быстродействие данного скрипта?

Скрипт:
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 - 3.4.3
Запускается из под командной строки таким образом:
python script.py F[-F][+F] N
где N - количество итераций
Скрипт нормально работает при N 1-4, но при N = 5 он неприемлемо долго вычисляет и не строит рисунок.
Как оптимизировать его?

P.S. Я постарался использовать Decimal, чтобы вычисления происходили с заданной точностью (избыточная точность нам не нужна, ибо это уменьшает производительность)
  • Вопрос задан
  • 251 просмотр
Решения вопроса 1
@CobaltTheTerrible
Копипастю код на Python
Оптимизировать это не получится.

Ваша L-система содержит такой production rule, что при N=5 строка с инструкцией состоит из 172186881 символов. Подозреваю, что у вас даже эмулятор терминала вылетает, потому что это 160 мегабайт, которые скрипт выводит в терминал.

Для сравнения при N=4 строка с инструкцией содержит 26241 символ. Насколько я вижу у вас код, который делает рисунок, имеет линейную сложность. Т.е. даже если для N=4 выполнение программы занимает 1 секунду, то для N=5 по оптимистичной оценке (линейная сложность без большой константы впереди) потребуется 6562 секунды.
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы