Browse Source

Merge pull request 'Merge SMG LRA MC' (#4) from smg_lra_model_checking into main

Reviewed-on: http://git.pranger.xyz/TEMPEST/tempest-devel/pulls/4

WIP w.r.t. debug output, will be fixed in the future
main
Stefan Pranger 4 years ago
parent
commit
fd87e0ef2d
  1. 5
      CMakeLists.txt
  2. 164
      src/storm-parsers/parser/FormulaParserGrammar.cpp
  3. 68
      src/storm-parsers/parser/FormulaParserGrammar.h
  4. 4
      src/storm-parsers/parser/PrismParser.cpp
  5. 14
      src/storm/api/verification.h
  6. 5
      src/storm/builder/ExplicitModelBuilder.cpp
  7. 18
      src/storm/builder/ExplicitModelBuilder.h
  8. 20
      src/storm/environment/solver/MultiplierEnvironment.cpp
  9. 18
      src/storm/environment/solver/MultiplierEnvironment.h
  10. 52
      src/storm/generator/Choice.cpp
  11. 16
      src/storm/generator/Choice.h
  12. 34
      src/storm/logic/CloneVisitor.cpp
  13. 56
      src/storm/logic/FragmentChecker.cpp
  14. 224
      src/storm/logic/FragmentSpecification.cpp
  15. 38
      src/storm/logic/FragmentSpecification.h
  16. 6
      src/storm/logic/GameFormula.cpp
  17. 2
      src/storm/logic/GameFormula.h
  18. 36
      src/storm/logic/LiftableTransitionRewardsVisitor.cpp
  19. 2
      src/storm/modelchecker/AbstractModelChecker.cpp
  20. 4
      src/storm/modelchecker/helper/infinitehorizon/SparseInfiniteHorizonHelper.h
  21. 135
      src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.cpp
  22. 73
      src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.h
  23. 120
      src/storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.cpp
  24. 9
      src/storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.h
  25. 59
      src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.cpp
  26. 5
      src/storm/models/sparse/Smg.cpp
  27. 2
      src/storm/models/sparse/Smg.h
  28. 108
      src/storm/solver/GmmxxMultiplier.cpp
  29. 40
      src/storm/solver/Multiplier.cpp
  30. 56
      src/storm/solver/Multiplier.h
  31. 56
      src/storm/storage/Decomposition.cpp
  32. 281
      src/storm/storage/GameMaximalEndComponentDecomposition.cpp
  33. 109
      src/storm/storage/GameMaximalEndComponentDecomposition.h
  34. 66
      src/storm/storage/MaximalEndComponent.cpp
  35. 593
      src/storm/storage/SparseMatrix.cpp
  36. 164
      src/storm/storage/jani/JSONExporter.cpp
  37. 6
      src/storm/storage/prism/Program.h
  38. 2
      src/storm/utility/Engine.cpp

5
CMakeLists.txt

@ -325,6 +325,11 @@ if (STORM_DEVELOPER)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-float-equal")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-local-typedef")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-missing-variable-declarations")
elseif (GCC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wunused")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unknown-pragmas")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-local-typedefs")
endif ()
else ()
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wextra")

164
src/storm-parsers/parser/FormulaParserGrammar.cpp

@ -3,7 +3,7 @@
namespace storm {
namespace parser {
FormulaParserGrammar::FormulaParserGrammar(std::shared_ptr<storm::expressions::ExpressionManager const> const& manager) : FormulaParserGrammar::base_type(start), constManager(manager), manager(nullptr), expressionParser(*manager, keywords_, true, true), propertyCount(0) {
initialize();
}
@ -16,72 +16,72 @@ namespace storm {
// Register all variables so we can parse them in the expressions.
for (auto variableTypePair : *constManager) {
identifiers_.add(variableTypePair.first.getName(), variableTypePair.first);
}
}
// Set the identifier mapping to actually generate expressions.
expressionParser.setIdentifierMapping(&identifiers_);
longRunAverageRewardFormula = (qi::lit("LRA") | qi::lit("S") | qi::lit("MP"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createLongRunAverageRewardFormula, phoenix::ref(*this))];
longRunAverageRewardFormula.name("long run average reward formula");
instantaneousRewardFormula = (qi::lit("I=") > expressionParser)[qi::_val = phoenix::bind(&FormulaParserGrammar::createInstantaneousRewardFormula, phoenix::ref(*this), qi::_1)];
instantaneousRewardFormula.name("instantaneous reward formula");
cumulativeRewardFormula = (qi::lit("C") >> timeBounds)[qi::_val = phoenix::bind(&FormulaParserGrammar::createCumulativeRewardFormula, phoenix::ref(*this), qi::_1)];
cumulativeRewardFormula.name("cumulative reward formula");
totalRewardFormula = (qi::lit("C"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createTotalRewardFormula, phoenix::ref(*this))];
totalRewardFormula.name("total reward formula");
rewardPathFormula = longRunAverageRewardFormula | conditionalFormula(storm::logic::FormulaContext::Reward) | eventuallyFormula(storm::logic::FormulaContext::Reward) | cumulativeRewardFormula | instantaneousRewardFormula | totalRewardFormula;
rewardPathFormula.name("reward path formula");
expressionFormula = expressionParser[qi::_val = phoenix::bind(&FormulaParserGrammar::createAtomicExpressionFormula, phoenix::ref(*this), qi::_1)];
expressionFormula.name("expression formula");
label = qi::as_string[qi::raw[qi::lexeme[((qi::alpha | qi::char_('_')) >> *(qi::alnum | qi::char_('_')))]]];
label.name("label");
labelFormula = (qi::lit("\"") >> label >> qi::lit("\""))[qi::_val = phoenix::bind(&FormulaParserGrammar::createAtomicLabelFormula, phoenix::ref(*this), qi::_1)];
labelFormula.name("label formula");
booleanLiteralFormula = (qi::lit("true")[qi::_a = true] | qi::lit("false")[qi::_a = false])[qi::_val = phoenix::bind(&FormulaParserGrammar::createBooleanLiteralFormula, phoenix::ref(*this), qi::_a)];
booleanLiteralFormula.name("boolean literal formula");
operatorFormula = probabilityOperator | rewardOperator | longRunAverageOperator | timeOperator;
operatorFormula.name("operator formulas");
atomicStateFormula = booleanLiteralFormula | labelFormula | expressionFormula | (qi::lit("(") > stateFormula > qi::lit(")")) | operatorFormula;
atomicStateFormula.name("atomic state formula");
atomicStateFormulaWithoutExpression = booleanLiteralFormula | labelFormula | (qi::lit("(") > stateFormula > qi::lit(")")) | operatorFormula;
atomicStateFormula.name("atomic state formula without expression");
notStateFormula = (unaryBooleanOperator_ >> atomicStateFormulaWithoutExpression)[qi::_val = phoenix::bind(&FormulaParserGrammar::createUnaryBooleanStateFormula, phoenix::ref(*this), qi::_2, qi::_1)] | atomicStateFormula[qi::_val = qi::_1];
notStateFormula.name("negation formula");
eventuallyFormula = (qi::lit("F") >> (-timeBounds) >> pathFormulaWithoutUntil(qi::_r1))[qi::_val = phoenix::bind(&FormulaParserGrammar::createEventuallyFormula, phoenix::ref(*this), qi::_1, qi::_r1, qi::_2)];
eventuallyFormula.name("eventually formula");
globallyFormula = (qi::lit("G") >> pathFormulaWithoutUntil(qi::_r1))[qi::_val = phoenix::bind(&FormulaParserGrammar::createGloballyFormula, phoenix::ref(*this), qi::_1)];
globallyFormula.name("globally formula");
nextFormula = (qi::lit("X") >> pathFormulaWithoutUntil(qi::_r1))[qi::_val = phoenix::bind(&FormulaParserGrammar::createNextFormula, phoenix::ref(*this), qi::_1)];
nextFormula.name("next formula");
pathFormulaWithoutUntil = eventuallyFormula(qi::_r1) | globallyFormula(qi::_r1) | nextFormula(qi::_r1) | stateFormula;
pathFormulaWithoutUntil.name("path formula");
untilFormula = pathFormulaWithoutUntil(qi::_r1)[qi::_val = qi::_1] >> *(qi::lit("U") >> (-timeBounds) >> pathFormulaWithoutUntil(qi::_r1))[qi::_val = phoenix::bind(&FormulaParserGrammar::createUntilFormula, phoenix::ref(*this), qi::_val, qi::_1, qi::_2)];
untilFormula.name("until formula");
conditionalFormula = untilFormula(qi::_r1)[qi::_val = qi::_1] >> *(qi::lit("||") >> untilFormula(storm::logic::FormulaContext::Probability))[qi::_val = phoenix::bind(&FormulaParserGrammar::createConditionalFormula, phoenix::ref(*this), qi::_val, qi::_1, qi::_r1)];
conditionalFormula.name("conditional formula");
timeBoundReference = (-qi::lit("rew") >> rewardModelName)[qi::_val = phoenix::bind(&FormulaParserGrammar::createTimeBoundReference, phoenix::ref(*this), storm::logic::TimeBoundType::Reward, qi::_1)]
| (qi::lit("steps"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createTimeBoundReference, phoenix::ref(*this), storm::logic::TimeBoundType::Steps, boost::none)]
| (-qi::lit("time"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createTimeBoundReference, phoenix::ref(*this), storm::logic::TimeBoundType::Time, boost::none)];
timeBoundReference.name("time bound reference");
timeBound = ((timeBoundReference >> qi::lit("[")) > expressionParser > qi::lit(",") > expressionParser > qi::lit("]"))
[qi::_val = phoenix::bind(&FormulaParserGrammar::createTimeBoundFromInterval, phoenix::ref(*this), qi::_2, qi::_3, qi::_1)]
| ( timeBoundReference >> (qi::lit("<=")[qi::_a = true, qi::_b = false] | qi::lit("<")[qi::_a = true, qi::_b = true] | qi::lit(">=")[qi::_a = false, qi::_b = false] | qi::lit(">")[qi::_a = false, qi::_b = true]) >> expressionParser)
@ -89,46 +89,46 @@ namespace storm {
| ( timeBoundReference >> qi::lit("=") >> expressionParser)
[qi::_val = phoenix::bind(&FormulaParserGrammar::createTimeBoundFromInterval, phoenix::ref(*this), qi::_2, qi::_2, qi::_1)];
timeBound.name("time bound");
timeBounds = (timeBound % qi::lit(",")) | (((-qi::lit("^") >> qi::lit("{")) >> (timeBound % qi::lit(","))) >> qi::lit("}"));
timeBounds.name("time bounds");
pathFormula = conditionalFormula(qi::_r1);
pathFormula.name("path formula");
rewardMeasureType = qi::lit("[") >> rewardMeasureType_ >> qi::lit("]");
rewardMeasureType.name("reward measure type");
operatorInformation = (-optimalityOperator_[qi::_a = qi::_1] >> ((relationalOperator_[qi::_b = qi::_1] > expressionParser[qi::_c = qi::_1]) | (qi::lit("=") > qi::lit("?"))))[qi::_val = phoenix::bind(&FormulaParserGrammar::createOperatorInformation, phoenix::ref(*this), qi::_a, qi::_b, qi::_c)];
operatorInformation.name("operator information");
longRunAverageOperator = ((qi::lit("LRA") | qi::lit("S")) > operatorInformation > qi::lit("[") > stateFormula > qi::lit("]"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createLongRunAverageOperatorFormula, phoenix::ref(*this), qi::_1, qi::_2)];
longRunAverageOperator.name("long-run average operator");
rewardModelName = qi::lit("{\"") > label > qi::lit("\"}");
rewardModelName.name("reward model name");
rewardOperator = (qi::lit("R") > -rewardMeasureType > -rewardModelName > operatorInformation > qi::lit("[") > rewardPathFormula > qi::lit("]"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createRewardOperatorFormula, phoenix::ref(*this), qi::_1, qi::_2, qi::_3, qi::_4)];
rewardOperator.name("reward operator");
timeOperator = (qi::lit("T") > -rewardMeasureType > operatorInformation > qi::lit("[") > eventuallyFormula(storm::logic::FormulaContext::Time) > qi::lit("]"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createTimeOperatorFormula, phoenix::ref(*this), qi::_1, qi::_2, qi::_3)];
timeOperator.name("time operator");
probabilityOperator = (qi::lit("P") > operatorInformation > qi::lit("[") > pathFormula(storm::logic::FormulaContext::Probability) > qi::lit("]"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createProbabilityOperatorFormula, phoenix::ref(*this), qi::_1, qi::_2)];
probabilityOperator.name("probability operator");
andStateFormula = notStateFormula[qi::_val = qi::_1] >> *(qi::lit("&") >> notStateFormula)[qi::_val = phoenix::bind(&FormulaParserGrammar::createBinaryBooleanStateFormula, phoenix::ref(*this), qi::_val, qi::_1, storm::logic::BinaryBooleanStateFormula::OperatorType::And)];
andStateFormula.name("and state formula");
orStateFormula = andStateFormula[qi::_val = qi::_1] >> *(qi::lit("|") >> andStateFormula)[qi::_val = phoenix::bind(&FormulaParserGrammar::createBinaryBooleanStateFormula, phoenix::ref(*this), qi::_val, qi::_1, storm::logic::BinaryBooleanStateFormula::OperatorType::Or)];
orStateFormula.name("or state formula");
multiFormula = (qi::lit("multi") > qi::lit("(") >> ((pathFormula(storm::logic::FormulaContext::Probability) | stateFormula) % qi::lit(",")) >> qi::lit(")"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createMultiFormula, phoenix::ref(*this), qi::_1)];
multiFormula.name("Multi formula");
identifier %= qi::as_string[qi::raw[qi::lexeme[((qi::alpha | qi::char_('_') | qi::char_('.')) >> *(qi::alnum | qi::char_('_')))]]];
identifier.name("identifier");
quantileBoundVariable = (-(qi::lit("min")[qi::_a = storm::solver::OptimizationDirection::Minimize] | qi::lit("max")[qi::_a = storm::solver::OptimizationDirection::Maximize]) >> identifier >> qi::lit(","))[qi::_val = phoenix::bind(&FormulaParserGrammar::createQuantileBoundVariables, phoenix::ref(*this), qi::_a, qi::_1)];
quantileBoundVariable.name("quantile bound variable");
quantileFormula = (qi::lit("quantile") > qi::lit("(") >> *(quantileBoundVariable) >> stateFormula > qi::lit(")"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createQuantileFormula, phoenix::ref(*this), qi::_1, qi::_2)];
@ -140,18 +140,30 @@ namespace storm {
gameFormula = (qi::lit("<<") > playerCoalition > qi::lit(">>") > operatorFormula)[qi::_val = phoenix::bind(&FormulaParserGrammar::createGameFormula, phoenix::ref(*this), qi::_1, qi::_2)];
gameFormula.name("game formula");
stateFormula = (orStateFormula | multiFormula | quantileFormula | gameFormula);
coalitionOperator = (qi::lit("<<")
> *( (identifier[phoenix::push_back(qi::_a, qi::_1)]
| qi::int_[phoenix::push_back(qi::_a, qi::_1)]) % ','
)
> qi::lit(">>"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createCoalition, phoenix::ref(*this), qi::_a)];
coalitionOperator.name("coalition operator");
gameFormula = (coalitionOperator > operatorFormula)[qi::_val = phoenix::bind(&FormulaParserGrammar::createGameFormula, phoenix::ref(*this), qi::_1, qi::_2)];
gameFormula.name("game formula");
stateFormula = (orStateFormula | multiFormula | quantileFormula | gameFormula);
stateFormula.name("state formula");
formulaName = qi::lit("\"") >> identifier >> qi::lit("\"") >> qi::lit(":");
formulaName.name("formula name");
constantDefinition = (qi::lit("const") > -(qi::lit("int")[qi::_a = ConstantDataType::Integer] | qi::lit("bool")[qi::_a = ConstantDataType::Bool] | qi::lit("double")[qi::_a = ConstantDataType::Rational]) >> identifier >> -(qi::lit("=") > expressionParser))[phoenix::bind(&FormulaParserGrammar::addConstant, phoenix::ref(*this), qi::_1, qi::_a, qi::_2)];
constantDefinition.name("constant definition");
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Woverloaded-shift-op-parentheses"
filterProperty = (-formulaName >> qi::lit("filter") > qi::lit("(") > filterType_ > qi::lit(",") > stateFormula > qi::lit(",") > stateFormula > qi::lit(")"))[qi::_val = phoenix::bind(&FormulaParserGrammar::createProperty, phoenix::ref(*this), qi::_1, qi::_2, qi::_3, qi::_4)] | (-formulaName >> stateFormula)[qi::_val = phoenix::bind(&FormulaParserGrammar::createPropertyWithDefaultFilterTypeAndStates, phoenix::ref(*this), qi::_1, qi::_2)];
filterProperty.name("filter property");
@ -162,7 +174,7 @@ namespace storm {
| qi::eps)
% +(qi::char_("\n;")) >> qi::skip(storm::spirit_encoding::space_type() | qi::lit("//") >> *(qi::char_ - (qi::eol | qi::eoi)))[qi::eps] >> qi::eoi;
start.name("start");
// Enable the following lines to print debug output for most the rules.
// debug(start);
// debug(constantDefinition);
@ -188,7 +200,7 @@ namespace storm {
// debug(totalRewardFormula);
// debug(instantaneousRewardFormula);
// debug(multiFormula);
// Enable error reporting.
qi::on_error<qi::fail>(start, handler(qi::_1, qi::_2, qi::_3, qi::_4));
qi::on_error<qi::fail>(stateFormula, handler(qi::_1, qi::_2, qi::_3, qi::_4));
@ -216,16 +228,16 @@ namespace storm {
qi::on_error<qi::fail>(instantaneousRewardFormula, handler(qi::_1, qi::_2, qi::_3, qi::_4));
qi::on_error<qi::fail>(multiFormula, handler(qi::_1, qi::_2, qi::_3, qi::_4));
}
void FormulaParserGrammar::addIdentifierExpression(std::string const& identifier, storm::expressions::Expression const& expression) {
this->identifiers_.add(identifier, expression);
}
void FormulaParserGrammar::addConstant(std::string const& name, ConstantDataType type, boost::optional<storm::expressions::Expression> const& expression) {
STORM_LOG_ASSERT(manager, "Mutable expression manager required to define new constants.");
storm::expressions::Variable newVariable;
STORM_LOG_THROW(!manager->hasVariable(name), storm::exceptions::WrongFormatException, "Invalid constant definition '" << name << "' in property: variable already exists.");
if (type == ConstantDataType::Bool) {
newVariable = manager->declareBooleanVariable(name);
} else if (type == ConstantDataType::Integer) {
@ -233,7 +245,7 @@ namespace storm {
} else {
newVariable = manager->declareRationalVariable(name);
}
if (expression) {
addIdentifierExpression(name, expression.get());
} else {
@ -241,11 +253,11 @@ namespace storm {
addIdentifierExpression(name, newVariable);
}
}
bool FormulaParserGrammar::areConstantDefinitionsAllowed() const {
return static_cast<bool>(manager);
}
std::shared_ptr<storm::logic::TimeBoundReference> FormulaParserGrammar::createTimeBoundReference(storm::logic::TimeBoundType const& type, boost::optional<std::string> const& rewardModelName) const {
if (type == storm::logic::TimeBoundType::Reward) {
STORM_LOG_THROW(rewardModelName, storm::exceptions::WrongFormatException, "Reward bound does not specify a reward model name.");
@ -254,7 +266,7 @@ namespace storm {
return std::make_shared<storm::logic::TimeBoundReference>(type);
}
}
std::tuple<boost::optional<storm::logic::TimeBound>, boost::optional<storm::logic::TimeBound>, std::shared_ptr<storm::logic::TimeBoundReference>> FormulaParserGrammar::createTimeBoundFromInterval(storm::expressions::Expression const& lowerBound, storm::expressions::Expression const& upperBound, std::shared_ptr<storm::logic::TimeBoundReference> const& timeBoundReference) const {
// As soon as it somehow does not break everything anymore, I will change return types here.
@ -262,7 +274,7 @@ namespace storm {
storm::logic::TimeBound upper(false, upperBound);
return std::make_tuple(lower, upper, timeBoundReference);
}
std::tuple<boost::optional<storm::logic::TimeBound>, boost::optional<storm::logic::TimeBound>, std::shared_ptr<storm::logic::TimeBoundReference>> FormulaParserGrammar::createTimeBoundFromSingleBound(storm::expressions::Expression const& bound, bool upperBound, bool strict, std::shared_ptr<storm::logic::TimeBoundReference> const& timeBoundReference) const {
// As soon as it somehow does not break everything anymore, I will change return types here.
if (upperBound) {
@ -271,11 +283,11 @@ namespace storm {
return std::make_tuple(storm::logic::TimeBound(strict, bound), boost::none, timeBoundReference);
}
}
std::shared_ptr<storm::logic::Formula const> FormulaParserGrammar::createInstantaneousRewardFormula(storm::expressions::Expression const& timeBound) const {
return std::shared_ptr<storm::logic::Formula const>(new storm::logic::InstantaneousRewardFormula(timeBound));
}
std::shared_ptr<storm::logic::Formula const> FormulaParserGrammar::createCumulativeRewardFormula(std::vector<std::tuple<boost::optional<storm::logic::TimeBound>, boost::optional<storm::logic::TimeBound>, std::shared_ptr<storm::logic::TimeBoundReference>>> const& timeBounds) const {
std::vector<storm::logic::TimeBound> bounds;
std::vector<storm::logic::TimeBoundReference> timeBoundReferences;
@ -287,28 +299,28 @@ namespace storm {
}
return std::shared_ptr<storm::logic::Formula const>(new storm::logic::CumulativeRewardFormula(bounds, timeBoundReferences));
}
std::shared_ptr<storm::logic::Formula const> FormulaParserGrammar::createTotalRewardFormula() const {
return std::shared_ptr<storm::logic::Formula const>(new storm::logic::TotalRewardFormula());
}
std::shared_ptr<storm::logic::Formula const> FormulaParserGrammar::createLongRunAverageRewardFormula() const {
return std::shared_ptr<storm::logic::Formula const>(new storm::logic::LongRunAverageRewardFormula());
}
std::shared_ptr<storm::logic::Formula const> FormulaParserGrammar::createAtomicExpressionFormula(storm::expressions::Expression const& expression) const {
STORM_LOG_THROW(expression.hasBooleanType(), storm::exceptions::WrongFormatException, "Expected expression of boolean type.");
return std::shared_ptr<storm::logic::Formula const>(new storm::logic::AtomicExpressionFormula(expression));
}
std::shared_ptr<storm::logic::Formula const> FormulaParserGrammar::createBooleanLiteralFormula(bool literal) const {
return std::shared_ptr<storm::logic::Formula const>(new storm::logic::BooleanLiteralFormula(literal));
}
std::shared_ptr<storm::logic::Formula const> FormulaParserGrammar::createAtomicLabelFormula(std::string const& label) const {
return std::shared_ptr<storm::logic::Formula const>(new storm::logic::AtomicLabelFormula(label));
}
std::shared_ptr<storm::logic::Formula const> FormulaParserGrammar::createEventuallyFormula(boost::optional<std::vector<std::tuple<boost::optional<storm::logic::TimeBound>, boost::optional<storm::logic::TimeBound>, std::shared_ptr<storm::logic::TimeBoundReference>>>> const& timeBounds, storm::logic::FormulaContext context, std::shared_ptr<storm::logic::Formula const> const& subformula) const {
if (timeBounds && !timeBounds.get().empty()) {
std::vector<boost::optional<storm::logic::TimeBound>> lowerBounds, upperBounds;
@ -323,15 +335,15 @@ namespace storm {
return std::shared_ptr<storm::logic::Formula const>(new storm::logic::EventuallyFormula(subformula, context));
}
}
std::shared_ptr<storm::logic::Formula const> FormulaParserGrammar::createGloballyFormula(std::shared_ptr<storm::logic::Formula const> const& subformula) const {
return std::shared_ptr<storm::logic::Formula const>(new storm::logic::GloballyFormula(subformula));
}
std::shared_ptr<storm::logic::Formula const> FormulaParserGrammar::createNextFormula(std::shared_ptr<storm::logic::Formula const> const& subformula) const {
return std::shared_ptr<storm::logic::Formula const>(new storm::logic::NextFormula(subformula));
}
std::shared_ptr<storm::logic::Formula const> FormulaParserGrammar::createUntilFormula(std::shared_ptr<storm::logic::Formula const> const& leftSubformula, boost::optional<std::vector<std::tuple<boost::optional<storm::logic::TimeBound>, boost::optional<storm::logic::TimeBound>, std::shared_ptr<storm::logic::TimeBoundReference>>>> const& timeBounds, std::shared_ptr<storm::logic::Formula const> const& rightSubformula) {
if (timeBounds && !timeBounds.get().empty()) {
std::vector<boost::optional<storm::logic::TimeBound>> lowerBounds, upperBounds;
@ -346,11 +358,11 @@ namespace storm {
return std::shared_ptr<storm::logic::Formula const>(new storm::logic::UntilFormula(leftSubformula, rightSubformula));
}
}
std::shared_ptr<storm::logic::Formula const> FormulaParserGrammar::createConditionalFormula(std::shared_ptr<storm::logic::Formula const> const& leftSubformula, std::shared_ptr<storm::logic::Formula const> const& rightSubformula, storm::logic::FormulaContext context) const {
return std::shared_ptr<storm::logic::Formula const>(new storm::logic::ConditionalFormula(leftSubformula, rightSubformula, context));
}
storm::logic::OperatorInformation FormulaParserGrammar::createOperatorInformation(boost::optional<storm::OptimizationDirection> const& optimizationDirection, boost::optional<storm::logic::ComparisonType> const& comparisonType, boost::optional<storm::expressions::Expression> const& threshold) const {
if (comparisonType && threshold) {
storm::expressions::ExpressionEvaluator<storm::RationalNumber> evaluator(*constManager);
@ -359,11 +371,11 @@ namespace storm {
return storm::logic::OperatorInformation(optimizationDirection, boost::none);
}
}
std::shared_ptr<storm::logic::Formula const> FormulaParserGrammar::createLongRunAverageOperatorFormula(storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr<storm::logic::Formula const> const& subformula) const {
return std::shared_ptr<storm::logic::Formula const>(new storm::logic::LongRunAverageOperatorFormula(subformula, operatorInformation));
}
std::shared_ptr<storm::logic::Formula const> FormulaParserGrammar::createRewardOperatorFormula(boost::optional<storm::logic::RewardMeasureType> const& rewardMeasureType, boost::optional<std::string> const& rewardModelName, storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr<storm::logic::Formula const> const& subformula) const {
storm::logic::RewardMeasureType measureType = storm::logic::RewardMeasureType::Expectation;
if (rewardMeasureType) {
@ -371,7 +383,7 @@ namespace storm {
}
return std::shared_ptr<storm::logic::Formula const>(new storm::logic::RewardOperatorFormula(subformula, rewardModelName, operatorInformation, measureType));
}
std::shared_ptr<storm::logic::Formula const> FormulaParserGrammar::createTimeOperatorFormula(boost::optional<storm::logic::RewardMeasureType> const& rewardMeasureType, storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr<storm::logic::Formula const> const& subformula) const {
storm::logic::RewardMeasureType measureType = storm::logic::RewardMeasureType::Expectation;
if (rewardMeasureType) {
@ -379,15 +391,15 @@ namespace storm {
}
return std::shared_ptr<storm::logic::Formula const>(new storm::logic::TimeOperatorFormula(subformula, operatorInformation, measureType));
}
std::shared_ptr<storm::logic::Formula const> FormulaParserGrammar::createProbabilityOperatorFormula(storm::logic::OperatorInformation const& operatorInformation, std::shared_ptr<storm::logic::Formula const> const& subformula) {
return std::shared_ptr<storm::logic::Formula const>(new storm::logic::ProbabilityOperatorFormula(subformula, operatorInformation));
}
std::shared_ptr<storm::logic::Formula const> FormulaParserGrammar::createBinaryBooleanStateFormula(std::shared_ptr<storm::logic::Formula const> const& leftSubformula, std::shared_ptr<storm::logic::Formula const> const& rightSubformula, storm::logic::BinaryBooleanStateFormula::OperatorType operatorType) {
return std::shared_ptr<storm::logic::Formula const>(new storm::logic::BinaryBooleanStateFormula(operatorType, leftSubformula, rightSubformula));
}
std::shared_ptr<storm::logic::Formula const> FormulaParserGrammar::createUnaryBooleanStateFormula(std::shared_ptr<storm::logic::Formula const> const& subformula, boost::optional<storm::logic::UnaryBooleanStateFormula::OperatorType> const& operatorType) {
if (operatorType) {
return std::shared_ptr<storm::logic::Formula const>(new storm::logic::UnaryBooleanStateFormula(operatorType.get(), subformula));
@ -395,7 +407,7 @@ namespace storm {
return subformula;
}
}
std::shared_ptr<storm::logic::Formula const> FormulaParserGrammar::createMultiFormula(std::vector<std::shared_ptr<storm::logic::Formula const>> const& subformulas) {
bool isMultiDimensionalBoundedUntilFormula = !subformulas.empty();
for (auto const& subformula : subformulas) {
@ -404,7 +416,7 @@ namespace storm {
break;
}
}
if (isMultiDimensionalBoundedUntilFormula) {
std::vector<std::shared_ptr<storm::logic::Formula const>> leftSubformulas, rightSubformulas;
std::vector<boost::optional<storm::logic::TimeBound>> lowerBounds, upperBounds;
@ -431,7 +443,7 @@ namespace storm {
return std::shared_ptr<storm::logic::Formula const>(new storm::logic::MultiObjectiveFormula(subformulas));
}
}
storm::expressions::Variable FormulaParserGrammar::createQuantileBoundVariables(boost::optional<storm::solver::OptimizationDirection> const& dir, std::string const& variableName) {
STORM_LOG_ASSERT(manager, "Mutable expression manager required to define quantile bound variable.");
storm::expressions::Variable var;
@ -450,17 +462,17 @@ namespace storm {
std::shared_ptr<storm::logic::Formula const> FormulaParserGrammar::createQuantileFormula(std::vector<storm::expressions::Variable> const& boundVariables, std::shared_ptr<storm::logic::Formula const> const& subformula) {
return std::shared_ptr<storm::logic::Formula const>(new storm::logic::QuantileFormula(boundVariables, subformula));
}
std::set<storm::expressions::Variable> FormulaParserGrammar::getUndefinedConstants(std::shared_ptr<storm::logic::Formula const> const& formula) const {
std::set<storm::expressions::Variable> result;
std::set<storm::expressions::Variable> usedVariables = formula->getUsedVariables();
std::set_intersection(usedVariables.begin(), usedVariables.end(), undefinedConstants.begin(), undefinedConstants.end(), std::inserter(result, result.begin()));
return result;
}
storm::jani::Property FormulaParserGrammar::createProperty(boost::optional<std::string> const& propertyName, storm::modelchecker::FilterType const& filterType, std::shared_ptr<storm::logic::Formula const> const& formula, std::shared_ptr<storm::logic::Formula const> const& states) {
storm::jani::FilterExpression filterExpression(formula, filterType, states);
++propertyCount;
if (propertyName) {
return storm::jani::Property(propertyName.get(), filterExpression, this->getUndefinedConstants(formula));
@ -468,7 +480,7 @@ namespace storm {
return storm::jani::Property(std::to_string(propertyCount - 1), filterExpression, this->getUndefinedConstants(formula));
}
}
storm::jani::Property FormulaParserGrammar::createPropertyWithDefaultFilterTypeAndStates(boost::optional<std::string> const& propertyName, std::shared_ptr<storm::logic::Formula const> const& formula) {
++propertyCount;
if (propertyName) {

68
src/storm-parsers/parser/FormulaParserGrammar.h

@ -19,17 +19,17 @@ namespace storm {
namespace logic {
class Formula;
}
namespace parser {
class FormulaParserGrammar : public qi::grammar<Iterator, std::vector<storm::jani::Property>(), Skipper> {
public:
FormulaParserGrammar(std::shared_ptr<storm::expressions::ExpressionManager const> const& manager);
FormulaParserGrammar(std::shared_ptr<storm::expressions::ExpressionManager> const& manager);
FormulaParserGrammar(FormulaParserGrammar const& other) = delete;
FormulaParserGrammar& operator=(FormulaParserGrammar const& other) = delete;
/*!
* Adds an identifier and the expression it is supposed to be replaced with. This can, for example be used
* to substitute special identifiers in the formula by expressions.
@ -38,10 +38,10 @@ namespace storm {
* @param expression The expression it is to be substituted with.
*/
void addIdentifierExpression(std::string const& identifier, storm::expressions::Expression const& expression);
private:
void initialize();
struct keywordsStruct : qi::symbols<char, uint_fast64_t> {
keywordsStruct() {
add
@ -56,10 +56,10 @@ namespace storm {
("quantile", 9);
}
};
// A parser used for recognizing the keywords.
keywordsStruct keywords_;
struct relationalOperatorStruct : qi::symbols<char, storm::logic::ComparisonType> {
relationalOperatorStruct() {
add
@ -69,10 +69,10 @@ namespace storm {
("<", storm::logic::ComparisonType::Less);
}
};
// A parser used for recognizing the operators at the "relational" precedence level.
relationalOperatorStruct relationalOperator_;
struct binaryBooleanOperatorStruct : qi::symbols<char, storm::logic::BinaryBooleanStateFormula::OperatorType> {
binaryBooleanOperatorStruct() {
add
@ -80,20 +80,20 @@ namespace storm {
("|", storm::logic::BinaryBooleanStateFormula::OperatorType::Or);
}
};
// A parser used for recognizing the operators at the "binary" precedence level.
binaryBooleanOperatorStruct binaryBooleanOperator_;
struct unaryBooleanOperatorStruct : qi::symbols<char, storm::logic::UnaryBooleanStateFormula::OperatorType> {
unaryBooleanOperatorStruct() {
add
("!", storm::logic::UnaryBooleanStateFormula::OperatorType::Not);
}
};
// A parser used for recognizing the operators at the "unary" precedence level.
unaryBooleanOperatorStruct unaryBooleanOperator_;
struct optimalityOperatorStruct : qi::symbols<char, storm::OptimizationDirection> {
optimalityOperatorStruct() {
add
@ -101,10 +101,10 @@ namespace storm {
("max", storm::OptimizationDirection::Maximize);
}
};
// A parser used for recognizing the optimality operators.
optimalityOperatorStruct optimalityOperator_;
struct rewardMeasureTypeStruct : qi::symbols<char, storm::logic::RewardMeasureType> {
rewardMeasureTypeStruct() {
add
@ -112,10 +112,10 @@ namespace storm {
("var", storm::logic::RewardMeasureType::Variance);
}
};
// A parser used for recognizing the reward measure types.
rewardMeasureTypeStruct rewardMeasureType_;
struct filterTypeStruct : qi::symbols<char, storm::modelchecker::FilterType> {
filterTypeStruct() {
add
@ -134,28 +134,28 @@ namespace storm {
// A parser used for recognizing the filter type.
filterTypeStruct filterType_;
// The manager used to parse expressions.
std::shared_ptr<storm::expressions::ExpressionManager const> constManager;
std::shared_ptr<storm::expressions::ExpressionManager> manager;
// Parser and manager used for recognizing expressions.
storm::parser::ExpressionParser expressionParser;
// A symbol table that is a mapping from identifiers that can be used in expressions to the expressions
// they are to be replaced with.
qi::symbols<char, storm::expressions::Expression> identifiers_;
qi::rule<Iterator, std::vector<storm::jani::Property>(), Skipper> start;
enum class ConstantDataType {
Bool, Integer, Rational
};
qi::rule<Iterator, qi::unused_type(), qi::locals<ConstantDataType>, Skipper> constantDefinition;
qi::rule<Iterator, std::string(), Skipper> identifier;
qi::rule<Iterator, std::string(), Skipper> formulaName;
qi::rule<Iterator, storm::logic::OperatorInformation(), qi::locals<boost::optional<storm::OptimizationDirection>, boost::optional<storm::logic::ComparisonType>, boost::optional<storm::expressions::Expression>>, Skipper> operatorInformation;
qi::rule<Iterator, storm::logic::RewardMeasureType(), Skipper> rewardMeasureType;
qi::rule<Iterator, std::shared_ptr<storm::logic::Formula const>(), Skipper> probabilityOperator;
@ -176,30 +176,30 @@ namespace storm {
qi::rule<Iterator, std::shared_ptr<storm::logic::Formula const>(), Skipper> operatorFormula;
qi::rule<Iterator, std::string(), Skipper> label;
qi::rule<Iterator, std::string(), Skipper> rewardModelName;
qi::rule<Iterator, std::shared_ptr<storm::logic::Formula const>(), Skipper> andStateFormula;
qi::rule<Iterator, std::shared_ptr<storm::logic::Formula const>(), Skipper> orStateFormula;
qi::rule<Iterator, std::shared_ptr<storm::logic::Formula const>(), Skipper> notStateFormula;
qi::rule<Iterator, std::shared_ptr<storm::logic::Formula const>(), Skipper> labelFormula;
qi::rule<Iterator, std::shared_ptr<storm::logic::Formula const>(), Skipper> expressionFormula;
qi::rule<Iterator, std::shared_ptr<storm::logic::Formula const>(), qi::locals<bool>, Skipper> booleanLiteralFormula;
qi::rule<Iterator, std::shared_ptr<storm::logic::Formula const>(storm::logic::FormulaContext), Skipper> conditionalFormula;
qi::rule<Iterator, std::shared_ptr<storm::logic::Formula const>(storm::logic::FormulaContext), Skipper> eventuallyFormula;
qi::rule<Iterator, std::shared_ptr<storm::logic::Formula const>(storm::logic::FormulaContext), Skipper> nextFormula;
qi::rule<Iterator, std::shared_ptr<storm::logic::Formula const>(storm::logic::FormulaContext), Skipper> globallyFormula;
qi::rule<Iterator, std::shared_ptr<storm::logic::Formula const>(storm::logic::FormulaContext), Skipper> untilFormula;
qi::rule<Iterator, std::shared_ptr<storm::logic::TimeBoundReference>, Skipper> timeBoundReference;
qi::rule<Iterator, std::tuple<boost::optional<storm::logic::TimeBound>, boost::optional<storm::logic::TimeBound>, std::shared_ptr<storm::logic::TimeBoundReference>>(), qi::locals<bool, bool>, Skipper> timeBound;
qi::rule<Iterator, std::vector<std::tuple<boost::optional<storm::logic::TimeBound>, boost::optional<storm::logic::TimeBound>, std::shared_ptr<storm::logic::TimeBoundReference>>>(), qi::locals<bool, bool>, Skipper> timeBounds;
qi::rule<Iterator, std::shared_ptr<storm::logic::Formula const>(), Skipper> rewardPathFormula;
qi::rule<Iterator, std::shared_ptr<storm::logic::Formula const>(), qi::locals<bool>, Skipper> cumulativeRewardFormula;
qi::rule<Iterator, std::shared_ptr<storm::logic::Formula const>(), Skipper> totalRewardFormula;
qi::rule<Iterator, std::shared_ptr<storm::logic::Formula const>(), Skipper> instantaneousRewardFormula;
qi::rule<Iterator, std::shared_ptr<storm::logic::Formula const>(), Skipper> longRunAverageRewardFormula;
qi::rule<Iterator, std::shared_ptr<storm::logic::Formula const>(), Skipper> multiFormula;
qi::rule<Iterator, storm::expressions::Variable(), qi::locals<boost::optional<storm::solver::OptimizationDirection>>, Skipper> quantileBoundVariable;
qi::rule<Iterator, std::shared_ptr<storm::logic::Formula const>(), Skipper> quantileFormula;
@ -242,16 +242,16 @@ namespace storm {
std::shared_ptr<storm::logic::Formula const> createMultiFormula(std::vector<std::shared_ptr<storm::logic::Formula const>> const& subformulas);
storm::expressions::Variable createQuantileBoundVariables(boost::optional<storm::solver::OptimizationDirection> const& dir, std::string const& variableName);
std::shared_ptr<storm::logic::Formula const> createQuantileFormula(std::vector<storm::expressions::Variable> const& boundVariables, std::shared_ptr<storm::logic::Formula const> const& subformula);
std::set<storm::expressions::Variable> getUndefinedConstants(std::shared_ptr<storm::logic::Formula const> const& formula) const;
storm::jani::Property createProperty(boost::optional<std::string> const& propertyName, storm::modelchecker::FilterType const& filterType, std::shared_ptr<storm::logic::Formula const> const& formula, std::shared_ptr<storm::logic::Formula const> const& states);
storm::jani::Property createPropertyWithDefaultFilterTypeAndStates(boost::optional<std::string> const& propertyName, std::shared_ptr<storm::logic::Formula const> const& formula);
// An error handler function.
phoenix::function<SpiritErrorHandler> handler;
uint64_t propertyCount;
std::set<storm::expressions::Variable> undefinedConstants;
std::set<storm::expressions::Variable> quantileFormulaVariables;
};

4
src/storm-parsers/parser/PrismParser.cpp

@ -869,7 +869,7 @@ namespace storm {
if (!this->secondRun) {
// Add a mapping from the new module name to its (future) index.
globalProgramInformation.moduleToIndexMap[newModuleName] = globalProgramInformation.modules.size();
// Register all (renamed) variables for later use.
// We already checked before, whether the renaiming is valid.
for (auto const& variable : moduleToRename.getBooleanVariables()) {
@ -921,7 +921,7 @@ namespace storm {
// Assert that the module name is already known and has the expected index.
STORM_LOG_ASSERT(globalProgramInformation.moduleToIndexMap.count(newModuleName) > 0, "Module name '" << newModuleName << "' was not found.");
STORM_LOG_ASSERT(globalProgramInformation.moduleToIndexMap[newModuleName] == globalProgramInformation.modules.size(), "The index for module " << newModuleName << " does not match the index from the first parsing run.");
// Create a mapping from identifiers to the expressions they need to be replaced with.
std::map<storm::expressions::Variable, storm::expressions::Expression> expressionRenaming;
for (auto const& namePair : renaming) {

14
src/storm/api/verification.h

@ -39,7 +39,7 @@
namespace storm {
namespace api {
template<typename ValueType>
storm::modelchecker::CheckTask<storm::logic::Formula, ValueType> createTask(std::shared_ptr<const storm::logic::Formula> const& formula, bool onlyInitialStatesRelevant = false) {
return storm::modelchecker::CheckTask<storm::logic::Formula, ValueType>(*formula, onlyInitialStatesRelevant);
@ -53,7 +53,7 @@ namespace storm {
AbstractionRefinementOptions(std::vector<storm::expressions::Expression>&& constraints, std::vector<std::vector<storm::expressions::Expression>>&& injectedRefinementPredicates) : constraints(std::move(constraints)), injectedRefinementPredicates(std::move(injectedRefinementPredicates)) {
// Intentionally left empty.
}
std::vector<storm::expressions::Expression> constraints;
std::vector<std::vector<storm::expressions::Expression>> injectedRefinementPredicates;
};
@ -228,13 +228,13 @@ namespace storm {
template<typename ValueType>
typename std::enable_if<!std::is_same<ValueType, storm::RationalFunction>::value, std::unique_ptr<storm::modelchecker::CheckResult>>::type verifyWithSparseEngine(storm::Environment const& env, std::shared_ptr<storm::models::sparse::MarkovAutomaton<ValueType>> const& ma, storm::modelchecker::CheckTask<storm::logic::Formula, ValueType> const& task) {
std::unique_ptr<storm::modelchecker::CheckResult> result;
// Close the MA, if it is not already closed.
if (!ma->isClosed()) {
STORM_LOG_WARN("Closing Markov automaton. Consider closing the MA before verification.");
ma->close();
}
storm::modelchecker::SparseMarkovAutomatonCslModelChecker<storm::models::sparse::MarkovAutomaton<ValueType>> modelchecker(*ma);
if (modelchecker.canHandle(task)) {
result = modelchecker.check(env, task);
@ -299,7 +299,7 @@ namespace storm {
Environment env;
return verifyWithSparseEngine(env, model, task);
}
template<typename ValueType>
std::unique_ptr<storm::modelchecker::CheckResult> computeSteadyStateDistributionWithSparseEngine(storm::Environment const& env, std::shared_ptr<storm::models::sparse::Dtmc<ValueType>> const& dtmc) {
std::unique_ptr<storm::modelchecker::CheckResult> result;
@ -326,7 +326,7 @@ namespace storm {
}
return result;
}
//
// Verifying with Hybrid engine
//
@ -485,6 +485,6 @@ namespace storm {
Environment env;
return verifyWithDdEngine(env, model, task);
}
}
}

5
src/storm/builder/ExplicitModelBuilder.cpp

@ -154,6 +154,7 @@ namespace storm {
while (!statesToExplore.empty()) {
// Get the first state in the queue.
CompressedState currentState = statesToExplore.front().first;
STORM_LOG_DEBUG("Exploring (" << currentRowGroup << ") : " << toString(currentState, this->generator->getVariableInformation()));
StateType currentIndex = statesToExplore.front().second;
statesToExplore.pop_front();
@ -196,7 +197,7 @@ namespace storm {
rewardModelBuilder.addStateActionReward(storm::utility::zero<ValueType>());
}
}
// This state shall be Markovian (to not introduce Zeno behavior)
if (stateAndChoiceInformationBuilder.isBuildMarkovianStates()) {
stateAndChoiceInformationBuilder.addMarkovianState(currentRowGroup);
@ -340,7 +341,7 @@ namespace storm {
stateAndChoiceInformationBuilder.setBuildStateValuations(generator->getOptions().isBuildStateValuationsSet());
buildMatrices(transitionMatrixBuilder, rewardModelBuilders, stateAndChoiceInformationBuilder);
// Initialize the model components with the obtained information.
storm::storage::sparse::ModelComponents<ValueType, RewardModelType> modelComponents(transitionMatrixBuilder.build(0, transitionMatrixBuilder.getCurrentRowGroupCount()), buildStateLabeling(), std::unordered_map<std::string, RewardModelType>(), !generator->isDiscreteTimeModel());

18
src/storm/builder/ExplicitModelBuilder.h

@ -35,12 +35,12 @@ namespace storm {
namespace utility {
template<typename ValueType> class ConstantsComparator;
}
namespace builder {
using namespace storm::utility::prism;
using namespace storm::generator;
// Forward-declare classes.
template <typename ValueType> class RewardModelBuilder;
class StateAndChoiceInformationBuilder;
@ -59,21 +59,21 @@ namespace storm {
VariableInformation varInfo;
storm::storage::BitVectorHashMap<StateType> stateToId;
};
template<typename ValueType, typename RewardModelType = storm::models::sparse::StandardRewardModel<ValueType>, typename StateType = uint32_t>
class ExplicitModelBuilder {
public:
struct Options {
/*!
* Creates an object representing the default building options.
*/
Options();
// The order in which to explore the model.
ExplorationOrder explorationOrder;
};
/*!
* Creates an explicit model builder that uses the provided generator.
*
@ -94,7 +94,7 @@ namespace storm {
* @param model The JANI model for which to build the model.
*/
ExplicitModelBuilder(storm::jani::Model const& model, storm::generator::NextStateGeneratorOptions const& generatorOptions = storm::generator::NextStateGeneratorOptions(), Options const& builderOptions = Options());
/*!
* Convert the program given at construction time to an abstract model. The type of the model is the one
* specified in the program. The given reward model name selects the rewards that the model will contain.
@ -121,7 +121,7 @@ namespace storm {
* @return A pair indicating whether the state was already discovered before and the state id of the state.
*/
StateType getOrAddStateIndex(CompressedState const& state);
/*!
* Builds the transition matrix and the transition reward matrix based for the given program.
*

20
src/storm/environment/solver/MultiplierEnvironment.cpp

@ -6,28 +6,36 @@
#include "storm/utility/macros.h"
namespace storm {
MultiplierEnvironment::MultiplierEnvironment() {
auto const& multiplierSettings = storm::settings::getModule<storm::settings::modules::MultiplierSettings>();
type = multiplierSettings.getMultiplierType();
typeSetFromDefault = multiplierSettings.isMultiplierTypeSetFromDefaultValue();
}
MultiplierEnvironment::~MultiplierEnvironment() {
// Intentionally left empty
}
storm::solver::MultiplierType const& MultiplierEnvironment::getType() const {
return type;
}
bool const& MultiplierEnvironment::isTypeSetFromDefault() const {
return typeSetFromDefault;
}
void MultiplierEnvironment::setType(storm::solver::MultiplierType value, bool isSetFromDefault) {
type = value;
typeSetFromDefault = isSetFromDefault;
}
void MultiplierEnvironment::setOptimizationDirectionOverride(storm::storage::BitVector optDirOverride) {
optimizationDirectionOverride = optDirOverride;
}
boost::optional<storm::storage::BitVector> const& MultiplierEnvironment::getOptimizationDirectionOverride() const {
return optimizationDirectionOverride;
}
}

18
src/storm/environment/solver/MultiplierEnvironment.h

@ -1,23 +1,31 @@
#pragma once
#include <boost/optional.hpp>
#include "storm/environment/solver/SolverEnvironment.h"
#include "storm/solver/SolverSelectionOptions.h"
#include "storm/storage/BitVector.h"
namespace storm {
class MultiplierEnvironment {
public:
MultiplierEnvironment();
~MultiplierEnvironment();
storm::solver::MultiplierType const& getType() const;
bool const& isTypeSetFromDefault() const;
void setType(storm::solver::MultiplierType value, bool isSetFromDefault = false);
void setOptimizationDirectionOverride(storm::storage::BitVector optimizationDirectionOverride);
boost::optional<storm::storage::BitVector> const& getOptimizationDirectionOverride() const;
private:
storm::solver::MultiplierType type;
bool typeSetFromDefault;
boost::optional<storm::storage::BitVector> optimizationDirectionOverride = boost::none;
};
}

52
src/storm/generator/Choice.cpp

@ -11,30 +11,30 @@
namespace storm {
namespace generator {
template<typename ValueType, typename StateType>
Choice<ValueType, StateType>::Choice(uint_fast64_t actionIndex, bool markovian) : markovian(markovian), actionIndex(actionIndex), distribution(), totalMass(storm::utility::zero<ValueType>()), rewards(), labels() {
// Intentionally left empty.
}
template<typename ValueType, typename StateType>
void Choice<ValueType, StateType>::add(Choice const& other) {
STORM_LOG_THROW(this->markovian == other.markovian, storm::exceptions::InvalidOperationException, "Type of choices do not match.");
STORM_LOG_THROW(this->actionIndex == other.actionIndex, storm::exceptions::InvalidOperationException, "Action index of choices do not match.");
STORM_LOG_THROW(this->rewards.size() == other.rewards.size(), storm::exceptions::InvalidOperationException, "Reward value sizes of choices do not match.");
// Add the elements to the distribution.
this->distribution.add(other.distribution);
// Update the total mass of the choice.
this->totalMass += other.totalMass;
// Add all reward values.
auto otherRewIt = other.rewards.begin();
for (auto& rewardValue : this->rewards) {
rewardValue += *otherRewIt;
}
// Join label sets and origin data if given.
if (other.labels) {
this->addLabels(other.labels.get());
@ -43,27 +43,27 @@ namespace storm {
this->addOriginData(other.originData.get());
}
}
template<typename ValueType, typename StateType>
typename storm::storage::Distribution<ValueType, StateType>::iterator Choice<ValueType, StateType>::begin() {
return distribution.begin();
}
template<typename ValueType, typename StateType>
typename storm::storage::Distribution<ValueType, StateType>::const_iterator Choice<ValueType, StateType>::begin() const {
return distribution.cbegin();
}
template<typename ValueType, typename StateType>
typename storm::storage::Distribution<ValueType, StateType>::iterator Choice<ValueType, StateType>::end() {
return distribution.end();
}
template<typename ValueType, typename StateType>
typename storm::storage::Distribution<ValueType, StateType>::const_iterator Choice<ValueType, StateType>::end() const {
return distribution.cend();
}
template<typename ValueType, typename StateType>
void Choice<ValueType, StateType>::addLabel(std::string const& newLabel) {
if (!labels) {
@ -71,7 +71,7 @@ namespace storm {
}
labels->insert(newLabel);
}
template<typename ValueType, typename StateType>
void Choice<ValueType, StateType>::addLabels(std::set<std::string> const& newLabels) {
if (labels) {
@ -113,7 +113,7 @@ namespace storm {
} else {
if (!data.empty()) {
// Reaching this point means that the both the existing and the given data are non-empty
auto existingDataAsIndexSet = boost::any_cast<storm::storage::FlatSet<uint_fast64_t>>(&this->originData.get());
if (existingDataAsIndexSet != nullptr) {
auto givenDataAsIndexSet = boost::any_cast<storm::storage::FlatSet<uint_fast64_t>>(&data);
@ -125,63 +125,63 @@ namespace storm {
}
}
}
template<typename ValueType, typename StateType>
bool Choice<ValueType, StateType>::hasOriginData() const {
return originData.is_initialized();
}
template<typename ValueType, typename StateType>
boost::any const& Choice<ValueType, StateType>::getOriginData() const {
return originData.get();
}
template<typename ValueType, typename StateType>
uint_fast64_t Choice<ValueType, StateType>::getActionIndex() const {
return actionIndex;
}
template<typename ValueType, typename StateType>
ValueType Choice<ValueType, StateType>::getTotalMass() const {
return totalMass;
}
template<typename ValueType, typename StateType>
void Choice<ValueType, StateType>::addProbability(StateType const& state, ValueType const& value) {
totalMass += value;
distribution.addProbability(state, value);
}
template<typename ValueType, typename StateType>
void Choice<ValueType, StateType>::addReward(ValueType const& value) {
rewards.push_back(value);
}
template<typename ValueType, typename StateType>
void Choice<ValueType, StateType>::addRewards(std::vector<ValueType>&& values) {
this->rewards = std::move(values);
}
template<typename ValueType, typename StateType>
std::vector<ValueType> const& Choice<ValueType, StateType>::getRewards() const {
return rewards;
}
template<typename ValueType, typename StateType>
bool Choice<ValueType, StateType>::isMarkovian() const {
return markovian;
}
template<typename ValueType, typename StateType>
std::size_t Choice<ValueType, StateType>::size() const {
return distribution.size();
}
template<typename ValueType, typename StateType>
void Choice<ValueType, StateType>::reserve(std::size_t const& size) {
distribution.reserve(size);
}
template<typename ValueType, typename StateType>
std::ostream& operator<<(std::ostream& out, Choice<ValueType, StateType> const& choice) {
out << "<";
@ -191,7 +191,7 @@ namespace storm {
out << ">";
return out;
}
template struct Choice<double>;
#ifdef STORM_HAVE_CARL

16
src/storm/generator/Choice.h

@ -13,51 +13,51 @@
namespace storm {
namespace generator {
// A structure holding information about a particular choice.
template<typename ValueType, typename StateType=uint32_t>
struct Choice {
public:
Choice(uint_fast64_t actionIndex = 0, bool markovian = false);
Choice(Choice const& other) = default;
Choice& operator=(Choice const& other) = default;
Choice(Choice&& other) = default;
Choice& operator=(Choice&& other) = default;
/*!
* Adds the given choice to the current one.
*/
void add(Choice const& other);
/*!
* Returns an iterator to the distribution associated with this choice.
*
* @return An iterator to the first element of the distribution.
*/
typename storm::storage::Distribution<ValueType, StateType>::iterator begin();
/*!
* Returns an iterator to the distribution associated with this choice.
*
* @return An iterator to the first element of the distribution.
*/
typename storm::storage::Distribution<ValueType, StateType>::const_iterator begin() const;
/*!
* Returns an iterator past the end of the distribution associated with this choice.
*
* @return An iterator past the end of the distribution.
*/
typename storm::storage::Distribution<ValueType, StateType>::iterator end();
/*!
* Returns an iterator past the end of the distribution associated with this choice.
*
* @return An iterator past the end of the distribution.
*/
typename storm::storage::Distribution<ValueType, StateType>::const_iterator end() const;
/*!
* Inserts the contents of this object to the given output stream.
*

34
src/storm/logic/CloneVisitor.cpp

@ -4,30 +4,30 @@
namespace storm {
namespace logic {
std::shared_ptr<Formula> CloneVisitor::clone(Formula const& f) const {
boost::any result = f.accept(*this, boost::any());
return boost::any_cast<std::shared_ptr<Formula>>(result);
}
boost::any CloneVisitor::visit(AtomicExpressionFormula const& f, boost::any const&) const {
return std::static_pointer_cast<Formula>(std::make_shared<AtomicExpressionFormula>(f));
}
boost::any CloneVisitor::visit(AtomicLabelFormula const& f, boost::any const&) const {
return std::static_pointer_cast<Formula>(std::make_shared<AtomicLabelFormula>(f));
}
boost::any CloneVisitor::visit(BinaryBooleanStateFormula const& f, boost::any const& data) const {
std::shared_ptr<Formula> left = boost::any_cast<std::shared_ptr<Formula>>(f.getLeftSubformula().accept(*this, data));
std::shared_ptr<Formula> right = boost::any_cast<std::shared_ptr<Formula>>(f.getRightSubformula().accept(*this, data));
return std::static_pointer_cast<Formula>(std::make_shared<BinaryBooleanStateFormula>(f.getOperator(), left, right));
}
boost::any CloneVisitor::visit(BooleanLiteralFormula const& f, boost::any const&) const {
return std::static_pointer_cast<Formula>(std::make_shared<BooleanLiteralFormula>(f));
}
boost::any CloneVisitor::visit(BoundedUntilFormula const& f, boost::any const& data) const {
std::vector<boost::optional<TimeBound>> lowerBounds, upperBounds;
std::vector<TimeBoundReference> timeBoundReferences;
@ -57,17 +57,17 @@ namespace storm {
return std::static_pointer_cast<Formula>(std::make_shared<BoundedUntilFormula>(left, right, lowerBounds, upperBounds, timeBoundReferences));
}
}
boost::any CloneVisitor::visit(ConditionalFormula const& f, boost::any const& data) const {
std::shared_ptr<Formula> subformula = boost::any_cast<std::shared_ptr<Formula>>(f.getSubformula().accept(*this, data));
std::shared_ptr<Formula> conditionFormula = boost::any_cast<std::shared_ptr<Formula>>(f.getConditionFormula().accept(*this, data));
return std::static_pointer_cast<Formula>(std::make_shared<ConditionalFormula>(subformula, conditionFormula, f.getContext()));
}
boost::any CloneVisitor::visit(CumulativeRewardFormula const& f, boost::any const&) const {
return std::static_pointer_cast<Formula>(std::make_shared<CumulativeRewardFormula>(f));
}
boost::any CloneVisitor::visit(EventuallyFormula const& f, boost::any const& data) const {
std::shared_ptr<Formula> subformula = boost::any_cast<std::shared_ptr<Formula>>(f.getSubformula().accept(*this, data));
if (f.hasRewardAccumulation()) {
@ -112,41 +112,41 @@ namespace storm {
}
return std::static_pointer_cast<Formula>(std::make_shared<MultiObjectiveFormula>(subformulas));
}
boost::any CloneVisitor::visit(QuantileFormula const& f, boost::any const& data) const {
std::shared_ptr<Formula> subformula = boost::any_cast<std::shared_ptr<Formula>>(f.getSubformula().accept(*this, data));
return std::static_pointer_cast<Formula>(std::make_shared<QuantileFormula>(f.getBoundVariables(), subformula));
}
boost::any CloneVisitor::visit(NextFormula const& f, boost::any const& data) const {
std::shared_ptr<Formula> subformula = boost::any_cast<std::shared_ptr<Formula>>(f.getSubformula().accept(*this, data));
return std::static_pointer_cast<Formula>(std::make_shared<NextFormula>(subformula));
}
boost::any CloneVisitor::visit(ProbabilityOperatorFormula const& f, boost::any const& data) const {
std::shared_ptr<Formula> subformula = boost::any_cast<std::shared_ptr<Formula>>(f.getSubformula().accept(*this, data));
return std::static_pointer_cast<Formula>(std::make_shared<ProbabilityOperatorFormula>(subformula, f.getOperatorInformation()));
}
boost::any CloneVisitor::visit(RewardOperatorFormula const& f, boost::any const& data) const {
std::shared_ptr<Formula> subformula = boost::any_cast<std::shared_ptr<Formula>>(f.getSubformula().accept(*this, data));
return std::static_pointer_cast<Formula>(std::make_shared<RewardOperatorFormula>(subformula, f.getOptionalRewardModelName(), f.getOperatorInformation()));
}
boost::any CloneVisitor::visit(TotalRewardFormula const& f, boost::any const&) const {
return std::static_pointer_cast<Formula>(std::make_shared<TotalRewardFormula>(f));
}
boost::any CloneVisitor::visit(UnaryBooleanStateFormula const& f, boost::any const& data) const {
std::shared_ptr<Formula> subformula = boost::any_cast<std::shared_ptr<Formula>>(f.getSubformula().accept(*this, data));
return std::static_pointer_cast<Formula>(std::make_shared<UnaryBooleanStateFormula>(f.getOperator(), subformula));
}
boost::any CloneVisitor::visit(UntilFormula const& f, boost::any const& data) const {
std::shared_ptr<Formula> left = boost::any_cast<std::shared_ptr<Formula>>(f.getLeftSubformula().accept(*this, data));
std::shared_ptr<Formula> right = boost::any_cast<std::shared_ptr<Formula>>(f.getRightSubformula().accept(*this, data));
return std::static_pointer_cast<Formula>(std::make_shared<UntilFormula>(left, right));
}
}
}

56
src/storm/logic/FragmentChecker.cpp

@ -9,7 +9,7 @@ namespace storm {
InheritedInformation(FragmentSpecification const& fragmentSpecification) : fragmentSpecification(fragmentSpecification) {
// Intentionally left empty.
}
FragmentSpecification const& getSpecification() const {
return fragmentSpecification;
}
@ -17,10 +17,10 @@ namespace storm {
private:
FragmentSpecification const& fragmentSpecification;
};
bool FragmentChecker::conformsToSpecification(Formula const& f, FragmentSpecification const& specification) const {
bool result = boost::any_cast<bool>(f.accept(*this, InheritedInformation(specification)));
if (specification.isOperatorAtTopLevelRequired()) {
result &= f.isOperatorFormula();
}
@ -30,20 +30,20 @@ namespace storm {
if (specification.isQuantileFormulaAtTopLevelRequired()) {
result &= f.isQuantileFormula();
}
return result;
}
boost::any FragmentChecker::visit(AtomicExpressionFormula const&, boost::any const& data) const {
InheritedInformation const& inherited = boost::any_cast<InheritedInformation const&>(data);
return inherited.getSpecification().areAtomicExpressionFormulasAllowed();
}
boost::any FragmentChecker::visit(AtomicLabelFormula const&, boost::any const& data) const {
InheritedInformation const& inherited = boost::any_cast<InheritedInformation const&>(data);
return inherited.getSpecification().areAtomicLabelFormulasAllowed();
}
boost::any FragmentChecker::visit(BinaryBooleanStateFormula const& f, boost::any const& data) const {
InheritedInformation const& inherited = boost::any_cast<InheritedInformation const&>(data);
bool result = inherited.getSpecification().areBinaryBooleanStateFormulasAllowed();
@ -51,12 +51,12 @@ namespace storm {
result = result && boost::any_cast<bool>(f.getRightSubformula().accept(*this, data));
return result;
}
boost::any FragmentChecker::visit(BooleanLiteralFormula const&, boost::any const& data) const {
InheritedInformation const& inherited = boost::any_cast<InheritedInformation const&>(data);
return inherited.getSpecification().areBooleanLiteralFormulasAllowed();
}
boost::any FragmentChecker::visit(BoundedUntilFormula const& f, boost::any const& data) const {
InheritedInformation const& inherited = boost::any_cast<InheritedInformation const&>(data);
bool result = inherited.getSpecification().areBoundedUntilFormulasAllowed();
@ -78,7 +78,7 @@ namespace storm {
}
}
}
if (f.hasMultiDimensionalSubformulas()) {
for (uint64_t i = 0; i < f.getDimension(); ++i) {
if (!inherited.getSpecification().areNestedPathFormulasAllowed()) {
@ -98,7 +98,7 @@ namespace storm {
}
return result;
}
boost::any FragmentChecker::visit(ConditionalFormula const& f, boost::any const& data) const {
InheritedInformation const& inherited = boost::any_cast<InheritedInformation const&>(data);
bool result = true;
@ -118,10 +118,10 @@ namespace storm {
result = result && boost::any_cast<bool>(f.getConditionFormula().accept(*this, data));
return result;
}
boost::any FragmentChecker::visit(CumulativeRewardFormula const& f, boost::any const& data) const {
InheritedInformation const& inherited = boost::any_cast<InheritedInformation const&>(data);
bool result = inherited.getSpecification().areCumulativeRewardFormulasAllowed();
result = result && (!f.isMultiDimensional() || inherited.getSpecification().areMultiDimensionalCumulativeRewardFormulasAllowed());
result = result && (!f.hasRewardAccumulation() || inherited.getSpecification().isRewardAccumulationAllowed());
@ -141,7 +141,7 @@ namespace storm {
}
return result;
}
boost::any FragmentChecker::visit(EventuallyFormula const& f, boost::any const& data) const {
InheritedInformation const& inherited = boost::any_cast<InheritedInformation const&>(data);
bool result = true;
@ -163,7 +163,7 @@ namespace storm {
result = result && boost::any_cast<bool>(f.getSubformula().accept(*this, data));
return result;
}
boost::any FragmentChecker::visit(TimeOperatorFormula const& f, boost::any const& data) const {
InheritedInformation const& inherited = boost::any_cast<InheritedInformation const&>(data);
bool result = inherited.getSpecification().areTimeOperatorsAllowed();
@ -178,7 +178,7 @@ namespace storm {
}
return result;
}
boost::any FragmentChecker::visit(GloballyFormula const& f, boost::any const& data) const {
InheritedInformation const& inherited = boost::any_cast<InheritedInformation const&>(data);
bool result = inherited.getSpecification().areGloballyFormulasAllowed();
@ -211,16 +211,16 @@ namespace storm {
}
return result;
}
boost::any FragmentChecker::visit(LongRunAverageRewardFormula const& f, boost::any const& data) const {
InheritedInformation const& inherited = boost::any_cast<InheritedInformation const&>(data);
bool result = (!f.hasRewardAccumulation() || inherited.getSpecification().isRewardAccumulationAllowed());
return result && inherited.getSpecification().areLongRunAverageRewardFormulasAllowed();
}
boost::any FragmentChecker::visit(MultiObjectiveFormula const& f, boost::any const& data) const {
InheritedInformation const& inherited = boost::any_cast<InheritedInformation const&>(data);
FragmentSpecification subFormulaFragment(inherited.getSpecification());
if(!inherited.getSpecification().areNestedMultiObjectiveFormulasAllowed()){
subFormulaFragment.setMultiObjectiveFormulasAllowed(false);
@ -228,7 +228,7 @@ namespace storm {
if(!inherited.getSpecification().areNestedOperatorsInsideMultiObjectiveFormulasAllowed()){
subFormulaFragment.setNestedOperatorsAllowed(false);
}
bool result = inherited.getSpecification().areMultiObjectiveFormulasAllowed();
for(auto const& subF : f.getSubformulas()){
if(inherited.getSpecification().areOperatorsAtTopLevelOfMultiObjectiveFormulasRequired()){
@ -238,7 +238,7 @@ namespace storm {
}
return result;
}
boost::any FragmentChecker::visit(QuantileFormula const& f, boost::any const& data) const {
InheritedInformation const& inherited = boost::any_cast<InheritedInformation const&>(data);
if (!inherited.getSpecification().areQuantileFormulasAllowed()) {
@ -246,7 +246,7 @@ namespace storm {
}
return f.getSubformula().accept(*this, data);
}
boost::any FragmentChecker::visit(NextFormula const& f, boost::any const& data) const {
InheritedInformation const& inherited = boost::any_cast<InheritedInformation const&>(data);
bool result = inherited.getSpecification().areNextFormulasAllowed();
@ -256,7 +256,7 @@ namespace storm {
result && boost::any_cast<bool>(f.getSubformula().accept(*this, data));
return result;
}
boost::any FragmentChecker::visit(ProbabilityOperatorFormula const& f, boost::any const& data) const {
InheritedInformation const& inherited = boost::any_cast<InheritedInformation const&>(data);
bool result = inherited.getSpecification().areProbabilityOperatorsAllowed();
@ -270,7 +270,7 @@ namespace storm {
}
return result;
}
boost::any FragmentChecker::visit(RewardOperatorFormula const& f, boost::any const& data) const {
InheritedInformation const& inherited = boost::any_cast<InheritedInformation const&>(data);
bool result = inherited.getSpecification().areRewardOperatorsAllowed();
@ -278,7 +278,7 @@ namespace storm {
result = result && (!f.hasQuantitativeResult() || inherited.getSpecification().areQuantitativeOperatorResultsAllowed());
result = result && (f.getSubformula().isRewardPathFormula() || f.getSubformula().isConditionalRewardFormula());
result = result && (inherited.getSpecification().isVarianceMeasureTypeAllowed() || f.getMeasureType() == RewardMeasureType::Expectation);
if (!inherited.getSpecification().areNestedOperatorsAllowed()) {
result = result && boost::any_cast<bool>(f.getSubformula().accept(*this, InheritedInformation(inherited.getSpecification().copy().setOperatorsAllowed(false))));
} else {
@ -286,21 +286,21 @@ namespace storm {
}
return result;
}
boost::any FragmentChecker::visit(TotalRewardFormula const& f, boost::any const& data) const {
InheritedInformation const& inherited = boost::any_cast<InheritedInformation const&>(data);
bool result = (!f.hasRewardAccumulation() || inherited.getSpecification().isRewardAccumulationAllowed());
result = result && inherited.getSpecification().areTotalRewardFormulasAllowed();
return result;
}
boost::any FragmentChecker::visit(UnaryBooleanStateFormula const& f, boost::any const& data) const {
InheritedInformation const& inherited = boost::any_cast<InheritedInformation const&>(data);
bool result = inherited.getSpecification().areUnaryBooleanStateFormulasAllowed();
result = result && boost::any_cast<bool>(f.getSubformula().accept(*this, data));
return result;
}
boost::any FragmentChecker::visit(UntilFormula const& f, boost::any const& data) const {
InheritedInformation const& inherited = boost::any_cast<InheritedInformation const&>(data);
bool result = inherited.getSpecification().areUntilFormulasAllowed();

224
src/storm/logic/FragmentSpecification.cpp

@ -5,34 +5,34 @@
namespace storm {
namespace logic {
FragmentSpecification propositional() {
FragmentSpecification propositional;
propositional.setBooleanLiteralFormulasAllowed(true);
propositional.setBinaryBooleanStateFormulasAllowed(true);
propositional.setUnaryBooleanStateFormulasAllowed(true);
propositional.setAtomicExpressionFormulasAllowed(true);
propositional.setAtomicLabelFormulasAllowed(true);
return propositional;
}
FragmentSpecification reachability() {
FragmentSpecification reachability = propositional();
reachability.setProbabilityOperatorsAllowed(true);
reachability.setUntilFormulasAllowed(true);
reachability.setReachabilityProbabilityFormulasAllowed(true);
reachability.setOperatorAtTopLevelRequired(true);
reachability.setNestedOperatorsAllowed(false);
return reachability;
}
FragmentSpecification pctl() {
FragmentSpecification pctl = propositional();
pctl.setProbabilityOperatorsAllowed(true);
pctl.setGloballyFormulasAllowed(true);
pctl.setReachabilityProbabilityFormulasAllowed(true);
@ -76,34 +76,34 @@ namespace storm {
prctl.setLongRunAverageOperatorsAllowed(true);
prctl.setStepBoundedCumulativeRewardFormulasAllowed(true);
prctl.setTimeBoundedCumulativeRewardFormulasAllowed(true);
return prctl;
}
FragmentSpecification csl() {
FragmentSpecification csl = pctl();
csl.setTimeBoundedUntilFormulasAllowed(true);
return csl;
}
FragmentSpecification csrl() {
FragmentSpecification csrl = csl();
csrl.setRewardOperatorsAllowed(true);
csrl.setCumulativeRewardFormulasAllowed(true);
csrl.setInstantaneousFormulasAllowed(true);
csrl.setReachabilityRewardFormulasAllowed(true);
csrl.setLongRunAverageOperatorsAllowed(true);
csrl.setTimeBoundedCumulativeRewardFormulasAllowed(true);
return csrl;
}
FragmentSpecification multiObjective() {
FragmentSpecification multiObjective = propositional();
multiObjective.setMultiObjectiveFormulasAllowed(true);
multiObjective.setMultiObjectiveFormulaAtTopLevelRequired(true);
multiObjective.setNestedMultiObjectiveFormulasAllowed(false);
@ -125,10 +125,10 @@ namespace storm {
return multiObjective;
}
FragmentSpecification quantiles() {
FragmentSpecification quantiles = propositional();
quantiles.setQuantileFormulasAllowed(true);
quantiles.setQuantileFormulaAtTopLevelRequired(true);
quantiles.setProbabilityOperatorsAllowed(true);
@ -143,44 +143,44 @@ namespace storm {
quantiles.setCumulativeRewardFormulasAllowed(true);
quantiles.setMultiDimensionalBoundedUntilFormulasAllowed(true);
quantiles.setMultiDimensionalCumulativeRewardFormulasAllowed(true);
return quantiles;
}
FragmentSpecification::FragmentSpecification() {
probabilityOperator = false;
rewardOperator = false;
expectedTimeOperator = false;
longRunAverageOperator = false;
multiObjectiveFormula = false;
quantileFormula = false;
globallyFormula = false;
reachabilityProbabilityFormula = false;
nextFormula = false;
untilFormula = false;
boundedUntilFormula = false;
atomicExpressionFormula = false;
atomicLabelFormula = false;
booleanLiteralFormula = false;
unaryBooleanStateFormula = false;
binaryBooleanStateFormula = false;
cumulativeRewardFormula = false;
instantaneousRewardFormula = false;
reachabilityRewardFormula = false;
longRunAverageRewardFormula = false;
totalRewardFormula = false;
conditionalProbabilityFormula = false;
conditionalRewardFormula = false;
reachabilityTimeFormula = false;
gameFormula = false;
nestedOperators = true;
nestedPathFormulas = false;
nestedMultiObjectiveFormulas = false;
@ -195,296 +195,296 @@ namespace storm {
rewardBoundedCumulativeRewardFormulas = false;
multiDimensionalCumulativeRewardFormulas = false;
varianceAsMeasureType = false;
qualitativeOperatorResults = true;
quantitativeOperatorResults = true;
operatorAtTopLevelRequired = false;
multiObjectiveFormulaAtTopLevelRequired = false;
operatorsAtTopLevelOfMultiObjectiveFormulasRequired = false;
quantileFormulaAtTopLevelRequired = false;
rewardAccumulation = false;
}
FragmentSpecification FragmentSpecification::copy() const {
return FragmentSpecification(*this);
}
bool FragmentSpecification::areProbabilityOperatorsAllowed() const {
return probabilityOperator;
}
FragmentSpecification& FragmentSpecification::setProbabilityOperatorsAllowed(bool newValue) {
this->probabilityOperator = newValue;
return *this;
}
bool FragmentSpecification::areRewardOperatorsAllowed() const {
return rewardOperator;
}
FragmentSpecification& FragmentSpecification::setRewardOperatorsAllowed(bool newValue) {
this->rewardOperator = newValue;
return *this;
}
bool FragmentSpecification::areTimeOperatorsAllowed() const {
return expectedTimeOperator;
}
FragmentSpecification& FragmentSpecification::setTimeOperatorsAllowed(bool newValue) {
this->expectedTimeOperator = newValue;
return *this;
}
bool FragmentSpecification::areLongRunAverageOperatorsAllowed() const {
return longRunAverageOperator;
}
FragmentSpecification& FragmentSpecification::setLongRunAverageOperatorsAllowed(bool newValue) {
this->longRunAverageOperator = newValue;
return *this;
}
bool FragmentSpecification::areMultiObjectiveFormulasAllowed() const {
return multiObjectiveFormula;
}
FragmentSpecification& FragmentSpecification::setMultiObjectiveFormulasAllowed( bool newValue) {
this->multiObjectiveFormula = newValue;
return *this;
}
bool FragmentSpecification::areQuantileFormulasAllowed() const {
return quantileFormula;
}
FragmentSpecification& FragmentSpecification::setQuantileFormulasAllowed( bool newValue) {
this->quantileFormula = newValue;
return *this;
}
bool FragmentSpecification::areGloballyFormulasAllowed() const {
return globallyFormula;
}
FragmentSpecification& FragmentSpecification::setGloballyFormulasAllowed(bool newValue) {
this->globallyFormula = newValue;
return *this;
}
bool FragmentSpecification::areReachabilityProbabilityFormulasAllowed() const {
return reachabilityProbabilityFormula;
}
FragmentSpecification& FragmentSpecification::setReachabilityProbabilityFormulasAllowed(bool newValue) {
this->reachabilityProbabilityFormula = newValue;
return *this;
}
bool FragmentSpecification::areNextFormulasAllowed() const {
return nextFormula;
}
FragmentSpecification& FragmentSpecification::setNextFormulasAllowed(bool newValue) {
this->nextFormula = newValue;
return *this;
}
bool FragmentSpecification::areUntilFormulasAllowed() const {
return untilFormula;
}
FragmentSpecification& FragmentSpecification::setUntilFormulasAllowed(bool newValue) {
this->untilFormula = newValue;
return *this;
}
bool FragmentSpecification::areBoundedUntilFormulasAllowed() const {
return boundedUntilFormula;
}
FragmentSpecification& FragmentSpecification::setBoundedUntilFormulasAllowed(bool newValue) {
this->boundedUntilFormula = newValue;
return *this;
}
bool FragmentSpecification::areAtomicExpressionFormulasAllowed() const {
return atomicExpressionFormula;
}
FragmentSpecification& FragmentSpecification::setAtomicExpressionFormulasAllowed(bool newValue) {
this->atomicExpressionFormula = newValue;
return *this;
}
bool FragmentSpecification::areAtomicLabelFormulasAllowed() const {
return atomicLabelFormula;
}
FragmentSpecification& FragmentSpecification::setAtomicLabelFormulasAllowed(bool newValue) {
this->atomicLabelFormula = newValue;
return *this;
}
bool FragmentSpecification::areBooleanLiteralFormulasAllowed() const {
return booleanLiteralFormula;
}
FragmentSpecification& FragmentSpecification::setBooleanLiteralFormulasAllowed(bool newValue) {
this->booleanLiteralFormula = newValue;
return *this;
}
bool FragmentSpecification::areUnaryBooleanStateFormulasAllowed() const {
return unaryBooleanStateFormula;
}
FragmentSpecification& FragmentSpecification::setUnaryBooleanStateFormulasAllowed(bool newValue) {
this->unaryBooleanStateFormula = newValue;
return *this;
}
bool FragmentSpecification::areBinaryBooleanStateFormulasAllowed() const {
return binaryBooleanStateFormula;
}
FragmentSpecification& FragmentSpecification::setBinaryBooleanStateFormulasAllowed(bool newValue) {
this->binaryBooleanStateFormula = newValue;
return *this;
}
bool FragmentSpecification::areCumulativeRewardFormulasAllowed() const {
return cumulativeRewardFormula;
}
FragmentSpecification& FragmentSpecification::setCumulativeRewardFormulasAllowed(bool newValue) {
this->cumulativeRewardFormula = newValue;
return *this;
}
bool FragmentSpecification::areInstantaneousRewardFormulasAllowed() const {
return instantaneousRewardFormula;
}
FragmentSpecification& FragmentSpecification::setInstantaneousFormulasAllowed(bool newValue) {
this->instantaneousRewardFormula = newValue;
return *this;
}
bool FragmentSpecification::areReachabilityRewardFormulasAllowed() const {
return reachabilityRewardFormula;
}
FragmentSpecification& FragmentSpecification::setReachabilityRewardFormulasAllowed(bool newValue) {
this->reachabilityRewardFormula = newValue;
return *this;
}
bool FragmentSpecification::areLongRunAverageRewardFormulasAllowed() const {
return longRunAverageRewardFormula;
}
FragmentSpecification& FragmentSpecification::setLongRunAverageRewardFormulasAllowed(bool newValue) {
this->longRunAverageRewardFormula = newValue;
return *this;
}
bool FragmentSpecification::areTotalRewardFormulasAllowed() const {
return totalRewardFormula;
}
FragmentSpecification& FragmentSpecification::setTotalRewardFormulasAllowed(bool newValue) {
this->totalRewardFormula = newValue;
return *this;
}
bool FragmentSpecification::areConditionalProbabilityFormulasAllowed() const {
return conditionalProbabilityFormula;
}
FragmentSpecification& FragmentSpecification::setConditionalProbabilityFormulasAllowed(bool newValue) {
this->conditionalProbabilityFormula = newValue;
return *this;
}
bool FragmentSpecification::areConditionalRewardFormulasFormulasAllowed() const {
return conditionalRewardFormula;
}
FragmentSpecification& FragmentSpecification::setConditionalRewardFormulasAllowed(bool newValue) {
this->conditionalRewardFormula = newValue;
return *this;
}
bool FragmentSpecification::areReachbilityTimeFormulasAllowed() const {
return reachabilityTimeFormula;
}
FragmentSpecification& FragmentSpecification::setReachbilityTimeFormulasAllowed(bool newValue) {
this->reachabilityTimeFormula = newValue;
return *this;
}
bool FragmentSpecification::areNestedOperatorsAllowed() const {
return this->nestedOperators;
}
FragmentSpecification& FragmentSpecification::setNestedOperatorsAllowed(bool newValue) {
this->nestedOperators = newValue;
return *this;
}
bool FragmentSpecification::areNestedPathFormulasAllowed() const {
return this->nestedPathFormulas;
}
FragmentSpecification& FragmentSpecification::setNestedPathFormulasAllowed(bool newValue) {
this->nestedPathFormulas = newValue;
return *this;
}
bool FragmentSpecification::areNestedMultiObjectiveFormulasAllowed() const {
return this->nestedMultiObjectiveFormulas;
}
FragmentSpecification& FragmentSpecification::setNestedMultiObjectiveFormulasAllowed(bool newValue) {
this->nestedMultiObjectiveFormulas = newValue;
return *this;
}
bool FragmentSpecification::areNestedOperatorsInsideMultiObjectiveFormulasAllowed() const {
return this->nestedOperatorsInsideMultiObjectiveFormulas;
}
FragmentSpecification& FragmentSpecification::setNestedOperatorsInsideMultiObjectiveFormulasAllowed(bool newValue) {
this->nestedOperatorsInsideMultiObjectiveFormulas = newValue;
return *this;
}
bool FragmentSpecification::areOnlyEventuallyFormuluasInConditionalFormulasAllowed() const {
return this->onlyEventuallyFormuluasInConditionalFormulas;
}
FragmentSpecification& FragmentSpecification::setOnlyEventuallyFormuluasInConditionalFormulasAllowed(bool newValue) {
this->onlyEventuallyFormuluasInConditionalFormulas = newValue;
return *this;
}
bool FragmentSpecification::areStepBoundedUntilFormulasAllowed() const {
return this->stepBoundedUntilFormulas;
}
FragmentSpecification& FragmentSpecification::setStepBoundedUntilFormulasAllowed(bool newValue) {
this->stepBoundedUntilFormulas = newValue;
return *this;
}
bool FragmentSpecification::areTimeBoundedUntilFormulasAllowed() const {
return this->timeBoundedUntilFormulas;
}
FragmentSpecification& FragmentSpecification::setTimeBoundedUntilFormulasAllowed(bool newValue) {
this->timeBoundedUntilFormulas = newValue;
return *this;
@ -498,7 +498,7 @@ namespace storm {
this->rewardBoundedUntilFormulas = newValue;
return *this;
}
bool FragmentSpecification::areMultiDimensionalBoundedUntilFormulasAllowed() const {
return this->multiDimensionalBoundedUntilFormulas;
}
@ -511,16 +511,16 @@ namespace storm {
bool FragmentSpecification::areStepBoundedCumulativeRewardFormulasAllowed() const {
return this->stepBoundedCumulativeRewardFormulas;
}
FragmentSpecification& FragmentSpecification::setStepBoundedCumulativeRewardFormulasAllowed(bool newValue) {
this->stepBoundedCumulativeRewardFormulas = newValue;
return *this;
}
bool FragmentSpecification::areTimeBoundedCumulativeRewardFormulasAllowed() const {
return this->timeBoundedCumulativeRewardFormulas;
}
FragmentSpecification& FragmentSpecification::setTimeBoundedCumulativeRewardFormulasAllowed(bool newValue) {
this->timeBoundedCumulativeRewardFormulas = newValue;
return *this;
@ -534,7 +534,7 @@ namespace storm {
this->rewardBoundedCumulativeRewardFormulas = newValue;
return *this;
}
bool FragmentSpecification::areMultiDimensionalCumulativeRewardFormulasAllowed() const {
return this->multiDimensionalCumulativeRewardFormulas;
}
@ -543,7 +543,7 @@ namespace storm {
this->multiDimensionalCumulativeRewardFormulas = newValue;
return *this;
}
FragmentSpecification& FragmentSpecification::setOperatorsAllowed(bool newValue) {
this->setProbabilityOperatorsAllowed(newValue);
this->setRewardOperatorsAllowed(newValue);
@ -551,40 +551,40 @@ namespace storm {
this->setTimeOperatorsAllowed(newValue);
return *this;
}
FragmentSpecification& FragmentSpecification::setTimeAllowed(bool newValue) {
this->setTimeOperatorsAllowed(newValue);
this->setReachbilityTimeFormulasAllowed(newValue);
return *this;
}
FragmentSpecification& FragmentSpecification::setLongRunAverageProbabilitiesAllowed(bool newValue) {
this->setLongRunAverageOperatorsAllowed(newValue);
return *this;
}
bool FragmentSpecification::isVarianceMeasureTypeAllowed() const {
return varianceAsMeasureType;
}
FragmentSpecification& FragmentSpecification::setVarianceMeasureTypeAllowed(bool newValue) {
this->varianceAsMeasureType = newValue;
return *this;
}
bool FragmentSpecification::areQuantitativeOperatorResultsAllowed() const {
return this->quantitativeOperatorResults;
}
FragmentSpecification& FragmentSpecification::setQuantitativeOperatorResultsAllowed(bool newValue) {
this->quantitativeOperatorResults = newValue;
return *this;
}
bool FragmentSpecification::areQualitativeOperatorResultsAllowed() const {
return this->qualitativeOperatorResults;
}
FragmentSpecification& FragmentSpecification::setQualitativeOperatorResultsAllowed(bool newValue) {
this->qualitativeOperatorResults = newValue;
return *this;
@ -593,7 +593,7 @@ namespace storm {
bool FragmentSpecification::isOperatorAtTopLevelRequired() const {
return operatorAtTopLevelRequired;
}
FragmentSpecification& FragmentSpecification::setOperatorAtTopLevelRequired(bool newValue) {
operatorAtTopLevelRequired = newValue;
return *this;
@ -602,7 +602,7 @@ namespace storm {
bool FragmentSpecification::isMultiObjectiveFormulaAtTopLevelRequired() const {
return multiObjectiveFormulaAtTopLevelRequired;
}
FragmentSpecification& FragmentSpecification::setMultiObjectiveFormulaAtTopLevelRequired(bool newValue) {
multiObjectiveFormulaAtTopLevelRequired = newValue;
return *this;
@ -611,7 +611,7 @@ namespace storm {
bool FragmentSpecification::areOperatorsAtTopLevelOfMultiObjectiveFormulasRequired() const {
return operatorsAtTopLevelOfMultiObjectiveFormulasRequired;
}
FragmentSpecification& FragmentSpecification::setOperatorsAtTopLevelOfMultiObjectiveFormulasRequired(bool newValue) {
operatorsAtTopLevelOfMultiObjectiveFormulasRequired = newValue;
return *this;

38
src/storm/logic/FragmentSpecification.h

@ -6,9 +6,9 @@
namespace storm {
namespace logic {
class RewardAccumulation;
class FragmentSpecification {
public:
FragmentSpecification();
@ -16,24 +16,24 @@ namespace storm {
FragmentSpecification(FragmentSpecification&& other) = default;
FragmentSpecification& operator=(FragmentSpecification const& other) = default;
FragmentSpecification& operator=(FragmentSpecification&& other) = default;
FragmentSpecification copy() const;
bool areProbabilityOperatorsAllowed() const;
FragmentSpecification& setProbabilityOperatorsAllowed(bool newValue);
bool areRewardOperatorsAllowed() const;
FragmentSpecification& setRewardOperatorsAllowed(bool newValue);
bool areTimeOperatorsAllowed() const;
FragmentSpecification& setTimeOperatorsAllowed(bool newValue);
bool areLongRunAverageOperatorsAllowed() const;
FragmentSpecification& setLongRunAverageOperatorsAllowed(bool newValue);
bool areMultiObjectiveFormulasAllowed() const;
FragmentSpecification& setMultiObjectiveFormulasAllowed( bool newValue);
bool areQuantileFormulasAllowed() const;
FragmentSpecification& setQuantileFormulasAllowed( bool newValue);
@ -75,10 +75,10 @@ namespace storm {
bool areReachabilityRewardFormulasAllowed() const;
FragmentSpecification& setReachabilityRewardFormulasAllowed(bool newValue);
bool areLongRunAverageRewardFormulasAllowed() const;
FragmentSpecification& setLongRunAverageRewardFormulasAllowed(bool newValue);
bool areTotalRewardFormulasAllowed() const;
FragmentSpecification& setTotalRewardFormulasAllowed(bool newValue);
@ -156,7 +156,7 @@ namespace storm {
bool areGameFormulasAllowed() const;
FragmentSpecification& setGameFormulasAllowed(bool newValue);
FragmentSpecification& setOperatorsAllowed(bool newValue);
FragmentSpecification& setTimeAllowed(bool newValue);
FragmentSpecification& setLongRunAverageProbabilitiesAllowed(bool newValue);
@ -217,16 +217,16 @@ namespace storm {
bool multiObjectiveFormulaAtTopLevelRequired;
bool quantileFormulaAtTopLevelRequired;
bool operatorsAtTopLevelOfMultiObjectiveFormulasRequired;
bool rewardAccumulation;
};
// Propositional.
FragmentSpecification propositional();
// Just reachability properties.
FragmentSpecification reachability();
// Regular PCTL.
FragmentSpecification pctl();
@ -238,16 +238,16 @@ namespace storm {
// PCTL + cumulative, instantaneous, reachability and long-run rewards.
FragmentSpecification prctl();
// Regular CSL.
FragmentSpecification csl();
// CSL + cumulative, instantaneous, reachability and long-run rewards.
FragmentSpecification csrl();
// Multi-Objective formulas.
FragmentSpecification multiObjective();
// Quantile formulas.
FragmentSpecification quantiles();

6
src/storm/logic/GameFormula.cpp

@ -23,7 +23,11 @@ namespace storm {
PlayerCoalition const& GameFormula::getCoalition() const {
return coalition;
}
void GameFormula::gatherReferencedRewardModels(std::set<std::string>& referencedRewardModels) const {
this->getSubformula().gatherReferencedRewardModels(referencedRewardModels);
}
boost::any GameFormula::accept(FormulaVisitor const& visitor, boost::any const& data) const {
return visitor.visit(*this, data);
}

2
src/storm/logic/GameFormula.h

@ -19,7 +19,7 @@ namespace storm {
virtual bool isGameFormula() const override;
virtual bool hasQualitativeResult() const override;
virtual bool hasQuantitativeResult() const override;
virtual boost::any accept(FormulaVisitor const& visitor, boost::any const& data) const override;
virtual std::ostream& writeToStream(std::ostream& out) const override;

36
src/storm/logic/LiftableTransitionRewardsVisitor.cpp

@ -5,38 +5,38 @@
namespace storm {
namespace logic {
LiftableTransitionRewardsVisitor::LiftableTransitionRewardsVisitor(storm::storage::SymbolicModelDescription const& symbolicModelDescription) : symbolicModelDescription(symbolicModelDescription) {
// Intentionally left empty.
}
bool LiftableTransitionRewardsVisitor::areTransitionRewardsLiftable(Formula const& f) const {
return boost::any_cast<bool>(f.accept(*this, boost::any()));
}
boost::any LiftableTransitionRewardsVisitor::visit(AtomicExpressionFormula const&, boost::any const&) const {
return true;
}
boost::any LiftableTransitionRewardsVisitor::visit(AtomicLabelFormula const&, boost::any const&) const {
return true;
}
boost::any LiftableTransitionRewardsVisitor::visit(BinaryBooleanStateFormula const&, boost::any const&) const {
return true;
}
boost::any LiftableTransitionRewardsVisitor::visit(BooleanLiteralFormula const&, boost::any const&) const {
return true;
}
boost::any LiftableTransitionRewardsVisitor::visit(BoundedUntilFormula const& f, boost::any const& data) const {
for (unsigned i = 0; i < f.getDimension(); ++i) {
if (f.getTimeBoundReference(i).isRewardBound() && rewardModelHasTransitionRewards(f.getTimeBoundReference(i).getRewardName())) {
return false;
}
}
bool result = true;
if (f.hasMultiDimensionalSubformulas()) {
for (unsigned i = 0; i < f.getDimension(); ++i) {
@ -49,11 +49,11 @@ namespace storm {
}
return result;
}
boost::any LiftableTransitionRewardsVisitor::visit(ConditionalFormula const& f, boost::any const& data) const {
return !f.isConditionalRewardFormula() && boost::any_cast<bool>(f.getSubformula().accept(*this, data)) && boost::any_cast<bool>(f.getConditionFormula().accept(*this, data));
}
boost::any LiftableTransitionRewardsVisitor::visit(CumulativeRewardFormula const& f, boost::any const&) const {
for (unsigned i = 0; i < f.getDimension(); ++i) {
if (f.getTimeBoundReference(i).isRewardBound() && rewardModelHasTransitionRewards(f.getTimeBoundReference(i).getRewardName())) {
@ -100,35 +100,35 @@ namespace storm {
}
return result;
}
boost::any LiftableTransitionRewardsVisitor::visit(QuantileFormula const& f, boost::any const& data) const {
return f.getSubformula().accept(*this, data);
}
boost::any LiftableTransitionRewardsVisitor::visit(NextFormula const& f, boost::any const& data) const {
return boost::any_cast<bool>(f.getSubformula().accept(*this, data));
}
boost::any LiftableTransitionRewardsVisitor::visit(ProbabilityOperatorFormula const& f, boost::any const& data) const {
return f.getSubformula().accept(*this, data);
}
boost::any LiftableTransitionRewardsVisitor::visit(RewardOperatorFormula const& f, boost::any const& data) const {
return boost::any_cast<bool>(f.getSubformula().accept(*this, data));
}
boost::any LiftableTransitionRewardsVisitor::visit(TotalRewardFormula const&, boost::any const&) const {
return true;
}
boost::any LiftableTransitionRewardsVisitor::visit(UnaryBooleanStateFormula const& f, boost::any const& data) const {
return f.getSubformula().accept(*this, data);
}
boost::any LiftableTransitionRewardsVisitor::visit(UntilFormula const& f, boost::any const& data) const {
return boost::any_cast<bool>(f.getLeftSubformula().accept(*this, data)) && boost::any_cast<bool>(f.getRightSubformula().accept(*this));
}
bool LiftableTransitionRewardsVisitor::rewardModelHasTransitionRewards(std::string const& rewardModelName) const {
if (symbolicModelDescription.hasModel()) {
if (symbolicModelDescription.isJaniModel()) {

2
src/storm/modelchecker/AbstractModelChecker.cpp

@ -54,6 +54,8 @@ namespace storm {
return this->checkMultiObjectiveFormula(env, checkTask.substituteFormula(formula.asMultiObjectiveFormula()));
} else if (formula.isQuantileFormula()){
return this->checkQuantileFormula(env, checkTask.substituteFormula(formula.asQuantileFormula()));
} else if(formula.isGameFormula()){
return this->checkGameFormula(env, checkTask.substituteFormula(formula.asGameFormula()));
}
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "The given formula '" << formula << "' is invalid.");
}

4
src/storm/modelchecker/helper/infinitehorizon/SparseInfiniteHorizonHelper.h

@ -93,8 +93,8 @@ namespace storm {
* @param actionValuesGetter a function returning a value for a given (global) choice index
* @return a value for each state
*/
std::vector<ValueType> computeLongRunAverageValues(Environment const& env, ValueGetter const& stateValuesGetter, ValueGetter const& actionValuesGetter);
virtual std::vector<ValueType> computeLongRunAverageValues(Environment const& env, ValueGetter const& stateValuesGetter, ValueGetter const& actionValuesGetter);
/*!
* @param stateValuesGetter a function returning a value for a given state index
* @param actionValuesGetter a function returning a value for a given (global) choice index

135
src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.cpp

@ -0,0 +1,135 @@
#include "SparseNondeterministicGameInfiniteHorizonHelper.h"
#include "storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.h"
#include "storm/storage/SparseMatrix.h"
#include "storm/storage/MaximalEndComponentDecomposition.h"
#include "storm/storage/GameMaximalEndComponentDecomposition.h"
#include "storm/storage/Scheduler.h"
#include "storm/solver/MinMaxLinearEquationSolver.h"
#include "storm/solver/Multiplier.h"
#include "storm/utility/solver.h"
#include "storm/utility/vector.h"
#include "storm/environment/solver/LongRunAverageSolverEnvironment.h"
#include "storm/environment/solver/MinMaxSolverEnvironment.h"
#include "storm/exceptions/UnmetRequirementException.h"
#include "storm/exceptions/InternalException.h"
namespace storm {
namespace modelchecker {
namespace helper {
template <typename ValueType>
SparseNondeterministicGameInfiniteHorizonHelper<ValueType>::SparseNondeterministicGameInfiniteHorizonHelper(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<std::pair<std::string, uint_fast64_t>> const& player) : SparseInfiniteHorizonHelper<ValueType, true>(transitionMatrix), player(player) {
// Intentionally left empty.
}
template <typename ValueType>
std::vector<uint64_t> const& SparseNondeterministicGameInfiniteHorizonHelper<ValueType>::getProducedOptimalChoices() const {
STORM_LOG_ASSERT(this->isProduceSchedulerSet(), "Trying to get the produced optimal choices although no scheduler was requested.");
STORM_LOG_ASSERT(this->_producedOptimalChoices.is_initialized(), "Trying to get the produced optimal choices but none were available. Was there a computation call before?");
return this->_producedOptimalChoices.get();
}
template <typename ValueType>
std::vector<uint64_t>& SparseNondeterministicGameInfiniteHorizonHelper<ValueType>::getProducedOptimalChoices() {
STORM_LOG_ASSERT(this->isProduceSchedulerSet(), "Trying to get the produced optimal choices although no scheduler was requested.");
STORM_LOG_ASSERT(this->_producedOptimalChoices.is_initialized(), "Trying to get the produced optimal choices but none were available. Was there a computation call before?");
return this->_producedOptimalChoices.get();
}
template <typename ValueType>
storm::storage::Scheduler<ValueType> SparseNondeterministicGameInfiniteHorizonHelper<ValueType>::extractScheduler() const {
auto const& optimalChoices = getProducedOptimalChoices();
storm::storage::Scheduler<ValueType> scheduler(optimalChoices.size());
for (uint64_t state = 0; state < optimalChoices.size(); ++state) {
scheduler.setChoice(optimalChoices[state], state);
}
return scheduler;
}
template <typename ValueType>
void SparseNondeterministicGameInfiniteHorizonHelper<ValueType>::createDecomposition() {
// TODO This needs to be changed to return the whole model as one component as long as there is no overwritten version of MaximalEndComponentDecomposition for SMGs.
if (this->_longRunComponentDecomposition == nullptr) {
// The decomposition has not been provided or computed, yet.
if (this->_backwardTransitions == nullptr) {
this->_computedBackwardTransitions = std::make_unique<storm::storage::SparseMatrix<ValueType>>(this->_transitionMatrix.transpose(true));
this->_backwardTransitions = this->_computedBackwardTransitions.get();
}
this->_computedLongRunComponentDecomposition = std::make_unique<storm::storage::GameMaximalEndComponentDecomposition<ValueType>>(this->_transitionMatrix, *this->_backwardTransitions);
this->_longRunComponentDecomposition = this->_computedLongRunComponentDecomposition.get();
//STORM_LOG_DEBUG("\n" << this->_transitionMatrix);
STORM_LOG_DEBUG("GMEC: " << *(this->_longRunComponentDecomposition));
}
}
template <typename ValueType>
std::vector<ValueType> SparseNondeterministicGameInfiniteHorizonHelper<ValueType>::computeLongRunAverageValues(Environment const& env, ValueGetter const& stateValuesGetter, ValueGetter const& actionValuesGetter) {
auto underlyingSolverEnvironment = env;
std::vector<ValueType> componentLraValues;
createDecomposition();
componentLraValues.reserve(this->_longRunComponentDecomposition->size());
for (auto const& c : *(this->_longRunComponentDecomposition)) {
componentLraValues.push_back(computeLraForComponent(underlyingSolverEnvironment, stateValuesGetter, actionValuesGetter, c));
}
return componentLraValues;
}
template <typename ValueType>
ValueType SparseNondeterministicGameInfiniteHorizonHelper<ValueType>::computeLraForComponent(Environment const& env, ValueGetter const& stateRewardsGetter, ValueGetter const& actionRewardsGetter, storm::storage::MaximalEndComponent const& component) {
// Allocate memory for the nondeterministic choices.
if (this->isProduceSchedulerSet()) {
if (!this->_producedOptimalChoices.is_initialized()) {
this->_producedOptimalChoices.emplace();
}
this->_producedOptimalChoices->resize(this->_transitionMatrix.getRowGroupCount());
}
storm::solver::LraMethod method = env.solver().lra().getNondetLraMethod();
if (method == storm::solver::LraMethod::LinearProgramming) {
STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Unsupported technique.");
} else if (method == storm::solver::LraMethod::ValueIteration) {
return computeLraVi(env, stateRewardsGetter, actionRewardsGetter, component);
} else {
STORM_LOG_THROW(false, storm::exceptions::InvalidSettingsException, "Unsupported technique.");
}
}
template <typename ValueType>
ValueType SparseNondeterministicGameInfiniteHorizonHelper<ValueType>::computeLraVi(Environment const& env, ValueGetter const& stateRewardsGetter, ValueGetter const& actionRewardsGetter, storm::storage::MaximalEndComponent const& mec) {
// Collect some parameters of the computation
ValueType aperiodicFactor = storm::utility::convertNumber<ValueType>(env.solver().lra().getAperiodicFactor());
std::vector<uint64_t>* optimalChoices = nullptr;
if (this->isProduceSchedulerSet()) {
optimalChoices = &this->_producedOptimalChoices.get();
}
// Now create a helper and perform the algorithm
if (this->isContinuousTime()) {
STORM_LOG_THROW(false, storm::exceptions::InternalException, "We cannot handle continuous time games.");
} else {
storm::modelchecker::helper::internal::LraViHelper<ValueType, storm::storage::MaximalEndComponent, storm::modelchecker::helper::internal::LraViTransitionsType::GameNondetTsNoIs> viHelper(mec, this->_transitionMatrix, aperiodicFactor);
return viHelper.performValueIteration(env, stateRewardsGetter, actionRewardsGetter, nullptr, &this->getOptimizationDirection(), optimalChoices);
}
}
template <typename ValueType>
std::vector<ValueType> SparseNondeterministicGameInfiniteHorizonHelper<ValueType>::buildAndSolveSsp(Environment const& env, std::vector<ValueType> const& componentLraValues) {
STORM_LOG_THROW(false, storm::exceptions::InternalException, "We do not create compositions for LRA for SMGs, solving a stochastic shortest path problem is not available.");
}
template class SparseNondeterministicGameInfiniteHorizonHelper<double>;
template class SparseNondeterministicGameInfiniteHorizonHelper<storm::RationalNumber>;
}
}
}

73
src/storm/modelchecker/helper/infinitehorizon/SparseNondeterministicGameInfiniteHorizonHelper.h

@ -0,0 +1,73 @@
#pragma once
#include "storm/modelchecker/helper/infinitehorizon/SparseInfiniteHorizonHelper.h"
namespace storm {
namespace storage {
template <typename VT> class Scheduler;
}
namespace modelchecker {
namespace helper {
/*!
* Helper class for model checking queries that depend on the long run behavior of the (nondeterministic) system with different players choices.
* @tparam ValueType the type a value can have
*/
template <typename ValueType>
class SparseNondeterministicGameInfiniteHorizonHelper : public SparseInfiniteHorizonHelper<ValueType, true> {
public:
/*!
* Function mapping from indices to values
*/
typedef typename SparseInfiniteHorizonHelper<ValueType, true>::ValueGetter ValueGetter;
/*!
* Initializes the helper for a discrete time model with different players (i.e. SMG)
*/
SparseNondeterministicGameInfiniteHorizonHelper(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<std::pair<std::string, uint_fast64_t>> const& player);
/*! TODO
* Computes the long run average value given the provided state and action based rewards
* @param stateValuesGetter a function returning a value for a given state index
* @param actionValuesGetter a function returning a value for a given (global) choice index
* @return a value for each state
*/
std::vector<ValueType> computeLongRunAverageValues(Environment const& env, ValueGetter const& stateValuesGetter, ValueGetter const& actionValuesGetter) override;
/*!
* @pre before calling this, a computation call should have been performed during which scheduler production was enabled.
* @return the produced scheduler of the most recent call.
*/
std::vector<uint64_t> const& getProducedOptimalChoices() const;
/*!
* @pre before calling this, a computation call should have been performed during which scheduler production was enabled.
* @return the produced scheduler of the most recent call.
*/
std::vector<uint64_t>& getProducedOptimalChoices();
/*!
* @pre before calling this, a computation call should have been performed during which scheduler production was enabled.
* @return a new scheduler containing optimal choices for each state that yield the long run average values of the most recent call.
*/
storm::storage::Scheduler<ValueType> extractScheduler() const;
ValueType computeLraForComponent(Environment const& env, ValueGetter const& stateValuesGetter, ValueGetter const& actionValuesGetter, storm::storage::MaximalEndComponent const& component);
ValueType computeLraVi(Environment const& env, ValueGetter const& stateValuesGetter, ValueGetter const& actionValuesGetter, storm::storage::MaximalEndComponent const& mec);
void createDecomposition();
std::vector<ValueType> buildAndSolveSsp(Environment const& env, std::vector<ValueType> const& mecLraValues);
private:
std::vector<std::pair<std::string, uint_fast64_t>> player;
};
}
}
}

120
src/storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.cpp

@ -14,6 +14,7 @@
#include "storm/environment/solver/SolverEnvironment.h"
#include "storm/environment/solver/LongRunAverageSolverEnvironment.h"
#include "storm/environment/solver/MinMaxSolverEnvironment.h"
#include "storm/environment/solver/MultiplierEnvironment.h"
#include "storm/exceptions/UnmetRequirementException.h"
@ -23,11 +24,11 @@ namespace storm {
namespace modelchecker {
namespace helper {
namespace internal {
template <typename ValueType, typename ComponentType, LraViTransitionsType TransitionsType>
LraViHelper<ValueType, ComponentType, TransitionsType>::LraViHelper(ComponentType const& component, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, ValueType const& aperiodicFactor, storm::storage::BitVector const* timedStates, std::vector<ValueType> const* exitRates) : _transitionMatrix(transitionMatrix), _timedStates(timedStates), _hasInstantStates(TransitionsType == LraViTransitionsType::DetTsNondetIs || TransitionsType == LraViTransitionsType::DetTsDetIs), _Tsx1IsCurrent(false) {
setComponent(component);
// Run through the component and collect some data:
// We create two submodels, one consisting of the timed states of the component and one consisting of the instant states of the component.
// For this, we create a state index map that point from state indices of the input model to indices of the corresponding submodel of that state.
@ -140,8 +141,9 @@ namespace storm {
_IsTransitions = isTransitionsBuilder.build();
_IsToTsTransitions = isToTsTransitionsBuilder.build();
}
STORM_LOG_DEBUG(uniformizationFactor << " - " << _uniformizationRate);
}
template <typename ValueType, typename ComponentType, LraViTransitionsType TransitionsType>
void LraViHelper<ValueType, ComponentType, TransitionsType>::setComponent(ComponentType component) {
_component.clear();
@ -155,7 +157,7 @@ namespace storm {
}
}
template <typename ValueType, typename ComponentType, LraViTransitionsType TransitionsType>
ValueType LraViHelper<ValueType, ComponentType, TransitionsType>::performValueIteration(Environment const& env, ValueGetter const& stateValueGetter, ValueGetter const& actionValueGetter, std::vector<ValueType> const* exitRates, storm::solver::OptimizationDirection const* dir, std::vector<uint64_t>* choices) {
initializeNewValues(stateValueGetter, actionValueGetter, exitRates);
@ -165,26 +167,43 @@ namespace storm {
if (env.solver().lra().isMaximalIterationCountSet()) {
maxIter = env.solver().lra().getMaximalIterationCount();
}
// start the iterations
ValueType result = storm::utility::zero<ValueType>();
uint64_t iter = 0;
while (!maxIter.is_initialized() || iter < maxIter.get()) {
++iter;
performIterationStep(env, dir);
std::vector<ValueType> xOldTemp = xOld();
std::vector<ValueType> xNewTemp = xNew();
if(gameNondetTs() && iter > 1) {
// Weight values with current iteration step
storm::utility::vector::applyPointwise<ValueType, ValueType>(xOld(), xOld(), [&iter] (ValueType const& x_i) -> ValueType { return x_i / (double)(iter - 1); });
storm::utility::vector::applyPointwise<ValueType, ValueType>(xNew(), xNew(), [&iter] (ValueType const& x_i) -> ValueType { return x_i / (double)iter; });
}
// Check if we are done
auto convergenceCheckResult = checkConvergence(relative, precision);
result = convergenceCheckResult.currentValue;
if(gameNondetTs() && iter > 1) {
xOld() = xOldTemp;
xNew() = xNewTemp;
}
if (convergenceCheckResult.isPrecisionAchieved) {
break;
}
if (storm::utility::resources::isTerminate()) {
break;
}
// If there will be a next iteration, we have to prepare it.
prepareNextIteration(env);
if(!gameNondetTs()) {
prepareNextIteration(env);
}
}
if (maxIter.is_initialized() && iter == maxIter.get()) {
STORM_LOG_WARN("LRA computation did not converge within " << iter << " iterations.");
@ -193,15 +212,24 @@ namespace storm {
} else {
STORM_LOG_TRACE("LRA computation converged after " << iter << " iterations.");
}
if (choices) {
// We will be doing one more iteration step and track scheduler choices this time.
prepareNextIteration(env);
if(!gameNondetTs()) {
prepareNextIteration(env);
}
performIterationStep(env, dir, choices);
}
std::cout << "result (" << iter << " steps):" << std::endl;
storm::utility::vector::applyPointwise<ValueType, ValueType>(xNew(), xNew(), [&iter] (ValueType const& x_i) -> ValueType { return x_i / (double)iter; });
for(int i = 0; i < xNew().size() ; i++ ) {
std::cout << std::setprecision(4) << i << "\t: " << xNew().at(i) << "\t" << xNew().at(i) * _uniformizationRate << "\t" << std::setprecision(16) << xOld().at(i) *_uniformizationRate << std::endl;
//if(i == 50) {std::cout << "only showing top 50 lines"; break; }
}
if(gameNondetTs()) result = xOld().at(0) * _uniformizationRate; // TODO is "init" always going to be .at(0) ?
return result;
}
template <typename ValueType, typename ComponentType, LraViTransitionsType TransitionsType>
void LraViHelper<ValueType, ComponentType, TransitionsType>::initializeNewValues(ValueGetter const& stateValueGetter, ValueGetter const& actionValueGetter, std::vector<ValueType> const* exitRates) {
// clear potential old values and reserve enough space for new values
@ -211,7 +239,7 @@ namespace storm {
_IsChoiceValues.clear();
_IsChoiceValues.reserve(_IsTransitions.getRowCount());
}
// Set the new choice-based values
ValueType actionRewardScalingFactor = storm::utility::one<ValueType>() / _uniformizationRate;
for (auto const& element : _component) {
@ -236,14 +264,14 @@ namespace storm {
// Set-up new iteration vectors for timed states
_Tsx1.assign(_TsTransitions.getRowGroupCount(), storm::utility::zero<ValueType>());
_Tsx2 = _Tsx1;
if (_hasInstantStates) {
// Set-up vectors for storing intermediate results for instant states.
_Isx.resize(_IsTransitions.getRowGroupCount(), storm::utility::zero<ValueType>());
_Isb = _IsChoiceValues;
}
}
template <typename ValueType, typename ComponentType, LraViTransitionsType TransitionsType>
void LraViHelper<ValueType, ComponentType, TransitionsType>::prepareSolversAndMultipliers(const Environment& env, storm::solver::OptimizationDirection const* dir) {
_TsMultiplier = storm::solver::MultiplierFactory<ValueType>().create(env, _TsTransitions);
@ -301,13 +329,16 @@ namespace storm {
STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UnmetRequirementException, "The solver requirement " << req.getEnabledRequirementsAsString() << " has not been cleared.");
}
}
// Set up multipliers for transitions connecting timed and instant states
_TsToIsMultiplier = storm::solver::MultiplierFactory<ValueType>().create(env, _TsToIsTransitions);
_IsToTsMultiplier = storm::solver::MultiplierFactory<ValueType>().create(env, _IsToTsTransitions);
}
if(env.solver().multiplier().getOptimizationDirectionOverride().is_initialized()) {
_TsMultiplier->setOptimizationDirectionOverride(env.solver().multiplier().getOptimizationDirectionOverride().get());
}
}
template <typename ValueType, typename ComponentType, LraViTransitionsType TransitionsType>
void LraViHelper<ValueType, ComponentType, TransitionsType>::setInputModelChoices(std::vector<uint64_t>& choices, std::vector<uint64_t> const& localMecChoices, bool setChoiceZeroToTimedStates, bool setChoiceZeroToInstantStates) const {
// Transform the local choices (within this mec) to choice indices for the input model
@ -330,7 +361,7 @@ namespace storm {
}
STORM_LOG_ASSERT(localState == localMecChoices.size(), "Did not traverse all component states.");
}
template <typename ValueType, typename ComponentType, LraViTransitionsType TransitionsType>
void LraViHelper<ValueType, ComponentType, TransitionsType>::performIterationStep(Environment const& env, storm::solver::OptimizationDirection const* dir, std::vector<uint64_t>* choices) {
STORM_LOG_ASSERT(!((nondetTs() || nondetIs()) && dir == nullptr), "No optimization direction provided for model with nondeterminism");
@ -338,15 +369,15 @@ namespace storm {
if (!_TsMultiplier) {
prepareSolversAndMultipliers(env, dir);
}
// Compute new x values for the timed states
// Flip what is new and what is old
_Tsx1IsCurrent = !_Tsx1IsCurrent;
// At this point, xOld() points to what has been computed in the most recent call of performIterationStep (initially, this is the 0-vector).
// The result of this ongoing computation will be stored in xNew()
// Compute the values obtained by a single uniformization step between timed states only
if (nondetTs()) {
if (nondetTs() && !gameNondetTs()) {
if (choices == nullptr) {
_TsMultiplier->multiplyAndReduce(env, *dir, xOld(), &_TsChoiceValues, xNew());
} else {
@ -358,6 +389,14 @@ namespace storm {
STORM_LOG_ASSERT(!_hasInstantStates, "Nondeterministic timed states are only supported if there are no instant states.");
setInputModelChoices(*choices, tsChoices);
}
} else if(gameNondetTs()) { // TODO DRYness? exact same behaviour as case above?
if (choices == nullptr) {
_TsMultiplier->multiplyAndReduce(env, *dir, xOld(), &_TsChoiceValues, xNew());
} else {
std::vector<uint64_t> tsChoices(_TsTransitions.getRowGroupCount());
_TsMultiplier->multiplyAndReduce(env, *dir, xOld(), &_TsChoiceValues, xNew(), &tsChoices);
setInputModelChoices(*choices, tsChoices); // no components -> no need for that call?
}
} else {
_TsMultiplier->multiply(env, xOld(), &_TsChoiceValues, xNew());
}
@ -400,7 +439,7 @@ namespace storm {
_TsToIsMultiplier->multiply(env, _Isx, &xNew(), xNew());
}
}
template <typename ValueType, typename ComponentType, LraViTransitionsType TransitionsType>
typename LraViHelper<ValueType, ComponentType, TransitionsType>::ConvergenceCheckResult LraViHelper<ValueType, ComponentType, TransitionsType>::checkConvergence(bool relative, ValueType precision) const {
STORM_LOG_ASSERT(_TsMultiplier, "tried to check for convergence without doing an iteration first.");
@ -408,7 +447,7 @@ namespace storm {
// We need to 'revert' this scaling when computing the absolute precision.
// However, for relative precision, the scaling cancels out.
ValueType threshold = relative ? precision : ValueType(precision / _uniformizationRate);
ConvergenceCheckResult res = { true, storm::utility::one<ValueType>() };
// Now check whether the currently produced results are precise enough
STORM_LOG_ASSERT(threshold > storm::utility::zero<ValueType>(), "Did not expect a non-positive threshold.");
@ -435,15 +474,15 @@ namespace storm {
break;
}
}
// Compute the average of the maximal and the minimal difference.
ValueType avgDiff = (maxDiff + minDiff) / (storm::utility::convertNumber<ValueType>(2.0));
// "Undo" the scaling of the values
res.currentValue = avgDiff * _uniformizationRate;
return res;
}
template <typename ValueType, typename ComponentType, LraViTransitionsType TransitionsType>
void LraViHelper<ValueType, ComponentType, TransitionsType>::prepareNextIteration(Environment const& env) {
// To avoid large (and numerically unstable) x-values, we substract a reference value.
@ -455,53 +494,60 @@ namespace storm {
_IsToTsMultiplier->multiply(env, xNew(), &_IsChoiceValues, _Isb);
}
}
template <typename ValueType, typename ComponentType, LraViTransitionsType TransitionsType>
bool LraViHelper<ValueType, ComponentType, TransitionsType>::isTimedState(uint64_t const& inputModelStateIndex) const {
STORM_LOG_ASSERT(!_hasInstantStates || _timedStates != nullptr, "Model has instant states but no partition into timed and instant states is given.");
STORM_LOG_ASSERT(!_hasInstantStates || inputModelStateIndex < _timedStates->size(), "Unable to determine whether state " << inputModelStateIndex << " is timed.");
return !_hasInstantStates || _timedStates->get(inputModelStateIndex);
}
template <typename ValueType, typename ComponentType, LraViTransitionsType TransitionsType>
std::vector<ValueType>& LraViHelper<ValueType, ComponentType, TransitionsType>::xNew() {
return _Tsx1IsCurrent ? _Tsx1 : _Tsx2;
}
template <typename ValueType, typename ComponentType, LraViTransitionsType TransitionsType>
std::vector<ValueType> const& LraViHelper<ValueType, ComponentType, TransitionsType>::xNew() const {
return _Tsx1IsCurrent ? _Tsx1 : _Tsx2;
}
template <typename ValueType, typename ComponentType, LraViTransitionsType TransitionsType>
std::vector<ValueType>& LraViHelper<ValueType, ComponentType, TransitionsType>::xOld() {
return _Tsx1IsCurrent ? _Tsx2 : _Tsx1;
}
template <typename ValueType, typename ComponentType, LraViTransitionsType TransitionsType>
std::vector<ValueType> const& LraViHelper<ValueType, ComponentType, TransitionsType>::xOld() const {
return _Tsx1IsCurrent ? _Tsx2 : _Tsx1;
}
template <typename ValueType, typename ComponentType, LraViTransitionsType TransitionsType>
bool LraViHelper<ValueType, ComponentType, TransitionsType>::nondetTs() const {
return TransitionsType == LraViTransitionsType::NondetTsNoIs;
return TransitionsType == LraViTransitionsType::NondetTsNoIs || gameNondetTs();
}
template <typename ValueType, typename ComponentType, LraViTransitionsType TransitionsType>
bool LraViHelper<ValueType, ComponentType, TransitionsType>::nondetIs() const {
return TransitionsType == LraViTransitionsType::DetTsNondetIs;
}
template <typename ValueType, typename ComponentType, LraViTransitionsType TransitionsType>
bool LraViHelper<ValueType, ComponentType, TransitionsType>::gameNondetTs() const {
return TransitionsType == LraViTransitionsType::GameNondetTsNoIs;
}
template class LraViHelper<double, storm::storage::MaximalEndComponent, LraViTransitionsType::NondetTsNoIs>;
template class LraViHelper<storm::RationalNumber, storm::storage::MaximalEndComponent, LraViTransitionsType::NondetTsNoIs>;
template class LraViHelper<double, storm::storage::MaximalEndComponent, LraViTransitionsType::GameNondetTsNoIs>;
template class LraViHelper<storm::RationalNumber, storm::storage::MaximalEndComponent, LraViTransitionsType::GameNondetTsNoIs>;
template class LraViHelper<double, storm::storage::MaximalEndComponent, LraViTransitionsType::DetTsNondetIs>;
template class LraViHelper<storm::RationalNumber, storm::storage::MaximalEndComponent, LraViTransitionsType::DetTsNondetIs>;
template class LraViHelper<double, storm::storage::StronglyConnectedComponent, LraViTransitionsType::DetTsNoIs>;
template class LraViHelper<storm::RationalNumber, storm::storage::StronglyConnectedComponent, LraViTransitionsType::DetTsNoIs>;
}
}
}
}
}

9
src/storm/modelchecker/helper/infinitehorizon/internal/LraViHelper.h

@ -25,9 +25,10 @@ namespace storm {
DetTsNoIs, /// deterministic choice at timed states, no instant states (as in DTMCs and CTMCs)
DetTsNondetIs, /// deterministic choice at timed states, nondeterministic choice at instant states (as in Markov Automata)
DetTsDetIs, /// deterministic choice at timed states, deterministic choice at instant states (as in Markov Automata without any nondeterminisim)
NondetTsNoIs /// nondeterministic choice at timed states, no instant states (as in MDPs)
NondetTsNoIs, /// nondeterministic choice at timed states, no instant states (as in MDPs)
GameNondetTsNoIs // nondeterministic choices of different players at timed states, no instant states (as in SMGs)
};
/*!
* Helper class that performs iterations of the value iteration method.
* The purpose of the template parameters ComponentType and TransitionsType are used to make this work for various model types.
@ -127,7 +128,9 @@ namespace storm {
/// @return true iff there potentially is a nondeterministic choice at instant states. Returns false if there are no instant states.
bool nondetIs() const;
/// @return true iff there potentially are nondeterministic choices for different players at timed states
bool gameNondetTs() const;
void setComponent(ComponentType component);
// We need to make sure that states/choices will be processed in ascending order

59
src/storm/modelchecker/rpatl/SparseSmgRpatlModelChecker.cpp

@ -2,6 +2,8 @@
#include <vector>
#include <memory>
#include <algorithm>
#include <boost/variant/get.hpp>
#include "storm/utility/macros.h"
#include "storm/utility/FilteredRewardModel.h"
@ -12,6 +14,10 @@
#include "storm/modelchecker/helper/utility/SetInformationFromCheckTask.h"
#include "storm/logic/FragmentSpecification.h"
#include "storm/logic/Coalition.h"
#include "storm/storage/BitVector.h"
#include "storm/environment/solver/MultiplierEnvironment.h"
#include "storm/models/sparse/StandardRewardModel.h"
@ -27,6 +33,8 @@ namespace storm {
// Intentionally left empty.
}
template<typename SparseSmgModelType>
bool SparseSmgRpatlModelChecker<SparseSmgModelType>::canHandleStatic(CheckTask<storm::logic::Formula, ValueType> const& checkTask, bool* requiresSingleInitialState) {
storm::logic::Formula const& formula = checkTask.getFormula();
@ -44,14 +52,46 @@ namespace storm {
}
}
template<typename SparseSmgModelType>
std::unique_ptr<CheckResult> SparseSmgRpatlModelChecker<SparseSmgModelType>::checkGameFormula(Environment const& env, CheckTask<storm::logic::GameFormula, ValueType> const& checkTask) {
storm::logic::GameFormula const& gameFormula = checkTask.getFormula();
storm::logic::Formula const& subFormula = gameFormula.getSubformula();
if (subFormula.isOperatorFormula()) {
return this->checkStateFormula(env, checkTask.substituteFormula(subFormula.asStateFormula()).setPlayerCoalition(gameFormula.getCoalition()));
if (subFormula.isRewardOperatorFormula()) {
return this->checkRewardOperatorFormula(solverEnv, checkTask.substituteFormula(subFormula.asRewardOperatorFormula()));
} else if (subFormula.isLongRunAverageOperatorFormula()) {
return this->checkLongRunAverageOperatorFormula(solverEnv, checkTask.substituteFormula(subFormula.asLongRunAverageOperatorFormula()));
}
STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Cannot check this property (yet).");
}
template<typename ModelType>
std::unique_ptr<CheckResult> SparseSmgRpatlModelChecker<ModelType>::checkRewardOperatorFormula(Environment const& env, CheckTask<storm::logic::RewardOperatorFormula, ValueType> const& checkTask) {
storm::logic::RewardOperatorFormula const& formula = checkTask.getFormula();
std::unique_ptr<CheckResult> result = this->computeRewards(env, formula.getMeasureType(), checkTask.substituteFormula(formula.getSubformula()));
return result;
}
template<typename ModelType>
std::unique_ptr<CheckResult> SparseSmgRpatlModelChecker<ModelType>::checkLongRunAverageOperatorFormula(Environment const& env, CheckTask<storm::logic::LongRunAverageOperatorFormula, ValueType> const& checkTask) {
storm::logic::LongRunAverageOperatorFormula const& formula = checkTask.getFormula();
std::unique_ptr<CheckResult> result = this->computeLongRunAverageProbabilities(env, checkTask.substituteFormula(formula.getSubformula().asStateFormula()));
return result;
}
template<typename ModelType>
std::unique_ptr<CheckResult> SparseSmgRpatlModelChecker<ModelType>::computeRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::Formula, ValueType> const& checkTask) {
storm::logic::Formula const& rewardFormula = checkTask.getFormula();
if (rewardFormula.isLongRunAverageRewardFormula()) {
return this->computeLongRunAverageRewards(env, rewardMeasureType, checkTask.substituteFormula(rewardFormula.asLongRunAverageRewardFormula()));
}
STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Only game formulas with Operatorformulas as subformula are supported.");
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "The given formula '" << rewardFormula << "' cannot (yet) be handled.");
}
template<typename SparseSmgModelType>
@ -62,10 +102,15 @@ namespace storm {
template<typename SparseSmgModelType>
std::unique_ptr<CheckResult> SparseSmgRpatlModelChecker<SparseSmgModelType>::computeLongRunAverageRewards(Environment const& env, storm::logic::RewardMeasureType rewardMeasureType, CheckTask<storm::logic::LongRunAverageRewardFormula, ValueType> const& checkTask) {
auto rewardModel = storm::utility::createFilteredRewardModel(this->getModel(), checkTask);
STORM_LOG_THROW(checkTask.isPlayerCoalitionSet(), storm::exceptions::InvalidPropertyException, "No player coalition was set.");
auto coalitionStates = this->getModel().computeStatesOfCoalition(checkTask.getPlayerCoalition());
std::cout << "Found " << coalitionStates.getNumberOfSetBits() << " states in coalition." << std::endl;
STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Not implemented.");
storm::modelchecker::helper::SparseNondeterministicGameInfiniteHorizonHelper<ValueType> helper(this->getModel().getTransitionMatrix(), this->getModel().getPlayerActionIndices());
storm::modelchecker::helper::setInformationFromCheckTaskNondeterministic(helper, checkTask, this->getModel());
auto values = helper.computeLongRunAverageRewards(env, rewardModel.get());
std::unique_ptr<CheckResult> result(new ExplicitQuantitativeCheckResult<ValueType>(std::move(values)));
if (checkTask.isProduceSchedulersSet()) {
result->asExplicitQuantitativeCheckResult<ValueType>().setScheduler(std::make_unique<storm::storage::Scheduler<ValueType>>(helper.extractScheduler()));
}
return result;
}
template class SparseSmgRpatlModelChecker<storm::models::sparse::Smg<double>>;

5
src/storm/models/sparse/Smg.cpp

@ -37,7 +37,6 @@ namespace storm {
storm::storage::PlayerIndex Smg<ValueType, RewardModelType>::getPlayerOfState(uint64_t stateIndex) const {
STORM_LOG_ASSERT(stateIndex < this->getNumberOfStates(), "Invalid state index: " << stateIndex << ".");
return statePlayerIndications[stateIndex];
}
template <typename ValueType, typename RewardModelType>
storm::storage::PlayerIndex Smg<ValueType, RewardModelType>::getPlayerIndex(std::string const& playerName) const {
@ -62,7 +61,7 @@ namespace storm {
for (auto const& pi : coalitionAsIndexSet) {
coalitionAsBitVector.set(pi);
}
// Now create the actual result
storm::storage::BitVector result(this->getNumberOfStates(), false);
for (uint64_t state = 0; state < this->getNumberOfStates(); ++state) {
@ -71,7 +70,7 @@ namespace storm {
result.set(state, true);
}
}
return result;
}

2
src/storm/models/sparse/Smg.h

@ -34,7 +34,7 @@ namespace storm {
storm::storage::PlayerIndex getPlayerOfState(uint64_t stateIndex) const;
storm::storage::PlayerIndex getPlayerIndex(std::string const& playerName) const;
storm::storage::BitVector computeStatesOfCoalition(storm::logic::PlayerCoalition const& coalition) const;
private:
// Assigns the controlling player to each state.
// If a state has storm::storage::INVALID_PLAYER_INDEX, it shall be the case that the choice at that state is unique

108
src/storm/solver/GmmxxMultiplier.cpp

@ -1,5 +1,7 @@
#include "storm/solver/GmmxxMultiplier.h"
#include <boost/optional.hpp>
#include "storm/adapters/RationalNumberAdapter.h"
#include "storm/adapters/RationalFunctionAdapter.h"
#include "storm/adapters/IntelTbbAdapter.h"
@ -14,25 +16,26 @@
namespace storm {
namespace solver {
template<typename ValueType>
GmmxxMultiplier<ValueType>::GmmxxMultiplier(storm::storage::SparseMatrix<ValueType> const& matrix) : Multiplier<ValueType>(matrix) {
// Intentionally left empty.
//STORM_LOG_DEBUG("\n" << matrix);
}
template<typename ValueType>
void GmmxxMultiplier<ValueType>::initialize() const {
if (gmmMatrix.nrows() == 0) {
gmmMatrix = std::move(*storm::adapters::GmmxxAdapter<ValueType>().toGmmxxSparseMatrix(this->matrix));
}
}
template<typename ValueType>
void GmmxxMultiplier<ValueType>::clearCache() const {
gmmMatrix = gmm::csr_matrix<ValueType>();
Multiplier<ValueType>::clearCache();
}
template<typename ValueType>
bool GmmxxMultiplier<ValueType>::parallelize(Environment const& env) const {
#ifdef STORM_HAVE_INTELTBB
@ -41,7 +44,7 @@ namespace storm {
return false;
#endif
}
template<typename ValueType>
void GmmxxMultiplier<ValueType>::multiply(Environment const& env, std::vector<ValueType> const& x, std::vector<ValueType> const* b, std::vector<ValueType>& result) const {
initialize();
@ -63,7 +66,7 @@ namespace storm {
std::swap(result, *this->cachedVector);
}
}
template<typename ValueType>
void GmmxxMultiplier<ValueType>::multiplyGaussSeidel(Environment const& env, std::vector<ValueType>& x, std::vector<ValueType> const* b, bool backwards) const {
initialize();
@ -82,7 +85,7 @@ namespace storm {
}
}
}
template<typename ValueType>
void GmmxxMultiplier<ValueType>::multiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector<uint64_t> const& rowGroupIndices, std::vector<ValueType> const& x, std::vector<ValueType> const* b, std::vector<ValueType>& result, std::vector<uint_fast64_t>* choices) const {
initialize();
@ -104,13 +107,13 @@ namespace storm {
std::swap(result, *this->cachedVector);
}
}
template<typename ValueType>
void GmmxxMultiplier<ValueType>::multiplyAndReduceGaussSeidel(Environment const& env, OptimizationDirection const& dir, std::vector<uint64_t> const& rowGroupIndices, std::vector<ValueType>& x, std::vector<ValueType> const* b, std::vector<uint_fast64_t>* choices, bool backwards) const {
initialize();
multAddReduceHelper(dir, rowGroupIndices, x, b, x, choices, backwards);
}
template<typename ValueType>
void GmmxxMultiplier<ValueType>::multiplyRow(uint64_t const& rowIndex, std::vector<ValueType> const& x, ValueType& value) const {
initialize();
@ -146,14 +149,14 @@ namespace storm {
}
}
}
template<typename ValueType>
template<typename Compare, bool backwards>
void GmmxxMultiplier<ValueType>::multAddReduceHelper(std::vector<uint64_t> const& rowGroupIndices, std::vector<ValueType> const& x, std::vector<ValueType> const* b, std::vector<ValueType>& result, std::vector<uint64_t>* choices) const {
Compare compare;
typedef std::vector<ValueType> VectorType;
typedef gmm::csr_matrix<ValueType> MatrixType;
typename gmm::linalg_traits<VectorType>::const_iterator add_it, add_ite;
if (b) {
add_it = backwards ? gmm::vect_end(*b) - 1 : gmm::vect_begin(*b);
@ -166,23 +169,30 @@ namespace storm {
choice_it = backwards ? choices->end() - 1 : choices->begin();
}
boost::optional<storm::storage::BitVector> optimizationDirectionOverride;
if(this->getOptimizationDirectionOverride().is_initialized()) {
optimizationDirectionOverride = this->getOptimizationDirectionOverride();
}
// Variables for correctly tracking choices (only update if new choice is strictly better).
ValueType oldSelectedChoiceValue;
uint64_t selectedChoice;
uint64_t currentRow = backwards ? gmmMatrix.nrows() - 1 : 0;
uint64_t currentRowGroup = backwards ? rowGroupIndices.size() - 1 : 0;
auto row_group_it = backwards ? rowGroupIndices.end() - 2 : rowGroupIndices.begin();
auto row_group_ite = backwards ? rowGroupIndices.begin() - 1 : rowGroupIndices.end() - 1;
//if(choices) STORM_LOG_DEBUG(" ");
while (row_group_it != row_group_ite) {
ValueType currentValue = storm::utility::zero<ValueType>();
// Only multiply and reduce if the row group is not empty.
if (*row_group_it != *(row_group_it + 1)) {
// Process the (backwards ? last : first) row of the current row group
if (b) {
currentValue = *add_it;
}
currentValue += vect_sp(gmm::linalg_traits<MatrixType>::row(itr), x);
if (choices) {
@ -191,7 +201,7 @@ namespace storm {
oldSelectedChoiceValue = currentValue;
}
}
// move row-based iterators to the next row
if (backwards) {
--itr;
@ -202,22 +212,28 @@ namespace storm {
++currentRow;
++add_it;
}
// Process the (rowGroupSize-1) remaining rows within the current row Group
uint64_t rowGroupSize = *(row_group_it + 1) - *row_group_it;
uint choiceforprintout = 0;
//std::cout << currentRowGroup << ": " << currentValue << ", ";
//STORM_LOG_DEBUG(std::setprecision(3) << vect_sp(gmm::linalg_traits<MatrixType>::row(itr), x) << " + " << *add_it << "; ");
//STORM_LOG_DEBUG(std::setprecision(3) << vect_sp(gmm::linalg_traits<MatrixType>::row(itr), x) << " + " << *add_it << "; ");
for (uint64_t i = 1; i < rowGroupSize; ++i) {
ValueType newValue = b ? *add_it : storm::utility::zero<ValueType>();
newValue += vect_sp(gmm::linalg_traits<MatrixType>::row(itr), x);
if (choices && currentRow == *choice_it + *row_group_it) {
oldSelectedChoiceValue = newValue;
}
if (compare(newValue, currentValue)) {
//std::cout << newValue << ", ";
//STORM_LOG_DEBUG(std::setprecision(3) << vect_sp(gmm::linalg_traits<MatrixType>::row(itr), x) << " + " << *add_it << "; ");
if(this->isOverridden(currentRowGroup) ? compare(currentValue, newValue) : compare(newValue, currentValue)) {
currentValue = newValue;
if (choices) {
selectedChoice = currentRow - *row_group_it;
}
choiceforprintout = currentRow - *row_group_it;
}
// move row-based iterators to the next row
if (backwards) {
@ -230,33 +246,39 @@ namespace storm {
++add_it;
}
}
//STORM_LOG_DEBUG("\t= " << currentValue << "\tchoice: " << choiceforprintout);
//std::cout << std::fixed << std::setprecision(2) << " | v(" << currentRowGroup << ")=" << currentValue << " c: " << choiceforprintout << " |\n" ;
// Finally write value to target vector.
*target_it = currentValue;
if (choices && compare(currentValue, oldSelectedChoiceValue)) {
*choice_it = selectedChoice;
if(choices) {
if(this->isOverridden(currentRowGroup) ? compare(oldSelectedChoiceValue, currentValue) : compare(currentValue, oldSelectedChoiceValue) ) {
*choice_it = selectedChoice;
}
}
}
// move rowGroup-based iterators to the next row group
if (backwards) {
--row_group_it;
--choice_it;
--target_it;
--currentRowGroup;
} else {
++row_group_it;
++choice_it;
++target_it;
++currentRowGroup;
}
}
//std::cout << std::endl;
}
template<>
template<typename Compare, bool backwards>
void GmmxxMultiplier<storm::RationalFunction>::multAddReduceHelper(std::vector<uint64_t> const& rowGroupIndices, std::vector<storm::RationalFunction> const& x, std::vector<storm::RationalFunction> const* b, std::vector<storm::RationalFunction>& result, std::vector<uint64_t>* choices) const {
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Operation not supported for this data type.");
}
template<typename ValueType>
void GmmxxMultiplier<ValueType>::multAddParallel(std::vector<ValueType> const& x, std::vector<ValueType> const* b, std::vector<ValueType>& result) const {
#ifdef STORM_HAVE_INTELTBB
@ -274,7 +296,7 @@ namespace storm {
multAdd(x, b, result);
#endif
}
#ifdef STORM_HAVE_INTELTBB
template<typename ValueType, typename Compare>
class TbbMultAddReduceFunctor {
@ -282,14 +304,14 @@ namespace storm {
TbbMultAddReduceFunctor(std::vector<uint64_t> const& rowGroupIndices, gmm::csr_matrix<ValueType> const& matrix, std::vector<ValueType> const& x, std::vector<ValueType> const* b, std::vector<ValueType>& result, std::vector<uint64_t>* choices) : rowGroupIndices(rowGroupIndices), matrix(matrix), x(x), b(b), result(result), choices(choices) {
// Intentionally left empty.
}
void operator()(tbb::blocked_range<unsigned long> const& range) const {
typedef std::vector<ValueType> VectorType;
typedef gmm::csr_matrix<ValueType> MatrixType;
auto groupIt = rowGroupIndices.begin() + range.begin();
auto groupIte = rowGroupIndices.begin() + range.end();
auto itr = mat_row_const_begin(matrix) + *groupIt;
typename std::vector<ValueType>::const_iterator bIt;
if (b) {
@ -299,40 +321,40 @@ namespace storm {
if (choices) {
choiceIt = choices->begin() + range.begin();
}
auto resultIt = result.begin() + range.begin();
// Variables for correctly tracking choices (only update if new choice is strictly better).
ValueType oldSelectedChoiceValue;
uint64_t selectedChoice;
uint64_t currentRow = *groupIt;
for (; groupIt != groupIte; ++groupIt, ++resultIt, ++choiceIt) {
ValueType currentValue = storm::utility::zero<ValueType>();
// Only multiply and reduce if the row group is not empty.
if (*groupIt != *(groupIt + 1)) {
if (b) {
currentValue = *bIt;
++bIt;
}
currentValue += vect_sp(gmm::linalg_traits<MatrixType>::row(itr), x);
if (choices) {
selectedChoice = currentRow - *groupIt;
if (*choiceIt == selectedChoice) {
oldSelectedChoiceValue = currentValue;
}
}
++itr;
++currentRow;
for (auto itre = mat_row_const_begin(matrix) + *(groupIt + 1); itr != itre; ++itr, ++bIt, ++currentRow) {
ValueType newValue = b ? *bIt : storm::utility::zero<ValueType>();
newValue += vect_sp(gmm::linalg_traits<MatrixType>::row(itr), x);
if (compare(newValue, currentValue)) {
currentValue = newValue;
if (choices) {
@ -341,7 +363,7 @@ namespace storm {
}
}
}
// Finally write value to target vector.
*resultIt = currentValue;
if (choices && compare(currentValue, oldSelectedChoiceValue)) {
@ -349,7 +371,7 @@ namespace storm {
}
}
}
private:
Compare compare;
std::vector<uint64_t> const& rowGroupIndices;
@ -360,7 +382,7 @@ namespace storm {
std::vector<uint64_t>* choices;
};
#endif
template<typename ValueType>
void GmmxxMultiplier<ValueType>::multAddReduceParallel(storm::solver::OptimizationDirection const& dir, std::vector<uint64_t> const& rowGroupIndices, std::vector<ValueType> const& x, std::vector<ValueType> const* b, std::vector<ValueType>& result, std::vector<uint64_t>* choices) const {
#ifdef STORM_HAVE_INTELTBB
@ -374,18 +396,18 @@ namespace storm {
multAddReduceHelper(dir, rowGroupIndices, x, b, result, choices);
#endif
}
template<>
void GmmxxMultiplier<storm::RationalFunction>::multAddReduceParallel(storm::solver::OptimizationDirection const& dir, std::vector<uint64_t> const& rowGroupIndices, std::vector<storm::RationalFunction> const& x, std::vector<storm::RationalFunction> const* b, std::vector<storm::RationalFunction>& result, std::vector<uint64_t>* choices) const {
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "This operation is not supported.");
}
template class GmmxxMultiplier<double>;
#ifdef STORM_HAVE_CARL
template class GmmxxMultiplier<storm::RationalNumber>;
template class GmmxxMultiplier<storm::RationalFunction>;
#endif
}
}

40
src/storm/solver/Multiplier.cpp

@ -18,17 +18,17 @@
namespace storm {
namespace solver {
template<typename ValueType>
Multiplier<ValueType>::Multiplier(storm::storage::SparseMatrix<ValueType> const& matrix) : matrix(matrix) {
// Intentionally left empty.
}
template<typename ValueType>
void Multiplier<ValueType>::clearCache() const {
cachedVector.reset();
}
template<typename ValueType>
void Multiplier<ValueType>::multiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector<ValueType> const& x, std::vector<ValueType> const* b, std::vector<ValueType>& result, std::vector<uint_fast64_t>* choices) const {
multiplyAndReduce(env, dir, this->matrix.getRowGroupIndices(), x, b, result, choices);
@ -38,7 +38,7 @@ namespace storm {
void Multiplier<ValueType>::multiplyAndReduceGaussSeidel(Environment const& env, OptimizationDirection const& dir, std::vector<ValueType>& x, std::vector<ValueType> const* b, std::vector<uint_fast64_t>* choices, bool backwards) const {
multiplyAndReduceGaussSeidel(env, dir, this->matrix.getRowGroupIndices(), x, b, choices, backwards);
}
template<typename ValueType>
void Multiplier<ValueType>::repeatedMultiply(Environment const& env, std::vector<ValueType>& x, std::vector<ValueType> const* b, uint64_t n) const {
storm::utility::ProgressMeasurement progress("multiplications");
@ -53,7 +53,7 @@ namespace storm {
}
}
}
template<typename ValueType>
void Multiplier<ValueType>::repeatedMultiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector<ValueType>& x, std::vector<ValueType> const* b, uint64_t n) const {
storm::utility::ProgressMeasurement progress("multiplications");
@ -67,17 +67,33 @@ namespace storm {
}
}
}
template<typename ValueType>
void Multiplier<ValueType>::multiplyRow2(uint64_t const& rowIndex, std::vector<ValueType> const& x1, ValueType& val1, std::vector<ValueType> const& x2, ValueType& val2) const {
multiplyRow(rowIndex, x1, val1);
multiplyRow(rowIndex, x2, val2);
}
template<typename ValueType>
void Multiplier<ValueType>::setOptimizationDirectionOverride(storm::storage::BitVector const& optDirOverride) {
optimizationDirectionOverride = optDirOverride;
}
template<typename ValueType>
boost::optional<storm::storage::BitVector> Multiplier<ValueType>::getOptimizationDirectionOverride() const {
return optimizationDirectionOverride;
}
template<typename ValueType>
bool Multiplier<ValueType>::isOverridden(uint_fast64_t const index) const {
if(!optimizationDirectionOverride.is_initialized()) return false;
return optimizationDirectionOverride.get().get(index);
}
template<typename ValueType>
std::unique_ptr<Multiplier<ValueType>> MultiplierFactory<ValueType>::create(Environment const& env, storm::storage::SparseMatrix<ValueType> const& matrix) {
auto type = env.solver().multiplier().getType();
// Adjust the multiplier type if an eqsolver was specified but not a multiplier
if (!env.solver().isLinearEquationSolverTypeSetFromDefaultValue() && env.solver().multiplier().isTypeSetFromDefault()) {
bool changed = false;
@ -90,7 +106,7 @@ namespace storm {
}
STORM_LOG_INFO_COND(!changed, "Selecting '" + toString(type) + "' as the multiplier type to match the selected equation solver. If you want to override this, please explicitly specify a different multiplier type.");
}
switch (type) {
case MultiplierType::Gmmxx:
return std::make_unique<GmmxxMultiplier<ValueType>>(matrix);
@ -99,16 +115,16 @@ namespace storm {
}
STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentException, "Unknown MultiplierType");
}
template class Multiplier<double>;
template class MultiplierFactory<double>;
#ifdef STORM_HAVE_CARL
template class Multiplier<storm::RationalNumber>;
template class MultiplierFactory<storm::RationalNumber>;
template class Multiplier<storm::RationalFunction>;
template class MultiplierFactory<storm::RationalFunction>;
#endif
}
}

56
src/storm/solver/Multiplier.h

@ -2,34 +2,37 @@
#include <vector>
#include <memory>
#include <boost/optional.hpp>
#include "storm/storage/BitVector.h"
#include "storm/solver/OptimizationDirection.h"
#include "storm/solver/MultiplicationStyle.h"
namespace storm {
class Environment;
namespace storage {
template<typename ValueType>
class SparseMatrix;
}
namespace solver {
template<typename ValueType>
class Multiplier {
public:
Multiplier(storm::storage::SparseMatrix<ValueType> const& matrix);
virtual ~Multiplier() = default;
/*
* Clears the currently cached data of this multiplier in order to free some memory.
*/
virtual void clearCache() const;
/*!
* Performs a matrix-vector multiplication x' = A*x + b.
*
@ -41,7 +44,7 @@ namespace storm {
* to the number of rows of A. Can be the same as the x vector.
*/
virtual void multiply(Environment const& env, std::vector<ValueType> const& x, std::vector<ValueType> const* b, std::vector<ValueType>& result) const = 0;
/*!
* Performs a matrix-vector multiplication in gauss-seidel style.
*
@ -52,7 +55,7 @@ namespace storm {
* @param backwards if true, the iterations will be performed beginning from the last row and ending at the first row.
*/
virtual void multiplyGaussSeidel(Environment const& env, std::vector<ValueType>& x, std::vector<ValueType> const* b, bool backwards = true) const = 0;
/*!
* Performs a matrix-vector multiplication x' = A*x + b and then minimizes/maximizes over the row groups
* so that the resulting vector has the size of number of row groups of A.
@ -69,7 +72,7 @@ namespace storm {
*/
void multiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector<ValueType> const& x, std::vector<ValueType> const* b, std::vector<ValueType>& result, std::vector<uint_fast64_t>* choices = nullptr) const;
virtual void multiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector<uint64_t> const& rowGroupIndices, std::vector<ValueType> const& x, std::vector<ValueType> const* b, std::vector<ValueType>& result, std::vector<uint_fast64_t>* choices = nullptr) const = 0;
/*!
* Performs a matrix-vector multiplication in gauss-seidel style and then minimizes/maximizes over the row groups
* so that the resulting vector has the size of number of row groups of A.
@ -87,7 +90,7 @@ namespace storm {
*/
void multiplyAndReduceGaussSeidel(Environment const& env, OptimizationDirection const& dir, std::vector<ValueType>& x, std::vector<ValueType> const* b, std::vector<uint_fast64_t>* choices = nullptr, bool backwards = true) const;
virtual void multiplyAndReduceGaussSeidel(Environment const& env, OptimizationDirection const& dir, std::vector<uint64_t> const& rowGroupIndices, std::vector<ValueType>& x, std::vector<ValueType> const* b, std::vector<uint_fast64_t>* choices = nullptr, bool backwards = true) const = 0;
/*!
* Performs repeated matrix-vector multiplication, using x[0] = x and x[i + 1] = A*x[i] + b. After
* performing the necessary multiplications, the result is written to the input vector x. Note that the
@ -100,7 +103,7 @@ namespace storm {
* @param n The number of times to perform the multiplication.
*/
void repeatedMultiply(Environment const& env, std::vector<ValueType>& x, std::vector<ValueType> const* b, uint64_t n) const;
/*!
* Performs repeated matrix-vector multiplication x' = A*x + b and then minimizes/maximizes over the row groups
* so that the resulting vector has the size of number of row groups of A.
@ -115,7 +118,7 @@ namespace storm {
* @param n The number of times to perform the multiplication.
*/
void repeatedMultiplyAndReduce(Environment const& env, OptimizationDirection const& dir, std::vector<ValueType>& x, std::vector<ValueType> const* b, uint64_t n) const;
/*!
* Multiplies the row with the given index with x and adds the result to the provided value
* @param rowIndex The index of the considered row
@ -123,7 +126,7 @@ namespace storm {
* @param value The multiplication result is added to this value. It shall not reffer to a value in x or in the Matrix.
*/
virtual void multiplyRow(uint64_t const& rowIndex, std::vector<ValueType> const& x, ValueType& value) const = 0;
/*!
* Multiplies the row with the given index with x1 and x2 and adds the given offset o1 and o2, respectively
* @param rowIndex The index of the considered row
@ -133,12 +136,29 @@ namespace storm {
* @param val2 The second multiplication result is added to this value. It shall not reffer to a value in x or in the Matrix.
*/
virtual void multiplyRow2(uint64_t const& rowIndex, std::vector<ValueType> const& x1, ValueType& val1, std::vector<ValueType> const& x2, ValueType& val2) const;
/*
* TODO
*/
void setOptimizationDirectionOverride(storm::storage::BitVector const& optimizationDirectionOverride);
/*
* TODO
*/
boost::optional<storm::storage::BitVector> getOptimizationDirectionOverride() const;
/*
* TODO
*/
bool isOverridden(uint_fast64_t const index) const;
protected:
mutable std::unique_ptr<std::vector<ValueType>> cachedVector;
storm::storage::SparseMatrix<ValueType> const& matrix;
boost::optional<storm::storage::BitVector> optimizationDirectionOverride = boost::none;
};
template<typename ValueType>
class MultiplierFactory {
public:
@ -147,6 +167,6 @@ namespace storm {
std::unique_ptr<Multiplier<ValueType>> create(Environment const& env, storm::storage::SparseMatrix<ValueType> const& matrix);
};
}
}

56
src/storm/storage/Decomposition.cpp

@ -8,84 +8,84 @@
namespace storm {
namespace storage {
template <typename BlockType>
Decomposition<BlockType>::Decomposition() : blocks() {
// Intentionally left empty.
}
template <typename BlockType>
Decomposition<BlockType>::Decomposition(Decomposition const& other) : blocks(other.blocks) {
// Intentionally left empty.
}
template <typename BlockType>
Decomposition<BlockType>& Decomposition<BlockType>::operator=(Decomposition const& other) {
this->blocks = other.blocks;
return *this;
}
template <typename BlockType>
Decomposition<BlockType>::Decomposition(Decomposition&& other) : blocks(std::move(other.blocks)) {
// Intentionally left empty.
}
template <typename BlockType>
Decomposition<BlockType>& Decomposition<BlockType>::operator=(Decomposition&& other) {
this->blocks = std::move(other.blocks);
return *this;
}
template <typename BlockType>
std::size_t Decomposition<BlockType>::size() const {
return blocks.size();
}
template <typename BlockType>
bool Decomposition<BlockType>::empty() const {
return blocks.empty();
}
template <typename BlockType>
typename Decomposition<BlockType>::iterator Decomposition<BlockType>::begin() {
return blocks.begin();
}
template <typename BlockType>
typename Decomposition<BlockType>::iterator Decomposition<BlockType>::end() {
return blocks.end();
}
template <typename BlockType>
typename Decomposition<BlockType>::const_iterator Decomposition<BlockType>::begin() const {
return blocks.begin();
}
template <typename BlockType>
typename Decomposition<BlockType>::const_iterator Decomposition<BlockType>::end() const {
return blocks.end();
}
template <typename BlockType>
BlockType const& Decomposition<BlockType>::getBlock(uint_fast64_t index) const {
return blocks.at(index);
}
template <typename BlockType>
BlockType& Decomposition<BlockType>::getBlock(uint_fast64_t index) {
return blocks.at(index);
}
template <typename BlockType>
BlockType const& Decomposition<BlockType>::operator[](uint_fast64_t index) const {
return blocks[index];
}
template <typename BlockType>
BlockType& Decomposition<BlockType>::operator[](uint_fast64_t index) {
return blocks[index];
}
template <typename BlockType>
template <typename ValueType>
storm::storage::SparseMatrix<ValueType> Decomposition<BlockType>::extractPartitionDependencyGraph(storm::storage::SparseMatrix<ValueType> const& matrix) const {
@ -97,49 +97,49 @@ namespace storm {
stateToBlockMap[state] = i;
}
}
// The resulting sparse matrix will have as many rows/columns as there are blocks in the partition.
storm::storage::SparseMatrixBuilder<ValueType> dependencyGraphBuilder(this->size(), this->size());
for (uint_fast64_t currentBlockIndex = 0; currentBlockIndex < this->size(); ++currentBlockIndex) {
// Get the next block.
block_type const& block = this->getBlock(currentBlockIndex);
// Now, we determine the blocks which are reachable (in one step) from the current block.
storm::storage::FlatSet<uint_fast64_t> allTargetBlocks;
for (auto state : block) {
for (auto const& transitionEntry : matrix.getRowGroup(state)) {
uint_fast64_t targetBlock = stateToBlockMap[transitionEntry.getColumn()];
// We only need to consider transitions that are actually leaving the SCC.
if (targetBlock != currentBlockIndex) {
allTargetBlocks.insert(targetBlock);
}
}
}
// Now we can just enumerate all the target blocks and insert the corresponding transitions.
for (auto const& targetBlock : allTargetBlocks) {
dependencyGraphBuilder.addNextValue(currentBlockIndex, targetBlock, storm::utility::one<ValueType>());
}
}
return dependencyGraphBuilder.build();
}
template <typename BlockType>
std::ostream& operator<<(std::ostream& out, Decomposition<BlockType> const& decomposition) {
out << "[";
out << "[ ";
if (decomposition.size() > 0) {
for (uint_fast64_t blockIndex = 0; blockIndex < decomposition.size() - 1; ++blockIndex) {
out << decomposition.blocks[blockIndex] << ", ";
out << decomposition.blocks[blockIndex] << ", " << std::endl;
}
out << decomposition.blocks.back();
}
out << "]";
out << " ]";
return out;
}
template storm::storage::SparseMatrix<double> Decomposition<StateBlock>::extractPartitionDependencyGraph(storm::storage::SparseMatrix<double> const& matrix) const;
template storm::storage::SparseMatrix<float> Decomposition<StateBlock>::extractPartitionDependencyGraph(storm::storage::SparseMatrix<float> const& matrix) const;
template class Decomposition<StateBlock>;
@ -149,7 +149,7 @@ namespace storm {
template storm::storage::SparseMatrix<float> Decomposition<StronglyConnectedComponent>::extractPartitionDependencyGraph(storm::storage::SparseMatrix<float> const& matrix) const;
template class Decomposition<StronglyConnectedComponent>;
template std::ostream& operator<<(std::ostream& out, Decomposition<StronglyConnectedComponent> const& decomposition);
template class Decomposition<MaximalEndComponent>;
template std::ostream& operator<<(std::ostream& out, Decomposition<MaximalEndComponent> const& decomposition);
} // namespace storage

281
src/storm/storage/GameMaximalEndComponentDecomposition.cpp

@ -0,0 +1,281 @@
#include <list>
#include <queue>
#include <numeric>
#include "storm/models/sparse/StandardRewardModel.h"
#include "storm/storage/GameMaximalEndComponentDecomposition.h"
#include "storm/storage/StronglyConnectedComponentDecomposition.h"
namespace storm {
namespace storage {
template<typename ValueType>
GameMaximalEndComponentDecomposition<ValueType>::GameMaximalEndComponentDecomposition() : Decomposition() {
// Intentionally left empty.
}
template<typename ValueType>
template<typename RewardModelType>
GameMaximalEndComponentDecomposition<ValueType>::GameMaximalEndComponentDecomposition(storm::models::sparse::NondeterministicModel<ValueType, RewardModelType> const& model) {
singleMEC(model.getTransitionMatrix(), model.getBackwardTransitions());
//performGameMaximalEndComponentDecomposition(model.getTransitionMatrix(), model.getBackwardTransitions());
}
template<typename ValueType>
GameMaximalEndComponentDecomposition<ValueType>::GameMaximalEndComponentDecomposition(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions) {
singleMEC(transitionMatrix, backwardTransitions);
//performGameMaximalEndComponentDecomposition(transitionMatrix, backwardTransitions);
}
template<typename ValueType>
GameMaximalEndComponentDecomposition<ValueType>::GameMaximalEndComponentDecomposition(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& states) {
}
template<typename ValueType>
GameMaximalEndComponentDecomposition<ValueType>::GameMaximalEndComponentDecomposition(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& states, storm::storage::BitVector const& choices) {
}
template<typename ValueType>
GameMaximalEndComponentDecomposition<ValueType>::GameMaximalEndComponentDecomposition(storm::models::sparse::NondeterministicModel<ValueType> const& model, storm::storage::BitVector const& states) {
}
template<typename ValueType>
GameMaximalEndComponentDecomposition<ValueType>::GameMaximalEndComponentDecomposition(GameMaximalEndComponentDecomposition const& other) : Decomposition(other) {
// Intentionally left empty.
}
template<typename ValueType>
GameMaximalEndComponentDecomposition<ValueType>& GameMaximalEndComponentDecomposition<ValueType>::operator=(GameMaximalEndComponentDecomposition const& other) {
Decomposition::operator=(other);
return *this;
}
template<typename ValueType>
GameMaximalEndComponentDecomposition<ValueType>::GameMaximalEndComponentDecomposition(GameMaximalEndComponentDecomposition&& other) : Decomposition(std::move(other)) {
// Intentionally left empty.
}
template<typename ValueType>
GameMaximalEndComponentDecomposition<ValueType>& GameMaximalEndComponentDecomposition<ValueType>::operator=(GameMaximalEndComponentDecomposition&& other) {
Decomposition::operator=(std::move(other));
return *this;
}
template <typename ValueType>
void GameMaximalEndComponentDecomposition<ValueType>::performGameMaximalEndComponentDecomposition(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> backwardTransitions, storm::storage::BitVector const* states, storm::storage::BitVector const* choices) {
// Get some data for convenient access.
uint_fast64_t numberOfStates = transitionMatrix.getRowGroupCount();
std::vector<uint_fast64_t> const& nondeterministicChoiceIndices = transitionMatrix.getRowGroupIndices();
// Initialize the maximal end component list to be the full state space.
std::list<StateBlock> endComponentStateSets;
if (states) {
endComponentStateSets.emplace_back(states->begin(), states->end(), true);
} else {
std::vector<storm::storage::sparse::state_type> allStates;
allStates.resize(transitionMatrix.getRowGroupCount());
std::iota(allStates.begin(), allStates.end(), 0);
endComponentStateSets.emplace_back(allStates.begin(), allStates.end(), true);
}
storm::storage::BitVector statesToCheck(numberOfStates);
storm::storage::BitVector includedChoices;
if (choices) {
includedChoices = *choices;
} else if (states) {
includedChoices = storm::storage::BitVector(transitionMatrix.getRowCount());
for (auto state : *states) {
for (uint_fast64_t choice = nondeterministicChoiceIndices[state]; choice < nondeterministicChoiceIndices[state + 1]; ++choice) {
includedChoices.set(choice, true);
}
}
} else {
includedChoices = storm::storage::BitVector(transitionMatrix.getRowCount(), true);
}
storm::storage::BitVector currMecAsBitVector(transitionMatrix.getRowGroupCount());
for (std::list<StateBlock>::const_iterator mecIterator = endComponentStateSets.begin(); mecIterator != endComponentStateSets.end();) {
StateBlock const& mec = *mecIterator;
currMecAsBitVector.clear();
currMecAsBitVector.set(mec.begin(), mec.end(), true);
// Keep track of whether the MEC changed during this iteration.
bool mecChanged = false;
// Get an SCC decomposition of the current MEC candidate.
StronglyConnectedComponentDecomposition<ValueType> sccs(transitionMatrix, StronglyConnectedComponentDecompositionOptions().subsystem(&currMecAsBitVector).choices(&includedChoices).dropNaiveSccs());
for(auto const& sc: sccs) {
STORM_LOG_DEBUG("SCC size: " << sc.size());
}
// We need to do another iteration in case we have either more than once SCC or the SCC is smaller than
// the MEC canditate itself.
mecChanged |= sccs.size() != 1 || (sccs.size() > 0 && sccs[0].size() < mec.size());
// Check for each of the SCCs whether all actions for each state do not leave the SCC. // TODO there is certainly a better way to do that...
for (auto& scc : sccs) {
statesToCheck.set(scc.begin(), scc.end());
while (!statesToCheck.empty()) {
storm::storage::BitVector statesToRemove(numberOfStates);
for (auto state : statesToCheck) {
bool keepStateInMEC = true;
for (uint_fast64_t choice = nondeterministicChoiceIndices[state]; choice < nondeterministicChoiceIndices[state + 1]; ++choice) {
// If the choice is not part of our subsystem, skip it.
if (choices && !choices->get(choice)) {
continue;
}
// If the choice is not included any more, skip it.
//if (!includedChoices.get(choice)) {
// continue;
//}
bool choiceContainedInMEC = true;
for (auto const& entry : transitionMatrix.getRow(choice)) {
if (storm::utility::isZero(entry.getValue())) {
continue;
}
if (!scc.containsState(entry.getColumn())) {
//includedChoices.set(choice, false);
choiceContainedInMEC = false;
break;
}
}
//TODO If there is at least one choice whose successor states are fully contained in the MEC, we can leave the state in the MEC.
if (!choiceContainedInMEC) {
keepStateInMEC = false;
break;
}
}
if (!keepStateInMEC) {
statesToRemove.set(state, true);
}
}
// Now erase the states that have no option to stay inside the MEC with all successors.
mecChanged |= !statesToRemove.empty();
for (uint_fast64_t state : statesToRemove) {
scc.erase(state);
}
// Now check which states should be reconsidered, because successors of them were removed.
statesToCheck.clear();
for (auto state : statesToRemove) {
for (auto const& entry : backwardTransitions.getRow(state)) {
if (scc.containsState(entry.getColumn())) {
statesToCheck.set(entry.getColumn());
}
}
}
}
}
// If the MEC changed, we delete it from the list of MECs and append the possible new MEC candidates to
// the list instead.
if (mecChanged) {
for (StronglyConnectedComponent& scc : sccs) {
if (!scc.empty()) {
endComponentStateSets.push_back(std::move(scc));
}
}
std::list<StateBlock>::const_iterator eraseIterator(mecIterator);
++mecIterator;
endComponentStateSets.erase(eraseIterator);
} else {
// Otherwise, we proceed with the next MEC candidate.
++mecIterator;
}
} // End of loop over all MEC candidates.
// Now that we computed the underlying state sets of the MECs, we need to properly identify the choices
// contained in the MEC and store them as actual MECs.
this->blocks.reserve(endComponentStateSets.size());
for (auto const& mecStateSet : endComponentStateSets) {
MaximalEndComponent newMec;
for (auto state : mecStateSet) {
MaximalEndComponent::set_type containedChoices;
for (uint_fast64_t choice = nondeterministicChoiceIndices[state]; choice < nondeterministicChoiceIndices[state + 1]; ++choice) {
// Skip the choice if it is not part of our subsystem.
if (choices && !choices->get(choice)) {
continue;
}
if (includedChoices.get(choice)) {
containedChoices.insert(choice);
}
}
STORM_LOG_ASSERT(!containedChoices.empty(), "The contained choices of any state in an MEC must be non-empty.");
newMec.addState(state, std::move(containedChoices));
}
this->blocks.emplace_back(std::move(newMec));
}
STORM_LOG_DEBUG("MEC decomposition found " << this->size() << " GMEC(s).");
}
template <typename ValueType>
void GameMaximalEndComponentDecomposition<ValueType>::singleMEC(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> backwardTransitions, storm::storage::BitVector const* states, storm::storage::BitVector const* choices) {
MaximalEndComponent singleMec;
std::vector<uint_fast64_t> const& nondeterministicChoiceIndices = transitionMatrix.getRowGroupIndices();
std::list<StateBlock> endComponentStateSets;
std::vector<storm::storage::sparse::state_type> allStates;
allStates.resize(transitionMatrix.getRowGroupCount());
std::iota(allStates.begin(), allStates.end(), 0);
endComponentStateSets.emplace_back(allStates.begin(), allStates.end(), true);
storm::storage::BitVector includedChoices = storm::storage::BitVector(transitionMatrix.getRowCount(), true);
this->blocks.reserve(endComponentStateSets.size());
for (auto const& mecStateSet : endComponentStateSets) {
MaximalEndComponent newMec;
for (auto state : mecStateSet) {
MaximalEndComponent::set_type containedChoices;
for (uint_fast64_t choice = nondeterministicChoiceIndices[state]; choice < nondeterministicChoiceIndices[state + 1]; ++choice) {
// Skip the choice if it is not part of our subsystem.
if (choices && !choices->get(choice)) {
continue;
}
if (includedChoices.get(choice)) {
containedChoices.insert(choice);
}
}
STORM_LOG_ASSERT(!containedChoices.empty(), "The contained choices of any state in an MEC must be non-empty.");
newMec.addState(state, std::move(containedChoices));
}
this->blocks.emplace_back(std::move(newMec));
}
STORM_LOG_DEBUG("Whole state space is one single MEC");
}
// Explicitly instantiate the MEC decomposition.
template class GameMaximalEndComponentDecomposition<double>;
template GameMaximalEndComponentDecomposition<double>::GameMaximalEndComponentDecomposition(storm::models::sparse::NondeterministicModel<double> const& model);
#ifdef STORM_HAVE_CARL
template class GameMaximalEndComponentDecomposition<storm::RationalNumber>;
template GameMaximalEndComponentDecomposition<storm::RationalNumber>::GameMaximalEndComponentDecomposition(storm::models::sparse::NondeterministicModel<storm::RationalNumber> const& model);
template class GameMaximalEndComponentDecomposition<storm::RationalFunction>;
template GameMaximalEndComponentDecomposition<storm::RationalFunction>::GameMaximalEndComponentDecomposition(storm::models::sparse::NondeterministicModel<storm::RationalFunction> const& model);
#endif
}
}

109
src/storm/storage/GameMaximalEndComponentDecomposition.h

@ -0,0 +1,109 @@
#ifndef STORM_STORAGE_GAMEMAXIMALENDCOMPONENTDECOMPOSITION_H_
#define STORM_STORAGE_GAMEMAXIMALENDCOMPONENTDECOMPOSITION_H_
#include "storm/storage/Decomposition.h"
#include "storm/storage/MaximalEndComponent.h"
#include "storm/models/sparse/NondeterministicModel.h"
namespace storm {
namespace storage {
/*!
* This class represents the decomposition of a stochastic multiplayer game into its (irreducible) maximal end components.
*/
template <typename ValueType>
class GameMaximalEndComponentDecomposition : public Decomposition<MaximalEndComponent> {
public:
/*
* Creates an empty MEC decomposition.
*/
GameMaximalEndComponentDecomposition();
/*
* Creates an MEC decomposition of the given model.
*
* @param model The model to decompose into MECs.
*/
template <typename RewardModelType = storm::models::sparse::StandardRewardModel<ValueType>>
GameMaximalEndComponentDecomposition(storm::models::sparse::NondeterministicModel<ValueType, RewardModelType> const& model);
/*
* Creates an MEC decomposition of the given model (represented by a row-grouped matrix).
*
* @param transitionMatrix The transition relation of model to decompose into MECs.
* @param backwardTransition The reversed transition relation.
*/
GameMaximalEndComponentDecomposition(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions);
/*
* Creates an MEC decomposition of the given subsystem of given model (represented by a row-grouped matrix).
*
* @param transitionMatrix The transition relation of model to decompose into MECs.
* @param backwardTransition The reversed transition relation.
* @param states The states of the subsystem to decompose.
*/
GameMaximalEndComponentDecomposition(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& states);
/*
* Creates an MEC decomposition of the given subsystem of given model (represented by a row-grouped matrix).
*
* @param transitionMatrix The transition relation of model to decompose into MECs.
* @param backwardTransition The reversed transition relation.
* @param states The states of the subsystem to decompose.
* @param choices The choices of the subsystem to decompose.
*/
GameMaximalEndComponentDecomposition(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& states, storm::storage::BitVector const& choices);
/*!
* Creates an MEC decomposition of the given subsystem in the given model.
*
* @param model The model whose subsystem to decompose into MECs.
* @param states The states of the subsystem to decompose.
*/
GameMaximalEndComponentDecomposition(storm::models::sparse::NondeterministicModel<ValueType> const& model, storm::storage::BitVector const& states);
/*!
* Creates an MEC decomposition by copying the contents of the given MEC decomposition.
*
* @param other The MEC decomposition to copy.
*/
GameMaximalEndComponentDecomposition(GameMaximalEndComponentDecomposition const& other);
/*!
* Assigns the contents of the given MEC decomposition to the current one by copying its contents.
*
* @param other The MEC decomposition from which to copy-assign.
*/
GameMaximalEndComponentDecomposition& operator=(GameMaximalEndComponentDecomposition const& other);
/*!
* Creates an MEC decomposition by moving the contents of the given MEC decomposition.
*
* @param other The MEC decomposition to move.
*/
GameMaximalEndComponentDecomposition(GameMaximalEndComponentDecomposition&& other);
/*!
* Assigns the contents of the given MEC decomposition to the current one by moving its contents.
*
* @param other The MEC decomposition from which to move-assign.
*/
GameMaximalEndComponentDecomposition& operator=(GameMaximalEndComponentDecomposition&& other);
private:
/*!
* Performs the actual decomposition of the given subsystem in the given model into MECs. As a side-effect
* this stores the MECs found in the current decomposition.
*
* @param transitionMatrix The transition matrix representing the system whose subsystem to decompose into MECs.
* @param backwardTransitions The reversed transition relation.
* @param states The states of the subsystem to decompose.
* @param choices The choices of the subsystem to decompose.
*/
void performGameMaximalEndComponentDecomposition(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> backwardTransitions, storm::storage::BitVector const* states = nullptr, storm::storage::BitVector const* choices = nullptr);
void singleMEC(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> backwardTransitions, storm::storage::BitVector const* states = nullptr, storm::storage::BitVector const* choices = nullptr);
};
}
}
#endif /* STORM_STORAGE_GAMEMAXIMALENDCOMPONENTDECOMPOSITION_H_ */

66
src/storm/storage/MaximalEndComponent.cpp

@ -3,125 +3,125 @@
namespace storm {
namespace storage {
std::ostream& operator<<(std::ostream& out, storm::storage::FlatSet<uint_fast64_t> const& block);
MaximalEndComponent::MaximalEndComponent() : stateToChoicesMapping() {
// Intentionally left empty.
}
MaximalEndComponent::MaximalEndComponent(MaximalEndComponent const& other) : stateToChoicesMapping(other.stateToChoicesMapping) {
// Intentionally left empty.
}
MaximalEndComponent& MaximalEndComponent::operator=(MaximalEndComponent const& other) {
stateToChoicesMapping = other.stateToChoicesMapping;
return *this;
}
MaximalEndComponent::MaximalEndComponent(MaximalEndComponent&& other) : stateToChoicesMapping(std::move(other.stateToChoicesMapping)) {
// Intentionally left empty.
}
MaximalEndComponent& MaximalEndComponent::operator=(MaximalEndComponent&& other) {
stateToChoicesMapping = std::move(other.stateToChoicesMapping);
return *this;
}
void MaximalEndComponent::addState(uint_fast64_t state, set_type const& choices) {
stateToChoicesMapping[state] = choices;
}
void MaximalEndComponent::addState(uint_fast64_t state, set_type&& choices) {
stateToChoicesMapping.emplace(state, std::move(choices));
}
std::size_t MaximalEndComponent::size() const {
return stateToChoicesMapping.size();
}
MaximalEndComponent::set_type const& MaximalEndComponent::getChoicesForState(uint_fast64_t state) const {
auto stateChoicePair = stateToChoicesMapping.find(state);
if (stateChoicePair == stateToChoicesMapping.end()) {
throw storm::exceptions::InvalidStateException() << "Invalid call to MaximalEndComponent::getChoicesForState: cannot retrieve choices for state not contained in MEC.";
}
return stateChoicePair->second;
}
MaximalEndComponent::set_type& MaximalEndComponent::getChoicesForState(uint_fast64_t state) {
auto stateChoicePair = stateToChoicesMapping.find(state);
if (stateChoicePair == stateToChoicesMapping.end()) {
throw storm::exceptions::InvalidStateException() << "Invalid call to MaximalEndComponent::getChoicesForState: cannot retrieve choices for state not contained in MEC.";
}
return stateChoicePair->second;
}
bool MaximalEndComponent::containsState(uint_fast64_t state) const {
auto stateChoicePair = stateToChoicesMapping.find(state);
if (stateChoicePair == stateToChoicesMapping.end()) {
return false;
}
return true;
}
void MaximalEndComponent::removeState(uint_fast64_t state) {
auto stateChoicePair = stateToChoicesMapping.find(state);
if (stateChoicePair == stateToChoicesMapping.end()) {
throw storm::exceptions::InvalidStateException() << "Invalid call to MaximalEndComponent::removeState: cannot remove state not contained in MEC.";
}
stateToChoicesMapping.erase(stateChoicePair);
}
bool MaximalEndComponent::containsChoice(uint_fast64_t state, uint_fast64_t choice) const {
auto stateChoicePair = stateToChoicesMapping.find(state);
if (stateChoicePair == stateToChoicesMapping.end()) {
throw storm::exceptions::InvalidStateException() << "Invalid call to MaximalEndComponent::containsChoice: cannot obtain choices for state not contained in MEC.";
}
return stateChoicePair->second.find(choice) != stateChoicePair->second.end();
}
MaximalEndComponent::set_type MaximalEndComponent::getStateSet() const {
set_type states;
states.reserve(stateToChoicesMapping.size());
for (auto const& stateChoicesPair : stateToChoicesMapping) {
states.insert(stateChoicesPair.first);
}
return states;
}
std::ostream& operator<<(std::ostream& out, MaximalEndComponent const& component) {
out << "{";
for (auto const& stateChoicesPair : component.stateToChoicesMapping) {
out << "{" << stateChoicesPair.first << ", " << stateChoicesPair.second << "}";
out << "(" << stateChoicesPair.first << ", " << stateChoicesPair.second << ")";
}
out << "}";
return out;
}
MaximalEndComponent::iterator MaximalEndComponent::begin() {
return stateToChoicesMapping.begin();
}
MaximalEndComponent::iterator MaximalEndComponent::end() {
return stateToChoicesMapping.end();
}
MaximalEndComponent::const_iterator MaximalEndComponent::begin() const {
return stateToChoicesMapping.begin();
}
MaximalEndComponent::const_iterator MaximalEndComponent::end() const {
return stateToChoicesMapping.end();
}

593
src/storm/storage/SparseMatrix.cpp
File diff suppressed because it is too large
View File

164
src/storm/storage/jani/JSONExporter.cpp

@ -44,7 +44,7 @@ namespace storm {
ExportJsonType res = std::move(*boost::any_cast<ExportJsonType>(&tmp));
return res;
}
ExportJsonType buildExpression(storm::expressions::Expression const& exp, std::vector<storm::jani::Constant> const& constants, VariableSet const& globalVariables = VariableSet(), VariableSet const& localVariables = VariableSet(), std::unordered_set<std::string> const& auxiliaryVariables = {}) {
STORM_LOG_TRACE("Exporting " << exp);
return ExpressionToJson::translate(exp, constants, globalVariables, localVariables, auxiliaryVariables);
@ -53,14 +53,14 @@ namespace storm {
class CompositionJsonExporter : public CompositionVisitor {
public:
CompositionJsonExporter(bool allowRecursion) : allowRecursion(allowRecursion){
}
static ExportJsonType translate(storm::jani::Composition const& comp, bool allowRecursion = true) {
CompositionJsonExporter visitor(allowRecursion);
return anyToJson(comp.accept(visitor, boost::none));
}
virtual boost::any visit(AutomatonComposition const& composition, boost::any const&) {
ExportJsonType compDecl;
ExportJsonType autDecl;
@ -70,10 +70,10 @@ namespace storm {
compDecl["elements"] = elements;
return compDecl;
}
virtual boost::any visit(ParallelComposition const& composition, boost::any const& data) {
ExportJsonType compDecl;
std::vector<ExportJsonType> elems;
for (auto const& subcomp : composition.getSubcompositions()) {
ExportJsonType elemDecl;
@ -103,14 +103,14 @@ namespace storm {
if (!synElems.empty()) {
compDecl["syncs"] = synElems;
}
return compDecl;
}
private:
bool allowRecursion;
};
std::string comparisonTypeToJani(storm::logic::ComparisonType ct) {
switch(ct) {
case storm::logic::ComparisonType::Less:
@ -124,12 +124,12 @@ namespace storm {
}
STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentException, "Unknown ComparisonType");
}
ExportJsonType FormulaToJaniJson::constructPropertyInterval(boost::optional<storm::expressions::Expression> const& lower, boost::optional<bool> const& lowerExclusive, boost::optional<storm::expressions::Expression> const& upper, boost::optional<bool> const& upperExclusive) const {
STORM_LOG_THROW((lower.is_initialized() || upper.is_initialized()), storm::exceptions::InvalidJaniException, "PropertyInterval needs either a lower or an upper bound, but none was given.");
STORM_LOG_THROW((lower.is_initialized() || !lowerExclusive.is_initialized()), storm::exceptions::InvalidJaniException, "PropertyInterval defines wether the lower bound is exclusive but no lower bound is given.");
STORM_LOG_THROW((upper.is_initialized() || !upperExclusive.is_initialized()), storm::exceptions::InvalidJaniException, "PropertyInterval defines wether the upper bound is exclusive but no upper bound is given.");
ExportJsonType iDecl;
if (lower) {
iDecl["lower"] = buildExpression(*lower, model.getConstants(), model.getGlobalVariables());
@ -145,17 +145,17 @@ namespace storm {
}
return iDecl;
}
ExportJsonType FormulaToJaniJson::constructRewardAccumulation(storm::logic::RewardAccumulation const& rewardAccumulation, std::string const& rewardModelName) const {
storm::jani::RewardModelInformation info(model, rewardModelName);
bool steps = rewardAccumulation.isStepsSet() && (info.hasActionRewards() || info.hasTransitionRewards());
bool time = rewardAccumulation.isTimeSet() && !model.isDiscreteTimeModel() && info.hasStateRewards();
bool exit = rewardAccumulation.isExitSet() && info.hasStateRewards();
return constructRewardAccumulation(storm::logic::RewardAccumulation(steps, time, exit));
}
ExportJsonType FormulaToJaniJson::constructRewardAccumulation(storm::logic::RewardAccumulation const& rewardAccumulation) const {
std::vector<std::string> res;
if (rewardAccumulation.isStepsSet()) {
@ -178,7 +178,7 @@ namespace storm {
return constructRewardAccumulation(storm::logic::RewardAccumulation(true, true, false), rewardModelName);
}
}
ExportJsonType FormulaToJaniJson::translate(storm::logic::Formula const& formula, storm::jani::Model const& model, storm::jani::ModelFeatures& modelFeatures) {
FormulaToJaniJson translator(model);
auto result = anyToJson(formula.accept(translator));
@ -187,15 +187,15 @@ namespace storm {
}
return result;
}
bool FormulaToJaniJson::containsStateExitRewards() const {
return stateExitRewards;
}
boost::any FormulaToJaniJson::visit(storm::logic::AtomicExpressionFormula const& f, boost::any const&) const {
return buildExpression(f.getExpression(), model.getConstants(), model.getGlobalVariables());
}
boost::any FormulaToJaniJson::visit(storm::logic::AtomicLabelFormula const& f, boost::any const&) const {
ExportJsonType opDecl(f.getLabel());
return opDecl;
@ -218,10 +218,10 @@ namespace storm {
opDecl["op"] = "U";
opDecl["left"] = anyToJson(f.getLeftSubformula().accept(*this, data));
opDecl["right"] = anyToJson(f.getRightSubformula().accept(*this, data));
bool hasStepBounds(false), hasTimeBounds(false);
std::vector<ExportJsonType> rewardBounds;
for (uint64_t i = 0; i < f.getDimension(); ++i) {
boost::optional<storm::expressions::Expression> lower, upper;
boost::optional<bool> lowerExclusive, upperExclusive;
@ -234,7 +234,7 @@ namespace storm {
upperExclusive = f.isUpperBoundStrict(i);
}
ExportJsonType propertyInterval = constructPropertyInterval(lower, lowerExclusive, upper, upperExclusive);
auto tbr = f.getTimeBoundReference(i);
if (tbr.isStepBound() || (model.isDiscreteTimeModel() && tbr.isTimeBound())) {
STORM_LOG_THROW(!hasStepBounds, storm::exceptions::NotSupportedException, "Jani export of until formulas with multiple step bounds is not supported.");
@ -262,15 +262,15 @@ namespace storm {
return opDecl;
}
boost::any FormulaToJaniJson::visit(storm::logic::ConditionalFormula const&, boost::any const&) const {
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Jani currently does not support conditional formulae");
}
boost::any FormulaToJaniJson::visit(storm::logic::CumulativeRewardFormula const&, boost::any const&) const {
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Storm currently does not support translating cumulative reward formulae");
}
boost::any FormulaToJaniJson::visit(storm::logic::EventuallyFormula const& f, boost::any const& data) const {
ExportJsonType opDecl;
opDecl["op"] = "U";
@ -278,10 +278,10 @@ namespace storm {
opDecl["right"] = anyToJson(f.getSubformula().accept(*this, data));
return opDecl;
}
boost::any FormulaToJaniJson::visit(storm::logic::TimeOperatorFormula const& f, boost::any const& data) const {
ExportJsonType opDecl;
// Create standard reward accumulation for time operator formulas.
storm::logic::RewardAccumulation rewAcc(model.isDiscreteTimeModel(), !model.isDiscreteTimeModel(), false);
if (f.getSubformula().isEventuallyFormula() && f.getSubformula().asEventuallyFormula().hasRewardAccumulation()) {
@ -357,7 +357,7 @@ namespace storm {
if(f.hasOptimalityType()) {
opDecl["op"] = f.getOptimalityType() == storm::solver::OptimizationDirection::Minimize ? "Smin" : "Smax";
opDecl["exp"] = anyToJson(f.getSubformula().accept(*this, data));
} else {
// TODO add checks
opDecl["op"] = "Smin";
@ -366,7 +366,7 @@ namespace storm {
}
return opDecl;
}
boost::any FormulaToJaniJson::visit(storm::logic::LongRunAverageRewardFormula const&, boost::any const&) const {
// ExportJsonType opDecl;
// if(f.()) {
@ -384,7 +384,7 @@ namespace storm {
// if(f.hasOptimalityType()) {
// opDecl["op"] = f.getOptimalityType() == storm::solver::OptimizationDirection::Minimize ? "Smin" : "Smax";
// opDecl["exp"] = anyToJson(f.getSubformula().accept(*this, boost::none));
//
//
// } else {
// // TODO add checks
// opDecl["op"] = "Pmin";
@ -392,19 +392,19 @@ namespace storm {
// }
// }
// return opDecl;
STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Jani currently does not support conversion of an LRA reward formula");
}
boost::any FormulaToJaniJson::visit(storm::logic::MultiObjectiveFormula const&, boost::any const&) const {
STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Jani currently does not support conversion of a multi-objective formula");
}
boost::any FormulaToJaniJson::visit(storm::logic::QuantileFormula const&, boost::any const&) const {
STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Jani currently does not support conversion of a Quantile formula");
}
boost::any FormulaToJaniJson::visit(storm::logic::NextFormula const& f, boost::any const& data) const {
ExportJsonType opDecl;
opDecl["op"] = "U";
@ -414,13 +414,13 @@ namespace storm {
opDecl["step-bounds"] = constructPropertyInterval(intervalExpressionManager->integer(1), false, intervalExpressionManager->integer(1), false);
return opDecl;
}
boost::any FormulaToJaniJson::visit(storm::logic::ProbabilityOperatorFormula const& f, boost::any const& data) const {
ExportJsonType opDecl;
if(f.hasBound()) {
auto bound = f.getBound();
opDecl["op"] = comparisonTypeToJani(bound.comparisonType);
@ -436,7 +436,7 @@ namespace storm {
if(f.hasOptimalityType()) {
opDecl["op"] = f.getOptimalityType() == storm::solver::OptimizationDirection::Minimize ? "Pmin" : "Pmax";
opDecl["exp"] = anyToJson(f.getSubformula().accept(*this, data));
} else {
// TODO add checks
opDecl["op"] = "Pmin";
@ -445,10 +445,10 @@ namespace storm {
}
return opDecl;
}
boost::any FormulaToJaniJson::visit(storm::logic::RewardOperatorFormula const& f, boost::any const& data) const {
ExportJsonType opDecl;
std::string instantName;
if (model.isDiscreteTimeModel()) {
instantName = "step-instant";
@ -514,7 +514,7 @@ namespace storm {
}
}
opDecl["exp"] = buildExpression(model.getRewardModelExpression(rewardModelName), model.getConstants(), model.getGlobalVariables());
if(f.hasBound()) {
ExportJsonType compDecl;
auto bound = f.getBound();
@ -526,11 +526,11 @@ namespace storm {
return opDecl;
}
}
boost::any FormulaToJaniJson::visit(storm::logic::TotalRewardFormula const&, boost::any const&) const {
STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "Jani currently does not support a total reward formula");
}
boost::any FormulaToJaniJson::visit(storm::logic::UnaryBooleanStateFormula const& f, boost::any const& data) const {
ExportJsonType opDecl;
storm::logic::UnaryBooleanStateFormula::OperatorType op = f.getOperator();
@ -539,7 +539,7 @@ namespace storm {
opDecl["exp"] = anyToJson(f.getSubformula().accept(*this, data));
return opDecl;
}
boost::any FormulaToJaniJson::visit(storm::logic::UntilFormula const& f, boost::any const& data) const {
ExportJsonType opDecl;
opDecl["op"] = "U";
@ -547,9 +547,9 @@ namespace storm {
opDecl["right"] = anyToJson(f.getRightSubformula().accept(*this, data));
return opDecl;
}
std::string operatorTypeToJaniString(storm::expressions::OperatorType optype) {
using OpType = storm::expressions::OperatorType;
switch(optype) {
case OpType::And:
@ -602,16 +602,16 @@ namespace storm {
STORM_LOG_THROW(false, storm::exceptions::InvalidJaniException, "Operator not supported by Jani");
}
}
ExportJsonType ExpressionToJson::translate(storm::expressions::Expression const& expr, std::vector<storm::jani::Constant> const& constants, VariableSet const& globalVariables, VariableSet const& localVariables, std::unordered_set<std::string> const& auxiliaryVariables) {
// Simplify the expression first and reduce the nesting
auto simplifiedExpr = storm::jani::reduceNestingInJaniExpression(expr.simplify());
ExpressionToJson visitor(constants, globalVariables, localVariables, auxiliaryVariables);
return anyToJson(simplifiedExpr.accept(visitor, boost::none));
}
boost::any ExpressionToJson::visit(storm::expressions::IfThenElseExpression const& expression, boost::any const& data) {
ExportJsonType opDecl;
opDecl["op"] = "ite";
@ -679,7 +679,7 @@ namespace storm {
boost::any ExpressionToJson::visit(storm::expressions::RationalLiteralExpression const& expression, boost::any const&) {
return ExportJsonType(expression.getValue());
}
boost::any ExpressionToJson::visit(storm::expressions::ValueArrayExpression const& expression, boost::any const& data) {
ExportJsonType opDecl;
opDecl["op"] = "av";
@ -691,7 +691,7 @@ namespace storm {
opDecl["elements"] = std::move(elements);
return opDecl;
}
boost::any ExpressionToJson::visit(storm::expressions::ConstructorArrayExpression const& expression, boost::any const& data) {
ExportJsonType opDecl;
opDecl["op"] = "ac";
@ -704,7 +704,7 @@ namespace storm {
}
return opDecl;
}
boost::any ExpressionToJson::visit(storm::expressions::ArrayAccessExpression const& expression, boost::any const& data) {
ExportJsonType opDecl;
opDecl["op"] = "aa";
@ -712,7 +712,7 @@ namespace storm {
opDecl["index"] = anyToJson(expression.getOperand(1)->accept(*this, data));
return opDecl;
}
boost::any ExpressionToJson::visit(storm::expressions::FunctionCallExpression const& expression, boost::any const& data) {
ExportJsonType opDecl;
opDecl["op"] = "call";
@ -724,14 +724,14 @@ namespace storm {
opDecl["args"] = std::move(arguments);
return opDecl;
}
void JsonExporter::toFile(storm::jani::Model const& janiModel, std::vector<storm::jani::Property> const& formulas, std::string const& filepath, bool checkValid, bool compact) {
std::ofstream stream;
storm::utility::openFile(filepath, stream, false, true);
toStream(janiModel, formulas, stream, checkValid, compact);
storm::utility::closeFile(stream);
}
void JsonExporter::toStream(storm::jani::Model const& janiModel, std::vector<storm::jani::Property> const& formulas, std::ostream& os, bool checkValid, bool compact) {
if(checkValid) {
janiModel.checkValid();
@ -752,7 +752,7 @@ namespace storm {
}
STORM_LOG_INFO("Conversion completed " << janiModel.getName() << ".");
}
ExportJsonType buildActionArray(std::vector<storm::jani::Action> const& actions) {
std::vector<ExportJsonType> actionReprs;
uint64_t actIndex = 0;
@ -766,11 +766,11 @@ namespace storm {
actEntry["name"] = act.getName();
actionReprs.push_back(actEntry);
}
return ExportJsonType(actionReprs);
}
ExportJsonType buildTypeDescription(storm::expressions::Type const& type) {
ExportJsonType typeDescr;
if (type.isIntegerType()) {
@ -787,7 +787,7 @@ namespace storm {
}
return typeDescr;
}
void getBoundsFromConstraints(ExportJsonType& typeDesc, storm::expressions::Variable const& var, storm::expressions::Expression const& constraint, std::vector<storm::jani::Constant> const& constants) {
if (constraint.getBaseExpression().isBinaryBooleanFunctionExpression() && constraint.getBaseExpression().getOperator() == storm::expressions::OperatorType::And) {
getBoundsFromConstraints(typeDesc, var, constraint.getBaseExpression().getOperand(0), constants);
@ -811,7 +811,7 @@ namespace storm {
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Jani Export for constant constraint " << constraint << " is not supported.");
}
}
ExportJsonType buildConstantsArray(std::vector<storm::jani::Constant> const& constants) {
std::vector<ExportJsonType> constantDeclarations;
for(auto const& constant : constants) {
@ -833,8 +833,8 @@ namespace storm {
}
return ExportJsonType(constantDeclarations);
}
ExportJsonType buildVariablesArray(storm::jani::VariableSet const& varSet, std::vector<storm::jani::Constant> const& constants, VariableSet const& globalVariables, VariableSet const& localVariables = VariableSet()) {
ExportJsonType variableDeclarations = std::vector<ExportJsonType>();
for(auto const& variable : varSet) {
@ -916,7 +916,7 @@ namespace storm {
}
return functionDeclarations;
}
ExportJsonType buildAssignmentArray(storm::jani::OrderedAssignments const& orderedAssignments, std::vector<storm::jani::Constant> const& constants, VariableSet const& globalVariables, VariableSet const& localVariables, bool commentExpressions) {
ExportJsonType assignmentDeclarations = std::vector<ExportJsonType>();
bool addIndex = orderedAssignments.hasMultipleLevels();
@ -943,7 +943,7 @@ namespace storm {
}
return assignmentDeclarations;
}
ExportJsonType buildLocationsArray(std::vector<storm::jani::Location> const& locations, std::vector<storm::jani::Constant> const& constants, VariableSet const& globalVariables, VariableSet const& localVariables, bool commentExpressions) {
ExportJsonType locationDeclarations = std::vector<ExportJsonType>();
for(auto const& location : locations) {
@ -964,7 +964,7 @@ namespace storm {
}
return locationDeclarations;
}
ExportJsonType buildInitialLocations(storm::jani::Automaton const& automaton) {
std::vector<std::string> names;
for(auto const& initLocIndex : automaton.getInitialLocationIndices()) {
@ -972,7 +972,7 @@ namespace storm {
}
return ExportJsonType(names);
}
ExportJsonType buildDestinations(std::vector<EdgeDestination> const& destinations, std::map<uint64_t, std::string> const& locationNames, std::vector<storm::jani::Constant> const& constants, VariableSet const& globalVariables, VariableSet const& localVariables, bool commentExpressions) {
assert(destinations.size() > 0);
ExportJsonType destDeclarations = std::vector<ExportJsonType>();
@ -998,7 +998,7 @@ namespace storm {
}
return destDeclarations;
}
ExportJsonType buildEdge(Edge const& edge , std::map<uint64_t, std::string> const& actionNames, std::map<uint64_t, std::string> const& locationNames, std::vector<storm::jani::Constant> const& constants, VariableSet const& globalVariables, VariableSet const& localVariables, bool commentExpressions) {
STORM_LOG_THROW(edge.getDestinations().size() > 0, storm::exceptions::InvalidJaniException, "An edge without destinations is not allowed.");
ExportJsonType edgeEntry;
@ -1024,7 +1024,7 @@ namespace storm {
}
return edgeEntry;
}
ExportJsonType buildEdges(std::vector<Edge> const& edges , std::map<uint64_t, std::string> const& actionNames, std::map<uint64_t, std::string> const& locationNames, std::vector<storm::jani::Constant> const& constants, VariableSet const& globalVariables, VariableSet const& localVariables, bool commentExpressions) {
ExportJsonType edgeDeclarations = std::vector<ExportJsonType>();
for(auto const& edge : edges) {
@ -1035,7 +1035,7 @@ namespace storm {
}
return edgeDeclarations;
}
ExportJsonType buildAutomataArray(std::vector<storm::jani::Automaton> const& automata, std::map<uint64_t, std::string> const& actionNames, std::vector<storm::jani::Constant> const& constants, VariableSet const& globalVariables, bool commentExpressions) {
ExportJsonType automataDeclarations = std::vector<ExportJsonType>();
for(auto const& automaton : automata) {
@ -1055,7 +1055,7 @@ namespace storm {
}
return automataDeclarations;
}
void JsonExporter::convertModel(storm::jani::Model const& janiModel, bool commentExpressions) {
modelFeatures = janiModel.getModelFeatures();
jsonStruct["jani-version"] = janiModel.getJaniVersion();
@ -1071,12 +1071,12 @@ namespace storm {
jsonStruct["automata"] = buildAutomataArray(janiModel.getAutomata(), janiModel.getActionIndexToNameMap(), janiModel.getConstants(), janiModel.getGlobalVariables(), commentExpressions);
jsonStruct["system"] = CompositionJsonExporter::translate(janiModel.getSystemComposition());
}
ExportJsonType JsonExporter::getEdgeAsJson(storm::jani::Model const& janiModel, uint64_t automatonIndex, uint64_t edgeIndex, bool commentExpressions) {
auto const& automaton = janiModel.getAutomaton(automatonIndex);
return buildEdge(automaton.getEdge(edgeIndex), janiModel.getActionIndexToNameMap(), automaton.buildIdToLocationNameMap(), janiModel.getConstants(), janiModel.getGlobalVariables(), automaton.getVariables(), commentExpressions);
}
std::string janiFilterTypeString(storm::modelchecker::FilterType const& ft) {
switch(ft) {
case storm::modelchecker::FilterType::MIN:
@ -1102,7 +1102,7 @@ namespace storm {
}
STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentException, "Unknown FilterType");
}
ExportJsonType convertFilterExpression(storm::jani::FilterExpression const& fe, storm::jani::Model const& model, storm::jani::ModelFeatures& modelFeatures) {
ExportJsonType propDecl;
propDecl["states"]["op"] = "initial";
@ -1111,11 +1111,11 @@ namespace storm {
propDecl["values"] = FormulaToJaniJson::translate(*fe.getFormula(), model, modelFeatures);
return propDecl;
}
void JsonExporter::convertProperties( std::vector<storm::jani::Property> const& formulas, storm::jani::Model const& model) {
ExportJsonType properties;
// Unset model-features that only relate to properties. These are only set if such properties actually exist.
modelFeatures.remove(storm::jani::ModelFeature::StateExitRewards);
if (formulas.empty()) {
@ -1133,7 +1133,7 @@ namespace storm {
}
jsonStruct["properties"] = std::move(properties);
}
ExportJsonType JsonExporter::finalize() {
jsonStruct["features"] = ExportJsonType::parse(modelFeatures.toString());
return jsonStruct;

6
src/storm/storage/prism/Program.h

@ -345,19 +345,19 @@ namespace storm {
* @return Retrieves the mapping of player names to their indices.
*/
std::map<std::string, storm::storage::PlayerIndex> const& getPlayerNameToIndexMapping() const;
/*!
* Retrieves a vector whose i'th entry corresponds to the player controlling module i.
* Modules that are not controlled by any player will get assigned INVALID_PLAYER_INDEX
*/
std::vector<storm::storage::PlayerIndex> buildModuleIndexToPlayerIndexMap() const;
/*!
* Retrieves a vector whose i'th entry corresponds to the player controlling action with index i.
* Actions that are not controlled by any player (in particular the silent action) will get assigned INVALID_PLAYER_INDEX.
*/
std::map<uint_fast64_t, storm::storage::PlayerIndex> buildActionIndexToPlayerIndexMap() const;
/*!
* Retrieves the mapping of action names to their indices.
*

2
src/storm/utility/Engine.cpp

@ -179,10 +179,10 @@ namespace storm {
return storm::modelchecker::SparseDtmcPrctlModelChecker<storm::models::sparse::Dtmc<storm::RationalFunction>>::canHandleStatic(checkTask);
case ModelType::CTMC:
return storm::modelchecker::SparseCtmcCslModelChecker<storm::models::sparse::Ctmc<storm::RationalFunction>>::canHandleStatic(checkTask);
case ModelType::SMG:
case ModelType::MDP:
case ModelType::MA:
case ModelType::POMDP:
case ModelType::SMG:
return false;
}
break;

Loading…
Cancel
Save