Пример #1
0
        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);
        }
Пример #2
0
        internal T DeterminantLaplace(int diagLength)
        {
            if (diagLength == 1)
            {
                return(ConstantsAndFunctions <T> .Forward(this.GetValueNoCheck(0, 0)));
            }
            var det = ConstantsAndFunctions <T> .CreateZero();

            var sign = ConstantsAndFunctions <T> .CreateOne();

            var temp = SquareMatrixFactory <T> .GetMatrix(diagLength);

            for (int i = 0; i < diagLength; i++)
            {
                GetCofactor(this, temp, 0, i, diagLength);
                det = ConstantsAndFunctions <T> .Add(det,
                                                     ConstantsAndFunctions <T> .Multiply(
                                                         sign,
                                                         ConstantsAndFunctions <T> .Multiply(
                                                             this.GetValueNoCheck(0, i),
                                                             temp.DeterminantLaplace(diagLength - 1)
                                                             ))
                                                     );

                sign = ConstantsAndFunctions <T> .Negate(sign);
            }
            return(det);
        }
Пример #3
0
        /// <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
                        );
                }
            }
        }
Пример #4
0
 internal void Assign(GenTensor <T> genTensor)
 {
     foreach (var(index, value) in genTensor.Iterate())
     {
         this.SetValueNoCheck(ConstantsAndFunctions <T> .Forward(value), index);
     }
 }
Пример #5
0
        /// <summary>
        /// Finds a perpendicular vector to two given
        /// TODO: So far only implemented for 3D vectors
        /// </summary>
        public static GenTensor <T> VectorCrossProduct(GenTensor <T> a,
                                                       GenTensor <T> b)
        {
            #if ALLOW_EXCEPTIONS
            if (!a.IsVector || !b.IsVector)
            {
                throw new InvalidShapeException($"Both {nameof(a)} and {nameof(b)} should be vectors");
            }
            if (a.Shape[0] != b.Shape[0])
            {
                throw new InvalidShapeException($"Length of {nameof(a)} and {nameof(b)} should be equal");
            }
            if (a.Shape[0] != 3)
            {
                throw new NotImplementedException("Other than vectors of the length of 3 aren't supported for VectorCrossProduct yet");
            }
            #endif
            return(GenTensor <T> .CreateVector(
                       ConstantsAndFunctions <T> .Subtract(
                           ConstantsAndFunctions <T> .Multiply(a[1], b[2]),
                           ConstantsAndFunctions <T> .Multiply(a[2], b[1])),

                       ConstantsAndFunctions <T> .Subtract(
                           ConstantsAndFunctions <T> .Multiply(a[2], b[0]),
                           ConstantsAndFunctions <T> .Multiply(a[0], b[2])),

                       ConstantsAndFunctions <T> .Subtract(
                           ConstantsAndFunctions <T> .Multiply(a[0], b[1]),
                           ConstantsAndFunctions <T> .Multiply(a[1], b[0]))
                       ));
        }
Пример #6
0
        /// <summary>
        /// Finds matrix multiplication result
        /// a and b are matrices
        /// a.Shape[1] should be equal to b.Shape[0]
        /// the resulting matrix is [a.Shape[0] x b.Shape[1]] shape
        ///
        /// O(N^3)
        /// </summary>
        public static GenTensor <T> MatrixMultiply(GenTensor <T> a,
                                                   GenTensor <T> b)
        {
            #if ALLOW_EXCEPTIONS
            if (!a.IsMatrix || !b.IsMatrix)
            {
                throw new InvalidShapeException($"Both {nameof(a)} and {nameof(b)} should be matrices");
            }
            if (a.Shape[1] != b.Shape[0])
            {
                throw new InvalidShapeException($"{nameof(a)}'s height must be equal to {nameof(b)}'s width");
            }
            #endif

            var width  = a.Shape[0];
            var height = b.Shape[1];
            var row    = a.Shape[1];
            var res    = CreateMatrix(width, height);
            for (int x = 0; x < width; x++)
            {
                for (int y = 0; y < height; y++)
                {
                    var s = ConstantsAndFunctions <T> .CreateZero();

                    for (int i = 0; i < row; i++)
                    {
                        var v1 = a.GetValueNoCheck(x, i);
                        var v2 = b.GetValueNoCheck(i, y);
                        s = ConstantsAndFunctions <T> .Add(s, ConstantsAndFunctions <T> .Multiply(v1, v2));
                    }
                    res.SetValueNoCheck(s, x, y);
                }
            }
            return(res);
        }
Пример #7
0
        /// <summary>
        /// You might need it to make sure you don't copy
        /// your data but recreate a wrapper (if have one)
        ///
        /// O(V)
        /// </summary>
        public GenTensor <T> Forward()
        {
            var res = new GenTensor <T>(Shape);

            foreach (var index in res.IterateOverElements())
            {
                res.SetValueNoCheck(ConstantsAndFunctions <T> .Forward(GetValueNoCheck(index)), index);
            }
            return(res);
        }
Пример #8
0
        /// <summary>
        /// [i, j, k...]th element of the resulting tensor is
        /// operation(a[i, j, k...], b[i, j, k...])
        /// </summary>
        public static GenTensor <T> Zip(GenTensor <T> a,
                                        GenTensor <T> b, Func <T, T, T> operation)
        {
            #if ALLOW_EXCEPTIONS
            if (a.Shape != b.Shape)
            {
                throw new InvalidShapeException("Arguments should be of the same shape");
            }
            #endif
            var res = new GenTensor <T>(a.Shape);

            if (res.Shape.shape.Length == 1)
            {
                for (int x = 0; x < res.Shape.shape[0]; x++)
                {
                    res.Data[x] = ConstantsAndFunctions <T> .Forward(
                        operation(a.GetValueNoCheck(x), b.GetValueNoCheck(x)));
                }
            }
            else if (res.Shape.shape.Length == 2)
            {
                for (int x = 0; x < res.Shape.shape[0]; x++)
                {
                    for (int y = 0; y < res.Shape.shape[1]; y++)
                    {
                        res.Data[x * res.Blocks[0] + y] = ConstantsAndFunctions <T> .Forward(
                            operation(a.GetValueNoCheck(x, y), b.GetValueNoCheck(x, y)));
                    }
                }
            }
            else if (res.Shape.shape.Length == 3)
            {
                for (int x = 0; x < res.Shape.shape[0]; x++)
                {
                    for (int y = 0; y < res.Shape.shape[1]; y++)
                    {
                        for (int z = 0; z < res.Shape.shape[2]; z++)
                        {
                            res.Data[x * res.Blocks[0] + y * res.Blocks[1] + z] = ConstantsAndFunctions <T> .Forward(
                                operation(a.GetValueNoCheck(x, y, z), b.GetValueNoCheck(x, y, z)));
                        }
                    }
                }
            }
            else
            {
                foreach (var index in res.IterateOverElements())
                {
                    res.SetValueNoCheck(ConstantsAndFunctions <T> .Forward(
                                            operation(a.GetValueNoCheck(index), b.GetValueNoCheck(index))), index);
                }
            }
            return(res);
        }
Пример #9
0
        // 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);
        }
Пример #10
0
 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);
 }
Пример #11
0
        /// <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);
        }
Пример #12
0
        private static void InitIfNotInitted()
        {
            if (isFracInitted)
            {
                return;
            }
            isFracInitted = true;

            ConstantsAndFunctions <SafeDivisionWrapper <T> > .Add =
                (a, b) =>
                new SafeDivisionWrapper <T>(
                    ConstantsAndFunctions <T> .Add(
                        ConstantsAndFunctions <T> .Multiply(a.num, b.den),
                        ConstantsAndFunctions <T> .Multiply(a.den, b.num)
                        ),
                    ConstantsAndFunctions <T> .Multiply(a.den, b.den)
                    );

            ConstantsAndFunctions <SafeDivisionWrapper <T> > .Subtract =
                (a, b) =>
                new SafeDivisionWrapper <T>(
                    ConstantsAndFunctions <T> .Subtract(
                        ConstantsAndFunctions <T> .Multiply(a.num, b.den),
                        ConstantsAndFunctions <T> .Multiply(a.den, b.num)
                        ),
                    ConstantsAndFunctions <T> .Multiply(a.den, b.den)
                    );

            ConstantsAndFunctions <SafeDivisionWrapper <T> > .Multiply =
                (a, b) =>
                new SafeDivisionWrapper <T>(
                    ConstantsAndFunctions <T> .Multiply(a.num, b.num),
                    ConstantsAndFunctions <T> .Multiply(a.den, b.den)
                    );

            ConstantsAndFunctions <SafeDivisionWrapper <T> > .Divide =
                (a, b) =>
                new SafeDivisionWrapper <T>(
                    ConstantsAndFunctions <T> .Multiply(a.num, b.den),
                    ConstantsAndFunctions <T> .Multiply(a.den, b.num)
                    );

            ConstantsAndFunctions <SafeDivisionWrapper <T> > .CreateOne = () =>
                                                                          new SafeDivisionWrapper <T>(ConstantsAndFunctions <T> .CreateOne());
        }
Пример #13
0
        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);
            }
        }
Пример #14
0
        /// <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);
        }
Пример #15
0
        /// <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);
        }
Пример #16
0
        /// <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);
        }
Пример #17
0
        /// <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());
        }
Пример #18
0
 public static GenTensor <T> PiecewiseDivide(
     T a, GenTensor <T> b)
 => CreateTensor(b.Shape, ind =>
                 ConstantsAndFunctions <T> .Divide(a, b[ind]));
Пример #19
0
 public SafeDivisionWrapper(W val)
 {
     num = val;
     den = ConstantsAndFunctions <W> .CreateOne();
 }
Пример #20
0
 public static GenTensor <T> PiecewiseSubtract(GenTensor <T> a,
                                               T b)
 => CreateTensor(a.Shape, ind =>
                 ConstantsAndFunctions <T> .Subtract(a[ind], b));
Пример #21
0
 public static GenTensor <T> PiecewiseSubtract(
     T a, GenTensor <T> b)
 => CreateTensor(b.Shape, ind =>
                 ConstantsAndFunctions <T> .Subtract(a, b[ind]));
Пример #22
0
 public static GenTensor <T> PiecewiseMultiply(GenTensor <T> a,
                                               T b)
 => CreateTensor(a.Shape, ind =>
                 ConstantsAndFunctions <T> .Multiply(a[ind], b));
Пример #23
0
 public W Count() => ConstantsAndFunctions <W> .Divide(num, den);
Пример #24
0
 public static GenTensor <T> PiecewiseDivide(GenTensor <T> a,
                                             T b)
 => CreateTensor(a.Shape, ind =>
                 ConstantsAndFunctions <T> .Divide(a[ind], b));