43namespace modelchecker {
45using detail::PreviousExplicitResult;
52template<storm::dd::DdType Type,
typename ModelType>
55 std::shared_ptr<storm::utility::solver::SmtSolverFactory>
const& smtSolverFactory)
57 smtSolverFactory(smtSolverFactory),
58 comparator(
storm::utility::convertNumber<
ValueType>(
storm::settings::getModule<
storm::settings::modules::AbstractionSettings>().getPrecision()),
59 storm::settings::getModule<
storm::settings::modules::AbstractionSettings>().getRelativeTerminationCriterion()),
60 reuseQualitativeResults(false),
61 reuseQuantitativeResults(false),
62 solveMode(
storm::settings::getModule<
storm::settings::modules::AbstractionSettings>().getSolveMode()),
63 debug(
storm::settings::getModule<
storm::settings::modules::AbstractionSettings>().isDebugSet()) {
66 std::vector<std::string> undefinedConstantNames;
67 for (
auto undefinedConstant : undefinedConstants) {
68 undefinedConstantNames.emplace_back(undefinedConstant.getName());
72 "Model contains undefined constants ("
73 << boost::algorithm::join(undefinedConstantNames,
",")
74 <<
"). Game-based abstraction can treat such models, but you should make sure that you did not simply forget to define these "
75 "constants. In particular, it may be necessary to constrain the values of the undefined constants.");
82 storm::exceptions::NotSupportedException,
"Currently only DTMCs/MDPs are supported by the game-based model checker.");
84 auto flattenStart = std::chrono::high_resolution_clock::now();
89 preprocessedModel = originalProgram;
91 auto flattenEnd = std::chrono::high_resolution_clock::now();
92 STORM_LOG_INFO(
"Flattened model in " << std::chrono::duration_cast<std::chrono::milliseconds>(flattenEnd - flattenStart).count() <<
"ms.");
98 storm::exceptions::NotSupportedException,
"Currently only DTMCs/MDPs are supported by the game-based model checker.");
110 maximalNumberOfAbstractions = abstractionSettings.getMaximalAbstractionCount();
111 fixPlayer1Strategy = abstractionSettings.isFixPlayer1StrategySet();
112 fixPlayer2Strategy = abstractionSettings.isFixPlayer2StrategySet();
115template<storm::dd::DdType Type,
typename ModelType>
122template<storm::dd::DdType Type,
typename ModelType>
126 std::map<std::string, storm::expressions::Expression> labelToExpressionMapping;
127 if (preprocessedModel.isPrismProgram()) {
128 labelToExpressionMapping = preprocessedModel.asPrismProgram().getLabelToExpressionMapping();
132 if (variable.isTransient()) {
133 labelToExpressionMapping[variable.getName()] = janiModel.
getLabelExpression(variable);
143 return performGameBasedAbstractionRefinement(env, checkTask.template substituteFormula<storm::logic::Formula>(pathFormula), constraintExpression,
144 targetStateExpression);
147template<storm::dd::DdType Type,
typename ModelType>
151 std::map<std::string, storm::expressions::Expression> labelToExpressionMapping;
152 if (preprocessedModel.isPrismProgram()) {
153 labelToExpressionMapping = preprocessedModel.asPrismProgram().getLabelToExpressionMapping();
157 if (variable.isTransient()) {
158 labelToExpressionMapping[variable.getName()] = janiModel.
getLabelExpression(variable);
166 return performGameBasedAbstractionRefinement(env, checkTask.template substituteFormula<storm::logic::Formula>(pathFormula), constraintExpression,
167 targetStateExpression);
170template<storm::dd::DdType Type,
typename ValueType>
174 std::unique_ptr<storm::modelchecker::CheckResult> result;
179 if (player2Direction == storm::OptimizationDirection::Minimize) {
181 if ((prob1 && initialStates) == initialStates) {
183 storm::utility::one<ValueType>());
186 if (!(prob1 && initialStates).isZero()) {
188 storm::utility::one<ValueType>());
191 }
else if (player2Direction == storm::OptimizationDirection::Maximize) {
193 if ((prob0 && initialStates) == initialStates) {
195 storm::utility::zero<ValueType>());
198 if (!(prob0 && initialStates).isZero()) {
200 storm::utility::zero<ValueType>());
205 if (player2Direction == storm::OptimizationDirection::Minimize && (prob1 && initialStates) == initialStates) {
207 storm::utility::one<ValueType>());
208 }
else if (player2Direction == storm::OptimizationDirection::Maximize && (prob0 && initialStates) == initialStates) {
210 storm::utility::zero<ValueType>());
217template<storm::dd::DdType Type,
typename ValueType>
222 std::unique_ptr<storm::modelchecker::CheckResult> result =
223 checkForResultAfterQualitativeCheck<Type, ValueType>(checkTask, storm::OptimizationDirection::Minimize, initialStates,
224 qualitativeResult.
prob0Min.getPlayer1States(), qualitativeResult.
prob1Min.getPlayer1States());
228 result = checkForResultAfterQualitativeCheck<Type, ValueType>(checkTask, storm::OptimizationDirection::Maximize, initialStates,
229 qualitativeResult.
prob0Max.getPlayer1States(), qualitativeResult.
prob1Max.getPlayer1States());
236template<
typename ValueType>
240 std::unique_ptr<storm::modelchecker::CheckResult> result;
245 if (player2Direction == storm::OptimizationDirection::Minimize) {
249 storm::utility::one<ValueType>());
254 storm::utility::one<ValueType>());
257 }
else if (player2Direction == storm::OptimizationDirection::Maximize) {
261 storm::utility::zero<ValueType>());
266 storm::utility::zero<ValueType>());
271 if (player2Direction == storm::OptimizationDirection::Minimize && initialStates.
isSubsetOf(prob1)) {
273 storm::utility::one<ValueType>());
274 }
else if (player2Direction == storm::OptimizationDirection::Maximize && initialStates.
isSubsetOf(prob0)) {
276 storm::utility::zero<ValueType>());
283template<
typename ValueType>
288 std::unique_ptr<storm::modelchecker::CheckResult> result =
289 checkForResultAfterQualitativeCheck<ValueType>(checkTask, storm::OptimizationDirection::Minimize, initialStates,
294 result = checkForResultAfterQualitativeCheck<ValueType>(checkTask, storm::OptimizationDirection::Maximize, initialStates,
302template<
typename ValueType>
305 std::pair<ValueType, ValueType>
const& initialValueRange) {
306 std::unique_ptr<storm::modelchecker::CheckResult> result;
316 ValueType
const& lowerValue = initialValueRange.first;
317 ValueType
const& upperValue = initialValueRange.second;
323 if (player2Direction == storm::OptimizationDirection::Minimize) {
333 if (player2Direction == storm::OptimizationDirection::Maximize) {
347template<
typename ValueType>
350 std::unique_ptr<storm::modelchecker::CheckResult> result;
353 if (comparator.
isEqual(minValue, maxValue)) {
355 (minValue + maxValue) / ValueType(2));
361template<storm::dd::DdType Type,
typename ValueType>
366 STORM_LOG_TRACE(
"Performing quantative solution step. Player 1: " << player1Direction <<
", player 2: " << player2Direction <<
".");
381 startVector = startInfo.get().values * maybeStatesAdd;
383 startVector = game.
getManager().template getAddZero<ValueType>();
388 std::unique_ptr<storm::solver::SymbolicGameSolver<Type, ValueType>> solver =
391 solver->setGeneratePlayersStrategies(
true);
392 auto values = solver->solveGame(env, player1Direction, player2Direction, startVector, subvector,
393 startInfo ? boost::make_optional(startInfo.get().getPlayer1Strategy()) : boost::none,
394 startInfo ? boost::make_optional(startInfo.get().getPlayer2Strategy()) : boost::none);
396 solver->getPlayer1Strategy(), solver->getPlayer2Strategy());
399template<storm::dd::DdType Type,
typename ValueType>
405 bool min = player2Direction == storm::OptimizationDirection::Minimize;
413 combinedPlayer1QualitativeStrategies = (qualitativeResult.
prob0Min.getPlayer1Strategy() || qualitativeResult.
prob1Min.getPlayer1Strategy());
414 combinedPlayer2QualitativeStrategies = (qualitativeResult.
prob0Min.getPlayer2Strategy() || qualitativeResult.
prob1Min.getPlayer2Strategy());
416 combinedPlayer1QualitativeStrategies = (qualitativeResult.
prob0Max.getPlayer1Strategy() || qualitativeResult.
prob1Max.getPlayer1Strategy());
417 combinedPlayer2QualitativeStrategies = (qualitativeResult.
prob0Max.getPlayer2Strategy() || qualitativeResult.
prob1Max.getPlayer2Strategy());
424 auto start = std::chrono::high_resolution_clock::now();
425 if (!maybeStates.
isZero()) {
429 result =
solveMaybeStates(env, player1Direction, player2Direction, game, maybeStates,
430 min ? qualitativeResult.
prob1Min.getPlayer1States() : qualitativeResult.
prob1Max.getPlayer1States(), startInfo);
437 result.
values += min ? qualitativeResult.
prob1Min.getPlayer1States().template toAdd<ValueType>()
438 : qualitativeResult.
prob1Max.getPlayer1States().template toAdd<ValueType>();
440 STORM_LOG_TRACE(
"No " << (player2Direction == storm::OptimizationDirection::Minimize ?
"min" :
"max") <<
" maybe states.");
443 result.
values += min ? qualitativeResult.
prob1Min.getPlayer1States().template toAdd<ValueType>()
444 : qualitativeResult.
prob1Max.getPlayer1States().template toAdd<ValueType>();
450 ValueType maxValueOverInitialStates = initialStateValueAdd.
getMax();
451 initialStateValueAdd += (!game.
getInitialStates()).
template toAdd<ValueType>();
452 ValueType minValueOverInitialStates = initialStateValueAdd.
getMin();
454 result.
initialStatesRange = std::make_pair(minValueOverInitialStates, maxValueOverInitialStates);
461 auto end = std::chrono::high_resolution_clock::now();
462 STORM_LOG_TRACE(
"Obtained quantitative " << (min ?
"lower" :
"upper") <<
" bound "
464 << std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() <<
"ms.");
469template<
typename ValueType>
477 bool player2Min = player2Direction == storm::OptimizationDirection::Minimize;
489 if (maybeStates.
empty()) {
494 if (previousResult) {
495 STORM_LOG_ASSERT(player2Min,
"Can only reuse previous values when minimizing.");
496 previousResult.get().odd.oldToNewIndex(odd, [&previousResult, &result, player2Min, player1Prob1States](uint64_t oldOffset, uint64_t newOffset) {
497 if (!player1Prob1States.get(newOffset)) {
498 result.getValues()[newOffset] =
499 player2Min ? previousResult.get().values.getValues()[oldOffset] : previousResult.get().values.getValues()[oldOffset];
509 uint64_t position = 0;
510 uint64_t previousPlayer2States = 0;
512 for (
auto state : maybeStates) {
513 subPlayer1Groups[position] = previousPlayer2States;
515 bool hasMaybePlayer2Successor =
false;
516 for (uint64_t player2State = player1Groups[state]; player2State < player1Groups[state + 1]; ++player2State) {
517 if (!player2Prob0States.get(player2State) && !player2Prob1States.get(player2State)) {
518 player2MaybeStates.
set(player2State);
519 hasMaybePlayer2Successor =
true;
520 ++previousPlayer2States;
523 STORM_LOG_ASSERT(hasMaybePlayer2Successor,
"Player 1 maybe state has no player2 maybe successor.");
526 subPlayer1Groups.back() = previousPlayer2States;
537 if (startingQuantitativeResult) {
540 if (previousResult) {
541 STORM_LOG_ASSERT(!startingQuantitativeResult,
"Cannot take two different hints.");
546 std::vector<uint64_t> player1Scheduler(subPlayer1Groups.size() - 1);
548 if (startingStrategyPair) {
550 uint64_t maybeStatePosition = 0;
551 previousPlayer2States = 0;
552 for (
auto state : maybeStates) {
553 uint64_t chosenPlayer2State = startingStrategyPair->getPlayer1Strategy().getChoice(state);
555 uint64_t previousPlayer2MaybeStatesForState = 0;
556 for (uint64_t player2State = player1Groups[state]; player2State < player1Groups[state + 1]; ++player2State) {
557 if (player2MaybeStates.
get(player2State)) {
558 if (player2State == chosenPlayer2State) {
559 player1Scheduler[maybeStatePosition] = previousPlayer2MaybeStatesForState;
563 if (startingStrategyPair->getPlayer2Strategy().hasDefinedChoice(player2State)) {
564 player2Scheduler[previousPlayer2States] =
565 startingStrategyPair->getPlayer2Strategy().getChoice(player2State) - transitionMatrix.
getRowGroupIndices()[player2State];
567 player2Scheduler[previousPlayer2States] = 0;
570 ++previousPlayer2MaybeStatesForState;
571 ++previousPlayer2States;
575 ++maybeStatePosition;
581 gameSolver->solveGame(env, player1Direction, player2Direction, values, b, &player1Scheduler, &player2Scheduler);
587 uint64_t previousPlayer1MaybeStates = 0;
588 uint64_t previousPlayer2MaybeStates = 0;
589 for (
auto state : maybeStates) {
590 uint64_t previousPlayer2MaybeStatesForState = 0;
591 bool madePlayer1Choice =
false;
592 for (uint64_t player2State = player1Groups[state]; player2State < player1Groups[state + 1]; ++player2State) {
593 if (player1Scheduler[previousPlayer1MaybeStates] == previousPlayer2MaybeStatesForState) {
595 madePlayer1Choice =
true;
598 if (player2MaybeStates.
get(player2State)) {
600 transitionMatrix.
getRowGroupIndices()[player2State] + player2Scheduler[previousPlayer2MaybeStates]);
602 ++previousPlayer2MaybeStatesForState;
603 ++previousPlayer2MaybeStates;
606 STORM_LOG_ASSERT(madePlayer1Choice,
"[" << player1Direction <<
"]: player 1 state " << state
607 <<
" did not make a choice, scheduler: " << player1Scheduler[previousPlayer1MaybeStates] <<
".");
609 ++previousPlayer1MaybeStates;
615template<storm::dd::DdType Type,
typename ModelType>
616std::unique_ptr<storm::modelchecker::CheckResult> GameBasedMdpModelChecker<Type, ModelType>::performGameBasedAbstractionRefinement(
620 "The game-based abstraction refinement model checker can only compute the result for the initial states.");
627 std::vector<storm::expressions::Expression> initialPredicates = getInitialPredicates(constraintExpression, targetStateExpression);
634 if (preprocessedModel.isPrismProgram()) {
635 abstractor = std::make_shared<storm::gbar::abstraction::prism::PrismMenuGameAbstractor<Type, ValueType>>(preprocessedModel.asPrismProgram(),
636 smtSolverFactory, abstractorOptions);
638 abstractor = std::make_shared<storm::gbar::abstraction::jani::JaniMenuGameAbstractor<Type, ValueType>>(preprocessedModel.asJaniModel(),
639 smtSolverFactory, abstractorOptions);
641 std::unique_ptr<storm::modelchecker::CheckResult> result;
642 abstractor->getDdManager().execute([&]() {
643 if (!constraintExpression.
isTrue()) {
644 abstractor->addTerminalStates(!constraintExpression);
646 abstractor->addTerminalStates(targetStateExpression);
647 abstractor->setTargetStates(targetStateExpression);
653 refiner.refine(initialPredicates,
false);
660 boost::optional<SymbolicQualitativeGameResultMinMax<Type>> previousSymbolicQualitativeResult = boost::none;
661 boost::optional<SymbolicQuantitativeGameResult<Type, ValueType>> previousSymbolicMinQuantitativeResult = boost::none;
662 boost::optional<PreviousExplicitResult<ValueType>> previousExplicitResult = boost::none;
663 uint64_t peakPlayer1States = 0;
664 uint64_t peakTransitions = 0;
665 for (iteration = 0; iteration < maximalNumberOfAbstractions; ++iteration) {
666 auto iterationStart = std::chrono::high_resolution_clock::now();
672 abstractionWatch.stop();
673 totalAbstractionWatch.add(abstractionWatch);
676 peakPlayer1States = std::max(peakPlayer1States, numberOfPlayer1States);
678 peakTransitions = std::max(peakTransitions, numberOfTransitions);
681 <<
" initial), " << game.
getNumberOfPlayer2States() <<
" player 2 states, " << numberOfTransitions <<
" transitions, "
684 << abstractionWatch.getTimeInMilliseconds() <<
"ms).");
693 if (player1Direction == storm::OptimizationDirection::Minimize) {
705 result = performSymbolicAbstractionSolutionStep(env, checkTask, game, player1Direction, initialStates, constraintStates, targetStates, refiner,
706 previousSymbolicQualitativeResult, previousSymbolicMinQuantitativeResult);
708 result = performExplicitAbstractionSolutionStep(env, checkTask, game, player1Direction, initialStates, constraintStates, targetStates, refiner,
709 previousExplicitResult);
714 printStatistics(*abstractor, game, iteration, peakPlayer1States, peakTransitions);
718 auto iterationEnd = std::chrono::high_resolution_clock::now();
719 STORM_LOG_INFO(
"Iteration " << iteration <<
" took " << std::chrono::duration_cast<std::chrono::milliseconds>(iterationEnd - iterationStart).
count()
729 STORM_LOG_WARN(
"Could not derive result, maximal number of abstractions exceeded.");
733template<storm::dd::DdType Type,
typename ModelType>
734std::unique_ptr<storm::modelchecker::CheckResult> GameBasedMdpModelChecker<Type, ModelType>::performSymbolicAbstractionSolutionStep(
739 boost::optional<SymbolicQualitativeGameResultMinMax<Type>>& previousQualitativeResult,
740 boost::optional<SymbolicQuantitativeGameResult<Type, ValueType>>& previousMinQuantitativeResult) {
748 SymbolicQualitativeGameResultMinMax<Type> qualitativeResult =
749 computeProb01States(previousQualitativeResult, game, player1Direction, transitionMatrixBdd, constraintStates, targetStates);
750 std::unique_ptr<storm::modelchecker::CheckResult> result =
751 checkForResultAfterQualitativeCheck<Type, ValueType>(checkTask, initialStates, qualitativeResult);
755 previousQualitativeResult = qualitativeResult;
756 qualitativeWatch.stop();
757 totalSolutionWatch.add(qualitativeWatch);
758 STORM_LOG_INFO(
"Qualitative computation completed in " << qualitativeWatch.getTimeInMilliseconds() <<
"ms.");
762 !(qualitativeResult.prob0Min.getPlayer1States() || qualitativeResult.prob1Min.getPlayer1States()) && game.
getReachableStates();
764 !(qualitativeResult.prob0Max.getPlayer1States() || qualitativeResult.prob1Max.getPlayer1States()) && game.
getReachableStates();
767 storm::dd::Bdd<Type> initialMaybeStates = (initialStates && maybeMin) || (initialStates && maybeMax);
768 bool qualitativeRefinement =
false;
769 if (initialMaybeStates.
isZero()) {
773 STORM_LOG_INFO(
"Obtained qualitative bounds [0, 1] on the actual value for the initial states (after "
774 << totalWatch.getTimeInMilliseconds() <<
"ms in iteration " << this->iteration <<
"). Refining abstraction based on qualitative check.");
779 qualitativeRefinement = refiner.
refine(game, transitionMatrixBdd, qualitativeResult);
780 refinementWatch.stop();
781 totalRefinementWatch.add(refinementWatch);
782 STORM_LOG_INFO(
"Qualitative refinement completed in " << refinementWatch.getTimeInMilliseconds() <<
"ms.");
786 if (!qualitativeRefinement) {
792 SymbolicQuantitativeGameResultMinMax<Type, ValueType> quantitativeResult;
796 quantitativeResult.min =
computeQuantitativeResult(env, player1Direction, storm::OptimizationDirection::Minimize, game, qualitativeResult,
797 initialStatesAdd, maybeMin, reuseQuantitativeResults ? previousMinQuantitativeResult :
boost::none);
798 quantitativeWatch.stop();
799 previousMinQuantitativeResult = quantitativeResult.min;
801 checkForResultAfterQuantitativeCheck<ValueType>(checkTask, storm::OptimizationDirection::Minimize, quantitativeResult.min.getInitialStatesRange());
803 totalSolutionWatch.add(quantitativeWatch);
808 quantitativeWatch.start();
809 quantitativeResult.max =
computeQuantitativeResult(env, player1Direction, storm::OptimizationDirection::Maximize, game, qualitativeResult,
810 initialStatesAdd, maybeMax, boost::make_optional(quantitativeResult.min));
811 quantitativeWatch.stop();
813 checkForResultAfterQuantitativeCheck<ValueType>(checkTask, storm::OptimizationDirection::Maximize, quantitativeResult.max.getInitialStatesRange());
814 totalSolutionWatch.add(quantitativeWatch);
819 ValueType minVal = quantitativeResult.min.getInitialStatesRange().first;
820 ValueType maxVal = quantitativeResult.max.getInitialStatesRange().second;
822 if (std::is_same<ValueType, double>::value) {
823 std::stringstream differenceStream;
824 differenceStream.setf(std::ios::fixed, std::ios::floatfield);
825 differenceStream.precision(15);
826 differenceStream << difference;
827 STORM_LOG_INFO(
"Obtained quantitative bounds [" << minVal <<
", " << maxVal <<
"] (difference " << differenceStream.str()
828 <<
") on the actual value for the initial states in " << quantitativeWatch.getTimeInMilliseconds()
829 <<
"ms (after " << totalWatch.getTimeInMilliseconds() <<
"ms in iteration " << this->iteration
832 STORM_LOG_INFO(
"Obtained quantitative bounds [" << minVal <<
", " << maxVal <<
"] (approx. [" << storm::utility::convertNumber<double>(minVal)
833 <<
", " << storm::utility::convertNumber<double>(maxVal) <<
"], difference " << difference
834 <<
") on the actual value for the initial states in " << quantitativeWatch.getTimeInMilliseconds()
835 <<
"ms (after " << totalWatch.getTimeInMilliseconds() <<
"ms in iteration " << this->iteration
840 result = checkForResultAfterQuantitativeCheck<ValueType>(quantitativeResult.min.getInitialStatesRange().first,
841 quantitativeResult.max.getInitialStatesRange().second, comparator);
848 quantitativeResult.min.getPlayer1Strategy().template toAdd<ValueType>().sumAbstract(game.
getPlayer1Variables()).getMax() <= 1,
849 "Player 1 strategy for min is illegal.");
851 quantitativeResult.max.getPlayer1Strategy().template toAdd<ValueType>().sumAbstract(game.
getPlayer1Variables()).getMax() <= 1,
852 "Player 1 strategy for max is illegal.");
854 quantitativeResult.min.getPlayer2Strategy().template toAdd<ValueType>().sumAbstract(game.
getPlayer2Variables()).getMax() <= 1,
855 "Player 2 strategy for min is illegal.");
857 quantitativeResult.max.getPlayer2Strategy().template toAdd<ValueType>().sumAbstract(game.
getPlayer2Variables()).getMax() <= 1,
858 "Player 2 strategy for max is illegal.");
863 refiner.
refine(game, transitionMatrixBdd, quantitativeResult);
864 refinementWatch.stop();
865 totalRefinementWatch.add(refinementWatch);
866 STORM_LOG_INFO(
"Quantitative refinement completed in " << refinementWatch.getTimeInMilliseconds() <<
"ms.");
873template<
typename ValueType>
879 if (!redirectPlayer1 && !redirectPlayer2) {
883 for (uint64_t state = 0; state < player1Groups.size() - 1; ++state) {
886 bool hasMinPlayer1Choice =
false;
887 uint64_t lowerPlayer1Choice = 0;
888 bool hasMaxPlayer1Choice =
false;
889 uint64_t upperPlayer1Choice = 0;
892 hasMinPlayer1Choice =
true;
899 if (lowerPlayer2Choice == upperPlayer2Choice) {
903 bool redirect =
true;
905 for (
auto const& entry : transitionMatrix.
getRow(upperPlayer2Choice)) {
913 if (redirectPlayer2 && redirect) {
919 bool lowerChoiceUnderUpperIsProb0 =
false;
924 hasMaxPlayer1Choice =
true;
929 if (lowerPlayer2Choice == upperPlayer2Choice) {
933 lowerChoiceUnderUpperIsProb0 =
true;
934 for (
auto const& entry : transitionMatrix.
getRow(lowerPlayer2Choice)) {
936 lowerChoiceUnderUpperIsProb0 =
false;
941 bool redirect =
true;
942 if (lowerChoiceUnderUpperIsProb0) {
943 for (
auto const& entry : transitionMatrix.
getRow(upperPlayer2Choice)) {
951 if (redirectPlayer2 && redirect) {
957 if (redirectPlayer1 && player1Direction == storm::OptimizationDirection::Minimize) {
958 if (hasMinPlayer1Choice && hasMaxPlayer1Choice && lowerPlayer1Choice != upperPlayer1Choice) {
959 if (!isProb0Min || lowerChoiceUnderUpperIsProb0) {
967template<
typename ValueType>
974 void exportToJson(std::string
const& filename, std::vector<uint64_t>
const& player1Groups, std::vector<uint64_t>
const& player2Groups,
980 std::ofstream outfile;
982 exportGame(outfile, player1Groups, player2Groups, transitionMatrix, initialStates, constraintStates, targetStates, quantitativeResult, minStrategyPair,
988 showNonStrategyAlternatives = value;
993 NodeData(uint64_t
id, uint64_t player,
bool initial,
bool target) : id(id), player(player), initial(initial), target(target) {
1004 EdgeData(uint64_t
id, uint64_t source, uint64_t target, ValueType probability, uint64_t label,
bool min,
bool max)
1005 : id(id), source(source), target(target), probability(probability), label(label), min(min), max(max) {
1012 ValueType probability;
1018 void exportEdge(std::ofstream& out, EdgeData
const& data,
bool& first) {
1025 out <<
"\t\t\t\"data\": {\n";
1026 out <<
"\t\t\t\t\"id\": \"" << data.id <<
"\",\n";
1027 if (data.probability != storm::utility::zero<ValueType>()) {
1028 out <<
"\t\t\t\t\"name\": \"" << data.probability <<
"\",\n";
1030 out <<
"\t\t\t\t\"name\": \"" << data.label <<
"\",\n";
1032 out <<
"\t\t\t\t\"source\": \"" << data.source <<
"\",\n";
1033 out <<
"\t\t\t\t\"target\": \"" << data.target <<
"\"\n";
1034 out <<
"\t\t\t},\n";
1035 out <<
"\t\t\t\"classes\": \"";
1036 if (data.min && data.max) {
1037 out <<
"minMaxEdge";
1038 }
else if (data.min) {
1040 }
else if (data.max) {
1049 void exportNode(std::ofstream& out, NodeData
const& data, ExplicitQuantitativeResultMinMax<ValueType>
const* quantitativeResult,
bool& first) {
1056 out <<
"\t\t\t\"data\": {\n";
1057 out <<
"\t\t\t\t\"id\": \"" << data.id <<
"\",\n";
1058 out <<
"\t\t\t\t\"name\": \"" << data.id;
1059 if (quantitativeResult && data.player == 1) {
1060 out <<
" [" << quantitativeResult->getMin().getValues()[data.id] <<
", " << quantitativeResult->getMax().getValues()[data.id] <<
"]";
1063 out <<
"\t\t\t},\n";
1064 out <<
"\t\t\t\"group\": \"nodes\",\n";
1065 out <<
"\t\t\t\"classes\": \"";
1066 if (data.player == 1) {
1068 out <<
"initialNode";
1069 }
else if (data.target) {
1070 out <<
"targetNode";
1074 }
else if (data.player == 2) {
1076 }
else if (data.player == 0) {
1083 void exportGame(std::ofstream& out, std::vector<uint64_t>
const& player1Groups, std::vector<uint64_t>
const& player2Groups,
1086 ExplicitQuantitativeResultMinMax<ValueType>
const& quantitativeResult, storage::ExplicitGameStrategyPair
const* minStrategyPair,
1087 storage::ExplicitGameStrategyPair
const* maxStrategyPair) {
1089 std::vector<NodeData> nodes;
1090 std::vector<EdgeData> edges;
1092 std::vector<uint64_t> stack;
1093 for (
auto state : initialStates) {
1094 stack.push_back(state);
1098 uint64_t edgeId = 0;
1099 while (!stack.empty()) {
1100 uint64_t currentState = stack.back();
1103 nodes.emplace_back(currentState, 1, initialStates.
get(currentState), targetStates.
get(currentState));
1105 for (uint64_t player2State = player1Groups[currentState]; player2State < player1Groups[currentState + 1]; ++player2State) {
1106 bool emit = (minStrategyPair || maxStrategyPair) ? this->showNonStrategyAlternatives : true;
1110 if (minStrategyPair && minStrategyPair->getPlayer1Strategy().hasDefinedChoice(currentState) &&
1111 minStrategyPair->getPlayer1Strategy().getChoice(currentState) == player2State) {
1115 if (maxStrategyPair && maxStrategyPair->getPlayer1Strategy().hasDefinedChoice(currentState) &&
1116 maxStrategyPair->getPlayer1Strategy().getChoice(currentState) == player2State) {
1122 nodes.emplace_back(player2State, 2,
false,
false);
1123 edges.emplace_back(edgeId++, currentState, player2State, storm::utility::zero<ValueType>(), player2State - player1Groups[currentState], min,
1126 for (uint64_t playerPState = player2Groups[player2State]; playerPState < player2Groups[player2State + 1]; ++playerPState) {
1127 emit = (minStrategyPair || maxStrategyPair) ? this->showNonStrategyAlternatives : true;
1131 if (minStrategyPair && minStrategyPair->getPlayer2Strategy().hasDefinedChoice(player2State) &&
1132 minStrategyPair->getPlayer2Strategy().getChoice(player2State) == playerPState) {
1136 if (maxStrategyPair && maxStrategyPair->getPlayer2Strategy().hasDefinedChoice(player2State) &&
1137 maxStrategyPair->getPlayer2Strategy().getChoice(player2State) == playerPState) {
1143 nodes.emplace_back(playerPState, 0,
false,
false);
1144 edges.emplace_back(edgeId++, player2State, playerPState, storm::utility::zero<ValueType>(),
1145 playerPState - player2Groups[player2State], min, max);
1147 for (
auto const& entry : transitionMatrix.getRow(playerPState)) {
1148 auto player1Successor = entry.getColumn();
1149 if (!reachablePlayer1.get(player1Successor)) {
1150 reachablePlayer1.set(player1Successor);
1151 stack.push_back(player1Successor);
1154 edges.emplace_back(edgeId++, playerPState, player1Successor, entry.getValue(), 0,
false,
false);
1165 out <<
"{\n\t\"nodes\": [\n";
1167 for (
auto const& node : nodes) {
1168 exportNode(out, node, &quantitativeResult, first);
1174 out <<
"\t\"edges\": [\n";
1175 for (
auto const& edge : edges) {
1176 exportEdge(out, edge, first);
1178 out <<
"\n\t]\n}\n";
1181 bool showNonStrategyAlternatives;
1184template<
typename ValueType>
1190 bool redirectPlayer1,
bool redirectPlayer2,
bool sanityCheck) {
1191 if (redirectPlayer1 || redirectPlayer2) {
1192 for (uint64_t state = 0; state < player1Groups.size() - 1; ++state) {
1194 "Expected lower player 1 choice in state " << state <<
".");
1196 "Expected upper player 1 choice in state " << state <<
".");
1198 bool hasMinPlayer1Choice =
false;
1199 uint64_t lowerPlayer1Choice = 0;
1200 ValueType lowerValueUnderMinChoicePlayer1 = storm::utility::zero<ValueType>();
1201 bool hasMaxPlayer1Choice =
false;
1202 uint64_t upperPlayer1Choice = 0;
1203 ValueType lowerValueUnderMaxChoicePlayer1 = storm::utility::zero<ValueType>();
1206 hasMinPlayer1Choice =
true;
1210 "Expected lower player 2 choice for state " << state <<
" (lower player 1 choice " << lowerPlayer1Choice <<
").");
1213 ValueType lowerValueUnderLowerChoicePlayer2 =
1215 lowerValueUnderMinChoicePlayer1 = lowerValueUnderLowerChoicePlayer2;
1220 if (lowerPlayer2Choice != upperPlayer2Choice) {
1221 ValueType lowerValueUnderUpperChoicePlayer2 =
1224 if (redirectPlayer2 && lowerValueUnderUpperChoicePlayer2 <= lowerValueUnderLowerChoicePlayer2) {
1225 lowerValueUnderMinChoicePlayer1 = lowerValueUnderUpperChoicePlayer2;
1236 hasMaxPlayer1Choice =
true;
1240 ValueType lowerValueUnderLowerChoicePlayer2 =
1242 lowerValueUnderMaxChoicePlayer1 = lowerValueUnderLowerChoicePlayer2;
1245 "Expected upper player 2 choice for state " << state <<
" (upper player 1 choice " << upperPlayer1Choice <<
").");
1248 if (lowerPlayer2Choice != upperPlayer2Choice) {
1249 ValueType lowerValueUnderUpperChoicePlayer2 =
1252 if (redirectPlayer2 && lowerValueUnderUpperChoicePlayer2 <= lowerValueUnderLowerChoicePlayer2) {
1259 if (redirectPlayer1 && player1Direction == storm::OptimizationDirection::Minimize) {
1260 if (hasMinPlayer1Choice && hasMaxPlayer1Choice && lowerPlayer1Choice != upperPlayer1Choice) {
1261 if (lowerValueUnderMaxChoicePlayer1 <= lowerValueUnderMinChoicePlayer1) {
1275 for (uint64_t state = 0; state < player1Groups.size() - 1; ++state) {
1276 if (targetStates.
get(state)) {
1277 dtmcMatrixBuilder.
addNextValue(state, state, storm::utility::one<ValueType>());
1281 "Expected max player 2 choice in state " << state <<
" with player 2 choice "
1284 for (
auto const& entry : transitionMatrix.
getRow(player2Choice)) {
1285 dtmcMatrixBuilder.
addNextValue(state, entry.getColumn(), entry.getValue());
1289 auto dtmcMatrix = dtmcMatrixBuilder.
build();
1293 ValueType maxDiff = storm::utility::zero<ValueType>();
1294 uint64_t maxState = 0;
1295 for (uint64_t state = 0; state < player1Groups.size() - 1; ++state) {
1297 if (diff > maxDiff) {
1304 "Deviation " << maxDiff <<
" between computed value (" << quantitativeResult.
getMin().getValues()[maxState]
1305 <<
") and sanity check value (" << sanityValues[maxState] <<
") in state " << maxState
1306 <<
" appears to be too high. (Obtained bounds were [" << quantitativeResult.
getMin().getValues()[maxState] <<
", "
1307 << quantitativeResult.
getMax().getValues()[maxState] <<
"].)");
1312 for (uint64_t state = 0; state < player1Groups.size() - 1; ++state) {
1313 if (targetStates.
get(state)) {
1314 dtmcMatrixBuilder.
addNextValue(state, state, storm::utility::one<ValueType>());
1318 "Expected max player 2 choice in state " << state <<
" with player 2 choice "
1322 for (
auto const& entry : transitionMatrix.
getRow(player2Choice)) {
1323 dtmcMatrixBuilder.
addNextValue(state, entry.getColumn(), entry.getValue());
1327 dtmcMatrix = dtmcMatrixBuilder.
build();
1331 maxDiff = storm::utility::zero<ValueType>();
1333 for (uint64_t state = 0; state < player1Groups.size() - 1; ++state) {
1335 if (diff > maxDiff) {
1342 "Deviation " << maxDiff <<
" between computed value (" << quantitativeResult.
getMax().getValues()[maxState]
1343 <<
") and sanity check value (" << sanityValues[maxState] <<
") in state " << maxState
1344 <<
" appears to be too high. (Obtained bounds were [" << quantitativeResult.
getMin().getValues()[maxState] <<
", "
1345 << quantitativeResult.
getMax().getValues()[maxState] <<
"].)");
1349template<storm::dd::DdType Type,
typename ModelType>
1350std::unique_ptr<storm::modelchecker::CheckResult> GameBasedMdpModelChecker<Type, ModelType>::performExplicitAbstractionSolutionStep(
1364 auto& transitionMatrix = matrixAndLabeling.
matrix;
1365 auto& player1Labeling = matrixAndLabeling.
labelings.front();
1366 auto& player2Labeling = matrixAndLabeling.
labelings.back();
1369 std::vector<uint64_t> tmpPlayer2RowGrouping;
1370 for (uint64_t player1State = 0; player1State < transitionMatrix.
getRowGroupCount(); ++player1State) {
1371 uint64_t lastLabel = std::numeric_limits<uint64_t>::max();
1373 if (player1Labeling[row] != lastLabel) {
1374 tmpPlayer2RowGrouping.emplace_back(row);
1375 lastLabel = player1Labeling[row];
1379 tmpPlayer2RowGrouping.emplace_back(player1Labeling.size());
1381 std::vector<uint64_t> player1RowGrouping = transitionMatrix.
swapRowGroupIndices(std::move(tmpPlayer2RowGrouping));
1385 std::vector<uint64_t> player1Groups(player1RowGrouping.size());
1387 std::vector<uint64_t> player2BackwardTransitions(transitionMatrix.
getRowGroupCount());
1389 uint64_t player2State = 0;
1390 for (uint64_t player1State = 0; player1State < player1RowGrouping.size() - 1; ++player1State) {
1391 while (player1RowGrouping[player1State + 1] > player2RowGrouping[player2State]) {
1392 player2BackwardTransitions[player2State] = player1State;
1396 player1Groups[player1State + 1] = player2State;
1400 for (uint64_t player1State = 0; player1State < player1Groups.size() - 1; ++player1State) {
1401 for (uint64_t player2State = player1Groups[player1State]; player2State < player1Groups[player1State + 1]; ++player2State) {
1402 player1Labeling[player2State] = player1Labeling[player2RowGrouping[player2State]];
1405 player1Labeling.resize(player2RowGrouping.size() - 1);
1411 translationWatch.stop();
1412 totalTranslationWatch.add(translationWatch);
1413 STORM_LOG_INFO(
"Translation to explicit representation completed in " << translationWatch.getTimeInMilliseconds() <<
"ms.");
1416 storage::ExplicitGameStrategyPair minStrategyPair(initialStates.
size(), transitionMatrix.
getRowGroupCount());
1417 storage::ExplicitGameStrategyPair maxStrategyPair(initialStates.
size(), transitionMatrix.
getRowGroupCount());
1421 ExplicitQualitativeGameResultMinMax qualitativeResult =
1422 computeProb01States(previousResult, odd, player1Direction, transitionMatrix, player1Groups, player1BackwardTransitions, player2BackwardTransitions,
1423 constraintStates, targetStates, minStrategyPair, maxStrategyPair);
1424 qualitativeWatch.stop();
1425 totalSolutionWatch.add(qualitativeWatch);
1426 STORM_LOG_INFO(
"Qualitative computation completed in " << qualitativeWatch.getTimeInMilliseconds() <<
"ms.");
1428 std::unique_ptr<storm::modelchecker::CheckResult> result = checkForResultAfterQualitativeCheck<ValueType>(checkTask, initialStates, qualitativeResult);
1434 storm::storage::BitVector maybeMin = ~(qualitativeResult.getProb0Min().getStates() | qualitativeResult.getProb1Min().getStates());
1435 storm::storage::BitVector maybeMax = ~(qualitativeResult.getProb0Max().getStates() | qualitativeResult.getProb1Max().getStates());
1439 bool qualitativeRefinement =
false;
1440 if (initialMaybeStates.
empty()) {
1444 STORM_LOG_INFO(
"Obtained qualitative bounds [0, 1] on the actual value for the initial states (after "
1445 << totalWatch.getTimeInMilliseconds() <<
"ms in iteration " << this->iteration <<
"). Refining abstraction based on qualitative check.");
1449 postProcessStrategies(player1Direction, minStrategyPair, maxStrategyPair, player1Groups, player2RowGrouping, transitionMatrix, constraintStates,
1450 targetStates, qualitativeResult, this->fixPlayer1Strategy, this->fixPlayer2Strategy, this->debug);
1451 strategyProcessingWatch.stop();
1452 totalStrategyProcessingWatch.add(strategyProcessingWatch);
1453 STORM_LOG_DEBUG(
"Postprocessed strategies in " << strategyProcessingWatch.getTimeInMilliseconds() <<
"ms.");
1458 qualitativeRefinement = refiner.
refine(game, odd, transitionMatrix, player1Groups, player1Labeling, player2Labeling, initialStates, constraintStates,
1459 targetStates, qualitativeResult, minStrategyPair, maxStrategyPair);
1460 refinementWatch.stop();
1461 totalRefinementWatch.add(refinementWatch);
1462 STORM_LOG_INFO(
"Qualitative refinement completed in " << refinementWatch.getTimeInMilliseconds() <<
"ms.");
1465 ExplicitQuantitativeResultMinMax<ValueType> quantitativeResult;
1468 if (!qualitativeRefinement) {
1474 quantitativeResult.setMin(computeQuantitativeResult<ValueType>(env, player1Direction, storm::OptimizationDirection::Minimize, transitionMatrix,
1475 player1Groups, qualitativeResult, maybeMin, minStrategyPair, odd,
nullptr,
nullptr,
1476 this->reuseQuantitativeResults ? previousResult :
boost::none));
1479 if (previousResult) {
1480 previousResult.get().clear();
1482 quantitativeWatch.stop();
1483 result = checkForResultAfterQuantitativeCheck<ValueType>(checkTask, storm::OptimizationDirection::Minimize,
1484 quantitativeResult.getMin().getRange(initialStates));
1486 totalSolutionWatch.add(quantitativeWatch);
1491 quantitativeWatch.start();
1492 quantitativeResult.setMax(
computeQuantitativeResult(env, player1Direction, storm::OptimizationDirection::Maximize, transitionMatrix, player1Groups,
1493 qualitativeResult, maybeMax, maxStrategyPair, odd, &quantitativeResult.getMin(), &minStrategyPair));
1494 quantitativeWatch.stop();
1495 result = checkForResultAfterQuantitativeCheck<ValueType>(checkTask, storm::OptimizationDirection::Maximize,
1496 quantitativeResult.getMax().getRange(initialStates));
1497 totalSolutionWatch.add(quantitativeWatch);
1502 ValueType minVal = quantitativeResult.getMin().getRange(initialStates).first;
1503 ValueType maxVal = quantitativeResult.getMax().getRange(initialStates).second;
1505 if (std::is_same<ValueType, double>::value) {
1506 std::stringstream differenceStream;
1507 differenceStream.setf(std::ios::fixed, std::ios::floatfield);
1508 differenceStream.precision(15);
1509 differenceStream << difference;
1510 STORM_LOG_INFO(
"Obtained quantitative bounds [" << minVal <<
", " << maxVal <<
"] (difference " << differenceStream.str()
1511 <<
") on the actual value for the initial states in " << quantitativeWatch.getTimeInMilliseconds()
1512 <<
"ms (after " << totalWatch.getTimeInMilliseconds() <<
"ms in iteration " << this->iteration
1515 STORM_LOG_INFO(
"Obtained quantitative bounds [" << minVal <<
", " << maxVal <<
"] (approx. [" << storm::utility::convertNumber<double>(minVal)
1516 <<
", " << storm::utility::convertNumber<double>(maxVal) <<
"], difference " << difference
1517 <<
") on the actual value for the initial states in " << quantitativeWatch.getTimeInMilliseconds()
1518 <<
"ms (after " << totalWatch.getTimeInMilliseconds() <<
"ms in iteration " << this->iteration
1523 result = checkForResultAfterQuantitativeCheck<ValueType>(quantitativeResult.getMin().getRange(initialStates).first,
1524 quantitativeResult.getMax().getRange(initialStates).second, comparator);
1531 postProcessStrategies(this->iteration, player1Direction, minStrategyPair, maxStrategyPair, player1Groups, player2RowGrouping, transitionMatrix,
1532 initialStates, constraintStates, targetStates, quantitativeResult, this->fixPlayer1Strategy, this->fixPlayer2Strategy,
1534 strategyProcessingWatch.stop();
1535 totalStrategyProcessingWatch.add(strategyProcessingWatch);
1536 STORM_LOG_DEBUG(
"Postprocessed strategies in " << strategyProcessingWatch.getTimeInMilliseconds() <<
"ms.");
1540 "Expected at most " << targetStates.
getNumberOfSetBits() <<
" (number of target states) player 1 states with undefined choice but got "
1541 << minStrategyPair.getNumberOfUndefinedPlayer1States() <<
".");
1543 "Expected at most " << targetStates.
getNumberOfSetBits() <<
" (number of target states) player 1 states with undefined choice but got "
1544 << maxStrategyPair.getNumberOfUndefinedPlayer1States() <<
".");
1549 refiner.
refine(game, odd, transitionMatrix, player1Groups, player1Labeling, player2Labeling, initialStates, constraintStates, targetStates,
1550 quantitativeResult, minStrategyPair, maxStrategyPair);
1551 refinementWatch.stop();
1552 totalRefinementWatch.add(refinementWatch);
1553 STORM_LOG_INFO(
"Quantitative refinement completed in " << refinementWatch.getTimeInMilliseconds() <<
"ms.");
1555 if (this->reuseQuantitativeResults) {
1556 PreviousExplicitResult<ValueType> nextPreviousResult;
1557 nextPreviousResult.values = std::move(quantitativeResult.getMin());
1558 nextPreviousResult.odd = odd;
1559 previousResult = std::move(nextPreviousResult);
1567template<storm::dd::DdType Type,
typename ModelType>
1568std::vector<storm::expressions::Expression> GameBasedMdpModelChecker<Type, ModelType>::getInitialPredicates(
1570 std::vector<storm::expressions::Expression> initialPredicates;
1571 if (preprocessedModel.isJaniModel()) {
1574 std::vector<storm::expressions::Expression> splitExpressions = splitter.split(targetStateExpression);
1575 initialPredicates.insert(initialPredicates.end(), splitExpressions.begin(), splitExpressions.end());
1577 splitExpressions = splitter.split(constraintExpression);
1578 initialPredicates.insert(initialPredicates.end(), splitExpressions.begin(), splitExpressions.end());
1580 if (!targetStateExpression.
isTrue() && !targetStateExpression.
isFalse()) {
1581 initialPredicates.push_back(targetStateExpression);
1583 if (!constraintExpression.
isTrue() && !constraintExpression.
isFalse()) {
1584 initialPredicates.push_back(constraintExpression);
1587 return initialPredicates;
1590template<storm::dd::DdType Type,
typename ModelType>
1594 return storm::OptimizationDirection::Maximize;
1600 STORM_LOG_THROW(
false, storm::exceptions::InvalidPropertyException,
"Could not derive player 1 optimization direction.");
1601 return storm::OptimizationDirection::Maximize;
1604template<storm::dd::DdType Type>
1608 "Unable to proceed without strategy.");
1611 "Unable to proceed without strategy.");
1615 "Unable to proceed without strategy.");
1620template<storm::dd::DdType Type>
1630template<storm::dd::DdType Type,
typename ModelType>
1631ExplicitQualitativeGameResultMinMax GameBasedMdpModelChecker<Type, ModelType>::computeProb01States(
1637 ExplicitQualitativeGameResultMinMax result;
1645 targetStates, player1Direction, storm::OptimizationDirection::Minimize, &minStrategyPair);
1648 targetStates, player1Direction, storm::OptimizationDirection::Minimize, &minStrategyPair);
1651 targetStates, player1Direction, storm::OptimizationDirection::Maximize, &maxStrategyPair);
1654 targetStates, player1Direction, storm::OptimizationDirection::Maximize, &maxStrategyPair);
1656 STORM_LOG_INFO(
"[" << player1Direction <<
", " << storm::OptimizationDirection::Minimize <<
"]: " << result.prob0Min.player1States.getNumberOfSetBits()
1657 <<
" 'no', " << result.prob1Min.player1States.getNumberOfSetBits() <<
" 'yes'.");
1658 STORM_LOG_INFO(
"[" << player1Direction <<
", " << storm::OptimizationDirection::Maximize <<
"]: " << result.prob0Max.player1States.getNumberOfSetBits()
1659 <<
" 'no', " << result.prob1Max.player1States.getNumberOfSetBits() <<
" 'yes'.");
1664template<storm::dd::DdType Type,
typename ModelType>
1665SymbolicQualitativeGameResultMinMax<Type> GameBasedMdpModelChecker<Type, ModelType>::computeProb01States(
1666 boost::optional<SymbolicQualitativeGameResultMinMax<Type>>
const& previousQualitativeResult,
1669 SymbolicQualitativeGameResultMinMax<Type> result;
1671 if (reuseQualitativeResults) {
1673 if (player1Direction == storm::OptimizationDirection::Minimize) {
1676 storm::OptimizationDirection::Minimize,
true,
true);
1681 game, transitionMatrixBdd, previousQualitativeResult ? previousQualitativeResult.get().prob1Min.player1States : targetStates, candidates);
1685 storm::OptimizationDirection::Minimize,
true,
true, boost::make_optional(prob1MinMinMdp));
1689 storm::OptimizationDirection::Maximize,
true,
true);
1694 boost::optional<storm::dd::Bdd<Type>> prob1Candidates;
1695 if (previousQualitativeResult) {
1696 prob1Candidates = previousQualitativeResult.get().prob1Max.player1States;
1699 storm::OptimizationDirection::Maximize,
true,
true, prob1Candidates);
1703 storm::OptimizationDirection::Maximize,
true,
true);
1707 if (previousQualitativeResult) {
1708 candidates &= previousQualitativeResult.get().prob1Max.player1States;
1714 storm::OptimizationDirection::Maximize,
true,
true, boost::make_optional(prob1MaxMaxMdp));
1718 storm::OptimizationDirection::Minimize,
true,
true);
1722 storm::OptimizationDirection::Minimize,
true,
true, boost::make_optional(prob1MaxMaxMdp));
1726 storm::OptimizationDirection::Minimize,
true,
true);
1728 storm::OptimizationDirection::Minimize,
true,
true);
1730 storm::OptimizationDirection::Maximize,
true,
true);
1732 storm::OptimizationDirection::Maximize,
true,
true);
1735 STORM_LOG_INFO(
"[" << player1Direction <<
", " << storm::OptimizationDirection::Minimize <<
"]: " << result.prob0Min.player1States.getNonZeroCount()
1736 <<
" 'no', " << result.prob1Min.player1States.getNonZeroCount() <<
" 'yes'.");
1737 STORM_LOG_INFO(
"[" << player1Direction <<
", " << storm::OptimizationDirection::Maximize <<
"]: " << result.prob0Max.player1States.getNonZeroCount()
1738 <<
" 'no', " << result.prob1Max.player1States.getNonZeroCount() <<
" 'yes'.");
1744template<storm::dd::DdType Type,
typename ModelType>
1747 uint64_t peakPlayer1States, uint64_t peakTransitions)
const {
1751 std::streamsize originalPrecision = std::cout.precision();
1752 std::cout << std::fixed << std::setprecision(2);
1755 std::cout <<
"Statistics:\n";
1758 std::cout <<
" * peak size of game: " << peakPlayer1States <<
" player 1 states, " << peakTransitions <<
" transitions\n";
1759 std::cout <<
" * refinements: " << refinements <<
'\n';
1762 uint64_t totalAbstractionTimeMillis = totalAbstractionWatch.getTimeInMilliseconds();
1763 uint64_t totalTranslationTimeMillis = totalTranslationWatch.getTimeInMilliseconds();
1764 uint64_t totalStrategyProcessingTimeMillis = totalStrategyProcessingWatch.getTimeInMilliseconds();
1765 uint64_t totalSolutionTimeMillis = totalSolutionWatch.getTimeInMilliseconds();
1766 uint64_t totalRefinementTimeMillis = totalRefinementWatch.getTimeInMilliseconds();
1767 uint64_t setupTime = setupWatch.getTimeInMilliseconds();
1768 uint64_t totalTimeMillis = totalWatch.getTimeInMilliseconds();
1770 std::cout <<
"Time breakdown:\n";
1771 std::cout <<
" * setup: " << setupTime <<
"ms (" << 100 *
static_cast<double>(setupTime) / totalTimeMillis <<
"%)\n";
1772 std::cout <<
" * abstraction: " << totalAbstractionTimeMillis <<
"ms (" << 100 *
static_cast<double>(totalAbstractionTimeMillis) / totalTimeMillis
1775 std::cout <<
" * translation: " << totalTranslationTimeMillis <<
"ms ("
1776 << 100 *
static_cast<double>(totalTranslationTimeMillis) / totalTimeMillis <<
"%)\n";
1777 if (fixPlayer1Strategy || fixPlayer2Strategy) {
1778 std::cout <<
" * strategy processing: " << totalStrategyProcessingTimeMillis <<
"ms ("
1779 << 100 *
static_cast<double>(totalStrategyProcessingTimeMillis) / totalTimeMillis <<
"%)\n";
1782 std::cout <<
" * solution: " << totalSolutionTimeMillis <<
"ms (" << 100 *
static_cast<double>(totalSolutionTimeMillis) / totalTimeMillis <<
"%)\n";
1783 std::cout <<
" * refinement: " << totalRefinementTimeMillis <<
"ms (" << 100 *
static_cast<double>(totalRefinementTimeMillis) / totalTimeMillis
1785 std::cout <<
" ---------------------------------------------\n";
1786 std::cout <<
" * total: " << totalTimeMillis <<
"ms\n\n";
1788 std::cout << std::defaultfloat << std::setprecision(originalPrecision);
1792template<storm::dd::DdType Type,
typename ModelType>
1795 storm::exceptions::InvalidPropertyException,
"The target states have to be given as label or an expression.");
1808template class GameBasedMdpModelChecker<storm::dd::DdType::CUDD, storm::models::symbolic::Dtmc<storm::dd::DdType::CUDD, double>>;
1809template class GameBasedMdpModelChecker<storm::dd::DdType::CUDD, storm::models::symbolic::Mdp<storm::dd::DdType::CUDD, double>>;
1810template class GameBasedMdpModelChecker<storm::dd::DdType::Sylvan, storm::models::symbolic::Dtmc<storm::dd::DdType::Sylvan, double>>;
1811template class GameBasedMdpModelChecker<storm::dd::DdType::Sylvan, storm::models::symbolic::Mdp<storm::dd::DdType::Sylvan, double>>;
1813template class GameBasedMdpModelChecker<storm::dd::DdType::Sylvan, storm::models::symbolic::Dtmc<storm::dd::DdType::Sylvan, storm::RationalNumber>>;
1814template class GameBasedMdpModelChecker<storm::dd::DdType::Sylvan, storm::models::symbolic::Mdp<storm::dd::DdType::Sylvan, storm::RationalNumber>>;
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.
MatrixAndLabeling toLabeledMatrix(std::set< storm::expressions::Variable > const &rowMetaVariables, std::set< storm::expressions::Variable > const &columnMetaVariables, std::set< storm::expressions::Variable > const &groupMetaVariables, storm::dd::Odd const &rowOdd, storm::dd::Odd const &columnOdd, std::vector< std::set< storm::expressions::Variable > > const &labelMetaVariables=std::vector< std::set< storm::expressions::Variable > >()) const
ValueType getMax() const
Retrieves the highest function value of any encoding.
ValueType getMin() const
Retrieves the lowest function value of any encoding.
virtual uint_fast64_t getNonZeroCount() const override
Retrieves the number of encodings that are mapped to a non-zero value.
Add< LibraryType, ValueType > sumAbstract(std::set< storm::expressions::Variable > const &metaVariables) const
Sum-abstracts from the given meta variables.
virtual uint_fast64_t getNodeCount() const override
Retrieves the number of nodes necessary to represent the DD.
Bdd< LibraryType > toBdd() const
Converts the ADD to a BDD by mapping all values unequal to zero to 1.
Bdd< LibraryType > existsAbstract(std::set< storm::expressions::Variable > const &metaVariables) const
Existentially abstracts from the given meta variables.
bool isZero() const
Retrieves whether this DD represents the constant zero function.
virtual uint_fast64_t getNonZeroCount() const override
Retrieves the number of encodings that are mapped to a non-zero value.
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.
Odd createOdd() const
Creates an ODD based on the current BDD.
storm::storage::BitVector toVector(storm::dd::Odd const &rowOdd) const
Converts the BDD to a bit vector.
bool isFalse() const
Checks if the expression is equal to the boolean literal false.
ExpressionManager const & getManager() const
Retrieves the manager responsible for this expression.
bool isTrue() const
Checks if the expression is equal to the boolean literal true.
Expression boolean(bool value) const
Creates an expression that characterizes the given boolean literal.
ExplicitQualitativeGameResult prob0Min
ExplicitQualitativeGameResult prob1Min
ExplicitQualitativeGameResult prob0Max
ExplicitQualitativeGameResult prob1Max
ExplicitQualitativeGameResult & asExplicitQualitativeGameResult()
virtual storm::storage::BitVector const & getStates() const =0
ExplicitQualitativeResult const & getProb0Max() const
ExplicitQualitativeResult const & getProb1Min() const
ExplicitQualitativeResult const & getProb1Max() const
ExplicitQualitativeResult const & getProb0Min() const
std::vector< ValueType > const & getValues() const
ExplicitQuantitativeResult< ValueType > const & getMin() const
ExplicitQuantitativeResult< ValueType > const & getMax() const
SymbolicQualitativeGameResult< Type > prob0Min
SymbolicQualitativeGameResult< Type > prob1Max
SymbolicQualitativeGameResult< Type > prob0Max
SymbolicQualitativeGameResult< Type > prob1Min
boost::optional< storm::dd::Bdd< Type > > player2Strategy
boost::optional< std::pair< ValueType, ValueType > > initialStatesRange
boost::optional< storm::dd::Bdd< Type > > player1Strategy
std::pair< ValueType, ValueType > const & getInitialStatesRange() const
storm::dd::Bdd< Type > const & getPlayer2Strategy() const
storm::dd::Add< Type, ValueType > values
storm::dd::Bdd< Type > const & getPlayer1Strategy() const
void setShowNonStrategyAlternatives(bool value)
void exportToJson(std::string const &filename, std::vector< uint64_t > const &player1Groups, std::vector< uint64_t > const &player2Groups, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::BitVector const &initialStates, storm::storage::BitVector const &constraintStates, storm::storage::BitVector const &targetStates, ExplicitQuantitativeResultMinMax< ValueType > const &quantitativeResult, storage::ExplicitGameStrategyPair const *minStrategyPair, storage::ExplicitGameStrategyPair const *maxStrategyPair)
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
ModelType::ValueType ValueType
GameBasedMdpModelChecker(storm::storage::SymbolicModelDescription const &model, GameBasedMdpModelCheckerOptions const &options=GameBasedMdpModelCheckerOptions(), std::shared_ptr< storm::utility::solver::SmtSolverFactory > const &smtSolverFactory=std::make_shared< storm::utility::solver::MathsatSmtSolverFactory >())
Constructs a model checker whose underlying model is implicitly given by the provided program.
virtual bool canHandle(storm::modelchecker::CheckTask< storm::logic::Formula, ValueType > const &checkTask) const override
Overridden methods from super class.
VariableSet & getGlobalVariables()
Retrieves the variables of this automaton.
ModelType const & getModelType() const
Retrieves the type of the model.
storm::expressions::Expression getLabelExpression(Variable const &transientVariable, std::vector< std::reference_wrapper< Automaton const > > const &automata) const
Creates the expression that characterizes all states in which the provided transient boolean variable...
Model flattenComposition(std::shared_ptr< storm::utility::solver::SmtSolverFactory > const &smtSolverFactory=std::make_shared< storm::utility::solver::SmtSolverFactory >()) const
Flatten the composition to obtain an equivalent model that contains exactly one automaton that has th...
detail::Variables< Variable > getBooleanVariables()
Retrieves the boolean variables in this set.
bool isBoundSet() const
Retrieves whether there is a bound with which the values for the states will be compared.
ValueType getBoundThreshold() const
Retrieves the value of the bound (if set).
storm::logic::ComparisonType const & getBoundComparisonType() const
Retrieves the comparison type of the bound (if set).
bool isOptimizationDirectionSet() const
Retrieves whether an optimization direction was set.
FormulaType const & getFormula() const
Retrieves the formula from this task.
storm::OptimizationDirection const & getOptimizationDirection() const
Retrieves the optimization direction (if set).
bool isOnlyInitialStatesRelevantSet() const
Retrieves whether only the initial states are relevant in the computation.
static std::vector< ValueType > computeUntilProbabilities(Environment const &env, storm::solver::SolveGoal< ValueType > &&goal, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::SparseMatrix< ValueType > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates, bool qualitative, ModelCheckerHint const &hint=ModelCheckerHint())
storm::dd::DdManager< Type > & getManager() const
Retrieves the manager responsible for the DDs that represent this model.
storm::dd::Add< Type, ValueType > const & getTransitionMatrix() const
Retrieves the matrix representing the transitions of the model.
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...
storm::dd::Bdd< Type > const & getInitialStates() const
Retrieves the initial states of the model.
std::vector< std::pair< storm::expressions::Variable, storm::expressions::Variable > > const & getRowColumnMetaVariablePairs() const
Retrieves the pairs of row and column meta variables.
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.
virtual uint_fast64_t getNumberOfTransitions() const override
Returns the number of (non-zero) transitions of the model.
storm::dd::Bdd< Type > const & getReachableStates() const
Retrieves the reachable states of the model.
virtual uint_fast64_t getNumberOfStates() const override
Returns the number of states of the model.
virtual std::set< storm::expressions::Variable > const & getNondeterminismVariables() const override
Retrieves the meta variables used to encode the nondeterminism in the model.
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.
uint64_t getNumberOfPlayer2States() const
Retrieves the number of player 2 states in the game.
storm::dd::Bdd< Type > getIllegalPlayer2Mask() const
Retrieves a BDD characterizing all illegal player 2 choice encodings in the model.
ModelType getModelType() const
Retrieves the model type of the model.
Program substituteFormulas() const
Substitutes all formulas appearing in the expressions of the program by their defining expressions.
std::size_t getNumberOfModules() const
Retrieves the number of modules in the program.
Program flattenModules(std::shared_ptr< storm::utility::solver::SmtSolverFactory > const &smtSolverFactory=std::shared_ptr< storm::utility::solver::SmtSolverFactory >(new storm::utility::solver::SmtSolverFactory())) const
Creates an equivalent program that contains exactly one module.
virtual std::unique_ptr< GameSolver< ValueType > > create(Environment const &env, storm::storage::SparseMatrix< storm::storage::sparse::state_type > const &player1Matrix, storm::storage::SparseMatrix< ValueType > const &player2Matrix) const
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
A bit vector that is internally represented as a vector of 64-bit values.
bool isDisjointFrom(BitVector const &other) const
Checks whether none of the bits that are set in the current bit vector are also set in the given bit ...
bool empty() const
Retrieves whether no bits are set to true in this bit vector.
bool isSubsetOf(BitVector const &other) const
Checks whether all bits that are set in the current bit vector are also set in the given bit vector.
void set(uint_fast64_t index, bool value=true)
Sets the given truth value at the given index.
size_t size() const
Retrieves the number of bits this bit vector can store.
uint_fast64_t getNumberOfSetBits() const
Returns the number of bits that are set to true in this bit vector.
bool get(uint_fast64_t index) const
Retrieves the truth value of the bit at the given index and performs a bound check.
bool hasDefinedChoice(uint64_t state) const
void setChoice(uint64_t state, uint64_t choice)
uint64_t getChoice(uint64_t state) const
ExplicitGameStrategy & getPlayer1Strategy()
ExplicitGameStrategy & getPlayer2Strategy()
A class that can be used to build a sparse matrix by adding value by value.
void addNextValue(index_type row, index_type column, value_type const &value)
Sets the matrix entry at the given row and column to the given value.
SparseMatrix< value_type > build(index_type overriddenRowCount=0, index_type overriddenColumnCount=0, index_type overriddenRowGroupCount=0)
A class that holds a possibly non-square matrix in the compressed row storage format.
const_rows getRow(index_type row) const
Returns an object representing the given row.
SparseMatrix getSubmatrix(bool useGroups, storm::storage::BitVector const &rowConstraint, storm::storage::BitVector const &columnConstraint, bool insertDiagonalEntries=false, storm::storage::BitVector const &makeZeroColumns=storm::storage::BitVector()) const
Creates a submatrix of the current matrix by dropping all rows and columns whose bits are not set to ...
std::vector< index_type > swapRowGroupIndices(std::vector< index_type > &&newRowGrouping)
Swaps the grouping of rows of this matrix.
value_type multiplyRowWithVector(index_type row, std::vector< value_type > const &vector) const
Multiplies a single row of the matrix with the given vector and returns the result.
index_type getRowGroupCount() const
Returns the number of row groups in the matrix.
std::vector< index_type > const & getRowGroupIndices() const
Returns the grouping of rows of this matrix.
std::vector< value_type > getConstrainedRowGroupSumVector(storm::storage::BitVector const &rowGroupConstraint, storm::storage::BitVector const &columnConstraint) const
Computes a vector whose entries represent the sums of selected columns for all rows in selected row g...
storm::storage::SparseMatrix< value_type > transpose(bool joinGroups=false, bool keepZeros=false) const
Transposes the matrix.
storm::prism::Program const & asPrismProgram() const
std::vector< storm::expressions::Variable > getUndefinedConstants() const
bool hasUndefinedConstants() const
bool isPrismProgram() const
storm::jani::Model const & asJaniModel() const
bool isZero(ValueType const &value) const
bool isEqual(ValueType const &value1, ValueType const &value2) const
A class that provides convenience operations to display run times.
#define STORM_LOG_INFO(message)
#define STORM_LOG_WARN(message)
#define STORM_LOG_DEBUG(message)
#define STORM_LOG_TRACE(message)
#define STORM_LOG_ASSERT(cond, message)
#define STORM_LOG_WARN_COND(cond, message)
#define STORM_LOG_THROW(cond, exception, message)
SFTBDDChecker::ValueType ValueType
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)
void postProcessStrategies(storm::OptimizationDirection const &player1Direction, storage::ExplicitGameStrategyPair &minStrategyPair, storage::ExplicitGameStrategyPair &maxStrategyPair, std::vector< uint64_t > const &player1Groups, std::vector< uint64_t > const &player2Groups, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::BitVector const &constraintStates, storm::storage::BitVector const &targetStates, ExplicitQualitativeGameResultMinMax const &qualitativeResult, bool redirectPlayer1, bool redirectPlayer2, bool sanityCheck)
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 checkQualitativeStrategies(bool prob0, SymbolicQualitativeGameResult< Type > const &result, storm::dd::Bdd< Type > const &targetStates)
SymbolicQuantitativeGameResult< Type, ValueType > solveMaybeStates(Environment const &env, storm::OptimizationDirection const &player1Direction, storm::OptimizationDirection const &player2Direction, storm::gbar::abstraction::MenuGame< Type, ValueType > const &game, storm::dd::Bdd< Type > const &maybeStates, storm::dd::Bdd< Type > const &prob1States, boost::optional< SymbolicQuantitativeGameResult< Type, ValueType > > const &startInfo=boost::none)
void closeFile(std::ofstream &stream)
Close the given file after writing.
void openFile(std::string const &filepath, std::ofstream &filestream, bool append=false, bool silent=false)
Open the given file for writing.
bool isLowerBound(ComparisonType t)
bool isStrict(ComparisonType t)
FragmentSpecification reachability()
std::pair< storm::RationalNumber, storm::RationalNumber > count(std::vector< storm::storage::BitVector > const &origSets, std::vector< storm::storage::BitVector > const &intersects, std::vector< storm::storage::BitVector > const &intersectsInfo, storm::RationalNumber val, bool plus, uint64_t remdepth)
SettingsType const & getModule()
Get module.
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.
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 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...
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.
void selectVectorValues(std::vector< T > &vector, storm::storage::BitVector const &positions, std::vector< T > const &values)
Selects the elements from a vector at the specified positions and writes them consecutively into anot...
ValueType max(ValueType const &first, ValueType const &second)
ValueType min(ValueType const &first, ValueType const &second)
ValueType abs(ValueType const &number)
Converts the ADD to a row-grouped (sparse) matrix.
std::vector< std::vector< uint64_t > > labelings
storm::storage::SparseMatrix< ValueType > matrix
storm::storage::BitVector const & getPlayer1States() const
storm::storage::BitVector const & getPlayer2States() const
bool hasPlayer1Strategy() const
storm::dd::Bdd< Type > const & getPlayer2States() const
bool hasPlayer2Strategy() const
storm::dd::Bdd< Type > const & getPlayer1Strategy() const
storm::dd::Bdd< Type > const & getPlayer2Strategy() const
storm::dd::Bdd< Type > const & getPlayer1States() const