You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
257 lines
14 KiB
257 lines
14 KiB
#include "storm/storage/jani/CompositionInformationVisitor.h"
|
|
|
|
#include "storm/storage/jani/Model.h"
|
|
#include "storm/storage/jani/Compositions.h"
|
|
|
|
#include "storm/utility/macros.h"
|
|
#include "storm/exceptions/WrongFormatException.h"
|
|
|
|
namespace storm {
|
|
namespace jani {
|
|
|
|
CompositionInformation::CompositionInformation() : nonStandardParallelComposition(false), nestedParallelComposition(false), parallelComposition(false) {
|
|
// Intentionally left empty.
|
|
}
|
|
|
|
void CompositionInformation::increaseAutomatonMultiplicity(std::string const& automatonName, uint64_t count) {
|
|
automatonNameToMultiplicity[automatonName] += count;
|
|
}
|
|
|
|
std::map<std::string, uint64_t> const& CompositionInformation::getAutomatonToMultiplicityMap() const {
|
|
return automatonNameToMultiplicity;
|
|
}
|
|
|
|
void CompositionInformation::addMultiplicityMap(std::map<std::string, uint64_t> const& multiplicityMap) {
|
|
automatonNameToMultiplicity = joinMultiplicityMaps(automatonNameToMultiplicity, multiplicityMap);
|
|
}
|
|
|
|
std::map<std::string, uint64_t> CompositionInformation::joinMultiplicityMaps(std::map<std::string, uint64_t> const& first, std::map<std::string, uint64_t> const& second) {
|
|
std::map<std::string, uint64_t> result = first;
|
|
for (auto const& element : second) {
|
|
result[element.first] += element.second;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void CompositionInformation::setContainsNonStandardParallelComposition(bool value) {
|
|
nonStandardParallelComposition = value;
|
|
}
|
|
|
|
bool CompositionInformation::containsNonStandardParallelComposition() const {
|
|
return nonStandardParallelComposition;
|
|
}
|
|
|
|
void CompositionInformation::setContainsNestedParallelComposition(bool value) {
|
|
nestedParallelComposition = value;
|
|
}
|
|
|
|
bool CompositionInformation::containsNestedParallelComposition() const {
|
|
return nestedParallelComposition;
|
|
}
|
|
|
|
void CompositionInformation::setContainsParallelComposition(bool value) {
|
|
parallelComposition = value;
|
|
}
|
|
|
|
bool CompositionInformation::containsParallelComposition() const {
|
|
return parallelComposition;
|
|
}
|
|
|
|
std::string const& CompositionInformation::getActionName(uint64_t index) const {
|
|
return indexToNameMap.at(index);
|
|
}
|
|
|
|
uint64_t CompositionInformation::getActionIndex(std::string const& name) const {
|
|
return nameToIndexMap.at(name);
|
|
}
|
|
|
|
void CompositionInformation::addNonSilentActionIndex(uint64_t index) {
|
|
nonSilentActionIndices.insert(index);
|
|
}
|
|
|
|
void CompositionInformation::addNonSilentActionIndices(std::set<uint64_t> const& indices) {
|
|
nonSilentActionIndices.insert(indices.begin(), indices.end());
|
|
}
|
|
|
|
bool CompositionInformation::hasNonSilentActionIndex(uint64_t index) {
|
|
return nonSilentActionIndices.find(index) != nonSilentActionIndices.end();
|
|
}
|
|
|
|
void CompositionInformation::addInputEnabledActionIndex(uint64_t index) {
|
|
inputEnabledActionIndices.insert(index);
|
|
}
|
|
|
|
std::set<uint64_t> const& CompositionInformation::getNonSilentActionIndices() const {
|
|
return nonSilentActionIndices;
|
|
}
|
|
|
|
std::set<uint64_t> const& CompositionInformation::getInputEnabledActionIndices() const {
|
|
return inputEnabledActionIndices;
|
|
}
|
|
|
|
void CompositionInformation::setMappings(std::map<uint64_t, std::string> const& indexToNameMap, std::map<std::string, uint64_t> const& nameToIndexMap) {
|
|
this->indexToNameMap = indexToNameMap;
|
|
this->nameToIndexMap = nameToIndexMap;
|
|
}
|
|
|
|
CompositionInformationVisitor::CompositionInformationVisitor(Model const& model, Composition const& composition) : model(model), composition(composition), nextFreeActionIndex(0) {
|
|
// Determine the next free index we can give out to a new action.
|
|
for (auto const& action : model.getActions()) {
|
|
uint64_t actionIndex = model.getActionIndex(action.getName());
|
|
|
|
nameToIndexMap[action.getName()] = model.getActionIndex(action.getName());
|
|
indexToNameMap[actionIndex] = action.getName();
|
|
|
|
nextFreeActionIndex = std::max(nextFreeActionIndex, model.getActionIndex(action.getName()));
|
|
}
|
|
++nextFreeActionIndex;
|
|
}
|
|
|
|
CompositionInformation CompositionInformationVisitor::getInformation() {
|
|
CompositionInformation result = boost::any_cast<CompositionInformation>(composition.accept(*this, model));
|
|
result.setMappings(indexToNameMap, nameToIndexMap);
|
|
return result;
|
|
}
|
|
|
|
boost::any CompositionInformationVisitor::visit(AutomatonComposition const& composition, boost::any const& data) {
|
|
Model const& model = boost::any_cast<Model const&>(data);
|
|
Automaton const& automaton = model.getAutomaton(composition.getAutomatonName());
|
|
|
|
CompositionInformation result;
|
|
result.increaseAutomatonMultiplicity(composition.getAutomatonName());
|
|
for (auto const& actionIndex : automaton.getActionIndices()) {
|
|
if (actionIndex != storm::jani::Model::SILENT_ACTION_INDEX) {
|
|
result.addNonSilentActionIndex(actionIndex);
|
|
}
|
|
}
|
|
for (auto const& action : composition.getInputEnabledActions()) {
|
|
auto it = nameToIndexMap.find(action);
|
|
STORM_LOG_THROW(it != nameToIndexMap.end(), storm::exceptions::WrongFormatException, "Illegal action name '" << action << "' in when input-enabling automaton '" << composition.getAutomatonName() << "'.");
|
|
uint64_t actionIndex = it->second;
|
|
STORM_LOG_THROW(result.hasNonSilentActionIndex(actionIndex), storm::exceptions::WrongFormatException, "Cannot make automaton '" << composition.getAutomatonName() << "' input enabled for action " << action << ", because it has no such action.");
|
|
result.addInputEnabledActionIndex(actionIndex);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
boost::any CompositionInformationVisitor::visit(ParallelComposition const& composition, boost::any const& data) {
|
|
CompositionInformation result;
|
|
|
|
std::vector<CompositionInformation> subinformation;
|
|
|
|
std::set<uint64_t> nonsilentSubActionIndices;
|
|
for (auto const& subcomposition : composition.getSubcompositions()) {
|
|
subinformation.push_back(boost::any_cast<CompositionInformation>(subcomposition->accept(*this, data)));
|
|
nonsilentSubActionIndices.insert(subinformation.back().getNonSilentActionIndices().begin(), subinformation.back().getNonSilentActionIndices().end());
|
|
}
|
|
|
|
bool containsNonStandardParallelComposition = false;
|
|
bool containsSubParallelComposition = false;
|
|
|
|
for (auto const& subinfo : subinformation) {
|
|
containsNonStandardParallelComposition |= subinfo.containsNonStandardParallelComposition();
|
|
containsSubParallelComposition |= subinfo.containsParallelComposition();
|
|
result.addMultiplicityMap(subinfo.getAutomatonToMultiplicityMap());
|
|
}
|
|
|
|
// Keep track of the synchronization vectors that are effective, meaning that the subcompositions all have
|
|
// the non-silent actions that are referred to.
|
|
std::set<uint64_t> effectiveSynchVectors;
|
|
for (uint64_t synchVectorIndex = 0; synchVectorIndex < composition.getNumberOfSynchronizationVectors(); ++synchVectorIndex) {
|
|
effectiveSynchVectors.insert(synchVectorIndex);
|
|
}
|
|
|
|
// Now compute non-silent actions.
|
|
std::set<uint64_t> nonSilentActionIndices;
|
|
for (uint_fast64_t infoIndex = 0; infoIndex < subinformation.size(); ++infoIndex) {
|
|
auto const& subinfo = subinformation[infoIndex];
|
|
|
|
std::set<uint64_t> enabledSynchVectors;
|
|
std::set<uint64_t> actionsInSynch;
|
|
for (uint64_t synchVectorIndex = 0; synchVectorIndex < composition.getNumberOfSynchronizationVectors(); ++synchVectorIndex) {
|
|
auto const& synchVector = composition.getSynchronizationVector(synchVectorIndex);
|
|
if (synchVector.getInput(infoIndex) != SynchronizationVector::NO_ACTION_INPUT) {
|
|
for (auto const& nonSilentActionIndex : subinfo.getNonSilentActionIndices()) {
|
|
std::string const& nonSilentAction = indexToNameMap.at(nonSilentActionIndex);
|
|
if (synchVector.getInput(infoIndex) == nonSilentAction) {
|
|
enabledSynchVectors.insert(synchVectorIndex);
|
|
actionsInSynch.insert(nonSilentActionIndex);
|
|
}
|
|
}
|
|
} else {
|
|
enabledSynchVectors.insert(synchVectorIndex);
|
|
}
|
|
}
|
|
|
|
std::set_difference(subinfo.getNonSilentActionIndices().begin(), subinfo.getNonSilentActionIndices().end(), actionsInSynch.begin(), actionsInSynch.end(), std::inserter(nonSilentActionIndices, nonSilentActionIndices.begin()));
|
|
|
|
std::set<uint64_t> newEffectiveSynchVectors;
|
|
std::set_intersection(effectiveSynchVectors.begin(), effectiveSynchVectors.end(), enabledSynchVectors.begin(), enabledSynchVectors.end(), std::inserter(newEffectiveSynchVectors, newEffectiveSynchVectors.begin()));
|
|
effectiveSynchVectors = std::move(newEffectiveSynchVectors);
|
|
}
|
|
|
|
// Now add all outputs of effective synchronization vectors.
|
|
for (auto const& synchVectorIndex : effectiveSynchVectors) {
|
|
auto const& synchVector = composition.getSynchronizationVector(synchVectorIndex);
|
|
if (synchVector.getOutput() != storm::jani::Model::SILENT_ACTION_NAME) {
|
|
nonSilentActionIndices.insert(addOrGetActionIndex(synchVector.getOutput()));
|
|
}
|
|
}
|
|
|
|
// Finally check whether it's a non-standard parallel composition. We do that by first constructing a set of
|
|
// all effective synchronization vectors and then checking whether this set is fully contained within the
|
|
// set of expected synchronization vectors.
|
|
|
|
std::set<storm::jani::SynchronizationVector, storm::jani::SynchronizationVectorLexicographicalLess> synchVectorSet;
|
|
for (auto synchVectorIndex : effectiveSynchVectors) {
|
|
synchVectorSet.insert(composition.getSynchronizationVector(synchVectorIndex));
|
|
}
|
|
|
|
// Construct the set of expected synchronization vectors.
|
|
std::set<storm::jani::SynchronizationVector, storm::jani::SynchronizationVectorLexicographicalLess> expectedSynchVectorSetUnderApprox;
|
|
std::set<storm::jani::SynchronizationVector, storm::jani::SynchronizationVectorLexicographicalLess> expectedSynchVectorSetOverApprox;
|
|
for (auto actionIndex : nonsilentSubActionIndices) {
|
|
std::string const& actionName = indexToNameMap.at(actionIndex);
|
|
std::vector<std::string> input;
|
|
uint64_t numberOfParticipatingAutomata = 0;
|
|
for (auto const& subcomposition : subinformation) {
|
|
if (subcomposition.getNonSilentActionIndices().find(actionIndex) != subcomposition.getNonSilentActionIndices().end()) {
|
|
input.push_back(actionName);
|
|
++numberOfParticipatingAutomata;
|
|
} else {
|
|
input.push_back(SynchronizationVector::NO_ACTION_INPUT);
|
|
}
|
|
}
|
|
|
|
storm::jani::SynchronizationVector newSynchVector(input, actionName);
|
|
expectedSynchVectorSetOverApprox.insert(newSynchVector);
|
|
if (numberOfParticipatingAutomata > 1) {
|
|
expectedSynchVectorSetUnderApprox.insert(newSynchVector);
|
|
}
|
|
}
|
|
|
|
containsNonStandardParallelComposition |= !std::includes(expectedSynchVectorSetOverApprox.begin(), expectedSynchVectorSetOverApprox.end(), synchVectorSet.begin(), synchVectorSet.end(), SynchronizationVectorLexicographicalLess());
|
|
|
|
containsNonStandardParallelComposition |= !std::includes(synchVectorSet.begin(), synchVectorSet.end(), expectedSynchVectorSetUnderApprox.begin(), expectedSynchVectorSetUnderApprox.end(), SynchronizationVectorLexicographicalLess());
|
|
|
|
result.setContainsNonStandardParallelComposition(containsNonStandardParallelComposition);
|
|
result.setContainsParallelComposition(true);
|
|
result.setContainsNestedParallelComposition(containsSubParallelComposition);
|
|
|
|
result.addNonSilentActionIndices(nonSilentActionIndices);
|
|
return result;
|
|
}
|
|
|
|
uint64_t CompositionInformationVisitor::addOrGetActionIndex(std::string const& name) {
|
|
auto it = nameToIndexMap.find(name);
|
|
if (it != nameToIndexMap.end()) {
|
|
return it->second;
|
|
} else {
|
|
nameToIndexMap[name] = nextFreeActionIndex;
|
|
indexToNameMap[nextFreeActionIndex] = name;
|
|
return nextFreeActionIndex++;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|