example.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. // Make an effort to verify bugs/gotchas for column and row major
  2. //#define EIGEN_DEFAULT_TO_ROW_MAJOR
  3. #define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
  4. #define EIGEN_IM_MAD_AS_HELL_AND_IM_NOT_GOING_TO_TAKE_IT_ANYMORE
  5. #include <Eigen/Sparse>
  6. using namespace Eigen;
  7. #include <cstdio>
  8. #include <iostream>
  9. using namespace std;
  10. #include <igl/print_ijv.h>
  11. using namespace igl;
  12. #if EIGEN_VERSION_AT_LEAST(3,0,92)
  13. # warning these gotchas have not been verified for your Eigen Version
  14. #else
  15. // Eigen fails to notice at compile time that the inneriterator used to loop
  16. // over the contents of a sparsematrix of type T is a different type
  17. //
  18. // http://www.alecjacobson.com/weblog/?p=2216
  19. void wrong_sparsematrix_inner_iterator_type()
  20. {
  21. // Fill 10 by 10 matrix with 0.5*(1:10) along the diagonal
  22. SparseMatrix<double> A(10,10);
  23. A.reserve(10);
  24. for(int i = 0;i<10;i++)
  25. {
  26. A.insert(i,i) = (double)i/2.0;
  27. }
  28. A.finalize();
  29. cout<<"AIJV=["<<endl;print_ijv(A,1);cout<<endl<<"];"<<endl<<
  30. "A=sparse(AIJV(:,1),AIJV(:,2),AIJV(:,3),"<<
  31. A.rows()<<","<<A.cols()<<");"<<endl;
  32. // Traverse A as *int*
  33. for(int k = 0;k<A.outerSize();k++)
  34. {
  35. // Each entry seems to be cast to int and if it's cast to zero then it's as
  36. // if it wasn't even there
  37. for (SparseMatrix<int>::InnerIterator it(A,k); it; ++it)
  38. {
  39. printf("A(%d,%d) = %d\n",it.row(),it.col(),it.value());
  40. }
  41. }
  42. }
  43. // Eigen can't handle .transpose within expression on right hand side of =
  44. // operator
  45. //
  46. // Temporary solution: Never use Something.transpose() in expression. Always
  47. // first compute Something into a matrix:
  48. // SparseMatrix S = Something;
  49. // then compute tranpose
  50. // SparseMatrix ST = Something.transpose();
  51. // then continue
  52. void sparsematrix_transpose_in_rhs_aliasing()
  53. {
  54. SparseMatrix<double> A(7,2);
  55. A.reserve(4);
  56. A.insert(0,0) = -0.5;
  57. A.insert(2,0) = -0.5;
  58. A.insert(4,1) = -0.5;
  59. A.insert(6,1) = -0.5;
  60. A.finalize();
  61. cout<<"AIJV=["<<endl;print_ijv(A,1);cout<<endl<<"];"<<endl<<
  62. "A=sparse(AIJV(:,1),AIJV(:,2),AIJV(:,3),"<<
  63. A.rows()<<","<<A.cols()<<");"<<endl;
  64. SparseMatrix<double> B(2,7);
  65. B.reserve(4);
  66. B.insert(0,0) = -0.5;
  67. B.insert(0,2) = -0.5;
  68. B.insert(1,4) = -0.5;
  69. B.insert(1,6) = -0.5;
  70. B.finalize();
  71. cout<<"BIJV=["<<endl;print_ijv(B,1);cout<<endl<<"];"<<endl<<
  72. "B=sparse(BIJV(:,1),BIJV(:,2),BIJV(:,3),"<<
  73. B.rows()<<","<<B.cols()<<");"<<endl;
  74. SparseMatrix<double> C;
  75. // Should be empty but isn't
  76. C = A-B.transpose();
  77. cout<<"C = A - B.transpose();"<<endl;
  78. cout<<"CIJV=["<<endl;print_ijv(C,1);cout<<endl<<"];"<<endl<<
  79. "C=sparse(CIJV(:,1),CIJV(:,2),CIJV(:,3),"<<
  80. C.rows()<<","<<C.cols()<<");"<<endl;
  81. // Should be empty but isn't
  82. C = A-B.transpose().eval();
  83. cout<<"C = A - B.transpose().eval();"<<endl;
  84. cout<<"CIJV=["<<endl;print_ijv(C,1);cout<<endl<<"];"<<endl<<
  85. "C=sparse(CIJV(:,1),CIJV(:,2),CIJV(:,3),"<<
  86. C.rows()<<","<<C.cols()<<");"<<endl;
  87. // This works
  88. SparseMatrix<double> BT = B.transpose();
  89. C = A-BT;
  90. cout<<"C = A - BT;"<<endl;
  91. cout<<"CIJV=["<<endl;print_ijv(C,1);cout<<endl<<"];"<<endl<<
  92. "C=sparse(CIJV(:,1),CIJV(:,2),CIJV(:,3),"<<
  93. C.rows()<<","<<C.cols()<<");"<<endl;
  94. }
  95. // Eigen claims the sparseLLT can be constructed using a SparseMatrix but
  96. // at runtime crashes unless it is given exclusively the lower triangle
  97. //
  98. // Temporary solution, replace:
  99. // SparseLLT<SparseMatrix<T> > A_LLT(A);
  100. // with:
  101. // SparseLLT<SparseMatrix<T> > A_LLT(A.template triangularView<Eigen::Lower>());
  102. //
  103. void sparsellt_needs_triangular_view()
  104. {
  105. // Succeeds
  106. SparseMatrix<double> A(2,2);
  107. A.reserve(4);
  108. A.insert(0,0) = 1;
  109. A.insert(0,1) = -0.5;
  110. A.insert(1,0) = -0.5;
  111. A.insert(1,1) = 1;
  112. A.finalize();
  113. cout<<"AIJV=["<<endl;print_ijv(A,1);cout<<endl<<"];"<<endl<<
  114. "A=sparse(AIJV(:,1),AIJV(:,2),AIJV(:,3),"<<
  115. A.rows()<<","<<A.cols()<<");"<<endl;
  116. SparseLLT<SparseMatrix<double> > A_LLT(A.triangularView<Eigen::Lower>());
  117. SparseMatrix<double> A_L = A_LLT.matrixL();
  118. cout<<"A_LIJV=["<<endl;print_ijv(A_L,1);cout<<endl<<"];"<<endl<<
  119. "A_L=sparse(A_LIJV(:,1),A_LIJV(:,2),A_LIJV(:,3),"<<
  120. A_L.rows()<<","<<A_L.cols()<<");"<<endl;
  121. //Crashes
  122. SparseMatrix<double> B(2,2);
  123. B.reserve(4);
  124. B.insert(0,0) = 1;
  125. B.insert(0,1) = -0.5;
  126. B.insert(1,0) = -0.5;
  127. B.insert(1,1) = 1;
  128. B.finalize();
  129. cout<<"BIJV=["<<endl;print_ijv(B,1);cout<<endl<<"];"<<endl<<
  130. "B=sparse(BIJV(:,1),BIJV(:,2),BIJV(:,3),"<<
  131. B.rows()<<","<<B.cols()<<");"<<endl;
  132. SparseLLT<SparseMatrix<double> > B_LLT(B);
  133. }
  134. void sparsematrix_nonzeros_after_expression()
  135. {
  136. SparseMatrix<double> A(2,2);
  137. A.reserve(4);
  138. A.insert(0,0) = 1;
  139. A.insert(0,1) = -0.5;
  140. A.insert(1,0) = -0.5;
  141. A.insert(1,1) = 1;
  142. A.finalize();
  143. cout<<"AIJV=["<<endl;print_ijv(A,1);cout<<endl<<"];"<<endl<<
  144. "A=sparse(AIJV(:,1),AIJV(:,2),AIJV(:,3),"<<
  145. A.rows()<<","<<A.cols()<<");"<<endl;
  146. // Succeeds
  147. SparseMatrix<double> AmA = A-A;
  148. cout<<"(AmA).nonZeros(): "<<AmA.nonZeros()<<endl;
  149. // Succeeds
  150. cout<<"(A-A).eval().nonZeros(): "<<(A-A).eval().nonZeros()<<endl;
  151. // Crashes
  152. cout<<"(A-A).nonZeros(): "<<(A-A).nonZeros()<<endl;
  153. }
  154. // Eigen's SparseLLT's succeeded() method claims to return whether LLT
  155. // computation was successful. Instead it seems its value is meaningless
  156. //
  157. // Temporary solution: Check for presence NaNs in matrixL()
  158. // bool succeeded = (A_LLT.matrixL()*0).eval().nonZeros() == 0;
  159. void sparsellt_succeeded_is_meaningless()
  160. {
  161. // Should succeed
  162. SparseMatrix<double> A(2,2);
  163. A.reserve(4);
  164. A.insert(0,0) = 1;
  165. A.insert(0,1) = -0.5;
  166. A.insert(1,0) = -0.5;
  167. A.insert(1,1) = 1;
  168. A.finalize();
  169. cout<<"AIJV=["<<endl;print_ijv(A,1);cout<<endl<<"];"<<endl<<
  170. "A=sparse(AIJV(:,1),AIJV(:,2),AIJV(:,3),"<<
  171. A.rows()<<","<<A.cols()<<");"<<endl;
  172. SparseLLT<SparseMatrix<double> > A_LLT(A.triangularView<Eigen::Lower>());
  173. cout<<"A_LLT.succeeded(): "<<(A_LLT.succeeded()?"TRUE":"FALSE")<<endl;
  174. SparseMatrix<double> A_L = A_LLT.matrixL();
  175. // See sparsematrix_nonzeros_after_expression
  176. cout<<"(A_L*0).eval().nonZeros(): "<<(A_L*0).eval().nonZeros()<<endl;
  177. cout<<"A_LIJV=["<<endl;print_ijv(A_L,1);cout<<endl<<"];"<<endl<<
  178. "A_L=sparse(A_LIJV(:,1),A_LIJV(:,2),A_LIJV(:,3),"<<
  179. A_L.rows()<<","<<A_L.cols()<<");"<<endl;
  180. // Should not succeed
  181. SparseMatrix<double> B(2,2);
  182. B.reserve(4);
  183. B.insert(0,0) = -1;
  184. B.insert(0,1) = 0.5;
  185. B.insert(1,0) = 0.5;
  186. B.insert(1,1) = -1;
  187. B.finalize();
  188. cout<<"BIJV=["<<endl;print_ijv(B,1);cout<<endl<<"];"<<endl<<
  189. "B=sparse(BIJV(:,1),BIJV(:,2),BIJV(:,3),"<<
  190. B.rows()<<","<<B.cols()<<");"<<endl;
  191. SparseLLT<SparseMatrix<double> > B_LLT(B.triangularView<Eigen::Lower>());
  192. cout<<"B_LLT.succeeded(): "<<(B_LLT.succeeded()?"TRUE":"FALSE")<<endl;
  193. SparseMatrix<double> B_L = B_LLT.matrixL();
  194. // See sparsematrix_nonzeros_after_expression
  195. cout<<"(B_L*0).eval().nonZeros(): "<<(B_L*0).eval().nonZeros()<<endl;
  196. cout<<"B_LIJV=["<<endl;print_ijv(B_L,1);cout<<endl<<"];"<<endl<<
  197. "B_L=sparse(B_LIJV(:,1),B_LIJV(:,2),B_LIJV(:,3),"<<
  198. B_L.rows()<<","<<B_L.cols()<<");"<<endl;
  199. }
  200. #endif
  201. int main(int argc, char * argv[])
  202. {
  203. //wrong_sparsematrix_inner_iterator_type();
  204. //sparsematrix_transpose_in_rhs_aliasing();
  205. //sparsellt_needs_triangular_view();
  206. //sparsematrix_nonzeros_after_expression();
  207. //sparsellt_succeeded_is_meaningless();
  208. return 0;
  209. }