cxx11_tensor_contraction.cpp File Reference
#include "main.h"
#include <Eigen/CXX11/Tensor>

Classes

struct  SqrtOutputKernel
 

Typedefs

typedef Tensor< float, 1 >::DimensionPair DimPair
 

Functions

template<int DataLayout>
static void test_evals ()
 
template<int DataLayout>
static void test_scalar ()
 
template<int DataLayout>
static void test_multidims ()
 
template<int DataLayout>
static void test_holes ()
 
template<int DataLayout>
static void test_full_redux ()
 
template<int DataLayout>
static void test_contraction_of_contraction ()
 
template<int DataLayout>
static void test_expr ()
 
template<int DataLayout>
static void test_out_of_order_contraction ()
 
template<int DataLayout>
static void test_consistency ()
 
template<int DataLayout>
static void test_large_contraction ()
 
template<int DataLayout>
static void test_matrix_vector ()
 
template<int DataLayout>
static void test_tensor_vector ()
 
template<int DataLayout>
static void test_small_blocking_factors ()
 
template<int DataLayout>
static void test_tensor_product ()
 
template<int DataLayout>
static void test_const_inputs ()
 
template<int DataLayout>
static void test_large_contraction_with_output_kernel ()
 
 EIGEN_DECLARE_TEST (cxx11_tensor_contraction)
 

Typedef Documentation

◆ DimPair

typedef Tensor<float, 1>::DimensionPair DimPair

Function Documentation

◆ EIGEN_DECLARE_TEST()

EIGEN_DECLARE_TEST ( cxx11_tensor_contraction  )
531  {
532  CALL_SUBTEST_1(test_evals<ColMajor>());
533  CALL_SUBTEST_1(test_evals<RowMajor>());
534  CALL_SUBTEST_1(test_scalar<ColMajor>());
535  CALL_SUBTEST_1(test_scalar<RowMajor>());
536  CALL_SUBTEST_2(test_multidims<ColMajor>());
537  CALL_SUBTEST_2(test_multidims<RowMajor>());
538  CALL_SUBTEST_2(test_holes<ColMajor>());
539  CALL_SUBTEST_2(test_holes<RowMajor>());
540  CALL_SUBTEST_3(test_full_redux<ColMajor>());
541  CALL_SUBTEST_3(test_full_redux<RowMajor>());
542  CALL_SUBTEST_3(test_contraction_of_contraction<ColMajor>());
543  CALL_SUBTEST_3(test_contraction_of_contraction<RowMajor>());
544  CALL_SUBTEST_4(test_expr<ColMajor>());
545  CALL_SUBTEST_4(test_expr<RowMajor>());
546  CALL_SUBTEST_4(test_out_of_order_contraction<ColMajor>());
547  CALL_SUBTEST_4(test_out_of_order_contraction<RowMajor>());
548  CALL_SUBTEST_5(test_consistency<ColMajor>());
549  CALL_SUBTEST_5(test_consistency<RowMajor>());
550  CALL_SUBTEST_5(test_large_contraction<ColMajor>());
551  CALL_SUBTEST_5(test_large_contraction<RowMajor>());
552  CALL_SUBTEST_6(test_matrix_vector<ColMajor>());
553  CALL_SUBTEST_6(test_matrix_vector<RowMajor>());
554  CALL_SUBTEST_6(test_tensor_vector<ColMajor>());
555  CALL_SUBTEST_6(test_tensor_vector<RowMajor>());
556  CALL_SUBTEST_7(test_small_blocking_factors<ColMajor>());
557  CALL_SUBTEST_7(test_small_blocking_factors<RowMajor>());
558  CALL_SUBTEST_7(test_tensor_product<ColMajor>());
559  CALL_SUBTEST_7(test_tensor_product<RowMajor>());
560  CALL_SUBTEST_8(test_const_inputs<ColMajor>());
561  CALL_SUBTEST_8(test_const_inputs<RowMajor>());
562  CALL_SUBTEST_8(test_large_contraction_with_output_kernel<ColMajor>());
563  CALL_SUBTEST_8(test_large_contraction_with_output_kernel<RowMajor>());
564 
565  // Force CMake to split this test.
566  // EIGEN_SUFFIXES;1;2;3;4;5;6;7;8
567 }
#define CALL_SUBTEST_6(FUNC)
Definition: split_test_helper.h:34
#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_8(FUNC)
Definition: split_test_helper.h:46
#define CALL_SUBTEST_5(FUNC)
Definition: split_test_helper.h:28
#define CALL_SUBTEST_2(FUNC)
Definition: split_test_helper.h:10
#define CALL_SUBTEST_7(FUNC)
Definition: split_test_helper.h:40
#define CALL_SUBTEST_4(FUNC)
Definition: split_test_helper.h:22

References CALL_SUBTEST_1, CALL_SUBTEST_2, CALL_SUBTEST_3, CALL_SUBTEST_4, CALL_SUBTEST_5, CALL_SUBTEST_6, CALL_SUBTEST_7, and CALL_SUBTEST_8.

◆ test_consistency()

template<int DataLayout>
static void test_consistency ( )
static
295  {
296  // this does something like testing (A*B)^T = (B^T * A^T)
297 
299  Tensor<float, 5, DataLayout> mat2(3, 2, 1, 5, 4);
300  mat1.setRandom();
301  mat2.setRandom();
302 
303  Tensor<float, 4, DataLayout> mat3(5, 2, 1, 5);
304  Tensor<float, 4, DataLayout> mat4(2, 1, 5, 5);
305 
306  // contract on dimensions of size 4 and 3
307  Eigen::array<DimPair, 2> dims1 = {{DimPair(0, 4), DimPair(1, 0)}};
308  Eigen::array<DimPair, 2> dims2 = {{DimPair(4, 0), DimPair(0, 1)}};
309 
310  mat3 = mat1.contract(mat2, dims1);
311  mat4 = mat2.contract(mat1, dims2);
312 
313  // check that these are equal except for ordering of dimensions
314  if (DataLayout == ColMajor) {
315  for (size_t i = 0; i < 5; i++) {
316  for (size_t j = 0; j < 10; j++) {
317  VERIFY_IS_APPROX(mat3.data()[i + 5 * j], mat4.data()[j + 10 * i]);
318  }
319  }
320  } else {
321  // Row major
322  for (size_t i = 0; i < 5; i++) {
323  for (size_t j = 0; j < 10; j++) {
324  VERIFY_IS_APPROX(mat3.data()[10 * i + j], mat4.data()[i + 5 * j]);
325  }
326  }
327  }
328 }
int i
Definition: BiCGSTAB_step_by_step.cpp:9
MatrixXd mat1(size, size)
The tensor class.
Definition: Tensor.h:68
Tensor< float, 1 >::DimensionPair DimPair
Definition: cxx11_tensor_contraction.cpp:17
static const int DataLayout
Definition: cxx11_tensor_image_patch_sycl.cpp:24
@ ColMajor
Definition: Constants.h:318
#define VERIFY_IS_APPROX(a, b)
Definition: integer_types.cpp:13
std::array< T, N > array
Definition: EmulateArray.h:231
std::ptrdiff_t j
Definition: tut_arithmetic_redux_minmax.cpp:2

References Eigen::ColMajor, Eigen::Tensor< Scalar_, NumIndices_, Options_, IndexType_ >::data(), DataLayout, i, j, mat1(), Eigen::TensorBase< Derived, AccessLevel >::setRandom(), and VERIFY_IS_APPROX.

◆ test_const_inputs()

template<int DataLayout>
static void test_const_inputs ( )
static
464  {
467  in1.setRandom();
468  in2.setRandom();
469 
471  TensorMap<Tensor<const float, 2, DataLayout>> mat2(in2.data(), 3, 2);
472  Tensor<float, 2, DataLayout> mat3(2, 2);
473 
474  Eigen::array<DimPair, 1> dims = {{DimPair(1, 0)}};
475  mat3 = mat1.contract(mat2, dims);
476 
477  VERIFY_IS_APPROX(mat3(0, 0), mat1(0, 0) * mat2(0, 0) + mat1(0, 1) * mat2(1, 0) + mat1(0, 2) * mat2(2, 0));
478  VERIFY_IS_APPROX(mat3(0, 1), mat1(0, 0) * mat2(0, 1) + mat1(0, 1) * mat2(1, 1) + mat1(0, 2) * mat2(2, 1));
479  VERIFY_IS_APPROX(mat3(1, 0), mat1(1, 0) * mat2(0, 0) + mat1(1, 1) * mat2(1, 0) + mat1(1, 2) * mat2(2, 0));
480  VERIFY_IS_APPROX(mat3(1, 1), mat1(1, 0) * mat2(0, 1) + mat1(1, 1) * mat2(1, 1) + mat1(1, 2) * mat2(2, 1));
481 }
A tensor expression mapping an existing array of data.
Definition: TensorMap.h:33

References Eigen::Tensor< Scalar_, NumIndices_, Options_, IndexType_ >::data(), mat1(), Eigen::TensorBase< Derived, AccessLevel >::setRandom(), and VERIFY_IS_APPROX.

◆ test_contraction_of_contraction()

template<int DataLayout>
static void test_contraction_of_contraction ( )
static
212  {
217  t1.setRandom();
218  t2.setRandom();
219  t3.setRandom();
220  t4.setRandom();
221 
222  Eigen::array<DimPair, 1> dims = {{DimPair(1, 0)}};
223  auto contract1 = t1.contract(t2, dims);
224  auto diff = t3 - contract1;
225  auto contract2 = t1.contract(t4, dims);
226  Tensor<float, 2, DataLayout> result = contract2.contract(diff, dims);
227 
228  VERIFY_IS_EQUAL(result.dimension(0), 2);
229  VERIFY_IS_EQUAL(result.dimension(1), 2);
230 
231  Eigen::Map<Eigen::Matrix<float, Dynamic, Dynamic, DataLayout>> m1(t1.data(), 2, 2), m2(t2.data(), 2, 2),
232  m3(t3.data(), 2, 2), m4(t4.data(), 2, 2);
233  Eigen::Matrix<float, Dynamic, Dynamic, DataLayout> expected = (m1 * m4) * (m3 - m1 * m2);
234 
235  VERIFY_IS_APPROX(result(0, 0), expected(0, 0));
236  VERIFY_IS_APPROX(result(0, 1), expected(0, 1));
237  VERIFY_IS_APPROX(result(1, 0), expected(1, 0));
238  VERIFY_IS_APPROX(result(1, 1), expected(1, 1));
239 }
Matrix3d m1
Definition: IOFormat.cpp:2
MatrixType m2(n_dims)
A matrix or vector expression mapping an existing array of data.
Definition: Map.h:96
The matrix class, also used for vectors and row-vectors.
Definition: Eigen/Eigen/src/Core/Matrix.h:186
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Index dimension(std::size_t n) const
Definition: Tensor.h:99
#define VERIFY_IS_EQUAL(a, b)
Definition: main.h:367

References Eigen::Tensor< Scalar_, NumIndices_, Options_, IndexType_ >::data(), Eigen::Tensor< Scalar_, NumIndices_, Options_, IndexType_ >::dimension(), m1, m2(), Eigen::TensorBase< Derived, AccessLevel >::setRandom(), VERIFY_IS_APPROX, and VERIFY_IS_EQUAL.

◆ test_evals()

template<int DataLayout>
static void test_evals ( )
static
20  {
24 
25  mat1.setRandom();
26  mat2.setRandom();
27  mat3.setRandom();
28 
30  mat4.setZero();
31  Eigen::array<DimPair, 1> dims3 = {{DimPair(0, 0)}};
32  typedef TensorEvaluator<decltype(mat1.contract(mat2, dims3)), DefaultDevice> Evaluator;
33  Evaluator eval(mat1.contract(mat2, dims3), DefaultDevice());
34  eval.evalTo(mat4.data());
35  EIGEN_STATIC_ASSERT(Evaluator::NumDims == 2ul, YOU_MADE_A_PROGRAMMING_MISTAKE);
36  VERIFY_IS_EQUAL(eval.dimensions()[0], 3);
37  VERIFY_IS_EQUAL(eval.dimensions()[1], 3);
38 
39  VERIFY_IS_APPROX(mat4(0, 0), mat1(0, 0) * mat2(0, 0) + mat1(1, 0) * mat2(1, 0));
40  VERIFY_IS_APPROX(mat4(0, 1), mat1(0, 0) * mat2(0, 1) + mat1(1, 0) * mat2(1, 1));
41  VERIFY_IS_APPROX(mat4(0, 2), mat1(0, 0) * mat2(0, 2) + mat1(1, 0) * mat2(1, 2));
42  VERIFY_IS_APPROX(mat4(1, 0), mat1(0, 1) * mat2(0, 0) + mat1(1, 1) * mat2(1, 0));
43  VERIFY_IS_APPROX(mat4(1, 1), mat1(0, 1) * mat2(0, 1) + mat1(1, 1) * mat2(1, 1));
44  VERIFY_IS_APPROX(mat4(1, 2), mat1(0, 1) * mat2(0, 2) + mat1(1, 1) * mat2(1, 2));
45  VERIFY_IS_APPROX(mat4(2, 0), mat1(0, 2) * mat2(0, 0) + mat1(1, 2) * mat2(1, 0));
46  VERIFY_IS_APPROX(mat4(2, 1), mat1(0, 2) * mat2(0, 1) + mat1(1, 2) * mat2(1, 1));
47  VERIFY_IS_APPROX(mat4(2, 2), mat1(0, 2) * mat2(0, 2) + mat1(1, 2) * mat2(1, 2));
48 
50  mat5.setZero();
51  Eigen::array<DimPair, 1> dims4 = {{DimPair(1, 1)}};
52  typedef TensorEvaluator<decltype(mat1.contract(mat2, dims4)), DefaultDevice> Evaluator2;
53  Evaluator2 eval2(mat1.contract(mat2, dims4), DefaultDevice());
54  eval2.evalTo(mat5.data());
55  EIGEN_STATIC_ASSERT(Evaluator2::NumDims == 2ul, YOU_MADE_A_PROGRAMMING_MISTAKE);
56  VERIFY_IS_EQUAL(eval2.dimensions()[0], 2);
57  VERIFY_IS_EQUAL(eval2.dimensions()[1], 2);
58 
59  VERIFY_IS_APPROX(mat5(0, 0), mat1(0, 0) * mat2(0, 0) + mat1(0, 1) * mat2(0, 1) + mat1(0, 2) * mat2(0, 2));
60  VERIFY_IS_APPROX(mat5(0, 1), mat1(0, 0) * mat2(1, 0) + mat1(0, 1) * mat2(1, 1) + mat1(0, 2) * mat2(1, 2));
61  VERIFY_IS_APPROX(mat5(1, 0), mat1(1, 0) * mat2(0, 0) + mat1(1, 1) * mat2(0, 1) + mat1(1, 2) * mat2(0, 2));
62  VERIFY_IS_APPROX(mat5(1, 1), mat1(1, 0) * mat2(1, 0) + mat1(1, 1) * mat2(1, 1) + mat1(1, 2) * mat2(1, 2));
63 
65  mat6.setZero();
66  Eigen::array<DimPair, 1> dims6 = {{DimPair(1, 0)}};
67  typedef TensorEvaluator<decltype(mat1.contract(mat3, dims6)), DefaultDevice> Evaluator3;
68  Evaluator3 eval3(mat1.contract(mat3, dims6), DefaultDevice());
69  eval3.evalTo(mat6.data());
70  EIGEN_STATIC_ASSERT(Evaluator3::NumDims == 2ul, YOU_MADE_A_PROGRAMMING_MISTAKE);
71  VERIFY_IS_EQUAL(eval3.dimensions()[0], 2);
72  VERIFY_IS_EQUAL(eval3.dimensions()[1], 2);
73 
74  VERIFY_IS_APPROX(mat6(0, 0), mat1(0, 0) * mat3(0, 0) + mat1(0, 1) * mat3(1, 0) + mat1(0, 2) * mat3(2, 0));
75  VERIFY_IS_APPROX(mat6(0, 1), mat1(0, 0) * mat3(0, 1) + mat1(0, 1) * mat3(1, 1) + mat1(0, 2) * mat3(2, 1));
76  VERIFY_IS_APPROX(mat6(1, 0), mat1(1, 0) * mat3(0, 0) + mat1(1, 1) * mat3(1, 0) + mat1(1, 2) * mat3(2, 0));
77  VERIFY_IS_APPROX(mat6(1, 1), mat1(1, 0) * mat3(0, 1) + mat1(1, 1) * mat3(1, 1) + mat1(1, 2) * mat3(2, 1));
78 }
#define EIGEN_STATIC_ASSERT(X, MSG)
Definition: StaticAssert.h:26
internal::nested_eval< T, 1 >::type eval(const T &xpr)
Definition: sparse_permutations.cpp:47
Definition: TensorDeviceDefault.h:19
A cost model used to limit the number of threads used for evaluating tensor expression.
Definition: TensorEvaluator.h:31

References Eigen::Tensor< Scalar_, NumIndices_, Options_, IndexType_ >::data(), EIGEN_STATIC_ASSERT, eval(), mat1(), Eigen::TensorBase< Derived, AccessLevel >::setRandom(), Eigen::TensorBase< Derived, AccessLevel >::setZero(), VERIFY_IS_APPROX, and VERIFY_IS_EQUAL.

◆ test_expr()

template<int DataLayout>
static void test_expr ( )
static
242  {
244  Tensor<float, 2, DataLayout> mat2(3, 2);
245  mat1.setRandom();
246  mat2.setRandom();
247 
248  Tensor<float, 2, DataLayout> mat3(2, 2);
249 
250  Eigen::array<DimPair, 1> dims = {{DimPair(1, 0)}};
251  mat3 = mat1.contract(mat2, dims);
252 
253  VERIFY_IS_APPROX(mat3(0, 0), mat1(0, 0) * mat2(0, 0) + mat1(0, 1) * mat2(1, 0) + mat1(0, 2) * mat2(2, 0));
254  VERIFY_IS_APPROX(mat3(0, 1), mat1(0, 0) * mat2(0, 1) + mat1(0, 1) * mat2(1, 1) + mat1(0, 2) * mat2(2, 1));
255  VERIFY_IS_APPROX(mat3(1, 0), mat1(1, 0) * mat2(0, 0) + mat1(1, 1) * mat2(1, 0) + mat1(1, 2) * mat2(2, 0));
256  VERIFY_IS_APPROX(mat3(1, 1), mat1(1, 0) * mat2(0, 1) + mat1(1, 1) * mat2(1, 1) + mat1(1, 2) * mat2(2, 1));
257 }

References mat1(), Eigen::TensorBase< Derived, AccessLevel >::setRandom(), and VERIFY_IS_APPROX.

◆ test_full_redux()

template<int DataLayout>
static void test_full_redux ( )
static
187  {
189  Tensor<float, 3, DataLayout> t2(2, 2, 2);
190  t1.setRandom();
191  t2.setRandom();
192 
193  Eigen::array<DimPair, 2> dims = {{DimPair(0, 0), DimPair(1, 1)}};
194  Tensor<float, 1, DataLayout> result = t1.contract(t2, dims);
195  VERIFY_IS_EQUAL(result.dimension(0), 2);
196  VERIFY_IS_APPROX(result(0),
197  t1(0, 0) * t2(0, 0, 0) + t1(1, 0) * t2(1, 0, 0) + t1(0, 1) * t2(0, 1, 0) + t1(1, 1) * t2(1, 1, 0));
198  VERIFY_IS_APPROX(result(1),
199  t1(0, 0) * t2(0, 0, 1) + t1(1, 0) * t2(1, 0, 1) + t1(0, 1) * t2(0, 1, 1) + t1(1, 1) * t2(1, 1, 1));
200 
201  dims[0] = DimPair(1, 0);
202  dims[1] = DimPair(2, 1);
203  result = t2.contract(t1, dims);
204  VERIFY_IS_EQUAL(result.dimension(0), 2);
205  VERIFY_IS_APPROX(result(0),
206  t1(0, 0) * t2(0, 0, 0) + t1(1, 0) * t2(0, 1, 0) + t1(0, 1) * t2(0, 0, 1) + t1(1, 1) * t2(0, 1, 1));
207  VERIFY_IS_APPROX(result(1),
208  t1(0, 0) * t2(1, 0, 0) + t1(1, 0) * t2(1, 1, 0) + t1(0, 1) * t2(1, 0, 1) + t1(1, 1) * t2(1, 1, 1));
209 }

References Eigen::Tensor< Scalar_, NumIndices_, Options_, IndexType_ >::dimension(), Eigen::TensorBase< Derived, AccessLevel >::setRandom(), VERIFY_IS_APPROX, and VERIFY_IS_EQUAL.

◆ test_holes()

template<int DataLayout>
static void test_holes ( )
static
156  {
157  Tensor<float, 4, DataLayout> t1(2, 5, 7, 3);
158  Tensor<float, 5, DataLayout> t2(2, 7, 11, 13, 3);
159  t1.setRandom();
160  t2.setRandom();
161 
162  Eigen::array<DimPair, 2> dims = {{DimPair(0, 0), DimPair(3, 4)}};
163  Tensor<float, 5, DataLayout> result = t1.contract(t2, dims);
164  VERIFY_IS_EQUAL(result.dimension(0), 5);
165  VERIFY_IS_EQUAL(result.dimension(1), 7);
166  VERIFY_IS_EQUAL(result.dimension(2), 7);
167  VERIFY_IS_EQUAL(result.dimension(3), 11);
168  VERIFY_IS_EQUAL(result.dimension(4), 13);
169 
170  for (int i = 0; i < 5; ++i) {
171  for (int j = 0; j < 5; ++j) {
172  for (int k = 0; k < 5; ++k) {
173  for (int l = 0; l < 5; ++l) {
174  for (int m = 0; m < 5; ++m) {
175  VERIFY_IS_APPROX(result(i, j, k, l, m),
176  t1(0, i, j, 0) * t2(0, k, l, m, 0) + t1(1, i, j, 0) * t2(1, k, l, m, 0) +
177  t1(0, i, j, 1) * t2(0, k, l, m, 1) + t1(1, i, j, 1) * t2(1, k, l, m, 1) +
178  t1(0, i, j, 2) * t2(0, k, l, m, 2) + t1(1, i, j, 2) * t2(1, k, l, m, 2));
179  }
180  }
181  }
182  }
183  }
184 }
int * m
Definition: level2_cplx_impl.h:294
char char char int int * k
Definition: level2_impl.h:374

References Eigen::Tensor< Scalar_, NumIndices_, Options_, IndexType_ >::dimension(), i, j, k, m, Eigen::TensorBase< Derived, AccessLevel >::setRandom(), VERIFY_IS_APPROX, and VERIFY_IS_EQUAL.

◆ test_large_contraction()

template<int DataLayout>
static void test_large_contraction ( )
static
331  {
332  Tensor<float, 4, DataLayout> t_left(30, 50, 8, 31);
333  Tensor<float, 5, DataLayout> t_right(8, 31, 7, 20, 10);
334  Tensor<float, 5, DataLayout> t_result(30, 50, 7, 20, 10);
335 
336  t_left.setRandom();
337  t_right.setRandom();
338 
339  // Add a little offset so that the results won't be close to zero.
340  t_left += t_left.constant(1.0f);
341  t_right += t_right.constant(1.0f);
342 
344  MapXf m_left(t_left.data(), 1500, 248);
345  MapXf m_right(t_right.data(), 248, 1400);
347 
348  // this contraction should be equivalent to a single matrix multiplication
349  Eigen::array<DimPair, 2> dims = {{DimPair(2, 0), DimPair(3, 1)}};
350 
351  // compute results by separate methods
352  t_result = t_left.contract(t_right, dims);
353  m_result = m_left * m_right;
354 
355  for (int i = 0; i < t_result.dimensions().TotalSize(); i++) {
356  VERIFY(&t_result.data()[i] != &m_result.data()[i]);
357  VERIFY_IS_APPROX(t_result.data()[i], m_result.data()[i]);
358  }
359 }
#define VERIFY(a)
Definition: main.h:362

References Eigen::Tensor< Scalar_, NumIndices_, Options_, IndexType_ >::data(), Eigen::PlainObjectBase< Derived >::data(), Eigen::Tensor< Scalar_, NumIndices_, Options_, IndexType_ >::dimensions(), i, Eigen::TensorBase< Derived, AccessLevel >::setRandom(), VERIFY, and VERIFY_IS_APPROX.

◆ test_large_contraction_with_output_kernel()

template<int DataLayout>
static void test_large_contraction_with_output_kernel ( )
static
498  {
499  Tensor<float, 4, DataLayout> t_left(30, 50, 8, 31);
500  Tensor<float, 5, DataLayout> t_right(8, 31, 7, 20, 10);
501  Tensor<float, 5, DataLayout> t_result(30, 50, 7, 20, 10);
502 
503  t_left.setRandom();
504  t_right.setRandom();
505  // Put trash in mat4 to verify contraction clears output memory.
506  t_result.setRandom();
507 
508  // Add a little offset so that the results won't be close to zero.
509  t_left += t_left.constant(1.0f);
510  t_right += t_right.constant(1.0f);
511 
513  MapXf m_left(t_left.data(), 1500, 248);
514  MapXf m_right(t_right.data(), 248, 1400);
516 
517  // this contraction should be equivalent to a single matrix multiplication
518  Eigen::array<DimPair, 2> dims({{DimPair(2, 0), DimPair(3, 1)}});
519 
520  // compute results by separate methods
521  t_result = t_left.contract(t_right, dims, SqrtOutputKernel());
522 
523  m_result = m_left * m_right;
524 
525  for (std::ptrdiff_t i = 0; i < t_result.dimensions().TotalSize(); i++) {
526  VERIFY(&t_result.data()[i] != &m_result.data()[i]);
527  VERIFY_IS_APPROX(t_result.data()[i], std::sqrt(m_result.data()[i]));
528  }
529 }
AnnoyingScalar sqrt(const AnnoyingScalar &x)
Definition: AnnoyingScalar.h:134
Definition: cxx11_tensor_contraction.cpp:484

References Eigen::Tensor< Scalar_, NumIndices_, Options_, IndexType_ >::data(), Eigen::PlainObjectBase< Derived >::data(), Eigen::Tensor< Scalar_, NumIndices_, Options_, IndexType_ >::dimensions(), i, Eigen::TensorBase< Derived, AccessLevel >::setRandom(), sqrt(), Eigen::DSizes< DenseIndex, NumDims >::TotalSize(), VERIFY, and VERIFY_IS_APPROX.

◆ test_matrix_vector()

template<int DataLayout>
static void test_matrix_vector ( )
static
362  {
363  Tensor<float, 2, DataLayout> t_left(30, 50);
364  Tensor<float, 1, DataLayout> t_right(50);
365  Tensor<float, 1, DataLayout> t_result(30);
366 
367  t_left.setRandom();
368  t_right.setRandom();
369 
371  MapXf m_left(t_left.data(), 30, 50);
372  MapXf m_right(t_right.data(), 50, 1);
374 
375  // this contraction should be equivalent to a single matrix multiplication
376  Eigen::array<DimPair, 1> dims{{DimPair(1, 0)}};
377 
378  // compute results by separate methods
379  t_result = t_left.contract(t_right, dims);
380  m_result = m_left * m_right;
381 
382  for (int i = 0; i < t_result.dimensions().TotalSize(); i++) {
383  VERIFY(internal::isApprox(t_result(i), m_result(i, 0), 1));
384  }
385 }
EIGEN_DEVICE_FUNC bool isApprox(const Scalar &x, const Scalar &y, const typename NumTraits< Scalar >::Real &precision=NumTraits< Scalar >::dummy_precision())
Definition: MathFunctions.h:1923

References Eigen::Tensor< Scalar_, NumIndices_, Options_, IndexType_ >::data(), Eigen::Tensor< Scalar_, NumIndices_, Options_, IndexType_ >::dimensions(), i, Eigen::internal::isApprox(), Eigen::TensorBase< Derived, AccessLevel >::setRandom(), and VERIFY.

◆ test_multidims()

template<int DataLayout>
static void test_multidims ( )
static
99  {
101  Tensor<float, 4, DataLayout> mat2(2, 2, 2, 2);
102 
103  mat1.setRandom();
104  mat2.setRandom();
105 
106  Tensor<float, 3, DataLayout> mat3(2, 2, 2);
107  mat3.setZero();
108  Eigen::array<DimPair, 2> dims = {{DimPair(1, 2), DimPair(2, 3)}};
109  typedef TensorEvaluator<decltype(mat1.contract(mat2, dims)), DefaultDevice> Evaluator;
110  Evaluator eval(mat1.contract(mat2, dims), DefaultDevice());
111  eval.evalTo(mat3.data());
112  EIGEN_STATIC_ASSERT(Evaluator::NumDims == 3ul, YOU_MADE_A_PROGRAMMING_MISTAKE);
113  VERIFY_IS_EQUAL(eval.dimensions()[0], 2);
114  VERIFY_IS_EQUAL(eval.dimensions()[1], 2);
115  VERIFY_IS_EQUAL(eval.dimensions()[2], 2);
116 
117  VERIFY_IS_APPROX(mat3(0, 0, 0), mat1(0, 0, 0) * mat2(0, 0, 0, 0) + mat1(0, 1, 0) * mat2(0, 0, 1, 0) +
118  mat1(0, 0, 1) * mat2(0, 0, 0, 1) + mat1(0, 1, 1) * mat2(0, 0, 1, 1));
119  VERIFY_IS_APPROX(mat3(0, 0, 1), mat1(0, 0, 0) * mat2(0, 1, 0, 0) + mat1(0, 1, 0) * mat2(0, 1, 1, 0) +
120  mat1(0, 0, 1) * mat2(0, 1, 0, 1) + mat1(0, 1, 1) * mat2(0, 1, 1, 1));
121  VERIFY_IS_APPROX(mat3(0, 1, 0), mat1(0, 0, 0) * mat2(1, 0, 0, 0) + mat1(0, 1, 0) * mat2(1, 0, 1, 0) +
122  mat1(0, 0, 1) * mat2(1, 0, 0, 1) + mat1(0, 1, 1) * mat2(1, 0, 1, 1));
123  VERIFY_IS_APPROX(mat3(0, 1, 1), mat1(0, 0, 0) * mat2(1, 1, 0, 0) + mat1(0, 1, 0) * mat2(1, 1, 1, 0) +
124  mat1(0, 0, 1) * mat2(1, 1, 0, 1) + mat1(0, 1, 1) * mat2(1, 1, 1, 1));
125  VERIFY_IS_APPROX(mat3(1, 0, 0), mat1(1, 0, 0) * mat2(0, 0, 0, 0) + mat1(1, 1, 0) * mat2(0, 0, 1, 0) +
126  mat1(1, 0, 1) * mat2(0, 0, 0, 1) + mat1(1, 1, 1) * mat2(0, 0, 1, 1));
127  VERIFY_IS_APPROX(mat3(1, 0, 1), mat1(1, 0, 0) * mat2(0, 1, 0, 0) + mat1(1, 1, 0) * mat2(0, 1, 1, 0) +
128  mat1(1, 0, 1) * mat2(0, 1, 0, 1) + mat1(1, 1, 1) * mat2(0, 1, 1, 1));
129  VERIFY_IS_APPROX(mat3(1, 1, 0), mat1(1, 0, 0) * mat2(1, 0, 0, 0) + mat1(1, 1, 0) * mat2(1, 0, 1, 0) +
130  mat1(1, 0, 1) * mat2(1, 0, 0, 1) + mat1(1, 1, 1) * mat2(1, 0, 1, 1));
131  VERIFY_IS_APPROX(mat3(1, 1, 1), mat1(1, 0, 0) * mat2(1, 1, 0, 0) + mat1(1, 1, 0) * mat2(1, 1, 1, 0) +
132  mat1(1, 0, 1) * mat2(1, 1, 0, 1) + mat1(1, 1, 1) * mat2(1, 1, 1, 1));
133 
134  Tensor<float, 2, DataLayout> mat4(2, 2);
135  Tensor<float, 3, DataLayout> mat5(2, 2, 2);
136 
137  mat4.setRandom();
138  mat5.setRandom();
139 
141  mat6.setZero();
142  Eigen::array<DimPair, 2> dims2({{DimPair(0, 1), DimPair(1, 0)}});
143  typedef TensorEvaluator<decltype(mat4.contract(mat5, dims2)), DefaultDevice> Evaluator2;
144  Evaluator2 eval2(mat4.contract(mat5, dims2), DefaultDevice());
145  eval2.evalTo(mat6.data());
146  EIGEN_STATIC_ASSERT(Evaluator2::NumDims == 1ul, YOU_MADE_A_PROGRAMMING_MISTAKE);
147  VERIFY_IS_EQUAL(eval2.dimensions()[0], 2);
148 
149  VERIFY_IS_APPROX(mat6(0), mat4(0, 0) * mat5(0, 0, 0) + mat4(1, 0) * mat5(0, 1, 0) + mat4(0, 1) * mat5(1, 0, 0) +
150  mat4(1, 1) * mat5(1, 1, 0));
151  VERIFY_IS_APPROX(mat6(1), mat4(0, 0) * mat5(0, 0, 1) + mat4(1, 0) * mat5(0, 1, 1) + mat4(0, 1) * mat5(1, 0, 1) +
152  mat4(1, 1) * mat5(1, 1, 1));
153 }

References Eigen::Tensor< Scalar_, NumIndices_, Options_, IndexType_ >::data(), EIGEN_STATIC_ASSERT, eval(), mat1(), Eigen::TensorBase< Derived, AccessLevel >::setRandom(), Eigen::TensorBase< Derived, AccessLevel >::setZero(), VERIFY_IS_APPROX, and VERIFY_IS_EQUAL.

◆ test_out_of_order_contraction()

template<int DataLayout>
static void test_out_of_order_contraction ( )
static
260  {
262  Tensor<float, 3, DataLayout> mat2(2, 2, 2);
263 
264  mat1.setRandom();
265  mat2.setRandom();
266 
267  Tensor<float, 2, DataLayout> mat3(2, 2);
268 
269  Eigen::array<DimPair, 2> dims = {{DimPair(2, 0), DimPair(0, 2)}};
270  mat3 = mat1.contract(mat2, dims);
271 
272  VERIFY_IS_APPROX(mat3(0, 0), mat1(0, 0, 0) * mat2(0, 0, 0) + mat1(1, 0, 0) * mat2(0, 0, 1) +
273  mat1(0, 0, 1) * mat2(1, 0, 0) + mat1(1, 0, 1) * mat2(1, 0, 1));
274  VERIFY_IS_APPROX(mat3(1, 0), mat1(0, 1, 0) * mat2(0, 0, 0) + mat1(1, 1, 0) * mat2(0, 0, 1) +
275  mat1(0, 1, 1) * mat2(1, 0, 0) + mat1(1, 1, 1) * mat2(1, 0, 1));
276  VERIFY_IS_APPROX(mat3(0, 1), mat1(0, 0, 0) * mat2(0, 1, 0) + mat1(1, 0, 0) * mat2(0, 1, 1) +
277  mat1(0, 0, 1) * mat2(1, 1, 0) + mat1(1, 0, 1) * mat2(1, 1, 1));
278  VERIFY_IS_APPROX(mat3(1, 1), mat1(0, 1, 0) * mat2(0, 1, 0) + mat1(1, 1, 0) * mat2(0, 1, 1) +
279  mat1(0, 1, 1) * mat2(1, 1, 0) + mat1(1, 1, 1) * mat2(1, 1, 1));
280 
281  Eigen::array<DimPair, 2> dims2 = {{DimPair(0, 2), DimPair(2, 0)}};
282  mat3 = mat1.contract(mat2, dims2);
283 
284  VERIFY_IS_APPROX(mat3(0, 0), mat1(0, 0, 0) * mat2(0, 0, 0) + mat1(1, 0, 0) * mat2(0, 0, 1) +
285  mat1(0, 0, 1) * mat2(1, 0, 0) + mat1(1, 0, 1) * mat2(1, 0, 1));
286  VERIFY_IS_APPROX(mat3(1, 0), mat1(0, 1, 0) * mat2(0, 0, 0) + mat1(1, 1, 0) * mat2(0, 0, 1) +
287  mat1(0, 1, 1) * mat2(1, 0, 0) + mat1(1, 1, 1) * mat2(1, 0, 1));
288  VERIFY_IS_APPROX(mat3(0, 1), mat1(0, 0, 0) * mat2(0, 1, 0) + mat1(1, 0, 0) * mat2(0, 1, 1) +
289  mat1(0, 0, 1) * mat2(1, 1, 0) + mat1(1, 0, 1) * mat2(1, 1, 1));
290  VERIFY_IS_APPROX(mat3(1, 1), mat1(0, 1, 0) * mat2(0, 1, 0) + mat1(1, 1, 0) * mat2(0, 1, 1) +
291  mat1(0, 1, 1) * mat2(1, 1, 0) + mat1(1, 1, 1) * mat2(1, 1, 1));
292 }

References mat1(), Eigen::TensorBase< Derived, AccessLevel >::setRandom(), and VERIFY_IS_APPROX.

◆ test_scalar()

template<int DataLayout>
static void test_scalar ( )
static
81  {
84 
85  vec1.setRandom();
86  vec2.setRandom();
87 
88  Eigen::array<DimPair, 1> dims = {{DimPair(0, 0)}};
89  Tensor<float, 0, DataLayout> scalar = vec1.contract(vec2, dims);
90 
91  float expected = 0.0f;
92  for (int i = 0; i < 6; ++i) {
93  expected += vec1(i) * vec2(i);
94  }
95  VERIFY_IS_APPROX(scalar(), expected);
96 }
RowVectorXd vec1(3)

References i, vec1(), and VERIFY_IS_APPROX.

◆ test_small_blocking_factors()

template<int DataLayout>
static void test_small_blocking_factors ( )
static
410  {
411  Tensor<float, 4, DataLayout> t_left(30, 5, 3, 31);
412  Tensor<float, 5, DataLayout> t_right(3, 31, 7, 20, 1);
413  t_left.setRandom();
414  t_right.setRandom();
415 
416  // Add a little offset so that the results won't be close to zero.
417  t_left += t_left.constant(1.0f);
418  t_right += t_right.constant(1.0f);
419 
420  // Force the cache sizes, which results in smaller blocking factors.
421  Eigen::setCpuCacheSizes(896, 1920, 2944);
422 
423  // this contraction should be equivalent to a single matrix multiplication
424  Eigen::array<DimPair, 2> dims = {{DimPair(2, 0), DimPair(3, 1)}};
426  t_result = t_left.contract(t_right, dims);
427 
428  // compute result using a simple eigen matrix product
429  Map<Eigen::Matrix<float, Dynamic, Dynamic, DataLayout>> m_left(t_left.data(), 150, 93);
430  Map<Eigen::Matrix<float, Dynamic, Dynamic, DataLayout>> m_right(t_right.data(), 93, 140);
431  Eigen::Matrix<float, Dynamic, Dynamic, DataLayout> m_result = m_left * m_right;
432 
433  for (int i = 0; i < t_result.dimensions().TotalSize(); i++) {
434  VERIFY_IS_APPROX(t_result.data()[i], m_result.data()[i]);
435  }
436 }
constexpr EIGEN_DEVICE_FUNC const Scalar * data() const
Definition: PlainObjectBase.h:273
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const Dimensions & dimensions() const
Definition: Tensor.h:100
EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE Scalar * data()
Definition: Tensor.h:102
void setCpuCacheSizes(std::ptrdiff_t l1, std::ptrdiff_t l2, std::ptrdiff_t l3)
Definition: products/GeneralBlockPanelKernel.h:3146

References Eigen::Tensor< Scalar_, NumIndices_, Options_, IndexType_ >::data(), Eigen::PlainObjectBase< Derived >::data(), Eigen::Tensor< Scalar_, NumIndices_, Options_, IndexType_ >::dimensions(), i, Eigen::setCpuCacheSizes(), Eigen::TensorBase< Derived, AccessLevel >::setRandom(), and VERIFY_IS_APPROX.

◆ test_tensor_product()

template<int DataLayout>
static void test_tensor_product ( )
static
439  {
441  Tensor<float, 2, DataLayout> mat2(4, 1);
442  mat1.setRandom();
443  mat2.setRandom();
444 
446  Tensor<float, 4, DataLayout> result = mat1.contract(mat2, dims);
447 
448  VERIFY_IS_EQUAL(result.dimension(0), 2);
449  VERIFY_IS_EQUAL(result.dimension(1), 3);
450  VERIFY_IS_EQUAL(result.dimension(2), 4);
451  VERIFY_IS_EQUAL(result.dimension(3), 1);
452  for (int i = 0; i < result.dimension(0); ++i) {
453  for (int j = 0; j < result.dimension(1); ++j) {
454  for (int k = 0; k < result.dimension(2); ++k) {
455  for (int l = 0; l < result.dimension(3); ++l) {
456  VERIFY_IS_APPROX(result(i, j, k, l), mat1(i, j) * mat2(k, l));
457  }
458  }
459  }
460  }
461 }

References Eigen::Tensor< Scalar_, NumIndices_, Options_, IndexType_ >::dimension(), i, j, k, mat1(), Eigen::TensorBase< Derived, AccessLevel >::setRandom(), VERIFY_IS_APPROX, and VERIFY_IS_EQUAL.

◆ test_tensor_vector()

template<int DataLayout>
static void test_tensor_vector ( )
static
388  {
389  Tensor<float, 3, DataLayout> t_left(7, 13, 17);
390  Tensor<float, 2, DataLayout> t_right(1, 7);
391 
392  t_left.setRandom();
393  t_right.setRandom();
394 
395  typedef typename Tensor<float, 1, DataLayout>::DimensionPair DimensionPair;
396  Eigen::array<DimensionPair, 1> dim_pair01{{{0, 1}}};
397  Tensor<float, 3, DataLayout> t_result = t_left.contract(t_right, dim_pair01);
398 
400  MapXf m_left(t_left.data(), 7, 13 * 17);
401  MapXf m_right(t_right.data(), 1, 7);
402  Eigen::Matrix<float, Dynamic, Dynamic, DataLayout> m_result = m_left.transpose() * m_right.transpose();
403 
404  for (int i = 0; i < t_result.dimensions().TotalSize(); i++) {
405  VERIFY(internal::isApprox(t_result(i), m_result(i, 0), 1));
406  }
407 }

References Eigen::Tensor< Scalar_, NumIndices_, Options_, IndexType_ >::data(), Eigen::Tensor< Scalar_, NumIndices_, Options_, IndexType_ >::dimensions(), i, Eigen::internal::isApprox(), Eigen::TensorBase< Derived, AccessLevel >::setRandom(), and VERIFY.