brintos

brintos / llvm-project-archived public Read only

0
0
Text · 80.9 KiB · b8880f2 Raw
2062 lines · plain
1//           Copyright Matthew Pulver 2018 - 2019.2// Distributed under the Boost Software License, Version 1.0.3//      (See accompanying file LICENSE_1_0.txt or copy at4//           https://www.boost.org/LICENSE_1_0.txt)5 6#ifndef BOOST_MATH_DIFFERENTIATION_AUTODIFF_HPP7#define BOOST_MATH_DIFFERENTIATION_AUTODIFF_HPP8 9#include <boost/cstdfloat.hpp>10#include <boost/math/constants/constants.hpp>11#include <boost/math/special_functions/trunc.hpp>12#include <boost/math/special_functions/round.hpp>13#include <boost/math/special_functions/acosh.hpp>14#include <boost/math/special_functions/asinh.hpp>15#include <boost/math/special_functions/atanh.hpp>16#include <boost/math/special_functions/digamma.hpp>17#include <boost/math/special_functions/polygamma.hpp>18#include <boost/math/special_functions/erf.hpp>19#include <boost/math/special_functions/lambert_w.hpp>20#include <boost/math/tools/config.hpp>21#include <boost/math/tools/promotion.hpp>22 23#include <algorithm>24#include <array>25#include <cmath>26#include <functional>27#include <limits>28#include <numeric>29#include <ostream>30#include <tuple>31#include <type_traits>32 33namespace boost {34namespace math {35namespace differentiation {36// Automatic Differentiation v137inline namespace autodiff_v1 {38namespace detail {39 40template <typename RealType, typename... RealTypes>41struct promote_args_n {42  using type = typename tools::promote_args<RealType, typename promote_args_n<RealTypes...>::type>::type;43};44 45template <typename RealType>46struct promote_args_n<RealType> {47  using type = typename tools::promote_arg<RealType>::type;48};49 50}  // namespace detail51 52template <typename RealType, typename... RealTypes>53using promote = typename detail::promote_args_n<RealType, RealTypes...>::type;54 55namespace detail {56 57template <typename RealType, size_t Order>58class fvar;59 60template <typename T>61struct is_fvar_impl : std::false_type {};62 63template <typename RealType, size_t Order>64struct is_fvar_impl<fvar<RealType, Order>> : std::true_type {};65 66template <typename T>67using is_fvar = is_fvar_impl<typename std::decay<T>::type>;68 69template <typename RealType, size_t Order, size_t... Orders>70struct nest_fvar {71  using type = fvar<typename nest_fvar<RealType, Orders...>::type, Order>;72};73 74template <typename RealType, size_t Order>75struct nest_fvar<RealType, Order> {76  using type = fvar<RealType, Order>;77};78 79template <typename>80struct get_depth_impl : std::integral_constant<size_t, 0> {};81 82template <typename RealType, size_t Order>83struct get_depth_impl<fvar<RealType, Order>>84    : std::integral_constant<size_t, get_depth_impl<RealType>::value + 1> {};85 86template <typename T>87using get_depth = get_depth_impl<typename std::decay<T>::type>;88 89template <typename>90struct get_order_sum_t : std::integral_constant<size_t, 0> {};91 92template <typename RealType, size_t Order>93struct get_order_sum_t<fvar<RealType, Order>>94    : std::integral_constant<size_t, get_order_sum_t<RealType>::value + Order> {};95 96template <typename T>97using get_order_sum = get_order_sum_t<typename std::decay<T>::type>;98 99template <typename RealType>100struct get_root_type {101  using type = RealType;102};103 104template <typename RealType, size_t Order>105struct get_root_type<fvar<RealType, Order>> {106  using type = typename get_root_type<RealType>::type;107};108 109template <typename RealType, size_t Depth>110struct type_at {111  using type = RealType;112};113 114template <typename RealType, size_t Order, size_t Depth>115struct type_at<fvar<RealType, Order>, Depth> {116  using type = typename std::conditional<Depth == 0,117                                         fvar<RealType, Order>,118                                         typename type_at<RealType, Depth - 1>::type>::type;119};120 121template <typename RealType, size_t Depth>122using get_type_at = typename type_at<RealType, Depth>::type;123 124// Satisfies Boost's Conceptual Requirements for Real Number Types.125// https://www.boost.org/libs/math/doc/html/math_toolkit/real_concepts.html126template <typename RealType, size_t Order>127class fvar {128 protected:129  std::array<RealType, Order + 1> v;130 131 public:132  using root_type = typename get_root_type<RealType>::type;  // RealType in the root fvar<RealType,Order>.133 134  fvar() = default;135 136  // Initialize a variable or constant.137  fvar(root_type const&, bool const is_variable);138 139  // RealType(cr) | RealType | RealType is copy constructible.140  fvar(fvar const&) = default;141 142  // Be aware of implicit casting from one fvar<> type to another by this copy constructor.143  template <typename RealType2, size_t Order2>144  fvar(fvar<RealType2, Order2> const&);145 146  // RealType(ca) | RealType | RealType is copy constructible from the arithmetic types.147  explicit fvar(root_type const&);  // Initialize a constant. (No epsilon terms.)148 149  template <typename RealType2>150  fvar(RealType2 const& ca);  // Supports any RealType2 for which static_cast<root_type>(ca) compiles.151 152  // r = cr | RealType& | Assignment operator.153  fvar& operator=(fvar const&) = default;154 155  // r = ca | RealType& | Assignment operator from the arithmetic types.156  // Handled by constructor that takes a single parameter of generic type.157  // fvar& operator=(root_type const&); // Set a constant.158 159  // r += cr | RealType& | Adds cr to r.160  template <typename RealType2, size_t Order2>161  fvar& operator+=(fvar<RealType2, Order2> const&);162 163  // r += ca | RealType& | Adds ar to r.164  fvar& operator+=(root_type const&);165 166  // r -= cr | RealType& | Subtracts cr from r.167  template <typename RealType2, size_t Order2>168  fvar& operator-=(fvar<RealType2, Order2> const&);169 170  // r -= ca | RealType& | Subtracts ca from r.171  fvar& operator-=(root_type const&);172 173  // r *= cr | RealType& | Multiplies r by cr.174  template <typename RealType2, size_t Order2>175  fvar& operator*=(fvar<RealType2, Order2> const&);176 177  // r *= ca | RealType& | Multiplies r by ca.178  fvar& operator*=(root_type const&);179 180  // r /= cr | RealType& | Divides r by cr.181  template <typename RealType2, size_t Order2>182  fvar& operator/=(fvar<RealType2, Order2> const&);183 184  // r /= ca | RealType& | Divides r by ca.185  fvar& operator/=(root_type const&);186 187  // -r | RealType | Unary Negation.188  fvar operator-() const;189 190  // +r | RealType& | Identity Operation.191  fvar const& operator+() const;192 193  // cr + cr2 | RealType | Binary Addition194  template <typename RealType2, size_t Order2>195  promote<fvar, fvar<RealType2, Order2>> operator+(fvar<RealType2, Order2> const&) const;196 197  // cr + ca | RealType | Binary Addition198  fvar operator+(root_type const&) const;199 200  // ca + cr | RealType | Binary Addition201  template <typename RealType2, size_t Order2>202  friend fvar<RealType2, Order2> operator+(typename fvar<RealType2, Order2>::root_type const&,203                                           fvar<RealType2, Order2> const&);204 205  // cr - cr2 | RealType | Binary Subtraction206  template <typename RealType2, size_t Order2>207  promote<fvar, fvar<RealType2, Order2>> operator-(fvar<RealType2, Order2> const&) const;208 209  // cr - ca | RealType | Binary Subtraction210  fvar operator-(root_type const&) const;211 212  // ca - cr | RealType | Binary Subtraction213  template <typename RealType2, size_t Order2>214  friend fvar<RealType2, Order2> operator-(typename fvar<RealType2, Order2>::root_type const&,215                                           fvar<RealType2, Order2> const&);216 217  // cr * cr2 | RealType | Binary Multiplication218  template <typename RealType2, size_t Order2>219  promote<fvar, fvar<RealType2, Order2>> operator*(fvar<RealType2, Order2> const&)const;220 221  // cr * ca | RealType | Binary Multiplication222  fvar operator*(root_type const&)const;223 224  // ca * cr | RealType | Binary Multiplication225  template <typename RealType2, size_t Order2>226  friend fvar<RealType2, Order2> operator*(typename fvar<RealType2, Order2>::root_type const&,227                                           fvar<RealType2, Order2> const&);228 229  // cr / cr2 | RealType | Binary Subtraction230  template <typename RealType2, size_t Order2>231  promote<fvar, fvar<RealType2, Order2>> operator/(fvar<RealType2, Order2> const&) const;232 233  // cr / ca | RealType | Binary Subtraction234  fvar operator/(root_type const&) const;235 236  // ca / cr | RealType | Binary Subtraction237  template <typename RealType2, size_t Order2>238  friend fvar<RealType2, Order2> operator/(typename fvar<RealType2, Order2>::root_type const&,239                                           fvar<RealType2, Order2> const&);240 241  // For all comparison overloads, only the root term is compared.242 243  // cr == cr2 | bool | Equality Comparison244  template <typename RealType2, size_t Order2>245  bool operator==(fvar<RealType2, Order2> const&) const;246 247  // cr == ca | bool | Equality Comparison248  bool operator==(root_type const&) const;249 250  // ca == cr | bool | Equality Comparison251  template <typename RealType2, size_t Order2>252  friend bool operator==(typename fvar<RealType2, Order2>::root_type const&, fvar<RealType2, Order2> const&);253 254  // cr != cr2 | bool | Inequality Comparison255  template <typename RealType2, size_t Order2>256  bool operator!=(fvar<RealType2, Order2> const&) const;257 258  // cr != ca | bool | Inequality Comparison259  bool operator!=(root_type const&) const;260 261  // ca != cr | bool | Inequality Comparison262  template <typename RealType2, size_t Order2>263  friend bool operator!=(typename fvar<RealType2, Order2>::root_type const&, fvar<RealType2, Order2> const&);264 265  // cr <= cr2 | bool | Less than equal to.266  template <typename RealType2, size_t Order2>267  bool operator<=(fvar<RealType2, Order2> const&) const;268 269  // cr <= ca | bool | Less than equal to.270  bool operator<=(root_type const&) const;271 272  // ca <= cr | bool | Less than equal to.273  template <typename RealType2, size_t Order2>274  friend bool operator<=(typename fvar<RealType2, Order2>::root_type const&, fvar<RealType2, Order2> const&);275 276  // cr >= cr2 | bool | Greater than equal to.277  template <typename RealType2, size_t Order2>278  bool operator>=(fvar<RealType2, Order2> const&) const;279 280  // cr >= ca | bool | Greater than equal to.281  bool operator>=(root_type const&) const;282 283  // ca >= cr | bool | Greater than equal to.284  template <typename RealType2, size_t Order2>285  friend bool operator>=(typename fvar<RealType2, Order2>::root_type const&, fvar<RealType2, Order2> const&);286 287  // cr < cr2 | bool | Less than comparison.288  template <typename RealType2, size_t Order2>289  bool operator<(fvar<RealType2, Order2> const&) const;290 291  // cr < ca | bool | Less than comparison.292  bool operator<(root_type const&) const;293 294  // ca < cr | bool | Less than comparison.295  template <typename RealType2, size_t Order2>296  friend bool operator<(typename fvar<RealType2, Order2>::root_type const&, fvar<RealType2, Order2> const&);297 298  // cr > cr2 | bool | Greater than comparison.299  template <typename RealType2, size_t Order2>300  bool operator>(fvar<RealType2, Order2> const&) const;301 302  // cr > ca | bool | Greater than comparison.303  bool operator>(root_type const&) const;304 305  // ca > cr | bool | Greater than comparison.306  template <typename RealType2, size_t Order2>307  friend bool operator>(typename fvar<RealType2, Order2>::root_type const&, fvar<RealType2, Order2> const&);308 309  // Will throw std::out_of_range if Order < order.310  template <typename... Orders>311  get_type_at<RealType, sizeof...(Orders)> at(size_t order, Orders... orders) const;312 313  template <typename... Orders>314  get_type_at<fvar, sizeof...(Orders)> derivative(Orders... orders) const;315 316  const RealType& operator[](size_t) const;317 318  fvar inverse() const;  // Multiplicative inverse.319 320  fvar& negate();  // Negate and return reference to *this.321 322  static constexpr size_t depth = get_depth<fvar>::value;  // Number of nested std::array<RealType,Order>.323 324  static constexpr size_t order_sum = get_order_sum<fvar>::value;325 326  explicit operator root_type() const;  // Must be explicit, otherwise overloaded operators are ambiguous.327 328  template <typename T, typename = typename std::enable_if<std::is_arithmetic<typename std::decay<T>::type>::value>>329  explicit operator T() const;  // Must be explicit; multiprecision has trouble without the std::enable_if330 331  fvar& set_root(root_type const&);332 333  // Apply coefficients using horner method.334  template <typename Func, typename Fvar, typename... Fvars>335  promote<fvar<RealType, Order>, Fvar, Fvars...> apply_coefficients(size_t const order,336                                                                    Func const& f,337                                                                    Fvar const& cr,338                                                                    Fvars&&... fvars) const;339 340  template <typename Func>341  fvar apply_coefficients(size_t const order, Func const& f) const;342 343  // Use when function returns derivative(i)/factorial(i) and may have some infinite derivatives.344  template <typename Func, typename Fvar, typename... Fvars>345  promote<fvar<RealType, Order>, Fvar, Fvars...> apply_coefficients_nonhorner(size_t const order,346                                                                              Func const& f,347                                                                              Fvar const& cr,348                                                                              Fvars&&... fvars) const;349 350  template <typename Func>351  fvar apply_coefficients_nonhorner(size_t const order, Func const& f) const;352 353  // Apply derivatives using horner method.354  template <typename Func, typename Fvar, typename... Fvars>355  promote<fvar<RealType, Order>, Fvar, Fvars...> apply_derivatives(size_t const order,356                                                                   Func const& f,357                                                                   Fvar const& cr,358                                                                   Fvars&&... fvars) const;359 360  template <typename Func>361  fvar apply_derivatives(size_t const order, Func const& f) const;362 363  // Use when function returns derivative(i) and may have some infinite derivatives.364  template <typename Func, typename Fvar, typename... Fvars>365  promote<fvar<RealType, Order>, Fvar, Fvars...> apply_derivatives_nonhorner(size_t const order,366                                                                             Func const& f,367                                                                             Fvar const& cr,368                                                                             Fvars&&... fvars) const;369 370  template <typename Func>371  fvar apply_derivatives_nonhorner(size_t const order, Func const& f) const;372 373 private:374  RealType epsilon_inner_product(size_t z0,375                                 size_t isum0,376                                 size_t m0,377                                 fvar const& cr,378                                 size_t z1,379                                 size_t isum1,380                                 size_t m1,381                                 size_t j) const;382 383  fvar epsilon_multiply(size_t z0, size_t isum0, fvar const& cr, size_t z1, size_t isum1) const;384 385  fvar epsilon_multiply(size_t z0, size_t isum0, root_type const& ca) const;386 387  fvar inverse_apply() const;388 389  fvar& multiply_assign_by_root_type(bool is_root, root_type const&);390 391  template <typename RealType2, size_t Orders2>392  friend class fvar;393 394  template <typename RealType2, size_t Order2>395  friend std::ostream& operator<<(std::ostream&, fvar<RealType2, Order2> const&);396 397  // C++11 Compatibility398#ifdef BOOST_MATH_NO_CXX17_IF_CONSTEXPR399  template <typename RootType>400  void fvar_cpp11(std::true_type, RootType const& ca, bool const is_variable);401 402  template <typename RootType>403  void fvar_cpp11(std::false_type, RootType const& ca, bool const is_variable);404 405  template <typename... Orders>406  get_type_at<RealType, sizeof...(Orders)> at_cpp11(std::true_type, size_t order, Orders... orders) const;407 408  template <typename... Orders>409  get_type_at<RealType, sizeof...(Orders)> at_cpp11(std::false_type, size_t order, Orders... orders) const;410 411  template <typename SizeType>412  fvar epsilon_multiply_cpp11(std::true_type,413                              SizeType z0,414                              size_t isum0,415                              fvar const& cr,416                              size_t z1,417                              size_t isum1) const;418 419  template <typename SizeType>420  fvar epsilon_multiply_cpp11(std::false_type,421                              SizeType z0,422                              size_t isum0,423                              fvar const& cr,424                              size_t z1,425                              size_t isum1) const;426 427  template <typename SizeType>428  fvar epsilon_multiply_cpp11(std::true_type, SizeType z0, size_t isum0, root_type const& ca) const;429 430  template <typename SizeType>431  fvar epsilon_multiply_cpp11(std::false_type, SizeType z0, size_t isum0, root_type const& ca) const;432 433  template <typename RootType>434  fvar& multiply_assign_by_root_type_cpp11(std::true_type, bool is_root, RootType const& ca);435 436  template <typename RootType>437  fvar& multiply_assign_by_root_type_cpp11(std::false_type, bool is_root, RootType const& ca);438 439  template <typename RootType>440  fvar& negate_cpp11(std::true_type, RootType const&);441 442  template <typename RootType>443  fvar& negate_cpp11(std::false_type, RootType const&);444 445  template <typename RootType>446  fvar& set_root_cpp11(std::true_type, RootType const& root);447 448  template <typename RootType>449  fvar& set_root_cpp11(std::false_type, RootType const& root);450#endif451};452 453// Standard Library Support Requirements454 455// fabs(cr1) | RealType456template <typename RealType, size_t Order>457fvar<RealType, Order> fabs(fvar<RealType, Order> const&);458 459// abs(cr1) | RealType460template <typename RealType, size_t Order>461fvar<RealType, Order> abs(fvar<RealType, Order> const&);462 463// ceil(cr1) | RealType464template <typename RealType, size_t Order>465fvar<RealType, Order> ceil(fvar<RealType, Order> const&);466 467// floor(cr1) | RealType468template <typename RealType, size_t Order>469fvar<RealType, Order> floor(fvar<RealType, Order> const&);470 471// exp(cr1) | RealType472template <typename RealType, size_t Order>473fvar<RealType, Order> exp(fvar<RealType, Order> const&);474 475// pow(cr, ca) | RealType476template <typename RealType, size_t Order>477fvar<RealType, Order> pow(fvar<RealType, Order> const&, typename fvar<RealType, Order>::root_type const&);478 479// pow(ca, cr) | RealType480template <typename RealType, size_t Order>481fvar<RealType, Order> pow(typename fvar<RealType, Order>::root_type const&, fvar<RealType, Order> const&);482 483// pow(cr1, cr2) | RealType484template <typename RealType1, size_t Order1, typename RealType2, size_t Order2>485promote<fvar<RealType1, Order1>, fvar<RealType2, Order2>> pow(fvar<RealType1, Order1> const&,486                                                              fvar<RealType2, Order2> const&);487 488// sqrt(cr1) | RealType489template <typename RealType, size_t Order>490fvar<RealType, Order> sqrt(fvar<RealType, Order> const&);491 492// log(cr1) | RealType493template <typename RealType, size_t Order>494fvar<RealType, Order> log(fvar<RealType, Order> const&);495 496// frexp(cr1, &i) | RealType497template <typename RealType, size_t Order>498fvar<RealType, Order> frexp(fvar<RealType, Order> const&, int*);499 500// ldexp(cr1, i) | RealType501template <typename RealType, size_t Order>502fvar<RealType, Order> ldexp(fvar<RealType, Order> const&, int);503 504// cos(cr1) | RealType505template <typename RealType, size_t Order>506fvar<RealType, Order> cos(fvar<RealType, Order> const&);507 508// sin(cr1) | RealType509template <typename RealType, size_t Order>510fvar<RealType, Order> sin(fvar<RealType, Order> const&);511 512// asin(cr1) | RealType513template <typename RealType, size_t Order>514fvar<RealType, Order> asin(fvar<RealType, Order> const&);515 516// tan(cr1) | RealType517template <typename RealType, size_t Order>518fvar<RealType, Order> tan(fvar<RealType, Order> const&);519 520// atan(cr1) | RealType521template <typename RealType, size_t Order>522fvar<RealType, Order> atan(fvar<RealType, Order> const&);523 524// atan2(cr, ca) | RealType525template <typename RealType, size_t Order>526fvar<RealType, Order> atan2(fvar<RealType, Order> const&, typename fvar<RealType, Order>::root_type const&);527 528// atan2(ca, cr) | RealType529template <typename RealType, size_t Order>530fvar<RealType, Order> atan2(typename fvar<RealType, Order>::root_type const&, fvar<RealType, Order> const&);531 532// atan2(cr1, cr2) | RealType533template <typename RealType1, size_t Order1, typename RealType2, size_t Order2>534promote<fvar<RealType1, Order1>, fvar<RealType2, Order2>> atan2(fvar<RealType1, Order1> const&,535                                                                fvar<RealType2, Order2> const&);536 537// fmod(cr1,cr2) | RealType538template <typename RealType1, size_t Order1, typename RealType2, size_t Order2>539promote<fvar<RealType1, Order1>, fvar<RealType2, Order2>> fmod(fvar<RealType1, Order1> const&,540                                                               fvar<RealType2, Order2> const&);541 542// round(cr1) | RealType543template <typename RealType, size_t Order>544fvar<RealType, Order> round(fvar<RealType, Order> const&);545 546// iround(cr1) | int547template <typename RealType, size_t Order>548int iround(fvar<RealType, Order> const&);549 550template <typename RealType, size_t Order>551long lround(fvar<RealType, Order> const&);552 553template <typename RealType, size_t Order>554long long llround(fvar<RealType, Order> const&);555 556// trunc(cr1) | RealType557template <typename RealType, size_t Order>558fvar<RealType, Order> trunc(fvar<RealType, Order> const&);559 560template <typename RealType, size_t Order>561long double truncl(fvar<RealType, Order> const&);562 563// itrunc(cr1) | int564template <typename RealType, size_t Order>565int itrunc(fvar<RealType, Order> const&);566 567template <typename RealType, size_t Order>568long long lltrunc(fvar<RealType, Order> const&);569 570// Additional functions571template <typename RealType, size_t Order>572fvar<RealType, Order> acos(fvar<RealType, Order> const&);573 574template <typename RealType, size_t Order>575fvar<RealType, Order> acosh(fvar<RealType, Order> const&);576 577template <typename RealType, size_t Order>578fvar<RealType, Order> asinh(fvar<RealType, Order> const&);579 580template <typename RealType, size_t Order>581fvar<RealType, Order> atanh(fvar<RealType, Order> const&);582 583template <typename RealType, size_t Order>584fvar<RealType, Order> cosh(fvar<RealType, Order> const&);585 586template <typename RealType, size_t Order>587fvar<RealType, Order> digamma(fvar<RealType, Order> const&);588 589template <typename RealType, size_t Order>590fvar<RealType, Order> erf(fvar<RealType, Order> const&);591 592template <typename RealType, size_t Order>593fvar<RealType, Order> erfc(fvar<RealType, Order> const&);594 595template <typename RealType, size_t Order>596fvar<RealType, Order> lambert_w0(fvar<RealType, Order> const&);597 598template <typename RealType, size_t Order>599fvar<RealType, Order> lgamma(fvar<RealType, Order> const&);600 601template <typename RealType, size_t Order>602fvar<RealType, Order> sinc(fvar<RealType, Order> const&);603 604template <typename RealType, size_t Order>605fvar<RealType, Order> sinh(fvar<RealType, Order> const&);606 607template <typename RealType, size_t Order>608fvar<RealType, Order> tanh(fvar<RealType, Order> const&);609 610template <typename RealType, size_t Order>611fvar<RealType, Order> tgamma(fvar<RealType, Order> const&);612 613template <size_t>614struct zero : std::integral_constant<size_t, 0> {};615 616}  // namespace detail617 618template <typename RealType, size_t Order, size_t... Orders>619using autodiff_fvar = typename detail::nest_fvar<RealType, Order, Orders...>::type;620 621template <typename RealType, size_t Order, size_t... Orders>622autodiff_fvar<RealType, Order, Orders...> make_fvar(RealType const& ca) {623  return autodiff_fvar<RealType, Order, Orders...>(ca, true);624}625 626#ifndef BOOST_MATH_NO_CXX17_IF_CONSTEXPR627namespace detail {628 629template <typename RealType, size_t Order, size_t... Is>630auto make_fvar_for_tuple(std::index_sequence<Is...>, RealType const& ca) {631  return make_fvar<RealType, zero<Is>::value..., Order>(ca);632}633 634template <typename RealType, size_t... Orders, size_t... Is, typename... RealTypes>635auto make_ftuple_impl(std::index_sequence<Is...>, RealTypes const&... ca) {636  return std::make_tuple(make_fvar_for_tuple<RealType, Orders>(std::make_index_sequence<Is>{}, ca)...);637}638 639}  // namespace detail640 641template <typename RealType, size_t... Orders, typename... RealTypes>642auto make_ftuple(RealTypes const&... ca) {643  static_assert(sizeof...(Orders) == sizeof...(RealTypes),644                "Number of Orders must match number of function parameters.");645  return detail::make_ftuple_impl<RealType, Orders...>(std::index_sequence_for<RealTypes...>{}, ca...);646}647#endif648 649namespace detail {650 651#ifndef BOOST_MATH_NO_CXX17_IF_CONSTEXPR652template <typename RealType, size_t Order>653fvar<RealType, Order>::fvar(root_type const& ca, bool const is_variable) {654  if constexpr (is_fvar<RealType>::value) {655    v.front() = RealType(ca, is_variable);656    if constexpr (0 < Order)657      std::fill(v.begin() + 1, v.end(), static_cast<RealType>(0));658  } else {659    v.front() = ca;660    if constexpr (0 < Order)661      v[1] = static_cast<root_type>(static_cast<int>(is_variable));662    if constexpr (1 < Order)663      std::fill(v.begin() + 2, v.end(), static_cast<RealType>(0));664  }665}666#endif667 668template <typename RealType, size_t Order>669template <typename RealType2, size_t Order2>670fvar<RealType, Order>::fvar(fvar<RealType2, Order2> const& cr) {671  for (size_t i = 0; i <= (std::min)(Order, Order2); ++i)672    v[i] = static_cast<RealType>(cr.v[i]);673  BOOST_MATH_IF_CONSTEXPR (Order2 < Order)674    std::fill(v.begin() + (Order2 + 1), v.end(), static_cast<RealType>(0));675}676 677template <typename RealType, size_t Order>678fvar<RealType, Order>::fvar(root_type const& ca) : v{{static_cast<RealType>(ca)}} {}679 680// Can cause compiler error if RealType2 cannot be cast to root_type.681template <typename RealType, size_t Order>682template <typename RealType2>683fvar<RealType, Order>::fvar(RealType2 const& ca) : v{{static_cast<RealType>(ca)}} {}684 685/*686template<typename RealType, size_t Order>687fvar<RealType,Order>& fvar<RealType,Order>::operator=(root_type const& ca)688{689    v.front() = static_cast<RealType>(ca);690    if constexpr (0 < Order)691        std::fill(v.begin()+1, v.end(), static_cast<RealType>(0));692    return *this;693}694*/695 696template <typename RealType, size_t Order>697template <typename RealType2, size_t Order2>698fvar<RealType, Order>& fvar<RealType, Order>::operator+=(fvar<RealType2, Order2> const& cr) {699  for (size_t i = 0; i <= (std::min)(Order, Order2); ++i)700    v[i] += cr.v[i];701  return *this;702}703 704template <typename RealType, size_t Order>705fvar<RealType, Order>& fvar<RealType, Order>::operator+=(root_type const& ca) {706  v.front() += ca;707  return *this;708}709 710template <typename RealType, size_t Order>711template <typename RealType2, size_t Order2>712fvar<RealType, Order>& fvar<RealType, Order>::operator-=(fvar<RealType2, Order2> const& cr) {713  for (size_t i = 0; i <= Order; ++i)714    v[i] -= cr.v[i];715  return *this;716}717 718template <typename RealType, size_t Order>719fvar<RealType, Order>& fvar<RealType, Order>::operator-=(root_type const& ca) {720  v.front() -= ca;721  return *this;722}723 724template <typename RealType, size_t Order>725template <typename RealType2, size_t Order2>726fvar<RealType, Order>& fvar<RealType, Order>::operator*=(fvar<RealType2, Order2> const& cr) {727  using diff_t = typename std::array<RealType, Order + 1>::difference_type;728  promote<RealType, RealType2> const zero(0);729  BOOST_MATH_IF_CONSTEXPR (Order <= Order2)730    for (size_t i = 0, j = Order; i <= Order; ++i, --j)731      v[j] = std::inner_product(v.cbegin(), v.cend() - diff_t(i), cr.v.crbegin() + diff_t(i), zero);732  else {733    for (size_t i = 0, j = Order; i <= Order - Order2; ++i, --j)734      v[j] = std::inner_product(cr.v.cbegin(), cr.v.cend(), v.crbegin() + diff_t(i), zero);735    for (size_t i = Order - Order2 + 1, j = Order2 - 1; i <= Order; ++i, --j)736      v[j] = std::inner_product(cr.v.cbegin(), cr.v.cbegin() + diff_t(j + 1), v.crbegin() + diff_t(i), zero);737  }738  return *this;739}740 741template <typename RealType, size_t Order>742fvar<RealType, Order>& fvar<RealType, Order>::operator*=(root_type const& ca) {743  return multiply_assign_by_root_type(true, ca);744}745 746template <typename RealType, size_t Order>747template <typename RealType2, size_t Order2>748fvar<RealType, Order>& fvar<RealType, Order>::operator/=(fvar<RealType2, Order2> const& cr) {749  using diff_t = typename std::array<RealType, Order + 1>::difference_type;750  RealType const zero(0);751  v.front() /= cr.v.front();752  BOOST_MATH_IF_CONSTEXPR (Order < Order2)753    for (size_t i = 1, j = Order2 - 1, k = Order; i <= Order; ++i, --j, --k)754      (v[i] -= std::inner_product(755           cr.v.cbegin() + 1, cr.v.cend() - diff_t(j), v.crbegin() + diff_t(k), zero)) /= cr.v.front();756  else BOOST_MATH_IF_CONSTEXPR (0 < Order2)757    for (size_t i = 1, j = Order2 - 1, k = Order; i <= Order; ++i, j && --j, --k)758      (v[i] -= std::inner_product(759           cr.v.cbegin() + 1, cr.v.cend() - diff_t(j), v.crbegin() + diff_t(k), zero)) /= cr.v.front();760  else761    for (size_t i = 1; i <= Order; ++i)762      v[i] /= cr.v.front();763  return *this;764}765 766template <typename RealType, size_t Order>767fvar<RealType, Order>& fvar<RealType, Order>::operator/=(root_type const& ca) {768  std::for_each(v.begin(), v.end(), [&ca](RealType& x) { x /= ca; });769  return *this;770}771 772template <typename RealType, size_t Order>773fvar<RealType, Order> fvar<RealType, Order>::operator-() const {774  fvar<RealType, Order> retval(*this);775  retval.negate();776  return retval;777}778 779template <typename RealType, size_t Order>780fvar<RealType, Order> const& fvar<RealType, Order>::operator+() const {781  return *this;782}783 784template <typename RealType, size_t Order>785template <typename RealType2, size_t Order2>786promote<fvar<RealType, Order>, fvar<RealType2, Order2>> fvar<RealType, Order>::operator+(787    fvar<RealType2, Order2> const& cr) const {788  promote<fvar<RealType, Order>, fvar<RealType2, Order2>> retval;789  for (size_t i = 0; i <= (std::min)(Order, Order2); ++i)790    retval.v[i] = v[i] + cr.v[i];791  BOOST_MATH_IF_CONSTEXPR (Order < Order2)792    for (size_t i = Order + 1; i <= Order2; ++i)793      retval.v[i] = cr.v[i];794  else BOOST_MATH_IF_CONSTEXPR (Order2 < Order)795    for (size_t i = Order2 + 1; i <= Order; ++i)796      retval.v[i] = v[i];797  return retval;798}799 800template <typename RealType, size_t Order>801fvar<RealType, Order> fvar<RealType, Order>::operator+(root_type const& ca) const {802  fvar<RealType, Order> retval(*this);803  retval.v.front() += ca;804  return retval;805}806 807template <typename RealType, size_t Order>808fvar<RealType, Order> operator+(typename fvar<RealType, Order>::root_type const& ca,809                                fvar<RealType, Order> const& cr) {810  return cr + ca;811}812 813template <typename RealType, size_t Order>814template <typename RealType2, size_t Order2>815promote<fvar<RealType, Order>, fvar<RealType2, Order2>> fvar<RealType, Order>::operator-(816    fvar<RealType2, Order2> const& cr) const {817  promote<fvar<RealType, Order>, fvar<RealType2, Order2>> retval;818  for (size_t i = 0; i <= (std::min)(Order, Order2); ++i)819    retval.v[i] = v[i] - cr.v[i];820  BOOST_MATH_IF_CONSTEXPR (Order < Order2)821    for (auto i = Order + 1; i <= Order2; ++i)822      retval.v[i] = -cr.v[i];823  else BOOST_MATH_IF_CONSTEXPR (Order2 < Order)824    for (auto i = Order2 + 1; i <= Order; ++i)825      retval.v[i] = v[i];826  return retval;827}828 829template <typename RealType, size_t Order>830fvar<RealType, Order> fvar<RealType, Order>::operator-(root_type const& ca) const {831  fvar<RealType, Order> retval(*this);832  retval.v.front() -= ca;833  return retval;834}835 836template <typename RealType, size_t Order>837fvar<RealType, Order> operator-(typename fvar<RealType, Order>::root_type const& ca,838                                fvar<RealType, Order> const& cr) {839  fvar<RealType, Order> mcr = -cr;  // Has same address as retval in operator-() due to NRVO.840  mcr += ca;841  return mcr;  // <-- This allows for NRVO. The following does not. --> return mcr += ca;842}843 844template <typename RealType, size_t Order>845template <typename RealType2, size_t Order2>846promote<fvar<RealType, Order>, fvar<RealType2, Order2>> fvar<RealType, Order>::operator*(847    fvar<RealType2, Order2> const& cr) const {848  using diff_t = typename std::array<RealType, Order + 1>::difference_type;849  promote<RealType, RealType2> const zero(0);850  promote<fvar<RealType, Order>, fvar<RealType2, Order2>> retval;851  BOOST_MATH_IF_CONSTEXPR (Order < Order2)852    for (size_t i = 0, j = Order, k = Order2; i <= Order2; ++i, j && --j, --k)853      retval.v[i] = std::inner_product(v.cbegin(), v.cend() - diff_t(j), cr.v.crbegin() + diff_t(k), zero);854  else855    for (size_t i = 0, j = Order2, k = Order; i <= Order; ++i, j && --j, --k)856      retval.v[i] = std::inner_product(cr.v.cbegin(), cr.v.cend() - diff_t(j), v.crbegin() + diff_t(k), zero);857  return retval;858}859 860template <typename RealType, size_t Order>861fvar<RealType, Order> fvar<RealType, Order>::operator*(root_type const& ca) const {862  fvar<RealType, Order> retval(*this);863  retval *= ca;864  return retval;865}866 867template <typename RealType, size_t Order>868fvar<RealType, Order> operator*(typename fvar<RealType, Order>::root_type const& ca,869                                fvar<RealType, Order> const& cr) {870  return cr * ca;871}872 873template <typename RealType, size_t Order>874template <typename RealType2, size_t Order2>875promote<fvar<RealType, Order>, fvar<RealType2, Order2>> fvar<RealType, Order>::operator/(876    fvar<RealType2, Order2> const& cr) const {877  using diff_t = typename std::array<RealType, Order + 1>::difference_type;878  promote<RealType, RealType2> const zero(0);879  promote<fvar<RealType, Order>, fvar<RealType2, Order2>> retval;880  retval.v.front() = v.front() / cr.v.front();881  BOOST_MATH_IF_CONSTEXPR (Order < Order2) {882    for (size_t i = 1, j = Order2 - 1; i <= Order; ++i, --j)883      retval.v[i] =884          (v[i] - std::inner_product(885                      cr.v.cbegin() + 1, cr.v.cend() - diff_t(j), retval.v.crbegin() + diff_t(j + 1), zero)) /886          cr.v.front();887    for (size_t i = Order + 1, j = Order2 - Order - 1; i <= Order2; ++i, --j)888      retval.v[i] =889          -std::inner_product(890              cr.v.cbegin() + 1, cr.v.cend() - diff_t(j), retval.v.crbegin() + diff_t(j + 1), zero) /891          cr.v.front();892  } else BOOST_MATH_IF_CONSTEXPR (0 < Order2)893    for (size_t i = 1, j = Order2 - 1, k = Order; i <= Order; ++i, j && --j, --k)894      retval.v[i] =895          (v[i] - std::inner_product(896                      cr.v.cbegin() + 1, cr.v.cend() - diff_t(j), retval.v.crbegin() + diff_t(k), zero)) /897          cr.v.front();898  else899    for (size_t i = 1; i <= Order; ++i)900      retval.v[i] = v[i] / cr.v.front();901  return retval;902}903 904template <typename RealType, size_t Order>905fvar<RealType, Order> fvar<RealType, Order>::operator/(root_type const& ca) const {906  fvar<RealType, Order> retval(*this);907  retval /= ca;908  return retval;909}910 911template <typename RealType, size_t Order>912fvar<RealType, Order> operator/(typename fvar<RealType, Order>::root_type const& ca,913                                fvar<RealType, Order> const& cr) {914  using diff_t = typename std::array<RealType, Order + 1>::difference_type;915  fvar<RealType, Order> retval;916  retval.v.front() = ca / cr.v.front();917  BOOST_MATH_IF_CONSTEXPR (0 < Order) {918    RealType const zero(0);919    for (size_t i = 1, j = Order - 1; i <= Order; ++i, --j)920      retval.v[i] =921          -std::inner_product(922              cr.v.cbegin() + 1, cr.v.cend() - diff_t(j), retval.v.crbegin() + diff_t(j + 1), zero) /923          cr.v.front();924  }925  return retval;926}927 928template <typename RealType, size_t Order>929template <typename RealType2, size_t Order2>930bool fvar<RealType, Order>::operator==(fvar<RealType2, Order2> const& cr) const {931  return v.front() == cr.v.front();932}933 934template <typename RealType, size_t Order>935bool fvar<RealType, Order>::operator==(root_type const& ca) const {936  return v.front() == ca;937}938 939template <typename RealType, size_t Order>940bool operator==(typename fvar<RealType, Order>::root_type const& ca, fvar<RealType, Order> const& cr) {941  return ca == cr.v.front();942}943 944template <typename RealType, size_t Order>945template <typename RealType2, size_t Order2>946bool fvar<RealType, Order>::operator!=(fvar<RealType2, Order2> const& cr) const {947  return v.front() != cr.v.front();948}949 950template <typename RealType, size_t Order>951bool fvar<RealType, Order>::operator!=(root_type const& ca) const {952  return v.front() != ca;953}954 955template <typename RealType, size_t Order>956bool operator!=(typename fvar<RealType, Order>::root_type const& ca, fvar<RealType, Order> const& cr) {957  return ca != cr.v.front();958}959 960template <typename RealType, size_t Order>961template <typename RealType2, size_t Order2>962bool fvar<RealType, Order>::operator<=(fvar<RealType2, Order2> const& cr) const {963  return v.front() <= cr.v.front();964}965 966template <typename RealType, size_t Order>967bool fvar<RealType, Order>::operator<=(root_type const& ca) const {968  return v.front() <= ca;969}970 971template <typename RealType, size_t Order>972bool operator<=(typename fvar<RealType, Order>::root_type const& ca, fvar<RealType, Order> const& cr) {973  return ca <= cr.v.front();974}975 976template <typename RealType, size_t Order>977template <typename RealType2, size_t Order2>978bool fvar<RealType, Order>::operator>=(fvar<RealType2, Order2> const& cr) const {979  return v.front() >= cr.v.front();980}981 982template <typename RealType, size_t Order>983bool fvar<RealType, Order>::operator>=(root_type const& ca) const {984  return v.front() >= ca;985}986 987template <typename RealType, size_t Order>988bool operator>=(typename fvar<RealType, Order>::root_type const& ca, fvar<RealType, Order> const& cr) {989  return ca >= cr.v.front();990}991 992template <typename RealType, size_t Order>993template <typename RealType2, size_t Order2>994bool fvar<RealType, Order>::operator<(fvar<RealType2, Order2> const& cr) const {995  return v.front() < cr.v.front();996}997 998template <typename RealType, size_t Order>999bool fvar<RealType, Order>::operator<(root_type const& ca) const {1000  return v.front() < ca;1001}1002 1003template <typename RealType, size_t Order>1004bool operator<(typename fvar<RealType, Order>::root_type const& ca, fvar<RealType, Order> const& cr) {1005  return ca < cr.v.front();1006}1007 1008template <typename RealType, size_t Order>1009template <typename RealType2, size_t Order2>1010bool fvar<RealType, Order>::operator>(fvar<RealType2, Order2> const& cr) const {1011  return v.front() > cr.v.front();1012}1013 1014template <typename RealType, size_t Order>1015bool fvar<RealType, Order>::operator>(root_type const& ca) const {1016  return v.front() > ca;1017}1018 1019template <typename RealType, size_t Order>1020bool 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_CONSTEXPR1027// f : order -> derivative(order)/factorial(order)1028// Use this when you have the polynomial coefficients, rather than just the derivatives. E.g. See atan2().1029template <typename RealType, size_t Order>1030template <typename Func, typename Fvar, typename... Fvars>1031promote<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#endif1046 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().1049template <typename RealType, size_t Order>1050template <typename Func>1051fvar<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_CONSTEXPR1054  size_t i = (std::min)(order, order_sum);1055#else  // ODR-use of static constexpr1056  size_t i = order < order_sum ? order : order_sum;1057#endif1058  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_CONSTEXPR1065// f : order -> derivative(order)1066template <typename RealType, size_t Order>1067template <typename Func, typename Fvar, typename... Fvars>1068promote<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 i1075  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#endif1095 1096// f : order -> coefficient(order)1097template <typename RealType, size_t Order>1098template <typename Func>1099fvar<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 i1103  fvar<RealType, Order> accumulator = fvar<RealType, Order>(f(0u));1104#ifndef BOOST_MATH_NO_CXX17_IF_CONSTEXPR1105  size_t const i_max = (std::min)(order, order_sum);1106#else  // ODR-use of static constexpr1107  size_t const i_max = order < order_sum ? order : order_sum;1108#endif1109  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_CONSTEXPR1117// f : order -> derivative(order)1118template <typename RealType, size_t Order>1119template <typename Func, typename Fvar, typename... Fvars>1120promote<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#endif1139 1140// f : order -> derivative(order)1141template <typename RealType, size_t Order>1142template <typename Func>1143fvar<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_CONSTEXPR1146  size_t i = (std::min)(order, order_sum);1147#else  // ODR-use of static constexpr1148  size_t i = order < order_sum ? order : order_sum;1149#endif1150  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_CONSTEXPR1157// f : order -> derivative(order)1158template <typename RealType, size_t Order>1159template <typename Func, typename Fvar, typename... Fvars>1160promote<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 i1167  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#endif1188 1189// f : order -> derivative(order)1190template <typename RealType, size_t Order>1191template <typename Func>1192fvar<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 i1196  fvar<RealType, Order> accumulator = fvar<RealType, Order>(f(0u));1197#ifndef BOOST_MATH_NO_CXX17_IF_CONSTEXPR1198  size_t const i_max = (std::min)(order, order_sum);1199#else  // ODR-use of static constexpr1200  size_t const i_max = order < order_sum ? order : order_sum;1201#endif1202  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_CONSTEXPR1210// Can throw "std::out_of_range: array::at: __n (which is 7) >= _Nm (which is 7)"1211template <typename RealType, size_t Order>1212template <typename... Orders>1213get_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  else1217    return v.at(order);1218}1219#endif1220 1221#ifndef BOOST_MATH_NO_CXX17_IF_CONSTEXPR1222// Can throw "std::out_of_range: array::at: __n (which is 7) >= _Nm (which is 7)"1223template <typename RealType, size_t Order>1224template <typename... Orders>1225get_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#endif1233 1234template <typename RealType, size_t Order>1235const RealType& fvar<RealType, Order>::operator[](size_t i) const {1236  return v[i];1237}1238 1239template <typename RealType, size_t Order>1240RealType 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_CONSTEXPR1257template <typename RealType, size_t Order>1258fvar<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  else1273    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#endif1279 1280#ifndef BOOST_MATH_NO_CXX17_IF_CONSTEXPR1281// When called from outside this method, z0 should be non-zero. Otherwise if z0=0 then it will give an1282// 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.1284template <typename RealType, size_t Order>1285fvar<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  else1294    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#endif1300 1301template <typename RealType, size_t Order>1302fvar<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_CONSTEXPR1307template <typename RealType, size_t Order>1308fvar<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  else1312    std::for_each(v.begin(), v.end(), [](RealType& a) { a = -a; });1313  return *this;1314}1315#endif1316 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)1319template <typename RealType, size_t Order>1320fvar<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_CONSTEXPR1330template <typename RealType, size_t Order>1331fvar<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#endif1348 1349template <typename RealType, size_t Order>1350fvar<RealType, Order>::operator root_type() const {1351  return static_cast<root_type>(v.front());1352}1353 1354template <typename RealType, size_t Order>1355template <typename T, typename>1356fvar<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_CONSTEXPR1361template <typename RealType, size_t Order>1362fvar<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  else1366    v.front() = root;1367  return *this;1368}1369#endif1370 1371// Standard Library Support Requirements1372 1373template <typename RealType, size_t Order>1374fvar<RealType, Order> fabs(fvar<RealType, Order> const& cr) {1375  typename fvar<RealType, Order>::root_type const zero(0);1376  return cr < zero ? -cr1377                   : cr == zero ? fvar<RealType, Order>()  // Canonical fabs'(0) = 0.1378                                : cr;                      // Propagate NaN.1379}1380 1381template <typename RealType, size_t Order>1382fvar<RealType, Order> abs(fvar<RealType, Order> const& cr) {1383  return fabs(cr);1384}1385 1386template <typename RealType, size_t Order>1387fvar<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 1392template <typename RealType, size_t Order>1393fvar<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 1398template <typename RealType, size_t Order>1399fvar<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 1407template <typename RealType, size_t Order>1408fvar<RealType, Order> pow(fvar<RealType, Order> const& x,1409                          typename fvar<RealType, Order>::root_type const& y) {1410  BOOST_MATH_STD_USING1411  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 1429template <typename RealType, size_t Order>1430fvar<RealType, Order> pow(typename fvar<RealType, Order>::root_type const& x,1431                          fvar<RealType, Order> const& y) {1432  BOOST_MATH_STD_USING1433  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 1444template <typename RealType1, size_t Order1, typename RealType2, size_t Order2>1445promote<fvar<RealType1, Order1>, fvar<RealType2, Order2>> pow(fvar<RealType1, Order1> const& x,1446                                                              fvar<RealType2, Order2> const& y) {1447  BOOST_MATH_STD_USING1448  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_CONSTEXPR1462    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#endif1466    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 1483template <typename RealType, size_t Order>1484fvar<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_CONSTEXPR1497    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#endif1501    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().1515template <typename RealType, size_t Order>1516fvar<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 / x1525    return cr.apply_coefficients_nonhorner(order, [&d0, &d1](size_t i) { return i ? d1[i - 1] / i : d0; });1526  }1527}1528 1529template <typename RealType, size_t Order>1530fvar<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 1538template <typename RealType, size_t Order>1539fvar<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 1545template <typename RealType, size_t Order>1546fvar<RealType, Order> cos(fvar<RealType, Order> const& cr) {1547  BOOST_MATH_STD_USING1548  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 1560template <typename RealType, size_t Order>1561fvar<RealType, Order> sin(fvar<RealType, Order> const& cr) {1562  BOOST_MATH_STD_USING1563  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 1575template <typename RealType, size_t Order>1576fvar<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 1590template <typename RealType, size_t Order>1591fvar<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)^21601    return cr.apply_coefficients_nonhorner(order, [&d0, &d1](size_t i) { return i ? d1[i - 1] / i : d0; });1602  }1603}1604 1605template <typename RealType, size_t Order>1606fvar<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 1620template <typename RealType, size_t Order>1621fvar<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 1636template <typename RealType, size_t Order>1637fvar<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 1652template <typename RealType1, size_t Order1, typename RealType2, size_t Order2>1653promote<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 1679template <typename RealType1, size_t Order1, typename RealType2, size_t Order2>1680promote<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 1688template <typename RealType, size_t Order>1689fvar<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 1694template <typename RealType, size_t Order>1695int 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 1700template <typename RealType, size_t Order>1701long 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 1706template <typename RealType, size_t Order>1707long 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 1712template <typename RealType, size_t Order>1713fvar<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 1718template <typename RealType, size_t Order>1719long 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 1724template <typename RealType, size_t Order>1725int 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 1730template <typename RealType, size_t Order>1731long 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 1736template <typename RealType, size_t Order>1737std::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 functions1745 1746template <typename RealType, size_t Order>1747fvar<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 1761template <typename RealType, size_t Order>1762fvar<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 1776template <typename RealType, size_t Order>1777fvar<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 1791template <typename RealType, size_t Order>1792fvar<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 1806template <typename RealType, size_t Order>1807fvar<RealType, Order> cosh(fvar<RealType, Order> const& cr) {1808  BOOST_MATH_STD_USING1809  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 1820template <typename RealType, size_t Order>1821fvar<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 1837template <typename RealType, size_t Order>1838fvar<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 1852template <typename RealType, size_t Order>1853fvar<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 1867template <typename RealType, size_t Order>1868fvar<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 1905template <typename RealType, size_t Order>1906fvar<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 1922template <typename RealType, size_t Order>1923fvar<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) = 11929  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 1938template <typename RealType, size_t Order>1939fvar<RealType, Order> sinh(fvar<RealType, Order> const& cr) {1940  BOOST_MATH_STD_USING1941  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 1952template <typename RealType, size_t Order>1953fvar<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 1960template <typename RealType, size_t Order>1961fvar<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 detail1975}  // namespace autodiff_v11976}  // namespace differentiation1977}  // namespace math1978}  // namespace boost1979 1980namespace 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.1984template <typename RealType, size_t Order>1985class 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 std1990 1991namespace boost {1992namespace math {1993namespace tools {1994namespace detail {1995 1996template <typename RealType, std::size_t Order>1997using autodiff_fvar_type = differentiation::detail::fvar<RealType, Order>;1998 1999template <typename RealType, std::size_t Order>2000using autodiff_root_type = typename autodiff_fvar_type<RealType, Order>::root_type;2001}  // namespace detail2002 2003// See boost/math/tools/promotion.hpp2004template <typename RealType0, size_t Order0, typename RealType1, size_t Order1>2005struct 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_CONSTEXPR2009                                          (std::max)(Order0, Order1)>;2010#else2011        Order0<Order1 ? Order1 : Order0>;2012#endif2013};2014 2015template <typename RealType, size_t Order>2016struct promote_args<detail::autodiff_fvar_type<RealType, Order>> {2017  using type = detail::autodiff_fvar_type<typename promote_args<RealType>::type, Order>;2018};2019 2020template <typename RealType0, size_t Order0, typename RealType1>2021struct 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 2025template <typename RealType0, typename RealType1, size_t Order1>2026struct 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 2030template <typename destination_t, typename RealType, std::size_t Order>2031inline 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 tools2037 2038namespace policies {2039 2040template <class Policy, std::size_t Order>2041using fvar_t = differentiation::detail::fvar<Policy, Order>;2042template <class Policy, std::size_t Order>2043struct 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 2047template <class Policy, std::size_t Order>2048struct 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 policies2054}  // namespace math2055}  // namespace boost2056 2057#ifdef BOOST_MATH_NO_CXX17_IF_CONSTEXPR2058#include "autodiff_cpp11.hpp"2059#endif2060 2061#endif  // BOOST_MATH_DIFFERENTIATION_AUTODIFF_HPP2062