// New test for Bug in SparseTimeDenseProduct template<typename SparseMatrixType, typename DenseMatrixType> void sparse_product_regression_test() { // This code does not compile with afflicted versions of the bug SparseMatrixType sm1(3,2); DenseMatrixType m2(2,2); sm1.setZero(); m2.setZero(); DenseMatrixType m3 = sm1*m2; // This code produces a segfault with afflicted versions of another SparseTimeDenseProduct // bug SparseMatrixType sm2(20000,2); sm2.setZero(); DenseMatrixType m4(sm2*m2); VERIFY_IS_APPROX( m4(0,0), 0.0 ); }
Int_t main(Int_t argc, Char_t *argv[]) { ROOT::Mpi::TEnvironment env(argc, argv); ROOT::Mpi::TIntraCommunicator world; // MpiInitTest(world, 2, ROOT::Mpi::GreaterIqual); TMatrixT<Double_t> mResult; TMatrixT<Double_t> m1(rowm1, colm1); TMatrixT<Double_t> m2(rowm2, colm2); TMatrixT<Double_t> m1square(side, side); TMatrixT<Double_t> m2square(side, side); for (Int_t i = 0; i < rowm1; i++) for (Int_t j = 0; j < colm1; j++) m1[i][j] = i + j; for (Int_t i = 0; i < rowm2; i++) for (Int_t j = 0; j < colm2; j++) m2[i][j] = j; for (Int_t i = 0; i < side; i++) for (Int_t j = 0; j < side; j++) { m1square[i][j] = j; m2square[i][j] = i; } /////////////////////////////////////////////// //Testing methdos with results in single Rank// /////////////////////////////////////////////// ROOT::Mpi::Math::TMatrixTWrapper<Double_t> mul(m1); mul.Mult(m2, root); ROOT::Mpi::Math::TMatrixTWrapper<Double_t> add(m1square); add.Addition(m2square, root); ROOT::Mpi::Math::TMatrixTWrapper<Double_t> sub(m1square); sub.Subtraction(m2square, root); ROOT::Mpi::Math::TMatrixTWrapper<Double_t> trans(m2); trans.Transpose(root); if (world.Rank() == root) { mul.GetResult(mResult); MpiCompareTMatrixTest(mResult, m1 * m2, world.Rank(), "Matrix Multiplication Single"); add.GetResult(mResult); MpiCompareTMatrixTest(mResult, m1square + m2square, world.Rank(), "Matrix Addition Single"); sub.GetResult(mResult); MpiCompareTMatrixTest(mResult, m1square - m2square, world.Rank(), "Matrix Subtraction Single"); trans.GetResult(mResult); MpiCompareTMatrixTest(mResult, TMatrixT<Double_t>(m2.GetNcols(), m2.GetNrows()).Transpose(m2), world.Rank(), "Matrix Transpose Single"); } /////////////////////////////////////////////// //Testing methdos with results in all ranks // /////////////////////////////////////////////// ROOT::Mpi::Math::TMatrixTWrapper<Double_t> mulAll(m1);//return the results in all ranks mulAll.Mult(m2); mulAll.GetResult(mResult); MpiCompareTMatrixTest(mResult, m1 * m2, world.Rank(), "Matrix Multiplication All"); ROOT::Mpi::Math::TMatrixTWrapper<Double_t> addAll(m1square); addAll.Addition(m2square); ROOT::Mpi::Math::TMatrixTWrapper<Double_t> subAll(m1square); subAll.Subtraction(m2square); ROOT::Mpi::Math::TMatrixTWrapper<Double_t> transAll(m2); transAll.Transpose(); addAll.GetResult(mResult); MpiCompareTMatrixTest(mResult, m1square + m2square, world.Rank(), "Matrix Addition All"); subAll.GetResult(mResult); MpiCompareTMatrixTest(mResult, m1square - m2square, world.Rank(), "Matrix Subtraction All"); transAll.GetResult(mResult); MpiCompareTMatrixTest(mResult, TMatrixT<Double_t>(m2.GetNcols(), m2.GetNrows()).Transpose(m2), world.Rank(), "Matrix Transpose All"); ////////////////////////////////////////////////// //Testing methdos with multiple matrices types // ////////////////////////////////////////////////// THilbertMatrixT<Double_t> him(side, side); TMatrixTSparse<Double_t> sm1(rowm1, colm1); TMatrixTSparse<Double_t> sm2(rowm2, colm2); TMatrixTFlat<Double_t> fm1(m1); TMatrixTFlat<Double_t> fm2(m2); TMatrixTSparse<Double_t> smResult; for (Int_t i = 0; i < rowm1; i++) for (Int_t j = 0; j < colm1; j++) { sm1[i][j] = i * j; } for (Int_t i = 0; i < rowm2; i++) for (Int_t j = 0; j < colm2; j++) { sm2[i][j] = i * j; } ROOT::Mpi::Math::TMatrixTWrapper<Double_t> mulHim(m1square);//return the results in all ranks mulHim.Mult(him); mulHim.GetResult(mResult); MpiCompareTMatrixTest(mResult, m1square * TMatrixT<Double_t>(him), world.Rank(), "Matrix Multiplication HilbertMatrix"); ROOT::Mpi::Math::TMatrixTWrapper<Double_t> mulHim2(him);//return the results in all ranks mulHim2.Mult(m1square); mulHim2.GetResult(mResult); MpiCompareTMatrixTest(mResult, TMatrixT<Double_t>(him)*m1square, world.Rank(), "Matrix Multiplication HilbertMatrix In Constructor"); ROOT::Mpi::Math::TMatrixTWrapper<Double_t> mulSm(m1);//return the results in all ranks mulSm.Mult(sm2); mulSm.GetResult(smResult); MpiCompareTMatrixTest(smResult, m1 * sm2, world.Rank(), "Matrix Multiplication SparseMatrix"); ROOT::Mpi::Math::TMatrixTWrapper<Double_t> mulSm2(sm1);//return the results in all ranks mulSm2.Mult(m2); mulSm2.GetResult(smResult); MpiCompareTMatrixTest(smResult, sm1 * m2, world.Rank(), "Matrix Multiplication SparseMatrix In Constructor"); // ROOT::Mpi::Math::TMatrixTWrapper<Double_t> mulFm(m1);//return the results in all ranks mulFm.Mult(fm2); mulFm.GetResult(mResult); MpiCompareTMatrixTest(mResult, m1 * TMatrixT<Double_t>(fm2.GetMatrix()->GetNrows(), fm2.GetMatrix()->GetNcols(), fm2.GetMatrix()->GetMatrixArray()), world.Rank(), "Matrix Multiplication FlatMatrix"); ROOT::Mpi::Math::TMatrixTWrapper<Double_t> mulFm2(fm1);//return the results in all ranks mulFm2.Mult(m2); mulFm2.GetResult(mResult); //NOTE fm matrix have data from m2, is the same tell m1*m2, just change the representation in memory MpiCompareTMatrixTest(mResult, m1 * m2, world.Rank(), "Matrix Multiplication FlatMatrix In Constructor"); TVectorT<Double_t> vec(rowv); for (Int_t i = 0; i < rowv; i++) vec[i] = i; ROOT::Mpi::Math::TMatrixTWrapper<Double_t> mulVec(m1);//return the results in all ranks mulVec.Mult(vec); mulVec.GetResult(mResult); TMatrixT<Double_t> mr((m1 * vec).GetNrows(), 1, (m1 * vec).GetMatrixArray()); // mResult.Print(); // mr.Print(); MpiCompareTMatrixTest(mResult, mr, world.Rank(), "Matrix Multiplication with Vector"); return 0; }
template<typename MatrixType> void basicStuff(const MatrixType& m) { typedef typename MatrixType::Index Index; typedef typename MatrixType::Scalar Scalar; typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> VectorType; typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> SquareMatrixType; Index rows = m.rows(); Index cols = m.cols(); // this test relies a lot on Random.h, and there's not much more that we can do // to test it, hence I consider that we will have tested Random.h MatrixType m1 = MatrixType::Random(rows, cols), m2 = MatrixType::Random(rows, cols), m3(rows, cols), mzero = MatrixType::Zero(rows, cols), square = Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime>::Random(rows, rows); VectorType v1 = VectorType::Random(rows), vzero = VectorType::Zero(rows); SquareMatrixType sm1 = SquareMatrixType::Random(rows,rows), sm2(rows,rows); Scalar x = 0; while(x == Scalar(0)) x = internal::random<Scalar>(); Index r = internal::random<Index>(0, rows-1), c = internal::random<Index>(0, cols-1); m1.coeffRef(r,c) = x; VERIFY_IS_APPROX(x, m1.coeff(r,c)); m1(r,c) = x; VERIFY_IS_APPROX(x, m1(r,c)); v1.coeffRef(r) = x; VERIFY_IS_APPROX(x, v1.coeff(r)); v1(r) = x; VERIFY_IS_APPROX(x, v1(r)); v1[r] = x; VERIFY_IS_APPROX(x, v1[r]); VERIFY_IS_APPROX( v1, v1); VERIFY_IS_NOT_APPROX( v1, 2*v1); VERIFY_IS_MUCH_SMALLER_THAN( vzero, v1); VERIFY_IS_MUCH_SMALLER_THAN( vzero, v1.squaredNorm()); VERIFY_IS_NOT_MUCH_SMALLER_THAN(v1, v1); VERIFY_IS_APPROX( vzero, v1-v1); VERIFY_IS_APPROX( m1, m1); VERIFY_IS_NOT_APPROX( m1, 2*m1); VERIFY_IS_MUCH_SMALLER_THAN( mzero, m1); VERIFY_IS_NOT_MUCH_SMALLER_THAN(m1, m1); VERIFY_IS_APPROX( mzero, m1-m1); // always test operator() on each read-only expression class, // in order to check const-qualifiers. // indeed, if an expression class (here Zero) is meant to be read-only, // hence has no _write() method, the corresponding MatrixBase method (here zero()) // should return a const-qualified object so that it is the const-qualified // operator() that gets called, which in turn calls _read(). VERIFY_IS_MUCH_SMALLER_THAN(MatrixType::Zero(rows,cols)(r,c), static_cast<Scalar>(1)); // now test copying a row-vector into a (column-)vector and conversely. square.col(r) = square.row(r).eval(); Matrix<Scalar, 1, MatrixType::RowsAtCompileTime> rv(rows); Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> cv(rows); rv = square.row(r); cv = square.col(r); VERIFY_IS_APPROX(rv, cv.transpose()); if(cols!=1 && rows!=1 && MatrixType::SizeAtCompileTime!=Dynamic) { VERIFY_RAISES_ASSERT(m1 = (m2.block(0,0, rows-1, cols-1))); } if(cols!=1 && rows!=1) { VERIFY_RAISES_ASSERT(m1[0]); VERIFY_RAISES_ASSERT((m1+m1)[0]); } VERIFY_IS_APPROX(m3 = m1,m1); MatrixType m4; VERIFY_IS_APPROX(m4 = m1,m1); m3.real() = m1.real(); VERIFY_IS_APPROX(static_cast<const MatrixType&>(m3).real(), static_cast<const MatrixType&>(m1).real()); VERIFY_IS_APPROX(static_cast<const MatrixType&>(m3).real(), m1.real()); // check == / != operators VERIFY(m1==m1); VERIFY(m1!=m2); VERIFY(!(m1==m2)); VERIFY(!(m1!=m1)); m1 = m2; VERIFY(m1==m2); VERIFY(!(m1!=m2)); // check automatic transposition sm2.setZero(); for(typename MatrixType::Index i=0;i<rows;++i) sm2.col(i) = sm1.row(i); VERIFY_IS_APPROX(sm2,sm1.transpose()); sm2.setZero(); for(typename MatrixType::Index i=0;i<rows;++i) sm2.col(i).noalias() = sm1.row(i); VERIFY_IS_APPROX(sm2,sm1.transpose()); sm2.setZero(); for(typename MatrixType::Index i=0;i<rows;++i) sm2.col(i).noalias() += sm1.row(i); VERIFY_IS_APPROX(sm2,sm1.transpose()); sm2.setZero(); for(typename MatrixType::Index i=0;i<rows;++i) sm2.col(i).noalias() -= sm1.row(i); VERIFY_IS_APPROX(sm2,-sm1.transpose()); // check ternary usage { bool b = internal::random<int>(0,10)>5; m3 = b ? m1 : m2; if(b) VERIFY_IS_APPROX(m3,m1); else VERIFY_IS_APPROX(m3,m2); m3 = b ? -m1 : m2; if(b) VERIFY_IS_APPROX(m3,-m1); else VERIFY_IS_APPROX(m3,m2); m3 = b ? m1 : -m2; if(b) VERIFY_IS_APPROX(m3,m1); else VERIFY_IS_APPROX(m3,-m2); } }
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); // timer.reset(); // timer.start(); // for (int k=0; k<REPEAT; ++k) BENCH( { m3 = cs_sorted_multiply(m1, m2); if (!m3) { std::cerr << "cs_multiply failed\n"; // break; } // 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; }