QR decomposition for a rectangular matrix.

For an m-by-n matrix A with m >= n, the QR decomposition is an m-by-n orthogonal matrix Q and an n-by-n upper triangular matrix R so that A = Q * R.

The QR decomposition always exists, even if the matrix does not have full rank, so the constructor will never fail. The primary use of the QR decomposition is in the least squares solution of nonsquare systems of simultaneous linear equations. This will fail if FullRank returns .

Inheritance: ISolverDecomposition
        public void QrDecompositionConstructorTest()
        {
            double[,] value =
            {
               {  2, -1,  0 },
               { -1,  2, -1 },
               {  0, -1,  2 }
            };


            QrDecomposition target = new QrDecomposition(value);

            // Decomposition Identity
            var Q = target.OrthogonalFactor;
            var QQt = Q.Multiply(Q.Transpose());
            Assert.IsTrue(Matrix.IsEqual(QQt, Matrix.Identity(3), 0.0000001));


            // Linear system solving
            double[,] B = Matrix.ColumnVector(new double[] { 1, 2, 3 });
            double[,] expected = Matrix.ColumnVector(new double[] { 2.5, 4.0, 3.5 });
            double[,] actual = target.Solve(B);

            Assert.IsTrue(Matrix.IsEqual(expected, actual, 0.0000000000001));
        }
        public void InverseTestNaN()
        {
            int n = 5;

            var I = Matrix.Identity(n);

            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    double[,] value = Matrix.Magic(n);

                    value[i, j] = double.NaN;

                    var target = new QrDecomposition(value);
                    var solution = target.Solve(I);
                    var inverse = target.Inverse();

                    Assert.IsTrue(Matrix.IsEqual(solution, inverse));
                }
            }
        }
 /// <summary>QR decomposition.</summary>
 protected static void qr(double[,] m, out double[,] Q, out double[,] R, out double[] d)
 {
     var qr = new QrDecomposition(m);
     Q = qr.OrthogonalFactor;
     R = qr.UpperTriangularFactor;
     d = qr.Diagonal;
 }
        public void SolveTransposeTest()
        {
            double[,] a = 
            {
                { 2, 1, 4 },
                { 6, 2, 2 },
                { 0, 1, 6 },
            };

            double[,] b =
            {
                { 1, 0, 7 },
                { 5, 2, 1 },
                { 1, 5, 2 },
            };

            double[,] expected =
            {
                 { 0.5062,    0.2813,    0.0875 },
                 { 0.1375,    1.1875,   -0.0750 },
                 { 0.8063,   -0.2188,    0.2875 },
            };

            double[,] actual = new QrDecomposition(b, true).SolveTranspose(a);
            Assert.IsTrue(Matrix.IsEqual(expected, actual, 0.001));
        }
        public void SolveTest2()
        {
            // Example from Lecture notes for MATHS 370: Advanced Numerical Methods
            // http://www.math.auckland.ac.nz/~sharp/370/qr-solving.pdf

            double[,] value =
            {
                { 1,           0,           0 },
                { 1,           7,          49 },
                { 1,          14,         196 },
                { 1,          21,         441 },
                { 1,          28,         784 },
                { 1,          35,        1225 },
            };

            // Matrices
            {
                double[,] b = 
                {
                    { 4 },
                    { 1 },
                    { 0 },
                    { 0 }, 
                    { 2 },
                    { 5 },
                };

                double[,] expected =
                {
                    { 3.9286  },
                    { -0.5031 },
                    { 0.0153  },
                };

                QrDecomposition target = new QrDecomposition(value);
                double[,] actual = target.Solve(b);

                Assert.IsTrue(Matrix.IsEqual(expected, actual, 1e-4));
            }

            // Vectors
            {
                double[] b = { 4, 1, 0, 0, 2, 5 };
                double[] expected = { 3.9286, -0.5031, 0.0153 };

                QrDecomposition target = new QrDecomposition(value);
                double[] actual = target.Solve(b);

                Assert.IsTrue(Matrix.IsEqual(expected, actual, 1e-4));
            }
        }
        public void SolveTest()
        {
            double[,] value =
            {
               {  2, -1,  0 },
               { -1,  2, -1 },
               {  0, -1,  2 }
            };

            double[] b = { 1, 2, 3 };

            double[] expected = { 2.5000, 4.0000, 3.5000 };

            QrDecomposition target = new QrDecomposition(value);
            double[] actual = target.Solve(b);

            Assert.IsTrue(Matrix.IsEqual(expected, actual, 0.0000000000001));
        }
        public void InverseTest()
        {
            double[,] value =
            {
               {  2, -1,  0 },
               { -1,  2, -1 },
               {  0, -1,  2 }
            };

            double[,] expected =
            {
                { 0.7500,    0.5000,    0.2500},
                { 0.5000,    1.0000,    0.5000},
                { 0.2500,    0.5000,    0.7500},
            };


            QrDecomposition target = new QrDecomposition(value);

            double[,] actual = target.Inverse();
            Assert.IsTrue(Matrix.IsEqual(expected, actual, 0.0000000000001));

            target = new QrDecomposition(value.Transpose(), true);
            actual = target.Inverse();
            Assert.IsTrue(Matrix.IsEqual(expected, actual, 0.0000000000001));
        }
Beispiel #8
0
        static void Main(string[] args)
        {
            Console.WriteLine("Please take a look at the source for examples!");
            Console.ReadKey();

            #region 1. Declaring matrices

            // 1.1 Using standard .NET declaration
            double[,] A = 
            {
                {1, 2, 3},
                {6, 2, 0},
                {0, 0, 1}
            };

            double[,] B = 
            {
                {2, 0, 0},
                {0, 2, 0},
                {0, 0, 2}
            };

            {
                // 1.2 Using Accord extension methods
                double[,] Bi = Matrix.Identity(3).Multiply(2);
                double[,] Bj = Matrix.Diagonal(3, 2.0); // both are equal to B

                // 1.2 Using Accord extension methods with implicit typing
                var I = Matrix.Identity(3);
            }
            #endregion



            #region 2. Matrix Operations
            {
                // 2.1 Addition
                var C = A.Add(B);

                // 2.2 Subtraction
                var D = A.Subtract(B);

                // 2.3 Multiplication
                {
                    // 2.3.1 By a scalar
                    var halfM = A.Multiply(0.5);

                    // 2.3.2 By a vector
                    double[] m = A.Multiply(new double[] { 1, 2, 3 });

                    // 2.3.3 By a matrix
                    var M = A.Multiply(B);

                    // 2.4 Transposing
                    var At = A.Transpose();
                }
            }


            // 2.5 Elementwise operations

            // 2.5.1 Elementwise multiplication
            A.ElementwiseMultiply(B); // A.*B

            // 2.5.1 Elementwise division
            A.ElementwiseDivide(B); // A./B

            #endregion



            #region 3. Matrix characteristics
            {
                // 3.1 Calculating the determinant
                double det = A.Determinant();

                // 3.2 Calculating the trace
                double tr = A.Trace();

                // 3.3 Computing the sum vector
                {
                    double[] sumVector = A.Sum();

                    // 3.3.1 Computing the total sum of elements
                    double sum = sumVector.Sum();

                    // 3.3.2 Computing the sum along the rows
                    sumVector = A.Sum(0); // Equivalent to Octave's sum(A, 1)

                    // 3.3.2 Computing the sum along the columns
                    sumVector = A.Sum(1); // Equivalent to Octave's sum(A, 2)
                }
            }
            #endregion



            #region 4. Linear Algebra
            {
                // 4.1 Computing the inverse
                var invA = A.Inverse();

                // 4.2 Computing the pseudo-inverse
                var pinvA = A.PseudoInverse();

                // 4.3 Solving a linear system (Ax = B)
                var x = A.Solve(B);
            }
            #endregion



            #region 5. Special operators
            {
                // 5.1 Finding the indices of elements
                double[] v = { 5, 2, 2, 7, 1, 0 };
                int[] idx = v.Find(e => e > 2); // finding the index of every element in v higher than 2.

                // 5.2 Selecting elements by index
                double[] u = v.Submatrix(idx); // u is { 5, 7 }

                // 5.3 Converting between different matrix representations
                double[][] jaggedA = A.ToArray(); // from multidimensional to jagged array

                // 5.4 Extracting a column or row from the matrix
                double[] a = A.GetColumn(0); // retrieves the first column
                double[] b = B.GetRow(1); // retrieves the second row

                // 5.5 Taking the absolute of a matrix
                var absA = A.Abs();

                // 5.6 Applying some function to every element
                var newv = v.Apply(e => e + 1);
            }
            #endregion



            #region 7. Vector operations
            {
                double[] u = { 1, 2, 3 };
                double[] v = { 4, 5, 6 };

                var w1 = u.InnerProduct(v);
                var w2 = u.OuterProduct(v);
                var w3 = u.CartesianProduct(v);


                double[] m = { 1, 2, 3, 4 };
                double[,] M = Matrix.Reshape(m, 2, 2);
            }
            #endregion


            #region Decompositions
            {
                // Singular value decomposition
                {
                    SingularValueDecomposition svd = new SingularValueDecomposition(A);
                    var U = svd.LeftSingularVectors;
                    var S = svd.Diagonal;
                    var V = svd.RightSingularVectors;
                }
                // or (please see documentation for details)
                {
                    SingularValueDecomposition svd = new SingularValueDecomposition(A.Transpose());
                    var U = svd.RightSingularVectors;
                    var S = svd.Diagonal;
                    var V = svd.LeftSingularVectors;
                }

                // Eigenvalue decomposition
                {
                    EigenvalueDecomposition eig = new EigenvalueDecomposition(A);
                    var V = eig.Eigenvectors;
                    var D = eig.DiagonalMatrix;
                }

                // QR decomposition
                {
                    QrDecomposition qr = new QrDecomposition(A);
                    var Q = qr.OrthogonalFactor;
                    var R = qr.UpperTriangularFactor;
                }

                // Cholesky decomposition
                {
                    CholeskyDecomposition chol = new CholeskyDecomposition(A);
                    var R = chol.LeftTriangularFactor;
                }

                // LU decomposition
                {
                    LuDecomposition lu = new LuDecomposition(A);
                    var L = lu.LowerTriangularFactor;
                    var U = lu.UpperTriangularFactor;
                }

            }
            #endregion

        }
 /// <summary>
 ///   Creates a new object that is a copy of the current instance.
 /// </summary>
 /// <returns>
 ///   A new object that is a copy of this instance.
 /// </returns>
 public object Clone()
 {
     var clone = new QrDecomposition();
     clone.qr = (double[,])qr.Clone();
     clone.Rdiag = (double[])Rdiag.Clone();
     return clone;
 }
        private double regress(double[][] inputs, double[] outputs, out double[,] designMatrix, bool robust)
        {
            if (inputs.Length != outputs.Length)
                throw new ArgumentException("Number of input and output samples does not match", "outputs");

            int parameters = Inputs;
            int rows = inputs.Length;   // number of instance points
            int cols = Inputs;          // dimension of each point

            for (int i = 0; i < inputs.Length; i++)
            {
                if (inputs[i].Length != parameters)
                {
                    throw new DimensionMismatchException("inputs", String.Format(
                        "Input vectors should have length {0}. The row at index {1} of the" +
                        " inputs matrix has length {2}.", parameters, i, inputs[i].Length));
                }
            }

            ISolverMatrixDecomposition<double> solver;


            // Create the problem's design matrix. If we
            //  have to add an intercept term, add a new
            //  extra column at the end and fill with 1s.

            if (!addIntercept)
            {
                // Just copy values over
                designMatrix = new double[rows, cols];
                for (int i = 0; i < inputs.Length; i++)
                    for (int j = 0; j < inputs[i].Length; j++)
                        designMatrix[i, j] = inputs[i][j];
            }
            else
            {
                // Add an intercept term
                designMatrix = new double[rows, cols + 1];
                for (int i = 0; i < inputs.Length; i++)
                {
                    for (int j = 0; j < inputs[i].Length; j++)
                        designMatrix[i, j] = inputs[i][j];
                    designMatrix[i, cols] = 1;
                }
            }

            // Check if we have an overdetermined or underdetermined
            //  system to select an appropriate matrix solver method.

            if (robust || cols >= rows)
            {
                // We have more variables than equations, an
                // underdetermined system. Solve using a SVD:
                solver = new SingularValueDecomposition(designMatrix,
                    computeLeftSingularVectors: true,
                    computeRightSingularVectors: true,
                    autoTranspose: true);
            }
            else
            {
                // We have more equations than variables, an
                // overdetermined system. Solve using the QR:
                solver = new QrDecomposition(designMatrix);
            }


            // Solve V*C = B to find C (the coefficients)
            coefficients = solver.Solve(outputs);


            // Calculate Sum-Of-Squares error
            double error = 0.0;
            double e;
            for (int i = 0; i < outputs.Length; i++)
            {
                e = outputs[i] - Compute(inputs[i]);
                error += e * e;
            }

            return error;
        }
        public void SolveTransposeTest()
        {
            double[][] a =
            {
                new double[] { 2, 1, 4 },
                new double[] { 6, 2, 2 },
                new double[] { 0, 1, 6 },
            };

            double[][] b =
            {
                new double[] { 1, 0, 7 },
                new double[] { 5, 2, 1 },
                new double[] { 1, 5, 2 },
            };

            double[][] expected =
            {
                 new double[] { 0.5062,    0.2813,    0.0875 },
                 new double[] { 0.1375,    1.1875,   -0.0750 },
                 new double[] { 0.8063,   -0.2188,    0.2875 },
            };

            double[][] actual = new JaggedQrDecomposition(b, true).SolveTranspose(a);
            Assert.IsTrue(Matrix.IsEqual(expected, actual, 0.001));

            var bX = b.Dot(expected);
            var Xb = expected.Dot(b);
            Assert.IsTrue(Matrix.IsEqual(Xb, a, atol: 1e-3));
            Assert.IsFalse(Matrix.IsEqual(bX, a, atol: 1e-3));

            double[,] actualMatrix = new QrDecomposition(b.ToMatrix(), true).SolveTranspose(a.ToMatrix());
            Assert.IsTrue(Matrix.IsEqual(expected, actualMatrix, 0.001));
        }
        public void InverseTest1()
        {
            double[][] value =
            {
                new double[] { 41.9, 29.1, 1 },
                new double[] { 43.4, 29.3, 1 },
                new double[] { 43.9, 29.5, 0 },
                new double[] { 44.5, 29.7, 0 },
                new double[] { 47.3, 29.9, 0 },
                new double[] { 47.5, 30.3, 0 },
                new double[] { 47.9, 30.5, 0 },
                new double[] { 50.2, 30.7, 0 },
                new double[] { 52.8, 30.8, 0 },
                new double[] { 53.2, 30.9, 0 },
                new double[] { 56.7, 31.5, 0 },
                new double[] { 57.0, 31.7, 0 },
                new double[] { 63.5, 31.9, 0 },
                new double[] { 65.3, 32.0, 0 },
                new double[] { 71.1, 32.1, 0 },
                new double[] { 77.0, 32.5, 0 },
                new double[] { 77.8, 32.9, 0 }
            };

            double[][] expected = new JaggedSingularValueDecomposition(value,
                computeLeftSingularVectors: true,
                computeRightSingularVectors: true,
                autoTranspose: true).Inverse();

            var target = new JaggedQrDecomposition(value);
            double[][] actual = target.Inverse();
            Assert.IsTrue(Matrix.IsEqual(expected, actual, atol: 1e-4));

            var targetMat = new QrDecomposition(value.ToMatrix());
            double[][] actualMat = target.Inverse();
            Assert.IsTrue(Matrix.IsEqual(expected, actualMat, atol: 1e-4));
        }
        public void SolveTest3()
        {
            double[][] value =
            {
                new double[] { 41.9, 29.1, 1 },
                new double[] { 43.4, 29.3, 1 },
                new double[] { 43.9, 29.5, 0 },
                new double[] { 44.5, 29.7, 0 },
                new double[] { 47.3, 29.9, 0 },
                new double[] { 47.5, 30.3, 0 },
                new double[] { 47.9, 30.5, 0 },
                new double[] { 50.2, 30.7, 0 },
                new double[] { 52.8, 30.8, 0 },
                new double[] { 53.2, 30.9, 0 },
                new double[] { 56.7, 31.5, 0 },
                new double[] { 57.0, 31.7, 0 },
                new double[] { 63.5, 31.9, 0 },
                new double[] { 65.3, 32.0, 0 },
                new double[] { 71.1, 32.1, 0 },
                new double[] { 77.0, 32.5, 0 },
                new double[] { 77.8, 32.9, 0 }
            };

            double[][] b =
            {
                new double[] { 251.3 },
                new double[] { 251.3 },
                new double[] { 248.3 },
                new double[] { 267.5 },
                new double[] { 273.0 },
                new double[] { 276.5 },
                new double[] { 270.3 },
                new double[] { 274.9 },
                new double[] { 285.0 },
                new double[] { 290.0 },
                new double[] { 297.0 },
                new double[] { 302.5 },
                new double[] { 304.5 },
                new double[] { 309.3 },
                new double[] { 321.7 },
                new double[] { 330.7 },
                new double[] { 349.0 }
            };

            double[][] expected =
            {
                new double[] { 1.7315235669547167  },
                new double[] { 6.25142110500275 },
                new double[] { -5.0909763966987178  },
            };

            var target = new JaggedQrDecomposition(value);
            double[][] actual = target.Solve(b);

            Assert.IsTrue(Matrix.IsEqual(expected, actual, atol: 1e-4));
            var reconstruct = value.Dot(expected);
            Assert.IsTrue(Matrix.IsEqual(reconstruct, b, rtol: 1e-1));
            double[] b2 = b.GetColumn(0);
            double[] expected2 = expected.GetColumn(0);

            var target2 = new JaggedQrDecomposition(value);
            double[] actual2 = target2.Solve(b2);
            Assert.IsTrue(Matrix.IsEqual(expected2, actual2, atol: 1e-4));

            var targetMat = new QrDecomposition(value.ToMatrix());
            double[,] actualMat = targetMat.Solve(b.ToMatrix());

            Assert.IsTrue(Matrix.IsEqual(expected, actualMat, atol: 1e-4));
            var reconstructMat = value.ToMatrix().Dot(expected);
            Assert.IsTrue(Matrix.IsEqual(reconstruct, b, rtol: 1e-1));

            var targetMat2 = new QrDecomposition(value.ToMatrix());
            double[] actualMat2 = targetMat2.Solve(b2);
            Assert.IsTrue(Matrix.IsEqual(expected2, actualMat2, atol: 1e-4));
        }