Большой объект SpMat с RcppArmadillo

Я пытаюсь изучить и использовать Rcpp и RcppArmadillo для разреженных подпрограмм линейной алгебры.

Код ниже является адаптацией приведенного здесь примера: http://gallery.rcpp.org/articles/armadillo-sparse-matrix/

code <- '
  S4 matx(x);
  IntegerVector Xd = matx.slot("Dim");
  IntegerVector Xi = matx.slot("i");
  IntegerVector Xp = matx.slot("p");
  NumericVector Xx = matx.slot("x");

  arma::sp_mat Xsp(Xd[0], Xd[1]);

  // create space for values, and copy
  arma::access::rw(Xsp.values) = arma::memory::acquire_chunked<double>(Xx.size() + 1);
  arma::arrayops::copy(arma::access::rwp(Xsp.values), 
             Xx.begin(), 
             Xx.size() + 1);

  // create space for row_indices, and copy -- so far in a lame loop
  arma::access::rw(Xsp.row_indices) = arma::memory::acquire_chunked<arma::uword>(Xx.size() + 1);
  for (int j=0; j<Xi.size(); j++)
    arma::access::rwp(Xsp.row_indices)[j] = Xi[j];

  // create space for col_ptrs, and copy -- so far in a lame loop
  arma::access::rw(Xsp.col_ptrs) = arma::memory::acquire_chunked<arma::uword>(Xp.size() + 1);
  for (int j=0; j<Xp.size(); j++)
      arma::access::rwp(Xsp.col_ptrs)[j] = Xp[j];

  // important: set the sentinel as well
  arma::access::rwp(Xsp.col_ptrs)[Xp.size()+1] = std::numeric_limits<arma::uword>::max();

  // set the number of non-zero elements
  arma::access::rw(Xsp.n_nonzero) = Xx.size();

  Rcout << "SpMat Xsp:\\n" << arma::dot(Xsp,Xsp) << std::endl;
'

norm2 <- cxxfunction(signature(x="Matrix"),
                     code,plugin="RcppArmadillo")

Когда я использую вектор 1e4, все работает нормально:

> p <- 10000
> X <- Matrix(rnorm(p),sparse=TRUE)
> norm2(X)
SpMat Xsp:
9997.14
NULL

Однако, когда я использую вектор длины 1e5, возникает ошибка

> p <- 100000
> X <- Matrix(rnorm(p),sparse=TRUE)
> norm2(X)

error: SpMat::init(): requested size is too large

Error: 
>

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

============== подробнее ==============

Проблема, похоже, связана с размером> = 2 ^ 16 = 65536

Следующие работы:

> m <- 1000
> n <- 65535
> nnz <- 10000
> iind <- sample.int(m,nnz,replace=TRUE)
> jind <- sample.int(n,nnz,replace=TRUE)
> xval <- rnorm(nnz)
> X <- sparseMatrix(i=iind,j=jind,x=xval,dims=c(m,n))
> norm2(X)
SpMat Xsp:
10029.8
NULL

Следующее не работает:

> m <- 1000
> n <- 65536
> nnz <- 10000
> iind <- sample.int(m,nnz,replace=TRUE)
> jind <- sample.int(n,nnz,replace=TRUE)
> xval <- rnorm(nnz)
> X <- sparseMatrix(i=iind,j=jind,x=xval,dims=c(m,n))
> norm2(X)

error: SpMat::init(): requested size is too large

Error: 
> 

Почему это так?


person Sang    schedule 23.04.2013    source источник
comment
Это была ошибка Armadillo. Я соответствующим образом отредактировал свой ответ.   -  person Dirk Eddelbuettel    schedule 30.04.2013


Ответы (2)


Ваша матрица кажется странной. Говоря

 Matrix(rnorm(p),sparse=TRUE)

вы получите матрицу p x 1, хотя и разреженную. Если я просто назначу 10 строк или столбцов, все будет работать.

R> p <- 100000
R> X <- Matrix(rnorm(p),nrow=10,sparse=TRUE)
R> dim(X)
[1]    10 10000
R> norm2(X)
SpMat Xsp:
100832
NULL
R> 

Поэтому я думаю, что вам просто нужна лучшая разреженная матрица для работы - код преобразования и тип разреженной матрицы Армадилло в порядке.

Обновление от 30 апреля 2013 г.: на самом деле это была ошибка Armadillo, которую только что исправили в апстриме. Новая версия RcppArmadillo 0.3.810.2 теперь находится в SVN и вскоре должна перейти на CRAN. Вам больше не нужно определять ARMA_64BIT_WORD.

person Dirk Eddelbuettel    schedule 23.04.2013
comment
Спасибо за ваш ответ. Я просто тестировал, чтобы убедиться, что все работает, поэтому я не стал делать разреженную матрицу. Кроме того, матрица px1 по-прежнему является матрицей. Мне было интересно, есть ли ограничение на количество ненулевых элементов. При дополнительном тестировании я обнаружил, что размер матрицы ограничен 2 ^ 16-1 = 65535. Это не очень много, особенно если матрица разреженная. Я надеюсь, что я могу что-то сделать, чтобы сформировать большую матрицу. - person Sang; 23.04.2013
comment
Можно ли указать include для перехода над #include ‹RcppArmadillo.h› с функцией cxx? Это было бы очень удобно и не требовало изменения установки пакета RcppArmadillo. Спасибо! - person Sang; 23.04.2013
comment
cxxfunction() - простой помощник. Похоже, вы хотите иметь больше контроля, поэтому вам следует действительно подумать о создании пакета. - person Dirk Eddelbuettel; 23.04.2013
comment
Кстати, вы также можете создать #define foo, добавив параметр компилятора -Dfoo. Это также будет работать с cxxfunction. - person Dirk Eddelbuettel; 23.04.2013
comment
Тогда не стесняйтесь принять и / или проголосовать за ответ за комментарий :) Кстати, какую (Rcpp) версию Armadillo вы используете? - person Dirk Eddelbuettel; 23.04.2013
comment
Я использую Rcpp версии 0.10.3 и RcppArmadillo версии 0.3.810.0. R версии 3.0.0 скомпилирован с библиотеками MKL. - person Sang; 24.04.2013
comment
Спасибо за обновления. (И нет, вы не компилируете с MKL. MKL используется как одна из нескольких возможных библиотек, обеспечивающих BLAS.) - person Dirk Eddelbuettel; 24.04.2013
comment
Интересно, можем ли мы использовать это в пакете. После попытки скомпилировать пакет с PKG_CXXFLAGS = -DARMA_64BIT_WORD и без него я все еще не могу создавать разреженные матрицы размером более 65 535 x 65 535. Я понял, что файл RcppArmadilloConfig.h (версия 0.6.600.4.0) имеет ARMA_32BIT_WORD 1, поэтому он фактически предотвращает использование ARMA_64BIT_WORD (я думаю?). В любом случае я могу решить эту проблему, или мне просто нужно иметь дело с R (3.2.4 Revised (2016-03-16 r70336)), не смог справиться с 64INT? Спасибо! - person gvegayon; 25.03.2016
comment
Попробуйте локально установить ARMA_64BIT_WORD (проверьте, как) - я не могу на уровне пакета, так как это нарушает существующий код. Скорее всего, это вам поможет. Если вы установите его до #include <RcppArmadillo.h>, все может работать. По крайней мере, PLN. (И вы должны были попросить на rcpp-devel получить больше двух глазных яблок по этому поводу ...) И да, другой ответ в основном говорит о том же. - person Dirk Eddelbuettel; 25.03.2016

Я столкнулся с этим: http://arma.sourceforge.net/docs.html#config_hpp.

Решение состоит в том, чтобы установить 64-битную целочисленную опцию, добавив строку над файлом заголовка для броненосца:

#define ARMA_64BIT_WORD

Я поместил это в [корень R] /lib/R/library/RcppArmadillo/include/RcppArmadilloConfig.h

Я пробовал использовать параметр "includes" для функции cxx, но я думаю, что этот оператор определения должен быть выше оператора include,

#include RcppArmadillo.h

в коде cpp. Я не знаю, позволяет ли это cxxfunction встроенного пакета.

После изменения RcppArmadilloConfig.h теперь я могу объявить матрицу больше 2 ^ 16.

> m <- 1000
> n <- 65536+1000
> nnz <- 10000
> iind <- sample.int(m,nnz,replace=TRUE)
> jind <- sample.int(n,nnz,replace=TRUE)
> xval <- rnorm(nnz)
> X <- sparseMatrix(i=iind,j=jind,x=xval,dims=c(m,n))
> norm2(X)
SpMat Xsp:
10218.8
NULL
> 
person Sang    schedule 23.04.2013
comment
Вы также можете определять переключатели компилятора "на лету" через -D: g++ -DARMA_64BIT_WORD и / или добавлять определение в src/Makevars или src/Makevars.win} вашего пакета. - person Dirk Eddelbuettel; 05.03.2014