product.h
Go to the documentation of this file.
00001 // This file is part of Eigen, a lightweight C++ template library
00002 // for linear algebra.
00003 //
00004 // Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
00005 //
00006 // Eigen is free software; you can redistribute it and/or
00007 // modify it under the terms of the GNU Lesser General Public
00008 // License as published by the Free Software Foundation; either
00009 // version 3 of the License, or (at your option) any later version.
00010 //
00011 // Alternatively, you can redistribute it and/or
00012 // modify it under the terms of the GNU General Public License as
00013 // published by the Free Software Foundation; either version 2 of
00014 // the License, or (at your option) any later version.
00015 //
00016 // Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
00017 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00018 // FOR A PARTICULAR PURPOSE.f See the GNU Lesser General Public License or the
00019 // GNU General Public License for more details.
00020 //
00021 // You should have received a copy of the GNU Lesser General Public
00022 // License and a copy of the GNU General Public License along with
00023 // Eigen. If not, see <http://www.gnu.org/licenses/>.
00024 
00025 #include "main.h"
00026 #include <Eigen/QR>
00027 
00028 template<typename Derived1, typename Derived2>
00029 bool areNotApprox(const MatrixBase<Derived1>& m1, const MatrixBase<Derived2>& m2, typename Derived1::RealScalar epsilon = NumTraits<typename Derived1::RealScalar>::dummy_precision())
00030 {
00031   return !((m1-m2).cwiseAbs2().maxCoeff() < epsilon * epsilon
00032                           * std::max(m1.cwiseAbs2().maxCoeff(), m2.cwiseAbs2().maxCoeff()));
00033 }
00034 
00035 template<typename MatrixType> void product(const MatrixType& m)
00036 {
00037   /* this test covers the following files:
00038      Identity.h Product.h
00039   */
00040   typedef typename MatrixType::Index Index;
00041   typedef typename MatrixType::Scalar Scalar;
00042   typedef typename NumTraits<Scalar>::NonInteger NonInteger;
00043   typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, 1> RowVectorType;
00044   typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, 1> ColVectorType;
00045   typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::RowsAtCompileTime> RowSquareMatrixType;
00046   typedef Matrix<Scalar, MatrixType::ColsAtCompileTime, MatrixType::ColsAtCompileTime> ColSquareMatrixType;
00047   typedef Matrix<Scalar, MatrixType::RowsAtCompileTime, MatrixType::ColsAtCompileTime,
00048                          MatrixType::Flags&RowMajorBit?ColMajor:RowMajor> OtherMajorMatrixType;
00049 
00050   Index rows = m.rows();
00051   Index cols = m.cols();
00052 
00053   // this test relies a lot on Random.h, and there's not much more that we can do
00054   // to test it, hence I consider that we will have tested Random.h
00055   MatrixType m1 = MatrixType::Random(rows, cols),
00056              m2 = MatrixType::Random(rows, cols),
00057              m3(rows, cols),
00058              mzero = MatrixType::Zero(rows, cols);
00059   RowSquareMatrixType
00060              identity = RowSquareMatrixType::Identity(rows, rows),
00061              square = RowSquareMatrixType::Random(rows, rows),
00062              res = RowSquareMatrixType::Random(rows, rows);
00063   ColSquareMatrixType
00064              square2 = ColSquareMatrixType::Random(cols, cols),
00065              res2 = ColSquareMatrixType::Random(cols, cols);
00066   RowVectorType v1 = RowVectorType::Random(rows),
00067              v2 = RowVectorType::Random(rows),
00068              vzero = RowVectorType::Zero(rows);
00069   ColVectorType vc2 = ColVectorType::Random(cols), vcres(cols);
00070   OtherMajorMatrixType tm1 = m1;
00071 
00072   Scalar s1 = internal::random<Scalar>();
00073 
00074   Index r  = internal::random<Index>(0, rows-1),
00075         c  = internal::random<Index>(0, cols-1),
00076         c2 = internal::random<Index>(0, cols-1);
00077 
00078   // begin testing Product.h: only associativity for now
00079   // (we use Transpose.h but this doesn't count as a test for it)
00080   VERIFY_IS_APPROX((m1*m1.transpose())*m2,  m1*(m1.transpose()*m2));
00081   m3 = m1;
00082   m3 *= m1.transpose() * m2;
00083   VERIFY_IS_APPROX(m3,                      m1 * (m1.transpose()*m2));
00084   VERIFY_IS_APPROX(m3,                      m1 * (m1.transpose()*m2));
00085 
00086   // continue testing Product.h: distributivity
00087   VERIFY_IS_APPROX(square*(m1 + m2),        square*m1+square*m2);
00088   VERIFY_IS_APPROX(square*(m1 - m2),        square*m1-square*m2);
00089 
00090   // continue testing Product.h: compatibility with ScalarMultiple.h
00091   VERIFY_IS_APPROX(s1*(square*m1),          (s1*square)*m1);
00092   VERIFY_IS_APPROX(s1*(square*m1),          square*(m1*s1));
00093 
00094   // test Product.h together with Identity.h
00095   VERIFY_IS_APPROX(v1,                      identity*v1);
00096   VERIFY_IS_APPROX(v1.transpose(),          v1.transpose() * identity);
00097   // again, test operator() to check const-qualification
00098   VERIFY_IS_APPROX(MatrixType::Identity(rows, cols)(r,c), static_cast<Scalar>(r==c));
00099 
00100   if (rows!=cols)
00101      VERIFY_RAISES_ASSERT(m3 = m1*m1);
00102 
00103   // test the previous tests were not screwed up because operator* returns 0
00104   // (we use the more accurate default epsilon)
00105   if (!NumTraits<Scalar>::IsInteger && std::min(rows,cols)>1)
00106   {
00107     VERIFY(areNotApprox(m1.transpose()*m2,m2.transpose()*m1));
00108   }
00109 
00110   // test optimized operator+= path
00111   res = square;
00112   res.noalias() += m1 * m2.transpose();
00113   VERIFY_IS_APPROX(res, square + m1 * m2.transpose());
00114   if (!NumTraits<Scalar>::IsInteger && std::min(rows,cols)>1)
00115   {
00116     VERIFY(areNotApprox(res,square + m2 * m1.transpose()));
00117   }
00118   vcres = vc2;
00119   vcres.noalias() += m1.transpose() * v1;
00120   VERIFY_IS_APPROX(vcres, vc2 + m1.transpose() * v1);
00121 
00122   // test optimized operator-= path
00123   res = square;
00124   res.noalias() -= m1 * m2.transpose();
00125   VERIFY_IS_APPROX(res, square - (m1 * m2.transpose()));
00126   if (!NumTraits<Scalar>::IsInteger && std::min(rows,cols)>1)
00127   {
00128     VERIFY(areNotApprox(res,square - m2 * m1.transpose()));
00129   }
00130   vcres = vc2;
00131   vcres.noalias() -= m1.transpose() * v1;
00132   VERIFY_IS_APPROX(vcres, vc2 - m1.transpose() * v1);
00133 
00134   tm1 = m1;
00135   VERIFY_IS_APPROX(tm1.transpose() * v1, m1.transpose() * v1);
00136   VERIFY_IS_APPROX(v1.transpose() * tm1, v1.transpose() * m1);
00137 
00138   // test submatrix and matrix/vector product
00139   for (int i=0; i<rows; ++i)
00140     res.row(i) = m1.row(i) * m2.transpose();
00141   VERIFY_IS_APPROX(res, m1 * m2.transpose());
00142   // the other way round:
00143   for (int i=0; i<rows; ++i)
00144     res.col(i) = m1 * m2.transpose().col(i);
00145   VERIFY_IS_APPROX(res, m1 * m2.transpose());
00146 
00147   res2 = square2;
00148   res2.noalias() += m1.transpose() * m2;
00149   VERIFY_IS_APPROX(res2, square2 + m1.transpose() * m2);
00150   if (!NumTraits<Scalar>::IsInteger && std::min(rows,cols)>1)
00151   {
00152     VERIFY(areNotApprox(res2,square2 + m2.transpose() * m1));
00153   }
00154 
00155   VERIFY_IS_APPROX(res.col(r).noalias() = square.adjoint() * square.col(r), (square.adjoint() * square.col(r)).eval());
00156   VERIFY_IS_APPROX(res.col(r).noalias() = square * square.col(r), (square * square.col(r)).eval());
00157 
00158   // inner product
00159   Scalar x = square2.row(c) * square2.col(c2);
00160   VERIFY_IS_APPROX(x, square2.row(c).transpose().cwiseProduct(square2.col(c2)).sum());
00161 }


re_vision
Author(s): Dorian Galvez-Lopez
autogenerated on Sun Jan 5 2014 11:32:10