Browse Source

more work on tearing PRISM-specific functionality out of the explicit model builder

Former-commit-id: a835c9072e
tempestpy_adaptions
dehnert 9 years ago
parent
commit
ddf165d4d3
  1. 177
      src/builder/ExplicitModelBuilder.cpp
  2. 9
      src/builder/ExplicitModelBuilder.h
  3. 2
      src/cli/entrypoints.h
  4. 40
      src/generator/NextStateGenerator.cpp
  5. 49
      src/generator/NextStateGenerator.h
  6. 75
      src/generator/PrismNextStateGenerator.cpp
  7. 15
      src/generator/PrismNextStateGenerator.h
  8. 4
      src/modelchecker/exploration/SparseExplorationModelChecker.cpp
  9. 3
      src/modelchecker/exploration/SparseExplorationModelChecker.h
  10. 2
      src/modelchecker/exploration/StateGeneration.cpp
  11. 2
      src/modelchecker/exploration/StateGeneration.h
  12. 2
      src/storage/BitVectorHashMap.h
  13. 41
      src/utility/prism.cpp
  14. 7
      src/utility/prism.h
  15. 28
      src/utility/storm.h

177
src/builder/ExplicitModelBuilder.cpp

@ -30,21 +30,21 @@ namespace storm {
* A structure that is used to keep track of a reward model currently being built.
*/
template <typename ValueType>
struct RewardModelBuilder {
class RewardModelBuilder {
public:
RewardModelBuilder(std::string const& rewardModelName) : rewardModelName(rewardModelName), stateRewardVector(), stateActionRewardVector() {
// Intentionally left empty.
RewardModelBuilder(storm::generator::RewardModelInformation const& rewardModelInformation) : rewardModelName(rewardModelInformation.getName()), stateRewards(rewardModelInformation.hasStateRewards()), stateRewardVector(), stateActionRewards(rewardModelInformation.hasStateActionRewards()), stateActionRewardVector() {
STORM_LOG_THROW(!rewardModelInformation.hasTransitionRewards(), storm::exceptions::InvalidArgumentException, "Unable to treat transition rewards.");
}
storm::models::sparse::StandardRewardModel<ValueType> build(uint_fast64_t rowCount, uint_fast64_t columnCount, uint_fast64_t rowGroupCount) {
boost::optional<std::vector<ValueType>> optionalStateRewardVector;
if (!stateRewardVector.empty()) {
if (hasStateRewards()) {
stateRewardVector.resize(rowGroupCount);
optionalStateRewardVector = std::move(stateRewardVector);
}
boost::optional<std::vector<ValueType>> optionalStateActionRewardVector;
if (!stateActionRewardVector.empty()) {
if (hasStateActionRewards()) {
stateActionRewardVector.resize(rowCount);
optionalStateActionRewardVector = std::move(stateActionRewardVector);
}
@ -52,8 +52,32 @@ namespace storm {
return storm::models::sparse::StandardRewardModel<ValueType>(std::move(optionalStateRewardVector), std::move(optionalStateActionRewardVector));
}
std::string const& getName() const {
return rewardModelName;
}
void addStateReward(ValueType const& value) {
stateRewardVector.push_back(value);
}
void addStateActionReward(ValueType const& value) {
stateActionRewardVector.push_back(value);
}
bool hasStateRewards() const {
return stateRewards;
}
bool hasStateActionRewards() const {
return stateActionRewards;
}
private:
std::string rewardModelName;
bool stateRewards;
bool stateActionRewards;
// The state reward vector.
std::vector<ValueType> stateRewardVector;
@ -72,7 +96,7 @@ namespace storm {
}
template <typename ValueType, typename RewardModelType, typename StateType>
ExplicitModelBuilder<ValueType, RewardModelType, StateType>::ExplicitModelBuilder(storm::prism::Program const& program, Options const& options) : program(storm::utility::prism::preprocessProgram<ValueType>(program, options.constantDefinitions, !options.buildAllLabels ? options.labelsToBuild : boost::none, options.expressionLabels)), options(options), variableInformation(this->program), stateStorage(variableInformation.getTotalBitOffset(true)) {
ExplicitModelBuilder<ValueType, RewardModelType, StateType>::ExplicitModelBuilder(std::shared_ptr<storm::generator::NextStateGenerator<ValueType, StateType>> const& generator, Options const& options) : generator(generator), options(options), stateStorage(generator->getStateSize()) {
// Intentionally left empty.
}
@ -84,39 +108,18 @@ namespace storm {
template <typename ValueType, typename RewardModelType, typename StateType>
std::shared_ptr<storm::models::sparse::Model<ValueType, RewardModelType>> ExplicitModelBuilder<ValueType, RewardModelType, StateType>::translate() {
STORM_LOG_DEBUG("Building representation of program:" << std::endl << program << std::endl);
STORM_LOG_DEBUG("Exploration order is: " << options.explorationOrder);
// First, we make sure that all selected reward models actually exist.
for (auto const& rewardModelName : options.rewardModelsToBuild) {
STORM_LOG_THROW(rewardModelName.empty() || program.hasRewardModel(rewardModelName), storm::exceptions::InvalidArgumentException, "Model does not possess a reward model with the name '" << rewardModelName << "'.");
}
std::vector<std::string> selectedRewardModels;
if (options.buildAllRewardModels) {
// for (auto const& rewardModel : program.getRewardModels()) {
// selectedRewardModels.push_back(rewardModel);
// }
} else {
selectedRewardModels = std::vector<std::string>(options.rewardModelsToBuild.begin(), options.rewardModelsToBuild.end());
}
// // If no reward model was selected until now and a referenced reward model appears to be unique, we build
// // the only existing reward model (given that no explicit name was given for the referenced reward model).
// if (selectedRewardModels.empty() && program.getNumberOfRewardModels() == 1 && options.rewardModelsToBuild.size() == 1 && *options.rewardModelsToBuild.begin() == "") {
// selectedRewardModels.push_back(program.getRewardModel(0));
// }
ModelComponents modelComponents = buildModelComponents(selectedRewardModels);
ModelComponents modelComponents = buildModelComponents();
std::shared_ptr<storm::models::sparse::Model<ValueType, RewardModelType>> result;
switch (program.getModelType()) {
case storm::prism::Program::ModelType::DTMC:
switch (generator->getModelType()) {
case storm::generator::ModelType::DTMC:
result = std::shared_ptr<storm::models::sparse::Model<ValueType, RewardModelType>>(new storm::models::sparse::Dtmc<ValueType, RewardModelType>(std::move(modelComponents.transitionMatrix), std::move(modelComponents.stateLabeling), std::move(modelComponents.rewardModels), std::move(modelComponents.choiceLabeling)));
break;
case storm::prism::Program::ModelType::CTMC:
case storm::generator::ModelType::CTMC:
result = std::shared_ptr<storm::models::sparse::Model<ValueType, RewardModelType>>(new storm::models::sparse::Ctmc<ValueType, RewardModelType>(std::move(modelComponents.transitionMatrix), std::move(modelComponents.stateLabeling), std::move(modelComponents.rewardModels), std::move(modelComponents.choiceLabeling)));
break;
case storm::prism::Program::ModelType::MDP:
case storm::generator::ModelType::MDP:
result = std::shared_ptr<storm::models::sparse::Model<ValueType, RewardModelType>>(new storm::models::sparse::Mdp<ValueType, RewardModelType>(std::move(modelComponents.transitionMatrix), std::move(modelComponents.stateLabeling), std::move(modelComponents.rewardModels), std::move(modelComponents.choiceLabeling)));
break;
default:
@ -151,22 +154,13 @@ namespace storm {
}
template <typename ValueType, typename RewardModelType, typename StateType>
boost::optional<std::vector<boost::container::flat_set<uint_fast64_t>>> ExplicitModelBuilder<ValueType, RewardModelType, StateType>::buildMatrices(std::vector<std::reference_wrapper<storm::prism::RewardModel const>> const& selectedRewardModels, storm::storage::SparseMatrixBuilder<ValueType>& transitionMatrixBuilder, std::vector<RewardModelBuilder<typename RewardModelType::ValueType>>& rewardModelBuilders, boost::optional<storm::expressions::Expression> const& terminalExpression) {
boost::optional<std::vector<boost::container::flat_set<uint_fast64_t>>> ExplicitModelBuilder<ValueType, RewardModelType, StateType>::buildMatrices(storm::storage::SparseMatrixBuilder<ValueType>& transitionMatrixBuilder, std::vector<RewardModelBuilder<typename RewardModelType::ValueType>>& rewardModelBuilders) {
// Create choice labels, if requested,
boost::optional<std::vector<boost::container::flat_set<uint_fast64_t>>> choiceLabels;
if (options.buildCommandLabels) {
if (generator->getOptions().isBuildChoiceLabelsSet()) {
choiceLabels = std::vector<boost::container::flat_set<uint_fast64_t>>();
}
// Create a generator that is able to expand states.
storm::generator::PrismNextStateGenerator<ValueType, StateType> generator(program, variableInformation, options.buildCommandLabels);
if (terminalExpression) {
generator.setTerminalExpression(terminalExpression.get());
}
for (auto const& rewardModel : selectedRewardModels) {
generator.addRewardModel(rewardModel.get());
}
// Create a callback for the next-state generator to enable it to request the index of states.
std::function<StateType (CompressedState const&)> stateToIdCallback = std::bind(&ExplicitModelBuilder<ValueType, RewardModelType, StateType>::getOrAddStateIndex, this, std::placeholders::_1);
@ -178,7 +172,7 @@ namespace storm {
}
// Let the generator create all initial states.
this->stateStorage.initialStateIndices = generator.getInitialStates(stateToIdCallback);
this->stateStorage.initialStateIndices = generator->getInitialStates(stateToIdCallback);
// Now explore the current state until there is no more reachable state.
uint_fast64_t currentRowGroup = 0;
@ -199,62 +193,56 @@ namespace storm {
STORM_LOG_TRACE("Exploring state with id " << currentIndex << ".");
generator.load(currentState);
storm::generator::StateBehavior<ValueType, StateType> behavior = generator.expand(stateToIdCallback);
generator->load(currentState);
storm::generator::StateBehavior<ValueType, StateType> behavior = generator->expand(stateToIdCallback);
// If there is no behavior, we might have to introduce a self-loop.
if (behavior.empty()) {
if (!storm::settings::getModule<storm::settings::modules::MarkovChainSettings>().isDontFixDeadlocksSet() || !behavior.wasExpanded()) {
if (options.buildCommandLabels) {
if (generator->getOptions().isBuildChoiceLabelsSet()) {
// Insert empty choice labeling for added self-loop transitions.
choiceLabels.get().push_back(boost::container::flat_set<uint_fast64_t>());
}
if (!generator.isDeterministicModel()) {
if (!generator->isDeterministicModel()) {
transitionMatrixBuilder.newRowGroup(currentRow);
}
transitionMatrixBuilder.addNextValue(currentRow, currentIndex, storm::utility::one<ValueType>());
auto builderIt = rewardModelBuilders.begin();
for (auto const& rewardModel : selectedRewardModels) {
if (rewardModel.get().hasStateRewards()) {
builderIt->stateRewardVector.push_back(storm::utility::zero<ValueType>());
for (auto& rewardModelBuilder : rewardModelBuilders) {
if (rewardModelBuilder.hasStateRewards()) {
rewardModelBuilder.addStateReward(storm::utility::zero<ValueType>());
}
if (rewardModel.get().hasStateActionRewards()) {
builderIt->stateActionRewardVector.push_back(storm::utility::zero<ValueType>());
if (rewardModelBuilder.hasStateActionRewards()) {
rewardModelBuilder.addStateActionReward(storm::utility::zero<ValueType>());
}
++builderIt;
}
++currentRow;
++currentRowGroup;
} else {
std::cout << storm::generator::unpackStateIntoValuation(currentState, variableInformation, program.getManager()).toString(true) << std::endl;
STORM_LOG_THROW(false, storm::exceptions::WrongFormatException,
"Error while creating sparse matrix from probabilistic program: found deadlock state. For fixing these, please provide the appropriate option.");
STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Error while creating sparse matrix from probabilistic program: found deadlock state (" << generator->toValuation(currentState).toString(true) << "). For fixing these, please provide the appropriate option.");
}
} else {
// Add the state rewards to the corresponding reward models.
auto builderIt = rewardModelBuilders.begin();
auto stateRewardIt = behavior.getStateRewards().begin();
for (auto const& rewardModel : selectedRewardModels) {
if (rewardModel.get().hasStateRewards()) {
builderIt->stateRewardVector.push_back(*stateRewardIt);
for (auto& rewardModelBuilder : rewardModelBuilders) {
if (rewardModelBuilder.hasStateRewards()) {
rewardModelBuilder.addStateReward(*stateRewardIt);
}
++stateRewardIt;
++builderIt;
}
// If the model is nondeterministic, we need to open a row group.
if (!generator.isDeterministicModel()) {
if (!generator->isDeterministicModel()) {
transitionMatrixBuilder.newRowGroup(currentRow);
}
// Now add all choices.
for (auto const& choice : behavior) {
// Add command labels if requested.
if (options.buildCommandLabels) {
if (generator->getOptions().isBuildChoiceLabelsSet()) {
choiceLabels.get().push_back(choice.getChoiceLabels());
}
@ -264,14 +252,12 @@ namespace storm {
}
// Add the rewards to the reward models.
auto builderIt = rewardModelBuilders.begin();
auto choiceRewardIt = choice.getChoiceRewards().begin();
for (auto const& rewardModel : selectedRewardModels) {
if (rewardModel.get().hasStateActionRewards()) {
builderIt->stateActionRewardVector.push_back(*choiceRewardIt);
for (auto& rewardModelBuilder : rewardModelBuilders) {
if (rewardModelBuilder.hasStateActionRewards()) {
rewardModelBuilder.addStateActionReward(*choiceRewardIt);
}
++choiceRewardIt;
++builderIt;
}
++currentRow;
}
@ -307,58 +293,26 @@ namespace storm {
}
template <typename ValueType, typename RewardModelType, typename StateType>
typename ExplicitModelBuilder<ValueType, RewardModelType, StateType>::ModelComponents ExplicitModelBuilder<ValueType, RewardModelType, StateType>::buildModelComponents(std::vector<std::string> const& selectedRewardModels) {
typename ExplicitModelBuilder<ValueType, RewardModelType, StateType>::ModelComponents ExplicitModelBuilder<ValueType, RewardModelType, StateType>::buildModelComponents() {
ModelComponents modelComponents;
// Determine whether we have to combine different choices to one or whether this model can have more than
// one choice per state.
bool deterministicModel = program.isDeterministicModel();
bool deterministicModel = generator->isDeterministicModel();
// Prepare the transition matrix builder and the reward model builders.
storm::storage::SparseMatrixBuilder<ValueType> transitionMatrixBuilder(0, 0, 0, false, !deterministicModel, 0);
std::vector<RewardModelBuilder<typename RewardModelType::ValueType>> rewardModelBuilders;
for (auto const& rewardModelName : selectedRewardModels) {
rewardModelBuilders.emplace_back(rewardModelName);
}
// If we were asked to treat some states as terminal states, we determine an expression characterizing the
// terminal states of the model that we pass on to the matrix building routine.
boost::optional<storm::expressions::Expression> terminalExpression;
if (options.terminalStates) {
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());
terminalExpression = program.getLabelExpression(labelName);
}
}
if (options.negatedTerminalStates) {
if (options.negatedTerminalStates.get().type() == typeid(storm::expressions::Expression)) {
if (terminalExpression) {
terminalExpression = terminalExpression.get() || !boost::get<storm::expressions::Expression>(options.negatedTerminalStates.get());
} else {
terminalExpression = !boost::get<storm::expressions::Expression>(options.negatedTerminalStates.get());
}
} else {
std::string const& labelName = boost::get<std::string>(options.negatedTerminalStates.get());
if (terminalExpression) {
terminalExpression = terminalExpression.get() || !program.getLabelExpression(labelName);
} else {
terminalExpression = !program.getLabelExpression(labelName);
}
}
}
if (terminalExpression) {
STORM_LOG_TRACE("Making the states satisfying " << terminalExpression.get() << " terminal.");
for (uint64_t i = 0; i < generator->getNumberOfRewardModels(); ++i) {
rewardModelBuilders.emplace_back(generator->getRewardModelInformation(i));
}
modelComponents.choiceLabeling = buildMatrices(selectedRewardModels, transitionMatrixBuilder, rewardModelBuilders, terminalExpression);
modelComponents.choiceLabeling = buildMatrices(transitionMatrixBuilder, rewardModelBuilders);
modelComponents.transitionMatrix = transitionMatrixBuilder.build();
// Now finalize all reward models.
auto builderIt = rewardModelBuilders.begin();
for (auto rewardModelIt = selectedRewardModels.begin(), rewardModelIte = selectedRewardModels.end(); rewardModelIt != rewardModelIte; ++rewardModelIt, ++builderIt) {
modelComponents.rewardModels.emplace(rewardModelIt->get().getName(), builderIt->build(modelComponents.transitionMatrix.getRowCount(), modelComponents.transitionMatrix.getColumnCount(), modelComponents.transitionMatrix.getRowGroupCount()));
for (auto& rewardModelBuilder : rewardModelBuilders) {
modelComponents.rewardModels.emplace(rewardModelBuilder.getName(), rewardModelBuilder.build(modelComponents.transitionMatrix.getRowCount(), modelComponents.transitionMatrix.getColumnCount(), modelComponents.transitionMatrix.getRowGroupCount()));
}
// Build the state labeling.
@ -368,7 +322,7 @@ namespace storm {
if (options.buildStateValuations) {
stateValuations = storm::storage::sparse::StateValuations(stateStorage.getNumberOfStates());
for (auto const& bitVectorIndexPair : stateStorage.stateToId) {
stateValuations.get().valuations[bitVectorIndexPair.second] = unpackStateIntoValuation(bitVectorIndexPair.first, variableInformation, program.getManager());
stateValuations.get().valuations[bitVectorIndexPair.second] = generator->toValuation(bitVectorIndexPair.first);
}
}
@ -377,8 +331,7 @@ namespace storm {
template <typename ValueType, typename RewardModelType, typename StateType>
storm::models::sparse::StateLabeling ExplicitModelBuilder<ValueType, RewardModelType, StateType>::buildStateLabeling() {
storm::generator::PrismStateLabelingGenerator<ValueType, StateType> generator(program, variableInformation);
return generator.generate(stateStorage.stateToId, stateStorage.initialStateIndices);
return generator->label(stateStorage.stateToId, stateStorage.initialStateIndices);
}
// Explicitly instantiate the class.

9
src/builder/ExplicitModelBuilder.h

@ -13,7 +13,6 @@
#include <src/models/sparse/StandardRewardModel.h>
#include "src/storage/prism/Program.h"
#include "src/storage/expressions/SimpleValuation.h"
#include "src/storage/expressions/ExpressionEvaluator.h"
#include "src/storage/BitVectorHashMap.h"
#include "src/logic/Formulas.h"
@ -88,7 +87,7 @@ namespace storm {
/*!
* Creates an explicit model builder that uses the provided generator..
*
* @param generator The generator to build.
* @param generator The generator to use.
*/
ExplicitModelBuilder(std::shared_ptr<storm::generator::NextStateGenerator<ValueType, StateType>> const& generator, Options const& options = Options());
@ -129,19 +128,17 @@ namespace storm {
*
* @param transitionMatrixBuilder The builder of the transition matrix.
* @param rewardModelBuilders The builders for the selected reward models.
* @param terminalExpression If given, states satisfying this expression are not explored further.
* @return A tuple containing a vector with all rows at which the nondeterministic choices of each state begin
* and a vector containing the labels associated with each choice.
*/
boost::optional<std::vector<boost::container::flat_set<uint_fast64_t>>> buildMatrices(storm::storage::SparseMatrixBuilder<ValueType>& transitionMatrixBuilder, std::vector<RewardModelBuilder<typename RewardModelType::ValueType>>& rewardModelBuilders, boost::optional<storm::expressions::Expression> const& terminalExpression);
boost::optional<std::vector<boost::container::flat_set<uint_fast64_t>>> buildMatrices(storm::storage::SparseMatrixBuilder<ValueType>& transitionMatrixBuilder, std::vector<RewardModelBuilder<typename RewardModelType::ValueType>>& rewardModelBuilders);
/*!
* Explores the state space of the given program and returns the components of the model as a result.
*
* @param selectedRewardModels The reward models that are to be considered.
* @return A structure containing the components of the resulting model.
*/
ModelComponents buildModelComponents(std::vector<std::string> const& selectedRewardModels);
ModelComponents buildModelComponents();
/*!
* Builds the state labeling for the given program.

2
src/cli/entrypoints.h

@ -162,7 +162,7 @@ namespace storm {
modelFormulasPair.model->printModelInformationToStream(std::cout);
// Verify the model, if a formula was given.
if (!formulas.empty()) {
if (!modelFormulasPair.formulas.empty()) {
if (modelFormulasPair.model->isSparseModel()) {
if (storm::settings::getModule<storm::settings::modules::MarkovChainSettings>().isCounterexampleSet()) {
// If we were requested to generate a counterexample, we now do so for each formula.

40
src/generator/NextStateGenerator.cpp

@ -34,6 +34,10 @@ namespace storm {
return boost::get<storm::expressions::Expression const&>(labelOrExpression);
}
NextStateGeneratorOptions::NextStateGeneratorOptions() : buildChoiceLabels(false) {
// Intentionally left empty.
}
NextStateGeneratorOptions::NextStateGeneratorOptions(storm::logic::Formula const& formula) {
this->preserveFormula(formula);
this->setTerminalStatesFromFormula(formula);
@ -112,8 +116,8 @@ namespace storm {
return labels;
}
std::vector<storm::expressions::Expression> const& NextStateGeneratorOptions::getLabelExpressions() const {
return labelExpressions;
std::vector<storm::expressions::Expression> const& NextStateGeneratorOptions::getExpressionLabels() const {
return expressionLabels;
}
std::vector<std::pair<LabelOrExpression, bool>> const& NextStateGeneratorOptions::getTerminalStates() const {
@ -138,7 +142,7 @@ namespace storm {
}
NextStateGeneratorOptions& NextStateGeneratorOptions::addLabel(storm::expressions::Expression const& expression) {
labelExpressions.emplace_back(expression);
expressionLabels.emplace_back(expression);
return *this;
}
@ -162,11 +166,41 @@ namespace storm {
return *this;
}
RewardModelInformation::RewardModelInformation(std::string const& name, bool stateRewards, bool stateActionRewards, bool transitionRewards) : name(name), stateRewards(stateRewards), stateActionRewards(stateActionRewards), transitionRewards(transitionRewards) {
// Intentionally left empty.
}
std::string const& RewardModelInformation::getName() const {
return name;
}
bool RewardModelInformation::hasStateRewards() const {
return stateRewards;
}
bool RewardModelInformation::hasStateActionRewards() const {
return stateActionRewards;
}
bool RewardModelInformation::hasTransitionRewards() const {
return transitionRewards;
}
template<typename ValueType, typename StateType>
NextStateGenerator<ValueType, StateType>::NextStateGenerator(NextStateGeneratorOptions const& options) : options(options) {
// Intentionally left empty.
}
template<typename ValueType, typename StateType>
std::size_t NextStateGenerator<ValueType, StateType>::getNumberOfRewardModels() const {
return this->options.getRewardModelNames().size();
}
template<typename ValueType, typename StateType>
NextStateGeneratorOptions const& NextStateGenerator<ValueType, StateType>::getOptions() const {
return options;
}
template class NextStateGenerator<double>;
template class NextStateGenerator<storm::RationalFunction>;

49
src/generator/NextStateGenerator.h

@ -7,6 +7,7 @@
#include <boost/variant.hpp>
#include "src/storage/expressions/Expression.h"
#include "src/storage/BitVectorHashMap.h"
#include "src/generator/CompressedState.h"
#include "src/generator/StateBehavior.h"
@ -16,11 +17,6 @@ namespace storm {
class Expression;
}
namespace storage {
template<typename StateType>
class BitVectorHashMap;
}
namespace models {
namespace sparse {
class StateLabeling;
@ -49,6 +45,11 @@ namespace storm {
class NextStateGeneratorOptions {
public:
/*!
* Creates an object representing the default options.
*/
NextStateGeneratorOptions();
/*!
* 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>.
@ -85,7 +86,7 @@ namespace storm {
std::vector<std::string> const& getRewardModelNames() const;
std::set<std::string> const& getLabels() const;
std::vector<storm::expressions::Expression> const& getLabelExpressions() const;
std::vector<storm::expressions::Expression> const& getExpressionLabels() const;
std::vector<std::pair<LabelOrExpression, bool>> const& getTerminalStates() const;
bool hasTerminalStates() const;
void clearTerminalStates();
@ -106,7 +107,7 @@ namespace storm {
std::set<std::string> labels;
/// The expression that are to be used for creating the state labeling.
std::vector<storm::expressions::Expression> labelExpressions;
std::vector<storm::expressions::Expression> expressionLabels;
/// If one of these labels/expressions evaluates to the given bool, the state generator can abort the exploration.
std::vector<std::pair<LabelOrExpression, bool>> terminalStates;
@ -115,6 +116,29 @@ namespace storm {
bool buildChoiceLabels;
};
enum class ModelType {
DTMC,
CTMC,
MDP,
MA
};
class RewardModelInformation {
public:
RewardModelInformation(std::string const& name, bool stateRewards, bool stateActionRewards, bool transitionRewards);
std::string const& getName() const;
bool hasStateRewards() const;
bool hasStateActionRewards() const;
bool hasTransitionRewards() const;
private:
std::string name;
bool stateRewards;
bool stateActionRewards;
bool transitionRewards;
};
template<typename ValueType, typename StateType = uint32_t>
class NextStateGenerator {
public:
@ -122,6 +146,8 @@ namespace storm {
NextStateGenerator(NextStateGeneratorOptions const& options);
virtual uint64_t getStateSize() const = 0;
virtual ModelType getModelType() const = 0;
virtual bool isDeterministicModel() const = 0;
virtual std::vector<StateType> getInitialStates(StateToIdCallback const& stateToIdCallback) = 0;
@ -129,7 +155,14 @@ namespace storm {
virtual StateBehavior<ValueType, StateType> expand(StateToIdCallback const& stateToIdCallback) = 0;
virtual bool satisfies(storm::expressions::Expression const& expression) const = 0;
virtual storm::models::sparse::StateLabeling generateLabeling(storm::storage::BitVectorHashMap<StateType> const& states, std::vector<StateType> const& initialStateIndices = {}) = 0;
std::size_t getNumberOfRewardModels() const;
virtual RewardModelInformation getRewardModelInformation(uint64_t const& index) const = 0;
virtual storm::expressions::SimpleValuation toValuation(CompressedState const& state) const = 0;
virtual storm::models::sparse::StateLabeling label(storm::storage::BitVectorHashMap<StateType> const& states, std::vector<StateType> const& initialStateIndices = {}) = 0;
NextStateGeneratorOptions const& getOptions() const;
protected:
NextStateGeneratorOptions options;

75
src/generator/PrismNextStateGenerator.cpp

@ -4,7 +4,7 @@
#include "src/models/sparse/StateLabeling.h"
#include "src/storage/BitVectorHashMap.h"
#include "src/storage/expressions/SimpleValuation.h"
#include "src/utility/constants.h"
#include "src/utility/macros.h"
@ -14,13 +14,41 @@ namespace storm {
namespace generator {
template<typename ValueType, typename StateType>
PrismNextStateGenerator<ValueType, StateType>::PrismNextStateGenerator(storm::prism::Program const& program, NextStateGeneratorOptions const& options) : NextStateGenerator(options), program(program), rewardModels(), variableInformation(VariableInformation(program)), evaluator(program.getManager()), state(nullptr), comparator() {
PrismNextStateGenerator<ValueType, StateType>::PrismNextStateGenerator(storm::prism::Program const& program, NextStateGeneratorOptions const& options) : NextStateGenerator<ValueType, StateType>(options), program(program), rewardModels(), variableInformation(program), evaluator(program.getManager()), state(nullptr), comparator() {
STORM_LOG_THROW(!program.specifiesSystemComposition(), storm::exceptions::WrongFormatException, "The explicit next-state generator currently does not support custom system compositions.");
// Extract the reward models from the program based on the names we were given.
for (auto const& rewardModelName : this->options.getRewardModelNames()) {
rewardModels.push_back(program.getRewardModel(rewardModelName));
}
// If there are terminal states we need to handle, we now need to translate all labels to expressions.
if (this->options.hasTerminalStates()) {
for (auto const& expressionOrLabelAndBool : this->options.getTerminalStates()) {
if (expressionOrLabelAndBool.first.isExpression()) {
terminalStates.push_back(std::make_pair(expressionOrLabelAndBool.first.getExpression(), expressionOrLabelAndBool.second));
} else {
terminalStates.push_back(std::make_pair(program.getLabelExpression(expressionOrLabelAndBool.first.getLabel()), expressionOrLabelAndBool.second));
}
}
}
}
template<typename ValueType, typename StateType>
uint64_t PrismNextStateGenerator<ValueType, StateType>::getStateSize() const {
return variableInformation.getTotalBitOffset(true);
}
template<typename ValueType, typename StateType>
ModelType PrismNextStateGenerator<ValueType, StateType>::getModelType() const {
switch (program.getModelType()) {
case storm::prism::Program::ModelType::DTMC: return ModelType::DTMC;
case storm::prism::Program::ModelType::CTMC: return ModelType::CTMC;
case storm::prism::Program::ModelType::MDP: return ModelType::MDP;
case storm::prism::Program::ModelType::MA: return ModelType::MA;
default:
STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Invalid model type.");
}
}
template<typename ValueType, typename StateType>
@ -83,9 +111,9 @@ namespace storm {
}
// If a terminal expression was set and we must not expand this state, return now.
if (this->options.hasTerminalExpression()) {
for (auto const& expression : this->options.getTerminalExpressions()) {
if (evaluator.asBool(expression) {
if (!terminalStates.empty()) {
for (auto const& expressionBool : terminalStates) {
if (evaluator.asBool(expressionBool.first) == expressionBool.second) {
return result;
}
}
@ -423,22 +451,38 @@ namespace storm {
}
template<typename ValueType, typename StateType>
storm::models::sparse::StateLabeling PrismNextStateGenerator<ValueType, StateType>::generateLabeling(storm::storage::BitVectorHashMap<StateType> const& states, std::vector<StateType> const& initialStateIndices) {
std::vector<storm::prism::Label> const& labels = program.getLabels();
storm::models::sparse::StateLabeling PrismNextStateGenerator<ValueType, StateType>::label(storm::storage::BitVectorHashMap<StateType> const& states, std::vector<StateType> const& initialStateIndices) {
// Gather a vector of labels and their expressions so we can iterate it over it a lot.
std::vector<std::pair<std::string, storm::expressions::Expression>> labels;
for (auto const& label : this->options.getLabels()) {
labels.push_back(std::make_pair(label, program.getLabelExpression(label)));
}
// Make the labels unique.
std::sort(labels.begin(), labels.end(), [] (std::pair<std::string, storm::expressions::Expression> const& a, std::pair<std::string, storm::expressions::Expression> const& b) { return a.first < b.first; } );
auto it = std::unique(labels.begin(), labels.end(), [] (std::pair<std::string, storm::expressions::Expression> const& a, std::pair<std::string, storm::expressions::Expression> const& b) { return a.first == b.first; } );
labels.resize(std::distance(labels.begin(), it));
for (auto const& expression : this->options.getExpressionLabels()) {
std::stringstream stream;
stream << expression;
labels.push_back(std::make_pair(stream.str(), expression));
}
// Prepare result.
storm::models::sparse::StateLabeling result(states.size());
// Initialize labeling.
for (auto const& label : labels) {
result.addLabel(label.getName());
result.addLabel(label.first);
}
for (auto const& stateIndexPair : states) {
unpackStateIntoEvaluator(stateIndexPair.first, variableInformation, evaluator);
for (auto const& label : labels) {
// Add label to state, if the corresponding expression is true.
if (evaluator.asBool(label.getStatePredicateExpression())) {
result.addLabelToState(label.getName(), stateIndexPair.second);
if (evaluator.asBool(label.second)) {
result.addLabelToState(label.first, stateIndexPair.second);
}
}
}
@ -452,6 +496,17 @@ namespace storm {
return result;
}
template<typename ValueType, typename StateType>
RewardModelInformation PrismNextStateGenerator<ValueType, StateType>::getRewardModelInformation(uint64_t const& index) const {
storm::prism::RewardModel const& rewardModel = rewardModels[index].get();
return RewardModelInformation(rewardModel.getName(), rewardModel.hasStateRewards(), rewardModel.hasStateActionRewards(), rewardModel.hasTransitionRewards());
}
template<typename ValueType, typename StateType>
storm::expressions::SimpleValuation PrismNextStateGenerator<ValueType, StateType>::toValuation(CompressedState const& state) const {
return unpackStateIntoValuation(state, variableInformation, program.getManager());
}
template class PrismNextStateGenerator<double>;
template class PrismNextStateGenerator<storm::RationalFunction>;
}

15
src/generator/PrismNextStateGenerator.h

@ -19,6 +19,8 @@ namespace storm {
PrismNextStateGenerator(storm::prism::Program const& program, NextStateGeneratorOptions const& options = NextStateGeneratorOptions());
virtual uint64_t getStateSize() const override;
virtual ModelType getModelType() const override;
virtual bool isDeterministicModel() const override;
virtual std::vector<StateType> getInitialStates(StateToIdCallback const& stateToIdCallback) override;
@ -26,7 +28,11 @@ namespace storm {
virtual StateBehavior<ValueType, StateType> expand(StateToIdCallback const& stateToIdCallback) override;
virtual bool satisfies(storm::expressions::Expression const& expression) const override;
virtual storm::models::sparse::StateLabeling generateLabeling(storm::storage::BitVectorHashMap<StateType> const& states, std::vector<StateType> const& initialStateIndices = {}) override;
virtual RewardModelInformation getRewardModelInformation(uint64_t const& index) const override;
virtual storm::expressions::SimpleValuation toValuation(CompressedState const& state) const override;
virtual storm::models::sparse::StateLabeling label(storm::storage::BitVectorHashMap<StateType> const& states, std::vector<StateType> const& initialStateIndices = {}) override;
private:
/*!
@ -76,13 +82,16 @@ namespace storm {
storm::prism::Program const& program;
// The reward models that need to be considered.
std::vector<std::reference_wrapper<storm::prism::RewardModel const>> selectedRewardModels;
std::vector<std::reference_wrapper<storm::prism::RewardModel const>> rewardModels;
// The expressions that define terminal states.
std::vector<std::pair<storm::expressions::Expression, bool>> terminalStates;
// A flag that stores whether at least one of the selected reward models has state-action rewards.
bool hasStateActionRewards;
// Information about how the variables are packed.
VariableInformation const& variableInformation;
VariableInformation variableInformation;
// An evaluator used to evaluate expressions.
storm::expressions::ExpressionEvaluator<ValueType> evaluator;

4
src/modelchecker/exploration/SparseExplorationModelChecker.cpp

@ -35,7 +35,7 @@ namespace storm {
namespace modelchecker {
template<typename ValueType, typename StateType>
SparseExplorationModelChecker<ValueType, StateType>::SparseExplorationModelChecker(storm::prism::Program const& program, boost::optional<std::map<storm::expressions::Variable, storm::expressions::Expression>> const& constantDefinitions) : program(storm::utility::prism::preprocessProgram<ValueType>(program, constantDefinitions)), variableInformation(this->program), randomGenerator(std::chrono::system_clock::now().time_since_epoch().count()), comparator(storm::settings::getModule<storm::settings::modules::ExplorationSettings>().getPrecision()) {
SparseExplorationModelChecker<ValueType, StateType>::SparseExplorationModelChecker(storm::prism::Program const& program, boost::optional<std::map<storm::expressions::Variable, storm::expressions::Expression>> const& constantDefinitions) : program(storm::utility::prism::preprocess<ValueType>(program, constantDefinitions.get())), randomGenerator(std::chrono::system_clock::now().time_since_epoch().count()), comparator(storm::settings::getModule<storm::settings::modules::ExplorationSettings>().getPrecision()) {
// Intentionally left empty.
}
@ -59,7 +59,7 @@ namespace storm {
explorationInformation.newRowGroup(0);
std::map<std::string, storm::expressions::Expression> labelToExpressionMapping = program.getLabelToExpressionMapping();
StateGeneration<StateType, ValueType> stateGeneration(program, variableInformation, explorationInformation, conditionFormula.toExpression(program.getManager(), labelToExpressionMapping), targetFormula.toExpression(program.getManager(), labelToExpressionMapping));
StateGeneration<StateType, ValueType> stateGeneration(program, explorationInformation, conditionFormula.toExpression(program.getManager(), labelToExpressionMapping), targetFormula.toExpression(program.getManager(), labelToExpressionMapping));
// Compute and return result.

3
src/modelchecker/exploration/SparseExplorationModelChecker.h

@ -74,9 +74,6 @@ namespace storm {
// The program that defines the model to check.
storm::prism::Program program;
// The variable information.
storm::generator::VariableInformation variableInformation;
// The random number generator.
mutable std::default_random_engine randomGenerator;

2
src/modelchecker/exploration/StateGeneration.cpp

@ -7,7 +7,7 @@ namespace storm {
namespace exploration_detail {
template <typename StateType, typename ValueType>
StateGeneration<StateType, ValueType>::StateGeneration(storm::prism::Program const& program, storm::generator::VariableInformation const& variableInformation, ExplorationInformation<StateType, ValueType>& explorationInformation, storm::expressions::Expression const& conditionStateExpression, storm::expressions::Expression const& targetStateExpression) : generator(program, variableInformation, false), stateStorage(variableInformation.getTotalBitOffset(true)), conditionStateExpression(conditionStateExpression), targetStateExpression(targetStateExpression) {
StateGeneration<StateType, ValueType>::StateGeneration(storm::prism::Program const& program, ExplorationInformation<StateType, ValueType>& explorationInformation, storm::expressions::Expression const& conditionStateExpression, storm::expressions::Expression const& targetStateExpression) : generator(program), stateStorage(generator.getStateSize()), conditionStateExpression(conditionStateExpression), targetStateExpression(targetStateExpression) {
stateToIdCallback = [&explorationInformation, this] (storm::generator::CompressedState const& state) -> StateType {
StateType newIndex = stateStorage.getNumberOfStates();

2
src/modelchecker/exploration/StateGeneration.h

@ -21,7 +21,7 @@ namespace storm {
template <typename StateType, typename ValueType>
class StateGeneration {
public:
StateGeneration(storm::prism::Program const& program, storm::generator::VariableInformation const& variableInformation, ExplorationInformation<StateType, ValueType>& explorationInformation, storm::expressions::Expression const& conditionStateExpression, storm::expressions::Expression const& targetStateExpression);
StateGeneration(storm::prism::Program const& program, ExplorationInformation<StateType, ValueType>& explorationInformation, storm::expressions::Expression const& conditionStateExpression, storm::expressions::Expression const& targetStateExpression);
void load(storm::generator::CompressedState const& state);

2
src/storage/BitVectorHashMap.h

@ -14,7 +14,7 @@ namespace storm {
* queries and insertions are supported. Also, the keys must be bit vectors with a length that is a multiple of
* 64.
*/
template<class ValueType, class Hash1 = std::hash<storm::storage::BitVector>, class Hash2 = storm::storage::NonZeroBitVectorHash>
template<typename ValueType, typename Hash1 = std::hash<storm::storage::BitVector>, class Hash2 = storm::storage::NonZeroBitVectorHash>
class BitVectorHashMap {
public:
class BitVectorHashMapIterator {

41
src/utility/prism.cpp

@ -14,15 +14,8 @@ namespace storm {
namespace prism {
template<typename ValueType>
storm::prism::Program preprocessProgram(storm::prism::Program const& program, boost::optional<std::map<storm::expressions::Variable, storm::expressions::Expression>> const& constantDefinitions, boost::optional<std::set<std::string>> const& restrictedLabelSet, boost::optional<std::vector<storm::expressions::Expression>> const& expressionLabels) {
storm::prism::Program result;
// Start by defining the undefined constants in the model.
if (constantDefinitions) {
result = program.defineUndefinedConstants(constantDefinitions.get());
} else {
result = program;
}
storm::prism::Program preprocess(storm::prism::Program const& program, std::map<storm::expressions::Variable, storm::expressions::Expression> const& constantDefinitions) {
storm::prism::Program result = program.defineUndefinedConstants(constantDefinitions);
// If the program still contains undefined constants and we are not in a parametric setting, assemble an appropriate error message.
if (!std::is_same<ValueType, storm::RationalFunction>::value && result.hasUndefinedConstants()) {
@ -43,30 +36,16 @@ namespace storm {
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "The program contains undefined constants that appear in some places other than update probabilities and reward value expressions, which is not admitted.");
}
// If the set of labels we are supposed to built is restricted, we need to remove the other labels from the program.
if (restrictedLabelSet) {
result.filterLabels(restrictedLabelSet.get());
}
// Build new labels.
if (expressionLabels) {
std::map<storm::expressions::Variable, storm::expressions::Expression> constantsSubstitution = result.getConstantsSubstitution();
for (auto const& expression : expressionLabels.get()) {
std::stringstream stream;
stream << expression.substitute(constantsSubstitution);
std::string name = stream.str();
if (!result.hasLabel(name)) {
result.addLabel(name, expression);
}
}
}
// Now that the program is fixed, we we need to substitute all constants with their concrete value.
result = result.substituteConstants();
return result;
}
template<typename ValueType>
storm::prism::Program preprocess(storm::prism::Program const& program, std::string const& constantDefinitionString) {
return preprocess<ValueType>(program, parseConstantDefinitionString(program, constantDefinitionString));
}
std::map<storm::expressions::Variable, storm::expressions::Expression> parseConstantDefinitionString(storm::prism::Program const& program, std::string const& constantDefinitionString) {
std::map<storm::expressions::Variable, storm::expressions::Expression> constantDefinitions;
std::set<storm::expressions::Variable> definedConstants;
@ -124,9 +103,11 @@ namespace storm {
return constantDefinitions;
}
template storm::prism::Program preprocessProgram<double>(storm::prism::Program const& program, boost::optional<std::map<storm::expressions::Variable, storm::expressions::Expression>> const& constantDefinitions, boost::optional<std::set<std::string>> const& restrictedLabelSet, boost::optional<std::vector<storm::expressions::Expression>> const& expressionLabels);
template storm::prism::Program preprocess<double>(storm::prism::Program const& program, std::map<storm::expressions::Variable, storm::expressions::Expression> const& constantDefinitions);
template storm::prism::Program preprocess<storm::RationalFunction>(storm::prism::Program const& program, std::map<storm::expressions::Variable, storm::expressions::Expression> const& constantDefinitions);
template storm::prism::Program preprocessProgram<storm::RationalFunction>(storm::prism::Program const& program, boost::optional<std::map<storm::expressions::Variable, storm::expressions::Expression>> const& constantDefinitions, boost::optional<std::set<std::string>> const& restrictedLabelSet, boost::optional<std::vector<storm::expressions::Expression>> const& expressionLabels);
template storm::prism::Program preprocess<double>(storm::prism::Program const& program, std::string const& constantDefinitionString);
template storm::prism::Program preprocess<storm::RationalFunction>(storm::prism::Program const& program, std::string const& constantDefinitionString);
}
}

7
src/utility/prism.h

@ -20,10 +20,13 @@ namespace storm {
namespace utility {
namespace prism {
std::map<storm::expressions::Variable, storm::expressions::Expression> parseConstantDefinitionString(storm::prism::Program const& program, std::string const& constantDefinitionString);
template<typename ValueType>
storm::prism::Program preprocessProgram(storm::prism::Program const& program, boost::optional<std::map<storm::expressions::Variable, storm::expressions::Expression>> const& constantDefinitions = boost::none, boost::optional<std::set<std::string>> const& restrictedLabelSet = boost::none, boost::optional<std::vector<storm::expressions::Expression>> const& expressionLabels = boost::none);
storm::prism::Program preprocess(storm::prism::Program const& program, std::map<storm::expressions::Variable, storm::expressions::Expression> const& constantDefinitions);
std::map<storm::expressions::Variable, storm::expressions::Expression> parseConstantDefinitionString(storm::prism::Program const& program, std::string const& constantDefinitionString);
template<typename ValueType>
storm::prism::Program preprocess(storm::prism::Program const& program, std::string const& constantDefinitionString);
} // namespace prism
} // namespace utility

28
src/utility/storm.h

@ -14,12 +14,9 @@
#include "storm-config.h"
// Headers that provide auxiliary functionality.
#include "src/settings/SettingsManager.h"
#include "src/settings/modules/MarkovChainSettings.h"
#include "src/settings/modules/IOSettings.h"
#include "src/settings/modules/BisimulationSettings.h"
@ -75,6 +72,9 @@
#include "src/counterexamples/MILPMinimalLabelSetGenerator.h"
#include "src/counterexamples/SMTMinimalCommandSetGenerator.h"
// Headers related to program preprocessing.
#include "src/utility/prism.h"
// Headers related to exception handling.
#include "src/exceptions/InvalidStateException.h"
#include "src/exceptions/InvalidArgumentException.h"
@ -83,9 +83,6 @@
#include "src/exceptions/NotImplementedException.h"
#include "src/exceptions/NotSupportedException.h"
// Notice: The implementation for the template functions must stay in the header.
// Otherwise the linker complains.
namespace storm {
template<typename ValueType>
@ -105,7 +102,9 @@ namespace storm {
storm::prism::Program translatedProgram;
// Get the string that assigns values to the unknown currently undefined constants in the model.
std::string constants = storm::settings::getModule<storm::settings::modules::IOSettings>().getConstantDefinitionString();
std::string constantDefinitionString = storm::settings::getModule<storm::settings::modules::IOSettings>().getConstantDefinitionString();
translatedProgram = storm::utility::prism::preprocess<ValueType>(program, constantDefinitionString);
std::map<storm::expressions::Variable, storm::expressions::Expression> constantsSubstitution = translatedProgram.getConstantsSubstitution();
// Customize and perform model-building.
if (storm::settings::getModule<storm::settings::modules::MarkovChainSettings>().getEngine() == storm::settings::modules::MarkovChainSettings::Engine::Sparse) {
@ -120,29 +119,20 @@ namespace storm {
storm::builder::ExplicitModelBuilder<ValueType> builder(program, options);
result.model = builder.translate();
translatedProgram = builder.getTranslatedProgram();
} else if (storm::settings::getModule<storm::settings::modules::MarkovChainSettings>().getEngine() == storm::settings::modules::MarkovChainSettings::Engine::Dd || storm::settings::getModule<storm::settings::modules::MarkovChainSettings>().getEngine() == storm::settings::modules::MarkovChainSettings::Engine::Hybrid) {
typename storm::builder::DdPrismModelBuilder<LibraryType>::Options options;
options = typename storm::builder::DdPrismModelBuilder<LibraryType>::Options(formulas);
options.addConstantDefinitionsFromString(program, constants);
options.addConstantDefinitionsFromString(program, constantDefinitionString);
storm::builder::DdPrismModelBuilder<LibraryType> builder;
result.model = builder.translateProgram(program, options);
translatedProgram = builder.getTranslatedProgram();
}
// There may be constants of the model appearing in the formulas, so we replace all their occurrences
// by their definitions in the translated program.
// Start by building a mapping from constants of the (translated) model to their defining expressions.
std::map<storm::expressions::Variable, storm::expressions::Expression> constantSubstitution;
for (auto const& constant : translatedProgram.getConstants()) {
if (constant.isDefined()) {
constantSubstitution.emplace(constant.getExpressionVariable(), constant.getExpression());
}
}
for (auto const& formula : formulas) {
result.formulas.emplace_back(formula->substitute(constantSubstitution));
result.formulas.emplace_back(formula->substitute(constantsSubstitution));
}
return result;
}

Loading…
Cancel
Save