product_notemporary.cpp File Reference
#include "main.h"

Macros

#define TEST_ENABLE_TEMPORARY_TRACKING
 
#define TEST_IGNORE_STACK_ALLOCATED_TEMPORARY
 

Functions

template<typename Dst , typename Lhs , typename Rhs >
void check_scalar_multiple3 (Dst &dst, const Lhs &A, const Rhs &B)
 
template<typename Dst , typename Lhs , typename Rhs , typename S2 >
void check_scalar_multiple2 (Dst &dst, const Lhs &A, const Rhs &B, S2 s2)
 
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)
 
template<typename MatrixType >
void product_notemporary (const MatrixType &m)
 
 EIGEN_DECLARE_TEST (product_notemporary)
 

Macro Definition Documentation

◆ TEST_ENABLE_TEMPORARY_TRACKING

#define TEST_ENABLE_TEMPORARY_TRACKING

◆ TEST_IGNORE_STACK_ALLOCATED_TEMPORARY

#define TEST_IGNORE_STACK_ALLOCATED_TEMPORARY

Function Documentation

◆ check_scalar_multiple1()

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 
)
35  {
38  CALL_SUBTEST(check_scalar_multiple2(dst, s1 * A, B, s2));
39  CALL_SUBTEST(check_scalar_multiple2(dst, A * s1, B, s2));
40  CALL_SUBTEST(check_scalar_multiple2(dst, (A * s1).conjugate(), B, s2));
41 }
The matrix class, also used for vectors and row-vectors.
Definition: Eigen/Eigen/src/Core/Matrix.h:186
Definition: matrices.h:74
#define CALL_SUBTEST(FUNC)
Definition: main.h:382
void check_scalar_multiple2(Dst &dst, const Lhs &A, const Rhs &B, S2 s2)
Definition: product_notemporary.cpp:26

References CALL_SUBTEST, and check_scalar_multiple2().

Referenced by product_notemporary().

◆ check_scalar_multiple2()

template<typename Dst , typename Lhs , typename Rhs , typename S2 >
void check_scalar_multiple2 ( Dst &  dst,
const Lhs &  A,
const Rhs &  B,
S2  s2 
)
26  {
31  CALL_SUBTEST(check_scalar_multiple3(dst, A, (B * s2).conjugate()));
32 }
void check_scalar_multiple3(Dst &dst, const Lhs &A, const Rhs &B)
Definition: product_notemporary.cpp:16

References CALL_SUBTEST, and check_scalar_multiple3().

Referenced by check_scalar_multiple1().

◆ check_scalar_multiple3()

template<typename Dst , typename Lhs , typename Rhs >
void check_scalar_multiple3 ( Dst &  dst,
const Lhs &  A,
const Rhs &  B 
)
16  {
17  VERIFY_EVALUATION_COUNT((dst.noalias() = A * B), 0);
18  VERIFY_IS_APPROX(dst, (A.eval() * B.eval()).eval());
19  VERIFY_EVALUATION_COUNT((dst.noalias() += A * B), 0);
20  VERIFY_IS_APPROX(dst, 2 * (A.eval() * B.eval()).eval());
21  VERIFY_EVALUATION_COUNT((dst.noalias() -= A * B), 0);
22  VERIFY_IS_APPROX(dst, (A.eval() * B.eval()).eval());
23 }
#define VERIFY_IS_APPROX(a, b)
Definition: integer_types.cpp:13
#define VERIFY_EVALUATION_COUNT(XPR, N)
Definition: test/sparse_product.cpp:28

References VERIFY_EVALUATION_COUNT, and VERIFY_IS_APPROX.

Referenced by check_scalar_multiple2().

◆ EIGEN_DECLARE_TEST()

EIGEN_DECLARE_TEST ( product_notemporary  )
211  {
212  int s;
213  for (int i = 0; i < g_repeat; i++) {
214  s = internal::random<int>(16, EIGEN_TEST_MAX_SIZE);
215  CALL_SUBTEST_1(product_notemporary(MatrixXf(s, s)));
216  CALL_SUBTEST_2(product_notemporary(MatrixXd(s, s)));
218 
219  s = internal::random<int>(16, EIGEN_TEST_MAX_SIZE / 2);
220  CALL_SUBTEST_3(product_notemporary(MatrixXcf(s, s)));
221  CALL_SUBTEST_4(product_notemporary(MatrixXcd(s, s)));
223  }
224 }
int i
Definition: BiCGSTAB_step_by_step.cpp:9
#define EIGEN_TEST_MAX_SIZE
Definition: boostmultiprec.cpp:16
RealScalar s
Definition: level1_cplx_impl.h:130
#define TEST_SET_BUT_UNUSED_VARIABLE(X)
Definition: main.h:139
static int g_repeat
Definition: main.h:191
void product_notemporary(const MatrixType &m)
Definition: product_notemporary.cpp:44
#define CALL_SUBTEST_3(FUNC)
Definition: split_test_helper.h:16
#define CALL_SUBTEST_1(FUNC)
Definition: split_test_helper.h:4
#define CALL_SUBTEST_2(FUNC)
Definition: split_test_helper.h:10
#define CALL_SUBTEST_4(FUNC)
Definition: split_test_helper.h:22

References CALL_SUBTEST_1, CALL_SUBTEST_2, CALL_SUBTEST_3, CALL_SUBTEST_4, EIGEN_TEST_MAX_SIZE, Eigen::g_repeat, i, product_notemporary(), s, and TEST_SET_BUT_UNUSED_VARIABLE.

◆ product_notemporary()

template<typename MatrixType >
void product_notemporary ( const MatrixType m)
44  {
45  /* This test checks the number of temporaries created
46  * during the evaluation of a complex expression */
47  typedef typename MatrixType::Scalar Scalar;
48  typedef typename MatrixType::RealScalar RealScalar;
49  typedef Matrix<Scalar, 1, Dynamic> RowVectorType;
50  typedef Matrix<Scalar, Dynamic, 1> ColVectorType;
51  typedef Matrix<Scalar, Dynamic, Dynamic, ColMajor> ColMajorMatrixType;
52  typedef Matrix<Scalar, Dynamic, Dynamic, RowMajor> RowMajorMatrixType;
53 
54  Index rows = m.rows();
55  Index cols = m.cols();
56 
57  ColMajorMatrixType m1 = MatrixType::Random(rows, cols), m2 = MatrixType::Random(rows, cols), m3(rows, cols);
58  RowVectorType rv1 = RowVectorType::Random(rows), rvres(rows);
59  ColVectorType cv1 = ColVectorType::Random(cols), cvres(cols);
60  RowMajorMatrixType rm3(rows, cols);
61 
62  Scalar s1 = internal::random<Scalar>(), s2 = internal::random<Scalar>(), s3 = internal::random<Scalar>();
63 
64  Index c0 = internal::random<Index>(4, cols - 8), c1 = internal::random<Index>(8, cols - c0),
65  r0 = internal::random<Index>(4, cols - 8), r1 = internal::random<Index>(8, rows - r0);
66 
67  VERIFY_EVALUATION_COUNT(m3 = (m1 * m2.adjoint()), 1);
68  VERIFY_EVALUATION_COUNT(m3 = (m1 * m2.adjoint()).transpose(), 1);
69  VERIFY_EVALUATION_COUNT(m3.noalias() = (m1 * m2.adjoint()).transpose(), 0);
70  VERIFY_EVALUATION_COUNT(m3.noalias() = (m1 * m2.transpose()).adjoint(), 0);
71  VERIFY_EVALUATION_COUNT(m3.noalias() = m1 * m2.adjoint(), 0);
72 
73  VERIFY_EVALUATION_COUNT(m3 = s1 * (m1 * m2.transpose()), 1);
74  // VERIFY_EVALUATION_COUNT( m3 = m3 + s1 * (m1 * m2.transpose()), 1);
75  VERIFY_EVALUATION_COUNT(m3.noalias() = s1 * (m1 * m2.transpose()), 0);
76 
77  VERIFY_EVALUATION_COUNT(m3 = m3 + (m1 * m2.adjoint()), 1);
78  VERIFY_EVALUATION_COUNT(m3 = m3 - (m1 * m2.adjoint()), 1);
79 
80  VERIFY_EVALUATION_COUNT(m3 = m3 + (m1 * m2.adjoint()).transpose(), 1);
81  VERIFY_EVALUATION_COUNT(m3.noalias() = m3 + (m1 * m2.adjoint()).transpose(), 0);
82  VERIFY_EVALUATION_COUNT(m3.noalias() = m3 + (m1 * m2.transpose()).adjoint(), 0);
83  VERIFY_EVALUATION_COUNT(m3.noalias() = m3 + m1 * m2.transpose(), 0);
84  VERIFY_EVALUATION_COUNT(m3.noalias() += m3 + m1 * m2.transpose(), 0);
85  VERIFY_EVALUATION_COUNT(m3.noalias() -= m3 + m1 * m2.transpose(), 0);
86  VERIFY_EVALUATION_COUNT(m3.noalias() = m3 - m1 * m2.transpose(), 0);
87  VERIFY_EVALUATION_COUNT(m3.noalias() += m3 - m1 * m2.transpose(), 0);
88  VERIFY_EVALUATION_COUNT(m3.noalias() -= m3 - m1 * m2.transpose(), 0);
89 
90  VERIFY_EVALUATION_COUNT(m3.noalias() = s1 * m1 * s2 * m2.adjoint(), 0);
91  VERIFY_EVALUATION_COUNT(m3.noalias() = s1 * m1 * s2 * (m1 * s3 + m2 * s2).adjoint(), 1);
92  VERIFY_EVALUATION_COUNT(m3.noalias() = (s1 * m1).adjoint() * s2 * m2, 0);
93  VERIFY_EVALUATION_COUNT(m3.noalias() += s1 * (-m1 * s3).adjoint() * (s2 * m2 * s3), 0);
94  VERIFY_EVALUATION_COUNT(m3.noalias() -= s1 * (m1.transpose() * m2), 0);
95 
97  (m3.block(r0, r0, r1, r1).noalias() += -m1.block(r0, c0, r1, c1) * (s2 * m2.block(r0, c0, r1, c1)).adjoint()), 0);
99  (m3.block(r0, r0, r1, r1).noalias() -= s1 * m1.block(r0, c0, r1, c1) * m2.block(c0, r0, c1, r1)), 0);
100 
101  // NOTE this is because the Block expression is not handled yet by our expression analyser
103  (m3.block(r0, r0, r1, r1).noalias() = s1 * m1.block(r0, c0, r1, c1) * (s1 * m2).block(c0, r0, c1, r1)), 1);
104 
105  VERIFY_EVALUATION_COUNT(m3.noalias() -= (s1 * m1).template triangularView<Lower>() * m2, 0);
106  VERIFY_EVALUATION_COUNT(rm3.noalias() = (s1 * m1.adjoint()).template triangularView<Upper>() * (m2 + m2), 1);
107  VERIFY_EVALUATION_COUNT(rm3.noalias() = (s1 * m1.adjoint()).template triangularView<UnitUpper>() * m2.adjoint(), 0);
108 
109  VERIFY_EVALUATION_COUNT(m3.template triangularView<Upper>() = (m1 * m2.adjoint()), 0);
110  VERIFY_EVALUATION_COUNT(m3.template triangularView<Upper>() -= (m1 * m2.adjoint()), 0);
111 
112  // NOTE this is because the blas_traits require innerstride==1 to avoid a temporary, but that doesn't seem to be
113  // actually needed for the triangular products
115  rm3.col(c0).noalias() = (s1 * m1.adjoint()).template triangularView<UnitUpper>() * (s2 * m2.row(c0)).adjoint(),
116  1);
117 
118  VERIFY_EVALUATION_COUNT(m1.template triangularView<Lower>().solveInPlace(m3), 0);
119  VERIFY_EVALUATION_COUNT(m1.adjoint().template triangularView<Lower>().solveInPlace(m3.transpose()), 0);
120 
121  VERIFY_EVALUATION_COUNT(m3.noalias() -= (s1 * m1).adjoint().template selfadjointView<Lower>() * (-m2 * s3).adjoint(),
122  0);
123  VERIFY_EVALUATION_COUNT(m3.noalias() = s2 * m2.adjoint() * (s1 * m1.adjoint()).template selfadjointView<Upper>(), 0);
124  VERIFY_EVALUATION_COUNT(rm3.noalias() = (s1 * m1.adjoint()).template selfadjointView<Lower>() * m2.adjoint(), 0);
125 
126  // NOTE this is because the blas_traits require innerstride==1 to avoid a temporary, but that doesn't seem to be
127  // actually needed for the triangular products
129  m3.col(c0).noalias() = (s1 * m1).adjoint().template selfadjointView<Lower>() * (-m2.row(c0) * s3).adjoint(), 1);
131  m3.col(c0).noalias() -= (s1 * m1).adjoint().template selfadjointView<Upper>() * (-m2.row(c0) * s3).adjoint(), 1);
132 
133  VERIFY_EVALUATION_COUNT(m3.block(r0, c0, r1, c1).noalias() +=
134  m1.block(r0, r0, r1, r1).template selfadjointView<Upper>() * (s1 * m2.block(r0, c0, r1, c1)),
135  0);
136  VERIFY_EVALUATION_COUNT(m3.block(r0, c0, r1, c1).noalias() =
137  m1.block(r0, r0, r1, r1).template selfadjointView<Upper>() * m2.block(r0, c0, r1, c1),
138  0);
139 
140  VERIFY_EVALUATION_COUNT(m3.template selfadjointView<Lower>().rankUpdate(m2.adjoint()), 0);
141 
142  // Here we will get 1 temporary for each resize operation of the lhs operator; resize(r1,c1) would lead to zero
143  // temporaries
144  m3.resize(1, 1);
146  m3.noalias() = m1.block(r0, r0, r1, r1).template selfadjointView<Lower>() * m2.block(r0, c0, r1, c1), 1);
147  m3.resize(1, 1);
149  m3.noalias() = m1.block(r0, r0, r1, r1).template triangularView<UnitUpper>() * m2.block(r0, c0, r1, c1), 1);
150 
151  // Zero temporaries for lazy products ...
152  m3.setRandom(rows, cols);
154  tmp += Scalar(RealScalar(1)) / (m3.transpose().lazyProduct(m3)).diagonal().sum(), 0);
155  VERIFY_EVALUATION_COUNT(m3.noalias() = m1.conjugate().lazyProduct(m2.conjugate()), 0);
156 
157  // ... and even no temporary for even deeply (>=2) nested products
158  VERIFY_EVALUATION_COUNT(Scalar tmp = 0; tmp += Scalar(RealScalar(1)) / (m3.transpose() * m3).diagonal().sum(), 0);
160  tmp += Scalar(RealScalar(1)) / (m3.transpose() * m3).diagonal().array().abs().sum(), 0);
161 
162  // Zero temporaries for ... CoeffBasedProductMode
164  m3.col(0).template head<5>() * m3.col(0).transpose() + m3.col(0).template head<5>() * m3.col(0).transpose(), 0);
165 
166  // Check matrix * vectors
167  VERIFY_EVALUATION_COUNT(cvres.noalias() = m1 * cv1, 0);
168  VERIFY_EVALUATION_COUNT(cvres.noalias() -= m1 * cv1, 0);
169  VERIFY_EVALUATION_COUNT(cvres.noalias() -= m1 * m2.col(0), 0);
170  VERIFY_EVALUATION_COUNT(cvres.noalias() -= m1 * rv1.adjoint(), 0);
171  VERIFY_EVALUATION_COUNT(cvres.noalias() -= m1 * m2.row(0).transpose(), 0);
172 
173  VERIFY_EVALUATION_COUNT(cvres.noalias() = (m1 + m1) * cv1, 0);
174  VERIFY_EVALUATION_COUNT(cvres.noalias() = (rm3 + rm3) * cv1, 0);
175  VERIFY_EVALUATION_COUNT(cvres.noalias() = (m1 + m1) * (m1 * cv1), 1);
176  VERIFY_EVALUATION_COUNT(cvres.noalias() = (rm3 + rm3) * (m1 * cv1), 1);
177 
178 // Check outer products
179 #ifdef EIGEN_ALLOCA
180  bool temp_via_alloca = m3.rows() * sizeof(Scalar) <= EIGEN_STACK_ALLOCATION_LIMIT;
181 #else
182  bool temp_via_alloca = false;
183 #endif
184  m3 = cv1 * rv1;
185  VERIFY_EVALUATION_COUNT(m3.noalias() = cv1 * rv1, 0);
186  VERIFY_EVALUATION_COUNT(m3.noalias() = (cv1 + cv1) * (rv1 + rv1), temp_via_alloca ? 0 : 1);
187  VERIFY_EVALUATION_COUNT(m3.noalias() = (m1 * cv1) * (rv1), 1);
188  VERIFY_EVALUATION_COUNT(m3.noalias() += (m1 * cv1) * (rv1), 1);
189  rm3 = cv1 * rv1;
190  VERIFY_EVALUATION_COUNT(rm3.noalias() = cv1 * rv1, 0);
191  VERIFY_EVALUATION_COUNT(rm3.noalias() = (cv1 + cv1) * (rv1 + rv1), temp_via_alloca ? 0 : 1);
192  VERIFY_EVALUATION_COUNT(rm3.noalias() = (cv1) * (rv1 * m1), 1);
193  VERIFY_EVALUATION_COUNT(rm3.noalias() -= (cv1) * (rv1 * m1), 1);
194  VERIFY_EVALUATION_COUNT(rm3.noalias() = (m1 * cv1) * (rv1 * m1), 2);
195  VERIFY_EVALUATION_COUNT(rm3.noalias() += (m1 * cv1) * (rv1 * m1), 2);
196 
197  // Check nested products
198  VERIFY_EVALUATION_COUNT(cvres.noalias() = m1.adjoint() * m1 * cv1, 1);
199  VERIFY_EVALUATION_COUNT(rvres.noalias() = rv1 * (m1 * m2.adjoint()), 1);
200 
201  // exhaustively check all scalar multiple combinations:
202  {
203  // Generic path:
204  check_scalar_multiple1(m3, m1, m2, s1, s2);
205  // Force fall back to coeff-based:
206  typename ColMajorMatrixType::BlockXpr m3_blck = m3.block(r0, r0, 1, 1);
207  check_scalar_multiple1(m3_blck, m1.block(r0, c0, 1, 1), m2.block(c0, r0, 1, 1), s1, s2);
208  }
209 }
Matrix3d m1
Definition: IOFormat.cpp:2
#define EIGEN_STACK_ALLOCATION_LIMIT
Definition: Macros.h:56
MatrixType m2(n_dims)
int rows
Definition: Tutorial_commainit_02.cpp:1
int cols
Definition: Tutorial_commainit_02.cpp:1
SCALAR Scalar
Definition: bench_gemm.cpp:45
NumTraits< Scalar >::Real RealScalar
Definition: bench_gemm.cpp:46
void diagonal(const MatrixType &m)
Definition: diagonal.cpp:13
int * m
Definition: level2_cplx_impl.h:294
Eigen::Matrix< Scalar, Dynamic, Dynamic, ColMajor > tmp
Definition: level3_impl.h:365
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
The Index type as used for the API.
Definition: Meta.h:83
void check_scalar_multiple1(Dst &dst, const Lhs &A, const Rhs &B, S1 s1, S2 s2)
Definition: product_notemporary.cpp:35

References check_scalar_multiple1(), cols, diagonal(), EIGEN_STACK_ALLOCATION_LIMIT, m, m1, m2(), rows, tmp, and VERIFY_EVALUATION_COUNT.

Referenced by EIGEN_DECLARE_TEST().