@ -23,7 +23,7 @@ namespace storm {
namespace abstraction {
namespace jani {
template < storm : : dd : : DdType DdType , typename ValueType >
EdgeAbstractor < DdType , ValueType > : : EdgeAbstractor ( uint64_t edgeId , storm : : jani : : Edge const & edge , AbstractionInformation < DdType > & abstractionInformation , std : : shared_ptr < storm : : utility : : solver : : SmtSolverFactory > const & smtSolverFactory , bool useDecomposition ) : smtSolver ( smtSolverFactory - > create ( abstractionInformation . getExpressionManager ( ) ) ) , abstractionInformation ( abstractionInformation ) , edgeId ( edgeId ) , edge ( edge ) , localExpressionInformation ( abstractionInformation ) , evaluator ( abstractionInformation . getExpressionManager ( ) ) , relevantPredicatesAndVariables ( ) , cachedDd ( abstractionInformation . getDdManager ( ) . getBddZero ( ) , 0 ) , decisionVariables ( ) , useDecomposition ( useDecomposition ) , skipBottomStates ( false ) , forceRecomputation ( true ) , abstractGuard ( abstractionInformation . getDdManager ( ) . getBddZero ( ) ) , bottomStateAbstractor ( abstractionInformation , { ! edge . getGuard ( ) } , smtSolverFactory ) {
EdgeAbstractor < DdType , ValueType > : : EdgeAbstractor ( uint64_t edgeId , storm : : jani : : Edge const & edge , AbstractionInformation < DdType > & abstractionInformation , std : : shared_ptr < storm : : utility : : solver : : SmtSolverFactory > const & smtSolverFactory , bool useDecomposition , bool debug ) : smtSolver ( smtSolverFactory - > create ( abstractionInformation . getExpressionManager ( ) ) ) , abstractionInformation ( abstractionInformation ) , edgeId ( edgeId ) , edge ( edge ) , localExpressionInformation ( abstractionInformation ) , evaluator ( abstractionInformation . getExpressionManager ( ) ) , relevantPredicatesAndVariables ( ) , cachedDd ( abstractionInformation . getDdManager ( ) . getBddZero ( ) , 0 ) , decisionVariables ( ) , useDecomposition ( useDecomposition ) , skipBottomStates ( false ) , forceRecomputation ( true ) , abstractGuard ( abstractionInformation . getDdManager ( ) . getBddZero ( ) ) , bottomStateAbstractor ( abstractionInformation , { ! edge . getGuard ( ) } , smtSolverFactory ) , debug ( debug ) {
// Make the second component of relevant predicates have the right size.
relevantPredicatesAndVariables . second . resize ( edge . getNumberOfDestinations ( ) ) ;
@ -179,7 +179,6 @@ namespace storm {
}
relevantBlockPartition [ representativeBlock ] . insert ( relevantBlockPartition [ assignmentVariableBlock ] . begin ( ) , relevantBlockPartition [ assignmentVariableBlock ] . end ( ) ) ;
relevantBlockPartition [ assignmentVariableBlock ] . clear ( ) ;
}
}
}
@ -188,200 +187,231 @@ 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 {
std : : set < storm : : expressions : : Variable > variablesContainedInGuard = edge . get ( ) . getGuard ( ) . getVariables ( ) ;
// Check whether we need to enumerate the guard. This is the case if the blocks related by the guard
// are not contained within a single block of our decomposition.
bool enumerateAbstractGuard = true ;
std : : set < uint64_t > guardBlocks = localExpressionInformation . getBlockIndicesOfVariables ( variablesContainedInGuard ) ;
STORM_LOG_TRACE ( " Decomposition into " < < relevantBlockPartition . size ( ) < < " blocks. " ) ;
if ( this - > debug ) {
uint64_t blockIndex = 0 ;
for ( auto const & block : relevantBlockPartition ) {
bool allContained = true ;
for ( auto const & guardBlock : guardBlocks ) {
if ( block . find ( guardBlock ) = = block . end ( ) ) {
allContained = false ;
break ;
}
}
if ( allContained ) {
enumerateAbstractGuard = false ;
}
}
uint64_t numberOfSolutions = 0 ;
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 ;
for ( auto const & element : relevantPredicatesAndVariables . first ) {
if ( relatedGuardPredicates . find ( element . second ) ! = relatedGuardPredicates . end ( ) ) {
guardDecisionVariables . push_back ( element . first ) ;
guardVariablesAndPredicates . push_back ( element ) ;
}
STORM_LOG_TRACE ( " Predicates of block " < < blockIndex < < " : " ) ;
std : : set < uint64_t > blockPredicateIndices ;
for ( auto const & innerBlock : block ) {
blockPredicateIndices . insert ( localExpressionInformation . getExpressionBlock ( innerBlock ) . begin ( ) , localExpressionInformation . getExpressionBlock ( innerBlock ) . end ( ) ) ;
}
abstractGuard = this - > getAbstractionInformation ( ) . getDdManager ( ) . getBddZero ( ) ;
smtSolver - > allSat ( guardDecisionVariables , [ this , & guardVariablesAndPredicates , & numberOfSolutions ] ( storm : : solver : : SmtSolver : : ModelReference const & model ) {
abstractGuard | = getSourceStateBdd ( model , guardVariablesAndPredicates ) ;
+ + numberOfSolutions ;
return true ;
} ) ;
STORM_LOG_TRACE ( " Enumerated " < < numberOfSolutions < < " 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.
// Create a new backtracking point before adding the guard.
smtSolver - > push ( ) ;
// Create the guard constraint.
std : : pair < std : : vector < storm : : expressions : : Expression > , std : : unordered_map < uint_fast64_t , storm : : expressions : : Variable > > result = abstractGuard . toExpression ( this - > getAbstractionInformation ( ) . getExpressionManager ( ) ) ;
// Then add it to the solver.
for ( auto const & expression : result . first ) {
smtSolver - > add ( expression ) ;
for ( auto const & predicateIndex : blockPredicateIndices ) {
STORM_LOG_TRACE ( abstractionInformation . get ( ) . getPredicateByIndex ( predicateIndex ) ) ;
}
// Finally associate the level variables with the predicates.
for ( auto const & indexVariablePair : result . second ) {
smtSolver - > add ( storm : : expressions : : iff ( indexVariablePair . second , this - > getAbstractionInformation ( ) . getPredicateForDdVariableIndex ( indexVariablePair . first ) ) ) ;
+ + blockIndex ;
}
}
std : : set < storm : : expressions : : Variable > variablesContainedInGuard = edge . get ( ) . getGuard ( ) . getVariables ( ) ;
// Check whether we need to enumerate the guard. This is the case if the blocks related by the guard
// are not contained within a single block of our decomposition.
bool enumerateAbstractGuard = true ;
std : : set < uint64_t > guardBlocks = localExpressionInformation . getBlockIndicesOfVariables ( variablesContainedInGuard ) ;
for ( auto const & block : relevantBlockPartition ) {
bool allContained = true ;
for ( auto const & guardBlock : guardBlocks ) {
if ( block . find ( guardBlock ) = = block . end ( ) ) {
allContained = false ;
break ;
}
}
// then enumerate the solutions for each of the blocks of the decomposition
uint64_t usedNondeterminismVariables = 0 ;
uint64_t blockCounter = 0 ;
std : : vector < storm : : dd : : Bdd < DdType > > blockBdds ;
for ( auto const & block : relevantBlockPartition ) {
std : : set < uint64_t > relevantPredicates ;
for ( auto const & innerBlock : block ) {
relevantPredicates . insert ( localExpressionInformation . getExpressionBlock ( innerBlock ) . begin ( ) , localExpressionInformation . getExpressionBlock ( innerBlock ) . end ( ) ) ;
if ( allContained ) {
enumerateAbstractGuard = false ;
}
}
uint64_t numberOfSolutions = 0 ;
uint64_t numberOfTotalSolutions = 0 ;
// If we need to enumerate the guard, do it only once now.
if ( enumerateAbstractGuard ) {
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 ;
for ( auto const & element : relevantPredicatesAndVariables . first ) {
if ( relatedGuardPredicates . find ( element . second ) ! = relatedGuardPredicates . end ( ) ) {
guardDecisionVariables . push_back ( element . first ) ;
guardVariablesAndPredicates . push_back ( element ) ;
}
std : : vector < storm : : expressions : : Variable > transitionDecisionVariables ;
std : : vector < std : : pair < storm : : expressions : : Variable , uint_fast64_t > > sourceVariablesAndPredicates ;
for ( auto const & element : relevantPredicatesAndVariables . first ) {
if ( relevantPredicates . find ( element . second ) ! = relevantPredicates . end ( ) ) {
transitionDecisionVariables . push_back ( element . first ) ;
sourceVariablesAndPredicates . push_back ( element ) ;
}
}
abstractGuard = this - > getAbstractionInformation ( ) . getDdManager ( ) . getBddZero ( ) ;
smtSolver - > allSat ( guardDecisionVariables , [ this , & guardVariablesAndPredicates , & numberOfSolutions ] ( storm : : solver : : SmtSolver : : ModelReference const & model ) {
abstractGuard | = getSourceStateBdd ( model , guardVariablesAndPredicates ) ;
+ + numberOfSolutions ;
return true ;
} ) ;
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.
// Create a new backtracking point before adding the guard.
smtSolver - > push ( ) ;
// Create the guard constraint.
std : : pair < std : : vector < storm : : expressions : : Expression > , std : : unordered_map < uint_fast64_t , storm : : expressions : : Variable > > result = abstractGuard . toExpression ( this - > getAbstractionInformation ( ) . getExpressionManager ( ) ) ;
// Then add it to the solver.
for ( auto const & expression : result . first ) {
smtSolver - > add ( expression ) ;
}
// Finally associate the level variables with the predicates.
for ( auto const & indexVariablePair : result . second ) {
smtSolver - > add ( storm : : expressions : : iff ( indexVariablePair . second , this - > getAbstractionInformation ( ) . getPredicateForDdVariableIndex ( indexVariablePair . first ) ) ) ;
}
}
// Then enumerate the solutions for each of the blocks of the decomposition
uint64_t usedNondeterminismVariables = 0 ;
uint64_t blockCounter = 0 ;
std : : vector < storm : : dd : : Bdd < DdType > > blockBdds ;
for ( auto const & block : relevantBlockPartition ) {
std : : set < uint64_t > relevantPredicates ;
for ( auto const & innerBlock : block ) {
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 ) {
if ( relevantPredicates . find ( element . second ) ! = relevantPredicates . end ( ) ) {
transitionDecisionVariables . push_back ( element . first ) ;
sourceVariablesAndPredicates . push_back ( element ) ;
}
std : : vector < std : : vector < std : : pair < storm : : expressions : : Variable , uint_fast64_t > > > destinationVariablesAndPredicates ;
for ( uint64_t destinationIndex = 0 ; destinationIndex < edge . get ( ) . getNumberOfDestinations ( ) ; + + destinationIndex ) {
destinationVariablesAndPredicates . emplace_back ( ) ;
for ( auto const & assignment : edge . get ( ) . getDestination ( destinationIndex ) . getOrderedAssignments ( ) . getAllAssignments ( ) ) {
uint64_t assignmentVariableBlockIndex = localExpressionInformation . getBlockIndexOfVariable ( assignment . getExpressionVariable ( ) ) ;
}
std : : vector < std : : vector < std : : pair < storm : : expressions : : Variable , uint_fast64_t > > > destinationVariablesAndPredicates ;
for ( uint64_t destinationIndex = 0 ; destinationIndex < edge . get ( ) . getNumberOfDestinations ( ) ; + + destinationIndex ) {
destinationVariablesAndPredicates . emplace_back ( ) ;
for ( auto const & assignment : edge . get ( ) . getDestination ( destinationIndex ) . getOrderedAssignments ( ) . getAllAssignments ( ) ) {
uint64_t assignmentVariableBlockIndex = localExpressionInformation . getBlockIndexOfVariable ( assignment . getVariable ( ) . getExpressionVariable ( ) ) ;
if ( block . find ( assignmentVariableBlockIndex ) ! = block . end ( ) ) {
std : : set < uint64_t > const & assignmentVariableBlock = localExpressionInformation . getExpressionBlock ( assignmentVariableBlockIndex ) ;
if ( block . find ( assignmentVariableBlockIndex ) ! = block . end ( ) ) {
for ( auto const & element : relevantPredicatesAndVariables . second [ destinationIndex ] ) {
if ( assignmentVariableBlock . find ( element . second ) ! = assignmentVariableBlock . end ( ) ) {
destinationVariablesAndPredicates . back ( ) . push_back ( element ) ;
transitionDecisionVariables . push_back ( element . first ) ;
}
for ( auto const & element : relevantPredicatesAndVariables . second [ destinationIndex ] ) {
if ( assignmentVariableBlock . find ( element . second ) ! = assignmentVariableBlock . end ( ) ) {
destinationVariablesAndPredicates . back ( ) . push_back ( element ) ;
transitionDecisionVariables . push_back ( element . first ) ;
}
}
}
}
std : : unordered_map < storm : : dd : : Bdd < DdType > , std : : vector < storm : : dd : : Bdd < DdType > > > sourceToDistributionsMap ;
numberOfSolutions = 0 ;
smtSolver - > allSat ( transitionDecisionVariables , [ & sourceToDistributionsMap , this , & numberOfSolutions , & sourceVariablesAndPredicates , & destinationVariablesAndPredicates ] ( storm : : solver : : SmtSolver : : ModelReference const & model ) {
sourceToDistributionsMap [ getSourceStateBdd ( model , sourceVariablesAndPredicates ) ] . push_back ( getDistributionBdd ( model , destinationVariablesAndPredicates ) ) ;
+ + numberOfSolutions ;
return true ;
} ) ;
STORM_LOG_TRACE ( " Enumerated " < < numberOfSolutions < < " solutions for block " < < blockCounter < < " . " ) ;
numberOfSolutions = 0 ;
// 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 ( ) ) ) ;
}
// 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 ) ) ) ;
// Finally, build overall result.
storm : : dd : : Bdd < DdType > resultBdd = this - > getAbstractionInformation ( ) . getDdManager ( ) . getBddZero ( ) ;
uint_fast64_t sourceStateIndex = 0 ;
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 ;
storm : : dd : : Bdd < DdType > allDistributions = this - > getAbstractionInformation ( ) . getDdManager ( ) . getBddZero ( ) ;
for ( auto const & distribution : sourceDistributionsPair . second ) {
allDistributions | = distribution & & this - > getAbstractionInformation ( ) . encodePlayer2Choice ( distributionIndex , usedNondeterminismVariables , usedNondeterminismVariables + numberOfVariablesNeeded ) ;
+ + distributionIndex ;
STORM_LOG_ASSERT ( ! allDistributions . isZero ( ) , " The BDD must not be empty. " ) ;
}
resultBdd | = sourceDistributionsPair . first & & allDistributions ;
+ + sourceStateIndex ;
STORM_LOG_ASSERT ( ! resultBdd . isZero ( ) , " The BDD must not be empty. " ) ;
}
usedNondeterminismVariables + = numberOfVariablesNeeded ;
blockBdds . push_back ( resultBdd ) ;
+ + blockCounter ;
}
if ( enumerateAbstractGuard ) {
smtSolver - > pop ( ) ;
}
std : : unordered_map < storm : : dd : : Bdd < DdType > , std : : vector < storm : : dd : : Bdd < DdType > > > sourceToDistributionsMap ;
numberOfSolutions = 0 ;
smtSolver - > allSat ( transitionDecisionVariables , [ & sourceToDistributionsMap , this , & numberOfSolutions , & sourceVariablesAndPredicates , & destinationVariablesAndPredicates ] ( storm : : solver : : SmtSolver : : ModelReference const & model ) {
sourceToDistributionsMap [ getSourceStateBdd ( model , sourceVariablesAndPredicates ) ] . push_back ( getDistributionBdd ( model , destinationVariablesAndPredicates ) ) ;
+ + numberOfSolutions ;
return true ;
} ) ;
STORM_LOG_TRACE ( " Enumerated " < < numberOfSolutions < < " solutions for block " < < blockCounter < < " . " ) ;
numberOfTotalSolutions + = numberOfSolutions ;
// multiply the results
storm : : dd : : Bdd < DdType > resultBdd = getAbstractionInformation ( ) . getDdManager ( ) . getBddOne ( ) ;
for ( auto const & blockBdd : blockBdds ) {
resultBdd & = blockBdd ;
// 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 ( ) ) ) ;
}
// if we did not explicitly enumerate the guard, we can construct it from the result BDD.
if ( ! enumerateAbstractGuard ) {
std : : set < storm : : expressions : : Variable > allVariables ( this - > getAbstractionInformation ( ) . getSuccessorVariables ( ) ) ;
auto player2Variables = this - > getAbstractionInformation ( ) . getPlayer2VariableSet ( usedNondeterminismVariables ) ;
allVariables . insert ( player2Variables . begin ( ) , player2Variables . end ( ) ) ;
auto auxVariables = this - > getAbstractionInformation ( ) . getAuxVariableSet ( 0 , this - > getAbstractionInformation ( ) . getAuxVariableCount ( ) ) ;
allVariables . insert ( auxVariables . begin ( ) , auxVariables . end ( ) ) ;
std : : set < storm : : expressions : : Variable > variablesToAbstract ;
std : : set_intersection ( allVariables . begin ( ) , allVariables . end ( ) , resultBdd . getContainedMetaVariables ( ) . begin ( ) , resultBdd . getContainedMetaVariables ( ) . end ( ) , std : : inserter ( variablesToAbstract , variablesToAbstract . begin ( ) ) ) ;
// 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 + ( blockCounter = = 0 ? 1 : 0 ) ) ) ) ;
// Finally, build overall result.
storm : : dd : : Bdd < DdType > resultBdd = this - > getAbstractionInformation ( ) . getDdManager ( ) . getBddZero ( ) ;
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. " ) ;
abstractGuard = resultBdd . existsAbstract ( variablesToAbstract ) ;
} else {
// Multiply the abstract guard as it can contain predicates that are not mentioned in the blocks.
resultBdd & = abstractGuard ;
// 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 ) ;
+ + distributionIndex ;
STORM_LOG_ASSERT ( ! allDistributions . isZero ( ) , " The BDD must not be empty. " ) ;
}
resultBdd | = sourceDistributionsPair . first & & allDistributions ;
STORM_LOG_ASSERT ( ! resultBdd . isZero ( ) , " The BDD must not be empty. " ) ;
}
usedNondeterminismVariables + = numberOfVariablesNeeded ;
// multiply with missing identities
resultBdd & = computeMissingIdentities ( ) ;
// cache and return result
resultBdd & = this - > getAbstractionInformation ( ) . encodePlayer1Choice ( edgeId , this - > getAbstractionInformation ( ) . getPlayer1VariableCount ( ) ) ;
blockBdds . push_back ( resultBdd ) ;
+ + blockCounter ;
}
if ( enumerateAbstractGuard ) {
smtSolver - > pop ( ) ;
}
// multiply the results
storm : : dd : : Bdd < DdType > resultBdd = getAbstractionInformation ( ) . getDdManager ( ) . getBddOne ( ) ;
uint64_t blockIndex = 0 ;
for ( auto const & blockBdd : blockBdds ) {
resultBdd & = blockBdd ;
+ + blockIndex ;
}
// If 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 ) ;
allVariables . insert ( player2Variables . begin ( ) , player2Variables . end ( ) ) ;
auto auxVariables = getAbstractionInformation ( ) . getAuxVariableSet ( 0 , getAbstractionInformation ( ) . getAuxVariableCount ( ) ) ;
allVariables . insert ( auxVariables . begin ( ) , auxVariables . end ( ) ) ;
// Cache the result.
cachedDd = GameBddResult < DdType > ( resultBdd , usedNondeterminismVariables ) ;
std : : set < storm : : expressions : : Variable > variablesToAbstract ;
std : : set_intersection ( allVariables . begin ( ) , allVariables . end ( ) , resultBdd . getContainedMetaVariables ( ) . begin ( ) , resultBdd . getContainedMetaVariables ( ) . end ( ) , std : : inserter ( variablesToAbstract , variablesToAbstract . begin ( ) ) ) ;
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. " ) ;
forceRecomputation = false ;
abstractGuard = resultBdd . existsAbstract ( variablesToAbstract ) ;
} else {
// Multiply the abstract guard as it can contain predicates that are not mentioned in the blocks.
resultBdd & = abstractGuard ;
}
// multiply with missing identities
resultBdd & = computeMissingDestinationIdentities ( ) ;
// cache and return result
resultBdd & = this - > getAbstractionInformation ( ) . encodePlayer1Choice ( edgeId , this - > getAbstractionInformation ( ) . getPlayer1VariableCount ( ) ) ;
// Cache the result.
cachedDd = GameBddResult < DdType > ( resultBdd , usedNondeterminismVariables ) ;
auto end = std : : chrono : : high_resolution_clock : : now ( ) ;
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 >
@ -414,7 +444,6 @@ namespace storm {
if ( ! skipBottomStates ) {
abstractGuard = this - > getAbstractionInformation ( ) . getDdManager ( ) . getBddZero ( ) ;
}
uint_fast64_t sourceStateIndex = 0 ;
for ( auto const & sourceDistributionsPair : sourceToDistributionsMap ) {
if ( ! skipBottomStates ) {
abstractGuard | = sourceDistributionsPair . first ;
@ -431,11 +460,10 @@ namespace storm {
STORM_LOG_ASSERT ( ! allDistributions . isZero ( ) , " The BDD must not be empty. " ) ;
}
resultBdd | = sourceDistributionsPair . first & & allDistributions ;
+ + sourceStateIndex ;
STORM_LOG_ASSERT ( ! resultBdd . isZero ( ) , " The BDD must not be empty. " ) ;
}
resultBdd & = computeMissingIdentities ( ) ;
resultBdd & = computeMissingDestination Identities ( ) ;
resultBdd & = this - > getAbstractionInformation ( ) . encodePlayer1Choice ( edgeId , this - > getAbstractionInformation ( ) . getPlayer1VariableCount ( ) ) ;
STORM_LOG_ASSERT ( sourceToDistributionsMap . empty ( ) | | ! resultBdd . isZero ( ) , " The BDD must not be empty, if there were distributions. " ) ;
@ -461,14 +489,8 @@ namespace storm {
storm : : expressions : : Variable const & assignedVariable = assignment . getExpressionVariable ( ) ;
auto const & leftHandSidePredicates = localExpressionInformation . getExpressionsUsingVariable ( 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 ) ;
}
auto const & predicatesRelatedToAssignedVariable = localExpressionInformation . getRelatedExpressions ( assignedVariables ) ;
result . first . insert ( predicatesRelatedToAssignedVariable . begin ( ) , predicatesRelatedToAssignedVariable . end ( ) ) ;
return result ;
}
@ -535,7 +557,8 @@ namespace storm {
template < storm : : dd : : DdType DdType , typename ValueType >
storm : : dd : : Bdd < DdType > EdgeAbstractor < DdType , ValueType > : : getSourceStateBdd ( storm : : solver : : SmtSolver : : ModelReference const & model , std : : vector < std : : pair < storm : : expressions : : Variable , uint_fast64_t > > const & variablePredicates ) const {
storm : : dd : : Bdd < DdType > result = this - > getAbstractionInformation ( ) . getDdManager ( ) . getBddOne ( ) ;
for ( auto const & variableIndexPair : variablePredicates ) {
for ( auto variableIndexPairIt = variablePredicates . rbegin ( ) , variableIndexPairIte = variablePredicates . rend ( ) ; variableIndexPairIt ! = variableIndexPairIte ; + + variableIndexPairIt ) {
auto const & variableIndexPair = * variableIndexPairIt ;
if ( model . getBooleanValue ( variableIndexPair . first ) ) {
result & = this - > getAbstractionInformation ( ) . encodePredicateAsSource ( variableIndexPair . second ) ;
} else {
@ -555,7 +578,8 @@ namespace storm {
storm : : dd : : Bdd < DdType > updateBdd = this - > getAbstractionInformation ( ) . getDdManager ( ) . getBddOne ( ) ;
// Translate block variables for this update into a successor block.
for ( auto const & variableIndexPair : variablePredicates [ destinationIndex ] ) {
for ( auto variableIndexPairIt = variablePredicates [ destinationIndex ] . rbegin ( ) , variableIndexPairIte = variablePredicates [ destinationIndex ] . rend ( ) ; variableIndexPairIt ! = variableIndexPairIte ; + + variableIndexPairIt ) {
auto const & variableIndexPair = * variableIndexPairIt ;
if ( model . getBooleanValue ( variableIndexPair . first ) ) {
updateBdd & = this - > getAbstractionInformation ( ) . encodePredicateAsSuccessor ( variableIndexPair . second ) ;
} else {
@ -572,99 +596,75 @@ namespace storm {
}
template < storm : : dd : : DdType DdType , typename ValueType >
storm : : dd : : Bdd < DdType > EdgeAbstractor < DdType , ValueType > : : computeMissingIdentities ( ) const {
storm : : dd : : Bdd < DdType > identities = computeMissingGlobalIdentities ( ) ;
identities & = computeMissingUpdateIdentities ( ) ;
return identities ;
}
template < storm : : dd : : DdType DdType , typename ValueType >
storm : : dd : : Bdd < DdType > EdgeAbstractor < DdType , ValueType > : : computeMissingUpdateIdentities ( ) const {
storm : : dd : : Bdd < DdType > EdgeAbstractor < DdType , ValueType > : : computeMissingDestinationIdentities ( ) const {
storm : : dd : : Bdd < DdType > result = this - > getAbstractionInformation ( ) . getDdManager ( ) . getBddZero ( ) ;
for ( uint_fast64_t update Index = 0 ; update Index < edge . get ( ) . getNumberOfDestinations ( ) ; + + update Index) {
for ( uint_fast64_t destinationIndex = 0 ; destinationIndex < edge . get ( ) . getNumberOfDestinations ( ) ; + + destinationIndex ) {
// Compute the identities that are missing for this update.
auto updateRelevantIt = relevantPredicatesAndVariables . second [ update Index] . begin ( ) ;
auto updateRelevantIte = relevantPredicatesAndVariables . second [ update Index] . end ( ) ;
auto updateRelevantIt = relevantPredicatesAndVariables . second [ destinationIndex ] . rbegin ( ) ;
auto updateRelevantIte = relevantPredicatesAndVariables . second [ destinationIndex ] . rend ( ) ;
storm : : dd : : Bdd < DdType > updateIdentity = this - > getAbstractionInformation ( ) . getDdManager ( ) . getBddOne ( ) ;
auto sourceRelevantIt = relevantPredicatesAndVariables . first . begin ( ) ;
auto sourceRelevantIte = relevantPredicatesAndVariables . first . 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 ( ; 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 ) {
updateIdentity & = this - > getAbstractionInformation ( ) . getPredicateIdentity ( sourceRelevantIt - > second ) ;
for ( uint_fast64_t predicateIndex = this - > getAbstractionInformation ( ) . getNumberOfPredicates ( ) - 1 ; ; - - predicateIndex ) {
if ( updateRelevantIt = = updateRelevantIte | | updateRelevantIt - > second ! = predicateIndex ) {
updateIdentity & = this - > getAbstractionInformation ( ) . getPredicateIdentity ( predicateIndex ) ;
} else {
+ + updateRelevantIt ;
}
if ( predicateIndex = = 0 ) {
break ;
}
}
result | = updateIdentity & & this - > getAbstractionInformation ( ) . encodeAux ( updateIndex , 0 , this - > getAbstractionInformation ( ) . getAuxVariableCount ( ) ) ;
result | = updateIdentity & & this - > getAbstractionInformation ( ) . encodeAux ( destination Index, 0 , this - > getAbstractionInformation ( ) . getAuxVariableCount ( ) ) ;
}
return result ;
}
template < storm : : dd : : DdType DdType , typename ValueType >
storm : : dd : : Bdd < DdType > EdgeAbstractor < DdType , ValueType > : : computeMissingGlobalIdentities ( ) const {
storm : : dd : : Bdd < DdType > result = this - > getAbstractionInformation ( ) . getDdManager ( ) . getBddOne ( ) ;
auto relevantIt = relevantPredicatesAndVariables . first . begin ( ) ;
auto relevantIte = relevantPredicatesAndVariables . first . end ( ) ;
for ( uint_fast64_t predicateIndex = 0 ; predicateIndex < this - > getAbstractionInformation ( ) . getNumberOfPredicates ( ) ; + + predicateIndex ) {
if ( relevantIt = = relevantIte | | relevantIt - > second ! = predicateIndex ) {
result & = this - > getAbstractionInformation ( ) . getPredicateIdentity ( predicateIndex ) ;
} else {
+ + relevantIt ;
}
}
return result ;
}
template < storm : : dd : : DdType DdType , typename ValueType >
GameBddResult < DdType > EdgeAbstractor < DdType , ValueType > : : abstract ( ) {
if ( forceRecomputation ) {
this - > recomputeCachedBdd ( ) ;
} else {
cachedDd . bdd & = computeMissingGlobal Identities ( ) ;
cachedDd . bdd & = computeMissingDestinationIdentities ( ) ;
}
STORM_LOG_TRACE ( " Edge produces " < < cachedDd . bdd . getNonZeroCount ( ) < < " transitions. " ) ;
return cachedDd ;
}
template < storm : : dd : : DdType DdType , typename ValueType >
BottomStateResult < DdType > EdgeAbstractor < DdType , ValueType > : : getBottomStateTransitions ( storm : : dd : : Bdd < DdType > const & reachableStates , uint_fast64_t numberOfPlayer2Variables , boost : : optional < std : : pair < storm : : expressions : : Variable , storm : : expressions : : Variable > > const & locationVariables ) {
// Compute the reachable states that have this edge enabled.
storm : : dd : : Bdd < DdType > reachableStatesWithEdge ;
if ( locationVariables ) {
reachableStatesWithEdge = ( reachableStates & & abstractGuard & & this - > getAbstractionInformation ( ) . encodeLocation ( locationVariables . get ( ) . first , edge . get ( ) . getSourceLocationIndex ( ) ) ) . existsAbstract ( this - > getAbstractionInformation ( ) . getSourceLocationVariables ( ) ) ;
} else {
reachableStatesWithEdge = ( reachableStates & & abstractGuard ) . existsAbstract ( this - > getAbstractionInformation ( ) . getSourceLocationVariables ( ) ) ;
}
STORM_LOG_TRACE ( " Computing bottom state transitions of edge with guard " < < edge . get ( ) . getGuard ( ) ) ;
STORM_LOG_TRACE ( " Computing bottom state transitions of edge with index " < < edgeId < < " . " ) ;
BottomStateResult < DdType > result ( this - > getAbstractionInformation ( ) . getDdManager ( ) . getBddZero ( ) , this - > getAbstractionInformation ( ) . getDdManager ( ) . getBddZero ( ) ) ;
// If the guard of this edge is a predicate, there are not bottom states/transitions.
// If the guard of this command is a predicate, there are not bottom states/transitions.
if ( skipBottomStates ) {
STORM_LOG_TRACE ( " Skipping bottom state computation for this edge. " ) ;
return result ;
}
// Use the state abstractor to compute the set of abstract states that has this edge enabled but still
// has a transition to a bottom state.
storm : : dd : : Bdd < DdType > reachableStatesWithEdge = reachableStates & & abstractGuard ;
// needed?
// if (locationVariables) {
// reachableStatesWithEdge = (reachableStates && abstractGuard && this->getAbstractionInformation().encodeLocation(locationVariables.get().first, edge.get().getSourceLocationIndex())).existsAbstract(this->getAbstractionInformation().getSourceLocationVariables());
// } else {
// reachableStatesWithEdge = (reachableStates && abstractGuard).existsAbstract(this->getAbstractionInformation().getSourceLocationVariables());
// }
// Use the state abstractor to compute the set of abstract states that has this command enabled but
// still has a transition to a bottom state.
bottomStateAbstractor . constrain ( reachableStatesWithEdge ) ;
if ( locationVariables ) {
result . states = bottomStateAbstractor . getAbstractStates ( ) & & reachableStatesWithEdge & & this - > getAbstractionInformation ( ) . encodeLocation ( locationVariables . get ( ) . first , edge . get ( ) . getSourceLocationIndex ( ) ) ;
} else {
result . states = bottomStateAbstractor . getAbstractStates ( ) & & reachableStatesWithEdge ;
}
// If the result is empty one time, we can skip the bottom state computation from now on.
if ( result . states . isZero ( ) ) {
skipBottomStates = true ;
@ -673,14 +673,11 @@ namespace storm {
// 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 ) ;
// Mark the states as bottom states and add source location information .
// Mark the states as bottom states.
result . states & = this - > getAbstractionInformation ( ) . getBottomStateBdd ( true , false ) ;
// Add the edge encoding.
result . transitions & = this - > getAbstractionInformation ( ) . encodePlayer1Choice ( edgeId , this - > getAbstractionInformation ( ) . getPlayer1VariableCount ( ) ) & & this - > getAbstractionInformation ( ) . encodePlayer2Choice ( 0 , 0 , numberOfPlayer2Variables ) & & this - > getAbstractionInformation ( ) . encodeAux ( 0 , 0 , this - > getAbstractionInformation ( ) . getAuxVariableCount ( ) ) ;
// Add the location identity to the transitions.
result . transitions & = this - > getAbstractionInformation ( ) . getAllLocationIdentities ( ) ;
// Add the command encoding and the next free player 2 encoding.
result . transitions & = this - > getAbstractionInformation ( ) . encodePlayer1Choice ( edgeId , this - > getAbstractionInformation ( ) . getPlayer1VariableCount ( ) ) & & this - > getAbstractionInformation ( ) . encodePlayer2Choice ( 0 , 0 , numberOfPlayer2Variables ) & & this - > getAbstractionInformation ( ) . encodeAux ( 0 , 0 , this - > getAbstractionInformation ( ) . getAuxVariableCount ( ) ) ;
return result ;
}