Browse Source

standard system composition of JANI models now only use synchronization vectors on the topmost level

Former-commit-id: 3c328b05b4 [formerly 5509822ac1]
Former-commit-id: 20ebbd8ee2
main
dehnert 9 years ago
parent
commit
02f545c54d
  1. 15
      src/builder/DdJaniModelBuilder.cpp
  2. 8
      src/storage/jani/Automaton.cpp
  3. 2
      src/storage/jani/CompositionActionInformationVisitor.cpp
  4. 58
      src/storage/jani/Model.cpp
  5. 43
      src/storage/jani/ParallelComposition.cpp
  6. 17
      src/storage/jani/ParallelComposition.h

15
src/builder/DdJaniModelBuilder.cpp

@ -1109,18 +1109,25 @@ namespace storm {
for (uint64_t subcompositionIndex = 0; subcompositionIndex < composition.getNumberOfSubcompositions(); ++subcompositionIndex) { for (uint64_t subcompositionIndex = 0; subcompositionIndex < composition.getNumberOfSubcompositions(); ++subcompositionIndex) {
// Prepare the new offset mapping. // Prepare the new offset mapping.
std::map<uint64_t, uint64_t> newSynchronizingActionToOffsetMap = actionIndexToLocalNondeterminismVariableOffset; std::map<uint64_t, uint64_t> newSynchronizingActionToOffsetMap = actionIndexToLocalNondeterminismVariableOffset;
if (subcompositionIndex == 0) { if (subcompositionIndex == 0) {
for (auto const& synchVector : composition.getSynchronizationVectors()) { for (auto const& synchVector : composition.getSynchronizationVectors()) {
auto it = actionIndexToLocalNondeterminismVariableOffset.find(actionInformation.getActionIndex(synchVector.getOutput())); auto it = actionIndexToLocalNondeterminismVariableOffset.find(actionInformation.getActionIndex(synchVector.getOutput()));
STORM_LOG_THROW(it != actionIndexToLocalNondeterminismVariableOffset.end(), storm::exceptions::InvalidArgumentException, "Invalid action " << synchVector.getOutput() << "."); STORM_LOG_THROW(it != actionIndexToLocalNondeterminismVariableOffset.end(), storm::exceptions::InvalidArgumentException, "Invalid action " << synchVector.getOutput() << ".");
if (synchVector.getInput(0) != storm::jani::SynchronizationVector::getNoActionInput()) {
newSynchronizingActionToOffsetMap[actionInformation.getActionIndex(synchVector.getInput(0))] = it->second; newSynchronizingActionToOffsetMap[actionInformation.getActionIndex(synchVector.getInput(0))] = it->second;
} }
}
} else { } else {
AutomatonDd const& previousAutomatonDd = subautomata.back();
// Based on the previous results, we need to update the offsets. // Based on the previous results, we need to update the offsets.
for (auto const& synchVector : composition.getSynchronizationVectors()) { for (auto const& synchVector : composition.getSynchronizationVectors()) {
auto it = previousAutomatonDd.actionIndexToAction.find(actionInformation.getActionIndex(synchVector.getInput(subcompositionIndex - 1)));
if (synchVector.getInput(subcompositionIndex) != storm::jani::SynchronizationVector::getNoActionInput()) {
boost::optional<uint64_t> previousActionPosition = synchVector.getPositionOfPrecedingParticipatingAction(subcompositionIndex);
if (previousActionPosition) {
AutomatonDd const& previousAutomatonDd = subautomata[previousActionPosition.get()];
std::string const& previousAction = synchVector.getInput(previousActionPosition.get());
auto it = previousAutomatonDd.actionIndexToAction.find(actionInformation.getActionIndex(previousAction));
if (it != previousAutomatonDd.actionIndexToAction.end()) { if (it != previousAutomatonDd.actionIndexToAction.end()) {
newSynchronizingActionToOffsetMap[actionInformation.getActionIndex(synchVector.getInput(subcompositionIndex))] = it->second.getHighestLocalNondeterminismVariable(); newSynchronizingActionToOffsetMap[actionInformation.getActionIndex(synchVector.getInput(subcompositionIndex))] = it->second.getHighestLocalNondeterminismVariable();
} else { } else {
@ -1128,6 +1135,8 @@ namespace storm {
} }
} }
} }
}
}
// Build the DD for the next element of the composition wrt. to the current offset mapping. // Build the DD for the next element of the composition wrt. to the current offset mapping.
subautomata.push_back(boost::any_cast<AutomatonDd>(composition.getSubcomposition(subcompositionIndex).accept(*this, newSynchronizingActionToOffsetMap))); subautomata.push_back(boost::any_cast<AutomatonDd>(composition.getSubcomposition(subcompositionIndex).accept(*this, newSynchronizingActionToOffsetMap)));

8
src/storage/jani/Automaton.cpp

@ -392,14 +392,6 @@ namespace storm {
} }
} }
std::set<uint64_t> Automaton::getUsedActionIndices() const {
std::set<uint64_t> result;
for (auto const& edge : edges) {
result.insert(edge.getActionIndex());
}
return result;
}
bool Automaton::containsVariablesOnlyInProbabilitiesOrTransientAssignments(std::set<storm::expressions::Variable> const& variables) const { bool Automaton::containsVariablesOnlyInProbabilitiesOrTransientAssignments(std::set<storm::expressions::Variable> const& variables) const {
// Check initial states restriction expression. // Check initial states restriction expression.
if (this->hasInitialStatesRestriction()) { if (this->hasInitialStatesRestriction()) {

2
src/storage/jani/CompositionActionInformationVisitor.cpp

@ -51,7 +51,7 @@ namespace storm {
} }
boost::any CompositionActionInformationVisitor::visit(AutomatonComposition const& composition, boost::any const& data) { boost::any CompositionActionInformationVisitor::visit(AutomatonComposition const& composition, boost::any const& data) {
std::set<uint64_t> result = model.getAutomaton(composition.getAutomatonName()).getUsedActionIndices();
std::set<uint64_t> result = model.getAutomaton(composition.getAutomatonName()).getActionIndices();
result.erase(model.getSilentActionIndex()); result.erase(model.getSilentActionIndex());
return result; return result;
} }

58
src/storage/jani/Model.cpp

@ -215,35 +215,45 @@ namespace storm {
} }
std::shared_ptr<Composition> Model::getStandardSystemComposition() const { std::shared_ptr<Composition> Model::getStandardSystemComposition() const {
std::shared_ptr<Composition> current;
current = std::make_shared<AutomatonComposition>(this->automata.front().getName());
std::set<uint64_t> leftHandActionIndices = this->automata.front().getActionIndices();
for (uint64_t index = 1; index < automata.size(); ++index) {
std::set<uint64_t> newActionIndices = automata[index].getActionIndices();
// Compute the intersection of actions of the left- and right-hand side.
std::set<uint64_t> intersectionActions;
std::set_intersection(leftHandActionIndices.begin(), leftHandActionIndices.end(), newActionIndices.begin(), newActionIndices.end(), std::inserter(intersectionActions, intersectionActions.begin()));
// If the silent action is in the intersection, we remove it since we cannot synchronize over it.
auto it = intersectionActions.find(this->getSilentActionIndex());
if (it != intersectionActions.end()) {
intersectionActions.erase(it);
// If there's just one automaton, we must not use the parallel composition operator.
if (this->getNumberOfAutomata() == 1) {
return std::make_shared<AutomatonComposition>(this->getAutomata().front().getName());
} }
// Then join the actions to reflect the actions of the new left-hand side.
leftHandActionIndices.insert(newActionIndices.begin(), newActionIndices.end());
// Create the set of strings that represents the actions over which to synchronize.
std::set<std::string> intersectionActionNames;
for (auto const& actionIndex : intersectionActions) {
intersectionActionNames.insert(this->getAction(actionIndex).getName());
// Determine the action indices used by each of the automata and create the standard subcompositions.
std::set<uint64_t> allActionIndices;
std::vector<std::set<uint64_t>> automatonActionIndices;
std::vector<std::shared_ptr<Composition>> subcompositions;
for (auto const& automaton : automata) {
automatonActionIndices.push_back(automaton.getActionIndices());
automatonActionIndices.back().erase(silentActionIndex);
allActionIndices.insert(automatonActionIndices.back().begin(), automatonActionIndices.back().end());
subcompositions.push_back(std::make_shared<AutomatonComposition>(automaton.getName()));
}
// Create the standard synchronization vectors: every automaton with that action participates in the
// synchronization.
std::vector<storm::jani::SynchronizationVector> synchVectors;
for (auto actionIndex : allActionIndices) {
std::string const& actionName = this->getAction(actionIndex).getName();
std::vector<std::string> synchVectorInputs;
uint64_t numberOfParticipatingAutomata = 0;
for (auto const& actionIndices : automatonActionIndices) {
if (actionIndices.find(actionIndex) != actionIndices.end()) {
++numberOfParticipatingAutomata;
synchVectorInputs.push_back(actionName);
} else {
synchVectorInputs.push_back(storm::jani::SynchronizationVector::getNoActionInput());
}
} }
current = std::make_shared<ParallelComposition>(current, std::make_shared<AutomatonComposition>(automata[index].getName()), intersectionActionNames);
// Only add the synchronization vector if there is more than one participating automaton.
if (numberOfParticipatingAutomata > 1) {
synchVectors.push_back(storm::jani::SynchronizationVector(synchVectorInputs, actionName));
} }
return current;
}
return std::make_shared<ParallelComposition>(subcompositions, synchVectors);
} }
Composition const& Model::getSystemComposition() const { Composition const& Model::getSystemComposition() const {

43
src/storage/jani/ParallelComposition.cpp

@ -28,7 +28,7 @@ namespace storm {
return input[index]; return input[index];
} }
std::string const& SynchronizationVector::getNoActionInput() const {
std::string const& SynchronizationVector::getNoActionInput() {
return SynchronizationVector::noAction; return SynchronizationVector::noAction;
} }
@ -36,7 +36,36 @@ namespace storm {
return output; return output;
} }
bool SynchronizationVector::isNoActionInput(std::string const& action) const {
boost::optional<std::string> SynchronizationVector::getPrecedingParticipatingAction(uint64_t index) const {
boost::optional<uint64_t> position = getPositionOfPrecedingParticipatingAction(index);
if (position) {
return getInput(position.get());
} else {
return boost::none;
}
}
boost::optional<uint64_t> SynchronizationVector::getPositionOfPrecedingParticipatingAction(uint64_t index) const {
if (index == 0) {
return boost::none;
}
uint64_t i = index - 1;
for (; i > 0; --i) {
if (this->getInput(i) != SynchronizationVector::getNoActionInput()) {
return boost::make_optional(i);
}
}
// Check the 0-index.
if (this->getInput(i) != SynchronizationVector::getNoActionInput()) {
return boost::make_optional(i);
}
return boost::none;
}
bool SynchronizationVector::isNoActionInput(std::string const& action) {
return action == noAction; return action == noAction;
} }
@ -108,11 +137,13 @@ namespace storm {
for (auto const& vector : synchronizationVectors) { for (auto const& vector : synchronizationVectors) {
STORM_LOG_THROW(vector.size() == this->subcompositions.size(), storm::exceptions::WrongFormatException, "Synchronization vectors must match parallel composition size."); STORM_LOG_THROW(vector.size() == this->subcompositions.size(), storm::exceptions::WrongFormatException, "Synchronization vectors must match parallel composition size.");
std::string const& action = vector.getInput(inputIndex); std::string const& action = vector.getInput(inputIndex);
if (action != SynchronizationVector::getNoActionInput()) {
STORM_LOG_THROW(actions.find(action) == actions.end(), storm::exceptions::WrongFormatException, "Cannot use the same action multiple times as input in synchronization vectors."); STORM_LOG_THROW(actions.find(action) == actions.end(), storm::exceptions::WrongFormatException, "Cannot use the same action multiple times as input in synchronization vectors.");
actions.insert(action); actions.insert(action);
} }
} }
} }
}
boost::any ParallelComposition::accept(CompositionVisitor& visitor, boost::any const& data) const { boost::any ParallelComposition::accept(CompositionVisitor& visitor, boost::any const& data) const {
return visitor.visit(*this, data); return visitor.visit(*this, data);
@ -127,15 +158,19 @@ namespace storm {
} }
bool first = true; bool first = true;
bool hasSynchVectors = !synchronizationVectors.empty();
stream << "("; stream << "(";
for (auto const& subcomposition : subcompositions) { for (auto const& subcomposition : subcompositions) {
if (!first) { if (!first) {
stream << " || ";
stream << (hasSynchVectors ? " || " : " ||| ");
} }
stream << *subcomposition; stream << *subcomposition;
first = false; first = false;
} }
stream << ")[" << boost::algorithm::join(synchronizationVectorsAsStrings, ", ") << "]";
stream << ")";
if (hasSynchVectors) {
stream << "[" << boost::algorithm::join(synchronizationVectorsAsStrings, ", ") << "]";
}
} }
} }

17
src/storage/jani/ParallelComposition.h

@ -5,6 +5,8 @@
#include <vector> #include <vector>
#include <string> #include <string>
#include <boost/optional.hpp>
#include "src/storage/jani/Composition.h" #include "src/storage/jani/Composition.h"
namespace storm { namespace storm {
@ -16,11 +18,22 @@ namespace storm {
std::size_t size() const; std::size_t size() const;
std::vector<std::string> const& getInput() const; std::vector<std::string> const& getInput() const;
std::string const& getNoActionInput() const;
static std::string const& getNoActionInput();
std::string const& getInput(uint64_t index) const; std::string const& getInput(uint64_t index) const;
std::string const& getOutput() const; std::string const& getOutput() const;
static bool isNoActionInput(std::string const& action);
/*!
* Retrieves the action name that is the last participating action before the given input index. If there is
* no such action none is returned.
*/
boost::optional<std::string> getPrecedingParticipatingAction(uint64_t index) const;
bool isNoActionInput(std::string const& action) const;
/*!
* Retrieves the position with the last participating action before the given input index. If there is
* no such action none is returned.
*/
boost::optional<uint64_t> getPositionOfPrecedingParticipatingAction(uint64_t index) const;
private: private:
// A marker that can be used as one of the inputs. The semantics is that no action of the corresponding // A marker that can be used as one of the inputs. The semantics is that no action of the corresponding

Loading…
Cancel
Save