public Matrix SolveFor(Matrix rightMatrix) { Debug.Assert(rightMatrix.RowCount == _columnCount); Debug.Assert(_columnCount == _rowCount); Matrix resultMatrix = new Matrix(_columnCount, rightMatrix.ColumnCount); LUDecompositionResults resDecomp = LUDecompose(); int[] nP = resDecomp.PivotArray; Matrix lMatrix = resDecomp.L; Matrix uMatrix = resDecomp.U; Parallel.For(0, rightMatrix.ColumnCount, k => { //Solve for the corresponding d Matrix from Ld=Pb double sum = 0.0; Matrix dMatrix = new Matrix(_rowCount, 1); dMatrix[0, 0] = rightMatrix[nP[0], k] / lMatrix[0, 0]; for (int i = 1; i < _rowCount; i++) { sum = 0.0; for (int j = 0; j < i; j++) { sum += lMatrix[i, j] * dMatrix[j, 0]; } dMatrix[i, 0] = (rightMatrix[nP[i], k] - sum) / lMatrix[i, i]; } //Solve for x using Ux = d resultMatrix[_rowCount - 1, k] = dMatrix[_rowCount - 1, 0]; for (int i = _rowCount - 2; i >= 0; i--) { sum = 0.0; for (int j = i + 1; j < _rowCount; j++) { sum += uMatrix[i, j] * resultMatrix[j, k]; } resultMatrix[i, k] = dMatrix[i, 0] - sum; } } ); return(resultMatrix); }
private LUDecompositionResults LUDecompose() { Debug.Assert(_columnCount == _rowCount); // Using Crout Decomp with P // // Ax = b //By definition of problem variables. // // LU = PA //By definition of L, U, and P. // // LUx = Pb //By substition for PA. // // Ux = d //By definition of d // // Ld = Pb //By subsitition for d. // //For 4x4 with P = I // [l11 0 0 0 ] [1 u12 u13 u14] [a11 a12 a13 a14] // [l21 l22 0 0 ] [0 1 u23 u24] = [a21 a22 a23 a24] // [l31 l32 l33 0 ] [0 0 1 u34] [a31 a32 a33 a34] // [l41 l42 l43 l44] [0 0 0 1 ] [a41 a42 a43 a44] LUDecompositionResults result = new LUDecompositionResults(); try { int[] pivotArray = new int[_rowCount]; //Pivot matrix. Matrix uMatrix = new Matrix(_rowCount, _columnCount); Matrix lMatrix = new Matrix(_rowCount, _columnCount); Matrix workingUMatrix = Clone(); Matrix workingLMatrix = new Matrix(_rowCount, _columnCount); Parallel.For(0, _rowCount, i => { pivotArray[i] = i; } ); //Iterate down the number of rows in the U matrix. for (int i = 0; i < _rowCount; i++) { //Do pivots first. //I want to make the matrix diagnolaly dominate. //Initialize the variables used to determine the pivot row. double maxRowRatio = double.NegativeInfinity; int maxRow = -1; int maxPosition = -1; //Check all of the rows below and including the current row //to determine which row should be pivoted to the working row position. //The pivot row will be set to the row with the maximum ratio //of the absolute value of the first column element divided by the //sum of the absolute values of the elements in that row. Parallel.For(i, _rowCount, j => { //Store the sum of the absolute values of the row elements in //dRowSum. Clear it out now because I am checking a new row. double rowSum = 0.0; //Go across the columns, add the absolute values of the elements in //that column to dRowSum. for (int k = i; k < _columnCount; k++) { rowSum += Math.Abs(workingUMatrix[pivotArray[j], k]); } //Check to see if the absolute value of the ratio of the lead //element over the sum of the absolute values of the elements is larger //that the ratio for preceding rows. If it is, then the current row //becomes the new pivot candidate. if (rowSum == 0.0) { throw new SingularMatrixException(); } double dCurrentRatio = Math.Abs(workingUMatrix[pivotArray[j], i]) / rowSum; lock (this) { if (dCurrentRatio > maxRowRatio) { maxRowRatio = Math.Abs(workingUMatrix[pivotArray[j], i] / rowSum); maxRow = pivotArray[j]; maxPosition = j; } } } ); //If the pivot candidate isn't the current row, update the //pivot array to swap the current row with the pivot row. if (maxRow != pivotArray[i]) { int hold = pivotArray[i]; pivotArray[i] = maxRow; pivotArray[maxPosition] = hold; } //Store the value of the left most element in the working U //matrix in dRowFirstElementValue. double rowFirstElementValue = workingUMatrix[pivotArray[i], i]; //Update the columns of the working row. j is the column index. Parallel.For(0, _columnCount, j => { if (j < i) { //If j<1, then the U matrix element value is 0. workingUMatrix[pivotArray[i], j] = 0.0; } else if (j == i) { //If i == j, the L matrix value is the value of the //element in the working U matrix. workingLMatrix[pivotArray[i], j] = rowFirstElementValue; //The value of the U matrix for i == j is 1 workingUMatrix[pivotArray[i], j] = 1.0; } else // j>i { //Divide each element in the current row of the U matrix by the //value of the first element in the row workingUMatrix[pivotArray[i], j] /= rowFirstElementValue; //The element value of the L matrix for j>i is 0 workingLMatrix[pivotArray[i], j] = 0.0; } } ); //For the working U matrix, subtract the ratioed active row from the rows below it. //Update the columns of the rows below the working row. k is the row index. for (int k = i + 1; k < _rowCount; k++) { //Store the value of the first element in the working row //of the U matrix. rowFirstElementValue = workingUMatrix[pivotArray[k], i]; //Go accross the columns of row k. Parallel.For(0, _columnCount, j => { if (j < i) { //If j<1, then the U matrix element value is 0. workingUMatrix[pivotArray[k], j] = 0.0; } else if (j == i) { //If i == j, the L matrix value is the value of the //element in the working U matrix. workingLMatrix[pivotArray[k], j] = rowFirstElementValue; //The element value of the L matrix for j>i is 0 workingUMatrix[pivotArray[k], j] = 0.0; } else //j>i { workingUMatrix[pivotArray[k], j] = workingUMatrix[pivotArray[k], j] - rowFirstElementValue * workingUMatrix[pivotArray[i], j]; } } ); } } Parallel.For(0, _rowCount, i => { for (int j = 0; j < _rowCount; j++) { uMatrix[i, j] = workingUMatrix[pivotArray[i], j]; lMatrix[i, j] = workingLMatrix[pivotArray[i], j]; } } ); result.U = uMatrix; result.L = lMatrix; result.PivotArray = pivotArray; } catch (AggregateException ex2) { if (ex2.InnerExceptions.Count > 0) { throw ex2.InnerExceptions[0]; } else { throw ex2; } } catch (Exception ex3) { throw ex3; } return(result); }