#include "storm/models/sparse/NondeterministicModel.h" #include "storm/models/sparse/StandardRewardModel.h" #include "storm/models/sparse/MarkovAutomaton.h" #include "storm/storage/Scheduler.h" #include "storm/storage/memorystructure/MemoryStructureBuilder.h" #include "storm/storage/memorystructure/SparseModelMemoryProduct.h" #include "storm/adapters/RationalFunctionAdapter.h" #include "storm/exceptions/InvalidOperationException.h" namespace storm { namespace models { namespace sparse { template NondeterministicModel::NondeterministicModel(ModelType modelType, storm::storage::sparse::ModelComponents const& components) : Model(modelType, components) { // Intentionally left empty } template NondeterministicModel::NondeterministicModel(ModelType modelType, storm::storage::sparse::ModelComponents&& components) : Model(modelType, std::move(components)) { // Intentionally left empty } template std::vector const& NondeterministicModel::getNondeterministicChoiceIndices() const { return this->getTransitionMatrix().getRowGroupIndices(); } template uint_fast64_t NondeterministicModel::getNumberOfChoices(uint_fast64_t state) const { auto indices = this->getNondeterministicChoiceIndices(); return indices[state+1] - indices[state]; } template void NondeterministicModel::reduceToStateBasedRewards() { for (auto& rewardModel : this->getRewardModels()) { rewardModel.second.reduceToStateBasedRewards(this->getTransitionMatrix(), false); } } template std::shared_ptr> NondeterministicModel::applyScheduler(storm::storage::Scheduler const& scheduler, bool dropUnreachableStates) const { storm::storage::SparseModelMemoryProduct memoryProduct(*this, scheduler); if (!dropUnreachableStates) { memoryProduct.setBuildFullProduct(); } return memoryProduct.build(); } template void NondeterministicModel::printModelInformationToStream(std::ostream& out) const { this->printModelInformationHeaderToStream(out); out << "Choices: \t" << this->getNumberOfChoices() << std::endl; this->printModelInformationFooterToStream(out); } template void NondeterministicModel::writeDotToStream(std::ostream& outStream, bool includeLabeling, storm::storage::BitVector const* subsystem, std::vector const* firstValue, std::vector const* secondValue, std::vector const* stateColoring, std::vector const* colors, std::vector* scheduler, bool finalizeOutput) const { Model::writeDotToStream(outStream, includeLabeling, subsystem, firstValue, secondValue, stateColoring, colors, scheduler, false); // Write the probability distributions for all the states. for (uint_fast64_t state = 0; state < this->getNumberOfStates(); ++state) { uint_fast64_t rowCount = this->getNondeterministicChoiceIndices()[state + 1] - this->getNondeterministicChoiceIndices()[state]; bool highlightChoice = true; // For this, we need to iterate over all available nondeterministic choices in the current state. for (uint_fast64_t choice = 0; choice < rowCount; ++choice) { uint_fast64_t rowIndex = this->getNondeterministicChoiceIndices()[state] + choice; typename storm::storage::SparseMatrix::const_rows row = this->getTransitionMatrix().getRow(rowIndex); if (scheduler != nullptr) { // If the scheduler picked the current choice, we will not make it dotted, but highlight it. if ((*scheduler)[state] == choice) { highlightChoice = true; } else { highlightChoice = false; } } // For each nondeterministic choice, we draw an arrow to an intermediate node to better display // the grouping of transitions. // The intermediate node: outStream << "\t\"" << state << "c" << choice << "\" [shape = \"point\""; // If we were given a scheduler to highlight, we do so now. if (scheduler != nullptr) { if (highlightChoice) { outStream << ", fillcolor=\"red\""; } } outStream << "];" << std::endl; // The arrow to the intermediate node: outStream << "\t" << state << " -> \"" << state << "c" << choice << "\""; bool arrowHasLabel = false; if (this->isOfType(ModelType::MarkovAutomaton)) { // If this is a Markov automaton, we have to check whether the current choice is a Markovian choice and correspondingly print the exit rate MarkovAutomaton const* ma = dynamic_cast const*>(this); if (ma->isMarkovianState(state) && choice == 0) { arrowHasLabel = true; outStream << " [ label = \"" << ma->getExitRate(state); } } if (this->hasChoiceLabeling()) { if (arrowHasLabel) { outStream << " | {"; } else { outStream << " [ label = \"{"; } arrowHasLabel = true; bool firstLabel = true; for (auto const& label : this->getChoiceLabeling().getLabelsOfChoice(rowIndex)) { if (!firstLabel) { outStream << ", "; } firstLabel = false; outStream << label; } outStream << "}"; } if (arrowHasLabel) { outStream << "\""; } // If we were given a scheduler to highlight, we do so now. if (scheduler != nullptr) { if (arrowHasLabel) { outStream << ", "; } else { outStream << "[ "; } if (highlightChoice) { outStream << "color=\"red\", penwidth = 2"; } else { outStream << "style = \"dotted\""; } } if (arrowHasLabel || scheduler != nullptr) { outStream << "]" << std::endl; } outStream << ";" << std::endl; // Now draw all probabilitic arcs that belong to this nondeterminstic choice. for (auto const& transition : row) { if (subsystem == nullptr || subsystem->get(transition.getColumn())) { outStream << "\t\"" << state << "c" << choice << "\" -> " << transition.getColumn() << " [ label= \"" << transition.getValue() << "\" ]"; // If we were given a scheduler to highlight, we do so now. if (scheduler != nullptr) { if (highlightChoice) { outStream << " [color=\"red\", penwidth = 2]"; } else { outStream << " [style = \"dotted\"]"; } } outStream << ";" << std::endl; } } } } if (finalizeOutput) { outStream << "}" << std::endl; } } template uint_least64_t NondeterministicModel::getChoiceIndex(storm::storage::StateActionPair const& stateactPair) const { return this->getNondeterministicChoiceIndices()[stateactPair.getState()]+stateactPair.getAction(); } template class NondeterministicModel; #ifdef STORM_HAVE_CARL template class NondeterministicModel; template class NondeterministicModel>; template class NondeterministicModel; #endif } } }