Home | History | Annotate | Download | only in test
      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 (at) 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 void test_simple_patch()
     17 {
     18   Tensor<float, 4> tensor(2,3,5,7);
     19   tensor.setRandom();
     20   Tensor<float, 4, RowMajor> tensor_row_major = tensor.swap_layout();
     21   VERIFY_IS_EQUAL(tensor.dimension(0), tensor_row_major.dimension(3));
     22   VERIFY_IS_EQUAL(tensor.dimension(1), tensor_row_major.dimension(2));
     23   VERIFY_IS_EQUAL(tensor.dimension(2), tensor_row_major.dimension(1));
     24   VERIFY_IS_EQUAL(tensor.dimension(3), tensor_row_major.dimension(0));
     25 
     26   // Single pixel patch: ColMajor
     27   Tensor<float, 5> single_pixel_patch;
     28   single_pixel_patch = tensor.extract_image_patches(1, 1);
     29   VERIFY_IS_EQUAL(single_pixel_patch.dimension(0), 2);
     30   VERIFY_IS_EQUAL(single_pixel_patch.dimension(1), 1);
     31   VERIFY_IS_EQUAL(single_pixel_patch.dimension(2), 1);
     32   VERIFY_IS_EQUAL(single_pixel_patch.dimension(3), 3*5);
     33   VERIFY_IS_EQUAL(single_pixel_patch.dimension(4), 7);
     34 
     35   // Single pixel patch: RowMajor
     36   Tensor<float, 5, RowMajor> single_pixel_patch_row_major;
     37   single_pixel_patch_row_major = tensor_row_major.extract_image_patches(1, 1);
     38   VERIFY_IS_EQUAL(single_pixel_patch_row_major.dimension(0), 7);
     39   VERIFY_IS_EQUAL(single_pixel_patch_row_major.dimension(1), 3*5);
     40   VERIFY_IS_EQUAL(single_pixel_patch_row_major.dimension(2), 1);
     41   VERIFY_IS_EQUAL(single_pixel_patch_row_major.dimension(3), 1);
     42   VERIFY_IS_EQUAL(single_pixel_patch_row_major.dimension(4), 2);
     43 
     44   for (int i = 0; i < tensor.size(); ++i) {
     45     // ColMajor
     46     if (tensor.data()[i] != single_pixel_patch.data()[i]) {
     47       std::cout << "Mismatch detected at index " << i << " : "
     48            << tensor.data()[i] << " vs " << single_pixel_patch.data()[i]
     49            << std::endl;
     50     }
     51     VERIFY_IS_EQUAL(single_pixel_patch.data()[i], tensor.data()[i]);
     52     // RowMajor
     53     if (tensor_row_major.data()[i] != single_pixel_patch_row_major.data()[i]) {
     54       std::cout << "Mismatch detected at index " << i << " : "
     55            << tensor.data()[i] << " vs "
     56            << single_pixel_patch_row_major.data()[i] << std::endl;
     57     }
     58     VERIFY_IS_EQUAL(single_pixel_patch_row_major.data()[i],
     59                     tensor_row_major.data()[i]);
     60     VERIFY_IS_EQUAL(tensor.data()[i], tensor_row_major.data()[i]);
     61     VERIFY_IS_EQUAL(single_pixel_patch.data()[i],
     62                     single_pixel_patch_row_major.data()[i]);
     63   }
     64 
     65   // Entire image patch: ColMajor
     66   Tensor<float, 5> entire_image_patch;
     67   entire_image_patch = tensor.extract_image_patches(3, 5);
     68   VERIFY_IS_EQUAL(entire_image_patch.dimension(0), 2);
     69   VERIFY_IS_EQUAL(entire_image_patch.dimension(1), 3);
     70   VERIFY_IS_EQUAL(entire_image_patch.dimension(2), 5);
     71   VERIFY_IS_EQUAL(entire_image_patch.dimension(3), 3*5);
     72   VERIFY_IS_EQUAL(entire_image_patch.dimension(4), 7);
     73 
     74   // Entire image patch: RowMajor
     75   Tensor<float, 5, RowMajor> entire_image_patch_row_major;
     76   entire_image_patch_row_major = tensor_row_major.extract_image_patches(3, 5);
     77   VERIFY_IS_EQUAL(entire_image_patch_row_major.dimension(0), 7);
     78   VERIFY_IS_EQUAL(entire_image_patch_row_major.dimension(1), 3*5);
     79   VERIFY_IS_EQUAL(entire_image_patch_row_major.dimension(2), 5);
     80   VERIFY_IS_EQUAL(entire_image_patch_row_major.dimension(3), 3);
     81   VERIFY_IS_EQUAL(entire_image_patch_row_major.dimension(4), 2);
     82 
     83   for (int i = 0; i < 3; ++i) {
     84     for (int j = 0; j < 5; ++j) {
     85       int patchId = i+3*j;
     86       for (int r = 0; r < 3; ++r) {
     87         for (int c = 0; c < 5; ++c) {
     88           for (int d = 0; d < 2; ++d) {
     89             for (int b = 0; b < 7; ++b) {
     90               float expected = 0.0f;
     91               float expected_row_major = 0.0f;
     92               if (r-1+i >= 0 && c-2+j >= 0 && r-1+i < 3 && c-2+j < 5) {
     93                 expected = tensor(d, r-1+i, c-2+j, b);
     94                 expected_row_major = tensor_row_major(b, c-2+j, r-1+i, d);
     95               }
     96               // ColMajor
     97               if (entire_image_patch(d, r, c, patchId, b) != expected) {
     98                 std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << " b=" << b << std::endl;
     99               }
    100               VERIFY_IS_EQUAL(entire_image_patch(d, r, c, patchId, b), expected);
    101               // RowMajor
    102               if (entire_image_patch_row_major(b, patchId, c, r, d) !=
    103                   expected_row_major) {
    104                 std::cout << "Mismatch detected at index i=" << i << " j=" << j
    105                      << " r=" << r << " c=" << c << " d=" << d << " b=" << b
    106                      << std::endl;
    107               }
    108               VERIFY_IS_EQUAL(entire_image_patch_row_major(b, patchId, c, r, d),
    109                               expected_row_major);
    110               // Check that ColMajor and RowMajor agree.
    111               VERIFY_IS_EQUAL(expected, expected_row_major);
    112             }
    113           }
    114         }
    115       }
    116     }
    117   }
    118 
    119   // 2D patch: ColMajor
    120   Tensor<float, 5> twod_patch;
    121   twod_patch = tensor.extract_image_patches(2, 2);
    122   VERIFY_IS_EQUAL(twod_patch.dimension(0), 2);
    123   VERIFY_IS_EQUAL(twod_patch.dimension(1), 2);
    124   VERIFY_IS_EQUAL(twod_patch.dimension(2), 2);
    125   VERIFY_IS_EQUAL(twod_patch.dimension(3), 3*5);
    126   VERIFY_IS_EQUAL(twod_patch.dimension(4), 7);
    127 
    128   // 2D patch: RowMajor
    129   Tensor<float, 5, RowMajor> twod_patch_row_major;
    130   twod_patch_row_major = tensor_row_major.extract_image_patches(2, 2);
    131   VERIFY_IS_EQUAL(twod_patch_row_major.dimension(0), 7);
    132   VERIFY_IS_EQUAL(twod_patch_row_major.dimension(1), 3*5);
    133   VERIFY_IS_EQUAL(twod_patch_row_major.dimension(2), 2);
    134   VERIFY_IS_EQUAL(twod_patch_row_major.dimension(3), 2);
    135   VERIFY_IS_EQUAL(twod_patch_row_major.dimension(4), 2);
    136 
    137 
    138   // Based on the calculation described in TensorTraits.h, padding happens to be 0.
    139   int row_padding = 0;
    140   int col_padding = 0;
    141   int stride = 1;
    142 
    143   for (int i = 0; i < 3; ++i) {
    144     for (int j = 0; j < 5; ++j) {
    145       int patchId = i+3*j;
    146       for (int r = 0; r < 2; ++r) {
    147         for (int c = 0; c < 2; ++c) {
    148           for (int d = 0; d < 2; ++d) {
    149             for (int b = 0; b < 7; ++b) {
    150               float expected = 0.0f;
    151               float expected_row_major = 0.0f;
    152               int row_offset = r*stride + i - row_padding;
    153               int col_offset = c*stride + j - col_padding;
    154               // ColMajor
    155               if (row_offset >= 0 && col_offset >= 0 && row_offset < tensor.dimension(1) && col_offset < tensor.dimension(2)) {
    156                 expected = tensor(d, row_offset, col_offset, b);
    157               }
    158               if (twod_patch(d, r, c, patchId, b) != expected) {
    159                 std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << " b=" << b << std::endl;
    160               }
    161               VERIFY_IS_EQUAL(twod_patch(d, r, c, patchId, b), expected);
    162 
    163               // RowMajor
    164               if (row_offset >= 0 && col_offset >= 0 && row_offset < tensor_row_major.dimension(2) && col_offset < tensor_row_major.dimension(1)) {
    165                 expected_row_major = tensor_row_major(b, col_offset, row_offset, d);
    166 
    167               }
    168               if (twod_patch_row_major(b, patchId, c, r, d) != expected_row_major) {
    169                 std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << " b=" << b << std::endl;
    170               }
    171               VERIFY_IS_EQUAL(twod_patch_row_major(b, patchId, c, r, d), expected_row_major);
    172               // Check that ColMajor and RowMajor agree.
    173               VERIFY_IS_EQUAL(expected, expected_row_major);
    174             }
    175           }
    176         }
    177       }
    178     }
    179   }
    180 }
    181 
    182 // Verifies VALID padding (no padding) with incrementing values.
    183 void test_patch_padding_valid()
    184 {
    185   int input_depth = 3;
    186   int input_rows = 3;
    187   int input_cols = 3;
    188   int input_batches = 1;
    189   int ksize = 2;  // Corresponds to the Rows and Cols for tensor.extract_image_patches<>.
    190   int stride = 2;  // Only same stride is supported.
    191   Tensor<float, 4> tensor(input_depth, input_rows, input_cols, input_batches);
    192   // Initializes tensor with incrementing numbers.
    193   for (int i = 0; i < tensor.size(); ++i) {
    194     tensor.data()[i] = i + 1;
    195   }
    196   // ColMajor
    197   Tensor<float, 5> result = tensor.extract_image_patches(ksize, ksize, stride, stride, 1, 1, PADDING_VALID);
    198 
    199   VERIFY_IS_EQUAL(result.dimension(0), input_depth);  // depth
    200   VERIFY_IS_EQUAL(result.dimension(1), ksize);  // kernel rows
    201   VERIFY_IS_EQUAL(result.dimension(2), ksize);  // kernel cols
    202   VERIFY_IS_EQUAL(result.dimension(3), 1);  // number of patches
    203   VERIFY_IS_EQUAL(result.dimension(4), input_batches);  // number of batches
    204 
    205   // RowMajor
    206   Tensor<float, 4, RowMajor> tensor_row_major = tensor.swap_layout();
    207   VERIFY_IS_EQUAL(tensor.dimension(0), tensor_row_major.dimension(3));
    208   VERIFY_IS_EQUAL(tensor.dimension(1), tensor_row_major.dimension(2));
    209   VERIFY_IS_EQUAL(tensor.dimension(2), tensor_row_major.dimension(1));
    210   VERIFY_IS_EQUAL(tensor.dimension(3), tensor_row_major.dimension(0));
    211 
    212   Tensor<float, 5, RowMajor> result_row_major = tensor_row_major.extract_image_patches(ksize, ksize, stride, stride, 1, 1, PADDING_VALID);
    213   VERIFY_IS_EQUAL(result.dimension(0), result_row_major.dimension(4));
    214   VERIFY_IS_EQUAL(result.dimension(1), result_row_major.dimension(3));
    215   VERIFY_IS_EQUAL(result.dimension(2), result_row_major.dimension(2));
    216   VERIFY_IS_EQUAL(result.dimension(3), result_row_major.dimension(1));
    217   VERIFY_IS_EQUAL(result.dimension(4), result_row_major.dimension(0));
    218 
    219   // No padding is carried out.
    220   int row_padding = 0;
    221   int col_padding = 0;
    222 
    223   for (int i = 0; (i+stride+ksize-1) < input_rows; i += stride) {  // input rows
    224     for (int j = 0; (j+stride+ksize-1) < input_cols; j += stride) {  // input cols
    225       int patchId = i+input_rows*j;
    226       for (int r = 0; r < ksize; ++r) {  // patch rows
    227         for (int c = 0; c < ksize; ++c) {  // patch cols
    228           for (int d = 0; d < input_depth; ++d) {  // depth
    229             for (int b = 0; b < input_batches; ++b) {  // batch
    230               float expected = 0.0f;
    231               float expected_row_major = 0.0f;
    232               int row_offset = r + i - row_padding;
    233               int col_offset = c + j - col_padding;
    234               if (row_offset >= 0 && col_offset >= 0 && row_offset < input_rows && col_offset < input_cols) {
    235                 expected = tensor(d, row_offset, col_offset, b);
    236                 expected_row_major = tensor_row_major(b, col_offset, row_offset, d);
    237               }
    238               // ColMajor
    239               if (result(d, r, c, patchId, b) != expected) {
    240                 std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << " b=" << b << std::endl;
    241               }
    242               VERIFY_IS_EQUAL(result(d, r, c, patchId, b), expected);
    243               // RowMajor
    244               if (result_row_major(b, patchId, c, r, d) != expected_row_major) {
    245                 std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << " b=" << b << std::endl;
    246               }
    247               VERIFY_IS_EQUAL(result_row_major(b, patchId, c, r, d), expected_row_major);
    248               // Check that ColMajor and RowMajor agree.
    249               VERIFY_IS_EQUAL(expected, expected_row_major);
    250             }
    251           }
    252         }
    253       }
    254     }
    255   }
    256 }
    257 
    258 // Verifies VALID padding (no padding) with the same value.
    259 void test_patch_padding_valid_same_value()
    260 {
    261   int input_depth = 1;
    262   int input_rows = 5;
    263   int input_cols = 5;
    264   int input_batches = 2;
    265   int ksize = 3;  // Corresponds to the Rows and Cols for tensor.extract_image_patches<>.
    266   int stride = 2;  // Only same stride is supported.
    267   // ColMajor
    268   Tensor<float, 4> tensor(input_depth, input_rows, input_cols, input_batches);
    269   tensor = tensor.constant(11.0f);
    270   Tensor<float, 5> result = tensor.extract_image_patches(ksize, ksize, stride, stride, 1, 1, PADDING_VALID);
    271 
    272   VERIFY_IS_EQUAL(result.dimension(0), input_depth);  // depth
    273   VERIFY_IS_EQUAL(result.dimension(1), ksize);  // kernel rows
    274   VERIFY_IS_EQUAL(result.dimension(2), ksize);  // kernel cols
    275   VERIFY_IS_EQUAL(result.dimension(3), 4);  // number of patches
    276   VERIFY_IS_EQUAL(result.dimension(4), input_batches);  // number of batches
    277 
    278   // RowMajor
    279   Tensor<float, 4, RowMajor> tensor_row_major = tensor.swap_layout();
    280   VERIFY_IS_EQUAL(tensor.dimension(0), tensor_row_major.dimension(3));
    281   VERIFY_IS_EQUAL(tensor.dimension(1), tensor_row_major.dimension(2));
    282   VERIFY_IS_EQUAL(tensor.dimension(2), tensor_row_major.dimension(1));
    283   VERIFY_IS_EQUAL(tensor.dimension(3), tensor_row_major.dimension(0));
    284 
    285   Tensor<float, 5, RowMajor> result_row_major = tensor_row_major.extract_image_patches(ksize, ksize, stride, stride, 1, 1, PADDING_VALID);
    286   VERIFY_IS_EQUAL(result.dimension(0), result_row_major.dimension(4));
    287   VERIFY_IS_EQUAL(result.dimension(1), result_row_major.dimension(3));
    288   VERIFY_IS_EQUAL(result.dimension(2), result_row_major.dimension(2));
    289   VERIFY_IS_EQUAL(result.dimension(3), result_row_major.dimension(1));
    290   VERIFY_IS_EQUAL(result.dimension(4), result_row_major.dimension(0));
    291 
    292   // No padding is carried out.
    293   int row_padding = 0;
    294   int col_padding = 0;
    295 
    296   for (int i = 0; (i+stride+ksize-1) <= input_rows; i += stride) {  // input rows
    297     for (int j = 0; (j+stride+ksize-1) <= input_cols; j += stride) {  // input cols
    298       int patchId = i+input_rows*j;
    299       for (int r = 0; r < ksize; ++r) {  // patch rows
    300         for (int c = 0; c < ksize; ++c) {  // patch cols
    301           for (int d = 0; d < input_depth; ++d) {  // depth
    302             for (int b = 0; b < input_batches; ++b) {  // batch
    303               float expected = 0.0f;
    304               float expected_row_major = 0.0f;
    305               int row_offset = r + i - row_padding;
    306               int col_offset = c + j - col_padding;
    307               if (row_offset >= 0 && col_offset >= 0 && row_offset < input_rows && col_offset < input_cols) {
    308                 expected = tensor(d, row_offset, col_offset, b);
    309                 expected_row_major = tensor_row_major(b, col_offset, row_offset, d);
    310               }
    311               // ColMajor
    312               if (result(d, r, c, patchId, b) != expected) {
    313                 std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << " b=" << b << std::endl;
    314               }
    315               VERIFY_IS_EQUAL(result(d, r, c, patchId, b), expected);
    316               // RowMajor
    317               if (result_row_major(b, patchId, c, r, d) != expected_row_major) {
    318                 std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << " b=" << b << std::endl;
    319               }
    320               VERIFY_IS_EQUAL(result_row_major(b, patchId, c, r, d), expected_row_major);
    321               // Check that ColMajor and RowMajor agree.
    322               VERIFY_IS_EQUAL(expected, expected_row_major);
    323             }
    324           }
    325         }
    326       }
    327     }
    328   }
    329 }
    330 
    331 // Verifies SAME padding.
    332 void test_patch_padding_same()
    333 {
    334   int input_depth = 3;
    335   int input_rows = 4;
    336   int input_cols = 2;
    337   int input_batches = 1;
    338   int ksize = 2;  // Corresponds to the Rows and Cols for tensor.extract_image_patches<>.
    339   int stride = 2;  // Only same stride is supported.
    340   // ColMajor
    341   Tensor<float, 4> tensor(input_depth, input_rows, input_cols, input_batches);
    342   // Initializes tensor with incrementing numbers.
    343   for (int i = 0; i < tensor.size(); ++i) {
    344     tensor.data()[i] = i + 1;
    345   }
    346   Tensor<float, 5> result = tensor.extract_image_patches(ksize, ksize, stride, stride, PADDING_SAME);
    347 
    348   VERIFY_IS_EQUAL(result.dimension(0), input_depth);  // depth
    349   VERIFY_IS_EQUAL(result.dimension(1), ksize);  // kernel rows
    350   VERIFY_IS_EQUAL(result.dimension(2), ksize);  // kernel cols
    351   VERIFY_IS_EQUAL(result.dimension(3), 2);  // number of patches
    352   VERIFY_IS_EQUAL(result.dimension(4), input_batches);  // number of batches
    353 
    354   // RowMajor
    355   Tensor<float, 4, RowMajor> tensor_row_major = tensor.swap_layout();
    356   VERIFY_IS_EQUAL(tensor.dimension(0), tensor_row_major.dimension(3));
    357   VERIFY_IS_EQUAL(tensor.dimension(1), tensor_row_major.dimension(2));
    358   VERIFY_IS_EQUAL(tensor.dimension(2), tensor_row_major.dimension(1));
    359   VERIFY_IS_EQUAL(tensor.dimension(3), tensor_row_major.dimension(0));
    360 
    361   Tensor<float, 5, RowMajor> result_row_major = tensor_row_major.extract_image_patches(ksize, ksize, stride, stride, PADDING_SAME);
    362   VERIFY_IS_EQUAL(result.dimension(0), result_row_major.dimension(4));
    363   VERIFY_IS_EQUAL(result.dimension(1), result_row_major.dimension(3));
    364   VERIFY_IS_EQUAL(result.dimension(2), result_row_major.dimension(2));
    365   VERIFY_IS_EQUAL(result.dimension(3), result_row_major.dimension(1));
    366   VERIFY_IS_EQUAL(result.dimension(4), result_row_major.dimension(0));
    367 
    368   // Based on the calculation described in TensorTraits.h, padding happens to be
    369   // 0.
    370   int row_padding = 0;
    371   int col_padding = 0;
    372 
    373   for (int i = 0; (i+stride+ksize-1) <= input_rows; i += stride) {  // input rows
    374     for (int j = 0; (j+stride+ksize-1) <= input_cols; j += stride) {  // input cols
    375       int patchId = i+input_rows*j;
    376       for (int r = 0; r < ksize; ++r) {  // patch rows
    377         for (int c = 0; c < ksize; ++c) {  // patch cols
    378           for (int d = 0; d < input_depth; ++d) {  // depth
    379             for (int b = 0; b < input_batches; ++b) {  // batch
    380               float expected = 0.0f;
    381               float expected_row_major = 0.0f;
    382               int row_offset = r*stride + i - row_padding;
    383               int col_offset = c*stride + j - col_padding;
    384               if (row_offset >= 0 && col_offset >= 0 && row_offset < input_rows && col_offset < input_cols) {
    385                 expected = tensor(d, row_offset, col_offset, b);
    386                 expected_row_major = tensor_row_major(b, col_offset, row_offset, d);
    387               }
    388               // ColMajor
    389               if (result(d, r, c, patchId, b) != expected) {
    390                 std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << " b=" << b << std::endl;
    391               }
    392               VERIFY_IS_EQUAL(result(d, r, c, patchId, b), expected);
    393               // RowMajor
    394               if (result_row_major(b, patchId, c, r, d) != expected_row_major) {
    395                 std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << " b=" << b << std::endl;
    396               }
    397               VERIFY_IS_EQUAL(result_row_major(b, patchId, c, r, d), expected_row_major);
    398               // Check that ColMajor and RowMajor agree.
    399               VERIFY_IS_EQUAL(expected, expected_row_major);
    400             }
    401           }
    402         }
    403       }
    404     }
    405   }
    406 }
    407 
    408 void test_patch_no_extra_dim()
    409 {
    410   Tensor<float, 3> tensor(2,3,5);
    411   tensor.setRandom();
    412   Tensor<float, 3, RowMajor> tensor_row_major = tensor.swap_layout();
    413   VERIFY_IS_EQUAL(tensor.dimension(0), tensor_row_major.dimension(2));
    414   VERIFY_IS_EQUAL(tensor.dimension(1), tensor_row_major.dimension(1));
    415   VERIFY_IS_EQUAL(tensor.dimension(2), tensor_row_major.dimension(0));
    416 
    417   // Single pixel patch: ColMajor
    418   Tensor<float, 4> single_pixel_patch;
    419   single_pixel_patch = tensor.extract_image_patches(1, 1);
    420   VERIFY_IS_EQUAL(single_pixel_patch.dimension(0), 2);
    421   VERIFY_IS_EQUAL(single_pixel_patch.dimension(1), 1);
    422   VERIFY_IS_EQUAL(single_pixel_patch.dimension(2), 1);
    423   VERIFY_IS_EQUAL(single_pixel_patch.dimension(3), 3*5);
    424 
    425   // Single pixel patch: RowMajor
    426   Tensor<float, 4, RowMajor> single_pixel_patch_row_major;
    427   single_pixel_patch_row_major = tensor_row_major.extract_image_patches(1, 1);
    428   VERIFY_IS_EQUAL(single_pixel_patch_row_major.dimension(0), 3*5);
    429   VERIFY_IS_EQUAL(single_pixel_patch_row_major.dimension(1), 1);
    430   VERIFY_IS_EQUAL(single_pixel_patch_row_major.dimension(2), 1);
    431   VERIFY_IS_EQUAL(single_pixel_patch_row_major.dimension(3), 2);
    432 
    433   for (int i = 0; i < tensor.size(); ++i) {
    434     // ColMajor
    435     if (tensor.data()[i] != single_pixel_patch.data()[i]) {
    436       std::cout << "Mismatch detected at index " << i << " : " << tensor.data()[i] << " vs " << single_pixel_patch.data()[i] << std::endl;
    437     }
    438     VERIFY_IS_EQUAL(single_pixel_patch.data()[i], tensor.data()[i]);
    439     // RowMajor
    440     if (tensor_row_major.data()[i] != single_pixel_patch_row_major.data()[i]) {
    441       std::cout << "Mismatch detected at index " << i << " : "
    442            << tensor.data()[i] << " vs "
    443            << single_pixel_patch_row_major.data()[i] << std::endl;
    444     }
    445     VERIFY_IS_EQUAL(single_pixel_patch_row_major.data()[i],
    446                     tensor_row_major.data()[i]);
    447     VERIFY_IS_EQUAL(tensor.data()[i], tensor_row_major.data()[i]);
    448     VERIFY_IS_EQUAL(single_pixel_patch.data()[i],
    449                     single_pixel_patch_row_major.data()[i]);
    450   }
    451 
    452   // Entire image patch: ColMajor
    453   Tensor<float, 4> entire_image_patch;
    454   entire_image_patch = tensor.extract_image_patches(3, 5);
    455   VERIFY_IS_EQUAL(entire_image_patch.dimension(0), 2);
    456   VERIFY_IS_EQUAL(entire_image_patch.dimension(1), 3);
    457   VERIFY_IS_EQUAL(entire_image_patch.dimension(2), 5);
    458   VERIFY_IS_EQUAL(entire_image_patch.dimension(3), 3*5);
    459 
    460   // Entire image patch: RowMajor
    461   Tensor<float, 4, RowMajor> entire_image_patch_row_major;
    462   entire_image_patch_row_major = tensor_row_major.extract_image_patches(3, 5);
    463   VERIFY_IS_EQUAL(entire_image_patch_row_major.dimension(0), 3*5);
    464   VERIFY_IS_EQUAL(entire_image_patch_row_major.dimension(1), 5);
    465   VERIFY_IS_EQUAL(entire_image_patch_row_major.dimension(2), 3);
    466   VERIFY_IS_EQUAL(entire_image_patch_row_major.dimension(3), 2);
    467 
    468   for (int i = 0; i < 3; ++i) {
    469     for (int j = 0; j < 5; ++j) {
    470       int patchId = i+3*j;
    471       for (int r = 0; r < 3; ++r) {
    472         for (int c = 0; c < 5; ++c) {
    473           for (int d = 0; d < 2; ++d) {
    474             float expected = 0.0f;
    475             float expected_row_major = 0.0f;
    476             if (r-1+i >= 0 && c-2+j >= 0 && r-1+i < 3 && c-2+j < 5) {
    477               expected = tensor(d, r-1+i, c-2+j);
    478               expected_row_major = tensor_row_major(c-2+j, r-1+i, d);
    479             }
    480             // ColMajor
    481             if (entire_image_patch(d, r, c, patchId) != expected) {
    482               std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << std::endl;
    483             }
    484             VERIFY_IS_EQUAL(entire_image_patch(d, r, c, patchId), expected);
    485             // RowMajor
    486             if (entire_image_patch_row_major(patchId, c, r, d) !=
    487                 expected_row_major) {
    488               std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << std::endl;
    489             }
    490             VERIFY_IS_EQUAL(entire_image_patch_row_major(patchId, c, r, d),
    491                             expected_row_major);
    492             // Check that ColMajor and RowMajor agree.
    493             VERIFY_IS_EQUAL(expected, expected_row_major);
    494           }
    495         }
    496       }
    497     }
    498   }
    499 
    500   // 2D patch: ColMajor
    501   Tensor<float, 4> twod_patch;
    502   twod_patch = tensor.extract_image_patches(2, 2);
    503   VERIFY_IS_EQUAL(twod_patch.dimension(0), 2);
    504   VERIFY_IS_EQUAL(twod_patch.dimension(1), 2);
    505   VERIFY_IS_EQUAL(twod_patch.dimension(2), 2);
    506   VERIFY_IS_EQUAL(twod_patch.dimension(3), 3*5);
    507 
    508   // 2D patch: RowMajor
    509   Tensor<float, 4, RowMajor> twod_patch_row_major;
    510   twod_patch_row_major = tensor_row_major.extract_image_patches(2, 2);
    511   VERIFY_IS_EQUAL(twod_patch_row_major.dimension(0), 3*5);
    512   VERIFY_IS_EQUAL(twod_patch_row_major.dimension(1), 2);
    513   VERIFY_IS_EQUAL(twod_patch_row_major.dimension(2), 2);
    514   VERIFY_IS_EQUAL(twod_patch_row_major.dimension(3), 2);
    515 
    516   // Based on the calculation described in TensorTraits.h, padding happens to be 0.
    517   int row_padding = 0;
    518   int col_padding = 0;
    519   int stride = 1;
    520 
    521   for (int i = 0; i < 3; ++i) {
    522     for (int j = 0; j < 5; ++j) {
    523       int patchId = i+3*j;
    524       for (int r = 0; r < 2; ++r) {
    525         for (int c = 0; c < 2; ++c) {
    526           for (int d = 0; d < 2; ++d) {
    527             float expected = 0.0f;
    528             float expected_row_major = 0.0f;
    529             int row_offset = r*stride + i - row_padding;
    530             int col_offset = c*stride + j - col_padding;
    531             // ColMajor
    532             if (row_offset >= 0 && col_offset >= 0 && row_offset < tensor.dimension(1) && col_offset < tensor.dimension(2)) {
    533               expected = tensor(d, row_offset, col_offset);
    534             }
    535             if (twod_patch(d, r, c, patchId) != expected) {
    536               std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << std::endl;
    537             }
    538             VERIFY_IS_EQUAL(twod_patch(d, r, c, patchId), expected);
    539             // RowMajor
    540             if (row_offset >= 0 && col_offset >= 0 && row_offset < tensor_row_major.dimension(1) && col_offset < tensor_row_major.dimension(0)) {
    541               expected_row_major = tensor_row_major(col_offset, row_offset, d);
    542             }
    543             if (twod_patch_row_major(patchId, c, r, d) != expected_row_major) {
    544               std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << std::endl;
    545             }
    546             VERIFY_IS_EQUAL(twod_patch_row_major(patchId, c, r, d), expected_row_major);
    547             // Check that ColMajor and RowMajor agree.
    548             VERIFY_IS_EQUAL(expected, expected_row_major);
    549           }
    550         }
    551       }
    552     }
    553   }
    554 }
    555 
    556 void test_imagenet_patches()
    557 {
    558   // Test the code on typical configurations used by the 'imagenet' benchmarks at
    559   // https://github.com/soumith/convnet-benchmarks
    560   // ColMajor
    561   Tensor<float, 4> l_in(3, 128, 128, 16);
    562   l_in.setRandom();
    563   Tensor<float, 5> l_out = l_in.extract_image_patches(11, 11);
    564   VERIFY_IS_EQUAL(l_out.dimension(0), 3);
    565   VERIFY_IS_EQUAL(l_out.dimension(1), 11);
    566   VERIFY_IS_EQUAL(l_out.dimension(2), 11);
    567   VERIFY_IS_EQUAL(l_out.dimension(3), 128*128);
    568   VERIFY_IS_EQUAL(l_out.dimension(4), 16);
    569 
    570   // RowMajor
    571   Tensor<float, 5, RowMajor> l_out_row_major = l_in.swap_layout().extract_image_patches(11, 11);
    572   VERIFY_IS_EQUAL(l_out_row_major.dimension(0), 16);
    573   VERIFY_IS_EQUAL(l_out_row_major.dimension(1), 128*128);
    574   VERIFY_IS_EQUAL(l_out_row_major.dimension(2), 11);
    575   VERIFY_IS_EQUAL(l_out_row_major.dimension(3), 11);
    576   VERIFY_IS_EQUAL(l_out_row_major.dimension(4), 3);
    577 
    578   for (int b = 0; b < 16; ++b) {
    579     for (int i = 0; i < 128; ++i) {
    580       for (int j = 0; j < 128; ++j) {
    581         int patchId = i+128*j;
    582         for (int c = 0; c < 11; ++c) {
    583           for (int r = 0; r < 11; ++r) {
    584             for (int d = 0; d < 3; ++d) {
    585               float expected = 0.0f;
    586               if (r-5+i >= 0 && c-5+j >= 0 && r-5+i < 128 && c-5+j < 128) {
    587                 expected = l_in(d, r-5+i, c-5+j, b);
    588               }
    589               // ColMajor
    590               if (l_out(d, r, c, patchId, b) != expected) {
    591                 std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << " b=" << b << std::endl;
    592               }
    593               VERIFY_IS_EQUAL(l_out(d, r, c, patchId, b), expected);
    594               // RowMajor
    595               if (l_out_row_major(b, patchId, c, r, d) !=
    596                   expected) {
    597                 std::cout << "Mismatch detected at index i=" << i << " j=" << j
    598                      << " r=" << r << " c=" << c << " d=" << d << " b=" << b
    599                      << std::endl;
    600               }
    601               VERIFY_IS_EQUAL(l_out_row_major(b, patchId, c, r, d),
    602                               expected);
    603             }
    604           }
    605         }
    606       }
    607     }
    608   }
    609 
    610   // ColMajor
    611   l_in.resize(16, 64, 64, 32);
    612   l_in.setRandom();
    613   l_out = l_in.extract_image_patches(9, 9);
    614   VERIFY_IS_EQUAL(l_out.dimension(0), 16);
    615   VERIFY_IS_EQUAL(l_out.dimension(1), 9);
    616   VERIFY_IS_EQUAL(l_out.dimension(2), 9);
    617   VERIFY_IS_EQUAL(l_out.dimension(3), 64*64);
    618   VERIFY_IS_EQUAL(l_out.dimension(4), 32);
    619 
    620   // RowMajor
    621   l_out_row_major = l_in.swap_layout().extract_image_patches(9, 9);
    622   VERIFY_IS_EQUAL(l_out_row_major.dimension(0), 32);
    623   VERIFY_IS_EQUAL(l_out_row_major.dimension(1), 64*64);
    624   VERIFY_IS_EQUAL(l_out_row_major.dimension(2), 9);
    625   VERIFY_IS_EQUAL(l_out_row_major.dimension(3), 9);
    626   VERIFY_IS_EQUAL(l_out_row_major.dimension(4), 16);
    627 
    628   for (int b = 0; b < 32; ++b) {
    629     for (int i = 0; i < 64; ++i) {
    630       for (int j = 0; j < 64; ++j) {
    631         int patchId = i+64*j;
    632         for (int c = 0; c < 9; ++c) {
    633           for (int r = 0; r < 9; ++r) {
    634             for (int d = 0; d < 16; ++d) {
    635               float expected = 0.0f;
    636               if (r-4+i >= 0 && c-4+j >= 0 && r-4+i < 64 && c-4+j < 64) {
    637                 expected = l_in(d, r-4+i, c-4+j, b);
    638               }
    639               // ColMajor
    640               if (l_out(d, r, c, patchId, b) != expected) {
    641                 std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << " b=" << b << std::endl;
    642               }
    643               VERIFY_IS_EQUAL(l_out(d, r, c, patchId, b), expected);
    644               // RowMajor
    645               if (l_out_row_major(b, patchId, c, r, d) != expected) {
    646                 std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << " b=" << b << std::endl;
    647               }
    648               VERIFY_IS_EQUAL(l_out_row_major(b, patchId, c, r, d), expected);
    649             }
    650           }
    651         }
    652       }
    653     }
    654   }
    655 
    656   // ColMajor
    657   l_in.resize(32, 16, 16, 32);
    658   l_in.setRandom();
    659   l_out = l_in.extract_image_patches(7, 7);
    660   VERIFY_IS_EQUAL(l_out.dimension(0), 32);
    661   VERIFY_IS_EQUAL(l_out.dimension(1), 7);
    662   VERIFY_IS_EQUAL(l_out.dimension(2), 7);
    663   VERIFY_IS_EQUAL(l_out.dimension(3), 16*16);
    664   VERIFY_IS_EQUAL(l_out.dimension(4), 32);
    665 
    666   // RowMajor
    667   l_out_row_major = l_in.swap_layout().extract_image_patches(7, 7);
    668   VERIFY_IS_EQUAL(l_out_row_major.dimension(0), 32);
    669   VERIFY_IS_EQUAL(l_out_row_major.dimension(1), 16*16);
    670   VERIFY_IS_EQUAL(l_out_row_major.dimension(2), 7);
    671   VERIFY_IS_EQUAL(l_out_row_major.dimension(3), 7);
    672   VERIFY_IS_EQUAL(l_out_row_major.dimension(4), 32);
    673 
    674   for (int b = 0; b < 32; ++b) {
    675     for (int i = 0; i < 16; ++i) {
    676       for (int j = 0; j < 16; ++j) {
    677         int patchId = i+16*j;
    678         for (int c = 0; c < 7; ++c) {
    679           for (int r = 0; r < 7; ++r) {
    680             for (int d = 0; d < 32; ++d) {
    681               float expected = 0.0f;
    682               if (r-3+i >= 0 && c-3+j >= 0 && r-3+i < 16 && c-3+j < 16) {
    683                 expected = l_in(d, r-3+i, c-3+j, b);
    684               }
    685               // ColMajor
    686               if (l_out(d, r, c, patchId, b) != expected) {
    687                 std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << " b=" << b << std::endl;
    688               }
    689               VERIFY_IS_EQUAL(l_out(d, r, c, patchId, b), expected);
    690               // RowMajor
    691               if (l_out_row_major(b, patchId, c, r, d) != expected) {
    692                 std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << " b=" << b << std::endl;
    693               }
    694               VERIFY_IS_EQUAL(l_out_row_major(b, patchId, c, r, d), expected);
    695             }
    696           }
    697         }
    698       }
    699     }
    700   }
    701 
    702   // ColMajor
    703   l_in.resize(64, 13, 13, 32);
    704   l_in.setRandom();
    705   l_out = l_in.extract_image_patches(3, 3);
    706   VERIFY_IS_EQUAL(l_out.dimension(0), 64);
    707   VERIFY_IS_EQUAL(l_out.dimension(1), 3);
    708   VERIFY_IS_EQUAL(l_out.dimension(2), 3);
    709   VERIFY_IS_EQUAL(l_out.dimension(3), 13*13);
    710   VERIFY_IS_EQUAL(l_out.dimension(4), 32);
    711 
    712   // RowMajor
    713   l_out_row_major = l_in.swap_layout().extract_image_patches(3, 3);
    714   VERIFY_IS_EQUAL(l_out_row_major.dimension(0), 32);
    715   VERIFY_IS_EQUAL(l_out_row_major.dimension(1), 13*13);
    716   VERIFY_IS_EQUAL(l_out_row_major.dimension(2), 3);
    717   VERIFY_IS_EQUAL(l_out_row_major.dimension(3), 3);
    718   VERIFY_IS_EQUAL(l_out_row_major.dimension(4), 64);
    719 
    720   for (int b = 0; b < 32; ++b) {
    721     for (int i = 0; i < 13; ++i) {
    722       for (int j = 0; j < 13; ++j) {
    723         int patchId = i+13*j;
    724         for (int c = 0; c < 3; ++c) {
    725           for (int r = 0; r < 3; ++r) {
    726             for (int d = 0; d < 64; ++d) {
    727               float expected = 0.0f;
    728               if (r-1+i >= 0 && c-1+j >= 0 && r-1+i < 13 && c-1+j < 13) {
    729                 expected = l_in(d, r-1+i, c-1+j, b);
    730               }
    731               // ColMajor
    732               if (l_out(d, r, c, patchId, b) != expected) {
    733                 std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << " b=" << b << std::endl;
    734               }
    735               VERIFY_IS_EQUAL(l_out(d, r, c, patchId, b), expected);
    736               // RowMajor
    737               if (l_out_row_major(b, patchId, c, r, d) != expected) {
    738                 std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << " b=" << b << std::endl;
    739               }
    740               VERIFY_IS_EQUAL(l_out_row_major(b, patchId, c, r, d), expected);
    741             }
    742           }
    743         }
    744       }
    745     }
    746   }
    747 }
    748 
    749 void test_cxx11_tensor_image_patch()
    750 {
    751   CALL_SUBTEST_1(test_simple_patch());
    752   CALL_SUBTEST_2(test_patch_no_extra_dim());
    753   CALL_SUBTEST_3(test_patch_padding_valid());
    754   CALL_SUBTEST_4(test_patch_padding_valid_same_value());
    755   CALL_SUBTEST_5(test_patch_padding_same());
    756   CALL_SUBTEST_6(test_imagenet_patches());
    757 }
    758