指向切成薄片的特征矩阵

发布于 2025-01-26 22:33:13 字数 317 浏览 1 评论 0原文

我有一个函数,该函数将指针指向特征矩阵。我需要将此矩阵切成几片,然后将矩阵的一部分传递给该函数。我想避免复制数据,因此我想用指针将其传递。

我切一个矩阵,例如:

MatrixXd A;
// some operations with the matrix
// now I want something like this:
MatrixXd *B = &A(seq(2, 4), all);

最后一行是无效的。我如何获取指向矩阵的指针,以便仍然可以将其视为特征矩阵?有解决方法吗?同样,我想避免创建新矩阵,就像我的真实程序中一样大。

I have a function which takes a pointer to an Eigen matrix. I need to slice this matrix to several pieces and pass a portion of the matrix to the function. I want to avoid copying data, so I want to pass it with a pointer.

I slice a matrix, for example like this:

MatrixXd A;
// some operations with the matrix
// now I want something like this:
MatrixXd *B = &A(seq(2, 4), all);

The last line is invalid. How can I get a pointer to a piece of matrix so that it can still be treated as an Eigen matrix? Are there any workarounds? Again, I'd like to avoid creating new matrices as in my real program they are quite big.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

濫情▎り 2025-02-02 22:33:13

这就是eigen :: ref是用来的。 “如何写通用但非塑造功能?

请参阅 这样:


void consume_matrix(const Eigen::Ref<const Eigen::MatrixXd>& in);
void produce_matrix(Eigen::Ref<Eigen::MatrixXd> out);


void foo()
{
    Eigen::MatrixXd matrix = ...;
    produce_matrix(matrix.middleRows(start, len));
    consume_matrix(matrix.leftCols(len));
}

存储块引用

eigen不带有非常适合保留矩阵的“借用”块表达式的类型。对于这种情况,我不推荐ref,因为它太容易了,无法指出临时分配,这很容易导致悬挂的指针。

最终,存储借来的观点是从根本上不安全的操作。但是,如果您绝对必须这样做,我将使用eigen :: Map。至少这清楚地表明,您不拥有所引用的内存。类似的事情:

struct MatrixReference
{
  using map_type = Eigen::Map<
    Eigen::MatrixXd, Eigen::Unaligned, Eigen::OuterStride<> >;

  map_type matrix;

  template<class Derived>
  static map_type to_map(const Eigen::DenseBase<Derived>& matrix) noexcept
  {
    assert(matrix.innerStride() == 1);
    return map_type(const_cast<double*>(matrix.derived().data()),
                    matrix.rows(), matrix.cols(),
                    Eigen::OuterStride<>(matrix.outerStride()));
  }

  MatrixReference() noexcept
  : matrix(nullptr, 0, 0, Eigen::OuterStride<>(1))
  {}
  template<class Derived>
  explicit MatrixReference(const Eigen::DenseBase<Derived>& matrix) noexcept
    : matrix(to_map(matrix))
  {}
  MatrixReference(const MatrixReference&) = default;
  MatrixReference& operator=(const MatrixReference& o) noexcept
  {
    // placement-new because assignment would overwrite the content
    new (&matrix) map_type(o.matrix);
    return *this;
  }
};
int main()
{
  Eigen::MatrixXd mat = Eigen::MatrixXd::Random(4, 5);
  MatrixReference ref(mat.topRows(2));
  std::cout << mat << "\n\n" << ref.matrix << "\n\n";
}

一个稍微更安全的选项是将shared_ptr保留到矩阵中,并存储信息单独使用的切片。也许这样:

struct CountedBlockRef
{
  std::shared_ptr<Eigen::MatrixXd> matrix;
  Eigen::Index first_row, first_col, rows, cols;

  using block_type = Eigen::Block<
    Eigen::MatrixXd, Eigen::Dynamic, Eigen::Dynamic>;
  using const_block_type = Eigen::Block<
    const Eigen::MatrixXd, Eigen::Dynamic, Eigen::Dynamic>;

  CountedBlockRef() noexcept
  : matrix(), first_row(), first_col(), rows(), cols()
  {}
  CountedBlockRef(std::shared_ptr<Eigen::MatrixXd> matrix,
                  Eigen::Index first_row, Eigen::Index first_col,
                  Eigen::Index rows, Eigen::Index cols) noexcept
    : matrix(std::move(matrix)),
      first_row(first_row),
      first_col(first_col),
      rows(rows),
      cols(cols)
  {}
  block_type block() noexcept
  { return matrix->block(first_row, first_col, rows, cols); }

  const_block_type block() const noexcept
  {
    const Eigen::MatrixXd& matrix = *this->matrix;
    return matrix.block(first_row, first_col, rows, cols);
  }
};
int main()
{
  std::shared_ptr<Eigen::MatrixXd> matptr =
    std::make_shared<Eigen::MatrixXd>(Eigen::MatrixXd::Random(4, 5));
  CountedBlockRef aref(matptr, 0, 0, 2, 5);
  std::cout << *matptr << "\n\n" << aref.block() << '\n';
}

这样,即使在调整了矩阵和悬空指针大小后,参考文献也将保持有效。只有缩水仍然是一个威胁,但假设您与他们进行了编译,那会被断言所抓住。

That's what Eigen::Ref was built for. See the section "How to write generic, but non-templated function?"

Something like this:


void consume_matrix(const Eigen::Ref<const Eigen::MatrixXd>& in);
void produce_matrix(Eigen::Ref<Eigen::MatrixXd> out);


void foo()
{
    Eigen::MatrixXd matrix = ...;
    produce_matrix(matrix.middleRows(start, len));
    consume_matrix(matrix.leftCols(len));
}

Storing block references

Eigen doesn't come with a type that is well-suited to keep a "borrowed" block expression of a matrix. I wouldn't recommend Ref for this case because it is far too easy to make it point at temporary allocations which can easily lead to dangling pointers.

Ultimately, storing borrowed views is a fundamentally unsafe operation. But if you absolutely have to do it, I would use an Eigen::Map. At least that makes it clear you aren't owning the memory to which you refer. Something like this:

struct MatrixReference
{
  using map_type = Eigen::Map<
    Eigen::MatrixXd, Eigen::Unaligned, Eigen::OuterStride<> >;

  map_type matrix;

  template<class Derived>
  static map_type to_map(const Eigen::DenseBase<Derived>& matrix) noexcept
  {
    assert(matrix.innerStride() == 1);
    return map_type(const_cast<double*>(matrix.derived().data()),
                    matrix.rows(), matrix.cols(),
                    Eigen::OuterStride<>(matrix.outerStride()));
  }

  MatrixReference() noexcept
  : matrix(nullptr, 0, 0, Eigen::OuterStride<>(1))
  {}
  template<class Derived>
  explicit MatrixReference(const Eigen::DenseBase<Derived>& matrix) noexcept
    : matrix(to_map(matrix))
  {}
  MatrixReference(const MatrixReference&) = default;
  MatrixReference& operator=(const MatrixReference& o) noexcept
  {
    // placement-new because assignment would overwrite the content
    new (&matrix) map_type(o.matrix);
    return *this;
  }
};
int main()
{
  Eigen::MatrixXd mat = Eigen::MatrixXd::Random(4, 5);
  MatrixReference ref(mat.topRows(2));
  std::cout << mat << "\n\n" << ref.matrix << "\n\n";
}

A slightly safer option is to keep a shared_ptr to the matrix and store the information what slice you use separately. Maybe like this:

struct CountedBlockRef
{
  std::shared_ptr<Eigen::MatrixXd> matrix;
  Eigen::Index first_row, first_col, rows, cols;

  using block_type = Eigen::Block<
    Eigen::MatrixXd, Eigen::Dynamic, Eigen::Dynamic>;
  using const_block_type = Eigen::Block<
    const Eigen::MatrixXd, Eigen::Dynamic, Eigen::Dynamic>;

  CountedBlockRef() noexcept
  : matrix(), first_row(), first_col(), rows(), cols()
  {}
  CountedBlockRef(std::shared_ptr<Eigen::MatrixXd> matrix,
                  Eigen::Index first_row, Eigen::Index first_col,
                  Eigen::Index rows, Eigen::Index cols) noexcept
    : matrix(std::move(matrix)),
      first_row(first_row),
      first_col(first_col),
      rows(rows),
      cols(cols)
  {}
  block_type block() noexcept
  { return matrix->block(first_row, first_col, rows, cols); }

  const_block_type block() const noexcept
  {
    const Eigen::MatrixXd& matrix = *this->matrix;
    return matrix.block(first_row, first_col, rows, cols);
  }
};
int main()
{
  std::shared_ptr<Eigen::MatrixXd> matptr =
    std::make_shared<Eigen::MatrixXd>(Eigen::MatrixXd::Random(4, 5));
  CountedBlockRef aref(matptr, 0, 0, 2, 5);
  std::cout << *matptr << "\n\n" << aref.block() << '\n';
}

That way, the reference will remain valid even after resizing the matrix and dangling pointers are avoided. Only shrinking remains a threat but that is caught by assertions, assuming you compile with them.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文