File indexing completed on 2025-12-16 09:54:37
0001
0002
0003
0004
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
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 }
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
0125
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;
0133
0134 fvar() = default;
0135
0136
0137 fvar(root_type const&, bool const is_variable);
0138
0139
0140 fvar(fvar const&) = default;
0141
0142
0143 template <typename RealType2, size_t Order2>
0144 fvar(fvar<RealType2, Order2> const&);
0145
0146
0147 explicit fvar(root_type const&);
0148
0149 template <typename RealType2>
0150 fvar(RealType2 const& ca);
0151
0152
0153 fvar& operator=(fvar const&) = default;
0154
0155
0156
0157
0158
0159
0160 template <typename RealType2, size_t Order2>
0161 fvar& operator+=(fvar<RealType2, Order2> const&);
0162
0163
0164 fvar& operator+=(root_type const&);
0165
0166
0167 template <typename RealType2, size_t Order2>
0168 fvar& operator-=(fvar<RealType2, Order2> const&);
0169
0170
0171 fvar& operator-=(root_type const&);
0172
0173
0174 template <typename RealType2, size_t Order2>
0175 fvar& operator*=(fvar<RealType2, Order2> const&);
0176
0177
0178 fvar& operator*=(root_type const&);
0179
0180
0181 template <typename RealType2, size_t Order2>
0182 fvar& operator/=(fvar<RealType2, Order2> const&);
0183
0184
0185 fvar& operator/=(root_type const&);
0186
0187
0188 fvar operator-() const;
0189
0190
0191 fvar const& operator+() const;
0192
0193
0194 template <typename RealType2, size_t Order2>
0195 promote<fvar, fvar<RealType2, Order2>> operator+(fvar<RealType2, Order2> const&) const;
0196
0197
0198 fvar operator+(root_type const&) const;
0199
0200
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
0206 template <typename RealType2, size_t Order2>
0207 promote<fvar, fvar<RealType2, Order2>> operator-(fvar<RealType2, Order2> const&) const;
0208
0209
0210 fvar operator-(root_type const&) const;
0211
0212
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
0218 template <typename RealType2, size_t Order2>
0219 promote<fvar, fvar<RealType2, Order2>> operator*(fvar<RealType2, Order2> const&)const;
0220
0221
0222 fvar operator*(root_type const&)const;
0223
0224
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
0230 template <typename RealType2, size_t Order2>
0231 promote<fvar, fvar<RealType2, Order2>> operator/(fvar<RealType2, Order2> const&) const;
0232
0233
0234 fvar operator/(root_type const&) const;
0235
0236
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
0242
0243
0244 template <typename RealType2, size_t Order2>
0245 bool operator==(fvar<RealType2, Order2> const&) const;
0246
0247
0248 bool operator==(root_type const&) const;
0249
0250
0251 template <typename RealType2, size_t Order2>
0252 friend bool operator==(typename fvar<RealType2, Order2>::root_type const&, fvar<RealType2, Order2> const&);
0253
0254
0255 template <typename RealType2, size_t Order2>
0256 bool operator!=(fvar<RealType2, Order2> const&) const;
0257
0258
0259 bool operator!=(root_type const&) const;
0260
0261
0262 template <typename RealType2, size_t Order2>
0263 friend bool operator!=(typename fvar<RealType2, Order2>::root_type const&, fvar<RealType2, Order2> const&);
0264
0265
0266 template <typename RealType2, size_t Order2>
0267 bool operator<=(fvar<RealType2, Order2> const&) const;
0268
0269
0270 bool operator<=(root_type const&) const;
0271
0272
0273 template <typename RealType2, size_t Order2>
0274 friend bool operator<=(typename fvar<RealType2, Order2>::root_type const&, fvar<RealType2, Order2> const&);
0275
0276
0277 template <typename RealType2, size_t Order2>
0278 bool operator>=(fvar<RealType2, Order2> const&) const;
0279
0280
0281 bool operator>=(root_type const&) const;
0282
0283
0284 template <typename RealType2, size_t Order2>
0285 friend bool operator>=(typename fvar<RealType2, Order2>::root_type const&, fvar<RealType2, Order2> const&);
0286
0287
0288 template <typename RealType2, size_t Order2>
0289 bool operator<(fvar<RealType2, Order2> const&) const;
0290
0291
0292 bool operator<(root_type const&) const;
0293
0294
0295 template <typename RealType2, size_t Order2>
0296 friend bool operator<(typename fvar<RealType2, Order2>::root_type const&, fvar<RealType2, Order2> const&);
0297
0298
0299 template <typename RealType2, size_t Order2>
0300 bool operator>(fvar<RealType2, Order2> const&) const;
0301
0302
0303 bool operator>(root_type const&) const;
0304
0305
0306 template <typename RealType2, size_t Order2>
0307 friend bool operator>(typename fvar<RealType2, Order2>::root_type const&, fvar<RealType2, Order2> const&);
0308
0309
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;
0319
0320 fvar& negate();
0321
0322 static constexpr size_t depth = get_depth<fvar>::value;
0323
0324 static constexpr size_t order_sum = get_order_sum<fvar>::value;
0325
0326 explicit operator root_type() const;
0327
0328 template <typename T, typename = typename std::enable_if<std::is_arithmetic<typename std::decay<T>::type>::value>>
0329 explicit operator T() const;
0330
0331 fvar& set_root(root_type const&);
0332
0333
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
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
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
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
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
0454
0455
0456 template <typename RealType, size_t Order>
0457 fvar<RealType, Order> fabs(fvar<RealType, Order> const&);
0458
0459
0460 template <typename RealType, size_t Order>
0461 fvar<RealType, Order> abs(fvar<RealType, Order> const&);
0462
0463
0464 template <typename RealType, size_t Order>
0465 fvar<RealType, Order> ceil(fvar<RealType, Order> const&);
0466
0467
0468 template <typename RealType, size_t Order>
0469 fvar<RealType, Order> floor(fvar<RealType, Order> const&);
0470
0471
0472 template <typename RealType, size_t Order>
0473 fvar<RealType, Order> exp(fvar<RealType, Order> const&);
0474
0475
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
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
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
0489 template <typename RealType, size_t Order>
0490 fvar<RealType, Order> sqrt(fvar<RealType, Order> const&);
0491
0492
0493 template <typename RealType, size_t Order>
0494 fvar<RealType, Order> log(fvar<RealType, Order> const&);
0495
0496
0497 template <typename RealType, size_t Order>
0498 fvar<RealType, Order> frexp(fvar<RealType, Order> const&, int*);
0499
0500
0501 template <typename RealType, size_t Order>
0502 fvar<RealType, Order> ldexp(fvar<RealType, Order> const&, int);
0503
0504
0505 template <typename RealType, size_t Order>
0506 fvar<RealType, Order> cos(fvar<RealType, Order> const&);
0507
0508
0509 template <typename RealType, size_t Order>
0510 fvar<RealType, Order> sin(fvar<RealType, Order> const&);
0511
0512
0513 template <typename RealType, size_t Order>
0514 fvar<RealType, Order> asin(fvar<RealType, Order> const&);
0515
0516
0517 template <typename RealType, size_t Order>
0518 fvar<RealType, Order> tan(fvar<RealType, Order> const&);
0519
0520
0521 template <typename RealType, size_t Order>
0522 fvar<RealType, Order> atan(fvar<RealType, Order> const&);
0523
0524
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
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
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
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
0543 template <typename RealType, size_t Order>
0544 fvar<RealType, Order> round(fvar<RealType, Order> const&);
0545
0546
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
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
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
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 }
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 }
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
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
0687
0688
0689
0690
0691
0692
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;
0840 mcr += ca;
0841 return mcr;
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
1025
1026 #ifndef BOOST_MATH_NO_CXX17_IF_CONSTEXPR
1027
1028
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
1048
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
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
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);
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
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);
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
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
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
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
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
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);
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
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);
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
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
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
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
1282
1283
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
1318
1319 template <typename RealType, size_t Order>
1320 fvar<RealType, Order> fvar<RealType, Order>::inverse_apply() const {
1321 root_type derivatives[order_sum + 1];
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;
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
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>()
1378 : cr;
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
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;
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
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
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();
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
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();
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();
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();
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));
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));
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
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();
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();
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();
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();
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));
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));
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}};
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};
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 }
1975 }
1976 }
1977 }
1978 }
1979
1980 namespace std {
1981
1982
1983
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 }
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 }
2002
2003
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 }
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 }
2054 }
2055 }
2056
2057 #ifdef BOOST_MATH_NO_CXX17_IF_CONSTEXPR
2058 #include "autodiff_cpp11.hpp"
2059 #endif
2060
2061 #endif