Storm 1.14.0.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
AbstractAbstractionRefinementModelChecker.cpp
Go to the documentation of this file.
2
29#include "storm/utility/graph.h"
31
32namespace storm::gbar {
33namespace modelchecker {
34
35template<typename ModelType>
37 : storm::modelchecker::AbstractModelChecker<ModelType>(), checkTask(nullptr), precision(options.precision) {
38 reuseQualitativeResults = options.reuseMode == abstraction::ReuseMode::All || options.reuseMode == abstraction::ReuseMode::Qualitative;
39 reuseQuantitativeResults = options.reuseMode == abstraction::ReuseMode::All || options.reuseMode == abstraction::ReuseMode::Quantitative;
40}
41
42template<typename ModelType>
46
47template<typename ModelType>
49 storm::logic::Formula const& formula = checkTask.getFormula();
50 bool enableRewards = this->supportsReachabilityRewards();
53 return formula.isInFragment(fragment) && checkTask.isOnlyInitialStatesRelevantSet();
54}
55
56template<typename ModelType>
60
61template<typename ModelType>
64 this->setCheckTask(checkTask.template substituteFormula<storm::logic::Formula>(checkTask.getFormula()));
66}
67
68template<typename ModelType>
71 STORM_LOG_THROW(this->supportsReachabilityRewards(), storm::exceptions::NotSupportedException,
72 "Reachability rewards are not supported by this abstraction-refinement model checker.");
73 this->setCheckTask(checkTask.template substituteFormula<storm::logic::Formula>(checkTask.getFormula()));
75}
76
77template<typename ModelType>
80 this->setCheckTask(checkTask.template substituteFormula<storm::logic::Formula>(checkTask.getFormula()));
82}
83
84template<typename ModelType>
86 this->checkTask = std::make_unique<storm::modelchecker::CheckTask<storm::logic::Formula, ValueType>>(checkTask);
87}
88
89template<typename ModelType>
94
95template<typename ModelType>
99
100template<typename ModelType>
102 return reuseQuantitativeResults;
103}
104
105template<typename ModelType>
106std::unique_ptr<storm::modelchecker::CheckResult> AbstractAbstractionRefinementModelChecker<ModelType>::performAbstractionRefinement(Environment const& env) {
107 STORM_LOG_THROW(checkTask->isOnlyInitialStatesRelevantSet(), storm::exceptions::InvalidPropertyException,
108 "The abstraction-refinement model checkers can only compute the result for the initial states.");
109
110 // Notify the underlying implementation that the abstraction-refinement process is being started.
112
113 uint64_t iterations = 0;
114 std::unique_ptr<storm::modelchecker::CheckResult> result;
115 auto start = std::chrono::high_resolution_clock::now();
116 while (!result) {
117 ++iterations;
118
119 // Obtain the abstract model.
120 auto abstractionStart = std::chrono::high_resolution_clock::now();
121 std::shared_ptr<storm::models::Model<ValueType>> abstractModel = this->getAbstractModel();
122 auto abstractionEnd = std::chrono::high_resolution_clock::now();
123 STORM_LOG_TRACE("Model in iteration " << iterations << " has " << abstractModel->getNumberOfStates() << " states and "
124 << abstractModel->getNumberOfTransitions() << " transitions (retrieved in "
125 << std::chrono::duration_cast<std::chrono::milliseconds>(abstractionEnd - abstractionStart).count() << "ms).");
126
127 // Obtain lower and upper bounds from the abstract model.
128 std::pair<std::unique_ptr<storm::modelchecker::CheckResult>, std::unique_ptr<storm::modelchecker::CheckResult>> bounds =
129 computeBounds(env, *abstractModel);
130
131 // Try to derive the final result from the obtained bounds.
132 if (bounds.first || bounds.second) {
133 result = tryToObtainResultFromBounds(*abstractModel, bounds);
134 }
135 if (!result) {
136 if (bounds.first && bounds.second) {
138 }
139
140 auto refinementStart = std::chrono::high_resolution_clock::now();
141 this->refineAbstractModel();
142 auto refinementEnd = std::chrono::high_resolution_clock::now();
143 STORM_LOG_TRACE("Refinement in iteration " << iterations << " completed in "
144 << std::chrono::duration_cast<std::chrono::milliseconds>(refinementEnd - refinementStart).count()
145 << "ms.");
146 }
147 }
148 auto end = std::chrono::high_resolution_clock::now();
149 STORM_LOG_TRACE("Completed abstraction-refinement (" << this->getName() << ") in "
150 << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() << "ms.");
151
152 return result;
153}
154
155template<typename ModelType>
156std::pair<std::unique_ptr<storm::modelchecker::CheckResult>, std::unique_ptr<storm::modelchecker::CheckResult>>
158 // We go through two phases. In phase (1) we are solving the qualitative part and in phase (2) the quantitative part.
159
160 std::pair<std::unique_ptr<storm::modelchecker::CheckResult>, std::unique_ptr<storm::modelchecker::CheckResult>> result;
161
162 // Preparation: determine the constraint states and the target states of the reachability objective.
163 std::pair<std::unique_ptr<storm::gbar::abstraction::StateSet>, std::unique_ptr<storm::gbar::abstraction::StateSet>> constraintAndTargetStates =
164 getConstraintAndTargetStates(abstractModel);
165
166 // Phase (1): solve qualitatively.
167 lastQualitativeResults = computeQualitativeResult(env, abstractModel, *constraintAndTargetStates.first, *constraintAndTargetStates.second);
168
169 // Check whether the answer can be given after the qualitative solution.
170 result.first = checkForResultAfterQualitativeCheck(abstractModel);
171 if (result.first) {
172 return result;
173 }
174
175 // Check whether we should skip the quantitative solution (for example if there are initial states for which
176 // the value is already known to be different at this point.
177 bool doSkipQuantitativeSolution = skipQuantitativeSolution(abstractModel, *lastQualitativeResults);
178 STORM_LOG_TRACE("" << (doSkipQuantitativeSolution ? "Skipping" : "Not skipping") << " quantitative solution.");
179
180 // Phase (2): solve quantitatively.
181 if (!doSkipQuantitativeSolution) {
182 lastBounds =
183 computeQuantitativeResult(env, abstractModel, *constraintAndTargetStates.first, *constraintAndTargetStates.second, *lastQualitativeResults);
184 STORM_LOG_ASSERT(lastBounds.first && lastBounds.second, "Expected both bounds.");
185
186 result = std::make_pair(lastBounds.first->clone(), lastBounds.second->clone());
187 filterInitialStates(abstractModel, result);
188
189 // Check whether the answer can be given after the quantitative solution.
190 if (checkForResultAfterQuantitativeCheck(abstractModel, true, result.first->asQuantitativeCheckResult<ValueType>())) {
191 result.second = nullptr;
192 } else if (checkForResultAfterQuantitativeCheck(abstractModel, false, result.second->asQuantitativeCheckResult<ValueType>())) {
193 result.first = nullptr;
194 }
195 }
196
197 return result;
198}
199
200template<typename ModelType>
202 storm::models::Model<ValueType> const& abstractModel, bool lowerBounds, storm::modelchecker::QuantitativeCheckResult<ValueType> const& quantitativeResult) {
203 bool result = false;
204 if (checkTask->isBoundSet()) {
205 storm::logic::ComparisonType comparisonType = checkTask->getBoundComparisonType();
206 ValueType threshold = checkTask->getBoundThreshold();
207
208 if (lowerBounds) {
209 if (storm::logic::isLowerBound(comparisonType)) {
210 ValueType minimalLowerBound = quantitativeResult.getMin();
211 result = (storm::logic::isStrict(comparisonType) && minimalLowerBound > threshold) ||
212 (!storm::logic::isStrict(comparisonType) && minimalLowerBound >= threshold);
213 } else {
214 ValueType maximalLowerBound = quantitativeResult.getMax();
215 result = (storm::logic::isStrict(comparisonType) && maximalLowerBound >= threshold) ||
216 (!storm::logic::isStrict(comparisonType) && maximalLowerBound > threshold);
217 }
218 } else {
219 if (storm::logic::isLowerBound(comparisonType)) {
220 ValueType minimalUpperBound = quantitativeResult.getMin();
221 result = (storm::logic::isStrict(comparisonType) && minimalUpperBound <= threshold) ||
222 (!storm::logic::isStrict(comparisonType) && minimalUpperBound < threshold);
223 } else {
224 ValueType maximalUpperBound = quantitativeResult.getMax();
225 result = (storm::logic::isStrict(comparisonType) && maximalUpperBound < threshold) ||
226 (!storm::logic::isStrict(comparisonType) && maximalUpperBound <= threshold);
227 }
228 }
229
230 if (result) {
231 STORM_LOG_TRACE("Found result after quantiative check.");
232 } else {
233 STORM_LOG_TRACE("Did not find result after quantiative check.");
234 }
235 }
236
237 return result;
238}
239
240template<typename ModelType>
242 std::pair<std::unique_ptr<storm::modelchecker::CheckResult>, std::unique_ptr<storm::modelchecker::CheckResult>>& bounds) {
243 STORM_LOG_THROW(bounds.first->isSymbolicQuantitativeCheckResult() && bounds.second->isSymbolicQuantitativeCheckResult(),
244 storm::exceptions::NotSupportedException, "Expected symbolic bounds.");
245
246 printBoundsInformation(bounds.first->asSymbolicQuantitativeCheckResult<DdType, ValueType>(),
247 bounds.second->asSymbolicQuantitativeCheckResult<DdType, ValueType>());
248}
249
250template<typename ModelType>
254 // If there is exactly one value that we stored, we print the current bounds as an interval.
255 if (lowerBounds.getStates().getNonZeroCount() == 1 && upperBounds.getStates().getNonZeroCount() == 1) {
256 STORM_LOG_TRACE("Obtained bounds [" << lowerBounds.getValueVector().getMax() << ", " << upperBounds.getValueVector().getMax() << "] on actual result.");
257 } else {
258 storm::dd::Add<DdType, ValueType> diffs = upperBounds.getValueVector() - lowerBounds.getValueVector();
260
261 std::pair<ValueType, ValueType> bounds;
262 bounds.first = (lowerBounds.getValueVector() * maxDiffRepresentative.template toAdd<ValueType>()).getMax();
263 bounds.second = (upperBounds.getValueVector() * maxDiffRepresentative.template toAdd<ValueType>()).getMax();
264
265 STORM_LOG_TRACE("Largest interval over initial is [" << bounds.first << ", " << bounds.second << "], difference " << (bounds.second - bounds.first)
266 << ".");
267 }
268}
269
270template<typename ModelType>
272 storm::models::Model<ValueType> const& abstractModel,
273 std::pair<std::unique_ptr<storm::modelchecker::CheckResult>, std::unique_ptr<storm::modelchecker::CheckResult>>& bounds) {
274 STORM_LOG_THROW(abstractModel.isSymbolicModel(), storm::exceptions::NotSupportedException, "Expected symbolic model.");
275
276 filterInitialStates(*abstractModel.template as<storm::models::symbolic::Model<DdType, ValueType>>(), bounds);
277}
278
279template<typename ModelType>
282 std::pair<std::unique_ptr<storm::modelchecker::CheckResult>, std::unique_ptr<storm::modelchecker::CheckResult>>& bounds) {
284 bounds.first->filter(initialStateFilter);
285 bounds.second->filter(initialStateFilter);
286}
287
288template<typename ModelType>
290 storm::models::Model<ValueType> const& abstractModel, storm::gbar::abstraction::QualitativeResultMinMax const& qualitativeResults) {
291 STORM_LOG_THROW(abstractModel.isSymbolicModel(), storm::exceptions::NotSupportedException, "Expected symbolic model.");
292
294 qualitativeResults.asSymbolicQualitativeResultMinMax<DdType>());
295}
296
297template<typename ModelType>
301 bool isRewardFormula =
302 checkTask->getFormula().isEventuallyFormula() && checkTask->getFormula().asEventuallyFormula().getContext() == storm::logic::FormulaContext::Reward;
303 if (isRewardFormula) {
304 if ((abstractModel.getInitialStates() && qualitativeResults.getProb1Min().getStates()) !=
305 (abstractModel.getInitialStates() && qualitativeResults.getProb1Max().getStates())) {
306 return true;
307 }
308 } else {
309 if ((abstractModel.getInitialStates() && qualitativeResults.getProb0Min().getStates()) !=
310 (abstractModel.getInitialStates() && qualitativeResults.getProb0Max().getStates())) {
311 return true;
312 } else if ((abstractModel.getInitialStates() && qualitativeResults.getProb1Min().getStates()) !=
313 (abstractModel.getInitialStates() && qualitativeResults.getProb1Max().getStates())) {
314 return true;
315 }
316 }
317 return false;
318}
319
320template<typename ModelType>
321std::pair<std::unique_ptr<storm::modelchecker::CheckResult>, std::unique_ptr<storm::modelchecker::CheckResult>>
323 storm::gbar::abstraction::StateSet const& constraintStates,
324 storm::gbar::abstraction::StateSet const& targetStates,
325 storm::gbar::abstraction::QualitativeResultMinMax const& qualitativeResults) {
326 STORM_LOG_ASSERT(abstractModel.isSymbolicModel(), "Expected symbolic abstract model.");
327
329 constraintStates.asSymbolicStateSet<DdType>(), targetStates.asSymbolicStateSet<DdType>(),
330 qualitativeResults.asSymbolicQualitativeResultMinMax<DdType>());
331}
332
333template<typename ModelType>
334std::pair<std::unique_ptr<storm::modelchecker::CheckResult>, std::unique_ptr<storm::modelchecker::CheckResult>>
336 Environment const& env, storm::models::symbolic::Model<DdType, ValueType> const& abstractModel,
341 storm::exceptions::NotSupportedException, "Abstract model type is not supported.");
342
343 if (abstractModel.isOfType(storm::models::ModelType::Dtmc)) {
344 return computeQuantitativeResult(env, *abstractModel.template as<storm::models::symbolic::Dtmc<DdType, ValueType>>(), constraintStates, targetStates,
345 qualitativeResults);
346 } else if (abstractModel.isOfType(storm::models::ModelType::Mdp)) {
347 return computeQuantitativeResult(env, *abstractModel.template as<storm::models::symbolic::Mdp<DdType, ValueType>>(), constraintStates, targetStates,
348 qualitativeResults);
349 } else {
351 constraintStates, targetStates, qualitativeResults);
352 }
353}
354
355template<typename ModelType>
356std::pair<std::unique_ptr<storm::modelchecker::CheckResult>, std::unique_ptr<storm::modelchecker::CheckResult>>
358 Environment const& env, storm::models::symbolic::Dtmc<DdType, ValueType> const& abstractModel,
361 std::pair<std::unique_ptr<storm::modelchecker::CheckResult>, std::unique_ptr<storm::modelchecker::CheckResult>> result;
363
364 bool isRewardFormula =
365 checkTask->getFormula().isEventuallyFormula() && checkTask->getFormula().asEventuallyFormula().getContext() == storm::logic::FormulaContext::Reward;
366 if (isRewardFormula) {
367 maybe = qualitativeResults.getProb1Min().getStates() && abstractModel.getReachableStates();
368 } else {
369 maybe = !(qualitativeResults.getProb0Min().getStates() || qualitativeResults.getProb1Min().getStates()) && abstractModel.getReachableStates();
370 }
371
373 if (this->getReuseQuantitativeResults() && lastBounds.first) {
374 startValues = maybe.ite(lastBounds.first->asSymbolicQuantitativeCheckResult<DdType, ValueType>().getValueVector(),
375 abstractModel.getManager().template getAddZero<ValueType>());
376 } else {
377 startValues = abstractModel.getManager().template getAddZero<ValueType>();
378 }
379
380 if (isRewardFormula) {
382 env, abstractModel, abstractModel.getTransitionMatrix(),
383 checkTask->isRewardModelSet() ? abstractModel.getRewardModel(checkTask->getRewardModel()) : abstractModel.getRewardModel(""), maybe,
384 targetStates.getStates(), !qualitativeResults.getProb1Min().getStates() && abstractModel.getReachableStates(), startValues);
385
386 result.first = std::make_unique<storm::modelchecker::SymbolicQuantitativeCheckResult<DdType, ValueType>>(abstractModel.getReachableStates(), values);
387 result.second = result.first->clone();
388 } else {
390 env, abstractModel, abstractModel.getTransitionMatrix(), maybe, qualitativeResults.getProb1Min().getStates(), startValues);
391
392 result.first = std::make_unique<storm::modelchecker::SymbolicQuantitativeCheckResult<DdType, ValueType>>(abstractModel.getReachableStates(), values);
393 result.second = result.first->clone();
394 }
395
396 return result;
397}
398
399template<typename ModelType>
400std::pair<std::unique_ptr<storm::modelchecker::CheckResult>, std::unique_ptr<storm::modelchecker::CheckResult>>
402 Environment const& env, storm::models::symbolic::Mdp<DdType, ValueType> const& abstractModel,
405 std::pair<std::unique_ptr<storm::modelchecker::CheckResult>, std::unique_ptr<storm::modelchecker::CheckResult>> result;
406 storm::dd::Bdd<DdType> maybeMin;
407 storm::dd::Bdd<DdType> maybeMax;
408
409 bool isRewardFormula =
410 checkTask->getFormula().isEventuallyFormula() && checkTask->getFormula().asEventuallyFormula().getContext() == storm::logic::FormulaContext::Reward;
411 if (isRewardFormula) {
412 maybeMin = qualitativeResults.getProb1Min().getStates() && abstractModel.getReachableStates();
413 maybeMax = qualitativeResults.getProb1Max().getStates() && abstractModel.getReachableStates();
414 } else {
415 maybeMin = !(qualitativeResults.getProb0Min().getStates() || qualitativeResults.getProb1Min().getStates()) && abstractModel.getReachableStates();
416 maybeMax = !(qualitativeResults.getProb0Max().getStates() || qualitativeResults.getProb1Max().getStates()) && abstractModel.getReachableStates();
417 }
418
420 if (this->getReuseQuantitativeResults() && lastBounds.first) {
421 minStartValues = maybeMin.ite(lastBounds.first->asSymbolicQuantitativeCheckResult<DdType, ValueType>().getValueVector(),
422 abstractModel.getManager().template getAddZero<ValueType>());
423 } else {
424 minStartValues = abstractModel.getManager().template getAddZero<ValueType>();
425 }
426
427 uint64_t abstractionPlayer = this->getAbstractionPlayer();
428 if (isRewardFormula) {
430 env, abstractionPlayer == 1 ? storm::OptimizationDirection::Minimize : checkTask->getOptimizationDirection(), abstractModel,
431 abstractModel.getTransitionMatrix(), abstractModel.getTransitionMatrix().notZero(),
432 checkTask->isRewardModelSet() ? abstractModel.getRewardModel(checkTask->getRewardModel()) : abstractModel.getRewardModel(""), maybeMin,
433 targetStates.getStates(), !qualitativeResults.getProb1Min().getStates() && abstractModel.getReachableStates(), minStartValues);
434
435 if (abstractionPlayer == 0) {
436 result.second = result.first->clone();
437 } else {
439 env, storm::OptimizationDirection::Maximize, abstractModel, abstractModel.getTransitionMatrix(), abstractModel.getTransitionMatrix().notZero(),
440 checkTask->isRewardModelSet() ? abstractModel.getRewardModel(checkTask->getRewardModel()) : abstractModel.getRewardModel(""), maybeMin,
441 targetStates.getStates(), !qualitativeResults.getProb1Max().getStates() && abstractModel.getReachableStates(),
442 maybeMax.ite(result.first->asSymbolicQuantitativeCheckResult<DdType, ValueType>().getValueVector(),
443 abstractModel.getManager().template getAddZero<ValueType>()));
444 }
445 } else {
447 env, abstractionPlayer == 1 ? storm::OptimizationDirection::Minimize : checkTask->getOptimizationDirection(), abstractModel,
448 abstractModel.getTransitionMatrix(), maybeMin, qualitativeResults.getProb1Min().getStates(), minStartValues);
449
450 if (abstractionPlayer == 0) {
451 result.second = result.first->clone();
452 } else {
454 env, storm::OptimizationDirection::Maximize, abstractModel, abstractModel.getTransitionMatrix(), maybeMax,
455 qualitativeResults.getProb1Max().getStates(),
456 maybeMax.ite(result.first->asSymbolicQuantitativeCheckResult<DdType, ValueType>().getValueVector(),
457 abstractModel.getManager().template getAddZero<ValueType>()));
458 }
459 }
460
461 return result;
462}
463
464template<typename ModelType>
465std::pair<std::unique_ptr<storm::modelchecker::CheckResult>, std::unique_ptr<storm::modelchecker::CheckResult>>
470 std::pair<std::unique_ptr<storm::modelchecker::CheckResult>, std::unique_ptr<storm::modelchecker::CheckResult>> result;
471 storm::dd::Bdd<DdType> maybeMin;
472 storm::dd::Bdd<DdType> maybeMax;
473
474 bool isRewardFormula =
475 checkTask->getFormula().isEventuallyFormula() && checkTask->getFormula().asEventuallyFormula().getContext() == storm::logic::FormulaContext::Reward;
476 if (!isRewardFormula) {
477 maybeMin = !(qualitativeResults.getProb0Min().getStates() || qualitativeResults.getProb1Min().getStates()) && abstractModel.getReachableStates();
478 maybeMax = !(qualitativeResults.getProb0Max().getStates() || qualitativeResults.getProb1Max().getStates()) && abstractModel.getReachableStates();
479 }
480
482 if (this->getReuseQuantitativeResults() && lastBounds.first) {
483 minStartValues = maybeMin.ite(lastBounds.first->asSymbolicQuantitativeCheckResult<DdType, ValueType>().getValueVector(),
484 abstractModel.getManager().template getAddZero<ValueType>());
485 } else {
486 minStartValues = abstractModel.getManager().template getAddZero<ValueType>();
487 }
488
489 if (isRewardFormula) {
490 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Reward properties are not supported for abstract stochastic games.");
491 } else {
493 env, abstractModel, this->getAbstractionPlayer() == 1 ? storm::OptimizationDirection::Minimize : checkTask->getOptimizationDirection(),
494 this->getAbstractionPlayer() == 2 ? storm::OptimizationDirection::Minimize : checkTask->getOptimizationDirection(), maybeMin,
495 qualitativeResults.getProb1Min().getStates(), minStartValues);
497 env, abstractModel, this->getAbstractionPlayer() == 1 ? storm::OptimizationDirection::Maximize : checkTask->getOptimizationDirection(),
498 this->getAbstractionPlayer() == 2 ? storm::OptimizationDirection::Maximize : checkTask->getOptimizationDirection(), maybeMin,
499 qualitativeResults.getProb1Max().getStates(),
500 maybeMax.ite(result.first->asSymbolicQuantitativeCheckResult<DdType, ValueType>().getValueVector(),
501 abstractModel.getManager().template getAddZero<ValueType>()));
502 }
503
504 return result;
505}
506
507template<typename ModelType>
510 storm::OptimizationDirection const& player1Direction, storm::OptimizationDirection const& player2Direction, storm::dd::Bdd<DdType> const& maybeStates,
511 storm::dd::Bdd<DdType> const& prob1States, storm::dd::Add<DdType, ValueType> const& startValues) {
512 STORM_LOG_TRACE("Performing quantative solution step. Player 1: " << player1Direction << ", player 2: " << player2Direction << ".");
513
514 // Compute the ingredients of the equation system.
515 storm::dd::Add<DdType, ValueType> maybeStatesAdd = maybeStates.template toAdd<ValueType>();
516 storm::dd::Add<DdType, ValueType> submatrix = maybeStatesAdd * abstractModel.getTransitionMatrix();
517 storm::dd::Add<DdType, ValueType> prob1StatesAsColumn =
518 prob1States.template toAdd<ValueType>().swapVariables(abstractModel.getRowColumnMetaVariablePairs());
519 storm::dd::Add<DdType, ValueType> subvector = submatrix * prob1StatesAsColumn;
520 subvector = subvector.sumAbstract(abstractModel.getColumnVariables());
521
522 // Cut away all columns targeting non-maybe states.
523 submatrix *= maybeStatesAdd.swapVariables(abstractModel.getRowColumnMetaVariablePairs());
524
525 // Cut the starting vector to the maybe states of this query.
526 storm::dd::Add<DdType, ValueType> startVector = maybeStates.ite(startValues, abstractModel.getManager().template getAddZero<ValueType>());
527
528 // Create the solver and solve the equation system.
530 std::unique_ptr<storm::solver::SymbolicGameSolver<DdType, ValueType>> solver =
531 solverFactory.create(submatrix, maybeStates, abstractModel.getIllegalPlayer1Mask(), abstractModel.getIllegalPlayer2Mask(),
532 abstractModel.getRowVariables(), abstractModel.getColumnVariables(), abstractModel.getRowColumnMetaVariablePairs(),
533 abstractModel.getPlayer1Variables(), abstractModel.getPlayer2Variables());
534 auto values = solver->solveGame(env, player1Direction, player2Direction, startVector, subvector);
535
536 return std::make_unique<storm::modelchecker::SymbolicQuantitativeCheckResult<DdType, ValueType>>(abstractModel.getReachableStates(),
537 prob1States.template toAdd<ValueType>() + values);
538}
539
540template<typename ModelType>
541std::unique_ptr<storm::gbar::abstraction::QualitativeResultMinMax> AbstractAbstractionRefinementModelChecker<ModelType>::computeQualitativeResult(
542 Environment const& env, storm::models::Model<ValueType> const& abstractModel, storm::gbar::abstraction::StateSet const& constraintStates,
543 storm::gbar::abstraction::StateSet const& targetStates) {
544 STORM_LOG_ASSERT(abstractModel.isSymbolicModel(), "Expected symbolic abstract model.");
545
546 return computeQualitativeResult(env, *abstractModel.template as<storm::models::symbolic::Model<DdType, ValueType>>(),
547 constraintStates.asSymbolicStateSet<DdType>(), targetStates.asSymbolicStateSet<DdType>());
548}
549
550template<typename ModelType>
551std::unique_ptr<storm::gbar::abstraction::QualitativeResultMinMax> AbstractAbstractionRefinementModelChecker<ModelType>::computeQualitativeResult(
552 Environment const& env, storm::models::symbolic::Model<DdType, ValueType> const& abstractModel,
556 storm::exceptions::NotSupportedException, "Expected discrete-time abstract model.");
557
558 if (abstractModel.isOfType(storm::models::ModelType::Dtmc)) {
559 return computeQualitativeResult(env, *abstractModel.template as<storm::models::symbolic::Dtmc<DdType, ValueType>>(), constraintStates, targetStates);
560 } else if (abstractModel.isOfType(storm::models::ModelType::Mdp)) {
561 return computeQualitativeResult(env, *abstractModel.template as<storm::models::symbolic::Mdp<DdType, ValueType>>(), constraintStates, targetStates);
562 } else {
564 constraintStates, targetStates);
565 }
566}
567
568template<typename ModelType>
569std::unique_ptr<storm::gbar::abstraction::QualitativeResultMinMax> AbstractAbstractionRefinementModelChecker<ModelType>::computeQualitativeResult(
570 Environment const& env, storm::models::symbolic::Dtmc<DdType, ValueType> const& abstractModel,
572 STORM_LOG_DEBUG("Computing qualitative solution for DTMC.");
573 std::unique_ptr<storm::gbar::abstraction::SymbolicQualitativeMdpResultMinMax<DdType>> result =
574 std::make_unique<storm::gbar::abstraction::SymbolicQualitativeMdpResultMinMax<DdType>>();
575
576 auto start = std::chrono::high_resolution_clock::now();
577 bool isRewardFormula =
578 checkTask->getFormula().isEventuallyFormula() && checkTask->getFormula().asEventuallyFormula().getContext() == storm::logic::FormulaContext::Reward;
579 storm::dd::Bdd<DdType> transitionMatrixBdd = abstractModel.getTransitionMatrix().notZero();
580 if (isRewardFormula) {
581 auto prob1 = storm::utility::graph::performProb1(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates());
582 result->prob1Min = result->prob1Max = storm::gbar::abstraction::SymbolicQualitativeMdpResult<DdType>(prob1);
583 } else {
584 auto prob01 = storm::utility::graph::performProb01(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates());
585 result->prob0Min = result->prob0Max = storm::gbar::abstraction::SymbolicQualitativeMdpResult<DdType>(prob01.first);
586 result->prob1Min = result->prob1Max = storm::gbar::abstraction::SymbolicQualitativeMdpResult<DdType>(prob01.second);
587 }
588 auto end = std::chrono::high_resolution_clock::now();
589
590 auto timeInMilliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
591 STORM_LOG_DEBUG("Computed qualitative solution in " << timeInMilliseconds << "ms.");
592
593 return result;
594}
595
596template<typename ModelType>
597std::unique_ptr<storm::gbar::abstraction::QualitativeResultMinMax> AbstractAbstractionRefinementModelChecker<ModelType>::computeQualitativeResult(
598 Environment const& env, storm::models::symbolic::Mdp<DdType, ValueType> const& abstractModel,
600 STORM_LOG_DEBUG("Computing qualitative solution for MDP.");
601 std::unique_ptr<storm::gbar::abstraction::SymbolicQualitativeMdpResultMinMax<DdType>> result =
602 std::make_unique<storm::gbar::abstraction::SymbolicQualitativeMdpResultMinMax<DdType>>();
603
604 auto start = std::chrono::high_resolution_clock::now();
605 bool isRewardFormula =
606 checkTask->getFormula().isEventuallyFormula() && checkTask->getFormula().asEventuallyFormula().getContext() == storm::logic::FormulaContext::Reward;
607 storm::dd::Bdd<DdType> transitionMatrixBdd = abstractModel.getTransitionMatrix().notZero();
608 uint64_t abstractionPlayer = this->getAbstractionPlayer();
609 if (this->getReuseQualitativeResults()) {
610 if (isRewardFormula) {
611 bool computedMin = false;
612 if (abstractionPlayer == 1 || checkTask->getOptimizationDirection() == storm::OptimizationDirection::Minimize) {
614 abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates(),
615 lastQualitativeResults ? lastQualitativeResults->asSymbolicQualitativeResultMinMax<DdType>().getProb1Min().getStates()
616 : storm::utility::graph::performProbGreater0E(abstractModel, transitionMatrixBdd, constraintStates.getStates(),
617 targetStates.getStates()));
619 computedMin = true;
620 }
621
622 if (abstractionPlayer == 1 || checkTask->getOptimizationDirection() == storm::OptimizationDirection::Maximize) {
624 abstractModel, transitionMatrixBdd, targetStates.getStates(),
625 storm::utility::graph::performProbGreater0A(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates()));
627 if (!computedMin) {
628 result->prob1Min = result->prob1Max;
629 }
630 } else {
631 result->prob1Max = result->prob1Min;
632 }
633
634 } else {
635 bool computedMax = false;
636 if (abstractionPlayer == 1 || checkTask->getOptimizationDirection() == storm::OptimizationDirection::Maximize) {
637 auto states = storm::utility::graph::performProb0A(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates());
640 abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates(),
641 lastQualitativeResults ? lastQualitativeResults->asSymbolicQualitativeResultMinMax<DdType>().getProb1Min().getStates()
642 : storm::utility::graph::performProbGreater0E(abstractModel, transitionMatrixBdd, constraintStates.getStates(),
643 targetStates.getStates()));
645 computedMax = true;
646 }
647
648 if (abstractionPlayer == 1 || checkTask->getOptimizationDirection() == storm::OptimizationDirection::Minimize) {
650 abstractModel, transitionMatrixBdd,
651 lastQualitativeResults ? lastQualitativeResults->asSymbolicQualitativeResultMinMax<DdType>().getProb1Min().getStates()
652 : targetStates.getStates(),
653 storm::utility::graph::performProbGreater0A(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates()));
655
656 states = storm::utility::graph::performProb0E(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates());
658
659 if (!computedMax) {
660 result->prob0Max = result->prob0Min;
661 result->prob1Max = result->prob1Min;
662 }
663 } else {
664 result->prob0Min = result->prob0Max;
665 result->prob1Min = result->prob1Max;
666 }
667 }
668 } else {
669 if (isRewardFormula) {
670 bool computedMin = false;
671 if (abstractionPlayer == 1 || checkTask->getOptimizationDirection() == storm::OptimizationDirection::Minimize) {
673 abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates(),
674 storm::utility::graph::performProbGreater0E(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates()));
676 computedMin = true;
677 }
678
679 if (abstractionPlayer == 1 || checkTask->getOptimizationDirection() == storm::OptimizationDirection::Maximize) {
681 abstractModel, transitionMatrixBdd, targetStates.getStates(),
682 storm::utility::graph::performProbGreater0A(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates()));
684 if (!computedMin) {
685 result->prob1Min = result->prob1Max;
686 }
687 } else {
688 result->prob1Max = result->prob1Min;
689 }
690 } else {
691 bool computedMin = false;
692 if (abstractionPlayer == 1 || checkTask->getOptimizationDirection() == storm::OptimizationDirection::Minimize) {
693 auto prob01 =
694 storm::utility::graph::performProb01Min(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates());
697 computedMin = true;
698 }
699
700 if (abstractionPlayer == 1 || checkTask->getOptimizationDirection() == storm::OptimizationDirection::Maximize) {
701 auto prob01 =
702 storm::utility::graph::performProb01Max(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates());
705 if (!computedMin) {
706 result->prob0Min = result->prob0Max;
707 result->prob1Min = result->prob1Max;
708 }
709 } else {
710 result->prob0Max = result->prob0Min;
711 result->prob1Max = result->prob1Min;
712 }
713 }
714 }
715 auto end = std::chrono::high_resolution_clock::now();
716
717 auto timeInMilliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
718 if (isRewardFormula) {
719 STORM_LOG_TRACE("Min: " << result->getProb1Min().getStates().getNonZeroCount() << " states with probability 1.");
720 STORM_LOG_TRACE("Max: " << result->getProb1Max().getStates().getNonZeroCount() << " states with probability 1.");
721 } else {
722 STORM_LOG_TRACE("Min: " << result->getProb0Min().getStates().getNonZeroCount() << " states with probability 0, "
723 << result->getProb1Min().getStates().getNonZeroCount() << " states with probability 1.");
724 STORM_LOG_TRACE("Max: " << result->getProb0Max().getStates().getNonZeroCount() << " states with probability 0, "
725 << result->getProb1Max().getStates().getNonZeroCount() << " states with probability 1.");
726 }
727 STORM_LOG_DEBUG("Computed qualitative solution in " << timeInMilliseconds << "ms.");
728
729 return result;
730}
731
732template<typename ModelType>
733std::unique_ptr<storm::gbar::abstraction::QualitativeResultMinMax> AbstractAbstractionRefinementModelChecker<ModelType>::computeQualitativeResult(
736 STORM_LOG_DEBUG("Computing qualitative solution for S2PG.");
737 std::unique_ptr<storm::gbar::abstraction::SymbolicQualitativeGameResultMinMax<DdType>> result;
738
739 // Obtain the player optimization directions.
740 uint64_t abstractionPlayer = this->getAbstractionPlayer();
741
742 // Obtain direction for player 1 (model nondeterminism).
743 storm::OptimizationDirection modelNondeterminismDirection = this->getCheckTask().getOptimizationDirection();
744
745 // Convert the transition matrix to a BDD to use it in the qualitative algorithms.
746 storm::dd::Bdd<DdType> transitionMatrixBdd = abstractModel.getTransitionMatrix().toBdd();
747
748 // Remembers whether we need to synthesize schedulers.
749 bool requiresSchedulers = this->requiresSchedulerSynthesis();
750
751 auto start = std::chrono::high_resolution_clock::now();
752 if (this->getReuseQualitativeResults()) {
753 result = computeQualitativeResultReuse(abstractModel, transitionMatrixBdd, constraintStates, targetStates, abstractionPlayer,
754 modelNondeterminismDirection, requiresSchedulers);
755 } else {
756 result = std::make_unique<storm::gbar::abstraction::SymbolicQualitativeGameResultMinMax<DdType>>();
757
758 result->prob0Min = storm::utility::graph::performProb0(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates(),
759 abstractionPlayer == 1 ? storm::OptimizationDirection::Minimize : modelNondeterminismDirection,
760 abstractionPlayer == 2 ? storm::OptimizationDirection::Minimize : modelNondeterminismDirection,
761 requiresSchedulers, requiresSchedulers);
762 result->prob1Min = storm::utility::graph::performProb1(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates(),
763 abstractionPlayer == 1 ? storm::OptimizationDirection::Minimize : modelNondeterminismDirection,
764 abstractionPlayer == 2 ? storm::OptimizationDirection::Minimize : modelNondeterminismDirection,
765 requiresSchedulers, requiresSchedulers);
766 result->prob0Max = storm::utility::graph::performProb0(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates(),
767 abstractionPlayer == 1 ? storm::OptimizationDirection::Maximize : modelNondeterminismDirection,
768 abstractionPlayer == 2 ? storm::OptimizationDirection::Maximize : modelNondeterminismDirection,
769 requiresSchedulers, requiresSchedulers);
770 result->prob1Max = storm::utility::graph::performProb1(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates(),
771 abstractionPlayer == 1 ? storm::OptimizationDirection::Maximize : modelNondeterminismDirection,
772 abstractionPlayer == 2 ? storm::OptimizationDirection::Maximize : modelNondeterminismDirection,
773 requiresSchedulers, requiresSchedulers);
774 }
775
776 STORM_LOG_TRACE("Qualitative precomputation completed.");
777 if (abstractionPlayer == 1) {
778 STORM_LOG_TRACE("[" << storm::OptimizationDirection::Minimize << ", " << modelNondeterminismDirection << "]: "
779 << result->prob0Min.player1States.getNonZeroCount() << " 'no', " << result->prob1Min.player1States.getNonZeroCount() << " 'yes'.");
780 STORM_LOG_TRACE("[" << storm::OptimizationDirection::Maximize << ", " << modelNondeterminismDirection << "]: "
781 << result->prob0Max.player1States.getNonZeroCount() << " 'no', " << result->prob1Max.player1States.getNonZeroCount() << " 'yes'.");
782 } else {
783 STORM_LOG_TRACE("[" << modelNondeterminismDirection << ", " << storm::OptimizationDirection::Minimize << "]: "
784 << result->prob0Min.player1States.getNonZeroCount() << " 'no', " << result->prob1Min.player1States.getNonZeroCount() << " 'yes'.");
785 STORM_LOG_TRACE("[" << modelNondeterminismDirection << ", " << storm::OptimizationDirection::Maximize << "]: "
786 << result->prob0Max.player1States.getNonZeroCount() << " 'no', " << result->prob1Max.player1States.getNonZeroCount() << " 'yes'.");
787 }
788
789 auto end = std::chrono::high_resolution_clock::now();
790
791 auto timeInMilliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
792 STORM_LOG_DEBUG("Computed qualitative solution in " << timeInMilliseconds << "ms.");
793
794 return result;
795}
796
797template<typename ModelType>
798std::unique_ptr<storm::gbar::abstraction::SymbolicQualitativeGameResultMinMax<AbstractAbstractionRefinementModelChecker<ModelType>::DdType>>
802 uint64_t abstractionPlayer, storm::OptimizationDirection const& modelNondeterminismDirection, bool requiresSchedulers) {
803 std::unique_ptr<storm::gbar::abstraction::SymbolicQualitativeGameResultMinMax<DdType>> result =
804 std::make_unique<storm::gbar::abstraction::SymbolicQualitativeGameResultMinMax<DdType>>();
805
806 // Depending on the model nondeterminism direction, we choose a different order of operations.
807 if (modelNondeterminismDirection == storm::OptimizationDirection::Minimize) {
808 // (1) min/min: compute prob0 using the game functions
809 result->prob0Min = storm::utility::graph::performProb0(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates(),
810 storm::OptimizationDirection::Minimize, storm::OptimizationDirection::Minimize,
811 requiresSchedulers, requiresSchedulers);
812
813 // (2) min/min: compute prob1 using the MDP functions
814 storm::dd::Bdd<DdType> candidates = abstractModel.getReachableStates() && !result->getProb0Min().getStates();
816 abstractModel, transitionMatrixBdd,
817 lastQualitativeResults ? lastQualitativeResults->asSymbolicQualitativeResultMinMax<DdType>().getProb1Min().getStates() : targetStates.getStates(),
818 candidates);
819
820 // (3) min/min: compute prob1 using the game functions
821 result->prob1Min = storm::utility::graph::performProb1(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates(),
822 storm::OptimizationDirection::Minimize, storm::OptimizationDirection::Minimize,
823 requiresSchedulers, requiresSchedulers, boost::make_optional(prob1MinMinMdp));
824
825 // (4) min/max, max/min: compute prob 0 using the game functions
826 result->prob0Max = storm::utility::graph::performProb0(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates(),
827 abstractionPlayer == 1 ? storm::OptimizationDirection::Maximize : modelNondeterminismDirection,
828 abstractionPlayer == 2 ? storm::OptimizationDirection::Maximize : modelNondeterminismDirection,
829 requiresSchedulers, requiresSchedulers);
830
831 // (5) min/max, max/min: compute prob 1 using the game functions
832 // We know that only previous prob1 states can now be prob 1 states again, because the upper bound
833 // values can only decrease over iterations.
834 result->prob1Max = storm::utility::graph::performProb1(
835 abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates(),
836 abstractionPlayer == 1 ? storm::OptimizationDirection::Maximize : modelNondeterminismDirection,
837 abstractionPlayer == 2 ? storm::OptimizationDirection::Maximize : modelNondeterminismDirection, requiresSchedulers, requiresSchedulers,
838 lastQualitativeResults ? lastQualitativeResults->asSymbolicQualitativeResultMinMax<DdType>().getProb1Max().getStates()
839 : boost::optional<storm::dd::Bdd<DdType>>());
840 } else {
841 // (1) max/max: compute prob0 using the game functions
842 result->prob0Max = storm::utility::graph::performProb0(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates(),
843 storm::OptimizationDirection::Maximize, storm::OptimizationDirection::Maximize,
844 requiresSchedulers, requiresSchedulers);
845
846 // (2) max/max: compute prob1 using the MDP functions, reuse prob1 states of last iteration to constrain the candidate states.
847 storm::dd::Bdd<DdType> candidates = abstractModel.getReachableStates() && !result->getProb0Max().getStates();
848 if (this->getReuseQualitativeResults() && lastQualitativeResults) {
849 candidates &= lastQualitativeResults->asSymbolicQualitativeResultMinMax<DdType>().getProb1Max().getStates();
850 }
851 storm::dd::Bdd<DdType> prob1MaxMaxMdp =
852 storm::utility::graph::performProb1E(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates(), candidates);
853
854 // (3) max/max: compute prob1 using the game functions, reuse prob1 states from the MDP precomputation
855 result->prob1Max = storm::utility::graph::performProb1(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates(),
856 storm::OptimizationDirection::Maximize, storm::OptimizationDirection::Maximize,
857 requiresSchedulers, requiresSchedulers, boost::make_optional(prob1MaxMaxMdp));
858
859 // (4) max/min, min/max: compute prob0 using the game functions
860 result->prob0Min = storm::utility::graph::performProb0(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates(),
861 abstractionPlayer == 1 ? storm::OptimizationDirection::Minimize : modelNondeterminismDirection,
862 abstractionPlayer == 2 ? storm::OptimizationDirection::Minimize : modelNondeterminismDirection,
863 requiresSchedulers, requiresSchedulers);
864
865 // (5) max/min:, max/min compute prob1 using the game functions, use prob1 from max/max as the candidate set
866 result->prob1Min = storm::utility::graph::performProb1(abstractModel, transitionMatrixBdd, constraintStates.getStates(), targetStates.getStates(),
867 abstractionPlayer == 1 ? storm::OptimizationDirection::Minimize : modelNondeterminismDirection,
868 abstractionPlayer == 2 ? storm::OptimizationDirection::Minimize : modelNondeterminismDirection,
869 requiresSchedulers, requiresSchedulers, boost::make_optional(prob1MaxMaxMdp));
870 }
871
872 return result;
873}
874
875template<typename ModelType>
877 storm::models::Model<ValueType> const& abstractModel) {
878 STORM_LOG_THROW(abstractModel.isSymbolicModel(), storm::exceptions::NotSupportedException, "Expected symbolic model.");
879
881}
882
883template<typename ModelType>
886 std::unique_ptr<storm::modelchecker::CheckResult> result;
887
888 auto const& symbolicQualitativeResultMinMax = lastQualitativeResults->asSymbolicQualitativeResultMinMax<DdType>();
889
890 bool isRewardFormula =
891 checkTask->getFormula().isEventuallyFormula() && checkTask->getFormula().asEventuallyFormula().getContext() == storm::logic::FormulaContext::Reward;
892 if (isRewardFormula) {
893 // In the reachability reward case, we can give an answer if all initial states of the system are infinity
894 // states in the min result.
895 if ((abstractModel.getInitialStates() && !symbolicQualitativeResultMinMax.getProb1Min().getStates()) == abstractModel.getInitialStates()) {
896 result = std::make_unique<storm::modelchecker::SymbolicQuantitativeCheckResult<DdType, ValueType>>(
897 abstractModel.getReachableStates(), abstractModel.getInitialStates(),
898 abstractModel.getInitialStates().ite(abstractModel.getManager().getConstant(storm::utility::infinity<ValueType>()),
899 abstractModel.getManager().template getAddZero<ValueType>()));
900 }
901 } else {
902 // In the reachability probability case, we can give the answer if all initial states are prob1 states
903 // in the min result or if all initial states are prob0 in the max case.
904 // Furthermore, we can give the answer if there are initial states with probability > 0 in the min case
905 // and the probability bound was 0 or if there are initial states with probability < 1 in the max case
906 // and the probability bound was 1.
907 if ((abstractModel.getInitialStates() && symbolicQualitativeResultMinMax.getProb1Min().getStates()) == abstractModel.getInitialStates()) {
908 result = std::make_unique<storm::modelchecker::SymbolicQuantitativeCheckResult<DdType, ValueType>>(
909 abstractModel.getReachableStates(), abstractModel.getInitialStates(), abstractModel.getManager().template getAddOne<ValueType>());
910 } else if ((abstractModel.getInitialStates() && symbolicQualitativeResultMinMax.getProb0Max().getStates()) == abstractModel.getInitialStates()) {
911 result = std::make_unique<storm::modelchecker::SymbolicQuantitativeCheckResult<DdType, ValueType>>(
912 abstractModel.getReachableStates(), abstractModel.getInitialStates(), abstractModel.getManager().template getAddZero<ValueType>());
913 } else if (checkTask->isBoundSet() && checkTask->getBoundThreshold() == storm::utility::zero<ValueType>() &&
914 (abstractModel.getInitialStates() && symbolicQualitativeResultMinMax.getProb0Min().getStates()) != abstractModel.getInitialStates()) {
915 result = std::make_unique<storm::modelchecker::SymbolicQuantitativeCheckResult<DdType, ValueType>>(
916 abstractModel.getReachableStates(), abstractModel.getInitialStates(),
917 (abstractModel.getInitialStates() && symbolicQualitativeResultMinMax.getProb0Min().getStates())
918 .ite(abstractModel.getManager().template getConstant<ValueType>(0.5), abstractModel.getManager().template getAddZero<ValueType>()));
919 } else if (checkTask->isBoundSet() && checkTask->getBoundThreshold() == storm::utility::one<ValueType>() &&
920 (abstractModel.getInitialStates() && symbolicQualitativeResultMinMax.getProb1Max().getStates()) != abstractModel.getInitialStates()) {
921 result = std::make_unique<storm::modelchecker::SymbolicQuantitativeCheckResult<DdType, ValueType>>(
922 abstractModel.getReachableStates(), abstractModel.getInitialStates(),
923 (abstractModel.getInitialStates() && symbolicQualitativeResultMinMax.getProb1Max().getStates())
924 .ite(abstractModel.getManager().template getConstant<ValueType>(0.5), abstractModel.getManager().template getAddZero<ValueType>()) +
925 symbolicQualitativeResultMinMax.getProb1Max().getStates().template toAdd<ValueType>());
926 }
927 }
928
929 if (result) {
930 STORM_LOG_TRACE("Found result after qualitative check.");
931 } else {
932 STORM_LOG_TRACE("Did not find result after qualitative check.");
933 }
934
935 return result;
936}
937
938template<typename ModelType>
940 storm::models::Model<ValueType> const& abstractModel,
941 std::pair<std::unique_ptr<storm::modelchecker::CheckResult>, std::unique_ptr<storm::modelchecker::CheckResult>>& bounds) {
942 std::unique_ptr<storm::modelchecker::CheckResult> result;
943
944 if (bounds.first == nullptr || bounds.second == nullptr) {
945 STORM_LOG_ASSERT(bounds.first || bounds.second, "Expected at least one bound.");
946
947 if (bounds.first) {
948 return std::move(bounds.first);
949 } else {
950 return std::move(bounds.second);
951 }
952 } else {
953 if (boundsAreSufficientlyClose(bounds)) {
954 STORM_LOG_TRACE("Obtained bounds are sufficiently close.");
955 result = getAverageOfBounds(bounds);
956 }
957 }
958
959 if (result) {
960 abstractModel.printModelInformationToStream(std::cout);
961 }
962
963 return result;
964}
965
966template<typename ModelType>
968 std::pair<std::unique_ptr<storm::modelchecker::CheckResult>, std::unique_ptr<storm::modelchecker::CheckResult>> const& bounds) {
969 STORM_LOG_ASSERT(bounds.first->isSymbolicQuantitativeCheckResult(), "Expected symbolic quantitative check result.");
972 STORM_LOG_ASSERT(bounds.second->isSymbolicQuantitativeCheckResult(), "Expected symbolic quantitative check result.");
975
976 return lowerBounds.getValueVector().equalModuloPrecision(upperBounds.getValueVector(), this->precision, false);
977}
978
979template<typename ModelType>
980std::unique_ptr<storm::modelchecker::CheckResult> AbstractAbstractionRefinementModelChecker<ModelType>::getAverageOfBounds(
981 std::pair<std::unique_ptr<storm::modelchecker::CheckResult>, std::unique_ptr<storm::modelchecker::CheckResult>> const& bounds) {
982 STORM_LOG_ASSERT(bounds.first->isSymbolicQuantitativeCheckResult(), "Expected symbolic quantitative check result.");
985 STORM_LOG_ASSERT(bounds.second->isSymbolicQuantitativeCheckResult(), "Expected symbolic quantitative check result.");
988
989 return std::make_unique<storm::modelchecker::SymbolicQuantitativeCheckResult<DdType, ValueType>>(
990 lowerBounds.getReachableStates(), lowerBounds.getStates(),
991 (lowerBounds.getValueVector() + upperBounds.getValueVector()) /
992 lowerBounds.getValueVector().getDdManager().getConstant(storm::utility::convertNumber<ValueType>(std::string("2.0"))));
993}
994
999
1000} // namespace modelchecker
1001} // namespace storm::gbar
Add< LibraryType, ValueType > swapVariables(std::vector< std::pair< storm::expressions::Variable, storm::expressions::Variable > > const &metaVariablePairs) const
Swaps the given pairs of meta variables in the ADD.
Definition Add.cpp:285
ValueType getMax() const
Retrieves the highest function value of any encoding.
Definition Add.cpp:468
Add< LibraryType, ValueType > sumAbstract(std::set< storm::expressions::Variable > const &metaVariables) const
Sum-abstracts from the given meta variables.
Definition Add.cpp:171
Bdd< LibraryType > toBdd() const
Converts the ADD to a BDD by mapping all values unequal to zero to 1.
Definition Add.cpp:1180
bool equalModuloPrecision(Add< LibraryType, ValueType > const &other, ValueType const &precision, bool relative=true) const
Checks whether the current and the given ADD represent the same function modulo some given precision.
Definition Add.cpp:204
Bdd< LibraryType > notZero() const
Computes a BDD that represents the function in which all assignments with a function value unequal to...
Definition Add.cpp:424
Bdd< LibraryType > maxAbstractRepresentative(std::set< storm::expressions::Variable > const &metaVariables) const
Similar to maxAbstract, but does not abstract from the variables but rather picks a valuation of each...
Definition Add.cpp:198
virtual uint_fast64_t getNonZeroCount() const override
Retrieves the number of encodings that are mapped to a non-zero value.
Definition Bdd.cpp:507
Bdd< LibraryType > swapVariables(std::vector< std::pair< storm::expressions::Variable, storm::expressions::Variable > > const &metaVariablePairs) const
Swaps the given pairs of meta variables in the BDD.
Definition Bdd.cpp:296
Bdd< LibraryType > ite(Bdd< LibraryType > const &thenBdd, Bdd< LibraryType > const &elseBdd) const
Performs an if-then-else with the given operands, i.e.
Definition Bdd.cpp:107
std::set< storm::expressions::Variable > const & getContainedMetaVariables() const
Retrieves the set of all meta variables contained in the DD.
Definition Dd.cpp:28
DdManager< LibraryType > & getDdManager() const
Retrieves the manager that is responsible for this DD.
Definition Dd.cpp:38
SymbolicQualitativeResultMinMax< Type > const & asSymbolicQualitativeResultMinMax() const
SymbolicStateSet< Type > const & asSymbolicStateSet() const
SymbolicQualitativeResult< Type > const & getProb0Min() const
SymbolicQualitativeResult< Type > const & getProb0Max() const
SymbolicQualitativeResult< Type > const & getProb1Max() const
SymbolicQualitativeResult< Type > const & getProb1Min() const
storm::dd::Bdd< Type > const & getStates() const
virtual std::shared_ptr< storm::models::Model< ValueType > > getAbstractModel()=0
Retrieves the abstract model.
std::unique_ptr< storm::gbar::abstraction::SymbolicQualitativeGameResultMinMax< DdType > > computeQualitativeResultReuse(storm::models::symbolic::StochasticTwoPlayerGame< DdType, ValueType > const &abstractModel, storm::dd::Bdd< DdType > const &transitionMatrixBdd, storm::gbar::abstraction::SymbolicStateSet< DdType > const &constraintStates, storm::gbar::abstraction::SymbolicStateSet< DdType > const &targetStates, uint64_t abstractionPlayer, storm::OptimizationDirection const &modelNondeterminismDirection, bool requiresSchedulers)
std::unique_ptr< storm::modelchecker::CheckResult > getAverageOfBounds(std::pair< std::unique_ptr< storm::modelchecker::CheckResult >, std::unique_ptr< storm::modelchecker::CheckResult > > const &bounds)
Retrieves the average of the two bounds.
bool checkForResultAfterQuantitativeCheck(storm::models::Model< ValueType > const &abstractModel, bool lowerBounds, storm::modelchecker::QuantitativeCheckResult< ValueType > const &result)
std::unique_ptr< storm::modelchecker::CheckResult > performAbstractionRefinement(Environment const &env)
-----— Methods used to implement the abstraction refinement procedure.
std::pair< std::unique_ptr< storm::modelchecker::CheckResult >, std::unique_ptr< storm::modelchecker::CheckResult > > computeQuantitativeResult(Environment const &env, storm::models::Model< ValueType > const &abstractModel, storm::gbar::abstraction::StateSet const &constraintStates, storm::gbar::abstraction::StateSet const &targetStates, storm::gbar::abstraction::QualitativeResultMinMax const &qualitativeResults)
virtual void refineAbstractModel()=0
Refines the abstract model so that the next iteration obtains bounds that are at least as precise as ...
storm::modelchecker::CheckTask< storm::logic::Formula, ValueType > const & getCheckTask() const
std::unique_ptr< storm::gbar::abstraction::QualitativeResultMinMax > computeQualitativeResult(Environment const &env, storm::models::Model< ValueType > const &abstractModel, storm::gbar::abstraction::StateSet const &constraintStates, storm::gbar::abstraction::StateSet const &targetStates)
Solves the current check task qualitatively, i.e. computes all states with probability 0/1.
void setCheckTask(storm::modelchecker::CheckTask< storm::logic::Formula, ValueType > const &checkTask)
Methods to set/get the check task that is currently handled.
virtual bool requiresSchedulerSynthesis() const =0
Retrieves whether schedulers need to be computed.
virtual std::string const & getName() const =0
Retrieves the name of the underlying method.
void printBoundsInformation(std::pair< std::unique_ptr< storm::modelchecker::CheckResult >, std::unique_ptr< storm::modelchecker::CheckResult > > &bounds)
virtual void initializeAbstractionRefinement()=0
Called before the abstraction refinement loop to give the implementation a time to set up auxiliary d...
virtual bool supportsReachabilityRewards() const
-----— Methods that need to be overwritten/defined by implementations in subclasses.
std::unique_ptr< storm::modelchecker::CheckResult > checkForResultAfterQualitativeCheck(storm::models::Model< ValueType > const &abstractModel)
virtual std::unique_ptr< storm::modelchecker::CheckResult > computeReachabilityProbabilities(Environment const &env, storm::modelchecker::CheckTask< storm::logic::EventuallyFormula, ValueType > const &checkTask) override
virtual std::unique_ptr< storm::modelchecker::CheckResult > computeUntilProbabilities(Environment const &env, storm::modelchecker::CheckTask< storm::logic::UntilFormula, ValueType > const &checkTask) override
virtual std::unique_ptr< storm::modelchecker::CheckResult > computeReachabilityRewards(Environment const &env, storm::modelchecker::CheckTask< storm::logic::EventuallyFormula, ValueType > const &checkTask) override
bool skipQuantitativeSolution(storm::models::Model< ValueType > const &abstractModel, storm::gbar::abstraction::QualitativeResultMinMax const &qualitativeResults)
virtual std::pair< std::unique_ptr< storm::gbar::abstraction::StateSet >, std::unique_ptr< storm::gbar::abstraction::StateSet > > getConstraintAndTargetStates(storm::models::Model< ValueType > const &abstractModel)=0
Retrieves the state sets corresponding to the constraint and target states.
std::unique_ptr< storm::modelchecker::CheckResult > computeReachabilityProbabilitiesHelper(Environment const &env, storm::models::symbolic::StochasticTwoPlayerGame< DdType, ValueType > const &abstractModel, storm::OptimizationDirection const &player1Direction, storm::OptimizationDirection const &player2Direction, storm::dd::Bdd< DdType > const &maybeStates, storm::dd::Bdd< DdType > const &prob1States, storm::dd::Add< DdType, ValueType > const &startValues)
virtual uint64_t getAbstractionPlayer() const =0
Retrieves the index of the abstraction player.
std::pair< std::unique_ptr< storm::modelchecker::CheckResult >, std::unique_ptr< storm::modelchecker::CheckResult > > computeBounds(Environment const &env, storm::models::Model< ValueType > const &abstractModel)
Computes lower and upper bounds on the abstract model and returns the bounds for the initial states.
void filterInitialStates(storm::models::Model< ValueType > const &abstractModel, std::pair< std::unique_ptr< storm::modelchecker::CheckResult >, std::unique_ptr< storm::modelchecker::CheckResult > > &bounds)
std::unique_ptr< storm::modelchecker::CheckResult > tryToObtainResultFromBounds(storm::models::Model< ValueType > const &model, std::pair< std::unique_ptr< storm::modelchecker::CheckResult >, std::unique_ptr< storm::modelchecker::CheckResult > > &bounds)
Tries to obtain the results from the bounds.
bool getReuseQualitativeResults() const
Methods that retrieve which results shall be reused.
bool boundsAreSufficientlyClose(std::pair< std::unique_ptr< storm::modelchecker::CheckResult >, std::unique_ptr< storm::modelchecker::CheckResult > > const &bounds)
Checks whether the provided bounds are sufficiently close to terminate.
virtual bool canHandle(storm::modelchecker::CheckTask< storm::logic::Formula > const &checkTask) const override
Overridden methods from super class.
AbstractAbstractionRefinementModelChecker(abstraction::AbstractionOptions const &options=abstraction::AbstractionOptions())
Constructs a model checker for the given model.
bool isInFragment(FragmentSpecification const &fragment) const
Definition Formula.cpp:218
FragmentSpecification & setReachabilityRewardFormulasAllowed(bool newValue)
FragmentSpecification & setRewardOperatorsAllowed(bool newValue)
SymbolicQuantitativeCheckResult< Type, ValueType > & asSymbolicQuantitativeCheckResult()
virtual ExtendedValueType getMax() const =0
virtual ExtendedValueType getMin() const =0
storm::dd::Add< Type, ValueType > const & getValueVector() const
static storm::dd::Add< DdType, ValueType > computeUntilProbabilities(Environment const &env, storm::models::symbolic::Model< DdType, ValueType > const &model, storm::dd::Add< DdType, ValueType > const &transitionMatrix, storm::dd::Bdd< DdType > const &phiStates, storm::dd::Bdd< DdType > const &psiStates, bool qualitative, boost::optional< storm::dd::Add< DdType, ValueType > > const &startValues=boost::none)
static storm::dd::Add< DdType, ValueType > computeReachabilityRewards(Environment const &env, storm::models::symbolic::Model< DdType, ValueType > const &model, storm::dd::Add< DdType, ValueType > const &transitionMatrix, RewardModelType const &rewardModel, storm::dd::Bdd< DdType > const &targetStates, bool qualitative, boost::optional< storm::dd::Add< DdType, ValueType > > const &startValues=boost::none)
static std::unique_ptr< CheckResult > computeUntilProbabilities(Environment const &env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel< DdType, ValueType > const &model, storm::dd::Add< DdType, ValueType > const &transitionMatrix, storm::dd::Bdd< DdType > const &phiStates, storm::dd::Bdd< DdType > const &psiStates, bool qualitative, boost::optional< storm::dd::Add< DdType, ValueType > > const &startValues=boost::none)
static std::unique_ptr< CheckResult > computeReachabilityRewards(Environment const &env, OptimizationDirection dir, storm::models::symbolic::NondeterministicModel< DdType, ValueType > const &model, storm::dd::Add< DdType, ValueType > const &transitionMatrix, RewardModelType const &rewardModel, storm::dd::Bdd< DdType > const &targetStates, boost::optional< storm::dd::Add< DdType, ValueType > > const &startValues=boost::none)
virtual bool isSymbolicModel() const
Checks whether the model is a symbolic model.
Definition ModelBase.cpp:15
virtual void printModelInformationToStream(std::ostream &out) const =0
Prints information about the model to the specified stream.
bool isOfType(storm::models::ModelType const &modelType) const
Checks whether the model is of the given type.
Definition ModelBase.cpp:27
This class represents a discrete-time Markov chain.
Definition Dtmc.h:13
This class represents a discrete-time Markov decision process.
Definition Mdp.h:13
Base class for all symbolic models.
Definition Model.h:42
storm::dd::DdManager< Type > & getManager() const
Retrieves the manager responsible for the DDs that represent this model.
Definition Model.cpp:89
RewardModelType const & getRewardModel(std::string const &rewardModelName) const
Retrieves the reward model with the given name, if one exists.
Definition Model.cpp:246
storm::dd::Add< Type, ValueType > const & getTransitionMatrix() const
Retrieves the matrix representing the transitions of the model.
Definition Model.cpp:174
std::set< storm::expressions::Variable > const & getColumnVariables() const
Retrieves the meta variables used to encode the columns of the transition matrix and the vector indic...
Definition Model.cpp:194
storm::dd::Bdd< Type > const & getInitialStates() const
Retrieves the initial states of the model.
Definition Model.cpp:104
std::vector< std::pair< storm::expressions::Variable, storm::expressions::Variable > > const & getRowColumnMetaVariablePairs() const
Retrieves the pairs of row and column meta variables.
Definition Model.cpp:220
std::set< storm::expressions::Variable > const & getRowVariables() const
Retrieves the meta variables used to encode the rows of the transition matrix and the vector indices.
Definition Model.cpp:189
storm::dd::Bdd< Type > const & getReachableStates() const
Retrieves the reachable states of the model.
Definition Model.cpp:99
This class represents a discrete-time stochastic two-player game.
std::set< storm::expressions::Variable > const & getPlayer1Variables() const
Retrieeves the set of meta variables used to encode the nondeterministic choices of player 1.
std::set< storm::expressions::Variable > const & getPlayer2Variables() const
Retrieeves the set of meta variables used to encode the nondeterministic choices of player 2.
storm::dd::Bdd< Type > getIllegalPlayer1Mask() const
Retrieves a BDD characterizing all illegal player 1 choice encodings in the model.
storm::dd::Bdd< Type > getIllegalPlayer2Mask() const
Retrieves a BDD characterizing all illegal player 2 choice encodings in the model.
virtual std::unique_ptr< storm::solver::SymbolicGameSolver< Type, ValueType > > create(storm::dd::Add< Type, ValueType > const &A, storm::dd::Bdd< Type > const &allRows, storm::dd::Bdd< Type > const &illegalPlayer1Mask, storm::dd::Bdd< Type > const &illegalPlayer2Mask, std::set< storm::expressions::Variable > const &rowMetaVariables, std::set< storm::expressions::Variable > const &columnMetaVariables, std::vector< std::pair< storm::expressions::Variable, storm::expressions::Variable > > const &rowColumnMetaVariablePairs, std::set< storm::expressions::Variable > const &player1Variables, std::set< storm::expressions::Variable > const &player2Variables) const
#define STORM_LOG_DEBUG(message)
Definition logging.h:28
#define STORM_LOG_TRACE(message)
Definition logging.h:22
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:9
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:39
std::unique_ptr< storm::modelchecker::CheckResult > checkForResultAfterQuantitativeCheck(storm::modelchecker::CheckTask< storm::logic::Formula, ValueType > const &checkTask, storm::OptimizationDirection const &player2Direction, std::pair< ValueType, ValueType > const &initialValueRange)
std::unique_ptr< storm::modelchecker::CheckResult > checkForResultAfterQualitativeCheck(storm::modelchecker::CheckTask< storm::logic::Formula, ValueType > const &checkTask, storm::OptimizationDirection player2Direction, storm::dd::Bdd< Type > const &initialStates, storm::dd::Bdd< Type > const &prob0, storm::dd::Bdd< Type > const &prob1)
SymbolicQuantitativeGameResult< Type, ValueType > computeQuantitativeResult(Environment const &env, storm::OptimizationDirection player1Direction, storm::OptimizationDirection player2Direction, storm::gbar::abstraction::MenuGame< Type, ValueType > const &game, SymbolicQualitativeGameResultMinMax< Type > const &qualitativeResult, storm::dd::Add< Type, ValueType > const &initialStatesAdd, storm::dd::Bdd< Type > const &maybeStates, boost::optional< SymbolicQuantitativeGameResult< Type, ValueType > > const &startInfo=boost::none)
bool isLowerBound(ComparisonType t)
bool isStrict(ComparisonType t)
FragmentSpecification reachability()
std::pair< storm::storage::BitVector, storm::storage::BitVector > performProb01(storm::models::sparse::DeterministicModel< T > const &model, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates)
Computes the sets of states that have probability 0 or 1, respectively, of satisfying phi until psi i...
Definition graph.cpp:394
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)
Definition graph.cpp:855
ExplicitGameProb01Result performProb0(storm::storage::SparseMatrix< ValueType > const &transitionMatrix, std::vector< uint64_t > const &player1Groups, storm::storage::SparseMatrix< ValueType > const &player1BackwardTransitions, std::vector< uint64_t > const &player2BackwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates, storm::OptimizationDirection const &player1Direction, storm::OptimizationDirection const &player2Direction, storm::storage::ExplicitGameStrategyPair *strategyPair)
Computes the set of states that have probability 0 given the strategies of the two players.
Definition graph.cpp:1330
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...
Definition graph.cpp:881
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...
Definition graph.cpp:1019
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...
Definition graph.cpp:674
storm::storage::BitVector performProb0A(storm::storage::SparseMatrix< T > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates)
Definition graph.cpp:732
storm::storage::BitVector performProb1(storm::storage::SparseMatrix< T > const &backwardTransitions, storm::storage::BitVector const &, storm::storage::BitVector const &psiStates, storm::storage::BitVector const &statesWithProbabilityGreater0)
Computes the set of states of the given model for which all paths lead to the given set of target sta...
Definition graph.cpp:377
storm::storage::BitVector performProb0E(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 0 of satisfying phi until psi under at least one po...
Definition graph.cpp:998
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)
Definition graph.cpp:1101
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...
Definition graph.cpp:740
ValueType zero()
Definition constants.cpp:26
ValueType infinity()
Definition constants.cpp:31
ValueType one()
Definition constants.cpp:21
TargetType convertNumber(SourceType const &number)
solver::OptimizationDirection OptimizationDirection
Options that configure the game-based abstraction-refinement procedure.
ReuseMode reuseMode
The mode determining which results are reused.