public void AugmentedReducedRowEchelonFormTest() { var A = new Matrix(new double[,] { { 1, 2, 3 }, { 0, 1, 4 }, { 5, 6, 0 } }); var I = A.GetIdentity(); var aug = new AugmentedMatrix(new Matrix[] { A, I }); var augGE = aug.ReducedRowEchelonForm(); var identity = new Matrix(new double[,] { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } }); var inverse = new Matrix(new double[,] { { -24, 18, 5 }, { 20, -15, -4 }, { -5, 4, 1 } }); Assert.That(augGE[0], Is.EqualTo(identity)); Assert.That(augGE[1], Is.EqualTo(inverse)); var B = new Matrix(new double[,] { { 1, 2, 3, 6 }, { 0, 1, 4, 8 }, { 5, 6, 0, 9 }, { 9, 4, 7, 3 } }); I = new Matrix(4, 4).GetIdentity(); var aug2 = new AugmentedMatrix(new Matrix[] { B, I }); var augRref2 = aug2.ReducedRowEchelonForm(); var identity2 = new Matrix(4, 4).GetIdentity(); var inverse2 = new Matrix( new double[,] { { -69.0 / 67.0, 36.0 / 67.0, 11.0 / 67.0, 9.0 / 67.0 }, { 544.0 / 335.0, -69.0 / 67, -44.0 / 335.0, -36.0 / 335.0 }, { 206.0 / 335.0, -18.0 / 67.0, -61.0 / 335.0, 11.0 / 335.0 }, { -171.0 / 335.0, 26.0 / 67.0, 36.0 / 335.0, -1.0 / 335.0 } }); Assert.That(augRref2[0], Is.EqualTo(identity2)); Assert.That(augRref2[1], Is.EqualTo(inverse2)); }
/// <summary> /// Computes the reduced row echelon form of the matrix. /// </summary> /// <param name="matrix"></param> /// <returns></returns> public static AugmentedMatrix ReducedRowEchelonForm(this AugmentedMatrix augMatrix) { augMatrix = augMatrix.GaussianElimination(); var gaussElimResult = augMatrix[0]; int iMax = Math.Min(gaussElimResult.Columns, gaussElimResult.Rows); for (int i = 0, currentCol = 0; i < iMax && currentCol < gaussElimResult.Columns; i++, currentCol++) { var currentStartElement = gaussElimResult[i, currentCol]; if (Math.Abs(currentStartElement) > TOLERANCE) { // If the current start element does not equal 1 then fix it if (Math.Abs(currentStartElement - 1) > TOLERANCE) { augMatrix = augMatrix.MultiplyRowByScalar(i, 1.0 / currentStartElement); } for (int j = 0; j <= i - 1; j++) { var ratio = -1.0 * gaussElimResult[j, currentCol] * gaussElimResult[i, currentCol]; augMatrix = augMatrix.AddRows(i, j, ratio); } } else { i--; // The test element was zero, do not increment the row } } return(augMatrix); }
public Matrix GetInverse() { if (!this.IsSquare) { throw new ArgumentException( "Inverses only exist for square matrices. See Lipschutz, Linear Algebra. 5th ed. pg. 34. or wikipedia."); } var augmentedMatix = new AugmentedMatrix(new Matrix[] { this, this.GetIdentity() }); return(augmentedMatix.ReducedRowEchelonForm()[1]); }
/// <summary> /// Performs the elementary row operation of assing two rows. /// The <paramref name="addendRow" /> is the row which is updated. /// </summary> /// <param name="matrix"></param> /// <param name="augendRow"></param> /// <param name="addendRow"></param> /// <returns></returns> public static AugmentedMatrix AddRows( this AugmentedMatrix augMatrix, double[] augendRow, int addendRow, int matrixIndex) { for (int j = 0; j < augMatrix[matrixIndex].Columns; j++) { augMatrix[matrixIndex][addendRow, j] += augendRow[j]; } return(augMatrix); }
/// <summary> /// Performs the elementary row operation of assing two rows. /// The <paramref name="addendRow" /> is the row which is updated. /// </summary> /// <param name="matrix"></param> /// <param name="augendRow"></param> /// <param name="addendRow"></param> /// <returns></returns> public static AugmentedMatrix AddRows( this AugmentedMatrix augMatrix, int augendRow, int addendRow, double scalarMultiple = 1.0) { for (int i = 0; i < augMatrix.Count; i++) { for (int j = 0; j < augMatrix[i].Columns; j++) { augMatrix[i][addendRow, j] = augMatrix[i][addendRow, j] + (scalarMultiple * augMatrix[i][augendRow, j]); } } return(augMatrix); }
public static AugmentedMatrix MultiplyRowByScalar( this AugmentedMatrix augMatrix, int row, double scalar, int startColumn = 0) { for (int i = 0; i < augMatrix.Count; i++) { // TODO: This method should not modify the original augMatrix for (int j = startColumn; j < augMatrix[i].Columns; j++) { augMatrix[i][row, j] = scalar * augMatrix[i][row, j]; } } return(augMatrix); }
public static AugmentedMatrix SwapRows(this AugmentedMatrix augMatrix, int row1, int row2) { var identity = augMatrix[0].GetIdentity(); identity[row1, row1] = 0; identity[row1, row2] = 1; identity[row2, row2] = 0; identity[row2, row1] = 1; for (int i = 0; i < augMatrix.Count; i++) { augMatrix[i] = identity * augMatrix[i]; } return(augMatrix); }
/// <summary> /// Performs gaussian elimination on the given matrix. /// </summary> /// <param name="matrix"></param> /// <returns></returns> public static AugmentedMatrix GaussianElimination(this AugmentedMatrix augMatrix) { // Derived from ref [1] Theorem 3.5 // identify the row with the first non zero element int nonZeroRowIndex = 0; bool run = true; int nonZeroColumnIndex = 0; while (run && nonZeroColumnIndex < augMatrix[0].Columns) { // Check if columns has non-zero entry var col = augMatrix[0].GetColumn(nonZeroColumnIndex); for (int j = 0; j < col.Length; j++) { if (Math.Abs(col[j]) > TOLERANCE) { nonZeroRowIndex = j; run = false; break; } } if (run) { nonZeroColumnIndex++; } } // Move this row into the top position if (nonZeroRowIndex != 0) { augMatrix = augMatrix.SwapRows(nonZeroRowIndex, 0); } // If the first non zero row does not equal 1 then normalize the if (Math.Abs(augMatrix[0][0, nonZeroColumnIndex] - 1.0) > TOLERANCE) { augMatrix = augMatrix.MultiplyRowByScalar(0, 1.0 / augMatrix[0][0, nonZeroColumnIndex]); } int iMax = Math.Min(augMatrix[0].Columns, augMatrix[0].Rows); // Zero-wise columns for (int i = 0, currentCol = 0; i < iMax && currentCol < augMatrix[0].Columns; i++, currentCol++) { var currentStartElement = augMatrix[0][i, currentCol]; if (Math.Abs(currentStartElement) > TOLERANCE) { for (int j = i + 1; j < iMax; j++) { var ratio = -1.0 * (augMatrix[0][j, currentCol] / currentStartElement); augMatrix = augMatrix.AddRows(i, j, ratio); } } else { i--; // The test element was zero, do not increment the row } } return(augMatrix); }