Browse Source

Merge branch 'master' into prism-pomdp

main
Sebastian Junges 5 years ago
parent
commit
160043a8b8
  1. 3
      CHANGELOG.md
  2. 13
      src/storm-cli-utilities/model-handling.h
  3. 2
      src/storm-dft/parser/DFTGalileoParser.cpp
  4. 2
      src/storm-gspn/api/storm-gspn.cpp
  5. 30
      src/storm-parsers/parser/DirectEncodingParser.cpp
  6. 15
      src/storm/api/builder.h
  7. 56
      src/storm/builder/BuilderOptions.cpp
  8. 149
      src/storm/builder/DdJaniModelBuilder.cpp
  9. 19
      src/storm/builder/DdJaniModelBuilder.h
  10. 90
      src/storm/builder/DdPrismModelBuilder.cpp
  11. 10
      src/storm/builder/DdPrismModelBuilder.h
  12. 101
      src/storm/builder/TerminalStatesGetter.cpp
  13. 58
      src/storm/builder/TerminalStatesGetter.h
  14. 2
      src/storm/settings/SettingsManager.cpp
  15. 12
      src/storm/settings/modules/BuildSettings.cpp
  16. 13
      src/storm/settings/modules/BuildSettings.h
  17. 4
      src/storm/settings/modules/IOSettings.cpp
  18. 1
      src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp
  19. 2
      src/storm/storage/dd/cudd/InternalCuddAdd.cpp
  20. 2
      src/storm/storage/dd/sylvan/InternalSylvanAdd.cpp
  21. 23
      src/storm/utility/file.h
  22. 8
      src/test/storm/storage/SparseMatrixTest.cpp
  23. 24
      src/test/storm/utility/FileTest.cpp

3
CHANGELOG.md

@ -9,6 +9,9 @@ Version 1.4.x
## Version 1.4.2 (under development)
- DRN: support import of choice labelling
- Added option `--build:buildchoiceorig` to build a model (PRISM or JANI) with choice origins (which are exported with, e.g. `--exportscheduler`).
- Apply the maximum progress assumption while building a Markov automata with the Dd engine.
- Added option `--build:nomaxprog` to disable applying the maximum progress assumption during model building (for Markov Automata)
- `storm-pomdp`: Only accept POMDPs that are canonical
- `storm-pomdp`: Prism language extended with observable expressions
- `storm-pomdp`: Various fixes that prevented usage.

13
src/storm-cli-utilities/model-handling.h

@ -260,7 +260,8 @@ namespace storm {
template <storm::dd::DdType DdType, typename ValueType>
std::shared_ptr<storm::models::ModelBase> buildModelDd(SymbolicInput const& input) {
return storm::api::buildSymbolicModel<DdType, ValueType>(input.model.get(), createFormulasToRespect(input.properties), storm::settings::getModule<storm::settings::modules::BuildSettings>().isBuildFullModelSet());
auto buildSettings = storm::settings::getModule<storm::settings::modules::BuildSettings>();
return storm::api::buildSymbolicModel<DdType, ValueType>(input.model.get(), createFormulasToRespect(input.properties), buildSettings.isBuildFullModelSet(), !buildSettings.isApplyNoMaximumProgressAssumptionSet());
}
template <typename ValueType>
@ -268,19 +269,23 @@ namespace storm {
storm::builder::BuilderOptions options(createFormulasToRespect(input.properties), input.model.get());
options.setBuildChoiceLabels(buildSettings.isBuildChoiceLabelsSet());
options.setBuildStateValuations(buildSettings.isBuildStateValuationsSet());
bool buildChoiceOrigins = false;
bool buildChoiceOrigins = buildSettings.isBuildChoiceOriginsSet();
if (storm::settings::manager().hasModule(storm::settings::modules::CounterexampleGeneratorSettings::moduleName)) {
auto counterexampleGeneratorSettings = storm::settings::getModule<storm::settings::modules::CounterexampleGeneratorSettings>();
if (counterexampleGeneratorSettings.isCounterexampleSet()) {
buildChoiceOrigins = counterexampleGeneratorSettings.isMinimalCommandSetGenerationSet();
buildChoiceOrigins |= counterexampleGeneratorSettings.isMinimalCommandSetGenerationSet();
}
options.setBuildChoiceOrigins(buildChoiceOrigins);
}
options.setBuildChoiceOrigins(buildChoiceOrigins);
if (input.model->getModelType() == storm::storage::SymbolicModelDescription::ModelType::POMDP) {
options.setBuildChoiceOrigins(true);
options.setBuildChoiceLabels(true);
}
if (buildSettings.isApplyNoMaximumProgressAssumptionSet()) {
options.setApplyMaximalProgressAssumption(false);
}
options.setAddOutOfBoundsState(buildSettings.isBuildOutOfBoundsStateSet());
if (buildSettings.isBuildFullModelSet()) {
options.clearTerminalStates();

2
src/storm-dft/parser/DFTGalileoParser.cpp

@ -48,7 +48,7 @@ namespace storm {
std::string toplevelId = "";
bool comment = false; // Indicates whether the current line is part of a multiline comment
try {
while (std::getline(file, line)) {
while (storm::utility::getline(file, line)) {
++lineNo;
// First consider comments
if (comment) {

2
src/storm-gspn/api/storm-gspn.cpp

@ -94,7 +94,7 @@ namespace storm {
storm::utility::openFile(filename, stream);
std::string line;
while ( std::getline(stream, line) ) {
while (storm::utility::getline(stream, line)) {
std::vector<std::string> strs;
boost::split(strs, line, boost::is_any_of("\t "));
STORM_LOG_THROW(strs.size() == 2, storm::exceptions::WrongFormatException, "Expect key value pairs");

30
src/storm-parsers/parser/DirectEncodingParser.cpp

@ -3,25 +3,21 @@
#include <iostream>
#include <string>
#include <regex>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include "storm/models/sparse/MarkovAutomaton.h"
#include "storm/models/sparse/Ctmc.h"
#include "storm/adapters/RationalFunctionAdapter.h"
#include "storm/exceptions/FileIoException.h"
#include "storm/exceptions/WrongFormatException.h"
#include "storm/exceptions/InvalidArgumentException.h"
#include "storm/exceptions/NotSupportedException.h"
#include "storm/exceptions/WrongFormatException.h"
#include "storm/models/sparse/MarkovAutomaton.h"
#include "storm/models/sparse/Ctmc.h"
#include "storm/settings/SettingsManager.h"
#include "storm/adapters/RationalFunctionAdapter.h"
#include "storm/utility/constants.h"
#include "storm/utility/builder.h"
#include "storm/utility/macros.h"
#include "storm/utility/constants.h"
#include "storm/utility/file.h"
#include "storm/utility/macros.h"
namespace storm {
@ -48,7 +44,7 @@ namespace storm {
std::shared_ptr<storm::storage::sparse::ModelComponents<ValueType, RewardModelType>> modelComponents;
// Parse header
while (std::getline(file, line)) {
while (storm::utility::getline(file, line)) {
if (line.empty() || boost::starts_with(line, "//")) {
continue;
}
@ -65,7 +61,7 @@ namespace storm {
} else if (line == "@parameters") {
// Parse parameters
STORM_LOG_THROW(!sawParameters, storm::exceptions::WrongFormatException, "Parameters declared twice");
std::getline(file, line);
storm::utility::getline(file, line);
if (line != "") {
std::vector<std::string> parameters;
boost::split(parameters, line, boost::is_any_of(" "));
@ -78,7 +74,7 @@ namespace storm {
} else if (line == "@placeholders") {
// Parse placeholders
while (std::getline(file, line)) {
while (storm::utility::getline(file, line)) {
size_t posColon = line.find(':');
STORM_LOG_THROW(posColon != std::string::npos, storm::exceptions::WrongFormatException, "':' not found.");
std::string placeName = line.substr(0, posColon - 1);
@ -96,16 +92,16 @@ namespace storm {
} else if (line == "@reward_models") {
// Parse reward models
STORM_LOG_THROW(rewardModelNames.empty(), storm::exceptions::WrongFormatException, "Reward model names declared twice");
std::getline(file, line);
storm::utility::getline(file, line);
boost::split(rewardModelNames, line, boost::is_any_of("\t "));
} else if (line == "@nr_states") {
// Parse no. of states
STORM_LOG_THROW(nrStates == 0, storm::exceptions::WrongFormatException, "Number states declared twice");
std::getline(file, line);
storm::utility::getline(file, line);
nrStates = parseNumber<size_t>(line);
} else if (line == "@nr_choices") {
STORM_LOG_THROW(nrChoices == 0, storm::exceptions::WrongFormatException, "Number of actions declared twice");
std::getline(file, line);
storm::utility::getline(file, line);
nrChoices = parseNumber<size_t>(line);
} else if (line == "@model") {
// Parse rest of the model
@ -164,7 +160,7 @@ namespace storm {
size_t state = 0;
bool firstState = true;
bool firstActionForState = true;
while (std::getline(file, line)) {
while (storm::utility::getline(file, line)) {
STORM_LOG_TRACE("Parsing: " << line);
if (boost::starts_with(line, "state ")) {
// New state

15
src/storm/api/builder.h

@ -43,26 +43,29 @@ namespace storm {
}
template<storm::dd::DdType LibraryType, typename ValueType>
std::shared_ptr<storm::models::symbolic::Model<LibraryType, ValueType>> buildSymbolicModel(storm::storage::SymbolicModelDescription const& model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool buildFullModel = false) {
std::shared_ptr<storm::models::symbolic::Model<LibraryType, ValueType>> buildSymbolicModel(storm::storage::SymbolicModelDescription const& model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool buildFullModel = false, bool applyMaximumProgress = true) {
if (model.isPrismProgram()) {
typename storm::builder::DdPrismModelBuilder<LibraryType, ValueType>::Options options;
options = typename storm::builder::DdPrismModelBuilder<LibraryType, ValueType>::Options(formulas);
if (buildFullModel) {
options.buildAllLabels = true;
options.buildAllRewardModels = true;
options.terminalStates.clear();
}
storm::builder::DdPrismModelBuilder<LibraryType, ValueType> builder;
return builder.build(model.asPrismProgram(), options);
} else {
STORM_LOG_THROW(model.isJaniModel(), storm::exceptions::NotSupportedException, "Building symbolic model from this model description is unsupported.");
typename storm::builder::DdJaniModelBuilder<LibraryType, ValueType>::Options options;
options = typename storm::builder::DdJaniModelBuilder<LibraryType, ValueType>::Options(formulas);
typename storm::builder::DdJaniModelBuilder<LibraryType, ValueType>::Options options(formulas);
if (buildFullModel) {
options.buildAllLabels = true;
options.buildAllRewardModels = true;
options.applyMaximumProgressAssumption = false;
options.terminalStates.clear();
} else {
options.applyMaximumProgressAssumption = (model.getModelType() == storm::storage::SymbolicModelDescription::ModelType::MA && applyMaximumProgress);
}
storm::builder::DdJaniModelBuilder<LibraryType, ValueType> builder;
@ -71,12 +74,12 @@ namespace storm {
}
template<>
inline std::shared_ptr<storm::models::symbolic::Model<storm::dd::DdType::CUDD, storm::RationalNumber>> buildSymbolicModel(storm::storage::SymbolicModelDescription const& model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool buildFullModel) {
inline std::shared_ptr<storm::models::symbolic::Model<storm::dd::DdType::CUDD, storm::RationalNumber>> buildSymbolicModel(storm::storage::SymbolicModelDescription const& model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool, bool) {
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "CUDD does not support rational numbers.");
}
template<>
inline std::shared_ptr<storm::models::symbolic::Model<storm::dd::DdType::CUDD, storm::RationalFunction>> buildSymbolicModel(storm::storage::SymbolicModelDescription const& model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool buildFullModel) {
inline std::shared_ptr<storm::models::symbolic::Model<storm::dd::DdType::CUDD, storm::RationalFunction>> buildSymbolicModel(storm::storage::SymbolicModelDescription const& model, std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas, bool, bool) {
STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "CUDD does not support rational functions.");
}

56
src/storm/builder/BuilderOptions.cpp

@ -1,5 +1,7 @@
#include "storm/builder/BuilderOptions.h"
#include "storm/builder/TerminalStatesGetter.h"
#include "storm/logic/Formulas.h"
#include "storm/logic/LiftableTransitionRewardsVisitor.h"
@ -95,58 +97,8 @@ namespace storm {
}
void BuilderOptions::setTerminalStatesFromFormula(storm::logic::Formula const& formula) {
if (formula.isAtomicExpressionFormula()) {
addTerminalExpression(formula.asAtomicExpressionFormula().getExpression(), true);
} else if (formula.isAtomicLabelFormula()) {
addTerminalLabel(formula.asAtomicLabelFormula().getLabel(), true);
} else if (formula.isEventuallyFormula()) {
storm::logic::Formula const& sub = formula.asEventuallyFormula().getSubformula();
if (sub.isAtomicExpressionFormula() || sub.isAtomicLabelFormula()) {
this->setTerminalStatesFromFormula(sub);
}
} else if (formula.isUntilFormula()) {
storm::logic::Formula const& right = formula.asUntilFormula().getRightSubformula();
if (right.isAtomicExpressionFormula() || right.isAtomicLabelFormula()) {
this->setTerminalStatesFromFormula(right);
}
storm::logic::Formula const& left = formula.asUntilFormula().getLeftSubformula();
if (left.isAtomicExpressionFormula()) {
addTerminalExpression(left.asAtomicExpressionFormula().getExpression(), false);
} else if (left.isAtomicLabelFormula()) {
addTerminalLabel(left.asAtomicLabelFormula().getLabel(), false);
}
} else if (formula.isBoundedUntilFormula()) {
storm::logic::BoundedUntilFormula const& boundedUntil = formula.asBoundedUntilFormula();
bool hasLowerBound = false;
for (uint64_t i = 0; i < boundedUntil.getDimension(); ++i) {
if (boundedUntil.hasLowerBound(i) && (boundedUntil.getLowerBound(i).containsVariables() || !storm::utility::isZero(boundedUntil.getLowerBound(i).evaluateAsRational()))) {
hasLowerBound = true;
break;
}
}
if (!hasLowerBound) {
storm::logic::Formula const& right = boundedUntil.getRightSubformula();
if (right.isAtomicExpressionFormula() || right.isAtomicLabelFormula()) {
this->setTerminalStatesFromFormula(right);
}
}
storm::logic::Formula const& left = boundedUntil.getLeftSubformula();
if (left.isAtomicExpressionFormula()) {
addTerminalExpression(left.asAtomicExpressionFormula().getExpression(), false);
} else if (left.isAtomicLabelFormula()) {
addTerminalLabel(left.asAtomicLabelFormula().getLabel(), false);
}
} else if (formula.isProbabilityOperatorFormula()) {
storm::logic::Formula const& sub = formula.asProbabilityOperatorFormula().getSubformula();
if (sub.isEventuallyFormula() || sub.isUntilFormula() || sub.isBoundedUntilFormula()) {
this->setTerminalStatesFromFormula(sub);
}
} else if (formula.isRewardOperatorFormula() || formula.isTimeOperatorFormula()) {
storm::logic::Formula const& sub = formula.asOperatorFormula().getSubformula();
if (sub.isEventuallyFormula()) {
this->setTerminalStatesFromFormula(sub);
}
}
getTerminalStatesFromFormula(formula, [this](storm::expressions::Expression const& expr, bool inverted){ this->addTerminalExpression(expr, inverted);}
, [this](std::string const& label, bool inverted){ this->addTerminalLabel(label, inverted);});
}
std::set<std::string> const& BuilderOptions::getRewardModelNames() const {

149
src/storm/builder/DdJaniModelBuilder.cpp

@ -46,18 +46,18 @@ namespace storm {
namespace builder {
template <storm::dd::DdType Type, typename ValueType>
DdJaniModelBuilder<Type, ValueType>::Options::Options(bool buildAllLabels, bool buildAllRewardModels) : buildAllLabels(buildAllLabels), buildAllRewardModels(buildAllRewardModels), rewardModelsToBuild(), constantDefinitions(), terminalStates(), negatedTerminalStates() {
DdJaniModelBuilder<Type, ValueType>::Options::Options(bool buildAllLabels, bool buildAllRewardModels, bool applyMaximumProgressAssumption) : buildAllLabels(buildAllLabels), buildAllRewardModels(buildAllRewardModels), applyMaximumProgressAssumption(applyMaximumProgressAssumption), rewardModelsToBuild(), constantDefinitions() {
// Intentionally left empty.
}
template <storm::dd::DdType Type, typename ValueType>
DdJaniModelBuilder<Type, ValueType>::Options::Options(storm::logic::Formula const& formula) : buildAllRewardModels(false), rewardModelsToBuild(), constantDefinitions(), terminalStates(), negatedTerminalStates() {
DdJaniModelBuilder<Type, ValueType>::Options::Options(storm::logic::Formula const& formula) : buildAllRewardModels(false), rewardModelsToBuild(), constantDefinitions() {
this->preserveFormula(formula);
this->setTerminalStatesFromFormula(formula);
}
template <storm::dd::DdType Type, typename ValueType>
DdJaniModelBuilder<Type, ValueType>::Options::Options(std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas) : buildAllLabels(false), buildAllRewardModels(false), rewardModelsToBuild(), constantDefinitions(), terminalStates(), negatedTerminalStates() {
DdJaniModelBuilder<Type, ValueType>::Options::Options(std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas) : buildAllLabels(false), buildAllRewardModels(false), rewardModelsToBuild(), constantDefinitions() {
if (!formulas.empty()) {
for (auto const& formula : formulas) {
this->preserveFormula(*formula);
@ -71,12 +71,7 @@ namespace storm {
template <storm::dd::DdType Type, typename ValueType>
void DdJaniModelBuilder<Type, ValueType>::Options::preserveFormula(storm::logic::Formula const& formula) {
// If we already had terminal states, we need to erase them.
if (terminalStates) {
terminalStates.reset();
}
if (negatedTerminalStates) {
negatedTerminalStates.reset();
}
terminalStates.clear();
// If we are not required to build all reward models, we determine the reward models we need to build.
if (!buildAllRewardModels) {
@ -93,28 +88,7 @@ namespace storm {
template <storm::dd::DdType Type, typename ValueType>
void DdJaniModelBuilder<Type, ValueType>::Options::setTerminalStatesFromFormula(storm::logic::Formula const& formula) {
if (formula.isAtomicExpressionFormula()) {
terminalStates = formula.asAtomicExpressionFormula().getExpression();
} else if (formula.isEventuallyFormula()) {
storm::logic::Formula const& sub = formula.asEventuallyFormula().getSubformula();
if (sub.isAtomicExpressionFormula() || sub.isAtomicLabelFormula()) {
this->setTerminalStatesFromFormula(sub);
}
} else if (formula.isUntilFormula()) {
storm::logic::Formula const& right = formula.asUntilFormula().getRightSubformula();
if (right.isAtomicExpressionFormula() || right.isAtomicLabelFormula()) {
this->setTerminalStatesFromFormula(right);
}
storm::logic::Formula const& left = formula.asUntilFormula().getLeftSubformula();
if (left.isAtomicExpressionFormula()) {
negatedTerminalStates = left.asAtomicExpressionFormula().getExpression();
}
} else if (formula.isProbabilityOperatorFormula()) {
storm::logic::Formula const& sub = formula.asProbabilityOperatorFormula().getSubformula();
if (sub.isEventuallyFormula() || sub.isUntilFormula()) {
this->setTerminalStatesFromFormula(sub);
}
}
terminalStates = getTerminalStatesFromFormula(formula);
}
template <storm::dd::DdType Type, typename ValueType>
@ -688,6 +662,19 @@ namespace storm {
return ActionDd(newGuard, newTransitions, newTransientEdgeAssignments, newLocalNondeterminismVariables, newVariableToWritingFragment, newIllegalFragment);
}
/*!
* Conjuncts the guard of the action with the provided condition, i.e., this action is only enabled if the provided condition is true.
*/
void conjunctGuardWith(storm::dd::Bdd<Type> const& condition) {
guard &= condition;
storm::dd::Add<Type, ValueType> conditionAdd = condition.template toAdd<ValueType>();
transitions *= conditionAdd;
for (auto& t : transientEdgeAssignments) {
t.second *= conditionAdd;
}
illegalFragment &= condition;
}
bool isInputEnabled() const {
return inputEnabled;
}
@ -696,10 +683,10 @@ namespace storm {
inputEnabled = true;
}
// A DD that represents all states that have this edge enabled.
// A DD that represents all states that have this action enabled.
storm::dd::Bdd<Type> guard;
// A DD that represents the transitions of this edge.
// A DD that represents the transitions of this action.
storm::dd::Add<Type, ValueType> transitions;
// A mapping from transient variables to their assignments.
@ -813,11 +800,12 @@ namespace storm {
std::pair<uint64_t, uint64_t> localNondeterminismVariables;
};
CombinedEdgesSystemComposer(storm::jani::Model const& model, storm::jani::CompositionInformation const& actionInformation, CompositionVariables<Type, ValueType> const& variables, std::vector<storm::expressions::Variable> const& transientVariables) : SystemComposer<Type, ValueType>(model, variables, transientVariables), actionInformation(actionInformation) {
CombinedEdgesSystemComposer(storm::jani::Model const& model, storm::jani::CompositionInformation const& actionInformation, CompositionVariables<Type, ValueType> const& variables, std::vector<storm::expressions::Variable> const& transientVariables, bool applyMaximumProgress) : SystemComposer<Type, ValueType>(model, variables, transientVariables), actionInformation(actionInformation), applyMaximumProgress(applyMaximumProgress) {
// Intentionally left empty.
}
storm::jani::CompositionInformation const& actionInformation;
bool applyMaximumProgress;
ComposerResult<Type, ValueType> compose() override {
STORM_LOG_THROW(this->model.hasStandardCompliantComposition(), storm::exceptions::WrongFormatException, "Model builder only supports non-nested parallel compositions.");
@ -899,7 +887,7 @@ namespace storm {
inputEnabledActionIndices.insert(actionInformation.getActionIndex(actionName));
}
return buildAutomatonDd(composition.getAutomatonName(), data.empty() ? actionInstantiations : boost::any_cast<ActionInstantiations const&>(data), inputEnabledActionIndices);
return buildAutomatonDd(composition.getAutomatonName(), data.empty() ? actionInstantiations : boost::any_cast<ActionInstantiations const&>(data), inputEnabledActionIndices, data.empty());
}
boost::any visit(storm::jani::ParallelComposition const& composition, boost::any const& data) override {
@ -939,13 +927,14 @@ namespace storm {
boost::optional<uint64_t> previousActionPosition = synchVector.getPositionOfPrecedingParticipatingAction(subcompositionIndex);
STORM_LOG_ASSERT(previousActionPosition, "Inconsistent information about synchronization vector.");
AutomatonDd const& previousAutomatonDd = subautomata[previousActionPosition.get()];
auto precedingActionIt = previousAutomatonDd.actions.find(ActionIdentification(actionInformation.getActionIndex(synchVector.getInput(previousActionPosition.get())), synchronizationVectorIndex, isCtmc));
auto precedingActionIndex = actionInformation.getActionIndex(synchVector.getInput(previousActionPosition.get()));
auto precedingActionIt = previousAutomatonDd.actions.find(ActionIdentification(precedingActionIndex, synchronizationVectorIndex, isCtmc));
uint64_t highestLocalNondeterminismVariable = 0;
if (precedingActionIt != previousAutomatonDd.actions.end()) {
highestLocalNondeterminismVariable = precedingActionIt->second.getHighestLocalNondeterminismVariable();
} else {
STORM_LOG_WARN("Subcomposition does not have action that is mentioned in parallel composition.");
STORM_LOG_WARN("Subcomposition does not have action" << actionInformation.getActionName(precedingActionIndex) << " that is mentioned in parallel composition.");
}
actionInstantiations[actionIndex].emplace_back(actionIndex, synchronizationVectorIndex, highestLocalNondeterminismVariable, isCtmc);
}
@ -961,6 +950,9 @@ namespace storm {
AutomatonDd composeInParallel(std::vector<AutomatonDd> const& subautomata, std::vector<storm::jani::SynchronizationVector> const& synchronizationVectors) {
AutomatonDd result(this->variables.manager->template getAddOne<ValueType>());
// Disjunction of all guards of non-markovian actions (only required for maximum progress assumption.
storm::dd::Bdd<Type> nonMarkovianActionGuards = this->variables.manager->getBddZero();
// Build the results of the synchronization vectors.
std::unordered_map<ActionIdentification, std::vector<ActionDd>, ActionIdentificationHash> actions;
for (uint64_t synchronizationVectorIndex = 0; synchronizationVectorIndex < synchronizationVectors.size(); ++synchronizationVectorIndex) {
@ -968,6 +960,11 @@ namespace storm {
boost::optional<ActionDd> synchronizingAction = combineSynchronizingActions(subautomata, synchVector, synchronizationVectorIndex);
if (synchronizingAction) {
if (applyMaximumProgress) {
STORM_LOG_ASSERT(this->model.getModelType() == storm::jani::ModelType::MA, "Maximum progress assumption enabled for unexpected model type.");
// By the JANI standard, we can assume that synchronizing actions of MAs are always non-Markovian.
nonMarkovianActionGuards |= synchronizingAction->guard;
}
actions[ActionIdentification(actionInformation.getActionIndex(synchVector.getOutput()), this->model.getModelType() == storm::jani::ModelType::CTMC)].emplace_back(synchronizingAction.get());
}
}
@ -1011,9 +1008,26 @@ namespace storm {
auto& allSilentActionDds = actions[silentActionIdentification];
allSilentActionDds.insert(allSilentActionDds.end(), silentActionDds.begin(), silentActionDds.end());
}
// Add guards of non-markovian actions
if (applyMaximumProgress) {
auto allSilentActionDdsIt = actions.find(silentActionIdentification);
if (allSilentActionDdsIt != actions.end()) {
for (ActionDd const& silentActionDd : allSilentActionDdsIt->second) {
nonMarkovianActionGuards |= silentActionDd.guard;
}
}
}
if (!silentMarkovianActionDds.empty()) {
auto& allMarkovianSilentActionDds = actions[silentMarkovianActionIdentification];
allMarkovianSilentActionDds.insert(allMarkovianSilentActionDds.end(), silentMarkovianActionDds.begin(), silentMarkovianActionDds.end());
if (applyMaximumProgress && !nonMarkovianActionGuards.isZero()) {
auto invertedNonMarkovianGuards = !nonMarkovianActionGuards;
for (ActionDd& markovianActionDd : allMarkovianSilentActionDds) {
markovianActionDd.conjunctGuardWith(invertedNonMarkovianGuards);
}
}
}
// Finally, combine (potentially) multiple action DDs.
@ -1693,10 +1707,13 @@ namespace storm {
}
}
AutomatonDd buildAutomatonDd(std::string const& automatonName, ActionInstantiations const& actionInstantiations, std::set<uint64_t> const& inputEnabledActionIndices) {
AutomatonDd buildAutomatonDd(std::string const& automatonName, ActionInstantiations const& actionInstantiations, std::set<uint64_t> const& inputEnabledActionIndices, bool isTopLevelAutomaton) {
STORM_LOG_TRACE("Building DD for automaton '" << automatonName << "'.");
AutomatonDd result(this->variables.automatonToIdentityMap.at(automatonName));
// Disjunction of all guards of non-markovian actions (only required for maximum progress assumption).
storm::dd::Bdd<Type> nonMarkovianActionGuards = this->variables.manager->getBddZero();
storm::jani::Automaton const& automaton = this->model.getAutomaton(automatonName);
for (auto const& actionInstantiation : actionInstantiations) {
uint64_t actionIndex = actionInstantiation.first;
@ -1713,12 +1730,20 @@ namespace storm {
if (inputEnabled) {
actionDd.setIsInputEnabled();
}
if (applyMaximumProgress && isTopLevelAutomaton && !instantiation.isMarkovian()) {
nonMarkovianActionGuards |= actionDd.guard;
}
STORM_LOG_TRACE("Used local nondeterminism variables are " << actionDd.getLowestLocalNondeterminismVariable() << " to " << actionDd.getHighestLocalNondeterminismVariable() << ".");
result.actions[ActionIdentification(actionIndex, instantiation.synchronizationVectorIndex, instantiation.isMarkovian())] = actionDd;
result.extendLocalNondeterminismVariables(actionDd.getLocalNondeterminismVariables());
}
}
if (applyMaximumProgress && isTopLevelAutomaton) {
ActionIdentification silentMarkovianActionIdentification(storm::jani::Model::SILENT_ACTION_INDEX, true);
result.actions[silentMarkovianActionIdentification].conjunctGuardWith(!nonMarkovianActionGuards);
}
for (uint64_t locationIndex = 0; locationIndex < automaton.getNumberOfLocations(); ++locationIndex) {
auto const& location = automaton.getLocation(locationIndex);
performTransientAssignments(location.getAssignments().getTransientAssignments(), [this,&automatonName,locationIndex,&result] (storm::jani::Assignment const& assignment) {
@ -1870,7 +1895,7 @@ namespace storm {
}
template <storm::dd::DdType Type, typename ValueType>
storm::dd::Bdd<Type> postprocessSystem(storm::jani::Model const& model, ComposerResult<Type, ValueType>& system, CompositionVariables<Type, ValueType> const& variables, typename DdJaniModelBuilder<Type, ValueType>::Options const& options) {
storm::dd::Bdd<Type> postprocessSystem(storm::jani::Model const& model, ComposerResult<Type, ValueType>& system, CompositionVariables<Type, ValueType> const& variables, typename DdJaniModelBuilder<Type, ValueType>::Options const& options, std::map<std::string, storm::expressions::Expression> const& labelsToExpressionMap) {
// For DTMCs, we normalize each row to 1 (to account for non-determinism).
if (model.getModelType() == storm::jani::ModelType::DTMC) {
storm::dd::Add<Type, ValueType> stateToNumberOfChoices = system.transitions.sumAbstract(variables.columnMetaVariables);
@ -1883,25 +1908,23 @@ namespace storm {
}
// If we were asked to treat some states as terminal states, we cut away their transitions now.
if (options.terminalStates || options.negatedTerminalStates) {
std::map<storm::expressions::Variable, storm::expressions::Expression> constantsSubstitution = model.getConstantsSubstitution();
storm::dd::Bdd<Type> terminalStatesBdd = variables.manager->getBddZero();
if (options.terminalStates) {
storm::expressions::Expression terminalExpression = options.terminalStates.get().substitute(constantsSubstitution);
STORM_LOG_TRACE("Making the states satisfying " << terminalExpression << " terminal.");
terminalStatesBdd = variables.rowExpressionAdapter->translateExpression(terminalExpression).toBdd();
}
if (options.negatedTerminalStates) {
storm::expressions::Expression negatedTerminalExpression = options.negatedTerminalStates.get().substitute(constantsSubstitution);
STORM_LOG_TRACE("Making the states *not* satisfying " << negatedTerminalExpression << " terminal.");
terminalStatesBdd |= !variables.rowExpressionAdapter->translateExpression(negatedTerminalExpression).toBdd();
}
storm::dd::Bdd<Type> terminalStatesBdd = variables.manager->getBddZero();
if (!options.terminalStates.empty()) {
storm::expressions::Expression terminalExpression = options.terminalStates.asExpression([&model, &labelsToExpressionMap](std::string const& labelName) {
auto exprIt = labelsToExpressionMap.find(labelName);
if (exprIt != labelsToExpressionMap.end()) {
return exprIt->second;
} else {
STORM_LOG_THROW(labelName == "init" || labelName == "deadlock", storm::exceptions::InvalidArgumentException, "Terminal states refer to illegal label '" << labelName << "'.");
// If the label name is "init" we can abort 'exploration' directly at the initial state. If it is deadlock, we do not have to abort.
return model.getExpressionManager().boolean(labelName == "init");
}
});
terminalExpression = terminalExpression.substitute(model.getConstantsSubstitution());
terminalStatesBdd = variables.rowExpressionAdapter->translateExpression(terminalExpression).toBdd();
system.transitions *= (!terminalStatesBdd).template toAdd<ValueType>();
return terminalStatesBdd;
}
return variables.manager->getBddZero();
return terminalStatesBdd;
}
template <storm::dd::DdType Type, typename ValueType>
@ -2089,18 +2112,25 @@ namespace storm {
std::vector<storm::expressions::Variable> rewardVariables = selectRewardVariables<Type, ValueType>(preparedModel, options);
// Create a builder to compose and build the model.
CombinedEdgesSystemComposer<Type, ValueType> composer(preparedModel, actionInformation, variables, rewardVariables);
bool applyMaximumProgress = options.applyMaximumProgressAssumption && model.getModelType() == storm::jani::ModelType::MA;
CombinedEdgesSystemComposer<Type, ValueType> composer(preparedModel, actionInformation, variables, rewardVariables, applyMaximumProgress);
ComposerResult<Type, ValueType> system = composer.compose();
// Postprocess the variables in place.
postprocessVariables(preparedModel.getModelType(), system, variables);
// Build the label to expressions mapping.
auto labelsToExpressionMap = buildLabelExpressions(preparedModel, variables, options);
// Postprocess the system in place and get the states that were terminal (i.e. whose transitions were cut off).
storm::dd::Bdd<Type> terminalStates = postprocessSystem(preparedModel, system, variables, options);
storm::dd::Bdd<Type> terminalStates = postprocessSystem(preparedModel, system, variables, options, labelsToExpressionMap);
// Start creating the model components.
ModelComponents<Type, ValueType> modelComponents;
// Set the label expressions
modelComponents.labelToExpressionMap = std::move(labelsToExpressionMap);
// Build initial states.
modelComponents.initialStates = computeInitialStates(preparedModel, variables);
@ -2128,9 +2158,6 @@ namespace storm {
// Build the reward models.
modelComponents.rewardModels = buildRewardModels(reachableStatesAdd, modelComponents.transitionMatrix, preparedModel.getModelType(), variables, system, rewardVariables);
// Build the label to expressions mapping.
modelComponents.labelToExpressionMap = buildLabelExpressions(preparedModel, variables, options);
// Finally, create the model.
return createModel(preparedModel.getModelType(), variables, modelComponents);
}

19
src/storm/builder/DdJaniModelBuilder.h

@ -5,6 +5,7 @@
#include "storm/storage/dd/DdType.h"
#include "storm/logic/Formula.h"
#include "storm/builder/TerminalStatesGetter.h"
namespace storm {
@ -27,7 +28,7 @@ namespace storm {
/*!
* Creates an object representing the default building options.
*/
Options(bool buildAllLabels = false, bool buildAllRewardModels = false);
Options(bool buildAllLabels = false, bool buildAllRewardModels = false, bool applyMaximumProgressAssumption = true);
/*! Creates an object representing the suggested building options assuming that the given formula is the
* only one to check. Additional formulas may be preserved by calling <code>preserveFormula</code>.
@ -78,9 +79,6 @@ namespace storm {
/// A flag that indicates whether all labels are to be built. In this case, the label names are to be ignored.
bool buildAllLabels;
/// A set of labels to build.
std::set<std::string> labelNames;
/*!
* Retrieves whether the flag to build all reward models is set.
@ -90,19 +88,22 @@ namespace storm {
// A flag that indicates whether or not all reward models are to be build.
bool buildAllRewardModels;
/// A flag that indicates whether the maximum progress assumption should be applied.
bool applyMaximumProgressAssumption;
/// A set of labels to build.
std::set<std::string> labelNames;
// A list of reward models to be build in case not all reward models are to be build.
std::set<std::string> rewardModelsToBuild;
// An optional mapping that, if given, contains defining expressions for undefined constants.
boost::optional<std::map<storm::expressions::Variable, storm::expressions::Expression>> constantDefinitions;
// An optional expression or label that (a subset of) characterizes the terminal states of the model.
// An optional set of expression or labels that characterizes (a subset of) the terminal states of the model.
// If this is set, the outgoing transitions of these states are replaced with a self-loop.
boost::optional<storm::expressions::Expression> terminalStates;
storm::builder::TerminalStates terminalStates;
// An optional expression or label whose negation characterizes (a subset of) the terminal states of the
// model. If this is set, the outgoing transitions of these states are replaced with a self-loop.
boost::optional<storm::expressions::Expression> negatedTerminalStates;
};
/*!

90
src/storm/builder/DdPrismModelBuilder.cpp

@ -540,18 +540,18 @@ namespace storm {
};
template <storm::dd::DdType Type, typename ValueType>
DdPrismModelBuilder<Type, ValueType>::Options::Options() : buildAllRewardModels(false), rewardModelsToBuild(), buildAllLabels(false), labelsToBuild(), terminalStates(), negatedTerminalStates() {
DdPrismModelBuilder<Type, ValueType>::Options::Options() : buildAllRewardModels(false), rewardModelsToBuild(), buildAllLabels(false), labelsToBuild() {
// Intentionally left empty.
}
template <storm::dd::DdType Type, typename ValueType>
DdPrismModelBuilder<Type, ValueType>::Options::Options(storm::logic::Formula const& formula) : buildAllRewardModels(false), rewardModelsToBuild(), buildAllLabels(false), labelsToBuild(std::set<std::string>()), terminalStates(), negatedTerminalStates() {
DdPrismModelBuilder<Type, ValueType>::Options::Options(storm::logic::Formula const& formula) : buildAllRewardModels(false), rewardModelsToBuild(), buildAllLabels(false), labelsToBuild(std::set<std::string>()) {
this->preserveFormula(formula);
this->setTerminalStatesFromFormula(formula);
}
template <storm::dd::DdType Type, typename ValueType>
DdPrismModelBuilder<Type, ValueType>::Options::Options(std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas) : buildAllRewardModels(false), rewardModelsToBuild(), buildAllLabels(false), labelsToBuild(), terminalStates(), negatedTerminalStates() {
DdPrismModelBuilder<Type, ValueType>::Options::Options(std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas) : buildAllRewardModels(false), rewardModelsToBuild(), buildAllLabels(false), labelsToBuild() {
for (auto const& formula : formulas) {
this->preserveFormula(*formula);
}
@ -563,12 +563,7 @@ namespace storm {
template <storm::dd::DdType Type, typename ValueType>
void DdPrismModelBuilder<Type, ValueType>::Options::preserveFormula(storm::logic::Formula const& formula) {
// If we already had terminal states, we need to erase them.
if (terminalStates) {
terminalStates.reset();
}
if (negatedTerminalStates) {
negatedTerminalStates.reset();
}
terminalStates.clear();
// If we are not required to build all reward models, we determine the reward models we need to build.
if (!buildAllRewardModels) {
@ -588,32 +583,7 @@ namespace storm {
template <storm::dd::DdType Type, typename ValueType>
void DdPrismModelBuilder<Type, ValueType>::Options::setTerminalStatesFromFormula(storm::logic::Formula const& formula) {
if (formula.isAtomicExpressionFormula()) {
terminalStates = formula.asAtomicExpressionFormula().getExpression();
} else if (formula.isAtomicLabelFormula()) {
terminalStates = formula.asAtomicLabelFormula().getLabel();
} else if (formula.isEventuallyFormula()) {
storm::logic::Formula const& sub = formula.asEventuallyFormula().getSubformula();
if (sub.isAtomicExpressionFormula() || sub.isAtomicLabelFormula()) {
this->setTerminalStatesFromFormula(sub);
}
} else if (formula.isUntilFormula()) {
storm::logic::Formula const& right = formula.asUntilFormula().getRightSubformula();
if (right.isAtomicExpressionFormula() || right.isAtomicLabelFormula()) {
this->setTerminalStatesFromFormula(right);
}
storm::logic::Formula const& left = formula.asUntilFormula().getLeftSubformula();
if (left.isAtomicExpressionFormula()) {
negatedTerminalStates = left.asAtomicExpressionFormula().getExpression();
} else if (left.isAtomicLabelFormula()) {
negatedTerminalStates = left.asAtomicLabelFormula().getLabel();
}
} else if (formula.isProbabilityOperatorFormula()) {
storm::logic::Formula const& sub = formula.asProbabilityOperatorFormula().getSubformula();
if (sub.isEventuallyFormula() || sub.isUntilFormula()) {
this->setTerminalStatesFromFormula(sub);
}
}
terminalStates = getTerminalStatesFromFormula(formula);
}
template <storm::dd::DdType Type, typename ValueType>
@ -1351,52 +1321,18 @@ namespace storm {
// If we were asked to treat some states as terminal states, we cut away their transitions now.
storm::dd::Bdd<Type> terminalStatesBdd = generationInfo.manager->getBddZero();
if (options.terminalStates || options.negatedTerminalStates) {
std::map<storm::expressions::Variable, storm::expressions::Expression> constantsSubstitution = program.getConstantsSubstitution();
if (options.terminalStates) {
storm::expressions::Expression terminalExpression;
if (options.terminalStates.get().type() == typeid(storm::expressions::Expression)) {
terminalExpression = boost::get<storm::expressions::Expression>(options.terminalStates.get());
} else {
std::string const& labelName = boost::get<std::string>(options.terminalStates.get());
if (!options.terminalStates.empty()) {
storm::expressions::Expression terminalExpression = options.terminalStates.asExpression([&program](std::string const& labelName) {
if (program.hasLabel(labelName)) {
terminalExpression = program.getLabelExpression(labelName);
return program.getLabelExpression(labelName);
} else {
STORM_LOG_THROW(labelName == "init" || labelName == "deadlock", storm::exceptions::InvalidArgumentException, "Terminal states refer to illegal label '" << labelName << "'.");
// If the label name is "init" we can abort 'exploration' directly at the initial state. If it is deadlock, we do not have to abort.
return program.getManager().boolean(labelName == "init");
}
}
if (terminalExpression.isInitialized()) {
// If the expression refers to constants of the model, we need to substitute them.
terminalExpression = terminalExpression.substitute(constantsSubstitution);
STORM_LOG_TRACE("Making the states satisfying " << terminalExpression << " terminal.");
terminalStatesBdd = generationInfo.rowExpressionAdapter->translateExpression(terminalExpression).toBdd();
}
}
if (options.negatedTerminalStates) {
storm::expressions::Expression negatedTerminalExpression;
if (options.negatedTerminalStates.get().type() == typeid(storm::expressions::Expression)) {
negatedTerminalExpression = boost::get<storm::expressions::Expression>(options.negatedTerminalStates.get());
} else {
std::string const& labelName = boost::get<std::string>(options.negatedTerminalStates.get());
if (program.hasLabel(labelName)) {
negatedTerminalExpression = program.getLabelExpression(labelName);
} else {
STORM_LOG_THROW(labelName == "init" || labelName == "deadlock", storm::exceptions::InvalidArgumentException, "Terminal states refer to illegal label '" << labelName << "'.");
}
}
if (negatedTerminalExpression.isInitialized()) {
// If the expression refers to constants of the model, we need to substitute them.
negatedTerminalExpression = negatedTerminalExpression.substitute(constantsSubstitution);
STORM_LOG_TRACE("Making the states *not* satisfying " << negatedTerminalExpression << " terminal.");
terminalStatesBdd |= !generationInfo.rowExpressionAdapter->translateExpression(negatedTerminalExpression).toBdd();
}
}
});
terminalExpression = terminalExpression.substitute(program.getConstantsSubstitution());
terminalStatesBdd = generationInfo.rowExpressionAdapter->translateExpression(terminalExpression).toBdd();
transitionMatrix *= (!terminalStatesBdd).template toAdd<ValueType>();
}

10
src/storm/builder/DdPrismModelBuilder.h

@ -7,6 +7,8 @@
#include "storm/storage/prism/Program.h"
#include "storm/builder/TerminalStatesGetter.h"
#include "storm/logic/Formulas.h"
#include "storm/adapters/AddExpressionAdapter.h"
#include "storm/utility/macros.h"
@ -81,13 +83,9 @@ namespace storm {
// An optional set of labels that, if given, restricts the labels that are built.
boost::optional<std::set<std::string>> labelsToBuild;
// An optional expression or label that (a subset of) characterizes the terminal states of the model.
// An optional set of expression or labels that characterizes (a subset of) the terminal states of the model.
// If this is set, the outgoing transitions of these states are replaced with a self-loop.
boost::optional<boost::variant<storm::expressions::Expression, std::string>> terminalStates;
// An optional expression or label whose negation characterizes (a subset of) the terminal states of the
// model. If this is set, the outgoing transitions of these states are replaced with a self-loop.
boost::optional<boost::variant<storm::expressions::Expression, std::string>> negatedTerminalStates;
storm::builder::TerminalStates terminalStates;
};
/*!

101
src/storm/builder/TerminalStatesGetter.cpp

@ -0,0 +1,101 @@
#include "storm/builder/TerminalStatesGetter.h"
#include "storm/storage/expressions/Expression.h"
#include "storm/logic/Formulas.h"
namespace storm {
namespace builder {
void getTerminalStatesFromFormula(storm::logic::Formula const& formula, std::function<void(storm::expressions::Expression const&, bool)> const& terminalExpressionCallback, std::function<void(std::string const&, bool)> const& terminalLabelCallback) {
if (formula.isAtomicExpressionFormula()) {
terminalExpressionCallback(formula.asAtomicExpressionFormula().getExpression(), true);
} else if (formula.isAtomicLabelFormula()) {
terminalLabelCallback(formula.asAtomicLabelFormula().getLabel(), true);
} else if (formula.isEventuallyFormula()) {
storm::logic::Formula const& sub = formula.asEventuallyFormula().getSubformula();
if (sub.isAtomicExpressionFormula() || sub.isAtomicLabelFormula()) {
getTerminalStatesFromFormula(sub, terminalExpressionCallback, terminalLabelCallback);
}
} else if (formula.isUntilFormula()) {
storm::logic::Formula const& right = formula.asUntilFormula().getRightSubformula();
if (right.isAtomicExpressionFormula() || right.isAtomicLabelFormula()) {
getTerminalStatesFromFormula(right, terminalExpressionCallback, terminalLabelCallback);
}
storm::logic::Formula const& left = formula.asUntilFormula().getLeftSubformula();
if (left.isAtomicExpressionFormula()) {
terminalExpressionCallback(left.asAtomicExpressionFormula().getExpression(), false);
} else if (left.isAtomicLabelFormula()) {
terminalLabelCallback(left.asAtomicLabelFormula().getLabel(), false);
}
} else if (formula.isBoundedUntilFormula()) {
storm::logic::BoundedUntilFormula const& boundedUntil = formula.asBoundedUntilFormula();
bool hasLowerBound = false;
for (uint64_t i = 0; i < boundedUntil.getDimension(); ++i) {
if (boundedUntil.hasLowerBound(i) && (boundedUntil.getLowerBound(i).containsVariables() || !storm::utility::isZero(boundedUntil.getLowerBound(i).evaluateAsRational()))) {
hasLowerBound = true;
break;
}
}
if (!hasLowerBound) {
storm::logic::Formula const& right = boundedUntil.getRightSubformula();
if (right.isAtomicExpressionFormula() || right.isAtomicLabelFormula()) {
getTerminalStatesFromFormula(right, terminalExpressionCallback, terminalLabelCallback);
}
}
storm::logic::Formula const& left = boundedUntil.getLeftSubformula();
if (left.isAtomicExpressionFormula()) {
terminalExpressionCallback(left.asAtomicExpressionFormula().getExpression(), false);
} else if (left.isAtomicLabelFormula()) {
terminalLabelCallback(left.asAtomicLabelFormula().getLabel(), false);
}
} else if (formula.isProbabilityOperatorFormula()) {
storm::logic::Formula const& sub = formula.asProbabilityOperatorFormula().getSubformula();
if (sub.isEventuallyFormula() || sub.isUntilFormula() || sub.isBoundedUntilFormula()) {
getTerminalStatesFromFormula(sub, terminalExpressionCallback, terminalLabelCallback);
}
} else if (formula.isRewardOperatorFormula() || formula.isTimeOperatorFormula()) {
storm::logic::Formula const& sub = formula.asOperatorFormula().getSubformula();
if (sub.isEventuallyFormula()) {
getTerminalStatesFromFormula(sub, terminalExpressionCallback, terminalLabelCallback);
}
}
}
void TerminalStates::clear() {
terminalExpressions.clear();
negatedTerminalExpressions.clear();
terminalLabels.clear();
negatedTerminalLabels.clear();
}
bool TerminalStates::empty() const {
return terminalExpressions.empty() && negatedTerminalExpressions.empty() && terminalLabels.empty() && negatedTerminalLabels.empty();
}
storm::expressions::Expression TerminalStates::asExpression(std::function<storm::expressions::Expression(std::string const&)> const& labelToExpressionMap) const {
auto allTerminalExpressions = terminalExpressions;
for (auto const& e : negatedTerminalExpressions) {
allTerminalExpressions.push_back(!e);
}
for (auto const& l : terminalLabels) {
allTerminalExpressions.push_back(labelToExpressionMap(l));
}
for (auto const& l : negatedTerminalLabels) {
allTerminalExpressions.push_back(!labelToExpressionMap(l));
}
STORM_LOG_ASSERT(!allTerminalExpressions.empty(), "Unable to convert empty terminal state set to expression");
return storm::expressions::disjunction(allTerminalExpressions);
}
TerminalStates getTerminalStatesFromFormula(storm::logic::Formula const& formula) {
TerminalStates result;
getTerminalStatesFromFormula(formula, [&result](storm::expressions::Expression const& expr, bool inverted){ if(inverted) { result.terminalExpressions.push_back(expr);} else {result.negatedTerminalExpressions.push_back(expr);} },
[&result](std::string const& label, bool inverted){ if(inverted) { result.terminalLabels.push_back(label);} else {result.negatedTerminalLabels.push_back(label);} });
return result;
}
}
}

58
src/storm/builder/TerminalStatesGetter.h

@ -0,0 +1,58 @@
#pragma once
#include <functional>
#include <string>
#include <vector>
namespace storm {
namespace expressions {
class Expression;
}
namespace logic {
class Formula;
}
namespace builder {
/*!
* Traverses the formula. If an expression (or label) is found such that checking the formula does not require further exploration from a state
* satisfying (or violating) the expression (or label), the corresponding callback function is called.
* @param formula The formula to analyzed
* @param terminalExpressionCallback called on terminal expressions. The corresponding flag indicates whether exploration can stop from states satisfying (true) or violating (false) the expression
* @param terminalLabelCallback called on terminal labels. The corresponding flag indicates whether exploration can stop from states having (true) or not having (false) the label
*/
void getTerminalStatesFromFormula(storm::logic::Formula const& formula, std::function<void(storm::expressions::Expression const&, bool)> const& terminalExpressionCallback, std::function<void(std::string const&, bool)> const& terminalLabelCallback);
struct TerminalStates {
std::vector<storm::expressions::Expression> terminalExpressions; // if one of these is true, we can stop exploration
std::vector<storm::expressions::Expression> negatedTerminalExpressions; // if one of these is false, we can stop exploration
std::vector<std::string> terminalLabels; // if a state has one of these labels, we can stop exploration
std::vector<std::string> negatedTerminalLabels; // if a state does not have all of these labels, we can stop exploration
/*!
* Clears all terminal states. After calling this, empty() holds.
*/
void clear();
/*!
* True if no terminal states are specified
*/
bool empty() const;
/*!
* Returns an expression that evaluates to true only if the exploration can stop at the corresponding state
* Should only be called if this is not empty.
*/
storm::expressions::Expression asExpression(std::function<storm::expressions::Expression(std::string const&)> const& labelToExpressionMap) const;
};
/*!
* Traverses the formula. If an expression (or label) is found such that checking the formula does not require further exploration from a state
* satisfying (or violating) the expression (or label), it is inserted into the returned struct.
*/
TerminalStates getTerminalStatesFromFormula(storm::logic::Formula const& formula);
}
}

2
src/storm/settings/SettingsManager.cpp

@ -539,7 +539,7 @@ namespace storm {
bool globalScope = true;
std::string activeModule = "";
uint_fast64_t lineNumber = 1;
for (std::string line; getline(input, line); ++lineNumber) {
for (std::string line; storm::utility::getline(input, line); ++lineNumber) {
// If the first character of the line is a "[", we expect the settings of a new module to start and
// the line to be of the shape [<module>].
if (line.at(0) == '[') {

12
src/storm/settings/modules/BuildSettings.cpp

@ -29,7 +29,9 @@ namespace storm {
const std::string dontFixDeadlockOptionShortName = "ndl";
const std::string noBuildOptionName = "nobuild";
const std::string fullModelBuildOptionName = "buildfull";
const std::string applyNoMaxProgAssumptionOptionName = "nomaxprog";
const std::string buildChoiceLabelOptionName = "buildchoicelab";
const std::string buildChoiceOriginsOptionName = "buildchoiceorig";
const std::string buildStateValuationsOptionName = "buildstateval";
const std::string buildOutOfBoundsStateOptionName = "buildoutofboundsstate";
const std::string bitsForUnboundedVariablesOptionName = "int-bits";
@ -40,7 +42,9 @@ namespace storm {
this->addOption(storm::settings::OptionBuilder(moduleName, dontFixDeadlockOptionName, false, "If the model contains deadlock states, they need to be fixed by setting this option.").setShortName(dontFixDeadlockOptionShortName).setIsAdvanced().build());
this->addOption(storm::settings::OptionBuilder(moduleName, jitOptionName, false, "If set, the model is built using the JIT model builder.").build());
this->addOption(storm::settings::OptionBuilder(moduleName, fullModelBuildOptionName, false, "If set, include all rewards and labels.").build());
this->addOption(storm::settings::OptionBuilder(moduleName, applyNoMaxProgAssumptionOptionName, false, "If set, the maximum progress assumption is not applied while building the model (relevant for MAs)").setIsAdvanced().build());
this->addOption(storm::settings::OptionBuilder(moduleName, buildChoiceLabelOptionName, false, "If set, also build the choice labels").setIsAdvanced().build());
this->addOption(storm::settings::OptionBuilder(moduleName, buildChoiceOriginsOptionName, false, "If set, also build information that for each choice indicates the part(s) of the input that yielded the choice.").setIsAdvanced().build());
this->addOption(storm::settings::OptionBuilder(moduleName, buildStateValuationsOptionName, false, "If set, also build the state valuations").setIsAdvanced().build());
this->addOption(storm::settings::OptionBuilder(moduleName, noBuildOptionName, false, "If set, do not build the model.").setIsAdvanced().build());
@ -81,9 +85,17 @@ namespace storm {
return this->getOption(noBuildOptionName).getHasOptionBeenSet();
}
bool BuildSettings::isApplyNoMaximumProgressAssumptionSet() const {
return this->getOption(applyNoMaxProgAssumptionOptionName).getHasOptionBeenSet();
}
bool BuildSettings::isBuildChoiceLabelsSet() const {
return this->getOption(buildChoiceLabelOptionName).getHasOptionBeenSet();
}
bool BuildSettings::isBuildChoiceOriginsSet() const {
return this->getOption(buildChoiceOriginsOptionName).getHasOptionBeenSet();
}
bool BuildSettings::isBuildStateValuationsSet() const {
return this->getOption(buildStateValuationsOptionName).getHasOptionBeenSet();

13
src/storm/settings/modules/BuildSettings.h

@ -78,12 +78,21 @@ namespace storm {
* @return true iff the full model should be build.
*/
bool isBuildFullModelSet() const;
/*!
* Retrieves whether the maximum progress assumption is to be applied when building the model
*/
bool isApplyNoMaximumProgressAssumptionSet() const;
/*!
* Retrieves whether the choice labels should be build
* @return
*/
bool isBuildChoiceLabelsSet() const;
/*!
* Retrieves whether the choice origins should be build
*/
bool isBuildChoiceOriginsSet() const;
/*!
* Retrieves whether the choice labels should be build

4
src/storm/settings/modules/IOSettings.cpp

@ -97,8 +97,8 @@ namespace storm {
this->addOption(storm::settings::OptionBuilder(moduleName, qvbsInputOptionName, false, "Selects a model from the Quantitative Verification Benchmark Set.").setShortName(qvbsInputOptionShortName)
.addArgument(storm::settings::ArgumentBuilder::createStringArgument("model", "The short model name as in the benchmark set.").build())
.addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("instance-index", "The selected instance of this model.").setDefaultValueUnsignedInteger(0).build())
.addArgument(storm::settings::ArgumentBuilder::createStringArgument("filter", "The comma separated list of property names to check. Omit to check all, \"\" to check none.").setDefaultValueString("").build())
.addArgument(storm::settings::ArgumentBuilder::createUnsignedIntegerArgument("instance-index", "The selected instance of this model.").setDefaultValueUnsignedInteger(0).makeOptional().build())
.addArgument(storm::settings::ArgumentBuilder::createStringArgument("filter", "The comma separated list of property names to check. Omit to check all, \"\" to check none.").setDefaultValueString("").makeOptional().build())
.build());
#ifdef STORM_HAVE_QVBS
std::string qvbsRootDefault = STORM_QVBS_ROOT;

1
src/storm/solver/IterativeMinMaxLinearEquationSolver.cpp

@ -424,6 +424,7 @@ namespace storm {
auto oldValueIt = oldValues.begin();
for (auto value : relevantValues) {
result = storm::utility::max<ValueType>(result, storm::utility::abs<ValueType>(allValues[value] - *oldValueIt));
++oldValueIt;
}
return result;
}

2
src/storm/storage/dd/cudd/InternalCuddAdd.cpp

@ -596,6 +596,8 @@ namespace storm {
splitIntoGroupsRec(dd, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel);
splitIntoGroupsRec(dd, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel);
} else {
// FIXME: We first traverse the else successor (unlike other variants of this method).
// Otherwise, the GameBasedMdpModelCheckerTest would not terminate. See github issue #64
splitIntoGroupsRec(Cudd_E(dd), groups, ddGroupVariableIndices, currentLevel + 1, maxLevel);
splitIntoGroupsRec(Cudd_T(dd), groups, ddGroupVariableIndices, currentLevel + 1, maxLevel);
}

2
src/storm/storage/dd/sylvan/InternalSylvanAdd.cpp

@ -1007,6 +1007,8 @@ namespace storm {
bool elseComplemented = mtbdd_hascomp(elseDdNode) ^ negated;
bool thenComplemented = mtbdd_hascomp(thenDdNode) ^ negated;
// FIXME: We first traverse the else successor (unlike other variants of this method).
// Otherwise, the GameBasedMdpModelCheckerTest would not terminate. See github issue #64
splitIntoGroupsRec(mtbdd_regular(elseDdNode), elseComplemented, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel);
splitIntoGroupsRec(mtbdd_regular(thenDdNode), thenComplemented, groups, ddGroupVariableIndices, currentLevel + 1, maxLevel);
}

23
src/storm/utility/file.h

@ -70,5 +70,28 @@ namespace storm {
return filestream.good();
}
/*!
* Overloaded getline function which handles different types of newline (\n and \r).
* @param input Input stream.
* @param str Output string.
* @return Remaining stream.
*/
template<class CharT, class Traits, class Allocator>
inline std::basic_istream<CharT, Traits>& getline(std::basic_istream<CharT, Traits>& input, std::basic_string<CharT, Traits, Allocator>& str) {
auto& res = std::getline(input, str);
// Remove linebreaks
std::string::reverse_iterator rit = str.rbegin();
while (rit != str.rend()) {
if (*rit == '\r' || *rit == '\n') {
++rit;
str.pop_back();
} else {
break;
}
}
return res;
}
}
}

8
src/test/storm/storage/SparseMatrixTest.cpp

@ -710,12 +710,12 @@ TEST(SparseMatrix, Permute) {
std::vector<uint64_t> inversePermutation = {1,4,0,3,2};
storm::storage::SparseMatrix<double> matrixperm = matrix.permuteRows(inversePermutation);
EXPECT_EQ(5, matrixperm.getRowCount());
EXPECT_EQ(4, matrixperm.getColumnCount());
EXPECT_EQ(8, matrixperm.getEntryCount());
EXPECT_EQ(5ul, matrixperm.getRowCount());
EXPECT_EQ(4ul, matrixperm.getColumnCount());
EXPECT_EQ(8ul, matrixperm.getEntryCount());
EXPECT_EQ(matrix.getRowSum(1), matrixperm.getRowSum(0));
EXPECT_EQ(matrix.getRowSum(4), matrixperm.getRowSum(1));
EXPECT_EQ(matrix.getRowSum(0), matrixperm.getRowSum(2));
EXPECT_EQ(matrix.getRowSum(3), matrixperm.getRowSum(3));
EXPECT_EQ(matrix.getRowSum(2), matrixperm.getRowSum(4));
}
}

24
src/test/storm/utility/FileTest.cpp

@ -0,0 +1,24 @@
#include "test/storm_gtest.h"
#include "storm-config.h"
#include "storm/utility/file.h"
TEST(FileTest, GetLine) {
std::stringstream stream;
stream << "Hello world" << std::endl << "This is a test with n\nThis is a test with rn\r\n\nMore tests";
std::string str;
int i = 0;
std::string expected[] = {"Hello world", "This is a test with n", "This is a test with rn", "", "More tests"};
while (storm::utility::getline(stream, str)) {
EXPECT_EQ(str, expected[i]);
++i;
}
}
TEST(FileTest, GetLineEmpty) {
std::stringstream stream;
std::string str;
EXPECT_FALSE(storm::utility::getline(stream, str));
}
Loading…
Cancel
Save