Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
1f55b2f
[Derivatives] Add support for std::comp_ellint_1
ayush4874 Dec 11, 2025
a4df60d
Implement derivative (darg0) and tests for std::comp_ellint_1
ayush4874 Dec 11, 2025
5f82a9d
Refactor: Move ellint_1 test to stl-cmath.cpp and clean comments
ayush4874 Dec 13, 2025
98de955
Refactor: Use templated wrapper for ellint_1 to match test style
ayush4874 Dec 13, 2025
7e4deb8
Refactor: Add full set of manual wrappers (f/l suffixes) for ellint_1
ayush4874 Dec 13, 2025
32e0513
Refactor: Integrate comp_ellint_1 fully into stl-cmath.cpp (table, ma…
ayush4874 Dec 14, 2025
984e443
Fix: Resolve ODR violation and implement comp_ellint_2/3
ayush4874 Jan 9, 2026
e7cf40f
Refactor: Inline derivative logic into pushforward templates
ayush4874 Jan 11, 2026
4693ac0
Test: Add domain comments and verify comp_ellint_3 numerically
ayush4874 Jan 12, 2026
1e46a93
Test: Refactor comp_ellint tests to match atan2/pow style and use num…
ayush4874 Jan 12, 2026
c686d61
Fix: Guard C++17 ellint derivatives to fix CI build on older standards
ayush4874 Feb 3, 2026
b6b2156
Fix: Guard C++17 test code for older compilers
ayush4874 Feb 3, 2026
e8be707
Fix: Remove redundant DEFINE_FUNCTIONS macros to resolve redefinition…
ayush4874 Feb 4, 2026
bece3fe
Fix: Use correct initializer list syntax for elliptic integral tests
ayush4874 Feb 6, 2026
6b6d0c7
Fix: Resolve CI failures by fixing type promotion mismatch in comp_el…
ayush4874 Feb 19, 2026
71439f3
Fix: Guard ellint functions with feature test macros for macOS compat…
ayush4874 Feb 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions include/clad/Differentiator/BuiltinDerivatives.h
Original file line number Diff line number Diff line change
Expand Up @@ -1062,6 +1062,84 @@ CUDA_HOST_DEVICE void hypot_pullback(T x, T y, U d_z, T* d_x, T* d_y) {
*d_y += (y / h) * d_z;
}

#if __cplusplus >= 201703L && (defined(__cpp_lib_math_special_funcs) || defined(__STDCPP_MATH_SPEC_FUNCS__))
template <typename T, typename dT,
typename T_out = decltype(::std::comp_ellint_1(T())),
typename dT_out = typename AdjOutType<T_out, dT>::type>
CUDA_HOST_DEVICE ValueAndPushforward<T_out, dT_out>
comp_ellint_1_pushforward(T k, dT d_k) {
T_out K = ::std::comp_ellint_1(k);
T_out E = ::std::comp_ellint_2(k);
T_out k_sq = k * k;
T_out one = 1.0;
T_out derivative = 0.0;
if (k_sq < 1.0 && k != 0.0)
derivative = (E - (one - k_sq) * K) / (k * (one - k_sq));
return {K, static_cast<dT_out>(d_k) * derivative};
}

template <typename T, typename dT,
typename T_out = decltype(::std::comp_ellint_2(T())),
typename dT_out = typename AdjOutType<T_out, dT>::type>
CUDA_HOST_DEVICE ValueAndPushforward<T_out, dT_out>
comp_ellint_2_pushforward(T k, dT d_k) {
T_out K = ::std::comp_ellint_1(k);
T_out E = ::std::comp_ellint_2(k);
T_out derivative = 0.0;
if (k != 0.0)
derivative = (E - K) / k;
return {E, static_cast<dT_out>(d_k) * derivative};
}

template <typename T1, typename T2, typename dT1, typename dT2,
typename T_out = decltype(::std::comp_ellint_3(T1(), T2())),
typename dT_out = typename AdjOutType<T_out, dT1>::type>
CUDA_HOST_DEVICE ValueAndPushforward<T_out, dT_out>
comp_ellint_3_pushforward(T1 k, T2 nu, dT1 d_k, dT2 d_nu) {
T_out K = ::std::comp_ellint_1(k);
T_out E = ::std::comp_ellint_2(k);
T_out Pi = ::std::comp_ellint_3(k, nu);
T_out k2 = k * k;
T_out one = 1.0;
T_out grad_k = 0.0;
if (k2 != static_cast<T_out>(nu) && k != 0.0 && k2 < 1.0) {
T_out term_k = E / (one - k2);
grad_k = (k / (k2 - static_cast<T_out>(nu))) * (term_k - Pi);
}
T_out grad_nu = 0.0;
if (nu != 0.0 && nu != 1.0 && k2 != static_cast<T_out>(nu)) {
T_out p2 = ((k2 - static_cast<T_out>(nu)) / static_cast<T_out>(nu)) * K;
T_out p3 = ((static_cast<T_out>(nu) * static_cast<T_out>(nu) - k2) /
static_cast<T_out>(nu)) *
Pi;
grad_nu = (one / (2.0 * (static_cast<T_out>(nu) - one) *
(k2 - static_cast<T_out>(nu)))) *
(E + p2 + p3);
}
return {Pi, (static_cast<dT_out>(d_k) * grad_k) +
(static_cast<dT_out>(d_nu) * grad_nu)};
}

template <typename T1, typename T2, typename T3>
CUDA_HOST_DEVICE void comp_ellint_3_pullback(T1 k, T2 nu, T3 d_out, T1* d_k,
T2* d_nu) {
auto K = ::std::comp_ellint_1(k);
auto E = ::std::comp_ellint_2(k);
auto Pi = ::std::comp_ellint_3(k, nu);
auto k2 = k * k;
auto one = 1.0;
if (k2 != nu && k != 0.0 && k2 < 1.0) {
auto term_k = E / (one - k2);
*d_k += d_out * ((k / (k2 - nu)) * (term_k - Pi));
}
if (nu != 0.0 && nu != one && k2 != nu) {
auto p2 = ((k2 - nu) / nu) * K;
auto p3 = ((nu * nu - k2) / nu) * Pi;
*d_nu += d_out * ((one / (2.0 * (nu - one) * (k2 - nu))) * (E + p2 + p3));
}
}
#endif

} // namespace std

CUDA_HOST_DEVICE inline ValueAndPushforward<float, float>
Expand Down Expand Up @@ -1326,6 +1404,12 @@ using std::min_pushforward;
using std::pow_pullback;
using std::pow_pushforward;
using std::sqrt_pushforward;
#if __cplusplus >= 201703L && (defined(__cpp_lib_math_special_funcs) || defined(__STDCPP_MATH_SPEC_FUNCS__))
using std::comp_ellint_1_pushforward;
using std::comp_ellint_2_pushforward;
using std::comp_ellint_3_pullback;
using std::comp_ellint_3_pushforward;
#endif

namespace class_functions {
template <typename T, typename U>
Expand Down
33 changes: 32 additions & 1 deletion test/Features/stl-cmath.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@
// D tgamma/ tgammaf/ tgammal (C++11) gamma function
// D lgamma/ lgammaf/ lgammal (C++11) log gamma
//
//------------------------ Elliptic integrals -----------------------------
// D comp_ellint_1 / comp_ellint_1f / comp_ellint_1l (C++17) complete elliptic integral of the first kind
// D comp_ellint_2 / comp_ellint_2f / comp_ellint_2l (C++17) complete elliptic integral of the second kind
// D comp_ellint_3 (C++17) complete elliptic integral of the third kind
//
//---------------------- Nearest integer operations ----------------------------
// N ceil/ ceilf/ ceill (C++11) smallest integer >= x
// N floor/ floorf/ floorl (C++11) largest integer <= x
Expand Down Expand Up @@ -295,6 +300,25 @@ DEFINE_FUNCTIONS(atanh) // x in [-1,1]
//
DEFINE_FUNCTIONS(erf) // x in (-inf,+inf)

#if __cplusplus >= 201703L && (defined(__cpp_lib_math_special_funcs) || defined(__STDCPP_MATH_SPEC_FUNCS__))
//------------------------ Elliptic integrals -----------------------------
//
// Domain: k in (-1, 1)
template<typename T> T f_comp_ellint_1(T k) { return std::comp_ellint_1(k); }
float f_comp_ellint_1f(float k) { return std::comp_ellint_1(k); }
long double f_comp_ellint_1l(long double k) { return std::comp_ellint_1(k); }

// Domain: k in (-1, 1)
template<typename T> T f_comp_ellint_2(T k) { return std::comp_ellint_2(k); }
float f_comp_ellint_2f(float k) { return std::comp_ellint_2(k); }
long double f_comp_ellint_2l(long double k) { return std::comp_ellint_2(k); }

// Domain: k in (-1, 1). Fixed nu = 0.5 for testing.
template<typename T> T f_comp_ellint_3(T k) { return std::comp_ellint_3(k, (T)0.5); }
float f_comp_ellint_3f(float k) { return std::comp_ellint_3(k, 0.5f); }
long double f_comp_ellint_3l(long double k) { return std::comp_ellint_3(k, 0.5L); }
#endif

int main() {
// Absolute value
CHECK(abs);
Expand Down Expand Up @@ -352,6 +376,13 @@ int main() {

// Error / Gamma functions
CHECK_ALL(erf);

#if __cplusplus >= 201703L && (defined(__cpp_lib_math_special_funcs) || defined(__STDCPP_MATH_SPEC_FUNCS__))
// Elliptic Integrals
CHECK_ALL_RANGE(comp_ellint_1, {-0.9, -0.6, -0.3, 0.0, 0.3, 0.6, 0.9});
CHECK_ALL_RANGE(comp_ellint_2, {-0.9, -0.6, -0.3, 0.0, 0.3, 0.6, 0.9});
CHECK_ALL_RANGE(comp_ellint_3, {-0.9, -0.6, -0.3, 0.0, 0.3, 0.6, 0.9});
#endif

return 0;
}
}