Как эффективно умножить 3D-матрицу на 2D-матрицу в numpy - PullRequest
1 голос
/ 23 апреля 2020

У меня есть два многомерных массива, которые я хочу умножить друг на друга. Один имеет форму N, N, 3, а другой имеет форму N, N.

Позвольте мне установить сцену:

У меня есть массив положений атомов в форме N,3 :

atom_positions = [[x1,y1,z1],
                  [x2,y2,z2],
                  [x3,y3,z3],
                  ...       
                            ]

Из них я вычисляю верхнюю три angular матрицу векторов расстояния так, чтобы полученная матрица N, N, 3 содержала все уникальные парные векторы расстояния r_ij векторов внутри atom_positions :

pair_distance_vectors = [[[0,0,0],[x2-x1,y2-y1,z2-z1],[x3-x1,y3-y1,z3-z1],...],
                         [[0,0,0],[0,0,0]            ,[x3-x2,y3-y2,z3-z2],...],
                          ...
                                                                              ]

Теперь я хочу нормализовать каждый из этих парных векторов расстояния. Для этого я хочу использовать массив N, N pair_distances, который содержит длину каждого вектора внутри pair_distance_vectors. Формула для одного вектора: r_ij / | r_ij |

Я хочу сделать это путем умножения матриц, где каждая запись в массиве N, N становится скаляром, с помощью которого вектор внутри N, N, 3 массив умножается. Я почти уверен, что это может быть как-то достигнуто с помощью numpy с помощью numpy.dot() или другой функции, но я просто не могу найти ответ сам. Кроме того, я боюсь, что если я найду преобразование, которое учитывает это, мои математические вычисления будут ошибочными.

Вот некоторый демонстрационный код, который выполняет то, что я хочу, очень неэффективным образом:

import numpy as np

pair_distance_vectors = np.ones(shape=(2,2,3))
pair_distances = np.array(((1,2),(3,4)))
normalized_pair_distance_vectors  = np.zeros(shape=(2,2,3))

for i,vec_list in enumerate(pair_distance_vectors):
    for j,vec in enumerate(vec_list):
        normalized_pair_distance_vectors[i,j] = vec*pair_distances[i,j]

print(normalized_pair_distance_vectors)

Заранее спасибо.

РЕДАКТИРОВАТЬ: Может быть, это яснее:

distance_vectors = [[[x11,y11,z11],[x12,y12,z12],[x13,y13,z13],...],
                    [[x21,y21,z21],[x22,y22,z22],[x23,y23,z23],...],
                    ...                                            ]

distance_matrix = [[r_11,r_12,r_13,...],
                   [r_21,r_22,r_23,...],
                    ...                 ]

norm_distance_vectors = some_operation(distance_vectors,distance_matrix)

norm_distance_vectors = [[r_11*[x11,y11,z11],r_12*[x12,y12,z12],r_13*[x13,y13,z13],...],
                         [r_21*[x21,y21,z21],r_22*[x22,y22,z22],r_23*[x23,y23,z23],...],
                          ...                                                    ]

1 Ответ

1 голос
/ 23 апреля 2020

Вам не понадобится все oop. Хитрость заключается в том, чтобы расширить pair_distance в 3-м измерении, повторяя его m раз (m - это измерение ваших векторов, здесь 3D), а затем разделить два массива по элементам (работает для любых m -мерных векторов , замените 3 на m):

pair_distances = np.repeat(pair_distances[:,:,None], 3, axis=2)
normalized_pair_distance_vectors = np.nan_to_num(pair_distance_vectors/ pair_distances)

Вывод для ваших примеров ввода:

[[[1.         1.         1.        ]
  [0.5        0.5        0.5       ]]

 [[0.33333333 0.33333333 0.33333333]
  [0.25       0.25       0.25      ]]]
...