public void AugmentedReducedRowEchelonFormTest()
        {
            var A = new Matrix(new double[,] { { 1, 2, 3 }, { 0, 1, 4 }, { 5, 6, 0 } });
            var I = A.GetIdentity();
            var aug = new AugmentedMatrix(new Matrix[] { A, I });
            var augGE = aug.ReducedRowEchelonForm();

            var identity = new Matrix(new double[,] { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } });
            var inverse = new Matrix(new double[,] { { -24, 18, 5 }, { 20, -15, -4 }, { -5, 4, 1 } });
            Assert.That(augGE[0], Is.EqualTo(identity));
            Assert.That(augGE[1], Is.EqualTo(inverse));

            var B = new Matrix(new double[,] { { 1, 2, 3, 6 }, { 0, 1, 4, 8 }, { 5, 6, 0, 9 }, { 9, 4, 7, 3 } });
            I = new Matrix(4, 4).GetIdentity();
            var aug2 = new AugmentedMatrix(new Matrix[] { B, I });
            var augRref2 = aug2.ReducedRowEchelonForm();

            var identity2 = new Matrix(4, 4).GetIdentity();
            var inverse2 =
                new Matrix(
                    new double[,]
                        {
                            { -69.0 / 67.0, 36.0 / 67.0, 11.0 / 67.0, 9.0 / 67.0 },
                            { 544.0 / 335.0, -69.0 / 67, -44.0 / 335.0, -36.0 / 335.0 },
                            { 206.0 / 335.0, -18.0 / 67.0, -61.0 / 335.0, 11.0 / 335.0 },
                            { -171.0 / 335.0, 26.0 / 67.0, 36.0 / 335.0, -1.0 / 335.0 }
                        });

            Assert.That(augRref2[0], Is.EqualTo(identity2));
            Assert.That(augRref2[1], Is.EqualTo(inverse2));
        }
        /// <summary>
        ///     Computes the reduced row echelon form of the matrix.
        /// </summary>
        /// <param name="matrix"></param>
        /// <returns></returns>
        public static AugmentedMatrix ReducedRowEchelonForm(this AugmentedMatrix augMatrix)
        {
            augMatrix = augMatrix.GaussianElimination();
            var gaussElimResult = augMatrix[0];

            int iMax = Math.Min(gaussElimResult.Columns, gaussElimResult.Rows);

            for (int i = 0, currentCol = 0; i < iMax && currentCol < gaussElimResult.Columns; i++, currentCol++)
            {
                var currentStartElement = gaussElimResult[i, currentCol];

                if (Math.Abs(currentStartElement) > TOLERANCE)
                {
                    // If the current start element does not equal 1 then fix it
                    if (Math.Abs(currentStartElement - 1) > TOLERANCE)
                    {
                        augMatrix = augMatrix.MultiplyRowByScalar(i, 1.0 / currentStartElement);
                    }

                    for (int j = 0; j <= i - 1; j++)
                    {
                        var ratio = -1.0 * gaussElimResult[j, currentCol] * gaussElimResult[i, currentCol];
                        augMatrix = augMatrix.AddRows(i, j, ratio);
                    }
                }
                else
                {
                    i--; // The test element was zero, do not increment the row
                }
            }

            return(augMatrix);
        }
Exemple #3
0
        public Matrix GetInverse()
        {
            if (!this.IsSquare)
            {
                throw new ArgumentException(
                          "Inverses only exist for square matrices. See Lipschutz, Linear Algebra. 5th ed. pg. 34. or wikipedia.");
            }

            var augmentedMatix = new AugmentedMatrix(new Matrix[] { this, this.GetIdentity() });

            return(augmentedMatix.ReducedRowEchelonForm()[1]);
        }
        /// <summary>
        ///     Performs the elementary row operation of assing two rows.
        ///     The <paramref name="addendRow" /> is the  row which is updated.
        /// </summary>
        /// <param name="matrix"></param>
        /// <param name="augendRow"></param>
        /// <param name="addendRow"></param>
        /// <returns></returns>
        public static AugmentedMatrix AddRows(
            this AugmentedMatrix augMatrix,
            double[] augendRow,
            int addendRow,
            int matrixIndex)
        {
            for (int j = 0; j < augMatrix[matrixIndex].Columns; j++)
            {
                augMatrix[matrixIndex][addendRow, j] += augendRow[j];
            }

            return(augMatrix);
        }
        /// <summary>
        ///     Performs the elementary row operation of assing two rows.
        ///     The <paramref name="addendRow" /> is the  row which is updated.
        /// </summary>
        /// <param name="matrix"></param>
        /// <param name="augendRow"></param>
        /// <param name="addendRow"></param>
        /// <returns></returns>
        public static AugmentedMatrix AddRows(
            this AugmentedMatrix augMatrix,
            int augendRow,
            int addendRow,
            double scalarMultiple = 1.0)
        {
            for (int i = 0; i < augMatrix.Count; i++)
            {
                for (int j = 0; j < augMatrix[i].Columns; j++)
                {
                    augMatrix[i][addendRow, j] = augMatrix[i][addendRow, j]
                                                 + (scalarMultiple * augMatrix[i][augendRow, j]);
                }
            }

            return(augMatrix);
        }
        public static AugmentedMatrix MultiplyRowByScalar(
            this AugmentedMatrix augMatrix,
            int row,
            double scalar,
            int startColumn = 0)
        {
            for (int i = 0; i < augMatrix.Count; i++)
            {
                // TODO: This method should not modify the original augMatrix
                for (int j = startColumn; j < augMatrix[i].Columns; j++)
                {
                    augMatrix[i][row, j] = scalar * augMatrix[i][row, j];
                }
            }

            return(augMatrix);
        }
        public static AugmentedMatrix SwapRows(this AugmentedMatrix augMatrix, int row1, int row2)
        {
            var identity = augMatrix[0].GetIdentity();

            identity[row1, row1] = 0;
            identity[row1, row2] = 1;

            identity[row2, row2] = 0;
            identity[row2, row1] = 1;

            for (int i = 0; i < augMatrix.Count; i++)
            {
                augMatrix[i] = identity * augMatrix[i];
            }

            return(augMatrix);
        }
        /// <summary>
        ///     Performs gaussian elimination on the given matrix.
        /// </summary>
        /// <param name="matrix"></param>
        /// <returns></returns>
        public static AugmentedMatrix GaussianElimination(this AugmentedMatrix augMatrix)
        {
            // Derived from ref [1] Theorem 3.5

            // identify the row with the first non zero element
            int  nonZeroRowIndex    = 0;
            bool run                = true;
            int  nonZeroColumnIndex = 0;

            while (run && nonZeroColumnIndex < augMatrix[0].Columns)
            {
                // Check if columns has non-zero entry
                var col = augMatrix[0].GetColumn(nonZeroColumnIndex);
                for (int j = 0; j < col.Length; j++)
                {
                    if (Math.Abs(col[j]) > TOLERANCE)
                    {
                        nonZeroRowIndex = j;
                        run             = false;
                        break;
                    }
                }

                if (run)
                {
                    nonZeroColumnIndex++;
                }
            }

            // Move this row into the top position
            if (nonZeroRowIndex != 0)
            {
                augMatrix = augMatrix.SwapRows(nonZeroRowIndex, 0);
            }

            // If the first non zero row does not equal 1 then normalize the
            if (Math.Abs(augMatrix[0][0, nonZeroColumnIndex] - 1.0) > TOLERANCE)
            {
                augMatrix = augMatrix.MultiplyRowByScalar(0, 1.0 / augMatrix[0][0, nonZeroColumnIndex]);
            }

            int iMax = Math.Min(augMatrix[0].Columns, augMatrix[0].Rows);

            // Zero-wise columns
            for (int i = 0, currentCol = 0; i < iMax && currentCol < augMatrix[0].Columns; i++, currentCol++)
            {
                var currentStartElement = augMatrix[0][i, currentCol];

                if (Math.Abs(currentStartElement) > TOLERANCE)
                {
                    for (int j = i + 1; j < iMax; j++)
                    {
                        var ratio = -1.0 * (augMatrix[0][j, currentCol] / currentStartElement);
                        augMatrix = augMatrix.AddRows(i, j, ratio);
                    }
                }
                else
                {
                    i--; // The test element was zero, do not increment the row
                }
            }

            return(augMatrix);
        }