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) 2006-2008 Benoit Jacob <jacob.benoit.1 (at) 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 10 #include "main.h" 11 #include <Eigen/Array> 12 #include <Eigen/QR> 13 14 template<typename Derived1, typename Derived2> 15 bool areNotApprox(const MatrixBase<Derived1>& m1, const MatrixBase<Derived2>& m2, typename Derived1::RealScalar epsilon = precision<typename Derived1::RealScalar>()) 16 { 17 return !((m1-m2).cwise().abs2().maxCoeff() < epsilon * epsilon 18 * std::max(m1.cwise().abs2().maxCoeff(), m2.cwise().abs2().maxCoeff())); 19 } 20 21 template<typename MatrixType> void product(const MatrixType& m) 22 { 23 /* this test covers the following files: 24 Identity.h Product.h 25 */ 26 27 typedef typename MatrixType::Scalar Scalar; 28 typedef typename NumTraits<Scalar>::FloatingPoint FloatingPoint; 29 typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> RowVectorType; 30 typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, 1> ColVectorType; 31 typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> RowSquareMatrixType; 32 typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, MatrixType::ColsAtCompileTime> ColSquareMatrixType; 33 typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::ColsAtCompileTime, 34 MatrixType::Options^RowMajor> OtherMajorMatrixType; 35 36 int rows = m.rows(); 37 int cols = m.cols(); 38 39 // this test relies a lot on Random.h, and there's not much more that we can do 40 // to test it, hence I consider that we will have tested Random.h 41 MatrixType m1 = MatrixType::Random(rows, cols), 42 m2 = MatrixType::Random(rows, cols), 43 m3(rows, cols); 44 RowSquareMatrixType 45 identity = RowSquareMatrixType::Identity(rows, rows), 46 square = RowSquareMatrixType::Random(rows, rows), 47 res = RowSquareMatrixType::Random(rows, rows); 48 ColSquareMatrixType 49 square2 = ColSquareMatrixType::Random(cols, cols), 50 res2 = ColSquareMatrixType::Random(cols, cols); 51 RowVectorType v1 = RowVectorType::Random(rows); 52 ColVectorType vc2 = ColVectorType::Random(cols), vcres(cols); 53 OtherMajorMatrixType tm1 = m1; 54 55 Scalar s1 = ei_random<Scalar>(); 56 57 int r = ei_random<int>(0, rows-1), 58 c = ei_random<int>(0, cols-1); 59 60 // begin testing Product.h: only associativity for now 61 // (we use Transpose.h but this doesn't count as a test for it) 62 63 VERIFY_IS_APPROX((m1*m1.transpose())*m2, m1*(m1.transpose()*m2)); 64 m3 = m1; 65 m3 *= m1.transpose() * m2; 66 VERIFY_IS_APPROX(m3, m1 * (m1.transpose()*m2)); 67 VERIFY_IS_APPROX(m3, m1.lazy() * (m1.transpose()*m2)); 68 69 // continue testing Product.h: distributivity 70 VERIFY_IS_APPROX(square*(m1 + m2), square*m1+square*m2); 71 VERIFY_IS_APPROX(square*(m1 - m2), square*m1-square*m2); 72 73 // continue testing Product.h: compatibility with ScalarMultiple.h 74 VERIFY_IS_APPROX(s1*(square*m1), (s1*square)*m1); 75 VERIFY_IS_APPROX(s1*(square*m1), square*(m1*s1)); 76 77 // again, test operator() to check const-qualification 78 s1 += (square.lazy() * m1)(r,c); 79 80 // test Product.h together with Identity.h 81 VERIFY_IS_APPROX(v1, identity*v1); 82 VERIFY_IS_APPROX(v1.transpose(), v1.transpose() * identity); 83 // again, test operator() to check const-qualification 84 VERIFY_IS_APPROX(MatrixType::Identity(rows, cols)(r,c), static_cast<Scalar>(r==c)); 85 86 if (rows!=cols) 87 VERIFY_RAISES_ASSERT(m3 = m1*m1); 88 89 // test the previous tests were not screwed up because operator* returns 0 90 // (we use the more accurate default epsilon) 91 if (NumTraits<Scalar>::HasFloatingPoint && std::min(rows,cols)>1) 92 { 93 VERIFY(areNotApprox(m1.transpose()*m2,m2.transpose()*m1)); 94 } 95 96 // test optimized operator+= path 97 res = square; 98 res += (m1 * m2.transpose()).lazy(); 99 VERIFY_IS_APPROX(res, square + m1 * m2.transpose()); 100 if (NumTraits<Scalar>::HasFloatingPoint && std::min(rows,cols)>1) 101 { 102 VERIFY(areNotApprox(res,square + m2 * m1.transpose())); 103 } 104 vcres = vc2; 105 vcres += (m1.transpose() * v1).lazy(); 106 VERIFY_IS_APPROX(vcres, vc2 + m1.transpose() * v1); 107 tm1 = m1; 108 VERIFY_IS_APPROX(tm1.transpose() * v1, m1.transpose() * v1); 109 VERIFY_IS_APPROX(v1.transpose() * tm1, v1.transpose() * m1); 110 111 // test submatrix and matrix/vector product 112 for (int i=0; i<rows; ++i) 113 res.row(i) = m1.row(i) * m2.transpose(); 114 VERIFY_IS_APPROX(res, m1 * m2.transpose()); 115 // the other way round: 116 for (int i=0; i<rows; ++i) 117 res.col(i) = m1 * m2.transpose().col(i); 118 VERIFY_IS_APPROX(res, m1 * m2.transpose()); 119 120 res2 = square2; 121 res2 += (m1.transpose() * m2).lazy(); 122 VERIFY_IS_APPROX(res2, square2 + m1.transpose() * m2); 123 124 if (NumTraits<Scalar>::HasFloatingPoint && std::min(rows,cols)>1) 125 { 126 VERIFY(areNotApprox(res2,square2 + m2.transpose() * m1)); 127 } 128 } 129 130