Click here to Skip to main content
15,867,568 members
Articles / Programming Languages / C#

MaNet: A matrix library for .NET (Rational Computing 2)

Rate me:
Please Sign up or sign in to vote.
4.90/5 (32 votes)
8 Jul 2010CPOL7 min read 55.7K   3.1K   74   18
A translation of the Java matrix library JAMA with LU, QR, Eigenvalue, and Cholesky decompositions.

Introduction

This article presents a reasonably full featured linear algebra library for .NET. It is a translation of the Java matrix package JAMA. All of the matrix operations were successfully translated, but the IO methods had too much of a Java flavor and so were replaced. The library provides the standard linear algebra features one would expect, such as multiplying and inverting matrices. The following decompositions are also provided:

  • Cholesky Decomposition of symmetric, positive definite matrices
  • LU Decomposition (Gaussian elimination) of rectangular matrices
  • QR Decomposition of rectangular matrices
  • Eigenvalue Decomposition of both symmetric and non-symmetric square matrices

This should be sufficient for many of one's matrix needs. There was also some Java testing code, but while it may have been sufficient for the original creators, it was not enough for a translator lacking intimate knowledge of why certain choices were made. The unit tests used on this project are included, and are at 97% code coverage, so you can have reasonable confidence in this software. I have purposely decided to limit the amount of code shown in this article. My goal is to allow you to use some of the power inherent in linear algebra as a black box. I want you to be able to just use the fact that you can solve systems of equations (not so hard) or perform least squares (a bit harder) or find Eigenvalues or singular values (really hard) without needing to understand the intricate mathematical details.

Background

I strongly advise going to Stanford Engineering Everywhere and watching the first lecture on linear dynamical systems. Unlike the lectures further on, this one does not require significant mathematical understanding to appreciate. Dr. Boyd does a brilliant job of illustrating the immense power that linear algebra can bring to your applications. If you are more mathematically inclined, the entire course is certainly worth watching, and it was also one of the major motivators for my translating JAMA and writing this article.

This is certainly not the only .NET linear algebra software on the web.

  • infer.net: A very interesting project from Microsoft in the UK.
  • A list of numerical libraries is available on Wikipedia. This includes both free and commercial libraries.
  • DotNumerics: This is a translation of LAPACK from Fortran.
  • DotNetMatrix: A previous translation of JAMA that I just recently found out about and you might like.

Roadmap

This is the second article in a series on computing with Rational numbers. This may seem a bit odd as this project does not use Rational numbers, but I felt it better to separate things. The next article will then be able to focus on Rational matrices and their performance characteristics.

As can be seen, there is a lot of work to do, enough to dominate my free time for quite a while. If anyone is inspired, I would be delighted to work with them on the advancement of rational computing on the .NET platform.

Caveats

This code has been sitting on my computer for over a year, and only now is it finally being released. You could reasonably wonder why what appears to be such a useful library was kept under wraps for so long after completion. There are two main reasons. The first is that this is a translation and so not fully original to me. It should be noted that linear algebra packages are, in general, not created from scratch. Pretty much everything is an outgrowth of some earlier Fortran routines such as LAPACK. On account of this, I have preserved the vast majority of the original comments, so one may see references to Java here and there. I would also note that though I deserve some credit for the effort I put into the translation and unit tests, much greater credit should be awarded to the original creators: Ronald F. Boisvert, Joe Hicklin, Bruce Miller, Cleve Moler, Roldan Pozo, Karin Remington, and Peter Webb.

My second concern is more serious. Some of the code in this library is very hard to understand. In particular, I speak of the EigenvalueDecomposition and SingularValueDecomposition constructors. To be honest, I do not understand those two massive routines. Since I believe that one should understand the code one presents, this is a bit of a quandary. However, solving this problem is one of the main problems unit testing was meant to solve. With sufficient unit tests, you can modify code that you do not understand and still have a reasonable expectation that if the tests pass, you will have working code.

Sample usage

Linear algebra is extremely useful. Solving systems of linear equations is a basic task that a linear algebra library ought to perform. Here is an example from the unit tests:

C#
// For equations
// 2x  +  y + z  = 5
// 4x  - 6y      = 2
//-2x  + 7y + 2  = 9
// with solution x = 1, y = 1, z = 2

String strMat = @"2  1  1
                  4 -6  0
                 -2  7  2";

String strVals = @"5
                  -2
                   9";

String strExpectedSoln = @"1
                           1
                           2";

Matrix mat = Matrix.Parse(strMat);
Matrix vals = Matrix.Parse(strVals);

Matrix expectedSoln = Matrix.Parse(strExpectedSoln);

Matrix soln = mat.Solve(vals);
//Checks that solution solves matrix equation. 
//Note that I can do this even if I don't know the solution.
Assert.That(mat.Times(soln), Is.EqualTo(vals)); 

//Check against expected solution
Assert.That (soln ,Is.EqualTo(expectedSoln));

This is pretty easy to do. You might notice that almost the entirety of the work involved is in setting up the input in a human readable format. This type of situation where we have the same number of unknowns and equations does come up; however, a much more interesting situation occurs when the number of equations exceeds the number of variables. In these types of problems, you try to find the best approximation to a solution given your equations. This can easily occur when the equations are based on error prone measurements. These problems are referred to as "least squares" problems, and you can do a remarkable amount of mathematical modeling with this technique.

C#
// For equations
// a +  b =  6
// a + 2b =  5
// a + 3b =  7
// a + 4b = 10
// with leastsqure approximate solution a=3.5 , b=1.4

String strMat = @"1  1  
                  1  2   
                  1  3  
                  1  4";

String strVals = @"6
                   5
                   7
                  10";

String strExpectedSoln = @"3.5
                           1.4";


Matrix mat = Matrix.Parse(strMat);
Matrix vals = Matrix.Parse(strVals);

Matrix expectedSoln = Matrix.Parse(strExpectedSoln);


Matrix soln = mat.Solve(vals);

//Check against expected solution
Assert.That(soln, Is.EqualTo(expectedSoln).Within(.001));

It is no harder from a programming standpoint to solve a least squares problem than it is to solve a more matched set of linear equations. Though there are many potential uses for this library, I will assume that you want to either solve linear systems of equations or calculate least squares approximate solutions. If we have two matrices A and B such that Ax=B, they can be solved or least square solved by the following:

C#
Matrix solution = A.Solve(B);

The majority of the work is involved in creating the matrices. Note that numerous IO samples can be found in the Matrix_IOTests unit test file.

Making matrices

There are three main methods for the creation of matrices. You can create a matrix of zeros and then set the values.

C#
Matrix A = new Matrix(3,2); //Creates matrix of zeros with 3 rows and 2 columns
A.Set(0,1,7);  //Sets element at row 0, column 1 to 7
//or
A.Array[0,1] = 7; //Sets element at row 0, column 1 to 7

A matrix can also be created directly from a one or two dimensional array.

C#
double[] valArray = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0 };
Matrix A = new Matrix(valArray,4);// Creates matrix with 4 rows using valArray;
  
double[][] valTwoD= new double[3][] { new double[4] { 1.0, 0.0, 0.0, 0.0 }, 
                                      new double[4] { 0.0, 1.0, 0.0, 0.0 }, 
                                      new double[4] { 0.0, 0.0, 1.0, 0.0 } };
                                     
Matrix B = new Matrix(valTwoD);
//creates a new matrix  with 3 rows and 4 columns from valTwoD

There are also several ways of parsing text to create a matrix. It is assumed that there are three likely formats that matrices are likely to come in. These are strings where rows are delimited by lines, and columns by spaces, the format used by MATLAB or the format used by Mathematica.

C#
Matrix A = Matrix.Parse("1 2\n3 4"); // standard format
A = Matrix.Parse("[1 2;3 4]"); // matlab format
A = Matrix.Parse("{{1, 2}, {3, 4}}"); // mathematica format

A = Matrix.ParseMatLab("[1 2;3 4]"); 
A = Matrix.ParseMathematica("{{1, 2}, {3, 4}}]");

If your string is in another format, there is also a version with many parameters.

C#
public static Matrix Parse(string str, string matrixFrontCap, string rowFrontCap, 
       string rowDelimiter, string columnDelimiter, 
       string rowEndCap, string matrixEndCap){..}

There is also a FromDataTable and a Load that takes a file path. There is also a Generators assembly that has more specialized methods to produce Toeplitz and some other matrices.

Unit tests

This project includes a large number of unit tests. In fact, the vast majority of time spent on this project was on writing and devising unit tests. Getting high levels of code coverage on preexisting code can be astonishingly difficult. Some of the unit tests use random numbers, and will on occasionally fail. This is due to the degree of numerical precision expected of the answers. All of these tests have random in their names.

Conclusion

My hope is that this library will make it significantly easier to write software that takes advantage of the power of linear algebra. It is also another step in my exploration of computing with Rational numbers. The third article in this series, where Rational matrices appear, is coming soon. Stay tuned.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United States United States
Written software for what seems like forever. I'm currenly infatuated with WPF. Hopefully my affections are returned.

Comments and Discussions

 
Questionis EigenvalueDecomposition functionality usable/stable ? Pin
elliot litz10-Mar-15 12:04
elliot litz10-Mar-15 12:04 
QuestionGreat stuff. Question about types Pin
cjbreisch13-Mar-13 3:16
cjbreisch13-Mar-13 3:16 
QuestionHow to perform Matrix column sum. and also Row sum Pin
deghosty24-Oct-12 9:27
deghosty24-Oct-12 9:27 
QuestionNice Pin
BillW334-Sep-12 10:56
professionalBillW334-Sep-12 10:56 
GeneralMy vote of 4 Pin
Reiss15-Aug-11 1:26
professionalReiss15-Aug-11 1:26 
GeneralMy vote of 5 [modified] Pin
César de Souza24-Jul-10 10:22
professionalCésar de Souza24-Jul-10 10:22 
GeneralRe: My vote of 5 Pin
KenJohnson1-Aug-10 5:04
KenJohnson1-Aug-10 5:04 
Thank you for the comment. I applaud you on your Mathematical programming. I wish far more of it was being done. You have got me thinking about the Generalized Eigenvalue Decomposition. This is something that I probably should consider adding. If you would like to assist it would be both credited and greatly appreciated.

You should not have to wait much longer for rational matrices. I have the code working and am now on the process of working on the comparison between the double and rational matrices. Working with rational numbers is an eye opening experience. I have been conditioned over the years to accept doubles and their round off errors. Rational calculations though slow offer promise in certain areas.

Do not be discouraged in your Unit testing. I am aware how frustrating the quest for good unit tests that also have high code coverage can be. There are few things that you can do that help other developers more. You are providing a form of active documentation that makes your classes much easier to use. More importantly you are making it possible for individuals who understand your code only partially to modify it. These are both wonderful things.

ken
GeneralMy vote of 5 Pin
Yves12-Jul-10 14:18
Yves12-Jul-10 14:18 
QuestionPreviously published? Pin
riskha6-Jul-10 21:58
riskha6-Jul-10 21:58 
AnswerRe: Previously published? [modified] Pin
KenJohnson8-Jul-10 17:05
KenJohnson8-Jul-10 17:05 
GeneralYou got my 5 but Pin
MeC++5-Jul-10 5:42
MeC++5-Jul-10 5:42 
GeneralRe: You got my 5 but Pin
KenJohnson5-Jul-10 9:35
KenJohnson5-Jul-10 9:35 
GeneralRe: You got my 5 but Pin
Kevin Drzycimski7-Jul-10 21:38
Kevin Drzycimski7-Jul-10 21:38 
GeneralRe: You got my 5 but [modified] Pin
KenJohnson8-Jul-10 17:34
KenJohnson8-Jul-10 17:34 
GeneralRe: You got my 5 but Pin
Kevin Drzycimski8-Jul-10 21:12
Kevin Drzycimski8-Jul-10 21:12 
GeneralMy vote of 5 Pin
MeC++5-Jul-10 5:24
MeC++5-Jul-10 5:24 
GeneralKeep it up [modified] Pin
JohnWindy4-Jul-10 22:25
JohnWindy4-Jul-10 22:25 
GeneralThank you. Pin
shivamkalra2-Jul-10 23:46
shivamkalra2-Jul-10 23:46 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.