@ -180,6 +180,9 @@ namespace storm {
// DDs representing the identity for each variable.
std : : map < storm : : expressions : : Variable , storm : : dd : : Add < Type , ValueType > > variableToIdentityMap ;
// DDs representing the ranges of each variable.
std : : map < storm : : expressions : : Variable , storm : : dd : : Bdd < Type > > variableToRangeMap ;
// A set of all meta variables that correspond to global variables.
std : : set < storm : : expressions : : Variable > allGlobalVariables ;
@ -266,6 +269,10 @@ namespace storm {
// Add the location variable to the row/column variables.
result . rowMetaVariables . insert ( variablePair . first ) ;
result . columnMetaVariables . insert ( variablePair . second ) ;
// Add the legal range for the location variables.
result . variableToRangeMap . emplace ( variablePair . first , result . manager - > getRange ( variablePair . first ) ) ;
result . variableToRangeMap . emplace ( variablePair . second , result . manager - > getRange ( variablePair . second ) ) ;
}
// Create global variables.
@ -327,6 +334,8 @@ namespace storm {
storm : : dd : : Add < Type , ValueType > variableIdentity = result . manager - > template getIdentity < ValueType > ( variablePair . first ) . equals ( result . manager - > template getIdentity < ValueType > ( variablePair . second ) ) . template toAdd < ValueType > ( ) * result . manager - > getRange ( variablePair . first ) . template toAdd < ValueType > ( ) * result . manager - > getRange ( variablePair . second ) . template toAdd < ValueType > ( ) ;
result . variableToIdentityMap . emplace ( variable . getExpressionVariable ( ) , variableIdentity ) ;
result . rowColumnMetaVariablePairs . push_back ( variablePair ) ;
result . variableToRangeMap . emplace ( variablePair . first , result . manager - > getRange ( variablePair . first ) ) ;
result . variableToRangeMap . emplace ( variablePair . second , result . manager - > getRange ( variablePair . second ) ) ;
result . allGlobalVariables . insert ( variable . getExpressionVariable ( ) ) ;
}
@ -345,6 +354,9 @@ namespace storm {
storm : : dd : : Add < Type , ValueType > variableIdentity = result . manager - > template getIdentity < ValueType > ( variablePair . first ) . equals ( result . manager - > template getIdentity < ValueType > ( variablePair . second ) ) . template toAdd < ValueType > ( ) ;
result . variableToIdentityMap . emplace ( variable . getExpressionVariable ( ) , variableIdentity ) ;
result . variableToRangeMap . emplace ( variablePair . first , result . manager - > getRange ( variablePair . first ) ) ;
result . variableToRangeMap . emplace ( variablePair . second , result . manager - > getRange ( variablePair . second ) ) ;
result . rowColumnMetaVariablePairs . push_back ( variablePair ) ;
result . allGlobalVariables . insert ( variable . getExpressionVariable ( ) ) ;
}
@ -395,15 +407,13 @@ namespace storm {
template < storm : : dd : : DdType Type , typename ValueType >
EdgeDestinationDd < Type , ValueType > buildEdgeDestinationDd ( storm : : jani : : Automaton const & automaton , storm : : jani : : EdgeDestination const & destination , storm : : dd : : Add < Type , ValueType > const & guard , CompositionVariables < Type , ValueType > const & variables ) {
storm : : dd : : Add < Type , ValueType > transitions = variables . manager - > template getAddOne < ValueType > ( ) ;
storm : : dd : : Add < Type , ValueType > transitions = variables . rowExpressionAdapter - > translateExpression ( destination . getProbability ( ) ) ;
STORM_LOG_TRACE ( " Translating edge destination. " ) ;
auto t1 = std : : chrono : : high_resolution_clock : : now ( ) ;
// Iterate over all assignments (boolean and integer) and build the DD for it.
std : : set < storm : : expressions : : Variable > assignedVariables ;
for ( auto const & assignment : destination . getAssignments ( ) ) {
std : : cout < < " assignment to variable " < < assignment . getExpressionVariable ( ) . getName ( ) < < " expr " < < assignment . getAssignedExpression ( ) < < std : : endl ;
// Record the variable as being written.
STORM_LOG_TRACE ( " Assigning to variable " < < variables . variableToRowMetaVariableMap - > at ( assignment . getExpressionVariable ( ) ) . getName ( ) ) ;
assignedVariables . insert ( assignment . getExpressionVariable ( ) ) ;
@ -415,35 +425,19 @@ namespace storm {
// Translate the expression that is being assigned.
storm : : dd : : Add < Type , ValueType > assignedExpression = variables . rowExpressionAdapter - > translateExpression ( assignment . getAssignedExpression ( ) ) ;
// Combine the update expression with the guard.
// Combine the assigned expression with the guard.
storm : : dd : : Add < Type , ValueType > result = assignedExpression * guard ;
auto inner1 = std : : chrono : : high_resolution_clock : : now ( ) ;
// Combine the variable and the assigned expression.
storm : : dd : : Add < Type , ValueType > tmp = result ;
result = result . equals ( writtenVariable ) . template toAdd < ValueType > ( ) ;
auto inner2 = std : : chrono : : high_resolution_clock : : now ( ) ;
std : : cout < < " inner-1 took " < < std : : chrono : : duration_cast < std : : chrono : : milliseconds > ( inner2 - inner1 ) . count ( ) < < " ms " < < std : : endl ;
if ( std : : chrono : : duration_cast < std : : chrono : : milliseconds > ( inner2 - inner1 ) . count ( ) > 30 ) {
writtenVariable . exportToDot ( " writtenVar.dot " ) ;
tmp . exportToDot ( " result.dot " ) ;
assignedExpression . exportToDot ( " assignedExpressions.dot " ) ;
guard . exportToDot ( " guard.dot " ) ;
exit ( - 1 ) ;
}
inner1 = std : : chrono : : high_resolution_clock : : now ( ) ;
result * = guard ;
inner2 = std : : chrono : : high_resolution_clock : : now ( ) ;
std : : cout < < " inner-2 took " < < std : : chrono : : duration_cast < std : : chrono : : milliseconds > ( inner2 - inner1 ) . count ( ) < < " ms " < < std : : endl ;
// Restrict the transitions to the range of the written variable.
result = result * variables . manager - > getRange ( primedMetaVariable ) . template toAdd < ValueType > ( ) ;
result = result * variables . variableToRangeMap . at ( primedMetaVariable ) . template toAdd < ValueType > ( ) ;
// Combine the assignment DDs.
transitions * = result ;
}
auto t2 = std : : chrono : : high_resolution_clock : : now ( ) ;
std : : cout < < " assignments took " < < std : : chrono : : duration_cast < std : : chrono : : milliseconds > ( t2 - t1 ) . count ( ) < < " ms " < < std : : endl ;
// Compute the set of assigned global variables.
std : : set < storm : : expressions : : Variable > assignedGlobalVariables ;
@ -851,7 +845,7 @@ namespace storm {
*/
EdgeDd buildEdgeDd ( storm : : jani : : Automaton const & automaton , storm : : jani : : Edge const & edge ) {
STORM_LOG_TRACE ( " Translating guard " < < edge . getGuard ( ) ) ;
storm : : dd : : Add < Type , ValueType > guard = this - > variables . rowExpressionAdapter - > translateExpression ( edge . getGuard ( ) ) * this - > variables . automatonToRangeMap . at ( automaton . getName ( ) ) ;
storm : : dd : : Add < Type , ValueType > guard = this - > variables . rowExpressionAdapter - > translateExpression ( edge . getGuard ( ) ) ; // * this->variables.automatonToRangeMap.at(automaton.getName());
STORM_LOG_WARN_COND ( ! guard . isZero ( ) , " The guard ' " < < edge . getGuard ( ) < < " ' is unsatisfiable. " ) ;
if ( ! guard . isZero ( ) ) {
@ -1107,7 +1101,6 @@ namespace storm {
private :
AutomatonDd composeInParallel ( AutomatonDd const & automaton1 , AutomatonDd const & automaton2 , std : : set < uint64_t > const & synchronizingActionIndices ) {
auto t1 = std : : chrono : : high_resolution_clock : : now ( ) ;
AutomatonDd result ( automaton1 ) ;
// Treat all actions of the first automaton.
@ -1152,9 +1145,6 @@ namespace storm {
result . identity = automaton1 . identity * automaton2 . identity ;
auto t2 = std : : chrono : : high_resolution_clock : : now ( ) ;
std : : cout < < " parallel composition took " < < std : : chrono : : duration_cast < std : : chrono : : milliseconds > ( t2 - t1 ) . count ( ) < < " ms " < < std : : endl ;
return result ;
}
@ -1166,7 +1156,6 @@ namespace storm {
// Cross-multiply the guards to the other fragments that write global variables and check for overlapping
// parts. This finds illegal parts in which a global variable is written multiple times.
auto t1 = std : : chrono : : high_resolution_clock : : now ( ) ;
std : : map < storm : : expressions : : Variable , storm : : dd : : Bdd < Type > > globalVariableToWritingFragment ;
for ( auto & entry : action1 . variableToWritingFragment ) {
entry . second & = guard2 ;
@ -1184,8 +1173,6 @@ namespace storm {
globalVariableToWritingFragment [ entry . first ] = entry . second ;
}
}
auto t2 = std : : chrono : : high_resolution_clock : : now ( ) ;
totalTime + = t2 - t1 ;
return ActionDd ( action1 . guard * action2 . guard , action1 . transitions * action2 . transitions , std : : make_pair ( std : : min ( action1 . getLowestLocalNondeterminismVariable ( ) , action2 . getLowestLocalNondeterminismVariable ( ) ) , std : : max ( action1 . getHighestLocalNondeterminismVariable ( ) , action2 . getHighestLocalNondeterminismVariable ( ) ) ) , globalVariableToWritingFragment , illegalFragment ) ;
}
@ -1281,11 +1268,14 @@ namespace storm {
EdgeDd buildEdgeDd ( storm : : jani : : Automaton const & automaton , storm : : jani : : Edge const & edge ) {
STORM_LOG_TRACE ( " Translating guard " < < edge . getGuard ( ) ) ;
storm : : dd : : Add < Type , ValueType > guard = this - > variables . rowExpressionAdapter - > translateExpression ( edge . getGuard ( ) ) * this - > variables . automatonToRangeMap . at ( automaton . getName ( ) ) ;
STORM_LOG_WARN_COND ( ! guard . isZero ( ) , " The guard ' " < < edge . getGuard ( ) < < " ' is unsatisfiable. " ) ;
if ( ! guard . isZero ( ) ) {
auto t1 = std : : chrono : : high_resolution_clock : : now ( ) ;
// We keep the guard and a "ranged" version seperate, because building the destinations tends to be
// slower when the full range is applied.
storm : : dd : : Add < Type , ValueType > guard = this - > variables . rowExpressionAdapter - > translateExpression ( edge . getGuard ( ) ) ;
storm : : dd : : Add < Type , ValueType > rangedGuard = guard * this - > variables . automatonToRangeMap . at ( automaton . getName ( ) ) ;
STORM_LOG_WARN_COND ( ! rangedGuard . isZero ( ) , " The guard ' " < < edge . getGuard ( ) < < " ' is unsatisfiable. " ) ;
if ( ! rangedGuard . isZero ( ) ) {
// Create the DDs representing the individual updates.
std : : vector < EdgeDestinationDd < Type , ValueType > > destinationDds ;
for ( storm : : jani : : EdgeDestination const & destination : edge . getDestinations ( ) ) {
@ -1294,11 +1284,9 @@ namespace storm {
STORM_LOG_WARN_COND ( ! destinationDds . back ( ) . transitions . isZero ( ) , " Destination does not have any effect. " ) ;
}
auto t2 = std : : chrono : : high_resolution_clock : : now ( ) ;
std : : cout < < " building destinations took " < < std : : chrono : : duration_cast < std : : chrono : : milliseconds > ( t2 - t1 ) . count ( ) < < " ms " < < std : : endl ;
// Now that we have built the destinations, we always take the full guard.
guard = rangedGuard ;
t1 = std : : chrono : : high_resolution_clock : : now ( ) ;
// Start by gathering all variables that were written in at least one destination.
std : : set < storm : : expressions : : Variable > globalVariablesInSomeDestination ;
@ -1326,9 +1314,8 @@ namespace storm {
// Now combine the destination DDs to the edge DD.
storm : : dd : : Add < Type , ValueType > transitions = this - > variables . manager - > template getAddZero < ValueType > ( ) ;
auto destinationDdIt = destinationDds . begin ( ) ;
for ( auto destinationIt = edge . getDestinations ( ) . begin ( ) , destinationIte = edge . getDestinations ( ) . end ( ) ; destinationIt ! = destinationIte ; + + destinationIt , + + destinationDdIt ) {
transitions + = destinationDdIt - > transitions * this - > variables . rowExpressionAdapter - > translateExpression ( destinationIt - > getProbability ( ) ) ;
for ( auto const & destinationDd : destinationDds ) {
transitions + = destinationDd . transitions ;
}
// Add the source location and the guard.
@ -1344,9 +1331,6 @@ namespace storm {
transitions * = this - > variables . rowExpressionAdapter - > translateExpression ( edge . getRate ( ) ) ;
}
t2 = std : : chrono : : high_resolution_clock : : now ( ) ;
std : : cout < < " rest took " < < std : : chrono : : duration_cast < std : : chrono : : milliseconds > ( t2 - t1 ) . count ( ) < < " ms " < < std : : endl ;
return EdgeDd ( guard , guard * transitions , globalVariablesInSomeDestination ) ;
} else {
return EdgeDd ( this - > variables . manager - > template getAddZero < ValueType > ( ) , this - > variables . manager - > template getAddZero < ValueType > ( ) ) ;
@ -1355,15 +1339,12 @@ namespace storm {
ActionDd buildActionDdForActionIndex ( storm : : jani : : Automaton const & automaton , uint64_t actionIndex , uint64_t localNondeterminismVariableOffset ) {
// Translate the individual edges.
auto t1 = std : : chrono : : high_resolution_clock : : now ( ) ;
std : : vector < EdgeDd > edgeDds ;
for ( auto const & edge : automaton . getEdges ( ) ) {
if ( edge . getActionId ( ) = = actionIndex ) {
edgeDds . push_back ( buildEdgeDd ( automaton , edge ) ) ;
}
}
auto t2 = std : : chrono : : high_resolution_clock : : now ( ) ;
std : : cout < < " building edges for index took " < < std : : chrono : : duration_cast < std : : chrono : : milliseconds > ( t2 - t1 ) . count ( ) < < " ms " < < std : : endl ;
// Now combine the edges to a single action.
if ( ! edgeDds . empty ( ) ) {
@ -1402,7 +1383,6 @@ namespace storm {
allTransitions + = edgeDd . transitions ;
// Keep track of the fragment that is writing global variables.
auto t1 = std : : chrono : : high_resolution_clock : : now ( ) ;
for ( auto const & variable : edgeDd . writtenGlobalVariables ) {
auto it = globalVariableToWritingFragment . find ( variable ) ;
if ( it ! = globalVariableToWritingFragment . end ( ) ) {
@ -1411,29 +1391,21 @@ namespace storm {
globalVariableToWritingFragment [ variable ] = guardBdd ;
}
}
auto t2 = std : : chrono : : high_resolution_clock : : now ( ) ;
totalTime + = t2 - t1 ;
}
return ActionDd ( allGuards . template toAdd < ValueType > ( ) , allTransitions , std : : make_pair < uint64_t , uint64_t > ( 0 , 0 ) , globalVariableToWritingFragment , this - > variables . manager - > getBddZero ( ) ) ;
}
mutable std : : chrono : : duration < uint64_t , std : : nano > totalTime = std : : chrono : : duration < uint64_t , std : : nano > ( 0 ) ;
void addToVariableWritingFragmentMap ( std : : map < storm : : expressions : : Variable , storm : : dd : : Bdd < Type > > & globalVariableToWritingFragment , storm : : expressions : : Variable const & variable , storm : : dd : : Bdd < Type > const & partToAdd ) const {
auto t1 = std : : chrono : : high_resolution_clock : : now ( ) ;
auto it = globalVariableToWritingFragment . find ( variable ) ;
if ( it ! = globalVariableToWritingFragment . end ( ) ) {
it - > second | = partToAdd ;
} else {
globalVariableToWritingFragment . emplace ( variable , partToAdd ) ;
}
auto t2 = std : : chrono : : high_resolution_clock : : now ( ) ;
totalTime + = t2 - t1 ;
}
std : : map < storm : : expressions : : Variable , storm : : dd : : Bdd < Type > > joinVariableWritingFragmentMaps ( std : : map < storm : : expressions : : Variable , storm : : dd : : Bdd < Type > > const & globalVariableToWritingFragment1 , std : : map < storm : : expressions : : Variable , storm : : dd : : Bdd < Type > > const & globalVariableToWritingFragment2 ) {
auto t1 = std : : chrono : : high_resolution_clock : : now ( ) ;
std : : map < storm : : expressions : : Variable , storm : : dd : : Bdd < Type > > result = globalVariableToWritingFragment1 ;
for ( auto const & entry : globalVariableToWritingFragment2 ) {
@ -1444,8 +1416,6 @@ namespace storm {
result [ entry . first ] = entry . second ;
}
}
auto t2 = std : : chrono : : high_resolution_clock : : now ( ) ;
totalTime + = t2 - t1 ;
return result ;
}
@ -1533,12 +1503,9 @@ namespace storm {
choiceDds [ k ] + = remainingGuardChoicesIntersection . template toAdd < ValueType > ( ) * currentEdge . transitions ;
// Keep track of the written global variables of the fragment.
auto t1 = std : : chrono : : high_resolution_clock : : now ( ) ;
for ( auto const & variable : currentEdge . writtenGlobalVariables ) {
addToVariableWritingFragmentMap ( globalVariableToWritingFragment , variable , remainingGuardChoicesIntersection & & indicesEncodedWithLocalNondeterminismVariables [ k ] . first ) ;
}
auto t2 = std : : chrono : : high_resolution_clock : : now ( ) ;
totalTime + = t2 - t1 ;
}
// Remove overlapping parts from the command guard DD
@ -1565,7 +1532,6 @@ namespace storm {
}
AutomatonDd buildAutomatonDd ( std : : string const & automatonName , std : : map < uint_fast64_t , uint_fast64_t > const & actionIndexToLocalNondeterminismVariableOffset ) {
auto t1 = std : : chrono : : high_resolution_clock : : now ( ) ;
AutomatonDd result ( this - > variables . automatonToIdentityMap . at ( automatonName ) ) ;
storm : : jani : : Automaton const & automaton = this - > model . getAutomaton ( automatonName ) ;
@ -1574,16 +1540,11 @@ namespace storm {
if ( ! automaton . hasEdgeLabeledWithActionIndex ( actionIndex ) ) {
continue ;
}
auto inner1 = std : : chrono : : high_resolution_clock : : now ( ) ;
ActionDd actionDd = buildActionDdForActionIndex ( automaton , actionIndex , actionIndexToLocalNondeterminismVariableOffset . at ( actionIndex ) ) ;
result . actionIndexToAction [ actionIndex ] = actionDd ;
result . setLowestLocalNondeterminismVariable ( std : : max ( result . getLowestLocalNondeterminismVariable ( ) , actionDd . getLowestLocalNondeterminismVariable ( ) ) ) ;
result . setHighestLocalNondeterminismVariable ( std : : max ( result . getHighestLocalNondeterminismVariable ( ) , actionDd . getHighestLocalNondeterminismVariable ( ) ) ) ;
auto inner2 = std : : chrono : : high_resolution_clock : : now ( ) ;
std : : cout < < " building action " < < action . getName ( ) < < " took " < < std : : chrono : : duration_cast < std : : chrono : : milliseconds > ( inner2 - inner1 ) . count ( ) < < " ms " < < std : : endl ;
}
auto t2 = std : : chrono : : high_resolution_clock : : now ( ) ;
std : : cout < < " building automaton " < < automatonName < < " took " < < std : : chrono : : duration_cast < std : : chrono : : milliseconds > ( t2 - t1 ) . count ( ) < < " ms " < < std : : endl ;
return result ;
}
@ -1615,18 +1576,14 @@ namespace storm {
// Add missing global variable identities, action and nondeterminism encodings.
for ( auto & action : automaton . actionIndexToAction ) {
auto t1 = std : : chrono : : high_resolution_clock : : now ( ) ;
illegalFragment | = action . second . illegalFragment ;
addMissingGlobalVariableIdentities ( action . second ) ;
auto t2 = std : : chrono : : high_resolution_clock : : now ( ) ;
totalTime + = t2 - t1 ;
storm : : dd : : Add < Type , ValueType > actionEncoding = encodeAction ( action . first ! = this - > model . getSilentActionIndex ( ) ? boost : : optional < uint64_t > ( action . first ) : boost : : none , this - > variables ) ;
storm : : dd : : Add < Type , ValueType > missingNondeterminismEncoding = encodeIndex ( 0 , action . second . getHighestLocalNondeterminismVariable ( ) , numberOfUsedNondeterminismVariables - action . second . getHighestLocalNondeterminismVariable ( ) , this - > variables ) ;
storm : : dd : : Add < Type , ValueType > extendedTransitions = actionEncoding * missingNondeterminismEncoding * action . second . transitions ;
result + = extendedTransitions ;
}
std : : cout < < " accumulated: " < < std : : chrono : : duration_cast < std : : chrono : : milliseconds > ( totalTime ) . count ( ) < < " ms " < < std : : endl ;
return ComposerResult < Type , ValueType > ( result , illegalFragment , numberOfUsedNondeterminismVariables ) ;
} else if ( this - > model . getModelType ( ) = = storm : : jani : : ModelType : : DTMC | | this - > model . getModelType ( ) = = storm : : jani : : ModelType : : CTMC ) {
// Simply add all actions, but make sure to include the missing global variable identities.
@ -1722,7 +1679,7 @@ namespace storm {
initialStates & = variables . manager - > getEncoding ( variables . automatonToLocationVariableMap . at ( automaton . getName ( ) ) . first , automaton . getInitialLocationIndex ( ) ) ;
}
for ( auto const & metaVariable : variables . rowMetaVariables ) {
initialStates & = variables . manager - > getRange ( metaVariable ) ;
initialStates & = variables . variableToRangeMap . at ( metaVariable ) ;
}
return initialStates ;
}