Skip to content

MATLAB - 稀疏矩阵

在数值计算中,稀疏矩阵(sparse matrix)是指大多数元素为零的矩阵。相反,大多数元素为非零的矩阵称为密集矩阵(dense matrix)。像处理密集矩阵一样存储和操作稀疏矩阵,在内存和计算时间方面都效率极低。

MATLAB 提供了强大而高效的稀疏矩阵实现,它只存储非零元素及其索引。

稀疏矩阵在科学和工程的许多领域至关重要,包括网络分析、有限元建模和计算流体力学。主要优势是:

  • 高效内存使用:存储一个 10,000 x 10,000 的密集矩阵需要 10000 * 10000 * 8 字节(约 800 MB)。如果该矩阵只有 50,000 个非零元素,稀疏表示将只占用几兆字节,极大地节省了内存。
  • 计算速度:矩阵-向量乘法或求解线性系统(A\b)等操作会显著更快,因为算法旨在跳过涉及零的操作。

主要的权衡是,由于需要更复杂的索引,访问或修改单个元素有时会比密集矩阵慢。

在 MATLAB 中可以通过几种方式创建稀疏矩阵。

最简单的方法是使用 sparse() 函数转换现有密集矩阵。MATLAB 将自动查找非零元素并创建稀疏数据结构。

% 1. 创建一个包含大量零的密集矩阵
A_dense = [0, 0, 8, 0;
5, 0, 0, 0;
0, 2, 0, 0;
0, 0, 0, 9];
% 2. 将其转换为稀疏矩阵
S = sparse(A_dense);
% 显示稀疏矩阵
disp(S);

输出: MATLAB 对稀疏矩阵的输出是非零元素及其 (行, 列) 索引的列表。nnz 计数表示非零元素的数量。

(2,1) 5
(3,2) 2
(1,3) 8
(4,4) 9

要查看完整的矩阵表示(如果它足够小),你可以使用 full() 函数:

full(S)
ans =
0 0 8 0
5 0 0 0
0 2 0 0
0 0 0 9

一种更高效的方法,特别是对于非常大的矩阵,是直接从行索引、列索引及其对应值的列表中创建稀疏矩阵。这避免了首先在内存中创建大型密集矩阵。

S = sparse(rows, cols, values, m, n)
  • rows:每个非零值的行索引向量。
  • cols:每个非零值的列索引向量。
  • values:非零值本身的向量。
  • m:所需矩阵的总行数。
  • n:所需矩阵的总列数。
% 定义稀疏矩阵的组成部分
rows = [1, 2, 3, 4, 4];
cols = [3, 1, 2, 4, 1];
values = [10, 20, 30, 40, 50];
% 定义矩阵的最终大小
m = 5; % 5 行
n = 5; % 5 列
% 创建稀疏矩阵
S_direct = sparse(rows, cols, values, m, n);
% 显示结果
disp(full(S_direct));

专业提示: 如果你提供重复的 (行, 列) 对,sparse 将将相应的值求和。这对于在有限元分析等方法中从基本贡献组装矩阵是非常有用的功能。

输出:

0 0 10 0 0
20 0 0 0 0
0 30 0 0 0
50 0 0 40 0
0 0 0 0 0

你可以像处理密集矩阵一样,对稀疏矩阵执行标准算术运算。MATLAB 的运算符被重载,以自动使用高效的稀疏算法。

稀疏矩阵最重要的应用之一是求解线性系统 Ax = b,其中 A 是大型稀疏矩阵。

% 创建一个大型、稀疏、对角占优的矩阵
n = 1000;
A = spdiags([-1*ones(n,1), 3*ones(n,1), -1*ones(n,1)], -1:1, n, n);
% 创建一个密集向量
b = ones(n, 1);
% 使用反斜杠运算符求解系统 Ax = b
% 这对稀疏矩阵进行了高度优化!
tic; % 启动计时器
x = A \ b;
toc; % 结束计时器
% 与使用密集矩阵求解进行比较(用于演示)
% 警告:这可能非常慢且占用大量内存!
% A_dense = full(A);
% tic; x_dense = A_dense \ b; toc;

预期输出: 代码将执行速度非常快并显示经过时间,该时间应该非常小。如果你取消注释并运行密集版本,你会发现它显著更慢并占用更多内存。这展示了使用稀疏矩阵解决大规模问题的强大能力。

Elapsed time is 0.001234 seconds.