Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 1 | // This file is part of Eigen, a lightweight C++ template library |
| 2 | // for linear algebra. |
| 3 | // |
| 4 | // Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr> |
| 5 | // |
| 6 | // This Source Code Form is subject to the terms of the Mozilla |
| 7 | // Public License v. 2.0. If a copy of the MPL was not distributed |
| 8 | // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. |
| 9 | |
| 10 | #ifndef EIGEN_NO_ASSERTION_CHECKING |
| 11 | #define EIGEN_NO_ASSERTION_CHECKING |
| 12 | #endif |
| 13 | |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 14 | #define TEST_ENABLE_TEMPORARY_TRACKING |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 15 | |
| 16 | #include "main.h" |
| 17 | #include <Eigen/Cholesky> |
| 18 | #include <Eigen/QR> |
| 19 | |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 20 | template<typename MatrixType, int UpLo> |
| 21 | typename MatrixType::RealScalar matrix_l1_norm(const MatrixType& m) { |
| 22 | if(m.cols()==0) return typename MatrixType::RealScalar(0); |
| 23 | MatrixType symm = m.template selfadjointView<UpLo>(); |
| 24 | return symm.cwiseAbs().colwise().sum().maxCoeff(); |
| 25 | } |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 26 | |
| 27 | template<typename MatrixType,template <typename,int> class CholType> void test_chol_update(const MatrixType& symm) |
| 28 | { |
| 29 | typedef typename MatrixType::Scalar Scalar; |
| 30 | typedef typename MatrixType::RealScalar RealScalar; |
| 31 | typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType; |
| 32 | |
| 33 | MatrixType symmLo = symm.template triangularView<Lower>(); |
| 34 | MatrixType symmUp = symm.template triangularView<Upper>(); |
| 35 | MatrixType symmCpy = symm; |
| 36 | |
| 37 | CholType<MatrixType,Lower> chollo(symmLo); |
| 38 | CholType<MatrixType,Upper> cholup(symmUp); |
| 39 | |
| 40 | for (int k=0; k<10; ++k) |
| 41 | { |
| 42 | VectorType vec = VectorType::Random(symm.rows()); |
| 43 | RealScalar sigma = internal::random<RealScalar>(); |
| 44 | symmCpy += sigma * vec * vec.adjoint(); |
| 45 | |
| 46 | // we are doing some downdates, so it might be the case that the matrix is not SPD anymore |
| 47 | CholType<MatrixType,Lower> chol(symmCpy); |
| 48 | if(chol.info()!=Success) |
| 49 | break; |
| 50 | |
| 51 | chollo.rankUpdate(vec, sigma); |
| 52 | VERIFY_IS_APPROX(symmCpy, chollo.reconstructedMatrix()); |
| 53 | |
| 54 | cholup.rankUpdate(vec, sigma); |
| 55 | VERIFY_IS_APPROX(symmCpy, cholup.reconstructedMatrix()); |
| 56 | } |
| 57 | } |
| 58 | |
| 59 | template<typename MatrixType> void cholesky(const MatrixType& m) |
| 60 | { |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 61 | /* this test covers the following files: |
| 62 | LLT.h LDLT.h |
| 63 | */ |
| 64 | Index rows = m.rows(); |
| 65 | Index cols = m.cols(); |
| 66 | |
| 67 | typedef typename MatrixType::Scalar Scalar; |
| 68 | typedef typename NumTraits<Scalar>::Real RealScalar; |
| 69 | typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> SquareMatrixType; |
| 70 | typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType; |
| 71 | |
| 72 | MatrixType a0 = MatrixType::Random(rows,cols); |
| 73 | VectorType vecB = VectorType::Random(rows), vecX(rows); |
| 74 | MatrixType matB = MatrixType::Random(rows,cols), matX(rows,cols); |
| 75 | SquareMatrixType symm = a0 * a0.adjoint(); |
| 76 | // let's make sure the matrix is not singular or near singular |
| 77 | for (int k=0; k<3; ++k) |
| 78 | { |
| 79 | MatrixType a1 = MatrixType::Random(rows,cols); |
| 80 | symm += a1 * a1.adjoint(); |
| 81 | } |
| 82 | |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 83 | { |
| 84 | SquareMatrixType symmUp = symm.template triangularView<Upper>(); |
| 85 | SquareMatrixType symmLo = symm.template triangularView<Lower>(); |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 86 | |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 87 | LLT<SquareMatrixType,Lower> chollo(symmLo); |
| 88 | VERIFY_IS_APPROX(symm, chollo.reconstructedMatrix()); |
| 89 | vecX = chollo.solve(vecB); |
| 90 | VERIFY_IS_APPROX(symm * vecX, vecB); |
| 91 | matX = chollo.solve(matB); |
| 92 | VERIFY_IS_APPROX(symm * matX, matB); |
| 93 | |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 94 | const MatrixType symmLo_inverse = chollo.solve(MatrixType::Identity(rows,cols)); |
| 95 | RealScalar rcond = (RealScalar(1) / matrix_l1_norm<MatrixType, Lower>(symmLo)) / |
| 96 | matrix_l1_norm<MatrixType, Lower>(symmLo_inverse); |
| 97 | RealScalar rcond_est = chollo.rcond(); |
| 98 | // Verify that the estimated condition number is within a factor of 10 of the |
| 99 | // truth. |
| 100 | VERIFY(rcond_est >= rcond / 10 && rcond_est <= rcond * 10); |
| 101 | |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 102 | // test the upper mode |
| 103 | LLT<SquareMatrixType,Upper> cholup(symmUp); |
| 104 | VERIFY_IS_APPROX(symm, cholup.reconstructedMatrix()); |
| 105 | vecX = cholup.solve(vecB); |
| 106 | VERIFY_IS_APPROX(symm * vecX, vecB); |
| 107 | matX = cholup.solve(matB); |
| 108 | VERIFY_IS_APPROX(symm * matX, matB); |
| 109 | |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 110 | // Verify that the estimated condition number is within a factor of 10 of the |
| 111 | // truth. |
| 112 | const MatrixType symmUp_inverse = cholup.solve(MatrixType::Identity(rows,cols)); |
| 113 | rcond = (RealScalar(1) / matrix_l1_norm<MatrixType, Upper>(symmUp)) / |
| 114 | matrix_l1_norm<MatrixType, Upper>(symmUp_inverse); |
| 115 | rcond_est = cholup.rcond(); |
| 116 | VERIFY(rcond_est >= rcond / 10 && rcond_est <= rcond * 10); |
| 117 | |
| 118 | |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 119 | MatrixType neg = -symmLo; |
| 120 | chollo.compute(neg); |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 121 | VERIFY(neg.size()==0 || chollo.info()==NumericalIssue); |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 122 | |
| 123 | VERIFY_IS_APPROX(MatrixType(chollo.matrixL().transpose().conjugate()), MatrixType(chollo.matrixU())); |
| 124 | VERIFY_IS_APPROX(MatrixType(chollo.matrixU().transpose().conjugate()), MatrixType(chollo.matrixL())); |
| 125 | VERIFY_IS_APPROX(MatrixType(cholup.matrixL().transpose().conjugate()), MatrixType(cholup.matrixU())); |
| 126 | VERIFY_IS_APPROX(MatrixType(cholup.matrixU().transpose().conjugate()), MatrixType(cholup.matrixL())); |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 127 | |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 128 | // test some special use cases of SelfCwiseBinaryOp: |
| 129 | MatrixType m1 = MatrixType::Random(rows,cols), m2(rows,cols); |
| 130 | m2 = m1; |
| 131 | m2 += symmLo.template selfadjointView<Lower>().llt().solve(matB); |
| 132 | VERIFY_IS_APPROX(m2, m1 + symmLo.template selfadjointView<Lower>().llt().solve(matB)); |
| 133 | m2 = m1; |
| 134 | m2 -= symmLo.template selfadjointView<Lower>().llt().solve(matB); |
| 135 | VERIFY_IS_APPROX(m2, m1 - symmLo.template selfadjointView<Lower>().llt().solve(matB)); |
| 136 | m2 = m1; |
| 137 | m2.noalias() += symmLo.template selfadjointView<Lower>().llt().solve(matB); |
| 138 | VERIFY_IS_APPROX(m2, m1 + symmLo.template selfadjointView<Lower>().llt().solve(matB)); |
| 139 | m2 = m1; |
| 140 | m2.noalias() -= symmLo.template selfadjointView<Lower>().llt().solve(matB); |
| 141 | VERIFY_IS_APPROX(m2, m1 - symmLo.template selfadjointView<Lower>().llt().solve(matB)); |
| 142 | } |
| 143 | |
| 144 | // LDLT |
| 145 | { |
| 146 | int sign = internal::random<int>()%2 ? 1 : -1; |
| 147 | |
| 148 | if(sign == -1) |
| 149 | { |
| 150 | symm = -symm; // test a negative matrix |
| 151 | } |
| 152 | |
| 153 | SquareMatrixType symmUp = symm.template triangularView<Upper>(); |
| 154 | SquareMatrixType symmLo = symm.template triangularView<Lower>(); |
| 155 | |
| 156 | LDLT<SquareMatrixType,Lower> ldltlo(symmLo); |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 157 | VERIFY(ldltlo.info()==Success); |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 158 | VERIFY_IS_APPROX(symm, ldltlo.reconstructedMatrix()); |
| 159 | vecX = ldltlo.solve(vecB); |
| 160 | VERIFY_IS_APPROX(symm * vecX, vecB); |
| 161 | matX = ldltlo.solve(matB); |
| 162 | VERIFY_IS_APPROX(symm * matX, matB); |
| 163 | |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 164 | const MatrixType symmLo_inverse = ldltlo.solve(MatrixType::Identity(rows,cols)); |
| 165 | RealScalar rcond = (RealScalar(1) / matrix_l1_norm<MatrixType, Lower>(symmLo)) / |
| 166 | matrix_l1_norm<MatrixType, Lower>(symmLo_inverse); |
| 167 | RealScalar rcond_est = ldltlo.rcond(); |
| 168 | // Verify that the estimated condition number is within a factor of 10 of the |
| 169 | // truth. |
| 170 | VERIFY(rcond_est >= rcond / 10 && rcond_est <= rcond * 10); |
| 171 | |
| 172 | |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 173 | LDLT<SquareMatrixType,Upper> ldltup(symmUp); |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 174 | VERIFY(ldltup.info()==Success); |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 175 | VERIFY_IS_APPROX(symm, ldltup.reconstructedMatrix()); |
| 176 | vecX = ldltup.solve(vecB); |
| 177 | VERIFY_IS_APPROX(symm * vecX, vecB); |
| 178 | matX = ldltup.solve(matB); |
| 179 | VERIFY_IS_APPROX(symm * matX, matB); |
| 180 | |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 181 | // Verify that the estimated condition number is within a factor of 10 of the |
| 182 | // truth. |
| 183 | const MatrixType symmUp_inverse = ldltup.solve(MatrixType::Identity(rows,cols)); |
| 184 | rcond = (RealScalar(1) / matrix_l1_norm<MatrixType, Upper>(symmUp)) / |
| 185 | matrix_l1_norm<MatrixType, Upper>(symmUp_inverse); |
| 186 | rcond_est = ldltup.rcond(); |
| 187 | VERIFY(rcond_est >= rcond / 10 && rcond_est <= rcond * 10); |
| 188 | |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 189 | VERIFY_IS_APPROX(MatrixType(ldltlo.matrixL().transpose().conjugate()), MatrixType(ldltlo.matrixU())); |
| 190 | VERIFY_IS_APPROX(MatrixType(ldltlo.matrixU().transpose().conjugate()), MatrixType(ldltlo.matrixL())); |
| 191 | VERIFY_IS_APPROX(MatrixType(ldltup.matrixL().transpose().conjugate()), MatrixType(ldltup.matrixU())); |
| 192 | VERIFY_IS_APPROX(MatrixType(ldltup.matrixU().transpose().conjugate()), MatrixType(ldltup.matrixL())); |
| 193 | |
| 194 | if(MatrixType::RowsAtCompileTime==Dynamic) |
| 195 | { |
| 196 | // note : each inplace permutation requires a small temporary vector (mask) |
| 197 | |
| 198 | // check inplace solve |
| 199 | matX = matB; |
| 200 | VERIFY_EVALUATION_COUNT(matX = ldltlo.solve(matX), 0); |
| 201 | VERIFY_IS_APPROX(matX, ldltlo.solve(matB).eval()); |
| 202 | |
| 203 | |
| 204 | matX = matB; |
| 205 | VERIFY_EVALUATION_COUNT(matX = ldltup.solve(matX), 0); |
| 206 | VERIFY_IS_APPROX(matX, ldltup.solve(matB).eval()); |
| 207 | } |
| 208 | |
| 209 | // restore |
| 210 | if(sign == -1) |
| 211 | symm = -symm; |
| 212 | |
| 213 | // check matrices coming from linear constraints with Lagrange multipliers |
| 214 | if(rows>=3) |
| 215 | { |
| 216 | SquareMatrixType A = symm; |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 217 | Index c = internal::random<Index>(0,rows-2); |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 218 | A.bottomRightCorner(c,c).setZero(); |
| 219 | // Make sure a solution exists: |
| 220 | vecX.setRandom(); |
| 221 | vecB = A * vecX; |
| 222 | vecX.setZero(); |
| 223 | ldltlo.compute(A); |
| 224 | VERIFY_IS_APPROX(A, ldltlo.reconstructedMatrix()); |
| 225 | vecX = ldltlo.solve(vecB); |
| 226 | VERIFY_IS_APPROX(A * vecX, vecB); |
| 227 | } |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 228 | |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 229 | // check non-full rank matrices |
| 230 | if(rows>=3) |
| 231 | { |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 232 | Index r = internal::random<Index>(1,rows-1); |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 233 | Matrix<Scalar,Dynamic,Dynamic> a = Matrix<Scalar,Dynamic,Dynamic>::Random(rows,r); |
| 234 | SquareMatrixType A = a * a.adjoint(); |
| 235 | // Make sure a solution exists: |
| 236 | vecX.setRandom(); |
| 237 | vecB = A * vecX; |
| 238 | vecX.setZero(); |
| 239 | ldltlo.compute(A); |
| 240 | VERIFY_IS_APPROX(A, ldltlo.reconstructedMatrix()); |
| 241 | vecX = ldltlo.solve(vecB); |
| 242 | VERIFY_IS_APPROX(A * vecX, vecB); |
| 243 | } |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 244 | |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 245 | // check matrices with a wide spectrum |
| 246 | if(rows>=3) |
| 247 | { |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 248 | using std::pow; |
| 249 | using std::sqrt; |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 250 | RealScalar s = (std::min)(16,std::numeric_limits<RealScalar>::max_exponent10/8); |
| 251 | Matrix<Scalar,Dynamic,Dynamic> a = Matrix<Scalar,Dynamic,Dynamic>::Random(rows,rows); |
| 252 | Matrix<RealScalar,Dynamic,1> d = Matrix<RealScalar,Dynamic,1>::Random(rows); |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 253 | for(Index k=0; k<rows; ++k) |
| 254 | d(k) = d(k)*pow(RealScalar(10),internal::random<RealScalar>(-s,s)); |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 255 | SquareMatrixType A = a * d.asDiagonal() * a.adjoint(); |
| 256 | // Make sure a solution exists: |
| 257 | vecX.setRandom(); |
| 258 | vecB = A * vecX; |
| 259 | vecX.setZero(); |
| 260 | ldltlo.compute(A); |
| 261 | VERIFY_IS_APPROX(A, ldltlo.reconstructedMatrix()); |
| 262 | vecX = ldltlo.solve(vecB); |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 263 | |
| 264 | if(ldltlo.vectorD().real().cwiseAbs().minCoeff()>RealScalar(0)) |
| 265 | { |
| 266 | VERIFY_IS_APPROX(A * vecX,vecB); |
| 267 | } |
| 268 | else |
| 269 | { |
| 270 | RealScalar large_tol = sqrt(test_precision<RealScalar>()); |
| 271 | VERIFY((A * vecX).isApprox(vecB, large_tol)); |
| 272 | |
| 273 | ++g_test_level; |
| 274 | VERIFY_IS_APPROX(A * vecX,vecB); |
| 275 | --g_test_level; |
| 276 | } |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 277 | } |
| 278 | } |
| 279 | |
| 280 | // update/downdate |
| 281 | CALL_SUBTEST(( test_chol_update<SquareMatrixType,LLT>(symm) )); |
| 282 | CALL_SUBTEST(( test_chol_update<SquareMatrixType,LDLT>(symm) )); |
| 283 | } |
| 284 | |
| 285 | template<typename MatrixType> void cholesky_cplx(const MatrixType& m) |
| 286 | { |
| 287 | // classic test |
| 288 | cholesky(m); |
| 289 | |
| 290 | // test mixing real/scalar types |
| 291 | |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 292 | Index rows = m.rows(); |
| 293 | Index cols = m.cols(); |
| 294 | |
| 295 | typedef typename MatrixType::Scalar Scalar; |
| 296 | typedef typename NumTraits<Scalar>::Real RealScalar; |
| 297 | typedef Matrix<RealScalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> RealMatrixType; |
| 298 | typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType; |
| 299 | |
| 300 | RealMatrixType a0 = RealMatrixType::Random(rows,cols); |
| 301 | VectorType vecB = VectorType::Random(rows), vecX(rows); |
| 302 | MatrixType matB = MatrixType::Random(rows,cols), matX(rows,cols); |
| 303 | RealMatrixType symm = a0 * a0.adjoint(); |
| 304 | // let's make sure the matrix is not singular or near singular |
| 305 | for (int k=0; k<3; ++k) |
| 306 | { |
| 307 | RealMatrixType a1 = RealMatrixType::Random(rows,cols); |
| 308 | symm += a1 * a1.adjoint(); |
| 309 | } |
| 310 | |
| 311 | { |
| 312 | RealMatrixType symmLo = symm.template triangularView<Lower>(); |
| 313 | |
| 314 | LLT<RealMatrixType,Lower> chollo(symmLo); |
| 315 | VERIFY_IS_APPROX(symm, chollo.reconstructedMatrix()); |
| 316 | vecX = chollo.solve(vecB); |
| 317 | VERIFY_IS_APPROX(symm * vecX, vecB); |
| 318 | // matX = chollo.solve(matB); |
| 319 | // VERIFY_IS_APPROX(symm * matX, matB); |
| 320 | } |
| 321 | |
| 322 | // LDLT |
| 323 | { |
| 324 | int sign = internal::random<int>()%2 ? 1 : -1; |
| 325 | |
| 326 | if(sign == -1) |
| 327 | { |
| 328 | symm = -symm; // test a negative matrix |
| 329 | } |
| 330 | |
| 331 | RealMatrixType symmLo = symm.template triangularView<Lower>(); |
| 332 | |
| 333 | LDLT<RealMatrixType,Lower> ldltlo(symmLo); |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 334 | VERIFY(ldltlo.info()==Success); |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 335 | VERIFY_IS_APPROX(symm, ldltlo.reconstructedMatrix()); |
| 336 | vecX = ldltlo.solve(vecB); |
| 337 | VERIFY_IS_APPROX(symm * vecX, vecB); |
| 338 | // matX = ldltlo.solve(matB); |
| 339 | // VERIFY_IS_APPROX(symm * matX, matB); |
| 340 | } |
| 341 | } |
| 342 | |
| 343 | // regression test for bug 241 |
| 344 | template<typename MatrixType> void cholesky_bug241(const MatrixType& m) |
| 345 | { |
| 346 | eigen_assert(m.rows() == 2 && m.cols() == 2); |
| 347 | |
| 348 | typedef typename MatrixType::Scalar Scalar; |
| 349 | typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType; |
| 350 | |
| 351 | MatrixType matA; |
| 352 | matA << 1, 1, 1, 1; |
| 353 | VectorType vecB; |
| 354 | vecB << 1, 1; |
| 355 | VectorType vecX = matA.ldlt().solve(vecB); |
| 356 | VERIFY_IS_APPROX(matA * vecX, vecB); |
| 357 | } |
| 358 | |
| 359 | // LDLT is not guaranteed to work for indefinite matrices, but happens to work fine if matrix is diagonal. |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 360 | // This test checks that LDLT reports correctly that matrix is indefinite. |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 361 | // See http://forum.kde.org/viewtopic.php?f=74&t=106942 and bug 736 |
| 362 | template<typename MatrixType> void cholesky_definiteness(const MatrixType& m) |
| 363 | { |
| 364 | eigen_assert(m.rows() == 2 && m.cols() == 2); |
| 365 | MatrixType mat; |
| 366 | LDLT<MatrixType> ldlt(2); |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 367 | |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 368 | { |
| 369 | mat << 1, 0, 0, -1; |
| 370 | ldlt.compute(mat); |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 371 | VERIFY(ldlt.info()==Success); |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 372 | VERIFY(!ldlt.isNegative()); |
| 373 | VERIFY(!ldlt.isPositive()); |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 374 | VERIFY_IS_APPROX(mat,ldlt.reconstructedMatrix()); |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 375 | } |
| 376 | { |
| 377 | mat << 1, 2, 2, 1; |
| 378 | ldlt.compute(mat); |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 379 | VERIFY(ldlt.info()==Success); |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 380 | VERIFY(!ldlt.isNegative()); |
| 381 | VERIFY(!ldlt.isPositive()); |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 382 | VERIFY_IS_APPROX(mat,ldlt.reconstructedMatrix()); |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 383 | } |
| 384 | { |
| 385 | mat << 0, 0, 0, 0; |
| 386 | ldlt.compute(mat); |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 387 | VERIFY(ldlt.info()==Success); |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 388 | VERIFY(ldlt.isNegative()); |
| 389 | VERIFY(ldlt.isPositive()); |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 390 | VERIFY_IS_APPROX(mat,ldlt.reconstructedMatrix()); |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 391 | } |
| 392 | { |
| 393 | mat << 0, 0, 0, 1; |
| 394 | ldlt.compute(mat); |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 395 | VERIFY(ldlt.info()==Success); |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 396 | VERIFY(!ldlt.isNegative()); |
| 397 | VERIFY(ldlt.isPositive()); |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 398 | VERIFY_IS_APPROX(mat,ldlt.reconstructedMatrix()); |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 399 | } |
| 400 | { |
| 401 | mat << -1, 0, 0, 0; |
| 402 | ldlt.compute(mat); |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 403 | VERIFY(ldlt.info()==Success); |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 404 | VERIFY(ldlt.isNegative()); |
| 405 | VERIFY(!ldlt.isPositive()); |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 406 | VERIFY_IS_APPROX(mat,ldlt.reconstructedMatrix()); |
| 407 | } |
| 408 | } |
| 409 | |
| 410 | template<typename> |
| 411 | void cholesky_faillure_cases() |
| 412 | { |
| 413 | MatrixXd mat; |
| 414 | LDLT<MatrixXd> ldlt; |
| 415 | |
| 416 | { |
| 417 | mat.resize(2,2); |
| 418 | mat << 0, 1, 1, 0; |
| 419 | ldlt.compute(mat); |
| 420 | VERIFY_IS_NOT_APPROX(mat,ldlt.reconstructedMatrix()); |
| 421 | VERIFY(ldlt.info()==NumericalIssue); |
| 422 | } |
| 423 | #if (!EIGEN_ARCH_i386) || defined(EIGEN_VECTORIZE_SSE2) |
| 424 | { |
| 425 | mat.resize(3,3); |
| 426 | mat << -1, -3, 3, |
| 427 | -3, -8.9999999999999999999, 1, |
| 428 | 3, 1, 0; |
| 429 | ldlt.compute(mat); |
| 430 | VERIFY(ldlt.info()==NumericalIssue); |
| 431 | VERIFY_IS_NOT_APPROX(mat,ldlt.reconstructedMatrix()); |
| 432 | } |
| 433 | #endif |
| 434 | { |
| 435 | mat.resize(3,3); |
| 436 | mat << 1, 2, 3, |
| 437 | 2, 4, 1, |
| 438 | 3, 1, 0; |
| 439 | ldlt.compute(mat); |
| 440 | VERIFY(ldlt.info()==NumericalIssue); |
| 441 | VERIFY_IS_NOT_APPROX(mat,ldlt.reconstructedMatrix()); |
| 442 | } |
| 443 | |
| 444 | { |
| 445 | mat.resize(8,8); |
| 446 | mat << 0.1, 0, -0.1, 0, 0, 0, 1, 0, |
| 447 | 0, 4.24667, 0, 2.00333, 0, 0, 0, 0, |
| 448 | -0.1, 0, 0.2, 0, -0.1, 0, 0, 0, |
| 449 | 0, 2.00333, 0, 8.49333, 0, 2.00333, 0, 0, |
| 450 | 0, 0, -0.1, 0, 0.1, 0, 0, 1, |
| 451 | 0, 0, 0, 2.00333, 0, 4.24667, 0, 0, |
| 452 | 1, 0, 0, 0, 0, 0, 0, 0, |
| 453 | 0, 0, 0, 0, 1, 0, 0, 0; |
| 454 | ldlt.compute(mat); |
| 455 | VERIFY(ldlt.info()==NumericalIssue); |
| 456 | VERIFY_IS_NOT_APPROX(mat,ldlt.reconstructedMatrix()); |
| 457 | } |
| 458 | |
| 459 | // bug 1479 |
| 460 | { |
| 461 | mat.resize(4,4); |
| 462 | mat << 1, 2, 0, 1, |
| 463 | 2, 4, 0, 2, |
| 464 | 0, 0, 0, 1, |
| 465 | 1, 2, 1, 1; |
| 466 | ldlt.compute(mat); |
| 467 | VERIFY(ldlt.info()==NumericalIssue); |
| 468 | VERIFY_IS_NOT_APPROX(mat,ldlt.reconstructedMatrix()); |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 469 | } |
| 470 | } |
| 471 | |
| 472 | template<typename MatrixType> void cholesky_verify_assert() |
| 473 | { |
| 474 | MatrixType tmp; |
| 475 | |
| 476 | LLT<MatrixType> llt; |
| 477 | VERIFY_RAISES_ASSERT(llt.matrixL()) |
| 478 | VERIFY_RAISES_ASSERT(llt.matrixU()) |
| 479 | VERIFY_RAISES_ASSERT(llt.solve(tmp)) |
| 480 | VERIFY_RAISES_ASSERT(llt.solveInPlace(&tmp)) |
| 481 | |
| 482 | LDLT<MatrixType> ldlt; |
| 483 | VERIFY_RAISES_ASSERT(ldlt.matrixL()) |
| 484 | VERIFY_RAISES_ASSERT(ldlt.permutationP()) |
| 485 | VERIFY_RAISES_ASSERT(ldlt.vectorD()) |
| 486 | VERIFY_RAISES_ASSERT(ldlt.isPositive()) |
| 487 | VERIFY_RAISES_ASSERT(ldlt.isNegative()) |
| 488 | VERIFY_RAISES_ASSERT(ldlt.solve(tmp)) |
| 489 | VERIFY_RAISES_ASSERT(ldlt.solveInPlace(&tmp)) |
| 490 | } |
| 491 | |
| 492 | void test_cholesky() |
| 493 | { |
| 494 | int s = 0; |
| 495 | for(int i = 0; i < g_repeat; i++) { |
| 496 | CALL_SUBTEST_1( cholesky(Matrix<double,1,1>()) ); |
| 497 | CALL_SUBTEST_3( cholesky(Matrix2d()) ); |
| 498 | CALL_SUBTEST_3( cholesky_bug241(Matrix2d()) ); |
| 499 | CALL_SUBTEST_3( cholesky_definiteness(Matrix2d()) ); |
| 500 | CALL_SUBTEST_4( cholesky(Matrix3f()) ); |
| 501 | CALL_SUBTEST_5( cholesky(Matrix4d()) ); |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 502 | |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 503 | s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE); |
| 504 | CALL_SUBTEST_2( cholesky(MatrixXd(s,s)) ); |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 505 | TEST_SET_BUT_UNUSED_VARIABLE(s) |
| 506 | |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 507 | s = internal::random<int>(1,EIGEN_TEST_MAX_SIZE/2); |
| 508 | CALL_SUBTEST_6( cholesky_cplx(MatrixXcd(s,s)) ); |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 509 | TEST_SET_BUT_UNUSED_VARIABLE(s) |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 510 | } |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 511 | // empty matrix, regression test for Bug 785: |
| 512 | CALL_SUBTEST_2( cholesky(MatrixXd(0,0)) ); |
| 513 | |
| 514 | // This does not work yet: |
| 515 | // CALL_SUBTEST_2( cholesky(Matrix<double,0,0>()) ); |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 516 | |
| 517 | CALL_SUBTEST_4( cholesky_verify_assert<Matrix3f>() ); |
| 518 | CALL_SUBTEST_7( cholesky_verify_assert<Matrix3d>() ); |
| 519 | CALL_SUBTEST_8( cholesky_verify_assert<MatrixXf>() ); |
| 520 | CALL_SUBTEST_2( cholesky_verify_assert<MatrixXd>() ); |
| 521 | |
| 522 | // Test problem size constructors |
| 523 | CALL_SUBTEST_9( LLT<MatrixXf>(10) ); |
| 524 | CALL_SUBTEST_9( LDLT<MatrixXf>(10) ); |
Austin Schuh | 189376f | 2018-12-20 22:11:15 +1100 | [diff] [blame] | 525 | |
| 526 | CALL_SUBTEST_2( cholesky_faillure_cases<void>() ); |
| 527 | |
Brian Silverman | 72890c2 | 2015-09-19 14:37:37 -0400 | [diff] [blame] | 528 | TEST_SET_BUT_UNUSED_VARIABLE(nb_temporaries) |
| 529 | } |