public GenTensor <T> GaussianEliminationSafeDivision() { #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 var wrp = InnerGaussianEliminationSafeDivision(Shape[0]); return(GenTensor <T> .CreateMatrix(Shape[0], Shape[1], (x, y) => wrp.GetValueNoCheck(x, y).Count())); }
public bool Equals(GenTensor <T> obj) { if (obj.Shape != Shape) { return(false); } foreach (var(index, _) in obj.Iterate()) { if (!ConstantsAndFunctions <T> .AreEqual(this.GetValueNoCheck(index), obj.GetValueNoCheck(index))) { return(false); } } return(true); }
/// <summary> /// Creates an indentity matrix whose width and height are equal to diag /// 1 is achieved with TWrapper.SetOne() /// 0 is achieved with TWrapper.SetZero() /// </summary> public static GenTensor <T> CreateIdentityMatrix(int diag) { var res = new GenTensor <T>(diag, diag); for (int i = 0; i < res.Data.Length; i++) { res.Data[i] = ConstantsAndFunctions <T> .CreateZero(); } for (int i = 0; i < diag; i++) { res.SetValueNoCheck(ConstantsAndFunctions <T> .CreateOne, i, i); } return(res); }
/// <summary> /// A / B /// Finds such C = A / B that A = C * B /// /// O(N^5) /// </summary> public static GenTensor <T> MatrixDivide(GenTensor <T> a, GenTensor <T> b) { #if ALLOW_EXCEPTIONS if (!a.IsSquareMatrix || !b.IsSquareMatrix) { throw new InvalidShapeException("Both should be square matrices"); } if (a.Shape != b.Shape) { throw new InvalidShapeException("Given matrices should be of the same shape"); } #endif var fwd = b.Forward(); fwd.InvertMatrix(); return(MatrixMultiply(a, fwd)); }
/// <summary> /// Get a subtensor of a tensor /// If you have a t = Tensor[2 x 3 x 4], /// t.GetSubtensor(0) will return the proper matrix [3 x 4] /// /// O(1) /// </summary> public GenTensor <T, TWrapper> GetSubtensor(int index) { #if ALLOW_EXCEPTIONS ReactIfBadBound(index, 0); #endif var newLinIndexDelta = GetFlattenedIndexSilent(index); var newBlocks = blocks.ToList(); var rootAxis = 0; newBlocks.RemoveAt(rootAxis); var newShape = Shape.CutOffset1(); var result = new GenTensor <T, TWrapper>(newShape, newBlocks.ToArray(), data) { LinOffset = newLinIndexDelta }; return(result); }
/// <summary> /// Applies scalar product to every vector in a tensor so that /// you will get a one-reduced dimensional tensor /// (e. g. TensorVectorDotProduct([4 x 3 x 2], [4 x 3 x 2]) -> [4 x 3] /// /// O(V) /// </summary> public static GenTensor <T> TensorVectorDotProduct(GenTensor <T> a, GenTensor <T> b) { #if ALLOW_EXCEPTIONS if (a.Shape.SubShape(0, 1) != b.Shape.SubShape(0, 1)) { throw new InvalidShapeException("Other dimensions of tensors should be equal"); } #endif var resTensor = new GenTensor <T>(a.Shape.SubShape(0, 1)); foreach (var index in resTensor.IterateOverElements()) { var scal = VectorDotProduct(a.GetSubtensor(index), b.GetSubtensor(index)); resTensor.SetValueNoCheck(scal, index); } return(resTensor); }
/// <summary> /// Creates a tensor whose all matrices are identity matrices /// 1 is achieved with TWrapper.SetOne() /// 0 is achieved with TWrapper.SetZero() /// </summary> public static GenTensor <T> CreateIdentityTensor(int[] dimensions, int finalMatrixDiag) { var newDims = new int[dimensions.Length + 2]; for (int i = 0; i < dimensions.Length; i++) { newDims[i] = dimensions[i]; } newDims[newDims.Length - 2] = newDims[newDims.Length - 1] = finalMatrixDiag; var res = new GenTensor <T>(newDims); foreach (var index in res.IterateOverMatrices()) { var iden = CreateIdentityMatrix(finalMatrixDiag); res.SetSubtensor(iden, index); } return(res); }
/// <summary> /// Slice with data sharing like in python /// A[3:5] in python /// same as /// A.Slice(3, 5) in GT /// /// O(N) /// </summary> // TODO: Make it O(1) public GenTensor <T, TWrapper> Slice(int leftIncluding, int rightExcluding) { #if ALLOW_EXCEPTIONS ReactIfBadBound(leftIncluding, 0); ReactIfBadBound(rightExcluding - 1, 0); if (leftIncluding >= rightExcluding) { throw new InvalidShapeException("Slicing cannot be performed"); } #endif var newLength = rightExcluding - leftIncluding; var toStack = new GenTensor <T, TWrapper> [newLength]; for (int i = 0; i < newLength; i++) { toStack[i] = GetSubtensor(i + leftIncluding); } return(Stack(toStack)); }
public static GenTensor <T> Concat(GenTensor <T> a, GenTensor <T> b) { #if ALLOW_EXCEPTIONS if (a.Shape.SubShape(1, 0) != b.Shape.SubShape(1, 0)) { throw new InvalidShapeException("Excluding the first dimension, all others should match"); } #endif if (a.IsVector) { var resultingVector = GenTensor <T> .CreateVector(a.Shape.shape[0] + b.Shape.shape[0]); for (int i = 0; i < a.Shape.shape[0]; i++) { resultingVector.SetValueNoCheck(ConstantsAndFunctions <T> .Forward(a.GetValueNoCheck(i)), i); } for (int i = 0; i < b.Shape.shape[0]; i++) { resultingVector.SetValueNoCheck(ConstantsAndFunctions <T> .Forward(b.GetValueNoCheck(i)), i + a.Shape.shape[0]); } return(resultingVector); } else { var newShape = a.Shape.Copy(); newShape.shape[0] = a.Shape.shape[0] + b.Shape.shape[0]; var res = new GenTensor <T>(newShape); for (int i = 0; i < a.Shape.shape[0]; i++) { res.SetSubtensor(a.GetSubtensor(i), i); } for (int i = 0; i < b.Shape.shape[0]; i++) { res.SetSubtensor(b.GetSubtensor(i), i + a.Shape.shape[0]); } return(res); } }
/// <summary> /// Calls VectorCrossProduct for every vector in the tensor /// </summary> public static GenTensor <T> TensorVectorCrossProduct(GenTensor <T> a, GenTensor <T> b) { #if ALLOW_EXCEPTIONS if (a.Shape != b.Shape) { throw new InvalidShapeException($"Pre-shapes of {nameof(a)} and {nameof(b)} should be equal"); } #endif var res = new GenTensor <T>(a.Shape); foreach (var index in a.IterateOverVectors()) { res.SetSubtensor( VectorCrossProduct(a.GetSubtensor(index), b.GetSubtensor(index)), index ); } return(res); }
/// <summary> /// Copies a tensor calling each cell with a .Copy() /// /// O(V) /// </summary> public GenTensor <T> Copy(bool copyElements) { var res = new GenTensor <T>(Shape); if (!copyElements) { foreach (var index in res.IterateOverElements()) { res.SetValueNoCheck(ConstantsAndFunctions <T> .Forward(GetValueNoCheck(index)), index); } } else { foreach (var index in res.IterateOverElements()) { res.SetValueNoCheck(ConstantsAndFunctions <T> .Copy(GetValueNoCheck(index)), index); } } return(res); }
/// <summary> /// Returns adjugate matrix /// /// O(N^5) /// </summary> public GenTensor <T> Adjoint() { #if ALLOW_EXCEPTIONS if (!IsSquareMatrix) { throw new InvalidShapeException("Matrix should be square"); } #endif var diagLength = Shape.shape[0]; var res = GenTensor <T> .CreateSquareMatrix(diagLength); var temp = SquareMatrixFactory <T> .GetMatrix(diagLength); if (diagLength == 1) { res.SetValueNoCheck(ConstantsAndFunctions <T> .CreateOne(), 0, 0); return(res); } var toNegate = false; for (int x = 0; x < diagLength; x++) { for (int y = 0; y < diagLength; y++) { GetCofactor(this, temp, x, y, diagLength); toNegate = (x + y) % 2 == 1; var det = temp.DeterminantGaussianSafeDivision(diagLength - 1); if (toNegate) { res.SetValueNoCheck(ConstantsAndFunctions <T> .Negate(det), y, x); } else { res.SetValueNoCheck(det, y, x); } } } return(res); }
private static void GetCofactor(GenTensor <T> a, GenTensor <T> temp, int rowId, int colId, int diagLength) { int i = 0, j = 0; for (int row = 0; row < diagLength; row++) { for (int col = 0; col < diagLength; col++) { if (row != rowId && col != colId) { temp.SetValueNoCheck(a.GetValueNoCheck(row, col), i, j++); if (j == diagLength - 1) { j = 0; i++; } } } } }
/// <summary> /// Finds the scalar product of two vectors /// /// O(N) /// </summary> public static T VectorDotProduct(GenTensor <T> a, GenTensor <T> b) { #if ALLOW_EXCEPTIONS if (!a.IsVector || !b.IsVector) { throw new InvalidShapeException($"{nameof(a)} and {nameof(b)} should be vectors"); } if (a.Shape[0] != b.Shape[0]) { throw new InvalidShapeException($"{nameof(a)}'s length should be the same as {nameof(b)}'s"); } #endif var res = ConstantsAndFunctions <T> .CreateZero(); for (int i = 0; i < a.Shape[0]; i++) { res = ConstantsAndFunctions <T> .Add(res, ConstantsAndFunctions <T> .Multiply(a.GetValueNoCheck(i), b.GetValueNoCheck(i))); } return(res); }
public static GenTensor <T> TensorMatrixDivide(GenTensor <T> a, GenTensor <T> b) { #if ALLOW_EXCEPTIONS InvalidShapeException.NeedTensorSquareMatrix(a); InvalidShapeException.NeedTensorSquareMatrix(b); if (a.Shape != b.Shape) { throw new InvalidShapeException("Should be of the same shape"); } #endif var res = new GenTensor <T>(a.Shape); foreach (var ind in res.IterateOverMatrices()) { res.SetSubtensor( MatrixDivide( a.GetSubtensor(ind), b.GetSubtensor(ind) ), ind); } return(res); }
/// <summary> /// Get a subtensor of a tensor /// If you have a t = Tensor[2 x 3 x 4], /// t.GetSubtensor(0) will return the proper matrix [3 x 4] /// /// O(1) /// </summary> public GenTensor <T> GetSubtensor(int index) { #if ALLOW_EXCEPTIONS ReactIfBadBound(index, 0); #endif var newLinIndexDelta = GetFlattenedIndexSilent(index); var newBlocks = Blocks.ToList(); var rootAxis = AxesOrder[0]; newBlocks.RemoveAt(rootAxis); var newAxesOrder = AxesOrder.ToList(); for (int i = 0; i < newAxesOrder.Count; i++) { if (newAxesOrder[i] > rootAxis) { newAxesOrder[i] -= 1; } } newAxesOrder.RemoveAt(0); var newShape = Shape.CutOffset1(); var result = new GenTensor <T>(newShape, newBlocks.ToArray(), newAxesOrder.ToArray(), Data); result.LinOffset = newLinIndexDelta; return(result); }
public static GenTensor <T> PiecewiseSubtract( T a, GenTensor <T> b) => CreateTensor(b.Shape, ind => ConstantsAndFunctions <T> .Subtract(a, b[ind]));
public static GenTensor <T, TWrapper> Concat(GenTensor <T, TWrapper> a, GenTensor <T, TWrapper> b) => Composition <T, TWrapper> .Concat(a, b);
public static GenTensor <T> PiecewiseSubtract(GenTensor <T> a, GenTensor <T> b) => Zip(a, b, ConstantsAndFunctions <T> .Subtract);
public static GenTensor <T> PiecewiseAdd(GenTensor <T> a, GenTensor <T> b) => Zip(a, b, ConstantsAndFunctions <T> .Add);
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));
public static GenTensor <T> PiecewiseSubtract(GenTensor <T> a, T b) => CreateTensor(a.Shape, ind => ConstantsAndFunctions <T> .Subtract(a[ind], b));
public static GenTensor <T> PiecewiseDivide(GenTensor <T> a, GenTensor <T> b) => Zip(a, b, ConstantsAndFunctions <T> .Divide);
public static GenTensor <T> PiecewiseMultiply(GenTensor <T> a, GenTensor <T> b) => Zip(a, b, ConstantsAndFunctions <T> .Multiply);
public static GenTensor <T> PiecewiseMultiply(GenTensor <T> a, T b) => CreateTensor(a.Shape, ind => ConstantsAndFunctions <T> .Multiply(a[ind], b));
/// <summary> /// Creates a vector from an array of primitives /// Its length will be equal to elements.Length /// </summary> public static GenTensor <T> CreateVector(int length) { var res = new GenTensor <T>(length); return(res); }