|
|
@ -221,11 +221,34 @@ namespace storm { |
|
|
|
} |
|
|
|
|
|
|
|
virtual boost::any visit(storm::prism::RenamingComposition const& composition) override { |
|
|
|
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Renaming is currently not supported in symbolic model building."); |
|
|
|
// First, we translate the subcomposition.
|
|
|
|
typename DdPrismModelBuilder<Type, ValueType>::ModuleDecisionDiagram sub = boost::any_cast<typename DdPrismModelBuilder<Type, ValueType>::ModuleDecisionDiagram>(composition.getSubcomposition().accept(*this)); |
|
|
|
|
|
|
|
// Create the mapping from action indices to action indices.
|
|
|
|
std::map<uint_fast64_t, uint_fast64_t> renaming; |
|
|
|
for (auto const& namePair : composition.getActionRenaming()) { |
|
|
|
STORM_LOG_THROW(generationInfo.program.hasAction(namePair.first), storm::exceptions::InvalidArgumentException, "Composition refers to unknown action '" << namePair.first << "'."); |
|
|
|
STORM_LOG_THROW(generationInfo.program.hasAction(namePair.second), storm::exceptions::InvalidArgumentException, "Composition refers to unknown action '" << namePair.second << "'."); |
|
|
|
renaming.emplace(generationInfo.program.getActionIndex(namePair.first), generationInfo.program.getActionIndex(namePair.second)); |
|
|
|
} |
|
|
|
|
|
|
|
// Perform the renaming and return result.
|
|
|
|
return rename(sub, renaming); |
|
|
|
} |
|
|
|
|
|
|
|
virtual boost::any visit(storm::prism::HidingComposition const& composition) override { |
|
|
|
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Hiding is currently not supported in symbolic model building."); |
|
|
|
// First, we translate the subcomposition.
|
|
|
|
typename DdPrismModelBuilder<Type, ValueType>::ModuleDecisionDiagram sub = boost::any_cast<typename DdPrismModelBuilder<Type, ValueType>::ModuleDecisionDiagram>(composition.getSubcomposition().accept(*this)); |
|
|
|
|
|
|
|
// Create the mapping from action indices to action indices.
|
|
|
|
std::set<uint_fast64_t> actionIndicesToHide; |
|
|
|
for (auto const& action : composition.getActionsToHide()) { |
|
|
|
STORM_LOG_THROW(generationInfo.program.hasAction(action), storm::exceptions::InvalidArgumentException, "Composition refers to unknown action '" << action << "'."); |
|
|
|
actionIndicesToHide.insert(generationInfo.program.getActionIndex(action)); |
|
|
|
} |
|
|
|
|
|
|
|
// Perform the hiding and return result.
|
|
|
|
return hide(sub, actionIndicesToHide); |
|
|
|
} |
|
|
|
|
|
|
|
virtual boost::any visit(storm::prism::SynchronizingParallelComposition const& composition) override { |
|
|
@ -280,16 +303,62 @@ namespace storm { |
|
|
|
|
|
|
|
private: |
|
|
|
/*!
|
|
|
|
* Composes the given modules while synchronizing over the provided action indices. As a result, the first |
|
|
|
* module is modified in place and will contain the composition after a call to this method. |
|
|
|
* Hides the actions of the given module according to the given set. As a result, the module is modified in |
|
|
|
* place. |
|
|
|
*/ |
|
|
|
void composeInParallel(typename DdPrismModelBuilder<Type, ValueType>::ModuleDecisionDiagram& left, typename DdPrismModelBuilder<Type, ValueType>::ModuleDecisionDiagram& right, std::set<uint_fast64_t> const& synchronizationActionIndices) { |
|
|
|
void hide(typename DdPrismModelBuilder<Type, ValueType>::ModuleDecisionDiagram& sub, std::set<uint_fast64_t> const& actionIndicesToHide) const { |
|
|
|
STORM_LOG_TRACE("Hiding the actions " << boost::join(actionIndicesToHide, ", ") << "."); |
|
|
|
|
|
|
|
for (auto const& action : sub.synchronizingActionToDecisionDiagramMap) { |
|
|
|
if (actionIndicesToHide.find(action) != actionIndicesToHide.end()) { |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/*!
|
|
|
|
* Renames the actions of the given module according to the given renaming. |
|
|
|
*/ |
|
|
|
typename DdPrismModelBuilder<Type, ValueType>::ModuleDecisionDiagram rename(typename DdPrismModelBuilder<Type, ValueType>::ModuleDecisionDiagram& sub, std::map<uint_fast64_t, uint_fast64_t> const& renaming) const { |
|
|
|
STORM_LOG_TRACE("Renaming actions."); |
|
|
|
uint_fast64_t numberOfUsedNondeterminismVariables = sub.numberOfUsedNondeterminismVariables; |
|
|
|
std::map<uint_fast64_t, typename DdPrismModelBuilder<Type, ValueType>::ActionDecisionDiagram> actionIndexToDdMap; |
|
|
|
|
|
|
|
std::vector<std::string> actionNames; |
|
|
|
for (auto const& actionIndex : synchronizationActionIndices) { |
|
|
|
actionNames.push_back(generationInfo.program.getActionName(actionIndex)); |
|
|
|
// Go through all action DDs with a synchronizing label and rename them if they appear in the renaming.
|
|
|
|
for (auto const& action : sub.synchronizingActionToDecisionDiagramMap) { |
|
|
|
auto renamingIt = renaming.find(action.first); |
|
|
|
if (renamingIt != renaming.end()) { |
|
|
|
// If the action is to be renamed and an action with the target index already exists, we need
|
|
|
|
// to combine the action DDs.
|
|
|
|
auto itNewActions = actionIndexToDdMap.find(renamingIt.second); |
|
|
|
if (itNewActions != actionIndexToDdMap.end()) { |
|
|
|
actionIndexToDdMap[renamingIt.second] = DdPrismModelBuilder<Type, ValueType>::combineUnsynchronizedActions(generationInfo, action.second, itNewActions->second); |
|
|
|
} else { |
|
|
|
// In this case, we can simply copy the action over.
|
|
|
|
actionIndexToDdMap[renamingIt.second] = action.second; |
|
|
|
} |
|
|
|
} else { |
|
|
|
// If the action is not to be renamed, we need to copy it over. However, if some other action
|
|
|
|
// was renamed to the very same action name before, we need to combine the transitions.
|
|
|
|
auto itNewActions = actionIndexToDdMap.find(action.first); |
|
|
|
if (itNewActions != actionIndexToDdMap.end()) { |
|
|
|
actionIndexToDdMap[action.first] = DdPrismModelBuilder<Type, ValueType>::combineUnsynchronizedActions(generationInfo, action.second, itNewActions->second); |
|
|
|
} else { |
|
|
|
// In this case, we can simply copy the action over.
|
|
|
|
actionIndexToDdMap[action.first] = action.second; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
STORM_LOG_TRACE("Composing two modules over the actions '" << boost::join(actionNames, ", ") << "'."); |
|
|
|
|
|
|
|
return ModuleDecisionDiagram(sub.independentAction, actionIndexToDdMap, sub.identity, numberOfUsedNondeterminismVariables); |
|
|
|
} |
|
|
|
|
|
|
|
/*!
|
|
|
|
* Composes the given modules while synchronizing over the provided action indices. As a result, the first |
|
|
|
* module is modified in place and will contain the composition after a call to this method. |
|
|
|
*/ |
|
|
|
void composeInParallel(typename DdPrismModelBuilder<Type, ValueType>::ModuleDecisionDiagram& left, typename DdPrismModelBuilder<Type, ValueType>::ModuleDecisionDiagram& right, std::set<uint_fast64_t> const& synchronizationActionIndices) const { |
|
|
|
STORM_LOG_TRACE("Composing two modules over the actions " << boost::join(synchronizationActionIndices, ", ") << "."); |
|
|
|
|
|
|
|
// Combine the tau action.
|
|
|
|
uint_fast64_t numberOfUsedNondeterminismVariables = right.independentAction.numberOfUsedNondeterminismVariables; |
|
|
@ -802,21 +871,30 @@ namespace storm { |
|
|
|
|
|
|
|
template <storm::dd::DdType Type, typename ValueType> |
|
|
|
typename DdPrismModelBuilder<Type, ValueType>::ActionDecisionDiagram DdPrismModelBuilder<Type, ValueType>::combineUnsynchronizedActions(GenerationInformation const& generationInfo, ActionDecisionDiagram& action1, ActionDecisionDiagram& action2, storm::dd::Add<Type, ValueType> const& identityDd1, storm::dd::Add<Type, ValueType> const& identityDd2) { |
|
|
|
storm::dd::Add<Type, ValueType> action1Extended = action1.transitionsDd * identityDd2; |
|
|
|
storm::dd::Add<Type, ValueType> action2Extended = action2.transitionsDd * identityDd1; |
|
|
|
|
|
|
|
// First extend the action DDs by the other identities.
|
|
|
|
STORM_LOG_TRACE("Multiplying identities to combine unsynchronized actions."); |
|
|
|
action1.transitionsDd = action1.transitionsDd * identityDd2; |
|
|
|
action2.transitionsDd = action2.transitionsDd * identityDd1; |
|
|
|
|
|
|
|
// Then combine the extended action DDs.
|
|
|
|
return combineUnsynchronizedActions(generationInfo, action1, action2); |
|
|
|
} |
|
|
|
|
|
|
|
template <storm::dd::DdType Type, typename ValueType> |
|
|
|
typename DdPrismModelBuilder<Type, ValueType>::ActionDecisionDiagram DdPrismModelBuilder<Type, ValueType>::combineUnsynchronizedActions(GenerationInformation const& generationInfo, ActionDecisionDiagram& action1, ActionDecisionDiagram& action2) { |
|
|
|
STORM_LOG_TRACE("Combining unsynchronized actions."); |
|
|
|
|
|
|
|
// Make both action DDs write to the same global variables.
|
|
|
|
std::set<storm::expressions::Variable> assignedGlobalVariables = equalizeAssignedGlobalVariables(generationInfo, action1, action2); |
|
|
|
|
|
|
|
if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::DTMC || generationInfo.program.getModelType() == storm::prism::Program::ModelType::CTMC) { |
|
|
|
return ActionDecisionDiagram(action1.guardDd + action2.guardDd, action1Extended + action2Extended, assignedGlobalVariables, 0); |
|
|
|
return ActionDecisionDiagram(action1.guardDd + action2.guardDd, action1.transitionsDd + action2.transitionsDd, assignedGlobalVariables, 0); |
|
|
|
} else if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::MDP) { |
|
|
|
if (action1.transitionsDd.isZero()) { |
|
|
|
return ActionDecisionDiagram(action2.guardDd, action2Extended, assignedGlobalVariables, action2.numberOfUsedNondeterminismVariables); |
|
|
|
return ActionDecisionDiagram(action2.guardDd, action2.transitionsDd, assignedGlobalVariables, action2.numberOfUsedNondeterminismVariables); |
|
|
|
} else if (action2.transitionsDd.isZero()) { |
|
|
|
return ActionDecisionDiagram(action1.guardDd, action1Extended, assignedGlobalVariables, action1.numberOfUsedNondeterminismVariables); |
|
|
|
return ActionDecisionDiagram(action1.guardDd, action1.transitionsDd, assignedGlobalVariables, action1.numberOfUsedNondeterminismVariables); |
|
|
|
} |
|
|
|
|
|
|
|
// Bring both choices to the same number of variables that encode the nondeterminism.
|
|
|
@ -827,18 +905,18 @@ namespace storm { |
|
|
|
for (uint_fast64_t i = action2.numberOfUsedNondeterminismVariables; i < action1.numberOfUsedNondeterminismVariables; ++i) { |
|
|
|
nondeterminismEncoding *= generationInfo.manager->getEncoding(generationInfo.nondeterminismMetaVariables[i], 0).template toAdd<ValueType>(); |
|
|
|
} |
|
|
|
action2Extended *= nondeterminismEncoding; |
|
|
|
action2.transitionsDd *= nondeterminismEncoding; |
|
|
|
} else if (action2.numberOfUsedNondeterminismVariables > action1.numberOfUsedNondeterminismVariables) { |
|
|
|
storm::dd::Add<Type, ValueType> nondeterminismEncoding = generationInfo.manager->template getAddOne<ValueType>(); |
|
|
|
|
|
|
|
for (uint_fast64_t i = action1.numberOfUsedNondeterminismVariables; i < action2.numberOfUsedNondeterminismVariables; ++i) { |
|
|
|
nondeterminismEncoding *= generationInfo.manager->getEncoding(generationInfo.nondeterminismMetaVariables[i], 0).template toAdd<ValueType>(); |
|
|
|
} |
|
|
|
action1Extended *= nondeterminismEncoding; |
|
|
|
action1.transitionsDd *= nondeterminismEncoding; |
|
|
|
} |
|
|
|
|
|
|
|
// Add a new variable that resolves the nondeterminism between the two choices.
|
|
|
|
storm::dd::Add<Type, ValueType> combinedTransitions = generationInfo.manager->getEncoding(generationInfo.nondeterminismMetaVariables[numberOfUsedNondeterminismVariables], 1).ite(action2Extended, action1Extended); |
|
|
|
storm::dd::Add<Type, ValueType> combinedTransitions = generationInfo.manager->getEncoding(generationInfo.nondeterminismMetaVariables[numberOfUsedNondeterminismVariables], 1).ite(action2.transitionsDd, action1.transitionsDd); |
|
|
|
|
|
|
|
return ActionDecisionDiagram((action1.guardDd.toBdd() || action2.guardDd.toBdd()).template toAdd<ValueType>(), combinedTransitions, assignedGlobalVariables, numberOfUsedNondeterminismVariables + 1); |
|
|
|
} else { |
|
|
|