cart-elc

Source code for CART-ELC
git clone git://git.laack.co/cart-elc.git
Log | Files | Refs | README | LICENSE

cxx11_tensor_morphing.cpp (18215B)


      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>
     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>
     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>
     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>
     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>
    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>
    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>
    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>
    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>
    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>
    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>
    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>
    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>
    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 
    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 }