diff --git a/src/counterexamples/SMTMinimalCommandSetGenerator.h b/src/counterexamples/SMTMinimalCommandSetGenerator.h index 3026ab74e..3f03440d3 100644 --- a/src/counterexamples/SMTMinimalCommandSetGenerator.h +++ b/src/counterexamples/SMTMinimalCommandSetGenerator.h @@ -1763,7 +1763,7 @@ namespace storm { STORM_LOG_THROW(probabilityOperator.getSubformula().isUntilFormula() || probabilityOperator.getSubformula().isEventuallyFormula(), storm::exceptions::InvalidPropertyException, "Path formula is required to be of the form 'phi U psi' for counterexample generation."); bool strictBound = comparisonType == storm::logic::ComparisonType::Less; - double bound = probabilityOperator.getBound(); + double threshold = probabilityOperator.getThreshold(); storm::storage::BitVector phiStates; storm::storage::BitVector psiStates; @@ -1793,7 +1793,7 @@ namespace storm { // Delegate the actual computation work to the function of equal name. auto startTime = std::chrono::high_resolution_clock::now(); - auto labelSet = getMinimalCommandSet(probabilityOperator.getSubformula(), program, constantDefinitionString, labeledMdp, phiStates, psiStates, bound, strictBound, true, storm::settings::counterexampleGeneratorSettings().isEncodeReachabilitySet()); + auto labelSet = getMinimalCommandSet(probabilityOperator.getSubformula(), program, constantDefinitionString, labeledMdp, phiStates, psiStates, threshold, strictBound, true, storm::settings::counterexampleGeneratorSettings().isEncodeReachabilitySet()); auto endTime = std::chrono::high_resolution_clock::now(); std::cout << std::endl << "Computed minimal label set of size " << labelSet.size() << " in " << std::chrono::duration_cast(endTime - startTime).count() << "ms." << std::endl; diff --git a/src/modelchecker/CheckTask.h b/src/modelchecker/CheckTask.h index a3646e464..be56e29e1 100644 --- a/src/modelchecker/CheckTask.h +++ b/src/modelchecker/CheckTask.h @@ -30,7 +30,7 @@ namespace storm { */ CheckTask(FormulaType const& formula, bool onlyInitialStatesRelevant = false) : formula(formula) { this->onlyInitialStatesRelevant = onlyInitialStatesRelevant; - this->produceSchedulers = true; + this->produceSchedulers = false; this->qualitative = false; if (formula.isOperatorFormula()) { @@ -165,6 +165,13 @@ namespace storm { return qualitative; } + /*! + * Sets whether to produce schedulers (if supported). + */ + void setProduceSchedulers(bool produceSchedulers) { + this->produceSchedulers = produceSchedulers; + } + /*! * Retrieves whether scheduler(s) are to be produced (if supported). */ diff --git a/src/modelchecker/prctl/helper/MDPModelCheckingHelperReturnType.h b/src/modelchecker/prctl/helper/MDPModelCheckingHelperReturnType.h index fac823940..4ce7bb23f 100644 --- a/src/modelchecker/prctl/helper/MDPModelCheckingHelperReturnType.h +++ b/src/modelchecker/prctl/helper/MDPModelCheckingHelperReturnType.h @@ -3,14 +3,13 @@ #include #include -#include "src/storage/PartialScheduler.h" +#include "src/storage/Scheduler.h" namespace storm { namespace storage { class BitVector; } - namespace modelchecker { namespace helper { template @@ -19,7 +18,7 @@ namespace storm { MDPSparseModelCheckingHelperReturnType(MDPSparseModelCheckingHelperReturnType const&) = delete; MDPSparseModelCheckingHelperReturnType(MDPSparseModelCheckingHelperReturnType&&) = default; - MDPSparseModelCheckingHelperReturnType(std::vector&& values, std::unique_ptr && scheduler = nullptr) : values(std::move(values)), scheduler(std::move(scheduler)) { + MDPSparseModelCheckingHelperReturnType(std::vector&& values, std::unique_ptr&& scheduler = nullptr) : values(std::move(values)), scheduler(std::move(scheduler)) { // Intentionally left empty. } @@ -31,7 +30,7 @@ namespace storm { std::vector values; // A scheduler, if it was computed. - std::unique_ptr scheduler; + std::unique_ptr scheduler; }; } diff --git a/src/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp b/src/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp index 85817b1b2..cb03e5724 100644 --- a/src/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp +++ b/src/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp @@ -1,4 +1,4 @@ -#include "src/modelchecker/prctl/helper/SparseMdpPrctlHelper.h" + #include "src/modelchecker/prctl/helper/SparseMdpPrctlHelper.h" #include "src/modelchecker/results/ExplicitQuantitativeCheckResult.h" @@ -12,6 +12,7 @@ #include "src/storage/expressions/Variable.h" #include "src/storage/expressions/Expression.h" +#include "src/storage/TotalScheduler.h" #include "src/solver/MinMaxLinearEquationSolver.h" #include "src/solver/LpSolver.h" @@ -56,7 +57,6 @@ namespace storm { return result; } - template std::vector SparseMdpPrctlHelper::computeNextProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& nextStates, storm::utility::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { @@ -73,7 +73,8 @@ namespace storm { template - MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeUntilProbabilities(storm::solver::SolveGoal const& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, bool producePolicy, storm::utility::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeUntilProbabilities(storm::solver::SolveGoal const& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, bool produceScheduler, storm::utility::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + STORM_LOG_THROW(!(qualitative && produceScheduler), storm::exceptions::InvalidSettingsException, "Cannot produce scheduler when performing qualitative model checking only."); // We need to identify the states which have to be taken out of the matrix, i.e. // all states that have probability 0 and 1 of satisfying the until-formula. @@ -96,7 +97,12 @@ namespace storm { // Set values of resulting vector that are known exactly. storm::utility::vector::setVectorValues(result, statesWithProbability0, storm::utility::zero()); storm::utility::vector::setVectorValues(result, statesWithProbability1, storm::utility::one()); - + + // If requested, we will produce a scheduler. + std::unique_ptr scheduler; + if (produceScheduler) { + scheduler = std::make_unique(transitionMatrix.getRowGroupCount()); + } // Check whether we need to compute exact probabilities for some states. if (qualitative) { @@ -119,20 +125,44 @@ namespace storm { // Solve the corresponding system of equations. std::unique_ptr> solver = storm::solver::configureMinMaxLinearEquationSolver(goal, minMaxLinearEquationSolverFactory, submatrix); + solver->setTrackScheduler(produceScheduler); solver->solveEquationSystem(x, b); // Set values of resulting vector according to result. storm::utility::vector::setVectorValues(result, maybeStates, x); + + if (produceScheduler) { + storm::storage::Scheduler const& subscheduler = solver->getScheduler(); + uint_fast64_t currentSubState = 0; + for (auto maybeState : maybeStates) { + scheduler->setChoice(maybeState, subscheduler.getChoice(currentSubState)); + ++currentSubState; + } + } + } + } + + // Finally, if we need to produce a scheduler, we also need to figure out the parts of the scheduler for + // the states with probability 0 or 1 (depending on whether we maximize or minimize). + if (produceScheduler) { + storm::storage::PartialScheduler relevantQualitativeScheduler; + if (goal.minimize()) { + relevantQualitativeScheduler = storm::utility::graph::computeSchedulerProb0E(statesWithProbability0, transitionMatrix); + } else { + relevantQualitativeScheduler = storm::utility::graph::computeSchedulerProb1E(statesWithProbability1, transitionMatrix, backwardTransitions, phiStates, psiStates); + } + for (auto const& stateChoicePair : relevantQualitativeScheduler) { + scheduler->setChoice(stateChoicePair.first, stateChoicePair.second); } } - return MDPSparseModelCheckingHelperReturnType(std::move(result)); + return MDPSparseModelCheckingHelperReturnType(std::move(result), std::move(scheduler)); } template - MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeUntilProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, bool producePolicy, storm::utility::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { + MDPSparseModelCheckingHelperReturnType SparseMdpPrctlHelper::computeUntilProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, bool produceScheduler, storm::utility::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory) { storm::solver::SolveGoal goal(dir); - return std::move(computeUntilProbabilities(goal, transitionMatrix, backwardTransitions, phiStates, psiStates, qualitative, producePolicy, minMaxLinearEquationSolverFactory)); + return std::move(computeUntilProbabilities(goal, transitionMatrix, backwardTransitions, phiStates, psiStates, qualitative, produceScheduler, minMaxLinearEquationSolverFactory)); } template diff --git a/src/modelchecker/prctl/helper/SparseMdpPrctlHelper.h b/src/modelchecker/prctl/helper/SparseMdpPrctlHelper.h index 8567c445b..f09e40d4a 100644 --- a/src/modelchecker/prctl/helper/SparseMdpPrctlHelper.h +++ b/src/modelchecker/prctl/helper/SparseMdpPrctlHelper.h @@ -36,9 +36,9 @@ namespace storm { static std::vector computeNextProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::BitVector const& nextStates, storm::utility::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); - static MDPSparseModelCheckingHelperReturnType computeUntilProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, bool producePolicy, storm::utility::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static MDPSparseModelCheckingHelperReturnType computeUntilProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, bool produceScheduler, storm::utility::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); - static MDPSparseModelCheckingHelperReturnType computeUntilProbabilities(storm::solver::SolveGoal const& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, bool producePolicy, storm::utility::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); + static MDPSparseModelCheckingHelperReturnType computeUntilProbabilities(storm::solver::SolveGoal const& goal, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, bool produceScheduler, storm::utility::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory); static std::vector computeGloballyProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix const& transitionMatrix, storm::storage::SparseMatrix const& backwardTransitions, storm::storage::BitVector const& psiStates, bool qualitative, storm::utility::solver::MinMaxLinearEquationSolverFactory const& minMaxLinearEquationSolverFactory, bool useMecBasedTechnique = false); diff --git a/src/modelchecker/results/ExplicitQuantitativeCheckResult.cpp b/src/modelchecker/results/ExplicitQuantitativeCheckResult.cpp index 3f22b4ff2..08ca016fd 100644 --- a/src/modelchecker/results/ExplicitQuantitativeCheckResult.cpp +++ b/src/modelchecker/results/ExplicitQuantitativeCheckResult.cpp @@ -79,6 +79,22 @@ namespace storm { } } + template + bool ExplicitQuantitativeCheckResult::hasScheduler() const { + return static_cast(scheduler); + } + + template + void ExplicitQuantitativeCheckResult::setScheduler(std::unique_ptr&& scheduler) { + this->scheduler = std::move(scheduler); + } + + template + storm::storage::Scheduler const& ExplicitQuantitativeCheckResult::getScheduler() const { + STORM_LOG_THROW(this->hasScheduler(), storm::exceptions::InvalidOperationException, "Unable to retrieve non-existing scheduler."); + return *scheduler.get(); + } + template std::ostream& ExplicitQuantitativeCheckResult::writeToStream(std::ostream& out) const { out << "["; diff --git a/src/modelchecker/results/ExplicitQuantitativeCheckResult.h b/src/modelchecker/results/ExplicitQuantitativeCheckResult.h index 9734a176f..ee49b74ec 100644 --- a/src/modelchecker/results/ExplicitQuantitativeCheckResult.h +++ b/src/modelchecker/results/ExplicitQuantitativeCheckResult.h @@ -4,9 +4,11 @@ #include #include #include +#include #include "src/modelchecker/results/QuantitativeCheckResult.h" #include "src/storage/sparse/StateType.h" +#include "src/storage/Scheduler.h" #include "src/utility/OsDetection.h" namespace storm { @@ -51,9 +53,16 @@ namespace storm { virtual void oneMinus() override; + bool hasScheduler() const; + void setScheduler(std::unique_ptr&& scheduler); + storm::storage::Scheduler const& getScheduler() const; + private: // The values of the quantitative check result. boost::variant values; + + // An optional scheduler that accompanies the values. + boost::optional> scheduler; }; } } diff --git a/src/parser/PrismParser.cpp b/src/parser/PrismParser.cpp index b2349ebf7..9040f3cf4 100644 --- a/src/parser/PrismParser.cpp +++ b/src/parser/PrismParser.cpp @@ -142,7 +142,7 @@ namespace storm { assignmentDefinitionList = (assignmentDefinition % "&")[qi::_val = qi::_1] | (qi::lit("true"))[qi::_val = phoenix::construct>()]; assignmentDefinitionList.name("assignment list"); - updateDefinition = (((expressionParser > qi::lit(":")) | qi::attr(manager->rational(1))) >> assignmentDefinitionList)[qi::_val = phoenix::bind(&PrismParser::createUpdate, phoenix::ref(*this), qi::_1, qi::_2, qi::_r1)]; + updateDefinition = (((expressionParser >> qi::lit(":")) | qi::attr(manager->rational(1))) >> assignmentDefinitionList)[qi::_val = phoenix::bind(&PrismParser::createUpdate, phoenix::ref(*this), qi::_1, qi::_2, qi::_r1)]; updateDefinition.name("update"); updateListDefinition %= +updateDefinition(qi::_r1) % "+"; diff --git a/src/solver/GmmxxMinMaxLinearEquationSolver.cpp b/src/solver/GmmxxMinMaxLinearEquationSolver.cpp index d5dcbb627..00c51e82c 100644 --- a/src/solver/GmmxxMinMaxLinearEquationSolver.cpp +++ b/src/solver/GmmxxMinMaxLinearEquationSolver.cpp @@ -16,12 +16,8 @@ namespace storm { template GmmxxMinMaxLinearEquationSolver::GmmxxMinMaxLinearEquationSolver(storm::storage::SparseMatrix const& A, MinMaxTechniqueSelection preferredTechnique, bool trackPolicy) : - MinMaxLinearEquationSolver(A, storm::settings::gmmxxEquationSolverSettings().getPrecision(), \ - storm::settings::gmmxxEquationSolverSettings().getConvergenceCriterion() == storm::settings::modules::GmmxxEquationSolverSettings::ConvergenceCriterion::Relative,\ - storm::settings::gmmxxEquationSolverSettings().getMaximalIterationCount(), trackPolicy, preferredTechnique), - gmmxxMatrix(storm::adapters::GmmxxAdapter::toGmmxxSparseMatrix(A)), rowGroupIndices(A.getRowGroupIndices()) { - - + MinMaxLinearEquationSolver(A, storm::settings::gmmxxEquationSolverSettings().getPrecision(), storm::settings::gmmxxEquationSolverSettings().getConvergenceCriterion() == storm::settings::modules::GmmxxEquationSolverSettings::ConvergenceCriterion::Relative, storm::settings::gmmxxEquationSolverSettings().getMaximalIterationCount(), trackPolicy, preferredTechnique), gmmxxMatrix(storm::adapters::GmmxxAdapter::toGmmxxSparseMatrix(A)), rowGroupIndices(A.getRowGroupIndices()) { + // Intentionally left empty. } template @@ -29,11 +25,12 @@ namespace storm { // Intentionally left empty. } - template void GmmxxMinMaxLinearEquationSolver::solveEquationSystem(OptimizationDirection dir, std::vector& x, std::vector const& b, std::vector* multiplyResult, std::vector* newX) const { if (this->useValueIteration) { - // Set up the environment for the power method. If scratch memory was not provided, we need to create it. + STORM_LOG_THROW(!this->isTrackSchedulerSet(), storm::exceptions::InvalidSettingsException, "Unable to produce a scheduler when using value iteration. Use policy iteration instead."); + + // Set up the environment for the power method. If scratch memory was not provided, we need to create it. bool multiplyResultMemoryProvided = true; if (multiplyResult == nullptr) { multiplyResult = new std::vector(b.size()); diff --git a/src/solver/MinMaxLinearEquationSolver.cpp b/src/solver/MinMaxLinearEquationSolver.cpp index 4f9627a20..294b32c2a 100644 --- a/src/solver/MinMaxLinearEquationSolver.cpp +++ b/src/solver/MinMaxLinearEquationSolver.cpp @@ -23,6 +23,11 @@ namespace storm { this->trackScheduler = trackScheduler; } + template + bool AbstractMinMaxLinearEquationSolver::hasScheduler() const { + return static_cast(scheduler); + } + template bool AbstractMinMaxLinearEquationSolver::isTrackSchedulerSet() const { return this->trackScheduler; diff --git a/src/solver/MinMaxLinearEquationSolver.h b/src/solver/MinMaxLinearEquationSolver.h index f33fdc6e1..78781c68a 100644 --- a/src/solver/MinMaxLinearEquationSolver.h +++ b/src/solver/MinMaxLinearEquationSolver.h @@ -30,6 +30,7 @@ namespace storm { public: void setTrackScheduler(bool trackScheduler = true); bool isTrackSchedulerSet() const; + bool hasScheduler() const; storm::storage::Scheduler const& getScheduler() const; @@ -69,7 +70,7 @@ namespace storm { template class MinMaxLinearEquationSolver : public AbstractMinMaxLinearEquationSolver { protected: - MinMaxLinearEquationSolver(storm::storage::SparseMatrix const& matrix, double precision, bool relativeError, uint_fast64_t maxNrIterations, bool trackPolicy, MinMaxTechniqueSelection prefTech) : AbstractMinMaxLinearEquationSolver(precision, relativeError, maxNrIterations, trackPolicy, prefTech), A(matrix) { + MinMaxLinearEquationSolver(storm::storage::SparseMatrix const& matrix, double precision, bool relativeError, uint_fast64_t maxNrIterations, bool trackScheduler, MinMaxTechniqueSelection prefTech) : AbstractMinMaxLinearEquationSolver(precision, relativeError, maxNrIterations, trackScheduler, prefTech), A(matrix) { // Intentionally left empty. } diff --git a/src/storage/PartialScheduler.cpp b/src/storage/PartialScheduler.cpp index 6f004c315..28076f7a1 100644 --- a/src/storage/PartialScheduler.cpp +++ b/src/storage/PartialScheduler.cpp @@ -22,6 +22,14 @@ namespace storm { return stateChoicePair->second; } + PartialScheduler::map_type::const_iterator PartialScheduler::begin() const { + return stateToChoiceMapping.begin(); + } + + PartialScheduler::map_type::const_iterator PartialScheduler::end() const { + return stateToChoiceMapping.end(); + } + std::ostream& operator<<(std::ostream& out, PartialScheduler const& scheduler) { out << "partial scheduler (defined on " << scheduler.stateToChoiceMapping.size() << " states) [ "; uint_fast64_t remainingEntries = scheduler.stateToChoiceMapping.size(); diff --git a/src/storage/PartialScheduler.h b/src/storage/PartialScheduler.h index e5f9fffb2..4ae503348 100644 --- a/src/storage/PartialScheduler.h +++ b/src/storage/PartialScheduler.h @@ -19,6 +19,9 @@ namespace storm { uint_fast64_t getChoice(uint_fast64_t state) const override; + map_type::const_iterator begin() const; + map_type::const_iterator end() const; + friend std::ostream& operator<<(std::ostream& out, PartialScheduler const& scheduler); private: diff --git a/src/utility/graph.cpp b/src/utility/graph.cpp index bac64948f..0aa8b2836 100644 --- a/src/utility/graph.cpp +++ b/src/utility/graph.cpp @@ -280,7 +280,7 @@ namespace storm { } } if (allSuccessorsInStates) { - result.setChoice(state, choice); + result.setChoice(state, choice - nondeterministicChoiceIndices[state]); break; } } @@ -304,7 +304,7 @@ namespace storm { } } if (oneSuccessorInStates) { - result.setChoice(state, choice); + result.setChoice(state, choice - nondeterministicChoiceIndices[state]); break; } } @@ -356,7 +356,7 @@ namespace storm { // If all successors for a given nondeterministic choice are in the prob1E state set, we // perform a backward search from that state. if (allSuccessorsInProb1EStates && hasSuccessorInCurrentStates) { - result.setChoice(predecessorEntryIt->getColumn(), row); + result.setChoice(predecessorEntryIt->getColumn(), row - nondeterministicChoiceIndices[predecessorEntryIt->getColumn()]); currentStates.set(predecessorEntryIt->getColumn(), true); stack.push_back(predecessorEntryIt->getColumn()); break; diff --git a/src/utility/solver.cpp b/src/utility/solver.cpp index dbb798cb2..013a800c4 100644 --- a/src/utility/solver.cpp +++ b/src/utility/solver.cpp @@ -91,17 +91,19 @@ namespace storm { } template - void MinMaxLinearEquationSolverFactory::setSolverType(storm::solver::EquationSolverTypeSelection solverTypeSel) { + MinMaxLinearEquationSolverFactory& MinMaxLinearEquationSolverFactory::setSolverType(storm::solver::EquationSolverTypeSelection solverTypeSel) { if(solverTypeSel == storm::solver::EquationSolverTypeSelection::FROMSETTINGS) { this->solverType = storm::settings::generalSettings().getEquationSolver(); } else { this->solverType = storm::solver::convert(solverTypeSel); } - + return *this; } + template - void MinMaxLinearEquationSolverFactory::setPreferredTechnique(storm::solver::MinMaxTechniqueSelection preferredTech) { + MinMaxLinearEquationSolverFactory& MinMaxLinearEquationSolverFactory::setPreferredTechnique(storm::solver::MinMaxTechniqueSelection preferredTech) { this->prefTech = preferredTech; + return *this; } template @@ -128,7 +130,6 @@ namespace storm { } p1->setTrackScheduler(trackScheduler); return p1; - } template diff --git a/src/utility/solver.h b/src/utility/solver.h index 446b22c7a..ef8120b65 100644 --- a/src/utility/solver.h +++ b/src/utility/solver.h @@ -114,8 +114,8 @@ namespace storm { * Creates a new min/max linear equation solver instance with the given matrix. */ virtual std::unique_ptr> create(storm::storage::SparseMatrix const& matrix, bool trackScheduler = false) const; - void setSolverType(storm::solver::EquationSolverTypeSelection solverType); - void setPreferredTechnique(storm::solver::MinMaxTechniqueSelection); + MinMaxLinearEquationSolverFactory& setSolverType(storm::solver::EquationSolverTypeSelection solverType); + MinMaxLinearEquationSolverFactory& setPreferredTechnique(storm::solver::MinMaxTechniqueSelection); protected: /// The type of solver which should be created. diff --git a/test/functional/modelchecker/GmmxxMdpPrctlModelCheckerTest.cpp b/test/functional/modelchecker/GmmxxMdpPrctlModelCheckerTest.cpp index 23184f61f..14239a438 100644 --- a/test/functional/modelchecker/GmmxxMdpPrctlModelCheckerTest.cpp +++ b/test/functional/modelchecker/GmmxxMdpPrctlModelCheckerTest.cpp @@ -14,6 +14,8 @@ #include "src/settings/modules/NativeEquationSolverSettings.h" #include "src/parser/AutoParser.h" +#include "src/parser/PrismParser.h" +#include "src/builder/ExplicitPrismModelBuilder.h" TEST(GmmxxMdpPrctlModelCheckerTest, Dice) { std::shared_ptr> abstractModel = storm::parser::AutoParser<>::parseModel(STORM_CPP_BASE_PATH "/examples/mdp/two_dice/two_dice.tra", STORM_CPP_BASE_PATH "/examples/mdp/two_dice/two_dice.lab", "", STORM_CPP_BASE_PATH "/examples/mdp/two_dice/two_dice.flip.trans.rew"); @@ -188,3 +190,37 @@ TEST(GmmxxMdpPrctlModelCheckerTest, AsynchronousLeader) { EXPECT_NEAR(4.285689611, quantitativeResult6[0], storm::settings::nativeEquationSolverSettings().getPrecision()); } + +TEST(GmmxxMdpPrctlModelCheckerTest, SchedulerGeneration) { + storm::prism::Program program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/modelchecker/scheduler_generation.nm"); + + // A parser that we use for conveniently constructing the formulas. + storm::parser::FormulaParser formulaParser; + + std::shared_ptr> model = storm::builder::ExplicitPrismModelBuilder().translateProgram(program); + EXPECT_EQ(4ul, model->getNumberOfStates()); + EXPECT_EQ(11ul, model->getNumberOfTransitions()); + + ASSERT_EQ(model->getType(), storm::models::ModelType::Mdp); + + std::shared_ptr> mdp = model->as>(); + + EXPECT_EQ(7ul, mdp->getNumberOfChoices()); + + auto solverFactory = std::make_unique>(storm::solver::EquationSolverTypeSelection::Gmmxx); + solverFactory->setPreferredTechnique(storm::solver::MinMaxTechniqueSelection::PolicyIteration); + storm::modelchecker::SparseMdpPrctlModelChecker> checker(*mdp, std::move(solverFactory)); + + std::shared_ptr formula = formulaParser.parseSingleFormulaFromString("Pmin=? [F \"target\"]"); + + storm::modelchecker::CheckTask checkTask(*formula); + checkTask.setProduceSchedulers(true); + + std::unique_ptr result = checker.check(checkTask); + + formula = formulaParser.parseSingleFormulaFromString("Pmax=? [F \"target\"]"); + checkTask.replaceFormula(*formula); + + result = checker.check(checkTask); + +} diff --git a/test/functional/modelchecker/scheduler_generation.nm b/test/functional/modelchecker/scheduler_generation.nm new file mode 100644 index 000000000..f5be3b746 --- /dev/null +++ b/test/functional/modelchecker/scheduler_generation.nm @@ -0,0 +1,16 @@ +mdp + +module one + + s : [0 .. 5] init 0; + + [] s=0 -> 0.5: (s'=1) + 0.5: (s'=3); + [] s=1 -> 0.4 : (s'=4) + 0.6: (s'=3); + [] s=1 -> 1: (s'=4); + [] s=1 -> 0.8: (s'=3) + 0.2: (s'=4); + [] s=0 | s = 2 -> 0.9: (s'=s) + 0.1 : (s'=3); + [] 3 <= s & s <= 4 -> 1: true; + +endmodule + +label "target" = s=3;