Skip to content

Commit

Permalink
Add basic Kokkos support for the original tests of vgvassilev#783
Browse files Browse the repository at this point in the history
This commit adds a test from the original Kokkos PR vgvassilev#783
and provides the implementation of the simplest Kokkos
features in the form of custom pushforwards. This commit
only addresses the forward mode.
  • Loading branch information
gojakuch committed Jul 13, 2024
1 parent ef668c7 commit e0d814e
Show file tree
Hide file tree
Showing 5 changed files with 177 additions and 25 deletions.
74 changes: 74 additions & 0 deletions include/clad/Differentiator/KokkosBuiltins.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// This header file contains the implementation of the Kokkos framework
// differentiation support in Clad in the form of custom pushforwards and
// pullbacks. Please include it manually to use Clad on Kokkos code.

#ifndef CLAD_KOKKOS_BUILTINS_H
#define CLAD_KOKKOS_BUILTINS_H

#include <Kokkos_Core.hpp>
#include "clad/Differentiator/Differentiator.h"

namespace clad {
namespace custom_derivatives {
namespace class_functions {
/// Kokkos arrays
template <typename ArrayT, typename Space>
clad::ValueAndPushforward<Kokkos::View<ArrayT, Space>,
Kokkos::View<ArrayT, Space>>
constructor_pushforward(
clad::ConstructorPushforwardTag<Kokkos::View<ArrayT, Space>>,
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) {
return {Kokkos::View<ArrayT, Space>(name, idx0, idx1, idx2, idx3, idx4, idx5,
idx6, idx7),
Kokkos::View<ArrayT, Space>("_diff_" + name, idx0, idx1, idx2, idx3,
idx4, idx5, idx6, idx7)};
};

template <typename ArrayT, typename Layout, typename Space>
clad::ValueAndPushforward<Kokkos::View<ArrayT, Layout, Space>,
Kokkos::View<ArrayT, Layout, Space>>
constructor_pushforward(
clad::ConstructorPushforwardTag<Kokkos::View<ArrayT, Layout, Space>>,
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) {
return {Kokkos::View<ArrayT, Layout, Space>(name, idx0, idx1, idx2, idx3,
idx4, idx5, idx6, idx7),
Kokkos::View<ArrayT, Layout, Space>("_diff_" + name, idx0, idx1, idx2,
idx3, idx4, idx5, idx6, idx7)};
}
} // namespace class_functions

/// Kokkos functions
namespace Kokkos {
template <typename View1, typename View2, typename T>
inline void deep_copy_pushforward(const View1& dst, const View2& src, T param,
const View1& _d_dst, const View2& _d_src,
T _d_param) {
deep_copy(dst, src);
deep_copy(_d_dst, _d_src);
}

template <class ExecPolicy, class FunctorType>
inline void parallel_for_pushforward(const ::std::string& str,
const ExecPolicy& policy,
const FunctorType& functor,
const ::std::string& _d_str,
const ExecPolicy& _d_policy,
const FunctorType& _d_functor) {
// TODO: implement parallel_for_pushforward
return;
}
} // namespace Kokkos
} // namespace custom_derivatives
} // namespace clad

#endif // #ifndef CLAD_KOKKOS_BUILTINS_H
1 change: 1 addition & 0 deletions unittests/Kokkos/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
add_clad_unittest(KokkosTests
main.cpp
ViewAccess.cpp
ViewBasics.cpp
ParallelReduce.cpp
ParallelFor.cpp
Expand Down
11 changes: 6 additions & 5 deletions unittests/Kokkos/TestUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
#ifndef KOKKOS_UNITTEST_UTILS
#define KOKKOS_UNITTEST_UTILS

template <typename T> // comparison with the finite difference approx. has been
// tested in the initial PR for Kokkos-aware Clad by Kim
// Liegeois
T finite_difference_tangent(std::function<T(T)> func, const T& x,
const T& epsilon) {
template <typename F, typename T> // comparison with the finite difference
// approx. has been tested in the initial PR
// for Kokkos-aware Clad by Kim Liegeois
T
finite_difference_tangent(F func, const T& x,
const T& epsilon) {
return (func(x + epsilon) - func(x - epsilon)) / (2 * epsilon);
}

Expand Down
76 changes: 76 additions & 0 deletions unittests/Kokkos/ViewAccess.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Source:
// https://github.com/vgvassilev/clad/pull/783/files#diff-c919937640674e1911d1f17d3df2b65426d152400589873ff9ba2f0391048d78
// Source: https://github.com/kliegeois/clad/tree/kokkos-PR
// Originally created by Kim Liegeois

#include "TestUtils.h"
#include <Kokkos_Core.hpp>
#include "clad/Differentiator/Differentiator.h"
#include "clad/Differentiator/KokkosBuiltins.h"
#include "gtest/gtest.h"

double f(double x, double y) {

const int N1 = 4;

Kokkos::View<double* [4], Kokkos::LayoutLeft, Kokkos::HostSpace> a("a", N1);
Kokkos::View<double* [4], Kokkos::LayoutLeft, Kokkos::HostSpace> b("b", N1);

a(0, 0) = x;
b(0, 0) = y;

b(0, 0) += a(0, 0) * b(0, 0);

return a(0, 0) * a(0, 0) * b(0, 0) + b(0, 0);
}

double f_2(double x, double y) {

const int N1 = 4;

Kokkos::View<double* [4], Kokkos::LayoutLeft, Kokkos::HostSpace> a("a", N1);
Kokkos::View<double* [4], Kokkos::LayoutLeft, Kokkos::HostSpace> b("b", N1);

Kokkos::deep_copy(a, 3 * x + y);
b(0, 0) = x;
Kokkos::deep_copy(b, a);

b(0, 0) += a(0, 0) * b(0, 0);

return a(0, 0);
}

TEST(ViewAccess, Test1) {
EXPECT_NEAR(f(0, 1), 1, 1e-8);
EXPECT_NEAR(f(0, 2), 2, 1e-8);
}

TEST(ViewAccess, Test2) {

double tolerance = 1e-8;
double epsilon = 1e-6;

auto f_x = clad::differentiate(f, "x");

std::function<double(double)> f_tmp = [](double x) { return f(x, 4.); };
double dx_f_FD = finite_difference_tangent(f_tmp, 3., epsilon);

EXPECT_NEAR(f_x.execute(3, 4), dx_f_FD, tolerance * dx_f_FD);

auto f_2_x = clad::differentiate(f_2, "x");

std::function<double(double)> f_2_tmp = [](double x) { return f_2(x, 4.); };
double dx_f_2_FD = finite_difference_tangent(f_2_tmp, 3., epsilon);
EXPECT_NEAR(f_2_x.execute(3, 4), dx_f_2_FD, tolerance * dx_f_2_FD);

// TODO: uncomment this once it has been implemented
// auto f_grad_exe = clad::gradient(f);
// double dx, dy;
// f_grad_exe.execute(3., 4., &dx, &dy);
// EXPECT_NEAR(f_x.execute(3, 4),dx,tolerance*dx);

// double dx_2, dy_2;
// auto f_2_grad_exe = clad::gradient(f_2);
// f_2_grad_exe.execute(3., 4., &dx_2, &dy_2);
// EXPECT_NEAR(f_2_x.execute(3, 4),dx_2,tolerance*dx_2);
}
40 changes: 20 additions & 20 deletions unittests/Kokkos/ViewBasics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
// it has been modified to match gtest guidelines and improve readability

#include "ParallelAdd.h"
#include "TestUtils.h"
// #include "TestUtils.h"
#include <Kokkos_Core.hpp>
#include "clad/Differentiator/Differentiator.h"
#include "gtest/gtest.h"

double f(double x, double y) {
double ff(double x, double y) {
const int N = 2;

Kokkos::View<double* [N], Kokkos::HostSpace> a("a", N);
Expand All @@ -27,9 +27,9 @@ TEST(ViewBasics, TestAccessForward) {
// const double tau = 1e-6; // tolerance

// // TODO: uncomment this once it has been implemented
// auto f_x = clad::differentiate(f, "x");
// auto f_x = clad::differentiate(ff, "x");
// for (double y = 3; y <= 5; y += 1) {
// std::function<double(double)> f_tmp = [y](double t){ return f(t, y); };
// std::function<double(double)> f_tmp = [y](double t){ return ff(t, y); };
// for (double x = 3; x <= 5; x += 1) {
// double f_x_ex = f_x.execute(x, y);
// double dx_f_FD = finite_difference_tangent(f_tmp, x, eps);
Expand All @@ -44,9 +44,9 @@ TEST(ViewBasics, TestAccessReverse) {
// const double tau = 1e-6; // tolerance

// // TODO: uncomment this once it has been implemented
// auto f_grad_exe = clad::gradient(f);
// auto f_grad_exe = clad::gradient(ff);
// for (double y = 3; y <= 5; y += 1) {
// std::function<double(double)> f_tmp = [y](double t){ return f(t, y); };
// std::function<double(double)> f_tmp = [y](double t){ return ff(t, y); };
// for (double x = 3; x <= 5; x += 1) {
// double dx_f_FD = finite_difference_tangent(f_tmp, x, eps);
// double dx, dy;
Expand All @@ -56,7 +56,7 @@ TEST(ViewBasics, TestAccessReverse) {
// }
}

double f_2(double x, double y) {
double ff_2(double x, double y) {
const int N = 2;

Kokkos::View<double* [4], Kokkos::LayoutLeft, Kokkos::HostSpace> a("a", N);
Expand All @@ -77,10 +77,10 @@ TEST(ViewBasics, TestDeepCopyForward) {
// const double tau = 1e-6; // tolerance

// // TODO: uncomment this once it has been implemented
// auto f_x = clad::differentiate(f_2, "x");
// auto f_x = clad::differentiate(ff_2, "x");
// for (double y = 3; y <= 5; y += 1) {
// std::function<double(double)> f_tmp = [y](double t){ return f_2(t, y); };
// for (double x = 3; x <= 5; x += 1) {
// std::function<double(double)> f_tmp = [y](double t){ return ff_2(t, y);
// }; for (double x = 3; x <= 5; x += 1) {
// double f_x_ex = f_x.execute(x, y);
// double dx_f_FD = finite_difference_tangent(f_tmp, x, eps);
// EXPECT_NEAR(f_x_ex, dx_f_FD, abs(tau*dx_f_FD));
Expand All @@ -94,10 +94,10 @@ TEST(ViewBasics, TestDeepCopyReverse) {
// const double tau = 1e-6; // tolerance

// // TODO: uncomment this once it has been implemented
// auto f_grad_exe = clad::gradient(f_2);
// auto f_grad_exe = clad::gradient(ff_2);
// for (double y = 3; y <= 5; y += 1) {
// std::function<double(double)> f_tmp = [y](double t){ return f_2(t, y); };
// for (double x = 3; x <= 5; x += 1) {
// std::function<double(double)> f_tmp = [y](double t){ return ff_2(t, y);
// }; for (double x = 3; x <= 5; x += 1) {
// double dx_f_FD = finite_difference_tangent(f_tmp, x, eps);
// double dx, dy;
// f_grad_exe.execute(x, y, &dx, &dy);
Expand All @@ -106,7 +106,7 @@ TEST(ViewBasics, TestDeepCopyReverse) {
// }
}

double f_3(double x, double y) {
double ff_3(double x, double y) {
const int N = 2;

Kokkos::View<double*, Kokkos::LayoutLeft, Kokkos::HostSpace> a("a", N);
Expand All @@ -130,10 +130,10 @@ TEST(ViewBasics, TestDeepCopy2Forward) {
// const double tau = 1e-6; // tolerance

// // TODO: uncomment this once it has been implemented
// auto f_y = clad::differentiate(f_3, "y");
// auto f_y = clad::differentiate(ff_3, "y");
// for (double x = 3; x <= 5; x += 1) {
// std::function<double(double)> f_tmp = [x](double t){ return f_3(x, t); };
// for (double y = 3; y <= 5; y += 1) {
// std::function<double(double)> f_tmp = [x](double t){ return ff_3(x, t);
// }; for (double y = 3; y <= 5; y += 1) {
// double f_y_ex = f_y.execute(x, y);
// double dy_f_FD = finite_difference_tangent(f_tmp, y, eps);
// EXPECT_NEAR(f_y_ex, dy_f_FD, abs(tau*dy_f_FD));
Expand All @@ -147,10 +147,10 @@ TEST(ViewBasics, TestDeepCopy2Reverse) {
// const double tau = 1e-6; // tolerance

// // TODO: uncomment this once it has been implemented
// auto f_grad_exe = clad::gradient(f_3);
// auto f_grad_exe = clad::gradient(ff_3);
// for (double x = 3; x <= 5; x += 1) {
// std::function<double(double)> f_tmp = [x](double t){ return f_3(x, t); };
// for (double y = 3; y <= 5; y += 1) {
// std::function<double(double)> f_tmp = [x](double t){ return ff_3(x, t);
// }; for (double y = 3; y <= 5; y += 1) {
// double dy_f_FD = finite_difference_tangent(f_tmp, y, eps);
// double dx, dy;
// f_grad_exe.execute(x, y, &dx, &dy);
Expand Down

0 comments on commit e0d814e

Please sign in to comment.