#include "src/solver/EigenLinearEquationSolver.h" #include "src/adapters/EigenAdapter.h" #include "src/settings/SettingsManager.h" #include "src/settings/modules/EigenEquationSolverSettings.h" #include "src/utility/macros.h" #include "src/exceptions/InvalidSettingsException.h" namespace storm { namespace solver { template EigenLinearEquationSolverSettings::EigenLinearEquationSolverSettings() { // Get the settings object to customize linear solving. storm::settings::modules::EigenEquationSolverSettings const& settings = storm::settings::getModule(); // Get appropriate settings. maximalNumberOfIterations = settings.getMaximalIterationCount(); precision = settings.getPrecision(); restart = settings.getRestartIterationCount(); // Determine the method to be used. storm::settings::modules::EigenEquationSolverSettings::LinearEquationMethod methodAsSetting = settings.getLinearEquationSystemMethod(); if (methodAsSetting == storm::settings::modules::EigenEquationSolverSettings::LinearEquationMethod::BiCGSTAB) { method = SolutionMethod::BiCGSTAB; } else if (methodAsSetting == storm::settings::modules::EigenEquationSolverSettings::LinearEquationMethod::SparseLU) { method = SolutionMethod::SparseLU; } else if (methodAsSetting == storm::settings::modules::EigenEquationSolverSettings::LinearEquationMethod::DGMRES) { method = SolutionMethod::DGMRES; } else if (methodAsSetting == storm::settings::modules::EigenEquationSolverSettings::LinearEquationMethod::GMRES) { method = SolutionMethod::GMRES; } // Check which preconditioner to use. storm::settings::modules::EigenEquationSolverSettings::PreconditioningMethod preconditionAsSetting = settings.getPreconditioningMethod(); if (preconditionAsSetting == storm::settings::modules::EigenEquationSolverSettings::PreconditioningMethod::Ilu) { preconditioner = Preconditioner::Ilu; } else if (preconditionAsSetting == storm::settings::modules::EigenEquationSolverSettings::PreconditioningMethod::Diagonal) { preconditioner = Preconditioner::Diagonal; } else if (preconditionAsSetting == storm::settings::modules::EigenEquationSolverSettings::PreconditioningMethod::None) { preconditioner = Preconditioner::None; } } template void EigenLinearEquationSolverSettings::setSolutionMethod(SolutionMethod const& method) { this->method = method; } template void EigenLinearEquationSolverSettings::setPreconditioner(Preconditioner const& preconditioner) { this->preconditioner = preconditioner; } template void EigenLinearEquationSolverSettings::setPrecision(ValueType precision) { this->precision = precision; } template void EigenLinearEquationSolverSettings::setMaximalNumberOfIterations(uint64_t maximalNumberOfIterations) { this->maximalNumberOfIterations = maximalNumberOfIterations; } template void EigenLinearEquationSolverSettings::setNumberOfIterationsUntilRestart(uint64_t restart) { this->restart = restart; } template typename EigenLinearEquationSolverSettings::SolutionMethod EigenLinearEquationSolverSettings::getSolutionMethod() const { return this->method; } template typename EigenLinearEquationSolverSettings::Preconditioner EigenLinearEquationSolverSettings::getPreconditioner() const { return this->preconditioner; } template ValueType EigenLinearEquationSolverSettings::getPrecision() const { return this->precision; } template uint64_t EigenLinearEquationSolverSettings::getMaximalNumberOfIterations() const { return this->maximalNumberOfIterations; } template uint64_t EigenLinearEquationSolverSettings::getNumberOfIterationsUntilRestart() const { return restart; } EigenLinearEquationSolverSettings::EigenLinearEquationSolverSettings() { // Intentionally left empty. } EigenLinearEquationSolverSettings::EigenLinearEquationSolverSettings() { // Intentionally left empty. } template EigenLinearEquationSolver::EigenLinearEquationSolver(storm::storage::SparseMatrix const& A, EigenLinearEquationSolverSettings const& settings) : eigenA(storm::adapters::EigenAdapter::toEigenSparseMatrix(A)), settings(settings) { // Intentionally left empty. } template EigenLinearEquationSolver::EigenLinearEquationSolver(storm::storage::SparseMatrix&& A, EigenLinearEquationSolverSettings const& settings) : settings(settings) { storm::storage::SparseMatrix localA(std::move(A)); eigenA = storm::adapters::EigenAdapter::toEigenSparseMatrix(localA); } template void EigenLinearEquationSolver::solveEquationSystem(std::vector& x, std::vector const& b, std::vector* multiplyResult) const { // Map the input vectors to Eigen's format. auto eigenX = Eigen::Matrix::Map(x.data(), x.size()); auto eigenB = Eigen::Matrix::Map(b.data(), b.size()); typename EigenLinearEquationSolverSettings::SolutionMethod solutionMethod = this->getSettings().getSolutionMethod(); if (solutionMethod == EigenLinearEquationSolverSettings::SolutionMethod::SparseLU) { Eigen::SparseLU, Eigen::COLAMDOrdering> solver; solver.compute(*this->eigenA); solver._solve_impl(eigenB, eigenX); } else { typename EigenLinearEquationSolverSettings::Preconditioner preconditioner = this->getSettings().getPreconditioner(); if (solutionMethod == EigenLinearEquationSolverSettings::SolutionMethod::BiCGSTAB) { if (preconditioner == EigenLinearEquationSolverSettings::Preconditioner::Ilu) { Eigen::BiCGSTAB, Eigen::IncompleteLUT> solver; solver.compute(*this->eigenA); solver.setTolerance(this->getSettings().getPrecision()); solver.setMaxIterations(this->getSettings().getMaximalNumberOfIterations()); eigenX = solver.solveWithGuess(eigenB, eigenX); } else if (preconditioner == EigenLinearEquationSolverSettings::Preconditioner::Diagonal) { Eigen::BiCGSTAB, Eigen::DiagonalPreconditioner> solver; solver.setTolerance(this->getSettings().getPrecision()); solver.setMaxIterations(this->getSettings().getMaximalNumberOfIterations()); solver.compute(*this->eigenA); eigenX = solver.solveWithGuess(eigenB, eigenX); } else { Eigen::BiCGSTAB, Eigen::IdentityPreconditioner> solver; solver.setTolerance(this->getSettings().getPrecision()); solver.setMaxIterations(this->getSettings().getMaximalNumberOfIterations()); solver.compute(*this->eigenA); eigenX = solver.solveWithGuess(eigenB, eigenX); } } else if (solutionMethod == EigenLinearEquationSolverSettings::SolutionMethod::DGMRES) { if (preconditioner == EigenLinearEquationSolverSettings::Preconditioner::Ilu) { Eigen::DGMRES, Eigen::IncompleteLUT> solver; solver.setTolerance(this->getSettings().getPrecision()); solver.setMaxIterations(this->getSettings().getMaximalNumberOfIterations()); solver.set_restart(this->getSettings().getNumberOfIterationsUntilRestart()); solver.compute(*this->eigenA); eigenX = solver.solveWithGuess(eigenB, eigenX); } else if (preconditioner == EigenLinearEquationSolverSettings::Preconditioner::Diagonal) { Eigen::DGMRES, Eigen::DiagonalPreconditioner> solver; solver.setTolerance(this->getSettings().getPrecision()); solver.setMaxIterations(this->getSettings().getMaximalNumberOfIterations()); solver.set_restart(this->getSettings().getNumberOfIterationsUntilRestart()); solver.compute(*this->eigenA); eigenX = solver.solveWithGuess(eigenB, eigenX); } else { Eigen::DGMRES, Eigen::IdentityPreconditioner> solver; solver.setTolerance(this->getSettings().getPrecision()); solver.setMaxIterations(this->getSettings().getMaximalNumberOfIterations()); solver.set_restart(this->getSettings().getNumberOfIterationsUntilRestart()); solver.compute(*this->eigenA); eigenX = solver.solveWithGuess(eigenB, eigenX); } } else if (solutionMethod == EigenLinearEquationSolverSettings::SolutionMethod::GMRES) { if (preconditioner == EigenLinearEquationSolverSettings::Preconditioner::Ilu) { Eigen::GMRES, Eigen::IncompleteLUT> solver; solver.setTolerance(this->getSettings().getPrecision()); solver.setMaxIterations(this->getSettings().getMaximalNumberOfIterations()); solver.set_restart(this->getSettings().getNumberOfIterationsUntilRestart()); solver.compute(*this->eigenA); eigenX = solver.solveWithGuess(eigenB, eigenX); } else if (preconditioner == EigenLinearEquationSolverSettings::Preconditioner::Diagonal) { Eigen::GMRES, Eigen::DiagonalPreconditioner> solver; solver.setTolerance(this->getSettings().getPrecision()); solver.setMaxIterations(this->getSettings().getMaximalNumberOfIterations()); solver.set_restart(this->getSettings().getNumberOfIterationsUntilRestart()); solver.compute(*this->eigenA); eigenX = solver.solveWithGuess(eigenB, eigenX); } else { Eigen::GMRES, Eigen::IdentityPreconditioner> solver; solver.setTolerance(this->getSettings().getPrecision()); solver.setMaxIterations(this->getSettings().getMaximalNumberOfIterations()); solver.set_restart(this->getSettings().getNumberOfIterationsUntilRestart()); solver.compute(*this->eigenA); eigenX = solver.solveWithGuess(eigenB, eigenX); } } } } template void EigenLinearEquationSolver::performMatrixVectorMultiplication(std::vector& x, std::vector const* b, uint_fast64_t n, std::vector* multiplyResult) const { // Typedef the map-type so we don't have to spell it out. typedef decltype(Eigen::Matrix::Map(b->data(), b->size())) MapType; bool multiplyResultProvided = multiplyResult != nullptr; if (!multiplyResult) { multiplyResult = new std::vector(eigenA->cols()); } auto eigenMultiplyResult = Eigen::Matrix::Map(multiplyResult->data(), multiplyResult->size()); // Map the input vectors x and b to Eigen's format. std::unique_ptr eigenB; if (b != nullptr) { eigenB = std::make_unique(Eigen::Matrix::Map(b->data(), b->size())); } auto eigenX = Eigen::Matrix::Map(x.data(), x.size()); // Perform n matrix-vector multiplications. auto currentX = &eigenX; auto nextX = &eigenMultiplyResult; for (uint64_t iteration = 0; iteration < n; ++iteration) { if (eigenB) { nextX->noalias() = *eigenA * *currentX + *eigenB; } else { nextX->noalias() = *eigenA * *currentX; } std::swap(nextX, currentX); } // If the last result we obtained is not the one in the input vector x, we swap the result there. if (currentX != &eigenX) { std::swap(*nextX, *currentX); } if (!multiplyResultProvided) { delete multiplyResult; } } template EigenLinearEquationSolverSettings& EigenLinearEquationSolver::getSettings() { return settings; } template EigenLinearEquationSolverSettings const& EigenLinearEquationSolver::getSettings() const { return settings; } // Specialization form storm::RationalNumber template<> void EigenLinearEquationSolver::solveEquationSystem(std::vector& x, std::vector const& b, std::vector* multiplyResult) const { // Map the input vectors to Eigen's format. auto eigenX = Eigen::Matrix::Map(x.data(), x.size()); auto eigenB = Eigen::Matrix::Map(b.data(), b.size()); Eigen::SparseLU, Eigen::COLAMDOrdering> solver; solver.compute(*eigenA); solver._solve_impl(eigenB, eigenX); } template<> void EigenLinearEquationSolver::performMatrixVectorMultiplication(std::vector& x, std::vector const* b, uint_fast64_t n, std::vector* multiplyResult) const { // Typedef the map-type so we don't have to spell it out. typedef decltype(Eigen::Matrix::Map(b->data(), b->size())) MapType; bool multiplyResultProvided = multiplyResult != nullptr; if (!multiplyResult) { multiplyResult = new std::vector(eigenA->cols()); } auto eigenMultiplyResult = Eigen::Matrix::Map(multiplyResult->data(), multiplyResult->size()); // Map the input vectors x and b to Eigen's format. std::unique_ptr eigenB; if (b != nullptr) { eigenB = std::make_unique(Eigen::Matrix::Map(b->data(), b->size())); } auto eigenX = Eigen::Matrix::Map(x.data(), x.size()); // Perform n matrix-vector multiplications. auto currentX = &eigenX; auto nextX = &eigenMultiplyResult; for (uint64_t iteration = 0; iteration < n; ++iteration) { if (eigenB) { nextX->noalias() = *eigenA * *currentX + *eigenB; } else { nextX->noalias() = *eigenA * *currentX; } } // If the last result we obtained is not the one in the input vector x, we swap the result there. if (currentX != &eigenX) { std::swap(*nextX, *currentX); } if (!multiplyResultProvided) { delete multiplyResult; } } // Specialization form storm::RationalFunction template<> void EigenLinearEquationSolver::solveEquationSystem(std::vector& x, std::vector const& b, std::vector* multiplyResult) const { // Map the input vectors to Eigen's format. auto eigenX = Eigen::Matrix::Map(x.data(), x.size()); auto eigenB = Eigen::Matrix::Map(b.data(), b.size()); Eigen::SparseLU, Eigen::COLAMDOrdering> solver; solver.compute(*eigenA); solver._solve_impl(eigenB, eigenX); } template<> void EigenLinearEquationSolver::performMatrixVectorMultiplication(std::vector& x, std::vector const* b, uint_fast64_t n, std::vector* multiplyResult) const { // Typedef the map-type so we don't have to spell it out. typedef decltype(Eigen::Matrix::Map(b->data(), b->size())) MapType; bool multiplyResultProvided = multiplyResult != nullptr; if (!multiplyResult) { multiplyResult = new std::vector(eigenA->cols()); } auto eigenMultiplyResult = Eigen::Matrix::Map(multiplyResult->data(), multiplyResult->size()); // Map the input vectors x and b to Eigen's format. std::unique_ptr eigenB; if (b != nullptr) { eigenB = std::make_unique(Eigen::Matrix::Map(b->data(), b->size())); } auto eigenX = Eigen::Matrix::Map(x.data(), x.size()); // Perform n matrix-vector multiplications. auto currentX = &eigenX; auto nextX = &eigenMultiplyResult; for (uint64_t iteration = 0; iteration < n; ++iteration) { if (eigenB) { nextX->noalias() = *eigenA * *currentX + *eigenB; } else { nextX->noalias() = *eigenA * *currentX; } } // If the last result we obtained is not the one in the input vector x, we swap the result there. if (currentX != &eigenX) { std::swap(*nextX, *currentX); } if (!multiplyResultProvided) { delete multiplyResult; } } template std::unique_ptr> EigenLinearEquationSolverFactory::create(storm::storage::SparseMatrix const& matrix) const { return std::make_unique>(matrix, settings); } template std::unique_ptr> EigenLinearEquationSolverFactory::create(storm::storage::SparseMatrix&& matrix) const { return std::make_unique>(std::move(matrix), settings); } template EigenLinearEquationSolverSettings& EigenLinearEquationSolverFactory::getSettings() { return settings; } template EigenLinearEquationSolverSettings const& EigenLinearEquationSolverFactory::getSettings() const { return settings; } template class EigenLinearEquationSolverSettings; template class EigenLinearEquationSolverSettings; template class EigenLinearEquationSolverSettings; template class EigenLinearEquationSolver; template class EigenLinearEquationSolver; template class EigenLinearEquationSolver; template class EigenLinearEquationSolverFactory; template class EigenLinearEquationSolverFactory; template class EigenLinearEquationSolverFactory; } }