23template<
typename SparseModelType,
typename ConstantType>
29template<
typename SparseModelType,
typename ConstantType>
32 : solverFactory(
std::move(solverFactory)) {
36template<
typename SparseModelType,
typename ConstantType>
40 result &= parametricModel->isSparseModel();
41 result &= parametricModel->supportsParameters();
42 auto mdp = parametricModel->template as<SparseModelType>();
43 result &=
static_cast<bool>(mdp);
56template<
typename SparseModelType,
typename ConstantType>
58 std::shared_ptr<storm::models::ModelBase> parametricModel,
60 std::optional<RegionSplitEstimateKind> generateRegionSplitEstimates,
62 bool allowModelSimplifications,
bool graphPreserving) {
63 STORM_LOG_THROW(this->canHandle(parametricModel, checkTask), storm::exceptions::NotSupportedException,
64 "Combination of model " << parametricModel->getType() <<
" and formula '" << checkTask.
getFormula() <<
"' is not supported.");
65 STORM_LOG_THROW(graphPreserving, storm::exceptions::NotImplementedException,
"Non-graph-preserving regions not implemented for MDPs");
66 this->specifySplitEstimates(generateRegionSplitEstimates, checkTask);
67 this->specifyMonotonicity(monotonicityBackend, checkTask);
68 auto mdp = parametricModel->template as<SparseModelType>();
71 if (allowModelSimplifications) {
73 if (!simplifier.simplify(checkTask.
getFormula())) {
74 STORM_LOG_THROW(
false, storm::exceptions::UnexpectedException,
"Simplifying the model was not successfull.");
76 this->parametricModel = simplifier.getSimplifiedModel();
77 this->specifyFormula(env, checkTask.
substituteFormula(*simplifier.getSimplifiedFormula()));
79 this->parametricModel = mdp;
80 this->specifyFormula(env, checkTask);
83 std::shared_ptr<storm::logic::Formula> formulaWithoutBounds = this->currentCheckTask->getFormula().clone();
84 formulaWithoutBounds->asOperatorFormula().removeBound();
85 this->currentFormulaNoBound = formulaWithoutBounds->asSharedPointer();
86 this->currentCheckTaskNoBound = std::make_unique<storm::modelchecker::CheckTask<storm::logic::Formula, ParametricType>>(*this->currentFormulaNoBound);
89template<
typename SparseModelType,
typename ConstantType>
93 STORM_LOG_THROW(!checkTask.
getFormula().hasLowerBound(), storm::exceptions::NotSupportedException,
"Lower step bounds are not supported.");
94 STORM_LOG_THROW(checkTask.
getFormula().hasUpperBound(), storm::exceptions::NotSupportedException,
"Expected a bounded until formula with an upper bound.");
96 "Expected a bounded until formula with step bounds.");
97 stepBound = checkTask.
getFormula().getUpperBound().evaluateAsInt();
98 STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException,
99 "Can not apply parameter lifting on step bounded formula: The step bound has to be positive.");
100 if (checkTask.
getFormula().isUpperBoundStrict()) {
101 STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException,
"Expected a strict upper step bound that is greater than zero.");
104 STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException,
105 "Can not apply parameter lifting on step bounded formula: The step bound has to be positive.");
111 storm::exceptions::NotSupportedException,
"Parameter lifting with non-propositional subformulas is not supported");
113 std::move(propositionalChecker.
check(checkTask.
getFormula().getLeftSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector());
115 std::move(propositionalChecker.
check(checkTask.
getFormula().getRightSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector());
120 this->parametricModel->getTransitionMatrix().getRowGroupIndices(),
121 this->parametricModel->getBackwardTransitions(), phiStates, psiStates,
true, *stepBound)
123 maybeStates &= ~psiStates;
126 resultsForNonMaybeStates = std::vector<ConstantType>(this->parametricModel->getNumberOfStates(), storm::utility::zero<ConstantType>());
130 if (!maybeStates.empty()) {
132 std::vector<ParametricType> b = this->parametricModel->getTransitionMatrix().getConstrainedRowSumVector(
135 parameterLifter = std::make_unique<storm::transformer::ParameterLifter<ParametricType, ConstantType>>(
136 this->parametricModel->getTransitionMatrix(), b, this->parametricModel->getTransitionMatrix().getRowFilter(maybeStates), maybeStates);
137 computePlayer1Matrix();
139 applyPreviousResultAsHint =
false;
143 lowerResultBound = storm::utility::zero<ConstantType>();
144 upperResultBound = storm::utility::one<ConstantType>();
147template<
typename SparseModelType,
typename ConstantType>
154 storm::exceptions::NotSupportedException,
"Parameter lifting with non-propositional subformulas is not supported");
156 std::move(propositionalChecker.
check(checkTask.
getFormula().getLeftSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector());
158 std::move(propositionalChecker.
check(checkTask.
getFormula().getRightSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector());
161 std::pair<storm::storage::BitVector, storm::storage::BitVector> statesWithProbability01 =
164 this->parametricModel->getTransitionMatrix().getRowGroupIndices(),
165 this->parametricModel->getBackwardTransitions(), phiStates, psiStates)
167 this->parametricModel->getTransitionMatrix().getRowGroupIndices(),
168 this->parametricModel->getBackwardTransitions(), phiStates, psiStates);
169 maybeStates = ~(statesWithProbability01.first | statesWithProbability01.second);
172 resultsForNonMaybeStates = std::vector<ConstantType>(this->parametricModel->getNumberOfStates(), storm::utility::zero<ConstantType>());
176 if (!maybeStates.empty()) {
178 std::vector<ParametricType> b = this->parametricModel->getTransitionMatrix().getConstrainedRowSumVector(
179 storm::storage::BitVector(this->parametricModel->getTransitionMatrix().getRowCount(),
true), statesWithProbability01.second);
181 parameterLifter = std::make_unique<storm::transformer::ParameterLifter<ParametricType, ConstantType>>(
182 this->parametricModel->getTransitionMatrix(), b, this->parametricModel->getTransitionMatrix().getRowFilter(maybeStates), maybeStates);
183 computePlayer1Matrix();
186 applyPreviousResultAsHint =
189 this->parametricModel->getTransitionMatrix().getRowGroupIndices(),
190 this->parametricModel->getBackwardTransitions(), maybeStates, ~maybeStates)
195 lowerResultBound = storm::utility::zero<ConstantType>();
196 upperResultBound = storm::utility::one<ConstantType>();
199template<
typename SparseModelType,
typename ConstantType>
205 "Parameter lifting with non-propositional subformulas is not supported");
207 std::move(propositionalChecker.
check(checkTask.
getFormula().getSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector());
213 this->parametricModel->getTransitionMatrix(), this->parametricModel->getTransitionMatrix().getRowGroupIndices(),
214 this->parametricModel->getBackwardTransitions(),
storm::storage::BitVector(this->parametricModel->getNumberOfStates(),
true), targetStates)
216 this->parametricModel->getTransitionMatrix(), this->parametricModel->getTransitionMatrix().getRowGroupIndices(),
217 this->parametricModel->getBackwardTransitions(),
storm::storage::BitVector(this->parametricModel->getNumberOfStates(),
true), targetStates);
219 maybeStates = ~(targetStates | infinityStates);
222 resultsForNonMaybeStates = std::vector<ConstantType>(this->parametricModel->getNumberOfStates(), storm::utility::zero<ConstantType>());
226 if (!maybeStates.empty()) {
229 (!checkTask.
isRewardModelSet() && this->parametricModel->hasUniqueRewardModel()),
230 storm::exceptions::InvalidPropertyException,
"The reward model specified by the CheckTask is not available in the given model.");
232 typename SparseModelType::RewardModelType
const& rewardModel =
235 std::vector<ParametricType> b = rewardModel.getTotalRewardVector(this->parametricModel->getTransitionMatrix());
240 storm::storage::BitVector selectedRows = this->parametricModel->getTransitionMatrix().getRowFilter(maybeStates, ~infinityStates);
242 parameterLifter = std::make_unique<storm::transformer::ParameterLifter<ParametricType, ConstantType>>(this->parametricModel->getTransitionMatrix(), b,
243 selectedRows, maybeStates);
244 computePlayer1Matrix(selectedRows);
247 applyPreviousResultAsHint =
250 this->parametricModel->getTransitionMatrix().getRowGroupIndices(),
251 this->parametricModel->getBackwardTransitions(), maybeStates, ~maybeStates)
256 lowerResultBound = storm::utility::zero<ConstantType>();
259template<
typename SparseModelType,
typename ConstantType>
263 stepBound = checkTask.
getFormula().getBound().evaluateAsInt();
265 STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException,
"Expected a strict upper step bound that is greater than zero.");
268 STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException,
269 "Can not apply parameter lifting on step bounded formula: The step bound has to be positive.");
273 resultsForNonMaybeStates = std::vector<ConstantType>(this->parametricModel->getNumberOfStates());
277 (!checkTask.
isRewardModelSet() && this->parametricModel->hasUniqueRewardModel()),
278 storm::exceptions::InvalidPropertyException,
"The reward model specified by the CheckTask is not available in the given model.");
279 typename SparseModelType::RewardModelType
const& rewardModel =
281 std::vector<ParametricType> b = rewardModel.getTotalRewardVector(this->parametricModel->getTransitionMatrix());
283 parameterLifter = std::make_unique<storm::transformer::ParameterLifter<ParametricType, ConstantType>>(
284 this->parametricModel->getTransitionMatrix(), b,
storm::storage::BitVector(this->parametricModel->getTransitionMatrix().getRowCount(),
true),
286 computePlayer1Matrix();
288 applyPreviousResultAsHint =
false;
291 lowerResultBound = storm::utility::zero<ConstantType>();
294template<
typename SparseModelType,
typename ConstantType>
297 if (!instantiationChecker) {
298 instantiationChecker = std::make_unique<storm::modelchecker::SparseMdpInstantiationModelChecker<SparseModelType, ConstantType>>(*this->parametricModel);
299 instantiationChecker->
specifyFormula(quantitative ? *this->currentCheckTaskNoBound
300 : this->currentCheckTask->template convertValueType<ParametricType>());
301 instantiationChecker->setInstantiationsAreGraphPreserving(
true);
303 return *instantiationChecker;
306template<
typename SparseModelType,
typename ConstantType>
313template<
typename SparseModelType,
typename ConstantType>
316 if (maybeStates.empty()) {
317 this->updateKnownValueBoundInRegion(region, dirForParameters, resultsForNonMaybeStates);
318 return resultsForNonMaybeStates;
321 parameterLifter->specifyRegion(region.
region, dirForParameters);
324 auto solver = solverFactory->create(env, player1Matrix, parameterLifter->getMatrix());
325 if (lowerResultBound)
326 solver->setLowerBound(lowerResultBound.value());
327 if (upperResultBound)
328 solver->setUpperBound(upperResultBound.value());
329 if (applyPreviousResultAsHint) {
330 solver->setTrackSchedulers(
true);
331 x.resize(maybeStates.getNumberOfSetBits(), storm::utility::zero<ConstantType>());
333 solver->setSchedulerHints(std::move(player1SchedChoices.value()), std::move(minSchedChoices.value()));
335 solver->setSchedulerHints(std::move(player1SchedChoices.value()), std::move(maxSchedChoices.value()));
337 x.assign(maybeStates.getNumberOfSetBits(), storm::utility::zero<ConstantType>());
339 if (this->currentCheckTask->isBoundSet() && this->currentCheckTask->getOptimizationDirection() == dirForParameters && solver->hasSchedulerHints()) {
341 std::unique_ptr<storm::solver::TerminationCondition<ConstantType>> termCond;
343 ? this->parametricModel->getInitialStates() % maybeStates
347 termCond = std::make_unique<storm::solver::TerminateIfFilteredExtremumBelowThreshold<ConstantType>>(
348 relevantStatesInSubsystem,
true, this->currentCheckTask->getBoundThreshold(),
false);
351 termCond = std::make_unique<storm::solver::TerminateIfFilteredExtremumExceedsThreshold<ConstantType>>(
352 relevantStatesInSubsystem,
true, this->currentCheckTask->getBoundThreshold(),
true);
354 solver->setTerminationCondition(std::move(termCond));
360 solver->repeatedMultiply(env, this->currentCheckTask->getOptimizationDirection(), dirForParameters, x, ¶meterLifter->getVector(), *stepBound);
362 solver->solveGame(env, this->currentCheckTask->getOptimizationDirection(), dirForParameters, x, parameterLifter->getVector());
363 if (applyPreviousResultAsHint) {
365 minSchedChoices = solver->getPlayer2SchedulerChoices();
367 maxSchedChoices = solver->getPlayer2SchedulerChoices();
369 player1SchedChoices = solver->getPlayer1SchedulerChoices();
374 std::vector<ConstantType> result = resultsForNonMaybeStates;
375 auto maybeStateResIt = x.begin();
376 for (
auto const& maybeState : maybeStates) {
377 result[maybeState] = *maybeStateResIt;
380 this->updateKnownValueBoundInRegion(region, dirForParameters, result);
384template<
typename SparseModelType,
typename ConstantType>
389 n = selectedRows->getNumberOfSetBits();
391 for (
auto const& maybeState : maybeStates) {
392 n += this->parametricModel->getTransitionMatrix().getRowGroupSize(maybeState);
398 uint64_t p1MatrixRow = 0;
399 for (
auto maybeState : maybeStates) {
400 matrixBuilder.newRowGroup(p1MatrixRow);
402 for (uint64_t row = selectedRows->getNextSetIndex(this->parametricModel->getTransitionMatrix().getRowGroupIndices()[maybeState]);
403 row < this->parametricModel->getTransitionMatrix().getRowGroupIndices()[maybeState + 1]; row = selectedRows->getNextSetIndex(row + 1)) {
404 matrixBuilder.addNextValue(p1MatrixRow, p1MatrixRow, storm::utility::one<storm::storage::sparse::state_type>());
408 for (uint64_t endOfGroup = p1MatrixRow + this->parametricModel->getTransitionMatrix().getRowGroupSize(maybeState); p1MatrixRow < endOfGroup;
410 matrixBuilder.addNextValue(p1MatrixRow, p1MatrixRow, storm::utility::one<storm::storage::sparse::state_type>());
414 player1Matrix = matrixBuilder.build();
417template<
typename SparseModelType,
typename ConstantType>
419 maybeStates.resize(0);
420 resultsForNonMaybeStates.clear();
421 stepBound = std::nullopt;
422 instantiationChecker =
nullptr;
424 parameterLifter =
nullptr;
425 minSchedChoices = std::nullopt;
426 maxSchedChoices = std::nullopt;
428 lowerResultBound = std::nullopt;
429 upperResultBound = std::nullopt;
430 applyPreviousResultAsHint =
false;
433template<
typename ConstantType>
434std::optional<storm::storage::Scheduler<ConstantType>>
getSchedulerHelper(std::optional<std::vector<uint64_t>>
const& choices) {
435 std::optional<storm::storage::Scheduler<ConstantType>> result;
437 result.emplace(choices->size());
439 for (
auto const& choice : choices.value()) {
440 result->setChoice(choice, state);
447template<
typename SparseModelType,
typename ConstantType>
449 return getSchedulerHelper<ConstantType>(minSchedChoices);
452template<
typename SparseModelType,
typename ConstantType>
454 return getSchedulerHelper<ConstantType>(maxSchedChoices);
457template<
typename SparseModelType,
typename ConstantType>
459 return getSchedulerHelper<ConstantType>(player1SchedChoices);
FragmentSpecification & setStepBoundedUntilFormulasAllowed(bool newValue)
FragmentSpecification & setTimeBoundedUntilFormulasAllowed(bool newValue)
FragmentSpecification & setCumulativeRewardFormulasAllowed(bool newValue)
FragmentSpecification & setReachabilityRewardFormulasAllowed(bool newValue)
FragmentSpecification & setRewardOperatorsAllowed(bool newValue)
FragmentSpecification & setBoundedUntilFormulasAllowed(bool newValue)
FragmentSpecification & setTimeBoundedCumulativeRewardFormulasAllowed(bool newValue)
FragmentSpecification & setStepBoundedCumulativeRewardFormulasAllowed(bool newValue)
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...
Class to efficiently check a formula on a parametric model with different parameter instantiations.
void specifyFormula(CheckTask< storm::logic::Formula, typename SparseModelType::ValueType > const &checkTask)
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
virtual bool canHandle(CheckTask< storm::logic::Formula, SolutionType > const &checkTask) const override
Determines whether the model checker can handle the given verification task.
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 can be used to build a sparse matrix by adding value by value.
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.
Region const region
The subregions of this region.