Какие методы могут быть использованы для ускорения этого кода Python, включая вложенные циклы for? - PullRequest
0 голосов
/ 26 февраля 2019

У меня есть следующий код, который включает суммирование по множеству вложенных циклов for.

Какими способами я могу ускорить выполнение этого кода?Меня интересует не только один метод его ускорения, мне бы очень хотелось увидеть ряд методов, например, «Чистый Питон», Numpy, Scipy, Cython и т. Д.

Это так, чтобыдля аналогичного, но (намного) более сложного кода, который я должен написать, я мог бы выбрать вариант ускорения, который дает хороший компромисс между скоростью выполнения и сложностью реализации.Что-нибудь, что избавит меня от необходимости писать код на C ++, что приведет к потере воли к жизни.

def f(a,b,c,d):
    return a+b+c+d

x = [0.04691008, 0.23076534, 0.5,        0.76923466, 0.95308992]
w = [0.11846344, 0.23931434, 0.28444444, 0.23931434, 0.11846344]
numQuadNodes = 5

def tensorGauss(func):
    sum = 0;
    for i in range(0,numQuadNodes):
        for j in range(0,numQuadNodes):
            for k in range(0,numQuadNodes):
                for l in range(0,numQuadNodes):
                    sum += w[i]*w[j]*w[k]*w[l]*func(x[l],x[k],x[j],x[i])

    return sum

print(tensorGauss(f))

Редактировать - более реалистичный код Как вы можете видеть, tenorGauss уже намного быстреечем nquad (0,07 с против 20,86 с на моей машине), но я действительно хотел бы иметь несколько способов снова ускорить тензор Гаусса, поскольку мне придется вычислять тонну оценок тензоргаусса!

import numpy as np
import numpy.linalg as LA
from scipy.integrate import nquad
import time

##################################################
# Triangle vertices
##################################################
v_a_1 = np.array([[4,0,0]]).T
v_a_2 = np.array([[5,1,0]]).T
v_a_3 = np.array([[4,2,0]]).T

v_b_1 = np.array([[4,0,0]]).T
v_b_2 = np.array([[5,-1,0]]).T
v_b_3 = np.array([[4,-2,0]]).T

##################################################
# g_tau
##################################################
def g_tau():
    J_tau = v_a_2-v_a_1
    J_tau = np.append(J_tau, v_a_3-v_a_2,axis=1)
    G = np.dot(J_tau.T,J_tau)
    return np.sqrt(LA.det(G))

##################################################
# g_t
##################################################
def g_t():
    J_t = v_b_2-v_b_1
    J_t = np.append(J_t, v_b_3-v_b_2,axis=1)
    G = np.dot(J_t.T,J_t)
    return np.sqrt(LA.det(G))

##################################################
# chi_tau
##################################################
def chi_tau(x):
    return v_a_1 + (v_a_2-v_a_1)*x[0] + (v_a_3-v_a_2)*x[1]

##################################################
# chi_t
##################################################
def chi_t(y):
    return v_b_1 + (v_b_2-v_b_1)*y[0] + (v_b_3-v_b_2)*y[1]

##################################################
# k_
##################################################
def k_(x,y):
    return LA.norm(x+y)

##################################################
# k
##################################################
def k(x,y):
    return k_(chi_tau(x),chi_t(y))*g_tau()*g_t()

start=time.time()

##################################################
# tensorGauss
##################################################
x = [0.04691008, 0.23076534, 0.5,        0.76923466, 0.95308992]
w = [0.11846344, 0.23931434, 0.28444444, 0.23931434, 0.11846344]
numQuadNodes = 5

def f(z, y, x, w):
    a_1_1 = z;
    a_1_2 = z * w;
    a_2_1 = z * x;
    a_2_2 = z * x * y;

    a_1 = np.array([a_1_1,a_1_2]).T
    a_2 = np.array([a_2_1,a_2_2]).T
    res = k(a_1,a_2)

    a_1_1 = z * x;
    a_1_2 = z * x * y;
    a_2_1 = z;
    a_2_2 = z * w;

    a_1 = np.array([a_1_1,a_1_2]).T
    a_2 = np.array([a_2_1,a_2_2]).T
    res += k(a_1,a_2) 

    a_1_1 = z * y;
    a_1_2 = z * w;
    a_2_1 = z * x;
    a_2_2 = z;

    a_1 = np.array([a_1_1,a_1_2]).T
    a_2 = np.array([a_2_1,a_2_2]).T
    res += k(a_1,a_2)     

    return res

def tensorGauss(func):
    sum = 0;
    for i in range(0,numQuadNodes):
        for j in range(0,numQuadNodes):
            for k in range(0,numQuadNodes):
                for l in range(0,numQuadNodes):
                    sum += w[i]*w[j]*w[k]*w[l]*func(x[l],x[k],x[j],x[i])

    return sum

start=time.time()
tensorGauss_res = tensorGauss(f)
end=time.time()
tensorGauss_time = end-start


start=time.time()
[nquad_res, err] = nquad(f, [[0,1], [0,1], [0,1], [0,1]])
end=time.time()
nquad_time = end-start

print(f'tensor-gauss: {tensorGauss_res}')
print(f'nquad:        {nquad_res}')
print('\n')
print(f'tensor-gauss time: {tensorGauss_time}')
print(f'nquad time:        {nquad_time}')

1 Ответ

0 голосов
/ 26 февраля 2019

Я переписал вашу функцию тензорGauss (), как показано ниже:

def tensorGauss(func):

    w_gen = np.meshgrid(w,w,w,w,indexing='ij')
    x_gen = np.meshgrid(x,x,x,x,indexing='ij')
    sum = np.sum(w_gen[0] * w_gen[1] * w_gen[2] * w_gen[3] * 
                            f(x_gen[3], x_gen[2], x_gen[1], x_gen[0]))

    return sum

, и она напечатала результат 2.0, в отличие от значения 1.9999999999999971, напечатанного упрощенной tensorGaussчто вы разместили (тот, который использует упрощенную функцию f()).

Однако некоторые заявления об отказе от ответственности:

  1. Будет ли это работать без ошибок, будет зависеть от вашего реальногокод (материал с такими именами, как g_tau и т. д.).Я говорю это потому, что это решение предполагает, что ваша f является векторизованной функцией, которая будет работать поэлементно, если вместо скаляров передаются массивы.Я вижу, что это предположение справедливо для вашего манекена f(), но тогда я не знаю, будет ли оно справедливо и для вашего реального f()
  2. Получите ли вы какие-либо преимущества в производительности или нет с этим решениемтакже лучше всего проверять ваш реальный код вместо фиктивной f и ваш реальный размер данных
...