LCOV - code coverage report
Current view: top level - core - subbin_sizes.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 69 70 98.6 %
Date: 2024-12-01 01:56:34 Functions: 13 13 100.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             : #include <algorithm>
       6             : #include <numeric>
       7             : 
       8             : #include "scipp/common/except.h"
       9             : #include "scipp/core/element/arithmetic.h"
      10             : #include "scipp/core/element/cumulative.h"
      11             : #include "scipp/core/subbin_sizes.h"
      12             : 
      13             : namespace scipp::core {
      14             : 
      15       94156 : SubbinSizes::SubbinSizes(const scipp::index offset, container_type &&sizes)
      16       94156 :     : m_offset(offset), m_sizes(std::move(sizes)) {
      17       94156 :   if (offset < 0)
      18           0 :     throw std::logic_error("Bad offset in class SubbinSizes.");
      19       94156 : }
      20             : 
      21       72028 : void SubbinSizes::operator=(const scipp::index value) {
      22    13552013 :   for (auto &size : m_sizes)
      23    13479985 :     size = value;
      24       72028 : }
      25             : 
      26       42814 : SubbinSizes &SubbinSizes::operator+=(const SubbinSizes &other) {
      27       42814 :   if (other.offset() < offset()) // avoid realloc if possible
      28           2 :     return *this = *this + other;
      29       42812 :   scipp::index current = other.offset() - offset();
      30       42812 :   const auto length = current + scipp::size(other.sizes());
      31       42812 :   if (length > scipp::size(sizes()))
      32       14396 :     m_sizes.resize(length);
      33     2411581 :   for (const auto &x : other.sizes())
      34     2368769 :     m_sizes[current++] += x;
      35       42812 :   return *this;
      36             : }
      37             : 
      38           5 : SubbinSizes &SubbinSizes::operator-=(const SubbinSizes &other) {
      39           5 :   return *this = *this - other;
      40             : }
      41             : 
      42       29230 : SubbinSizes SubbinSizes::cumsum_exclusive() const {
      43       29230 :   auto out = sizes();
      44       29230 :   scipp::index sum = 0;
      45    11160338 :   for (auto &x : out)
      46    11131108 :     element::exclusive_scan(sum, x);
      47       58460 :   return {offset(), std::move(out)};
      48       29230 : }
      49             : 
      50       29230 : scipp::index SubbinSizes::sum() const {
      51       29230 :   return std::accumulate(sizes().begin(), sizes().end(), scipp::index{0});
      52             : }
      53             : 
      54      111542 : SubbinSizes &SubbinSizes::add_intersection(const SubbinSizes &other) {
      55      111542 :   scipp::index delta = other.offset() - offset();
      56      111542 :   auto i = std::max(scipp::index(0), delta);
      57      111542 :   auto j = std::max(scipp::index(0), -delta);
      58    14223888 :   for (; j < scipp::size(other.sizes()) && i < scipp::size(sizes()); ++j, ++i) {
      59    14112346 :     m_sizes[i] += other.sizes()[j];
      60             :   }
      61      111542 :   return *this;
      62             : }
      63             : 
      64          43 : bool operator==(const SubbinSizes &a, const SubbinSizes &b) {
      65          43 :   return (a.offset() == b.offset()) && (a.sizes() == b.sizes());
      66             : }
      67             : 
      68             : template <class Op>
      69          17 : SubbinSizes binary(const SubbinSizes &a, const SubbinSizes &b, Op op) {
      70          17 :   const auto begin = std::min(a.offset(), b.offset());
      71          17 :   const auto end =
      72          17 :       std::max(a.offset() + a.sizes().size(), b.offset() + b.sizes().size());
      73          17 :   typename SubbinSizes::container_type sizes(end - begin);
      74          17 :   scipp::index current = a.offset() - begin;
      75          81 :   for (const auto &size : a.sizes())
      76          64 :     sizes[current++] += size;
      77          17 :   current = b.offset() - begin;
      78          44 :   for (const auto &size : b.sizes())
      79          27 :     op(sizes[current++], size);
      80          34 :   return {begin, std::move(sizes)};
      81          17 : }
      82             : 
      83           7 : SubbinSizes operator+(const SubbinSizes &a, const SubbinSizes &b) {
      84           7 :   return binary(a, b, element::add_equals);
      85             : }
      86             : 
      87          10 : SubbinSizes operator-(const SubbinSizes &a, const SubbinSizes &b) {
      88          10 :   return binary(a, b, element::subtract_equals);
      89             : }
      90             : 
      91             : /** Perform a step of an exclusive scan.
      92             :  *
      93             :  * The instance is the accumulant, the argument is the next value to be added.
      94             :  * Trims the accumulant to the offset and size of the argument.
      95             :  *
      96             :  * Note that effective cache use matters here, so we do not implemented this
      97             :  * via suboperations but a single loop.
      98             :  */
      99       42811 : void SubbinSizes::exclusive_scan(SubbinSizes &x) {
     100       42811 :   const scipp::index osize = scipp::size(sizes());
     101       42811 :   const scipp::index size = scipp::size(x.sizes());
     102       42811 :   const auto delta = x.offset() - offset();
     103       42811 :   m_sizes.reserve(size);
     104       42811 :   m_offset = x.m_offset;
     105     2411581 :   for (scipp::index i = 0; i < size; ++i) {
     106     2368770 :     const auto prev = delta + i >= osize ? 0 : m_sizes[delta + i];
     107     2368770 :     if (i >= osize)
     108        3710 :       m_sizes.push_back(prev + x.m_sizes[i]);
     109             :     else
     110     2365060 :       m_sizes[i] = prev + x.m_sizes[i];
     111     2368770 :     x.m_sizes[i] = prev;
     112             :   }
     113       42811 :   m_sizes.resize(size);
     114       42811 : }
     115             : 
     116             : } // namespace scipp::core

Generated by: LCOV version 1.14