복잡한 값을 포함 할 수있는 2x2 행렬의 singular value decomposition을 계산하는 방법을 보여주는 예제 코드를 찾고있었습니다.복잡한 2x2 행렬의 특이 값 분해
예를 들어, 사용자 입력 행렬을 "복구"하여 단일화하는 것이 유용합니다. u, s, v = svd(m)
을 입력 한 다음 제품에서 s
부분을 생략하십시오 : repaired = u * v
.
복잡한 값을 포함 할 수있는 2x2 행렬의 singular value decomposition을 계산하는 방법을 보여주는 예제 코드를 찾고있었습니다.복잡한 2x2 행렬의 특이 값 분해
예를 들어, 사용자 입력 행렬을 "복구"하여 단일화하는 것이 유용합니다. u, s, v = svd(m)
을 입력 한 다음 제품에서 s
부분을 생략하십시오 : repaired = u * v
.
트릭을 수행하는 파이썬 코드가 있습니다. 기본적으로 복잡한 부분을 추출한 다음 the solution from this answer for real 2x2 matrices에 위임합니다.
저는 파이썬으로 numpy를 사용하여 코드를 작성했습니다. numpy가 있으면 np.linalg.svd
을 사용해야하기 때문에 이것은 약간 아이러니합니다. 분명히 이것은 핀치 (pinch)에서 다른 언어로 배우거나 번역하기에 적합한 예제 코드로 의도 된 것입니다.
저는 또한 수치 안정성에 대한 전문가가 아니므로 ... 구매자가주의하십시오.
import numpy as np
import math
# Note: in practice in python just use np.linalg.svd instead
def singular_value_decomposition_complex_2x2(m):
"""
Returns a singular value decomposition of the given 2x2 complex numpy
matrix.
:param m: A 2x2 numpy matrix with complex values.
:returns: A tuple (U, S, V) where U*S*V ~= m, where U and V are complex
2x2 unitary matrices, and where S is a 2x2 diagonal matrix with
non-negative real values.
"""
# Make top row non-imaginary and non-negative by column phasing.
# m2 = m p = | > > |
# | ?+?i ?+?i |
p = phase_cancel_matrix(m[0, 0], m[0, 1])
m2 = m * p
# Cancel top-right value by rotation.
# m3 = m p r = | ?+?i 0 |
# | ?+?i ?+?i |
r = rotation_matrix(math.atan2(m2[0, 1].real, m2[0, 0].real))
m3 = m2 * r
# Make bottom row non-imaginary and non-negative by column phasing.
# m4 = m p r q = | ?+?i 0 |
# | > > |
q = phase_cancel_matrix(m3[1, 0], m3[1, 1])
m4 = m3 * q
# Cancel imaginary part of top left value by row phasing.
# m5 = t m p r q = | > 0 |
# | > > |
t = phase_cancel_matrix(m4[0, 0], 1)
m5 = t * m4
# All values are now real (also the top-right is zero), so delegate to a
# singular value decomposition that works for real matrices.
# t m p r q = u s v
u, s, v = singular_value_decomposition_real_2x2(np.real(m5))
# m = (t* u) s (v q* r* p*)
return adjoint(t) * u, s, v * adjoint(q) * adjoint(r) * adjoint(p)
def singular_value_decomposition_real_2x2(m):
"""
Returns a singular value decomposition of the given 2x2 real numpy matrix.
:param m: A 2x2 numpy matrix with real values.
:returns: A tuple (U, S, V) where U*S*V ~= m, where U and V are 2x2
rotation matrices, and where S is a 2x2 diagonal matrix with
non-negative real values.
"""
a = m[0, 0]
b = m[0, 1]
c = m[1, 0]
d = m[1, 1]
t = a + d
x = b + c
y = b - c
z = a - d
theta_0 = math.atan2(x, t)/2.0
theta_d = math.atan2(y, z)/2.0
s_0 = math.sqrt(t**2 + x**2)/2.0
s_d = math.sqrt(z**2 + y**2)/2.0
return \
rotation_matrix(theta_0 - theta_d), \
np.mat([[s_0 + s_d, 0], [0, s_0 - s_d]]), \
rotation_matrix(theta_0 + theta_d)
def adjoint(m):
"""
Returns the adjoint, i.e. the conjugate transpose, of the given matrix.
When the matrix is unitary, the adjoint is also its inverse.
:param m: A numpy matrix to transpose and conjugate.
:return: A numpy matrix.
"""
return m.conjugate().transpose()
def rotation_matrix(theta):
"""
Returns a 2x2 unitary matrix corresponding to a 2d rotation by the given angle.
:param theta: The angle, in radians, that the matrix should rotate by.
:return: A 2x2 orthogonal matrix.
"""
c, s = math.cos(theta), math.sin(theta)
return np.mat([[c, -s],
[s, c]])
def phase_cancel_complex(c):
"""
Returns a unit complex number p that cancels the phase of the given complex
number c. That is, c * p will be real and non-negative (approximately).
:param c: A complex number.
:return: A complex number on the complex unit circle.
"""
m = abs(c)
# For small values, where the division is in danger of exploding small
# errors, use trig functions instead.
if m < 0.0001:
theta = math.atan2(c.imag, c.real)
return math.cos(theta) - math.sin(theta) * 1j
return (c/float(m)).conjugate()
def phase_cancel_matrix(p, q):
"""
Returns a 2x2 unitary matrix M such that M cancels out the phases in the
column {{p}, {q}} so that the result of M * {{p}, {q}} should be a vector
with non-negative real values.
:param p: A complex number.
:param q: A complex number.
:return: A 2x2 diagonal unitary matrix.
"""
return np.mat([[phase_cancel_complex(p), 0],
[0, phase_cancel_complex(q)]])
는 I는 [-10, 10] + [-10, 10] I, 및 (분해 요소 오른쪽 특성 것으로 확인 즉 단일의 랜덤 값으로 채워 행렬와를 퍼징함으로써 상기 코드를 테스트 , 대각선, 실수), 그리고 그들의 제품이 (대략) 입력과 동일하다는 것을 나타냅니다. 다음 출력
m = np.mat([[5, 10], [1j, -1]])
u, s, v = singular_value_decomposition_complex_2x2(m)
np.set_printoptions(precision=5, suppress=True)
print "M:\n", m
print "U*S*V:\n", u*s*v
print "U:\n", u
print "S:\n", s
print "V:\n", v
print "M ~= U*S*V:", np.all(np.abs(m - u*s*v) < 0.1**14)
:
그러나 여기 간단한 연기 테스트입니다. U와 V는 다를 수 있지만 (물론 다르지만) 인자 화 된 S가 svd from wolfram alpha과 일치하는지 확인할 수 있습니다.
M:
[[ 5.+0.j 10.+0.j]
[ 0.+1.j -1.+0.j]]
U*S*V:
[[ 5.+0.j 10.+0.j]
[ 0.+1.j -1.-0.j]]
U:
[[-0.89081-0.44541j 0.08031+0.04016j]
[ 0.08979+0.j 0.99596+0.j ]]
S:
[[ 11.22533 0. ]
[ 0. 0.99599]]
V:
[[-0.39679+0.20639j -0.80157+0.39679j]
[ 0.40319+0.79837j -0.19359-0.40319j]]
M ~= U*S*V: True