diff --git a/MathNet.Numerics.sln b/MathNet.Numerics.sln index 723672c5..94ee2de2 100644 --- a/MathNet.Numerics.sln +++ b/MathNet.Numerics.sln @@ -50,6 +50,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docs", "Docs", "{039229DA-A docs\content\Integration.fsx = docs\content\Integration.fsx docs\content\Interpolation.fsx = docs\content\Interpolation.fsx docs\content\LinearEquations.fsx = docs\content\LinearEquations.fsx + docs\content\Matrix.fsx = docs\content\Matrix.fsx docs\content\MKL.fsx = docs\content\MKL.fsx docs\content\Probability.fsx = docs\content\Probability.fsx docs\content\Random.fsx = docs\content\Random.fsx diff --git a/docs/content/Matrix.fsx b/docs/content/Matrix.fsx new file mode 100644 index 00000000..e1803f3e --- /dev/null +++ b/docs/content/Matrix.fsx @@ -0,0 +1,310 @@ +(*** hide ***) +#I "../../out/lib/net40" +#r "MathNet.Numerics.dll" +#r "MathNet.Numerics.FSharp.dll" +open MathNet.Numerics.LinearAlgebra + +(** +Matrices and Vectors +==================== + +Math.NET Numerics includes rich types for matrices and vectors. +They support both single and double precision, real and complex floating point numbers. + + +$$$ +\mathbf{A}= +\begin{bmatrix} +a_{0,0} & a_{0,1} & \cdots & a_{0,(n-1)} \\ +a_{1,0} & a_{1,1} & \cdots & a_{1,(n-1)} \\ +\vdots & \vdots & \ddots & \vdots \\ +a_{(m-1),0} & a_{(m-1),1} & \cdots & a_{(m-1),(n-1)} +\end{bmatrix},\quad +\mathbf{v}=\begin{bmatrix}v_0\\v_1\\ \vdots \\v_{n-1}\end{bmatrix} + +Like all data structures in .Net they are 0-indexed, i.e. the top left cell has index (0,0). In matrices, +the first index always refers to the row and the second index to the column. +Empty matrices or vectors are not supported, i.e. each dimension must have a length of at least 1. + +### Context: Linear Algebra + +The context and primary scenario for these types is linear algebra. Their API is broad enough +to use them in other contexts as well, but they are *not* optimized for geometry or +as general purpose storage structure as common in MATLAB. This is intentional, as +spatial problems, geography and geometry have very different usage patterns and requirements +than linear algebra. Also, all places where Math.NET Numerics can be used have a strong +programming language with their own data structures. For example, if you have a collection of vectors, +consider to store them in a list or array, not in a matrix (unless you need matrix operations, of course). + +Storage Layout +-------------- + +Both dense and sparse vectors are supported: + +* **Dense Vector** uses a single array of the same length as the vector. +* **Sparse Vector** uses two arrays which are usually much shorter than the vector. + One array stores all values that are not zero, the other stores their indices. + They are sorted ascendingly by index. + +Matrices can be either dense, diagonal or sparse: + +* **Dense Matrix** uses a single array in column-major order. +* **Diagonal Matrix** stores only the diagonal values, in a single array. +* **Sparse Matrix** stores non-zero values in 3 arrays in the standard compressed sparse row (CSR) format. + One array stores all values that are not zero, another array of the same length stores + the their corresponding column index. The third array of the length of the number of rows plus one, + stores the offsets where each row starts, and the total number of non-zero values in the last field. + +If your data contains only very few zeros, using the sparse variant is orders of magnitudes +slower than their dense counterparts, so consider to use dense types unless the data is very sparse (i.e. almost all zeros). + +Creating Matrices and Vectors +----------------------------- + +The `Matrix` and `Vector` types are defined in the `MathNet.Numerics.LinearAlgebra` namespace. + +For technical and performance reasons there are distinct implementations for each data type. +For example, for double precision numbers there is a `DenseMatrix` class in the `MathNet.Numerics.LinearAlgebra.Double` +namespace. You do not normally need to be aware of that, but as consequence the generic `Matrix` type is abstract +and we need other ways to create a matrix or vector instance. + +The matrix and vector builder provide functions to create instances from a variety of formats or approaches. + + [lang=csharp] + // create a dense matrix with 3 rows and 4 columns + // filled with random numbers sampled from the standard distribution + Matrix m = Matrix.Build.Random(3, 4); + + // create a dense zero-vector of length 10 + Vector v = Vector.Build.Dense(10); + +Since within an application you often only work with one specific data type, a common trick to keep this a bit shorter +is to define shortcuts to the builders: + + [lang=csharp] + var M = Matrix.Build; + var V = Vector.Build; + + // build the same as above + var m = M.Random(3, 4); + var v = V.Dense(10); + +The builder functions usually start with the layout (Dense, Sparse, Diagonal), +so if we'd like to build a sparse matrix, intellisense will list all available options +together once you type `M.Sparse`. + +There are variants to generate synthetic matrices, for example: + + [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)); + + +But often we already have data available in some format and +need a matrix representing the same data. Whenever a function contains +"Of" in its name it does create a copy of the original data. + + [lang=csharp] + // Copy of an existing matrix (can also be sparse or diagonal) + Matrix 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[] 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> 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[,] x = ... + M.DenseOfMatrixArray(x); + +Very similar variants also exist for sparse and diagonal matrices, prefixed +with `Sparse` and `Diagonal` respectively. + +The approach for vectors is exactly the same: + + [lang=csharp] + // Standard-distributed random vector of length 10 + V.Random(10); + + // All-zero vector of length 10 + V.Dense(10); + + // Each field is initialized using a function + V.Dense(10, i => i*i); + + // From an enumerable of values and their index + Tuple[] x = {Tuple.Create(3,2.0), Tuple.Create(1,-3.0)}; + V.DenseOfIndexed(x); + + // Directly bind to an existing array without copying (note: no "Of") + double[] x = existing... + V.Dense(x); + +### Creating matrices and vectors in F# + +In F# we can use the builds just like in C#, but we can also use the F# modules: +*) + +let m1 = matrix [[ 2.0; 3.0 ] + [ 4.0; 5.0 ]] + +let v1 = vector [ 1.0; 2.0; 3.0 ] + +// dense 3x4 matrix filled with zeros +let m2 = DenseMatrix.zero 3 4 + +// dense 3x4 matrix initialized by a function +let m3 = DenseMatrix.init 3 4 (fun i j -> float (i+j)) + +// diagonal 4x4 identity matrix of single precision +let m4 = DiagonalMatrix.identity 4 + +// dense 3x4 matrix created from a sequence of sequence-columns +let x = Seq.init 4 (fun c -> Seq.init 3 (fun r -> float (100*r + c))) +let m5 = DenseMatrix.ofColumnSeq x + +(** +Or using any other of all the available functions. + + +Arithmetics +----------- + +All the common arithmetic operators like `+`, `-`, `*`, `/` and `%` are provided, +between matrices, vectors and scalars. In F# there are additional pointwise +operators `.*`, `./` and `.%` available for convenience. +*) + +let m = matrix [[ 1.0; 4.0; 7.0 ] + [ 2.0; 5.0; 8.0 ] + [ 3.0; 6.0; 9.0 ]] + +let v = vector [ 10.0; 20.0; 30.0 ] + +let v2 = m * v +let m2 = m + 2.0*m + +(** +All other operations are covered by methods, like `Transpose` and `Conjugate`, +or in F# as functions in the Matrix module, e.g. `Matrix.transpose`. +But even the operators have equivalent methods. The equivalent code from +above when using instance methods: + + [lang=csharp] + var v2 = m.Multiply(v); + var m2 = m.Add(m.Multiply(2)); + +These methods also have an overload that accepts the result data structure as last argument, +allowing to avoid allocating new structures for every single operation. Provided the +dimensions match, most also allow one of the arguments to be passed as result, +resulting in an in-place application. For example, an in-place version of the code above: + + [lang=csharp] + m.Multiply(v, v); // v <- m*v + m.Multiply(3, m); // m <- 3*m + + +Norms +----- + +With norms we assign a "size" to vectors and matrices, satisfying certain +properties pertaining to scalability and additivity. Except for the zero element, +the norm is strictly positive. + +Vectors support the following norms: + +* **L1Norm** or Manhattan norm (p=1): the sum of the absolute values. +* **L2Norm** or Euclidean norm (p=2): the square root of the sum of the squared values. + This is the most common norm and assumed if nothing else is stated. +* **InfinityNorm** (p=infinity): the maximum absolute value. +* **Norm(p)**: generalized norm, essentially the p-th root of the sum of the absolute p-power of the values. + +Similarly, matrices support the following norms: + +* **L1Norm** (induced): the maximum absolute column sum. +* **L2Norm** (induced): the largest singular value of the matrix (expensive). +* **InfinityNorm** (induced): the maximum absolute row sum. +* **FrobeniusNorm** (entry-wise): the square root of the sum of the squared values. +* **RowNorms(p)**: the generalized p-norm for each row vector. +* **ColumnNorms(p)**: the generalized p-norm for each column vector. + +Vectors can be normalized to unit p-norm with the `Normalize` method, matrices can +normalize all rows or all columns to unit p-norm with `NormalizeRows` and `NormalizeColumns`. + + +Rank, Trace, Determinant & Condition +------------------------------------ + +Kernel and Range +---------------- + + +Matrix Decompositions +--------------------- + +### Cholesky Decomposition + +### LU Decomposition + +### QR Decomposition + +### Singular Value Decomposition + +### Eigenvalue Decomposition + +Manipulating Matrices and Vectors +--------------------------------- + + +Higher Order Functions +---------------------- + + +Printing and Strings +-------------------- + + + +*) \ No newline at end of file diff --git a/docs/tools/templates/template.cshtml b/docs/tools/templates/template.cshtml index 2a860edb..6143a13b 100644 --- a/docs/tools/templates/template.cshtml +++ b/docs/tools/templates/template.cshtml @@ -57,7 +57,7 @@
  • Floating-Point Numbers
  • Arbitrary Precision Numbers
  • Complex Numbers
  • -
  • Matrices and Vectors
  • +
  • Matrices and Vectors
  • Euclid & Number Theory
  • Combinatorics