Browse Source

working on making model composition in PRISM work again

Former-commit-id: 080a6d80cd
tempestpy_adaptions
dehnert 9 years ago
parent
commit
ebb47aaa13
  1. 498
      src/builder/DdPrismModelBuilder.cpp
  2. 12
      src/builder/DdPrismModelBuilder.h
  3. 2
      src/storage/prism/InterleavingParallelComposition.cpp
  4. 4
      src/storage/prism/InterleavingParallelComposition.h
  5. 27
      src/storage/prism/Program.cpp
  6. 7
      src/storage/prism/Program.h
  7. 2
      src/storage/prism/RestrictedParallelComposition.cpp
  8. 2
      src/storage/prism/RestrictedParallelComposition.h
  9. 2
      src/storage/prism/SynchronizingParallelComposition.cpp
  10. 4
      src/storage/prism/SynchronizingParallelComposition.h

498
src/builder/DdPrismModelBuilder.cpp

@ -1,5 +1,7 @@
#include "src/builder/DdPrismModelBuilder.h"
#include <boost/algorithm/string/join.hpp>
#include "src/models/symbolic/Dtmc.h"
#include "src/models/symbolic/Ctmc.h"
#include "src/models/symbolic/Mdp.h"
@ -9,12 +11,13 @@
#include "src/settings/SettingsManager.h"
#include "src/exceptions/InvalidStateException.h"
#include "src/exceptions/NotSupportedException.h"
#include "src/exceptions/InvalidArgumentException.h"
#include "src/utility/prism.h"
#include "src/utility/math.h"
#include "src/storage/prism/Program.h"
#include "src/storage/prism/Compositions.h"
#include "src/storage/dd/Add.h"
#include "src/storage/dd/cudd/CuddAddIterator.h"
@ -27,107 +30,148 @@ namespace storm {
template <storm::dd::DdType Type, typename ValueType>
class DdPrismModelBuilder<Type, ValueType>::GenerationInformation {
public:
GenerationInformation(storm::prism::Program const& program) : program(program), manager(std::make_shared<storm::dd::DdManager<Type>>()), rowMetaVariables(), variableToRowMetaVariableMap(), rowExpressionAdapter(nullptr), columnMetaVariables(), variableToColumnMetaVariableMap(), columnExpressionAdapter(nullptr), rowColumnMetaVariablePairs(), nondeterminismMetaVariables(), variableToIdentityMap(), allGlobalVariables(), moduleToIdentityMap() {
// Initializes variables and identity DDs.
createMetaVariablesAndIdentities();
rowExpressionAdapter = std::shared_ptr<storm::adapters::AddExpressionAdapter<Type>>(new storm::adapters::AddExpressionAdapter<Type>(manager, variableToRowMetaVariableMap));
columnExpressionAdapter = std::shared_ptr<storm::adapters::AddExpressionAdapter<Type>>(new storm::adapters::AddExpressionAdapter<Type>(manager, variableToColumnMetaVariableMap));
}
// The program that is currently translated.
storm::prism::Program const& program;
// The manager used to build the decision diagrams.
std::shared_ptr<storm::dd::DdManager<Type>> manager;
// The meta variables for the row encoding.
std::set<storm::expressions::Variable> rowMetaVariables;
std::map<storm::expressions::Variable, storm::expressions::Variable> variableToRowMetaVariableMap;
std::shared_ptr<storm::adapters::AddExpressionAdapter<Type>> rowExpressionAdapter;
// The meta variables for the column encoding.
std::set<storm::expressions::Variable> columnMetaVariables;
std::map<storm::expressions::Variable, storm::expressions::Variable> variableToColumnMetaVariableMap;
std::shared_ptr<storm::adapters::AddExpressionAdapter<Type>> columnExpressionAdapter;
// All pairs of row/column meta variables.
std::vector<std::pair<storm::expressions::Variable, storm::expressions::Variable>> rowColumnMetaVariablePairs;
// The meta variables used to encode the nondeterminism.
std::vector<storm::expressions::Variable> nondeterminismMetaVariables;
// The meta variables used to encode the synchronization.
std::vector<storm::expressions::Variable> synchronizationMetaVariables;
public:
GenerationInformation(storm::prism::Program const& program) : program(program), manager(std::make_shared<storm::dd::DdManager<Type>>()), rowMetaVariables(), variableToRowMetaVariableMap(), rowExpressionAdapter(nullptr), columnMetaVariables(), variableToColumnMetaVariableMap(), columnExpressionAdapter(nullptr), rowColumnMetaVariablePairs(), nondeterminismMetaVariables(), variableToIdentityMap(), allGlobalVariables(), moduleToIdentityMap() {
// Initializes variables and identity DDs.
createMetaVariablesAndIdentities();
// A set of all variables used for encoding the nondeterminism (i.e. nondetermism + synchronization
// variables). This is handy to abstract from this variable set.
std::set<storm::expressions::Variable> allNondeterminismVariables;
rowExpressionAdapter = std::shared_ptr<storm::adapters::AddExpressionAdapter<Type>>(new storm::adapters::AddExpressionAdapter<Type>(manager, variableToRowMetaVariableMap));
columnExpressionAdapter = std::shared_ptr<storm::adapters::AddExpressionAdapter<Type>>(new storm::adapters::AddExpressionAdapter<Type>(manager, variableToColumnMetaVariableMap));
}
// The program that is currently translated.
storm::prism::Program const& program;
// The manager used to build the decision diagrams.
std::shared_ptr<storm::dd::DdManager<Type>> manager;
// The meta variables for the row encoding.
std::set<storm::expressions::Variable> rowMetaVariables;
std::map<storm::expressions::Variable, storm::expressions::Variable> variableToRowMetaVariableMap;
std::shared_ptr<storm::adapters::AddExpressionAdapter<Type>> rowExpressionAdapter;
// The meta variables for the column encoding.
std::set<storm::expressions::Variable> columnMetaVariables;
std::map<storm::expressions::Variable, storm::expressions::Variable> variableToColumnMetaVariableMap;
std::shared_ptr<storm::adapters::AddExpressionAdapter<Type>> columnExpressionAdapter;
// All pairs of row/column meta variables.
std::vector<std::pair<storm::expressions::Variable, storm::expressions::Variable>> rowColumnMetaVariablePairs;
// The meta variables used to encode the nondeterminism.
std::vector<storm::expressions::Variable> nondeterminismMetaVariables;
// The meta variables used to encode the synchronization.
std::vector<storm::expressions::Variable> synchronizationMetaVariables;
// A set of all variables used for encoding the nondeterminism (i.e. nondetermism + synchronization
// variables). This is handy to abstract from this variable set.
std::set<storm::expressions::Variable> allNondeterminismVariables;
// As set of all variables used for encoding the synchronization.
std::set<storm::expressions::Variable> allSynchronizationMetaVariables;
// As set of all variables used for encoding the synchronization.
std::set<storm::expressions::Variable> allSynchronizationMetaVariables;
// DDs representing the identity for each variable.
std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> variableToIdentityMap;
// DDs representing the identity for each variable.
std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> variableToIdentityMap;
// A set of all meta variables that correspond to global variables.
std::set<storm::expressions::Variable> allGlobalVariables;
// A set of all meta variables that correspond to global variables.
std::set<storm::expressions::Variable> allGlobalVariables;
// DDs representing the identity for each module.
std::map<std::string, storm::dd::Add<Type, ValueType>> moduleToIdentityMap;
// DDs representing the identity for each module.
std::map<std::string, storm::dd::Add<Type, ValueType>> moduleToIdentityMap;
// DDs representing the valid ranges of the variables of each module.
std::map<std::string, storm::dd::Add<Type, ValueType>> moduleToRangeMap;
private:
/*!
* Creates the required meta variables and variable/module identities.
*/
void createMetaVariablesAndIdentities() {
// Add synchronization variables.
for (auto const& actionIndex : program.getSynchronizingActionIndices()) {
std::pair<storm::expressions::Variable, storm::expressions::Variable> variablePair = manager->addMetaVariable(program.getActionName(actionIndex));
synchronizationMetaVariables.push_back(variablePair.first);
allSynchronizationMetaVariables.insert(variablePair.first);
allNondeterminismVariables.insert(variablePair.first);
}
// DDs representing the valid ranges of the variables of each module.
std::map<std::string, storm::dd::Add<Type, ValueType>> moduleToRangeMap;
// Add nondeterminism variables (number of modules + number of commands).
uint_fast64_t numberOfNondeterminismVariables = program.getModules().size();
for (auto const& module : program.getModules()) {
numberOfNondeterminismVariables += module.getNumberOfCommands();
}
for (uint_fast64_t i = 0; i < numberOfNondeterminismVariables; ++i) {
std::pair<storm::expressions::Variable, storm::expressions::Variable> variablePair = manager->addMetaVariable("nondet" + std::to_string(i));
nondeterminismMetaVariables.push_back(variablePair.first);
allNondeterminismVariables.insert(variablePair.first);
}
private:
/*!
* Creates the required meta variables and variable/module identities.
*/
void createMetaVariablesAndIdentities() {
// Add synchronization variables.
for (auto const& actionIndex : program.getSynchronizingActionIndices()) {
std::pair<storm::expressions::Variable, storm::expressions::Variable> variablePair = manager->addMetaVariable(program.getActionName(actionIndex));
synchronizationMetaVariables.push_back(variablePair.first);
allSynchronizationMetaVariables.insert(variablePair.first);
allNondeterminismVariables.insert(variablePair.first);
}
// Create meta variables for global program variables.
for (storm::prism::IntegerVariable const& integerVariable : program.getGlobalIntegerVariables()) {
int_fast64_t low = integerVariable.getLowerBoundExpression().evaluateAsInt();
int_fast64_t high = integerVariable.getUpperBoundExpression().evaluateAsInt();
std::pair<storm::expressions::Variable, storm::expressions::Variable> variablePair = manager->addMetaVariable(integerVariable.getName(), low, high);
// Add nondeterminism variables (number of modules + number of commands).
uint_fast64_t numberOfNondeterminismVariables = program.getModules().size();
for (auto const& module : program.getModules()) {
numberOfNondeterminismVariables += module.getNumberOfCommands();
}
for (uint_fast64_t i = 0; i < numberOfNondeterminismVariables; ++i) {
std::pair<storm::expressions::Variable, storm::expressions::Variable> variablePair = manager->addMetaVariable("nondet" + std::to_string(i));
nondeterminismMetaVariables.push_back(variablePair.first);
allNondeterminismVariables.insert(variablePair.first);
}
STORM_LOG_TRACE("Created meta variables for global integer variable: " << variablePair.first.getName() << "[" << variablePair.first.getIndex() << "] and " << variablePair.second.getName() << "[" << variablePair.second.getIndex() << "]");
rowMetaVariables.insert(variablePair.first);
variableToRowMetaVariableMap.emplace(integerVariable.getExpressionVariable(), variablePair.first);
columnMetaVariables.insert(variablePair.second);
variableToColumnMetaVariableMap.emplace(integerVariable.getExpressionVariable(), variablePair.second);
// Create meta variables for global program variables.
for (storm::prism::IntegerVariable const& integerVariable : program.getGlobalIntegerVariables()) {
storm::dd::Add<Type, ValueType> variableIdentity = manager->template getIdentity<ValueType>(variablePair.first).equals(manager->template getIdentity<ValueType>(variablePair.second)).template toAdd<ValueType>() * manager->getRange(variablePair.first).template toAdd<ValueType>() * manager->getRange(variablePair.second).template toAdd<ValueType>();
variableToIdentityMap.emplace(integerVariable.getExpressionVariable(), variableIdentity);
rowColumnMetaVariablePairs.push_back(variablePair);
allGlobalVariables.insert(integerVariable.getExpressionVariable());
}
for (storm::prism::BooleanVariable const& booleanVariable : program.getGlobalBooleanVariables()) {
std::pair<storm::expressions::Variable, storm::expressions::Variable> variablePair = manager->addMetaVariable(booleanVariable.getName());
STORM_LOG_TRACE("Created meta variables for global boolean variable: " << variablePair.first.getName() << "[" << variablePair.first.getIndex() << "] and " << variablePair.second.getName() << "[" << variablePair.second.getIndex() << "]");
rowMetaVariables.insert(variablePair.first);
variableToRowMetaVariableMap.emplace(booleanVariable.getExpressionVariable(), variablePair.first);
columnMetaVariables.insert(variablePair.second);
variableToColumnMetaVariableMap.emplace(booleanVariable.getExpressionVariable(), variablePair.second);
storm::dd::Add<Type, ValueType> variableIdentity = manager->template getIdentity<ValueType>(variablePair.first).equals(manager->template getIdentity<ValueType>(variablePair.second)).template toAdd<ValueType>();
variableToIdentityMap.emplace(booleanVariable.getExpressionVariable(), variableIdentity);
rowColumnMetaVariablePairs.push_back(variablePair);
allGlobalVariables.insert(booleanVariable.getExpressionVariable());
}
// Create meta variables for each of the modules' variables.
for (storm::prism::Module const& module : program.getModules()) {
storm::dd::Bdd<Type> moduleIdentity = manager->getBddOne();
storm::dd::Bdd<Type> moduleRange = manager->getBddOne();
for (storm::prism::IntegerVariable const& integerVariable : module.getIntegerVariables()) {
int_fast64_t low = integerVariable.getLowerBoundExpression().evaluateAsInt();
int_fast64_t high = integerVariable.getUpperBoundExpression().evaluateAsInt();
std::pair<storm::expressions::Variable, storm::expressions::Variable> variablePair = manager->addMetaVariable(integerVariable.getName(), low, high);
STORM_LOG_TRACE("Created meta variables for integer variable: " << variablePair.first.getName() << "[" << variablePair.first.getIndex() << "] and " << variablePair.second.getName() << "[" << variablePair.second.getIndex() << "]");
STORM_LOG_TRACE("Created meta variables for global integer variable: " << variablePair.first.getName() << "[" << variablePair.first.getIndex() << "] and " << variablePair.second.getName() << "[" << variablePair.second.getIndex() << "]");
rowMetaVariables.insert(variablePair.first);
variableToRowMetaVariableMap.emplace(integerVariable.getExpressionVariable(), variablePair.first);
columnMetaVariables.insert(variablePair.second);
variableToColumnMetaVariableMap.emplace(integerVariable.getExpressionVariable(), variablePair.second);
storm::dd::Add<Type, ValueType> variableIdentity = manager->template getIdentity<ValueType>(variablePair.first).equals(manager->template getIdentity<ValueType>(variablePair.second)).template toAdd<ValueType>() * manager->getRange(variablePair.first).template toAdd<ValueType>() * manager->getRange(variablePair.second).template toAdd<ValueType>();
variableToIdentityMap.emplace(integerVariable.getExpressionVariable(), variableIdentity);
rowColumnMetaVariablePairs.push_back(variablePair);
storm::dd::Bdd<Type> variableIdentity = manager->template getIdentity<ValueType>(variablePair.first).equals(manager->template getIdentity<ValueType>(variablePair.second)) && manager->getRange(variablePair.first) && manager->getRange(variablePair.second);
variableToIdentityMap.emplace(integerVariable.getExpressionVariable(), variableIdentity.template toAdd<ValueType>());
moduleIdentity &= variableIdentity;
moduleRange &= manager->getRange(variablePair.first);
allGlobalVariables.insert(integerVariable.getExpressionVariable());
rowColumnMetaVariablePairs.push_back(variablePair);
}
for (storm::prism::BooleanVariable const& booleanVariable : program.getGlobalBooleanVariables()) {
for (storm::prism::BooleanVariable const& booleanVariable : module.getBooleanVariables()) {
std::pair<storm::expressions::Variable, storm::expressions::Variable> variablePair = manager->addMetaVariable(booleanVariable.getName());
STORM_LOG_TRACE("Created meta variables for global boolean variable: " << variablePair.first.getName() << "[" << variablePair.first.getIndex() << "] and " << variablePair.second.getName() << "[" << variablePair.second.getIndex() << "]");
STORM_LOG_TRACE("Created meta variables for boolean variable: " << variablePair.first.getName() << "[" << variablePair.first.getIndex() << "] and " << variablePair.second.getName() << "[" << variablePair.second.getIndex() << "]");
rowMetaVariables.insert(variablePair.first);
variableToRowMetaVariableMap.emplace(booleanVariable.getExpressionVariable(), variablePair.first);
@ -135,60 +179,163 @@ namespace storm {
columnMetaVariables.insert(variablePair.second);
variableToColumnMetaVariableMap.emplace(booleanVariable.getExpressionVariable(), variablePair.second);
storm::dd::Add<Type, ValueType> variableIdentity = manager->template getIdentity<ValueType>(variablePair.first).equals(manager->template getIdentity<ValueType>(variablePair.second)).template toAdd<ValueType>();
variableToIdentityMap.emplace(booleanVariable.getExpressionVariable(), variableIdentity);
storm::dd::Bdd<Type> variableIdentity = manager->template getIdentity<ValueType>(variablePair.first).equals(manager->template getIdentity<ValueType>(variablePair.second)) && manager->getRange(variablePair.first) && manager->getRange(variablePair.second);
variableToIdentityMap.emplace(booleanVariable.getExpressionVariable(), variableIdentity.template toAdd<ValueType>());
moduleIdentity &= variableIdentity;
moduleRange &= manager->getRange(variablePair.first);
rowColumnMetaVariablePairs.push_back(variablePair);
allGlobalVariables.insert(booleanVariable.getExpressionVariable());
}
moduleToIdentityMap[module.getName()] = moduleIdentity.template toAdd<ValueType>();
moduleToRangeMap[module.getName()] = moduleRange.template toAdd<ValueType>();
}
}
};
template <storm::dd::DdType Type, typename ValueType>
class ModuleComposer : public storm::prism::CompositionVisitor {
public:
ModuleComposer(typename DdPrismModelBuilder<Type, ValueType>::GenerationInformation& generationInfo) : generationInfo(generationInfo) {
for (auto const& actionIndex : generationInfo.program.getSynchronizingActionIndices()) {
synchronizingActionToOffsetMap[actionIndex] = 0;
}
}
typename DdPrismModelBuilder<Type, ValueType>::ModuleDecisionDiagram compose(storm::prism::Composition const& composition) {
std::cout << "composing the system " << composition << std::endl;
return boost::any_cast<typename DdPrismModelBuilder<Type, ValueType>::ModuleDecisionDiagram>(composition.accept(*this));
}
virtual boost::any visit(storm::prism::ModuleComposition const& composition) override {
STORM_LOG_TRACE("Translating module '" << composition.getModuleName() << "'.");
typename DdPrismModelBuilder<Type, ValueType>::ModuleDecisionDiagram result = DdPrismModelBuilder<Type, ValueType>::createModuleDecisionDiagram(generationInfo, generationInfo.program.getModule(composition.getModuleName()), synchronizingActionToOffsetMap);
// Update the offset indices.
for (auto const& actionIndex : generationInfo.program.getSynchronizingActionIndices()) {
if (result.hasSynchronizingAction(actionIndex)) {
synchronizingActionToOffsetMap[actionIndex] = result.synchronizingActionToDecisionDiagramMap[actionIndex].numberOfUsedNondeterminismVariables;
}
}
return result;
}
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.");
}
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.");
}
virtual boost::any visit(storm::prism::SynchronizingParallelComposition const& composition) override {
// First, we translate the subcompositions.
typename DdPrismModelBuilder<Type, ValueType>::ModuleDecisionDiagram left = boost::any_cast<typename DdPrismModelBuilder<Type, ValueType>::ModuleDecisionDiagram>(composition.getLeftSubcomposition().accept(*this));
typename DdPrismModelBuilder<Type, ValueType>::ModuleDecisionDiagram right = boost::any_cast<typename DdPrismModelBuilder<Type, ValueType>::ModuleDecisionDiagram>(composition.getRightSubcomposition().accept(*this));
// Then, determine the action indices on which we need to synchronize.
std::set<uint_fast64_t> leftSynchronizationActionIndices = left.getSynchronizingActionIndices();
for (auto const& entry : leftSynchronizationActionIndices) {
std::cout << "entry 1: " << entry << std::endl;
}
std::set<uint_fast64_t> rightSynchronizationActionIndices = right.getSynchronizingActionIndices();
for (auto const& entry : rightSynchronizationActionIndices) {
std::cout << "entry 2: " << entry << std::endl;
}
std::set<uint_fast64_t> synchronizationActionIndices;
std::set_intersection(leftSynchronizationActionIndices.begin(), leftSynchronizationActionIndices.end(), rightSynchronizationActionIndices.begin(), rightSynchronizationActionIndices.end(), std::inserter(synchronizationActionIndices, synchronizationActionIndices.begin()));
// Finally, we compose the subcompositions to create the result. For this, we modify the left
// subcomposition in place and later return it.
composeInParallel(left, right, synchronizationActionIndices);
return left;
}
virtual boost::any visit(storm::prism::InterleavingParallelComposition const& composition) override {
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Interleaving is currently not supported in symbolic model building.");
}
virtual boost::any visit(storm::prism::RestrictedParallelComposition const& composition) override {
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Restricted parallel composition is currently not supported in symbolic model building.");
}
// Create meta variables for each of the modules' variables.
for (storm::prism::Module const& module : program.getModules()) {
storm::dd::Bdd<Type> moduleIdentity = manager->getBddOne();
storm::dd::Bdd<Type> moduleRange = manager->getBddOne();
for (storm::prism::IntegerVariable const& integerVariable : module.getIntegerVariables()) {
int_fast64_t low = integerVariable.getLowerBoundExpression().evaluateAsInt();
int_fast64_t high = integerVariable.getUpperBoundExpression().evaluateAsInt();
std::pair<storm::expressions::Variable, storm::expressions::Variable> variablePair = manager->addMetaVariable(integerVariable.getName(), low, high);
STORM_LOG_TRACE("Created meta variables for integer variable: " << variablePair.first.getName() << "[" << variablePair.first.getIndex() << "] and " << variablePair.second.getName() << "[" << variablePair.second.getIndex() << "]");
rowMetaVariables.insert(variablePair.first);
variableToRowMetaVariableMap.emplace(integerVariable.getExpressionVariable(), variablePair.first);
columnMetaVariables.insert(variablePair.second);
variableToColumnMetaVariableMap.emplace(integerVariable.getExpressionVariable(), variablePair.second);
storm::dd::Bdd<Type> variableIdentity = manager->template getIdentity<ValueType>(variablePair.first).equals(manager->template getIdentity<ValueType>(variablePair.second)) && manager->getRange(variablePair.first) && manager->getRange(variablePair.second);
variableToIdentityMap.emplace(integerVariable.getExpressionVariable(), variableIdentity.template toAdd<ValueType>());
moduleIdentity &= variableIdentity;
moduleRange &= manager->getRange(variablePair.first);
rowColumnMetaVariablePairs.push_back(variablePair);
}
for (storm::prism::BooleanVariable const& booleanVariable : module.getBooleanVariables()) {
std::pair<storm::expressions::Variable, storm::expressions::Variable> variablePair = manager->addMetaVariable(booleanVariable.getName());
STORM_LOG_TRACE("Created meta variables for boolean variable: " << variablePair.first.getName() << "[" << variablePair.first.getIndex() << "] and " << variablePair.second.getName() << "[" << variablePair.second.getIndex() << "]");
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.
*/
void composeInParallel(typename DdPrismModelBuilder<Type, ValueType>::ModuleDecisionDiagram& left, typename DdPrismModelBuilder<Type, ValueType>::ModuleDecisionDiagram& right, std::set<uint_fast64_t> const& synchronizationActionIndices) {
std::vector<std::string> actionNames;
for (auto const& actionIndex : synchronizationActionIndices) {
actionNames.push_back(generationInfo.program.getActionName(actionIndex));
}
STORM_LOG_TRACE("Composing two modules over the actions '" << boost::join(actionNames, ", ") << "'.");
// Combine the tau action.
uint_fast64_t numberOfUsedNondeterminismVariables = right.independentAction.numberOfUsedNondeterminismVariables;
left.independentAction = DdPrismModelBuilder<Type, ValueType>::combineUnsynchronizedActions(generationInfo, left.independentAction, right.independentAction, left.identity, right.identity);
numberOfUsedNondeterminismVariables = std::max(numberOfUsedNondeterminismVariables, left.independentAction.numberOfUsedNondeterminismVariables);
rowMetaVariables.insert(variablePair.first);
variableToRowMetaVariableMap.emplace(booleanVariable.getExpressionVariable(), variablePair.first);
columnMetaVariables.insert(variablePair.second);
variableToColumnMetaVariableMap.emplace(booleanVariable.getExpressionVariable(), variablePair.second);
storm::dd::Bdd<Type> variableIdentity = manager->template getIdentity<ValueType>(variablePair.first).equals(manager->template getIdentity<ValueType>(variablePair.second)) && manager->getRange(variablePair.first) && manager->getRange(variablePair.second);
variableToIdentityMap.emplace(booleanVariable.getExpressionVariable(), variableIdentity.template toAdd<ValueType>());
moduleIdentity &= variableIdentity;
moduleRange &= manager->getRange(variablePair.first);
// Create an empty action for the case where one of the modules does not have a certain action.
typename DdPrismModelBuilder<Type, ValueType>::ActionDecisionDiagram emptyAction(*generationInfo.manager);
rowColumnMetaVariablePairs.push_back(variablePair);
// Treat all non-tau actions of the left module.
for (auto& action : left.synchronizingActionToDecisionDiagramMap) {
// If we need to synchronize over this action index, we try to do so now.
if (synchronizationActionIndices.find(action.first) != synchronizationActionIndices.end()) {
// If we are to synchronize over an action that does not exist in the second module, the result
// is that the synchronization is the empty action.
if (right.hasSynchronizingAction(action.first)) {
action.second = emptyAction;
} else {
// Otherwise, the actions of the modules are synchronized.
action.second = DdPrismModelBuilder<Type, ValueType>::combineSynchronizingActions(generationInfo, action.second, right.synchronizingActionToDecisionDiagramMap[action.first]);
}
} else {
// If we don't synchronize over this action, we need to construct the interleaving.
// If both modules contain the action, we need to mutually multiply the other identity.
if (right.hasSynchronizingAction(action.first)) {
action.second = DdPrismModelBuilder<Type, ValueType>::combineUnsynchronizedActions(generationInfo, action.second, right.synchronizingActionToDecisionDiagramMap[action.first], left.identity, right.identity);
} else {
// If only the first module has this action, we need to use a dummy action decision diagram
// for the second module.
action.second = DdPrismModelBuilder<Type, ValueType>::combineUnsynchronizedActions(generationInfo, action.second, emptyAction, left.identity, right.identity);
}
moduleToIdentityMap[module.getName()] = moduleIdentity.template toAdd<ValueType>();
moduleToRangeMap[module.getName()] = moduleRange.template toAdd<ValueType>();
}
numberOfUsedNondeterminismVariables = std::max(numberOfUsedNondeterminismVariables, action.second.numberOfUsedNondeterminismVariables);
}
};
// Treat all non-tau actions of the right module.
for (auto const& actionIndex : right.getSynchronizingActionIndices()) {
// Here, we only need to treat actions that the first module does not have, because we have handled
// this case earlier.
if (!left.hasSynchronizingAction(actionIndex)) {
if (synchronizationActionIndices.find(actionIndex) != synchronizationActionIndices.end()) {
// If we are to synchronize over this action that does not exist in the first module, the
// result is that the synchronization is the empty action.
left.synchronizingActionToDecisionDiagramMap[actionIndex] = emptyAction;
} else {
// If only the second module has this action, we need to use a dummy action decision diagram
// for the first module.
left.synchronizingActionToDecisionDiagramMap[actionIndex] = DdPrismModelBuilder<Type, ValueType>::combineUnsynchronizedActions(generationInfo, emptyAction, right.synchronizingActionToDecisionDiagramMap[actionIndex], left.identity, right.identity);
}
}
numberOfUsedNondeterminismVariables = std::max(numberOfUsedNondeterminismVariables, left.synchronizingActionToDecisionDiagramMap[actionIndex].numberOfUsedNondeterminismVariables);
}
// Combine identity matrices.
left.identity = left.identity * right.identity;
// Keep track of the number of nondeterminism variables used.
left.numberOfUsedNondeterminismVariables = std::max(left.numberOfUsedNondeterminismVariables, numberOfUsedNondeterminismVariables);
}
typename DdPrismModelBuilder<Type, ValueType>::GenerationInformation& generationInfo;
std::map<uint_fast64_t, uint_fast64_t> synchronizingActionToOffsetMap;
};
template <storm::dd::DdType Type, typename ValueType>
DdPrismModelBuilder<Type, ValueType>::Options::Options() : buildAllRewardModels(true), rewardModelsToBuild(), constantDefinitions(), buildAllLabels(true), labelsToBuild(), terminalStates(), negatedTerminalStates() {
// Intentionally left empty.
@ -224,7 +371,7 @@ namespace storm {
if (negatedTerminalStates) {
negatedTerminalStates.reset();
}
// If we are not required to build all reward models, we determine the reward models we need to build.
if (!buildAllRewardModels) {
std::set<std::string> referencedRewardModels = formula.getReferencedRewardModels();
@ -369,7 +516,7 @@ namespace storm {
STORM_LOG_WARN_COND(!updateResults.back().updateDd.isZero(), "Update '" << update << "' does not have any effect.");
}
// Start by gathering all variables that were written in at least one update.
std::set<storm::expressions::Variable> globalVariablesInSomeUpdate;
@ -386,7 +533,7 @@ namespace storm {
for (auto& updateResult : updateResults) {
std::set<storm::expressions::Variable> missingIdentities;
std::set_difference(globalVariablesInSomeUpdate.begin(), globalVariablesInSomeUpdate.end(), updateResult.assignedGlobalVariables.begin(), updateResult.assignedGlobalVariables.end(), std::inserter(missingIdentities, missingIdentities.begin()));
for (auto const& variable : missingIdentities) {
STORM_LOG_TRACE("Multiplying identity for variable " << variable.getName() << "[" << variable.getIndex() << "] to update.");
updateResult.updateDd *= generationInfo.variableToIdentityMap.at(variable);
@ -448,7 +595,7 @@ namespace storm {
// Start by gathering all variables that were written in at least one action DD.
std::set<storm::expressions::Variable> globalVariablesInActionDd;
std::set_union(action1.assignedGlobalVariables.begin(), action1.assignedGlobalVariables.end(), action2.assignedGlobalVariables.begin(), action2.assignedGlobalVariables.end(), std::inserter(globalVariablesInActionDd, globalVariablesInActionDd.begin()));
std::set<storm::expressions::Variable> missingIdentitiesInAction1;
std::set_difference(globalVariablesInActionDd.begin(), globalVariablesInActionDd.end(), action1.assignedGlobalVariables.begin(), action1.assignedGlobalVariables.end(), std::inserter(missingIdentitiesInAction1, missingIdentitiesInAction1.begin()));
for (auto const& variable : missingIdentitiesInAction1) {
@ -460,7 +607,7 @@ namespace storm {
for (auto const& variable : missingIdentitiesInAction2) {
action2.transitionsDd *= generationInfo.variableToIdentityMap.at(variable);
}
return globalVariablesInActionDd;
}
@ -473,7 +620,7 @@ namespace storm {
}
STORM_LOG_TRACE("Equalizing assigned global variables.");
// Then multiply the transitions of each action with the missing identities.
for (auto& actionDd : actionDds) {
STORM_LOG_TRACE("Equalizing next action.");
@ -545,7 +692,7 @@ namespace storm {
allGuards |= commandDd.guardDd.toBdd();
}
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.
@ -626,7 +773,7 @@ namespace storm {
return ActionDecisionDiagram(allGuards.template toAdd<ValueType>(), allCommands, assignedGlobalVariables, nondeterminismVariableOffset + numberOfBinaryVariables);
}
}
template <storm::dd::DdType Type, typename ValueType>
typename DdPrismModelBuilder<Type, ValueType>::ActionDecisionDiagram DdPrismModelBuilder<Type, ValueType>::combineSynchronizingActions(GenerationInformation const& generationInfo, ActionDecisionDiagram const& action1, ActionDecisionDiagram const& action2) {
std::set<storm::expressions::Variable> assignedGlobalVariables;
@ -638,7 +785,7 @@ namespace storm {
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;
STORM_LOG_TRACE("Combining unsynchronized actions.");
// Make both action DDs write to the same global variables.
@ -679,7 +826,7 @@ namespace storm {
STORM_LOG_THROW(false, storm::exceptions::InvalidStateException, "Illegal model type.");
}
}
template <storm::dd::DdType Type, typename ValueType>
typename DdPrismModelBuilder<Type, ValueType>::ModuleDecisionDiagram DdPrismModelBuilder<Type, ValueType>::createModuleDecisionDiagram(GenerationInformation& generationInfo, storm::prism::Module const& module, std::map<uint_fast64_t, uint_fast64_t> const& synchronizingActionToOffsetMap) {
// Start by creating the action DD for the independent action.
@ -726,7 +873,7 @@ namespace storm {
// First, determine the highest number of nondeterminism variables that is used in any action and make
// all actions use the same amout of nondeterminism variables.
uint_fast64_t numberOfUsedNondeterminismVariables = module.numberOfUsedNondeterminismVariables;
// Compute missing global variable identities in independent action.
std::set<storm::expressions::Variable> missingIdentities;
std::set_difference(generationInfo.allGlobalVariables.begin(), generationInfo.allGlobalVariables.end(), module.independentAction.assignedGlobalVariables.begin(), module.independentAction.assignedGlobalVariables.end(), std::inserter(missingIdentities, missingIdentities.begin()));
@ -742,7 +889,7 @@ namespace storm {
nondeterminismEncoding *= generationInfo.manager->getEncoding(generationInfo.nondeterminismMetaVariables[i], 0).template toAdd<ValueType>();
}
result = identityEncoding * module.independentAction.transitionsDd * nondeterminismEncoding;
// Add variables to synchronized action DDs.
std::map<uint_fast64_t, storm::dd::Add<Type, ValueType>> synchronizingActionToDdMap;
for (auto const& synchronizingAction : module.synchronizingActionToDecisionDiagramMap) {
@ -773,7 +920,7 @@ namespace storm {
for (auto const& synchronizingAction : synchronizingActionToDdMap) {
result += synchronizingAction.second;
}
return result;
} else if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::DTMC || generationInfo.program.getModelType() == storm::prism::Program::ModelType::CTMC) {
// Simply add all actions.
@ -789,67 +936,14 @@ namespace storm {
template <storm::dd::DdType Type, typename ValueType>
typename DdPrismModelBuilder<Type, ValueType>::SystemResult DdPrismModelBuilder<Type, ValueType>::createSystemDecisionDiagram(GenerationInformation& generationInfo) {
// Create the initial offset mapping.
std::map<uint_fast64_t, uint_fast64_t> synchronizingActionToOffsetMap;
for (auto const& actionIndex : generationInfo.program.getSynchronizingActionIndices()) {
synchronizingActionToOffsetMap[actionIndex] = 0;
}
// Start by creating DDs for the first module.
STORM_LOG_TRACE("Translating (first) module '" << generationInfo.program.getModule(0).getName() << "'.");
ModuleDecisionDiagram system = createModuleDecisionDiagram(generationInfo, generationInfo.program.getModule(0), synchronizingActionToOffsetMap);
// Now translate module by module and combine it with the system created thus far.
for (uint_fast64_t i = 1; i < generationInfo.program.getNumberOfModules(); ++i) {
storm::prism::Module const& currentModule = generationInfo.program.getModule(i);
STORM_LOG_TRACE("Translating module '" << currentModule.getName() << "'.");
// Update the offset index.
for (auto const& actionIndex : generationInfo.program.getSynchronizingActionIndices()) {
if (system.hasSynchronizingAction(actionIndex)) {
synchronizingActionToOffsetMap[actionIndex] = system.synchronizingActionToDecisionDiagramMap[actionIndex].numberOfUsedNondeterminismVariables;
}
}
ModuleDecisionDiagram currentModuleDd = createModuleDecisionDiagram(generationInfo, currentModule, synchronizingActionToOffsetMap);
// Combine the non-synchronizing action.
uint_fast64_t numberOfUsedNondeterminismVariables = currentModuleDd.numberOfUsedNondeterminismVariables;
system.independentAction = combineUnsynchronizedActions(generationInfo, system.independentAction, currentModuleDd.independentAction, system.identity, currentModuleDd.identity);
numberOfUsedNondeterminismVariables = std::max(numberOfUsedNondeterminismVariables, system.independentAction.numberOfUsedNondeterminismVariables);
ActionDecisionDiagram emptyAction(*generationInfo.manager);
// For all synchronizing actions that the next module does not have, we need to multiply the identity of the next module.
for (auto& action : system.synchronizingActionToDecisionDiagramMap) {
if (!currentModuleDd.hasSynchronizingAction(action.first)) {
action.second = combineUnsynchronizedActions(generationInfo, action.second, emptyAction, system.identity, currentModuleDd.identity);
}
}
// Combine synchronizing actions.
for (auto const& actionIndex : currentModule.getSynchronizingActionIndices()) {
if (system.hasSynchronizingAction(actionIndex)) {
system.synchronizingActionToDecisionDiagramMap[actionIndex] = combineSynchronizingActions(generationInfo, system.synchronizingActionToDecisionDiagramMap[actionIndex], currentModuleDd.synchronizingActionToDecisionDiagramMap[actionIndex]);
numberOfUsedNondeterminismVariables = std::max(numberOfUsedNondeterminismVariables, system.synchronizingActionToDecisionDiagramMap[actionIndex].numberOfUsedNondeterminismVariables);
} else {
system.synchronizingActionToDecisionDiagramMap[actionIndex] = combineUnsynchronizedActions(generationInfo, emptyAction, currentModuleDd.synchronizingActionToDecisionDiagramMap[actionIndex], system.identity, currentModuleDd.identity);
numberOfUsedNondeterminismVariables = std::max(numberOfUsedNondeterminismVariables, system.synchronizingActionToDecisionDiagramMap[actionIndex].numberOfUsedNondeterminismVariables);
}
}
// Combine identity matrices.
system.identity = system.identity * currentModuleDd.identity;
// Keep track of the number of nondeterminism variables used.
system.numberOfUsedNondeterminismVariables = std::max(system.numberOfUsedNondeterminismVariables, numberOfUsedNondeterminismVariables);
}
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.
storm::dd::Add<Type, ValueType> stateActionDd = result.sumAbstract(generationInfo.columnMetaVariables);
// For DTMCs, we normalize each row to 1 (to account for non-determinism).
if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::DTMC) {
result = result / stateActionDd;
@ -892,7 +986,7 @@ namespace storm {
// Next, build the state-action reward vector.
boost::optional<storm::dd::Add<Type, ValueType>> stateActionRewards;
if (rewardModel.hasStateActionRewards()) {
stateActionRewards = generationInfo.manager->template getAddZero<ValueType>();
stateActionRewards = generationInfo.manager->template getAddZero<ValueType>();
for (auto const& stateActionReward : rewardModel.getStateActionRewards()) {
storm::dd::Add<Type, ValueType> states = generationInfo.rowExpressionAdapter->translateExpression(stateActionReward.getStatePredicateExpression());
@ -980,7 +1074,7 @@ namespace storm {
return storm::models::symbolic::StandardRewardModel<Type, double>(stateRewards, stateActionRewards, transitionRewards);
}
template <storm::dd::DdType Type, typename ValueType>
storm::prism::Program const& DdPrismModelBuilder<Type, ValueType>::getTranslatedProgram() const {
return preparedProgram.get();
@ -1017,7 +1111,7 @@ namespace storm {
// Start by initializing the structure used for storing all information needed during the model generation.
// In particular, this creates the meta variables used to encode the model.
GenerationInformation generationInfo(*preparedProgram);
SystemResult system = createSystemDecisionDiagram(generationInfo);
storm::dd::Add<Type, ValueType> transitionMatrix = system.allTransitionsDd;
@ -1037,7 +1131,7 @@ namespace storm {
std::string const& labelName = boost::get<std::string>(options.terminalStates.get());
terminalExpression = preparedProgram->getLabelExpression(labelName);
}
// If the expression refers to constants of the model, we need to substitute them.
terminalExpression = terminalExpression.substitute(constantsSubstitution);
@ -1078,7 +1172,7 @@ namespace storm {
// Detect deadlocks and 1) fix them if requested 2) throw an error otherwise.
storm::dd::Bdd<Type> statesWithTransition = transitionMatrixBdd.existsAbstract(generationInfo.columnMetaVariables);
storm::dd::Add<Type, ValueType> deadlockStates = (reachableStates && !statesWithTransition).template toAdd<ValueType>();
if (!deadlockStates.isZero()) {
// If we need to fix deadlocks, we do so now.
if (!storm::settings::getModule<storm::settings::modules::MarkovChainSettings>().isDontFixDeadlocksSet()) {
@ -1088,7 +1182,7 @@ namespace storm {
for (auto it = deadlockStates.begin(), ite = deadlockStates.end(); it != ite && count < 3; ++it, ++count) {
STORM_LOG_INFO((*it).first.toPrettyString(generationInfo.rowMetaVariables) << std::endl);
}
if (program.getModelType() == storm::prism::Program::ModelType::DTMC) {
// For DTMCs, we can simply add the identity of the global module for all deadlock states.
transitionMatrix += deadlockStates * globalModule.identity;
@ -1175,7 +1269,7 @@ namespace storm {
changed = false;
storm::dd::Bdd<Type> tmp = reachableStates.relationalProduct(transitionBdd, generationInfo.rowMetaVariables, generationInfo.columnMetaVariables);
storm::dd::Bdd<Type> newReachableStates = tmp && (!reachableStates);
// Check whether new states were indeed discovered.
if (!newReachableStates.isZero()) {
changed = true;
@ -1192,7 +1286,7 @@ namespace storm {
// Explicitly instantiate the symbolic model builder.
template class DdPrismModelBuilder<storm::dd::DdType::CUDD>;
template class DdPrismModelBuilder<storm::dd::DdType::Sylvan>;
} // namespace adapters
} // namespace storm

12
src/builder/DdPrismModelBuilder.h

@ -188,6 +188,14 @@ namespace storm {
return synchronizingActionToDecisionDiagramMap.find(actionIndex) != synchronizingActionToDecisionDiagramMap.end();
}
std::set<uint_fast64_t> getSynchronizingActionIndices() const {
std::set<uint_fast64_t> result;
for (auto const& entry : synchronizingActionToDecisionDiagramMap) {
result.insert(entry.first);
}
return result;
}
// The decision diagram for the independent action.
ActionDecisionDiagram independentAction;
@ -210,7 +218,11 @@ namespace storm {
* Structure to store the result of the system creation phase.
*/
struct SystemResult;
private:
template <storm::dd::DdType TypePrime, typename ValueTypePrime>
friend class ModuleComposer;
static std::set<storm::expressions::Variable> equalizeAssignedGlobalVariables(GenerationInformation const& generationInfo, ActionDecisionDiagram& action1, ActionDecisionDiagram& action2);
static std::set<storm::expressions::Variable> equalizeAssignedGlobalVariables(GenerationInformation const& generationInfo, std::vector<ActionDecisionDiagram>& actionDds);

2
src/storage/prism/InterleavingParallelComposition.cpp

@ -12,7 +12,7 @@ namespace storm {
}
void InterleavingParallelComposition::writeToStream(std::ostream& stream) const {
stream << "(" << *left << " ||| " << *right << ")";
stream << "(" << this->getLeftSubcomposition() << " ||| " << this->getRightSubcomposition() << ")";
}
}

4
src/storage/prism/InterleavingParallelComposition.h

@ -13,10 +13,6 @@ namespace storm {
protected:
virtual void writeToStream(std::ostream& stream) const override;
private:
std::shared_ptr<Composition> left;
std::shared_ptr<Composition> right;
};
}
}

27
src/storage/prism/Program.cpp

@ -27,11 +27,21 @@ namespace storm {
}
bool isValid(Composition const& composition) {
return boost::any_cast<bool>(composition.accept(*this));
bool isValid = boost::any_cast<bool>(composition.accept(*this));
if (appearingModules.size() != program.getNumberOfModules()) {
isValid = false;
STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException, "Not every module is used in the system composition.");
}
return isValid;
}
virtual boost::any visit(ModuleComposition const& composition) override {
return program.hasModule(composition.getModuleName());
bool isValid = program.hasModule(composition.getModuleName());
STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException, "The module \"" << composition.getModuleName() << "\" referred to in the system composition does not exist.");
isValid = appearingModules.find(composition.getModuleName()) == appearingModules.end();
STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException, "The module \"" << composition.getModuleName() << "\" is referred to more than once in the system composition.");
appearingModules.insert(composition.getModuleName());
return isValid;
}
virtual boost::any visit(RenamingComposition const& composition) override {
@ -56,6 +66,7 @@ namespace storm {
private:
storm::prism::Program const& program;
std::set<std::string> appearingModules;
};
Program::Program(std::shared_ptr<storm::expressions::ExpressionManager> manager, ModelType modelType, std::vector<Constant> const& constants, std::vector<BooleanVariable> const& globalBooleanVariables, std::vector<IntegerVariable> const& globalIntegerVariables, std::vector<Formula> const& formulas, std::vector<Module> const& modules, std::map<std::string, uint_fast64_t> const& actionToIndexMap, std::vector<RewardModel> const& rewardModels, std::vector<Label> const& labels, boost::optional<InitialConstruct> const& initialConstruct, boost::optional<SystemCompositionConstruct> const& compositionConstruct, std::string const& filename, uint_fast64_t lineNumber, bool finalModel)
@ -352,6 +363,18 @@ namespace storm {
return systemCompositionConstruct;
}
std::shared_ptr<Composition> Program::getDefaultSystemComposition() const {
std::shared_ptr<Composition> current = std::make_shared<ModuleComposition>(this->modules.front().getName());
for (uint_fast64_t index = 1; index < this->modules.size(); ++index) {
std::shared_ptr<Composition> newComposition = std::make_shared<SynchronizingParallelComposition>(current, std::make_shared<ModuleComposition>(this->modules[index].getName()));
current = newComposition;
}
return current;
}
std::set<std::string> const& Program::getActions() const {
return this->actions;
}

7
src/storage/prism/Program.h

@ -296,6 +296,13 @@ namespace storm {
*/
boost::optional<SystemCompositionConstruct> getOptionalSystemCompositionConstruct() const;
/*!
* Retrieves the default system composition for this program.
*
* @return The default system composition.
*/
std::shared_ptr<Composition> getDefaultSystemComposition() const;
/*!
* Retrieves the set of actions present in the program.
*

2
src/storage/prism/RestrictedParallelComposition.cpp

@ -14,7 +14,7 @@ namespace storm {
}
void RestrictedParallelComposition::writeToStream(std::ostream& stream) const {
stream << "(" << *left << " |[" << boost::algorithm::join(synchronizingActions, ", ") << "]| " << *right << ")";
stream << "(" << this->getLeftSubcomposition() << " |[" << boost::algorithm::join(synchronizingActions, ", ") << "]| " << this->getRightSubcomposition() << ")";
}
}

2
src/storage/prism/RestrictedParallelComposition.h

@ -18,9 +18,7 @@ namespace storm {
virtual void writeToStream(std::ostream& stream) const override;
private:
std::shared_ptr<Composition> left;
std::set<std::string> synchronizingActions;
std::shared_ptr<Composition> right;
};
}
}

2
src/storage/prism/SynchronizingParallelComposition.cpp

@ -12,7 +12,7 @@ namespace storm {
}
void SynchronizingParallelComposition::writeToStream(std::ostream& stream) const {
stream << "(" << *left << " || " << *right << ")";
stream << "(" << this->getLeftSubcomposition() << " || " << this->getRightSubcomposition() << ")";
}
}

4
src/storage/prism/SynchronizingParallelComposition.h

@ -13,10 +13,6 @@ namespace storm {
protected:
virtual void writeToStream(std::ostream& stream) const override;
private:
std::shared_ptr<Composition> left;
std::shared_ptr<Composition> right;
};
}
}

Loading…
Cancel
Save