/// <summary> /// Does the work of matrix inversion. Assumes that this is an r by 2r matrix. /// </summary> private void GaussianElimination() { // Clear out the part below the main diagonal and scale the main diagonal to be 1. for (int r = 0; r < Rows; r++) { // If the element on the diagonal is 0, find a row below // that has a non-zero and swap them. if (_data[r, r] == (byte)0) { for (int rowBelow = r + 1; rowBelow < Rows; rowBelow++) { if (_data[rowBelow, r] != 0) { SwapRows(r, rowBelow); break; } } } // If we couldn't find one, the matrix is singular. Throw.If(_data[r, r] == 0, "Matrix is singular"); // Scale to 1. if (_data[r, r] != 1) { byte scale = GaloisField.Divide(1, _data[r, r]); for (int c = 0; c < Columns; c++) { _data[r, c] = GaloisField.Multiply(_data[r, c], scale); } } // Make everything below the 1 be a 0 by subtracting a multiple of it. // Note: subtraction and addition are both exclusive or in the Galois field. for (int rowBelow = r + 1; rowBelow < Rows; rowBelow++) { if (_data[rowBelow, r] != 0) { byte scale = _data[rowBelow, r]; for (int c = 0; c < Columns; c++) { _data[rowBelow, c] ^= GaloisField.Multiply(scale, _data[r, c]); } } } } // Now clear the part above the main diagonal. for (int d = 0; d < Rows; d++) { for (int rowAbove = 0; rowAbove < d; rowAbove++) { if (_data[rowAbove, d] != (byte)0) { byte scale = _data[rowAbove, d]; for (int c = 0; c < Columns; c++) { _data[rowAbove, c] ^= GaloisField.Multiply(scale, _data[d, c]); } } } } }