OpenKalman
value-arithmetic.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-2024 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_VALUE_ARITHMETIC_HPP
17 #define OPENKALMAN_VALUE_ARITHMETIC_HPP
18 
19 #include <functional>
22 #include "to_number.hpp"
24 
25 namespace OpenKalman::values
26 {
27  namespace detail
28  {
29  template<typename Arg1, typename Arg2>
30  using binary_common_type = std::common_type<number_type_of_t<Arg1>, number_type_of_t<Arg2>>;
31 
32  template<typename Arg1, typename Arg2>
33  using binary_common_type_t = std::common_type_t<number_type_of_t<Arg1>, number_type_of_t<Arg2>>;
34 
35 
36 #ifndef __cpp_concepts
37  template<typename Arg1, typename Arg2, typename = void>
38  struct value_common_with_impl : std::false_type {};
39 
40  template<typename Arg1, typename Arg2>
41  struct value_common_with_impl<Arg1, Arg2, std::void_t<typename std::common_type<
42  std::decay_t<decltype(values::to_number(std::declval<Arg1>()))>,
43  std::decay_t<decltype(values::to_number(std::declval<Arg2>()))>>::type>>
44  : std::true_type {};
45 #endif
46 
47 
48  template<typename Arg1, typename Arg2>
49 #ifdef __cpp_concepts
50  concept value_common_with = value<Arg1> and value<Arg2> and std::common_with<number_type_of_t<Arg1>, number_type_of_t<Arg2>>;
51 #else
52  constexpr bool value_common_with = value_common_with_impl<Arg1, Arg2>::value;
53 #endif
54  }
55 
56 
57 #ifdef __cpp_concepts
58  template<value Arg>
59 #else
60  template<typename Arg, std::enable_if_t<value<Arg>, int> = 0>
61 #endif
62  constexpr Arg&& operator+(Arg&& arg)
63  {
64  return std::forward<Arg>(arg);
65  }
66 
67 
68 #ifdef __cpp_concepts
69  template<value Arg> requires requires(Arg arg) { -to_number(std::move(arg)); }
70 #else
71  template<typename Arg, std::enable_if_t<value<Arg>, int> = 0>
72 #endif
73  constexpr auto operator-(Arg arg)
74  {
75  if constexpr (fixed<Arg>)
76  return operation {std::negate{}, std::move(arg)};
77  else
78  return -to_number(std::move(arg));
79  }
80 
81 
82 #ifdef __cpp_concepts
83  template<value Arg1, detail::value_common_with<Arg1> Arg2> requires
84  std::invocable<std::plus<detail::binary_common_type_t<Arg1, Arg2>>, Arg1&&, Arg2&&>
85 #else
86  template<typename Arg1, typename Arg2, std::enable_if_t<detail::value_common_with<Arg1, Arg2> and
87  std::is_invocable<std::plus<detail::binary_common_type_t<Arg1, Arg2>>, Arg1&&, Arg2&&>::value, int> = 0>
88 #endif
89  constexpr auto operator+(Arg1 arg1, Arg2 arg2)
90  {
91  using Common = detail::binary_common_type_t<Arg1, Arg2>;
92  if constexpr (fixed<Arg1> and fixed<Arg2>) return operation {std::plus<Common>{}, std::move(arg1), std::move(arg2)};
93  else return static_cast<Common>(to_number(std::move(arg1))) + static_cast<Common>(to_number(std::move(arg2)));
94  }
95 
96 
97 #ifdef __cpp_concepts
98  template<value Arg1, detail::value_common_with<Arg1> Arg2> requires
99  std::invocable<std::minus<detail::binary_common_type_t<Arg1, Arg2>>, Arg1&&, Arg2&&>
100 #else
101  template<typename Arg1, typename Arg2, std::enable_if_t<detail::value_common_with<Arg1, Arg2> and
102  std::is_invocable<std::minus<detail::binary_common_type_t<Arg1, Arg2>>, Arg1&&, Arg2&&>::value, int> = 0>
103 #endif
104  constexpr auto operator-(Arg1 arg1, Arg2 arg2)
105  {
106  using Common = detail::binary_common_type_t<Arg1, Arg2>;
107  if constexpr (fixed<Arg1> and fixed<Arg2>) return operation {std::minus<Common>{}, std::move(arg1), std::move(arg2)};
108  else return static_cast<Common>(to_number(std::move(arg1))) - static_cast<Common>(to_number(std::move(arg2)));
109  }
110 
111 
112 #ifdef __cpp_concepts
113  template<value Arg1, detail::value_common_with<Arg1> Arg2> requires
114  std::invocable<std::multiplies<detail::binary_common_type_t<Arg1, Arg2>>, Arg1&&, Arg2&&>
115 #else
116  template<typename Arg1, typename Arg2, std::enable_if_t<detail::value_common_with<Arg1, Arg2> and
117  std::is_invocable<std::multiplies<detail::binary_common_type_t<Arg1, Arg2>>, Arg1&&, Arg2&&>::value, int> = 0>
118 #endif
119  constexpr auto operator*(Arg1 arg1, Arg2 arg2)
120  {
121  using Common = detail::binary_common_type_t<Arg1, Arg2>;
122  if constexpr (fixed<Arg1> and fixed<Arg2>) return operation {std::multiplies<Common>{}, std::move(arg1), std::move(arg2)};
123  else return static_cast<Common>(to_number(std::move(arg1))) * static_cast<Common>(to_number(std::move(arg2)));
124  }
125 
126 
127 #ifdef __cpp_concepts
128  template<value Arg1, detail::value_common_with<Arg1> Arg2> requires
129  std::invocable<std::divides<detail::binary_common_type_t<Arg1, Arg2>>, Arg1&&, Arg2&&>
130 #else
131  template<typename Arg1, typename Arg2, std::enable_if_t<detail::value_common_with<Arg1, Arg2> and
132  std::is_invocable<std::divides<detail::binary_common_type_t<Arg1, Arg2>>, Arg1&&, Arg2&&>::value, int> = 0>
133 #endif
134  constexpr auto operator/(Arg1 arg1, Arg2 arg2)
135  {
136  using Common = detail::binary_common_type_t<Arg1, Arg2>;
137  if constexpr (fixed<Arg1> and fixed<Arg2>) return operation {std::divides<Common>{}, std::move(arg1), std::move(arg2)};
138  else return static_cast<Common>(to_number(std::move(arg1))) / static_cast<Common>(to_number(std::move(arg2)));
139  }
140 
141 
142 #if defined(__cpp_concepts) and defined(__cpp_impl_three_way_comparison)
143  template<value A, detail::value_common_with<A> B> requires
144  std::invocable<std::compare_three_way, number_type_of_t<A>, number_type_of_t<B>>
145  constexpr auto operator<=>(const A& a, const B& b)
146  {
147  using Common = detail::binary_common_type_t<A, B>;
148  return static_cast<Common>(to_number(a)) <=> static_cast<Common>(to_number(b));
149  }
150 
151  template<value A, detail::value_common_with<A> B> requires
152  std::invocable<std::compare_three_way, number_type_of_t<A>, number_type_of_t<B>>
153  constexpr bool operator==(const A& a, const B& b)
154  {
155  return std::is_eq(a <=> b);
156  }
157 #else
158  template<typename A, typename B, std::enable_if_t<detail::value_common_with<A, B> and
159  std::is_invocable<std::equal_to<detail::binary_common_type_t<A, B>>, const A&, const B&>::value, int> = 0>
160  constexpr bool operator==(const A& a, const B& b)
161  {
162  using Common = detail::binary_common_type_t<A, B>;
163  return static_cast<Common>(to_number(a)) == static_cast<Common>(to_number(b));
164  }
165 
166  template<typename A, typename B, std::enable_if_t<detail::value_common_with<A, B> and
167  std::is_invocable<std::not_equal_to<detail::binary_common_type_t<A, B>>, const A&, const B&>::value, int> = 0>
168  constexpr bool operator!=(const A& a, const B& b)
169  {
170  using Common = detail::binary_common_type_t<A, B>;
171  return static_cast<Common>(to_number(a)) != static_cast<Common>(to_number(b));
172  }
173 
174 template<typename A, typename B, std::enable_if_t<detail::value_common_with<A, B> and
175  std::is_invocable<std::less<detail::binary_common_type_t<A, B>>, const A&, const B&>::value, int> = 0>
176  constexpr auto operator<(const A& a, const B& b)
177  {
178  using Common = detail::binary_common_type_t<A, B>;
179  return static_cast<Common>(to_number(a)) < static_cast<Common>(to_number(b));
180  }
181 
182 template<typename A, typename B, std::enable_if_t<detail::value_common_with<A, B> and
183  std::is_invocable<std::greater<detail::binary_common_type_t<A, B>>, const A&, const B&>::value, int> = 0>
184  constexpr auto operator>(const A& a, const B& b)
185  {
186  using Common = detail::binary_common_type_t<A, B>;
187  return static_cast<Common>(to_number(a)) > static_cast<Common>(to_number(b));
188  }
189 
190 template<typename A, typename B, std::enable_if_t<detail::value_common_with<A, B> and
191  std::is_invocable<std::less_equal<detail::binary_common_type_t<A, B>>, const A&, const B&>::value, int> = 0>
192  constexpr auto operator<=(const A& a, const B& b)
193  {
194  using Common = detail::binary_common_type_t<A, B>;
195  return static_cast<Common>(to_number(a)) <= static_cast<Common>(to_number(b));
196  }
197 
198 template<typename A, typename B, std::enable_if_t<detail::value_common_with<A, B> and
199  std::is_invocable<std::greater_equal<detail::binary_common_type_t<A, B>>, const A&, const B&>::value, int> = 0>
200  constexpr auto operator>=(const A& a, const B& b)
201  {
202  using Common = detail::binary_common_type_t<A, B>;
203  return static_cast<Common>(to_number(a)) >= static_cast<Common>(to_number(b));
204  }
205 #endif
206 
207 
208 } // namespace OpenKalman::values
209 
210 #endif //OPENKALMAN_VALUE_ARITHMETIC_HPP
Definition for values::to_number.
An operation involving some number of values.
Definition: operation.hpp:69
Definition: tuple_reverse.hpp:103
constexpr auto to_number(Arg arg)
Convert any values::value to a values::number.
Definition: to_number.hpp:34
Definition: value-arithmetic.hpp:38
Definition for values::abs.
Definition: constant_coefficient.hpp:25
std::decay_t< decltype(values::to_number(std::declval< T >()))> number_type_of_t
Obtain the values::number type associated with avalues::value.
Definition: number_type_of_t.hpp:34
Definition for ::fixed.
A matrix with typed rows and columns.
Definition: forward-class-declarations.hpp:448
Definition for ::value.