矩阵和向量
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<T>
和Vector<T>
类型定义在MathNet.Numerics.LinearAlgebra
命名空间中。从技术和性能上考虑,可以对每种数据类型进行明确的实现,例如,双精度类型可以使用DenseMatrix
类,这个类在MathNet.Numerics.LinearAlgebra.Double
命名空间中。你一般不需要考虑这个,而是使用通常意义的Matrix<T>
的抽象类型,我们需要其他的方法来创建矩阵和向量实例。
Matrix<double> m = Matrix<double>.Build.Random(2, 2); Vector<double> v = Vector<double>.Build.Random(4); Console.WriteLine(m.ToString()); Console.WriteLine(m.ToString());
由于在一个应用程序中,你通常指需要用到一个特定的数据类型,通常用来来减少代码的小技巧是定义这个组建器的快捷方式。
var M = Matrix<double>.Build; var V = Vector<double>.Build; Matrix<double> m1 = M.Dense(2, 2); Matrix<double> m2 = M.Dense(2, 2,(i,j)=>i+j); Vector<double> v1 = V.Dense(4); Vector<double> 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); // 3x3 dense identity matrix M.DenseIdentity(3); // 3x4 dense random matrix sampled from a Gamma distribution M.Random(3, 4, new Gamma(1.0, 5.0));
但是大多数情况下,我们已经其他格式的数据,需要转换到矩阵形式,当函数中有一个of的函数他是用来创建原始数据副本的。
[lang=csharp] // Copy of an existing matrix (can also be sparse or diagonal) Matrix<double> x = ... M.DenseOfMatrix(x); // Directly bind to an existing column-major array without copying (note: no "Of") double[] x = existing... M.Dense(3, 4, x); // From a 2D-array double[,] x = {{ 1.0, 2.0 }, { 3.0, 4.0 }}; M.DenseOfArray(x); // From an enumerable of values and their coordinates Tuple<int,int,double>[] x = {Tuple.Create(0,0,2.0), Tuple.Create(0,1,-3.0)}; M.DenseOfIndexed(3,4,x); // From an enumerable in column major order (column by column) double[] x = {1.0, 2.0, 3.0, 4.0}; M.DenseOfColumnMajor(2, 2, x); // From an enumerable of enumerable-columns (optional with explicit size) IEnumerable<IEnumerable<double>> x = ... M.DenseOfColumns(x); // From a params-array of array-columns (or an enumerable of them) M.DenseOfColumnArrays(new[] {2.0, 3.0}, new[] {4.0, 5.0}); // From a params-array of column vectors (or an enumerable of them) M.DenseOfColumnVectors(V.Random(3), V.Random(3)); // Equivalent variants also for rows or diagonals: M.DenseOfRowArrays(new[] {2.0, 3.0}, new[] {4.0, 5.0}); M.DenseOfDiagonalArray(new[] {2.0, 3.0, 4.0}); // if you already have existing matrices and want to concatenate them Matrix<double>[,] x = ... M.DenseOfMatrixArray(x);
矩阵运算
可以直接加减乘除操作,也可以使用方法进行运算。
var M = Matrix<double>.Build; var V = Vector<double>.Build; Matrix<double> m1 = M.Dense(2, 2, 1); Matrix<double> m2 = M.Dense(2, 2, (i, j) => i + j); Matrix<double> m3 = m1 * m2; //or //Matrix<double> m3 = m1.Multiply(m2);//m1 * m2 note that order Matrix<double> m4 = m3.Transpose(); Console.WriteLine("{0}\n{1}\nmultiply:\n{2}\ntranpose\n{3}", m1.ToString(), m2.ToString(), m3.ToString(), m4.ToString());
这些方法也重载一个方法,它赋值给第三个参数,允许避免为每单个操作分配新的变量,提供了维数匹配。
Matrix<double> m1 = M.Diagonal(3, 2, 1); Matrix<double> m2 = M.Dense(2, 2, (i, j) => i + j); Matrix<double> m3 = M.Random(3,2); m1.Multiply(m2, m3);// m3 <= m1 * m2