blob: 3b7f23fc9b9ab0087c3b903785ae0e8868b4d865 [file] [log] [blame]
Austin Schuh70cc9552019-01-21 19:46:48 -08001// Ceres Solver - A fast non-linear least squares minimizer
Austin Schuh3de38b02024-06-25 18:25:10 -07002// Copyright 2024 Google Inc. All rights reserved.
Austin Schuh70cc9552019-01-21 19:46:48 -08003// http://ceres-solver.org/
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are met:
7//
8// * Redistributions of source code must retain the above copyright notice,
9// this list of conditions and the following disclaimer.
10// * Redistributions in binary form must reproduce the above copyright notice,
11// this list of conditions and the following disclaimer in the documentation
12// and/or other materials provided with the distribution.
13// * Neither the name of Google Inc. nor the names of its contributors may be
14// used to endorse or promote products derived from this software without
15// specific prior written permission.
16//
17// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27// POSSIBILITY OF SUCH DAMAGE.
28//
29// Author: keir@google.com (Keir Mierle)
30//
31// A simple implementation of N-dimensional dual numbers, for automatically
32// computing exact derivatives of functions.
33//
34// While a complete treatment of the mechanics of automatic differentiation is
35// beyond the scope of this header (see
36// http://en.wikipedia.org/wiki/Automatic_differentiation for details), the
37// basic idea is to extend normal arithmetic with an extra element, "e," often
38// denoted with the greek symbol epsilon, such that e != 0 but e^2 = 0. Dual
39// numbers are extensions of the real numbers analogous to complex numbers:
40// whereas complex numbers augment the reals by introducing an imaginary unit i
41// such that i^2 = -1, dual numbers introduce an "infinitesimal" unit e such
42// that e^2 = 0. Dual numbers have two components: the "real" component and the
43// "infinitesimal" component, generally written as x + y*e. Surprisingly, this
44// leads to a convenient method for computing exact derivatives without needing
45// to manipulate complicated symbolic expressions.
46//
47// For example, consider the function
48//
49// f(x) = x^2 ,
50//
51// evaluated at 10. Using normal arithmetic, f(10) = 100, and df/dx(10) = 20.
52// Next, argument 10 with an infinitesimal to get:
53//
54// f(10 + e) = (10 + e)^2
55// = 100 + 2 * 10 * e + e^2
56// = 100 + 20 * e -+-
57// -- |
58// | +--- This is zero, since e^2 = 0
59// |
60// +----------------- This is df/dx!
61//
62// Note that the derivative of f with respect to x is simply the infinitesimal
63// component of the value of f(x + e). So, in order to take the derivative of
64// any function, it is only necessary to replace the numeric "object" used in
65// the function with one extended with infinitesimals. The class Jet, defined in
66// this header, is one such example of this, where substitution is done with
67// templates.
68//
69// To handle derivatives of functions taking multiple arguments, different
70// infinitesimals are used, one for each variable to take the derivative of. For
71// example, consider a scalar function of two scalar parameters x and y:
72//
73// f(x, y) = x^2 + x * y
74//
75// Following the technique above, to compute the derivatives df/dx and df/dy for
76// f(1, 3) involves doing two evaluations of f, the first time replacing x with
77// x + e, the second time replacing y with y + e.
78//
79// For df/dx:
80//
81// f(1 + e, y) = (1 + e)^2 + (1 + e) * 3
82// = 1 + 2 * e + 3 + 3 * e
83// = 4 + 5 * e
84//
85// --> df/dx = 5
86//
87// For df/dy:
88//
89// f(1, 3 + e) = 1^2 + 1 * (3 + e)
90// = 1 + 3 + e
91// = 4 + e
92//
93// --> df/dy = 1
94//
95// To take the gradient of f with the implementation of dual numbers ("jets") in
96// this file, it is necessary to create a single jet type which has components
97// for the derivative in x and y, and passing them to a templated version of f:
98//
99// template<typename T>
100// T f(const T &x, const T &y) {
101// return x * x + x * y;
102// }
103//
104// // The "2" means there should be 2 dual number components.
105// // It computes the partial derivative at x=10, y=20.
106// Jet<double, 2> x(10, 0); // Pick the 0th dual number for x.
107// Jet<double, 2> y(20, 1); // Pick the 1st dual number for y.
108// Jet<double, 2> z = f(x, y);
109//
110// LOG(INFO) << "df/dx = " << z.v[0]
111// << "df/dy = " << z.v[1];
112//
113// Most users should not use Jet objects directly; a wrapper around Jet objects,
114// which makes computing the derivative, gradient, or jacobian of templated
115// functors simple, is in autodiff.h. Even autodiff.h should not be used
116// directly; instead autodiff_cost_function.h is typically the file of interest.
117//
118// For the more mathematically inclined, this file implements first-order
119// "jets". A 1st order jet is an element of the ring
120//
121// T[N] = T[t_1, ..., t_N] / (t_1, ..., t_N)^2
122//
123// which essentially means that each jet consists of a "scalar" value 'a' from T
124// and a 1st order perturbation vector 'v' of length N:
125//
126// x = a + \sum_i v[i] t_i
127//
128// A shorthand is to write an element as x = a + u, where u is the perturbation.
129// Then, the main point about the arithmetic of jets is that the product of
130// perturbations is zero:
131//
132// (a + u) * (b + v) = ab + av + bu + uv
133// = ab + (av + bu) + 0
134//
135// which is what operator* implements below. Addition is simpler:
136//
137// (a + u) + (b + v) = (a + b) + (u + v).
138//
139// The only remaining question is how to evaluate the function of a jet, for
140// which we use the chain rule:
141//
142// f(a + u) = f(a) + f'(a) u
143//
144// where f'(a) is the (scalar) derivative of f at a.
145//
146// By pushing these things through sufficiently and suitably templated
147// functions, we can do automatic differentiation. Just be sure to turn on
148// function inlining and common-subexpression elimination, or it will be very
149// slow!
150//
151// WARNING: Most Ceres users should not directly include this file or know the
152// details of how jets work. Instead the suggested method for automatic
153// derivatives is to use autodiff_cost_function.h, which is a wrapper around
154// both jets.h and autodiff.h to make taking derivatives of cost functions for
155// use in Ceres easier.
156
157#ifndef CERES_PUBLIC_JET_H_
158#define CERES_PUBLIC_JET_H_
159
160#include <cmath>
Austin Schuh3de38b02024-06-25 18:25:10 -0700161#include <complex>
Austin Schuh70cc9552019-01-21 19:46:48 -0800162#include <iosfwd>
163#include <iostream> // NOLINT
164#include <limits>
Austin Schuh3de38b02024-06-25 18:25:10 -0700165#include <numeric>
Austin Schuh70cc9552019-01-21 19:46:48 -0800166#include <string>
Austin Schuh3de38b02024-06-25 18:25:10 -0700167#include <type_traits>
Austin Schuh70cc9552019-01-21 19:46:48 -0800168
169#include "Eigen/Core"
Austin Schuh3de38b02024-06-25 18:25:10 -0700170#include "ceres/internal/jet_traits.h"
Austin Schuh70cc9552019-01-21 19:46:48 -0800171#include "ceres/internal/port.h"
Austin Schuh3de38b02024-06-25 18:25:10 -0700172#include "ceres/jet_fwd.h"
173
174// Here we provide partial specializations of std::common_type for the Jet class
175// to allow determining a Jet type with a common underlying arithmetic type.
176// Such an arithmetic type can be either a scalar or an another Jet. An example
177// for a common type, say, between a float and a Jet<double, N> is a Jet<double,
178// N> (i.e., std::common_type_t<float, ceres::Jet<double, N>> and
179// ceres::Jet<double, N> refer to the same type.)
180//
181// The partial specialization are also used for determining compatible types by
182// means of SFINAE and thus allow such types to be expressed as operands of
183// logical comparison operators. Missing (partial) specialization of
184// std::common_type for a particular (custom) type will therefore disable the
185// use of comparison operators defined by Ceres.
186//
187// Since these partial specializations are used as SFINAE constraints, they
188// enable standard promotion rules between various scalar types and consequently
189// their use in comparison against a Jet without providing implicit
190// conversions from a scalar, such as an int, to a Jet (see the implementation
191// of logical comparison operators below).
192
193template <typename T, int N, typename U>
194struct std::common_type<T, ceres::Jet<U, N>> {
195 using type = ceres::Jet<common_type_t<T, U>, N>;
196};
197
198template <typename T, int N, typename U>
199struct std::common_type<ceres::Jet<T, N>, U> {
200 using type = ceres::Jet<common_type_t<T, U>, N>;
201};
202
203template <typename T, int N, typename U>
204struct std::common_type<ceres::Jet<T, N>, ceres::Jet<U, N>> {
205 using type = ceres::Jet<common_type_t<T, U>, N>;
206};
Austin Schuh70cc9552019-01-21 19:46:48 -0800207
208namespace ceres {
209
210template <typename T, int N>
211struct Jet {
212 enum { DIMENSION = N };
Austin Schuh3de38b02024-06-25 18:25:10 -0700213 using Scalar = T;
Austin Schuh70cc9552019-01-21 19:46:48 -0800214
215 // Default-construct "a" because otherwise this can lead to false errors about
216 // uninitialized uses when other classes relying on default constructed T
217 // (where T is a Jet<T, N>). This usually only happens in opt mode. Note that
218 // the C++ standard mandates that e.g. default constructed doubles are
219 // initialized to 0.0; see sections 8.5 of the C++03 standard.
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800220 Jet() : a() { v.setConstant(Scalar()); }
Austin Schuh70cc9552019-01-21 19:46:48 -0800221
222 // Constructor from scalar: a + 0.
223 explicit Jet(const T& value) {
224 a = value;
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800225 v.setConstant(Scalar());
Austin Schuh70cc9552019-01-21 19:46:48 -0800226 }
227
228 // Constructor from scalar plus variable: a + t_i.
229 Jet(const T& value, int k) {
230 a = value;
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800231 v.setConstant(Scalar());
Austin Schuh70cc9552019-01-21 19:46:48 -0800232 v[k] = T(1.0);
233 }
234
235 // Constructor from scalar and vector part
236 // The use of Eigen::DenseBase allows Eigen expressions
237 // to be passed in without being fully evaluated until
238 // they are assigned to v
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800239 template <typename Derived>
240 EIGEN_STRONG_INLINE Jet(const T& a, const Eigen::DenseBase<Derived>& v)
241 : a(a), v(v) {}
Austin Schuh70cc9552019-01-21 19:46:48 -0800242
243 // Compound operators
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800244 Jet<T, N>& operator+=(const Jet<T, N>& y) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800245 *this = *this + y;
246 return *this;
247 }
248
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800249 Jet<T, N>& operator-=(const Jet<T, N>& y) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800250 *this = *this - y;
251 return *this;
252 }
253
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800254 Jet<T, N>& operator*=(const Jet<T, N>& y) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800255 *this = *this * y;
256 return *this;
257 }
258
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800259 Jet<T, N>& operator/=(const Jet<T, N>& y) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800260 *this = *this / y;
261 return *this;
262 }
263
264 // Compound with scalar operators.
265 Jet<T, N>& operator+=(const T& s) {
266 *this = *this + s;
267 return *this;
268 }
269
270 Jet<T, N>& operator-=(const T& s) {
271 *this = *this - s;
272 return *this;
273 }
274
275 Jet<T, N>& operator*=(const T& s) {
276 *this = *this * s;
277 return *this;
278 }
279
280 Jet<T, N>& operator/=(const T& s) {
281 *this = *this / s;
282 return *this;
283 }
284
285 // The scalar part.
286 T a;
287
288 // The infinitesimal part.
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800289 Eigen::Matrix<T, N, 1> v;
Austin Schuh70cc9552019-01-21 19:46:48 -0800290
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800291 // This struct needs to have an Eigen aligned operator new as it contains
292 // fixed-size Eigen types.
293 EIGEN_MAKE_ALIGNED_OPERATOR_NEW
Austin Schuh70cc9552019-01-21 19:46:48 -0800294};
295
296// Unary +
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800297template <typename T, int N>
298inline Jet<T, N> const& operator+(const Jet<T, N>& f) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800299 return f;
300}
301
302// TODO(keir): Try adding __attribute__((always_inline)) to these functions to
303// see if it causes a performance increase.
304
305// Unary -
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800306template <typename T, int N>
307inline Jet<T, N> operator-(const Jet<T, N>& f) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800308 return Jet<T, N>(-f.a, -f.v);
309}
310
311// Binary +
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800312template <typename T, int N>
313inline Jet<T, N> operator+(const Jet<T, N>& f, const Jet<T, N>& g) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800314 return Jet<T, N>(f.a + g.a, f.v + g.v);
315}
316
317// Binary + with a scalar: x + s
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800318template <typename T, int N>
319inline Jet<T, N> operator+(const Jet<T, N>& f, T s) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800320 return Jet<T, N>(f.a + s, f.v);
321}
322
323// Binary + with a scalar: s + x
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800324template <typename T, int N>
325inline Jet<T, N> operator+(T s, const Jet<T, N>& f) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800326 return Jet<T, N>(f.a + s, f.v);
327}
328
329// Binary -
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800330template <typename T, int N>
331inline Jet<T, N> operator-(const Jet<T, N>& f, const Jet<T, N>& g) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800332 return Jet<T, N>(f.a - g.a, f.v - g.v);
333}
334
335// Binary - with a scalar: x - s
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800336template <typename T, int N>
337inline Jet<T, N> operator-(const Jet<T, N>& f, T s) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800338 return Jet<T, N>(f.a - s, f.v);
339}
340
341// Binary - with a scalar: s - x
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800342template <typename T, int N>
343inline Jet<T, N> operator-(T s, const Jet<T, N>& f) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800344 return Jet<T, N>(s - f.a, -f.v);
345}
346
347// Binary *
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800348template <typename T, int N>
349inline Jet<T, N> operator*(const Jet<T, N>& f, const Jet<T, N>& g) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800350 return Jet<T, N>(f.a * g.a, f.a * g.v + f.v * g.a);
351}
352
353// Binary * with a scalar: x * s
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800354template <typename T, int N>
355inline Jet<T, N> operator*(const Jet<T, N>& f, T s) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800356 return Jet<T, N>(f.a * s, f.v * s);
357}
358
359// Binary * with a scalar: s * x
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800360template <typename T, int N>
361inline Jet<T, N> operator*(T s, const Jet<T, N>& f) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800362 return Jet<T, N>(f.a * s, f.v * s);
363}
364
365// Binary /
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800366template <typename T, int N>
367inline Jet<T, N> operator/(const Jet<T, N>& f, const Jet<T, N>& g) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800368 // This uses:
369 //
370 // a + u (a + u)(b - v) (a + u)(b - v)
371 // ----- = -------------- = --------------
372 // b + v (b + v)(b - v) b^2
373 //
374 // which holds because v*v = 0.
375 const T g_a_inverse = T(1.0) / g.a;
376 const T f_a_by_g_a = f.a * g_a_inverse;
377 return Jet<T, N>(f_a_by_g_a, (f.v - f_a_by_g_a * g.v) * g_a_inverse);
378}
379
380// Binary / with a scalar: s / x
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800381template <typename T, int N>
382inline Jet<T, N> operator/(T s, const Jet<T, N>& g) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800383 const T minus_s_g_a_inverse2 = -s / (g.a * g.a);
384 return Jet<T, N>(s / g.a, g.v * minus_s_g_a_inverse2);
385}
386
387// Binary / with a scalar: x / s
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800388template <typename T, int N>
389inline Jet<T, N> operator/(const Jet<T, N>& f, T s) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800390 const T s_inverse = T(1.0) / s;
391 return Jet<T, N>(f.a * s_inverse, f.v * s_inverse);
392}
393
Austin Schuh3de38b02024-06-25 18:25:10 -0700394// Binary comparison operators for both scalars and jets. At least one of the
395// operands must be a Jet. Promotable scalars (e.g., int, float, double etc.)
396// can appear on either side of the operator. std::common_type_t is used as an
397// SFINAE constraint to selectively enable compatible operand types. This allows
398// comparison, for instance, against int literals without implicit conversion.
399// In case the Jet arithmetic type is a Jet itself, a recursive expansion of Jet
400// value is performed.
401#define CERES_DEFINE_JET_COMPARISON_OPERATOR(op) \
402 template <typename Lhs, \
403 typename Rhs, \
404 std::enable_if_t<PromotableJetOperands_v<Lhs, Rhs>>* = nullptr> \
405 constexpr bool operator op(const Lhs& f, const Rhs& g) noexcept( \
406 noexcept(internal::AsScalar(f) op internal::AsScalar(g))) { \
407 using internal::AsScalar; \
408 return AsScalar(f) op AsScalar(g); \
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800409 }
410CERES_DEFINE_JET_COMPARISON_OPERATOR(<) // NOLINT
411CERES_DEFINE_JET_COMPARISON_OPERATOR(<=) // NOLINT
412CERES_DEFINE_JET_COMPARISON_OPERATOR(>) // NOLINT
413CERES_DEFINE_JET_COMPARISON_OPERATOR(>=) // NOLINT
414CERES_DEFINE_JET_COMPARISON_OPERATOR(==) // NOLINT
415CERES_DEFINE_JET_COMPARISON_OPERATOR(!=) // NOLINT
Austin Schuh70cc9552019-01-21 19:46:48 -0800416#undef CERES_DEFINE_JET_COMPARISON_OPERATOR
417
418// Pull some functions from namespace std.
419//
420// This is necessary because we want to use the same name (e.g. 'sqrt') for
421// double-valued and Jet-valued functions, but we are not allowed to put
422// Jet-valued functions inside namespace std.
423using std::abs;
424using std::acos;
425using std::asin;
426using std::atan;
427using std::atan2;
428using std::cbrt;
429using std::ceil;
Austin Schuh3de38b02024-06-25 18:25:10 -0700430using std::copysign;
Austin Schuh70cc9552019-01-21 19:46:48 -0800431using std::cos;
432using std::cosh;
Austin Schuh3de38b02024-06-25 18:25:10 -0700433#ifdef CERES_HAS_CPP17_BESSEL_FUNCTIONS
434using std::cyl_bessel_j;
435#endif // CERES_HAS_CPP17_BESSEL_FUNCTIONS
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800436using std::erf;
437using std::erfc;
Austin Schuh70cc9552019-01-21 19:46:48 -0800438using std::exp;
439using std::exp2;
Austin Schuh3de38b02024-06-25 18:25:10 -0700440using std::expm1;
441using std::fdim;
Austin Schuh70cc9552019-01-21 19:46:48 -0800442using std::floor;
Austin Schuh3de38b02024-06-25 18:25:10 -0700443using std::fma;
Austin Schuh70cc9552019-01-21 19:46:48 -0800444using std::fmax;
445using std::fmin;
Austin Schuh3de38b02024-06-25 18:25:10 -0700446using std::fpclassify;
Austin Schuh70cc9552019-01-21 19:46:48 -0800447using std::hypot;
448using std::isfinite;
449using std::isinf;
450using std::isnan;
451using std::isnormal;
452using std::log;
Austin Schuh3de38b02024-06-25 18:25:10 -0700453using std::log10;
454using std::log1p;
Austin Schuh70cc9552019-01-21 19:46:48 -0800455using std::log2;
Austin Schuh3de38b02024-06-25 18:25:10 -0700456using std::norm;
Austin Schuh70cc9552019-01-21 19:46:48 -0800457using std::pow;
Austin Schuh3de38b02024-06-25 18:25:10 -0700458using std::signbit;
Austin Schuh70cc9552019-01-21 19:46:48 -0800459using std::sin;
460using std::sinh;
461using std::sqrt;
462using std::tan;
463using std::tanh;
464
Austin Schuh3de38b02024-06-25 18:25:10 -0700465// MSVC (up to 1930) defines quiet comparison functions as template functions
466// which causes compilation errors due to ambiguity in the template parameter
467// type resolution for using declarations in the ceres namespace. Workaround the
468// issue by defining specific overload and bypass MSVC standard library
469// definitions.
470#if defined(_MSC_VER)
471inline bool isgreater(double lhs,
472 double rhs) noexcept(noexcept(std::isgreater(lhs, rhs))) {
473 return std::isgreater(lhs, rhs);
474}
475inline bool isless(double lhs,
476 double rhs) noexcept(noexcept(std::isless(lhs, rhs))) {
477 return std::isless(lhs, rhs);
478}
479inline bool islessequal(double lhs,
480 double rhs) noexcept(noexcept(std::islessequal(lhs,
481 rhs))) {
482 return std::islessequal(lhs, rhs);
483}
484inline bool isgreaterequal(double lhs, double rhs) noexcept(
485 noexcept(std::isgreaterequal(lhs, rhs))) {
486 return std::isgreaterequal(lhs, rhs);
487}
488inline bool islessgreater(double lhs, double rhs) noexcept(
489 noexcept(std::islessgreater(lhs, rhs))) {
490 return std::islessgreater(lhs, rhs);
491}
492inline bool isunordered(double lhs,
493 double rhs) noexcept(noexcept(std::isunordered(lhs,
494 rhs))) {
495 return std::isunordered(lhs, rhs);
496}
497#else
498using std::isgreater;
499using std::isgreaterequal;
500using std::isless;
501using std::islessequal;
502using std::islessgreater;
503using std::isunordered;
504#endif
505
506#ifdef CERES_HAS_CPP20
507using std::lerp;
508using std::midpoint;
509#endif // defined(CERES_HAS_CPP20)
510
Austin Schuh70cc9552019-01-21 19:46:48 -0800511// Legacy names from pre-C++11 days.
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800512// clang-format off
Austin Schuh3de38b02024-06-25 18:25:10 -0700513CERES_DEPRECATED_WITH_MSG("ceres::IsFinite will be removed in a future Ceres Solver release. Please use ceres::isfinite.")
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800514inline bool IsFinite(double x) { return std::isfinite(x); }
Austin Schuh3de38b02024-06-25 18:25:10 -0700515CERES_DEPRECATED_WITH_MSG("ceres::IsInfinite will be removed in a future Ceres Solver release. Please use ceres::isinf.")
Austin Schuh70cc9552019-01-21 19:46:48 -0800516inline bool IsInfinite(double x) { return std::isinf(x); }
Austin Schuh3de38b02024-06-25 18:25:10 -0700517CERES_DEPRECATED_WITH_MSG("ceres::IsNaN will be removed in a future Ceres Solver release. Please use ceres::isnan.")
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800518inline bool IsNaN(double x) { return std::isnan(x); }
Austin Schuh3de38b02024-06-25 18:25:10 -0700519CERES_DEPRECATED_WITH_MSG("ceres::IsNormal will be removed in a future Ceres Solver release. Please use ceres::isnormal.")
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800520inline bool IsNormal(double x) { return std::isnormal(x); }
521// clang-format on
Austin Schuh70cc9552019-01-21 19:46:48 -0800522
523// In general, f(a + h) ~= f(a) + f'(a) h, via the chain rule.
524
Austin Schuh3de38b02024-06-25 18:25:10 -0700525// abs(x + h) ~= abs(x) + sgn(x)h
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800526template <typename T, int N>
527inline Jet<T, N> abs(const Jet<T, N>& f) {
Austin Schuh3de38b02024-06-25 18:25:10 -0700528 return Jet<T, N>(abs(f.a), copysign(T(1), f.a) * f.v);
529}
530
531// copysign(a, b) composes a float with the magnitude of a and the sign of b.
532// Therefore, the function can be formally defined as
533//
534// copysign(a, b) = sgn(b)|a|
535//
536// where
537//
538// d/dx |x| = sgn(x)
539// d/dx sgn(x) = 2δ(x)
540//
541// sgn(x) being the signum function. Differentiating copysign(a, b) with respect
542// to a and b gives:
543//
544// d/da sgn(b)|a| = sgn(a) sgn(b)
545// d/db sgn(b)|a| = 2|a|δ(b)
546//
547// with the dual representation given by
548//
549// copysign(a + da, b + db) ~= sgn(b)|a| + (sgn(a)sgn(b) da + 2|a|δ(b) db)
550//
551// where δ(b) is the Dirac delta function.
552template <typename T, int N>
553inline Jet<T, N> copysign(const Jet<T, N>& f, const Jet<T, N> g) {
554 // The Dirac delta function δ(b) is undefined at b=0 (here it's
555 // infinite) and 0 everywhere else.
556 T d = fpclassify(g) == FP_ZERO ? std::numeric_limits<T>::infinity() : T(0);
557 T sa = copysign(T(1), f.a); // sgn(a)
558 T sb = copysign(T(1), g.a); // sgn(b)
559 // The second part of the infinitesimal is 2|a|δ(b) which is either infinity
560 // or 0 unless a or any of the values of the b infinitesimal are 0. In the
561 // latter case, the corresponding values become NaNs (multiplying 0 by
562 // infinity gives NaN). We drop the constant factor 2 since it does not change
563 // the result (its values will still be either 0, infinity or NaN).
564 return Jet<T, N>(copysign(f.a, g.a), sa * sb * f.v + abs(f.a) * d * g.v);
Austin Schuh70cc9552019-01-21 19:46:48 -0800565}
566
567// log(a + h) ~= log(a) + h / a
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800568template <typename T, int N>
569inline Jet<T, N> log(const Jet<T, N>& f) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800570 const T a_inverse = T(1.0) / f.a;
571 return Jet<T, N>(log(f.a), f.v * a_inverse);
572}
573
Austin Schuh3de38b02024-06-25 18:25:10 -0700574// log10(a + h) ~= log10(a) + h / (a log(10))
575template <typename T, int N>
576inline Jet<T, N> log10(const Jet<T, N>& f) {
577 // Most compilers will expand log(10) to a constant.
578 const T a_inverse = T(1.0) / (f.a * log(T(10.0)));
579 return Jet<T, N>(log10(f.a), f.v * a_inverse);
580}
581
582// log1p(a + h) ~= log1p(a) + h / (1 + a)
583template <typename T, int N>
584inline Jet<T, N> log1p(const Jet<T, N>& f) {
585 const T a_inverse = T(1.0) / (T(1.0) + f.a);
586 return Jet<T, N>(log1p(f.a), f.v * a_inverse);
587}
588
Austin Schuh70cc9552019-01-21 19:46:48 -0800589// exp(a + h) ~= exp(a) + exp(a) h
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800590template <typename T, int N>
591inline Jet<T, N> exp(const Jet<T, N>& f) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800592 const T tmp = exp(f.a);
593 return Jet<T, N>(tmp, tmp * f.v);
594}
595
Austin Schuh3de38b02024-06-25 18:25:10 -0700596// expm1(a + h) ~= expm1(a) + exp(a) h
597template <typename T, int N>
598inline Jet<T, N> expm1(const Jet<T, N>& f) {
599 const T tmp = expm1(f.a);
600 const T expa = tmp + T(1.0); // exp(a) = expm1(a) + 1
601 return Jet<T, N>(tmp, expa * f.v);
602}
603
Austin Schuh70cc9552019-01-21 19:46:48 -0800604// sqrt(a + h) ~= sqrt(a) + h / (2 sqrt(a))
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800605template <typename T, int N>
606inline Jet<T, N> sqrt(const Jet<T, N>& f) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800607 const T tmp = sqrt(f.a);
608 const T two_a_inverse = T(1.0) / (T(2.0) * tmp);
609 return Jet<T, N>(tmp, f.v * two_a_inverse);
610}
611
612// cos(a + h) ~= cos(a) - sin(a) h
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800613template <typename T, int N>
614inline Jet<T, N> cos(const Jet<T, N>& f) {
615 return Jet<T, N>(cos(f.a), -sin(f.a) * f.v);
Austin Schuh70cc9552019-01-21 19:46:48 -0800616}
617
618// acos(a + h) ~= acos(a) - 1 / sqrt(1 - a^2) h
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800619template <typename T, int N>
620inline Jet<T, N> acos(const Jet<T, N>& f) {
621 const T tmp = -T(1.0) / sqrt(T(1.0) - f.a * f.a);
Austin Schuh70cc9552019-01-21 19:46:48 -0800622 return Jet<T, N>(acos(f.a), tmp * f.v);
623}
624
625// sin(a + h) ~= sin(a) + cos(a) h
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800626template <typename T, int N>
627inline Jet<T, N> sin(const Jet<T, N>& f) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800628 return Jet<T, N>(sin(f.a), cos(f.a) * f.v);
629}
630
631// asin(a + h) ~= asin(a) + 1 / sqrt(1 - a^2) h
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800632template <typename T, int N>
633inline Jet<T, N> asin(const Jet<T, N>& f) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800634 const T tmp = T(1.0) / sqrt(T(1.0) - f.a * f.a);
635 return Jet<T, N>(asin(f.a), tmp * f.v);
636}
637
638// tan(a + h) ~= tan(a) + (1 + tan(a)^2) h
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800639template <typename T, int N>
640inline Jet<T, N> tan(const Jet<T, N>& f) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800641 const T tan_a = tan(f.a);
642 const T tmp = T(1.0) + tan_a * tan_a;
643 return Jet<T, N>(tan_a, tmp * f.v);
644}
645
646// atan(a + h) ~= atan(a) + 1 / (1 + a^2) h
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800647template <typename T, int N>
648inline Jet<T, N> atan(const Jet<T, N>& f) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800649 const T tmp = T(1.0) / (T(1.0) + f.a * f.a);
650 return Jet<T, N>(atan(f.a), tmp * f.v);
651}
652
653// sinh(a + h) ~= sinh(a) + cosh(a) h
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800654template <typename T, int N>
655inline Jet<T, N> sinh(const Jet<T, N>& f) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800656 return Jet<T, N>(sinh(f.a), cosh(f.a) * f.v);
657}
658
659// cosh(a + h) ~= cosh(a) + sinh(a) h
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800660template <typename T, int N>
661inline Jet<T, N> cosh(const Jet<T, N>& f) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800662 return Jet<T, N>(cosh(f.a), sinh(f.a) * f.v);
663}
664
665// tanh(a + h) ~= tanh(a) + (1 - tanh(a)^2) h
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800666template <typename T, int N>
667inline Jet<T, N> tanh(const Jet<T, N>& f) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800668 const T tanh_a = tanh(f.a);
669 const T tmp = T(1.0) - tanh_a * tanh_a;
670 return Jet<T, N>(tanh_a, tmp * f.v);
671}
672
673// The floor function should be used with extreme care as this operation will
674// result in a zero derivative which provides no information to the solver.
675//
676// floor(a + h) ~= floor(a) + 0
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800677template <typename T, int N>
678inline Jet<T, N> floor(const Jet<T, N>& f) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800679 return Jet<T, N>(floor(f.a));
680}
681
682// The ceil function should be used with extreme care as this operation will
683// result in a zero derivative which provides no information to the solver.
684//
685// ceil(a + h) ~= ceil(a) + 0
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800686template <typename T, int N>
687inline Jet<T, N> ceil(const Jet<T, N>& f) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800688 return Jet<T, N>(ceil(f.a));
689}
690
691// Some new additions to C++11:
692
693// cbrt(a + h) ~= cbrt(a) + h / (3 a ^ (2/3))
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800694template <typename T, int N>
695inline Jet<T, N> cbrt(const Jet<T, N>& f) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800696 const T derivative = T(1.0) / (T(3.0) * cbrt(f.a * f.a));
697 return Jet<T, N>(cbrt(f.a), f.v * derivative);
698}
699
700// exp2(x + h) = 2^(x+h) ~= 2^x + h*2^x*log(2)
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800701template <typename T, int N>
702inline Jet<T, N> exp2(const Jet<T, N>& f) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800703 const T tmp = exp2(f.a);
704 const T derivative = tmp * log(T(2));
705 return Jet<T, N>(tmp, f.v * derivative);
706}
707
708// log2(x + h) ~= log2(x) + h / (x * log(2))
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800709template <typename T, int N>
710inline Jet<T, N> log2(const Jet<T, N>& f) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800711 const T derivative = T(1.0) / (f.a * log(T(2)));
712 return Jet<T, N>(log2(f.a), f.v * derivative);
713}
714
715// Like sqrt(x^2 + y^2),
716// but acts to prevent underflow/overflow for small/large x/y.
717// Note that the function is non-smooth at x=y=0,
718// so the derivative is undefined there.
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800719template <typename T, int N>
720inline Jet<T, N> hypot(const Jet<T, N>& x, const Jet<T, N>& y) {
Austin Schuh70cc9552019-01-21 19:46:48 -0800721 // d/da sqrt(a) = 0.5 / sqrt(a)
722 // d/dx x^2 + y^2 = 2x
723 // So by the chain rule:
724 // d/dx sqrt(x^2 + y^2) = 0.5 / sqrt(x^2 + y^2) * 2x = x / sqrt(x^2 + y^2)
725 // d/dy sqrt(x^2 + y^2) = y / sqrt(x^2 + y^2)
726 const T tmp = hypot(x.a, y.a);
727 return Jet<T, N>(tmp, x.a / tmp * x.v + y.a / tmp * y.v);
728}
729
Austin Schuh3de38b02024-06-25 18:25:10 -0700730// Like sqrt(x^2 + y^2 + z^2),
731// but acts to prevent underflow/overflow for small/large x/y/z.
732// Note that the function is non-smooth at x=y=z=0,
733// so the derivative is undefined there.
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800734template <typename T, int N>
Austin Schuh3de38b02024-06-25 18:25:10 -0700735inline Jet<T, N> hypot(const Jet<T, N>& x,
736 const Jet<T, N>& y,
737 const Jet<T, N>& z) {
738 // d/da sqrt(a) = 0.5 / sqrt(a)
739 // d/dx x^2 + y^2 + z^2 = 2x
740 // So by the chain rule:
741 // d/dx sqrt(x^2 + y^2 + z^2)
742 // = 0.5 / sqrt(x^2 + y^2 + z^2) * 2x
743 // = x / sqrt(x^2 + y^2 + z^2)
744 // d/dy sqrt(x^2 + y^2 + z^2) = y / sqrt(x^2 + y^2 + z^2)
745 // d/dz sqrt(x^2 + y^2 + z^2) = z / sqrt(x^2 + y^2 + z^2)
746 const T tmp = hypot(x.a, y.a, z.a);
747 return Jet<T, N>(tmp, x.a / tmp * x.v + y.a / tmp * y.v + z.a / tmp * z.v);
Austin Schuh70cc9552019-01-21 19:46:48 -0800748}
749
Austin Schuh3de38b02024-06-25 18:25:10 -0700750// Like x * y + z but rounded only once.
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800751template <typename T, int N>
Austin Schuh3de38b02024-06-25 18:25:10 -0700752inline Jet<T, N> fma(const Jet<T, N>& x,
753 const Jet<T, N>& y,
754 const Jet<T, N>& z) {
755 // d/dx fma(x, y, z) = y
756 // d/dy fma(x, y, z) = x
757 // d/dz fma(x, y, z) = 1
758 return Jet<T, N>(fma(x.a, y.a, z.a), y.a * x.v + x.a * y.v + z.v);
Austin Schuh70cc9552019-01-21 19:46:48 -0800759}
760
Austin Schuh3de38b02024-06-25 18:25:10 -0700761// Return value of fmax() and fmin() on equality
762// ---------------------------------------------
763//
764// There is arguably no good answer to what fmax() & fmin() should return on
765// equality, which for Jets by definition ONLY compares the scalar parts. We
766// choose what we think is the least worst option (averaging as Jets) which
767// minimises undesirable/unexpected behaviour as used, and also supports client
768// code written against Ceres versions prior to type promotion being supported
769// in Jet comparisons (< v2.1).
770//
771// The std::max() convention of returning the first argument on equality is
772// problematic, as it means that the derivative component may or may not be
773// preserved (when comparing a Jet with a scalar) depending upon the ordering.
774//
775// Always returning the Jet in {Jet, scalar} cases on equality is problematic
776// as it is inconsistent with the behaviour that would be obtained if the scalar
777// was first cast to Jet and the {Jet, Jet} case was used. Prior to type
778// promotion (Ceres v2.1) client code would typically cast constants to Jets
779// e.g: fmax(x, T(2.0)) which means the {Jet, Jet} case predominates, and we
780// still want the result to be order independent.
781//
782// Our intuition is that preserving a non-zero derivative is best, even if
783// its value does not match either of the inputs. Averaging achieves this
784// whilst ensuring argument ordering independence. This is also the approach
785// used by the Jax library, and TensorFlow's reduce_max().
786
787// Returns the larger of the two arguments, with Jet averaging on equality.
788// NaNs are treated as missing data.
789//
790// NOTE: This function is NOT subject to any of the error conditions specified
791// in `math_errhandling`.
792template <typename Lhs,
793 typename Rhs,
794 std::enable_if_t<CompatibleJetOperands_v<Lhs, Rhs>>* = nullptr>
795inline decltype(auto) fmax(const Lhs& x, const Rhs& y) {
796 using J = std::common_type_t<Lhs, Rhs>;
797 // As x == y may set FP exceptions in the presence of NaNs when used with
798 // non-default compiler options so we avoid its use here.
799 if (isnan(x) || isnan(y) || islessgreater(x, y)) {
800 return isnan(x) || isless(x, y) ? J{y} : J{x};
801 }
802 // x == y (scalar parts) return the average of their Jet representations.
803#if defined(CERES_HAS_CPP20)
804 return midpoint(J{x}, J{y});
805#else
806 return (J{x} + J{y}) * typename J::Scalar(0.5);
807#endif // defined(CERES_HAS_CPP20)
808}
809
810// Returns the smaller of the two arguments, with Jet averaging on equality.
811// NaNs are treated as missing data.
812//
813// NOTE: This function is NOT subject to any of the error conditions specified
814// in `math_errhandling`.
815template <typename Lhs,
816 typename Rhs,
817 std::enable_if_t<CompatibleJetOperands_v<Lhs, Rhs>>* = nullptr>
818inline decltype(auto) fmin(const Lhs& x, const Rhs& y) {
819 using J = std::common_type_t<Lhs, Rhs>;
820 // As x == y may set FP exceptions in the presence of NaNs when used with
821 // non-default compiler options so we avoid its use here.
822 if (isnan(x) || isnan(y) || islessgreater(x, y)) {
823 return isnan(x) || isgreater(x, y) ? J{y} : J{x};
824 }
825 // x == y (scalar parts) return the average of their Jet representations.
826#if defined(CERES_HAS_CPP20)
827 return midpoint(J{x}, J{y});
828#else
829 return (J{x} + J{y}) * typename J::Scalar(0.5);
830#endif // defined(CERES_HAS_CPP20)
831}
832
833// Returns the positive difference (f - g) of two arguments and zero if f <= g.
834// If at least one argument is NaN, a NaN is return.
835//
836// NOTE At least one of the argument types must be a Jet, the other one can be a
837// scalar. In case both arguments are Jets, their dimensionality must match.
838template <typename Lhs,
839 typename Rhs,
840 std::enable_if_t<CompatibleJetOperands_v<Lhs, Rhs>>* = nullptr>
841inline decltype(auto) fdim(const Lhs& f, const Rhs& g) {
842 using J = std::common_type_t<Lhs, Rhs>;
843 if (isnan(f) || isnan(g)) {
844 return std::numeric_limits<J>::quiet_NaN();
845 }
846 return isgreater(f, g) ? J{f - g} : J{};
847}
848
849// erf is defined as an integral that cannot be expressed analytically
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800850// however, the derivative is trivial to compute
851// erf(x + h) = erf(x) + h * 2*exp(-x^2)/sqrt(pi)
852template <typename T, int N>
853inline Jet<T, N> erf(const Jet<T, N>& x) {
Austin Schuh3de38b02024-06-25 18:25:10 -0700854 // We evaluate the constant as follows:
855 // 2 / sqrt(pi) = 1 / sqrt(atan(1.))
856 // On POSIX systems it is defined as M_2_SQRTPI, but this is not
857 // portable and the type may not be T. The above expression
858 // evaluates to full precision with IEEE arithmetic and, since it's
859 // constant, the compiler can generate exactly the same code. gcc
860 // does so even at -O0.
861 return Jet<T, N>(erf(x.a), x.v * exp(-x.a * x.a) * (T(1) / sqrt(atan(T(1)))));
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800862}
863
864// erfc(x) = 1-erf(x)
865// erfc(x + h) = erfc(x) + h * (-2*exp(-x^2)/sqrt(pi))
866template <typename T, int N>
867inline Jet<T, N> erfc(const Jet<T, N>& x) {
Austin Schuh3de38b02024-06-25 18:25:10 -0700868 // See in erf() above for the evaluation of the constant in the derivative.
869 return Jet<T, N>(erfc(x.a),
870 -x.v * exp(-x.a * x.a) * (T(1) / sqrt(atan(T(1)))));
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800871}
872
Austin Schuh3de38b02024-06-25 18:25:10 -0700873#if defined(CERES_HAS_CPP17_BESSEL_FUNCTIONS) || \
874 defined(CERES_HAS_POSIX_BESSEL_FUNCTIONS)
875
Austin Schuh70cc9552019-01-21 19:46:48 -0800876// Bessel functions of the first kind with integer order equal to 0, 1, n.
877//
878// Microsoft has deprecated the j[0,1,n]() POSIX Bessel functions in favour of
879// _j[0,1,n](). Where available on MSVC, use _j[0,1,n]() to avoid deprecated
880// function errors in client code (the specific warning is suppressed when
881// Ceres itself is built).
882inline double BesselJ0(double x) {
Austin Schuh3de38b02024-06-25 18:25:10 -0700883#ifdef CERES_HAS_CPP17_BESSEL_FUNCTIONS
884 return cyl_bessel_j(0, x);
Austin Schuh70cc9552019-01-21 19:46:48 -0800885#else
Austin Schuh3de38b02024-06-25 18:25:10 -0700886 CERES_DISABLE_DEPRECATED_WARNING
Austin Schuh70cc9552019-01-21 19:46:48 -0800887 return j0(x);
Austin Schuh3de38b02024-06-25 18:25:10 -0700888 CERES_RESTORE_DEPRECATED_WARNING
889#endif // defined(CERES_HAS_CPP17_BESSEL_FUNCTIONS)
Austin Schuh70cc9552019-01-21 19:46:48 -0800890}
Austin Schuh3de38b02024-06-25 18:25:10 -0700891
Austin Schuh70cc9552019-01-21 19:46:48 -0800892inline double BesselJ1(double x) {
Austin Schuh3de38b02024-06-25 18:25:10 -0700893#ifdef CERES_HAS_CPP17_BESSEL_FUNCTIONS
894 return cyl_bessel_j(1, x);
Austin Schuh70cc9552019-01-21 19:46:48 -0800895#else
Austin Schuh3de38b02024-06-25 18:25:10 -0700896 CERES_DISABLE_DEPRECATED_WARNING
Austin Schuh70cc9552019-01-21 19:46:48 -0800897 return j1(x);
Austin Schuh3de38b02024-06-25 18:25:10 -0700898 CERES_RESTORE_DEPRECATED_WARNING
899#endif // defined(CERES_HAS_CPP17_BESSEL_FUNCTIONS)
Austin Schuh70cc9552019-01-21 19:46:48 -0800900}
Austin Schuh3de38b02024-06-25 18:25:10 -0700901
Austin Schuh70cc9552019-01-21 19:46:48 -0800902inline double BesselJn(int n, double x) {
Austin Schuh3de38b02024-06-25 18:25:10 -0700903#ifdef CERES_HAS_CPP17_BESSEL_FUNCTIONS
904 return cyl_bessel_j(static_cast<double>(n), x);
Austin Schuh70cc9552019-01-21 19:46:48 -0800905#else
Austin Schuh3de38b02024-06-25 18:25:10 -0700906 CERES_DISABLE_DEPRECATED_WARNING
Austin Schuh70cc9552019-01-21 19:46:48 -0800907 return jn(n, x);
Austin Schuh3de38b02024-06-25 18:25:10 -0700908 CERES_RESTORE_DEPRECATED_WARNING
909#endif // defined(CERES_HAS_CPP17_BESSEL_FUNCTIONS)
Austin Schuh70cc9552019-01-21 19:46:48 -0800910}
911
912// For the formulae of the derivatives of the Bessel functions see the book:
913// Olver, Lozier, Boisvert, Clark, NIST Handbook of Mathematical Functions,
914// Cambridge University Press 2010.
915//
916// Formulae are also available at http://dlmf.nist.gov
917
918// See formula http://dlmf.nist.gov/10.6#E3
919// j0(a + h) ~= j0(a) - j1(a) h
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800920template <typename T, int N>
921inline Jet<T, N> BesselJ0(const Jet<T, N>& f) {
Austin Schuh3de38b02024-06-25 18:25:10 -0700922#ifdef CERES_HAS_CPP17_BESSEL_FUNCTIONS
923 return cyl_bessel_j(0, f);
924#else
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800925 return Jet<T, N>(BesselJ0(f.a), -BesselJ1(f.a) * f.v);
Austin Schuh3de38b02024-06-25 18:25:10 -0700926#endif // defined(CERES_HAS_CPP17_BESSEL_FUNCTIONS)
Austin Schuh70cc9552019-01-21 19:46:48 -0800927}
928
929// See formula http://dlmf.nist.gov/10.6#E1
930// j1(a + h) ~= j1(a) + 0.5 ( j0(a) - j2(a) ) h
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800931template <typename T, int N>
932inline Jet<T, N> BesselJ1(const Jet<T, N>& f) {
Austin Schuh3de38b02024-06-25 18:25:10 -0700933#ifdef CERES_HAS_CPP17_BESSEL_FUNCTIONS
934 return cyl_bessel_j(1, f);
935#else
Austin Schuh70cc9552019-01-21 19:46:48 -0800936 return Jet<T, N>(BesselJ1(f.a),
937 T(0.5) * (BesselJ0(f.a) - BesselJn(2, f.a)) * f.v);
Austin Schuh3de38b02024-06-25 18:25:10 -0700938#endif // defined(CERES_HAS_CPP17_BESSEL_FUNCTIONS)
Austin Schuh70cc9552019-01-21 19:46:48 -0800939}
940
941// See formula http://dlmf.nist.gov/10.6#E1
942// j_n(a + h) ~= j_n(a) + 0.5 ( j_{n-1}(a) - j_{n+1}(a) ) h
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800943template <typename T, int N>
944inline Jet<T, N> BesselJn(int n, const Jet<T, N>& f) {
Austin Schuh3de38b02024-06-25 18:25:10 -0700945#ifdef CERES_HAS_CPP17_BESSEL_FUNCTIONS
946 return cyl_bessel_j(n, f);
947#else
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800948 return Jet<T, N>(
949 BesselJn(n, f.a),
950 T(0.5) * (BesselJn(n - 1, f.a) - BesselJn(n + 1, f.a)) * f.v);
Austin Schuh3de38b02024-06-25 18:25:10 -0700951#endif // defined(CERES_HAS_CPP17_BESSEL_FUNCTIONS)
Austin Schuh70cc9552019-01-21 19:46:48 -0800952}
953
Austin Schuh3de38b02024-06-25 18:25:10 -0700954#endif // defined(CERES_HAS_CPP17_BESSEL_FUNCTIONS) ||
955 // defined(CERES_HAS_POSIX_BESSEL_FUNCTIONS)
Austin Schuh70cc9552019-01-21 19:46:48 -0800956
Austin Schuh3de38b02024-06-25 18:25:10 -0700957#ifdef CERES_HAS_CPP17_BESSEL_FUNCTIONS
958
959// See formula http://dlmf.nist.gov/10.6#E1
960// j_n(a + h) ~= j_n(a) + 0.5 ( j_{n-1}(a) - j_{n+1}(a) ) h
961template <typename T, int N>
962inline Jet<T, N> cyl_bessel_j(double v, const Jet<T, N>& f) {
963 // See formula http://dlmf.nist.gov/10.6#E3
964 // j0(a + h) ~= j0(a) - j1(a) h
965 if (fpclassify(v) == FP_ZERO) {
966 return Jet<T, N>(cyl_bessel_j(0, f.a), -cyl_bessel_j(1, f.a) * f.v);
967 }
968
969 return Jet<T, N>(
970 cyl_bessel_j(v, f.a),
971 T(0.5) * (cyl_bessel_j(v - 1, f.a) - cyl_bessel_j(v + 1, f.a)) * f.v);
972}
973
974#endif // CERES_HAS_CPP17_BESSEL_FUNCTIONS
975
976// Classification and comparison functionality referencing only the scalar part
977// of a Jet. To classify the derivatives (e.g., for sanity checks), the dual
978// part should be referenced explicitly. For instance, to check whether the
979// derivatives of a Jet 'f' are reasonable, one can use
980//
981// isfinite(f.v.array()).all()
982// !isnan(f.v.array()).any()
983//
984// etc., depending on the desired semantics.
985//
986// NOTE: Floating-point classification and comparison functions and operators
987// should be used with care as no derivatives can be propagated by such
988// functions directly but only by expressions resulting from corresponding
989// conditional statements. At the same time, conditional statements can possibly
990// introduce a discontinuity in the cost function making it impossible to
991// evaluate its derivative and thus the optimization problem intractable.
992
993// Determines whether the scalar part of the Jet is finite.
Austin Schuh1d1e6ea2020-12-23 21:56:30 -0800994template <typename T, int N>
995inline bool isfinite(const Jet<T, N>& f) {
Austin Schuh3de38b02024-06-25 18:25:10 -0700996 return isfinite(f.a);
Austin Schuh70cc9552019-01-21 19:46:48 -0800997}
998
Austin Schuh3de38b02024-06-25 18:25:10 -0700999// Determines whether the scalar part of the Jet is infinite.
Austin Schuh1d1e6ea2020-12-23 21:56:30 -08001000template <typename T, int N>
1001inline bool isinf(const Jet<T, N>& f) {
Austin Schuh3de38b02024-06-25 18:25:10 -07001002 return isinf(f.a);
Austin Schuh70cc9552019-01-21 19:46:48 -08001003}
1004
Austin Schuh3de38b02024-06-25 18:25:10 -07001005// Determines whether the scalar part of the Jet is NaN.
Austin Schuh1d1e6ea2020-12-23 21:56:30 -08001006template <typename T, int N>
1007inline bool isnan(const Jet<T, N>& f) {
Austin Schuh3de38b02024-06-25 18:25:10 -07001008 return isnan(f.a);
Austin Schuh70cc9552019-01-21 19:46:48 -08001009}
1010
Austin Schuh3de38b02024-06-25 18:25:10 -07001011// Determines whether the scalar part of the Jet is neither zero, subnormal,
1012// infinite, nor NaN.
Austin Schuh1d1e6ea2020-12-23 21:56:30 -08001013template <typename T, int N>
1014inline bool isnormal(const Jet<T, N>& f) {
Austin Schuh3de38b02024-06-25 18:25:10 -07001015 return isnormal(f.a);
1016}
1017
1018// Determines whether the scalar part of the Jet f is less than the scalar
1019// part of g.
1020//
1021// NOTE: This function does NOT set any floating-point exceptions.
1022template <typename Lhs,
1023 typename Rhs,
1024 std::enable_if_t<CompatibleJetOperands_v<Lhs, Rhs>>* = nullptr>
1025inline bool isless(const Lhs& f, const Rhs& g) {
1026 using internal::AsScalar;
1027 return isless(AsScalar(f), AsScalar(g));
1028}
1029
1030// Determines whether the scalar part of the Jet f is greater than the scalar
1031// part of g.
1032//
1033// NOTE: This function does NOT set any floating-point exceptions.
1034template <typename Lhs,
1035 typename Rhs,
1036 std::enable_if_t<CompatibleJetOperands_v<Lhs, Rhs>>* = nullptr>
1037inline bool isgreater(const Lhs& f, const Rhs& g) {
1038 using internal::AsScalar;
1039 return isgreater(AsScalar(f), AsScalar(g));
1040}
1041
1042// Determines whether the scalar part of the Jet f is less than or equal to the
1043// scalar part of g.
1044//
1045// NOTE: This function does NOT set any floating-point exceptions.
1046template <typename Lhs,
1047 typename Rhs,
1048 std::enable_if_t<CompatibleJetOperands_v<Lhs, Rhs>>* = nullptr>
1049inline bool islessequal(const Lhs& f, const Rhs& g) {
1050 using internal::AsScalar;
1051 return islessequal(AsScalar(f), AsScalar(g));
1052}
1053
1054// Determines whether the scalar part of the Jet f is less than or greater than
1055// (f < g || f > g) the scalar part of g.
1056//
1057// NOTE: This function does NOT set any floating-point exceptions.
1058template <typename Lhs,
1059 typename Rhs,
1060 std::enable_if_t<CompatibleJetOperands_v<Lhs, Rhs>>* = nullptr>
1061inline bool islessgreater(const Lhs& f, const Rhs& g) {
1062 using internal::AsScalar;
1063 return islessgreater(AsScalar(f), AsScalar(g));
1064}
1065
1066// Determines whether the scalar part of the Jet f is greater than or equal to
1067// the scalar part of g.
1068//
1069// NOTE: This function does NOT set any floating-point exceptions.
1070template <typename Lhs,
1071 typename Rhs,
1072 std::enable_if_t<CompatibleJetOperands_v<Lhs, Rhs>>* = nullptr>
1073inline bool isgreaterequal(const Lhs& f, const Rhs& g) {
1074 using internal::AsScalar;
1075 return isgreaterequal(AsScalar(f), AsScalar(g));
1076}
1077
1078// Determines if either of the scalar parts of the arguments are NaN and
1079// thus cannot be ordered with respect to each other.
1080template <typename Lhs,
1081 typename Rhs,
1082 std::enable_if_t<CompatibleJetOperands_v<Lhs, Rhs>>* = nullptr>
1083inline bool isunordered(const Lhs& f, const Rhs& g) {
1084 using internal::AsScalar;
1085 return isunordered(AsScalar(f), AsScalar(g));
1086}
1087
1088// Categorize scalar part as zero, subnormal, normal, infinite, NaN, or
1089// implementation-defined.
1090template <typename T, int N>
1091inline int fpclassify(const Jet<T, N>& f) {
1092 return fpclassify(f.a);
1093}
1094
1095// Determines whether the scalar part of the argument is negative.
1096template <typename T, int N>
1097inline bool signbit(const Jet<T, N>& f) {
1098 return signbit(f.a);
Austin Schuh70cc9552019-01-21 19:46:48 -08001099}
1100
1101// Legacy functions from the pre-C++11 days.
1102template <typename T, int N>
Austin Schuh3de38b02024-06-25 18:25:10 -07001103CERES_DEPRECATED_WITH_MSG(
1104 "ceres::IsFinite will be removed in a future Ceres Solver release. Please "
1105 "use ceres::isfinite.")
Austin Schuh70cc9552019-01-21 19:46:48 -08001106inline bool IsFinite(const Jet<T, N>& f) {
1107 return isfinite(f);
1108}
1109
1110template <typename T, int N>
Austin Schuh3de38b02024-06-25 18:25:10 -07001111CERES_DEPRECATED_WITH_MSG(
1112 "ceres::IsNaN will be removed in a future Ceres Solver release. Please use "
1113 "ceres::isnan.")
Austin Schuh70cc9552019-01-21 19:46:48 -08001114inline bool IsNaN(const Jet<T, N>& f) {
1115 return isnan(f);
1116}
1117
1118template <typename T, int N>
Austin Schuh3de38b02024-06-25 18:25:10 -07001119CERES_DEPRECATED_WITH_MSG(
1120 "ceres::IsNormal will be removed in a future Ceres Solver release. Please "
1121 "use ceres::isnormal.")
Austin Schuh70cc9552019-01-21 19:46:48 -08001122inline bool IsNormal(const Jet<T, N>& f) {
1123 return isnormal(f);
1124}
1125
1126// The jet is infinite if any part of the jet is infinite.
Austin Schuh1d1e6ea2020-12-23 21:56:30 -08001127template <typename T, int N>
Austin Schuh3de38b02024-06-25 18:25:10 -07001128CERES_DEPRECATED_WITH_MSG(
1129 "ceres::IsInfinite will be removed in a future Ceres Solver release. "
1130 "Please use ceres::isinf.")
Austin Schuh1d1e6ea2020-12-23 21:56:30 -08001131inline bool IsInfinite(const Jet<T, N>& f) {
Austin Schuh70cc9552019-01-21 19:46:48 -08001132 return isinf(f);
1133}
1134
Austin Schuh3de38b02024-06-25 18:25:10 -07001135#ifdef CERES_HAS_CPP20
1136// Computes the linear interpolation a + t(b - a) between a and b at the value
1137// t. For arguments outside of the range 0 <= t <= 1, the values are
1138// extrapolated.
1139//
1140// Differentiating lerp(a, b, t) with respect to a, b, and t gives:
1141//
1142// d/da lerp(a, b, t) = 1 - t
1143// d/db lerp(a, b, t) = t
1144// d/dt lerp(a, b, t) = b - a
1145//
1146// with the dual representation given by
1147//
1148// lerp(a + da, b + db, t + dt)
1149// ~= lerp(a, b, t) + (1 - t) da + t db + (b - a) dt .
1150template <typename T, int N>
1151inline Jet<T, N> lerp(const Jet<T, N>& a,
1152 const Jet<T, N>& b,
1153 const Jet<T, N>& t) {
1154 return Jet<T, N>{lerp(a.a, b.a, t.a),
1155 (T(1) - t.a) * a.v + t.a * b.v + (b.a - a.a) * t.v};
1156}
1157
1158// Computes the midpoint a + (b - a) / 2.
1159//
1160// Differentiating midpoint(a, b) with respect to a and b gives:
1161//
1162// d/da midpoint(a, b) = 1/2
1163// d/db midpoint(a, b) = 1/2
1164//
1165// with the dual representation given by
1166//
1167// midpoint(a + da, b + db) ~= midpoint(a, b) + (da + db) / 2 .
1168template <typename T, int N>
1169inline Jet<T, N> midpoint(const Jet<T, N>& a, const Jet<T, N>& b) {
1170 Jet<T, N> result{midpoint(a.a, b.a)};
1171 // To avoid overflow in the differential, compute
1172 // (da + db) / 2 using midpoint.
1173 for (int i = 0; i < N; ++i) {
1174 result.v[i] = midpoint(a.v[i], b.v[i]);
1175 }
1176 return result;
1177}
1178#endif // defined(CERES_HAS_CPP20)
1179
Austin Schuh70cc9552019-01-21 19:46:48 -08001180// atan2(b + db, a + da) ~= atan2(b, a) + (- b da + a db) / (a^2 + b^2)
1181//
1182// In words: the rate of change of theta is 1/r times the rate of
1183// change of (x, y) in the positive angular direction.
Austin Schuh1d1e6ea2020-12-23 21:56:30 -08001184template <typename T, int N>
1185inline Jet<T, N> atan2(const Jet<T, N>& g, const Jet<T, N>& f) {
Austin Schuh70cc9552019-01-21 19:46:48 -08001186 // Note order of arguments:
1187 //
1188 // f = a + da
1189 // g = b + db
1190
1191 T const tmp = T(1.0) / (f.a * f.a + g.a * g.a);
Austin Schuh1d1e6ea2020-12-23 21:56:30 -08001192 return Jet<T, N>(atan2(g.a, f.a), tmp * (-g.a * f.v + f.a * g.v));
Austin Schuh70cc9552019-01-21 19:46:48 -08001193}
1194
Austin Schuh3de38b02024-06-25 18:25:10 -07001195// Computes the square x^2 of a real number x (not the Euclidean L^2 norm as
1196// the name might suggest).
1197//
1198// NOTE: While std::norm is primarily intended for computing the squared
1199// magnitude of a std::complex<> number, the current Jet implementation does not
1200// support mixing a scalar T in its real part and std::complex<T> and in the
1201// infinitesimal. Mixed Jet support is necessary for the type decay from
1202// std::complex<T> to T (the squared magnitude of a complex number is always
1203// real) performed by std::norm.
1204//
1205// norm(x + h) ~= norm(x) + 2x h
1206template <typename T, int N>
1207inline Jet<T, N> norm(const Jet<T, N>& f) {
1208 return Jet<T, N>(norm(f.a), T(2) * f.a * f.v);
1209}
1210
Austin Schuh70cc9552019-01-21 19:46:48 -08001211// pow -- base is a differentiable function, exponent is a constant.
1212// (a+da)^p ~= a^p + p*a^(p-1) da
Austin Schuh1d1e6ea2020-12-23 21:56:30 -08001213template <typename T, int N>
1214inline Jet<T, N> pow(const Jet<T, N>& f, double g) {
Austin Schuh70cc9552019-01-21 19:46:48 -08001215 T const tmp = g * pow(f.a, g - T(1.0));
1216 return Jet<T, N>(pow(f.a, g), tmp * f.v);
1217}
1218
1219// pow -- base is a constant, exponent is a differentiable function.
1220// We have various special cases, see the comment for pow(Jet, Jet) for
1221// analysis:
1222//
1223// 1. For f > 0 we have: (f)^(g + dg) ~= f^g + f^g log(f) dg
1224//
1225// 2. For f == 0 and g > 0 we have: (f)^(g + dg) ~= f^g
1226//
1227// 3. For f < 0 and integer g we have: (f)^(g + dg) ~= f^g but if dg
1228// != 0, the derivatives are not defined and we return NaN.
1229
Austin Schuh1d1e6ea2020-12-23 21:56:30 -08001230template <typename T, int N>
1231inline Jet<T, N> pow(T f, const Jet<T, N>& g) {
1232 Jet<T, N> result;
1233
Austin Schuh3de38b02024-06-25 18:25:10 -07001234 if (fpclassify(f) == FP_ZERO && g > 0) {
Austin Schuh70cc9552019-01-21 19:46:48 -08001235 // Handle case 2.
Austin Schuh1d1e6ea2020-12-23 21:56:30 -08001236 result = Jet<T, N>(T(0.0));
1237 } else {
Austin Schuh3de38b02024-06-25 18:25:10 -07001238 if (f < 0 && g == floor(g.a)) { // Handle case 3.
Austin Schuh1d1e6ea2020-12-23 21:56:30 -08001239 result = Jet<T, N>(pow(f, g.a));
1240 for (int i = 0; i < N; i++) {
Austin Schuh3de38b02024-06-25 18:25:10 -07001241 if (fpclassify(g.v[i]) != FP_ZERO) {
Austin Schuh1d1e6ea2020-12-23 21:56:30 -08001242 // Return a NaN when g.v != 0.
1243 result.v[i] = std::numeric_limits<T>::quiet_NaN();
1244 }
Austin Schuh70cc9552019-01-21 19:46:48 -08001245 }
Austin Schuh1d1e6ea2020-12-23 21:56:30 -08001246 } else {
1247 // Handle case 1.
1248 T const tmp = pow(f, g.a);
1249 result = Jet<T, N>(tmp, log(f) * tmp * g.v);
Austin Schuh70cc9552019-01-21 19:46:48 -08001250 }
Austin Schuh70cc9552019-01-21 19:46:48 -08001251 }
Austin Schuh1d1e6ea2020-12-23 21:56:30 -08001252
1253 return result;
Austin Schuh70cc9552019-01-21 19:46:48 -08001254}
1255
1256// pow -- both base and exponent are differentiable functions. This has a
1257// variety of special cases that require careful handling.
1258//
1259// 1. For f > 0:
1260// (f + df)^(g + dg) ~= f^g + f^(g - 1) * (g * df + f * log(f) * dg)
1261// The numerical evaluation of f * log(f) for f > 0 is well behaved, even for
1262// extremely small values (e.g. 1e-99).
1263//
1264// 2. For f == 0 and g > 1: (f + df)^(g + dg) ~= 0
1265// This cases is needed because log(0) can not be evaluated in the f > 0
1266// expression. However the function f*log(f) is well behaved around f == 0
1267// and its limit as f-->0 is zero.
1268//
1269// 3. For f == 0 and g == 1: (f + df)^(g + dg) ~= 0 + df
1270//
1271// 4. For f == 0 and 0 < g < 1: The value is finite but the derivatives are not.
1272//
1273// 5. For f == 0 and g < 0: The value and derivatives of f^g are not finite.
1274//
1275// 6. For f == 0 and g == 0: The C standard incorrectly defines 0^0 to be 1
1276// "because there are applications that can exploit this definition". We
1277// (arbitrarily) decree that derivatives here will be nonfinite, since that
1278// is consistent with the behavior for f == 0, g < 0 and 0 < g < 1.
1279// Practically any definition could have been justified because mathematical
1280// consistency has been lost at this point.
1281//
1282// 7. For f < 0, g integer, dg == 0: (f + df)^(g + dg) ~= f^g + g * f^(g - 1) df
1283// This is equivalent to the case where f is a differentiable function and g
1284// is a constant (to first order).
1285//
1286// 8. For f < 0, g integer, dg != 0: The value is finite but the derivatives are
1287// not, because any change in the value of g moves us away from the point
1288// with a real-valued answer into the region with complex-valued answers.
1289//
1290// 9. For f < 0, g noninteger: The value and derivatives of f^g are not finite.
1291
Austin Schuh1d1e6ea2020-12-23 21:56:30 -08001292template <typename T, int N>
1293inline Jet<T, N> pow(const Jet<T, N>& f, const Jet<T, N>& g) {
1294 Jet<T, N> result;
1295
Austin Schuh3de38b02024-06-25 18:25:10 -07001296 if (fpclassify(f) == FP_ZERO && g >= 1) {
Austin Schuh70cc9552019-01-21 19:46:48 -08001297 // Handle cases 2 and 3.
Austin Schuh3de38b02024-06-25 18:25:10 -07001298 if (g > 1) {
Austin Schuh1d1e6ea2020-12-23 21:56:30 -08001299 result = Jet<T, N>(T(0.0));
1300 } else {
1301 result = f;
Austin Schuh70cc9552019-01-21 19:46:48 -08001302 }
Austin Schuh1d1e6ea2020-12-23 21:56:30 -08001303
1304 } else {
Austin Schuh3de38b02024-06-25 18:25:10 -07001305 if (f < 0 && g == floor(g.a)) {
Austin Schuh1d1e6ea2020-12-23 21:56:30 -08001306 // Handle cases 7 and 8.
1307 T const tmp = g.a * pow(f.a, g.a - T(1.0));
1308 result = Jet<T, N>(pow(f.a, g.a), tmp * f.v);
1309 for (int i = 0; i < N; i++) {
Austin Schuh3de38b02024-06-25 18:25:10 -07001310 if (fpclassify(g.v[i]) != FP_ZERO) {
Austin Schuh1d1e6ea2020-12-23 21:56:30 -08001311 // Return a NaN when g.v != 0.
1312 result.v[i] = T(std::numeric_limits<double>::quiet_NaN());
1313 }
Austin Schuh70cc9552019-01-21 19:46:48 -08001314 }
Austin Schuh1d1e6ea2020-12-23 21:56:30 -08001315 } else {
1316 // Handle the remaining cases. For cases 4,5,6,9 we allow the log()
1317 // function to generate -HUGE_VAL or NaN, since those cases result in a
1318 // nonfinite derivative.
1319 T const tmp1 = pow(f.a, g.a);
1320 T const tmp2 = g.a * pow(f.a, g.a - T(1.0));
1321 T const tmp3 = tmp1 * log(f.a);
1322 result = Jet<T, N>(tmp1, tmp2 * f.v + tmp3 * g.v);
Austin Schuh70cc9552019-01-21 19:46:48 -08001323 }
Austin Schuh70cc9552019-01-21 19:46:48 -08001324 }
Austin Schuh1d1e6ea2020-12-23 21:56:30 -08001325
1326 return result;
Austin Schuh70cc9552019-01-21 19:46:48 -08001327}
1328
1329// Note: This has to be in the ceres namespace for argument dependent lookup to
1330// function correctly. Otherwise statements like CHECK_LE(x, 2.0) fail with
1331// strange compile errors.
1332template <typename T, int N>
Austin Schuh1d1e6ea2020-12-23 21:56:30 -08001333inline std::ostream& operator<<(std::ostream& s, const Jet<T, N>& z) {
Austin Schuh70cc9552019-01-21 19:46:48 -08001334 s << "[" << z.a << " ; ";
1335 for (int i = 0; i < N; ++i) {
1336 s << z.v[i];
1337 if (i != N - 1) {
1338 s << ", ";
1339 }
1340 }
1341 s << "]";
1342 return s;
1343}
Austin Schuh70cc9552019-01-21 19:46:48 -08001344} // namespace ceres
1345
Austin Schuh1d1e6ea2020-12-23 21:56:30 -08001346namespace std {
1347template <typename T, int N>
1348struct numeric_limits<ceres::Jet<T, N>> {
1349 static constexpr bool is_specialized = true;
1350 static constexpr bool is_signed = std::numeric_limits<T>::is_signed;
1351 static constexpr bool is_integer = std::numeric_limits<T>::is_integer;
1352 static constexpr bool is_exact = std::numeric_limits<T>::is_exact;
1353 static constexpr bool has_infinity = std::numeric_limits<T>::has_infinity;
1354 static constexpr bool has_quiet_NaN = std::numeric_limits<T>::has_quiet_NaN;
1355 static constexpr bool has_signaling_NaN =
1356 std::numeric_limits<T>::has_signaling_NaN;
1357 static constexpr bool is_iec559 = std::numeric_limits<T>::is_iec559;
1358 static constexpr bool is_bounded = std::numeric_limits<T>::is_bounded;
1359 static constexpr bool is_modulo = std::numeric_limits<T>::is_modulo;
1360
Austin Schuh3de38b02024-06-25 18:25:10 -07001361 // has_denorm (and has_denorm_loss, not defined for Jet) has been deprecated
1362 // in C++23. However, without an intent to remove the declaration. Disable
1363 // deprecation warnings temporarily just for the corresponding symbols.
1364 CERES_DISABLE_DEPRECATED_WARNING
Austin Schuh1d1e6ea2020-12-23 21:56:30 -08001365 static constexpr std::float_denorm_style has_denorm =
1366 std::numeric_limits<T>::has_denorm;
Austin Schuh3de38b02024-06-25 18:25:10 -07001367 CERES_RESTORE_DEPRECATED_WARNING
Austin Schuh1d1e6ea2020-12-23 21:56:30 -08001368 static constexpr std::float_round_style round_style =
1369 std::numeric_limits<T>::round_style;
1370
1371 static constexpr int digits = std::numeric_limits<T>::digits;
1372 static constexpr int digits10 = std::numeric_limits<T>::digits10;
1373 static constexpr int max_digits10 = std::numeric_limits<T>::max_digits10;
1374 static constexpr int radix = std::numeric_limits<T>::radix;
1375 static constexpr int min_exponent = std::numeric_limits<T>::min_exponent;
1376 static constexpr int min_exponent10 = std::numeric_limits<T>::max_exponent10;
1377 static constexpr int max_exponent = std::numeric_limits<T>::max_exponent;
1378 static constexpr int max_exponent10 = std::numeric_limits<T>::max_exponent10;
1379 static constexpr bool traps = std::numeric_limits<T>::traps;
1380 static constexpr bool tinyness_before =
1381 std::numeric_limits<T>::tinyness_before;
1382
Austin Schuh3de38b02024-06-25 18:25:10 -07001383 static constexpr ceres::Jet<T, N> min
1384 CERES_PREVENT_MACRO_SUBSTITUTION() noexcept {
1385 return ceres::Jet<T, N>((std::numeric_limits<T>::min)());
Austin Schuh1d1e6ea2020-12-23 21:56:30 -08001386 }
1387 static constexpr ceres::Jet<T, N> lowest() noexcept {
1388 return ceres::Jet<T, N>(std::numeric_limits<T>::lowest());
1389 }
1390 static constexpr ceres::Jet<T, N> epsilon() noexcept {
1391 return ceres::Jet<T, N>(std::numeric_limits<T>::epsilon());
1392 }
1393 static constexpr ceres::Jet<T, N> round_error() noexcept {
1394 return ceres::Jet<T, N>(std::numeric_limits<T>::round_error());
1395 }
1396 static constexpr ceres::Jet<T, N> infinity() noexcept {
1397 return ceres::Jet<T, N>(std::numeric_limits<T>::infinity());
1398 }
1399 static constexpr ceres::Jet<T, N> quiet_NaN() noexcept {
1400 return ceres::Jet<T, N>(std::numeric_limits<T>::quiet_NaN());
1401 }
1402 static constexpr ceres::Jet<T, N> signaling_NaN() noexcept {
1403 return ceres::Jet<T, N>(std::numeric_limits<T>::signaling_NaN());
1404 }
1405 static constexpr ceres::Jet<T, N> denorm_min() noexcept {
1406 return ceres::Jet<T, N>(std::numeric_limits<T>::denorm_min());
1407 }
1408
Austin Schuh3de38b02024-06-25 18:25:10 -07001409 static constexpr ceres::Jet<T, N> max
1410 CERES_PREVENT_MACRO_SUBSTITUTION() noexcept {
1411 return ceres::Jet<T, N>((std::numeric_limits<T>::max)());
Austin Schuh1d1e6ea2020-12-23 21:56:30 -08001412 }
1413};
1414
1415} // namespace std
1416
Austin Schuh70cc9552019-01-21 19:46:48 -08001417namespace Eigen {
1418
1419// Creating a specialization of NumTraits enables placing Jet objects inside
1420// Eigen arrays, getting all the goodness of Eigen combined with autodiff.
Austin Schuh1d1e6ea2020-12-23 21:56:30 -08001421template <typename T, int N>
Austin Schuh70cc9552019-01-21 19:46:48 -08001422struct NumTraits<ceres::Jet<T, N>> {
Austin Schuh3de38b02024-06-25 18:25:10 -07001423 using Real = ceres::Jet<T, N>;
1424 using NonInteger = ceres::Jet<T, N>;
1425 using Nested = ceres::Jet<T, N>;
1426 using Literal = ceres::Jet<T, N>;
Austin Schuh70cc9552019-01-21 19:46:48 -08001427
1428 static typename ceres::Jet<T, N> dummy_precision() {
1429 return ceres::Jet<T, N>(1e-12);
1430 }
1431
1432 static inline Real epsilon() {
1433 return Real(std::numeric_limits<T>::epsilon());
1434 }
1435
1436 static inline int digits10() { return NumTraits<T>::digits10(); }
Austin Schuh3de38b02024-06-25 18:25:10 -07001437 static inline int max_digits10() { return NumTraits<T>::max_digits10(); }
Austin Schuh70cc9552019-01-21 19:46:48 -08001438
1439 enum {
1440 IsComplex = 0,
1441 IsInteger = 0,
1442 IsSigned,
1443 ReadCost = 1,
1444 AddCost = 1,
1445 // For Jet types, multiplication is more expensive than addition.
1446 MulCost = 3,
1447 HasFloatingPoint = 1,
1448 RequireInitialization = 1
1449 };
1450
Austin Schuh1d1e6ea2020-12-23 21:56:30 -08001451 template <bool Vectorized>
Austin Schuh70cc9552019-01-21 19:46:48 -08001452 struct Div {
1453 enum {
1454#if defined(EIGEN_VECTORIZE_AVX)
1455 AVX = true,
1456#else
1457 AVX = false,
1458#endif
1459
1460 // Assuming that for Jets, division is as expensive as
1461 // multiplication.
1462 Cost = 3
1463 };
1464 };
1465
Austin Schuh3de38b02024-06-25 18:25:10 -07001466 static inline Real highest() { return Real((std::numeric_limits<T>::max)()); }
1467 static inline Real lowest() { return Real(-(std::numeric_limits<T>::max)()); }
Austin Schuh70cc9552019-01-21 19:46:48 -08001468};
1469
Austin Schuh70cc9552019-01-21 19:46:48 -08001470// Specifying the return type of binary operations between Jets and scalar types
1471// allows you to perform matrix/array operations with Eigen matrices and arrays
1472// such as addition, subtraction, multiplication, and division where one Eigen
1473// matrix/array is of type Jet and the other is a scalar type. This improves
1474// performance by using the optimized scalar-to-Jet binary operations but
1475// is only available on Eigen versions >= 3.3
1476template <typename BinaryOp, typename T, int N>
1477struct ScalarBinaryOpTraits<ceres::Jet<T, N>, T, BinaryOp> {
Austin Schuh3de38b02024-06-25 18:25:10 -07001478 using ReturnType = ceres::Jet<T, N>;
Austin Schuh70cc9552019-01-21 19:46:48 -08001479};
1480template <typename BinaryOp, typename T, int N>
1481struct ScalarBinaryOpTraits<T, ceres::Jet<T, N>, BinaryOp> {
Austin Schuh3de38b02024-06-25 18:25:10 -07001482 using ReturnType = ceres::Jet<T, N>;
Austin Schuh70cc9552019-01-21 19:46:48 -08001483};
Austin Schuh70cc9552019-01-21 19:46:48 -08001484
1485} // namespace Eigen
1486
1487#endif // CERES_PUBLIC_JET_H_