lu_lagrange.h 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. #ifndef IGL_LU_LAGRANGE_H
  2. #define IGL_LU_LAGRANGE_H
  3. #define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
  4. #include <Eigen/Dense>
  5. #include <Eigen/Sparse>
  6. namespace igl
  7. {
  8. // LU_LAGRANGE Compute a LU decomposition for a special type of
  9. // matrix Q that is symmetric but not positive-definite:
  10. // Q = [A'*A C
  11. // C' 0];
  12. // where A'*A, or ATA, is given as a symmetric positive definite matrix and C
  13. // has full column-rank(?)
  14. //
  15. // [J] = lu_lagrange(ATA,C)
  16. //
  17. // Templates:
  18. // T should be a eigen matrix primitive type like int or double
  19. // Inputs:
  20. // ATA n by n square, symmetric, positive-definite system matrix, usually
  21. // the quadratic coefficients corresponding to the original unknowns in a
  22. // system
  23. // C n by m rectangular matrix corresponding the quadratic coefficients of
  24. // the original unknowns times the lagrange multipliers enforcing linear
  25. // equality constraints
  26. // Outputs:
  27. // L lower triangular matrix such that Q = L*U
  28. // U upper triangular matrix such that Q = L*U
  29. // Returns true on success, false on error
  30. //
  31. template <typename T>
  32. bool lu_lagrange(
  33. const SparseMatrix<T> & ATA,
  34. const SparseMatrix<T> & C,
  35. SparseMatrix<T> & L,
  36. SparseMatrix<T> & U);
  37. }
  38. // Implementation
  39. // Cholesky LLT decomposition for symmetric positive definite
  40. #include <Eigen/SparseExtra>
  41. #include <cassert>
  42. #include "find.h"
  43. #include "sparse.h"
  44. template <typename T>
  45. bool igl::lu_lagrange(
  46. const SparseMatrix<T> & ATA,
  47. const SparseMatrix<T> & C,
  48. SparseMatrix<T> & L,
  49. SparseMatrix<T> & U)
  50. {
  51. // number of unknowns
  52. int n = ATA.rows();
  53. // number of lagrange multipliers
  54. int m = C.cols();
  55. assert(ATA.cols() == n);
  56. if(m != 0)
  57. {
  58. assert(C.rows() == n);
  59. }
  60. // Cholesky factorization of ATA
  61. //// Eigen fails if you give a full view of the matrix like this:
  62. //Eigen::SparseLLT<SparseMatrix<T> > ATA_LLT(ATA);
  63. SparseMatrix<T> ATA_LT = ATA.template triangularView<Eigen::Lower>();
  64. Eigen::SparseLLT<SparseMatrix<T> > ATA_LLT(ATA_LT);
  65. Eigen::SparseMatrix<T> J = ATA_LLT.matrixL();
  66. //if(!ATA_LLT.succeeded())
  67. if(!((J*0).eval().nonZeros() == 0))
  68. {
  69. fprintf(stderr,"Error: lu_lagrange() failed to factor ATA\n");
  70. return false;
  71. }
  72. if(m == 0)
  73. {
  74. L = J;
  75. U = J.transpose();
  76. }else
  77. {
  78. // Construct helper matrix M
  79. Eigen::SparseMatrix<T> M = C;
  80. J.template triangularView<Eigen::Lower>().solveInPlace(M);
  81. // Compute cholesky factorizaiton of M'*M
  82. Eigen::SparseMatrix<T> MTM = M.transpose() * M;
  83. Eigen::SparseLLT<SparseMatrix<T> > MTM_LLT(MTM.template triangularView<Eigen::Lower>());
  84. Eigen::SparseMatrix<T> K = MTM_LLT.matrixL();
  85. //if(!MTM_LLT.succeeded())
  86. if(!((K*0).eval().nonZeros() == 0))
  87. {
  88. fprintf(stderr,"Error: lu_lagrange() failed to factor MTM\n");
  89. return false;
  90. }
  91. // assemble LU decomposition of Q
  92. Eigen::Matrix<int,Eigen::Dynamic,1> MI;
  93. Eigen::Matrix<int,Eigen::Dynamic,1> MJ;
  94. Eigen::Matrix<T,Eigen::Dynamic,1> MV;
  95. igl::find(M,MI,MJ,MV);
  96. Eigen::Matrix<int,Eigen::Dynamic,1> KI;
  97. Eigen::Matrix<int,Eigen::Dynamic,1> KJ;
  98. Eigen::Matrix<T,Eigen::Dynamic,1> KV;
  99. igl::find(K,KI,KJ,KV);
  100. Eigen::Matrix<int,Eigen::Dynamic,1> JI;
  101. Eigen::Matrix<int,Eigen::Dynamic,1> JJ;
  102. Eigen::Matrix<T,Eigen::Dynamic,1> JV;
  103. igl::find(J,JI,JJ,JV);
  104. int nnz = JV.size() + MV.size() + KV.size();
  105. Eigen::Matrix<int,Eigen::Dynamic,1> UI(nnz);
  106. Eigen::Matrix<int,Eigen::Dynamic,1> UJ(nnz);
  107. Eigen::Matrix<T,Eigen::Dynamic,1> UV(nnz);
  108. UI << JJ, MI, (KJ.array() + n).matrix();
  109. UJ << JI, (MJ.array() + n).matrix(), (KI.array() + n).matrix();
  110. UV << JV, MV, KV*-1;
  111. igl::sparse(UI,UJ,UV,U);
  112. Eigen::Matrix<int,Eigen::Dynamic,1> LI(nnz);
  113. Eigen::Matrix<int,Eigen::Dynamic,1> LJ(nnz);
  114. Eigen::Matrix<T,Eigen::Dynamic,1> LV(nnz);
  115. LI << JI, (MJ.array() + n).matrix(), (KI.array() + n).matrix();
  116. LJ << JJ, MI, (KJ.array() + n).matrix();
  117. LV << JV, MV, KV;
  118. igl::sparse(LI,LJ,LV,L);
  119. //// Only keep lower and upper parts
  120. //L = L.template triangularView<Lower>();
  121. //U = U.template triangularView<Upper>();
  122. }
  123. return true;
  124. }
  125. #endif