2014-11-15 1 views

답변

0

트릭을 수행하는 파이썬 코드가 있습니다. 기본적으로 복잡한 부분을 추출한 다음 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