EnzymeAD / Enzyme

High-performance automatic differentiation of LLVM and MLIR.
https://enzyme.mit.edu
Other
1.2k stars 100 forks source link

Enzyme C++ sugar for vector input/outputs #1964

Open ipcamit opened 4 days ago

ipcamit commented 4 days ago

Hi, going through the test examples, I could run C++ sugar for scalar inputs, but I could not figure out how to make enzyme C++ syntax work for vector input outputs, e.g. how to compile the following program (or equivalent)

#include <cstdio>
#include <enzyme/enzyme>
#include <cmath>
#include <typeinfo>
#include <tuple>
#include <vector>

//void f(double *x, double *y, int n) {
//    for (int i = 0; i < n; i++) {
//        x[i] = y[i] * y[i];
//    }
//    
//}

double f(std::vector<double> &x, std::vector<double> & y, int n) {
    for (int i = 0; i < n; i++) {
        y[i] = x[i] * x[i];
    }

}

int main() {
    std::vector<double> x = {1, 2, 3};
    std::vector<double> y = {4, 5, 6};

    std::vector<double> dx = {0, 0, 0};
    std::vector<double> dy = {1, 1, 1};

    int n = 3;

    enzyme::autodiff<enzyme::Reverse>(
        f, 
        enzyme::Duplicated<std::vector<double>&>{x, dx},
        enzyme::Duplicated<std::vector<double>&>{y, dy},
        enzyme::Const<int>{n}
    );

    printf("x: %f %f %f\n", x[0], x[1], x[2]);
    printf("dx: %f %f %f\n", dx[0], dx[1], dx[2]);
    printf("y: %f %f %f\n", y[0], y[1], y[2]);
    printf("dy: %f %f %f\n", dy[0], dy[1], dy[2]);

    return 0;
}

I compile it as,

clang++ example_vector.cpp -I/path/to/enzyme/Enzyme/enzyme/include -std=c++17 -Xclang -load -Xclang /path/to/Enzyme/ClangEnzyme-13.so -O3

During the compilation I get the following error:

example_3f_vector.cpp:20:1: warning: non-void function does not return a value [-Wreturn-type]
}
^
In file included from example_3f_vector.cpp:2:
In file included from /home/amit/enzyme/Enzyme/enzyme/include/enzyme/enzyme:2:
/home/amit/enzyme/Enzyme/enzyme/include/enzyme/utils:57:7: error: multiple overloads of 'Duplicated' instantiate to the same signature 'void (std::vector<double> &, std::vector<double> &)'
      Duplicated(T&& v, T&& s) : value(v), shadow(s) {};
      ^
example_3f_vector.cpp:34:9: note: in instantiation of template class 'enzyme::Duplicated<std::vector<double> &>' requested here
        enzyme::Duplicated<std::vector<double>&>{x, dx},
        ^
/home/amit/enzyme/Enzyme/enzyme/include/enzyme/utils:56:7: note: previous declaration is here
      Duplicated(const T& v, const T& s) : value(v), shadow(s) {};
      ^
/home/amit/enzyme/Enzyme/enzyme/include/enzyme/utils:421:47: error: non-const lvalue reference to type 'vector<...>' cannot bind to a temporary of type 'vector<...>'
        using primal_return_type = decltype(f(primal_args_nt(args)...));
                                              ^~~~~~~~~~~~~~~~~~~~
example_3f_vector.cpp:32:13: note: in instantiation of function template specialization 'enzyme::autodiff<enzyme::ReverseMode<false>, double (&)(std::vector<double> &, std::vector<double> &, int), enzyme::Duplicated<std::vector<double> &>, enzyme::Duplicated<std::vector<double> &>, enzyme::Const<int>>' requested here
    enzyme::autodiff<enzyme::Reverse>(
            ^
In file included from example_3f_vector.cpp:2:
In file included from /home/amit/enzyme/Enzyme/enzyme/include/enzyme/enzyme:2:
/home/amit/enzyme/Enzyme/enzyme/include/enzyme/utils:406:82: error: static_cast from 'double (*)(std::vector<double> &, std::vector<double> &, int)' to 'int (*)(std::vector<double>, std::vector<double>, int)' is not allowed
      return detail::autodiff_apply<DiffMode>::template impl<return_type>((void*)static_cast<functy*>(f), detail::ret_global<RetActivity>::value, impl::forward<Tuple>(arg_tup), std::make_index_sequence<enzyme::tuple_size_v<Tuple>>{});
                                                                                 ^~~~~~~~~~~~~~~~~~~~~~~
/home/amit/enzyme/Enzyme/enzyme/include/enzyme/utils:425:16: note: in instantiation of function template specialization 'enzyme::autodiff_impl<enzyme::tuple<enzyme::tuple<enzyme::nodiff, enzyme::nodiff, enzyme::nodiff>>, enzyme::ReverseMode<false>, double (&)(std::vector<double> &, std::vector<double> &, int), int (std::vector<double>, std::vector<double>, int), enzyme::Const<int>, int *, int, std::vector<double>, std::vector<double>, int, std::vector<double>, std::vector<double>, int, int, 0>' requested here
        return autodiff_impl<return_type, DiffMode, function, functy, RetActivity>(impl::forward<function>(f), enzyme::tuple_cat(enzyme::tuple{detail::ret_used<DiffMode, RetActivity>::value}, expand_args(args)...));
               ^
example_3f_vector.cpp:32:13: note: in instantiation of function template specialization 'enzyme::autodiff<enzyme::ReverseMode<false>, double (&)(std::vector<double> &, std::vector<double> &, int), enzyme::Duplicated<std::vector<double> &>, enzyme::Duplicated<std::vector<double> &>, enzyme::Const<int>>' requested here
    enzyme::autodiff<enzyme::Reverse>(
            ^
1 warning and 3 errors generated.