EmrysFilter 0.1.0
State estimation utilities in C++23 using Eigen
Loading...
Searching...
No Matches
Math.h
Go to the documentation of this file.
1#pragma once
2
57
58#include <cmath>
59#include <concepts>
60#include <numbers>
61#include <type_traits>
62
64
65#include <unsupported/Eigen/AutoDiff>
66#include <unsupported/Eigen/SpecialFunctions>
67
68namespace Emrys
69{
70
79template <typename T>
80concept RealScalar =
81 !Eigen::NumTraits<T>::IsInteger && !Eigen::NumTraits<T>::IsComplex && requires(T const & a, T const & b) {
82 a + b;
83 a - b;
84 a * b;
85 a / b;
86 a < b;
87 };
88
89namespace internal
90{
91
99template <typename T>
100inline constexpr bool isAutoDiffScalar = false;
101
103template <typename Derivatives>
104inline constexpr bool isAutoDiffScalar<Eigen::AutoDiffScalar<Derivatives>>{true};
105
107
115template <typename... Values>
116 requires(std::is_arithmetic_v<Values> && ...)
117struct DeducedScalarOf
118{
120 using type = std::conditional_t<
121 (std::integral<Values> && ...),
122 double,
123 std::common_type_t<std::conditional_t<std::integral<Values>, float, Values>...>>;
124};
125
127template <typename... Values>
128using DeducedScalar = typename DeducedScalarOf<Values...>::type;
129
130} // namespace internal
131
143template <typename Scalar>
144[[nodiscard]] Scalar
146{
147 using Literal = typename Eigen::NumTraits<Scalar>::Literal;
148 if constexpr (std::floating_point<Scalar>)
149 {
150 return std::numbers::pi_v<Scalar>;
151 }
152 else if constexpr (std::floating_point<Literal>)
153 {
154 return Scalar(std::numbers::pi_v<Literal>);
155 }
156 else
157 {
158 return Scalar(4) * Eigen::numext::atan(Scalar(1));
159 }
160}
161
175template <typename Scalar>
176[[nodiscard]] Scalar
178{
179 using Literal = typename Eigen::NumTraits<Scalar>::Literal;
180 if constexpr (std::floating_point<Scalar>)
181 {
182 return Scalar(1.83787706640934548356065947281123527972L);
183 }
184 else if constexpr (std::floating_point<Literal>)
185 {
186 return Scalar(log2Pi<Literal>());
187 }
188 else
189 {
190 Scalar const twoPi = Scalar(2) * pi<Scalar>();
191 return Eigen::numext::log(twoPi);
192 }
193}
194
214template <typename Scalar>
215[[nodiscard]] Scalar
216logGamma(std::type_identity_t<Scalar> const & x)
217{
218 if constexpr (std::floating_point<Scalar>)
219 {
220 return std::lgamma(x);
221 }
222 else if constexpr (internal::isAutoDiffScalar<Scalar>)
223 {
224 using Real = typename Scalar::Real;
225 return Scalar{logGamma<Real>(x.value()), Eigen::numext::digamma(x.value()) * x.derivatives()};
226 }
227 else
228 {
229 return lgamma(x);
230 }
231}
232
245template <typename Scalar>
246[[nodiscard]] Scalar
247logOnePlus(std::type_identity_t<Scalar> const & x)
248{
249 if constexpr (std::floating_point<Scalar>)
250 {
251 return std::log1p(x);
252 }
253 else if constexpr (internal::isAutoDiffScalar<Scalar>)
254 {
255 using Real = typename Scalar::Real;
256 return Scalar{logOnePlus<Real>(x.value()), x.derivatives() / (Real(1) + x.value())};
257 }
258 else
259 {
260 return Eigen::numext::log1p(x);
261 }
262}
263
275template <typename Scalar>
276[[nodiscard]] Scalar
277floorOf(std::type_identity_t<Scalar> const & x)
278{
279 if constexpr (std::floating_point<Scalar>)
280 {
281 return std::floor(x);
282 }
283 else if constexpr (internal::isAutoDiffScalar<Scalar>)
284 {
285 using Real = typename Scalar::Real;
286 return Scalar{floorOf<Real>(x.value()), Scalar::DerType::Zero(x.derivatives().size())};
287 }
288 else
289 {
290 return Eigen::numext::floor(x);
291 }
292}
293
303template <typename T>
304[[nodiscard]] bool
305isFinite(T const & x)
306{
307 if constexpr (std::floating_point<T>)
308 {
309 return std::isfinite(x);
310 }
311 else if constexpr (internal::isAutoDiffScalar<T>)
312 {
313 return isFinite(x.value());
314 }
315 else
316 {
317 return Eigen::numext::isfinite(x);
318 }
319}
320
327template <typename T>
328[[nodiscard]] bool
329isNaN(T const & x)
330{
331 if constexpr (std::floating_point<T>)
332 {
333 return std::isnan(x);
334 }
335 else if constexpr (internal::isAutoDiffScalar<T>)
336 {
337 return isNaN(x.value());
338 }
339 else
340 {
341 return Eigen::numext::isnan(x);
342 }
343}
344
352template <typename Derived>
353[[nodiscard]] bool
354allFinite(Eigen::DenseBase<Derived> const & x)
355{
356 if constexpr (std::floating_point<typename Derived::Scalar>)
357 {
358 return x.allFinite();
359 }
360 else
361 {
362 for (Eigen::Index j = 0; j < x.cols(); ++j)
363 {
364 for (Eigen::Index i = 0; i < x.rows(); ++i)
365 {
366 if (!isFinite(x.coeff(i, j)))
367 {
368 return false;
369 }
370 }
371 }
372 return true;
373 }
374}
375
376namespace internal
377{
378
386template <typename Scalar>
387[[nodiscard]] Scalar
388scalarFromCount(std::integral auto count)
389{
390 using Literal = typename Eigen::NumTraits<Scalar>::Literal;
391 if constexpr (std::floating_point<Literal>)
392 {
393 return Scalar(Literal(count));
394 }
395 else
396 {
397 return Scalar(count);
398 }
399}
400
406[[nodiscard]] consteval double
407compileTimeSqrt(double x)
408{
409 if (x <= 0)
410 {
411 return 0;
412 }
413 double root = x > 1 ? x : 1;
414 while (true)
415 {
416 double const next = (root + x / root) / 2;
417 if (!(next < root))
418 {
419 return root;
420 }
421 root = next;
422 }
423}
424
425} // namespace internal
426
427} // namespace Emrys
The macros every header includes first.
A type usable as the scalar of a distribution: a real number type such as float, double,...
Definition Math.h:80
Scalar pi()
Definition Math.h:145
bool allFinite(Eigen::DenseBase< Derived > const &x)
Definition Math.h:354
Scalar logOnePlus(std::type_identity_t< Scalar > const &x)
Definition Math.h:247
Scalar logGamma(std::type_identity_t< Scalar > const &x)
Definition Math.h:216
bool isNaN(T const &x)
Definition Math.h:329
Scalar floorOf(std::type_identity_t< Scalar > const &x)
Definition Math.h:277
bool isFinite(T const &x)
Definition Math.h:305
Scalar log2Pi()
Definition Math.h:177