Matrices are two-dimensional tables. The Extreme Optimization Numerical Libraries for .NET includes
classes that allow you to work with the rows and columns of a matrix as vectors. In addition, these classes allow you
to easily navigate through a matrix.
Accessing individual elements
The MatrixT class
has an ItemInt32, Int32
property. The first index is the zero-based row index. The second index is the zero-based
column index. In languages that don't support indexers, you can use the indexed Item property.
If the index is greater than or equal to the number of rows or columns,
an exception of type ArgumentOutOfRangeException
is thrown.
var m = Matrix.Create(2, 2, (i, j) => 11 + 10 * i + j);
m[1, 1] = 99;
Dim m = Matrix.Create(2, 2, Function(i, j) 11 + 10 * i + j)
m(1, 1) = 99
No code example is currently available or this language may not be supported.
let m = Matrix.Create(2, 2, fun i j -> 11 + 10 * i + j)
m.[1, 1] <- 99
Accessing rows and columns
There are three ways to access the rows or columns of a matrix: through indexers,
through row and column getter methods, and through enumerators.
The indexer property is overloaded to allow for direct indexed access
to complete or partial rows or columns. The indexers are similar to
the indexers for vectors. For row access, the first index is the row index.
The second index can be any value that is valid for a vector indexer.
The special range All lets you access
an entire row or column without having to specify any details about the range.
var m = Matrix.Create(3, 3, (i, j) => 11 + 10 * i + j);
var row1 = m[0, Range.All];
var column1 = m[Range.All, 1];
var row2 = m[1, new Range(1, 2)];
var row3 = m[1, new Range(0, 2, 2)];
Dim m = Matrix.Create(3, 3, Function(i, j) 11 + 10 * i + j)
Dim row1 = m(0, Range.All)
Dim column1 = m(Range.All, 1)
Dim row2 = m(1, New Range(1, 2))
Dim row3 = m(1, New Range(0, 2, 2))
No code example is currently available or this language may not be supported.
let m = Matrix.Create(3, 3, fun i j -> 11 + 10 * i + j)
let row1 = m.[0, *]
let column1 = m.[*, 1]
let row2 = m.[1, 1..2]
let row3 = m.[1, Range(0, 2, 2)]
The first example retrieves the entire first row of the matrix m.
The second example retrieves the entire second column. The third example retrieves
only the last two elements of the second row. The final example retrieves the first
and last element of the second row.
The indexers can be assigned to as well. In this case, he elements in the range specified
by the index are set to the corresponding elements of the right-hand side.
This is illustrated in the next example:
m[1, new Range(1, 2)] = Vector.Create(88, 99);
m[1, new Range(0, 2, 2)] = Vector.Create(77, 66);
m[Range.All, 1] = Vector.Create(1, 2, 3);
m(1, New Range(1, 2)) = Vector.Create(88, 99)
m(1, New Range(0, 2, 2)) = Vector.Create(77, 66)
m(Range.All, 1) = Vector.Create(1, 2, 3)
No code example is currently available or this language may not be supported.
m.[1, 1..2] <- Vector.Create(88, 99)
m.[1, Range(0, 2, 2)] <- Vector.Create(77, 66)
m.[*, 1] <- Vector.Create(1, 2, 3)
Boolean masks and predicates may also be used to select a subset of the elements
of the row or column. Once again, you can both get and set the elements:
var m = Matrix.Create(3, 3, (i, j) => Elementary.Pow(i, j));
var mask1 = Vector.Create(false, true, true);
var row1 = m[1, mask1];
var column1 = m[x => x > 1.0, 1];
m[1, mask1] = Vector.Create(4.0, 7.0);
Dim m = Matrix.Create(Of Double)(3, 3, Function(i, j) Elementary.Pow(i, j))
Dim mask1 = Vector.Create(False, True, True)
Dim row1 = m(1, mask1)
Dim column1 = m(Function(x) x > 1.0, 1)
m(1, mask1) = Vector.Create(4.0, 7.0)
No code example is currently available or this language may not be supported.
let m = Matrix.Create(3, 3, fun i j -> Elementary.Pow(float i, j))
let mask1 = Vector.Create(false, true, true)
let row1 = m.[1, mask1]
let column1 = m.[Func<_,_>(fun x -> x > 1.0), 1]
m.[1, mask1] <- Vector.Create(4.0, 7.0)
The GetRow
and GetColumn
methods provide the same functionality as indexed range access, but add the option to specify the intent.
GetRow
always takes the row index as its first argument. If no further arguments are supplied, the
entire row is returned. A partial row can be returned by providing the column index
of the first and last index in the new vector, and optionally a stride. You can also
pass a Range structure
as the only second argument.
GetColumn
has similar overloads. The first argument is always the column index. The remaining
arguments, if present, specify the range of row indexes. The following code sample performs the same operations as
the indexed range sample above, but uses
GetRow
and GetColumn:
var m = Matrix.Create(3, 3, (i, j) => 11 + 10 * i + j, ArrayMutability.Immutable);
var row1 = m.GetRow(1, 1, 2, Intent.WritableCopy);
row1[0] = 99;
var row2 = m.GetRow(1, new Range(0, 2, 2));
var column1 = m.GetColumn(1);
Dim m = Matrix.Create(3, 3, Function(i, j) 11 + 10 * i + j,
ArrayMutability.Immutable)
Dim row1 = m.GetRow(1, 1, 2, Intent.WritableCopy)
row1(0) = 99
Dim row2 = m.GetRow(1, New Range(0, 2, 2))
Dim column1 = m.GetColumn(1)
No code example is currently available or this language may not be supported.
let m = Matrix.Create(3, 3, (fun i j -> 11 + 10 * i + j), ArrayMutability.Immutable)
let row1 = m.GetRow(1, 1, 2, Intent.WritableCopy)
row1.[0] <- 99
let row2 = m.GetRow(1, Range(0, 2, 2))
let column1 = m.GetColumn(1)
Note that the matrix m is immutable, so its rows and columns
are always immutable as well. In the example, we make a writable copy of a row,
and the elements of this vector can be changed
without changing the elements of m.
Matrix operations often involve performing some action on each of the rows
or columns of a matrix. The Rows
and Columns
properties return the rows and columns as collections that can be iterated over.
Enumerating rows and columns is often more efficient than getting each row or column
in a loop because only one vector may be allocated
The following example shows a method that calculates the sum of
the absolute values of a matrix.
double SumOfAbsoluteValues(Matrix<double> a)
{
double sum = 0;
foreach (var column in a.Columns)
sum += column.OneNorm();
return sum;
}
Function SumOfAbsoluteValues(a As Matrix(Of Double)) As Double
Dim sum = 0.0
For Each column In a.Columns
sum += column.OneNorm()
Next
Return sum
End Function
No code example is currently available or this language may not be supported.
let SumOfAbsoluteValues(a : Matrix<double>) =
let mutable sum = 0.0
for column in a.Columns do
sum <- sum + column.OneNorm()
sum
The one-norm of a vector equals the sum of the absolute values of its elements.
All we have to do to obtain the sum of the absolute values of a matrix, then,
is to sum the one-norms of all the rows or columns. Since most algorithms are
optimized for matrices stored in column major order, it is recommended to iterate
over the columns rather than the rows whenever possible.
The GetDiagonal
method returns a vector whose elements are the diagonal of a matrix. The method has
an optional argument that specifies the index of the diagonal.
A value of zero indicates the main diagonal. A value greater than zero indicates
a super-diagonal. A value less than zero indicates a sub-diagonal.
The default is to return the main diagonal.
As with the GetRow
and GetRow
methods, an Intent value
can be passed as the last argument.
Sometimes it may be useful to treat part of a matrix as if it were a matrix
in its own right. There are two ways of achieving this.
The indexer for the MatrixT
class has several overloads that lets you extract a part of a matrix.
Both arguments of the indexer are
Range structures. The first specifies the range of rows
to include. The second argument specifies the range of columns. Both arguments may have the special value
All, which indicates that the entire column or
row should be included. Some examples:
var m = Matrix.CreateRandom(10, 10);
var m1 = m[new Range(1, 4), Range.All];
var m2 = m[Range.All, new Range(1, 10, 2)];
var m3 = m[new Range(0, 3), new Range(0, 3)];
Dim m = Matrix.CreateRandom(10, 10)
Dim m1 = m(New Range(1, 4), Range.All)
Dim m2 = m(Range.All, New Range(1, 10, 2))
Dim m3 = m(New Range(0, 3), New Range(0, 3))
No code example is currently available or this language may not be supported.
let m = Matrix.CreateRandom(10, 10)
let m1 = m.[1..4, *]
let m2 = m.[Range.All, Range(1, 10, 2)]
let m3 = m.[0..3, 0..3]
You can also assign to ranges. The following example sets the upper right and lower left blocks of a 10x10 matrix
to the identity matrix:
var m = Matrix.Create<double>(10, 10);
var ones = Vector.CreateConstant(5, 1.0);
var identity5 = Matrix.CreateDiagonal(ones);
m[new Range(0, 4), new Range(5, 9)] = identity5;
m[new Range(5, 9), new Range(0, 4)] = identity5;
Dim m = Matrix.Create(Of Double)(10, 10)
Dim ones = Vector.CreateConstant(5, 1.0)
Dim identity5 = Matrix.CreateDiagonal(ones)
m(New Range(0, 4), New Range(5, 9)) = identity5
m(New Range(5, 9), New Range(0, 4)) = identity5
No code example is currently available or this language may not be supported.
let m = Matrix.Create<double>(10, 10)
let ones = Vector.CreateConstant(5, 1.0)
let identity5 = Matrix.CreateDiagonal(ones)
m.[Range(0, 4), Range(5, 9)] <- identity5
m.[Range(5, 9), Range(0, 4)] <- identity5
We first create a 5x5 identity matrix by calling the
CreateDiagonal
method. We then assign this matrix to the selected blocks of m.
The same results can be achieved with the
GetSubmatrix
method, which is somewhat more flexible.
Like the GetRow
and GetColumn
methods mentioned earlier, you can specify the intended use of the sub-matrix.
You can also apply a transposition operation to the matrix.
The ranges can be specified using either Range
structures or explicit start and end indices. An optional argument lets you specify the transpose operation to
apply, if any. The earlier examples can be expressed using the GetSubmatrix method as follows:
var m = Matrix.CreateRandom(10, 10);
var m1 = m.GetSubmatrix(1, 4, 0, 9);
var m2 = m.GetSubmatrix(0, 9, 1, 1, 10, 2, TransposeOperation.None);
var m3 = m.GetSubmatrix(0, 3, 1, 0, 3, 1,
TransposeOperation.Transpose);
Dim m = Matrix.CreateRandom(10, 10)
Dim m1 = m.GetSubmatrix(1, 4, 0, 9)
Dim m2 = m.GetSubmatrix(0, 9, 1, 1, 10, 2, TransposeOperation.None)
Dim m3 = m.GetSubmatrix(0, 3, 1, 0, 3, 1,
TransposeOperation.Transpose)
No code example is currently available or this language may not be supported.
let m = Matrix.CreateRandom(10, 10)
let m1 = m.GetSubmatrix(1, 4, 0, 9)
let m2 = m.GetSubmatrix(0, 9, 1, 1, 10, 2, TransposeOperation.None)
let m3 = m.GetSubmatrix(0, 3, 1, 0, 3, 1,
TransposeOperation.Transpose)
Notice how in the last sample, the transpose of the sub-matrix was returned.
You can still assign to sub-matrices using the
CopyTo
method:
var m = Matrix.Create<double>(10, 10);
var ones = Vector.CreateConstant(5, 1.0);
var identity5 = Matrix.CreateDiagonal(ones);
identity5.CopyTo(m.GetSubmatrix(0, 4, 5, 9));
identity5.CopyTo(m.GetSubmatrix(5, 9, 0, 4));
Dim m = Matrix.Create(Of Double)(10, 10)
Dim ones = Vector.CreateConstant(5, 1.0)
Dim identity5 = Matrix.CreateDiagonal(ones)
identity5.CopyTo(m.GetSubmatrix(0, 4, 5, 9))
identity5.CopyTo(m.GetSubmatrix(5, 9, 0, 4))
No code example is currently available or this language may not be supported.
let m = Matrix.Create<double>(10, 10)
let ones = Vector.CreateConstant(5, 1.0)
let identity5 = Matrix.CreateDiagonal(ones)
identity5.CopyTo(m.GetSubmatrix(0, 4, 5, 9)) |> ignore
identity5.CopyTo(m.GetSubmatrix(5, 9, 0, 4)) |> ignore