@ -5,6 +5,8 @@ 
			
		
	
		
			
				
					# include  "storm/storage/jani/Compositions.h" 
  
			
		
	
		
			
				
					# include  "storm/storage/jani/CompositionInformationVisitor.h" 
  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					# include  "storm/utility/combinatorics.h" 
  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					# include  "storm/utility/macros.h" 
  
			
		
	
		
			
				
					# include  "storm/exceptions/WrongFormatException.h" 
  
			
		
	
		
			
				
					# include  "storm/exceptions/InvalidArgumentException.h" 
  
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -61,15 +63,15 @@ namespace storm { 
			
		
	
		
			
				
					            }  
			
		
	
		
			
				
					             
			
		
	
		
			
				
					            uint64_t  actionIndex ;  
			
		
	
		
			
				
					            std : : vector < std : : pair < uint64_t ,  uint64_t > >  condition ;  
			
		
	
		
			
				
					            std : : vector < uint64_t >  components ;  
			
		
	
		
			
				
					            std : : vector < uint64_t >  condition ;  
			
		
	
		
			
				
					            boost : : optional < storm : : expressions : : Expression >  rate ;  
			
		
	
		
			
				
					            std : : vector < storm : : expressions : : Expression >  probabilities ;  
			
		
	
		
			
				
					            std : : vector < std : : vector < std : : pair < uint64_t ,  uint64_t > > >  effects ;  
			
		
	
		
			
				
					            std : : vector < std : : vector < uint64_t > >  effects ;  
			
		
	
		
			
				
					            std : : shared_ptr < TemplateEdge >  templateEdge ;  
			
		
	
		
			
				
					        } ;  
			
		
	
		
			
				
					         
			
		
	
		
			
				
					        std : : vector < ConditionalMetaEdge >  createSynchronizingMetaEdges ( Model  const &  model ,  Automaton &  newAutomaton ,  std : : vector < std : : set < uint64_t > > &  synchronizingActionIndices ,  SynchronizationVector  const &  vector ,  std : : vector < std : : reference_wrapper < Automaton  const > >  const &  composedAutomata ,  storm : : solver : : SmtSolver &  solver )  {  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					        std : : vector < ConditionalMetaEdge >  createSynchronizingMetaEdges ( Model  const &  oldModel ,  Model &  newModel ,  std : : vector < std : : set < uint64_t > > &  synchronizingActionIndices ,  SynchronizationVector  const &  vector ,  std : : vector < std : : reference_wrapper < Automaton  const > >  const &  composedAutomata ,  storm : : solver : : SmtSolver &  solver )  {  
			
		
	
		
			
				
					            std : : vector < ConditionalMetaEdge >  result ;  
			
		
	
		
			
				
					             
			
		
	
		
			
				
					            // Gather all participating automata and the corresponding input symbols.
  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -77,22 +79,113 @@ namespace storm { 
			
		
	
		
			
				
					            for  ( uint64_t  i  =  0 ;  i  <  composedAutomata . size ( ) ;  + + i )  {  
			
		
	
		
			
				
					                std : : string  const &  actionName  =  vector . getInput ( i ) ;  
			
		
	
		
			
				
					                if  ( ! SynchronizationVector : : isNoActionInput ( actionName ) )  {  
			
		
	
		
			
				
					                    uint64_t  actionIndex  =  m odel. getActionIndex ( actionName ) ;  
			
		
	
		
			
				
					                    uint64_t  actionIndex  =  oldM odel. getActionIndex ( actionName ) ;  
			
		
	
		
			
				
					                    participatingAutomataAndActions . push_back ( std : : make_pair ( composedAutomata [ i ] ,  actionIndex ) ) ;  
			
		
	
		
			
				
					                    synchronizingActionIndices [ i ] . insert ( actionIndex ) ;  
			
		
	
		
			
				
					                }  
			
		
	
		
			
				
					            }  
			
		
	
		
			
				
					             
			
		
	
		
			
				
					            uint64_t  resultingActionIndex  =  Model : : SILENT_ACTION_INDEX ;  
			
		
	
		
			
				
					            if  ( vector . getOutput ( )  ! =  Model : : SILENT_ACTION_NAME )  {  
			
		
	
		
			
				
					                if  ( newModel . hasAction ( vector . getOutput ( ) ) )  {  
			
		
	
		
			
				
					                    resultingActionIndex  =  newModel . getActionIndex ( vector . getOutput ( ) ) ;  
			
		
	
		
			
				
					                }  else  {  
			
		
	
		
			
				
					                    resultingActionIndex  =  newModel . addAction ( vector . getOutput ( ) ) ;  
			
		
	
		
			
				
					                }  
			
		
	
		
			
				
					            }  
			
		
	
		
			
				
					             
			
		
	
		
			
				
					            bool  noCombinations  =  false ;  
			
		
	
		
			
				
					             
			
		
	
		
			
				
					            // Prepare the list that stores for each automaton the list of edges with the participating action.
  
			
		
	
		
			
				
					            std : : vector < std : : vector < std : : reference_wrapper < storm : : jani : : Edge  const > > >  possibleEdges ;  
			
		
	
		
			
				
					             
			
		
	
		
			
				
					            for  ( auto  const &  automatonActionPair  :  participatingAutomataAndActions )  {  
			
		
	
		
			
				
					                possibleEdges . emplace_back ( ) ;  
			
		
	
		
			
				
					                for  ( auto  const &  edge  :  automatonActionPair . first . get ( ) . getEdges ( ) )  {  
			
		
	
		
			
				
					                    if  ( edge . getActionIndex ( )  = =  automatonActionPair . second )  {  
			
		
	
		
			
				
					                        possibleEdges . back ( ) . push_back ( edge ) ;  
			
		
	
		
			
				
					                    }  
			
		
	
		
			
				
					                }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					                // If there were no edges with the participating action index, then there is no synchronization possible.
  
			
		
	
		
			
				
					                if  ( possibleEdges . back ( ) . empty ( ) )  {  
			
		
	
		
			
				
					                    noCombinations  =  true ;  
			
		
	
		
			
				
					                    break ;  
			
		
	
		
			
				
					                }  
			
		
	
		
			
				
					            }  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					             
			
		
	
		
			
				
					            return  result ;  
			
		
	
		
			
				
					        }  
			
		
	
		
			
				
					         
			
		
	
		
			
				
					        void  addEdgesToReachableLocations ( Model  const &  model ,  std : : vector < std : : reference_wrapper < Automaton  const & > >  const &  composedAutomata ,  Automaton &  newAutomaton ,  std : : vector < ConditionalMetaEdge >  const &  conditionalMetaEdges )  {  
			
		
	
		
			
				
					        std : : unordered_map < std : : vector < uint64_t > ,  uint64_t ,  storm : : utility : : vector : : VectorHash < uint64_t > >  addEdgesToReachableLocations ( Model  const &  model ,  std : : vector < std : : reference_wrapper < Automaton  const > >  const &  composedAutomata ,  Automaton &  newAutomaton ,  std : : vector < ConditionalMetaEdge >  const &  conditionalMetaEdges )  {  
			
		
	
		
			
				
					             
			
		
	
		
			
				
					            std : : vector < uint64_t >  locations ;  
			
		
	
		
			
				
					            // Maintain a stack of locations that still need to be to explored.
  
			
		
	
		
			
				
					            std : : vector < std : : vector < uint64_t > >  locationsToExplore ;  
			
		
	
		
			
				
					             
			
		
	
		
			
				
					            // Enumerate all initial location combinations.
  
			
		
	
		
			
				
					            std : : vector < std : : set < uint64_t > : : const_iterator >  initialLocationsIts ;  
			
		
	
		
			
				
					            std : : vector < std : : set < uint64_t > : : const_iterator >  initialLocationsItes ;  
			
		
	
		
			
				
					            for  ( auto  const &  automaton  :  composedAutomata )  {  
			
		
	
		
			
				
					                // TODO: iterate over initial locations of all automata
  
			
		
	
		
			
				
					                initialLocationsIts . push_back ( automaton . get ( ) . getInitialLocationIndices ( ) . cbegin ( ) ) ;  
			
		
	
		
			
				
					                initialLocationsItes . push_back ( automaton . get ( ) . getInitialLocationIndices ( ) . cend ( ) ) ;  
			
		
	
		
			
				
					            }  
			
		
	
		
			
				
					            std : : vector < uint64_t >  initialLocation ( composedAutomata . size ( ) ) ;  
			
		
	
		
			
				
					            storm : : utility : : combinatorics : : forEach ( initialLocationsIts ,  initialLocationsItes ,  [ & initialLocation ]  ( uint64_t  index ,  uint64_t  value )  {  initialLocation [ index ]  =  value ;  } ,  [ & locationsToExplore ,  & initialLocation ]  ( )  {  
			
		
	
		
			
				
					                locationsToExplore . push_back ( initialLocation ) ;  
			
		
	
		
			
				
					                return  true ;  
			
		
	
		
			
				
					            } ) ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					            // We also maintain a mapping from location combinations to new locations.
  
			
		
	
		
			
				
					            std : : unordered_map < std : : vector < uint64_t > ,  uint64_t ,  storm : : utility : : vector : : VectorHash < uint64_t > >  newLocationMapping ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					            // Register all initial locations as new locations.
  
			
		
	
		
			
				
					            for  ( auto  const &  location  :  locationsToExplore )  {  
			
		
	
		
			
				
					                uint64_t  id  =  newLocationMapping . size ( ) ;  
			
		
	
		
			
				
					                newLocationMapping [ location ]  =  id ;  
			
		
	
		
			
				
					            }  
			
		
	
		
			
				
					             
			
		
	
		
			
				
					            // As long as there are locations to explore, do so.
  
			
		
	
		
			
				
					            while  ( ! locationsToExplore . empty ( ) )  {  
			
		
	
		
			
				
					                std : : vector < uint64_t >  currentLocations  =  std : : move ( locationsToExplore . back ( ) ) ;  
			
		
	
		
			
				
					                locationsToExplore . pop_back ( ) ;  
			
		
	
		
			
				
					                 
			
		
	
		
			
				
					                for  ( auto  const &  metaEdge  :  conditionalMetaEdges )  {  
			
		
	
		
			
				
					                    bool  isApplicable  =  true ;  
			
		
	
		
			
				
					                    for  ( uint64_t  i  =  0 ;  i  <  metaEdge . components . size ( ) ;  + + i )  {  
			
		
	
		
			
				
					                        if  ( currentLocations [ metaEdge . components [ i ] ]  ! =  metaEdge . condition [ i ] )  {  
			
		
	
		
			
				
					                            isApplicable  =  false ;  
			
		
	
		
			
				
					                            break ;  
			
		
	
		
			
				
					                        }  
			
		
	
		
			
				
					                    }  
			
		
	
		
			
				
					                     
			
		
	
		
			
				
					                    if  ( isApplicable )  {  
			
		
	
		
			
				
					                        std : : vector < uint64_t >  newLocations ;  
			
		
	
		
			
				
					                         
			
		
	
		
			
				
					                        for  ( auto  const &  effect  :  metaEdge . effects )  {  
			
		
	
		
			
				
					                            std : : vector < uint64_t >  targetLocationCombination  =  currentLocations ;  
			
		
	
		
			
				
					                            for  ( uint64_t  i  =  0 ;  i  <  metaEdge . components . size ( ) ;  + + i )  {  
			
		
	
		
			
				
					                                targetLocationCombination [ metaEdge . components [ i ] ]  =  effect [ i ] ;  
			
		
	
		
			
				
					                            }  
			
		
	
		
			
				
					                             
			
		
	
		
			
				
					                            // Check whether the target combination is new.
  
			
		
	
		
			
				
					                            auto  it  =  newLocationMapping . find ( targetLocationCombination ) ;  
			
		
	
		
			
				
					                            if  ( it  ! =  newLocationMapping . end ( ) )  {  
			
		
	
		
			
				
					                                newLocations . emplace_back ( it - > second ) ;  
			
		
	
		
			
				
					                            }  else  {  
			
		
	
		
			
				
					                                uint64_t  id  =  newLocationMapping . size ( ) ;  
			
		
	
		
			
				
					                                newLocationMapping [ targetLocationCombination ]  =  id ;  
			
		
	
		
			
				
					                                locationsToExplore . emplace_back ( std : : move ( targetLocationCombination ) ) ;  
			
		
	
		
			
				
					                                newLocations . emplace_back ( id ) ;  
			
		
	
		
			
				
					                            }  
			
		
	
		
			
				
					                        }  
			
		
	
		
			
				
					                         
			
		
	
		
			
				
					                        newAutomaton . addEdge ( Edge ( newLocationMapping . at ( currentLocations ) ,  metaEdge . actionIndex ,  metaEdge . rate ,  metaEdge . templateEdge ,  newLocations ,  metaEdge . probabilities ) ) ;  
			
		
	
		
			
				
					                    }  
			
		
	
		
			
				
					                }  
			
		
	
		
			
				
					            }  
			
		
	
		
			
				
					             
			
		
	
		
			
				
					            return  newLocationMapping ;  
			
		
	
		
			
				
					        }  
			
		
	
		
			
				
					         
			
		
	
		
			
				
					        Model  Model : : flattenComposition ( std : : shared_ptr < storm : : utility : : solver : : SmtSolverFactory >  const &  smtSolverFactory )  const  {  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -107,6 +200,7 @@ namespace storm { 
			
		
	
		
			
				
					            STORM_LOG_THROW ( this - > getModelType ( )  = =  ModelType : : DTMC  | |  this - > getModelType ( )  = =  ModelType : : MDP ,  storm : : exceptions : : InvalidTypeException ,  " Unable to flatten modules for model of type ' "  < <  this - > getModelType ( )  < <  " '. " ) ;  
			
		
	
		
			
				
					             
			
		
	
		
			
				
					            // Otherwise, we need to actually flatten composition.
  
			
		
	
		
			
				
					            Model  flattenedModel ( this - > getName ( )  +  " _flattened " ,  this - > getModelType ( ) ,  this - > getJaniVersion ( ) ,  this - > getManager ( ) . shared_from_this ( ) ) ;  
			
		
	
		
			
				
					
 
			
		
	
		
			
				
					            // Get an SMT solver for computing possible guard combinations.
  
			
		
	
		
			
				
					            std : : unique_ptr < storm : : solver : : SmtSolver >  solver  =  smtSolverFactory - > create ( * expressionManager ) ;  
			
		
	
	
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
				
				@ -168,7 +262,7 @@ namespace storm { 
			
		
	
		
			
				
					                }  
			
		
	
		
			
				
					                 
			
		
	
		
			
				
					                // Create all conditional template edges corresponding to this synchronization vector.
  
			
		
	
		
			
				
					                std : : vector < ConditionalMetaEdge >  newConditionalMetaEdges  =  createSynchronizingMetaEdges ( * this ,  newAutomaton ,  synchronizingActionIndices ,  vector ,  composedAutomata ,  * solver ) ;  
			
		
	
		
			
				
					                std : : vector < ConditionalMetaEdge >  newConditionalMetaEdges  =  createSynchronizingMetaEdges ( * this ,  flattenedModel ,  synchronizingActionIndices ,  vector ,  composedAutomata ,  * solver ) ;  
			
		
	
		
			
				
					                conditionalMetaEdges . insert ( conditionalMetaEdges . end ( ) ,  newConditionalMetaEdges . begin ( ) ,  newConditionalMetaEdges . end ( ) ) ;  
			
		
	
		
			
				
					            }  
			
		
	
		
			
				
					             
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -177,15 +271,28 @@ namespace storm { 
			
		
	
		
			
				
					                Automaton  const &  automaton  =  composedAutomata [ i ] . get ( ) ;  
			
		
	
		
			
				
					                for  ( auto  const &  edge  :  automaton . getEdges ( ) )  {  
			
		
	
		
			
				
					                    if  ( synchronizingActionIndices [ i ] . find ( edge . getActionIndex ( ) )  = =  synchronizingActionIndices [ i ] . end ( ) )  {  
			
		
	
		
			
				
					                        uint64_t  actionIndex  =  edge . getActionIndex ( ) ;  
			
		
	
		
			
				
					                        if  ( actionIndex  ! =  SILENT_ACTION_INDEX )  {  
			
		
	
		
			
				
					                            std : : string  actionName  =  this - > getActionIndexToNameMap ( ) . at ( edge . getActionIndex ( ) ) ;  
			
		
	
		
			
				
					                            if  ( flattenedModel . hasAction ( actionName ) )  {  
			
		
	
		
			
				
					                                actionIndex  =  flattenedModel . getActionIndex ( actionName ) ;  
			
		
	
		
			
				
					                            }  else  {  
			
		
	
		
			
				
					                                actionIndex  =  flattenedModel . addAction ( actionName ) ;  
			
		
	
		
			
				
					                            }  
			
		
	
		
			
				
					                        }  
			
		
	
		
			
				
					                         
			
		
	
		
			
				
					                        std : : shared_ptr < TemplateEdge >  templateEdge  =  newAutomaton . createTemplateEdge ( edge . getGuard ( ) ) ;  
			
		
	
		
			
				
					                        conditionalMetaEdges . emplace_back ( ) ;  
			
		
	
		
			
				
					                        ConditionalMetaEdge &  conditionalMetaEdge  =  conditionalMetaEdges . back ( ) ;  
			
		
	
		
			
				
					                         
			
		
	
		
			
				
					                        conditionalMetaEdge . actionIndex  =  edge . getActionIndex ( ) ;  
			
		
	
		
			
				
					                        conditionalMetaEdge . condition . emplace_back ( static_cast < uint64_t > ( i ) ,  edge . getSourceLocationIndex ( ) ) ;  
			
		
	
		
			
				
					                        conditionalMetaEdge . components . emplace_back ( static_cast < uint64_t > ( i ) ) ;  
			
		
	
		
			
				
					                        conditionalMetaEdge . condition . emplace_back ( edge . getSourceLocationIndex ( ) ) ;  
			
		
	
		
			
				
					                        conditionalMetaEdge . rate  =  edge . getOptionalRate ( ) ;  
			
		
	
		
			
				
					                        for  ( auto  const &  destination  :  edge . getDestinations ( ) )  {  
			
		
	
		
			
				
					                            conditionalMetaEdge . effects . emplace_back ( i ,  destination . getLocationIndex ( ) ) ;  
			
		
	
		
			
				
					                            conditionalMetaEdge . effects . emplace_back ( ) ;  
			
		
	
		
			
				
					                             
			
		
	
		
			
				
					                            conditionalMetaEdge . effects . back ( ) . emplace_back ( destination . getLocationIndex ( ) ) ;  
			
		
	
		
			
				
					                            conditionalMetaEdge . probabilities . emplace_back ( destination . getProbability ( ) ) ;  
			
		
	
		
			
				
					                        }  
			
		
	
		
			
				
					                        conditionalMetaEdge . templateEdge  =  templateEdge ;  
			
		
	
	
		
			
				
					
						
						
						
							
								 
						
					 
				
				@ -193,9 +300,26 @@ namespace storm { 
			
		
	
		
			
				
					                }  
			
		
	
		
			
				
					            }  
			
		
	
		
			
				
					             
			
		
	
		
			
				
					            addEdgesToReachableLocations ( * this ,  composedAutomata ,  newAutomaton ,  conditionalMetaEdges ) ;  
			
		
	
		
			
				
					            std : : unordered_map < std : : vector < uint64_t > ,  uint64_t ,  storm : : utility : : vector : : VectorHash < uint64_t > >  newLocationMapping  =  addEdgesToReachableLocations ( * this ,  composedAutomata ,  newAutomaton ,  conditionalMetaEdges ) ;  
			
		
	
		
			
				
					             
			
		
	
		
			
				
					            for  ( auto  const &  newLocation  :  newLocationMapping )  {  
			
		
	
		
			
				
					                std : : stringstream  locationNameBuilder ;  
			
		
	
		
			
				
					                for  ( uint64_t  i  =  0 ;  i  <  newLocation . first . size ( ) ;  + + i )  {  
			
		
	
		
			
				
					                    locationNameBuilder  < <  composedAutomata [ i ] . get ( ) . getLocation ( newLocation . first [ i ] ) . getName ( )  < <  " _ " ;  
			
		
	
		
			
				
					                }  
			
		
	
		
			
				
					                 
			
		
	
		
			
				
					                uint64_t  locationIndex  =  newAutomaton . addLocation ( Location ( locationNameBuilder . str ( ) ) ) ;  
			
		
	
		
			
				
					                Location &  location  =  newAutomaton . getLocation ( locationIndex ) ;  
			
		
	
		
			
				
					                for  ( uint64_t  i  =  0 ;  i  <  newLocation . first . size ( ) ;  + + i )  {  
			
		
	
		
			
				
					                    for  ( auto  const &  assignment  :  composedAutomata [ i ] . get ( ) . getLocation ( newLocation . first [ i ] ) . getAssignments ( ) )  {  
			
		
	
		
			
				
					                        location . addTransientAssignment ( assignment ) ;  
			
		
	
		
			
				
					                    }  
			
		
	
		
			
				
					                }  
			
		
	
		
			
				
					            }  
			
		
	
		
			
				
					             
			
		
	
		
			
				
					            flattenedModel . addAutomaton ( newAutomaton ) ;  
			
		
	
		
			
				
					             
			
		
	
		
			
				
					            return  flattenedModel ;  
			
		
	
		
			
				
					        }  
			
		
	
		
			
				
					         
			
		
	
		
			
				
					        uint64_t  Model : : addAction ( Action  const &  action )  {