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 if (!simplifier.simplify(checkTask.
getFormula())) {
73 STORM_LOG_THROW(
false, storm::exceptions::UnexpectedException,
"Simplifying the model was not successfull.");
75 this->parametricModel = simplifier.getSimplifiedModel();
78 this->parametricModel = mdp;
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 ->template asExplicitQualitativeCheckResult<typename SparseModelType::ValueType>()
113 .getTruthValuesVector());
115 ->template asExplicitQualitativeCheckResult<typename SparseModelType::ValueType>()
116 .getTruthValuesVector());
121 this->parametricModel->getTransitionMatrix().getRowGroupIndices(),
122 this->parametricModel->getBackwardTransitions(), phiStates, psiStates,
true, *stepBound)
124 maybeStates &= ~psiStates;
131 if (!maybeStates.empty()) {
133 std::vector<ParametricType> b = this->
parametricModel->getTransitionMatrix().getConstrainedRowSumVector(
136 parameterLifter = std::make_unique<storm::transformer::ParameterLifter<ParametricType, ConstantType>>(
138 computePlayer1Matrix();
140 applyPreviousResultAsHint =
false;
148template<
typename SparseModelType,
typename ConstantType>
155 storm::exceptions::NotSupportedException,
"Parameter lifting with non-propositional subformulas is not supported");
157 ->template asExplicitQualitativeCheckResult<typename SparseModelType::ValueType>()
158 .getTruthValuesVector());
160 ->template asExplicitQualitativeCheckResult<typename SparseModelType::ValueType>()
161 .getTruthValuesVector());
164 std::pair<storm::storage::BitVector, storm::storage::BitVector> statesWithProbability01 =
167 this->parametricModel->getTransitionMatrix().getRowGroupIndices(),
168 this->parametricModel->getBackwardTransitions(), phiStates, psiStates)
170 this->parametricModel->getTransitionMatrix().getRowGroupIndices(),
171 this->parametricModel->getBackwardTransitions(), phiStates, psiStates);
172 maybeStates = ~(statesWithProbability01.first | statesWithProbability01.second);
179 if (!maybeStates.empty()) {
181 std::vector<ParametricType> b = this->
parametricModel->getTransitionMatrix().getConstrainedRowSumVector(
184 parameterLifter = std::make_unique<storm::transformer::ParameterLifter<ParametricType, ConstantType>>(
186 computePlayer1Matrix();
189 applyPreviousResultAsHint =
192 this->parametricModel->getTransitionMatrix().getRowGroupIndices(),
193 this->parametricModel->getBackwardTransitions(), maybeStates, ~maybeStates)
202template<
typename SparseModelType,
typename ConstantType>
208 "Parameter lifting with non-propositional subformulas is not supported");
210 ->template asExplicitQualitativeCheckResult<typename SparseModelType::ValueType>()
211 .getTruthValuesVector());
217 this->
parametricModel->getTransitionMatrix(), this->parametricModel->getTransitionMatrix().getRowGroupIndices(),
218 this->parametricModel->getBackwardTransitions(),
storm::storage::BitVector(this->parametricModel->getNumberOfStates(),
true), targetStates)
220 this->
parametricModel->getTransitionMatrix(), this->parametricModel->getTransitionMatrix().getRowGroupIndices(),
221 this->parametricModel->getBackwardTransitions(),
storm::storage::BitVector(this->parametricModel->getNumberOfStates(),
true), targetStates);
223 maybeStates = ~(targetStates | infinityStates);
230 if (!maybeStates.empty()) {
233 (!checkTask.
isRewardModelSet() && this->parametricModel->hasUniqueRewardModel()),
234 storm::exceptions::InvalidPropertyException,
"The reward model specified by the CheckTask is not available in the given model.");
236 typename SparseModelType::RewardModelType
const& rewardModel =
239 std::vector<ParametricType> b = rewardModel.getTotalRewardVector(this->
parametricModel->getTransitionMatrix());
246 parameterLifter = std::make_unique<storm::transformer::ParameterLifter<ParametricType, ConstantType>>(this->
parametricModel->getTransitionMatrix(), b,
247 selectedRows, maybeStates);
248 computePlayer1Matrix(selectedRows);
251 applyPreviousResultAsHint =
254 this->parametricModel->getTransitionMatrix().getRowGroupIndices(),
255 this->parametricModel->getBackwardTransitions(), maybeStates, ~maybeStates)
263template<
typename SparseModelType,
typename ConstantType>
267 stepBound = checkTask.
getFormula().getBound().evaluateAsInt();
269 STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException,
"Expected a strict upper step bound that is greater than zero.");
272 STORM_LOG_THROW(*stepBound > 0, storm::exceptions::NotSupportedException,
273 "Can not apply parameter lifting on step bounded formula: The step bound has to be positive.");
277 resultsForNonMaybeStates = std::vector<ConstantType>(this->
parametricModel->getNumberOfStates());
281 (!checkTask.
isRewardModelSet() && this->parametricModel->hasUniqueRewardModel()),
282 storm::exceptions::InvalidPropertyException,
"The reward model specified by the CheckTask is not available in the given model.");
283 typename SparseModelType::RewardModelType
const& rewardModel =
285 std::vector<ParametricType> b = rewardModel.getTotalRewardVector(this->
parametricModel->getTransitionMatrix());
287 parameterLifter = std::make_unique<storm::transformer::ParameterLifter<ParametricType, ConstantType>>(
290 computePlayer1Matrix();
292 applyPreviousResultAsHint =
false;
298template<
typename SparseModelType,
typename ConstantType>
301 if (!instantiationChecker) {
302 instantiationChecker = std::make_unique<storm::modelchecker::SparseMdpInstantiationModelChecker<SparseModelType, ConstantType>>(*this->
parametricModel);
303 instantiationChecker->specifyFormula(quantitative ? *this->currentCheckTaskNoBound
305 instantiationChecker->setInstantiationsAreGraphPreserving(
true);
307 return *instantiationChecker;
310template<
typename SparseModelType,
typename ConstantType>
317template<
typename SparseModelType,
typename ConstantType>
320 if (maybeStates.empty()) {
322 return resultsForNonMaybeStates;
325 parameterLifter->specifyRegion(
region.region, dirForParameters);
328 auto solver = solverFactory->create(env, player1Matrix, parameterLifter->getMatrix());
329 if (lowerResultBound)
330 solver->setLowerBound(lowerResultBound.value());
331 if (upperResultBound)
332 solver->setUpperBound(upperResultBound.value());
333 if (applyPreviousResultAsHint) {
334 solver->setTrackSchedulers(
true);
337 solver->setSchedulerHints(std::move(player1SchedChoices.value()), std::move(minSchedChoices.value()));
339 solver->setSchedulerHints(std::move(player1SchedChoices.value()), std::move(maxSchedChoices.value()));
343 if (this->
currentCheckTask->isBoundSet() && this->currentCheckTask->getOptimizationDirection() == dirForParameters &&
solver->hasSchedulerHints()) {
345 std::unique_ptr<storm::solver::TerminationCondition<ConstantType>> termCond;
351 termCond = std::make_unique<storm::solver::TerminateIfFilteredExtremumBelowThreshold<ConstantType>>(
352 relevantStatesInSubsystem,
true, this->
currentCheckTask->getBoundThreshold(),
false);
355 termCond = std::make_unique<storm::solver::TerminateIfFilteredExtremumExceedsThreshold<ConstantType>>(
356 relevantStatesInSubsystem,
true, this->
currentCheckTask->getBoundThreshold(),
true);
358 solver->setTerminationCondition(std::move(termCond));
364 solver->repeatedMultiply(env, this->
currentCheckTask->getOptimizationDirection(), dirForParameters, x, ¶meterLifter->getVector(), *stepBound);
366 solver->solveGame(env, this->
currentCheckTask->getOptimizationDirection(), dirForParameters, x, parameterLifter->getVector());
367 if (applyPreviousResultAsHint) {
369 minSchedChoices =
solver->getPlayer2SchedulerChoices();
371 maxSchedChoices =
solver->getPlayer2SchedulerChoices();
373 player1SchedChoices =
solver->getPlayer1SchedulerChoices();
378 std::vector<ConstantType> result = resultsForNonMaybeStates;
379 auto maybeStateResIt = x.begin();
380 for (
auto const& maybeState : maybeStates) {
381 result[maybeState] = *maybeStateResIt;
388template<
typename SparseModelType,
typename ConstantType>
389void SparseMdpParameterLiftingModelChecker<SparseModelType, ConstantType>::computePlayer1Matrix(std::optional<storm::storage::BitVector>
const& selectedRows) {
393 n = selectedRows->getNumberOfSetBits();
395 for (
auto const& maybeState : maybeStates) {
396 n += this->parametricModel->getTransitionMatrix().getRowGroupSize(maybeState);
401 storm::storage::SparseMatrixBuilder<storm::storage::sparse::state_type> matrixBuilder(n, n, n,
true,
true, maybeStates.getNumberOfSetBits());
402 uint64_t p1MatrixRow = 0;
403 for (
auto maybeState : maybeStates) {
404 matrixBuilder.newRowGroup(p1MatrixRow);
406 for (uint64_t row = selectedRows->getNextSetIndex(this->parametricModel->getTransitionMatrix().getRowGroupIndices()[maybeState]);
407 row < this->parametricModel->getTransitionMatrix().getRowGroupIndices()[maybeState + 1]; row = selectedRows->getNextSetIndex(row + 1)) {
412 for (uint64_t endOfGroup = p1MatrixRow + this->parametricModel->getTransitionMatrix().getRowGroupSize(maybeState); p1MatrixRow < endOfGroup;
418 player1Matrix = matrixBuilder.build();
421template<
typename SparseModelType,
typename ConstantType>
423 maybeStates.resize(0);
424 resultsForNonMaybeStates.clear();
425 stepBound = std::nullopt;
426 instantiationChecker =
nullptr;
428 parameterLifter =
nullptr;
429 minSchedChoices = std::nullopt;
430 maxSchedChoices = std::nullopt;
432 lowerResultBound = std::nullopt;
433 upperResultBound = std::nullopt;
434 applyPreviousResultAsHint =
false;
437template<
typename ConstantType>
438std::optional<storm::storage::Scheduler<ConstantType>>
getSchedulerHelper(std::optional<std::vector<uint64_t>>
const& choices) {
439 std::optional<storm::storage::Scheduler<ConstantType>> result;
441 result.emplace(choices->size());
443 for (
auto const& choice : choices.value()) {
444 result->setChoice(choice, state);
451template<
typename SparseModelType,
typename ConstantType>
456template<
typename SparseModelType,
typename ConstantType>
461template<
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.