繁体   English   中英

使用 Eigen 库,我可以获得只有一个“近似”矩阵的 kernel 吗?

[英]Using the Eigen library, can I get the kernel of a matrix which only has one "approximately"?

我需要找到一个 3*3 矩阵的 kernel(又名 null 空间),它的满秩为 3,但非常接近单数,因此是秩 2。这意味着它没有 null 空间,除非你用一些东西寻找它“宽容”。

在 Scilab(它是 Matlab 的免费且功能较少的替代品)中,我可以执行以下操作:

--> Rx_1  = 

  -0.000004    0.0000376  -0.0000261
  -0.0000017  -0.459682    0.84146  
   0.0000458  -0.841457   -0.459684 


--> kernel(Rx_1)  ans  =

    []         <--- no exact null space


--> kernel(Rx_1, 0.0001)  ans  =    <--- this 0.0001 is my tolerance

   1.
   0.0000411        <--- null space basis found with "tolerance".
   0.0000244

但是,当我go到C++时,我不知道如何在Eigen中引入容差:

FullPivLU<MatrixXd> lu(Rx_1);        <--- lu won't take any extra arguments
MatrixXd A_null_space = lu.kernel();

我能做什么?

我对Eigen库不是很熟悉。 但我知道它可用于执行许多分解,还可以用于查找特征空间(考虑到名称,如果没有,那将是令人惊讶的)。 例如使用EigenSolver ,或者可能从任何分解开始。

null 空间也是与特征值 0 相关联的特征空间。如果矩阵值中存在噪声(或只是数值错误),则不会有恰好为 0 的特征值(如您所知,数值矩阵在实践中从来都不是完全奇异的。总会有一些数值错误)

我推测 scilab 中的“公差”是:特征值或类似值的最大值。 阅读之后,我发现 scilab 默认依赖 SVD 分解来提取 kernel 之类的东西。因此, tol可能是奇异值的最大值(即 Mᵀ·M 的特征值的平方根)。 Null 空间是与“足够空”的奇异值匹配的 V 线的跨度。

所以,也许你应该对Eigen做同样的事情:执行 SVD。 然后是 V 的 select 行(或列,具体取决于库。有些返回 V,有些返回 Vᵀ)匹配对你来说足够小的奇异值。

例如,在 python 中(抱歉,我既没有scilab也没有Eigen 。我知道我回答这个问题很奇怪。但这是更多的线性代数问题,没有其他人回答:D)。

import numpy as np
import scipy

# Same matrix
M=np.array([[-0.000004,   0.0000376, -0.0000261],
            [-0.0000017, -0.459682,   0.84146  ],
            [ 0.0000458, -0.841457,  -0.459684 ]])

scipy.linalg.null_space(M)
# returns array([], shape=(3, 0), dtype=float64)
# Same problem: no null space

np.linalg.eig(M)
# Returns
# (array([-3.99909409e-06+0.j       , 
#         -4.59683000e-01+0.8414585j,
#         -4.59683000e-01-0.8414585j]),
# array([[ 9.99999999e-01+0.00000000e+00j, -3.01853493e-05-1.51067336e-05j, -3.01853493e-05+1.51067336e-05j],
#        [ 4.10693606e-05+0.00000000e+00j,  7.07107411e-01+0.00000000e+00j,  7.07107411e-01-0.00000000e+00j],
#        [ 2.44559237e-05+0.00000000e+00j, -8.40775572e-07+7.07106151e-01j, -8.40775572e-07-7.07106151e-01j]]))

# No 0 eigen value. But you may think that the first one is small enough.
# Therefore, the associated eigen vectors are a basis for a "almost null space"
# So here, "almost null-space" is the span of first column
# That is [1, 4.11×10⁻⁵, 2.45×10⁻⁵]

# Using SVD
np.linalg.svd(M)
# Returns
#(array([[-2.54689055e-05,  4.03741349e-05, -9.99999999e-01],
#        [ 8.55645091e-01, -5.17563016e-01, -4.26885031e-05],
#        [-5.17563018e-01, -8.55645091e-01, -2.13641668e-05]]),
# array([9.58834879e-01, 9.58831275e-01, 3.99909409e-06]), 
# array([[-2.62390131e-05,  4.39933685e-02,  9.99031823e-01],
#        [-3.99536921e-05,  9.99031822e-01, -4.39933695e-02],
#        [ 9.99999999e-01,  4.10693525e-05,  2.44559116e-05]]))

# No null singular value. But the last one is "null enough"
# So the "almost null space" is the span of the last row of V
# [ 9.99999999e-01,  4.10693525e-05,  2.44559116e-05]

编辑

刚才在文档中看到python scipy的null_space也有一个tolerance参数。

所以scipy.linalg.null_space(M, 0.0001)返回

array([[9.99999999e-01],
       [4.10693525e-05],
       [2.44559116e-05]])

但是,更重要的是,我在null_space文档中读到它

使用 SVD 构造 A 的 null 空间的正交基

关于这种公差:

相对条件数。 小于 rcond * max(s) 的奇异值 s 被视为零。

所以,这是官方的。 至少对于 python scipy,一个 null 空间是匹配足够小的奇异值的 Vᵀ 行的跨度。 与我之前的猜测唯一不同的是,它不是sᵢ<tol ,而是sᵢ<tol*max(s)来表征什么是“足够小”。

所以,回到你的Eigen库。 我会做同样的事情。 计算 M 的 SVD 分解。然后 select V 行(或列,但如果文档没有说明是哪一个,请使用您的示例,看看它是在行还是列中找到您的 [1, 4.1×10⁻⁵, 2.4×10⁻⁵]) 匹配小于tol × bigger singular value

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM