vgvassilev / clad

clad -- automatic differentiation for C/C++
GNU Lesser General Public License v3.0
288 stars 122 forks source link

Support for default arguments #1028

Open davidlange6 opened 3 months ago

davidlange6 commented 3 months ago

Having stolen an example of AD from Clad slides, i see that the use of default arguments does not work.

#include <cmath>
double f (double x, int N=5) {
  double result = x;
  for (unsigned i = 0; i < N; i++)
    result = std::exp(result);
  return result;
}

with

#include "clad/Differentiator/Differentiator.h"
auto f_dx_clad = clad::differentiate(f, "x");

std::cout << f_dx_clad(-1.0,5) << std::endl;

works, however

std::cout << f_dx_clad(-1.0) << std::endl;

results in

In file included from <<< inputs >>>:1:
In file included from input_line_4:1:
[/srv/conda/envs/notebook//include/clad/Differentiator/Differentiator.h:132:40](https://jupyterhub.ssl-hep.org/srv/conda/envs/notebook//include/clad/Differentiator/Differentiator.h#line=131): error: too few arguments to function call, expected 2, have 1
  132 |     return f(static_cast<Args>(args)...);
      |            ~                           ^
vgvassilev commented 3 months ago

Probably related to #53.

MihailMihov commented 3 months ago

I looked into this issue and the problem here is that inside CladFunction we call the derived functions through a function pointer, but the default arguments of a function are not part of it's signature and a call without all the arguments specified explicitly fails.

I started thinking of some solution where we generate function overloads for each possible combination of arguments and then creating the correct function pointer based on the arguments given (godbolt example), but actually we need to store the function pointer from clad::differentiate/clad::gradient and we don't know the args until execute is called.

Another idea would be to fill in the missing arguments and then also somehow pass in which of them should use the default and set the defaults at the start of the generated function, but the implementation would likely be very complex and ugly. (Currently CladFunction has some padding option that is disabled by default and I'm not sure if it can even be enabled. With a slight modification I got it to fill in a zero for this issue's example, but how is that useful on it's own?)

davidlange6 commented 2 months ago

Given the # of arguments passed in to the differentiate/gradiant function, one can determine how many default arguments were used... however, given the current ordering of arguments, a code taking advantage of such a functionality becomes quite hard to understand in this case (as the default arguments end up in the middle). The big change suggested in #53 of changing the order would be a solution, but that would have been easier 6 years ago....