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.
 
 
 
 

262 lines
11 KiB

#include "storm/storage/jani/ParallelComposition.h"
#include <sstream>
#include <boost/algorithm/string/join.hpp>
#include "storm/utility/macros.h"
#include "storm/exceptions/WrongFormatException.h"
#include "storm/storage/jani/Model.h"
namespace storm {
namespace jani {
const std::string SynchronizationVector::NO_ACTION_INPUT = "-";
SynchronizationVector::SynchronizationVector(std::vector<std::string> const& input, std::string const& output) : input(input), output(output) {
// Intentionally left empty.
}
SynchronizationVector::SynchronizationVector(std::vector<std::string> const& input) : input(input), output(storm::jani::Model::SILENT_ACTION_NAME) {
}
std::size_t SynchronizationVector::size() const {
return input.size();
}
std::vector<std::string> const& SynchronizationVector::getInput() const {
return input;
}
std::string const& SynchronizationVector::getInput(uint64_t index) const {
return input[index];
}
std::string const& SynchronizationVector::getOutput() const {
return output;
}
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) != NO_ACTION_INPUT) {
return boost::make_optional(i);
}
}
// Check the 0-index.
if (this->getInput(i) != NO_ACTION_INPUT) {
return boost::make_optional(i);
}
return boost::none;
}
uint64_t SynchronizationVector::getPositionOfFirstParticipatingAction() const {
for (uint64_t result = 0; result < this->size(); ++result) {
if (this->getInput(result) != NO_ACTION_INPUT) {
return result;
}
}
STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Synchronization vector must have at least one participating action.");
}
uint64_t SynchronizationVector::getNumberOfActionInputs() const {
uint64_t result = 0;
for (auto const& inputEntry : input) {
if (!isNoActionInput(inputEntry)) {
++result;
}
}
return result;
}
bool SynchronizationVector::isNoActionInput(std::string const& action) {
return action == NO_ACTION_INPUT;
}
std::ostream& operator<<(std::ostream& stream, SynchronizationVector const& synchronizationVector) {
bool first = true;
stream << "(";
for (auto const& element : synchronizationVector.getInput()) {
if (!first) {
stream << ", ";
}
stream << element;
first = false;
}
stream << ") -> " << synchronizationVector.getOutput();
return stream;
}
bool operator==(SynchronizationVector const& vector1, SynchronizationVector const& vector2) {
if (vector1.getOutput() != vector2.getOutput()) {
return false;
}
if (vector1.getInput() != vector1.getInput()) {
return false;
}
return true;
}
bool operator!=(SynchronizationVector const& vector1, SynchronizationVector const& vector2) {
return !(vector1 == vector2);
}
bool SynchronizationVectorLexicographicalLess::operator()(SynchronizationVector const& vector1, SynchronizationVector const& vector2) const {
STORM_LOG_THROW(vector1.size() == vector2.size(), storm::exceptions::WrongFormatException, "Cannot compare synchronization vectors of different size.");
for (uint64_t i = 0; i < vector1.size(); ++i) {
if (vector1.getInput(i) < vector2.getInput(i)) {
return true;
} else if (vector1.getInput(i) > vector2.getInput(i)) {
return false;
}
}
if (vector1.getOutput() < vector2.getOutput()) {
return true;
} else if (vector1.getOutput() > vector2.getOutput()) {
return false;
}
return false;
}
ParallelComposition::ParallelComposition(std::shared_ptr<Composition> const& subcomposition, std::vector<SynchronizationVector> const& synchronizationVectors) : ParallelComposition(std::vector<std::shared_ptr<Composition>>{subcomposition}, synchronizationVectors) {
// Intentionally left empty.
}
ParallelComposition::ParallelComposition(std::vector<std::shared_ptr<Composition>> const& subcompositions, std::vector<SynchronizationVector> const& synchronizationVectors) : subcompositions(subcompositions), synchronizationVectors(synchronizationVectors) {
STORM_LOG_THROW(!subcompositions.empty(), storm::exceptions::WrongFormatException, "At least one automaton required for parallel composition.");
this->checkSynchronizationVectors();
}
ParallelComposition::ParallelComposition(std::vector<std::shared_ptr<Composition>> const& subcompositions, std::set<std::string> const& synchronizationAlphabet) : subcompositions(subcompositions), synchronizationVectors() {
STORM_LOG_THROW(!subcompositions.empty(), storm::exceptions::WrongFormatException, "At least one automaton required for parallel composition.");
// Manually construct the synchronization vectors for all elements of the synchronization alphabet.
for (auto const& action : synchronizationAlphabet) {
synchronizationVectors.emplace_back(std::vector<std::string>(this->subcompositions.size(), action), action);
}
}
ParallelComposition::ParallelComposition(std::shared_ptr<Composition> const& leftSubcomposition, std::shared_ptr<Composition> const& rightSubcomposition, std::set<std::string> const& synchronizationAlphabet) {
subcompositions.push_back(leftSubcomposition);
subcompositions.push_back(rightSubcomposition);
// Manually construct the synchronization vectors for all elements of the synchronization alphabet.
for (auto const& action : synchronizationAlphabet) {
synchronizationVectors.emplace_back(std::vector<std::string>(this->subcompositions.size(), action), action);
}
}
bool ParallelComposition::isParallelComposition() const {
return true;
}
Composition const& ParallelComposition::getSubcomposition(uint64_t index) const {
return *subcompositions[index];
}
std::vector<std::shared_ptr<Composition>> const& ParallelComposition::getSubcompositions() const {
return subcompositions;
}
uint64_t ParallelComposition::getNumberOfSubcompositions() const {
return subcompositions.size();
}
SynchronizationVector const& ParallelComposition::getSynchronizationVector(uint64_t index) const {
return synchronizationVectors[index];
}
std::vector<SynchronizationVector> const& ParallelComposition::getSynchronizationVectors() const {
return synchronizationVectors;
}
std::size_t ParallelComposition::getNumberOfSynchronizationVectors() const {
return synchronizationVectors.size();
}
bool ParallelComposition::areActionsReused() const {
for (uint_fast64_t inputIndex = 0; inputIndex < subcompositions.size(); ++ inputIndex) {
std::set<std::string> actions;
for (auto const& vector : synchronizationVectors) {
std::string const& action = vector.getInput(inputIndex);
if (action != SynchronizationVector::NO_ACTION_INPUT) {
if (actions.find(action) != actions.end()) {
return true;
}
actions.insert(action);
}
}
// And check recursively, in case we have nested parallel composition
if (subcompositions.at(inputIndex)->isParallelComposition()) {
if (subcompositions.at(inputIndex)->asParallelComposition().areActionsReused()) {
return true;
}
}
}
return false;
}
void ParallelComposition::checkSynchronizationVectors() const {
for (uint_fast64_t inputIndex = 0; inputIndex < subcompositions.size(); ++ inputIndex) {
for (auto const& vector : synchronizationVectors) {
STORM_LOG_THROW(vector.size() == this->subcompositions.size(), storm::exceptions::WrongFormatException, "Synchronization vectors must match parallel composition size.");
}
}
for (auto const& vector : synchronizationVectors) {
bool hasInput = false;
for (auto const& input : vector.getInput()) {
if (input != SynchronizationVector::NO_ACTION_INPUT) {
hasInput = true;
break;
}
}
STORM_LOG_THROW(hasInput, storm::exceptions::WrongFormatException, "Synchronization vector must have at least one proper input.");
}
}
boost::any ParallelComposition::accept(CompositionVisitor& visitor, boost::any const& data) const {
return visitor.visit(*this, data);
}
void ParallelComposition::write(std::ostream& stream) const {
std::vector<std::string> synchronizationVectorsAsStrings;
for (auto const& synchronizationVector : synchronizationVectors) {
std::stringstream tmpStream;
tmpStream << synchronizationVector;
synchronizationVectorsAsStrings.push_back(tmpStream.str());
}
bool first = true;
bool hasSynchVectors = !synchronizationVectors.empty();
stream << "(";
for (auto const& subcomposition : subcompositions) {
if (!first) {
stream << (hasSynchVectors ? " || " : " ||| ");
}
stream << *subcomposition;
first = false;
}
stream << ")";
if (hasSynchVectors) {
stream << "[" << boost::algorithm::join(synchronizationVectorsAsStrings, ", ") << "]";
}
}
}
}