diff --git a/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h b/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h index d4aa4738b..6bd0fa1ec 100644 --- a/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h +++ b/Eigen/src/SparseCore/ConservativeSparseSparseProduct.h @@ -126,6 +126,11 @@ static void conservative_sparse_sparse_product_impl(const Lhs& lhs, const Rhs& r namespace internal { + +// Helper template to generate new sparse matrix types +template +using WithStorageOrder = SparseMatrix; + template::Flags&RowMajorBit) ? RowMajor : ColMajor, int RhsStorageOrder = (traits::Flags&RowMajorBit) ? RowMajor : ColMajor, @@ -140,15 +145,15 @@ struct conservative_sparse_sparse_product_selector RowMajorMatrix; - typedef SparseMatrix ColMajorMatrixAux; - typedef typename sparse_eval::type ColMajorMatrix; + using RowMajorMatrix = WithStorageOrder; + using ColMajorMatrixAux = WithStorageOrder; // If the result is tall and thin (in the extreme case a column vector) // then it is faster to sort the coefficients inplace instead of transposing twice. // FIXME, the following heuristic is probably not very good. if(lhs.rows()>rhs.cols()) { + using ColMajorMatrix = typename sparse_eval::type; ColMajorMatrix resCol(lhs.rows(),rhs.cols()); // perform sorted insertion internal::conservative_sparse_sparse_product_impl(lhs, rhs, resCol, true); @@ -170,8 +175,8 @@ struct conservative_sparse_sparse_product_selector RowMajorRhs; - typedef SparseMatrix RowMajorRes; + using RowMajorRhs = WithStorageOrder; + using RowMajorRes = WithStorageOrder; RowMajorRhs rhsRow = rhs; RowMajorRes resRow(lhs.rows(), rhs.cols()); internal::conservative_sparse_sparse_product_impl(rhsRow, lhs, resRow); @@ -184,8 +189,8 @@ struct conservative_sparse_sparse_product_selector RowMajorLhs; - typedef SparseMatrix RowMajorRes; + using RowMajorLhs = WithStorageOrder; + using RowMajorRes = WithStorageOrder; RowMajorLhs lhsRow = lhs; RowMajorRes resRow(lhs.rows(), rhs.cols()); internal::conservative_sparse_sparse_product_impl(rhs, lhsRow, resRow); @@ -198,9 +203,9 @@ struct conservative_sparse_sparse_product_selector RowMajorMatrix; - RowMajorMatrix resRow(lhs.rows(), rhs.cols()); - internal::conservative_sparse_sparse_product_impl(rhs, lhs, resRow); + using RowMajorRes = WithStorageOrder; + RowMajorRes resRow(lhs.rows(), rhs.cols()); + internal::conservative_sparse_sparse_product_impl(rhs, lhs, resRow); res = resRow; } }; @@ -213,9 +218,9 @@ struct conservative_sparse_sparse_product_selector ColMajorMatrix; - ColMajorMatrix resCol(lhs.rows(), rhs.cols()); - internal::conservative_sparse_sparse_product_impl(lhs, rhs, resCol); + using ColMajorRes = WithStorageOrder; + ColMajorRes resCol(lhs.rows(), rhs.cols()); + internal::conservative_sparse_sparse_product_impl(lhs, rhs, resCol); res = resCol; } }; @@ -225,8 +230,8 @@ struct conservative_sparse_sparse_product_selector ColMajorLhs; - typedef SparseMatrix ColMajorRes; + using ColMajorLhs = WithStorageOrder; + using ColMajorRes = WithStorageOrder; ColMajorLhs lhsCol = lhs; ColMajorRes resCol(lhs.rows(), rhs.cols()); internal::conservative_sparse_sparse_product_impl(lhsCol, rhs, resCol); @@ -239,8 +244,8 @@ struct conservative_sparse_sparse_product_selector ColMajorRhs; - typedef SparseMatrix ColMajorRes; + using ColMajorRhs = WithStorageOrder; + using ColMajorRes = WithStorageOrder; ColMajorRhs rhsCol = rhs; ColMajorRes resCol(lhs.rows(), rhs.cols()); internal::conservative_sparse_sparse_product_impl(lhs, rhsCol, resCol); @@ -253,12 +258,12 @@ struct conservative_sparse_sparse_product_selector RowMajorMatrix; - typedef SparseMatrix ColMajorMatrix; - RowMajorMatrix resRow(lhs.rows(),rhs.cols()); - internal::conservative_sparse_sparse_product_impl(rhs, lhs, resRow); + using ColMajorRes = WithStorageOrder; + using RowMajorRes = WithStorageOrder; + RowMajorRes resRow(lhs.rows(),rhs.cols()); + internal::conservative_sparse_sparse_product_impl(rhs, lhs, resRow); // sort the non zeros: - ColMajorMatrix resCol(resRow); + ColMajorRes resCol(resRow); res = resCol; } }; @@ -319,7 +324,7 @@ struct sparse_sparse_to_dense_product_selector ColMajorLhs; + using ColMajorLhs = WithStorageOrder; ColMajorLhs lhsCol(lhs); internal::sparse_sparse_to_dense_product_impl(lhsCol, rhs, res); } @@ -330,7 +335,7 @@ struct sparse_sparse_to_dense_product_selector ColMajorRhs; + using ColMajorRhs = WithStorageOrder; ColMajorRhs rhsCol(rhs); internal::sparse_sparse_to_dense_product_impl(lhs, rhsCol, res); } diff --git a/test/sparse.h b/test/sparse.h index 67cc06ebf..663aaee00 100644 --- a/test/sparse.h +++ b/test/sparse.h @@ -59,7 +59,8 @@ initSparse(double density, sparseMat.setZero(); //sparseMat.reserve(int(refMat.rows()*refMat.cols()*density)); sparseMat.reserve(VectorXi::Constant(IsRowMajor ? refMat.rows() : refMat.cols(), int((1.5*density)*(IsRowMajor?refMat.cols():refMat.rows())))); - + + Index insert_count = 0; for(Index j=0; jpush_back(Matrix (ai,aj)); } @@ -97,6 +99,9 @@ initSparse(double density, zeroCoords->push_back(Matrix (ai,aj)); } refMat(ai,aj) = v; + + // make sure we only insert as many as the sparse matrix supports + if(insert_count == NumTraits::highest()) return; } } //sparseMat.finalize(); diff --git a/test/sparse_product.cpp b/test/sparse_product.cpp index 6e85f6914..488a3920c 100644 --- a/test/sparse_product.cpp +++ b/test/sparse_product.cpp @@ -461,6 +461,58 @@ void test_mixing_types() VERIFY_IS_APPROX( dC2 = sC1 * dR1.col(0), dC3 = sC1 * dR1.template cast().col(0) ); } +// Test mixed storage types +template +void test_mixed_storage_imp() { + typedef float Real; + typedef Matrix DenseMat; + + // Case: Large inputs but small result + { + SparseMatrix A(8, 512); + SparseMatrix B(512, 8); + DenseMat refA(8, 512); + DenseMat refB(512, 8); + + initSparse(0.1, refA, A); + initSparse(0.1, refB, B); + + SparseMatrix result; + SparseMatrix result_large; + DenseMat refResult; + + VERIFY_IS_APPROX( result = (A * B), refResult = refA * refB ); + } + + // Case: Small input but large result + { + SparseMatrix A(127, 8); + SparseMatrix B(8, 127); + DenseMat refA(127, 8); + DenseMat refB(8, 127); + + initSparse(0.01, refA, A); + initSparse(0.01, refB, B); + + SparseMatrix result; + SparseMatrix result_large; + DenseMat refResult; + + VERIFY_IS_APPROX( result = (A * B), refResult = refA * refB ); + } +} + +void test_mixed_storage() { + test_mixed_storage_imp(); + test_mixed_storage_imp(); + test_mixed_storage_imp(); + test_mixed_storage_imp(); + test_mixed_storage_imp(); + test_mixed_storage_imp(); + test_mixed_storage_imp(); + test_mixed_storage_imp(); +} + EIGEN_DECLARE_TEST(sparse_product) { for(int i = 0; i < g_repeat; i++) { @@ -473,5 +525,6 @@ EIGEN_DECLARE_TEST(sparse_product) CALL_SUBTEST_4( (sparse_product_regression_test, Matrix >()) ); CALL_SUBTEST_5( (test_mixing_types()) ); + CALL_SUBTEST_5( (test_mixed_storage()) ); } }