LCOV - code coverage report
Current view: top level - core/include/scipp/core/element - comparison.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 42 47 89.4 %
Date: 2024-04-28 01:25:40 Functions: 77 318 24.2 %

          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 Piotr Rozyczko
       5             : #pragma once
       6             : 
       7             : #include <cmath>
       8             : 
       9             : #include "scipp/common/numeric.h"
      10             : #include "scipp/common/overloaded.h"
      11             : #include "scipp/core/eigen.h"
      12             : #include "scipp/core/element/arg_list.h"
      13             : #include "scipp/core/transform_common.h"
      14             : #include "scipp/core/values_and_variances.h"
      15             : 
      16             : /// Operators to be used with transform and transform_in_place to implement
      17             : /// operations for Variable.
      18             : namespace scipp::core::element {
      19             : 
      20             : using isclose_types_t = arg_list_t<
      21             :     double, float, int64_t, int32_t, std::tuple<float, float, double>,
      22             :     std::tuple<int64_t, int64_t, double>, std::tuple<int32_t, int32_t, double>,
      23             :     std::tuple<int32_t, int64_t, double>, std::tuple<int64_t, int32_t, double>,
      24             :     std::tuple<int64_t, int32_t, int64_t>,
      25             :     std::tuple<int32_t, int32_t, int64_t>,
      26             :     std::tuple<int32_t, int64_t, int64_t>>;
      27             : 
      28         449 : constexpr auto isclose_units = [](const units::Unit &x, const units::Unit &y,
      29             :                                   const units::Unit &t) {
      30         449 :   expect::equals(x, y);
      31         449 :   expect::equals(x, t);
      32         449 :   return units::none;
      33             : };
      34             : 
      35             : constexpr auto isclose = overloaded{
      36             :     transform_flags::expect_no_variance_arg_t<2>{}, isclose_types_t{},
      37       21804 :     isclose_units, [](const auto &x, const auto &y, const auto &t) {
      38             :       using std::abs;
      39       21804 :       return abs(x - y) <= t;
      40             :     }};
      41             : 
      42             : constexpr auto isclose_equal_nan = overloaded{
      43             :     transform_flags::expect_no_variance_arg_t<2>{}, isclose_types_t{},
      44         268 :     isclose_units, [](const auto &x, const auto &y, const auto &t) {
      45             :       using std::abs;
      46             :       using numeric::isnan;
      47             :       using numeric::isinf;
      48             :       using numeric::signbit;
      49         268 :       if (isnan(x) && isnan(y))
      50           1 :         return true;
      51         267 :       if (isinf(x) && isinf(y) && signbit(x) == signbit(y))
      52           0 :         return true;
      53         267 :       return abs(x - y) <= t;
      54             :     }};
      55             : 
      56             : struct comparison_types_t {
      57             :   constexpr void operator()() const noexcept;
      58             :   using types = decltype(std::tuple_cat(std::declval<arithmetic_type_pairs>(),
      59             :                                         std::tuple<bool>{},
      60             :                                         std::tuple<core::time_point>{}));
      61             : };
      62             : 
      63             : struct equality_types_t {
      64             :   constexpr void operator()() const noexcept;
      65             :   using types = decltype(std::tuple_cat(
      66             :       comparison_types_t::types{}, std::tuple<std::string>{},
      67             :       std::tuple<Eigen::Vector3d>{}, std::tuple<Eigen::Matrix3d>{},
      68             :       std::tuple<Eigen::Affine3d>{}, std::tuple<Quaternion>{},
      69             :       std::tuple<Translation>{}));
      70             : };
      71             : 
      72             : // Allow variance broadcasts because we just want to check for numeric equality.
      73             : // For inequalities, the variances are ignored anyway.
      74             : // See issue #3266
      75             : constexpr auto comparison = overloaded{
      76             :     transform_flags::no_out_variance, transform_flags::force_variance_broadcast,
      77        5665 :     [](const units::Unit &x, const units::Unit &y) {
      78        5666 :       expect::equals(x, y);
      79        5664 :       return units::none;
      80             :     }};
      81             : 
      82             : constexpr auto inequality = overloaded{comparison_types_t{}, comparison};
      83             : 
      84             : constexpr auto equality = overloaded{equality_types_t{}, comparison};
      85             : 
      86             : constexpr auto less = overloaded{
      87             :     inequality,
      88         596 :     [](const auto &x, const auto &y) { return x < y; },
      89             : };
      90             : 
      91             : constexpr auto greater = overloaded{
      92             :     inequality,
      93        5092 :     [](const auto &x, const auto &y) { return x > y; },
      94             : };
      95             : 
      96             : constexpr auto less_equal = overloaded{
      97             :     inequality,
      98        1109 :     [](const auto &x, const auto &y) { return x <= y; },
      99             : };
     100             : 
     101             : constexpr auto greater_equal =
     102        1835 :     overloaded{inequality, [](const auto &x, const auto &y) { return x >= y; }};
     103             : 
     104             : constexpr auto equal = overloaded{
     105             :     equality,
     106        1487 :     [](const auto &x, const auto &y) {
     107             :       using numeric::operator==;
     108        1487 :       return x == y;
     109             :     },
     110             : };
     111             : constexpr auto not_equal =
     112         356 :     overloaded{equality, [](const auto &x, const auto &y) {
     113             :                  using numeric::operator!=;
     114         356 :                  return x != y;
     115             :                }};
     116             : 
     117             : constexpr auto max_equals =
     118             :     overloaded{arg_list<double, float, int64_t, int32_t, bool, time_point>,
     119             :                transform_flags::expect_in_variance_if_out_variance,
     120    49598064 :                [](auto &&a, const auto &b) {
     121             :                  using numeric::isnan;
     122             :                  using std::max;
     123    49598064 :                  if (isnan(b))
     124           0 :                    a = b;
     125    49598064 :                  else if (!isnan(a))
     126    49598064 :                    a = max(a, b);
     127    49598064 :                }};
     128             : 
     129             : constexpr auto nanmax_equals =
     130             :     overloaded{arg_list<double, float, int64_t, int32_t, bool, time_point>,
     131             :                transform_flags::expect_in_variance_if_out_variance,
     132         480 :                [](auto &&a, const auto &b) {
     133             :                  using numeric::isnan;
     134             :                  using std::max;
     135         480 :                  if (isnan(a))
     136           0 :                    a = b;
     137         480 :                  if (!isnan(b))
     138         418 :                    a = max(a, b);
     139         480 :                }};
     140             : 
     141             : constexpr auto min_equals =
     142             :     overloaded{arg_list<double, float, int64_t, int32_t, bool, time_point>,
     143             :                transform_flags::expect_in_variance_if_out_variance,
     144    49597242 :                [](auto &&a, const auto &b) {
     145             :                  using numeric::isnan;
     146             :                  using std::min;
     147    49597242 :                  if (isnan(b))
     148           0 :                    a = b;
     149    49597242 :                  else if (!isnan(a))
     150    49597242 :                    a = min(a, b);
     151    49597242 :                }};
     152             : 
     153             : constexpr auto nanmin_equals =
     154             :     overloaded{arg_list<double, float, int64_t, int32_t, bool, time_point>,
     155             :                transform_flags::expect_in_variance_if_out_variance,
     156         480 :                [](auto &&a, const auto &b) {
     157             :                  using numeric::isnan;
     158             :                  using std::min;
     159         480 :                  if (isnan(a))
     160           0 :                    a = b;
     161         480 :                  if (!isnan(b))
     162         418 :                    a = min(a, b);
     163         480 :                }};
     164             : 
     165             : } // namespace scipp::core::element

Generated by: LCOV version 1.14