修改矩阵后,通过内存指针memptr直接访问 armadillo-matrix 的条目不起作用

问题描述

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

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

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

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

#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

解决方法

Armadillo 中的操作 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,false,true);

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

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

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...