在Matlab中检查矩阵是否为对称正定的最快(运行时)方法是什么?我已经为大量稀疏矩阵运行了这个测试,其大小(维度)从10000到100000不等?
编辑:
Cholesky为我的目的付出了昂贵的代价。我首先需要进行脏检查,如果它表明矩阵可能是spd那么我可能会使用CHOL更可靠地检查那些矩阵
答案 0 :(得分:3)
如上所述here,您可以使用chol
函数检查矩阵是否为PD。
CHOL函数提供可选的第二个输出参数“p” 如果发现矩阵为正定,则为零。 CHOL 如果只提供单个函数,函数将返回错误 输出参数,并且还给出了一个非正数的矩阵 定。注意:CHOL期望其输入矩阵是对称的且仅对称 看着矩阵的上三角部分。
对于对称性,您可以使用以下函数:
issym = @(m) isequal(tril(x), triu(x)');
答案 1 :(得分:2)
我认为这是一个非常重要的问题。如果矩阵不是正定的,Cholesky算法将失败,因此最好自己实现,这也有一个优点,即当算法失败时,由于输入不是正定的,人们可以控制该做什么。我使用C#而不是Matlab进行数学编程,而我的Cholesky实现只是少数几行,所以并不困难。如果你使用其他人的算法,那么根据它的实现方式,如果你输入非对称矩阵,你可能会得到误导结果,因为有些实现假设矩阵是对称的。我能想到的唯一快速预测试是检查the matrix trace,如果矩阵是SPD,这将是正数。
答案 2 :(得分:1)
我想你可能会看一下矩阵的特征值,并检查它们是否都是不同的和真正有价值的。
因此,您可以考虑按以下方式调用eig
函数:
[V,D] = eig(A)
我希望这会有所帮助
答案 3 :(得分:0)
关于上述跟踪测试: 假设矩阵A为:
//data is my double[,,] of size [160, 304, 304]
//setup MatLab code's 1:y and 1:x
int xx = data.GetLength(0);
int yy = data.GetLength(1);
double[] x = Enumerable.Range(0, xx).Select(num => (double)num).ToArray();
double[] y = Enumerable.Range(0, yy).Select(num => (double)num).ToArray();
//use Accord.Math.Matrix.MeshGrid similarly to matlab's meshgrid
var xy = Accord.Math.Matrix.MeshGrid(y, x);
//split results from tuple
var x1 = xy.Item1;
var y1 = xy.Item2;
//same thing, only LineSpace is a method I made to imitate MatLab's linspace
var xy2 = Accord.Math.Matrix.MeshGrid(y, LineSpace(1, xx, 640).ToArray());
var x2 = xy2.Item1;
var y2 = xy2.Item2;
//this is all to imitate MatLab's zeros and populate a multidimensional double array with all zeros
var interpData = new double[xx * 4, yy, data.GetLength(2)];
for (int i = 0; i < interpData.GetLength(0); i++)
for (int j = 0; j < interpData.GetLength(1); j++)
for (int k = 0; k < interpData.GetLength(2); k++)
interpData[i, j, k] = 0d;
for(int bscan = 0; bscan < data.GetLength(2); bscan++)
{
//slim down data to a dataBscan which is just the first two dimensions
float[,] dataBscan = new float[data.GetLength(0), data.GetLength(1)];
for (int i = 0; i < data.GetLength(0); i++)
for (int j = 0; j < data.GetLength(1); j++)
dataBscan[i,j] = data[i, j, bscan];
for (int i = 0; i < interpData.GetLength(0); i++)
for(int j = 0; j < interpData.GetLength(1); j++)
{
//interpData[i,j,bscan] = ***hopefully*** interp2(x1, y1, dataBscan, x2, y2);
}
}
然后
interp2
但是A的特征值是eig(A)
A =
1.0000 1.6000
1.6000 1.0000
因此,特征值并非全部为正。 因此,此矩阵不是SPD,而是其迹线> 0。 根据这个反例,我怀疑跟踪测试不是结论性的。
答案 4 :(得分:0)
通过使用用于估计特征值的Gershgorin's Theorem,从考虑中消除一些矩阵,您也许可以稍微简化一下领域。
结果是,如果将每一行(除对角线上的元素)的绝对值求和, k ,则得到半径, r k 。对应的特征值必须位于对角线 a kk 上该值的半径之内。因此,如果对所有 k 使用 a kk > r k ,则您的矩阵为PD。如果 a kk <= r k 对于某些 k ,您的矩阵可能仍然是PD,因为这意味着一个或多个Gershgorin圆盘跨在虚轴上(或为零),并且实际特征值可能在任一侧。
假设issymmetric(A)
成功,则类似:
r = sum(abs(A),2)-diag(A);
if length(find(r>diag(A))) == 0,
% No circles cross the origin: A is PD
else
% A might still be PD: do some other test
end
使用矩阵M=sprandsym(n,n,d)+c*speye(n,n)
对此进行快速的肮脏测试,其中一些是PD,而有些不是(搅动n
,d
和{{1} })似乎表明它可以识别许多但不是全部SPD矩阵(如预期的那样),但对于“大”而言,与c
(及其底层的Cholesky)相比,非常便宜 n 。对于您的特定矩阵,它可能会起作用,也可能不会起作用。我想是YMMV。
显然,我还没有弄清所有细节,但是我敢肯定,你知道这个主意。