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