2014-07-08 98 views
7

我正在開發中Rcpp是從bigmemorybig.matrix對象進行操作某些功能的不同類型的變量。這些對象被傳遞到作爲Rcpp對象SEXP我然後必須強制轉換爲XPtr<BigMatrix>,然後到一個MatrixAccessor對象來訪問矩陣的元素。初始化基於switch語句

例如,如果我想要實現的是得到一個功能就是對角線:

#include <Rcpp.h> 
using namespace Rcpp; 

// [[Rcpp::depends(BH, bigmemory) 
#include <bigmemory/MatrixAccessor.hpp> 

#include <numeric> 

// [[Rcpp::export]] 
NumericVector GetDiag(SEXP pmat) { 
    XPtr<BigMatrix> xpMat(pMat); // allows you to access attributes 
    MatrixAccessor<double> mat(*xpMat); // allows you to access matrix elements 

    NumericVector diag(xpMat->nrow()); // Assume matrix is square 
    for (int i = 0; i < xpMat->nrow(); i++) { 
    diag[i] = mat[i][i]; 
    } 
    return diag; 
} 

此功能精美,提供R中的big.matrix對象充滿了一倍。

但是,如果您在整數矩陣(例如diag(as.big.matrix(matrix(1:9, 3))@address))上調用此函數,則會因此導致垃圾回收,因爲MatrixAccessor已被初始化爲<double>

內部,big.matrix對象可以有四種類型:

void typeof(SEXP pMat) { 
    XPtr<BigMatrix> xpMat(pMat); 
    int type = xpMat->matrix_type(); 
    type == 1 // char 
    type == 2 // short 
    type == 4 // int 
    type == 8 // double 
} 

由於所有我們正在做的是訪問矩陣的元素,在diag功能應該能夠處理這些類型。但是現在,由於我們的函數簽名是NumericVector,我會忽略字符矩陣。

爲了解決這個問題,我想我可能只是扔在一個switch語句,在運行時使用合適的類型初始化相應mat

// [[Rcpp::export]] 
NumericVector GetDiag(SEXP pmat) { 
    XPtr<BigMatrix> xpMat(pMat); 
    // Determine the typeof(pmat), and initialize accordingly: 
    switch(xpMat->matrix_type()) { 
    case == 1: 
    { 
     // Function expects to return a NumericVector. 
     throw; 
    } 
    case == 2: 
    { 
     MatrixAccessor<short> mat(*xpMat); 
     break; 
    } 
    case == 4: 
    { 
     MatrixAccessor<int> mat(*xpMat); 
     break; 
    } 
    case == 8: 
    { 
     MatrixAccessor<double> mat(*xpMat); 
    } 
    } 
    MatrixAccessor<double> mat(*xpMat); // allows you to access matrix elements 

    NumericVector diag(xpMat->nrow()); // Assume matrix is square 
    for (int i = 0; i < xpMat->nrow(); i++) { 
    diag[i] = mat[i][i]; 
    } 
    return diag; 
} 

然而,這會導致編譯器錯誤,因爲我重新定義mat已經在第一個case中聲明之後。

我可以看到要做到這一點的唯一方法是編寫三種不同的diag函數,每種類型一個,其代碼與mat的初始化例外相同。有沒有更好的辦法?

回答

7

感謝來自Kevin Ushey關於分離調度和函數邏輯的指針。所需的模板代碼與凱文的建議足夠不同,以保證自己的答案。

要寫一個普遍適用於所有類型的big.matrix功能,該模式如下:

#include <Rcpp.h> 
using namespace Rcpp; 

// [[Rcpp::depends(BH, bigmemory)]] 
#include <bigmemory/MatrixAccessor.hpp> 

// Generic Implementation of GetDiag: 
template <typename T> 
NumericVector GetDiag_impl(XPtr<BigMatrix> xpMat, MatrixAccessor<T> mat) { 
    NumericVector diag(xpMat->nrow()); // Assume matrix is square 
    for (unsigned int i = 0; i < xpMat->nrow(); i++) { 
    diag[i] = mat[i][i]; 
    } 
    return diag; 
} 

// Dispatch code 
// [[Rcpp::export]] 
NumericVector GetDiag(SEXP pMat) { 
    XPtr<BigMatrix> xpMat(pMat); 
    switch(xpMat->matrix_type()) { 
    case 1: 
     return GetDiag_impl(xpMat, MatrixAccessor<char>(*xpMat)); 
    case 2: 
     return GetDiag_impl(xpMat, MatrixAccessor<short>(*xpMat)); 
    case 4: 
     return GetDiag_impl(xpMat, MatrixAccessor<int>(*xpMat)); 
    case 8: 
     return GetDiag_impl(xpMat, MatrixAccessor<double>(*xpMat)); 
    default: 
     // This should be impossible to reach, but shuts up the compiler 
     throw Rcpp::exception("Unknown type of big.matrix detected! Aborting."); 
    } 
} 

您不需要模板GetDiag_impl返回類型:所有四個big.matrix類型存儲爲數字在R中(關於'char'big.matrix對象的討論見This Answer)。

+1

感謝您的支持,並將其作爲[bigmemory文章](http://gallery.rcpp.org/articles/using-bigmemory-with-rcpp/)的修訂版移至Rcpp Gallery。 –

7

在這些情況下,您通常需要分離邏輯:首先,您有一個調度函數,它將SEXP類型編組爲一些編譯時類型,以及一個處理實際工作的單獨(模板化)函數。一些(不完整的)示例代碼:

#include <Rcpp.h> 
using namespace Rcpp; 

// the actual generic implementation 
template <typename T> 
T GetDiag_impl(T const& pMat) { 
    // logic goes here 
} 

// the dispatch code 

// [[Rcpp::export]] 
SEXP GetDiag(SEXP pMat) { 
    switch (TYPEOF(pMat)) { 
    case INTSXP: return GetDiag_impl<IntegerMatrix>(pMat); 
    case REALSXP: return GetDiag_impl<NumericMatrix>(pMat); 
    <...> 
    } 
} 
+0

謝謝,我會試試看 –

+0

感謝您的指點,我到底到了那裏。我需要實現的模板與您的答案非常不同,因此我添加了一般設計模式作爲答案,並且會爲Rmepp Gallery示例中的bigmemory寫入一個附加內容。 –

+1

嘿凱文...我只是意識到,我無法分裂兩個用戶之間的賞金。我打算授予你50和@ScottRitchie 50作爲你的帖子非常有幫助。任何人,我會打開另一個賞金,並在1天的強制等待期後直接授予您。 –