⚫ 安装 C# 科学计算库 Math.NET Numerics
在 Visual Studio 2015 中,打开 Tools -> Nuget Package Manager -> Package Manager
Console。然后在 Package Manager Console 中输入如下命令:
Install-Package MathNet.Numerics
然后会自动安装 Math.NET Numerics。安装成功后,Package Manager Console
会有如下提示
⚫ 在 C#中使用 mathnet,需要利用 using 引入相关类
矩阵运算的相关类:
using MathNet.Numerics.LinearAlgebra.Double;
using MathNet.Numerics.LinearAlgebra.Generic;
⚫ // 格式设置
var formatProvider=(CultureInfo)CultureInfo.InvariantCulture.Clone();
formatProvider.TextInfo.ListSeparator=" ";
⚫ 利用 C#中的 double[,]直接创建矩阵
var mb = Matrix.Build;
double[,] d_matrix = new double[2,3];
var matrix2 = mb.DenseOfArray(d_matrix);//2×3 矩阵
我 曾 做过 测试 , 将 double[,] 先转 成 Math 矩阵 , 然后 进行 矩 阵运 算, 再 利用
matrix2.ToArray()将 Math 矩阵转换成 double[,],其运算时间和直接利用 C#编写
的矩阵运算相差很小。但如果是利用 for 循环将 double 数组的数值赋值给 Math 矩阵进
行矩阵运算,然后再利用 for 循环将 Math 矩阵赋值给某个 double[,]数组,其运算时间
可以减少 1/3。在开发效率和运算效率上,使用的时候可以根据需要进行取舍。
⚫ 矩阵操作
矩阵操作最常用的莫过于从一个矩阵中取值
//取从第二行开始的 2 行,第三列开始的三列子矩阵
var submatrix = matrix.SubMatrix(2, 2, 3, 3);
//取从第 5 行第 3 列开始的 4 个行元素
var row = matrix.Row(5, 3, 4);
//取从第 2 列第 6 行开始的 3 个列元素
var column = matrix.Column(2, 6, 3);
//取从第 2 列开始的 4 列
matrix.ColumnEnumerator(2, 4)
//取从第 4 行开始的 3 行
matrix.RowEnumerator(4, 3)
//矩阵变为行向量或者列向量
matrix.ToRowWiseArray()/matrix.ToColumnWiseArray()
//取矩阵的对角线元素向量
matrix.Diagonal()
⚫ 向矩阵中插值
//将向量 vector 插入到指定的行/列,原有的行列顺延
var result = matrix.InsertColumn(3,vector)/matrix.InsertRow(3,vector);
//用 vector 替换指定的行/列
matrix.SetColumn(2,(Vector)vector);/matrix.SetRow(3,(double[])vector);
//用矩阵替换指定位置的块矩阵
matrix.SetSubMatrix(1,3,1,3,DenseMatrix.Identity(3));
//替换矩阵的对角线元素
matrix.SetDiagonal(new[]{5.0,4.0,3.0,2.0,1.0});
//将 matrixB 扩展到 matrixA 的右方/上方,将结果保存在 result 中
matrixA.Append(matrixB,result)/matrixA.Stack(matrixB,result)
⚫ //创建一个随机的矩阵
var matrix = new DenseMatrix(5);
var rnd = new Random(1);
for (var i=0; i < matrix.RowCount; i++)
{
for (var j=0; j < matrix.ColumnCount; j++)
{
matrix[i,j] = rnd.NextDouble();
}
}
⚫ 矩阵相乘
var mb = Matrix.Build;
var A = mb.Dense(3, 5, 2.0);//3×5 矩阵,所有值为 2.0
var B = mb.Dense(5, 4, 3.0);//5×4 矩阵,所有值为 3.0
var y = A * B;//或 var y=A.Multiply(B);
Console.WriteLine("A:\n{0}\nB:\n{1}\ny:\n{2}",A,B,y);
A:
2,2,2,2,2
2,2,2,2,2
2,2,2,2,2
B:
3,3,3,3
3,3,3,3
3,3,3,3
3,3,3,3
3,3,3,3
y:
30,30,30,30
30,30,30,30
30,30,30,30
⚫ 矩阵相减
var mb = Matrix.Build;
var A = mb.Dense(3,3,2.0);
var B = mb.Dense(3,3,1.2);
var C = A.Subtract(B);
⚫ 矩阵相加
var mb = Matrix.Build;
var A = mb.Dense(3,3,2.0);
var B = mb.Dense(3,3,1.2);
var C = A.Add(B);
⚫ 矩阵转置
var mb = Matrix.Build;
var A = mb.DenseOfArray(new double[,]{
{1,2,3,4},{5,6,7,8},
{9,10,11,12},{13,14,15,16}
var B = A.Transpose();
});
⚫ 矩阵求逆
var mb = Matrix.Build;
var A = mb.DenseOfArray (new double[,]{
{1,1,2},
{-1,2,0},
{1,1,3}
var B = A.Inverse();
});
A:
1,1,2
-1,2,0
1,1,3
B:
2,-0.3,-1.33
1,0.33,-0.67
-1,0,1
⚫ 矩阵行列式的值
var mb = Matrix.Build;
var A = mb.DenseOfArray(new double[,]{
{1,1,2},
{-1,2,0},
{1,1,3}
var B = A.Determinant();
});
⚫ 矩阵的秩
var mb = Matrix.Build;
var A = mb.DenseOfArray(new double[,]{
{1,2,3,4},{5,6,7,8},
{9,10,11,12},{13,14,15,16}
});
var B =A.Rank();
⚫ 矩阵左乘向量:y=b*A
var mb = Matrix.Build;
var vb = DenseVector.Build;
var A = mb.Dense(3,5,2.0);
var b = vb.Dense(3,3);
var y = A.LeftMultiply(b);
Console.WriteLine("A:\n{0}\nB:\n{1}\ny:\n{2}",A,b,y);
A:
2,2,2,2,2
2,2,2,2,2
2,2,2,2,2
B:
3,3,3
y:
18,18,18,18,18
⚫ 矩阵分解
LU 分解
var mb = Matrix.Build;
var A = mb.Dense(3, 3, 2.0);
var l=A.LU().L;
var u = A.LU().U;
Console.WriteLine("A:\n{0}\nl:\n{1}\nu:\n{2}",A,l,u);
A:
2,2,2
2,2,2
2,2,2
l:
1,0,0
1,1,0
1,0,1
u:
2,2,2
0,0,0
0,0,0
类似的还有 Cholesky 分解,Evd 分解,GramSchmidt 分解,QR 分解,Svd 分解
⚫ 求解线性方程组
对于一阶线性方程组
5*x+2*y-4*z=-7
3*x-7*y+6*z=38
4*x+1*y+5*z=43
可以如下求解:
//先创建系数矩阵 A
var matrixA = DenseMatrix.OfArray(new[,] {
{5.00, 2.00, -4.00},
{3.00, -7.00, 6.00},
{4.00, 1.00, 5.00}
});
var vectorB = new DenseVector(new[] { -7.0, 38.0, 43.0 });
// 1.使用 LU 分解方法求解
var resultX = matrixA.LU().Solve(vectorB);
Console.WriteLine(@"1. Solution using LU decomposition");
Console.WriteLine(resultX.ToString("#0.00\t", formatProvider));
// 2.使用 QR 分解方法求解
resultX = matrixA.QR().Solve(vectorB);
Console.WriteLine(@"2. Solution using QR decomposition");
Console.WriteLine(resultX.ToString("#0.00\t", formatProvider));
// 3. 使用 SVD 分解方法求解
matrixA.Svd().Solve(vectorB, resultX);
Console.WriteLine(@"3. Solution using SVD decomposition");
Console.WriteLine(resultX.ToString("#0.00\t", formatProvider));
// 4.使用 Gram-Shmidt 分解方法求解
matrixA.GramSchmidt().Solve(vectorB, resultX);
Console.WriteLine(@"4. Solution using Gram-Shmidt decomposition");
Console.WriteLine(resultX.ToString("#0.00\t", formatProvider));
----------------------------------------------------------
矩阵定义和初始化
常用矩阵初始化函数:
var matrix2 = new DenseMatrix(3);//3 维方阵
var matrix3 = new DenseMatrix(2, 3);//2×3 矩阵
var matrixI = DenseMatrix.Identity(5);//5 维单位矩阵
矩阵操作和 C#中的数组操作一致,matrix2[m,n]取其 m 行 n 列上的值或对其赋值
MathNet 中重载了.ToString()函数,可以直接用 matrix.ToString()输出整个数组,
大大方便了调试和保存数据。
矩阵转换:
var permutations = new Permutation(new[] { 0, 1, 3, 2, 4 });
matrix.PermuteRows(permutations); //互换矩阵的 3,4 行
permutations = new Permutation(new[] { 1, 0, 4, 3, 2 });
matrix.PermuteColumns(permutations); //互换矩阵的 1,2 列,3,5 列。
可以看出,互换是由 Permutation 中的数字序号决定的。
1.矩阵运算
matrixA = 3.0 * matrixB//数乘
matrixA = vector*matrixB/matrixA=matrixB*vector//向量乘
matrixC = matrixA+/-/*matrixB//矩阵加、减、乘
resultM = (DenseMatrix)matrixA.PointwiseDivide(matrixB); //点乘
上述所有运算符都有对应的函数,也可是利用函数进行运算,如“+”可以写成
matrixC=(DenseMatrix)matrixA.Add(matrixB);
或者 matrixA.Add(matrixB,matrixC);
matrixB = matrixA.Inverse()/Transpose() //求逆和转置
2.求解线性方程组
对于一阶线性方程组
5*x+2*y-4*z=-7
3*x-7*y+6*z=38
4*x+1*y+5*z=43
可以如下求解:
var matrixA =new DenseMatrix(new[,] { { 5.00, 2.00, -4.00 }, { 3.00,
-7.00, 6.00 },{ 4.00, 1.00, 5.00 } });
var vectorB = new DenseVector(new[] { -7.0, 38.0, 43.0 });
var resultX = matrixA.LU().Solve(vectorB);
或者
resultX = matrixA.QR().Solve(vectorB);
或者
matrixA.Svd(true).Solve(vectorB, resultX);
或者
matrixA.GramSchmidt().Solve(vectorB, resultX);
3.矩阵秩、行列式、trace 和范数
matrix.Determinant()/Rank()/ConditionNumber()/Trace() //行列式/秩
/条件数/trace
matrix.L1Norm()/L2Norm()/FrobeniusNorm()/InfinityNorm() //范数
矩阵和向量
Math.Net Numberics 程序集中包含了矩阵和向量的丰富类型。他们都支持单精度和双
精度类型。 像在 dotnet 中所有的数据类型一样,他们都是基于 0 索引的,例如,左上
位置的索引值是(0,0),在矩阵中第一个索引值指的是行,第二个索引值指的是列,空
矩阵和向量不支持,例如,每个维数的长度至少是一。
存储布局
1.向量
• 密集向量 使用一个与向量相同长度数组。
• 稀疏向量 用两个通常比向量小的数组,一个数组存储非零值,另一个数组存储他们的索引值,向上排序.
2.矩阵
• 密集矩阵 用一个数组存储
• 对角矩阵 只存储对角值,在一个数组存储。
• 稀疏矩阵 用了三个数组存储,第一个数组存储非零值,第二个数组存储非零值对应列号,第三个数组存储行偏
移值,并且最后一个元素存储矩阵中非零值的个数。
第一个数组 values 存储非零值,顺序是每行从左往右扫,扫完依次扫下一行,即
1,7,2,8,5,3,9,6,4
第二个数组 column indices 存储非零值的对应列号,即 0,1,1,2,0,2,3,1,3。
第三个数组 row offsets 存储行偏移值,首先数组大小为行数+1(该例为 4+1),第 i 个
元素值存储第 i 行首个非零值前面非零值的个数(第 0 个数肯定为 0),例如该数组第 1(基
于 0 索引)个值存储的是第 1 行第一个非零值(该例为 2)前面非零值的个数(该例为 2,
非零值为 1,7)。在例如该数组第 3 个值存储的是第 3 行第一个非零值(6)前面非零值的
个数(该例为 7,非零值为 1,7,2,8,5,3,9)。第三个数组最后一个值存储矩阵中所有非
零值的个数(该例为 9)。
创建矩阵和向量
Matrix和 Vector类型定义在 MathNet.Numerics.LinearAlgebra 命名空
间中。从技术和性能上考虑,可以对每种数据类型进行明确的实现,例如,双精度类型可以
使用 DenseMatrix 类,这个类在 MathNet.Numerics.LinearAlgebra.Double 命
名空间中。你一般不需要考虑这个,而是使用通常意义的 Matrix 的抽象类型,我们
需要其他的方法来创建矩阵和向量实例。
Matrix m = Matrix.Build.Random(2, 2);
Vector v = Vector.Build.Random(4);
Console.WriteLine(m.ToString());
Console.WriteLine(m.ToString());
由于在一个应用程序中,你通常指需要用到一个特定的数据类型,通常用来来减少代码的小
技巧是定义这个组建器的快捷方式。
var M = Matrix.Build;
var V = Vector.Build;
Matrix m1 = M.Dense(2, 2);
Matrix m2 = M.Dense(2, 2,(i,j)=>i+j);
Vector v1 = V.Dense(4);
Vector v2 = V.Dense(4, (i) => i % 2);
Console.WriteLine("{0}\n{1}\n{2}\n{3}",
m1.ToString(),
m2.ToString(),
v1.ToString(),
v2.ToString());
这个组建器通常确定数据的存储方式,因此如果你想构建一个稀疏矩阵,intelligense
将会列出所有的选项,一旦你敲入 M.Sparse.
[lang=csharp]
// 3x4 dense matrix filled with zeros
M.Dense(3, 4);
// 3x4 dense matrix filled with 1.0.
M.Dense(3, 4, 1.0);
// 3x4 dense matrix where each field is initialized using a function
M.Dense(3, 4, (i,j) => 100*i + j);
// 3x4 square dense matrix with each diagonal value set to 2.0
M.DenseDiagonal(3, 4, 2.0);