From c3b76c02bb80710a66d7df84205c1256e861f333 Mon Sep 17 00:00:00 2001 From: Atell Krasnopolski Date: Mon, 26 Aug 2024 19:23:20 +0200 Subject: [PATCH 1/6] Provide pushforward methods for `Kokkos::View` indexing Previously, we relied on automatically generated pushforwards for these operator calls, but this solution is way safer and should work for more machines and Kokkos versions. --- include/clad/Differentiator/KokkosBuiltins.h | 71 +++++++++++++++++++- unittests/Kokkos/ViewBasics.cpp | 31 +++++++++ 2 files changed, 100 insertions(+), 2 deletions(-) diff --git a/include/clad/Differentiator/KokkosBuiltins.h b/include/clad/Differentiator/KokkosBuiltins.h index d21710705..2ffee0e4f 100644 --- a/include/clad/Differentiator/KokkosBuiltins.h +++ b/include/clad/Differentiator/KokkosBuiltins.h @@ -28,6 +28,75 @@ constructor_pushforward( Kokkos::View( "_diff_" + name, idx0, idx1, idx2, idx3, idx4, idx5, idx6, idx7)}; } + +/// View indexing +template +inline clad::ValueAndPushforward +operator_call_pushforward(const View* v, Idx i0, const View* d_v, + Idx /*d_i0*/) { + return {(*v)(i0), (*d_v)(i0)}; +} +template +clad::ValueAndPushforward +operator_call_pushforward(const View* v, Idx i0, Idx i1, const View* d_v, + Idx /*d_i0*/, Idx /*d_i1*/) { + return {(*v)(i0, i1), (*d_v)(i0, i1)}; +} +template +clad::ValueAndPushforward +operator_call_pushforward(const View* v, Idx i0, Idx i1, Idx i2, + const View* d_v, Idx /*d_i0*/, Idx /*d_i1*/, + Idx /*d_i2*/) { + return {(*v)(i0, i1, i2), (*d_v)(i0, i1, i2)}; +} +template +clad::ValueAndPushforward +operator_call_pushforward(const View* v, Idx i0, Idx i1, Idx i2, Idx i3, + const View* d_v, Idx /*d_i0*/, Idx /*d_i1*/, + Idx /*d_i2*/, Idx /*d_i3*/) { + return {(*v)(i0, i1, i2, i3), (*d_v)(i0, i1, i2, i3)}; +} +template +clad::ValueAndPushforward +operator_call_pushforward(const View* v, Idx i0, Idx i1, Idx i2, Idx i3, Idx i4, + const View* d_v, Idx /*d_i0*/, Idx /*d_i1*/, + Idx /*d_i2*/, Idx /*d_i3*/, Idx /*d_i4*/) { + return {(*v)(i0, i1, i2, i3, i4), (*d_v)(i0, i1, i2, i3, i4)}; +} +template +clad::ValueAndPushforward +operator_call_pushforward(const View* v, Idx i0, Idx i1, Idx i2, Idx i3, Idx i4, + Idx i5, const View* d_v, Idx /*d_i0*/, Idx /*d_i1*/, + Idx /*d_i2*/, Idx /*d_i3*/, Idx /*d_i4*/, + Idx /*d_i5*/) { + return {(*v)(i0, i1, i2, i3, i4, i5), (*d_v)(i0, i1, i2, i3, i4, i5)}; +} +template +clad::ValueAndPushforward +operator_call_pushforward(const View* v, Idx i0, Idx i1, Idx i2, Idx i3, Idx i4, + Idx i5, Idx i6, const View* d_v, Idx /*d_i0*/, + Idx /*d_i1*/, Idx /*d_i2*/, Idx /*d_i3*/, + Idx /*d_i4*/, Idx /*d_i5*/, Idx /*d_i6*/) { + return {(*v)(i0, i1, i2, i3, i4, i5, i6), (*d_v)(i0, i1, i2, i3, i4, i5, i6)}; +} +template +clad::ValueAndPushforward +operator_call_pushforward(const View* v, Idx i0, Idx i1, Idx i2, Idx i3, Idx i4, + Idx i5, Idx i6, Idx i7, const View* d_v, Idx /*d_i0*/, + Idx /*d_i1*/, Idx /*d_i2*/, Idx /*d_i3*/, + Idx /*d_i4*/, Idx /*d_i5*/, Idx /*d_i6*/, + Idx /*d_i7*/) { + return {(*v)(i0, i1, i2, i3, i4, i5, i6, i7), + (*d_v)(i0, i1, i2, i3, i4, i5, i6, i7)}; +} } // namespace class_functions /// Kokkos functions (view utils) @@ -39,7 +108,6 @@ inline void deep_copy_pushforward(const View1& dst, const View2& src, T param, deep_copy(dst, src); deep_copy(d_dst, d_src); } - template inline void resize_pushforward(View& v, const size_t n0, const size_t n1, const size_t n2, const size_t n3, @@ -52,7 +120,6 @@ inline void resize_pushforward(View& v, const size_t n0, const size_t n1, ::Kokkos::resize(v, n0, n1, n2, n3, n4, n5, n6, n7); ::Kokkos::resize(d_v, n0, n1, n2, n3, n4, n5, n6, n7); } - template inline void resize_pushforward(const I& arg, View& v, const size_t n0, const size_t n1, const size_t n2, diff --git a/unittests/Kokkos/ViewBasics.cpp b/unittests/Kokkos/ViewBasics.cpp index b16e59f90..4f996d921 100644 --- a/unittests/Kokkos/ViewBasics.cpp +++ b/unittests/Kokkos/ViewBasics.cpp @@ -248,4 +248,35 @@ TEST(ViewBasics, TestResize4) { for (double x = 3; x <= 5; x += 1) for (double y = 3; y <= 5; y += 1) EXPECT_NEAR(df.execute(x, y), df_true(x, y), eps); +} + +template struct FooModifier { + double x; + + FooModifier(View& v, double x) : x(x) {} + + void operator()(View& v) { v(1, 0, 1, 0, 1, 0, 1) += x; } +}; + +double f_basics_call(double x) { + Kokkos::View + a("a"); + Kokkos::deep_copy(a, 3 * x); + + FooModifier> + f(a, x); + + f(a); + + return a(1, 0, 1, 0, 1, 0, 1); +} + +TEST(ViewBasics, FunctorCall4) { + const double eps = 1e-8; + + auto df = clad::differentiate(f_basics_call, 0); + for (double x = 3; x <= 5; x += 1) + EXPECT_NEAR(df.execute(x), 4, eps); } \ No newline at end of file From 3bd062457151e6146d2d38d9b06a844f794f3c88 Mon Sep 17 00:00:00 2001 From: Atell Krasnopolski Date: Fri, 23 Aug 2024 21:45:03 +0200 Subject: [PATCH 2/6] Add support for `Kokkos::parallel_reduce` in the fwd mode --- include/clad/Differentiator/KokkosBuiltins.h | 297 +++++++++++++++++++ unittests/Kokkos/ParallelFor.cpp | 1 - unittests/Kokkos/ParallelReduce.cpp | 89 +++++- 3 files changed, 385 insertions(+), 2 deletions(-) diff --git a/include/clad/Differentiator/KokkosBuiltins.h b/include/clad/Differentiator/KokkosBuiltins.h index 2ffee0e4f..ef479a16d 100644 --- a/include/clad/Differentiator/KokkosBuiltins.h +++ b/include/clad/Differentiator/KokkosBuiltins.h @@ -386,6 +386,303 @@ void parallel_for_pushforward( parallel_for_pushforward(str, policy, functor, d_str, d_policy, d_functor); } +/// Parallel reduce +// TODO: ADD SUPORT FOR MULTIPLE REDUCED ARGUMENTS +// TODO: ADD SUPPORT FOR UNNAMED LOOPS + +// This structure is used to dispatch parallel reduce pushforward calls for +// multidimentional policies +template +struct diff_parallel_reduce_MDP_dispatch { // non-MDPolicy + static void run(const ::std::string& str, const Policy& policy, + const FunctorType& functor, Reduced& res, + const FunctorType& d_functor, Reduced& d_res) { + ::Kokkos::parallel_reduce( + "_diff_" + str, policy, + [&](const auto _work_tag, const auto& i, auto& r, auto& d_r) { + functor.operator_call_pushforward(_work_tag, i, r, &d_functor, {}, {}, + d_r); + }, + res, d_res); + } +}; +template +struct diff_parallel_reduce_MDP_dispatch { // non-MDPolicy + static void run(const ::std::string& str, const Policy& policy, + const FunctorType& functor, Reduced& res, + const FunctorType& d_functor, Reduced& d_res) { + ::Kokkos::parallel_reduce( + "_diff_" + str, policy, + [&](const auto& i, auto& r, auto& d_r) { + functor.operator_call_pushforward(i, r, &d_functor, {}, d_r); + }, + res, d_res); + } +}; +template +struct diff_parallel_reduce_MDP_dispatch< + ::Kokkos::MDRangePolicy, FunctorType, Reduced, WT, + 2> { // MDPolicy, rank = 2 + static void + run(const ::std::string& str, + const ::Kokkos::MDRangePolicy& policy, + const FunctorType& functor, Reduced& res, const FunctorType& d_functor, + Reduced& d_res) { + ::Kokkos::parallel_reduce( + "_diff_" + str, policy, + [&](const auto _work_tag, const auto& i0, const auto& i1, auto& r, + auto& d_r) { + functor.operator_call_pushforward(_work_tag, i0, i1, r, &d_functor, + {}, {}, {}, d_r); + }, + res, d_res); + } +}; +template +struct diff_parallel_reduce_MDP_dispatch< + ::Kokkos::MDRangePolicy, FunctorType, Reduced, + void, 2> { // MDPolicy, rank = 2 + static void + run(const ::std::string& str, + const ::Kokkos::MDRangePolicy& policy, + const FunctorType& functor, Reduced& res, const FunctorType& d_functor, + Reduced& d_res) { + ::Kokkos::parallel_reduce( + "_diff_" + str, policy, + [&](const auto& i0, const auto& i1, auto& r, auto& d_r) { + functor.operator_call_pushforward(i0, i1, r, &d_functor, {}, {}, d_r); + }, + res, d_res); + } +}; +template +struct diff_parallel_reduce_MDP_dispatch< + ::Kokkos::MDRangePolicy, FunctorType, Reduced, WT, + 3> { // MDPolicy, rank = 3 + static void + run(const ::std::string& str, + const ::Kokkos::MDRangePolicy& policy, + const FunctorType& functor, Reduced& res, const FunctorType& d_functor, + Reduced& d_res) { + ::Kokkos::parallel_reduce( + "_diff_" + str, policy, + [&](const auto _work_tag, const auto& i0, const auto& i1, + const auto& i2, auto& r, auto& d_r) { + functor.operator_call_pushforward(_work_tag, i0, i1, i2, r, + &d_functor, {}, {}, {}, {}, d_r); + }, + res, d_res); + } +}; +template +struct diff_parallel_reduce_MDP_dispatch< + ::Kokkos::MDRangePolicy, FunctorType, Reduced, + void, 3> { // MDPolicy, rank = 3 + static void + run(const ::std::string& str, + const ::Kokkos::MDRangePolicy& policy, + const FunctorType& functor, Reduced& res, const FunctorType& d_functor, + Reduced& d_res) { + ::Kokkos::parallel_reduce( + "_diff_" + str, policy, + [&](const auto& i0, const auto& i1, const auto& i2, auto& r, + auto& d_r) { + functor.operator_call_pushforward(i0, i1, i2, r, &d_functor, {}, {}, + {}, d_r); + }, + res, d_res); + } +}; +template +struct diff_parallel_reduce_MDP_dispatch< + ::Kokkos::MDRangePolicy, FunctorType, Reduced, WT, + 4> { // MDPolicy, rank = 4 + static void + run(const ::std::string& str, + const ::Kokkos::MDRangePolicy& policy, + const FunctorType& functor, Reduced& res, const FunctorType& d_functor, + Reduced& d_res) { + ::Kokkos::parallel_reduce( + "_diff_" + str, policy, + [&](const auto wt, const auto& i0, const auto& i1, const auto& i2, + const auto& i3, auto& r, auto& d_r) { + functor.operator_call_pushforward(wt, i0, i1, i2, i3, r, &d_functor, + {}, {}, {}, {}, {}, d_r); + }, + res, d_res); + } +}; +template +struct diff_parallel_reduce_MDP_dispatch< + ::Kokkos::MDRangePolicy, FunctorType, Reduced, + void, 4> { // MDPolicy, rank = 4 + static void + run(const ::std::string& str, + const ::Kokkos::MDRangePolicy& policy, + const FunctorType& functor, Reduced& res, const FunctorType& d_functor, + Reduced& d_res) { + ::Kokkos::parallel_reduce( + "_diff_" + str, policy, + [&](const auto& i0, const auto& i1, const auto& i2, const auto& i3, + auto& r, auto& d_r) { + functor.operator_call_pushforward(i0, i1, i2, i3, r, &d_functor, {}, + {}, {}, {}, d_r); + }, + res, d_res); + } +}; +template +struct diff_parallel_reduce_MDP_dispatch< + ::Kokkos::MDRangePolicy, FunctorType, Reduced, WT, + 5> { // MDPolicy, rank = 5 + static void + run(const ::std::string& str, + const ::Kokkos::MDRangePolicy& policy, + const FunctorType& functor, Reduced& res, const FunctorType& d_functor, + Reduced& d_res) { + ::Kokkos::parallel_reduce( + "_diff_" + str, policy, + [&](const auto wt, const auto& i0, const auto& i1, const auto& i2, + const auto& i3, const auto& i4, auto& r, auto& d_r) { + functor.operator_call_pushforward(wt, i0, i1, i2, i3, i4, r, + &d_functor, {}, {}, {}, {}, {}, {}, + d_r); + }, + res, d_res); + } +}; +template +struct diff_parallel_reduce_MDP_dispatch< + ::Kokkos::MDRangePolicy, FunctorType, Reduced, + void, 5> { // MDPolicy, rank = 5 + static void + run(const ::std::string& str, + const ::Kokkos::MDRangePolicy& policy, + const FunctorType& functor, Reduced& res, const FunctorType& d_functor, + Reduced& d_res) { + ::Kokkos::parallel_reduce( + "_diff_" + str, policy, + [&](const auto& i0, const auto& i1, const auto& i2, const auto& i3, + const auto& i4, auto& r, auto& d_r) { + functor.operator_call_pushforward(i0, i1, i2, i3, i4, r, &d_functor, + {}, {}, {}, {}, {}, d_r); + }, + res, d_res); + } +}; +template +struct diff_parallel_reduce_MDP_dispatch< + ::Kokkos::MDRangePolicy, FunctorType, Reduced, WT, + 6> { // MDPolicy, rank = 6 + static void + run(const ::std::string& str, + const ::Kokkos::MDRangePolicy& policy, + const FunctorType& functor, Reduced& res, const FunctorType& d_functor, + Reduced& d_res) { + ::Kokkos::parallel_reduce( + "_diff_" + str, policy, + [&](const auto wt, const auto& i0, const auto& i1, const auto& i2, + const auto& i3, const auto& i4, const auto& i5, auto& r, + auto& d_r) { + functor.operator_call_pushforward(wt, i0, i1, i2, i3, i4, i5, r, + &d_functor, {}, {}, {}, {}, {}, {}, + {}, d_r); + }, + res, d_res); + } +}; +template +struct diff_parallel_reduce_MDP_dispatch< + ::Kokkos::MDRangePolicy, FunctorType, Reduced, + void, 6> { // MDPolicy, rank = 6 + static void + run(const ::std::string& str, + const ::Kokkos::MDRangePolicy& policy, + const FunctorType& functor, Reduced& res, const FunctorType& d_functor, + Reduced& d_res) { + ::Kokkos::parallel_reduce( + "_diff_" + str, policy, + [&](const auto& i0, const auto& i1, const auto& i2, const auto& i3, + const auto& i4, const auto& i5, auto& r, auto& d_r) { + functor.operator_call_pushforward(i0, i1, i2, i3, i4, i5, r, + &d_functor, {}, {}, {}, {}, {}, {}, + d_r); + }, + res, d_res); + } +}; +template +struct diff_parallel_reduce_MDP_dispatch< + ::Kokkos::MDRangePolicy, FunctorType, Reduced, + void, 0> { // MDPolicy matched, now figure out the rank + static void + run(const ::std::string& str, + const ::Kokkos::MDRangePolicy& policy, + const FunctorType& functor, Reduced& res, const FunctorType& d_functor, + Reduced& d_res) { + diff_parallel_reduce_MDP_dispatch< + ::Kokkos::MDRangePolicy, FunctorType, Reduced, + typename ::Kokkos::MDRangePolicy::work_tag, + ::Kokkos::MDRangePolicy::rank>::run(str, + policy, + functor, + res, + d_functor, + d_res); + } +}; + +// This structure is used to dispatch parallel reduce pushforward calls for +// integral policies +template +struct diff_parallel_reduce_int_dispatch { // non-integral policy + static void run(const ::std::string& str, const Policy& policy, + const FunctorType& functor, Reduced& res, + const FunctorType& d_functor, Reduced& d_res) { + diff_parallel_reduce_MDP_dispatch::run(str, policy, functor, res, + d_functor, d_res); + } +}; +template // integral policy +struct diff_parallel_reduce_int_dispatch { + static void run(const ::std::string& str, const Policy& policy, + const FunctorType& functor, Reduced& res, + const FunctorType& d_functor, Reduced& d_res) { + ::Kokkos::parallel_reduce( + "_diff_" + str, policy, + [&](const auto& i, auto& r, auto& d_r) { + functor.operator_call_pushforward(i, r, &d_functor, {}, d_r); + }, + res, d_res); + } +}; + +template // generally, this is matched +void parallel_reduce_pushforward(const ::std::string& str, const Policy& policy, + const FunctorType& functor, Reduced& res, + const ::std::string& /*d_str*/, + const Policy& /*d_policy*/, + const FunctorType& d_functor, Reduced& d_res) { + diff_parallel_reduce_int_dispatch< + Policy, FunctorType, Reduced, + ::std::is_integral::value>::run(str, policy, functor, res, + d_functor, d_res); +} + } // namespace Kokkos } // namespace clad::custom_derivatives diff --git a/unittests/Kokkos/ParallelFor.cpp b/unittests/Kokkos/ParallelFor.cpp index 220ffc111..28975e3f5 100644 --- a/unittests/Kokkos/ParallelFor.cpp +++ b/unittests/Kokkos/ParallelFor.cpp @@ -3,7 +3,6 @@ #include "clad/Differentiator/KokkosBuiltins.h" #include "gtest/gtest.h" // #include "TestUtils.h" -#include "ParallelAdd.h" TEST(ParallelFor, HelloWorldLambdaLoopForward) { // // check finite difference and forward mode similarity diff --git a/unittests/Kokkos/ParallelReduce.cpp b/unittests/Kokkos/ParallelReduce.cpp index 7ee7b92cd..3ffbb316c 100644 --- a/unittests/Kokkos/ParallelReduce.cpp +++ b/unittests/Kokkos/ParallelReduce.cpp @@ -1,8 +1,8 @@ #include #include "clad/Differentiator/Differentiator.h" +#include "clad/Differentiator/KokkosBuiltins.h" #include "gtest/gtest.h" // #include "TestUtils.h" -#include "ParallelAdd.h" TEST(ParallelReduce, HelloWorldLambdaLoopForward) { // // check finite difference and forward mode similarity @@ -92,4 +92,91 @@ TEST(ParallelReduce, ParallelPolynomialReverse) { // f_grad.execute(x, &dx); // EXPECT_NEAR(dx_f_true, dx, abs(tau*dx)); // } +} + +struct Foo3 { + double& x; + + Foo3(double& _x) : x(_x) {} + + KOKKOS_INLINE_FUNCTION + void operator()(const int& i, double& value) const { + // 1+x*(value) -> 1+x(1+x(1+x(...))) + value = x * value + 1; + } +}; + +double parallel_recursive_polynomial_reduce(double x) { + double r = 0; + + Foo3 f(x); + + f(0, r); // FIXME: this is a workaround to put Foo3::operator() into the + // differentiation plan. This needs to be solved in clad. + + Kokkos::parallel_reduce("polynomial", 3, f, r); + + return r; +} + +double parallel_recursive_polynomial_reduce_rangepol(double x) { + double r = 0; + + Foo3 f(x); + + f(0, r); // FIXME: this is a workaround to put Foo3::operator() into the + // differentiation plan. This needs to be solved in clad. + + Kokkos::parallel_reduce( + "polynomial", + Kokkos::RangePolicy(0, 3), f, r); + + return r; +} + +struct Foo4 { + double& x; + + Foo4(double& _x) : x(_x) {} + + KOKKOS_INLINE_FUNCTION + void operator()(const int& i, const int& j, double& value) const { + value += j * i * x; + } +}; + +double parallel_MD_polynomial_reduce(double x) { + double r = 0; + + Foo4 f(x); + + f(1, 1, r); // FIXME: this is a workaround to put Foo4::operator() into the + // differentiation plan. This needs to be solved in clad. + + Kokkos::parallel_reduce( + "polynomial", + Kokkos::MDRangePolicy< + Kokkos::DefaultHostExecutionSpace, + Kokkos::Rank<2, Kokkos::Iterate::Right, Kokkos::Iterate::Left>>( + {1, 1}, {5, 5}, {1, 1}), + f, r); + + return r; +} + +TEST(ParallelReduce, FunctorSimplestCases) { + const double eps = 1e-8; + + auto df1 = clad::differentiate(parallel_recursive_polynomial_reduce, 0); + for (double x = 3; x <= 5; x += 1) + EXPECT_NEAR(df1.execute(x), (1 + 2 * x), eps); + + auto df2 = + clad::differentiate(parallel_recursive_polynomial_reduce_rangepol, 0); + for (double x = 3; x <= 5; x += 1) + EXPECT_NEAR(df2.execute(x), (1 + 2 * x), eps); + + auto df3 = clad::differentiate(parallel_MD_polynomial_reduce, 0); + for (double x = 3; x <= 5; x += 1) + EXPECT_NEAR(df3.execute(x), 100, eps); } \ No newline at end of file From dde2f083e96930a74a05074ec2853dbab8a22abd Mon Sep 17 00:00:00 2001 From: Atell Krasnopolski Date: Sun, 25 Aug 2024 16:58:54 +0200 Subject: [PATCH 3/6] Remove `ParallelAdd.h` from Kokkos unittest files --- unittests/Kokkos/ParallelAdd.h | 338 --------------------------------- 1 file changed, 338 deletions(-) delete mode 100644 unittests/Kokkos/ParallelAdd.h diff --git a/unittests/Kokkos/ParallelAdd.h b/unittests/Kokkos/ParallelAdd.h deleted file mode 100644 index 6d8b3d039..000000000 --- a/unittests/Kokkos/ParallelAdd.h +++ /dev/null @@ -1,338 +0,0 @@ -// source: -// https://github.com/kliegeois/clad/blob/kokkos-PR/unittests/Kokkos/parallel_sum.hpp - -#ifndef KOKKOS_UNITTEST_PARALLELSUM -#define KOKKOS_UNITTEST_PARALLELSUM - -#include - -namespace kokkos_builtin_derivative { - -// Parallel sum: - -template -struct ViewSum; - -template -struct ViewSum { - - template - static void execute(ResultT& result, const Viewtype& v, - const ExecSpace space = ExecSpace()) { - - using policy_type = - Kokkos::RangePolicy>; - using value_type = typename Viewtype::value_type; - - value_type sum; - - Kokkos::parallel_reduce( - "ViewSum-1D", policy_type(space, 0, v.extent(0)), - KOKKOS_LAMBDA(const iType& i0, value_type& update) { update += v(i0); }, - sum); - - result += sum; - } -}; - -template -struct ViewSum { - - template - static void execute(ResultT& result, const Viewtype& v, - const ExecSpace space = ExecSpace()) { - - static const Kokkos::Iterate outer_iteration_pattern = - Kokkos::layout_iterate_type_selector::outer_iteration_pattern; - static const Kokkos::Iterate inner_iteration_pattern = - Kokkos::layout_iterate_type_selector::inner_iteration_pattern; - using iterate_type = - Kokkos::Rank<2, outer_iteration_pattern, inner_iteration_pattern>; - using policy_type = Kokkos::MDRangePolicy>; - using value_type = typename Viewtype::value_type; - - value_type sum; - - Kokkos::parallel_reduce( - "ViewSum-2D", policy_type(space, {0, 0}, {v.extent(0), v.extent(1)}), - KOKKOS_LAMBDA(const iType& i0, const iType& i1, value_type& update) { - update += v(i0, i1); - }, - sum); - - result += sum; - } -}; - -template -struct ViewSum { - - template - static void execute(ResultT& result, const Viewtype& v, - const ExecSpace space = ExecSpace()) { - - static const Kokkos::Iterate outer_iteration_pattern = - Kokkos::layout_iterate_type_selector::outer_iteration_pattern; - static const Kokkos::Iterate inner_iteration_pattern = - Kokkos::layout_iterate_type_selector::inner_iteration_pattern; - using iterate_type = - Kokkos::Rank<3, outer_iteration_pattern, inner_iteration_pattern>; - using policy_type = Kokkos::MDRangePolicy>; - using value_type = typename Viewtype::value_type; - - value_type sum; - - Kokkos::parallel_reduce( - "ViewSum-3D", - policy_type(space, {0, 0}, {v.extent(0), v.extent(1), v.extent(2)}), - KOKKOS_LAMBDA(const iType& i0, const iType& i1, const iType& i2, - value_type& update) { update += v(i0, i1, i2); }, - sum); - - result += sum; - } -}; - -// Parallel add - -template -struct ViewAdd; - -template -struct ViewAdd { - - template - static void execute(const Viewtype& v, ResultT& update, - const ExecSpace space = ExecSpace()) { - - using policy_type = - Kokkos::RangePolicy>; - - Kokkos::parallel_for( - "ViewAdd-1D", policy_type(space, 0, v.extent(0)), - KOKKOS_LAMBDA(const iType& i0) { v(i0) += update; }); - } - - template - static void executeView(const Viewtype& v, ResultT& update, - const ExecSpace space = ExecSpace()) { - - using policy_type = - Kokkos::RangePolicy>; - - Kokkos::parallel_for( - "ViewAdd-1D", policy_type(space, 0, v.extent(0)), - KOKKOS_LAMBDA(const iType& i0) { v(i0) += update(i0); }); - } -}; - -template -struct ViewAdd { - - template - static void execute(const Viewtype& v, ResultT& update, - const ExecSpace space = ExecSpace()) { - - static const Kokkos::Iterate outer_iteration_pattern = - Kokkos::layout_iterate_type_selector::outer_iteration_pattern; - static const Kokkos::Iterate inner_iteration_pattern = - Kokkos::layout_iterate_type_selector::inner_iteration_pattern; - using iterate_type = - Kokkos::Rank<2, outer_iteration_pattern, inner_iteration_pattern>; - using policy_type = Kokkos::MDRangePolicy>; - - Kokkos::parallel_for( - "ViewAdd-2D", policy_type(space, {0, 0}, {v.extent(0), v.extent(1)}), - KOKKOS_LAMBDA(const iType& i0, const iType& i1) { - v(i0, i1) += update; - }); - } - - template - static void executeView(const Viewtype& v, ResultT& update, - const ExecSpace space = ExecSpace()) { - - static const Kokkos::Iterate outer_iteration_pattern = - Kokkos::layout_iterate_type_selector::outer_iteration_pattern; - static const Kokkos::Iterate inner_iteration_pattern = - Kokkos::layout_iterate_type_selector::inner_iteration_pattern; - using iterate_type = - Kokkos::Rank<2, outer_iteration_pattern, inner_iteration_pattern>; - using policy_type = Kokkos::MDRangePolicy>; - - Kokkos::parallel_for( - "ViewAdd-2D", policy_type(space, {0, 0}, {v.extent(0), v.extent(1)}), - KOKKOS_LAMBDA(const iType& i0, const iType& i1) { - v(i0, i1) += update(i0, i1); - }); - } -}; - -template -struct ViewAdd { - - template - static void execute(const Viewtype& v, ResultT& update, - const ExecSpace space = ExecSpace()) { - - static const Kokkos::Iterate outer_iteration_pattern = - Kokkos::layout_iterate_type_selector::outer_iteration_pattern; - static const Kokkos::Iterate inner_iteration_pattern = - Kokkos::layout_iterate_type_selector::inner_iteration_pattern; - using iterate_type = - Kokkos::Rank<3, outer_iteration_pattern, inner_iteration_pattern>; - using policy_type = Kokkos::MDRangePolicy>; - - Kokkos::parallel_for( - "ViewAdd-3D", - policy_type(space, {0, 0}, {v.extent(0), v.extent(1), v.extent(2)}), - KOKKOS_LAMBDA(const iType& i0, const iType& i1, const iType& i2) { - v(i0, i1, i2) += update; - }); - } - - template - static void executeView(const Viewtype& v, ResultT& update, - const ExecSpace space = ExecSpace()) { - - static const Kokkos::Iterate outer_iteration_pattern = - Kokkos::layout_iterate_type_selector::outer_iteration_pattern; - static const Kokkos::Iterate inner_iteration_pattern = - Kokkos::layout_iterate_type_selector::inner_iteration_pattern; - using iterate_type = - Kokkos::Rank<3, outer_iteration_pattern, inner_iteration_pattern>; - using policy_type = Kokkos::MDRangePolicy>; - - Kokkos::parallel_for( - "ViewAdd-3D", - policy_type(space, {0, 0}, {v.extent(0), v.extent(1), v.extent(2)}), - KOKKOS_LAMBDA(const iType& i0, const iType& i1, const iType& i2) { - v(i0, i1, i2) += update(i0, i1, i2); - }); - } -}; - -template -void parallel_sum(typename Kokkos::ViewTraits::value_type& sum, - const Kokkos::View A) { - using ViewtypeA = Kokkos::View; - Kokkos::fence(); - if (A.span_is_contiguous()) { - - using ViewTypeFlat = Kokkos::View< - typename ViewtypeA::value_type*, Kokkos::LayoutRight, - Kokkos::Device>, - Kokkos::MemoryTraits<0>>; - - ViewTypeFlat A_flat(A.data(), A.size()); - ViewSum::template execute< - typename ViewTypeFlat::execution_space>(sum, A_flat); - } else { - ViewSum::template execute(sum, A); - } - Kokkos::fence(); -} - -template -void parallel_sum(const ExecSpace& space, - typename Kokkos::ViewTraits::value_type& sum, - const Kokkos::View A) { - using ViewtypeA = Kokkos::View; - space.fence(); - if (A.span_is_contiguous()) { - - using ViewTypeFlat = Kokkos::View< - typename ViewtypeA::value_type*, Kokkos::LayoutRight, - Kokkos::Device>, - Kokkos::MemoryTraits<0>>; - - ViewTypeFlat A_flat(A.data(), A.size()); - ViewSum::template execute< - typename ViewTypeFlat::execution_space>(sum, A_flat, space); - } else { - ViewSum::template execute(sum, A, space); - } - space.fence(); -} - -template -void parallel_add(Kokkos::View A, - typename Kokkos::ViewTraits::const_value_type b) { - using ViewtypeA = Kokkos::View; - Kokkos::fence(); - if (A.span_is_contiguous()) { - - using ViewTypeFlat = Kokkos::View< - typename ViewtypeA::value_type*, Kokkos::LayoutRight, - Kokkos::Device>, - Kokkos::MemoryTraits<0>>; - - ViewTypeFlat A_flat(A.data(), A.size()); - ViewAdd::template execute< - typename ViewTypeFlat::execution_space>(A_flat, b); - } else { - ViewAdd::template execute(A, b); - } - Kokkos::fence(); -} - -template -void parallel_add(const ExecSpace& space, Kokkos::View A, - typename Kokkos::ViewTraits::const_value_type b) { - using ViewtypeA = Kokkos::View; - space.fence(); - if (A.span_is_contiguous()) { - - using ViewTypeFlat = Kokkos::View< - typename ViewtypeA::value_type*, Kokkos::LayoutRight, - Kokkos::Device>, - Kokkos::MemoryTraits<0>>; - - ViewTypeFlat A_flat(A.data(), A.size()); - ViewAdd::template execute< - typename ViewTypeFlat::execution_space>(A_flat, b, space); - } else { - ViewAdd::template execute(A, b, space); - } - space.fence(); -} - -template -void parallel_add(Kokkos::View A, const Kokkos::View B) { - using ViewtypeA = Kokkos::View; - using ViewtypeA = Kokkos::View; - Kokkos::fence(); - - ViewAdd::template executeView(A, B); - - Kokkos::fence(); -} - -} // namespace kokkos_builtin_derivative - -#endif \ No newline at end of file From e2f4638e24ad32e2fb24e75c68eac43d89fd47ff Mon Sep 17 00:00:00 2001 From: Atell Krasnopolski Date: Sun, 25 Aug 2024 20:34:07 +0200 Subject: [PATCH 4/6] Fix `Kokkos::parallel_for_pushforward` signature for non-void work tag --- include/clad/Differentiator/KokkosBuiltins.h | 64 +++++++++++--------- 1 file changed, 34 insertions(+), 30 deletions(-) diff --git a/include/clad/Differentiator/KokkosBuiltins.h b/include/clad/Differentiator/KokkosBuiltins.h index ef479a16d..14af4dfa0 100644 --- a/include/clad/Differentiator/KokkosBuiltins.h +++ b/include/clad/Differentiator/KokkosBuiltins.h @@ -168,11 +168,11 @@ template struct diff_parallel_for_MDP_call_dispatch { static void run(const ::std::string& str, const Policy& policy, const FunctorType& functor, const FunctorType& d_functor) { - ::Kokkos::parallel_for("_diff_" + str, policy, - [&functor, &d_functor](const T x, auto&&... args) { - functor.operator_call_pushforward( - x, args..., &d_functor, &x, 0, 0); - }); + ::Kokkos::parallel_for( + "_diff_" + str, policy, + [&functor, &d_functor](const auto x, auto&&... args) { + functor.operator_call_pushforward(x, args..., &d_functor, {}, 0, 0); + }); } }; template @@ -189,11 +189,12 @@ template struct diff_parallel_for_MDP_call_dispatch { static void run(const ::std::string& str, const Policy& policy, const FunctorType& functor, const FunctorType& d_functor) { - ::Kokkos::parallel_for("_diff_" + str, policy, - [&functor, &d_functor](const T x, auto&&... args) { - functor.operator_call_pushforward( - x, args..., &d_functor, &x, 0, 0, 0); - }); + ::Kokkos::parallel_for( + "_diff_" + str, policy, + [&functor, &d_functor](const auto x, auto&&... args) { + functor.operator_call_pushforward(x, args..., &d_functor, {}, 0, 0, + 0); + }); } }; template @@ -210,11 +211,12 @@ template struct diff_parallel_for_MDP_call_dispatch { static void run(const ::std::string& str, const Policy& policy, const FunctorType& functor, const FunctorType& d_functor) { - ::Kokkos::parallel_for("_diff_" + str, policy, - [&functor, &d_functor](const T x, auto&&... args) { - functor.operator_call_pushforward( - x, args..., &d_functor, &x, 0, 0, 0, 0); - }); + ::Kokkos::parallel_for( + "_diff_" + str, policy, + [&functor, &d_functor](const auto x, auto&&... args) { + functor.operator_call_pushforward(x, args..., &d_functor, {}, 0, 0, 0, + 0); + }); } }; template @@ -231,11 +233,12 @@ template struct diff_parallel_for_MDP_call_dispatch { static void run(const ::std::string& str, const Policy& policy, const FunctorType& functor, const FunctorType& d_functor) { - ::Kokkos::parallel_for("_diff_" + str, policy, - [&functor, &d_functor](const T x, auto&&... args) { - functor.operator_call_pushforward( - x, args..., &d_functor, &x, 0, 0, 0, 0, 0); - }); + ::Kokkos::parallel_for( + "_diff_" + str, policy, + [&functor, &d_functor](const auto x, auto&&... args) { + functor.operator_call_pushforward(x, args..., &d_functor, {}, 0, 0, 0, + 0, 0); + }); } }; template @@ -252,11 +255,12 @@ template struct diff_parallel_for_MDP_call_dispatch { static void run(const ::std::string& str, const Policy& policy, const FunctorType& functor, const FunctorType& d_functor) { - ::Kokkos::parallel_for("_diff_" + str, policy, - [&functor, &d_functor](const T x, auto&&... args) { - functor.operator_call_pushforward( - x, args..., &d_functor, &x, 0, 0, 0, 0, 0, 0); - }); + ::Kokkos::parallel_for( + "_diff_" + str, policy, + [&functor, &d_functor](const auto x, auto&&... args) { + functor.operator_call_pushforward(x, args..., &d_functor, {}, 0, 0, 0, + 0, 0, 0); + }); } }; template @@ -294,11 +298,11 @@ template struct diff_parallel_for_OP_call_dispatch { static void run(const ::std::string& str, const Policy& policy, const FunctorType& functor, const FunctorType& d_functor) { - ::Kokkos::parallel_for("_diff_" + str, policy, - [&functor, &d_functor](const T x, auto&&... args) { - functor.operator_call_pushforward( - x, args..., &d_functor, &x, {}); - }); + ::Kokkos::parallel_for( + "_diff_" + str, policy, + [&functor, &d_functor](const auto x, auto&&... args) { + functor.operator_call_pushforward(x, args..., &d_functor, {}, {}); + }); } }; template From 181208c417b13018924203aecc3f66e38beabf92 Mon Sep 17 00:00:00 2001 From: Atell Krasnopolski Date: Wed, 28 Aug 2024 16:53:08 +0200 Subject: [PATCH 5/6] Make the signatues of `KokkosBuiltins.h` more general --- include/clad/Differentiator/KokkosBuiltins.h | 117 ++++++++++--------- 1 file changed, 64 insertions(+), 53 deletions(-) diff --git a/include/clad/Differentiator/KokkosBuiltins.h b/include/clad/Differentiator/KokkosBuiltins.h index 14af4dfa0..1a6253027 100644 --- a/include/clad/Differentiator/KokkosBuiltins.h +++ b/include/clad/Differentiator/KokkosBuiltins.h @@ -20,9 +20,11 @@ constructor_pushforward( const ::std::string& name, const size_t& idx0, const size_t& idx1, const size_t& idx2, const size_t& idx3, const size_t& idx4, const size_t& idx5, const size_t& idx6, const size_t& idx7, - const ::std::string& d_name, const size_t& d_idx0, const size_t& d_idx1, - const size_t& d_idx2, const size_t& d_idx3, const size_t& d_idx4, - const size_t& d_idx5, const size_t& d_idx6, const size_t& d_idx7) { + const ::std::string& /*d_name*/, const size_t& /*d_idx0*/, + const size_t& /*d_idx1*/, const size_t& /*d_idx2*/, + const size_t& /*d_idx3*/, const size_t& /*d_idx4*/, + const size_t& /*d_idx5*/, const size_t& /*d_idx6*/, + const size_t& /*d_idx7*/) { return {Kokkos::View(name, idx0, idx1, idx2, idx3, idx4, idx5, idx6, idx7), Kokkos::View( @@ -37,63 +39,71 @@ operator_call_pushforward(const View* v, Idx i0, const View* d_v, Idx /*d_i0*/) { return {(*v)(i0), (*d_v)(i0)}; } -template +template clad::ValueAndPushforward -operator_call_pushforward(const View* v, Idx i0, Idx i1, const View* d_v, - Idx /*d_i0*/, Idx /*d_i1*/) { +operator_call_pushforward(const View* v, Idx0 i0, Idx1 i1, const View* d_v, + Idx0 /*d_i0*/, Idx1 /*d_i1*/) { return {(*v)(i0, i1), (*d_v)(i0, i1)}; } -template +template clad::ValueAndPushforward -operator_call_pushforward(const View* v, Idx i0, Idx i1, Idx i2, - const View* d_v, Idx /*d_i0*/, Idx /*d_i1*/, - Idx /*d_i2*/) { +operator_call_pushforward(const View* v, Idx0 i0, Idx1 i1, Idx2 i2, + const View* d_v, Idx0 /*d_i0*/, Idx1 /*d_i1*/, + Idx2 /*d_i2*/) { return {(*v)(i0, i1, i2), (*d_v)(i0, i1, i2)}; } -template +template clad::ValueAndPushforward -operator_call_pushforward(const View* v, Idx i0, Idx i1, Idx i2, Idx i3, - const View* d_v, Idx /*d_i0*/, Idx /*d_i1*/, - Idx /*d_i2*/, Idx /*d_i3*/) { +operator_call_pushforward(const View* v, Idx0 i0, Idx1 i1, Idx2 i2, Idx3 i3, + const View* d_v, Idx0 /*d_i0*/, Idx1 /*d_i1*/, + Idx2 /*d_i2*/, Idx3 /*d_i3*/) { return {(*v)(i0, i1, i2, i3), (*d_v)(i0, i1, i2, i3)}; } -template +template clad::ValueAndPushforward -operator_call_pushforward(const View* v, Idx i0, Idx i1, Idx i2, Idx i3, Idx i4, - const View* d_v, Idx /*d_i0*/, Idx /*d_i1*/, - Idx /*d_i2*/, Idx /*d_i3*/, Idx /*d_i4*/) { +operator_call_pushforward(const View* v, Idx0 i0, Idx1 i1, Idx2 i2, Idx3 i3, + Idx4 i4, const View* d_v, Idx0 /*d_i0*/, + Idx1 /*d_i1*/, Idx2 /*d_i2*/, Idx3 /*d_i3*/, + Idx4 /*d_i4*/) { return {(*v)(i0, i1, i2, i3, i4), (*d_v)(i0, i1, i2, i3, i4)}; } -template +template clad::ValueAndPushforward -operator_call_pushforward(const View* v, Idx i0, Idx i1, Idx i2, Idx i3, Idx i4, - Idx i5, const View* d_v, Idx /*d_i0*/, Idx /*d_i1*/, - Idx /*d_i2*/, Idx /*d_i3*/, Idx /*d_i4*/, - Idx /*d_i5*/) { +operator_call_pushforward(const View* v, Idx0 i0, Idx1 i1, Idx2 i2, Idx3 i3, + Idx4 i4, Idx5 i5, const View* d_v, Idx0 /*d_i0*/, + Idx1 /*d_i1*/, Idx2 /*d_i2*/, Idx3 /*d_i3*/, + Idx4 /*d_i4*/, Idx5 /*d_i5*/) { return {(*v)(i0, i1, i2, i3, i4, i5), (*d_v)(i0, i1, i2, i3, i4, i5)}; } -template +template clad::ValueAndPushforward -operator_call_pushforward(const View* v, Idx i0, Idx i1, Idx i2, Idx i3, Idx i4, - Idx i5, Idx i6, const View* d_v, Idx /*d_i0*/, - Idx /*d_i1*/, Idx /*d_i2*/, Idx /*d_i3*/, - Idx /*d_i4*/, Idx /*d_i5*/, Idx /*d_i6*/) { +operator_call_pushforward(const View* v, Idx0 i0, Idx1 i1, Idx2 i2, Idx3 i3, + Idx4 i4, Idx5 i5, Idx6 i6, const View* d_v, + Idx0 /*d_i0*/, Idx1 /*d_i1*/, Idx2 /*d_i2*/, + Idx3 /*d_i3*/, Idx4 /*d_i4*/, Idx5 /*d_i5*/, + Idx6 /*d_i6*/) { return {(*v)(i0, i1, i2, i3, i4, i5, i6), (*d_v)(i0, i1, i2, i3, i4, i5, i6)}; } -template +template clad::ValueAndPushforward -operator_call_pushforward(const View* v, Idx i0, Idx i1, Idx i2, Idx i3, Idx i4, - Idx i5, Idx i6, Idx i7, const View* d_v, Idx /*d_i0*/, - Idx /*d_i1*/, Idx /*d_i2*/, Idx /*d_i3*/, - Idx /*d_i4*/, Idx /*d_i5*/, Idx /*d_i6*/, - Idx /*d_i7*/) { +operator_call_pushforward(const View* v, Idx0 i0, Idx1 i1, Idx2 i2, Idx3 i3, + Idx4 i4, Idx5 i5, Idx6 i6, Idx7 i7, const View* d_v, + Idx0 /*d_i0*/, Idx1 /*d_i1*/, Idx2 /*d_i2*/, + Idx3 /*d_i3*/, Idx4 /*d_i4*/, Idx5 /*d_i5*/, + Idx6 /*d_i6*/, Idx7 /*d_i7*/) { return {(*v)(i0, i1, i2, i3, i4, i5, i6, i7), (*d_v)(i0, i1, i2, i3, i4, i5, i6, i7)}; } @@ -108,28 +118,29 @@ inline void deep_copy_pushforward(const View1& dst, const View2& src, T param, deep_copy(dst, src); deep_copy(d_dst, d_src); } -template -inline void resize_pushforward(View& v, const size_t n0, const size_t n1, - const size_t n2, const size_t n3, - const size_t n4, const size_t n5, - const size_t n6, const size_t n7, View& d_v, - const size_t /*d_n0*/, const size_t /*d_n1*/, - const size_t /*d_n2*/, const size_t /*d_n3*/, - const size_t /*d_n4*/, const size_t /*d_n5*/, - const size_t /*d_n6*/, const size_t /*d_n7*/) { +template +inline void +resize_pushforward(View& v, const Idx0 n0, const Idx1 n1, const Idx2 n2, + const Idx3 n3, const Idx4 n4, const Idx5 n5, const Idx6 n6, + const Idx7 n7, View& d_v, const Idx0 /*d_n*/, + const Idx1 /*d_n*/, const Idx2 /*d_n*/, const Idx3 /*d_n*/, + const Idx4 /*d_n*/, const Idx5 /*d_n*/, const Idx6 /*d_n*/, + const Idx7 /*d_n*/) { ::Kokkos::resize(v, n0, n1, n2, n3, n4, n5, n6, n7); ::Kokkos::resize(d_v, n0, n1, n2, n3, n4, n5, n6, n7); } -template -inline void resize_pushforward(const I& arg, View& v, const size_t n0, - const size_t n1, const size_t n2, - const size_t n3, const size_t n4, - const size_t n5, const size_t n6, - const size_t n7, const dI& /*d_arg*/, View& d_v, - const size_t /*d_n0*/, const size_t /*d_n1*/, - const size_t /*d_n2*/, const size_t /*d_n3*/, - const size_t /*d_n4*/, const size_t /*d_n5*/, - const size_t /*d_n6*/, const size_t /*d_n7*/) { +template +inline void +resize_pushforward(const I& arg, View& v, const Idx0 n0, const Idx1 n1, + const Idx2 n2, const Idx3 n3, const Idx4 n4, const Idx5 n5, + const Idx6 n6, const Idx7 n7, const dI& /*d_arg*/, View& d_v, + const Idx0 /*d_n*/, const Idx1 /*d_n*/, const Idx2 /*d_n*/, + const Idx3 /*d_n*/, const Idx4 /*d_n*/, const Idx5 /*d_n*/, + const Idx6 /*d_n*/, const Idx7 /*d_n*/) { ::Kokkos::resize(arg, v, n0, n1, n2, n3, n4, n5, n6, n7); ::Kokkos::resize(arg, d_v, n0, n1, n2, n3, n4, n5, n6, n7); } From 8f7d247641592845ba93c6b0bf681eea5028ecd1 Mon Sep 17 00:00:00 2001 From: infinite-void-16 Date: Thu, 29 Aug 2024 01:31:57 +0530 Subject: [PATCH 6/6] Add primitive support of reverse-mode constructor custom derivatives (#1045) This commit adds primitive support of reverse-mode custom derivatives for constructors. Constructors can thought of like a special function. A function which also constructs an object. Therefore, differentiation of a constructor is very similar to the differentiation of a function call. Please note that this includes innocent looking initialization such as: ``` SomeClass C1 = C2; ``` This would involve differentiation of copy-constructor of `SomeClass`. Let's see a concrete example of how differentiation of a constructor call looks like: Original code: ```cpp SomeClass c(u, v, w); ``` Derivative code: ```cpp // forward-pass clad::ValueAndAdjoint _t0 = constructor_reverse_forw(clad::ConstructorReverseForwTag, u, v, w, _d_u, _d_v, _d_w); SomeClass _d_c(_t0.adjoint); SomeClass c(_t0.value); // reverse-pass { double _r0 = 0; double _r1 = 0; double _r2 = 0; constructor_pullback(&c, u, v, w, &_d_c, &_r0, &_r1, &_r2); _d_u += _r0; _d_v += _r1; _d_w += _r2; } ``` Please note the use of `clad::ConstructorReverseForwTag` for `constructor_reverse_forw` function. The reasoning and motivation for this is the same as we have for `clad::ConstructorPushforwardTag` Reverse-mode custom derivatives for constructor can be specified as: ```cpp namespace clad { namespace custom_derivatives { namespace class_functions { clad::ValueAndAdjoint constructor_reverse_forw(clad::ConstructorReverseForwTag, ...) { // ... // ... } void constructor_pullback(SomeClass *c, ..., SomeClass *d_c, ...) { // ... } ``` --- .../clad/Differentiator/BuiltinDerivatives.h | 12 ++ .../clad/Differentiator/ReverseModeVisitor.h | 30 +++ include/clad/Differentiator/STLBuiltins.h | 22 +++ include/clad/Differentiator/VisitorBase.h | 7 + lib/Differentiator/DerivativeBuilder.cpp | 1 - lib/Differentiator/ReverseModeVisitor.cpp | 187 ++++++++++++++++-- lib/Differentiator/VisitorBase.cpp | 19 +- test/Gradient/Functors.C | 24 ++- test/Gradient/MemberFunctions.C | 78 +++++++- test/Gradient/NonDifferentiable.C | 22 ++- test/Gradient/PointersWithTBR.C | 2 +- test/Gradient/STLCustomDerivatives.C | 40 +++- test/Gradient/UserDefinedTypes.C | 9 + test/Hessian/BuiltinDerivatives.C | 90 +++++---- test/Hessian/NestedFunctionCalls.C | 28 +-- unittests/Misc/CMakeLists.txt | 2 +- 16 files changed, 486 insertions(+), 87 deletions(-) diff --git a/include/clad/Differentiator/BuiltinDerivatives.h b/include/clad/Differentiator/BuiltinDerivatives.h index ac47237bc..a31b239bb 100644 --- a/include/clad/Differentiator/BuiltinDerivatives.h +++ b/include/clad/Differentiator/BuiltinDerivatives.h @@ -54,6 +54,8 @@ template struct ValueAndAdjoint { /// class for which constructor pushforward is defined. template class ConstructorPushforwardTag {}; +template class ConstructorReverseForwTag {}; + namespace custom_derivatives { #ifdef __CUDACC__ template @@ -329,6 +331,16 @@ using std::pow_pullback; using std::pow_pushforward; using std::sin_pushforward; using std::sqrt_pushforward; + +namespace class_functions { +template +void constructor_pullback(ValueAndPushforward* lhs, + ValueAndPushforward rhs, + ValueAndPushforward* d_lhs, + ValueAndPushforward* d_rhs) { + d_rhs->pushforward += d_lhs->pushforward; +} +} // namespace class_functions } // namespace custom_derivatives } // namespace clad diff --git a/include/clad/Differentiator/ReverseModeVisitor.h b/include/clad/Differentiator/ReverseModeVisitor.h index 5eeb60286..40feb6723 100644 --- a/include/clad/Differentiator/ReverseModeVisitor.h +++ b/include/clad/Differentiator/ReverseModeVisitor.h @@ -16,6 +16,7 @@ #include "clang/Sema/Sema.h" #include +#include #include #include #include @@ -689,6 +690,35 @@ namespace clad { } void PopSwitchStmtInfo() { m_SwitchStmtsData.pop_back(); } + + struct ConstructorPullbackCallInfo { + clang::CallExpr* pullbackCE = nullptr; + size_t thisAdjointArgIdx = std::numeric_limits::max(); + void updateThisParmArgs(clang::Expr* thisE, clang::Expr* dThisE) const; + ConstructorPullbackCallInfo() = default; + ConstructorPullbackCallInfo(clang::CallExpr* pPullbackCE, + size_t pThisAdjointArgIdx) + : pullbackCE(pPullbackCE), thisAdjointArgIdx(pThisAdjointArgIdx) {} + + bool empty() const { return !pullbackCE; } + }; + + void setConstructorPullbackCallInfo(clang::CallExpr* pullbackCE, + size_t thisAdjointArgIdx) { + m_ConstructorPullbackCallInfo = {pullbackCE, thisAdjointArgIdx}; + } + + ConstructorPullbackCallInfo getConstructorPullbackCallInfo() { + return m_ConstructorPullbackCallInfo; + } + + void resetConstructorPullbackCallInfo() { + m_ConstructorPullbackCallInfo = ConstructorPullbackCallInfo{}; + } + + private: + ConstructorPullbackCallInfo m_ConstructorPullbackCallInfo; + bool m_TrackConstructorPullbackInfo = false; }; } // end namespace clad diff --git a/include/clad/Differentiator/STLBuiltins.h b/include/clad/Differentiator/STLBuiltins.h index e1e0f5abb..147938080 100644 --- a/include/clad/Differentiator/STLBuiltins.h +++ b/include/clad/Differentiator/STLBuiltins.h @@ -231,6 +231,28 @@ void operator_subscript_pullback(::std::vector* vec, (*d_vec)[idx] += d_y; } +template +::clad::ValueAndAdjoint<::std::vector, ::std::vector> +constructor_reverse_forw(::clad::ConstructorReverseForwTag<::std::vector>, + S count, U val, + typename ::std::vector::allocator_type alloc, + S d_count, U d_val, + typename ::std::vector::allocator_type d_alloc) { + ::std::vector v(count, val); + ::std::vector d_v(count, 0); + return {v, d_v}; +} + +template +void constructor_pullback(::std::vector* v, S count, U val, + typename ::std::vector::allocator_type alloc, + ::std::vector* d_v, S* d_count, U* d_val, + typename ::std::vector::allocator_type* d_alloc) { + for (unsigned i = 0; i < count; ++i) + *d_val += (*d_v)[i]; + d_v->clear(); +} + } // namespace class_functions } // namespace custom_derivatives } // namespace clad diff --git a/include/clad/Differentiator/VisitorBase.h b/include/clad/Differentiator/VisitorBase.h index c209c8cee..e78149d3d 100644 --- a/include/clad/Differentiator/VisitorBase.h +++ b/include/clad/Differentiator/VisitorBase.h @@ -614,6 +614,12 @@ namespace clad { /// Returns type clad::Identify clang::QualType GetCladConstructorPushforwardTagOfType(clang::QualType T); + /// Returns clad::ConstructorReverseForwTag template declaration. + clang::TemplateDecl* GetCladConstructorReverseForwTag(); + + /// Returns type clad::ConstructorReverseForwTag + clang::QualType GetCladConstructorReverseForwTagOfType(clang::QualType T); + public: /// Rebuild a sequence of nested namespaces ending with DC. clang::NamespaceDecl* RebuildEnclosingNamespaces(clang::DeclContext* DC); @@ -661,6 +667,7 @@ namespace clad { private: clang::TemplateDecl* m_CladConstructorPushforwardTag = nullptr; + clang::TemplateDecl* m_CladConstructorReverseForwTag = nullptr; }; } // end namespace clad diff --git a/lib/Differentiator/DerivativeBuilder.cpp b/lib/Differentiator/DerivativeBuilder.cpp index a4defc87e..a569a90ae 100644 --- a/lib/Differentiator/DerivativeBuilder.cpp +++ b/lib/Differentiator/DerivativeBuilder.cpp @@ -247,7 +247,6 @@ static void registerDerivative(FunctionDecl* derivedFD, Sema& semaRef) { const std::string& Name, llvm::SmallVectorImpl& CallArgs, clang::Scope* S, clang::DeclContext* originalFnDC, bool forCustomDerv /*=true*/, bool namespaceShouldExist /*=true*/) { - CXXScopeSpec SS; LookupResult R = LookupCustomDerivativeOrNumericalDiff( Name, originalFnDC, SS, forCustomDerv, namespaceShouldExist); diff --git a/lib/Differentiator/ReverseModeVisitor.cpp b/lib/Differentiator/ReverseModeVisitor.cpp index 637b027cc..da656a33f 100644 --- a/lib/Differentiator/ReverseModeVisitor.cpp +++ b/lib/Differentiator/ReverseModeVisitor.cpp @@ -29,6 +29,10 @@ #include "clang/Sema/Sema.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" +#include +#include +#include +#include #include "llvm/Support/SaveAndRestore.h" @@ -2763,6 +2767,8 @@ Expr* getArraySizeExpr(const ArrayType* AT, ASTContext& context, if (isPointerType && VD->getInit() && isa(VD->getInit())) isInitializedByNewExpr = true; + ConstructorPullbackCallInfo constructorPullbackInfo; + // VDDerivedInit now serves two purposes -- as the initial derivative value // or the size of the derivative array -- depending on the primal type. if (const auto* AT = dyn_cast(VDType)) { @@ -2819,6 +2825,16 @@ Expr* getArraySizeExpr(const ArrayType* AT, ASTContext& context, VDDerivedInit = initDiff.getForwSweepExpr_dx(); } + if (VDType->isStructureOrClassType()) { + m_TrackConstructorPullbackInfo = true; + initDiff = Visit(VD->getInit()); + m_TrackConstructorPullbackInfo = false; + constructorPullbackInfo = getConstructorPullbackCallInfo(); + resetConstructorPullbackCallInfo(); + if (initDiff.getForwSweepExpr_dx()) + VDDerivedInit = initDiff.getForwSweepExpr_dx(); + } + // FIXME: Remove the special cases introduced by `specialThisDiffCase` // once reverse mode supports pointers. `specialThisDiffCase` is only // required for correctly differentiating the following code: @@ -2880,9 +2896,10 @@ Expr* getArraySizeExpr(const ArrayType* AT, ASTContext& context, } if (VD->getInit()) { - if (isa(VD->getInit())) - initDiff = Visit(VD->getInit()); - else + if (VDType->isStructureOrClassType()) { + if (!initDiff.getExpr()) + initDiff = Visit(VD->getInit()); + } else initDiff = Visit(VD->getInit(), derivedE); } @@ -2994,6 +3011,13 @@ Expr* getArraySizeExpr(const ArrayType* AT, ASTContext& context, VDType != VDClone->getType())) m_DeclReplacements[VD] = VDClone; + if (!constructorPullbackInfo.empty()) { + Expr* thisE = + BuildOp(UnaryOperatorKind::UO_AddrOf, BuildDeclRef(VDClone)); + Expr* dThisE = + BuildOp(UnaryOperatorKind::UO_AddrOf, BuildDeclRef(VDDerived)); + constructorPullbackInfo.updateThisParmArgs(thisE, dThisE); + } return DeclDiff(VDClone, VDDerived); } @@ -4111,20 +4135,140 @@ Expr* getArraySizeExpr(const ArrayType* AT, ASTContext& context, return {nullptr, nullptr}; } - // FIXME: Add support for differentiating calls to constructors. - // We currently assume that constructor arguments are non-differentiable. StmtDiff ReverseModeVisitor::VisitCXXConstructExpr(const CXXConstructExpr* CE) { - llvm::SmallVector clonedArgs; + + llvm::SmallVector primalArgs; + llvm::SmallVector adjointArgs; + llvm::SmallVector reverseForwAdjointArgs; + // It is used to store '_r0' temporary gradient variables that are used for + // differentiating non-reference args. + llvm::SmallVector prePullbackCallStmts; + + // Insertion point is required because we need to insert pullback call + // before the statements inserted by 'Visit(arg, ...)' calls for arguments. + std::size_t insertionPoint = getCurrentBlock(direction::reverse).size(); + + // FIXME: Restore arguments passed as non-const reference. for (const auto* arg : CE->arguments()) { - auto argDiff = Visit(arg, dfdx()); - clonedArgs.push_back(argDiff.getExpr()); + QualType ArgTy = arg->getType(); + StmtDiff argDiff{}; + Expr* adjointArg = nullptr; + if (utils::IsReferenceOrPointerArg(arg->IgnoreParenImpCasts())) { + argDiff = Visit(arg); + adjointArg = argDiff.getExpr_dx(); + } else { + // non-reference arguments are differentiated as follows: + // + // primal code: + // ``` + // SomeClass c(u, ...); + // ``` + // + // Derivative code: + // ``` + // // forward pass + // ... + // // reverse pass + // double _r0 = 0; + // SomeClass_pullback(c, u, ..., &_d_c, &_r0, ...); + // _d_u += _r0; + QualType dArgTy = getNonConstType(ArgTy, m_Context, m_Sema); + VarDecl* dArgDecl = BuildVarDecl(dArgTy, "_r", getZeroInit(dArgTy)); + prePullbackCallStmts.push_back(BuildDeclStmt(dArgDecl)); + adjointArg = BuildDeclRef(dArgDecl); + argDiff = Visit(arg, BuildDeclRef(dArgDecl)); + } + + if (utils::isArrayOrPointerType(ArgTy)) { + reverseForwAdjointArgs.push_back(adjointArg); + adjointArgs.push_back(adjointArg); + } else { + if (utils::IsReferenceOrPointerArg(arg->IgnoreParenImpCasts())) + reverseForwAdjointArgs.push_back(adjointArg); + else + reverseForwAdjointArgs.push_back(getZeroInit(ArgTy)); + adjointArgs.push_back(BuildOp(UnaryOperatorKind::UO_AddrOf, adjointArg, + m_DiffReq->getLocation())); + } + primalArgs.push_back(argDiff.getExpr()); + } + + // Try to create a pullback constructor call + llvm::SmallVector pullbackArgs; + QualType recordType = + m_Context.getRecordType(CE->getConstructor()->getParent()); + QualType recordPointerType = m_Context.getPointerType(recordType); + // thisE = object being created by this constructor call. + // dThisE = adjoint of the object being created by this constructor call. + // + // We cannot fill these args yet because these objects have not yet been + // created. The caller which triggers 'VisitCXXConstructExpr' is + // responsible for updating these args. + Expr* thisE = getZeroInit(recordPointerType); + Expr* dThisE = getZeroInit(recordPointerType); + + pullbackArgs.push_back(thisE); + pullbackArgs.append(primalArgs.begin(), primalArgs.end()); + pullbackArgs.push_back(dThisE); + pullbackArgs.append(adjointArgs.begin(), adjointArgs.end()); + + Stmts& curRevBlock = getCurrentBlock(direction::reverse); + Stmts::iterator it = std::begin(curRevBlock) + insertionPoint; + curRevBlock.insert(it, prePullbackCallStmts.begin(), + prePullbackCallStmts.end()); + it += prePullbackCallStmts.size(); + std::string customPullbackName = "constructor_pullback"; + if (Expr* customPullbackCall = + m_Builder.BuildCallToCustomDerivativeOrNumericalDiff( + customPullbackName, pullbackArgs, getCurrentScope(), + const_cast( + CE->getConstructor()->getDeclContext()))) { + curRevBlock.insert(it, customPullbackCall); + if (m_TrackConstructorPullbackInfo) { + setConstructorPullbackCallInfo(llvm::cast(customPullbackCall), + primalArgs.size() + 1); + m_TrackConstructorPullbackInfo = false; + } + } + // FIXME: If no compatible custom constructor pullback is found then try + // to automatically differentiate the constructor. + + // Create the constructor call in the forward-pass, or creates + // 'constructor_forw' call if possible. + + // This works as follows: + // + // primal code: + // ``` + // SomeClass c(u, v); + // ``` + // + // adjoint code: + // ``` + // // forward-pass + // clad::ValueAndAdjoint _t0 = + // constructor_forw(clad::ConstructorReverseForwTag{}, u, v, + // _d_u, _d_v); + // SomeClass _d_c = _t0.adjoint; + // SomeClass c = _t0.value; + // ``` + if (Expr* customReverseForwFnCall = BuildCallToCustomForwPassFn( + CE->getConstructor(), primalArgs, reverseForwAdjointArgs, + /*baseExpr=*/nullptr)) { + Expr* callRes = StoreAndRef(customReverseForwFnCall); + Expr* val = + utils::BuildMemberExpr(m_Sema, getCurrentScope(), callRes, "value"); + Expr* adjoint = + utils::BuildMemberExpr(m_Sema, getCurrentScope(), callRes, "adjoint"); + return {val, nullptr, adjoint}; } + Expr* clonedArgsE = nullptr; if (CE->getNumArgs() != 1) { if (CE->isListInitialization()) { - clonedArgsE = m_Sema.ActOnInitList(noLoc, clonedArgs, noLoc).get(); + clonedArgsE = m_Sema.ActOnInitList(noLoc, primalArgs, noLoc).get(); } else { if (CE->getNumArgs() == 0) { // ParenList is empty -- default initialisation. @@ -4132,10 +4276,10 @@ Expr* getArraySizeExpr(const ArrayType* AT, ASTContext& context, // parse' issue. return StmtDiff(); } - clonedArgsE = m_Sema.ActOnParenListExpr(noLoc, noLoc, clonedArgs).get(); + clonedArgsE = m_Sema.ActOnParenListExpr(noLoc, noLoc, primalArgs).get(); } } else { - clonedArgsE = clonedArgs[0]; + clonedArgsE = primalArgs[0]; } // `CXXConstructExpr` node will be created automatically by passing these // initialiser to higher level `ActOn`/`Build` Sema functions. @@ -4384,6 +4528,21 @@ Expr* getArraySizeExpr(const ArrayType* AT, ASTContext& context, m_DiffReq->getLocation()); args.push_back(baseExpr); } + if (auto CD = llvm::dyn_cast(FD)) { + const RecordDecl* RD = CD->getParent(); + QualType constructorReverseForwTagT = + GetCladConstructorReverseForwTagOfType(m_Context.getRecordType(RD)); + Expr* constructorReverseForwTagArg = + m_Sema + .BuildCXXTypeConstructExpr( + m_Context.getTrivialTypeSourceInfo( + constructorReverseForwTagT, utils::GetValidSLoc(m_Sema)), + utils::GetValidSLoc(m_Sema), MultiExprArg{}, + utils::GetValidSLoc(m_Sema), + /*ListInitialization=*/false) + .get(); + args.push_back(constructorReverseForwTagArg); + } args.append(primalArgs.begin(), primalArgs.end()); args.append(derivedArgs.begin(), derivedArgs.end()); Expr* customForwPassCE = @@ -4392,4 +4551,10 @@ Expr* getArraySizeExpr(const ArrayType* AT, ASTContext& context, const_cast(FD->getDeclContext())); return customForwPassCE; } + + void ReverseModeVisitor::ConstructorPullbackCallInfo::updateThisParmArgs( + Expr* thisE, Expr* dThisE) const { + pullbackCE->setArg(0, thisE); + pullbackCE->setArg(thisAdjointArgIdx, dThisE); + } } // end namespace clad diff --git a/lib/Differentiator/VisitorBase.cpp b/lib/Differentiator/VisitorBase.cpp index 113e01e4d..a3c3ec384 100644 --- a/lib/Differentiator/VisitorBase.cpp +++ b/lib/Differentiator/VisitorBase.cpp @@ -449,11 +449,12 @@ namespace clad { QualType VisitorBase::InstantiateTemplate(TemplateDecl* CladClassDecl, TemplateArgumentListInfo& TLI) { // This will instantiate tape type and return it. - QualType TT = - m_Sema.CheckTemplateIdType(TemplateName(CladClassDecl), noLoc, TLI); + QualType TT = m_Sema.CheckTemplateIdType(TemplateName(CladClassDecl), + utils::GetValidSLoc(m_Sema), TLI); // Get clad namespace and its identifier clad::. CXXScopeSpec CSS; - CSS.Extend(m_Context, GetCladNamespace(), noLoc, noLoc); + CSS.Extend(m_Context, GetCladNamespace(), utils::GetValidSLoc(m_Sema), + utils::GetValidSLoc(m_Sema)); NestedNameSpecifier* NS = CSS.getScopeRep(); // Create elaborated type with namespace specifier, @@ -853,4 +854,16 @@ namespace clad { VisitorBase::GetCladConstructorPushforwardTagOfType(clang::QualType T) { return InstantiateTemplate(GetCladConstructorPushforwardTag(), {T}); } + + clang::TemplateDecl* VisitorBase::GetCladConstructorReverseForwTag() { + if (!m_CladConstructorPushforwardTag) + m_CladConstructorReverseForwTag = + LookupTemplateDeclInCladNamespace("ConstructorReverseForwTag"); + return m_CladConstructorReverseForwTag; + } + + clang::QualType + VisitorBase::GetCladConstructorReverseForwTagOfType(clang::QualType T) { + return InstantiateTemplate(GetCladConstructorReverseForwTag(), {T}); + } } // end namespace clad diff --git a/test/Gradient/Functors.C b/test/Gradient/Functors.C index e2116ce9d..47b633078 100644 --- a/test/Gradient/Functors.C +++ b/test/Gradient/Functors.C @@ -227,11 +227,15 @@ int main() { // CHECK-NEXT: Experiment E(3, 5); // CHECK-NEXT: Experiment _t0 = E; // CHECK-NEXT: { + // CHECK-NEXT: double _r2 = 0; + // CHECK-NEXT: double _r3 = 0; + // CHECK-NEXT: _t0.operator_call_pullback(i, j, 1, &_d_E, &_r2, &_r3); + // CHECK-NEXT: *_d_i += _r2; + // CHECK-NEXT: *_d_j += _r3; + // CHECK-NEXT: } + // CHECK-NEXT: { // CHECK-NEXT: double _r0 = 0; // CHECK-NEXT: double _r1 = 0; - // CHECK-NEXT: _t0.operator_call_pullback(i, j, 1, &_d_E, &_r0, &_r1); - // CHECK-NEXT: *_d_i += _r0; - // CHECK-NEXT: *_d_j += _r1; // CHECK-NEXT: } // CHECK-NEXT: } @@ -265,12 +269,16 @@ int main() { // CHECK-NEXT: Experiment _d_E({}); // CHECK-NEXT: Experiment E(3, 5); // CHECK-NEXT: { - // CHECK-NEXT: Experiment _r0 = {}; + // CHECK-NEXT: Experiment _r2 = {}; + // CHECK-NEXT: double _r3 = 0; + // CHECK-NEXT: double _r4 = 0; + // CHECK-NEXT: FunctorAsArg_pullback(E, i, j, 1, &_r2, &_r3, &_r4); + // CHECK-NEXT: *_d_i += _r3; + // CHECK-NEXT: *_d_j += _r4; + // CHECK-NEXT: } + // CHECK-NEXT: { + // CHECK-NEXT: double _r0 = 0; // CHECK-NEXT: double _r1 = 0; - // CHECK-NEXT: double _r2 = 0; - // CHECK-NEXT: FunctorAsArg_pullback(E, i, j, 1, &_r0, &_r1, &_r2); - // CHECK-NEXT: *_d_i += _r1; - // CHECK-NEXT: *_d_j += _r2; // CHECK-NEXT: } // CHECK-NEXT: } diff --git a/test/Gradient/MemberFunctions.C b/test/Gradient/MemberFunctions.C index d12446025..fda50ca9a 100644 --- a/test/Gradient/MemberFunctions.C +++ b/test/Gradient/MemberFunctions.C @@ -485,6 +485,63 @@ double fn4(SimpleFunctions& v) { // CHECK-NEXT: _t0.operator_plus_plus_pullback({}, &(*_d_v)); // CHECK-NEXT: } +class SafeTestClass { + public: + SafeTestClass() {}; + SafeTestClass(double &x) { + } + SafeTestClass(double x, double* y) { + *y = x; + } +}; + +namespace clad { +namespace custom_derivatives { +namespace class_functions { + clad::ValueAndAdjoint + constructor_reverse_forw(clad::ConstructorReverseForwTag, double x, double* y, double d_x, double* d_y) { + return {SafeTestClass(x, y), SafeTestClass(d_x, d_y)}; + } + clad::ValueAndAdjoint + constructor_reverse_forw(clad::ConstructorReverseForwTag, double &x, double &d_x) { + return {SafeTestClass(x), SafeTestClass(d_x)}; + } + clad::ValueAndAdjoint + constructor_reverse_forw(clad::ConstructorReverseForwTag) { + return {SafeTestClass(), SafeTestClass()}; + } + + void constructor_pullback(SafeTestClass *c, double x, double* y, SafeTestClass *d_c, double* d_x, double* d_y) { + *d_x += *d_y; + *d_y = 0; + } +}}} + +double fn6(double u, double v) { + double &w = u; + SafeTestClass s1; + SafeTestClass s2(u, &v); + SafeTestClass s3(w); + return v; +} + +// CHECK: void fn6_grad(double u, double v, double *_d_u, double *_d_v) { +// CHECK-NEXT: double &_d_w = *_d_u; +// CHECK-NEXT: double &w = u; +// CHECK-NEXT: clad::ValueAndAdjoint _t0 = {{.*}}constructor_reverse_forw(clad::ConstructorReverseForwTag()); +// CHECK-NEXT: SafeTestClass _d_s1(_t0.adjoint); +// CHECK-NEXT: SafeTestClass s1(_t0.value); +// CHECK-NEXT: clad::ValueAndAdjoint _t1 = {{.*}}constructor_reverse_forw(clad::ConstructorReverseForwTag(), u, &v, *_d_u, &*_d_v); +// CHECK-NEXT: SafeTestClass _d_s2(_t1.adjoint); +// CHECK-NEXT: SafeTestClass s2(_t1.value); +// CHECK-NEXT: clad::ValueAndAdjoint _t2 = {{.*}}constructor_reverse_forw(clad::ConstructorReverseForwTag(), w, _d_w); +// CHECK-NEXT: SafeTestClass _d_s3(_t2.adjoint); +// CHECK-NEXT: SafeTestClass s3(_t2.value); +// CHECK-NEXT: *_d_v += 1; +// CHECK-NEXT: {{.*}}constructor_pullback(&s2, u, &v, &_d_s2, &*_d_u, &*_d_v); +// CHECK-NEXT: } + + int main() { auto d_mem_fn = clad::gradient(&SimpleFunctions::mem_fn); auto d_const_mem_fn = clad::gradient(&SimpleFunctions::const_mem_fn); @@ -534,6 +591,12 @@ int main() { d_fn4.execute(sf3, &d_sf); printf("%.2f", d_sf.x); //CHECK-EXEC: 2.00 + double dx = 0, dy = 0; + auto d_fn6 = clad::gradient(fn6); + d_fn6.execute(3, 5, &dx, &dy); + printf("%.2f", dx); //CHECK-EXEC: 1.00 + printf("%.2f", dy); //CHECK-EXEC: 0.00 + auto d_const_volatile_lval_ref_mem_fn_i = clad::gradient(&SimpleFunctions::const_volatile_lval_ref_mem_fn, "i"); // CHECK: void const_volatile_lval_ref_mem_fn_grad_0(double i, double j, volatile SimpleFunctions *_d_this, double *_d_i) const volatile & { @@ -573,14 +636,15 @@ int main() { // CHECK-NEXT: SimpleFunctions _d_sf({}); // CHECK-NEXT: SimpleFunctions sf(x, y); // CHECK-NEXT: SimpleFunctions _t0 = sf; -// CHECK-NEXT: { -// CHECK-NEXT: double _r0 = 0; -// CHECK-NEXT: double _r1 = 0; -// CHECK-NEXT: _t0.mem_fn_pullback(i, j, 1, &_d_sf, &_r0, &_r1); -// CHECK-NEXT: *_d_i += _r0; -// CHECK-NEXT: *_d_j += _r1; +// CHECK-NEXT: { +// CHECK-NEXT: double _r0 = 0; +// CHECK-NEXT: double _r1 = 0; +// CHECK-NEXT: _t0.mem_fn_pullback(i, j, 1, &_d_sf, &_r0, &_r1); +// CHECK-NEXT: *_d_i += _r0; +// CHECK-NEXT: *_d_j += _r1; +// CHECK-NEXT: } // CHECK-NEXT: } -// CHECK-NEXT: } + // CHECK: void ref_mem_fn_pullback(double i, double _d_y, SimpleFunctions *_d_this, double *_d_i) { // CHECK-NEXT: double _t0 = this->x; diff --git a/test/Gradient/NonDifferentiable.C b/test/Gradient/NonDifferentiable.C index 230c9a2b1..2542034f9 100644 --- a/test/Gradient/NonDifferentiable.C +++ b/test/Gradient/NonDifferentiable.C @@ -130,14 +130,18 @@ int main() { // CHECK-NEXT: SimpleFunctions1 obj(2, 3); // CHECK-NEXT: SimpleFunctions1 _t0 = obj; // CHECK-NEXT: { - // CHECK-NEXT: double _r0 = 0; - // CHECK-NEXT: double _r1 = 0; - // CHECK-NEXT: _t0.mem_fn_1_pullback(i, j, 1, &_d_obj, &_r0, &_r1); - // CHECK-NEXT: *_d_i += _r0; - // CHECK-NEXT: *_d_j += _r1; + // CHECK-NEXT: double _r2 = 0; + // CHECK-NEXT: double _r3 = 0; + // CHECK-NEXT: _t0.mem_fn_1_pullback(i, j, 1, &_d_obj, &_r2, &_r3); + // CHECK-NEXT: *_d_i += _r2; + // CHECK-NEXT: *_d_j += _r3; // CHECK-NEXT: *_d_i += 1 * j; // CHECK-NEXT: *_d_j += i * 1; // CHECK-NEXT: } + // CHECK-NEXT: { + // CHECK-NEXT: double _r0 = 0; + // CHECK-NEXT: double _r1 = 0; + // CHECK-NEXT: } // CHECK-NEXT: } // CHECK: void fn_s1_field_grad(double i, double j, double *_d_i, double *_d_j) { @@ -148,6 +152,10 @@ int main() { // CHECK-NEXT: *_d_i += 1 * j; // CHECK-NEXT: *_d_j += i * 1; // CHECK-NEXT: } + // CHECK-NEXT: { + // CHECK-NEXT: double _r0 = 0; + // CHECK-NEXT: double _r1 = 0; + // CHECK-NEXT: } // CHECK-NEXT: } // CHECK: void fn_s1_field_pointer_grad(double i, double j, double *_d_i, double *_d_j) { @@ -158,6 +166,10 @@ int main() { // CHECK-NEXT: *_d_i += 1 * j; // CHECK-NEXT: *_d_j += i * 1; // CHECK-NEXT: } + // CHECK-NEXT: { + // CHECK-NEXT: double _r0 = 0; + // CHECK-NEXT: double _r1 = 0; + // CHECK-NEXT: } // CHECK-NEXT: } // CHECK: void fn_s2_mem_fn_grad(double i, double j, double *_d_i, double *_d_j) { diff --git a/test/Gradient/PointersWithTBR.C b/test/Gradient/PointersWithTBR.C index a86f9cfb2..80cb20c4a 100644 --- a/test/Gradient/PointersWithTBR.C +++ b/test/Gradient/PointersWithTBR.C @@ -36,5 +36,5 @@ int main() { double arr[5] = {1, 2, 3, 4, 5}; double d_arr[5] = {0, 0, 0, 0, 0}; d_pointerParam.execute(arr, 5, d_arr); - printf("%.2f %.2f %.2f %.2f %.2f\n", d_arr[0], d_arr[1], d_arr[2], d_arr[3], d_arr[4]); // CHECK-EXEC: 0.00 1.00 2.00 3.00 4.00 + printf("%.2f %.2f %.2f %.2f %.2f\n", d_arr[0], d_arr[1], d_arr[2], d_arr[3], d_arr[4]); // CHECK-EXEC: 0.00 2.00 6.00 12.00 20.00 } diff --git a/test/Gradient/STLCustomDerivatives.C b/test/Gradient/STLCustomDerivatives.C index 3f01775dd..03886c7d8 100644 --- a/test/Gradient/STLCustomDerivatives.C +++ b/test/Gradient/STLCustomDerivatives.C @@ -95,15 +95,25 @@ double fn12(double u, double v) { return res; } +double fn13(double u, double v) { + double res = u; + std::vector::allocator_type allocator; + typename ::std::vector::size_type count = 3; + std::vector vec(count, u, allocator); + return vec[0] + vec[1] + vec[2]; +} + int main() { double d_i, d_j; INIT_GRADIENT(fn10); INIT_GRADIENT(fn11); INIT_GRADIENT(fn12); + INIT_GRADIENT(fn13); TEST_GRADIENT(fn10, /*numOfDerivativeArgs=*/2, 3, 5, &d_i, &d_j); // CHECK-EXEC: {1.00, 1.00} TEST_GRADIENT(fn11, /*numOfDerivativeArgs=*/2, 3, 5, &d_i, &d_j); // CHECK-EXEC: {2.00, 1.00} TEST_GRADIENT(fn12, /*numOfDerivativeArgs=*/2, 3, 5, &d_i, &d_j); // CHECK-EXEC: {4.00, 2.00} + TEST_GRADIENT(fn13, /*numOfDerivativeArgs=*/2, 3, 5, &d_i, &d_j); // CHECK-EXEC: {3.00, 0.00} } // CHECK: void fn10_grad(double u, double v, double *_d_u, double *_d_v) { @@ -342,4 +352,32 @@ int main() { // CHECK-NEXT: {{.*}} _r0 = 0; // CHECK-NEXT: {{.*}}class_functions::resize_pullback(&_t0, 3, &_d_vec, &_r0); // CHECK-NEXT: } -// CHECK-NEXT: } \ No newline at end of file +// CHECK-NEXT: } + +// CHECK-NEXT: void fn13_grad(double u, double v, double *_d_u, double *_d_v) { +// CHECK-NEXT: double _d_res = 0; +// CHECK-NEXT: double res = u; +// CHECK-NEXT: {{.*}}allocator_type _d_allocator({}); +// CHECK-NEXT: {{.*}}allocator_type allocator; +// CHECK-NEXT: {{.*}} _d_count = 0; +// CHECK-NEXT: {{.*}} count = 3; +// CHECK-NEXT: {{.*}}ValueAndAdjoint<{{.*}}vector<{{.*}}>, {{.*}}vector<{{.*}}> > _t0 = {{.*}}class_functions::constructor_reverse_forw(clad::ConstructorReverseForwTag >(), count, u, allocator, _d_count, *_d_u, _d_allocator); +// CHECK-NEXT: std::vector _d_vec(_t0.adjoint); +// CHECK-NEXT: std::vector vec(_t0.value); +// CHECK-NEXT: std::vector _t1 = vec; +// CHECK-NEXT: {{.*}}ValueAndAdjoint _t2 = {{.*}}class_functions::operator_subscript_reverse_forw(&vec, 0, &_d_vec, _r0); +// CHECK-NEXT: std::vector _t3 = vec; +// CHECK-NEXT: {{.*}}ValueAndAdjoint _t4 = {{.*}}class_functions::operator_subscript_reverse_forw(&vec, 1, &_d_vec, _r1); +// CHECK-NEXT: std::vector _t5 = vec; +// CHECK-NEXT: {{.*}}ValueAndAdjoint _t6 = {{.*}}class_functions::operator_subscript_reverse_forw(&vec, 2, &_d_vec, _r2); +// CHECK-NEXT: { +// CHECK-NEXT: {{.*}} _r0 = 0; +// CHECK-NEXT: {{.*}}operator_subscript_pullback(&_t1, 0, 1, &_d_vec, &_r0); +// CHECK-NEXT: {{.*}} _r1 = 0; +// CHECK-NEXT: {{.*}}operator_subscript_pullback(&_t3, 1, 1, &_d_vec, &_r1); +// CHECK-NEXT: {{.*}} _r2 = 0; +// CHECK-NEXT: {{.*}}operator_subscript_pullback(&_t5, 2, 1, &_d_vec, &_r2); +// CHECK-NEXT: } +// CHECK-NEXT: {{.*}}constructor_pullback(&vec, count, u, allocator, &_d_vec, &_d_count, &*_d_u, &_d_allocator); +// CHECK-NEXT: *_d_u += _d_res; +// CHECK-NEXT: } diff --git a/test/Gradient/UserDefinedTypes.C b/test/Gradient/UserDefinedTypes.C index ee8d6e62a..5c620ba21 100644 --- a/test/Gradient/UserDefinedTypes.C +++ b/test/Gradient/UserDefinedTypes.C @@ -145,6 +145,15 @@ double fn4(double i, double j) { // CHECK-NEXT: _d_q.second += 1 * j; // CHECK-NEXT: *_d_j += q.second * 1; // CHECK-NEXT: } +// CHECK-NEXT: { +// CHECK-NEXT: {{.*}} _r2 = {}; +// CHECK-NEXT: int _r3 = 0; +// CHECK-NEXT: int _r4 = 0; +// CHECK-NEXT: } +// CHECK-NEXT: { +// CHECK-NEXT: int _r0 = 0; +// CHECK-NEXT: int _r1 = 0; +// CHECK-NEXT: } // CHECK-NEXT: } // CHECK: void someMemFn_grad(double i, double j, Tangent *_d_this, double *_d_i, double *_d_j) { diff --git a/test/Hessian/BuiltinDerivatives.C b/test/Hessian/BuiltinDerivatives.C index 416b7da26..8cb6ab2e0 100644 --- a/test/Hessian/BuiltinDerivatives.C +++ b/test/Hessian/BuiltinDerivatives.C @@ -197,18 +197,22 @@ int main() { // CHECK-NEXT: _d__t1.pushforward += 1; // CHECK-NEXT: } // CHECK-NEXT: { -// CHECK-NEXT: float _r2 = 0; -// CHECK-NEXT: float _r3 = 0; -// CHECK-NEXT: cos_pushforward_pullback(x, _d_x0, _d__t1, &_r2, &_r3); -// CHECK-NEXT: *_d_x += _r2; -// CHECK-NEXT: _d__d_x += _r3; +// CHECK-NEXT: {{.*}}ValueAndPushforward _r3 = {}; +// CHECK-NEXT: clad::custom_derivatives::class_functions::constructor_pullback(&_t10, {{.*}}cos_pushforward(x, _d_x0), &_d__t1, &_r3); +// CHECK-NEXT: float _r4 = 0; +// CHECK-NEXT: float _r5 = 0; +// CHECK-NEXT: cos_pushforward_pullback(x, _d_x0, _r3, &_r4, &_r5); +// CHECK-NEXT: *_d_x += _r4; +// CHECK-NEXT: _d__d_x += _r5; // CHECK-NEXT: } // CHECK-NEXT: { -// CHECK-NEXT: float _r0 = 0; +// CHECK-NEXT: {{.*}}ValueAndPushforward _r0 = {}; +// CHECK-NEXT: clad::custom_derivatives::class_functions::constructor_pullback(&_t00, {{.*}}sin_pushforward(x, _d_x0), &_d__t0, &_r0); // CHECK-NEXT: float _r1 = 0; -// CHECK-NEXT: sin_pushforward_pullback(x, _d_x0, _d__t0, &_r0, &_r1); -// CHECK-NEXT: *_d_x += _r0; -// CHECK-NEXT: _d__d_x += _r1; +// CHECK-NEXT: float _r2 = 0; +// CHECK-NEXT: sin_pushforward_pullback(x, _d_x0, _r0, &_r1, &_r2); +// CHECK-NEXT: *_d_x += _r1; +// CHECK-NEXT: _d__d_x += _r2; // CHECK-NEXT: } // CHECK-NEXT: } @@ -227,11 +231,13 @@ int main() { // CHECK-NEXT: ValueAndPushforward _t00 = clad::custom_derivatives{{(::std)?}}::exp_pushforward(x, _d_x0); // CHECK-NEXT: _d__t0.pushforward += 1; // CHECK-NEXT: { -// CHECK-NEXT: float _r0 = 0; +// CHECK-NEXT: {{.*}}ValueAndPushforward _r0 = {}; +// CHECK-NEXT: {{.*}}constructor_pullback(&_t00, {{.*}}exp_pushforward(x, _d_x0), &_d__t0, &_r0); // CHECK-NEXT: float _r1 = 0; -// CHECK-NEXT: exp_pushforward_pullback(x, _d_x0, _d__t0, &_r0, &_r1); -// CHECK-NEXT: *_d_x += _r0; -// CHECK-NEXT: _d__d_x += _r1; +// CHECK-NEXT: float _r2 = 0; +// CHECK-NEXT: exp_pushforward_pullback(x, _d_x0, _r0, &_r1, &_r2); +// CHECK-NEXT: *_d_x += _r1; +// CHECK-NEXT: _d__d_x += _r2; // CHECK-NEXT: } // CHECK-NEXT: } @@ -250,11 +256,13 @@ int main() { // CHECK-NEXT: ValueAndPushforward _t00 = clad::custom_derivatives{{(::std)?}}::log_pushforward(x, _d_x0); // CHECK-NEXT: _d__t0.pushforward += 1; // CHECK-NEXT: { -// CHECK-NEXT: float _r0 = 0; +// CHECK-NEXT: {{.*}}ValueAndPushforward _r0 = {}; +// CHECK-NEXT: {{.*}}constructor_pullback(&_t00, {{.*}}log_pushforward(x, _d_x0), &_d__t0, &_r0); // CHECK-NEXT: float _r1 = 0; -// CHECK-NEXT: log_pushforward_pullback(x, _d_x0, _d__t0, &_r0, &_r1); -// CHECK-NEXT: *_d_x += _r0; -// CHECK-NEXT: _d__d_x += _r1; +// CHECK-NEXT: float _r2 = 0; +// CHECK-NEXT: log_pushforward_pullback(x, _d_x0, _r0, &_r1, &_r2); +// CHECK-NEXT: *_d_x += _r1; +// CHECK-NEXT: _d__d_x += _r2; // CHECK-NEXT: } // CHECK-NEXT: } @@ -273,13 +281,15 @@ int main() { // CHECK-NEXT: ValueAndPushforward _t00 = clad::custom_derivatives{{(::std)?}}::pow_pushforward(x, 4.F, _d_x0, 0.F); // CHECK-NEXT: _d__t0.pushforward += 1; // CHECK-NEXT: { -// CHECK-NEXT: float _r0 = 0; +// CHECK-NEXT: {{.*}} _r0 = {}; +// CHECK-NEXT: {{.*}}constructor_pullback(&_t00, {{.*}}pow_pushforward(x, 4.F, _d_x0, 0.F), &_d__t0, &_r0); // CHECK-NEXT: float _r1 = 0; // CHECK-NEXT: float _r2 = 0; // CHECK-NEXT: float _r3 = 0; -// CHECK-NEXT: pow_pushforward_pullback(x, 4.F, _d_x0, 0.F, _d__t0, &_r0, &_r1, &_r2, &_r3); -// CHECK-NEXT: *_d_x += _r0; -// CHECK-NEXT: _d__d_x += _r2; +// CHECK-NEXT: float _r4 = 0; +// CHECK-NEXT: pow_pushforward_pullback(x, 4.F, _d_x0, 0.F, _r0, &_r1, &_r2, &_r3, &_r4); +// CHECK-NEXT: *_d_x += _r1; +// CHECK-NEXT: _d__d_x += _r3; // CHECK-NEXT: } // CHECK-NEXT: } @@ -296,13 +306,15 @@ int main() { // CHECK-NEXT: ValueAndPushforward _t00 = clad::custom_derivatives{{(::std)?}}::pow_pushforward(2.F, x, 0.F, _d_x0); // CHECK-NEXT: _d__t0.pushforward += 1; // CHECK-NEXT: { -// CHECK-NEXT: float _r0 = 0; +// CHECK-NEXT: {{.*}} _r0 = {}; +// CHECK-NEXT: {{.*}}constructor_pullback(&_t00, {{.*}}pow_pushforward(2.F, x, 0.F, _d_x0), &_d__t0, &_r0); // CHECK-NEXT: float _r1 = 0; // CHECK-NEXT: float _r2 = 0; // CHECK-NEXT: float _r3 = 0; -// CHECK-NEXT: pow_pushforward_pullback(2.F, x, 0.F, _d_x0, _d__t0, &_r0, &_r1, &_r2, &_r3); -// CHECK-NEXT: *_d_x += _r1; -// CHECK-NEXT: _d__d_x += _r3; +// CHECK-NEXT: float _r4 = 0; +// CHECK-NEXT: {{.*}}pow_pushforward_pullback(2.F, x, 0.F, _d_x0, _r0, &_r1, &_r2, &_r3, &_r4); +// CHECK-NEXT: *_d_x += _r2; +// CHECK-NEXT: _d__d_x += _r4; // CHECK-NEXT: } // CHECK-NEXT: } @@ -322,15 +334,17 @@ int main() { // CHECK-NEXT: ValueAndPushforward _t00 = clad::custom_derivatives{{(::std)?}}::pow_pushforward(x, y, _d_x0, _d_y0); // CHECK-NEXT: _d__t0.pushforward += 1; // CHECK-NEXT: { -// CHECK-NEXT: float _r0 = 0; +// CHECK-NEXT: {{.*}} _r0 = {}; +// CHECK-NEXT: {{.*}}constructor_pullback(&_t00, {{.*}}pow_pushforward(x, y, _d_x0, _d_y0), &_d__t0, &_r0); // CHECK-NEXT: float _r1 = 0; // CHECK-NEXT: float _r2 = 0; // CHECK-NEXT: float _r3 = 0; -// CHECK-NEXT: pow_pushforward_pullback(x, y, _d_x0, _d_y0, _d__t0, &_r0, &_r1, &_r2, &_r3); -// CHECK-NEXT: *_d_x += _r0; -// CHECK-NEXT: *_d_y += _r1; -// CHECK-NEXT: _d__d_x += _r2; -// CHECK-NEXT: _d__d_y += _r3; +// CHECK-NEXT: float _r4 = 0; +// CHECK-NEXT: {{.*}}pow_pushforward_pullback(x, y, _d_x0, _d_y0, _r0, &_r1, &_r2, &_r3, &_r4); +// CHECK-NEXT: *_d_x += _r1; +// CHECK-NEXT: *_d_y += _r2; +// CHECK-NEXT: _d__d_x += _r3; +// CHECK-NEXT: _d__d_y += _r4; // CHECK-NEXT: } // CHECK-NEXT: } @@ -350,15 +364,17 @@ int main() { // CHECK-NEXT: ValueAndPushforward _t00 = clad::custom_derivatives{{(::std)?}}::pow_pushforward(x, y, _d_x0, _d_y0); // CHECK-NEXT: _d__t0.pushforward += 1; // CHECK-NEXT: { -// CHECK-NEXT: float _r0 = 0; +// CHECK-NEXT: {{.*}} _r0 = {}; +// CHECK-NEXT: {{.*}}constructor_pullback(&_t00, {{.*}}pow_pushforward(x, y, _d_x0, _d_y0), &_d__t0, &_r0); // CHECK-NEXT: float _r1 = 0; // CHECK-NEXT: float _r2 = 0; // CHECK-NEXT: float _r3 = 0; -// CHECK-NEXT: pow_pushforward_pullback(x, y, _d_x0, _d_y0, _d__t0, &_r0, &_r1, &_r2, &_r3); -// CHECK-NEXT: *_d_x += _r0; -// CHECK-NEXT: *_d_y += _r1; -// CHECK-NEXT: _d__d_x += _r2; -// CHECK-NEXT: _d__d_y += _r3; +// CHECK-NEXT: float _r4 = 0; +// CHECK-NEXT: {{.*}}pow_pushforward_pullback(x, y, _d_x0, _d_y0, _r0, &_r1, &_r2, &_r3, &_r4); +// CHECK-NEXT: *_d_x += _r1; +// CHECK-NEXT: *_d_y += _r2; +// CHECK-NEXT: _d__d_x += _r3; +// CHECK-NEXT: _d__d_y += _r4; // CHECK-NEXT: } // CHECK-NEXT: } diff --git a/test/Hessian/NestedFunctionCalls.C b/test/Hessian/NestedFunctionCalls.C index afc737fc9..fe61e33e2 100644 --- a/test/Hessian/NestedFunctionCalls.C +++ b/test/Hessian/NestedFunctionCalls.C @@ -55,15 +55,17 @@ double f2(double x, double y){ // CHECK-NEXT: _d__t0.value += _d_ans0; // CHECK-NEXT: _d__t0.pushforward += _d__d_ans; // CHECK-NEXT: { -// CHECK-NEXT: double _r0 = 0; +// CHECK-NEXT: {{.*}}ValueAndPushforward _r0 = {}; +// CHECK-NEXT: {{.*}}constructor_pullback(&_t00, f_pushforward(x, y, _d_x0, _d_y0), &_d__t0, &_r0); // CHECK-NEXT: double _r1 = 0; // CHECK-NEXT: double _r2 = 0; // CHECK-NEXT: double _r3 = 0; -// CHECK-NEXT: f_pushforward_pullback(x, y, _d_x0, _d_y0, _d__t0, &_r0, &_r1, &_r2, &_r3); -// CHECK-NEXT: *_d_x += _r0; -// CHECK-NEXT: *_d_y += _r1; -// CHECK-NEXT: _d__d_x += _r2; -// CHECK-NEXT: _d__d_y += _r3; +// CHECK-NEXT: double _r4 = 0; +// CHECK-NEXT: f_pushforward_pullback(x, y, _d_x0, _d_y0, _r0, &_r1, &_r2, &_r3, &_r4); +// CHECK-NEXT: *_d_x += _r1; +// CHECK-NEXT: *_d_y += _r2; +// CHECK-NEXT: _d__d_x += _r3; +// CHECK-NEXT: _d__d_y += _r4; // CHECK-NEXT: } // CHECK-NEXT: } @@ -91,15 +93,17 @@ double f2(double x, double y){ // CHECK-NEXT: _d__t0.value += _d_ans0; // CHECK-NEXT: _d__t0.pushforward += _d__d_ans; // CHECK-NEXT: { -// CHECK-NEXT: double _r0 = 0; +// CHECK-NEXT: {{.*}}ValueAndPushforward _r0 = {}; +// CHECK-NEXT: {{.*}}constructor_pullback(&_t00, f_pushforward(x, y, _d_x0, _d_y0), &_d__t0, &_r0); // CHECK-NEXT: double _r1 = 0; // CHECK-NEXT: double _r2 = 0; // CHECK-NEXT: double _r3 = 0; -// CHECK-NEXT: f_pushforward_pullback(x, y, _d_x0, _d_y0, _d__t0, &_r0, &_r1, &_r2, &_r3); -// CHECK-NEXT: *_d_x += _r0; -// CHECK-NEXT: *_d_y += _r1; -// CHECK-NEXT: _d__d_x += _r2; -// CHECK-NEXT: _d__d_y += _r3; +// CHECK-NEXT: double _r4 = 0; +// CHECK-NEXT: f_pushforward_pullback(x, y, _d_x0, _d_y0, _r0, &_r1, &_r2, &_r3, &_r4); +// CHECK-NEXT: *_d_x += _r1; +// CHECK-NEXT: *_d_y += _r2; +// CHECK-NEXT: _d__d_x += _r3; +// CHECK-NEXT: _d__d_y += _r4; // CHECK-NEXT: } // CHECK-NEXT: } diff --git a/unittests/Misc/CMakeLists.txt b/unittests/Misc/CMakeLists.txt index 07fb60885..02388cce8 100644 --- a/unittests/Misc/CMakeLists.txt +++ b/unittests/Misc/CMakeLists.txt @@ -7,6 +7,6 @@ add_clad_unittest(MiscTests # Create a library from the Defs.cpp file ADD_CLAD_LIBRARY(Defs Defs.cpp) - # Link the library to the test target_link_libraries(MiscTests PRIVATE Defs) +set_property(TARGET MiscTests PROPERTY CXX_STANDARD 11)