Browse Source

First implementation of quick value iteration for MinMax Equation systems

tempestpy_adaptions
TimQu 7 years ago
parent
commit
9c96bd0a1c
  1. 4
      src/storm/settings/modules/MinMaxEquationSolverSettings.cpp
  2. 291
      src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp
  3. 2
      src/storm/solver/IterativeMinMaxLinearEquationSolver.h
  4. 4
      src/storm/solver/MinMaxLinearEquationSolver.cpp
  5. 2
      src/storm/solver/SolverSelectionOptions.cpp
  6. 2
      src/storm/solver/SolverSelectionOptions.h
  7. 2
      src/storm/solver/StandardMinMaxLinearEquationSolver.cpp
  8. 17
      src/test/storm/modelchecker/MdpPrctlModelCheckerTest.cpp

4
src/storm/settings/modules/MinMaxEquationSolverSettings.cpp

@ -21,7 +21,7 @@ namespace storm {
const std::string MinMaxEquationSolverSettings::valueIterationMultiplicationStyleOptionName = "vimult";
MinMaxEquationSolverSettings::MinMaxEquationSolverSettings() : ModuleSettings(moduleName) {
std::vector<std::string> minMaxSolvingTechniques = {"vi", "value-iteration", "pi", "policy-iteration", "linear-programming", "lp", "ratsearch"};
std::vector<std::string> minMaxSolvingTechniques = {"vi", "value-iteration", "pi", "policy-iteration", "linear-programming", "lp", "ratsearch", "qvi", "quick-value-iteration"};
this->addOption(storm::settings::OptionBuilder(moduleName, solvingMethodOptionName, false, "Sets which min/max linear equation solving technique is preferred.")
.addArgument(storm::settings::ArgumentBuilder::createStringArgument("name", "The name of a min/max linear equation solving technique.").addValidatorString(ArgumentValidatorFactory::createMultipleChoiceValidator(minMaxSolvingTechniques)).setDefaultValueString("vi").build()).build());
@ -50,6 +50,8 @@ namespace storm {
return storm::solver::MinMaxMethod::LinearProgramming;
} else if (minMaxEquationSolvingTechnique == "ratsearch") {
return storm::solver::MinMaxMethod::RationalSearch;
} else if (minMaxEquationSolvingTechnique == "quick-value-iteration" || minMaxEquationSolvingTechnique == "qvi") {
return storm::solver::MinMaxMethod::QuickValueIteration;
}
STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentValueException, "Unknown min/max equation solving technique '" << minMaxEquationSolvingTechnique << "'.");
}

291
src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp

@ -1,3 +1,5 @@
#include <functional>
#include "storm/solver/IterativeMinMaxLinearEquationSolver.h"
#include "storm/utility/ConstantsComparator.h"
@ -46,7 +48,7 @@ namespace storm {
STORM_LOG_WARN("The selected solution method does not guarantee exact results.");
}
}
STORM_LOG_THROW(method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch, storm::exceptions::InvalidEnvironmentException, "This solver does not support the selected method.");
STORM_LOG_THROW(method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch || method == MinMaxMethod::QuickValueIteration, storm::exceptions::InvalidEnvironmentException, "This solver does not support the selected method.");
return method;
}
@ -67,6 +69,9 @@ namespace storm {
case MinMaxMethod::RationalSearch:
result = solveEquationsRationalSearch(env, dir, x, b);
break;
case MinMaxMethod::QuickValueIteration:
result = solveEquationsQuickSoundValueIteration(env, dir, x, b);
break;
default:
STORM_LOG_THROW(false, storm::exceptions::InvalidEnvironmentException, "This solver does not implement the selected solution method");
}
@ -211,10 +216,8 @@ namespace storm {
// Start by getting the requirements of the linear equation solver.
LinearEquationSolverTask linEqTask = LinearEquationSolverTask::Unspecified;
if (method == MinMaxMethod::ValueIteration || method == MinMaxMethod::RationalSearch) {
if (!this->hasInitialScheduler() && assumeNoInitialScheduler) {
linEqTask = LinearEquationSolverTask::Multiply;
}
if ((method == MinMaxMethod::ValueIteration && !this->hasInitialScheduler() && assumeNoInitialScheduler) || method == MinMaxMethod::RationalSearch || method == MinMaxMethod::QuickValueIteration) {
linEqTask = LinearEquationSolverTask::Multiply;
}
MinMaxLinearEquationSolverRequirements requirements(this->linearEquationSolverFactory->getRequirements(env, linEqTask));
@ -250,6 +253,10 @@ namespace storm {
if (!this->hasUniqueSolution()) {
requirements.requireValidInitialScheduler();
}
} else if (method == MinMaxMethod::QuickValueIteration) {
if (!this->hasUniqueSolution()) {
requirements.requireNoEndComponents();
}
} else {
STORM_LOG_THROW(false, storm::exceptions::InvalidEnvironmentException, "Unsupported technique for iterative MinMax linear equation solver.");
}
@ -596,6 +603,278 @@ namespace storm {
return status == SolverStatus::Converged;
}
template<typename ValueType>
bool IterativeMinMaxLinearEquationSolver<ValueType>::solveEquationsQuickSoundValueIteration(Environment const& env, OptimizationDirection dir, std::vector<ValueType>& x, std::vector<ValueType> const& b) const {
if (!this->linEqSolverA) {
this->createLinearEquationSolver(env);
this->linEqSolverA->setCachingEnabled(true);
}
// Allow aliased multiplications.
bool useGaussSeidelMultiplication = this->linEqSolverA->supportsGaussSeidelMultiplication() && env.solver().minMax().getMultiplicationStyle() == storm::solver::MultiplicationStyle::GaussSeidel;
// Prepare the solution vectors.
assert(x.size() == this->A->getRowGroupCount());
std::vector<ValueType> *stepBoundedX, *stepBoundedStayProbs, *tmp;
if (useGaussSeidelMultiplication) {
stepBoundedX = &x;
stepBoundedX->assign(this->A->getRowGroupCount(), storm::utility::zero<ValueType>());
if (!this->auxiliaryRowGroupVector) {
this->auxiliaryRowGroupVector = std::make_unique<std::vector<ValueType>>(this->A->getRowGroupCount(), storm::utility::one<ValueType>());
} else {
this->auxiliaryRowGroupVector->assign(this->A->getRowGroupCount(), storm::utility::one<ValueType>());
}
stepBoundedStayProbs = this->auxiliaryRowGroupVector.get();
tmp = nullptr;
} else {
if (!this->auxiliaryRowGroupVector) {
this->auxiliaryRowGroupVector = std::make_unique<std::vector<ValueType>>(this->A->getRowGroupCount(), storm::utility::zero<ValueType>());
} else {
this->auxiliaryRowGroupVector->assign(this->A->getRowGroupCount(), storm::utility::zero<ValueType>());
}
stepBoundedX = this->auxiliaryRowGroupVector.get();
if (!this->auxiliaryRowGroupVector2) {
this->auxiliaryRowGroupVector2 = std::make_unique<std::vector<ValueType>>(this->A->getRowGroupCount(), storm::utility::one<ValueType>());
} else {
this->auxiliaryRowGroupVector2->assign(this->A->getRowGroupCount(), storm::utility::one<ValueType>());
}
stepBoundedStayProbs = this->auxiliaryRowGroupVector2.get();
tmp = &x;
}
// Get the precision
bool relative = env.solver().minMax().getRelativeTerminationCriterion();
ValueType precision = storm::utility::convertNumber<ValueType>(env.solver().minMax().getPrecision());
if (!relative) {
precision *= storm::utility::convertNumber<ValueType>(2.0);
}
this->startMeasureProgress();
// Prepare some data used in the iterations.
// We store the current lower (upper) bound for the minimal (maximal) value occurring at some index (if already found)
// Moreover, we store a decisionValue: When minimizing (maximizing) this is the largest (smallest) possible lower (upper) bound
// for which the performed scheduler decisions are valid.
// All these values might not be available yet.
ValueType currentLowerBound, currentUpperBound, decisionValue;
bool hasCurrentLowerBound(false), hasCurrentUpperBound(false), hasDecisionValue(false);
if (this->hasLowerBound(AbstractEquationSolver<ValueType>::BoundType::Global)) {
currentLowerBound = this->getLowerBound();
hasCurrentLowerBound = true;
} else if (this->hasLowerBound(AbstractEquationSolver<ValueType>::BoundType::Local)) {
currentLowerBound = *std::min_element(this->getLowerBounds().begin(), this->getLowerBounds().end());
hasCurrentLowerBound = true;
}
if (this->hasUpperBound(AbstractEquationSolver<ValueType>::BoundType::Global)) {
currentUpperBound = this->getUpperBound();
hasCurrentUpperBound = true;
} else if (this->hasUpperBound(AbstractEquationSolver<ValueType>::BoundType::Local)) {
currentUpperBound = *std::max_element(this->getUpperBounds().begin(), this->getUpperBounds().end());
hasCurrentUpperBound = true;
}
// reduce the number of case distinctions w.r.t. minimizing/maximizing optimization direction
std::function<bool(ValueType const&, ValueType const&)> better, betterEqual;
if (minimize(dir)) {
better = std::less<ValueType>();
betterEqual = std::less_equal<ValueType>();
} else {
better = std::greater<ValueType>();
betterEqual = std::greater_equal<ValueType>();
}
// If minimizing, the primary bound is the lower bound; if maximizing, the primary bound is the upper bound.
ValueType& primaryBound = minimize(dir) ? currentLowerBound : currentUpperBound;
bool& hasPrimaryBound = minimize(dir) ? hasCurrentLowerBound : hasCurrentUpperBound;
// Proceed with the iterations as long as the method did not converge or reach the maximum number of iterations.
SolverStatus status = SolverStatus::InProgress;
uint64_t iterations = 0;
std::vector<ValueType> xTmp, yTmp;
uint64_t minIndex(0), maxIndex(0);
uint64_t firstStayProb1Index = 0;
uint64_t firstIndexViolatingConvergence = this->hasRelevantValues() ? this->getRelevantValues().getNextSetIndex(0) : 0;
while (status == SolverStatus::InProgress && iterations < env.solver().minMax().getMaximalNumberOfIterations()) {
//Perform the iteration step
auto xIt = stepBoundedX->rbegin();
auto yIt = stepBoundedStayProbs->rbegin();
auto groupStartIt = this->A->getRowGroupIndices().rbegin();
++groupStartIt;
auto groupEndIt = this->A->getRowGroupIndices().rbegin();
while (groupStartIt != this->A->getRowGroupIndices().rend()) {
// Handle Row Groups of size 1 quickly
if (*groupStartIt + 1 == *groupEndIt) {
*xIt = this->linEqSolverA->multiplyRow(*groupStartIt, *stepBoundedX) + b[*groupStartIt];
*yIt = this->linEqSolverA->multiplyRow(*groupStartIt, *stepBoundedStayProbs);
} else {
// First pass through the group: get the multiplication results
xTmp.clear();
yTmp.clear();
for (uint64_t row = *groupStartIt; row < *groupEndIt; ++row) {
xTmp.push_back(this->linEqSolverA->multiplyRow(row, *stepBoundedX) + b[row]);
yTmp.push_back(this->linEqSolverA->multiplyRow(row, *stepBoundedStayProbs));
}
// Second pass: get the best choice
uint64_t bestChoice = 0;
if (hasPrimaryBound) {
// Second pass: get the best choice
ValueType bestValue = xTmp.front() + yTmp.front() * primaryBound;
for (uint64_t choice = 1; choice < xTmp.size(); ++choice) {
ValueType value = xTmp[choice] + yTmp[choice] * primaryBound;
if (betterEqual(value, bestValue) && (value != bestValue || yTmp[choice] < yTmp[bestChoice])) {
bestValue = std::move(value);
bestChoice = choice;
}
}
} else {
// If no bound is known, we implicitly assume a sufficiently large (or low) bound
ValueType bestValue = yTmp.front();
for (uint64_t choice = 1; choice < xTmp.size(); ++choice) {
ValueType const& value = yTmp[choice];
if (betterEqual(value, bestValue) && (value != bestValue || better(xTmp[choice], xTmp[bestChoice]))) {
bestValue = std::move(value);
bestChoice = choice;
}
}
}
*xIt = xTmp[bestChoice];
*yIt = yTmp[bestChoice];
// Third pass: Update the decision value
for (uint64_t choice = 0; choice < xTmp.size(); ++choice) {
if (choice != bestChoice) {
ValueType deltaY = *yIt - yTmp[choice];
if (deltaY > storm::utility::zero<ValueType>()) {
ValueType newDecisionValue = (xTmp[choice] - *xIt) / deltaY;
if (!hasDecisionValue || better(newDecisionValue, decisionValue)) {
// std::cout << "Updating decision value to " << newDecisionValue << ", where deltaX = " << xTmp[choice] << " - " << *xIt << " = " << (xTmp[choice] - *xIt) << " and deltaY= " << *yIt << " - " << yTmp[choice] << " = " << deltaY << "." << std::endl;
decisionValue = std::move(newDecisionValue);
hasDecisionValue = true;
}
}
}
}
}
++groupStartIt;
++groupEndIt;
++xIt;
++yIt;
}
// Update bounds and check for convergence
// Phase 1: the probability to 'stay within the matrix' has to be < 1 at every state
for (; firstStayProb1Index != stepBoundedStayProbs->size(); ++firstStayProb1Index) {
static_assert(NumberTraits<ValueType>::IsExact || std::is_same<ValueType, double>::value, "Considered ValueType not handled.");
if (NumberTraits<ValueType>::IsExact) {
if (storm::utility::isOne(stepBoundedStayProbs->at(firstStayProb1Index))) {
break;
}
} else {
if (storm::utility::isAlmostOne(storm::utility::convertNumber<double>(stepBoundedStayProbs->at(firstStayProb1Index)))) {
break;
}
}
}
if (firstStayProb1Index == stepBoundedStayProbs->size()) {
STORM_LOG_ASSERT(!std::any_of(stepBoundedStayProbs->begin(), stepBoundedStayProbs->end(), [](ValueType value){return storm::utility::isOne(value);}), "Did not expect staying-probability 1 at this point.");
// Phase 2: the difference between lower and upper bound has to be < precision at every (relevant) value
// First check with (possibly too tight) bounds from a previous iteration. Only compute the actual bounds if this first check passes.
currentLowerBound = stepBoundedX->at(minIndex) / (storm::utility::one<ValueType>() - stepBoundedStayProbs->at(minIndex));
currentUpperBound = stepBoundedX->at(maxIndex) / (storm::utility::one<ValueType>() - stepBoundedStayProbs->at(maxIndex));
// Potentially correct the primary bound so that scheduler choices remain valid
if (hasDecisionValue && better(decisionValue, primaryBound)) {
primaryBound = decisionValue;
}
ValueType const& stayProb = stepBoundedStayProbs->at(firstIndexViolatingConvergence);
// The error made in this iteration
ValueType absoluteError = stayProb * (currentUpperBound - currentLowerBound);
// The maximal allowed error (possibly respecting relative precision)
// Note: We implement the relative convergence criterion in a way that avoids division by zero in the case where stepBoundedX[i] is zero.
ValueType maxAllowedError = relative ? (precision * stepBoundedX->at(firstIndexViolatingConvergence)) : precision;
if (absoluteError <= maxAllowedError) {
// Compute the actual bounds now
auto valIt = stepBoundedX->begin();
auto valIte = stepBoundedX->end();
auto probIt = stepBoundedStayProbs->begin();
for (uint64_t index = 0; valIt != valIte; ++valIt, ++probIt, ++index) {
ValueType currentBound = *valIt / (storm::utility::one<ValueType>() - *probIt);
if (currentBound < currentLowerBound) {
minIndex = index;
currentLowerBound = std::move(currentBound);
} else if (currentBound > currentUpperBound) {
maxIndex = index;
currentUpperBound = std::move(currentBound);
}
}
// Potentially correct the primary bound so that scheduler choices remain valid
if (hasDecisionValue && better(decisionValue, primaryBound)) {
primaryBound = decisionValue;
}
hasCurrentUpperBound = true;
hasCurrentLowerBound = true;
absoluteError = stayProb * (currentUpperBound - currentLowerBound);
if (absoluteError <= maxAllowedError) {
// The current index satisfies the desired bound. We now move to the next index that violates it
while (true) {
++firstIndexViolatingConvergence;
if (this->hasRelevantValues()) {
firstIndexViolatingConvergence = this->getRelevantValues().getNextSetIndex(firstIndexViolatingConvergence);
}
if (firstIndexViolatingConvergence == stepBoundedStayProbs->size()) {
status = SolverStatus::Converged;
break;
} else {
absoluteError = stepBoundedStayProbs->at(firstIndexViolatingConvergence) * (currentUpperBound - currentLowerBound);
maxAllowedError = relative ? (precision * stepBoundedX->at(firstIndexViolatingConvergence)) : precision;
if (absoluteError > maxAllowedError) {
// not converged yet
break;
}
}
}
}
}
}
// Update environment variables.
++iterations;
// TODO: Implement custom termination criterion. We would need to add our errors to the stepBoundedX values (only if in second phase)
status = updateStatusIfNotConverged(status, *stepBoundedX, iterations, env.solver().minMax().getMaximalNumberOfIterations(), SolverGuarantee::None);
// Potentially show progress.
this->showProgressIterative(iterations);
}
reportStatus(status, iterations);
STORM_LOG_WARN_COND(hasCurrentLowerBound && hasCurrentUpperBound, "No lower or upper result bound could be computed within the given number of Iterations.");
// Finally set up the solution vector
ValueType meanBound = (currentUpperBound + currentLowerBound) / storm::utility::convertNumber<ValueType>(2.0);
storm::utility::vector::applyPointwise(*stepBoundedX, *stepBoundedStayProbs, x, [&meanBound] (ValueType const& v, ValueType const& p) { return v + p * meanBound; });
// If requested, we store the scheduler for retrieval.
if (this->isTrackSchedulerSet()) {
this->schedulerChoices = std::vector<uint_fast64_t>(this->A->getRowGroupCount());
this->linEqSolverA->multiplyAndReduce(dir, this->A->getRowGroupIndices(), x, &b, *this->auxiliaryRowGroupVector, &this->schedulerChoices.get());
}
STORM_LOG_INFO("Quick Value Iteration terminated with lower value bound "
<< (hasCurrentLowerBound ? currentLowerBound : storm::utility::zero<ValueType>()) << (hasCurrentLowerBound ? "" : "(none)")
<< " and upper value bound "
<< (hasCurrentUpperBound ? currentUpperBound : storm::utility::zero<ValueType>()) << (hasCurrentUpperBound ? "" : "(none)")
<< ". Decision value is "
<< (hasDecisionValue ? decisionValue : storm::utility::zero<ValueType>()) << (hasDecisionValue ? "" : "(none)")
<< ".");
if (!this->isCachingEnabled()) {
clearCache();
}
return status == SolverStatus::Converged;
}
template<typename ValueType>
bool IterativeMinMaxLinearEquationSolver<ValueType>::isSolution(storm::OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& matrix, std::vector<ValueType> const& values, std::vector<ValueType> const& b) {
storm::utility::ConstantsComparator<ValueType> comparator;
@ -954,7 +1233,7 @@ namespace storm {
STORM_LOG_ASSERT(this->linearEquationSolverFactory, "Linear equation solver factory not initialized.");
auto method = env.solver().minMax().getMethod();
STORM_LOG_THROW(method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch, storm::exceptions::InvalidEnvironmentException, "This solver does not support the selected method.");
STORM_LOG_THROW(method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch || method == MinMaxMethod::QuickValueIteration, storm::exceptions::InvalidEnvironmentException, "This solver does not support the selected method.");
std::unique_ptr<MinMaxLinearEquationSolver<ValueType>> result = std::make_unique<IterativeMinMaxLinearEquationSolver<ValueType>>(this->linearEquationSolverFactory->clone());
result->setRequirementsChecked(this->isRequirementsCheckedSet());

2
src/storm/solver/IterativeMinMaxLinearEquationSolver.h

@ -38,6 +38,8 @@ namespace storm {
bool solveEquationsValueIteration(Environment const& env, OptimizationDirection dir, std::vector<ValueType>& x, std::vector<ValueType> const& b) const;
bool solveEquationsSoundValueIteration(Environment const& env, OptimizationDirection dir, std::vector<ValueType>& x, std::vector<ValueType> const& b) const;
bool solveEquationsQuickSoundValueIteration(Environment const& env, OptimizationDirection dir, std::vector<ValueType>& x, std::vector<ValueType> const& b) const;
bool solveEquationsRationalSearch(Environment const& env, OptimizationDirection dir, std::vector<ValueType>& x, std::vector<ValueType> const& b) const;
template<typename RationalType, typename ImpreciseType>

4
src/storm/solver/MinMaxLinearEquationSolver.cpp

@ -196,7 +196,7 @@ namespace storm {
std::unique_ptr<MinMaxLinearEquationSolver<ValueType>> GeneralMinMaxLinearEquationSolverFactory<ValueType>::create(Environment const& env) const {
std::unique_ptr<MinMaxLinearEquationSolver<ValueType>> result;
auto method = env.solver().minMax().getMethod();
if (method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch) {
if (method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch || method == MinMaxMethod::QuickValueIteration) {
result = std::make_unique<IterativeMinMaxLinearEquationSolver<ValueType>>(std::make_unique<GeneralLinearEquationSolverFactory<ValueType>>());
} else if (method == MinMaxMethod::Topological) {
result = std::make_unique<TopologicalMinMaxLinearEquationSolver<ValueType>>();
@ -213,7 +213,7 @@ namespace storm {
std::unique_ptr<MinMaxLinearEquationSolver<storm::RationalNumber>> GeneralMinMaxLinearEquationSolverFactory<storm::RationalNumber>::create(Environment const& env) const {
std::unique_ptr<MinMaxLinearEquationSolver<storm::RationalNumber>> result;
auto method = env.solver().minMax().getMethod();
if (method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch) {
if (method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch || method == MinMaxMethod::QuickValueIteration) {
result = std::make_unique<IterativeMinMaxLinearEquationSolver<storm::RationalNumber>>(std::make_unique<GeneralLinearEquationSolverFactory<storm::RationalNumber>>());
} else if (method == MinMaxMethod::LinearProgramming) {
result = std::make_unique<LpMinMaxLinearEquationSolver<storm::RationalNumber>>(std::make_unique<GeneralLinearEquationSolverFactory<storm::RationalNumber>>(), std::make_unique<storm::utility::solver::LpSolverFactory<storm::RationalNumber>>());

2
src/storm/solver/SolverSelectionOptions.cpp

@ -14,6 +14,8 @@ namespace storm {
return "topological";
case MinMaxMethod::RationalSearch:
return "ratsearch";
case MinMaxMethod::QuickValueIteration:
return "QuickValueIteration";
}
return "invalid";
}

2
src/storm/solver/SolverSelectionOptions.h

@ -6,7 +6,7 @@
namespace storm {
namespace solver {
ExtendEnumsWithSelectionField(MinMaxMethod, PolicyIteration, ValueIteration, LinearProgramming, Topological, RationalSearch)
ExtendEnumsWithSelectionField(MinMaxMethod, PolicyIteration, ValueIteration, LinearProgramming, Topological, RationalSearch, QuickValueIteration)
ExtendEnumsWithSelectionField(GameMethod, PolicyIteration, ValueIteration)
ExtendEnumsWithSelectionField(LraMethod, LinearProgramming, ValueIteration)

2
src/storm/solver/StandardMinMaxLinearEquationSolver.cpp

@ -111,7 +111,7 @@ namespace storm {
std::unique_ptr<MinMaxLinearEquationSolver<ValueType>> StandardMinMaxLinearEquationSolverFactory<ValueType>::create(Environment const& env) const {
std::unique_ptr<MinMaxLinearEquationSolver<ValueType>> result;
auto method = env.solver().minMax().getMethod();
if (method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch) {
if (method == MinMaxMethod::ValueIteration || method == MinMaxMethod::PolicyIteration || method == MinMaxMethod::RationalSearch || method == MinMaxMethod::QuickValueIteration) {
result = std::make_unique<IterativeMinMaxLinearEquationSolver<ValueType>>(this->linearEquationSolverFactory->clone());
} else {
STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "The selected min max method is not supported by this solver.");

17
src/test/storm/modelchecker/MdpPrctlModelCheckerTest.cpp

@ -55,6 +55,22 @@ namespace {
return env;
}
};
class SparseDoubleQuickValueIterationEnvironment {
public:
static const storm::dd::DdType ddType = storm::dd::DdType::Sylvan; // Unused for sparse models
static const storm::settings::modules::CoreSettings::Engine engine = storm::settings::modules::CoreSettings::Engine::Sparse;
static const bool isExact = false;
typedef double ValueType;
typedef storm::models::sparse::Mdp<ValueType> ModelType;
static storm::Environment createEnvironment() {
storm::Environment env;
env.solver().setForceSoundness(true);
env.solver().minMax().setMethod(storm::solver::MinMaxMethod::QuickValueIteration);
env.solver().minMax().setPrecision(storm::utility::convertNumber<storm::RationalNumber>(1e-6));
env.solver().minMax().setRelativeTerminationCriterion(false);
return env;
}
};
class SparseRationalPolicyIterationEnvironment {
public:
static const storm::dd::DdType ddType = storm::dd::DdType::Sylvan; // Unused for sparse models
@ -283,6 +299,7 @@ namespace {
typedef ::testing::Types<
SparseDoubleValueIterationEnvironment,
SparseDoubleSoundValueIterationEnvironment,
SparseDoubleQuickValueIterationEnvironment,
SparseRationalPolicyIterationEnvironment,
SparseRationalRationalSearchEnvironment,
HybridCuddDoubleValueIterationEnvironment,

Loading…
Cancel
Save