C# 矩阵库
一个用于基本数值线性代数的 C# 库。
引言
CSML - C# 矩阵库 - 是一个紧凑轻量级的数值线性代数包。实现了许多在 Matlab、Scilab 等软件中已知的矩阵运算。
版本信息
版本 0.91 - 最后更新:2007 年 11 月 29 日。
备注
请不时返回此文章查看更新。像这样的项目对于一个人来说是一项艰巨的任务。例如,Scilab(免费的 Matlab 克隆版)是由一个学术联盟创建的,而 Matlab 的创建者 Mathworks 是一家财力雄厚的企业。
错误修复将始终作为更新发布,如果您查看下面的历史记录,您会发现在一小段时间内已经进行了相当多的,呃,改进。
它的功能
该库的核心,即 Matrix
类,包含 90 多个用于矩阵运算的方法,如乘法、加法、指数运算和求解线性方程组;矩阵操作,如连接、插入、转置、求逆、翻转、对称化、插入和提取;用于矩阵计算,如行列式、迹、永久式、范数(Frobenius、欧几里得、最大范数、出租车范数、p-范数)、条件数;用于矩阵分解,如 LU 分解、Gram-Schmidt 正交化和 Cholesky 分解。
现在整个库已更新为支持复数运算。实数矩阵 M 被视为特殊的复数矩阵,其中 M.Re() == M,即每个元素的虚部为 0。
该项目几乎完全采用 PDF 形式记录;大多数方法还配有示例。像求逆这样复杂的算法也在数学层面上进行了解释。如有必要,还会注明某些算法的复杂度类别。
它的局限性
目前,没有实现:
- 多项式、插值、积分(*);
- 特征向量(*);
(*) - 正在努力。欢迎任何贡献。我在这里的 CodeProject 上发布了一个复数库,请查找 CompLib。也发布了一个多项式库,PolyLib。
如何使用 CSML
使用代码的两种通用方法:
- 将 CSML.dll 添加到您的项目中作为引用,并在源文件顶部输入 "
using CSML;
" - 将 Matrix.cs 和 Complex.cs 类添加到您的项目中并调整命名空间。
让我们看一个例子。假设我们要计算 2x2 矩阵 [1, 1; 1, 2] 的行列式和逆。
Matrix M = new Matrix("1,1;1,2"); // init
Complex det = M.Determinant(); // det = 1
Matrix Minv = M.Inverse(); // Minv = [2, -1; -1, 1]
string buf = M.ToString(); // for outputting M in a multiline textbox
有关实现和用法的详细信息,请参阅文档。
关注点
此项目在未获得许可和保修的情况下发布,应视为对开发人员社区(尤其是本页面)的普遍赠予——我大部分编程知识都基于免费代码、示例和教程,不以营利为目的。我现在有幸不必将任何东西变成金钱:这是结果。
关于速度问题的说明
这里提供的算法均未针对速度进行优化。此项目的想法是以直接易懂的方式演示许多常见且知名的矩阵算法。
可能的优化思路包括:
- 将您需要的方法移植到 C++
- 许多小型方法应声明为内联
- 使用双精度数组而不是矩阵数据类型;C++ 允许通过指针算术在运行时扩展维度
关于特征值的说明
当前状态下的 Eigenvalues()
方法使用基于 Gram-Schmidt 正交化的基本 QR 迭代。这意味着两点:
- 目前,特征值的计算仅对实数矩阵有效
- 如果矩阵具有多个特征值或复数特征值,该方法会起作用,但可能会返回垃圾结果
事实上,我只对三角矩阵和对称正定矩阵获得了令人满意的结果。
这些问题反映了特征值问题背后隐藏的困难。由于矩阵 A 的特征值被定义为特征多项式的根
p(L) = det(A-L*id)
计算在数学上等同于计算行列式和 p 的 n 个根。(好吧,这对所有具有任意特征值分布的矩阵都有效,但这是数值上的最差选择,因为 Weierstrass 迭代(参见 PolyLib 中的 Roots()
方法)对于根不明显分离的多项式条件很差。
因此,我正在开发一种基于 Givens 旋转的规范双移 QR 迭代。Matlab 的 eig
函数就是这样工作的。
事实上,我不得不花很长时间谈论特征值,尽管还有许多其他困难的计算已经实现,这表明这个问题是基本数值线性代数中最深刻和最令人头疼的问题之一。
历史
共轭梯度法(实现了 SolveCG()
但存在 bug);我将在不久的将来发布一个示例项目,展示 CSML 的用法和基本功能。
更新于 2007 年 11 月 29 日
- 修复了矩阵加/减法中的错误(由 Raven123 发现)以及水平/垂直连接中的错误(由 alexei_s 发现)。
更新于 2007 年 7 月 4 日
- 添加了 Hessenberg-Householder 约简、Householder 反射和 Givens 旋转;
HessenbergHouseholder()
工作正常;QRGivens()
和QRIterationHessenberg()
仍存在 bug。 - 略微修改了向量初始化的构造函数。
- 修复了
InverseLeverrier()
中的错误;这个黑匣子方法现在应该是矩阵求逆的标准方法(对于通用矩阵Inverse()
速度慢,但对于正交、酉或对角矩阵等特殊矩阵速度快)。 - 美化了 Complex.cs 中的
ToString(string format)
方法;双精度数和复数乘法略有改变(没有 bug,但存在不一致)。
更新于 2007 年 7 月 3 日 #2
- 修复了
Arg()
中的重大 bug(感谢 Petr Stanislav!);这影响了Log()
、Pow()
和Sqrt()
。
2007 年 7 月 3 日更新
- 修复了矩阵访问例程中的一个小 bug,使两个
try-catch
块不再需要,并极大地提高了速度。 - 定义了负指数 k 的矩阵指数运算为求逆矩阵的 (-k) 次幂;(3)修复了
Insert()
方法中的重大 bug。 - 删除了旧的矩阵类(不支持复数)。
更新于 2007 年 7 月 2 日
- 巴伐利亚的一个下雨天……我没有去复习考试,而是更新并完成了文档,并在
Complex
类中添加了双曲函数Sinh
、Cosh
、Tanh
、Coth
、Sech
、Csch
。 - 修复了
SolveSafe
,并重命名为Solve
并设为静态。该方法现在几乎等同于 Matlab 的反斜杠运算符。修复SolveSafe
(使用带列主元的 LU 分解)后,旧的Solve
方法变得多余,已被删除。 - 移除了
Size
方法,并用只读属性RowCount
和ColumnCount
替换。 - 将
IsVector
方法重命名为VectorLength
(测试矩阵是否为向量,即 n x 1 或 1 x n)。
更新于 2007 年 6 月 29 日
- 终于支持复数和复数矩阵;现在任何矩阵都包含复数项。
新功能
- 移除了
IsPermutation()
中的重大 bug(现在:置换矩阵精确地是不可约的 0-1 矩阵;参见文档)。 - 实现了复数矩阵的测试:
IsUnitary()
、IsReal()
、IsImaginary()
、IsHermitian()
。 - 添加了测试:
IsZeroOneMatrix()
。 - 实现了
KroneckerDelta()
。 - Gram-Schmidt 正交化。
- 基于 Gram-Schmidt 的 QR 迭代。
- 特征值函数(速度慢!)。
- 通用方法
Insert()
,用于在特定位置插入子矩阵。 - 通用方法
Extract()
,用于从给定矩阵复制子矩阵。 Conjugate()
、ConjugateTranpose()
。BlockMatrix()
,用于由四个给定矩阵构建矩阵。ChessboardMatrix()
,用于构造具有交替 0-1 条目的矩阵。RandomZeroOne()
- 扩展了
Random()
以生成不仅是双精度数,还有整数矩阵。 Re()
、Im()
,用于提取矩阵的实部/虚部。SolveSafe()
标记为有 bug。- 实现了
Eigenvector()
、SolveCG()
、QRHessenbergHouseholder()
、HouseholderVector()
,但仍(正确地)标记为有 bug。 - 更新了文档(但未完成)。
- 更快的矩阵求逆方法:
InverseLeverrier()
,使用 Leverrier 方法(阅读手册)。
更新于 2007 年 6 月 10 日
- 移除了乘法中的重大 bug;在 "
Matrix operator *(Matrix A, double x)
" 中。 - 添加了正定性测试(仅对对称矩阵有效);需要进行 beta 测试!
- 添加了对称正定性 (SPD) 测试,并在
Cholesky()
中使用;Cholesky 分解仅可能对 SPD 矩阵进行。 - 未记录的基本图算法:BFS(广度优先搜索)、DFS(深度优先搜索)和 Floyd(图中所有顶点之间的最短路径)。