diff --git a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp index 1975ebf45..b390327c0 100644 --- a/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp +++ b/src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp @@ -12,6 +12,7 @@ #include "storm/settings/modules/MinMaxEquationSolverSettings.h" #include "storm/environment/Environment.h" +#include "storm/environment/solver/MinMaxSolverEnvironment.h" #include "storm/utility/macros.h" #include "storm/utility/vector.h" @@ -655,6 +656,12 @@ namespace storm { std::vector stateToMecIndexMap(numberOfStates); storm::storage::BitVector statesInMecs(numberOfStates); + auto underlyingSolverEnvironment = env; + if (env.solver().isForceSoundness()) { + // For sound computations, the error in the MECS plus the error in the remaining system should be less then the user defined precsion. + underlyingSolverEnvironment.solver().minMax().setPrecision(env.solver().minMax().getPrecision() / storm::utility::convertNumber(2)); + } + for (uint64_t currentMecIndex = 0; currentMecIndex < mecDecomposition.size(); ++currentMecIndex) { storm::storage::MaximalEndComponent const& mec = mecDecomposition[currentMecIndex]; @@ -667,7 +674,7 @@ namespace storm { } // Compute the LRA value for the current MEC. - lraValuesForEndComponents.push_back(computeLraForMaximalEndComponent(env, dir, transitionMatrix, exitRateVector, markovianStates, rewardModel, mec)); + lraValuesForEndComponents.push_back(computeLraForMaximalEndComponent(underlyingSolverEnvironment, dir, transitionMatrix, exitRateVector, markovianStates, rewardModel, mec)); } // For fast transition rewriting, we build some auxiliary data structures. @@ -770,16 +777,16 @@ namespace storm { // Check for requirements of the solver. storm::solver::GeneralMinMaxLinearEquationSolverFactory minMaxLinearEquationSolverFactory; - storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, true, dir); + storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(underlyingSolverEnvironment, true, dir); requirements.clearBounds(); STORM_LOG_THROW(!requirements.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + requirements.getEnabledRequirementsAsString() + " not checked."); - std::unique_ptr> solver = minMaxLinearEquationSolverFactory.create(env, sspMatrix); + std::unique_ptr> solver = minMaxLinearEquationSolverFactory.create(underlyingSolverEnvironment, sspMatrix); solver->setHasUniqueSolution(); solver->setLowerBound(storm::utility::zero()); solver->setUpperBound(*std::max_element(lraValuesForEndComponents.begin(), lraValuesForEndComponents.end())); solver->setRequirementsChecked(); - solver->solveEquations(env, dir, x, b); + solver->solveEquations(underlyingSolverEnvironment, dir, x, b); // Prepare result vector. std::vector result(numberOfStates); @@ -830,6 +837,9 @@ namespace storm { if (storm::NumberTraits::IsExact && minMaxSettings.isLraMethodSetFromDefaultValue() && method != storm::solver::LraMethod::LinearProgramming) { STORM_LOG_INFO("Selecting 'LP' as the solution technique for long-run properties to guarantee exact results. If you want to override this, please explicitly specify a different LRA method."); method = storm::solver::LraMethod::LinearProgramming; + } else if (env.solver().isForceSoundness() && minMaxSettings.isLraMethodSetFromDefaultValue() && method != storm::solver::LraMethod::ValueIteration) { + STORM_LOG_INFO("Selecting 'VI' as the solution technique for long-run properties to guarantee sound results. If you want to override this, please explicitly specify a different LRA method."); + method = storm::solver::LraMethod::ValueIteration; } if (method == storm::solver::LraMethod::LinearProgramming) { return computeLraForMaximalEndComponentLP(env, dir, transitionMatrix, exitRateVector, markovianStates, rewardModel, mec); @@ -980,7 +990,8 @@ namespace storm { // start the iterations - ValueType precision = storm::utility::convertNumber(storm::settings::getModule().getPrecision()) / uniformizationRate; + ValueType precision = storm::utility::convertNumber(env.solver().minMax().getPrecision()) / uniformizationRate; + bool relative = env.solver().minMax().getRelativeTerminationCriterion(); std::vector v(aMarkovian.getRowCount(), storm::utility::zero()); std::vector w = v; std::vector x(aProbabilistic.getRowGroupCount(), storm::utility::zero()); @@ -1019,7 +1030,7 @@ namespace storm { } // Check for convergence - if (maxDiff - minDiff < precision) { + if (maxDiff - minDiff <= relative ? (precision * minDiff) : precision) { break; } diff --git a/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp b/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp index 7e1d6e45c..310360ac5 100644 --- a/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp +++ b/src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp @@ -1328,10 +1328,16 @@ namespace storm { std::vector stateToMecIndexMap(transitionMatrix.getColumnCount()); std::vector lraValuesForEndComponents(mecDecomposition.size(), zero); + auto underlyingSolverEnvironment = env; + if (env.solver().isForceSoundness()) { + // For sound computations, the error in the MECS plus the error in the remaining system should be less then the user defined precsion. + underlyingSolverEnvironment.solver().minMax().setPrecision(env.solver().minMax().getPrecision() / storm::utility::convertNumber(2)); + } + for (uint_fast64_t currentMecIndex = 0; currentMecIndex < mecDecomposition.size(); ++currentMecIndex) { storm::storage::MaximalEndComponent const& mec = mecDecomposition[currentMecIndex]; - lraValuesForEndComponents[currentMecIndex] = computeLraForMaximalEndComponent(env, goal.direction(), transitionMatrix, rewardModel, mec); + lraValuesForEndComponents[currentMecIndex] = computeLraForMaximalEndComponent(underlyingSolverEnvironment, goal.direction(), transitionMatrix, rewardModel, mec); // Gather information for later use. for (auto const& stateChoicesPair : mec) { @@ -1438,19 +1444,19 @@ namespace storm { // Check for requirements of the solver. storm::solver::GeneralMinMaxLinearEquationSolverFactory minMaxLinearEquationSolverFactory; - storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(env, true, goal.direction()); + storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(underlyingSolverEnvironment, true, goal.direction()); requirements.clearBounds(); STORM_LOG_THROW(!requirements.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException, "Solver requirements " + requirements.getEnabledRequirementsAsString() + " not checked."); std::vector sspResult(numberOfSspStates); goal.restrictRelevantValues(statesNotContainedInAnyMec); - std::unique_ptr> solver = storm::solver::configureMinMaxLinearEquationSolver(env, std::move(goal), minMaxLinearEquationSolverFactory, sspMatrix); + std::unique_ptr> solver = storm::solver::configureMinMaxLinearEquationSolver(underlyingSolverEnvironment, std::move(goal), minMaxLinearEquationSolverFactory, sspMatrix); solver->setLowerBound(storm::utility::zero()); solver->setUpperBound(*std::max_element(lraValuesForEndComponents.begin(), lraValuesForEndComponents.end())); solver->setHasUniqueSolution(); solver->setRequirementsChecked(); - solver->solveEquations(env, sspResult, b); + solver->solveEquations(underlyingSolverEnvironment, sspResult, b); // Prepare result vector. std::vector result(numberOfStates, zero); @@ -1491,6 +1497,9 @@ namespace storm { if (storm::NumberTraits::IsExact && minMaxSettings.isLraMethodSetFromDefaultValue() && method != storm::solver::LraMethod::LinearProgramming) { STORM_LOG_INFO("Selecting 'LP' as the solution technique for long-run properties to guarantee exact results. If you want to override this, please explicitly specify a different LRA method."); method = storm::solver::LraMethod::LinearProgramming; + } else if (env.solver().isForceSoundness() && minMaxSettings.isLraMethodSetFromDefaultValue() && method != storm::solver::LraMethod::ValueIteration) { + STORM_LOG_INFO("Selecting 'VI' as the solution technique for long-run properties to guarantee sound results. If you want to override this, please explicitly specify a different LRA method."); + method = storm::solver::LraMethod::ValueIteration; } if (method == storm::solver::LraMethod::LinearProgramming) { return computeLraForMaximalEndComponentLP(env, dir, transitionMatrix, rewardModel, mec); @@ -1563,7 +1572,8 @@ namespace storm { STORM_LOG_ASSERT(mecTransitions.isProbabilistic(), "The MEC-Matrix is not probabilistic."); // start the iterations - ValueType precision = storm::utility::convertNumber(storm::settings::getModule().getPrecision()); + ValueType precision = storm::utility::convertNumber(env.solver().minMax().getPrecision()); + bool relative = env.solver().minMax().getRelativeTerminationCriterion(); std::vector x(mecTransitions.getRowGroupCount(), storm::utility::zero()); std::vector xPrime = x; @@ -1590,7 +1600,7 @@ namespace storm { *xPrimeIt = *xIt; } - if ((maxDiff - minDiff) < precision) { + if ((maxDiff - minDiff) <= relative ? (precision * minDiff) : precision) { break; } }