умножение матриц по строкам с использованием numpy - PullRequest
0 голосов
/ 16 июня 2020

Я хочу реализовать "построчное" матричное умножение.

Говоря более конкретно, я хочу построить набор стрелок, направление которых варьируется от (-pi, pi). Я реализовал это в следующем коде.

scan_phi = np.linspace(-np.pi*0.5, np.pi*0.5, 450)

points = np.ones((450, 2), dtype=np.float)
points[..., 0] = 0.0

n_pts = len(points)

sin = np.sin(scan_phi)
cos = np.cos(scan_phi)

rot = np.append(np.expand_dims(np.vstack([cos, -sin]).T, axis=1), 
                np.expand_dims(np.vstack([sin, cos]).T, axis=1), 
                axis=1)

points_rot = []

for idx, p in enumerate(points):
    points_rot.append(np.matmul(rot[idx], p.T))

points_rot = np.array(points_rot)
sample = points_rot[::10]

ax = plt.axes()
ax.set_xlim(-2, 2)
ax.set_ylim(-2, 2)

for idx, p in enumerate(sample):
    if idx == 0:
        ax.arrow(0, 0, p[0], p[1], head_width=0.05, head_length=0.1, color='red')
    else:
        ax.arrow(0, 0, p[0], p[1], head_width=0.05, head_length=0.1, fc='k', ec='k')

plt.show()

В моем коде "rot" оказывается массивом (450, 2, 2), что означает для каждой стрелки, я создал соответствующую матрицу вращения чтобы повернуть его. У меня есть 450 точек, хранящихся в «точках» (450, 2), которыми я хочу рисовать стрелки. (Здесь все стрелки инициализируются с помощью [0, 1]. Однако он может быть инициализирован с разными значениями, поэтому я хочу иметь 450 отдельных точек вместо простого поворота одной точки на 450 разных углов)

Я использовал for-l oop, т.е. для каждой стрелки я трансформирую ее индивидуально.

points_rot = []

for idx, p in enumerate(points):
    points_rot.append(np.matmul(rot[idx], p.T))

points_rot = np.array(points_rot)

Однако мне интересно, есть ли какой-нибудь более приятный и простой способ сделать это полностью через numpy, например, некоторые операции, которые могут выполнять матричное умножение по строкам. Любая идея буду благодарен, заранее спасибо!

1 Ответ

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

Это хороший вариант использования np.einsum:

aa = np.random.normal(size=(450, 2, 2))
bb = np.random.normal(size=(450, 2))

cc = np.einsum('ijk,ik->ij', aa, bb)

Таким образом, каждая строка cc является продуктом соответствующих строк aa и bb:

np.allclose(aa[3].dot(bb[3]), cc)  # returns True

Пояснение: нотация Эйнштейна ijk,ik->ij говорит:

cc[i,j] = sum(aa[i,j,k] * bb[i,k] for k in range(2))

То есть, все переменные, которые не появляются в правой части, суммируются.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...