private static void TestSystemSolutionFullUpper()
        {
            int n         = SymmPosDef10by10.Order;
            var A         = Matrix.CreateFromArray(SymmPosDef10by10.Matrix);
            var b         = SymmPosDef10by10.Rhs;
            var xExpected = SymmPosDef10by10.Lhs;

            // Factorization
            CholeskyFactorizations.FactorizeFullUpper2(A.NumColumns, A, pivotTolerance);

            // Forward substitution
            var x1Computed = new double[n];
            var x2Computed = new double[n];

            CholeskyFactorizations.ForwardSubstitutionFullUpper(n, A, b, x1Computed);
            CholeskyFactorizations.ForwardSubstitutionFullUpper(n, A, b, x2Computed);

            // Back substitution - column / vector version
            CholeskyFactorizations.BackSubstitutionFullUpper1(n, A, x1Computed);
            comparer.AssertEqual(xExpected, x1Computed);

            // Back substitution - dot version
            CholeskyFactorizations.BackSubstitutionFullUpper2(n, A, x2Computed);
            comparer.AssertEqual(xExpected, x2Computed);
        }
        /// <summary>
        /// Performs the operation: <paramref name="result"/> = generalized_inverse(A) * <paramref name="vector"/>
        /// </summary>
        /// <param name="vector">The vector that will be multiplied. Its <see cref="IIndexable1D.Length"/> must be equal to
        /// <see cref="IIndexable2D.NumRows"/> of the original matrix A.
        /// </param>
        /// <param name="result">
        /// Output vector that will be overwritten with the solution of the linear system. Its <see cref="IIndexable1D.Length"/>
        /// must be equal to <see cref="IIndexable2D.NumColumns"/> of the original matrix A.
        /// </param>
        /// <exception cref="NonMatchingDimensionsException">
        /// Thrown if <paramref name="vector"/> or <paramref name="result"/> violate the described constraints.
        /// </exception>
        /// <exception cref="IndefiniteMatrixException">
        /// Thrown if the original skyline matrix turns out to not be symmetric positive semi-definite.
        /// </exception>
        public void MultiplyGeneralizedInverseMatrixTimesVector(Vector vector, Vector result)
        {
            Preconditions.CheckSystemSolutionDimensions(Order, vector.Length);
            Preconditions.CheckMultiplicationDimensions(Order, result.Length);

            // TODO: Is this correct?
            CholeskyFactorizations.ForwardSubstitutionFullUpper(Order, upperFactorized, vector.RawData, result.RawData);
            CholeskyFactorizations.BackSubstitutionFullUpper1(Order, upperFactorized, result.RawData);
        }
        public IReadOnlyList <double[]> NullSpaceBasis => nullSpaceBasis; //TODO: return IVectorView

        /// <summary>
        /// Applies the Cholesky factorization to the independent columns of a symmetric positive semi-definite matrix,
        /// sets the dependent ones equal to columns of the identity matrix and return the nullspace of the matrix. Requires
        /// extra memory for the basis vectors of the nullspace.
        /// </summary>
        /// <param name="order">The number of rows/ columns of the square matrix.</param>
        /// <param name="matrix">The matrix to factorize. It will be overwritten with the factorization data.</param>
        /// <param name="pivotTolerance">
        /// If a diagonal entry is &lt;= <paramref name="pivotTolerance"/> it means that the corresponding column is dependent
        /// on the rest. The Cholesky factorization only applies to independent column, while dependent ones are used to compute
        /// the nullspace. Therefore it is important to select a tolerance that will identify small pivots that result from
        /// singularity, but not from ill-conditioning.
        /// </param>
        public static SemidefiniteCholeskyFull Factorize(Matrix matrix, double pivotTolerance = PivotTolerance)
        {
            Preconditions.CheckSquare(matrix);
            int order = matrix.NumColumns;

            (List <int> dependentColumns, List <double[]> nullSpaceBasis) =
                CholeskyFactorizations.FactorizeSemiDefiniteFullUpper1(order, matrix, pivotTolerance);
            Debug.Assert(dependentColumns.Count == nullSpaceBasis.Count);
            return(new SemidefiniteCholeskyFull(order, matrix, dependentColumns, nullSpaceBasis));
        }
        private static void TestFactorizeFullUpper1()
        {
            // positive definite
            var A1         = Matrix.CreateFromArray(SymmPosDef10by10.Matrix);
            var expectedU1 = Matrix.CreateFromArray(SymmPosDef10by10.FactorU);

            CholeskyFactorizations.FactorizeFullUpper1(A1.NumColumns, A1, pivotTolerance);
            var computedU1 = Matrix.CreateFromArray(Conversions.FullUpperColMajorToArray2D(A1.RawData, false));

            comparer.AssertEqual(expectedU1, computedU1);
        }