特征:累积可变大小的数组

Eigen: Accumulating arrays of variable size

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

我有一个保存 Eigen::Array 数据数组的类和一个通过沿第一个轴附加到数组来添加新数据(行数可能会有所不同(的方法。我通过创建一个大小合适的新数组并使用旧数据和新数据初始化它来解决累积问题。

typedef Eigen::Array<double, Eigen::Dynamic, 3> DataArray
class Accumulator {
    void add(DataArray &new_data) {
        DataArray accu(accumulated_data_.rows() + new_data.rows(), 3)
        accu << accumulated_data_, new_data;
        accumulated_data_ = accu;
    }
    DataArray accumulated_data_;
}

这样做有什么不对吗?还是首选调整累积数据数组的大小:

  • .resize()和复制新旧
  • .conservative_resize()并复制新数据(如果新数据超过 1 行,则需要进行块操作(

首先,当前实现存在两个易于修复的缺陷:

  • 默认情况下,Eigen 以列主顺序存储数组(和矩阵(,因此如果要追加行,则应首选RowMajor存储顺序:

    Eigen::Array<double, Eigen::Dynamic, 3, Eigen::RowMajor>

  • 由于accu将不再使用,因此应将其移至累加器: accumulated_data_ = std::move(accu);

    如果您使用的是 C++11 之前的版本,您还可以交换数据:

    accumulated_data_.swap(accu);

那么你的方法几乎等同于

accumulated_data_.conservativeResize(accumulated_data_.rows() + new_data.rows(), 3);
accumulated_data_.bottomRows(new_data.rows()) = new_data;

在每次调用时,您仍将拥有内存(重新(分配和内存副本。

更有效的方法是仅偶尔调整accumulated_data_的大小(理想情况下仅在开始时调整一次(,并跟踪当前实际有效的内容:

typedef Eigen::Array<double, Eigen::Dynamic, 3, Eigen::RowMajor> DataArray;
class Accumulator {
public:
    Accumulator(Eigen::Index initialCapacity=10000) : accumulated_data_(initialCapacity, 3), actual_rows_(0) {}
    void add(DataArray &new_data) {
        if(actual_rows_+new_data.rows() > accumulated_data_.rows())
        { // TODO adapt memory-growing to your use case
             accumulated_data_.conservativeResize(2*actual_rows_+new_data.rows(), 3);
        }
        accumulated_data_.midRows(actual_rows, new_data.rows()) = new_data;
        actual_rows_+=new_data.rows();
    }
    DataArray accumulated_data_;
    Eigen::Index actual_rows_;
};