@ -179,7 +179,6 @@ namespace storm {
}
relevantBlockPartition [ representativeBlock ] . insert ( relevantBlockPartition [ assignmentVariableBlock ] . begin ( ) , relevantBlockPartition [ assignmentVariableBlock ] . end ( ) ) ;
relevantBlockPartition [ assignmentVariableBlock ] . clear ( ) ;
}
}
}
@ -188,18 +187,37 @@ namespace storm {
// Now remove all blocks that are empty and obtain the partition.
std : : vector < std : : set < uint64_t > > cleanedRelevantBlockPartition ;
for ( auto & element : relevantBlockPartition ) {
if ( ! element . empty ( ) ) {
cleanedRelevantBlockPartition . emplace_back ( std : : move ( element ) ) ;
for ( auto & outerBlock : relevantBlockPartition ) {
if ( ! outerBlock . empty ( ) ) {
cleanedRelevantBlockPartition . emplace_back ( ) ;
for ( auto const & innerBlock : outerBlock ) {
if ( ! localExpressionInformation . getExpressionBlock ( innerBlock ) . empty ( ) ) {
cleanedRelevantBlockPartition . back ( ) . insert ( innerBlock ) ;
}
}
if ( cleanedRelevantBlockPartition . back ( ) . empty ( ) ) {
cleanedRelevantBlockPartition . pop_back ( ) ;
}
}
}
relevantBlockPartition = std : : move ( cleanedRelevantBlockPartition ) ;
// if the decomposition has size 1, use the plain technique from before
if ( relevantBlockPartition . size ( ) = = 1 ) {
STORM_LOG_TRACE ( " Relevant block partition size is one, falling back to regular computation. " ) ;
recomputeCachedBddWithoutDecomposition ( ) ;
} else {
STORM_LOG_TRACE ( " Decomposition into " < < relevantBlockPartition . size ( ) < < " blocks. " ) ;
for ( auto const & block : relevantBlockPartition ) {
STORM_LOG_TRACE ( " New block of size " < < block . size ( ) < < " : " ) ;
std : : set < uint64_t > blockPredicateIndices ;
for ( auto const & innerBlock : block ) {
blockPredicateIndices . insert ( localExpressionInformation . getExpressionBlock ( innerBlock ) . begin ( ) , localExpressionInformation . getExpressionBlock ( innerBlock ) . end ( ) ) ;
}
for ( auto const & predicateIndex : blockPredicateIndices ) {
STORM_LOG_TRACE ( abstractionInformation . get ( ) . getPredicateByIndex ( predicateIndex ) ) ;
}
}
std : : set < storm : : expressions : : Variable > variablesContainedInGuard = command . get ( ) . getGuardExpression ( ) . getVariables ( ) ;
// Check whether we need to enumerate the guard. This is the case if the blocks related by the guard
@ -220,9 +238,10 @@ namespace storm {
}
uint64_t numberOfSolutions = 0 ;
uint64_t numberOfTotalSolutions = 0 ;
// If we need to enumerate the guard, do it only once now.
if ( enumerateAbstractGuard ) {
// otherwise, enumerate the abstract guard so we do this only once
std : : set < uint64_t > relatedGuardPredicates = localExpressionInformation . getRelatedExpressions ( variablesContainedInGuard ) ;
std : : vector < storm : : expressions : : Variable > guardDecisionVariables ;
std : : vector < std : : pair < storm : : expressions : : Variable , uint_fast64_t > > guardVariablesAndPredicates ;
@ -238,7 +257,7 @@ namespace storm {
+ + numberOfSolutions ;
return true ;
} ) ;
STORM_LOG_TRACE ( " Enumerated " < < numberOfSolutions < < " for abstract guard. " ) ;
STORM_LOG_TRACE ( " Enumerated " < < numberOfSolutions < < " solutions for abstract guard." ) ;
// now that we have the abstract guard, we can add it as an assertion to the solver before enumerating
// the other solutions.
@ -270,6 +289,11 @@ namespace storm {
relevantPredicates . insert ( localExpressionInformation . getExpressionBlock ( innerBlock ) . begin ( ) , localExpressionInformation . getExpressionBlock ( innerBlock ) . end ( ) ) ;
}
if ( relevantPredicates . empty ( ) ) {
STORM_LOG_TRACE ( " Block does not contain relevant predicates, skipping it. " ) ;
continue ;
}
std : : vector < storm : : expressions : : Variable > transitionDecisionVariables ;
std : : vector < std : : pair < storm : : expressions : : Variable , uint_fast64_t > > sourceVariablesAndPredicates ;
for ( auto const & element : relevantPredicatesAndVariables . first ) {
@ -304,7 +328,7 @@ namespace storm {
return true ;
} ) ;
STORM_LOG_TRACE ( " Enumerated " < < numberOfSolutions < < " solutions for block " < < blockCounter < < " . " ) ;
numberOfSolutions = 0 ;
numberOfTotalSolutions + = numberOfSolutions ;
// Now we search for the maximal number of choices of player 2 to determine how many DD variables we
// need to encode the nondeterminism.
@ -315,7 +339,8 @@ namespace storm {
// We now compute how many variables we need to encode the choices. We add one to the maximal number of
// choices to account for a possible transition to a bottom state.
uint_fast64_t numberOfVariablesNeeded = static_cast < uint_fast64_t > ( std : : ceil ( std : : log2 ( maximalNumberOfChoices + 1 ) ) ) ;
uint_fast64_t numberOfVariablesNeeded = static_cast < uint_fast64_t > ( std : : ceil ( std : : log2 ( maximalNumberOfChoices + ( blockCounter = = 0 ? 1 : 0 ) ) ) ) ;
std : : cout < < " need " < < numberOfVariablesNeeded < < " variables for " < < ( maximalNumberOfChoices + ( blockCounter = = 0 ? 1 : 0 ) ) < < " choices " < < std : : endl ;
// Finally, build overall result.
storm : : dd : : Bdd < DdType > resultBdd = this - > getAbstractionInformation ( ) . getDdManager ( ) . getBddZero ( ) ;
@ -324,8 +349,9 @@ namespace storm {
for ( auto const & sourceDistributionsPair : sourceToDistributionsMap ) {
STORM_LOG_ASSERT ( ! sourceDistributionsPair . first . isZero ( ) , " The source BDD must not be empty. " ) ;
STORM_LOG_ASSERT ( ! sourceDistributionsPair . second . empty ( ) , " The distributions must not be empty. " ) ;
// We start with the distribution index of 1, becase 0 is reserved for a potential bottom choice.
uint_fast64_t distributionIndex = 1 ;
// We start with the distribution index of 1, because 0 is reserved for a potential bottom choice.
uint_fast64_t distributionIndex = blockCounter = = 0 ? 1 : 0 ;
storm : : dd : : Bdd < DdType > allDistributions = this - > getAbstractionInformation ( ) . getDdManager ( ) . getBddZero ( ) ;
for ( auto const & distribution : sourceDistributionsPair . second ) {
allDistributions | = distribution & & this - > getAbstractionInformation ( ) . encodePlayer2Choice ( distributionIndex , usedNondeterminismVariables , usedNondeterminismVariables + numberOfVariablesNeeded ) ;
@ -348,11 +374,14 @@ namespace storm {
// multiply the results
storm : : dd : : Bdd < DdType > resultBdd = getAbstractionInformation ( ) . getDdManager ( ) . getBddOne ( ) ;
uint64_t blockIndex = 0 ;
for ( auto const & blockBdd : blockBdds ) {
blockBdd . template toAdd < ValueType > ( ) . exportToDot ( " block " + std : : to_string ( command . get ( ) . getGlobalIndex ( ) ) + " _ " + std : : to_string ( blockIndex ) + " .dot " ) ;
resultBdd & = blockBdd ;
+ + blockIndex ;
}
// i f we did not explicitly enumerate the guard, we can construct it from the result BDD.
// I f we did not explicitly enumerate the guard, we can construct it from the result BDD.
if ( ! enumerateAbstractGuard ) {
std : : set < storm : : expressions : : Variable > allVariables ( getAbstractionInformation ( ) . getSuccessorVariables ( ) ) ;
auto player2Variables = getAbstractionInformation ( ) . getPlayer2VariableSet ( usedNondeterminismVariables ) ;
@ -369,6 +398,11 @@ namespace storm {
resultBdd & = abstractGuard ;
}
resultBdd . template toAdd < ValueType > ( ) . exportToDot ( " decomp " + std : : to_string ( command . get ( ) . getGlobalIndex ( ) ) + " .dot " ) ;
auto identities = computeMissingIdentities ( ) ;
identities . template toAdd < ValueType > ( ) . exportToDot ( " idents " + std : : to_string ( command . get ( ) . getGlobalIndex ( ) ) + " .dot " ) ;
// multiply with missing identities
resultBdd & = computeMissingIdentities ( ) ;
@ -379,10 +413,10 @@ namespace storm {
cachedDd = GameBddResult < DdType > ( resultBdd , usedNondeterminismVariables ) ;
auto end = std : : chrono : : high_resolution_clock : : now ( ) ;
STORM_LOG_TRACE ( " Enumerated " < < numberOfSolutions < < " solutions in " < < std : : chrono : : duration_cast < std : : chrono : : milliseconds > ( end - start ) . count ( ) < < " ms. " ) ;
STORM_LOG_TRACE ( " Enumerated " < < numberOfTotalSolutions < < " solutions in " < < std : : chrono : : duration_cast < std : : chrono : : milliseconds > ( end - start ) . count ( ) < < " ms. " ) ;
forceRecomputation = false ;
}
}
template < storm : : dd : : DdType DdType , typename ValueType >
void CommandAbstractor < DdType , ValueType > : : recomputeCachedBddWithoutDecomposition ( ) {
@ -433,6 +467,8 @@ namespace storm {
STORM_LOG_ASSERT ( ! resultBdd . isZero ( ) , " The BDD must not be empty. " ) ;
}
resultBdd . template toAdd < ValueType > ( ) . exportToDot ( " nodecomp " + std : : to_string ( command . get ( ) . getGlobalIndex ( ) ) + " .dot " ) ;
resultBdd & = computeMissingIdentities ( ) ;
resultBdd & = this - > getAbstractionInformation ( ) . encodePlayer1Choice ( command . get ( ) . getGlobalIndex ( ) , this - > getAbstractionInformation ( ) . getPlayer1VariableCount ( ) ) ;
STORM_LOG_ASSERT ( sourceToDistributionsMap . empty ( ) | | ! resultBdd . isZero ( ) , " The BDD must not be empty, if there were distributions. " ) ;
@ -460,12 +496,12 @@ namespace storm {
auto const & leftHandSidePredicates = localExpressionInformation . getRelatedExpressions ( assignedVariable ) ;
result . second . insert ( leftHandSidePredicates . begin ( ) , leftHandSidePredicates . end ( ) ) ;
// Keep track of all assigned variables, so we can find the related predicates later.
assignedVariables . insert ( assignedVariable ) ;
// // Keep track of all assigned variables, so we can find the related predicates later.
// assignedVariables.insert(assignedVariable);
}
auto c onst & predicatesRelatedToAssignedVariable = localExpressionInformation . getRelatedExpressions ( assignedVariables ) ;
result . first . insert ( predicatesRelatedToAssignedVariable . begin ( ) , predicatesRelatedToAssignedVariable . end ( ) ) ;
// auto c onst& predicatesRelatedToAssignedVariable = localExpressionInformation.getRelatedExpressions(assignedVariables);
// result.first.insert(predicatesRelatedToAssignedVariable.begin(), predicatesRelatedToAssignedVariable.end());
return result ;
}
@ -594,6 +630,7 @@ namespace storm {
for ( ; sourceRelevantIt ! = sourceRelevantIte ; + + sourceRelevantIt ) {
// If the predicates do not match, there is a predicate missing, so we need to add its identity.
if ( updateRelevantIt = = updateRelevantIte | | sourceRelevantIt - > second ! = updateRelevantIt - > second ) {
std : : cout < < " adding update identity of predicate " < < this - > getAbstractionInformation ( ) . getPredicateByIndex ( sourceRelevantIt - > second ) < < " to update " < < updateIndex < < std : : endl ;
updateIdentity & = this - > getAbstractionInformation ( ) . getPredicateIdentity ( sourceRelevantIt - > second ) ;
} else {
+ + updateRelevantIt ;
@ -614,6 +651,7 @@ namespace storm {
for ( uint_fast64_t predicateIndex = 0 ; predicateIndex < this - > getAbstractionInformation ( ) . getNumberOfPredicates ( ) ; + + predicateIndex ) {
if ( relevantIt = = relevantIte | | relevantIt - > second ! = predicateIndex ) {
std : : cout < < " adding global identity of predicate " < < this - > getAbstractionInformation ( ) . getPredicateByIndex ( predicateIndex ) < < std : : endl ;
result & = this - > getAbstractionInformation ( ) . getPredicateIdentity ( predicateIndex ) ;
} else {
+ + relevantIt ;