在 Matlab 中有效地存储大部分为零的 N 维数组

Efficiently store an N-dimensional array of mostly zeros in Matlab

我实现了有限差分算法来求解 PDE。

网格是大小为 [Nx, Nz] 的结构化二维域,已求解 Nt 次。

我预先分配了包含所有解决方案的对象:

sol = zeros(Nx, Nz, Nt, 'single') ;

这很容易变得太大,我收到“内存不足”错误。 不幸的是 sparse 不适用于 N 维数组。

为了这个问题,知道这些值并不重要,不用说,随着网格间距的减小和模拟时间的增加,RAM 使用量呈指数增长。

我知道我不需要为了解决方案的进步而存储每个时间点。只存储前两个时间步长就足够了。 但是,出于post-处理原因,我需要在所有时间步长(或至少是总数的约数)访问解决方案。可能有助于指定即使在解决方案之后,网格仍然主要由零填充。

我是在打败仗还是有更有效的方法(其他类型的对象、矢量化...)?

谢谢。

您可以将数组存储为稀疏、线性形式;即,长度等于维度乘积的列向量:

sol = sparse([], [], [], Nx*Nz*Nt, 1); % sparse column vector containing zeros

然后,不是正常索引,

sol(x, z, t),

您需要将索引xzt转换为对应的线性索引:

  • 对于 标量 您使用的指数

    sol(x + Nx*(z-1) + Nx*Nz*(t-1))
    

    为了方便,你可以定义一个辅助函数:

    ind = @(sol, x, y, t) sol(x + Nx*(z-1) + Nx*Nz*(t-1))
    

    因此索引变得更具可读性:

    ind(sol, x, z, t)
    
  • 对于一般(数组)索引,您需要reshape the indices along different dimensions so that implicit expansion生成适当的线性索引:

    sol(reshape(x,[],1,1) + Nx*(reshape(z,1,[],1)-1) + Nx*Nz*(reshape(t,1,1,[])-1))
    

    当然也可以封装成函数

检查 到线性索引的转换是否有效(一般情况下,使用 non-sparse 数组与正常索引进行比较):

Nx = 15; Nz = 18; Nt = 11;
sol = randi(9, Nx, Nz, Nt);
x = [5 6; 7 8]; z = 7; t = [4 9 1];
isequal(sol(x, z, t), ...
    sol(reshape(x,[],1,1) + Nx*(reshape(z,1,[],1)-1) + Nx*Nz*(reshape(t,1,1,[])-1)))

给予

ans =
  logical
   1

您可以创建一个稀疏矩阵元胞数组来存储结果。但是,如果使用全矩阵比稀疏矩阵更快并将全矩阵转换为稀疏矩阵并将其放入单元格中,则可以在全矩阵上执行计算。