Существует ли эффективный способ вычисления точечного произведения двух трехмерных векторов из индекса массива? - PullRequest
1 голос
/ 05 марта 2019

Я выполняю следующее скалярное произведение двух трехмерных векторов:

import numpy as np

Nk = 8
Ns = 15
k_box = np.zeros(Nk**3)
R_box = np.zeros(Ns**3)
for k in range(Nk**3):
        Kx = int(k / (Nk*Nk))
        Ky = int(k / Nk) % Nk
        Kz = k % Nk
        for R in range(Ns**3):
            Rx = int(R / (Ns*Ns))
            Ry = int(R / Ns) % Ns
            Rz = R % Ns
            # This is the only place these variables are used!
            dot_product = Rx*Kx + Ry*Ky + Rz*Kz
            k_box[k], R_box[R] = perform_some_calculation(dot_product)

Есть ли способ вычислить скалярное произведение без предварительного явного вычисления компонентов x, y, z? Превращение этого в 6 циклов будет работать, но будет выглядеть брутто. Это похоже на то, для чего нужен трюк.

Мне также может понадобиться расширить это до некубических объемов, поэтому, если есть хитрость, и она работает для общей геометрии бокса, это было бы идеально.

Ответы [ 2 ]

2 голосов
/ 05 марта 2019

Точка продукта должна быть сделана следующим образом

import numpy as np

R = np.array([Rx,Ry,Rz])
K = np.array([Kx,Ky,Kz])
value = np.dot(R,K)
0 голосов
/ 05 марта 2019

Используйте itertools.product, чтобы получить список точек, который эквивалентен декартову произведению диапазонов каждой координаты:

>>> list(itertools.product(range(3), range(3), range(3)))
[(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 1, 0), (0, 1, 1), (0, 1, 2), (0, 2, 0), 
 (0, 2, 1), (0, 2, 2), (1, 0, 0), (1, 0, 1), (1, 0, 2), (1, 1, 0), (1, 1, 1), 
 (1, 1, 2), (1, 2, 0), (1, 2, 1), (1, 2, 2), (2, 0, 0), (2, 0, 1), (2, 0, 2), 
 (2, 1, 0), (2, 1, 1), (2, 1, 2), (2, 2, 0), (2, 2, 1), (2, 2, 2)]

Вы также можете объединить все 6 координатв один генератор:

coords = itertools.product(range(Nk), range(Nk), range(Nk), range(Ns), range(Ns), range(Ns))
for kz, ky, kx, rz, ry, rx in coords:
    k, r = Nk * (Nk * kz + ky) + kx, Ns * (Ns * rz + ry) + rx
    dot_product = kx * rx + ky * ry + kz * rz
    k_box[k], R_box[r] = perform_some_calculation(dot_product)

В качестве альтернативы, чтобы избежать вычислений индекса, используйте enumerate:

for k, (kz, ky, kx) in enumerate(itertools.product(range(Nk), range(Nk), range(Nk))):
    for r, (rz, ry, rx) in enumerate(itertools.product(range(Ns), range(Ns), range(Ns))):
        dot_product = kx * rx + ky * ry + kz * rz
        k_box[k], R_box[r] = perform_some_calculation(dot_product)
...