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