[英]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.