/* * IntermediateRepresentationAdapter.h * * Created on: 13.01.2013 * Author: Christian Dehnert */ #ifndef STORM_IR_EXPLICITMODELADAPTER_H_ #define STORM_IR_EXPLICITMODELADAPTER_H_ #include "src/storage/SparseMatrix.h" #include "src/utility/Settings.h" #include <tuple> #include <unordered_map> #include <boost/functional/hash.hpp> #include <map> #include <queue> #include <set> #include <iostream> #include <memory> #include <list> typedef std::pair<std::vector<bool>, std::vector<int_fast64_t>> StateType; #include "log4cplus/logger.h" #include "log4cplus/loggingmacros.h" extern log4cplus::Logger logger; namespace storm { namespace adapters { class StateHash { public: std::size_t operator()(StateType* state) const { size_t seed = 0; for (auto it = state->first.begin(); it != state->first.end(); ++it) { boost::hash_combine<bool>(seed, *it); } for (auto it = state->second.begin(); it != state->second.end(); ++it) { boost::hash_combine<int_fast64_t>(seed, *it); } return seed; } }; class StateCompare { public: bool operator()(StateType* state1, StateType* state2) const { return *state1 == *state2; } }; class ExplicitModelAdapter { public: ExplicitModelAdapter(std::shared_ptr<storm::ir::Program> program) : program(program), allStates(), stateToIndexMap(), booleanVariables(), integerVariables(), booleanVariableToIndexMap(), integerVariableToIndexMap(), numberOfTransitions(0) { } template<class T> std::shared_ptr<storm::storage::SparseMatrix<T>> toSparseMatrix() { LOG4CPLUS_INFO(logger, "Creating sparse matrix for probabilistic program."); //this->buildMatrix2<T>(); //this->computeReachableStateSpace(); std::shared_ptr<storm::storage::SparseMatrix<T>> resultMatrix = this->buildMatrix2<T>(); LOG4CPLUS_INFO(logger, "Created sparse matrix with " << resultMatrix->getRowCount() << " reachable states and " << resultMatrix->getNonZeroEntryCount() << " transitions."); this->clearReachableStateSpace(); return resultMatrix; } private: static void setValue(StateType* state, uint_fast64_t index, bool value) { std::get<0>(*state)[index] = value; } static void setValue(StateType* state, uint_fast64_t index, int_fast64_t value) { std::get<1>(*state)[index] = value; } void prepareAuxiliaryDatastructures() { uint_fast64_t numberOfIntegerVariables = 0; uint_fast64_t numberOfBooleanVariables = 0; for (uint_fast64_t i = 0; i < program->getNumberOfModules(); ++i) { numberOfIntegerVariables += program->getModule(i).getNumberOfIntegerVariables(); numberOfBooleanVariables += program->getModule(i).getNumberOfBooleanVariables(); } this->booleanVariables.resize(numberOfBooleanVariables); this->integerVariables.resize(numberOfIntegerVariables); uint_fast64_t nextBooleanVariableIndex = 0; uint_fast64_t nextIntegerVariableIndex = 0; for (uint_fast64_t i = 0; i < program->getNumberOfModules(); ++i) { storm::ir::Module const& module = program->getModule(i); for (uint_fast64_t j = 0; j < module.getNumberOfBooleanVariables(); ++j) { this->booleanVariables[nextBooleanVariableIndex] = module.getBooleanVariable(j); this->booleanVariableToIndexMap[module.getBooleanVariable(j).getName()] = nextBooleanVariableIndex; ++nextBooleanVariableIndex; } for (uint_fast64_t j = 0; j < module.getNumberOfIntegerVariables(); ++j) { this->integerVariables[nextIntegerVariableIndex] = module.getIntegerVariable(j); this->integerVariableToIndexMap[module.getIntegerVariable(j).getName()] = nextIntegerVariableIndex; ++nextIntegerVariableIndex; } } } std::unique_ptr<std::list<std::list<storm::ir::Command>>> getActiveCommandsByAction(StateType const * state, std::string& action) { std::unique_ptr<std::list<std::list<storm::ir::Command>>> res = std::unique_ptr<std::list<std::list<storm::ir::Command>>>(new std::list<std::list<storm::ir::Command>>()); // Iterate over all modules. for (uint_fast64_t i = 0; i < this->program->getNumberOfModules(); ++i) { storm::ir::Module const& module = this->program->getModule(i); std::shared_ptr<std::set<uint_fast64_t>> ids = module.getCommandsByAction(action); std::list<storm::ir::Command> commands; // Look up commands by their id. Add, if guard holds. for (uint_fast64_t id : *ids) { storm::ir::Command cmd = module.getCommand(id); if (cmd.getGuard()->getValueAsBool(state)) { commands.push_back(module.getCommand(id)); } } res->push_back(commands); } // Sort the result in the vague hope that having small lists at the beginning will speed up the expanding. // This is how lambdas may look like in C++... res->sort([](const std::list<storm::ir::Command>& a, const std::list<storm::ir::Command>& b){ return a.size() < b.size(); }); return res; } /*! * Apply an update to the given state and return resulting state. * @params state Current state. * @params update Update to be applied. * @return Resulting state. */ StateType* applyUpdate(StateType const * const state, storm::ir::Update const & update) { StateType* newState = new StateType(*state); for (auto assignedVariable : update.getBooleanAssignments()) { setValue(newState, this->booleanVariableToIndexMap[assignedVariable.first], assignedVariable.second.getExpression()->getValueAsBool(state)); } for (auto assignedVariable : update.getIntegerAssignments()) { setValue(newState, this->integerVariableToIndexMap[assignedVariable.first], assignedVariable.second.getExpression()->getValueAsInt(state)); } return newState; } /*! * Create a new state and initialize with initial values. * @return Pointer to initial state. */ StateType* buildInitialState() { // Create a fresh state which can hold as many boolean and integer variables as there are. StateType* initialState = new StateType(); initialState->first.resize(this->booleanVariables.size()); initialState->second.resize(this->integerVariables.size()); // Now initialize all fields in the value vectors of the state according to the initial // values provided by the input program. for (uint_fast64_t i = 0; i < this->booleanVariables.size(); ++i) { bool initialValue = this->booleanVariables[i].getInitialValue()->getValueAsBool(initialState); std::get<0>(*initialState)[i] = initialValue; } for (uint_fast64_t i = 0; i < this->integerVariables.size(); ++i) { int_fast64_t initialValue = this->integerVariables[i].getInitialValue()->getValueAsInt(initialState); std::get<1>(*initialState)[i] = initialValue; } return initialState; } /*! * Generates all initial states and adds them to allStates. */ void generateInitialStates() { // Create a fresh state which can hold as many boolean and integer variables as there are. this->allStates.clear(); this->allStates.push_back(new StateType()); this->allStates[0]->first.resize(this->booleanVariables.size()); this->allStates[0]->second.resize(this->integerVariables.size()); // Start with boolean variables. for (uint_fast64_t i = 0; i < this->booleanVariables.size(); ++i) { // Check if an initial value is given if (this->booleanVariables[i].getInitialValue().get() == nullptr) { // No initial value was given. uint_fast64_t size = this->allStates.size(); for (uint_fast64_t pos = 0; pos < size; pos++) { // Duplicate each state, one with true and one with false. this->allStates.push_back(new StateType(*this->allStates[pos])); std::get<0>(*this->allStates[pos])[i] = false; std::get<0>(*this->allStates[size + pos])[i] = true; } } else { // Initial value was given. bool initialValue = this->booleanVariables[i].getInitialValue()->getValueAsBool(this->allStates[0]); for (auto it : this->allStates) { std::get<0>(*it)[i] = initialValue; } } } // Now process integer variables. for (uint_fast64_t i = 0; i < this->integerVariables.size(); ++i) { // Check if an initial value was given. if (this->integerVariables[i].getInitialValue().get() == nullptr) { // No initial value was given. uint_fast64_t size = this->allStates.size(); int_fast64_t lower = this->integerVariables[i].getLowerBound()->getValueAsInt(this->allStates[0]); int_fast64_t upper = this->integerVariables[i].getUpperBound()->getValueAsInt(this->allStates[0]); // Duplicate all states for all values in variable interval. for (int_fast64_t value = lower; value <= upper; value++) { for (uint_fast64_t pos = 0; pos < size; pos++) { // If value is lower bound, we reuse the existing state, otherwise we create a new one. if (value > lower) this->allStates.push_back(new StateType(*this->allStates[pos])); // Set value to current state. std::get<1>(*this->allStates[(value - lower) * size + pos])[i] = value; } } } else { // Initial value was given. int_fast64_t initialValue = this->integerVariables[i].getInitialValue()->getValueAsInt(this->allStates[0]); for (auto it : this->allStates) { std::get<1>(*it)[i] = initialValue; } } } } /*! * Retrieves the state id of the given state. * If the state has not been hit yet, it will be added to allStates and given a new id. * In this case, the pointer must not be deleted, as it is used within allStates. * If the state is already known, the pointer is deleted and the old state id is returned. * Hence, the given state pointer should not be used afterwards. * @param state Pointer to state, shall not be used afterwards. * @returns State id of given state. */ uint_fast64_t getOrAddStateId(StateType * state) { // Check, if we already know this state at all. auto indexIt = this->stateToIndexMap.find(state); if (indexIt == this->stateToIndexMap.end()) { // No, add to allStates, initialize index. allStates.push_back(state); stateToIndexMap[state] = allStates.size()-1; return allStates.size()-1; } else { // Yes, obtain index and delete state object. delete state; return indexIt->second; } } /*! * Expands all unlabeled transitions for a given state and adds them to the given list of results. * There will be an additional map for each Command that is active. * Each such map will contain a probability distribution over the reachable states using this Command. * @params state State to be expanded * @params res List of */ void addUnlabeledTransitions(const uint_fast64_t stateID, std::list<std::map<uint_fast64_t, double>>& res) { const StateType* state = this->allStates[stateID]; // Iterate over all modules. for (uint_fast64_t i = 0; i < program->getNumberOfModules(); ++i) { storm::ir::Module const& module = program->getModule(i); // Iterate over all commands. for (uint_fast64_t j = 0; j < module.getNumberOfCommands(); ++j) { storm::ir::Command const& command = module.getCommand(j); // Only consider unlabeled commands. if (command.getActionName() != "") continue; // Omit, if command is not active. if (!command.getGuard()->getValueAsBool(state)) continue; // Add a new map and get pointer. res.emplace_back(); std::map<uint_fast64_t, double>* states = &res.back(); // Iterate over all updates. for (uint_fast64_t k = 0; k < command.getNumberOfUpdates(); ++k) { // Obtain new state id. storm::ir::Update const& update = command.getUpdate(k); uint_fast64_t newStateId = this->getOrAddStateId(this->applyUpdate(state, update)); // Check, if we already know this state, add up probabilities for every state. auto stateIt = states->find(newStateId); if (stateIt == states->end()) { (*states)[newStateId] = update.getLikelihoodExpression()->getValueAsDouble(state); this->numberOfTransitions++; } else { (*states)[newStateId] += update.getLikelihoodExpression()->getValueAsDouble(state); } } } } } void addLabeledTransitions(const uint_fast64_t stateID, std::list<std::map<uint_fast64_t, double>>& res) { // Create a copy of the current state, as we will free intermediate states... StateType* state = new StateType(*this->allStates[stateID]); for (std::string action : this->program->getActions()) { std::unique_ptr<std::list<std::list<storm::ir::Command>>> cmds = this->getActiveCommandsByAction(state, action); // Start with current state std::unordered_map<StateType*, double, StateHash, StateCompare> resultStates; resultStates[state] = 1.0; for (std::list<storm::ir::Command> module : *cmds) { if (resultStates.size() == 0) break; std::unordered_map<StateType*, double, StateHash, StateCompare> newStates; // Iterate over all commands within this module. for (storm::ir::Command command : module) { // Iterate over all updates of this command. for (uint_fast64_t k = 0; k < command.getNumberOfUpdates(); ++k) { storm::ir::Update const& update = command.getUpdate(k); // Iterate over all resultStates. for (auto it : resultStates) { // Apply the new update and get resulting state. StateType* newState = this->applyUpdate(it.first, update); // Insert the new state into newStates array. // Take care of calculation of likelihood, combine identical states. auto s = newStates.find(newState); if (s == newStates.end()) { newStates[newState] = it.second * update.getLikelihoodExpression()->getValueAsDouble(it.first); } else { newStates[newState] += it.second * update.getLikelihoodExpression()->getValueAsDouble(it.first); } } } } for (auto it: resultStates) { delete it.first; } // Move new states to resultStates. resultStates.clear(); resultStates.insert(newStates.begin(), newStates.end()); } if (resultStates.size() > 0) { res.emplace_back(); std::map<uint_fast64_t, double>* states = &res.back(); // Now add our final result states to our global result. for (auto it : resultStates) { uint_fast64_t newStateID = this->getOrAddStateId(it.first); (*states)[newStateID] = it.second; } this->numberOfTransitions += states->size(); } } } void dump(std::map<uint_fast64_t, double>& obj) { std::cout << "Some map:" << std::endl; for (auto it: obj) { std::cout << "\t" << it.first << ": " << it.second << std::endl; } } /*! * Create matrix from intermediate mapping, assuming it is a dtmc model. * @param intermediate Intermediate representation of transition mapping. * @return result matrix. */ template<class T> std::shared_ptr<storm::storage::SparseMatrix<T>> buildDTMCMatrix(std::map<uint_fast64_t, std::list<std::map<uint_fast64_t, double>>> intermediate) { std::cout << "Building DTMC matrix" << std::endl; std::shared_ptr<storm::storage::SparseMatrix<T>> result(new storm::storage::SparseMatrix<T>(allStates.size())); uint_fast64_t numberOfTransitions = 0; for (uint_fast64_t state = 0; state < this->allStates.size(); state++) { std::set<uint_fast64_t> set; for (auto choice : intermediate[state]) { for (auto elem : choice) { set.insert(elem.first); } } numberOfTransitions += set.size(); } std::cout << "number of Transitions: " << numberOfTransitions << std::endl; result->initialize(numberOfTransitions); for (uint_fast64_t state = 0; state < this->allStates.size(); state++) { if (intermediate[state].size() > 1) { std::cout << "Warning: state " << state << " has " << intermediate[state].size() << " overlapping guards in dtmc" << std::endl; } std::map<uint_fast64_t, double> map; for (auto choice : intermediate[state]) { for (auto elem : choice) { map[elem.first] += elem.second; } } double factor = 1.0 / intermediate[state].size(); for (auto it : map) { result->addNextValue(state, it.first, it.second * factor); } } result->finalize(); return result; } /*! * Create matrix from intermediate mapping, assuming it is a mdp model. * @param intermediate Intermediate representation of transition mapping. * @param choices Overall number of choices for all nodes. * @return result matrix. */ template<class T> std::shared_ptr<storm::storage::SparseMatrix<T>> buildMDPMatrix(std::map<uint_fast64_t, std::list<std::map<uint_fast64_t, double>>> intermediate, uint_fast64_t choices) { std::cout << "Building MDP matrix" << std::endl; std::shared_ptr<storm::storage::SparseMatrix<T>> result(new storm::storage::SparseMatrix<T>(allStates.size(), choices)); result->initialize(this->numberOfTransitions); uint_fast64_t nextRow = 0; for (uint_fast64_t state = 0; state < this->allStates.size(); state++) { for (auto choice : intermediate[state]) { for (auto it : choice) { result->addNextValue(nextRow, it.first, it.second); } nextRow++; } } result->finalize(); return result; } template<class T> std::shared_ptr<storm::storage::SparseMatrix<T>> buildMatrix2() { this->prepareAuxiliaryDatastructures(); this->allStates.clear(); this->stateToIndexMap.clear(); this->numberOfTransitions = 0; uint_fast64_t choices; std::map<uint_fast64_t, std::list<std::map<uint_fast64_t, double>>> intermediate; this->generateInitialStates(); for (uint_fast64_t curIndex = 0; curIndex < this->allStates.size(); curIndex++) { this->addUnlabeledTransitions(curIndex, intermediate[curIndex]); this->addLabeledTransitions(curIndex, intermediate[curIndex]); choices += intermediate[curIndex].size(); if (intermediate[curIndex].size() == 0) { // This is a deadlock state. if (storm::settings::instance()->isSet("fix-deadlocks")) { this->numberOfTransitions++; intermediate[curIndex].emplace_back(); intermediate[curIndex].back()[curIndex] = 1; } else { LOG4CPLUS_ERROR(logger, "Error while creating sparse matrix from probabilistic program: found deadlock state."); throw storm::exceptions::WrongFileFormatException() << "Error while creating sparse matrix from probabilistic program: found deadlock state."; } } } switch (this->program->getModelType()) { case storm::ir::Program::DTMC: case storm::ir::Program::CTMC: return this->buildDTMCMatrix<T>(intermediate); case storm::ir::Program::MDP: case storm::ir::Program::CTMDP: return this->buildMDPMatrix<T>(intermediate, choices); default: LOG4CPLUS_ERROR(logger, "Error while creating sparse matrix from probabilistic program: We can't handle this model type."); throw storm::exceptions::WrongFileFormatException() << "Error while creating sparse matrix from probabilistic program: We can't handle this model type."; break; } return std::shared_ptr<storm::storage::SparseMatrix<T>>(nullptr); } void computeReachableStateSpace() { // Prepare some internal data structures, such as mappings from variables to indices and so on. this->prepareAuxiliaryDatastructures(); // Build initial state. StateType* initialState = this->buildInitialState(); // Now set up the environment for a breadth-first search starting from the initial state. uint_fast64_t nextIndex = 1; this->allStates.clear(); this->stateToIndexMap.clear(); std::queue<StateType*> stateQueue; this->allStates.push_back(initialState); stateQueue.push(initialState); this->stateToIndexMap[initialState] = 0; this->numberOfTransitions = 0; while (!stateQueue.empty()) { // Get first state in queue. StateType* currentState = stateQueue.front(); stateQueue.pop(); // Remember whether the state has at least one transition such that transitions can be // inserted upon detection of a deadlock state. bool hasTransition = false; // First expand all transitions for commands labelled with some // action. For every module, we determine all commands with this // action whose guard holds. Then, we add a transition for each // combination of all updates of those commands. for (std::string action : this->program->getActions()) { // Get list of all commands. // This list contains a list for every module that has commands labelled by action. // Each such list contains all commands whose guards are fulfilled. // If no guard is fulfilled (i.e. there is no way to perform this action), the list will be empty! std::unique_ptr<std::list<std::list<storm::ir::Command>>> cmds = this->getActiveCommandsByAction(currentState, action); // Start with current state. std::unordered_map<StateType*, double, StateHash, StateCompare> resultStates; resultStates[currentState] = 1; std::queue<StateType*> deleteQueue; // Iterate over all modules (represented by the list of commands with the current action). // We will now combine every state in resultStates with every additional update in the next module. // The final result will be this map after we are done with all modules. for (std::list<storm::ir::Command> module : *cmds) { // If no states are left, we are done. // This happens, if there is a module where commands existed, but no guard was fulfilled. if (resultStates.size() == 0) break; // Put all new states in this new map. std::unordered_map<StateType*, double, StateHash, StateCompare> newStates; // Iterate over all commands within this module. for (storm::ir::Command command : module) { // Iterate over all updates of this command. for (uint_fast64_t k = 0; k < command.getNumberOfUpdates(); ++k) { storm::ir::Update const& update = command.getUpdate(k); // Iterate over all resultStates. for (auto it : resultStates) { // Apply the new update and get resulting state. StateType* newState = this->applyUpdate(it.first, update); // Insert the new state into newStates array. // Take care of calculation of likelihood, combine identical states. auto s = newStates.find(newState); if (s == newStates.end()) { newStates[newState] = it.second * update.getLikelihoodExpression()->getValueAsDouble(it.first); } else { newStates[newState] += it.second * update.getLikelihoodExpression()->getValueAsDouble(it.first); } // No matter what happened, we must delete the states of the previous iteration. deleteQueue.push(it.first); } } } // Move new states to resultStates. resultStates.clear(); resultStates.insert(newStates.begin(), newStates.end()); // Delete old result states. while (!deleteQueue.empty()) { if (deleteQueue.front() != currentState) { delete deleteQueue.front(); } deleteQueue.pop(); } } // Now add our final result states to our global result. for (auto it : resultStates) { hasTransition = true; auto s = stateToIndexMap.find(it.first); if (s == stateToIndexMap.end()) { stateQueue.push(it.first); // Add state to list of all reachable states. allStates.push_back(it.first); // Give a unique index to the newly found state. stateToIndexMap[it.first] = nextIndex; ++nextIndex; } else { deleteQueue.push(it.first); } } // Delete states we already had. while (!deleteQueue.empty()) { delete deleteQueue.front(); deleteQueue.pop(); } this->numberOfTransitions += resultStates.size(); } // Now, expand all transitions for commands not labelled with // some action. Those commands each build a transition for // themselves. // Iterate over all modules. for (uint_fast64_t i = 0; i < program->getNumberOfModules(); ++i) { storm::ir::Module const& module = program->getModule(i); // Iterate over all commands. for (uint_fast64_t j = 0; j < module.getNumberOfCommands(); ++j) { storm::ir::Command const& command = module.getCommand(j); if (command.getActionName() != "") continue; // Check if this command is enabled in the current state. if (command.getGuard()->getValueAsBool(currentState)) { hasTransition = true; // Remember what states are targeted by an update of the current command // in order to be able to sum those probabilities and not increase the // transition count. std::unordered_map<StateType*, double, StateHash, StateCompare> stateToProbabilityMap; // Keep a queue of states to delete after the current command. When one // command is processed and states are encountered which were already found // before, we can only delete them after the command has been processed, // because the stateToProbabilityMap will contain illegal values otherwise. std::queue<StateType*> statesToDelete; // Now iterate over all updates to see where the updates take the current // state. for (uint_fast64_t k = 0; k < command.getNumberOfUpdates(); ++k) { storm::ir::Update const& update = command.getUpdate(k); // Now copy the current state and only overwrite the entries in the // vectors if there is an assignment to that variable in the current // update. StateType* newState = this->applyUpdate(currentState, update); // If we have already found the target state of the update, we must not // increase the transition count. auto probIt = stateToProbabilityMap.find(newState); if (probIt != stateToProbabilityMap.end()) { stateToProbabilityMap[newState] += update.getLikelihoodExpression()->getValueAsDouble(currentState); } else { ++numberOfTransitions; stateToProbabilityMap[newState] = update.getLikelihoodExpression()->getValueAsDouble(currentState); } // Depending on whether the state was found previously, we mark it for // deletion or add it to the reachable state space and mark it for // further exploration. auto it = stateToIndexMap.find(newState); if (it != stateToIndexMap.end()) { // Queue the state object for deletion as we have already seen that // state. statesToDelete.push(newState); } else { // Add state to the queue of states that are still to be explored. stateQueue.push(newState); // Add state to list of all reachable states. allStates.push_back(newState); // Give a unique index to the newly found state. stateToIndexMap[newState] = nextIndex; ++nextIndex; } } // Now delete all states queued for deletion. while (!statesToDelete.empty()) { delete statesToDelete.front(); statesToDelete.pop(); } } } } // If the state is a deadlock state, and the corresponding flag is set, we tolerate that // and increase the number of transitions by one, because a self-loop is going to be // inserted in the next step. If the flag is not set, an exception is thrown. if (!hasTransition) { if (storm::settings::instance()->isSet("fix-deadlocks")) { ++numberOfTransitions; } else { LOG4CPLUS_ERROR(logger, "Error while creating sparse matrix from probabilistic program: found deadlock state."); throw storm::exceptions::WrongFileFormatException() << "Error while creating sparse matrix from probabilistic program: found deadlock state."; } } } } template<class T> std::shared_ptr<storm::storage::SparseMatrix<T>> buildMatrix() { std::shared_ptr<storm::storage::SparseMatrix<T>> resultMatrix(new storm::storage::SparseMatrix<T>(allStates.size())); resultMatrix->initialize(numberOfTransitions); // Keep track of the running index to insert values into correct matrix row. uint_fast64_t currentIndex = 0; // Determine the matrix content for every row (i.e. reachable state). for (StateType* currentState : allStates) { bool hasTransition = false; std::map<uint_fast64_t, double> stateIndexToProbabilityMap; for (std::string action : this->program->getActions()) { std::unique_ptr<std::list<std::list<storm::ir::Command>>> cmds = this->getActiveCommandsByAction(currentState, action); std::unordered_map<StateType*, double, StateHash, StateCompare> resultStates; resultStates[currentState] = 1; std::queue<StateType*> deleteQueue; for (std::list<storm::ir::Command> module : *cmds) { std::unordered_map<StateType*, double, StateHash, StateCompare> newStates; for (storm::ir::Command command : module) { for (uint_fast64_t k = 0; k < command.getNumberOfUpdates(); ++k) { storm::ir::Update const& update = command.getUpdate(k); for (auto it : resultStates) { StateType* newState = this->applyUpdate(it.first, update); auto s = newStates.find(newState); if (s == newStates.end()) { newStates[newState] = it.second * update.getLikelihoodExpression()->getValueAsDouble(it.first); } else { newStates[newState] += it.second * update.getLikelihoodExpression()->getValueAsDouble(it.first); } deleteQueue.push(it.first); } } } resultStates.clear(); resultStates.insert(newStates.begin(), newStates.end()); while (!deleteQueue.empty()) { if (deleteQueue.front() != currentState) { delete deleteQueue.front(); } deleteQueue.pop(); } } for (auto it : resultStates) { hasTransition = true; uint_fast64_t targetIndex = stateToIndexMap[it.first]; auto s = stateIndexToProbabilityMap.find(targetIndex); if (s == stateIndexToProbabilityMap.end()) { stateIndexToProbabilityMap[targetIndex] = it.second; } else { stateIndexToProbabilityMap[targetIndex] += it.second; } delete it.first; } } for (auto targetIndex : stateIndexToProbabilityMap) { resultMatrix->addNextValue(currentIndex, targetIndex.first, targetIndex.second); } // Iterate over all modules. for (uint_fast64_t i = 0; i < program->getNumberOfModules(); ++i) { storm::ir::Module const& module = program->getModule(i); // Iterate over all commands. for (uint_fast64_t j = 0; j < module.getNumberOfCommands(); ++j) { storm::ir::Command const& command = module.getCommand(j); if (command.getActionName() != "") continue; // Check if this command is enabled in the current state. if (command.getGuard()->getValueAsBool(currentState)) { hasTransition = true; std::map<uint_fast64_t, double> stateIndexToProbabilityMap; for (uint_fast64_t k = 0; k < command.getNumberOfUpdates(); ++k) { storm::ir::Update const& update = command.getUpdate(k); StateType* newState = this->applyUpdate(currentState, update); uint_fast64_t targetIndex = (*stateToIndexMap.find(newState)).second; delete newState; auto probIt = stateIndexToProbabilityMap.find(targetIndex); if (probIt != stateIndexToProbabilityMap.end()) { stateIndexToProbabilityMap[targetIndex] += update.getLikelihoodExpression()->getValueAsDouble(currentState); } else { stateIndexToProbabilityMap[targetIndex] = update.getLikelihoodExpression()->getValueAsDouble(currentState); } } // Now insert the actual values into the matrix. for (auto targetIndex : stateIndexToProbabilityMap) { resultMatrix->addNextValue(currentIndex, targetIndex.first, targetIndex.second); } } } } // If the state is a deadlock state, a self-loop is inserted. Note that we do not have // to check whether --fix-deadlocks is set, because if this was not the case an // exception would have been thrown earlier. if (!hasTransition) { resultMatrix->addNextValue(currentIndex, currentIndex, 1); } ++currentIndex; } // Finalize matrix and return it. resultMatrix->finalize(); return resultMatrix; } void clearReachableStateSpace() { for (auto it : allStates) { delete it; } allStates.clear(); stateToIndexMap.clear(); } std::shared_ptr<storm::ir::Program> program; std::vector<StateType*> allStates; std::unordered_map<StateType*, uint_fast64_t, StateHash, StateCompare> stateToIndexMap; std::vector<storm::ir::BooleanVariable> booleanVariables; std::vector<storm::ir::IntegerVariable> integerVariables; std::unordered_map<std::string, uint_fast64_t> booleanVariableToIndexMap; std::unordered_map<std::string, uint_fast64_t> integerVariableToIndexMap; uint_fast64_t numberOfTransitions; }; } // namespace adapters } // namespace storm #endif /* STORM_IR_EXPLICITMODELADAPTER_H_ */