22template<
typename SparseModelType,
typename ConstantType>
28template<
typename SparseModelType,
typename ConstantType>
31 : solverFactory(
std::move(solverFactory)) {
35template<
typename SparseModelType,
typename ConstantType>
42 result &=
static_cast<bool>(mdp);
44 .setRewardOperatorsAllowed(
true)
45 .setReachabilityRewardFormulasAllowed(
true)
46 .setBoundedUntilFormulasAllowed(
true)
47 .setCumulativeRewardFormulasAllowed(
true)
48 .setStepBoundedUntilFormulasAllowed(
true)
49 .setTimeBoundedCumulativeRewardFormulasAllowed(
true)
50 .setStepBoundedCumulativeRewardFormulasAllowed(
true)
51 .setTimeBoundedUntilFormulasAllowed(
true));
55template<
typename SparseModelType,
typename ConstantType>
59 std::optional<RegionSplitEstimateKind> generateRegionSplitEstimates,
61 bool allowModelSimplifications,
bool graphPreserving) {
63 "Combination of model " <<
parametricModel->getType() <<
" and formula '" << checkTask.
getFormula() <<
"' is not supported.");
64 STORM_LOG_THROW(graphPreserving, storm::exceptions::NotImplementedException,
"Non-graph-preserving regions not implemented for MDPs.");
70 if (allowModelSimplifications) {
72 STORM_LOG_THROW(simplifier.simplify(checkTask.
getFormula()), storm::exceptions::UnexpectedException,
"Simplifying the model was not successfull.");
73 this->parametricModel = simplifier.getSimplifiedModel();
76 this->parametricModel = mdp;
80 std::shared_ptr<storm::logic::Formula> formulaWithoutBounds = this->
currentCheckTask->getFormula().clone();
81 formulaWithoutBounds->asOperatorFormula().removeBound();
82 this->currentFormulaNoBound = formulaWithoutBounds->asSharedPointer();
83 this->currentCheckTaskNoBound = std::make_unique<storm::modelchecker::CheckTask<storm::logic::Formula, ParametricType>>(*this->currentFormulaNoBound);
86template<
typename SparseModelType,
typename ConstantType>
90 STORM_LOG_THROW(!checkTask.
getFormula().hasLowerBound(), storm::exceptions::NotSupportedException,
"Lower step bounds are not supported.");
91 STORM_LOG_THROW(checkTask.
getFormula().hasUpperBound(), storm::exceptions::NotSupportedException,
"Expected a bounded until formula with an upper bound.");
93 "Expected a bounded until formula with step bounds.");
94 stepBound = checkTask.
getFormula().getUpperBound().evaluateAsInt();
95 STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException,
96 "Can not apply parameter lifting on step bounded formula: The step bound has to be positive.");
97 if (checkTask.
getFormula().isUpperBoundStrict()) {
98 STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException,
"Expected a strict upper step bound that is greater than zero.");
101 STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException,
102 "Can not apply parameter lifting on step bounded formula: The step bound has to be positive.");
108 storm::exceptions::NotSupportedException,
"Parameter lifting with non-propositional subformulas is not supported.");
110 ->template asExplicitQualitativeCheckResult<typename SparseModelType::ValueType>()
111 .getTruthValuesVector());
113 ->template asExplicitQualitativeCheckResult<typename SparseModelType::ValueType>()
114 .getTruthValuesVector());
119 this->parametricModel->getTransitionMatrix().getRowGroupIndices(),
120 this->parametricModel->getBackwardTransitions(), phiStates, psiStates,
true, *stepBound)
122 maybeStates &= ~psiStates;
129 if (!maybeStates.empty()) {
131 std::vector<ParametricType> b = this->
parametricModel->getTransitionMatrix().getConstrainedRowSumVector(
134 parameterLifter = std::make_unique<storm::transformer::ParameterLifter<ParametricType, ConstantType>>(
136 computePlayer1Matrix();
138 applyPreviousResultAsHint =
false;
146template<
typename SparseModelType,
typename ConstantType>
153 storm::exceptions::NotSupportedException,
"Parameter lifting with non-propositional subformulas is not supported.");
155 ->template asExplicitQualitativeCheckResult<typename SparseModelType::ValueType>()
156 .getTruthValuesVector());
158 ->template asExplicitQualitativeCheckResult<typename SparseModelType::ValueType>()
159 .getTruthValuesVector());
162 std::pair<storm::storage::BitVector, storm::storage::BitVector> statesWithProbability01 =
165 this->parametricModel->getTransitionMatrix().getRowGroupIndices(),
166 this->parametricModel->getBackwardTransitions(), phiStates, psiStates)
168 this->parametricModel->getTransitionMatrix().getRowGroupIndices(),
169 this->parametricModel->getBackwardTransitions(), phiStates, psiStates);
170 maybeStates = ~(statesWithProbability01.first | statesWithProbability01.second);
177 if (!maybeStates.empty()) {
179 std::vector<ParametricType> b = this->
parametricModel->getTransitionMatrix().getConstrainedRowSumVector(
182 parameterLifter = std::make_unique<storm::transformer::ParameterLifter<ParametricType, ConstantType>>(
184 computePlayer1Matrix();
187 applyPreviousResultAsHint =
190 this->parametricModel->getTransitionMatrix().getRowGroupIndices(),
191 this->parametricModel->getBackwardTransitions(), maybeStates, ~maybeStates)
200template<
typename SparseModelType,
typename ConstantType>
206 "Parameter lifting with non-propositional subformulas is not supported.");
208 ->template asExplicitQualitativeCheckResult<typename SparseModelType::ValueType>()
209 .getTruthValuesVector());
215 this->
parametricModel->getTransitionMatrix(), this->parametricModel->getTransitionMatrix().getRowGroupIndices(),
216 this->parametricModel->getBackwardTransitions(),
storm::storage::BitVector(this->parametricModel->getNumberOfStates(),
true), targetStates)
218 this->
parametricModel->getTransitionMatrix(), this->parametricModel->getTransitionMatrix().getRowGroupIndices(),
219 this->parametricModel->getBackwardTransitions(),
storm::storage::BitVector(this->parametricModel->getNumberOfStates(),
true), targetStates);
221 maybeStates = ~(targetStates | infinityStates);
228 if (!maybeStates.empty()) {
231 (!checkTask.
isRewardModelSet() && this->parametricModel->hasUniqueRewardModel()),
232 storm::exceptions::InvalidPropertyException,
"The reward model specified by the CheckTask is not available in the given model.");
234 typename SparseModelType::RewardModelType
const& rewardModel =
237 std::vector<ParametricType> b = rewardModel.getTotalRewardVector(this->
parametricModel->getTransitionMatrix());
244 parameterLifter = std::make_unique<storm::transformer::ParameterLifter<ParametricType, ConstantType>>(this->
parametricModel->getTransitionMatrix(), b,
245 selectedRows, maybeStates);
246 computePlayer1Matrix(selectedRows);
249 applyPreviousResultAsHint =
252 this->parametricModel->getTransitionMatrix().getRowGroupIndices(),
253 this->parametricModel->getBackwardTransitions(), maybeStates, ~maybeStates)
261template<
typename SparseModelType,
typename ConstantType>
265 stepBound = checkTask.
getFormula().getBound().evaluateAsInt();
267 STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException,
"Expected a strict upper step bound that is greater than zero.");
270 STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException,
271 "Can not apply parameter lifting on step bounded formula: The step bound has to be positive.");
275 resultsForNonMaybeStates = std::vector<ConstantType>(this->
parametricModel->getNumberOfStates());
279 (!checkTask.
isRewardModelSet() && this->parametricModel->hasUniqueRewardModel()),
280 storm::exceptions::InvalidPropertyException,
"The reward model specified by the CheckTask is not available in the given model.");
281 typename SparseModelType::RewardModelType
const& rewardModel =
283 std::vector<ParametricType> b = rewardModel.getTotalRewardVector(this->
parametricModel->getTransitionMatrix());
285 parameterLifter = std::make_unique<storm::transformer::ParameterLifter<ParametricType, ConstantType>>(
288 computePlayer1Matrix();
290 applyPreviousResultAsHint =
false;
296template<
typename SparseModelType,
typename ConstantType>
299 if (!instantiationChecker) {
300 instantiationChecker = std::make_unique<storm::modelchecker::SparseMdpInstantiationModelChecker<SparseModelType, ConstantType>>(*this->
parametricModel);
301 instantiationChecker->specifyFormula(quantitative ? *this->currentCheckTaskNoBound
303 instantiationChecker->setInstantiationsAreGraphPreserving(
true);
305 return *instantiationChecker;
308template<
typename SparseModelType,
typename ConstantType>
315template<
typename SparseModelType,
typename ConstantType>
318 if (maybeStates.empty()) {
320 return resultsForNonMaybeStates;
323 parameterLifter->specifyRegion(
region.region, dirForParameters);
326 auto solver = solverFactory->create(env, player1Matrix, parameterLifter->getMatrix());
327 if (lowerResultBound) {
328 solver->setLowerBound(lowerResultBound.value());
330 if (upperResultBound) {
331 solver->setUpperBound(upperResultBound.value());
333 if (applyPreviousResultAsHint) {
334 solver->setTrackSchedulers(
true);
337 solver->setSchedulerHints(std::move(player1SchedChoices.value()), std::move(minSchedChoices.value()));
340 solver->setSchedulerHints(std::move(player1SchedChoices.value()), std::move(maxSchedChoices.value()));
345 if (this->
currentCheckTask->isBoundSet() && this->currentCheckTask->getOptimizationDirection() == dirForParameters &&
solver->hasSchedulerHints()) {
347 std::unique_ptr<storm::solver::TerminationCondition<ConstantType>> termCond;
353 termCond = std::make_unique<storm::solver::TerminateIfFilteredExtremumBelowThreshold<ConstantType>>(
354 relevantStatesInSubsystem,
true, this->
currentCheckTask->getBoundThreshold(),
false);
357 termCond = std::make_unique<storm::solver::TerminateIfFilteredExtremumExceedsThreshold<ConstantType>>(
358 relevantStatesInSubsystem,
true, this->
currentCheckTask->getBoundThreshold(),
true);
360 solver->setTerminationCondition(std::move(termCond));
366 solver->repeatedMultiply(env, this->
currentCheckTask->getOptimizationDirection(), dirForParameters, x, ¶meterLifter->getVector(), *stepBound);
368 solver->solveGame(env, this->
currentCheckTask->getOptimizationDirection(), dirForParameters, x, parameterLifter->getVector());
369 if (applyPreviousResultAsHint) {
371 minSchedChoices =
solver->getPlayer2SchedulerChoices();
373 maxSchedChoices =
solver->getPlayer2SchedulerChoices();
375 player1SchedChoices =
solver->getPlayer1SchedulerChoices();
380 std::vector<ConstantType> result = resultsForNonMaybeStates;
381 auto maybeStateResIt = x.begin();
382 for (uint64_t maybeState : maybeStates) {
383 result[maybeState] = *maybeStateResIt;
390template<
typename SparseModelType,
typename ConstantType>
391void SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::computePlayer1Matrix(std::optional<storm::storage::BitVector>
const& selectedRows) {
395 n = selectedRows->getNumberOfSetBits();
397 for (uint64_t maybeState : maybeStates) {
398 n += this->parametricModel->getTransitionMatrix().getRowGroupSize(maybeState);
403 storm::storage::SparseMatrixBuilder<storm::storage::sparse::state_type> matrixBuilder(n, n, n,
true,
true, maybeStates.getNumberOfSetBits());
404 uint64_t p1MatrixRow = 0;
405 for (uint64_t maybeState : maybeStates) {
406 matrixBuilder.newRowGroup(p1MatrixRow);
408 for (uint64_t row = selectedRows->getNextSetIndex(this->parametricModel->getTransitionMatrix().getRowGroupIndices()[maybeState]);
409 row < this->parametricModel->getTransitionMatrix().getRowGroupIndices()[maybeState + 1]; row = selectedRows->getNextSetIndex(row + 1)) {
414 for (uint64_t endOfGroup = p1MatrixRow + this->parametricModel->getTransitionMatrix().getRowGroupSize(maybeState); p1MatrixRow < endOfGroup;
420 player1Matrix = matrixBuilder.build();
423template<
typename SparseModelType,
typename ConstantType>
425 maybeStates.resize(0);
426 resultsForNonMaybeStates.clear();
427 stepBound = std::nullopt;
428 instantiationChecker =
nullptr;
430 parameterLifter =
nullptr;
431 minSchedChoices = std::nullopt;
432 maxSchedChoices = std::nullopt;
434 lowerResultBound = std::nullopt;
435 upperResultBound = std::nullopt;
436 applyPreviousResultAsHint =
false;
439template<
typename ConstantType>
440std::optional<storm::storage::Scheduler<ConstantType>>
getSchedulerHelper(std::optional<std::vector<uint64_t>>
const& choices) {
441 std::optional<storm::storage::Scheduler<ConstantType>> result;
443 result.emplace(choices->size());
445 for (
auto const& choice : choices.value()) {
446 result->setChoice(choice, state);
453template<
typename SparseModelType,
typename ConstantType>
458template<
typename SparseModelType,
typename ConstantType>
463template<
typename SparseModelType,
typename ConstantType>
virtual std::unique_ptr< CheckResult > check(Environment const &env, CheckTask< storm::logic::Formula, SolutionType > const &checkTask)
Checks the provided formula.
CheckTask< NewFormulaType, ValueType > substituteFormula(NewFormulaType const &newFormula) const
Copies the check task from the source while replacing the formula with the new one.
bool isRewardModelSet() const
Retrieves whether a reward model was set.
std::string const & getRewardModel() const
Retrieves the reward model over which to perform the checking (if set).
FormulaType const & getFormula() const
Retrieves the formula from this task.
storm::OptimizationDirection const & getOptimizationDirection() const
Retrieves the optimization direction (if set).
virtual bool requiresInteractionWithRegionModelChecker() const
Returns true, if a region model checker needs to implement specific methods to properly use this back...
virtual void specifyMonotonicity(std::shared_ptr< MonotonicityBackend< SparseModelType::ValueType > > backend, CheckTask< storm::logic::Formula, SparseModelType::ValueType > const &checkTask)
std::shared_ptr< MonotonicityBackend< SparseModelType::ValueType > > monotonicityBackend
virtual void specifySplitEstimates(std::optional< RegionSplitEstimateKind > splitEstimates, CheckTask< storm::logic::Formula, SparseModelType::ValueType > const &checkTask)
Class to efficiently check a formula on a parametric model with different parameter instantiations.
std::optional< storm::storage::Scheduler< ConstantType > > getCurrentMinScheduler()
virtual void specifyReachabilityRewardFormula(Environment const &env, CheckTask< storm::logic::EventuallyFormula, ConstantType > const &checkTask) override
std::optional< storm::storage::Scheduler< ConstantType > > getCurrentPlayer1Scheduler()
SparseMdpParameterLiftingModelChecker()
virtual void reset() override
std::optional< storm::storage::Scheduler< ConstantType > > getCurrentMaxScheduler()
virtual std::vector< ConstantType > computeQuantitativeValues(Environment const &env, AnnotatedRegion< ParametricType > ®ion, storm::solver::OptimizationDirection const &dirForParameters) override
virtual bool isMonotonicitySupported(MonotonicityBackend< ParametricType > const &backend, CheckTask< storm::logic::Formula, ParametricType > const &checkTask) const override
Returns whether this region model checker can work together with the given monotonicity backend.
virtual bool canHandle(std::shared_ptr< storm::models::ModelBase > parametricModel, CheckTask< storm::logic::Formula, ParametricType > const &checkTask) const override
virtual void specifyUntilFormula(Environment const &env, CheckTask< storm::logic::UntilFormula, ConstantType > const &checkTask) override
virtual void specify(Environment const &env, std::shared_ptr< storm::models::ModelBase > parametricModel, CheckTask< storm::logic::Formula, ParametricType > const &checkTask, std::optional< RegionSplitEstimateKind > generateRegionSplitEstimates=std::nullopt, std::shared_ptr< MonotonicityBackend< ParametricType > > monotonicityBackend={}, bool allowModelSimplifications=true, bool graphPreserving=true) override
virtual void specifyBoundedUntilFormula(const CheckTask< storm::logic::BoundedUntilFormula, ConstantType > &checkTask) override
virtual storm::modelchecker::SparseInstantiationModelChecker< SparseModelType, ConstantType > & getInstantiationChecker(bool quantitative) override
virtual void specifyCumulativeRewardFormula(const CheckTask< storm::logic::CumulativeRewardFormula, ConstantType > &checkTask) override
std::unique_ptr< CheckTask< storm::logic::Formula, ConstantType > > currentCheckTask
void specifyFormula(Environment const &env, CheckTask< storm::logic::Formula, ParametricType > const &checkTask)
void updateKnownValueBoundInRegion(AnnotatedRegion< ParametricType > ®ion, storm::solver::OptimizationDirection dir, std::vector< ConstantType > const &newValues)
std::shared_ptr< SparseModelType > parametricModel
virtual bool canHandle(CheckTask< storm::logic::Formula, SolutionType > const &checkTask) const override
A bit vector that is internally represented as a vector of 64-bit values.
void complement()
Negates all bits in the bit vector.
bool full() const
Retrieves whether all bits are set in this bit vector.
A class that holds a possibly non-square matrix in the compressed row storage format.
#define STORM_LOG_ASSERT(cond, message)
#define STORM_LOG_THROW(cond, exception, message)
FragmentSpecification reachability()
std::optional< storm::storage::Scheduler< ConstantType > > getSchedulerHelper(std::optional< std::vector< uint64_t > > const &choices)
bool constexpr maximize(OptimizationDirection d)
bool constexpr minimize(OptimizationDirection d)
std::pair< storm::storage::BitVector, storm::storage::BitVector > performProb01Max(storm::storage::SparseMatrix< T > const &transitionMatrix, std::vector< uint_fast64_t > const &nondeterministicChoiceIndices, storm::storage::SparseMatrix< T > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates)
storm::storage::BitVector performProbGreater0A(storm::storage::SparseMatrix< T > const &transitionMatrix, std::vector< uint_fast64_t > const &nondeterministicChoiceIndices, storm::storage::SparseMatrix< T > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates, bool useStepBound, uint_fast64_t maximalSteps, boost::optional< storm::storage::BitVector > const &choiceConstraint)
Computes the sets of states that have probability greater 0 of satisfying phi until psi under any pos...
storm::storage::BitVector performProb1A(storm::models::sparse::NondeterministicModel< T, RM > const &model, storm::storage::SparseMatrix< T > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates)
Computes the sets of states that have probability 1 of satisfying phi until psi under all possible re...
storm::storage::BitVector performProbGreater0E(storm::storage::SparseMatrix< T > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates, bool useStepBound, uint_fast64_t maximalSteps)
Computes the sets of states that have probability greater 0 of satisfying phi until psi under at leas...
std::pair< storm::storage::BitVector, storm::storage::BitVector > performProb01Min(storm::storage::SparseMatrix< T > const &transitionMatrix, std::vector< uint_fast64_t > const &nondeterministicChoiceIndices, storm::storage::SparseMatrix< T > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates)
storm::storage::BitVector performProb1E(storm::storage::SparseMatrix< T > const &transitionMatrix, std::vector< uint_fast64_t > const &nondeterministicChoiceIndices, storm::storage::SparseMatrix< T > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates, boost::optional< storm::storage::BitVector > const &choiceConstraint)
Computes the sets of states that have probability 1 of satisfying phi until psi under at least one po...
void setVectorValues(std::vector< T > &vector, storm::storage::BitVector const &positions, std::vector< T > const &values)
Sets the provided values at the provided positions in the given vector.