commit
48de5ffca7
@ -0,0 +1,222 @@
|
||||
#include "paddle/majel/ddim.h"
|
||||
|
||||
namespace majel {
|
||||
|
||||
///@cond HIDDEN
|
||||
|
||||
template <int i>
|
||||
Dim<i> make_dim(const int* d) {
|
||||
return Dim<i>(*d, make_dim<i - 1>(d + 1));
|
||||
}
|
||||
|
||||
template <>
|
||||
Dim<1> make_dim<1>(const int* d) {
|
||||
return Dim<1>(*d);
|
||||
}
|
||||
|
||||
void make_ddim(DDim& ddim, const int* dims, int n) {
|
||||
switch (n) {
|
||||
case 1:
|
||||
ddim = make_dim<1>(dims);
|
||||
break;
|
||||
case 2:
|
||||
ddim = make_dim<2>(dims);
|
||||
break;
|
||||
case 3:
|
||||
ddim = make_dim<3>(dims);
|
||||
break;
|
||||
case 4:
|
||||
ddim = make_dim<4>(dims);
|
||||
break;
|
||||
case 5:
|
||||
ddim = make_dim<5>(dims);
|
||||
break;
|
||||
case 6:
|
||||
ddim = make_dim<6>(dims);
|
||||
break;
|
||||
case 7:
|
||||
ddim = make_dim<7>(dims);
|
||||
break;
|
||||
case 8:
|
||||
ddim = make_dim<8>(dims);
|
||||
break;
|
||||
case 9:
|
||||
ddim = make_dim<9>(dims);
|
||||
break;
|
||||
default:
|
||||
throw std::invalid_argument(
|
||||
"Dynamic dimensions must have between [1, 9] dimensions.");
|
||||
}
|
||||
}
|
||||
|
||||
///@endcond
|
||||
|
||||
DDim make_ddim(std::initializer_list<int> dims) {
|
||||
DDim result(make_dim(0));
|
||||
make_ddim(result, dims.begin(), dims.size());
|
||||
return result;
|
||||
}
|
||||
|
||||
DDim make_ddim(const std::vector<int>& dims) {
|
||||
DDim result(make_dim(0));
|
||||
make_ddim(result, &dims[0], dims.size());
|
||||
return result;
|
||||
}
|
||||
|
||||
///@cond HIDDEN
|
||||
// XXX For some reason, putting this in an anonymous namespace causes errors
|
||||
class DynamicMutableIndexer : public boost::static_visitor<int&> {
|
||||
public:
|
||||
DynamicMutableIndexer(int idx) : idx_(idx) {}
|
||||
|
||||
template <int D>
|
||||
int& operator()(Dim<D>& dim) const {
|
||||
return dim[idx_];
|
||||
}
|
||||
|
||||
private:
|
||||
int idx_;
|
||||
};
|
||||
|
||||
class DynamicConstIndexer : public boost::static_visitor<int> {
|
||||
public:
|
||||
DynamicConstIndexer(int idx) : idx_(idx) {}
|
||||
|
||||
template <int D>
|
||||
int operator()(const Dim<D>& dim) const {
|
||||
return dim[idx_];
|
||||
}
|
||||
|
||||
private:
|
||||
int idx_;
|
||||
};
|
||||
|
||||
///@endcond
|
||||
|
||||
int& DDim::operator[](int idx) {
|
||||
return boost::apply_visitor(DynamicMutableIndexer(idx), var);
|
||||
}
|
||||
|
||||
int DDim::operator[](int idx) const {
|
||||
return boost::apply_visitor(DynamicConstIndexer(idx), var);
|
||||
}
|
||||
|
||||
bool DDim::operator==(DDim d) const {
|
||||
if (var.which() != d.getVar().which()) {
|
||||
return false;
|
||||
} else {
|
||||
std::vector<int> v1 = vectorize(*this);
|
||||
std::vector<int> v2 = vectorize(d);
|
||||
|
||||
for (unsigned int i = 0; i < v1.size(); i++) {
|
||||
if (v1[i] != v2[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool DDim::operator!=(DDim d) const { return !(*this == d); }
|
||||
|
||||
DDim DDim::operator+(DDim d) const {
|
||||
std::vector<int> v1 = vectorize(*this);
|
||||
std::vector<int> v2 = vectorize(d);
|
||||
|
||||
std::vector<int> v3;
|
||||
|
||||
assert(v1.size() == v2.size());
|
||||
|
||||
for (unsigned int i = 0; i < v1.size(); i++) {
|
||||
v3.push_back(v1[i] + v2[i]);
|
||||
}
|
||||
|
||||
return make_ddim(v3);
|
||||
}
|
||||
|
||||
DDim DDim::operator*(DDim d) const {
|
||||
std::vector<int> v1 = vectorize(*this);
|
||||
std::vector<int> v2 = vectorize(d);
|
||||
|
||||
std::vector<int> v3;
|
||||
|
||||
assert(v1.size() == v2.size());
|
||||
|
||||
for (unsigned int i = 0; i < v1.size(); i++) {
|
||||
v3.push_back(v1[i] * v2[i]);
|
||||
}
|
||||
|
||||
return make_ddim(v3);
|
||||
}
|
||||
|
||||
int get(const DDim& ddim, int idx) { return ddim[idx]; }
|
||||
|
||||
void set(DDim& ddim, int idx, int value) { ddim[idx] = value; }
|
||||
|
||||
///@cond HIDDEN
|
||||
struct VectorizeVisitor : public boost::static_visitor<> {
|
||||
std::vector<int>& vector;
|
||||
|
||||
VectorizeVisitor(std::vector<int>& v) : vector(v) {}
|
||||
|
||||
template <typename T>
|
||||
void operator()(const T& t) {
|
||||
vector.push_back(t.head);
|
||||
this->operator()(t.tail);
|
||||
}
|
||||
|
||||
void operator()(const Dim<1>& t) { vector.push_back(t.head); }
|
||||
};
|
||||
///@endcond
|
||||
|
||||
std::vector<int> vectorize(const DDim& ddim) {
|
||||
std::vector<int> result;
|
||||
VectorizeVisitor visitor(result);
|
||||
boost::apply_visitor(visitor, ddim);
|
||||
return result;
|
||||
}
|
||||
|
||||
ssize_t product(const DDim& ddim) {
|
||||
ssize_t result = 1;
|
||||
std::vector<int> v = vectorize(ddim);
|
||||
for (auto i : v) {
|
||||
result *= i;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
///\cond HIDDEN
|
||||
|
||||
struct ArityVisitor : boost::static_visitor<int> {
|
||||
template <int D>
|
||||
int operator()(Dim<D>) const {
|
||||
return D;
|
||||
}
|
||||
};
|
||||
|
||||
///\endcond
|
||||
|
||||
int arity(const DDim& d) { return boost::apply_visitor(ArityVisitor(), d); }
|
||||
|
||||
///\cond HIDDEN
|
||||
|
||||
struct DDimPrinter : boost::static_visitor<void> {
|
||||
std::ostream& os;
|
||||
DDimPrinter(std::ostream& os_) : os(os_) {}
|
||||
|
||||
template <typename T>
|
||||
void operator()(const T& t) {
|
||||
os << t;
|
||||
}
|
||||
};
|
||||
|
||||
///\endcond
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const majel::DDim& ddim) {
|
||||
DDimPrinter printer(os);
|
||||
boost::apply_visitor(printer, ddim);
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace majel
|
@ -0,0 +1,109 @@
|
||||
#pragma once
|
||||
|
||||
#include <boost/variant.hpp>
|
||||
#include <initializer_list>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
#include "paddle/majel/dim.h"
|
||||
|
||||
namespace majel {
|
||||
|
||||
namespace {
|
||||
typedef boost::variant<Dim<1>,
|
||||
Dim<2>,
|
||||
Dim<3>,
|
||||
Dim<4>,
|
||||
Dim<5>,
|
||||
Dim<6>,
|
||||
Dim<7>,
|
||||
Dim<8>,
|
||||
Dim<9>>
|
||||
DDimVar;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief A dynamically sized dimension.
|
||||
*
|
||||
* The number of dimensions must be between [1, 9].
|
||||
*/
|
||||
struct DDim {
|
||||
DDimVar var;
|
||||
|
||||
DDim() : var(Dim<1>()) {}
|
||||
|
||||
template <int D>
|
||||
DDim(const Dim<D>& in) : var(in) {}
|
||||
|
||||
template <int D>
|
||||
DDim& operator=(const Dim<D>& in) {
|
||||
var = in;
|
||||
return *this;
|
||||
}
|
||||
|
||||
int& operator[](int idx);
|
||||
int operator[](int idx) const;
|
||||
|
||||
template <typename Visitor>
|
||||
typename Visitor::result_type apply_visitor(Visitor& visitor) {
|
||||
return var.apply_visitor(visitor);
|
||||
}
|
||||
|
||||
template <typename Visitor>
|
||||
typename Visitor::result_type apply_visitor(Visitor& visitor) const {
|
||||
return var.apply_visitor(visitor);
|
||||
}
|
||||
|
||||
DDimVar getVar() { return var; }
|
||||
|
||||
bool operator==(DDim d) const;
|
||||
|
||||
bool operator!=(DDim d) const;
|
||||
|
||||
DDim operator+(DDim d) const;
|
||||
|
||||
DDim operator*(DDim d) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Make a DDim from std::vector<int>
|
||||
*
|
||||
* \param dims An vector of ints. Must be sized between [1, 9]
|
||||
*/
|
||||
DDim make_ddim(const std::vector<int>& dims);
|
||||
|
||||
/**
|
||||
* \brief Make a DDim from an initializer list
|
||||
*
|
||||
* \param dims An initializer list of ints. Must be sized between [1, 9]
|
||||
*
|
||||
*/
|
||||
DDim make_ddim(std::initializer_list<int> dims);
|
||||
|
||||
int get(const DDim& dim, int idx);
|
||||
void set(DDim& dim, int idx, int val);
|
||||
|
||||
std::vector<int> vectorize(const DDim& ddim);
|
||||
|
||||
ssize_t product(const DDim& ddim);
|
||||
|
||||
/**
|
||||
* \brief What is the length of this dimension?
|
||||
*
|
||||
* \param Dynamic dimension to inspect
|
||||
*/
|
||||
|
||||
int arity(const DDim& ddim);
|
||||
|
||||
std::ostream& operator<<(std::ostream&, const majel::DDim&);
|
||||
|
||||
} // namespace majel
|
||||
|
||||
namespace boost {
|
||||
|
||||
template <typename T>
|
||||
T get(const majel::DDim& in) {
|
||||
return boost::get<T>(in.var);
|
||||
}
|
||||
|
||||
} // namespace boost
|
@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#define STRINGIFY(x) #x
|
||||
#define TOSTRING(x) STRINGIFY(x)
|
||||
|
||||
#if defined(__APPLE__) && defined(__CUDA_ARCH__) && !defined(NDEBUG)
|
||||
#include <stdio.h>
|
||||
#define MAJEL_ASSERT(e) \
|
||||
do { \
|
||||
if (!(e)) { \
|
||||
printf( \
|
||||
"%s:%d Assertion `%s` failed.\n", __FILE__, __LINE__, TOSTRING(e)); \
|
||||
asm("trap;"); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define MAJEL_ASSERT_MSG(e, m) \
|
||||
do { \
|
||||
if (!(e)) { \
|
||||
printf("%s:%d Assertion `%s` failed (%s).\n", \
|
||||
__FILE__, \
|
||||
__LINE__, \
|
||||
TOSTRING(e), \
|
||||
m); \
|
||||
asm("trap;"); \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
#include <assert.h>
|
||||
#define MAJEL_ASSERT(e) assert(e)
|
||||
#define MAJEL_ASSERT_MSG(e, m) assert((e) && (m))
|
||||
#endif
|
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __CUDACC__
|
||||
#define HOSTDEVICE __host__ __device__
|
||||
#define HOST __host__
|
||||
#else
|
||||
#define HOSTDEVICE
|
||||
#define HOST
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,12 @@
|
||||
cc_test(place_test
|
||||
SRCS place_test.cc
|
||||
DEPS majel)
|
||||
DEPS place)
|
||||
|
||||
cc_test(ddim_test
|
||||
SRCS ddim_test.cc
|
||||
DEPS ddim)
|
||||
|
||||
if(WITH_GPU)
|
||||
nv_test(cuda_test SRCS cuda_test.cu)
|
||||
nv_test(dim_test SRCS dim_test.cu DEPS ddim)
|
||||
endif()
|
||||
|
@ -0,0 +1,65 @@
|
||||
//#include <stdexcept>
|
||||
//#include <unittest/unittest.h>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "paddle/majel/ddim.h"
|
||||
|
||||
TEST(DDim, Equality) {
|
||||
// construct a DDim from an initialization list
|
||||
majel::DDim ddim = majel::make_ddim({9, 1, 5});
|
||||
EXPECT_EQ(ddim[0], 9);
|
||||
EXPECT_EQ(ddim[1], 1);
|
||||
EXPECT_EQ(ddim[2], 5);
|
||||
|
||||
// construct a DDim from a vector
|
||||
std::vector<int> vec({9, 1, 5});
|
||||
majel::DDim vddim = majel::make_ddim(vec);
|
||||
EXPECT_EQ(ddim[0], 9);
|
||||
EXPECT_EQ(ddim[1], 1);
|
||||
EXPECT_EQ(ddim[2], 5);
|
||||
|
||||
// mutate a DDim
|
||||
ddim[1] = 2;
|
||||
EXPECT_EQ(ddim[1], 2);
|
||||
majel::set(ddim, 0, 6);
|
||||
EXPECT_EQ(majel::get(ddim, 0), 6);
|
||||
|
||||
// vectorize a DDim
|
||||
std::vector<int> res_vec = majel::vectorize(vddim);
|
||||
EXPECT_EQ(res_vec[0], 9);
|
||||
EXPECT_EQ(res_vec[1], 1);
|
||||
EXPECT_EQ(res_vec[2], 5);
|
||||
majel::Dim<3> d(3, 2, 1);
|
||||
res_vec = majel::vectorize(majel::DDim(d));
|
||||
EXPECT_EQ(res_vec[0], 3);
|
||||
EXPECT_EQ(res_vec[1], 2);
|
||||
EXPECT_EQ(res_vec[2], 1);
|
||||
|
||||
// add two DDims
|
||||
majel::DDim ddim_sum = ddim + vddim;
|
||||
EXPECT_EQ(ddim_sum[0], 15);
|
||||
EXPECT_EQ(ddim_sum[1], 3);
|
||||
EXPECT_EQ(ddim_sum[2], 10);
|
||||
|
||||
// multiply two DDims
|
||||
majel::DDim ddim_mul = ddim * vddim;
|
||||
EXPECT_EQ(ddim_mul[0], 54);
|
||||
EXPECT_EQ(ddim_mul[1], 2);
|
||||
EXPECT_EQ(ddim_mul[2], 25);
|
||||
|
||||
// arity of a DDim
|
||||
EXPECT_EQ(majel::arity(ddim), 3);
|
||||
|
||||
// product of a DDim
|
||||
EXPECT_EQ(majel::product(vddim), 45);
|
||||
}
|
||||
|
||||
TEST(DDim, Print) {
|
||||
// print a DDim
|
||||
std::stringstream ss;
|
||||
majel::DDim ddim = majel::make_ddim({2, 3, 4});
|
||||
ss << ddim;
|
||||
EXPECT_EQ("2, 3, 4", ss.str());
|
||||
}
|
@ -0,0 +1,128 @@
|
||||
#include <thrust/device_vector.h>
|
||||
#include <sstream>
|
||||
|
||||
#include "paddle/majel/dim.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
__global__ void test(majel::Dim<2>* o) {
|
||||
o[0] = majel::make_dim(5, 6);
|
||||
}
|
||||
|
||||
__global__ void dyn_idx_gpu(int* o) {
|
||||
auto d = majel::make_dim(5, 6);
|
||||
o[0] = d[1];
|
||||
}
|
||||
|
||||
TEST(Dim, Equality) {
|
||||
// construct a Dim on the CPU
|
||||
auto a = majel::make_dim(3, 4);
|
||||
EXPECT_EQ(majel::get<0>(a), 3);
|
||||
EXPECT_EQ(majel::get<1>(a), 4);
|
||||
|
||||
// construct a Dim on the GPU
|
||||
thrust::device_vector<majel::Dim<2>> t(2);
|
||||
test<<<1,1>>>(thrust::raw_pointer_cast(t.data()));
|
||||
a = t[0];
|
||||
EXPECT_EQ(majel::get<0>(a), 5);
|
||||
EXPECT_EQ(majel::get<1>(a), 6);
|
||||
|
||||
// linearization
|
||||
auto b = majel::make_dim(7, 8);
|
||||
EXPECT_EQ(majel::linearize(a, b), 83);
|
||||
|
||||
// product
|
||||
EXPECT_EQ(majel::product(a), 30);
|
||||
|
||||
// mutate a Dim
|
||||
majel::get<1>(b) = 10;
|
||||
EXPECT_EQ(majel::get<0>(b), 7);
|
||||
EXPECT_EQ(majel::get<1>(b), 10);
|
||||
|
||||
// dynamic access
|
||||
majel::get(b, 0) = 8;
|
||||
b[1] = 11;
|
||||
EXPECT_EQ(majel::get<0>(b), 8);
|
||||
EXPECT_EQ(majel::get<1>(b), 11);
|
||||
EXPECT_EQ(majel::get(b, 0), 8);
|
||||
EXPECT_EQ(b[1], 11);
|
||||
|
||||
// dynamic access on GPU
|
||||
thrust::device_vector<int> r(1);
|
||||
dyn_idx_gpu<<<1,1>>>(thrust::raw_pointer_cast(r.data()));
|
||||
int res = r[0];
|
||||
EXPECT_EQ(res, 6);
|
||||
|
||||
// ex_prefix_mul
|
||||
majel::Dim<3> c = majel::ex_prefix_mul(majel::Dim<3>(3, 4, 5));
|
||||
EXPECT_EQ(majel::get<0>(c), 1);
|
||||
EXPECT_EQ(majel::get<1>(c), 3);
|
||||
EXPECT_EQ(majel::get<2>(c), 12);
|
||||
|
||||
// contiguous_strides
|
||||
c = majel::contiguous_strides(majel::Dim<3>(10, 1, 10));
|
||||
EXPECT_EQ(majel::get<0>(c), 1);
|
||||
EXPECT_EQ(majel::get<1>(c), 0);
|
||||
EXPECT_EQ(majel::get<2>(c), 10);
|
||||
c = majel::contiguous_strides(majel::Dim<3>(10, 10, 1));
|
||||
EXPECT_EQ(majel::get<0>(c), 1);
|
||||
EXPECT_EQ(majel::get<1>(c), 10);
|
||||
EXPECT_EQ(majel::get<2>(c), 0);
|
||||
c = majel::contiguous_strides(majel::Dim<3>(1, 10, 10));
|
||||
EXPECT_EQ(majel::get<0>(c), 0);
|
||||
EXPECT_EQ(majel::get<1>(c), 1);
|
||||
EXPECT_EQ(majel::get<2>(c), 10);
|
||||
c = majel::contiguous_strides(majel::Dim<3>(2, 3, 4));
|
||||
EXPECT_EQ(majel::get<0>(c), 1);
|
||||
EXPECT_EQ(majel::get<1>(c), 2);
|
||||
EXPECT_EQ(majel::get<2>(c), 6);
|
||||
|
||||
// generate from an index
|
||||
auto size = majel::make_dim(4, 5, 2);
|
||||
c = majel::Dim<3>(14, size);
|
||||
EXPECT_EQ(majel::get<0>(c), 2);
|
||||
EXPECT_EQ(majel::get<1>(c), 3);
|
||||
EXPECT_EQ(majel::get<2>(c), 0);
|
||||
c = majel::Dim<3>(25, size);
|
||||
EXPECT_EQ(majel::get<0>(c), 1);
|
||||
EXPECT_EQ(majel::get<1>(c), 1);
|
||||
EXPECT_EQ(majel::get<2>(c), 1);
|
||||
}
|
||||
|
||||
TEST(Dim, Bool) {
|
||||
auto a = majel::make_dim(3, 4);
|
||||
auto b = majel::make_dim(5, 6);
|
||||
auto c = majel::make_dim(3, 4);
|
||||
|
||||
// in_bounds check
|
||||
EXPECT_TRUE(majel::contained(a, b));
|
||||
EXPECT_FALSE(majel::contained(b, a));
|
||||
|
||||
// comparison
|
||||
EXPECT_TRUE(a == a);
|
||||
EXPECT_FALSE(a == b);
|
||||
EXPECT_TRUE(a == c);
|
||||
|
||||
// contiguous check
|
||||
int x = 4, y = 5, z = 2;
|
||||
majel::Dim<3> sizef(x, y, z);
|
||||
majel::Dim<3> stridea(1, x, x*y);
|
||||
majel::Dim<3> strideb(2, 2*x, 2*x*y);
|
||||
majel::Dim<3> stridec(1, x, 2*x*y);
|
||||
EXPECT_TRUE(majel::contiguous(sizef, stridea));
|
||||
EXPECT_FALSE(majel::contiguous(sizef, strideb));
|
||||
EXPECT_FALSE(majel::contiguous(sizef, stridec));
|
||||
}
|
||||
|
||||
TEST(Dim, Print) {
|
||||
{
|
||||
std::stringstream ss;
|
||||
auto a = majel::make_dim(2, 3);
|
||||
ss << a;
|
||||
EXPECT_EQ(ss.str(), "2, 3");
|
||||
}
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << majel::make_dim(8);
|
||||
EXPECT_EQ(ss.str(), "8");
|
||||
}
|
||||
}
|
Loading…
Reference in new issue