166 lines
8.8 KiB
166 lines
8.8 KiB
#include "storm/generator/NextStateGenerator.h"
|
|
|
|
#include "storm/adapters/RationalFunctionAdapter.h"
|
|
|
|
#include "storm/logic/Formulas.h"
|
|
|
|
#include "storm/storage/expressions/ExpressionManager.h"
|
|
#include "storm/storage/expressions/SimpleValuation.h"
|
|
|
|
#include "storm/models/sparse/StateLabeling.h"
|
|
|
|
#include "storm/utility/macros.h"
|
|
#include "storm/exceptions/InvalidSettingsException.h"
|
|
|
|
namespace storm {
|
|
namespace generator {
|
|
|
|
template<typename ValueType, typename StateType>
|
|
NextStateGenerator<ValueType, StateType>::NextStateGenerator(storm::expressions::ExpressionManager const& expressionManager, VariableInformation const& variableInformation, NextStateGeneratorOptions const& options) : options(options), expressionManager(expressionManager.getSharedPointer()), variableInformation(variableInformation), evaluator(nullptr), state(nullptr) {
|
|
// Intentionally left empty.
|
|
}
|
|
|
|
template<typename ValueType, typename StateType>
|
|
NextStateGenerator<ValueType, StateType>::NextStateGenerator(storm::expressions::ExpressionManager const& expressionManager, NextStateGeneratorOptions const& options) : options(options), expressionManager(expressionManager.getSharedPointer()), variableInformation(), evaluator(nullptr), state(nullptr) {
|
|
// Intentionally left empty.
|
|
}
|
|
|
|
template<typename ValueType, typename StateType>
|
|
NextStateGeneratorOptions const& NextStateGenerator<ValueType, StateType>::getOptions() const {
|
|
return options;
|
|
}
|
|
|
|
template<typename ValueType, typename StateType>
|
|
uint64_t NextStateGenerator<ValueType, StateType>::getStateSize() const {
|
|
return variableInformation.getTotalBitOffset(true);
|
|
}
|
|
|
|
template<typename ValueType, typename StateType>
|
|
void NextStateGenerator<ValueType, StateType>::load(CompressedState const& state) {
|
|
// Since almost all subsequent operations are based on the evaluator, we load the state into it now.
|
|
unpackStateIntoEvaluator(state, variableInformation, *evaluator);
|
|
|
|
// Also, we need to store a pointer to the state itself, because we need to be able to access it when expanding it.
|
|
this->state = &state;
|
|
}
|
|
|
|
template<typename ValueType, typename StateType>
|
|
bool NextStateGenerator<ValueType, StateType>::satisfies(storm::expressions::Expression const& expression) const {
|
|
if (expression.isTrue()) {
|
|
return true;
|
|
}
|
|
return evaluator->asBool(expression);
|
|
}
|
|
|
|
template<typename ValueType, typename StateType>
|
|
storm::models::sparse::StateLabeling NextStateGenerator<ValueType, StateType>::label(storm::storage::sparse::StateStorage<StateType> const& stateStorage, std::vector<StateType> const& initialStateIndices, std::vector<StateType> const& deadlockStateIndices, std::vector<std::pair<std::string, storm::expressions::Expression>> labelsAndExpressions) {
|
|
|
|
for (auto const& expression : this->options.getExpressionLabels()) {
|
|
std::stringstream stream;
|
|
stream << expression;
|
|
labelsAndExpressions.push_back(std::make_pair(stream.str(), expression));
|
|
}
|
|
|
|
// Make the labels unique.
|
|
std::sort(labelsAndExpressions.begin(), labelsAndExpressions.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(labelsAndExpressions.begin(), labelsAndExpressions.end(), [] (std::pair<std::string, storm::expressions::Expression> const& a, std::pair<std::string, storm::expressions::Expression> const& b) { return a.first == b.first; } );
|
|
labelsAndExpressions.resize(std::distance(labelsAndExpressions.begin(), it));
|
|
|
|
// Prepare result.
|
|
storm::models::sparse::StateLabeling result(stateStorage.getNumberOfStates());
|
|
|
|
// Initialize labeling.
|
|
for (auto const& label : labelsAndExpressions) {
|
|
result.addLabel(label.first);
|
|
}
|
|
|
|
auto const& states = stateStorage.stateToId;
|
|
for (auto const& stateIndexPair : states) {
|
|
unpackStateIntoEvaluator(stateIndexPair.first, variableInformation, *this->evaluator);
|
|
|
|
for (auto const& label : labelsAndExpressions) {
|
|
// Add label to state, if the corresponding expression is true.
|
|
if (evaluator->asBool(label.second)) {
|
|
result.addLabelToState(label.first, stateIndexPair.second);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!result.containsLabel("init")) {
|
|
// Also label the initial state with the special label "init".
|
|
result.addLabel("init");
|
|
for (auto index : initialStateIndices) {
|
|
result.addLabelToState("init", index);
|
|
}
|
|
}
|
|
if (!result.containsLabel("deadlock")) {
|
|
result.addLabel("deadlock");
|
|
for (auto index : deadlockStateIndices) {
|
|
result.addLabelToState("deadlock", index);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
template<typename ValueType, typename StateType>
|
|
void NextStateGenerator<ValueType, StateType>::postprocess(StateBehavior<ValueType, StateType>& result) {
|
|
// If the model we build is a Markov Automaton, we postprocess the choices to sum all Markovian choices
|
|
// and make the Markovian choice the very first one (if there is any).
|
|
bool foundPreviousMarkovianChoice = false;
|
|
if (this->getModelType() == ModelType::MA) {
|
|
uint64_t numberOfChoicesToDelete = 0;
|
|
|
|
for (uint_fast64_t index = 0; index + numberOfChoicesToDelete < result.getNumberOfChoices();) {
|
|
Choice<ValueType>& choice = result.getChoices()[index];
|
|
|
|
if (choice.isMarkovian()) {
|
|
if (foundPreviousMarkovianChoice) {
|
|
// If there was a previous Markovian choice, we need to sum them. Note that we can assume
|
|
// that the previous Markovian choice is the very first one in the choices vector.
|
|
result.getChoices().front().add(choice);
|
|
|
|
// Swap the choice to the end to indicate it can be removed (if it's not already there).
|
|
if (index != result.getNumberOfChoices() - 1 - numberOfChoicesToDelete) {
|
|
choice = std::move(result.getChoices()[result.getNumberOfChoices() - 1 - numberOfChoicesToDelete]);
|
|
}
|
|
++numberOfChoicesToDelete;
|
|
} else {
|
|
// If there is no previous Markovian choice, just move the Markovian choice to the front.
|
|
if (index != 0) {
|
|
std::swap(result.getChoices().front(), choice);
|
|
}
|
|
foundPreviousMarkovianChoice = true;
|
|
++index;
|
|
}
|
|
} else {
|
|
++index;
|
|
}
|
|
}
|
|
|
|
// Finally remove the choices that were added to other Markovian choices.
|
|
if (numberOfChoicesToDelete > 0) {
|
|
result.getChoices().resize(result.getChoices().size() - numberOfChoicesToDelete);
|
|
}
|
|
}
|
|
}
|
|
|
|
template<typename ValueType, typename StateType>
|
|
storm::expressions::SimpleValuation NextStateGenerator<ValueType, StateType>::toValuation(CompressedState const& state) const {
|
|
return unpackStateIntoValuation(state, variableInformation, *expressionManager);
|
|
}
|
|
|
|
template<typename ValueType, typename StateType>
|
|
std::shared_ptr<storm::storage::sparse::ChoiceOrigins> NextStateGenerator<ValueType, StateType>::generateChoiceOrigins(std::vector<boost::any>& dataForChoiceOrigins) const {
|
|
STORM_LOG_ERROR_COND(!options.isBuildChoiceOriginsSet(), "Generating choice origins is not supported for the considered model format.");
|
|
return nullptr;
|
|
}
|
|
|
|
template class NextStateGenerator<double>;
|
|
|
|
#ifdef STORM_HAVE_CARL
|
|
template class NextStateGenerator<storm::RationalNumber>;
|
|
template class NextStateGenerator<storm::RationalFunction>;
|
|
#endif
|
|
}
|
|
}
|