代码之家  ›  专栏  ›  技术社区  ›  Rushabh Mehta

用SVD计算SPINV

  •  3
  • Rushabh Mehta  · 技术社区  · 8 年前

    背景

    我正在做一个项目,涉及求解大型不确定方程组。

    我目前的算法计算SVD( numpy.linalg.svd )对于表示给定系统的矩阵,然后利用其结果计算出该矩阵的摩尔-彭罗斯伪逆和右零空间。我使用nullspace查找具有唯一解的所有变量,并使用伪逆函数查找其值。

    但是,MPP(moore-penrose-pseudo-inverse)非常密集,有点太大,我的服务器无法处理。

    问题

    我发现了以下 paper 它详细描述了一个稀疏的伪逆函数,它保持了MPP的大部分基本特性。这显然对我很感兴趣,但我根本没有数学背景来理解他是如何计算伪逆的。可以用SVD计算吗?如果没有,最好的方法是什么?

    细节

    这些是我认为相关的文章,但我还没有过时到可以理解的程度。

    • spinv(a)=arg min b表示b的入口L1范数

    • 这通常是一个不可追踪的问题,所以我们使用标准线性松弛和l1范数

    • sspinv(a)=···[自旋v(a)··,其中·(u)=u1 u|

    编辑

    查找我的代码和有关实际实现的更多详细信息 here

    1 回复  |  直到 8 年前
        1
  •  1
  •   dhanushka    8 年前

    据我所知,这篇论文是关于稀疏伪逆的:

    上面写着

    我们的目标是最小化spinv(a)中的非零数量。

    这意味着你应该采用l0标准(见大卫多诺霍的定义 here : 非零条目数 这使得问题难以解决。

    spinv(A) = argmin ||B||_0 subject to B.A = I

    因此,他们转向这个问题的凸松弛,这样它就可以用线性规划来解决。

    这通常是一个不可处理的问题,因此我们使用标准 1范数的线性松弛。

    轻松的问题是

    spinv(A) = argmin ||B||_1 subject to B.A = I (6)

    这有时叫做 Basis pursuit 并倾向于产生稀疏的解决方案(参见 凸优化 作者:Boyd和Vandenberghe,第 6.2最小范数问题 )

    所以,解决这个放松的问题。

    线性程序(6)是可分离的,可以通过计算得到。 一次B行

    所以,你可以解决下面的一系列形式的问题,得到解决方案。

    spinv(A)_i = argmin ||B_i||_1 subject to B_i.A = I_i

    哪里 _i 表示矩阵的第i行。

    here 了解如何将这个绝对值问题转换为线性程序。

    在下面的代码中,我将问题稍微更改为 spinv(A)_i = argmin ||B_i||_1 subject to A.B_i = I_i 在哪里? 一世 是矩阵的第i列,所以问题变成 spinv(A) = argmin ||B||_1 subject to A.B = I . 老实说,我不知道这两者是否有区别。我用的是西皮的 linprog 单纯形法。我不知道simplex的内部结构,也不知道它是否使用SVD。

    import numpy as np
    from scipy import optimize
    
    # argmin ||B_i||_1 stubect to A.B_i = I_i, where _i is the ith column
    # let B_i = u_i - v_i where u_i >= 0 and v_i >= 0
    # then ||B_i||_1 = [1' 1'][u_i;v_i] which is the objective function
    # and A.B_i = I_i becomes
    # A.[u_i - v_i] = I_i
    # [A -A][u_i;v_i] = I_i which is the equality constraint
    # and [u_i;v_i] >= 0 the bounds
    # here A is n x m (as opposed to m x n in paper)
    
    A = np.random.randn(4, 6)
    n, m = A.shape
    I = np.eye(n)
    
    Aeq = np.hstack((A, -A))
    # objective
    c = np.ones((2*m))
    # spinv
    B = np.zeros((m, n))
    
    for i in range(n):
        beq = I[:, i]
        result = optimize.linprog(c, A_eq=Aeq, b_eq=beq)
        x = result.x[0:m]-result.x[m:2*m]
        B[:, i] = x
    
    print('spinv(A) = \n' + str(B))
    print('pinv(A) = \n' + str(np.linalg.pinv(A)))
    print('A.B = \n' + str(np.dot(A, B)))
    

    这是一个输出。 spinv(A) 比…更稀疏 pinv(A) .

    spinv(A) = 
    [[ 0.         -0.33361925  0.          0.        ]
     [ 0.04987467  0.          0.12741509  0.02897778]
     [ 0.          0.         -0.52306324  0.        ]
     [ 0.43848257  0.12114828  0.15678815 -0.19302049]
     [-0.16814546  0.02911103 -0.41089271  0.50785258]
     [-0.05696924  0.13391736  0.         -0.43858428]]
    pinv(A) = 
    [[ 0.05626402 -0.1478497   0.19953692 -0.19719524]
     [ 0.04007696 -0.07330993  0.19903311  0.14704798]
     [ 0.01177361 -0.05761487 -0.23074996  0.15597663]
     [ 0.44471989  0.13849828  0.18733242 -0.20824972]
     [-0.1273604   0.15615595 -0.24647117  0.38047901]
     [-0.04638221  0.09879972  0.21951122 -0.33244635]]
    A.B = 
    [[ 1.00000000e+00 -1.82225048e-17  6.73349443e-18 -2.39383542e-17]
     [-5.20584593e-18  1.00000000e+00 -3.70118759e-16 -1.62063433e-15]
     [-8.83342417e-18 -5.80049814e-16  1.00000000e+00  3.56175852e-15]
     [ 2.31629738e-17 -1.13459832e-15 -2.28503999e-16  1.00000000e+00]]
    

    为了进一步稀疏矩阵,我们可以硬应用entrywise 阈值化,从而牺牲了反转特性并计算出 近似稀疏伪逆

    如果不想在稀疏PINv中保留小条目,可以这样删除它们:

    Bt = B.copy()
    Bt[np.abs(Bt) < 0.1] = 0
    print('sspinv_0.1(A) = \n' + str(Bt))
    print('A.Bt = \n' + str(np.dot(A, Bt)))
    

    得到

    sspinv_0.1(A) = 
    [[ 0.         -0.33361925  0.          0.        ]
     [ 0.          0.          0.12741509  0.        ]
     [ 0.          0.         -0.52306324  0.        ]
     [ 0.43848257  0.12114828  0.15678815 -0.19302049]
     [-0.16814546  0.         -0.41089271  0.50785258]
     [ 0.          0.13391736  0.         -0.43858428]]
    A.Bt = 
    [[ 9.22717491e-01  1.17555372e-02  6.73349443e-18 -1.10993934e-03]
     [ 1.24361576e-01  9.41538212e-01 -3.70118759e-16  1.15028494e-02]
     [-8.76662313e-02 -1.36349311e-02  1.00000000e+00 -7.48302663e-02]
     [-1.54387852e-01 -3.27969169e-02 -2.28503999e-16  9.39161039e-01]]
    

    希望我回答了你的问题,并提供了足够的参考,如果你想进一步的细节。如果有任何问题,请告诉我。我不是专家,所以如果你对我的主张有任何疑问的话,你可以随时咨询数学交换专家(当然没有任何代码),请告诉我。

    这是一个有趣的问题。它使我能够重新学习线性代数和一些我知道的优化,所以谢谢你:)