From 82023d280d50947bf74c2d63a2cbae64e9a49ae5 Mon Sep 17 00:00:00 2001 From: dehnert <dehnert@cs.rwth-aachen.de> Date: Fri, 3 Jun 2016 15:09:52 +0200 Subject: [PATCH] JANI model builder for MDPs is working now, but too slow Former-commit-id: 8b36f65251bed031701fe51760ce6350afd37c0f --- src/builder/DdJaniModelBuilder.cpp | 298 ++++++++++++------ src/builder/DdPrismModelBuilder.cpp | 8 +- src/models/symbolic/NondeterministicModel.cpp | 6 +- src/storage/dd/Dd.h | 16 +- .../builder/DdJaniModelBuilderTest.cpp | 4 +- .../builder/DdPrismModelBuilderTest.cpp | 2 - 6 files changed, 212 insertions(+), 122 deletions(-) diff --git a/src/builder/DdJaniModelBuilder.cpp b/src/builder/DdJaniModelBuilder.cpp index d76da2f74..51fe6f36f 100644 --- a/src/builder/DdJaniModelBuilder.cpp +++ b/src/builder/DdJaniModelBuilder.cpp @@ -26,6 +26,7 @@ #include "src/utility/macros.h" #include "src/utility/jani.h" #include "src/utility/dd.h" +#include "src/utility/math.h" #include "src/exceptions/InvalidArgumentException.h" namespace storm { @@ -161,7 +162,7 @@ namespace storm { // All pairs of row/column meta variables. std::vector<std::pair<storm::expressions::Variable, storm::expressions::Variable>> rowColumnMetaVariablePairs; - + // A mapping from automata to the meta variable encoding their location. std::map<std::string, std::pair<storm::expressions::Variable, storm::expressions::Variable>> automatonToLocationVariableMap; @@ -170,7 +171,7 @@ namespace storm { // The meta variables used to encode the remaining nondeterminism. std::vector<storm::expressions::Variable> localNondeterminismVariables; - + // The meta variables used to encode the actions and nondeterminism. std::set<storm::expressions::Variable> allNondeterminismVariables; @@ -236,16 +237,6 @@ namespace storm { CompositionVariables<Type, ValueType> createVariables() { CompositionVariables<Type, ValueType> result; - for (auto const& automaton : this->model.getAutomata()) { - // Start by creating a meta variable for the location of the automaton. - std::pair<storm::expressions::Variable, storm::expressions::Variable> variablePair = result.manager->addMetaVariable("l_" + automaton.getName(), 0, automaton.getNumberOfLocations() - 1); - result.automatonToLocationVariableMap[automaton.getName()] = variablePair; - - // Add the location variable to the row/column variables. - result.rowMetaVariables.insert(variablePair.first); - result.columnMetaVariables.insert(variablePair.second); - } - for (auto const& action : this->model.getActions()) { if (this->model.getActionIndex(action.getName()) != this->model.getSilentActionIndex()) { std::pair<storm::expressions::Variable, storm::expressions::Variable> variablePair = result.manager->addMetaVariable(action.getName()); @@ -265,6 +256,16 @@ namespace storm { result.allNondeterminismVariables.insert(variablePair.first); } + for (auto const& automaton : this->model.getAutomata()) { + // Start by creating a meta variable for the location of the automaton. + std::pair<storm::expressions::Variable, storm::expressions::Variable> variablePair = result.manager->addMetaVariable("l_" + automaton.getName(), 0, automaton.getNumberOfLocations() - 1); + result.automatonToLocationVariableMap[automaton.getName()] = variablePair; + + // Add the location variable to the row/column variables. + result.rowMetaVariables.insert(variablePair.first); + result.columnMetaVariables.insert(variablePair.second); + } + // Create global variables. storm::dd::Bdd<Type> globalVariableRanges = result.manager->getBddOne(); for (auto const& variable : this->model.getGlobalVariables()) { @@ -272,7 +273,7 @@ namespace storm { globalVariableRanges &= result.manager->getRange(result.variableToRowMetaVariableMap->at(variable.getExpressionVariable())); } result.globalVariableRanges = globalVariableRanges.template toAdd<ValueType>(); - + // Create the variables for the individual automata. for (auto const& automaton : this->model.getAutomata()) { storm::dd::Bdd<Type> identity = result.manager->getBddOne(); @@ -408,13 +409,14 @@ namespace storm { template <storm::dd::DdType Type, typename ValueType> EdgeDd<Type, ValueType> composeEdgesInParallel(EdgeDd<Type, ValueType> const& edge1, EdgeDd<Type, ValueType> const& edge2) { EdgeDd<Type, ValueType> result; - + // Compose the guards. result.guardDd = edge1.guardDd * edge2.guardDd; // If the composed guard is already zero, we can immediately return an empty result. if (result.guardDd.isZero()) { result.transitionsDd = edge1.transitionsDd.getDdManager().template getAddZero<ValueType>(); + return result; } // Compute the set of variables written multiple times by the composition. @@ -571,7 +573,7 @@ namespace storm { // Combine the update expression with the guard. storm::dd::Add<Type, ValueType> result = updateExpression * guard; - + // Combine the variable and the assigned expression. result = result.equals(writtenVariable).template toAdd<ValueType>(); result *= guard; @@ -654,7 +656,7 @@ namespace storm { // Add the source location and the guard. transitionsDd *= variables.manager->getEncoding(variables.automatonToLocationVariableMap.at(automaton.getName()).first, edge.getSourceLocationId()).template toAdd<ValueType>() * guard; - + // If we multiply the ranges of global variables, make sure everything stays within its bounds. if (!globalVariablesInSomeUpdate.empty()) { transitionsDd *= variables.globalVariableRanges; @@ -697,18 +699,14 @@ namespace storm { }; template <storm::dd::DdType Type, typename ValueType> - storm::dd::Add<Type, ValueType> encodeAction(boost::optional<uint64_t> trueIndex, std::vector<storm::expressions::Variable> const& actionVariables, CompositionVariables<Type, ValueType> const& variables) { + storm::dd::Add<Type, ValueType> encodeAction(boost::optional<uint64_t> const& actionIndex, CompositionVariables<Type, ValueType> const& variables) { storm::dd::Add<Type, ValueType> encoding = variables.manager->template getAddOne<ValueType>(); - - if (trueIndex) { - *trueIndex = actionVariables.size() - (*trueIndex + 1); - } - uint64_t index = 0; - for (auto it = actionVariables.rbegin(), ite = actionVariables.rend(); it != ite; ++it, ++index) { - if (trueIndex && index == trueIndex) { - encoding *= variables.manager->getEncoding(*it, 1).template toAdd<ValueType>(); + + for (auto it = variables.actionVariablesMap.rbegin(), ite = variables.actionVariablesMap.rend(); it != ite; ++it) { + if (actionIndex && it->first == actionIndex.get()) { + encoding *= variables.manager->getEncoding(it->second, 1).template toAdd<ValueType>(); } else { - encoding *= variables.manager->getEncoding(*it, 0).template toAdd<ValueType>(); + encoding *= variables.manager->getEncoding(it->second, 0).template toAdd<ValueType>(); } } @@ -727,17 +725,15 @@ namespace storm { } template <storm::dd::DdType Type, typename ValueType> - storm::dd::Add<Type, ValueType> encodeIndex(uint64_t index, std::vector<storm::expressions::Variable> const& localNondeterminismVariables, CompositionVariables<Type, ValueType> const& variables) { + storm::dd::Add<Type, ValueType> encodeIndex(uint64_t index, uint64_t localNondeterminismVariableOffset, uint64_t numberOfLocalNondeterminismVariables, CompositionVariables<Type, ValueType> const& variables) { storm::dd::Add<Type, ValueType> result = variables.manager->template getAddZero<ValueType>(); - STORM_LOG_TRACE("Encoding " << index << " with " << localNondeterminismVariables.size() << " binary variable(s)."); - std::map<storm::expressions::Variable, int_fast64_t> metaVariableNameToValueMap; - for (uint_fast64_t i = 0; i < localNondeterminismVariables.size(); ++i) { - if (index & (1ull << (localNondeterminismVariables.size() - i - 1))) { - metaVariableNameToValueMap.emplace(localNondeterminismVariables[i], 1); + for (uint_fast64_t i = 0; i < numberOfLocalNondeterminismVariables; ++i) { + if (index & (1ull << (numberOfLocalNondeterminismVariables - i - 1))) { + metaVariableNameToValueMap.emplace(variables.localNondeterminismVariables[localNondeterminismVariableOffset + i], 1); } else { - metaVariableNameToValueMap.emplace(localNondeterminismVariables[i], 0); + metaVariableNameToValueMap.emplace(variables.localNondeterminismVariables[localNondeterminismVariableOffset + i], 0); } } @@ -746,8 +742,8 @@ namespace storm { } template <storm::dd::DdType Type, typename ValueType> - struct SystemDd { - SystemDd(storm::dd::Add<Type, ValueType> const& transitionsDd, storm::dd::Add<Type, ValueType> const& stateActionDd, uint64_t numberOfNondeterminismVariables = 0) : transitionsDd(transitionsDd), stateActionDd(stateActionDd), numberOfNondeterminismVariables(numberOfNondeterminismVariables) { + struct BuilderResult { + BuilderResult(storm::dd::Add<Type, ValueType> const& transitionsDd, storm::dd::Add<Type, ValueType> const& stateActionDd, uint64_t numberOfNondeterminismVariables = 0) : transitionsDd(transitionsDd), stateActionDd(stateActionDd), numberOfNondeterminismVariables(numberOfNondeterminismVariables) { // Intentionally left empty. } @@ -757,66 +753,136 @@ namespace storm { }; template <storm::dd::DdType Type, typename ValueType> - SystemDd<Type, ValueType> buildSystemDd(storm::jani::Model const& model, AutomatonDd<Type, ValueType> const& automatonDd, CompositionVariables<Type, ValueType>& variables) { - // If the model is an MDP, we need to encode the nondeterminism using additional variables. - if (model.getModelType() == storm::jani::ModelType::MDP) { - // Determine how many nondeterminism variables we need. - std::vector<storm::expressions::Variable> orderedActionVariables; - std::set<storm::expressions::Variable> actionVariables; - std::map<uint64_t, boost::optional<uint64_t>> actionIndexToVariableIndex; - uint64_t maximalNumberOfEdgesPerAction = 0; - for (auto const& action : automatonDd.actionIndexToEdges) { - if (action.first != model.getSilentActionIndex()) { - orderedActionVariables.push_back(variables.actionVariablesMap.at(action.first)); - actionVariables.insert(orderedActionVariables.back()); - actionIndexToVariableIndex[action.first] = orderedActionVariables.size() - 1; - } else { - actionIndexToVariableIndex[action.first] = boost::none; - } - maximalNumberOfEdgesPerAction = std::max(maximalNumberOfEdgesPerAction, static_cast<uint64_t>(action.second.size())); - } - - // If the maximal number of edges per action is zero, which can happen if the model only has unsatisfiable guards, - // then we must not compute the number of variables. - if (maximalNumberOfEdgesPerAction == 0) { - return SystemDd<Type, ValueType>(variables.manager->template getAddZero<ValueType>(), variables.manager->template getAddZero<ValueType>(), 0); - } + storm::dd::Add<Type, ValueType> combineEdgesBySummation(std::vector<EdgeDd<Type, ValueType>> const& edges, CompositionVariables<Type, ValueType> const& variables) { + storm::dd::Add<Type, ValueType> result = variables.manager->template getAddZero<ValueType>(); + for (auto const& edge : edges) { + // Simply add all actions, but make sure to include the missing global variable identities. + result += edge.transitionsDd * computeMissingGlobalVariableIdentities(edge, variables); + } + return result; + } + + template <storm::dd::DdType Type, typename ValueType> + std::pair<uint64_t, storm::dd::Add<Type, ValueType>> combineEdgesByNondeterministicChoice(std::vector<EdgeDd<Type, ValueType>>& edges, CompositionVariables<Type, ValueType> const& variables) { + // Complete all edges by adding the missing global variable identities. + for (auto& edge : edges) { + edge.transitionsDd *= computeMissingGlobalVariableIdentities(edge, variables); + } + + // Sum all guards, so we can read off the maximal number of nondeterministic choices in any given state. + storm::dd::Add<Type, ValueType> sumOfGuards = variables.manager->template getAddZero<ValueType>(); + for (auto const& edge : edges) { + sumOfGuards += edge.guardDd; + } + uint_fast64_t maxChoices = static_cast<uint_fast64_t>(sumOfGuards.getMax()); + STORM_LOG_TRACE("Found " << maxChoices << " local choices."); + + // Depending on the maximal number of nondeterminstic choices, we need to use some variables to encode the nondeterminism. + if (maxChoices == 0) { + return std::make_pair(0, variables.manager->template getAddZero<ValueType>()); + } else if (maxChoices == 1) { + return std::make_pair(0, combineEdgesBySummation(edges, variables)); + } else { + // Calculate number of required variables to encode the nondeterminism. + uint_fast64_t numberOfBinaryVariables = static_cast<uint_fast64_t>(std::ceil(storm::utility::math::log2(maxChoices))); - uint64_t numberOfNondeterminismVariables = static_cast<uint64_t>(std::ceil(std::log2(maximalNumberOfEdgesPerAction))); - std::vector<storm::expressions::Variable> localNondeterminismVariables(numberOfNondeterminismVariables); - std::copy(variables.localNondeterminismVariables.begin(), variables.localNondeterminismVariables.begin() + numberOfNondeterminismVariables, localNondeterminismVariables.begin()); + storm::dd::Add<Type, ValueType> allEdges = variables.manager->template getAddZero<ValueType>(); - // Prepare result. - storm::dd::Add<Type, ValueType> result = variables.manager->template getAddZero<ValueType>(); + storm::dd::Bdd<Type> equalsNumberOfChoicesDd; + std::vector<storm::dd::Add<Type, ValueType>> choiceDds(maxChoices, variables.manager->template getAddZero<ValueType>()); + std::vector<storm::dd::Bdd<Type>> remainingDds(maxChoices, variables.manager->getBddZero()); - // Add edges to the result. - for (auto const& action : automatonDd.actionIndexToEdges) { - storm::dd::Add<Type, ValueType> edgesForAction = variables.manager->template getAddZero<ValueType>(); + for (uint_fast64_t currentChoices = 1; currentChoices <= maxChoices; ++currentChoices) { + // Determine the set of states with exactly currentChoices choices. + equalsNumberOfChoicesDd = sumOfGuards.equals(variables.manager->getConstant(static_cast<double>(currentChoices))); + + // If there is no such state, continue with the next possible number of choices. + if (equalsNumberOfChoicesDd.isZero()) { + continue; + } - uint64_t edgeIndex = 0; - for (auto const& edge : action.second) { - storm::dd::Add<Type, ValueType> dd = edge.transitionsDd * computeMissingGlobalVariableIdentities(edge, variables) * encodeIndex(edgeIndex, localNondeterminismVariables, variables); - dd.exportToDot("add" + std::to_string(edgeIndex) + ".dot"); - edgesForAction += edge.transitionsDd * computeMissingGlobalVariableIdentities(edge, variables) * encodeIndex(edgeIndex, localNondeterminismVariables, variables); - ++edgeIndex; + // Reset the previously used intermediate storage. + for (uint_fast64_t j = 0; j < currentChoices; ++j) { + choiceDds[j] = variables.manager->template getAddZero<ValueType>(); + remainingDds[j] = equalsNumberOfChoicesDd; } - result += edgesForAction * encodeAction<Type, ValueType>(actionIndexToVariableIndex.at(action.first), orderedActionVariables, variables); + for (std::size_t j = 0; j < edges.size(); ++j) { + // Check if edge guard overlaps with equalsNumberOfChoicesDd. That is, there are states with exactly currentChoices + // choices such that one outgoing choice is given by the j-th edge. + storm::dd::Bdd<Type> guardChoicesIntersection = edges[j].guardDd.toBdd() && equalsNumberOfChoicesDd; + + // If there is no such state, continue with the next command. + if (guardChoicesIntersection.isZero()) { + continue; + } + + // Split the currentChoices nondeterministic choices. + for (uint_fast64_t k = 0; k < currentChoices; ++k) { + // Calculate the overlapping part of command guard and the remaining DD. + storm::dd::Bdd<Type> remainingGuardChoicesIntersection = guardChoicesIntersection && remainingDds[k]; + + // Check if we can add some overlapping parts to the current index. + if (!remainingGuardChoicesIntersection.isZero()) { + // Remove overlapping parts from the remaining DD. + remainingDds[k] = remainingDds[k] && !remainingGuardChoicesIntersection; + + // Combine the overlapping part of the guard with command updates and add it to the resulting DD. + choiceDds[k] += remainingGuardChoicesIntersection.template toAdd<ValueType>() * edges[j].transitionsDd; + } + + // Remove overlapping parts from the command guard DD + guardChoicesIntersection = guardChoicesIntersection && !remainingGuardChoicesIntersection; + + // If the guard DD has become equivalent to false, we can stop here. + if (guardChoicesIntersection.isZero()) { + break; + } + } + } + + // Add the meta variables that encode the nondeterminisim to the different choices. + for (uint_fast64_t j = 0; j < currentChoices; ++j) { + allEdges += encodeIndex(j, 0, numberOfBinaryVariables, variables) * choiceDds[j]; + } + + // Delete currentChoices out of overlapping DD + sumOfGuards = sumOfGuards * (!equalsNumberOfChoicesDd).template toAdd<ValueType>(); } - return SystemDd<Type, ValueType>(result, result.sumAbstract(variables.columnMetaVariables), numberOfNondeterminismVariables); + return std::make_pair(numberOfBinaryVariables, allEdges); + } + } + + template <storm::dd::DdType Type, typename ValueType> + BuilderResult<Type, ValueType> buildSystemFromSingleAutomaton(storm::jani::Model const& model, AutomatonDd<Type, ValueType>& automatonDd, CompositionVariables<Type, ValueType> const& variables) { + // If the model is an MDP, we need to encode the nondeterminism using additional variables. + if (model.getModelType() == storm::jani::ModelType::MDP) { + std::map<uint64_t, std::pair<uint64_t, storm::dd::Add<Type, ValueType>>> actionIndexToUsedVariablesAndDd; + + // Combine the edges of each action individually and keep track of how many local nondeterminism variables + // were used. + uint64_t highestNumberOfUsedNondeterminismVariables = 0; + for (auto& action : automatonDd.actionIndexToEdges) { + std::pair<uint64_t, storm::dd::Add<Type, ValueType>> usedVariablesAndDd = combineEdgesByNondeterministicChoice<Type, ValueType>(action.second, variables); + actionIndexToUsedVariablesAndDd.emplace(action.first, usedVariablesAndDd); + highestNumberOfUsedNondeterminismVariables = std::max(highestNumberOfUsedNondeterminismVariables, usedVariablesAndDd.first); + } + + storm::dd::Add<Type, ValueType> result = variables.manager->template getAddZero<ValueType>(); + for (auto const& element : actionIndexToUsedVariablesAndDd) { + result += element.second.second * encodeAction(element.first, variables) * encodeIndex(0, element.second.first, highestNumberOfUsedNondeterminismVariables - element.second.first, variables); + } + + return BuilderResult<Type, ValueType>(result, result.sumAbstract(variables.columnMetaVariables), highestNumberOfUsedNondeterminismVariables); } else if (model.getModelType() == storm::jani::ModelType::DTMC || model.getModelType() == storm::jani::ModelType::CTMC) { - // Simply add all actions, but make sure to include the missing global variable identities. storm::dd::Add<Type, ValueType> result = variables.manager->template getAddZero<ValueType>(); for (auto const& action : automatonDd.actionIndexToEdges) { - for (auto const& edge : action.second) { - result += edge.transitionsDd * computeMissingGlobalVariableIdentities(edge, variables); - } + result += combineEdgesBySummation(action.second, variables); } - - return SystemDd<Type, ValueType>(result, result.sumAbstract(variables.columnMetaVariables)); + return BuilderResult<Type, ValueType>(result, result.sumAbstract(variables.columnMetaVariables)); } - + STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Illegal model type."); } @@ -839,17 +905,31 @@ namespace storm { } else { STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Invalid model type."); } - } template <storm::dd::DdType Type, typename ValueType> - void postprocessSystemAndVariables(storm::jani::Model const& model, SystemDd<Type, ValueType>& system, CompositionVariables<Type, ValueType>& variables, typename DdJaniModelBuilder<Type, ValueType>::Options const& options) { - // Get rid of the nondeterminism variables that were not used. + void postprocessVariables(storm::jani::ModelType const& modelType, BuilderResult<Type, ValueType>& system, CompositionVariables<Type, ValueType>& variables) { + // Add all action/row/column variables to the DD. If we omitted multiplying edges in the construction, this will + // introduce the variables so they can later be abstracted without raising an error. + system.transitionsDd.addMetaVariables(variables.rowMetaVariables); + system.transitionsDd.addMetaVariables(variables.columnMetaVariables); + + // If the model is an MDP, we also add all action variables. + if (modelType == storm::jani::ModelType::MDP) { + for (auto const& actionVariablePair : variables.actionVariablesMap) { + system.transitionsDd.addMetaVariable(actionVariablePair.second); + } + } + + // Get rid of the local nondeterminism variables that were not used. for (uint64_t index = system.numberOfNondeterminismVariables; index < variables.localNondeterminismVariables.size(); ++index) { variables.allNondeterminismVariables.erase(variables.localNondeterminismVariables[index]); } variables.localNondeterminismVariables.resize(system.numberOfNondeterminismVariables); - + } + + template <storm::dd::DdType Type, typename ValueType> + void postprocessSystem(storm::jani::Model const& model, BuilderResult<Type, ValueType>& system, CompositionVariables<Type, ValueType> const& variables, typename DdJaniModelBuilder<Type, ValueType>::Options const& options) { // For DTMCs, we normalize each row to 1 (to account for non-determinism). if (model.getModelType() == storm::jani::ModelType::DTMC) { system.transitionsDd = system.transitionsDd / system.stateActionDd; @@ -933,43 +1013,61 @@ namespace storm { } } + template <storm::dd::DdType Type, typename ValueType> + class SeparateEdgesSystemBuilder { + public: + SeparateEdgesSystemBuilder(storm::jani::Model const& model, CompositionVariables<Type, ValueType> const& variables) : model(model), variables(variables) { + // Intentional + } + + BuilderResult<Type, ValueType> build() { + // Compose the automata to a single automaton. + AutomatonComposer<Type, ValueType> composer(this->model, variables); + AutomatonDd<Type, ValueType> globalAutomaton = composer.compose(); + + // Combine the edges of the single automaton to the full system DD. + return buildSystemFromSingleAutomaton<Type, ValueType>(this->model, globalAutomaton, variables); + } + + private: + storm::jani::Model const& model; + CompositionVariables<Type, ValueType> const& variables; + }; + template <storm::dd::DdType Type, typename ValueType> std::shared_ptr<storm::models::symbolic::Model<Type, ValueType>> DdJaniModelBuilder<Type, ValueType>::translate() { // Create all necessary variables. CompositionVariableCreator<Type, ValueType> variableCreator(*this->model); CompositionVariables<Type, ValueType> variables = variableCreator.create(); - // Compose the automata to a single automaton. - AutomatonComposer<Type, ValueType> composer(*this->model, variables); - AutomatonDd<Type, ValueType> globalAutomaton = composer.compose(); - - // Combine the edges of the single automaton to the full system DD. - SystemDd<Type, ValueType> system = buildSystemDd(*this->model, globalAutomaton, variables); + // Create a builder to compose and build the model. + SeparateEdgesSystemBuilder<Type, ValueType> builder(*this->model, variables); + BuilderResult<Type, ValueType> system = builder.build(); + + // Postprocess the variables in place. + postprocessVariables(this->model->getModelType(), system, variables); - // Postprocess the system. This modifies the systemDd in place. - postprocessSystemAndVariables(*this->model, system, variables, options); + // Postprocess the system in place. + postprocessSystem(*this->model, system, variables, options); // Start creating the model components. ModelComponents<Type, ValueType> modelComponents; // Build initial states. modelComponents.initialStates = computeInitialStates(*this->model, variables); - + // Perform reachability analysis to obtain reachable states. - system.transitionsDd.exportToDot("trans.dot"); - std::cout << "nnz: " << system.transitionsDd.getNonZeroCount() << std::endl; - std::cout << "size: " << system.transitionsDd.getNodeCount() << std::endl; storm::dd::Bdd<Type> transitionMatrixBdd = system.transitionsDd.notZero(); if (this->model->getModelType() == storm::jani::ModelType::MDP) { transitionMatrixBdd = transitionMatrixBdd.existsAbstract(variables.allNondeterminismVariables); } modelComponents.reachableStates = storm::utility::dd::computeReachableStates(modelComponents.initialStates, transitionMatrixBdd, variables.rowMetaVariables, variables.columnMetaVariables); - + // Cut transitions to reachable states. storm::dd::Add<Type, ValueType> reachableStatesAdd = modelComponents.reachableStates.template toAdd<ValueType>(); modelComponents.transitionMatrix = system.transitionsDd * reachableStatesAdd; system.stateActionDd *= reachableStatesAdd; - + // Fix deadlocks if existing. fixDeadlocks(this->model->getModelType(), modelComponents.transitionMatrix, transitionMatrixBdd, modelComponents.reachableStates, variables); diff --git a/src/builder/DdPrismModelBuilder.cpp b/src/builder/DdPrismModelBuilder.cpp index db2567e2c..f03ca33a4 100644 --- a/src/builder/DdPrismModelBuilder.cpp +++ b/src/builder/DdPrismModelBuilder.cpp @@ -1103,7 +1103,7 @@ namespace storm { typename DdPrismModelBuilder<Type, ValueType>::SystemResult DdPrismModelBuilder<Type, ValueType>::createSystemDecisionDiagram(GenerationInformation& generationInfo) { ModuleComposer<Type, ValueType> composer(generationInfo); ModuleDecisionDiagram system = composer.compose(generationInfo.program.specifiesSystemComposition() ? generationInfo.program.getSystemCompositionConstruct().getSystemComposition() : *generationInfo.program.getDefaultSystemComposition()); - + storm::dd::Add<Type, ValueType> result = createSystemFromModule(generationInfo, system); // Create an auxiliary DD that is used later during the construction of reward models. @@ -1324,11 +1324,7 @@ namespace storm { // Cut the transitions and rewards to the reachable fragment of the state space. storm::dd::Bdd<Type> initialStates = createInitialStatesDecisionDiagram(generationInfo); - - transitionMatrix.exportToDot("trans_prism.dot"); - std::cout << "nnz: " << transitionMatrix.getNonZeroCount() << std::endl; - std::cout << "size: " << transitionMatrix.getNodeCount() << std::endl; - + storm::dd::Bdd<Type> transitionMatrixBdd = transitionMatrix.notZero(); if (program.getModelType() == storm::prism::Program::ModelType::MDP) { transitionMatrixBdd = transitionMatrixBdd.existsAbstract(generationInfo.allNondeterminismVariables); diff --git a/src/models/symbolic/NondeterministicModel.cpp b/src/models/symbolic/NondeterministicModel.cpp index 2eac2ccf5..1ac1b5436 100644 --- a/src/models/symbolic/NondeterministicModel.cpp +++ b/src/models/symbolic/NondeterministicModel.cpp @@ -33,10 +33,10 @@ namespace storm { template<storm::dd::DdType Type, typename ValueType> uint_fast64_t NondeterministicModel<Type, ValueType>::getNumberOfChoices() const { - std::set<storm::expressions::Variable> rowAndNondeterminsmVariables; - std::set_union(this->getNondeterminismVariables().begin(), this->getNondeterminismVariables().end(), this->getRowVariables().begin(), this->getRowVariables().end(), std::inserter(rowAndNondeterminsmVariables, rowAndNondeterminsmVariables.begin())); + std::set<storm::expressions::Variable> rowAndNondeterminismVariables; + std::set_union(this->getNondeterminismVariables().begin(), this->getNondeterminismVariables().end(), this->getRowVariables().begin(), this->getRowVariables().end(), std::inserter(rowAndNondeterminismVariables, rowAndNondeterminismVariables.begin())); - storm::dd::Add<Type, uint_fast64_t> tmp = this->getTransitionMatrix().notZero().existsAbstract(this->getColumnVariables()).template toAdd<uint_fast64_t>().sumAbstract(rowAndNondeterminsmVariables); + storm::dd::Add<Type, uint_fast64_t> tmp = this->getTransitionMatrix().notZero().existsAbstract(this->getColumnVariables()).template toAdd<uint_fast64_t>().sumAbstract(rowAndNondeterminismVariables); return tmp.getValue(); } diff --git a/src/storage/dd/Dd.h b/src/storage/dd/Dd.h index 30a0c3b97..18605c259 100644 --- a/src/storage/dd/Dd.h +++ b/src/storage/dd/Dd.h @@ -109,14 +109,6 @@ namespace storm { */ std::set<storm::expressions::Variable>& getContainedMetaVariables(); - protected: - /*! - * Retrieves the (sorted) list of the variable indices of DD variables contained in this DD. - * - * @return The sorted list of variable indices. - */ - std::vector<uint_fast64_t> getSortedVariableIndices() const; - /*! * Adds the given set of meta variables to the DD. * @@ -145,6 +137,14 @@ namespace storm { */ void removeMetaVariables(std::set<storm::expressions::Variable> const& metaVariables); + protected: + /*! + * Retrieves the (sorted) list of the variable indices of DD variables contained in this DD. + * + * @return The sorted list of variable indices. + */ + std::vector<uint_fast64_t> getSortedVariableIndices() const; + /*! * Creates a DD with the given manager and meta variables. * diff --git a/test/functional/builder/DdJaniModelBuilderTest.cpp b/test/functional/builder/DdJaniModelBuilderTest.cpp index 24c372693..083beaf9e 100644 --- a/test/functional/builder/DdJaniModelBuilderTest.cpp +++ b/test/functional/builder/DdJaniModelBuilderTest.cpp @@ -270,9 +270,7 @@ TEST(DdJaniModelBuilderTest_Cudd, Mdp) { EXPECT_EQ(364ul, mdp->getNumberOfStates()); EXPECT_EQ(654ul, mdp->getNumberOfTransitions()); EXPECT_EQ(573ul, mdp->getNumberOfChoices()); - - exit(-1); - + program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/coin2-2.nm"); janiModel = program.toJani(true); builder = storm::builder::DdJaniModelBuilder<storm::dd::DdType::CUDD, double>(janiModel); diff --git a/test/functional/builder/DdPrismModelBuilderTest.cpp b/test/functional/builder/DdPrismModelBuilderTest.cpp index bfaffc1f3..fe0e00def 100644 --- a/test/functional/builder/DdPrismModelBuilderTest.cpp +++ b/test/functional/builder/DdPrismModelBuilderTest.cpp @@ -211,8 +211,6 @@ TEST(DdPrismModelBuilderTest_Cudd, Mdp) { EXPECT_EQ(654ul, mdp->getNumberOfTransitions()); EXPECT_EQ(573ul, mdp->getNumberOfChoices()); - exit(-1); - program = storm::parser::PrismParser::parse(STORM_CPP_TESTS_BASE_PATH "/functional/builder/coin2-2.nm"); model = storm::builder::DdPrismModelBuilder<storm::dd::DdType::CUDD>().translateProgram(program);