scipy.linalg.

orthogonal_procrustes#

scipy.linalg.orthogonal_procrustes(A, B, check_finite=True)[source]#

Compute the matrix solution of the orthogonal (or unitary) Procrustes problem.

Given matrices A and B of the same shape, find an orthogonal (or unitary in the case of complex input) matrix R that most closely maps A to B using the algorithm given in [1].

Parameters:
A(M, N) array_like

Matrix to be mapped.

B(M, N) array_like

Target matrix.

check_finitebool, optional

Whether to check that the input matrices contain only finite numbers. Disabling may give a performance gain, but may result in problems (crashes, non-termination) if the inputs do contain infinities or NaNs.

Returns:
R(N, N) ndarray

The matrix solution of the orthogonal Procrustes problem. Minimizes the Frobenius norm of (A @ R) - B, subject to R.conj().T @ R = I.

scalefloat

Sum of the singular values of A.conj().T @ B.

Raises:
ValueError

If the input array shapes don’t match or if check_finite is True and the arrays contain Inf or NaN.

Notes

Note that unlike higher level Procrustes analyses of spatial data, this function only uses orthogonal transformations like rotations and reflections, and it does not use scaling or translation.

Added in version 0.15.0.

References

[1]

Peter H. Schonemann, “A generalized solution of the orthogonal Procrustes problem”, Psychometrica – Vol. 31, No. 1, March, 1966. DOI:10.1007/BF02289451

Examples

>>> import numpy as np
>>> from scipy.linalg import orthogonal_procrustes
>>> A = np.array([[ 2,  0,  1], [-2,  0,  0]])

Flip the order of columns and check for the anti-diagonal mapping

>>> R, sca = orthogonal_procrustes(A, np.fliplr(A))
>>> R
array([[-5.34384992e-17,  0.00000000e+00,  1.00000000e+00],
       [ 0.00000000e+00,  1.00000000e+00,  0.00000000e+00],
       [ 1.00000000e+00,  0.00000000e+00, -7.85941422e-17]])
>>> sca
9.0

As an example of the unitary Procrustes problem, generate a random complex matrix A, a random unitary matrix Q, and their product B.

>>> shape = (4, 4)
>>> rng = np.random.default_rng()
>>> A = rng.random(shape) + rng.random(shape)*1j
>>> Q = rng.random(shape) + rng.random(shape)*1j
>>> Q, _ = np.linalg.qr(Q)
>>> B = A @ Q

orthogonal_procrustes recovers the unitary matrix Q from A and B.

>>> R, _ = orthogonal_procrustes(A, B)
>>> np.allclose(R, Q)
True