using System; namespace MatrixInverse { class MatrixInverseProgram { static void Main(string[] args) { Console.WriteLine("\nBegin matrix inverse using Crout LU decomp demo \n"); double[][] m = MatrixCreate(4, 4); m[0][0] = 3.0; m[0][1] = 7.0; m[0][2] = 2.0; m[0][3] = 5.0; m[1][0] = 1.0; m[1][1] = 8.0; m[1][2] = 4.0; m[1][3] = 2.0; m[2][0] = 2.0; m[2][1] = 1.0; m[2][2] = 9.0; m[2][3] = 3.0; m[3][0] = 5.0; m[3][1] = 4.0; m[3][2] = 7.0; m[3][3] = 1.0; Console.WriteLine("Original matrix m is "); Console.WriteLine(MatrixAsString(m)); double d = MatrixDeterminant(m); if (Math.Abs(d) < 1.0e-5) Console.WriteLine("Matrix has no inverse"); double[][] inv = MatrixInverse(m); Console.WriteLine("Inverse matrix inv is "); Console.WriteLine(MatrixAsString(inv)); double[][] prod = MatrixProduct(m, inv); Console.WriteLine("The product of m * inv is "); Console.WriteLine(MatrixAsString(prod)); Console.WriteLine("========== \n"); double[][] lum; int[] perm; int toggle = MatrixDecompose(m, out lum, out perm); Console.WriteLine("The combined lower-upper decomposition of m is"); Console.WriteLine(MatrixAsString(lum)); double[][] lower = ExtractLower(lum); double[][] upper = ExtractUpper(lum); Console.WriteLine("The lower part of LUM is"); Console.WriteLine(MatrixAsString(lower)); Console.WriteLine("The upper part of LUM is"); Console.WriteLine(MatrixAsString(upper)); Console.WriteLine("The perm[] array is"); ShowVector(perm); double[][] lowTimesUp = MatrixProduct(lower, upper); Console.WriteLine("The product of lower * upper is "); Console.WriteLine(MatrixAsString(lowTimesUp)); Console.WriteLine("\nEnd matrix inverse demo \n"); Console.ReadLine(); } // Main static void ShowVector(int[] vector) { Console.Write(" "); for (int i = 0; i < vector.Length; ++i) Console.Write(vector[i] + " "); Console.WriteLine("\n"); } static double[][] MatrixInverse(double[][] matrix) { // assumes determinant is not 0 // that is, the matrix does have an inverse int n = matrix.Length; double[][] result = MatrixCreate(n, n); // make a copy of matrix for (int i = 0; i < n; ++i) for (int j = 0; j < n; ++j) result[i][j] = matrix[i][j]; double[][] lum; // combined lower & upper int[] perm; int toggle; toggle = MatrixDecompose(matrix, out lum, out perm); double[] b = new double[n]; for (int i = 0; i < n; ++i) { for (int j = 0; j < n; ++j) if (i == perm[j]) b[j] = 1.0; else b[j] = 0.0; double[] x = Helper(lum, b); // for (int j = 0; j < n; ++j) result[j][i] = x[j]; } return result; } // MatrixInverse static int MatrixDecompose(double[][] m, out double[][] lum, out int[] perm) { // Crout's LU decomposition for matrix determinant and inverse // stores combined lower & upper in lum[][] // stores row permuations into perm[] // returns +1 or -1 according to even or odd number of row permutations // lower gets dummy 1.0s on diagonal (0.0s above) // upper gets lum values on diagonal (0.0s below) int toggle = +1; // even (+1) or odd (-1) row permutatuions int n = m.Length; // make a copy of m[][] into result lu[][] lum = MatrixCreate(n, n); for (int i = 0; i < n; ++i) for (int j = 0; j < n; ++j) lum[i][j] = m[i][j]; // make perm[] perm = new int[n]; for (int i = 0; i < n; ++i) perm[i] = i; for (int j = 0; j < n - 1; ++j) // process by column. note n-1 { double max = Math.Abs(lum[j][j]); int piv = j; for (int i = j + 1; i < n; ++i) // find pivot index { double xij = Math.Abs(lum[i][j]); if (xij > max) { max = xij; piv = i; } } // i if (piv != j) { double[] tmp = lum[piv]; // swap rows j, piv lum[piv] = lum[j]; lum[j] = tmp; int t = perm[piv]; // swap perm elements perm[piv] = perm[j]; perm[j] = t; toggle = -toggle; } double xjj = lum[j][j]; if (xjj != 0.0) { for (int i = j + 1; i < n; ++i) { double xij = lum[i][j] / xjj; lum[i][j] = xij; for (int k = j + 1; k < n; ++k) lum[i][k] -= xij * lum[j][k]; } } } // j return toggle; } // MatrixDecompose static double[] Helper(double[][] luMatrix, double[] b) // helper { int n = luMatrix.Length; double[] x = new double[n]; b.CopyTo(x, 0); for (int i = 1; i < n; ++i) { double sum = x[i]; for (int j = 0; j < i; ++j) sum -= luMatrix[i][j] * x[j]; x[i] = sum; } x[n - 1] /= luMatrix[n - 1][n - 1]; for (int i = n - 2; i >= 0; --i) { double sum = x[i]; for (int j = i + 1; j < n; ++j) sum -= luMatrix[i][j] * x[j]; x[i] = sum / luMatrix[i][i]; } return x; } // Helper static double MatrixDeterminant(double[][] matrix) { double[][] lum; int[] perm; int toggle = MatrixDecompose(matrix, out lum, out perm); double result = toggle; for (int i = 0; i < lum.Length; ++i) result *= lum[i][i]; return result; } // ---------------------------------------------------------------- static double[][] MatrixCreate(int rows, int cols) { double[][] result = new double[rows][]; for (int i = 0; i < rows; ++i) result[i] = new double[cols]; return result; } static double[][] MatrixProduct(double[][] matrixA, double[][] matrixB) { int aRows = matrixA.Length; int aCols = matrixA[0].Length; int bRows = matrixB.Length; int bCols = matrixB[0].Length; if (aCols != bRows) throw new Exception("Non-conformable matrices"); double[][] result = MatrixCreate(aRows, bCols); for (int i = 0; i < aRows; ++i) // each row of A for (int j = 0; j < bCols; ++j) // each col of B for (int k = 0; k < aCols; ++k) // could use k < bRows result[i][j] += matrixA[i][k] * matrixB[k][j]; return result; } static string MatrixAsString(double[][] matrix) { string s = ""; for (int i = 0; i < matrix.Length; ++i) { for (int j = 0; j < matrix[i].Length; ++j) s += matrix[i][j].ToString("F3").PadLeft(8) + " "; s += Environment.NewLine; } return s; } static double[][] ExtractLower(double[][] lum) { // lower part of an LU Doolittle decomposition (dummy 1.0s on diagonal, 0.0s above) int n = lum.Length; double[][] result = MatrixCreate(n, n); for (int i = 0; i < n; ++i) { for (int j = 0; j < n; ++j) { if (i == j) result[i][j] = 1.0; else if (i > j) result[i][j] = lum[i][j]; } } return result; } static double[][] ExtractUpper(double[][] lum) { // upper part of an LU (lu values on diagional and above, 0.0s below) int n = lum.Length; double[][] result = MatrixCreate(n, n); for (int i = 0; i < n; ++i) { for (int j = 0; j < n; ++j) { if (i <= j) result[i][j] = lum[i][j]; } } return result; } // ---------------------------------------------------------------- } // Program } // ns