@ -1,5 +1,7 @@
# include "src/builder/DdPrismModelBuilder.h"
# include <boost/algorithm/string/join.hpp>
# include "src/models/symbolic/Dtmc.h"
# include "src/models/symbolic/Ctmc.h"
# include "src/models/symbolic/Mdp.h"
@ -9,12 +11,13 @@
# include "src/settings/SettingsManager.h"
# include "src/exceptions/InvalidStateException.h"
# include "src/exceptions/NotSupportedException.h"
# include "src/exceptions/InvalidArgumentException.h"
# include "src/utility/prism.h"
# include "src/utility/math.h"
# include "src/storage/prism/Program.h"
# include "src/storage/prism/Compositions.h"
# include "src/storage/dd/Add.h"
# include "src/storage/dd/cudd/CuddAddIterator.h"
@ -189,6 +192,238 @@ namespace storm {
}
} ;
template < storm : : dd : : DdType Type , typename ValueType >
class ModuleComposer : public storm : : prism : : CompositionVisitor {
public :
ModuleComposer ( typename DdPrismModelBuilder < Type , ValueType > : : GenerationInformation & generationInfo ) : generationInfo ( generationInfo ) {
for ( auto const & actionIndex : generationInfo . program . getSynchronizingActionIndices ( ) ) {
synchronizingActionToOffsetMap [ actionIndex ] = 0 ;
}
}
typename DdPrismModelBuilder < Type , ValueType > : : ModuleDecisionDiagram compose ( storm : : prism : : Composition const & composition ) {
std : : cout < < " composing the system " < < composition < < std : : endl ;
return boost : : any_cast < typename DdPrismModelBuilder < Type , ValueType > : : ModuleDecisionDiagram > ( composition . accept ( * this ) ) ;
}
virtual boost : : any visit ( storm : : prism : : ModuleComposition const & composition ) override {
STORM_LOG_TRACE ( " Translating module ' " < < composition . getModuleName ( ) < < " '. " ) ;
typename DdPrismModelBuilder < Type , ValueType > : : ModuleDecisionDiagram result = DdPrismModelBuilder < Type , ValueType > : : createModuleDecisionDiagram ( generationInfo , generationInfo . program . getModule ( composition . getModuleName ( ) ) , synchronizingActionToOffsetMap ) ;
// Update the offset indices.
for ( auto const & actionIndex : generationInfo . program . getSynchronizingActionIndices ( ) ) {
if ( result . hasSynchronizingAction ( actionIndex ) ) {
synchronizingActionToOffsetMap [ actionIndex ] = result . synchronizingActionToDecisionDiagramMap [ actionIndex ] . numberOfUsedNondeterminismVariables ;
}
}
return result ;
}
virtual boost : : any visit ( storm : : prism : : RenamingComposition const & composition ) override {
// First, we translate the subcomposition.
typename DdPrismModelBuilder < Type , ValueType > : : ModuleDecisionDiagram sub = boost : : any_cast < typename DdPrismModelBuilder < Type , ValueType > : : ModuleDecisionDiagram > ( composition . getSubcomposition ( ) . accept ( * this ) ) ;
// Create the mapping from action indices to action indices.
std : : map < uint_fast64_t , uint_fast64_t > renaming ;
for ( auto const & namePair : composition . getActionRenaming ( ) ) {
STORM_LOG_THROW ( generationInfo . program . hasAction ( namePair . first ) , storm : : exceptions : : InvalidArgumentException , " Composition refers to unknown action ' " < < namePair . first < < " '. " ) ;
STORM_LOG_THROW ( generationInfo . program . hasAction ( namePair . second ) , storm : : exceptions : : InvalidArgumentException , " Composition refers to unknown action ' " < < namePair . second < < " '. " ) ;
renaming . emplace ( generationInfo . program . getActionIndex ( namePair . first ) , generationInfo . program . getActionIndex ( namePair . second ) ) ;
}
// Perform the renaming and return result.
return rename ( sub , renaming ) ;
}
virtual boost : : any visit ( storm : : prism : : HidingComposition const & composition ) override {
// First, we translate the subcomposition.
typename DdPrismModelBuilder < Type , ValueType > : : ModuleDecisionDiagram sub = boost : : any_cast < typename DdPrismModelBuilder < Type , ValueType > : : ModuleDecisionDiagram > ( composition . getSubcomposition ( ) . accept ( * this ) ) ;
// Create the mapping from action indices to action indices.
std : : set < uint_fast64_t > actionIndicesToHide ;
for ( auto const & action : composition . getActionsToHide ( ) ) {
STORM_LOG_THROW ( generationInfo . program . hasAction ( action ) , storm : : exceptions : : InvalidArgumentException , " Composition refers to unknown action ' " < < action < < " '. " ) ;
actionIndicesToHide . insert ( generationInfo . program . getActionIndex ( action ) ) ;
}
// Perform the hiding and return result.
return hide ( sub , actionIndicesToHide ) ;
}
virtual boost : : any visit ( storm : : prism : : SynchronizingParallelComposition const & composition ) override {
// First, we translate the subcompositions.
typename DdPrismModelBuilder < Type , ValueType > : : ModuleDecisionDiagram left = boost : : any_cast < typename DdPrismModelBuilder < Type , ValueType > : : ModuleDecisionDiagram > ( composition . getLeftSubcomposition ( ) . accept ( * this ) ) ;
typename DdPrismModelBuilder < Type , ValueType > : : ModuleDecisionDiagram right = boost : : any_cast < typename DdPrismModelBuilder < Type , ValueType > : : ModuleDecisionDiagram > ( composition . getRightSubcomposition ( ) . accept ( * this ) ) ;
// Then, determine the action indices on which we need to synchronize.
std : : set < uint_fast64_t > leftSynchronizationActionIndices = left . getSynchronizingActionIndices ( ) ;
std : : set < uint_fast64_t > rightSynchronizationActionIndices = right . getSynchronizingActionIndices ( ) ;
std : : set < uint_fast64_t > synchronizationActionIndices ;
std : : set_intersection ( leftSynchronizationActionIndices . begin ( ) , leftSynchronizationActionIndices . end ( ) , rightSynchronizationActionIndices . begin ( ) , rightSynchronizationActionIndices . end ( ) , std : : inserter ( synchronizationActionIndices , synchronizationActionIndices . begin ( ) ) ) ;
// Finally, we compose the subcompositions to create the result.
composeInParallel ( left , right , synchronizationActionIndices ) ;
return left ;
}
virtual boost : : any visit ( storm : : prism : : InterleavingParallelComposition const & composition ) override {
// First, we translate the subcompositions.
typename DdPrismModelBuilder < Type , ValueType > : : ModuleDecisionDiagram left = boost : : any_cast < typename DdPrismModelBuilder < Type , ValueType > : : ModuleDecisionDiagram > ( composition . getLeftSubcomposition ( ) . accept ( * this ) ) ;
typename DdPrismModelBuilder < Type , ValueType > : : ModuleDecisionDiagram right = boost : : any_cast < typename DdPrismModelBuilder < Type , ValueType > : : ModuleDecisionDiagram > ( composition . getRightSubcomposition ( ) . accept ( * this ) ) ;
// Finally, we compose the subcompositions to create the result.
composeInParallel ( left , right , std : : set < uint_fast64_t > ( ) ) ;
return left ;
}
virtual boost : : any visit ( storm : : prism : : RestrictedParallelComposition const & composition ) override {
// First, we translate the subcompositions.
typename DdPrismModelBuilder < Type , ValueType > : : ModuleDecisionDiagram left = boost : : any_cast < typename DdPrismModelBuilder < Type , ValueType > : : ModuleDecisionDiagram > ( composition . getLeftSubcomposition ( ) . accept ( * this ) ) ;
typename DdPrismModelBuilder < Type , ValueType > : : ModuleDecisionDiagram right = boost : : any_cast < typename DdPrismModelBuilder < Type , ValueType > : : ModuleDecisionDiagram > ( composition . getRightSubcomposition ( ) . accept ( * this ) ) ;
// Construct the synchronizing action indices from the synchronizing action names.
std : : set < uint_fast64_t > synchronizingActionIndices ;
for ( auto const & action : composition . getSynchronizingActions ( ) ) {
synchronizingActionIndices . insert ( generationInfo . program . getActionIndex ( action ) ) ;
}
std : : set < uint_fast64_t > leftSynchronizationActionIndices = left . getSynchronizingActionIndices ( ) ;
bool isContainedInLeft = std : : includes ( leftSynchronizationActionIndices . begin ( ) , leftSynchronizationActionIndices . end ( ) , synchronizingActionIndices . begin ( ) , synchronizingActionIndices . end ( ) ) ;
STORM_LOG_WARN_COND ( isContainedInLeft , " Left subcomposition of composition ' " < < composition < < " ' does not include all actions over which to synchronize. " ) ;
std : : set < uint_fast64_t > rightSynchronizationActionIndices = right . getSynchronizingActionIndices ( ) ;
bool isContainedInRight = std : : includes ( rightSynchronizationActionIndices . begin ( ) , rightSynchronizationActionIndices . end ( ) , synchronizingActionIndices . begin ( ) , synchronizingActionIndices . end ( ) ) ;
STORM_LOG_WARN_COND ( isContainedInRight , " Right subcomposition of composition ' " < < composition < < " ' does not include all actions over which to synchronize. " ) ;
// Finally, we compose the subcompositions to create the result.
composeInParallel ( left , right , synchronizingActionIndices ) ;
return left ;
}
private :
/*!
* Hides the actions of the given module according to the given set . As a result , the module is modified in
* place .
*/
void hide ( typename DdPrismModelBuilder < Type , ValueType > : : ModuleDecisionDiagram & sub , std : : set < uint_fast64_t > const & actionIndicesToHide ) const {
STORM_LOG_TRACE ( " Hiding the actions " < < boost : : join ( actionIndicesToHide , " , " ) < < " . " ) ;
for ( auto const & action : sub . synchronizingActionToDecisionDiagramMap ) {
if ( actionIndicesToHide . find ( action ) ! = actionIndicesToHide . end ( ) ) {
}
}
}
/*!
* Renames the actions of the given module according to the given renaming .
*/
typename DdPrismModelBuilder < Type , ValueType > : : ModuleDecisionDiagram rename ( typename DdPrismModelBuilder < Type , ValueType > : : ModuleDecisionDiagram & sub , std : : map < uint_fast64_t , uint_fast64_t > const & renaming ) const {
STORM_LOG_TRACE ( " Renaming actions. " ) ;
uint_fast64_t numberOfUsedNondeterminismVariables = sub . numberOfUsedNondeterminismVariables ;
std : : map < uint_fast64_t , typename DdPrismModelBuilder < Type , ValueType > : : ActionDecisionDiagram > actionIndexToDdMap ;
// Go through all action DDs with a synchronizing label and rename them if they appear in the renaming.
for ( auto const & action : sub . synchronizingActionToDecisionDiagramMap ) {
auto renamingIt = renaming . find ( action . first ) ;
if ( renamingIt ! = renaming . end ( ) ) {
// If the action is to be renamed and an action with the target index already exists, we need
// to combine the action DDs.
auto itNewActions = actionIndexToDdMap . find ( renamingIt . second ) ;
if ( itNewActions ! = actionIndexToDdMap . end ( ) ) {
actionIndexToDdMap [ renamingIt . second ] = DdPrismModelBuilder < Type , ValueType > : : combineUnsynchronizedActions ( generationInfo , action . second , itNewActions - > second ) ;
} else {
// In this case, we can simply copy the action over.
actionIndexToDdMap [ renamingIt . second ] = action . second ;
}
} else {
// If the action is not to be renamed, we need to copy it over. However, if some other action
// was renamed to the very same action name before, we need to combine the transitions.
auto itNewActions = actionIndexToDdMap . find ( action . first ) ;
if ( itNewActions ! = actionIndexToDdMap . end ( ) ) {
actionIndexToDdMap [ action . first ] = DdPrismModelBuilder < Type , ValueType > : : combineUnsynchronizedActions ( generationInfo , action . second , itNewActions - > second ) ;
} else {
// In this case, we can simply copy the action over.
actionIndexToDdMap [ action . first ] = action . second ;
}
}
}
return ModuleDecisionDiagram ( sub . independentAction , actionIndexToDdMap , sub . identity , numberOfUsedNondeterminismVariables ) ;
}
/*!
* Composes the given modules while synchronizing over the provided action indices . As a result , the first
* module is modified in place and will contain the composition after a call to this method .
*/
void composeInParallel ( typename DdPrismModelBuilder < Type , ValueType > : : ModuleDecisionDiagram & left , typename DdPrismModelBuilder < Type , ValueType > : : ModuleDecisionDiagram & right , std : : set < uint_fast64_t > const & synchronizationActionIndices ) const {
STORM_LOG_TRACE ( " Composing two modules over the actions " < < boost : : join ( synchronizationActionIndices , " , " ) < < " . " ) ;
// Combine the tau action.
uint_fast64_t numberOfUsedNondeterminismVariables = right . independentAction . numberOfUsedNondeterminismVariables ;
left . independentAction = DdPrismModelBuilder < Type , ValueType > : : combineUnsynchronizedActions ( generationInfo , left . independentAction , right . independentAction , left . identity , right . identity ) ;
numberOfUsedNondeterminismVariables = std : : max ( numberOfUsedNondeterminismVariables , left . independentAction . numberOfUsedNondeterminismVariables ) ;
// Create an empty action for the case where one of the modules does not have a certain action.
typename DdPrismModelBuilder < Type , ValueType > : : ActionDecisionDiagram emptyAction ( * generationInfo . manager ) ;
// Treat all non-tau actions of the left module.
for ( auto & action : left . synchronizingActionToDecisionDiagramMap ) {
// If we need to synchronize over this action index, we try to do so now.
if ( synchronizationActionIndices . find ( action . first ) ! = synchronizationActionIndices . end ( ) ) {
// If we are to synchronize over an action that does not exist in the second module, the result
// is that the synchronization is the empty action.
if ( ! right . hasSynchronizingAction ( action . first ) ) {
action . second = emptyAction ;
} else {
// Otherwise, the actions of the modules are synchronized.
action . second = DdPrismModelBuilder < Type , ValueType > : : combineSynchronizingActions ( generationInfo , action . second , right . synchronizingActionToDecisionDiagramMap [ action . first ] ) ;
}
} else {
// If we don't synchronize over this action, we need to construct the interleaving.
// If both modules contain the action, we need to mutually multiply the other identity.
if ( right . hasSynchronizingAction ( action . first ) ) {
action . second = DdPrismModelBuilder < Type , ValueType > : : combineUnsynchronizedActions ( generationInfo , action . second , right . synchronizingActionToDecisionDiagramMap [ action . first ] , left . identity , right . identity ) ;
} else {
// If only the first module has this action, we need to use a dummy action decision diagram
// for the second module.
action . second = DdPrismModelBuilder < Type , ValueType > : : combineUnsynchronizedActions ( generationInfo , action . second , emptyAction , left . identity , right . identity ) ;
}
}
numberOfUsedNondeterminismVariables = std : : max ( numberOfUsedNondeterminismVariables , action . second . numberOfUsedNondeterminismVariables ) ;
}
// Treat all non-tau actions of the right module.
for ( auto const & actionIndex : right . getSynchronizingActionIndices ( ) ) {
// Here, we only need to treat actions that the first module does not have, because we have handled
// this case earlier.
if ( ! left . hasSynchronizingAction ( actionIndex ) ) {
if ( synchronizationActionIndices . find ( actionIndex ) ! = synchronizationActionIndices . end ( ) ) {
// If we are to synchronize over this action that does not exist in the first module, the
// result is that the synchronization is the empty action.
left . synchronizingActionToDecisionDiagramMap [ actionIndex ] = emptyAction ;
} else {
// If only the second module has this action, we need to use a dummy action decision diagram
// for the first module.
left . synchronizingActionToDecisionDiagramMap [ actionIndex ] = DdPrismModelBuilder < Type , ValueType > : : combineUnsynchronizedActions ( generationInfo , emptyAction , right . synchronizingActionToDecisionDiagramMap [ actionIndex ] , left . identity , right . identity ) ;
}
}
numberOfUsedNondeterminismVariables = std : : max ( numberOfUsedNondeterminismVariables , left . synchronizingActionToDecisionDiagramMap [ actionIndex ] . numberOfUsedNondeterminismVariables ) ;
}
// Combine identity matrices.
left . identity = left . identity * right . identity ;
// Keep track of the number of nondeterminism variables used.
left . numberOfUsedNondeterminismVariables = std : : max ( left . numberOfUsedNondeterminismVariables , numberOfUsedNondeterminismVariables ) ;
}
typename DdPrismModelBuilder < Type , ValueType > : : GenerationInformation & generationInfo ;
std : : map < uint_fast64_t , uint_fast64_t > synchronizingActionToOffsetMap ;
} ;
template < storm : : dd : : DdType Type , typename ValueType >
DdPrismModelBuilder < Type , ValueType > : : Options : : Options ( ) : buildAllRewardModels ( true ) , rewardModelsToBuild ( ) , constantDefinitions ( ) , buildAllLabels ( true ) , labelsToBuild ( ) , terminalStates ( ) , negatedTerminalStates ( ) {
// Intentionally left empty.
@ -636,21 +871,30 @@ namespace storm {
template < storm : : dd : : DdType Type , typename ValueType >
typename DdPrismModelBuilder < Type , ValueType > : : ActionDecisionDiagram DdPrismModelBuilder < Type , ValueType > : : combineUnsynchronizedActions ( GenerationInformation const & generationInfo , ActionDecisionDiagram & action1 , ActionDecisionDiagram & action2 , storm : : dd : : Add < Type , ValueType > const & identityDd1 , storm : : dd : : Add < Type , ValueType > const & identityDd2 ) {
storm : : dd : : Add < Type , ValueType > action1Extended = action1 . transitionsDd * identityDd2 ;
storm : : dd : : Add < Type , ValueType > action2Extended = action2 . transitionsDd * identityDd1 ;
// First extend the action DDs by the other identities.
STORM_LOG_TRACE ( " Multiplying identities to combine unsynchronized actions. " ) ;
action1 . transitionsDd = action1 . transitionsDd * identityDd2 ;
action2 . transitionsDd = action2 . transitionsDd * identityDd1 ;
// Then combine the extended action DDs.
return combineUnsynchronizedActions ( generationInfo , action1 , action2 ) ;
}
template < storm : : dd : : DdType Type , typename ValueType >
typename DdPrismModelBuilder < Type , ValueType > : : ActionDecisionDiagram DdPrismModelBuilder < Type , ValueType > : : combineUnsynchronizedActions ( GenerationInformation const & generationInfo , ActionDecisionDiagram & action1 , ActionDecisionDiagram & action2 ) {
STORM_LOG_TRACE ( " Combining unsynchronized actions. " ) ;
// Make both action DDs write to the same global variables.
std : : set < storm : : expressions : : Variable > assignedGlobalVariables = equalizeAssignedGlobalVariables ( generationInfo , action1 , action2 ) ;
if ( generationInfo . program . getModelType ( ) = = storm : : prism : : Program : : ModelType : : DTMC | | generationInfo . program . getModelType ( ) = = storm : : prism : : Program : : ModelType : : CTMC ) {
return ActionDecisionDiagram ( action1 . guardDd + action2 . guardDd , action1Extended + action2Extended , assignedGlobalVariables , 0 ) ;
return ActionDecisionDiagram ( action1 . guardDd + action2 . guardDd , action1 . transitionsDd + action2 . transitionsD d, assignedGlobalVariables , 0 ) ;
} else if ( generationInfo . program . getModelType ( ) = = storm : : prism : : Program : : ModelType : : MDP ) {
if ( action1 . transitionsDd . isZero ( ) ) {
return ActionDecisionDiagram ( action2 . guardDd , action2Extended , assignedGlobalVariables , action2 . numberOfUsedNondeterminismVariables ) ;
return ActionDecisionDiagram ( action2 . guardDd , action2 . transitionsD d, assignedGlobalVariables , action2 . numberOfUsedNondeterminismVariables ) ;
} else if ( action2 . transitionsDd . isZero ( ) ) {
return ActionDecisionDiagram ( action1 . guardDd , action1Extende d , assignedGlobalVariables , action1 . numberOfUsedNondeterminismVariables ) ;
return ActionDecisionDiagram ( action1 . guardDd , action1 . transitionsD d, assignedGlobalVariables , action1 . numberOfUsedNondeterminismVariables ) ;
}
// Bring both choices to the same number of variables that encode the nondeterminism.
@ -661,18 +905,18 @@ namespace storm {
for ( uint_fast64_t i = action2 . numberOfUsedNondeterminismVariables ; i < action1 . numberOfUsedNondeterminismVariables ; + + i ) {
nondeterminismEncoding * = generationInfo . manager - > getEncoding ( generationInfo . nondeterminismMetaVariables [ i ] , 0 ) . template toAdd < ValueType > ( ) ;
}
action2Extende d * = nondeterminismEncoding ;
action2 . transitionsD d * = nondeterminismEncoding ;
} else if ( action2 . numberOfUsedNondeterminismVariables > action1 . numberOfUsedNondeterminismVariables ) {
storm : : dd : : Add < Type , ValueType > nondeterminismEncoding = generationInfo . manager - > template getAddOne < ValueType > ( ) ;
for ( uint_fast64_t i = action1 . numberOfUsedNondeterminismVariables ; i < action2 . numberOfUsedNondeterminismVariables ; + + i ) {
nondeterminismEncoding * = generationInfo . manager - > getEncoding ( generationInfo . nondeterminismMetaVariables [ i ] , 0 ) . template toAdd < ValueType > ( ) ;
}
action1Extende d * = nondeterminismEncoding ;
action1 . transitionsD d * = nondeterminismEncoding ;
}
// Add a new variable that resolves the nondeterminism between the two choices.
storm : : dd : : Add < Type , ValueType > combinedTransitions = generationInfo . manager - > getEncoding ( generationInfo . nondeterminismMetaVariables [ numberOfUsedNondeterminismVariables ] , 1 ) . ite ( action2Extended , action1Extende d ) ;
storm : : dd : : Add < Type , ValueType > combinedTransitions = generationInfo . manager - > getEncoding ( generationInfo . nondeterminismMetaVariables [ numberOfUsedNondeterminismVariables ] , 1 ) . ite ( action2 . transitionsDd , action1 . transitionsD d) ;
return ActionDecisionDiagram ( ( action1 . guardDd . toBdd ( ) | | action2 . guardDd . toBdd ( ) ) . template toAdd < ValueType > ( ) , combinedTransitions , assignedGlobalVariables , numberOfUsedNondeterminismVariables + 1 ) ;
} else {
@ -789,61 +1033,8 @@ namespace storm {
template < storm : : dd : : DdType Type , typename ValueType >
typename DdPrismModelBuilder < Type , ValueType > : : SystemResult DdPrismModelBuilder < Type , ValueType > : : createSystemDecisionDiagram ( GenerationInformation & generationInfo ) {
// Create the initial offset mapping.
std : : map < uint_fast64_t , uint_fast64_t > synchronizingActionToOffsetMap ;
for ( auto const & actionIndex : generationInfo . program . getSynchronizingActionIndices ( ) ) {
synchronizingActionToOffsetMap [ actionIndex ] = 0 ;
}
// Start by creating DDs for the first module.
STORM_LOG_TRACE ( " Translating (first) module ' " < < generationInfo . program . getModule ( 0 ) . getName ( ) < < " '. " ) ;
ModuleDecisionDiagram system = createModuleDecisionDiagram ( generationInfo , generationInfo . program . getModule ( 0 ) , synchronizingActionToOffsetMap ) ;
// Now translate module by module and combine it with the system created thus far.
for ( uint_fast64_t i = 1 ; i < generationInfo . program . getNumberOfModules ( ) ; + + i ) {
storm : : prism : : Module const & currentModule = generationInfo . program . getModule ( i ) ;
STORM_LOG_TRACE ( " Translating module ' " < < currentModule . getName ( ) < < " '. " ) ;
// Update the offset index.
for ( auto const & actionIndex : generationInfo . program . getSynchronizingActionIndices ( ) ) {
if ( system . hasSynchronizingAction ( actionIndex ) ) {
synchronizingActionToOffsetMap [ actionIndex ] = system . synchronizingActionToDecisionDiagramMap [ actionIndex ] . numberOfUsedNondeterminismVariables ;
}
}
ModuleDecisionDiagram currentModuleDd = createModuleDecisionDiagram ( generationInfo , currentModule , synchronizingActionToOffsetMap ) ;
// Combine the non-synchronizing action.
uint_fast64_t numberOfUsedNondeterminismVariables = currentModuleDd . numberOfUsedNondeterminismVariables ;
system . independentAction = combineUnsynchronizedActions ( generationInfo , system . independentAction , currentModuleDd . independentAction , system . identity , currentModuleDd . identity ) ;
numberOfUsedNondeterminismVariables = std : : max ( numberOfUsedNondeterminismVariables , system . independentAction . numberOfUsedNondeterminismVariables ) ;
ActionDecisionDiagram emptyAction ( * generationInfo . manager ) ;
// For all synchronizing actions that the next module does not have, we need to multiply the identity of the next module.
for ( auto & action : system . synchronizingActionToDecisionDiagramMap ) {
if ( ! currentModuleDd . hasSynchronizingAction ( action . first ) ) {
action . second = combineUnsynchronizedActions ( generationInfo , action . second , emptyAction , system . identity , currentModuleDd . identity ) ;
}
}
// Combine synchronizing actions.
for ( auto const & actionIndex : currentModule . getSynchronizingActionIndices ( ) ) {
if ( system . hasSynchronizingAction ( actionIndex ) ) {
system . synchronizingActionToDecisionDiagramMap [ actionIndex ] = combineSynchronizingActions ( generationInfo , system . synchronizingActionToDecisionDiagramMap [ actionIndex ] , currentModuleDd . synchronizingActionToDecisionDiagramMap [ actionIndex ] ) ;
numberOfUsedNondeterminismVariables = std : : max ( numberOfUsedNondeterminismVariables , system . synchronizingActionToDecisionDiagramMap [ actionIndex ] . numberOfUsedNondeterminismVariables ) ;
} else {
system . synchronizingActionToDecisionDiagramMap [ actionIndex ] = combineUnsynchronizedActions ( generationInfo , emptyAction , currentModuleDd . synchronizingActionToDecisionDiagramMap [ actionIndex ] , system . identity , currentModuleDd . identity ) ;
numberOfUsedNondeterminismVariables = std : : max ( numberOfUsedNondeterminismVariables , system . synchronizingActionToDecisionDiagramMap [ actionIndex ] . numberOfUsedNondeterminismVariables ) ;
}
}
// Combine identity matrices.
system . identity = system . identity * currentModuleDd . identity ;
// Keep track of the number of nondeterminism variables used.
system . numberOfUsedNondeterminismVariables = std : : max ( system . numberOfUsedNondeterminismVariables , numberOfUsedNondeterminismVariables ) ;
}
ModuleComposer < Type , ValueType > composer ( generationInfo ) ;
ModuleDecisionDiagram system = composer . compose ( generationInfo . program . specifiesSystemComposition ( ) ? generationInfo . program . getSystemCompositionConstruct ( ) . getSystemComposition ( ) : * generationInfo . program . getDefaultSystemComposition ( ) ) ;
storm : : dd : : Add < Type , ValueType > result = createSystemFromModule ( generationInfo , system ) ;
xxxxxxxxxx