Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-16 09:54:37

0001 //           Copyright Matthew Pulver 2018 - 2019.
0002 // Distributed under the Boost Software License, Version 1.0.
0003 //      (See accompanying file LICENSE_1_0.txt or copy at
0004 //           https://www.boost.org/LICENSE_1_0.txt)
0005 
0006 #ifndef BOOST_MATH_DIFFERENTIATION_AUTODIFF_HPP
0007 #define BOOST_MATH_DIFFERENTIATION_AUTODIFF_HPP
0008 
0009 #include <boost/cstdfloat.hpp>
0010 #include <boost/math/constants/constants.hpp>
0011 #include <boost/math/special_functions/trunc.hpp>
0012 #include <boost/math/special_functions/round.hpp>
0013 #include <boost/math/special_functions/acosh.hpp>
0014 #include <boost/math/special_functions/asinh.hpp>
0015 #include <boost/math/special_functions/atanh.hpp>
0016 #include <boost/math/special_functions/digamma.hpp>
0017 #include <boost/math/special_functions/polygamma.hpp>
0018 #include <boost/math/special_functions/erf.hpp>
0019 #include <boost/math/special_functions/lambert_w.hpp>
0020 #include <boost/math/tools/config.hpp>
0021 #include <boost/math/tools/promotion.hpp>
0022 
0023 #include <algorithm>
0024 #include <array>
0025 #include <cmath>
0026 #include <functional>
0027 #include <limits>
0028 #include <numeric>
0029 #include <ostream>
0030 #include <tuple>
0031 #include <type_traits>
0032 
0033 namespace boost {
0034 namespace math {
0035 namespace differentiation {
0036 // Automatic Differentiation v1
0037 inline namespace autodiff_v1 {
0038 namespace detail {
0039 
0040 template <typename RealType, typename... RealTypes>
0041 struct promote_args_n {
0042   using type = typename tools::promote_args<RealType, typename promote_args_n<RealTypes...>::type>::type;
0043 };
0044 
0045 template <typename RealType>
0046 struct promote_args_n<RealType> {
0047   using type = typename tools::promote_arg<RealType>::type;
0048 };
0049 
0050 }  // namespace detail
0051 
0052 template <typename RealType, typename... RealTypes>
0053 using promote = typename detail::promote_args_n<RealType, RealTypes...>::type;
0054 
0055 namespace detail {
0056 
0057 template <typename RealType, size_t Order>
0058 class fvar;
0059 
0060 template <typename T>
0061 struct is_fvar_impl : std::false_type {};
0062 
0063 template <typename RealType, size_t Order>
0064 struct is_fvar_impl<fvar<RealType, Order>> : std::true_type {};
0065 
0066 template <typename T>
0067 using is_fvar = is_fvar_impl<typename std::decay<T>::type>;
0068 
0069 template <typename RealType, size_t Order, size_t... Orders>
0070 struct nest_fvar {
0071   using type = fvar<typename nest_fvar<RealType, Orders...>::type, Order>;
0072 };
0073 
0074 template <typename RealType, size_t Order>
0075 struct nest_fvar<RealType, Order> {
0076   using type = fvar<RealType, Order>;
0077 };
0078 
0079 template <typename>
0080 struct get_depth_impl : std::integral_constant<size_t, 0> {};
0081 
0082 template <typename RealType, size_t Order>
0083 struct get_depth_impl<fvar<RealType, Order>>
0084     : std::integral_constant<size_t, get_depth_impl<RealType>::value + 1> {};
0085 
0086 template <typename T>
0087 using get_depth = get_depth_impl<typename std::decay<T>::type>;
0088 
0089 template <typename>
0090 struct get_order_sum_t : std::integral_constant<size_t, 0> {};
0091 
0092 template <typename RealType, size_t Order>
0093 struct get_order_sum_t<fvar<RealType, Order>>
0094     : std::integral_constant<size_t, get_order_sum_t<RealType>::value + Order> {};
0095 
0096 template <typename T>
0097 using get_order_sum = get_order_sum_t<typename std::decay<T>::type>;
0098 
0099 template <typename RealType>
0100 struct get_root_type {
0101   using type = RealType;
0102 };
0103 
0104 template <typename RealType, size_t Order>
0105 struct get_root_type<fvar<RealType, Order>> {
0106   using type = typename get_root_type<RealType>::type;
0107 };
0108 
0109 template <typename RealType, size_t Depth>
0110 struct type_at {
0111   using type = RealType;
0112 };
0113 
0114 template <typename RealType, size_t Order, size_t Depth>
0115 struct type_at<fvar<RealType, Order>, Depth> {
0116   using type = typename std::conditional<Depth == 0,
0117                                          fvar<RealType, Order>,
0118                                          typename type_at<RealType, Depth - 1>::type>::type;
0119 };
0120 
0121 template <typename RealType, size_t Depth>
0122 using get_type_at = typename type_at<RealType, Depth>::type;
0123 
0124 // Satisfies Boost's Conceptual Requirements for Real Number Types.
0125 // https://www.boost.org/libs/math/doc/html/math_toolkit/real_concepts.html
0126 template <typename RealType, size_t Order>
0127 class fvar {
0128  protected:
0129   std::array<RealType, Order + 1> v;
0130 
0131  public:
0132   using root_type = typename get_root_type<RealType>::type;  // RealType in the root fvar<RealType,Order>.
0133 
0134   fvar() = default;
0135 
0136   // Initialize a variable or constant.
0137   fvar(root_type const&, bool const is_variable);
0138 
0139   // RealType(cr) | RealType | RealType is copy constructible.
0140   fvar(fvar const&) = default;
0141 
0142   // Be aware of implicit casting from one fvar<> type to another by this copy constructor.
0143   template <typename RealType2, size_t Order2>
0144   fvar(fvar<RealType2, Order2> const&);
0145 
0146   // RealType(ca) | RealType | RealType is copy constructible from the arithmetic types.
0147   explicit fvar(root_type const&);  // Initialize a constant. (No epsilon terms.)
0148 
0149   template <typename RealType2>
0150   fvar(RealType2 const& ca);  // Supports any RealType2 for which static_cast<root_type>(ca) compiles.
0151 
0152   // r = cr | RealType& | Assignment operator.
0153   fvar& operator=(fvar const&) = default;
0154 
0155   // r = ca | RealType& | Assignment operator from the arithmetic types.
0156   // Handled by constructor that takes a single parameter of generic type.
0157   // fvar& operator=(root_type const&); // Set a constant.
0158 
0159   // r += cr | RealType& | Adds cr to r.
0160   template <typename RealType2, size_t Order2>
0161   fvar& operator+=(fvar<RealType2, Order2> const&);
0162 
0163   // r += ca | RealType& | Adds ar to r.
0164   fvar& operator+=(root_type const&);
0165 
0166   // r -= cr | RealType& | Subtracts cr from r.
0167   template <typename RealType2, size_t Order2>
0168   fvar& operator-=(fvar<RealType2, Order2> const&);
0169 
0170   // r -= ca | RealType& | Subtracts ca from r.
0171   fvar& operator-=(root_type const&);
0172 
0173   // r *= cr | RealType& | Multiplies r by cr.
0174   template <typename RealType2, size_t Order2>
0175   fvar& operator*=(fvar<RealType2, Order2> const&);
0176 
0177   // r *= ca | RealType& | Multiplies r by ca.
0178   fvar& operator*=(root_type const&);
0179 
0180   // r /= cr | RealType& | Divides r by cr.
0181   template <typename RealType2, size_t Order2>
0182   fvar& operator/=(fvar<RealType2, Order2> const&);
0183 
0184   // r /= ca | RealType& | Divides r by ca.
0185   fvar& operator/=(root_type const&);
0186 
0187   // -r | RealType | Unary Negation.
0188   fvar operator-() const;
0189 
0190   // +r | RealType& | Identity Operation.
0191   fvar const& operator+() const;
0192 
0193   // cr + cr2 | RealType | Binary Addition
0194   template <typename RealType2, size_t Order2>
0195   promote<fvar, fvar<RealType2, Order2>> operator+(fvar<RealType2, Order2> const&) const;
0196 
0197   // cr + ca | RealType | Binary Addition
0198   fvar operator+(root_type const&) const;
0199 
0200   // ca + cr | RealType | Binary Addition
0201   template <typename RealType2, size_t Order2>
0202   friend fvar<RealType2, Order2> operator+(typename fvar<RealType2, Order2>::root_type const&,
0203                                            fvar<RealType2, Order2> const&);
0204 
0205   // cr - cr2 | RealType | Binary Subtraction
0206   template <typename RealType2, size_t Order2>
0207   promote<fvar, fvar<RealType2, Order2>> operator-(fvar<RealType2, Order2> const&) const;
0208 
0209   // cr - ca | RealType | Binary Subtraction
0210   fvar operator-(root_type const&) const;
0211 
0212   // ca - cr | RealType | Binary Subtraction
0213   template <typename RealType2, size_t Order2>
0214   friend fvar<RealType2, Order2> operator-(typename fvar<RealType2, Order2>::root_type const&,
0215                                            fvar<RealType2, Order2> const&);
0216 
0217   // cr * cr2 | RealType | Binary Multiplication
0218   template <typename RealType2, size_t Order2>
0219   promote<fvar, fvar<RealType2, Order2>> operator*(fvar<RealType2, Order2> const&)const;
0220 
0221   // cr * ca | RealType | Binary Multiplication
0222   fvar operator*(root_type const&)const;
0223 
0224   // ca * cr | RealType | Binary Multiplication
0225   template <typename RealType2, size_t Order2>
0226   friend fvar<RealType2, Order2> operator*(typename fvar<RealType2, Order2>::root_type const&,
0227                                            fvar<RealType2, Order2> const&);
0228 
0229   // cr / cr2 | RealType | Binary Subtraction
0230   template <typename RealType2, size_t Order2>
0231   promote<fvar, fvar<RealType2, Order2>> operator/(fvar<RealType2, Order2> const&) const;
0232 
0233   // cr / ca | RealType | Binary Subtraction
0234   fvar operator/(root_type const&) const;
0235 
0236   // ca / cr | RealType | Binary Subtraction
0237   template <typename RealType2, size_t Order2>
0238   friend fvar<RealType2, Order2> operator/(typename fvar<RealType2, Order2>::root_type const&,
0239                                            fvar<RealType2, Order2> const&);
0240 
0241   // For all comparison overloads, only the root term is compared.
0242 
0243   // cr == cr2 | bool | Equality Comparison
0244   template <typename RealType2, size_t Order2>
0245   bool operator==(fvar<RealType2, Order2> const&) const;
0246 
0247   // cr == ca | bool | Equality Comparison
0248   bool operator==(root_type const&) const;
0249 
0250   // ca == cr | bool | Equality Comparison
0251   template <typename RealType2, size_t Order2>
0252   friend bool operator==(typename fvar<RealType2, Order2>::root_type const&, fvar<RealType2, Order2> const&);
0253 
0254   // cr != cr2 | bool | Inequality Comparison
0255   template <typename RealType2, size_t Order2>
0256   bool operator!=(fvar<RealType2, Order2> const&) const;
0257 
0258   // cr != ca | bool | Inequality Comparison
0259   bool operator!=(root_type const&) const;
0260 
0261   // ca != cr | bool | Inequality Comparison
0262   template <typename RealType2, size_t Order2>
0263   friend bool operator!=(typename fvar<RealType2, Order2>::root_type const&, fvar<RealType2, Order2> const&);
0264 
0265   // cr <= cr2 | bool | Less than equal to.
0266   template <typename RealType2, size_t Order2>
0267   bool operator<=(fvar<RealType2, Order2> const&) const;
0268 
0269   // cr <= ca | bool | Less than equal to.
0270   bool operator<=(root_type const&) const;
0271 
0272   // ca <= cr | bool | Less than equal to.
0273   template <typename RealType2, size_t Order2>
0274   friend bool operator<=(typename fvar<RealType2, Order2>::root_type const&, fvar<RealType2, Order2> const&);
0275 
0276   // cr >= cr2 | bool | Greater than equal to.
0277   template <typename RealType2, size_t Order2>
0278   bool operator>=(fvar<RealType2, Order2> const&) const;
0279 
0280   // cr >= ca | bool | Greater than equal to.
0281   bool operator>=(root_type const&) const;
0282 
0283   // ca >= cr | bool | Greater than equal to.
0284   template <typename RealType2, size_t Order2>
0285   friend bool operator>=(typename fvar<RealType2, Order2>::root_type const&, fvar<RealType2, Order2> const&);
0286 
0287   // cr < cr2 | bool | Less than comparison.
0288   template <typename RealType2, size_t Order2>
0289   bool operator<(fvar<RealType2, Order2> const&) const;
0290 
0291   // cr < ca | bool | Less than comparison.
0292   bool operator<(root_type const&) const;
0293 
0294   // ca < cr | bool | Less than comparison.
0295   template <typename RealType2, size_t Order2>
0296   friend bool operator<(typename fvar<RealType2, Order2>::root_type const&, fvar<RealType2, Order2> const&);
0297 
0298   // cr > cr2 | bool | Greater than comparison.
0299   template <typename RealType2, size_t Order2>
0300   bool operator>(fvar<RealType2, Order2> const&) const;
0301 
0302   // cr > ca | bool | Greater than comparison.
0303   bool operator>(root_type const&) const;
0304 
0305   // ca > cr | bool | Greater than comparison.
0306   template <typename RealType2, size_t Order2>
0307   friend bool operator>(typename fvar<RealType2, Order2>::root_type const&, fvar<RealType2, Order2> const&);
0308 
0309   // Will throw std::out_of_range if Order < order.
0310   template <typename... Orders>
0311   get_type_at<RealType, sizeof...(Orders)> at(size_t order, Orders... orders) const;
0312 
0313   template <typename... Orders>
0314   get_type_at<fvar, sizeof...(Orders)> derivative(Orders... orders) const;
0315 
0316   const RealType& operator[](size_t) const;
0317 
0318   fvar inverse() const;  // Multiplicative inverse.
0319 
0320   fvar& negate();  // Negate and return reference to *this.
0321 
0322   static constexpr size_t depth = get_depth<fvar>::value;  // Number of nested std::array<RealType,Order>.
0323 
0324   static constexpr size_t order_sum = get_order_sum<fvar>::value;
0325 
0326   explicit operator root_type() const;  // Must be explicit, otherwise overloaded operators are ambiguous.
0327 
0328   template <typename T, typename = typename std::enable_if<std::is_arithmetic<typename std::decay<T>::type>::value>>
0329   explicit operator T() const;  // Must be explicit; multiprecision has trouble without the std::enable_if
0330 
0331   fvar& set_root(root_type const&);
0332 
0333   // Apply coefficients using horner method.
0334   template <typename Func, typename Fvar, typename... Fvars>
0335   promote<fvar<RealType, Order>, Fvar, Fvars...> apply_coefficients(size_t const order,
0336                                                                     Func const& f,
0337                                                                     Fvar const& cr,
0338                                                                     Fvars&&... fvars) const;
0339 
0340   template <typename Func>
0341   fvar apply_coefficients(size_t const order, Func const& f) const;
0342 
0343   // Use when function returns derivative(i)/factorial(i) and may have some infinite derivatives.
0344   template <typename Func, typename Fvar, typename... Fvars>
0345   promote<fvar<RealType, Order>, Fvar, Fvars...> apply_coefficients_nonhorner(size_t const order,
0346                                                                               Func const& f,
0347                                                                               Fvar const& cr,
0348                                                                               Fvars&&... fvars) const;
0349 
0350   template <typename Func>
0351   fvar apply_coefficients_nonhorner(size_t const order, Func const& f) const;
0352 
0353   // Apply derivatives using horner method.
0354   template <typename Func, typename Fvar, typename... Fvars>
0355   promote<fvar<RealType, Order>, Fvar, Fvars...> apply_derivatives(size_t const order,
0356                                                                    Func const& f,
0357                                                                    Fvar const& cr,
0358                                                                    Fvars&&... fvars) const;
0359 
0360   template <typename Func>
0361   fvar apply_derivatives(size_t const order, Func const& f) const;
0362 
0363   // Use when function returns derivative(i) and may have some infinite derivatives.
0364   template <typename Func, typename Fvar, typename... Fvars>
0365   promote<fvar<RealType, Order>, Fvar, Fvars...> apply_derivatives_nonhorner(size_t const order,
0366                                                                              Func const& f,
0367                                                                              Fvar const& cr,
0368                                                                              Fvars&&... fvars) const;
0369 
0370   template <typename Func>
0371   fvar apply_derivatives_nonhorner(size_t const order, Func const& f) const;
0372 
0373  private:
0374   RealType epsilon_inner_product(size_t z0,
0375                                  size_t isum0,
0376                                  size_t m0,
0377                                  fvar const& cr,
0378                                  size_t z1,
0379                                  size_t isum1,
0380                                  size_t m1,
0381                                  size_t j) const;
0382 
0383   fvar epsilon_multiply(size_t z0, size_t isum0, fvar const& cr, size_t z1, size_t isum1) const;
0384 
0385   fvar epsilon_multiply(size_t z0, size_t isum0, root_type const& ca) const;
0386 
0387   fvar inverse_apply() const;
0388 
0389   fvar& multiply_assign_by_root_type(bool is_root, root_type const&);
0390 
0391   template <typename RealType2, size_t Orders2>
0392   friend class fvar;
0393 
0394   template <typename RealType2, size_t Order2>
0395   friend std::ostream& operator<<(std::ostream&, fvar<RealType2, Order2> const&);
0396 
0397   // C++11 Compatibility
0398 #ifdef BOOST_MATH_NO_CXX17_IF_CONSTEXPR
0399   template <typename RootType>
0400   void fvar_cpp11(std::true_type, RootType const& ca, bool const is_variable);
0401 
0402   template <typename RootType>
0403   void fvar_cpp11(std::false_type, RootType const& ca, bool const is_variable);
0404 
0405   template <typename... Orders>
0406   get_type_at<RealType, sizeof...(Orders)> at_cpp11(std::true_type, size_t order, Orders... orders) const;
0407 
0408   template <typename... Orders>
0409   get_type_at<RealType, sizeof...(Orders)> at_cpp11(std::false_type, size_t order, Orders... orders) const;
0410 
0411   template <typename SizeType>
0412   fvar epsilon_multiply_cpp11(std::true_type,
0413                               SizeType z0,
0414                               size_t isum0,
0415                               fvar const& cr,
0416                               size_t z1,
0417                               size_t isum1) const;
0418 
0419   template <typename SizeType>
0420   fvar epsilon_multiply_cpp11(std::false_type,
0421                               SizeType z0,
0422                               size_t isum0,
0423                               fvar const& cr,
0424                               size_t z1,
0425                               size_t isum1) const;
0426 
0427   template <typename SizeType>
0428   fvar epsilon_multiply_cpp11(std::true_type, SizeType z0, size_t isum0, root_type const& ca) const;
0429 
0430   template <typename SizeType>
0431   fvar epsilon_multiply_cpp11(std::false_type, SizeType z0, size_t isum0, root_type const& ca) const;
0432 
0433   template <typename RootType>
0434   fvar& multiply_assign_by_root_type_cpp11(std::true_type, bool is_root, RootType const& ca);
0435 
0436   template <typename RootType>
0437   fvar& multiply_assign_by_root_type_cpp11(std::false_type, bool is_root, RootType const& ca);
0438 
0439   template <typename RootType>
0440   fvar& negate_cpp11(std::true_type, RootType const&);
0441 
0442   template <typename RootType>
0443   fvar& negate_cpp11(std::false_type, RootType const&);
0444 
0445   template <typename RootType>
0446   fvar& set_root_cpp11(std::true_type, RootType const& root);
0447 
0448   template <typename RootType>
0449   fvar& set_root_cpp11(std::false_type, RootType const& root);
0450 #endif
0451 };
0452 
0453 // Standard Library Support Requirements
0454 
0455 // fabs(cr1) | RealType
0456 template <typename RealType, size_t Order>
0457 fvar<RealType, Order> fabs(fvar<RealType, Order> const&);
0458 
0459 // abs(cr1) | RealType
0460 template <typename RealType, size_t Order>
0461 fvar<RealType, Order> abs(fvar<RealType, Order> const&);
0462 
0463 // ceil(cr1) | RealType
0464 template <typename RealType, size_t Order>
0465 fvar<RealType, Order> ceil(fvar<RealType, Order> const&);
0466 
0467 // floor(cr1) | RealType
0468 template <typename RealType, size_t Order>
0469 fvar<RealType, Order> floor(fvar<RealType, Order> const&);
0470 
0471 // exp(cr1) | RealType
0472 template <typename RealType, size_t Order>
0473 fvar<RealType, Order> exp(fvar<RealType, Order> const&);
0474 
0475 // pow(cr, ca) | RealType
0476 template <typename RealType, size_t Order>
0477 fvar<RealType, Order> pow(fvar<RealType, Order> const&, typename fvar<RealType, Order>::root_type const&);
0478 
0479 // pow(ca, cr) | RealType
0480 template <typename RealType, size_t Order>
0481 fvar<RealType, Order> pow(typename fvar<RealType, Order>::root_type const&, fvar<RealType, Order> const&);
0482 
0483 // pow(cr1, cr2) | RealType
0484 template <typename RealType1, size_t Order1, typename RealType2, size_t Order2>
0485 promote<fvar<RealType1, Order1>, fvar<RealType2, Order2>> pow(fvar<RealType1, Order1> const&,
0486                                                               fvar<RealType2, Order2> const&);
0487 
0488 // sqrt(cr1) | RealType
0489 template <typename RealType, size_t Order>
0490 fvar<RealType, Order> sqrt(fvar<RealType, Order> const&);
0491 
0492 // log(cr1) | RealType
0493 template <typename RealType, size_t Order>
0494 fvar<RealType, Order> log(fvar<RealType, Order> const&);
0495 
0496 // frexp(cr1, &i) | RealType
0497 template <typename RealType, size_t Order>
0498 fvar<RealType, Order> frexp(fvar<RealType, Order> const&, int*);
0499 
0500 // ldexp(cr1, i) | RealType
0501 template <typename RealType, size_t Order>
0502 fvar<RealType, Order> ldexp(fvar<RealType, Order> const&, int);
0503 
0504 // cos(cr1) | RealType
0505 template <typename RealType, size_t Order>
0506 fvar<RealType, Order> cos(fvar<RealType, Order> const&);
0507 
0508 // sin(cr1) | RealType
0509 template <typename RealType, size_t Order>
0510 fvar<RealType, Order> sin(fvar<RealType, Order> const&);
0511 
0512 // asin(cr1) | RealType
0513 template <typename RealType, size_t Order>
0514 fvar<RealType, Order> asin(fvar<RealType, Order> const&);
0515 
0516 // tan(cr1) | RealType
0517 template <typename RealType, size_t Order>
0518 fvar<RealType, Order> tan(fvar<RealType, Order> const&);
0519 
0520 // atan(cr1) | RealType
0521 template <typename RealType, size_t Order>
0522 fvar<RealType, Order> atan(fvar<RealType, Order> const&);
0523 
0524 // atan2(cr, ca) | RealType
0525 template <typename RealType, size_t Order>
0526 fvar<RealType, Order> atan2(fvar<RealType, Order> const&, typename fvar<RealType, Order>::root_type const&);
0527 
0528 // atan2(ca, cr) | RealType
0529 template <typename RealType, size_t Order>
0530 fvar<RealType, Order> atan2(typename fvar<RealType, Order>::root_type const&, fvar<RealType, Order> const&);
0531 
0532 // atan2(cr1, cr2) | RealType
0533 template <typename RealType1, size_t Order1, typename RealType2, size_t Order2>
0534 promote<fvar<RealType1, Order1>, fvar<RealType2, Order2>> atan2(fvar<RealType1, Order1> const&,
0535                                                                 fvar<RealType2, Order2> const&);
0536 
0537 // fmod(cr1,cr2) | RealType
0538 template <typename RealType1, size_t Order1, typename RealType2, size_t Order2>
0539 promote<fvar<RealType1, Order1>, fvar<RealType2, Order2>> fmod(fvar<RealType1, Order1> const&,
0540                                                                fvar<RealType2, Order2> const&);
0541 
0542 // round(cr1) | RealType
0543 template <typename RealType, size_t Order>
0544 fvar<RealType, Order> round(fvar<RealType, Order> const&);
0545 
0546 // iround(cr1) | int
0547 template <typename RealType, size_t Order>
0548 int iround(fvar<RealType, Order> const&);
0549 
0550 template <typename RealType, size_t Order>
0551 long lround(fvar<RealType, Order> const&);
0552 
0553 template <typename RealType, size_t Order>
0554 long long llround(fvar<RealType, Order> const&);
0555 
0556 // trunc(cr1) | RealType
0557 template <typename RealType, size_t Order>
0558 fvar<RealType, Order> trunc(fvar<RealType, Order> const&);
0559 
0560 template <typename RealType, size_t Order>
0561 long double truncl(fvar<RealType, Order> const&);
0562 
0563 // itrunc(cr1) | int
0564 template <typename RealType, size_t Order>
0565 int itrunc(fvar<RealType, Order> const&);
0566 
0567 template <typename RealType, size_t Order>
0568 long long lltrunc(fvar<RealType, Order> const&);
0569 
0570 // Additional functions
0571 template <typename RealType, size_t Order>
0572 fvar<RealType, Order> acos(fvar<RealType, Order> const&);
0573 
0574 template <typename RealType, size_t Order>
0575 fvar<RealType, Order> acosh(fvar<RealType, Order> const&);
0576 
0577 template <typename RealType, size_t Order>
0578 fvar<RealType, Order> asinh(fvar<RealType, Order> const&);
0579 
0580 template <typename RealType, size_t Order>
0581 fvar<RealType, Order> atanh(fvar<RealType, Order> const&);
0582 
0583 template <typename RealType, size_t Order>
0584 fvar<RealType, Order> cosh(fvar<RealType, Order> const&);
0585 
0586 template <typename RealType, size_t Order>
0587 fvar<RealType, Order> digamma(fvar<RealType, Order> const&);
0588 
0589 template <typename RealType, size_t Order>
0590 fvar<RealType, Order> erf(fvar<RealType, Order> const&);
0591 
0592 template <typename RealType, size_t Order>
0593 fvar<RealType, Order> erfc(fvar<RealType, Order> const&);
0594 
0595 template <typename RealType, size_t Order>
0596 fvar<RealType, Order> lambert_w0(fvar<RealType, Order> const&);
0597 
0598 template <typename RealType, size_t Order>
0599 fvar<RealType, Order> lgamma(fvar<RealType, Order> const&);
0600 
0601 template <typename RealType, size_t Order>
0602 fvar<RealType, Order> sinc(fvar<RealType, Order> const&);
0603 
0604 template <typename RealType, size_t Order>
0605 fvar<RealType, Order> sinh(fvar<RealType, Order> const&);
0606 
0607 template <typename RealType, size_t Order>
0608 fvar<RealType, Order> tanh(fvar<RealType, Order> const&);
0609 
0610 template <typename RealType, size_t Order>
0611 fvar<RealType, Order> tgamma(fvar<RealType, Order> const&);
0612 
0613 template <size_t>
0614 struct zero : std::integral_constant<size_t, 0> {};
0615 
0616 }  // namespace detail
0617 
0618 template <typename RealType, size_t Order, size_t... Orders>
0619 using autodiff_fvar = typename detail::nest_fvar<RealType, Order, Orders...>::type;
0620 
0621 template <typename RealType, size_t Order, size_t... Orders>
0622 autodiff_fvar<RealType, Order, Orders...> make_fvar(RealType const& ca) {
0623   return autodiff_fvar<RealType, Order, Orders...>(ca, true);
0624 }
0625 
0626 #ifndef BOOST_MATH_NO_CXX17_IF_CONSTEXPR
0627 namespace detail {
0628 
0629 template <typename RealType, size_t Order, size_t... Is>
0630 auto make_fvar_for_tuple(std::index_sequence<Is...>, RealType const& ca) {
0631   return make_fvar<RealType, zero<Is>::value..., Order>(ca);
0632 }
0633 
0634 template <typename RealType, size_t... Orders, size_t... Is, typename... RealTypes>
0635 auto make_ftuple_impl(std::index_sequence<Is...>, RealTypes const&... ca) {
0636   return std::make_tuple(make_fvar_for_tuple<RealType, Orders>(std::make_index_sequence<Is>{}, ca)...);
0637 }
0638 
0639 }  // namespace detail
0640 
0641 template <typename RealType, size_t... Orders, typename... RealTypes>
0642 auto make_ftuple(RealTypes const&... ca) {
0643   static_assert(sizeof...(Orders) == sizeof...(RealTypes),
0644                 "Number of Orders must match number of function parameters.");
0645   return detail::make_ftuple_impl<RealType, Orders...>(std::index_sequence_for<RealTypes...>{}, ca...);
0646 }
0647 #endif
0648 
0649 namespace detail {
0650 
0651 #ifndef BOOST_MATH_NO_CXX17_IF_CONSTEXPR
0652 template <typename RealType, size_t Order>
0653 fvar<RealType, Order>::fvar(root_type const& ca, bool const is_variable) {
0654   if constexpr (is_fvar<RealType>::value) {
0655     v.front() = RealType(ca, is_variable);
0656     if constexpr (0 < Order)
0657       std::fill(v.begin() + 1, v.end(), static_cast<RealType>(0));
0658   } else {
0659     v.front() = ca;
0660     if constexpr (0 < Order)
0661       v[1] = static_cast<root_type>(static_cast<int>(is_variable));
0662     if constexpr (1 < Order)
0663       std::fill(v.begin() + 2, v.end(), static_cast<RealType>(0));
0664   }
0665 }
0666 #endif
0667 
0668 template <typename RealType, size_t Order>
0669 template <typename RealType2, size_t Order2>
0670 fvar<RealType, Order>::fvar(fvar<RealType2, Order2> const& cr) {
0671   for (size_t i = 0; i <= (std::min)(Order, Order2); ++i)
0672     v[i] = static_cast<RealType>(cr.v[i]);
0673   BOOST_MATH_IF_CONSTEXPR (Order2 < Order)
0674     std::fill(v.begin() + (Order2 + 1), v.end(), static_cast<RealType>(0));
0675 }
0676 
0677 template <typename RealType, size_t Order>
0678 fvar<RealType, Order>::fvar(root_type const& ca) : v{{static_cast<RealType>(ca)}} {}
0679 
0680 // Can cause compiler error if RealType2 cannot be cast to root_type.
0681 template <typename RealType, size_t Order>
0682 template <typename RealType2>
0683 fvar<RealType, Order>::fvar(RealType2 const& ca) : v{{static_cast<RealType>(ca)}} {}
0684 
0685 /*
0686 template<typename RealType, size_t Order>
0687 fvar<RealType,Order>& fvar<RealType,Order>::operator=(root_type const& ca)
0688 {
0689     v.front() = static_cast<RealType>(ca);
0690     if constexpr (0 < Order)
0691         std::fill(v.begin()+1, v.end(), static_cast<RealType>(0));
0692     return *this;
0693 }
0694 */
0695 
0696 template <typename RealType, size_t Order>
0697 template <typename RealType2, size_t Order2>
0698 fvar<RealType, Order>& fvar<RealType, Order>::operator+=(fvar<RealType2, Order2> const& cr) {
0699   for (size_t i = 0; i <= (std::min)(Order, Order2); ++i)
0700     v[i] += cr.v[i];
0701   return *this;
0702 }
0703 
0704 template <typename RealType, size_t Order>
0705 fvar<RealType, Order>& fvar<RealType, Order>::operator+=(root_type const& ca) {
0706   v.front() += ca;
0707   return *this;
0708 }
0709 
0710 template <typename RealType, size_t Order>
0711 template <typename RealType2, size_t Order2>
0712 fvar<RealType, Order>& fvar<RealType, Order>::operator-=(fvar<RealType2, Order2> const& cr) {
0713   for (size_t i = 0; i <= Order; ++i)
0714     v[i] -= cr.v[i];
0715   return *this;
0716 }
0717 
0718 template <typename RealType, size_t Order>
0719 fvar<RealType, Order>& fvar<RealType, Order>::operator-=(root_type const& ca) {
0720   v.front() -= ca;
0721   return *this;
0722 }
0723 
0724 template <typename RealType, size_t Order>
0725 template <typename RealType2, size_t Order2>
0726 fvar<RealType, Order>& fvar<RealType, Order>::operator*=(fvar<RealType2, Order2> const& cr) {
0727   using diff_t = typename std::array<RealType, Order + 1>::difference_type;
0728   promote<RealType, RealType2> const zero(0);
0729   BOOST_MATH_IF_CONSTEXPR (Order <= Order2)
0730     for (size_t i = 0, j = Order; i <= Order; ++i, --j)
0731       v[j] = std::inner_product(v.cbegin(), v.cend() - diff_t(i), cr.v.crbegin() + diff_t(i), zero);
0732   else {
0733     for (size_t i = 0, j = Order; i <= Order - Order2; ++i, --j)
0734       v[j] = std::inner_product(cr.v.cbegin(), cr.v.cend(), v.crbegin() + diff_t(i), zero);
0735     for (size_t i = Order - Order2 + 1, j = Order2 - 1; i <= Order; ++i, --j)
0736       v[j] = std::inner_product(cr.v.cbegin(), cr.v.cbegin() + diff_t(j + 1), v.crbegin() + diff_t(i), zero);
0737   }
0738   return *this;
0739 }
0740 
0741 template <typename RealType, size_t Order>
0742 fvar<RealType, Order>& fvar<RealType, Order>::operator*=(root_type const& ca) {
0743   return multiply_assign_by_root_type(true, ca);
0744 }
0745 
0746 template <typename RealType, size_t Order>
0747 template <typename RealType2, size_t Order2>
0748 fvar<RealType, Order>& fvar<RealType, Order>::operator/=(fvar<RealType2, Order2> const& cr) {
0749   using diff_t = typename std::array<RealType, Order + 1>::difference_type;
0750   RealType const zero(0);
0751   v.front() /= cr.v.front();
0752   BOOST_MATH_IF_CONSTEXPR (Order < Order2)
0753     for (size_t i = 1, j = Order2 - 1, k = Order; i <= Order; ++i, --j, --k)
0754       (v[i] -= std::inner_product(
0755            cr.v.cbegin() + 1, cr.v.cend() - diff_t(j), v.crbegin() + diff_t(k), zero)) /= cr.v.front();
0756   else BOOST_MATH_IF_CONSTEXPR (0 < Order2)
0757     for (size_t i = 1, j = Order2 - 1, k = Order; i <= Order; ++i, j && --j, --k)
0758       (v[i] -= std::inner_product(
0759            cr.v.cbegin() + 1, cr.v.cend() - diff_t(j), v.crbegin() + diff_t(k), zero)) /= cr.v.front();
0760   else
0761     for (size_t i = 1; i <= Order; ++i)
0762       v[i] /= cr.v.front();
0763   return *this;
0764 }
0765 
0766 template <typename RealType, size_t Order>
0767 fvar<RealType, Order>& fvar<RealType, Order>::operator/=(root_type const& ca) {
0768   std::for_each(v.begin(), v.end(), [&ca](RealType& x) { x /= ca; });
0769   return *this;
0770 }
0771 
0772 template <typename RealType, size_t Order>
0773 fvar<RealType, Order> fvar<RealType, Order>::operator-() const {
0774   fvar<RealType, Order> retval(*this);
0775   retval.negate();
0776   return retval;
0777 }
0778 
0779 template <typename RealType, size_t Order>
0780 fvar<RealType, Order> const& fvar<RealType, Order>::operator+() const {
0781   return *this;
0782 }
0783 
0784 template <typename RealType, size_t Order>
0785 template <typename RealType2, size_t Order2>
0786 promote<fvar<RealType, Order>, fvar<RealType2, Order2>> fvar<RealType, Order>::operator+(
0787     fvar<RealType2, Order2> const& cr) const {
0788   promote<fvar<RealType, Order>, fvar<RealType2, Order2>> retval;
0789   for (size_t i = 0; i <= (std::min)(Order, Order2); ++i)
0790     retval.v[i] = v[i] + cr.v[i];
0791   BOOST_MATH_IF_CONSTEXPR (Order < Order2)
0792     for (size_t i = Order + 1; i <= Order2; ++i)
0793       retval.v[i] = cr.v[i];
0794   else BOOST_MATH_IF_CONSTEXPR (Order2 < Order)
0795     for (size_t i = Order2 + 1; i <= Order; ++i)
0796       retval.v[i] = v[i];
0797   return retval;
0798 }
0799 
0800 template <typename RealType, size_t Order>
0801 fvar<RealType, Order> fvar<RealType, Order>::operator+(root_type const& ca) const {
0802   fvar<RealType, Order> retval(*this);
0803   retval.v.front() += ca;
0804   return retval;
0805 }
0806 
0807 template <typename RealType, size_t Order>
0808 fvar<RealType, Order> operator+(typename fvar<RealType, Order>::root_type const& ca,
0809                                 fvar<RealType, Order> const& cr) {
0810   return cr + ca;
0811 }
0812 
0813 template <typename RealType, size_t Order>
0814 template <typename RealType2, size_t Order2>
0815 promote<fvar<RealType, Order>, fvar<RealType2, Order2>> fvar<RealType, Order>::operator-(
0816     fvar<RealType2, Order2> const& cr) const {
0817   promote<fvar<RealType, Order>, fvar<RealType2, Order2>> retval;
0818   for (size_t i = 0; i <= (std::min)(Order, Order2); ++i)
0819     retval.v[i] = v[i] - cr.v[i];
0820   BOOST_MATH_IF_CONSTEXPR (Order < Order2)
0821     for (auto i = Order + 1; i <= Order2; ++i)
0822       retval.v[i] = -cr.v[i];
0823   else BOOST_MATH_IF_CONSTEXPR (Order2 < Order)
0824     for (auto i = Order2 + 1; i <= Order; ++i)
0825       retval.v[i] = v[i];
0826   return retval;
0827 }
0828 
0829 template <typename RealType, size_t Order>
0830 fvar<RealType, Order> fvar<RealType, Order>::operator-(root_type const& ca) const {
0831   fvar<RealType, Order> retval(*this);
0832   retval.v.front() -= ca;
0833   return retval;
0834 }
0835 
0836 template <typename RealType, size_t Order>
0837 fvar<RealType, Order> operator-(typename fvar<RealType, Order>::root_type const& ca,
0838                                 fvar<RealType, Order> const& cr) {
0839   fvar<RealType, Order> mcr = -cr;  // Has same address as retval in operator-() due to NRVO.
0840   mcr += ca;
0841   return mcr;  // <-- This allows for NRVO. The following does not. --> return mcr += ca;
0842 }
0843 
0844 template <typename RealType, size_t Order>
0845 template <typename RealType2, size_t Order2>
0846 promote<fvar<RealType, Order>, fvar<RealType2, Order2>> fvar<RealType, Order>::operator*(
0847     fvar<RealType2, Order2> const& cr) const {
0848   using diff_t = typename std::array<RealType, Order + 1>::difference_type;
0849   promote<RealType, RealType2> const zero(0);
0850   promote<fvar<RealType, Order>, fvar<RealType2, Order2>> retval;
0851   BOOST_MATH_IF_CONSTEXPR (Order < Order2)
0852     for (size_t i = 0, j = Order, k = Order2; i <= Order2; ++i, j && --j, --k)
0853       retval.v[i] = std::inner_product(v.cbegin(), v.cend() - diff_t(j), cr.v.crbegin() + diff_t(k), zero);
0854   else
0855     for (size_t i = 0, j = Order2, k = Order; i <= Order; ++i, j && --j, --k)
0856       retval.v[i] = std::inner_product(cr.v.cbegin(), cr.v.cend() - diff_t(j), v.crbegin() + diff_t(k), zero);
0857   return retval;
0858 }
0859 
0860 template <typename RealType, size_t Order>
0861 fvar<RealType, Order> fvar<RealType, Order>::operator*(root_type const& ca) const {
0862   fvar<RealType, Order> retval(*this);
0863   retval *= ca;
0864   return retval;
0865 }
0866 
0867 template <typename RealType, size_t Order>
0868 fvar<RealType, Order> operator*(typename fvar<RealType, Order>::root_type const& ca,
0869                                 fvar<RealType, Order> const& cr) {
0870   return cr * ca;
0871 }
0872 
0873 template <typename RealType, size_t Order>
0874 template <typename RealType2, size_t Order2>
0875 promote<fvar<RealType, Order>, fvar<RealType2, Order2>> fvar<RealType, Order>::operator/(
0876     fvar<RealType2, Order2> const& cr) const {
0877   using diff_t = typename std::array<RealType, Order + 1>::difference_type;
0878   promote<RealType, RealType2> const zero(0);
0879   promote<fvar<RealType, Order>, fvar<RealType2, Order2>> retval;
0880   retval.v.front() = v.front() / cr.v.front();
0881   BOOST_MATH_IF_CONSTEXPR (Order < Order2) {
0882     for (size_t i = 1, j = Order2 - 1; i <= Order; ++i, --j)
0883       retval.v[i] =
0884           (v[i] - std::inner_product(
0885                       cr.v.cbegin() + 1, cr.v.cend() - diff_t(j), retval.v.crbegin() + diff_t(j + 1), zero)) /
0886           cr.v.front();
0887     for (size_t i = Order + 1, j = Order2 - Order - 1; i <= Order2; ++i, --j)
0888       retval.v[i] =
0889           -std::inner_product(
0890               cr.v.cbegin() + 1, cr.v.cend() - diff_t(j), retval.v.crbegin() + diff_t(j + 1), zero) /
0891           cr.v.front();
0892   } else BOOST_MATH_IF_CONSTEXPR (0 < Order2)
0893     for (size_t i = 1, j = Order2 - 1, k = Order; i <= Order; ++i, j && --j, --k)
0894       retval.v[i] =
0895           (v[i] - std::inner_product(
0896                       cr.v.cbegin() + 1, cr.v.cend() - diff_t(j), retval.v.crbegin() + diff_t(k), zero)) /
0897           cr.v.front();
0898   else
0899     for (size_t i = 1; i <= Order; ++i)
0900       retval.v[i] = v[i] / cr.v.front();
0901   return retval;
0902 }
0903 
0904 template <typename RealType, size_t Order>
0905 fvar<RealType, Order> fvar<RealType, Order>::operator/(root_type const& ca) const {
0906   fvar<RealType, Order> retval(*this);
0907   retval /= ca;
0908   return retval;
0909 }
0910 
0911 template <typename RealType, size_t Order>
0912 fvar<RealType, Order> operator/(typename fvar<RealType, Order>::root_type const& ca,
0913                                 fvar<RealType, Order> const& cr) {
0914   using diff_t = typename std::array<RealType, Order + 1>::difference_type;
0915   fvar<RealType, Order> retval;
0916   retval.v.front() = ca / cr.v.front();
0917   BOOST_MATH_IF_CONSTEXPR (0 < Order) {
0918     RealType const zero(0);
0919     for (size_t i = 1, j = Order - 1; i <= Order; ++i, --j)
0920       retval.v[i] =
0921           -std::inner_product(
0922               cr.v.cbegin() + 1, cr.v.cend() - diff_t(j), retval.v.crbegin() + diff_t(j + 1), zero) /
0923           cr.v.front();
0924   }
0925   return retval;
0926 }
0927 
0928 template <typename RealType, size_t Order>
0929 template <typename RealType2, size_t Order2>
0930 bool fvar<RealType, Order>::operator==(fvar<RealType2, Order2> const& cr) const {
0931   return v.front() == cr.v.front();
0932 }
0933 
0934 template <typename RealType, size_t Order>
0935 bool fvar<RealType, Order>::operator==(root_type const& ca) const {
0936   return v.front() == ca;
0937 }
0938 
0939 template <typename RealType, size_t Order>
0940 bool operator==(typename fvar<RealType, Order>::root_type const& ca, fvar<RealType, Order> const& cr) {
0941   return ca == cr.v.front();
0942 }
0943 
0944 template <typename RealType, size_t Order>
0945 template <typename RealType2, size_t Order2>
0946 bool fvar<RealType, Order>::operator!=(fvar<RealType2, Order2> const& cr) const {
0947   return v.front() != cr.v.front();
0948 }
0949 
0950 template <typename RealType, size_t Order>
0951 bool fvar<RealType, Order>::operator!=(root_type const& ca) const {
0952   return v.front() != ca;
0953 }
0954 
0955 template <typename RealType, size_t Order>
0956 bool operator!=(typename fvar<RealType, Order>::root_type const& ca, fvar<RealType, Order> const& cr) {
0957   return ca != cr.v.front();
0958 }
0959 
0960 template <typename RealType, size_t Order>
0961 template <typename RealType2, size_t Order2>
0962 bool fvar<RealType, Order>::operator<=(fvar<RealType2, Order2> const& cr) const {
0963   return v.front() <= cr.v.front();
0964 }
0965 
0966 template <typename RealType, size_t Order>
0967 bool fvar<RealType, Order>::operator<=(root_type const& ca) const {
0968   return v.front() <= ca;
0969 }
0970 
0971 template <typename RealType, size_t Order>
0972 bool operator<=(typename fvar<RealType, Order>::root_type const& ca, fvar<RealType, Order> const& cr) {
0973   return ca <= cr.v.front();
0974 }
0975 
0976 template <typename RealType, size_t Order>
0977 template <typename RealType2, size_t Order2>
0978 bool fvar<RealType, Order>::operator>=(fvar<RealType2, Order2> const& cr) const {
0979   return v.front() >= cr.v.front();
0980 }
0981 
0982 template <typename RealType, size_t Order>
0983 bool fvar<RealType, Order>::operator>=(root_type const& ca) const {
0984   return v.front() >= ca;
0985 }
0986 
0987 template <typename RealType, size_t Order>
0988 bool operator>=(typename fvar<RealType, Order>::root_type const& ca, fvar<RealType, Order> const& cr) {
0989   return ca >= cr.v.front();
0990 }
0991 
0992 template <typename RealType, size_t Order>
0993 template <typename RealType2, size_t Order2>
0994 bool fvar<RealType, Order>::operator<(fvar<RealType2, Order2> const& cr) const {
0995   return v.front() < cr.v.front();
0996 }
0997 
0998 template <typename RealType, size_t Order>
0999 bool fvar<RealType, Order>::operator<(root_type const& ca) const {
1000   return v.front() < ca;
1001 }
1002 
1003 template <typename RealType, size_t Order>
1004 bool operator<(typename fvar<RealType, Order>::root_type const& ca, fvar<RealType, Order> const& cr) {
1005   return ca < cr.v.front();
1006 }
1007 
1008 template <typename RealType, size_t Order>
1009 template <typename RealType2, size_t Order2>
1010 bool fvar<RealType, Order>::operator>(fvar<RealType2, Order2> const& cr) const {
1011   return v.front() > cr.v.front();
1012 }
1013 
1014 template <typename RealType, size_t Order>
1015 bool fvar<RealType, Order>::operator>(root_type const& ca) const {
1016   return v.front() > ca;
1017 }
1018 
1019 template <typename RealType, size_t Order>
1020 bool operator>(typename fvar<RealType, Order>::root_type const& ca, fvar<RealType, Order> const& cr) {
1021   return ca > cr.v.front();
1022 }
1023 
1024   /*** Other methods and functions ***/
1025 
1026 #ifndef BOOST_MATH_NO_CXX17_IF_CONSTEXPR
1027 // f : order -> derivative(order)/factorial(order)
1028 // Use this when you have the polynomial coefficients, rather than just the derivatives. E.g. See atan2().
1029 template <typename RealType, size_t Order>
1030 template <typename Func, typename Fvar, typename... Fvars>
1031 promote<fvar<RealType, Order>, Fvar, Fvars...> fvar<RealType, Order>::apply_coefficients(
1032     size_t const order,
1033     Func const& f,
1034     Fvar const& cr,
1035     Fvars&&... fvars) const {
1036   fvar<RealType, Order> const epsilon = fvar<RealType, Order>(*this).set_root(0);
1037   size_t i = (std::min)(order, order_sum);
1038   promote<fvar<RealType, Order>, Fvar, Fvars...> accumulator = cr.apply_coefficients(
1039       order - i, [&f, i](auto... indices) { return f(i, indices...); }, std::forward<Fvars>(fvars)...);
1040   while (i--)
1041     (accumulator *= epsilon) += cr.apply_coefficients(
1042         order - i, [&f, i](auto... indices) { return f(i, indices...); }, std::forward<Fvars>(fvars)...);
1043   return accumulator;
1044 }
1045 #endif
1046 
1047 // f : order -> derivative(order)/factorial(order)
1048 // Use this when you have the polynomial coefficients, rather than just the derivatives. E.g. See atan().
1049 template <typename RealType, size_t Order>
1050 template <typename Func>
1051 fvar<RealType, Order> fvar<RealType, Order>::apply_coefficients(size_t const order, Func const& f) const {
1052   fvar<RealType, Order> const epsilon = fvar<RealType, Order>(*this).set_root(0);
1053 #ifndef BOOST_MATH_NO_CXX17_IF_CONSTEXPR
1054   size_t i = (std::min)(order, order_sum);
1055 #else  // ODR-use of static constexpr
1056   size_t i = order < order_sum ? order : order_sum;
1057 #endif
1058   fvar<RealType, Order> accumulator = f(i);
1059   while (i--)
1060     (accumulator *= epsilon) += f(i);
1061   return accumulator;
1062 }
1063 
1064 #ifndef BOOST_MATH_NO_CXX17_IF_CONSTEXPR
1065 // f : order -> derivative(order)
1066 template <typename RealType, size_t Order>
1067 template <typename Func, typename Fvar, typename... Fvars>
1068 promote<fvar<RealType, Order>, Fvar, Fvars...> fvar<RealType, Order>::apply_coefficients_nonhorner(
1069     size_t const order,
1070     Func const& f,
1071     Fvar const& cr,
1072     Fvars&&... fvars) const {
1073   fvar<RealType, Order> const epsilon = fvar<RealType, Order>(*this).set_root(0);
1074   fvar<RealType, Order> epsilon_i = fvar<RealType, Order>(1);  // epsilon to the power of i
1075   promote<fvar<RealType, Order>, Fvar, Fvars...> accumulator = cr.apply_coefficients_nonhorner(
1076       order,
1077       [&f](auto... indices) { return f(0, static_cast<std::size_t>(indices)...); },
1078       std::forward<Fvars>(fvars)...);
1079   size_t const i_max = (std::min)(order, order_sum);
1080   for (size_t i = 1; i <= i_max; ++i) {
1081     epsilon_i = epsilon_i.epsilon_multiply(i - 1, 0, epsilon, 1, 0);
1082     accumulator += epsilon_i.epsilon_multiply(
1083         i,
1084         0,
1085         cr.apply_coefficients_nonhorner(
1086             order - i,
1087             [&f, i](auto... indices) { return f(i, static_cast<std::size_t>(indices)...); },
1088             std::forward<Fvars>(fvars)...),
1089         0,
1090         0);
1091   }
1092   return accumulator;
1093 }
1094 #endif
1095 
1096 // f : order -> coefficient(order)
1097 template <typename RealType, size_t Order>
1098 template <typename Func>
1099 fvar<RealType, Order> fvar<RealType, Order>::apply_coefficients_nonhorner(size_t const order,
1100                                                                           Func const& f) const {
1101   fvar<RealType, Order> const epsilon = fvar<RealType, Order>(*this).set_root(0);
1102   fvar<RealType, Order> epsilon_i = fvar<RealType, Order>(1);  // epsilon to the power of i
1103   fvar<RealType, Order> accumulator = fvar<RealType, Order>(f(0u));
1104 #ifndef BOOST_MATH_NO_CXX17_IF_CONSTEXPR
1105   size_t const i_max = (std::min)(order, order_sum);
1106 #else  // ODR-use of static constexpr
1107   size_t const i_max = order < order_sum ? order : order_sum;
1108 #endif
1109   for (size_t i = 1; i <= i_max; ++i) {
1110     epsilon_i = epsilon_i.epsilon_multiply(i - 1, 0, epsilon, 1, 0);
1111     accumulator += epsilon_i.epsilon_multiply(i, 0, f(i));
1112   }
1113   return accumulator;
1114 }
1115 
1116 #ifndef BOOST_MATH_NO_CXX17_IF_CONSTEXPR
1117 // f : order -> derivative(order)
1118 template <typename RealType, size_t Order>
1119 template <typename Func, typename Fvar, typename... Fvars>
1120 promote<fvar<RealType, Order>, Fvar, Fvars...> fvar<RealType, Order>::apply_derivatives(
1121     size_t const order,
1122     Func const& f,
1123     Fvar const& cr,
1124     Fvars&&... fvars) const {
1125   fvar<RealType, Order> const epsilon = fvar<RealType, Order>(*this).set_root(0);
1126   size_t i = (std::min)(order, order_sum);
1127   promote<fvar<RealType, Order>, Fvar, Fvars...> accumulator =
1128       cr.apply_derivatives(
1129           order - i, [&f, i](auto... indices) { return f(i, indices...); }, std::forward<Fvars>(fvars)...) /
1130       factorial<root_type>(static_cast<unsigned>(i));
1131   while (i--)
1132     (accumulator *= epsilon) +=
1133         cr.apply_derivatives(
1134             order - i, [&f, i](auto... indices) { return f(i, indices...); }, std::forward<Fvars>(fvars)...) /
1135         factorial<root_type>(static_cast<unsigned>(i));
1136   return accumulator;
1137 }
1138 #endif
1139 
1140 // f : order -> derivative(order)
1141 template <typename RealType, size_t Order>
1142 template <typename Func>
1143 fvar<RealType, Order> fvar<RealType, Order>::apply_derivatives(size_t const order, Func const& f) const {
1144   fvar<RealType, Order> const epsilon = fvar<RealType, Order>(*this).set_root(0);
1145 #ifndef BOOST_MATH_NO_CXX17_IF_CONSTEXPR
1146   size_t i = (std::min)(order, order_sum);
1147 #else  // ODR-use of static constexpr
1148   size_t i = order < order_sum ? order : order_sum;
1149 #endif
1150   fvar<RealType, Order> accumulator = f(i) / factorial<root_type>(static_cast<unsigned>(i));
1151   while (i--)
1152     (accumulator *= epsilon) += f(i) / factorial<root_type>(static_cast<unsigned>(i));
1153   return accumulator;
1154 }
1155 
1156 #ifndef BOOST_MATH_NO_CXX17_IF_CONSTEXPR
1157 // f : order -> derivative(order)
1158 template <typename RealType, size_t Order>
1159 template <typename Func, typename Fvar, typename... Fvars>
1160 promote<fvar<RealType, Order>, Fvar, Fvars...> fvar<RealType, Order>::apply_derivatives_nonhorner(
1161     size_t const order,
1162     Func const& f,
1163     Fvar const& cr,
1164     Fvars&&... fvars) const {
1165   fvar<RealType, Order> const epsilon = fvar<RealType, Order>(*this).set_root(0);
1166   fvar<RealType, Order> epsilon_i = fvar<RealType, Order>(1);  // epsilon to the power of i
1167   promote<fvar<RealType, Order>, Fvar, Fvars...> accumulator = cr.apply_derivatives_nonhorner(
1168       order,
1169       [&f](auto... indices) { return f(0, static_cast<std::size_t>(indices)...); },
1170       std::forward<Fvars>(fvars)...);
1171   size_t const i_max = (std::min)(order, order_sum);
1172   for (size_t i = 1; i <= i_max; ++i) {
1173     epsilon_i = epsilon_i.epsilon_multiply(i - 1, 0, epsilon, 1, 0);
1174     accumulator += epsilon_i.epsilon_multiply(
1175         i,
1176         0,
1177         cr.apply_derivatives_nonhorner(
1178             order - i,
1179             [&f, i](auto... indices) { return f(i, static_cast<std::size_t>(indices)...); },
1180             std::forward<Fvars>(fvars)...) /
1181             factorial<root_type>(static_cast<unsigned>(i)),
1182         0,
1183         0);
1184   }
1185   return accumulator;
1186 }
1187 #endif
1188 
1189 // f : order -> derivative(order)
1190 template <typename RealType, size_t Order>
1191 template <typename Func>
1192 fvar<RealType, Order> fvar<RealType, Order>::apply_derivatives_nonhorner(size_t const order,
1193                                                                          Func const& f) const {
1194   fvar<RealType, Order> const epsilon = fvar<RealType, Order>(*this).set_root(0);
1195   fvar<RealType, Order> epsilon_i = fvar<RealType, Order>(1);  // epsilon to the power of i
1196   fvar<RealType, Order> accumulator = fvar<RealType, Order>(f(0u));
1197 #ifndef BOOST_MATH_NO_CXX17_IF_CONSTEXPR
1198   size_t const i_max = (std::min)(order, order_sum);
1199 #else  // ODR-use of static constexpr
1200   size_t const i_max = order < order_sum ? order : order_sum;
1201 #endif
1202   for (size_t i = 1; i <= i_max; ++i) {
1203     epsilon_i = epsilon_i.epsilon_multiply(i - 1, 0, epsilon, 1, 0);
1204     accumulator += epsilon_i.epsilon_multiply(i, 0, f(i) / factorial<root_type>(static_cast<unsigned>(i)));
1205   }
1206   return accumulator;
1207 }
1208 
1209 #ifndef BOOST_MATH_NO_CXX17_IF_CONSTEXPR
1210 // Can throw "std::out_of_range: array::at: __n (which is 7) >= _Nm (which is 7)"
1211 template <typename RealType, size_t Order>
1212 template <typename... Orders>
1213 get_type_at<RealType, sizeof...(Orders)> fvar<RealType, Order>::at(size_t order, Orders... orders) const {
1214   if constexpr (0 < sizeof...(Orders))
1215     return v.at(order).at(static_cast<std::size_t>(orders)...);
1216   else
1217     return v.at(order);
1218 }
1219 #endif
1220 
1221 #ifndef BOOST_MATH_NO_CXX17_IF_CONSTEXPR
1222 // Can throw "std::out_of_range: array::at: __n (which is 7) >= _Nm (which is 7)"
1223 template <typename RealType, size_t Order>
1224 template <typename... Orders>
1225 get_type_at<fvar<RealType, Order>, sizeof...(Orders)> fvar<RealType, Order>::derivative(
1226     Orders... orders) const {
1227   static_assert(sizeof...(Orders) <= depth,
1228                 "Number of parameters to derivative(...) cannot exceed fvar::depth.");
1229   return at(static_cast<std::size_t>(orders)...) *
1230          (... * factorial<root_type>(static_cast<unsigned>(orders)));
1231 }
1232 #endif
1233 
1234 template <typename RealType, size_t Order>
1235 const RealType& fvar<RealType, Order>::operator[](size_t i) const {
1236   return v[i];
1237 }
1238 
1239 template <typename RealType, size_t Order>
1240 RealType fvar<RealType, Order>::epsilon_inner_product(size_t z0,
1241                                                       size_t const isum0,
1242                                                       size_t const m0,
1243                                                       fvar<RealType, Order> const& cr,
1244                                                       size_t z1,
1245                                                       size_t const isum1,
1246                                                       size_t const m1,
1247                                                       size_t const j) const {
1248   static_assert(is_fvar<RealType>::value, "epsilon_inner_product() must have 1 < depth.");
1249   RealType accumulator = RealType();
1250   auto const i0_max = m1 < j ? j - m1 : 0;
1251   for (auto i0 = m0, i1 = j - m0; i0 <= i0_max; ++i0, --i1)
1252     accumulator += v[i0].epsilon_multiply(z0, isum0 + i0, cr.v[i1], z1, isum1 + i1);
1253   return accumulator;
1254 }
1255 
1256 #ifndef BOOST_MATH_NO_CXX17_IF_CONSTEXPR
1257 template <typename RealType, size_t Order>
1258 fvar<RealType, Order> fvar<RealType, Order>::epsilon_multiply(size_t z0,
1259                                                               size_t isum0,
1260                                                               fvar<RealType, Order> const& cr,
1261                                                               size_t z1,
1262                                                               size_t isum1) const {
1263   using diff_t = typename std::array<RealType, Order + 1>::difference_type;
1264   RealType const zero(0);
1265   size_t const m0 = order_sum + isum0 < Order + z0 ? Order + z0 - (order_sum + isum0) : 0;
1266   size_t const m1 = order_sum + isum1 < Order + z1 ? Order + z1 - (order_sum + isum1) : 0;
1267   size_t const i_max = m0 + m1 < Order ? Order - (m0 + m1) : 0;
1268   fvar<RealType, Order> retval = fvar<RealType, Order>();
1269   if constexpr (is_fvar<RealType>::value)
1270     for (size_t i = 0, j = Order; i <= i_max; ++i, --j)
1271       retval.v[j] = epsilon_inner_product(z0, isum0, m0, cr, z1, isum1, m1, j);
1272   else
1273     for (size_t i = 0, j = Order; i <= i_max; ++i, --j)
1274       retval.v[j] = std::inner_product(
1275           v.cbegin() + diff_t(m0), v.cend() - diff_t(i + m1), cr.v.crbegin() + diff_t(i + m0), zero);
1276   return retval;
1277 }
1278 #endif
1279 
1280 #ifndef BOOST_MATH_NO_CXX17_IF_CONSTEXPR
1281 // When called from outside this method, z0 should be non-zero. Otherwise if z0=0 then it will give an
1282 // incorrect result of 0 when the root value is 0 and ca=inf, when instead the correct product is nan.
1283 // If z0=0 then use the regular multiply operator*() instead.
1284 template <typename RealType, size_t Order>
1285 fvar<RealType, Order> fvar<RealType, Order>::epsilon_multiply(size_t z0,
1286                                                               size_t isum0,
1287                                                               root_type const& ca) const {
1288   fvar<RealType, Order> retval(*this);
1289   size_t const m0 = order_sum + isum0 < Order + z0 ? Order + z0 - (order_sum + isum0) : 0;
1290   if constexpr (is_fvar<RealType>::value)
1291     for (size_t i = m0; i <= Order; ++i)
1292       retval.v[i] = retval.v[i].epsilon_multiply(z0, isum0 + i, ca);
1293   else
1294     for (size_t i = m0; i <= Order; ++i)
1295       if (retval.v[i] != static_cast<RealType>(0))
1296         retval.v[i] *= ca;
1297   return retval;
1298 }
1299 #endif
1300 
1301 template <typename RealType, size_t Order>
1302 fvar<RealType, Order> fvar<RealType, Order>::inverse() const {
1303   return static_cast<root_type>(*this) == 0 ? inverse_apply() : 1 / *this;
1304 }
1305 
1306 #ifndef BOOST_MATH_NO_CXX17_IF_CONSTEXPR
1307 template <typename RealType, size_t Order>
1308 fvar<RealType, Order>& fvar<RealType, Order>::negate() {
1309   if constexpr (is_fvar<RealType>::value)
1310     std::for_each(v.begin(), v.end(), [](RealType& r) { r.negate(); });
1311   else
1312     std::for_each(v.begin(), v.end(), [](RealType& a) { a = -a; });
1313   return *this;
1314 }
1315 #endif
1316 
1317 // This gives log(0.0) = depth(1)(-inf,inf,-inf,inf,-inf,inf)
1318 // 1 / *this: log(0.0) = depth(1)(-inf,inf,-inf,-nan,-nan,-nan)
1319 template <typename RealType, size_t Order>
1320 fvar<RealType, Order> fvar<RealType, Order>::inverse_apply() const {
1321   root_type derivatives[order_sum + 1];  // LCOV_EXCL_LINE This causes a false negative on lcov coverage test.
1322   root_type const x0 = static_cast<root_type>(*this);
1323   *derivatives = 1 / x0;
1324   for (size_t i = 1; i <= order_sum; ++i)
1325     derivatives[i] = -derivatives[i - 1] * i / x0;
1326   return apply_derivatives_nonhorner(order_sum, [&derivatives](size_t j) { return derivatives[j]; });
1327 }
1328 
1329 #ifndef BOOST_MATH_NO_CXX17_IF_CONSTEXPR
1330 template <typename RealType, size_t Order>
1331 fvar<RealType, Order>& fvar<RealType, Order>::multiply_assign_by_root_type(bool is_root,
1332                                                                            root_type const& ca) {
1333   auto itr = v.begin();
1334   if constexpr (is_fvar<RealType>::value) {
1335     itr->multiply_assign_by_root_type(is_root, ca);
1336     for (++itr; itr != v.end(); ++itr)
1337       itr->multiply_assign_by_root_type(false, ca);
1338   } else {
1339     if (is_root || *itr != 0)
1340       *itr *= ca;  // Skip multiplication of 0 by ca=inf to avoid nan, except when is_root.
1341     for (++itr; itr != v.end(); ++itr)
1342       if (*itr != 0)
1343         *itr *= ca;
1344   }
1345   return *this;
1346 }
1347 #endif
1348 
1349 template <typename RealType, size_t Order>
1350 fvar<RealType, Order>::operator root_type() const {
1351   return static_cast<root_type>(v.front());
1352 }
1353 
1354 template <typename RealType, size_t Order>
1355 template <typename T, typename>
1356 fvar<RealType, Order>::operator T() const {
1357   return static_cast<T>(static_cast<root_type>(v.front()));
1358 }
1359 
1360 #ifndef BOOST_MATH_NO_CXX17_IF_CONSTEXPR
1361 template <typename RealType, size_t Order>
1362 fvar<RealType, Order>& fvar<RealType, Order>::set_root(root_type const& root) {
1363   if constexpr (is_fvar<RealType>::value)
1364     v.front().set_root(root);
1365   else
1366     v.front() = root;
1367   return *this;
1368 }
1369 #endif
1370 
1371 // Standard Library Support Requirements
1372 
1373 template <typename RealType, size_t Order>
1374 fvar<RealType, Order> fabs(fvar<RealType, Order> const& cr) {
1375   typename fvar<RealType, Order>::root_type const zero(0);
1376   return cr < zero ? -cr
1377                    : cr == zero ? fvar<RealType, Order>()  // Canonical fabs'(0) = 0.
1378                                 : cr;                      // Propagate NaN.
1379 }
1380 
1381 template <typename RealType, size_t Order>
1382 fvar<RealType, Order> abs(fvar<RealType, Order> const& cr) {
1383   return fabs(cr);
1384 }
1385 
1386 template <typename RealType, size_t Order>
1387 fvar<RealType, Order> ceil(fvar<RealType, Order> const& cr) {
1388   using std::ceil;
1389   return fvar<RealType, Order>(ceil(static_cast<typename fvar<RealType, Order>::root_type>(cr)));
1390 }
1391 
1392 template <typename RealType, size_t Order>
1393 fvar<RealType, Order> floor(fvar<RealType, Order> const& cr) {
1394   using std::floor;
1395   return fvar<RealType, Order>(floor(static_cast<typename fvar<RealType, Order>::root_type>(cr)));
1396 }
1397 
1398 template <typename RealType, size_t Order>
1399 fvar<RealType, Order> exp(fvar<RealType, Order> const& cr) {
1400   using std::exp;
1401   constexpr size_t order = fvar<RealType, Order>::order_sum;
1402   using root_type = typename fvar<RealType, Order>::root_type;
1403   root_type const d0 = exp(static_cast<root_type>(cr));
1404   return cr.apply_derivatives(order, [&d0](size_t) { return d0; });
1405 }
1406 
1407 template <typename RealType, size_t Order>
1408 fvar<RealType, Order> pow(fvar<RealType, Order> const& x,
1409                           typename fvar<RealType, Order>::root_type const& y) {
1410   BOOST_MATH_STD_USING
1411   using root_type = typename fvar<RealType, Order>::root_type;
1412   constexpr size_t order = fvar<RealType, Order>::order_sum;
1413   root_type const x0 = static_cast<root_type>(x);
1414   root_type derivatives[order + 1]{pow(x0, y)};
1415   if (fabs(x0) < std::numeric_limits<root_type>::epsilon()) {
1416     root_type coef = 1;
1417     for (size_t i = 0; i < order && y - i != 0; ++i) {
1418       coef *= y - i;
1419       derivatives[i + 1] = coef * pow(x0, y - (i + 1));
1420     }
1421     return x.apply_derivatives_nonhorner(order, [&derivatives](size_t i) { return derivatives[i]; });
1422   } else {
1423     for (size_t i = 0; i < order && y - i != 0; ++i)
1424       derivatives[i + 1] = (y - i) * derivatives[i] / x0;
1425     return x.apply_derivatives(order, [&derivatives](size_t i) { return derivatives[i]; });
1426   }
1427 }
1428 
1429 template <typename RealType, size_t Order>
1430 fvar<RealType, Order> pow(typename fvar<RealType, Order>::root_type const& x,
1431                           fvar<RealType, Order> const& y) {
1432   BOOST_MATH_STD_USING
1433   using root_type = typename fvar<RealType, Order>::root_type;
1434   constexpr size_t order = fvar<RealType, Order>::order_sum;
1435   root_type const y0 = static_cast<root_type>(y);
1436   root_type derivatives[order + 1];
1437   *derivatives = pow(x, y0);
1438   root_type const logx = log(x);
1439   for (size_t i = 0; i < order; ++i)
1440     derivatives[i + 1] = derivatives[i] * logx;
1441   return y.apply_derivatives(order, [&derivatives](size_t i) { return derivatives[i]; });
1442 }
1443 
1444 template <typename RealType1, size_t Order1, typename RealType2, size_t Order2>
1445 promote<fvar<RealType1, Order1>, fvar<RealType2, Order2>> pow(fvar<RealType1, Order1> const& x,
1446                                                               fvar<RealType2, Order2> const& y) {
1447   BOOST_MATH_STD_USING
1448   using return_type = promote<fvar<RealType1, Order1>, fvar<RealType2, Order2>>;
1449   using root_type = typename return_type::root_type;
1450   constexpr size_t order = return_type::order_sum;
1451   root_type const x0 = static_cast<root_type>(x);
1452   root_type const y0 = static_cast<root_type>(y);
1453   root_type dxydx[order + 1]{pow(x0, y0)};
1454   BOOST_MATH_IF_CONSTEXPR (order == 0)
1455     return return_type(*dxydx);
1456   else {
1457     for (size_t i = 0; i < order && y0 - i != 0; ++i)
1458       dxydx[i + 1] = (y0 - i) * dxydx[i] / x0;
1459     std::array<fvar<root_type, order>, order + 1> lognx;
1460     lognx.front() = fvar<root_type, order>(1);
1461 #ifndef BOOST_MATH_NO_CXX17_IF_CONSTEXPR
1462     lognx[1] = log(make_fvar<root_type, order>(x0));
1463 #else  // for compilers that compile this branch when order == 0.
1464     lognx[(std::min)(size_t(1), order)] = log(make_fvar<root_type, order>(x0));
1465 #endif
1466     for (size_t i = 1; i < order; ++i)
1467       lognx[i + 1] = lognx[i] * lognx[1];
1468     auto const f = [&dxydx, &lognx](size_t i, size_t j) {
1469       size_t binomial = 1;
1470       root_type sum = dxydx[i] * static_cast<root_type>(lognx[j]);
1471       for (size_t k = 1; k <= i; ++k) {
1472         (binomial *= (i - k + 1)) /= k;  // binomial_coefficient(i,k)
1473         sum += binomial * dxydx[i - k] * lognx[j].derivative(k);
1474       }
1475       return sum;
1476     };
1477     if (fabs(x0) < std::numeric_limits<root_type>::epsilon())
1478       return x.apply_derivatives_nonhorner(order, f, y);
1479     return x.apply_derivatives(order, f, y);
1480   }
1481 }
1482 
1483 template <typename RealType, size_t Order>
1484 fvar<RealType, Order> sqrt(fvar<RealType, Order> const& cr) {
1485   using std::sqrt;
1486   using root_type = typename fvar<RealType, Order>::root_type;
1487   constexpr size_t order = fvar<RealType, Order>::order_sum;
1488   root_type derivatives[order + 1];
1489   root_type const x = static_cast<root_type>(cr);
1490   *derivatives = sqrt(x);
1491   BOOST_MATH_IF_CONSTEXPR (order == 0)
1492     return fvar<RealType, Order>(*derivatives);
1493   else {
1494     root_type numerator = root_type(0.5);
1495     root_type powers = 1;
1496 #ifndef BOOST_MATH_NO_CXX17_IF_CONSTEXPR
1497     derivatives[1] = numerator / *derivatives;
1498 #else  // for compilers that compile this branch when order == 0.
1499     derivatives[(std::min)(size_t(1), order)] = numerator / *derivatives;
1500 #endif
1501     using diff_t = typename std::array<RealType, Order + 1>::difference_type;
1502     for (size_t i = 2; i <= order; ++i) {
1503       numerator *= static_cast<root_type>(-0.5) * ((static_cast<diff_t>(i) << 1) - 3);
1504       powers *= x;
1505       derivatives[i] = numerator / (powers * *derivatives);
1506     }
1507     auto const f = [&derivatives](size_t i) { return derivatives[i]; };
1508     if (cr < std::numeric_limits<root_type>::epsilon())
1509       return cr.apply_derivatives_nonhorner(order, f);
1510     return cr.apply_derivatives(order, f);
1511   }
1512 }
1513 
1514 // Natural logarithm. If cr==0 then derivative(i) may have nans due to nans from inverse().
1515 template <typename RealType, size_t Order>
1516 fvar<RealType, Order> log(fvar<RealType, Order> const& cr) {
1517   using std::log;
1518   using root_type = typename fvar<RealType, Order>::root_type;
1519   constexpr size_t order = fvar<RealType, Order>::order_sum;
1520   root_type const d0 = log(static_cast<root_type>(cr));
1521   BOOST_MATH_IF_CONSTEXPR (order == 0)
1522     return fvar<RealType, Order>(d0);
1523   else {
1524     auto const d1 = make_fvar<root_type, bool(order) ? order - 1 : 0>(static_cast<root_type>(cr)).inverse();  // log'(x) = 1 / x
1525     return cr.apply_coefficients_nonhorner(order, [&d0, &d1](size_t i) { return i ? d1[i - 1] / i : d0; });
1526   }
1527 }
1528 
1529 template <typename RealType, size_t Order>
1530 fvar<RealType, Order> frexp(fvar<RealType, Order> const& cr, int* exp) {
1531   using std::exp2;
1532   using std::frexp;
1533   using root_type = typename fvar<RealType, Order>::root_type;
1534   frexp(static_cast<root_type>(cr), exp);
1535   return cr * static_cast<root_type>(exp2(-*exp));
1536 }
1537 
1538 template <typename RealType, size_t Order>
1539 fvar<RealType, Order> ldexp(fvar<RealType, Order> const& cr, int exp) {
1540   // argument to std::exp2 must be casted to root_type, otherwise std::exp2 returns double (always)
1541   using std::exp2;
1542   return cr * exp2(static_cast<typename fvar<RealType, Order>::root_type>(exp));
1543 }
1544 
1545 template <typename RealType, size_t Order>
1546 fvar<RealType, Order> cos(fvar<RealType, Order> const& cr) {
1547   BOOST_MATH_STD_USING
1548   using root_type = typename fvar<RealType, Order>::root_type;
1549   constexpr size_t order = fvar<RealType, Order>::order_sum;
1550   root_type const d0 = cos(static_cast<root_type>(cr));
1551   BOOST_MATH_IF_CONSTEXPR (order == 0)
1552     return fvar<RealType, Order>(d0);
1553   else {
1554     root_type const d1 = -sin(static_cast<root_type>(cr));
1555     root_type const derivatives[4]{d0, d1, -d0, -d1};
1556     return cr.apply_derivatives(order, [&derivatives](size_t i) { return derivatives[i & 3]; });
1557   }
1558 }
1559 
1560 template <typename RealType, size_t Order>
1561 fvar<RealType, Order> sin(fvar<RealType, Order> const& cr) {
1562   BOOST_MATH_STD_USING
1563   using root_type = typename fvar<RealType, Order>::root_type;
1564   constexpr size_t order = fvar<RealType, Order>::order_sum;
1565   root_type const d0 = sin(static_cast<root_type>(cr));
1566   BOOST_MATH_IF_CONSTEXPR (order == 0)
1567     return fvar<RealType, Order>(d0);
1568   else {
1569     root_type const d1 = cos(static_cast<root_type>(cr));
1570     root_type const derivatives[4]{d0, d1, -d0, -d1};
1571     return cr.apply_derivatives(order, [&derivatives](size_t i) { return derivatives[i & 3]; });
1572   }
1573 }
1574 
1575 template <typename RealType, size_t Order>
1576 fvar<RealType, Order> asin(fvar<RealType, Order> const& cr) {
1577   using std::asin;
1578   using root_type = typename fvar<RealType, Order>::root_type;
1579   constexpr size_t order = fvar<RealType, Order>::order_sum;
1580   root_type const d0 = asin(static_cast<root_type>(cr));
1581   BOOST_MATH_IF_CONSTEXPR (order == 0)
1582     return fvar<RealType, Order>(d0);
1583   else {
1584     auto x = make_fvar<root_type, bool(order) ? order - 1 : 0>(static_cast<root_type>(cr));
1585     auto const d1 = sqrt((x *= x).negate() += 1).inverse();  // asin'(x) = 1 / sqrt(1-x*x).
1586     return cr.apply_coefficients_nonhorner(order, [&d0, &d1](size_t i) { return i ? d1[i - 1] / i : d0; });
1587   }
1588 }
1589 
1590 template <typename RealType, size_t Order>
1591 fvar<RealType, Order> tan(fvar<RealType, Order> const& cr) {
1592   using std::tan;
1593   using root_type = typename fvar<RealType, Order>::root_type;
1594   constexpr size_t order = fvar<RealType, Order>::order_sum;
1595   root_type const d0 = tan(static_cast<root_type>(cr));
1596   BOOST_MATH_IF_CONSTEXPR (order == 0)
1597     return fvar<RealType, Order>(d0);
1598   else {
1599     auto c = cos(make_fvar<root_type, bool(order) ? order - 1 : 0>(static_cast<root_type>(cr)));
1600     auto const d1 = (c *= c).inverse();  // tan'(x) = 1 / cos(x)^2
1601     return cr.apply_coefficients_nonhorner(order, [&d0, &d1](size_t i) { return i ? d1[i - 1] / i : d0; });
1602   }
1603 }
1604 
1605 template <typename RealType, size_t Order>
1606 fvar<RealType, Order> atan(fvar<RealType, Order> const& cr) {
1607   using std::atan;
1608   using root_type = typename fvar<RealType, Order>::root_type;
1609   constexpr size_t order = fvar<RealType, Order>::order_sum;
1610   root_type const d0 = atan(static_cast<root_type>(cr));
1611   BOOST_MATH_IF_CONSTEXPR (order == 0)
1612     return fvar<RealType, Order>(d0);
1613   else {
1614     auto x = make_fvar<root_type, bool(order) ? order - 1 : 0>(static_cast<root_type>(cr));
1615     auto const d1 = ((x *= x) += 1).inverse();  // atan'(x) = 1 / (x*x+1).
1616     return cr.apply_coefficients(order, [&d0, &d1](size_t i) { return i ? d1[i - 1] / i : d0; });
1617   }
1618 }
1619 
1620 template <typename RealType, size_t Order>
1621 fvar<RealType, Order> atan2(fvar<RealType, Order> const& cr,
1622                             typename fvar<RealType, Order>::root_type const& ca) {
1623   using std::atan2;
1624   using root_type = typename fvar<RealType, Order>::root_type;
1625   constexpr size_t order = fvar<RealType, Order>::order_sum;
1626   root_type const d0 = atan2(static_cast<root_type>(cr), ca);
1627   BOOST_MATH_IF_CONSTEXPR (order == 0)
1628     return fvar<RealType, Order>(d0);
1629   else {
1630     auto y = make_fvar<root_type, bool(order) ? order - 1 : 0>(static_cast<root_type>(cr));
1631     auto const d1 = ca / ((y *= y) += (ca * ca));  // (d/dy)atan2(y,x) = x / (y*y+x*x)
1632     return cr.apply_coefficients(order, [&d0, &d1](size_t i) { return i ? d1[i - 1] / i : d0; });
1633   }
1634 }
1635 
1636 template <typename RealType, size_t Order>
1637 fvar<RealType, Order> atan2(typename fvar<RealType, Order>::root_type const& ca,
1638                             fvar<RealType, Order> const& cr) {
1639   using std::atan2;
1640   using root_type = typename fvar<RealType, Order>::root_type;
1641   constexpr size_t order = fvar<RealType, Order>::order_sum;
1642   root_type const d0 = atan2(ca, static_cast<root_type>(cr));
1643   BOOST_MATH_IF_CONSTEXPR (order == 0)
1644     return fvar<RealType, Order>(d0);
1645   else {
1646     auto x = make_fvar<root_type, bool(order) ? order - 1 : 0>(static_cast<root_type>(cr));
1647     auto const d1 = -ca / ((x *= x) += (ca * ca));  // (d/dx)atan2(y,x) = -y / (x*x+y*y)
1648     return cr.apply_coefficients(order, [&d0, &d1](size_t i) { return i ? d1[i - 1] / i : d0; });
1649   }
1650 }
1651 
1652 template <typename RealType1, size_t Order1, typename RealType2, size_t Order2>
1653 promote<fvar<RealType1, Order1>, fvar<RealType2, Order2>> atan2(fvar<RealType1, Order1> const& cr1,
1654                                                                 fvar<RealType2, Order2> const& cr2) {
1655   using std::atan2;
1656   using return_type = promote<fvar<RealType1, Order1>, fvar<RealType2, Order2>>;
1657   using root_type = typename return_type::root_type;
1658   constexpr size_t order = return_type::order_sum;
1659   root_type const y = static_cast<root_type>(cr1);
1660   root_type const x = static_cast<root_type>(cr2);
1661   root_type const d00 = atan2(y, x);
1662   BOOST_MATH_IF_CONSTEXPR (order == 0)
1663     return return_type(d00);
1664   else {
1665     constexpr size_t order1 = fvar<RealType1, Order1>::order_sum;
1666     constexpr size_t order2 = fvar<RealType2, Order2>::order_sum;
1667     auto x01 = make_fvar<typename fvar<RealType2, Order2>::root_type, order2 - 1>(x);
1668     auto const d01 = -y / ((x01 *= x01) += (y * y));
1669     auto y10 = make_fvar<typename fvar<RealType1, Order1>::root_type, order1 - 1>(y);
1670     auto x10 = make_fvar<typename fvar<RealType2, Order2>::root_type, 0, order2>(x);
1671     auto const d10 = x10 / ((x10 * x10) + (y10 *= y10));
1672     auto const f = [&d00, &d01, &d10](size_t i, size_t j) {
1673       return i ? d10[i - 1][j] / i : j ? d01[j - 1] / j : d00;
1674     };
1675     return cr1.apply_coefficients(order, f, cr2);
1676   }
1677 }
1678 
1679 template <typename RealType1, size_t Order1, typename RealType2, size_t Order2>
1680 promote<fvar<RealType1, Order1>, fvar<RealType2, Order2>> fmod(fvar<RealType1, Order1> const& cr1,
1681                                                                fvar<RealType2, Order2> const& cr2) {
1682   using boost::math::trunc;
1683   auto const numer = static_cast<typename fvar<RealType1, Order1>::root_type>(cr1);
1684   auto const denom = static_cast<typename fvar<RealType2, Order2>::root_type>(cr2);
1685   return cr1 - cr2 * trunc(numer / denom);
1686 }
1687 
1688 template <typename RealType, size_t Order>
1689 fvar<RealType, Order> round(fvar<RealType, Order> const& cr) {
1690   using boost::math::round;
1691   return fvar<RealType, Order>(round(static_cast<typename fvar<RealType, Order>::root_type>(cr)));
1692 }
1693 
1694 template <typename RealType, size_t Order>
1695 int iround(fvar<RealType, Order> const& cr) {
1696   using boost::math::iround;
1697   return iround(static_cast<typename fvar<RealType, Order>::root_type>(cr));
1698 }
1699 
1700 template <typename RealType, size_t Order>
1701 long lround(fvar<RealType, Order> const& cr) {
1702   using boost::math::lround;
1703   return lround(static_cast<typename fvar<RealType, Order>::root_type>(cr));
1704 }
1705 
1706 template <typename RealType, size_t Order>
1707 long long llround(fvar<RealType, Order> const& cr) {
1708   using boost::math::llround;
1709   return llround(static_cast<typename fvar<RealType, Order>::root_type>(cr));
1710 }
1711 
1712 template <typename RealType, size_t Order>
1713 fvar<RealType, Order> trunc(fvar<RealType, Order> const& cr) {
1714   using boost::math::trunc;
1715   return fvar<RealType, Order>(trunc(static_cast<typename fvar<RealType, Order>::root_type>(cr)));
1716 }
1717 
1718 template <typename RealType, size_t Order>
1719 long double truncl(fvar<RealType, Order> const& cr) {
1720   using std::truncl;
1721   return truncl(static_cast<typename fvar<RealType, Order>::root_type>(cr));
1722 }
1723 
1724 template <typename RealType, size_t Order>
1725 int itrunc(fvar<RealType, Order> const& cr) {
1726   using boost::math::itrunc;
1727   return itrunc(static_cast<typename fvar<RealType, Order>::root_type>(cr));
1728 }
1729 
1730 template <typename RealType, size_t Order>
1731 long long lltrunc(fvar<RealType, Order> const& cr) {
1732   using boost::math::lltrunc;
1733   return lltrunc(static_cast<typename fvar<RealType, Order>::root_type>(cr));
1734 }
1735 
1736 template <typename RealType, size_t Order>
1737 std::ostream& operator<<(std::ostream& out, fvar<RealType, Order> const& cr) {
1738   out << "depth(" << cr.depth << ")(" << cr.v.front();
1739   for (size_t i = 1; i <= Order; ++i)
1740     out << ',' << cr.v[i];
1741   return out << ')';
1742 }
1743 
1744 // Additional functions
1745 
1746 template <typename RealType, size_t Order>
1747 fvar<RealType, Order> acos(fvar<RealType, Order> const& cr) {
1748   using std::acos;
1749   using root_type = typename fvar<RealType, Order>::root_type;
1750   constexpr size_t order = fvar<RealType, Order>::order_sum;
1751   root_type const d0 = acos(static_cast<root_type>(cr));
1752   BOOST_MATH_IF_CONSTEXPR (order == 0)
1753     return fvar<RealType, Order>(d0);
1754   else {
1755     auto x = make_fvar<root_type, bool(order) ? order - 1 : 0>(static_cast<root_type>(cr));
1756     auto const d1 = sqrt((x *= x).negate() += 1).inverse().negate();  // acos'(x) = -1 / sqrt(1-x*x).
1757     return cr.apply_coefficients(order, [&d0, &d1](size_t i) { return i ? d1[i - 1] / i : d0; });
1758   }
1759 }
1760 
1761 template <typename RealType, size_t Order>
1762 fvar<RealType, Order> acosh(fvar<RealType, Order> const& cr) {
1763   using boost::math::acosh;
1764   using root_type = typename fvar<RealType, Order>::root_type;
1765   constexpr size_t order = fvar<RealType, Order>::order_sum;
1766   root_type const d0 = acosh(static_cast<root_type>(cr));
1767   BOOST_MATH_IF_CONSTEXPR (order == 0)
1768     return fvar<RealType, Order>(d0);
1769   else {
1770     auto x = make_fvar<root_type, bool(order) ? order - 1 : 0>(static_cast<root_type>(cr));
1771     auto const d1 = sqrt((x *= x) -= 1).inverse();  // acosh'(x) = 1 / sqrt(x*x-1).
1772     return cr.apply_coefficients(order, [&d0, &d1](size_t i) { return i ? d1[i - 1] / i : d0; });
1773   }
1774 }
1775 
1776 template <typename RealType, size_t Order>
1777 fvar<RealType, Order> asinh(fvar<RealType, Order> const& cr) {
1778   using boost::math::asinh;
1779   using root_type = typename fvar<RealType, Order>::root_type;
1780   constexpr size_t order = fvar<RealType, Order>::order_sum;
1781   root_type const d0 = asinh(static_cast<root_type>(cr));
1782   BOOST_MATH_IF_CONSTEXPR (order == 0)
1783     return fvar<RealType, Order>(d0);
1784   else {
1785     auto x = make_fvar<root_type, bool(order) ? order - 1 : 0>(static_cast<root_type>(cr));
1786     auto const d1 = sqrt((x *= x) += 1).inverse();  // asinh'(x) = 1 / sqrt(x*x+1).
1787     return cr.apply_coefficients(order, [&d0, &d1](size_t i) { return i ? d1[i - 1] / i : d0; });
1788   }
1789 }
1790 
1791 template <typename RealType, size_t Order>
1792 fvar<RealType, Order> atanh(fvar<RealType, Order> const& cr) {
1793   using boost::math::atanh;
1794   using root_type = typename fvar<RealType, Order>::root_type;
1795   constexpr size_t order = fvar<RealType, Order>::order_sum;
1796   root_type const d0 = atanh(static_cast<root_type>(cr));
1797   BOOST_MATH_IF_CONSTEXPR (order == 0)
1798     return fvar<RealType, Order>(d0);
1799   else {
1800     auto x = make_fvar<root_type, bool(order) ? order - 1 : 0>(static_cast<root_type>(cr));
1801     auto const d1 = ((x *= x).negate() += 1).inverse();  // atanh'(x) = 1 / (1-x*x)
1802     return cr.apply_coefficients(order, [&d0, &d1](size_t i) { return i ? d1[i - 1] / i : d0; });
1803   }
1804 }
1805 
1806 template <typename RealType, size_t Order>
1807 fvar<RealType, Order> cosh(fvar<RealType, Order> const& cr) {
1808   BOOST_MATH_STD_USING
1809   using root_type = typename fvar<RealType, Order>::root_type;
1810   constexpr size_t order = fvar<RealType, Order>::order_sum;
1811   root_type const d0 = cosh(static_cast<root_type>(cr));
1812   BOOST_MATH_IF_CONSTEXPR (order == 0)
1813     return fvar<RealType, Order>(d0);
1814   else {
1815     root_type const derivatives[2]{d0, sinh(static_cast<root_type>(cr))};
1816     return cr.apply_derivatives(order, [&derivatives](size_t i) { return derivatives[i & 1]; });
1817   }
1818 }
1819 
1820 template <typename RealType, size_t Order>
1821 fvar<RealType, Order> digamma(fvar<RealType, Order> const& cr) {
1822   using boost::math::digamma;
1823   using root_type = typename fvar<RealType, Order>::root_type;
1824   constexpr size_t order = fvar<RealType, Order>::order_sum;
1825   root_type const x = static_cast<root_type>(cr);
1826   root_type const d0 = digamma(x);
1827   BOOST_MATH_IF_CONSTEXPR (order == 0)
1828     return fvar<RealType, Order>(d0);
1829   else {
1830     static_assert(order <= static_cast<size_t>((std::numeric_limits<int>::max)()),
1831                   "order exceeds maximum derivative for boost::math::polygamma().");
1832     return cr.apply_derivatives(
1833         order, [&x, &d0](size_t i) { return i ? boost::math::polygamma(static_cast<int>(i), x) : d0; });
1834   }
1835 }
1836 
1837 template <typename RealType, size_t Order>
1838 fvar<RealType, Order> erf(fvar<RealType, Order> const& cr) {
1839   using boost::math::erf;
1840   using root_type = typename fvar<RealType, Order>::root_type;
1841   constexpr size_t order = fvar<RealType, Order>::order_sum;
1842   root_type const d0 = erf(static_cast<root_type>(cr));
1843   BOOST_MATH_IF_CONSTEXPR (order == 0)
1844     return fvar<RealType, Order>(d0);
1845   else {
1846     auto x = make_fvar<root_type, bool(order) ? order - 1 : 0>(static_cast<root_type>(cr));  // d1 = 2/sqrt(pi)*exp(-x*x)
1847     auto const d1 = 2 * constants::one_div_root_pi<root_type>() * exp((x *= x).negate());
1848     return cr.apply_coefficients(order, [&d0, &d1](size_t i) { return i ? d1[i - 1] / i : d0; });
1849   }
1850 }
1851 
1852 template <typename RealType, size_t Order>
1853 fvar<RealType, Order> erfc(fvar<RealType, Order> const& cr) {
1854   using boost::math::erfc;
1855   using root_type = typename fvar<RealType, Order>::root_type;
1856   constexpr size_t order = fvar<RealType, Order>::order_sum;
1857   root_type const d0 = erfc(static_cast<root_type>(cr));
1858   BOOST_MATH_IF_CONSTEXPR (order == 0)
1859     return fvar<RealType, Order>(d0);
1860   else {
1861     auto x = make_fvar<root_type, bool(order) ? order - 1 : 0>(static_cast<root_type>(cr));  // erfc'(x) = -erf'(x)
1862     auto const d1 = -2 * constants::one_div_root_pi<root_type>() * exp((x *= x).negate());
1863     return cr.apply_coefficients(order, [&d0, &d1](size_t i) { return i ? d1[i - 1] / i : d0; });
1864   }
1865 }
1866 
1867 template <typename RealType, size_t Order>
1868 fvar<RealType, Order> lambert_w0(fvar<RealType, Order> const& cr) {
1869   using std::exp;
1870   using boost::math::lambert_w0;
1871   using root_type = typename fvar<RealType, Order>::root_type;
1872   constexpr size_t order = fvar<RealType, Order>::order_sum;
1873   root_type derivatives[order + 1];
1874   *derivatives = lambert_w0(static_cast<root_type>(cr));
1875   BOOST_MATH_IF_CONSTEXPR (order == 0)
1876     return fvar<RealType, Order>(*derivatives);
1877   else {
1878     root_type const expw = exp(*derivatives);
1879     derivatives[1] = 1 / (static_cast<root_type>(cr) + expw);
1880     BOOST_MATH_IF_CONSTEXPR (order == 1)
1881       return cr.apply_derivatives_nonhorner(order, [&derivatives](size_t i) { return derivatives[i]; });
1882     else {
1883       using diff_t = typename std::array<RealType, Order + 1>::difference_type;
1884       root_type d1powers = derivatives[1] * derivatives[1];
1885       root_type const x = derivatives[1] * expw;
1886       derivatives[2] = d1powers * (-1 - x);
1887       std::array<root_type, order> coef{{-1, -1}};  // as in derivatives[2].
1888       for (size_t n = 3; n <= order; ++n) {
1889         coef[n - 1] = coef[n - 2] * -static_cast<root_type>(2 * n - 3);
1890         for (size_t j = n - 2; j != 0; --j)
1891           (coef[j] *= -static_cast<root_type>(n - 1)) -= (n + j - 2) * coef[j - 1];
1892         coef[0] *= -static_cast<root_type>(n - 1);
1893         d1powers *= derivatives[1];
1894         derivatives[n] =
1895             d1powers * std::accumulate(coef.crend() - diff_t(n - 1),
1896                                        coef.crend(),
1897                                        coef[n - 1],
1898                                        [&x](root_type const& a, root_type const& b) { return a * x + b; });
1899       }
1900       return cr.apply_derivatives_nonhorner(order, [&derivatives](size_t i) { return derivatives[i]; });
1901     }
1902   }
1903 }
1904 
1905 template <typename RealType, size_t Order>
1906 fvar<RealType, Order> lgamma(fvar<RealType, Order> const& cr) {
1907   using std::lgamma;
1908   using root_type = typename fvar<RealType, Order>::root_type;
1909   constexpr size_t order = fvar<RealType, Order>::order_sum;
1910   root_type const x = static_cast<root_type>(cr);
1911   root_type const d0 = lgamma(x);
1912   BOOST_MATH_IF_CONSTEXPR (order == 0)
1913     return fvar<RealType, Order>(d0);
1914   else {
1915     static_assert(order <= static_cast<size_t>((std::numeric_limits<int>::max)()) + 1,
1916                   "order exceeds maximum derivative for boost::math::polygamma().");
1917     return cr.apply_derivatives(
1918         order, [&x, &d0](size_t i) { return i ? boost::math::polygamma(static_cast<int>(i - 1), x) : d0; });
1919   }
1920 }
1921 
1922 template <typename RealType, size_t Order>
1923 fvar<RealType, Order> sinc(fvar<RealType, Order> const& cr) {
1924   if (cr != 0)
1925     return sin(cr) / cr;
1926   using root_type = typename fvar<RealType, Order>::root_type;
1927   constexpr size_t order = fvar<RealType, Order>::order_sum;
1928   root_type taylor[order + 1]{1};  // sinc(0) = 1
1929   BOOST_MATH_IF_CONSTEXPR (order == 0)
1930     return fvar<RealType, Order>(*taylor);
1931   else {
1932     for (size_t n = 2; n <= order; n += 2)
1933       taylor[n] = (1 - static_cast<int>(n & 2)) / factorial<root_type>(static_cast<unsigned>(n + 1));
1934     return cr.apply_coefficients_nonhorner(order, [&taylor](size_t i) { return taylor[i]; });
1935   }
1936 }
1937 
1938 template <typename RealType, size_t Order>
1939 fvar<RealType, Order> sinh(fvar<RealType, Order> const& cr) {
1940   BOOST_MATH_STD_USING
1941   using root_type = typename fvar<RealType, Order>::root_type;
1942   constexpr size_t order = fvar<RealType, Order>::order_sum;
1943   root_type const d0 = sinh(static_cast<root_type>(cr));
1944   BOOST_MATH_IF_CONSTEXPR (fvar<RealType, Order>::order_sum == 0)
1945     return fvar<RealType, Order>(d0);
1946   else {
1947     root_type const derivatives[2]{d0, cosh(static_cast<root_type>(cr))};
1948     return cr.apply_derivatives(order, [&derivatives](size_t i) { return derivatives[i & 1]; });
1949   }
1950 }
1951 
1952 template <typename RealType, size_t Order>
1953 fvar<RealType, Order> tanh(fvar<RealType, Order> const& cr) {
1954   fvar<RealType, Order> retval = exp(cr * 2);
1955   fvar<RealType, Order> const denom = retval + 1;
1956   (retval -= 1) /= denom;
1957   return retval;
1958 }
1959 
1960 template <typename RealType, size_t Order>
1961 fvar<RealType, Order> tgamma(fvar<RealType, Order> const& cr) {
1962   using std::tgamma;
1963   using root_type = typename fvar<RealType, Order>::root_type;
1964   constexpr size_t order = fvar<RealType, Order>::order_sum;
1965   BOOST_MATH_IF_CONSTEXPR (order == 0)
1966     return fvar<RealType, Order>(tgamma(static_cast<root_type>(cr)));
1967   else {
1968     if (cr < 0)
1969       return constants::pi<root_type>() / (sin(constants::pi<root_type>() * cr) * tgamma(1 - cr));
1970     return exp(lgamma(cr)).set_root(tgamma(static_cast<root_type>(cr)));
1971   }
1972 }
1973 
1974 }  // namespace detail
1975 }  // namespace autodiff_v1
1976 }  // namespace differentiation
1977 }  // namespace math
1978 }  // namespace boost
1979 
1980 namespace std {
1981 
1982 // boost::math::tools::digits<RealType>() is handled by this std::numeric_limits<> specialization,
1983 // and similarly for max_value, min_value, log_max_value, log_min_value, and epsilon.
1984 template <typename RealType, size_t Order>
1985 class numeric_limits<boost::math::differentiation::detail::fvar<RealType, Order>>
1986     : public numeric_limits<typename boost::math::differentiation::detail::fvar<RealType, Order>::root_type> {
1987 };
1988 
1989 }  // namespace std
1990 
1991 namespace boost {
1992 namespace math {
1993 namespace tools {
1994 namespace detail {
1995 
1996 template <typename RealType, std::size_t Order>
1997 using autodiff_fvar_type = differentiation::detail::fvar<RealType, Order>;
1998 
1999 template <typename RealType, std::size_t Order>
2000 using autodiff_root_type = typename autodiff_fvar_type<RealType, Order>::root_type;
2001 }  // namespace detail
2002 
2003 // See boost/math/tools/promotion.hpp
2004 template <typename RealType0, size_t Order0, typename RealType1, size_t Order1>
2005 struct promote_args<detail::autodiff_fvar_type<RealType0, Order0>,
2006                       detail::autodiff_fvar_type<RealType1, Order1>> {
2007   using type = detail::autodiff_fvar_type<typename promote_args<RealType0, RealType1>::type,
2008 #ifndef BOOST_MATH_NO_CXX14_CONSTEXPR
2009                                           (std::max)(Order0, Order1)>;
2010 #else
2011         Order0<Order1 ? Order1 : Order0>;
2012 #endif
2013 };
2014 
2015 template <typename RealType, size_t Order>
2016 struct promote_args<detail::autodiff_fvar_type<RealType, Order>> {
2017   using type = detail::autodiff_fvar_type<typename promote_args<RealType>::type, Order>;
2018 };
2019 
2020 template <typename RealType0, size_t Order0, typename RealType1>
2021 struct promote_args<detail::autodiff_fvar_type<RealType0, Order0>, RealType1> {
2022   using type = detail::autodiff_fvar_type<typename promote_args<RealType0, RealType1>::type, Order0>;
2023 };
2024 
2025 template <typename RealType0, typename RealType1, size_t Order1>
2026 struct promote_args<RealType0, detail::autodiff_fvar_type<RealType1, Order1>> {
2027   using type = detail::autodiff_fvar_type<typename promote_args<RealType0, RealType1>::type, Order1>;
2028 };
2029 
2030 template <typename destination_t, typename RealType, std::size_t Order>
2031 inline constexpr destination_t real_cast(detail::autodiff_fvar_type<RealType, Order> const& from_v)
2032     noexcept(BOOST_MATH_IS_FLOAT(destination_t) && BOOST_MATH_IS_FLOAT(RealType)) {
2033   return real_cast<destination_t>(static_cast<detail::autodiff_root_type<RealType, Order>>(from_v));
2034 }
2035 
2036 }  // namespace tools
2037 
2038 namespace policies {
2039 
2040 template <class Policy, std::size_t Order>
2041 using fvar_t = differentiation::detail::fvar<Policy, Order>;
2042 template <class Policy, std::size_t Order>
2043 struct evaluation<fvar_t<float, Order>, Policy> {
2044   using type = fvar_t<typename std::conditional<Policy::promote_float_type::value, double, float>::type, Order>;
2045 };
2046 
2047 template <class Policy, std::size_t Order>
2048 struct evaluation<fvar_t<double, Order>, Policy> {
2049   using type =
2050       fvar_t<typename std::conditional<Policy::promote_double_type::value, long double, double>::type, Order>;
2051 };
2052 
2053 }  // namespace policies
2054 }  // namespace math
2055 }  // namespace boost
2056 
2057 #ifdef BOOST_MATH_NO_CXX17_IF_CONSTEXPR
2058 #include "autodiff_cpp11.hpp"
2059 #endif
2060 
2061 #endif  // BOOST_MATH_DIFFERENTIATION_AUTODIFF_HPP