Accessing Matrix Elements in C# QuickStart Sample

Illustrates different ways of iterating through the rows and columns of a matrix using classes in the Numerics.NET.LinearAlgebra namespace in C#.

View this sample in: Visual Basic F# IronPython

using System;

using Numerics.NET;
using Numerics.NET.LinearAlgebra;

// Avoid ambiguity.
using Range = Numerics.NET.Range;

namespace Numerics.NET.QuickStart.CSharp
{
    /// <summary>
    /// Illustrates accessing matrix components and iterating 
    /// through the rows and columns of a matrix. Matrix classes
    /// reside in the Numerics.NET.LinearAlgebra namespace 
    /// of Numerics.NET.
    /// </summary>
    class AccessingMatrixComponents
    {
        static void Main(string[] args)
        {
            // The license is verified at runtime. We're using
            // a 30 day trial key here. For more information, see
            //     https://numerics.net/trial-key
            Numerics.NET.License.Verify("64542-18980-57619-62268");

            // We'll work with this matrix:
            var m = Matrix.CreateFromArray(2, 3, new double[] { 1, 2, 3, 4, 5, 6 }, 
                MatrixElementOrder.ColumnMajor);

            //
            // Individual components
            //
            // The Matrix class has an indexer property that takes two arguments:
            // the row and column index. Both are zero based.
            Console.WriteLine("m[1,1] = {0}", m[1, 1]);

            //
            // Rows and columns
            //

            // Indexed range access

            // The indexer property is overloaded to allow for direct indexed access 
            // to complete or partial rows or columns.

            var row1 = m[0, new Range(1, 2)];
            // This prints "[3, 5]":
            Console.WriteLine($"row1 = {row1}");

            // The special range Range.All lets you access an entire row
            // or column without having to specify any details about the range.
            var row2 = m[1, Range.All];
            // This prints "[2, 4, 6]":
            Console.WriteLine($"2nd row = {row2}");
            var column1 = m[Range.All, 0];
            // This prints "[1, 2]":
            Console.WriteLine($"column1 = {column1}");

            // We can assign to rows and columns, too:
            m[Range.All, 0] = row1;
            // This prints "[[3, 3, 5] [5, 4, 6]]"
            Console.WriteLine($"m = {m}");

            // GetRow and GetColumn provide an alternate mechanism 
            // for achieving the same result.

            // Passing just one parameter retrieves the specified row or column:
            row1 = m.GetRow(1);
            // This prints "[2, 4, 6]":
            Console.WriteLine($"row1 = {row1}");
            column1 = m.GetColumn(0);
            // This prints "[1, 2]":
            Console.WriteLine($"column1 = {column1}");

            // You can also pass a start and end index:
            row2 = m.GetRow(0, 1, 2);
            // This prints "[3, 5]":
            Console.WriteLine($"row2 = {row2}");

            // We can assign to rows and columns, too, using CopyTo:
            row2.CopyTo(m.GetColumn(0));
            // This prints "[[3, 3, 5] [5, 4, 6]]"
            Console.WriteLine($"m = {m}");

            // Enumeration

            // The Rows and Columns methods allow you to enumerate over 
            // the rows and columns of a matrix.

            // For example: this calculates the sum of the absolute values
            // of the components of the matrix m:
            double sum = 0;
            foreach(Vector<double> column in m.Columns )
                sum += column.OneNorm();
    
            //
            // Accessing diagonals
            //

            // Diagonals are retrieved using the GetDiagonal method:
            var mainDiagonal = m.GetDiagonal();
            // An optional parameter specifies which diagonal:
            //   n < 0 means subdiagonal
            //   n > 0 means nth superdiagonal:
            var superDiagonal = m.GetDiagonal(1);

            //
            // Accessing submatrices
            //

            // Indexed range access
            
            // A fourth overload of the indexer property lets you 
            // extract a part of a matrix. Both parameters are Range 
            // structures:
            var a = Matrix.Create<double>(10, 10);
            // Extract the 2nd to the 5th row of m:
            var a1 = a[new Range(1, 4), Range.All];
            // Extract the odd columns:
            var a2 = a[Range.All, new Range(1, 9, 2)];
            // Extract the 4x4 leading submatrix of m:
            var a3 = a[new Range(0, 3), new Range(0, 3)];

            // You can also assign to submatrices:
            var identity5 = DenseMatrix<double>.GetIdentity(5);
            a[new Range(0, 4), new Range(5, 9)] = identity5;
            a[new Range(5, 9), new Range(0, 4)] = identity5;

            // The same results can be achieved with the GetSubmatrix method.

            // Extract the 2nd to the 5th row of m. 
            // Start and end columns are supplied manually.
            var a4 = a.GetSubmatrix(1, 4, 0, 9);
            // Extract the odd columns:
            // Here we need to supply the transpose parameter.
            var a5 = a.GetSubmatrix(0, 9, 1, 1, 9, 2, 
                TransposeOperation.None);
            // Extract the 4x4 leading submatrix of m.
            // And let's get its transpose, just because we can.
            // We need to specify the row and column stride:
            var a6 = a.GetSubmatrix(0, 3, 1, 0, 3, 1,
                TransposeOperation.Transpose);

            // You can still assign to submatrices, using the
            // CopyTo method:
            identity5.CopyTo(a.GetSubmatrix(0, 4, 5, 9));
            identity5.CopyTo(a.GetSubmatrix(5, 9, 0, 4));

            Console.WriteLine("Press Enter key to continue.");
            Console.ReadLine();
        }
    }
}