Skip to content

Commit

Permalink
Remove special handling of non-copied arrays and use array_ref
Browse files Browse the repository at this point in the history
  • Loading branch information
vaithak committed Aug 2, 2023
1 parent 4ea339f commit c8e7b4e
Show file tree
Hide file tree
Showing 5 changed files with 188 additions and 124 deletions.
32 changes: 10 additions & 22 deletions include/clad/Differentiator/Array.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ template <typename T> class array {
T* m_arr = nullptr;
/// The size of the array
std::size_t m_size = 0;
// Boolean to indicate if the array is owned by this class or not.
bool m_owned = true;

public:
/// Delete default constructor
Expand All @@ -36,21 +34,11 @@ template <typename T> class array {
(*this) = arr;
}

// use this only if U and T are not the same type.
template <typename U, typename = typename std::enable_if<
!std::is_same<T, U>::value>::type>
template <typename U>
CUDA_HOST_DEVICE array(U* a, std::size_t size)
: m_arr(new T[size]{static_cast<T>(T())}), m_size(size) {
for (std::size_t i = 0; i < size; ++i)
m_arr[i] = a[i];
}

CUDA_HOST_DEVICE array(T* a, std::size_t size, bool copy = true)
: m_arr(copy ? new T[size]{static_cast<T>(T())} : a), m_size(size),
m_owned(copy) {
if (copy)
for (std::size_t i = 0; i < size; ++i)
m_arr[i] = a[i];
m_arr[i] = static_cast<T>(a[i]);
}

CUDA_HOST_DEVICE array(const array<T>& arr) : array(arr.m_arr, arr.m_size) {}
Expand All @@ -64,7 +52,10 @@ template <typename T> class array {
// initializing all entries using the same value
template <typename U>
CUDA_HOST_DEVICE array(std::size_t size, U val)
: m_arr(new T[size]{static_cast<T>(val)}), m_size(size) {}
: m_arr(new T[size]{static_cast<T>(T())}), m_size(size) {
for (std::size_t i = 0; i < size; ++i)
m_arr[i] = static_cast<T>(val);
}

CUDA_HOST_DEVICE array(std::initializer_list<T> arr)
: m_arr(new T[arr.size()]{static_cast<T>(T())}), m_size(arr.size()) {
Expand All @@ -78,16 +69,13 @@ template <typename T> class array {
return *this;
}

CUDA_HOST_DEVICE array<T> slice(std::size_t offset, std::size_t size) {
CUDA_HOST_DEVICE array<T> slice(std::size_t offset, std::size_t size) const {
assert(offset + size <= m_size);
return array<T>(&m_arr[offset], size, false);
return array<T>(&m_arr[offset], size);
}

/// Destructor to delete the array if owned by this class.
CUDA_HOST_DEVICE ~array() {
if (m_owned)
delete[] m_arr;
}
/// Destructor to delete the array.
CUDA_HOST_DEVICE ~array() { delete[] m_arr; }

/// Returns the size of the underlying array
CUDA_HOST_DEVICE std::size_t size() const { return m_size; }
Expand Down
224 changes: 145 additions & 79 deletions include/clad/Differentiator/ArrayRef.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,88 +8,153 @@
#include <type_traits>

namespace clad {
/// Stores the pointer to and the size of an array and provides some helper
/// functions for it. The array is supplied should have a life greater than
/// that of the array_ref
template <typename T> class array_ref {
private:
/// The pointer to the underlying array
T* m_arr = nullptr;
/// The size of the array
std::size_t m_size = 0;
/// Stores the pointer to and the size of an array and provides some helper
/// functions for it. The array is supplied should have a life greater than
/// that of the array_ref

public:
/// Delete default constructor
array_ref() = delete;
/// Constructor to store the pointer to and size of an array supplied by the
/// user
CUDA_HOST_DEVICE array_ref(T* arr, std::size_t size)
: m_arr(arr), m_size(size) {}
/// Constructor for arrays having size equal to 1 or non pointer types to
/// store their addresses
CUDA_HOST_DEVICE array_ref(T* a) : m_arr(a), m_size(1) {}
/// Constructor for clad::array types
CUDA_HOST_DEVICE array_ref(array<T>& a)
: m_arr(a.ptr()), m_size(a.size()) {}
// NOLINTBEGIN(*-pointer-arithmetic)
template <typename T> class array_ref {
private:
/// The pointer to the underlying array
T* m_arr = nullptr;
/// The size of the array
std::size_t m_size = 0;

template <typename U>
CUDA_HOST_DEVICE array_ref<T>& operator=(array<U>& a) {
assert(m_size == a.size());
for (std::size_t i = 0; i < m_size; ++i)
m_arr[i] = a[i];
return *this;
}
/// Returns the size of the underlying array
CUDA_HOST_DEVICE std::size_t size() const { return m_size; }
CUDA_HOST_DEVICE T* ptr() const { return m_arr; }
/// Returns an array_ref to a part of the underlying array starting at
/// offset and having the specified size
CUDA_HOST_DEVICE array_ref<T> slice(std::size_t offset, std::size_t size) {
assert((offset >= 0) && (offset + size <= m_size) &&
"Window is outside array. Please provide an offset and size "
"inside the array size.");
return array_ref<T>(&m_arr[offset], size);
}
/// Returns the reference to the location at the index of the underlying
/// array
CUDA_HOST_DEVICE T& operator[](std::size_t i) { return m_arr[i]; }
/// Returns the reference to the underlying array
CUDA_HOST_DEVICE T& operator*() { return *m_arr; }
public:
/// Delete default constructor
array_ref() = delete;
/// Constructor to store the pointer to and size of an array supplied by the
/// user
CUDA_HOST_DEVICE array_ref(T* arr, std::size_t size)
: m_arr(arr), m_size(size) {}
/// Constructor for arrays having size equal to 1 or non pointer types to
/// store their addresses
CUDA_HOST_DEVICE array_ref(T* a) : m_arr(a), m_size(1) {}
/// Constructor for clad::array types
CUDA_HOST_DEVICE array_ref(array<T>& a) : m_arr(a.ptr()), m_size(a.size()) {}

// Arithmetic overloads
/// Divides the arrays element wise
CUDA_HOST_DEVICE array_ref<T>& operator/=(array_ref<T>& Ar) {
assert(m_size == Ar.size() && "Size of both the array_refs must be equal "
"for carrying out addition assignment");
for (std::size_t i = 0; i < m_size; i++)
m_arr[i] /= Ar[i];
return *this;
}
/// Multiplies the arrays element wise
CUDA_HOST_DEVICE array_ref<T>& operator*=(array_ref<T>& Ar) {
assert(m_size == Ar.size() && "Size of both the array_refs must be equal "
"for carrying out addition assignment");
for (std::size_t i = 0; i < m_size; i++)
m_arr[i] *= Ar[i];
return *this;
}
/// Adds the arrays element wise
CUDA_HOST_DEVICE array_ref<T>& operator+=(array_ref<T>& Ar) {
assert(m_size == Ar.size() && "Size of both the array_refs must be equal "
"for carrying out addition assignment");
for (std::size_t i = 0; i < m_size; i++)
m_arr[i] += Ar[i];
return *this;
}
/// Subtracts the arrays element wise
CUDA_HOST_DEVICE array_ref<T>& operator-=(array_ref<T>& Ar) {
assert(m_size == Ar.size() && "Size of both the array_refs must be equal "
"for carrying out addition assignment");
for (std::size_t i = 0; i < m_size; i++)
m_arr[i] -= Ar[i];
return *this;
}
};
template <typename U> CUDA_HOST_DEVICE array_ref<T>& operator=(array<U>& a) {
assert(m_size == a.size());
for (std::size_t i = 0; i < m_size; ++i)
m_arr[i] = a[i];
return *this;
}
/// Returns the size of the underlying array
CUDA_HOST_DEVICE std::size_t size() const { return m_size; }
CUDA_HOST_DEVICE T* ptr() const { return m_arr; }
/// Returns an array_ref to a part of the underlying array starting at
/// offset and having the specified size
CUDA_HOST_DEVICE array_ref<T> slice(std::size_t offset, std::size_t size) {
assert((offset >= 0) && (offset + size <= m_size) &&
"Window is outside array. Please provide an offset and size "
"inside the array size.");
return array_ref<T>(&m_arr[offset], size);
}
/// Returns the reference to the location at the index of the underlying
/// array
CUDA_HOST_DEVICE T& operator[](std::size_t i) { return m_arr[i]; }
/// Returns the reference to the underlying array
CUDA_HOST_DEVICE T& operator*() { return *m_arr; }

// Arithmetic overloads
/// Divides the arrays element wise
template <typename U>
CUDA_HOST_DEVICE array_ref<T>& operator/=(array_ref<U>& Ar) {
assert(m_size == Ar.size() && "Size of both the array_refs must be equal "
"for carrying out addition assignment");
for (std::size_t i = 0; i < m_size; i++)
m_arr[i] /= Ar[i];
return *this;
}
/// Multiplies the arrays element wise
template <typename U>
CUDA_HOST_DEVICE array_ref<T>& operator*=(array_ref<U>& Ar) {
assert(m_size == Ar.size() && "Size of both the array_refs must be equal "
"for carrying out addition assignment");
for (std::size_t i = 0; i < m_size; i++)
m_arr[i] *= Ar[i];
return *this;
}
/// Adds the arrays element wise
template <typename U>
CUDA_HOST_DEVICE array_ref<T>& operator+=(array_ref<U>& Ar) {
assert(m_size == Ar.size() && "Size of both the array_refs must be equal "
"for carrying out addition assignment");
for (std::size_t i = 0; i < m_size; i++)
m_arr[i] += Ar[i];
return *this;
}
/// Subtracts the arrays element wise
template <typename U>
CUDA_HOST_DEVICE array_ref<T>& operator-=(array_ref<U>& Ar) {
assert(m_size == Ar.size() && "Size of both the array_refs must be equal "
"for carrying out addition assignment");
for (std::size_t i = 0; i < m_size; i++)
m_arr[i] -= Ar[i];
return *this;
}
/// Divides the elements of the array_ref by elements of the array
template <typename U> CUDA_HOST_DEVICE array_ref<T>& operator/=(array<U>& A) {
assert(m_size == A.size() && "Size of arrays must be equal");
for (std::size_t i = 0; i < m_size; i++)
m_arr[i] /= A[i];
return *this;
}
/// Multiplies the elements of the array_ref by elements of the array
template <typename U> CUDA_HOST_DEVICE array_ref<T>& operator*=(array<U>& A) {
assert(m_size == A.size() && "Size of arrays must be equal");
for (std::size_t i = 0; i < m_size; i++)
m_arr[i] *= A[i];
return *this;
}
/// Adds the elements of the array_ref by elements of the array
template <typename U> CUDA_HOST_DEVICE array_ref<T>& operator+=(array<U>& A) {
assert(m_size == A.size() && "Size of arrays must be equal");
for (std::size_t i = 0; i < m_size; i++)
m_arr[i] += A[i];
return *this;
}
/// Subtracts the elements of the array_ref by elements of the array
template <typename U> CUDA_HOST_DEVICE array_ref<T>& operator-=(array<U>& A) {
assert(m_size == A.size() && "Size of arrays must be equal");
for (std::size_t i = 0; i < m_size; i++)
m_arr[i] -= A[i];
return *this;
}
/// Divides the array by a scalar
template <typename U, typename std::enable_if<std::is_arithmetic<U>::value,
int>::type = 0>
CUDA_HOST_DEVICE array_ref<T>& operator/=(U a) {
for (std::size_t i = 0; i < m_size; i++)
m_arr[i] /= a;
return *this;
}
/// Multiplies the array by a scalar
template <typename U, typename std::enable_if<std::is_arithmetic<U>::value,
int>::type = 0>
CUDA_HOST_DEVICE array_ref<T>& operator*=(U a) {
for (std::size_t i = 0; i < m_size; i++)
m_arr[i] *= a;
return *this;
}
/// Adds the array by a scalar
template <typename U, typename std::enable_if<std::is_arithmetic<U>::value,
int>::type = 0>
CUDA_HOST_DEVICE array_ref<T>& operator+=(U a) {
for (std::size_t i = 0; i < m_size; i++)
m_arr[i] += a;
return *this;
}

/// Subtracts the array by a scalar
template <typename U, typename std::enable_if<std::is_arithmetic<U>::value,
int>::type = 0>
CUDA_HOST_DEVICE array_ref<T>& operator-=(U a) {
for (std::size_t i = 0; i < m_size; i++)
m_arr[i] -= a;
return *this;
}
};

/// `array_ref<void>` specialisation is created to be used as a placeholder
/// type in the overloaded derived function. All `array_ref<T>` types are
Expand Down Expand Up @@ -131,6 +196,7 @@ namespace clad {
CUDA_HOST_DEVICE void* ptr() const { return m_arr; }
CUDA_HOST_DEVICE std::size_t size() const { return m_size; }
};
// NOLINTEND(*-pointer-arithmetic)
} // namespace clad

#endif // CLAD_ARRAY_REF_H
10 changes: 2 additions & 8 deletions include/clad/Differentiator/Matrix.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,15 +81,9 @@ template <typename T> class matrix {
}

/// Returns the reference to the row at the given index.
CUDA_HOST_DEVICE clad::array<T>& operator[](size_t row_idx) {
CUDA_HOST_DEVICE clad::array_ref<T> operator[](size_t row_idx) {
assert(row_idx < m_rows);
return m_data.slice(row_idx * m_cols, m_cols);
}

/// Returns the reference to the row at the given index.
CUDA_HOST_DEVICE const clad::array<T>& operator[](size_t row_idx) const {
assert(row_idx < m_rows);
return m_data.slice(row_idx * m_cols, m_cols);
return clad::array_ref<T>(m_data).slice(row_idx * m_cols, m_cols);
}

/// Adding constant to matrix.
Expand Down
30 changes: 15 additions & 15 deletions test/Misc/CladArray.C
Original file line number Diff line number Diff line change
Expand Up @@ -171,36 +171,36 @@ int main() {
// CHECK-EXEC: 2 : 0.00

// Create a slice of double_test_arr2 and modify one of its elements.
// This should modify the original array.
// This should not modify the original array.
clad::array<double> double_test_arr2_slice = double_test_arr2.slice(1, 2);
double_test_arr2_slice[0] = 2;
for (int i = 0; i < 3; i++) {
printf("%d : %.2f\n", i, double_test_arr2[i]);
}
// CHECK-EXEC: 0 : 0.00
// CHECK-EXEC: 1 : 2.00
// CHECK-EXEC: 1 : 1.00
// CHECK-EXEC: 2 : 0.00

// Create a clad array from pointer with copy=true and modify
// one of its elements. This should not modify the original array.
double double_test_arr3[] = {1, 2, 3};
clad::array<double> double_test_arr4(double_test_arr3, 3, true);
double_test_arr4[0] = 2;
// Create a slice by creating array_ref and modify one of its elements.
// This should modify the original array.
clad::array_ref<double> ref_slice = clad::array_ref<double>(double_test_arr2).slice(1, 2);
ref_slice[0] = 2;
for (int i = 0; i < 3; i++) {
printf("%d : %.2f\n", i, double_test_arr3[i]);
printf("%d : %.2f\n", i, double_test_arr2[i]);
}
// CHECK-EXEC: 0 : 1.00
// CHECK-EXEC: 0 : 0.00
// CHECK-EXEC: 1 : 2.00
// CHECK-EXEC: 2 : 3.00
// CHECK-EXEC: 2 : 0.00

// Create a clad array from pointer with copy=false and modify
// one of its elements. This should modify the original array.
clad::array<double> double_test_arr5(double_test_arr3, 3, false);
double_test_arr5[0] = 2;
// Create a clad array from pointer and modify one of its elements.
// This should not modify the original array.
double double_test_arr3[] = {1, 2, 3};
clad::array<double> double_test_arr4(double_test_arr3, 3);
double_test_arr4[0] = 2;
for (int i = 0; i < 3; i++) {
printf("%d : %.2f\n", i, double_test_arr3[i]);
}
// CHECK-EXEC: 0 : 2.00
// CHECK-EXEC: 0 : 1.00
// CHECK-EXEC: 1 : 2.00
// CHECK-EXEC: 2 : 3.00
}
16 changes: 16 additions & 0 deletions test/Misc/CladMatrix.C
Original file line number Diff line number Diff line change
Expand Up @@ -153,4 +153,20 @@ int main() {
// CHECK-EXEC: 2, 0 : 0
// CHECK-EXEC: 2, 1 : 0
// CHECK-EXEC: 2, 2 : 0

test3_mat[0][0] = 4;
for (int i = 0; i < test3_mat.rows(); i++) {
for (int j = 0; j < test3_mat.cols(); ++j) {
printf("%d, %d : %d\n", i, j, test3_mat(i, j));
}
}
// CHECK-EXEC: 0, 0 : 4
// CHECK-EXEC: 0, 1 : 2
// CHECK-EXEC: 0, 2 : 3
// CHECK-EXEC: 1, 0 : 0
// CHECK-EXEC: 1, 1 : 0
// CHECK-EXEC: 1, 2 : 1
// CHECK-EXEC: 2, 0 : 0
// CHECK-EXEC: 2, 1 : 0
// CHECK-EXEC: 2, 2 : 0
}

0 comments on commit c8e7b4e

Please sign in to comment.