具有未知行数和列数的矩阵特征库

Matrix with unknown number of rows and columns Eigen library

本文关键字:特征 未知      更新时间:2023-10-16

我想从文件中读取数据到Eigen中的矩阵。我已经编码了所有东西,但我遇到了一个问题。我事先不知道文件中有多少数据点,所以我想在不指定矩阵大小的情况下初始化矩阵。我知道下面的初始化矩阵的方法在Eigen中是有效的:

MatrixXd A;

但是现在如果我写例如

A << 1, 2,
     4, 7;

它不工作。在这个例子中,我希望它能识别出它是一个2x2矩阵,这样我就可以处理它了。我的问题是,如何在不指定大小的情况下,向A中添加数据?

如果您想要从没有明确指定矩阵大小的文件中读取数据,那么我建议将std::vector中的条目推回,并在解析结束时使用Mapstd::vector复制数据:

MatrixXf A;
std::vector<float> entries;
int rows(0), cols(0);
while(...) { entries.push_back(...); /* update rows/cols*/ }
A = MatrixXf::Map(&entries[0], rows, cols);

这将比每次调用conservativeResize更有效。

From the eigentutorial about Matrix


当然,本征并不局限于已知维数的矩阵在编译时。RowsAtCompileTime和ColsAtCompileTime模板参数可以采用特殊值Dynamic,表示大小在编译时是未知的,因此必须作为运行时处理变量。在特征学术语中,这样的尺寸被称为a动态规模;而在编译时已知的大小称为固定大小。例如,方便的类型为pedef MatrixXd,表示a具有动态大小的双精度矩阵,定义如下:

typedef Matrix<double, Dynamic, Dynamic> MatrixXd;
同样,我们定义了一个自解释的类型pedef VectorXi为:
typedef Matrix<int, Dynamic, 1> VectorXi;

您可以完美地使用例如固定数量的行与动态列数,如:

Matrix<float, 3, Dynamic>

下面是我刚刚快速做的一个例子:

Eigen::Matrix<float, Eigen::Dynamic, Eigen::Dynamic> myMatrix;
myMatrix.resize(1, 1);
myMatrix(0, 0) = 1.0;
myMatrix.resize(2, 2);
myMatrix(1, 1) = 1.0;
myMatrix.resize(3, 3);
myMatrix(2, 2) = 1.0;
myMatrix.resize(4, 4);
myMatrix(3, 3) = 1.0;

所以我有类似的(但不完全相同的问题),感谢这个情节和回答从这个论坛的另一个问题,我创建了代码。我有一个未知矩阵大小的文件作为输入,我需要稍后对其进行操作。

我们首先读取文件的第一行,获取数据,放入向量,读取列数。然后从文件中读取所有剩余的数据,继续解析到vector。

void getTimeSeries(const char* TimeSeriesFileName1)
{
std::ifstream ifile(TimeSeriesFileName1, std::ios::in);
std::vector<double> LineOfTimeSeriesFile;
std::string line;
int rows(0), cols(0);
double number;
//get number of columns you have to read the first line
if (ifile.good())
{
  std::getline(ifile, line);
  std::stringstream ss(line);
  while (ss>>number) 
  {
    ++cols;
    LineOfTimeSeriesFile.push_back(number);
  }
  std::cout << cols << std::endl;
}
// consume and discard token from stream.
if (ifile.fail())
{
  ifile.clear();
  std::string token;
  ifile >> token;
}
//Read all the data into a one big vector
do
{
    // read as many numbers as possible.
    for (number = 0; ifile >> number;) {
        LineOfTimeSeriesFile.push_back(number);
    }
    // consume and discard token from stream.
    if (ifile.fail())
    {
        ifile.clear();
        std::string token;
        ifile >> token;
    }
}
while (!ifile.eof());
//get the number of rows
rows = LineOfTimeSeriesFile.size()/cols;
for (std::size_t i=0; i < LineOfTimeSeriesFile.size(); ++i) 
{
    std::cout << LineOfTimeSeriesFile[i] << std::endl;
    std::cout << "Rows: " << cols << ", Cols: " << rows << ", points: " << LineOfTimeSeriesFile.size() << std::endl;
}    
//Here we map the matrix
timeSeriesMatrix = MatrixXd::Map(&LineOfTimeSeriesFile[0], rows, cols);

我很高兴看到这段代码在效率方面的一些审查,但我认为它目前是OK的。输入文件是用"tab/空格"分隔的矩阵。

你所要求的是不可能做到的。您希望库如何猜测数组的形状?它怎么能确定它不是4x11x4。对于c++编译器来说,新行无关紧要,因此您的代码与m << 1,2,3,4;相同。

动态数组是动态的,因为它们的大小在编译时不知道,而是在运行时知道。但是,在放入元素之前,您仍然需要设置矩阵的大小/形状,因为库需要知道需要为矩阵分配多少空间。

默认Matrix m;的大小为0x0。你需要在放入元素之前调整它的大小。

#include<Eigen/Core>
#include<iostream>
int main(){
Eigen::MatrixXd m;
m.resize(2,2);
m << 1, 2, 3, 4;
std::cout << m << 'n';
m.resize(1,4);
std::cout << m << 'n';
}