MatrixDotNet 0.0.7.3

dotnet add package MatrixDotNet --version 0.0.7.3
NuGet\Install-Package MatrixDotNet -Version 0.0.7.3
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="MatrixDotNet" Version="0.0.7.3" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add MatrixDotNet --version 0.0.7.3
#r "nuget: MatrixDotNet, 0.0.7.3"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install MatrixDotNet as a Cake Addin
#addin nuget:?package=MatrixDotNet&version=0.0.7.3

// Install MatrixDotNet as a Cake Tool
#tool nuget:?package=MatrixDotNet&version=0.0.7.3

MatrixDotNet

alternate text is missing from this package README image

<h3 align="center">

NuGet Downloads Stars Gitter License

</h3> <h3 align="center"> <a href="#features">Features</a> <span> · </span> <a href="https://toor1245.github.io/MatrixDotNet/articles/intro.html">Getting started</a> <span> · </span> <a href="https://toor1245.github.io/MatrixDotNet/index.html">Documentation</a> <span> · </span> <a href="https://toor1245.github.io/MatrixDotNet/api/index.html">API Reference</a> </h3>

MatrixDotNet is a powerful .NET library for matrix calculation. You can install MatrixDotNet via NuGet package.

Features

  • Have many algorithms such sections as: factorizations, solving a linear system, conversion matrix, statistics
  • Have algorithms which enhance precision
  • You can write your matrix to markdown or html and open them with happen .dat file

Have many algorithms such sections as: factorization, solver, conversion matrix, statistics

Let's consider several algorithms on each section.

  • <a href = "#factorizations">Factorizations</a>
  • <a href = "#solving-a-linear-system">Solving a linear system</a>
  • <a href = "#conversion-matrix">Conversion matrix</a>
  • <a href = "#statistics">Statistics</a>
Factorizations

In many applications, it is useful to decompose a matrix using other representations. All decompositions are available in namespace MatrixDotNet.Extensions.Decomposition. So let's consider the decompositions supported by MatrixDotNet.

LUP decomposition

The LU decomposition finds a representation for the square matrix A as:

<h5> A = LU</h5>

  • where L is lower-triangular matrix n x n
  • where U is upper-triangular matrix n x n

for example lets take matrix size 3 x 3

example

Without proper ordering or permutations in the matrix, the factorization mays fail to materialize. For example, it is easy to verify (by expanding the matrix multiplication) that a<sub>11</sub> = l<sub>11</sub> * u<sub>11</sub> If a<sub>11</sub> = 0, then at least one of l<sub>11</sub> and u<sub>11</sub> has to be zero, which implies that either L or U is singular. This is impossible if A is nonsingular (invertible). This procedural problem can be removed by simply reordering the rows of A so that the first element of the permuted matrix is nonzero. The same problem is applied for subsequent factorization steps and can be solved in the same way.

Lets see LU factorization in MatrixDotNet

public class LUSample
{
    public static void Run()
    {
        // initialize matrix with random values.
        Matrix<double> matrix = BuildMatrix.Random(5, 5, -10, 10);
        
        // display matrix.
        matrix.Pretty();
        
        // LU decomposition.
        matrix.GetLowerUpper(out var lower,out var upper);
        
        // display lower-triangular matrix.
        Console.WriteLine("lower-triangular matrix");
        lower.Pretty();
        
        // display upper-triangular matrix.
        Console.WriteLine("upper-triangular matrix");
        upper.Pretty();
        
        // A = LU
        Console.WriteLine("A = LU");
        Console.WriteLine(lower * upper);
    }
}
Output

Number of rows: 5
Number of columns: 5


  -8,00  |  9,00   |  -3,00  |  2,00   |  6,00   |
  7,00   |  -6,00  |  -5,00  |  -9,00  |  6,00   |
  5,00   |  4,00   |  6,00   |  -1,00  |  -9,00  |
  -4,00  |  3,00   |  -8,00  |  -9,00  |  5,00   |
  6,00   |  0,00   |  3,00   |  3,00   |  8,00   |

lower-triangular matrix
Number of rows: 5
Number of columns: 5


  1,00   |  0,00   |  0,00   |  0,00   |  0,00  |
  -0,88  |  1,00   |  0,00   |  0,00   |  0,00  |
  -0,62  |  5,13   |  1,00   |  0,00   |  0,00  |
  0,50   |  -0,80  |  -0,29  |  1,00   |  0,00  |
  -0,75  |  3,60   |  0,65   |  -1,26  |  1,00  |

upper-triangular matrix
Number of rows: 5
Number of columns: 5


  -8,00  |  9,00  |  -3,00  |  2,00   |  6,00    |
  0,00   |  1,88  |  -7,62  |  -7,25  |  11,25   |
  0,00   |  0,00  |  43,27  |  37,47  |  -63,00  |
  0,00   |  0,00  |  0,00   |  -4,89  |  -7,35   |
  0,00   |  0,00  |  0,00   |  0,00   |  3,77    |

A = LU

  -8,00  |  9,00   |  -3,00  |  2,00   |  6,00   |
  7,00   |  -6,00  |  -5,00  |  -9,00  |  6,00   |
  5,00   |  4,00   |  6,00   |  -1,00  |  -9,00  |
  -4,00  |  3,00   |  -8,00  |  -9,00  |  5,00   |
  6,00   |  0,00   |  3,00   |  3,00   |  8,00   |

LUP decomposition

It turns out that a proper permutation in rows (or columns) is sufficient for LU factorization. LU factorization with partial pivoting (LUP) refers often to LU factorization with row permutations only:

<h5>PA = LU</h5>

where L and U are again lower and upper triangular matrices, and P is a permutation matrix, which, when left-multiplied to A, reorders the rows of A. It turns out that all square matrices can be factorized in this form, and the factorization is numerically stable in practice.This makes LUP decomposition a useful technique in practice.

public class LUPSample
{
    public static void Run()
    {
        // initialize matrix with random values.
        Matrix<double> matrix = BuildMatrix.Random(3, 3, -10, 10);
        
        // display matrix.
        matrix.Pretty();
        
        // LU decomposition.
        matrix.GetLowerUpperPermutation(out var lower,out var upper,out var perm);
        
        // Gets permutation matrix and C = L + U - E.
        matrix.GetLowerUpperPermutation(out var matrixC,out var matrixP);
        
        // display lower-triangular matrix.
        Console.WriteLine("lower-triangular matrix");
        lower.Pretty();
        
        // display upper-triangular matrix.
        Console.WriteLine("upper-triangular matrix");
        upper.Pretty();
        
        // display permutation matrix.
        Console.WriteLine("permutation matrix");
        perm.Pretty();
        
        // display matrix C
        Console.WriteLine("matrix C = L + U - E");
        matrixC.Pretty();
    }
}

Output
Number of rows: 3
Number of columns: 3

  -8,00  |  -6,00  |  -1,00  |
  5,00   |  6,00   |  6,00   |
  -1,00  |  -2,00  |  -5,00  |

lower-triangular matrix
Number of rows: 3
Number of columns: 3

  1,00   |  0,00   |  0,00  |
  -0,62  |  1,00   |  0,00  |
  0,12   |  -1,80  |  1,00  |

upper-triangular matrix
Number of rows: 3
Number of columns: 3

  -8,00  |  -6,00  |  -1,00  |
  0,00   |  -1,25  |  -4,88  |
  0,00   |  0,00   |  -3,40  |

permutation matrix
Number of rows: 3
Number of columns: 3

  1,00  |  0,00  |  0,00  |
  0,00  |  0,00  |  1,00  |
  0,00  |  1,00  |  0,00  |

matrix C = L + U - E
Number of rows: 3
Number of columns: 3


  -8,00  |  -6,00  |  -1,00  |
  5,00   |  6,00   |  6,00   |
  -1,00  |  -0,33  |  -3,00  |
Solving a linear system
Kramer solve

Cramer's rule is an explicit formula for the solution of a system of linear equations with as many equations as unknowns, valid whenever the system has a unique solution. It expresses the solution in terms of the determinants of the (square) coefficient matrix and of matrices obtained from it by replacing one column by the column vector of right-hand-sides of the equations.

public sealed class Program
{
    static void Main(string[] args)
    {
        // initialize matrix.
        double[,] arr =
        {
            {5,56,7},
            {3,6,3},
            {5,9,15}
        };


        Matrix<double> matrix = new Matrix<double>(arr);

        double[] right = { 1, 23, 5 };

        double[] res = matrix.KramerSolve(right);
        for(var i = 0; i < res.Length; i++)
        {
            Console.Write($"x{i}: {res[i]}\n");
        }
    }
}
 
Output
x0: 12,393939393939394
x1: -0,6637806637806638
x2: -3,3997113997114
Gauss solve

Gaussian elimination, also known as row reduction, is an algorithm in linear algebra for solving a system of linear equations. It is usually understood as a sequence of operations performed on the corresponding matrix of coefficients. This method can also be used to find the rank of a matrix, to calculate the determinant of a matrix, and to calculate the inverse of an invertible square matrix.

using System;
using MatrixDotNet;
using MatrixDotNet.Extensions.Solver;

namespace Samples.Samples
{
    public class GaussSolveSample
    {

        public static void Run()
        {
            // initialize matrix.
            Matrix<double> matrix = new double[,]
            {
                {5, 56, 7},
                {3, 6, 3},
                {5, 9, 15}
            };

            double[] right = { 1, 23, 5 };

            double[] res = matrix.GaussSolve(right);
            for(var i = 0; i < res.Length; i++)
            {
                Console.Write($"x{i}: {res[i]}\n");
            }
        }
    }
}
Output
x0: 12,393939393939394
x1: -0,6637806637806638
x2: -3,3997113997114
Conversion Matrix

Conversion of matrix consist in MatrixDotNet.Extensions.Conversion which contains static class MatrixConverter.

How change size of Matrix?

In this sample i`ll demonstrate how you can add column or row in any position of matrix and reduce them.

using System;
using MatrixDotNet;
using MatrixDotNet.Extensions;
using MatrixDotNet.Extensions.Builder;
using MatrixDotNet.Extensions.Conversion;

namespace Sample
{
    public class ConverterSample
    {
        public static void Run()
        {
            // Build matrix.
            Matrix<int> matrix = BuildMatrix.Build(3,3,
                (x, y) => x + y * y,
                new[] { 43, 23, 54 },
                new[] { 52, 12, 21 });

            Console.WriteLine("Before conversion:");
            matrix.Pretty();
            
            // Add row to matrix by index.
            Matrix<int> matrixA = matrix.AddRow(new[] { 1, 2, 3 }, 1);
            Console.WriteLine("Add row to matrix on second row index:");
            matrixA.Pretty();
            
            // Add column to matrix by index.
            Matrix<int> matrixB = matrix.AddColumn(new[] { 4, 5, 6 }, 2);
            Console.WriteLine("Add column to matrix on second column index:");
            matrixB.Pretty();
            
            // now we will reduce this new column and row.
            Matrix<int> matrixC = matrix.ReduceColumn(2);
            Matrix<int> matrixD = matrix.ReduceRow(1);
            Console.WriteLine("After reduce:");
            matrixC.Pretty();
            matrixD.Pretty();

            // Also in MatrixDotNet you can join two matrix with the same size row length.
            Matrix<int> matrixF = matrixA.Concat(matrixA);
            matrixF.Pretty();
        }
    }
}
Output
Before conversion:

Number of rows: 3
Number of columns: 3

  2747  |  187  |  484  |
  2727  |  167  |  464  |
  2758  |  198  |  495  |

Add row to matrix on second row index:

Number of rows: 4
Number of columns: 3

  2747  |  187  |  484  |
  1     |  2    |  3    |
  2727  |  167  |  464  |
  2758  |  198  |  495  |

Add column to matrix on second column index:

Number of rows: 3
Number of columns: 4

  2747  |  187  |  4  |  484  |
  2727  |  167  |  5  |  464  |
  2758  |  198  |  6  |  495  |

After reduce:

Number of rows: 3
Number of columns: 2

  2747  |  187  |
  2727  |  167  |
  2758  |  198  |


Number of rows: 2
Number of columns: 3

  2747  |  187  |  484  |
  2758  |  198  |  495  |


Number of rows: 4
Number of columns: 6

  2747  |  187  |  484  |  2747  |  187  |  484  |
  1     |  2    |  3    |  1     |  2    |  3    |
  2727  |  167  |  464  |  2727  |  167  |  464  |
  2758  |  198  |  495  |  2758  |  198  |  495  |
How to cast matrix to two-dimensional array?
using System;
using MatrixDotNet;
using MatrixDotNet.Extensions;
using MatrixDotNet.Extensions.Builder;
using MatrixDotNet.Extensions.Conversion;

namespace Sample {

    public class ConverterSample()
    {
        public static void CastRun()
        {
            // Build matrix.
            Matrix<int> matrixA = BuildMatrix.Build(3,3,
                (x, y) => x + y * y,
                new[] { 43, 23, 54 },
                new[] { 52, 12, 21 });
            
            // If you want cast Matrix to two-dimensional
            // array use method ToPrimitive.
            int[,] array = matrixA.ToPrimitive();
            
            // Converts two-dimensional array to Matrix.
            var matrixB = array.ToMatrix();
        }
    }
}

As you can see for convert matrix to two-dimensional array you can easily use method ToPrimitive.

public class StrassenSample
{
    int[,] matrix = new int[512,512];
    int[,] matrix2 = new int[512,512];

    private Matrix<int> matrix3;
    private Matrix<int> matrix4;

    [GlobalSetup]
    public void Setup()
    {
        Random random = new Random();
        Random random2 = new Random();
        for (int i = 0; i < matrix.GetLength(0); i++)
        {
            for (int j = 0; j < matrix.GetLength(1); j++)
            {
                matrix[i, j] = random.Next(1, 10);
            }
        }
        matrix3 = new Matrix<int>(matrix);

        for (int i = 0; i < matrix2.GetLength(0); i++)
        {
            for (int j = 0; j < matrix2.GetLength(1); j++)
            {
                matrix2[i, j] = random2.Next(1, 10);
            }
        }

        matrix4 = new Matrix<int>(matrix2);
    }

    [Benchmark]
    public Matrix<int> Default()
    {
        return matrix3 * matrix4;
    }

    [Benchmark]
    public Matrix<int> Strassen()
    {
        return MatrixExtension.MultiplyStrassen(matrix3, matrix4);
    }
}

BenchmarkDotNet=v0.12.1, OS=Windows 10.0.14393.3808 (1607/AnniversaryUpdate/Redstone1)
Intel Core i5-8250U CPU 1.60GHz (Kaby Lake R), 1 CPU, 8 logical and 4 physical cores
Frequency=1757816 Hz, Resolution=568.8878 ns, Timer=TSC
  [Host]     : .NET Framework 4.8 (4.8.4180.0), X86 LegacyJIT
  Job-YFITZW : .NET Framework 4.8 (4.8.4180.0), X86 LegacyJIT

IterationCount=5  LaunchCount=1  WarmupCount=5  

Method Mean Error StdDev Gen 0 Gen 1 Gen 2 Allocated
Default 69.88 s 1.241 s 0.322 s - - - 1.01 MB
Strassen 43.23 s 0.991 s 0.153 s 30000.0000 5000.0000 2000.0000 174.32 MB

As you can see algorithm Strassen multiply works significant faster(x1.625) than default multiply matrix on big size M x N.

Statistics

In section statistics yo can find any metrics such as minimum, maximum, median. relative frequencies, distribution

Also some algorithms works faster to due bit hacks which eliminate branch prediction.

Lets consider simple benchmark which measure finding minimum of matrix with bitwise operation and custom.


public class MatrixBitMinVsDefaultMin
{
    private int N = 256;
    private int[,] matrix;
    private Matrix<int> matrix3;
    private Random random = new Random();
    private int[] arr;

    [GlobalSetup]
    public void Setup()
    {
        matrix = new int[N,N];
        arr = new int[N];
        // init matrix random data
        for (int i = 0; i < N; i++)
        {
            for (int j = 0; j < N; j++)
            {
                matrix[i, j] = random.Next(-255, 255);
            }
        }
        matrix3 = new Matrix<int>(matrix);


    }

    [Benchmark]
    public void DefaultMin()
    { 
        for (int i = 0; i < N; i++)
        {
            arr[i] = matrix3.Min();   
        }
    }
    
    [Benchmark]
    public void BitMin()
    {
        for (int i = 0; i < N; i++)
        {
            arr[i] = matrix3.BitMin();   
        }
    }
}

BenchmarkDotNet=v0.12.1, OS=Windows 10.0.14393.3808 (1607/AnniversaryUpdate/Redstone1)
Intel Core i5-8250U CPU 1.60GHz (Kaby Lake R), 1 CPU, 8 logical and 4 physical cores
Frequency=1757816 Hz, Resolution=568.8878 ns, Timer=TSC
  [Host]     : .NET Framework 4.8 (4.8.4180.0), X86 LegacyJIT
  DefaultJob : .NET Framework 4.8 (4.8.4180.0), X86 LegacyJIT
Method Mean Error StdDev Code Size
DefaultMin 1,117.2 ms 12.93 ms 11.46 ms 292 B
BitMin 646.5 ms 4.16 ms 3.25 ms 165 B

As you can see BitMin() method works faster(x1.725) than DefaultMin(). Because we eliminate branch prediction. See more information about Bitwise operations in article.

See more information here

Product Compatible and additional computed target framework versions.
.NET net5.0 is compatible.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp3.0 was computed.  netcoreapp3.1 is compatible. 
.NET Standard netstandard2.1 is compatible. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on MatrixDotNet:

Package Downloads
DS.SeriesAnalysis

Package Description

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
0.0.7.3 1,370 10/15/2021
0.0.7.2 931 1/23/2021
0.0.7.1 950 12/27/2020
0.0.7 1,556 11/16/2020
0.0.6.2 972 11/2/2020
0.0.6.1 914 10/14/2020
0.0.6 897 10/14/2020
0.0.5 1,081 9/29/2020
0.0.4 1,034 8/27/2020
0.0.3.2 950 8/21/2020
0.0.3.1 1,180 8/14/2020
0.0.3 1,104 8/8/2020