|  |  | @ -55,18 +55,44 @@ namespace storm { | 
			
		
	
		
			
				
					|  |  |  |             return name; | 
			
		
	
		
			
				
					|  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |          | 
			
		
	
		
			
				
					|  |  |  |         void Model::flattenSynchronizationVector(Automaton& newAutomaton, std::unordered_map<std::vector<uint64_t>, uint64_t, storm::utility::vector::VectorHash<uint64_t>>& newLocations, std::unordered_map<std::string, uint64_t>& newActionToIndex, std::vector<std::set<uint64_t>>& synchronizingActionIndices, SynchronizationVector const& vector, std::vector<std::reference_wrapper<Automaton const>> const& composedAutomata, storm::solver::SmtSolver& solver) const { | 
			
		
	
		
			
				
					|  |  |  |         struct ConditionalMetaEdge { | 
			
		
	
		
			
				
					|  |  |  |             ConditionalMetaEdge() : actionIndex(0) { | 
			
		
	
		
			
				
					|  |  |  |                 // Intentionally left empty.
 | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |              | 
			
		
	
		
			
				
					|  |  |  |             uint64_t actionIndex; | 
			
		
	
		
			
				
					|  |  |  |             std::vector<std::pair<uint64_t, 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::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> result; | 
			
		
	
		
			
				
					|  |  |  |              | 
			
		
	
		
			
				
					|  |  |  |             // Gather all participating automata and the corresponding input symbols.
 | 
			
		
	
		
			
				
					|  |  |  |             std::vector<std::pair<std::reference_wrapper<Automaton const>, uint64_t>> participatingAutomataAndActions; | 
			
		
	
		
			
				
					|  |  |  |             for (uint64_t i = 0; i < composedAutomata.size(); ++i) { | 
			
		
	
		
			
				
					|  |  |  |                 std::string const& actionName = vector.getInput(i); | 
			
		
	
		
			
				
					|  |  |  |                 if (!SynchronizationVector::isNoActionInput(actionName)) { | 
			
		
	
		
			
				
					|  |  |  |                     uint64_t actionIndex = getActionIndex(actionName); | 
			
		
	
		
			
				
					|  |  |  |                     uint64_t actionIndex = model.getActionIndex(actionName); | 
			
		
	
		
			
				
					|  |  |  |                     participatingAutomataAndActions.push_back(std::make_pair(composedAutomata[i], actionIndex)); | 
			
		
	
		
			
				
					|  |  |  |                     synchronizingActionIndices[i].insert(actionIndex); | 
			
		
	
		
			
				
					|  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |              | 
			
		
	
		
			
				
					|  |  |  |             return result; | 
			
		
	
		
			
				
					|  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |          | 
			
		
	
		
			
				
					|  |  |  |         void 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; | 
			
		
	
		
			
				
					|  |  |  |             for (auto const& automaton : composedAutomata) { | 
			
		
	
		
			
				
					|  |  |  |                 // TODO: iterate over initial locations of all automata
 | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |              | 
			
		
	
		
			
				
					|  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |          | 
			
		
	
		
			
				
					|  |  |  |         Model Model::flattenComposition(std::shared_ptr<storm::utility::solver::SmtSolverFactory> const& smtSolverFactory) const { | 
			
		
	
	
		
			
				
					|  |  | @ -132,19 +158,18 @@ namespace storm { | 
			
		
	
		
			
				
					|  |  |  |                 solver->add(variable.getExpressionVariable() <= variable.getUpperBound()); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |             // Since we need to reduce a tuple of locations to a single location, we keep a hashmap for this.
 | 
			
		
	
		
			
				
					|  |  |  |             std::unordered_map<std::vector<uint64_t>, uint64_t, storm::utility::vector::VectorHash<uint64_t>> newLocations; | 
			
		
	
		
			
				
					|  |  |  |             std::unordered_map<std::string, uint64_t> newActionToIndex; | 
			
		
	
		
			
				
					|  |  |  |              | 
			
		
	
		
			
				
					|  |  |  |             // Perform all necessary synchronizations and keep track which action indices participate in synchronization.
 | 
			
		
	
		
			
				
					|  |  |  |             std::vector<std::set<uint64_t>> synchronizingActionIndices; | 
			
		
	
		
			
				
					|  |  |  |             std::vector<ConditionalMetaEdge> conditionalMetaEdges; | 
			
		
	
		
			
				
					|  |  |  |             for (auto const& vector : parallelComposition.getSynchronizationVectors()) { | 
			
		
	
		
			
				
					|  |  |  |                 // If less then 2 automata participate, there is no need to perform a synchronization.
 | 
			
		
	
		
			
				
					|  |  |  |                 if (vector.getNumberOfActionInputs() <= 1) { | 
			
		
	
		
			
				
					|  |  |  |                     continue; | 
			
		
	
		
			
				
					|  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |                  | 
			
		
	
		
			
				
					|  |  |  |                 flattenSynchronizationVector(newAutomaton, newLocations, newActionToIndex, synchronizingActionIndices, vector, composedAutomata, *solver); | 
			
		
	
		
			
				
					|  |  |  |                 // Create all conditional template edges corresponding to this synchronization vector.
 | 
			
		
	
		
			
				
					|  |  |  |                 std::vector<ConditionalMetaEdge> newConditionalMetaEdges = createSynchronizingMetaEdges(*this, newAutomaton, synchronizingActionIndices, vector, composedAutomata, *solver); | 
			
		
	
		
			
				
					|  |  |  |                 conditionalMetaEdges.insert(conditionalMetaEdges.end(), newConditionalMetaEdges.begin(), newConditionalMetaEdges.end()); | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |              | 
			
		
	
		
			
				
					|  |  |  |             // Now add all edges with action indices that were not mentioned in synchronization vectors.
 | 
			
		
	
	
		
			
				
					|  |  | @ -152,166 +177,25 @@ namespace storm { | 
			
		
	
		
			
				
					|  |  |  |                 Automaton const& automaton = composedAutomata[i].get(); | 
			
		
	
		
			
				
					|  |  |  |                 for (auto const& edge : automaton.getEdges()) { | 
			
		
	
		
			
				
					|  |  |  |                     if (synchronizingActionIndices[i].find(edge.getActionIndex()) == synchronizingActionIndices[i].end()) { | 
			
		
	
		
			
				
					|  |  |  |                         // TODO: create template edge and create all concrete edges.
 | 
			
		
	
		
			
				
					|  |  |  |                         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.rate = edge.getOptionalRate(); | 
			
		
	
		
			
				
					|  |  |  |                         for (auto const& destination : edge.getDestinations()) { | 
			
		
	
		
			
				
					|  |  |  |                             conditionalMetaEdge.effects.emplace_back(i, destination.getLocationIndex()); | 
			
		
	
		
			
				
					|  |  |  |                             conditionalMetaEdge.probabilities.emplace_back(destination.getProbability()); | 
			
		
	
		
			
				
					|  |  |  |                         } | 
			
		
	
		
			
				
					|  |  |  |                         conditionalMetaEdge.templateEdge = templateEdge; | 
			
		
	
		
			
				
					|  |  |  |                     } | 
			
		
	
		
			
				
					|  |  |  |                 } | 
			
		
	
		
			
				
					|  |  |  |             } | 
			
		
	
		
			
				
					|  |  |  |              | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |             addEdgesToReachableLocations(*this, composedAutomata, newAutomaton, conditionalMetaEdges); | 
			
		
	
		
			
				
					|  |  |  |              | 
			
		
	
		
			
				
					|  |  |  |              | 
			
		
	
		
			
				
					|  |  |  | //            
 | 
			
		
	
		
			
				
					|  |  |  | //            
 | 
			
		
	
		
			
				
					|  |  |  | //            
 | 
			
		
	
		
			
				
					|  |  |  | //            // Now go through the modules, gather the variables, construct the name of the new module and assert the
 | 
			
		
	
		
			
				
					|  |  |  | //            // bounds of the discovered variables.
 | 
			
		
	
		
			
				
					|  |  |  | //            for (auto const& module : this->getModules()) {
 | 
			
		
	
		
			
				
					|  |  |  | //                newModuleName << module.getName() << "_";
 | 
			
		
	
		
			
				
					|  |  |  | //                allBooleanVariables.insert(allBooleanVariables.end(), module.getBooleanVariables().begin(), module.getBooleanVariables().end());
 | 
			
		
	
		
			
				
					|  |  |  | //                allIntegerVariables.insert(allIntegerVariables.end(), module.getIntegerVariables().begin(), module.getIntegerVariables().end());
 | 
			
		
	
		
			
				
					|  |  |  | //                
 | 
			
		
	
		
			
				
					|  |  |  | //                // The commands without a synchronizing action name, can simply be copied (plus adjusting the global
 | 
			
		
	
		
			
				
					|  |  |  | //                // indices of the command and its updates).
 | 
			
		
	
		
			
				
					|  |  |  | //                for (auto const& command : module.getCommands()) {
 | 
			
		
	
		
			
				
					|  |  |  | //                    if (!command.isLabeled()) {
 | 
			
		
	
		
			
				
					|  |  |  | //                        std::vector<storm::prism::Update> updates;
 | 
			
		
	
		
			
				
					|  |  |  | //                        updates.reserve(command.getUpdates().size());
 | 
			
		
	
		
			
				
					|  |  |  | //                        
 | 
			
		
	
		
			
				
					|  |  |  | //                        for (auto const& update : command.getUpdates()) {
 | 
			
		
	
		
			
				
					|  |  |  | //                            updates.push_back(storm::prism::Update(nextUpdateIndex, update.getLikelihoodExpression(), update.getAssignments(), update.getFilename(), 0));
 | 
			
		
	
		
			
				
					|  |  |  | //                            ++nextUpdateIndex;
 | 
			
		
	
		
			
				
					|  |  |  | //                        }
 | 
			
		
	
		
			
				
					|  |  |  | //                        
 | 
			
		
	
		
			
				
					|  |  |  | //                        newCommands.push_back(storm::prism::Command(nextCommandIndex, command.isMarkovian(), actionToIndexMap.find("")->second, "", command.getGuardExpression(), updates, command.getFilename(), 0));
 | 
			
		
	
		
			
				
					|  |  |  | //                        ++nextCommandIndex;
 | 
			
		
	
		
			
				
					|  |  |  | //                    }
 | 
			
		
	
		
			
				
					|  |  |  | //                }
 | 
			
		
	
		
			
				
					|  |  |  | //            }
 | 
			
		
	
		
			
				
					|  |  |  | //            
 | 
			
		
	
		
			
				
					|  |  |  | //            // Save state of solver so that we can always restore the point where we have exactly the constant values
 | 
			
		
	
		
			
				
					|  |  |  | //            // and variables bounds on the assertion stack.
 | 
			
		
	
		
			
				
					|  |  |  | //            solver->push();
 | 
			
		
	
		
			
				
					|  |  |  | //            
 | 
			
		
	
		
			
				
					|  |  |  | //            // Now we need to enumerate all possible combinations of synchronizing commands. For this, we iterate over
 | 
			
		
	
		
			
				
					|  |  |  | //            // all actions and let the solver enumerate the possible combinations of commands that can be enabled together.
 | 
			
		
	
		
			
				
					|  |  |  | //            for (auto const& actionIndex : this->getSynchronizingActionIndices()) {
 | 
			
		
	
		
			
				
					|  |  |  | //                bool noCombinationsForAction = false;
 | 
			
		
	
		
			
				
					|  |  |  | //                
 | 
			
		
	
		
			
				
					|  |  |  | //                // Prepare the list that stores for each module the list of commands with the given action.
 | 
			
		
	
		
			
				
					|  |  |  | //                std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>> possibleCommands;
 | 
			
		
	
		
			
				
					|  |  |  | //                
 | 
			
		
	
		
			
				
					|  |  |  | //                for (auto const& module : this->getModules()) {
 | 
			
		
	
		
			
				
					|  |  |  | //                    // If the module has no command with this action, we can skip it.
 | 
			
		
	
		
			
				
					|  |  |  | //                    if (!module.hasActionIndex(actionIndex)) {
 | 
			
		
	
		
			
				
					|  |  |  | //                        continue;
 | 
			
		
	
		
			
				
					|  |  |  | //                    }
 | 
			
		
	
		
			
				
					|  |  |  | //                    
 | 
			
		
	
		
			
				
					|  |  |  | //                    std::set<uint_fast64_t> const& commandIndices = module.getCommandIndicesByActionIndex(actionIndex);
 | 
			
		
	
		
			
				
					|  |  |  | //                    
 | 
			
		
	
		
			
				
					|  |  |  | //                    // If there is no command even though the module has this action, there is no valid command
 | 
			
		
	
		
			
				
					|  |  |  | //                    // combination with this action.
 | 
			
		
	
		
			
				
					|  |  |  | //                    if (commandIndices.empty()) {
 | 
			
		
	
		
			
				
					|  |  |  | //                        noCombinationsForAction = true;
 | 
			
		
	
		
			
				
					|  |  |  | //                        break;
 | 
			
		
	
		
			
				
					|  |  |  | //                    }
 | 
			
		
	
		
			
				
					|  |  |  | //                    
 | 
			
		
	
		
			
				
					|  |  |  | //                    // Prepare empty list of commands for this module.
 | 
			
		
	
		
			
				
					|  |  |  | //                    possibleCommands.push_back(std::vector<std::reference_wrapper<storm::prism::Command const>>());
 | 
			
		
	
		
			
				
					|  |  |  | //                    
 | 
			
		
	
		
			
				
					|  |  |  | //                    // Add references to the commands labeled with the current action.
 | 
			
		
	
		
			
				
					|  |  |  | //                    for (auto const& commandIndex : commandIndices) {
 | 
			
		
	
		
			
				
					|  |  |  | //                        possibleCommands.back().push_back(module.getCommand(commandIndex));
 | 
			
		
	
		
			
				
					|  |  |  | //                    }
 | 
			
		
	
		
			
				
					|  |  |  | //                }
 | 
			
		
	
		
			
				
					|  |  |  | //                
 | 
			
		
	
		
			
				
					|  |  |  | //                // If there are no valid combinations for the action, we need to skip the generation of synchronizing
 | 
			
		
	
		
			
				
					|  |  |  | //                // commands.
 | 
			
		
	
		
			
				
					|  |  |  | //                if (!noCombinationsForAction) {
 | 
			
		
	
		
			
				
					|  |  |  | //                    // Save the solver state to be able to restore it when this action index is done.
 | 
			
		
	
		
			
				
					|  |  |  | //                    solver->push();
 | 
			
		
	
		
			
				
					|  |  |  | //                    
 | 
			
		
	
		
			
				
					|  |  |  | //                    // Start by creating a fresh auxiliary variable for each command and link it with the guard.
 | 
			
		
	
		
			
				
					|  |  |  | //                    std::vector<std::vector<storm::expressions::Variable>> commandVariables(possibleCommands.size());
 | 
			
		
	
		
			
				
					|  |  |  | //                    std::vector<storm::expressions::Variable> allCommandVariables;
 | 
			
		
	
		
			
				
					|  |  |  | //                    for (uint_fast64_t outerIndex = 0; outerIndex < possibleCommands.size(); ++outerIndex) {
 | 
			
		
	
		
			
				
					|  |  |  | //                        // Create auxiliary variables and link them with the guards.
 | 
			
		
	
		
			
				
					|  |  |  | //                        for (uint_fast64_t innerIndex = 0; innerIndex < possibleCommands[outerIndex].size(); ++innerIndex) {
 | 
			
		
	
		
			
				
					|  |  |  | //                            commandVariables[outerIndex].push_back(manager->declareFreshBooleanVariable());
 | 
			
		
	
		
			
				
					|  |  |  | //                            allCommandVariables.push_back(commandVariables[outerIndex].back());
 | 
			
		
	
		
			
				
					|  |  |  | //                            solver->add(implies(commandVariables[outerIndex].back(), possibleCommands[outerIndex][innerIndex].get().getGuardExpression()));
 | 
			
		
	
		
			
				
					|  |  |  | //                        }
 | 
			
		
	
		
			
				
					|  |  |  | //                        
 | 
			
		
	
		
			
				
					|  |  |  | //                        storm::expressions::Expression atLeastOneCommandFromModule = manager->boolean(false);
 | 
			
		
	
		
			
				
					|  |  |  | //                        for (auto const& commandVariable : commandVariables[outerIndex]) {
 | 
			
		
	
		
			
				
					|  |  |  | //                            atLeastOneCommandFromModule = atLeastOneCommandFromModule || commandVariable;
 | 
			
		
	
		
			
				
					|  |  |  | //                        }
 | 
			
		
	
		
			
				
					|  |  |  | //                        solver->add(atLeastOneCommandFromModule);
 | 
			
		
	
		
			
				
					|  |  |  | //                    }
 | 
			
		
	
		
			
				
					|  |  |  | //                    
 | 
			
		
	
		
			
				
					|  |  |  | //                    // Now we are in a position to start the enumeration over all command variables. While doing so, we
 | 
			
		
	
		
			
				
					|  |  |  | //                    // keep track of previously seen command combinations, because the AllSat procedures are not
 | 
			
		
	
		
			
				
					|  |  |  | //                    // always guaranteed to only provide distinct models.
 | 
			
		
	
		
			
				
					|  |  |  | //                    std::unordered_set<std::vector<uint_fast64_t>, storm::utility::vector::VectorHash<uint_fast64_t>> seenCommandCombinations;
 | 
			
		
	
		
			
				
					|  |  |  | //                    solver->allSat(allCommandVariables, [&] (storm::solver::SmtSolver::ModelReference& modelReference) -> bool {
 | 
			
		
	
		
			
				
					|  |  |  | //                        // Now we need to reconstruct the chosen commands from the valuation of the command variables.
 | 
			
		
	
		
			
				
					|  |  |  | //                        std::vector<std::vector<std::reference_wrapper<Command const>>> chosenCommands(possibleCommands.size());
 | 
			
		
	
		
			
				
					|  |  |  | //                        
 | 
			
		
	
		
			
				
					|  |  |  | //                        for (uint_fast64_t outerIndex = 0; outerIndex < commandVariables.size(); ++outerIndex) {
 | 
			
		
	
		
			
				
					|  |  |  | //                            for (uint_fast64_t innerIndex = 0; innerIndex < commandVariables[outerIndex].size(); ++innerIndex) {
 | 
			
		
	
		
			
				
					|  |  |  | //                                if (modelReference.getBooleanValue(commandVariables[outerIndex][innerIndex])) {
 | 
			
		
	
		
			
				
					|  |  |  | //                                    chosenCommands[outerIndex].push_back(possibleCommands[outerIndex][innerIndex]);
 | 
			
		
	
		
			
				
					|  |  |  | //                                }
 | 
			
		
	
		
			
				
					|  |  |  | //                            }
 | 
			
		
	
		
			
				
					|  |  |  | //                        }
 | 
			
		
	
		
			
				
					|  |  |  | //                        
 | 
			
		
	
		
			
				
					|  |  |  | //                        // Now that we have retrieved the commands, we need to build their synchronizations and add them
 | 
			
		
	
		
			
				
					|  |  |  | //                        // to the flattened module.
 | 
			
		
	
		
			
				
					|  |  |  | //                        std::vector<std::vector<std::reference_wrapper<Command const>>::const_iterator> iterators;
 | 
			
		
	
		
			
				
					|  |  |  | //                        for (auto const& element : chosenCommands) {
 | 
			
		
	
		
			
				
					|  |  |  | //                            iterators.push_back(element.begin());
 | 
			
		
	
		
			
				
					|  |  |  | //                        }
 | 
			
		
	
		
			
				
					|  |  |  | //                        
 | 
			
		
	
		
			
				
					|  |  |  | //                        bool movedAtLeastOneIterator = false;
 | 
			
		
	
		
			
				
					|  |  |  | //                        std::vector<std::reference_wrapper<Command const>> commandCombination(chosenCommands.size(), chosenCommands.front().front());
 | 
			
		
	
		
			
				
					|  |  |  | //                        std::vector<uint_fast64_t> commandCombinationIndices(iterators.size());
 | 
			
		
	
		
			
				
					|  |  |  | //                        do {
 | 
			
		
	
		
			
				
					|  |  |  | //                            for (uint_fast64_t index = 0; index < iterators.size(); ++index) {
 | 
			
		
	
		
			
				
					|  |  |  | //                                commandCombination[index] = *iterators[index];
 | 
			
		
	
		
			
				
					|  |  |  | //                                commandCombinationIndices[index] = commandCombination[index].get().getGlobalIndex();
 | 
			
		
	
		
			
				
					|  |  |  | //                            }
 | 
			
		
	
		
			
				
					|  |  |  | //                            
 | 
			
		
	
		
			
				
					|  |  |  | //                            // Only add the command combination if it was not previously seen.
 | 
			
		
	
		
			
				
					|  |  |  | //                            auto seenIt = seenCommandCombinations.find(commandCombinationIndices);
 | 
			
		
	
		
			
				
					|  |  |  | //                            if (seenIt == seenCommandCombinations.end()) {
 | 
			
		
	
		
			
				
					|  |  |  | //                                newCommands.push_back(synchronizeCommands(nextCommandIndex, actionIndex, nextUpdateIndex, indexToActionMap.find(actionIndex)->second, commandCombination));
 | 
			
		
	
		
			
				
					|  |  |  | //                                seenCommandCombinations.insert(commandCombinationIndices);
 | 
			
		
	
		
			
				
					|  |  |  | //                                
 | 
			
		
	
		
			
				
					|  |  |  | //                                // Move the counters appropriately.
 | 
			
		
	
		
			
				
					|  |  |  | //                                ++nextCommandIndex;
 | 
			
		
	
		
			
				
					|  |  |  | //                                nextUpdateIndex += newCommands.back().getNumberOfUpdates();
 | 
			
		
	
		
			
				
					|  |  |  | //                            }
 | 
			
		
	
		
			
				
					|  |  |  | //                            
 | 
			
		
	
		
			
				
					|  |  |  | //                            movedAtLeastOneIterator = false;
 | 
			
		
	
		
			
				
					|  |  |  | //                            for (uint_fast64_t index = 0; index < iterators.size(); ++index) {
 | 
			
		
	
		
			
				
					|  |  |  | //                                ++iterators[index];
 | 
			
		
	
		
			
				
					|  |  |  | //                                if (iterators[index] != chosenCommands[index].cend()) {
 | 
			
		
	
		
			
				
					|  |  |  | //                                    movedAtLeastOneIterator = true;
 | 
			
		
	
		
			
				
					|  |  |  | //                                    break;
 | 
			
		
	
		
			
				
					|  |  |  | //                                } else {
 | 
			
		
	
		
			
				
					|  |  |  | //                                    iterators[index] = chosenCommands[index].cbegin();
 | 
			
		
	
		
			
				
					|  |  |  | //                                }
 | 
			
		
	
		
			
				
					|  |  |  | //                            }
 | 
			
		
	
		
			
				
					|  |  |  | //                        } while (movedAtLeastOneIterator);
 | 
			
		
	
		
			
				
					|  |  |  | //                        
 | 
			
		
	
		
			
				
					|  |  |  | //                        return true;
 | 
			
		
	
		
			
				
					|  |  |  | //                    });
 | 
			
		
	
		
			
				
					|  |  |  | //                    
 | 
			
		
	
		
			
				
					|  |  |  | //                    solver->pop();
 | 
			
		
	
		
			
				
					|  |  |  | //                }
 | 
			
		
	
		
			
				
					|  |  |  | //            }
 | 
			
		
	
		
			
				
					|  |  |  | //            
 | 
			
		
	
		
			
				
					|  |  |  | //            // Finally, we can create the module and the program and return it.
 | 
			
		
	
		
			
				
					|  |  |  | //            storm::prism::Module singleModule(newModuleName.str(), allBooleanVariables, allIntegerVariables, newCommands, this->getFilename(), 0);
 | 
			
		
	
		
			
				
					|  |  |  | //            return Program(manager, this->getModelType(), this->getConstants(), std::vector<storm::prism::BooleanVariable>(), std::vector<storm::prism::IntegerVariable>(), this->getFormulas(), {singleModule}, actionToIndexMap, this->getRewardModels(), this->getLabels(), this->getOptionalInitialConstruct(), this->getOptionalSystemCompositionConstruct(), this->getFilename(), 0, true);
 | 
			
		
	
		
			
				
					|  |  |  |         } | 
			
		
	
		
			
				
					|  |  |  |          | 
			
		
	
		
			
				
					|  |  |  |         uint64_t Model::addAction(Action const& action) { | 
			
		
	
	
		
			
				
					|  |  | 
 |