protected override Matrix InverseSystemMatrixTimesOtherMatrix(IMatrixView otherMatrix) { var watch = new Stopwatch(); // Factorization if (mustFactorize) { watch.Start(); factorization = CholeskySuiteSparse.Factorize(linearSystem.Matrix, useSuperNodalFactorization); watch.Stop(); Logger.LogTaskDuration("Matrix factorization", watch.ElapsedMilliseconds); watch.Reset(); mustFactorize = false; } // Substitutions watch.Start(); Matrix solutionVectors; if (otherMatrix is Matrix otherDense) { return(factorization.SolveLinearSystems(otherDense)); } else { try { // If there is enough memory, copy the RHS matrix to a dense one, to speed up computations. //TODO: must be benchmarked, if it is actually more efficient than solving column by column. Matrix rhsVectors = otherMatrix.CopyToFullMatrix(); solutionVectors = factorization.SolveLinearSystems(rhsVectors); } catch (InsufficientMemoryException) //TODO: what about OutOfMemoryException? { // Solution vectors int systemOrder = linearSystem.Matrix.NumColumns; int numRhs = otherMatrix.NumColumns; solutionVectors = Matrix.CreateZero(systemOrder, numRhs); Vector solutionVector = linearSystem.CreateZeroVectorConcrete(); // Solve each linear system separately, to avoid copying the RHS matrix to a dense one. for (int j = 0; j < numRhs; ++j) { if (j != 0) { solutionVector.Clear(); } Vector rhsVector = otherMatrix.GetColumn(j); factorization.SolveLinearSystem(rhsVector, solutionVector); solutionVectors.SetSubcolumn(j, solutionVector); } } } watch.Stop(); Logger.LogTaskDuration("Back/forward substitutions", watch.ElapsedMilliseconds); Logger.IncrementAnalysisStep(); return(solutionVectors); }
protected override Matrix InverseSystemMatrixTimesOtherMatrix(IMatrixView otherMatrix) { //TODO: Use a reorthogonalizetion approach when solving multiple rhs vectors. It would be even better if the CG // algorithm exposed a method for solving for multiple rhs vectors. var watch = new Stopwatch(); // Preconditioning if (mustUpdatePreconditioner) { watch.Start(); preconditioner = preconditionerFactory.CreatePreconditionerFor(linearSystem.Matrix); watch.Stop(); Logger.LogTaskDuration("Calculating preconditioner", watch.ElapsedMilliseconds); watch.Reset(); mustUpdatePreconditioner = false; } // Iterative algorithm watch.Start(); int systemOrder = linearSystem.Matrix.NumColumns; int numRhs = otherMatrix.NumColumns; var solutionVectors = Matrix.CreateZero(systemOrder, numRhs); Vector solutionVector = linearSystem.CreateZeroVectorConcrete(); // Solve each linear system for (int j = 0; j < numRhs; ++j) { if (j != 0) { solutionVector.Clear(); } //TODO: we should make sure this is the same type as the vectors used by this solver, otherwise vector operations // in CG will be slow. Vector rhsVector = otherMatrix.GetColumn(j); IterativeStatistics stats = pcgAlgorithm.Solve(linearSystem.Matrix, preconditioner, rhsVector, solutionVector, true, () => linearSystem.CreateZeroVector()); solutionVectors.SetSubcolumn(j, solutionVector); } watch.Stop(); Logger.LogTaskDuration("Iterative algorithm", watch.ElapsedMilliseconds); Logger.IncrementAnalysisStep(); return(solutionVectors); }