Skip to content

Commit

Permalink
Add multidim support for scaled_reduced_row_major
Browse files Browse the repository at this point in the history
  • Loading branch information
Thomas Grützmacher committed Nov 10, 2020
1 parent b724abe commit 96a78aa
Show file tree
Hide file tree
Showing 2 changed files with 193 additions and 37 deletions.
129 changes: 128 additions & 1 deletion core/test/base/range_accessors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


#include <tuple>
#include <type_traits>


#include <ginkgo/core/base/dim.hpp>
Expand Down Expand Up @@ -460,6 +461,12 @@ class ReducedStorageXd : public ::testing::Test {
gko::accessor::reduced_row_major<1, ar_type, const st_type>;
using const_accessor2d =
gko::accessor::reduced_row_major<2, ar_type, const st_type>;
static_assert(std::is_same<const_accessor1d,
typename accessor1d::const_accessor>::value,
"Const accessors must be the same!");
static_assert(std::is_same<const_accessor2d,
typename accessor2d::const_accessor>::value,
"Const accessors must be the same!");

using reduced_storage1d = gko::range<accessor1d>;
using reduced_storage2d = gko::range<accessor2d>;
Expand All @@ -473,7 +480,7 @@ class ReducedStorageXd : public ::testing::Test {
static constexpr gko::size_type data_elements{8};
st_type data[data_elements]{1.1f, 2.2f, 3.3f, 4.4f,
5.5f, 6.6f, 7.7f, -8.8f};
reduced_storage1d r1{data, size_1d /*, stride0*/};
reduced_storage1d r1{data, size_1d};
reduced_storage2d r2{data, size_2d, stride1[0]};
const_reduced_storage1d cr1{data, size_1d, stride0};
const_reduced_storage2d cr2{data, size_2d, stride1};
Expand Down Expand Up @@ -502,6 +509,24 @@ TEST_F(ReducedStorageXd, CanRead)
}


TEST_F(ReducedStorageXd, CanWrite1)
{
r1(2) = 0.25;

data_equal_except_for(2);
EXPECT_EQ(r1(2), 0.25); // expect exact since easy to store
}


TEST_F(ReducedStorageXd, CanWrite2)
{
r2(1, 1) = 0.75;

data_equal_except_for(5);
EXPECT_EQ(r2(1, 1), 0.75); // expect exact since easy to store
}


class ScaledReducedStorage3d : public ::testing::Test {
protected:
using span = gko::span;
Expand Down Expand Up @@ -786,4 +811,106 @@ TEST_F(ScaledReducedStorage3d, UnaryMinus)
}


class ScaledReducedStorageXd : public ::testing::Test {
protected:
using span = gko::span;
using ar_type = double;
using st_type = int;
using size_type = gko::size_type;
static constexpr ar_type delta{0.1};

using accessor1d =
gko::accessor::scaled_reduced_row_major<1, ar_type, st_type, 1>;
using accessor2d =
gko::accessor::scaled_reduced_row_major<2, ar_type, st_type, 2>;
using const_accessor1d =
gko::accessor::scaled_reduced_row_major<1, ar_type, const st_type, 1>;
using const_accessor2d =
gko::accessor::scaled_reduced_row_major<2, ar_type, const st_type, 2>;
static_assert(std::is_same<const_accessor1d,
typename accessor1d::const_accessor>::value,
"Const accessors must be the same!");
static_assert(std::is_same<const_accessor2d,
typename accessor2d::const_accessor>::value,
"Const accessors must be the same!");

using reduced_storage1d = gko::range<accessor1d>;
using reduced_storage2d = gko::range<accessor2d>;
using const_reduced_storage2d = gko::range<const_accessor2d>;
using const_reduced_storage1d = gko::range<const_accessor1d>;

const std::array<const size_type, 0> stride0{};
const std::array<const size_type, 1> stride1{4};
const gko::dim<1> size_1d{8u};
const gko::dim<2> size_2d{2u, 4u};

static constexpr gko::size_type data_elements{8};
st_type data[data_elements]{11, 22, 33, 44, 55, 66, 77, -88};
const double default_scalar{.1};
ar_type scalar[data_elements]{
default_scalar, default_scalar, default_scalar, default_scalar,
default_scalar, default_scalar, default_scalar, default_scalar};

reduced_storage1d r1{data, scalar, size_1d};
reduced_storage2d r2{data, scalar, size_2d, stride1[0]};
const_reduced_storage1d cr1{data, scalar, size_1d, stride0};
const_reduced_storage2d cr2{data, scalar, size_2d, stride1};

void data_equal_except_for(int idx)
{
// clang-format off
if (idx != 0) { EXPECT_EQ(data[0], 11); }
if (idx != 1) { EXPECT_EQ(data[1], 22); }
if (idx != 2) { EXPECT_EQ(data[2], 33); }
if (idx != 3) { EXPECT_EQ(data[3], 44); }
if (idx != 4) { EXPECT_EQ(data[4], 55); }
if (idx != 5) { EXPECT_EQ(data[5], 66); }
if (idx != 6) { EXPECT_EQ(data[6], 77); }
if (idx != 7) { EXPECT_EQ(data[7], -88); }
// clang-format on
}
void scalar_equal_except_for(int idx)
{
// clang-format off
if (idx != 0) { EXPECT_EQ(scalar[0], default_scalar); }
if (idx != 1) { EXPECT_EQ(scalar[1], default_scalar); }
if (idx != 2) { EXPECT_EQ(scalar[2], default_scalar); }
if (idx != 3) { EXPECT_EQ(scalar[3], default_scalar); }
if (idx != 4) { EXPECT_EQ(scalar[4], default_scalar); }
if (idx != 5) { EXPECT_EQ(scalar[5], default_scalar); }
if (idx != 6) { EXPECT_EQ(scalar[6], default_scalar); }
if (idx != 7) { EXPECT_EQ(scalar[7], default_scalar); }
// clang-format on
}
};

TEST_F(ScaledReducedStorageXd, CanRead)
{
EXPECT_NEAR(cr1(1), 2.2, delta);
EXPECT_NEAR(cr2(0, 1), 2.2, delta);
EXPECT_NEAR(r1(1), 2.2, delta);
EXPECT_NEAR(r2(0, 1), 2.2, delta);
}


TEST_F(ScaledReducedStorageXd, CanWrite1)
{
r1(2) = 0.2;

data_equal_except_for(2);
scalar_equal_except_for(99);
EXPECT_NEAR(r1(2), 0.2, delta);
}


TEST_F(ScaledReducedStorageXd, CanWrite2)
{
r2(1, 1) = 0.7;

data_equal_except_for(5);
scalar_equal_except_for(99);
EXPECT_NEAR(r2(1, 1), 0.7, delta);
}


} // namespace
101 changes: 65 additions & 36 deletions include/ginkgo/core/base/range_accessors.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,9 @@ class reduced_row_major {
using const_accessor =
reduced_row_major<dimensionality, arithmetic_type, const storage_type>;

static_assert(Dimensionality >= 1,
"Dimensionality must be a positive number!");

friend class range<reduced_row_major>;

protected:
Expand All @@ -257,7 +260,7 @@ class reduced_row_major {
*
* @param storage pointer to the block of memory containing the storage
* @param size multidimensional size of the memory
* @param stride stride array used for the x-indices
* @param stride stride array used for memory accesses
*/
GKO_ATTRIBUTES constexpr reduced_row_major(
storage_type *storage, gko::dim<dimensionality> size,
Expand All @@ -272,7 +275,7 @@ class reduced_row_major {
*
* @param storage pointer to the block of memory containing the storage
* @param size multidimensional size of the memory
* @param stride stride array used for the x-indices
* @param stride stride array used for memory accesses
*/
GKO_ATTRIBUTES constexpr reduced_row_major(
storage_type *storage, gko::dim<dimensionality> size,
Expand All @@ -284,7 +287,7 @@ class reduced_row_major {
* Creates the accessor with an already allocated storage space with a
* stride. The first stride is used for computing the index for the first
* index, the second stride for the second index, and so on.
* It is assumed that accesses are without a stride.
* It is assumed that accesses are without padding.
*
* @param storage pointer to the block of memory containing the storage
* @param size multidimensional size of the memory
Expand All @@ -302,7 +305,7 @@ class reduced_row_major {
*
* @param storage pointer to the block of memory containing the storage
* @param size multidimensional size of the memory
* @param stride stride array used for the x-indices
* @param strides strides used for memory accesses
*/
template <typename... Strides>
GKO_ATTRIBUTES constexpr reduced_row_major(storage_type *storage,
Expand Down Expand Up @@ -363,6 +366,7 @@ class reduced_row_major {
template <typename OtherAccessor>
GKO_ATTRIBUTES void copy_from(const OtherAccessor &other) const
{
// TODO add proper copy_from implementation independent of size!!!
for (size_type i = 0; i < size_[0]; ++i) {
for (size_type j = 0; j < size_[1]; ++j) {
for (size_type k = 0; k < size_[2]; ++k) {
Expand Down Expand Up @@ -505,7 +509,8 @@ template <int Dimensionality, typename Accessor, typename ScaleType>
struct enable_write_scalar<Dimensionality, Accessor, ScaleType, false> {
static_assert(!std::is_const<ScaleType>::value,
"This class must NOT have a constant ScaleType!");
static_assert(Dimensionality == 3, "Only Dimensionality 3 supported!");
static_assert(Dimensionality >= 1,
"Dimensionality must be a positive number!");

using scalar_type = ScaleType;

Expand Down Expand Up @@ -588,6 +593,8 @@ class scaled_reduced_row_major
scaled_reduced_row_major<dimensionality, arithmetic_type,
const storage_type, ScalarMask>;

static_assert(Dimensionality >= 1,
"Dimensionality must be a positive number!");
static_assert(dimensionality <= 32,
"Only Dimensionality <= 32 is currently supported");

Expand All @@ -608,57 +615,77 @@ class scaled_reduced_row_major
*
* @param storage pointer to the block of memory containing the storage
* @param scalar pointer to the block of memory containing the scalar
* values. Memory required is size[0] * stride1.
* values.
* @param size multidimensional size of the memory
* @param stride0 stride used for the x-indices
* @param stride1 stride used for the y-indices
* @param stride strides used for memory accesses
*/
GKO_ATTRIBUTES constexpr scaled_reduced_row_major(storage_type *storage,
scalar_type *scalar,
dim<dimensionality> size,
size_type stride0,
size_type stride1)
: storage_{storage},
scalar_{scalar},
size_{size},
stride_{stride0, stride1}
GKO_ATTRIBUTES constexpr scaled_reduced_row_major(
storage_type *storage, scalar_type *scalar, dim<dimensionality> size,
const std::array<const size_type, dimensionality - 1> &stride)
: storage_{storage}, scalar_{scalar}, size_{size}, stride_{stride}
{}

/**
* Creates the accessor with an already allocated storage space with a
* stride. The first stride is used for computing the index for the first
* index, the second stride for the second index, and so on.
*
* @param storage pointer to the block of memory containing the storage
* @param scalar pointer to the block of memory containing the scalar
* values. Memory required is size[0] * stride1.
* values.
* @param size multidimensional size of the memory
* @param stride stride array of size dimensionality - 1, used for the
* x-indices
* @param stride strides used for memory accesses
*/
GKO_ATTRIBUTES constexpr scaled_reduced_row_major(
storage_type *storage, scalar_type *scalar, dim<dimensionality> size,
std::array<const size_type, dimensionality - 1> stride)
std::array<const size_type, dimensionality - 1> &&stride)
: storage_{storage}, scalar_{scalar}, size_{size}, stride_{stride}
{}

/**
* Creates the accessor with an already allocated storage space with a
* stride. The first stride is used for computing the index for the first
* index, the second stride for the second index, and so on.
* It is assumed that accesses are without a stride.
* It is assumed that accesses are without padding.
*
* @param storage pointer to the block of memory containing the storage
* @param scalar pointer to the block of memory containing the scalar
* values. Memory required is size[0] * size[1].
* values.
* @param size multidimensional size of the memory
*/
GKO_ATTRIBUTES constexpr scaled_reduced_row_major(storage_type *storage,
scalar_type *scalar,
dim<dimensionality> size)
: scaled_reduced_row_major{storage, scalar, size, size[1] * size[2],
size[2]}
: scaled_reduced_row_major{
storage, scalar, size,
helper::compute_stride_array<const size_type>(size)}
{}

/**
* Creates the accessor with an already allocated storage space with a
* stride. The first stride is used for computing the index for the first
* index, the second stride for the second index, and so on.
*
* @param storage pointer to the block of memory containing the storage
* @param scalar pointer to the block of memory containing the scalar
* values.
* @param size multidimensional size of the memory
* @param strides strides used for memory accesses
*/
template <typename... Strides>
GKO_ATTRIBUTES constexpr scaled_reduced_row_major(storage_type *storage,
scalar_type *scalar,
dim<dimensionality> size,
Strides &&... strides)
: storage_{storage},
scalar_{scalar},
size_{size},
stride_{std::forward<Strides>(strides)...}
{
static_assert(sizeof...(Strides) + 1 == dimensionality,
"Number of provided Strides must be dimensionality - 1!");
}

/**
* Creates an empty accessor (pointing nowhere with an empty size)
*/
Expand All @@ -674,15 +701,13 @@ class scaled_reduced_row_major
*/
GKO_ATTRIBUTES GKO_INLINE constexpr range<const_accessor> to_const() const
{
return range<const_accessor>{storage_, scalar_, size_, stride_[0],
stride_[1]};
return range<const_accessor>{storage_, scalar_, size_, stride_};
}

/**
* Reads the scalar value at the given indices.
*
* @param x x index
* @param y y index
* @param indices indices which data to access
*
* @returns the scalar value at the given indices.
*/
Expand Down Expand Up @@ -723,6 +748,7 @@ class scaled_reduced_row_major
template <typename OtherAccessor>
GKO_ATTRIBUTES void copy_from(const OtherAccessor &other) const
{
// TODO add proper copy_from implementation independent of size!!!
for (size_type i = 0; i < this->size_[0]; ++i) {
for (size_type k = 0; k < this->size_[2]; ++k) {
this->write_scalar(other.read_scalar(i, 0, k), i, 0, k);
Expand Down Expand Up @@ -750,7 +776,7 @@ class scaled_reduced_row_major
GKO_ATTRIBUTES GKO_INLINE constexpr std::enable_if_t<
helper::are_all_integral<Indices...>::value,
std::conditional_t<is_const, arithmetic_type, reference_type>>
operator()(Indices &&... indices) const
operator()(Indices... indices) const
{
return reference_type{
this->storage_ + compute_index(std::forward<Indices>(indices)...),
Expand Down Expand Up @@ -862,11 +888,16 @@ class scaled_reduced_row_major
}

protected:
GKO_ATTRIBUTES constexpr GKO_INLINE size_type
compute_index(size_type x, size_type y, size_type z) const
template <typename... Indices>
GKO_ATTRIBUTES GKO_INLINE constexpr size_type compute_index(
Indices &&... indices) const
{
return GKO_ASSERT(x < size_[0]), GKO_ASSERT(y < size_[1]),
GKO_ASSERT(z < size_[2]), x * stride_[0] + y * stride_[1] + z;
static_assert(sizeof...(Indices) == dimensionality,
"Number of indices must match dimensionality!");
return helper::row_major_index<
const size_type, dimensionality>::compute(size_, stride_,
std::forward<Indices>(
indices)...);
}

template <typename... Indices>
Expand All @@ -879,8 +910,6 @@ class scaled_reduced_row_major
const size_type, dimensionality,
scalar_mask>::compute(size_, stride_,
std::forward_as_tuple(indices...));
// return GKO_ASSERT(x < size_[0]), GKO_ASSERT(z < size_[2]),
// x * stride_[1] + z;
}

storage_type *storage_;
Expand Down

0 comments on commit 96a78aa

Please sign in to comment.