Reference documentation for deal.II version 9.0.0
ad_number_traits.h
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2016 - 2017 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE at
12 // the top level of the deal.II distribution.
13 //
14 // ---------------------------------------------------------------------
15 
16 #ifndef dealii_differentiation_ad_ad_number_traits_h
17 #define dealii_differentiation_ad_ad_number_traits_h
18 
19 #include <deal.II/base/exceptions.h>
20 #include <deal.II/differentiation/ad/ad_number_types.h>
21 
22 #include <boost/type_traits.hpp>
23 
24 #include <complex>
25 #include <type_traits>
26 
27 DEAL_II_NAMESPACE_OPEN
28 
29 namespace Differentiation
30 {
31  namespace AD
32  {
33 
47  template<typename ScalarType, enum NumberTypes ADNumberTypeCode, typename T = void>
48  struct NumberTraits;
49 
50 
51 
66  template<typename ADNumberType, typename T = void>
68 
69 
74  namespace internal
75  {
76 
77  // The following three classes, namely ADNumberInfoFromEnum, Marking, and
78  // ExtractData, are those that need to be implemented for each new
79  // auto-differentiable number type. This information is then used by
80  // NumberTraits and ADNumberTraits to provide a uniform interface, as used
81  // by our drivers, to the underlying number types.
82 
83 
109  template<typename ScalarType, enum NumberTypes ADNumberTypeCode, typename = void>
111 
112 
144  template<typename ADNumberType, typename T = void>
145  struct Marking;
146 
147 
179  template<typename ADNumberType, typename T = void>
180  struct ExtractData;
181 
182 
197  template <typename ADNumberTrait, typename T = void>
199 
200 
217  template <typename T>
218  struct NumberType;
219 
220 
227  template<typename Number>
229 
230  } // namespace internal
231 
232 
241  template <typename NumberType>
242  struct is_ad_number;
243 
244 
253  template <typename NumberType, typename = void>
255 
256 
265  template <typename NumberType, typename = void>
267 
268 
277  template <typename NumberType, typename = void>
279 
280 
289  template <typename NumberType, typename = void>
291 
292  } // namespace AD
293 } // namespace Differentiation
294 
295 
296 /* --------------------------- inline and template functions and specializations ------------------------- */
297 
298 
299 #ifndef DOXYGEN
300 
301 
302 namespace Differentiation
303 {
304  namespace AD
305  {
306  namespace internal
307  {
308  template <typename ADNumberTrait, typename>
309  struct HasRequiredADInfo
310  : std::false_type
311  { };
312 
313 
324  template <typename ADNumberTrait>
325  struct HasRequiredADInfo <ADNumberTrait, decltype(
326  (void) ADNumberTrait::type_code,
327  (void) ADNumberTrait::is_taped,
328  (void) std::declval<typename ADNumberTrait::real_type>(),
329  (void) std::declval<typename ADNumberTrait::derivative_type>(),
330  void() )> : std::true_type
331  { };
332 
333 
339  template<typename ScalarType>
340  struct Marking<ScalarType, typename std::enable_if<
341  std::is_arithmetic<ScalarType>::value
342  >::type>
343  {
351  template<typename ADNumberType>
352  static void
353  independent_variable(const ScalarType &in,
354  const unsigned int ,
355  const unsigned int ,
356  ADNumberType &out)
357  {
358  out = in;
359  }
360 
361  /*
362  * Initialize the state of a dependent variable.
363  */
364  template<typename ADNumberType>
365  static void
366  dependent_variable(ADNumberType &,
367  const ScalarType &)
368  {
369  AssertThrow(false, ExcMessage("Floating point numbers cannot be marked as dependent variables."));
370  }
371  };
372 
373 
377  template<typename ADNumberType>
378  struct Marking<ADNumberType, typename std::enable_if<
379  boost::is_complex<ADNumberType>::value
380  >::type>
381  {
382 
383  /*
384  * Initialize the state of an independent variable.
385  */
386  template<typename ScalarType>
387  static void
388  independent_variable(const ScalarType &in,
389  const unsigned int ,
390  const unsigned int ,
391  ADNumberType &out)
392  {
393  AssertThrow(false, ExcMessage("Marking for complex numbers has not yet been implemented."));
394  out = in;
395  }
396 
397  /*
398  * Initialize the state of a dependent variable.
399  */
400  template<typename ScalarType>
401  static void
402  dependent_variable(ADNumberType &,
403  const ScalarType &)
404  {
405  AssertThrow(false, ExcMessage("Marking for complex numbers has not yet been implemented."));
406  }
407  };
408 
409  } // namespace internal
410 
411 
412  template <typename NumberType, typename>
413  struct is_taped_ad_number
414  : std::false_type
415  {};
416 
417 
418  template <typename NumberType, typename>
419  struct is_tapeless_ad_number
420  : std::false_type
421  {};
422 
423 
424  template <typename NumberType, typename>
425  struct is_real_valued_ad_number
426  : std::false_type
427  {};
428 
429 
430  template <typename NumberType, typename>
431  struct is_complex_valued_ad_number
432  : std::false_type
433  {};
434 
435 
441  template <typename NumberType>
442  struct is_ad_number
443  : internal::HasRequiredADInfo< ADNumberTraits<typename std::decay<NumberType>::type> >
444  {};
445 
446 
451  template <typename NumberType>
452  struct is_taped_ad_number<NumberType, typename std::enable_if<
453  ADNumberTraits<typename std::decay<NumberType>::type>::is_taped
454  >::type>
455  : std::true_type
456  {};
457 
458 
463  template <typename NumberType>
464  struct is_tapeless_ad_number<NumberType, typename std::enable_if<
465  ADNumberTraits<typename std::decay<NumberType>::type>::is_tapeless
466  >::type>
467  : std::true_type
468  {};
469 
470 
475  template <typename NumberType>
476  struct is_real_valued_ad_number<NumberType, typename std::enable_if<
477  ADNumberTraits<typename std::decay<NumberType>::type>::is_real_valued
478  >::type>
479  : std::true_type
480  {};
481 
482 
487  template <typename NumberType>
488  struct is_complex_valued_ad_number<NumberType, typename std::enable_if<
489  ADNumberTraits<typename std::decay<NumberType>::type>::is_complex_valued
490  >::type>
491  : std::true_type
492  {};
493 
494 
495  namespace internal
496  {
497 
502  template<typename Number>
503  struct RemoveComplexWrapper
504  {
505  typedef Number type;
506  };
507 
508 
514  template<typename Number>
515  struct RemoveComplexWrapper<std::complex<Number> >
516  {
517  typedef typename RemoveComplexWrapper<Number>::type type;
518  };
519 
520 
526  template<typename NumberType>
527  struct ExtractData<NumberType, typename std::enable_if<
528  std::is_arithmetic<NumberType>::value
529  >::type>
530  {
534  static const NumberType &
535  value (const NumberType &x)
536  {
537  return x;
538  }
539 
540 
544  static unsigned int
545  n_directional_derivatives (const NumberType &)
546  {
547  return 0;
548  }
549 
550 
554  static NumberType
555  directional_derivative (const NumberType &,
556  const unsigned int )
557  {
558  return 0.0;
559  }
560  };
561 
562 
563 
568  template<typename ADNumberType>
569  struct ExtractData< std::complex<ADNumberType> >
570  {
571  static_assert(
573  "Expected an auto-differentiable number."
574  );
575 
576 
580  static std::complex<typename ADNumberTraits<ADNumberType>::scalar_type>
581  value (const std::complex<ADNumberType> &x)
582  {
583  return std::complex<typename ADNumberTraits<ADNumberType>::scalar_type>(
584  ExtractData<ADNumberType>::value(x.real()),
585  ExtractData<ADNumberType>::value(x.imag()) );
586  }
587 
588 
592  static unsigned int
593  n_directional_derivatives (const std::complex<ADNumberType> &x)
594  {
595  return ExtractData<ADNumberType>::n_directional_derivatives(x.real());
596  }
597 
598 
602  static std::complex<typename ADNumberTraits<ADNumberType>::derivative_type>
603  directional_derivative (const std::complex<ADNumberType> &x,
604  const unsigned int direction)
605  {
606  return std::complex<typename ADNumberTraits<ADNumberType>::derivative_type>(
607  ExtractData<ADNumberType>::directional_derivative(x.real(), direction),
608  ExtractData<ADNumberType>::directional_derivative(x.imag(), direction) );
609  }
610  };
611 
612 
613  template <typename T>
614  struct NumberType
615  {
619  template<typename F>
620  static auto
621  value (const F &f,
622  typename std::enable_if<
623  !is_ad_number<F>::value
624  >::type * = nullptr)
625  -> decltype (::internal::NumberType<T>::value(f))
626  {
627  // We call the other function defined in the numbers
628  // header to take care of all of the usual cases.
629  return ::internal::NumberType<T>::value(f);
630  }
631 
638  template<typename F>
639  static T
640  value (const F &f,
641  typename std::enable_if<
642  is_ad_number<F>::value &&
643  std::is_arithmetic<T>::value
644  >::type * = nullptr)
645  {
646  // We recursively call this function in case the AD number is a
647  // nested one. The recursion ends when the extracted value is
648  // a floating point number.
649  return NumberType<T>::value(ExtractData<F>::value(f));
650  }
651 
658  template<typename F>
659  static T
660  value (const F &f,
661  typename std::enable_if<
662  is_ad_number<F>::value &&
663  is_ad_number<T>::value
664  >::type * = nullptr)
665  {
666  return T(f);
667  }
668  };
669 
670  template <typename T>
671  struct NumberType< std::complex<T> >
672  {
676  template<typename F>
677  static auto
678  value (const F &f,
679  typename std::enable_if<
680  !is_ad_number<F>::value
681  >::type * = nullptr)
682  -> decltype (::internal::NumberType< std::complex<T> >::value(f))
683  {
684  // We call the other function defined in the numbers
685  // header to take care of all of the usual cases.
686  return ::internal::NumberType< std::complex<T> >::value(f);
687  }
688 
689 
694  template<typename F>
695  static std::complex<T>
696  value (const F &f,
697  typename std::enable_if<
698  is_ad_number<F>::value &&
699  std::is_arithmetic<T>::value
700  >::type * = nullptr)
701  {
702  // We recursively call this function in case the AD number is a
703  // nested one. The recursion ends when the extracted value is
704  // a floating point number.
705  return std::complex<T>(NumberType<T>::value(ExtractData<F>::value(f)));
706  }
707 
708  template <typename F>
709  static std::complex<T>
710  value (const std::complex<F> &f)
711  {
712  // Deal with the two parts of the input complex
713  // number individually.
714  return std::complex<T>(
715  NumberType<T>::value(f.real()),
716  NumberType<T>::value(f.imag()));
717  }
718  };
719 
720  } // namespace internal
721 
722 
723 
744  template<typename ScalarType, enum NumberTypes ADNumberTypeCode>
745  struct NumberTraits<ScalarType, ADNumberTypeCode, typename std::enable_if<
746  std::is_floating_point<ScalarType>::value ||
747  (boost::is_complex<ScalarType>::value &&
748  std::is_floating_point<typename internal::RemoveComplexWrapper<ScalarType>::type>::value)
749  >::type>
750  {
754  static constexpr enum NumberTypes type_code
755  = ADNumberTypeCode;
756 
757  // The clang compiler does not seem to like these
758  // variables being defined as constant expressions
759  // (the tests <adolc|sacado>/ad_number_traits_02 will
760  // fail with linking errors). However, GCC complains
761  // about the use of non-constant expressions in
762  // std::conditional.
763 #ifdef __clang__
764 
769  static const bool is_taped;
770 
771 
776  static const bool is_tapeless;
777 
778 
783  static const bool is_real_valued;
784 
785 
790  static const bool is_complex_valued;
791 
792 
797  static const unsigned int n_supported_derivative_levels;
798 
799 #else
800 
805  static constexpr bool is_taped
806  = internal::ADNumberInfoFromEnum<
807  typename internal::RemoveComplexWrapper<ScalarType>::type, ADNumberTypeCode
808  >::is_taped;
809 
810 
815  static constexpr bool is_tapeless
816  = !(NumberTraits<ScalarType,ADNumberTypeCode>::is_taped);
817 
818 
823  static constexpr bool is_real_valued
824  = (!boost::is_complex<ScalarType>::value);
825 
826 
831  static constexpr bool is_complex_valued
832  = !(NumberTraits<ScalarType,ADNumberTypeCode>::is_real_valued);
833 
834 
839  static constexpr unsigned int n_supported_derivative_levels
840  = internal::ADNumberInfoFromEnum<
841  typename internal::RemoveComplexWrapper<ScalarType>::type, ADNumberTypeCode
842  >::n_supported_derivative_levels;
843 
844 #endif
845 
846 
851  typedef ScalarType scalar_type;
852 
853 
857  typedef typename internal::ADNumberInfoFromEnum<
858  typename internal::RemoveComplexWrapper<ScalarType>::type,ADNumberTypeCode
859  >::real_type real_type;
860 
861 
865  typedef std::complex<real_type> complex_type;
866 
867 
871  typedef typename std::conditional<
872  is_real_valued,real_type,complex_type
873  >::type ad_type;
874 
878  typedef typename std::conditional<
879  is_real_valued,
880  typename internal::ADNumberInfoFromEnum<
881  typename internal::RemoveComplexWrapper<ScalarType>::type,ADNumberTypeCode
882  >::derivative_type,
883  std::complex<typename internal::ADNumberInfoFromEnum<
884  typename internal::RemoveComplexWrapper<ScalarType>::type,ADNumberTypeCode
885  >::derivative_type>
886  >::type derivative_type;
887 
888 
892  static scalar_type
893  get_scalar_value(const ad_type &x)
894  {
895  // Some tricky conversion cases to consider here:
896  // - Nested AD numbers
897  // - std::complex<double> --> std::complex<float>
898  // e.g. when ScalarType = float and ADNumberTypeCode = adolc_taped
899  // Therefore, we use the internal casting mechanism
900  // provided by the internal::NumberType struct.
901  return internal::NumberType<scalar_type>::value(internal::ExtractData<ad_type>::value(x));
902  }
903 
904 
908  static derivative_type
909  get_directional_derivative(const ad_type &x,
910  const unsigned int direction)
911  {
912  return internal::ExtractData<ad_type>::directional_derivative(x, direction);
913  }
914 
915 
920  static unsigned int
921  n_directional_derivatives(const ad_type &x)
922  {
923  return internal::ExtractData<ad_type>::n_directional_derivatives(x);
924  }
925 
926 
927  static_assert(
928  (is_real_valued==true ?
929  std::is_same<ad_type,real_type>::value :
930  std::is_same<ad_type,complex_type>::value),
931  "Incorrect template type selected for ad_type");
932 
933  static_assert(
934  (is_complex_valued==true ?
935  boost::is_complex<scalar_type>::value :
936  true),
937  "Expected a complex float_type");
938 
939  static_assert(
940  (is_complex_valued==true ?
941  boost::is_complex<ad_type>::value :
942  true),
943  "Expected a complex ad_type");
944 
945  };
946 
947 #ifdef __clang__
948 
949  template<typename ScalarType, enum NumberTypes ADNumberTypeCode>
950  const bool
951  NumberTraits<ScalarType, ADNumberTypeCode, typename std::enable_if<
952  std::is_floating_point<ScalarType>::value ||
953  (boost::is_complex<ScalarType>::value &&
954  std::is_floating_point<typename internal::RemoveComplexWrapper<ScalarType>::type>::value)
955  >::type>::is_taped
956  = internal::ADNumberInfoFromEnum<
957  typename internal::RemoveComplexWrapper<ScalarType>::type, ADNumberTypeCode
958  >::is_taped;
959 
960 
961  template<typename ScalarType, enum NumberTypes ADNumberTypeCode>
962  const bool
963  NumberTraits<ScalarType, ADNumberTypeCode, typename std::enable_if<
964  std::is_floating_point<ScalarType>::value ||
965  (boost::is_complex<ScalarType>::value &&
966  std::is_floating_point<typename internal::RemoveComplexWrapper<ScalarType>::type>::value)
967  >::type>::is_tapeless
968  = !(NumberTraits<ScalarType,ADNumberTypeCode>::is_taped);
969 
970 
971  template<typename ScalarType, enum NumberTypes ADNumberTypeCode>
972  const bool
973  NumberTraits<ScalarType, ADNumberTypeCode, typename std::enable_if<
974  std::is_floating_point<ScalarType>::value ||
975  (boost::is_complex<ScalarType>::value &&
976  std::is_floating_point<typename internal::RemoveComplexWrapper<ScalarType>::type>::value)
977  >::type>::is_real_valued
978  = (!boost::is_complex<ScalarType>::value);
979 
980 
981  template<typename ScalarType, enum NumberTypes ADNumberTypeCode>
982  const bool
983  NumberTraits<ScalarType, ADNumberTypeCode, typename std::enable_if<
984  std::is_floating_point<ScalarType>::value ||
985  (boost::is_complex<ScalarType>::value &&
986  std::is_floating_point<typename internal::RemoveComplexWrapper<ScalarType>::type>::value)
987  >::type>::is_complex_valued
988  = !(NumberTraits<ScalarType,ADNumberTypeCode>::is_real_valued);
989 
990 
991  template<typename ScalarType, enum NumberTypes ADNumberTypeCode>
992  const unsigned int
993  NumberTraits<ScalarType, ADNumberTypeCode, typename std::enable_if<
994  std::is_floating_point<ScalarType>::value ||
995  (boost::is_complex<ScalarType>::value &&
996  std::is_floating_point<typename internal::RemoveComplexWrapper<ScalarType>::type>::value)
997  >::type>::n_supported_derivative_levels
998  = internal::ADNumberInfoFromEnum<
999  typename internal::RemoveComplexWrapper<ScalarType>::type, ADNumberTypeCode
1000  >::n_supported_derivative_levels;
1001 
1002 #endif
1003 
1004 
1019  template<typename ScalarType>
1020  struct ADNumberTraits<ScalarType, typename std::enable_if<
1021  std::is_arithmetic<ScalarType>::value
1022  >::type>
1023  {
1028  typedef ScalarType scalar_type;
1029 
1030  static ScalarType
1031  get_directional_derivative(const ScalarType &/*x*/,
1032  const unsigned int /*direction*/)
1033  {
1034  // If the AD drivers are correctly implemented then we should not get here.
1035  // This is essentially a dummy for when the ADNumberTypeCode for the original
1036  // AD number (from which one is getting a derivative >= 2) is one that specified
1037  // Adol-C taped and tapeless numbers, or a non-nested Sacado number.
1038  AssertThrow(false, ExcMessage("Floating point numbers have no directional derivatives."));
1039  return 0.0;
1040  }
1041  };
1042 
1043  } // namespace AD
1044 } // namespace Differentiation
1045 
1046 #endif // DOXYGEN
1047 
1048 
1049 namespace numbers
1050 {
1051 
1052  template<typename ADNumberType>
1053  bool
1054  is_nan (const typename std::enable_if<
1056  ADNumberType>::type &x)
1057  {
1059  }
1060 
1061 } // namespace numbers
1062 
1063 
1064 DEAL_II_NAMESPACE_CLOSE
1065 
1066 #endif
STL namespace.
#define AssertThrow(cond, exc)
Definition: exceptions.h:1221
static ::ExceptionBase & ExcMessage(std::string arg1)
bool is_nan(const double x)
Definition: numbers.h:400