修改矩阵后,通过内存指针 (memptr) 直接访问犰狳矩阵的条目不起作用

Directly accessing entries of armadillo-matrix by memory-pointer (memptr) does not work after matrix is modified

我有一个问题,我想通过结构(或 class)中的指针访问犰狳矩阵“M”的某些条目。初始化 M 后,我在结构中设置了指针。通过取消引用指针,我可以看到它具有正确的值(M 的第一个条目 - 或 M(0,0))。

然后我将 M 更改为 M * M。但是现在取消引用指针不再给我正确的值。奇怪的是:如果我有一个小矩阵,即 3x3 或 4x4(请参阅我的代码中的“matrixSize”),则不会发生错误。对于小矩阵,取消引用指针会给出 RIGHT 值。 更大的矩阵虽然会导致错误的值(5x5 类似于“2.76282e-320”,这可能是内存中的某个随机位置)。

我在这里做错了什么?我该如何解决这个问题?

如果有帮助,我想解释一下我想要实现的目标: 我有一个延迟耦合节点网络,每个节点都有某种动态行为。 (想想延迟耦合微分方程 DDE - 延迟耦合振荡器)。由于它们是延迟耦合的,我需要存储它们过去的状态(它们的历史数组)。每个振荡器也有一些局部动态,动态变量不影响其他节点,这意味着我不必存储它们的历史记录。 该矩阵用于保存节点的某些变量的过去状态。我想把它们放在一个矩阵中,因为我想对它们使用向量运算(矩阵的一个索引代表时间,而另一个是节点索引)。但我也想单独访问它们以计算每个节点(振荡器)的一些局部动态。所以我想更新单个节点,还有全局状态。 这就是为什么同时使用这两种表示形式会有所帮助:对于局部动力学,我通过指向矩阵的指针访问延迟状态。对于全局动态,我通过充当历史数组的矩阵中的一行访问耦合变量。

#include <iostream>
#include <armadillo>

struct someStruct {
    const double *currentStateInMatrix;
    void printvalue() {std::cout << "*currentState (pointer to first enty of matrix) = " << *currentStateInMatrix << std::endl;}
};

int main(int argc, char* argv[]){

    uint M_size = 4;

    arma::Mat<double> M(M_size, M_size, arma::fill::randu);


    double* pointerIntoMatrix = M.memptr();
    std::cout << "pointer [ " << pointerIntoMatrix << " ] has value: " << *pointerIntoMatrix << std::endl;

    someStruct myStruct;
    myStruct.currentStateInMatrix = pointerIntoMatrix;

    std::cout << "original matrix M: \n" << M;
    myStruct.printvalue();
    std::cout << "\n+++changing contents of matrix M+++\n\n";

    M = M * M;

    std::cout << "M * M: \n" << M;
    myStruct.printvalue();
}

我编译它使用: g++ file.cpp -std=c++17 -larmadillo -o main

犰狳中的运算M = M * M是矩阵乘法(不是逐元素乘法)。因此,将 M * M 的中间计算直接存储到 M 中是有问题的。它将覆盖 M 中仍然需要完成 M * M 操作的现有数据。

可以安全地假设 Armadillo 检测到这个问题并将 M * M 的结果存储到一个单独的内存块中,然后将该块分配给 M

有很多方法可以解决这个问题。使用固定大小的矩阵,如评论中提到的 darcamo。使用 Mat<double>::fixed<4, 4> M; 声明矩阵。

另一种方法是手动管理矩阵元素的内存,并告诉 M 矩阵始终使用该内存。有 advanced constructors 可以做到这一点:

mat(ptr_aux_mem, n_rows, n_cols, copy_aux_mem = true, strict = false)

所以我们可以这样做:

double* my_mem = (double*)std::malloc(M_size * M_size * sizeof(double));
// or use new[]

Mat<double> M(my_mem, M_size, M_size, false, true);

// don't forget to call std::free(my_mem) or delete[] when done!

提醒一句。上述两种解决方法(固定大小矩阵和手动内存管理)可能对性能有轻微影响。无法避免为 M = M * M 操作使用单独的内存块。使用这些变通方法时,Armadillo 会将 M * M 的结果存储到临时缓冲区中,然后将缓冲区的内容复制到 M.

使用的内存中