min_quad_with_fixed.cpp 8.0 KB

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