mirror of
https://gitlab.com/libeigen/eigen.git
synced 2026-04-10 11:34:33 +08:00
merge Tensor module within Eigen/unsupported and update gemv BLAS wrapper
This commit is contained in:
@@ -50,7 +50,7 @@ if(MPFR_FOUND)
|
||||
include_directories(${MPFR_INCLUDES} ./mpreal)
|
||||
ei_add_property(EIGEN_TESTED_BACKENDS "MPFR C++, ")
|
||||
set(EIGEN_MPFR_TEST_LIBRARIES ${MPFR_LIBRARIES} ${GMP_LIBRARIES})
|
||||
ei_add_test(mpreal_support "" "${EIGEN_MPFR_TEST_LIBRARIES}" )
|
||||
# ei_add_test(mpreal_support "" "${EIGEN_MPFR_TEST_LIBRARIES}" )
|
||||
else()
|
||||
ei_add_property(EIGEN_MISSING_BACKENDS "MPFR C++, ")
|
||||
endif()
|
||||
@@ -95,12 +95,50 @@ ei_add_test(minres)
|
||||
ei_add_test(levenberg_marquardt)
|
||||
ei_add_test(kronecker_product)
|
||||
|
||||
option(EIGEN_TEST_CXX11 "Enable testing of C++11 features (e.g. Tensor module)." OFF)
|
||||
option(EIGEN_TEST_CXX11 "Enable testing of C++11 features (e.g. Tensor module)." ON)
|
||||
if(EIGEN_TEST_CXX11)
|
||||
# FIXME: add C++11 compiler switch in some portable way
|
||||
# (MSVC doesn't need any for example, so this will
|
||||
# clash there)
|
||||
# It should be safe to always run these tests as there is some fallback code for
|
||||
# older compiler that don't support cxx11.
|
||||
ei_add_test(cxx11_meta "-std=c++0x")
|
||||
ei_add_test(cxx11_tensor_simple "-std=c++0x")
|
||||
ei_add_test(cxx11_tensor_symmetry "-std=c++0x")
|
||||
# ei_add_test(cxx11_tensor_symmetry "-std=c++0x")
|
||||
ei_add_test(cxx11_tensor_assign "-std=c++0x")
|
||||
ei_add_test(cxx11_tensor_dimension "-std=c++0x")
|
||||
ei_add_test(cxx11_tensor_index_list "-std=c++0x")
|
||||
ei_add_test(cxx11_tensor_comparisons "-std=c++0x")
|
||||
ei_add_test(cxx11_tensor_contraction "-std=c++0x")
|
||||
ei_add_test(cxx11_tensor_convolution "-std=c++0x")
|
||||
ei_add_test(cxx11_tensor_expr "-std=c++0x")
|
||||
ei_add_test(cxx11_tensor_forced_eval "-std=c++0x")
|
||||
ei_add_test(cxx11_tensor_fixed_size "-std=c++0x")
|
||||
ei_add_test(cxx11_tensor_const "-std=c++0x")
|
||||
ei_add_test(cxx11_tensor_of_const_values "-std=c++0x")
|
||||
ei_add_test(cxx11_tensor_of_complex "-std=c++0x")
|
||||
ei_add_test(cxx11_tensor_of_strings "-std=c++0x")
|
||||
ei_add_test(cxx11_tensor_intdiv "-std=c++0x")
|
||||
ei_add_test(cxx11_tensor_lvalue "-std=c++0x")
|
||||
ei_add_test(cxx11_tensor_map "-std=c++0x")
|
||||
ei_add_test(cxx11_tensor_broadcasting "-std=c++0x")
|
||||
ei_add_test(cxx11_tensor_chipping "-std=c++0x")
|
||||
ei_add_test(cxx11_tensor_concatenation "-std=c++0x")
|
||||
ei_add_test(cxx11_tensor_morphing "-std=c++0x")
|
||||
ei_add_test(cxx11_tensor_padding "-std=c++0x")
|
||||
ei_add_test(cxx11_tensor_patch "-std=c++0x")
|
||||
ei_add_test(cxx11_tensor_image_patch "-std=c++0x")
|
||||
ei_add_test(cxx11_tensor_reduction "-std=c++0x")
|
||||
ei_add_test(cxx11_tensor_shuffling "-std=c++0x")
|
||||
ei_add_test(cxx11_tensor_striding "-std=c++0x")
|
||||
ei_add_test(cxx11_tensor_thread_pool "-std=c++0x")
|
||||
ei_add_test(cxx11_tensor_ref "-std=c++0x")
|
||||
ei_add_test(cxx11_tensor_random "-std=c++0x")
|
||||
ei_add_test(cxx11_tensor_casts "-std=c++0x")
|
||||
ei_add_test(cxx11_tensor_reverse "-std=c++0x")
|
||||
ei_add_test(cxx11_tensor_layout_swap "-std=c++0x")
|
||||
ei_add_test(cxx11_tensor_io "-std=c++0x")
|
||||
|
||||
# These tests needs nvcc
|
||||
# ei_add_test(cxx11_tensor_device "-std=c++0x")
|
||||
# ei_add_test(cxx11_tensor_cuda "-std=c++0x")
|
||||
# ei_add_test(cxx11_tensor_contract_cuda "-std=c++0x")
|
||||
|
||||
endif()
|
||||
|
||||
370
unsupported/test/cxx11_tensor_assign.cpp
Normal file
370
unsupported/test/cxx11_tensor_assign.cpp
Normal file
@@ -0,0 +1,370 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#include <Eigen/CXX11/Tensor>
|
||||
|
||||
using Eigen::Tensor;
|
||||
using Eigen::RowMajor;
|
||||
|
||||
static void test_1d()
|
||||
{
|
||||
Tensor<int, 1> vec1(6);
|
||||
Tensor<int, 1, RowMajor> vec2(6);
|
||||
vec1(0) = 4; vec2(0) = 0;
|
||||
vec1(1) = 8; vec2(1) = 1;
|
||||
vec1(2) = 15; vec2(2) = 2;
|
||||
vec1(3) = 16; vec2(3) = 3;
|
||||
vec1(4) = 23; vec2(4) = 4;
|
||||
vec1(5) = 42; vec2(5) = 5;
|
||||
|
||||
int col_major[6];
|
||||
int row_major[6];
|
||||
memset(col_major, 0, 6*sizeof(int));
|
||||
memset(row_major, 0, 6*sizeof(int));
|
||||
TensorMap<Tensor<int, 1>> vec3(col_major, 6);
|
||||
TensorMap<Tensor<int, 1, RowMajor>> vec4(row_major, 6);
|
||||
|
||||
vec3 = vec1;
|
||||
vec4 = vec2;
|
||||
|
||||
VERIFY_IS_EQUAL(vec3(0), 4);
|
||||
VERIFY_IS_EQUAL(vec3(1), 8);
|
||||
VERIFY_IS_EQUAL(vec3(2), 15);
|
||||
VERIFY_IS_EQUAL(vec3(3), 16);
|
||||
VERIFY_IS_EQUAL(vec3(4), 23);
|
||||
VERIFY_IS_EQUAL(vec3(5), 42);
|
||||
|
||||
VERIFY_IS_EQUAL(vec4(0), 0);
|
||||
VERIFY_IS_EQUAL(vec4(1), 1);
|
||||
VERIFY_IS_EQUAL(vec4(2), 2);
|
||||
VERIFY_IS_EQUAL(vec4(3), 3);
|
||||
VERIFY_IS_EQUAL(vec4(4), 4);
|
||||
VERIFY_IS_EQUAL(vec4(5), 5);
|
||||
|
||||
vec1.setZero();
|
||||
vec2.setZero();
|
||||
vec1 = vec3;
|
||||
vec2 = vec4;
|
||||
|
||||
VERIFY_IS_EQUAL(vec1(0), 4);
|
||||
VERIFY_IS_EQUAL(vec1(1), 8);
|
||||
VERIFY_IS_EQUAL(vec1(2), 15);
|
||||
VERIFY_IS_EQUAL(vec1(3), 16);
|
||||
VERIFY_IS_EQUAL(vec1(4), 23);
|
||||
VERIFY_IS_EQUAL(vec1(5), 42);
|
||||
|
||||
VERIFY_IS_EQUAL(vec2(0), 0);
|
||||
VERIFY_IS_EQUAL(vec2(1), 1);
|
||||
VERIFY_IS_EQUAL(vec2(2), 2);
|
||||
VERIFY_IS_EQUAL(vec2(3), 3);
|
||||
VERIFY_IS_EQUAL(vec2(4), 4);
|
||||
VERIFY_IS_EQUAL(vec2(5), 5);
|
||||
}
|
||||
|
||||
static void test_2d()
|
||||
{
|
||||
Tensor<int, 2> mat1(2,3);
|
||||
Tensor<int, 2, RowMajor> mat2(2,3);
|
||||
|
||||
mat1(0,0) = 0;
|
||||
mat1(0,1) = 1;
|
||||
mat1(0,2) = 2;
|
||||
mat1(1,0) = 3;
|
||||
mat1(1,1) = 4;
|
||||
mat1(1,2) = 5;
|
||||
|
||||
mat2(0,0) = 0;
|
||||
mat2(0,1) = 1;
|
||||
mat2(0,2) = 2;
|
||||
mat2(1,0) = 3;
|
||||
mat2(1,1) = 4;
|
||||
mat2(1,2) = 5;
|
||||
|
||||
int col_major[6];
|
||||
int row_major[6];
|
||||
memset(col_major, 0, 6*sizeof(int));
|
||||
memset(row_major, 0, 6*sizeof(int));
|
||||
TensorMap<Tensor<int, 2>> mat3(row_major, 2, 3);
|
||||
TensorMap<Tensor<int, 2, RowMajor>> mat4(col_major, 2, 3);
|
||||
|
||||
mat3 = mat1;
|
||||
mat4 = mat2;
|
||||
|
||||
VERIFY_IS_EQUAL(mat3(0,0), 0);
|
||||
VERIFY_IS_EQUAL(mat3(0,1), 1);
|
||||
VERIFY_IS_EQUAL(mat3(0,2), 2);
|
||||
VERIFY_IS_EQUAL(mat3(1,0), 3);
|
||||
VERIFY_IS_EQUAL(mat3(1,1), 4);
|
||||
VERIFY_IS_EQUAL(mat3(1,2), 5);
|
||||
|
||||
VERIFY_IS_EQUAL(mat4(0,0), 0);
|
||||
VERIFY_IS_EQUAL(mat4(0,1), 1);
|
||||
VERIFY_IS_EQUAL(mat4(0,2), 2);
|
||||
VERIFY_IS_EQUAL(mat4(1,0), 3);
|
||||
VERIFY_IS_EQUAL(mat4(1,1), 4);
|
||||
VERIFY_IS_EQUAL(mat4(1,2), 5);
|
||||
|
||||
mat1.setZero();
|
||||
mat2.setZero();
|
||||
mat1 = mat3;
|
||||
mat2 = mat4;
|
||||
|
||||
VERIFY_IS_EQUAL(mat1(0,0), 0);
|
||||
VERIFY_IS_EQUAL(mat1(0,1), 1);
|
||||
VERIFY_IS_EQUAL(mat1(0,2), 2);
|
||||
VERIFY_IS_EQUAL(mat1(1,0), 3);
|
||||
VERIFY_IS_EQUAL(mat1(1,1), 4);
|
||||
VERIFY_IS_EQUAL(mat1(1,2), 5);
|
||||
|
||||
VERIFY_IS_EQUAL(mat2(0,0), 0);
|
||||
VERIFY_IS_EQUAL(mat2(0,1), 1);
|
||||
VERIFY_IS_EQUAL(mat2(0,2), 2);
|
||||
VERIFY_IS_EQUAL(mat2(1,0), 3);
|
||||
VERIFY_IS_EQUAL(mat2(1,1), 4);
|
||||
VERIFY_IS_EQUAL(mat2(1,2), 5);
|
||||
}
|
||||
|
||||
static void test_3d()
|
||||
{
|
||||
Tensor<int, 3> mat1(2,3,7);
|
||||
Tensor<int, 3, RowMajor> mat2(2,3,7);
|
||||
|
||||
int val = 0;
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 7; ++k) {
|
||||
mat1(i,j,k) = val;
|
||||
mat2(i,j,k) = val;
|
||||
val++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int col_major[2*3*7];
|
||||
int row_major[2*3*7];
|
||||
memset(col_major, 0, 2*3*7*sizeof(int));
|
||||
memset(row_major, 0, 2*3*7*sizeof(int));
|
||||
TensorMap<Tensor<int, 3>> mat3(col_major, 2, 3, 7);
|
||||
TensorMap<Tensor<int, 3, RowMajor>> mat4(row_major, 2, 3, 7);
|
||||
|
||||
mat3 = mat1;
|
||||
mat4 = mat2;
|
||||
|
||||
val = 0;
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 7; ++k) {
|
||||
VERIFY_IS_EQUAL(mat3(i,j,k), val);
|
||||
VERIFY_IS_EQUAL(mat4(i,j,k), val);
|
||||
val++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mat1.setZero();
|
||||
mat2.setZero();
|
||||
mat1 = mat3;
|
||||
mat2 = mat4;
|
||||
|
||||
val = 0;
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 7; ++k) {
|
||||
VERIFY_IS_EQUAL(mat1(i,j,k), val);
|
||||
VERIFY_IS_EQUAL(mat2(i,j,k), val);
|
||||
val++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void test_same_type()
|
||||
{
|
||||
Tensor<int, 1> orig_tensor(5);
|
||||
Tensor<int, 1> dest_tensor(5);
|
||||
orig_tensor.setRandom();
|
||||
dest_tensor.setRandom();
|
||||
int* orig_data = orig_tensor.data();
|
||||
int* dest_data = dest_tensor.data();
|
||||
dest_tensor = orig_tensor;
|
||||
VERIFY_IS_EQUAL(orig_tensor.data(), orig_data);
|
||||
VERIFY_IS_EQUAL(dest_tensor.data(), dest_data);
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
VERIFY_IS_EQUAL(dest_tensor(i), orig_tensor(i));
|
||||
}
|
||||
|
||||
TensorFixedSize<int, Sizes<5> > orig_array;
|
||||
TensorFixedSize<int, Sizes<5> > dest_array;
|
||||
orig_array.setRandom();
|
||||
dest_array.setRandom();
|
||||
orig_data = orig_array.data();
|
||||
dest_data = dest_array.data();
|
||||
dest_array = orig_array;
|
||||
VERIFY_IS_EQUAL(orig_array.data(), orig_data);
|
||||
VERIFY_IS_EQUAL(dest_array.data(), dest_data);
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
VERIFY_IS_EQUAL(dest_array(i), orig_array(i));
|
||||
}
|
||||
|
||||
int orig[5] = {1, 2, 3, 4, 5};
|
||||
int dest[5] = {6, 7, 8, 9, 10};
|
||||
TensorMap<Tensor<int, 1> > orig_map(orig, 5);
|
||||
TensorMap<Tensor<int, 1> > dest_map(dest, 5);
|
||||
orig_data = orig_map.data();
|
||||
dest_data = dest_map.data();
|
||||
dest_map = orig_map;
|
||||
VERIFY_IS_EQUAL(orig_map.data(), orig_data);
|
||||
VERIFY_IS_EQUAL(dest_map.data(), dest_data);
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
VERIFY_IS_EQUAL(dest[i], i+1);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_auto_resize()
|
||||
{
|
||||
Tensor<int, 1> tensor1;
|
||||
Tensor<int, 1> tensor2(3);
|
||||
Tensor<int, 1> tensor3(5);
|
||||
Tensor<int, 1> tensor4(7);
|
||||
|
||||
Tensor<int, 1> new_tensor(5);
|
||||
new_tensor.setRandom();
|
||||
|
||||
tensor1 = tensor2 = tensor3 = tensor4 = new_tensor;
|
||||
|
||||
VERIFY_IS_EQUAL(tensor1.dimension(0), new_tensor.dimension(0));
|
||||
VERIFY_IS_EQUAL(tensor2.dimension(0), new_tensor.dimension(0));
|
||||
VERIFY_IS_EQUAL(tensor3.dimension(0), new_tensor.dimension(0));
|
||||
VERIFY_IS_EQUAL(tensor4.dimension(0), new_tensor.dimension(0));
|
||||
for (int i = 0; i < new_tensor.dimension(0); ++i) {
|
||||
VERIFY_IS_EQUAL(tensor1(i), new_tensor(i));
|
||||
VERIFY_IS_EQUAL(tensor2(i), new_tensor(i));
|
||||
VERIFY_IS_EQUAL(tensor3(i), new_tensor(i));
|
||||
VERIFY_IS_EQUAL(tensor4(i), new_tensor(i));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void test_compound_assign()
|
||||
{
|
||||
Tensor<int, 1> start_tensor(10);
|
||||
Tensor<int, 1> offset_tensor(10);
|
||||
start_tensor.setRandom();
|
||||
offset_tensor.setRandom();
|
||||
|
||||
Tensor<int, 1> tensor = start_tensor;
|
||||
tensor += offset_tensor;
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
VERIFY_IS_EQUAL(tensor(i), start_tensor(i) + offset_tensor(i));
|
||||
}
|
||||
|
||||
tensor = start_tensor;
|
||||
tensor -= offset_tensor;
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
VERIFY_IS_EQUAL(tensor(i), start_tensor(i) - offset_tensor(i));
|
||||
}
|
||||
|
||||
tensor = start_tensor;
|
||||
tensor *= offset_tensor;
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
VERIFY_IS_EQUAL(tensor(i), start_tensor(i) * offset_tensor(i));
|
||||
}
|
||||
|
||||
tensor = start_tensor;
|
||||
tensor /= offset_tensor;
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
VERIFY_IS_EQUAL(tensor(i), start_tensor(i) / offset_tensor(i));
|
||||
}
|
||||
}
|
||||
|
||||
static void test_std_initializers_tensor() {
|
||||
#ifdef EIGEN_HAS_VARIADIC_TEMPLATES
|
||||
Tensor<int, 1> a(3);
|
||||
a.setValues({0, 1, 2});
|
||||
VERIFY_IS_EQUAL(a(0), 0);
|
||||
VERIFY_IS_EQUAL(a(1), 1);
|
||||
VERIFY_IS_EQUAL(a(2), 2);
|
||||
|
||||
// It fills the top-left slice.
|
||||
a.setValues({10, 20});
|
||||
VERIFY_IS_EQUAL(a(0), 10);
|
||||
VERIFY_IS_EQUAL(a(1), 20);
|
||||
VERIFY_IS_EQUAL(a(2), 2);
|
||||
|
||||
// Chaining.
|
||||
Tensor<int, 1> a2(3);
|
||||
a2 = a.setValues({100, 200, 300});
|
||||
VERIFY_IS_EQUAL(a(0), 100);
|
||||
VERIFY_IS_EQUAL(a(1), 200);
|
||||
VERIFY_IS_EQUAL(a(2), 300);
|
||||
VERIFY_IS_EQUAL(a2(0), 100);
|
||||
VERIFY_IS_EQUAL(a2(1), 200);
|
||||
VERIFY_IS_EQUAL(a2(2), 300);
|
||||
|
||||
Tensor<int, 2> b(2, 3);
|
||||
b.setValues({{0, 1, 2}, {3, 4, 5}});
|
||||
VERIFY_IS_EQUAL(b(0, 0), 0);
|
||||
VERIFY_IS_EQUAL(b(0, 1), 1);
|
||||
VERIFY_IS_EQUAL(b(0, 2), 2);
|
||||
VERIFY_IS_EQUAL(b(1, 0), 3);
|
||||
VERIFY_IS_EQUAL(b(1, 1), 4);
|
||||
VERIFY_IS_EQUAL(b(1, 2), 5);
|
||||
|
||||
// It fills the top-left slice.
|
||||
b.setValues({{10, 20}, {30}});
|
||||
VERIFY_IS_EQUAL(b(0, 0), 10);
|
||||
VERIFY_IS_EQUAL(b(0, 1), 20);
|
||||
VERIFY_IS_EQUAL(b(0, 2), 2);
|
||||
VERIFY_IS_EQUAL(b(1, 0), 30);
|
||||
VERIFY_IS_EQUAL(b(1, 1), 4);
|
||||
VERIFY_IS_EQUAL(b(1, 2), 5);
|
||||
|
||||
Eigen::Tensor<int, 3> c(3, 2, 4);
|
||||
c.setValues({{{0, 1, 2, 3}, {4, 5, 6, 7}},
|
||||
{{10, 11, 12, 13}, {14, 15, 16, 17}},
|
||||
{{20, 21, 22, 23}, {24, 25, 26, 27}}});
|
||||
VERIFY_IS_EQUAL(c(0, 0, 0), 0);
|
||||
VERIFY_IS_EQUAL(c(0, 0, 1), 1);
|
||||
VERIFY_IS_EQUAL(c(0, 0, 2), 2);
|
||||
VERIFY_IS_EQUAL(c(0, 0, 3), 3);
|
||||
VERIFY_IS_EQUAL(c(0, 1, 0), 4);
|
||||
VERIFY_IS_EQUAL(c(0, 1, 1), 5);
|
||||
VERIFY_IS_EQUAL(c(0, 1, 2), 6);
|
||||
VERIFY_IS_EQUAL(c(0, 1, 3), 7);
|
||||
VERIFY_IS_EQUAL(c(1, 0, 0), 10);
|
||||
VERIFY_IS_EQUAL(c(1, 0, 1), 11);
|
||||
VERIFY_IS_EQUAL(c(1, 0, 2), 12);
|
||||
VERIFY_IS_EQUAL(c(1, 0, 3), 13);
|
||||
VERIFY_IS_EQUAL(c(1, 1, 0), 14);
|
||||
VERIFY_IS_EQUAL(c(1, 1, 1), 15);
|
||||
VERIFY_IS_EQUAL(c(1, 1, 2), 16);
|
||||
VERIFY_IS_EQUAL(c(1, 1, 3), 17);
|
||||
VERIFY_IS_EQUAL(c(2, 0, 0), 20);
|
||||
VERIFY_IS_EQUAL(c(2, 0, 1), 21);
|
||||
VERIFY_IS_EQUAL(c(2, 0, 2), 22);
|
||||
VERIFY_IS_EQUAL(c(2, 0, 3), 23);
|
||||
VERIFY_IS_EQUAL(c(2, 1, 0), 24);
|
||||
VERIFY_IS_EQUAL(c(2, 1, 1), 25);
|
||||
VERIFY_IS_EQUAL(c(2, 1, 2), 26);
|
||||
VERIFY_IS_EQUAL(c(2, 1, 3), 27);
|
||||
#endif // EIGEN_HAS_VARIADIC_TEMPLATES
|
||||
}
|
||||
|
||||
void test_cxx11_tensor_assign()
|
||||
{
|
||||
CALL_SUBTEST(test_1d());
|
||||
CALL_SUBTEST(test_2d());
|
||||
CALL_SUBTEST(test_3d());
|
||||
CALL_SUBTEST(test_same_type());
|
||||
CALL_SUBTEST(test_auto_resize());
|
||||
CALL_SUBTEST(test_compound_assign());
|
||||
CALL_SUBTEST(test_std_initializers_tensor());
|
||||
}
|
||||
194
unsupported/test/cxx11_tensor_broadcasting.cpp
Normal file
194
unsupported/test/cxx11_tensor_broadcasting.cpp
Normal file
@@ -0,0 +1,194 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#include <Eigen/CXX11/Tensor>
|
||||
|
||||
using Eigen::Tensor;
|
||||
|
||||
template <int DataLayout>
|
||||
static void test_simple_broadcasting()
|
||||
{
|
||||
Tensor<float, 4, DataLayout> tensor(2,3,5,7);
|
||||
tensor.setRandom();
|
||||
array<ptrdiff_t, 4> broadcasts;
|
||||
broadcasts[0] = 1;
|
||||
broadcasts[1] = 1;
|
||||
broadcasts[2] = 1;
|
||||
broadcasts[3] = 1;
|
||||
|
||||
Tensor<float, 4, DataLayout> no_broadcast;
|
||||
no_broadcast = tensor.broadcast(broadcasts);
|
||||
|
||||
VERIFY_IS_EQUAL(no_broadcast.dimension(0), 2);
|
||||
VERIFY_IS_EQUAL(no_broadcast.dimension(1), 3);
|
||||
VERIFY_IS_EQUAL(no_broadcast.dimension(2), 5);
|
||||
VERIFY_IS_EQUAL(no_broadcast.dimension(3), 7);
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 5; ++k) {
|
||||
for (int l = 0; l < 7; ++l) {
|
||||
VERIFY_IS_EQUAL(tensor(i,j,k,l), no_broadcast(i,j,k,l));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
broadcasts[0] = 2;
|
||||
broadcasts[1] = 3;
|
||||
broadcasts[2] = 1;
|
||||
broadcasts[3] = 4;
|
||||
Tensor<float, 4, DataLayout> broadcast;
|
||||
broadcast = tensor.broadcast(broadcasts);
|
||||
|
||||
VERIFY_IS_EQUAL(broadcast.dimension(0), 4);
|
||||
VERIFY_IS_EQUAL(broadcast.dimension(1), 9);
|
||||
VERIFY_IS_EQUAL(broadcast.dimension(2), 5);
|
||||
VERIFY_IS_EQUAL(broadcast.dimension(3), 28);
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
for (int j = 0; j < 9; ++j) {
|
||||
for (int k = 0; k < 5; ++k) {
|
||||
for (int l = 0; l < 28; ++l) {
|
||||
VERIFY_IS_EQUAL(tensor(i%2,j%3,k%5,l%7), broadcast(i,j,k,l));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <int DataLayout>
|
||||
static void test_vectorized_broadcasting()
|
||||
{
|
||||
Tensor<float, 3, DataLayout> tensor(8,3,5);
|
||||
tensor.setRandom();
|
||||
array<ptrdiff_t, 3> broadcasts;
|
||||
broadcasts[0] = 2;
|
||||
broadcasts[1] = 3;
|
||||
broadcasts[2] = 4;
|
||||
|
||||
Tensor<float, 3, DataLayout> broadcast;
|
||||
broadcast = tensor.broadcast(broadcasts);
|
||||
|
||||
VERIFY_IS_EQUAL(broadcast.dimension(0), 16);
|
||||
VERIFY_IS_EQUAL(broadcast.dimension(1), 9);
|
||||
VERIFY_IS_EQUAL(broadcast.dimension(2), 20);
|
||||
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
for (int j = 0; j < 9; ++j) {
|
||||
for (int k = 0; k < 20; ++k) {
|
||||
VERIFY_IS_EQUAL(tensor(i%8,j%3,k%5), broadcast(i,j,k));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tensor.resize(11,3,5);
|
||||
tensor.setRandom();
|
||||
broadcast = tensor.broadcast(broadcasts);
|
||||
|
||||
VERIFY_IS_EQUAL(broadcast.dimension(0), 22);
|
||||
VERIFY_IS_EQUAL(broadcast.dimension(1), 9);
|
||||
VERIFY_IS_EQUAL(broadcast.dimension(2), 20);
|
||||
|
||||
for (int i = 0; i < 22; ++i) {
|
||||
for (int j = 0; j < 9; ++j) {
|
||||
for (int k = 0; k < 20; ++k) {
|
||||
VERIFY_IS_EQUAL(tensor(i%11,j%3,k%5), broadcast(i,j,k));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <int DataLayout>
|
||||
static void test_static_broadcasting()
|
||||
{
|
||||
Tensor<float, 3, DataLayout> tensor(8,3,5);
|
||||
tensor.setRandom();
|
||||
|
||||
#ifdef EIGEN_HAS_CONSTEXPR
|
||||
Eigen::IndexList<Eigen::type2index<2>, Eigen::type2index<3>, Eigen::type2index<4>> broadcasts;
|
||||
#else
|
||||
Eigen::array<int, 3> broadcasts;
|
||||
broadcasts[0] = 2;
|
||||
broadcasts[1] = 3;
|
||||
broadcasts[2] = 4;
|
||||
#endif
|
||||
|
||||
Tensor<float, 3, DataLayout> broadcast;
|
||||
broadcast = tensor.broadcast(broadcasts);
|
||||
|
||||
VERIFY_IS_EQUAL(broadcast.dimension(0), 16);
|
||||
VERIFY_IS_EQUAL(broadcast.dimension(1), 9);
|
||||
VERIFY_IS_EQUAL(broadcast.dimension(2), 20);
|
||||
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
for (int j = 0; j < 9; ++j) {
|
||||
for (int k = 0; k < 20; ++k) {
|
||||
VERIFY_IS_EQUAL(tensor(i%8,j%3,k%5), broadcast(i,j,k));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tensor.resize(11,3,5);
|
||||
tensor.setRandom();
|
||||
broadcast = tensor.broadcast(broadcasts);
|
||||
|
||||
VERIFY_IS_EQUAL(broadcast.dimension(0), 22);
|
||||
VERIFY_IS_EQUAL(broadcast.dimension(1), 9);
|
||||
VERIFY_IS_EQUAL(broadcast.dimension(2), 20);
|
||||
|
||||
for (int i = 0; i < 22; ++i) {
|
||||
for (int j = 0; j < 9; ++j) {
|
||||
for (int k = 0; k < 20; ++k) {
|
||||
VERIFY_IS_EQUAL(tensor(i%11,j%3,k%5), broadcast(i,j,k));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <int DataLayout>
|
||||
static void test_fixed_size_broadcasting()
|
||||
{
|
||||
// Need to add a [] operator to the Size class for this to work
|
||||
#if 0
|
||||
Tensor<float, 1, DataLayout> t1(10);
|
||||
t1.setRandom();
|
||||
TensorFixedSize<float, Sizes<1>, DataLayout> t2;
|
||||
t2 = t2.constant(20.0f);
|
||||
|
||||
Tensor<float, 1, DataLayout> t3 = t1 + t2.broadcast(Eigen::array<int, 1>{{10}});
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
VERIFY_IS_APPROX(t3(i), t1(i) + t2(0));
|
||||
}
|
||||
|
||||
TensorMap<TensorFixedSize<float, Sizes<1>, DataLayout> > t4(t2.data(), {{1}});
|
||||
Tensor<float, 1, DataLayout> t5 = t1 + t4.broadcast(Eigen::array<int, 1>{{10}});
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
VERIFY_IS_APPROX(t5(i), t1(i) + t2(0));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void test_cxx11_tensor_broadcasting()
|
||||
{
|
||||
CALL_SUBTEST(test_simple_broadcasting<ColMajor>());
|
||||
CALL_SUBTEST(test_simple_broadcasting<RowMajor>());
|
||||
CALL_SUBTEST(test_vectorized_broadcasting<ColMajor>());
|
||||
CALL_SUBTEST(test_vectorized_broadcasting<RowMajor>());
|
||||
CALL_SUBTEST(test_static_broadcasting<ColMajor>());
|
||||
CALL_SUBTEST(test_static_broadcasting<RowMajor>());
|
||||
CALL_SUBTEST(test_fixed_size_broadcasting<ColMajor>());
|
||||
CALL_SUBTEST(test_fixed_size_broadcasting<RowMajor>());
|
||||
}
|
||||
41
unsupported/test/cxx11_tensor_casts.cpp
Normal file
41
unsupported/test/cxx11_tensor_casts.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#include <Eigen/CXX11/Tensor>
|
||||
|
||||
using Eigen::Tensor;
|
||||
using Eigen::array;
|
||||
|
||||
static void test_simple_cast()
|
||||
{
|
||||
Tensor<float, 2> ftensor(20,30);
|
||||
ftensor.setRandom();
|
||||
Tensor<char, 2> chartensor(20,30);
|
||||
chartensor.setRandom();
|
||||
Tensor<std::complex<float>, 2> cplextensor(20,30);
|
||||
cplextensor.setRandom();
|
||||
|
||||
chartensor = ftensor.cast<char>();
|
||||
cplextensor = ftensor.cast<std::complex<float>>();
|
||||
|
||||
for (int i = 0; i < 20; ++i) {
|
||||
for (int j = 0; j < 30; ++j) {
|
||||
VERIFY_IS_EQUAL(chartensor(i,j), static_cast<char>(ftensor(i,j)));
|
||||
VERIFY_IS_EQUAL(cplextensor(i,j), static_cast<std::complex<float>>(ftensor(i,j)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void test_cxx11_tensor_casts()
|
||||
{
|
||||
CALL_SUBTEST(test_simple_cast());
|
||||
}
|
||||
397
unsupported/test/cxx11_tensor_chipping.cpp
Normal file
397
unsupported/test/cxx11_tensor_chipping.cpp
Normal file
@@ -0,0 +1,397 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#include <Eigen/CXX11/Tensor>
|
||||
|
||||
using Eigen::Tensor;
|
||||
|
||||
template<int DataLayout>
|
||||
static void test_simple_chip()
|
||||
{
|
||||
Tensor<float, 5, DataLayout> tensor(2,3,5,7,11);
|
||||
tensor.setRandom();
|
||||
|
||||
Tensor<float, 4, DataLayout> chip1;
|
||||
chip1 = tensor.template chip<0>(1);
|
||||
|
||||
VERIFY_IS_EQUAL(chip1.dimension(0), 3);
|
||||
VERIFY_IS_EQUAL(chip1.dimension(1), 5);
|
||||
VERIFY_IS_EQUAL(chip1.dimension(2), 7);
|
||||
VERIFY_IS_EQUAL(chip1.dimension(3), 11);
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
for (int j = 0; j < 5; ++j) {
|
||||
for (int k = 0; k < 7; ++k) {
|
||||
for (int l = 0; l < 11; ++l) {
|
||||
VERIFY_IS_EQUAL(chip1(i,j,k,l), tensor(1,i,j,k,l));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Tensor<float, 4, DataLayout> chip2 = tensor.template chip<1>(1);
|
||||
VERIFY_IS_EQUAL(chip2.dimension(0), 2);
|
||||
VERIFY_IS_EQUAL(chip2.dimension(1), 5);
|
||||
VERIFY_IS_EQUAL(chip2.dimension(2), 7);
|
||||
VERIFY_IS_EQUAL(chip2.dimension(3), 11);
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 7; ++k) {
|
||||
for (int l = 0; l < 11; ++l) {
|
||||
VERIFY_IS_EQUAL(chip2(i,j,k,l), tensor(i,1,j,k,l));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Tensor<float, 4, DataLayout> chip3 = tensor.template chip<2>(2);
|
||||
VERIFY_IS_EQUAL(chip3.dimension(0), 2);
|
||||
VERIFY_IS_EQUAL(chip3.dimension(1), 3);
|
||||
VERIFY_IS_EQUAL(chip3.dimension(2), 7);
|
||||
VERIFY_IS_EQUAL(chip3.dimension(3), 11);
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 7; ++k) {
|
||||
for (int l = 0; l < 11; ++l) {
|
||||
VERIFY_IS_EQUAL(chip3(i,j,k,l), tensor(i,j,2,k,l));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Tensor<float, 4, DataLayout> chip4(tensor.template chip<3>(5));
|
||||
VERIFY_IS_EQUAL(chip4.dimension(0), 2);
|
||||
VERIFY_IS_EQUAL(chip4.dimension(1), 3);
|
||||
VERIFY_IS_EQUAL(chip4.dimension(2), 5);
|
||||
VERIFY_IS_EQUAL(chip4.dimension(3), 11);
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 5; ++k) {
|
||||
for (int l = 0; l < 7; ++l) {
|
||||
VERIFY_IS_EQUAL(chip4(i,j,k,l), tensor(i,j,k,5,l));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Tensor<float, 4, DataLayout> chip5(tensor.template chip<4>(7));
|
||||
VERIFY_IS_EQUAL(chip5.dimension(0), 2);
|
||||
VERIFY_IS_EQUAL(chip5.dimension(1), 3);
|
||||
VERIFY_IS_EQUAL(chip5.dimension(2), 5);
|
||||
VERIFY_IS_EQUAL(chip5.dimension(3), 7);
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 5; ++k) {
|
||||
for (int l = 0; l < 7; ++l) {
|
||||
VERIFY_IS_EQUAL(chip5(i,j,k,l), tensor(i,j,k,l,7));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<int DataLayout>
|
||||
static void test_dynamic_chip()
|
||||
{
|
||||
Tensor<float, 5, DataLayout> tensor(2,3,5,7,11);
|
||||
tensor.setRandom();
|
||||
|
||||
Tensor<float, 4, DataLayout> chip1;
|
||||
chip1 = tensor.chip(1, 0);
|
||||
VERIFY_IS_EQUAL(chip1.dimension(0), 3);
|
||||
VERIFY_IS_EQUAL(chip1.dimension(1), 5);
|
||||
VERIFY_IS_EQUAL(chip1.dimension(2), 7);
|
||||
VERIFY_IS_EQUAL(chip1.dimension(3), 11);
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
for (int j = 0; j < 5; ++j) {
|
||||
for (int k = 0; k < 7; ++k) {
|
||||
for (int l = 0; l < 11; ++l) {
|
||||
VERIFY_IS_EQUAL(chip1(i,j,k,l), tensor(1,i,j,k,l));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Tensor<float, 4, DataLayout> chip2 = tensor.chip(1, 1);
|
||||
VERIFY_IS_EQUAL(chip2.dimension(0), 2);
|
||||
VERIFY_IS_EQUAL(chip2.dimension(1), 5);
|
||||
VERIFY_IS_EQUAL(chip2.dimension(2), 7);
|
||||
VERIFY_IS_EQUAL(chip2.dimension(3), 11);
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 7; ++k) {
|
||||
for (int l = 0; l < 11; ++l) {
|
||||
VERIFY_IS_EQUAL(chip2(i,j,k,l), tensor(i,1,j,k,l));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Tensor<float, 4, DataLayout> chip3 = tensor.chip(2, 2);
|
||||
VERIFY_IS_EQUAL(chip3.dimension(0), 2);
|
||||
VERIFY_IS_EQUAL(chip3.dimension(1), 3);
|
||||
VERIFY_IS_EQUAL(chip3.dimension(2), 7);
|
||||
VERIFY_IS_EQUAL(chip3.dimension(3), 11);
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 7; ++k) {
|
||||
for (int l = 0; l < 11; ++l) {
|
||||
VERIFY_IS_EQUAL(chip3(i,j,k,l), tensor(i,j,2,k,l));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Tensor<float, 4, DataLayout> chip4(tensor.chip(5, 3));
|
||||
VERIFY_IS_EQUAL(chip4.dimension(0), 2);
|
||||
VERIFY_IS_EQUAL(chip4.dimension(1), 3);
|
||||
VERIFY_IS_EQUAL(chip4.dimension(2), 5);
|
||||
VERIFY_IS_EQUAL(chip4.dimension(3), 11);
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 5; ++k) {
|
||||
for (int l = 0; l < 7; ++l) {
|
||||
VERIFY_IS_EQUAL(chip4(i,j,k,l), tensor(i,j,k,5,l));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Tensor<float, 4, DataLayout> chip5(tensor.chip(7, 4));
|
||||
VERIFY_IS_EQUAL(chip5.dimension(0), 2);
|
||||
VERIFY_IS_EQUAL(chip5.dimension(1), 3);
|
||||
VERIFY_IS_EQUAL(chip5.dimension(2), 5);
|
||||
VERIFY_IS_EQUAL(chip5.dimension(3), 7);
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 5; ++k) {
|
||||
for (int l = 0; l < 7; ++l) {
|
||||
VERIFY_IS_EQUAL(chip5(i,j,k,l), tensor(i,j,k,l,7));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<int DataLayout>
|
||||
static void test_chip_in_expr() {
|
||||
Tensor<float, 5, DataLayout> input1(2,3,5,7,11);
|
||||
input1.setRandom();
|
||||
Tensor<float, 4, DataLayout> input2(3,5,7,11);
|
||||
input2.setRandom();
|
||||
|
||||
Tensor<float, 4, DataLayout> result = input1.template chip<0>(0) + input2;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
for (int j = 0; j < 5; ++j) {
|
||||
for (int k = 0; k < 7; ++k) {
|
||||
for (int l = 0; l < 11; ++l) {
|
||||
float expected = input1(0,i,j,k,l) + input2(i,j,k,l);
|
||||
VERIFY_IS_EQUAL(result(i,j,k,l), expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Tensor<float, 3, DataLayout> input3(3,7,11);
|
||||
input3.setRandom();
|
||||
Tensor<float, 3, DataLayout> result2 = input1.template chip<0>(0).template chip<1>(2) + input3;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
for (int j = 0; j < 7; ++j) {
|
||||
for (int k = 0; k < 11; ++k) {
|
||||
float expected = input1(0,i,2,j,k) + input3(i,j,k);
|
||||
VERIFY_IS_EQUAL(result2(i,j,k), expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<int DataLayout>
|
||||
static void test_chip_as_lvalue()
|
||||
{
|
||||
Tensor<float, 5, DataLayout> input1(2,3,5,7,11);
|
||||
input1.setRandom();
|
||||
|
||||
Tensor<float, 4, DataLayout> input2(3,5,7,11);
|
||||
input2.setRandom();
|
||||
Tensor<float, 5, DataLayout> tensor = input1;
|
||||
tensor.template chip<0>(1) = input2;
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 5; ++k) {
|
||||
for (int l = 0; l < 7; ++l) {
|
||||
for (int m = 0; m < 11; ++m) {
|
||||
if (i != 1) {
|
||||
VERIFY_IS_EQUAL(tensor(i,j,k,l,m), input1(i,j,k,l,m));
|
||||
} else {
|
||||
VERIFY_IS_EQUAL(tensor(i,j,k,l,m), input2(j,k,l,m));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Tensor<float, 4, DataLayout> input3(2,5,7,11);
|
||||
input3.setRandom();
|
||||
tensor = input1;
|
||||
tensor.template chip<1>(1) = input3;
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 5; ++k) {
|
||||
for (int l = 0; l < 7; ++l) {
|
||||
for (int m = 0; m < 11; ++m) {
|
||||
if (j != 1) {
|
||||
VERIFY_IS_EQUAL(tensor(i,j,k,l,m), input1(i,j,k,l,m));
|
||||
} else {
|
||||
VERIFY_IS_EQUAL(tensor(i,j,k,l,m), input3(i,k,l,m));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Tensor<float, 4, DataLayout> input4(2,3,7,11);
|
||||
input4.setRandom();
|
||||
tensor = input1;
|
||||
tensor.template chip<2>(3) = input4;
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 5; ++k) {
|
||||
for (int l = 0; l < 7; ++l) {
|
||||
for (int m = 0; m < 11; ++m) {
|
||||
if (k != 3) {
|
||||
VERIFY_IS_EQUAL(tensor(i,j,k,l,m), input1(i,j,k,l,m));
|
||||
} else {
|
||||
VERIFY_IS_EQUAL(tensor(i,j,k,l,m), input4(i,j,l,m));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Tensor<float, 4, DataLayout> input5(2,3,5,11);
|
||||
input5.setRandom();
|
||||
tensor = input1;
|
||||
tensor.template chip<3>(4) = input5;
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 5; ++k) {
|
||||
for (int l = 0; l < 7; ++l) {
|
||||
for (int m = 0; m < 11; ++m) {
|
||||
if (l != 4) {
|
||||
VERIFY_IS_EQUAL(tensor(i,j,k,l,m), input1(i,j,k,l,m));
|
||||
} else {
|
||||
VERIFY_IS_EQUAL(tensor(i,j,k,l,m), input5(i,j,k,m));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Tensor<float, 4, DataLayout> input6(2,3,5,7);
|
||||
input6.setRandom();
|
||||
tensor = input1;
|
||||
tensor.template chip<4>(5) = input6;
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 5; ++k) {
|
||||
for (int l = 0; l < 7; ++l) {
|
||||
for (int m = 0; m < 11; ++m) {
|
||||
if (m != 5) {
|
||||
VERIFY_IS_EQUAL(tensor(i,j,k,l,m), input1(i,j,k,l,m));
|
||||
} else {
|
||||
VERIFY_IS_EQUAL(tensor(i,j,k,l,m), input6(i,j,k,l));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Tensor<float, 5, DataLayout> input7(2,3,5,7,11);
|
||||
input7.setRandom();
|
||||
tensor = input1;
|
||||
tensor.chip(0, 0) = input7.chip(0, 0);
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 5; ++k) {
|
||||
for (int l = 0; l < 7; ++l) {
|
||||
for (int m = 0; m < 11; ++m) {
|
||||
if (i != 0) {
|
||||
VERIFY_IS_EQUAL(tensor(i,j,k,l,m), input1(i,j,k,l,m));
|
||||
} else {
|
||||
VERIFY_IS_EQUAL(tensor(i,j,k,l,m), input7(i,j,k,l,m));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<int DataLayout>
|
||||
static void test_chip_raw_data()
|
||||
{
|
||||
Tensor<float, 5, DataLayout> tensor(2,3,5,7,11);
|
||||
tensor.setRandom();
|
||||
|
||||
typedef TensorEvaluator<decltype(tensor.template chip<4>(3)), DefaultDevice> Evaluator4;
|
||||
auto chip = Evaluator4(tensor.template chip<4>(3), DefaultDevice());
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 5; ++k) {
|
||||
for (int l = 0; l < 7; ++l) {
|
||||
int chip_index;
|
||||
if (DataLayout == ColMajor) {
|
||||
chip_index = i + 2 * (j + 3 * (k + 5 * l));
|
||||
} else {
|
||||
chip_index = 11 * (l + 7 * (k + 5 * (j + 3 * i)));
|
||||
}
|
||||
VERIFY_IS_EQUAL(chip.data()[chip_index], tensor(i,j,k,l,3));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef TensorEvaluator<decltype(tensor.template chip<0>(0)), DefaultDevice> Evaluator0;
|
||||
auto chip0 = Evaluator0(tensor.template chip<0>(0), DefaultDevice());
|
||||
VERIFY_IS_EQUAL(chip0.data(), static_cast<float*>(0));
|
||||
|
||||
typedef TensorEvaluator<decltype(tensor.template chip<1>(0)), DefaultDevice> Evaluator1;
|
||||
auto chip1 = Evaluator1(tensor.template chip<1>(0), DefaultDevice());
|
||||
VERIFY_IS_EQUAL(chip1.data(), static_cast<float*>(0));
|
||||
|
||||
typedef TensorEvaluator<decltype(tensor.template chip<2>(0)), DefaultDevice> Evaluator2;
|
||||
auto chip2 = Evaluator2(tensor.template chip<2>(0), DefaultDevice());
|
||||
VERIFY_IS_EQUAL(chip2.data(), static_cast<float*>(0));
|
||||
|
||||
typedef TensorEvaluator<decltype(tensor.template chip<3>(0)), DefaultDevice> Evaluator3;
|
||||
auto chip3 = Evaluator3(tensor.template chip<3>(0), DefaultDevice());
|
||||
VERIFY_IS_EQUAL(chip3.data(), static_cast<float*>(0));
|
||||
}
|
||||
|
||||
void test_cxx11_tensor_chipping()
|
||||
{
|
||||
CALL_SUBTEST(test_simple_chip<ColMajor>());
|
||||
CALL_SUBTEST(test_simple_chip<RowMajor>());
|
||||
CALL_SUBTEST(test_dynamic_chip<ColMajor>());
|
||||
CALL_SUBTEST(test_dynamic_chip<RowMajor>());
|
||||
CALL_SUBTEST(test_chip_in_expr<ColMajor>());
|
||||
CALL_SUBTEST(test_chip_in_expr<RowMajor>());
|
||||
CALL_SUBTEST(test_chip_as_lvalue<ColMajor>());
|
||||
CALL_SUBTEST(test_chip_as_lvalue<RowMajor>());
|
||||
CALL_SUBTEST(test_chip_raw_data<ColMajor>());
|
||||
CALL_SUBTEST(test_chip_raw_data<RowMajor>());
|
||||
}
|
||||
84
unsupported/test/cxx11_tensor_comparisons.cpp
Normal file
84
unsupported/test/cxx11_tensor_comparisons.cpp
Normal file
@@ -0,0 +1,84 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#include <Eigen/CXX11/Tensor>
|
||||
|
||||
using Eigen::Tensor;
|
||||
using Eigen::RowMajor;
|
||||
|
||||
static void test_orderings()
|
||||
{
|
||||
Tensor<float, 3> mat1(2,3,7);
|
||||
Tensor<float, 3> mat2(2,3,7);
|
||||
Tensor<bool, 3> lt(2,3,7);
|
||||
Tensor<bool, 3> le(2,3,7);
|
||||
Tensor<bool, 3> gt(2,3,7);
|
||||
Tensor<bool, 3> ge(2,3,7);
|
||||
|
||||
mat1.setRandom();
|
||||
mat2.setRandom();
|
||||
|
||||
lt = mat1 < mat2;
|
||||
le = mat1 <= mat2;
|
||||
gt = mat1 > mat2;
|
||||
ge = mat1 >= mat2;
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 7; ++k) {
|
||||
VERIFY_IS_EQUAL(lt(i,j,k), mat1(i,j,k) < mat2(i,j,k));
|
||||
VERIFY_IS_EQUAL(le(i,j,k), mat1(i,j,k) <= mat2(i,j,k));
|
||||
VERIFY_IS_EQUAL(gt(i,j,k), mat1(i,j,k) > mat2(i,j,k));
|
||||
VERIFY_IS_EQUAL(ge(i,j,k), mat1(i,j,k) >= mat2(i,j,k));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void test_equality()
|
||||
{
|
||||
Tensor<float, 3> mat1(2,3,7);
|
||||
Tensor<float, 3> mat2(2,3,7);
|
||||
|
||||
mat1.setRandom();
|
||||
mat2.setRandom();
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 7; ++k) {
|
||||
if (random() < 0.5) {
|
||||
mat2(i,j,k) = mat1(i,j,k);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Tensor<bool, 3> eq(2,3,7);
|
||||
Tensor<bool, 3> ne(2,3,7);
|
||||
eq = (mat1 == mat2);
|
||||
ne = (mat1 != mat2);
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 7; ++k) {
|
||||
VERIFY_IS_EQUAL(eq(i,j,k), mat1(i,j,k) == mat2(i,j,k));
|
||||
VERIFY_IS_EQUAL(ne(i,j,k), mat1(i,j,k) != mat2(i,j,k));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void test_cxx11_tensor_comparisons()
|
||||
{
|
||||
CALL_SUBTEST(test_orderings());
|
||||
CALL_SUBTEST(test_equality());
|
||||
}
|
||||
116
unsupported/test/cxx11_tensor_concatenation.cpp
Normal file
116
unsupported/test/cxx11_tensor_concatenation.cpp
Normal file
@@ -0,0 +1,116 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#include <Eigen/CXX11/Tensor>
|
||||
|
||||
using Eigen::Tensor;
|
||||
|
||||
template<int DataLayout>
|
||||
static void test_dimension_failures()
|
||||
{
|
||||
Tensor<int, 3, DataLayout> left(2, 3, 1);
|
||||
Tensor<int, 3, DataLayout> right(3, 3, 1);
|
||||
left.setRandom();
|
||||
right.setRandom();
|
||||
|
||||
// Okay; other dimensions are equal.
|
||||
Tensor<int, 3, DataLayout> concatenation = left.concatenate(right, 0);
|
||||
|
||||
// Dimension mismatches.
|
||||
VERIFY_RAISES_ASSERT(concatenation = left.concatenate(right, 1));
|
||||
VERIFY_RAISES_ASSERT(concatenation = left.concatenate(right, 2));
|
||||
|
||||
// Axis > NumDims or < 0.
|
||||
VERIFY_RAISES_ASSERT(concatenation = left.concatenate(right, 3));
|
||||
VERIFY_RAISES_ASSERT(concatenation = left.concatenate(right, -1));
|
||||
}
|
||||
|
||||
template<int DataLayout>
|
||||
static void test_static_dimension_failure()
|
||||
{
|
||||
Tensor<int, 2, DataLayout> left(2, 3);
|
||||
Tensor<int, 3, DataLayout> right(2, 3, 1);
|
||||
|
||||
#ifdef CXX11_TENSOR_CONCATENATION_STATIC_DIMENSION_FAILURE
|
||||
// Technically compatible, but we static assert that the inputs have same
|
||||
// NumDims.
|
||||
Tensor<int, 3, DataLayout> concatenation = left.concatenate(right, 0);
|
||||
#endif
|
||||
|
||||
// This can be worked around in this case.
|
||||
Tensor<int, 3, DataLayout> concatenation = left
|
||||
.reshape(Tensor<int, 3>::Dimensions{{2, 3, 1}})
|
||||
.concatenate(right, 0);
|
||||
Tensor<int, 2, DataLayout> alternative = left
|
||||
.concatenate(right.reshape(Tensor<int, 2>::Dimensions{{2, 3}}), 0);
|
||||
}
|
||||
|
||||
template<int DataLayout>
|
||||
static void test_simple_concatenation()
|
||||
{
|
||||
Tensor<int, 3, DataLayout> left(2, 3, 1);
|
||||
Tensor<int, 3, DataLayout> right(2, 3, 1);
|
||||
left.setRandom();
|
||||
right.setRandom();
|
||||
|
||||
Tensor<int, 3, DataLayout> concatenation = left.concatenate(right, 0);
|
||||
VERIFY_IS_EQUAL(concatenation.dimension(0), 4);
|
||||
VERIFY_IS_EQUAL(concatenation.dimension(1), 3);
|
||||
VERIFY_IS_EQUAL(concatenation.dimension(2), 1);
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
VERIFY_IS_EQUAL(concatenation(i, j, 0), left(i, j, 0));
|
||||
}
|
||||
for (int i = 2; i < 4; ++i) {
|
||||
VERIFY_IS_EQUAL(concatenation(i, j, 0), right(i - 2, j, 0));
|
||||
}
|
||||
}
|
||||
|
||||
concatenation = left.concatenate(right, 1);
|
||||
VERIFY_IS_EQUAL(concatenation.dimension(0), 2);
|
||||
VERIFY_IS_EQUAL(concatenation.dimension(1), 6);
|
||||
VERIFY_IS_EQUAL(concatenation.dimension(2), 1);
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
VERIFY_IS_EQUAL(concatenation(i, j, 0), left(i, j, 0));
|
||||
}
|
||||
for (int j = 3; j < 6; ++j) {
|
||||
VERIFY_IS_EQUAL(concatenation(i, j, 0), right(i, j - 3, 0));
|
||||
}
|
||||
}
|
||||
|
||||
concatenation = left.concatenate(right, 2);
|
||||
VERIFY_IS_EQUAL(concatenation.dimension(0), 2);
|
||||
VERIFY_IS_EQUAL(concatenation.dimension(1), 3);
|
||||
VERIFY_IS_EQUAL(concatenation.dimension(2), 2);
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
VERIFY_IS_EQUAL(concatenation(i, j, 0), left(i, j, 0));
|
||||
VERIFY_IS_EQUAL(concatenation(i, j, 1), right(i, j, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TODO(phli): Add test once we have a real vectorized implementation.
|
||||
// static void test_vectorized_concatenation() {}
|
||||
|
||||
|
||||
void test_cxx11_tensor_concatenation()
|
||||
{
|
||||
CALL_SUBTEST(test_dimension_failures<ColMajor>());
|
||||
CALL_SUBTEST(test_dimension_failures<RowMajor>());
|
||||
CALL_SUBTEST(test_static_dimension_failure<ColMajor>());
|
||||
CALL_SUBTEST(test_static_dimension_failure<RowMajor>());
|
||||
CALL_SUBTEST(test_simple_concatenation<ColMajor>());
|
||||
CALL_SUBTEST(test_simple_concatenation<RowMajor>());
|
||||
// CALL_SUBTEST(test_vectorized_concatenation());
|
||||
}
|
||||
39
unsupported/test/cxx11_tensor_const.cpp
Normal file
39
unsupported/test/cxx11_tensor_const.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#include <Eigen/CXX11/Tensor>
|
||||
using Eigen::Tensor;
|
||||
|
||||
|
||||
|
||||
|
||||
static void test_simple_assign()
|
||||
{
|
||||
Tensor<int, 3> random(2,3,7);
|
||||
random.setRandom();
|
||||
|
||||
TensorMap<Tensor<const int, 3> > constant(random.data(), 2, 3, 7);
|
||||
Tensor<int, 3> result(2,3,7);
|
||||
result = constant;
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 7; ++k) {
|
||||
VERIFY_IS_EQUAL((result(i,j,k)), random(i,j,k));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test_cxx11_tensor_const()
|
||||
{
|
||||
CALL_SUBTEST(test_simple_assign());
|
||||
}
|
||||
121
unsupported/test/cxx11_tensor_contract_cuda.cpp
Normal file
121
unsupported/test/cxx11_tensor_contract_cuda.cpp
Normal file
@@ -0,0 +1,121 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
// Copyright (C) 2014 Navdeep Jaitly <ndjaitly@google.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#define EIGEN_TEST_NO_LONGDOUBLE
|
||||
#define EIGEN_TEST_NO_COMPLEX
|
||||
#define EIGEN_TEST_FUNC cxx11_tensor_cuda
|
||||
#define EIGEN_DEFAULT_DENSE_INDEX_TYPE int
|
||||
#define EIGEN_USE_GPU
|
||||
|
||||
|
||||
#include "main.h"
|
||||
#include <unsupported/Eigen/CXX11/Tensor>
|
||||
|
||||
using Eigen::Tensor;
|
||||
typedef Tensor<float, 1>::DimensionPair DimPair;
|
||||
|
||||
template<int DataLayout>
|
||||
static void test_cuda_contraction(int m_size, int k_size, int n_size)
|
||||
{
|
||||
cout<<"Calling with ("<<m_size<<","<<k_size<<","<<n_size<<")"<<std::endl;
|
||||
// with these dimensions, the output has 300 * 140 elements, which is
|
||||
// more than 30 * 1024, which is the number of threads in blocks on
|
||||
// a 15 SM GK110 GPU
|
||||
Tensor<float, 2, DataLayout> t_left(Eigen::array<int, 2>(m_size, k_size));
|
||||
Tensor<float, 2, DataLayout> t_right(Eigen::array<int, 2>(k_size, n_size));
|
||||
Tensor<float, 2, DataLayout> t_result(Eigen::array<int, 2>(m_size, n_size));
|
||||
Tensor<float, 2, DataLayout> t_result_gpu(Eigen::array<int, 2>(m_size, n_size));
|
||||
Eigen::array<DimPair, 1> dims(DimPair(1, 0));
|
||||
|
||||
t_left.setRandom();
|
||||
t_right.setRandom();
|
||||
|
||||
std::size_t t_left_bytes = t_left.size() * sizeof(float);
|
||||
std::size_t t_right_bytes = t_right.size() * sizeof(float);
|
||||
std::size_t t_result_bytes = t_result.size() * sizeof(float);
|
||||
|
||||
float* d_t_left;
|
||||
float* d_t_right;
|
||||
float* d_t_result;
|
||||
|
||||
cudaMalloc((void**)(&d_t_left), t_left_bytes);
|
||||
cudaMalloc((void**)(&d_t_right), t_right_bytes);
|
||||
cudaMalloc((void**)(&d_t_result), t_result_bytes);
|
||||
|
||||
cudaMemcpy(d_t_left, t_left.data(), t_left_bytes, cudaMemcpyHostToDevice);
|
||||
cudaMemcpy(d_t_right, t_right.data(), t_right_bytes, cudaMemcpyHostToDevice);
|
||||
|
||||
cudaStream_t stream;
|
||||
assert(cudaStreamCreate(&stream) == cudaSuccess);
|
||||
Eigen::GpuDevice gpu_device(&stream);
|
||||
|
||||
Eigen::TensorMap<Eigen::Tensor<float, 2, DataLayout> >
|
||||
gpu_t_left(d_t_left, Eigen::array<int, 2>(m_size, k_size));
|
||||
Eigen::TensorMap<Eigen::Tensor<float, 2, DataLayout> >
|
||||
gpu_t_right(d_t_right, Eigen::array<int, 2>(k_size, n_size));
|
||||
Eigen::TensorMap<Eigen::Tensor<float, 2, DataLayout> >
|
||||
gpu_t_result(d_t_result, Eigen::array<int, 2>(m_size, n_size));
|
||||
|
||||
|
||||
gpu_t_result.device(gpu_device) = gpu_t_left.contract(gpu_t_right, dims);
|
||||
t_result = t_left.contract(t_right, dims);
|
||||
|
||||
cudaMemcpy(t_result_gpu.data(), d_t_result, t_result_bytes, cudaMemcpyDeviceToHost);
|
||||
for (size_t i = 0; i < t_result.dimensions().TotalSize(); i++) {
|
||||
if (fabs(t_result.data()[i] - t_result_gpu.data()[i]) >= 1e-4) {
|
||||
cout << "mismatch detected at index " << i << ": " << t_result.data()[i]
|
||||
<< " vs " << t_result_gpu.data()[i] << endl;
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
cudaFree((void*)d_t_left);
|
||||
cudaFree((void*)d_t_right);
|
||||
cudaFree((void*)d_t_result);
|
||||
}
|
||||
|
||||
|
||||
void test_cxx11_tensor_cuda()
|
||||
{
|
||||
cout<<"Calling contraction tests"<<std::endl;
|
||||
CALL_SUBTEST(test_cuda_contraction<ColMajor>(128, 128, 128));
|
||||
CALL_SUBTEST(test_cuda_contraction<RowMajor>(128, 128, 128));
|
||||
for (int k = 32; k < 256; k++) {
|
||||
CALL_SUBTEST(test_cuda_contraction<ColMajor>(128, k, 128));
|
||||
CALL_SUBTEST(test_cuda_contraction<RowMajor>(128, k, 128));
|
||||
}
|
||||
for (int k = 32; k < 256; k++) {
|
||||
CALL_SUBTEST(test_cuda_contraction<ColMajor>(128, 128, k));
|
||||
CALL_SUBTEST(test_cuda_contraction<RowMajor>(128, 128, k));
|
||||
}
|
||||
for (int k = 32; k < 256; k++) {
|
||||
CALL_SUBTEST(test_cuda_contraction<ColMajor>(k, 128, 128));
|
||||
CALL_SUBTEST(test_cuda_contraction<RowMajor>(k, 128, 128));
|
||||
}
|
||||
|
||||
int m_sizes[] = {31, 39, 63, 64, 65,
|
||||
127, 129, 255, 257, 511,
|
||||
512, 513, 1023, 1024, 1025 };
|
||||
int n_sizes[] = {31, 39, 63, 64, 65,
|
||||
127, 129, 255, 257, 511,
|
||||
512, 513, 1023, 1024, 1025 };
|
||||
|
||||
int k_sizes[] = { 31, 39, 63, 64, 65,
|
||||
95, 96, 127, 129, 255,
|
||||
257, 511, 512, 513, 1023,
|
||||
1024, 1025};
|
||||
|
||||
for (int i = 0; i <15; i++)
|
||||
for (int j = 0; j < 15; j++)
|
||||
for (int k = 0; k < 17; k++) {
|
||||
CALL_SUBTEST(test_cuda_contraction<ColMajor>(m_sizes[i], n_sizes[j], k_sizes[k]));
|
||||
CALL_SUBTEST(test_cuda_contraction<RowMajor>(m_sizes[i], n_sizes[j], k_sizes[k]));
|
||||
}
|
||||
}
|
||||
480
unsupported/test/cxx11_tensor_contraction.cpp
Normal file
480
unsupported/test/cxx11_tensor_contraction.cpp
Normal file
@@ -0,0 +1,480 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#include <Eigen/CXX11/Tensor>
|
||||
|
||||
using Eigen::DefaultDevice;
|
||||
using Eigen::Tensor;
|
||||
|
||||
typedef Tensor<float, 1>::DimensionPair DimPair;
|
||||
|
||||
template<int DataLayout>
|
||||
static void test_evals()
|
||||
{
|
||||
Tensor<float, 2, DataLayout> mat1(2, 3);
|
||||
Tensor<float, 2, DataLayout> mat2(2, 3);
|
||||
Tensor<float, 2, DataLayout> mat3(3, 2);
|
||||
|
||||
mat1.setRandom();
|
||||
mat2.setRandom();
|
||||
mat3.setRandom();
|
||||
|
||||
Tensor<float, 2, DataLayout> mat4(3,3);
|
||||
mat4.setZero();
|
||||
Eigen::array<DimPair, 1> dims3({{DimPair(0, 0)}});
|
||||
typedef TensorEvaluator<decltype(mat1.contract(mat2, dims3)), DefaultDevice> Evaluator;
|
||||
Evaluator eval(mat1.contract(mat2, dims3), DefaultDevice());
|
||||
eval.evalTo(mat4.data());
|
||||
EIGEN_STATIC_ASSERT(Evaluator::NumDims==2ul, YOU_MADE_A_PROGRAMMING_MISTAKE);
|
||||
VERIFY_IS_EQUAL(eval.dimensions()[0], 3);
|
||||
VERIFY_IS_EQUAL(eval.dimensions()[1], 3);
|
||||
|
||||
VERIFY_IS_APPROX(mat4(0,0), mat1(0,0)*mat2(0,0) + mat1(1,0)*mat2(1,0));
|
||||
VERIFY_IS_APPROX(mat4(0,1), mat1(0,0)*mat2(0,1) + mat1(1,0)*mat2(1,1));
|
||||
VERIFY_IS_APPROX(mat4(0,2), mat1(0,0)*mat2(0,2) + mat1(1,0)*mat2(1,2));
|
||||
VERIFY_IS_APPROX(mat4(1,0), mat1(0,1)*mat2(0,0) + mat1(1,1)*mat2(1,0));
|
||||
VERIFY_IS_APPROX(mat4(1,1), mat1(0,1)*mat2(0,1) + mat1(1,1)*mat2(1,1));
|
||||
VERIFY_IS_APPROX(mat4(1,2), mat1(0,1)*mat2(0,2) + mat1(1,1)*mat2(1,2));
|
||||
VERIFY_IS_APPROX(mat4(2,0), mat1(0,2)*mat2(0,0) + mat1(1,2)*mat2(1,0));
|
||||
VERIFY_IS_APPROX(mat4(2,1), mat1(0,2)*mat2(0,1) + mat1(1,2)*mat2(1,1));
|
||||
VERIFY_IS_APPROX(mat4(2,2), mat1(0,2)*mat2(0,2) + mat1(1,2)*mat2(1,2));
|
||||
|
||||
Tensor<float, 2, DataLayout> mat5(2,2);
|
||||
mat5.setZero();
|
||||
Eigen::array<DimPair, 1> dims4({{DimPair(1, 1)}});
|
||||
typedef TensorEvaluator<decltype(mat1.contract(mat2, dims4)), DefaultDevice> Evaluator2;
|
||||
Evaluator2 eval2(mat1.contract(mat2, dims4), DefaultDevice());
|
||||
eval2.evalTo(mat5.data());
|
||||
EIGEN_STATIC_ASSERT(Evaluator2::NumDims==2ul, YOU_MADE_A_PROGRAMMING_MISTAKE);
|
||||
VERIFY_IS_EQUAL(eval2.dimensions()[0], 2);
|
||||
VERIFY_IS_EQUAL(eval2.dimensions()[1], 2);
|
||||
|
||||
VERIFY_IS_APPROX(mat5(0,0), mat1(0,0)*mat2(0,0) + mat1(0,1)*mat2(0,1) + mat1(0,2)*mat2(0,2));
|
||||
VERIFY_IS_APPROX(mat5(0,1), mat1(0,0)*mat2(1,0) + mat1(0,1)*mat2(1,1) + mat1(0,2)*mat2(1,2));
|
||||
VERIFY_IS_APPROX(mat5(1,0), mat1(1,0)*mat2(0,0) + mat1(1,1)*mat2(0,1) + mat1(1,2)*mat2(0,2));
|
||||
VERIFY_IS_APPROX(mat5(1,1), mat1(1,0)*mat2(1,0) + mat1(1,1)*mat2(1,1) + mat1(1,2)*mat2(1,2));
|
||||
|
||||
Tensor<float, 2, DataLayout> mat6(2,2);
|
||||
mat6.setZero();
|
||||
Eigen::array<DimPair, 1> dims6({{DimPair(1, 0)}});
|
||||
typedef TensorEvaluator<decltype(mat1.contract(mat3, dims6)), DefaultDevice> Evaluator3;
|
||||
Evaluator3 eval3(mat1.contract(mat3, dims6), DefaultDevice());
|
||||
eval3.evalTo(mat6.data());
|
||||
EIGEN_STATIC_ASSERT(Evaluator3::NumDims==2ul, YOU_MADE_A_PROGRAMMING_MISTAKE);
|
||||
VERIFY_IS_EQUAL(eval3.dimensions()[0], 2);
|
||||
VERIFY_IS_EQUAL(eval3.dimensions()[1], 2);
|
||||
|
||||
VERIFY_IS_APPROX(mat6(0,0), mat1(0,0)*mat3(0,0) + mat1(0,1)*mat3(1,0) + mat1(0,2)*mat3(2,0));
|
||||
VERIFY_IS_APPROX(mat6(0,1), mat1(0,0)*mat3(0,1) + mat1(0,1)*mat3(1,1) + mat1(0,2)*mat3(2,1));
|
||||
VERIFY_IS_APPROX(mat6(1,0), mat1(1,0)*mat3(0,0) + mat1(1,1)*mat3(1,0) + mat1(1,2)*mat3(2,0));
|
||||
VERIFY_IS_APPROX(mat6(1,1), mat1(1,0)*mat3(0,1) + mat1(1,1)*mat3(1,1) + mat1(1,2)*mat3(2,1));
|
||||
}
|
||||
|
||||
template<int DataLayout>
|
||||
static void test_scalar()
|
||||
{
|
||||
Tensor<float, 1, DataLayout> vec1({6});
|
||||
Tensor<float, 1, DataLayout> vec2({6});
|
||||
|
||||
vec1.setRandom();
|
||||
vec2.setRandom();
|
||||
|
||||
Tensor<float, 1, DataLayout> scalar(1);
|
||||
scalar.setZero();
|
||||
Eigen::array<DimPair, 1> dims({{DimPair(0, 0)}});
|
||||
typedef TensorEvaluator<decltype(vec1.contract(vec2, dims)), DefaultDevice> Evaluator;
|
||||
Evaluator eval(vec1.contract(vec2, dims), DefaultDevice());
|
||||
eval.evalTo(scalar.data());
|
||||
EIGEN_STATIC_ASSERT(Evaluator::NumDims==1ul, YOU_MADE_A_PROGRAMMING_MISTAKE);
|
||||
|
||||
float expected = 0.0f;
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
expected += vec1(i) * vec2(i);
|
||||
}
|
||||
VERIFY_IS_APPROX(scalar(0), expected);
|
||||
}
|
||||
|
||||
template<int DataLayout>
|
||||
static void test_multidims()
|
||||
{
|
||||
Tensor<float, 3, DataLayout> mat1(2, 2, 2);
|
||||
Tensor<float, 4, DataLayout> mat2(2, 2, 2, 2);
|
||||
|
||||
mat1.setRandom();
|
||||
mat2.setRandom();
|
||||
|
||||
Tensor<float, 3, DataLayout> mat3(2, 2, 2);
|
||||
mat3.setZero();
|
||||
Eigen::array<DimPair, 2> dims({{DimPair(1, 2), DimPair(2, 3)}});
|
||||
typedef TensorEvaluator<decltype(mat1.contract(mat2, dims)), DefaultDevice> Evaluator;
|
||||
Evaluator eval(mat1.contract(mat2, dims), DefaultDevice());
|
||||
eval.evalTo(mat3.data());
|
||||
EIGEN_STATIC_ASSERT(Evaluator::NumDims==3ul, YOU_MADE_A_PROGRAMMING_MISTAKE);
|
||||
VERIFY_IS_EQUAL(eval.dimensions()[0], 2);
|
||||
VERIFY_IS_EQUAL(eval.dimensions()[1], 2);
|
||||
VERIFY_IS_EQUAL(eval.dimensions()[2], 2);
|
||||
|
||||
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) +
|
||||
mat1(0,0,1)*mat2(0,0,0,1) + mat1(0,1,1)*mat2(0,0,1,1));
|
||||
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) +
|
||||
mat1(0,0,1)*mat2(0,1,0,1) + mat1(0,1,1)*mat2(0,1,1,1));
|
||||
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) +
|
||||
mat1(0,0,1)*mat2(1,0,0,1) + mat1(0,1,1)*mat2(1,0,1,1));
|
||||
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) +
|
||||
mat1(0,0,1)*mat2(1,1,0,1) + mat1(0,1,1)*mat2(1,1,1,1));
|
||||
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) +
|
||||
mat1(1,0,1)*mat2(0,0,0,1) + mat1(1,1,1)*mat2(0,0,1,1));
|
||||
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) +
|
||||
mat1(1,0,1)*mat2(0,1,0,1) + mat1(1,1,1)*mat2(0,1,1,1));
|
||||
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) +
|
||||
mat1(1,0,1)*mat2(1,0,0,1) + mat1(1,1,1)*mat2(1,0,1,1));
|
||||
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) +
|
||||
mat1(1,0,1)*mat2(1,1,0,1) + mat1(1,1,1)*mat2(1,1,1,1));
|
||||
}
|
||||
|
||||
template<int DataLayout>
|
||||
static void test_holes() {
|
||||
Tensor<float, 4, DataLayout> t1(2, 5, 7, 3);
|
||||
Tensor<float, 5, DataLayout> t2(2, 7, 11, 13, 3);
|
||||
t1.setRandom();
|
||||
t2.setRandom();
|
||||
|
||||
Eigen::array<DimPair, 2> dims({{DimPair(0, 0), DimPair(3, 4)}});
|
||||
Tensor<float, 5, DataLayout> result = t1.contract(t2, dims);
|
||||
VERIFY_IS_EQUAL(result.dimension(0), 5);
|
||||
VERIFY_IS_EQUAL(result.dimension(1), 7);
|
||||
VERIFY_IS_EQUAL(result.dimension(2), 7);
|
||||
VERIFY_IS_EQUAL(result.dimension(3), 11);
|
||||
VERIFY_IS_EQUAL(result.dimension(4), 13);
|
||||
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
for (int j = 0; j < 5; ++j) {
|
||||
for (int k = 0; k < 5; ++k) {
|
||||
for (int l = 0; l < 5; ++l) {
|
||||
for (int m = 0; m < 5; ++m) {
|
||||
VERIFY_IS_APPROX(result(i, j, k, l, m),
|
||||
t1(0, i, j, 0) * t2(0, k, l, m, 0) +
|
||||
t1(1, i, j, 0) * t2(1, k, l, m, 0) +
|
||||
t1(0, i, j, 1) * t2(0, k, l, m, 1) +
|
||||
t1(1, i, j, 1) * t2(1, k, l, m, 1) +
|
||||
t1(0, i, j, 2) * t2(0, k, l, m, 2) +
|
||||
t1(1, i, j, 2) * t2(1, k, l, m, 2));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<int DataLayout>
|
||||
static void test_full_redux()
|
||||
{
|
||||
Tensor<float, 2, DataLayout> t1(2, 2);
|
||||
Tensor<float, 3, DataLayout> t2(2, 2, 2);
|
||||
t1.setRandom();
|
||||
t2.setRandom();
|
||||
|
||||
Eigen::array<DimPair, 2> dims({{DimPair(0, 0), DimPair(1, 1)}});
|
||||
Tensor<float, 1, DataLayout> result = t1.contract(t2, dims);
|
||||
VERIFY_IS_EQUAL(result.dimension(0), 2);
|
||||
VERIFY_IS_APPROX(result(0), 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));
|
||||
VERIFY_IS_APPROX(result(1), 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));
|
||||
|
||||
dims[0] = DimPair(1, 0);
|
||||
dims[1] = DimPair(2, 1);
|
||||
result = t2.contract(t1, dims);
|
||||
VERIFY_IS_EQUAL(result.dimension(0), 2);
|
||||
VERIFY_IS_APPROX(result(0), 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));
|
||||
VERIFY_IS_APPROX(result(1), 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));
|
||||
}
|
||||
|
||||
template<int DataLayout>
|
||||
static void test_contraction_of_contraction()
|
||||
{
|
||||
Tensor<float, 2, DataLayout> t1(2, 2);
|
||||
Tensor<float, 2, DataLayout> t2(2, 2);
|
||||
Tensor<float, 2, DataLayout> t3(2, 2);
|
||||
Tensor<float, 2, DataLayout> t4(2, 2);
|
||||
t1.setRandom();
|
||||
t2.setRandom();
|
||||
t3.setRandom();
|
||||
t4.setRandom();
|
||||
|
||||
Eigen::array<DimPair, 1> dims({{DimPair(1, 0)}});
|
||||
auto contract1 = t1.contract(t2, dims);
|
||||
auto diff = t3 - contract1;
|
||||
auto contract2 = t1.contract(t4, dims);
|
||||
Tensor<float, 2, DataLayout> result = contract2.contract(diff, dims);
|
||||
|
||||
VERIFY_IS_EQUAL(result.dimension(0), 2);
|
||||
VERIFY_IS_EQUAL(result.dimension(1), 2);
|
||||
|
||||
Eigen::Map<Eigen::Matrix<float, Dynamic, Dynamic, DataLayout>>
|
||||
m1(t1.data(), 2, 2), m2(t2.data(), 2, 2), m3(t3.data(), 2, 2),
|
||||
m4(t4.data(), 2, 2);
|
||||
Eigen::Matrix<float, Dynamic, Dynamic, DataLayout>
|
||||
expected = (m1 * m4) * (m3 - m1 * m2);
|
||||
|
||||
VERIFY_IS_APPROX(result(0, 0), expected(0, 0));
|
||||
VERIFY_IS_APPROX(result(0, 1), expected(0, 1));
|
||||
VERIFY_IS_APPROX(result(1, 0), expected(1, 0));
|
||||
VERIFY_IS_APPROX(result(1, 1), expected(1, 1));
|
||||
}
|
||||
|
||||
template<int DataLayout>
|
||||
static void test_expr()
|
||||
{
|
||||
Tensor<float, 2, DataLayout> mat1(2, 3);
|
||||
Tensor<float, 2, DataLayout> mat2(3, 2);
|
||||
mat1.setRandom();
|
||||
mat2.setRandom();
|
||||
|
||||
Tensor<float, 2, DataLayout> mat3(2,2);
|
||||
|
||||
Eigen::array<DimPair, 1> dims({{DimPair(1, 0)}});
|
||||
mat3 = mat1.contract(mat2, dims);
|
||||
|
||||
VERIFY_IS_APPROX(mat3(0,0), mat1(0,0)*mat2(0,0) + mat1(0,1)*mat2(1,0) + mat1(0,2)*mat2(2,0));
|
||||
VERIFY_IS_APPROX(mat3(0,1), mat1(0,0)*mat2(0,1) + mat1(0,1)*mat2(1,1) + mat1(0,2)*mat2(2,1));
|
||||
VERIFY_IS_APPROX(mat3(1,0), mat1(1,0)*mat2(0,0) + mat1(1,1)*mat2(1,0) + mat1(1,2)*mat2(2,0));
|
||||
VERIFY_IS_APPROX(mat3(1,1), mat1(1,0)*mat2(0,1) + mat1(1,1)*mat2(1,1) + mat1(1,2)*mat2(2,1));
|
||||
}
|
||||
|
||||
template<int DataLayout>
|
||||
static void test_out_of_order_contraction()
|
||||
{
|
||||
Tensor<float, 3, DataLayout> mat1(2, 2, 2);
|
||||
Tensor<float, 3, DataLayout> mat2(2, 2, 2);
|
||||
|
||||
mat1.setRandom();
|
||||
mat2.setRandom();
|
||||
|
||||
Tensor<float, 2, DataLayout> mat3(2, 2);
|
||||
|
||||
Eigen::array<DimPair, 2> dims({{DimPair(2, 0), DimPair(0, 2)}});
|
||||
mat3 = mat1.contract(mat2, dims);
|
||||
|
||||
VERIFY_IS_APPROX(mat3(0, 0),
|
||||
mat1(0,0,0)*mat2(0,0,0) + mat1(1,0,0)*mat2(0,0,1) +
|
||||
mat1(0,0,1)*mat2(1,0,0) + mat1(1,0,1)*mat2(1,0,1));
|
||||
VERIFY_IS_APPROX(mat3(1, 0),
|
||||
mat1(0,1,0)*mat2(0,0,0) + mat1(1,1,0)*mat2(0,0,1) +
|
||||
mat1(0,1,1)*mat2(1,0,0) + mat1(1,1,1)*mat2(1,0,1));
|
||||
VERIFY_IS_APPROX(mat3(0, 1),
|
||||
mat1(0,0,0)*mat2(0,1,0) + mat1(1,0,0)*mat2(0,1,1) +
|
||||
mat1(0,0,1)*mat2(1,1,0) + mat1(1,0,1)*mat2(1,1,1));
|
||||
VERIFY_IS_APPROX(mat3(1, 1),
|
||||
mat1(0,1,0)*mat2(0,1,0) + mat1(1,1,0)*mat2(0,1,1) +
|
||||
mat1(0,1,1)*mat2(1,1,0) + mat1(1,1,1)*mat2(1,1,1));
|
||||
|
||||
Eigen::array<DimPair, 2> dims2({{DimPair(0, 2), DimPair(2, 0)}});
|
||||
mat3 = mat1.contract(mat2, dims2);
|
||||
|
||||
VERIFY_IS_APPROX(mat3(0, 0),
|
||||
mat1(0,0,0)*mat2(0,0,0) + mat1(1,0,0)*mat2(0,0,1) +
|
||||
mat1(0,0,1)*mat2(1,0,0) + mat1(1,0,1)*mat2(1,0,1));
|
||||
VERIFY_IS_APPROX(mat3(1, 0),
|
||||
mat1(0,1,0)*mat2(0,0,0) + mat1(1,1,0)*mat2(0,0,1) +
|
||||
mat1(0,1,1)*mat2(1,0,0) + mat1(1,1,1)*mat2(1,0,1));
|
||||
VERIFY_IS_APPROX(mat3(0, 1),
|
||||
mat1(0,0,0)*mat2(0,1,0) + mat1(1,0,0)*mat2(0,1,1) +
|
||||
mat1(0,0,1)*mat2(1,1,0) + mat1(1,0,1)*mat2(1,1,1));
|
||||
VERIFY_IS_APPROX(mat3(1, 1),
|
||||
mat1(0,1,0)*mat2(0,1,0) + mat1(1,1,0)*mat2(0,1,1) +
|
||||
mat1(0,1,1)*mat2(1,1,0) + mat1(1,1,1)*mat2(1,1,1));
|
||||
|
||||
}
|
||||
|
||||
template<int DataLayout>
|
||||
static void test_consistency()
|
||||
{
|
||||
// this does something like testing (A*B)^T = (B^T * A^T)
|
||||
|
||||
Tensor<float, 3, DataLayout> mat1(4, 3, 5);
|
||||
Tensor<float, 5, DataLayout> mat2(3, 2, 1, 5, 4);
|
||||
mat1.setRandom();
|
||||
mat2.setRandom();
|
||||
|
||||
Tensor<float, 4, DataLayout> mat3(5, 2, 1, 5);
|
||||
Tensor<float, 4, DataLayout> mat4(2, 1, 5, 5);
|
||||
|
||||
// contract on dimensions of size 4 and 3
|
||||
Eigen::array<DimPair, 2> dims1({{DimPair(0, 4), DimPair(1, 0)}});
|
||||
Eigen::array<DimPair, 2> dims2({{DimPair(4, 0), DimPair(0, 1)}});
|
||||
|
||||
mat3 = mat1.contract(mat2, dims1);
|
||||
mat4 = mat2.contract(mat1, dims2);
|
||||
|
||||
// check that these are equal except for ordering of dimensions
|
||||
if (DataLayout == ColMajor) {
|
||||
for (size_t i = 0; i < 5; i++) {
|
||||
for (size_t j = 0; j < 10; j++) {
|
||||
VERIFY_IS_APPROX(mat3.data()[i + 5 * j], mat4.data()[j + 10 * i]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Row major
|
||||
for (size_t i = 0; i < 5; i++) {
|
||||
for (size_t j = 0; j < 10; j++) {
|
||||
VERIFY_IS_APPROX(mat3.data()[10 * i + j], mat4.data()[i + 5 * j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<int DataLayout>
|
||||
static void test_large_contraction()
|
||||
{
|
||||
Tensor<float, 4, DataLayout> t_left(30, 50, 8, 31);
|
||||
Tensor<float, 5, DataLayout> t_right(8, 31, 7, 20, 10);
|
||||
Tensor<float, 5, DataLayout> t_result(30, 50, 7, 20, 10);
|
||||
|
||||
t_left.setRandom();
|
||||
t_right.setRandom();
|
||||
|
||||
// Add a little offset so that the results won't be close to zero.
|
||||
t_left += t_left.constant(1.0f);
|
||||
t_right += t_right.constant(1.0f);
|
||||
|
||||
typedef Map<Eigen::Matrix<float, Dynamic, Dynamic, DataLayout>> MapXf;
|
||||
MapXf m_left(t_left.data(), 1500, 248);
|
||||
MapXf m_right(t_right.data(), 248, 1400);
|
||||
Eigen::Matrix<float, Dynamic, Dynamic, DataLayout> m_result(1500, 1400);
|
||||
|
||||
// this contraction should be equivalent to a single matrix multiplication
|
||||
Eigen::array<DimPair, 2> dims({{DimPair(2, 0), DimPair(3, 1)}});
|
||||
|
||||
// compute results by separate methods
|
||||
t_result = t_left.contract(t_right, dims);
|
||||
m_result = m_left * m_right;
|
||||
|
||||
for (size_t i = 0; i < t_result.dimensions().TotalSize(); i++) {
|
||||
VERIFY(&t_result.data()[i] != &m_result.data()[i]);
|
||||
VERIFY_IS_APPROX(t_result.data()[i], m_result.data()[i]);
|
||||
}
|
||||
}
|
||||
|
||||
template<int DataLayout>
|
||||
static void test_matrix_vector()
|
||||
{
|
||||
Tensor<float, 2, DataLayout> t_left(30, 50);
|
||||
Tensor<float, 1, DataLayout> t_right(50);
|
||||
Tensor<float, 1, DataLayout> t_result(30);
|
||||
|
||||
t_left.setRandom();
|
||||
t_right.setRandom();
|
||||
|
||||
typedef Map<Eigen::Matrix<float, Dynamic, Dynamic, DataLayout>> MapXf;
|
||||
MapXf m_left(t_left.data(), 30, 50);
|
||||
MapXf m_right(t_right.data(), 50, 1);
|
||||
Eigen::Matrix<float, Dynamic, Dynamic, DataLayout> m_result(30, 1);
|
||||
|
||||
// this contraction should be equivalent to a single matrix multiplication
|
||||
Eigen::array<DimPair, 1> dims{{DimPair(1, 0)}};
|
||||
|
||||
// compute results by separate methods
|
||||
t_result = t_left.contract(t_right, dims);
|
||||
m_result = m_left * m_right;
|
||||
|
||||
for (size_t i = 0; i < t_result.dimensions().TotalSize(); i++) {
|
||||
VERIFY(internal::isApprox(t_result(i), m_result(i, 0), 1));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<int DataLayout>
|
||||
static void test_tensor_vector()
|
||||
{
|
||||
Tensor<float, 3, DataLayout> t_left(7, 13, 17);
|
||||
Tensor<float, 2, DataLayout> t_right(1, 7);
|
||||
|
||||
t_left.setRandom();
|
||||
t_right.setRandom();
|
||||
|
||||
typedef typename Tensor<float, 1, DataLayout>::DimensionPair DimensionPair;
|
||||
Eigen::array<DimensionPair, 1> dim_pair01{{{0, 1}}};
|
||||
Tensor<float, 3, DataLayout> t_result = t_left.contract(t_right, dim_pair01);
|
||||
|
||||
typedef Map<Eigen::Matrix<float, Dynamic, Dynamic, DataLayout>> MapXf;
|
||||
MapXf m_left(t_left.data(), 7, 13*17);
|
||||
MapXf m_right(t_right.data(), 1, 7);
|
||||
Eigen::Matrix<float, Dynamic, Dynamic, DataLayout> m_result = m_left.transpose() * m_right.transpose();
|
||||
|
||||
for (size_t i = 0; i < t_result.dimensions().TotalSize(); i++) {
|
||||
VERIFY(internal::isApprox(t_result(i), m_result(i, 0), 1));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<int DataLayout>
|
||||
static void test_small_blocking_factors()
|
||||
{
|
||||
Tensor<float, 4, DataLayout> t_left(30, 5, 3, 31);
|
||||
Tensor<float, 5, DataLayout> t_right(3, 31, 7, 20, 1);
|
||||
t_left.setRandom();
|
||||
t_right.setRandom();
|
||||
|
||||
// Add a little offset so that the results won't be close to zero.
|
||||
t_left += t_left.constant(1.0f);
|
||||
t_right += t_right.constant(1.0f);
|
||||
|
||||
// Force the cache sizes, which results in smaller blocking factors.
|
||||
Eigen::setCpuCacheSizes(896, 1920, 2944);
|
||||
|
||||
// this contraction should be equivalent to a single matrix multiplication
|
||||
Eigen::array<DimPair, 2> dims({{DimPair(2, 0), DimPair(3, 1)}});
|
||||
Tensor<float, 5, DataLayout> t_result;
|
||||
t_result = t_left.contract(t_right, dims);
|
||||
|
||||
// compute result using a simple eigen matrix product
|
||||
Map<Eigen::Matrix<float, Dynamic, Dynamic, DataLayout>> m_left(t_left.data(), 150, 93);
|
||||
Map<Eigen::Matrix<float, Dynamic, Dynamic, DataLayout>> m_right(t_right.data(), 93, 140);
|
||||
Eigen::Matrix<float, Dynamic, Dynamic, DataLayout> m_result = m_left * m_right;
|
||||
|
||||
for (size_t i = 0; i < t_result.dimensions().TotalSize(); i++) {
|
||||
VERIFY_IS_APPROX(t_result.data()[i], m_result.data()[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void test_cxx11_tensor_contraction()
|
||||
{
|
||||
CALL_SUBTEST(test_evals<ColMajor>());
|
||||
CALL_SUBTEST(test_evals<RowMajor>());
|
||||
CALL_SUBTEST(test_scalar<ColMajor>());
|
||||
CALL_SUBTEST(test_scalar<RowMajor>());
|
||||
CALL_SUBTEST(test_multidims<ColMajor>());
|
||||
CALL_SUBTEST(test_multidims<RowMajor>());
|
||||
CALL_SUBTEST(test_holes<ColMajor>());
|
||||
CALL_SUBTEST(test_holes<RowMajor>());
|
||||
CALL_SUBTEST(test_full_redux<ColMajor>());
|
||||
CALL_SUBTEST(test_full_redux<RowMajor>());
|
||||
CALL_SUBTEST(test_contraction_of_contraction<ColMajor>());
|
||||
CALL_SUBTEST(test_contraction_of_contraction<RowMajor>());
|
||||
CALL_SUBTEST(test_expr<ColMajor>());
|
||||
CALL_SUBTEST(test_expr<RowMajor>());
|
||||
CALL_SUBTEST(test_out_of_order_contraction<ColMajor>());
|
||||
CALL_SUBTEST(test_out_of_order_contraction<RowMajor>());
|
||||
CALL_SUBTEST(test_consistency<ColMajor>());
|
||||
CALL_SUBTEST(test_consistency<RowMajor>());
|
||||
CALL_SUBTEST(test_large_contraction<ColMajor>());
|
||||
CALL_SUBTEST(test_large_contraction<RowMajor>());
|
||||
CALL_SUBTEST(test_matrix_vector<ColMajor>());
|
||||
CALL_SUBTEST(test_matrix_vector<RowMajor>());
|
||||
CALL_SUBTEST(test_tensor_vector<ColMajor>());
|
||||
CALL_SUBTEST(test_tensor_vector<RowMajor>());
|
||||
CALL_SUBTEST(test_small_blocking_factors<ColMajor>());
|
||||
CALL_SUBTEST(test_small_blocking_factors<RowMajor>());
|
||||
}
|
||||
141
unsupported/test/cxx11_tensor_convolution.cpp
Normal file
141
unsupported/test/cxx11_tensor_convolution.cpp
Normal file
@@ -0,0 +1,141 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#include <Eigen/CXX11/Tensor>
|
||||
|
||||
using Eigen::Tensor;
|
||||
using Eigen::DefaultDevice;
|
||||
|
||||
static void test_evals()
|
||||
{
|
||||
Tensor<float, 2> input(3, 3);
|
||||
Tensor<float, 1> kernel(2);
|
||||
|
||||
input.setRandom();
|
||||
kernel.setRandom();
|
||||
|
||||
Tensor<float, 2> result(2,3);
|
||||
result.setZero();
|
||||
Eigen::array<Tensor<float, 2>::Index, 1> dims3({0});
|
||||
|
||||
typedef TensorEvaluator<decltype(input.convolve(kernel, dims3)), DefaultDevice> Evaluator;
|
||||
Evaluator eval(input.convolve(kernel, dims3), DefaultDevice());
|
||||
eval.evalTo(result.data());
|
||||
EIGEN_STATIC_ASSERT(Evaluator::NumDims==2ul, YOU_MADE_A_PROGRAMMING_MISTAKE);
|
||||
VERIFY_IS_EQUAL(eval.dimensions()[0], 2);
|
||||
VERIFY_IS_EQUAL(eval.dimensions()[1], 3);
|
||||
|
||||
VERIFY_IS_APPROX(result(0,0), input(0,0)*kernel(0) + input(1,0)*kernel(1)); // index 0
|
||||
VERIFY_IS_APPROX(result(0,1), input(0,1)*kernel(0) + input(1,1)*kernel(1)); // index 2
|
||||
VERIFY_IS_APPROX(result(0,2), input(0,2)*kernel(0) + input(1,2)*kernel(1)); // index 4
|
||||
VERIFY_IS_APPROX(result(1,0), input(1,0)*kernel(0) + input(2,0)*kernel(1)); // index 1
|
||||
VERIFY_IS_APPROX(result(1,1), input(1,1)*kernel(0) + input(2,1)*kernel(1)); // index 3
|
||||
VERIFY_IS_APPROX(result(1,2), input(1,2)*kernel(0) + input(2,2)*kernel(1)); // index 5
|
||||
}
|
||||
|
||||
|
||||
static void test_expr()
|
||||
{
|
||||
Tensor<float, 2> input(3, 3);
|
||||
Tensor<float, 2> kernel(2, 2);
|
||||
input.setRandom();
|
||||
kernel.setRandom();
|
||||
|
||||
Tensor<float, 2> result(2,2);
|
||||
Eigen::array<ptrdiff_t, 2> dims({0, 1});
|
||||
result = input.convolve(kernel, dims);
|
||||
|
||||
VERIFY_IS_APPROX(result(0,0), input(0,0)*kernel(0,0) + input(0,1)*kernel(0,1) +
|
||||
input(1,0)*kernel(1,0) + input(1,1)*kernel(1,1));
|
||||
VERIFY_IS_APPROX(result(0,1), input(0,1)*kernel(0,0) + input(0,2)*kernel(0,1) +
|
||||
input(1,1)*kernel(1,0) + input(1,2)*kernel(1,1));
|
||||
VERIFY_IS_APPROX(result(1,0), input(1,0)*kernel(0,0) + input(1,1)*kernel(0,1) +
|
||||
input(2,0)*kernel(1,0) + input(2,1)*kernel(1,1));
|
||||
VERIFY_IS_APPROX(result(1,1), input(1,1)*kernel(0,0) + input(1,2)*kernel(0,1) +
|
||||
input(2,1)*kernel(1,0) + input(2,2)*kernel(1,1));
|
||||
}
|
||||
|
||||
|
||||
static void test_modes() {
|
||||
Tensor<float, 1> input(3);
|
||||
Tensor<float, 1> kernel(3);
|
||||
input(0) = 1.0f;
|
||||
input(1) = 2.0f;
|
||||
input(2) = 3.0f;
|
||||
kernel(0) = 0.5f;
|
||||
kernel(1) = 1.0f;
|
||||
kernel(2) = 0.0f;
|
||||
|
||||
const Eigen::array<ptrdiff_t, 1> dims{{0}};
|
||||
Eigen::array<std::pair<ptrdiff_t, ptrdiff_t>, 1> padding;
|
||||
|
||||
// Emulate VALID mode (as defined in
|
||||
// http://docs.scipy.org/doc/numpy/reference/generated/numpy.convolve.html).
|
||||
padding[0] = std::make_pair(0, 0);
|
||||
Tensor<float, 1> valid(1);
|
||||
valid = input.pad(padding).convolve(kernel, dims);
|
||||
VERIFY_IS_EQUAL(valid.dimension(0), 1);
|
||||
VERIFY_IS_APPROX(valid(0), 2.5f);
|
||||
|
||||
// Emulate SAME mode (as defined in
|
||||
// http://docs.scipy.org/doc/numpy/reference/generated/numpy.convolve.html).
|
||||
padding[0] = std::make_pair(1, 1);
|
||||
Tensor<float, 1> same(3);
|
||||
same = input.pad(padding).convolve(kernel, dims);
|
||||
VERIFY_IS_EQUAL(same.dimension(0), 3);
|
||||
VERIFY_IS_APPROX(same(0), 1.0f);
|
||||
VERIFY_IS_APPROX(same(1), 2.5f);
|
||||
VERIFY_IS_APPROX(same(2), 4.0f);
|
||||
|
||||
// Emulate FULL mode (as defined in
|
||||
// http://docs.scipy.org/doc/numpy/reference/generated/numpy.convolve.html).
|
||||
padding[0] = std::make_pair(2, 2);
|
||||
Tensor<float, 1> full(5);
|
||||
full = input.pad(padding).convolve(kernel, dims);
|
||||
VERIFY_IS_EQUAL(full.dimension(0), 5);
|
||||
VERIFY_IS_APPROX(full(0), 0.0f);
|
||||
VERIFY_IS_APPROX(full(1), 1.0f);
|
||||
VERIFY_IS_APPROX(full(2), 2.5f);
|
||||
VERIFY_IS_APPROX(full(3), 4.0f);
|
||||
VERIFY_IS_APPROX(full(4), 1.5f);
|
||||
}
|
||||
|
||||
|
||||
static void test_strides() {
|
||||
Tensor<float, 1> input(13);
|
||||
Tensor<float, 1> kernel(3);
|
||||
input.setRandom();
|
||||
kernel.setRandom();
|
||||
|
||||
const Eigen::array<ptrdiff_t, 1> dims{{0}};
|
||||
const Eigen::array<ptrdiff_t, 1> stride_of_3{{3}};
|
||||
const Eigen::array<ptrdiff_t, 1> stride_of_2{{2}};
|
||||
|
||||
Tensor<float, 1> result;
|
||||
result = input.stride(stride_of_3).convolve(kernel, dims).stride(stride_of_2);
|
||||
|
||||
VERIFY_IS_EQUAL(result.dimension(0), 2);
|
||||
VERIFY_IS_APPROX(result(0), (input(0)*kernel(0) + input(3)*kernel(1) +
|
||||
input(6)*kernel(2)));
|
||||
VERIFY_IS_APPROX(result(1), (input(6)*kernel(0) + input(9)*kernel(1) +
|
||||
input(12)*kernel(2)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void test_cxx11_tensor_convolution()
|
||||
{
|
||||
CALL_SUBTEST(test_evals());
|
||||
CALL_SUBTEST(test_expr());
|
||||
CALL_SUBTEST(test_modes());
|
||||
CALL_SUBTEST(test_strides());
|
||||
}
|
||||
514
unsupported/test/cxx11_tensor_cuda.cpp
Normal file
514
unsupported/test/cxx11_tensor_cuda.cpp
Normal file
@@ -0,0 +1,514 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
// TODO(mdevin): Free the cuda memory.
|
||||
|
||||
#define EIGEN_TEST_NO_LONGDOUBLE
|
||||
#define EIGEN_TEST_NO_COMPLEX
|
||||
#define EIGEN_TEST_FUNC cxx11_tensor_cuda
|
||||
#define EIGEN_DEFAULT_DENSE_INDEX_TYPE int
|
||||
#define EIGEN_USE_GPU
|
||||
|
||||
|
||||
#include "main.h"
|
||||
#include <unsupported/Eigen/CXX11/Tensor>
|
||||
|
||||
using Eigen::Tensor;
|
||||
|
||||
void test_cuda_elementwise_small() {
|
||||
Tensor<float, 1> in1(Eigen::array<int, 1>(2));
|
||||
Tensor<float, 1> in2(Eigen::array<int, 1>(2));
|
||||
Tensor<float, 1> out(Eigen::array<int, 1>(2));
|
||||
in1.setRandom();
|
||||
in2.setRandom();
|
||||
|
||||
std::size_t in1_bytes = in1.size() * sizeof(float);
|
||||
std::size_t in2_bytes = in2.size() * sizeof(float);
|
||||
std::size_t out_bytes = out.size() * sizeof(float);
|
||||
|
||||
float* d_in1;
|
||||
float* d_in2;
|
||||
float* d_out;
|
||||
cudaMalloc((void**)(&d_in1), in1_bytes);
|
||||
cudaMalloc((void**)(&d_in2), in2_bytes);
|
||||
cudaMalloc((void**)(&d_out), out_bytes);
|
||||
|
||||
cudaMemcpy(d_in1, in1.data(), in1_bytes, cudaMemcpyHostToDevice);
|
||||
cudaMemcpy(d_in2, in2.data(), in2_bytes, cudaMemcpyHostToDevice);
|
||||
|
||||
cudaStream_t stream;
|
||||
assert(cudaStreamCreate(&stream) == cudaSuccess);
|
||||
Eigen::GpuDevice gpu_device(&stream);
|
||||
|
||||
Eigen::TensorMap<Eigen::Tensor<float, 1>, Eigen::Aligned> gpu_in1(
|
||||
d_in1, Eigen::array<int, 1>(2));
|
||||
Eigen::TensorMap<Eigen::Tensor<float, 1>, Eigen::Aligned> gpu_in2(
|
||||
d_in2, Eigen::array<int, 1>(2));
|
||||
Eigen::TensorMap<Eigen::Tensor<float, 1>, Eigen::Aligned> gpu_out(
|
||||
d_out, Eigen::array<int, 1>(2));
|
||||
|
||||
gpu_out.device(gpu_device) = gpu_in1 + gpu_in2;
|
||||
|
||||
assert(cudaMemcpyAsync(out.data(), d_out, out_bytes, cudaMemcpyDeviceToHost,
|
||||
gpu_device.stream()) == cudaSuccess);
|
||||
assert(cudaStreamSynchronize(gpu_device.stream()) == cudaSuccess);
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
VERIFY_IS_APPROX(
|
||||
out(Eigen::array<int, 1>(i)),
|
||||
in1(Eigen::array<int, 1>(i)) + in2(Eigen::array<int, 1>(i)));
|
||||
}
|
||||
}
|
||||
|
||||
void test_cuda_elementwise()
|
||||
{
|
||||
Tensor<float, 3> in1(Eigen::array<int, 3>(72,53,97));
|
||||
Tensor<float, 3> in2(Eigen::array<int, 3>(72,53,97));
|
||||
Tensor<float, 3> in3(Eigen::array<int, 3>(72,53,97));
|
||||
Tensor<float, 3> out(Eigen::array<int, 3>(72,53,97));
|
||||
in1.setRandom();
|
||||
in2.setRandom();
|
||||
in3.setRandom();
|
||||
|
||||
std::size_t in1_bytes = in1.size() * sizeof(float);
|
||||
std::size_t in2_bytes = in2.size() * sizeof(float);
|
||||
std::size_t in3_bytes = in3.size() * sizeof(float);
|
||||
std::size_t out_bytes = out.size() * sizeof(float);
|
||||
|
||||
float* d_in1;
|
||||
float* d_in2;
|
||||
float* d_in3;
|
||||
float* d_out;
|
||||
cudaMalloc((void**)(&d_in1), in1_bytes);
|
||||
cudaMalloc((void**)(&d_in2), in2_bytes);
|
||||
cudaMalloc((void**)(&d_in3), in3_bytes);
|
||||
cudaMalloc((void**)(&d_out), out_bytes);
|
||||
|
||||
cudaMemcpy(d_in1, in1.data(), in1_bytes, cudaMemcpyHostToDevice);
|
||||
cudaMemcpy(d_in2, in2.data(), in2_bytes, cudaMemcpyHostToDevice);
|
||||
cudaMemcpy(d_in3, in3.data(), in3_bytes, cudaMemcpyHostToDevice);
|
||||
|
||||
cudaStream_t stream;
|
||||
assert(cudaStreamCreate(&stream) == cudaSuccess);
|
||||
Eigen::GpuDevice gpu_device(&stream);
|
||||
|
||||
Eigen::TensorMap<Eigen::Tensor<float, 3> > gpu_in1(d_in1, Eigen::array<int, 3>(72,53,97));
|
||||
Eigen::TensorMap<Eigen::Tensor<float, 3> > gpu_in2(d_in2, Eigen::array<int, 3>(72,53,97));
|
||||
Eigen::TensorMap<Eigen::Tensor<float, 3> > gpu_in3(d_in3, Eigen::array<int, 3>(72,53,97));
|
||||
Eigen::TensorMap<Eigen::Tensor<float, 3> > gpu_out(d_out, Eigen::array<int, 3>(72,53,97));
|
||||
|
||||
gpu_out.device(gpu_device) = gpu_in1 + gpu_in2 * gpu_in3;
|
||||
|
||||
assert(cudaMemcpyAsync(out.data(), d_out, out_bytes, cudaMemcpyDeviceToHost, gpu_device.stream()) == cudaSuccess);
|
||||
assert(cudaStreamSynchronize(gpu_device.stream()) == cudaSuccess);
|
||||
|
||||
for (int i = 0; i < 72; ++i) {
|
||||
for (int j = 0; j < 53; ++j) {
|
||||
for (int k = 0; k < 97; ++k) {
|
||||
VERIFY_IS_APPROX(out(Eigen::array<int, 3>(i,j,k)), in1(Eigen::array<int, 3>(i,j,k)) + in2(Eigen::array<int, 3>(i,j,k)) * in3(Eigen::array<int, 3>(i,j,k)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void test_cuda_reduction()
|
||||
{
|
||||
Tensor<float, 4> in1(Eigen::array<int, 4>(72,53,97,113));
|
||||
Tensor<float, 2> out(Eigen::array<int, 2>(72,97));
|
||||
in1.setRandom();
|
||||
|
||||
std::size_t in1_bytes = in1.size() * sizeof(float);
|
||||
std::size_t out_bytes = out.size() * sizeof(float);
|
||||
|
||||
float* d_in1;
|
||||
float* d_out;
|
||||
cudaMalloc((void**)(&d_in1), in1_bytes);
|
||||
cudaMalloc((void**)(&d_out), out_bytes);
|
||||
|
||||
cudaMemcpy(d_in1, in1.data(), in1_bytes, cudaMemcpyHostToDevice);
|
||||
|
||||
cudaStream_t stream;
|
||||
assert(cudaStreamCreate(&stream) == cudaSuccess);
|
||||
Eigen::GpuDevice gpu_device(&stream);
|
||||
|
||||
Eigen::TensorMap<Eigen::Tensor<float, 4> > gpu_in1(d_in1, Eigen::array<int, 4>(72,53,97,113));
|
||||
Eigen::TensorMap<Eigen::Tensor<float, 2> > gpu_out(d_out, Eigen::array<int, 2>(72,97));
|
||||
|
||||
array<int, 2> reduction_axis;
|
||||
reduction_axis[0] = 1;
|
||||
reduction_axis[1] = 3;
|
||||
|
||||
gpu_out.device(gpu_device) = gpu_in1.maximum(reduction_axis);
|
||||
|
||||
assert(cudaMemcpyAsync(out.data(), d_out, out_bytes, cudaMemcpyDeviceToHost, gpu_device.stream()) == cudaSuccess);
|
||||
assert(cudaStreamSynchronize(gpu_device.stream()) == cudaSuccess);
|
||||
|
||||
for (int i = 0; i < 72; ++i) {
|
||||
for (int j = 0; j < 97; ++j) {
|
||||
float expected = 0;
|
||||
for (int k = 0; k < 53; ++k) {
|
||||
for (int l = 0; l < 113; ++l) {
|
||||
expected =
|
||||
std::max<float>(expected, in1(Eigen::array<int, 4>(i, k, j, l)));
|
||||
}
|
||||
}
|
||||
VERIFY_IS_APPROX(out(Eigen::array<int, 2>(i,j)), expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<int DataLayout>
|
||||
static void test_cuda_contraction()
|
||||
{
|
||||
// with these dimensions, the output has 300 * 140 elements, which is
|
||||
// more than 30 * 1024, which is the number of threads in blocks on
|
||||
// a 15 SM GK110 GPU
|
||||
Tensor<float, 4, DataLayout> t_left(Eigen::array<int, 4>(6, 50, 3, 31));
|
||||
Tensor<float, 5, DataLayout> t_right(Eigen::array<int, 5>(3, 31, 7, 20, 1));
|
||||
Tensor<float, 5, DataLayout> t_result(Eigen::array<int, 5>(6, 50, 7, 20, 1));
|
||||
|
||||
t_left.setRandom();
|
||||
t_right.setRandom();
|
||||
|
||||
std::size_t t_left_bytes = t_left.size() * sizeof(float);
|
||||
std::size_t t_right_bytes = t_right.size() * sizeof(float);
|
||||
std::size_t t_result_bytes = t_result.size() * sizeof(float);
|
||||
|
||||
float* d_t_left;
|
||||
float* d_t_right;
|
||||
float* d_t_result;
|
||||
|
||||
cudaMalloc((void**)(&d_t_left), t_left_bytes);
|
||||
cudaMalloc((void**)(&d_t_right), t_right_bytes);
|
||||
cudaMalloc((void**)(&d_t_result), t_result_bytes);
|
||||
|
||||
cudaMemcpy(d_t_left, t_left.data(), t_left_bytes, cudaMemcpyHostToDevice);
|
||||
cudaMemcpy(d_t_right, t_right.data(), t_right_bytes, cudaMemcpyHostToDevice);
|
||||
|
||||
cudaStream_t stream;
|
||||
assert(cudaStreamCreate(&stream) == cudaSuccess);
|
||||
Eigen::GpuDevice gpu_device(&stream);
|
||||
|
||||
Eigen::TensorMap<Eigen::Tensor<float, 4, DataLayout> >
|
||||
gpu_t_left(d_t_left, Eigen::array<int, 4>(6, 50, 3, 31));
|
||||
Eigen::TensorMap<Eigen::Tensor<float, 5, DataLayout> >
|
||||
gpu_t_right(d_t_right, Eigen::array<int, 5>(3, 31, 7, 20, 1));
|
||||
Eigen::TensorMap<Eigen::Tensor<float, 5, DataLayout> >
|
||||
gpu_t_result(d_t_result, Eigen::array<int, 5>(6, 50, 7, 20, 1));
|
||||
|
||||
typedef Eigen::Map<Eigen::Matrix<float, Dynamic, Dynamic, DataLayout> > MapXf;
|
||||
MapXf m_left(t_left.data(), 300, 93);
|
||||
MapXf m_right(t_right.data(), 93, 140);
|
||||
Eigen::Matrix<float, Dynamic, Dynamic, DataLayout> m_result(300, 140);
|
||||
|
||||
typedef Tensor<float, 1>::DimensionPair DimPair;
|
||||
Eigen::array<DimPair, 2> dims;
|
||||
dims[0] = DimPair(2, 0);
|
||||
dims[1] = DimPair(3, 1);
|
||||
|
||||
m_result = m_left * m_right;
|
||||
gpu_t_result.device(gpu_device) = gpu_t_left.contract(gpu_t_right, dims);
|
||||
|
||||
cudaMemcpy(t_result.data(), d_t_result, t_result_bytes, cudaMemcpyDeviceToHost);
|
||||
|
||||
for (size_t i = 0; i < t_result.dimensions().TotalSize(); i++) {
|
||||
if (fabs(t_result.data()[i] - m_result.data()[i]) >= 1e-4) {
|
||||
cout << "mismatch detected at index " << i << ": " << t_result.data()[i] << " vs " << m_result.data()[i] << endl;
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void test_cuda_convolution_1d()
|
||||
{
|
||||
Tensor<float, 4> input(Eigen::array<int, 4>(74,37,11,137));
|
||||
Tensor<float, 1> kernel(Eigen::array<int, 1>(4));
|
||||
Tensor<float, 4> out(Eigen::array<int, 4>(74,34,11,137));
|
||||
input = input.constant(10.0f) + input.random();
|
||||
kernel = kernel.constant(7.0f) + kernel.random();
|
||||
|
||||
std::size_t input_bytes = input.size() * sizeof(float);
|
||||
std::size_t kernel_bytes = kernel.size() * sizeof(float);
|
||||
std::size_t out_bytes = out.size() * sizeof(float);
|
||||
|
||||
float* d_input;
|
||||
float* d_kernel;
|
||||
float* d_out;
|
||||
cudaMalloc((void**)(&d_input), input_bytes);
|
||||
cudaMalloc((void**)(&d_kernel), kernel_bytes);
|
||||
cudaMalloc((void**)(&d_out), out_bytes);
|
||||
|
||||
cudaMemcpy(d_input, input.data(), input_bytes, cudaMemcpyHostToDevice);
|
||||
cudaMemcpy(d_kernel, kernel.data(), kernel_bytes, cudaMemcpyHostToDevice);
|
||||
|
||||
cudaStream_t stream;
|
||||
assert(cudaStreamCreate(&stream) == cudaSuccess);
|
||||
Eigen::GpuDevice gpu_device(&stream);
|
||||
|
||||
Eigen::TensorMap<Eigen::Tensor<float, 4> > gpu_input(d_input, Eigen::array<int, 4>(74,37,11,137));
|
||||
Eigen::TensorMap<Eigen::Tensor<float, 1> > gpu_kernel(d_kernel, Eigen::array<int, 1>(4));
|
||||
Eigen::TensorMap<Eigen::Tensor<float, 4> > gpu_out(d_out, Eigen::array<int, 4>(74,34,11,137));
|
||||
|
||||
Eigen::array<int, 1> dims(1);
|
||||
gpu_out.device(gpu_device) = gpu_input.convolve(gpu_kernel, dims);
|
||||
|
||||
assert(cudaMemcpyAsync(out.data(), d_out, out_bytes, cudaMemcpyDeviceToHost, gpu_device.stream()) == cudaSuccess);
|
||||
assert(cudaStreamSynchronize(gpu_device.stream()) == cudaSuccess);
|
||||
|
||||
for (int i = 0; i < 74; ++i) {
|
||||
for (int j = 0; j < 34; ++j) {
|
||||
for (int k = 0; k < 11; ++k) {
|
||||
for (int l = 0; l < 137; ++l) {
|
||||
const float result = out(Eigen::array<int, 4>(i,j,k,l));
|
||||
const float expected = input(Eigen::array<int, 4>(i,j+0,k,l)) * kernel(Eigen::array<int, 1>(0)) +
|
||||
input(Eigen::array<int, 4>(i,j+1,k,l)) * kernel(Eigen::array<int, 1>(1)) +
|
||||
input(Eigen::array<int, 4>(i,j+2,k,l)) * kernel(Eigen::array<int, 1>(2)) +
|
||||
input(Eigen::array<int, 4>(i,j+3,k,l)) * kernel(Eigen::array<int, 1>(3));
|
||||
VERIFY_IS_APPROX(result, expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void test_cuda_convolution_2d()
|
||||
{
|
||||
Tensor<float, 4> input(Eigen::array<int, 4>(74,37,11,137));
|
||||
Tensor<float, 2> kernel(Eigen::array<int, 2>(3,4));
|
||||
Tensor<float, 4> out(Eigen::array<int, 4>(74,35,8,137));
|
||||
input = input.constant(10.0f) + input.random();
|
||||
kernel = kernel.constant(7.0f) + kernel.random();
|
||||
|
||||
std::size_t input_bytes = input.size() * sizeof(float);
|
||||
std::size_t kernel_bytes = kernel.size() * sizeof(float);
|
||||
std::size_t out_bytes = out.size() * sizeof(float);
|
||||
|
||||
float* d_input;
|
||||
float* d_kernel;
|
||||
float* d_out;
|
||||
cudaMalloc((void**)(&d_input), input_bytes);
|
||||
cudaMalloc((void**)(&d_kernel), kernel_bytes);
|
||||
cudaMalloc((void**)(&d_out), out_bytes);
|
||||
|
||||
cudaMemcpy(d_input, input.data(), input_bytes, cudaMemcpyHostToDevice);
|
||||
cudaMemcpy(d_kernel, kernel.data(), kernel_bytes, cudaMemcpyHostToDevice);
|
||||
|
||||
cudaStream_t stream;
|
||||
assert(cudaStreamCreate(&stream) == cudaSuccess);
|
||||
Eigen::GpuDevice gpu_device(&stream);
|
||||
|
||||
Eigen::TensorMap<Eigen::Tensor<float, 4> > gpu_input(d_input, Eigen::array<int, 4>(74,37,11,137));
|
||||
Eigen::TensorMap<Eigen::Tensor<float, 2> > gpu_kernel(d_kernel, Eigen::array<int, 2>(3,4));
|
||||
Eigen::TensorMap<Eigen::Tensor<float, 4> > gpu_out(d_out, Eigen::array<int, 4>(74,35,8,137));
|
||||
|
||||
Eigen::array<int, 2> dims(1,2);
|
||||
gpu_out.device(gpu_device) = gpu_input.convolve(gpu_kernel, dims);
|
||||
|
||||
assert(cudaMemcpyAsync(out.data(), d_out, out_bytes, cudaMemcpyDeviceToHost, gpu_device.stream()) == cudaSuccess);
|
||||
assert(cudaStreamSynchronize(gpu_device.stream()) == cudaSuccess);
|
||||
|
||||
for (int i = 0; i < 74; ++i) {
|
||||
for (int j = 0; j < 35; ++j) {
|
||||
for (int k = 0; k < 8; ++k) {
|
||||
for (int l = 0; l < 137; ++l) {
|
||||
const float result = out(Eigen::array<int, 4>(i,j,k,l));
|
||||
const float expected = input(Eigen::array<int, 4>(i,j+0,k+0,l)) * kernel(Eigen::array<int, 2>(0,0)) +
|
||||
input(Eigen::array<int, 4>(i,j+1,k+0,l)) * kernel(Eigen::array<int, 2>(1,0)) +
|
||||
input(Eigen::array<int, 4>(i,j+2,k+0,l)) * kernel(Eigen::array<int, 2>(2,0)) +
|
||||
input(Eigen::array<int, 4>(i,j+0,k+1,l)) * kernel(Eigen::array<int, 2>(0,1)) +
|
||||
input(Eigen::array<int, 4>(i,j+1,k+1,l)) * kernel(Eigen::array<int, 2>(1,1)) +
|
||||
input(Eigen::array<int, 4>(i,j+2,k+1,l)) * kernel(Eigen::array<int, 2>(2,1)) +
|
||||
input(Eigen::array<int, 4>(i,j+0,k+2,l)) * kernel(Eigen::array<int, 2>(0,2)) +
|
||||
input(Eigen::array<int, 4>(i,j+1,k+2,l)) * kernel(Eigen::array<int, 2>(1,2)) +
|
||||
input(Eigen::array<int, 4>(i,j+2,k+2,l)) * kernel(Eigen::array<int, 2>(2,2)) +
|
||||
input(Eigen::array<int, 4>(i,j+0,k+3,l)) * kernel(Eigen::array<int, 2>(0,3)) +
|
||||
input(Eigen::array<int, 4>(i,j+1,k+3,l)) * kernel(Eigen::array<int, 2>(1,3)) +
|
||||
input(Eigen::array<int, 4>(i,j+2,k+3,l)) * kernel(Eigen::array<int, 2>(2,3));
|
||||
VERIFY_IS_APPROX(result, expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void test_cuda_convolution_3d()
|
||||
{
|
||||
Tensor<float, 5> input(Eigen::array<int, 5>(74,37,11,137,17));
|
||||
Tensor<float, 3> kernel(Eigen::array<int, 3>(3,4,2));
|
||||
Tensor<float, 5> out(Eigen::array<int, 5>(74,35,8,136,17));
|
||||
input = input.constant(10.0f) + input.random();
|
||||
kernel = kernel.constant(7.0f) + kernel.random();
|
||||
|
||||
std::size_t input_bytes = input.size() * sizeof(float);
|
||||
std::size_t kernel_bytes = kernel.size() * sizeof(float);
|
||||
std::size_t out_bytes = out.size() * sizeof(float);
|
||||
|
||||
float* d_input;
|
||||
float* d_kernel;
|
||||
float* d_out;
|
||||
cudaMalloc((void**)(&d_input), input_bytes);
|
||||
cudaMalloc((void**)(&d_kernel), kernel_bytes);
|
||||
cudaMalloc((void**)(&d_out), out_bytes);
|
||||
|
||||
cudaMemcpy(d_input, input.data(), input_bytes, cudaMemcpyHostToDevice);
|
||||
cudaMemcpy(d_kernel, kernel.data(), kernel_bytes, cudaMemcpyHostToDevice);
|
||||
|
||||
cudaStream_t stream;
|
||||
assert(cudaStreamCreate(&stream) == cudaSuccess);
|
||||
Eigen::GpuDevice gpu_device(&stream);
|
||||
|
||||
Eigen::TensorMap<Eigen::Tensor<float, 5> > gpu_input(d_input, Eigen::array<int, 5>(74,37,11,137,17));
|
||||
Eigen::TensorMap<Eigen::Tensor<float, 3> > gpu_kernel(d_kernel, Eigen::array<int, 3>(3,4,2));
|
||||
Eigen::TensorMap<Eigen::Tensor<float, 5> > gpu_out(d_out, Eigen::array<int, 5>(74,35,8,136,17));
|
||||
|
||||
Eigen::array<int, 3> dims(1,2,3);
|
||||
gpu_out.device(gpu_device) = gpu_input.convolve(gpu_kernel, dims);
|
||||
|
||||
assert(cudaMemcpyAsync(out.data(), d_out, out_bytes, cudaMemcpyDeviceToHost, gpu_device.stream()) == cudaSuccess);
|
||||
assert(cudaStreamSynchronize(gpu_device.stream()) == cudaSuccess);
|
||||
|
||||
for (int i = 0; i < 74; ++i) {
|
||||
for (int j = 0; j < 35; ++j) {
|
||||
for (int k = 0; k < 8; ++k) {
|
||||
for (int l = 0; l < 136; ++l) {
|
||||
for (int m = 0; m < 17; ++m) {
|
||||
const float result = out(Eigen::array<int, 5>(i,j,k,l,m));
|
||||
const float expected = input(Eigen::array<int, 5>(i,j+0,k+0,l+0,m)) * kernel(Eigen::array<int, 3>(0,0,0)) +
|
||||
input(Eigen::array<int, 5>(i,j+1,k+0,l+0,m)) * kernel(Eigen::array<int, 3>(1,0,0)) +
|
||||
input(Eigen::array<int, 5>(i,j+2,k+0,l+0,m)) * kernel(Eigen::array<int, 3>(2,0,0)) +
|
||||
input(Eigen::array<int, 5>(i,j+0,k+1,l+0,m)) * kernel(Eigen::array<int, 3>(0,1,0)) +
|
||||
input(Eigen::array<int, 5>(i,j+1,k+1,l+0,m)) * kernel(Eigen::array<int, 3>(1,1,0)) +
|
||||
input(Eigen::array<int, 5>(i,j+2,k+1,l+0,m)) * kernel(Eigen::array<int, 3>(2,1,0)) +
|
||||
input(Eigen::array<int, 5>(i,j+0,k+2,l+0,m)) * kernel(Eigen::array<int, 3>(0,2,0)) +
|
||||
input(Eigen::array<int, 5>(i,j+1,k+2,l+0,m)) * kernel(Eigen::array<int, 3>(1,2,0)) +
|
||||
input(Eigen::array<int, 5>(i,j+2,k+2,l+0,m)) * kernel(Eigen::array<int, 3>(2,2,0)) +
|
||||
input(Eigen::array<int, 5>(i,j+0,k+3,l+0,m)) * kernel(Eigen::array<int, 3>(0,3,0)) +
|
||||
input(Eigen::array<int, 5>(i,j+1,k+3,l+0,m)) * kernel(Eigen::array<int, 3>(1,3,0)) +
|
||||
input(Eigen::array<int, 5>(i,j+2,k+3,l+0,m)) * kernel(Eigen::array<int, 3>(2,3,0)) +
|
||||
input(Eigen::array<int, 5>(i,j+0,k+0,l+1,m)) * kernel(Eigen::array<int, 3>(0,0,1)) +
|
||||
input(Eigen::array<int, 5>(i,j+1,k+0,l+1,m)) * kernel(Eigen::array<int, 3>(1,0,1)) +
|
||||
input(Eigen::array<int, 5>(i,j+2,k+0,l+1,m)) * kernel(Eigen::array<int, 3>(2,0,1)) +
|
||||
input(Eigen::array<int, 5>(i,j+0,k+1,l+1,m)) * kernel(Eigen::array<int, 3>(0,1,1)) +
|
||||
input(Eigen::array<int, 5>(i,j+1,k+1,l+1,m)) * kernel(Eigen::array<int, 3>(1,1,1)) +
|
||||
input(Eigen::array<int, 5>(i,j+2,k+1,l+1,m)) * kernel(Eigen::array<int, 3>(2,1,1)) +
|
||||
input(Eigen::array<int, 5>(i,j+0,k+2,l+1,m)) * kernel(Eigen::array<int, 3>(0,2,1)) +
|
||||
input(Eigen::array<int, 5>(i,j+1,k+2,l+1,m)) * kernel(Eigen::array<int, 3>(1,2,1)) +
|
||||
input(Eigen::array<int, 5>(i,j+2,k+2,l+1,m)) * kernel(Eigen::array<int, 3>(2,2,1)) +
|
||||
input(Eigen::array<int, 5>(i,j+0,k+3,l+1,m)) * kernel(Eigen::array<int, 3>(0,3,1)) +
|
||||
input(Eigen::array<int, 5>(i,j+1,k+3,l+1,m)) * kernel(Eigen::array<int, 3>(1,3,1)) +
|
||||
input(Eigen::array<int, 5>(i,j+2,k+3,l+1,m)) * kernel(Eigen::array<int, 3>(2,3,1));
|
||||
VERIFY_IS_APPROX(result, expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static float* CudaCopyFloat(float* data, int size) {
|
||||
const int nbytes = size * sizeof(float);
|
||||
float* result = NULL;
|
||||
if (cudaMalloc((void**)(&result), nbytes) != cudaSuccess) {
|
||||
return NULL;
|
||||
} else {
|
||||
if (data != NULL) {
|
||||
cudaMemcpy(result, data, nbytes, cudaMemcpyHostToDevice);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
static void test_cuda_constant_broadcast()
|
||||
{
|
||||
cudaStream_t stream;
|
||||
assert(cudaStreamCreate(&stream) == cudaSuccess);
|
||||
Eigen::GpuDevice gpu_device(&stream);
|
||||
|
||||
Tensor<float, 1> t1(10);
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
t1(i) = 10.0f * i;
|
||||
}
|
||||
float* t1_cuda = CudaCopyFloat(t1.data(), t1.size());
|
||||
Eigen::TensorMap<Eigen::Tensor<float, 1> > t1_gpu(t1_cuda, 10);
|
||||
|
||||
Tensor<float, 1> t2(1);
|
||||
t2 = t2.constant(20.0f);
|
||||
float* t2_cuda = CudaCopyFloat(t2.data(), t2.size());
|
||||
Eigen::TensorMap<Eigen::TensorFixedSize<float, Sizes<1> > > t2_gpu(t2_cuda, 1);
|
||||
|
||||
float* t3_cuda = CudaCopyFloat(NULL, 10);
|
||||
Eigen::TensorMap<Eigen::Tensor<float, 1> > t3_gpu(t3_cuda, 10);
|
||||
|
||||
t3_gpu.device(gpu_device) =
|
||||
t1_gpu + t2_gpu.broadcast(Eigen::array<int, 1>(10));
|
||||
|
||||
Eigen::Tensor<float, 1> t3(10);
|
||||
cudaMemcpy(t3.data(), t3_gpu.data(), 10 * sizeof(float),
|
||||
cudaMemcpyDeviceToHost);
|
||||
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
VERIFY_IS_APPROX(t3(i), t1(i) + t2(0));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void test_cuda_cast()
|
||||
{
|
||||
Tensor<double, 3> in(Eigen::array<int, 3>(72,53,97));
|
||||
Tensor<float, 3> out(Eigen::array<int, 3>(72,53,97));
|
||||
in.setRandom();
|
||||
|
||||
std::size_t in_bytes = in.size() * sizeof(double);
|
||||
std::size_t out_bytes = out.size() * sizeof(float);
|
||||
|
||||
double* d_in;
|
||||
float* d_out;
|
||||
cudaMalloc((void**)(&d_in), in_bytes);
|
||||
cudaMalloc((void**)(&d_out), out_bytes);
|
||||
|
||||
cudaMemcpy(d_in, in.data(), in_bytes, cudaMemcpyHostToDevice);
|
||||
|
||||
cudaStream_t stream;
|
||||
assert(cudaStreamCreate(&stream) == cudaSuccess);
|
||||
Eigen::GpuDevice gpu_device(&stream);
|
||||
|
||||
Eigen::TensorMap<Eigen::Tensor<double, 3> > gpu_in(d_in, Eigen::array<int, 3>(72,53,97));
|
||||
Eigen::TensorMap<Eigen::Tensor<float, 3> > gpu_out(d_out, Eigen::array<int, 3>(72,53,97));
|
||||
|
||||
gpu_out.device(gpu_device) = gpu_in.template cast<float>();
|
||||
|
||||
assert(cudaMemcpyAsync(out.data(), d_out, out_bytes, cudaMemcpyDeviceToHost, gpu_device.stream()) == cudaSuccess);
|
||||
assert(cudaStreamSynchronize(gpu_device.stream()) == cudaSuccess);
|
||||
|
||||
for (int i = 0; i < 72; ++i) {
|
||||
for (int j = 0; j < 53; ++j) {
|
||||
for (int k = 0; k < 97; ++k) {
|
||||
VERIFY_IS_APPROX(out(Eigen::array<int, 3>(i,j,k)), static_cast<float>(in(Eigen::array<int, 3>(i,j,k))));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void test_cxx11_tensor_cuda()
|
||||
{
|
||||
CALL_SUBTEST(test_cuda_elementwise_small());
|
||||
CALL_SUBTEST(test_cuda_elementwise());
|
||||
CALL_SUBTEST(test_cuda_reduction());
|
||||
CALL_SUBTEST(test_cuda_contraction<ColMajor>());
|
||||
CALL_SUBTEST(test_cuda_contraction<RowMajor>());
|
||||
CALL_SUBTEST(test_cuda_convolution_1d());
|
||||
CALL_SUBTEST(test_cuda_convolution_2d());
|
||||
CALL_SUBTEST(test_cuda_convolution_3d());
|
||||
CALL_SUBTEST(test_cuda_constant_broadcast());
|
||||
CALL_SUBTEST(test_cuda_cast());
|
||||
}
|
||||
391
unsupported/test/cxx11_tensor_device.cpp
Normal file
391
unsupported/test/cxx11_tensor_device.cpp
Normal file
@@ -0,0 +1,391 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#define EIGEN_TEST_NO_LONGDOUBLE
|
||||
#define EIGEN_TEST_NO_COMPLEX
|
||||
#define EIGEN_TEST_FUNC cxx11_tensor_device
|
||||
#define EIGEN_DEFAULT_DENSE_INDEX_TYPE int
|
||||
#define EIGEN_USE_GPU
|
||||
|
||||
|
||||
#include "main.h"
|
||||
#include <unsupported/Eigen/CXX11/Tensor>
|
||||
|
||||
using Eigen::Tensor;
|
||||
using Eigen::RowMajor;
|
||||
|
||||
// Context for evaluation on cpu
|
||||
struct CPUContext {
|
||||
CPUContext(const Eigen::Tensor<float, 3>& in1, Eigen::Tensor<float, 3>& in2, Eigen::Tensor<float, 3>& out) : in1_(in1), in2_(in2), out_(out), kernel_1d_(2), kernel_2d_(2,2), kernel_3d_(2,2,2) {
|
||||
kernel_1d_(0) = 3.14f;
|
||||
kernel_1d_(1) = 2.7f;
|
||||
|
||||
kernel_2d_(0,0) = 3.14f;
|
||||
kernel_2d_(1,0) = 2.7f;
|
||||
kernel_2d_(0,1) = 0.2f;
|
||||
kernel_2d_(1,1) = 7.0f;
|
||||
|
||||
kernel_3d_(0,0,0) = 3.14f;
|
||||
kernel_3d_(0,1,0) = 2.7f;
|
||||
kernel_3d_(0,0,1) = 0.2f;
|
||||
kernel_3d_(0,1,1) = 7.0f;
|
||||
kernel_3d_(1,0,0) = -1.0f;
|
||||
kernel_3d_(1,1,0) = -0.3f;
|
||||
kernel_3d_(1,0,1) = -0.7f;
|
||||
kernel_3d_(1,1,1) = -0.5f;
|
||||
}
|
||||
|
||||
const Eigen::DefaultDevice& device() const { return cpu_device_; }
|
||||
|
||||
const Eigen::Tensor<float, 3>& in1() const { return in1_; }
|
||||
const Eigen::Tensor<float, 3>& in2() const { return in2_; }
|
||||
Eigen::Tensor<float, 3>& out() { return out_; }
|
||||
const Eigen::Tensor<float, 1>& kernel1d() const { return kernel_1d_; }
|
||||
const Eigen::Tensor<float, 2>& kernel2d() const { return kernel_2d_; }
|
||||
const Eigen::Tensor<float, 3>& kernel3d() const { return kernel_3d_; }
|
||||
|
||||
private:
|
||||
const Eigen::Tensor<float, 3>& in1_;
|
||||
const Eigen::Tensor<float, 3>& in2_;
|
||||
Eigen::Tensor<float, 3>& out_;
|
||||
|
||||
Eigen::Tensor<float, 1> kernel_1d_;
|
||||
Eigen::Tensor<float, 2> kernel_2d_;
|
||||
Eigen::Tensor<float, 3> kernel_3d_;
|
||||
|
||||
Eigen::DefaultDevice cpu_device_;
|
||||
};
|
||||
|
||||
|
||||
// Context for evaluation on GPU
|
||||
struct GPUContext {
|
||||
GPUContext(const Eigen::TensorMap<Eigen::Tensor<float, 3> >& in1, Eigen::TensorMap<Eigen::Tensor<float, 3> >& in2, Eigen::TensorMap<Eigen::Tensor<float, 3> >& out) : in1_(in1), in2_(in2), out_(out), gpu_device_(&stream_) {
|
||||
assert(cudaMalloc((void**)(&kernel_1d_), 2*sizeof(float)) == cudaSuccess);
|
||||
float kernel_1d_val[] = {3.14f, 2.7f};
|
||||
assert(cudaMemcpy(kernel_1d_, kernel_1d_val, 2*sizeof(float), cudaMemcpyHostToDevice) == cudaSuccess);
|
||||
|
||||
assert(cudaMalloc((void**)(&kernel_2d_), 4*sizeof(float)) == cudaSuccess);
|
||||
float kernel_2d_val[] = {3.14f, 2.7f, 0.2f, 7.0f};
|
||||
assert(cudaMemcpy(kernel_2d_, kernel_2d_val, 4*sizeof(float), cudaMemcpyHostToDevice) == cudaSuccess);
|
||||
|
||||
assert(cudaMalloc((void**)(&kernel_3d_), 8*sizeof(float)) == cudaSuccess);
|
||||
float kernel_3d_val[] = {3.14f, -1.0f, 2.7f, -0.3f, 0.2f, -0.7f, 7.0f, -0.5f};
|
||||
assert(cudaMemcpy(kernel_3d_, kernel_3d_val, 8*sizeof(float), cudaMemcpyHostToDevice) == cudaSuccess);
|
||||
|
||||
assert(cudaStreamCreate(&stream_) == cudaSuccess);
|
||||
}
|
||||
~GPUContext() {
|
||||
assert(cudaFree(kernel_1d_) == cudaSuccess);
|
||||
assert(cudaFree(kernel_2d_) == cudaSuccess);
|
||||
assert(cudaFree(kernel_3d_) == cudaSuccess);
|
||||
assert(cudaStreamDestroy(stream_) == cudaSuccess);
|
||||
}
|
||||
|
||||
const Eigen::GpuDevice& device() const { return gpu_device_; }
|
||||
|
||||
const Eigen::TensorMap<Eigen::Tensor<float, 3> >& in1() const { return in1_; }
|
||||
const Eigen::TensorMap<Eigen::Tensor<float, 3> >& in2() const { return in2_; }
|
||||
Eigen::TensorMap<Eigen::Tensor<float, 3> >& out() { return out_; }
|
||||
Eigen::TensorMap<Eigen::Tensor<float, 1> > kernel1d() const { return Eigen::TensorMap<Eigen::Tensor<float, 1> >(kernel_1d_, 2); }
|
||||
Eigen::TensorMap<Eigen::Tensor<float, 2> > kernel2d() const { return Eigen::TensorMap<Eigen::Tensor<float, 2> >(kernel_2d_, 2, 2); }
|
||||
Eigen::TensorMap<Eigen::Tensor<float, 3> > kernel3d() const { return Eigen::TensorMap<Eigen::Tensor<float, 3> >(kernel_3d_, 2, 2, 2); }
|
||||
|
||||
private:
|
||||
const Eigen::TensorMap<Eigen::Tensor<float, 3> >& in1_;
|
||||
const Eigen::TensorMap<Eigen::Tensor<float, 3> >& in2_;
|
||||
Eigen::TensorMap<Eigen::Tensor<float, 3> >& out_;
|
||||
|
||||
float* kernel_1d_;
|
||||
float* kernel_2d_;
|
||||
float* kernel_3d_;
|
||||
|
||||
cudaStream_t stream_;
|
||||
Eigen::GpuDevice gpu_device_;
|
||||
};
|
||||
|
||||
|
||||
// The actual expression to evaluate
|
||||
template <typename Context>
|
||||
static void test_contextual_eval(Context* context)
|
||||
{
|
||||
context->out().device(context->device()) = context->in1() + context->in2() * 3.14f + context->in1().constant(2.718f);
|
||||
}
|
||||
|
||||
template <typename Context>
|
||||
static void test_forced_contextual_eval(Context* context)
|
||||
{
|
||||
context->out().device(context->device()) = (context->in1() + context->in2()).eval() * 3.14f + context->in1().constant(2.718f);
|
||||
}
|
||||
|
||||
template <typename Context>
|
||||
static void test_compound_assignment(Context* context)
|
||||
{
|
||||
context->out().device(context->device()) = context->in1().constant(2.718f);
|
||||
context->out().device(context->device()) += context->in1() + context->in2() * 3.14f;
|
||||
}
|
||||
|
||||
|
||||
template <typename Context>
|
||||
static void test_contraction(Context* context)
|
||||
{
|
||||
Eigen::array<std::pair<int, int>, 2> dims;
|
||||
dims[0] = std::make_pair(1, 1);
|
||||
dims[1] = std::make_pair(2, 2);
|
||||
|
||||
Eigen::array<int, 2> shape(40, 50*70);
|
||||
|
||||
Eigen::DSizes<int, 2> indices(0,0);
|
||||
Eigen::DSizes<int, 2> sizes(40,40);
|
||||
|
||||
context->out().reshape(shape).slice(indices, sizes).device(context->device()) = context->in1().contract(context->in2(), dims);
|
||||
}
|
||||
|
||||
|
||||
template <typename Context>
|
||||
static void test_1d_convolution(Context* context)
|
||||
{
|
||||
Eigen::DSizes<int, 3> indices(0,0,0);
|
||||
Eigen::DSizes<int, 3> sizes(40,49,70);
|
||||
|
||||
Eigen::array<int, 1> dims(1);
|
||||
context->out().slice(indices, sizes).device(context->device()) = context->in1().convolve(context->kernel1d(), dims);
|
||||
}
|
||||
|
||||
template <typename Context>
|
||||
static void test_2d_convolution(Context* context)
|
||||
{
|
||||
Eigen::DSizes<int, 3> indices(0,0,0);
|
||||
Eigen::DSizes<int, 3> sizes(40,49,69);
|
||||
|
||||
Eigen::array<int, 2> dims(1,2);
|
||||
context->out().slice(indices, sizes).device(context->device()) = context->in1().convolve(context->kernel2d(), dims);
|
||||
}
|
||||
|
||||
template <typename Context>
|
||||
static void test_3d_convolution(Context* context)
|
||||
{
|
||||
Eigen::DSizes<int, 3> indices(0,0,0);
|
||||
Eigen::DSizes<int, 3> sizes(39,49,69);
|
||||
|
||||
Eigen::array<int, 3> dims(0,1,2);
|
||||
context->out().slice(indices, sizes).device(context->device()) = context->in1().convolve(context->kernel3d(), dims);
|
||||
}
|
||||
|
||||
|
||||
static void test_cpu() {
|
||||
Eigen::Tensor<float, 3> in1(40,50,70);
|
||||
Eigen::Tensor<float, 3> in2(40,50,70);
|
||||
Eigen::Tensor<float, 3> out(40,50,70);
|
||||
|
||||
in1 = in1.random() + in1.constant(10.0f);
|
||||
in2 = in2.random() + in2.constant(10.0f);
|
||||
|
||||
CPUContext context(in1, in2, out);
|
||||
test_contextual_eval(&context);
|
||||
for (int i = 0; i < 40; ++i) {
|
||||
for (int j = 0; j < 50; ++j) {
|
||||
for (int k = 0; k < 70; ++k) {
|
||||
VERIFY_IS_APPROX(out(i,j,k), in1(i,j,k) + in2(i,j,k) * 3.14f + 2.718f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test_forced_contextual_eval(&context);
|
||||
for (int i = 0; i < 40; ++i) {
|
||||
for (int j = 0; j < 50; ++j) {
|
||||
for (int k = 0; k < 70; ++k) {
|
||||
VERIFY_IS_APPROX(out(i,j,k), (in1(i,j,k) + in2(i,j,k)) * 3.14f + 2.718f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test_compound_assignment(&context);
|
||||
for (int i = 0; i < 40; ++i) {
|
||||
for (int j = 0; j < 50; ++j) {
|
||||
for (int k = 0; k < 70; ++k) {
|
||||
VERIFY_IS_APPROX(out(i,j,k), in1(i,j,k) + in2(i,j,k) * 3.14f + 2.718f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test_contraction(&context);
|
||||
for (int i = 0; i < 40; ++i) {
|
||||
for (int j = 0; j < 40; ++j) {
|
||||
const float result = out(i,j,0);
|
||||
float expected = 0;
|
||||
for (int k = 0; k < 50; ++k) {
|
||||
for (int l = 0; l < 70; ++l) {
|
||||
expected += in1(i, k, l) * in2(j, k, l);
|
||||
}
|
||||
}
|
||||
VERIFY_IS_APPROX(expected, result);
|
||||
}
|
||||
}
|
||||
|
||||
test_1d_convolution(&context);
|
||||
for (int i = 0; i < 40; ++i) {
|
||||
for (int j = 0; j < 49; ++j) {
|
||||
for (int k = 0; k < 70; ++k) {
|
||||
VERIFY_IS_APPROX(out(i,j,k), (in1(i,j,k) * 3.14f + in1(i,j+1,k) * 2.7f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test_2d_convolution(&context);
|
||||
for (int i = 0; i < 40; ++i) {
|
||||
for (int j = 0; j < 49; ++j) {
|
||||
for (int k = 0; k < 69; ++k) {
|
||||
const float result = out(i,j,k);
|
||||
const float expected = (in1(i,j,k) * 3.14f + in1(i,j+1,k) * 2.7f) +
|
||||
(in1(i,j,k+1) * 0.2f + in1(i,j+1,k+1) * 7.0f);
|
||||
if (fabs(expected) < 1e-4 && fabs(result) < 1e-4) {
|
||||
continue;
|
||||
}
|
||||
VERIFY_IS_APPROX(expected, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test_3d_convolution(&context);
|
||||
for (int i = 0; i < 39; ++i) {
|
||||
for (int j = 0; j < 49; ++j) {
|
||||
for (int k = 0; k < 69; ++k) {
|
||||
const float result = out(i,j,k);
|
||||
const float expected = (in1(i,j,k) * 3.14f + in1(i,j+1,k) * 2.7f +
|
||||
in1(i,j,k+1) * 0.2f + in1(i,j+1,k+1) * 7.0f) +
|
||||
(in1(i+1,j,k) * -1.0f + in1(i+1,j+1,k) * -0.3f +
|
||||
in1(i+1,j,k+1) * -0.7f + in1(i+1,j+1,k+1) * -0.5f);
|
||||
if (fabs(expected) < 1e-4 && fabs(result) < 1e-4) {
|
||||
continue;
|
||||
}
|
||||
VERIFY_IS_APPROX(expected, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void test_gpu() {
|
||||
Eigen::Tensor<float, 3> in1(40,50,70);
|
||||
Eigen::Tensor<float, 3> in2(40,50,70);
|
||||
Eigen::Tensor<float, 3> out(40,50,70);
|
||||
in1 = in1.random() + in1.constant(10.0f);
|
||||
in2 = in2.random() + in2.constant(10.0f);
|
||||
|
||||
std::size_t in1_bytes = in1.size() * sizeof(float);
|
||||
std::size_t in2_bytes = in2.size() * sizeof(float);
|
||||
std::size_t out_bytes = out.size() * sizeof(float);
|
||||
|
||||
float* d_in1;
|
||||
float* d_in2;
|
||||
float* d_out;
|
||||
cudaMalloc((void**)(&d_in1), in1_bytes);
|
||||
cudaMalloc((void**)(&d_in2), in2_bytes);
|
||||
cudaMalloc((void**)(&d_out), out_bytes);
|
||||
|
||||
cudaMemcpy(d_in1, in1.data(), in1_bytes, cudaMemcpyHostToDevice);
|
||||
cudaMemcpy(d_in2, in2.data(), in2_bytes, cudaMemcpyHostToDevice);
|
||||
|
||||
Eigen::TensorMap<Eigen::Tensor<float, 3> > gpu_in1(d_in1, 40,50,70);
|
||||
Eigen::TensorMap<Eigen::Tensor<float, 3> > gpu_in2(d_in2, 40,50,70);
|
||||
Eigen::TensorMap<Eigen::Tensor<float, 3> > gpu_out(d_out, 40,50,70);
|
||||
|
||||
GPUContext context(gpu_in1, gpu_in2, gpu_out);
|
||||
test_contextual_eval(&context);
|
||||
assert(cudaMemcpy(out.data(), d_out, out_bytes, cudaMemcpyDeviceToHost) == cudaSuccess);
|
||||
for (int i = 0; i < 40; ++i) {
|
||||
for (int j = 0; j < 50; ++j) {
|
||||
for (int k = 0; k < 70; ++k) {
|
||||
VERIFY_IS_APPROX(out(i,j,k), in1(i,j,k) + in2(i,j,k) * 3.14f + 2.718f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test_forced_contextual_eval(&context);
|
||||
assert(cudaMemcpy(out.data(), d_out, out_bytes, cudaMemcpyDeviceToHost) == cudaSuccess);
|
||||
for (int i = 0; i < 40; ++i) {
|
||||
for (int j = 0; j < 50; ++j) {
|
||||
for (int k = 0; k < 70; ++k) {
|
||||
VERIFY_IS_APPROX(out(i,j,k), (in1(i,j,k) + in2(i,j,k)) * 3.14f + 2.718f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test_compound_assignment(&context);
|
||||
assert(cudaMemcpy(out.data(), d_out, out_bytes, cudaMemcpyDeviceToHost) == cudaSuccess);
|
||||
for (int i = 0; i < 40; ++i) {
|
||||
for (int j = 0; j < 50; ++j) {
|
||||
for (int k = 0; k < 70; ++k) {
|
||||
VERIFY_IS_APPROX(out(i,j,k), in1(i,j,k) + in2(i,j,k) * 3.14f + 2.718f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test_contraction(&context);
|
||||
assert(cudaMemcpy(out.data(), d_out, out_bytes, cudaMemcpyDeviceToHost) == cudaSuccess);
|
||||
for (int i = 0; i < 40; ++i) {
|
||||
for (int j = 0; j < 40; ++j) {
|
||||
const float result = out(i,j,0);
|
||||
float expected = 0;
|
||||
for (int k = 0; k < 50; ++k) {
|
||||
for (int l = 0; l < 70; ++l) {
|
||||
expected += in1(i, k, l) * in2(j, k, l);
|
||||
}
|
||||
}
|
||||
VERIFY_IS_APPROX(expected, result);
|
||||
}
|
||||
}
|
||||
|
||||
test_1d_convolution(&context);
|
||||
assert(cudaMemcpyAsync(out.data(), d_out, out_bytes, cudaMemcpyDeviceToHost, context.device().stream()) == cudaSuccess);
|
||||
assert(cudaStreamSynchronize(context.device().stream()) == cudaSuccess);
|
||||
for (int i = 0; i < 40; ++i) {
|
||||
for (int j = 0; j < 49; ++j) {
|
||||
for (int k = 0; k < 70; ++k) {
|
||||
VERIFY_IS_APPROX(out(i,j,k), (in1(i,j,k) * 3.14f + in1(i,j+1,k) * 2.7f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test_2d_convolution(&context);
|
||||
assert(cudaMemcpyAsync(out.data(), d_out, out_bytes, cudaMemcpyDeviceToHost, context.device().stream()) == cudaSuccess);
|
||||
assert(cudaStreamSynchronize(context.device().stream()) == cudaSuccess);
|
||||
for (int i = 0; i < 40; ++i) {
|
||||
for (int j = 0; j < 49; ++j) {
|
||||
for (int k = 0; k < 69; ++k) {
|
||||
const float result = out(i,j,k);
|
||||
const float expected = (in1(i,j,k) * 3.14f + in1(i,j+1,k) * 2.7f +
|
||||
in1(i,j,k+1) * 0.2f + in1(i,j+1,k+1) * 7.0f);
|
||||
VERIFY_IS_APPROX(expected, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test_3d_convolution(&context);
|
||||
assert(cudaMemcpyAsync(out.data(), d_out, out_bytes, cudaMemcpyDeviceToHost, context.device().stream()) == cudaSuccess);
|
||||
assert(cudaStreamSynchronize(context.device().stream()) == cudaSuccess);
|
||||
for (int i = 0; i < 39; ++i) {
|
||||
for (int j = 0; j < 49; ++j) {
|
||||
for (int k = 0; k < 69; ++k) {
|
||||
const float result = out(i,j,k);
|
||||
const float expected = (in1(i,j,k) * 3.14f + in1(i,j+1,k) * 2.7f +
|
||||
in1(i,j,k+1) * 0.2f + in1(i,j+1,k+1) * 7.0f +
|
||||
in1(i+1,j,k) * -1.0f + in1(i+1,j+1,k) * -0.3f +
|
||||
in1(i+1,j,k+1) * -0.7f + in1(i+1,j+1,k+1) * -0.5f);
|
||||
VERIFY_IS_APPROX(expected, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void test_cxx11_tensor_device()
|
||||
{
|
||||
CALL_SUBTEST(test_cpu());
|
||||
CALL_SUBTEST(test_gpu());
|
||||
}
|
||||
54
unsupported/test/cxx11_tensor_dimension.cpp
Normal file
54
unsupported/test/cxx11_tensor_dimension.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#include <Eigen/CXX11/Tensor>
|
||||
|
||||
using Eigen::Tensor;
|
||||
|
||||
|
||||
static void test_dynamic_size()
|
||||
{
|
||||
Eigen::DSizes<int, 3> dimensions(2,3,7);
|
||||
|
||||
VERIFY_IS_EQUAL((int)Eigen::internal::array_get<0>(dimensions), 2);
|
||||
VERIFY_IS_EQUAL((int)Eigen::internal::array_get<1>(dimensions), 3);
|
||||
VERIFY_IS_EQUAL((int)Eigen::internal::array_get<2>(dimensions), 7);
|
||||
VERIFY_IS_EQUAL(dimensions.TotalSize(), (size_t)2*3*7);
|
||||
VERIFY_IS_EQUAL((int)dimensions[0], 2);
|
||||
VERIFY_IS_EQUAL((int)dimensions[1], 3);
|
||||
VERIFY_IS_EQUAL((int)dimensions[2], 7);
|
||||
}
|
||||
|
||||
static void test_fixed_size()
|
||||
{
|
||||
Eigen::Sizes<2,3,7> dimensions;
|
||||
|
||||
VERIFY_IS_EQUAL((int)Eigen::internal::array_get<0>(dimensions), 2);
|
||||
VERIFY_IS_EQUAL((int)Eigen::internal::array_get<1>(dimensions), 3);
|
||||
VERIFY_IS_EQUAL((int)Eigen::internal::array_get<2>(dimensions), 7);
|
||||
VERIFY_IS_EQUAL(dimensions.TotalSize(), (size_t)2*3*7);
|
||||
}
|
||||
|
||||
|
||||
static void test_match()
|
||||
{
|
||||
Eigen::DSizes<int, 3> dyn(2,3,7);
|
||||
Eigen::Sizes<2,3,7> stat;
|
||||
VERIFY_IS_EQUAL(Eigen::dimensions_match(dyn, stat), true);
|
||||
}
|
||||
|
||||
|
||||
void test_cxx11_tensor_dimension()
|
||||
{
|
||||
CALL_SUBTEST(test_dynamic_size());
|
||||
CALL_SUBTEST(test_fixed_size());
|
||||
CALL_SUBTEST(test_match());
|
||||
}
|
||||
314
unsupported/test/cxx11_tensor_expr.cpp
Normal file
314
unsupported/test/cxx11_tensor_expr.cpp
Normal file
@@ -0,0 +1,314 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#include <Eigen/CXX11/Tensor>
|
||||
|
||||
using Eigen::Tensor;
|
||||
using Eigen::RowMajor;
|
||||
|
||||
static void test_1d()
|
||||
{
|
||||
Tensor<float, 1> vec1({6});
|
||||
Tensor<float, 1, RowMajor> vec2({6});
|
||||
|
||||
vec1(0) = 4.0; vec2(0) = 0.0;
|
||||
vec1(1) = 8.0; vec2(1) = 1.0;
|
||||
vec1(2) = 15.0; vec2(2) = 2.0;
|
||||
vec1(3) = 16.0; vec2(3) = 3.0;
|
||||
vec1(4) = 23.0; vec2(4) = 4.0;
|
||||
vec1(5) = 42.0; vec2(5) = 5.0;
|
||||
|
||||
float data3[6];
|
||||
TensorMap<Tensor<float, 1>> vec3(data3, 6);
|
||||
vec3 = vec1.sqrt();
|
||||
float data4[6];
|
||||
TensorMap<Tensor<float, 1, RowMajor>> vec4(data4, 6);
|
||||
vec4 = vec2.square();
|
||||
float data5[6];
|
||||
TensorMap<Tensor<float, 1, RowMajor>> vec5(data5, 6);
|
||||
vec5 = vec2.cube();
|
||||
|
||||
VERIFY_IS_APPROX(vec3(0), sqrtf(4.0));
|
||||
VERIFY_IS_APPROX(vec3(1), sqrtf(8.0));
|
||||
VERIFY_IS_APPROX(vec3(2), sqrtf(15.0));
|
||||
VERIFY_IS_APPROX(vec3(3), sqrtf(16.0));
|
||||
VERIFY_IS_APPROX(vec3(4), sqrtf(23.0));
|
||||
VERIFY_IS_APPROX(vec3(5), sqrtf(42.0));
|
||||
|
||||
VERIFY_IS_APPROX(vec4(0), 0.0f);
|
||||
VERIFY_IS_APPROX(vec4(1), 1.0f);
|
||||
VERIFY_IS_APPROX(vec4(2), 2.0f * 2.0f);
|
||||
VERIFY_IS_APPROX(vec4(3), 3.0f * 3.0f);
|
||||
VERIFY_IS_APPROX(vec4(4), 4.0f * 4.0f);
|
||||
VERIFY_IS_APPROX(vec4(5), 5.0f * 5.0f);
|
||||
|
||||
VERIFY_IS_APPROX(vec5(0), 0.0f);
|
||||
VERIFY_IS_APPROX(vec5(1), 1.0f);
|
||||
VERIFY_IS_APPROX(vec5(2), 2.0f * 2.0f * 2.0f);
|
||||
VERIFY_IS_APPROX(vec5(3), 3.0f * 3.0f * 3.0f);
|
||||
VERIFY_IS_APPROX(vec5(4), 4.0f * 4.0f * 4.0f);
|
||||
VERIFY_IS_APPROX(vec5(5), 5.0f * 5.0f * 5.0f);
|
||||
|
||||
vec3 = vec1 + vec2;
|
||||
VERIFY_IS_APPROX(vec3(0), 4.0f + 0.0f);
|
||||
VERIFY_IS_APPROX(vec3(1), 8.0f + 1.0f);
|
||||
VERIFY_IS_APPROX(vec3(2), 15.0f + 2.0f);
|
||||
VERIFY_IS_APPROX(vec3(3), 16.0f + 3.0f);
|
||||
VERIFY_IS_APPROX(vec3(4), 23.0f + 4.0f);
|
||||
VERIFY_IS_APPROX(vec3(5), 42.0f + 5.0f);
|
||||
}
|
||||
|
||||
static void test_2d()
|
||||
{
|
||||
float data1[6];
|
||||
TensorMap<Tensor<float, 2>> mat1(data1, 2, 3);
|
||||
float data2[6];
|
||||
TensorMap<Tensor<float, 2, RowMajor>> mat2(data2, 2, 3);
|
||||
|
||||
mat1(0,0) = 0.0;
|
||||
mat1(0,1) = 1.0;
|
||||
mat1(0,2) = 2.0;
|
||||
mat1(1,0) = 3.0;
|
||||
mat1(1,1) = 4.0;
|
||||
mat1(1,2) = 5.0;
|
||||
|
||||
mat2(0,0) = -0.0;
|
||||
mat2(0,1) = -1.0;
|
||||
mat2(0,2) = -2.0;
|
||||
mat2(1,0) = -3.0;
|
||||
mat2(1,1) = -4.0;
|
||||
mat2(1,2) = -5.0;
|
||||
|
||||
Tensor<float, 2> mat3(2,3);
|
||||
Tensor<float, 2, RowMajor> mat4(2,3);
|
||||
mat3 = mat1.abs();
|
||||
mat4 = mat2.abs();
|
||||
|
||||
VERIFY_IS_APPROX(mat3(0,0), 0.0f);
|
||||
VERIFY_IS_APPROX(mat3(0,1), 1.0f);
|
||||
VERIFY_IS_APPROX(mat3(0,2), 2.0f);
|
||||
VERIFY_IS_APPROX(mat3(1,0), 3.0f);
|
||||
VERIFY_IS_APPROX(mat3(1,1), 4.0f);
|
||||
VERIFY_IS_APPROX(mat3(1,2), 5.0f);
|
||||
|
||||
VERIFY_IS_APPROX(mat4(0,0), 0.0f);
|
||||
VERIFY_IS_APPROX(mat4(0,1), 1.0f);
|
||||
VERIFY_IS_APPROX(mat4(0,2), 2.0f);
|
||||
VERIFY_IS_APPROX(mat4(1,0), 3.0f);
|
||||
VERIFY_IS_APPROX(mat4(1,1), 4.0f);
|
||||
VERIFY_IS_APPROX(mat4(1,2), 5.0f);
|
||||
}
|
||||
|
||||
static void test_3d()
|
||||
{
|
||||
Tensor<float, 3> mat1(2,3,7);
|
||||
Tensor<float, 3, RowMajor> mat2(2,3,7);
|
||||
|
||||
float val = 1.0;
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 7; ++k) {
|
||||
mat1(i,j,k) = val;
|
||||
mat2(i,j,k) = val;
|
||||
val += 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Tensor<float, 3> mat3(2,3,7);
|
||||
mat3 = mat1 + mat1;
|
||||
Tensor<float, 3, RowMajor> mat4(2,3,7);
|
||||
mat4 = mat2 * 3.14f;
|
||||
Tensor<float, 3> mat5(2,3,7);
|
||||
mat5 = mat1.inverse().log();
|
||||
Tensor<float, 3, RowMajor> mat6(2,3,7);
|
||||
mat6 = mat2.pow(0.5f) * 3.14f;
|
||||
Tensor<float, 3> mat7(2,3,7);
|
||||
mat7 = mat1.cwiseMax(mat5 * 2.0f).exp();
|
||||
Tensor<float, 3, RowMajor> mat8(2,3,7);
|
||||
mat8 = (-mat2).exp() * 3.14f;
|
||||
Tensor<float, 3, RowMajor> mat9(2,3,7);
|
||||
mat9 = mat2 + 3.14f;
|
||||
Tensor<float, 3, RowMajor> mat10(2,3,7);
|
||||
mat10 = mat2 - 3.14f;
|
||||
Tensor<float, 3, RowMajor> mat11(2,3,7);
|
||||
mat11 = mat2 / 3.14f;
|
||||
|
||||
val = 1.0;
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 7; ++k) {
|
||||
VERIFY_IS_APPROX(mat3(i,j,k), val + val);
|
||||
VERIFY_IS_APPROX(mat4(i,j,k), val * 3.14f);
|
||||
VERIFY_IS_APPROX(mat5(i,j,k), logf(1.0f/val));
|
||||
VERIFY_IS_APPROX(mat6(i,j,k), sqrtf(val) * 3.14f);
|
||||
VERIFY_IS_APPROX(mat7(i,j,k), expf((std::max)(val, mat5(i,j,k) * 2.0f)));
|
||||
VERIFY_IS_APPROX(mat8(i,j,k), expf(-val) * 3.14f);
|
||||
VERIFY_IS_APPROX(mat9(i,j,k), val + 3.14f);
|
||||
VERIFY_IS_APPROX(mat10(i,j,k), val - 3.14f);
|
||||
VERIFY_IS_APPROX(mat11(i,j,k), val / 3.14f);
|
||||
val += 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void test_constants()
|
||||
{
|
||||
Tensor<float, 3> mat1(2,3,7);
|
||||
Tensor<float, 3> mat2(2,3,7);
|
||||
Tensor<float, 3> mat3(2,3,7);
|
||||
|
||||
float val = 1.0;
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 7; ++k) {
|
||||
mat1(i,j,k) = val;
|
||||
val += 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
mat2 = mat1.constant(3.14f);
|
||||
mat3 = mat1.cwiseMax(7.3f).exp();
|
||||
|
||||
val = 1.0;
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 7; ++k) {
|
||||
VERIFY_IS_APPROX(mat2(i,j,k), 3.14f);
|
||||
VERIFY_IS_APPROX(mat3(i,j,k), expf((std::max)(val, 7.3f)));
|
||||
val += 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void test_boolean()
|
||||
{
|
||||
Tensor<int, 1> vec(6);
|
||||
std::copy_n(std::begin({0, 1, 2, 3, 4, 5}), 6, vec.data());
|
||||
|
||||
// Test ||.
|
||||
Tensor<bool, 1> bool1 = vec < vec.constant(1) || vec > vec.constant(4);
|
||||
VERIFY_IS_EQUAL(bool1[0], true);
|
||||
VERIFY_IS_EQUAL(bool1[1], false);
|
||||
VERIFY_IS_EQUAL(bool1[2], false);
|
||||
VERIFY_IS_EQUAL(bool1[3], false);
|
||||
VERIFY_IS_EQUAL(bool1[4], false);
|
||||
VERIFY_IS_EQUAL(bool1[5], true);
|
||||
|
||||
// Test &&, including cast of operand vec.
|
||||
Tensor<bool, 1> bool2 = vec.cast<bool>() && vec < vec.constant(4);
|
||||
VERIFY_IS_EQUAL(bool2[0], false);
|
||||
VERIFY_IS_EQUAL(bool2[1], true);
|
||||
VERIFY_IS_EQUAL(bool2[2], true);
|
||||
VERIFY_IS_EQUAL(bool2[3], true);
|
||||
VERIFY_IS_EQUAL(bool2[4], false);
|
||||
VERIFY_IS_EQUAL(bool2[5], false);
|
||||
|
||||
// Compilation tests:
|
||||
// Test Tensor<bool> against results of cast or comparison; verifies that
|
||||
// CoeffReturnType is set to match Op return type of bool for Unary and Binary
|
||||
// Ops.
|
||||
Tensor<bool, 1> bool3 = vec.cast<bool>() && bool2;
|
||||
bool3 = vec < vec.constant(4) && bool2;
|
||||
}
|
||||
|
||||
static void test_functors()
|
||||
{
|
||||
Tensor<float, 3> mat1(2,3,7);
|
||||
Tensor<float, 3> mat2(2,3,7);
|
||||
Tensor<float, 3> mat3(2,3,7);
|
||||
|
||||
float val = 1.0;
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 7; ++k) {
|
||||
mat1(i,j,k) = val;
|
||||
val += 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
mat2 = mat1.inverse().unaryExpr(&asinf);
|
||||
mat3 = mat1.unaryExpr(&tanhf);
|
||||
|
||||
val = 1.0;
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 7; ++k) {
|
||||
VERIFY_IS_APPROX(mat2(i,j,k), asinf(1.0f / mat1(i,j,k)));
|
||||
VERIFY_IS_APPROX(mat3(i,j,k), tanhf(mat1(i,j,k)));
|
||||
val += 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void test_type_casting()
|
||||
{
|
||||
Tensor<bool, 3> mat1(2,3,7);
|
||||
Tensor<float, 3> mat2(2,3,7);
|
||||
Tensor<double, 3> mat3(2,3,7);
|
||||
mat1.setRandom();
|
||||
mat2.setRandom();
|
||||
|
||||
mat3 = mat1.template cast<double>();
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 7; ++k) {
|
||||
VERIFY_IS_APPROX(mat3(i,j,k), mat1(i,j,k) ? 1.0 : 0.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mat3 = mat2.template cast<double>();
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 7; ++k) {
|
||||
VERIFY_IS_APPROX(mat3(i,j,k), static_cast<double>(mat2(i,j,k)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void test_select()
|
||||
{
|
||||
Tensor<float, 3> selector(2,3,7);
|
||||
Tensor<float, 3> mat1(2,3,7);
|
||||
Tensor<float, 3> mat2(2,3,7);
|
||||
Tensor<float, 3> result(2,3,7);
|
||||
|
||||
selector.setRandom();
|
||||
mat1.setRandom();
|
||||
mat2.setRandom();
|
||||
result = (selector > selector.constant(0.5f)).select(mat1, mat2);
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 7; ++k) {
|
||||
VERIFY_IS_APPROX(result(i,j,k), (selector(i,j,k) > 0.5f) ? mat1(i,j,k) : mat2(i,j,k));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void test_cxx11_tensor_expr()
|
||||
{
|
||||
CALL_SUBTEST(test_1d());
|
||||
CALL_SUBTEST(test_2d());
|
||||
CALL_SUBTEST(test_3d());
|
||||
CALL_SUBTEST(test_constants());
|
||||
CALL_SUBTEST(test_boolean());
|
||||
CALL_SUBTEST(test_functors());
|
||||
CALL_SUBTEST(test_type_casting());
|
||||
CALL_SUBTEST(test_select());
|
||||
}
|
||||
198
unsupported/test/cxx11_tensor_fixed_size.cpp
Normal file
198
unsupported/test/cxx11_tensor_fixed_size.cpp
Normal file
@@ -0,0 +1,198 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#include <Eigen/CXX11/Tensor>
|
||||
|
||||
using Eigen::Tensor;
|
||||
using Eigen::RowMajor;
|
||||
|
||||
|
||||
static void test_1d()
|
||||
{
|
||||
TensorFixedSize<float, Sizes<6> > vec1;
|
||||
TensorFixedSize<float, Sizes<6>, RowMajor> vec2;
|
||||
|
||||
VERIFY_IS_EQUAL((vec1.size()), 6);
|
||||
// VERIFY_IS_EQUAL((vec1.dimensions()[0]), 6);
|
||||
// VERIFY_IS_EQUAL((vec1.dimension(0)), 6);
|
||||
|
||||
vec1(0) = 4.0; vec2(0) = 0.0;
|
||||
vec1(1) = 8.0; vec2(1) = 1.0;
|
||||
vec1(2) = 15.0; vec2(2) = 2.0;
|
||||
vec1(3) = 16.0; vec2(3) = 3.0;
|
||||
vec1(4) = 23.0; vec2(4) = 4.0;
|
||||
vec1(5) = 42.0; vec2(5) = 5.0;
|
||||
|
||||
float data3[6];
|
||||
TensorMap<TensorFixedSize<float, Sizes<6> > > vec3(data3, 6);
|
||||
vec3 = vec1.sqrt();
|
||||
float data4[6];
|
||||
TensorMap<TensorFixedSize<float, Sizes<6>, RowMajor> > vec4(data4, 6);
|
||||
vec4 = vec2.sqrt();
|
||||
|
||||
VERIFY_IS_EQUAL((vec3.size()), 6);
|
||||
VERIFY_IS_EQUAL(vec3.rank(), 1);
|
||||
// VERIFY_IS_EQUAL((vec3.dimensions()[0]), 6);
|
||||
// VERIFY_IS_EQUAL((vec3.dimension(0)), 6);
|
||||
|
||||
VERIFY_IS_APPROX(vec3(0), sqrtf(4.0));
|
||||
VERIFY_IS_APPROX(vec3(1), sqrtf(8.0));
|
||||
VERIFY_IS_APPROX(vec3(2), sqrtf(15.0));
|
||||
VERIFY_IS_APPROX(vec3(3), sqrtf(16.0));
|
||||
VERIFY_IS_APPROX(vec3(4), sqrtf(23.0));
|
||||
VERIFY_IS_APPROX(vec3(5), sqrtf(42.0));
|
||||
|
||||
VERIFY_IS_APPROX(vec4(0), sqrtf(0.0));
|
||||
VERIFY_IS_APPROX(vec4(1), sqrtf(1.0));
|
||||
VERIFY_IS_APPROX(vec4(2), sqrtf(2.0));
|
||||
VERIFY_IS_APPROX(vec4(3), sqrtf(3.0));
|
||||
VERIFY_IS_APPROX(vec4(4), sqrtf(4.0));
|
||||
VERIFY_IS_APPROX(vec4(5), sqrtf(5.0));
|
||||
|
||||
vec3 = vec1 + vec2;
|
||||
VERIFY_IS_APPROX(vec3(0), 4.0f + 0.0f);
|
||||
VERIFY_IS_APPROX(vec3(1), 8.0f + 1.0f);
|
||||
VERIFY_IS_APPROX(vec3(2), 15.0f + 2.0f);
|
||||
VERIFY_IS_APPROX(vec3(3), 16.0f + 3.0f);
|
||||
VERIFY_IS_APPROX(vec3(4), 23.0f + 4.0f);
|
||||
VERIFY_IS_APPROX(vec3(5), 42.0f + 5.0f);
|
||||
}
|
||||
|
||||
static void test_2d()
|
||||
{
|
||||
float data1[6];
|
||||
TensorMap<TensorFixedSize<float, Sizes<2, 3> >> mat1(data1,2,3);
|
||||
float data2[6];
|
||||
TensorMap<TensorFixedSize<float, Sizes<2, 3>, RowMajor>> mat2(data2,2,3);
|
||||
|
||||
VERIFY_IS_EQUAL((mat1.size()), 2*3);
|
||||
VERIFY_IS_EQUAL(mat1.rank(), 2);
|
||||
// VERIFY_IS_EQUAL((mat1.dimension(0)), 2);
|
||||
// VERIFY_IS_EQUAL((mat1.dimension(1)), 3);
|
||||
|
||||
mat1(0,0) = 0.0;
|
||||
mat1(0,1) = 1.0;
|
||||
mat1(0,2) = 2.0;
|
||||
mat1(1,0) = 3.0;
|
||||
mat1(1,1) = 4.0;
|
||||
mat1(1,2) = 5.0;
|
||||
|
||||
mat2(0,0) = -0.0;
|
||||
mat2(0,1) = -1.0;
|
||||
mat2(0,2) = -2.0;
|
||||
mat2(1,0) = -3.0;
|
||||
mat2(1,1) = -4.0;
|
||||
mat2(1,2) = -5.0;
|
||||
|
||||
TensorFixedSize<float, Sizes<2, 3>> mat3;
|
||||
TensorFixedSize<float, Sizes<2, 3>, RowMajor> mat4;
|
||||
mat3 = mat1.abs();
|
||||
mat4 = mat2.abs();
|
||||
|
||||
VERIFY_IS_EQUAL((mat3.size()), 2*3);
|
||||
// VERIFY_IS_EQUAL((mat3.dimension(0)), 2);
|
||||
// VERIFY_IS_EQUAL((mat3.dimension(1)), 3);
|
||||
|
||||
VERIFY_IS_APPROX(mat3(0,0), 0.0f);
|
||||
VERIFY_IS_APPROX(mat3(0,1), 1.0f);
|
||||
VERIFY_IS_APPROX(mat3(0,2), 2.0f);
|
||||
VERIFY_IS_APPROX(mat3(1,0), 3.0f);
|
||||
VERIFY_IS_APPROX(mat3(1,1), 4.0f);
|
||||
VERIFY_IS_APPROX(mat3(1,2), 5.0f);
|
||||
|
||||
VERIFY_IS_APPROX(mat4(0,0), 0.0f);
|
||||
VERIFY_IS_APPROX(mat4(0,1), 1.0f);
|
||||
VERIFY_IS_APPROX(mat4(0,2), 2.0f);
|
||||
VERIFY_IS_APPROX(mat4(1,0), 3.0f);
|
||||
VERIFY_IS_APPROX(mat4(1,1), 4.0f);
|
||||
VERIFY_IS_APPROX(mat4(1,2), 5.0f);
|
||||
}
|
||||
|
||||
static void test_3d()
|
||||
{
|
||||
TensorFixedSize<float, Sizes<2, 3, 7> > mat1;
|
||||
TensorFixedSize<float, Sizes<2, 3, 7>, RowMajor> mat2;
|
||||
|
||||
VERIFY_IS_EQUAL((mat1.size()), 2*3*7);
|
||||
VERIFY_IS_EQUAL(mat1.rank(), 3);
|
||||
// VERIFY_IS_EQUAL((mat1.dimension(0)), 2);
|
||||
// VERIFY_IS_EQUAL((mat1.dimension(1)), 3);
|
||||
// VERIFY_IS_EQUAL((mat1.dimension(2)), 7);
|
||||
|
||||
float val = 0.0;
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 7; ++k) {
|
||||
mat1(i,j,k) = val;
|
||||
mat2(i,j,k) = val;
|
||||
val += 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TensorFixedSize<float, Sizes<2, 3, 7> > mat3;
|
||||
mat3 = mat1.sqrt();
|
||||
TensorFixedSize<float, Sizes<2, 3, 7>, RowMajor> mat4;
|
||||
mat4 = mat2.sqrt();
|
||||
|
||||
VERIFY_IS_EQUAL((mat3.size()), 2*3*7);
|
||||
// VERIFY_IS_EQUAL((mat3.dimension(0)), 2);
|
||||
// VERIFY_IS_EQUAL((mat3.dimension(1)), 3);
|
||||
// VERIFY_IS_EQUAL((mat3.dimension(2)), 7);
|
||||
|
||||
|
||||
val = 0.0;
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 7; ++k) {
|
||||
VERIFY_IS_APPROX(mat3(i,j,k), sqrtf(val));
|
||||
VERIFY_IS_APPROX(mat4(i,j,k), sqrtf(val));
|
||||
val += 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void test_array()
|
||||
{
|
||||
TensorFixedSize<float, Sizes<2, 3, 7> > mat1;
|
||||
float val = 0.0;
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 7; ++k) {
|
||||
mat1(i,j,k) = val;
|
||||
val += 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TensorFixedSize<float, Sizes<2, 3, 7> > mat3;
|
||||
mat3 = mat1.pow(3.5f);
|
||||
|
||||
val = 0.0;
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 7; ++k) {
|
||||
VERIFY_IS_APPROX(mat3(i,j,k), powf(val, 3.5f));
|
||||
val += 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test_cxx11_tensor_fixed_size()
|
||||
{
|
||||
CALL_SUBTEST(test_1d());
|
||||
CALL_SUBTEST(test_2d());
|
||||
CALL_SUBTEST(test_3d());
|
||||
CALL_SUBTEST(test_array());
|
||||
}
|
||||
78
unsupported/test/cxx11_tensor_forced_eval.cpp
Normal file
78
unsupported/test/cxx11_tensor_forced_eval.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#include <Eigen/Core>
|
||||
#include <Eigen/CXX11/Tensor>
|
||||
|
||||
using Eigen::MatrixXf;
|
||||
using Eigen::Tensor;
|
||||
|
||||
static void test_simple()
|
||||
{
|
||||
MatrixXf m1(3,3);
|
||||
MatrixXf m2(3,3);
|
||||
m1.setRandom();
|
||||
m2.setRandom();
|
||||
|
||||
TensorMap<Tensor<float, 2>> mat1(m1.data(), 3,3);
|
||||
TensorMap<Tensor<float, 2>> mat2(m2.data(), 3,3);
|
||||
|
||||
Tensor<float, 2> mat3(3,3);
|
||||
mat3 = mat1;
|
||||
|
||||
typedef Tensor<float, 1>::DimensionPair DimPair;
|
||||
Eigen::array<DimPair, 1> dims({{DimPair(1, 0)}});
|
||||
|
||||
mat3 = mat3.contract(mat2, dims).eval();
|
||||
|
||||
VERIFY_IS_APPROX(mat3(0, 0), (m1*m2).eval()(0,0));
|
||||
VERIFY_IS_APPROX(mat3(0, 1), (m1*m2).eval()(0,1));
|
||||
VERIFY_IS_APPROX(mat3(0, 2), (m1*m2).eval()(0,2));
|
||||
VERIFY_IS_APPROX(mat3(1, 0), (m1*m2).eval()(1,0));
|
||||
VERIFY_IS_APPROX(mat3(1, 1), (m1*m2).eval()(1,1));
|
||||
VERIFY_IS_APPROX(mat3(1, 2), (m1*m2).eval()(1,2));
|
||||
VERIFY_IS_APPROX(mat3(2, 0), (m1*m2).eval()(2,0));
|
||||
VERIFY_IS_APPROX(mat3(2, 1), (m1*m2).eval()(2,1));
|
||||
VERIFY_IS_APPROX(mat3(2, 2), (m1*m2).eval()(2,2));
|
||||
}
|
||||
|
||||
|
||||
static void test_const()
|
||||
{
|
||||
MatrixXf input(3,3);
|
||||
input.setRandom();
|
||||
MatrixXf output = input;
|
||||
output.rowwise() -= input.colwise().maxCoeff();
|
||||
|
||||
Eigen::array<int, 1> depth_dim;
|
||||
depth_dim[0] = 0;
|
||||
Tensor<float, 2>::Dimensions dims2d;
|
||||
dims2d[0] = 1;
|
||||
dims2d[1] = 3;
|
||||
Eigen::array<int, 2> bcast;
|
||||
bcast[0] = 3;
|
||||
bcast[1] = 1;
|
||||
const TensorMap<Tensor<const float, 2>> input_tensor(input.data(), 3, 3);
|
||||
Tensor<float, 2> output_tensor= (input_tensor - input_tensor.maximum(depth_dim).eval().reshape(dims2d).broadcast(bcast));
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
VERIFY_IS_APPROX(output(i, j), output_tensor(i, j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void test_cxx11_tensor_forced_eval()
|
||||
{
|
||||
CALL_SUBTEST(test_simple());
|
||||
CALL_SUBTEST(test_const());
|
||||
}
|
||||
476
unsupported/test/cxx11_tensor_image_patch.cpp
Normal file
476
unsupported/test/cxx11_tensor_image_patch.cpp
Normal file
@@ -0,0 +1,476 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#include <Eigen/CXX11/Tensor>
|
||||
|
||||
using Eigen::Tensor;
|
||||
|
||||
static void test_simple_patch()
|
||||
{
|
||||
Tensor<float, 4> tensor(2,3,5,7);
|
||||
tensor.setRandom();
|
||||
|
||||
Tensor<float, 5> single_pixel_patch;
|
||||
single_pixel_patch = tensor.extract_image_patches<1, 1>();
|
||||
|
||||
VERIFY_IS_EQUAL(single_pixel_patch.dimension(0), 2);
|
||||
VERIFY_IS_EQUAL(single_pixel_patch.dimension(1), 1);
|
||||
VERIFY_IS_EQUAL(single_pixel_patch.dimension(2), 1);
|
||||
VERIFY_IS_EQUAL(single_pixel_patch.dimension(3), 3*5);
|
||||
VERIFY_IS_EQUAL(single_pixel_patch.dimension(4), 7);
|
||||
|
||||
for (int i = 0; i < tensor.size(); ++i) {
|
||||
if (tensor.data()[i] != single_pixel_patch.data()[i]) {
|
||||
std::cout << "Mismatch detected at index " << i << " : " << tensor.data()[i] << " vs " << single_pixel_patch.data()[i] << std::endl;
|
||||
}
|
||||
VERIFY_IS_EQUAL(single_pixel_patch.data()[i], tensor.data()[i]);
|
||||
}
|
||||
|
||||
Tensor<float, 5> entire_image_patch;
|
||||
entire_image_patch = tensor.extract_image_patches<3, 5>();
|
||||
|
||||
VERIFY_IS_EQUAL(entire_image_patch.dimension(0), 2);
|
||||
VERIFY_IS_EQUAL(entire_image_patch.dimension(1), 3);
|
||||
VERIFY_IS_EQUAL(entire_image_patch.dimension(2), 5);
|
||||
VERIFY_IS_EQUAL(entire_image_patch.dimension(3), 3*5);
|
||||
VERIFY_IS_EQUAL(entire_image_patch.dimension(4), 7);
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
for (int j = 0; j < 5; ++j) {
|
||||
int patchId = i+3*j;
|
||||
for (int r = 0; r < 3; ++r) {
|
||||
for (int c = 0; c < 5; ++c) {
|
||||
for (int d = 0; d < 2; ++d) {
|
||||
for (int b = 0; b < 7; ++b) {
|
||||
float expected = 0.0f;
|
||||
if (r-1+i >= 0 && c-2+j >= 0 && r-1+i < 3 && c-2+j < 5) {
|
||||
expected = tensor(d, r-1+i, c-2+j, b);
|
||||
}
|
||||
if (entire_image_patch(d, r, c, patchId, b) != expected) {
|
||||
std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << " b=" << b << std::endl;
|
||||
}
|
||||
VERIFY_IS_EQUAL(entire_image_patch(d, r, c, patchId, b), expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Tensor<float, 5> twod_patch;
|
||||
twod_patch = tensor.extract_image_patches<2, 2>();
|
||||
|
||||
VERIFY_IS_EQUAL(twod_patch.dimension(0), 2);
|
||||
VERIFY_IS_EQUAL(twod_patch.dimension(1), 2);
|
||||
VERIFY_IS_EQUAL(twod_patch.dimension(2), 2);
|
||||
VERIFY_IS_EQUAL(twod_patch.dimension(3), 3*5);
|
||||
VERIFY_IS_EQUAL(twod_patch.dimension(4), 7);
|
||||
|
||||
// Based on the calculation described in TensorTraits.h, padding happens to be 0.
|
||||
int row_padding = 0;
|
||||
int col_padding = 0;
|
||||
int stride = 1;
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
for (int j = 0; j < 5; ++j) {
|
||||
int patchId = i+3*j;
|
||||
for (int r = 0; r < 2; ++r) {
|
||||
for (int c = 0; c < 2; ++c) {
|
||||
for (int d = 0; d < 2; ++d) {
|
||||
for (int b = 0; b < 7; ++b) {
|
||||
float expected = 0.0f;
|
||||
int row_offset = r*stride + i - row_padding;
|
||||
int col_offset = c*stride + j - col_padding;
|
||||
if (row_offset >= 0 && col_offset >= 0 && row_offset < tensor.dimension(1) && col_offset < tensor.dimension(2)) {
|
||||
expected = tensor(d, row_offset, col_offset, b);
|
||||
}
|
||||
if (twod_patch(d, r, c, patchId, b) != expected) {
|
||||
std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << " b=" << b << std::endl;
|
||||
}
|
||||
VERIFY_IS_EQUAL(twod_patch(d, r, c, patchId, b), expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Verifies VALID padding (no padding) with incrementing values.
|
||||
static void test_patch_padding_valid()
|
||||
{
|
||||
int input_depth = 3;
|
||||
int input_rows = 3;
|
||||
int input_cols = 3;
|
||||
int input_batches = 1;
|
||||
int ksize = 2; // Corresponds to the Rows and Cols for tensor.extract_image_patches<>.
|
||||
int stride = 2; // Only same stride is supported.
|
||||
Tensor<float, 4> tensor(input_depth, input_rows, input_cols, input_batches);
|
||||
// Initializes tensor with incrementing numbers.
|
||||
for (int i = 0; i < tensor.size(); ++i) {
|
||||
tensor.data()[i] = i + 1;
|
||||
}
|
||||
Tensor<float, 5> result = tensor.extract_image_patches(ksize, ksize, stride, stride, PADDING_VALID);
|
||||
|
||||
VERIFY_IS_EQUAL(result.dimension(0), input_depth); // depth
|
||||
VERIFY_IS_EQUAL(result.dimension(1), ksize); // kernel rows
|
||||
VERIFY_IS_EQUAL(result.dimension(2), ksize); // kernel cols
|
||||
VERIFY_IS_EQUAL(result.dimension(3), 1); // number of patches
|
||||
VERIFY_IS_EQUAL(result.dimension(4), input_batches); // number of batches
|
||||
|
||||
// No padding is carried out.
|
||||
int row_padding = 0;
|
||||
int col_padding = 0;
|
||||
|
||||
for (int i = 0; (i+stride+ksize-1) < input_rows; i += stride) { // input rows
|
||||
for (int j = 0; (j+stride+ksize-1) < input_cols; j += stride) { // input cols
|
||||
int patchId = i+input_rows*j;
|
||||
for (int r = 0; r < ksize; ++r) { // patch rows
|
||||
for (int c = 0; c < ksize; ++c) { // patch cols
|
||||
for (int d = 0; d < input_depth; ++d) { // depth
|
||||
for (int b = 0; b < input_batches; ++b) { // batch
|
||||
float expected = 0.0f;
|
||||
int row_offset = r + i - row_padding;
|
||||
int col_offset = c + j - col_padding;
|
||||
if (row_offset >= 0 && col_offset >= 0 && row_offset < input_rows && col_offset < input_cols) {
|
||||
expected = tensor(d, row_offset, col_offset, b);
|
||||
}
|
||||
if (result(d, r, c, patchId, b) != expected) {
|
||||
std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << " b=" << b << std::endl;
|
||||
}
|
||||
VERIFY_IS_EQUAL(result(d, r, c, patchId, b), expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Verifies VALID padding (no padding) with the same value.
|
||||
static void test_patch_padding_valid_same_value()
|
||||
{
|
||||
int input_depth = 1;
|
||||
int input_rows = 5;
|
||||
int input_cols = 5;
|
||||
int input_batches = 2;
|
||||
int ksize = 3; // Corresponds to the Rows and Cols for tensor.extract_image_patches<>.
|
||||
int stride = 2; // Only same stride is supported.
|
||||
Tensor<float, 4> tensor(input_depth, input_rows, input_cols, input_batches);
|
||||
tensor = tensor.constant(11.0f);
|
||||
Tensor<float, 5> result = tensor.extract_image_patches(ksize, ksize, stride, stride, PADDING_VALID);
|
||||
|
||||
VERIFY_IS_EQUAL(result.dimension(0), input_depth); // depth
|
||||
VERIFY_IS_EQUAL(result.dimension(1), ksize); // kernel rows
|
||||
VERIFY_IS_EQUAL(result.dimension(2), ksize); // kernel cols
|
||||
VERIFY_IS_EQUAL(result.dimension(3), 4); // number of patches
|
||||
VERIFY_IS_EQUAL(result.dimension(4), input_batches); // number of batches
|
||||
|
||||
// No padding is carried out.
|
||||
int row_padding = 0;
|
||||
int col_padding = 0;
|
||||
|
||||
for (int i = 0; (i+stride+ksize-1) <= input_rows; i += stride) { // input rows
|
||||
for (int j = 0; (j+stride+ksize-1) <= input_cols; j += stride) { // input cols
|
||||
int patchId = i+input_rows*j;
|
||||
for (int r = 0; r < ksize; ++r) { // patch rows
|
||||
for (int c = 0; c < ksize; ++c) { // patch cols
|
||||
for (int d = 0; d < input_depth; ++d) { // depth
|
||||
for (int b = 0; b < input_batches; ++b) { // batch
|
||||
float expected = 0.0f;
|
||||
int row_offset = r + i - row_padding;
|
||||
int col_offset = c + j - col_padding;
|
||||
if (row_offset >= 0 && col_offset >= 0 && row_offset < input_rows && col_offset < input_cols) {
|
||||
expected = tensor(d, row_offset, col_offset, b);
|
||||
}
|
||||
if (result(d, r, c, patchId, b) != expected) {
|
||||
std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << " b=" << b << std::endl;
|
||||
}
|
||||
VERIFY_IS_EQUAL(result(d, r, c, patchId, b), expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Verifies SAME padding.
|
||||
static void test_patch_padding_same()
|
||||
{
|
||||
int input_depth = 3;
|
||||
int input_rows = 4;
|
||||
int input_cols = 2;
|
||||
int input_batches = 1;
|
||||
int ksize = 2; // Corresponds to the Rows and Cols for tensor.extract_image_patches<>.
|
||||
int stride = 2; // Only same stride is supported.
|
||||
Tensor<float, 4> tensor(input_depth, input_rows, input_cols, input_batches);
|
||||
// Initializes tensor with incrementing numbers.
|
||||
for (int i = 0; i < tensor.size(); ++i) {
|
||||
tensor.data()[i] = i + 1;
|
||||
}
|
||||
Tensor<float, 5> result = tensor.extract_image_patches(ksize, ksize, stride, stride, PADDING_SAME);
|
||||
|
||||
VERIFY_IS_EQUAL(result.dimension(0), input_depth); // depth
|
||||
VERIFY_IS_EQUAL(result.dimension(1), ksize); // kernel rows
|
||||
VERIFY_IS_EQUAL(result.dimension(2), ksize); // kernel cols
|
||||
VERIFY_IS_EQUAL(result.dimension(3), 2); // number of patches
|
||||
VERIFY_IS_EQUAL(result.dimension(4), input_batches); // number of batches
|
||||
|
||||
// Based on the calculation described in TensorTraits.h, padding happens to be
|
||||
// 0.
|
||||
int row_padding = 0;
|
||||
int col_padding = 0;
|
||||
|
||||
for (int i = 0; (i+stride+ksize-1) <= input_rows; i += stride) { // input rows
|
||||
for (int j = 0; (j+stride+ksize-1) <= input_cols; j += stride) { // input cols
|
||||
int patchId = i+input_rows*j;
|
||||
for (int r = 0; r < ksize; ++r) { // patch rows
|
||||
for (int c = 0; c < ksize; ++c) { // patch cols
|
||||
for (int d = 0; d < input_depth; ++d) { // depth
|
||||
for (int b = 0; b < input_batches; ++b) { // batch
|
||||
float expected = 0.0f;
|
||||
int row_offset = r*stride + i - row_padding;
|
||||
int col_offset = c*stride + j - col_padding;
|
||||
if (row_offset >= 0 && col_offset >= 0 && row_offset < input_rows && col_offset < input_cols) {
|
||||
expected = tensor(d, row_offset, col_offset, b);
|
||||
}
|
||||
if (result(d, r, c, patchId, b) != expected) {
|
||||
std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << " b=" << b << std::endl;
|
||||
}
|
||||
VERIFY_IS_EQUAL(result(d, r, c, patchId, b), expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void test_patch_no_extra_dim()
|
||||
{
|
||||
Tensor<float, 3> tensor(2,3,5);
|
||||
tensor.setRandom();
|
||||
|
||||
Tensor<float, 4> single_pixel_patch;
|
||||
single_pixel_patch = tensor.extract_image_patches<1, 1>();
|
||||
|
||||
VERIFY_IS_EQUAL(single_pixel_patch.dimension(0), 2);
|
||||
VERIFY_IS_EQUAL(single_pixel_patch.dimension(1), 1);
|
||||
VERIFY_IS_EQUAL(single_pixel_patch.dimension(2), 1);
|
||||
VERIFY_IS_EQUAL(single_pixel_patch.dimension(3), 3*5);
|
||||
|
||||
for (int i = 0; i < tensor.size(); ++i) {
|
||||
if (tensor.data()[i] != single_pixel_patch.data()[i]) {
|
||||
std::cout << "Mismatch detected at index " << i << " : " << tensor.data()[i] << " vs " << single_pixel_patch.data()[i] << std::endl;
|
||||
}
|
||||
VERIFY_IS_EQUAL(single_pixel_patch.data()[i], tensor.data()[i]);
|
||||
}
|
||||
|
||||
Tensor<float, 4> entire_image_patch;
|
||||
entire_image_patch = tensor.extract_image_patches<3, 5>();
|
||||
|
||||
VERIFY_IS_EQUAL(entire_image_patch.dimension(0), 2);
|
||||
VERIFY_IS_EQUAL(entire_image_patch.dimension(1), 3);
|
||||
VERIFY_IS_EQUAL(entire_image_patch.dimension(2), 5);
|
||||
VERIFY_IS_EQUAL(entire_image_patch.dimension(3), 3*5);
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
for (int j = 0; j < 5; ++j) {
|
||||
int patchId = i+3*j;
|
||||
for (int r = 0; r < 3; ++r) {
|
||||
for (int c = 0; c < 5; ++c) {
|
||||
for (int d = 0; d < 2; ++d) {
|
||||
float expected = 0.0f;
|
||||
if (r-1+i >= 0 && c-2+j >= 0 && r-1+i < 3 && c-2+j < 5) {
|
||||
expected = tensor(d, r-1+i, c-2+j);
|
||||
}
|
||||
if (entire_image_patch(d, r, c, patchId) != expected) {
|
||||
std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << std::endl;
|
||||
}
|
||||
VERIFY_IS_EQUAL(entire_image_patch(d, r, c, patchId), expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Tensor<float, 4> twod_patch;
|
||||
twod_patch = tensor.extract_image_patches<2, 2>();
|
||||
|
||||
VERIFY_IS_EQUAL(twod_patch.dimension(0), 2);
|
||||
VERIFY_IS_EQUAL(twod_patch.dimension(1), 2);
|
||||
VERIFY_IS_EQUAL(twod_patch.dimension(2), 2);
|
||||
VERIFY_IS_EQUAL(twod_patch.dimension(3), 3*5);
|
||||
|
||||
// Based on the calculation described in TensorTraits.h, padding happens to be 0.
|
||||
int row_padding = 0;
|
||||
int col_padding = 0;
|
||||
int stride = 1;
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
for (int j = 0; j < 5; ++j) {
|
||||
int patchId = i+3*j;
|
||||
for (int r = 0; r < 2; ++r) {
|
||||
for (int c = 0; c < 2; ++c) {
|
||||
for (int d = 0; d < 2; ++d) {
|
||||
float expected = 0.0f;
|
||||
int row_offset = r*stride + i - row_padding;
|
||||
int col_offset = c*stride + j - col_padding;
|
||||
if (row_offset >= 0 && col_offset >= 0 && row_offset < tensor.dimension(1) && col_offset < tensor.dimension(2)) {
|
||||
expected = tensor(d, row_offset, col_offset);
|
||||
}
|
||||
if (twod_patch(d, r, c, patchId) != expected) {
|
||||
std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << std::endl;
|
||||
}
|
||||
VERIFY_IS_EQUAL(twod_patch(d, r, c, patchId), expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void test_imagenet_patches()
|
||||
{
|
||||
// Test the code on typical configurations used by the 'imagenet' benchmarks at
|
||||
// https://github.com/soumith/convnet-benchmarks
|
||||
Tensor<float, 4> l_in(3, 128, 128, 128);
|
||||
l_in.setRandom();
|
||||
Tensor<float, 5> l_out = l_in.extract_image_patches(11, 11);
|
||||
VERIFY_IS_EQUAL(l_out.dimension(0), 3);
|
||||
VERIFY_IS_EQUAL(l_out.dimension(1), 11);
|
||||
VERIFY_IS_EQUAL(l_out.dimension(2), 11);
|
||||
VERIFY_IS_EQUAL(l_out.dimension(3), 128*128);
|
||||
VERIFY_IS_EQUAL(l_out.dimension(4), 128);
|
||||
for (int b = 0; b < 128; ++b) {
|
||||
for (int i = 0; i < 128; ++i) {
|
||||
for (int j = 0; j < 128; ++j) {
|
||||
int patchId = i+128*j;
|
||||
for (int c = 0; c < 11; ++c) {
|
||||
for (int r = 0; r < 11; ++r) {
|
||||
for (int d = 0; d < 3; ++d) {
|
||||
float expected = 0.0f;
|
||||
if (r-5+i >= 0 && c-5+j >= 0 && r-5+i < 128 && c-5+j < 128) {
|
||||
expected = l_in(d, r-5+i, c-5+j, b);
|
||||
}
|
||||
if (l_out(d, r, c, patchId, b) != expected) {
|
||||
std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << " b=" << b << std::endl;
|
||||
}
|
||||
VERIFY_IS_EQUAL(l_out(d, r, c, patchId, b), expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
l_in.resize(64, 64, 64, 128);
|
||||
l_in.setRandom();
|
||||
l_out = l_in.extract_image_patches(9, 9);
|
||||
VERIFY_IS_EQUAL(l_out.dimension(0), 64);
|
||||
VERIFY_IS_EQUAL(l_out.dimension(1), 9);
|
||||
VERIFY_IS_EQUAL(l_out.dimension(2), 9);
|
||||
VERIFY_IS_EQUAL(l_out.dimension(3), 64*64);
|
||||
VERIFY_IS_EQUAL(l_out.dimension(4), 128);
|
||||
for (int b = 0; b < 128; ++b) {
|
||||
for (int i = 0; i < 64; ++i) {
|
||||
for (int j = 0; j < 64; ++j) {
|
||||
int patchId = i+64*j;
|
||||
for (int c = 0; c < 9; ++c) {
|
||||
for (int r = 0; r < 9; ++r) {
|
||||
for (int d = 0; d < 64; ++d) {
|
||||
float expected = 0.0f;
|
||||
if (r-4+i >= 0 && c-4+j >= 0 && r-4+i < 64 && c-4+j < 64) {
|
||||
expected = l_in(d, r-4+i, c-4+j, b);
|
||||
}
|
||||
if (l_out(d, r, c, patchId, b) != expected) {
|
||||
std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << " b=" << b << std::endl;
|
||||
}
|
||||
VERIFY_IS_EQUAL(l_out(d, r, c, patchId, b), expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
l_in.resize(128, 16, 16, 128);
|
||||
l_in.setRandom();
|
||||
l_out = l_in.extract_image_patches(7, 7);
|
||||
VERIFY_IS_EQUAL(l_out.dimension(0), 128);
|
||||
VERIFY_IS_EQUAL(l_out.dimension(1), 7);
|
||||
VERIFY_IS_EQUAL(l_out.dimension(2), 7);
|
||||
VERIFY_IS_EQUAL(l_out.dimension(3), 16*16);
|
||||
VERIFY_IS_EQUAL(l_out.dimension(4), 128);
|
||||
for (int b = 0; b < 128; ++b) {
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
for (int j = 0; j < 16; ++j) {
|
||||
int patchId = i+16*j;
|
||||
for (int c = 0; c < 7; ++c) {
|
||||
for (int r = 0; r < 7; ++r) {
|
||||
for (int d = 0; d < 128; ++d) {
|
||||
float expected = 0.0f;
|
||||
if (r-3+i >= 0 && c-3+j >= 0 && r-3+i < 16 && c-3+j < 16) {
|
||||
expected = l_in(d, r-3+i, c-3+j, b);
|
||||
}
|
||||
if (l_out(d, r, c, patchId, b) != expected) {
|
||||
std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << " b=" << b << std::endl;
|
||||
}
|
||||
VERIFY_IS_EQUAL(l_out(d, r, c, patchId, b), expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
l_in.resize(384, 13, 13, 128);
|
||||
l_in.setRandom();
|
||||
l_out = l_in.extract_image_patches(3, 3);
|
||||
VERIFY_IS_EQUAL(l_out.dimension(0), 384);
|
||||
VERIFY_IS_EQUAL(l_out.dimension(1), 3);
|
||||
VERIFY_IS_EQUAL(l_out.dimension(2), 3);
|
||||
VERIFY_IS_EQUAL(l_out.dimension(3), 13*13);
|
||||
VERIFY_IS_EQUAL(l_out.dimension(4), 128);
|
||||
for (int b = 0; b < 128; ++b) {
|
||||
for (int i = 0; i < 13; ++i) {
|
||||
for (int j = 0; j < 13; ++j) {
|
||||
int patchId = i+13*j;
|
||||
for (int c = 0; c < 3; ++c) {
|
||||
for (int r = 0; r < 3; ++r) {
|
||||
for (int d = 0; d < 384; ++d) {
|
||||
float expected = 0.0f;
|
||||
if (r-1+i >= 0 && c-1+j >= 0 && r-1+i < 13 && c-1+j < 13) {
|
||||
expected = l_in(d, r-1+i, c-1+j, b);
|
||||
}
|
||||
if (l_out(d, r, c, patchId, b) != expected) {
|
||||
std::cout << "Mismatch detected at index i=" << i << " j=" << j << " r=" << r << " c=" << c << " d=" << d << " b=" << b << std::endl;
|
||||
}
|
||||
VERIFY_IS_EQUAL(l_out(d, r, c, patchId, b), expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test_cxx11_tensor_image_patch()
|
||||
{
|
||||
CALL_SUBTEST(test_simple_patch());
|
||||
CALL_SUBTEST(test_patch_no_extra_dim());
|
||||
CALL_SUBTEST(test_patch_padding_valid());
|
||||
CALL_SUBTEST(test_patch_padding_valid_same_value());
|
||||
CALL_SUBTEST(test_patch_padding_same());
|
||||
CALL_SUBTEST(test_imagenet_patches());
|
||||
}
|
||||
268
unsupported/test/cxx11_tensor_index_list.cpp
Normal file
268
unsupported/test/cxx11_tensor_index_list.cpp
Normal file
@@ -0,0 +1,268 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#include <Eigen/CXX11/Tensor>
|
||||
|
||||
#ifdef EIGEN_HAS_CONSTEXPR
|
||||
|
||||
static void test_static_index_list()
|
||||
{
|
||||
Tensor<float, 4> tensor(2,3,5,7);
|
||||
tensor.setRandom();
|
||||
|
||||
constexpr auto reduction_axis = make_index_list(0, 1, 2);
|
||||
VERIFY_IS_EQUAL(internal::array_get<0>(reduction_axis), 0);
|
||||
VERIFY_IS_EQUAL(internal::array_get<1>(reduction_axis), 1);
|
||||
VERIFY_IS_EQUAL(internal::array_get<2>(reduction_axis), 2);
|
||||
VERIFY_IS_EQUAL(static_cast<DenseIndex>(reduction_axis[0]), 0);
|
||||
VERIFY_IS_EQUAL(static_cast<DenseIndex>(reduction_axis[1]), 1);
|
||||
VERIFY_IS_EQUAL(static_cast<DenseIndex>(reduction_axis[2]), 2);
|
||||
|
||||
EIGEN_STATIC_ASSERT((internal::array_get<0>(reduction_axis) == 0), YOU_MADE_A_PROGRAMMING_MISTAKE);
|
||||
EIGEN_STATIC_ASSERT((internal::array_get<1>(reduction_axis) == 1), YOU_MADE_A_PROGRAMMING_MISTAKE);
|
||||
EIGEN_STATIC_ASSERT((internal::array_get<2>(reduction_axis) == 2), YOU_MADE_A_PROGRAMMING_MISTAKE);
|
||||
|
||||
Tensor<float, 1> result = tensor.sum(reduction_axis);
|
||||
for (int i = 0; i < result.size(); ++i) {
|
||||
float expected = 0.0f;
|
||||
for (int j = 0; j < 2; ++j) {
|
||||
for (int k = 0; k < 3; ++k) {
|
||||
for (int l = 0; l < 5; ++l) {
|
||||
expected += tensor(j,k,l,i);
|
||||
}
|
||||
}
|
||||
}
|
||||
VERIFY_IS_APPROX(result(i), expected);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void test_type2index_list()
|
||||
{
|
||||
Tensor<float, 5> tensor(2,3,5,7,11);
|
||||
tensor.setRandom();
|
||||
tensor += tensor.constant(10.0f);
|
||||
|
||||
typedef Eigen::IndexList<Eigen::type2index<0>> Dims0;
|
||||
typedef Eigen::IndexList<Eigen::type2index<0>, Eigen::type2index<1>> Dims1;
|
||||
typedef Eigen::IndexList<Eigen::type2index<0>, Eigen::type2index<1>, Eigen::type2index<2>> Dims2;
|
||||
typedef Eigen::IndexList<Eigen::type2index<0>, Eigen::type2index<1>, Eigen::type2index<2>, Eigen::type2index<3>> Dims3;
|
||||
typedef Eigen::IndexList<Eigen::type2index<0>, Eigen::type2index<1>, Eigen::type2index<2>, Eigen::type2index<3>, Eigen::type2index<4>> Dims4;
|
||||
|
||||
#if 0
|
||||
EIGEN_STATIC_ASSERT((internal::indices_statically_known_to_increase<Dims0>()() == true), YOU_MADE_A_PROGRAMMING_MISTAKE);
|
||||
EIGEN_STATIC_ASSERT((internal::indices_statically_known_to_increase<Dims1>()() == true), YOU_MADE_A_PROGRAMMING_MISTAKE);
|
||||
EIGEN_STATIC_ASSERT((internal::indices_statically_known_to_increase<Dims2>()() == true), YOU_MADE_A_PROGRAMMING_MISTAKE);
|
||||
EIGEN_STATIC_ASSERT((internal::indices_statically_known_to_increase<Dims3>()() == true), YOU_MADE_A_PROGRAMMING_MISTAKE);
|
||||
EIGEN_STATIC_ASSERT((internal::indices_statically_known_to_increase<Dims4>()() == true), YOU_MADE_A_PROGRAMMING_MISTAKE);
|
||||
#endif
|
||||
|
||||
EIGEN_STATIC_ASSERT((internal::are_inner_most_dims<Dims0, 1, ColMajor>::value == true), YOU_MADE_A_PROGRAMMING_MISTAKE);
|
||||
EIGEN_STATIC_ASSERT((internal::are_inner_most_dims<Dims1, 2, ColMajor>::value == true), YOU_MADE_A_PROGRAMMING_MISTAKE);
|
||||
EIGEN_STATIC_ASSERT((internal::are_inner_most_dims<Dims2, 3, ColMajor>::value == true), YOU_MADE_A_PROGRAMMING_MISTAKE);
|
||||
EIGEN_STATIC_ASSERT((internal::are_inner_most_dims<Dims3, 4, ColMajor>::value == true), YOU_MADE_A_PROGRAMMING_MISTAKE);
|
||||
EIGEN_STATIC_ASSERT((internal::are_inner_most_dims<Dims4, 5, ColMajor>::value == true), YOU_MADE_A_PROGRAMMING_MISTAKE);
|
||||
|
||||
EIGEN_STATIC_ASSERT((internal::are_inner_most_dims<Dims0, 1, RowMajor>::value == true), YOU_MADE_A_PROGRAMMING_MISTAKE);
|
||||
EIGEN_STATIC_ASSERT((internal::are_inner_most_dims<Dims1, 2, RowMajor>::value == true), YOU_MADE_A_PROGRAMMING_MISTAKE);
|
||||
EIGEN_STATIC_ASSERT((internal::are_inner_most_dims<Dims2, 3, RowMajor>::value == true), YOU_MADE_A_PROGRAMMING_MISTAKE);
|
||||
EIGEN_STATIC_ASSERT((internal::are_inner_most_dims<Dims3, 4, RowMajor>::value == true), YOU_MADE_A_PROGRAMMING_MISTAKE);
|
||||
EIGEN_STATIC_ASSERT((internal::are_inner_most_dims<Dims4, 5, RowMajor>::value == true), YOU_MADE_A_PROGRAMMING_MISTAKE);
|
||||
|
||||
const Dims0 reduction_axis0;
|
||||
Tensor<float, 4> result0 = tensor.sum(reduction_axis0);
|
||||
for (int m = 0; m < 11; ++m) {
|
||||
for (int l = 0; l < 7; ++l) {
|
||||
for (int k = 0; k < 5; ++k) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
float expected = 0.0f;
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
expected += tensor(i,j,k,l,m);
|
||||
}
|
||||
VERIFY_IS_APPROX(result0(j,k,l,m), expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const Dims1 reduction_axis1;
|
||||
Tensor<float, 3> result1 = tensor.sum(reduction_axis1);
|
||||
for (int m = 0; m < 11; ++m) {
|
||||
for (int l = 0; l < 7; ++l) {
|
||||
for (int k = 0; k < 5; ++k) {
|
||||
float expected = 0.0f;
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
expected += tensor(i,j,k,l,m);
|
||||
}
|
||||
}
|
||||
VERIFY_IS_APPROX(result1(k,l,m), expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const Dims2 reduction_axis2;
|
||||
Tensor<float, 2> result2 = tensor.sum(reduction_axis2);
|
||||
for (int m = 0; m < 11; ++m) {
|
||||
for (int l = 0; l < 7; ++l) {
|
||||
float expected = 0.0f;
|
||||
for (int k = 0; k < 5; ++k) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
expected += tensor(i,j,k,l,m);
|
||||
}
|
||||
}
|
||||
}
|
||||
VERIFY_IS_APPROX(result2(l,m), expected);
|
||||
}
|
||||
}
|
||||
|
||||
const Dims3 reduction_axis3;
|
||||
Tensor<float, 1> result3 = tensor.sum(reduction_axis3);
|
||||
for (int m = 0; m < 11; ++m) {
|
||||
float expected = 0.0f;
|
||||
for (int l = 0; l < 7; ++l) {
|
||||
for (int k = 0; k < 5; ++k) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
expected += tensor(i,j,k,l,m);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
VERIFY_IS_APPROX(result3(m), expected);
|
||||
}
|
||||
|
||||
const Dims4 reduction_axis4;
|
||||
Tensor<float, 1> result4 = tensor.sum(reduction_axis4);
|
||||
float expected = 0.0f;
|
||||
for (int m = 0; m < 11; ++m) {
|
||||
for (int l = 0; l < 7; ++l) {
|
||||
for (int k = 0; k < 5; ++k) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
expected += tensor(i,j,k,l,m);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
VERIFY_IS_APPROX(result4(0), expected);
|
||||
}
|
||||
|
||||
|
||||
static void test_dynamic_index_list()
|
||||
{
|
||||
Tensor<float, 4> tensor(2,3,5,7);
|
||||
tensor.setRandom();
|
||||
|
||||
int dim1 = 2;
|
||||
int dim2 = 1;
|
||||
int dim3 = 0;
|
||||
|
||||
auto reduction_axis = make_index_list(dim1, dim2, dim3);
|
||||
|
||||
VERIFY_IS_EQUAL(internal::array_get<0>(reduction_axis), 2);
|
||||
VERIFY_IS_EQUAL(internal::array_get<1>(reduction_axis), 1);
|
||||
VERIFY_IS_EQUAL(internal::array_get<2>(reduction_axis), 0);
|
||||
VERIFY_IS_EQUAL(static_cast<DenseIndex>(reduction_axis[0]), 2);
|
||||
VERIFY_IS_EQUAL(static_cast<DenseIndex>(reduction_axis[1]), 1);
|
||||
VERIFY_IS_EQUAL(static_cast<DenseIndex>(reduction_axis[2]), 0);
|
||||
|
||||
Tensor<float, 1> result = tensor.sum(reduction_axis);
|
||||
for (int i = 0; i < result.size(); ++i) {
|
||||
float expected = 0.0f;
|
||||
for (int j = 0; j < 2; ++j) {
|
||||
for (int k = 0; k < 3; ++k) {
|
||||
for (int l = 0; l < 5; ++l) {
|
||||
expected += tensor(j,k,l,i);
|
||||
}
|
||||
}
|
||||
}
|
||||
VERIFY_IS_APPROX(result(i), expected);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_mixed_index_list()
|
||||
{
|
||||
Tensor<float, 4> tensor(2,3,5,7);
|
||||
tensor.setRandom();
|
||||
|
||||
int dim2 = 1;
|
||||
int dim4 = 3;
|
||||
|
||||
auto reduction_axis = make_index_list(0, dim2, 2, dim4);
|
||||
|
||||
VERIFY_IS_EQUAL(internal::array_get<0>(reduction_axis), 0);
|
||||
VERIFY_IS_EQUAL(internal::array_get<1>(reduction_axis), 1);
|
||||
VERIFY_IS_EQUAL(internal::array_get<2>(reduction_axis), 2);
|
||||
VERIFY_IS_EQUAL(internal::array_get<3>(reduction_axis), 3);
|
||||
VERIFY_IS_EQUAL(static_cast<DenseIndex>(reduction_axis[0]), 0);
|
||||
VERIFY_IS_EQUAL(static_cast<DenseIndex>(reduction_axis[1]), 1);
|
||||
VERIFY_IS_EQUAL(static_cast<DenseIndex>(reduction_axis[2]), 2);
|
||||
VERIFY_IS_EQUAL(static_cast<DenseIndex>(reduction_axis[3]), 3);
|
||||
|
||||
typedef IndexList<type2index<0>, int, type2index<2>, int> ReductionIndices;
|
||||
ReductionIndices reduction_indices;
|
||||
reduction_indices.set(1, 1);
|
||||
reduction_indices.set(3, 3);
|
||||
EIGEN_STATIC_ASSERT((internal::array_get<0>(reduction_indices) == 0), YOU_MADE_A_PROGRAMMING_MISTAKE);
|
||||
EIGEN_STATIC_ASSERT((internal::array_get<2>(reduction_indices) == 2), YOU_MADE_A_PROGRAMMING_MISTAKE);
|
||||
EIGEN_STATIC_ASSERT((internal::index_known_statically<ReductionIndices>()(0) == true), YOU_MADE_A_PROGRAMMING_MISTAKE);
|
||||
EIGEN_STATIC_ASSERT((internal::index_known_statically<ReductionIndices>()(2) == true), YOU_MADE_A_PROGRAMMING_MISTAKE);
|
||||
EIGEN_STATIC_ASSERT((internal::index_statically_eq<ReductionIndices>()(0, 0) == true), YOU_MADE_A_PROGRAMMING_MISTAKE);
|
||||
EIGEN_STATIC_ASSERT((internal::index_statically_eq<ReductionIndices>()(2, 2) == true), YOU_MADE_A_PROGRAMMING_MISTAKE);
|
||||
#if 0
|
||||
EIGEN_STATIC_ASSERT((internal::all_indices_known_statically<ReductionIndices>()() == false), YOU_MADE_A_PROGRAMMING_MISTAKE);
|
||||
EIGEN_STATIC_ASSERT((internal::indices_statically_known_to_increase<ReductionIndices>()() == false), YOU_MADE_A_PROGRAMMING_MISTAKE);
|
||||
#endif
|
||||
|
||||
typedef IndexList<type2index<0>, type2index<1>, type2index<2>, type2index<3>> ReductionList;
|
||||
ReductionList reduction_list;
|
||||
EIGEN_STATIC_ASSERT((internal::index_statically_eq<ReductionList>()(0, 0) == true), YOU_MADE_A_PROGRAMMING_MISTAKE);
|
||||
EIGEN_STATIC_ASSERT((internal::index_statically_eq<ReductionList>()(1, 1) == true), YOU_MADE_A_PROGRAMMING_MISTAKE);
|
||||
EIGEN_STATIC_ASSERT((internal::index_statically_eq<ReductionList>()(2, 2) == true), YOU_MADE_A_PROGRAMMING_MISTAKE);
|
||||
EIGEN_STATIC_ASSERT((internal::index_statically_eq<ReductionList>()(3, 3) == true), YOU_MADE_A_PROGRAMMING_MISTAKE);
|
||||
#if 0
|
||||
EIGEN_STATIC_ASSERT((internal::all_indices_known_statically<ReductionList>()() == true), YOU_MADE_A_PROGRAMMING_MISTAKE);
|
||||
EIGEN_STATIC_ASSERT((internal::indices_statically_known_to_increase<ReductionList>()() == true), YOU_MADE_A_PROGRAMMING_MISTAKE);
|
||||
#endif
|
||||
|
||||
Tensor<float, 1> result1 = tensor.sum(reduction_axis);
|
||||
Tensor<float, 1> result2 = tensor.sum(reduction_indices);
|
||||
Tensor<float, 1> result3 = tensor.sum(reduction_list);
|
||||
|
||||
float expected = 0.0f;
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 5; ++k) {
|
||||
for (int l = 0; l < 7; ++l) {
|
||||
expected += tensor(i,j,k,l);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
VERIFY_IS_APPROX(result1(0), expected);
|
||||
VERIFY_IS_APPROX(result2(0), expected);
|
||||
VERIFY_IS_APPROX(result3(0), expected);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void test_cxx11_tensor_index_list()
|
||||
{
|
||||
#ifdef EIGEN_HAS_CONSTEXPR
|
||||
CALL_SUBTEST(test_static_index_list());
|
||||
CALL_SUBTEST(test_type2index_list());
|
||||
CALL_SUBTEST(test_dynamic_index_list());
|
||||
CALL_SUBTEST(test_mixed_index_list());
|
||||
#endif
|
||||
}
|
||||
77
unsupported/test/cxx11_tensor_intdiv.cpp
Normal file
77
unsupported/test/cxx11_tensor_intdiv.cpp
Normal file
@@ -0,0 +1,77 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#include <Eigen/CXX11/Tensor>
|
||||
|
||||
|
||||
static void test_signed_32bit()
|
||||
{
|
||||
for (int32_t i = 1; i < 25000; ++i) {
|
||||
const Eigen::internal::TensorIntDivisor<int32_t> div(i);
|
||||
|
||||
for (int32_t j = 0; j < 25000; ++j) {
|
||||
const int32_t fast_div = j / div;
|
||||
const int32_t slow_div = j / i;
|
||||
VERIFY_IS_EQUAL(fast_div, slow_div);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void test_unsigned_32bit()
|
||||
{
|
||||
for (uint32_t i = 1; i < 25000; ++i) {
|
||||
const Eigen::internal::TensorIntDivisor<uint32_t> div(i);
|
||||
|
||||
for (uint32_t j = 0; j < 25000; ++j) {
|
||||
const uint32_t fast_div = j / div;
|
||||
const uint32_t slow_div = j / i;
|
||||
VERIFY_IS_EQUAL(fast_div, slow_div);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void test_signed_64bit()
|
||||
{
|
||||
for (int64_t i = 2; i < 25000; ++i) {
|
||||
const Eigen::internal::TensorIntDivisor<int64_t> div(i);
|
||||
|
||||
for (int64_t j = 0; j < 25000; ++j) {
|
||||
const int64_t fast_div = j / div;
|
||||
const int64_t slow_div = j / i;
|
||||
VERIFY_IS_EQUAL(fast_div, slow_div);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void test_unsigned_64bit()
|
||||
{
|
||||
for (uint64_t i = 2; i < 25000; ++i) {
|
||||
const Eigen::internal::TensorIntDivisor<uint64_t> div(i);
|
||||
|
||||
for (uint64_t j = 0; j < 25000; ++j) {
|
||||
const uint64_t fast_div = j / div;
|
||||
const uint64_t slow_div = j / i;
|
||||
VERIFY_IS_EQUAL(fast_div, slow_div);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void test_cxx11_tensor_intdiv()
|
||||
{
|
||||
CALL_SUBTEST(test_signed_32bit());
|
||||
CALL_SUBTEST(test_unsigned_32bit());
|
||||
CALL_SUBTEST(test_signed_64bit());
|
||||
CALL_SUBTEST(test_unsigned_64bit());
|
||||
}
|
||||
114
unsupported/test/cxx11_tensor_io.cpp
Normal file
114
unsupported/test/cxx11_tensor_io.cpp
Normal file
@@ -0,0 +1,114 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "main.h"
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <Eigen/CXX11/Tensor>
|
||||
|
||||
|
||||
template<int DataLayout>
|
||||
static void test_output_1d()
|
||||
{
|
||||
Tensor<int, 1, DataLayout> tensor(5);
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
tensor(i) = i;
|
||||
}
|
||||
|
||||
std::stringstream os;
|
||||
os << tensor;
|
||||
|
||||
std::string expected("0\n1\n2\n3\n4");
|
||||
VERIFY_IS_EQUAL(std::string(os.str()), expected);
|
||||
}
|
||||
|
||||
|
||||
template<int DataLayout>
|
||||
static void test_output_2d()
|
||||
{
|
||||
Tensor<int, 2, DataLayout> tensor(5, 3);
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
tensor(i, j) = i*j;
|
||||
}
|
||||
}
|
||||
|
||||
std::stringstream os;
|
||||
os << tensor;
|
||||
|
||||
std::string expected("0 0 0\n0 1 2\n0 2 4\n0 3 6\n0 4 8");
|
||||
VERIFY_IS_EQUAL(std::string(os.str()), expected);
|
||||
}
|
||||
|
||||
|
||||
template<int DataLayout>
|
||||
static void test_output_expr()
|
||||
{
|
||||
Tensor<int, 1, DataLayout> tensor1(5);
|
||||
Tensor<int, 1, DataLayout> tensor2(5);
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
tensor1(i) = i;
|
||||
tensor2(i) = 7;
|
||||
}
|
||||
|
||||
std::stringstream os;
|
||||
os << tensor1 + tensor2;
|
||||
|
||||
std::string expected(" 7\n 8\n 9\n10\n11");
|
||||
VERIFY_IS_EQUAL(std::string(os.str()), expected);
|
||||
}
|
||||
|
||||
|
||||
template<int DataLayout>
|
||||
static void test_output_string()
|
||||
{
|
||||
Tensor<std::string, 2, DataLayout> tensor(5, 3);
|
||||
tensor.setConstant(std::string("foo"));
|
||||
|
||||
std::cout << tensor << std::endl;
|
||||
|
||||
std::stringstream os;
|
||||
os << tensor;
|
||||
|
||||
std::string expected("foo foo foo\nfoo foo foo\nfoo foo foo\nfoo foo foo\nfoo foo foo");
|
||||
VERIFY_IS_EQUAL(std::string(os.str()), expected);
|
||||
}
|
||||
|
||||
|
||||
template<int DataLayout>
|
||||
static void test_output_const()
|
||||
{
|
||||
Tensor<int, 1, DataLayout> tensor(5);
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
tensor(i) = i;
|
||||
}
|
||||
|
||||
TensorMap<Tensor<const int, 1, DataLayout> > tensor_map(tensor.data(), 5);
|
||||
|
||||
std::stringstream os;
|
||||
os << tensor_map;
|
||||
|
||||
std::string expected("0\n1\n2\n3\n4");
|
||||
VERIFY_IS_EQUAL(std::string(os.str()), expected);
|
||||
}
|
||||
|
||||
|
||||
void test_cxx11_tensor_io()
|
||||
{
|
||||
CALL_SUBTEST(test_output_1d<ColMajor>());
|
||||
CALL_SUBTEST(test_output_1d<RowMajor>());
|
||||
CALL_SUBTEST(test_output_2d<ColMajor>());
|
||||
CALL_SUBTEST(test_output_2d<RowMajor>());
|
||||
CALL_SUBTEST(test_output_expr<ColMajor>());
|
||||
CALL_SUBTEST(test_output_expr<RowMajor>());
|
||||
CALL_SUBTEST(test_output_string<ColMajor>());
|
||||
CALL_SUBTEST(test_output_string<RowMajor>());
|
||||
CALL_SUBTEST(test_output_const<ColMajor>());
|
||||
CALL_SUBTEST(test_output_const<RowMajor>());
|
||||
}
|
||||
61
unsupported/test/cxx11_tensor_layout_swap.cpp
Normal file
61
unsupported/test/cxx11_tensor_layout_swap.cpp
Normal file
@@ -0,0 +1,61 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#include <Eigen/CXX11/Tensor>
|
||||
|
||||
using Eigen::Tensor;
|
||||
|
||||
static void test_simple_swap()
|
||||
{
|
||||
Tensor<float, 3, ColMajor> tensor(2,3,7);
|
||||
tensor.setRandom();
|
||||
|
||||
Tensor<float, 3, RowMajor> tensor2 = tensor.swap_layout();
|
||||
VERIFY_IS_EQUAL(tensor.dimension(0), tensor2.dimension(2));
|
||||
VERIFY_IS_EQUAL(tensor.dimension(1), tensor2.dimension(1));
|
||||
VERIFY_IS_EQUAL(tensor.dimension(2), tensor2.dimension(0));
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 7; ++k) {
|
||||
VERIFY_IS_EQUAL(tensor(i,j,k), tensor2(k,j,i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void test_swap_as_lvalue()
|
||||
{
|
||||
Tensor<float, 3, ColMajor> tensor(2,3,7);
|
||||
tensor.setRandom();
|
||||
|
||||
Tensor<float, 3, RowMajor> tensor2(7,3,2);
|
||||
tensor2.swap_layout() = tensor;
|
||||
VERIFY_IS_EQUAL(tensor.dimension(0), tensor2.dimension(2));
|
||||
VERIFY_IS_EQUAL(tensor.dimension(1), tensor2.dimension(1));
|
||||
VERIFY_IS_EQUAL(tensor.dimension(2), tensor2.dimension(0));
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 7; ++k) {
|
||||
VERIFY_IS_EQUAL(tensor(i,j,k), tensor2(k,j,i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void test_cxx11_tensor_layout_swap()
|
||||
{
|
||||
CALL_SUBTEST(test_simple_swap());
|
||||
CALL_SUBTEST(test_swap_as_lvalue());
|
||||
}
|
||||
42
unsupported/test/cxx11_tensor_lvalue.cpp
Normal file
42
unsupported/test/cxx11_tensor_lvalue.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#include <Eigen/CXX11/Tensor>
|
||||
|
||||
using Eigen::Tensor;
|
||||
using Eigen::RowMajor;
|
||||
|
||||
|
||||
static void test_compound_assignment()
|
||||
{
|
||||
Tensor<float, 3> mat1(2,3,7);
|
||||
Tensor<float, 3> mat2(2,3,7);
|
||||
Tensor<float, 3> mat3(2,3,7);
|
||||
|
||||
mat1.setRandom();
|
||||
mat2.setRandom();
|
||||
mat3 = mat1;
|
||||
mat3 += mat2;
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 7; ++k) {
|
||||
VERIFY_IS_APPROX(mat3(i,j,k), mat1(i,j,k) + mat2(i,j,k));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void test_cxx11_tensor_lvalue()
|
||||
{
|
||||
CALL_SUBTEST(test_compound_assignment());
|
||||
}
|
||||
147
unsupported/test/cxx11_tensor_map.cpp
Normal file
147
unsupported/test/cxx11_tensor_map.cpp
Normal file
@@ -0,0 +1,147 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#include <Eigen/CXX11/Tensor>
|
||||
|
||||
using Eigen::Tensor;
|
||||
using Eigen::RowMajor;
|
||||
|
||||
static void test_1d()
|
||||
{
|
||||
Tensor<int, 1> vec1(6);
|
||||
Tensor<int, 1, RowMajor> vec2(6);
|
||||
|
||||
TensorMap<Tensor<const int, 1>> vec3(vec1.data(), 6);
|
||||
TensorMap<Tensor<const int, 1, RowMajor>> vec4(vec2.data(), 6);
|
||||
|
||||
vec1(0) = 4; vec2(0) = 0;
|
||||
vec1(1) = 8; vec2(1) = 1;
|
||||
vec1(2) = 15; vec2(2) = 2;
|
||||
vec1(3) = 16; vec2(3) = 3;
|
||||
vec1(4) = 23; vec2(4) = 4;
|
||||
vec1(5) = 42; vec2(5) = 5;
|
||||
|
||||
VERIFY_IS_EQUAL(vec1.rank(), 1);
|
||||
VERIFY_IS_EQUAL(vec1.size(), 6);
|
||||
VERIFY_IS_EQUAL(vec1.dimension(0), 6);
|
||||
|
||||
VERIFY_IS_EQUAL(vec3(0), 4);
|
||||
VERIFY_IS_EQUAL(vec3(1), 8);
|
||||
VERIFY_IS_EQUAL(vec3(2), 15);
|
||||
VERIFY_IS_EQUAL(vec3(3), 16);
|
||||
VERIFY_IS_EQUAL(vec3(4), 23);
|
||||
VERIFY_IS_EQUAL(vec3(5), 42);
|
||||
|
||||
VERIFY_IS_EQUAL(vec4(0), 0);
|
||||
VERIFY_IS_EQUAL(vec4(1), 1);
|
||||
VERIFY_IS_EQUAL(vec4(2), 2);
|
||||
VERIFY_IS_EQUAL(vec4(3), 3);
|
||||
VERIFY_IS_EQUAL(vec4(4), 4);
|
||||
VERIFY_IS_EQUAL(vec4(5), 5);
|
||||
}
|
||||
|
||||
static void test_2d()
|
||||
{
|
||||
Tensor<int, 2> mat1(2,3);
|
||||
Tensor<int, 2, RowMajor> mat2(2,3);
|
||||
|
||||
mat1(0,0) = 0;
|
||||
mat1(0,1) = 1;
|
||||
mat1(0,2) = 2;
|
||||
mat1(1,0) = 3;
|
||||
mat1(1,1) = 4;
|
||||
mat1(1,2) = 5;
|
||||
|
||||
mat2(0,0) = 0;
|
||||
mat2(0,1) = 1;
|
||||
mat2(0,2) = 2;
|
||||
mat2(1,0) = 3;
|
||||
mat2(1,1) = 4;
|
||||
mat2(1,2) = 5;
|
||||
|
||||
TensorMap<Tensor<const int, 2>> mat3(mat1.data(), 2, 3);
|
||||
TensorMap<Tensor<const int, 2, RowMajor>> mat4(mat2.data(), 2, 3);
|
||||
|
||||
VERIFY_IS_EQUAL(mat3.rank(), 2);
|
||||
VERIFY_IS_EQUAL(mat3.size(), 6);
|
||||
VERIFY_IS_EQUAL(mat3.dimension(0), 2);
|
||||
VERIFY_IS_EQUAL(mat3.dimension(1), 3);
|
||||
|
||||
VERIFY_IS_EQUAL(mat4.rank(), 2);
|
||||
VERIFY_IS_EQUAL(mat4.size(), 6);
|
||||
VERIFY_IS_EQUAL(mat4.dimension(0), 2);
|
||||
VERIFY_IS_EQUAL(mat4.dimension(1), 3);
|
||||
|
||||
VERIFY_IS_EQUAL(mat3(0,0), 0);
|
||||
VERIFY_IS_EQUAL(mat3(0,1), 1);
|
||||
VERIFY_IS_EQUAL(mat3(0,2), 2);
|
||||
VERIFY_IS_EQUAL(mat3(1,0), 3);
|
||||
VERIFY_IS_EQUAL(mat3(1,1), 4);
|
||||
VERIFY_IS_EQUAL(mat3(1,2), 5);
|
||||
|
||||
VERIFY_IS_EQUAL(mat4(0,0), 0);
|
||||
VERIFY_IS_EQUAL(mat4(0,1), 1);
|
||||
VERIFY_IS_EQUAL(mat4(0,2), 2);
|
||||
VERIFY_IS_EQUAL(mat4(1,0), 3);
|
||||
VERIFY_IS_EQUAL(mat4(1,1), 4);
|
||||
VERIFY_IS_EQUAL(mat4(1,2), 5);
|
||||
}
|
||||
|
||||
static void test_3d()
|
||||
{
|
||||
Tensor<int, 3> mat1(2,3,7);
|
||||
Tensor<int, 3, RowMajor> mat2(2,3,7);
|
||||
|
||||
int val = 0;
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 7; ++k) {
|
||||
mat1(i,j,k) = val;
|
||||
mat2(i,j,k) = val;
|
||||
val++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TensorMap<Tensor<const int, 3>> mat3(mat1.data(), 2, 3, 7);
|
||||
TensorMap<Tensor<const int, 3, RowMajor>> mat4(mat2.data(), array<DenseIndex, 3>{{2, 3, 7}});
|
||||
|
||||
VERIFY_IS_EQUAL(mat3.rank(), 3);
|
||||
VERIFY_IS_EQUAL(mat3.size(), 2*3*7);
|
||||
VERIFY_IS_EQUAL(mat3.dimension(0), 2);
|
||||
VERIFY_IS_EQUAL(mat3.dimension(1), 3);
|
||||
VERIFY_IS_EQUAL(mat3.dimension(2), 7);
|
||||
|
||||
VERIFY_IS_EQUAL(mat4.rank(), 3);
|
||||
VERIFY_IS_EQUAL(mat4.size(), 2*3*7);
|
||||
VERIFY_IS_EQUAL(mat4.dimension(0), 2);
|
||||
VERIFY_IS_EQUAL(mat4.dimension(1), 3);
|
||||
VERIFY_IS_EQUAL(mat4.dimension(2), 7);
|
||||
|
||||
val = 0;
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 7; ++k) {
|
||||
VERIFY_IS_EQUAL(mat3(i,j,k), val);
|
||||
VERIFY_IS_EQUAL(mat4(i,j,k), val);
|
||||
val++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void test_cxx11_tensor_map()
|
||||
{
|
||||
CALL_SUBTEST(test_1d());
|
||||
CALL_SUBTEST(test_2d());
|
||||
CALL_SUBTEST(test_3d());
|
||||
}
|
||||
342
unsupported/test/cxx11_tensor_morphing.cpp
Normal file
342
unsupported/test/cxx11_tensor_morphing.cpp
Normal file
@@ -0,0 +1,342 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#include <Eigen/CXX11/Tensor>
|
||||
|
||||
using Eigen::Tensor;
|
||||
|
||||
static void test_simple_reshape()
|
||||
{
|
||||
Tensor<float, 5> tensor1(2,3,1,7,1);
|
||||
tensor1.setRandom();
|
||||
|
||||
Tensor<float, 3> tensor2(2,3,7);
|
||||
Tensor<float, 2> tensor3(6,7);
|
||||
Tensor<float, 2> tensor4(2,21);
|
||||
|
||||
Tensor<float, 3>::Dimensions dim1{{2,3,7}};
|
||||
tensor2 = tensor1.reshape(dim1);
|
||||
Tensor<float, 2>::Dimensions dim2{{6,7}};
|
||||
tensor3 = tensor1.reshape(dim2);
|
||||
Tensor<float, 2>::Dimensions dim3{{2,21}};
|
||||
tensor4 = tensor1.reshape(dim1).reshape(dim3);
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 7; ++k) {
|
||||
VERIFY_IS_EQUAL(tensor1(i,j,0,k,0), tensor2(i,j,k));
|
||||
VERIFY_IS_EQUAL(tensor1(i,j,0,k,0), tensor3(i+2*j,k));
|
||||
VERIFY_IS_EQUAL(tensor1(i,j,0,k,0), tensor4(i,j+3*k));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void test_reshape_in_expr() {
|
||||
MatrixXf m1(2,3*5*7*11);
|
||||
MatrixXf m2(3*5*7*11,13);
|
||||
m1.setRandom();
|
||||
m2.setRandom();
|
||||
MatrixXf m3 = m1 * m2;
|
||||
|
||||
TensorMap<Tensor<float, 5>> tensor1(m1.data(), 2,3,5,7,11);
|
||||
TensorMap<Tensor<float, 5>> tensor2(m2.data(), 3,5,7,11,13);
|
||||
Tensor<float, 2>::Dimensions newDims1{{2,3*5*7*11}};
|
||||
Tensor<float, 2>::Dimensions newDims2{{3*5*7*11,13}};
|
||||
typedef Tensor<float, 1>::DimensionPair DimPair;
|
||||
array<DimPair, 1> contract_along{{DimPair(1, 0)}};
|
||||
Tensor<float, 2> tensor3(2,13);
|
||||
tensor3 = tensor1.reshape(newDims1).contract(tensor2.reshape(newDims2), contract_along);
|
||||
|
||||
Map<MatrixXf> res(tensor3.data(), 2, 13);
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 13; ++j) {
|
||||
VERIFY_IS_APPROX(res(i,j), m3(i,j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void test_reshape_as_lvalue()
|
||||
{
|
||||
Tensor<float, 3> tensor(2,3,7);
|
||||
tensor.setRandom();
|
||||
|
||||
Tensor<float, 2> tensor2d(6,7);
|
||||
Tensor<float, 3>::Dimensions dim{{2,3,7}};
|
||||
tensor2d.reshape(dim) = tensor;
|
||||
|
||||
float scratch[2*3*1*7*1];
|
||||
TensorMap<Tensor<float, 5>> tensor5d(scratch, 2,3,1,7,1);
|
||||
tensor5d.reshape(dim).device(Eigen::DefaultDevice()) = tensor;
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 7; ++k) {
|
||||
VERIFY_IS_EQUAL(tensor2d(i+2*j,k), tensor(i,j,k));
|
||||
VERIFY_IS_EQUAL(tensor5d(i,j,0,k,0), tensor(i,j,k));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<int DataLayout>
|
||||
static void test_simple_slice()
|
||||
{
|
||||
Tensor<float, 5, DataLayout> tensor(2,3,5,7,11);
|
||||
tensor.setRandom();
|
||||
|
||||
Tensor<float, 5, DataLayout> slice1(1,1,1,1,1);
|
||||
Eigen::DSizes<ptrdiff_t, 5> indices(1,2,3,4,5);
|
||||
Eigen::DSizes<ptrdiff_t, 5> sizes(1,1,1,1,1);
|
||||
slice1 = tensor.slice(indices, sizes);
|
||||
VERIFY_IS_EQUAL(slice1(0,0,0,0,0), tensor(1,2,3,4,5));
|
||||
|
||||
Tensor<float, 5, DataLayout> slice2(1,1,2,2,3);
|
||||
Eigen::DSizes<ptrdiff_t, 5> indices2(1,1,3,4,5);
|
||||
Eigen::DSizes<ptrdiff_t, 5> sizes2(1,1,2,2,3);
|
||||
slice2 = tensor.slice(indices2, sizes2);
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 2; ++j) {
|
||||
for (int k = 0; k < 3; ++k) {
|
||||
VERIFY_IS_EQUAL(slice2(0,0,i,j,k), tensor(1,1,3+i,4+j,5+k));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(andydavis) Add RowMajor support when TensorContract supports RowMajor.
|
||||
static void test_slice_in_expr() {
|
||||
MatrixXf m1(7,7);
|
||||
MatrixXf m2(3,3);
|
||||
m1.setRandom();
|
||||
m2.setRandom();
|
||||
|
||||
MatrixXf m3 = m1.block(1, 2, 3, 3) * m2.block(0, 2, 3, 1);
|
||||
|
||||
TensorMap<Tensor<float, 2>> tensor1(m1.data(), 7, 7);
|
||||
TensorMap<Tensor<float, 2>> tensor2(m2.data(), 3, 3);
|
||||
Tensor<float, 2> tensor3(3,1);
|
||||
typedef Tensor<float, 1>::DimensionPair DimPair;
|
||||
array<DimPair, 1> contract_along{{DimPair(1, 0)}};
|
||||
|
||||
Eigen::DSizes<ptrdiff_t, 2> indices1(1,2);
|
||||
Eigen::DSizes<ptrdiff_t, 2> sizes1(3,3);
|
||||
Eigen::DSizes<ptrdiff_t, 2> indices2(0,2);
|
||||
Eigen::DSizes<ptrdiff_t, 2> sizes2(3,1);
|
||||
tensor3 = tensor1.slice(indices1, sizes1).contract(tensor2.slice(indices2, sizes2), contract_along);
|
||||
|
||||
Map<MatrixXf> res(tensor3.data(), 3, 1);
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
for (int j = 0; j < 1; ++j) {
|
||||
VERIFY_IS_APPROX(res(i,j), m3(i,j));
|
||||
}
|
||||
}
|
||||
|
||||
// Take an arbitrary slice of an arbitrarily sized tensor.
|
||||
TensorMap<Tensor<const float, 2>> tensor4(m1.data(), 7, 7);
|
||||
Tensor<float, 1> tensor6 = tensor4.reshape(DSizes<ptrdiff_t, 1>(7*7)).exp().slice(DSizes<ptrdiff_t, 1>(0), DSizes<ptrdiff_t, 1>(35));
|
||||
for (int i = 0; i < 35; ++i) {
|
||||
VERIFY_IS_APPROX(tensor6(i), expf(tensor4.data()[i]));
|
||||
}
|
||||
}
|
||||
|
||||
template<int DataLayout>
|
||||
static void test_slice_as_lvalue()
|
||||
{
|
||||
Tensor<float, 3, DataLayout> tensor1(2,2,7);
|
||||
tensor1.setRandom();
|
||||
Tensor<float, 3, DataLayout> tensor2(2,2,7);
|
||||
tensor2.setRandom();
|
||||
Tensor<float, 3, DataLayout> tensor3(4,3,5);
|
||||
tensor3.setRandom();
|
||||
Tensor<float, 3, DataLayout> tensor4(4,3,2);
|
||||
tensor4.setRandom();
|
||||
Tensor<float, 3, DataLayout> tensor5(10,13,12);
|
||||
tensor5.setRandom();
|
||||
|
||||
Tensor<float, 3, DataLayout> result(4,5,7);
|
||||
Eigen::DSizes<ptrdiff_t, 3> sizes12(2,2,7);
|
||||
Eigen::DSizes<ptrdiff_t, 3> first_slice(0,0,0);
|
||||
result.slice(first_slice, sizes12) = tensor1;
|
||||
Eigen::DSizes<ptrdiff_t, 3> second_slice(2,0,0);
|
||||
result.slice(second_slice, sizes12).device(Eigen::DefaultDevice()) = tensor2;
|
||||
|
||||
Eigen::DSizes<ptrdiff_t, 3> sizes3(4,3,5);
|
||||
Eigen::DSizes<ptrdiff_t, 3> third_slice(0,2,0);
|
||||
result.slice(third_slice, sizes3) = tensor3;
|
||||
|
||||
Eigen::DSizes<ptrdiff_t, 3> sizes4(4,3,2);
|
||||
Eigen::DSizes<ptrdiff_t, 3> fourth_slice(0,2,5);
|
||||
result.slice(fourth_slice, sizes4) = tensor4;
|
||||
|
||||
for (int j = 0; j < 2; ++j) {
|
||||
for (int k = 0; k < 7; ++k) {
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
VERIFY_IS_EQUAL(result(i,j,k), tensor1(i,j,k));
|
||||
VERIFY_IS_EQUAL(result(i+2,j,k), tensor2(i,j,k));
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
for (int j = 2; j < 5; ++j) {
|
||||
for (int k = 0; k < 5; ++k) {
|
||||
VERIFY_IS_EQUAL(result(i,j,k), tensor3(i,j-2,k));
|
||||
}
|
||||
for (int k = 5; k < 7; ++k) {
|
||||
VERIFY_IS_EQUAL(result(i,j,k), tensor4(i,j-2,k-5));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Eigen::DSizes<ptrdiff_t, 3> sizes5(4,5,7);
|
||||
Eigen::DSizes<ptrdiff_t, 3> fifth_slice(0,0,0);
|
||||
result.slice(fifth_slice, sizes5) = tensor5.slice(fifth_slice, sizes5);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
for (int j = 2; j < 5; ++j) {
|
||||
for (int k = 0; k < 7; ++k) {
|
||||
VERIFY_IS_EQUAL(result(i,j,k), tensor5(i,j,k));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<int DataLayout>
|
||||
static void test_slice_raw_data()
|
||||
{
|
||||
Tensor<float, 4, DataLayout> tensor(3,5,7,11);
|
||||
tensor.setRandom();
|
||||
|
||||
Eigen::DSizes<ptrdiff_t, 4> offsets(1,2,3,4);
|
||||
Eigen::DSizes<ptrdiff_t, 4> extents(1,1,1,1);
|
||||
typedef TensorEvaluator<decltype(tensor.slice(offsets, extents)), DefaultDevice> SliceEvaluator;
|
||||
auto slice1 = SliceEvaluator(tensor.slice(offsets, extents), DefaultDevice());
|
||||
VERIFY_IS_EQUAL(slice1.dimensions().TotalSize(), 1ul);
|
||||
VERIFY_IS_EQUAL(slice1.data()[0], tensor(1,2,3,4));
|
||||
|
||||
if (DataLayout == ColMajor) {
|
||||
extents = Eigen::DSizes<ptrdiff_t, 4>(2,1,1,1);
|
||||
auto slice2 = SliceEvaluator(tensor.slice(offsets, extents), DefaultDevice());
|
||||
VERIFY_IS_EQUAL(slice2.dimensions().TotalSize(), 2ul);
|
||||
VERIFY_IS_EQUAL(slice2.data()[0], tensor(1,2,3,4));
|
||||
VERIFY_IS_EQUAL(slice2.data()[1], tensor(2,2,3,4));
|
||||
} else {
|
||||
extents = Eigen::DSizes<ptrdiff_t, 4>(1,1,1,2);
|
||||
auto slice2 = SliceEvaluator(tensor.slice(offsets, extents), DefaultDevice());
|
||||
VERIFY_IS_EQUAL(slice2.dimensions().TotalSize(), 2ul);
|
||||
VERIFY_IS_EQUAL(slice2.data()[0], tensor(1,2,3,4));
|
||||
VERIFY_IS_EQUAL(slice2.data()[1], tensor(1,2,3,5));
|
||||
}
|
||||
|
||||
extents = Eigen::DSizes<ptrdiff_t, 4>(1,2,1,1);
|
||||
auto slice3 = SliceEvaluator(tensor.slice(offsets, extents), DefaultDevice());
|
||||
VERIFY_IS_EQUAL(slice3.dimensions().TotalSize(), 2ul);
|
||||
VERIFY_IS_EQUAL(slice3.data(), static_cast<float*>(0));
|
||||
|
||||
if (DataLayout == ColMajor) {
|
||||
offsets = Eigen::DSizes<ptrdiff_t, 4>(0,2,3,4);
|
||||
extents = Eigen::DSizes<ptrdiff_t, 4>(3,2,1,1);
|
||||
auto slice4 = SliceEvaluator(tensor.slice(offsets, extents), DefaultDevice());
|
||||
VERIFY_IS_EQUAL(slice4.dimensions().TotalSize(), 6ul);
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
for (int j = 0; j < 2; ++j) {
|
||||
VERIFY_IS_EQUAL(slice4.data()[i+3*j], tensor(i,2+j,3,4));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
offsets = Eigen::DSizes<ptrdiff_t, 4>(1,2,3,0);
|
||||
extents = Eigen::DSizes<ptrdiff_t, 4>(1,1,2,11);
|
||||
auto slice4 = SliceEvaluator(tensor.slice(offsets, extents), DefaultDevice());
|
||||
VERIFY_IS_EQUAL(slice4.dimensions().TotalSize(), 22ul);
|
||||
for (int l = 0; l < 11; ++l) {
|
||||
for (int k = 0; k < 2; ++k) {
|
||||
VERIFY_IS_EQUAL(slice4.data()[l+11*k], tensor(1,2,3+k,l));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (DataLayout == ColMajor) {
|
||||
offsets = Eigen::DSizes<ptrdiff_t, 4>(0,0,0,4);
|
||||
extents = Eigen::DSizes<ptrdiff_t, 4>(3,5,7,2);
|
||||
auto slice5 = SliceEvaluator(tensor.slice(offsets, extents), DefaultDevice());
|
||||
VERIFY_IS_EQUAL(slice5.dimensions().TotalSize(), 210ul);
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
for (int j = 0; j < 5; ++j) {
|
||||
for (int k = 0; k < 7; ++k) {
|
||||
for (int l = 0; l < 2; ++l) {
|
||||
int slice_index = i + 3 * (j + 5 * (k + 7 * l));
|
||||
VERIFY_IS_EQUAL(slice5.data()[slice_index], tensor(i,j,k,l+4));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
offsets = Eigen::DSizes<ptrdiff_t, 4>(1,0,0,0);
|
||||
extents = Eigen::DSizes<ptrdiff_t, 4>(2,5,7,11);
|
||||
auto slice5 = SliceEvaluator(tensor.slice(offsets, extents), DefaultDevice());
|
||||
VERIFY_IS_EQUAL(slice5.dimensions().TotalSize(), 770ul);
|
||||
for (int l = 0; l < 11; ++l) {
|
||||
for (int k = 0; k < 7; ++k) {
|
||||
for (int j = 0; j < 5; ++j) {
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
int slice_index = l + 11 * (k + 7 * (j + 5 * i));
|
||||
VERIFY_IS_EQUAL(slice5.data()[slice_index], tensor(i+1,j,k,l));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
offsets = Eigen::DSizes<ptrdiff_t, 4>(0,0,0,0);
|
||||
extents = Eigen::DSizes<ptrdiff_t, 4>(3,5,7,11);
|
||||
auto slice6 = SliceEvaluator(tensor.slice(offsets, extents), DefaultDevice());
|
||||
VERIFY_IS_EQUAL(slice6.dimensions().TotalSize(), 3ul*5*7*11);
|
||||
VERIFY_IS_EQUAL(slice6.data(), tensor.data());
|
||||
}
|
||||
|
||||
|
||||
static void test_composition()
|
||||
{
|
||||
Eigen::Tensor<float, 2> matrix(7, 11);
|
||||
matrix.setRandom();
|
||||
|
||||
const DSizes<ptrdiff_t, 3> newDims{{1, 1, 11}};
|
||||
Eigen::Tensor<float, 3> tensor =
|
||||
matrix.slice(DSizes<ptrdiff_t, 2>(2, 0), DSizes<ptrdiff_t, 2>(1, 11)).reshape(newDims);
|
||||
|
||||
VERIFY_IS_EQUAL(tensor.dimensions().TotalSize(), 11ul);
|
||||
VERIFY_IS_EQUAL(tensor.dimension(0), 1);
|
||||
VERIFY_IS_EQUAL(tensor.dimension(1), 1);
|
||||
VERIFY_IS_EQUAL(tensor.dimension(2), 11);
|
||||
for (int i = 0; i < 11; ++i) {
|
||||
VERIFY_IS_EQUAL(tensor(0,0,i), matrix(2,i));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void test_cxx11_tensor_morphing()
|
||||
{
|
||||
CALL_SUBTEST(test_simple_reshape());
|
||||
CALL_SUBTEST(test_reshape_in_expr());
|
||||
CALL_SUBTEST(test_reshape_as_lvalue());
|
||||
|
||||
CALL_SUBTEST(test_simple_slice<ColMajor>());
|
||||
CALL_SUBTEST(test_simple_slice<RowMajor>());
|
||||
CALL_SUBTEST(test_slice_in_expr());
|
||||
CALL_SUBTEST(test_slice_as_lvalue<ColMajor>());
|
||||
CALL_SUBTEST(test_slice_as_lvalue<RowMajor>());
|
||||
CALL_SUBTEST(test_slice_raw_data<ColMajor>());
|
||||
CALL_SUBTEST(test_slice_raw_data<RowMajor>());
|
||||
|
||||
CALL_SUBTEST(test_composition());
|
||||
}
|
||||
81
unsupported/test/cxx11_tensor_of_complex.cpp
Normal file
81
unsupported/test/cxx11_tensor_of_complex.cpp
Normal file
@@ -0,0 +1,81 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#include <Eigen/CXX11/Tensor>
|
||||
|
||||
using Eigen::Tensor;
|
||||
using Eigen::TensorMap;
|
||||
|
||||
|
||||
|
||||
static void test_additions()
|
||||
{
|
||||
Tensor<std::complex<float>, 1> data1(3);
|
||||
Tensor<std::complex<float>, 1> data2(3);
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
data1(i) = std::complex<float>(i, -i);
|
||||
data2(i) = std::complex<float>(i, 7 * i);
|
||||
}
|
||||
|
||||
Tensor<std::complex<float>, 1> sum = data1 + data2;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
VERIFY_IS_EQUAL(sum(i), std::complex<float>(2*i, 6*i));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void test_abs()
|
||||
{
|
||||
Tensor<std::complex<float>, 1> data1(3);
|
||||
Tensor<std::complex<double>, 1> data2(3);
|
||||
data1.setRandom();
|
||||
data2.setRandom();
|
||||
|
||||
Tensor<float, 1> abs1 = data1.abs();
|
||||
Tensor<double, 1> abs2 = data2.abs();
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
VERIFY_IS_APPROX(abs1(i), std::abs(data1(i)));
|
||||
VERIFY_IS_APPROX(abs2(i), std::abs(data2(i)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void test_contractions()
|
||||
{
|
||||
Tensor<std::complex<float>, 4> t_left(30, 50, 8, 31);
|
||||
Tensor<std::complex<float>, 5> t_right(8, 31, 7, 20, 10);
|
||||
Tensor<std::complex<float>, 5> t_result(30, 50, 7, 20, 10);
|
||||
|
||||
t_left.setRandom();
|
||||
t_right.setRandom();
|
||||
|
||||
typedef Map<Matrix<std::complex<float>, Dynamic, Dynamic>> MapXcf;
|
||||
MapXcf m_left(t_left.data(), 1500, 248);
|
||||
MapXcf m_right(t_right.data(), 248, 1400);
|
||||
Matrix<std::complex<float>, Dynamic, Dynamic> m_result(1500, 1400);
|
||||
|
||||
// This contraction should be equivalent to a regular matrix multiplication
|
||||
typedef Tensor<float, 1>::DimensionPair DimPair;
|
||||
Eigen::array<DimPair, 2> dims({{DimPair(2, 0), DimPair(3, 1)}});
|
||||
t_result = t_left.contract(t_right, dims);
|
||||
m_result = m_left * m_right;
|
||||
for (size_t i = 0; i < t_result.dimensions().TotalSize(); i++) {
|
||||
VERIFY_IS_APPROX(t_result.data()[i], m_result.data()[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void test_cxx11_tensor_of_complex()
|
||||
{
|
||||
CALL_SUBTEST(test_additions());
|
||||
CALL_SUBTEST(test_abs());
|
||||
CALL_SUBTEST(test_contractions());
|
||||
}
|
||||
105
unsupported/test/cxx11_tensor_of_const_values.cpp
Normal file
105
unsupported/test/cxx11_tensor_of_const_values.cpp
Normal file
@@ -0,0 +1,105 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#include <Eigen/CXX11/Tensor>
|
||||
|
||||
using Eigen::Tensor;
|
||||
using Eigen::RowMajor;
|
||||
|
||||
static void test_assign()
|
||||
{
|
||||
float data1[6];
|
||||
TensorMap<Tensor<const float, 2>> mat1(data1, 2, 3);
|
||||
float data2[6];
|
||||
const TensorMap<Tensor<float, 2>> mat2(data2, 2, 3);
|
||||
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
data1[i] = i;
|
||||
data2[i] = -i;
|
||||
}
|
||||
|
||||
Tensor<float, 2> rslt1;
|
||||
rslt1 = mat1;
|
||||
Tensor<float, 2> rslt2;
|
||||
rslt2 = mat2;
|
||||
|
||||
Tensor<float, 2> rslt3 = mat1;
|
||||
Tensor<float, 2> rslt4 = mat2;
|
||||
|
||||
Tensor<float, 2> rslt5(mat1);
|
||||
Tensor<float, 2> rslt6(mat2);
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
VERIFY_IS_APPROX(rslt1(i,j), static_cast<float>(i + 2*j));
|
||||
VERIFY_IS_APPROX(rslt2(i,j), static_cast<float>(-i - 2*j));
|
||||
VERIFY_IS_APPROX(rslt3(i,j), static_cast<float>(i + 2*j));
|
||||
VERIFY_IS_APPROX(rslt4(i,j), static_cast<float>(-i - 2*j));
|
||||
VERIFY_IS_APPROX(rslt5(i,j), static_cast<float>(i + 2*j));
|
||||
VERIFY_IS_APPROX(rslt6(i,j), static_cast<float>(-i - 2*j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void test_plus()
|
||||
{
|
||||
float data1[6];
|
||||
TensorMap<Tensor<const float, 2>> mat1(data1, 2, 3);
|
||||
float data2[6];
|
||||
TensorMap<Tensor<float, 2>> mat2(data2, 2, 3);
|
||||
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
data1[i] = i;
|
||||
data2[i] = -i;
|
||||
}
|
||||
|
||||
Tensor<float, 2> sum1;
|
||||
sum1 = mat1 + mat2;
|
||||
Tensor<float, 2> sum2;
|
||||
sum2 = mat2 + mat1;
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
VERIFY_IS_APPROX(sum1(i,j), 0.0f);
|
||||
VERIFY_IS_APPROX(sum2(i,j), 0.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void test_plus_equal()
|
||||
{
|
||||
float data1[6];
|
||||
TensorMap<Tensor<const float, 2>> mat1(data1, 2, 3);
|
||||
float data2[6];
|
||||
TensorMap<Tensor<float, 2>> mat2(data2, 2, 3);
|
||||
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
data1[i] = i;
|
||||
data2[i] = -i;
|
||||
}
|
||||
mat2 += mat1;
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
VERIFY_IS_APPROX(mat2(i,j), 0.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void test_cxx11_tensor_of_const_values()
|
||||
{
|
||||
CALL_SUBTEST(test_assign());
|
||||
CALL_SUBTEST(test_plus());
|
||||
CALL_SUBTEST(test_plus_equal());
|
||||
}
|
||||
152
unsupported/test/cxx11_tensor_of_strings.cpp
Normal file
152
unsupported/test/cxx11_tensor_of_strings.cpp
Normal file
@@ -0,0 +1,152 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#include <Eigen/CXX11/Tensor>
|
||||
|
||||
using Eigen::Tensor;
|
||||
using Eigen::TensorMap;
|
||||
|
||||
static void test_assign()
|
||||
{
|
||||
std::string data1[6];
|
||||
TensorMap<Tensor<std::string, 2>> mat1(data1, 2, 3);
|
||||
std::string data2[6];
|
||||
const TensorMap<Tensor<const std::string, 2>> mat2(data2, 2, 3);
|
||||
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
std::ostringstream s1;
|
||||
s1 << "abc" << i*3;
|
||||
data1[i] = s1.str();
|
||||
std::ostringstream s2;
|
||||
s2 << "def" << i*5;
|
||||
data2[i] = s2.str();
|
||||
}
|
||||
|
||||
Tensor<std::string, 2> rslt1;
|
||||
rslt1 = mat1;
|
||||
Tensor<std::string, 2> rslt2;
|
||||
rslt2 = mat2;
|
||||
|
||||
Tensor<std::string, 2> rslt3 = mat1;
|
||||
Tensor<std::string, 2> rslt4 = mat2;
|
||||
|
||||
Tensor<std::string, 2> rslt5(mat1);
|
||||
Tensor<std::string, 2> rslt6(mat2);
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
VERIFY_IS_EQUAL(rslt1(i,j), data1[i+2*j]);
|
||||
VERIFY_IS_EQUAL(rslt2(i,j), data2[i+2*j]);
|
||||
VERIFY_IS_EQUAL(rslt3(i,j), data1[i+2*j]);
|
||||
VERIFY_IS_EQUAL(rslt4(i,j), data2[i+2*j]);
|
||||
VERIFY_IS_EQUAL(rslt5(i,j), data1[i+2*j]);
|
||||
VERIFY_IS_EQUAL(rslt6(i,j), data2[i+2*j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void test_concat()
|
||||
{
|
||||
Tensor<std::string, 2> t1(2, 3);
|
||||
Tensor<std::string, 2> t2(2, 3);
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
std::ostringstream s1;
|
||||
s1 << "abc" << i + j*2;
|
||||
t1(i, j) = s1.str();
|
||||
std::ostringstream s2;
|
||||
s2 << "def" << i*5 + j*32;
|
||||
t2(i, j) = s2.str();
|
||||
}
|
||||
}
|
||||
|
||||
Tensor<std::string, 2> result = t1.concatenate(t2, 1);
|
||||
VERIFY_IS_EQUAL(result.dimension(0), 2);
|
||||
VERIFY_IS_EQUAL(result.dimension(1), 6);
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
VERIFY_IS_EQUAL(result(i, j), t1(i, j));
|
||||
VERIFY_IS_EQUAL(result(i, j+3), t2(i, j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void test_slices()
|
||||
{
|
||||
Tensor<std::string, 2> data(2, 6);
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
std::ostringstream s1;
|
||||
s1 << "abc" << i + j*2;
|
||||
data(i, j) = s1.str();
|
||||
}
|
||||
}
|
||||
|
||||
const Eigen::DSizes<ptrdiff_t, 2> half_size{{2, 3}};
|
||||
const Eigen::DSizes<ptrdiff_t, 2> first_half{{0, 0}};
|
||||
const Eigen::DSizes<ptrdiff_t, 2> second_half{{0, 3}};
|
||||
|
||||
Tensor<std::string, 2> t1 = data.slice(first_half, half_size);
|
||||
Tensor<std::string, 2> t2 = data.slice(second_half, half_size);
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
VERIFY_IS_EQUAL(data(i, j), t1(i, j));
|
||||
VERIFY_IS_EQUAL(data(i, j+3), t2(i, j));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void test_additions()
|
||||
{
|
||||
Tensor<std::string, 1> data1(3);
|
||||
Tensor<std::string, 1> data2(3);
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
data1(i) = "abc";
|
||||
std::ostringstream s1;
|
||||
s1 << i;
|
||||
data2(i) = s1.str();
|
||||
}
|
||||
|
||||
Tensor<std::string, 1> sum = data1 + data2;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
std::ostringstream concat;
|
||||
concat << "abc" << i;
|
||||
std::string expected = concat.str();
|
||||
VERIFY_IS_EQUAL(sum(i), expected);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void test_initialization()
|
||||
{
|
||||
Tensor<std::string, 2> a(2, 3);
|
||||
a.setConstant(std::string("foo"));
|
||||
for (int i = 0; i < 2*3; ++i) {
|
||||
VERIFY_IS_EQUAL(a(i), std::string("foo"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void test_cxx11_tensor_of_strings()
|
||||
{
|
||||
// Beware: none of this is likely to ever work on a GPU.
|
||||
CALL_SUBTEST(test_assign());
|
||||
CALL_SUBTEST(test_concat());
|
||||
CALL_SUBTEST(test_slices());
|
||||
CALL_SUBTEST(test_additions());
|
||||
CALL_SUBTEST(test_initialization());
|
||||
}
|
||||
93
unsupported/test/cxx11_tensor_padding.cpp
Normal file
93
unsupported/test/cxx11_tensor_padding.cpp
Normal file
@@ -0,0 +1,93 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#include <Eigen/CXX11/Tensor>
|
||||
|
||||
using Eigen::Tensor;
|
||||
|
||||
template<int DataLayout>
|
||||
static void test_simple_padding()
|
||||
{
|
||||
Tensor<float, 4, DataLayout> tensor(2,3,5,7);
|
||||
tensor.setRandom();
|
||||
|
||||
array<std::pair<ptrdiff_t, ptrdiff_t>, 4> paddings;
|
||||
paddings[0] = std::make_pair(0, 0);
|
||||
paddings[1] = std::make_pair(2, 1);
|
||||
paddings[2] = std::make_pair(3, 4);
|
||||
paddings[3] = std::make_pair(0, 0);
|
||||
|
||||
Tensor<float, 4, DataLayout> padded;
|
||||
padded = tensor.pad(paddings);
|
||||
|
||||
VERIFY_IS_EQUAL(padded.dimension(0), 2+0);
|
||||
VERIFY_IS_EQUAL(padded.dimension(1), 3+3);
|
||||
VERIFY_IS_EQUAL(padded.dimension(2), 5+7);
|
||||
VERIFY_IS_EQUAL(padded.dimension(3), 7+0);
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 6; ++j) {
|
||||
for (int k = 0; k < 12; ++k) {
|
||||
for (int l = 0; l < 7; ++l) {
|
||||
if (j >= 2 && j < 5 && k >= 3 && k < 8) {
|
||||
VERIFY_IS_EQUAL(padded(i,j,k,l), tensor(i,j-2,k-3,l));
|
||||
} else {
|
||||
VERIFY_IS_EQUAL(padded(i,j,k,l), 0.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<int DataLayout>
|
||||
static void test_padded_expr()
|
||||
{
|
||||
Tensor<float, 4, DataLayout> tensor(2,3,5,7);
|
||||
tensor.setRandom();
|
||||
|
||||
array<std::pair<ptrdiff_t, ptrdiff_t>, 4> paddings;
|
||||
paddings[0] = std::make_pair(0, 0);
|
||||
paddings[1] = std::make_pair(2, 1);
|
||||
paddings[2] = std::make_pair(3, 4);
|
||||
paddings[3] = std::make_pair(0, 0);
|
||||
|
||||
Eigen::DSizes<ptrdiff_t, 2> reshape_dims;
|
||||
reshape_dims[0] = 12;
|
||||
reshape_dims[1] = 84;
|
||||
|
||||
Tensor<float, 2, DataLayout> result;
|
||||
result = tensor.pad(paddings).reshape(reshape_dims);
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 6; ++j) {
|
||||
for (int k = 0; k < 12; ++k) {
|
||||
for (int l = 0; l < 7; ++l) {
|
||||
const float result_value = DataLayout == ColMajor ?
|
||||
result(i+2*j,k+12*l) : result(j+6*i,l+7*k);
|
||||
if (j >= 2 && j < 5 && k >= 3 && k < 8) {
|
||||
VERIFY_IS_EQUAL(result_value, tensor(i,j-2,k-3,l));
|
||||
} else {
|
||||
VERIFY_IS_EQUAL(result_value, 0.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test_cxx11_tensor_padding()
|
||||
{
|
||||
CALL_SUBTEST(test_simple_padding<ColMajor>());
|
||||
CALL_SUBTEST(test_simple_padding<RowMajor>());
|
||||
CALL_SUBTEST(test_padded_expr<ColMajor>());
|
||||
CALL_SUBTEST(test_padded_expr<RowMajor>());
|
||||
}
|
||||
120
unsupported/test/cxx11_tensor_patch.cpp
Normal file
120
unsupported/test/cxx11_tensor_patch.cpp
Normal file
@@ -0,0 +1,120 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#include <Eigen/CXX11/Tensor>
|
||||
|
||||
using Eigen::Tensor;
|
||||
|
||||
static void test_simple_patch()
|
||||
{
|
||||
Tensor<float, 4> tensor(2,3,5,7);
|
||||
tensor.setRandom();
|
||||
array<ptrdiff_t, 4> patch_dims;
|
||||
patch_dims[0] = 1;
|
||||
patch_dims[1] = 1;
|
||||
patch_dims[2] = 1;
|
||||
patch_dims[3] = 1;
|
||||
|
||||
Tensor<float, 5> no_patch;
|
||||
no_patch = tensor.extract_patches(patch_dims);
|
||||
|
||||
VERIFY_IS_EQUAL(no_patch.dimension(0), 1);
|
||||
VERIFY_IS_EQUAL(no_patch.dimension(1), 1);
|
||||
VERIFY_IS_EQUAL(no_patch.dimension(2), 1);
|
||||
VERIFY_IS_EQUAL(no_patch.dimension(3), 1);
|
||||
VERIFY_IS_EQUAL(no_patch.dimension(4), tensor.size());
|
||||
|
||||
for (int i = 0; i < tensor.size(); ++i) {
|
||||
VERIFY_IS_EQUAL(tensor.data()[i], no_patch.data()[i]);
|
||||
}
|
||||
|
||||
patch_dims[0] = 2;
|
||||
patch_dims[1] = 3;
|
||||
patch_dims[2] = 5;
|
||||
patch_dims[3] = 7;
|
||||
Tensor<float, 5> single_patch;
|
||||
single_patch = tensor.extract_patches(patch_dims);
|
||||
|
||||
VERIFY_IS_EQUAL(single_patch.dimension(0), 2);
|
||||
VERIFY_IS_EQUAL(single_patch.dimension(1), 3);
|
||||
VERIFY_IS_EQUAL(single_patch.dimension(2), 5);
|
||||
VERIFY_IS_EQUAL(single_patch.dimension(3), 7);
|
||||
VERIFY_IS_EQUAL(single_patch.dimension(4), 1);
|
||||
|
||||
for (int i = 0; i < tensor.size(); ++i) {
|
||||
VERIFY_IS_EQUAL(tensor.data()[i], single_patch.data()[i]);
|
||||
}
|
||||
|
||||
patch_dims[0] = 1;
|
||||
patch_dims[1] = 2;
|
||||
patch_dims[2] = 2;
|
||||
patch_dims[3] = 1;
|
||||
Tensor<float, 5> twod_patch;
|
||||
twod_patch = tensor.extract_patches(patch_dims);
|
||||
|
||||
VERIFY_IS_EQUAL(twod_patch.dimension(0), 1);
|
||||
VERIFY_IS_EQUAL(twod_patch.dimension(1), 2);
|
||||
VERIFY_IS_EQUAL(twod_patch.dimension(2), 2);
|
||||
VERIFY_IS_EQUAL(twod_patch.dimension(3), 1);
|
||||
VERIFY_IS_EQUAL(twod_patch.dimension(4), 2*2*4*7);
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 2; ++j) {
|
||||
for (int k = 0; k < 4; ++k) {
|
||||
for (int l = 0; l < 7; ++l) {
|
||||
int patch_loc = i + 2 * (j + 2 * (k + 4 * l));
|
||||
for (int x = 0; x < 2; ++x) {
|
||||
for (int y = 0; y < 2; ++y) {
|
||||
VERIFY_IS_EQUAL(tensor(i,j+x,k+y,l), twod_patch(0,x,y,0,patch_loc));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
patch_dims[0] = 1;
|
||||
patch_dims[1] = 2;
|
||||
patch_dims[2] = 3;
|
||||
patch_dims[3] = 5;
|
||||
Tensor<float, 5> threed_patch;
|
||||
threed_patch = tensor.extract_patches(patch_dims);
|
||||
|
||||
VERIFY_IS_EQUAL(threed_patch.dimension(0), 1);
|
||||
VERIFY_IS_EQUAL(threed_patch.dimension(1), 2);
|
||||
VERIFY_IS_EQUAL(threed_patch.dimension(2), 3);
|
||||
VERIFY_IS_EQUAL(threed_patch.dimension(3), 5);
|
||||
VERIFY_IS_EQUAL(threed_patch.dimension(4), 2*2*3*3);
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 2; ++j) {
|
||||
for (int k = 0; k < 3; ++k) {
|
||||
for (int l = 0; l < 3; ++l) {
|
||||
int patch_loc = i + 2 * (j + 2 * (k + 3 * l));
|
||||
for (int x = 0; x < 2; ++x) {
|
||||
for (int y = 0; y < 3; ++y) {
|
||||
for (int z = 0; z < 5; ++z) {
|
||||
VERIFY_IS_EQUAL(tensor(i,j+x,k+y,l+z), threed_patch(0,x,y,z,patch_loc));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void test_cxx11_tensor_patch()
|
||||
{
|
||||
CALL_SUBTEST(test_simple_patch());
|
||||
// CALL_SUBTEST(test_expr_shuffling());
|
||||
}
|
||||
78
unsupported/test/cxx11_tensor_random.cpp
Normal file
78
unsupported/test/cxx11_tensor_random.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#include <Eigen/CXX11/Tensor>
|
||||
|
||||
static void test_default()
|
||||
{
|
||||
Tensor<float, 1> vec(6);
|
||||
vec.setRandom();
|
||||
|
||||
// Fixme: we should check that the generated numbers follow a uniform
|
||||
// distribution instead.
|
||||
for (int i = 1; i < 6; ++i) {
|
||||
VERIFY_IS_NOT_EQUAL(vec(i), vec(i-1));
|
||||
}
|
||||
}
|
||||
|
||||
static void test_normal()
|
||||
{
|
||||
Tensor<float, 1> vec(6);
|
||||
vec.setRandom<Eigen::internal::NormalRandomGenerator<float>>();
|
||||
|
||||
// Fixme: we should check that the generated numbers follow a gaussian
|
||||
// distribution instead.
|
||||
for (int i = 1; i < 6; ++i) {
|
||||
VERIFY_IS_NOT_EQUAL(vec(i), vec(i-1));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct MyGenerator {
|
||||
MyGenerator() { }
|
||||
MyGenerator(const MyGenerator&) { }
|
||||
|
||||
// Return a random value to be used. "element_location" is the
|
||||
// location of the entry to set in the tensor, it can typically
|
||||
// be ignored.
|
||||
int operator()(Eigen::DenseIndex element_location, Eigen::DenseIndex /*unused*/ = 0) const {
|
||||
return 3 * element_location;
|
||||
}
|
||||
|
||||
// Same as above but generates several numbers at a time.
|
||||
typename internal::packet_traits<int>::type packetOp(
|
||||
Eigen::DenseIndex packet_location, Eigen::DenseIndex /*unused*/ = 0) const {
|
||||
const int packetSize = internal::packet_traits<int>::size;
|
||||
EIGEN_ALIGN_DEFAULT int values[packetSize];
|
||||
for (int i = 0; i < packetSize; ++i) {
|
||||
values[i] = 3 * (packet_location + i);
|
||||
}
|
||||
return internal::pload<typename internal::packet_traits<int>::type>(values);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static void test_custom()
|
||||
{
|
||||
Tensor<int, 1> vec(6);
|
||||
vec.setRandom<MyGenerator>();
|
||||
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
VERIFY_IS_EQUAL(vec(i), 3*i);
|
||||
}
|
||||
}
|
||||
|
||||
void test_cxx11_tensor_random()
|
||||
{
|
||||
CALL_SUBTEST(test_default());
|
||||
CALL_SUBTEST(test_normal());
|
||||
CALL_SUBTEST(test_custom());
|
||||
}
|
||||
420
unsupported/test/cxx11_tensor_reduction.cpp
Normal file
420
unsupported/test/cxx11_tensor_reduction.cpp
Normal file
@@ -0,0 +1,420 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "main.h"
|
||||
#include <limits>
|
||||
#include <Eigen/CXX11/Tensor>
|
||||
|
||||
using Eigen::Tensor;
|
||||
|
||||
template <int DataLayout>
|
||||
static void test_simple_reductions() {
|
||||
Tensor<float, 4, DataLayout> tensor(2, 3, 5, 7);
|
||||
tensor.setRandom();
|
||||
array<ptrdiff_t, 2> reduction_axis;
|
||||
reduction_axis[0] = 1;
|
||||
reduction_axis[1] = 3;
|
||||
|
||||
Tensor<float, 2, DataLayout> result = tensor.sum(reduction_axis);
|
||||
VERIFY_IS_EQUAL(result.dimension(0), 2);
|
||||
VERIFY_IS_EQUAL(result.dimension(1), 5);
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 5; ++j) {
|
||||
float sum = 0.0f;
|
||||
for (int k = 0; k < 3; ++k) {
|
||||
for (int l = 0; l < 7; ++l) {
|
||||
sum += tensor(i, k, j, l);
|
||||
}
|
||||
}
|
||||
VERIFY_IS_APPROX(result(i, j), sum);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
Tensor<float, 1, DataLayout> sum1 = tensor.sum();
|
||||
VERIFY_IS_EQUAL(sum1.dimension(0), 1);
|
||||
|
||||
array<ptrdiff_t, 4> reduction_axis;
|
||||
reduction_axis[0] = 0;
|
||||
reduction_axis[1] = 1;
|
||||
reduction_axis[2] = 2;
|
||||
reduction_axis[3] = 3;
|
||||
Tensor<float, 1, DataLayout> sum2 = tensor.sum(reduction_axis);
|
||||
VERIFY_IS_EQUAL(sum2.dimension(0), 1);
|
||||
|
||||
VERIFY_IS_APPROX(sum1(0), sum2(0));
|
||||
}
|
||||
|
||||
reduction_axis[0] = 0;
|
||||
reduction_axis[1] = 2;
|
||||
result = tensor.prod(reduction_axis);
|
||||
VERIFY_IS_EQUAL(result.dimension(0), 3);
|
||||
VERIFY_IS_EQUAL(result.dimension(1), 7);
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
for (int j = 0; j < 7; ++j) {
|
||||
float prod = 1.0f;
|
||||
for (int k = 0; k < 2; ++k) {
|
||||
for (int l = 0; l < 5; ++l) {
|
||||
prod *= tensor(k, i, l, j);
|
||||
}
|
||||
}
|
||||
VERIFY_IS_APPROX(result(i, j), prod);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
Tensor<float, 1, DataLayout> prod1 = tensor.prod();
|
||||
VERIFY_IS_EQUAL(prod1.dimension(0), 1);
|
||||
|
||||
array<ptrdiff_t, 4> reduction_axis;
|
||||
reduction_axis[0] = 0;
|
||||
reduction_axis[1] = 1;
|
||||
reduction_axis[2] = 2;
|
||||
reduction_axis[3] = 3;
|
||||
Tensor<float, 1, DataLayout> prod2 = tensor.prod(reduction_axis);
|
||||
VERIFY_IS_EQUAL(prod2.dimension(0), 1);
|
||||
|
||||
VERIFY_IS_APPROX(prod1(0), prod2(0));
|
||||
}
|
||||
|
||||
reduction_axis[0] = 0;
|
||||
reduction_axis[1] = 2;
|
||||
result = tensor.maximum(reduction_axis);
|
||||
VERIFY_IS_EQUAL(result.dimension(0), 3);
|
||||
VERIFY_IS_EQUAL(result.dimension(1), 7);
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
for (int j = 0; j < 7; ++j) {
|
||||
float max_val = std::numeric_limits<float>::lowest();
|
||||
for (int k = 0; k < 2; ++k) {
|
||||
for (int l = 0; l < 5; ++l) {
|
||||
max_val = (std::max)(max_val, tensor(k, i, l, j));
|
||||
}
|
||||
}
|
||||
VERIFY_IS_APPROX(result(i, j), max_val);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
Tensor<float, 1, DataLayout> max1 = tensor.maximum();
|
||||
VERIFY_IS_EQUAL(max1.dimension(0), 1);
|
||||
|
||||
array<ptrdiff_t, 4> reduction_axis;
|
||||
reduction_axis[0] = 0;
|
||||
reduction_axis[1] = 1;
|
||||
reduction_axis[2] = 2;
|
||||
reduction_axis[3] = 3;
|
||||
Tensor<float, 1, DataLayout> max2 = tensor.maximum(reduction_axis);
|
||||
VERIFY_IS_EQUAL(max2.dimension(0), 1);
|
||||
|
||||
VERIFY_IS_APPROX(max1(0), max2(0));
|
||||
}
|
||||
|
||||
reduction_axis[0] = 0;
|
||||
reduction_axis[1] = 1;
|
||||
result = tensor.minimum(reduction_axis);
|
||||
VERIFY_IS_EQUAL(result.dimension(0), 5);
|
||||
VERIFY_IS_EQUAL(result.dimension(1), 7);
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
for (int j = 0; j < 7; ++j) {
|
||||
float min_val = (std::numeric_limits<float>::max)();
|
||||
for (int k = 0; k < 2; ++k) {
|
||||
for (int l = 0; l < 3; ++l) {
|
||||
min_val = (std::min)(min_val, tensor(k, l, i, j));
|
||||
}
|
||||
}
|
||||
VERIFY_IS_APPROX(result(i, j), min_val);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
Tensor<float, 1, DataLayout> min1 = tensor.minimum();
|
||||
VERIFY_IS_EQUAL(min1.dimension(0), 1);
|
||||
|
||||
array<ptrdiff_t, 4> reduction_axis;
|
||||
reduction_axis[0] = 0;
|
||||
reduction_axis[1] = 1;
|
||||
reduction_axis[2] = 2;
|
||||
reduction_axis[3] = 3;
|
||||
Tensor<float, 1, DataLayout> min2 = tensor.minimum(reduction_axis);
|
||||
VERIFY_IS_EQUAL(min2.dimension(0), 1);
|
||||
|
||||
VERIFY_IS_APPROX(min1(0), min2(0));
|
||||
}
|
||||
|
||||
reduction_axis[0] = 0;
|
||||
reduction_axis[1] = 1;
|
||||
result = tensor.mean(reduction_axis);
|
||||
VERIFY_IS_EQUAL(result.dimension(0), 5);
|
||||
VERIFY_IS_EQUAL(result.dimension(1), 7);
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
for (int j = 0; j < 7; ++j) {
|
||||
float sum = 0.0f;
|
||||
int count = 0;
|
||||
for (int k = 0; k < 2; ++k) {
|
||||
for (int l = 0; l < 3; ++l) {
|
||||
sum += tensor(k, l, i, j);
|
||||
++count;
|
||||
}
|
||||
}
|
||||
VERIFY_IS_APPROX(result(i, j), sum / count);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
Tensor<float, 1, DataLayout> mean1 = tensor.mean();
|
||||
VERIFY_IS_EQUAL(mean1.dimension(0), 1);
|
||||
|
||||
array<ptrdiff_t, 4> reduction_axis;
|
||||
reduction_axis[0] = 0;
|
||||
reduction_axis[1] = 1;
|
||||
reduction_axis[2] = 2;
|
||||
reduction_axis[3] = 3;
|
||||
Tensor<float, 1, DataLayout> mean2 = tensor.mean(reduction_axis);
|
||||
VERIFY_IS_EQUAL(mean2.dimension(0), 1);
|
||||
|
||||
VERIFY_IS_APPROX(mean1(0), mean2(0));
|
||||
}
|
||||
}
|
||||
|
||||
template <int DataLayout>
|
||||
static void test_full_reductions() {
|
||||
Tensor<float, 2, DataLayout> tensor(2, 3);
|
||||
tensor.setRandom();
|
||||
array<ptrdiff_t, 2> reduction_axis;
|
||||
reduction_axis[0] = 0;
|
||||
reduction_axis[1] = 1;
|
||||
|
||||
Tensor<float, 1, DataLayout> result = tensor.sum(reduction_axis);
|
||||
VERIFY_IS_EQUAL(result.dimension(0), 1);
|
||||
|
||||
float sum = 0.0f;
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
sum += tensor(i, j);
|
||||
}
|
||||
}
|
||||
VERIFY_IS_APPROX(result(0), sum);
|
||||
|
||||
result = tensor.square().sum(reduction_axis).sqrt();
|
||||
VERIFY_IS_EQUAL(result.dimension(0), 1);
|
||||
|
||||
sum = 0.0f;
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
sum += tensor(i, j) * tensor(i, j);
|
||||
}
|
||||
}
|
||||
VERIFY_IS_APPROX(result(0), sqrtf(sum));
|
||||
}
|
||||
|
||||
struct UserReducer {
|
||||
static const bool PacketAccess = false;
|
||||
UserReducer(float offset) : offset_(offset) {}
|
||||
void reduce(const float val, float* accum) { *accum += val * val; }
|
||||
float initialize() const { return 0; }
|
||||
float finalize(const float accum) const { return 1.0f / (accum + offset_); }
|
||||
|
||||
private:
|
||||
const float offset_;
|
||||
};
|
||||
|
||||
template <int DataLayout>
|
||||
static void test_user_defined_reductions() {
|
||||
Tensor<float, 2, DataLayout> tensor(5, 7);
|
||||
tensor.setRandom();
|
||||
array<ptrdiff_t, 1> reduction_axis;
|
||||
reduction_axis[0] = 1;
|
||||
|
||||
UserReducer reducer(10.0f);
|
||||
Tensor<float, 1, DataLayout> result = tensor.reduce(reduction_axis, reducer);
|
||||
VERIFY_IS_EQUAL(result.dimension(0), 5);
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
float expected = 10.0f;
|
||||
for (int j = 0; j < 7; ++j) {
|
||||
expected += tensor(i, j) * tensor(i, j);
|
||||
}
|
||||
expected = 1.0f / expected;
|
||||
VERIFY_IS_APPROX(result(i), expected);
|
||||
}
|
||||
}
|
||||
|
||||
template <int DataLayout>
|
||||
static void test_tensor_maps() {
|
||||
int inputs[2 * 3 * 5 * 7];
|
||||
TensorMap<Tensor<int, 4, DataLayout> > tensor_map(inputs, 2, 3, 5, 7);
|
||||
TensorMap<Tensor<const int, 4, DataLayout> > tensor_map_const(inputs, 2, 3, 5,
|
||||
7);
|
||||
const TensorMap<Tensor<const int, 4, DataLayout> > tensor_map_const_const(
|
||||
inputs, 2, 3, 5, 7);
|
||||
|
||||
tensor_map.setRandom();
|
||||
array<ptrdiff_t, 2> reduction_axis;
|
||||
reduction_axis[0] = 1;
|
||||
reduction_axis[1] = 3;
|
||||
|
||||
Tensor<int, 2, DataLayout> result = tensor_map.sum(reduction_axis);
|
||||
Tensor<int, 2, DataLayout> result2 = tensor_map_const.sum(reduction_axis);
|
||||
Tensor<int, 2, DataLayout> result3 =
|
||||
tensor_map_const_const.sum(reduction_axis);
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 5; ++j) {
|
||||
int sum = 0;
|
||||
for (int k = 0; k < 3; ++k) {
|
||||
for (int l = 0; l < 7; ++l) {
|
||||
sum += tensor_map(i, k, j, l);
|
||||
}
|
||||
}
|
||||
VERIFY_IS_EQUAL(result(i, j), sum);
|
||||
VERIFY_IS_EQUAL(result2(i, j), sum);
|
||||
VERIFY_IS_EQUAL(result3(i, j), sum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <int DataLayout>
|
||||
static void test_static_dims() {
|
||||
Tensor<float, 4, DataLayout> in(72, 53, 97, 113);
|
||||
Tensor<float, 2, DataLayout> out(72, 97);
|
||||
in.setRandom();
|
||||
|
||||
#ifndef EIGEN_HAS_CONSTEXPR
|
||||
array<int, 2> reduction_axis;
|
||||
reduction_axis[0] = 1;
|
||||
reduction_axis[1] = 3;
|
||||
#else
|
||||
Eigen::IndexList<Eigen::type2index<1>, Eigen::type2index<3> > reduction_axis;
|
||||
#endif
|
||||
|
||||
out = in.maximum(reduction_axis);
|
||||
|
||||
for (int i = 0; i < 72; ++i) {
|
||||
for (int j = 0; j < 97; ++j) {
|
||||
float expected = -1e10f;
|
||||
for (int k = 0; k < 53; ++k) {
|
||||
for (int l = 0; l < 113; ++l) {
|
||||
expected = (std::max)(expected, in(i, k, j, l));
|
||||
}
|
||||
}
|
||||
VERIFY_IS_APPROX(out(i, j), expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <int DataLayout>
|
||||
static void test_innermost_last_dims() {
|
||||
Tensor<float, 4, DataLayout> in(72, 53, 97, 113);
|
||||
Tensor<float, 2, DataLayout> out(97, 113);
|
||||
in.setRandom();
|
||||
|
||||
// Reduce on the innermost dimensions.
|
||||
#ifndef EIGEN_HAS_CONSTEXPR
|
||||
array<int, 2> reduction_axis;
|
||||
reduction_axis[0] = 0;
|
||||
reduction_axis[1] = 1;
|
||||
#else
|
||||
// This triggers the use of packets for ColMajor.
|
||||
Eigen::IndexList<Eigen::type2index<0>, Eigen::type2index<1> > reduction_axis;
|
||||
#endif
|
||||
|
||||
out = in.maximum(reduction_axis);
|
||||
|
||||
for (int i = 0; i < 97; ++i) {
|
||||
for (int j = 0; j < 113; ++j) {
|
||||
float expected = -1e10f;
|
||||
for (int k = 0; k < 53; ++k) {
|
||||
for (int l = 0; l < 72; ++l) {
|
||||
expected = (std::max)(expected, in(l, k, i, j));
|
||||
}
|
||||
}
|
||||
VERIFY_IS_APPROX(out(i, j), expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <int DataLayout>
|
||||
static void test_innermost_first_dims() {
|
||||
Tensor<float, 4, DataLayout> in(72, 53, 97, 113);
|
||||
Tensor<float, 2, DataLayout> out(72, 53);
|
||||
in.setRandom();
|
||||
|
||||
// Reduce on the innermost dimensions.
|
||||
#ifndef EIGEN_HAS_CONSTEXPR
|
||||
array<int, 2> reduction_axis;
|
||||
reduction_axis[0] = 2;
|
||||
reduction_axis[1] = 3;
|
||||
#else
|
||||
// This triggers the use of packets for RowMajor.
|
||||
Eigen::IndexList<Eigen::type2index<2>, Eigen::type2index<3>> reduction_axis;
|
||||
#endif
|
||||
|
||||
out = in.maximum(reduction_axis);
|
||||
|
||||
for (int i = 0; i < 72; ++i) {
|
||||
for (int j = 0; j < 53; ++j) {
|
||||
float expected = -1e10f;
|
||||
for (int k = 0; k < 97; ++k) {
|
||||
for (int l = 0; l < 113; ++l) {
|
||||
expected = (std::max)(expected, in(i, j, k, l));
|
||||
}
|
||||
}
|
||||
VERIFY_IS_APPROX(out(i, j), expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <int DataLayout>
|
||||
static void test_reduce_middle_dims() {
|
||||
Tensor<float, 4, DataLayout> in(72, 53, 97, 113);
|
||||
Tensor<float, 2, DataLayout> out(72, 53);
|
||||
in.setRandom();
|
||||
|
||||
// Reduce on the innermost dimensions.
|
||||
#ifndef EIGEN_HAS_CONSTEXPR
|
||||
array<int, 2> reduction_axis;
|
||||
reduction_axis[0] = 1;
|
||||
reduction_axis[1] = 2;
|
||||
#else
|
||||
// This triggers the use of packets for RowMajor.
|
||||
Eigen::IndexList<Eigen::type2index<1>, Eigen::type2index<2>> reduction_axis;
|
||||
#endif
|
||||
|
||||
out = in.maximum(reduction_axis);
|
||||
|
||||
for (int i = 0; i < 72; ++i) {
|
||||
for (int j = 0; j < 113; ++j) {
|
||||
float expected = -1e10f;
|
||||
for (int k = 0; k < 53; ++k) {
|
||||
for (int l = 0; l < 97; ++l) {
|
||||
expected = (std::max)(expected, in(i, k, l, j));
|
||||
}
|
||||
}
|
||||
VERIFY_IS_APPROX(out(i, j), expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test_cxx11_tensor_reduction() {
|
||||
CALL_SUBTEST(test_simple_reductions<ColMajor>());
|
||||
CALL_SUBTEST(test_simple_reductions<RowMajor>());
|
||||
CALL_SUBTEST(test_full_reductions<ColMajor>());
|
||||
CALL_SUBTEST(test_full_reductions<RowMajor>());
|
||||
CALL_SUBTEST(test_user_defined_reductions<ColMajor>());
|
||||
CALL_SUBTEST(test_user_defined_reductions<RowMajor>());
|
||||
CALL_SUBTEST(test_tensor_maps<ColMajor>());
|
||||
CALL_SUBTEST(test_tensor_maps<RowMajor>());
|
||||
CALL_SUBTEST(test_static_dims<ColMajor>());
|
||||
CALL_SUBTEST(test_static_dims<RowMajor>());
|
||||
CALL_SUBTEST(test_innermost_last_dims<ColMajor>());
|
||||
CALL_SUBTEST(test_innermost_last_dims<RowMajor>());
|
||||
CALL_SUBTEST(test_innermost_first_dims<ColMajor>());
|
||||
CALL_SUBTEST(test_innermost_first_dims<RowMajor>());
|
||||
CALL_SUBTEST(test_reduce_middle_dims<ColMajor>());
|
||||
CALL_SUBTEST(test_reduce_middle_dims<RowMajor>());
|
||||
}
|
||||
208
unsupported/test/cxx11_tensor_ref.cpp
Normal file
208
unsupported/test/cxx11_tensor_ref.cpp
Normal file
@@ -0,0 +1,208 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#include <Eigen/CXX11/Tensor>
|
||||
|
||||
using Eigen::Tensor;
|
||||
using Eigen::RowMajor;
|
||||
|
||||
static void test_simple_lvalue_ref()
|
||||
{
|
||||
Tensor<int, 1> input(6);
|
||||
input.setRandom();
|
||||
|
||||
TensorRef<Tensor<int, 1>> ref3(input);
|
||||
TensorRef<Tensor<int, 1>> ref4 = input;
|
||||
|
||||
VERIFY_IS_EQUAL(ref3.data(), input.data());
|
||||
VERIFY_IS_EQUAL(ref4.data(), input.data());
|
||||
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
VERIFY_IS_EQUAL(ref3(i), input(i));
|
||||
VERIFY_IS_EQUAL(ref4(i), input(i));
|
||||
}
|
||||
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
ref3.coeffRef(i) = i;
|
||||
}
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
VERIFY_IS_EQUAL(input(i), i);
|
||||
}
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
ref4.coeffRef(i) = -i * 2;
|
||||
}
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
VERIFY_IS_EQUAL(input(i), -i*2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void test_simple_rvalue_ref()
|
||||
{
|
||||
Tensor<int, 1> input1(6);
|
||||
input1.setRandom();
|
||||
Tensor<int, 1> input2(6);
|
||||
input2.setRandom();
|
||||
|
||||
TensorRef<Tensor<int, 1>> ref3(input1 + input2);
|
||||
TensorRef<Tensor<int, 1>> ref4 = input1 + input2;
|
||||
|
||||
VERIFY_IS_NOT_EQUAL(ref3.data(), input1.data());
|
||||
VERIFY_IS_NOT_EQUAL(ref4.data(), input1.data());
|
||||
VERIFY_IS_NOT_EQUAL(ref3.data(), input2.data());
|
||||
VERIFY_IS_NOT_EQUAL(ref4.data(), input2.data());
|
||||
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
VERIFY_IS_EQUAL(ref3(i), input1(i) + input2(i));
|
||||
VERIFY_IS_EQUAL(ref4(i), input1(i) + input2(i));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void test_multiple_dims()
|
||||
{
|
||||
Tensor<float, 3> input(3,5,7);
|
||||
input.setRandom();
|
||||
|
||||
TensorRef<Tensor<float, 3>> ref(input);
|
||||
VERIFY_IS_EQUAL(ref.data(), input.data());
|
||||
VERIFY_IS_EQUAL(ref.dimension(0), 3);
|
||||
VERIFY_IS_EQUAL(ref.dimension(1), 5);
|
||||
VERIFY_IS_EQUAL(ref.dimension(2), 7);
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
for (int j = 0; j < 5; ++j) {
|
||||
for (int k = 0; k < 7; ++k) {
|
||||
VERIFY_IS_EQUAL(ref(i,j,k), input(i,j,k));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void test_slice()
|
||||
{
|
||||
Tensor<float, 5> tensor(2,3,5,7,11);
|
||||
tensor.setRandom();
|
||||
|
||||
Eigen::DSizes<ptrdiff_t, 5> indices(1,2,3,4,5);
|
||||
Eigen::DSizes<ptrdiff_t, 5> sizes(1,1,1,1,1);
|
||||
TensorRef<Tensor<float, 5>> slice = tensor.slice(indices, sizes);
|
||||
VERIFY_IS_EQUAL(slice(0,0,0,0,0), tensor(1,2,3,4,5));
|
||||
|
||||
Eigen::DSizes<ptrdiff_t, 5> indices2(1,1,3,4,5);
|
||||
Eigen::DSizes<ptrdiff_t, 5> sizes2(1,1,2,2,3);
|
||||
slice = tensor.slice(indices2, sizes2);
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 2; ++j) {
|
||||
for (int k = 0; k < 3; ++k) {
|
||||
VERIFY_IS_EQUAL(slice(0,0,i,j,k), tensor(1,1,3+i,4+j,5+k));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Eigen::DSizes<ptrdiff_t, 5> indices3(0,0,0,0,0);
|
||||
Eigen::DSizes<ptrdiff_t, 5> sizes3(2,3,1,1,1);
|
||||
slice = tensor.slice(indices3, sizes3);
|
||||
VERIFY_IS_EQUAL(slice.data(), tensor.data());
|
||||
}
|
||||
|
||||
|
||||
static void test_ref_of_ref()
|
||||
{
|
||||
Tensor<float, 3> input(3,5,7);
|
||||
input.setRandom();
|
||||
|
||||
TensorRef<Tensor<float, 3>> ref(input);
|
||||
TensorRef<Tensor<float, 3>> ref_of_ref(ref);
|
||||
TensorRef<Tensor<float, 3>> ref_of_ref2;
|
||||
ref_of_ref2 = ref;
|
||||
|
||||
VERIFY_IS_EQUAL(ref_of_ref.data(), input.data());
|
||||
VERIFY_IS_EQUAL(ref_of_ref.dimension(0), 3);
|
||||
VERIFY_IS_EQUAL(ref_of_ref.dimension(1), 5);
|
||||
VERIFY_IS_EQUAL(ref_of_ref.dimension(2), 7);
|
||||
|
||||
VERIFY_IS_EQUAL(ref_of_ref2.data(), input.data());
|
||||
VERIFY_IS_EQUAL(ref_of_ref2.dimension(0), 3);
|
||||
VERIFY_IS_EQUAL(ref_of_ref2.dimension(1), 5);
|
||||
VERIFY_IS_EQUAL(ref_of_ref2.dimension(2), 7);
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
for (int j = 0; j < 5; ++j) {
|
||||
for (int k = 0; k < 7; ++k) {
|
||||
VERIFY_IS_EQUAL(ref_of_ref(i,j,k), input(i,j,k));
|
||||
VERIFY_IS_EQUAL(ref_of_ref2(i,j,k), input(i,j,k));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void test_ref_in_expr()
|
||||
{
|
||||
Tensor<float, 3> input(3,5,7);
|
||||
input.setRandom();
|
||||
TensorRef<Tensor<float, 3>> input_ref(input);
|
||||
|
||||
Tensor<float, 3> result(3,5,7);
|
||||
result.setRandom();
|
||||
TensorRef<Tensor<float, 3>> result_ref(result);
|
||||
|
||||
Tensor<float, 3> bias(3,5,7);
|
||||
bias.setRandom();
|
||||
|
||||
result_ref = input_ref + bias;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
for (int j = 0; j < 5; ++j) {
|
||||
for (int k = 0; k < 7; ++k) {
|
||||
VERIFY_IS_EQUAL(result_ref(i,j,k), input(i,j,k) + bias(i,j,k));
|
||||
VERIFY_IS_NOT_EQUAL(result(i,j,k), input(i,j,k) + bias(i,j,k));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result = result_ref;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
for (int j = 0; j < 5; ++j) {
|
||||
for (int k = 0; k < 7; ++k) {
|
||||
VERIFY_IS_EQUAL(result(i,j,k), input(i,j,k) + bias(i,j,k));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void test_coeff_ref()
|
||||
{
|
||||
Tensor<float, 5> tensor(2,3,5,7,11);
|
||||
tensor.setRandom();
|
||||
Tensor<float, 5> original = tensor;
|
||||
|
||||
TensorRef<Tensor<float, 4>> slice = tensor.chip(7, 4);
|
||||
slice.coeffRef(0, 0, 0, 0) = 1.0f;
|
||||
slice.coeffRef(1, 0, 0, 0) += 2.0f;
|
||||
|
||||
VERIFY_IS_EQUAL(tensor(0,0,0,0,7), 1.0f);
|
||||
VERIFY_IS_EQUAL(tensor(1,0,0,0,7), original(1,0,0,0,7) + 2.0f);
|
||||
}
|
||||
|
||||
|
||||
void test_cxx11_tensor_ref()
|
||||
{
|
||||
CALL_SUBTEST(test_simple_lvalue_ref());
|
||||
CALL_SUBTEST(test_simple_rvalue_ref());
|
||||
CALL_SUBTEST(test_multiple_dims());
|
||||
CALL_SUBTEST(test_slice());
|
||||
CALL_SUBTEST(test_ref_of_ref());
|
||||
CALL_SUBTEST(test_ref_in_expr());
|
||||
CALL_SUBTEST(test_coeff_ref());
|
||||
}
|
||||
167
unsupported/test/cxx11_tensor_reverse.cpp
Normal file
167
unsupported/test/cxx11_tensor_reverse.cpp
Normal file
@@ -0,0 +1,167 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2014 Navdeep Jaitly <ndjaitly@google.com and
|
||||
// Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#include <Eigen/CXX11/Tensor>
|
||||
|
||||
using Eigen::Tensor;
|
||||
using Eigen::array;
|
||||
|
||||
template <int DataLayout>
|
||||
static void test_simple_reverse()
|
||||
{
|
||||
Tensor<float, 4, DataLayout> tensor(2,3,5,7);
|
||||
tensor.setRandom();
|
||||
|
||||
array<bool, 4> dim_rev;
|
||||
dim_rev[0] = false;
|
||||
dim_rev[1] = true;
|
||||
dim_rev[2] = true;
|
||||
dim_rev[3] = false;
|
||||
|
||||
Tensor<float, 4, DataLayout> reversed_tensor;
|
||||
reversed_tensor = tensor.reverse(dim_rev);
|
||||
|
||||
VERIFY_IS_EQUAL(reversed_tensor.dimension(0), 2);
|
||||
VERIFY_IS_EQUAL(reversed_tensor.dimension(1), 3);
|
||||
VERIFY_IS_EQUAL(reversed_tensor.dimension(2), 5);
|
||||
VERIFY_IS_EQUAL(reversed_tensor.dimension(3), 7);
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 5; ++k) {
|
||||
for (int l = 0; l < 7; ++l) {
|
||||
VERIFY_IS_EQUAL(tensor(i,j,k,l), reversed_tensor(i,2-j,4-k,l));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dim_rev[0] = true;
|
||||
dim_rev[1] = false;
|
||||
dim_rev[2] = false;
|
||||
dim_rev[3] = false;
|
||||
|
||||
reversed_tensor = tensor.reverse(dim_rev);
|
||||
|
||||
VERIFY_IS_EQUAL(reversed_tensor.dimension(0), 2);
|
||||
VERIFY_IS_EQUAL(reversed_tensor.dimension(1), 3);
|
||||
VERIFY_IS_EQUAL(reversed_tensor.dimension(2), 5);
|
||||
VERIFY_IS_EQUAL(reversed_tensor.dimension(3), 7);
|
||||
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 5; ++k) {
|
||||
for (int l = 0; l < 7; ++l) {
|
||||
VERIFY_IS_EQUAL(tensor(i,j,k,l), reversed_tensor(1-i,j,k,l));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dim_rev[0] = true;
|
||||
dim_rev[1] = false;
|
||||
dim_rev[2] = false;
|
||||
dim_rev[3] = true;
|
||||
|
||||
reversed_tensor = tensor.reverse(dim_rev);
|
||||
|
||||
VERIFY_IS_EQUAL(reversed_tensor.dimension(0), 2);
|
||||
VERIFY_IS_EQUAL(reversed_tensor.dimension(1), 3);
|
||||
VERIFY_IS_EQUAL(reversed_tensor.dimension(2), 5);
|
||||
VERIFY_IS_EQUAL(reversed_tensor.dimension(3), 7);
|
||||
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 5; ++k) {
|
||||
for (int l = 0; l < 7; ++l) {
|
||||
VERIFY_IS_EQUAL(tensor(i,j,k,l), reversed_tensor(1-i,j,k,6-l));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <int DataLayout>
|
||||
static void test_expr_reverse()
|
||||
{
|
||||
Tensor<float, 4, DataLayout> tensor(2,3,5,7);
|
||||
tensor.setRandom();
|
||||
|
||||
array<bool, 4> dim_rev;
|
||||
dim_rev[0] = false;
|
||||
dim_rev[1] = true;
|
||||
dim_rev[2] = false;
|
||||
dim_rev[3] = true;
|
||||
|
||||
|
||||
Tensor<float, 4, DataLayout> expected;
|
||||
expected = tensor.reverse(dim_rev);
|
||||
|
||||
Tensor<float, 4, DataLayout> result(2,3,5,7);
|
||||
|
||||
array<ptrdiff_t, 4> src_slice_dim{{2,3,1,7}};
|
||||
array<ptrdiff_t, 4> src_slice_start{{0,0,0,0}};
|
||||
array<ptrdiff_t, 4> dst_slice_dim{{2,3,1,7}};
|
||||
array<ptrdiff_t, 4> dst_slice_start{{0,0,0,0}};
|
||||
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
result.slice(dst_slice_start, dst_slice_dim) =
|
||||
tensor.slice(src_slice_start, src_slice_dim).reverse(dim_rev);
|
||||
src_slice_start[2] += 1;
|
||||
dst_slice_start[2] += 1;
|
||||
}
|
||||
|
||||
VERIFY_IS_EQUAL(result.dimension(0), 2);
|
||||
VERIFY_IS_EQUAL(result.dimension(1), 3);
|
||||
VERIFY_IS_EQUAL(result.dimension(2), 5);
|
||||
VERIFY_IS_EQUAL(result.dimension(3), 7);
|
||||
|
||||
for (int i = 0; i < expected.dimension(0); ++i) {
|
||||
for (int j = 0; j < expected.dimension(1); ++j) {
|
||||
for (int k = 0; k < expected.dimension(2); ++k) {
|
||||
for (int l = 0; l < expected.dimension(3); ++l) {
|
||||
VERIFY_IS_EQUAL(result(i,j,k,l), expected(i,j,k,l));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dst_slice_start[2] = 0;
|
||||
result.setRandom();
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
result.slice(dst_slice_start, dst_slice_dim) =
|
||||
tensor.reverse(dim_rev).slice(dst_slice_start, dst_slice_dim);
|
||||
dst_slice_start[2] += 1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < expected.dimension(0); ++i) {
|
||||
for (int j = 0; j < expected.dimension(1); ++j) {
|
||||
for (int k = 0; k < expected.dimension(2); ++k) {
|
||||
for (int l = 0; l < expected.dimension(3); ++l) {
|
||||
VERIFY_IS_EQUAL(result(i,j,k,l), expected(i,j,k,l));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void test_cxx11_tensor_reverse()
|
||||
{
|
||||
CALL_SUBTEST(test_simple_reverse<ColMajor>());
|
||||
CALL_SUBTEST(test_simple_reverse<RowMajor>());
|
||||
CALL_SUBTEST(test_expr_reverse<ColMajor>());
|
||||
CALL_SUBTEST(test_expr_reverse<RowMajor>());
|
||||
}
|
||||
187
unsupported/test/cxx11_tensor_shuffling.cpp
Normal file
187
unsupported/test/cxx11_tensor_shuffling.cpp
Normal file
@@ -0,0 +1,187 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#include <Eigen/CXX11/Tensor>
|
||||
|
||||
using Eigen::Tensor;
|
||||
using Eigen::array;
|
||||
|
||||
template <int DataLayout>
|
||||
static void test_simple_shuffling()
|
||||
{
|
||||
Tensor<float, 4, DataLayout> tensor(2,3,5,7);
|
||||
tensor.setRandom();
|
||||
array<ptrdiff_t, 4> shuffles;
|
||||
shuffles[0] = 0;
|
||||
shuffles[1] = 1;
|
||||
shuffles[2] = 2;
|
||||
shuffles[3] = 3;
|
||||
|
||||
Tensor<float, 4, DataLayout> no_shuffle;
|
||||
no_shuffle = tensor.shuffle(shuffles);
|
||||
|
||||
VERIFY_IS_EQUAL(no_shuffle.dimension(0), 2);
|
||||
VERIFY_IS_EQUAL(no_shuffle.dimension(1), 3);
|
||||
VERIFY_IS_EQUAL(no_shuffle.dimension(2), 5);
|
||||
VERIFY_IS_EQUAL(no_shuffle.dimension(3), 7);
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 5; ++k) {
|
||||
for (int l = 0; l < 7; ++l) {
|
||||
VERIFY_IS_EQUAL(tensor(i,j,k,l), no_shuffle(i,j,k,l));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
shuffles[0] = 2;
|
||||
shuffles[1] = 3;
|
||||
shuffles[2] = 1;
|
||||
shuffles[3] = 0;
|
||||
Tensor<float, 4, DataLayout> shuffle;
|
||||
shuffle = tensor.shuffle(shuffles);
|
||||
|
||||
VERIFY_IS_EQUAL(shuffle.dimension(0), 5);
|
||||
VERIFY_IS_EQUAL(shuffle.dimension(1), 7);
|
||||
VERIFY_IS_EQUAL(shuffle.dimension(2), 3);
|
||||
VERIFY_IS_EQUAL(shuffle.dimension(3), 2);
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 5; ++k) {
|
||||
for (int l = 0; l < 7; ++l) {
|
||||
VERIFY_IS_EQUAL(tensor(i,j,k,l), shuffle(k,l,j,i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <int DataLayout>
|
||||
static void test_expr_shuffling()
|
||||
{
|
||||
Tensor<float, 4, DataLayout> tensor(2,3,5,7);
|
||||
tensor.setRandom();
|
||||
|
||||
array<ptrdiff_t, 4> shuffles;
|
||||
shuffles[0] = 2;
|
||||
shuffles[1] = 3;
|
||||
shuffles[2] = 1;
|
||||
shuffles[3] = 0;
|
||||
Tensor<float, 4, DataLayout> expected;
|
||||
expected = tensor.shuffle(shuffles);
|
||||
|
||||
Tensor<float, 4, DataLayout> result(5,7,3,2);
|
||||
|
||||
array<int, 4> src_slice_dim{{2,3,1,7}};
|
||||
array<int, 4> src_slice_start{{0,0,0,0}};
|
||||
array<int, 4> dst_slice_dim{{1,7,3,2}};
|
||||
array<int, 4> dst_slice_start{{0,0,0,0}};
|
||||
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
result.slice(dst_slice_start, dst_slice_dim) =
|
||||
tensor.slice(src_slice_start, src_slice_dim).shuffle(shuffles);
|
||||
src_slice_start[2] += 1;
|
||||
dst_slice_start[0] += 1;
|
||||
}
|
||||
|
||||
VERIFY_IS_EQUAL(result.dimension(0), 5);
|
||||
VERIFY_IS_EQUAL(result.dimension(1), 7);
|
||||
VERIFY_IS_EQUAL(result.dimension(2), 3);
|
||||
VERIFY_IS_EQUAL(result.dimension(3), 2);
|
||||
|
||||
for (int i = 0; i < expected.dimension(0); ++i) {
|
||||
for (int j = 0; j < expected.dimension(1); ++j) {
|
||||
for (int k = 0; k < expected.dimension(2); ++k) {
|
||||
for (int l = 0; l < expected.dimension(3); ++l) {
|
||||
VERIFY_IS_EQUAL(result(i,j,k,l), expected(i,j,k,l));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dst_slice_start[0] = 0;
|
||||
result.setRandom();
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
result.slice(dst_slice_start, dst_slice_dim) =
|
||||
tensor.shuffle(shuffles).slice(dst_slice_start, dst_slice_dim);
|
||||
dst_slice_start[0] += 1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < expected.dimension(0); ++i) {
|
||||
for (int j = 0; j < expected.dimension(1); ++j) {
|
||||
for (int k = 0; k < expected.dimension(2); ++k) {
|
||||
for (int l = 0; l < expected.dimension(3); ++l) {
|
||||
VERIFY_IS_EQUAL(result(i,j,k,l), expected(i,j,k,l));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <int DataLayout>
|
||||
static void test_shuffling_as_value()
|
||||
{
|
||||
Tensor<float, 4, DataLayout> tensor(2,3,5,7);
|
||||
tensor.setRandom();
|
||||
array<ptrdiff_t, 4> shuffles;
|
||||
shuffles[2] = 0;
|
||||
shuffles[3] = 1;
|
||||
shuffles[1] = 2;
|
||||
shuffles[0] = 3;
|
||||
Tensor<float, 4, DataLayout> shuffle(5,7,3,2);
|
||||
shuffle.shuffle(shuffles) = tensor;
|
||||
|
||||
VERIFY_IS_EQUAL(shuffle.dimension(0), 5);
|
||||
VERIFY_IS_EQUAL(shuffle.dimension(1), 7);
|
||||
VERIFY_IS_EQUAL(shuffle.dimension(2), 3);
|
||||
VERIFY_IS_EQUAL(shuffle.dimension(3), 2);
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 5; ++k) {
|
||||
for (int l = 0; l < 7; ++l) {
|
||||
VERIFY_IS_EQUAL(tensor(i,j,k,l), shuffle(k,l,j,i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
array<ptrdiff_t, 4> no_shuffle;
|
||||
no_shuffle[0] = 0;
|
||||
no_shuffle[1] = 1;
|
||||
no_shuffle[2] = 2;
|
||||
no_shuffle[3] = 3;
|
||||
Tensor<float, 4, DataLayout> shuffle2(5,7,3,2);
|
||||
shuffle2.shuffle(shuffles) = tensor.shuffle(no_shuffle);
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
for (int j = 0; j < 7; ++j) {
|
||||
for (int k = 0; k < 3; ++k) {
|
||||
for (int l = 0; l < 2; ++l) {
|
||||
VERIFY_IS_EQUAL(shuffle2(i,j,k,l), shuffle(i,j,k,l));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test_cxx11_tensor_shuffling()
|
||||
{
|
||||
CALL_SUBTEST(test_simple_shuffling<ColMajor>());
|
||||
CALL_SUBTEST(test_simple_shuffling<RowMajor>());
|
||||
CALL_SUBTEST(test_expr_shuffling<ColMajor>());
|
||||
CALL_SUBTEST(test_expr_shuffling<RowMajor>());
|
||||
CALL_SUBTEST(test_shuffling_as_value<ColMajor>());
|
||||
CALL_SUBTEST(test_shuffling_as_value<RowMajor>());
|
||||
}
|
||||
@@ -32,6 +32,7 @@ static void test_1d()
|
||||
vec1(5) = 42; vec2(5) = 5; vec3(5) = 0;
|
||||
vec4.setZero();
|
||||
|
||||
VERIFY_IS_EQUAL((vec1.rank()), 1);
|
||||
VERIFY_IS_EQUAL((vec1.size()), 6);
|
||||
VERIFY_IS_EQUAL((vec1.dimensions()[0]), 6);
|
||||
|
||||
@@ -99,10 +100,12 @@ static void test_2d()
|
||||
mat2(1,1) = 4;
|
||||
mat2(1,2) = 5;
|
||||
|
||||
VERIFY_IS_EQUAL((mat1.rank()), 2);
|
||||
VERIFY_IS_EQUAL((mat1.size()), 6);
|
||||
VERIFY_IS_EQUAL((mat1.dimensions()[0]), 2);
|
||||
VERIFY_IS_EQUAL((mat1.dimensions()[1]), 3);
|
||||
|
||||
VERIFY_IS_EQUAL((mat2.rank()), 2);
|
||||
VERIFY_IS_EQUAL((mat2.size()), 6);
|
||||
VERIFY_IS_EQUAL((mat2.dimensions()[0]), 2);
|
||||
VERIFY_IS_EQUAL((mat2.dimensions()[1]), 3);
|
||||
@@ -163,7 +166,7 @@ static void test_3d()
|
||||
VERIFY_IS_EQUAL((epsilon(0,2,1)), -1);
|
||||
VERIFY_IS_EQUAL((epsilon(1,0,2)), -1);
|
||||
|
||||
std::array<Eigen::DenseIndex, 3> dims{{2,3,4}};
|
||||
array<Eigen::DenseIndex, 3> dims{{2,3,4}};
|
||||
Tensor<int, 3> t1(dims);
|
||||
Tensor<int, 3, RowMajor> t2(dims);
|
||||
|
||||
@@ -244,7 +247,7 @@ static void test_simple_assign()
|
||||
epsilon(0,1,2) = epsilon(2,0,1) = epsilon(1,2,0) = 1;
|
||||
epsilon(2,1,0) = epsilon(0,2,1) = epsilon(1,0,2) = -1;
|
||||
|
||||
Tensor<int, 3> e2(2,3,1);
|
||||
Tensor<int, 3> e2(3,3,3);
|
||||
e2.setZero();
|
||||
VERIFY_IS_EQUAL((e2(1,2,0)), 0);
|
||||
|
||||
@@ -257,12 +260,38 @@ static void test_simple_assign()
|
||||
VERIFY_IS_EQUAL((e2(1,0,2)), -1);
|
||||
}
|
||||
|
||||
static void test_resize()
|
||||
{
|
||||
Tensor<int, 3> epsilon;
|
||||
epsilon.resize(2,3,7);
|
||||
VERIFY_IS_EQUAL(epsilon.dimension(0), 2);
|
||||
VERIFY_IS_EQUAL(epsilon.dimension(1), 3);
|
||||
VERIFY_IS_EQUAL(epsilon.dimension(2), 7);
|
||||
VERIFY_IS_EQUAL(epsilon.dimensions().TotalSize(), 2ul*3*7);
|
||||
|
||||
const int* old_data = epsilon.data();
|
||||
epsilon.resize(3,2,7);
|
||||
VERIFY_IS_EQUAL(epsilon.dimension(0), 3);
|
||||
VERIFY_IS_EQUAL(epsilon.dimension(1), 2);
|
||||
VERIFY_IS_EQUAL(epsilon.dimension(2), 7);
|
||||
VERIFY_IS_EQUAL(epsilon.dimensions().TotalSize(), 2ul*3*7);
|
||||
VERIFY_IS_EQUAL(epsilon.data(), old_data);
|
||||
|
||||
epsilon.resize(3,5,7);
|
||||
VERIFY_IS_EQUAL(epsilon.dimension(0), 3);
|
||||
VERIFY_IS_EQUAL(epsilon.dimension(1), 5);
|
||||
VERIFY_IS_EQUAL(epsilon.dimension(2), 7);
|
||||
VERIFY_IS_EQUAL(epsilon.dimensions().TotalSize(), 3ul*5*7);
|
||||
VERIFY_IS_NOT_EQUAL(epsilon.data(), old_data);
|
||||
}
|
||||
|
||||
void test_cxx11_tensor_simple()
|
||||
{
|
||||
CALL_SUBTEST(test_1d());
|
||||
CALL_SUBTEST(test_2d());
|
||||
CALL_SUBTEST(test_3d());
|
||||
CALL_SUBTEST(test_simple_assign());
|
||||
CALL_SUBTEST(test_resize());
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
119
unsupported/test/cxx11_tensor_striding.cpp
Normal file
119
unsupported/test/cxx11_tensor_striding.cpp
Normal file
@@ -0,0 +1,119 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#include "main.h"
|
||||
|
||||
#include <Eigen/CXX11/Tensor>
|
||||
|
||||
using Eigen::Tensor;
|
||||
|
||||
template<int DataLayout>
|
||||
static void test_simple_striding()
|
||||
{
|
||||
Tensor<float, 4, DataLayout> tensor(2,3,5,7);
|
||||
tensor.setRandom();
|
||||
array<ptrdiff_t, 4> strides;
|
||||
strides[0] = 1;
|
||||
strides[1] = 1;
|
||||
strides[2] = 1;
|
||||
strides[3] = 1;
|
||||
|
||||
Tensor<float, 4, DataLayout> no_stride;
|
||||
no_stride = tensor.stride(strides);
|
||||
|
||||
VERIFY_IS_EQUAL(no_stride.dimension(0), 2);
|
||||
VERIFY_IS_EQUAL(no_stride.dimension(1), 3);
|
||||
VERIFY_IS_EQUAL(no_stride.dimension(2), 5);
|
||||
VERIFY_IS_EQUAL(no_stride.dimension(3), 7);
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 5; ++k) {
|
||||
for (int l = 0; l < 7; ++l) {
|
||||
VERIFY_IS_EQUAL(tensor(i,j,k,l), no_stride(i,j,k,l));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
strides[0] = 2;
|
||||
strides[1] = 4;
|
||||
strides[2] = 2;
|
||||
strides[3] = 3;
|
||||
Tensor<float, 4, DataLayout> stride;
|
||||
stride = tensor.stride(strides);
|
||||
|
||||
VERIFY_IS_EQUAL(stride.dimension(0), 1);
|
||||
VERIFY_IS_EQUAL(stride.dimension(1), 1);
|
||||
VERIFY_IS_EQUAL(stride.dimension(2), 3);
|
||||
VERIFY_IS_EQUAL(stride.dimension(3), 3);
|
||||
|
||||
for (int i = 0; i < 1; ++i) {
|
||||
for (int j = 0; j < 1; ++j) {
|
||||
for (int k = 0; k < 3; ++k) {
|
||||
for (int l = 0; l < 3; ++l) {
|
||||
VERIFY_IS_EQUAL(tensor(2*i,4*j,2*k,3*l), stride(i,j,k,l));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<int DataLayout>
|
||||
static void test_striding_as_lvalue()
|
||||
{
|
||||
Tensor<float, 4, DataLayout> tensor(2,3,5,7);
|
||||
tensor.setRandom();
|
||||
array<ptrdiff_t, 4> strides;
|
||||
strides[0] = 2;
|
||||
strides[1] = 4;
|
||||
strides[2] = 2;
|
||||
strides[3] = 3;
|
||||
|
||||
Tensor<float, 4, DataLayout> result(3, 12, 10, 21);
|
||||
result.stride(strides) = tensor;
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 5; ++k) {
|
||||
for (int l = 0; l < 7; ++l) {
|
||||
VERIFY_IS_EQUAL(tensor(i,j,k,l), result(2*i,4*j,2*k,3*l));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
array<ptrdiff_t, 4> no_strides;
|
||||
no_strides[0] = 1;
|
||||
no_strides[1] = 1;
|
||||
no_strides[2] = 1;
|
||||
no_strides[3] = 1;
|
||||
Tensor<float, 4, DataLayout> result2(3, 12, 10, 21);
|
||||
result2.stride(strides) = tensor.stride(no_strides);
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 5; ++k) {
|
||||
for (int l = 0; l < 7; ++l) {
|
||||
VERIFY_IS_EQUAL(tensor(i,j,k,l), result2(2*i,4*j,2*k,3*l));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void test_cxx11_tensor_striding()
|
||||
{
|
||||
CALL_SUBTEST(test_simple_striding<ColMajor>());
|
||||
CALL_SUBTEST(test_simple_striding<RowMajor>());
|
||||
CALL_SUBTEST(test_striding_as_lvalue<ColMajor>());
|
||||
CALL_SUBTEST(test_striding_as_lvalue<RowMajor>());
|
||||
}
|
||||
270
unsupported/test/cxx11_tensor_thread_pool.cpp
Normal file
270
unsupported/test/cxx11_tensor_thread_pool.cpp
Normal file
@@ -0,0 +1,270 @@
|
||||
// This file is part of Eigen, a lightweight C++ template library
|
||||
// for linear algebra.
|
||||
//
|
||||
// Copyright (C) 2014 Benoit Steiner <benoit.steiner.goog@gmail.com>
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla
|
||||
// Public License v. 2.0. If a copy of the MPL was not distributed
|
||||
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
#define EIGEN_USE_THREADS
|
||||
|
||||
|
||||
#include "main.h"
|
||||
#include <iostream>
|
||||
#include <Eigen/CXX11/Tensor>
|
||||
|
||||
using Eigen::Tensor;
|
||||
|
||||
|
||||
static void test_multithread_elementwise()
|
||||
{
|
||||
Tensor<float, 3> in1(2,3,7);
|
||||
Tensor<float, 3> in2(2,3,7);
|
||||
Tensor<float, 3> out(2,3,7);
|
||||
|
||||
in1.setRandom();
|
||||
in2.setRandom();
|
||||
|
||||
Eigen::ThreadPoolDevice thread_pool_device(internal::random<int>(3, 11));
|
||||
out.device(thread_pool_device) = in1 + in2 * 3.14f;
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 7; ++k) {
|
||||
VERIFY_IS_APPROX(out(i,j,k), in1(i,j,k) + in2(i,j,k) * 3.14f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void test_multithread_compound_assignment()
|
||||
{
|
||||
Tensor<float, 3> in1(2,3,7);
|
||||
Tensor<float, 3> in2(2,3,7);
|
||||
Tensor<float, 3> out(2,3,7);
|
||||
|
||||
in1.setRandom();
|
||||
in2.setRandom();
|
||||
|
||||
Eigen::ThreadPoolDevice thread_pool_device(internal::random<int>(3, 11));
|
||||
out.device(thread_pool_device) = in1;
|
||||
out.device(thread_pool_device) += in2 * 3.14f;
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int k = 0; k < 7; ++k) {
|
||||
VERIFY_IS_APPROX(out(i,j,k), in1(i,j,k) + in2(i,j,k) * 3.14f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<int DataLayout>
|
||||
static void test_multithread_contraction()
|
||||
{
|
||||
Tensor<float, 4, DataLayout> t_left(30, 50, 37, 31);
|
||||
Tensor<float, 5, DataLayout> t_right(37, 31, 70, 2, 10);
|
||||
Tensor<float, 5, DataLayout> t_result(30, 50, 70, 2, 10);
|
||||
|
||||
t_left.setRandom();
|
||||
t_right.setRandom();
|
||||
|
||||
// this contraction should be equivalent to a single matrix multiplication
|
||||
typedef Tensor<float, 1>::DimensionPair DimPair;
|
||||
Eigen::array<DimPair, 2> dims({{DimPair(2, 0), DimPair(3, 1)}});
|
||||
|
||||
typedef Map<Matrix<float, Dynamic, Dynamic, DataLayout>> MapXf;
|
||||
MapXf m_left(t_left.data(), 1500, 1147);
|
||||
MapXf m_right(t_right.data(), 1147, 1400);
|
||||
Matrix<float, Dynamic, Dynamic, DataLayout> m_result(1500, 1400);
|
||||
|
||||
Eigen::ThreadPoolDevice thread_pool_device(4);
|
||||
|
||||
// compute results by separate methods
|
||||
t_result.device(thread_pool_device) = t_left.contract(t_right, dims);
|
||||
m_result = m_left * m_right;
|
||||
|
||||
for (ptrdiff_t i = 0; i < t_result.size(); i++) {
|
||||
VERIFY(&t_result.data()[i] != &m_result.data()[i]);
|
||||
if (fabs(t_result.data()[i] - m_result.data()[i]) >= 1e-4) {
|
||||
std::cout << "mismatch detected: " << t_result.data()[i] << " vs " << m_result.data()[i] << std::endl;
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<int DataLayout>
|
||||
static void test_contraction_corner_cases()
|
||||
{
|
||||
Tensor<float, 2, DataLayout> t_left(32, 500);
|
||||
Tensor<float, 2, DataLayout> t_right(32, 28*28);
|
||||
Tensor<float, 2, DataLayout> t_result(500, 28*28);
|
||||
|
||||
t_left = (t_left.constant(-0.5f) + t_left.random()) * 2.0f;
|
||||
t_right = (t_right.constant(-0.6f) + t_right.random()) * 2.0f;
|
||||
t_result = t_result.constant(NAN);
|
||||
|
||||
// this contraction should be equivalent to a single matrix multiplication
|
||||
typedef Tensor<float, 1>::DimensionPair DimPair;
|
||||
Eigen::array<DimPair, 1> dims{{DimPair(0, 0)}};
|
||||
|
||||
typedef Map<Matrix<float, Dynamic, Dynamic, DataLayout>> MapXf;
|
||||
MapXf m_left(t_left.data(), 32, 500);
|
||||
MapXf m_right(t_right.data(), 32, 28*28);
|
||||
Matrix<float, Dynamic, Dynamic, DataLayout> m_result(500, 28*28);
|
||||
|
||||
Eigen::ThreadPoolDevice thread_pool_device(12);
|
||||
|
||||
// compute results by separate methods
|
||||
t_result.device(thread_pool_device) = t_left.contract(t_right, dims);
|
||||
m_result = m_left.transpose() * m_right;
|
||||
|
||||
for (ptrdiff_t i = 0; i < t_result.size(); i++) {
|
||||
assert(!std::isnan(t_result.data()[i]));
|
||||
if (fabs(t_result.data()[i] - m_result.data()[i]) >= 1e-4) {
|
||||
std::cout << "mismatch detected at index " << i << " : " << t_result.data()[i] << " vs " << m_result.data()[i] << std::endl;
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
t_left.resize(32, 1);
|
||||
t_left = (t_left.constant(-0.5f) + t_left.random()) * 2.0f;
|
||||
t_result.resize (1, 28*28);
|
||||
t_result = t_result.constant(NAN);
|
||||
t_result.device(thread_pool_device) = t_left.contract(t_right, dims);
|
||||
new(&m_left) MapXf(t_left.data(), 32, 1);
|
||||
m_result = m_left.transpose() * m_right;
|
||||
for (ptrdiff_t i = 0; i < t_result.size(); i++) {
|
||||
assert(!std::isnan(t_result.data()[i]));
|
||||
if (fabs(t_result.data()[i] - m_result.data()[i]) >= 1e-4) {
|
||||
std::cout << "mismatch detected: " << t_result.data()[i] << " vs " << m_result.data()[i] << std::endl;
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
t_left.resize(32, 500);
|
||||
t_right.resize(32, 4);
|
||||
t_left = (t_left.constant(-0.5f) + t_left.random()) * 2.0f;
|
||||
t_right = (t_right.constant(-0.6f) + t_right.random()) * 2.0f;
|
||||
t_result.resize (500, 4);
|
||||
t_result = t_result.constant(NAN);
|
||||
t_result.device(thread_pool_device) = t_left.contract(t_right, dims);
|
||||
new(&m_left) MapXf(t_left.data(), 32, 500);
|
||||
new(&m_right) MapXf(t_right.data(), 32, 4);
|
||||
m_result = m_left.transpose() * m_right;
|
||||
for (ptrdiff_t i = 0; i < t_result.size(); i++) {
|
||||
assert(!std::isnan(t_result.data()[i]));
|
||||
if (fabs(t_result.data()[i] - m_result.data()[i]) >= 1e-4) {
|
||||
std::cout << "mismatch detected: " << t_result.data()[i] << " vs " << m_result.data()[i] << std::endl;
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
t_left.resize(32, 1);
|
||||
t_right.resize(32, 4);
|
||||
t_left = (t_left.constant(-0.5f) + t_left.random()) * 2.0f;
|
||||
t_right = (t_right.constant(-0.6f) + t_right.random()) * 2.0f;
|
||||
t_result.resize (1, 4);
|
||||
t_result = t_result.constant(NAN);
|
||||
t_result.device(thread_pool_device) = t_left.contract(t_right, dims);
|
||||
new(&m_left) MapXf(t_left.data(), 32, 1);
|
||||
new(&m_right) MapXf(t_right.data(), 32, 4);
|
||||
m_result = m_left.transpose() * m_right;
|
||||
for (ptrdiff_t i = 0; i < t_result.size(); i++) {
|
||||
assert(!std::isnan(t_result.data()[i]));
|
||||
if (fabs(t_result.data()[i] - m_result.data()[i]) >= 1e-4) {
|
||||
std::cout << "mismatch detected: " << t_result.data()[i] << " vs " << m_result.data()[i] << std::endl;
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<int DataLayout>
|
||||
static void test_multithread_contraction_agrees_with_singlethread() {
|
||||
int contract_size = internal::random<int>(1, 5000);
|
||||
|
||||
Tensor<float, 3, DataLayout> left(internal::random<int>(1, 80),
|
||||
contract_size,
|
||||
internal::random<int>(1, 100));
|
||||
|
||||
Tensor<float, 4, DataLayout> right(internal::random<int>(1, 25),
|
||||
internal::random<int>(1, 37),
|
||||
contract_size,
|
||||
internal::random<int>(1, 51));
|
||||
|
||||
left.setRandom();
|
||||
right.setRandom();
|
||||
|
||||
// add constants to shift values away from 0 for more precision
|
||||
left += left.constant(1.5f);
|
||||
right += right.constant(1.5f);
|
||||
|
||||
typedef Tensor<float, 1>::DimensionPair DimPair;
|
||||
Eigen::array<DimPair, 1> dims({{DimPair(1, 2)}});
|
||||
|
||||
Eigen::ThreadPoolDevice thread_pool_device(internal::random<int>(2, 11));
|
||||
|
||||
Tensor<float, 5, DataLayout> st_result;
|
||||
st_result = left.contract(right, dims);
|
||||
|
||||
Tensor<float, 5, DataLayout> tp_result(st_result.dimensions());
|
||||
tp_result.device(thread_pool_device) = left.contract(right, dims);
|
||||
|
||||
VERIFY(dimensions_match(st_result.dimensions(), tp_result.dimensions()));
|
||||
for (ptrdiff_t i = 0; i < st_result.size(); i++) {
|
||||
// if both of the values are very small, then do nothing (because the test will fail
|
||||
// due to numerical precision issues when values are small)
|
||||
if (fabs(st_result.data()[i] - tp_result.data()[i]) >= 1e-4) {
|
||||
VERIFY_IS_APPROX(st_result.data()[i], tp_result.data()[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void test_memcpy() {
|
||||
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
const int num_threads = internal::random<int>(3, 11);
|
||||
Eigen::ThreadPoolDevice thread_pool_device(num_threads);
|
||||
|
||||
const int size = internal::random<int>(13, 7632);
|
||||
Tensor<float, 1> t1(size);
|
||||
t1.setRandom();
|
||||
std::vector<float> result(size);
|
||||
thread_pool_device.memcpy(&result[0], t1.data(), size*sizeof(float));
|
||||
for (int i = 0; i < size; i++) {
|
||||
VERIFY_IS_EQUAL(t1(i), result[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void test_multithread_random()
|
||||
{
|
||||
Eigen::ThreadPoolDevice device(2);
|
||||
Tensor<float, 1> t(1 << 20);
|
||||
t.device(device) = t.random<Eigen::internal::NormalRandomGenerator<float>>();
|
||||
}
|
||||
|
||||
|
||||
void test_cxx11_tensor_thread_pool()
|
||||
{
|
||||
CALL_SUBTEST(test_multithread_elementwise());
|
||||
CALL_SUBTEST(test_multithread_compound_assignment());
|
||||
|
||||
CALL_SUBTEST(test_multithread_contraction<ColMajor>());
|
||||
CALL_SUBTEST(test_multithread_contraction<RowMajor>());
|
||||
|
||||
CALL_SUBTEST(test_multithread_contraction_agrees_with_singlethread<ColMajor>());
|
||||
CALL_SUBTEST(test_multithread_contraction_agrees_with_singlethread<RowMajor>());
|
||||
|
||||
// Exercise various cases that have been problematic in the past.
|
||||
CALL_SUBTEST(test_contraction_corner_cases<ColMajor>());
|
||||
CALL_SUBTEST(test_contraction_corner_cases<RowMajor>());
|
||||
|
||||
CALL_SUBTEST(test_memcpy());
|
||||
|
||||
CALL_SUBTEST(test_multithread_random());
|
||||
}
|
||||
Reference in New Issue
Block a user