/// <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));
        }
        /// <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));
        }
 /// <summary>
 /// See https://software.intel.com/en-us/mkl-developer-reference-fortran-trsv#D8733073-F041-4AA1-B82C-123DFA993AD7
 /// </summary>
 public void Dtrsv(StoredTriangle uplo, TransposeMatrix transA, DiagonalValues diag, int n,
                   double[] a, int offsetA, int ldA, double[] x, int offsetX, int incX)
 => Blas.Dtrsv(uplo.Translate(), transA.Translate(), diag.Translate(), ref n, ref a[offsetA], ref ldA,
               ref x[offsetX], ref incX);