Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/MySQL/unsupported/test/   (MySQL Server Version 8.1-8.4©)  Datei vom 12.11.2025 mit Größe 15 kB image not shown  

Quelle  cxx11_tensor_block_io.cpp   Sprache: C

 
// 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);
}

static internal::TensorBlockShapeType RandomBlockShape() {
  return internal::random<bool>()
         ? internal::TensorBlockShapeType::kUniformAllDims
         : internal::TensorBlockShapeType::kSkewedInnerDims;
}

template <int NumDims>
static size_t RandomTargetBlockSize(const DSizes<Index, NumDims>& dims) {
  return internal::random<size_t>(1, dims.TotalSize());
}

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>
static void 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);

  const T* input_data = input.data();
  T* output_data = output.data();
  T* block_data = block.data();

  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>
static void 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);

  const T* input_data = input.data();
  T* output_data = output.data();
  T* block_data = block.data();

  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>
static void 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;

  DSizes<int, 3> block_to_tensor_dim;
  block_to_tensor_dim[0] = 2;
  block_to_tensor_dim[1] = 1;
  block_to_tensor_dim[2] = 0;

  auto tensor_strides = internal::strides<Layout>(tensor_dims);
  auto block_strides = internal::strides<Layout>(block_dims);

  Tensor<float, 3, Layout> block(block_dims);
  Tensor<float, 3, Layout> tensor(tensor_dims);
  tensor.setRandom();

  float* tensor_data = tensor.data();
  float* block_data = block.data();

  using TensorBlockIO = internal::TensorBlockIO<float, Index, 3, Layout>;
  using IODst = typename TensorBlockIO::Dst;
  using IOSrc = typename TensorBlockIO::Src;

  // Read from a tensor into a block.
  IODst dst(block_dims, block_strides, block_data, 0);
  IOSrc src(tensor_strides, tensor_data, 0);

  TensorBlockIO::Copy(dst, src, /*dst_to_src_dim_map=*/block_to_tensor_dim);

  TensorMap<Tensor<float, 3, Layout> > block_tensor(block_data, block_dims);
  TensorMap<Tensor<float, 3, Layout> > tensor_tensor(tensor_data, tensor_dims);

  for (Index d0 = 0; d0 < tensor_dims[0]; ++d0) {
    for (Index d1 = 0; d1 < tensor_dims[1]; ++d1) {
      for (Index d2 = 0; d2 < tensor_dims[2]; ++d2) {
        float block_value = block_tensor(d2, d1, d0);
        float tensor_value = tensor_tensor(d0, d1, d2);
        VERIFY_IS_EQUAL(block_value, tensor_value);
      }
    }
  }
}

// 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>
static void test_block_io_copy_using_reordered_dimensions_squeeze() {
  DSizes<Index, 4> tensor_dims(7, 5, 9, 9);
  DSizes<Index, 4> block_dims = tensor_dims;

  DSizes<int, 4> block_to_tensor_dim;
  block_to_tensor_dim[0] = 0;
  block_to_tensor_dim[1] = 1;
  block_to_tensor_dim[2] = 3;
  block_to_tensor_dim[3] = 2;

  auto tensor_strides = internal::strides<Layout>(tensor_dims);
  auto block_strides = internal::strides<Layout>(block_dims);

  Tensor<float, 4, Layout> block(block_dims);
  Tensor<float, 4, Layout> tensor(tensor_dims);
  tensor.setRandom();

  float* tensor_data = tensor.data();
  float* block_data = block.data();

  using TensorBlockIO = internal::TensorBlockIO<float, Index, 4, Layout>;
  using IODst = typename TensorBlockIO::Dst;
  using IOSrc = typename TensorBlockIO::Src;

  // Read from a tensor into a block.
  IODst dst(block_dims, block_strides, block_data, 0);
  IOSrc src(tensor_strides, tensor_data, 0);

  TensorBlockIO::Copy(dst, src, /*dst_to_src_dim_map=*/block_to_tensor_dim);

  TensorMap<Tensor<float, 4, Layout> > block_tensor(block_data, block_dims);
  TensorMap<Tensor<float, 4, Layout> > tensor_tensor(tensor_data, tensor_dims);

  for (Index d0 = 0; d0 < tensor_dims[0]; ++d0) {
    for (Index d1 = 0; d1 < tensor_dims[1]; ++d1) {
      for (Index d2 = 0; d2 < tensor_dims[2]; ++d2) {
        for (Index d3 = 0; d3 < tensor_dims[3]; ++d3) {
          float block_value = block_tensor(d0, d1, d3, d2);
          float tensor_value = tensor_tensor(d0, d1, d2, d3);
          VERIFY_IS_EQUAL(block_value, tensor_value);
        }
      }
    }
  }
}

template <int Layout>
static void test_block_io_zero_stride() {
  DSizes<Index, 5> rnd_dims = RandomDims<5>(1, 30);

  DSizes<Index, 5> input_tensor_dims = rnd_dims;
  input_tensor_dims[0] = 1;
  input_tensor_dims[2] = 1;
  input_tensor_dims[4] = 1;

  Tensor<float, 5, Layout> input(input_tensor_dims);
  input.setRandom();

  DSizes<Index, 5> output_tensor_dims = rnd_dims;

  auto input_tensor_strides = internal::strides<Layout>(input_tensor_dims);
  auto output_tensor_strides = internal::strides<Layout>(output_tensor_dims);

  auto input_tensor_strides_with_zeros = input_tensor_strides;
  input_tensor_strides_with_zeros[0] = 0;
  input_tensor_strides_with_zeros[2] = 0;
  input_tensor_strides_with_zeros[4] = 0;

  Tensor<float, 5, Layout> output(output_tensor_dims);
  output.setRandom();

  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>
static void 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();

    Tensor<float, 5> output(block_sizes);

    IODst dst(block_sizes, strides, output.data(), 0);
    IOSrc src(strides, input.data());
    TensorBlockIO::Copy(dst, src);

    for (Index i = 0; i < block_sizes.TotalSize(); ++i) {
      VERIFY_IS_EQUAL(output.data()[i], input.data()[i]);
    }
  }

  // Total size == 1.
  {
    DSizes<Index, 5> block_sizes(1, 1, 1, 1, 1);
    auto strides = internal::strides<Layout>(block_sizes);

    // Create a random input tensor.
    Tensor<float, 5> input(block_sizes);
    input.setRandom();

    Tensor<float, 5> output(block_sizes);

    IODst dst(block_sizes, strides, output.data(), 0);
    IOSrc src(strides, input.data());
    TensorBlockIO::Copy(dst, src);

    for (Index i = 0; i < block_sizes.TotalSize(); ++i) {
      VERIFY_IS_EQUAL(output.data()[i], input.data()[i]);
    }
  }
}

#define CALL_SUBTESTS(NAME)                   \
  CALL_SUBTEST((NAME<float, 1, RowMajor>())); \
  CALL_SUBTEST((NAME<float, 2, RowMajor>())); \
  CALL_SUBTEST((NAME<float, 4, RowMajor>())); \
  CALL_SUBTEST((NAME<float, 5, RowMajor>())); \
  CALL_SUBTEST((NAME<float, 1, ColMajor>())); \
  CALL_SUBTEST((NAME<float, 2, ColMajor>())); \
  CALL_SUBTEST((NAME<float, 4, ColMajor>())); \
  CALL_SUBTEST((NAME<float, 5, ColMajor>())); \
  CALL_SUBTEST((NAME<bool, 1, RowMajor>())); \
  CALL_SUBTEST((NAME<bool, 2, RowMajor>())); \
  CALL_SUBTEST((NAME<bool, 4, RowMajor>())); \
  CALL_SUBTEST((NAME<bool, 5, RowMajor>())); \
  CALL_SUBTEST((NAME<bool, 1, ColMajor>())); \
  CALL_SUBTEST((NAME<bool, 2, ColMajor>())); \
  CALL_SUBTEST((NAME<bool, 4, ColMajor>())); \
  CALL_SUBTEST((NAME<bool, 5, ColMajor>()))

EIGEN_DECLARE_TEST(cxx11_tensor_block_io) {
  // clang-format off
  CALL_SUBTESTS(test_block_io_copy_data_from_source_to_target);
  CALL_SUBTESTS(test_block_io_copy_using_reordered_dimensions);

  CALL_SUBTEST(test_block_io_copy_using_reordered_dimensions_do_not_squeeze<RowMajor>());
  CALL_SUBTEST(test_block_io_copy_using_reordered_dimensions_do_not_squeeze<ColMajor>());

  CALL_SUBTEST(test_block_io_copy_using_reordered_dimensions_squeeze<RowMajor>());
  CALL_SUBTEST(test_block_io_copy_using_reordered_dimensions_squeeze<ColMajor>());

  CALL_SUBTEST(test_block_io_zero_stride<RowMajor>());
  CALL_SUBTEST(test_block_io_zero_stride<ColMajor>());

  CALL_SUBTEST(test_block_io_squeeze_ones<RowMajor>());
  CALL_SUBTEST(test_block_io_squeeze_ones<ColMajor>());
  // clang-format on
}

75%


¤ Dauer der Verarbeitung: 0.17 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

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.