/// <summary> /// Inverts a matrix A to B so that A * B = I /// Borrowed from here: https://www.geeksforgeeks.org/adjoint-inverse-matrix/ /// /// O(N^5) /// </summary> public void InvertMatrix() { #if ALLOW_EXCEPTIONS if (!IsSquareMatrix) { throw new InvalidShapeException("this should be a square matrix"); } #endif var diagLength = Shape.shape[0]; var det = DeterminantGaussianSafeDivision(); #if ALLOW_EXCEPTIONS if (ConstantsAndFunctions <T> .IsZero(det)) { throw new InvalidDeterminantException("Cannot invert a singular matrix"); } #endif var adj = Adjoint(); for (int x = 0; x < diagLength; x++) { for (int y = 0; y < diagLength; y++) { this.SetValueNoCheck( ConstantsAndFunctions <T> .Divide( adj.GetValueNoCheck(x, y), det ), x, y ); } } }
/// <summary> /// Finds Determinant with possible overflow /// because it uses fractions for avoiding division /// /// O(N^3) /// </summary> internal T DeterminantGaussianSafeDivision(int diagLength) { InitIfNotInitted(); #if ALLOW_EXCEPTIONS if (!IsMatrix) { throw new InvalidShapeException("this should be matrix"); } if (Shape[0] != Shape[1]) { throw new InvalidShapeException("this should be square matrix"); } #endif if (Shape[0] == 1) { return(ConstantsAndFunctions <T> .Forward(this.GetValueNoCheck(0, 0))); } var n = diagLength; var elemMatrix = InnerGaussianEliminationSafeDivision(n); var det = ConstantsAndFunctions <SafeDivisionWrapper <T> > .CreateOne(); for (int i = 0; i < n; i++) { det = ConstantsAndFunctions <SafeDivisionWrapper <T> > .Multiply(det, elemMatrix.GetValueNoCheck(i, i)); } if (ConstantsAndFunctions <T> .IsZero(det.den)) { return(ConstantsAndFunctions <T> .CreateZero()); } return(det.Count()); }