#include "storm/parser/DirectEncodingParser.h" #include #include #include "storm/models/sparse/MarkovAutomaton.h" #include "storm/models/sparse/Ctmc.h" #include "storm/exceptions/FileIoException.h" #include "storm/exceptions/WrongFormatException.h" #include "storm/exceptions/InvalidArgumentException.h" #include "storm/exceptions/NotSupportedException.h" #include "storm/settings/SettingsManager.h" #include "storm/adapters/CarlAdapter.h" #include "storm/utility/constants.h" #include "storm/utility/macros.h" #include "storm/utility/file.h" namespace storm { namespace parser { template void ValueParser::addParameter(std::string const& parameter) { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Parameters are not supported in this build."); } template<> void ValueParser::addParameter(std::string const& parameter) { //STORM_LOG_THROW((std::is_same::value), storm::exceptions::NotSupportedException, "Parameters only allowed when using rational functions."); storm::expressions::Variable var = manager->declareRationalVariable(parameter); identifierMapping.emplace(var.getName(), var); parser.setIdentifierMapping(identifierMapping); STORM_LOG_TRACE("Added parameter: " << var.getName()); } template<> double ValueParser::parseValue(std::string const& value) const { return boost::lexical_cast(value); } template<> storm::RationalFunction ValueParser::parseValue(std::string const& value) const { storm::RationalFunction rationalFunction = evaluator.asRational(parser.parseFromString(value)); STORM_LOG_TRACE("Parsed expression: " << rationalFunction); return rationalFunction; } template std::shared_ptr> DirectEncodingParser::parseModel(std::string const& filename) { // Load file STORM_LOG_INFO("Reading from file " << filename); std::ifstream file; storm::utility::openFile(filename, file); std::string line; // Initialize ValueParser valueParser; // Parse header std::getline(file, line); STORM_LOG_THROW(line == "// Exported by storm", storm::exceptions::WrongFormatException, "Expected header information."); std::getline(file, line); STORM_LOG_THROW(boost::starts_with(line, "// Original model type: "), storm::exceptions::WrongFormatException, "Expected header information."); // Parse model type std::getline(file, line); STORM_LOG_THROW(boost::starts_with(line, "@type: "), storm::exceptions::WrongFormatException, "Expected model type."); storm::models::ModelType type = storm::models::getModelType(line.substr(7)); STORM_LOG_TRACE("Model type: " << type); // Parse parameters std::getline(file, line); STORM_LOG_THROW(line == "@parameters", storm::exceptions::WrongFormatException, "Expected parameter declaration."); std::getline(file, line); if (line != "") { std::vector parameters; boost::split(parameters, line, boost::is_any_of(" ")); for (std::string parameter : parameters) { STORM_LOG_TRACE("New parameter: " << parameter); valueParser.addParameter(parameter); } } // Parse no. states std::getline(file, line); STORM_LOG_THROW(line == "@nr_states", storm::exceptions::WrongFormatException, "Expected number of states."); std::getline(file, line); size_t nrStates = boost::lexical_cast(line); STORM_LOG_TRACE("Model type: " << type); std::getline(file, line); STORM_LOG_THROW(line == "@model", storm::exceptions::WrongFormatException, "Expected model declaration."); // Construct transition matrix std::shared_ptr> modelComponents = parseStates(file, type, nrStates, valueParser); // Done parsing storm::utility::closeFile(file); // Build model switch (type) { case storm::models::ModelType::Dtmc: { STORM_LOG_THROW(false, storm::exceptions::FileIoException, "DTMC not supported."); } case storm::models::ModelType::Ctmc: { modelComponents->rateTransitions = true; return std::make_shared>(std::move(*modelComponents)); } case storm::models::ModelType::Mdp: { STORM_LOG_THROW(false, storm::exceptions::FileIoException, "MDP not supported."); } case storm::models::ModelType::MarkovAutomaton: { modelComponents->rateTransitions = true; return std::make_shared>(std::move(*modelComponents)); } default: STORM_LOG_THROW(false, storm::exceptions::FileIoException, "Unknown/Unhandled model type " << type << " which cannot be parsed."); } } template std::shared_ptr> DirectEncodingParser::parseStates(std::istream& file, storm::models::ModelType type, size_t stateSize, ValueParser const& valueParser) { // Initialize auto modelComponents = std::make_shared>(); bool nonDeterministic = (type == storm::models::ModelType::Mdp || type == storm::models::ModelType::MarkovAutomaton); storm::storage::SparseMatrixBuilder builder = storm::storage::SparseMatrixBuilder(0, 0, 0, false, nonDeterministic, 0); modelComponents->stateLabeling = storm::models::sparse::StateLabeling(stateSize); // Iterate over all lines std::string line; size_t row = 0; size_t state = 0; bool first = true; while (std::getline(file, line)) { STORM_LOG_TRACE("Parsing: " << line); if (boost::starts_with(line, "state ")) { // New state if (first) { first = false; } else { ++state; } line = line.substr(6); size_t parsedId; size_t posId = line.find(" "); if (posId != std::string::npos) { parsedId = boost::lexical_cast(line.substr(0, posId)); // Parse rewards and labels line = line.substr(posId+1); // Check for rewards if (boost::starts_with(line, "[")) { // Rewards found size_t posEndReward = line.find(']'); STORM_LOG_THROW(posEndReward != std::string::npos, storm::exceptions::WrongFormatException, "] missing."); std::string rewards = line.substr(1, posEndReward-1); STORM_LOG_TRACE("State rewards: " << rewards); // TODO import rewards STORM_LOG_WARN("Rewards were not imported"); line = line.substr(posEndReward+1); } // Check for labels std::vector labels; boost::split(labels, line, boost::is_any_of(" ")); for (std::string label : labels) { if (!modelComponents->stateLabeling.containsLabel(label)) { modelComponents->stateLabeling.addLabel(label); } modelComponents->stateLabeling.addLabelToState(label, state); STORM_LOG_TRACE("New label: " << label); } } else { // Only state id given parsedId = boost::lexical_cast(line); } STORM_LOG_TRACE("New state " << state); STORM_LOG_ASSERT(state == parsedId, "State ids do not correspond."); if (nonDeterministic) { builder.newRowGroup(row); } } else if (boost::starts_with(line, "\taction ")) { // New action if (first) { first = false; } else { ++row; } line = line.substr(8); STORM_LOG_TRACE("New action: " << row); // Check for rewards if (boost::starts_with(line, "[")) { // Rewards found size_t posEndReward = line.find(']'); STORM_LOG_THROW(posEndReward != std::string::npos, storm::exceptions::WrongFormatException, "] missing."); std::string rewards = line.substr(1, posEndReward-1); STORM_LOG_TRACE("Transition rewards: " << rewards); // TODO save rewards line = line.substr(posEndReward+1); } // TODO import choice labeling when the export works } else { // New transition size_t posColon = line.find(":"); STORM_LOG_ASSERT(posColon != std::string::npos, "':' not found."); size_t target = boost::lexical_cast(line.substr(2, posColon-3)); std::string valueStr = line.substr(posColon+2); ValueType value = valueParser.parseValue(valueStr); STORM_LOG_TRACE("Transition " << state << " -> " << target << ": " << value); builder.addNextValue(state, target, value); } } STORM_LOG_TRACE("Finished parsing"); modelComponents->transitionMatrix = builder.build(stateSize, stateSize); STORM_LOG_TRACE("Built matrix"); return modelComponents; } // Template instantiations. template class DirectEncodingParser; #ifdef STORM_HAVE_CARL template class DirectEncodingParser; #endif } // namespace parser } // namespace storm