|  |  | @ -11,6 +11,8 @@ | 
			
		
	
		
			
				
					|  |  |  | #include "src/storage/prism/Command.h"
 | 
			
		
	
		
			
				
					|  |  |  | #include "src/storage/prism/Update.h"
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | #include "src/utility/macros.h"
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | namespace storm { | 
			
		
	
		
			
				
					|  |  |  |     namespace prism { | 
			
		
	
		
			
				
					|  |  |  |         namespace menu_games { | 
			
		
	
	
		
			
				
					|  |  | @ -24,6 +26,80 @@ namespace storm { | 
			
		
	
		
			
				
					|  |  |  |                 for (auto const& rangeExpression : expressionInformation.rangeExpressions) { | 
			
		
	
		
			
				
					|  |  |  |                     smtSolver->add(rangeExpression); | 
			
		
	
		
			
				
					|  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |                  | 
			
		
	
		
			
				
					|  |  |  |                 // Assert the guard of the command.
 | 
			
		
	
		
			
				
					|  |  |  |                 smtSolver->add(command.getGuardExpression()); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |                 // Refine the command based on all initial predicates.
 | 
			
		
	
		
			
				
					|  |  |  |                 std::vector<uint_fast64_t> allPredicateIndices(expressionInformation.predicates.size()); | 
			
		
	
		
			
				
					|  |  |  |                 for (auto index = 0; index < expressionInformation.predicates.size(); ++index) { | 
			
		
	
		
			
				
					|  |  |  |                     allPredicateIndices[index] = index; | 
			
		
	
		
			
				
					|  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |                 this->refine(allPredicateIndices); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |              | 
			
		
	
		
			
				
					|  |  |  |             template <storm::dd::DdType DdType, typename ValueType> | 
			
		
	
		
			
				
					|  |  |  |             void AbstractCommand<DdType, ValueType>::refine(std::vector<uint_fast64_t> const& predicates) { | 
			
		
	
		
			
				
					|  |  |  |                 // Add all predicates to the variable partition.
 | 
			
		
	
		
			
				
					|  |  |  |                 for (auto predicateIndex : predicates) { | 
			
		
	
		
			
				
					|  |  |  |                     variablePartition.addExpression(expressionInformation.predicates[predicateIndex]); | 
			
		
	
		
			
				
					|  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |                  | 
			
		
	
		
			
				
					|  |  |  |                 STORM_LOG_TRACE("Current variable partition is: " << variablePartition); | 
			
		
	
		
			
				
					|  |  |  |                  | 
			
		
	
		
			
				
					|  |  |  |                 // Next, we check whether there is work to be done by recomputing the relevant predicates and checking
 | 
			
		
	
		
			
				
					|  |  |  |                 // whether they changed.
 | 
			
		
	
		
			
				
					|  |  |  |                 std::pair<std::set<uint_fast64_t>, std::vector<std::set<uint_fast64_t>>> newRelevantPredicates = this->computeRelevantPredicates(); | 
			
		
	
		
			
				
					|  |  |  |                  | 
			
		
	
		
			
				
					|  |  |  |                 // If the DD does not need recomputation, we can return the cached result.
 | 
			
		
	
		
			
				
					|  |  |  |                 bool recomputeDd = this->relevantPredicatesChanged(newRelevantPredicates); | 
			
		
	
		
			
				
					|  |  |  |                 if (!recomputeDd) { | 
			
		
	
		
			
				
					|  |  |  |                     // If the new predicates are unrelated to the BDD of this command, we need to multiply their identities.
 | 
			
		
	
		
			
				
					|  |  |  |                     for (auto predicateIndex : predicates) { | 
			
		
	
		
			
				
					|  |  |  |                         cachedDd.first &= ddInformation.predicateIdentities[predicateIndex]; | 
			
		
	
		
			
				
					|  |  |  |                     } | 
			
		
	
		
			
				
					|  |  |  |                 } else { | 
			
		
	
		
			
				
					|  |  |  |                     // If the DD needs recomputation, it is because of new relevant predicates, so we need to assert the appropriate clauses in the solver.
 | 
			
		
	
		
			
				
					|  |  |  |                     addMissingPredicates(newRelevantPredicates); | 
			
		
	
		
			
				
					|  |  |  |                      | 
			
		
	
		
			
				
					|  |  |  |                     // Finally recompute the cached BDD.
 | 
			
		
	
		
			
				
					|  |  |  |                     this->recomputeCachedBdd(); | 
			
		
	
		
			
				
					|  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |              | 
			
		
	
		
			
				
					|  |  |  |             template <storm::dd::DdType DdType, typename ValueType> | 
			
		
	
		
			
				
					|  |  |  |             void AbstractCommand<DdType, ValueType>::recomputeCachedBdd() { | 
			
		
	
		
			
				
					|  |  |  |                 STORM_LOG_TRACE("Recomputing BDD for command " << command.get()); | 
			
		
	
		
			
				
					|  |  |  |                  | 
			
		
	
		
			
				
					|  |  |  |                 // Create a mapping from source state DDs to their distributions.
 | 
			
		
	
		
			
				
					|  |  |  |                 std::unordered_map<storm::dd::Bdd<DdType>, std::vector<storm::dd::Bdd<DdType>>> sourceToDistributionsMap; | 
			
		
	
		
			
				
					|  |  |  |                 smtSolver->allSat(decisionVariables, [&sourceToDistributionsMap,this] (storm::solver::SmtSolver::ModelReference const& model) { sourceToDistributionsMap[getSourceStateBdd(model)].push_back(getDistributionBdd(model)); return true; } ); | 
			
		
	
		
			
				
					|  |  |  |                  | 
			
		
	
		
			
				
					|  |  |  |                 // Now we search for the maximal number of choices of player 2 to determine how many DD variables we
 | 
			
		
	
		
			
				
					|  |  |  |                 // need to encode the nondeterminism.
 | 
			
		
	
		
			
				
					|  |  |  |                 uint_fast64_t maximalNumberOfChoices = 0; | 
			
		
	
		
			
				
					|  |  |  |                 for (auto const& sourceDistributionsPair : sourceToDistributionsMap) { | 
			
		
	
		
			
				
					|  |  |  |                     maximalNumberOfChoices = std::max(maximalNumberOfChoices, static_cast<uint_fast64_t>(sourceDistributionsPair.second.size())); | 
			
		
	
		
			
				
					|  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |                  | 
			
		
	
		
			
				
					|  |  |  |                 uint_fast64_t numberOfVariablesNeeded = static_cast<uint_fast64_t>(std::ceil(std::log2(maximalNumberOfChoices))); | 
			
		
	
		
			
				
					|  |  |  |                  | 
			
		
	
		
			
				
					|  |  |  |                 // Finally, build overall result.
 | 
			
		
	
		
			
				
					|  |  |  |                 storm::dd::Bdd<DdType> resultBdd = ddInformation.manager->getBddZero(); | 
			
		
	
		
			
				
					|  |  |  |                 for (auto const& sourceDistributionsPair : sourceToDistributionsMap) { | 
			
		
	
		
			
				
					|  |  |  |                     uint_fast64_t distributionIndex = 0; | 
			
		
	
		
			
				
					|  |  |  |                     storm::dd::Bdd<DdType> allDistributions = ddInformation.manager->getBddZero(); | 
			
		
	
		
			
				
					|  |  |  |                     for (auto const& distribution : sourceDistributionsPair.second) { | 
			
		
	
		
			
				
					|  |  |  |                         allDistributions |= distribution && ddInformation.encodeDistributionIndex(numberOfVariablesNeeded, distributionIndex); | 
			
		
	
		
			
				
					|  |  |  |                     } | 
			
		
	
		
			
				
					|  |  |  |                     resultBdd |= sourceDistributionsPair.first && allDistributions; | 
			
		
	
		
			
				
					|  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |                  | 
			
		
	
		
			
				
					|  |  |  |                 resultBdd &= computeMissingSourceStateIdentities(); | 
			
		
	
		
			
				
					|  |  |  |                 resultBdd &= ddInformation.manager->getEncoding(ddInformation.commandDdVariable, command.get().getGlobalIndex()); | 
			
		
	
		
			
				
					|  |  |  |                  | 
			
		
	
		
			
				
					|  |  |  |                 // Cache the result before returning it.
 | 
			
		
	
		
			
				
					|  |  |  |                 cachedDd = std::make_pair(resultBdd, numberOfVariablesNeeded); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |              | 
			
		
	
		
			
				
					|  |  |  |             template <storm::dd::DdType DdType, typename ValueType> | 
			
		
	
	
		
			
				
					|  |  | @ -126,6 +202,7 @@ namespace storm { | 
			
		
	
		
			
				
					|  |  |  |              | 
			
		
	
		
			
				
					|  |  |  |             template <storm::dd::DdType DdType, typename ValueType> | 
			
		
	
		
			
				
					|  |  |  |             storm::dd::Bdd<DdType> AbstractCommand<DdType, ValueType>::getSourceStateBdd(storm::solver::SmtSolver::ModelReference const& model) const { | 
			
		
	
		
			
				
					|  |  |  |                 STORM_LOG_TRACE("Building source state BDD."); | 
			
		
	
		
			
				
					|  |  |  |                 storm::dd::Bdd<DdType> result = ddInformation.manager->getBddOne(); | 
			
		
	
		
			
				
					|  |  |  |                 for (auto const& variableIndexPair : relevantPredicatesAndVariables.first) { | 
			
		
	
		
			
				
					|  |  |  |                     if (model.getBooleanValue(variableIndexPair.first)) { | 
			
		
	
	
		
			
				
					|  |  | @ -139,11 +216,13 @@ namespace storm { | 
			
		
	
		
			
				
					|  |  |  |              | 
			
		
	
		
			
				
					|  |  |  |             template <storm::dd::DdType DdType, typename ValueType> | 
			
		
	
		
			
				
					|  |  |  |             storm::dd::Bdd<DdType> AbstractCommand<DdType, ValueType>::getDistributionBdd(storm::solver::SmtSolver::ModelReference const& model) const { | 
			
		
	
		
			
				
					|  |  |  |                 STORM_LOG_TRACE("Building distribution BDD."); | 
			
		
	
		
			
				
					|  |  |  |                 storm::dd::Bdd<DdType> result = ddInformation.manager->getBddZero(); | 
			
		
	
		
			
				
					|  |  |  |                  | 
			
		
	
		
			
				
					|  |  |  |                 for (uint_fast64_t updateIndex = 0; updateIndex < command.get().getNumberOfUpdates(); ++updateIndex) { | 
			
		
	
		
			
				
					|  |  |  |                     storm::dd::Bdd<DdType> updateBdd = ddInformation.manager->getBddOne(); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |                     // Translate block variables for this update into a successor block.
 | 
			
		
	
		
			
				
					|  |  |  |                     for (auto const& variableIndexPair : relevantPredicatesAndVariables.second[updateIndex]) { | 
			
		
	
		
			
				
					|  |  |  |                         if (model.getBooleanValue(variableIndexPair.first)) { | 
			
		
	
		
			
				
					|  |  |  |                             updateBdd &= ddInformation.predicateBdds[variableIndexPair.second].second; | 
			
		
	
	
		
			
				
					|  |  | @ -159,9 +238,12 @@ namespace storm { | 
			
		
	
		
			
				
					|  |  |  |                     auto secondIt = relevantPredicatesAndVariables.second[updateIndex].begin(); | 
			
		
	
		
			
				
					|  |  |  |                     auto secondIte = relevantPredicatesAndVariables.second[updateIndex].end(); | 
			
		
	
		
			
				
					|  |  |  |                      | 
			
		
	
		
			
				
					|  |  |  |                     // Go through all relevant source predicates. This is guaranteed to be a superset of the set of
 | 
			
		
	
		
			
				
					|  |  |  |                     // relevant successor predicates for any update.
 | 
			
		
	
		
			
				
					|  |  |  |                     for (; firstIt != firstIte; ++firstIt) { | 
			
		
	
		
			
				
					|  |  |  |                         // If the predicates do not match, there is a predicate missing, so we need to add its identity.
 | 
			
		
	
		
			
				
					|  |  |  |                         if (secondIt == secondIte || firstIt->second != secondIt->second) { | 
			
		
	
		
			
				
					|  |  |  |                             result &= ddInformation.predicateIdentities[firstIt->second]; | 
			
		
	
		
			
				
					|  |  |  |                             updateBdd &= ddInformation.predicateIdentities[firstIt->second]; | 
			
		
	
		
			
				
					|  |  |  |                         } else if (secondIt != secondIte) { | 
			
		
	
		
			
				
					|  |  |  |                             ++secondIt; | 
			
		
	
		
			
				
					|  |  |  |                         } | 
			
		
	
	
		
			
				
					|  |  | @ -172,49 +254,23 @@ namespace storm { | 
			
		
	
		
			
				
					|  |  |  |                  | 
			
		
	
		
			
				
					|  |  |  |                 return result; | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |                          | 
			
		
	
		
			
				
					|  |  |  |              | 
			
		
	
		
			
				
					|  |  |  |             template <storm::dd::DdType DdType, typename ValueType> | 
			
		
	
		
			
				
					|  |  |  |             std::pair<storm::dd::Bdd<DdType>, uint_fast64_t> AbstractCommand<DdType, ValueType>::computeDd() { | 
			
		
	
		
			
				
					|  |  |  |                 // First, we check whether there is work to be done by recomputing the relevant predicates and checking
 | 
			
		
	
		
			
				
					|  |  |  |                 // whether they changed.
 | 
			
		
	
		
			
				
					|  |  |  |                 std::pair<std::set<uint_fast64_t>, std::vector<std::set<uint_fast64_t>>> newRelevantPredicates = this->computeRelevantPredicates(); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |                 // If the DD does not need recomputation, we can return the cached result.
 | 
			
		
	
		
			
				
					|  |  |  |                 bool recomputeDd = this->relevantPredicatesChanged(newRelevantPredicates); | 
			
		
	
		
			
				
					|  |  |  |                 if (!recomputeDd) { | 
			
		
	
		
			
				
					|  |  |  |                     // FIXME: multiply identity of new predicates
 | 
			
		
	
		
			
				
					|  |  |  |                     return cachedDd; | 
			
		
	
		
			
				
					|  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |                  | 
			
		
	
		
			
				
					|  |  |  |                 // If the DD needs recomputation, it is because of new relevant predicates, so we need to assert the appropriate clauses in the solver.
 | 
			
		
	
		
			
				
					|  |  |  |                 addMissingPredicates(newRelevantPredicates); | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |                 // Create a mapping from source state DDs to their distributions.
 | 
			
		
	
		
			
				
					|  |  |  |                 std::unordered_map<storm::dd::Bdd<DdType>, std::vector<storm::dd::Bdd<DdType>>> sourceToDistributionsMap; | 
			
		
	
		
			
				
					|  |  |  |                 smtSolver->allSat(decisionVariables, [&sourceToDistributionsMap,this] (storm::solver::SmtSolver::ModelReference const& model) { sourceToDistributionsMap[getSourceStateBdd(model)].push_back(getDistributionBdd(model)); return true; } ); | 
			
		
	
		
			
				
					|  |  |  |                  | 
			
		
	
		
			
				
					|  |  |  |                 // Now we search for the maximal number of choices of player 2 to determine how many DD variables we
 | 
			
		
	
		
			
				
					|  |  |  |                 // need to encode the nondeterminism.
 | 
			
		
	
		
			
				
					|  |  |  |                 uint_fast64_t maximalNumberOfChoices = 0; | 
			
		
	
		
			
				
					|  |  |  |                 for (auto const& sourceDistributionsPair : sourceToDistributionsMap) { | 
			
		
	
		
			
				
					|  |  |  |                     maximalNumberOfChoices = std::max(maximalNumberOfChoices, static_cast<uint_fast64_t>(sourceDistributionsPair.second.size())); | 
			
		
	
		
			
				
					|  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |                  | 
			
		
	
		
			
				
					|  |  |  |                 uint_fast64_t numberOfVariablesNeeded = static_cast<uint_fast64_t>(std::ceil(std::log2(maximalNumberOfChoices))); | 
			
		
	
		
			
				
					|  |  |  |             storm::dd::Bdd<DdType> AbstractCommand<DdType, ValueType>::computeMissingSourceStateIdentities() const { | 
			
		
	
		
			
				
					|  |  |  |                 auto relevantIt = relevantPredicatesAndVariables.first.begin(); | 
			
		
	
		
			
				
					|  |  |  |                 auto relevantIte = relevantPredicatesAndVariables.first.end(); | 
			
		
	
		
			
				
					|  |  |  |                  | 
			
		
	
		
			
				
					|  |  |  |                 // Finally, build overall result.
 | 
			
		
	
		
			
				
					|  |  |  |                 storm::dd::Bdd<DdType> resultBdd = ddInformation.manager->getBddZero(); | 
			
		
	
		
			
				
					|  |  |  |                 for (auto const& sourceDistributionsPair : sourceToDistributionsMap) { | 
			
		
	
		
			
				
					|  |  |  |                     uint_fast64_t distributionIndex = 0; | 
			
		
	
		
			
				
					|  |  |  |                     storm::dd::Bdd<DdType> allDistributions = ddInformation.manager->getBddZero(); | 
			
		
	
		
			
				
					|  |  |  |                     for (auto const& distribution : sourceDistributionsPair.second) { | 
			
		
	
		
			
				
					|  |  |  |                         allDistributions |= distribution && ddInformation.encodeDistributionIndex(numberOfVariablesNeeded, distributionIndex); | 
			
		
	
		
			
				
					|  |  |  |                 storm::dd::Bdd<DdType> result = ddInformation.manager->getBddOne(); | 
			
		
	
		
			
				
					|  |  |  |                 for (uint_fast64_t predicateIndex = 0; predicateIndex < expressionInformation.predicates.size(); ++predicateIndex) { | 
			
		
	
		
			
				
					|  |  |  |                     if (relevantIt == relevantIte || relevantIt->second != predicateIndex) { | 
			
		
	
		
			
				
					|  |  |  |                         result &= ddInformation.predicateIdentities[predicateIndex]; | 
			
		
	
		
			
				
					|  |  |  |                     } | 
			
		
	
		
			
				
					|  |  |  |                     resultBdd |= sourceDistributionsPair.first && allDistributions; | 
			
		
	
		
			
				
					|  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |                  | 
			
		
	
		
			
				
					|  |  |  |                 // Cache the result before returning it.
 | 
			
		
	
		
			
				
					|  |  |  |                 cachedDd = std::make_pair(resultBdd, numberOfVariablesNeeded); | 
			
		
	
		
			
				
					|  |  |  |                 return result; | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |             template <storm::dd::DdType DdType, typename ValueType> | 
			
		
	
		
			
				
					|  |  |  |             std::pair<storm::dd::Bdd<DdType>, uint_fast64_t> AbstractCommand<DdType, ValueType>::getAbstractBdd() { | 
			
		
	
		
			
				
					|  |  |  |                 return cachedDd; | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |              | 
			
		
	
	
		
			
				
					|  |  | 
 |