/// <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 ); } } }
private GenTensor <SafeDivisionWrapper <T> > InnerGaussianEliminationSafeDivision(int n) { InitIfNotInitted(); var elemMatrix = GenTensor <SafeDivisionWrapper <T> > .CreateMatrix(n, n, (x, y) => new SafeDivisionWrapper <T>(ConstantsAndFunctions <T> .Forward(this.GetValueNoCheck(x, y))) ); for (int k = 1; k < n; k++) { for (int j = k; j < n; j++) { var m = ConstantsAndFunctions <SafeDivisionWrapper <T> > .Divide( elemMatrix.GetValueNoCheck(j, k - 1), elemMatrix.GetValueNoCheck(k - 1, k - 1) ); for (int i = 0; i < n; i++) { var curr = elemMatrix.GetValueNoCheck(j, i); elemMatrix.SetValueNoCheck(ConstantsAndFunctions <SafeDivisionWrapper <T> > .Subtract( curr, ConstantsAndFunctions <SafeDivisionWrapper <T> > .Multiply( m, elemMatrix.GetValueNoCheck(k - 1, i) ) ), j, i); } } } return(elemMatrix); }
// TODO: how to avoid code duplication? /// <summary> /// Performs simple Gaussian elimination method on a tensor /// /// O(N^3) /// </summary> public T DeterminantGaussianSimple() { #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 = Shape[0]; var elemMatrix = this.Forward(); for (int k = 1; k < n; k++) { for (int j = k; j < n; j++) { var m = ConstantsAndFunctions <T> .Divide( ConstantsAndFunctions <T> .Forward(elemMatrix.GetValueNoCheck(j, k - 1)), ConstantsAndFunctions <T> .Forward(elemMatrix.GetValueNoCheck(k - 1, k - 1)) ); for (int i = 0; i < n; i++) { var curr = ConstantsAndFunctions <T> .Forward(elemMatrix.GetValueNoCheck(j, i)); elemMatrix.SetValueNoCheck(ConstantsAndFunctions <T> .Subtract( curr, ConstantsAndFunctions <T> .Multiply( m, elemMatrix.GetValueNoCheck(k - 1, i) ) ), j, i); } } } var det = ConstantsAndFunctions <T> .CreateOne(); for (int i = 0; i < n; i++) { det = ConstantsAndFunctions <T> .Multiply(det, elemMatrix.GetValueNoCheck(i, i)); } return(det); }
public W Count() => ConstantsAndFunctions <W> .Divide(num, den);
public static GenTensor <T> PiecewiseDivide( T a, GenTensor <T> b) => CreateTensor(b.Shape, ind => ConstantsAndFunctions <T> .Divide(a, b[ind]));
public static GenTensor <T> PiecewiseDivide(GenTensor <T> a, T b) => CreateTensor(a.Shape, ind => ConstantsAndFunctions <T> .Divide(a[ind], b));