Browse Source

MinMax Solver requirements now respect whether the solution is known to be unique or not.

tempestpy_adaptions
TimQu 7 years ago
parent
commit
33585c811f
  1. 9
      src/storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.cpp
  2. 16
      src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp
  3. 15
      src/storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.cpp
  4. 55
      src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp
  5. 30
      src/storm/modelchecker/prctl/helper/SymbolicMdpPrctlHelper.cpp
  6. 152
      src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp
  7. 2
      src/storm/solver/IterativeMinMaxLinearEquationSolver.h
  8. 6
      src/storm/solver/LpMinMaxLinearEquationSolver.cpp
  9. 2
      src/storm/solver/LpMinMaxLinearEquationSolver.h
  10. 19
      src/storm/solver/MinMaxLinearEquationSolver.cpp
  11. 18
      src/storm/solver/MinMaxLinearEquationSolver.h
  12. 46
      src/storm/solver/SymbolicMinMaxLinearEquationSolver.cpp
  13. 17
      src/storm/solver/SymbolicMinMaxLinearEquationSolver.h

9
src/storm-pars/modelchecker/region/SparseDtmcParameterLiftingModelChecker.cpp

@ -146,9 +146,9 @@ namespace storm {
lowerResultBound = storm::utility::zero<ConstantType>();
upperResultBound = storm::utility::one<ConstantType>();
auto req = solverFactory->getRequirements(storm::solver::EquationSystemType::UntilProbabilities);
// The solution of the min-max equation system will always be unique (assuming graph-preserving instantiations).
auto req = solverFactory->getRequirements(true);
req.clearBounds();
req.clearNoEndComponents(); // We never have end components within the maybestates (assuming graph-preserving instantiations).
STORM_LOG_THROW(req.empty(), storm::exceptions::UncheckedRequirementException, "Unchecked solver requirement.");
solverFactory->setRequirementsChecked(true);
}
@ -185,8 +185,8 @@ namespace storm {
// We only know a lower bound for the result
lowerResultBound = storm::utility::zero<ConstantType>();
auto req = solverFactory->getRequirements(storm::solver::EquationSystemType::ReachabilityRewards);
req.clearNoEndComponents(); // We never have end components within the maybestates (assuming graph-preserving instantiations).
// The solution of the min-max equation system will always be unique (assuming graph-preserving instantiations).
auto req = solverFactory->getRequirements(true);
req.clearLowerBounds();
if (req.requiresUpperBounds()) {
solvingRequiresUpperRewardBounds = true;
@ -253,6 +253,7 @@ namespace storm {
solverFactory->setMinMaxMethod(storm::solver::MinMaxMethod::PolicyIteration);
}
auto solver = solverFactory->create(parameterLifter->getMatrix());
solver->setHasUniqueSolution();
if (lowerResultBound) solver->setLowerBound(lowerResultBound.get());
if (upperResultBound) {
solver->setUpperBound(upperResultBound.get());

16
src/storm/modelchecker/csl/helper/SparseMarkovAutomatonCslHelper.cpp

@ -89,11 +89,13 @@ namespace storm {
}
// Check for requirements of the solver.
storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(storm::solver::EquationSystemType::UntilProbabilities);
// The solution is unique as we assume non-zeno MAs.
storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(true, dir);
requirements.clearBounds();
STORM_LOG_THROW(requirements.empty(), storm::exceptions::UncheckedRequirementException, "Cannot establish requirements for solver.");
std::unique_ptr<storm::solver::MinMaxLinearEquationSolver<ValueType>> solver = minMaxLinearEquationSolverFactory.create(aProbabilistic);
solver->setHasUniqueSolution();
solver->setBounds(storm::utility::zero<ValueType>(), storm::utility::one<ValueType>());
solver->setRequirementsChecked();
solver->setCachingEnabled(true);
@ -378,12 +380,14 @@ namespace storm {
std::vector<ValueType> x(numberOfSspStates);
// Check for requirements of the solver.
storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(storm::solver::EquationSystemType::StochasticShortestPath);
requirements.clearLowerBounds();
storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(true, dir);
requirements.clearBounds();
STORM_LOG_THROW(requirements.empty(), storm::exceptions::UncheckedRequirementException, "Cannot establish requirements for solver.");
std::unique_ptr<storm::solver::MinMaxLinearEquationSolver<ValueType>> solver = minMaxLinearEquationSolverFactory.create(sspMatrix);
solver->setHasUniqueSolution();
solver->setLowerBound(storm::utility::zero<ValueType>());
solver->setUpperBound(*std::max_element(lraValuesForEndComponents.begin(), lraValuesForEndComponents.end()));
solver->setRequirementsChecked();
solver->solveEquations(dir, x, b);
@ -588,10 +592,14 @@ namespace storm {
std::vector<ValueType> b = probabilisticChoiceRewards;
// Check for requirements of the solver.
storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(storm::solver::EquationSystemType::ReachabilityRewards);
// The solution is unique as we assume non-zeno MAs.
storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(true, dir);
requirements.clearLowerBounds();
STORM_LOG_THROW(requirements.empty(), storm::exceptions::UncheckedRequirementException, "Cannot establish requirements for solver.");
auto solver = minMaxLinearEquationSolverFactory.create(std::move(aProbabilistic));
solver->setLowerBound(storm::utility::zero<ValueType>());
solver->setHasUniqueSolution(true);
solver->setRequirementsChecked(true);
solver->setCachingEnabled(true);

15
src/storm/modelchecker/prctl/helper/HybridMdpPrctlHelper.cpp

@ -135,8 +135,10 @@ namespace storm {
} else {
// If there are maybe states, we need to solve an equation system.
if (!maybeStates.isZero()) {
// If we minimize, we know that the solution to the equation system is unique.
bool uniqueSolution = dir == storm::solver::OptimizationDirection::Minimize;
// Check for requirements of the solver early so we can adjust the maybe state computation accordingly.
storm::solver::MinMaxLinearEquationSolverRequirements requirements = linearEquationSolverFactory.getRequirements(storm::solver::EquationSystemType::UntilProbabilities, dir);
storm::solver::MinMaxLinearEquationSolverRequirements requirements = linearEquationSolverFactory.getRequirements(uniqueSolution, dir);
storm::solver::MinMaxLinearEquationSolverRequirements clearedRequirements = requirements;
SolverRequirementsData<ValueType> solverRequirementsData;
bool extendMaybeStates = false;
@ -212,6 +214,10 @@ namespace storm {
std::vector<ValueType> x(explicitRepresentation.first.getRowGroupCount(), storm::utility::zero<ValueType>());
std::unique_ptr<storm::solver::MinMaxLinearEquationSolver<ValueType>> solver = linearEquationSolverFactory.create(std::move(explicitRepresentation.first));
// Set whether the equation system will have a unique solution
solver->setHasUniqueSolution(uniqueSolution);
if (solverRequirementsData.initialScheduler) {
solver->setInitialScheduler(std::move(solverRequirementsData.initialScheduler.get()));
}
@ -487,8 +493,10 @@ namespace storm {
} else {
// If there are maybe states, we need to solve an equation system.
if (!maybeStates.isZero()) {
// If we maximize, we know that the solution to the equation system is unique.
bool uniqueSolution = dir == storm::solver::OptimizationDirection::Maximize;
// Check for requirements of the solver this early so we can adapt the maybe states accordingly.
storm::solver::MinMaxLinearEquationSolverRequirements requirements = linearEquationSolverFactory.getRequirements(storm::solver::EquationSystemType::ReachabilityRewards, dir);
storm::solver::MinMaxLinearEquationSolverRequirements requirements = linearEquationSolverFactory.getRequirements(uniqueSolution, dir);
storm::solver::MinMaxLinearEquationSolverRequirements clearedRequirements = requirements;
bool extendMaybeStates = false;
if (!clearedRequirements.empty()) {
@ -568,6 +576,9 @@ namespace storm {
// Now solve the resulting equation system.
std::unique_ptr<storm::solver::MinMaxLinearEquationSolver<ValueType>> solver = linearEquationSolverFactory.create();
// Set whether the equation system will have a unique solution
solver->setHasUniqueSolution(uniqueSolution);
// If the solver requires upper bounds, compute them now.
if (requirements.requiresUpperBounds()) {
setUpperRewardBounds(*solver, dir, explicitRepresentation.first, explicitRepresentation.second, solverRequirementsData.oneStepTargetProbabilities.get());

55
src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp

@ -22,7 +22,7 @@
#include "storm/solver/MinMaxLinearEquationSolver.h"
#include "storm/solver/LpSolver.h"
#include "storm/settings/SettingsManager.h"
#include "storm/settings/modules/MinMaxEquationSolverSettings.h"
@ -38,6 +38,11 @@ namespace storm {
namespace modelchecker {
namespace helper {
enum class EquationSystemType {
UntilProbabilities,
ExpectedRewards
};
template<typename ValueType>
std::vector<ValueType> SparseMdpPrctlHelper<ValueType>::computeBoundedUntilProbabilities(storm::solver::SolveGoal<ValueType>&& goal, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, uint_fast64_t stepBound, storm::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory, ModelCheckerHint const& hint) {
std::vector<ValueType> result(transitionMatrix.getRowGroupCount(), storm::utility::zero<ValueType>());
@ -91,12 +96,12 @@ namespace storm {
}
template<typename ValueType>
std::vector<uint_fast64_t> computeValidSchedulerHint(storm::solver::EquationSystemType const& type, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& maybeStates, storm::storage::BitVector const& filterStates, storm::storage::BitVector const& targetStates) {
std::vector<uint_fast64_t> computeValidSchedulerHint(EquationSystemType const& type, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& maybeStates, storm::storage::BitVector const& filterStates, storm::storage::BitVector const& targetStates) {
storm::storage::Scheduler<ValueType> validScheduler(maybeStates.size());
if (type == storm::solver::EquationSystemType::UntilProbabilities) {
if (type == EquationSystemType::UntilProbabilities) {
storm::utility::graph::computeSchedulerProbGreater0E(transitionMatrix, backwardTransitions, filterStates, targetStates, validScheduler, boost::none);
} else if (type == storm::solver::EquationSystemType::ReachabilityRewards) {
} else if (type == EquationSystemType::ExpectedRewards) {
storm::utility::graph::computeSchedulerProb1E(maybeStates | targetStates, transitionMatrix, backwardTransitions, filterStates, targetStates, validScheduler);
} else {
STORM_LOG_ASSERT(false, "Unexpected equation system type.");
@ -114,7 +119,7 @@ namespace storm {
template<typename ValueType>
struct SparseMdpHintType {
SparseMdpHintType() : eliminateEndComponents(false), computeUpperBounds(false) {
SparseMdpHintType() : eliminateEndComponents(false), computeUpperBounds(false), uniqueSolution(false) {
// Intentionally left empty.
}
@ -169,6 +174,10 @@ namespace storm {
bool getComputeUpperBounds() {
return computeUpperBounds;
}
bool hasUniqueSolution() const {
return uniqueSolution;
}
boost::optional<std::vector<uint64_t>> schedulerHint;
boost::optional<std::vector<ValueType>> valueHint;
@ -177,6 +186,7 @@ namespace storm {
boost::optional<std::vector<ValueType>> upperResultBounds;
bool eliminateEndComponents;
bool computeUpperBounds;
bool uniqueSolution;
};
template<typename ValueType>
@ -230,19 +240,22 @@ namespace storm {
}
template<typename ValueType>
SparseMdpHintType<ValueType> computeHints(storm::solver::EquationSystemType const& type, ModelCheckerHint const& hint, storm::OptimizationDirection const& dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& maybeStates, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& targetStates, storm::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory, boost::optional<storm::storage::BitVector> const& selectedChoices = boost::none) {
SparseMdpHintType<ValueType> computeHints(EquationSystemType const& type, ModelCheckerHint const& hint, storm::OptimizationDirection const& dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& maybeStates, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& targetStates, storm::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory, boost::optional<storm::storage::BitVector> const& selectedChoices = boost::none) {
SparseMdpHintType<ValueType> result;
// The solution to the min-max equation system is unique if we minimize until probabilities or
// maximize reachability rewards or if the hint tells us that there are no end-compontnes.
result.uniqueSolution = (dir == storm::solver::OptimizationDirection::Minimize && type == EquationSystemType::UntilProbabilities)
|| (dir == storm::solver::OptimizationDirection::Maximize && type == EquationSystemType::ExpectedRewards)
|| (hint.isExplicitModelCheckerHint() && hint.asExplicitModelCheckerHint<ValueType>().getNoEndComponentsInMaybeStates());
// Check for requirements of the solver.
storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(type, dir);
storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(result.uniqueSolution, dir);
if (!requirements.empty()) {
// If the hint tells us that there are no end-components, we can clear that requirement.
if (hint.isExplicitModelCheckerHint() && hint.asExplicitModelCheckerHint<ValueType>().getNoEndComponentsInMaybeStates()) {
requirements.clearNoEndComponents();
}
// If the solver still requires no end-components, we have to eliminate them later.
if (requirements.requiresNoEndComponents()) {
STORM_LOG_ASSERT(!result.hasUniqueSolution(), "The solver requires to eliminate the end components although the solution is already assumed to be unique.");
STORM_LOG_DEBUG("Scheduling EC elimination, because the solver requires it.");
result.eliminateEndComponents = true;
requirements.clearNoEndComponents();
@ -256,9 +269,9 @@ namespace storm {
}
// Finally, we have information on the bounds depending on the problem type.
if (type == storm::solver::EquationSystemType::UntilProbabilities) {
if (type == EquationSystemType::UntilProbabilities) {
requirements.clearBounds();
} else if (type == storm::solver::EquationSystemType::ReachabilityRewards) {
} else if (type == EquationSystemType::ExpectedRewards) {
requirements.clearLowerBounds();
}
if (requirements.requiresUpperBounds()) {
@ -273,8 +286,7 @@ namespace storm {
// Only if there is no end component decomposition that we will need to do later, we use value and scheduler
// hints from the provided hint.
if (!result.eliminateEndComponents) {
bool skipEcWithinMaybeStatesCheck = dir == storm::OptimizationDirection::Minimize || (hint.isExplicitModelCheckerHint() && hint.asExplicitModelCheckerHint<ValueType>().getNoEndComponentsInMaybeStates());
extractValueAndSchedulerHint(result, transitionMatrix, backwardTransitions, maybeStates, selectedChoices, hint, skipEcWithinMaybeStatesCheck);
extractValueAndSchedulerHint(result, transitionMatrix, backwardTransitions, maybeStates, selectedChoices, hint, result.uniqueSolution);
} else {
STORM_LOG_WARN_COND(hint.isEmpty(), "A non-empty hint was provided, but its information will be disregarded.");
}
@ -283,7 +295,7 @@ namespace storm {
if (!result.hasLowerResultBound()) {
result.lowerResultBound = storm::utility::zero<ValueType>();
}
if (!result.hasUpperResultBound() && type == storm::solver::EquationSystemType::UntilProbabilities) {
if (!result.hasUpperResultBound() && type == EquationSystemType::UntilProbabilities) {
result.upperResultBound = storm::utility::one<ValueType>();
}
@ -326,6 +338,7 @@ namespace storm {
// Set up the solver.
std::unique_ptr<storm::solver::MinMaxLinearEquationSolver<ValueType>> solver = storm::solver::configureMinMaxLinearEquationSolver(std::move(goal), minMaxLinearEquationSolverFactory, std::move(submatrix));
solver->setRequirementsChecked();
solver->setHasUniqueSolution(hint.hasUniqueSolution());
if (hint.hasLowerResultBound()) {
solver->setLowerBound(hint.getLowerResultBound());
}
@ -526,7 +539,7 @@ namespace storm {
// In this case we have have to compute the remaining probabilities.
// Obtain proper hint information either from the provided hint or from requirements of the solver.
SparseMdpHintType<ValueType> hintInformation = computeHints(storm::solver::EquationSystemType::UntilProbabilities, hint, goal.direction(), transitionMatrix, backwardTransitions, qualitativeStateSets.maybeStates, phiStates, qualitativeStateSets.statesWithProbability1, minMaxLinearEquationSolverFactory);
SparseMdpHintType<ValueType> hintInformation = computeHints(EquationSystemType::UntilProbabilities, hint, goal.direction(), transitionMatrix, backwardTransitions, qualitativeStateSets.maybeStates, phiStates, qualitativeStateSets.statesWithProbability1, minMaxLinearEquationSolverFactory);
// Declare the components of the equation system we will solve.
storm::storage::SparseMatrix<ValueType> submatrix;
@ -882,7 +895,7 @@ namespace storm {
}
// Obtain proper hint information either from the provided hint or from requirements of the solver.
SparseMdpHintType<ValueType> hintInformation = computeHints(storm::solver::EquationSystemType::ReachabilityRewards, hint, goal.direction(), transitionMatrix, backwardTransitions, qualitativeStateSets.maybeStates, ~targetStates, targetStates, minMaxLinearEquationSolverFactory, selectedChoices);
SparseMdpHintType<ValueType> hintInformation = computeHints(EquationSystemType::ExpectedRewards, hint, goal.direction(), transitionMatrix, backwardTransitions, qualitativeStateSets.maybeStates, ~targetStates, targetStates, minMaxLinearEquationSolverFactory, selectedChoices);
// Declare the components of the equation system we will solve.
storm::storage::SparseMatrix<ValueType> submatrix;
@ -1089,14 +1102,16 @@ namespace storm {
storm::storage::SparseMatrix<ValueType> sspMatrix = sspMatrixBuilder.build(currentChoice, numberOfSspStates, numberOfSspStates);
// Check for requirements of the solver.
storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(storm::solver::EquationSystemType::StochasticShortestPath);
requirements.clearLowerBounds();
storm::solver::MinMaxLinearEquationSolverRequirements requirements = minMaxLinearEquationSolverFactory.getRequirements(true, goal.direction());
requirements.clearBounds();
STORM_LOG_THROW(requirements.empty(), storm::exceptions::UncheckedRequirementException, "Cannot establish requirements for solver.");
std::vector<ValueType> sspResult(numberOfSspStates);
goal.restrictRelevantValues(statesNotContainedInAnyMec);
std::unique_ptr<storm::solver::MinMaxLinearEquationSolver<ValueType>> solver = storm::solver::configureMinMaxLinearEquationSolver(std::move(goal), minMaxLinearEquationSolverFactory, sspMatrix);
solver->setLowerBound(storm::utility::zero<ValueType>());
solver->setUpperBound(*std::max_element(lraValuesForEndComponents.begin(), lraValuesForEndComponents.end()));
solver->setHasUniqueSolution();
solver->setRequirementsChecked();
solver->solveEquations(sspResult, b);

30
src/storm/modelchecker/prctl/helper/SymbolicMdpPrctlHelper.cpp

@ -21,15 +21,21 @@
namespace storm {
namespace modelchecker {
namespace helper {
enum class EquationSystemType {
UntilProbabilities,
ExpectedRewards
};
template<storm::dd::DdType DdType, typename ValueType>
storm::dd::Bdd<DdType> computeValidSchedulerHint(storm::solver::EquationSystemType const& type, storm::models::symbolic::NondeterministicModel<DdType, ValueType> const& model, storm::dd::Add<DdType, ValueType> const& transitionMatrix, storm::dd::Bdd<DdType> const& maybeStates, storm::dd::Bdd<DdType> const& targetStates) {
storm::dd::Bdd<DdType> computeValidSchedulerHint(EquationSystemType const& type, storm::models::symbolic::NondeterministicModel<DdType, ValueType> const& model, storm::dd::Add<DdType, ValueType> const& transitionMatrix, storm::dd::Bdd<DdType> const& maybeStates, storm::dd::Bdd<DdType> const& targetStates) {
storm::dd::Bdd<DdType> result;
if (type == storm::solver::EquationSystemType::UntilProbabilities) {
if (type == EquationSystemType::UntilProbabilities) {
result = storm::utility::graph::computeSchedulerProbGreater0E(model, transitionMatrix.notZero(), maybeStates, targetStates);
} else if (type == storm::solver::EquationSystemType::ReachabilityRewards) {
} else if (type == EquationSystemType::ExpectedRewards) {
result = storm::utility::graph::computeSchedulerProb1E(model, transitionMatrix.notZero(), maybeStates, targetStates, maybeStates || targetStates);
}
@ -78,13 +84,18 @@ namespace storm {
// Now solve the resulting equation system.
std::unique_ptr<storm::solver::SymbolicMinMaxLinearEquationSolver<DdType, ValueType>> solver = linearEquationSolverFactory.create(submatrix, maybeStates, model.getIllegalMask() && maybeStates, model.getRowVariables(), model.getColumnVariables(), model.getNondeterminismVariables(), model.getRowColumnMetaVariablePairs());
// If we minimize, we know that the solution is unique
if (dir == storm::solver::OptimizationDirection::Minimize) {
solver->setHasUniqueSolution();
}
// Check requirements of solver.
storm::solver::MinMaxLinearEquationSolverRequirements requirements = solver->getRequirements(storm::solver::EquationSystemType::UntilProbabilities, dir);
storm::solver::MinMaxLinearEquationSolverRequirements requirements = solver->getRequirements(dir);
boost::optional<storm::dd::Bdd<DdType>> initialScheduler;
if (!requirements.empty()) {
if (requirements.requires(storm::solver::MinMaxLinearEquationSolverRequirements::Element::ValidInitialScheduler)) {
STORM_LOG_DEBUG("Computing valid scheduler, because the solver requires it.");
initialScheduler = computeValidSchedulerHint(storm::solver::EquationSystemType::UntilProbabilities, model, transitionMatrix, maybeStates, statesWithProbability01.second);
initialScheduler = computeValidSchedulerHint(EquationSystemType::UntilProbabilities, model, transitionMatrix, maybeStates, statesWithProbability01.second);
requirements.clearValidInitialScheduler();
}
requirements.clearBounds();
@ -237,13 +248,18 @@ namespace storm {
// Now solve the resulting equation system.
std::unique_ptr<storm::solver::SymbolicMinMaxLinearEquationSolver<DdType, ValueType>> solver = linearEquationSolverFactory.create(submatrix, maybeStates, model.getIllegalMask() && maybeStates, model.getRowVariables(), model.getColumnVariables(), model.getNondeterminismVariables(), model.getRowColumnMetaVariablePairs());
// If we maximize, we know that the solution is unique
if (dir == storm::solver::OptimizationDirection::Maximize) {
solver->setHasUniqueSolution();
}
// Check requirements of solver.
storm::solver::MinMaxLinearEquationSolverRequirements requirements = solver->getRequirements(storm::solver::EquationSystemType::ReachabilityRewards, dir);
storm::solver::MinMaxLinearEquationSolverRequirements requirements = solver->getRequirements(dir);
boost::optional<storm::dd::Bdd<DdType>> initialScheduler;
if (!requirements.empty()) {
if (requirements.requires(storm::solver::MinMaxLinearEquationSolverRequirements::Element::ValidInitialScheduler)) {
STORM_LOG_DEBUG("Computing valid scheduler, because the solver requires it.");
initialScheduler = computeValidSchedulerHint(storm::solver::EquationSystemType::ReachabilityRewards, model, transitionMatrix, maybeStates, targetStates);
initialScheduler = computeValidSchedulerHint(EquationSystemType::ExpectedRewards, model, transitionMatrix, maybeStates, targetStates);
requirements.clearValidInitialScheduler();
}
requirements.clearLowerBounds();

152
src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp

@ -45,7 +45,6 @@ namespace storm {
switch (solutionMethod) {
case MinMaxMethod::ValueIteration: this->solutionMethod = SolutionMethod::ValueIteration; break;
case MinMaxMethod::PolicyIteration: this->solutionMethod = SolutionMethod::PolicyIteration; break;
case MinMaxMethod::Acyclic: this->solutionMethod = SolutionMethod::Acyclic; break;
case MinMaxMethod::RationalSearch: this->solutionMethod = SolutionMethod::RationalSearch; break;
default:
STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Unsupported technique for iterative MinMax linear equation solver.");
@ -136,9 +135,6 @@ namespace storm {
case IterativeMinMaxLinearEquationSolverSettings<ValueType>::SolutionMethod::PolicyIteration:
result = solveEquationsPolicyIteration(dir, x, b);
break;
case IterativeMinMaxLinearEquationSolverSettings<ValueType>::SolutionMethod::Acyclic:
result = solveEquationsAcyclic(dir, x, b);
break;
case IterativeMinMaxLinearEquationSolverSettings<ValueType>::SolutionMethod::RationalSearch:
result = solveEquationsRationalSearch(dir, x, b);
break;
@ -268,67 +264,44 @@ namespace storm {
}
template<typename ValueType>
MinMaxLinearEquationSolverRequirements IterativeMinMaxLinearEquationSolver<ValueType>::getRequirements(EquationSystemType const& equationSystemType, boost::optional<storm::solver::OptimizationDirection> const& direction) const {
MinMaxLinearEquationSolverRequirements IterativeMinMaxLinearEquationSolver<ValueType>::getRequirements(boost::optional<storm::solver::OptimizationDirection> const& direction) const {
// Start by copying the requirements of the linear equation solver.
MinMaxLinearEquationSolverRequirements requirements(this->linearEquationSolverFactory->getRequirements());
// General requirements.
if (this->getSettings().getSolutionMethod() == IterativeMinMaxLinearEquationSolverSettings<ValueType>::SolutionMethod::ValueIteration) {
requirements.requireLowerBounds();
} else if (this->getSettings().getSolutionMethod() == IterativeMinMaxLinearEquationSolverSettings<ValueType>::SolutionMethod::RationalSearch) {
// As rational search needs to approach the solution from below, we cannot start with a valid scheduler hint as we would otherwise do.
// Instead, we need to require no end components.
if (equationSystemType == EquationSystemType::ReachabilityRewards) {
if (!direction || direction.get() == OptimizationDirection::Minimize) {
if (this->getSettings().getForceSoundness()) {
// Interval iteration requires a unique solution and lower+upper bounds
if (!this->hasUniqueSolution()) {
requirements.requireNoEndComponents();
}
}
}
// In case we perform value iteration and need to retrieve a scheduler, end components are forbidden
if (this->getSettings().getSolutionMethod() == IterativeMinMaxLinearEquationSolverSettings<ValueType>::SolutionMethod::ValueIteration && this->isTrackSchedulerSet()) {
requirements.requireNoEndComponents();
}
// Guide requirements by whether or not we force soundness.
if (this->getSettings().getForceSoundness()) {
if (this->getSettings().getSolutionMethod() == IterativeMinMaxLinearEquationSolverSettings<ValueType>::SolutionMethod::ValueIteration) {
// Require both bounds now.
requirements.requireBounds();
// If we need to also converge from above, we cannot deal with end components in the notorious cases.
if (equationSystemType == EquationSystemType::UntilProbabilities) {
if (!direction || direction.get() == OptimizationDirection::Maximize) {
requirements.requireNoEndComponents();
}
} else if (equationSystemType == EquationSystemType::ReachabilityRewards) {
if (!direction || direction.get() == OptimizationDirection::Minimize) {
requirements.requireNoEndComponents();
}
}
} else if (this->getSettings().getSolutionMethod() == IterativeMinMaxLinearEquationSolverSettings<ValueType>::SolutionMethod::PolicyIteration) {
if (equationSystemType == EquationSystemType::UntilProbabilities) {
} else if (!this->hasUniqueSolution()) { // Traditional value iteration has no requirements if the solution is unique.
// Computing a scheduler is only possible if the solution is unique
if (this->isTrackSchedulerSet()) {
requirements.requireNoEndComponents();
} else {
// As we want the smallest (largest) solution for maximizing (minimizing) equation systems, we have to approach the solution from below (above).
if (!direction || direction.get() == OptimizationDirection::Maximize) {
requirements.requireValidInitialScheduler();
requirements.requireLowerBounds();
}
} else if (equationSystemType == EquationSystemType::ReachabilityRewards) {
if (!direction || direction.get() == OptimizationDirection::Minimize) {
requirements.requireValidInitialScheduler();
requirements.requireUpperBounds();
}
}
}
} else {
if (equationSystemType == EquationSystemType::UntilProbabilities) {
if (this->getSettings().getSolutionMethod() == IterativeMinMaxLinearEquationSolverSettings<ValueType>::SolutionMethod::PolicyIteration) {
if (!direction || direction.get() == OptimizationDirection::Maximize) {
requirements.requireValidInitialScheduler();
}
}
} else if (equationSystemType == EquationSystemType::ReachabilityRewards) {
if (!direction || direction.get() == OptimizationDirection::Minimize) {
requirements.requireValidInitialScheduler();
}
} else if (this->getSettings().getSolutionMethod() == IterativeMinMaxLinearEquationSolverSettings<ValueType>::SolutionMethod::RationalSearch) {
// Rational search needs to approach the solution from below.
requirements.requireLowerBounds();
// The solution needs to be unique in case of minimizing or in cases where we want a scheduler.
if (!this->hasUniqueSolution() && (!direction || direction.get() == OptimizationDirection::Minimize || this->isTrackSchedulerSet())) {
requirements.requireNoEndComponents();
}
} else if (this->getSettings().getSolutionMethod() == IterativeMinMaxLinearEquationSolverSettings<ValueType>::SolutionMethod::PolicyIteration) {
if (!this->hasUniqueSolution()) {
requirements.requireValidInitialScheduler();
}
} else {
STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Unsupported technique for iterative MinMax linear equation solver.");
}
return requirements;
@ -934,83 +907,6 @@ namespace storm {
return solveEquationsRationalSearchHelper<double>(dir, x, b);
}
template<typename ValueType>
bool IterativeMinMaxLinearEquationSolver<ValueType>::solveEquationsAcyclic(OptimizationDirection dir, std::vector<ValueType>& x, std::vector<ValueType> const& b) const {
uint64_t numGroups = this->A->getRowGroupCount();
// Allocate memory for the scheduler (if required)
if (this->isTrackSchedulerSet()) {
if (this->schedulerChoices) {
this->schedulerChoices->resize(numGroups);
} else {
this->schedulerChoices = std::vector<uint_fast64_t>(numGroups);
}
}
// We now compute a topological sort of the row groups.
// If caching is enabled, it might be possible to obtain this sort from the cache.
if (this->isCachingEnabled()) {
if (rowGroupOrdering) {
for (auto const& group : *rowGroupOrdering) {
computeOptimalValueForRowGroup(group, dir, x, b, this->isTrackSchedulerSet() ? &this->schedulerChoices.get()[group] : nullptr);
}
return true;
} else {
rowGroupOrdering = std::make_unique<std::vector<uint64_t>>();
rowGroupOrdering->reserve(numGroups);
}
}
auto transposedMatrix = this->A->transpose(true);
// We store the groups that have already been processed, i.e., the groups for which x[group] was already set to the correct value.
storm::storage::BitVector processedGroups(numGroups, false);
// Furthermore, we keep track of all candidate groups for which we still need to check whether this group can be processed now.
// A group can be processed if all successors have already been processed.
// Notice that the BitVector candidates is considered in a reversed way, i.e., group i is a candidate iff candidates.get(numGroups - i - 1) is true.
// This is due to the observation that groups with higher indices usually need to be processed earlier.
storm::storage::BitVector candidates(numGroups, true);
uint64_t candidate = numGroups - 1;
for (uint64_t numCandidates = candidates.size(); numCandidates > 0; --numCandidates) {
candidates.set(numGroups - candidate - 1, false);
// Check if the candidate row group has an unprocessed successor
bool hasUnprocessedSuccessor = false;
for (auto const& entry : this->A->getRowGroup(candidate)) {
if (!processedGroups.get(entry.getColumn())) {
hasUnprocessedSuccessor = true;
break;
}
}
uint64_t nextCandidate = numGroups - candidates.getNextSetIndex(numGroups - candidate - 1 + 1) - 1;
if (!hasUnprocessedSuccessor) {
// This candidate can be processed.
processedGroups.set(candidate);
computeOptimalValueForRowGroup(candidate, dir, x, b, this->isTrackSchedulerSet() ? &this->schedulerChoices.get()[candidate] : nullptr);
if (this->isCachingEnabled()) {
rowGroupOrdering->push_back(candidate);
}
// Add new candidates
for (auto const& predecessorEntry : transposedMatrix.getRow(candidate)) {
uint64_t predecessor = predecessorEntry.getColumn();
if (!candidates.get(numGroups - predecessor - 1)) {
candidates.set(numGroups - predecessor - 1, true);
nextCandidate = std::max(nextCandidate, predecessor);
++numCandidates;
}
}
}
candidate = nextCandidate;
}
assert(candidates.empty());
STORM_LOG_THROW(processedGroups.full(), storm::exceptions::InvalidOperationException, "The MinMax equation system is not acyclic.");
return true;
}
template<typename ValueType>
void IterativeMinMaxLinearEquationSolver<ValueType>::computeOptimalValueForRowGroup(uint_fast64_t group, OptimizationDirection dir, std::vector<ValueType>& x, std::vector<ValueType> const& b, uint_fast64_t* choice) const {
uint64_t row = this->A->getRowGroupIndices()[group];

2
src/storm/solver/IterativeMinMaxLinearEquationSolver.h

@ -62,7 +62,7 @@ namespace storm {
ValueType getPrecision() const;
bool getRelative() const;
virtual MinMaxLinearEquationSolverRequirements getRequirements(EquationSystemType const& equationSystemType, boost::optional<storm::solver::OptimizationDirection> const& direction = boost::none) const override;
virtual MinMaxLinearEquationSolverRequirements getRequirements(boost::optional<storm::solver::OptimizationDirection> const& direction = boost::none) const override;
private:
bool solveEquationsPolicyIteration(OptimizationDirection dir, std::vector<ValueType>& x, std::vector<ValueType> const& b) const;

6
src/storm/solver/LpMinMaxLinearEquationSolver.cpp

@ -110,12 +110,12 @@ namespace storm {
template<typename ValueType>
MinMaxLinearEquationSolverRequirements LpMinMaxLinearEquationSolver<ValueType>::getRequirements(EquationSystemType const& equationSystemType, boost::optional<storm::solver::OptimizationDirection> const& direction) const {
MinMaxLinearEquationSolverRequirements LpMinMaxLinearEquationSolver<ValueType>::getRequirements(boost::optional<storm::solver::OptimizationDirection> const& direction) const {
MinMaxLinearEquationSolverRequirements requirements;
// In case we need to retrieve a scheduler, end components are forbidden
if (this->isTrackSchedulerSet()) {
// In case we need to retrieve a scheduler, the solution has to be unique
if (!this->hasUniqueSolution() && this->isTrackSchedulerSet()) {
requirements.requireNoEndComponents();
}

2
src/storm/solver/LpMinMaxLinearEquationSolver.h

@ -18,7 +18,7 @@ namespace storm {
virtual void clearCache() const override;
virtual MinMaxLinearEquationSolverRequirements getRequirements(EquationSystemType const& equationSystemType, boost::optional<storm::solver::OptimizationDirection> const& direction = boost::none) const override;
virtual MinMaxLinearEquationSolverRequirements getRequirements(boost::optional<storm::solver::OptimizationDirection> const& direction = boost::none) const override;
private:
std::unique_ptr<storm::utility::solver::LpSolverFactory<ValueType>> lpSolverFactory;

19
src/storm/solver/MinMaxLinearEquationSolver.cpp

@ -19,7 +19,7 @@ namespace storm {
namespace solver {
template<typename ValueType>
MinMaxLinearEquationSolver<ValueType>::MinMaxLinearEquationSolver(OptimizationDirectionSetting direction) : direction(direction), trackScheduler(false), cachingEnabled(false), requirementsChecked(false) {
MinMaxLinearEquationSolver<ValueType>::MinMaxLinearEquationSolver(OptimizationDirectionSetting direction) : direction(direction), trackScheduler(false), uniqueSolution(false), cachingEnabled(false), requirementsChecked(false) {
// Intentionally left empty.
}
@ -56,6 +56,16 @@ namespace storm {
direction = OptimizationDirectionSetting::Unset;
}
template<typename ValueType>
void MinMaxLinearEquationSolver<ValueType>::setHasUniqueSolution(bool value) {
uniqueSolution = value;
}
template<typename ValueType>
bool MinMaxLinearEquationSolver<ValueType>::hasUniqueSolution() const {
return uniqueSolution;
}
template<typename ValueType>
void MinMaxLinearEquationSolver<ValueType>::setTrackScheduler(bool trackScheduler) {
this->trackScheduler = trackScheduler;
@ -127,7 +137,7 @@ namespace storm {
}
template<typename ValueType>
MinMaxLinearEquationSolverRequirements MinMaxLinearEquationSolver<ValueType>::getRequirements(EquationSystemType const& equationSystemType, boost::optional<storm::solver::OptimizationDirection> const& direction) const {
MinMaxLinearEquationSolverRequirements MinMaxLinearEquationSolver<ValueType>::getRequirements(boost::optional<storm::solver::OptimizationDirection> const& direction) const {
return MinMaxLinearEquationSolverRequirements();
}
@ -199,10 +209,11 @@ namespace storm {
}
template<typename ValueType>
MinMaxLinearEquationSolverRequirements MinMaxLinearEquationSolverFactory<ValueType>::getRequirements(EquationSystemType const& equationSystemType, boost::optional<storm::solver::OptimizationDirection> const& direction) const {
MinMaxLinearEquationSolverRequirements MinMaxLinearEquationSolverFactory<ValueType>::getRequirements(bool hasUniqueSolution, boost::optional<storm::solver::OptimizationDirection> const& direction) const {
// Create dummy solver and ask it for requirements.
std::unique_ptr<MinMaxLinearEquationSolver<ValueType>> solver = this->create();
return solver->getRequirements(equationSystemType, direction);
solver->setHasUniqueSolution(hasUniqueSolution);
return solver->getRequirements(direction);
}
template<typename ValueType>

18
src/storm/solver/MinMaxLinearEquationSolver.h

@ -12,7 +12,6 @@
#include "storm/storage/sparse/StateType.h"
#include "storm/storage/Scheduler.h"
#include "storm/solver/OptimizationDirection.h"
#include "storm/solver/EquationSystemType.h"
#include "storm/solver/MinMaxLinearEquationSolverRequirements.h"
#include "storm/exceptions/InvalidSettingsException.h"
@ -94,6 +93,16 @@ namespace storm {
*/
void unsetOptimizationDirection();
/*!
* Sets whether the solution to the min max equation system is known to be unique.
*/
void setHasUniqueSolution(bool value = true);
/*!
* Retrieves whether the solution to the min max equation system is assumed to be unique
*/
bool hasUniqueSolution() const;
/*!
* Sets whether schedulers are generated when solving equation systems. If the argument is false, the currently
* stored scheduler (if any) is deleted.
@ -155,7 +164,7 @@ namespace storm {
* Retrieves the requirements of this solver for solving equations with the current settings. The requirements
* are guaranteed to be ordered according to their appearance in the SolverRequirement type.
*/
virtual MinMaxLinearEquationSolverRequirements getRequirements(EquationSystemType const& equationSystemType, boost::optional<storm::solver::OptimizationDirection> const& direction = boost::none) const;
virtual MinMaxLinearEquationSolverRequirements getRequirements(boost::optional<storm::solver::OptimizationDirection> const& direction = boost::none) const;
/*!
* Notifies the solver that the requirements for solving equations have been checked. If this has not been
@ -184,6 +193,9 @@ namespace storm {
boost::optional<std::vector<uint_fast64_t>> initialScheduler;
private:
// Whether the solver can assume that the min-max equation system has a unique solution
bool uniqueSolution;
/// Whether some of the generated data during solver calls should be cached.
bool cachingEnabled;
@ -212,7 +224,7 @@ namespace storm {
* Retrieves the requirements of the solver that would be created when calling create() right now. The
* requirements are guaranteed to be ordered according to their appearance in the SolverRequirement type.
*/
MinMaxLinearEquationSolverRequirements getRequirements(EquationSystemType const& equationSystemType, boost::optional<storm::solver::OptimizationDirection> const& direction = boost::none) const;
MinMaxLinearEquationSolverRequirements getRequirements(bool hasUniqueSolution = false, boost::optional<storm::solver::OptimizationDirection> const& direction = boost::none) const;
void setRequirementsChecked(bool value = true);
bool isRequirementsCheckedSet() const;

46
src/storm/solver/SymbolicMinMaxLinearEquationSolver.cpp

@ -86,12 +86,12 @@ namespace storm {
}
template<storm::dd::DdType DdType, typename ValueType>
SymbolicMinMaxLinearEquationSolver<DdType, ValueType>::SymbolicMinMaxLinearEquationSolver(SymbolicMinMaxLinearEquationSolverSettings<ValueType> const& settings) : SymbolicEquationSolver<DdType, ValueType>(), settings(settings), requirementsChecked(false) {
SymbolicMinMaxLinearEquationSolver<DdType, ValueType>::SymbolicMinMaxLinearEquationSolver(SymbolicMinMaxLinearEquationSolverSettings<ValueType> const& settings) : SymbolicEquationSolver<DdType, ValueType>(), settings(settings), uniqueSolution(false), requirementsChecked(false) {
// Intentionally left empty.
}
template<storm::dd::DdType DdType, typename ValueType>
SymbolicMinMaxLinearEquationSolver<DdType, ValueType>::SymbolicMinMaxLinearEquationSolver(storm::dd::Add<DdType, ValueType> const& A, storm::dd::Bdd<DdType> const& allRows, storm::dd::Bdd<DdType> const& illegalMask, std::set<storm::expressions::Variable> const& rowMetaVariables, std::set<storm::expressions::Variable> const& columnMetaVariables, std::set<storm::expressions::Variable> const& choiceVariables, std::vector<std::pair<storm::expressions::Variable, storm::expressions::Variable>> const& rowColumnMetaVariablePairs, std::unique_ptr<SymbolicLinearEquationSolverFactory<DdType, ValueType>>&& linearEquationSolverFactory, SymbolicMinMaxLinearEquationSolverSettings<ValueType> const& settings) : SymbolicEquationSolver<DdType, ValueType>(allRows), A(A), illegalMask(illegalMask), illegalMaskAdd(illegalMask.ite(A.getDdManager().getConstant(storm::utility::infinity<ValueType>()), A.getDdManager().template getAddZero<ValueType>())), rowMetaVariables(rowMetaVariables), columnMetaVariables(columnMetaVariables), choiceVariables(choiceVariables), rowColumnMetaVariablePairs(rowColumnMetaVariablePairs), linearEquationSolverFactory(std::move(linearEquationSolverFactory)), settings(settings), requirementsChecked(false) {
SymbolicMinMaxLinearEquationSolver<DdType, ValueType>::SymbolicMinMaxLinearEquationSolver(storm::dd::Add<DdType, ValueType> const& A, storm::dd::Bdd<DdType> const& allRows, storm::dd::Bdd<DdType> const& illegalMask, std::set<storm::expressions::Variable> const& rowMetaVariables, std::set<storm::expressions::Variable> const& columnMetaVariables, std::set<storm::expressions::Variable> const& choiceVariables, std::vector<std::pair<storm::expressions::Variable, storm::expressions::Variable>> const& rowColumnMetaVariablePairs, std::unique_ptr<SymbolicLinearEquationSolverFactory<DdType, ValueType>>&& linearEquationSolverFactory, SymbolicMinMaxLinearEquationSolverSettings<ValueType> const& settings) : SymbolicEquationSolver<DdType, ValueType>(allRows), A(A), illegalMask(illegalMask), illegalMaskAdd(illegalMask.ite(A.getDdManager().getConstant(storm::utility::infinity<ValueType>()), A.getDdManager().template getAddZero<ValueType>())), rowMetaVariables(rowMetaVariables), columnMetaVariables(columnMetaVariables), choiceVariables(choiceVariables), rowColumnMetaVariablePairs(rowColumnMetaVariablePairs), linearEquationSolverFactory(std::move(linearEquationSolverFactory)), settings(settings), uniqueSolution(false), requirementsChecked(false) {
// Intentionally left empty.
}
@ -419,39 +419,42 @@ namespace storm {
}
template<storm::dd::DdType DdType, typename ValueType>
MinMaxLinearEquationSolverRequirements SymbolicMinMaxLinearEquationSolver<DdType, ValueType>::getRequirements(EquationSystemType const& equationSystemType, boost::optional<storm::solver::OptimizationDirection> const& direction) const {
MinMaxLinearEquationSolverRequirements SymbolicMinMaxLinearEquationSolver<DdType, ValueType>::getRequirements(boost::optional<storm::solver::OptimizationDirection> const& direction) const {
MinMaxLinearEquationSolverRequirements requirements;
if (this->getSettings().getSolutionMethod() == SymbolicMinMaxLinearEquationSolverSettings<ValueType>::SolutionMethod::PolicyIteration) {
if (equationSystemType == EquationSystemType::UntilProbabilities) {
if (!direction || direction.get() == OptimizationDirection::Maximize) {
requirements.requireValidInitialScheduler();
}
}
if (equationSystemType == EquationSystemType::ReachabilityRewards) {
if (!direction || direction.get() == OptimizationDirection::Minimize) {
requirements.requireValidInitialScheduler();
}
if (!this->hasUniqueSolution()) {
requirements.requireValidInitialScheduler();
}
} else if (this->getSettings().getSolutionMethod() == SymbolicMinMaxLinearEquationSolverSettings<ValueType>::SolutionMethod::ValueIteration) {
requirements.requireLowerBounds();
if (equationSystemType == EquationSystemType::ReachabilityRewards) {
if (!direction || direction.get() == OptimizationDirection::Minimize) {
if (!this->hasUniqueSolution()) {
if (!direction || direction.get() == storm::solver::OptimizationDirection::Maximize) {
requirements.requireLowerBounds();
}
if (!direction || direction.get() == storm::solver::OptimizationDirection::Minimize) {
requirements.requireValidInitialScheduler();
}
}
} else if (this->getSettings().getSolutionMethod() == SymbolicMinMaxLinearEquationSolverSettings<ValueType>::SolutionMethod::RationalSearch) {
requirements.requireLowerBounds();
if (equationSystemType == EquationSystemType::ReachabilityRewards) {
if (!direction || direction.get() == OptimizationDirection::Minimize) {
requirements.requireNoEndComponents();
}
if (!this->hasUniqueSolution() && (!direction || direction.get() == storm::solver::OptimizationDirection::Minimize)) {
requirements.requireNoEndComponents();
}
}
return requirements;
}
template<storm::dd::DdType DdType, typename ValueType>
void SymbolicMinMaxLinearEquationSolver<DdType, ValueType>::setHasUniqueSolution(bool value) {
this->uniqueSolution = value;
}
template<storm::dd::DdType DdType, typename ValueType>
bool SymbolicMinMaxLinearEquationSolver<DdType, ValueType>::hasUniqueSolution() const {
return this->uniqueSolution;
}
template<storm::dd::DdType DdType, typename ValueType>
void SymbolicMinMaxLinearEquationSolver<DdType, ValueType>::setRequirementsChecked(bool value) {
this->requirementsChecked = value;
@ -484,9 +487,10 @@ namespace storm {
}
template<storm::dd::DdType DdType, typename ValueType>
MinMaxLinearEquationSolverRequirements SymbolicMinMaxLinearEquationSolverFactory<DdType, ValueType>::getRequirements(EquationSystemType const& equationSystemType, boost::optional<storm::solver::OptimizationDirection> const& direction) const {
MinMaxLinearEquationSolverRequirements SymbolicMinMaxLinearEquationSolverFactory<DdType, ValueType>::getRequirements(bool hasUniqueSolution, boost::optional<storm::solver::OptimizationDirection> const& direction) const {
std::unique_ptr<storm::solver::SymbolicMinMaxLinearEquationSolver<DdType, ValueType>> solver = this->create();
return solver->getRequirements(equationSystemType, direction);
solver->setHasUniqueSolution(hasUniqueSolution);
return solver->getRequirements(direction);
}
template<storm::dd::DdType DdType, typename ValueType>

17
src/storm/solver/SymbolicMinMaxLinearEquationSolver.h

@ -127,7 +127,17 @@ namespace storm {
/*!
* Retrieves the requirements of the solver.
*/
virtual MinMaxLinearEquationSolverRequirements getRequirements(EquationSystemType const& equationSystemType, boost::optional<storm::solver::OptimizationDirection> const& direction = boost::none) const;
virtual MinMaxLinearEquationSolverRequirements getRequirements(boost::optional<storm::solver::OptimizationDirection> const& direction = boost::none) const;
/*!
* Sets whether the solution to the min max equation system is known to be unique.
*/
void setHasUniqueSolution(bool value = true);
/*!
* Retrieves whether the solution to the min max equation system is assumed to be unique
*/
bool hasUniqueSolution() const;
/*!
* Notifies the solver that the requirements for solving equations have been checked. If this has not been
@ -208,6 +218,9 @@ namespace storm {
// The settings to use.
SymbolicMinMaxLinearEquationSolverSettings<ValueType> settings;
// Whether the solver can assume that the min-max equation system has a unique solution
bool uniqueSolution;
// A flag indicating whether the requirements were checked.
bool requirementsChecked;
@ -230,7 +243,7 @@ namespace storm {
* Retrieves the requirements of the solver that would be created when calling create() right now. The
* requirements are guaranteed to be ordered according to their appearance in the SolverRequirement type.
*/
MinMaxLinearEquationSolverRequirements getRequirements(EquationSystemType const& equationSystemType, boost::optional<storm::solver::OptimizationDirection> const& direction = boost::none) const;
MinMaxLinearEquationSolverRequirements getRequirements(bool hasUniqueSolution = false, boost::optional<storm::solver::OptimizationDirection> const& direction = boost::none) const;
private:
virtual std::unique_ptr<storm::solver::SymbolicMinMaxLinearEquationSolver<DdType, ValueType>> create() const = 0;

Loading…
Cancel
Save