You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

317 lines
10 KiB

  1. // This file is part of Eigen, a lightweight C++ template library
  2. // for linear algebra. Eigen itself is part of the KDE project.
  3. //
  4. // Copyright (C) 2008 Daniel Gomez Ferro <dgomezferro@gmail.com>
  5. //
  6. // This Source Code Form is subject to the terms of the Mozilla
  7. // Public License v. 2.0. If a copy of the MPL was not distributed
  8. // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
  9. #include "sparse.h"
  10. template<typename SetterType,typename DenseType, typename Scalar, int Options>
  11. bool test_random_setter(SparseMatrix<Scalar,Options>& sm, const DenseType& ref, const std::vector<Vector2i>& nonzeroCoords)
  12. {
  13. typedef SparseMatrix<Scalar,Options> SparseType;
  14. {
  15. sm.setZero();
  16. SetterType w(sm);
  17. std::vector<Vector2i> remaining = nonzeroCoords;
  18. while(!remaining.empty())
  19. {
  20. int i = ei_random<int>(0,remaining.size()-1);
  21. w(remaining[i].x(),remaining[i].y()) = ref.coeff(remaining[i].x(),remaining[i].y());
  22. remaining[i] = remaining.back();
  23. remaining.pop_back();
  24. }
  25. }
  26. return sm.isApprox(ref);
  27. }
  28. template<typename SetterType,typename DenseType, typename T>
  29. bool test_random_setter(DynamicSparseMatrix<T>& sm, const DenseType& ref, const std::vector<Vector2i>& nonzeroCoords)
  30. {
  31. sm.setZero();
  32. std::vector<Vector2i> remaining = nonzeroCoords;
  33. while(!remaining.empty())
  34. {
  35. int i = ei_random<int>(0,remaining.size()-1);
  36. sm.coeffRef(remaining[i].x(),remaining[i].y()) = ref.coeff(remaining[i].x(),remaining[i].y());
  37. remaining[i] = remaining.back();
  38. remaining.pop_back();
  39. }
  40. return sm.isApprox(ref);
  41. }
  42. template<typename SparseMatrixType> void sparse_basic(const SparseMatrixType& ref)
  43. {
  44. const int rows = ref.rows();
  45. const int cols = ref.cols();
  46. typedef typename SparseMatrixType::Scalar Scalar;
  47. enum { Flags = SparseMatrixType::Flags };
  48. double density = std::max(8./(rows*cols), 0.01);
  49. typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix;
  50. typedef Matrix<Scalar,Dynamic,1> DenseVector;
  51. Scalar eps = 1e-6;
  52. SparseMatrixType m(rows, cols);
  53. DenseMatrix refMat = DenseMatrix::Zero(rows, cols);
  54. DenseVector vec1 = DenseVector::Random(rows);
  55. Scalar s1 = ei_random<Scalar>();
  56. std::vector<Vector2i> zeroCoords;
  57. std::vector<Vector2i> nonzeroCoords;
  58. initSparse<Scalar>(density, refMat, m, 0, &zeroCoords, &nonzeroCoords);
  59. if (zeroCoords.size()==0 || nonzeroCoords.size()==0)
  60. return;
  61. // test coeff and coeffRef
  62. for (int i=0; i<(int)zeroCoords.size(); ++i)
  63. {
  64. VERIFY_IS_MUCH_SMALLER_THAN( m.coeff(zeroCoords[i].x(),zeroCoords[i].y()), eps );
  65. if(ei_is_same_type<SparseMatrixType,SparseMatrix<Scalar,Flags> >::ret)
  66. VERIFY_RAISES_ASSERT( m.coeffRef(zeroCoords[0].x(),zeroCoords[0].y()) = 5 );
  67. }
  68. VERIFY_IS_APPROX(m, refMat);
  69. m.coeffRef(nonzeroCoords[0].x(), nonzeroCoords[0].y()) = Scalar(5);
  70. refMat.coeffRef(nonzeroCoords[0].x(), nonzeroCoords[0].y()) = Scalar(5);
  71. VERIFY_IS_APPROX(m, refMat);
  72. /*
  73. // test InnerIterators and Block expressions
  74. for (int t=0; t<10; ++t)
  75. {
  76. int j = ei_random<int>(0,cols-1);
  77. int i = ei_random<int>(0,rows-1);
  78. int w = ei_random<int>(1,cols-j-1);
  79. int h = ei_random<int>(1,rows-i-1);
  80. // VERIFY_IS_APPROX(m.block(i,j,h,w), refMat.block(i,j,h,w));
  81. for(int c=0; c<w; c++)
  82. {
  83. VERIFY_IS_APPROX(m.block(i,j,h,w).col(c), refMat.block(i,j,h,w).col(c));
  84. for(int r=0; r<h; r++)
  85. {
  86. // VERIFY_IS_APPROX(m.block(i,j,h,w).col(c).coeff(r), refMat.block(i,j,h,w).col(c).coeff(r));
  87. }
  88. }
  89. // for(int r=0; r<h; r++)
  90. // {
  91. // VERIFY_IS_APPROX(m.block(i,j,h,w).row(r), refMat.block(i,j,h,w).row(r));
  92. // for(int c=0; c<w; c++)
  93. // {
  94. // VERIFY_IS_APPROX(m.block(i,j,h,w).row(r).coeff(c), refMat.block(i,j,h,w).row(r).coeff(c));
  95. // }
  96. // }
  97. }
  98. for(int c=0; c<cols; c++)
  99. {
  100. VERIFY_IS_APPROX(m.col(c) + m.col(c), (m + m).col(c));
  101. VERIFY_IS_APPROX(m.col(c) + m.col(c), refMat.col(c) + refMat.col(c));
  102. }
  103. for(int r=0; r<rows; r++)
  104. {
  105. VERIFY_IS_APPROX(m.row(r) + m.row(r), (m + m).row(r));
  106. VERIFY_IS_APPROX(m.row(r) + m.row(r), refMat.row(r) + refMat.row(r));
  107. }
  108. */
  109. // test SparseSetters
  110. // coherent setter
  111. // TODO extend the MatrixSetter
  112. // {
  113. // m.setZero();
  114. // VERIFY_IS_NOT_APPROX(m, refMat);
  115. // SparseSetter<SparseMatrixType, FullyCoherentAccessPattern> w(m);
  116. // for (int i=0; i<nonzeroCoords.size(); ++i)
  117. // {
  118. // w->coeffRef(nonzeroCoords[i].x(),nonzeroCoords[i].y()) = refMat.coeff(nonzeroCoords[i].x(),nonzeroCoords[i].y());
  119. // }
  120. // }
  121. // VERIFY_IS_APPROX(m, refMat);
  122. // random setter
  123. // {
  124. // m.setZero();
  125. // VERIFY_IS_NOT_APPROX(m, refMat);
  126. // SparseSetter<SparseMatrixType, RandomAccessPattern> w(m);
  127. // std::vector<Vector2i> remaining = nonzeroCoords;
  128. // while(!remaining.empty())
  129. // {
  130. // int i = ei_random<int>(0,remaining.size()-1);
  131. // w->coeffRef(remaining[i].x(),remaining[i].y()) = refMat.coeff(remaining[i].x(),remaining[i].y());
  132. // remaining[i] = remaining.back();
  133. // remaining.pop_back();
  134. // }
  135. // }
  136. // VERIFY_IS_APPROX(m, refMat);
  137. VERIFY(( test_random_setter<RandomSetter<SparseMatrixType, StdMapTraits> >(m,refMat,nonzeroCoords) ));
  138. #ifdef EIGEN_UNORDERED_MAP_SUPPORT
  139. VERIFY(( test_random_setter<RandomSetter<SparseMatrixType, StdUnorderedMapTraits> >(m,refMat,nonzeroCoords) ));
  140. #endif
  141. #ifdef _DENSE_HASH_MAP_H_
  142. VERIFY(( test_random_setter<RandomSetter<SparseMatrixType, GoogleDenseHashMapTraits> >(m,refMat,nonzeroCoords) ));
  143. #endif
  144. #ifdef _SPARSE_HASH_MAP_H_
  145. VERIFY(( test_random_setter<RandomSetter<SparseMatrixType, GoogleSparseHashMapTraits> >(m,refMat,nonzeroCoords) ));
  146. #endif
  147. // test fillrand
  148. {
  149. DenseMatrix m1(rows,cols);
  150. m1.setZero();
  151. SparseMatrixType m2(rows,cols);
  152. m2.startFill();
  153. for (int j=0; j<cols; ++j)
  154. {
  155. for (int k=0; k<rows/2; ++k)
  156. {
  157. int i = ei_random<int>(0,rows-1);
  158. if (m1.coeff(i,j)==Scalar(0))
  159. m2.fillrand(i,j) = m1(i,j) = ei_random<Scalar>();
  160. }
  161. }
  162. m2.endFill();
  163. VERIFY_IS_APPROX(m2,m1);
  164. }
  165. // test RandomSetter
  166. /*{
  167. SparseMatrixType m1(rows,cols), m2(rows,cols);
  168. DenseMatrix refM1 = DenseMatrix::Zero(rows, rows);
  169. initSparse<Scalar>(density, refM1, m1);
  170. {
  171. Eigen::RandomSetter<SparseMatrixType > setter(m2);
  172. for (int j=0; j<m1.outerSize(); ++j)
  173. for (typename SparseMatrixType::InnerIterator i(m1,j); i; ++i)
  174. setter(i.index(), j) = i.value();
  175. }
  176. VERIFY_IS_APPROX(m1, m2);
  177. }*/
  178. // std::cerr << m.transpose() << "\n\n" << refMat.transpose() << "\n\n";
  179. // VERIFY_IS_APPROX(m, refMat);
  180. // test basic computations
  181. {
  182. DenseMatrix refM1 = DenseMatrix::Zero(rows, rows);
  183. DenseMatrix refM2 = DenseMatrix::Zero(rows, rows);
  184. DenseMatrix refM3 = DenseMatrix::Zero(rows, rows);
  185. DenseMatrix refM4 = DenseMatrix::Zero(rows, rows);
  186. SparseMatrixType m1(rows, rows);
  187. SparseMatrixType m2(rows, rows);
  188. SparseMatrixType m3(rows, rows);
  189. SparseMatrixType m4(rows, rows);
  190. initSparse<Scalar>(density, refM1, m1);
  191. initSparse<Scalar>(density, refM2, m2);
  192. initSparse<Scalar>(density, refM3, m3);
  193. initSparse<Scalar>(density, refM4, m4);
  194. VERIFY_IS_APPROX(m1+m2, refM1+refM2);
  195. VERIFY_IS_APPROX(m1+m2+m3, refM1+refM2+refM3);
  196. VERIFY_IS_APPROX(m3.cwise()*(m1+m2), refM3.cwise()*(refM1+refM2));
  197. VERIFY_IS_APPROX(m1*s1-m2, refM1*s1-refM2);
  198. VERIFY_IS_APPROX(m1*=s1, refM1*=s1);
  199. VERIFY_IS_APPROX(m1/=s1, refM1/=s1);
  200. VERIFY_IS_APPROX(m1+=m2, refM1+=refM2);
  201. VERIFY_IS_APPROX(m1-=m2, refM1-=refM2);
  202. VERIFY_IS_APPROX(m1.col(0).eigen2_dot(refM2.row(0)), refM1.col(0).eigen2_dot(refM2.row(0)));
  203. refM4.setRandom();
  204. // sparse cwise* dense
  205. VERIFY_IS_APPROX(m3.cwise()*refM4, refM3.cwise()*refM4);
  206. // VERIFY_IS_APPROX(m3.cwise()/refM4, refM3.cwise()/refM4);
  207. }
  208. // test innerVector()
  209. {
  210. DenseMatrix refMat2 = DenseMatrix::Zero(rows, rows);
  211. SparseMatrixType m2(rows, rows);
  212. initSparse<Scalar>(density, refMat2, m2);
  213. int j0 = ei_random(0,rows-1);
  214. int j1 = ei_random(0,rows-1);
  215. VERIFY_IS_APPROX(m2.innerVector(j0), refMat2.col(j0));
  216. VERIFY_IS_APPROX(m2.innerVector(j0)+m2.innerVector(j1), refMat2.col(j0)+refMat2.col(j1));
  217. //m2.innerVector(j0) = 2*m2.innerVector(j1);
  218. //refMat2.col(j0) = 2*refMat2.col(j1);
  219. //VERIFY_IS_APPROX(m2, refMat2);
  220. }
  221. // test innerVectors()
  222. {
  223. DenseMatrix refMat2 = DenseMatrix::Zero(rows, rows);
  224. SparseMatrixType m2(rows, rows);
  225. initSparse<Scalar>(density, refMat2, m2);
  226. int j0 = ei_random(0,rows-2);
  227. int j1 = ei_random(0,rows-2);
  228. int n0 = ei_random<int>(1,rows-std::max(j0,j1));
  229. VERIFY_IS_APPROX(m2.innerVectors(j0,n0), refMat2.block(0,j0,rows,n0));
  230. VERIFY_IS_APPROX(m2.innerVectors(j0,n0)+m2.innerVectors(j1,n0),
  231. refMat2.block(0,j0,rows,n0)+refMat2.block(0,j1,rows,n0));
  232. //m2.innerVectors(j0,n0) = m2.innerVectors(j0,n0) + m2.innerVectors(j1,n0);
  233. //refMat2.block(0,j0,rows,n0) = refMat2.block(0,j0,rows,n0) + refMat2.block(0,j1,rows,n0);
  234. }
  235. // test transpose
  236. {
  237. DenseMatrix refMat2 = DenseMatrix::Zero(rows, rows);
  238. SparseMatrixType m2(rows, rows);
  239. initSparse<Scalar>(density, refMat2, m2);
  240. VERIFY_IS_APPROX(m2.transpose().eval(), refMat2.transpose().eval());
  241. VERIFY_IS_APPROX(m2.transpose(), refMat2.transpose());
  242. }
  243. // test prune
  244. {
  245. SparseMatrixType m2(rows, rows);
  246. DenseMatrix refM2(rows, rows);
  247. refM2.setZero();
  248. int countFalseNonZero = 0;
  249. int countTrueNonZero = 0;
  250. m2.startFill();
  251. for (int j=0; j<m2.outerSize(); ++j)
  252. for (int i=0; i<m2.innerSize(); ++i)
  253. {
  254. float x = ei_random<float>(0,1);
  255. if (x<0.1)
  256. {
  257. // do nothing
  258. }
  259. else if (x<0.5)
  260. {
  261. countFalseNonZero++;
  262. m2.fill(i,j) = Scalar(0);
  263. }
  264. else
  265. {
  266. countTrueNonZero++;
  267. m2.fill(i,j) = refM2(i,j) = Scalar(1);
  268. }
  269. }
  270. m2.endFill();
  271. VERIFY(countFalseNonZero+countTrueNonZero == m2.nonZeros());
  272. VERIFY_IS_APPROX(m2, refM2);
  273. m2.prune(1);
  274. VERIFY(countTrueNonZero==m2.nonZeros());
  275. VERIFY_IS_APPROX(m2, refM2);
  276. }
  277. }
  278. void test_eigen2_sparse_basic()
  279. {
  280. for(int i = 0; i < g_repeat; i++) {
  281. CALL_SUBTEST_1( sparse_basic(SparseMatrix<double>(8, 8)) );
  282. CALL_SUBTEST_2( sparse_basic(SparseMatrix<std::complex<double> >(16, 16)) );
  283. CALL_SUBTEST_1( sparse_basic(SparseMatrix<double>(33, 33)) );
  284. CALL_SUBTEST_3( sparse_basic(DynamicSparseMatrix<double>(8, 8)) );
  285. }
  286. }