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.
		
		
		
		
		
			
		
			
				
					
					
						
							323 lines
						
					
					
						
							8.8 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							323 lines
						
					
					
						
							8.8 KiB
						
					
					
				| 
 | |
| //g++ -O3 -g0 -DNDEBUG  sparse_product.cpp -I.. -I/home/gael/Coding/LinearAlgebra/mtl4/ -DDENSITY=0.005 -DSIZE=10000 && ./a.out | |
| //g++ -O3 -g0 -DNDEBUG  sparse_product.cpp -I.. -I/home/gael/Coding/LinearAlgebra/mtl4/ -DDENSITY=0.05 -DSIZE=2000 && ./a.out | |
| // -DNOGMM -DNOMTL -DCSPARSE | |
| // -I /home/gael/Coding/LinearAlgebra/CSparse/Include/ /home/gael/Coding/LinearAlgebra/CSparse/Lib/libcsparse.a | |
|  | |
| #include <typeinfo> | |
|  | |
| #ifndef SIZE | |
| #define SIZE 1000000 | |
| #endif | |
|  | |
| #ifndef NNZPERCOL | |
| #define NNZPERCOL 6 | |
| #endif | |
|  | |
| #ifndef REPEAT | |
| #define REPEAT 1 | |
| #endif | |
|  | |
| #include <algorithm> | |
| #include "BenchTimer.h" | |
| #include "BenchUtil.h" | |
| #include "BenchSparseUtil.h" | |
|  | |
| #ifndef NBTRIES | |
| #define NBTRIES 1 | |
| #endif | |
|  | |
| #define BENCH(X) \ | |
|   timer.reset(); \ | |
|   for (int _j=0; _j<NBTRIES; ++_j) { \ | |
|     timer.start(); \ | |
|     for (int _k=0; _k<REPEAT; ++_k) { \ | |
|         X  \ | |
|   } timer.stop(); } | |
|  | |
| // #ifdef MKL | |
| // | |
| // #include "mkl_types.h" | |
| // #include "mkl_spblas.h" | |
| // | |
| // template<typename Lhs,typename Rhs,typename Res> | |
| // void mkl_multiply(const Lhs& lhs, const Rhs& rhs, Res& res) | |
| // { | |
| //   char n = 'N'; | |
| //   float alpha = 1; | |
| //   char matdescra[6]; | |
| //   matdescra[0] = 'G'; | |
| //   matdescra[1] = 0; | |
| //   matdescra[2] = 0; | |
| //   matdescra[3] = 'C'; | |
| //   mkl_scscmm(&n, lhs.rows(), rhs.cols(), lhs.cols(), &alpha, matdescra, | |
| //              lhs._valuePtr(), lhs._innerIndexPtr(), lhs.outerIndexPtr(), | |
| //              pntre, b, &ldb, &beta, c, &ldc); | |
| // //   mkl_somatcopy('C', 'T', lhs.rows(), lhs.cols(), 1, | |
| // //                 lhs._valuePtr(), lhs.rows(), DST, dst_stride); | |
| // } | |
| // | |
| // #endif | |
|  | |
| 
 | |
| #ifdef CSPARSE | |
| cs* cs_sorted_multiply(const cs* a, const cs* b) | |
| { | |
| //   return cs_multiply(a,b); | |
|  | |
|   cs* A = cs_transpose(a, 1); | |
|   cs* B = cs_transpose(b, 1); | |
|   cs* D = cs_multiply(B,A);   /* D = B'*A' */ | |
|   cs_spfree (A) ; | |
|   cs_spfree (B) ; | |
|   cs_dropzeros (D) ;      /* drop zeros from D */ | |
|   cs* C = cs_transpose (D, 1) ;   /* C = D', so that C is sorted */ | |
|   cs_spfree (D) ; | |
|   return C; | |
| 
 | |
| //   cs* A = cs_transpose(a, 1); | |
| //   cs* C = cs_transpose(A, 1); | |
| //   return C; | |
| } | |
| 
 | |
| cs* cs_sorted_multiply2(const cs* a, const cs* b) | |
| { | |
|   cs* D = cs_multiply(a,b); | |
|   cs* E = cs_transpose(D,1); | |
|   cs_spfree(D); | |
|   cs* C = cs_transpose(E,1); | |
|   cs_spfree(E); | |
|   return C; | |
| } | |
| #endif | |
|  | |
| void bench_sort(); | |
| 
 | |
| int main(int argc, char *argv[]) | |
| { | |
| //   bench_sort(); | |
|  | |
|   int rows = SIZE; | |
|   int cols = SIZE; | |
|   float density = DENSITY; | |
| 
 | |
|   EigenSparseMatrix sm1(rows,cols), sm2(rows,cols), sm3(rows,cols), sm4(rows,cols); | |
| 
 | |
|   BenchTimer timer; | |
|   for (int nnzPerCol = NNZPERCOL; nnzPerCol>1; nnzPerCol/=1.1) | |
|   { | |
|     sm1.setZero(); | |
|     sm2.setZero(); | |
|     fillMatrix2(nnzPerCol, rows, cols, sm1); | |
|     fillMatrix2(nnzPerCol, rows, cols, sm2); | |
| //     std::cerr << "filling OK\n"; | |
|  | |
|     // dense matrices | |
|     #ifdef DENSEMATRIX | |
|     { | |
|       std::cout << "Eigen Dense\t" << nnzPerCol << "%\n"; | |
|       DenseMatrix m1(rows,cols), m2(rows,cols), m3(rows,cols); | |
|       eiToDense(sm1, m1); | |
|       eiToDense(sm2, m2); | |
| 
 | |
|       timer.reset(); | |
|       timer.start(); | |
|       for (int k=0; k<REPEAT; ++k) | |
|         m3 = m1 * m2; | |
|       timer.stop(); | |
|       std::cout << "   a * b:\t" << timer.value() << endl; | |
| 
 | |
|       timer.reset(); | |
|       timer.start(); | |
|       for (int k=0; k<REPEAT; ++k) | |
|         m3 = m1.transpose() * m2; | |
|       timer.stop(); | |
|       std::cout << "   a' * b:\t" << timer.value() << endl; | |
| 
 | |
|       timer.reset(); | |
|       timer.start(); | |
|       for (int k=0; k<REPEAT; ++k) | |
|         m3 = m1.transpose() * m2.transpose(); | |
|       timer.stop(); | |
|       std::cout << "   a' * b':\t" << timer.value() << endl; | |
| 
 | |
|       timer.reset(); | |
|       timer.start(); | |
|       for (int k=0; k<REPEAT; ++k) | |
|         m3 = m1 * m2.transpose(); | |
|       timer.stop(); | |
|       std::cout << "   a * b':\t" << timer.value() << endl; | |
|     } | |
|     #endif | |
|  | |
|     // eigen sparse matrices | |
|     { | |
|       std::cout << "Eigen sparse\t" << sm1.nonZeros()/(float(sm1.rows())*float(sm1.cols()))*100 << "% * " | |
|                 << sm2.nonZeros()/(float(sm2.rows())*float(sm2.cols()))*100 << "%\n"; | |
| 
 | |
|       BENCH(sm3 = sm1 * sm2; ) | |
|       std::cout << "   a * b:\t" << timer.value() << endl; | |
| 
 | |
| //       BENCH(sm3 = sm1.transpose() * sm2; ) | |
| //       std::cout << "   a' * b:\t" << timer.value() << endl; | |
| // // | |
| //       BENCH(sm3 = sm1.transpose() * sm2.transpose(); ) | |
| //       std::cout << "   a' * b':\t" << timer.value() << endl; | |
| // // | |
| //       BENCH(sm3 = sm1 * sm2.transpose(); ) | |
| //       std::cout << "   a * b' :\t" << timer.value() << endl; | |
|  | |
| 
 | |
| //       std::cout << "\n"; | |
| // | |
| //       BENCH( sm3._experimentalNewProduct(sm1, sm2); ) | |
| //       std::cout << "   a * b:\t" << timer.value() << endl; | |
| // | |
| //       BENCH(sm3._experimentalNewProduct(sm1.transpose(),sm2); ) | |
| //       std::cout << "   a' * b:\t" << timer.value() << endl; | |
| // // | |
| //       BENCH(sm3._experimentalNewProduct(sm1.transpose(),sm2.transpose()); ) | |
| //       std::cout << "   a' * b':\t" << timer.value() << endl; | |
| // // | |
| //       BENCH(sm3._experimentalNewProduct(sm1, sm2.transpose());) | |
| //       std::cout << "   a * b' :\t" << timer.value() << endl; | |
|     } | |
| 
 | |
|     // eigen dyn-sparse matrices | |
|     /*{ | |
|       DynamicSparseMatrix<Scalar> m1(sm1), m2(sm2), m3(sm3); | |
|       std::cout << "Eigen dyn-sparse\t" << m1.nonZeros()/(float(m1.rows())*float(m1.cols()))*100 << "% * " | |
|                 << m2.nonZeros()/(float(m2.rows())*float(m2.cols()))*100 << "%\n"; | |
|  | |
| //       timer.reset(); | |
| //       timer.start(); | |
|       BENCH(for (int k=0; k<REPEAT; ++k) m3 = m1 * m2;) | |
| //       timer.stop(); | |
|       std::cout << "   a * b:\t" << timer.value() << endl; | |
| //       std::cout << sm3 << "\n"; | |
|  | |
|       timer.reset(); | |
|       timer.start(); | |
| //       std::cerr << "transpose...\n"; | |
| //       EigenSparseMatrix sm4 = sm1.transpose(); | |
| //       std::cout << sm4.nonZeros() << " == " << sm1.nonZeros() << "\n"; | |
| //       exit(1); | |
| //       std::cerr << "transpose OK\n"; | |
| //       std::cout << sm1 << "\n\n" << sm1.transpose() << "\n\n" << sm4.transpose() << "\n\n"; | |
|       BENCH(for (int k=0; k<REPEAT; ++k) m3 = m1.transpose() * m2;) | |
| //       timer.stop(); | |
|       std::cout << "   a' * b:\t" << timer.value() << endl; | |
|  | |
| //       timer.reset(); | |
| //       timer.start(); | |
|       BENCH( for (int k=0; k<REPEAT; ++k) m3 = m1.transpose() * m2.transpose(); ) | |
| //       timer.stop(); | |
|       std::cout << "   a' * b':\t" << timer.value() << endl; | |
|  | |
| //       timer.reset(); | |
| //       timer.start(); | |
|       BENCH( for (int k=0; k<REPEAT; ++k) m3 = m1 * m2.transpose(); ) | |
| //       timer.stop(); | |
|       std::cout << "   a * b' :\t" << timer.value() << endl; | |
|     }*/ | |
| 
 | |
|     // CSparse | |
|     #ifdef CSPARSE | |
|     { | |
|       std::cout << "CSparse \t" << nnzPerCol << "%\n"; | |
|       cs *m1, *m2, *m3; | |
|       eiToCSparse(sm1, m1); | |
|       eiToCSparse(sm2, m2); | |
| 
 | |
|       BENCH( | |
|       { | |
|         m3 = cs_sorted_multiply(m1, m2); | |
|         if (!m3) | |
|         { | |
|           std::cerr << "cs_multiply failed\n"; | |
|         } | |
| //         cs_print(m3, 0); | |
|         cs_spfree(m3); | |
|       } | |
|       ); | |
| //       timer.stop(); | |
|       std::cout << "   a * b:\t" << timer.value() << endl; | |
| 
 | |
| //       BENCH( { m3 = cs_sorted_multiply2(m1, m2); cs_spfree(m3); } ); | |
| //       std::cout << "   a * b:\t" << timer.value() << endl; | |
|     } | |
|     #endif | |
|  | |
|     #ifndef NOUBLAS | |
|     { | |
|       std::cout << "ublas\t" << nnzPerCol << "%\n"; | |
|       UBlasSparse m1(rows,cols), m2(rows,cols), m3(rows,cols); | |
|       eiToUblas(sm1, m1); | |
|       eiToUblas(sm2, m2); | |
| 
 | |
|       BENCH(boost::numeric::ublas::prod(m1, m2, m3);); | |
|       std::cout << "   a * b:\t" << timer.value() << endl; | |
|     } | |
|     #endif | |
|  | |
|     // GMM++ | |
|     #ifndef NOGMM | |
|     { | |
|       std::cout << "GMM++ sparse\t" << nnzPerCol << "%\n"; | |
|       GmmDynSparse  gmmT3(rows,cols); | |
|       GmmSparse m1(rows,cols), m2(rows,cols), m3(rows,cols); | |
|       eiToGmm(sm1, m1); | |
|       eiToGmm(sm2, m2); | |
| 
 | |
|       BENCH(gmm::mult(m1, m2, gmmT3);); | |
|       std::cout << "   a * b:\t" << timer.value() << endl; | |
| 
 | |
| //       BENCH(gmm::mult(gmm::transposed(m1), m2, gmmT3);); | |
| //       std::cout << "   a' * b:\t" << timer.value() << endl; | |
| // | |
| //       if (rows<500) | |
| //       { | |
| //         BENCH(gmm::mult(gmm::transposed(m1), gmm::transposed(m2), gmmT3);); | |
| //         std::cout << "   a' * b':\t" << timer.value() << endl; | |
| // | |
| //         BENCH(gmm::mult(m1, gmm::transposed(m2), gmmT3);); | |
| //         std::cout << "   a * b':\t" << timer.value() << endl; | |
| //       } | |
| //       else | |
| //       { | |
| //         std::cout << "   a' * b':\t" << "forever" << endl; | |
| //         std::cout << "   a * b':\t" << "forever" << endl; | |
| //       } | |
|     } | |
|     #endif | |
|  | |
|     // MTL4 | |
|     #ifndef NOMTL | |
|     { | |
|       std::cout << "MTL4\t" << nnzPerCol << "%\n"; | |
|       MtlSparse m1(rows,cols), m2(rows,cols), m3(rows,cols); | |
|       eiToMtl(sm1, m1); | |
|       eiToMtl(sm2, m2); | |
| 
 | |
|       BENCH(m3 = m1 * m2;); | |
|       std::cout << "   a * b:\t" << timer.value() << endl; | |
| 
 | |
| //       BENCH(m3 = trans(m1) * m2;); | |
| //       std::cout << "   a' * b:\t" << timer.value() << endl; | |
| // | |
| //       BENCH(m3 = trans(m1) * trans(m2);); | |
| //       std::cout << "  a' * b':\t" << timer.value() << endl; | |
| // | |
| //       BENCH(m3 = m1 * trans(m2);); | |
| //       std::cout << "   a * b' :\t" << timer.value() << endl; | |
|     } | |
|     #endif | |
|  | |
|     std::cout << "\n\n"; | |
|   } | |
| 
 | |
|   return 0; | |
| } | |
| 
 | |
| 
 | |
| 
 |