为稀疏矩阵编写 C++ 迭代器 class
Writing a C++ iterator for a sparse matrix class
我正在尝试让一个基本常量前向迭代器在 C++ 中工作。
namespace Rcpp {
class SparseMatrix {
public:
IntegerVector i, p;
NumericVector x;
int begin_col(int j) { return p[j]; };
int end_col(int j) { return p[j + 1]; };
class iterator {
public:
int index;
iterator(SparseMatrix& g) : parent(g) {}
iterator(int ind) { index = ind; }; // ERROR!
bool operator!=(int x) const { return index != x; };
iterator operator++(int) { ++index; return (*this); };
int row() { return parent.i[index]; };
double value() { return parent.x[index]; };
private:
SparseMatrix& parent;
};
};
}
我的意图是在类似于以下的上下文中使用迭代器:
// sum of values in column 7
Rcpp::SparseMatrix A(nrow, ncol, fill::random);
double sum = 0;
for(Rcpp::SparseMatrix::iterator it = A.begin_col(7); it != A.end_col(7); it++)
sum += it.value();
两个问题:
- 编译器在上面指示的行上抛出错误:
uninitialized reference member in 'class Rcpp::SparseMatrix&' [-fpermissive]
。如何解决?
- 如何将
double value() { return parent.x[index]; };
重新工作为 return 指向值的指针而不是值的副本?
关于 SparseMatrix
class 的一点上下文:就像 R 中的 dgCMatrix
一样,class SparseMatrix
的这个对象由三个向量组成:
i
保存 x
中每个元素的行指针
p
给出 i
中的索引,对应于每一列的开始
x
包含非零值
感谢@Evg,这是解决方案:
namespace Rcpp {
class SparseMatrix {
public:
IntegerVector i, p;
NumericVector x;
class iterator {
public:
int index;
iterator(SparseMatrix& g, int ind) : parent(g) { index = ind; }
bool operator!=(iterator x) const { return index != x.index; };
iterator& operator++() { ++index; return (*this); };
int row() { return parent.i[index]; };
double& value() { return parent.x[index]; };
private:
SparseMatrix& parent;
};
iterator begin_col(int j) { return iterator(*this, p[j]); };
iterator end_col(int j) { return iterator(*this, p[j + 1]); };
};
}
并且可以如下使用,例如计算colSums:
//[[Rcpp::export]]
Rcpp::NumericVector Rcpp_colSums(Rcpp::SparseMatrix& A) {
Rcpp::NumericVector sums(A.cols());
for (int i = 0; i < A.cols(); ++i)
for (Rcpp::SparseMatrix::iterator it = A.begin_col(i); it != A.end_col(i); it++)
sums(i) += it.value();
return sums;
}
并且,当从 R 进行微基准测试时,上述函数比 RcppArmadillo
、RcppEigen
和 R::Matrix
等效函数更快!
编辑:
以上语法的灵感来自犰狳。我开始意识到稍微不同的语法(涉及更少的结构)给出了一个类似于 Eigen 的迭代器:
class col_iterator {
public:
col_iterator(SparseMatrix& ptr, int col) : ptr(ptr) { indx = ptr.p[col]; max_index = ptr.p[col + 1]; }
operator bool() const { return (indx != max_index); }
col_iterator& operator++() { ++indx; return *this; }
const double& value() const { return ptr.x[indx]; }
int row() const { return ptr.i[indx]; }
private:
SparseMatrix& ptr;
int indx, max_index;
};
然后可以这样使用:
int col = 0;
for (Rcpp::SparseMatrix::col_iterator it(A, col); it; ++it)
Rprintf("row: %3d, value: %10.2e", it.row(), it.value());
我正在尝试让一个基本常量前向迭代器在 C++ 中工作。
namespace Rcpp {
class SparseMatrix {
public:
IntegerVector i, p;
NumericVector x;
int begin_col(int j) { return p[j]; };
int end_col(int j) { return p[j + 1]; };
class iterator {
public:
int index;
iterator(SparseMatrix& g) : parent(g) {}
iterator(int ind) { index = ind; }; // ERROR!
bool operator!=(int x) const { return index != x; };
iterator operator++(int) { ++index; return (*this); };
int row() { return parent.i[index]; };
double value() { return parent.x[index]; };
private:
SparseMatrix& parent;
};
};
}
我的意图是在类似于以下的上下文中使用迭代器:
// sum of values in column 7
Rcpp::SparseMatrix A(nrow, ncol, fill::random);
double sum = 0;
for(Rcpp::SparseMatrix::iterator it = A.begin_col(7); it != A.end_col(7); it++)
sum += it.value();
两个问题:
- 编译器在上面指示的行上抛出错误:
uninitialized reference member in 'class Rcpp::SparseMatrix&' [-fpermissive]
。如何解决? - 如何将
double value() { return parent.x[index]; };
重新工作为 return 指向值的指针而不是值的副本?
关于 SparseMatrix
class 的一点上下文:就像 R 中的 dgCMatrix
一样,class SparseMatrix
的这个对象由三个向量组成:
i
保存x
中每个元素的行指针
p
给出i
中的索引,对应于每一列的开始x
包含非零值
感谢@Evg,这是解决方案:
namespace Rcpp {
class SparseMatrix {
public:
IntegerVector i, p;
NumericVector x;
class iterator {
public:
int index;
iterator(SparseMatrix& g, int ind) : parent(g) { index = ind; }
bool operator!=(iterator x) const { return index != x.index; };
iterator& operator++() { ++index; return (*this); };
int row() { return parent.i[index]; };
double& value() { return parent.x[index]; };
private:
SparseMatrix& parent;
};
iterator begin_col(int j) { return iterator(*this, p[j]); };
iterator end_col(int j) { return iterator(*this, p[j + 1]); };
};
}
并且可以如下使用,例如计算colSums:
//[[Rcpp::export]]
Rcpp::NumericVector Rcpp_colSums(Rcpp::SparseMatrix& A) {
Rcpp::NumericVector sums(A.cols());
for (int i = 0; i < A.cols(); ++i)
for (Rcpp::SparseMatrix::iterator it = A.begin_col(i); it != A.end_col(i); it++)
sums(i) += it.value();
return sums;
}
并且,当从 R 进行微基准测试时,上述函数比 RcppArmadillo
、RcppEigen
和 R::Matrix
等效函数更快!
编辑:
以上语法的灵感来自犰狳。我开始意识到稍微不同的语法(涉及更少的结构)给出了一个类似于 Eigen 的迭代器:
class col_iterator {
public:
col_iterator(SparseMatrix& ptr, int col) : ptr(ptr) { indx = ptr.p[col]; max_index = ptr.p[col + 1]; }
operator bool() const { return (indx != max_index); }
col_iterator& operator++() { ++indx; return *this; }
const double& value() const { return ptr.x[indx]; }
int row() const { return ptr.i[indx]; }
private:
SparseMatrix& ptr;
int indx, max_index;
};
然后可以这样使用:
int col = 0;
for (Rcpp::SparseMatrix::col_iterator it(A, col); it; ++it)
Rprintf("row: %3d, value: %10.2e", it.row(), it.value());