LCOV - code coverage report
Current view: top level - core - multi_index.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 71 72 98.6 %
Date: 2024-04-28 01:25:40 Functions: 38 40 95.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: BSD-3-Clause
       2             : // Copyright (c) 2023 Scipp contributors (https://github.com/scipp)
       3             : /// @file
       4             : /// @author Simon Heybrock
       5             : 
       6             : #include "scipp/core/multi_index.h"
       7             : #include "scipp-core_export.h"
       8             : #include "scipp/core/except.h"
       9             : 
      10             : namespace scipp::core {
      11             : 
      12             : template class SCIPP_CORE_EXPORT MultiIndex<1>;
      13             : template class SCIPP_CORE_EXPORT MultiIndex<2>;
      14             : template class SCIPP_CORE_EXPORT MultiIndex<3>;
      15             : template class SCIPP_CORE_EXPORT MultiIndex<4>;
      16             : template class SCIPP_CORE_EXPORT MultiIndex<5>;
      17             : 
      18             : namespace {
      19       36913 : void validate_bin_indices_impl(const ElementArrayViewParams &param0,
      20             :                                const ElementArrayViewParams &param1) {
      21       36913 :   const auto &iterDims = param0.dims();
      22       36913 :   auto index = MultiIndex(iterDims, param0.strides(), param1.strides());
      23       36913 :   const auto indices0 = param0.bucketParams().indices;
      24       36913 :   const auto indices1 = param1.bucketParams().indices;
      25    28419668 :   constexpr auto size = [](const auto range) {
      26    28419668 :     return range.second - range.first;
      27             :   };
      28    14246730 :   for (scipp::index i = 0; i < iterDims.volume(); ++i) {
      29    14209834 :     const auto [i0, i1] = index.get();
      30    14209834 :     if (size(indices0[i0]) != size(indices1[i1]))
      31          17 :       throw except::BinnedDataError(
      32             :           "Bin size mismatch in operation with binned data. Refer to "
      33             :           "https://scipp.github.io/user-guide/binned-data/"
      34             :           "computation.html#Overview-and-Quick-Reference for equivalent "
      35          34 :           "operations for binned data (event data).");
      36    14209817 :     index.increment();
      37             :   }
      38       36896 : }
      39             : 
      40       71444 : template <class Param> void validate_bin_indices(const Param &) {}
      41             : 
      42             : /// Check that corresponding bins have matching sizes.
      43             : template <class Param0, class Param1, class... Params>
      44       68589 : void validate_bin_indices(const Param0 &param0, const Param1 &param1,
      45             :                           const Params &...params) {
      46       68589 :   if (param0.bucketParams() && param1.bucketParams())
      47       36913 :     validate_bin_indices_impl(param0, param1);
      48       68572 :   if (param0.bucketParams())
      49       50823 :     validate_bin_indices(param0, params...);
      50             :   else
      51       17749 :     validate_bin_indices(param1, params...);
      52       68569 : }
      53             : 
      54           0 : inline auto get_slice_dim() { return Dim::Invalid; }
      55             : 
      56             : template <class T, class... Ts>
      57       89193 : auto get_slice_dim(const T &param, const Ts &...params) {
      58       89193 :   return param ? param.dim : get_slice_dim(params...);
      59             : }
      60             : 
      61             : template <class T>
      62     3974920 : [[nodiscard]] auto make_span(T &&array, const scipp::index begin) {
      63     3974920 :   return scipp::span{array.data() + begin,
      64     3974920 :                      static_cast<size_t>(NDIM_OP_MAX - begin)};
      65             : }
      66             : 
      67             : template <class StridesArg>
      68     3165368 : [[nodiscard]] scipp::index value_or_default(const StridesArg &strides,
      69             :                                             const scipp::index i) {
      70     3165368 :   return i < strides.size() ? strides[i] : 0;
      71             : }
      72             : 
      73             : template <size_t... I, class... StridesArgs>
      74      157155 : bool can_be_flattened(
      75             :     const scipp::index dim, const scipp::index size, std::index_sequence<I...>,
      76             :     std::array<scipp::index, sizeof...(I)> &strides_for_contiguous,
      77             :     const StridesArgs &...strides) {
      78      157155 :   const bool res =
      79      157155 :       ((value_or_default(strides, dim) == strides_for_contiguous[I]) && ...);
      80      157155 :   ((strides_for_contiguous[I] = size * value_or_default(strides, dim)), ...);
      81      157155 :   return res;
      82             : }
      83             : 
      84             : // non_flattenable_dim is in the storage order of Dimensions & Strides.
      85             : // It is not possible to flatten dimensions outside of the bin-slice dim
      86             : // because they are sliced by that dim and their layout changes depending on
      87             : // the current bin.
      88             : // But the inner dimensions always have the same layout.
      89             : template <class... StridesArgs>
      90             : [[nodiscard]] scipp::index
      91     1987460 : flatten_dims(const scipp::span<std::array<scipp::index, sizeof...(StridesArgs)>>
      92             :                  &out_strides,
      93             :              const scipp::span<scipp::index> &out_shape, const Dimensions &dims,
      94             :              const scipp::index non_flattenable_dim,
      95             :              const StridesArgs &...strides) {
      96     1987460 :   constexpr scipp::index N = sizeof...(StridesArgs);
      97     1987460 :   std::array strides_array{std::ref(strides)...};
      98     1987460 :   std::array<scipp::index, N> strides_for_contiguous{};
      99     1987460 :   scipp::index dim_write = 0;
     100     3188227 :   for (scipp::index dim_read = dims.ndim() - 1; dim_read >= 0; --dim_read) {
     101     1200768 :     if (dim_write >= static_cast<scipp::index>(out_shape.size()))
     102           1 :       throw std::runtime_error("Operations with more than " +
     103             :                                std::to_string(NDIM_OP_MAX) +
     104             :                                " dimensions are not supported. "
     105             :                                "For binned data, the combined bin+event "
     106             :                                "dimensions count");
     107     1200767 :     const auto size = dims.size(dim_read);
     108      383943 :     if (dim_read > non_flattenable_dim &&
     109     1584710 :         dim_write > 0 && // need to write at least one inner dim
     110      157155 :         can_be_flattened(dim_read, size, std::make_index_sequence<N>{},
     111             :                          strides_for_contiguous, strides...)) {
     112       24581 :       out_shape[dim_write - 1] *= size;
     113             :     } else {
     114     1176186 :       out_shape[dim_write] = size;
     115     3808600 :       for (scipp::index data = 0; data < N; ++data) {
     116     2632414 :         out_strides[dim_write][data] =
     117     2632414 :             value_or_default(strides_array[data].get(), dim_read);
     118             :       }
     119     1176186 :       ++dim_write;
     120             :     }
     121             :   }
     122     1987459 :   return dim_write;
     123             : }
     124             : } // namespace
     125             : 
     126             : template <scipp::index N>
     127             : template <class... StridesArgs>
     128     1844572 : MultiIndex<N>::MultiIndex(const Dimensions &iter_dims,
     129             :                           const StridesArgs &...strides)
     130     1844572 :     : m_ndim{flatten_dims(make_span(m_stride, 0), make_span(m_shape, 0),
     131             :                           iter_dims, 0, strides...)},
     132     3689144 :       m_inner_ndim{m_ndim} {}
     133             : 
     134             : template <scipp::index N>
     135             : template <class... Params>
     136       71461 : MultiIndex<N>::MultiIndex(binned_tag, const Dimensions &inner_dims,
     137             :                           const Dimensions &bin_dims, const Params &...params)
     138       71461 :     : m_bin{BinIterator(params.bucketParams(), bin_dims.volume())...} {
     139       71461 :   validate_bin_indices(params...);
     140             : 
     141       71444 :   const Dim slice_dim = get_slice_dim(params.bucketParams()...);
     142             : 
     143             :   // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
     144      142888 :   m_inner_ndim = flatten_dims(
     145       71444 :       make_span(m_stride, 0), make_span(m_shape, 0), inner_dims,
     146             :       inner_dims.index(slice_dim),
     147      142888 :       params.bucketParams() ? params.bucketParams().strides : Strides{}...);
     148             :   // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
     149      142888 :   m_ndim = m_inner_ndim + flatten_dims(make_span(m_stride, m_inner_ndim),
     150       71445 :                                        make_span(m_shape, m_inner_ndim),
     151             :                                        bin_dims, 0, params.strides()...);
     152             : 
     153             :   // NOLINTNEXTLINE(cppcoreguidelines-prefer-member-initializer)
     154       71443 :   m_nested_dim_index = m_inner_ndim - inner_dims.index(slice_dim) - 1;
     155             : 
     156      211454 :   for (scipp::index data = 0; data < N; ++data) {
     157      140011 :     load_bin_params(data);
     158             :   }
     159       71443 :   if (m_shape[m_nested_dim_index] == 0 || bin_dims.volume() == 0)
     160        9178 :     seek_bin();
     161       71443 : }
     162             : 
     163             : template SCIPP_CORE_EXPORT MultiIndex<1>::MultiIndex(const Dimensions &,
     164             :                                                      const Strides &);
     165             : template SCIPP_CORE_EXPORT
     166             : MultiIndex<2>::MultiIndex(const Dimensions &, const Strides &, const Strides &);
     167             : template SCIPP_CORE_EXPORT MultiIndex<3>::MultiIndex(const Dimensions &,
     168             :                                                      const Strides &,
     169             :                                                      const Strides &,
     170             :                                                      const Strides &);
     171             : template SCIPP_CORE_EXPORT
     172             : MultiIndex<4>::MultiIndex(const Dimensions &, const Strides &, const Strides &,
     173             :                           const Strides &, const Strides &);
     174             : template SCIPP_CORE_EXPORT
     175             : MultiIndex<5>::MultiIndex(const Dimensions &, const Strides &, const Strides &,
     176             :                           const Strides &, const Strides &, const Strides &);
     177             : 
     178             : template SCIPP_CORE_EXPORT
     179             : MultiIndex<1>::MultiIndex(binned_tag, const Dimensions &, const Dimensions &,
     180             :                           const ElementArrayViewParams &);
     181             : template SCIPP_CORE_EXPORT
     182             : MultiIndex<2>::MultiIndex(binned_tag, const Dimensions &, const Dimensions &,
     183             :                           const ElementArrayViewParams &,
     184             :                           const ElementArrayViewParams &);
     185             : template SCIPP_CORE_EXPORT
     186             : MultiIndex<3>::MultiIndex(binned_tag, const Dimensions &, const Dimensions &,
     187             :                           const ElementArrayViewParams &,
     188             :                           const ElementArrayViewParams &,
     189             :                           const ElementArrayViewParams &);
     190             : template SCIPP_CORE_EXPORT MultiIndex<4>::MultiIndex(
     191             :     binned_tag, const Dimensions &, const Dimensions &,
     192             :     const ElementArrayViewParams &, const ElementArrayViewParams &,
     193             :     const ElementArrayViewParams &, const ElementArrayViewParams &);
     194             : template SCIPP_CORE_EXPORT MultiIndex<5>::MultiIndex(
     195             :     binned_tag, const Dimensions &, const Dimensions &,
     196             :     const ElementArrayViewParams &, const ElementArrayViewParams &,
     197             :     const ElementArrayViewParams &, const ElementArrayViewParams &,
     198             :     const ElementArrayViewParams &);
     199             : 
     200             : } // namespace scipp::core

Generated by: LCOV version 1.14