Попытка оптимизировать Python циклов с множеством условных выражений - PullRequest
0 голосов
/ 19 июня 2020

Я работаю над адаптацией кода C к Python. В общем, у меня очень мало опыта работы с C, а код был написан на C90, и при компиляции на локальном компьютере не будет давать точных результатов.

Из-за этого я хотел «ориентироваться на будущее» "программа, которую я использую. Хотя у меня есть хороший gr asp о том, что делает программа, она работает чрезвычайно медленно по сравнению с его эквивалентом C. Я хотел бы увидеть, смогу ли я оптимизировать этот код, не добавляя Cython в микс.

Чтобы дать представление о том, что делает этот код. Он начинается в начальной точке, окруженной небольшим кубом 5x5x5. Внутри куба вычисляется время пути до центральной точки в каждой ячейке (обозначается как time0 [индекс]). Оттуда куб расширяется на 1 ячейку в каждом измерении, пока не будет вычислено время прохождения для предопределенной области (400x400x53 в моем случае).

Проблема в том, что вычисление времени прохождения зависит от соседних ячеек, вычислено на предыдущих шагах в a для l oop (что может быть до 160000 итераций на расширение ячейки). Каждая стенка куба расширяется на l oop, каждая из которых содержит 49 операторов if. Итого 294 оператора if для всех 6 циклов, которые выполняются для каждого расширения измерений куба.

Короче говоря, здесь выполняется МНОГО операторов if. Я включил образец кода ниже для расширяющейся верхней части куба. Я определенно был бы признателен за совет здесь, поскольку этот код выходит за рамки любого предыдущего проекта, за который я брался.

        if dz1 > 0:
            ii = 0
            for j in range(y1+1,y2):
                for i in range(x1+1,x2):
                    sort.time[ii] = T0[i,j,z1+1]
                    sort.i1[ii] = i
                    sort.i2[ii] = j
                    ii += 1
                    print(j,i)
            sort_index = np.argsort(sort.time[0:ii])
            sort.time[0:ii] = sort.time[sort_index]
            sort.i1[0:ii] = sort.i1[sort_index]
            sort.i2[0:ii] = sort.i2[sort_index]
            for i in range(0,ii):
                X1 = int(sort.i1[i])
                X2 = int(sort.i2[i])
                index = int(z1*nxy + X2*nx + X1)
                lasti = int((z1+1)*nxy + X2*nx + X1)
                fhead = 0
                guess = time0[index]
                if time0[index+1] < 1.e9 and time0[index+nx+1] < 1.e9 and time0[index+nx] < 1.e9 and X2 < ny-1 and X1 < nx-1:
                    attempt = fdh3d(T0[X1,X2,z1+1],T0[X1+1,X2,z1+1],T0[X1+1,X2+1,z1+1],T0[X1,X2+1,z1+1],T0[X1+1,X2,z1],T0[X1+1,X2+1,z1],T0[X1,X2+1,z1],S0[X1,X2,z1],S0[X1,X2,z1+1],S0[X1+1,X2,z1+1],S0[X1+1,X2+1,z1+1],S0[X1,X2+1,z1+1],S0[X1+1,X2,z1],S0[X1+1,X2+1,z1],S0[X1,X2+1,z1])
                    if attempt < guess:
                        guess = attempt
                if time0[index-1] < 1.e9 and time0[index+nx-1] < 1.e9 and time0[index+nx] < 1.e9 and X2<ny-1  and X1>0:
                    attempt = fdh3d(T0[X1,X2,z1+1],T0[X1-1,X2,z1+1],T0[X1-1,X2+1,z1+1],T0[X1,X2+1,z1+1],T0[X1-1,X2,z1],T0[X1-1,X2+1,z1],T0[X1,X2+1,z1],S0[X1,X2,z1],S0[X1,X2,z1+1],S0[X1-1,X2,z1+1],S0[X1-1,X2+1,z1+1],S0[X1,X2+1,z1+1],S0[X1-1,X2,z1],S0[X1-1,X2+1,z1],S0[X1,X2+1,z1])
                    if attempt<guess:
                        guess = attempt
                if time0[index+1] < 1.e9 and time0[index-nx+1] < 1.e9 and time0[index-nx] < 1.e9 and X2>0  and X1<nx-1:
                    attempt = fdh3d(T0[X1,X2,z1+1],T0[X1+1,X2,z1+1],T0[X1+1,X2-1,z1+1],T0[X1,X2-1,z1+1],T0[X1+1,X2,z1],T0[X1+1,X2-1,z1],T0[X1,X2-1,z1],S0[X1,X2,z1],S0[X1,X2,z1+1],S0[X1+1,X2,z1+1],S0[X1+1,X2-1,z1+1],S0[X1,X2-1,z1+1],S0[X1+1,X2,z1  ],S0[X1+1,X2-1,z1],S0[X1,X2-1,z1])
                    if attempt<guess: 
                        guess = attempt
                if time0[index-1] < 1.e9 and time0[index-nx-1] < 1.e9 and time0[index-nx] < 1.e9 and X2>0  and X1>0:
                    attempt = fdh3d(T0[X1,X2,z1+1],T0[X1-1,X2,z1+1],T0[X1-1,X2-1,z1+1],T0[X1,X2-1,z1+1],T0[X1-1,X2,z1  ],T0[X1-1,X2-1,z1],T0[X1,X2-1,z1],S0[X1,X2,z1],S0[X1,X2,z1+1],S0[X1-1,X2,z1+1],S0[X1-1,X2-1,z1+1],S0[X1,X2-1,z1+1],S0[X1-1,X2,z1  ],S0[X1-1,X2-1,z1],S0[X1,X2-1,z1])
                    if attempt<guess: 
                        guess = attempt
                if guess > 1.0e9:
                    if time0[index+1] < 1.e9 and X1<nx-1 and X2>y1+1 and X2<y2-1:
                        attempt = fdhne(T0[X1,X2,z1+1],T0[X1+1,X2,z1+1],T0[X1+1,X2,z1],T0[X1+1,X2-1,z1+1],T0[X1+1,X2+1,z1+1], S0[X1,X2,z1],S0[X1,X2,z1+1],S0[X1+1,X2,z1+1],S0[X1+1,X2,z1] )
                        if attempt<guess:
                            guess = attempt
                    if time0[index-1] < 1.e9 and X1>0 and X2>y1+1 and X2<y2-1:
                        attempt = fdhne(T0[X1,X2,z1+1],T0[X1-1,X2,z1+1],T0[X1-1,X2,z1],T0[X1-1,X2-1,z1+1],T0[X1-1,X2+1,z1+1], S0[X1,X2,z1],S0[X1,X2,z1+1],S0[X1-1,X2,z1+1],S0[X1-1,X2,z1] )
                        if attempt<guess:
                            guess = attempt
                    if time0[index+nx] < 1.e9 and X2<ny-1 and X1>x1+1 and X1<x2-1:
                        attempt = fdhne(T0[X1,X2,z1+1],T0[X1,X2+1,z1+1],T0[X1,X2+1,z1],T0[X1-1,X2+1,z1+1],T0[X1+1,X2+1,z1+1], S0[X1,X2,z1],S0[X1,X2,z1+1],S0[X1,X2+1,z1+1],S0[X1,X2+1,z1] )
                        if attempt<guess:
                            guess = attempt
                    if time0[index-nx] < 1.e9 and X2>0 and X1>x1+1 and X1<x2-1:
                        attempt = fdhne(T0[X1,X2,z1+1],T0[X1,X2-1,z1+1],T0[X1,X2-1,z1],T0[X1-1,X2-1,z1+1],T0[X1+1,X2-1,z1+1], S0[X1,X2,z1],S0[X1,X2,z1+1],S0[X1,X2-1,z1+1],S0[X1,X2-1,z1])
                        if attempt<guess: 
                            guess = attempt
                if time0[index+1] < 1.e9 and X1<nx-1:
                    attempt = fdh2d(T0[X1,X2,z1+1],T0[X1+1,X2,z1+1],T0[X1+1,X2,z1],S0[X1,X2,z1], S0[X1,X2,z1+1],S0[X1+1,X2,z1+1],S0[X1+1,X2,z1])
                    if attempt<guess:
                        guess = attempt
                if time0[index-1] < 1.e9 and X1>0:
                    attempt = fdh2d(T0[X1,X2,z1+1],T0[X1-1,X2,z1+1],T0[X1-1,X2,z1],S0[X1,X2,z1], S0[X1,X2,z1+1],S0[X1-1,X2,z1+1],S0[X1-1,X2,z1])
                    if attempt<guess:
                        guess = attempt
                if time0[index+nx] < 1.e9 and X2<ny-1:
                    attempt = fdh2d(T0[X1,X2,z1+1],T0[X1,X2+1,z1+1],T0[X1,X2+1,z1],S0[X1,X2,z1], S0[X1,X2,z1+1],S0[X1,X2+1,z1+1],S0[X1,X2+1,z1])
                    if attempt<guess:
                        guess = attempt
                if time0[index-nx] < 1.e9 and X2>0:
                    attempt = fdh2d(T0[X1,X2,z1+1],T0[X1,X2-1,z1+1],T0[X1,X2-1,z1],S0[X1,X2,z1], S0[X1,X2,z1+1],S0[X1,X2-1,z1+1],S0[X1,X2-1,z1])
                    if attempt<guess:
                        guess = attempt
                if time0[index+1] < 1.e9 and time0[index+nx+1] < 1.e9 and time0[index+nx] < 1.e9 and X2<ny-1  and X1<nx-1:
                    attempt = fdh2d(T0[X1+1,X2,z1],T0[X1+1,X2+1,z1],T0[X1,X2+1,z1],S0[X1,X2,z1], S0[X1+1,X2,z1],S0[X1+1,X2+1,z1],S0[X1,X2+1,z1])
                    if attempt<guess:
                        fhead=(guess-attempt)/slow0[index]
                        guess=attempt
                if time0[index+1] < 1.e9 and time0[index-nx+1] < 1.e9 and time0[index-nx] < 1.e9 and X2>0  and X1<nx-1:
                    attempt = fdh2d(T0[X1+1,X2,z1],T0[X1+1,X2-1,z1],T0[X1,X2-1,z1],S0[X1,X2,z1], S0[X1+1,X2,z1],S0[X1+1,X2-1,z1],S0[X1,X2-1,z1])
                    if attempt<guess:
                        fhead=(guess-attempt)/slow0[index]
                        guess=attempt
                if time0[index-1] < 1.e9 and time0[index+nx-1] < 1.e9 and time0[index+nx] < 1.e9 and X2<ny-1  and X1>0:
                    attempt = fdh2d(T0[X1-1,X2,z1],T0[X1-1,X2+1,z1],T0[X1,X2+1,z1],S0[X1,X2,z1],S0[X1-1,X2,z1],S0[X1-1,X2+1,z1],S0[X1,X2+1,z1])
                    if attempt<guess:
                        fhead=(guess-attempt)/slow0[index]
                        guess=attempt
                if time0[index-1] < 1.e9 and time0[index-nx-1] < 1.e9 and time0[index-nx] < 1.e9 and X2>0  and X1>0:
                    attempt = fdh2d(T0[X1-1,X2,z1],T0[X1-1,X2-1,z1],T0[X1,X2-1,z1],S0[X1,X2,z1],S0[X1-1,X2,z1],S0[X1-1,X2-1,z1],S0[X1,X2-1,z1])
                    if attempt<guess:
                        fhead=(guess-attempt)/slow0[index]
                        guess=attempt
                if guess > 1.0e9:
                    if X1>x1+1 and X1<x2-1 and X2>y1+1 and X2<y2-1:
                        attempt = fdhnf(T0[X1,X2,z1+1],T0[X1+1,X2,z1+1],T0[X1,X2+1,z1+1],T0[X1-1,X2,z1+1],T0[X1,X2-1,z1+1],S0[X1,X2,z1],S0[X1,X2,z1+1] )
                        if attempt<guess:
                            guess = attempt
                attempt = T0[X1,X2,z1+1] + .5*(S0[X1,X2,z1]+S0[X1,X2,z1+1])
                if attempt<guess:
                    guess = attempt
                if time0[index+1]<1.e9 and X1<nx-1:
                    attempt = T0[X1+1,X2,z1] + .5*(S0[X1,X2,z1]+S0[X1+1,X2,z1])
                    if attempt<guess:
                        fhead=(guess-attempt)/slow0[index]
                        guess=attempt
                if time0[index-1]<1.e9 and X1>0:
                    attempt = T0[X1-1,X2,z1] + .5*(S0[X1,X2,z1]+S0[X1-1,X2,z1])
                    if attempt<guess:
                        fhead=(guess-attempt)/slow0[index]
                        guess=attempt
                if time0[index+nx]<1.e9 and X2<ny-1:
                    attempt = T0[X1,X2+1,z1] + .5*(S0[X1,X2,z1]+S0[X1,X2+1,z1])
                    if attempt<guess:
                        fhead=(guess-attempt)/slow0[index]
                        guess=attempt
                if time0[index-nx]<1.e9 and X2>0:
                    attempt = T0[X1,X2-1,z1] + .5*(S0[X1,X2,z1]+S0[X1,X2-1,z1]);
                    if attempt<guess:
                        fhead=(guess-attempt)/slow0[index]
                        guess=attempt
                if guess < time0[index]:
                    time0[index] = guess
                    T0[X1,X2,z1] = guess
                    if fhead > headtest:
                        headw[5]+=1
            if z1 == 0:
                dz1 = 0
            z1-=1

Я также пытался ускорить код, уменьшив размер циклов for, однако это действительно замедлило код! Вот пример того, что я сделал:

        if dz1 > 0:
            ii = 0
            sort.time = np.ndarray.flatten(T0[x1+1:x2,y1+1:y2,z1+1])
            sort.i1 = np.array([(i) for i, j in product(range(x1+1,x2), range(y1+1,y2))])
            sort.i2 = np.array([(j) for i, j in product(range(x1+1,x2), range(y1+1,y2))])
            ii = sort.time.size
            sort_index = np.argsort(sort.time)
            sort.time = sort.time[sort_index]
            sort.i1 = sort.i1[sort_index]
            sort.i2 = sort.i2[sort_index]
            for X1,X2 in zip(sort.i1,sort.i2):
                 index = z1*nxy + X2*nx + X1

1 Ответ

0 голосов
/ 19 июня 2020

Это уродливый кусок кода. Довольно непонятно. Единственное, что приходит в голову, - это преобразование вашей структуры if-if-if в структуру if-elif-elif, что является правильным способом сделать это, если у вас есть взаимоисключающие случаи. Это позволит избежать некоторых математических вычислений и немного ускорит процесс, но, честно говоря, это требует пересмотра с нуля.

...