Math.NET Numerics | Math.NET Project | GitHub


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 quite different usage patterns and requirements to linear algebra. 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 of vectors, not in a matrix (unless you need matrix operations, of course).

Storage Layout

Both dense and sparse vectors are supported:

Matrices can be either dense, diagonal or sparse:

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<T> and Vector<T> 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<T> 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.

// create a dense matrix with 3 rows and 4 columns
// filled with random numbers sampled from the standard distribution
Matrix<double> m = Matrix<double>.Build.Random(3, 4);

// create a dense zero-vector of length 10
Vector<double> v = Vector<double>.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:

var M = Matrix<double>.Build;
var V = Vector<double>.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:

// 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.

// 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);

Very similar variants also exist for sparse and diagonal matrices, prefixed with Sparse and Diagonal respectively.

The approach for vectors is exactly the same:

// 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<int,double>[] 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 builders 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.
// (usually the type is inferred, but not for zero matrices)
let m2 = DenseMatrix.zero<float> 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<float32> 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

// random matrix with standard distribution:
let m6 = DenseMatrix.randomStandard<float> 3 4

// random matrix with a uniform and one with a Gamma distribution:
let m7a = DenseMatrix.random<float> 3 4 (ContinuousUniform(-2.0, 4.0))
let m7b = DenseMatrix.random<float> 3 4 (Gamma(1.0, 2.0))

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 v' = m * v
let m' = m + 2.0*m

Arithmetic Instance Methods

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:

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:

m.Multiply(v, v); // v <- m*v
m.Multiply(3, m); // m <- 3*m

Shortcut Methods

A typical linear algebra problem is the regression normal equation \(\mathbf{X}^T\mathbf y = \mathbf{X}^T\mathbf X \mathbf p\) which we would like to solve for \(p\). By matrix inversion we get \(\mathbf p = (\mathbf{X}^T\mathbf X)^{-1}(\mathbf{X}^T\mathbf y)\). This can directly be translated to the following code:

(X.Transpose() * X).Inverse() * (X.Transpose() * y)

Since products where one of the arguments is transposed are common, there are a few shortcut routines that are more efficient:

X.TransposeThisAndMultiply(X).Inverse() * X.TransposeThisAndMultiply(y)

Of course in practice you would not use the matrix inverse but a decomposition:

X.TransposeThisAndMultiply(X).Cholesky().Solve(X.TransposeThisAndMultiply(y))

// or if the problem is small enough, simply:
X.Solve(y);

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:

Similarly, matrices support the following norms:

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.

Sums

Closely related to the norms are sum functions. Vectors have a Sum function that returns the sum of all vector elements, and SumMagnitudes that returns the sum of the absolute vector elements (and is identical to the L1-norm).

Matrices provide RowSums and ColumnSums functions that return the sum of each row or column vector, and RowAbsoluteSums and ColumnAbsoluteSums for the sums of the absolute elements.

Condition Number

The condition number of a function measures how much the output value can change for a small change in the input arguments. A problem with a low condition number is said to be well-conditioned, with a high condition number ill-conditioned. For a linear equation \(Ax=b\) the condition number is the maximum ratio of the relative error in \(x\) divided by the relative error in \(b\). It therefore gives a bound on how inaccurate the solution \(x\) will be after approximation.

M.Random(4,4).ConditionNumber(); // e.g. 14.829

Trace and Determinant

For a square matrix, the trace of a matrix is the sum of the elements on the main diagonal, which is equal to the sum of all its eigenvalues with multiplicities. Similarly, the determinant of a square matrix is the product of all its eigenvalues with multiplicities. A matrix is said to be singular if its determinant is zero and non-singular otherwise. In the latter case the matrix is invertible and the linear equation system it represents has a single unique solution.

var m = M.DenseOfArray(new[,] {{ 1.0,  2.0, 1.0},
                               {-2.0, -3.0, 1.0},
                               { 3.0,  5.0, 0.0}});

m.Trace();       // -2
m.Determinant(); // ~0 hence not invertible, either none or multiple solutions

Column Space, Rank and Range

The rank of a matrix is the dimension of its column and row space, i.e. the maximum number of linearly independent column and row vectors of the matrix. It is a measure of the non-degenerateness of the linear equation system the matrix represents.

An orthonormal basis of the column space can be computed with the range method.

// with the same m as above
m.Rank();  // 2
m.Range(); // [-0.30519,0.503259,-0.808449], [-0.757315,-0.64296,-0.114355]

Null Space, Nullity and Kernel

The null space or kernel of a matrix \(A\) is the set of solutions to the equation \(Ax=0\). It is the orthogonal complement to the row space of the matrix.

The nullity of a matrix is the dimension of its null space. An orthonormal basis of the null space can be computed with the kernel method.

// with the same m as above
m.Nullity(); // 1
m.Kernel();  // [0.845154,-0.507093,0.169031]

// verify:
(m * (10*m.Kernel()[0])); // ~[0,0,0]

Matrix Decompositions

Most common matrix decompositions are directly available as instance methods. Computing a decomposition can be expensive for large matrices, so if you need to access multiple properties of a decomposition, consider to reuse the returned instance.

All decompositions provide Solve methods than can be used to solve linear equations of the form \(Ax=b\) or \(AX=B\). For simplicity the Matrix class also provides direct Solve methods that automatically choose a decomposition. See Linear Equation Systems for details.

Currently these decompositions are optimized for dense matrices only, and can leverage native providers like Intel MKL if available. For sparse data consider to use the iterative solvers instead if appropriate, or convert to dense if small enough.

Manipulating Matrices and Vectors

Individual values can be get and set in matrices and vectors using the indexers or the At methods. Using At instead of the indexers is slightly faster but skips some range checks, so use it only after checking the range yourself.

var m = Matrix<double>.Build.Dense(3,4,(i,j) => 10*i + j);
m[0,0]; // 0   (row 0, column 0)
m[2,0]; // 20 (row 2, column 0)
m[0,2]; // 2   (row 0, column 2)
m[0,2] = -1.0;
m[0,2]; // -1

In F#:

m.[2,0] // 20

We can also get entire column or row vectors, or a new matrix from parts of an existing one.

var m = M.Dense(6,4,(i,j) => 10*i + j);
m.Column(2);          // [2,12,22,32,42,52]
m.Row(3);             // [30,31,32,33]
m.SubMatrix(1,2,1,2); // [11,12; 21,22]

For each of these methods there is also a variant prefixed with Set that can be used to overwrite those elements with the provided data.

m.SetRow(3, V.Random(4));

In F# we can also use its slicing syntax:

let m = DenseMatrix.init 6 4 (fun i j -> float (10*i + j))
m.[0,0..3]    // vector [0,1,2,3]
m.[1..2,0..3] // matrix [10,11,12,13; 20,21,22,23]
// overwrite a sub-matrix with the content of another matrix:
m.[0..1,1..2] <- matrix [[ 3.0; 4.0 ]; [ 5.0; 6.0 ]]

To set the whole matrix or some of its columns or rows to zero, use one of the clear methods:

m.Clear(); // set all elements to 0
m.ClearColumn(2); // set the 3rd column to 0 (0-based indexing)
m.ClearColumns(1,3); // set the 2nd and 4th columns to 0 (params-array)
m.ClearSubMatrix(1,2,1,2); // set the 2x2 submatrix with offset 1,1 to zero

Because of the limitations of floating point numbers, we may want to set very small numbers to zero:

m.CoerceZero(1e-14); // set all elements smaller than 1e-14 to 0
m.CoerceZero(x => x < 10); // set all elements that match a predicate function to 0.

Even though matrices and vectors are mutable, their dimension is fixed and cannot be changed after creation. However, we can still insert or remove rows or columns, or concatenate matrices together. But all these operations will create and return a new instance.

var m2 = m.RemoveRow(2); // remove the 3rd rows
var m3 = m2.RemoveColumn(3); // remove the 4th column

var m4 = m.Stack(m2); // new matrix with m on top and m2 on the bottom
var m5 = m2.Append(m3); // new matrix with m2 on the left and m3 on the right
var m6 = m.DiagonalStack(m3); // m on the top left and m3 on the bottom right

Enumerators and Higher Order Functions

Since looping over all entries of a matrix or vector with direct access is inefficient, especially with a sparse storage layout, and working with the raw structures is non-trivial, both vectors and matrices provide specialized enumerators and higher order functions that understand the actual layout and can use it more efficiently.

Most of these functions can optionally skip zero-value entries. If you do not need to handle zero-value elements, skipping them can massively speed up execution on sparse layouts.

Iterate

Both vectors and matrices have Enumerate methods that return an IEnumerable<T>, that can be used to iterate through all elements. All these methods optionally accept a Zeros enumeration to control whether zero-values may be skipped or not.

Matrices can also enumerate over all column or row vectors, or all of them within a range:

Map

Similarly there are also Map methods that replace each element with the result of applying a function to its value. Or, if indexed, to its index and value.

Example: Convert a complex vector to a real vector containing only the real parts in C#:

Vector<Complex> u = Vector<Complex>.Build.Random(10);
Vector<Double> v = u.Map(c => c.Real);

Or in F#:

let u = DenseVector.randomStandard<Complex> 10
let v = u |> Vector.map (fun c -> c.Real)

Fold and Reduce

Matrices also provide column/row fold and reduce routines:

Printing and Strings

Matrices and vectors try to print themselves to a string with the ToString in a reasonable way, without overflowing the output device on a large matrix.

Note that this function is not intended to export a data structure to a string or file, but to give an informative summary about it. For data import/export, use one of the MathNet.Numerics.Data packages instead.

Some matrix examples:

// Matrix<double>.Build.Dense(3,4,(i,j) => i*10*j).ToString()
DenseMatrix 3x4-Double
0   0   0   0
0  10  20  30
0  20  40  60

// Matrix<double>.Build.Dense(100,100,(i,j) => i*10*j).ToString()
DenseMatrix 100x100-Double
 0    0     0     0     0     0     0     0     0     0     0  ..      0      0
 0   10    20    30    40    50    60    70    80    90   100  ..    980    990
 0   20    40    60    80   100   120   140   160   180   200  ..   1960   1980
 0   30    60    90   120   150   180   210   240   270   300  ..   2940   2970
 0   40    80   120   160   200   240   280   320   360   400  ..   3920   3960
 0   50   100   150   200   250   300   350   400   450   500  ..   4900   4950
 0   60   120   180   240   300   360   420   480   540   600  ..   5880   5940
 0   70   140   210   280   350   420   490   560   630   700  ..   6860   6930
..   ..    ..    ..    ..    ..    ..    ..    ..    ..    ..  ..     ..     ..
 0  960  1920  2880  3840  4800  5760  6720  7680  8640  9600  ..  94080  95040
 0  970  1940  2910  3880  4850  5820  6790  7760  8730  9700  ..  95060  96030
 0  980  1960  2940  3920  4900  5880  6860  7840  8820  9800  ..  96040  97020
 0  990  1980  2970  3960  4950  5940  6930  7920  8910  9900  ..  97020  98010

// Matrix<double>.Build.Random(4,4).ToString()
DenseMatrix 4x4-Double
  1.6286    -1.1126    1.95526  0.950545
0.537503  -0.465534    2.00984   1.90885
-1.62816    1.04109   -2.06876  0.812197
0.452355  -0.689394  -0.277921   2.72224

// Matrix<double>.Build.SparseOfIndexed(4,100,new[] {Tuple.Create(1,2,3.0)})
SparseMatrix 4x100-Double 0.25% Filled
0  0    0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  ..  0  0
0  0  3.5  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  ..  0  0
0  0    0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  ..  0  0
0  0    0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  0  ..  0  0

Vectors are printed as a column that can wrap over to multiple columns if needed:

// Vector<double>.Build.Random(15).ToString()
DenseVector 15-Double
 0.519184  0.0950414
  1.65913    2.56783
 0.743408   0.574037
 -1.73394           
-0.906662           
 0.853759           
-0.162181           
-0.231667           
 -1.26393           
-0.434873           
 0.693421           
-0.513683           

// Vector<double>.Build.Dense(500,i => i).ToString()
DenseVector 500-Double
 0  12  24  36  48  60  72  84   96  108  120  132  144  156  168  180  192
 1  13  25  37  49  61  73  85   97  109  121  133  145  157  169  181  193
 2  14  26  38  50  62  74  86   98  110  122  134  146  158  170  182  194
 3  15  27  39  51  63  75  87   99  111  123  135  147  159  171  183  195
 4  16  28  40  52  64  76  88  100  112  124  136  148  160  172  184  196
 5  17  29  41  53  65  77  89  101  113  125  137  149  161  173  185  197
 6  18  30  42  54  66  78  90  102  114  126  138  150  162  174  186  198
 7  19  31  43  55  67  79  91  103  115  127  139  151  163  175  187  199
 8  20  32  44  56  68  80  92  104  116  128  140  152  164  176  188   ..
 9  21  33  45  57  69  81  93  105  117  129  141  153  165  177  189   ..
10  22  34  46  58  70  82  94  106  118  130  142  154  166  178  190  498
11  23  35  47  59  71  83  95  107  119  131  143  155  167  179  191  499

The format is customizable to some degree, for example we can choose the floating point format and culture, or how many rows or columns should be shown:

// var m = Matrix<double>.Build.Random(5,100,42); // 42 = random seed

// m.ToString()
DenseMatrix 5x100-Double
 0.408388  -0.847291  -0.320552   0.162242    2.46434  ..   0.180466   -0.278793
 -1.06988   0.063008  -0.527378    1.40716    -0.5962  ..  -0.622447   -0.488186
-0.734176  -0.703003    1.33158   0.286498    1.44158  ..  -0.834335  -0.0756724
  1.78532   0.020217    1.94275  -0.742821  -0.790251  ..    1.52823     2.49427
-0.660645    1.28166   -1.71351   -1.33282  -0.328162  ..   0.110989    0.252272

// m.ToString("G2", CultureInfo.GetCultureInfo("de-DE"))
DenseMatrix 5x100-Double
 0,41  -0,85  -0,32   0,16    2,5     -0,77   0,12   0,58  ..   0,18   -0,28
 -1,1  0,063  -0,53    1,4   -0,6      -2,8  -0,35    0,3  ..  -0,62   -0,49
-0,73   -0,7    1,3   0,29    1,4  -0,00022   -0,3   0,51  ..  -0,83  -0,076
  1,8   0,02    1,9  -0,74  -0,79     0,088   0,78  -0,94  ..    1,5     2,5
-0,66    1,3   -1,7   -1,3  -0,33     -0,69  -0,27  -0,68  ..   0,11    0,25

// m.ToString(3,5) // max 3 rows, 5 columns
DenseMatrix 5x100-Double
 0.408388  -0.847291  -0.320552  ..   0.180466   -0.278793
 -1.06988   0.063008  -0.527378  ..  -0.622447   -0.488186
-0.734176  -0.703003    1.33158  ..  -0.834335  -0.0756724
       ..         ..         ..  ..         ..          ..

// Matrix<double>.Build.Random(100,100,42)
// .ToMatrixString(2,4,3,4,"=","||",@"\\"," ",Environment.NewLine,x=>x.ToString("G2"))
 0.41   0.36  0.29  =  0.43 0.56   -0.56  0.98
 -1.1  -0.64   0.9  =  0.49 -0.3       2  -0.5
   ||     ||    || \\    ||   ||      ||    ||
-0.87   -2.2  0.79  =  0.96  1.8     1.4 0.067
-0.14 -0.016 -0.55  = -0.36 0.33    0.24  0.52
 -1.3     -1 -0.81  =   1.3    1    -1.1 -0.28
-0.21   -1.7   2.6  =  -1.5 -1.2 -0.0014   3.4

If you are using Math.NET Numerics from within F# interactive, you may want to load the MathNet.Numerics.fsx script of the F# package. Besides loading the assemblies it also adds proper FSI printers for both matrices and vectors.

val m1 : obj
val v1 : obj
val m2 : obj
Multiple items
val float : value:'T -> float (requires member op_Explicit)
<summary>Converts the argument to 64-bit float. This is a direct conversion for all primitive numeric types. For strings, the input is converted using <c>Double.Parse()</c> with InvariantCulture settings. Otherwise the operation requires an appropriate static conversion method on the input type.</summary>
<param name="value">The input value.</param>
<returns>The converted float</returns>


--------------------
[<Struct>] type float = System.Double
<summary>An abbreviation for the CLI type <see cref="T:System.Double" />.</summary>
<category>Basic Types</category>


--------------------
type float<'Measure> = float
<summary>The type of double-precision floating point numbers, annotated with a unit of measure. The unit of measure is erased in compiled code and when values of this type are analyzed using reflection. The type is representationally equivalent to <see cref="T:System.Double" />.</summary>
<category index="6">Basic Types with Units of Measure</category>
val m3 : obj
val m4 : obj
Multiple items
val float32 : value:'T -> float32 (requires member op_Explicit)
<summary>Converts the argument to 32-bit float. This is a direct conversion for all primitive numeric types. For strings, the input is converted using <c>Single.Parse()</c> with InvariantCulture settings. Otherwise the operation requires an appropriate static conversion method on the input type.</summary>
<param name="value">The input value.</param>
<returns>The converted float32</returns>


--------------------
[<Struct>] type float32 = System.Single
<summary>An abbreviation for the CLI type <see cref="T:System.Single" />.</summary>
<category>Basic Types</category>


--------------------
type float32<'Measure> = float32
<summary>The type of single-precision floating point numbers, annotated with a unit of measure. The unit of measure is erased in compiled code and when values of this type are analyzed using reflection. The type is representationally equivalent to <see cref="T:System.Single" />. </summary>
<category>Basic Types with Units of Measure</category>
val x : seq<seq<float>>
module Seq from Microsoft.FSharp.Collections
<summary>Contains operations for working with values of type <see cref="T:Microsoft.FSharp.Collections.seq`1" />.</summary>
val init : count:int -> initializer:(int -> 'T) -> seq<'T>
<summary>Generates a new sequence which, when iterated, will return successive elements by calling the given function, up to the given count. Each element is saved after its initialization. The function is passed the index of the item being generated.</summary>
<remarks>The returned sequence may be passed between threads safely. However, individual IEnumerator values generated from the returned sequence should not be accessed concurrently.</remarks>
<param name="count">The maximum number of items to generate for the sequence.</param>
<param name="initializer">A function that generates an item in the sequence from a given index.</param>
<returns>The result sequence.</returns>
<exception cref="T:System.ArgumentException">Thrown when count is negative.</exception>
val c : int
val r : int
val m5 : obj
val m6 : obj
val m7a : obj
val m7b : obj
val m : float
val v : float
val v' : float
val m' : float
val m : obj
val u : obj
Multiple items
[<Struct>] type Complex = new : real: float * imaginary: float -> unit member Equals : value: Complex -> bool + 1 overload member GetHashCode : unit -> int member ToString : unit -> string + 3 overloads static member Abs : value: Complex -> float static member Acos : value: Complex -> Complex static member Add : left: float * right: Complex -> Complex + 2 overloads static member Asin : value: Complex -> Complex static member Atan : value: Complex -> Complex static member Conjugate : value: Complex -> Complex ...
<summary>Represents a complex number.</summary>

--------------------
Complex ()
Complex(real: float, imaginary: float) : Complex
val v : obj
Multiple items
type Vector = static member Abs<'T (requires default constructor and value type and 'T :> ValueType)> : value: Vector<'T> -> Vector<'T> static member Add<'T (requires default constructor and value type and 'T :> ValueType)> : left: Vector<'T> * right: Vector<'T> -> Vector<'T> static member AndNot<'T (requires default constructor and value type and 'T :> ValueType)> : left: Vector<'T> * right: Vector<'T> -> Vector<'T> static member As<'TFrom,'TTo (requires default constructor and value type and 'TFrom :> ValueType and default constructor and value type and 'TTo :> ValueType)> : vector: Vector<'TFrom> -> Vector<'TTo> static member AsVectorByte<'T (requires default constructor and value type and 'T :> ValueType)> : value: Vector<'T> -> Vector<byte> static member AsVectorDouble<'T (requires default constructor and value type and 'T :> ValueType)> : value: Vector<'T> -> Vector<float> static member AsVectorInt16<'T (requires default constructor and value type and 'T :> ValueType)> : value: Vector<'T> -> Vector<int16> static member AsVectorInt32<'T (requires default constructor and value type and 'T :> ValueType)> : value: Vector<'T> -> Vector<int> static member AsVectorInt64<'T (requires default constructor and value type and 'T :> ValueType)> : value: Vector<'T> -> Vector<int64> static member AsVectorNInt<'T (requires default constructor and value type and 'T :> ValueType)> : value: Vector<'T> -> Vector<nativeint> ...

--------------------
[<Struct>] type Vector<'T (requires default constructor and value type and 'T :> ValueType)> = new : values: ReadOnlySpan<byte> -> unit + 5 overloads member CopyTo : destination: Span<byte> -> unit + 3 overloads member Equals : other: Vector<'T> -> bool + 1 overload member GetHashCode : unit -> int member ToString : unit -> string + 2 overloads member TryCopyTo : destination: Span<byte> -> bool + 1 overload static member op_Addition : left: Vector<'T> * right: Vector<'T> -> Vector<'T> static member op_BitwiseAnd : left: Vector<'T> * right: Vector<'T> -> Vector<'T> static member op_BitwiseOr : left: Vector<'T> * right: Vector<'T> -> Vector<'T> static member op_Division : left: Vector<'T> * right: Vector<'T> -> Vector<'T> ...

--------------------
Vector ()
Vector(values: System.ReadOnlySpan<byte>) : Vector<'T>
Vector(values: System.ReadOnlySpan<'T>) : Vector<'T>
Vector(values: System.Span<'T>) : Vector<'T>
Vector(value: 'T) : Vector<'T>
Vector(values: 'T []) : Vector<'T>
Vector(values: 'T [], index: int) : Vector<'T>