• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra.
3 //
4 // Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
5 //
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/.
9 
10 #include "main.h"
11 
12 #include <Eigen/CXX11/Tensor>
13 
14 using Eigen::Tensor;
15 
16 template<typename>
test_simple_reshape()17 static void test_simple_reshape()
18 {
19   Tensor<float, 5> tensor1(2,3,1,7,1);
20   tensor1.setRandom();
21 
22   Tensor<float, 3> tensor2(2,3,7);
23   Tensor<float, 2> tensor3(6,7);
24   Tensor<float, 2> tensor4(2,21);
25 
26   Tensor<float, 3>::Dimensions dim1(2,3,7);
27   tensor2 = tensor1.reshape(dim1);
28   Tensor<float, 2>::Dimensions dim2(6,7);
29   tensor3 = tensor1.reshape(dim2);
30   Tensor<float, 2>::Dimensions dim3(2,21);
31   tensor4 = tensor1.reshape(dim1).reshape(dim3);
32 
33   for (int i = 0; i < 2; ++i) {
34     for (int j = 0; j < 3; ++j) {
35       for (int k = 0; k < 7; ++k) {
36         VERIFY_IS_EQUAL(tensor1(i,j,0,k,0), tensor2(i,j,k));
37         VERIFY_IS_EQUAL(tensor1(i,j,0,k,0), tensor3(i+2*j,k));
38         VERIFY_IS_EQUAL(tensor1(i,j,0,k,0), tensor4(i,j+3*k));
39       }
40     }
41   }
42 }
43 
44 template <typename>
test_static_reshape()45 static void test_static_reshape() {
46 #if defined(EIGEN_HAS_INDEX_LIST)
47   using Eigen::type2index;
48 
49   Tensor<float, 5> tensor(2, 3, 1, 7, 1);
50   tensor.setRandom();
51 
52   // New dimensions: [2, 3, 7]
53   Eigen::IndexList<type2index<2>, type2index<3>, type2index<7>> dim;
54   Tensor<float, 3> reshaped = tensor.reshape(static_cast<Eigen::DSizes<ptrdiff_t,3>>(dim));
55 
56   for (int i = 0; i < 2; ++i) {
57     for (int j = 0; j < 3; ++j) {
58       for (int k = 0; k < 7; ++k) {
59         VERIFY_IS_EQUAL(tensor(i, j, 0, k, 0), reshaped(i, j, k));
60       }
61     }
62   }
63 #endif
64 }
65 
66 template <typename>
test_reshape_in_expr()67 static void test_reshape_in_expr() {
68   MatrixXf m1(2,3*5*7*11);
69   MatrixXf m2(3*5*7*11,13);
70   m1.setRandom();
71   m2.setRandom();
72   MatrixXf m3 = m1 * m2;
73 
74   TensorMap<Tensor<float, 5>> tensor1(m1.data(), 2,3,5,7,11);
75   TensorMap<Tensor<float, 5>> tensor2(m2.data(), 3,5,7,11,13);
76   Tensor<float, 2>::Dimensions newDims1(2,3*5*7*11);
77   Tensor<float, 2>::Dimensions newDims2(3*5*7*11,13);
78   typedef Tensor<float, 1>::DimensionPair DimPair;
79   array<DimPair, 1> contract_along{{DimPair(1, 0)}};
80   Tensor<float, 2> tensor3(2,13);
81   tensor3 = tensor1.reshape(newDims1).contract(tensor2.reshape(newDims2), contract_along);
82 
83   Map<MatrixXf> res(tensor3.data(), 2, 13);
84   for (int i = 0; i < 2; ++i) {
85     for (int j = 0; j < 13; ++j) {
86       VERIFY_IS_APPROX(res(i,j), m3(i,j));
87     }
88   }
89 }
90 
91 template<typename>
test_reshape_as_lvalue()92 static void test_reshape_as_lvalue()
93 {
94   Tensor<float, 3> tensor(2,3,7);
95   tensor.setRandom();
96 
97   Tensor<float, 2> tensor2d(6,7);
98   Tensor<float, 3>::Dimensions dim(2,3,7);
99   tensor2d.reshape(dim) = tensor;
100 
101   float scratch[2*3*1*7*1];
102   TensorMap<Tensor<float, 5>> tensor5d(scratch, 2,3,1,7,1);
103   tensor5d.reshape(dim).device(Eigen::DefaultDevice()) = tensor;
104 
105   for (int i = 0; i < 2; ++i) {
106     for (int j = 0; j < 3; ++j) {
107       for (int k = 0; k < 7; ++k) {
108         VERIFY_IS_EQUAL(tensor2d(i+2*j,k), tensor(i,j,k));
109         VERIFY_IS_EQUAL(tensor5d(i,j,0,k,0), tensor(i,j,k));
110       }
111     }
112   }
113 }
114 
115 template<typename T, int DataLayout>
test_simple_slice()116 static void test_simple_slice()
117 {
118   Tensor<T, 5, DataLayout> tensor(2,3,5,7,11);
119   tensor.setRandom();
120 
121   Tensor<T, 5, DataLayout> slice1(1,1,1,1,1);
122   Eigen::DSizes<ptrdiff_t, 5> indices(1,2,3,4,5);
123   Eigen::DSizes<ptrdiff_t, 5> sizes(1,1,1,1,1);
124   slice1 = tensor.slice(indices, sizes);
125   VERIFY_IS_EQUAL(slice1(0,0,0,0,0), tensor(1,2,3,4,5));
126 
127   Tensor<T, 5, DataLayout> slice2(1,1,2,2,3);
128   Eigen::DSizes<ptrdiff_t, 5> indices2(1,1,3,4,5);
129   Eigen::DSizes<ptrdiff_t, 5> sizes2(1,1,2,2,3);
130   slice2 = tensor.slice(indices2, sizes2);
131   for (int i = 0; i < 2; ++i) {
132     for (int j = 0; j < 2; ++j) {
133       for (int k = 0; k < 3; ++k) {
134         VERIFY_IS_EQUAL(slice2(0,0,i,j,k), tensor(1,1,3+i,4+j,5+k));
135       }
136     }
137   }
138 }
139 
140 template<typename T>
test_const_slice()141 static void test_const_slice()
142 {
143   const T b[1] = {42};
144   TensorMap<Tensor<const T, 1> > m(b, 1);
145   DSizes<DenseIndex, 1> offsets;
146   offsets[0] = 0;
147   TensorRef<Tensor<const T, 1> > slice_ref(m.slice(offsets, m.dimensions()));
148   VERIFY_IS_EQUAL(slice_ref(0), 42);
149 }
150 
151 template<typename T, int DataLayout>
test_slice_in_expr()152 static void test_slice_in_expr() {
153   typedef Matrix<T, Dynamic, Dynamic, DataLayout> Mtx;
154   Mtx m1(7,7);
155   Mtx m2(3,3);
156   m1.setRandom();
157   m2.setRandom();
158 
159   Mtx m3 = m1.block(1, 2, 3, 3) * m2.block(0, 2, 3, 1);
160 
161   TensorMap<Tensor<T, 2, DataLayout>> tensor1(m1.data(), 7, 7);
162   TensorMap<Tensor<T, 2, DataLayout>> tensor2(m2.data(), 3, 3);
163   Tensor<T, 2, DataLayout> tensor3(3,1);
164   typedef typename Tensor<T, 1>::DimensionPair DimPair;
165   array<DimPair, 1> contract_along{{DimPair(1, 0)}};
166 
167   Eigen::DSizes<ptrdiff_t, 2> indices1(1,2);
168   Eigen::DSizes<ptrdiff_t, 2> sizes1(3,3);
169   Eigen::DSizes<ptrdiff_t, 2> indices2(0,2);
170   Eigen::DSizes<ptrdiff_t, 2> sizes2(3,1);
171   tensor3 = tensor1.slice(indices1, sizes1).contract(tensor2.slice(indices2, sizes2), contract_along);
172 
173   Map<Mtx> res(tensor3.data(), 3, 1);
174   for (int i = 0; i < 3; ++i) {
175     for (int j = 0; j < 1; ++j) {
176       VERIFY_IS_APPROX(res(i,j), m3(i,j));
177     }
178   }
179 
180   // Take an arbitrary slice of an arbitrarily sized tensor.
181   TensorMap<Tensor<const T, 2, DataLayout>> tensor4(m1.data(), 7, 7);
182   Tensor<T, 1, DataLayout> tensor6 = tensor4.reshape(DSizes<ptrdiff_t, 1>(7*7)).exp().slice(DSizes<ptrdiff_t, 1>(0), DSizes<ptrdiff_t, 1>(35));
183   for (int i = 0; i < 35; ++i) {
184     VERIFY_IS_APPROX(tensor6(i), expf(tensor4.data()[i]));
185   }
186 }
187 
188 template<typename T, int DataLayout>
test_slice_as_lvalue()189 static void test_slice_as_lvalue()
190 {
191   Tensor<T, 3, DataLayout> tensor1(2,2,7);
192   tensor1.setRandom();
193   Tensor<T, 3, DataLayout> tensor2(2,2,7);
194   tensor2.setRandom();
195   Tensor<T, 3, DataLayout> tensor3(4,3,5);
196   tensor3.setRandom();
197   Tensor<T, 3, DataLayout> tensor4(4,3,2);
198   tensor4.setRandom();
199   Tensor<T, 3, DataLayout> tensor5(10,13,12);
200   tensor5.setRandom();
201 
202   Tensor<T, 3, DataLayout> result(4,5,7);
203   Eigen::DSizes<ptrdiff_t, 3> sizes12(2,2,7);
204   Eigen::DSizes<ptrdiff_t, 3> first_slice(0,0,0);
205   result.slice(first_slice, sizes12) = tensor1;
206   Eigen::DSizes<ptrdiff_t, 3> second_slice(2,0,0);
207   result.slice(second_slice, sizes12).device(Eigen::DefaultDevice()) = tensor2;
208 
209   Eigen::DSizes<ptrdiff_t, 3> sizes3(4,3,5);
210   Eigen::DSizes<ptrdiff_t, 3> third_slice(0,2,0);
211   result.slice(third_slice, sizes3) = tensor3;
212 
213   Eigen::DSizes<ptrdiff_t, 3> sizes4(4,3,2);
214   Eigen::DSizes<ptrdiff_t, 3> fourth_slice(0,2,5);
215   result.slice(fourth_slice, sizes4) = tensor4;
216 
217   for (int j = 0; j < 2; ++j) {
218     for (int k = 0; k < 7; ++k) {
219       for (int i = 0; i < 2; ++i) {
220         VERIFY_IS_EQUAL(result(i,j,k), tensor1(i,j,k));
221         VERIFY_IS_EQUAL(result(i+2,j,k), tensor2(i,j,k));
222       }
223     }
224   }
225   for (int i = 0; i < 4; ++i) {
226     for (int j = 2; j < 5; ++j) {
227       for (int k = 0; k < 5; ++k) {
228         VERIFY_IS_EQUAL(result(i,j,k), tensor3(i,j-2,k));
229       }
230       for (int k = 5; k < 7; ++k) {
231         VERIFY_IS_EQUAL(result(i,j,k), tensor4(i,j-2,k-5));
232       }
233     }
234   }
235 
236   Eigen::DSizes<ptrdiff_t, 3> sizes5(4,5,7);
237   Eigen::DSizes<ptrdiff_t, 3> fifth_slice(0,0,0);
238   result.slice(fifth_slice, sizes5) = tensor5.slice(fifth_slice, sizes5);
239   for (int i = 0; i < 4; ++i) {
240     for (int j = 2; j < 5; ++j) {
241       for (int k = 0; k < 7; ++k) {
242         VERIFY_IS_EQUAL(result(i,j,k), tensor5(i,j,k));
243       }
244     }
245   }
246 }
247 
248 template<typename T, int DataLayout>
test_slice_raw_data()249 static void test_slice_raw_data()
250 {
251   Tensor<T, 4, DataLayout> tensor(3,5,7,11);
252   tensor.setRandom();
253 
254   Eigen::DSizes<ptrdiff_t, 4> offsets(1,2,3,4);
255   Eigen::DSizes<ptrdiff_t, 4> extents(1,1,1,1);
256   typedef TensorEvaluator<decltype(tensor.slice(offsets, extents)), DefaultDevice> SliceEvaluator;
257   auto slice1 = SliceEvaluator(tensor.slice(offsets, extents), DefaultDevice());
258   VERIFY_IS_EQUAL(slice1.dimensions().TotalSize(), 1);
259   VERIFY_IS_EQUAL(slice1.data()[0], tensor(1,2,3,4));
260 
261   if (DataLayout == ColMajor) {
262     extents = Eigen::DSizes<ptrdiff_t, 4>(2,1,1,1);
263     auto slice2 = SliceEvaluator(tensor.slice(offsets, extents), DefaultDevice());
264     VERIFY_IS_EQUAL(slice2.dimensions().TotalSize(), 2);
265     VERIFY_IS_EQUAL(slice2.data()[0], tensor(1,2,3,4));
266     VERIFY_IS_EQUAL(slice2.data()[1], tensor(2,2,3,4));
267   } else {
268     extents = Eigen::DSizes<ptrdiff_t, 4>(1,1,1,2);
269     auto slice2 = SliceEvaluator(tensor.slice(offsets, extents), DefaultDevice());
270     VERIFY_IS_EQUAL(slice2.dimensions().TotalSize(), 2);
271     VERIFY_IS_EQUAL(slice2.data()[0], tensor(1,2,3,4));
272     VERIFY_IS_EQUAL(slice2.data()[1], tensor(1,2,3,5));
273   }
274 
275   extents = Eigen::DSizes<ptrdiff_t, 4>(1,2,1,1);
276   auto slice3 = SliceEvaluator(tensor.slice(offsets, extents), DefaultDevice());
277   VERIFY_IS_EQUAL(slice3.dimensions().TotalSize(), 2);
278   VERIFY_IS_EQUAL(slice3.data(), static_cast<T*>(0));
279 
280   if (DataLayout == ColMajor) {
281     offsets = Eigen::DSizes<ptrdiff_t, 4>(0,2,3,4);
282     extents = Eigen::DSizes<ptrdiff_t, 4>(3,2,1,1);
283     auto slice4 = SliceEvaluator(tensor.slice(offsets, extents), DefaultDevice());
284     VERIFY_IS_EQUAL(slice4.dimensions().TotalSize(), 6);
285     for (int i = 0; i < 3; ++i) {
286       for (int j = 0; j < 2; ++j) {
287         VERIFY_IS_EQUAL(slice4.data()[i+3*j], tensor(i,2+j,3,4));
288       }
289     }
290   } else {
291     offsets = Eigen::DSizes<ptrdiff_t, 4>(1,2,3,0);
292     extents = Eigen::DSizes<ptrdiff_t, 4>(1,1,2,11);
293     auto slice4 = SliceEvaluator(tensor.slice(offsets, extents), DefaultDevice());
294     VERIFY_IS_EQUAL(slice4.dimensions().TotalSize(), 22);
295     for (int l = 0; l < 11; ++l) {
296       for (int k = 0; k < 2; ++k) {
297         VERIFY_IS_EQUAL(slice4.data()[l+11*k], tensor(1,2,3+k,l));
298       }
299     }
300   }
301 
302   if (DataLayout == ColMajor) {
303     offsets = Eigen::DSizes<ptrdiff_t, 4>(0,0,0,4);
304     extents = Eigen::DSizes<ptrdiff_t, 4>(3,5,7,2);
305     auto slice5 = SliceEvaluator(tensor.slice(offsets, extents), DefaultDevice());
306     VERIFY_IS_EQUAL(slice5.dimensions().TotalSize(), 210);
307     for (int i = 0; i < 3; ++i) {
308       for (int j = 0; j < 5; ++j) {
309         for (int k = 0; k < 7; ++k) {
310           for (int l = 0; l < 2; ++l) {
311             int slice_index = i + 3 * (j + 5 * (k + 7 * l));
312             VERIFY_IS_EQUAL(slice5.data()[slice_index], tensor(i,j,k,l+4));
313           }
314         }
315       }
316     }
317   } else {
318     offsets = Eigen::DSizes<ptrdiff_t, 4>(1,0,0,0);
319     extents = Eigen::DSizes<ptrdiff_t, 4>(2,5,7,11);
320     auto slice5 = SliceEvaluator(tensor.slice(offsets, extents), DefaultDevice());
321     VERIFY_IS_EQUAL(slice5.dimensions().TotalSize(), 770);
322     for (int l = 0; l < 11; ++l) {
323       for (int k = 0; k < 7; ++k) {
324         for (int j = 0; j < 5; ++j) {
325           for (int i = 0; i < 2; ++i) {
326             int slice_index = l + 11 * (k + 7 * (j + 5 * i));
327             VERIFY_IS_EQUAL(slice5.data()[slice_index], tensor(i+1,j,k,l));
328           }
329         }
330       }
331     }
332 
333   }
334 
335   offsets = Eigen::DSizes<ptrdiff_t, 4>(0,0,0,0);
336   extents = Eigen::DSizes<ptrdiff_t, 4>(3,5,7,11);
337   auto slice6 = SliceEvaluator(tensor.slice(offsets, extents), DefaultDevice());
338   VERIFY_IS_EQUAL(slice6.dimensions().TotalSize(), 3*5*7*11);
339   VERIFY_IS_EQUAL(slice6.data(), tensor.data());
340 }
341 
342 
343 template<typename T, int DataLayout>
test_strided_slice()344 static void test_strided_slice()
345 {
346   typedef Tensor<T, 5, DataLayout> Tensor5f;
347   typedef Eigen::DSizes<Eigen::DenseIndex, 5> Index5;
348   typedef Tensor<T, 2, DataLayout> Tensor2f;
349   typedef Eigen::DSizes<Eigen::DenseIndex, 2> Index2;
350   Tensor<T, 5, DataLayout> tensor(2,3,5,7,11);
351   Tensor<T, 2, DataLayout> tensor2(7,11);
352   tensor.setRandom();
353   tensor2.setRandom();
354 
355   if (true) {
356     Tensor2f slice(2,3);
357     Index2 strides(-2,-1);
358     Index2 indicesStart(5,7);
359     Index2 indicesStop(0,4);
360     slice = tensor2.stridedSlice(indicesStart, indicesStop, strides);
361     for (int j = 0; j < 2; ++j) {
362       for (int k = 0; k < 3; ++k) {
363         VERIFY_IS_EQUAL(slice(j,k), tensor2(5-2*j,7-k));
364       }
365     }
366   }
367 
368   if(true) {
369     Tensor2f slice(0,1);
370     Index2 strides(1,1);
371     Index2 indicesStart(5,4);
372     Index2 indicesStop(5,5);
373     slice = tensor2.stridedSlice(indicesStart, indicesStop, strides);
374   }
375 
376   if(true) { // test clamped degenerate interavls
377     Tensor2f slice(7,11);
378     Index2 strides(1,-1);
379     Index2 indicesStart(-3,20); // should become 0,10
380     Index2 indicesStop(20,-11); // should become 11, -1
381     slice = tensor2.stridedSlice(indicesStart, indicesStop, strides);
382     for (int j = 0; j < 7; ++j) {
383       for (int k = 0; k < 11; ++k) {
384         VERIFY_IS_EQUAL(slice(j,k), tensor2(j,10-k));
385       }
386     }
387   }
388 
389   if(true) {
390     Tensor5f slice1(1,1,1,1,1);
391     Eigen::DSizes<Eigen::DenseIndex, 5> indicesStart(1, 2, 3, 4, 5);
392     Eigen::DSizes<Eigen::DenseIndex, 5> indicesStop(2, 3, 4, 5, 6);
393     Eigen::DSizes<Eigen::DenseIndex, 5> strides(1, 1, 1, 1, 1);
394     slice1 = tensor.stridedSlice(indicesStart, indicesStop, strides);
395     VERIFY_IS_EQUAL(slice1(0,0,0,0,0), tensor(1,2,3,4,5));
396   }
397 
398   if(true) {
399     Tensor5f slice(1,1,2,2,3);
400     Index5 start(1, 1, 3, 4, 5);
401     Index5 stop(2, 2, 5, 6, 8);
402     Index5 strides(1, 1, 1, 1, 1);
403     slice = tensor.stridedSlice(start, stop, strides);
404     for (int i = 0; i < 2; ++i) {
405       for (int j = 0; j < 2; ++j) {
406         for (int k = 0; k < 3; ++k) {
407           VERIFY_IS_EQUAL(slice(0,0,i,j,k), tensor(1,1,3+i,4+j,5+k));
408         }
409       }
410     }
411   }
412 
413   if(true) {
414     Tensor5f slice(1,1,2,2,3);
415     Index5 strides3(1, 1, -2, 1, -1);
416     Index5 indices3Start(1, 1, 4, 4, 7);
417     Index5 indices3Stop(2, 2, 0, 6, 4);
418     slice = tensor.stridedSlice(indices3Start, indices3Stop, strides3);
419     for (int i = 0; i < 2; ++i) {
420       for (int j = 0; j < 2; ++j) {
421         for (int k = 0; k < 3; ++k) {
422           VERIFY_IS_EQUAL(slice(0,0,i,j,k), tensor(1,1,4-2*i,4+j,7-k));
423         }
424       }
425     }
426   }
427 
428   if(false) { // tests degenerate interval
429     Tensor5f slice(1,1,2,2,3);
430     Index5 strides3(1, 1, 2, 1, 1);
431     Index5 indices3Start(1, 1, 4, 4, 7);
432     Index5 indices3Stop(2, 2, 0, 6, 4);
433     slice = tensor.stridedSlice(indices3Start, indices3Stop, strides3);
434   }
435 }
436 
437 template<typename T, int DataLayout>
test_strided_slice_write()438 static void test_strided_slice_write()
439 {
440   typedef Tensor<T, 2, DataLayout> Tensor2f;
441   typedef Eigen::DSizes<Eigen::DenseIndex, 2> Index2;
442 
443   Tensor<T, 2, DataLayout> tensor(7,11),tensor2(7,11);
444   tensor.setRandom();
445   tensor2=tensor;
446   Tensor2f slice(2,3);
447 
448   slice.setRandom();
449 
450   Index2 strides(1,1);
451   Index2 indicesStart(3,4);
452   Index2 indicesStop(5,7);
453   Index2 lengths(2,3);
454 
455   tensor.slice(indicesStart,lengths)=slice;
456   tensor2.stridedSlice(indicesStart,indicesStop,strides)=slice;
457 
458   for(int i=0;i<7;i++) for(int j=0;j<11;j++){
459     VERIFY_IS_EQUAL(tensor(i,j), tensor2(i,j));
460   }
461 }
462 
463 template<typename T, int DataLayout>
test_composition()464 static void test_composition()
465 {
466   Eigen::Tensor<T, 2, DataLayout> matrix(7, 11);
467   matrix.setRandom();
468 
469   const DSizes<ptrdiff_t, 3> newDims(1, 1, 11);
470   Eigen::Tensor<T, 3, DataLayout> tensor =
471       matrix.slice(DSizes<ptrdiff_t, 2>(2, 0), DSizes<ptrdiff_t, 2>(1, 11)).reshape(newDims);
472 
473   VERIFY_IS_EQUAL(tensor.dimensions().TotalSize(), 11);
474   VERIFY_IS_EQUAL(tensor.dimension(0), 1);
475   VERIFY_IS_EQUAL(tensor.dimension(1), 1);
476   VERIFY_IS_EQUAL(tensor.dimension(2), 11);
477   for (int i = 0; i < 11; ++i) {
478     VERIFY_IS_EQUAL(tensor(0,0,i), matrix(2,i));
479   }
480 }
481 
482 template<typename T, int DataLayout>
test_empty_slice()483 static void test_empty_slice()
484 {
485   Tensor<T, 3, DataLayout> tensor(2,3,5);
486   tensor.setRandom();
487   Tensor<T, 3, DataLayout> copy = tensor;
488 
489   // empty size in first dimension
490   Eigen::DSizes<ptrdiff_t, 3> indices1(1,2,3);
491   Eigen::DSizes<ptrdiff_t, 3> sizes1(0,1,2);
492   Tensor<T, 3, DataLayout> slice1(0,1,2);
493   slice1.setRandom();
494   tensor.slice(indices1, sizes1) = slice1;
495 
496   // empty size in second dimension
497   Eigen::DSizes<ptrdiff_t, 3> indices2(1,2,3);
498   Eigen::DSizes<ptrdiff_t, 3> sizes2(1,0,2);
499   Tensor<T, 3, DataLayout> slice2(1,0,2);
500   slice2.setRandom();
501   tensor.slice(indices2, sizes2) = slice2;
502 
503   // empty size in third dimension
504   Eigen::DSizes<ptrdiff_t, 3> indices3(1,2,3);
505   Eigen::DSizes<ptrdiff_t, 3> sizes3(1,1,0);
506   Tensor<T, 3, DataLayout> slice3(1,1,0);
507   slice3.setRandom();
508   tensor.slice(indices3, sizes3) = slice3;
509 
510   // empty size in first and second dimension
511   Eigen::DSizes<ptrdiff_t, 3> indices4(1,2,3);
512   Eigen::DSizes<ptrdiff_t, 3> sizes4(0,0,2);
513   Tensor<T, 3, DataLayout> slice4(0,0,2);
514   slice4.setRandom();
515   tensor.slice(indices4, sizes4) = slice4;
516 
517   // empty size in second and third dimension
518   Eigen::DSizes<ptrdiff_t, 3> indices5(1,2,3);
519   Eigen::DSizes<ptrdiff_t, 3> sizes5(1,0,0);
520   Tensor<T, 3, DataLayout> slice5(1,0,0);
521   slice5.setRandom();
522   tensor.slice(indices5, sizes5) = slice5;
523 
524   // empty size in all dimensions
525   Eigen::DSizes<ptrdiff_t, 3> indices6(1,2,3);
526   Eigen::DSizes<ptrdiff_t, 3> sizes6(0,0,0);
527   Tensor<T, 3, DataLayout> slice6(0,0,0);
528   slice6.setRandom();
529   tensor.slice(indices6, sizes6) = slice6;
530 
531   // none of these operations should change the tensor's components
532   // because all of the rvalue slices have at least one zero dimension
533   for (int i = 0; i < 2; ++i) {
534     for (int j = 0; j < 3; ++j) {
535       for (int k = 0; k < 5; ++k) {
536           VERIFY_IS_EQUAL(tensor(i,j,k), copy(i,j,k));
537       }
538     }
539   }
540 }
541 
542 #define CALL_SUBTEST_PART(PART) \
543   CALL_SUBTEST_##PART
544 
545 #define CALL_SUBTESTS_TYPES_LAYOUTS(PART, NAME)       \
546   CALL_SUBTEST_PART(PART)((NAME<float, ColMajor>())); \
547   CALL_SUBTEST_PART(PART)((NAME<float, RowMajor>())); \
548   CALL_SUBTEST_PART(PART)((NAME<bool, ColMajor>())); \
549   CALL_SUBTEST_PART(PART)((NAME<bool, RowMajor>()))
550 
EIGEN_DECLARE_TEST(cxx11_tensor_morphing)551 EIGEN_DECLARE_TEST(cxx11_tensor_morphing)
552 {
553   CALL_SUBTEST_1(test_simple_reshape<void>());
554   CALL_SUBTEST_1(test_static_reshape<void>());
555   CALL_SUBTEST_1(test_reshape_as_lvalue<void>());
556   CALL_SUBTEST_1(test_reshape_in_expr<void>());
557   CALL_SUBTEST_1(test_const_slice<float>());
558 
559   CALL_SUBTESTS_TYPES_LAYOUTS(2, test_simple_slice);
560   CALL_SUBTESTS_TYPES_LAYOUTS(3, test_slice_as_lvalue);
561   CALL_SUBTESTS_TYPES_LAYOUTS(4, test_slice_raw_data);
562   CALL_SUBTESTS_TYPES_LAYOUTS(5, test_strided_slice_write);
563   CALL_SUBTESTS_TYPES_LAYOUTS(6, test_strided_slice);
564   CALL_SUBTESTS_TYPES_LAYOUTS(7, test_composition);
565 }
566