OpenKalman
redux.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) 2023 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_EIGEN_TRAITS_FUNCTORS_REDUX_HPP
17 #define OPENKALMAN_EIGEN_TRAITS_FUNCTORS_REDUX_HPP
18 
19 #include <type_traits>
20 
21 namespace OpenKalman::Eigen3
22 {
23 
24  // Default, if MemberOp is not handled below.
25  template<typename MemberOp, std::size_t direction>
26  struct ReduxTraits
27  {
28  template<typename C, typename Factor, typename Dim>
29  static constexpr auto get_constant(const C&, const Factor& factor, const Dim& dim)
30  {
31  return std::monostate{};
32  }
33 
34  template<bool at_least_square, typename C, typename Factor, typename Dim>
35  static constexpr auto get_constant_diagonal(const C&, const Factor& factor, const Dim& dim)
36  {
37  return std::monostate{};
38  }
39  };
40 
41 
42 #ifndef __cpp_concepts
43  namespace detail
44  {
45  template<typename C, typename = void>
46  struct const_is_zero : std::false_type {};
47 
48  template<typename C>
49  struct const_is_zero<C, std::enable_if_t<values::to_number(C{}) == 0>> : std::true_type {};
50  } // namespace detail
51 #endif
52 
53 
55  // Norms //
57 
58 #if EIGEN_VERSION_AT_LEAST(3,4,0)
59  template<int p, typename ResultType, typename Scalar, std::size_t direction>
60  struct ReduxTraits<Eigen::internal::member_lpnorm<p, ResultType, Scalar>, direction>
61 #else
62  template<int p, typename ResultType, std::size_t direction>
63  struct ReduxTraits<Eigen::internal::member_lpnorm<p, ResultType>, direction>
64 #endif
65  {
66  private:
67 
68  struct Op
69  {
70  template<typename X>
71  constexpr Scalar operator()(X x, std::size_t dim) const
72  {
73  auto abs_x = values::abs(x);
74  if constexpr (p == 1) return static_cast<Scalar>(dim) * abs_x;
75  else if constexpr (p == 2) return values::sqrt(static_cast<Scalar>(dim)) * abs_x;
76  else return values::pow(static_cast<Scalar>(dim), static_cast<Scalar>(1)/p) * abs_x;
77  }
78  };
79 
80 
81  struct OpInf
82  {
83  template<typename X>
84  constexpr Scalar operator()(X x) const { return values::abs(x); }
85  };
86 
87 
88  template<bool diag, bool at_least_square, typename C, typename Factor, typename Dim>
89  static constexpr auto get_constant_impl(const C& c, const Factor& factor, const Dim& dim)
90  {
91  if constexpr (p == 0)
92  {
93  // Note: Eigen does not specifically define the l0 norm, so if p==0 the result is infinity.
94  if constexpr (std::numeric_limits<ResultType>::has_infinity) return std::numeric_limits<ResultType>::infinity();
95  else throw std::domain_error {"Domain error in lpnorm<0>: result is infinity"};
96  }
97 #ifdef __cpp_concepts
98  else if constexpr (requires { requires values::to_number(C{}) == 0; })
99 #else
100  else if constexpr (detail::const_is_zero<C>::value)
101 #endif
102  {
104  }
105  else if constexpr (not at_least_square)
106  {
107  return std::monostate{};
108  }
109  else if constexpr (p == Eigen::Infinity)
110  {
111  return values::operation{OpInf{}, c};
112  }
113  else if constexpr (diag)
114  {
115  return values::operation{Op{}, c, factor};
116  }
117  else
118  {
119  return values::operation{Op{}, c,
120  values::operation{std::multiplies<std::size_t>{}, factor, dim}};
121  }
122  }
123 
124  public:
125 
126  template<typename C, typename Factor, typename Dim>
127  static constexpr auto get_constant(const C& c, const Factor& factor, const Dim& dim)
128  {
129  return get_constant_impl<false, true>(c, factor, dim);
130  }
131 
132 
133  template<bool at_least_square, typename C, typename Factor, typename Dim>
134  static constexpr auto get_constant_diagonal(const C& c, const Factor& factor, const Dim& dim)
135  {
136  return get_constant_impl<true, at_least_square>(c, factor, dim);
137  }
138  };
139 
140 
141 #if EIGEN_VERSION_AT_LEAST(3,4,0)
142  template<typename ResultType, typename Scalar, std::size_t direction>
143  struct ReduxTraits<Eigen::internal::member_stableNorm<ResultType, Scalar>, direction>
144  : ReduxTraits<Eigen::internal::member_lpnorm<2, ResultType, Scalar>, direction> {};
145 #else
146  template<typename ResultType, std::size_t direction>
147  struct ReduxTraits<Eigen::internal::member_stableNorm<ResultType>, direction>
148  : ReduxTraits<Eigen::internal::member_lpnorm<2, ResultType>, direction> {};
149 #endif
150 
151 
152 #if EIGEN_VERSION_AT_LEAST(3,4,0)
153  template<typename ResultType, typename Scalar, std::size_t direction>
154  struct ReduxTraits<Eigen::internal::member_hypotNorm<ResultType, Scalar>, direction>
155  : ReduxTraits<Eigen::internal::member_lpnorm<2, ResultType, Scalar>, direction> {};
156 #else
157  template<typename ResultType, std::size_t direction>
158  struct ReduxTraits<Eigen::internal::member_hypotNorm<ResultType>, direction>
159  : ReduxTraits<Eigen::internal::member_lpnorm<2, ResultType>, direction> {};
160 #endif
161 
162 
163 # if not EIGEN_VERSION_AT_LEAST(3,4,0)
164  template<typename...Args, std::size_t direction>
165  struct ReduxTraits<Eigen::internal::member_squaredNorm<Args...>, direction>
166  {
167  struct Op
168  {
169  template<typename Scalar>
170  constexpr Scalar operator()(Scalar x, std::size_t dim) const
171  {
172  if constexpr (values::complex<Scalar>)
173  {
174  auto r = values::real(x);
175  auto i = values::imag(x);
176  if constexpr (constant_diagonal_matrix<XprType>) return r * r + i * i;
177  else return dim * (r * r + i * i);
178  }
179  else return dim * x * x;
180  }
181  };
182 
183 
184  template<typename C, typename Factor, typename Dim>
185  static constexpr auto get_constant(const C& c, const Factor& factor, const Dim& dim)
186  {
187 #ifdef __cpp_concepts
188  if constexpr (requires { requires values::to_number(C{}) == 0; })
189 #else
190  if constexpr (detail::const_is_zero<C>::value)
191 #endif
193  else
194  return values::operation{Op{}, c,
195  values::operation{std::multiplies<std::size_t>{}, factor, dim}};
196  }
197 
198 
199  template<bool at_least_square, typename C, typename Factor>
200  static constexpr auto get_constant_diagonal(const C& c, const Factor& factor, const Dim&)
201  {
202 #ifdef __cpp_concepts
203  if constexpr (requires { requires values::to_number(C{}) == 0; })
204 #else
205  if constexpr (detail::const_is_zero<C>::value)
206 #endif
208  else if constexpr (at_least_square)
209  return values::operation{Op{}, c, factor};
210  else
211  return std::monostate{};
212  }
213  };
214 
215 
216  template<typename...Args, std::size_t direction>
217  struct ReduxTraits<Eigen::internal::member_norm<Args...>, direction>
218  {
219  struct Op
220  {
221  template<typename Scalar>
222  constexpr Scalar operator()(Scalar x, std::size_t dim) const
223  {
224  if constexpr (values::complex<Scalar>)
225  {
226  auto r = values::real(x);
227  auto i = values::imag(x);
228  if constexpr (constant_diagonal_matrix<XprType>) return r * r + i * i;
229  return values::sqrt(dim * (r * r + i * i));
230  }
231  else
232  {
233  auto arg = values::abs(x);
234  return values::sqrt(static_cast<Scalar>(dim)) * arg;
235  }
236  }
237  };
238 
239  template<typename XprType, typename Factor, typename Dim>
240  static constexpr auto get_constant(const C& c, const Factor& factor, const Dim& dim)
241  {
242 #ifdef __cpp_concepts
243  if constexpr (requires { requires values::to_number(C{}) == 0; })
244 #else
245  if constexpr (detail::const_is_zero<C>::value)
246 #endif
248  else
249  return values::operation{Op{}, c,
250  values::operation{std::multiplies<std::size_t>{}, factor, dim}};
251  }
252 
253 
254  template<bool at_least_square, typename C, typename Factor, typename Dim>
255  static constexpr auto get_constant_diagonal(const C& c, const Factor& factor, const Dim& dim)
256  {
257  if constexpr (at_least_square)
258  return values::operation{Op{}, c, factor};
259  else
260  return std::monostate{};
261  }
262  };
263 
264 
265  template<typename...Args, std::size_t direction>
266  struct ReduxTraits<Eigen::internal::member_mean<Args...>, direction>
267  {
268  template<typename C, typename Factor, typename Dim>
269  static constexpr auto get_constant(const C& c, const Factor& factor, const Dim&)
270  {
271  return c;
272  }
273 
274 
275  template<bool at_least_square, typename C, typename Factor, typename Dim>
276  static constexpr auto get_constant_diagonal(const C& c, const Factor& factor, const Dim& dim)
277  {
278 #ifdef __cpp_concepts
279  if constexpr (requires { requires values::to_number(C{}) == 0; })
280 #else
281  if constexpr (detail::const_is_zero<C>::value)
282 #endif
284  else if constexpr (at_least_square)
285  return (c * factor) / dim;
286  else
287  return std::monostate{};
288  }
289  };
290 # endif
291 
292 
294  // sum //
296 
297  template<typename T, typename Scalar, std::size_t direction>
298  struct ReduxTraits<Eigen::internal::member_redux<std::plus<T>, Scalar>, direction>
299  {
300  template<typename C, typename Factor, typename Dim>
301  static constexpr auto get_constant(const C& c, const Factor& factor, const Dim& dim)
302  {
303  #ifdef __cpp_concepts
304  if constexpr (requires { requires values::to_number(C{}) == 0; })
305  #else
306  if constexpr (detail::const_is_zero<C>::value)
307  #endif
308  return values::Fixed<Scalar, 0>{};
309  else
310  return values::operation{std::multiplies<Scalar>{}, c,
311  values::operation{std::multiplies<Scalar>{}, factor, dim}};
312  }
313 
314 
315  template<bool at_least_square, typename C, typename Factor, typename Dim>
316  static constexpr auto get_constant_diagonal(const C& c, const Factor& factor, const Dim& dim)
317  {
318 #ifdef __cpp_concepts
319  if constexpr (requires { requires values::to_number(C{}) == 0; })
320 #else
321  if constexpr (detail::const_is_zero<C>::value)
322 #endif
323  return values::Fixed<Scalar, 0>{};
324  else if constexpr (at_least_square)
325  return values::operation{std::multiplies<Scalar>{}, c, factor};
326  else
327  return std::monostate{};
328  }
329  };
330 
331 
332 #if EIGEN_VERSION_AT_LEAST(3,4,0)
333  template<typename ResultType, typename Scalar, std::size_t direction>
334  struct ReduxTraits<Eigen::internal::member_sum<ResultType, Scalar>, direction>
335 #else
336  template<typename ResultType, std::size_t direction>
337  struct ReduxTraits<Eigen::internal::member_sum<ResultType>, direction>
338 #endif
339  : ReduxTraits<Eigen::internal::member_redux<std::plus<Scalar>, Scalar>, direction> {};
340 
341 
342  template<typename LhsScalar, typename RhsScalar, typename Scalar, std::size_t direction>
343  struct ReduxTraits<Eigen::internal::member_redux<Eigen::internal::scalar_sum_op<LhsScalar, RhsScalar>, Scalar>, direction>
344  : ReduxTraits<Eigen::internal::member_redux<std::plus<Scalar>, Scalar>, direction> {};
345 
346 
348  // min //
350 
351 #if EIGEN_VERSION_AT_LEAST(3,4,0)
352  template<typename ResultType, typename Scalar, std::size_t direction>
353  struct ReduxTraits<Eigen::internal::member_minCoeff<ResultType, Scalar>, direction>
354 #else
355  template<typename ResultType, std::size_t direction>
356  struct ReduxTraits<Eigen::internal::member_minCoeff<ResultType>, direction>
357 #endif
358  {
359  struct Op
360  {
361  template<typename X, typename Dim>
362  constexpr auto operator()(X x, Dim dim) const
363  {
364  if (dim > 1) return std::min<ResultType>(x, 0);
365  else return x;
366  }
367  };
368 
369 
370  template<typename C, typename Factor, typename Dim>
371  static constexpr auto get_constant(const C& c, const Factor& factor, const Dim& dim)
372  {
373  return c;
374  }
375 
376 
377  template<bool at_least_square, typename C, typename Factor, typename Dim>
378  static constexpr auto get_constant_diagonal(const C& c, const Factor& factor, const Dim& dim)
379  {
380  if constexpr (at_least_square)
381  {
382  return values::operation {Op{}, c, dim};
383  }
384  else if constexpr (values::fixed<C>)
385  {
386  if constexpr (C::value < 0) return std::monostate{};
387  else return values::Fixed<ResultType, 0>{};
388  }
389  else return std::monostate{};
390  }
391  };
392 
393 
394  template<typename LhsScalar, typename RhsScalar, typename Scalar, std::size_t direction>
395  struct ReduxTraits<Eigen::internal::member_redux<Eigen::internal::scalar_min_op<LhsScalar, RhsScalar>, Scalar>, direction>
396 #if EIGEN_VERSION_AT_LEAST(3,4,0)
397  : ReduxTraits<Eigen::internal::member_minCoeff<Scalar, Scalar>, direction> {};
398 #else
400 #endif
401 
402 
404  // max //
406 
407 #if EIGEN_VERSION_AT_LEAST(3,4,0)
408  template<typename ResultType, typename Scalar, std::size_t direction>
409  struct ReduxTraits<Eigen::internal::member_maxCoeff<ResultType, Scalar>, direction>
410 #else
411  template<typename ResultType, std::size_t direction>
412  struct ReduxTraits<Eigen::internal::member_maxCoeff<ResultType>, direction>
413 #endif
414  {
415  struct Op
416  {
417  template<typename X, typename Dim>
418  constexpr auto operator()(X x, Dim dim) const
419  {
420  if (dim > 1) return std::max<ResultType>(x, 0);
421  else return x;
422  }
423  };
424 
425 
426  template<typename C, typename Factor, typename Dim>
427  static constexpr auto get_constant(const C& c, const Factor& factor, const Dim& dim)
428  {
429  return c;
430  }
431 
432 
433  template<bool at_least_square, typename C, typename Factor, typename Dim>
434  static constexpr auto get_constant_diagonal(const C& c, const Factor& factor, const Dim& dim)
435  {
436  if constexpr (at_least_square)
437  {
438  return values::operation {Op{}, c, dim};
439  }
440  else if constexpr (values::fixed<C>)
441  {
442  if constexpr (C::value > 0) return std::monostate{};
443  else return values::Fixed<ResultType, 0>{};
444  }
445  else return std::monostate{};
446  }
447  };
448 
449 
450  template<typename LhsScalar, typename RhsScalar, typename Scalar, std::size_t direction>
451  struct ReduxTraits<Eigen::internal::member_redux<Eigen::internal::scalar_max_op<LhsScalar, RhsScalar>, Scalar>, direction>
452 #if EIGEN_VERSION_AT_LEAST(3,4,0)
453  : ReduxTraits<Eigen::internal::member_maxCoeff<Scalar, Scalar>, direction> {};
454 #else
456 #endif
457 
458 
460  // and //
462 
463 #if EIGEN_VERSION_AT_LEAST(3,4,0)
464  template<typename ResultType, typename Scalar, std::size_t direction>
465  struct ReduxTraits<Eigen::internal::member_all<ResultType, Scalar>, direction>
466 #else
467  template<typename ResultType, std::size_t direction>
468  struct ReduxTraits<Eigen::internal::member_all<ResultType>, direction>
469 #endif
470  {
471  struct Op
472  {
473  template<typename X>
474  constexpr bool operator()(X x) const { return static_cast<bool>(x); }
475  };
476 
477 
478  template<typename C, typename Factor, typename Dim>
479  static constexpr auto get_constant(const C& c, const Factor&, const Dim&)
480  {
481  return values::operation {Op{}, c};
482  }
483 
484 
485  template<bool at_least_square, typename C, typename Factor, typename Dim>
486  static constexpr auto get_constant_diagonal(const C&, const Factor&, const Dim&)
487  {
488  return std::false_type{};
489  }
490  };
491 
492 
493  template<typename T, typename Scalar, std::size_t direction>
494  struct ReduxTraits<Eigen::internal::member_redux<std::logical_and<T>, Scalar>, direction>
495 #if EIGEN_VERSION_AT_LEAST(3,4,0)
496  : ReduxTraits<Eigen::internal::member_all<bool, Scalar>, direction> {};
497 #else
499 #endif
500 
501 
502  template<typename Scalar, std::size_t direction>
503  struct ReduxTraits<Eigen::internal::member_redux<Eigen::internal::scalar_boolean_and_op, Scalar>, direction>
504 #if EIGEN_VERSION_AT_LEAST(3,4,0)
505  : ReduxTraits<Eigen::internal::member_all<bool, Scalar>, direction> {};
506 #else
508 #endif
509 
510 
512  // or //
514 
515 #if EIGEN_VERSION_AT_LEAST(3,4,0)
516  template<typename ResultType, typename Scalar, std::size_t direction>
517  struct ReduxTraits<Eigen::internal::member_any<ResultType, Scalar>, direction>
518 #else
519  template<typename ResultType, std::size_t direction>
520  struct ReduxTraits<Eigen::internal::member_any<ResultType>, direction>
521 #endif
522  {
523  struct Op
524  {
525  template<typename X>
526  constexpr bool operator()(X x) const { return static_cast<bool>(x); }
527  };
528 
529 
530  template<typename C, typename Factor, typename Dim>
531  static constexpr auto get_constant(const C& c, const Factor& factor, const Dim& dim)
532  {
533  return values::operation {Op{}, c};
534  }
535 
536 
537  template<bool at_least_square, typename C, typename Factor, typename Dim>
538  static constexpr auto get_constant_diagonal(const C& c, const Factor& factor, const Dim& dim)
539  {
540  if constexpr (at_least_square)
541  return values::operation {Op{}, c};
542  else
543  return std::monostate{};
544  }
545  };
546 
547 
548  template<typename T, typename Scalar, std::size_t direction>
549  struct ReduxTraits<Eigen::internal::member_redux<std::logical_or<T>, Scalar>, direction>
550 #if EIGEN_VERSION_AT_LEAST(3,4,0)
551  : ReduxTraits<Eigen::internal::member_any<bool, Scalar>, direction> {};
552 #else
554 #endif
555 
556 
557  template<typename Scalar, std::size_t direction>
558  struct ReduxTraits<Eigen::internal::member_redux<Eigen::internal::scalar_boolean_or_op, Scalar>, direction>
559 #if EIGEN_VERSION_AT_LEAST(3,4,0)
560  : ReduxTraits<Eigen::internal::member_any<bool, Scalar>, direction> {};
561 #else
563 #endif
564 
565 
567  // count //
569 
570 #if EIGEN_VERSION_AT_LEAST(3,4,0)
571  template<typename ResultType, typename Scalar, std::size_t direction>
572  struct ReduxTraits<Eigen::internal::member_count<ResultType, Scalar>, direction>
573 #else
574  template<typename ResultType, std::size_t direction>
575  struct ReduxTraits<Eigen::internal::member_count<ResultType>, direction>
576 #endif
577  {
578  struct Op
579  {
580  template<typename X>
581  constexpr Eigen::Index operator()(X x, std::size_t dim) const
582  {
583  return static_cast<bool>(x) ? static_cast<Eigen::Index>(dim) : Eigen::Index{0};
584  }
585  };
586 
587 
588  template<typename C, typename Factor, typename Dim>
589  static constexpr auto get_constant(const C& c, const Factor& factor, const Dim& dim)
590  {
591  return values::operation {Op{}, c,
592  values::operation{std::multiplies<std::size_t>{}, dim, factor}};
593  }
594 
595 
596  template<bool at_least_square, typename C, typename Factor, typename Dim>
597  static constexpr auto get_constant_diagonal(const C& c, const Factor& factor, const Dim&)
598  {
599  if constexpr (at_least_square)
600  return values::operation {Op{}, c, factor};
601  else
602  return std::monostate{};
603  }
604  };
605 
606 
608  // product //
610 
611 #if EIGEN_VERSION_AT_LEAST(3,4,0)
612  template<typename ResultType, typename Scalar, std::size_t direction>
613  struct ReduxTraits<Eigen::internal::member_prod<ResultType, Scalar>, direction>
614 #else
615  template<typename ResultType, std::size_t direction>
616  struct ReduxTraits<Eigen::internal::member_prod<ResultType>, direction>
617 #endif
618  {
619  struct Op
620  {
621  template<typename X>
622  constexpr Scalar operator()(X x, std::size_t dim) const { return values::pow(x, dim); }
623  };
624 
625 
626  template<typename C, typename Factor, typename Dim>
627  static constexpr auto get_constant(const C& c, const Factor& factor, const Dim& dim)
628  {
629 #ifdef __cpp_concepts
630  if constexpr (requires { requires values::to_number(C{}) == 0; })
631 #else
632  if constexpr (detail::const_is_zero<C>::value)
633 #endif
635  else
636  return values::operation{Op{}, c,
637  values::operation{std::multiplies<std::size_t>{}, factor, dim}};
638  }
639 
640 
641  template<bool at_least_square, typename C, typename Factor, typename Dim>
642  static constexpr auto get_constant_diagonal(const C& c, const Factor& factor, const Dim& dim)
643  {
645  }
646  };
647 
648 
649  template<typename LhsScalar, typename RhsScalar, typename Scalar, std::size_t direction>
650  struct ReduxTraits<Eigen::internal::member_redux<Eigen::internal::scalar_product_op<LhsScalar, RhsScalar>, Scalar>, direction>
651 #if EIGEN_VERSION_AT_LEAST(3,4,0)
652  : ReduxTraits<Eigen::internal::member_prod<Scalar, Scalar>, direction> {};
653 #else
655 #endif
656 
657 
658  template<typename T, typename Scalar, std::size_t direction>
659  struct ReduxTraits<Eigen::internal::member_redux<std::multiplies<T>, Scalar>, direction>
660 #if EIGEN_VERSION_AT_LEAST(3,4,0)
661  : ReduxTraits<Eigen::internal::member_prod<Scalar, Scalar>, direction> {};
662 #else
664 #endif
665 
666 } // namespace OpenKalman::Eigen3
667 
668 #endif //OPENKALMAN_EIGEN_TRAITS_FUNCTORS_REDUX_HPP
An operation involving some number of values.
Definition: operation.hpp:69
constexpr auto imag(Arg arg)
A constexpr function to obtain the imaginary part of a (complex) number.
Definition: imag.hpp:40
Definition: tuple_reverse.hpp:103
constexpr bool value
T is numerical value or is reducible to a numerical value.
Definition: value.hpp:31
constexpr auto to_number(Arg arg)
Convert any values::value to a values::number.
Definition: to_number.hpp:34
constexpr auto sqrt(const Arg &arg)
A constexpr alternative to std::sqrt.
Definition: sqrt.hpp:46
Definition: eigen-forward-declarations.hpp:22
Definition: redux.hpp:26
constexpr auto real(Arg arg)
A constexpr function to obtain the real part of a (complex) number.
Definition: real.hpp:40
Definition: Fixed.hpp:36
constexpr auto abs(const Arg &arg)
A constexpr alternative to std::abs.
Definition: abs.hpp:38