diff --git a/roofit/roofitcore/inc/RooFit/Detail/MathFuncs.h b/roofit/roofitcore/inc/RooFit/Detail/MathFuncs.h index 9dda0467cbfb8..5f81c10614992 100644 --- a/roofit/roofitcore/inc/RooFit/Detail/MathFuncs.h +++ b/roofit/roofitcore/inc/RooFit/Detail/MathFuncs.h @@ -865,19 +865,49 @@ double stepFunctionIntegral(double xmin, double xmax, std::size_t nBins, DoubleA } // namespace RooFit::Detail::MathFuncs +namespace clad { +// Only declared, never defined here: clad's own headers exist exclusively +// inside the interpreter, but this header is also compiled normally. +template +struct ValueAndPushforward; +} // namespace clad + namespace clad::custom_derivatives { namespace RooFit::Detail::MathFuncs { -// Clad can't generate the pullback for binNumber because of the +// Clad can't generate the derivatives for binNumber because of the // std::lower_bound usage. But since binNumber returns an integer, and such -// functions have mathematically no derivatives anyway, we just declare a -// custom dummy pullback that does nothing. +// functions have mathematically no derivatives anyway, we just declare custom +// dummy derivatives that do nothing. +// +// Both directions have to be covered: the pullback alone is enough for +// gradients, but Hessians also run the forward pass over binNumber, and +// without a pushforward clad descends into std::lower_bound. template void binNumber_pullback(Types...) { } +// The second parameter is unused. It is what keeps the return type of the +// pushforward below dependent, so that clad::ValueAndPushforward only has to be +// complete once that template is instantiated. That happens under clad and +// nowhere else, while parsing the declaration happens in every build that +// includes this header. A class template is needed here: an alias template +// would be expanded eagerly and defeat the purpose. +template +struct ValueAndPushforwardOf { + using type = ::clad::ValueAndPushforward; +}; + +template +typename ValueAndPushforwardOf::type +binNumber_pushforward(double x, double coef, DoubleArray boundaries, unsigned int nBoundaries, int nbins, int blo, + Types...) +{ + return {::RooFit::Detail::MathFuncs::binNumber(x, coef, boundaries, nBoundaries, nbins, blo), 0}; +} + } // namespace RooFit::Detail::MathFuncs } // namespace clad::custom_derivatives