min_quad_with_fixed.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. #include "min_quad_with_fixed.h"
  2. //#include <Eigen/SparseExtra>
  3. // Bug in unsupported/Eigen/SparseExtra needs iostream first
  4. #include <iostream>
  5. #include <unsupported/Eigen/SparseExtra>
  6. #include <cassert>
  7. #include <cstdio>
  8. #include <iostream>
  9. #include "slice.h"
  10. #include "is_symmetric.h"
  11. #include "find.h"
  12. #include "sparse.h"
  13. #include "repmat.h"
  14. #include "lu_lagrange.h"
  15. #include "full.h"
  16. template <typename T>
  17. IGL_INLINE bool igl::min_quad_with_fixed_precompute(
  18. const Eigen::SparseMatrix<T>& A,
  19. const Eigen::Matrix<int,Eigen::Dynamic,1> & known,
  20. const Eigen::SparseMatrix<T>& Aeq,
  21. const bool pd,
  22. igl::min_quad_with_fixed_data<T> & data
  23. )
  24. {
  25. // number of rows
  26. int n = A.rows();
  27. // cache problem size
  28. data.n = n;
  29. int neq = Aeq.rows();
  30. // default is to have 0 linear equality constraints
  31. if(Aeq.size() != 0)
  32. {
  33. assert(n == Aeq.cols());
  34. }
  35. assert(A.rows() == n);
  36. assert(A.cols() == n);
  37. // number of known rows
  38. int kr = known.size();
  39. assert(kr == 0 || known.minCoeff() >= 0);
  40. assert(kr == 0 || known.maxCoeff() < n);
  41. assert(neq <= n);
  42. // cache known
  43. data.known = known;
  44. // get list of unknown indices
  45. data.unknown.resize(n-kr);
  46. std::vector<bool> unknown_mask;
  47. unknown_mask.resize(n,true);
  48. for(int i = 0;i<kr;i++)
  49. {
  50. unknown_mask[known(i)] = false;
  51. }
  52. int u = 0;
  53. for(int i = 0;i<n;i++)
  54. {
  55. if(unknown_mask[i])
  56. {
  57. data.unknown(u) = i;
  58. u++;
  59. }
  60. }
  61. // get list of lagrange multiplier indices
  62. data.lagrange.resize(neq);
  63. for(int i = 0;i<neq;i++)
  64. {
  65. data.lagrange(i) = n + i;
  66. }
  67. // cache unknown followed by lagrange indices
  68. data.unknown_lagrange.resize(data.unknown.size()+data.lagrange.size());
  69. data.unknown_lagrange << data.unknown, data.lagrange;
  70. Eigen::SparseMatrix<T> Auu;
  71. igl::slice(A,data.unknown,data.unknown,Auu);
  72. // determine if A(unknown,unknown) is symmetric and/or positive definite
  73. data.Auu_sym = igl::is_symmetric(Auu);
  74. // Positive definiteness is *not* determined, rather it is given as a
  75. // parameter
  76. data.Auu_pd = pd;
  77. // Append lagrange multiplier quadratic terms
  78. Eigen::SparseMatrix<T> new_A;
  79. Eigen::Matrix<int,Eigen::Dynamic,1> AI;
  80. Eigen::Matrix<int,Eigen::Dynamic,1> AJ;
  81. Eigen::Matrix<T,Eigen::Dynamic,1> AV;
  82. igl::find(A,AI,AJ,AV);
  83. Eigen::Matrix<int,Eigen::Dynamic,1> AeqI(0,1);
  84. Eigen::Matrix<int,Eigen::Dynamic,1> AeqJ(0,1);
  85. Eigen::Matrix<T,Eigen::Dynamic,1> AeqV(0,1);
  86. if(neq > 0)
  87. {
  88. igl::find(Aeq,AeqI,AeqJ,AeqV);
  89. }
  90. Eigen::Matrix<int,Eigen::Dynamic,1> new_AI(AV.size()+AeqV.size()*2);
  91. Eigen::Matrix<int,Eigen::Dynamic,1> new_AJ(AV.size()+AeqV.size()*2);
  92. Eigen::Matrix<T,Eigen::Dynamic,1> new_AV(AV.size()+AeqV.size()*2);
  93. new_AI << AI, (AeqI.array()+n).matrix(), AeqJ;
  94. new_AJ << AJ, AeqJ, (AeqI.array()+n).matrix();
  95. new_AV << AV, AeqV, AeqV;
  96. igl::sparse(new_AI,new_AJ,new_AV,n+neq,n+neq,new_A);
  97. // precompute RHS builders
  98. if(kr > 0)
  99. {
  100. Eigen::SparseMatrix<T> Aulk;
  101. igl::slice(new_A,data.unknown_lagrange,data.known,Aulk);
  102. Eigen::SparseMatrix<T> Akul;
  103. igl::slice(new_A,data.known,data.unknown_lagrange,Akul);
  104. //// This doesn't work!!!
  105. //data.preY = Aulk + Akul.transpose();
  106. Eigen::SparseMatrix<T> AkulT = Akul.transpose();
  107. data.preY = Aulk + AkulT;
  108. }else
  109. {
  110. data.preY.resize(data.unknown_lagrange.size(),0);
  111. }
  112. // Create factorization
  113. if(data.Auu_sym && data.Auu_pd)
  114. {
  115. data.sparse = true;
  116. Eigen::SparseMatrix<T> Aequ(0,0);
  117. if(neq>0)
  118. {
  119. Eigen::Matrix<int,Eigen::Dynamic,1> Aeq_rows;
  120. Aeq_rows.resize(neq);
  121. for(int i = 0;i<neq;i++)
  122. {
  123. Aeq_rows(i) = i;
  124. }
  125. igl::slice(Aeq,Aeq_rows,data.unknown,Aequ);
  126. }
  127. // Get transpose of Aequ
  128. Eigen::SparseMatrix<T> AequT = Aequ.transpose();
  129. // Compute LU decomposition
  130. // TODO: This should be using SimplicialLDLT
  131. // Q: Does SimplicialLDLT work on "Hermitian indefinite matrices" the way
  132. // that matlabs ldl does?
  133. // A: Maybe not. The eigen documentation writes, "This class provides a
  134. // LDL^T Cholesky factorizations without square root of sparse matrices
  135. // that are selfadjoint and positive definite"
  136. bool lu_success = igl::lu_lagrange(Auu,AequT,data.L,data.U);
  137. if(!lu_success)
  138. {
  139. return false;
  140. }
  141. }else
  142. {
  143. Eigen::SparseMatrix<T> NA;
  144. igl::slice(new_A,data.unknown_lagrange,data.unknown_lagrange,NA);
  145. // Build LU decomposition of NA
  146. data.sparse = false;
  147. fprintf(stderr,
  148. "Warning: min_quad_with_fixed_precompute() resorting to dense LU\n");
  149. Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> NAfull;
  150. igl::full(NA,NAfull);
  151. data.lu =
  152. Eigen::FullPivLU<Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> >(NAfull);
  153. if(!data.lu.isInvertible())
  154. {
  155. fprintf(stderr,
  156. "Error: min_quad_with_fixed_precompute() LU not invertible\n");
  157. return false;
  158. }
  159. }
  160. return true;
  161. }
  162. template <typename T>
  163. IGL_INLINE bool igl::min_quad_with_fixed_solve(
  164. const igl::min_quad_with_fixed_data<T> & data,
  165. const Eigen::Matrix<T,Eigen::Dynamic,1> & B,
  166. const Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & Y,
  167. const Eigen::Matrix<T,Eigen::Dynamic,1> & Beq,
  168. Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & Z)
  169. {
  170. // number of known rows
  171. int kr = data.known.size();
  172. if(kr!=0)
  173. {
  174. assert(kr == Y.rows());
  175. }
  176. // number of columns to solve
  177. int cols = Y.cols();
  178. // number of lagrange multipliers aka linear equality constraints
  179. int neq = data.lagrange.size();
  180. // append lagrange multiplier rhs's
  181. Eigen::Matrix<T,Eigen::Dynamic,1> BBeq(B.size() + Beq.size());
  182. BBeq << B, (Beq*-2.0);
  183. // Build right hand side
  184. Eigen::Matrix<T,Eigen::Dynamic,1> BBequl;
  185. igl::slice(BBeq,data.unknown_lagrange,BBequl);
  186. Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> BBequlcols;
  187. igl::repmat(BBequl,1,cols,BBequlcols);
  188. Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> NB;
  189. if(kr == 0)
  190. {
  191. NB = BBequlcols;
  192. }else
  193. {
  194. NB = data.preY * Y + BBequlcols;
  195. }
  196. // resize output
  197. Z.resize(data.n,cols);
  198. // Set known values
  199. for(int i = 0;i < kr;i++)
  200. {
  201. for(int j = 0;j < cols;j++)
  202. {
  203. Z(data.known(i),j) = Y(i,j);
  204. }
  205. }
  206. //std::cout<<"NB=["<<std::endl<<NB<<std::endl<<"];"<<std::endl;
  207. if(data.sparse)
  208. {
  209. //std::cout<<"data.LIJV=["<<std::endl;print_ijv(data.L,1);std::cout<<std::endl<<"];"<<
  210. // std::endl<<"data.L=sparse(data.LIJV(:,1),data.LIJV(:,2),data.LIJV(:,3),"<<
  211. // data.L.rows()<<","<<data.L.cols()<<");"<<std::endl;
  212. //std::cout<<"data.UIJV=["<<std::endl;print_ijv(data.U,1);std::cout<<std::endl<<"];"<<
  213. // std::endl<<"data.U=sparse(data.UIJV(:,1),data.UIJV(:,2),data.UIJV(:,3),"<<
  214. // data.U.rows()<<","<<data.U.cols()<<");"<<std::endl;
  215. data.L.template triangularView<Eigen::Lower>().solveInPlace(NB);
  216. data.U.template triangularView<Eigen::Upper>().solveInPlace(NB);
  217. }else
  218. {
  219. NB = data.lu.solve(NB);
  220. }
  221. // Now NB contains sol/-0.5
  222. NB *= -0.5;
  223. // Now NB contains solution
  224. // Place solution in Z
  225. for(int i = 0;i<(NB.rows()-neq);i++)
  226. {
  227. for(int j = 0;j<NB.cols();j++)
  228. {
  229. Z(data.unknown_lagrange(i),j) = NB(i,j);
  230. }
  231. }
  232. return true;
  233. }
  234. #ifndef IGL_HEADER_ONLY
  235. // Explicit template specialization
  236. #endif