OpenKalman
compares_with.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) 2019-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_COORDINATE_COMPARES_WITH_HPP
17 #define OPENKALMAN_COORDINATE_COMPARES_WITH_HPP
18 
21 
22 namespace OpenKalman::patterns
23 {
24  namespace detail
25  {
26  template<auto comp, bool op_is_and = false, typename...Ords>
27  constexpr bool
28  do_comps(Ords...ords)
29  {
30  if constexpr (op_is_and) return (... and stdex::invoke(comp, ords));
31  else return (... or stdex::invoke(comp, ords));
32  }
33 
34 
35  constexpr std::size_t
36  inc_bank(std::size_t bank, std::size_t inc)
37  {
38  return (bank == stdex::dynamic_extent or inc == stdex::dynamic_extent) ? stdex::dynamic_extent : bank + inc;
39  }
40 
41 
42 #ifdef __cpp_concepts
43  template<typename A, typename B>
44 #else
45  template<typename A, typename B, typename = void>
46 #endif
47  struct same_descriptors : std::false_type {};
48 
49 #ifdef __cpp_concepts
50  template<typename A, typename B> requires
51  std::bool_constant<internal::get_descriptor_hash_code(A{}) == internal::get_descriptor_hash_code(B{})>::value
53 #else
54  template<typename A, typename B>
55  struct same_descriptors<A, B, std::enable_if_t<
56  std::bool_constant<internal::get_descriptor_hash_code(A{}) == internal::get_descriptor_hash_code(B{})>::value>>
57 #endif
58  : std::true_type {};
59 
60 
61 #ifdef __cpp_concepts
62  template<typename A, typename B>
63 #else
64  template<typename A, typename B, typename = void>
65 #endif
66  struct different_descriptors : std::false_type {};
67 
68 #ifdef __cpp_concepts
69  template<typename A, typename B> requires
70  std::bool_constant<internal::get_descriptor_hash_code(A{}) != internal::get_descriptor_hash_code(B{})>::value
72 #else
73  template<typename A, typename B>
74  struct different_descriptors<A, B, std::enable_if_t<
75  std::bool_constant<internal::get_descriptor_hash_code(A{}) != internal::get_descriptor_hash_code(B{})>::value>>
76 #endif
77  : std::true_type {};
78 
79 
80  template<typename A, typename B, auto comp, applicability app,
81  std::size_t ia = 0, std::size_t ib = 0, std::size_t abank = 0, std::size_t bbank = 0>
82  constexpr bool
83  compares_with_iter()
84  {
86 
87  if constexpr (ia < collections::size_of_v<A>)
88  {
89  using Ai = std::decay_t<collections::collection_element_t<ia, A>>;
90  constexpr bool ae = euclidean_pattern<Ai>;
91  constexpr std::size_t dim_Ai = dimension_of_v<Ai>;
92  if constexpr (ib < collections::size_of_v<B>)
93  {
94  using Bi = std::decay_t<collections::collection_element_t<ib, B>>;
95  constexpr bool be = euclidean_pattern<Bi>;
96  constexpr std::size_t dim_Bi = dimension_of_v<Bi>;
97 
98  if constexpr (ae and be)
99  {
100  return compares_with_iter<A, B, comp, app, ia + 1, ib + 1, inc_bank(abank, dim_Ai), bbank + dim_Bi>();
101  }
102  else if constexpr (ae)
103  {
104  return compares_with_iter<A, B, comp, app, ia + 1, ib, inc_bank(abank, dim_Ai), bbank>();
105  }
106  else if constexpr (be)
107  {
108  return compares_with_iter<A, B, comp, app, ia, ib + 1, abank, inc_bank(bbank, dim_Bi)>();
109  }
110  else if constexpr (abank == stdex::dynamic_extent or bbank == stdex::dynamic_extent)
111  {
112  return app == applicability::permitted and do_comps<comp>(partial_ordering::equivalent, partial_ordering::unordered);
113  }
114  else if constexpr (abank != bbank)
115  {
116  return do_comps<comp>(partial_ordering::unordered);
117  }
118  else if constexpr (same_descriptors<Ai, Bi>::value)
119  {
120  return compares_with_iter<A, B, comp, app, ia + 1, ib + 1>();
121  }
122  else if constexpr (different_descriptors<Ai, Bi>::value)
123  {
124  return do_comps<comp>(partial_ordering::unordered);
125  }
126  else if constexpr (do_comps<comp>(partial_ordering::equivalent))
127  {
128  return app == applicability::permitted and
129  compares_with_iter<A, B, comp, app, ia + 1, ib + 1>();
130  }
131  else if constexpr (do_comps<comp>(partial_ordering::unordered))
132  {
133  return app == applicability::permitted or
134  compares_with_iter<A, B, comp, app, ia + 1, ib + 1>();
135  }
136  else if constexpr (do_comps<comp>(partial_ordering::less))
137  {
138  return app == applicability::permitted and
139  (dim_Ai == stdex::dynamic_extent or dim_Ai == 0) and
140  compares_with_iter<A, B, comp, app, ia + 1, ib + 1, dim_Ai, dim_Bi>();
141  }
142  else //if constexpr (do_comps<comp>(partial_ordering::greater))
143  {
144  return app == applicability::permitted and
145  (dim_Bi == stdex::dynamic_extent or dim_Bi == 0) and
146  compares_with_iter<A, B, comp, app, ia + 1, ib + 1, dim_Ai, dim_Bi>();
147  }
148  }
149  else if constexpr (euclidean_pattern<Ai>)
150  {
151  return compares_with_iter<A, B, comp, app, ia + 1, ib, inc_bank(abank, dim_Ai), bbank>();
152  }
153  else if constexpr (abank == stdex::dynamic_extent or bbank == stdex::dynamic_extent)
154  {
155  return (dim_Ai != stdex::dynamic_extent and do_comps<comp>(partial_ordering::unordered)) or
156  (app == applicability::permitted and (dim_Ai == stdex::dynamic_extent or do_comps<comp>(partial_ordering::greater)));
157  }
158  else if (abank >= bbank)
159  {
160  return do_comps<comp>(partial_ordering::greater);
161  }
162  else if constexpr (dim_Ai == stdex::dynamic_extent)
163  {
164  return app == applicability::permitted and
165  ( do_comps<comp>(partial_ordering::unordered, partial_ordering::greater, partial_ordering::equivalent) or
166  (do_comps<comp>(partial_ordering::less) and bbank > 0));
167  }
168  else
169  {
170  return do_comps<comp>(partial_ordering::unordered);
171  }
172  }
173  else if constexpr (ib < collections::size_of_v<B>) // ia >= collections::size_of_v<A>
174  {
175  using Bi = std::decay_t<collections::collection_element_t<ib, B>>;
176  constexpr std::size_t dim_Bi = dimension_of_v<Bi>;
177 
178  if constexpr (euclidean_pattern<Bi>)
179  {
180  return compares_with_iter<A, B, comp, app, ia, ib + 1, abank, inc_bank(bbank, dim_Bi)>();
181  }
182  else if constexpr (abank == stdex::dynamic_extent or bbank == stdex::dynamic_extent)
183  {
184  return (dim_Bi != stdex::dynamic_extent and do_comps<comp>(partial_ordering::unordered)) or
185  (app == applicability::permitted and (dim_Bi == stdex::dynamic_extent or do_comps<comp>(partial_ordering::less)));
186  }
187  else if (abank <= bbank)
188  {
189  return do_comps<comp>(partial_ordering::less);
190  }
191  else if constexpr (dim_Bi == stdex::dynamic_extent)
192  {
193  return app == applicability::permitted and
194  ( do_comps<comp>(partial_ordering::unordered, partial_ordering::less, partial_ordering::equivalent) or
195  (do_comps<comp>(partial_ordering::greater) and abank > 0));
196  }
197  else
198  {
199  return do_comps<comp>(partial_ordering::unordered);
200  }
201  }
202  else if constexpr (abank != stdex::dynamic_extent and bbank != stdex::dynamic_extent)
203  {
204  return do_comps<comp>(stdex::compare_three_way{}(abank, bbank));
205  }
206  else if constexpr (abank == 0)
207  {
208  return do_comps<comp, app == applicability::guaranteed>(partial_ordering::less, partial_ordering::equivalent);
209  }
210  else if constexpr (bbank == 0)
211  {
212  return do_comps<comp, app == applicability::guaranteed>(partial_ordering::greater, partial_ordering::equivalent);
213  }
214  else if constexpr (abank != stdex::dynamic_extent or bbank != stdex::dynamic_extent)
215  {
216  return app == applicability::permitted and do_comps<comp>(partial_ordering::less, partial_ordering::greater, partial_ordering::equivalent);
217  }
218  else
219  {
220  return app == applicability::permitted;
221  }
222  }
223 
224 
225  template<typename T, typename U, auto comp, applicability a>
226  constexpr bool
228  {
232 
233  if constexpr (descriptor<T>)
234  {
235  return compares_with_impl<std::tuple<stdex::unwrap_ref_decay_t<T>>, U, comp, a>();
236  }
237  else if constexpr (descriptor<U>)
238  {
239  return compares_with_impl<T, std::tuple<stdex::unwrap_ref_decay_t<U>>, comp, a>();
240  }
241 
245 
246  else if constexpr (not values::fixed<dimension_of<T>> and not values::fixed<dimension_of<U>>)
247  {
248  using DT = stdex::ranges::range_value_t<T>;
249  using DU = stdex::ranges::range_value_t<U>;
250  if constexpr ((euclidean_pattern<DT> and euclidean_pattern<DU>))
251  return detail::do_comps<comp>(stdex::partial_ordering::equivalent);
252  else if constexpr (dimension_of_v<DT> == 0 or dimension_of_v<DU> == 0)
253  return values::size_compares_with<dimension_of<DT>, dimension_of<DU>, comp, a>;
254  else if constexpr (dimension_of_v<DT> == stdex::dynamic_extent or dimension_of_v<DU> == stdex::dynamic_extent)
255  return a == applicability::permitted;
256  else if constexpr (compares_with_impl<DT, DU, &stdex::is_eq, a>())
257  return detail::do_comps<comp>(stdex::partial_ordering::equivalent);
258  else
259  return false;
260  }
261  else if constexpr (not values::fixed<dimension_of<T>>) // and values::fixed<dimension_of<U>>
262  {
263  using DT = stdex::ranges::range_value_t<T>;
264  if constexpr (euclidean_pattern<DT> and euclidean_pattern<U>)
265  {
266  return detail::do_comps<comp>(stdex::partial_ordering::greater);
267  }
268  else if constexpr (dimension_of_v<U> == 0)
269  {
270  if constexpr (dimension_of_v<DT> == stdex::dynamic_extent)
271  return detail::do_comps<comp, a == applicability::guaranteed>(
272  stdex::partial_ordering::greater, stdex::partial_ordering::equivalent);
273  else
274  return detail::do_comps<comp>(stdex::partial_ordering::greater);
275  }
276  else if constexpr (dimension_of_v<DT> == stdex::dynamic_extent)
277  {
278  return a == applicability::permitted;
279  }
280  else if constexpr (dimension_of_v<U> == stdex::dynamic_extent)
281  {
282  if constexpr (detail::do_comps<comp>(stdex::partial_ordering::unordered))
283  return true;
284  else if constexpr (detail::do_comps<comp>(stdex::partial_ordering::greater))
285  return compares_with_impl<DT, stdex::ranges::range_value_t<U>, &stdex::is_eq, a>();
286  else
287  return false;
288  }
289  else // U has a fixed dimension and size
290  {
291  return compares_with_impl<collections::repeat_tuple_view<collections::size_of_v<U> + 1, DT>, U, comp, a>();
292  }
293  }
294  else if constexpr (not values::fixed<dimension_of<U>>) // and values::fixed<dimension_of<T>>
295  {
296  using DU = stdex::ranges::range_value_t<U>;
297  if constexpr (euclidean_pattern<T> and euclidean_pattern<DU>)
298  {
299  return detail::do_comps<comp>(stdex::partial_ordering::less);
300  }
301  else if constexpr (not values::fixed<dimension_of<DU>>)
302  {
303  return a == applicability::permitted;
304  }
305  else if constexpr (dimension_of_v<T> == 0)
306  {
307  if constexpr (dimension_of_v<DU> == stdex::dynamic_extent)
308  return detail::do_comps<comp, a == applicability::guaranteed>(
309  stdex::partial_ordering::less, stdex::partial_ordering::equivalent);
310  else
311  return detail::do_comps<comp>(stdex::partial_ordering::less);
312  }
313  else if constexpr (dimension_of_v<DU> == stdex::dynamic_extent)
314  {
315  return a == applicability::permitted;
316  }
317  else if constexpr (dimension_of_v<T> == stdex::dynamic_extent)
318  {
319  if constexpr (detail::do_comps<comp>(stdex::partial_ordering::unordered))
320  return true;
321  else if constexpr (detail::do_comps<comp>(stdex::partial_ordering::less))
322  return compares_with_impl<stdex::ranges::range_value_t<T>, DU, &stdex::is_eq, a>();
323  else
324  return false;
325  }
326  else // T has a fixed dimension and size
327  {
328  return compares_with_impl<T, collections::repeat_tuple_view<collections::size_of_v<T> + 1, DU>, comp, a>();
329  }
330  }
331 
335 
336  else if constexpr (dimension_of_v<T> == 0 and dimension_of_v<U> == 0)
337  {
338  return detail::do_comps<comp>(stdex::partial_ordering::equivalent);
339  }
340  else if constexpr (dimension_of_v<T> == 0 and collections::size_of_v<U> == stdex::dynamic_extent)
341  {
342  return detail::do_comps<comp, a == applicability::guaranteed>(stdex::partial_ordering::less, stdex::partial_ordering::equivalent);
343  }
344  else if constexpr (dimension_of_v<U> == 0 and collections::size_of_v<T> == stdex::dynamic_extent)
345  {
346  return detail::do_comps<comp, a == applicability::guaranteed>(stdex::partial_ordering::greater, stdex::partial_ordering::equivalent);
347  }
348  else if constexpr (collections::size_of_v<T> != stdex::dynamic_extent and collections::size_of_v<U> != stdex::dynamic_extent)
349  {
351  return detail::do_comps<comp>(stdex::partial_ordering::equivalent);
352  else
353  return detail::compares_with_iter<T, U, comp, a>();
354  }
355  else if constexpr (collections::size_of_v<T> != stdex::dynamic_extent) // collections::size_of_v<U> == stdex::dynamic_extent
356  {
357  using DU = stdex::ranges::range_value_t<U>;
358  if constexpr (dimension_of_v<DU> == 0)
359  {
360  return detail::do_comps<comp>(stdex::partial_ordering::greater);
361  }
362  else if constexpr (dimension_of_v<T> != stdex::dynamic_extent and dimension_of_v<DU> != stdex::dynamic_extent)
363  {
364  if constexpr (euclidean_pattern<T> and euclidean_pattern<DU>)
365  {
366  if constexpr (detail::do_comps<comp>(stdex::partial_ordering::unordered))
367  return a == applicability::permitted or dimension_of_v<T> % dimension_of_v<DU> != 0;
368  else if constexpr (detail::do_comps<comp>(stdex::partial_ordering::less, stdex::partial_ordering::greater))
369  return a == applicability::permitted;
370  else if constexpr (detail::do_comps<comp>(stdex::partial_ordering::equivalent))
371  return a == applicability::permitted and dimension_of_v<T> % dimension_of_v<DU> == 0;
372  else
373  return a == applicability::permitted;
374  }
375  else if constexpr (detail::do_comps<comp>(stdex::partial_ordering::unordered))
376  {
377  return a == applicability::permitted or
378  compares_with_impl<T, collections::repeat_tuple_view<collections::size_of_v<T>, DU>, comp, a>();
379  }
380  else if constexpr (detail::do_comps<comp>(stdex::partial_ordering::greater))
381  {
382  return a == applicability::permitted;
383  }
384  else if constexpr (detail::do_comps<comp>(stdex::partial_ordering::less))
385  {
386  return a == applicability::permitted and
387  compares_with_impl<T, collections::repeat_tuple_view<collections::size_of_v<T>, DU>, &stdex::is_eq, a>();
388  }
389  else
390  {
391  return a == applicability::permitted and
392  compares_with_impl<T, collections::repeat_tuple_view<collections::size_of_v<T>, DU>, comp, a>();
393  }
394  }
395  else
396  {
397  return a == applicability::permitted;
398  }
399  }
400  else if constexpr (collections::size_of_v<U> != stdex::dynamic_extent) // collections::size_of_v<T> == stdex::dynamic_extent
401  {
402  using DT = stdex::ranges::range_value_t<T>;
403  if constexpr (dimension_of_v<DT> == 0)
404  {
405  return detail::do_comps<comp>(stdex::partial_ordering::less);
406  }
407  else if constexpr (dimension_of_v<DT> != stdex::dynamic_extent and dimension_of_v<U> != stdex::dynamic_extent)
408  {
409  if constexpr (euclidean_pattern<DT> and euclidean_pattern<U>)
410  {
411  if constexpr (detail::do_comps<comp>(stdex::partial_ordering::unordered))
412  return a == applicability::permitted or dimension_of_v<U> % dimension_of_v<DT> != 0;
413  else if constexpr (detail::do_comps<comp>(stdex::partial_ordering::less, stdex::partial_ordering::greater))
414  return a == applicability::permitted;
415  else if constexpr (detail::do_comps<comp>(stdex::partial_ordering::equivalent))
416  return a == applicability::permitted and dimension_of_v<U> % dimension_of_v<DT> == 0;
417  else
418  return a == applicability::permitted;
419  }
420  else if constexpr (detail::do_comps<comp>(stdex::partial_ordering::unordered))
421  {
422  return a == applicability::permitted or
423  compares_with_impl<collections::repeat_tuple_view<collections::size_of_v<U>, DT>, U, comp, a>();
424  }
425  else if constexpr (detail::do_comps<comp>(stdex::partial_ordering::less))
426  {
427  return a == applicability::permitted;
428  }
429  else if constexpr (detail::do_comps<comp>(stdex::partial_ordering::greater))
430  {
431  return a == applicability::permitted and
432  compares_with_impl<collections::repeat_tuple_view<collections::size_of_v<U>, DT>, U, &stdex::is_eq, a>();
433  }
434  else
435  {
436  return a == applicability::permitted and
437  compares_with_impl<collections::repeat_tuple_view<collections::size_of_v<U>, DT>, U, comp, a>();
438  }
439  }
440  else
441  {
442  return a == applicability::permitted;
443  }
444  }
445  else // if constexpr (collections::size_of_v<T> == stdex::dynamic_extent and collections::size_of_v<U> == stdex::dynamic_extent)
446  {
447  return a == applicability::permitted;
448  }
449  }
450 
451  }
452 
453 
468  template<typename T, typename U, auto comp = &stdex::is_eq, applicability a = applicability::guaranteed>
469 #ifdef __cpp_concepts
470  concept compares_with =
471 #else
472  constexpr bool compares_with =
473 #endif
474  pattern<T> and pattern<U> and
475  std::is_invocable_r_v<bool, decltype(comp), stdex::partial_ordering> and
476  detail::compares_with_impl<T, U, comp, a>();
477 
478 
479 }
480 
481 #endif
Definition: comparison.hpp:104
The size of a patterns::pattern.
Definition: dimension_of.hpp:36
applicability
The applicability of a concept, trait, or restraint.
Definition: constants.hpp:35
The concept, trait, or restraint is permitted, but whether it applies is not necessarily known at com...
constexpr bool compares_with
Compares two patterns::pattern objects.
Definition: compares_with.hpp:472
Definition: comparison.hpp:176
The size of a sized object (including a collection).
Definition: size_of.hpp:33
constexpr bool value
T is a fixed or dynamic value that is reducible to a number.
Definition: value.hpp:45
Definition for patterns::pattern.
The namespace for features relating to patterns::pattern object.
Definition: collection_compares_with.hpp:24
Inclusion file for collections.
constexpr bool compares_with_impl()
Definition: compares_with.hpp:227
Definition: compares_with.hpp:47
constexpr bool fixed
T has a value that is determinable at compile time.
Definition: fixed.hpp:65
A matrix with typed rows and columns.
Definition: forward-class-declarations.hpp:292