예제 #1
0
        /// <summary>
        /// Solve the minimum norm problem A * x = b => transpose(Q) * inv(L) * b. The minimum nrom problem is defined as:
        /// from the infinite solutions of A * x = b, find the one with the minimum norm2(x). Warning: the rows of the original
        /// matrix must be independent for this to work: If A (m-by-n, with m &lt;= n) has full row rank, r = m => the column
        /// space of A is an m dimensional subspace of R^m (every vector A*z is m-by-1) => the column space of A is the whole
        /// R^m and A*x=b, always has at least one solution. The nullspace of A is an (n-m) dimensional subspace of R^n. Thus
        /// there are infinite solutions to A*x=b.
        /// </summary>
        /// <param name="rhsVector">The right hand side vector b. It may lie outside the column space of the original matrix. Its
        ///     <see cref="IIndexable1D.Length"/> must be equal to this.<see cref="NumRows"/>.</param>
        /// <exception cref="Exceptions.LapackException">Thrown if tha call to LAPACK fails due to <paramref name="rhsVector"/>
        ///     having a different <see cref="IIndexable1D.Length"/> than this.<see cref="NumRows"/>.</exception>
        public Vector SolveMinNorm(Vector rhsVector) //TODO: perhaps I should use the driver routines of LAPACKE
        {
            if (NumRows > NumColumns)
            {
                throw new NotImplementedException("For now, the number of rows must be <= the number of columns");
            }
            Preconditions.CheckSystemSolutionDimensions(NumRows, rhsVector.Length);

            // Min norm: A * x = b => L * Q * x = b, where b is the right hand side vector.
            // Step 1: L * c = b. L is m-by-n, b is m-by-1 => c is n-by-1. Reminder n>=m.
            // Decomposing L: [L1 0] * [c1; c2] = b => L1*c1 = b, where:
            // L1 is m-by-m, lower triangular and stored in the factorized col major dat
            // c1 is m-by-1 and can be found by forward substitution
            // c2 is (n-m)-by-1 and can be any vector whatsoever.
            int leadingDimA = NumRows; // Also k = min(NumRows, NumColumns) = NumRows = ldA
            int incC        = 1;       // step in rhs array

            double[] c = new double[NumColumns];
            rhsVector.CopyToArray(0, c, 0, NumRows);
            Blas.Dtrsv(StoredTriangle.Lower, TransposeMatrix.NoTranspose, DiagonalValues.NonUnit,
                       NumRows, reflectorsAndL, 0, leadingDimA, c, 0, incC);
            // TODO: Check output of BLAS somehow. E.g. Zero diagonal entries will result in NaN in the result vector.

            // Step 2: x = Q^T * c. Q is n-by-n, c is n-by-1, x is n-by-1
            int numRowsC    = NumColumns; // c has been grown past the limits of rhs.
            int numColsC    = 1;          // c is m-by-1
            int k           = reflectorScalars.Length;
            int leadingDimC = numRowsC;

            LapackLeastSquares.Dormlq(MultiplicationSide.Left, TransposeMatrix.Transpose, numRowsC, numColsC, k,
                                      reflectorsAndL, 0, leadingDimA, reflectorScalars, 0, c, 0, leadingDimC);

            return(Vector.CreateFromArray(c, false));
        }
예제 #2
0
        /// <summary>
        /// Explicitly creates the matrix Q1, which consists of the first n columns of the orthogonal matrix Q that resulted
        /// from the factorization: A =  Q * R = [Q1, Q2] * [R1; 0] (Matlab notation) = Q1 * R1,
        /// where A is m-by-n, Q is m-by-m, R is m-by-n, Q1 is m-by-n and R1 is (n-by-n).
        /// This method is safe to use as the factorization data are copied (if necessary). However, it is inefficient if the
        /// generated matrix is only used once.
        /// </summary>
        public Matrix GetEconomyFactorQ()
        {
            if (NumRows < NumColumns)
            {
                throw new NotImplementedException("For now, the number of rows must be >= the number of columns");
            }
            int m   = NumRows;
            int n   = NumColumns;
            int k   = NumColumns;
            int ldA = m;

            var matrixQ = new double[NumRows * NumColumns];

            Array.Copy(reflectorsAndR, matrixQ, matrixQ.Length);

            // Call Lapack
            int numRowsQ      = NumRows;
            int numColsQ      = NumColumns;
            int numReflectors = NumColumns;
            int leadingDimQ   = numRowsQ;

            LapackLeastSquares.Dorgqr(numRowsQ, numColsQ, numReflectors, matrixQ, 0, leadingDimQ, reflectorScalars, 0);

            return(Matrix.CreateFromArray(matrixQ, NumRows, NumColumns, false));
        }
예제 #3
0
        /// <summary>
        /// Calculates the LQ factorization of a matrix, such that A = L * Q. Requires an extra
        /// min(<paramref name="numRows"/>, <paramref name="numCols"/>) available memory.
        /// </summary>
        /// <param name="numRows">The number of rows of the matrix.</param>
        /// <param name="numCols">The number of columns of the matrix.</param>
        /// <param name="matrix">The internal buffer storing the matrix entries in column major order. It will
        ///     be overwritten with the factorization data.</param>
        /// <exception cref="NotImplementedException">Thrown if <paramref name="numCols"/> &lt; <paramref name="numRows"/>.
        ///     </exception>
        /// <exception cref="Exceptions.LapackException">Thrown if tha call to LAPACK fails due to an invalid
        ///     <paramref name="matrix"/>.</exception>
        public static LQFactorization Factorize(int numRows, int numCols, double[] matrix)
        {
            if (numRows > numCols)
            {
                throw new NotImplementedException("For now, the number of rows must be <= the number of columns");
            }

            int leadingDimA = numRows;
            int minDim      = Math.Min(numRows, numCols); //TODO: this is known to be numRows (though it may change in the future)

            double[] reflectorScalars = new double[minDim];
            LapackLeastSquares.Dgelqf(numRows, numCols, matrix, 0, leadingDimA, reflectorScalars, 0);

            return(new LQFactorization(numRows, numCols, matrix, reflectorScalars));
        }
예제 #4
0
        /// <summary>
        /// Explicitly creates the orthogonal matrix Q that resulted from the factorization: A = L * Q, where A is m-by-n,
        /// L is m-by-n and Q is n-by-n.
        /// This method is safe to use as the factorization data are copied (if necessary). However, it is inefficient if the
        /// generated matrix is only used once.
        /// </summary>
        public Matrix GetFactorQ()
        {
            if (NumRows > NumColumns)
            {
                throw new NotImplementedException("For now, the number of rows must be <= the number of columns");
            }

            // We need a larger buffer for Q (n-by-n) > reflectorsAndL (p-by-n)
            double[] matrixQ = ArrayColMajor.IncreaseRows(NumRows, NumColumns, NumColumns, reflectorsAndL);

            // Call LAPACK
            int numColsQ      = NumColumns;
            int numRowsQ      = numColsQ;
            int numReflectors = NumRows;
            int leadingDimQ   = numRowsQ;

            LapackLeastSquares.Dorglq(numRowsQ, numColsQ, numReflectors, matrixQ, 0, leadingDimQ, reflectorScalars, 0);
            return(Matrix.CreateFromArray(matrixQ, NumColumns, NumColumns, false));
        }
예제 #5
0
        /// <summary>
        /// Explicitly creates the orthogonal matrix Q that resulted from the factorization: A = Q * R, where A is m-by-n,
        /// Q is m-by-m and R is m-by-n.
        /// This method is safe to use as the factorization data are copied (if necessary). However, it is inefficient if the
        /// generated matrix is only used once.
        /// </summary>
        public Matrix GetFactorQ()
        {
            if (NumRows < NumColumns)
            {
                throw new NotImplementedException("For now, the number of rows must be >= the number of columns");
            }

            // We need a larger buffer for Q (m-by-m) > reflectorsAndR (m-by-p)
            double[] matrixQ = ArrayColMajor.ResizeCols(NumRows, NumColumns, NumRows, reflectorsAndR);

            // Call Lapack
            int numRowsQ      = NumRows;
            int numColsQ      = numRowsQ;
            int numReflectors = NumColumns;
            int leadingDimQ   = numRowsQ;

            LapackLeastSquares.Dorgqr(numRowsQ, numColsQ, numReflectors, matrixQ, 0, leadingDimQ, reflectorScalars, 0);

            return(Matrix.CreateFromArray(matrixQ, NumRows, NumRows, false));
        }
예제 #6
0
        /// <summary>
        /// Solve the linear least squares problem A * x = b => x = inv(R) * transpose(Q) * b.
        /// Warning: the columns of the original matrix A must be independent for this to work.
        /// </summary>
        /// <param name="rhsVector">The right hand side vector b. It may lie outside the column space of the original matrix. Its
        ///     <see cref="IIndexable1D.Length"/> must be equal to this.<see cref="NumRows"/>.</param>
        /// <exception cref="Exceptions.LapackException">Thrown if the call to LAPACK fails due to <paramref name="rhsVector"/>
        ///     having a different <see cref="IIndexable1D.Length"/> than this.<see cref="NumRows"/>.</exception>
        public Vector SolveLeastSquares(Vector rhsVector) //TODO: perhaps I should use the driver routines of LAPACKE
        {
            if (NumRows < NumColumns)
            {
                throw new NotImplementedException("For now, the number of rows must be >= the number of columns");
            }
            Preconditions.CheckSystemSolutionDimensions(NumRows, rhsVector.Length);

            // Least squares: x = inv(A^T * A) * A^T * b = inv(R) * Q^T * b, where b is the right hand side vector.
            // Step 1: c = Q^T * b. Q is m-by-m, b is m-by-1 => c is m-by-1
            double[] c             = rhsVector.CopyToArray();
            int      numRowsC      = rhsVector.Length;
            int      numColsC      = 1; // rhs = m-by-1
            int      numReflectors = reflectorScalars.Length;
            int      leadingDimA   = numRowsC;
            int      leadingDimC   = numRowsC;

            LapackLeastSquares.Dormqr(MultiplicationSide.Left, TransposeMatrix.Transpose, numRowsC, numColsC, numReflectors,
                                      reflectorsAndR, 0, leadingDimA, reflectorScalars, 0, c, 0, leadingDimC);

            // Step 2: R * x = c, with R being m-by-n and upper trapezoidal (because m >= n).
            // Decomposing R: [R1; 0] * x = [c1 ; c2 ] => R1 * x = c1 => R1 * x = c1, with R1 being n-by-n, upper triangular
            // and stored in the factorized col major data. c1 and x are both n-by-1. The information stored in c2 is lost due to
            // the least squares approximation.
            // TODO: I do not really need to discard the extra m-n terms of c2, but I think it is unsafe to carry them around and
            // risk some method of Vector using the length of the internal buffer, instead of its Length propert.
            if (NumRows > NumColumns)
            {
                Array.Resize <double>(ref c, NumColumns);
            }
            int n    = NumColumns; // Order of matrix R1
            int ldR  = NumRows;    // R1 is stored in the upper trapezoid of a NumRows * NumColumns col major array.
            int incC = 1;          // step in rhs array, which is the same c used for Q^T * b

            Blas.Dtrsv(StoredTriangle.Upper, TransposeMatrix.NoTranspose, DiagonalValues.NonUnit,
                       n, reflectorsAndR, 0, ldR, c, 0, incC);
            // TODO: Check output of BLAS somehow. E.g. Zero diagonal entries will result in NaN in the result vector.
            return(Vector.CreateFromArray(c, false));
        }