// This file is part of Eigen, a lightweight C++ template library // for linear algebra. // // 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/.
// clang-format off #include"main.h" #include <Eigen/CXX11/Tensor> // clang-format on
// -------------------------------------------------------------------------- // // A set of tests for TensorBlockIO: copying data between tensor blocks.
template <int NumDims> static DSizes<Index, NumDims> RandomDims(Index min, Index max) {
DSizes<Index, NumDims> dims; for (int i = 0; i < NumDims; ++i) {
dims[i] = internal::random<Index>(min, max);
} return DSizes<Index, NumDims>(dims);
}
template <int Layout, int NumDims> static Index GetInputIndex(Index output_index, const array<Index, NumDims>& output_to_input_dim_map, const array<Index, NumDims>& input_strides, const array<Index, NumDims>& output_strides) { int input_index = 0; if (Layout == ColMajor) { for (int i = NumDims - 1; i > 0; --i) { const Index idx = output_index / output_strides[i];
input_index += idx * input_strides[output_to_input_dim_map[i]];
output_index -= idx * output_strides[i];
} return input_index +
output_index * input_strides[output_to_input_dim_map[0]];
} else { for (int i = 0; i < NumDims - 1; ++i) { const Index idx = output_index / output_strides[i];
input_index += idx * input_strides[output_to_input_dim_map[i]];
output_index -= idx * output_strides[i];
} return input_index +
output_index * input_strides[output_to_input_dim_map[NumDims - 1]];
}
}
template <typename T, int NumDims, int Layout> staticvoid test_block_io_copy_data_from_source_to_target() { using TensorBlockIO = internal::TensorBlockIO<T, Index, NumDims, Layout>; using IODst = typename TensorBlockIO::Dst; using IOSrc = typename TensorBlockIO::Src;
// Generate a random input Tensor.
DSizes<Index, NumDims> dims = RandomDims<NumDims>(1, 30);
Tensor<T, NumDims, Layout> input(dims);
input.setRandom();
// Write data to an output Tensor.
Tensor<T, NumDims, Layout> output(dims);
// Construct a tensor block mapper. using TensorBlockMapper =
internal::TensorBlockMapper<NumDims, Layout, Index>;
TensorBlockMapper block_mapper(
dims, {RandomBlockShape(), RandomTargetBlockSize(dims), {0, 0, 0}});
// We will copy data from input to output through this buffer.
Tensor<T, NumDims, Layout> block(block_mapper.blockDimensions());
// Precompute strides for TensorBlockIO::Copy. auto input_strides = internal::strides<Layout>(dims); auto output_strides = internal::strides<Layout>(dims);
for (int i = 0; i < block_mapper.blockCount(); ++i) { auto desc = block_mapper.blockDescriptor(i);
auto blk_dims = desc.dimensions(); auto blk_strides = internal::strides<Layout>(blk_dims);
{ // Read from input into a block buffer.
IODst dst(blk_dims, blk_strides, block_data, 0);
IOSrc src(input_strides, input_data, desc.offset());
TensorBlockIO::Copy(dst, src);
}
{ // Write from block buffer to output.
IODst dst(blk_dims, output_strides, output_data, desc.offset());
IOSrc src(blk_strides, block_data, 0);
TensorBlockIO::Copy(dst, src);
}
}
for (int i = 0; i < dims.TotalSize(); ++i) {
VERIFY_IS_EQUAL(input_data[i], output_data[i]);
}
}
template <typename T, int NumDims, int Layout> staticvoid test_block_io_copy_using_reordered_dimensions() { // Generate a random input Tensor.
DSizes<Index, NumDims> dims = RandomDims<NumDims>(1, 30);
Tensor<T, NumDims, Layout> input(dims);
input.setRandom();
// Create a random dimension re-ordering/shuffle.
std::vector<int> shuffle;
for (int i = 0; i < NumDims; ++i) shuffle.push_back(i);
std::shuffle(shuffle.begin(), shuffle.end(), std::mt19937(g_seed));
DSizes<Index, NumDims> output_tensor_dims;
DSizes<Index, NumDims> input_to_output_dim_map;
DSizes<Index, NumDims> output_to_input_dim_map; for (Index i = 0; i < NumDims; ++i) {
output_tensor_dims[shuffle[i]] = dims[i];
input_to_output_dim_map[i] = shuffle[i];
output_to_input_dim_map[shuffle[i]] = i;
}
// Write data to an output Tensor.
Tensor<T, NumDims, Layout> output(output_tensor_dims);
// Construct a tensor block mapper. // NOTE: Tensor block mapper works with shuffled dimensions. using TensorBlockMapper =
internal::TensorBlockMapper<NumDims, Layout, Index>;
TensorBlockMapper block_mapper(output_tensor_dims,
{RandomBlockShape(),
RandomTargetBlockSize(output_tensor_dims),
{0, 0, 0}});
// We will copy data from input to output through this buffer.
Tensor<T, NumDims, Layout> block(block_mapper.blockDimensions());
// Precompute strides for TensorBlockIO::Copy. auto input_strides = internal::strides<Layout>(dims); auto output_strides = internal::strides<Layout>(output_tensor_dims);
for (Index i = 0; i < block_mapper.blockCount(); ++i) { auto desc = block_mapper.blockDescriptor(i);
const Index first_coeff_index = GetInputIndex<Layout, NumDims>(
desc.offset(), output_to_input_dim_map, input_strides,
output_strides);
// NOTE: Block dimensions are in the same order as output dimensions.
using TensorBlockIO = internal::TensorBlockIO<T, Index, NumDims, Layout>; using IODst = typename TensorBlockIO::Dst; using IOSrc = typename TensorBlockIO::Src;
auto blk_dims = desc.dimensions(); auto blk_strides = internal::strides<Layout>(blk_dims);
{ // Read from input into a block buffer.
IODst dst(blk_dims, blk_strides, block_data, 0);
IOSrc src(input_strides, input_data, first_coeff_index);
// TODO(ezhulenev): Remove when fully switched to TensorBlock.
DSizes<int, NumDims> dim_map; for (int j = 0; j < NumDims; ++j)
dim_map[j] = static_cast<int>(output_to_input_dim_map[j]);
TensorBlockIO::Copy(dst, src, /*dst_to_src_dim_map=*/dim_map);
}
{ // We need to convert block dimensions from output to input order. auto dst_dims = blk_dims; for (int out_dim = 0; out_dim < NumDims; ++out_dim) {
dst_dims[output_to_input_dim_map[out_dim]] = blk_dims[out_dim];
}
// Write from block buffer to output.
IODst dst(dst_dims, input_strides, output_data, first_coeff_index);
IOSrc src(blk_strides, block_data, 0);
// TODO(ezhulenev): Remove when fully switched to TensorBlock.
DSizes<int, NumDims> dim_map; for (int j = 0; j < NumDims; ++j)
dim_map[j] = static_cast<int>(input_to_output_dim_map[j]);
TensorBlockIO::Copy(dst, src, /*dst_to_src_dim_map=*/dim_map);
}
}
for (Index i = 0; i < dims.TotalSize(); ++i) {
VERIFY_IS_EQUAL(input_data[i], output_data[i]);
}
}
// This is the special case for reading data with reordering, when dimensions // before/after reordering are the same. Squeezing reads along inner dimensions // in this case is illegal, because we reorder innermost dimension. template <int Layout> staticvoid test_block_io_copy_using_reordered_dimensions_do_not_squeeze() {
DSizes<Index, 3> tensor_dims(7, 9, 7);
DSizes<Index, 3> block_dims = tensor_dims;
// This is the special case for reading data with reordering, when dimensions // before/after reordering are the same. Squeezing reads in this case is allowed // because we reorder outer dimensions. template <int Layout> staticvoid test_block_io_copy_using_reordered_dimensions_squeeze() {
DSizes<Index, 4> tensor_dims(7, 5, 9, 9);
DSizes<Index, 4> block_dims = tensor_dims;
using TensorBlockIO = internal::TensorBlockIO<float, Index, 5, Layout>; using IODst = typename TensorBlockIO::Dst; using IOSrc = typename TensorBlockIO::Src;
// Write data from input to output with broadcasting in dims [0, 2, 4].
IODst dst(output_tensor_dims, output_tensor_strides, output.data(), 0);
IOSrc src(input_tensor_strides_with_zeros, input.data(), 0);
TensorBlockIO::Copy(dst, src);
for (int i = 0; i < output_tensor_dims[0]; ++i) { for (int j = 0; j < output_tensor_dims[1]; ++j) { for (int k = 0; k < output_tensor_dims[2]; ++k) { for (int l = 0; l < output_tensor_dims[3]; ++l) { for (int m = 0; m < output_tensor_dims[4]; ++m) { float input_value = input(0, j, 0, l, 0); float output_value = output(i, j, k, l, m);
VERIFY_IS_EQUAL(input_value, output_value);
}
}
}
}
}
}
template <int Layout> staticvoid test_block_io_squeeze_ones() { using TensorBlockIO = internal::TensorBlockIO<float, Index, 5, Layout>; using IODst = typename TensorBlockIO::Dst; using IOSrc = typename TensorBlockIO::Src;
// Total size > 1.
{
DSizes<Index, 5> block_sizes(1, 2, 1, 2, 1); auto strides = internal::strides<Layout>(block_sizes);
// Create a random input tensor.
Tensor<float, 5> input(block_sizes);
input.setRandom();
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.