Умножение векторов

Пусть даны два вектора \(x, y \in \mathbb{R}^3\). Для них определенны три вида умножения:

  • Векторное произведение:

\[\begin{split} x \times y = \begin{pmatrix} x_1 \\ x_2 \\ x_3 \end{pmatrix} \times \begin{pmatrix} y_1 \\ y_2 \\ y_3 \end{pmatrix} = \begin{pmatrix} x_2 * y_3 - x_3 * y_2 \\ x_3 * y_1 - x_1 * y_3 \\ x_1 * y_2 - x_2 * y_1 \end{pmatrix}. \end{split}\]
  • Скалярное умножение:

\[ x \cdot y = \sum_{i=1}^n x_i y_i. \]
  • Внешнее произведение:

\[\begin{split} x \wedge y = \begin{pmatrix} x_1 y_1 & x_1 y_2 & x_1 y_3 \\ x_2 y_1 & x_2 y_2 & x_2 y_3 \\ x_3 y_1 & x_3 y_2 & x_3 y_3 \\ \end{pmatrix}. \end{split}\]

Note

Векторное произведение определенно для векторов из трехмерного пространства, скалярное произведение можно определить для двух векторов из одного пространства любой размерности, а внешнее произведение можно определить для любых двух векторов, необязательно одной длинны.

Вычисление каждого их этих произведений векторизуется.

1. Векторное произведение

За векторное произведение отвечает функция np.cross.

import numpy as np

x = [1, 2, 3]
y = [4, 5, 6]
np.cross(x, y)
array([-3,  6, -3])

Если необходимо произвести несколько векторных умножений, то лучше избегать циклы и использовать векторизацию.

x = [[1, 2, 3], [4, 5, 6]]
y = [[4, 5, 6], [1, 2, 3]]
np.cross(x, y)
array([[-3,  6, -3],
       [ 3, -6,  3]])

Можно прибегать и к бродкастингу. Например, если необходимо векторно умножить один вектор на несколько других.

x = [1, 2, 3]
y = [[4, 5, 6], [1, 2, 3]]
np.cross(x, y)
array([[-3,  6, -3],
       [ 0,  0,  0]])

2. Скалярное произведение.

Скалярное произведение можно сделать минимум двумя способами.

Первый из них — применить функцию np.dot. Если оба аргумента одномерные массивы (одинаковой), то результат — скалярное произведение.

x = np.array([1, 2])
y = np.array([3, 4])
np.dot(x, y)
11

Если хотя бы один из них двухмерный, то выполняется матричное умножение. В этом и заключается второй подход. Матричное умножение вектора строки на вектор столбец эквивалентно скалярному произведению

print(x @ y[:, np.newaxis])
[11]

Чтобы векторизовать вычисление многих скалярных произведений удобно записать эти вектора в матрицы. Предположим, мы хотим скалярно умножить вектора \( \vec{a} = \begin{pmatrix} a_1 & a_2 \\ \end{pmatrix} \) и \( \vec{b} = \begin{pmatrix} b_1 & b_2 \\ \end{pmatrix} \) на вектора \( \vec{c} = \begin{pmatrix} c_1 & c_2 \\ \end{pmatrix} \) и \( \vec{d} = \begin{pmatrix} d_1 & d_2 \\ \end{pmatrix}. \) Для этого умножим матрицы \(L\) и \(R\), где

\[\begin{split} L = \begin{pmatrix} a_1 & a_2 \\ b_1 & b_2 \end{pmatrix} \end{split}\]

и

\[\begin{split} R = \begin{pmatrix} c_1 & d_1 \\ c_2 & d_2 \end{pmatrix}. \end{split}\]

Элементами результирующей матрицы будут искомые скалярные произведения.

a = np.array([1, 2])
b = np.array([-1, -2])
c = np.array([3, 4])
d = np.array([-3, -4])

L = np.vstack([a, b])
print(L)
R = np.vstack([c, d]).T
print(R)
print(L @ R)
[[ 1  2]
 [-1 -2]]
[[ 3 -3]
 [ 4 -4]]
[[ 11 -11]
 [-11  11]]
print(np.dot(a, c))
11

3. Внешнее произведение

Внешнее произведение можно посчитать с помощью функции np.outer, используя матричное умножение столбца на строку или используя broadcasting.

print(x, y)
[1 2] [3 4]
np.outer(x, y)
array([[3, 4],
       [6, 8]])
x[:, np.newaxis] * y
array([[3, 4],
       [6, 8]])
x[:, np.newaxis] @ y[ np.newaxis, :] # x и y должны быть матрицами
array([[3, 4],
       [6, 8]])
x[:, np.newaxis]
array([[1],
       [2]])