检查矩阵是否为SPD

时间:2013-05-22 06:44:22

标签: matlab linear-algebra

在Matlab中检查矩阵是否为对称正定的最快(运行时)方法是什么?我已经为大量稀疏矩阵运行了这个测试,其大小(维度)从10000到100000不等?

编辑:

Cholesky为我的目的付出了昂贵的代价。我首先需要进行脏检查,如果它表明矩阵可能是spd那么我可能会使用CHOL更可靠地检查那些矩阵

5 个答案:

答案 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,而有些不是(搅动nd和{{1} })似乎表明它可以识别许多但不是全部SPD矩阵(如预期的那样),但对于“大”而言,与c(及其底层的Cholesky)相比,非常便宜 n 。对于您的特定矩阵,它可能会起作用,也可能不会起作用。我想是YMMV。

显然,我还没有弄清所有细节,但是我敢肯定,你知道这个主意。