22template<
typename SparseModelType,
typename ConstantType>
28template<
typename SparseModelType,
typename ConstantType>
31 : solverFactory(
std::move(solverFactory)) {
35template<
typename SparseModelType,
typename ConstantType>
39 result &= parametricModel->isSparseModel();
40 result &= parametricModel->supportsParameters();
41 auto mdp = parametricModel->template as<SparseModelType>();
42 result &=
static_cast<bool>(mdp);
55template<
typename SparseModelType,
typename ConstantType>
57 std::shared_ptr<storm::models::ModelBase> parametricModel,
59 std::optional<RegionSplitEstimateKind> generateRegionSplitEstimates,
61 bool allowModelSimplifications,
bool graphPreserving) {
62 STORM_LOG_THROW(this->canHandle(parametricModel, checkTask), storm::exceptions::NotSupportedException,
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");
65 this->specifySplitEstimates(generateRegionSplitEstimates, checkTask);
66 this->specifyMonotonicity(monotonicityBackend, checkTask);
67 auto mdp = parametricModel->template as<SparseModelType>();
70 if (allowModelSimplifications) {
72 if (!simplifier.simplify(checkTask.
getFormula())) {
73 STORM_LOG_THROW(
false, storm::exceptions::UnexpectedException,
"Simplifying the model was not successfull.");
75 this->parametricModel = simplifier.getSimplifiedModel();
76 this->specifyFormula(env, checkTask.
substituteFormula(*simplifier.getSimplifiedFormula()));
78 this->parametricModel = mdp;
79 this->specifyFormula(env, checkTask);
82 std::shared_ptr<storm::logic::Formula> formulaWithoutBounds = this->currentCheckTask->getFormula().clone();
83 formulaWithoutBounds->asOperatorFormula().removeBound();
84 this->currentFormulaNoBound = formulaWithoutBounds->asSharedPointer();
85 this->currentCheckTaskNoBound = std::make_unique<storm::modelchecker::CheckTask<storm::logic::Formula, ParametricType>>(*this->currentFormulaNoBound);
88template<
typename SparseModelType,
typename ConstantType>
92 STORM_LOG_THROW(!checkTask.
getFormula().hasLowerBound(), storm::exceptions::NotSupportedException,
"Lower step bounds are not supported.");
93 STORM_LOG_THROW(checkTask.
getFormula().hasUpperBound(), storm::exceptions::NotSupportedException,
"Expected a bounded until formula with an upper bound.");
95 "Expected a bounded until formula with step bounds.");
96 stepBound = checkTask.
getFormula().getUpperBound().evaluateAsInt();
97 STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException,
98 "Can not apply parameter lifting on step bounded formula: The step bound has to be positive.");
99 if (checkTask.
getFormula().isUpperBoundStrict()) {
100 STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException,
"Expected a strict upper step bound that is greater than zero.");
103 STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException,
104 "Can not apply parameter lifting on step bounded formula: The step bound has to be positive.");
110 storm::exceptions::NotSupportedException,
"Parameter lifting with non-propositional subformulas is not supported");
112 std::move(propositionalChecker.
check(checkTask.
getFormula().getLeftSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector());
114 std::move(propositionalChecker.
check(checkTask.
getFormula().getRightSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector());
119 this->parametricModel->getTransitionMatrix().getRowGroupIndices(),
120 this->parametricModel->getBackwardTransitions(), phiStates, psiStates,
true, *stepBound)
122 maybeStates &= ~psiStates;
125 resultsForNonMaybeStates = std::vector<ConstantType>(this->parametricModel->getNumberOfStates(), storm::utility::zero<ConstantType>());
129 if (!maybeStates.empty()) {
131 std::vector<ParametricType> b = this->parametricModel->getTransitionMatrix().getConstrainedRowSumVector(
134 parameterLifter = std::make_unique<storm::transformer::ParameterLifter<ParametricType, ConstantType>>(
135 this->parametricModel->getTransitionMatrix(), b, this->parametricModel->getTransitionMatrix().getRowFilter(maybeStates), maybeStates);
136 computePlayer1Matrix();
138 applyPreviousResultAsHint =
false;
142 lowerResultBound = storm::utility::zero<ConstantType>();
143 upperResultBound = storm::utility::one<ConstantType>();
146template<
typename SparseModelType,
typename ConstantType>
153 storm::exceptions::NotSupportedException,
"Parameter lifting with non-propositional subformulas is not supported");
155 std::move(propositionalChecker.
check(checkTask.
getFormula().getLeftSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector());
157 std::move(propositionalChecker.
check(checkTask.
getFormula().getRightSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector());
160 std::pair<storm::storage::BitVector, storm::storage::BitVector> statesWithProbability01 =
163 this->parametricModel->getTransitionMatrix().getRowGroupIndices(),
164 this->parametricModel->getBackwardTransitions(), phiStates, psiStates)
166 this->parametricModel->getTransitionMatrix().getRowGroupIndices(),
167 this->parametricModel->getBackwardTransitions(), phiStates, psiStates);
168 maybeStates = ~(statesWithProbability01.first | statesWithProbability01.second);
171 resultsForNonMaybeStates = std::vector<ConstantType>(this->parametricModel->getNumberOfStates(), storm::utility::zero<ConstantType>());
175 if (!maybeStates.empty()) {
177 std::vector<ParametricType> b = this->parametricModel->getTransitionMatrix().getConstrainedRowSumVector(
178 storm::storage::BitVector(this->parametricModel->getTransitionMatrix().getRowCount(),
true), statesWithProbability01.second);
180 parameterLifter = std::make_unique<storm::transformer::ParameterLifter<ParametricType, ConstantType>>(
181 this->parametricModel->getTransitionMatrix(), b, this->parametricModel->getTransitionMatrix().getRowFilter(maybeStates), maybeStates);
182 computePlayer1Matrix();
185 applyPreviousResultAsHint =
188 this->parametricModel->getTransitionMatrix().getRowGroupIndices(),
189 this->parametricModel->getBackwardTransitions(), maybeStates, ~maybeStates)
194 lowerResultBound = storm::utility::zero<ConstantType>();
195 upperResultBound = storm::utility::one<ConstantType>();
198template<
typename SparseModelType,
typename ConstantType>
204 "Parameter lifting with non-propositional subformulas is not supported");
206 std::move(propositionalChecker.
check(checkTask.
getFormula().getSubformula())->asExplicitQualitativeCheckResult().getTruthValuesVector());
212 this->parametricModel->getTransitionMatrix(), this->parametricModel->getTransitionMatrix().getRowGroupIndices(),
213 this->parametricModel->getBackwardTransitions(),
storm::storage::BitVector(this->parametricModel->getNumberOfStates(),
true), targetStates)
215 this->parametricModel->getTransitionMatrix(), this->parametricModel->getTransitionMatrix().getRowGroupIndices(),
216 this->parametricModel->getBackwardTransitions(),
storm::storage::BitVector(this->parametricModel->getNumberOfStates(),
true), targetStates);
218 maybeStates = ~(targetStates | infinityStates);
221 resultsForNonMaybeStates = std::vector<ConstantType>(this->parametricModel->getNumberOfStates(), storm::utility::zero<ConstantType>());
225 if (!maybeStates.empty()) {
228 (!checkTask.
isRewardModelSet() && this->parametricModel->hasUniqueRewardModel()),
229 storm::exceptions::InvalidPropertyException,
"The reward model specified by the CheckTask is not available in the given model.");
231 typename SparseModelType::RewardModelType
const& rewardModel =
234 std::vector<ParametricType> b = rewardModel.getTotalRewardVector(this->parametricModel->getTransitionMatrix());
239 storm::storage::BitVector selectedRows = this->parametricModel->getTransitionMatrix().getRowFilter(maybeStates, ~infinityStates);
241 parameterLifter = std::make_unique<storm::transformer::ParameterLifter<ParametricType, ConstantType>>(this->parametricModel->getTransitionMatrix(), b,
242 selectedRows, maybeStates);
243 computePlayer1Matrix(selectedRows);
246 applyPreviousResultAsHint =
249 this->parametricModel->getTransitionMatrix().getRowGroupIndices(),
250 this->parametricModel->getBackwardTransitions(), maybeStates, ~maybeStates)
255 lowerResultBound = storm::utility::zero<ConstantType>();
258template<
typename SparseModelType,
typename ConstantType>
262 stepBound = checkTask.
getFormula().getBound().evaluateAsInt();
264 STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException,
"Expected a strict upper step bound that is greater than zero.");
267 STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException,
268 "Can not apply parameter lifting on step bounded formula: The step bound has to be positive.");
272 resultsForNonMaybeStates = std::vector<ConstantType>(this->parametricModel->getNumberOfStates());
276 (!checkTask.
isRewardModelSet() && this->parametricModel->hasUniqueRewardModel()),
277 storm::exceptions::InvalidPropertyException,
"The reward model specified by the CheckTask is not available in the given model.");
278 typename SparseModelType::RewardModelType
const& rewardModel =
280 std::vector<ParametricType> b = rewardModel.getTotalRewardVector(this->parametricModel->getTransitionMatrix());
282 parameterLifter = std::make_unique<storm::transformer::ParameterLifter<ParametricType, ConstantType>>(
283 this->parametricModel->getTransitionMatrix(), b,
storm::storage::BitVector(this->parametricModel->getTransitionMatrix().getRowCount(),
true),
285 computePlayer1Matrix();
287 applyPreviousResultAsHint =
false;
290 lowerResultBound = storm::utility::zero<ConstantType>();
293template<
typename SparseModelType,
typename ConstantType>
296 if (!instantiationChecker) {
297 instantiationChecker = std::make_unique<storm::modelchecker::SparseMdpInstantiationModelChecker<SparseModelType, ConstantType>>(*this->parametricModel);
298 instantiationChecker->
specifyFormula(quantitative ? *this->currentCheckTaskNoBound
299 : this->currentCheckTask->template convertValueType<ParametricType>());
300 instantiationChecker->setInstantiationsAreGraphPreserving(
true);
302 return *instantiationChecker;
305template<
typename SparseModelType,
typename ConstantType>
312template<
typename SparseModelType,
typename ConstantType>
315 if (maybeStates.empty()) {
316 this->updateKnownValueBoundInRegion(region, dirForParameters, resultsForNonMaybeStates);
317 return resultsForNonMaybeStates;
320 parameterLifter->specifyRegion(region.
region, dirForParameters);
323 auto solver = solverFactory->create(env, player1Matrix, parameterLifter->getMatrix());
324 if (lowerResultBound)
325 solver->setLowerBound(lowerResultBound.value());
326 if (upperResultBound)
327 solver->setUpperBound(upperResultBound.value());
328 if (applyPreviousResultAsHint) {
329 solver->setTrackSchedulers(
true);
330 x.resize(maybeStates.getNumberOfSetBits(), storm::utility::zero<ConstantType>());
332 solver->setSchedulerHints(std::move(player1SchedChoices.value()), std::move(minSchedChoices.value()));
334 solver->setSchedulerHints(std::move(player1SchedChoices.value()), std::move(maxSchedChoices.value()));
336 x.assign(maybeStates.getNumberOfSetBits(), storm::utility::zero<ConstantType>());
338 if (this->currentCheckTask->isBoundSet() && this->currentCheckTask->getOptimizationDirection() == dirForParameters && solver->hasSchedulerHints()) {
340 std::unique_ptr<storm::solver::TerminationCondition<ConstantType>> termCond;
342 ? this->parametricModel->getInitialStates() % maybeStates
346 termCond = std::make_unique<storm::solver::TerminateIfFilteredExtremumBelowThreshold<ConstantType>>(
347 relevantStatesInSubsystem,
true, this->currentCheckTask->getBoundThreshold(),
false);
350 termCond = std::make_unique<storm::solver::TerminateIfFilteredExtremumExceedsThreshold<ConstantType>>(
351 relevantStatesInSubsystem,
true, this->currentCheckTask->getBoundThreshold(),
true);
353 solver->setTerminationCondition(std::move(termCond));
359 solver->repeatedMultiply(env, this->currentCheckTask->getOptimizationDirection(), dirForParameters, x, ¶meterLifter->getVector(), *stepBound);
361 solver->solveGame(env, this->currentCheckTask->getOptimizationDirection(), dirForParameters, x, parameterLifter->getVector());
362 if (applyPreviousResultAsHint) {
364 minSchedChoices = solver->getPlayer2SchedulerChoices();
366 maxSchedChoices = solver->getPlayer2SchedulerChoices();
368 player1SchedChoices = solver->getPlayer1SchedulerChoices();
373 std::vector<ConstantType> result = resultsForNonMaybeStates;
374 auto maybeStateResIt = x.begin();
375 for (
auto const& maybeState : maybeStates) {
376 result[maybeState] = *maybeStateResIt;
379 this->updateKnownValueBoundInRegion(region, dirForParameters, result);
383template<
typename SparseModelType,
typename ConstantType>
388 n = selectedRows->getNumberOfSetBits();
390 for (
auto const& maybeState : maybeStates) {
391 n += this->parametricModel->getTransitionMatrix().getRowGroupSize(maybeState);
397 uint64_t p1MatrixRow = 0;
398 for (
auto maybeState : maybeStates) {
399 matrixBuilder.newRowGroup(p1MatrixRow);
401 for (uint64_t row = selectedRows->getNextSetIndex(this->parametricModel->getTransitionMatrix().getRowGroupIndices()[maybeState]);
402 row < this->parametricModel->getTransitionMatrix().getRowGroupIndices()[maybeState + 1]; row = selectedRows->getNextSetIndex(row + 1)) {
403 matrixBuilder.addNextValue(p1MatrixRow, p1MatrixRow, storm::utility::one<storm::storage::sparse::state_type>());
407 for (uint64_t endOfGroup = p1MatrixRow + this->parametricModel->getTransitionMatrix().getRowGroupSize(maybeState); p1MatrixRow < endOfGroup;
409 matrixBuilder.addNextValue(p1MatrixRow, p1MatrixRow, storm::utility::one<storm::storage::sparse::state_type>());
413 player1Matrix = matrixBuilder.build();
416template<
typename SparseModelType,
typename ConstantType>
418 maybeStates.resize(0);
419 resultsForNonMaybeStates.clear();
420 stepBound = std::nullopt;
421 instantiationChecker =
nullptr;
423 parameterLifter =
nullptr;
424 minSchedChoices = std::nullopt;
425 maxSchedChoices = std::nullopt;
427 lowerResultBound = std::nullopt;
428 upperResultBound = std::nullopt;
429 applyPreviousResultAsHint =
false;
432template<
typename ConstantType>
433std::optional<storm::storage::Scheduler<ConstantType>>
getSchedulerHelper(std::optional<std::vector<uint64_t>>
const& choices) {
434 std::optional<storm::storage::Scheduler<ConstantType>> result;
436 result.emplace(choices->size());
438 for (
auto const& choice : choices.value()) {
439 result->setChoice(choice, state);
446template<
typename SparseModelType,
typename ConstantType>
448 return getSchedulerHelper<ConstantType>(minSchedChoices);
451template<
typename SparseModelType,
typename ConstantType>
453 return getSchedulerHelper<ConstantType>(maxSchedChoices);
456template<
typename SparseModelType,
typename ConstantType>
458 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.