Example #1
0
        // ------------------- INVERSE MATRIX ---------------------------

        // TO DO: make without minor matrix copy, but with minor matrix itself. Economy of the memory.

        /// <summary>
        /// Calculates the inverse matrix using the LUP-factorization for calculating matrix determinants
        /// and algebraic supplements of its elements.
        /// It takes O(n^5) operations to run.
        ///
        /// Works only for square, non-singular matrices.
        /// If these requirements are not met, either a MatrixSizeException
        /// or a MatrixSingularityException shall be thrown.
        /// </summary>
        public Matrix <T, C> inverseMatrix_LUP_Factorization()
        {
            this.checkSquare();

            Numeric <T, C> determinant = this.Determinant_LUP_Factorization();

            if (determinant == Numeric <T, C> .Zero)
            {
                throw new MatrixSingularityException("cannot calculate the inverse matrix.");
            }

            // to do: make matrix type

            Matrix <T, C> inverse = new Matrix_SDA <T, C>(this.rows, this.columns);

            for (int i = 0; i < rows; i++)
            {
                for (int j = 0; j < columns; j++)
                {
                    Numeric <T, C> minor = this.getMinorMatrix(j, i).Determinant_LUP_Factorization();

                    if (((i + j) & 1) == 1)
                    {
                        minor = -minor;
                    }

                    inverse.setItemAt(i, j, minor / determinant);
                }
            }

            return(inverse);
        }
Example #2
0
        /// <summary>
        /// Preforms the LUP-factorization of a matrix (let it be A)
        /// in the form of:
        ///
        /// P*A = L*U.
        ///
        /// The P is an identity matrix with a plenty of row inversions.
        /// For the economy of space it is provided as a single-dimensional array of integers:
        ///
        /// (0, 1, 2, 3, ..., n).
        ///
        /// Element indices of this array stand for matrix rows, and elements value
        /// mean the position of '1' in a row.
        ///
        /// Requirements: works for any square and nonsingular matrix (having a non-zero determinant).
        /// If these requirements aren't met, either MatrixSingularException of MatrixSizeException
        /// would be thrown.
        /// </summary>
        /// <param name="L">The lower-triangular matrix with '1' on the main diagonal.</param>
        /// <param name="U">The upper-triangular matrix.</param>
        /// <param name="P">The identity matrix with a plenty of row inversions in the form of array.</param>
        public void LUP_Factorization(out int[] P, out Matrix_SDA <T, C> L, out Matrix_SDA <T, C> U)
        {
            Matrix_SDA <T, C> C;

            this.LUP_Factorization(out P, out C);

            int n = this.rows;

            L = new Matrix_SDA <T, C>(n, n);
            U = new Matrix_SDA <T, C>(n, n);

            Numeric <T, C> one = (Numeric <T, C>) 1;

            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    if (i < j)
                    {
                        U.setItemAt(i, j, C.getItemAt(i, j));
                    }
                    else if (i > j)
                    {
                        L.setItemAt(i, j, C.getItemAt(i, j));
                    }
                    else
                    {
                        L.setItemAt(i, j, one);                         // здесь единицы на диагонали
                        U.setItemAt(i, j, C.getItemAt(i, j));           // E возместить не надо.
                    }
                }
            }

            return;
        }
Example #3
0
        protected override Matrix <T, C> sum(Matrix <T, C> another)
        {
            if (this.rows != another.RowCount || this.columns != another.ColumnCount)
            {
                throw new MatrixSizeException("Matrices must be of the same size in order to sum.");
            }

            // If the matrix is SDA, we can do it quick'n'lucky.
            if (this.GetType().IsInstanceOfType(another))
            {
                Matrix_SDA <T, C> temp      = (Matrix_SDA <T, C>)another;
                Matrix_SDA <T, C> newMatrix = new Matrix_SDA <T, C>(this.rows, this.columns);

                for (int i = 0; i < this.ElementCount; i++)
                {
                    newMatrix.matrixArray[i] = this.matrixArray[i] + temp.matrixArray[i];
                }

                return(newMatrix);
            }
            // Here comes the bad case
            else
            {
                Matrix_SDA <T, C> newMatrix = new Matrix_SDA <T, C>(this.rows, this.columns);

                for (int i = 0; i < this.ElementCount; i++)
                {
                    newMatrix.matrixArray[i] = this.matrixArray[i] + another.getItemAt(i / columns, i % columns);
                }

                return(newMatrix);
            }
        }
Example #4
0
        /// <summary>
        /// Provides a deep clone of the current matrix.
        /// </summary>
        /// <returns>The cloned matrix.</returns>
        public override object Clone()
        {
            Matrix_SDA <T, C> temp = new Matrix_SDA <T, C>();

            temp.matrixArray = (Numeric <T, C>[]) this.matrixArray.Clone();
            temp.rows        = this.rows;
            temp.columns     = this.columns;

            return(temp);
        }
Example #5
0
        /// <summary>
        /// Provides a deep clone of the current matrix.
        /// </summary>
        /// <returns>The cloned matrix.</returns>
        public override object Clone()
        {
            Matrix_SDA temp = new Matrix_SDA();

            temp.matrixArray = (double[])this.matrixArray.Clone();
            temp.rows        = this.rows;
            temp.columns     = this.columns;

            return(temp);
        }
Example #6
0
        protected override Matrix <double> multiply(Matrix <double> another)
        {
            if (this.columns != another.RowCount)
            {
                throw new ArgumentException("The column count of the first matrix and the row count of the second matrix must match.");
            }

            Matrix_SDA temp = new Matrix_SDA(this.rows, another.ColumnCount);

            MatrixHelper.multiplySimple(this, another, temp);
            return(temp);
        }
Example #7
0
        // ------------------ OPERATORS

        /// <summary>
        /// Negates the matrix so that all the elements change their sign to the opposite.
        /// </summary>
        /// <returns></returns>
        protected override Matrix <T, C> negate()
        {
            Matrix_SDA <T, C> temp = new Matrix_SDA <T, C>(rows, columns);

            temp.matrixArray = (Numeric <T, C>[]) this.matrixArray.Clone();

            for (int i = 0; i < this.ElementCount; i++)
            {
                temp.matrixArray[i] = -temp.matrixArray[i];
            }

            return(temp);
        }
Example #8
0
        /// <summary>
        /// Negates the matrix so that all the elements change their sign to the opposite.
        /// </summary>
        /// <returns></returns>
        protected override Matrix <double> negate()
        {
            Matrix_SDA temp = new Matrix_SDA(rows, columns);

            temp.matrixArray = (double[])this.matrixArray.Clone();

            for (int i = 0; i < this.ElementCount; i++)
            {
                temp.matrixArray[i] *= -1;
            }

            return(temp);
        }
Example #9
0
        /// <summary>
        /// Preforms the LUP-factorization of a matrix (let it be A)
        /// in the form of:
        ///
        /// P*A = L*U.
        ///
        /// The P is an identity matrix with a plenty of row inversions.
        ///
        /// Requirements: works for any square and nonsingular matrix (having a non-zero determinant).
        /// If these requirements aren't met, either MatrixSingularException of MatrixSizeException
        /// would be thrown.
        /// </summary>
        /// <param name="L">The lower-triangular matrix with '1' on the main diagonal.</param>
        /// <param name="U">The upper-triangular matrix.</param>
        /// <param name="P">The identity matrix with a plenty of row inversions.</param>
        public void LUP_Factorization(out Matrix_SDA <T, C> P, out Matrix_SDA <T, C> L, out Matrix_SDA <T, C> U)
        {
            int[] arr;
            int   n = this.rows;

            Numeric <T, C> one = (Numeric <T, C>) 1;

            LUP_Factorization(out arr, out L, out U);

            P = new Matrix_SDA <T, C>(n, n);

            for (int i = 0; i < n; i++)
            {
                P.setItemAt(i, arr[i], one);
            }

            return;
        }
Example #10
0
        // ---------------------------------------------
        //             MATRIX ARITHMETIC
        // ---------------------------------------------

        /// <summary>
        /// Performs the matrix multiplication using the quick Strassen algorithm.
        /// Consumes more memory than simple iterational method, but much quicker
        /// on bigger dimensions (128+).
        ///
        /// If the dimension of method parameters passed is N, then maximum additional object memory consumption is
        /// <value>9N + [if N>64: (log2(N)-6)*f] + o(N)</value>
        /// Where f == (nearly) 4.5*(new Matrix of 2N*2N memory consumption).
        /// </summary>
        /// <param name="A">The matrix to multiply.</param>
        /// <param name="B">The matrix to multiply by.</param>
        /// <param name="result">The resulting matrix of [A.Rows x B.Columns] size.</param>
        public static void multiplyStrassen(Matrix <T, C> A, Matrix <T, C> B, Matrix <T, C> result)
        {
            int exp = 1;

            do
            {
                exp *= 2;
            } while (A.ColumnCount > exp || A.RowCount > exp || B.ColumnCount > exp || B.RowCount > exp);

            Matrix_SDA <T, C> Anew   = new Matrix_SDA <T, C>(exp, exp);
            Matrix_SDA <T, C> Bnew   = new Matrix_SDA <T, C>(exp, exp);
            Matrix_SDA <T, C> ResNew = new Matrix_SDA <T, C>(exp, exp);

            Anew.layMatrixAt(A, 0, 0);
            Bnew.layMatrixAt(B, 0, 0);

            strassenSkeleton(Anew, Bnew, ResNew, exp);

            result.layMatrixAt(ResNew.getSubMatrixCopyAt(0, 0, result.RowCount, result.ColumnCount), 0, 0);
        }
Example #11
0
        /// <summary>
        /// Overloaded. Gets the submatrix at the specified point and with specified size.
        /// </summary>
        /// <param name="i">Row index of the upper-left corner element</param>
        /// <param name="j">Columnt index of the upper-left corner element</param>
        /// <param name="rows">Row count of the submatrix</param>
        /// <param name="columns">Column count of the submatrix</param>
        /// <returns>The submatrix of specified size</returns>
        public override Matrix <double> getSubMatrixCopyAt(int i, int j, int rows, int columns)
        {
            checkPositive(rows, columns);
            checkBounds(i + rows, j + columns);

            double[] ma = new double[rows * columns];
            int      z  = 0;

            for (int k = i; k < i + rows; k++)
            {
                Array.Copy(this.matrixArray, this.columns * k + j, ma, z++ *columns, columns);
            }

            Matrix_SDA temp = new Matrix_SDA();

            temp.matrixArray = ma;
            temp.rows        = rows;
            temp.columns     = columns;

            return(temp);
        }
Example #12
0
        /// <summary>
        /// Overloaded. Gets the stand-alone submatrix copy at the specified point and with specified size.
        /// </summary>
        /// <param name="i">Row index of the upper-left corner element.</param>
        /// <param name="j">Columnt index of the upper-left corner element.</param>
        /// <param name="rows">Row count of the submatrix.</param>
        /// <param name="columns">Column count of the submatrix.</param>
        /// <returns>The submatrix of specified size.</returns>
        public virtual Matrix <T, C> getSubMatrixCopyAt(int i, int j, int rows, int columns)
        {
            checkPositive(rows, columns);
            checkBounds(i + rows, j + columns);

            Numeric <T, C>[] ma = new Numeric <T, C> [rows * columns];

            for (int k = i; k < i + rows; k++)
            {
                for (int m = j; m < j + rows; m++)
                {
                    ma[k * rows + m] = calc.getCopy(this.getItemAt(k, m));
                }
            }

            Matrix_SDA <T, C> temp = new Matrix_SDA <T, C>();

            temp.matrixArray = ma;
            temp.rows        = rows;
            temp.columns     = columns;

            return(temp);
        }
Example #13
0
        // ------------------- FACTORIZATION ----------------------------

        /// <summary>
        /// Preforms the LUP-factorization of a matrix (let it be A)
        /// in the form of:
        ///
        /// P*A = L*U.
        ///
        /// The P is an identity matrix with a plenty of row inversions.
        /// For the economy of space it is provided as a single-dimensional array of integers:
        ///
        /// (0, 1, 2, 3, ..., n).
        ///
        /// Element indices of this array stand for matrix rows, and elements value
        /// mean the position of '1' in a row.
        ///
        /// Requirements: works for any square and nonsingular matrix (having a non-zero determinant).
        /// If these requirements aren't met, either a MatrixSingularException or a MatrixSizeException
        /// would be thrown.
        /// </summary>
        /// <param name="C">The matrix C containing L + U - E. It is clear that both L and U can be easily extracted from this matrix.</param>
        /// <param name="P">The identity matrix with a plenty of row inversions in the form of array.</param>
        public void LUP_Factorization(out int[] P, out Matrix_SDA <T, C> C)
        {
            if (this.rows != this.columns)
            {
                throw new MatrixSizeException("The matrix is not square an thus cannot be factorized.");
            }

            int n = this.rows;  // размер матрицы

            C = new Matrix_SDA <T, C>(n, n);

            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    C.setItemAt(i, j, this.getItemAt(i, j));
                }
            }

            P = new int[n];
            P.FillByAssign(delegate(int i) { return(i); });

            // ----- пошел ----------

            Numeric <T, C> pivot;
            Numeric <T, C> abs;

            int pivotIndex;

            for (int i = 0; i < n; i++)
            {
                pivot      = Numeric <T, C> .Zero;
                pivotIndex = -1;

                for (int row = i; row < n; row++)
                {
                    abs = WhiteMath <T, C> .Abs(this.getItemAt(row, i));

                    if (abs > pivot)
                    {
                        pivot      = abs;
                        pivotIndex = row;
                    }
                }

                if (pivot == Numeric <T, C> .Zero)
                {
                    throw new MatrixSingularityException("The matrix is singular. It cannot be factorized.");
                }

                if (pivotIndex != i)
                {
                    P.Swap(pivotIndex, i);
                    C.swapRows(pivotIndex, i);
                }

                try
                {
                    for (int j = i + 1; j < n; j++)
                    {
                        C.setItemAt(j, i, C.getItemAt(j, i) / C.getItemAt(i, i));

                        if (Numeric <T, C> .isInfinity(C.getItemAt(j, i)) || Numeric <T, C> .isNaN(C.getItemAt(j, i)))
                        {
                            throw new DivideByZeroException();
                        }

                        for (int k = i + 1; k < n; k++)
                        {
                            C.setItemAt(j, k, C.getItemAt(j, k) - C.getItemAt(j, i) * C.getItemAt(i, k));
                        }
                    }
                }
                catch (DivideByZeroException)
                {
                    throw new MatrixSingularityException("The matrix is singular. It cannot be factorized.");
                }
            }

            return;
        }
Example #14
0
        /// <summary>
        /// Overloaded. Gets the submatrix at the specified point and with specified size.
        /// </summary>
        /// <param name="i">Row index of the upper-left corner element</param>
        /// <param name="j">Columnt index of the upper-left corner element</param>
        /// <param name="rows">Row count of the submatrix</param>
        /// <param name="columns">Column count of the submatrix</param>
        /// <returns>The submatrix of specified size</returns>
        public override Matrix<double> getSubMatrixCopyAt(int i, int j, int rows, int columns)
        {
            checkPositive(rows, columns);
            checkBounds(i + rows, j + columns);

            double[] ma = new double[rows * columns];
            int z=0;

            for (int k = i; k < i + rows; k++)
            {
                Array.Copy(this.matrixArray, this.columns*k + j, ma, z++*columns, columns);
            }

            Matrix_SDA temp = new Matrix_SDA();
            temp.matrixArray = ma;
            temp.rows = rows;
            temp.columns = columns;

            return temp;
        }
Example #15
0
        /// <summary>
        /// Private recursive Strassen multiplying method skeleton called implicitly by the wrapper method.
        /// </summary>
        /// <param name="A">The matrix to multiply</param>
        /// <param name="B">The matrix to multiply by</param>
        /// <param name="result">The resulting matrix</param>
        /// <param name="curDim">Current matrix dimension</param>
        private static void strassenSkeleton(Matrix <T, C> A, Matrix <T, C> B, Matrix <T, C> result, int curDim)
        {
            if (curDim <= 64)
            {
                multiplySimple(A, B, result);
                return;
            }

            int size = curDim / 2;

            Matrix <T, C> A11 = A.getSubMatrixAt(0, 0, size, size);
            Matrix <T, C> A12 = A.getSubMatrixAt(0, size, size, size);
            Matrix <T, C> A21 = A.getSubMatrixAt(size, 0, size, size);
            Matrix <T, C> A22 = A.getSubMatrixAt(size, size, size, size);

            Matrix <T, C> B11 = B.getSubMatrixAt(0, 0, size, size);
            Matrix <T, C> B12 = B.getSubMatrixAt(0, size, size, size);
            Matrix <T, C> B21 = B.getSubMatrixAt(size, 0, size, size);
            Matrix <T, C> B22 = B.getSubMatrixAt(size, size, size, size);

            Matrix <T, C> P1 = new Matrix_SDA <T, C>(size, size);
            Matrix <T, C> P2 = new Matrix_SDA <T, C>(size, size);
            Matrix <T, C> P3 = new Matrix_SDA <T, C>(size, size);
            Matrix <T, C> P4 = new Matrix_SDA <T, C>(size, size);
            Matrix <T, C> P5 = new Matrix_SDA <T, C>(size, size);
            Matrix <T, C> P6 = new Matrix_SDA <T, C>(size, size);
            Matrix <T, C> P7 = new Matrix_SDA <T, C>(size, size);

            Matrix <T, C> temp1 = new Matrix_SDA <T, C>(size, size);
            Matrix <T, C> temp2 = new Matrix_SDA <T, C>(size, size);

            sum(A11, A22, temp1);
            sum(B11, B22, temp2);

            strassenSkeleton(temp1, temp2, P1, size);

            sum(A21, A22, temp1);

            strassenSkeleton(temp1, B11, P2, size);

            dif(B12, B22, temp1);

            strassenSkeleton(A11, temp1, P3, size);

            dif(B21, B11, temp1);

            strassenSkeleton(A22, temp1, P4, size);

            sum(A11, A12, temp1);

            strassenSkeleton(temp1, B22, P5, size);

            dif(A21, A11, temp1);
            sum(B11, B12, temp2);

            strassenSkeleton(temp1, temp2, P6, size);

            dif(A12, A22, temp1);
            sum(B21, B22, temp2);

            strassenSkeleton(temp1, temp2, P7, size);

            sum(P1, P4, temp1);
            dif(temp1, P5, temp1);
            sum(temp1, P7, temp1);

            result.layMatrixAt(temp1, 0, 0);

            sum(P3, P5, temp1);

            result.layMatrixAt(temp1, 0, size);

            sum(P2, P4, temp1);

            result.layMatrixAt(temp1, size, 0);

            dif(P1, P2, temp1);
            sum(temp1, P3, temp1);
            sum(temp1, P6, temp1);

            result.layMatrixAt(temp1, size, size);
        }
Example #16
0
        /// <summary>
        /// Provides a deep clone of the current matrix.
        /// </summary>
        /// <returns>The cloned matrix.</returns>
        public override object Clone()
        {
            Matrix_SDA temp = new Matrix_SDA();
            temp.matrixArray = (double[])this.matrixArray.Clone();
            temp.rows = this.rows;
            temp.columns = this.columns;

            return temp;
        }
Example #17
0
        protected override Matrix<double> sum(Matrix<double> another)
        {
            if (this.rows != another.RowCount || this.columns != another.ColumnCount)
                throw new ArgumentException("Matrices must be of the same size in order to sum.");

            // If the matrix is SDA, we can do it quick'n'lucky.
            if (this.GetType().IsInstanceOfType(another))
            {
                Matrix_SDA temp = (Matrix_SDA)another;
                Matrix_SDA newMatrix = new Matrix_SDA(this.rows, this.columns);

                for (int i = 0; i < this.ElementCount; i++)
                    newMatrix.matrixArray[i] = this.matrixArray[i] + temp.matrixArray[i];

                return newMatrix;
            }
            // Here comes the bad case
            else
            {
                Matrix_SDA newMatrix = new Matrix_SDA(this.rows, this.columns);

                for (int i = 0; i < this.ElementCount; i++)
                    newMatrix.matrixArray[i] = this.matrixArray[i] + another.getItemAt(i / columns, i % columns);

                return newMatrix;
            }
        }
Example #18
0
        protected override Matrix<double> multiply(Matrix<double> another)
        {
            if (this.columns != another.RowCount)
                throw new ArgumentException("The column count of the first matrix and the row count of the second matrix must match.");

            Matrix_SDA temp = new Matrix_SDA(this.rows, another.ColumnCount);
            MatrixHelper.multiplySimple(this, another, temp);
            return temp;
        }
Example #19
0
        /// <summary>
        /// Negates the matrix so that all the elements change their sign to the opposite.
        /// </summary>
        /// <returns></returns>
        protected override Matrix<double> negate()
        {
            Matrix_SDA temp = new Matrix_SDA(rows, columns);
            temp.matrixArray = (double[])this.matrixArray.Clone();

            for (int i = 0; i < this.ElementCount; i++)
                temp.matrixArray[i] *= -1;

            return temp;
        }
Example #20
0
        /// <summary>
        /// This algorithm uses the LU-Factorization of coefficient matrix in order
        /// to calculate the solution of the equation system.
        ///
        /// As LU-Factorization is not guaranteed to exist for every
        /// non-singular matrix, this method may sometimes fail.
        /// </summary>
        /// <param name="coefficients">A square matrix of unknown terms' coefficients.</param>
        /// <param name="freeTerm">A vector of free terms.</param>
        /// <param name="x">The vector containing the solution of the equation system.</param>
        public static void LU_FactorizationSolving <T, C>(Matrix <T, C> coefficients, Vector <T, C> freeTerm, out Vector <T, C> x) where C : ICalc <T>, new()
        {
            if (coefficients.RowCount != coefficients.ColumnCount)
            {
                throw new ArgumentException("Only square matrices are supported.");
            }

            int dim = coefficients.RowCount;

            Matrix_SDA <T, C> K = new Matrix_SDA <T, C>(dim, dim);
            Matrix_SDA <T, C> M = new Matrix_SDA <T, C>(dim, dim);

            // Заполняем единичную диагональ матрицы K.
            for (int i = 0; i < dim; i++)
            {
                for (int j = 0; j < dim; j++)
                {
                    K[i, j] = M[i, j] = Numeric <T, C> .Zero;
                }

                M[i, i] = (Numeric <T, C>) 1;
                K[i, 0] = coefficients[i, 0];
                M[0, i] = coefficients[0, i] / K[0, 0];
            }

            // вектор промежуточных решений
            Vector <T, C> y = new Vector <T, C>(dim);

            y[0] = freeTerm[0] / K[0, 0];

            Numeric <T, C> s; // вспомогательная

            for (int i = 1; i < dim; i++)
            {
                int j;

                for (j = 0; j < dim; j++)
                {
                    s = (Numeric <T, C>) 0;

                    for (int z = 0; z <= j - 1; z++)
                    {
                        s += K[i, z] * M[z, j];
                    }

                    K[i, j] = coefficients[i, j] - s;
                }

                for (j = i; j < dim; j++)
                {
                    Numeric <T, C> s1 = (Numeric <T, C>) 0;
                    Numeric <T, C> s2 = (Numeric <T, C>) 0;

                    for (int z = 0; z <= i - 1; z++)
                    {
                        s1 += K[i, z] * M[z, j];
                        s2 += K[i, z] * y[z];
                    }

                    M[i, j] = (coefficients[i, j] - s1) / K[i, i];
                    y[i]    = (freeTerm[i] - s2) / K[i, i];
                }
            }

            x          = new Vector <T, C>(dim);
            x[dim - 1] = y[dim - 1];

            for (int i = dim - 2; i >= 0; i--)
            {
                s = (Numeric <T, C>) 0;

                for (int z = i + 1; z < dim; z++)
                {
                    s += M[i, z] * x[z];
                }

                x[i] = y[i] - s;
            }

            return;
        }