2009-07-28 23:13:13 +08:00
// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
//
2012-07-14 02:42:47 +08:00
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
2009-07-28 23:13:13 +08:00
2015-06-19 22:38:26 +08:00
# define TEST_ENABLE_TEMPORARY_TRACKING
2009-07-28 23:13:13 +08:00
# include "main.h"
2019-02-18 18:47:54 +08:00
template < typename Dst , typename Lhs , typename Rhs >
void check_scalar_multiple3 ( Dst & dst , const Lhs & A , const Rhs & B )
{
VERIFY_EVALUATION_COUNT ( ( dst . noalias ( ) = A * B ) , 0 ) ;
VERIFY_IS_APPROX ( dst , ( A . eval ( ) * B . eval ( ) ) . eval ( ) ) ;
VERIFY_EVALUATION_COUNT ( ( dst . noalias ( ) + = A * B ) , 0 ) ;
VERIFY_IS_APPROX ( dst , 2 * ( A . eval ( ) * B . eval ( ) ) . eval ( ) ) ;
VERIFY_EVALUATION_COUNT ( ( dst . noalias ( ) - = A * B ) , 0 ) ;
VERIFY_IS_APPROX ( dst , ( A . eval ( ) * B . eval ( ) ) . eval ( ) ) ;
}
template < typename Dst , typename Lhs , typename Rhs , typename S2 >
void check_scalar_multiple2 ( Dst & dst , const Lhs & A , const Rhs & B , S2 s2 )
{
CALL_SUBTEST ( check_scalar_multiple3 ( dst , A , B ) ) ;
CALL_SUBTEST ( check_scalar_multiple3 ( dst , A , - B ) ) ;
CALL_SUBTEST ( check_scalar_multiple3 ( dst , A , s2 * B ) ) ;
CALL_SUBTEST ( check_scalar_multiple3 ( dst , A , B * s2 ) ) ;
2019-02-18 21:45:55 +08:00
CALL_SUBTEST ( check_scalar_multiple3 ( dst , A , ( B * s2 ) . conjugate ( ) ) ) ;
2019-02-18 18:47:54 +08:00
}
template < typename Dst , typename Lhs , typename Rhs , typename S1 , typename S2 >
void check_scalar_multiple1 ( Dst & dst , const Lhs & A , const Rhs & B , S1 s1 , S2 s2 )
{
CALL_SUBTEST ( check_scalar_multiple2 ( dst , A , B , s2 ) ) ;
CALL_SUBTEST ( check_scalar_multiple2 ( dst , - A , B , s2 ) ) ;
CALL_SUBTEST ( check_scalar_multiple2 ( dst , s1 * A , B , s2 ) ) ;
CALL_SUBTEST ( check_scalar_multiple2 ( dst , A * s1 , B , s2 ) ) ;
2019-02-18 21:45:55 +08:00
CALL_SUBTEST ( check_scalar_multiple2 ( dst , ( A * s1 ) . conjugate ( ) , B , s2 ) ) ;
2019-02-18 18:47:54 +08:00
}
2009-07-28 23:13:13 +08:00
template < typename MatrixType > void product_notemporary ( const MatrixType & m )
{
2010-02-10 03:32:48 +08:00
/* This test checks the number of temporaries created
2009-07-28 23:13:13 +08:00
* during the evaluation of a complex expression */
typedef typename MatrixType : : Scalar Scalar ;
2010-02-10 03:32:48 +08:00
typedef typename MatrixType : : RealScalar RealScalar ;
2009-07-28 23:13:13 +08:00
typedef Matrix < Scalar , 1 , Dynamic > RowVectorType ;
typedef Matrix < Scalar , Dynamic , 1 > ColVectorType ;
2010-06-24 23:49:51 +08:00
typedef Matrix < Scalar , Dynamic , Dynamic , ColMajor > ColMajorMatrixType ;
2009-07-28 23:13:13 +08:00
typedef Matrix < Scalar , Dynamic , Dynamic , RowMajor > RowMajorMatrixType ;
2010-06-20 23:37:56 +08:00
Index rows = m . rows ( ) ;
Index cols = m . cols ( ) ;
2009-07-28 23:13:13 +08:00
2010-06-24 23:49:51 +08:00
ColMajorMatrixType m1 = MatrixType : : Random ( rows , cols ) ,
m2 = MatrixType : : Random ( rows , cols ) ,
m3 ( rows , cols ) ;
2009-07-28 23:13:13 +08:00
RowVectorType rv1 = RowVectorType : : Random ( rows ) , rvres ( rows ) ;
2011-01-30 15:17:46 +08:00
ColVectorType cv1 = ColVectorType : : Random ( cols ) , cvres ( cols ) ;
2009-07-28 23:13:13 +08:00
RowMajorMatrixType rm3 ( rows , cols ) ;
2010-10-25 22:15:22 +08:00
Scalar s1 = internal : : random < Scalar > ( ) ,
s2 = internal : : random < Scalar > ( ) ,
s3 = internal : : random < Scalar > ( ) ;
2009-07-28 23:13:13 +08:00
2010-10-25 22:15:22 +08:00
Index c0 = internal : : random < Index > ( 4 , cols - 8 ) ,
c1 = internal : : random < Index > ( 8 , cols - c0 ) ,
r0 = internal : : random < Index > ( 4 , cols - 8 ) ,
r1 = internal : : random < Index > ( 8 , rows - r0 ) ;
2009-07-28 23:13:13 +08:00
VERIFY_EVALUATION_COUNT ( m3 = ( m1 * m2 . adjoint ( ) ) , 1 ) ;
2016-01-09 15:30:38 +08:00
VERIFY_EVALUATION_COUNT ( m3 = ( m1 * m2 . adjoint ( ) ) . transpose ( ) , 1 ) ;
2009-08-16 00:35:51 +08:00
VERIFY_EVALUATION_COUNT ( m3 . noalias ( ) = m1 * m2 . adjoint ( ) , 0 ) ;
2016-01-09 15:30:38 +08:00
VERIFY_EVALUATION_COUNT ( m3 = s1 * ( m1 * m2 . transpose ( ) ) , 1 ) ;
// VERIFY_EVALUATION_COUNT( m3 = m3 + s1 * (m1 * m2.transpose()), 1);
2009-08-16 00:35:51 +08:00
VERIFY_EVALUATION_COUNT ( m3 . noalias ( ) = s1 * ( m1 * m2 . transpose ( ) ) , 0 ) ;
2009-08-04 22:54:17 +08:00
2016-01-09 15:30:38 +08:00
VERIFY_EVALUATION_COUNT ( m3 = m3 + ( m1 * m2 . adjoint ( ) ) , 1 ) ;
2017-06-08 18:55:25 +08:00
VERIFY_EVALUATION_COUNT ( m3 = m3 - ( m1 * m2 . adjoint ( ) ) , 1 ) ;
2016-01-09 15:30:38 +08:00
VERIFY_EVALUATION_COUNT ( m3 = m3 + ( m1 * m2 . adjoint ( ) ) . transpose ( ) , 1 ) ;
2015-10-09 21:28:09 +08:00
VERIFY_EVALUATION_COUNT ( m3 . noalias ( ) = m3 + m1 * m2 . transpose ( ) , 0 ) ;
VERIFY_EVALUATION_COUNT ( m3 . noalias ( ) + = m3 + m1 * m2 . transpose ( ) , 0 ) ;
VERIFY_EVALUATION_COUNT ( m3 . noalias ( ) - = m3 + m1 * m2 . transpose ( ) , 0 ) ;
2016-08-23 22:52:22 +08:00
VERIFY_EVALUATION_COUNT ( m3 . noalias ( ) = m3 - m1 * m2 . transpose ( ) , 0 ) ;
VERIFY_EVALUATION_COUNT ( m3 . noalias ( ) + = m3 - m1 * m2 . transpose ( ) , 0 ) ;
VERIFY_EVALUATION_COUNT ( m3 . noalias ( ) - = m3 - m1 * m2 . transpose ( ) , 0 ) ;
2015-10-09 21:28:09 +08:00
2009-09-01 19:35:44 +08:00
VERIFY_EVALUATION_COUNT ( m3 . noalias ( ) = s1 * m1 * s2 * m2 . adjoint ( ) , 0 ) ;
VERIFY_EVALUATION_COUNT ( m3 . noalias ( ) = s1 * m1 * s2 * ( m1 * s3 + m2 * s2 ) . adjoint ( ) , 1 ) ;
VERIFY_EVALUATION_COUNT ( m3 . noalias ( ) = ( s1 * m1 ) . adjoint ( ) * s2 * m2 , 0 ) ;
2009-08-16 00:35:51 +08:00
VERIFY_EVALUATION_COUNT ( m3 . noalias ( ) + = s1 * ( - m1 * s3 ) . adjoint ( ) * ( s2 * m2 * s3 ) , 0 ) ;
VERIFY_EVALUATION_COUNT ( m3 . noalias ( ) - = s1 * ( m1 . transpose ( ) * m2 ) , 0 ) ;
2009-07-28 23:13:13 +08:00
2009-09-01 19:35:44 +08:00
VERIFY_EVALUATION_COUNT ( ( m3 . block ( r0 , r0 , r1 , r1 ) . noalias ( ) + = - m1 . block ( r0 , c0 , r1 , c1 ) * ( s2 * m2 . block ( r0 , c0 , r1 , c1 ) ) . adjoint ( ) ) , 0 ) ;
VERIFY_EVALUATION_COUNT ( ( m3 . block ( r0 , r0 , r1 , r1 ) . noalias ( ) - = s1 * m1 . block ( r0 , c0 , r1 , c1 ) * m2 . block ( c0 , r0 , c1 , r1 ) ) , 0 ) ;
2009-08-04 22:54:17 +08:00
2009-07-28 23:13:13 +08:00
// NOTE this is because the Block expression is not handled yet by our expression analyser
2009-09-03 02:59:57 +08:00
VERIFY_EVALUATION_COUNT ( ( m3 . block ( r0 , r0 , r1 , r1 ) . noalias ( ) = s1 * m1 . block ( r0 , c0 , r1 , c1 ) * ( s1 * m2 ) . block ( c0 , r0 , c1 , r1 ) ) , 1 ) ;
2009-07-28 23:13:13 +08:00
2010-01-08 04:15:32 +08:00
VERIFY_EVALUATION_COUNT ( m3 . noalias ( ) - = ( s1 * m1 ) . template triangularView < Lower > ( ) * m2 , 0 ) ;
VERIFY_EVALUATION_COUNT ( rm3 . noalias ( ) = ( s1 * m1 . adjoint ( ) ) . template triangularView < Upper > ( ) * ( m2 + m2 ) , 1 ) ;
VERIFY_EVALUATION_COUNT ( rm3 . noalias ( ) = ( s1 * m1 . adjoint ( ) ) . template triangularView < UnitUpper > ( ) * m2 . adjoint ( ) , 0 ) ;
2015-10-09 03:41:53 +08:00
2013-04-11 05:13:04 +08:00
VERIFY_EVALUATION_COUNT ( m3 . template triangularView < Upper > ( ) = ( m1 * m2 . adjoint ( ) ) , 0 ) ;
VERIFY_EVALUATION_COUNT ( m3 . template triangularView < Upper > ( ) - = ( m1 * m2 . adjoint ( ) ) , 0 ) ;
2009-07-28 23:13:13 +08:00
2010-04-23 02:11:18 +08:00
// NOTE this is because the blas_traits require innerstride==1 to avoid a temporary, but that doesn't seem to be actually needed for the triangular products
VERIFY_EVALUATION_COUNT ( rm3 . col ( c0 ) . noalias ( ) = ( s1 * m1 . adjoint ( ) ) . template triangularView < UnitUpper > ( ) * ( s2 * m2 . row ( c0 ) ) . adjoint ( ) , 1 ) ;
2009-07-28 23:13:13 +08:00
2010-01-08 04:15:32 +08:00
VERIFY_EVALUATION_COUNT ( m1 . template triangularView < Lower > ( ) . solveInPlace ( m3 ) , 0 ) ;
VERIFY_EVALUATION_COUNT ( m1 . adjoint ( ) . template triangularView < Lower > ( ) . solveInPlace ( m3 . transpose ( ) ) , 0 ) ;
2009-07-28 23:13:13 +08:00
2010-01-08 04:15:32 +08:00
VERIFY_EVALUATION_COUNT ( m3 . noalias ( ) - = ( s1 * m1 ) . adjoint ( ) . template selfadjointView < Lower > ( ) * ( - m2 * s3 ) . adjoint ( ) , 0 ) ;
VERIFY_EVALUATION_COUNT ( m3 . noalias ( ) = s2 * m2 . adjoint ( ) * ( s1 * m1 . adjoint ( ) ) . template selfadjointView < Upper > ( ) , 0 ) ;
VERIFY_EVALUATION_COUNT ( rm3 . noalias ( ) = ( s1 * m1 . adjoint ( ) ) . template selfadjointView < Lower > ( ) * m2 . adjoint ( ) , 0 ) ;
2009-07-28 23:13:13 +08:00
2010-04-23 02:11:18 +08:00
// NOTE this is because the blas_traits require innerstride==1 to avoid a temporary, but that doesn't seem to be actually needed for the triangular products
VERIFY_EVALUATION_COUNT ( m3 . col ( c0 ) . noalias ( ) = ( s1 * m1 ) . adjoint ( ) . template selfadjointView < Lower > ( ) * ( - m2 . row ( c0 ) * s3 ) . adjoint ( ) , 1 ) ;
VERIFY_EVALUATION_COUNT ( m3 . col ( c0 ) . noalias ( ) - = ( s1 * m1 ) . adjoint ( ) . template selfadjointView < Upper > ( ) * ( - m2 . row ( c0 ) * s3 ) . adjoint ( ) , 1 ) ;
2009-07-28 23:13:13 +08:00
2010-01-08 04:15:32 +08:00
VERIFY_EVALUATION_COUNT ( m3 . block ( r0 , c0 , r1 , c1 ) . noalias ( ) + = m1 . block ( r0 , r0 , r1 , r1 ) . template selfadjointView < Upper > ( ) * ( s1 * m2 . block ( r0 , c0 , r1 , c1 ) ) , 0 ) ;
VERIFY_EVALUATION_COUNT ( m3 . block ( r0 , c0 , r1 , c1 ) . noalias ( ) = m1 . block ( r0 , r0 , r1 , r1 ) . template selfadjointView < Upper > ( ) * m2 . block ( r0 , c0 , r1 , c1 ) , 0 ) ;
2009-07-28 23:13:13 +08:00
2010-01-08 04:15:32 +08:00
VERIFY_EVALUATION_COUNT ( m3 . template selfadjointView < Lower > ( ) . rankUpdate ( m2 . adjoint ( ) ) , 0 ) ;
2009-07-29 00:11:30 +08:00
2010-02-10 03:32:48 +08:00
// Here we will get 1 temporary for each resize operation of the lhs operator; resize(r1,c1) would lead to zero temporaries
2009-07-29 00:11:30 +08:00
m3 . resize ( 1 , 1 ) ;
2010-02-10 03:32:48 +08:00
VERIFY_EVALUATION_COUNT ( m3 . noalias ( ) = m1 . block ( r0 , r0 , r1 , r1 ) . template selfadjointView < Lower > ( ) * m2 . block ( r0 , c0 , r1 , c1 ) , 1 ) ;
2009-07-29 00:11:30 +08:00
m3 . resize ( 1 , 1 ) ;
2010-02-10 03:32:48 +08:00
VERIFY_EVALUATION_COUNT ( m3 . noalias ( ) = m1 . block ( r0 , r0 , r1 , r1 ) . template triangularView < UnitUpper > ( ) * m2 . block ( r0 , c0 , r1 , c1 ) , 1 ) ;
// Zero temporaries for lazy products ...
2019-02-18 21:43:07 +08:00
m3 . setRandom ( rows , cols ) ;
2010-02-11 01:00:36 +08:00
VERIFY_EVALUATION_COUNT ( Scalar tmp = 0 ; tmp + = Scalar ( RealScalar ( 1 ) ) / ( m3 . transpose ( ) . lazyProduct ( m3 ) ) . diagonal ( ) . sum ( ) , 0 ) ;
2019-02-18 21:43:07 +08:00
VERIFY_EVALUATION_COUNT ( m3 . noalias ( ) = m1 . conjugate ( ) . lazyProduct ( m2 . conjugate ( ) ) , 0 ) ;
2010-02-10 03:32:48 +08:00
2010-02-12 16:41:56 +08:00
// ... and even no temporary for even deeply (>=2) nested products
2010-02-11 18:31:36 +08:00
VERIFY_EVALUATION_COUNT ( Scalar tmp = 0 ; tmp + = Scalar ( RealScalar ( 1 ) ) / ( m3 . transpose ( ) * m3 ) . diagonal ( ) . sum ( ) , 0 ) ;
VERIFY_EVALUATION_COUNT ( Scalar tmp = 0 ; tmp + = Scalar ( RealScalar ( 1 ) ) / ( m3 . transpose ( ) * m3 ) . diagonal ( ) . array ( ) . abs ( ) . sum ( ) , 0 ) ;
2010-02-10 03:32:48 +08:00
// Zero temporaries for ... CoeffBasedProductMode
2014-02-19 00:43:16 +08:00
VERIFY_EVALUATION_COUNT ( m3 . col ( 0 ) . template head < 5 > ( ) * m3 . col ( 0 ) . transpose ( ) + m3 . col ( 0 ) . template head < 5 > ( ) * m3 . col ( 0 ) . transpose ( ) , 0 ) ;
2011-01-30 15:17:46 +08:00
// Check matrix * vectors
VERIFY_EVALUATION_COUNT ( cvres . noalias ( ) = m1 * cv1 , 0 ) ;
VERIFY_EVALUATION_COUNT ( cvres . noalias ( ) - = m1 * cv1 , 0 ) ;
VERIFY_EVALUATION_COUNT ( cvres . noalias ( ) - = m1 * m2 . col ( 0 ) , 0 ) ;
VERIFY_EVALUATION_COUNT ( cvres . noalias ( ) - = m1 * rv1 . adjoint ( ) , 0 ) ;
VERIFY_EVALUATION_COUNT ( cvres . noalias ( ) - = m1 * m2 . row ( 0 ) . transpose ( ) , 0 ) ;
2015-10-08 23:36:57 +08:00
VERIFY_EVALUATION_COUNT ( cvres . noalias ( ) = ( m1 + m1 ) * cv1 , 0 ) ;
VERIFY_EVALUATION_COUNT ( cvres . noalias ( ) = ( rm3 + rm3 ) * cv1 , 0 ) ;
VERIFY_EVALUATION_COUNT ( cvres . noalias ( ) = ( m1 + m1 ) * ( m1 * cv1 ) , 1 ) ;
VERIFY_EVALUATION_COUNT ( cvres . noalias ( ) = ( rm3 + rm3 ) * ( m1 * cv1 ) , 1 ) ;
2015-10-09 03:41:53 +08:00
// Check outer products
2018-07-09 21:41:14 +08:00
# ifdef EIGEN_ALLOCA
bool temp_via_alloca = m3 . rows ( ) * sizeof ( Scalar ) < = EIGEN_STACK_ALLOCATION_LIMIT ;
# else
bool temp_via_alloca = false ;
# endif
2015-10-09 03:41:53 +08:00
m3 = cv1 * rv1 ;
VERIFY_EVALUATION_COUNT ( m3 . noalias ( ) = cv1 * rv1 , 0 ) ;
2018-07-09 21:41:14 +08:00
VERIFY_EVALUATION_COUNT ( m3 . noalias ( ) = ( cv1 + cv1 ) * ( rv1 + rv1 ) , temp_via_alloca ? 0 : 1 ) ;
2015-10-09 03:41:53 +08:00
VERIFY_EVALUATION_COUNT ( m3 . noalias ( ) = ( m1 * cv1 ) * ( rv1 ) , 1 ) ;
VERIFY_EVALUATION_COUNT ( m3 . noalias ( ) + = ( m1 * cv1 ) * ( rv1 ) , 1 ) ;
2018-07-09 21:41:14 +08:00
rm3 = cv1 * rv1 ;
VERIFY_EVALUATION_COUNT ( rm3 . noalias ( ) = cv1 * rv1 , 0 ) ;
VERIFY_EVALUATION_COUNT ( rm3 . noalias ( ) = ( cv1 + cv1 ) * ( rv1 + rv1 ) , temp_via_alloca ? 0 : 1 ) ;
2015-10-09 03:41:53 +08:00
VERIFY_EVALUATION_COUNT ( rm3 . noalias ( ) = ( cv1 ) * ( rv1 * m1 ) , 1 ) ;
VERIFY_EVALUATION_COUNT ( rm3 . noalias ( ) - = ( cv1 ) * ( rv1 * m1 ) , 1 ) ;
VERIFY_EVALUATION_COUNT ( rm3 . noalias ( ) = ( m1 * cv1 ) * ( rv1 * m1 ) , 2 ) ;
VERIFY_EVALUATION_COUNT ( rm3 . noalias ( ) + = ( m1 * cv1 ) * ( rv1 * m1 ) , 2 ) ;
2016-12-01 00:59:13 +08:00
// Check nested products
VERIFY_EVALUATION_COUNT ( cvres . noalias ( ) = m1 . adjoint ( ) * m1 * cv1 , 1 ) ;
VERIFY_EVALUATION_COUNT ( rvres . noalias ( ) = rv1 * ( m1 * m2 . adjoint ( ) ) , 1 ) ;
2019-02-18 18:47:54 +08:00
// exhaustively check all scalar multiple combinations:
{
// Generic path:
check_scalar_multiple1 ( m3 , m1 , m2 , s1 , s2 ) ;
// Force fall back to coeff-based:
typename ColMajorMatrixType : : BlockXpr m3_blck = m3 . block ( r0 , r0 , 1 , 1 ) ;
check_scalar_multiple1 ( m3_blck , m1 . block ( r0 , c0 , 1 , 1 ) , m2 . block ( c0 , r0 , 1 , 1 ) , s1 , s2 ) ;
}
2009-07-28 23:13:13 +08:00
}
2018-07-17 20:46:15 +08:00
EIGEN_DECLARE_TEST ( product_notemporary )
2009-07-28 23:13:13 +08:00
{
int s ;
for ( int i = 0 ; i < g_repeat ; i + + ) {
2011-07-12 20:41:00 +08:00
s = internal : : random < int > ( 16 , EIGEN_TEST_MAX_SIZE ) ;
2009-10-29 06:19:29 +08:00
CALL_SUBTEST_1 ( product_notemporary ( MatrixXf ( s , s ) ) ) ;
2010-07-07 16:50:40 +08:00
CALL_SUBTEST_2 ( product_notemporary ( MatrixXd ( s , s ) ) ) ;
2015-02-18 18:30:44 +08:00
TEST_SET_BUT_UNUSED_VARIABLE ( s )
2011-07-12 20:41:00 +08:00
s = internal : : random < int > ( 16 , EIGEN_TEST_MAX_SIZE / 2 ) ;
2010-07-07 16:50:40 +08:00
CALL_SUBTEST_3 ( product_notemporary ( MatrixXcf ( s , s ) ) ) ;
CALL_SUBTEST_4 ( product_notemporary ( MatrixXcd ( s , s ) ) ) ;
2015-02-18 18:30:44 +08:00
TEST_SET_BUT_UNUSED_VARIABLE ( s )
2009-07-28 23:13:13 +08:00
}
}