My question is how to initialize an eigen Matrix, but NOT this way:
matrix << 1,0,1,0,
1,0,1,0,
1,0,1,0,
I think I found a solution! Its not fast or efficient but it works:
#include "topo.h"
#include <iostream>
#include <fstream>
#include <vector>
#include <Eigen/Dense>
#include <Eigen/Sparse>
#include <iterator>
#include <algorithm>
using namespace std;
using namespace Eigen;
/**Read data from File and store it in vector as string**/
int readFromFile (const char * path, vector <string> & mv) // muss vector vorher resized werden? wenn ja lese zeilenanzahl
{
fstream file;
string line;
file.open(path);
while (getline(file,line)) // lese zeile für zeile
{
mv.push_back(line); //fülle vector von hinten last in first
}
file.close();
return 0;
}
typedef Matrix <int, 4, 4> MyMatrix; // Matrix später dynamisch
/**Parsing data to be used as Eigen Matrix**/
int fromVectoEigen (vector<string> & source, MyMatrix & target)
{ /**convert string to int and write it to the two dimensional array **/
int array [4][4]; // noch resize nach vectorsize -->matrizen sind quadratisch
int i = source.size();
for ( i= i-1 ; i >= 0 ; i-- ) // da nur von hintern auf vector zugreifbar auch von hinten bei array anfangen
{
string myString = source.back(); // leztzes Element von Vector als String
stringstream ssin(myString);
int j = 0;
while (ssin.good() && j < 4) // auch hier vectorsize später dynamisch
{
ssin >> array[j][i]; // fülle spalten in i.ter zeile
++j;
}
source.pop_back(); //lösche letztes element
}
// cout<<array[0][0]<<array[1][0]<<array[2][0]<<array[3][0]<<'\n';
// cout<<array[0][1]<<array[1][1]<<array[2][1]<<array[3][1]<<'\n';
// cout<<array[0][2]<<array[1][2]<<array[2][2]<<array[3][2]<<'\n';
// cout<<array[0][3]<<array[1][3]<<array[2][3]<<array[3][3]<<'\n';
//
/** from 2 dimensional array to one dimensional array**/
int newarray [16]; // vectorsize * vectorsize
int k = 0;
for ( int i = 0 ; i< 4 ; i++) // vectorsize
{ for (int j = 0 ; j<4; j++) // vectorsize
{
newarray[k]=array[j][i];
k++;
}
}
/**create Eigen Matrix from Array**/
target= Map<Matrix4i>(newarray);
target.transposeInPlace();
cout<<target<<'\n';
return 0 ;
}
I used element-wise initialization (assuming we know nrows and ncols):
MatrixXf X = MatrixXf::Zero(nrows,ncols);
ifstream fin ("./data.txt");
if (fin.is_open())
{
for (int row = 0; row < nrows; row++)
for (int col = 0; col < ncols; col++)
{
float item = 0.0;
fin >> item;
X(row, col) = item;
}
fin.close();
}
cout << "X = " << endl << X << endl;
I used iterators to collect the data in a vector and then initialize the matrix. The conversion to the vector<double>
seem to be the time-consuming part of the method, which approximately has the same speed as the solutions above. Ideas on how to improve this would be interesting.
template <class T>
using Tmat = Eigen::Matrix<T,Dynamic,Dynamic>;
Tmat<double> txt_to_mat(std::string path, int rows, int cols)
{
std::ifstream fstr(path.c_str());
std::vector<double> data_vec = std::vector<double>{
std::istream_iterator<double>(fstr),
std::istream_iterator<double>()
};
Tmat<double> mat(rows, cols);
for(int i=0; i<rows; i++){
for(int j=0; j<cols; j++){
mat(i,j) = data_vec[i*cols + j];
}
}
return mat;
}
A variation using only Eigen::Map for mapping data from std::vector, based on examples from https://eigen.tuxfamily.org/dox/group__TutorialMapClass.html
#include <vector>
#include <Eigen/Dense>
std::vector<double> myStdVector;
// Insert code for filling myStdVector here
// ....
// Detect or set number of rows/columns
size_t numRows = 3;
size_t numCols = 7;
typedef Eigen::Map<Eigen::MatrixXd> Mapper;
Mapper myMatrix(&myStdVector.data()[0], numRows, numCols);
The following code works with files containing matrices of arbitrary size:
#include <iostream>
#include <fstream>
#include <string>
#include <Eigen/Dense>
using namespace std;
using namespace Eigen;
#define MAXBUFSIZE ((int) 1e6)
MatrixXd readMatrix(const char *filename)
{
int cols = 0, rows = 0;
double buff[MAXBUFSIZE];
// Read numbers from file into buffer.
ifstream infile;
infile.open(filename);
while (! infile.eof())
{
string line;
getline(infile, line);
int temp_cols = 0;
stringstream stream(line);
while(! stream.eof())
stream >> buff[cols*rows+temp_cols++];
if (temp_cols == 0)
continue;
if (cols == 0)
cols = temp_cols;
rows++;
}
infile.close();
rows--;
// Populate matrix with numbers.
MatrixXd result(rows,cols);
for (int i = 0; i < rows; i++)
for (int j = 0; j < cols; j++)
result(i,j) = buff[ cols*i+j ];
return result;
};
Regards.
I just released an extension of the Eigen package that does some of what you want. It defines the >> operator, so you can say:
MatrixXd A(5,5); cin >> A;
It also lets you assign a VectorXd to equal a std::vector. The extended version of Eigen can be found here. However, it doesn't (yet) let you copy a std::vector into a MatrixXd object that isn't a vector. The functionality you want is the Map function in Eigen.