From 501ff6dbba447315e2a620b10d282d93f70e1613 Mon Sep 17 00:00:00 2001 From: kafku Date: Sat, 22 Sep 2018 21:06:03 +0900 Subject: [PATCH 01/15] add class for sparse array --- inst/include/RcppArrayFireAs.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/inst/include/RcppArrayFireAs.h b/inst/include/RcppArrayFireAs.h index b0e1921..e90414d 100644 --- a/inst/include/RcppArrayFireAs.h +++ b/inst/include/RcppArrayFireAs.h @@ -47,6 +47,16 @@ namespace RcppArrayFire{ typed_array(const af::array &src_data) : af::array(src_data) {}; }; + template< + af::dtype AF_DTYPE, + af::storage AF_STORAGETYPE = AF_STORAGE_CSR> + class typed_sparray : public af::array{ + public: + typed_sparray() : af::array() {} + ~typed_sparray(){} + typed_sparray(const af::array &src_data) : af::array(src_data) {}; + }; + template class SEXP2CxxPtr : private ::Rcpp::Shield { private: From c4c389dfe068e9210b3fea63e30c8da84dd8c999 Mon Sep 17 00:00:00 2001 From: kafku Date: Sat, 22 Sep 2018 21:07:30 +0900 Subject: [PATCH 02/15] add Exporter for dgRMatrix and dgCMatrix --- inst/include/RcppArrayFireAs.h | 60 ++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/inst/include/RcppArrayFireAs.h b/inst/include/RcppArrayFireAs.h index e90414d..ab4fac9 100644 --- a/inst/include/RcppArrayFireAs.h +++ b/inst/include/RcppArrayFireAs.h @@ -179,6 +179,66 @@ namespace traits { } }; + + // Exporter for CSR matrix (dgRMatrix) + template + class Exporter< ::RcppArrayFire::typed_sparray >{ + private: + S4 d_x; + IntegerVector d_dims, d_j, d_p; + + public: + Exporter(SEXP x) : d_x(x), d_dims(d_x.slot("Dim")), d_j(d_x.slot("j")), d_p(d_x.slot("p")) { + if (!d_x.is("dgRMatrix")) + throw std::invalid_argument("Need S4 class dgRMatrix for a teyped_sparray"); + } + ~Exporter(){} + + ::RcppArrayFire::typed_sparray get() { + typedef typename ::RcppArrayFire::dtype2cpp::type cpp_type ; + ::RcppArrayFire::SEXP2CxxPtr buff( + static_cast(d_x.slot("x")) ) ; + + af::array result; + result = af::sparse( + d_dims[0], d_dims[1], buff.size(), + buff.data(), d_p.begin(), d_j.begin(), + AF_DTYPE, AF_STORAGE_CSR); + + return ::RcppArrayFire::typed_sparray( result ); + } + }; + + // Exporter for CSC matrix (dgCMatrix) + // NOTE: af::sparseConvertTo does not support CSC + template + class Exporter< ::RcppArrayFire::typed_sparray >{ + private: + typedef typename ::RcppArrayFire::dtype2cpp::type cpp_type ; + S4 d_x; + IntegerVector d_dims, d_i, d_p; + + public: + Exporter(SEXP x) : d_x(x), d_dims(d_x.slot("Dim")), d_i(d_x.slot("i")), d_p(d_x.slot("p")) { + if (!d_x.is("dgCMatrix")) + throw std::invalid_argument("Need S4 class dgCMatrix for a teyped_sparray"); + } + ~Exporter(){} + + ::RcppArrayFire::typed_sparray get() { + typedef typename ::RcppArrayFire::dtype2cpp::type cpp_type ; + ::RcppArrayFire::SEXP2CxxPtr buff( + static_cast(d_x.slot("x")) ) ; + + af::array result; + result = af::sparse( + d_dims[0], d_dims[1], buff.size(), + buff.data(), d_i.begin(), d_p.begin(), + AF_DTYPE, AF_STORAGE_CSC); + + return ::RcppArrayFire::typed_sparray( result ); + } + }; } } From e8472310007136dc93c1c98a5d25a466a3b4e736 Mon Sep 17 00:00:00 2001 From: kafku Date: Sun, 23 Sep 2018 09:35:36 +0900 Subject: [PATCH 03/15] implement wrap() for sparse af::array --- inst/include/RcppArrayFireWrap.h | 51 +++++++++++++++++++++- src/RcppArrayFireWrap.cpp | 72 +++++++++++--------------------- 2 files changed, 73 insertions(+), 50 deletions(-) diff --git a/inst/include/RcppArrayFireWrap.h b/inst/include/RcppArrayFireWrap.h index ea44ab3..57bfb5f 100644 --- a/inst/include/RcppArrayFireWrap.h +++ b/inst/include/RcppArrayFireWrap.h @@ -75,11 +75,58 @@ namespace RcppArrayFire{ return ::Rcpp::wrap_extra_steps(x) ; } - template SEXP wrap_array( const af::array& object ){ + + template SEXP wrap_dense_array( const af::array& object ){ return wrap_array_dispatch(object, typename ::Rcpp::traits::r_sexptype_needscast()); } - SEXP af_wrap( const af::array& object ) ; + template SEXP wrap_sparse_array( const af::array& object, const af::storage storage_type ){ + const int RTYPE = Rcpp::traits::r_sexptype_traits::rtype; + + const std::string major = (storage_type == AF_STORAGE_CSR)? "R" : "C"; + std::string klass ; + switch( RTYPE ){ + case REALSXP: + klass = std::string("dg") + major + "Matrix"; + break; + + case LGLSXP: + klass = std::string("lg") + major + "Matrix"; + break; + + default: + throw std::invalid_argument( "RTYPE not matched in conversion to sparse matrix" ); + break; + } + + ::Rcpp::S4 s(klass); + switch ( storage_type ) { + case AF_STORAGE_CSR: + s.slot("p") = wrap_dense_array( af::sparseGetRowIdx( object ) ); + s.slot("j") = wrap_dense_array( af::sparseGetColIdx( object ) ); + break; + + case AF_STORAGE_CSC: + s.slot("i") = wrap_dense_array( af::sparseGetRowIdx( object ) ); + s.slot("p") = wrap_dense_array( af::sparseGetColIdx( object ) ); + break; + } + s.slot("x") = wrap_dense_array( af::sparseGetValues( object ) ); + s.slot("Dim") = ::Rcpp::IntegerVector::create( object.dims(0), object.dims(1) ); + + return s; + } + + template SEXP wrap_array( const af::array& object ){ + if ( object.issparse() ) { + return wrap_sparse_array( object, af::sparseGetStorage( object ) ); + } + else { // if dense array + return wrap_dense_array( object ); + } + } + + SEXP wrap_af_impl( const af::array& object ) ; } /* namespace RcppArrayFire */ #endif diff --git a/src/RcppArrayFireWrap.cpp b/src/RcppArrayFireWrap.cpp index 0ca2a99..415ca5b 100644 --- a/src/RcppArrayFireWrap.cpp +++ b/src/RcppArrayFireWrap.cpp @@ -23,57 +23,33 @@ #include namespace RcppArrayFire{ - SEXP af_wrap( const af::array& object ){ + SEXP wrap_af_impl( const af::array& object ){ ::Rcpp::RObject x; switch(object.type()){ - case f64: - x = wrap_array( object ) ; - break; - case c64: - x = wrap_array>( object ) ; - break; - case f32: - x = wrap_array( object ) ; - break; - case c32: - x = wrap_array>( object ) ; - break; - case s32: - x = wrap_array( object ) ; - break; - case u32: - x = wrap_array( object ) ; - break; - default: - Rcpp::stop("Unsopprted data type"); + case f64: + x = wrap_array( object ) ; + break; + case c64: + x = wrap_array>( object ) ; + break; + case f32: + x = wrap_array( object ) ; + break; + case c32: + x = wrap_array>( object ) ; + break; + case s32: + x = wrap_array( object ) ; + break; + case u32: + x = wrap_array( object ) ; + break; + default: + Rcpp::stop("Unsopprted data type"); + break; } - //NOTE:there is no af::sparse() in the current open source version of arrayfire - //if(object.issparse() == true){ - // const int RTYPE = Rcpp::traits::r_sexptype_traits::rtype; - // IntegerVector dim = IntegerVector::create( object.dims(0), object.dims(1) ); - - // // copy the data into R objects - // Vector x(object.device(), object.device() + object.nonzeros() ) ; - // IntegerVector i(/*begin of the row indices of object*/, /*end*/); - // IntegerVector p(/*begin of the col indices of object*/, /*end*/); - - // std::string klass ; - // switch( RTYPE ){ - // case REALSXP: klass = "dgCMatrix" ; break ; - // // case INTSXP : klass = "igCMatrix" ; break ; class not exported - // case LGLSXP : klass = "lgCMatrix" ; break ; - // default: - // throw std::invalid_argument( "RTYPE not matched in conversion to sparse matrix" ) ; - // } - // S4 s(klass); - // s.slot("i") = i; - // s.slot("p") = p; - // s.slot("x") = x; - // s.slot("Dim") = dim; - // return s; - //} return x; } } /* namespace RcppArrayFire */ @@ -88,8 +64,8 @@ namespace Rcpp{ } template <> SEXP wrap (const af::array& data ){ - ::Rcpp::RObject x = ::RcppArrayFire::af_wrap( data ); - if (data.numdims() > 1) + ::Rcpp::RObject x = ::RcppArrayFire::wrap_af_impl( data ); + if (data.issparse() == false && data.numdims() > 1) x.attr("dim") = wrap(data.dims()); return x; } From badb41526e1e1fbd40b0dcca81619673eda43b69 Mon Sep 17 00:00:00 2001 From: kafku Date: Sun, 23 Sep 2018 11:18:46 +0900 Subject: [PATCH 04/15] add template parameter --- inst/include/RcppArrayFireAs.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/inst/include/RcppArrayFireAs.h b/inst/include/RcppArrayFireAs.h index ab4fac9..3df4ca0 100644 --- a/inst/include/RcppArrayFireAs.h +++ b/inst/include/RcppArrayFireAs.h @@ -205,7 +205,7 @@ namespace traits { buff.data(), d_p.begin(), d_j.begin(), AF_DTYPE, AF_STORAGE_CSR); - return ::RcppArrayFire::typed_sparray( result ); + return ::RcppArrayFire::typed_sparray( result ); } }; @@ -236,7 +236,7 @@ namespace traits { buff.data(), d_i.begin(), d_p.begin(), AF_DTYPE, AF_STORAGE_CSC); - return ::RcppArrayFire::typed_sparray( result ); + return ::RcppArrayFire::typed_sparray( result ); } }; } From 1e81a8e62220ff4a4f4d0a2974ba218353a0b522 Mon Sep 17 00:00:00 2001 From: kafku Date: Sun, 23 Sep 2018 12:04:40 +0900 Subject: [PATCH 05/15] fix type check --- inst/include/RcppArrayFireAs.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/inst/include/RcppArrayFireAs.h b/inst/include/RcppArrayFireAs.h index 3df4ca0..2aef15d 100644 --- a/inst/include/RcppArrayFireAs.h +++ b/inst/include/RcppArrayFireAs.h @@ -189,8 +189,8 @@ namespace traits { public: Exporter(SEXP x) : d_x(x), d_dims(d_x.slot("Dim")), d_j(d_x.slot("j")), d_p(d_x.slot("p")) { - if (!d_x.is("dgRMatrix")) - throw std::invalid_argument("Need S4 class dgRMatrix for a teyped_sparray"); + if (!d_x.is("dgRMatrix") && !d_x.is("lgRMatrix")) + throw std::invalid_argument("Need S4 class dgRMatrix/lgRMatrix for a teyped_sparray"); } ~Exporter(){} @@ -220,8 +220,8 @@ namespace traits { public: Exporter(SEXP x) : d_x(x), d_dims(d_x.slot("Dim")), d_i(d_x.slot("i")), d_p(d_x.slot("p")) { - if (!d_x.is("dgCMatrix")) - throw std::invalid_argument("Need S4 class dgCMatrix for a teyped_sparray"); + if (!d_x.is("dgCMatrix") && !d_x.is("lgCMatrix")) + throw std::invalid_argument("Need S4 class dgCMatrix/lgCMatrix for a teyped_sparray"); } ~Exporter(){} From 0534316e5e645f400c1aec1758833646b4623643 Mon Sep 17 00:00:00 2001 From: kafku Date: Sun, 23 Sep 2018 14:51:57 +0900 Subject: [PATCH 06/15] Exporter for dgTMatrix --- inst/include/RcppArrayFireAs.h | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/inst/include/RcppArrayFireAs.h b/inst/include/RcppArrayFireAs.h index 2aef15d..5726e9f 100644 --- a/inst/include/RcppArrayFireAs.h +++ b/inst/include/RcppArrayFireAs.h @@ -239,6 +239,36 @@ namespace traits { return ::RcppArrayFire::typed_sparray( result ); } }; + + // Exporter for COO matrix (dgTMatrix) + template + class Exporter< ::RcppArrayFire::typed_sparray >{ + private: + typedef typename ::RcppArrayFire::dtype2cpp::type cpp_type ; + S4 d_x; + IntegerVector d_dims, d_i, d_j; + + public: + Exporter(SEXP x) : d_x(x), d_dims(d_x.slot("Dim")), d_i(d_x.slot("i")), d_j(d_x.slot("j")) { + if (!d_x.is("dgTMatrix") && !d_x.is("lgTMatrix")) + throw std::invalid_argument("Need S4 class dgTMatrix/lgTMatrix for a teyped_sparray"); + } + ~Exporter(){} + + ::RcppArrayFire::typed_sparray get() { + typedef typename ::RcppArrayFire::dtype2cpp::type cpp_type ; + ::RcppArrayFire::SEXP2CxxPtr buff( + static_cast(d_x.slot("x")) ) ; + + af::array result; + result = af::sparse( + d_dims[0], d_dims[1], buff.size(), + buff.data(), d_i.begin(), d_j.begin(), + AF_DTYPE, AF_STORAGE_COO); + + return ::RcppArrayFire::typed_sparray( result ); + } + }; } } From 6f6cdcf33f1cf1a6f99983921cc6a11342d8d76c Mon Sep 17 00:00:00 2001 From: kafku Date: Sun, 23 Sep 2018 17:37:34 +0900 Subject: [PATCH 07/15] wrap function for dgTMatrix --- inst/include/RcppArrayFireWrap.h | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/inst/include/RcppArrayFireWrap.h b/inst/include/RcppArrayFireWrap.h index 57bfb5f..3d21ce7 100644 --- a/inst/include/RcppArrayFireWrap.h +++ b/inst/include/RcppArrayFireWrap.h @@ -83,8 +83,14 @@ namespace RcppArrayFire{ template SEXP wrap_sparse_array( const af::array& object, const af::storage storage_type ){ const int RTYPE = Rcpp::traits::r_sexptype_traits::rtype; - const std::string major = (storage_type == AF_STORAGE_CSR)? "R" : "C"; - std::string klass ; + std::string major; + switch ( storage_type ) { + case AF_STORAGE_CSR: major = "R"; break; + case AF_STORAGE_CSC: major = "C"; break; + case AF_STORAGE_COO: major = "T"; break; + } + + std::string klass; switch( RTYPE ){ case REALSXP: klass = std::string("dg") + major + "Matrix"; @@ -110,6 +116,11 @@ namespace RcppArrayFire{ s.slot("i") = wrap_dense_array( af::sparseGetRowIdx( object ) ); s.slot("p") = wrap_dense_array( af::sparseGetColIdx( object ) ); break; + + case AF_STORAGE_COO: + s.slot("i") = wrap_dense_array( af::sparseGetRowIdx( object ) ); + s.slot("j") = wrap_dense_array( af::sparseGetColIdx( object ) ); + break; } s.slot("x") = wrap_dense_array( af::sparseGetValues( object ) ); s.slot("Dim") = ::Rcpp::IntegerVector::create( object.dims(0), object.dims(1) ); From fff23193857188a6ec590ea8c0c382ad8973a72b Mon Sep 17 00:00:00 2001 From: kafku Date: Tue, 25 Sep 2018 12:33:01 +0900 Subject: [PATCH 08/15] use typed_array instead of typed_sparray --- inst/include/RcppArrayFireAs.h | 44 ++++++++++++----------------- inst/include/RcppArrayFireForward.h | 8 ++++-- 2 files changed, 24 insertions(+), 28 deletions(-) diff --git a/inst/include/RcppArrayFireAs.h b/inst/include/RcppArrayFireAs.h index 5726e9f..d181d8c 100644 --- a/inst/include/RcppArrayFireAs.h +++ b/inst/include/RcppArrayFireAs.h @@ -39,7 +39,9 @@ namespace RcppArrayFire{ template<> struct dtype2cpp{ typedef unsigned int type ; }; - template + template< + af::dtype AF_DTYPE, + af::storage AF_STORAGETYPE = AF_STORAGE_DENSE> class typed_array : public af::array{ public: typed_array() : af::array() {} @@ -47,16 +49,6 @@ namespace RcppArrayFire{ typed_array(const af::array &src_data) : af::array(src_data) {}; }; - template< - af::dtype AF_DTYPE, - af::storage AF_STORAGETYPE = AF_STORAGE_CSR> - class typed_sparray : public af::array{ - public: - typed_sparray() : af::array() {} - ~typed_sparray(){} - typed_sparray(const af::array &src_data) : af::array(src_data) {}; - }; - template class SEXP2CxxPtr : private ::Rcpp::Shield { private: @@ -147,7 +139,7 @@ namespace internal{ namespace traits { template - class Exporter< ::RcppArrayFire::typed_array >{ + class Exporter< ::RcppArrayFire::typed_array >{ private: SEXP object ; @@ -155,7 +147,7 @@ namespace traits { Exporter( SEXP x ) : object(x){} ~Exporter(){} - ::RcppArrayFire::typed_array get() { + ::RcppArrayFire::typed_array get() { typedef typename ::RcppArrayFire::dtype2cpp::type cpp_type ; //std::vector buff( Rf_length( object ) ); @@ -175,14 +167,14 @@ namespace traits { result = af::array(::Rcpp::as(dims), buff.data()); } - return ::RcppArrayFire::typed_array( result ); + return ::RcppArrayFire::typed_array( result ); } }; // Exporter for CSR matrix (dgRMatrix) template - class Exporter< ::RcppArrayFire::typed_sparray >{ + class Exporter< ::RcppArrayFire::typed_array >{ private: S4 d_x; IntegerVector d_dims, d_j, d_p; @@ -190,11 +182,11 @@ namespace traits { public: Exporter(SEXP x) : d_x(x), d_dims(d_x.slot("Dim")), d_j(d_x.slot("j")), d_p(d_x.slot("p")) { if (!d_x.is("dgRMatrix") && !d_x.is("lgRMatrix")) - throw std::invalid_argument("Need S4 class dgRMatrix/lgRMatrix for a teyped_sparray"); + throw std::invalid_argument("Need S4 class dgRMatrix/lgRMatrix for a teyped_array"); } ~Exporter(){} - ::RcppArrayFire::typed_sparray get() { + ::RcppArrayFire::typed_array get() { typedef typename ::RcppArrayFire::dtype2cpp::type cpp_type ; ::RcppArrayFire::SEXP2CxxPtr buff( static_cast(d_x.slot("x")) ) ; @@ -205,14 +197,14 @@ namespace traits { buff.data(), d_p.begin(), d_j.begin(), AF_DTYPE, AF_STORAGE_CSR); - return ::RcppArrayFire::typed_sparray( result ); + return ::RcppArrayFire::typed_array( result ); } }; // Exporter for CSC matrix (dgCMatrix) // NOTE: af::sparseConvertTo does not support CSC template - class Exporter< ::RcppArrayFire::typed_sparray >{ + class Exporter< ::RcppArrayFire::typed_array >{ private: typedef typename ::RcppArrayFire::dtype2cpp::type cpp_type ; S4 d_x; @@ -221,11 +213,11 @@ namespace traits { public: Exporter(SEXP x) : d_x(x), d_dims(d_x.slot("Dim")), d_i(d_x.slot("i")), d_p(d_x.slot("p")) { if (!d_x.is("dgCMatrix") && !d_x.is("lgCMatrix")) - throw std::invalid_argument("Need S4 class dgCMatrix/lgCMatrix for a teyped_sparray"); + throw std::invalid_argument("Need S4 class dgCMatrix/lgCMatrix for a teyped_array"); } ~Exporter(){} - ::RcppArrayFire::typed_sparray get() { + ::RcppArrayFire::typed_array get() { typedef typename ::RcppArrayFire::dtype2cpp::type cpp_type ; ::RcppArrayFire::SEXP2CxxPtr buff( static_cast(d_x.slot("x")) ) ; @@ -236,13 +228,13 @@ namespace traits { buff.data(), d_i.begin(), d_p.begin(), AF_DTYPE, AF_STORAGE_CSC); - return ::RcppArrayFire::typed_sparray( result ); + return ::RcppArrayFire::typed_array( result ); } }; // Exporter for COO matrix (dgTMatrix) template - class Exporter< ::RcppArrayFire::typed_sparray >{ + class Exporter< ::RcppArrayFire::typed_array >{ private: typedef typename ::RcppArrayFire::dtype2cpp::type cpp_type ; S4 d_x; @@ -251,11 +243,11 @@ namespace traits { public: Exporter(SEXP x) : d_x(x), d_dims(d_x.slot("Dim")), d_i(d_x.slot("i")), d_j(d_x.slot("j")) { if (!d_x.is("dgTMatrix") && !d_x.is("lgTMatrix")) - throw std::invalid_argument("Need S4 class dgTMatrix/lgTMatrix for a teyped_sparray"); + throw std::invalid_argument("Need S4 class dgTMatrix/lgTMatrix for a teyped_array"); } ~Exporter(){} - ::RcppArrayFire::typed_sparray get() { + ::RcppArrayFire::typed_array get() { typedef typename ::RcppArrayFire::dtype2cpp::type cpp_type ; ::RcppArrayFire::SEXP2CxxPtr buff( static_cast(d_x.slot("x")) ) ; @@ -266,7 +258,7 @@ namespace traits { buff.data(), d_i.begin(), d_j.begin(), AF_DTYPE, AF_STORAGE_COO); - return ::RcppArrayFire::typed_sparray( result ); + return ::RcppArrayFire::typed_array( result ); } }; } diff --git a/inst/include/RcppArrayFireForward.h b/inst/include/RcppArrayFireForward.h index 9b37088..59de307 100644 --- a/inst/include/RcppArrayFireForward.h +++ b/inst/include/RcppArrayFireForward.h @@ -30,7 +30,9 @@ /* forward declarations */ namespace RcppArrayFire{ - template class typed_array; + template< + af::dtype AF_DTYPE, + af::storage AF_STORAGETYPE> class typed_array; } namespace Rcpp { @@ -43,7 +45,9 @@ namespace Rcpp { namespace traits { /* support for as */ - template class Exporter>; + template< + af::dtype AF_DTYPE, + af::storage AF_STORAGETYPE> class Exporter>; } } From dae39b1fd670e18a15235fadf453f50c76815f70 Mon Sep 17 00:00:00 2001 From: kafku Date: Tue, 25 Sep 2018 13:14:23 +0900 Subject: [PATCH 09/15] add af_storage_traits --- inst/include/RcppArrayFireAs.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/inst/include/RcppArrayFireAs.h b/inst/include/RcppArrayFireAs.h index d181d8c..d8c9eeb 100644 --- a/inst/include/RcppArrayFireAs.h +++ b/inst/include/RcppArrayFireAs.h @@ -38,6 +38,31 @@ namespace RcppArrayFire{ template<> struct dtype2cpp{ typedef int type ; }; template<> struct dtype2cpp{ typedef unsigned int type ; }; + template struct af_storage_traits{}; + template<> struct af_storage_traits{ + static constexpr auto row_idx = "p"; + static constexpr auto col_idx = "j"; + static void check_s4_class(const ::Rcpp::S4 &x){ + if(!x.is("dgRMatrix") && !x.is("lgRMatrix")) + throw std::invalid_argument("Need S4 class dgRMatrix/lgRMatrix for a teyped_array"); + } + }; + template<> struct af_storage_traits{ + static constexpr auto row_idx = "i"; + static constexpr auto col_idx = "p"; + static void check_s4_class(const ::Rcpp::S4 &x){ + if(!x.is("dgCMatrix") && !x.is("lgCMatrix")) + throw std::invalid_argument("Need S4 class dgCMatrix/lgCMatrix for a teyped_array"); + } + }; + template<> struct af_storage_traits{ + static constexpr auto row_idx = "i"; + static constexpr auto col_idx = "j"; + static void check_s4_class(const ::Rcpp::S4 &x){ + if(!x.is("dgTMatrix") && !x.is("lgTMatrix")) + throw std::invalid_argument("Need S4 class dgTMatrix/lgTMatrix for a teyped_array"); + } + }; template< af::dtype AF_DTYPE, From bd18d51b34bf0fb98a7d552518145caf6819e16b Mon Sep 17 00:00:00 2001 From: kafku Date: Tue, 25 Sep 2018 13:24:59 +0900 Subject: [PATCH 10/15] remove duplicated code --- inst/include/RcppArrayFireAs.h | 85 ++++++---------------------------- 1 file changed, 13 insertions(+), 72 deletions(-) diff --git a/inst/include/RcppArrayFireAs.h b/inst/include/RcppArrayFireAs.h index d8c9eeb..381ca1d 100644 --- a/inst/include/RcppArrayFireAs.h +++ b/inst/include/RcppArrayFireAs.h @@ -197,82 +197,23 @@ namespace traits { }; - // Exporter for CSR matrix (dgRMatrix) - template - class Exporter< ::RcppArrayFire::typed_array >{ - private: - S4 d_x; - IntegerVector d_dims, d_j, d_p; - - public: - Exporter(SEXP x) : d_x(x), d_dims(d_x.slot("Dim")), d_j(d_x.slot("j")), d_p(d_x.slot("p")) { - if (!d_x.is("dgRMatrix") && !d_x.is("lgRMatrix")) - throw std::invalid_argument("Need S4 class dgRMatrix/lgRMatrix for a teyped_array"); - } - ~Exporter(){} - - ::RcppArrayFire::typed_array get() { - typedef typename ::RcppArrayFire::dtype2cpp::type cpp_type ; - ::RcppArrayFire::SEXP2CxxPtr buff( - static_cast(d_x.slot("x")) ) ; - - af::array result; - result = af::sparse( - d_dims[0], d_dims[1], buff.size(), - buff.data(), d_p.begin(), d_j.begin(), - AF_DTYPE, AF_STORAGE_CSR); - - return ::RcppArrayFire::typed_array( result ); - } - }; - - // Exporter for CSC matrix (dgCMatrix) - // NOTE: af::sparseConvertTo does not support CSC - template - class Exporter< ::RcppArrayFire::typed_array >{ + // Exporter for compressed matrix (dgRMatrix, dgCMatrix, dgTMatrix) + template + class Exporter< ::RcppArrayFire::typed_array >{ private: - typedef typename ::RcppArrayFire::dtype2cpp::type cpp_type ; S4 d_x; - IntegerVector d_dims, d_i, d_p; + IntegerVector d_dims, d_row, d_col; public: - Exporter(SEXP x) : d_x(x), d_dims(d_x.slot("Dim")), d_i(d_x.slot("i")), d_p(d_x.slot("p")) { - if (!d_x.is("dgCMatrix") && !d_x.is("lgCMatrix")) - throw std::invalid_argument("Need S4 class dgCMatrix/lgCMatrix for a teyped_array"); - } - ~Exporter(){} - - ::RcppArrayFire::typed_array get() { - typedef typename ::RcppArrayFire::dtype2cpp::type cpp_type ; - ::RcppArrayFire::SEXP2CxxPtr buff( - static_cast(d_x.slot("x")) ) ; - - af::array result; - result = af::sparse( - d_dims[0], d_dims[1], buff.size(), - buff.data(), d_i.begin(), d_p.begin(), - AF_DTYPE, AF_STORAGE_CSC); - - return ::RcppArrayFire::typed_array( result ); - } - }; - - // Exporter for COO matrix (dgTMatrix) - template - class Exporter< ::RcppArrayFire::typed_array >{ - private: - typedef typename ::RcppArrayFire::dtype2cpp::type cpp_type ; - S4 d_x; - IntegerVector d_dims, d_i, d_j; - - public: - Exporter(SEXP x) : d_x(x), d_dims(d_x.slot("Dim")), d_i(d_x.slot("i")), d_j(d_x.slot("j")) { - if (!d_x.is("dgTMatrix") && !d_x.is("lgTMatrix")) - throw std::invalid_argument("Need S4 class dgTMatrix/lgTMatrix for a teyped_array"); + Exporter(SEXP x) : d_x(x) { + ::RcppArrayFire::af_storage_traits::check_s4_class(d_x); + d_dims = d_x.slot("Dim"); + d_row = d_x.slot(::RcppArrayFire::af_storage_traits::row_idx); + d_col = d_x.slot(::RcppArrayFire::af_storage_traits::col_idx); } ~Exporter(){} - ::RcppArrayFire::typed_array get() { + ::RcppArrayFire::typed_array get() { typedef typename ::RcppArrayFire::dtype2cpp::type cpp_type ; ::RcppArrayFire::SEXP2CxxPtr buff( static_cast(d_x.slot("x")) ) ; @@ -280,10 +221,10 @@ namespace traits { af::array result; result = af::sparse( d_dims[0], d_dims[1], buff.size(), - buff.data(), d_i.begin(), d_j.begin(), - AF_DTYPE, AF_STORAGE_COO); + buff.data(), d_row.begin(), d_col.begin(), + AF_DTYPE, AF_STORAGETYPE); - return ::RcppArrayFire::typed_array( result ); + return ::RcppArrayFire::typed_array( result ); } }; } From 9ad8e317f0af65868f3920336babafa6afd73a96 Mon Sep 17 00:00:00 2001 From: kafku Date: Tue, 25 Sep 2018 14:03:18 +0900 Subject: [PATCH 11/15] fix check function --- inst/include/RcppArrayFireAs.h | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/inst/include/RcppArrayFireAs.h b/inst/include/RcppArrayFireAs.h index 381ca1d..2078558 100644 --- a/inst/include/RcppArrayFireAs.h +++ b/inst/include/RcppArrayFireAs.h @@ -42,25 +42,25 @@ namespace RcppArrayFire{ template<> struct af_storage_traits{ static constexpr auto row_idx = "p"; static constexpr auto col_idx = "j"; - static void check_s4_class(const ::Rcpp::S4 &x){ - if(!x.is("dgRMatrix") && !x.is("lgRMatrix")) - throw std::invalid_argument("Need S4 class dgRMatrix/lgRMatrix for a teyped_array"); + static void check_s4_class(const SEXP &x){ + if(!Rf_inherits(x, "dgRMatrix") && !Rf_inherits(x, "lgRMatrix")) + throw std::invalid_argument("Need S4 class dgRMatrix/lgRMatrix for a typed_array"); } }; template<> struct af_storage_traits{ static constexpr auto row_idx = "i"; static constexpr auto col_idx = "p"; - static void check_s4_class(const ::Rcpp::S4 &x){ - if(!x.is("dgCMatrix") && !x.is("lgCMatrix")) - throw std::invalid_argument("Need S4 class dgCMatrix/lgCMatrix for a teyped_array"); + static void check_s4_class(const SEXP &x){ + if(!Rf_inherits(x, "dgCMatrix") && !Rf_inherits(x, "lgCMatrix")) + throw std::invalid_argument("Need S4 class dgCMatrix/lgCMatrix for a typed_array"); } }; template<> struct af_storage_traits{ static constexpr auto row_idx = "i"; static constexpr auto col_idx = "j"; - static void check_s4_class(const ::Rcpp::S4 &x){ - if(!x.is("dgTMatrix") && !x.is("lgTMatrix")) - throw std::invalid_argument("Need S4 class dgTMatrix/lgTMatrix for a teyped_array"); + static void check_s4_class(const SEXP &x){ + if(!Rf_inherits(x, "dgTMatrix") && !Rf_inherits(x, "lgTMatrix")) + throw std::invalid_argument("Need S4 class dgTMatrix/lgTMatrix for a typed_array"); } }; @@ -205,8 +205,9 @@ namespace traits { IntegerVector d_dims, d_row, d_col; public: - Exporter(SEXP x) : d_x(x) { - ::RcppArrayFire::af_storage_traits::check_s4_class(d_x); + Exporter(SEXP x){ + ::RcppArrayFire::af_storage_traits::check_s4_class(x); + d_x = x; d_dims = d_x.slot("Dim"); d_row = d_x.slot(::RcppArrayFire::af_storage_traits::row_idx); d_col = d_x.slot(::RcppArrayFire::af_storage_traits::col_idx); From 2b9b8aa54a5cb1dc4cf1ac855a8a5c701b29bf43 Mon Sep 17 00:00:00 2001 From: kafku Date: Tue, 25 Sep 2018 17:11:10 +0900 Subject: [PATCH 12/15] add tests to check sparse arrays --- tests/testthat/test-exporter-wrap-sparse.R | 60 ++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 tests/testthat/test-exporter-wrap-sparse.R diff --git a/tests/testthat/test-exporter-wrap-sparse.R b/tests/testthat/test-exporter-wrap-sparse.R new file mode 100644 index 0000000..6cd487f --- /dev/null +++ b/tests/testthat/test-exporter-wrap-sparse.R @@ -0,0 +1,60 @@ +context("export and wrap sparse array") + +library(Matrix) +library(Rcpp) + +create.src <- function(dtype, storage){ + src.template <- ' + af::array asis%s_%s(const RcppArrayFire::typed_array<%s, AF_STORAGE_%s>& x) { + return x; + }' + fill.template <- function(d, s){ + sprintf(src.template, s, d, d, s) + } + + return(outer(dtype, storage, FUN = fill.template)) +} + +# NOTE: Matrix package <= 1.2-14 does not support integer and complex matrices +# NOTE: Arrayfire v3.6.1 only supports f64/f32/c64/c32 +# TODO: Add some tests for other data types(complex, bool, etc.) when they are supported. +for (src in create.src(c('f64', 'f32'), c('CSR', 'CSC', 'COO'))){ + Rcpp::cppFunction(code = src, depends = "RcppArrayFire") +} + +test_that("export and wrap CSR array", { + x <- as(matrix(c(1, 0, 0, 2, 3, + 0, 0, 1, 0, 2), 2, 5), + 'dgRMatrix') + invalid.x <- new('dgCMatrix') + + expect_equal(x, asisCSR_f64(x)) + expect_equal(x, asisCSR_f32(x)) + expect_error(asisCSR_f64(invalid.x)) +}) + + +test_that("export and wrap CSC array", { + x <- as(matrix(c(1, 0, 0, 2, 3, + 0, 0, 1, 0, 2), 2, 5), + 'dgCMatrix') + invalid.x <- new('dgRMatrix') + + expect_equal(x, asisCSC_f64(x)) + expect_equal(x, asisCSC_f32(x)) + expect_error(asisCSC_f64(invalid.x)) +}) + + +test_that("export and wrap COO array", { + x <- as(matrix(c(1, 0, 0, 2, 3, + 0, 0, 1, 0, 2), 2, 5), + 'dgTMatrix') + invalid.x <- new('dgCMatrix') + + expect_equal(x, asisCOO_f64(x)) + expect_equal(x, asisCOO_f32(x)) + expect_error(asisCOO_f64(invalid.x)) + +}) + From e2c35518cb77b9fe48b814e0b5ff1e2b72dd5799 Mon Sep 17 00:00:00 2001 From: kafku Date: Tue, 25 Sep 2018 17:17:29 +0900 Subject: [PATCH 13/15] throw when lg*Mtarix is given --- inst/include/RcppArrayFireAs.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/inst/include/RcppArrayFireAs.h b/inst/include/RcppArrayFireAs.h index 2078558..6f0334c 100644 --- a/inst/include/RcppArrayFireAs.h +++ b/inst/include/RcppArrayFireAs.h @@ -43,24 +43,24 @@ namespace RcppArrayFire{ static constexpr auto row_idx = "p"; static constexpr auto col_idx = "j"; static void check_s4_class(const SEXP &x){ - if(!Rf_inherits(x, "dgRMatrix") && !Rf_inherits(x, "lgRMatrix")) - throw std::invalid_argument("Need S4 class dgRMatrix/lgRMatrix for a typed_array"); + if(!Rf_inherits(x, "dgRMatrix")) + throw std::invalid_argument("Need S4 class dgRMatrix for a typed_array"); } }; template<> struct af_storage_traits{ static constexpr auto row_idx = "i"; static constexpr auto col_idx = "p"; static void check_s4_class(const SEXP &x){ - if(!Rf_inherits(x, "dgCMatrix") && !Rf_inherits(x, "lgCMatrix")) - throw std::invalid_argument("Need S4 class dgCMatrix/lgCMatrix for a typed_array"); + if(!Rf_inherits(x, "dgCMatrix")) + throw std::invalid_argument("Need S4 class dgCMatrix for a typed_array"); } }; template<> struct af_storage_traits{ static constexpr auto row_idx = "i"; static constexpr auto col_idx = "j"; static void check_s4_class(const SEXP &x){ - if(!Rf_inherits(x, "dgTMatrix") && !Rf_inherits(x, "lgTMatrix")) - throw std::invalid_argument("Need S4 class dgTMatrix/lgTMatrix for a typed_array"); + if(!Rf_inherits(x, "dgTMatrix")) + throw std::invalid_argument("Need S4 class dgTMatrix for a typed_array"); } }; From 7ed0d08a03e131488bcb59ccecd1fbbf0e6dfddd Mon Sep 17 00:00:00 2001 From: kafku Date: Tue, 25 Sep 2018 17:40:09 +0900 Subject: [PATCH 14/15] add Matrix package to r_packages --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 4d7063d..b53a6e6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,6 +19,7 @@ r_packages: - knitr - rmarkdown - pkgKitten + - Matrix addons: apt: sources: From 94645f1895596a7959bfa48e40d47da76e81f65e Mon Sep 17 00:00:00 2001 From: kafku Date: Tue, 25 Sep 2018 17:56:56 +0900 Subject: [PATCH 15/15] add Matrix package to DESCRIPTION --- DESCRIPTION | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 4def4c0..1dc79ce 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -25,5 +25,6 @@ Suggests: pkgKitten, rmarkdown, covr, testthat, - inline + inline, + Matrix VignetteBuilder: knitr