From ee87c50313690a96374f7febd1dcfbb9b033fd30 Mon Sep 17 00:00:00 2001 From: TimQu <tim.quatmann@cs.rwth-aachen.de> Date: Thu, 13 Sep 2018 13:33:31 +0200 Subject: [PATCH] fixed some issues related to jani parsing --- src/storm-parsers/parser/JaniParser.cpp | 76 +++++++++++++++++-------- src/storm/storage/jani/LValue.cpp | 2 +- 2 files changed, 53 insertions(+), 25 deletions(-) diff --git a/src/storm-parsers/parser/JaniParser.cpp b/src/storm-parsers/parser/JaniParser.cpp index 63423299d..4c897b5a1 100644 --- a/src/storm-parsers/parser/JaniParser.cpp +++ b/src/storm-parsers/parser/JaniParser.cpp @@ -67,7 +67,6 @@ namespace storm { return static_cast<int64_t>(num); } - std::pair<storm::jani::Model, std::map<std::string, storm::jani::Property>> JaniParser::parse(std::string const& path) { JaniParser parser; parser.readFile(path); @@ -107,6 +106,8 @@ namespace storm { model.getModelFeatures().add(storm::jani::ModelFeature::Arrays); } else if (featureStr == "derived-operators") { model.getModelFeatures().add(storm::jani::ModelFeature::DerivedOperators); + } else if (featureStr == "functions") { + model.getModelFeatures().add(storm::jani::ModelFeature::Functions); } else if (featureStr == "state-exit-rewards") { model.getModelFeatures().add(storm::jani::ModelFeature::StateExitRewards); } else { @@ -480,7 +481,7 @@ namespace storm { assert(args.size() == 1); return std::make_shared<storm::logic::UnaryBooleanStateFormula const>(storm::logic::UnaryBooleanStateFormula::OperatorType::Not, args[0]); - } else if (opString == "≥" || opString == "≤" || opString == "<" || opString == ">") { + } else if (opString == "≥" || opString == "≤" || opString == "<" || opString == ">" || opString == "=" || opString == "≠") { assert(bound == boost::none); storm::logic::ComparisonType ct; if(opString == "≥") { @@ -492,17 +493,38 @@ namespace storm { } else if (opString == ">") { ct = storm::logic::ComparisonType::Greater; } - if (propertyStructure.at("left").count("op") > 0 && (propertyStructure.at("left").at("op") == "Pmin" || propertyStructure.at("left").at("op") == "Pmax" || propertyStructure.at("left").at("op") == "Emin" || propertyStructure.at("left").at("op") == "Emax" || propertyStructure.at("left").at("op") == "Smin" || propertyStructure.at("left").at("op") == "Smax")) { - auto expr = parseExpression(propertyStructure.at("right"), "Threshold for operator " + propertyStructure.at("left").at("op").get<std::string>(),{},{}); - STORM_LOG_THROW(expr.getVariables().empty(), storm::exceptions::NotSupportedException, "Only constant thresholds supported"); - return parseFormula(propertyStructure.at("left"), formulaContext, globalVars, constants, "", storm::logic::Bound(ct, expr)); - - } else if(propertyStructure.at("right").count("op") > 0 && (propertyStructure.at("right").at("op") == "Pmin" || propertyStructure.at("right").at("op") == "Pmax" || propertyStructure.at("right").at("op") == "Emin" || propertyStructure.at("right").at("op") == "Emax" || propertyStructure.at("right").at("op") == "Smin" || propertyStructure.at("right").at("op") == "Smax")) { - auto expr = parseExpression(propertyStructure.at("left"), "Threshold for operator " + propertyStructure.at("right").at("op").get<std::string>(),{},{}); - return parseFormula(propertyStructure.at("right"),formulaContext, globalVars, constants, "", storm::logic::Bound(ct, expr)); - } else { - STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "No complex comparisons are allowed."); + + std::vector<std::string> const leftRight = {"left", "right"}; + for (uint64_t i = 0; i < 2; ++i) { + if (propertyStructure.at(leftRight[i]).count("op") > 0) { + std::string propertyOperatorString = getString(propertyStructure.at(leftRight[i]).at("op"), "property-operator"); + std::set<std::string> const propertyOperatorStrings = {"Pmin", "Pmax","Emin", "Emax", "Smin", "Smax"}; + if (propertyOperatorStrings.count(propertyOperatorString) > 0) { + auto boundExpr = parseExpression(propertyStructure.at(leftRight[1-i]), "Threshold for operator " + propertyStructure.at(leftRight[i]).at("op").get<std::string>(), {}, constants); + if ((opString == "=" || opString == "≠")) { + STORM_LOG_THROW(!boundExpr.containsVariables(), storm::exceptions::NotSupportedException, "Comparison operators '=' or '≠' in property specifications are currently not supported."); + auto boundValue = boundExpr.evaluateAsRational(); + if (storm::utility::isZero(boundValue)) { + if (opString == "=") { + ct = storm::logic::ComparisonType::LessEqual; + } else { + ct = storm::logic::ComparisonType::Greater; + } + } else if (storm::utility::isOne(boundValue) && (propertyOperatorString == "Pmin" || propertyOperatorString == "Pmax")) { + if (opString == "=") { + ct = storm::logic::ComparisonType::GreaterEqual; + } else { + ct = storm::logic::ComparisonType::Less; + } + } else { + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Comparison operators '=' or '≠' in property specifications are currently not supported."); + } + } + return parseFormula(propertyStructure.at(leftRight[i]), formulaContext, globalVars, constants, "", storm::logic::Bound(ct, boundExpr)); + } + } } + STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "No complex comparisons for properties are supported."); } else { STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Unknown operator " << opString); } @@ -914,26 +936,26 @@ namespace storm { } storm::expressions::Expression JaniParser::parseExpression(json const& expressionStructure, std::string const& scopeDescription, VariablesMap const& globalVars, ConstantsMap const& constants, VariablesMap const& localVars, bool returnNoneInitializedOnUnknownOperator, std::unordered_map<std::string, storm::expressions::Variable> const& auxiliaryVariables) { - if(expressionStructure.is_boolean()) { - if(expressionStructure.get<bool>()) { + if (expressionStructure.is_boolean()) { + if (expressionStructure.get<bool>()) { return expressionManager->boolean(true); } else { return expressionManager->boolean(false); } - } else if(expressionStructure.is_number_integer()) { + } else if (expressionStructure.is_number_integer()) { return expressionManager->integer(expressionStructure.get<int64_t>()); - } else if(expressionStructure.is_number_float()) { + } else if (expressionStructure.is_number_float()) { // For now, just take the double. // TODO make this a rational number return expressionManager->rational(expressionStructure.get<double>()); - } else if(expressionStructure.is_string()) { + } else if (expressionStructure.is_string()) { std::string ident = expressionStructure.get<std::string>(); - return storm::expressions::Expression(getVariableOrConstantExpression(ident, scopeDescription, globalVars, constants, localVars)); - } else if(expressionStructure.is_object()) { - if(expressionStructure.count("distribution") == 1) { + return storm::expressions::Expression(getVariableOrConstantExpression(ident, scopeDescription, globalVars, constants, localVars, auxiliaryVariables)); + } else if (expressionStructure.is_object()) { + if (expressionStructure.count("distribution") == 1) { STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Distributions are not supported by storm expressions, cannot import " << expressionStructure.dump() << " in " << scopeDescription << "."); } - if(expressionStructure.count("op") == 1) { + if (expressionStructure.count("op") == 1) { std::string opstring = getString(expressionStructure.at("op"), scopeDescription); std::vector<storm::expressions::Expression> arguments = {}; if(opstring == "ite") { @@ -985,6 +1007,9 @@ namespace storm { } else if (opstring == "=") { arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); + if(!arguments[0].isInitialized() || !arguments[1].isInitialized()) { + return storm::expressions::Expression(); + } if(arguments[0].hasBooleanType()) { ensureBooleanType(arguments[1], opstring, 1, scopeDescription); return storm::expressions::iff(arguments[0], arguments[1]); @@ -995,6 +1020,9 @@ namespace storm { } else if (opstring == "≠") { arguments = parseBinaryExpressionArguments(expressionStructure, opstring, scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, auxiliaryVariables); assert(arguments.size() == 2); + if(!arguments[0].isInitialized() || !arguments[1].isInitialized()) { + return storm::expressions::Expression(); + } if(arguments[0].hasBooleanType()) { ensureBooleanType(arguments[1], opstring, 1, scopeDescription); return storm::expressions::xclusiveor(arguments[0], arguments[1]); @@ -1165,10 +1193,10 @@ namespace storm { std::string indexVarName = getString(expressionStructure.at("var"), "Field 'var' of Array access operator (at " + scopeDescription + ")."); STORM_LOG_THROW(auxiliaryVariables.find(indexVarName) == auxiliaryVariables.end(), storm::exceptions::InvalidJaniException, "Index variable " << indexVarName << " is already defined as an auxiliary variable (at " + scopeDescription + ")."); auto newAuxVars = auxiliaryVariables; - storm::expressions::Variable indexVar = expressionManager->declareIntegerVariable(indexVarName); + storm::expressions::Variable indexVar = expressionManager->declareFreshIntegerVariable(false, "ac_" + indexVarName); newAuxVars.emplace(indexVarName, indexVar); - STORM_LOG_THROW(expressionStructure.count("exp") == 1, storm::exceptions::InvalidJaniException, "Array access operator requires exactly one exp (at " + scopeDescription + ")."); - storm::expressions::Expression exp = parseExpression(expressionStructure.at("exp"), "exp in " + scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, newAuxVars); + STORM_LOG_THROW(expressionStructure.count("exp") == 1, storm::exceptions::InvalidJaniException, "Array constructor operator requires exactly one exp (at " + scopeDescription + ")."); + storm::expressions::Expression exp = parseExpression(expressionStructure.at("exp"), "exp of array constructor in " + scopeDescription, globalVars, constants, localVars, returnNoneInitializedOnUnknownOperator, newAuxVars); return std::make_shared<storm::expressions::ConstructorArrayExpression>(*expressionManager, expressionManager->getArrayType(exp.getType()), length.getBaseExpressionPointer(), indexVar, exp.getBaseExpressionPointer())->toExpression(); } else if (unsupportedOpstrings.count(opstring) > 0){ STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Opstring " + opstring + " is not supported by storm"); diff --git a/src/storm/storage/jani/LValue.cpp b/src/storm/storage/jani/LValue.cpp index 27788db78..7ae2b3e42 100644 --- a/src/storm/storage/jani/LValue.cpp +++ b/src/storm/storage/jani/LValue.cpp @@ -77,7 +77,7 @@ namespace storm { return other.isVariable() && getVariable().getExpressionVariable() == other.getVariable().getExpressionVariable(); } else { STORM_LOG_ASSERT(isArrayAccess(), "Unhandled LValue."); - return other.isArrayAccess() && getVariable().getExpressionVariable() == other.getVariable().getExpressionVariable() && getArrayIndex().isSyntacticallyEqual(other.getArrayIndex()); + return other.isArrayAccess() && getArray().getExpressionVariable() == other.getArray().getExpressionVariable() && getArrayIndex().isSyntacticallyEqual(other.getArrayIndex()); } }