@ -34,12 +34,9 @@ namespace storm {
template < typename ValueType , typename StateType >
JaniNextStateGenerator < ValueType , StateType > : : JaniNextStateGenerator ( storm : : jani : : Model const & model , NextStateGeneratorOptions const & options , bool ) : NextStateGenerator < ValueType , StateType > ( model . getExpressionManager ( ) , options ) , model ( model ) , rewardVariables ( ) , hasStateActionRewards ( false ) {
STORM_LOG_THROW ( model . hasStandardComposition ( ) , storm : : exceptions : : WrongFormatException , " The explicit next-state generator currently does not support custom system compositions. " ) ;
STORM_LOG_THROW ( ! model . hasNonGlobalTransientVariable ( ) , storm : : exceptions : : InvalidSettingsException , " The explicit next-state generator currently does not support automata-local transient variables. " ) ;
STORM_LOG_THROW ( ! model . usesAssignmentLevels ( ) , storm : : exceptions : : InvalidSettingsException , " The explicit next-state generator currently does not support assignment levels. " ) ;
STORM_LOG_THROW ( ! this - > options . isBuildChoiceLabelsSet ( ) , storm : : exceptions : : InvalidSettingsException , " JANI next-state generator cannot generate choice labels. " ) ;
STORM_LOG_THROW ( ! model . reusesActionsInComposition ( ) , storm : : exceptions : : InvalidArgumentException , " The jit JANI model builder currently does not support reusing actions in parallel composition " ) ;
// Lift the transient edge destinations. We can do so, as we know that there are no assignment levels (because that's not supported anyway).
if ( this - > model . hasTransientEdgeDestinationAssignments ( ) ) {
@ -47,9 +44,12 @@ namespace storm {
}
STORM_LOG_THROW ( ! this - > model . hasTransientEdgeDestinationAssignments ( ) , storm : : exceptions : : InvalidSettingsException , " The explicit next-state generator currently does not support transient edge destination assignments. " ) ;
// Only after checking validity of the program, we initialize the variable information.
// Create all synchronization-related information, e.g. the automata that are put in parallel.
this - > createSynchronizationInformation ( ) ;
// Now we are ready to initialize the variable information.
this - > checkValid ( ) ;
this - > variableInformation = VariableInformation ( model ) ;
this - > variableInformation = VariableInformation ( model , this - > parallelAutomata ) ;
// Create a proper evalator.
this - > evaluator = std : : make_unique < storm : : expressions : : ExpressionEvaluator < ValueType > > ( model . getManager ( ) ) ;
@ -92,11 +92,6 @@ namespace storm {
// If there are terminal states we need to handle, we now need to translate all labels to expressions.
if ( this - > options . hasTerminalStates ( ) ) {
std : : vector < std : : reference_wrapper < storm : : jani : : Automaton const > > composedAutomata ;
for ( auto const & automaton : this - > model . getAutomata ( ) ) {
composedAutomata . emplace_back ( automaton ) ;
}
for ( auto const & expressionOrLabelAndBool : this - > options . getTerminalStates ( ) ) {
if ( expressionOrLabelAndBool . first . isExpression ( ) ) {
this - > terminalStates . push_back ( std : : make_pair ( expressionOrLabelAndBool . first . getExpression ( ) , expressionOrLabelAndBool . second ) ) ;
@ -110,7 +105,7 @@ namespace storm {
STORM_LOG_THROW ( variable . isBooleanVariable ( ) , storm : : exceptions : : InvalidSettingsException , " Terminal states refer to non-boolean variable ' " < < expressionOrLabelAndBool . first . getLabel ( ) < < " '. " ) ;
STORM_LOG_THROW ( variable . isTransient ( ) , storm : : exceptions : : InvalidSettingsException , " Terminal states refer to non-transient variable ' " < < expressionOrLabelAndBool . first . getLabel ( ) < < " '. " ) ;
this - > terminalStates . push_back ( std : : make_pair ( this - > model . getLabelExpression ( variable . asBooleanVariable ( ) , composed Automata) , expressionOrLabelAndBool . second ) ) ;
this - > terminalStates . push_back ( std : : make_pair ( this - > model . getLabelExpression ( variable . asBooleanVariable ( ) , this - > parallel Automata) , expressionOrLabelAndBool . second ) ) ;
}
}
}
@ -177,15 +172,11 @@ namespace storm {
storm : : utility : : solver : : SmtSolverFactory factory ;
std : : unique_ptr < storm : : solver : : SmtSolver > solver = factory . create ( model . getExpressionManager ( ) ) ;
std : : vector < std : : reference_wrapper < storm : : jani : : Automaton const > > allAutomata ;
for ( auto const & automaton : model . getAutomata ( ) ) {
allAutomata . push_back ( automaton ) ;
}
std : : vector < storm : : expressions : : Expression > rangeExpressions = model . getAllRangeExpressions ( allAutomata ) ;
std : : vector < storm : : expressions : : Expression > rangeExpressions = model . getAllRangeExpressions ( this - > parallelAutomata ) ;
for ( auto const & expression : rangeExpressions ) {
solver - > add ( expression ) ;
}
solver - > add ( model . getInitialStatesExpression ( al lAutomata) ) ;
solver - > add ( model . getInitialStatesExpression ( this - > parallelAutomata ) ) ;
// Proceed as long as the solver can still enumerate initial states.
std : : vector < StateType > initialStateIndices ;
@ -213,9 +204,10 @@ namespace storm {
// Gather iterators to the initial locations of all the automata.
std : : vector < std : : set < uint64_t > : : const_iterator > initialLocationsIts ;
std : : vector < std : : set < uint64_t > : : const_iterator > initialLocationsItes ;
for ( auto const & automaton : allAutomata ) {
initialLocationsIts . push_back ( automaton . get ( ) . getInitialLocationIndices ( ) . cbegin ( ) ) ;
initialLocationsItes . push_back ( automaton . get ( ) . getInitialLocationIndices ( ) . cend ( ) ) ;
for ( auto const & automatonRef : this - > parallelAutomata ) {
auto const & automaton = automatonRef . get ( ) ;
initialLocationsIts . push_back ( automaton . getInitialLocationIndices ( ) . cbegin ( ) ) ;
initialLocationsItes . push_back ( automaton . getInitialLocationIndices ( ) . cend ( ) ) ;
}
storm : : utility : : combinatorics : : forEach ( initialLocationsIts , initialLocationsItes , [ this , & initialState ] ( uint64_t index , uint64_t value ) { setLocation ( initialState , this - > variableInformation . locationVariables [ index ] , value ) ; } , [ & stateToIdCallback , & initialStateIndices , & initialState ] ( ) {
// Register initial state.
@ -287,7 +279,8 @@ namespace storm {
// need the state rewards then.
std : : vector < ValueType > stateRewards ( this - > rewardVariables . size ( ) , storm : : utility : : zero < ValueType > ( ) ) ;
uint64_t automatonIndex = 0 ;
for ( auto const & automaton : model . getAutomata ( ) ) {
for ( auto const & automatonRef : this - > parallelAutomata ) {
auto const & automaton = automatonRef . get ( ) ;
uint64_t currentLocationIndex = locations [ automatonIndex ] ;
storm : : jani : : Location const & location = automaton . getLocation ( currentLocationIndex ) ;
auto valueIt = stateRewards . begin ( ) ;
@ -307,12 +300,7 @@ namespace storm {
// Get all choices for the state.
result . setExpanded ( ) ;
std : : vector < Choice < ValueType > > allChoices = getSilentActionChoices ( locations , * this - > state , stateToIdCallback ) ;
std : : vector < Choice < ValueType > > allLabeledChoices = getNonsilentActionChoices ( locations , * this - > state , stateToIdCallback ) ;
for ( auto & choice : allLabeledChoices ) {
allChoices . push_back ( std : : move ( choice ) ) ;
}
std : : vector < Choice < ValueType > > allChoices = getActionChoices ( locations , * this - > state , stateToIdCallback ) ;
std : : size_t totalNumberOfChoices = allChoices . size ( ) ;
// If there is not a single choice, we return immediately, because the state has no behavior (other than
@ -372,35 +360,14 @@ namespace storm {
}
template < typename ValueType , typename StateType >
std : : vector < Choice < ValueType > > JaniNextStateGenerator < ValueType , StateType > : : getSilentActionChoices ( std : : vector < uint64_t > const & locations , CompressedState const & state , StateToIdCallback stateToIdCallback ) {
std : : vector < Choice < ValueType > > result ;
// Iterate over all automata.
uint64_t automatonIndex = 0 ;
for ( auto const & automaton : model . getAutomata ( ) ) {
uint64_t location = locations [ automatonIndex ] ;
// Iterate over all edges from the source location.
for ( auto const & edge : automaton . getEdgesFromLocation ( location ) ) {
// Skip the edge if it is labeled with a non-silent action.
if ( edge . getActionIndex ( ) ! = storm : : jani : : Model : : SILENT_ACTION_INDEX ) {
continue ;
}
// Skip the command, if it is not enabled.
if ( ! this - > evaluator - > asBool ( edge . getGuard ( ) ) ) {
continue ;
}
Choice < ValueType > JaniNextStateGenerator < ValueType , StateType > : : expandNonSynchronizingEdge ( storm : : jani : : Edge const & edge , uint64_t outputActionIndex , uint64_t automatonIndex , CompressedState const & state , StateToIdCallback stateToIdCallback ) {
// Determine the exit rate if it's a Markovian edge.
boost : : optional < ValueType > exitRate = boost : : none ;
if ( edge . hasRate ( ) ) {
exitRate = this - > evaluator - > asRational ( edge . getRate ( ) ) ;
}
result . push_back ( Choice < ValueType > ( edge . getActionIndex ( ) , static_cast < bool > ( exitRate ) ) ) ;
Choice < ValueType > & choice = result . back ( ) ;
Choice < ValueType > choice ( edge . getActionIndex ( ) , static_cast < bool > ( exitRate ) ) ;
// Iterate over all updates of the current command.
ValueType probabilitySum = storm : : utility : : zero < ValueType > ( ) ;
@ -410,6 +377,8 @@ namespace storm {
if ( probability ! = storm : : utility : : zero < ValueType > ( ) ) {
// Obtain target state index and add it to the list of known states. If it has not yet been
// seen, we also add it to the set of states that have yet to be explored.
auto newState = applyUpdate ( state , destination , this - > variableInformation . locationVariables [ automatonIndex ] ) ;
StateType stateIndex = stateToIdCallback ( applyUpdate ( state , destination , this - > variableInformation . locationVariables [ automatonIndex ] ) ) ;
// Update the choice by adding the probability/target state to it.
@ -429,33 +398,24 @@ namespace storm {
// Check that the resulting distribution is in fact a distribution.
STORM_LOG_THROW ( ! this - > isDiscreteTimeModel ( ) | | this - > comparator . isOne ( probabilitySum ) , storm : : exceptions : : WrongFormatException , " Probabilities do not sum to one for edge (actually sum to " < < probabilitySum < < " ). " ) ;
}
}
+ + automatonIndex ;
}
return result ;
return choice ;
}
template < typename ValueType , typename StateType >
std : : vector < Choice < ValueType > > JaniNextStateGenerator < ValueType , StateType > : : getNonsilentActionChoices ( std : : vector < uint64_t > const & locations , CompressedState const & state , StateToIdCallback stateToIdCallback ) {
std : : vector < Choice < ValueType > > JaniNextStateGenerator < ValueType , StateType > : : expandSynchronizingEdgeCombination ( AutomataEdgeSets const & edgeCombination , uint64_t outputActionIndex , CompressedState const & state , StateToIdCallback stateToIdCallback ) {
std : : vector < Choice < ValueType > > result ;
for ( uint64_t actionIndex : model . getNonsilentActionIndices ( ) ) {
std : : vector < std : : vector < storm : : jani : : Edge const * > > enabledEdges = getEnabledEdges ( locations , actionIndex ) ;
// Only process this action, if there is at least one feasible solution.
if ( ! enabledEdges . empty ( ) ) {
if ( this - > options . isExplorationChecksSet ( ) ) {
// Check whether a global variable is written multiple times in any combination.
checkGlobalVariableWritesValid ( enabledEdges ) ;
checkGlobalVariableWritesValid ( edgeCombination ) ;
}
std : : vector < std : : vector < storm : : jani : : Edge const * > : : const_iterator > iteratorList ( enabledEdges . size ( ) ) ;
std : : vector < EdgeSet : : const_iterator > iteratorList ( edgeCombination . size ( ) ) ;
// Initialize the list of iterators.
for ( size_t i = 0 ; i < enabledEdges . size ( ) ; + + i ) {
iteratorList [ i ] = enabledEdges [ i ] . cbegin ( ) ;
for ( size_t i = 0 ; i < edgeCombination . size ( ) ; + + i ) {
iteratorList [ i ] = edgeCombination [ i ] . second . cbegin ( ) ;
}
// As long as there is one feasible combination of commands, keep on expanding it.
@ -467,14 +427,13 @@ namespace storm {
currentTargetStates - > emplace ( state , storm : : utility : : one < ValueType > ( ) ) ;
auto locationVariableIt = this - > variableInformation . locationVariables . cbegin ( ) ;
for ( uint_fast64_t i = 0 ; i < iteratorList . size ( ) ; + + i ) {
storm : : jani : : Edge const & edge = * * iteratorList [ i ] ;
for ( auto const & destination : edge . getDestinations ( ) ) {
for ( auto const & stateProbabilityPair : * currentTargetStates ) {
// Compute the new state under the current update and add it to the set of new target states.
CompressedState newTargetState = applyUpdate ( stateProbabilityPair . first , destination , * locationVariableIt ) ;
CompressedState newTargetState = applyUpdate ( stateProbabilityPair . first , destination , this - > variableInformation . locationVariables [ edgeCombination [ i ] . first ] ) ;
// If the new state was already found as a successor state, update the probability
// and otherwise insert it.
@ -503,14 +462,12 @@ namespace storm {
currentTargetStates = newTargetStates ;
newTargetStates = new boost : : container : : flat_map < CompressedState , ValueType > ( ) ;
}
+ + locationVariableIt ;
}
// At this point, we applied all commands of the current command combination and newTargetStates
// contains all target states and their respective probabilities. That means we are now ready to
// add the choice to the list of transitions.
result . push_back ( Choice < ValueType > ( actionIndex ) ) ;
result . emplace_back ( outputActionIndex ) ;
// Now create the actual distribution.
Choice < ValueType > & choice = result . back ( ) ;
@ -542,67 +499,94 @@ namespace storm {
bool movedIterator = false ;
for ( uint64_t j = 0 ; ! movedIterator & & j < iteratorList . size ( ) ; + + j ) {
+ + iteratorList [ j ] ;
if ( iteratorList [ j ] ! = enabledEdges [ j ] . end ( ) ) {
if ( iteratorList [ j ] ! = edgeCombination [ j ] . second . end ( ) ) {
movedIterator = true ;
} else {
// Reset the iterator to the beginning of the list.
iteratorList [ j ] = enabledEdges [ j ] . begin ( ) ;
iteratorList [ j ] = edgeCombination [ j ] . second . begin ( ) ;
}
}
done = ! movedIterator ;
}
}
}
return result ;
}
template < typename ValueType , typename StateType >
std : : vector < std : : vector < storm : : jani : : Edge const * > > JaniNextStateGenerator < ValueType , StateType > : : getEnabledEdges ( std : : vector < uint64_t > const & locationIndices , uint64_t actionIndex ) {
std : : vector < std : : vector < storm : : jani : : Edge const * > > result ;
std : : vector < Choice < ValueType > > JaniNextStateGenerator < ValueType , StateType > : : getActionChoices ( std : : vector < uint64_t > const & locations , CompressedState const & state , StateToIdCallback stateToIdCallback ) {
std : : vector < Choice < ValueType > > result ;
// Iterate over all automata.
uint64_t automatonIndex = 0 ;
for ( auto const & automaton : model . getAutomata ( ) ) {
// If the automaton has no edge labeled with the given action, we can skip it.
if ( ! automaton . hasEdgeLabeledWithActionIndex ( actionIndex ) ) {
for ( auto const & outputAndEdges : edges ) {
auto const & edges = outputAndEdges . second ;
if ( edges . size ( ) = = 1 ) {
// If the synch consists of just one element, it's non-synchronizing.
auto const & nonsychingEdges = edges . front ( ) ;
uint64_t automatonIndex = nonsychingEdges . first ;
auto edgesIt = nonsychingEdges . second . find ( locations [ automatonIndex ] ) ;
if ( edgesIt ! = nonsychingEdges . second . end ( ) ) {
for ( auto const & edge : edgesIt - > second ) {
if ( ! this - > evaluator - > asBool ( edge - > getGuard ( ) ) ) {
continue ;
}
auto edges = automaton . getEdgesFromLocation ( locationIndices [ automatonIndex ] , actionIndex ) ;
// If the automaton contains the action, but there is no edge available labeled with
// this action, we don't have any feasible command combinations.
if ( edges . empty ( ) ) {
return std : : vector < std : : vector < storm : : jani : : Edge const * > > ( ) ;
Choice < ValueType > choice = expandNonSynchronizingEdge ( * edge , outputAndEdges . first ? outputAndEdges . first . get ( ) : edge - > getActionIndex ( ) , automatonIndex , state , stateToIdCallback ) ;
result . emplace_back ( std : : move ( choice ) ) ;
}
}
} else {
// If the element has more than one set of edges, we need to perform a synchronization.
STORM_LOG_ASSERT ( outputAndEdges . first , " Need output action index for synchronization. " ) ;
AutomataEdgeSets automataEdgeSets ;
uint64_t outputActionIndex = outputAndEdges . first . get ( ) ;
bool productiveCombination = true ;
for ( auto const & automatonAndEdges : outputAndEdges . second ) {
uint64_t automatonIndex = automatonAndEdges . first ;
EdgeSet enabledEdgesOfAutomaton ;
bool atLeastOneEdge = false ;
auto edgesIt = automatonAndEdges . second . find ( locations [ automatonIndex ] ) ;
if ( edgesIt ! = automatonAndEdges . second . end ( ) ) {
for ( auto const & edge : edgesIt - > second ) {
if ( ! this - > evaluator - > asBool ( edge - > getGuard ( ) ) ) {
continue ;
}
std : : vector < storm : : jani : : Edge const * > edgePointers ;
for ( auto const & edge : edges ) {
if ( this - > evaluator - > asBool ( edge . getGuard ( ) ) ) {
edgePointers . push_back ( & edge ) ;
atLeastOneEdge = true ;
enabledEdgesOfAutomaton . emplace_back ( edge ) ;
}
}
// If there was no enabled edge although the automaton has some edge with the required action, we must
// not return anything.
if ( edgePointers . empty ( ) ) {
return std : : vector < std : : vector < storm : : jani : : Edge const * > > ( ) ;
// If there is no enabled edge of this automaton, the whole combination is not productive.
if ( ! atLeastOneEdge ) {
productiveCombination = false ;
break ;
}
result . emplace_back ( std : : move ( edgePointers ) ) ;
+ + automatonIndex ;
automataEdgeSets . emplace_back ( std : : make_pair ( automatonIndex , std : : move ( enabledEdgesOfAutomaton ) ) ) ;
}
if ( productiveCombination ) {
std : : vector < Choice < ValueType > > choices = expandSynchronizingEdgeCombination ( automataEdgeSets , outputActionIndex , state , stateToIdCallback ) ;
for ( auto const & choice : choices ) {
result . emplace_back ( std : : move ( choice ) ) ;
}
}
}
}
return result ;
}
template < typename ValueType , typename StateType >
void JaniNextStateGenerator < ValueType , StateType > : : checkGlobalVariableWritesValid ( std : : vector < std : : vector < storm : : jani : : Edge const * > > const & enabledEdges ) const {
void JaniNextStateGenerator < ValueType , StateType > : : checkGlobalVariableWritesValid ( AutomataEdgeSets const & enabledEdges ) const {
std : : map < storm : : expressions : : Variable , uint64_t > writtenGlobalVariables ;
for ( auto edgeSetIt = enabledEdges . begin ( ) , edgeSetIte = enabledEdges . end ( ) ; edgeSetIt ! = edgeSetIte ; + + edgeSetIt ) {
for ( auto const & edge : * edgeSetIt ) {
for ( auto const & edge : edgeSetIt - > second ) {
for ( auto const & globalVariable : edge - > getWrittenGlobalVariables ( ) ) {
auto it = writtenGlobalVariables . find ( globalVariable ) ;
@ -629,20 +613,13 @@ namespace storm {
template < typename ValueType , typename StateType >
storm : : models : : sparse : : StateLabeling JaniNextStateGenerator < ValueType , StateType > : : label ( storm : : storage : : BitVectorHashMap < StateType > const & states , std : : vector < StateType > const & initialStateIndices , std : : vector < StateType > const & deadlockStateIndices ) {
// Prepare a mapping from automata names to the location variables.
std : : vector < std : : reference_wrapper < storm : : jani : : Automaton const > > composedAutomata ;
for ( auto const & automaton : model . getAutomata ( ) ) {
composedAutomata . emplace_back ( automaton ) ;
}
// As in JANI we can use transient boolean variable assignments in locations to identify states, we need to
// create a list of boolean transient variables and the expressions that define them.
std : : unordered_map < storm : : expressions : : Variable , storm : : expressions : : Expression > transientVariableToExpressionMap ;
for ( auto const & variable : model . getGlobalVariables ( ) . getTransientVariables ( ) ) {
if ( variable . isBooleanVariable ( ) ) {
if ( this - > options . isBuildAllLabelsSet ( ) | | this - > options . getLabelNames ( ) . find ( variable . getName ( ) ) ! = this - > options . getLabelNames ( ) . end ( ) ) {
transientVariableToExpressionMap [ variable . getExpressionVariable ( ) ] = model . getLabelExpression ( variable . asBooleanVariable ( ) , composed Automata) ;
transientVariableToExpressionMap [ variable . getExpressionVariable ( ) ] = model . getLabelExpression ( variable . asBooleanVariable ( ) , this - > parallelAutomata ) ;
}
}
}
@ -691,7 +668,8 @@ namespace storm {
}
// Then fill them.
for ( auto const & automaton : model . getAutomata ( ) ) {
for ( auto const & automatonRef : this - > parallelAutomata ) {
auto const & automaton = automatonRef . get ( ) ;
for ( auto const & location : automaton . getLocations ( ) ) {
auto rewardVariableIt = rewardVariables . begin ( ) ;
auto rewardVariableIte = rewardVariables . end ( ) ;
@ -731,6 +709,81 @@ namespace storm {
}
}
template < typename ValueType , typename StateType >
void JaniNextStateGenerator < ValueType , StateType > : : createSynchronizationInformation ( ) {
// Create synchronizing edges information.
storm : : jani : : Composition const & topLevelComposition = this - > model . getSystemComposition ( ) ;
if ( topLevelComposition . isAutomatonComposition ( ) ) {
auto const & automaton = this - > model . getAutomaton ( topLevelComposition . asAutomatonComposition ( ) . getAutomatonName ( ) ) ;
this - > parallelAutomata . push_back ( automaton ) ;
LocationsAndEdges locationsAndEdges ;
for ( auto const & edge : automaton . getEdges ( ) ) {
locationsAndEdges [ edge . getSourceLocationIndex ( ) ] . emplace_back ( & edge ) ;
}
AutomataAndEdges automataAndEdges ;
automataAndEdges . emplace_back ( std : : make_pair ( 0 , std : : move ( locationsAndEdges ) ) ) ;
this - > edges . emplace_back ( std : : make_pair ( boost : : none , std : : move ( automataAndEdges ) ) ) ;
} else {
STORM_LOG_THROW ( topLevelComposition . isParallelComposition ( ) , storm : : exceptions : : WrongFormatException , " Expected parallel composition. " ) ;
storm : : jani : : ParallelComposition const & parallelComposition = topLevelComposition . asParallelComposition ( ) ;
uint64_t automatonIndex = 0 ;
for ( auto const & composition : parallelComposition . getSubcompositions ( ) ) {
STORM_LOG_THROW ( composition - > isAutomatonComposition ( ) , storm : : exceptions : : WrongFormatException , " Expected flat parallel composition. " ) ;
this - > parallelAutomata . push_back ( this - > model . getAutomaton ( composition - > asAutomatonComposition ( ) . getAutomatonName ( ) ) ) ;
// Add edges with silent action.
LocationsAndEdges locationsAndEdges ;
for ( auto const & edge : parallelAutomata . back ( ) . get ( ) . getEdges ( ) ) {
if ( edge . getActionIndex ( ) = = storm : : jani : : Model : : SILENT_ACTION_INDEX ) {
locationsAndEdges [ edge . getSourceLocationIndex ( ) ] . emplace_back ( & edge ) ;
}
}
if ( ! locationsAndEdges . empty ( ) ) {
AutomataAndEdges automataAndEdges ;
automataAndEdges . emplace_back ( std : : make_pair ( automatonIndex , std : : move ( locationsAndEdges ) ) ) ;
this - > edges . emplace_back ( std : : make_pair ( boost : : none , std : : move ( automataAndEdges ) ) ) ;
}
+ + automatonIndex ;
}
for ( auto const & vector : parallelComposition . getSynchronizationVectors ( ) ) {
uint64_t outputActionIndex = this - > model . getActionIndex ( vector . getOutput ( ) ) ;
AutomataAndEdges automataAndEdges ;
bool atLeastOneEdge = true ;
uint64_t automatonIndex = 0 ;
for ( auto const & element : vector . getInput ( ) ) {
if ( ! storm : : jani : : SynchronizationVector : : isNoActionInput ( element ) ) {
LocationsAndEdges locationsAndEdges ;
uint64_t actionIndex = this - > model . getActionIndex ( element ) ;
for ( auto const & edge : parallelAutomata [ automatonIndex ] . get ( ) . getEdges ( ) ) {
if ( edge . getActionIndex ( ) = = actionIndex ) {
locationsAndEdges [ edge . getSourceLocationIndex ( ) ] . emplace_back ( & edge ) ;
}
}
if ( locationsAndEdges . empty ( ) ) {
atLeastOneEdge = false ;
break ;
}
automataAndEdges . emplace_back ( std : : make_pair ( automatonIndex , std : : move ( locationsAndEdges ) ) ) ;
}
+ + automatonIndex ;
}
if ( atLeastOneEdge ) {
this - > edges . emplace_back ( std : : make_pair ( outputActionIndex , std : : move ( automataAndEdges ) ) ) ;
}
}
}
STORM_LOG_TRACE ( " Number of synchronizations: " < < this - > edges . size ( ) < < " . " ) ;
}
template < typename ValueType , typename StateType >
void JaniNextStateGenerator < ValueType , StateType > : : checkValid ( ) const {
// If the program still contains undefined constants and we are not in a parametric setting, assemble an appropriate error message.
xxxxxxxxxx