#include "storm/storage/prism/Program.h" #include #include #include #include "storm/storage/jani/Model.h" #include "storm/storage/jani/Property.h" #include "storm/storage/expressions/ExpressionManager.h" #include "storm/utility/macros.h" #include "storm/utility/solver.h" #include "storm/utility/vector.h" #include "storm/exceptions/InvalidArgumentException.h" #include "storm/exceptions/OutOfRangeException.h" #include "storm/exceptions/WrongFormatException.h" #include "storm/exceptions/InvalidTypeException.h" #include "storm/exceptions/InvalidOperationException.h" #include "storm/solver/SmtSolver.h" #include "storm/storage/jani/expressions/JaniExpressionSubstitutionVisitor.h" #include "storm/storage/prism/CompositionVisitor.h" #include "storm/storage/prism/Compositions.h" #include "storm/storage/prism/ToJaniConverter.h" #include "storm/utility/macros.h" namespace storm { namespace prism { class CompositionValidityChecker : public CompositionVisitor { public: CompositionValidityChecker(storm::prism::Program const& program) : program(program) { // Intentionally left empty. } void check(Composition const& composition) { composition.accept(*this, boost::any()); if (appearingModules.size() != program.getNumberOfModules()) { STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Not every module is used in the system composition."); } } virtual boost::any visit(ModuleComposition const& composition, boost::any const&) override { 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()); std::set synchronizingActionIndices = program.getModule(composition.getModuleName()).getSynchronizingActionIndices(); return synchronizingActionIndices; } virtual boost::any visit(RenamingComposition const& composition, boost::any const& data) override { std::set subSynchronizingActionIndices = boost::any_cast>(composition.getSubcomposition().accept(*this, data)); std::set newSynchronizingActionIndices = subSynchronizingActionIndices; for (auto const& namePair : composition.getActionRenaming()) { if (!program.hasAction(namePair.first)) { STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "System composition refers to unknown action '" << namePair.first << "'."); } else if (!program.hasAction(namePair.second)) { STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "System composition refers to unknown action '" << namePair.second << "'."); } else { uint_fast64_t fromIndex = program.getActionIndex(namePair.first); uint_fast64_t toIndex = program.getActionIndex(namePair.second); auto it = subSynchronizingActionIndices.find(fromIndex); STORM_LOG_THROW(it != subSynchronizingActionIndices.end(), storm::exceptions::WrongFormatException, "Cannot rename action '" << namePair.first << "', because module '" << composition.getSubcomposition() << " does not have this action."); newSynchronizingActionIndices.erase(newSynchronizingActionIndices.find(fromIndex)); newSynchronizingActionIndices.insert(toIndex); } } return newSynchronizingActionIndices; } virtual boost::any visit(HidingComposition const& composition, boost::any const& data) override { std::set subSynchronizingActionIndices = boost::any_cast>(composition.getSubcomposition().accept(*this, data)); for (auto const& action : composition.getActionsToHide()) { if (!program.hasAction(action)) { STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "System composition refers to unknown action '" << action << "'."); } else { uint_fast64_t index = program.getActionIndex(action); auto it = subSynchronizingActionIndices.find(index); STORM_LOG_THROW(it != subSynchronizingActionIndices.end(), storm::exceptions::WrongFormatException, "Cannot hide action '" << action << "', because module '" << composition.getSubcomposition() << " does not have this action."); subSynchronizingActionIndices.erase(it); } } return subSynchronizingActionIndices; } virtual boost::any visit(SynchronizingParallelComposition const& composition, boost::any const& data) override { std::set leftSynchronizingActionIndices = boost::any_cast>(composition.getLeftSubcomposition().accept(*this, data)); std::set rightSynchronizingActionIndices = boost::any_cast>(composition.getRightSubcomposition().accept(*this, data)); std::set synchronizingActionIndices; std::set_union(leftSynchronizingActionIndices.begin(), leftSynchronizingActionIndices.end(), rightSynchronizingActionIndices.begin(), rightSynchronizingActionIndices.end(), std::inserter(synchronizingActionIndices, synchronizingActionIndices.begin())); return synchronizingActionIndices; } virtual boost::any visit(InterleavingParallelComposition const& composition, boost::any const& data) override { std::set leftSynchronizingActionIndices = boost::any_cast>(composition.getLeftSubcomposition().accept(*this, data)); std::set rightSynchronizingActionIndices = boost::any_cast>(composition.getRightSubcomposition().accept(*this, data)); std::set synchronizingActionIndices; std::set_union(leftSynchronizingActionIndices.begin(), leftSynchronizingActionIndices.end(), rightSynchronizingActionIndices.begin(), rightSynchronizingActionIndices.end(), std::inserter(synchronizingActionIndices, synchronizingActionIndices.begin())); return synchronizingActionIndices; } virtual boost::any visit(RestrictedParallelComposition const& composition, boost::any const& data) override { std::set leftSynchronizingActionIndices = boost::any_cast>(composition.getLeftSubcomposition().accept(*this, data)); std::set rightSynchronizingActionIndices = boost::any_cast>(composition.getRightSubcomposition().accept(*this, data)); for (auto const& action : composition.getSynchronizingActions()) { if (!program.hasAction(action)) { STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "System composition refers to unknown action '" << action << "'."); } else { uint_fast64_t index = program.getActionIndex(action); auto it = leftSynchronizingActionIndices.find(index); STORM_LOG_THROW(it != leftSynchronizingActionIndices.end(), storm::exceptions::WrongFormatException, "Cannot synchronize on action '" << action << "', because module '" << composition.getLeftSubcomposition() << " does not have this action."); it = rightSynchronizingActionIndices.find(index); STORM_LOG_THROW(it != rightSynchronizingActionIndices.end(), storm::exceptions::WrongFormatException, "Cannot synchronize on action '" << action << "', because module '" << composition.getRightSubcomposition() << " does not have this action."); } } std::set synchronizingActionIndices; std::set_union(leftSynchronizingActionIndices.begin(), leftSynchronizingActionIndices.end(), rightSynchronizingActionIndices.begin(), rightSynchronizingActionIndices.end(), std::inserter(synchronizingActionIndices, synchronizingActionIndices.begin())); return synchronizingActionIndices; } private: storm::prism::Program const& program; std::set appearingModules; }; Program::Program(std::shared_ptr manager, ModelType modelType, std::vector const& constants, std::vector const& globalBooleanVariables, std::vector const& globalIntegerVariables, std::vector const& formulas, std::vector const& modules, std::map const& actionToIndexMap, std::vector const& rewardModels, std::vector