矩阵,数学术语。在数学中,矩阵(Matrix)是一个按照长方阵列排列的复数或实数集合,最早来自于方程组的系数及常数所构成的方阵。这一概念由19世纪英国数学家凯利首先提出。
矩阵是高等代数学中的常见工具,也常见于统计分析等应用数学学科中。 在物理学中,矩阵于电路学、力学、光学和量子物理中都有应用;计算机科学中,三维动画制作也需要用到矩阵。 矩阵的运算是数值分析领域的重要问题。将矩阵分解为简单矩阵的组合可以在理论和实际应用上简化矩阵的运算。对一些应用广泛而形式特殊的矩阵,例如稀疏矩阵和准对角矩阵,有特定的快速运算算法。关于矩阵相关理论的发展和应用,请参考《矩阵理论》。在天体物理、量子力学等领域,也会出现无穷维的矩阵,是矩阵的一种推广。
数值分析的主要分支致力于开发矩阵计算的有效算法,这是一个已持续几个世纪以来的课题,是一个不断扩大的研究领域。 矩阵分解方法简化了理论和实际的计算。 针对特定矩阵结构(如稀疏矩阵和近角矩阵)定制的算法在有限元方法和其他计算中加快了计算。 无限矩阵发生在行星理论和原子理论中。 无限矩阵的一个简单例子是代表一个函数的泰勒级数的导数算子的矩阵。
矩阵的研究历史悠久,拉丁方阵和幻方在史前年代已有人研究。
在数学中,矩阵(Matrix)是一个按照长方阵列排列的复数或实数集合,最早来自于方程组的系数及常数所构成的方阵。这一概念由19世纪英国数学家凯利首先提出。作为解决线性方程的工具,矩阵也有不短的历史。成书最早在东汉前期的《九章算术》中,用分离系数法表示线性方程组,得到了其增广矩阵。在消元过程中,使用的把某行乘以某一非零实数、从某行中减去另一行等运算技巧,相当于矩阵的初等变换。但那时并没有现今理解的矩阵概念,虽然它与现有的矩阵形式上相同,但在当时只是作为线性方程组的标准表示与处理方式。
矩阵正式作为数学中的研究对象出现,则是在行列式的研究发展起来后。逻辑上,矩阵的概念先于行列式,但在实际的历史上则恰好相反。日本数学家关孝和(1683年)与微积分的发现者之一戈特弗里德·威廉·莱布尼茨(1693年)近乎同时地独立建立了行列式论。其后行列式作为解线性方程组的工具逐步发展。1750年,加布里尔·克拉默发现了克莱姆法则。
矩阵的概念在19世纪逐渐形成。1800年代,高斯和威廉·若尔当建立了高斯—若尔当消去法。1844年,德国数学家费迪南·艾森斯坦(F.Eisenstein)讨论了“变换”(矩阵)及其乘积。1850年,英国数学家詹姆斯·约瑟夫·西尔维斯特(James Joseph Sylvester)首先使用矩阵一词。
英国数学家阿瑟·凯利被公认为矩阵论的奠基人。他开始将矩阵作为独立的数学对象研究时,许多与矩阵有关的性质已经在行列式的研究中被发现了,这也使得凯利认为矩阵的引进是十分自然的。他说:“我决然不是通过四元数而获得矩阵概念的;它或是直接从行列式的概念而来,或是作为一个表达线性方程组的方便方法而来的。”他从1858年开始,发表了《矩阵论的研究报告》等一系列关于矩阵的专门论文,研究了矩阵的运算律、矩阵的逆以及转置和特征多项式方程。凯利还提出了凯莱-哈密尔顿定理,并验证了3×3矩阵的情况,又说进一步的证明是不必要的。哈密尔顿证明了4×4矩阵的情况,而一般情况下的证明是德国数学家弗罗贝尼乌斯(F.G.Frohenius)于1898年给出的。
1854年时法国数学家埃尔米特(C.Hermite)使用了“正交矩阵”这一术语,但他的正式定义直到1878年才由费罗贝尼乌斯发表。1879年,费罗贝尼乌斯引入矩阵秩的概念。至此,矩阵的体系基本上建立起来了。
无限维矩阵的研究始于1884年。庞加莱在两篇不严谨地使用了无限维矩阵和行列式理论的文章后开始了对这一方面的专门研究。1906年,希尔伯特引入无限二次型(相当于无限维矩阵)对积分方程进行研究,极大地促进了无限维矩阵的研究。在此基础上,施密茨、赫林格和特普利茨发展出算子理论,而无限维矩阵成为了研究函数空间算子的有力工具。
矩阵的概念最早在1922年见于中文。1922年,程廷熙在一篇介绍文章中将矩阵译为“纵横阵”。1925年,科学名词审查会算学名词审查组在《科学》第十卷第四期刊登的审定名词表中,矩阵被翻译为“矩阵式”,方块矩阵翻译为“方阵式”,而各类矩阵如“正交矩阵”、“伴随矩阵”中的“矩阵”则被翻译为“方阵”。1935年,中国数学会审查后,中华民国教育部审定的《数学名词》(并“通令全国各院校一律遵用,以昭划一”)中,“矩阵”作为译名首次出现。1938年,曹惠群在接受科学名词审查会委托就数学名词加以校订的《算学名词汇编》中,认为应当的译名是“长方阵”。中华人民共和国成立后编订的《数学名词》中,则将译名定为“(矩)阵”。1993年,中国自然科学名词审定委员会公布的《数学名词》中,“矩阵”被定为正式译名,并沿用至今。
矩阵的基本运算包括但不限于:加、减、乘、除、转置、共轭、共轭转置等等。
本文发布了上述算法的源代码。
后续文章陆续发布求逆、行列式及更多算法的源代码。
using System;
namespace Zhou.CSharp.Algorithm
{
///
/// 矩阵类
/// 作者:周长发
/// 改进:深度混淆
/// https://blog.csdn.net/beijinghorn
///
public partial class Matrix
{
///
/// 矩阵列数
///
public int Columns { get; set; } = 0;
///
/// 矩阵行数
///
public int Rows { get; set; } = 0;
///
/// 缺省精度
///
public double Eps { get; set; } = 0.0;
///
/// 矩阵数据缓冲区
///
private double[] elements { get; set; } = null;
///
/// 索引器: 访问矩阵元素
///
/// 行
/// 列
///
public double this[int row, int col]
{
get
{
return elements[col + row * Columns];
}
set
{
elements[col + row * Columns] = value;
}
}
public double this[int index]
{
get
{
return elements[index];
}
set
{
elements[index] = value;
}
}
public Matrix()
{
Columns = 1;
Rows = 1;
Init(Rows, Columns);
}
///
/// 指定行列构造函数
///
/// 矩阵行数
/// 矩阵列数
public Matrix(int nRows, int nCols)
{
Rows = nRows;
Columns = nCols;
Init(Rows, Columns);
}
///
/// 指定值构造函数
///
/// 二维数组,存储矩阵各元素的值
public Matrix(double[,] value)
{
Rows = value.GetLength(0);
Columns = value.GetLength(1);
double[] data = new double[Rows * Columns];
int k = 0;
for (int i = 0; i < Rows; ++i)
{
for (int j = 0; j < Columns; ++j)
{
data[k++] = value[i, j];
}
}
Init(Rows, Columns);
SetData(data);
}
///
/// 指定值构造函数
///
/// 矩阵行数
/// 矩阵列数
/// 一维数组,长度为nRows*nCols,存储矩阵各元素的值
public Matrix(int nRows, int nCols, double[] value)
{
Rows = nRows;
Columns = nCols;
Init(Rows, Columns);
SetData(value);
}
///
/// 方阵构造函数
///
/// 方阵行列数
public Matrix(int nSize)
{
Rows = nSize;
Columns = nSize;
Init(nSize, nSize);
}
///
/// 方阵构造函数
///
/// 方阵行列数
/// 一维数组,长度为nRows*nRows,存储方阵各元素的值
public Matrix(int nSize, double[] value)
{
Rows = nSize;
Columns = nSize;
Init(nSize, nSize);
SetData(value);
}
///
/// 拷贝构造函数
///
/// 源矩阵
public Matrix(Matrix other)
{
Columns = other.GetNumColumns();
Rows = other.GetNumRows();
Init(Rows, Columns);
SetData(other.elements);
}
///
/// 初始化函数
///
/// 矩阵行数
/// 矩阵列数
/// 成功返回true, 否则返回false
public bool Init(int nRows, int nCols)
{
Rows = nRows;
Columns = nCols;
int nSize = nCols * nRows;
if (nSize < 0) return false;
// 分配内存
elements = new double[nSize];
return true;
}
///
/// 重载 + 运算符
///
///
///
///
public static Matrix operator +(Matrix m1, Matrix m2)
{
return m1.Add(m2);
}
///
/// 重载 - 运算符
///
///
///
///
public static Matrix operator -(Matrix m1, Matrix m2)
{
return m1.Subtract(m2);
}
///
/// 重载 * 运算符
///
///
///
///
public static Matrix operator *(Matrix m1, Matrix m2)
{
return m1.Multiply(m2);
}
///
/// 重载 double[] 运算符
///
///
public static implicit operator double[](Matrix m)
{
return m.elements;
}
///
/// 将方阵初始化为单位矩阵
///
/// 方阵行列数
///
public bool MakeUnitMatrix(int nSize)
{
if (!Init(nSize, nSize)) return false;
for (int i = 0; i < nSize; ++i)
{
#if __ORIGINAL__
for (int j = 0; j < nSize; ++j)
{
if (i == j)
{
SetElement(i, j, 1);
}
}
#endif
SetElement(i, i, 1);
}
return true;
}
///
/// 将矩阵各元素的值转化为字符串, 元素之间的分隔符为",", 行与行之间有回车换行符
///
/// 转换得到的字符串
public override string ToString()
{
return ToString(",", true);
}
///
/// 将矩阵各元素的值转化为字符串
///
/// 元素之间的分隔符
/// 行与行之间是否有回车换行符
///
public string ToString(string sDelim = ",", bool bLineBreak = true)
{
string s = "";
for (int i = 0; i < Rows; ++i)
{
for (int j = 0; j < Columns; ++j)
{
string ss = GetElement(i, j).ToString("F");
s += ss;
if (bLineBreak)
{
if (j != Columns - 1) s += sDelim;
}
else
{
if (i != Rows - 1 || j != Columns - 1) s += sDelim;
}
}
if (bLineBreak)
{
if (i != Rows - 1)
{
s += "\r\n";
}
}
}
return s;
}
///
/// 将矩阵指定行中各元素的值转化为字符串
///
/// 指定的矩阵行,nRow = 0表示第一行
/// 元素之间的分隔符
///
public string ToStringRow(int nRow, string sDelim)
{
string s = "";
if (nRow >= Rows)
{
return s;
}
for (int j = 0; j < Columns; ++j)
{
string ss = GetElement(nRow, j).ToString("F");
s += ss;
if (j != Columns - 1)
{
s += sDelim;
}
}
return s;
}
///
/// 将矩阵指定列中各元素的值转化为字符串
///
/// 指定的矩阵行,nCol = 0表示第一列
/// 元素之间的分隔符
///
public string ToStringCol(int nCol, string sDelim /*= " "*/)
{
string s = "";
if (nCol >= Columns)
{
return s;
}
for (int i = 0; i < Rows; ++i)
{
string ss = GetElement(i, nCol).ToString("F");
s += ss;
if (i != Rows - 1)
{
s += sDelim;
}
}
return s;
}
///
/// 设置矩阵各元素的值
///
/// 一维数组,长度为Columns* Rows,存储
public void SetData(double[] value)
{
elements = (double[])value.Clone();
}
///
/// 设置指定元素的值
///
/// 行
/// 列
/// 值
///
public bool SetElement(int nRow, int nCol, double value)
{
// array bounds error
if (nCol < 0 || nCol >= Columns || nRow < 0 || nRow >= Rows)
{
return false;
}
elements[nCol + nRow * Columns] = value;
return true;
}
///
/// 获取指定元素的值
///
/// 行
/// 列
///
public double GetElement(int nRow, int nCol)
{
return elements[nCol + nRow * Columns];
}
///
/// 获取矩阵的列数
///
///
public int GetNumColumns()
{
return Columns;
}
///
/// 获取矩阵的行数
///
///
public int GetNumRows()
{
return Rows;
}
///
/// 获取矩阵的数据
///
///
public double[] GetData()
{
return elements;
}
///
/// 获取指定行的向量
///
/// 向量所在的行
/// 指向向量中各元素的缓冲区
/// 向量中元素的个数,即矩阵的列数
public int GetRowVector(int nRow, double[] pVector)
{
for (int j = 0; j < Columns; ++j)
{
pVector[j] = GetElement(nRow, j);
}
return Columns;
}
///
/// 获取指定列的向量
///
/// 向量所在的列
/// 指向向量中各元素的缓冲区
/// 向量中元素的个数,即矩阵的行数
public int GetColVector(int nCol, double[] pVector)
{
for (int i = 0; i < Rows; ++i)
{
pVector[i] = GetElement(i, nCol);
}
return Rows;
}
///
/// 给矩阵赋值
///
/// 用于给矩阵赋值的源矩阵
///
public Matrix SetValue(Matrix other)
{
if (other != this)
{
Init(other.GetNumRows(), other.GetNumColumns());
SetData(other.elements);
}
// finally return a reference to ourselves
return this;
}
///
/// 判断矩阵否相等
///
/// 用于比较的矩阵
/// 两个矩阵相等则为true,否则为false
public override bool Equals(object other)
{
Matrix matrix = other as Matrix;
if (matrix == null)
{
return false;
}
// 首先检查行列数是否相等
if (Columns != matrix.GetNumColumns() || Rows != matrix.GetNumRows())
{
return false;
}
for (int i = 0; i < Rows; ++i)
{
for (int j = 0; j < Columns; ++j)
{
if (Math.Abs(GetElement(i, j) - matrix.GetElement(i, j)) > Eps)
{
return false;
}
}
}
return true;
}
///
/// 因为重写了Equals,因此必须重写GetHashCode
///
/// 返回对象散列码
public override int GetHashCode()
{
double sum = 0;
for (int i = 0; i < Rows; ++i)
{
for (int j = 0; j < Columns; ++j)
{
sum += Math.Abs(GetElement(i, j));
}
}
return (int)Math.Sqrt(sum);
}
///
/// 实现矩阵的加法
///
/// 与指定矩阵相加的矩阵
/// 指定矩阵与other相加之和
/// 如果矩阵的行/列数不匹配,则会抛出异常
public Matrix Add(Matrix other)
{
// 首先检查行列数是否相等
if (Columns != other.GetNumColumns() || Rows != other.GetNumRows())
{
throw new Exception("矩阵的行/列数不匹配。");
}
// 构造结果矩阵
// 拷贝构造
Matrix result = new Matrix(this);
// 矩阵加法
for (int i = 0; i < Rows; ++i)
{
for (int j = 0; j < Columns; ++j)
{
result.SetElement(i, j, result.GetElement(i, j) + other.GetElement(i, j));
}
}
return result;
}
///
/// 实现矩阵的减法
///
/// 与指定矩阵相减的矩阵
/// 指定矩阵与other相减之差
/// 如果矩阵的行/列数不匹配,则会抛出异常
public Matrix Subtract(Matrix other)
{
if (Columns != other.GetNumColumns() || Rows != other.GetNumRows())
{
throw new Exception("矩阵的行/列数不匹配。");
}
// 构造结果矩阵
// 拷贝构造
Matrix result = new Matrix(this);
// 进行减法操作
for (int i = 0; i < Rows; ++i)
{
for (int j = 0; j < Columns; ++j)
{
result.SetElement(i, j, result.GetElement(i, j) - other.GetElement(i, j));
}
}
return result;
}
///
/// 实现矩阵的数乘
///
/// 与指定矩阵相乘的实数
/// 指定矩阵与value相乘之积
public Matrix Multiply(double value)
{
// 构造目标矩阵
// copy ourselves
Matrix result = new Matrix(this);
// 进行数乘
for (int i = 0; i < Rows; ++i)
{
for (int j = 0; j < Columns; ++j)
{
result.SetElement(i, j, result.GetElement(i, j) * value);
}
}
return result;
}
///
/// 实现矩阵的乘法
///
/// 与指定矩阵相乘的矩阵
/// 指定矩阵与other相乘之积
/// 如果矩阵的行/列数不匹配,则会抛出异常
public Matrix Multiply(Matrix other)
{
// 首先检查行列数是否符合要求
if (Columns != other.GetNumRows())
{
throw new Exception("矩阵的行/列数不匹配。");
}
// ruct the object we are going to return
Matrix result = new Matrix(Rows, other.GetNumColumns());
// 矩阵乘法,即
//
// [A][B][C] [G][H] [A*G + B*I + C*K][A*H + B*J + C*L]
// [D][E][F] * [I][J] = [D*G + E*I + F*K][D*H + E*J + F*L]
// [K][L]
//
double value;
for (int i = 0; i < result.GetNumRows(); ++i)
{
for (int j = 0; j < other.GetNumColumns(); ++j)
{
value = 0.0;
for (int k = 0; k < Columns; ++k)
{
value += GetElement(i, k) * other.GetElement(k, j);
}
result.SetElement(i, j, value);
}
}
return result;
}
///
/// 复矩阵的乘法
///
/// 左边复矩阵的实部矩阵
/// 左边复矩阵的虚部矩阵
/// 右边复矩阵的实部矩阵
/// 右边复矩阵的虚部矩阵
/// 乘积复矩阵的实部矩阵
/// 乘积复矩阵的虚部矩阵
/// 复矩阵乘法是否成功
public bool Multiply(Matrix AR, Matrix AI, Matrix BR, Matrix BI, Matrix CR, Matrix CI)
{
// 首先检查行列数是否符合要求
if (AR.GetNumColumns() != AI.GetNumColumns() ||
AR.GetNumRows() != AI.GetNumRows() ||
BR.GetNumColumns() != BI.GetNumColumns() ||
BR.GetNumRows() != BI.GetNumRows() ||
AR.GetNumColumns() != BR.GetNumRows())
{
return false;
}
// 构造乘积矩阵实部矩阵和虚部矩阵
Matrix mtxCR = new Matrix(AR.GetNumRows(), BR.GetNumColumns());
Matrix mtxCI = new Matrix(AR.GetNumRows(), BR.GetNumColumns());
// 复矩阵相乘
for (int i = 0; i < AR.GetNumRows(); ++i)
{
for (int j = 0; j < BR.GetNumColumns(); ++j)
{
double vr = 0;
double vi = 0;
for (int k = 0; k < AR.GetNumColumns(); ++k)
{
double p = AR.GetElement(i, k) * BR.GetElement(k, j);
double q = AI.GetElement(i, k) * BI.GetElement(k, j);
double s = (AR.GetElement(i, k) + AI.GetElement(i, k)) * (BR.GetElement(k, j) + BI.GetElement(k, j));
vr += p - q;
vi += s - p - q;
}
mtxCR.SetElement(i, j, vr);
mtxCI.SetElement(i, j, vi);
}
}
CR = mtxCR;
CI = mtxCI;
return true;
}
///
/// 矩阵的转置
///
///
public Matrix Transpose()
{
// 构造目标矩阵
Matrix Trans = new Matrix(Columns, Rows);
// 转置各元素
for (int i = 0; i < Rows; ++i)
{
for (int j = 0; j < Columns; ++j)
{
//Trans.SetElement(j, i, GetElement(i, j));
Trans[j, i] = this[i, j];
}
}
return Trans;
}
}
}