diff --git a/src/storm/abstraction/MenuGameRefiner.cpp b/src/storm/abstraction/MenuGameRefiner.cpp new file mode 100644 index 000000000..e31327157 --- /dev/null +++ b/src/storm/abstraction/MenuGameRefiner.cpp @@ -0,0 +1,22 @@ +#include "storm/abstraction/MenuGameRefiner.h" + +#include "storm/abstraction/MenuGameAbstractor.h" + +namespace storm { + namespace abstraction { + + template + MenuGameRefiner::MenuGameRefiner(MenuGameAbstractor& abstractor) : abstractor(abstractor) { + // Intentionally left empty. + } + + template + void MenuGameRefiner::refine(std::vector const& predicates) const { + abstractor.get().refine(predicates); + } + + template class MenuGameRefiner; + template class MenuGameRefiner; + + } +} diff --git a/src/storm/abstraction/MenuGameRefiner.h b/src/storm/abstraction/MenuGameRefiner.h new file mode 100644 index 000000000..b6a9e7482 --- /dev/null +++ b/src/storm/abstraction/MenuGameRefiner.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include + +#include "storm/storage/expressions/Expression.h" + +#include "storm/storage/dd/DdType.h" + +namespace storm { + namespace abstraction { + + template + class MenuGameAbstractor; + + template + class MenuGameRefiner { + public: + /*! + * Creates a refiner for the provided abstractor. + */ + MenuGameRefiner(MenuGameAbstractor& abstractor); + + /*! + * Refines the abstractor with the given set of predicates. + */ + void refine(std::vector const& predicates) const; + + + + private: + /// The underlying abstractor to refine. + std::reference_wrapper> abstractor; + }; + + } +} diff --git a/src/storm/abstraction/StateSetAbstractor.cpp b/src/storm/abstraction/StateSetAbstractor.cpp index 0483635b6..50da8f008 100644 --- a/src/storm/abstraction/StateSetAbstractor.cpp +++ b/src/storm/abstraction/StateSetAbstractor.cpp @@ -14,7 +14,7 @@ namespace storm { namespace abstraction { template - StateSetAbstractor::StateSetAbstractor(AbstractionInformation& abstractionInformation, std::set const& allVariables, std::vector const& statePredicates, std::shared_ptr const& smtSolverFactory) : smtSolver(smtSolverFactory->create(abstractionInformation.getExpressionManager())), abstractionInformation(abstractionInformation), localExpressionInformation(allVariables), relevantPredicatesAndVariables(), concretePredicateVariables(), needsRecomputation(false), cachedBdd(abstractionInformation.getDdManager().getBddZero()), constraint(abstractionInformation.getDdManager().getBddOne()) { + StateSetAbstractor::StateSetAbstractor(AbstractionInformation& abstractionInformation, std::set const& allVariables, std::vector const& statePredicates, std::shared_ptr const& smtSolverFactory) : smtSolver(smtSolverFactory->create(abstractionInformation.getExpressionManager())), abstractionInformation(abstractionInformation), localExpressionInformation(allVariables), relevantPredicatesAndVariables(), concretePredicateVariables(), needsRecomputation(false), cachedBdd(abstractionInformation.getDdManager().getBddOne()), constraint(abstractionInformation.getDdManager().getBddOne()) { // Assert all state predicates. for (auto const& predicate : statePredicates) { @@ -101,8 +101,7 @@ namespace storm { STORM_LOG_TRACE("Recomputing BDD for state set abstraction."); storm::dd::Bdd result = this->getAbstractionInformation().getDdManager().getBddZero(); - uint_fast64_t modelCounter = 0; - smtSolver->allSat(decisionVariables, [&result,this,&modelCounter] (storm::solver::SmtSolver::ModelReference const& model) { result |= getStateBdd(model); ++modelCounter; return true; } ); + smtSolver->allSat(decisionVariables, [&result,this] (storm::solver::SmtSolver::ModelReference const& model) { result |= getStateBdd(model); return true; } ); cachedBdd = result; } diff --git a/src/storm/abstraction/prism/AbstractCommand.cpp b/src/storm/abstraction/prism/AbstractCommand.cpp index 63a889472..dd9b51efc 100644 --- a/src/storm/abstraction/prism/AbstractCommand.cpp +++ b/src/storm/abstraction/prism/AbstractCommand.cpp @@ -23,7 +23,7 @@ namespace storm { namespace abstraction { namespace prism { template - AbstractCommand::AbstractCommand(storm::prism::Command const& command, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool guardIsPredicate) : smtSolver(smtSolverFactory->create(abstractionInformation.getExpressionManager())), abstractionInformation(abstractionInformation), command(command), localExpressionInformation(abstractionInformation.getVariables()), evaluator(abstractionInformation.getExpressionManager()), relevantPredicatesAndVariables(), cachedDd(abstractionInformation.getDdManager().getBddZero(), 0), decisionVariables(), guardIsPredicate(guardIsPredicate), abstractGuard(abstractionInformation.getDdManager().getBddZero()), bottomStateAbstractor(abstractionInformation, abstractionInformation.getExpressionVariables(), {!command.getGuardExpression()}, smtSolverFactory) { + AbstractCommand::AbstractCommand(storm::prism::Command const& command, AbstractionInformation& abstractionInformation, std::shared_ptr const& smtSolverFactory, bool guardIsPredicate) : smtSolver(smtSolverFactory->create(abstractionInformation.getExpressionManager())), abstractionInformation(abstractionInformation), command(command), localExpressionInformation(abstractionInformation.getVariables()), evaluator(abstractionInformation.getExpressionManager()), relevantPredicatesAndVariables(), cachedDd(abstractionInformation.getDdManager().getBddZero(), 0), decisionVariables(), guardIsPredicate(guardIsPredicate), forceRecomputation(true), abstractGuard(abstractionInformation.getDdManager().getBddZero()), bottomStateAbstractor(abstractionInformation, abstractionInformation.getExpressionVariables(), {!command.getGuardExpression()}, smtSolverFactory) { // Make the second component of relevant predicates have the right size. relevantPredicatesAndVariables.second.resize(command.getNumberOfUpdates()); @@ -36,17 +36,10 @@ namespace storm { // Assert the guard of the command. smtSolver->add(command.getGuardExpression()); - - // Refine the command based on all initial predicates. - std::vector allPredicateIndices(abstractionInformation.getNumberOfPredicates()); - for (uint_fast64_t index = 0; index < abstractionInformation.getNumberOfPredicates(); ++index) { - allPredicateIndices[index] = index; - } - this->refine(allPredicateIndices, true); } template - void AbstractCommand::refine(std::vector const& predicates, bool forceRecomputation) { + void AbstractCommand::refine(std::vector const& predicates) { // Add all predicates to the variable partition. for (auto predicateIndex : predicates) { localExpressionInformation.addExpression(this->getAbstractionInformation().getPredicateByIndex(predicateIndex), predicateIndex); @@ -69,6 +62,9 @@ namespace storm { // Finally recompute the cached BDD. this->recomputeCachedBdd(); + + // Disable forcing recomputation until it is set again. + forceRecomputation = false; } // Refine bottom state abstractor. Note that this does not trigger a recomputation yet. @@ -322,6 +318,7 @@ namespace storm { // If the guard of this command is a predicate, there are not bottom states/transitions. if (guardIsPredicate) { + STORM_LOG_TRACE("Guard is predicate, no bottom state transitions for this command."); return result; } @@ -329,7 +326,7 @@ namespace storm { // still has a transition to a bottom state. bottomStateAbstractor.constrain(reachableStates && abstractGuard); result.states = bottomStateAbstractor.getAbstractStates(); - + // Now equip all these states with an actual transition to a bottom state. result.transitions = result.states && this->getAbstractionInformation().getAllPredicateIdentities() && this->getAbstractionInformation().getBottomStateBdd(false, false); diff --git a/src/storm/abstraction/prism/AbstractCommand.h b/src/storm/abstraction/prism/AbstractCommand.h index 5a67d4a30..600693bbf 100644 --- a/src/storm/abstraction/prism/AbstractCommand.h +++ b/src/storm/abstraction/prism/AbstractCommand.h @@ -65,9 +65,8 @@ namespace storm { * Refines the abstract command with the given predicates. * * @param predicates The new predicates. - * @param forceRecomputation If set, the BDD is recomputed even if the relevant predicates have not changed. */ - void refine(std::vector const& predicates, bool forceRecomputation = false); + void refine(std::vector const& predicates); /*! * Computes the abstraction of the command wrt. to the current set of predicates. @@ -227,6 +226,9 @@ namespace storm { // is no need to compute bottom states. bool guardIsPredicate; + // A flag remembering whether we need to force recomputation of the BDD. + bool forceRecomputation; + // The abstract guard of the command. This is only used if the guard is not a predicate, because it can // then be used to constrain the bottom state abstractor. storm::dd::Bdd abstractGuard; diff --git a/src/storm/abstraction/prism/AbstractProgram.cpp b/src/storm/abstraction/prism/AbstractProgram.cpp index 29e627806..c6738a740 100644 --- a/src/storm/abstraction/prism/AbstractProgram.cpp +++ b/src/storm/abstraction/prism/AbstractProgram.cpp @@ -29,7 +29,6 @@ namespace storm { template AbstractProgram::AbstractProgram(storm::prism::Program const& program, - std::vector const& initialPredicates, std::shared_ptr const& smtSolverFactory, bool addAllGuards, bool splitPredicates) : program(program), smtSolverFactory(smtSolverFactory), abstractionInformation(program.getManager()), modules(), initialStateAbstractor(abstractionInformation, program.getAllExpressionVariables(), {program.getInitialStatesExpression()}, this->smtSolverFactory), splitPredicates(splitPredicates), splitter(), equivalenceChecker(smtSolverFactory->create(abstractionInformation.getExpressionManager()), abstractionInformation.getExpressionManager().boolean(true)), addedAllGuards(addAllGuards), currentGame(nullptr) { @@ -58,7 +57,7 @@ namespace storm { } maximalUpdateCount = std::max(maximalUpdateCount, static_cast(command.getNumberOfUpdates())); } - + totalNumberOfCommands += module.getNumberOfCommands(); } @@ -76,23 +75,19 @@ namespace storm { commandUpdateProbabilitiesAdd = modules.front().getCommandUpdateProbabilitiesAdd(); // Now that we have created all other DD variables, we create the DD variables for the predicates. - std::vector> allPredicates; - for (auto const& predicate : initialPredicates) { - allPredicates.push_back(std::make_pair(predicate, false)); - } + std::vector> initialPredicates; if (addAllGuards) { for (auto const& guard : allGuards) { - allPredicates.push_back(std::make_pair(guard, true)); + initialPredicates.push_back(std::make_pair(guard, true)); } } + // Finally, refine using the all predicates and build game as a by-product. - this->refine(allPredicates); + this->refine(initialPredicates); } template void AbstractProgram::refine(std::vector> const& predicates) { - STORM_LOG_THROW(!predicates.empty(), storm::exceptions::InvalidArgumentException, "Cannot refine without predicates."); - // Add the predicates to the global list of predicates. std::vector newPredicateIndices; for (auto const& predicateAllowSplitPair : predicates) { @@ -132,7 +127,7 @@ namespace storm { // Refine initial state abstractor. initialStateAbstractor.refine(newPredicateIndices); - + // Finally, we rebuild the game. currentGame = buildGame(); } @@ -240,7 +235,7 @@ namespace storm { #endif std::map upperChoiceUpdateToSuccessorMapping = decodeChoiceToUpdateSuccessorMapping(upperChoice); STORM_LOG_ASSERT(lowerChoiceUpdateToSuccessorMapping.size() == upperChoiceUpdateToSuccessorMapping.size(), "Mismatching sizes after decode (" << lowerChoiceUpdateToSuccessorMapping.size() << " vs. " << upperChoiceUpdateToSuccessorMapping.size() << ")."); - + #ifdef LOCAL_DEBUG std::cout << "lower" << std::endl; for (auto const& entry : lowerChoiceUpdateToSuccessorMapping) { @@ -268,6 +263,9 @@ namespace storm { for (uint_fast64_t predicateIndex = 0; predicateIndex < lowerIt->second.size(); ++predicateIndex) { if (lowerIt->second.get(predicateIndex) != upperIt->second.get(predicateIndex)) { // Now we know the point of the deviation (command, update, predicate). + std::cout << "ref" << std::endl; + std::cout << abstractionInformation.getPredicateByIndex(predicateIndex) << std::endl; + std::cout << concreteCommand.getUpdate(updateIndex) << std::endl; newPredicate = abstractionInformation.getPredicateByIndex(predicateIndex).substitute(concreteCommand.getUpdate(updateIndex).getAsVariableToExpressionMap()).simplify(); break; } @@ -298,12 +296,12 @@ namespace storm { STORM_LOG_ASSERT(currentGame != nullptr, "Game was not properly created."); return abstractionInformation.getPredicateSourceVariable(predicate); } - + template std::unique_ptr> AbstractProgram::buildGame() { // As long as there is only one module, we only build its game representation. GameBddResult game = modules.front().getAbstractBdd(); - + // Construct a set of all unnecessary variables, so we can abstract from it. std::set variablesToAbstract(abstractionInformation.getPlayer1VariableSet(abstractionInformation.getPlayer1VariableCount())); auto player2Variables = abstractionInformation.getPlayer2VariableSet(game.numberOfPlayer2Variables); @@ -326,7 +324,7 @@ namespace storm { if (!deadlockStates.isZero()) { deadlockTransitions = (deadlockStates && abstractionInformation.getAllPredicateIdentities() && abstractionInformation.encodePlayer1Choice(0, abstractionInformation.getPlayer1VariableCount()) && abstractionInformation.encodePlayer2Choice(0, game.numberOfPlayer2Variables) && abstractionInformation.encodeAux(0, 0, abstractionInformation.getAuxVariableCount())).template toAdd(); } - + // Compute bottom states and the appropriate transitions if necessary. BottomStateResult bottomStateResult(abstractionInformation.getDdManager().getBddZero(), abstractionInformation.getDdManager().getBddZero()); bool hasBottomStates = false; @@ -345,17 +343,17 @@ namespace storm { reachableStates &= abstractionInformation.getBottomStateBdd(true, true); initialStates &= abstractionInformation.getBottomStateBdd(true, true); - // If there are bottom transitions, exnted the transition matrix and reachable states now. + // If there are bottom transitions, exnted the transition matrix and reachable states now. if (hasBottomStates) { transitionMatrix += bottomStateResult.transitions.template toAdd(); reachableStates |= bottomStateResult.states; } - + std::set usedPlayer2Variables(abstractionInformation.getPlayer2Variables().begin(), abstractionInformation.getPlayer2Variables().begin() + game.numberOfPlayer2Variables); std::set allNondeterminismVariables = usedPlayer2Variables; allNondeterminismVariables.insert(abstractionInformation.getPlayer1Variables().begin(), abstractionInformation.getPlayer1Variables().end()); - + std::set allSourceVariables(abstractionInformation.getSourceVariables()); allSourceVariables.insert(abstractionInformation.getBottomStateVariable(true)); std::set allSuccessorVariables(abstractionInformation.getSuccessorVariables()); @@ -363,7 +361,7 @@ namespace storm { return std::make_unique>(abstractionInformation.getDdManagerAsSharedPointer(), reachableStates, initialStates, abstractionInformation.getDdManager().getBddZero(), transitionMatrix, bottomStateResult.states, allSourceVariables, allSuccessorVariables, abstractionInformation.getExtendedSourceSuccessorVariablePairs(), std::set(abstractionInformation.getPlayer1Variables().begin(), abstractionInformation.getPlayer1Variables().end()), usedPlayer2Variables, allNondeterminismVariables, auxVariables, abstractionInformation.getPredicateToBddMap()); } - + template void AbstractProgram::exportToDot(std::string const& filename, storm::dd::Bdd const& highlightStatesBdd, storm::dd::Bdd const& filter) const { std::ofstream out(filename); @@ -402,7 +400,7 @@ namespace storm { } highlightStates.insert(stateName.str()); } - + out << "digraph game {" << std::endl; // Create the player 1 nodes. @@ -504,7 +502,7 @@ namespace storm { template class AbstractProgram; template class AbstractProgram; #ifdef STORM_HAVE_CARL - template class AbstractProgram; + template class AbstractProgram; #endif } } diff --git a/src/storm/abstraction/prism/AbstractProgram.h b/src/storm/abstraction/prism/AbstractProgram.h index 5cfca0f41..d20ca12e0 100644 --- a/src/storm/abstraction/prism/AbstractProgram.h +++ b/src/storm/abstraction/prism/AbstractProgram.h @@ -42,12 +42,11 @@ namespace storm { * * @param expressionManager The manager responsible for the expressions of the program. * @param program The concrete program for which to build the abstraction. - * @param initialPredicates The initial set of predicates. * @param smtSolverFactory A factory that is to be used for creating new SMT solvers. * @param addAllGuards A flag that indicates whether all guards of the program should be added to the initial set of predicates. * @param splitPredicates A flag that indicates whether the predicates are to be split into atoms before being added. */ - AbstractProgram(storm::prism::Program const& program, std::vector const& initialPredicates, std::shared_ptr const& smtSolverFactory = std::make_shared(), bool addAllGuards = false, bool splitPredicates = false); + AbstractProgram(storm::prism::Program const& program, std::shared_ptr const& smtSolverFactory = std::make_shared(), bool addAllGuards = false, bool splitPredicates = false); AbstractProgram(AbstractProgram const&) = default; AbstractProgram& operator=(AbstractProgram const&) = default; diff --git a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp index e6ce56eca..7c5a22861 100644 --- a/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp +++ b/src/storm/abstraction/prism/PrismMenuGameAbstractor.cpp @@ -10,7 +10,7 @@ namespace storm { namespace prism { template - PrismMenuGameAbstractor::PrismMenuGameAbstractor(storm::prism::Program const& program, std::vector const& initialPredicates, std::shared_ptr const& smtSolverFactory) : abstractProgram(program, initialPredicates, smtSolverFactory, storm::settings::getModule().isAddAllGuardsSet(), storm::settings::getModule().isSplitPredicatesSet()) { + PrismMenuGameAbstractor::PrismMenuGameAbstractor(storm::prism::Program const& program, std::shared_ptr const& smtSolverFactory) : abstractProgram(program, smtSolverFactory, storm::settings::getModule().isAddAllGuardsSet(), storm::settings::getModule().isSplitPredicatesSet()) { // Intentionally left empty. } diff --git a/src/storm/abstraction/prism/PrismMenuGameAbstractor.h b/src/storm/abstraction/prism/PrismMenuGameAbstractor.h index 7214a380e..84fd5ec36 100644 --- a/src/storm/abstraction/prism/PrismMenuGameAbstractor.h +++ b/src/storm/abstraction/prism/PrismMenuGameAbstractor.h @@ -11,7 +11,7 @@ namespace storm { template class PrismMenuGameAbstractor : public MenuGameAbstractor { public: - PrismMenuGameAbstractor(storm::prism::Program const& program, std::vector const& initialPredicates, std::shared_ptr const& smtSolverFactory = std::make_shared()); + PrismMenuGameAbstractor(storm::prism::Program const& program, std::shared_ptr const& smtSolverFactory = std::make_shared()); virtual storm::abstraction::MenuGame abstract() override; virtual void refine(std::vector const& predicates) override; diff --git a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp index cf5596dfa..fc0313ab5 100644 --- a/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp +++ b/src/storm/modelchecker/abstraction/GameBasedMdpModelChecker.cpp @@ -12,6 +12,7 @@ #include "storm/storage/dd/DdManager.h" #include "storm/abstraction/prism/PrismMenuGameAbstractor.h" +#include "storm/abstraction/MenuGameRefiner.h" #include "storm/logic/FragmentSpecification.h" @@ -261,6 +262,7 @@ namespace storm { if (lowerChoicesDifferent) { STORM_LOG_TRACE("Refining based on lower choice."); auto refinementStart = std::chrono::high_resolution_clock::now(); + abstractor.refine(pivotState, (pivotState && minPlayer1Strategy).existsAbstract(game.getRowVariables()), lowerChoice1, lowerChoice2); auto refinementEnd = std::chrono::high_resolution_clock::now(); STORM_LOG_TRACE("Refinement completed in " << std::chrono::duration_cast(refinementEnd - refinementStart).count() << "ms."); @@ -466,9 +468,11 @@ namespace storm { storm::OptimizationDirection player1Direction = getPlayer1Direction(checkTask); // Create the abstractor. - storm::abstraction::prism::PrismMenuGameAbstractor abstractor(preprocessedModel.asPrismProgram(), initialPredicates, smtSolverFactory); + storm::abstraction::prism::PrismMenuGameAbstractor abstractor(preprocessedModel.asPrismProgram(), smtSolverFactory); - // TODO: create refiner and move initial predicates there. + // Create a refiner that can be used to refine the abstraction when needed. + storm::abstraction::MenuGameRefiner refiner(abstractor); + refiner.refine(initialPredicates); // Enter the main-loop of abstraction refinement. for (uint_fast64_t iterations = 0; iterations < 10000; ++iterations) { @@ -526,6 +530,7 @@ namespace storm { } } + // (6) if we arrived at this point and no refinement was made, we need to compute the quantitative solution. if (!qualitativeRefinement) { // At this point, we know that we cannot answer the query without further numeric computation. @@ -534,14 +539,14 @@ namespace storm { STORM_LOG_TRACE("Starting numerical solution step."); auto quantitativeStart = std::chrono::high_resolution_clock::now(); - // Solve the min values and check whether we can give the answer already. + // (7) Solve the min values and check whether we can give the answer already. QuantitativeResult minResult = computeQuantitativeResult(player1Direction, storm::OptimizationDirection::Minimize, game, qualitativeResult, initialStatesAdd, maybeMin); result = checkForResultAfterQuantitativeCheck(checkTask, storm::OptimizationDirection::Minimize, minResult.initialStateValue); if (result) { return result; } - // Solve the max values and check whether we can give the answer already. + // (8) Solve the max values and check whether we can give the answer already. QuantitativeResult maxResult = computeQuantitativeResult(player1Direction, storm::OptimizationDirection::Maximize, game, qualitativeResult, initialStatesAdd, maybeMax, boost::make_optional(minResult)); result = checkForResultAfterQuantitativeCheck(checkTask, storm::OptimizationDirection::Maximize, maxResult.initialStateValue); if (result) { @@ -551,27 +556,20 @@ namespace storm { auto quantitativeEnd = std::chrono::high_resolution_clock::now(); STORM_LOG_DEBUG("Obtained quantitative bounds [" << minResult.initialStateValue << ", " << maxResult.initialStateValue << "] on the actual value for the initial states in " << std::chrono::duration_cast(quantitativeEnd - quantitativeStart).count() << "ms."); + // (9) Check whether the lower and upper bounds are close enough to terminate with an answer. result = checkForResultAfterQuantitativeCheck(checkTask, minResult.initialStateValue, maxResult.initialStateValue); if (result) { return result; } - // If we arrived at this point, it means that we have all qualitative and quantitative information - // about the game, but we could not yet answer the query. In this case, we need to refine. - // Make sure that all strategies are still valid strategies. STORM_LOG_ASSERT(minResult.player1Strategy.template toAdd().sumAbstract(game.getPlayer1Variables()).getMax() <= 1, "Player 1 strategy for min is illegal."); STORM_LOG_ASSERT(maxResult.player1Strategy.template toAdd().sumAbstract(game.getPlayer1Variables()).getMax() <= 1, "Player 1 strategy for max is illegal."); STORM_LOG_ASSERT(minResult.player2Strategy.template toAdd().sumAbstract(game.getPlayer2Variables()).getMax() <= 1, "Player 2 strategy for min is illegal."); STORM_LOG_ASSERT(maxResult.player2Strategy.template toAdd().sumAbstract(game.getPlayer2Variables()).getMax() <= 1, "Player 2 strategy for max is illegal."); -#ifdef LOCAL_DEBUG - // Check whether the strategies coincide over the reachable parts. -// storm::dd::Bdd tmp = game.getTransitionMatrix().toBdd() && (minMaybeStateResult.player1Strategy || maxMaybeStateResult.player1Strategy) && (minMaybeStateResult.player2Strategy || maxMaybeStateResult.player2Strategy); -// storm::dd::Bdd commonReach = storm::utility::dd::computeReachableStates(initialStates, tmp.existsAbstract(game.getNondeterminismVariables()), game.getRowVariables(), game.getColumnVariables()); -// STORM_LOG_ASSERT((commonReach && minMaybeStateResult.player1Strategy) != (commonReach && maxMaybeStateResult.player1Strategy) || (commonReach && minMaybeStateResult.player2Strategy) != (commonReach && maxMaybeStateResult.player2Strategy), "The strategies fully coincide."); -#endif - + // (10) If we arrived at this point, it means that we have all qualitative and quantitative + // information about the game, but we could not yet answer the query. In this case, we need to refine. refineAfterQuantitativeCheck(abstractor, game, transitionMatrixBdd, minResult, maxResult); } auto iterationEnd = std::chrono::high_resolution_clock::now(); @@ -632,7 +630,11 @@ namespace storm { result = storm::utility::graph::performProb1(game, transitionMatrixBdd, constraintStates, targetStates, player1Direction, player2Direction, true, true); } - STORM_LOG_ASSERT(result.hasPlayer1Strategy() && (result.getPlayer1States().isZero() || !result.getPlayer1Strategy().isZero()), "Unable to proceed without strategy."); + if (prob0) { + STORM_LOG_ASSERT(result.hasPlayer1Strategy() && (result.getPlayer1States().isZero() || !result.getPlayer1Strategy().isZero()), "Unable to proceed without strategy."); + } else { + STORM_LOG_ASSERT(result.hasPlayer1Strategy() && ((result.getPlayer1States() && !targetStates).isZero() || !result.getPlayer1Strategy().isZero()), "Unable to proceed without strategy."); + } STORM_LOG_ASSERT(result.hasPlayer2Strategy() && (result.getPlayer2States().isZero() || !result.getPlayer2Strategy().isZero()), "Unable to proceed without strategy."); STORM_LOG_TRACE("Computed states with probability " << (prob0 ? "0" : "1") << " (player 1: " << player1Direction << ", player 2: " << player2Direction << "): " << result.getPlayer1States().getNonZeroCount() << " '" << (prob0 ? "no" : "yes") << "' states."); diff --git a/src/storm/utility/graph.cpp b/src/storm/utility/graph.cpp index 499817ce0..ceecdfb18 100644 --- a/src/storm/utility/graph.cpp +++ b/src/storm/utility/graph.cpp @@ -961,7 +961,10 @@ namespace storm { // Since we have determined the complements of the desired sets, we need to complement it now. player1States = !player1States && model.getReachableStates(); - player2States = !player2States && model.getReachableStates(); + + std::set variablesToAbstract(model.getColumnVariables()); + variablesToAbstract.insert(model.getPlayer2Variables().begin(), model.getPlayer2Variables().end()); + player2States = !player2States && transitionMatrix.existsAbstract(variablesToAbstract); // Determine all transitions between prob0 states. storm::dd::Bdd transitionsBetweenProb0States = player2States && (transitionMatrix && player1States.swapVariables(model.getRowColumnMetaVariablePairs()));