1 // This file is part of Eigen, a lightweight C++ template library
4 // Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
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/.
10 static int nb_temporaries
;
12 inline void on_temporary_creation(int size
) {
13 // here's a great place to set a breakpoint when debugging failures in this test!
14 if(size
!=0) nb_temporaries
++;
18 #define EIGEN_DENSE_STORAGE_CTOR_PLUGIN { on_temporary_creation(size); }
22 #define VERIFY_EVALUATION_COUNT(XPR,N) {\
25 if(nb_temporaries!=N) std::cerr << "nb_temporaries == " << nb_temporaries << "\n"; \
26 VERIFY( (#XPR) && nb_temporaries==N ); \
29 template<typename MatrixType
> void product_notemporary(const MatrixType
& m
)
31 /* This test checks the number of temporaries created
32 * during the evaluation of a complex expression */
33 typedef typename
MatrixType::Index Index
;
34 typedef typename
MatrixType::Scalar Scalar
;
35 typedef typename
MatrixType::RealScalar RealScalar
;
36 typedef Matrix
<Scalar
, 1, Dynamic
> RowVectorType
;
37 typedef Matrix
<Scalar
, Dynamic
, 1> ColVectorType
;
38 typedef Matrix
<Scalar
, Dynamic
, Dynamic
, ColMajor
> ColMajorMatrixType
;
39 typedef Matrix
<Scalar
, Dynamic
, Dynamic
, RowMajor
> RowMajorMatrixType
;
41 Index rows
= m
.rows();
42 Index cols
= m
.cols();
44 ColMajorMatrixType m1
= MatrixType::Random(rows
, cols
),
45 m2
= MatrixType::Random(rows
, cols
),
47 RowVectorType rv1
= RowVectorType::Random(rows
), rvres(rows
);
48 ColVectorType cv1
= ColVectorType::Random(cols
), cvres(cols
);
49 RowMajorMatrixType
rm3(rows
, cols
);
51 Scalar s1
= internal::random
<Scalar
>(),
52 s2
= internal::random
<Scalar
>(),
53 s3
= internal::random
<Scalar
>();
55 Index c0
= internal::random
<Index
>(4,cols
-8),
56 c1
= internal::random
<Index
>(8,cols
-c0
),
57 r0
= internal::random
<Index
>(4,cols
-8),
58 r1
= internal::random
<Index
>(8,rows
-r0
);
60 VERIFY_EVALUATION_COUNT( m3
= (m1
* m2
.adjoint()), 1);
61 VERIFY_EVALUATION_COUNT( m3
= (m1
* m2
.adjoint()).transpose(), 1);
62 VERIFY_EVALUATION_COUNT( m3
.noalias() = m1
* m2
.adjoint(), 0);
64 VERIFY_EVALUATION_COUNT( m3
= s1
* (m1
* m2
.transpose()), 1);
65 VERIFY_EVALUATION_COUNT( m3
= m3
+ s1
* (m1
* m2
.transpose()), 1);
66 VERIFY_EVALUATION_COUNT( m3
.noalias() = s1
* (m1
* m2
.transpose()), 0);
68 VERIFY_EVALUATION_COUNT( m3
= m3
+ (m1
* m2
.adjoint()), 1);
69 VERIFY_EVALUATION_COUNT( m3
= m3
+ (m1
* m2
.adjoint()).transpose(), 1);
70 VERIFY_EVALUATION_COUNT( m3
.noalias() = m3
+ m1
* m2
.transpose(), 1); // 0 in 3.3
71 VERIFY_EVALUATION_COUNT( m3
.noalias() += m3
+ m1
* m2
.transpose(), 1); // 0 in 3.3
72 VERIFY_EVALUATION_COUNT( m3
.noalias() -= m3
+ m1
* m2
.transpose(), 1); // 0 in 3.3
74 VERIFY_EVALUATION_COUNT( m3
.noalias() = s1
* m1
* s2
* m2
.adjoint(), 0);
75 VERIFY_EVALUATION_COUNT( m3
.noalias() = s1
* m1
* s2
* (m1
*s3
+m2
*s2
).adjoint(), 1);
76 VERIFY_EVALUATION_COUNT( m3
.noalias() = (s1
* m1
).adjoint() * s2
* m2
, 0);
77 VERIFY_EVALUATION_COUNT( m3
.noalias() += s1
* (-m1
*s3
).adjoint() * (s2
* m2
* s3
), 0);
78 VERIFY_EVALUATION_COUNT( m3
.noalias() -= s1
* (m1
.transpose() * m2
), 0);
80 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);
81 VERIFY_EVALUATION_COUNT(( m3
.block(r0
,r0
,r1
,r1
).noalias() -= s1
* m1
.block(r0
,c0
,r1
,c1
) * m2
.block(c0
,r0
,c1
,r1
) ), 0);
83 // NOTE this is because the Block expression is not handled yet by our expression analyser
84 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);
86 VERIFY_EVALUATION_COUNT( m3
.noalias() -= (s1
* m1
).template triangularView
<Lower
>() * m2
, 0);
87 VERIFY_EVALUATION_COUNT( rm3
.noalias() = (s1
* m1
.adjoint()).template triangularView
<Upper
>() * (m2
+m2
), 1);
88 VERIFY_EVALUATION_COUNT( rm3
.noalias() = (s1
* m1
.adjoint()).template triangularView
<UnitUpper
>() * m2
.adjoint(), 0);
90 VERIFY_EVALUATION_COUNT( m3
.template triangularView
<Upper
>() = (m1
* m2
.adjoint()), 0);
91 VERIFY_EVALUATION_COUNT( m3
.template triangularView
<Upper
>() -= (m1
* m2
.adjoint()), 0);
93 // 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
94 VERIFY_EVALUATION_COUNT( rm3
.col(c0
).noalias() = (s1
* m1
.adjoint()).template triangularView
<UnitUpper
>() * (s2
*m2
.row(c0
)).adjoint(), 1);
96 VERIFY_EVALUATION_COUNT( m1
.template triangularView
<Lower
>().solveInPlace(m3
), 0);
97 VERIFY_EVALUATION_COUNT( m1
.adjoint().template triangularView
<Lower
>().solveInPlace(m3
.transpose()), 0);
99 VERIFY_EVALUATION_COUNT( m3
.noalias() -= (s1
* m1
).adjoint().template selfadjointView
<Lower
>() * (-m2
*s3
).adjoint(), 0);
100 VERIFY_EVALUATION_COUNT( m3
.noalias() = s2
* m2
.adjoint() * (s1
* m1
.adjoint()).template selfadjointView
<Upper
>(), 0);
101 VERIFY_EVALUATION_COUNT( rm3
.noalias() = (s1
* m1
.adjoint()).template selfadjointView
<Lower
>() * m2
.adjoint(), 0);
103 // 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
104 VERIFY_EVALUATION_COUNT( m3
.col(c0
).noalias() = (s1
* m1
).adjoint().template selfadjointView
<Lower
>() * (-m2
.row(c0
)*s3
).adjoint(), 1);
105 VERIFY_EVALUATION_COUNT( m3
.col(c0
).noalias() -= (s1
* m1
).adjoint().template selfadjointView
<Upper
>() * (-m2
.row(c0
)*s3
).adjoint(), 1);
107 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);
108 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);
110 VERIFY_EVALUATION_COUNT( m3
.template selfadjointView
<Lower
>().rankUpdate(m2
.adjoint()), 0);
112 // Here we will get 1 temporary for each resize operation of the lhs operator; resize(r1,c1) would lead to zero temporaries
114 VERIFY_EVALUATION_COUNT( m3
.noalias() = m1
.block(r0
,r0
,r1
,r1
).template selfadjointView
<Lower
>() * m2
.block(r0
,c0
,r1
,c1
), 1);
116 VERIFY_EVALUATION_COUNT( m3
.noalias() = m1
.block(r0
,r0
,r1
,r1
).template triangularView
<UnitUpper
>() * m2
.block(r0
,c0
,r1
,c1
), 1);
118 // Zero temporaries for lazy products ...
119 VERIFY_EVALUATION_COUNT( Scalar tmp
= 0; tmp
+= Scalar(RealScalar(1)) / (m3
.transpose().lazyProduct(m3
)).diagonal().sum(), 0 );
121 // ... and even no temporary for even deeply (>=2) nested products
122 VERIFY_EVALUATION_COUNT( Scalar tmp
= 0; tmp
+= Scalar(RealScalar(1)) / (m3
.transpose() * m3
).diagonal().sum(), 0 );
123 VERIFY_EVALUATION_COUNT( Scalar tmp
= 0; tmp
+= Scalar(RealScalar(1)) / (m3
.transpose() * m3
).diagonal().array().abs().sum(), 0 );
125 // Zero temporaries for ... CoeffBasedProductMode
126 // - does not work with GCC because of the <..>, we'ld need variadic macros ...
127 //VERIFY_EVALUATION_COUNT( m3.col(0).head<5>() * m3.col(0).transpose() + m3.col(0).head<5>() * m3.col(0).transpose(), 0 );
129 // Check matrix * vectors
130 VERIFY_EVALUATION_COUNT( cvres
.noalias() = m1
* cv1
, 0 );
131 VERIFY_EVALUATION_COUNT( cvres
.noalias() -= m1
* cv1
, 0 );
132 VERIFY_EVALUATION_COUNT( cvres
.noalias() -= m1
* m2
.col(0), 0 );
133 VERIFY_EVALUATION_COUNT( cvres
.noalias() -= m1
* rv1
.adjoint(), 0 );
134 VERIFY_EVALUATION_COUNT( cvres
.noalias() -= m1
* m2
.row(0).transpose(), 0 );
137 void test_product_notemporary()
140 for(int i
= 0; i
< g_repeat
; i
++) {
141 s
= internal::random
<int>(16,EIGEN_TEST_MAX_SIZE
);
142 CALL_SUBTEST_1( product_notemporary(MatrixXf(s
, s
)) );
143 s
= internal::random
<int>(16,EIGEN_TEST_MAX_SIZE
);
144 CALL_SUBTEST_2( product_notemporary(MatrixXd(s
, s
)) );
145 s
= internal::random
<int>(16,EIGEN_TEST_MAX_SIZE
/2);
146 CALL_SUBTEST_3( product_notemporary(MatrixXcf(s
,s
)) );
147 s
= internal::random
<int>(16,EIGEN_TEST_MAX_SIZE
/2);
148 CALL_SUBTEST_4( product_notemporary(MatrixXcd(s
,s
)) );