#include "storm/generator/NextStateGenerator.h" #include "storm/adapters/CarlAdapter.h" #include "storm/logic/Formulas.h" #include "storm/storage/expressions/ExpressionManager.h" #include "storm/storage/expressions/SimpleValuation.h" #include "storm/models/sparse/StateLabeling.h" #include "storm/utility/macros.h" #include "storm/exceptions/InvalidSettingsException.h" namespace storm { namespace generator { template NextStateGenerator::NextStateGenerator(storm::expressions::ExpressionManager const& expressionManager, VariableInformation const& variableInformation, NextStateGeneratorOptions const& options) : options(options), expressionManager(expressionManager.getSharedPointer()), variableInformation(variableInformation), evaluator(nullptr), state(nullptr) { // Intentionally left empty. } template NextStateGenerator::NextStateGenerator(storm::expressions::ExpressionManager const& expressionManager, NextStateGeneratorOptions const& options) : options(options), expressionManager(expressionManager.getSharedPointer()), variableInformation(), evaluator(nullptr), state(nullptr) { // Intentionally left empty. } template NextStateGeneratorOptions const& NextStateGenerator::getOptions() const { return options; } template uint64_t NextStateGenerator::getStateSize() const { return variableInformation.getTotalBitOffset(true); } template void NextStateGenerator::load(CompressedState const& state) { // Since almost all subsequent operations are based on the evaluator, we load the state into it now. unpackStateIntoEvaluator(state, variableInformation, *evaluator); // Also, we need to store a pointer to the state itself, because we need to be able to access it when expanding it. this->state = &state; } template bool NextStateGenerator::satisfies(storm::expressions::Expression const& expression) const { if (expression.isTrue()) { return true; } return evaluator->asBool(expression); } template storm::models::sparse::StateLabeling NextStateGenerator::label(storm::storage::BitVectorHashMap const& states, std::vector const& initialStateIndices, std::vector const& deadlockStateIndices, std::vector> labelsAndExpressions) { for (auto const& expression : this->options.getExpressionLabels()) { std::stringstream stream; stream << expression; labelsAndExpressions.push_back(std::make_pair(stream.str(), expression)); } // Make the labels unique. std::sort(labelsAndExpressions.begin(), labelsAndExpressions.end(), [] (std::pair const& a, std::pair const& b) { return a.first < b.first; } ); auto it = std::unique(labelsAndExpressions.begin(), labelsAndExpressions.end(), [] (std::pair const& a, std::pair const& b) { return a.first == b.first; } ); labelsAndExpressions.resize(std::distance(labelsAndExpressions.begin(), it)); // Prepare result. storm::models::sparse::StateLabeling result(states.size()); // Initialize labeling. for (auto const& label : labelsAndExpressions) { result.addLabel(label.first); } for (auto const& stateIndexPair : states) { unpackStateIntoEvaluator(stateIndexPair.first, variableInformation, *this->evaluator); for (auto const& label : labelsAndExpressions) { // Add label to state, if the corresponding expression is true. if (evaluator->asBool(label.second)) { result.addLabelToState(label.first, stateIndexPair.second); } } } if (!result.containsLabel("init")) { // Also label the initial state with the special label "init". result.addLabel("init"); for (auto index : initialStateIndices) { result.addLabelToState("init", index); } } if (!result.containsLabel("deadlock")) { result.addLabel("deadlock"); for (auto index : deadlockStateIndices) { result.addLabelToState("deadlock", index); } } return result; } template void NextStateGenerator::postprocess(StateBehavior& result) { // If the model we build is a Markov Automaton, we postprocess the choices to sum all Markovian choices // and make the Markovian choice the very first one (if there is any). bool foundPreviousMarkovianChoice = false; if (this->getModelType() == ModelType::MA) { uint64_t numberOfChoicesToDelete = 0; for (uint_fast64_t index = 0; index + numberOfChoicesToDelete < result.getNumberOfChoices();) { Choice& choice = result.getChoices()[index]; if (choice.isMarkovian()) { if (foundPreviousMarkovianChoice) { // If there was a previous Markovian choice, we need to sum them. Note that we can assume // that the previous Markovian choice is the very first one in the choices vector. result.getChoices().front().add(choice); // Swap the choice to the end to indicate it can be removed (if it's not already there). if (index != result.getNumberOfChoices() - 1 - numberOfChoicesToDelete) { choice = std::move(result.getChoices()[result.getNumberOfChoices() - 1 - numberOfChoicesToDelete]); } ++numberOfChoicesToDelete; } else { // If there is no previous Markovian choice, just move the Markovian choice to the front. if (index != 0) { std::swap(result.getChoices().front(), choice); } foundPreviousMarkovianChoice = true; ++index; } } else { ++index; } } // Finally remove the choices that were added to other Markovian choices. if (numberOfChoicesToDelete > 0) { result.getChoices().resize(result.getChoices().size() - numberOfChoicesToDelete); } } } template storm::expressions::SimpleValuation NextStateGenerator::toValuation(CompressedState const& state) const { return unpackStateIntoValuation(state, variableInformation, *expressionManager); } template class NextStateGenerator; #ifdef STORM_HAVE_CARL template class NextStateGenerator; template class NextStateGenerator; #endif } }