lu_lagrange.h 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  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. // Note: C should *not* have any empty columns. Typically C is the slice of
  32. // the linear constraints matrix Aeq concerning the unknown variables of a
  33. // quadratic optimization. Generally constraints may deal with unknowns as
  34. // well as knowns. Each linear constraint corresponds to a column of Aeq. As
  35. // long as each constraint concerns at least one unknown then the
  36. // corresponding column in C will have at least one non zero entry. If a
  37. // constraint concerns *no* unknowns, you should double check that this is a
  38. // valid constraint. How can you constrain known values to each other? This
  39. // is either a contradiction to the knowns' values or redundent. In either
  40. // case, it's not this functions responsiblilty to handle empty constraints
  41. // so you will get an error.
  42. //
  43. template <typename T>
  44. inline bool lu_lagrange(
  45. const Eigen::SparseMatrix<T> & ATA,
  46. const Eigen::SparseMatrix<T> & C,
  47. Eigen::SparseMatrix<T> & L,
  48. Eigen::SparseMatrix<T> & U);
  49. }
  50. // Implementation
  51. // Cholesky LLT decomposition for symmetric positive definite
  52. #include <Eigen/SparseExtra>
  53. #include <cassert>
  54. #include "find.h"
  55. #include "sparse.h"
  56. template <typename T>
  57. inline bool igl::lu_lagrange(
  58. const Eigen::SparseMatrix<T> & ATA,
  59. const Eigen::SparseMatrix<T> & C,
  60. Eigen::SparseMatrix<T> & L,
  61. Eigen::SparseMatrix<T> & U)
  62. {
  63. // number of unknowns
  64. int n = ATA.rows();
  65. // number of lagrange multipliers
  66. int m = C.cols();
  67. assert(ATA.cols() == n);
  68. if(m != 0)
  69. {
  70. assert(C.rows() == n);
  71. if(C.nonZeros() == 0)
  72. {
  73. // See note above about empty columns in C
  74. fprintf(stderr,"Error: lu_lagrange() C has columns but no entries\n");
  75. return false;
  76. }
  77. }
  78. // Check that each column of C has at least one entry
  79. std::vector<bool> has_entry; has_entry.resize(C.cols(),false);
  80. // Iterate over outside
  81. for(int k=0; k<C.outerSize(); ++k)
  82. {
  83. // Iterate over inside
  84. for(typename Eigen::SparseMatrix<T>::InnerIterator it (C,k); it; ++it)
  85. {
  86. has_entry[it.col()] = true;
  87. }
  88. }
  89. for(int i=0;i<(int)has_entry.size();i++)
  90. {
  91. if(!has_entry[i])
  92. {
  93. // See note above about empty columns in C
  94. fprintf(stderr,"Error: lu_lagrange() C(:,%d) has no entries\n",i);
  95. return false;
  96. }
  97. }
  98. // Cholesky factorization of ATA
  99. //// Eigen fails if you give a full view of the matrix like this:
  100. //Eigen::SparseLLT<SparseMatrix<T> > ATA_LLT(ATA);
  101. Eigen::SparseMatrix<T> ATA_LT = ATA.template triangularView<Eigen::Lower>();
  102. Eigen::SparseLLT<Eigen::SparseMatrix<T> > ATA_LLT(ATA_LT);
  103. Eigen::SparseMatrix<T> J = ATA_LLT.matrixL();
  104. //if(!ATA_LLT.succeeded())
  105. if(!((J*0).eval().nonZeros() == 0))
  106. {
  107. fprintf(stderr,"Error: lu_lagrange() failed to factor ATA\n");
  108. return false;
  109. }
  110. if(m == 0)
  111. {
  112. // If there are no constraints (C is empty) then LU decomposition is just L
  113. // and L' from cholesky decomposition
  114. L = J;
  115. U = J.transpose();
  116. }else
  117. {
  118. // Construct helper matrix M
  119. Eigen::SparseMatrix<T> M = C;
  120. J.template triangularView<Eigen::Lower>().solveInPlace(M);
  121. // Compute cholesky factorizaiton of M'*M
  122. Eigen::SparseMatrix<T> MTM = M.transpose() * M;
  123. Eigen::SparseLLT<Eigen::SparseMatrix<T> > MTM_LLT(MTM.template triangularView<Eigen::Lower>());
  124. Eigen::SparseMatrix<T> K = MTM_LLT.matrixL();
  125. //if(!MTM_LLT.succeeded())
  126. if(!((K*0).eval().nonZeros() == 0))
  127. {
  128. fprintf(stderr,"Error: lu_lagrange() failed to factor MTM\n");
  129. return false;
  130. }
  131. // assemble LU decomposition of Q
  132. Eigen::Matrix<int,Eigen::Dynamic,1> MI;
  133. Eigen::Matrix<int,Eigen::Dynamic,1> MJ;
  134. Eigen::Matrix<T,Eigen::Dynamic,1> MV;
  135. igl::find(M,MI,MJ,MV);
  136. Eigen::Matrix<int,Eigen::Dynamic,1> KI;
  137. Eigen::Matrix<int,Eigen::Dynamic,1> KJ;
  138. Eigen::Matrix<T,Eigen::Dynamic,1> KV;
  139. igl::find(K,KI,KJ,KV);
  140. Eigen::Matrix<int,Eigen::Dynamic,1> JI;
  141. Eigen::Matrix<int,Eigen::Dynamic,1> JJ;
  142. Eigen::Matrix<T,Eigen::Dynamic,1> JV;
  143. igl::find(J,JI,JJ,JV);
  144. int nnz = JV.size() + MV.size() + KV.size();
  145. Eigen::Matrix<int,Eigen::Dynamic,1> UI(nnz);
  146. Eigen::Matrix<int,Eigen::Dynamic,1> UJ(nnz);
  147. Eigen::Matrix<T,Eigen::Dynamic,1> UV(nnz);
  148. UI << JJ, MI, (KJ.array() + n).matrix();
  149. UJ << JI, (MJ.array() + n).matrix(), (KI.array() + n).matrix();
  150. UV << JV, MV, KV*-1;
  151. igl::sparse(UI,UJ,UV,U);
  152. Eigen::Matrix<int,Eigen::Dynamic,1> LI(nnz);
  153. Eigen::Matrix<int,Eigen::Dynamic,1> LJ(nnz);
  154. Eigen::Matrix<T,Eigen::Dynamic,1> LV(nnz);
  155. LI << JI, (MJ.array() + n).matrix(), (KI.array() + n).matrix();
  156. LJ << JJ, MI, (KJ.array() + n).matrix();
  157. LV << JV, MV, KV;
  158. igl::sparse(LI,LJ,LV,L);
  159. }
  160. return true;
  161. }
  162. #endif