OpenKalman
tests.hpp
Go to the documentation of this file.
1 /* This file is part of OpenKalman, a header-only C++ library for
2  * Kalman filters and other recursive filters.
3  *
4  * Copyright (c) 2017-2026 Christopher Lee Ogden <ogden@gatech.edu>
5  *
6  * This Source Code Form is subject to the terms of the Mozilla Public
7  * License, v. 2.0. If a copy of the MPL was not distributed with this
8  * file, You can obtain one at https://mozilla.org/MPL/2.0/.
9  */
10 
16 #ifndef OPENKALMAN_LINEAR_ALGEBRA_TESTS_HPP
17 #define OPENKALMAN_LINEAR_ALGEBRA_TESTS_HPP
18 
25 
26 namespace OpenKalman::test
27 {
28  // ------------------- //
29  // indexible objects //
30  // ------------------- //
31 
32 #ifdef __cpp_concepts
33  template<indexible Arg1, indexible Arg2, typename Err> requires
34  (values::value<Err> or indexible<Err>) and
35  (not collections::collection<Arg1> or not collections::collection<Arg2>)
36  struct TestComparison<Arg1, Arg2, Err>
37 #else
38  template<typename Arg1, typename Arg2, typename Err>
39  struct TestComparison<Arg1, Arg2, Err, std::enable_if_t<
40  indexible<Arg1> and indexible<Arg2> and
41  (values::value<Err> or indexible<Err>) and
42  (not collections::collection<Arg1> or not collections::collection<Arg2>)>>
43 #endif
44  : ::testing::AssertionResult
45  {
46  private:
47 
48  static_assert(not indexible<Err> or
49  values::fixed_value_compares_with<index_count<Err>, std::max(index_count_v<Arg1>, index_count_v<Arg2>)>);
50 
51  static constexpr std::size_t
52  rank1 = std::decay_t<decltype(get_mdspan(std::declval<Arg1&>()))>::rank();
53 
54  static constexpr std::size_t
55  rank2 = std::decay_t<decltype(get_mdspan(std::declval<Arg2&>()))>::rank();
56 
57 
58  template<typename Indices>
59  static constexpr auto
60  print_indices(const Indices& indices, std::index_sequence<>) { return std::string{"()"}; }
61 
62  template<typename Indices, std::size_t i, std::size_t...is>
63  static constexpr auto
64  print_indices(const Indices& indices, std::index_sequence<i, is...>)
65  {
66  return std::string{"("} + (std::to_string(std::get<i>(indices)) + ... + (", " + std::to_string(std::get<is>(indices)))) + ")";
67  }
68 
69 
70  template<typename Indices, std::size_t...i1, std::size_t...i2>
71  static ::testing::AssertionResult
72  compare_element(const Arg1& arg1, const Arg2& arg2, const Err& e, const Indices& indices,
74  {
75  auto indices1 = std::array {std::get<i1>(indices)...};
76  auto indices2 = std::array {std::get<i2>(indices)...};
77  auto res = test::TestComparison {get_mdspan(arg1)[indices1], get_mdspan(arg2)[indices2], e};
78  if (res) return ::testing::AssertionSuccess();
79  constexpr auto seq = std::make_index_sequence<std::max(rank1, rank2)>{};
80  return ::testing::AssertionFailure() << print_indices(indices, seq) << ": " << res.message() << std::endl;
81  }
82 
83 
84  template<typename...Ix>
85  static ::testing::AssertionResult
86  compare_mdspan(const Arg1& arg1, const Arg2& arg2, const Err& err, Ix...ix)
87  {
88  constexpr std::size_t ind = sizeof...(Ix);
89  if constexpr (ind < std::min(rank1, rank2))
90  {
91  auto dim1 = get_index_extent<ind>(arg1);
92  auto dim2 = get_index_extent<ind>(arg2);
93  if (dim1 != dim2) return ::testing::AssertionFailure() << "Dimensions do not match for index " <<
94  std::to_string(ind) << ": " << std::to_string(dim1) << " != " << std::to_string(dim2) << ")";
95  std::string msg = "";
96  for (std::size_t i = 0; i < dim1; ++i) msg += compare_mdspan(arg1, arg2, err, ix..., i).message();
97  if (msg.size() == 0) return ::testing::AssertionSuccess();
98  return ::testing::AssertionFailure() << msg;
99  }
100  else if constexpr (ind < std::max(rank1, rank2))
101  {
102  auto dim = rank2 > rank1 ? get_index_extent<ind>(arg2) : get_index_extent<ind>(arg1);
103  if (dim != 1) return ::testing::AssertionFailure() << "Dimensions do not match for index" <<
104  std::to_string(ind) << " (" << (rank2 > rank1 ? "1" : std::to_string(dim)) << " != " << (rank2 < rank1 ? "1" : std::to_string(dim)) << ")";
105  std::string msg = compare_mdspan(arg1, arg2, err, ix..., 0_uz).message();
106  if (msg.size() == 0) return ::testing::AssertionSuccess();
107  return ::testing::AssertionFailure() << msg;
108  }
109  else
110  {
111  auto indices = std::array{ix...};
112  auto e = [&]{ if constexpr (indexible<Err>) return err[indices]; else return err; }();
113  return compare_element(arg1, arg2, e, indices, std::make_index_sequence<rank1>{}, std::make_index_sequence<rank2>{});
114  }
115  }
116 
117  public:
118 
119  TestComparison(const Arg1& arg1, const Arg2& arg2, const Err& err)
120  : ::testing::AssertionResult {compare_mdspan(arg1, arg2, err)} {};
121 
122  };
123 
124 
125 }
126 
127 
128 #endif
Definition of get_index_extent function.
Definition: tests.hpp:36
Definition: tests.hpp:22
Inclusion file for collections.
Definition of get_mdspan function.
Definition for index_count.
Definition: trait_backports.hpp:64
constexpr bool fixed_value_compares_with
T has a fixed value that compares with N in a particular way based on parameter comp.
Definition: fixed_value_compares_with.hpp:74
Definition for indexible.
The minimum number of indices needed to access all the components of an object (i.e., the rank or order).
Definition: index_count.hpp:34
decltype(auto) constexpr get_mdspan(T &&t)
Get the mdspan associated with indexible object T.
Definition: get_mdspan.hpp:35