{"id":585,"date":"2012-07-07T14:15:52","date_gmt":"2012-07-07T14:15:52","guid":{"rendered":"http:\/\/gswce.net\/?p=585"},"modified":"2012-07-07T14:30:18","modified_gmt":"2012-07-07T14:30:18","slug":"matrix-inversion-in-c","status":"publish","type":"post","link":"https:\/\/gswce.net\/?p=585","title":{"rendered":"Matrix inversion in C#"},"content":{"rendered":"<p>I was talking to someone about my demos the other day, and he mentioned that he&#8217;d tried to find a simple matrix inversion routine in C# on the web, and not found one he could easily understand.  So, for what it&#8217;s worth, I thought I&#8217;d post the one I use.  It uses the System.Numerics namespace for the Complex structure for complex numbers, and a straight-forward Gaussian elimination technique with pivoting.  It returns &#8220;true&#8221; if the inversion was successful, and &#8220;false&#8221; if the matrix is singular.  Somewhat controversially, it does carry on with the inversion when the matrix is singular, but in these cases the result will normally be rubbish.<\/p>\n<p>The theory behind this technique is described in the book chapter on Gaussian Elimination, now available in the <a href=\"http:\/\/gswce.net\/?page_id=98\" title=\"Linear algebra\">Linear Algebra section of the book<\/a>.  <\/p>\n<p>Just in case anyone finds it interesting \/ useful, the code is here: <\/p>\n<pre>\r\n\/\/ The complex matrix inversion routine:\r\ninternal Boolean MyInvertMatrix(Complex[,] A, out Complex[,] invA)\r\n{\r\n    \/\/ There are faster ways to do this, but for simplicity\r\n    \/\/ and to get something working quickly, I'll just write a \r\n    \/\/ simple Gaussian-elimination matrix inverter here, and look \r\n    \/\/ at speeding things up later.\r\n\r\n    \/\/ Keep a record to see if there is a sensible inverse:\r\n    Boolean bNotIllConditioned = true;\r\n\r\n    \/\/ If the matrix is not square, there is no inverse:\r\n    if (A.GetLength(0) != A.GetLength(1))\r\n    {\r\n        invA = A; \/\/ Have to assign something to invA before returning\r\n        return false;\r\n    }\r\n\r\n    \/\/ This routine destroys the matrix it's working on, so I'll first \r\n    \/\/ make a copy of it, as well as setting up the output matrix invA \r\n    \/\/ as a unit matrix of the appropriate size:\r\n    int dimension = A.GetLength(0);\r\n    Complex[,] working = (Complex[,])A.Clone();\r\n    Complex[,] inverse = new Complex[dimension, dimension];\r\n    \/\/ C# will set the initial values to zero, so to create a unit\r\n    \/\/ matrix, I just need to fill in the diagonal elements:\r\n    for (int loop = 0; loop < dimension; loop++) inverse[loop, loop] = 1.0;\r\n\r\n    \/\/ OK, first convert working to upper triangular form:\r\n    for (int loop = 0; loop < dimension; loop++) \/\/ for each row\r\n    {\r\n        int currentRow = loop;\r\n\r\n        \/\/ First step is pivoting: make sure the biggest element\r\n        \/\/ remaining in any column is on the next row.  First, find\r\n        \/\/ the biggest element remaining in the current column:\r\n        double biggestSoFar = 0.0; int biggestRow = currentRow;\r\n        for (int x = currentRow; x < dimension; x++)\r\n        {\r\n            double sizeOfThis = working[x, currentRow].Magnitude;\r\n            if (sizeOfThis > biggestSoFar)\r\n            {\r\n                biggestSoFar = sizeOfThis;\r\n                biggestRow = x;\r\n            }\r\n        }\r\n\r\n        \/\/ and if this is not at the top, swop the rows of working\r\n        \/\/ and inverse around until it is:\r\n        if (biggestRow != currentRow)\r\n        {\r\n            Complex temp;\r\n            for (int lop = currentRow; lop < dimension; lop++)\r\n            {\r\n                temp = working[currentRow, lop];\r\n                working[currentRow, lop] = working[biggestRow, lop];\r\n                working[biggestRow, lop] = temp;\r\n            }\r\n            for (int lop = 0; lop < dimension; lop++)\r\n            {\r\n                temp = inverse[currentRow, lop];\r\n                inverse[currentRow, lop] = inverse[biggestRow, lop];\r\n                inverse[biggestRow, lop] = temp;\r\n            }\r\n        }\r\n\r\n        \/\/ Then, go down the matrix subtracting as necessary\r\n        \/\/ to get rid of the lower-triangular elements:\r\n        for (int lop = currentRow + 1; lop < dimension; lop++)\r\n        {\r\n            \/\/ Matrix might be ill-conditioned.  I should check:\r\n            if (working[currentRow, currentRow] == 0)\r\n            {\r\n                bNotIllConditioned = false;\r\n                working[currentRow, currentRow] = Globals.TINYDOUBLE;\r\n            }\r\n            Complex factor = working[lop, currentRow] \/ working[currentRow, currentRow];\r\n\r\n            \/\/ If the matrix is fairly sparse (quite common for this\r\n            \/\/ application), it might make sense to check that the \r\n            \/\/ lower elements are not already zero before doing all\r\n            \/\/ the scaling and replacing:\r\n            if (factor != 0.0)\r\n            {\r\n                \/\/ Only have to do from current row on in working, but due\r\n                \/\/ to pivoting, might have to do the entire row in inverse:\r\n                for (int lp = currentRow; lp < dimension; lp++)\r\n                    working[lop, lp] -= factor * working[currentRow, lp];\r\n                for (int lp = 0; lp < dimension; lp++)\r\n                    inverse[lop, lp] -= factor * inverse[currentRow, lp];\r\n            }\r\n        }\r\n        \/\/ That's it for this row, now on to the next one...\r\n    }\r\n\r\n    \/\/ Now with the working matrix in upper-triangular form, continue the same\r\n    \/\/ process amongst the upper-triangular elements to convert working into\r\n    \/\/ diagonal form:\r\n    for (int loop = dimension - 1; loop >= 0; loop--) \/\/ for each row\r\n    {\r\n        int currentRow = loop;\r\n\r\n        \/\/ Matrix might be ill-conditioned.  I should check:\r\n        if (working[currentRow, currentRow] == 0)\r\n        {\r\n            bNotIllConditioned = false;\r\n            working[currentRow, currentRow] = Globals.TINYDOUBLE;\r\n        }\r\n\r\n        \/\/ Then, go up the matrix subtracting as necessary to get \r\n        \/\/ rid of the remaining upper-triangular elements:\r\n        for (int lop = currentRow - 1; lop >= 0; lop--)\r\n        {\r\n            Complex factor = working[lop, currentRow] \/ working[currentRow, currentRow];\r\n\r\n            \/\/ There's only one element in working to change (the other elements\r\n            \/\/ in the row of working are all zero), and that will always be set\r\n            \/\/ to zero; but you might have to do the entire row in inverse:\r\n            working[lop, currentRow] = 0.0;\r\n\r\n            if (factor != 0.0)\r\n            {\r\n                for (int lp = 0; lp < dimension; lp++)\r\n                {\r\n                    inverse[lop, lp] -= factor * inverse[currentRow, lp];\r\n                }\r\n            }\r\n        }\r\n        \/\/ That's it for this row, now on to the next one...\r\n    }\r\n\r\n    \/\/ Should now have working as a diagonal matrix.  Final thing is \r\n    \/\/ to scale all the rows:\r\n    for (int loop = 0; loop < dimension; loop++)\r\n    {\r\n        Complex scale = working[loop, loop];\r\n        for (int lop = 0; lop < dimension; lop++) inverse[loop, lop] \/= scale;\r\n    }\r\n\r\n    \/\/ That's it.  inverse should now be the inverse of the original matrix.\r\n    invA = inverse;\r\n    return bNotIllConditioned;\r\n}\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>I was talking to someone about my demos the other day, and he mentioned that he&#8217;d tried to find a simple matrix inversion routine in C# on the web, and not found one he could easily understand. So, for what &hellip; <a href=\"https:\/\/gswce.net\/?p=585\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"_links":{"self":[{"href":"https:\/\/gswce.net\/index.php?rest_route=\/wp\/v2\/posts\/585"}],"collection":[{"href":"https:\/\/gswce.net\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/gswce.net\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/gswce.net\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/gswce.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=585"}],"version-history":[{"count":6,"href":"https:\/\/gswce.net\/index.php?rest_route=\/wp\/v2\/posts\/585\/revisions"}],"predecessor-version":[{"id":591,"href":"https:\/\/gswce.net\/index.php?rest_route=\/wp\/v2\/posts\/585\/revisions\/591"}],"wp:attachment":[{"href":"https:\/\/gswce.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=585"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/gswce.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=585"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/gswce.net\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=585"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}