В дополнение к ответу @vsoftco мы также проверим симметрию матрицы, поскольку для определения PD/PSD требуется симметричная матрица.
Eigen::LLT<Eigen::MatrixXd> A_llt(A);
if (!A.isApprox(A.transpose()) || A_llt.info() == Eigen::NumericalIssue) {
throw std::runtime_error("Possibly non semi-positive definitie matrix!");
}
Эта проверка важна, т.е. некоторые решатели Eigen (например, 1LDLT.html" rel="noreferrer">LTDT) требуют ввода матрицы PSD (или NSD). На самом деле существует несимметричная и, следовательно, не-PSD матрица A
, которая проходит тест A_llt.info() != Eigen::NumericalIssue
. Рассмотрим следующий пример (числа взяты из Jiuzhang Suanshu, глава 8, задача 1):
Eigen::Matrix3d A;
Eigen::Vector3d b;
Eigen::Vector3d x;
// A is full rank and all its eigen values >= 0
// However A is not symmetric, thus not PSD
A << 3, 2, 1,
2, 3, 1,
1, 2, 3;
b << 39, 34, 26;
// This alone doesn't check matrix symmetry, so can't guarantee PSD
Eigen::LLT<Eigen::Matrix3d> A_llt(A);
std::cout << (A_llt.info() == Eigen::NumericalIssue)
<< std::endl; // false, no issue detected
// ldlt solver requires PSD, wrong answer
x = A.ldlt().solve(b);
std::cout << x << std::endl; // Wrong solution [10.625, 1.5, 4.125]
std::cout << b.isApprox(A * x) << std::endl; // false
// ColPivHouseholderQR doesn't assume PSD, right answer
x = A.colPivHouseholderQr().solve(b);
std::cout << x << std::endl; // Correct solution [9.25, 4.25, 2.75]
std::cout << b.isApprox(A * x) << std::endl; // true
Примечания: чтобы быть более точным, можно применить определение PSD проверив, что A
является симметричным, а все собственные значения A >= 0. Но, как уже упоминалось в вопросе, это может быть дорогостоящим в вычислительном отношении.
person
Yixing
schedule
07.02.2019
NumericalIssue
, если матрица отрицательна, см. eigen. tuxfamily.org/dox/classEigenNumericalIssue
1LLT.html - person vsoftco   schedule 05.02.2016error: 'class Eigen::LDLT has no member named 'info'
- person dim_tz   schedule 05.02.2016