From 6fcebed10eafa1c15a3b12f16949d164b36a3d56 Mon Sep 17 00:00:00 2001 From: Matthias Volk Date: Sun, 4 Nov 2018 23:01:02 +0100 Subject: [PATCH] More robust handling of BE arguments in Galileo format --- src/storm-dft/parser/DFTGalileoParser.cpp | 140 +++++++++++++++------- src/storm-dft/parser/DFTGalileoParser.h | 26 +++- 2 files changed, 124 insertions(+), 42 deletions(-) diff --git a/src/storm-dft/parser/DFTGalileoParser.cpp b/src/storm-dft/parser/DFTGalileoParser.cpp index 21323bc4b..eac7e2c66 100644 --- a/src/storm-dft/parser/DFTGalileoParser.cpp +++ b/src/storm-dft/parser/DFTGalileoParser.cpp @@ -144,7 +144,7 @@ namespace storm { ValueType probability = valueParser.parseValue(type.substr(5)); success = builder.addDepElement(name, childNames, probability); } else if (type.find("=") != std::string::npos) { - success = parseBasicElement(tokens, builder, valueParser); + success = parseBasicElement(name, line, builder, valueParser); } else { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Type name: " << type << " in line " << lineNo << " not recognized."); success = false; @@ -168,52 +168,112 @@ namespace storm { } template - bool DFTGalileoParser::parseBasicElement(std::vector const& tokens, storm::builder::DFTBuilder& builder, ValueParser& valueParser) { + std::pair DFTGalileoParser::parseValue(std::string name, std::string& line, ValueParser& valueParser) { + // Build regex for: name=(value) + std::regex lambdaRegex(name + "\\s*=\\s*([^\\s]*)"); + std::smatch match; + if (std::regex_search(line, match, lambdaRegex)) { + std::string value = match.str(1); + // Remove matched part + line = std::regex_replace(line, lambdaRegex, ""); + return std::make_pair(true, valueParser.parseValue(value)); + } else { + // No match found + return std::make_pair(false, storm::utility::zero()); + } + } + + template + std::pair DFTGalileoParser::parseNumber(std::string name, std::string& line) { + // Build regex for: name=(number) + std::regex lambdaRegex(name + "\\s*=\\s*([[:digit:]]+)"); + std::smatch match; + if (std::regex_search(line, match, lambdaRegex)) { + std::string value = match.str(1); + // Remove matched part + line = std::regex_replace(line, lambdaRegex, ""); + return std::make_pair(true, NumberParser::parse(value)); + } else { + // No match found + return std::make_pair(false, 0); + } + } + + template + bool DFTGalileoParser::parseBasicElement(std::string const& name, std::string const& input, storm::builder::DFTBuilder& builder, ValueParser& valueParser) { // Default values Distribution distribution = Distribution::None; ValueType firstValDistribution = storm::utility::zero(); ValueType secondValDistribution = storm::utility::zero(); ValueType dormancyFactor = storm::utility::one(); size_t replication = 1; + // Remove name from input + std::regex regexName("\"?" + name + "\"?"); + std::string line = std::regex_replace(input, regexName, ""); // Parse properties and determine distribution - for (size_t i = 1; i < tokens.size(); ++i) { - std::string token = tokens[i]; - if (boost::starts_with(token, "prob=")) { - STORM_LOG_THROW(distribution == Distribution::None, storm::exceptions::WrongFormatException, "A different distribution was already defined for this basic element."); - firstValDistribution = valueParser.parseValue(token.substr(5)); - distribution = Distribution::Constant; - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Constant distribution is not supported."); - } else if (boost::starts_with(token, "lambda=")) { - STORM_LOG_THROW(distribution == Distribution::None, storm::exceptions::WrongFormatException, "A different distribution was already defined for this basic element."); - firstValDistribution = valueParser.parseValue(token.substr(7)); - distribution = Distribution::Exponential; - } else if (boost::starts_with(token, "rate=")) { - STORM_LOG_THROW(distribution == Distribution::None || distribution == Distribution::Weibull, storm::exceptions::WrongFormatException, "A different distribution was already defined for this basic element."); - firstValDistribution = valueParser.parseValue(token.substr(5)); - distribution = Distribution::Weibull; - } else if (boost::starts_with(token, "shape=")) { - STORM_LOG_THROW(distribution == Distribution::None || distribution == Distribution::Weibull, storm::exceptions::WrongFormatException, "A different distribution was already defined for this basic element."); - secondValDistribution = valueParser.parseValue(token.substr(6)); - distribution = Distribution::Weibull; - } else if (boost::starts_with(token, "mean=")) { - STORM_LOG_THROW(distribution == Distribution::None || distribution == Distribution::LogNormal, storm::exceptions::WrongFormatException, "A different distribution was already defined for this basic element."); - firstValDistribution = valueParser.parseValue(token.substr(5)); - distribution = Distribution::LogNormal; - } else if (boost::starts_with(token, "stddev=")) { - STORM_LOG_THROW(distribution == Distribution::None || distribution == Distribution::LogNormal, storm::exceptions::WrongFormatException, "A different distribution was already defined for this basic element."); - secondValDistribution = valueParser.parseValue(token.substr(7)); - distribution = Distribution::LogNormal; - } else if (boost::starts_with(token, "cov=")) { - STORM_LOG_WARN("Coverage is not supported and will be ignored."); - } else if (boost::starts_with(token, "res=")) { - STORM_LOG_WARN("Restoration is not supported and will be ignored."); - } else if (boost::starts_with(token, "repl=")) { - replication = NumberParser::parse(token.substr(5)); - STORM_LOG_THROW(replication == 1, storm::exceptions::NotSupportedException, "Replication > 1 is not supported."); - } else if (boost::starts_with(token, "dorm=")) { - dormancyFactor = valueParser.parseValue(token.substr(5)); - } + // Constant distribution + std::pair result = parseValue("prob", line, valueParser); + if (result.first) { + STORM_LOG_THROW(distribution == Distribution::None, storm::exceptions::WrongFormatException, "A different distribution was already defined for this basic element."); + firstValDistribution = result.second; + distribution = Distribution::Constant; + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Constant distribution is not supported."); + } + // Exponential distribution + result = parseValue("lambda", line, valueParser); + if (result.first) { + STORM_LOG_THROW(distribution == Distribution::None, storm::exceptions::WrongFormatException, "A different distribution was already defined for this basic element."); + firstValDistribution = result.second; + distribution = Distribution::Exponential; + } + // Weibull distribution + result = parseValue("rate", line, valueParser); + if (result.first) { + STORM_LOG_THROW(distribution == Distribution::None || distribution == Distribution::Weibull, storm::exceptions::WrongFormatException, "A different distribution was already defined for this basic element."); + firstValDistribution = result.second; + distribution = Distribution::Weibull; + } + result = parseValue("shape", line, valueParser); + if (result.first) { + STORM_LOG_THROW(distribution == Distribution::None || distribution == Distribution::Weibull, storm::exceptions::WrongFormatException, "A different distribution was already defined for this basic element."); + secondValDistribution = result.second; + distribution = Distribution::Weibull; + } + // Lognormal distribution + result = parseValue("mean", line, valueParser); + if (result.first) { + STORM_LOG_THROW(distribution == Distribution::None || distribution == Distribution::LogNormal, storm::exceptions::WrongFormatException, "A different distribution was already defined for this basic element."); + firstValDistribution = result.second; + distribution = Distribution::LogNormal; + } + result = parseValue("stddev", line, valueParser); + if (result.first) { + STORM_LOG_THROW(distribution == Distribution::None || distribution == Distribution::LogNormal, storm::exceptions::WrongFormatException, "A different distribution was already defined for this basic element."); + secondValDistribution = result.second; + distribution = Distribution::LogNormal; + } + // Additional arguments + result = parseValue("cov", line, valueParser); + if (result.first) { + STORM_LOG_WARN("Coverage is not supported and will be ignored."); + } + result = parseValue("res", line, valueParser); + if (result.first) { + STORM_LOG_WARN("Restoration is not supported and will be ignored."); + } + std::pair resultNum = parseNumber("repl", line); + if (result.first) { + replication = resultNum.second; + STORM_LOG_THROW(replication == 1, storm::exceptions::NotSupportedException, "Replication > 1 is not supported."); + } + result = parseValue("dorm", line, valueParser); + if (result.first) { + dormancyFactor = result.second; + } + boost::trim(line); + if (line != "") { + STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Unknown arguments: " << line << "."); } switch (distribution) { @@ -221,7 +281,7 @@ namespace storm { STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Constant distribution is not supported."); break; case Exponential: - return builder.addBasicElement(parseName(tokens[0]), firstValDistribution, dormancyFactor, false); // TODO set transient BEs + return builder.addBasicElement(parseName(name), firstValDistribution, dormancyFactor, false); // TODO set transient BEs break; case Weibull: STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Weibull distribution is not supported."); diff --git a/src/storm-dft/parser/DFTGalileoParser.h b/src/storm-dft/parser/DFTGalileoParser.h index f956d8cb9..a92627ba0 100644 --- a/src/storm-dft/parser/DFTGalileoParser.h +++ b/src/storm-dft/parser/DFTGalileoParser.h @@ -45,13 +45,35 @@ namespace storm { /*! * Parse basic element and add it to builder. * - * @param tokens Tokens defining the basic element. + * @param name Name of BE. + * @param input Input line. * @param builder DFTBuilder. * @param valueParser ValueParser. * * @return True iff the parsing and creation was successful. */ - static bool parseBasicElement(std::vector const& tokens, storm::builder::DFTBuilder& builder, ValueParser& valueParser); + static bool parseBasicElement(std::string const& name, std::string const& input, storm::builder::DFTBuilder& builder, ValueParser& valueParser); + + /*! + * Parse argument of basic element of the form "name=value". + * + * @param name Name of BE. + * @param input Input line. The parsed argument will be removed from the line. + * @param valueParser ValueParser. + * + * @return Pair (success, value). Success is true iff the parsing was succesful. Then value contains the parsed value. + */ + static std::pair parseValue(std::string name, std::string& line, ValueParser& valueParser); + + /*! + * Parse argument of basic element of type number: "name=number". + * + * @param name Name of BE. + * @param input Input line. The parsed argument will be removed from the line. + * + * @return Pair (success, value). Success is true iff the parsing was succesful. Then value contains the parsed value. + */ + static std::pair parseNumber(std::string name, std::string& line); enum Distribution { None, Constant, Exponential, Weibull, LogNormal }; };