简体   繁体   English

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

[英]Eigen: Accumulating arrays of variable size

I have a class holding an Eigen::Array of data and a method that adds new data (number of rows may vary) by appending to the array along the first axis. 我有一个类,其中包含一个Eigen :: Array数据,以及一个通过沿第一个轴附加到数组来添加新数据(行数可能会变化)的方法。 I solved the accumulation by creating a new Array of the right size and initializing it with the old and the new data. 我通过创建一个大小合适的新数组并用新旧数据进行初始化来解决了累积问题。

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_;
}

Is there anything wrong with doing it like this? 这样做有什么问题吗? Or is it preferred to resize the accumulated data array: 还是最好调整累积数据数组的大小:

  • .resize() and copy in both old and new .resize()并复制旧的和新的
  • or .conservative_resize() and copy in the new data (requires block operations if new data is longer than 1 row) .conservative_resize()并复制新数据(如果新数据长于1行,则需要执行块操作)

First of all, two easy-to-fix flaws with your current implementation: 首先,当前的实现存在两个易于修复的缺陷:

  • Eigen stores Arrays (and Matrices) in column-major order by default, so if you are appending rows, you should prefer the RowMajor storage order: Eigen默认情况下按列主顺序存储数组(和矩阵),因此,如果要追加行,则应首选RowMajor存储顺序:

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

  • Since accu will not be used anymore, you should move it to the accumulator: accumulated_data_ = std::move(accu); 由于accu将不再使用,你应该把它移动到蓄电池: accumulated_data_ = std::move(accu);

    If you are pre-C++11, you can also swap the data: 如果您使用的是C ++ 11之前的版本,则还可以交换数据:

    accumulated_data_.swap(accu);

Then your approach is nearly equivalent to 那么你的方法几乎等同于

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

You will still have memory (re-)allocations and memory-copies at every call. 每次调用时,您仍将具有内存(重新)分配和内存副本。

A more efficient approach would be to resize the accumulated_data_ only occasionally (ideally just once at the beginning), and keep track of how much of it is currently actually valid: 一个更有效的方法是调整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_;
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM