Browse Source

Improved storage::Scheduler. We can now consider arbitrary finite memory schedulers, potentially employing randomization.

main
TimQu 8 years ago
parent
commit
2f49255db6
  1. 8
      src/storm/modelchecker/hints/ExplicitModelCheckerHint.cpp
  2. 12
      src/storm/modelchecker/hints/ExplicitModelCheckerHint.h
  3. 8
      src/storm/modelchecker/multiobjective/pcaa/SparseMaPcaaWeightVectorChecker.cpp
  4. 33
      src/storm/modelchecker/multiobjective/pcaa/SparsePcaaWeightVectorChecker.cpp
  5. 9
      src/storm/modelchecker/multiobjective/pcaa/SparsePcaaWeightVectorChecker.h
  6. 42
      src/storm/modelchecker/parametric/SparseDtmcParameterLiftingModelChecker.cpp
  7. 8
      src/storm/modelchecker/parametric/SparseDtmcParameterLiftingModelChecker.h
  8. 8
      src/storm/modelchecker/parametric/SparseDtmcRegionChecker.cpp
  9. 17
      src/storm/modelchecker/parametric/SparseMdpInstantiationModelChecker.cpp
  10. 1
      src/storm/modelchecker/parametric/SparseMdpInstantiationModelChecker.h
  11. 59
      src/storm/modelchecker/parametric/SparseMdpParameterLiftingModelChecker.cpp
  12. 12
      src/storm/modelchecker/parametric/SparseMdpParameterLiftingModelChecker.h
  13. 12
      src/storm/modelchecker/parametric/SparseMdpRegionChecker.cpp
  14. 4
      src/storm/modelchecker/prctl/helper/MDPModelCheckingHelperReturnType.h
  15. 165
      src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.cpp
  16. 4
      src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.h
  17. 6
      src/storm/modelchecker/results/ExplicitQuantitativeCheckResult.cpp
  18. 8
      src/storm/modelchecker/results/ExplicitQuantitativeCheckResult.h
  19. 50
      src/storm/solver/GameSolver.cpp
  20. 32
      src/storm/solver/GameSolver.h
  21. 28
      src/storm/solver/MinMaxLinearEquationSolver.cpp
  22. 22
      src/storm/solver/MinMaxLinearEquationSolver.h
  23. 18
      src/storm/solver/StandardGameSolver.cpp
  24. 2
      src/storm/solver/StandardGameSolver.h
  25. 17
      src/storm/solver/StandardMinMaxLinearEquationSolver.cpp
  26. 8
      src/storm/storage/Distribution.cpp
  27. 48
      src/storm/storage/PartialScheduler.cpp
  28. 34
      src/storm/storage/PartialScheduler.h
  29. 166
      src/storm/storage/Scheduler.cpp
  30. 93
      src/storm/storage/Scheduler.h
  31. 82
      src/storm/storage/SchedulerChoice.cpp
  32. 79
      src/storm/storage/SchedulerChoice.h
  33. 68
      src/storm/storage/TotalScheduler.cpp
  34. 78
      src/storm/storage/TotalScheduler.h
  35. 59
      src/storm/utility/graph.cpp
  36. 19
      src/storm/utility/graph.h
  37. 20
      src/test/modelchecker/GmmxxMdpPrctlModelCheckerTest.cpp
  38. 67
      src/test/storage/SchedulerTest.cpp

8
src/storm/modelchecker/hints/ExplicitModelCheckerHint.cpp

@ -85,22 +85,22 @@ namespace storm {
}
template<typename ValueType>
storm::storage::TotalScheduler const& ExplicitModelCheckerHint<ValueType>::getSchedulerHint() const {
storm::storage::Scheduler<ValueType> const& ExplicitModelCheckerHint<ValueType>::getSchedulerHint() const {
return *schedulerHint;
}
template<typename ValueType>
storm::storage::TotalScheduler& ExplicitModelCheckerHint<ValueType>::getSchedulerHint() {
storm::storage::Scheduler<ValueType>& ExplicitModelCheckerHint<ValueType>::getSchedulerHint() {
return *schedulerHint;
}
template<typename ValueType>
void ExplicitModelCheckerHint<ValueType>::setSchedulerHint(boost::optional<storm::storage::TotalScheduler> const& schedulerHint) {
void ExplicitModelCheckerHint<ValueType>::setSchedulerHint(boost::optional<storm::storage::Scheduler<ValueType>> const& schedulerHint) {
this->schedulerHint = schedulerHint;
}
template<typename ValueType>
void ExplicitModelCheckerHint<ValueType>::setSchedulerHint(boost::optional<storm::storage::TotalScheduler>&& schedulerHint) {
void ExplicitModelCheckerHint<ValueType>::setSchedulerHint(boost::optional<storm::storage::Scheduler<ValueType>>&& schedulerHint) {
this->schedulerHint = schedulerHint;
}

12
src/storm/modelchecker/hints/ExplicitModelCheckerHint.h

@ -5,7 +5,7 @@
#include <boost/optional.hpp>
#include "storm/modelchecker/hints/ModelCheckerHint.h"
#include "storm/storage/TotalScheduler.h"
#include "storm/storage/Scheduler.h"
namespace storm {
namespace modelchecker {
@ -46,10 +46,10 @@ namespace storm {
void setMaybeStates(storm::storage::BitVector&& maybeStates);
bool hasSchedulerHint() const;
storm::storage::TotalScheduler const& getSchedulerHint() const;
storm::storage::TotalScheduler& getSchedulerHint();
void setSchedulerHint(boost::optional<storage::TotalScheduler> const& schedulerHint);
void setSchedulerHint(boost::optional<storage::TotalScheduler>&& schedulerHint);
storm::storage::Scheduler<ValueType> const& getSchedulerHint() const;
storm::storage::Scheduler<ValueType>& getSchedulerHint();
void setSchedulerHint(boost::optional<storage::Scheduler<ValueType>> const& schedulerHint);
void setSchedulerHint(boost::optional<storage::Scheduler<ValueType>>&& schedulerHint);
// If set, it is assumed that there are no end components that consist only of maybestates.
// May only be enabled iff maybestates are given.
@ -58,7 +58,7 @@ namespace storm {
private:
boost::optional<std::vector<ValueType>> resultHint;
boost::optional<storm::storage::TotalScheduler> schedulerHint;
boost::optional<storm::storage::Scheduler<ValueType>> schedulerHint;
bool computeOnlyMaybeStates;
boost::optional<storm::storage::BitVector> maybeStates;

8
src/storm/modelchecker/multiobjective/pcaa/SparseMaPcaaWeightVectorChecker.cpp

@ -340,18 +340,18 @@ namespace storm {
void SparseMaPcaaWeightVectorChecker<SparseMaModelType>::performPSStep(SubModel& PS, SubModel const& MS, MinMaxSolverData& minMax, LinEqSolverData& linEq, std::vector<uint_fast64_t>& optimalChoicesAtCurrentEpoch, storm::storage::BitVector const& consideredObjectives, std::vector<ValueType> const& weightVector) const {
// compute a choice vector for the probabilistic states that is optimal w.r.t. the weighted reward vector
minMax.solver->solveEquations(PS.weightedSolutionVector, minMax.b);
auto newScheduler = minMax.solver->getScheduler();
auto const& newChoices = minMax.solver->getSchedulerChoices();
if(consideredObjectives.getNumberOfSetBits() == 1 && storm::utility::isOne(weightVector[*consideredObjectives.begin()])) {
// In this case there is no need to perform the computation on the individual objectives
optimalChoicesAtCurrentEpoch = newScheduler->getChoices();
optimalChoicesAtCurrentEpoch = newChoices;
PS.objectiveSolutionVectors[*consideredObjectives.begin()] = PS.weightedSolutionVector;
if (storm::solver::minimize(this->objectives[*consideredObjectives.begin()].optimizationDirection)) {
storm::utility::vector::scaleVectorInPlace(PS.objectiveSolutionVectors[*consideredObjectives.begin()], -storm::utility::one<ValueType>());
}
} else {
// check whether the linEqSolver needs to be updated, i.e., whether the scheduler has changed
if(linEq.solver == nullptr || newScheduler->getChoices() != optimalChoicesAtCurrentEpoch) {
optimalChoicesAtCurrentEpoch = newScheduler->getChoices();
if(linEq.solver == nullptr || newChoices != optimalChoicesAtCurrentEpoch) {
optimalChoicesAtCurrentEpoch = newChoices;
linEq.solver = nullptr;
storm::storage::SparseMatrix<ValueType> linEqMatrix = PS.toPS.selectRowsFromRowGroups(optimalChoicesAtCurrentEpoch, true);
linEqMatrix.convertToEquationSystem();

33
src/storm/modelchecker/multiobjective/pcaa/SparsePcaaWeightVectorChecker.cpp

@ -37,7 +37,8 @@ namespace storm {
checkHasBeenCalled(false),
objectiveResults(objectives.size()),
offsetsToUnderApproximation(objectives.size()),
offsetsToOverApproximation(objectives.size()) {
offsetsToOverApproximation(objectives.size()),
optimalChoices(model.getNumberOfStates(), 0) {
// set data for unbounded objectives
for(uint_fast64_t objIndex = 0; objIndex < objectives.size(); ++objIndex) {
@ -86,6 +87,7 @@ namespace storm {
}
unboundedWeightedPhase(weightedRewardVector, weightedLowerResultBound, weightedUpperResultBound);
unboundedIndividualPhase(weightVector);
// Only invoke boundedPhase if necessarry, i.e., if there is at least one objective with a time bound
for(auto const& obj : this->objectives) {
@ -136,19 +138,27 @@ namespace storm {
}
template <class SparseModelType>
storm::storage::TotalScheduler const& SparsePcaaWeightVectorChecker<SparseModelType>::getScheduler() const {
storm::storage::Scheduler<typename SparsePcaaWeightVectorChecker<SparseModelType>::ValueType> SparsePcaaWeightVectorChecker<SparseModelType>::computeScheduler() const {
STORM_LOG_THROW(this->checkHasBeenCalled, storm::exceptions::IllegalFunctionCallException, "Tried to retrieve results but check(..) has not been called before.");
for(auto const& obj : this->objectives) {
STORM_LOG_THROW(!obj.lowerTimeBound && !obj.upperTimeBound, storm::exceptions::NotImplementedException, "Scheduler retrival is not implemented for timeBounded objectives.");
}
return scheduler;
storm::storage::Scheduler<ValueType> result(this->optimalChoices.size());
uint_fast64_t state = 0;
for (auto const& choice : optimalChoices) {
result.setChoice(choice, state);
++state;
}
return result;
}
template <class SparseModelType>
void SparsePcaaWeightVectorChecker<SparseModelType>::unboundedWeightedPhase(std::vector<ValueType> const& weightedRewardVector, boost::optional<ValueType> const& lowerResultBound, boost::optional<ValueType> const& upperResultBound) {
if(this->objectivesWithNoUpperTimeBound.empty() || !storm::utility::vector::hasNonZeroEntry(weightedRewardVector)) {
if (this->objectivesWithNoUpperTimeBound.empty() || !storm::utility::vector::hasNonZeroEntry(weightedRewardVector)) {
this->weightedResult = std::vector<ValueType>(model.getNumberOfStates(), storm::utility::zero<ValueType>());
this->scheduler = storm::storage::TotalScheduler(model.getNumberOfStates());
this->optimalChoices = std::vector<uint_fast64_t>(model.getNumberOfStates(), 0);
return;
}
@ -183,16 +193,13 @@ namespace storm {
solver->solveEquations(subResult, subRewardVector);
this->weightedResult = std::vector<ValueType>(model.getNumberOfStates());
std::vector<uint_fast64_t> optimalChoices(model.getNumberOfStates());
transformReducedSolutionToOriginalModel(ecEliminatorResult.matrix, subResult, solver->getScheduler()->getChoices(), ecEliminatorResult.newToOldRowMapping, ecEliminatorResult.oldToNewStateMapping, this->weightedResult, optimalChoices);
this->scheduler = storm::storage::TotalScheduler(std::move(optimalChoices));
transformReducedSolutionToOriginalModel(ecEliminatorResult.matrix, subResult, solver->getSchedulerChoices(), ecEliminatorResult.newToOldRowMapping, ecEliminatorResult.oldToNewStateMapping, this->weightedResult, this->optimalChoices);
}
template <class SparseModelType>
void SparsePcaaWeightVectorChecker<SparseModelType>::unboundedIndividualPhase(std::vector<ValueType> const& weightVector) {
if (objectivesWithNoUpperTimeBound.getNumberOfSetBits() == 1 && storm::utility::isOne(weightVector[*objectivesWithNoUpperTimeBound.begin()])) {
if (objectivesWithNoUpperTimeBound.getNumberOfSetBits() == 1 && storm::utility::isOne(weightVector[*objectivesWithNoUpperTimeBound.begin()])) {
uint_fast64_t objIndex = *objectivesWithNoUpperTimeBound.begin();
objectiveResults[objIndex] = weightedResult;
if (storm::solver::minimize(objectives[objIndex].optimizationDirection)) {
@ -203,8 +210,8 @@ namespace storm {
objectiveResults[objIndex2] = std::vector<ValueType>(model.getNumberOfStates(), storm::utility::zero<ValueType>());
}
}
} else {
storm::storage::SparseMatrix<ValueType> deterministicMatrix = model.getTransitionMatrix().selectRowsFromRowGroups(this->scheduler.getChoices(), true);
} else {
storm::storage::SparseMatrix<ValueType> deterministicMatrix = model.getTransitionMatrix().selectRowsFromRowGroups(this->optimalChoices, true);
storm::storage::SparseMatrix<ValueType> deterministicBackwardTransitions = deterministicMatrix.transpose();
std::vector<ValueType> deterministicStateRewards(deterministicMatrix.getRowCount());
storm::solver::GeneralLinearEquationSolverFactory<ValueType> linearEquationSolverFactory;
@ -219,7 +226,7 @@ namespace storm {
if (objectivesWithNoUpperTimeBound.get(objIndex)) {
offsetsToUnderApproximation[objIndex] = storm::utility::zero<ValueType>();
offsetsToOverApproximation[objIndex] = storm::utility::zero<ValueType>();
storm::utility::vector::selectVectorValues(deterministicStateRewards, this->scheduler.getChoices(), model.getTransitionMatrix().getRowGroupIndices(), discreteActionRewards[objIndex]);
storm::utility::vector::selectVectorValues(deterministicStateRewards, this->optimalChoices, model.getTransitionMatrix().getRowGroupIndices(), discreteActionRewards[objIndex]);
storm::storage::BitVector statesWithRewards = ~storm::utility::vector::filterZero(deterministicStateRewards);
// As maybestates we pick the states from which a state with reward is reachable
storm::storage::BitVector maybeStates = storm::utility::graph::performProbGreater0(deterministicBackwardTransitions, storm::storage::BitVector(deterministicMatrix.getRowCount(), true), statesWithRewards);

9
src/storm/modelchecker/multiobjective/pcaa/SparsePcaaWeightVectorChecker.h

@ -4,7 +4,7 @@
#include "storm/storage/BitVector.h"
#include "storm/storage/SparseMatrix.h"
#include "storm/storage/TotalScheduler.h"
#include "storm/storage/Scheduler.h"
#include "storm/modelchecker/multiobjective/Objective.h"
#include "storm/utility/vector.h"
@ -75,8 +75,9 @@ namespace storm {
/*!
* Retrieves a scheduler that induces the current values
* Note that check(..) has to be called before retrieving the scheduler. Otherwise, an exception is thrown.
* Also note that (currently) the scheduler only supports unbounded objectives.
*/
storm::storage::TotalScheduler const& getScheduler() const;
storm::storage::Scheduler<ValueType> computeScheduler() const;
protected:
@ -147,8 +148,8 @@ namespace storm {
// The distances are stored as a (possibly negative) offset that has to be added (+) to to the objectiveResults.
std::vector<ValueType> offsetsToUnderApproximation;
std::vector<ValueType> offsetsToOverApproximation;
// The scheduler that optimizes the weighted rewards
storm::storage::TotalScheduler scheduler;
// The scheduler choices that optimize the weighted rewards of undounded objectives.
std::vector<uint_fast64_t> optimalChoices;
};

42
src/storm/modelchecker/parametric/SparseDtmcParameterLiftingModelChecker.cpp

@ -186,8 +186,8 @@ namespace storm {
if (lowerResultBound) solver->setLowerBound(lowerResultBound.get());
if (upperResultBound) solver->setUpperBound(upperResultBound.get());
if (!stepBound) solver->setTrackScheduler(true);
if (storm::solver::minimize(dirForParameters) && minSched && !stepBound) solver->setSchedulerHint(std::move(minSched.get()));
if (storm::solver::maximize(dirForParameters) && maxSched && !stepBound) solver->setSchedulerHint(std::move(maxSched.get()));
if (storm::solver::minimize(dirForParameters) && minSchedChoices && !stepBound) solver->setSchedulerHint(std::move(minSchedChoices.get()));
if (storm::solver::maximize(dirForParameters) && maxSchedChoices && !stepBound) solver->setSchedulerHint(std::move(maxSchedChoices.get()));
if (this->currentCheckTask->isBoundSet() && solver->hasSchedulerHint()) {
// If we reach this point, we know that after applying the hint, the x-values can only become larger (if we maximize) or smaller (if we minimize).
std::unique_ptr<storm::solver::TerminationCondition<ConstantType>> termCond;
@ -211,9 +211,9 @@ namespace storm {
x.resize(maybeStates.getNumberOfSetBits(), storm::utility::zero<ConstantType>());
solver->solveEquations(dirForParameters, x, parameterLifter->getVector());
if(storm::solver::minimize(dirForParameters)) {
minSched = std::move(*solver->getScheduler());
minSchedChoices = solver->getSchedulerChoices();
} else {
maxSched = std::move(*solver->getScheduler());
maxSchedChoices = solver->getSchedulerChoices();
}
}
@ -234,21 +234,43 @@ namespace storm {
resultsForNonMaybeStates.clear();
stepBound = boost::none;
parameterLifter = nullptr;
minSched = boost::none;
maxSched = boost::none;
minSchedChoices = boost::none;
maxSchedChoices = boost::none;
x.clear();
lowerResultBound = boost::none;
upperResultBound = boost::none;
}
template <typename SparseModelType, typename ConstantType>
boost::optional<storm::storage::TotalScheduler>& SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::getCurrentMinScheduler() {
return minSched;
boost::optional<storm::storage::Scheduler<ConstantType>> SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::getCurrentMinScheduler() {
if (!minSchedChoices) {
return boost::none;
}
storm::storage::Scheduler<ConstantType> result(minSchedChoices->size());
uint_fast64_t state = 0;
for (auto const& schedulerChoice : minSchedChoices.get()) {
result.setChoice(schedulerChoice, state);
++state;
}
return result;
}
template <typename SparseModelType, typename ConstantType>
boost::optional<storm::storage::TotalScheduler>& SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::getCurrentMaxScheduler() {
return maxSched;
boost::optional<storm::storage::Scheduler<ConstantType>> SparseDtmcParameterLiftingModelChecker<SparseModelType, ConstantType>::getCurrentMaxScheduler() {
if (!maxSchedChoices) {
return boost::none;
}
storm::storage::Scheduler<ConstantType> result(maxSchedChoices->size());
uint_fast64_t state = 0;
for (auto const& schedulerChoice : maxSchedChoices.get()) {
result.setChoice(schedulerChoice, state);
++state;
}
return result;
}
template class SparseDtmcParameterLiftingModelChecker<storm::models::sparse::Dtmc<storm::RationalFunction>, double>;

8
src/storm/modelchecker/parametric/SparseDtmcParameterLiftingModelChecker.h

@ -6,7 +6,7 @@
#include "storm/modelchecker/parametric/SparseParameterLiftingModelChecker.h"
#include "storm/storage/BitVector.h"
#include "storm/storage/TotalScheduler.h"
#include "storm/storage/Scheduler.h"
#include "storm/solver/MinMaxLinearEquationSolver.h"
#include "storm/transformer/ParameterLifter.h"
#include "storm/logic/FragmentSpecification.h"
@ -24,8 +24,8 @@ namespace storm {
virtual bool canHandle(CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) const override;
boost::optional<storm::storage::TotalScheduler>& getCurrentMinScheduler();
boost::optional<storm::storage::TotalScheduler>& getCurrentMaxScheduler();
boost::optional<storm::storage::Scheduler<ConstantType>> getCurrentMinScheduler();
boost::optional<storm::storage::Scheduler<ConstantType>> getCurrentMaxScheduler();
protected:
@ -47,7 +47,7 @@ namespace storm {
std::unique_ptr<storm::solver::MinMaxLinearEquationSolverFactory<ConstantType>> solverFactory;
// Results from the most recent solver call.
boost::optional<storm::storage::TotalScheduler> minSched, maxSched;
boost::optional<std::vector<uint_fast64_t>> minSchedChoices, maxSchedChoices;
std::vector<ConstantType> x;
boost::optional<ConstantType> lowerResultBound, upperResultBound;
};

8
src/storm/modelchecker/parametric/SparseDtmcRegionChecker.cpp

@ -47,8 +47,12 @@ namespace storm {
STORM_LOG_ASSERT(dtmcPLChecker, "Underlying Parameter lifting checker has unexpected type");
auto exactDtmcPLChecker = dynamic_cast<storm::modelchecker::parametric::SparseDtmcParameterLiftingModelChecker<SparseModelType, ExactConstantType>*>(this->exactParameterLiftingChecker.get());
STORM_LOG_ASSERT(exactDtmcPLChecker, "Underlying exact parameter lifting checker has unexpected type");
exactDtmcPLChecker->getCurrentMaxScheduler() = dtmcPLChecker->getCurrentMaxScheduler();
exactDtmcPLChecker->getCurrentMinScheduler() = dtmcPLChecker->getCurrentMinScheduler();
if (dtmcPLChecker->getCurrentMaxScheduler()) {
exactDtmcPLChecker->getCurrentMaxScheduler() = dtmcPLChecker->getCurrentMaxScheduler()->template toValueType<ExactConstantType>();
}
if (dtmcPLChecker->getCurrentMinScheduler()) {
exactDtmcPLChecker->getCurrentMinScheduler() = dtmcPLChecker->getCurrentMinScheduler()->template toValueType<ExactConstantType>();
}
}
#ifdef STORM_HAVE_CARL

17
src/storm/modelchecker/parametric/SparseMdpInstantiationModelChecker.cpp

@ -4,6 +4,7 @@
#include "storm/modelchecker/results/ExplicitQuantitativeCheckResult.h"
#include "storm/modelchecker/results/ExplicitQualitativeCheckResult.h"
#include "storm/modelchecker/hints/ExplicitModelCheckerHint.h"
#include "storm/storage/Scheduler.h"
#include "storm/utility/graph.h"
#include "storm/utility/vector.h"
@ -53,16 +54,16 @@ namespace storm {
// For qualitative properties, we still want a quantitative result hint. Hence we perform the check on the subformula
if(this->currentCheckTask->getFormula().asOperatorFormula().hasQuantitativeResult()) {
result = modelChecker.check(*this->currentCheckTask);
storm::storage::Scheduler const& scheduler = result->template asExplicitQuantitativeCheckResult<ConstantType>().getScheduler();
storm::storage::Scheduler<ConstantType> const& scheduler = result->template asExplicitQuantitativeCheckResult<ConstantType>().getScheduler();
hint.setResultHint(result->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector());
hint.setSchedulerHint(dynamic_cast<storm::storage::TotalScheduler const&>(scheduler));
hint.setSchedulerHint(dynamic_cast<storm::storage::Scheduler<ConstantType> const&>(scheduler));
} else {
auto newCheckTask = this->currentCheckTask->substituteFormula(this->currentCheckTask->getFormula().asOperatorFormula().getSubformula()).setOnlyInitialStatesRelevant(false);
std::unique_ptr<storm::modelchecker::CheckResult> quantitativeResult = modelChecker.computeProbabilities(newCheckTask);
result = quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().compareAgainstBound(this->currentCheckTask->getFormula().asOperatorFormula().getComparisonType(), this->currentCheckTask->getFormula().asOperatorFormula().template getThresholdAs<ConstantType>());
storm::storage::Scheduler& scheduler = quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().getScheduler();
storm::storage::Scheduler<ConstantType>& scheduler = quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().getScheduler();
hint.setResultHint(std::move(quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector()));
hint.setSchedulerHint(std::move(dynamic_cast<storm::storage::TotalScheduler&>(scheduler)));
hint.setSchedulerHint(std::move(dynamic_cast<storm::storage::Scheduler<ConstantType>&>(scheduler)));
}
if (this->getInstantiationsAreGraphPreserving() && !hint.hasMaybeStates()) {
@ -98,16 +99,16 @@ namespace storm {
// For qualitative properties, we still want a quantitative result hint. Hence we perform the check on the subformula
if(this->currentCheckTask->getFormula().asOperatorFormula().hasQuantitativeResult()) {
std::unique_ptr<storm::modelchecker::CheckResult> result = modelChecker.check(*this->currentCheckTask);
storm::storage::Scheduler const& scheduler = result->template asExplicitQuantitativeCheckResult<ConstantType>().getScheduler();
storm::storage::Scheduler<ConstantType> const& scheduler = result->template asExplicitQuantitativeCheckResult<ConstantType>().getScheduler();
hint.setResultHint(result->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector());
hint.setSchedulerHint(dynamic_cast<storm::storage::TotalScheduler const&>(scheduler));
hint.setSchedulerHint(dynamic_cast<storm::storage::Scheduler<ConstantType> const&>(scheduler));
} else {
auto newCheckTask = this->currentCheckTask->substituteFormula(this->currentCheckTask->getFormula().asOperatorFormula().getSubformula()).setOnlyInitialStatesRelevant(false);
std::unique_ptr<storm::modelchecker::CheckResult> quantitativeResult = modelChecker.computeRewards(this->currentCheckTask->getFormula().asRewardOperatorFormula().getMeasureType(), newCheckTask);
result = quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().compareAgainstBound(this->currentCheckTask->getFormula().asOperatorFormula().getComparisonType(), this->currentCheckTask->getFormula().asOperatorFormula().template getThresholdAs<ConstantType>());
storm::storage::Scheduler& scheduler = quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().getScheduler();
storm::storage::Scheduler<ConstantType>& scheduler = quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().getScheduler();
hint.setResultHint(std::move(quantitativeResult->template asExplicitQuantitativeCheckResult<ConstantType>().getValueVector()));
hint.setSchedulerHint(std::move(dynamic_cast<storm::storage::TotalScheduler&>(scheduler)));
hint.setSchedulerHint(std::move(dynamic_cast<storm::storage::Scheduler<ConstantType>&>(scheduler)));
}
if (this->getInstantiationsAreGraphPreserving() && !hint.hasMaybeStates()) {

1
src/storm/modelchecker/parametric/SparseMdpInstantiationModelChecker.h

@ -8,7 +8,6 @@
#include "storm/modelchecker/parametric/SparseInstantiationModelChecker.h"
#include "storm/modelchecker/prctl/SparseMdpPrctlModelChecker.h"
#include "storm/utility/ModelInstantiator.h"
#include "storm/storage/TotalScheduler.h"
namespace storm {
namespace modelchecker {

59
src/storm/modelchecker/parametric/SparseMdpParameterLiftingModelChecker.cpp

@ -214,8 +214,8 @@ namespace storm {
if (applyPreviousResultAsHint) {
solver->setTrackSchedulers(true);
x.resize(maybeStates.getNumberOfSetBits(), storm::utility::zero<ConstantType>());
if(storm::solver::minimize(dirForParameters) && minSched && player1Sched) solver->setSchedulerHints(std::move(player1Sched.get()), std::move(minSched.get()));
if(storm::solver::maximize(dirForParameters) && maxSched && player1Sched) solver->setSchedulerHints(std::move(player1Sched.get()), std::move(maxSched.get()));
if(storm::solver::minimize(dirForParameters) && minSchedChoices && player1SchedChoices) solver->setSchedulerHints(std::move(player1SchedChoices.get()), std::move(minSchedChoices.get()));
if(storm::solver::maximize(dirForParameters) && maxSchedChoices && player1SchedChoices) solver->setSchedulerHints(std::move(player1SchedChoices.get()), std::move(maxSchedChoices.get()));
} else {
x.assign(maybeStates.getNumberOfSetBits(), storm::utility::zero<ConstantType>());
}
@ -241,11 +241,11 @@ namespace storm {
solver->solveGame(this->currentCheckTask->getOptimizationDirection(), dirForParameters, x, parameterLifter->getVector());
if(applyPreviousResultAsHint) {
if(storm::solver::minimize(dirForParameters)) {
minSched = std::move(*solver->getPlayer2Scheduler());
minSchedChoices = solver->getPlayer2SchedulerChoices();
} else {
maxSched = std::move(*solver->getPlayer2Scheduler());
maxSchedChoices = solver->getPlayer2SchedulerChoices();
}
player1Sched = std::move(*solver->getPlayer1Scheduler());
player1SchedChoices = solver->getPlayer1SchedulerChoices();
}
}
@ -285,8 +285,8 @@ namespace storm {
stepBound = boost::none;
player1Matrix = storm::storage::SparseMatrix<storm::storage::sparse::state_type>();
parameterLifter = nullptr;
minSched = boost::none;
maxSched = boost::none;
minSchedChoices = boost::none;
maxSchedChoices = boost::none;
x.clear();
lowerResultBound = boost::none;
upperResultBound = boost::none;
@ -294,18 +294,51 @@ namespace storm {
}
template <typename SparseModelType, typename ConstantType>
boost::optional<storm::storage::TotalScheduler>& SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::getCurrentMinScheduler() {
return minSched;
boost::optional<storm::storage::Scheduler<ConstantType>> SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::getCurrentMinScheduler() {
if (!minSchedChoices) {
return boost::none;
}
storm::storage::Scheduler<ConstantType> result(minSchedChoices->size());
uint_fast64_t state = 0;
for (auto const& schedulerChoice : minSchedChoices.get()) {
result.setChoice(schedulerChoice, state);
++state;
}
return result;
}
template <typename SparseModelType, typename ConstantType>
boost::optional<storm::storage::TotalScheduler>& SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::getCurrentMaxScheduler() {
return maxSched;
boost::optional<storm::storage::Scheduler<ConstantType>> SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::getCurrentMaxScheduler() {
if (!maxSchedChoices) {
return boost::none;
}
storm::storage::Scheduler<ConstantType> result(maxSchedChoices->size());
uint_fast64_t state = 0;
for (auto const& schedulerChoice : maxSchedChoices.get()) {
result.setChoice(schedulerChoice, state);
++state;
}
return result;
}
template <typename SparseModelType, typename ConstantType>
boost::optional<storm::storage::TotalScheduler>& SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::getCurrentPlayer1Scheduler() {
return player1Sched;
boost::optional<storm::storage::Scheduler<ConstantType>> SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::getCurrentPlayer1Scheduler() {
if (!player1SchedChoices) {
return boost::none;
}
storm::storage::Scheduler<ConstantType> result(player1SchedChoices->size());
uint_fast64_t state = 0;
for (auto const& schedulerChoice : player1SchedChoices.get()) {
result.setChoice(schedulerChoice, state);
++state;
}
return result;
}
template class SparseMdpParameterLiftingModelChecker<storm::models::sparse::Mdp<storm::RationalFunction>, double>;

12
src/storm/modelchecker/parametric/SparseMdpParameterLiftingModelChecker.h

@ -10,7 +10,7 @@
#include "storm/storage/sparse/StateType.h"
#include "storm/solver/GameSolver.h"
#include "storm/transformer/ParameterLifter.h"
#include "storm/storage/TotalScheduler.h"
#include "storm/storage/Scheduler.h"
namespace storm {
namespace modelchecker {
@ -24,9 +24,9 @@ namespace storm {
virtual bool canHandle(CheckTask<storm::logic::Formula, typename SparseModelType::ValueType> const& checkTask) const override;
boost::optional<storm::storage::TotalScheduler>& getCurrentMinScheduler();
boost::optional<storm::storage::TotalScheduler>& getCurrentMaxScheduler();
boost::optional<storm::storage::TotalScheduler>& getCurrentPlayer1Scheduler();
boost::optional<storm::storage::Scheduler<ConstantType>> getCurrentMinScheduler();
boost::optional<storm::storage::Scheduler<ConstantType>> getCurrentMaxScheduler();
boost::optional<storm::storage::Scheduler<ConstantType>> getCurrentPlayer1Scheduler();
protected:
@ -52,8 +52,8 @@ namespace storm {
std::unique_ptr<storm::solver::GameSolverFactory<ConstantType>> solverFactory;
// Results from the most recent solver call.
boost::optional<storm::storage::TotalScheduler> minSched, maxSched;
boost::optional<storm::storage::TotalScheduler> player1Sched;
boost::optional<std::vector<uint_fast64_t>> minSchedChoices, maxSchedChoices;
boost::optional<std::vector<uint_fast64_t>> player1SchedChoices;
std::vector<ConstantType> x;
boost::optional<ConstantType> lowerResultBound, upperResultBound;
bool applyPreviousResultAsHint;

12
src/storm/modelchecker/parametric/SparseMdpRegionChecker.cpp

@ -48,9 +48,15 @@ namespace storm {
STORM_LOG_ASSERT(MdpPLChecker, "Underlying Parameter lifting checker has unexpected type");
auto exactMdpPLChecker = dynamic_cast<storm::modelchecker::parametric::SparseMdpParameterLiftingModelChecker<SparseModelType, ExactConstantType>*>(this->exactParameterLiftingChecker.get());
STORM_LOG_ASSERT(exactMdpPLChecker, "Underlying exact parameter lifting checker has unexpected type");
exactMdpPLChecker->getCurrentMaxScheduler() = MdpPLChecker->getCurrentMaxScheduler();
exactMdpPLChecker->getCurrentMinScheduler() = MdpPLChecker->getCurrentMinScheduler();
exactMdpPLChecker->getCurrentPlayer1Scheduler() = MdpPLChecker->getCurrentPlayer1Scheduler();
if (MdpPLChecker->getCurrentMaxScheduler()) {
exactMdpPLChecker->getCurrentMaxScheduler() = MdpPLChecker->getCurrentMaxScheduler()->template toValueType<ExactConstantType>();
}
if (MdpPLChecker->getCurrentMinScheduler()) {
exactMdpPLChecker->getCurrentMinScheduler() = MdpPLChecker->getCurrentMinScheduler()->template toValueType<ExactConstantType>();
}
if (MdpPLChecker->getCurrentPlayer1Scheduler()) {
exactMdpPLChecker->getCurrentPlayer1Scheduler() = MdpPLChecker->getCurrentPlayer1Scheduler()->template toValueType<ExactConstantType>();
}
}

4
src/storm/modelchecker/prctl/helper/MDPModelCheckingHelperReturnType.h

@ -18,7 +18,7 @@ namespace storm {
MDPSparseModelCheckingHelperReturnType(MDPSparseModelCheckingHelperReturnType const&) = delete;
MDPSparseModelCheckingHelperReturnType(MDPSparseModelCheckingHelperReturnType&&) = default;
MDPSparseModelCheckingHelperReturnType(std::vector<ValueType>&& values, std::unique_ptr<storm::storage::Scheduler>&& scheduler = nullptr) : values(std::move(values)), scheduler(std::move(scheduler)) {
MDPSparseModelCheckingHelperReturnType(std::vector<ValueType>&& values, std::unique_ptr<storm::storage::Scheduler<ValueType>>&& scheduler = nullptr) : values(std::move(values)), scheduler(std::move(scheduler)) {
// Intentionally left empty.
}
@ -30,7 +30,7 @@ namespace storm {
std::vector<ValueType> values;
// A scheduler, if it was computed.
std::unique_ptr<storm::storage::Scheduler> scheduler;
std::unique_ptr<storm::storage::Scheduler<ValueType>> scheduler;
};
}

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

@ -13,7 +13,7 @@
#include "storm/storage/expressions/Variable.h"
#include "storm/storage/expressions/Expression.h"
#include "storm/storage/TotalScheduler.h"
#include "storm/storage/Scheduler.h"
#include "storm/solver/MinMaxLinearEquationSolver.h"
#include "storm/solver/LpSolver.h"
@ -126,9 +126,9 @@ namespace storm {
}
// If requested, we will produce a scheduler.
std::unique_ptr<storm::storage::TotalScheduler> scheduler;
std::unique_ptr<storm::storage::Scheduler<ValueType>> scheduler;
if (produceScheduler) {
scheduler = std::make_unique<storm::storage::TotalScheduler>(transitionMatrix.getRowGroupCount());
scheduler = std::make_unique<storm::storage::Scheduler<ValueType>>(transitionMatrix.getRowGroupCount());
}
// Check whether we need to compute exact probabilities for some states.
@ -147,43 +147,105 @@ namespace storm {
// the accumulated probability of going from state i to some 'yes' state.
std::vector<ValueType> b = transitionMatrix.getConstrainedRowGroupSumVector(maybeStates, statesWithProbability1);
// Now compute the results for the maybeStates
// obtain hint information if possible
bool skipEcWithinMaybeStatesCheck = goal.minimize() || (hint.isExplicitModelCheckerHint() && hint.asExplicitModelCheckerHint<ValueType>().getNoEndComponentsInMaybeStates());
MDPSparseModelCheckingHelperReturnType<ValueType> resultForMaybeStates = computeValuesOnlyMaybeStates(goal, transitionMatrix, backwardTransitions, maybeStates, submatrix, b, produceScheduler, minMaxLinearEquationSolverFactory, hint, skipEcWithinMaybeStatesCheck, storm::utility::zero<ValueType>(), storm::utility::one<ValueType>());
std::pair<boost::optional<std::vector<ValueType>>, boost::optional<std::vector<uint_fast64_t>>> hintInformation = extractHintInformationForMaybeStates(transitionMatrix, backwardTransitions, maybeStates, boost::none, hint, skipEcWithinMaybeStatesCheck);
// Now compute the results for the maybeStates
std::pair<std::vector<ValueType>, boost::optional<std::vector<uint_fast64_t>>> resultForMaybeStates = computeValuesOnlyMaybeStates(goal, submatrix, b, produceScheduler, minMaxLinearEquationSolverFactory, std::move(hintInformation.first), std::move(hintInformation.second), storm::utility::zero<ValueType>(), storm::utility::one<ValueType>());
// Set values of resulting vector according to result.
storm::utility::vector::setVectorValues<ValueType>(result, maybeStates, resultForMaybeStates.values);
storm::utility::vector::setVectorValues<ValueType>(result, maybeStates, resultForMaybeStates.first);
if (produceScheduler) {
storm::storage::Scheduler const& subscheduler = *resultForMaybeStates.scheduler;
uint_fast64_t currentSubState = 0;
std::vector<uint_fast64_t> const& subChoices = resultForMaybeStates.second.get();
auto subChoiceIt = subChoices.begin();
for (auto maybeState : maybeStates) {
scheduler->setChoice(maybeState, subscheduler.getChoice(currentSubState));
++currentSubState;
scheduler->setChoice(*subChoiceIt, maybeState);
++subChoiceIt;
}
assert(subChoiceIt == subChoices.end());
}
}
}
// 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).
// the states with probability 1 or 0 (depending on whether we maximize or minimize).
// We also need to define some arbitrary choice for the remaining states to obtain a fully defined scheduler.
if (produceScheduler) {
storm::storage::PartialScheduler relevantQualitativeScheduler;
if (goal.minimize()) {
relevantQualitativeScheduler = storm::utility::graph::computeSchedulerProb0E(statesWithProbability0, transitionMatrix);
storm::utility::graph::computeSchedulerProb0E(statesWithProbability0, transitionMatrix, *scheduler);
for (auto const& prob1State : statesWithProbability1) {
scheduler->setChoice(0, prob1State);
}
} else {
relevantQualitativeScheduler = storm::utility::graph::computeSchedulerProb1E(statesWithProbability1, transitionMatrix, backwardTransitions, phiStates, psiStates);
}
for (auto const& stateChoicePair : relevantQualitativeScheduler) {
scheduler->setChoice(stateChoicePair.first, stateChoicePair.second);
storm::utility::graph::computeSchedulerProb1E(statesWithProbability1, transitionMatrix, backwardTransitions, phiStates, psiStates, *scheduler);
for (auto const& prob0State : statesWithProbability0) {
scheduler->setChoice(0, prob0State);
}
}
}
STORM_LOG_ASSERT((!produceScheduler && !scheduler) || (!scheduler->isPartialScheduler() && scheduler->isDeterministicScheduler() && scheduler->isMemorylessScheduler()), "Unexpected format of obtained scheduler.");
return MDPSparseModelCheckingHelperReturnType<ValueType>(std::move(result), std::move(scheduler));
}
template<typename ValueType>
MDPSparseModelCheckingHelperReturnType<ValueType> SparseMdpPrctlHelper<ValueType>::computeValuesOnlyMaybeStates(storm::solver::SolveGoal const& goal, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& maybeStates, storm::storage::SparseMatrix<ValueType> const& submatrix, std::vector<ValueType> const& b, bool produceScheduler, storm::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory, ModelCheckerHint const& hint, bool skipECWithinMaybeStatesCheck, boost::optional<ValueType> const& lowerResultBound, boost::optional<ValueType> const& upperResultBound) {
std::pair<boost::optional<std::vector<ValueType>>, boost::optional<std::vector<uint_fast64_t>>> SparseMdpPrctlHelper<ValueType>::extractHintInformationForMaybeStates(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& maybeStates, boost::optional<storm::storage::BitVector> const& selectedChoices, ModelCheckerHint const& hint, bool skipECWithinMaybeStatesCheck) {
// Scheduler hint
boost::optional<std::vector<uint_fast64_t>> subSchedulerChoices;
if (hint.isExplicitModelCheckerHint() && hint.template asExplicitModelCheckerHint<ValueType>().hasSchedulerHint()) {
auto const& schedulerHint = hint.template asExplicitModelCheckerHint<ValueType>().getSchedulerHint();
std::vector<uint_fast64_t> hintChoices;
// the scheduler hint is only applicable if it induces no BSCC consisting of maybestates
bool hintApplicable;
if (!skipECWithinMaybeStatesCheck) {
hintChoices.reserve(maybeStates.size());
for (uint_fast64_t state = 0; state < maybeStates.size(); ++state) {
hintChoices.push_back(schedulerHint.getChoice(state).getDeterministicChoice());
}
hintApplicable = storm::utility::graph::performProb1(transitionMatrix.transposeSelectedRowsFromRowGroups(hintChoices), maybeStates, ~maybeStates).full();
} else {
hintApplicable = true;
}
if (hintApplicable) {
// Compute the hint w.r.t. the given subsystem
hintChoices.clear();
hintChoices.reserve(maybeStates.getNumberOfSetBits());
for (auto const& state : maybeStates) {
uint_fast64_t hintChoice = schedulerHint.getChoice(state).getDeterministicChoice();
if (selectedChoices) {
uint_fast64_t firstChoice = transitionMatrix.getRowGroupIndices()[state];
uint_fast64_t lastChoice = firstChoice + hintChoice;
hintChoice = 0;
for (uint_fast64_t choice = selectedChoices->getNextSetIndex(firstChoice); choice < lastChoice; choice = selectedChoices->getNextSetIndex(choice + 1)) {
++hintChoice;
}
}
hintChoices.push_back(hintChoice);
}
subSchedulerChoices = std::move(hintChoices);
}
}
// Solution value hint
boost::optional<std::vector<ValueType>> subValues;
// The result hint is only applicable if there are no End Components consisting of maybestates
if (hint.isExplicitModelCheckerHint() && hint.template asExplicitModelCheckerHint<ValueType>().hasResultHint() &&
(skipECWithinMaybeStatesCheck || subSchedulerChoices ||
storm::utility::graph::performProb1A(transitionMatrix, transitionMatrix.getRowGroupIndices(), backwardTransitions, maybeStates, ~maybeStates).full())) {
subValues = storm::utility::vector::filterVector(hint.template asExplicitModelCheckerHint<ValueType>().getResultHint(), maybeStates);
}
return std::make_pair(std::move(subValues), std::move(subSchedulerChoices));
}
template<typename ValueType>
std::pair<std::vector<ValueType>, boost::optional<std::vector<uint_fast64_t>>> SparseMdpPrctlHelper<ValueType>::computeValuesOnlyMaybeStates(storm::solver::SolveGoal const& goal, storm::storage::SparseMatrix<ValueType> const& submatrix, std::vector<ValueType> const& b, bool produceScheduler, storm::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory, boost::optional<std::vector<ValueType>>&& hintValues, boost::optional<std::vector<uint_fast64_t>>&& hintChoices, boost::optional<ValueType> const& lowerResultBound, boost::optional<ValueType> const& upperResultBound) {
// Set up the solver
std::unique_ptr<storm::solver::MinMaxLinearEquationSolver<ValueType>> solver = storm::solver::configureMinMaxLinearEquationSolver(goal, minMaxLinearEquationSolverFactory, submatrix);
@ -193,33 +255,22 @@ namespace storm {
if (upperResultBound) {
solver->setUpperBound(upperResultBound.get());
}
// the scheduler hint is only applicable if it induces no BSCC consisting of maybestates
if (hint.isExplicitModelCheckerHint() && hint.template asExplicitModelCheckerHint<ValueType>().hasSchedulerHint() &&
(skipECWithinMaybeStatesCheck ||
storm::utility::graph::performProb1(transitionMatrix.transposeSelectedRowsFromRowGroups(hint.template asExplicitModelCheckerHint<ValueType>().getSchedulerHint().getChoices()), maybeStates, ~maybeStates).full())) {
solver->setSchedulerHint(hint.template asExplicitModelCheckerHint<ValueType>().getSchedulerHint().getSchedulerForSubsystem(maybeStates));
if (hintChoices) {
solver->setSchedulerHint(std::move(hintChoices.get()));
}
solver->setTrackScheduler(produceScheduler);
// Create the solution vector.
std::vector<ValueType> x;
// The result hint is only applicable if there are no End Components consisting of maybestates
if (hint.isExplicitModelCheckerHint() && hint.template asExplicitModelCheckerHint<ValueType>().hasResultHint() &&
(skipECWithinMaybeStatesCheck || solver->hasSchedulerHint() ||
storm::utility::graph::performProb1A(transitionMatrix, transitionMatrix.getRowGroupIndices(), backwardTransitions, maybeStates, ~maybeStates).full())) {
x = storm::utility::vector::filterVector(hint.template asExplicitModelCheckerHint<ValueType>().getResultHint(), maybeStates);
} else {
x = std::vector<ValueType>(submatrix.getRowGroupCount(), lowerResultBound ? lowerResultBound.get() : storm::utility::zero<ValueType>());
}
// Initialize the solution vector.
std::vector<ValueType> x = hintValues ? std::move(hintValues.get()) : std::vector<ValueType>(submatrix.getRowGroupCount(), lowerResultBound ? lowerResultBound.get() : storm::utility::zero<ValueType>());
// Solve the corresponding system of equations.
solver->solveEquations(x, b);
// If requested, a scheduler was produced
if (produceScheduler) {
return MDPSparseModelCheckingHelperReturnType<ValueType>(std::move(x), std::move(solver->getScheduler()));
return std::pair<std::vector<ValueType>, boost::optional<std::vector<uint_fast64_t>>>(std::move(x), std::move(solver->getSchedulerChoices()));
} else {
return MDPSparseModelCheckingHelperReturnType<ValueType>(std::move(x));
return std::pair<std::vector<ValueType>, boost::optional<std::vector<uint_fast64_t>>>(std::move(x), boost::none);
}
}
@ -363,9 +414,9 @@ namespace storm {
storm::utility::vector::setVectorValues(result, infinityStates, storm::utility::infinity<ValueType>());
// If requested, we will produce a scheduler.
std::unique_ptr<storm::storage::TotalScheduler> scheduler;
std::unique_ptr<storm::storage::Scheduler<ValueType>> scheduler;
if (produceScheduler) {
scheduler = std::make_unique<storm::storage::TotalScheduler>(transitionMatrix.getRowGroupCount());
scheduler = std::make_unique<storm::storage::Scheduler<ValueType>>(transitionMatrix.getRowGroupCount());
}
// Check whether we need to compute exact rewards for some states.
@ -394,50 +445,58 @@ namespace storm {
storm::utility::vector::filterVectorInPlace(b, *selectedChoices);
}
// obtain hint information if possible
bool skipEcWithinMaybeStatesCheck = !goal.minimize() || (hint.isExplicitModelCheckerHint() && hint.asExplicitModelCheckerHint<ValueType>().getNoEndComponentsInMaybeStates());
std::pair<boost::optional<std::vector<ValueType>>, boost::optional<std::vector<uint_fast64_t>>> hintInformation = extractHintInformationForMaybeStates(transitionMatrix, backwardTransitions, maybeStates, selectedChoices, hint, skipEcWithinMaybeStatesCheck);
// Now compute the results for the maybeStates
MDPSparseModelCheckingHelperReturnType<ValueType> resultForMaybeStates = computeValuesOnlyMaybeStates(goal, transitionMatrix, backwardTransitions, maybeStates, submatrix, b, produceScheduler, minMaxLinearEquationSolverFactory, hint, skipEcWithinMaybeStatesCheck, storm::utility::zero<ValueType>());
std::pair<std::vector<ValueType>, boost::optional<std::vector<uint_fast64_t>>> resultForMaybeStates = computeValuesOnlyMaybeStates(goal, submatrix, b, produceScheduler, minMaxLinearEquationSolverFactory, std::move(hintInformation.first), std::move(hintInformation.second), storm::utility::zero<ValueType>());
// Set values of resulting vector according to result.
storm::utility::vector::setVectorValues<ValueType>(result, maybeStates, resultForMaybeStates.values);
storm::utility::vector::setVectorValues<ValueType>(result, maybeStates, resultForMaybeStates.first);
if (produceScheduler) {
storm::storage::Scheduler const& subscheduler = *resultForMaybeStates.scheduler;
std::vector<uint_fast64_t> const& subChoices = resultForMaybeStates.second.get();
auto subChoiceIt = subChoices.begin();
if (selectedChoices) {
uint_fast64_t currentSubState = 0;
for (auto maybeState : maybeStates) {
uint_fast64_t subChoice = subscheduler.getChoice(currentSubState);
// find the rowindex that corresponds to the selected row of the submodel
uint_fast64_t firstRowIndex = transitionMatrix.getRowGroupIndices()[maybeState];
uint_fast64_t selectedRowIndex = selectedChoices->getNextSetIndex(firstRowIndex);
for (uint_fast64_t choice = 0; choice < subChoice; ++choice) {
for (uint_fast64_t choice = 0; choice < *subChoiceIt; ++choice) {
selectedRowIndex = selectedChoices->getNextSetIndex(selectedRowIndex + 1);
}
scheduler->setChoice(maybeState, selectedRowIndex - firstRowIndex);
++currentSubState;
scheduler->setChoice(selectedRowIndex - firstRowIndex, maybeState);
++subChoiceIt;
}
} else {
uint_fast64_t currentSubState = 0;
for (auto maybeState : maybeStates) {
scheduler->setChoice(maybeState, subscheduler.getChoice(currentSubState));
++currentSubState;
scheduler->setChoice(*subChoiceIt, maybeState);
++subChoiceIt;
}
}
assert(subChoiceIt == subChoices.end());
}
}
}
// Finally, if we need to produce a scheduler, we also need to figure out the parts of the scheduler for
// the states with reward infinity.
// the states with reward infinity. Moreover, we have to set some arbitrary choice for the remaining states
// to obtain a fully defined scheduler
if (produceScheduler) {
storm::storage::PartialScheduler relevantQualitativeScheduler;
if (!goal.minimize()) {
relevantQualitativeScheduler = storm::utility::graph::computeSchedulerProb0E(infinityStates, transitionMatrix);
storm::utility::graph::computeSchedulerProb0E(infinityStates, transitionMatrix, *scheduler);
} else {
for (auto const& state : infinityStates) {
scheduler->setChoice(0, state);
}
}
for (auto const& stateChoicePair : relevantQualitativeScheduler) {
scheduler->setChoice(stateChoicePair.first, stateChoicePair.second);
for (auto const& state : targetStates) {
scheduler->setChoice(0, state);
}
}
STORM_LOG_ASSERT((!produceScheduler && !scheduler) || (!scheduler->isPartialScheduler() && scheduler->isDeterministicScheduler() && scheduler->isMemorylessScheduler()), "Unexpected format of obtained scheduler.");
return MDPSparseModelCheckingHelperReturnType<ValueType>(std::move(result), std::move(scheduler));
}

4
src/storm/modelchecker/prctl/helper/SparseMdpPrctlHelper.h

@ -39,7 +39,9 @@ namespace storm {
static MDPSparseModelCheckingHelperReturnType<ValueType> computeUntilProbabilities(OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, bool produceScheduler, storm::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory, ModelCheckerHint const& hint = ModelCheckerHint());
static MDPSparseModelCheckingHelperReturnType<ValueType> computeValuesOnlyMaybeStates(storm::solver::SolveGoal const& goal, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& maybeStates, storm::storage::SparseMatrix<ValueType> const& submatrix, std::vector<ValueType> const& b, bool produceScheduler, storm::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory, ModelCheckerHint const& hint = ModelCheckerHint(), bool skipECWithinMaybeStatesCheck = false, boost::optional<ValueType> const& lowerResultBound = boost::none, boost::optional<ValueType> const& upperResultBound = boost::none);
static std::pair<boost::optional<std::vector<ValueType>>, boost::optional<std::vector<uint_fast64_t>>> extractHintInformationForMaybeStates(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& maybeStates, boost::optional<storm::storage::BitVector> const& selectedChoices, ModelCheckerHint const& hint, bool skipECWithinMaybeStatesCheck);
static std::pair<std::vector<ValueType>, boost::optional<std::vector<uint_fast64_t>>> computeValuesOnlyMaybeStates(storm::solver::SolveGoal const& goal, storm::storage::SparseMatrix<ValueType> const& submatrix, std::vector<ValueType> const& b, bool produceScheduler, storm::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory, boost::optional<std::vector<ValueType>>&& hintValues = boost::none, boost::optional<std::vector<uint_fast64_t>>&& hintChoices = boost::none, boost::optional<ValueType> const& lowerResultBound = boost::none, boost::optional<ValueType> const& upperResultBound = boost::none);
static MDPSparseModelCheckingHelperReturnType<ValueType> computeUntilProbabilities(storm::solver::SolveGoal const& goal, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool qualitative, bool produceScheduler, storm::solver::MinMaxLinearEquationSolverFactory<ValueType> const& minMaxLinearEquationSolverFactory, ModelCheckerHint const& hint = ModelCheckerHint());

6
src/storm/modelchecker/results/ExplicitQuantitativeCheckResult.cpp

@ -166,18 +166,18 @@ namespace storm {
}
template<typename ValueType>
void ExplicitQuantitativeCheckResult<ValueType>::setScheduler(std::unique_ptr<storm::storage::Scheduler>&& scheduler) {
void ExplicitQuantitativeCheckResult<ValueType>::setScheduler(std::unique_ptr<storm::storage::Scheduler<ValueType>>&& scheduler) {
this->scheduler = std::move(scheduler);
}
template<typename ValueType>
storm::storage::Scheduler const& ExplicitQuantitativeCheckResult<ValueType>::getScheduler() const {
storm::storage::Scheduler<ValueType> const& ExplicitQuantitativeCheckResult<ValueType>::getScheduler() const {
STORM_LOG_THROW(this->hasScheduler(), storm::exceptions::InvalidOperationException, "Unable to retrieve non-existing scheduler.");
return *scheduler.get();
}
template<typename ValueType>
storm::storage::Scheduler& ExplicitQuantitativeCheckResult<ValueType>::getScheduler() {
storm::storage::Scheduler<ValueType>& ExplicitQuantitativeCheckResult<ValueType>::getScheduler() {
STORM_LOG_THROW(this->hasScheduler(), storm::exceptions::InvalidOperationException, "Unable to retrieve non-existing scheduler.");
return *scheduler.get();
}

8
src/storm/modelchecker/results/ExplicitQuantitativeCheckResult.h

@ -62,16 +62,16 @@ namespace storm {
virtual ValueType sum() const override;
bool hasScheduler() const;
void setScheduler(std::unique_ptr<storm::storage::Scheduler>&& scheduler);
storm::storage::Scheduler const& getScheduler() const;
storm::storage::Scheduler& getScheduler();
void setScheduler(std::unique_ptr<storm::storage::Scheduler<ValueType>>&& scheduler);
storm::storage::Scheduler<ValueType> const& getScheduler() const;
storm::storage::Scheduler<ValueType>& getScheduler();
private:
// The values of the quantitative check result.
boost::variant<vector_type, map_type> values;
// An optional scheduler that accompanies the values.
boost::optional<std::shared_ptr<storm::storage::Scheduler>> scheduler;
boost::optional<std::shared_ptr<storm::storage::Scheduler<ValueType>>> scheduler;
};
}
}

50
src/storm/solver/GameSolver.cpp

@ -18,8 +18,8 @@ namespace storm {
void GameSolver<ValueType>::setTrackSchedulers(bool value) {
trackSchedulers = value;
if (!trackSchedulers) {
player1Scheduler = boost::none;
player2Scheduler = boost::none;
player1SchedulerChoices = boost::none;
player2SchedulerChoices = boost::none;
}
}
@ -30,42 +30,54 @@ namespace storm {
template<typename ValueType>
bool GameSolver<ValueType>::hasSchedulers() const {
return player1Scheduler.is_initialized() && player2Scheduler.is_initialized();
return player1SchedulerChoices.is_initialized() && player2SchedulerChoices.is_initialized();
}
template<typename ValueType>
storm::storage::TotalScheduler const& GameSolver<ValueType>::getPlayer1Scheduler() const {
STORM_LOG_THROW(player1Scheduler, storm::exceptions::IllegalFunctionCallException, "Cannot retrieve player 1 scheduler, because none was generated.");
return *player1Scheduler.get();
storm::storage::Scheduler<ValueType> GameSolver<ValueType>::computePlayer1Scheduler() const {
STORM_LOG_THROW(hasSchedulers(), storm::exceptions::IllegalFunctionCallException, "Cannot retrieve player 1 scheduler, because none was generated.");
storm::storage::Scheduler<ValueType> result(player1SchedulerChoices->size());
uint_fast64_t state = 0;
for (auto const& schedulerChoice : player1SchedulerChoices.get()) {
result.setChoice(schedulerChoice, state);
++state;
}
return result;
}
template<typename ValueType>
storm::storage::TotalScheduler const& GameSolver<ValueType>::getPlayer2Scheduler() const {
STORM_LOG_THROW(player2Scheduler, storm::exceptions::IllegalFunctionCallException, "Cannot retrieve player 2 scheduler, because none was generated.");
return *player2Scheduler.get();
storm::storage::Scheduler<ValueType> GameSolver<ValueType>::computePlayer2Scheduler() const {
STORM_LOG_THROW(hasSchedulers(), storm::exceptions::IllegalFunctionCallException, "Cannot retrieve player 2 scheduler, because none was generated.");
storm::storage::Scheduler<ValueType> result(player2SchedulerChoices->size());
uint_fast64_t state = 0;
for (auto const& schedulerChoice : player2SchedulerChoices.get()) {
result.setChoice(schedulerChoice, state);
++state;
}
return result;
}
template<typename ValueType>
std::unique_ptr<storm::storage::TotalScheduler> GameSolver<ValueType>::getPlayer1Scheduler() {
STORM_LOG_THROW(player1Scheduler, storm::exceptions::IllegalFunctionCallException, "Cannot retrieve player 1 scheduler, because none was generated.");
return std::move(player1Scheduler.get());
std::vector<uint_fast64_t> const& GameSolver<ValueType>::getPlayer1SchedulerChoices() const {
STORM_LOG_THROW(hasSchedulers(), storm::exceptions::IllegalFunctionCallException, "Cannot retrieve player 1 scheduler choices, because they were not generated.");
return player1SchedulerChoices.get();
}
template<typename ValueType>
std::unique_ptr<storm::storage::TotalScheduler> GameSolver<ValueType>::getPlayer2Scheduler() {
STORM_LOG_THROW(player2Scheduler, storm::exceptions::IllegalFunctionCallException, "Cannot retrieve player 2 scheduler, because none was generated.");
return std::move(player2Scheduler.get());
std::vector<uint_fast64_t> const& GameSolver<ValueType>::getPlayer2SchedulerChoices() const {
STORM_LOG_THROW(hasSchedulers(), storm::exceptions::IllegalFunctionCallException, "Cannot retrieve player 2 scheduler choices, because they were not generated.");
return player2SchedulerChoices.get();
}
template<typename ValueType>
void GameSolver<ValueType>::setSchedulerHints(storm::storage::TotalScheduler&& player1Scheduler, storm::storage::TotalScheduler&& player2Scheduler) {
this->player1SchedulerHint = std::move(player1Scheduler);
this->player2SchedulerHint = std::move(player2Scheduler);
void GameSolver<ValueType>::setSchedulerHints(std::vector<uint_fast64_t>&& player1Choices, std::vector<uint_fast64_t>&& player2Choices) {
this->player1ChoicesHint = std::move(player1Choices);
this->player2ChoicesHint = std::move(player2Choices);
}
template<typename ValueType>
bool GameSolver<ValueType>::hasSchedulerHints() const {
return player1SchedulerHint.is_initialized() && player2SchedulerHint.is_initialized();
return player1ChoicesHint.is_initialized() && player2ChoicesHint.is_initialized();
}
template<typename ValueType>

32
src/storm/solver/GameSolver.h

@ -7,7 +7,7 @@
#include "storm/solver/AbstractEquationSolver.h"
#include "storm/solver/OptimizationDirection.h"
#include "storm/storage/sparse/StateType.h"
#include "storm/storage/TotalScheduler.h"
#include "storm/storage/Scheduler.h"
#include "storm/utility/macros.h"
#include "storm/exceptions/InvalidSettingsException.h"
@ -72,23 +72,21 @@ namespace storm {
bool hasSchedulers() const;
/*!
* Retrieves the generated schedulers. Note: it is only legal to call this function if schedulers were generated.
* Retrieves the generated scheduler. Note: it is only legal to call this function if schedulers were generated.
*/
storm::storage::TotalScheduler const& getPlayer1Scheduler() const;
storm::storage::TotalScheduler const& getPlayer2Scheduler() const;
storm::storage::Scheduler<ValueType> computePlayer1Scheduler() const;
storm::storage::Scheduler<ValueType> computePlayer2Scheduler() const;
/*!
* Retrieves the generated schedulers and takes ownership of it. Note: it is only legal to call this functions
* if scheduler were generated and after calling this methods, the solver will not contain the corresponding scheduler
* any more (i.e. it is illegal to call this methods again until new schedulers have been generated).
* Retrieves the generated (deterministic) choices of the optimal scheduler. Note: it is only legal to call this function if schedulers were generated.
*/
std::unique_ptr<storm::storage::TotalScheduler> getPlayer1Scheduler();
std::unique_ptr<storm::storage::TotalScheduler> getPlayer2Scheduler();
std::vector<uint_fast64_t> const& getPlayer1SchedulerChoices() const;
std::vector<uint_fast64_t> const& getPlayer2SchedulerChoices() const;
/*!
* Sets scheduler hints that might be considered by the solver as an initial guess
*/
void setSchedulerHints(storm::storage::TotalScheduler&& player1Scheduler, storm::storage::TotalScheduler&& player2Scheduler);
void setSchedulerHints(std::vector<uint_fast64_t>&& player1Choices, std::vector<uint_fast64_t>&& player2Choices);
/*!
* Returns whether Scheduler hints are available
@ -145,9 +143,9 @@ namespace storm {
/// Whether we generate schedulers during solving.
bool trackSchedulers;
/// The schedulers (if they could be successfully generated).
mutable boost::optional<std::unique_ptr<storm::storage::TotalScheduler>> player1Scheduler;
mutable boost::optional<std::unique_ptr<storm::storage::TotalScheduler>> player2Scheduler;
/// The scheduler choices that induce the optimal values (if they could be successfully generated).
mutable boost::optional<std::vector<uint_fast64_t>> player1SchedulerChoices;
mutable boost::optional<std::vector<uint_fast64_t>> player2SchedulerChoices;
// A lower bound if one was set.
boost::optional<ValueType> lowerBound;
@ -155,9 +153,9 @@ namespace storm {
// An upper bound if one was set.
boost::optional<ValueType> upperBound;
// schedulers that might be considered by the solver as an initial guess
boost::optional<storm::storage::TotalScheduler> player1SchedulerHint;
boost::optional<storm::storage::TotalScheduler> player2SchedulerHint;
// scheduler choices that might be considered by the solver as an initial guess
boost::optional<std::vector<uint_fast64_t>> player1ChoicesHint;
boost::optional<std::vector<uint_fast64_t>> player2ChoicesHint;
private:
/// Whether some of the generated data during solver calls should be cached.

28
src/storm/solver/MinMaxLinearEquationSolver.cpp

@ -53,7 +53,7 @@ namespace storm {
void MinMaxLinearEquationSolver<ValueType>::setTrackScheduler(bool trackScheduler) {
this->trackScheduler = trackScheduler;
if (!this->trackScheduler) {
scheduler = boost::none;
schedulerChoices = boost::none;
}
}
@ -64,19 +64,25 @@ namespace storm {
template<typename ValueType>
bool MinMaxLinearEquationSolver<ValueType>::hasScheduler() const {
return static_cast<bool>(scheduler);
return static_cast<bool>(schedulerChoices);
}
template<typename ValueType>
storm::storage::TotalScheduler const& MinMaxLinearEquationSolver<ValueType>::getScheduler() const {
STORM_LOG_THROW(scheduler, storm::exceptions::IllegalFunctionCallException, "Cannot retrieve scheduler, because none was generated.");
return *scheduler.get();
storm::storage::Scheduler<ValueType> MinMaxLinearEquationSolver<ValueType>::computeScheduler() const {
STORM_LOG_THROW(hasScheduler(), storm::exceptions::IllegalFunctionCallException, "Cannot retrieve scheduler, because none was generated.");
storm::storage::Scheduler<ValueType> result(schedulerChoices->size());
uint_fast64_t state = 0;
for (auto const& schedulerChoice : schedulerChoices.get()) {
result.setChoice(schedulerChoice, state);
++state;
}
return result;
}
template<typename ValueType>
std::unique_ptr<storm::storage::TotalScheduler> MinMaxLinearEquationSolver<ValueType>:: getScheduler() {
STORM_LOG_THROW(scheduler, storm::exceptions::IllegalFunctionCallException, "Cannot retrieve scheduler, because none was generated.");
return std::move(scheduler.get());
std::vector<uint_fast64_t> const& MinMaxLinearEquationSolver<ValueType>::getSchedulerChoices() const {
STORM_LOG_THROW(hasScheduler(), storm::exceptions::IllegalFunctionCallException, "Cannot retrieve scheduler choices, because they were not generated.");
return schedulerChoices.get();
}
template<typename ValueType>
@ -115,13 +121,13 @@ namespace storm {
}
template<typename ValueType>
void MinMaxLinearEquationSolver<ValueType>::setSchedulerHint(storm::storage::TotalScheduler&& scheduler) {
schedulerHint = scheduler;
void MinMaxLinearEquationSolver<ValueType>::setSchedulerHint(std::vector<uint_fast64_t>&& choices) {
choicesHint = std::move(choices);
}
template<typename ValueType>
bool MinMaxLinearEquationSolver<ValueType>::hasSchedulerHint() const {
return schedulerHint.is_initialized();
return choicesHint.is_initialized();
}
template<typename ValueType>

22
src/storm/solver/MinMaxLinearEquationSolver.h

@ -10,7 +10,7 @@
#include "storm/solver/AbstractEquationSolver.h"
#include "storm/solver/SolverSelectionOptions.h"
#include "storm/storage/sparse/StateType.h"
#include "storm/storage/TotalScheduler.h"
#include "storm/storage/Scheduler.h"
#include "storm/solver/OptimizationDirection.h"
#include "storm/exceptions/InvalidSettingsException.h"
@ -108,14 +108,12 @@ namespace storm {
/*!
* Retrieves the generated scheduler. Note: it is only legal to call this function if a scheduler was generated.
*/
storm::storage::TotalScheduler const& getScheduler() const;
storm::storage::Scheduler<ValueType> computeScheduler() const;
/*!
* Retrieves the generated scheduler and takes ownership of it. Note: it is only legal to call this function
* if a scheduler was generated and after a call to this method, the solver will not contain the scheduler
* any more (i.e. it is illegal to call this method again until a new scheduler has been generated).
* Retrieves the generated (deterministic) choices of the optimal scheduler. Note: it is only legal to call this function if a scheduler was generated.
*/
std::unique_ptr<storm::storage::TotalScheduler> getScheduler();
std::vector<uint_fast64_t> const& getSchedulerChoices() const;
/**
* Gets the precision after which the solver takes two numbers as equal.
@ -163,7 +161,7 @@ namespace storm {
/*!
* Sets a scheduler that might be considered by the solver as an initial guess
*/
void setSchedulerHint(storm::storage::TotalScheduler&& scheduler);
void setSchedulerHint(std::vector<uint_fast64_t>&& choices);
/*!
* Returns true iff a scheduler hint was defined
@ -177,8 +175,8 @@ namespace storm {
/// Whether we generate a scheduler during solving.
bool trackScheduler;
/// The scheduler (if it could be successfully generated).
mutable boost::optional<std::unique_ptr<storm::storage::TotalScheduler>> scheduler;
/// The scheduler choices that induce the optimal values (if they could be successfully generated).
mutable boost::optional<std::vector<uint_fast64_t>> schedulerChoices;
// A lower bound if one was set.
boost::optional<ValueType> lowerBound;
@ -186,8 +184,8 @@ namespace storm {
// An upper bound if one was set.
boost::optional<ValueType> upperBound;
// A scheduler that might be considered by the solver as an initial guess
boost::optional<storm::storage::TotalScheduler> schedulerHint;
// Scheduler choices that might be considered by the solver as an initial guess
boost::optional<std::vector<uint_fast64_t>> choicesHint;
private:
/// Whether some of the generated data during solver calls should be cached.

18
src/storm/solver/StandardGameSolver.cpp

@ -101,8 +101,8 @@ namespace storm {
bool StandardGameSolver<ValueType>::solveGamePolicyIteration(OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector<ValueType>& x, std::vector<ValueType> const& b) const {
// Create the initial choice selections.
std::vector<storm::storage::sparse::state_type> player1Choices = this->hasSchedulerHints() ? this->player1SchedulerHint->getChoices() : std::vector<storm::storage::sparse::state_type>(this->player1Matrix.getRowGroupCount(), 0);
std::vector<storm::storage::sparse::state_type> player2Choices = this->hasSchedulerHints() ? this->player2SchedulerHint->getChoices() : std::vector<storm::storage::sparse::state_type>(this->player2Matrix.getRowGroupCount(), 0);
std::vector<storm::storage::sparse::state_type> player1Choices = this->hasSchedulerHints() ? this->player1ChoicesHint.get() : std::vector<storm::storage::sparse::state_type>(this->player1Matrix.getRowGroupCount(), 0);
std::vector<storm::storage::sparse::state_type> player2Choices = this->hasSchedulerHints() ? this->player2ChoicesHint.get() : std::vector<storm::storage::sparse::state_type>(this->player2Matrix.getRowGroupCount(), 0);
if(!auxiliaryP2RowGroupVector) {
auxiliaryP2RowGroupVector = std::make_unique<std::vector<ValueType>>(this->player2Matrix.getRowGroupCount());
@ -149,8 +149,8 @@ namespace storm {
// If requested, we store the scheduler for retrieval.
if (this->isTrackSchedulersSet()) {
this->player1Scheduler = std::make_unique<storm::storage::TotalScheduler>(std::move(player1Choices));
this->player2Scheduler = std::make_unique<storm::storage::TotalScheduler>(std::move(player2Choices));
this->player1SchedulerChoices = std::move(player1Choices);
this->player2SchedulerChoices = std::move(player2Choices);
}
if(!this->isCachingEnabled()) {
@ -205,7 +205,7 @@ namespace storm {
if (this->hasSchedulerHints()) {
// Solve the equation system induced by the two schedulers.
storm::storage::SparseMatrix<ValueType> submatrix;
getInducedMatrixVector(x, b, this->player1SchedulerHint->getChoices(), this->player2SchedulerHint->getChoices(), submatrix, *auxiliaryP1RowGroupVector);
getInducedMatrixVector(x, b, this->player1ChoicesHint.get(), this->player2ChoicesHint.get(), submatrix, *auxiliaryP1RowGroupVector);
submatrix.convertToEquationSystem();
auto submatrixSolver = linearEquationSolverFactory->create(std::move(submatrix));
if (this->lowerBound) { submatrixSolver->setLowerBound(this->lowerBound.get()); }
@ -244,11 +244,9 @@ namespace storm {
// If requested, we store the scheduler for retrieval.
if (this->isTrackSchedulersSet()) {
std::vector<uint_fast64_t> player1Choices(player1Matrix.getRowGroupCount(), 0);
std::vector<uint_fast64_t> player2Choices(player2Matrix.getRowGroupCount(), 0);
extractChoices(player1Dir, player2Dir, x, b, *auxiliaryP2RowGroupVector, player1Choices, player2Choices);
this->player1Scheduler = std::make_unique<storm::storage::TotalScheduler>(std::move(player1Choices));
this->player2Scheduler = std::make_unique<storm::storage::TotalScheduler>(std::move(player2Choices));
this->player1SchedulerChoices = std::vector<uint_fast64_t>(player1Matrix.getRowGroupCount(), 0);
this->player2SchedulerChoices = std::vector<uint_fast64_t>(player2Matrix.getRowGroupCount(), 0);
extractChoices(player1Dir, player2Dir, x, b, *auxiliaryP2RowGroupVector, this->player1SchedulerChoices.get(), this->player2SchedulerChoices.get());
}
if(!this->isCachingEnabled()) {

2
src/storm/solver/StandardGameSolver.h

@ -62,7 +62,7 @@ namespace storm {
void getInducedMatrixVector(std::vector<ValueType>& x, std::vector<ValueType> const& b, std::vector<uint_fast64_t> const& player1Choices, std::vector<uint_fast64_t> const& player2Choices, storm::storage::SparseMatrix<ValueType>& inducedMatrix, std::vector<ValueType>& inducedVector) const;
// Extracts the choices of the different players for the given solution x.
// Returns true iff there are "better" choices for one of the players.
// Returns true iff the newly extracted choices yield "better" values then the given choices for one of the players.
bool extractChoices(OptimizationDirection player1Dir, OptimizationDirection player2Dir, std::vector<ValueType> const& x, std::vector<ValueType> const& b, std::vector<ValueType>& player2ChoiceValues, std::vector<uint_fast64_t>& player1Choices, std::vector<uint_fast64_t>& player2Choices) const;
bool valueImproved(OptimizationDirection dir, ValueType const& value1, ValueType const& value2) const;

17
src/storm/solver/StandardMinMaxLinearEquationSolver.cpp

@ -100,7 +100,7 @@ namespace storm {
template<typename ValueType>
bool StandardMinMaxLinearEquationSolver<ValueType>::solveEquationsPolicyIteration(OptimizationDirection dir, std::vector<ValueType>& x, std::vector<ValueType> const& b) const {
// Create the initial scheduler.
std::vector<storm::storage::sparse::state_type> scheduler = this->schedulerHint ? this->schedulerHint->getChoices() : std::vector<storm::storage::sparse::state_type>(this->A.getRowGroupCount());
std::vector<storm::storage::sparse::state_type> scheduler = this->hasSchedulerHint() ? this->choicesHint.get() : std::vector<storm::storage::sparse::state_type>(this->A.getRowGroupCount());
// Get a vector for storing the right-hand side of the inner equation system.
if(!auxiliaryRowGroupVector) {
@ -180,7 +180,7 @@ namespace storm {
// If requested, we store the scheduler for retrieval.
if (this->isTrackSchedulerSet()) {
this->scheduler = std::make_unique<storm::storage::TotalScheduler>(std::move(scheduler));
this->schedulerChoices = std::move(scheduler);
}
if(!this->isCachingEnabled()) {
@ -225,11 +225,11 @@ namespace storm {
auxiliaryRowGroupVector = std::make_unique<std::vector<ValueType>>(A.getRowGroupCount());
}
if(this->schedulerHint) {
if (this->hasSchedulerHint()) {
// Resolve the nondeterminism according to the scheduler hint
storm::storage::SparseMatrix<ValueType> submatrix = this->A.selectRowsFromRowGroups(this->schedulerHint->getChoices(), true);
storm::storage::SparseMatrix<ValueType> submatrix = this->A.selectRowsFromRowGroups(this->choicesHint.get(), true);
submatrix.convertToEquationSystem();
storm::utility::vector::selectVectorValues<ValueType>(*auxiliaryRowGroupVector, this->schedulerHint->getChoices(), this->A.getRowGroupIndices(), b);
storm::utility::vector::selectVectorValues<ValueType>(*auxiliaryRowGroupVector, this->choicesHint.get(), this->A.getRowGroupIndices(), b);
// Solve the resulting equation system.
// Note that the linEqSolver might consider a slightly different interpretation of "equalModuloPrecision". Hence, we iteratively increase its precision.
@ -281,13 +281,12 @@ namespace storm {
if (iterations==0) {
linEqSolverA->multiply(x, &b, multiplyResult);
}
std::vector<storm::storage::sparse::state_type> choices(this->A.getRowGroupCount());
this->schedulerChoices = std::vector<uint_fast64_t>(this->A.getRowGroupCount());
// Reduce the multiplyResult and keep track of the choices made
storm::utility::vector::reduceVectorMinOrMax(dir, multiplyResult, x, this->A.getRowGroupIndices(), &choices);
this->scheduler = std::make_unique<storm::storage::TotalScheduler>(std::move(choices));
storm::utility::vector::reduceVectorMinOrMax(dir, multiplyResult, x, this->A.getRowGroupIndices(), &this->schedulerChoices.get());
}
if(!this->isCachingEnabled()) {
if (!this->isCachingEnabled()) {
clearCache();
}

8
src/storm/storage/Distribution.cpp

@ -158,13 +158,21 @@ namespace storm {
template class Distribution<double>;
template std::ostream& operator<<(std::ostream& out, Distribution<double> const& distribution);
template class Distribution<double, uint_fast64_t>;
template std::ostream& operator<<(std::ostream& out, Distribution<double, uint_fast64_t> const& distribution);
template class Distribution<float, uint_fast64_t>;
template std::ostream& operator<<(std::ostream& out, Distribution<float, uint_fast64_t> const& distribution);
#ifdef STORM_HAVE_CARL
template class Distribution<storm::RationalNumber>;
template std::ostream& operator<<(std::ostream& out, Distribution<storm::RationalNumber> const& distribution);
template class Distribution<storm::RationalNumber, uint_fast64_t>;
template std::ostream& operator<<(std::ostream& out, Distribution<storm::RationalNumber, uint_fast64_t> const& distribution);
template class Distribution<storm::RationalFunction>;
template std::ostream& operator<<(std::ostream& out, Distribution<storm::RationalFunction> const& distribution);
template class Distribution<storm::RationalFunction, uint_fast64_t>;
template std::ostream& operator<<(std::ostream& out, Distribution<storm::RationalFunction, uint_fast64_t> const& distribution);
#endif
}
}

48
src/storm/storage/PartialScheduler.cpp

@ -1,48 +0,0 @@
#include "storm/storage/PartialScheduler.h"
#include "storm/exceptions/InvalidArgumentException.h"
namespace storm {
namespace storage {
void PartialScheduler::setChoice(uint_fast64_t state, uint_fast64_t choice) {
stateToChoiceMapping[state] = choice;
}
bool PartialScheduler::isChoiceDefined(uint_fast64_t state) const {
return stateToChoiceMapping.find(state) != stateToChoiceMapping.end();
}
uint_fast64_t PartialScheduler::getChoice(uint_fast64_t state) const {
auto stateChoicePair = stateToChoiceMapping.find(state);
if (stateChoicePair == stateToChoiceMapping.end()) {
throw storm::exceptions::InvalidArgumentException() << "Invalid call to PartialScheduler::getChoice: scheduler does not define a choice for state " << state << ".";
}
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();
for (auto const& stateChoicePair : scheduler.stateToChoiceMapping) {
out << stateChoicePair.first << " -> " << stateChoicePair.second;
--remainingEntries;
if (remainingEntries > 0) {
out << ", ";
}
}
out << "]";
return out;
}
} // namespace storage
} // namespace storm

34
src/storm/storage/PartialScheduler.h

@ -1,34 +0,0 @@
#ifndef STORM_STORAGE_PARTIALSCHEDULER_H_
#define STORM_STORAGE_PARTIALSCHEDULER_H_
#include <unordered_map>
#include <ostream>
#include "storm/storage/Scheduler.h"
namespace storm {
namespace storage {
class PartialScheduler : public Scheduler {
public:
typedef std::unordered_map<uint_fast64_t, uint_fast64_t> map_type;
void setChoice(uint_fast64_t state, uint_fast64_t choice) override;
bool isChoiceDefined(uint_fast64_t state) const override;
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:
// A mapping from all states that have defined choices to their respective choices.
map_type stateToChoiceMapping;
};
}
}
#endif /* STORM_STORAGE_PARTIALSCHEDULER_H_ */

166
src/storm/storage/Scheduler.cpp

@ -0,0 +1,166 @@
#include <storm/utility/vector.h>
#include "storm/storage/Scheduler.h"
#include "storm/utility/macros.h"
#include "storm/exceptions/NotImplementedException.h"
namespace storm {
namespace storage {
template <typename ValueType>
Scheduler<ValueType>::Scheduler(uint_fast64_t numberOfModelStates, boost::optional<storm::storage::MemoryStructure> const& memoryStructure) : memoryStructure(memoryStructure) {
uint_fast64_t numOfMemoryStates = memoryStructure ? memoryStructure->getNumberOfStates() : 1;
schedulerChoices = std::vector<std::vector<SchedulerChoice<ValueType>>>(numOfMemoryStates, std::vector<SchedulerChoice<ValueType>>(numberOfModelStates));
numOfUndefinedChoices = numOfMemoryStates * numberOfModelStates;
numOfDeterministicChoices = 0;
}
template <typename ValueType>
Scheduler<ValueType>::Scheduler(uint_fast64_t numberOfModelStates, boost::optional<storm::storage::MemoryStructure>&& memoryStructure) : memoryStructure(std::move(memoryStructure)) {
uint_fast64_t numOfMemoryStates = memoryStructure ? memoryStructure->getNumberOfStates() : 1;
schedulerChoices = std::vector<std::vector<SchedulerChoice<ValueType>>>(numOfMemoryStates, std::vector<SchedulerChoice<ValueType>>(numberOfModelStates));
numOfUndefinedChoices = numOfMemoryStates * numberOfModelStates;
numOfDeterministicChoices = 0;
}
template <typename ValueType>
void Scheduler<ValueType>::setChoice(SchedulerChoice<ValueType> const& choice, uint_fast64_t modelState, uint_fast64_t memoryState) {
STORM_LOG_ASSERT(memoryState < getNumberOfMemoryStates(), "Illegal memory state index");
STORM_LOG_ASSERT(modelState < schedulerChoices[memoryState].size(), "Illegal model state index");
auto& schedulerChoice = schedulerChoices[memoryState][modelState];
if (schedulerChoice.isDefined()) {
if (!choice.isDefined()) {
++numOfUndefinedChoices;
}
} else {
if (choice.isDefined()) {
assert(numOfUndefinedChoices > 0);
--numOfUndefinedChoices;
}
}
if (schedulerChoice.isDeterministic()) {
if (!choice.isDeterministic()) {
assert(numOfDeterministicChoices > 0);
--numOfDeterministicChoices;
}
} else {
if (choice.isDeterministic()) {
++numOfDeterministicChoices;
}
}
schedulerChoice = choice;
}
template <typename ValueType>
void Scheduler<ValueType>::clearChoice(uint_fast64_t modelState, uint_fast64_t memoryState) {
STORM_LOG_ASSERT(memoryState < getNumberOfMemoryStates(), "Illegal memory state index");
STORM_LOG_ASSERT(modelState < schedulerChoices[memoryState].size(), "Illegal model state index");
setChoice(SchedulerChoice<ValueType>(), modelState, memoryState);
}
template <typename ValueType>
SchedulerChoice<ValueType> const& Scheduler<ValueType>::getChoice(uint_fast64_t modelState, uint_fast64_t memoryState) const {
STORM_LOG_ASSERT(memoryState < getNumberOfMemoryStates(), "Illegal memory state index");
STORM_LOG_ASSERT(modelState < schedulerChoices[memoryState].size(), "Illegal model state index");
return schedulerChoices[memoryState][modelState];
}
template <typename ValueType>
bool Scheduler<ValueType>::isPartialScheduler() const {
return numOfUndefinedChoices != 0;
}
template <typename ValueType>
bool Scheduler<ValueType>::isDeterministicScheduler() const {
return numOfDeterministicChoices == (schedulerChoices.size() * schedulerChoices.begin()->size()) - numOfUndefinedChoices;
}
template <typename ValueType>
bool Scheduler<ValueType>::isMemorylessScheduler() const {
return getNumberOfMemoryStates() == 1;
}
template <typename ValueType>
uint_fast64_t Scheduler<ValueType>::getNumberOfMemoryStates() const {
return memoryStructure ? memoryStructure->getNumberOfStates() : 1;
}
template <typename ValueType>
void Scheduler<ValueType>::printToStream(std::ostream& out, std::shared_ptr<storm::models::sparse::Model<ValueType>> model, bool skipUniqueChoices) const {
out << "___________________________________________________________________" << std::endl;
out << (isPartialScheduler() ? "Partially" : "Fully") << " defined ";
out << (isMemorylessScheduler() ? "memoryless " : "");
out << (isDeterministicScheduler() ? "deterministic" : "randomized") << " scheduler";
if (!isMemorylessScheduler()) {
out << " with " << getNumberOfMemoryStates() << " memory states";
}
out << "." << std::endl;
out << "___________________________________________________________________" << std::endl;
out << "Choices on " << schedulerChoices.front().size() << " model states:" << std::endl;
STORM_LOG_WARN_COND(!(skipUniqueChoices && model == nullptr), "Can not skip unique choices if the model is not given.");
out << " model state: " << " " << (isMemorylessScheduler() ? "" : " memory: ") << "choice(s)" << std::endl;
for (uint_fast64_t state = 0; state < schedulerChoices.front().size(); ++state) {
// Check whether the state is skipped
if (skipUniqueChoices && model != nullptr && model->getTransitionMatrix().getRowGroupSize(state) == 1) {
continue;
}
if (model != nullptr && model->hasStateValuations()) {
out << std::setw(20) << model->getStateValuations().getStateInfo(state);
} else {
out << std::setw(20) << state;
}
out << " ";
bool firstMemoryState = true;
for (uint_fast64_t memoryState = 0; memoryState < getNumberOfMemoryStates(); ++memoryState) {
if (firstMemoryState) {
firstMemoryState = false;
} else {
out << std::setw(20) << "";
out << " ";
}
if (!isMemorylessScheduler()) {
out << "m" << std::setw(8) << memoryState;
}
SchedulerChoice<ValueType> const& choice = schedulerChoices[memoryState][state];
if (choice.isDefined()) {
if (choice.isDeterministic()) {
if (model != nullptr && model->hasChoiceOrigins()) {
out << model->getChoiceOrigins()->getChoiceInfo(model->getTransitionMatrix().getRowGroupIndices()[state] + choice.getDeterministicChoice());
} else {
out << choice.getDeterministicChoice();
}
} else {
bool firstChoice = true;
for (auto const& choiceProbPair : choice.getChoiceAsDistribution()) {
if (firstChoice) {
firstChoice = false;
} else {
out << " + ";
}
out << choiceProbPair.second << ": (";
if (model != nullptr && model->hasChoiceOrigins()) {
out << model->getChoiceOrigins()->getChoiceInfo(model->getTransitionMatrix().getRowGroupIndices()[state] + choiceProbPair.first);
} else {
out << choiceProbPair.first;
}
out << ")";
}
}
} else {
out << "undefined.";
}
out << std::endl;
}
}
out << "___________________________________________________________________" << std::endl;
}
template class Scheduler<double>;
template class Scheduler<float>;
template class Scheduler<storm::RationalNumber>;
template class Scheduler<storm::RationalFunction>;
}
}

93
src/storm/storage/Scheduler.h

@ -2,37 +2,106 @@
#define STORM_STORAGE_SCHEDULER_H_
#include <cstdint>
#include "storm/storage/memorystructure/MemoryStructure.h"
#include "storm/storage/SchedulerChoice.h"
namespace storm {
namespace storage {
/*
* This class is the abstract base class of all scheduler classes. Scheduler classes define which action is
* chosen in a particular state of a non-deterministic model. More concretely, a scheduler maps a state s to i
* This class defines which action is chosen in a particular state of a non-deterministic model. More concretely, a scheduler maps a state s to i
* if the scheduler takes the i-th action available in s (i.e. the choices are relative to the states).
* A Choice can be undefined, deterministic
*/
template <typename ValueType>
class Scheduler {
public:
/*
/*!
* Initializes a scheduler for the given number of model states.
*
* @param numberOfModelStates number of model states
* @param memoryStructure the considered memory structure. If not given, the scheduler is considered as memoryless.
*/
Scheduler(uint_fast64_t numberOfModelStates, boost::optional<storm::storage::MemoryStructure> const& memoryStructure = boost::none);
Scheduler(uint_fast64_t numberOfModelStates, boost::optional<storm::storage::MemoryStructure>&& memoryStructure);
/*!
* Sets the choice defined by the scheduler for the given state.
*
* @param state The state for which to set the choice.
* @param choice The choice to set for the given state.
* @param modelState The state of the model for which to set the choice.
* @param memoryState The state of the memoryStructure for which to set the choice.
*/
void setChoice(SchedulerChoice<ValueType> const& choice, uint_fast64_t modelState, uint_fast64_t memoryState = 0);
/*!
* Clears the choice defined by the scheduler for the given state.
*
* @param modelState The state of the model for which to clear the choice.
* @param memoryState The state of the memoryStructure for which to clear the choice.
*/
virtual void setChoice(uint_fast64_t state, uint_fast64_t choice) = 0;
void clearChoice(uint_fast64_t modelState, uint_fast64_t memoryState = 0);
/*
* Retrieves whether this scheduler defines a choice for the given state.
/*!
* Sets the choice defined by the scheduler for the given model and memory state.
*
* @param state The state for which to check whether the scheduler defines a choice.
* @return True if the scheduler defines a choice for the given state.
* @param state The state for which to set the choice.
* @param choice The choice to set for the given state.
*/
SchedulerChoice<ValueType> const& getChoice(uint_fast64_t modelState, uint_fast64_t memoryState = 0) const;
/*!
* Retrieves whether there is a pair of model and memory state for which the choice is undefined.
*/
bool isPartialScheduler() const;
/*!
* Retrieves whether all defined choices are deterministic
*/
virtual bool isChoiceDefined(uint_fast64_t state) const = 0;
bool isDeterministicScheduler() const;
/*!
* Retrieves the choice for the given state under the assumption that the scheduler defines a proper choice for the state.
* Retrieves whether the scheduler considers a trivial memory structure (i.e., a memory structure with just a single state)
*/
bool isMemorylessScheduler() const;
/*!
* Retrieves the number of memory states this scheduler considers.
*/
uint_fast64_t getNumberOfMemoryStates() const;
/*!
* Returns a copy of this scheduler with the new value type
*/
template<typename NewValueType>
Scheduler<NewValueType> toValueType() const {
uint_fast64_t numModelStates = schedulerChoices.front().size();
Scheduler<NewValueType> newScheduler(numModelStates, memoryStructure);
for (uint_fast64_t memState = 0; memState < this->getNumberOfMemoryStates(); ++memState) {
for (uint_fast64_t modelState = 0; modelState < numModelStates; ++modelState) {
newScheduler.setChoice(getChoice(modelState, memState).template toValueType<NewValueType>(), modelState, memState);
}
}
return newScheduler;
}
/*!
* Prints the scheduler to the given output stream.
* @param out The output stream
* @param model If given, provides additional information for printing (e.g., displaying the state valuations instead of state indices)
* @param skipUniqueChoices If true, the (unique) choice for deterministic states (i.e., states with only one enabled choice) is not printed explicitly.
* Requires a model to be given.
*/
virtual uint_fast64_t getChoice(uint_fast64_t state) const = 0;
void printToStream(std::ostream& out, std::shared_ptr<storm::models::sparse::Model<ValueType>> model = nullptr, bool skipUniqueChoices = false) const;
private:
boost::optional<storm::storage::MemoryStructure> memoryStructure;
std::vector<std::vector<SchedulerChoice<ValueType>>> schedulerChoices;
uint_fast64_t numOfUndefinedChoices;
uint_fast64_t numOfDeterministicChoices;
};
}
}

82
src/storm/storage/SchedulerChoice.cpp

@ -0,0 +1,82 @@
#include "storm/storage/SchedulerChoice.h"
#include "storm/utility/constants.h"
#include "storm/utility/macros.h"
#include "storm/exceptions/InvalidOperationException.h"
#include "storm/adapters/RationalFunctionAdapter.h"
#include "storm/adapters/RationalNumberAdapter.h"
namespace storm {
namespace storage {
template <typename ValueType>
SchedulerChoice<ValueType>::SchedulerChoice() {
// Intentionally left empty
}
template <typename ValueType>
SchedulerChoice<ValueType>::SchedulerChoice(uint_fast64_t deterministicChoice) {
distribution.addProbability(deterministicChoice, storm::utility::one<ValueType>());
}
template <typename ValueType>
SchedulerChoice<ValueType>::SchedulerChoice(storm::storage::Distribution<ValueType, uint_fast64_t> const& randomizedChoice) : distribution(randomizedChoice) {
// Intentionally left empty
}
template <typename ValueType>
SchedulerChoice<ValueType>::SchedulerChoice(storm::storage::Distribution<ValueType, uint_fast64_t>&& randomizedChoice) : distribution(std::move(randomizedChoice)) {
// Intentionally left empty
}
template <typename ValueType>
bool SchedulerChoice<ValueType>::isDefined() const {
return distribution.size() != 0;
}
template <typename ValueType>
bool SchedulerChoice<ValueType>::isDeterministic() const {
return distribution.size() == 1;
}
template <typename ValueType>
uint_fast64_t SchedulerChoice<ValueType>::getDeterministicChoice() const {
STORM_LOG_THROW(isDeterministic(), storm::exceptions::InvalidOperationException, "Tried to obtain the deterministic choice of a scheduler, but the choice is not deterministic");
return distribution.begin()->first;
}
template <typename ValueType>
storm::storage::Distribution<ValueType, uint_fast64_t> const& SchedulerChoice<ValueType>::getChoiceAsDistribution() const {
return distribution;
}
template <typename ValueType>
std::ostream& operator<<(std::ostream& out, SchedulerChoice<ValueType> const& schedulerChoice) {
if (schedulerChoice.isDefined()) {
if (schedulerChoice.isDeterministic()) {
out << schedulerChoice.getDeterministicChoice();
} else {
out << schedulerChoice.getChoiceAsDistribution();
}
} else {
out << "undefined";
}
return out;
}
template class SchedulerChoice<double>;
template std::ostream& operator<<(std::ostream& out, SchedulerChoice<double> const& schedulerChoice);
template class SchedulerChoice<float>;
template std::ostream& operator<<(std::ostream& out, SchedulerChoice<float> const& schedulerChoice);
template class SchedulerChoice<storm::RationalNumber>;
template std::ostream& operator<<(std::ostream& out, SchedulerChoice<storm::RationalNumber> const& schedulerChoice);
template class SchedulerChoice<storm::RationalFunction>;
template std::ostream& operator<<(std::ostream& out, SchedulerChoice<storm::RationalFunction> const& schedulerChoice);
}
}

79
src/storm/storage/SchedulerChoice.h

@ -0,0 +1,79 @@
#pragma once
#include "storm/utility/constants.h"
#include "storm/storage/Distribution.h"
namespace storm {
namespace storage {
template <typename ValueType>
class SchedulerChoice {
public:
/*!
* Creates an undefined scheduler choice
*/
SchedulerChoice();
/*!
* Creates a deterministic scheduler choice
* @param deterministicChoice the (local) choice index
*/
SchedulerChoice(uint_fast64_t deterministicChoice);
/*!
* Creates a scheduler choice that potentially considers randomization
* @param randomizedChoice a distribution over the (local) choice indices
*/
SchedulerChoice(storm::storage::Distribution<ValueType, uint_fast64_t> const& randomizedChoice);
/*!
* Creates a scheduler choice that potentially considers randomization
* @param randomizedChoice a distribution over the (local) choice indices
*/
SchedulerChoice(storm::storage::Distribution<ValueType, uint_fast64_t>&& randomizedChoice);
/*!
* Returns true iff this scheduler choice is defined
*/
bool isDefined() const;
/*!
* Returns true iff this scheduler choice is deterministic (i.e., not randomized)
*/
bool isDeterministic() const;
/*!
* If this choice is deterministic, this function returns the selected (local) choice index.
* Otherwise, an exception is thrown.
*/
uint_fast64_t getDeterministicChoice() const;
/*!
* Retrieves this choice in the form of a probability distribution.
*/
storm::storage::Distribution<ValueType, uint_fast64_t> const& getChoiceAsDistribution() const;
/*!
* Changes the value type of this scheduler choice to the given one.
*/
template<typename NewValueType>
SchedulerChoice<NewValueType> toValueType() const {
storm::storage::Distribution<NewValueType, uint_fast64_t> newDistribution;
for (auto const& stateValuePair : distribution) {
newDistribution.addProbability(stateValuePair.first, storm::utility::convertNumber<NewValueType>(stateValuePair.second));
}
return SchedulerChoice<NewValueType>(std::move(newDistribution));
}
private:
storm::storage::Distribution<ValueType, uint_fast64_t> distribution;
};
template<typename ValueType>
std::ostream& operator<<(std::ostream& out, SchedulerChoice<ValueType> const& schedulerChoice);
}
}

68
src/storm/storage/TotalScheduler.cpp

@ -1,68 +0,0 @@
#include "storm/storage/TotalScheduler.h"
#include "storm/exceptions/InvalidArgumentException.h"
#include "storm/utility/Hash.h"
#include "storm/utility/vector.h"
namespace storm {
namespace storage {
TotalScheduler::TotalScheduler(uint_fast64_t numberOfStates) : choices(numberOfStates) {
// Intentionally left empty.
}
TotalScheduler::TotalScheduler(std::vector<uint_fast64_t> const& choices) : choices(choices) {
// Intentionally left empty.
}
TotalScheduler::TotalScheduler(std::vector<uint_fast64_t>&& choices) : choices(std::move(choices)) {
// Intentionally left empty.
}
bool TotalScheduler::operator==(storm::storage::TotalScheduler const& other) const {
return this->choices == other.choices;
}
void TotalScheduler::setChoice(uint_fast64_t state, uint_fast64_t choice) {
if (state > choices.size()) {
throw storm::exceptions::InvalidArgumentException() << "Invalid call to TotalScheduler::setChoice: scheduler cannot not define a choice for state " << state << ".";
}
choices[state] = choice;
}
bool TotalScheduler::isChoiceDefined(uint_fast64_t state) const {
return state < choices.size();
}
uint_fast64_t TotalScheduler::getChoice(uint_fast64_t state) const {
if (state >= choices.size()) {
throw storm::exceptions::InvalidArgumentException() << "Invalid call to TotalScheduler::getChoice: scheduler does not define a choice for state " << state << ".";
}
return choices[state];
}
std::vector<uint_fast64_t> const& TotalScheduler::getChoices() const {
return choices;
}
TotalScheduler TotalScheduler::getSchedulerForSubsystem(storm::storage::BitVector const& subsystem) const {
return TotalScheduler(storm::utility::vector::filterVector(choices, subsystem));
}
std::ostream& operator<<(std::ostream& out, TotalScheduler const& scheduler) {
out << "total scheduler (defined on " << scheduler.choices.size() << " states) [ ";
for (uint_fast64_t state = 0; state < scheduler.choices.size() - 1; ++state) {
out << state << " -> " << scheduler.choices[state] << ", ";
}
if (scheduler.choices.size() > 0) {
out << (scheduler.choices.size() - 1) << " -> " << scheduler.choices[scheduler.choices.size() - 1] << " ]";
}
return out;
}
}
}
namespace std {
std::size_t hash<storm::storage::TotalScheduler>::operator()(storm::storage::TotalScheduler const& totalScheduler) const {
return storm::utility::Hash<uint_fast64_t>::getHash(totalScheduler.choices);
}
}

78
src/storm/storage/TotalScheduler.h

@ -1,78 +0,0 @@
#ifndef STORM_STORAGE_TOTALSCHEDULER_H_
#define STORM_STORAGE_TOTALSCHEDULER_H_
#include <vector>
#include <ostream>
#include "storm/storage/Scheduler.h"
#include "storm/storage/BitVector.h"
namespace storm {
namespace storage {
class TotalScheduler : public Scheduler {
public:
TotalScheduler(TotalScheduler const& other) = default;
TotalScheduler(TotalScheduler&& other) = default;
TotalScheduler& operator=(TotalScheduler const& other) = default;
TotalScheduler& operator=(TotalScheduler&& other) = default;
/*!
* Creates a total scheduler that defines a choice for the given number of states. By default, all choices
* are initialized to zero.
*
* @param numberOfStates The number of states for which the scheduler defines a choice.
*/
TotalScheduler(uint_fast64_t numberOfStates = 0);
/*!
* Creates a total scheduler that defines the choices for states according to the given vector.
*
* @param choices A vector whose i-th entry defines the choice of state i.
*/
TotalScheduler(std::vector<uint_fast64_t> const& choices);
/*!
* Creates a total scheduler that defines the choices for states according to the given vector.
*
* @param choices A vector whose i-th entry defines the choice of state i.
*/
TotalScheduler(std::vector<uint_fast64_t>&& choices);
bool operator==(TotalScheduler const& other) const;
void setChoice(uint_fast64_t state, uint_fast64_t choice) override;
bool isChoiceDefined(uint_fast64_t state) const override;
uint_fast64_t getChoice(uint_fast64_t state) const override;
std::vector<uint_fast64_t> const& getChoices() const;
/*!
* Constructs the scheduler for the subsystem indicated by the given BitVector
*
* @param subsystem A BitVector whose i-th entry is true iff state i is part of the subsystem
*/
TotalScheduler getSchedulerForSubsystem(storm::storage::BitVector const& subsystem) const;
friend std::ostream& operator<<(std::ostream& out, TotalScheduler const& scheduler);
friend struct std::hash<storm::storage::TotalScheduler>;
private:
// A vector that stores the choice for each state.
std::vector<uint_fast64_t> choices;
};
} // namespace storage
} // namespace storm
namespace std {
template <>
struct hash<storm::storage::TotalScheduler> {
std::size_t operator()(storm::storage::TotalScheduler const& totalScheduler) const;
};
}
#endif /* STORM_STORAGE_TOTALSCHEDULER_H_ */

59
src/storm/utility/graph.cpp

@ -385,8 +385,7 @@ namespace storm {
}
template <typename T>
storm::storage::PartialScheduler computeSchedulerStayingInStates(storm::storage::BitVector const& states, storm::storage::SparseMatrix<T> const& transitionMatrix) {
storm::storage::PartialScheduler result;
void computeSchedulerStayingInStates(storm::storage::BitVector const& states, storm::storage::SparseMatrix<T> const& transitionMatrix, storm::storage::Scheduler<T>& scheduler) {
std::vector<uint_fast64_t> const& nondeterministicChoiceIndices = transitionMatrix.getRowGroupIndices();
for (auto const& state : states) {
@ -399,18 +398,17 @@ namespace storm {
}
}
if (allSuccessorsInStates) {
result.setChoice(state, choice - nondeterministicChoiceIndices[state]);
for (uint_fast64_t memState = 0; memState < scheduler.getNumberOfMemoryStates(); ++memState) {
scheduler.setChoice(choice - nondeterministicChoiceIndices[state], state, memState);
}
break;
}
}
}
return result;
}
template <typename T>
storm::storage::PartialScheduler computeSchedulerWithOneSuccessorInStates(storm::storage::BitVector const& states, storm::storage::SparseMatrix<T> const& transitionMatrix) {
storm::storage::PartialScheduler result;
void computeSchedulerWithOneSuccessorInStates(storm::storage::BitVector const& states, storm::storage::SparseMatrix<T> const& transitionMatrix, storm::storage::Scheduler<T>& scheduler) {
std::vector<uint_fast64_t> const& nondeterministicChoiceIndices = transitionMatrix.getRowGroupIndices();
for (auto const& state : states) {
@ -423,20 +421,19 @@ namespace storm {
}
}
if (oneSuccessorInStates) {
result.setChoice(state, choice - nondeterministicChoiceIndices[state]);
for (uint_fast64_t memState = 0; memState < scheduler.getNumberOfMemoryStates(); ++memState) {
scheduler.setChoice(choice - nondeterministicChoiceIndices[state], state, memState);
}
break;
}
}
}
return result;
}
template <typename T>
storm::storage::PartialScheduler computeSchedulerProbGreater0E(storm::storage::SparseMatrix<T> const& transitionMatrix, storm::storage::SparseMatrix<T> const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, boost::optional<storm::storage::BitVector> const& rowFilter) {
void computeSchedulerProbGreater0E(storm::storage::SparseMatrix<T> const& transitionMatrix, storm::storage::SparseMatrix<T> const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::storage::Scheduler<T>& scheduler, boost::optional<storm::storage::BitVector> const& rowFilter) {
//Perform backwards DFS from psiStates and find a valid choice for each visited state.
storm::storage::PartialScheduler result;
std::vector<uint_fast64_t> stack;
storm::storage::BitVector currentStates(psiStates); //the states that are either psiStates or for which we have found a valid choice.
stack.insert(stack.end(), currentStates.begin(), currentStates.end());
@ -462,7 +459,9 @@ namespace storm {
}
}
if(foundValidChoice){
result.setChoice(predecessor, row - transitionMatrix.getRowGroupIndices()[predecessor]);
for (uint_fast64_t memState = 0; memState < scheduler.getNumberOfMemoryStates(); ++memState) {
scheduler.setChoice(row - transitionMatrix.getRowGroupIndices()[predecessor], predecessor, memState);
}
currentStates.set(predecessor, true);
stack.push_back(predecessor);
break;
@ -472,18 +471,24 @@ namespace storm {
}
}
}
return result;
}
template <typename T>
storm::storage::PartialScheduler computeSchedulerProb0E(storm::storage::BitVector const& prob0EStates, storm::storage::SparseMatrix<T> const& transitionMatrix) {
return computeSchedulerStayingInStates(prob0EStates, transitionMatrix);
void computeSchedulerProb0E(storm::storage::BitVector const& prob0EStates, storm::storage::SparseMatrix<T> const& transitionMatrix, storm::storage::Scheduler<T>& scheduler) {
computeSchedulerStayingInStates(prob0EStates, transitionMatrix, scheduler);
}
template <typename T>
storm::storage::PartialScheduler computeSchedulerProb1E(storm::storage::BitVector const& prob1EStates, storm::storage::SparseMatrix<T> const& transitionMatrix, storm::storage::SparseMatrix<T> const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates) {
void computeSchedulerProb1E(storm::storage::BitVector const& prob1EStates, storm::storage::SparseMatrix<T> const& transitionMatrix, storm::storage::SparseMatrix<T> const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::storage::Scheduler<T>& scheduler) {
// set an arbitrary choice for the psi states.
for (auto const& psiState : psiStates) {
for (uint_fast64_t memState = 0; memState < scheduler.getNumberOfMemoryStates(); ++memState) {
scheduler.setChoice(0, psiState, memState);
}
}
storm::storage::PartialScheduler result;
// Now perform a backwards search from the psi states and store choices with prob. 1
std::vector<uint_fast64_t> const& nondeterministicChoiceIndices = transitionMatrix.getRowGroupIndices();
std::vector<uint_fast64_t> stack;
storm::storage::BitVector currentStates(psiStates);
@ -513,7 +518,9 @@ 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 - nondeterministicChoiceIndices[predecessorEntryIt->getColumn()]);
for (uint_fast64_t memState = 0; memState < scheduler.getNumberOfMemoryStates(); ++memState) {
scheduler.setChoice(row - nondeterministicChoiceIndices[predecessorEntryIt->getColumn()], predecessorEntryIt->getColumn(), memState);
}
currentStates.set(predecessorEntryIt->getColumn(), true);
stack.push_back(predecessorEntryIt->getColumn());
break;
@ -522,8 +529,6 @@ namespace storm {
}
}
}
return result;
}
template <typename T>
@ -1309,11 +1314,11 @@ namespace storm {
template storm::storage::PartialScheduler computeSchedulerProbGreater0E(storm::storage::SparseMatrix<double> const& transitionMatrix, storm::storage::SparseMatrix<double> const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, boost::optional<storm::storage::BitVector> const& rowFilter);
template void computeSchedulerProbGreater0E(storm::storage::SparseMatrix<double> const& transitionMatrix, storm::storage::SparseMatrix<double> const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::storage::Scheduler<double>& scheduler, boost::optional<storm::storage::BitVector> const& rowFilter);
template storm::storage::PartialScheduler computeSchedulerProb0E(storm::storage::BitVector const& prob0EStates, storm::storage::SparseMatrix<double> const& transitionMatrix);
template void computeSchedulerProb0E(storm::storage::BitVector const& prob0EStates, storm::storage::SparseMatrix<double> const& transitionMatrix, storm::storage::Scheduler<double>& scheduler);
template storm::storage::PartialScheduler computeSchedulerProb1E(storm::storage::BitVector const& prob1EStates, storm::storage::SparseMatrix<double> const& transitionMatrix, storm::storage::SparseMatrix<double> const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates);
template void computeSchedulerProb1E(storm::storage::BitVector const& prob1EStates, storm::storage::SparseMatrix<double> const& transitionMatrix, storm::storage::SparseMatrix<double> const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::storage::Scheduler<double>& scheduler);
template storm::storage::BitVector performProbGreater0E(storm::storage::SparseMatrix<double> const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool useStepBound = false, uint_fast64_t maximalSteps = 0) ;
@ -1374,11 +1379,11 @@ namespace storm {
template std::pair<storm::storage::BitVector, storm::storage::BitVector> performProb01(storm::storage::SparseMatrix<storm::RationalNumber> const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates);
template storm::storage::PartialScheduler computeSchedulerProbGreater0E(storm::storage::SparseMatrix<storm::RationalNumber> const& transitionMatrix, storm::storage::SparseMatrix<storm::RationalNumber> const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, boost::optional<storm::storage::BitVector> const& rowFilter);
template void computeSchedulerProbGreater0E(storm::storage::SparseMatrix<storm::RationalNumber> const& transitionMatrix, storm::storage::SparseMatrix<storm::RationalNumber> const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::storage::Scheduler<storm::RationalNumber>& scheduler, boost::optional<storm::storage::BitVector> const& rowFilter);
template storm::storage::PartialScheduler computeSchedulerProb0E(storm::storage::BitVector const& prob0EStates, storm::storage::SparseMatrix<storm::RationalNumber> const& transitionMatrix);
template void computeSchedulerProb0E(storm::storage::BitVector const& prob0EStates, storm::storage::SparseMatrix<storm::RationalNumber> const& transitionMatrix, storm::storage::Scheduler<storm::RationalNumber>& scheduler);
template storm::storage::PartialScheduler computeSchedulerProb1E(storm::storage::BitVector const& prob1EStates, storm::storage::SparseMatrix<storm::RationalNumber> const& transitionMatrix, storm::storage::SparseMatrix<storm::RationalNumber> const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates);
template void computeSchedulerProb1E(storm::storage::BitVector const& prob1EStates, storm::storage::SparseMatrix<storm::RationalNumber> const& transitionMatrix, storm::storage::SparseMatrix<storm::RationalNumber> const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::storage::Scheduler<storm::RationalNumber>& scheduler);
template storm::storage::BitVector performProbGreater0E(storm::storage::SparseMatrix<storm::RationalNumber> const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, bool useStepBound = false, uint_fast64_t maximalSteps = 0) ;

19
src/storm/utility/graph.h

@ -7,7 +7,7 @@
#include "storm/utility/OsDetection.h"
#include "storm/storage/sparse/StateType.h"
#include "storm/storage/PartialScheduler.h"
#include "storm/storage/Scheduler.h"
#include "storm/models/sparse/NondeterministicModel.h"
#include "storm/models/sparse/DeterministicModel.h"
#include "storm/storage/dd/DdType.h"
@ -245,9 +245,10 @@ namespace storm {
*
* @param states The set of states for which to compute the scheduler that stays in this very set.
* @param transitionMatrix The transition matrix.
* @param scheduler The resulting scheduler. The scheduler is only set at the given states.
*/
template <typename T>
storm::storage::PartialScheduler computeSchedulerStayingInStates(storm::storage::BitVector const& states, storm::storage::SparseMatrix<T> const& transitionMatrix);
void computeSchedulerStayingInStates(storm::storage::BitVector const& states, storm::storage::SparseMatrix<T> const& transitionMatrix, storm::storage::Scheduler<T>& scheduler);
/*!
* Computes a scheduler for the given states that chooses an action that has at least one successor in the
@ -256,9 +257,10 @@ namespace storm {
* @param states The set of states for which to compute the scheduler that chooses an action with a successor
* in this very set.
* @param transitionMatrix The transition matrix.
* @param scheduler The resulting scheduler. The scheduler is only set at the given states.
*/
template <typename T>
storm::storage::PartialScheduler computeSchedulerWithOneSuccessorInStates(storm::storage::BitVector const& states, storm::storage::SparseMatrix<T> const& transitionMatrix);
void computeSchedulerWithOneSuccessorInStates(storm::storage::BitVector const& states, storm::storage::SparseMatrix<T> const& transitionMatrix, storm::storage::Scheduler<T>& scheduler);
/*!
* Computes a scheduler for the ProbGreater0E-States such that in the induced system the given psiStates are reachable via phiStates
@ -268,22 +270,23 @@ namespace storm {
* @param phiStates The set of states satisfying phi.
* @param psiStates The set of states satisfying psi.
* @param rowFilter If given, the returned scheduler will only pick choices such that rowFilter is true for the corresponding matrixrow.
* @return A Scheduler for the ProbGreater0E-States
* @param scheduler The resulting scheduler for the ProbGreater0E-States. The scheduler is not set at prob0A states.
*
* @note No choice is defined for ProbGreater0E-States if all the probGreater0-choices violate the row filter.
* This also holds for states that only reach psi via such states.
*/
template <typename T>
storm::storage::PartialScheduler computeSchedulerProbGreater0E(storm::storage::SparseMatrix<T> const& transitionMatrix, storm::storage::SparseMatrix<T> const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, boost::optional<storm::storage::BitVector> const& rowFilter = boost::none);
void computeSchedulerProbGreater0E(storm::storage::SparseMatrix<T> const& transitionMatrix, storm::storage::SparseMatrix<T> const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::storage::Scheduler<T>& scheduler, boost::optional<storm::storage::BitVector> const& rowFilter = boost::none);
/*!
* Computes a scheduler for the given states that have a scheduler that has a probability 0.
*
* @param prob0EStates The states that have a scheduler achieving probablity 0.
* @param transitionMatrix The transition matrix of the system.
* @param scheduler The resulting scheduler for the prob0EStates States. The scheduler is not set at probGreater0A states.
*/
template <typename T>
storm::storage::PartialScheduler computeSchedulerProb0E(storm::storage::BitVector const& prob0EStates, storm::storage::SparseMatrix<T> const& transitionMatrix);
void computeSchedulerProb0E(storm::storage::BitVector const& prob0EStates, storm::storage::SparseMatrix<T> const& transitionMatrix, storm::storage::Scheduler<T>& scheduler);
/*!
* Computes a scheduler for the given prob1EStates such that in the induced system the given psiStates are reached with probability 1.
@ -293,10 +296,10 @@ namespace storm {
* @param backwardTransitions The reversed transition relation.
* @param phiStates The set of states satisfying phi.
* @param psiStates The set of states satisfying psi.
* @return A scheduler for the Prob1E-States
* @param scheduler The resulting scheduler for the prob1EStates. The scheduler is not set at the remaining states.
*/
template <typename T>
storm::storage::PartialScheduler computeSchedulerProb1E(storm::storage::BitVector const& prob1EStates, storm::storage::SparseMatrix<T> const& transitionMatrix, storm::storage::SparseMatrix<T> const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates);
void computeSchedulerProb1E(storm::storage::BitVector const& prob1EStates, storm::storage::SparseMatrix<T> const& transitionMatrix, storm::storage::SparseMatrix<T> const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates, storm::storage::Scheduler<T>& scheduler);
/*!
* Computes the sets of states that have probability greater 0 of satisfying phi until psi under at least

20
src/test/modelchecker/GmmxxMdpPrctlModelCheckerTest.cpp

@ -222,11 +222,11 @@ TEST(GmmxxMdpPrctlModelCheckerTest, SchedulerGeneration) {
ASSERT_TRUE(result->isExplicitQuantitativeCheckResult());
ASSERT_TRUE(result->asExplicitQuantitativeCheckResult<double>().hasScheduler());
storm::storage::Scheduler const& scheduler = result->asExplicitQuantitativeCheckResult<double>().getScheduler();
EXPECT_EQ(0ull, scheduler.getChoice(0));
EXPECT_EQ(1ull, scheduler.getChoice(1));
EXPECT_EQ(0ull, scheduler.getChoice(2));
EXPECT_EQ(0ull, scheduler.getChoice(3));
storm::storage::Scheduler<double> const& scheduler = result->asExplicitQuantitativeCheckResult<double>().getScheduler();
EXPECT_EQ(0ull, scheduler.getChoice(0).getDeterministicChoice());
EXPECT_EQ(1ull, scheduler.getChoice(1).getDeterministicChoice());
EXPECT_EQ(0ull, scheduler.getChoice(2).getDeterministicChoice());
EXPECT_EQ(0ull, scheduler.getChoice(3).getDeterministicChoice());
formula = formulaParser.parseSingleFormulaFromString("Pmax=? [F \"target\"]");
@ -236,11 +236,11 @@ TEST(GmmxxMdpPrctlModelCheckerTest, SchedulerGeneration) {
ASSERT_TRUE(result->isExplicitQuantitativeCheckResult());
ASSERT_TRUE(result->asExplicitQuantitativeCheckResult<double>().hasScheduler());
storm::storage::Scheduler const& scheduler2 = result->asExplicitQuantitativeCheckResult<double>().getScheduler();
EXPECT_EQ(1ull, scheduler2.getChoice(0));
EXPECT_EQ(2ull, scheduler2.getChoice(1));
EXPECT_EQ(0ull, scheduler2.getChoice(2));
EXPECT_EQ(0ull, scheduler2.getChoice(3));
storm::storage::Scheduler<double> const& scheduler2 = result->asExplicitQuantitativeCheckResult<double>().getScheduler();
EXPECT_EQ(1ull, scheduler2.getChoice(0).getDeterministicChoice());
EXPECT_EQ(2ull, scheduler2.getChoice(1).getDeterministicChoice());
EXPECT_EQ(0ull, scheduler2.getChoice(2).getDeterministicChoice());
EXPECT_EQ(0ull, scheduler2.getChoice(3).getDeterministicChoice());
}
// Test is currently disabled as the computation of this property requires eliminating the zero-reward MECs, which is

67
src/test/storage/SchedulerTest.cpp

@ -1,42 +1,53 @@
#include "gtest/gtest.h"
#include "storm-config.h"
#include "storm/exceptions/InvalidArgumentException.h"
#include "storm/storage/PartialScheduler.h"
#include "storm/storage/TotalScheduler.h"
#include "storm/exceptions/InvalidOperationException.h"
#include "storm/storage/Scheduler.h"
TEST(SchedulerTest, PartialScheduler) {
storm::storage::PartialScheduler scheduler;
TEST(SchedulerTest, TotalDeterministicMemorylessScheduler) {
storm::storage::Scheduler<double> scheduler(4);
ASSERT_NO_THROW(scheduler.setChoice(0, 1));
ASSERT_NO_THROW(scheduler.setChoice(0, 3));
ASSERT_NO_THROW(scheduler.setChoice(3, 4));
ASSERT_NO_THROW(scheduler.setChoice(1, 0));
ASSERT_NO_THROW(scheduler.setChoice(3, 1));
ASSERT_NO_THROW(scheduler.setChoice(5, 2));
ASSERT_NO_THROW(scheduler.setChoice(4, 3));
ASSERT_TRUE(scheduler.isChoiceDefined(0));
ASSERT_EQ(3ul, scheduler.getChoice(0));
ASSERT_FALSE(scheduler.isPartialScheduler());
ASSERT_TRUE(scheduler.isMemorylessScheduler());
ASSERT_TRUE(scheduler.isDeterministicScheduler());
ASSERT_TRUE(scheduler.isChoiceDefined(3));
ASSERT_EQ(4ul, scheduler.getChoice(3));
ASSERT_TRUE(scheduler.getChoice(0).isDefined());
ASSERT_EQ(1ul, scheduler.getChoice(0).getDeterministicChoice());
ASSERT_TRUE(scheduler.getChoice(1).isDefined());
ASSERT_EQ(3ul, scheduler.getChoice(1).getDeterministicChoice());
ASSERT_TRUE(scheduler.getChoice(2).isDefined());
ASSERT_EQ(5ul, scheduler.getChoice(2).getDeterministicChoice());
ASSERT_TRUE(scheduler.getChoice(3).isDefined());
ASSERT_EQ(4ul, scheduler.getChoice(3).getDeterministicChoice());
ASSERT_FALSE(scheduler.isChoiceDefined(1));
ASSERT_THROW(scheduler.getChoice(1), storm::exceptions::InvalidArgumentException);
}
TEST(SchedulerTest, TotalScheduler) {
storm::storage::TotalScheduler scheduler(4);
TEST(SchedulerTest, PartialDeterministicMemorylessScheduler) {
storm::storage::Scheduler<double> scheduler(4);
ASSERT_NO_THROW(scheduler.setChoice(1, 0));
ASSERT_NO_THROW(scheduler.setChoice(3, 0));
ASSERT_NO_THROW(scheduler.setChoice(5, 2));
ASSERT_NO_THROW(scheduler.setChoice(4, 3));
ASSERT_NO_THROW(scheduler.clearChoice(2));
ASSERT_NO_THROW(scheduler.setChoice(0, 1));
ASSERT_NO_THROW(scheduler.setChoice(0, 3));
ASSERT_NO_THROW(scheduler.setChoice(3, 4));
ASSERT_TRUE(scheduler.isPartialScheduler());
ASSERT_TRUE(scheduler.isMemorylessScheduler());
ASSERT_TRUE(scheduler.isDeterministicScheduler());
ASSERT_TRUE(scheduler.isChoiceDefined(0));
ASSERT_EQ(3ul, scheduler.getChoice(0));
ASSERT_TRUE(scheduler.getChoice(0).isDefined());
ASSERT_EQ(3ul, scheduler.getChoice(0).getDeterministicChoice());
ASSERT_TRUE(scheduler.isChoiceDefined(3));
ASSERT_EQ(4ul, scheduler.getChoice(3));
ASSERT_TRUE(scheduler.getChoice(3).isDefined());
ASSERT_EQ(4ul, scheduler.getChoice(3).getDeterministicChoice());
ASSERT_TRUE(scheduler.isChoiceDefined(1));
ASSERT_EQ(0ul, scheduler.getChoice(1));
ASSERT_THROW(scheduler.getChoice(4), storm::exceptions::InvalidArgumentException);
ASSERT_THROW(scheduler.setChoice(5, 2), storm::exceptions::InvalidArgumentException);
ASSERT_FALSE(scheduler.getChoice(1).isDefined());
ASSERT_FALSE(scheduler.getChoice(2).isDefined());
}
|||||||
100:0
Loading…
Cancel
Save