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 at
4 //           https://www.boost.org/LICENSE_1_0.txt)
5 
6 #ifndef BOOST_MATH_DIFFERENTIATION_AUTODIFF_HPP
7 #define BOOST_MATH_DIFFERENTIATION_AUTODIFF_HPP
8 
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 
33 namespace boost {
34 namespace math {
35 namespace differentiation {
36 // Automatic Differentiation v1
37 inline namespace autodiff_v1 {
38 namespace detail {
39 
40 template <typename RealType, typename... RealTypes>
41 struct promote_args_n {
42   using type = typename tools::promote_args_2<RealType, typename promote_args_n<RealTypes...>::type>::type;
43 };
44 
45 template <typename RealType>
46 struct promote_args_n<RealType> {
47   using type = typename tools::promote_arg<RealType>::type;
48 };
49 
50 }  // namespace detail
51 
52 template <typename RealType, typename... RealTypes>
53 using promote = typename detail::promote_args_n<RealType, RealTypes...>::type;
54 
55 namespace detail {
56 
57 template <typename RealType, size_t Order>
58 class fvar;
59 
60 template <typename T>
61 struct is_fvar_impl : std::false_type {};
62 
63 template <typename RealType, size_t Order>
64 struct is_fvar_impl<fvar<RealType, Order>> : std::true_type {};
65 
66 template <typename T>
67 using is_fvar = is_fvar_impl<typename std::decay<T>::type>;
68 
69 template <typename RealType, size_t Order, size_t... Orders>
70 struct nest_fvar {
71   using type = fvar<typename nest_fvar<RealType, Orders...>::type, Order>;
72 };
73 
74 template <typename RealType, size_t Order>
75 struct nest_fvar<RealType, Order> {
76   using type = fvar<RealType, Order>;
77 };
78 
79 template <typename>
80 struct get_depth_impl : std::integral_constant<size_t, 0> {};
81 
82 template <typename RealType, size_t Order>
83 struct get_depth_impl<fvar<RealType, Order>>
84     : std::integral_constant<size_t, get_depth_impl<RealType>::value + 1> {};
85 
86 template <typename T>
87 using get_depth = get_depth_impl<typename std::decay<T>::type>;
88 
89 template <typename>
90 struct get_order_sum_t : std::integral_constant<size_t, 0> {};
91 
92 template <typename RealType, size_t Order>
93 struct get_order_sum_t<fvar<RealType, Order>>
94     : std::integral_constant<size_t, get_order_sum_t<RealType>::value + Order> {};
95 
96 template <typename T>
97 using get_order_sum = get_order_sum_t<typename std::decay<T>::type>;
98 
99 template <typename RealType>
100 struct get_root_type {
101   using type = RealType;
102 };
103 
104 template <typename RealType, size_t Order>
105 struct get_root_type<fvar<RealType, Order>> {
106   using type = typename get_root_type<RealType>::type;
107 };
108 
109 template <typename RealType, size_t Depth>
110 struct type_at {
111   using type = RealType;
112 };
113 
114 template <typename RealType, size_t Order, size_t Depth>
115 struct type_at<fvar<RealType, Order>, Depth> {
116   using type = typename conditional<Depth == 0,
117                                     fvar<RealType, Order>,
118                                     typename type_at<RealType, Depth - 1>::type>::type;
119 };
120 
121 template <typename RealType, size_t Depth>
122 using 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.html
126 template <typename RealType, size_t Order>
127 class fvar {
128   std::array<RealType, Order + 1> v;
129 
130  public:
131   using root_type = typename get_root_type<RealType>::type;  // RealType in the root fvar<RealType,Order>.
132 
133   fvar() = default;
134 
135   // Initialize a variable or constant.
136   fvar(root_type const&, bool const is_variable);
137 
138   // RealType(cr) | RealType | RealType is copy constructible.
139   fvar(fvar const&) = default;
140 
141   // Be aware of implicit casting from one fvar<> type to another by this copy constructor.
142   template <typename RealType2, size_t Order2>
143   fvar(fvar<RealType2, Order2> const&);
144 
145   // RealType(ca) | RealType | RealType is copy constructible from the arithmetic types.
146   explicit fvar(root_type const&);  // Initialize a constant. (No epsilon terms.)
147 
148   template <typename RealType2>
149   fvar(RealType2 const& ca);  // Supports any RealType2 for which static_cast<root_type>(ca) compiles.
150 
151   // r = cr | RealType& | Assignment operator.
152   fvar& operator=(fvar const&) = default;
153 
154   // r = ca | RealType& | Assignment operator from the arithmetic types.
155   // Handled by constructor that takes a single parameter of generic type.
156   // fvar& operator=(root_type const&); // Set a constant.
157 
158   // r += cr | RealType& | Adds cr to r.
159   template <typename RealType2, size_t Order2>
160   fvar& operator+=(fvar<RealType2, Order2> const&);
161 
162   // r += ca | RealType& | Adds ar to r.
163   fvar& operator+=(root_type const&);
164 
165   // r -= cr | RealType& | Subtracts cr from r.
166   template <typename RealType2, size_t Order2>
167   fvar& operator-=(fvar<RealType2, Order2> const&);
168 
169   // r -= ca | RealType& | Subtracts ca from r.
170   fvar& operator-=(root_type const&);
171 
172   // r *= cr | RealType& | Multiplies r by cr.
173   template <typename RealType2, size_t Order2>
174   fvar& operator*=(fvar<RealType2, Order2> const&);
175 
176   // r *= ca | RealType& | Multiplies r by ca.
177   fvar& operator*=(root_type const&);
178 
179   // r /= cr | RealType& | Divides r by cr.
180   template <typename RealType2, size_t Order2>
181   fvar& operator/=(fvar<RealType2, Order2> const&);
182 
183   // r /= ca | RealType& | Divides r by ca.
184   fvar& operator/=(root_type const&);
185 
186   // -r | RealType | Unary Negation.
187   fvar operator-() const;
188 
189   // +r | RealType& | Identity Operation.
190   fvar const& operator+() const;
191 
192   // cr + cr2 | RealType | Binary Addition
193   template <typename RealType2, size_t Order2>
194   promote<fvar, fvar<RealType2, Order2>> operator+(fvar<RealType2, Order2> const&) const;
195 
196   // cr + ca | RealType | Binary Addition
197   fvar operator+(root_type const&) const;
198 
199   // ca + cr | RealType | Binary Addition
200   template <typename RealType2, size_t Order2>
201   friend fvar<RealType2, Order2> operator+(typename fvar<RealType2, Order2>::root_type const&,
202                                            fvar<RealType2, Order2> const&);
203 
204   // cr - cr2 | RealType | Binary Subtraction
205   template <typename RealType2, size_t Order2>
206   promote<fvar, fvar<RealType2, Order2>> operator-(fvar<RealType2, Order2> const&) const;
207 
208   // cr - ca | RealType | Binary Subtraction
209   fvar operator-(root_type const&) const;
210 
211   // ca - cr | RealType | Binary Subtraction
212   template <typename RealType2, size_t Order2>
213   friend fvar<RealType2, Order2> operator-(typename fvar<RealType2, Order2>::root_type const&,
214                                            fvar<RealType2, Order2> const&);
215 
216   // cr * cr2 | RealType | Binary Multiplication
217   template <typename RealType2, size_t Order2>
218   promote<fvar, fvar<RealType2, Order2>> operator*(fvar<RealType2, Order2> const&)const;
219 
220   // cr * ca | RealType | Binary Multiplication
221   fvar operator*(root_type const&)const;
222 
223   // ca * cr | RealType | Binary Multiplication
224   template <typename RealType2, size_t Order2>
225   friend fvar<RealType2, Order2> operator*(typename fvar<RealType2, Order2>::root_type const&,
226                                            fvar<RealType2, Order2> const&);
227 
228   // cr / cr2 | RealType | Binary Subtraction
229   template <typename RealType2, size_t Order2>
230   promote<fvar, fvar<RealType2, Order2>> operator/(fvar<RealType2, Order2> const&) const;
231 
232   // cr / ca | RealType | Binary Subtraction
233   fvar operator/(root_type const&) const;
234 
235   // ca / cr | RealType | Binary Subtraction
236   template <typename RealType2, size_t Order2>
237   friend fvar<RealType2, Order2> operator/(typename fvar<RealType2, Order2>::root_type const&,
238                                            fvar<RealType2, Order2> const&);
239 
240   // For all comparison overloads, only the root term is compared.
241 
242   // cr == cr2 | bool | Equality Comparison
243   template <typename RealType2, size_t Order2>
244   bool operator==(fvar<RealType2, Order2> const&) const;
245 
246   // cr == ca | bool | Equality Comparison
247   bool operator==(root_type const&) const;
248 
249   // ca == cr | bool | Equality Comparison
250   template <typename RealType2, size_t Order2>
251   friend bool operator==(typename fvar<RealType2, Order2>::root_type const&, fvar<RealType2, Order2> const&);
252 
253   // cr != cr2 | bool | Inequality Comparison
254   template <typename RealType2, size_t Order2>
255   bool operator!=(fvar<RealType2, Order2> const&) const;
256 
257   // cr != ca | bool | Inequality Comparison
258   bool operator!=(root_type const&) const;
259 
260   // ca != cr | bool | Inequality Comparison
261   template <typename RealType2, size_t Order2>
262   friend bool operator!=(typename fvar<RealType2, Order2>::root_type const&, fvar<RealType2, Order2> const&);
263 
264   // cr <= cr2 | bool | Less than equal to.
265   template <typename RealType2, size_t Order2>
266   bool operator<=(fvar<RealType2, Order2> const&) const;
267 
268   // cr <= ca | bool | Less than equal to.
269   bool operator<=(root_type const&) const;
270 
271   // ca <= cr | bool | Less than equal to.
272   template <typename RealType2, size_t Order2>
273   friend bool operator<=(typename fvar<RealType2, Order2>::root_type const&, fvar<RealType2, Order2> const&);
274 
275   // cr >= cr2 | bool | Greater than equal to.
276   template <typename RealType2, size_t Order2>
277   bool operator>=(fvar<RealType2, Order2> const&) const;
278 
279   // cr >= ca | bool | Greater than equal to.
280   bool operator>=(root_type const&) const;
281 
282   // ca >= cr | bool | Greater than equal to.
283   template <typename RealType2, size_t Order2>
284   friend bool operator>=(typename fvar<RealType2, Order2>::root_type const&, fvar<RealType2, Order2> const&);
285 
286   // cr < cr2 | bool | Less than comparison.
287   template <typename RealType2, size_t Order2>
288   bool operator<(fvar<RealType2, Order2> const&) const;
289 
290   // cr < ca | bool | Less than comparison.
291   bool operator<(root_type const&) const;
292 
293   // ca < cr | bool | Less than comparison.
294   template <typename RealType2, size_t Order2>
295   friend bool operator<(typename fvar<RealType2, Order2>::root_type const&, fvar<RealType2, Order2> const&);
296 
297   // cr > cr2 | bool | Greater than comparison.
298   template <typename RealType2, size_t Order2>
299   bool operator>(fvar<RealType2, Order2> const&) const;
300 
301   // cr > ca | bool | Greater than comparison.
302   bool operator>(root_type const&) const;
303 
304   // ca > cr | bool | Greater than comparison.
305   template <typename RealType2, size_t Order2>
306   friend bool operator>(typename fvar<RealType2, Order2>::root_type const&, fvar<RealType2, Order2> const&);
307 
308   // Will throw std::out_of_range if Order < order.
309   template <typename... Orders>
310   get_type_at<RealType, sizeof...(Orders)> at(size_t order, Orders... orders) const;
311 
312   template <typename... Orders>
313   get_type_at<fvar, sizeof...(Orders)> derivative(Orders... orders) const;
314 
315   const RealType& operator[](size_t) const;
316 
317   fvar inverse() const;  // Multiplicative inverse.
318 
319   fvar& negate();  // Negate and return reference to *this.
320 
321   static constexpr size_t depth = get_depth<fvar>::value;  // Number of nested std::array<RealType,Order>.
322 
323   static constexpr size_t order_sum = get_order_sum<fvar>::value;
324 
325   explicit operator root_type() const;  // Must be explicit, otherwise overloaded operators are ambiguous.
326 
327   template <typename T, typename = typename std::enable_if<std::is_arithmetic<typename std::decay<T>::type>::value>>
328   explicit operator T() const;  // Must be explicit; multiprecision has trouble without the std::enable_if
329 
330   fvar& set_root(root_type const&);
331 
332   // Apply coefficients using horner method.
333   template <typename Func, typename Fvar, typename... Fvars>
334   promote<fvar<RealType, Order>, Fvar, Fvars...> apply_coefficients(size_t const order,
335                                                                     Func const& f,
336                                                                     Fvar const& cr,
337                                                                     Fvars&&... fvars) const;
338 
339   template <typename Func>
340   fvar apply_coefficients(size_t const order, Func const& f) const;
341 
342   // Use when function returns derivative(i)/factorial(i) and may have some infinite derivatives.
343   template <typename Func, typename Fvar, typename... Fvars>
344   promote<fvar<RealType, Order>, Fvar, Fvars...> apply_coefficients_nonhorner(size_t const order,
345                                                                               Func const& f,
346                                                                               Fvar const& cr,
347                                                                               Fvars&&... fvars) const;
348 
349   template <typename Func>
350   fvar apply_coefficients_nonhorner(size_t const order, Func const& f) const;
351 
352   // Apply derivatives using horner method.
353   template <typename Func, typename Fvar, typename... Fvars>
354   promote<fvar<RealType, Order>, Fvar, Fvars...> apply_derivatives(size_t const order,
355                                                                    Func const& f,
356                                                                    Fvar const& cr,
357                                                                    Fvars&&... fvars) const;
358 
359   template <typename Func>
360   fvar apply_derivatives(size_t const order, Func const& f) const;
361 
362   // Use when function returns derivative(i) and may have some infinite derivatives.
363   template <typename Func, typename Fvar, typename... Fvars>
364   promote<fvar<RealType, Order>, Fvar, Fvars...> apply_derivatives_nonhorner(size_t const order,
365                                                                              Func const& f,
366                                                                              Fvar const& cr,
367                                                                              Fvars&&... fvars) const;
368 
369   template <typename Func>
370   fvar apply_derivatives_nonhorner(size_t const order, Func const& f) const;
371 
372  private:
373   RealType epsilon_inner_product(size_t z0,
374                                  size_t isum0,
375                                  size_t m0,
376                                  fvar const& cr,
377                                  size_t z1,
378                                  size_t isum1,
379                                  size_t m1,
380                                  size_t j) const;
381 
382   fvar epsilon_multiply(size_t z0, size_t isum0, fvar const& cr, size_t z1, size_t isum1) const;
383 
384   fvar epsilon_multiply(size_t z0, size_t isum0, root_type const& ca) const;
385 
386   fvar inverse_apply() const;
387 
388   fvar& multiply_assign_by_root_type(bool is_root, root_type const&);
389 
390   template <typename RealType2, size_t Orders2>
391   friend class fvar;
392 
393   template <typename RealType2, size_t Order2>
394   friend std::ostream& operator<<(std::ostream&, fvar<RealType2, Order2> const&);
395 
396   // C++11 Compatibility
397 #ifdef BOOST_NO_CXX17_IF_CONSTEXPR
398   template <typename RootType>
399   void fvar_cpp11(std::true_type, RootType const& ca, bool const is_variable);
400 
401   template <typename RootType>
402   void fvar_cpp11(std::false_type, RootType const& ca, bool const is_variable);
403 
404   template <typename... Orders>
405   get_type_at<RealType, sizeof...(Orders)> at_cpp11(std::true_type, size_t order, Orders... orders) const;
406 
407   template <typename... Orders>
408   get_type_at<RealType, sizeof...(Orders)> at_cpp11(std::false_type, size_t order, Orders... orders) const;
409 
410   template <typename SizeType>
411   fvar epsilon_multiply_cpp11(std::true_type,
412                               SizeType z0,
413                               size_t isum0,
414                               fvar const& cr,
415                               size_t z1,
416                               size_t isum1) const;
417 
418   template <typename SizeType>
419   fvar epsilon_multiply_cpp11(std::false_type,
420                               SizeType z0,
421                               size_t isum0,
422                               fvar const& cr,
423                               size_t z1,
424                               size_t isum1) const;
425 
426   template <typename SizeType>
427   fvar epsilon_multiply_cpp11(std::true_type, SizeType z0, size_t isum0, root_type const& ca) const;
428 
429   template <typename SizeType>
430   fvar epsilon_multiply_cpp11(std::false_type, SizeType z0, size_t isum0, root_type const& ca) const;
431 
432   template <typename RootType>
433   fvar& multiply_assign_by_root_type_cpp11(std::true_type, bool is_root, RootType const& ca);
434 
435   template <typename RootType>
436   fvar& multiply_assign_by_root_type_cpp11(std::false_type, bool is_root, RootType const& ca);
437 
438   template <typename RootType>
439   fvar& negate_cpp11(std::true_type, RootType const&);
440 
441   template <typename RootType>
442   fvar& negate_cpp11(std::false_type, RootType const&);
443 
444   template <typename RootType>
445   fvar& set_root_cpp11(std::true_type, RootType const& root);
446 
447   template <typename RootType>
448   fvar& set_root_cpp11(std::false_type, RootType const& root);
449 #endif
450 };
451 
452 // Standard Library Support Requirements
453 
454 // fabs(cr1) | RealType
455 template <typename RealType, size_t Order>
456 fvar<RealType, Order> fabs(fvar<RealType, Order> const&);
457 
458 // abs(cr1) | RealType
459 template <typename RealType, size_t Order>
460 fvar<RealType, Order> abs(fvar<RealType, Order> const&);
461 
462 // ceil(cr1) | RealType
463 template <typename RealType, size_t Order>
464 fvar<RealType, Order> ceil(fvar<RealType, Order> const&);
465 
466 // floor(cr1) | RealType
467 template <typename RealType, size_t Order>
468 fvar<RealType, Order> floor(fvar<RealType, Order> const&);
469 
470 // exp(cr1) | RealType
471 template <typename RealType, size_t Order>
472 fvar<RealType, Order> exp(fvar<RealType, Order> const&);
473 
474 // pow(cr, ca) | RealType
475 template <typename RealType, size_t Order>
476 fvar<RealType, Order> pow(fvar<RealType, Order> const&, typename fvar<RealType, Order>::root_type const&);
477 
478 // pow(ca, cr) | RealType
479 template <typename RealType, size_t Order>
480 fvar<RealType, Order> pow(typename fvar<RealType, Order>::root_type const&, fvar<RealType, Order> const&);
481 
482 // pow(cr1, cr2) | RealType
483 template <typename RealType1, size_t Order1, typename RealType2, size_t Order2>
484 promote<fvar<RealType1, Order1>, fvar<RealType2, Order2>> pow(fvar<RealType1, Order1> const&,
485                                                               fvar<RealType2, Order2> const&);
486 
487 // sqrt(cr1) | RealType
488 template <typename RealType, size_t Order>
489 fvar<RealType, Order> sqrt(fvar<RealType, Order> const&);
490 
491 // log(cr1) | RealType
492 template <typename RealType, size_t Order>
493 fvar<RealType, Order> log(fvar<RealType, Order> const&);
494 
495 // frexp(cr1, &i) | RealType
496 template <typename RealType, size_t Order>
497 fvar<RealType, Order> frexp(fvar<RealType, Order> const&, int*);
498 
499 // ldexp(cr1, i) | RealType
500 template <typename RealType, size_t Order>
501 fvar<RealType, Order> ldexp(fvar<RealType, Order> const&, int);
502 
503 // cos(cr1) | RealType
504 template <typename RealType, size_t Order>
505 fvar<RealType, Order> cos(fvar<RealType, Order> const&);
506 
507 // sin(cr1) | RealType
508 template <typename RealType, size_t Order>
509 fvar<RealType, Order> sin(fvar<RealType, Order> const&);
510 
511 // asin(cr1) | RealType
512 template <typename RealType, size_t Order>
513 fvar<RealType, Order> asin(fvar<RealType, Order> const&);
514 
515 // tan(cr1) | RealType
516 template <typename RealType, size_t Order>
517 fvar<RealType, Order> tan(fvar<RealType, Order> const&);
518 
519 // atan(cr1) | RealType
520 template <typename RealType, size_t Order>
521 fvar<RealType, Order> atan(fvar<RealType, Order> const&);
522 
523 // atan2(cr, ca) | RealType
524 template <typename RealType, size_t Order>
525 fvar<RealType, Order> atan2(fvar<RealType, Order> const&, typename fvar<RealType, Order>::root_type const&);
526 
527 // atan2(ca, cr) | RealType
528 template <typename RealType, size_t Order>
529 fvar<RealType, Order> atan2(typename fvar<RealType, Order>::root_type const&, fvar<RealType, Order> const&);
530 
531 // atan2(cr1, cr2) | RealType
532 template <typename RealType1, size_t Order1, typename RealType2, size_t Order2>
533 promote<fvar<RealType1, Order1>, fvar<RealType2, Order2>> atan2(fvar<RealType1, Order1> const&,
534                                                                 fvar<RealType2, Order2> const&);
535 
536 // fmod(cr1,cr2) | RealType
537 template <typename RealType1, size_t Order1, typename RealType2, size_t Order2>
538 promote<fvar<RealType1, Order1>, fvar<RealType2, Order2>> fmod(fvar<RealType1, Order1> const&,
539                                                                fvar<RealType2, Order2> const&);
540 
541 // round(cr1) | RealType
542 template <typename RealType, size_t Order>
543 fvar<RealType, Order> round(fvar<RealType, Order> const&);
544 
545 // iround(cr1) | int
546 template <typename RealType, size_t Order>
547 int iround(fvar<RealType, Order> const&);
548 
549 template <typename RealType, size_t Order>
550 long lround(fvar<RealType, Order> const&);
551 
552 template <typename RealType, size_t Order>
553 long long llround(fvar<RealType, Order> const&);
554 
555 // trunc(cr1) | RealType
556 template <typename RealType, size_t Order>
557 fvar<RealType, Order> trunc(fvar<RealType, Order> const&);
558 
559 template <typename RealType, size_t Order>
560 long double truncl(fvar<RealType, Order> const&);
561 
562 // itrunc(cr1) | int
563 template <typename RealType, size_t Order>
564 int itrunc(fvar<RealType, Order> const&);
565 
566 template <typename RealType, size_t Order>
567 long long lltrunc(fvar<RealType, Order> const&);
568 
569 // Additional functions
570 template <typename RealType, size_t Order>
571 fvar<RealType, Order> acos(fvar<RealType, Order> const&);
572 
573 template <typename RealType, size_t Order>
574 fvar<RealType, Order> acosh(fvar<RealType, Order> const&);
575 
576 template <typename RealType, size_t Order>
577 fvar<RealType, Order> asinh(fvar<RealType, Order> const&);
578 
579 template <typename RealType, size_t Order>
580 fvar<RealType, Order> atanh(fvar<RealType, Order> const&);
581 
582 template <typename RealType, size_t Order>
583 fvar<RealType, Order> cosh(fvar<RealType, Order> const&);
584 
585 template <typename RealType, size_t Order>
586 fvar<RealType, Order> digamma(fvar<RealType, Order> const&);
587 
588 template <typename RealType, size_t Order>
589 fvar<RealType, Order> erf(fvar<RealType, Order> const&);
590 
591 template <typename RealType, size_t Order>
592 fvar<RealType, Order> erfc(fvar<RealType, Order> const&);
593 
594 template <typename RealType, size_t Order>
595 fvar<RealType, Order> lambert_w0(fvar<RealType, Order> const&);
596 
597 template <typename RealType, size_t Order>
598 fvar<RealType, Order> lgamma(fvar<RealType, Order> const&);
599 
600 template <typename RealType, size_t Order>
601 fvar<RealType, Order> sinc(fvar<RealType, Order> const&);
602 
603 template <typename RealType, size_t Order>
604 fvar<RealType, Order> sinh(fvar<RealType, Order> const&);
605 
606 template <typename RealType, size_t Order>
607 fvar<RealType, Order> tanh(fvar<RealType, Order> const&);
608 
609 template <typename RealType, size_t Order>
610 fvar<RealType, Order> tgamma(fvar<RealType, Order> const&);
611 
612 template <size_t>
613 struct zero : std::integral_constant<size_t, 0> {};
614 
615 }  // namespace detail
616 
617 template <typename RealType, size_t Order, size_t... Orders>
618 using autodiff_fvar = typename detail::nest_fvar<RealType, Order, Orders...>::type;
619 
620 template <typename RealType, size_t Order, size_t... Orders>
make_fvar(RealType const & ca)621 autodiff_fvar<RealType, Order, Orders...> make_fvar(RealType const& ca) {
622   return autodiff_fvar<RealType, Order, Orders...>(ca, true);
623 }
624 
625 #ifndef BOOST_NO_CXX17_IF_CONSTEXPR
626 namespace detail {
627 
628 template <typename RealType, size_t Order, size_t... Is>
make_fvar_for_tuple(std::index_sequence<Is...>,RealType const & ca)629 auto make_fvar_for_tuple(std::index_sequence<Is...>, RealType const& ca) {
630   return make_fvar<RealType, zero<Is>::value..., Order>(ca);
631 }
632 
633 template <typename RealType, size_t... Orders, size_t... Is, typename... RealTypes>
make_ftuple_impl(std::index_sequence<Is...>,RealTypes const &...ca)634 auto make_ftuple_impl(std::index_sequence<Is...>, RealTypes const&... ca) {
635   return std::make_tuple(make_fvar_for_tuple<RealType, Orders>(std::make_index_sequence<Is>{}, ca)...);
636 }
637 
638 }  // namespace detail
639 
640 template <typename RealType, size_t... Orders, typename... RealTypes>
make_ftuple(RealTypes const &...ca)641 auto make_ftuple(RealTypes const&... ca) {
642   static_assert(sizeof...(Orders) == sizeof...(RealTypes),
643                 "Number of Orders must match number of function parameters.");
644   return detail::make_ftuple_impl<RealType, Orders...>(std::index_sequence_for<RealTypes...>{}, ca...);
645 }
646 #endif
647 
648 namespace detail {
649 
650 #ifndef BOOST_NO_CXX17_IF_CONSTEXPR
651 template <typename RealType, size_t Order>
fvar(root_type const & ca,bool const is_variable)652 fvar<RealType, Order>::fvar(root_type const& ca, bool const is_variable) {
653   if constexpr (is_fvar<RealType>::value) {
654     v.front() = RealType(ca, is_variable);
655     if constexpr (0 < Order)
656       std::fill(v.begin() + 1, v.end(), static_cast<RealType>(0));
657   } else {
658     v.front() = ca;
659     if constexpr (0 < Order)
660       v[1] = static_cast<root_type>(static_cast<int>(is_variable));
661     if constexpr (1 < Order)
662       std::fill(v.begin() + 2, v.end(), static_cast<RealType>(0));
663   }
664 }
665 #endif
666 
667 template <typename RealType, size_t Order>
668 template <typename RealType2, size_t Order2>
fvar(fvar<RealType2,Order2> const & cr)669 fvar<RealType, Order>::fvar(fvar<RealType2, Order2> const& cr) {
670   for (size_t i = 0; i <= (std::min)(Order, Order2); ++i)
671     v[i] = static_cast<RealType>(cr.v[i]);
672   BOOST_IF_CONSTEXPR (Order2 < Order)
673     std::fill(v.begin() + (Order2 + 1), v.end(), static_cast<RealType>(0));
674 }
675 
676 template <typename RealType, size_t Order>
fvar(root_type const & ca)677 fvar<RealType, Order>::fvar(root_type const& ca) : v{{static_cast<RealType>(ca)}} {}
678 
679 // Can cause compiler error if RealType2 cannot be cast to root_type.
680 template <typename RealType, size_t Order>
681 template <typename RealType2>
fvar(RealType2 const & ca)682 fvar<RealType, Order>::fvar(RealType2 const& ca) : v{{static_cast<RealType>(ca)}} {}
683 
684 /*
685 template<typename RealType, size_t Order>
686 fvar<RealType,Order>& fvar<RealType,Order>::operator=(root_type const& ca)
687 {
688     v.front() = static_cast<RealType>(ca);
689     if constexpr (0 < Order)
690         std::fill(v.begin()+1, v.end(), static_cast<RealType>(0));
691     return *this;
692 }
693 */
694 
695 template <typename RealType, size_t Order>
696 template <typename RealType2, size_t Order2>
operator +=(fvar<RealType2,Order2> const & cr)697 fvar<RealType, Order>& fvar<RealType, Order>::operator+=(fvar<RealType2, Order2> const& cr) {
698   for (size_t i = 0; i <= (std::min)(Order, Order2); ++i)
699     v[i] += cr.v[i];
700   return *this;
701 }
702 
703 template <typename RealType, size_t Order>
operator +=(root_type const & ca)704 fvar<RealType, Order>& fvar<RealType, Order>::operator+=(root_type const& ca) {
705   v.front() += ca;
706   return *this;
707 }
708 
709 template <typename RealType, size_t Order>
710 template <typename RealType2, size_t Order2>
operator -=(fvar<RealType2,Order2> const & cr)711 fvar<RealType, Order>& fvar<RealType, Order>::operator-=(fvar<RealType2, Order2> const& cr) {
712   for (size_t i = 0; i <= Order; ++i)
713     v[i] -= cr.v[i];
714   return *this;
715 }
716 
717 template <typename RealType, size_t Order>
operator -=(root_type const & ca)718 fvar<RealType, Order>& fvar<RealType, Order>::operator-=(root_type const& ca) {
719   v.front() -= ca;
720   return *this;
721 }
722 
723 template <typename RealType, size_t Order>
724 template <typename RealType2, size_t Order2>
operator *=(fvar<RealType2,Order2> const & cr)725 fvar<RealType, Order>& fvar<RealType, Order>::operator*=(fvar<RealType2, Order2> const& cr) {
726   using diff_t = typename std::array<RealType, Order + 1>::difference_type;
727   promote<RealType, RealType2> const zero(0);
728   BOOST_IF_CONSTEXPR (Order <= Order2)
729     for (size_t i = 0, j = Order; i <= Order; ++i, --j)
730       v[j] = std::inner_product(v.cbegin(), v.cend() - diff_t(i), cr.v.crbegin() + diff_t(i), zero);
731   else {
732     for (size_t i = 0, j = Order; i <= Order - Order2; ++i, --j)
733       v[j] = std::inner_product(cr.v.cbegin(), cr.v.cend(), v.crbegin() + diff_t(i), zero);
734     for (size_t i = Order - Order2 + 1, j = Order2 - 1; i <= Order; ++i, --j)
735       v[j] = std::inner_product(cr.v.cbegin(), cr.v.cbegin() + diff_t(j + 1), v.crbegin() + diff_t(i), zero);
736   }
737   return *this;
738 }
739 
740 template <typename RealType, size_t Order>
operator *=(root_type const & ca)741 fvar<RealType, Order>& fvar<RealType, Order>::operator*=(root_type const& ca) {
742   return multiply_assign_by_root_type(true, ca);
743 }
744 
745 template <typename RealType, size_t Order>
746 template <typename RealType2, size_t Order2>
operator /=(fvar<RealType2,Order2> const & cr)747 fvar<RealType, Order>& fvar<RealType, Order>::operator/=(fvar<RealType2, Order2> const& cr) {
748   using diff_t = typename std::array<RealType, Order + 1>::difference_type;
749   RealType const zero(0);
750   v.front() /= cr.v.front();
751   BOOST_IF_CONSTEXPR (Order < Order2)
752     for (size_t i = 1, j = Order2 - 1, k = Order; i <= Order; ++i, --j, --k)
753       (v[i] -= std::inner_product(
754            cr.v.cbegin() + 1, cr.v.cend() - diff_t(j), v.crbegin() + diff_t(k), zero)) /= cr.v.front();
755   else BOOST_IF_CONSTEXPR (0 < Order2)
756     for (size_t i = 1, j = Order2 - 1, k = Order; i <= Order; ++i, j && --j, --k)
757       (v[i] -= std::inner_product(
758            cr.v.cbegin() + 1, cr.v.cend() - diff_t(j), v.crbegin() + diff_t(k), zero)) /= cr.v.front();
759   else
760     for (size_t i = 1; i <= Order; ++i)
761       v[i] /= cr.v.front();
762   return *this;
763 }
764 
765 template <typename RealType, size_t Order>
operator /=(root_type const & ca)766 fvar<RealType, Order>& fvar<RealType, Order>::operator/=(root_type const& ca) {
767   std::for_each(v.begin(), v.end(), [&ca](RealType& x) { x /= ca; });
768   return *this;
769 }
770 
771 template <typename RealType, size_t Order>
operator -() const772 fvar<RealType, Order> fvar<RealType, Order>::operator-() const {
773   fvar<RealType, Order> retval(*this);
774   retval.negate();
775   return retval;
776 }
777 
778 template <typename RealType, size_t Order>
operator +() const779 fvar<RealType, Order> const& fvar<RealType, Order>::operator+() const {
780   return *this;
781 }
782 
783 template <typename RealType, size_t Order>
784 template <typename RealType2, size_t Order2>
operator +(fvar<RealType2,Order2> const & cr) const785 promote<fvar<RealType, Order>, fvar<RealType2, Order2>> fvar<RealType, Order>::operator+(
786     fvar<RealType2, Order2> const& cr) const {
787   promote<fvar<RealType, Order>, fvar<RealType2, Order2>> retval;
788   for (size_t i = 0; i <= (std::min)(Order, Order2); ++i)
789     retval.v[i] = v[i] + cr.v[i];
790   BOOST_IF_CONSTEXPR (Order < Order2)
791     for (size_t i = Order + 1; i <= Order2; ++i)
792       retval.v[i] = cr.v[i];
793   else BOOST_IF_CONSTEXPR (Order2 < Order)
794     for (size_t i = Order2 + 1; i <= Order; ++i)
795       retval.v[i] = v[i];
796   return retval;
797 }
798 
799 template <typename RealType, size_t Order>
operator +(root_type const & ca) const800 fvar<RealType, Order> fvar<RealType, Order>::operator+(root_type const& ca) const {
801   fvar<RealType, Order> retval(*this);
802   retval.v.front() += ca;
803   return retval;
804 }
805 
806 template <typename RealType, size_t Order>
operator +(typename fvar<RealType,Order>::root_type const & ca,fvar<RealType,Order> const & cr)807 fvar<RealType, Order> operator+(typename fvar<RealType, Order>::root_type const& ca,
808                                 fvar<RealType, Order> const& cr) {
809   return cr + ca;
810 }
811 
812 template <typename RealType, size_t Order>
813 template <typename RealType2, size_t Order2>
operator -(fvar<RealType2,Order2> const & cr) const814 promote<fvar<RealType, Order>, fvar<RealType2, Order2>> fvar<RealType, Order>::operator-(
815     fvar<RealType2, Order2> const& cr) const {
816   promote<fvar<RealType, Order>, fvar<RealType2, Order2>> retval;
817   for (size_t i = 0; i <= (std::min)(Order, Order2); ++i)
818     retval.v[i] = v[i] - cr.v[i];
819   BOOST_IF_CONSTEXPR (Order < Order2)
820     for (auto i = Order + 1; i <= Order2; ++i)
821       retval.v[i] = -cr.v[i];
822   else BOOST_IF_CONSTEXPR (Order2 < Order)
823     for (auto i = Order2 + 1; i <= Order; ++i)
824       retval.v[i] = v[i];
825   return retval;
826 }
827 
828 template <typename RealType, size_t Order>
operator -(root_type const & ca) const829 fvar<RealType, Order> fvar<RealType, Order>::operator-(root_type const& ca) const {
830   fvar<RealType, Order> retval(*this);
831   retval.v.front() -= ca;
832   return retval;
833 }
834 
835 template <typename RealType, size_t Order>
operator -(typename fvar<RealType,Order>::root_type const & ca,fvar<RealType,Order> const & cr)836 fvar<RealType, Order> operator-(typename fvar<RealType, Order>::root_type const& ca,
837                                 fvar<RealType, Order> const& cr) {
838   fvar<RealType, Order> mcr = -cr;  // Has same address as retval in operator-() due to NRVO.
839   mcr += ca;
840   return mcr;  // <-- This allows for NRVO. The following does not. --> return mcr += ca;
841 }
842 
843 template <typename RealType, size_t Order>
844 template <typename RealType2, size_t Order2>
operator *(fvar<RealType2,Order2> const & cr) const845 promote<fvar<RealType, Order>, fvar<RealType2, Order2>> fvar<RealType, Order>::operator*(
846     fvar<RealType2, Order2> const& cr) const {
847   using diff_t = typename std::array<RealType, Order + 1>::difference_type;
848   promote<RealType, RealType2> const zero(0);
849   promote<fvar<RealType, Order>, fvar<RealType2, Order2>> retval;
850   BOOST_IF_CONSTEXPR (Order < Order2)
851     for (size_t i = 0, j = Order, k = Order2; i <= Order2; ++i, j && --j, --k)
852       retval.v[i] = std::inner_product(v.cbegin(), v.cend() - diff_t(j), cr.v.crbegin() + diff_t(k), zero);
853   else
854     for (size_t i = 0, j = Order2, k = Order; i <= Order; ++i, j && --j, --k)
855       retval.v[i] = std::inner_product(cr.v.cbegin(), cr.v.cend() - diff_t(j), v.crbegin() + diff_t(k), zero);
856   return retval;
857 }
858 
859 template <typename RealType, size_t Order>
operator *(root_type const & ca) const860 fvar<RealType, Order> fvar<RealType, Order>::operator*(root_type const& ca) const {
861   fvar<RealType, Order> retval(*this);
862   retval *= ca;
863   return retval;
864 }
865 
866 template <typename RealType, size_t Order>
operator *(typename fvar<RealType,Order>::root_type const & ca,fvar<RealType,Order> const & cr)867 fvar<RealType, Order> operator*(typename fvar<RealType, Order>::root_type const& ca,
868                                 fvar<RealType, Order> const& cr) {
869   return cr * ca;
870 }
871 
872 template <typename RealType, size_t Order>
873 template <typename RealType2, size_t Order2>
operator /(fvar<RealType2,Order2> const & cr) const874 promote<fvar<RealType, Order>, fvar<RealType2, Order2>> fvar<RealType, Order>::operator/(
875     fvar<RealType2, Order2> const& cr) const {
876   using diff_t = typename std::array<RealType, Order + 1>::difference_type;
877   promote<RealType, RealType2> const zero(0);
878   promote<fvar<RealType, Order>, fvar<RealType2, Order2>> retval;
879   retval.v.front() = v.front() / cr.v.front();
880   BOOST_IF_CONSTEXPR (Order < Order2) {
881     for (size_t i = 1, j = Order2 - 1; i <= Order; ++i, --j)
882       retval.v[i] =
883           (v[i] - std::inner_product(
884                       cr.v.cbegin() + 1, cr.v.cend() - diff_t(j), retval.v.crbegin() + diff_t(j + 1), zero)) /
885           cr.v.front();
886     for (size_t i = Order + 1, j = Order2 - Order - 1; i <= Order2; ++i, --j)
887       retval.v[i] =
888           -std::inner_product(
889               cr.v.cbegin() + 1, cr.v.cend() - diff_t(j), retval.v.crbegin() + diff_t(j + 1), zero) /
890           cr.v.front();
891   } else BOOST_IF_CONSTEXPR (0 < Order2)
892     for (size_t i = 1, j = Order2 - 1, k = Order; i <= Order; ++i, j && --j, --k)
893       retval.v[i] =
894           (v[i] - std::inner_product(
895                       cr.v.cbegin() + 1, cr.v.cend() - diff_t(j), retval.v.crbegin() + diff_t(k), zero)) /
896           cr.v.front();
897   else
898     for (size_t i = 1; i <= Order; ++i)
899       retval.v[i] = v[i] / cr.v.front();
900   return retval;
901 }
902 
903 template <typename RealType, size_t Order>
operator /(root_type const & ca) const904 fvar<RealType, Order> fvar<RealType, Order>::operator/(root_type const& ca) const {
905   fvar<RealType, Order> retval(*this);
906   retval /= ca;
907   return retval;
908 }
909 
910 template <typename RealType, size_t Order>
operator /(typename fvar<RealType,Order>::root_type const & ca,fvar<RealType,Order> const & cr)911 fvar<RealType, Order> operator/(typename fvar<RealType, Order>::root_type const& ca,
912                                 fvar<RealType, Order> const& cr) {
913   using diff_t = typename std::array<RealType, Order + 1>::difference_type;
914   fvar<RealType, Order> retval;
915   retval.v.front() = ca / cr.v.front();
916   BOOST_IF_CONSTEXPR (0 < Order) {
917     RealType const zero(0);
918     for (size_t i = 1, j = Order - 1; i <= Order; ++i, --j)
919       retval.v[i] =
920           -std::inner_product(
921               cr.v.cbegin() + 1, cr.v.cend() - diff_t(j), retval.v.crbegin() + diff_t(j + 1), zero) /
922           cr.v.front();
923   }
924   return retval;
925 }
926 
927 template <typename RealType, size_t Order>
928 template <typename RealType2, size_t Order2>
operator ==(fvar<RealType2,Order2> const & cr) const929 bool fvar<RealType, Order>::operator==(fvar<RealType2, Order2> const& cr) const {
930   return v.front() == cr.v.front();
931 }
932 
933 template <typename RealType, size_t Order>
operator ==(root_type const & ca) const934 bool fvar<RealType, Order>::operator==(root_type const& ca) const {
935   return v.front() == ca;
936 }
937 
938 template <typename RealType, size_t Order>
operator ==(typename fvar<RealType,Order>::root_type const & ca,fvar<RealType,Order> const & cr)939 bool operator==(typename fvar<RealType, Order>::root_type const& ca, fvar<RealType, Order> const& cr) {
940   return ca == cr.v.front();
941 }
942 
943 template <typename RealType, size_t Order>
944 template <typename RealType2, size_t Order2>
operator !=(fvar<RealType2,Order2> const & cr) const945 bool fvar<RealType, Order>::operator!=(fvar<RealType2, Order2> const& cr) const {
946   return v.front() != cr.v.front();
947 }
948 
949 template <typename RealType, size_t Order>
operator !=(root_type const & ca) const950 bool fvar<RealType, Order>::operator!=(root_type const& ca) const {
951   return v.front() != ca;
952 }
953 
954 template <typename RealType, size_t Order>
operator !=(typename fvar<RealType,Order>::root_type const & ca,fvar<RealType,Order> const & cr)955 bool operator!=(typename fvar<RealType, Order>::root_type const& ca, fvar<RealType, Order> const& cr) {
956   return ca != cr.v.front();
957 }
958 
959 template <typename RealType, size_t Order>
960 template <typename RealType2, size_t Order2>
operator <=(fvar<RealType2,Order2> const & cr) const961 bool fvar<RealType, Order>::operator<=(fvar<RealType2, Order2> const& cr) const {
962   return v.front() <= cr.v.front();
963 }
964 
965 template <typename RealType, size_t Order>
operator <=(root_type const & ca) const966 bool fvar<RealType, Order>::operator<=(root_type const& ca) const {
967   return v.front() <= ca;
968 }
969 
970 template <typename RealType, size_t Order>
operator <=(typename fvar<RealType,Order>::root_type const & ca,fvar<RealType,Order> const & cr)971 bool operator<=(typename fvar<RealType, Order>::root_type const& ca, fvar<RealType, Order> const& cr) {
972   return ca <= cr.v.front();
973 }
974 
975 template <typename RealType, size_t Order>
976 template <typename RealType2, size_t Order2>
operator >=(fvar<RealType2,Order2> const & cr) const977 bool fvar<RealType, Order>::operator>=(fvar<RealType2, Order2> const& cr) const {
978   return v.front() >= cr.v.front();
979 }
980 
981 template <typename RealType, size_t Order>
operator >=(root_type const & ca) const982 bool fvar<RealType, Order>::operator>=(root_type const& ca) const {
983   return v.front() >= ca;
984 }
985 
986 template <typename RealType, size_t Order>
operator >=(typename fvar<RealType,Order>::root_type const & ca,fvar<RealType,Order> const & cr)987 bool operator>=(typename fvar<RealType, Order>::root_type const& ca, fvar<RealType, Order> const& cr) {
988   return ca >= cr.v.front();
989 }
990 
991 template <typename RealType, size_t Order>
992 template <typename RealType2, size_t Order2>
operator <(fvar<RealType2,Order2> const & cr) const993 bool fvar<RealType, Order>::operator<(fvar<RealType2, Order2> const& cr) const {
994   return v.front() < cr.v.front();
995 }
996 
997 template <typename RealType, size_t Order>
operator <(root_type const & ca) const998 bool fvar<RealType, Order>::operator<(root_type const& ca) const {
999   return v.front() < ca;
1000 }
1001 
1002 template <typename RealType, size_t Order>
operator <(typename fvar<RealType,Order>::root_type const & ca,fvar<RealType,Order> const & cr)1003 bool operator<(typename fvar<RealType, Order>::root_type const& ca, fvar<RealType, Order> const& cr) {
1004   return ca < cr.v.front();
1005 }
1006 
1007 template <typename RealType, size_t Order>
1008 template <typename RealType2, size_t Order2>
operator >(fvar<RealType2,Order2> const & cr) const1009 bool fvar<RealType, Order>::operator>(fvar<RealType2, Order2> const& cr) const {
1010   return v.front() > cr.v.front();
1011 }
1012 
1013 template <typename RealType, size_t Order>
operator >(root_type const & ca) const1014 bool fvar<RealType, Order>::operator>(root_type const& ca) const {
1015   return v.front() > ca;
1016 }
1017 
1018 template <typename RealType, size_t Order>
operator >(typename fvar<RealType,Order>::root_type const & ca,fvar<RealType,Order> const & cr)1019 bool operator>(typename fvar<RealType, Order>::root_type const& ca, fvar<RealType, Order> const& cr) {
1020   return ca > cr.v.front();
1021 }
1022 
1023   /*** Other methods and functions ***/
1024 
1025 #ifndef BOOST_NO_CXX17_IF_CONSTEXPR
1026 // f : order -> derivative(order)/factorial(order)
1027 // Use this when you have the polynomial coefficients, rather than just the derivatives. E.g. See atan2().
1028 template <typename RealType, size_t Order>
1029 template <typename Func, typename Fvar, typename... Fvars>
apply_coefficients(size_t const order,Func const & f,Fvar const & cr,Fvars &&...fvars) const1030 promote<fvar<RealType, Order>, Fvar, Fvars...> fvar<RealType, Order>::apply_coefficients(
1031     size_t const order,
1032     Func const& f,
1033     Fvar const& cr,
1034     Fvars&&... fvars) const {
1035   fvar<RealType, Order> const epsilon = fvar<RealType, Order>(*this).set_root(0);
1036   size_t i = (std::min)(order, order_sum);
1037   promote<fvar<RealType, Order>, Fvar, Fvars...> accumulator = cr.apply_coefficients(
1038       order - i, [&f, i](auto... indices) { return f(i, indices...); }, std::forward<Fvars>(fvars)...);
1039   while (i--)
1040     (accumulator *= epsilon) += cr.apply_coefficients(
1041         order - i, [&f, i](auto... indices) { return f(i, indices...); }, std::forward<Fvars>(fvars)...);
1042   return accumulator;
1043 }
1044 #endif
1045 
1046 // f : order -> derivative(order)/factorial(order)
1047 // Use this when you have the polynomial coefficients, rather than just the derivatives. E.g. See atan().
1048 template <typename RealType, size_t Order>
1049 template <typename Func>
apply_coefficients(size_t const order,Func const & f) const1050 fvar<RealType, Order> fvar<RealType, Order>::apply_coefficients(size_t const order, Func const& f) const {
1051   fvar<RealType, Order> const epsilon = fvar<RealType, Order>(*this).set_root(0);
1052 #ifndef BOOST_NO_CXX17_IF_CONSTEXPR
1053   size_t i = (std::min)(order, order_sum);
1054 #else  // ODR-use of static constexpr
1055   size_t i = order < order_sum ? order : order_sum;
1056 #endif
1057   fvar<RealType, Order> accumulator = f(i);
1058   while (i--)
1059     (accumulator *= epsilon) += f(i);
1060   return accumulator;
1061 }
1062 
1063 #ifndef BOOST_NO_CXX17_IF_CONSTEXPR
1064 // f : order -> derivative(order)
1065 template <typename RealType, size_t Order>
1066 template <typename Func, typename Fvar, typename... Fvars>
apply_coefficients_nonhorner(size_t const order,Func const & f,Fvar const & cr,Fvars &&...fvars) const1067 promote<fvar<RealType, Order>, Fvar, Fvars...> fvar<RealType, Order>::apply_coefficients_nonhorner(
1068     size_t const order,
1069     Func const& f,
1070     Fvar const& cr,
1071     Fvars&&... fvars) const {
1072   fvar<RealType, Order> const epsilon = fvar<RealType, Order>(*this).set_root(0);
1073   fvar<RealType, Order> epsilon_i = fvar<RealType, Order>(1);  // epsilon to the power of i
1074   promote<fvar<RealType, Order>, Fvar, Fvars...> accumulator = cr.apply_coefficients_nonhorner(
1075       order,
1076       [&f](auto... indices) { return f(0, static_cast<std::size_t>(indices)...); },
1077       std::forward<Fvars>(fvars)...);
1078   size_t const i_max = (std::min)(order, order_sum);
1079   for (size_t i = 1; i <= i_max; ++i) {
1080     epsilon_i = epsilon_i.epsilon_multiply(i - 1, 0, epsilon, 1, 0);
1081     accumulator += epsilon_i.epsilon_multiply(
1082         i,
1083         0,
1084         cr.apply_coefficients_nonhorner(
1085             order - i,
1086             [&f, i](auto... indices) { return f(i, static_cast<std::size_t>(indices)...); },
1087             std::forward<Fvars>(fvars)...),
1088         0,
1089         0);
1090   }
1091   return accumulator;
1092 }
1093 #endif
1094 
1095 // f : order -> coefficient(order)
1096 template <typename RealType, size_t Order>
1097 template <typename Func>
apply_coefficients_nonhorner(size_t const order,Func const & f) const1098 fvar<RealType, Order> fvar<RealType, Order>::apply_coefficients_nonhorner(size_t const order,
1099                                                                           Func const& f) const {
1100   fvar<RealType, Order> const epsilon = fvar<RealType, Order>(*this).set_root(0);
1101   fvar<RealType, Order> epsilon_i = fvar<RealType, Order>(1);  // epsilon to the power of i
1102   fvar<RealType, Order> accumulator = fvar<RealType, Order>(f(0u));
1103 #ifndef BOOST_NO_CXX17_IF_CONSTEXPR
1104   size_t const i_max = (std::min)(order, order_sum);
1105 #else  // ODR-use of static constexpr
1106   size_t const i_max = order < order_sum ? order : order_sum;
1107 #endif
1108   for (size_t i = 1; i <= i_max; ++i) {
1109     epsilon_i = epsilon_i.epsilon_multiply(i - 1, 0, epsilon, 1, 0);
1110     accumulator += epsilon_i.epsilon_multiply(i, 0, f(i));
1111   }
1112   return accumulator;
1113 }
1114 
1115 #ifndef BOOST_NO_CXX17_IF_CONSTEXPR
1116 // f : order -> derivative(order)
1117 template <typename RealType, size_t Order>
1118 template <typename Func, typename Fvar, typename... Fvars>
apply_derivatives(size_t const order,Func const & f,Fvar const & cr,Fvars &&...fvars) const1119 promote<fvar<RealType, Order>, Fvar, Fvars...> fvar<RealType, Order>::apply_derivatives(
1120     size_t const order,
1121     Func const& f,
1122     Fvar const& cr,
1123     Fvars&&... fvars) const {
1124   fvar<RealType, Order> const epsilon = fvar<RealType, Order>(*this).set_root(0);
1125   size_t i = (std::min)(order, order_sum);
1126   promote<fvar<RealType, Order>, Fvar, Fvars...> accumulator =
1127       cr.apply_derivatives(
1128           order - i, [&f, i](auto... indices) { return f(i, indices...); }, std::forward<Fvars>(fvars)...) /
1129       factorial<root_type>(static_cast<unsigned>(i));
1130   while (i--)
1131     (accumulator *= epsilon) +=
1132         cr.apply_derivatives(
1133             order - i, [&f, i](auto... indices) { return f(i, indices...); }, std::forward<Fvars>(fvars)...) /
1134         factorial<root_type>(static_cast<unsigned>(i));
1135   return accumulator;
1136 }
1137 #endif
1138 
1139 // f : order -> derivative(order)
1140 template <typename RealType, size_t Order>
1141 template <typename Func>
apply_derivatives(size_t const order,Func const & f) const1142 fvar<RealType, Order> fvar<RealType, Order>::apply_derivatives(size_t const order, Func const& f) const {
1143   fvar<RealType, Order> const epsilon = fvar<RealType, Order>(*this).set_root(0);
1144 #ifndef BOOST_NO_CXX17_IF_CONSTEXPR
1145   size_t i = (std::min)(order, order_sum);
1146 #else  // ODR-use of static constexpr
1147   size_t i = order < order_sum ? order : order_sum;
1148 #endif
1149   fvar<RealType, Order> accumulator = f(i) / factorial<root_type>(static_cast<unsigned>(i));
1150   while (i--)
1151     (accumulator *= epsilon) += f(i) / factorial<root_type>(static_cast<unsigned>(i));
1152   return accumulator;
1153 }
1154 
1155 #ifndef BOOST_NO_CXX17_IF_CONSTEXPR
1156 // f : order -> derivative(order)
1157 template <typename RealType, size_t Order>
1158 template <typename Func, typename Fvar, typename... Fvars>
apply_derivatives_nonhorner(size_t const order,Func const & f,Fvar const & cr,Fvars &&...fvars) const1159 promote<fvar<RealType, Order>, Fvar, Fvars...> fvar<RealType, Order>::apply_derivatives_nonhorner(
1160     size_t const order,
1161     Func const& f,
1162     Fvar const& cr,
1163     Fvars&&... fvars) const {
1164   fvar<RealType, Order> const epsilon = fvar<RealType, Order>(*this).set_root(0);
1165   fvar<RealType, Order> epsilon_i = fvar<RealType, Order>(1);  // epsilon to the power of i
1166   promote<fvar<RealType, Order>, Fvar, Fvars...> accumulator = cr.apply_derivatives_nonhorner(
1167       order,
1168       [&f](auto... indices) { return f(0, static_cast<std::size_t>(indices)...); },
1169       std::forward<Fvars>(fvars)...);
1170   size_t const i_max = (std::min)(order, order_sum);
1171   for (size_t i = 1; i <= i_max; ++i) {
1172     epsilon_i = epsilon_i.epsilon_multiply(i - 1, 0, epsilon, 1, 0);
1173     accumulator += epsilon_i.epsilon_multiply(
1174         i,
1175         0,
1176         cr.apply_derivatives_nonhorner(
1177             order - i,
1178             [&f, i](auto... indices) { return f(i, static_cast<std::size_t>(indices)...); },
1179             std::forward<Fvars>(fvars)...) /
1180             factorial<root_type>(static_cast<unsigned>(i)),
1181         0,
1182         0);
1183   }
1184   return accumulator;
1185 }
1186 #endif
1187 
1188 // f : order -> derivative(order)
1189 template <typename RealType, size_t Order>
1190 template <typename Func>
apply_derivatives_nonhorner(size_t const order,Func const & f) const1191 fvar<RealType, Order> fvar<RealType, Order>::apply_derivatives_nonhorner(size_t const order,
1192                                                                          Func const& f) const {
1193   fvar<RealType, Order> const epsilon = fvar<RealType, Order>(*this).set_root(0);
1194   fvar<RealType, Order> epsilon_i = fvar<RealType, Order>(1);  // epsilon to the power of i
1195   fvar<RealType, Order> accumulator = fvar<RealType, Order>(f(0u));
1196 #ifndef BOOST_NO_CXX17_IF_CONSTEXPR
1197   size_t const i_max = (std::min)(order, order_sum);
1198 #else  // ODR-use of static constexpr
1199   size_t const i_max = order < order_sum ? order : order_sum;
1200 #endif
1201   for (size_t i = 1; i <= i_max; ++i) {
1202     epsilon_i = epsilon_i.epsilon_multiply(i - 1, 0, epsilon, 1, 0);
1203     accumulator += epsilon_i.epsilon_multiply(i, 0, f(i) / factorial<root_type>(static_cast<unsigned>(i)));
1204   }
1205   return accumulator;
1206 }
1207 
1208 #ifndef BOOST_NO_CXX17_IF_CONSTEXPR
1209 // Can throw "std::out_of_range: array::at: __n (which is 7) >= _Nm (which is 7)"
1210 template <typename RealType, size_t Order>
1211 template <typename... Orders>
at(size_t order,Orders...orders) const1212 get_type_at<RealType, sizeof...(Orders)> fvar<RealType, Order>::at(size_t order, Orders... orders) const {
1213   if constexpr (0 < sizeof...(Orders))
1214     return v.at(order).at(static_cast<std::size_t>(orders)...);
1215   else
1216     return v.at(order);
1217 }
1218 #endif
1219 
1220 #ifndef BOOST_NO_CXX17_IF_CONSTEXPR
1221 // Can throw "std::out_of_range: array::at: __n (which is 7) >= _Nm (which is 7)"
1222 template <typename RealType, size_t Order>
1223 template <typename... Orders>
derivative(Orders...orders) const1224 get_type_at<fvar<RealType, Order>, sizeof...(Orders)> fvar<RealType, Order>::derivative(
1225     Orders... orders) const {
1226   static_assert(sizeof...(Orders) <= depth,
1227                 "Number of parameters to derivative(...) cannot exceed fvar::depth.");
1228   return at(static_cast<std::size_t>(orders)...) *
1229          (... * factorial<root_type>(static_cast<unsigned>(orders)));
1230 }
1231 #endif
1232 
1233 template <typename RealType, size_t Order>
operator [](size_t i) const1234 const RealType& fvar<RealType, Order>::operator[](size_t i) const {
1235   return v[i];
1236 }
1237 
1238 template <typename RealType, size_t Order>
1239 RealType fvar<RealType, Order>::epsilon_inner_product(size_t z0,
1240                                                       size_t const isum0,
1241                                                       size_t const m0,
1242                                                       fvar<RealType, Order> const& cr,
1243                                                       size_t z1,
1244                                                       size_t const isum1,
1245                                                       size_t const m1,
1246                                                       size_t const j) const {
1247   static_assert(is_fvar<RealType>::value, "epsilon_inner_product() must have 1 < depth.");
1248   RealType accumulator = RealType();
1249   auto const i0_max = m1 < j ? j - m1 : 0;
1250   for (auto i0 = m0, i1 = j - m0; i0 <= i0_max; ++i0, --i1)
1251     accumulator += v[i0].epsilon_multiply(z0, isum0 + i0, cr.v[i1], z1, isum1 + i1);
1252   return accumulator;
1253 }
1254 
1255 #ifndef BOOST_NO_CXX17_IF_CONSTEXPR
1256 template <typename RealType, size_t Order>
epsilon_multiply(size_t z0,size_t isum0,fvar<RealType,Order> const & cr,size_t z1,size_t isum1) const1257 fvar<RealType, Order> fvar<RealType, Order>::epsilon_multiply(size_t z0,
1258                                                               size_t isum0,
1259                                                               fvar<RealType, Order> const& cr,
1260                                                               size_t z1,
1261                                                               size_t isum1) const {
1262   using diff_t = typename std::array<RealType, Order + 1>::difference_type;
1263   RealType const zero(0);
1264   size_t const m0 = order_sum + isum0 < Order + z0 ? Order + z0 - (order_sum + isum0) : 0;
1265   size_t const m1 = order_sum + isum1 < Order + z1 ? Order + z1 - (order_sum + isum1) : 0;
1266   size_t const i_max = m0 + m1 < Order ? Order - (m0 + m1) : 0;
1267   fvar<RealType, Order> retval = fvar<RealType, Order>();
1268   if constexpr (is_fvar<RealType>::value)
1269     for (size_t i = 0, j = Order; i <= i_max; ++i, --j)
1270       retval.v[j] = epsilon_inner_product(z0, isum0, m0, cr, z1, isum1, m1, j);
1271   else
1272     for (size_t i = 0, j = Order; i <= i_max; ++i, --j)
1273       retval.v[j] = std::inner_product(
1274           v.cbegin() + diff_t(m0), v.cend() - diff_t(i + m1), cr.v.crbegin() + diff_t(i + m0), zero);
1275   return retval;
1276 }
1277 #endif
1278 
1279 #ifndef BOOST_NO_CXX17_IF_CONSTEXPR
1280 // When called from outside this method, z0 should be non-zero. Otherwise if z0=0 then it will give an
1281 // incorrect result of 0 when the root value is 0 and ca=inf, when instead the correct product is nan.
1282 // If z0=0 then use the regular multiply operator*() instead.
1283 template <typename RealType, size_t Order>
epsilon_multiply(size_t z0,size_t isum0,root_type const & ca) const1284 fvar<RealType, Order> fvar<RealType, Order>::epsilon_multiply(size_t z0,
1285                                                               size_t isum0,
1286                                                               root_type const& ca) const {
1287   fvar<RealType, Order> retval(*this);
1288   size_t const m0 = order_sum + isum0 < Order + z0 ? Order + z0 - (order_sum + isum0) : 0;
1289   if constexpr (is_fvar<RealType>::value)
1290     for (size_t i = m0; i <= Order; ++i)
1291       retval.v[i] = retval.v[i].epsilon_multiply(z0, isum0 + i, ca);
1292   else
1293     for (size_t i = m0; i <= Order; ++i)
1294       if (retval.v[i] != static_cast<RealType>(0))
1295         retval.v[i] *= ca;
1296   return retval;
1297 }
1298 #endif
1299 
1300 template <typename RealType, size_t Order>
inverse() const1301 fvar<RealType, Order> fvar<RealType, Order>::inverse() const {
1302   return static_cast<root_type>(*this) == 0 ? inverse_apply() : 1 / *this;
1303 }
1304 
1305 #ifndef BOOST_NO_CXX17_IF_CONSTEXPR
1306 template <typename RealType, size_t Order>
negate()1307 fvar<RealType, Order>& fvar<RealType, Order>::negate() {
1308   if constexpr (is_fvar<RealType>::value)
1309     std::for_each(v.begin(), v.end(), [](RealType& r) { r.negate(); });
1310   else
1311     std::for_each(v.begin(), v.end(), [](RealType& a) { a = -a; });
1312   return *this;
1313 }
1314 #endif
1315 
1316 // This gives log(0.0) = depth(1)(-inf,inf,-inf,inf,-inf,inf)
1317 // 1 / *this: log(0.0) = depth(1)(-inf,inf,-inf,-nan,-nan,-nan)
1318 template <typename RealType, size_t Order>
inverse_apply() const1319 fvar<RealType, Order> fvar<RealType, Order>::inverse_apply() const {
1320   root_type derivatives[order_sum + 1];  // LCOV_EXCL_LINE This causes a false negative on lcov coverage test.
1321   root_type const x0 = static_cast<root_type>(*this);
1322   *derivatives = 1 / x0;
1323   for (size_t i = 1; i <= order_sum; ++i)
1324     derivatives[i] = -derivatives[i - 1] * i / x0;
1325   return apply_derivatives_nonhorner(order_sum, [&derivatives](size_t j) { return derivatives[j]; });
1326 }
1327 
1328 #ifndef BOOST_NO_CXX17_IF_CONSTEXPR
1329 template <typename RealType, size_t Order>
multiply_assign_by_root_type(bool is_root,root_type const & ca)1330 fvar<RealType, Order>& fvar<RealType, Order>::multiply_assign_by_root_type(bool is_root,
1331                                                                            root_type const& ca) {
1332   auto itr = v.begin();
1333   if constexpr (is_fvar<RealType>::value) {
1334     itr->multiply_assign_by_root_type(is_root, ca);
1335     for (++itr; itr != v.end(); ++itr)
1336       itr->multiply_assign_by_root_type(false, ca);
1337   } else {
1338     if (is_root || *itr != 0)
1339       *itr *= ca;  // Skip multiplication of 0 by ca=inf to avoid nan, except when is_root.
1340     for (++itr; itr != v.end(); ++itr)
1341       if (*itr != 0)
1342         *itr *= ca;
1343   }
1344   return *this;
1345 }
1346 #endif
1347 
1348 template <typename RealType, size_t Order>
operator root_type() const1349 fvar<RealType, Order>::operator root_type() const {
1350   return static_cast<root_type>(v.front());
1351 }
1352 
1353 template <typename RealType, size_t Order>
1354 template <typename T, typename>
operator T() const1355 fvar<RealType, Order>::operator T() const {
1356   return static_cast<T>(static_cast<root_type>(v.front()));
1357 }
1358 
1359 #ifndef BOOST_NO_CXX17_IF_CONSTEXPR
1360 template <typename RealType, size_t Order>
set_root(root_type const & root)1361 fvar<RealType, Order>& fvar<RealType, Order>::set_root(root_type const& root) {
1362   if constexpr (is_fvar<RealType>::value)
1363     v.front().set_root(root);
1364   else
1365     v.front() = root;
1366   return *this;
1367 }
1368 #endif
1369 
1370 // Standard Library Support Requirements
1371 
1372 template <typename RealType, size_t Order>
fabs(fvar<RealType,Order> const & cr)1373 fvar<RealType, Order> fabs(fvar<RealType, Order> const& cr) {
1374   typename fvar<RealType, Order>::root_type const zero(0);
1375   return cr < zero ? -cr
1376                    : cr == zero ? fvar<RealType, Order>()  // Canonical fabs'(0) = 0.
1377                                 : cr;                      // Propagate NaN.
1378 }
1379 
1380 template <typename RealType, size_t Order>
abs(fvar<RealType,Order> const & cr)1381 fvar<RealType, Order> abs(fvar<RealType, Order> const& cr) {
1382   return fabs(cr);
1383 }
1384 
1385 template <typename RealType, size_t Order>
ceil(fvar<RealType,Order> const & cr)1386 fvar<RealType, Order> ceil(fvar<RealType, Order> const& cr) {
1387   using std::ceil;
1388   return fvar<RealType, Order>(ceil(static_cast<typename fvar<RealType, Order>::root_type>(cr)));
1389 }
1390 
1391 template <typename RealType, size_t Order>
floor(fvar<RealType,Order> const & cr)1392 fvar<RealType, Order> floor(fvar<RealType, Order> const& cr) {
1393   using std::floor;
1394   return fvar<RealType, Order>(floor(static_cast<typename fvar<RealType, Order>::root_type>(cr)));
1395 }
1396 
1397 template <typename RealType, size_t Order>
exp(fvar<RealType,Order> const & cr)1398 fvar<RealType, Order> exp(fvar<RealType, Order> const& cr) {
1399   using std::exp;
1400   constexpr size_t order = fvar<RealType, Order>::order_sum;
1401   using root_type = typename fvar<RealType, Order>::root_type;
1402   root_type const d0 = exp(static_cast<root_type>(cr));
1403   return cr.apply_derivatives(order, [&d0](size_t) { return d0; });
1404 }
1405 
1406 template <typename RealType, size_t Order>
pow(fvar<RealType,Order> const & x,typename fvar<RealType,Order>::root_type const & y)1407 fvar<RealType, Order> pow(fvar<RealType, Order> const& x,
1408                           typename fvar<RealType, Order>::root_type const& y) {
1409   BOOST_MATH_STD_USING
1410   using root_type = typename fvar<RealType, Order>::root_type;
1411   constexpr size_t order = fvar<RealType, Order>::order_sum;
1412   root_type const x0 = static_cast<root_type>(x);
1413   root_type derivatives[order + 1]{pow(x0, y)};
1414   if (fabs(x0) < std::numeric_limits<root_type>::epsilon()) {
1415     root_type coef = 1;
1416     for (size_t i = 0; i < order && y - i != 0; ++i) {
1417       coef *= y - i;
1418       derivatives[i + 1] = coef * pow(x0, y - (i + 1));
1419     }
1420     return x.apply_derivatives_nonhorner(order, [&derivatives](size_t i) { return derivatives[i]; });
1421   } else {
1422     for (size_t i = 0; i < order && y - i != 0; ++i)
1423       derivatives[i + 1] = (y - i) * derivatives[i] / x0;
1424     return x.apply_derivatives(order, [&derivatives](size_t i) { return derivatives[i]; });
1425   }
1426 }
1427 
1428 template <typename RealType, size_t Order>
pow(typename fvar<RealType,Order>::root_type const & x,fvar<RealType,Order> const & y)1429 fvar<RealType, Order> pow(typename fvar<RealType, Order>::root_type const& x,
1430                           fvar<RealType, Order> const& y) {
1431   BOOST_MATH_STD_USING
1432   using root_type = typename fvar<RealType, Order>::root_type;
1433   constexpr size_t order = fvar<RealType, Order>::order_sum;
1434   root_type const y0 = static_cast<root_type>(y);
1435   root_type derivatives[order + 1];
1436   *derivatives = pow(x, y0);
1437   root_type const logx = log(x);
1438   for (size_t i = 0; i < order; ++i)
1439     derivatives[i + 1] = derivatives[i] * logx;
1440   return y.apply_derivatives(order, [&derivatives](size_t i) { return derivatives[i]; });
1441 }
1442 
1443 template <typename RealType1, size_t Order1, typename RealType2, size_t Order2>
pow(fvar<RealType1,Order1> const & x,fvar<RealType2,Order2> const & y)1444 promote<fvar<RealType1, Order1>, fvar<RealType2, Order2>> pow(fvar<RealType1, Order1> const& x,
1445                                                               fvar<RealType2, Order2> const& y) {
1446   BOOST_MATH_STD_USING
1447   using return_type = promote<fvar<RealType1, Order1>, fvar<RealType2, Order2>>;
1448   using root_type = typename return_type::root_type;
1449   constexpr size_t order = return_type::order_sum;
1450   root_type const x0 = static_cast<root_type>(x);
1451   root_type const y0 = static_cast<root_type>(y);
1452   root_type dxydx[order + 1]{pow(x0, y0)};
1453   BOOST_IF_CONSTEXPR (order == 0)
1454     return return_type(*dxydx);
1455   else {
1456     for (size_t i = 0; i < order && y0 - i != 0; ++i)
1457       dxydx[i + 1] = (y0 - i) * dxydx[i] / x0;
1458     std::array<fvar<root_type, order>, order + 1> lognx;
1459     lognx.front() = fvar<root_type, order>(1);
1460 #ifndef BOOST_NO_CXX17_IF_CONSTEXPR
1461     lognx[1] = log(make_fvar<root_type, order>(x0));
1462 #else  // for compilers that compile this branch when order == 0.
1463     lognx[(std::min)(size_t(1), order)] = log(make_fvar<root_type, order>(x0));
1464 #endif
1465     for (size_t i = 1; i < order; ++i)
1466       lognx[i + 1] = lognx[i] * lognx[1];
1467     auto const f = [&dxydx, &lognx](size_t i, size_t j) {
1468       size_t binomial = 1;
1469       root_type sum = dxydx[i] * static_cast<root_type>(lognx[j]);
1470       for (size_t k = 1; k <= i; ++k) {
1471         (binomial *= (i - k + 1)) /= k;  // binomial_coefficient(i,k)
1472         sum += binomial * dxydx[i - k] * lognx[j].derivative(k);
1473       }
1474       return sum;
1475     };
1476     if (fabs(x0) < std::numeric_limits<root_type>::epsilon())
1477       return x.apply_derivatives_nonhorner(order, f, y);
1478     return x.apply_derivatives(order, f, y);
1479   }
1480 }
1481 
1482 template <typename RealType, size_t Order>
sqrt(fvar<RealType,Order> const & cr)1483 fvar<RealType, Order> sqrt(fvar<RealType, Order> const& cr) {
1484   using std::sqrt;
1485   using root_type = typename fvar<RealType, Order>::root_type;
1486   constexpr size_t order = fvar<RealType, Order>::order_sum;
1487   root_type derivatives[order + 1];
1488   root_type const x = static_cast<root_type>(cr);
1489   *derivatives = sqrt(x);
1490   BOOST_IF_CONSTEXPR (order == 0)
1491     return fvar<RealType, Order>(*derivatives);
1492   else {
1493     root_type numerator = 0.5;
1494     root_type powers = 1;
1495 #ifndef BOOST_NO_CXX17_IF_CONSTEXPR
1496     derivatives[1] = numerator / *derivatives;
1497 #else  // for compilers that compile this branch when order == 0.
1498     derivatives[(std::min)(size_t(1), order)] = numerator / *derivatives;
1499 #endif
1500     using diff_t = typename std::array<RealType, Order + 1>::difference_type;
1501     for (size_t i = 2; i <= order; ++i) {
1502       numerator *= static_cast<root_type>(-0.5) * ((static_cast<diff_t>(i) << 1) - 3);
1503       powers *= x;
1504       derivatives[i] = numerator / (powers * *derivatives);
1505     }
1506     auto const f = [&derivatives](size_t i) { return derivatives[i]; };
1507     if (cr < std::numeric_limits<root_type>::epsilon())
1508       return cr.apply_derivatives_nonhorner(order, f);
1509     return cr.apply_derivatives(order, f);
1510   }
1511 }
1512 
1513 // Natural logarithm. If cr==0 then derivative(i) may have nans due to nans from inverse().
1514 template <typename RealType, size_t Order>
log(fvar<RealType,Order> const & cr)1515 fvar<RealType, Order> log(fvar<RealType, Order> const& cr) {
1516   using std::log;
1517   using root_type = typename fvar<RealType, Order>::root_type;
1518   constexpr size_t order = fvar<RealType, Order>::order_sum;
1519   root_type const d0 = log(static_cast<root_type>(cr));
1520   BOOST_IF_CONSTEXPR (order == 0)
1521     return fvar<RealType, Order>(d0);
1522   else {
1523     auto const d1 = make_fvar<root_type, bool(order) ? order - 1 : 0>(static_cast<root_type>(cr)).inverse();  // log'(x) = 1 / x
1524     return cr.apply_coefficients_nonhorner(order, [&d0, &d1](size_t i) { return i ? d1[i - 1] / i : d0; });
1525   }
1526 }
1527 
1528 template <typename RealType, size_t Order>
frexp(fvar<RealType,Order> const & cr,int * exp)1529 fvar<RealType, Order> frexp(fvar<RealType, Order> const& cr, int* exp) {
1530   using std::exp2;
1531   using std::frexp;
1532   using root_type = typename fvar<RealType, Order>::root_type;
1533   frexp(static_cast<root_type>(cr), exp);
1534   return cr * static_cast<root_type>(exp2(-*exp));
1535 }
1536 
1537 template <typename RealType, size_t Order>
ldexp(fvar<RealType,Order> const & cr,int exp)1538 fvar<RealType, Order> ldexp(fvar<RealType, Order> const& cr, int exp) {
1539   // argument to std::exp2 must be casted to root_type, otherwise std::exp2 returns double (always)
1540   using std::exp2;
1541   return cr * exp2(static_cast<typename fvar<RealType, Order>::root_type>(exp));
1542 }
1543 
1544 template <typename RealType, size_t Order>
cos(fvar<RealType,Order> const & cr)1545 fvar<RealType, Order> cos(fvar<RealType, Order> const& cr) {
1546   BOOST_MATH_STD_USING
1547   using root_type = typename fvar<RealType, Order>::root_type;
1548   constexpr size_t order = fvar<RealType, Order>::order_sum;
1549   root_type const d0 = cos(static_cast<root_type>(cr));
1550   BOOST_IF_CONSTEXPR (order == 0)
1551     return fvar<RealType, Order>(d0);
1552   else {
1553     root_type const d1 = -sin(static_cast<root_type>(cr));
1554     root_type const derivatives[4]{d0, d1, -d0, -d1};
1555     return cr.apply_derivatives(order, [&derivatives](size_t i) { return derivatives[i & 3]; });
1556   }
1557 }
1558 
1559 template <typename RealType, size_t Order>
sin(fvar<RealType,Order> const & cr)1560 fvar<RealType, Order> sin(fvar<RealType, Order> const& cr) {
1561   BOOST_MATH_STD_USING
1562   using root_type = typename fvar<RealType, Order>::root_type;
1563   constexpr size_t order = fvar<RealType, Order>::order_sum;
1564   root_type const d0 = sin(static_cast<root_type>(cr));
1565   BOOST_IF_CONSTEXPR (order == 0)
1566     return fvar<RealType, Order>(d0);
1567   else {
1568     root_type const d1 = cos(static_cast<root_type>(cr));
1569     root_type const derivatives[4]{d0, d1, -d0, -d1};
1570     return cr.apply_derivatives(order, [&derivatives](size_t i) { return derivatives[i & 3]; });
1571   }
1572 }
1573 
1574 template <typename RealType, size_t Order>
asin(fvar<RealType,Order> const & cr)1575 fvar<RealType, Order> asin(fvar<RealType, Order> const& cr) {
1576   using std::asin;
1577   using root_type = typename fvar<RealType, Order>::root_type;
1578   constexpr size_t order = fvar<RealType, Order>::order_sum;
1579   root_type const d0 = asin(static_cast<root_type>(cr));
1580   BOOST_IF_CONSTEXPR (order == 0)
1581     return fvar<RealType, Order>(d0);
1582   else {
1583     auto x = make_fvar<root_type, bool(order) ? order - 1 : 0>(static_cast<root_type>(cr));
1584     auto const d1 = sqrt((x *= x).negate() += 1).inverse();  // asin'(x) = 1 / sqrt(1-x*x).
1585     return cr.apply_coefficients_nonhorner(order, [&d0, &d1](size_t i) { return i ? d1[i - 1] / i : d0; });
1586   }
1587 }
1588 
1589 template <typename RealType, size_t Order>
tan(fvar<RealType,Order> const & cr)1590 fvar<RealType, Order> tan(fvar<RealType, Order> const& cr) {
1591   using std::tan;
1592   using root_type = typename fvar<RealType, Order>::root_type;
1593   constexpr size_t order = fvar<RealType, Order>::order_sum;
1594   root_type const d0 = tan(static_cast<root_type>(cr));
1595   BOOST_IF_CONSTEXPR (order == 0)
1596     return fvar<RealType, Order>(d0);
1597   else {
1598     auto c = cos(make_fvar<root_type, bool(order) ? order - 1 : 0>(static_cast<root_type>(cr)));
1599     auto const d1 = (c *= c).inverse();  // tan'(x) = 1 / cos(x)^2
1600     return cr.apply_coefficients_nonhorner(order, [&d0, &d1](size_t i) { return i ? d1[i - 1] / i : d0; });
1601   }
1602 }
1603 
1604 template <typename RealType, size_t Order>
atan(fvar<RealType,Order> const & cr)1605 fvar<RealType, Order> atan(fvar<RealType, Order> const& cr) {
1606   using std::atan;
1607   using root_type = typename fvar<RealType, Order>::root_type;
1608   constexpr size_t order = fvar<RealType, Order>::order_sum;
1609   root_type const d0 = atan(static_cast<root_type>(cr));
1610   BOOST_IF_CONSTEXPR (order == 0)
1611     return fvar<RealType, Order>(d0);
1612   else {
1613     auto x = make_fvar<root_type, bool(order) ? order - 1 : 0>(static_cast<root_type>(cr));
1614     auto const d1 = ((x *= x) += 1).inverse();  // atan'(x) = 1 / (x*x+1).
1615     return cr.apply_coefficients(order, [&d0, &d1](size_t i) { return i ? d1[i - 1] / i : d0; });
1616   }
1617 }
1618 
1619 template <typename RealType, size_t Order>
atan2(fvar<RealType,Order> const & cr,typename fvar<RealType,Order>::root_type const & ca)1620 fvar<RealType, Order> atan2(fvar<RealType, Order> const& cr,
1621                             typename fvar<RealType, Order>::root_type const& ca) {
1622   using std::atan2;
1623   using root_type = typename fvar<RealType, Order>::root_type;
1624   constexpr size_t order = fvar<RealType, Order>::order_sum;
1625   root_type const d0 = atan2(static_cast<root_type>(cr), ca);
1626   BOOST_IF_CONSTEXPR (order == 0)
1627     return fvar<RealType, Order>(d0);
1628   else {
1629     auto y = make_fvar<root_type, bool(order) ? order - 1 : 0>(static_cast<root_type>(cr));
1630     auto const d1 = ca / ((y *= y) += (ca * ca));  // (d/dy)atan2(y,x) = x / (y*y+x*x)
1631     return cr.apply_coefficients(order, [&d0, &d1](size_t i) { return i ? d1[i - 1] / i : d0; });
1632   }
1633 }
1634 
1635 template <typename RealType, size_t Order>
atan2(typename fvar<RealType,Order>::root_type const & ca,fvar<RealType,Order> const & cr)1636 fvar<RealType, Order> atan2(typename fvar<RealType, Order>::root_type const& ca,
1637                             fvar<RealType, Order> const& cr) {
1638   using std::atan2;
1639   using root_type = typename fvar<RealType, Order>::root_type;
1640   constexpr size_t order = fvar<RealType, Order>::order_sum;
1641   root_type const d0 = atan2(ca, static_cast<root_type>(cr));
1642   BOOST_IF_CONSTEXPR (order == 0)
1643     return fvar<RealType, Order>(d0);
1644   else {
1645     auto x = make_fvar<root_type, bool(order) ? order - 1 : 0>(static_cast<root_type>(cr));
1646     auto const d1 = -ca / ((x *= x) += (ca * ca));  // (d/dx)atan2(y,x) = -y / (x*x+y*y)
1647     return cr.apply_coefficients(order, [&d0, &d1](size_t i) { return i ? d1[i - 1] / i : d0; });
1648   }
1649 }
1650 
1651 template <typename RealType1, size_t Order1, typename RealType2, size_t Order2>
atan2(fvar<RealType1,Order1> const & cr1,fvar<RealType2,Order2> const & cr2)1652 promote<fvar<RealType1, Order1>, fvar<RealType2, Order2>> atan2(fvar<RealType1, Order1> const& cr1,
1653                                                                 fvar<RealType2, Order2> const& cr2) {
1654   using std::atan2;
1655   using return_type = promote<fvar<RealType1, Order1>, fvar<RealType2, Order2>>;
1656   using root_type = typename return_type::root_type;
1657   constexpr size_t order = return_type::order_sum;
1658   root_type const y = static_cast<root_type>(cr1);
1659   root_type const x = static_cast<root_type>(cr2);
1660   root_type const d00 = atan2(y, x);
1661   BOOST_IF_CONSTEXPR (order == 0)
1662     return return_type(d00);
1663   else {
1664     constexpr size_t order1 = fvar<RealType1, Order1>::order_sum;
1665     constexpr size_t order2 = fvar<RealType2, Order2>::order_sum;
1666     auto x01 = make_fvar<typename fvar<RealType2, Order2>::root_type, order2 - 1>(x);
1667     auto const d01 = -y / ((x01 *= x01) += (y * y));
1668     auto y10 = make_fvar<typename fvar<RealType1, Order1>::root_type, order1 - 1>(y);
1669     auto x10 = make_fvar<typename fvar<RealType2, Order2>::root_type, 0, order2>(x);
1670     auto const d10 = x10 / ((x10 * x10) + (y10 *= y10));
1671     auto const f = [&d00, &d01, &d10](size_t i, size_t j) {
1672       return i ? d10[i - 1][j] / i : j ? d01[j - 1] / j : d00;
1673     };
1674     return cr1.apply_coefficients(order, f, cr2);
1675   }
1676 }
1677 
1678 template <typename RealType1, size_t Order1, typename RealType2, size_t Order2>
fmod(fvar<RealType1,Order1> const & cr1,fvar<RealType2,Order2> const & cr2)1679 promote<fvar<RealType1, Order1>, fvar<RealType2, Order2>> fmod(fvar<RealType1, Order1> const& cr1,
1680                                                                fvar<RealType2, Order2> const& cr2) {
1681   using boost::math::trunc;
1682   auto const numer = static_cast<typename fvar<RealType1, Order1>::root_type>(cr1);
1683   auto const denom = static_cast<typename fvar<RealType2, Order2>::root_type>(cr2);
1684   return cr1 - cr2 * trunc(numer / denom);
1685 }
1686 
1687 template <typename RealType, size_t Order>
round(fvar<RealType,Order> const & cr)1688 fvar<RealType, Order> round(fvar<RealType, Order> const& cr) {
1689   using boost::math::round;
1690   return fvar<RealType, Order>(round(static_cast<typename fvar<RealType, Order>::root_type>(cr)));
1691 }
1692 
1693 template <typename RealType, size_t Order>
iround(fvar<RealType,Order> const & cr)1694 int iround(fvar<RealType, Order> const& cr) {
1695   using boost::math::iround;
1696   return iround(static_cast<typename fvar<RealType, Order>::root_type>(cr));
1697 }
1698 
1699 template <typename RealType, size_t Order>
lround(fvar<RealType,Order> const & cr)1700 long lround(fvar<RealType, Order> const& cr) {
1701   using boost::math::lround;
1702   return lround(static_cast<typename fvar<RealType, Order>::root_type>(cr));
1703 }
1704 
1705 template <typename RealType, size_t Order>
llround(fvar<RealType,Order> const & cr)1706 long long llround(fvar<RealType, Order> const& cr) {
1707   using boost::math::llround;
1708   return llround(static_cast<typename fvar<RealType, Order>::root_type>(cr));
1709 }
1710 
1711 template <typename RealType, size_t Order>
trunc(fvar<RealType,Order> const & cr)1712 fvar<RealType, Order> trunc(fvar<RealType, Order> const& cr) {
1713   using boost::math::trunc;
1714   return fvar<RealType, Order>(trunc(static_cast<typename fvar<RealType, Order>::root_type>(cr)));
1715 }
1716 
1717 template <typename RealType, size_t Order>
truncl(fvar<RealType,Order> const & cr)1718 long double truncl(fvar<RealType, Order> const& cr) {
1719   using std::truncl;
1720   return truncl(static_cast<typename fvar<RealType, Order>::root_type>(cr));
1721 }
1722 
1723 template <typename RealType, size_t Order>
itrunc(fvar<RealType,Order> const & cr)1724 int itrunc(fvar<RealType, Order> const& cr) {
1725   using boost::math::itrunc;
1726   return itrunc(static_cast<typename fvar<RealType, Order>::root_type>(cr));
1727 }
1728 
1729 template <typename RealType, size_t Order>
lltrunc(fvar<RealType,Order> const & cr)1730 long long lltrunc(fvar<RealType, Order> const& cr) {
1731   using boost::math::lltrunc;
1732   return lltrunc(static_cast<typename fvar<RealType, Order>::root_type>(cr));
1733 }
1734 
1735 template <typename RealType, size_t Order>
operator <<(std::ostream & out,fvar<RealType,Order> const & cr)1736 std::ostream& operator<<(std::ostream& out, fvar<RealType, Order> const& cr) {
1737   out << "depth(" << cr.depth << ")(" << cr.v.front();
1738   for (size_t i = 1; i <= Order; ++i)
1739     out << ',' << cr.v[i];
1740   return out << ')';
1741 }
1742 
1743 // Additional functions
1744 
1745 template <typename RealType, size_t Order>
acos(fvar<RealType,Order> const & cr)1746 fvar<RealType, Order> acos(fvar<RealType, Order> const& cr) {
1747   using std::acos;
1748   using root_type = typename fvar<RealType, Order>::root_type;
1749   constexpr size_t order = fvar<RealType, Order>::order_sum;
1750   root_type const d0 = acos(static_cast<root_type>(cr));
1751   BOOST_IF_CONSTEXPR (order == 0)
1752     return fvar<RealType, Order>(d0);
1753   else {
1754     auto x = make_fvar<root_type, bool(order) ? order - 1 : 0>(static_cast<root_type>(cr));
1755     auto const d1 = sqrt((x *= x).negate() += 1).inverse().negate();  // acos'(x) = -1 / sqrt(1-x*x).
1756     return cr.apply_coefficients(order, [&d0, &d1](size_t i) { return i ? d1[i - 1] / i : d0; });
1757   }
1758 }
1759 
1760 template <typename RealType, size_t Order>
acosh(fvar<RealType,Order> const & cr)1761 fvar<RealType, Order> acosh(fvar<RealType, Order> const& cr) {
1762   using boost::math::acosh;
1763   using root_type = typename fvar<RealType, Order>::root_type;
1764   constexpr size_t order = fvar<RealType, Order>::order_sum;
1765   root_type const d0 = acosh(static_cast<root_type>(cr));
1766   BOOST_IF_CONSTEXPR (order == 0)
1767     return fvar<RealType, Order>(d0);
1768   else {
1769     auto x = make_fvar<root_type, bool(order) ? order - 1 : 0>(static_cast<root_type>(cr));
1770     auto const d1 = sqrt((x *= x) -= 1).inverse();  // acosh'(x) = 1 / sqrt(x*x-1).
1771     return cr.apply_coefficients(order, [&d0, &d1](size_t i) { return i ? d1[i - 1] / i : d0; });
1772   }
1773 }
1774 
1775 template <typename RealType, size_t Order>
asinh(fvar<RealType,Order> const & cr)1776 fvar<RealType, Order> asinh(fvar<RealType, Order> const& cr) {
1777   using boost::math::asinh;
1778   using root_type = typename fvar<RealType, Order>::root_type;
1779   constexpr size_t order = fvar<RealType, Order>::order_sum;
1780   root_type const d0 = asinh(static_cast<root_type>(cr));
1781   BOOST_IF_CONSTEXPR (order == 0)
1782     return fvar<RealType, Order>(d0);
1783   else {
1784     auto x = make_fvar<root_type, bool(order) ? order - 1 : 0>(static_cast<root_type>(cr));
1785     auto const d1 = sqrt((x *= x) += 1).inverse();  // asinh'(x) = 1 / sqrt(x*x+1).
1786     return cr.apply_coefficients(order, [&d0, &d1](size_t i) { return i ? d1[i - 1] / i : d0; });
1787   }
1788 }
1789 
1790 template <typename RealType, size_t Order>
atanh(fvar<RealType,Order> const & cr)1791 fvar<RealType, Order> atanh(fvar<RealType, Order> const& cr) {
1792   using boost::math::atanh;
1793   using root_type = typename fvar<RealType, Order>::root_type;
1794   constexpr size_t order = fvar<RealType, Order>::order_sum;
1795   root_type const d0 = atanh(static_cast<root_type>(cr));
1796   BOOST_IF_CONSTEXPR (order == 0)
1797     return fvar<RealType, Order>(d0);
1798   else {
1799     auto x = make_fvar<root_type, bool(order) ? order - 1 : 0>(static_cast<root_type>(cr));
1800     auto const d1 = ((x *= x).negate() += 1).inverse();  // atanh'(x) = 1 / (1-x*x)
1801     return cr.apply_coefficients(order, [&d0, &d1](size_t i) { return i ? d1[i - 1] / i : d0; });
1802   }
1803 }
1804 
1805 template <typename RealType, size_t Order>
cosh(fvar<RealType,Order> const & cr)1806 fvar<RealType, Order> cosh(fvar<RealType, Order> const& cr) {
1807   BOOST_MATH_STD_USING
1808   using root_type = typename fvar<RealType, Order>::root_type;
1809   constexpr size_t order = fvar<RealType, Order>::order_sum;
1810   root_type const d0 = cosh(static_cast<root_type>(cr));
1811   BOOST_IF_CONSTEXPR (order == 0)
1812     return fvar<RealType, Order>(d0);
1813   else {
1814     root_type const derivatives[2]{d0, sinh(static_cast<root_type>(cr))};
1815     return cr.apply_derivatives(order, [&derivatives](size_t i) { return derivatives[i & 1]; });
1816   }
1817 }
1818 
1819 template <typename RealType, size_t Order>
digamma(fvar<RealType,Order> const & cr)1820 fvar<RealType, Order> digamma(fvar<RealType, Order> const& cr) {
1821   using boost::math::digamma;
1822   using root_type = typename fvar<RealType, Order>::root_type;
1823   constexpr size_t order = fvar<RealType, Order>::order_sum;
1824   root_type const x = static_cast<root_type>(cr);
1825   root_type const d0 = digamma(x);
1826   BOOST_IF_CONSTEXPR (order == 0)
1827     return fvar<RealType, Order>(d0);
1828   else {
1829     static_assert(order <= static_cast<size_t>((std::numeric_limits<int>::max)()),
1830                   "order exceeds maximum derivative for boost::math::polygamma().");
1831     return cr.apply_derivatives(
1832         order, [&x, &d0](size_t i) { return i ? boost::math::polygamma(static_cast<int>(i), x) : d0; });
1833   }
1834 }
1835 
1836 template <typename RealType, size_t Order>
erf(fvar<RealType,Order> const & cr)1837 fvar<RealType, Order> erf(fvar<RealType, Order> const& cr) {
1838   using boost::math::erf;
1839   using root_type = typename fvar<RealType, Order>::root_type;
1840   constexpr size_t order = fvar<RealType, Order>::order_sum;
1841   root_type const d0 = erf(static_cast<root_type>(cr));
1842   BOOST_IF_CONSTEXPR (order == 0)
1843     return fvar<RealType, Order>(d0);
1844   else {
1845     auto x = make_fvar<root_type, bool(order) ? order - 1 : 0>(static_cast<root_type>(cr));  // d1 = 2/sqrt(pi)*exp(-x*x)
1846     auto const d1 = 2 * constants::one_div_root_pi<root_type>() * exp((x *= x).negate());
1847     return cr.apply_coefficients(order, [&d0, &d1](size_t i) { return i ? d1[i - 1] / i : d0; });
1848   }
1849 }
1850 
1851 template <typename RealType, size_t Order>
erfc(fvar<RealType,Order> const & cr)1852 fvar<RealType, Order> erfc(fvar<RealType, Order> const& cr) {
1853   using boost::math::erfc;
1854   using root_type = typename fvar<RealType, Order>::root_type;
1855   constexpr size_t order = fvar<RealType, Order>::order_sum;
1856   root_type const d0 = erfc(static_cast<root_type>(cr));
1857   BOOST_IF_CONSTEXPR (order == 0)
1858     return fvar<RealType, Order>(d0);
1859   else {
1860     auto x = make_fvar<root_type, bool(order) ? order - 1 : 0>(static_cast<root_type>(cr));  // erfc'(x) = -erf'(x)
1861     auto const d1 = -2 * constants::one_div_root_pi<root_type>() * exp((x *= x).negate());
1862     return cr.apply_coefficients(order, [&d0, &d1](size_t i) { return i ? d1[i - 1] / i : d0; });
1863   }
1864 }
1865 
1866 template <typename RealType, size_t Order>
lambert_w0(fvar<RealType,Order> const & cr)1867 fvar<RealType, Order> lambert_w0(fvar<RealType, Order> const& cr) {
1868   using std::exp;
1869   using boost::math::lambert_w0;
1870   using root_type = typename fvar<RealType, Order>::root_type;
1871   constexpr size_t order = fvar<RealType, Order>::order_sum;
1872   root_type derivatives[order + 1];
1873   *derivatives = lambert_w0(static_cast<root_type>(cr));
1874   BOOST_IF_CONSTEXPR (order == 0)
1875     return fvar<RealType, Order>(*derivatives);
1876   else {
1877     root_type const expw = exp(*derivatives);
1878     derivatives[1] = 1 / (static_cast<root_type>(cr) + expw);
1879     BOOST_IF_CONSTEXPR (order == 1)
1880       return cr.apply_derivatives_nonhorner(order, [&derivatives](size_t i) { return derivatives[i]; });
1881     else {
1882       using diff_t = typename std::array<RealType, Order + 1>::difference_type;
1883       root_type d1powers = derivatives[1] * derivatives[1];
1884       root_type const x = derivatives[1] * expw;
1885       derivatives[2] = d1powers * (-1 - x);
1886       std::array<root_type, order> coef{{-1, -1}};  // as in derivatives[2].
1887       for (size_t n = 3; n <= order; ++n) {
1888         coef[n - 1] = coef[n - 2] * -static_cast<root_type>(2 * n - 3);
1889         for (size_t j = n - 2; j != 0; --j)
1890           (coef[j] *= -static_cast<root_type>(n - 1)) -= (n + j - 2) * coef[j - 1];
1891         coef[0] *= -static_cast<root_type>(n - 1);
1892         d1powers *= derivatives[1];
1893         derivatives[n] =
1894             d1powers * std::accumulate(coef.crend() - diff_t(n - 1),
1895                                        coef.crend(),
1896                                        coef[n - 1],
1897                                        [&x](root_type const& a, root_type const& b) { return a * x + b; });
1898       }
1899       return cr.apply_derivatives_nonhorner(order, [&derivatives](size_t i) { return derivatives[i]; });
1900     }
1901   }
1902 }
1903 
1904 template <typename RealType, size_t Order>
lgamma(fvar<RealType,Order> const & cr)1905 fvar<RealType, Order> lgamma(fvar<RealType, Order> const& cr) {
1906   using std::lgamma;
1907   using root_type = typename fvar<RealType, Order>::root_type;
1908   constexpr size_t order = fvar<RealType, Order>::order_sum;
1909   root_type const x = static_cast<root_type>(cr);
1910   root_type const d0 = lgamma(x);
1911   BOOST_IF_CONSTEXPR (order == 0)
1912     return fvar<RealType, Order>(d0);
1913   else {
1914     static_assert(order <= static_cast<size_t>((std::numeric_limits<int>::max)()) + 1,
1915                   "order exceeds maximum derivative for boost::math::polygamma().");
1916     return cr.apply_derivatives(
1917         order, [&x, &d0](size_t i) { return i ? boost::math::polygamma(static_cast<int>(i - 1), x) : d0; });
1918   }
1919 }
1920 
1921 template <typename RealType, size_t Order>
sinc(fvar<RealType,Order> const & cr)1922 fvar<RealType, Order> sinc(fvar<RealType, Order> const& cr) {
1923   if (cr != 0)
1924     return sin(cr) / cr;
1925   using root_type = typename fvar<RealType, Order>::root_type;
1926   constexpr size_t order = fvar<RealType, Order>::order_sum;
1927   root_type taylor[order + 1]{1};  // sinc(0) = 1
1928   BOOST_IF_CONSTEXPR (order == 0)
1929     return fvar<RealType, Order>(*taylor);
1930   else {
1931     for (size_t n = 2; n <= order; n += 2)
1932       taylor[n] = (1 - static_cast<int>(n & 2)) / factorial<root_type>(static_cast<unsigned>(n + 1));
1933     return cr.apply_coefficients_nonhorner(order, [&taylor](size_t i) { return taylor[i]; });
1934   }
1935 }
1936 
1937 template <typename RealType, size_t Order>
sinh(fvar<RealType,Order> const & cr)1938 fvar<RealType, Order> sinh(fvar<RealType, Order> const& cr) {
1939   BOOST_MATH_STD_USING
1940   using root_type = typename fvar<RealType, Order>::root_type;
1941   constexpr size_t order = fvar<RealType, Order>::order_sum;
1942   root_type const d0 = sinh(static_cast<root_type>(cr));
1943   BOOST_IF_CONSTEXPR (fvar<RealType, Order>::order_sum == 0)
1944     return fvar<RealType, Order>(d0);
1945   else {
1946     root_type const derivatives[2]{d0, cosh(static_cast<root_type>(cr))};
1947     return cr.apply_derivatives(order, [&derivatives](size_t i) { return derivatives[i & 1]; });
1948   }
1949 }
1950 
1951 template <typename RealType, size_t Order>
tanh(fvar<RealType,Order> const & cr)1952 fvar<RealType, Order> tanh(fvar<RealType, Order> const& cr) {
1953   fvar<RealType, Order> retval = exp(cr * 2);
1954   fvar<RealType, Order> const denom = retval + 1;
1955   (retval -= 1) /= denom;
1956   return retval;
1957 }
1958 
1959 template <typename RealType, size_t Order>
tgamma(fvar<RealType,Order> const & cr)1960 fvar<RealType, Order> tgamma(fvar<RealType, Order> const& cr) {
1961   using std::tgamma;
1962   using root_type = typename fvar<RealType, Order>::root_type;
1963   constexpr size_t order = fvar<RealType, Order>::order_sum;
1964   BOOST_IF_CONSTEXPR (order == 0)
1965     return fvar<RealType, Order>(tgamma(static_cast<root_type>(cr)));
1966   else {
1967     if (cr < 0)
1968       return constants::pi<root_type>() / (sin(constants::pi<root_type>() * cr) * tgamma(1 - cr));
1969     return exp(lgamma(cr)).set_root(tgamma(static_cast<root_type>(cr)));
1970   }
1971 }
1972 
1973 }  // namespace detail
1974 }  // namespace autodiff_v1
1975 }  // namespace differentiation
1976 }  // namespace math
1977 }  // namespace boost
1978 
1979 namespace std {
1980 
1981 // boost::math::tools::digits<RealType>() is handled by this std::numeric_limits<> specialization,
1982 // and similarly for max_value, min_value, log_max_value, log_min_value, and epsilon.
1983 template <typename RealType, size_t Order>
1984 class numeric_limits<boost::math::differentiation::detail::fvar<RealType, Order>>
1985     : public numeric_limits<typename boost::math::differentiation::detail::fvar<RealType, Order>::root_type> {
1986 };
1987 
1988 }  // namespace std
1989 
1990 namespace boost {
1991 namespace math {
1992 namespace tools {
1993 namespace detail {
1994 
1995 template <typename RealType, std::size_t Order>
1996 using autodiff_fvar_type = differentiation::detail::fvar<RealType, Order>;
1997 
1998 template <typename RealType, std::size_t Order>
1999 using autodiff_root_type = typename autodiff_fvar_type<RealType, Order>::root_type;
2000 }  // namespace detail
2001 
2002 // See boost/math/tools/promotion.hpp
2003 template <typename RealType0, size_t Order0, typename RealType1, size_t Order1>
2004 struct promote_args_2<detail::autodiff_fvar_type<RealType0, Order0>,
2005                       detail::autodiff_fvar_type<RealType1, Order1>> {
2006   using type = detail::autodiff_fvar_type<typename promote_args_2<RealType0, RealType1>::type,
2007 #ifndef BOOST_NO_CXX14_CONSTEXPR
2008                                           (std::max)(Order0, Order1)>;
2009 #else
2010         Order0<Order1 ? Order1 : Order0>;
2011 #endif
2012 };
2013 
2014 template <typename RealType, size_t Order>
2015 struct promote_args<detail::autodiff_fvar_type<RealType, Order>> {
2016   using type = detail::autodiff_fvar_type<typename promote_args<RealType>::type, Order>;
2017 };
2018 
2019 template <typename RealType0, size_t Order0, typename RealType1>
2020 struct promote_args_2<detail::autodiff_fvar_type<RealType0, Order0>, RealType1> {
2021   using type = detail::autodiff_fvar_type<typename promote_args_2<RealType0, RealType1>::type, Order0>;
2022 };
2023 
2024 template <typename RealType0, typename RealType1, size_t Order1>
2025 struct promote_args_2<RealType0, detail::autodiff_fvar_type<RealType1, Order1>> {
2026   using type = detail::autodiff_fvar_type<typename promote_args_2<RealType0, RealType1>::type, Order1>;
2027 };
2028 
2029 template <typename destination_t, typename RealType, std::size_t Order>
real_cast(detail::autodiff_fvar_type<RealType,Order> const & from_v)2030 inline BOOST_MATH_CONSTEXPR destination_t real_cast(detail::autodiff_fvar_type<RealType, Order> const& from_v)
2031     BOOST_NOEXCEPT_IF(BOOST_MATH_IS_FLOAT(destination_t) && BOOST_MATH_IS_FLOAT(RealType)) {
2032   return real_cast<destination_t>(static_cast<detail::autodiff_root_type<RealType, Order>>(from_v));
2033 }
2034 
2035 }  // namespace tools
2036 
2037 namespace policies {
2038 
2039 template <class Policy, std::size_t Order>
2040 using fvar_t = differentiation::detail::fvar<Policy, Order>;
2041 template <class Policy, std::size_t Order>
2042 struct evaluation<fvar_t<float, Order>, Policy> {
2043   using type = fvar_t<typename conditional<Policy::promote_float_type::value, double, float>::type, Order>;
2044 };
2045 
2046 template <class Policy, std::size_t Order>
2047 struct evaluation<fvar_t<double, Order>, Policy> {
2048   using type =
2049       fvar_t<typename conditional<Policy::promote_double_type::value, long double, double>::type, Order>;
2050 };
2051 
2052 }  // namespace policies
2053 }  // namespace math
2054 }  // namespace boost
2055 
2056 #ifdef BOOST_NO_CXX17_IF_CONSTEXPR
2057 #include "autodiff_cpp11.hpp"
2058 #endif
2059 
2060 #endif  // BOOST_MATH_DIFFERENTIATION_AUTODIFF_HPP
2061