修改矩阵后,通过内存指针 (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
.
使用的内存中
我有一个问题,我想通过结构(或 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
.