min_quad_with_fixed.cpp 6.6 KB

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