@@ -1062,6 +1062,112 @@ CUDA_HOST_DEVICE void hypot_pullback(T x, T y, U d_z, T* d_x, T* d_y) {
10621062 *d_y += (y / h) * d_z;
10631063}
10641064
1065+ // 7. Special Functions
1066+ #if __cplusplus >= 201703L
1067+ template <typename T> CUDA_HOST_DEVICE inline T clad_beta_primal (T x, T y) {
1068+ #if defined(__cpp_lib_math_special_functions)
1069+ return ::std::beta (x, y);
1070+ #else
1071+ return ::std::tgamma (x) * ::std::tgamma (y) / ::std::tgamma (x + y);
1072+ #endif
1073+ }
1074+ // Computes the digamma function psi(x) using a standard asymptotic expansion
1075+ // NOTE: This is a numerical approximation
1076+ // Reference: Wolfram MathWorld, Digamma Function
1077+ // https://mathworld.wolfram.com/DigammaFunction.html
1078+
1079+ template <typename T> CUDA_HOST_DEVICE inline T clad_digamma (T x) {
1080+ if (x <= 0.0 ) {
1081+ if (x == ::std::floor (x))
1082+ return (T)NAN ;
1083+ return clad_digamma (1.0 - x) -
1084+ ::std::acos ((T)-1.0) / ::std::tan(::std::acos((T)-1.0) * x);
1085+ }
1086+ T result = 0.0 ;
1087+ while (x < 8.0 ) {
1088+ result -= 1.0 / x;
1089+ x += 1.0 ;
1090+ }
1091+ T inv_x = 1.0 / x;
1092+ T inv_x2 = inv_x * inv_x;
1093+ result +=
1094+ ::std::log (x) - 0.5 * inv_x -
1095+ inv_x2 * (1.0 / 12.0 -
1096+ inv_x2 * (1.0 / 120.0 -
1097+ inv_x2 * (1.0 / 252.0 - inv_x2 * (1.0 / 240.0 ))));
1098+ return result;
1099+ }
1100+
1101+ // NOTE: Like digamma this uses a truncated asymptotic expansion.
1102+ // Used as a custom derivative for digamma
1103+ // Reference: Wolfram MathWorld, Trigamma Function
1104+ // https://mathworld.wolfram.com/TrigammaFunction.html
1105+
1106+ template <typename T> CUDA_HOST_DEVICE inline T clad_trigamma (T x) {
1107+ if (x <= 0.0 ) {
1108+ if (x == ::std::floor (x))
1109+ return (T)NAN ;
1110+ T pi = ::std::acos ((T)-1.0 );
1111+ T csc = 1.0 / ::std::sin (pi * x);
1112+ return -clad_trigamma (1.0 - x) + (pi * pi * csc * csc);
1113+ }
1114+
1115+ T result = 0.0 ;
1116+ while (x < 8.0 ) {
1117+ result += 1.0 / (x * x);
1118+ x += 1.0 ;
1119+ }
1120+
1121+ T inv_x = 1.0 / x;
1122+ T inv_x2 = inv_x * inv_x;
1123+
1124+ result += inv_x + 0.5 * inv_x2 +
1125+ inv_x2 * inv_x *
1126+ (1.0 / 6.0 -
1127+ inv_x2 * (1.0 / 30.0 -
1128+ inv_x2 * (1.0 / 42.0 - inv_x2 * (1.0 / 30.0 ))));
1129+ return result;
1130+ }
1131+
1132+ template <typename T, typename dT>
1133+ CUDA_HOST_DEVICE ValueAndPushforward<T, dT> digamma_pushforward (T x, dT d_x) {
1134+ T psi = clad_digamma (x);
1135+ dT pushforward = 0 ;
1136+ if (d_x)
1137+ pushforward += clad_trigamma (x) * d_x;
1138+ return {psi, pushforward};
1139+ }
1140+
1141+ template <typename T, typename U>
1142+ CUDA_HOST_DEVICE void digamma_pullback (T x, U d_z, T* d_x) {
1143+ if (d_x)
1144+ *d_x += clad_trigamma (x) * d_z;
1145+ }
1146+
1147+ template <typename T, typename dT>
1148+ CUDA_HOST_DEVICE ValueAndPushforward<T, dT> beta_pushforward (T x, T y, dT d_x,
1149+ dT d_y) {
1150+ T b = clad_beta_primal (x, y);
1151+ T psi_xy = clad_digamma (x + y);
1152+ dT pushforward = 0 ;
1153+ if (d_x)
1154+ pushforward += b * (clad_digamma (x) - psi_xy) * d_x;
1155+ if (d_y)
1156+ pushforward += b * (clad_digamma (y) - psi_xy) * d_y;
1157+ return {b, pushforward};
1158+ }
1159+
1160+ template <typename T, typename U>
1161+ CUDA_HOST_DEVICE void beta_pullback (T x, T y, U d_z, T* d_x, T* d_y) {
1162+ T b = clad_beta_primal (x, y);
1163+ T psi_xy = clad_digamma (x + y);
1164+ if (d_x)
1165+ *d_x += b * (clad_digamma (x) - psi_xy) * d_z;
1166+ if (d_y)
1167+ *d_y += b * (clad_digamma (y) - psi_xy) * d_z;
1168+ }
1169+ #endif
1170+
10651171} // namespace std
10661172
10671173CUDA_HOST_DEVICE inline ValueAndPushforward<float , float >
@@ -1327,6 +1433,12 @@ using std::pow_pullback;
13271433using std::pow_pushforward;
13281434using std::sqrt_pushforward;
13291435
1436+ // 7. Special Functions
1437+ #if __cplusplus >= 201703L
1438+ using std::beta_pullback;
1439+ using std::beta_pushforward;
1440+ #endif
1441+
13301442namespace class_functions {
13311443template <typename T, typename U>
13321444void constructor_pullback (ValueAndPushforward<T, U> rhs,
0 commit comments