Есть ли метод, который я могу вызвать для создания случайной ортонормированной матрицы в python? Возможно использование numpy? Или существует способ создания ортонормированной матрицы с использованием нескольких методов numpy? Спасибо.
Как создать произвольную ортонормированную матрицу в python numpy
Ответ 1
Это метод rvs
извлеченный из rvs
https://github.com/scipy/scipy/pull/5622//, с минимальными изменениями - достаточный для запуска в качестве отдельной функции numpy.
import numpy as np
def rvs(dim=3):
random_state = np.random
H = np.eye(dim)
D = np.ones((dim,))
for n in range(1, dim):
x = random_state.normal(size=(dim-n+1,))
D[n-1] = np.sign(x[0])
x[0] -= D[n-1]*np.sqrt((x*x).sum())
# Householder transformation
Hx = (np.eye(dim-n+1) - 2.*np.outer(x, x)/(x*x).sum())
mat = np.eye(dim)
mat[n-1:, n-1:] = Hx
H = np.dot(H, mat)
# Fix the last sign such that the determinant is 1
D[-1] = (-1)**(1-(dim % 2))*D.prod()
# Equivalent to np.dot(np.diag(D), H) but faster, apparently
H = (D*H.T).T
return H
Это соответствует тесту Уоррена, fooobar.com/questions/558170/...
Ответ 2
Версия 0.18 scipy имеет scipy.stats.ortho_group
и scipy.stats.special_ortho_group
. Запрос на растяжение, где он был добавлен, https://github.com/scipy/scipy/pull/5622
Например,
In [24]: from scipy.stats import ortho_group # Requires version 0.18 of scipy
In [25]: m = ortho_group.rvs(dim=3)
In [26]: m
Out[26]:
array([[-0.23939017, 0.58743526, -0.77305379],
[ 0.81921268, -0.30515101, -0.48556508],
[-0.52113619, -0.74953498, -0.40818426]])
In [27]: np.set_printoptions(suppress=True)
In [28]: m.dot(m.T)
Out[28]:
array([[ 1., 0., -0.],
[ 0., 1., 0.],
[-0., 0., 1.]])
Ответ 3
Вы можете получить случайную nxn
ортогональную матрицу Q
(равномерно распределенную по многообразию nxn
ортогональных матриц), выполнив QR
факторизацию матрицы nxn
с элементами, имеющими гауссовские случайные величины со средним значением 0
и дисперсией 1
. Вот пример:
import numpy as np
from scipy.linalg import qr
n = 3
H = np.random.randn(n, n)
Q, R = qr(H)
print (Q.dot(Q.T))
[[ 1.00000000e+00 -2.77555756e-17 2.49800181e-16] [ -2.77555756e-17 1.00000000e+00 -1.38777878e-17] [ 2.49800181e-16 -1.38777878e-17 1.00000000e+00]]
РЕДАКТИРОВАТЬ: (Возвращаясь к этому ответу после комментария @g g.) Приведенное выше утверждение о QR-разложении гауссовой матрицы, обеспечивающей равномерно распределенную (по так называемому многообразию Штифеля) ортогональную матрицу, предложено в теоремах 2.3.18- 19 из этой ссылки. Отметим, что утверждение результата предполагает "QR-подобное" разложение, однако с треугольной матрицей R
имеющей положительные элементы.
По-видимому, функция qr
функции scipy (numpy) не гарантирует положительных диагональных элементов для R
и соответствующий Q
фактически не является равномерно распределенным. Это было отмечено в этой монографии, гл. 4.6 (обсуждение относится к MATLAB, но я полагаю, что и MATLAB, и scipy используют одни и те же процедуры LAPACK). Предполагается, что матрица Q
предоставленная qr
, модифицируется путем умножения ее на случайную унитарную диагональную матрицу.
Ниже я воспроизвожу эксперимент в приведенной выше ссылке, построив график эмпирического распределения (гистограммы) фаз собственных значений "прямой" Q
матрицы, предоставленной qr
, а также "модифицированной" версии, где видно, что модифицированная версия делает действительно имеют однородную фазу собственных значений, как и следовало ожидать от равномерно распределенной ортогональной матрицы.
from scipy.linalg import qr, eigvals
from seaborn import distplot
n = 50
repeats = 10000
angles = []
angles_modified = []
for rp in range(repeats):
H = np.random.randn(n, n)
Q, R = qr(H)
angles.append(np.angle(eigvals(Q)))
Q_modified = Q @ np.diag(np.exp(1j * np.pi * 2 * np.random.rand(n)))
angles_modified.append(np.angle(eigvals(Q_modified)))
fig, ax = plt.subplots(1,2, figsize = (10,3))
distplot(np.asarray(angles).flatten(),kde = False, hist_kws=dict(edgecolor="k", linewidth=2), ax= ax[0])
ax[0].set(xlabel='phase', title='direct')
distplot(np.asarray(angles_modified).flatten(),kde = False, hist_kws=dict(edgecolor="k", linewidth=2), ax= ax[1])
ax[1].set(xlabel='phase', title='modified');
Ответ 4
если вы хотите, чтобы квадратная матрица не имела ортонормированных векторов столбцов, вы могли бы создать квадрат с любым из указанных методов и удалить некоторые столбцы.
Ответ 5
from scipy.stats import special_ortho_group
num_dim=3
x = special_ortho_group.rvs(num_dim)
Ответ 6
Простой способ создания ортогональной матрицы любой формы (nxm
):
import numpy as np
n, m = 3, 5
H = np.random.rand(n, m)
u, s, vh = np.linalg.svd(H, full_matrices=False)
mat = u @ vh
print(mat @ mat.T) # -> eye(n)
Обратите внимание, что если n > m
, получится mat.T @mat = eye(m)
.