Приведение BigMatrix/массива к матрице Armadillo

У меня есть big.matrix, который я хочу преобразовать в arma::Mat, чтобы использовать функциональность линейной алгебры Armadillo.

Тем не менее, я не могу заставить актеров работать.

Насколько я могу понять из чтения, оба внутренне хранятся в основном формате столбца, а фактический матричный компонент big.matrix является просто указателем типа <T> (char/short/int/double)

Следующий код компилируется, но приведение к arma::Mat не работает, возникает ошибка сегментации при повторении матрицы приведения.

#include <RcppArmadillo.h>
using namespace Rcpp;

// [[Rcpp::depends(BH, bigmemory, RcppArmadillo)]]
#include <bigmemory/BigMatrix.h>

template <typename T>
void armacast(const arma::Mat<T>& M) {
  // This segfaults
  for (int j = 0; j < 2; j++) {
    for (int i = 0; i < 2; i++) {
      std::cout << M.at(j, i) << std::endl;
    }   
  }
  std::cout << "Success!" << std::endl;                                                                                                                                                                                                       
}

// [[Rcpp::export]]
void armacast(SEXP pDat) {
  XPtr<BigMatrix> xpDat(pDat);

  if (xpDat->matrix_type() == 8) {
    // I can iterate over this *mat and get sensible output.
    double *mat = (double *)xpDat->matrix();
    for (int j = 0; j < 2; j++) {
      for (int i = 0; i < 2; i++) {
        std::cout << *mat + 2 * (j + 0) + i << std::endl;
      }   
    }
    armacast((const arma::Mat<double> &)mat);
  } else {
    std::cout << "Not implemented yet!" << std::endl;
  }
}

In R:

library(Rcpp)
library(RcppArmadillo)
library(bigmemory)
sourceCpp("armacast.cpp")
m <- as.big.matrix(matrix(1:4, 2), type="double")
armacast(m@address)

person Scott Ritchie    schedule 24.07.2014    source источник
comment
как насчет того, чтобы записать big.matrix в файл, а затем использовать метод броненосца load() для автоматического получения мата броненосца?   -  person Emma    schedule 24.07.2014
comment
Файловые интерфейсы — это самое последнее средство, которое следует рассматривать только тогда, когда ваша жизнь находится в опасности.   -  person Dirk Eddelbuettel    schedule 24.07.2014


Ответы (1)


Отличный вопрос! Мы можем превратить это в еще один пост в галерее Rcpp.

Есть одна важная деталь, которую вы, возможно, упустили из виду. Объекты большой памяти являются внешними, поэтому мы заставляем R не допускать вмешательства в управление памятью. У Armadillo есть конструкторы для этого (и, пожалуйста, прочитайте там документацию и предупреждения), поэтому в первую очередь мы можем просто сделать

arma::mat M( (double*) xpDat->matrix(), xpDat->nrow(), xpDat->ncol(), false);

где мы используем указатель на данные матрицы, а также количество строк и столбцов. Полная версия:

// [[Rcpp::export]]
void armacast(SEXP pDat) {
  XPtr<BigMatrix> xpDat(pDat);

  if (xpDat->matrix_type() == 8) {
    arma::mat M(mat, xpDat->nrow(), xpDat>-ncol(), false);
    M.print("Arma matrix M");
  } else {
    std::cout << "Not implemented yet!" << std::endl;
  }
}

Он правильно вызывает метод печати из Armadillo:

R> armacast(m@address)
Arma matrix M
   1.0000   3.0000
   2.0000   4.0000
R> 
person Dirk Eddelbuettel    schedule 24.07.2014
comment
Круто, спасибо, Дирк! Для справки, объект внешнего указателя имеет поля nrow и ncol, поэтому вы можете просто включить xpDat->nrow() и xpDat->ncol() в качестве второго и третьего аргументов конструктора mat. - person Scott Ritchie; 25.07.2014