牛客题解 | 2x2矩阵的奇异值分解(SVD)_使用雅可比方法近似2x2矩阵的奇异值分解
题目
题目链接
2x2矩阵的奇异值分解(SVD)是一种常用的矩阵分解方法,用于将矩阵分解为两个正交矩阵和一个对角矩阵。
本题使用了一种几何方法,但基础原理是Jacobi方法,具体公式如下:
设矩阵A为:
A = [ a b c d ] A = \\begin{bmatrix} a & b \\\\ c & d \\end{bmatrix} A=[acbd]
Jacobi方法的步骤如下:
- 计算矩阵A的特征值和特征向量。
- 通过旋转矩阵将A对角化,得到奇异值。
- 最终的分解形式为:
A = U Σ V T A = U \\Sigma V^TA=UΣVT
其中, U U U和 V V V为正交矩阵, Σ \\Sigma Σ为对角矩阵,包含奇异值。
而本题利用几何方法简化了旋转矩阵的计算,具体公式如下:
U = [ − c 1 − s 1 − s 1 c 1 ] U = \\begin{bmatrix} -c1 & -s1 \\\\ -s1 & c1 \\end{bmatrix}U=[−c1−s1−s1c1]
s = [ ( h 1 + h 2 ) / 2.0 a b s ( h 1 − h 2 ) / 2.0 ] s = \\begin{bmatrix} (h1 + h2) / 2.0 \\\\ abs(h1 - h2) / 2.0 \\end{bmatrix}s=[(h1+h2)/2.0abs(h1−h2)/2.0]
标准代码如下
def svd_2x2(A: np.ndarray) -> tuple: y1, x1 = (A[1, 0] + A[0, 1]), (A[0, 0] - A[1, 1]) y2, x2 = (A[1, 0] - A[0, 1]), (A[0, 0] + A[1, 1]) h1 = np.sqrt(y1**2 + x1**2) h2 = np.sqrt(y2**2 + x2**2) t1 = x1 / h1 t2 = x2 / h2 cc = np.sqrt((1.0 + t1) * (1.0 + t2)) ss = np.sqrt((1.0 - t1) * (1.0 - t2)) cs = np.sqrt((1.0 + t1) * (1.0 - t2)) sc = np.sqrt((1.0 - t1) * (1.0 + t2)) c1, s1 = (cc - ss) / 2.0, (sc + cs) / 2.0 U = np.array([[-c1, -s1], [-s1, c1]]) s = np.array([(h1 + h2) / 2.0, abs(h1 - h2) / 2.0]) V = np.diag(1.0 / s) @ U.T @ A return U, s, V
本题也可以使用numpy库的linalg.svd函数实现,这里给出具体实现:
def svd_2x2(A: np.ndarray) -> tuple: U, s, V = np.linalg.svd(A) return U, s, V