1 // This file is part of Eigen, a lightweight C++ template library 2 // for linear algebra. 3 // 4 // Copyright (C) 2008-2011 Gael Guennebaud <gael.guennebaud (at) inria.fr> 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 10 #include "sparse.h" 11 12 template<typename SparseMatrixType, typename DenseMatrix, bool IsRowMajor=SparseMatrixType::IsRowMajor> struct test_outer; 13 14 template<typename SparseMatrixType, typename DenseMatrix> struct test_outer<SparseMatrixType,DenseMatrix,false> { 15 static void run(SparseMatrixType& m2, SparseMatrixType& m4, DenseMatrix& refMat2, DenseMatrix& refMat4) { 16 int c = internal::random(0,m2.cols()-1); 17 int c1 = internal::random(0,m2.cols()-1); 18 VERIFY_IS_APPROX(m4=m2.col(c)*refMat2.col(c1).transpose(), refMat4=refMat2.col(c)*refMat2.col(c1).transpose()); 19 VERIFY_IS_APPROX(m4=refMat2.col(c1)*m2.col(c).transpose(), refMat4=refMat2.col(c1)*refMat2.col(c).transpose()); 20 } 21 }; 22 23 template<typename SparseMatrixType, typename DenseMatrix> struct test_outer<SparseMatrixType,DenseMatrix,true> { 24 static void run(SparseMatrixType& m2, SparseMatrixType& m4, DenseMatrix& refMat2, DenseMatrix& refMat4) { 25 int r = internal::random(0,m2.rows()-1); 26 int c1 = internal::random(0,m2.cols()-1); 27 VERIFY_IS_APPROX(m4=m2.row(r).transpose()*refMat2.col(c1).transpose(), refMat4=refMat2.row(r).transpose()*refMat2.col(c1).transpose()); 28 VERIFY_IS_APPROX(m4=refMat2.col(c1)*m2.row(r), refMat4=refMat2.col(c1)*refMat2.row(r)); 29 } 30 }; 31 32 // (m2,m4,refMat2,refMat4,dv1); 33 // VERIFY_IS_APPROX(m4=m2.innerVector(c)*dv1.transpose(), refMat4=refMat2.colVector(c)*dv1.transpose()); 34 // VERIFY_IS_APPROX(m4=dv1*mcm.col(c).transpose(), refMat4=dv1*refMat2.col(c).transpose()); 35 36 template<typename SparseMatrixType> void sparse_product() 37 { 38 typedef typename SparseMatrixType::Index Index; 39 Index n = 100; 40 const Index rows = internal::random<int>(1,n); 41 const Index cols = internal::random<int>(1,n); 42 const Index depth = internal::random<int>(1,n); 43 typedef typename SparseMatrixType::Scalar Scalar; 44 enum { Flags = SparseMatrixType::Flags }; 45 46 double density = (std::max)(8./(rows*cols), 0.01); 47 typedef Matrix<Scalar,Dynamic,Dynamic> DenseMatrix; 48 typedef Matrix<Scalar,Dynamic,1> DenseVector; 49 50 Scalar s1 = internal::random<Scalar>(); 51 Scalar s2 = internal::random<Scalar>(); 52 53 // test matrix-matrix product 54 { 55 DenseMatrix refMat2 = DenseMatrix::Zero(rows, depth); 56 DenseMatrix refMat2t = DenseMatrix::Zero(depth, rows); 57 DenseMatrix refMat3 = DenseMatrix::Zero(depth, cols); 58 DenseMatrix refMat3t = DenseMatrix::Zero(cols, depth); 59 DenseMatrix refMat4 = DenseMatrix::Zero(rows, cols); 60 DenseMatrix refMat4t = DenseMatrix::Zero(cols, rows); 61 DenseMatrix refMat5 = DenseMatrix::Random(depth, cols); 62 DenseMatrix refMat6 = DenseMatrix::Random(rows, rows); 63 DenseMatrix dm4 = DenseMatrix::Zero(rows, rows); 64 // DenseVector dv1 = DenseVector::Random(rows); 65 SparseMatrixType m2 (rows, depth); 66 SparseMatrixType m2t(depth, rows); 67 SparseMatrixType m3 (depth, cols); 68 SparseMatrixType m3t(cols, depth); 69 SparseMatrixType m4 (rows, cols); 70 SparseMatrixType m4t(cols, rows); 71 SparseMatrixType m6(rows, rows); 72 initSparse(density, refMat2, m2); 73 initSparse(density, refMat2t, m2t); 74 initSparse(density, refMat3, m3); 75 initSparse(density, refMat3t, m3t); 76 initSparse(density, refMat4, m4); 77 initSparse(density, refMat4t, m4t); 78 initSparse(density, refMat6, m6); 79 80 // int c = internal::random<int>(0,depth-1); 81 82 // sparse * sparse 83 VERIFY_IS_APPROX(m4=m2*m3, refMat4=refMat2*refMat3); 84 VERIFY_IS_APPROX(m4=m2t.transpose()*m3, refMat4=refMat2t.transpose()*refMat3); 85 VERIFY_IS_APPROX(m4=m2t.transpose()*m3t.transpose(), refMat4=refMat2t.transpose()*refMat3t.transpose()); 86 VERIFY_IS_APPROX(m4=m2*m3t.transpose(), refMat4=refMat2*refMat3t.transpose()); 87 88 VERIFY_IS_APPROX(m4 = m2*m3/s1, refMat4 = refMat2*refMat3/s1); 89 VERIFY_IS_APPROX(m4 = m2*m3*s1, refMat4 = refMat2*refMat3*s1); 90 VERIFY_IS_APPROX(m4 = s2*m2*m3*s1, refMat4 = s2*refMat2*refMat3*s1); 91 92 VERIFY_IS_APPROX(m4=(m2*m3).pruned(0), refMat4=refMat2*refMat3); 93 VERIFY_IS_APPROX(m4=(m2t.transpose()*m3).pruned(0), refMat4=refMat2t.transpose()*refMat3); 94 VERIFY_IS_APPROX(m4=(m2t.transpose()*m3t.transpose()).pruned(0), refMat4=refMat2t.transpose()*refMat3t.transpose()); 95 VERIFY_IS_APPROX(m4=(m2*m3t.transpose()).pruned(0), refMat4=refMat2*refMat3t.transpose()); 96 97 // test aliasing 98 m4 = m2; refMat4 = refMat2; 99 VERIFY_IS_APPROX(m4=m4*m3, refMat4=refMat4*refMat3); 100 101 // sparse * dense 102 VERIFY_IS_APPROX(dm4=m2*refMat3, refMat4=refMat2*refMat3); 103 VERIFY_IS_APPROX(dm4=m2*refMat3t.transpose(), refMat4=refMat2*refMat3t.transpose()); 104 VERIFY_IS_APPROX(dm4=m2t.transpose()*refMat3, refMat4=refMat2t.transpose()*refMat3); 105 VERIFY_IS_APPROX(dm4=m2t.transpose()*refMat3t.transpose(), refMat4=refMat2t.transpose()*refMat3t.transpose()); 106 107 VERIFY_IS_APPROX(dm4=m2*(refMat3+refMat3), refMat4=refMat2*(refMat3+refMat3)); 108 VERIFY_IS_APPROX(dm4=m2t.transpose()*(refMat3+refMat5)*0.5, refMat4=refMat2t.transpose()*(refMat3+refMat5)*0.5); 109 110 // dense * sparse 111 VERIFY_IS_APPROX(dm4=refMat2*m3, refMat4=refMat2*refMat3); 112 VERIFY_IS_APPROX(dm4=refMat2*m3t.transpose(), refMat4=refMat2*refMat3t.transpose()); 113 VERIFY_IS_APPROX(dm4=refMat2t.transpose()*m3, refMat4=refMat2t.transpose()*refMat3); 114 VERIFY_IS_APPROX(dm4=refMat2t.transpose()*m3t.transpose(), refMat4=refMat2t.transpose()*refMat3t.transpose()); 115 116 // sparse * dense and dense * sparse outer product 117 test_outer<SparseMatrixType,DenseMatrix>::run(m2,m4,refMat2,refMat4); 118 119 VERIFY_IS_APPROX(m6=m6*m6, refMat6=refMat6*refMat6); 120 } 121 122 // test matrix - diagonal product 123 { 124 DenseMatrix refM2 = DenseMatrix::Zero(rows, rows); 125 DenseMatrix refM3 = DenseMatrix::Zero(rows, rows); 126 DiagonalMatrix<Scalar,Dynamic> d1(DenseVector::Random(rows)); 127 SparseMatrixType m2(rows, rows); 128 SparseMatrixType m3(rows, rows); 129 initSparse<Scalar>(density, refM2, m2); 130 initSparse<Scalar>(density, refM3, m3); 131 VERIFY_IS_APPROX(m3=m2*d1, refM3=refM2*d1); 132 VERIFY_IS_APPROX(m3=m2.transpose()*d1, refM3=refM2.transpose()*d1); 133 VERIFY_IS_APPROX(m3=d1*m2, refM3=d1*refM2); 134 VERIFY_IS_APPROX(m3=d1*m2.transpose(), refM3=d1 * refM2.transpose()); 135 } 136 137 // test self adjoint products 138 { 139 DenseMatrix b = DenseMatrix::Random(rows, rows); 140 DenseMatrix x = DenseMatrix::Random(rows, rows); 141 DenseMatrix refX = DenseMatrix::Random(rows, rows); 142 DenseMatrix refUp = DenseMatrix::Zero(rows, rows); 143 DenseMatrix refLo = DenseMatrix::Zero(rows, rows); 144 DenseMatrix refS = DenseMatrix::Zero(rows, rows); 145 SparseMatrixType mUp(rows, rows); 146 SparseMatrixType mLo(rows, rows); 147 SparseMatrixType mS(rows, rows); 148 do { 149 initSparse<Scalar>(density, refUp, mUp, ForceRealDiag|/*ForceNonZeroDiag|*/MakeUpperTriangular); 150 } while (refUp.isZero()); 151 refLo = refUp.adjoint(); 152 mLo = mUp.adjoint(); 153 refS = refUp + refLo; 154 refS.diagonal() *= 0.5; 155 mS = mUp + mLo; 156 // TODO be able to address the diagonal.... 157 for (int k=0; k<mS.outerSize(); ++k) 158 for (typename SparseMatrixType::InnerIterator it(mS,k); it; ++it) 159 if (it.index() == k) 160 it.valueRef() *= 0.5; 161 162 VERIFY_IS_APPROX(refS.adjoint(), refS); 163 VERIFY_IS_APPROX(mS.adjoint(), mS); 164 VERIFY_IS_APPROX(mS, refS); 165 VERIFY_IS_APPROX(x=mS*b, refX=refS*b); 166 167 VERIFY_IS_APPROX(x=mUp.template selfadjointView<Upper>()*b, refX=refS*b); 168 VERIFY_IS_APPROX(x=mLo.template selfadjointView<Lower>()*b, refX=refS*b); 169 VERIFY_IS_APPROX(x=mS.template selfadjointView<Upper|Lower>()*b, refX=refS*b); 170 } 171 } 172 173 // New test for Bug in SparseTimeDenseProduct 174 template<typename SparseMatrixType, typename DenseMatrixType> void sparse_product_regression_test() 175 { 176 // This code does not compile with afflicted versions of the bug 177 SparseMatrixType sm1(3,2); 178 DenseMatrixType m2(2,2); 179 sm1.setZero(); 180 m2.setZero(); 181 182 DenseMatrixType m3 = sm1*m2; 183 184 185 // This code produces a segfault with afflicted versions of another SparseTimeDenseProduct 186 // bug 187 188 SparseMatrixType sm2(20000,2); 189 sm2.setZero(); 190 DenseMatrixType m4(sm2*m2); 191 192 VERIFY_IS_APPROX( m4(0,0), 0.0 ); 193 } 194 195 void test_sparse_product() 196 { 197 for(int i = 0; i < g_repeat; i++) { 198 CALL_SUBTEST_1( (sparse_product<SparseMatrix<double,ColMajor> >()) ); 199 CALL_SUBTEST_1( (sparse_product<SparseMatrix<double,RowMajor> >()) ); 200 CALL_SUBTEST_2( (sparse_product<SparseMatrix<std::complex<double>, ColMajor > >()) ); 201 CALL_SUBTEST_2( (sparse_product<SparseMatrix<std::complex<double>, RowMajor > >()) ); 202 CALL_SUBTEST_4( (sparse_product_regression_test<SparseMatrix<double,RowMajor>, Matrix<double, Dynamic, Dynamic, RowMajor> >()) ); 203 } 204 } 205