#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; } #ifdef STORM_HAVE_CARL EigenLinearEquationSolverSettings::EigenLinearEquationSolverSettings() { // Intentionally left empty. } EigenLinearEquationSolverSettings::EigenLinearEquationSolverSettings() { // Intentionally left empty. } #endif 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) { this->setMatrix(std::move(A)); } template void EigenLinearEquationSolver::setMatrix(storm::storage::SparseMatrix const& A) { eigenA = storm::adapters::EigenAdapter::toEigenSparseMatrix(A); } template void EigenLinearEquationSolver::setMatrix(storm::storage::SparseMatrix&& A) { // Take ownership of the matrix so it is destroyed after we have translated it to Eigen's format. storm::storage::SparseMatrix localA(std::move(A)); this->setMatrix(localA); } template bool EigenLinearEquationSolver::solveEquations(std::vector& x, std::vector const& b) 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); return solver.info() == Eigen::ComputationInfo::Success; } 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); return solver.info() == Eigen::ComputationInfo::Success; } 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); return solver.info() == Eigen::ComputationInfo::Success; } } 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); return solver.info() == Eigen::ComputationInfo::Success; } 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); return solver.info() == Eigen::ComputationInfo::Success; } 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); return solver.info() == Eigen::ComputationInfo::Success; } } 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); return solver.info() == Eigen::ComputationInfo::Success; } 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); return solver.info() == Eigen::ComputationInfo::Success; } 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); return solver.info() == Eigen::ComputationInfo::Success; } } } return false; } template void EigenLinearEquationSolver::multiply(std::vector& x, std::vector const* b, std::vector& result) const { // Typedef the map-type so we don't have to spell it out. typedef decltype(Eigen::Matrix::Map(b->data(), b->size())) MapType; auto eigenX = Eigen::Matrix::Map(x.data(), x.size()); auto eigenResult = Eigen::Matrix::Map(result.data(), result.size()); std::unique_ptr eigenB; if (b != nullptr) { eigenB = std::make_unique(Eigen::Matrix::Map(b->data(), b->size())); } if (&x != &result) { if (b != nullptr) { eigenResult.noalias() = *eigenA * eigenX + *eigenB; } else { eigenResult.noalias() = *eigenA * eigenX; } } else { if (b != nullptr) { eigenResult = *eigenA * eigenX + *eigenB; } else { eigenResult = *eigenA * eigenX; } } } template EigenLinearEquationSolverSettings& EigenLinearEquationSolver::getSettings() { return settings; } template EigenLinearEquationSolverSettings const& EigenLinearEquationSolver::getSettings() const { return settings; } template uint64_t EigenLinearEquationSolver::getMatrixRowCount() const { return eigenA->rows(); } template uint64_t EigenLinearEquationSolver::getMatrixColumnCount() const { return eigenA->cols(); } #ifdef STORM_HAVE_CARL // Specialization for storm::RationalNumber template<> bool EigenLinearEquationSolver::solveEquations(std::vector& x, std::vector const& b) 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); return solver.info() == Eigen::ComputationInfo::Success; } // Specialization for storm::RationalFunction template<> bool EigenLinearEquationSolver::solveEquations(std::vector& x, std::vector const& b) 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); return solver.info() == Eigen::ComputationInfo::Success; } #endif 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 std::unique_ptr> EigenLinearEquationSolverFactory::clone() const { return std::make_unique>(*this); } template class EigenLinearEquationSolverSettings; template class EigenLinearEquationSolver; template class EigenLinearEquationSolverFactory; #ifdef STORM_HAVE_CARL template class EigenLinearEquationSolverSettings; template class EigenLinearEquationSolverSettings; template class EigenLinearEquationSolver; template class EigenLinearEquationSolver; template class EigenLinearEquationSolverFactory; template class EigenLinearEquationSolverFactory; #endif } }