Apply clang-format

This commit is contained in:
Tobias Wood
2023-11-29 11:12:48 +00:00
parent 9ea520fc45
commit f38e16c193
534 changed files with 103368 additions and 116934 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -17,205 +17,194 @@
// IWYU pragma: private
#include "./InternalHeaderCheck.h"
namespace Eigen {
namespace Eigen {
namespace internal
{
template <typename Scalar, typename StorageIndex>
inline void GetMarketLine (const char* line, StorageIndex& i, StorageIndex& j, Scalar& value)
{
std::stringstream sline(line);
sline >> i >> j >> value;
}
namespace internal {
template <typename Scalar, typename StorageIndex>
inline void GetMarketLine(const char* line, StorageIndex& i, StorageIndex& j, Scalar& value) {
std::stringstream sline(line);
sline >> i >> j >> value;
}
template<> inline void GetMarketLine (const char* line, int& i, int& j, float& value)
{ std::sscanf(line, "%d %d %g", &i, &j, &value); }
template <>
inline void GetMarketLine(const char* line, int& i, int& j, float& value) {
std::sscanf(line, "%d %d %g", &i, &j, &value);
}
template<> inline void GetMarketLine (const char* line, int& i, int& j, double& value)
{ std::sscanf(line, "%d %d %lg", &i, &j, &value); }
template <>
inline void GetMarketLine(const char* line, int& i, int& j, double& value) {
std::sscanf(line, "%d %d %lg", &i, &j, &value);
}
template<> inline void GetMarketLine (const char* line, int& i, int& j, std::complex<float>& value)
{ std::sscanf(line, "%d %d %g %g", &i, &j, &numext::real_ref(value), &numext::imag_ref(value)); }
template <>
inline void GetMarketLine(const char* line, int& i, int& j, std::complex<float>& value) {
std::sscanf(line, "%d %d %g %g", &i, &j, &numext::real_ref(value), &numext::imag_ref(value));
}
template<> inline void GetMarketLine (const char* line, int& i, int& j, std::complex<double>& value)
{ std::sscanf(line, "%d %d %lg %lg", &i, &j, &numext::real_ref(value), &numext::imag_ref(value)); }
template <>
inline void GetMarketLine(const char* line, int& i, int& j, std::complex<double>& value) {
std::sscanf(line, "%d %d %lg %lg", &i, &j, &numext::real_ref(value), &numext::imag_ref(value));
}
template <typename Scalar, typename StorageIndex>
inline void GetMarketLine (const char* line, StorageIndex& i, StorageIndex& j, std::complex<Scalar>& value)
{
std::stringstream sline(line);
Scalar valR, valI;
sline >> i >> j >> valR >> valI;
value = std::complex<Scalar>(valR,valI);
}
template <typename Scalar, typename StorageIndex>
inline void GetMarketLine(const char* line, StorageIndex& i, StorageIndex& j, std::complex<Scalar>& value) {
std::stringstream sline(line);
Scalar valR, valI;
sline >> i >> j >> valR >> valI;
value = std::complex<Scalar>(valR, valI);
}
template <typename RealScalar>
inline void GetDenseElt (const std::string& line, RealScalar& val)
{
std::istringstream newline(line);
newline >> val;
}
template <typename RealScalar>
inline void GetDenseElt(const std::string& line, RealScalar& val) {
std::istringstream newline(line);
newline >> val;
}
template <typename RealScalar>
inline void GetDenseElt (const std::string& line, std::complex<RealScalar>& val)
{
RealScalar valR, valI;
std::istringstream newline(line);
newline >> valR >> valI;
val = std::complex<RealScalar>(valR, valI);
}
template<typename Scalar>
inline void putMarketHeader(std::string& header,int sym)
{
header= "%%MatrixMarket matrix coordinate ";
if(internal::is_same<Scalar, std::complex<float> >::value || internal::is_same<Scalar, std::complex<double> >::value)
{
header += " complex";
if(sym == Symmetric) header += " symmetric";
else if (sym == SelfAdjoint) header += " Hermitian";
else header += " general";
}
template <typename RealScalar>
inline void GetDenseElt(const std::string& line, std::complex<RealScalar>& val) {
RealScalar valR, valI;
std::istringstream newline(line);
newline >> valR >> valI;
val = std::complex<RealScalar>(valR, valI);
}
template <typename Scalar>
inline void putMarketHeader(std::string& header, int sym) {
header = "%%MatrixMarket matrix coordinate ";
if (internal::is_same<Scalar, std::complex<float> >::value ||
internal::is_same<Scalar, std::complex<double> >::value) {
header += " complex";
if (sym == Symmetric)
header += " symmetric";
else if (sym == SelfAdjoint)
header += " Hermitian";
else
{
header += " real";
if(sym == Symmetric) header += " symmetric";
else header += " general";
}
header += " general";
} else {
header += " real";
if (sym == Symmetric)
header += " symmetric";
else
header += " general";
}
}
template<typename Scalar, typename StorageIndex>
inline void PutMatrixElt(Scalar value, StorageIndex row, StorageIndex col, std::ofstream& out)
{
out << row << " "<< col << " " << value << "\n";
}
template<typename Scalar, typename StorageIndex>
inline void PutMatrixElt(std::complex<Scalar> value, StorageIndex row, StorageIndex col, std::ofstream& out)
{
out << row << " " << col << " " << value.real() << " " << value.imag() << "\n";
}
template <typename Scalar, typename StorageIndex>
inline void PutMatrixElt(Scalar value, StorageIndex row, StorageIndex col, std::ofstream& out) {
out << row << " " << col << " " << value << "\n";
}
template <typename Scalar, typename StorageIndex>
inline void PutMatrixElt(std::complex<Scalar> value, StorageIndex row, StorageIndex col, std::ofstream& out) {
out << row << " " << col << " " << value.real() << " " << value.imag() << "\n";
}
template <typename Scalar>
inline void putDenseElt(Scalar value, std::ofstream& out) {
out << value << "\n";
}
template <typename Scalar>
inline void putDenseElt(std::complex<Scalar> value, std::ofstream& out) {
out << value.real() << " " << value.imag() << "\n";
}
template<typename Scalar>
inline void putDenseElt(Scalar value, std::ofstream& out)
{
out << value << "\n";
}
template<typename Scalar>
inline void putDenseElt(std::complex<Scalar> value, std::ofstream& out)
{
out << value.real() << " " << value.imag()<< "\n";
}
} // end namespace internal
} // end namespace internal
/**
* \ingroup SparseExtra_Module
* @brief Reads the header of a matrixmarket file and determines the properties of a matrix
*
*
* @param filename of the file
* @param sym if the matrix is hermitian,symmetric or none of the latter (sym=0)
* @param iscomplex if the matrix has complex or real coefficients
* @param sym if the matrix is hermitian,symmetric or none of the latter (sym=0)
* @param iscomplex if the matrix has complex or real coefficients
* @param isdense if the matrix is dense or sparse
* @return true if the file was found
*/
inline bool getMarketHeader(const std::string& filename, int& sym, bool& iscomplex, bool& isdense)
{
sym = 0;
inline bool getMarketHeader(const std::string& filename, int& sym, bool& iscomplex, bool& isdense) {
sym = 0;
iscomplex = false;
isdense = false;
std::ifstream in(filename.c_str(),std::ios::in);
if(!in)
return false;
std::string line;
// The matrix header is always the first line in the file
std::getline(in, line); eigen_assert(in.good());
std::stringstream fmtline(line);
std::ifstream in(filename.c_str(), std::ios::in);
if (!in) return false;
std::string line;
// The matrix header is always the first line in the file
std::getline(in, line);
eigen_assert(in.good());
std::stringstream fmtline(line);
std::string substr[5];
fmtline>> substr[0] >> substr[1] >> substr[2] >> substr[3] >> substr[4];
if(substr[2].compare("array") == 0) isdense = true;
if(substr[3].compare("complex") == 0) iscomplex = true;
if(substr[4].compare("symmetric") == 0) sym = Symmetric;
else if (substr[4].compare("Hermitian") == 0) sym = SelfAdjoint;
fmtline >> substr[0] >> substr[1] >> substr[2] >> substr[3] >> substr[4];
if (substr[2].compare("array") == 0) isdense = true;
if (substr[3].compare("complex") == 0) iscomplex = true;
if (substr[4].compare("symmetric") == 0)
sym = Symmetric;
else if (substr[4].compare("Hermitian") == 0)
sym = SelfAdjoint;
return true;
}
/**
* \ingroup SparseExtra_Module
* @brief Loads a sparse matrix from a matrixmarket format file.
*
*
* @tparam SparseMatrixType to read into, symmetries are not supported
* @param mat SparseMatrix to read into, current values are overwritten
* @param filename to parse matrix from
* @return returns true if file exists. Returns false if the parsing did not succeed.
*/
template<typename SparseMatrixType>
bool loadMarket(SparseMatrixType& mat, const std::string& filename)
{
template <typename SparseMatrixType>
bool loadMarket(SparseMatrixType& mat, const std::string& filename) {
typedef typename SparseMatrixType::Scalar Scalar;
typedef typename SparseMatrixType::StorageIndex StorageIndex;
std::ifstream input(filename.c_str(),std::ios::in);
if(!input)
return false;
std::ifstream input(filename.c_str(), std::ios::in);
if (!input) return false;
char rdbuffer[4096];
input.rdbuf()->pubsetbuf(rdbuffer, 4096);
const int maxBuffersize = 2048;
char buffer[maxBuffersize];
bool readsizes = false;
typedef Triplet<Scalar,StorageIndex> T;
typedef Triplet<Scalar, StorageIndex> T;
std::vector<T> elements;
Index M(-1), N(-1), NNZ(-1);
Index count = 0;
while(input.getline(buffer, maxBuffersize))
{
// skip comments
//NOTE An appropriate test should be done on the header to get the symmetry
if(buffer[0]=='%')
continue;
while (input.getline(buffer, maxBuffersize)) {
// skip comments
// NOTE An appropriate test should be done on the header to get the symmetry
if (buffer[0] == '%') continue;
if(!readsizes)
{
if (!readsizes) {
std::stringstream line(buffer);
line >> M >> N >> NNZ;
if(M > 0 && N > 0)
{
if (M > 0 && N > 0) {
readsizes = true;
mat.resize(M,N);
mat.resize(M, N);
mat.reserve(NNZ);
elements.reserve(NNZ);
}
}
else
{
} else {
StorageIndex i(-1), j(-1);
Scalar value;
Scalar value;
internal::GetMarketLine(buffer, i, j, value);
i--;
j--;
if(i>=0 && j>=0 && i<M && j<N)
{
if (i >= 0 && j >= 0 && i < M && j < N) {
++count;
elements.push_back(T(i,j,value));
}
else
{
std::cerr << "Invalid read: " << i << "," << j << "\n";
elements.push_back(T(i, j, value));
} else {
std::cerr << "Invalid read: " << i << "," << j << "\n";
return false;
}
}
}
}
mat.setFromTriplets(elements.begin(), elements.end());
if(count!=NNZ){
if (count != NNZ) {
std::cerr << count << "!=" << NNZ << "\n";
return false;
}
@@ -223,68 +212,66 @@ bool loadMarket(SparseMatrixType& mat, const std::string& filename)
return true;
}
/**
* \ingroup SparseExtra_Module
* @brief Loads a dense Matrix or Vector from a matrixmarket file. If a statically sized matrix has to be parsed and the file contains the wrong dimensions it is undefined behaviour.
*
* @brief Loads a dense Matrix or Vector from a matrixmarket file. If a statically sized matrix has to be parsed and the
* file contains the wrong dimensions it is undefined behaviour.
*
* @tparam DenseMatrixType to read into
* @param mat DenseMatrix to read into, current values are overwritten, symmetries are not supported
* @param filename to parse matrix from
* @return true if parsing was successful. Returns false if the parsing did not succeed.
*/
template<typename DenseType>
bool loadMarketDense(DenseType& mat, const std::string& filename)
{
typedef typename DenseType::Scalar Scalar;
template <typename DenseType>
bool loadMarketDense(DenseType& mat, const std::string& filename) {
typedef typename DenseType::Scalar Scalar;
std::ifstream in(filename.c_str(), std::ios::in);
if(!in)
return false;
std::string line;
Index rows(0), cols(0);
do
{ // Skip comments
std::getline(in, line); eigen_assert(in.good());
if (!in) return false;
std::string line;
Index rows(0), cols(0);
do { // Skip comments
std::getline(in, line);
eigen_assert(in.good());
} while (line[0] == '%');
std::istringstream newline(line);
newline >> rows >> cols;
newline >> rows >> cols;
bool sizes_not_positive=(rows<1 || cols<1);
bool sizes_not_positive = (rows < 1 || cols < 1);
bool wrong_input_rows = (DenseType::MaxRowsAtCompileTime != Dynamic && rows > DenseType::MaxRowsAtCompileTime) ||
(DenseType::RowsAtCompileTime!=Dynamic && rows!=DenseType::RowsAtCompileTime);
(DenseType::RowsAtCompileTime != Dynamic && rows != DenseType::RowsAtCompileTime);
bool wrong_input_cols = (DenseType::MaxColsAtCompileTime != Dynamic && cols > DenseType::MaxColsAtCompileTime) ||
(DenseType::ColsAtCompileTime!=Dynamic && cols!=DenseType::ColsAtCompileTime);
(DenseType::ColsAtCompileTime != Dynamic && cols != DenseType::ColsAtCompileTime);
if(sizes_not_positive || wrong_input_rows || wrong_input_cols){
if(sizes_not_positive){
std::cerr<< "non-positive row or column size in file" << filename << "\n";
}else{
std::cerr<< "Input matrix can not be resized to"<<rows<<" x "<<cols<< "as given in " << filename << "\n";
if (sizes_not_positive || wrong_input_rows || wrong_input_cols) {
if (sizes_not_positive) {
std::cerr << "non-positive row or column size in file" << filename << "\n";
} else {
std::cerr << "Input matrix can not be resized to" << rows << " x " << cols << "as given in " << filename << "\n";
}
in.close();
return false;
}
mat.resize(rows,cols);
mat.resize(rows, cols);
Index row = 0;
Index col = 0;
Index n=0;
Scalar value;
while ( std::getline(in, line) && (row < rows) && (col < cols)){
internal::GetDenseElt(line, value);
//matrixmarket format is column major
mat(row,col) = value;
Index col = 0;
Index n = 0;
Scalar value;
while (std::getline(in, line) && (row < rows) && (col < cols)) {
internal::GetDenseElt(line, value);
// matrixmarket format is column major
mat(row, col) = value;
row++;
if(row==rows){
row=0;
if (row == rows) {
row = 0;
col++;
}
n++;
}
in.close();
if (n!=mat.size()){
std::cerr<< "Unable to read all elements from file " << filename << "\n";
if (n != mat.size()) {
std::cerr << "Unable to read all elements from file " << filename << "\n";
return false;
}
return true;
@@ -293,94 +280,86 @@ bool loadMarketDense(DenseType& mat, const std::string& filename)
* \ingroup SparseExtra_Module
* @brief Same functionality as loadMarketDense, deprecated
*/
template<typename VectorType>
bool loadMarketVector(VectorType& vec, const std::string& filename)
{
return loadMarketDense(vec, filename);
template <typename VectorType>
bool loadMarketVector(VectorType& vec, const std::string& filename) {
return loadMarketDense(vec, filename);
}
/**
* \ingroup SparseExtra_Module
* @brief writes a sparse Matrix to a marketmarket format file
*
*
* @tparam SparseMatrixType to write to file
* @param mat matrix to write to file
* @param filename filename to write to
* @param filename filename to write to
* @param sym at the moment no symmetry operations are supported
* @return true if writing succeeded
*/
template<typename SparseMatrixType>
bool saveMarket(const SparseMatrixType& mat, const std::string& filename, int sym = 0)
{
template <typename SparseMatrixType>
bool saveMarket(const SparseMatrixType& mat, const std::string& filename, int sym = 0) {
typedef typename SparseMatrixType::Scalar Scalar;
typedef typename SparseMatrixType::RealScalar RealScalar;
std::ofstream out(filename.c_str(),std::ios::out);
if(!out)
return false;
std::ofstream out(filename.c_str(), std::ios::out);
if (!out) return false;
out.flags(std::ios_base::scientific);
out.precision(std::numeric_limits<RealScalar>::digits10 + 2);
std::string header;
internal::putMarketHeader<Scalar>(header, sym);
out << header << std::endl;
std::string header;
internal::putMarketHeader<Scalar>(header, sym);
out << header << std::endl;
out << mat.rows() << " " << mat.cols() << " " << mat.nonZeros() << "\n";
int count = 0;
for(int j=0; j<mat.outerSize(); ++j)
for(typename SparseMatrixType::InnerIterator it(mat,j); it; ++it)
{
++ count;
internal::PutMatrixElt(it.value(), it.row()+1, it.col()+1, out);
for (int j = 0; j < mat.outerSize(); ++j)
for (typename SparseMatrixType::InnerIterator it(mat, j); it; ++it) {
++count;
internal::PutMatrixElt(it.value(), it.row() + 1, it.col() + 1, out);
}
out.close();
return true;
}
/**
* \ingroup SparseExtra_Module
* @brief writes a dense Matrix or vector to a marketmarket format file
*
*
* @tparam DenseMatrixType to write to file
* @param mat matrix to write to file
* @param filename filename to write to
* @param filename filename to write to
* @return true if writing succeeded
*/
template<typename DenseType>
bool saveMarketDense (const DenseType& mat, const std::string& filename)
{
typedef typename DenseType::Scalar Scalar;
typedef typename DenseType::RealScalar RealScalar;
std::ofstream out(filename.c_str(),std::ios::out);
if(!out)
return false;
template <typename DenseType>
bool saveMarketDense(const DenseType& mat, const std::string& filename) {
typedef typename DenseType::Scalar Scalar;
typedef typename DenseType::RealScalar RealScalar;
std::ofstream out(filename.c_str(), std::ios::out);
if (!out) return false;
out.flags(std::ios_base::scientific);
out.precision(std::numeric_limits<RealScalar>::digits10 + 2);
if(internal::is_same<Scalar, std::complex<float> >::value || internal::is_same<Scalar, std::complex<double> >::value)
out << "%%MatrixMarket matrix array complex general\n";
if (internal::is_same<Scalar, std::complex<float> >::value || internal::is_same<Scalar, std::complex<double> >::value)
out << "%%MatrixMarket matrix array complex general\n";
else
out << "%%MatrixMarket matrix array real general\n";
out << mat.rows() << " "<< mat.cols() << "\n";
for (Index i=0; i < mat.cols(); i++){
for (Index j=0; j < mat.rows(); j++){
internal::putDenseElt(mat(j,i), out);
out << "%%MatrixMarket matrix array real general\n";
out << mat.rows() << " " << mat.cols() << "\n";
for (Index i = 0; i < mat.cols(); i++) {
for (Index j = 0; j < mat.rows(); j++) {
internal::putDenseElt(mat(j, i), out);
}
}
out.close();
return true;
return true;
}
/**
* \ingroup SparseExtra_Module
* @brief Same functionality as saveMarketDense, deprecated
*/
template<typename VectorType>
bool saveMarketVector (const VectorType& vec, const std::string& filename)
{
template <typename VectorType>
bool saveMarketVector(const VectorType& vec, const std::string& filename) {
return saveMarketDense(vec, filename);
}
} // end namespace Eigen
} // end namespace Eigen
#endif // EIGEN_SPARSE_MARKET_IO_H
#endif // EIGEN_SPARSE_MARKET_IO_H

View File

@@ -16,235 +16,205 @@
namespace Eigen {
enum {
SPD = 0x100,
NonSymmetric = 0x0
};
enum { SPD = 0x100, NonSymmetric = 0x0 };
/**
/**
* @brief Iterator to browse matrices from a specified folder
*
* This is used to load all the matrices from a folder.
*
* This is used to load all the matrices from a folder.
* The matrices should be in Matrix Market format
* It is assumed that the matrices are named as matname.mtx
* and matname_SPD.mtx if the matrix is Symmetric and positive definite (or Hermitian)
* The right hand side vectors are loaded as well, if they exist.
* They should be named as matname_b.mtx.
* They should be named as matname_b.mtx.
* Note that the right hand side for a SPD matrix is named as matname_SPD_b.mtx
*
*
* Sometimes a reference solution is available. In this case, it should be named as matname_x.mtx
*
*
* Sample code
* \code
*
*
* \endcode
*
* \tparam Scalar The scalar type
*
* \tparam Scalar The scalar type
*/
template <typename Scalar>
class MatrixMarketIterator
{
typedef typename NumTraits<Scalar>::Real RealScalar;
public:
typedef Matrix<Scalar,Dynamic,1> VectorType;
typedef SparseMatrix<Scalar,ColMajor> MatrixType;
public:
MatrixMarketIterator(const std::string &folder)
: m_sym(0), m_isvalid(false), m_matIsLoaded(false), m_hasRhs(false), m_hasrefX(false), m_folder(folder)
{
m_folder_id = opendir(folder.c_str());
if(m_folder_id)
Getnextvalidmatrix();
}
~MatrixMarketIterator()
{
if (m_folder_id) closedir(m_folder_id);
}
inline MatrixMarketIterator& operator++()
{
m_matIsLoaded = false;
m_hasrefX = false;
m_hasRhs = false;
Getnextvalidmatrix();
return *this;
}
inline operator bool() const { return m_isvalid;}
/** Return the sparse matrix corresponding to the current file */
inline MatrixType& matrix()
{
// Read the matrix
if (m_matIsLoaded) return m_mat;
std::string matrix_file = m_folder + "/" + m_matname + ".mtx";
if ( !loadMarket(m_mat, matrix_file))
{
std::cerr << "Warning loadMarket failed when loading \"" << matrix_file << "\"" << std::endl;
m_matIsLoaded = false;
return m_mat;
}
m_matIsLoaded = true;
class MatrixMarketIterator {
typedef typename NumTraits<Scalar>::Real RealScalar;
if (m_sym != NonSymmetric)
{
// Check whether we need to restore a full matrix:
RealScalar diag_norm = m_mat.diagonal().norm();
RealScalar lower_norm = m_mat.template triangularView<Lower>().norm();
RealScalar upper_norm = m_mat.template triangularView<Upper>().norm();
if(lower_norm>diag_norm && upper_norm==diag_norm)
{
// only the lower part is stored
MatrixType tmp(m_mat);
m_mat = tmp.template selfadjointView<Lower>();
}
else if(upper_norm>diag_norm && lower_norm==diag_norm)
{
// only the upper part is stored
MatrixType tmp(m_mat);
m_mat = tmp.template selfadjointView<Upper>();
}
}
return m_mat;
public:
typedef Matrix<Scalar, Dynamic, 1> VectorType;
typedef SparseMatrix<Scalar, ColMajor> MatrixType;
public:
MatrixMarketIterator(const std::string& folder)
: m_sym(0), m_isvalid(false), m_matIsLoaded(false), m_hasRhs(false), m_hasrefX(false), m_folder(folder) {
m_folder_id = opendir(folder.c_str());
if (m_folder_id) Getnextvalidmatrix();
}
~MatrixMarketIterator() {
if (m_folder_id) closedir(m_folder_id);
}
inline MatrixMarketIterator& operator++() {
m_matIsLoaded = false;
m_hasrefX = false;
m_hasRhs = false;
Getnextvalidmatrix();
return *this;
}
inline operator bool() const { return m_isvalid; }
/** Return the sparse matrix corresponding to the current file */
inline MatrixType& matrix() {
// Read the matrix
if (m_matIsLoaded) return m_mat;
std::string matrix_file = m_folder + "/" + m_matname + ".mtx";
if (!loadMarket(m_mat, matrix_file)) {
std::cerr << "Warning loadMarket failed when loading \"" << matrix_file << "\"" << std::endl;
m_matIsLoaded = false;
return m_mat;
}
/** Return the right hand side corresponding to the current matrix.
* If the rhs file is not provided, a random rhs is generated
*/
inline VectorType& rhs()
{
// Get the right hand side
if (m_hasRhs) return m_rhs;
std::string rhs_file;
rhs_file = m_folder + "/" + m_matname + "_b.mtx"; // The pattern is matname_b.mtx
m_hasRhs = Fileexists(rhs_file);
if (m_hasRhs)
{
m_rhs.resize(m_mat.cols());
m_hasRhs = loadMarketVector(m_rhs, rhs_file);
}
if (!m_hasRhs)
{
// Generate a random right hand side
if (!m_matIsLoaded) this->matrix();
m_refX.resize(m_mat.cols());
m_refX.setRandom();
m_rhs = m_mat * m_refX;
m_hasrefX = true;
m_hasRhs = true;
}
return m_rhs;
}
/** Return a reference solution
* If it is not provided and if the right hand side is not available
* then refX is randomly generated such that A*refX = b
* where A and b are the matrix and the rhs.
* Note that when a rhs is provided, refX is not available
*/
inline VectorType& refX()
{
// Check if a reference solution is provided
if (m_hasrefX) return m_refX;
std::string lhs_file;
lhs_file = m_folder + "/" + m_matname + "_x.mtx";
m_hasrefX = Fileexists(lhs_file);
if (m_hasrefX)
{
m_refX.resize(m_mat.cols());
m_hasrefX = loadMarketVector(m_refX, lhs_file);
}
else
m_refX.resize(0);
return m_refX;
}
inline std::string& matname() { return m_matname; }
inline int sym() { return m_sym; }
bool hasRhs() {return m_hasRhs; }
bool hasrefX() {return m_hasrefX; }
bool isFolderValid() { return bool(m_folder_id); }
protected:
inline bool Fileexists(std::string file)
{
std::ifstream file_id(file.c_str());
if (!file_id.good() )
{
return false;
}
else
{
file_id.close();
return true;
m_matIsLoaded = true;
if (m_sym != NonSymmetric) {
// Check whether we need to restore a full matrix:
RealScalar diag_norm = m_mat.diagonal().norm();
RealScalar lower_norm = m_mat.template triangularView<Lower>().norm();
RealScalar upper_norm = m_mat.template triangularView<Upper>().norm();
if (lower_norm > diag_norm && upper_norm == diag_norm) {
// only the lower part is stored
MatrixType tmp(m_mat);
m_mat = tmp.template selfadjointView<Lower>();
} else if (upper_norm > diag_norm && lower_norm == diag_norm) {
// only the upper part is stored
MatrixType tmp(m_mat);
m_mat = tmp.template selfadjointView<Upper>();
}
}
void Getnextvalidmatrix( )
{
return m_mat;
}
/** Return the right hand side corresponding to the current matrix.
* If the rhs file is not provided, a random rhs is generated
*/
inline VectorType& rhs() {
// Get the right hand side
if (m_hasRhs) return m_rhs;
std::string rhs_file;
rhs_file = m_folder + "/" + m_matname + "_b.mtx"; // The pattern is matname_b.mtx
m_hasRhs = Fileexists(rhs_file);
if (m_hasRhs) {
m_rhs.resize(m_mat.cols());
m_hasRhs = loadMarketVector(m_rhs, rhs_file);
}
if (!m_hasRhs) {
// Generate a random right hand side
if (!m_matIsLoaded) this->matrix();
m_refX.resize(m_mat.cols());
m_refX.setRandom();
m_rhs = m_mat * m_refX;
m_hasrefX = true;
m_hasRhs = true;
}
return m_rhs;
}
/** Return a reference solution
* If it is not provided and if the right hand side is not available
* then refX is randomly generated such that A*refX = b
* where A and b are the matrix and the rhs.
* Note that when a rhs is provided, refX is not available
*/
inline VectorType& refX() {
// Check if a reference solution is provided
if (m_hasrefX) return m_refX;
std::string lhs_file;
lhs_file = m_folder + "/" + m_matname + "_x.mtx";
m_hasrefX = Fileexists(lhs_file);
if (m_hasrefX) {
m_refX.resize(m_mat.cols());
m_hasrefX = loadMarketVector(m_refX, lhs_file);
} else
m_refX.resize(0);
return m_refX;
}
inline std::string& matname() { return m_matname; }
inline int sym() { return m_sym; }
bool hasRhs() { return m_hasRhs; }
bool hasrefX() { return m_hasrefX; }
bool isFolderValid() { return bool(m_folder_id); }
protected:
inline bool Fileexists(std::string file) {
std::ifstream file_id(file.c_str());
if (!file_id.good()) {
return false;
} else {
file_id.close();
return true;
}
}
void Getnextvalidmatrix() {
m_isvalid = false;
// Here, we return with the next valid matrix in the folder
while ((m_curs_id = readdir(m_folder_id)) != NULL) {
m_isvalid = false;
// Here, we return with the next valid matrix in the folder
while ( (m_curs_id = readdir(m_folder_id)) != NULL) {
m_isvalid = false;
std::string curfile;
curfile = m_folder + "/" + m_curs_id->d_name;
// Discard if it is a folder
if (m_curs_id->d_type == DT_DIR) continue; //FIXME This may not be available on non BSD systems
// struct stat st_buf;
// stat (curfile.c_str(), &st_buf);
// if (S_ISDIR(st_buf.st_mode)) continue;
// Determine from the header if it is a matrix or a right hand side
bool isvector,iscomplex=false;
if(!getMarketHeader(curfile,m_sym,iscomplex,isvector)) continue;
if(isvector) continue;
if (!iscomplex)
{
if(internal::is_same<Scalar, std::complex<float> >::value || internal::is_same<Scalar, std::complex<double> >::value)
continue;
}
if (iscomplex)
{
if(internal::is_same<Scalar, float>::value || internal::is_same<Scalar, double>::value)
continue;
}
// Get the matrix name
std::string filename = m_curs_id->d_name;
m_matname = filename.substr(0, filename.length()-4);
// Find if the matrix is SPD
size_t found = m_matname.find("SPD");
if( (found!=std::string::npos) && (m_sym != NonSymmetric) )
m_sym = SPD;
m_isvalid = true;
break;
std::string curfile;
curfile = m_folder + "/" + m_curs_id->d_name;
// Discard if it is a folder
if (m_curs_id->d_type == DT_DIR) continue; // FIXME This may not be available on non BSD systems
// struct stat st_buf;
// stat (curfile.c_str(), &st_buf);
// if (S_ISDIR(st_buf.st_mode)) continue;
// Determine from the header if it is a matrix or a right hand side
bool isvector, iscomplex = false;
if (!getMarketHeader(curfile, m_sym, iscomplex, isvector)) continue;
if (isvector) continue;
if (!iscomplex) {
if (internal::is_same<Scalar, std::complex<float> >::value ||
internal::is_same<Scalar, std::complex<double> >::value)
continue;
}
if (iscomplex) {
if (internal::is_same<Scalar, float>::value || internal::is_same<Scalar, double>::value) continue;
}
// Get the matrix name
std::string filename = m_curs_id->d_name;
m_matname = filename.substr(0, filename.length() - 4);
// Find if the matrix is SPD
size_t found = m_matname.find("SPD");
if ((found != std::string::npos) && (m_sym != NonSymmetric)) m_sym = SPD;
m_isvalid = true;
break;
}
int m_sym; // Symmetry of the matrix
MatrixType m_mat; // Current matrix
VectorType m_rhs; // Current vector
VectorType m_refX; // The reference solution, if exists
std::string m_matname; // Matrix Name
bool m_isvalid;
bool m_matIsLoaded; // Determine if the matrix has already been loaded from the file
bool m_hasRhs; // The right hand side exists
bool m_hasrefX; // A reference solution is provided
std::string m_folder;
DIR * m_folder_id;
struct dirent *m_curs_id;
}
int m_sym; // Symmetry of the matrix
MatrixType m_mat; // Current matrix
VectorType m_rhs; // Current vector
VectorType m_refX; // The reference solution, if exists
std::string m_matname; // Matrix Name
bool m_isvalid;
bool m_matIsLoaded; // Determine if the matrix has already been loaded from the file
bool m_hasRhs; // The right hand side exists
bool m_hasrefX; // A reference solution is provided
std::string m_folder;
DIR* m_folder_id;
struct dirent* m_curs_id;
};
} // end namespace Eigen
} // end namespace Eigen
#endif

View File

@@ -11,7 +11,7 @@
#define EIGEN_RANDOMSETTER_H
#if defined(EIGEN_GOOGLEHASH_SUPPORT)
// Ensure the ::google namespace exists, required for checking existence of
// Ensure the ::google namespace exists, required for checking existence of
// ::google::dense_hash_map and ::google::sparse_hash_map.
namespace google {}
#endif
@@ -22,31 +22,26 @@ namespace google {}
namespace Eigen {
/** Represents a std::map
*
* \see RandomSetter
*/
template<typename Scalar> struct StdMapTraits
{
*
* \see RandomSetter
*/
template <typename Scalar>
struct StdMapTraits {
typedef int KeyType;
typedef std::map<KeyType,Scalar> Type;
enum {
IsSorted = 1
};
typedef std::map<KeyType, Scalar> Type;
enum { IsSorted = 1 };
static void setInvalidKey(Type&, const KeyType&) {}
};
/** Represents a std::unordered_map
* \see RandomSetter
*/
template<typename Scalar> struct StdUnorderedMapTraits
{
* \see RandomSetter
*/
template <typename Scalar>
struct StdUnorderedMapTraits {
typedef int KeyType;
typedef std::unordered_map<KeyType,Scalar> Type;
enum {
IsSorted = 0
};
typedef std::unordered_map<KeyType, Scalar> Type;
enum { IsSorted = 0 };
static void setInvalidKey(Type&, const KeyType&) {}
};
@@ -54,283 +49,255 @@ template<typename Scalar> struct StdUnorderedMapTraits
#if defined(EIGEN_GOOGLEHASH_SUPPORT)
namespace google {
// Namespace work-around, since sometimes dense_hash_map and sparse_hash_map
// are in the global namespace, and other times they are under ::google.
using namespace ::google;
template<typename KeyType, typename Scalar>
template <typename KeyType, typename Scalar>
struct DenseHashMap {
typedef dense_hash_map<KeyType, Scalar> type;
};
template<typename KeyType, typename Scalar>
template <typename KeyType, typename Scalar>
struct SparseHashMap {
typedef sparse_hash_map<KeyType, Scalar> type;
};
} // namespace google
} // namespace google
/** Represents a google::dense_hash_map
*
* \see RandomSetter
*/
template<typename Scalar> struct GoogleDenseHashMapTraits
{
*
* \see RandomSetter
*/
template <typename Scalar>
struct GoogleDenseHashMapTraits {
typedef int KeyType;
typedef typename google::DenseHashMap<KeyType,Scalar>::type Type;
enum {
IsSorted = 0
};
typedef typename google::DenseHashMap<KeyType, Scalar>::type Type;
enum { IsSorted = 0 };
static void setInvalidKey(Type& map, const KeyType& k)
{ map.set_empty_key(k); }
static void setInvalidKey(Type& map, const KeyType& k) { map.set_empty_key(k); }
};
/** Represents a google::sparse_hash_map
*
* \see RandomSetter
*/
template<typename Scalar> struct GoogleSparseHashMapTraits
{
*
* \see RandomSetter
*/
template <typename Scalar>
struct GoogleSparseHashMapTraits {
typedef int KeyType;
typedef typename google::SparseHashMap<KeyType,Scalar>::type Type;
enum {
IsSorted = 0
};
typedef typename google::SparseHashMap<KeyType, Scalar>::type Type;
enum { IsSorted = 0 };
static void setInvalidKey(Type&, const KeyType&) {}
};
#endif
/** \class RandomSetter
* \ingroup SparseExtra_Module
* \brief The RandomSetter is a wrapper object allowing to set/update a sparse matrix with random access
*
* \tparam SparseMatrixType the type of the sparse matrix we are updating
* \tparam MapTraits a traits class representing the map implementation used for the temporary sparse storage.
* Its default value depends on the system.
* \tparam OuterPacketBits defines the number of rows (or columns) manage by a single map object
* as a power of two exponent.
*
* This class temporarily represents a sparse matrix object using a generic map implementation allowing for
* efficient random access. The conversion from the compressed representation to a hash_map object is performed
* in the RandomSetter constructor, while the sparse matrix is updated back at destruction time. This strategy
* suggest the use of nested blocks as in this example:
*
* \code
* SparseMatrix<double> m(rows,cols);
* {
* RandomSetter<SparseMatrix<double> > w(m);
* // don't use m but w instead with read/write random access to the coefficients:
* for(;;)
* w(rand(),rand()) = rand;
* }
* // when w is deleted, the data are copied back to m
* // and m is ready to use.
* \endcode
*
* Since hash_map objects are not fully sorted, representing a full matrix as a single hash_map would
* involve a big and costly sort to update the compressed matrix back. To overcome this issue, a RandomSetter
* use multiple hash_map, each representing 2^OuterPacketBits columns or rows according to the storage order.
* To reach optimal performance, this value should be adjusted according to the average number of nonzeros
* per rows/columns.
*
* The possible values for the template parameter MapTraits are:
* - \b StdMapTraits: corresponds to std::map. (does not perform very well)
* - \b StdUnorderedMapTraits: corresponds to std::unordered_map
* - \b GoogleDenseHashMapTraits: corresponds to google::dense_hash_map (best efficiency, reasonable memory consumption)
* - \b GoogleSparseHashMapTraits: corresponds to google::sparse_hash_map (best memory consumption, relatively good performance)
*
* The default map implementation depends on the availability, and the preferred order is:
* GoogleSparseHashMapTraits, StdUnorderedMapTraits, and finally StdMapTraits.
*
* For performance and memory consumption reasons it is highly recommended to use one of
* Google's hash_map implementations. To enable the support for them, you must define
* EIGEN_GOOGLEHASH_SUPPORT. This will include both <google/dense_hash_map> and
* <google/sparse_hash_map> for you.
*
* \see https://github.com/sparsehash/sparsehash
*/
template<typename SparseMatrixType,
template <typename T> class MapTraits =
* \ingroup SparseExtra_Module
* \brief The RandomSetter is a wrapper object allowing to set/update a sparse matrix with random access
*
* \tparam SparseMatrixType the type of the sparse matrix we are updating
* \tparam MapTraits a traits class representing the map implementation used for the temporary sparse storage.
* Its default value depends on the system.
* \tparam OuterPacketBits defines the number of rows (or columns) manage by a single map object
* as a power of two exponent.
*
* This class temporarily represents a sparse matrix object using a generic map implementation allowing for
* efficient random access. The conversion from the compressed representation to a hash_map object is performed
* in the RandomSetter constructor, while the sparse matrix is updated back at destruction time. This strategy
* suggest the use of nested blocks as in this example:
*
* \code
* SparseMatrix<double> m(rows,cols);
* {
* RandomSetter<SparseMatrix<double> > w(m);
* // don't use m but w instead with read/write random access to the coefficients:
* for(;;)
* w(rand(),rand()) = rand;
* }
* // when w is deleted, the data are copied back to m
* // and m is ready to use.
* \endcode
*
* Since hash_map objects are not fully sorted, representing a full matrix as a single hash_map would
* involve a big and costly sort to update the compressed matrix back. To overcome this issue, a RandomSetter
* use multiple hash_map, each representing 2^OuterPacketBits columns or rows according to the storage order.
* To reach optimal performance, this value should be adjusted according to the average number of nonzeros
* per rows/columns.
*
* The possible values for the template parameter MapTraits are:
* - \b StdMapTraits: corresponds to std::map. (does not perform very well)
* - \b StdUnorderedMapTraits: corresponds to std::unordered_map
* - \b GoogleDenseHashMapTraits: corresponds to google::dense_hash_map (best efficiency, reasonable memory
* consumption)
* - \b GoogleSparseHashMapTraits: corresponds to google::sparse_hash_map (best memory consumption, relatively good
* performance)
*
* The default map implementation depends on the availability, and the preferred order is:
* GoogleSparseHashMapTraits, StdUnorderedMapTraits, and finally StdMapTraits.
*
* For performance and memory consumption reasons it is highly recommended to use one of
* Google's hash_map implementations. To enable the support for them, you must define
* EIGEN_GOOGLEHASH_SUPPORT. This will include both <google/dense_hash_map> and
* <google/sparse_hash_map> for you.
*
* \see https://github.com/sparsehash/sparsehash
*/
template <typename SparseMatrixType,
template <typename T> class MapTraits =
#if defined(EIGEN_GOOGLEHASH_SUPPORT)
GoogleDenseHashMapTraits
GoogleDenseHashMapTraits
#else
StdUnorderedMapTraits
StdUnorderedMapTraits
#endif
,int OuterPacketBits = 6>
class RandomSetter
{
typedef typename SparseMatrixType::Scalar Scalar;
typedef typename SparseMatrixType::StorageIndex StorageIndex;
,
int OuterPacketBits = 6>
class RandomSetter {
typedef typename SparseMatrixType::Scalar Scalar;
typedef typename SparseMatrixType::StorageIndex StorageIndex;
struct ScalarWrapper
{
ScalarWrapper() : value(0) {}
Scalar value;
};
typedef typename MapTraits<ScalarWrapper>::KeyType KeyType;
typedef typename MapTraits<ScalarWrapper>::Type HashMapType;
static constexpr int OuterPacketMask = (1 << OuterPacketBits) - 1;
enum {
SwapStorage = 1 - MapTraits<ScalarWrapper>::IsSorted,
TargetRowMajor = (SparseMatrixType::Flags & RowMajorBit) ? 1 : 0,
SetterRowMajor = SwapStorage ? 1-TargetRowMajor : TargetRowMajor
};
struct ScalarWrapper {
ScalarWrapper() : value(0) {}
Scalar value;
};
typedef typename MapTraits<ScalarWrapper>::KeyType KeyType;
typedef typename MapTraits<ScalarWrapper>::Type HashMapType;
static constexpr int OuterPacketMask = (1 << OuterPacketBits) - 1;
enum {
SwapStorage = 1 - MapTraits<ScalarWrapper>::IsSorted,
TargetRowMajor = (SparseMatrixType::Flags & RowMajorBit) ? 1 : 0,
SetterRowMajor = SwapStorage ? 1 - TargetRowMajor : TargetRowMajor
};
public:
/** Constructs a random setter object from the sparse matrix \a target
*
* Note that the initial value of \a target are imported. If you want to re-set
* a sparse matrix from scratch, then you must set it to zero first using the
* setZero() function.
*/
inline RandomSetter(SparseMatrixType& target)
: mp_target(&target)
{
const Index outerSize = SwapStorage ? target.innerSize() : target.outerSize();
const Index innerSize = SwapStorage ? target.outerSize() : target.innerSize();
m_outerPackets = outerSize >> OuterPacketBits;
if (outerSize&OuterPacketMask)
m_outerPackets += 1;
m_hashmaps = new HashMapType[m_outerPackets];
// compute number of bits needed to store inner indices
Index aux = innerSize - 1;
m_keyBitsOffset = 0;
while (aux)
{
++m_keyBitsOffset;
aux = aux >> 1;
}
KeyType ik = (1<<(OuterPacketBits+m_keyBitsOffset));
for (Index k=0; k<m_outerPackets; ++k)
MapTraits<ScalarWrapper>::setInvalidKey(m_hashmaps[k],ik);
// insert current coeffs
for (Index j=0; j<mp_target->outerSize(); ++j)
for (typename SparseMatrixType::InnerIterator it(*mp_target,j); it; ++it)
(*this)(TargetRowMajor?j:it.index(), TargetRowMajor?it.index():j) = it.value();
public:
/** Constructs a random setter object from the sparse matrix \a target
*
* Note that the initial value of \a target are imported. If you want to re-set
* a sparse matrix from scratch, then you must set it to zero first using the
* setZero() function.
*/
inline RandomSetter(SparseMatrixType& target) : mp_target(&target) {
const Index outerSize = SwapStorage ? target.innerSize() : target.outerSize();
const Index innerSize = SwapStorage ? target.outerSize() : target.innerSize();
m_outerPackets = outerSize >> OuterPacketBits;
if (outerSize & OuterPacketMask) m_outerPackets += 1;
m_hashmaps = new HashMapType[m_outerPackets];
// compute number of bits needed to store inner indices
Index aux = innerSize - 1;
m_keyBitsOffset = 0;
while (aux) {
++m_keyBitsOffset;
aux = aux >> 1;
}
KeyType ik = (1 << (OuterPacketBits + m_keyBitsOffset));
for (Index k = 0; k < m_outerPackets; ++k) MapTraits<ScalarWrapper>::setInvalidKey(m_hashmaps[k], ik);
/** Destructor updating back the sparse matrix target */
~RandomSetter()
// insert current coeffs
for (Index j = 0; j < mp_target->outerSize(); ++j)
for (typename SparseMatrixType::InnerIterator it(*mp_target, j); it; ++it)
(*this)(TargetRowMajor ? j : it.index(), TargetRowMajor ? it.index() : j) = it.value();
}
/** Destructor updating back the sparse matrix target */
~RandomSetter() {
KeyType keyBitsMask = (1 << m_keyBitsOffset) - 1;
if (!SwapStorage) // also means the map is sorted
{
KeyType keyBitsMask = (1<<m_keyBitsOffset)-1;
if (!SwapStorage) // also means the map is sorted
{
mp_target->setZero();
mp_target->makeCompressed();
mp_target->reserve(nonZeros());
Index prevOuter = -1;
for (Index k=0; k<m_outerPackets; ++k)
{
const Index outerOffset = (1<<OuterPacketBits) * k;
typename HashMapType::iterator end = m_hashmaps[k].end();
for (typename HashMapType::iterator it = m_hashmaps[k].begin(); it!=end; ++it)
{
const Index outer = (it->first >> m_keyBitsOffset) + outerOffset;
const Index inner = it->first & keyBitsMask;
if (prevOuter!=outer)
{
for (Index j=prevOuter+1;j<=outer;++j)
mp_target->startVec(j);
prevOuter = outer;
}
mp_target->insertBackByOuterInner(outer, inner) = it->second.value;
}
}
mp_target->finalize();
}
else
{
VectorXi positions(mp_target->outerSize());
positions.setZero();
// pass 1
for (Index k=0; k<m_outerPackets; ++k)
{
typename HashMapType::iterator end = m_hashmaps[k].end();
for (typename HashMapType::iterator it = m_hashmaps[k].begin(); it!=end; ++it)
{
const Index outer = it->first & keyBitsMask;
++positions[outer];
}
}
// prefix sum
StorageIndex count = 0;
for (Index j=0; j<mp_target->outerSize(); ++j)
{
StorageIndex tmp = positions[j];
mp_target->outerIndexPtr()[j] = count;
positions[j] = count;
count += tmp;
}
mp_target->makeCompressed();
mp_target->outerIndexPtr()[mp_target->outerSize()] = count;
mp_target->resizeNonZeros(count);
// pass 2
for (Index k=0; k<m_outerPackets; ++k)
{
const Index outerOffset = (1<<OuterPacketBits) * k;
typename HashMapType::iterator end = m_hashmaps[k].end();
for (typename HashMapType::iterator it = m_hashmaps[k].begin(); it!=end; ++it)
{
const Index inner = (it->first >> m_keyBitsOffset) + outerOffset;
const Index outer = it->first & keyBitsMask;
// sorted insertion
// Note that we have to deal with at most 2^OuterPacketBits unsorted coefficients,
// moreover those 2^OuterPacketBits coeffs are likely to be sparse, an so only a
// small fraction of them have to be sorted, whence the following simple procedure:
Index posStart = mp_target->outerIndexPtr()[outer];
Index i = (positions[outer]++) - 1;
while ( (i >= posStart) && (mp_target->innerIndexPtr()[i] > inner) )
{
mp_target->valuePtr()[i+1] = mp_target->valuePtr()[i];
mp_target->innerIndexPtr()[i+1] = mp_target->innerIndexPtr()[i];
--i;
}
mp_target->innerIndexPtr()[i+1] = internal::convert_index<StorageIndex>(inner);
mp_target->valuePtr()[i+1] = it->second.value;
mp_target->setZero();
mp_target->makeCompressed();
mp_target->reserve(nonZeros());
Index prevOuter = -1;
for (Index k = 0; k < m_outerPackets; ++k) {
const Index outerOffset = (1 << OuterPacketBits) * k;
typename HashMapType::iterator end = m_hashmaps[k].end();
for (typename HashMapType::iterator it = m_hashmaps[k].begin(); it != end; ++it) {
const Index outer = (it->first >> m_keyBitsOffset) + outerOffset;
const Index inner = it->first & keyBitsMask;
if (prevOuter != outer) {
for (Index j = prevOuter + 1; j <= outer; ++j) mp_target->startVec(j);
prevOuter = outer;
}
mp_target->insertBackByOuterInner(outer, inner) = it->second.value;
}
}
mp_target->finalize();
} else {
VectorXi positions(mp_target->outerSize());
positions.setZero();
// pass 1
for (Index k = 0; k < m_outerPackets; ++k) {
typename HashMapType::iterator end = m_hashmaps[k].end();
for (typename HashMapType::iterator it = m_hashmaps[k].begin(); it != end; ++it) {
const Index outer = it->first & keyBitsMask;
++positions[outer];
}
}
// prefix sum
StorageIndex count = 0;
for (Index j = 0; j < mp_target->outerSize(); ++j) {
StorageIndex tmp = positions[j];
mp_target->outerIndexPtr()[j] = count;
positions[j] = count;
count += tmp;
}
mp_target->makeCompressed();
mp_target->outerIndexPtr()[mp_target->outerSize()] = count;
mp_target->resizeNonZeros(count);
// pass 2
for (Index k = 0; k < m_outerPackets; ++k) {
const Index outerOffset = (1 << OuterPacketBits) * k;
typename HashMapType::iterator end = m_hashmaps[k].end();
for (typename HashMapType::iterator it = m_hashmaps[k].begin(); it != end; ++it) {
const Index inner = (it->first >> m_keyBitsOffset) + outerOffset;
const Index outer = it->first & keyBitsMask;
// sorted insertion
// Note that we have to deal with at most 2^OuterPacketBits unsorted coefficients,
// moreover those 2^OuterPacketBits coeffs are likely to be sparse, an so only a
// small fraction of them have to be sorted, whence the following simple procedure:
Index posStart = mp_target->outerIndexPtr()[outer];
Index i = (positions[outer]++) - 1;
while ((i >= posStart) && (mp_target->innerIndexPtr()[i] > inner)) {
mp_target->valuePtr()[i + 1] = mp_target->valuePtr()[i];
mp_target->innerIndexPtr()[i + 1] = mp_target->innerIndexPtr()[i];
--i;
}
mp_target->innerIndexPtr()[i + 1] = internal::convert_index<StorageIndex>(inner);
mp_target->valuePtr()[i + 1] = it->second.value;
}
}
delete[] m_hashmaps;
}
delete[] m_hashmaps;
}
/** \returns a reference to the coefficient at given coordinates \a row, \a col */
Scalar& operator() (Index row, Index col)
{
const Index outer = SetterRowMajor ? row : col;
const Index inner = SetterRowMajor ? col : row;
const Index outerMajor = outer >> OuterPacketBits; // index of the packet/map
const Index outerMinor = outer & OuterPacketMask; // index of the inner vector in the packet
const KeyType key = internal::convert_index<KeyType>((outerMinor<<m_keyBitsOffset) | inner);
return m_hashmaps[outerMajor][key].value;
}
/** \returns a reference to the coefficient at given coordinates \a row, \a col */
Scalar& operator()(Index row, Index col) {
const Index outer = SetterRowMajor ? row : col;
const Index inner = SetterRowMajor ? col : row;
const Index outerMajor = outer >> OuterPacketBits; // index of the packet/map
const Index outerMinor = outer & OuterPacketMask; // index of the inner vector in the packet
const KeyType key = internal::convert_index<KeyType>((outerMinor << m_keyBitsOffset) | inner);
return m_hashmaps[outerMajor][key].value;
}
/** \returns the number of non zero coefficients
*
* \note According to the underlying map/hash_map implementation,
* this function might be quite expensive.
*/
Index nonZeros() const
{
Index nz = 0;
for (Index k=0; k<m_outerPackets; ++k)
nz += static_cast<Index>(m_hashmaps[k].size());
return nz;
}
/** \returns the number of non zero coefficients
*
* \note According to the underlying map/hash_map implementation,
* this function might be quite expensive.
*/
Index nonZeros() const {
Index nz = 0;
for (Index k = 0; k < m_outerPackets; ++k) nz += static_cast<Index>(m_hashmaps[k].size());
return nz;
}
protected:
HashMapType* m_hashmaps;
SparseMatrixType* mp_target;
Index m_outerPackets;
unsigned char m_keyBitsOffset;
protected:
HashMapType* m_hashmaps;
SparseMatrixType* mp_target;
Index m_outerPackets;
unsigned char m_keyBitsOffset;
};
} // end namespace Eigen
} // end namespace Eigen
#endif // EIGEN_RANDOMSETTER_H
#endif // EIGEN_RANDOMSETTER_H