Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Calling templated functions inside function doesn't work in backwards mode #1125

Open
guitargeek opened this issue Oct 28, 2024 · 6 comments

Comments

@guitargeek
Copy link
Contributor

guitargeek commented Oct 28, 2024

Reproducer as a ROOT macro:

#include <Math/CladDerivator.h>

template <class T>
inline double foo(double *params) { return params[0]; }
inline double bar(double *params) { return params[0]; }

double wrapper(double *params)
{
   return foo<int>(params); // doesn't work!
   // return bar(params); // works!
}

#pragma clad ON
void gradient_request() { clad::gradient(wrapper, "params"); }
#pragma clad OFF

// To run as a ROOT macro
void macro()
{
   std::vector<double> parametersVec{.5};
   std::vector<double> gradientVec(parametersVec.size());

   auto func = [&](std::span<double> params) { return wrapper(params.data()); };
   auto grad = [&](std::span<double> params, std::span<double> out) {
      return wrapper_grad(parametersVec.data(), out.data());
   };

   grad(parametersVec, gradientVec);

   auto numDiff = [&](int i) {
      const double eps = 1e-6;
      std::vector<double> p{parametersVec};
      p[i] = parametersVec[i] - eps;
      double funcValDown = func(p);
      p[i] = parametersVec[i] + eps;
      double funcValUp = func(p);
      return (funcValUp - funcValDown) / (2 * eps);
   };

   for (std::size_t i = 0; i < parametersVec.size(); ++i) {
      std::cout << i << ":" << std::endl;
      std::cout << "  numr : " << numDiff(i) << std::endl;
      std::cout << "  clad : " << gradientVec[i] << std::endl;
   }
}

Output:

Processing macro.C...
0:
  numr : 1
  clad : 0

I could work around this limitation in RooFit by avoiding template functions in the generated code, but at some point it becomes unavoidable if we want to use functors as parameters.

This follows up on the following issue:

If this works, this would finally enable us to use more accurate routines for numeric integration that take function parameters, closing the gap between RooFit AD and regular RooFit.

@guitargeek guitargeek changed the title Using functors in inner functions doesn't work in backwards mode Calling templated functions inside function doesn't work in backwards mode Oct 28, 2024
@parth-07
Copy link
Collaborator

I am unable to reproduce this issue. I tried to reproduce it outside the ROOT environment.

#include "clad/Differentiator/Differentiator.h"
#include <iostream>
#define show(x) std::cout<< #x << ": " << x << "\n";

template <class T>
inline double foo(double *params) { return params[0]; }
inline double bar(double *params) { return params[0]; }

double wrapper(double *params)
{
   return foo<int>(params); // doesn't work!
  //  return bar(params); // works!
}

int main() {
  auto wrapper_grad = clad::gradient(wrapper, "params");
  std::vector<double> params(1, 0), d_params(1, 0);
  wrapper_grad.execute(params.data(), d_params.data());
  show(d_params[0]);
}

This outputs: d_params[0]: 1 and generates the correct derivative functions.

Can you please tell which Clad version are you using?

@guitargeek
Copy link
Contributor Author

guitargeek commented Oct 30, 2024

Oh that is surprising. I'm using ROOT master with Clad master, by editing this line here and re-building ROOT from scratch:
https://github.com/root-project/root/blob/master/interpreter/cling/tools/plugins/clad/CMakeLists.txt#L86

I also converted your smaller reproducer to a ROOT macro, by replacing the int main() signature with void macro() and and renaming the file to macro.C. I still get the wrong result: d_params[0]: 0.

You have a ROOT build at hand to try this out too? I'll also try it with building Clad standalone.

@parth-07
Copy link
Collaborator

This is surprising indeed.

You have a ROOT build at hand to try this out too?

Unfortunately, I do not have a root build handy. I will try building ROOT and reproducing the issue..

@parth-07
Copy link
Collaborator

I also converted your smaller reproducer to a ROOT macro, by replacing the int main() signature with void macro() and and renaming the file to macro.C. I still get the wrong result: d_params[0]: 1.

I am assuming that d_params[0]: 1 is a mistype here and the code actually outputs d_params[0]: 0 when used with ROOT macro. Please correct me if I am wrong.

@guitargeek
Copy link
Contributor Author

guitargeek commented Oct 30, 2024

Yes, that was a typo, sorry! I copy pasted from your post, instead of from my terminal output!

@vgvassilev
Copy link
Owner

@parth-07, ROOT has not moved to clang-repl and still does not really use the delay-until-end-of-tu logic. Maybe that’s the difference.

@guitargeek what error do you get?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants