Browse Source
Started refactoring explicit model generator of PRISM models
Started refactoring explicit model generator of PRISM models
Former-commit-id: 4ea82670d0
main
7 changed files with 870 additions and 796 deletions
-
2CMakeLists.txt
-
791src/adapters/ExplicitModelAdapter.h
-
616src/builder/ExplicitPrismModelBuilder.cpp
-
248src/builder/ExplicitPrismModelBuilder.h
-
1src/counterexamples/SMTMinimalCommandSetGenerator.h
-
2src/storage/BitVectorHashMap.cpp
-
6src/utility/cli.h
@ -1,791 +0,0 @@ |
|||||
#ifndef STORM_ADAPTERS_EXPLICITMODELADAPTER_H |
|
||||
#define STORM_ADAPTERS_EXPLICITMODELADAPTER_H |
|
||||
|
|
||||
#include <memory> |
|
||||
#include <unordered_map> |
|
||||
#include <utility> |
|
||||
#include <vector> |
|
||||
#include <queue> |
|
||||
#include <cstdint> |
|
||||
#include <boost/functional/hash.hpp> |
|
||||
#include <boost/container/flat_set.hpp> |
|
||||
#include <boost/algorithm/string.hpp> |
|
||||
|
|
||||
#include "src/storage/prism/Program.h" |
|
||||
#include "src/storage/expressions/SimpleValuation.h" |
|
||||
#include "src/storage/expressions/ExprtkExpressionEvaluator.h" |
|
||||
#include "src/storage/BitVectorHashMap.h" |
|
||||
#include "src/utility/PrismUtility.h" |
|
||||
#include "src/models/AbstractModel.h" |
|
||||
#include "src/models/Dtmc.h" |
|
||||
#include "src/models/Ctmc.h" |
|
||||
#include "src/models/Mdp.h" |
|
||||
#include "src/models/Ctmdp.h" |
|
||||
#include "src/models/AtomicPropositionsLabeling.h" |
|
||||
#include "src/storage/SparseMatrix.h" |
|
||||
#include "src/settings/SettingsManager.h" |
|
||||
#include "src/utility/macros.h" |
|
||||
#include "src/exceptions/WrongFormatException.h" |
|
||||
|
|
||||
namespace storm { |
|
||||
namespace adapters { |
|
||||
|
|
||||
using namespace storm::utility::prism; |
|
||||
|
|
||||
template<typename ValueType> |
|
||||
class ExplicitModelAdapter { |
|
||||
public: |
|
||||
typedef storm::storage::BitVector StateType; |
|
||||
|
|
||||
// A structure holding information about the reachable state space. |
|
||||
struct StateInformation { |
|
||||
StateInformation(uint64_t bitsPerState) : bitsPerState(bitsPerState), reachableStates(), stateToIndexMap(bitsPerState, 1000000) { |
|
||||
// Intentionally left empty. |
|
||||
} |
|
||||
|
|
||||
// The number of bits of each state. |
|
||||
uint64_t bitsPerState; |
|
||||
|
|
||||
// A list of reachable states as indices in the stateToIndexMap. |
|
||||
std::vector<storm::storage::BitVector> reachableStates; |
|
||||
|
|
||||
// A list of initial states in terms of their global indices. |
|
||||
std::vector<uint32_t> initialStateIndices; |
|
||||
|
|
||||
// A mapping from reachable states to their indices. |
|
||||
storm::storage::BitVectorHashMap<uint32_t> stateToIndexMap; |
|
||||
}; |
|
||||
|
|
||||
// A structure storing information about the used variables of the program. |
|
||||
struct VariableInformation { |
|
||||
struct BooleanVariableInformation { |
|
||||
BooleanVariableInformation(storm::expressions::Variable const& variable, bool initialValue, uint_fast64_t bitOffset) : variable(variable), initialValue(initialValue), bitOffset(bitOffset) { |
|
||||
// Intentionally left empty. |
|
||||
} |
|
||||
|
|
||||
storm::expressions::Variable variable; |
|
||||
bool initialValue; |
|
||||
uint_fast64_t bitOffset; |
|
||||
}; |
|
||||
|
|
||||
struct IntegerVariableInformation { |
|
||||
IntegerVariableInformation(storm::expressions::Variable const& variable, int_fast64_t initialValue, int_fast64_t lowerBound, int_fast64_t upperBound, uint_fast64_t bitOffset, uint_fast64_t bitWidth) : variable(variable), initialValue(initialValue), lowerBound(lowerBound), upperBound(upperBound), bitOffset(bitOffset), bitWidth(bitWidth) { |
|
||||
// Intentionally left empty. |
|
||||
} |
|
||||
|
|
||||
storm::expressions::Variable variable; |
|
||||
int_fast64_t initialValue; |
|
||||
int_fast64_t lowerBound; |
|
||||
int_fast64_t upperBound; |
|
||||
uint_fast64_t bitOffset; |
|
||||
uint_fast64_t bitWidth; |
|
||||
}; |
|
||||
|
|
||||
uint_fast64_t getBitOffset(storm::expressions::Variable const& variable) const { |
|
||||
auto const& booleanIndex = booleanVariableToIndexMap.find(variable); |
|
||||
if (booleanIndex != booleanVariableToIndexMap.end()) { |
|
||||
return booleanVariables[booleanIndex].bitOffset; |
|
||||
} |
|
||||
auto const& integerIndex = integerVariableToIndexMap.find(variable); |
|
||||
if (integerIndex != integerVariableToIndexMap.end()) { |
|
||||
return integerVariables[integerIndex].bitOffset; |
|
||||
} |
|
||||
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Cannot look-up bit index of unknown variable."); |
|
||||
} |
|
||||
|
|
||||
uint_fast64_t getBitWidth(storm::expressions::Variable const& variable) const { |
|
||||
auto const& integerIndex = integerVariableToIndexMap.find(variable); |
|
||||
if (integerIndex != integerVariableToIndexMap.end()) { |
|
||||
return integerVariables[integerIndex].bitWidth; |
|
||||
} |
|
||||
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Cannot look-up bit width of unknown variable."); |
|
||||
} |
|
||||
|
|
||||
// The list of boolean variables. |
|
||||
std::map<storm::expressions::Variable, uint_fast64_t> booleanVariableToIndexMap; |
|
||||
std::vector<BooleanVariableInformation> booleanVariables; |
|
||||
|
|
||||
// The list of integer variables. |
|
||||
std::map<storm::expressions::Variable, uint_fast64_t> integerVariableToIndexMap; |
|
||||
std::vector<IntegerVariableInformation> integerVariables; |
|
||||
}; |
|
||||
|
|
||||
// A structure holding the individual components of a model. |
|
||||
struct ModelComponents { |
|
||||
ModelComponents() : transitionMatrix(), stateLabeling(), stateRewards(), transitionRewardMatrix(), choiceLabeling() { |
|
||||
// Intentionally left empty. |
|
||||
} |
|
||||
|
|
||||
// The transition matrix. |
|
||||
storm::storage::SparseMatrix<ValueType> transitionMatrix; |
|
||||
|
|
||||
// The state labeling. |
|
||||
storm::models::AtomicPropositionsLabeling stateLabeling; |
|
||||
|
|
||||
// The state reward vector. |
|
||||
std::vector<ValueType> stateRewards; |
|
||||
|
|
||||
// A matrix storing the reward for particular transitions. |
|
||||
storm::storage::SparseMatrix<ValueType> transitionRewardMatrix; |
|
||||
|
|
||||
// A vector that stores a labeling for each choice. |
|
||||
std::vector<boost::container::flat_set<uint_fast64_t>> choiceLabeling; |
|
||||
}; |
|
||||
|
|
||||
/*! |
|
||||
* Convert the program given at construction time to an abstract model. The type of the model is the one |
|
||||
* specified in the program. The given reward model name selects the rewards that the model will contain. |
|
||||
* |
|
||||
* @param program The program to translate. |
|
||||
* @param constantDefinitionString A string that contains a comma-separated definition of all undefined |
|
||||
* constants in the model. |
|
||||
* @param rewardModel The reward model that is to be built. |
|
||||
* @return The explicit model that was given by the probabilistic program. |
|
||||
*/ |
|
||||
static std::unique_ptr<storm::models::AbstractModel<ValueType>> translateProgram(storm::prism::Program program, bool rewards = true, std::string const& rewardModelName = "", std::string const& constantDefinitionString = "") { |
|
||||
// Start by defining the undefined constants in the model. |
|
||||
// First, we need to parse the constant definition string. |
|
||||
std::map<storm::expressions::Variable, storm::expressions::Expression> constantDefinitions = storm::utility::prism::parseConstantDefinitionString(program, constantDefinitionString); |
|
||||
|
|
||||
storm::prism::Program preparedProgram = program.defineUndefinedConstants(constantDefinitions); |
|
||||
STORM_LOG_THROW(!preparedProgram.hasUndefinedConstants(), storm::exceptions::InvalidArgumentException, "Program still contains undefined constants."); |
|
||||
|
|
||||
// Now that we have defined all the constants in the program, we need to substitute their appearances in |
|
||||
// all expressions in the program so we can then evaluate them without having to store the values of the |
|
||||
// constants in the state (i.e., valuation). |
|
||||
preparedProgram = preparedProgram.substituteConstants(); |
|
||||
storm::prism::RewardModel rewardModel = storm::prism::RewardModel(); |
|
||||
|
|
||||
// Select the appropriate reward model. |
|
||||
if (rewards) { |
|
||||
// If a specific reward model was selected or one with the empty name exists, select it. |
|
||||
if (rewardModelName != "" || preparedProgram.hasRewardModel(rewardModelName)) { |
|
||||
rewardModel = preparedProgram.getRewardModel(rewardModelName); |
|
||||
} else if (preparedProgram.hasRewardModel()) { |
|
||||
// Otherwise, we select the first one. |
|
||||
rewardModel = preparedProgram.getRewardModel(0); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
ModelComponents modelComponents = buildModelComponents(preparedProgram, rewardModel); |
|
||||
|
|
||||
std::unique_ptr<storm::models::AbstractModel<ValueType>> result; |
|
||||
switch (program.getModelType()) { |
|
||||
case storm::prism::Program::ModelType::DTMC: |
|
||||
result = std::unique_ptr<storm::models::AbstractModel<ValueType>>(new storm::models::Dtmc<ValueType>(std::move(modelComponents.transitionMatrix), std::move(modelComponents.stateLabeling), rewardModel.hasStateRewards() ? std::move(modelComponents.stateRewards) : boost::optional<std::vector<ValueType>>(), rewardModel.hasTransitionRewards() ? std::move(modelComponents.transitionRewardMatrix) : boost::optional<storm::storage::SparseMatrix<ValueType>>(), std::move(modelComponents.choiceLabeling))); |
|
||||
break; |
|
||||
case storm::prism::Program::ModelType::CTMC: |
|
||||
result = std::unique_ptr<storm::models::AbstractModel<ValueType>>(new storm::models::Ctmc<ValueType>(std::move(modelComponents.transitionMatrix), std::move(modelComponents.stateLabeling), rewardModel.hasStateRewards() ? std::move(modelComponents.stateRewards) : boost::optional<std::vector<ValueType>>(), rewardModel.hasTransitionRewards() ? std::move(modelComponents.transitionRewardMatrix) : boost::optional<storm::storage::SparseMatrix<ValueType>>(), std::move(modelComponents.choiceLabeling))); |
|
||||
break; |
|
||||
case storm::prism::Program::ModelType::MDP: |
|
||||
result = std::unique_ptr<storm::models::AbstractModel<ValueType>>(new storm::models::Mdp<ValueType>(std::move(modelComponents.transitionMatrix), std::move(modelComponents.stateLabeling), rewardModel.hasStateRewards() ? std::move(modelComponents.stateRewards) : boost::optional<std::vector<ValueType>>(), rewardModel.hasTransitionRewards() ? std::move(modelComponents.transitionRewardMatrix) : boost::optional<storm::storage::SparseMatrix<ValueType>>(), std::move(modelComponents.choiceLabeling))); |
|
||||
break; |
|
||||
case storm::prism::Program::ModelType::CTMDP: |
|
||||
result = std::unique_ptr<storm::models::AbstractModel<ValueType>>(new storm::models::Ctmdp<ValueType>(std::move(modelComponents.transitionMatrix), std::move(modelComponents.stateLabeling), rewardModel.hasStateRewards() ? std::move(modelComponents.stateRewards) : boost::optional<std::vector<ValueType>>(), rewardModel.hasTransitionRewards() ? std::move(modelComponents.transitionRewardMatrix) : boost::optional<storm::storage::SparseMatrix<ValueType>>(), std::move(modelComponents.choiceLabeling))); |
|
||||
break; |
|
||||
default: |
|
||||
LOG4CPLUS_ERROR(logger, "Error while creating model from probabilistic program: cannot handle this model type."); |
|
||||
throw storm::exceptions::WrongFormatException() << "Error while creating model from probabilistic program: cannot handle this model type."; |
|
||||
break; |
|
||||
} |
|
||||
|
|
||||
return result; |
|
||||
} |
|
||||
|
|
||||
private: |
|
||||
static void unpackStateIntoEvaluator(storm::storage::BitVector const& currentState, VariableInformation const& variableInformation, storm::expressions::ExprtkExpressionEvaluator& evaluator) { |
|
||||
for (auto const& booleanVariable : variableInformation.booleanVariables) { |
|
||||
evaluator.setBooleanValue(booleanVariable.variable, currentState.get(booleanVariable.bitOffset)); |
|
||||
} |
|
||||
for (auto const& integerVariable : variableInformation.integerVariables) { |
|
||||
evaluator.setIntegerValue(integerVariable.variable, currentState.getAsInt(integerVariable.bitOffset, integerVariable.bitWidth) + integerVariable.lowerBound); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/*! |
|
||||
* Applies an update to the given state and returns the resulting new state object. This methods does not |
|
||||
* modify the given state but returns a new one. |
|
||||
* |
|
||||
* @params state The state to which to apply the update. |
|
||||
* @params update The update to apply. |
|
||||
* @return The resulting state. |
|
||||
*/ |
|
||||
static StateType applyUpdate(VariableInformation const& variableInformation, StateType const& state, storm::prism::Update const& update, storm::expressions::ExprtkExpressionEvaluator const& evaluator) { |
|
||||
return applyUpdate(variableInformation, state, state, update, evaluator); |
|
||||
} |
|
||||
|
|
||||
/*! |
|
||||
* Applies an update to the given state and returns the resulting new state object. The update is evaluated |
|
||||
* over the variable values of the given base state. This methods does not modify the given state but |
|
||||
* returns a new one. |
|
||||
* |
|
||||
* @param state The state to which to apply the update. |
|
||||
* @param baseState The state used for evaluating the update. |
|
||||
* @param update The update to apply. |
|
||||
* @return The resulting state. |
|
||||
*/ |
|
||||
static StateType applyUpdate(VariableInformation const& variableInformation, StateType const& state, StateType const& baseState, storm::prism::Update const& update, storm::expressions::ExprtkExpressionEvaluator const& evaluator) { |
|
||||
StateType newState(state); |
|
||||
|
|
||||
auto assignmentIt = update.getAssignments().begin(); |
|
||||
auto assignmentIte = update.getAssignments().end(); |
|
||||
|
|
||||
// Iterate over all boolean assignments and carry them out. |
|
||||
auto boolIt = variableInformation.booleanVariables.begin(); |
|
||||
for (; assignmentIt != assignmentIte && assignmentIt->getExpression().hasBooleanType(); ++assignmentIt) { |
|
||||
while (assignmentIt->getVariable() != boolIt->variable) { |
|
||||
++boolIt; |
|
||||
} |
|
||||
newState.set(boolIt->bitOffset, evaluator.asBool(assignmentIt->getExpression())); |
|
||||
} |
|
||||
|
|
||||
// Iterate over all integer assignments and carry them out. |
|
||||
auto integerIt = variableInformation.integerVariables.begin(); |
|
||||
for (; assignmentIt != assignmentIte && assignmentIt->getExpression().hasIntegerType(); ++assignmentIt) { |
|
||||
while (assignmentIt->getVariable() != integerIt->variable) { |
|
||||
++integerIt; |
|
||||
} |
|
||||
newState.setFromInt(integerIt->bitOffset, integerIt->bitWidth, evaluator.asInt(assignmentIt->getExpression()) - integerIt->lowerBound); |
|
||||
} |
|
||||
|
|
||||
// Check that we processed all assignments. |
|
||||
STORM_LOG_ASSERT(assignmentIt == assignmentIte, "Not all assignments were consumed."); |
|
||||
|
|
||||
return newState; |
|
||||
} |
|
||||
|
|
||||
/*! |
|
||||
* Retrieves the state id of the given state. If the state has not been encountered yet, it will be added to |
|
||||
* the lists of all states with a new id. If the state was already known, the object that is pointed to by |
|
||||
* the given state pointer is deleted and the old state id is returned. Note that the pointer should not be |
|
||||
* used after invoking this method. |
|
||||
* |
|
||||
* @param state A pointer to a state for which to retrieve the index. This must not be used after the call. |
|
||||
* @param stateInformation The information about the already explored part of the reachable state space. |
|
||||
* @return A pair indicating whether the state was already discovered before and the state id of the state. |
|
||||
*/ |
|
||||
static uint32_t getOrAddStateIndex(StateType const& state, StateInformation& stateInformation, std::queue<storm::storage::BitVector>& stateQueue) { |
|
||||
uint32_t newIndex = stateInformation.reachableStates.size(); |
|
||||
|
|
||||
// Check, if the state was already registered. |
|
||||
std::pair<uint32_t, std::size_t> actualIndexBucketPair = stateInformation.stateToIndexMap.findOrAddAndGetBucket(state, newIndex); |
|
||||
|
|
||||
if (actualIndexBucketPair.first == newIndex) { |
|
||||
stateQueue.push(state); |
|
||||
stateInformation.reachableStates.push_back(state); |
|
||||
} |
|
||||
|
|
||||
return actualIndexBucketPair.first; |
|
||||
} |
|
||||
|
|
||||
/*! |
|
||||
* Retrieves all commands that are labeled with the given label and enabled in the given state, grouped by |
|
||||
* modules. |
|
||||
* |
|
||||
* This function will iterate over all modules and retrieve all commands that are labeled with the given |
|
||||
* action and active (i.e. enabled) in the current state. The result is a list of lists of commands in which |
|
||||
* the inner lists contain all commands of exactly one module. If a module does not have *any* (including |
|
||||
* disabled) commands, there will not be a list of commands of that module in the result. If, however, the |
|
||||
* module has a command with a relevant label, but no enabled one, nothing is returned to indicate that there |
|
||||
* is no legal transition possible. |
|
||||
* |
|
||||
* @param The program in which to search for active commands. |
|
||||
* @param state The current state. |
|
||||
* @param actionIndex The index of the action label to select. |
|
||||
* @return A list of lists of active commands or nothing. |
|
||||
*/ |
|
||||
static boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>> getActiveCommandsByActionIndex(storm::prism::Program const& program,storm::expressions::ExprtkExpressionEvaluator const& evaluator, uint_fast64_t const& actionIndex) { |
|
||||
boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>> result((std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>())); |
|
||||
|
|
||||
// Iterate over all modules. |
|
||||
for (uint_fast64_t i = 0; i < program.getNumberOfModules(); ++i) { |
|
||||
storm::prism::Module const& module = program.getModule(i); |
|
||||
|
|
||||
// If the module has no command labeled with the given action, we can skip this module. |
|
||||
if (!module.hasActionIndex(actionIndex)) { |
|
||||
continue; |
|
||||
} |
|
||||
|
|
||||
std::set<uint_fast64_t> const& commandIndices = module.getCommandIndicesByActionIndex(actionIndex); |
|
||||
|
|
||||
// If the module contains the action, but there is no command in the module that is labeled with |
|
||||
// this action, we don't have any feasible command combinations. |
|
||||
if (commandIndices.empty()) { |
|
||||
return boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>>(); |
|
||||
} |
|
||||
|
|
||||
std::vector<std::reference_wrapper<storm::prism::Command const>> commands; |
|
||||
|
|
||||
// Look up commands by their indices and add them if the guard evaluates to true in the given state. |
|
||||
for (uint_fast64_t commandIndex : commandIndices) { |
|
||||
storm::prism::Command const& command = module.getCommand(commandIndex); |
|
||||
if (evaluator.asBool(command.getGuardExpression())) { |
|
||||
commands.push_back(command); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
// If there was no enabled command although the module has some command with the required action label, |
|
||||
// we must not return anything. |
|
||||
if (commands.size() == 0) { |
|
||||
return boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>>(); |
|
||||
} |
|
||||
|
|
||||
result.get().push_back(std::move(commands)); |
|
||||
} |
|
||||
|
|
||||
return result; |
|
||||
} |
|
||||
|
|
||||
static std::vector<Choice<ValueType>> getUnlabeledTransitions(storm::prism::Program const& program, StateInformation& stateInformation, VariableInformation const& variableInformation, storm::storage::BitVector const& currentState, storm::expressions::ExprtkExpressionEvaluator const& evaluator, std::queue<storm::storage::BitVector>& stateQueue) { |
|
||||
std::vector<Choice<ValueType>> result; |
|
||||
|
|
||||
// Iterate over all modules. |
|
||||
for (uint_fast64_t i = 0; i < program.getNumberOfModules(); ++i) { |
|
||||
storm::prism::Module const& module = program.getModule(i); |
|
||||
|
|
||||
// Iterate over all commands. |
|
||||
for (uint_fast64_t j = 0; j < module.getNumberOfCommands(); ++j) { |
|
||||
storm::prism::Command const& command = module.getCommand(j); |
|
||||
|
|
||||
// Only consider unlabeled commands. |
|
||||
if (command.isLabeled()) continue; |
|
||||
|
|
||||
// Skip the command, if it is not enabled. |
|
||||
if (!evaluator.asBool(command.getGuardExpression())) { |
|
||||
continue; |
|
||||
} |
|
||||
|
|
||||
result.push_back(Choice<ValueType>()); |
|
||||
Choice<ValueType>& choice = result.back(); |
|
||||
choice.addChoiceLabel(command.getGlobalIndex()); |
|
||||
|
|
||||
// Iterate over all updates of the current command. |
|
||||
double probabilitySum = 0; |
|
||||
for (uint_fast64_t k = 0; k < command.getNumberOfUpdates(); ++k) { |
|
||||
storm::prism::Update const& update = command.getUpdate(k); |
|
||||
|
|
||||
// Obtain target state index and add it to the list of known states. If it has not yet been |
|
||||
// seen, we also add it to the set of states that have yet to be explored. |
|
||||
uint32_t stateIndex = getOrAddStateIndex(applyUpdate(variableInformation, currentState, update, evaluator), stateInformation, stateQueue); |
|
||||
|
|
||||
// Update the choice by adding the probability/target state to it. |
|
||||
ValueType probability = evaluator.asDouble(update.getLikelihoodExpression()); |
|
||||
choice.addProbability(stateIndex, probability); |
|
||||
probabilitySum += probability; |
|
||||
} |
|
||||
|
|
||||
// Check that the resulting distribution is in fact a distribution. |
|
||||
STORM_LOG_THROW(std::abs(1 - probabilitySum) < storm::settings::generalSettings().getPrecision(), storm::exceptions::WrongFormatException, "Probabilities do not sum to one for command '" << command << "' (actually sum to " << probabilitySum << ")."); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return result; |
|
||||
} |
|
||||
|
|
||||
static std::vector<Choice<ValueType>> getLabeledTransitions(storm::prism::Program const& program, StateInformation& stateInformation, VariableInformation const& variableInformation, storm::storage::BitVector const& currentState, storm::expressions::ExprtkExpressionEvaluator const& evaluator, std::queue<storm::storage::BitVector>& stateQueue) { |
|
||||
std::vector<Choice<ValueType>> result; |
|
||||
|
|
||||
for (uint_fast64_t actionIndex : program.getActionIndices()) { |
|
||||
boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>> optionalActiveCommandLists = getActiveCommandsByActionIndex(program, evaluator, actionIndex); |
|
||||
|
|
||||
// Only process this action label, if there is at least one feasible solution. |
|
||||
if (optionalActiveCommandLists) { |
|
||||
std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>> const& activeCommandList = optionalActiveCommandLists.get(); |
|
||||
std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>::const_iterator> iteratorList(activeCommandList.size()); |
|
||||
|
|
||||
// Initialize the list of iterators. |
|
||||
for (size_t i = 0; i < activeCommandList.size(); ++i) { |
|
||||
iteratorList[i] = activeCommandList[i].cbegin(); |
|
||||
} |
|
||||
|
|
||||
// As long as there is one feasible combination of commands, keep on expanding it. |
|
||||
bool done = false; |
|
||||
while (!done) { |
|
||||
std::unordered_map<StateType, ValueType>* currentTargetStates = new std::unordered_map<StateType, ValueType>(); |
|
||||
std::unordered_map<StateType, ValueType>* newTargetStates = new std::unordered_map<StateType, ValueType>(); |
|
||||
currentTargetStates->emplace(currentState, storm::utility::one<ValueType>()); |
|
||||
|
|
||||
// FIXME: This does not check whether a global variable is written multiple times. While the |
|
||||
// behaviour for this is undefined anyway, a warning should be issued in that case. |
|
||||
for (uint_fast64_t i = 0; i < iteratorList.size(); ++i) { |
|
||||
storm::prism::Command const& command = *iteratorList[i]; |
|
||||
|
|
||||
for (uint_fast64_t j = 0; j < command.getNumberOfUpdates(); ++j) { |
|
||||
storm::prism::Update const& update = command.getUpdate(j); |
|
||||
|
|
||||
for (auto const& stateProbabilityPair : *currentTargetStates) { |
|
||||
// Compute the new state under the current update and add it to the set of new target states. |
|
||||
StateType newTargetState = applyUpdate(variableInformation, stateProbabilityPair.first, currentState, update, evaluator); |
|
||||
newTargetStates->emplace(newTargetState, stateProbabilityPair.second * evaluator.asDouble(update.getLikelihoodExpression())); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
// If there is one more command to come, shift the target states one time step back. |
|
||||
if (i < iteratorList.size() - 1) { |
|
||||
delete currentTargetStates; |
|
||||
currentTargetStates = newTargetStates; |
|
||||
newTargetStates = new std::unordered_map<StateType, ValueType>(); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
// At this point, we applied all commands of the current command combination and newTargetStates |
|
||||
// contains all target states and their respective probabilities. That means we are now ready to |
|
||||
// add the choice to the list of transitions. |
|
||||
result.push_back(Choice<ValueType>(actionIndex)); |
|
||||
|
|
||||
// Now create the actual distribution. |
|
||||
Choice<ValueType>& choice = result.back(); |
|
||||
|
|
||||
// Add the labels of all commands to this choice. |
|
||||
for (uint_fast64_t i = 0; i < iteratorList.size(); ++i) { |
|
||||
choice.addChoiceLabel(iteratorList[i]->get().getGlobalIndex()); |
|
||||
} |
|
||||
|
|
||||
double probabilitySum = 0; |
|
||||
for (auto const& stateProbabilityPair : *newTargetStates) { |
|
||||
uint32_t actualIndex = getOrAddStateIndex(stateProbabilityPair.first, stateInformation, stateQueue); |
|
||||
choice.addProbability(actualIndex, stateProbabilityPair.second); |
|
||||
probabilitySum += stateProbabilityPair.second; |
|
||||
} |
|
||||
|
|
||||
// Check that the resulting distribution is in fact a distribution. |
|
||||
STORM_LOG_THROW(std::abs(1 - probabilitySum) <= storm::settings::generalSettings().getPrecision(), storm::exceptions::WrongFormatException, "Sum of update probabilities do not some to one for some command (actually sum to " << probabilitySum << ")."); |
|
||||
|
|
||||
// Dispose of the temporary maps. |
|
||||
delete currentTargetStates; |
|
||||
delete newTargetStates; |
|
||||
|
|
||||
// Now, check whether there is one more command combination to consider. |
|
||||
bool movedIterator = false; |
|
||||
for (int_fast64_t j = iteratorList.size() - 1; j >= 0; --j) { |
|
||||
++iteratorList[j]; |
|
||||
if (iteratorList[j] != activeCommandList[j].end()) { |
|
||||
movedIterator = true; |
|
||||
} else { |
|
||||
// Reset the iterator to the beginning of the list. |
|
||||
iteratorList[j] = activeCommandList[j].begin(); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
done = !movedIterator; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return result; |
|
||||
} |
|
||||
|
|
||||
/*! |
|
||||
* Builds the transition matrix and the transition reward matrix based for the given program. |
|
||||
* |
|
||||
* @param program The program for which to build the matrices. |
|
||||
* @param variableInformation A structure containing information about the variables in the program. |
|
||||
* @param transitionRewards A list of transition rewards that are to be considered in the transition reward |
|
||||
* matrix. |
|
||||
* @param stateInformation A structure containing information about the states of the program. |
|
||||
* @param deterministicModel A flag indicating whether the model is supposed to be deterministic or not. |
|
||||
* @param transitionMatrix A reference to an initialized matrix which is filled with all transitions by this |
|
||||
* function. |
|
||||
* @param transitionRewardMatrix A reference to an initialized matrix which is filled with all transition |
|
||||
* rewards by this function. |
|
||||
* @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. |
|
||||
*/ |
|
||||
static std::vector<boost::container::flat_set<uint_fast64_t>> buildMatrices(storm::prism::Program const& program, VariableInformation const& variableInformation, std::vector<storm::prism::TransitionReward> const& transitionRewards, StateInformation& stateInformation, bool deterministicModel, storm::storage::SparseMatrixBuilder<ValueType>& transitionMatrixBuilder, storm::storage::SparseMatrixBuilder<ValueType>& transitionRewardMatrixBuilder) { |
|
||||
std::vector<boost::container::flat_set<uint_fast64_t>> choiceLabels; |
|
||||
|
|
||||
// Initialize a queue and insert the initial state. |
|
||||
std::queue<storm::storage::BitVector> stateQueue; |
|
||||
StateType initialState(stateInformation.bitsPerState); |
|
||||
|
|
||||
// We need to initialize the values of the variables to their initial value. |
|
||||
for (auto const& booleanVariable : variableInformation.booleanVariables) { |
|
||||
initialState.set(booleanVariable.bitOffset, booleanVariable.initialValue); |
|
||||
} |
|
||||
for (auto const& integerVariable : variableInformation.integerVariables) { |
|
||||
initialState.setFromInt(integerVariable.bitOffset, integerVariable.bitWidth, static_cast<uint_fast64_t>(integerVariable.initialValue - integerVariable.lowerBound)); |
|
||||
} |
|
||||
|
|
||||
// Insert the initial state in the global state to index mapping and state queue. |
|
||||
uint32_t stateIndex = getOrAddStateIndex(initialState, stateInformation, stateQueue); |
|
||||
stateInformation.initialStateIndices.push_back(stateIndex); |
|
||||
|
|
||||
// Now explore the current state until there is no more reachable state. |
|
||||
uint_fast64_t currentRow = 0; |
|
||||
storm::expressions::ExprtkExpressionEvaluator evaluator(program.getManager()); |
|
||||
while (!stateQueue.empty()) { |
|
||||
// Get the current state and unpack it. |
|
||||
storm::storage::BitVector currentState = stateQueue.front(); |
|
||||
stateQueue.pop(); |
|
||||
ValueType stateIndex = stateInformation.stateToIndexMap.getValue(currentState); |
|
||||
unpackStateIntoEvaluator(currentState, variableInformation, evaluator); |
|
||||
|
|
||||
// Retrieve all choices for the current state. |
|
||||
std::vector<Choice<ValueType>> allUnlabeledChoices = getUnlabeledTransitions(program, stateInformation, variableInformation, currentState, evaluator, stateQueue); |
|
||||
std::vector<Choice<ValueType>> allLabeledChoices = getLabeledTransitions(program, stateInformation, variableInformation, currentState, evaluator, stateQueue); |
|
||||
|
|
||||
uint_fast64_t totalNumberOfChoices = allUnlabeledChoices.size() + allLabeledChoices.size(); |
|
||||
|
|
||||
// If the current state does not have a single choice, we equip it with a self-loop if that was |
|
||||
// requested and issue an error otherwise. |
|
||||
if (totalNumberOfChoices == 0) { |
|
||||
if (!storm::settings::generalSettings().isDontFixDeadlocksSet()) { |
|
||||
// Insert empty choice labeling for added self-loop transitions. |
|
||||
choiceLabels.push_back(boost::container::flat_set<uint_fast64_t>()); |
|
||||
transitionMatrixBuilder.addNextValue(currentRow, stateIndex, storm::utility::one<ValueType>()); |
|
||||
++currentRow; |
|
||||
} else { |
|
||||
LOG4CPLUS_ERROR(logger, "Error while creating sparse matrix from probabilistic program: found deadlock state. For fixing these, please provide the appropriate option."); |
|
||||
throw storm::exceptions::WrongFormatException() << "Error while creating sparse matrix from probabilistic program: found deadlock state. For fixing these, please provide the appropriate option."; |
|
||||
} |
|
||||
} else { |
|
||||
// Then, based on whether the model is deterministic or not, either add the choices individually |
|
||||
// or compose them to one choice. |
|
||||
if (deterministicModel) { |
|
||||
Choice<ValueType> globalChoice; |
|
||||
std::map<uint32_t, ValueType> stateToRewardMap; |
|
||||
|
|
||||
// Combine all the choices and scale them with the total number of choices of the current state. |
|
||||
for (auto const& choice : allUnlabeledChoices) { |
|
||||
globalChoice.addChoiceLabels(choice.getChoiceLabels()); |
|
||||
for (auto const& stateProbabilityPair : choice) { |
|
||||
globalChoice.getOrAddEntry(stateProbabilityPair.first) += stateProbabilityPair.second / totalNumberOfChoices; |
|
||||
|
|
||||
// Now add all rewards that match this choice. |
|
||||
for (auto const& transitionReward : transitionRewards) { |
|
||||
if (!transitionReward.isLabeled() && evaluator.asBool(transitionReward.getStatePredicateExpression())) { |
|
||||
stateToRewardMap[stateProbabilityPair.first] += ValueType(evaluator.asDouble(transitionReward.getRewardValueExpression())); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
for (auto const& choice : allLabeledChoices) { |
|
||||
globalChoice.addChoiceLabels(choice.getChoiceLabels()); |
|
||||
for (auto const& stateProbabilityPair : choice) { |
|
||||
globalChoice.getOrAddEntry(stateProbabilityPair.first) += stateProbabilityPair.second / totalNumberOfChoices; |
|
||||
|
|
||||
// Now add all rewards that match this choice. |
|
||||
for (auto const& transitionReward : transitionRewards) { |
|
||||
if (transitionReward.getActionIndex() == choice.getActionIndex() && evaluator.asBool(transitionReward.getStatePredicateExpression())) { |
|
||||
stateToRewardMap[stateProbabilityPair.first] += ValueType(evaluator.asDouble(transitionReward.getRewardValueExpression())); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
|
|
||||
// Now add the resulting distribution as the only choice of the current state. |
|
||||
choiceLabels.push_back(globalChoice.getChoiceLabels()); |
|
||||
|
|
||||
for (auto const& stateProbabilityPair : globalChoice) { |
|
||||
transitionMatrixBuilder.addNextValue(currentRow, stateProbabilityPair.first, stateProbabilityPair.second); |
|
||||
} |
|
||||
|
|
||||
// Add all transition rewards to the matrix and add dummy entry if there is none. |
|
||||
if (stateToRewardMap.size() > 0) { |
|
||||
for (auto const& stateRewardPair : stateToRewardMap) { |
|
||||
transitionRewardMatrixBuilder.addNextValue(currentRow, stateRewardPair.first, stateRewardPair.second); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
++currentRow; |
|
||||
} else { |
|
||||
// If the model is nondeterministic, we add all choices individually. |
|
||||
transitionMatrixBuilder.newRowGroup(currentRow); |
|
||||
transitionRewardMatrixBuilder.newRowGroup(currentRow); |
|
||||
|
|
||||
// First, process all unlabeled choices. |
|
||||
for (auto const& choice : allUnlabeledChoices) { |
|
||||
std::map<uint_fast64_t, ValueType> stateToRewardMap; |
|
||||
choiceLabels.emplace_back(std::move(choice.getChoiceLabels())); |
|
||||
|
|
||||
for (auto const& stateProbabilityPair : choice) { |
|
||||
transitionMatrixBuilder.addNextValue(currentRow, stateProbabilityPair.first, stateProbabilityPair.second); |
|
||||
|
|
||||
// Now add all rewards that match this choice. |
|
||||
for (auto const& transitionReward : transitionRewards) { |
|
||||
if (!transitionReward.isLabeled() && evaluator.asBool(transitionReward.getStatePredicateExpression())) { |
|
||||
stateToRewardMap[stateProbabilityPair.first] += ValueType(evaluator.asDouble(transitionReward.getRewardValueExpression())); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
} |
|
||||
|
|
||||
// Add all transition rewards to the matrix and add dummy entry if there is none. |
|
||||
if (stateToRewardMap.size() > 0) { |
|
||||
for (auto const& stateRewardPair : stateToRewardMap) { |
|
||||
transitionRewardMatrixBuilder.addNextValue(currentRow, stateRewardPair.first, stateRewardPair.second); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
++currentRow; |
|
||||
} |
|
||||
|
|
||||
// Then, process all labeled choices. |
|
||||
for (auto const& choice : allLabeledChoices) { |
|
||||
std::map<uint_fast64_t, ValueType> stateToRewardMap; |
|
||||
choiceLabels.emplace_back(std::move(choice.getChoiceLabels())); |
|
||||
|
|
||||
for (auto const& stateProbabilityPair : choice) { |
|
||||
transitionMatrixBuilder.addNextValue(currentRow, stateProbabilityPair.first, stateProbabilityPair.second); |
|
||||
|
|
||||
// Now add all rewards that match this choice. |
|
||||
for (auto const& transitionReward : transitionRewards) { |
|
||||
if (transitionReward.getActionIndex() == choice.getActionIndex() && evaluator.asBool(transitionReward.getStatePredicateExpression())) { |
|
||||
stateToRewardMap[stateProbabilityPair.first] += ValueType(evaluator.asDouble(transitionReward.getRewardValueExpression())); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
} |
|
||||
|
|
||||
// Add all transition rewards to the matrix and add dummy entry if there is none. |
|
||||
if (stateToRewardMap.size() > 0) { |
|
||||
for (auto const& stateRewardPair : stateToRewardMap) { |
|
||||
transitionRewardMatrixBuilder.addNextValue(currentRow, stateRewardPair.first, stateRewardPair.second); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
++currentRow; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return choiceLabels; |
|
||||
} |
|
||||
|
|
||||
/*! |
|
||||
* Explores the state space of the given program and returns the components of the model as a result. |
|
||||
* |
|
||||
* @param program The program whose state space to explore. |
|
||||
* @param rewardModel The reward model that is to be considered. |
|
||||
* @return A structure containing the components of the resulting model. |
|
||||
*/ |
|
||||
static ModelComponents buildModelComponents(storm::prism::Program const& program, storm::prism::RewardModel const& rewardModel) { |
|
||||
ModelComponents modelComponents; |
|
||||
|
|
||||
uint_fast64_t bitOffset = 0; |
|
||||
VariableInformation variableInformation; |
|
||||
for (auto const& booleanVariable : program.getGlobalBooleanVariables()) { |
|
||||
variableInformation.booleanVariables.emplace_back(booleanVariable.getExpressionVariable(), booleanVariable.getInitialValueExpression().evaluateAsBool(), bitOffset); |
|
||||
++bitOffset; |
|
||||
variableInformation.booleanVariableToIndexMap[booleanVariable.getExpressionVariable()] = variableInformation.booleanVariables.size() - 1; |
|
||||
} |
|
||||
for (auto const& integerVariable : program.getGlobalIntegerVariables()) { |
|
||||
int_fast64_t lowerBound = integerVariable.getLowerBoundExpression().evaluateAsInt(); |
|
||||
int_fast64_t upperBound = integerVariable.getUpperBoundExpression().evaluateAsInt(); |
|
||||
uint_fast64_t bitwidth = static_cast<uint_fast64_t>(std::ceil(std::log2(upperBound - lowerBound + 1))); |
|
||||
variableInformation.integerVariables.emplace_back(integerVariable.getExpressionVariable(), integerVariable.getInitialValueExpression().evaluateAsInt(), lowerBound, upperBound, bitOffset, bitwidth); |
|
||||
bitOffset += bitwidth; |
|
||||
variableInformation.integerVariableToIndexMap[integerVariable.getExpressionVariable()] = variableInformation.integerVariables.size() - 1; |
|
||||
} |
|
||||
for (auto const& module : program.getModules()) { |
|
||||
for (auto const& booleanVariable : module.getBooleanVariables()) { |
|
||||
variableInformation.booleanVariables.emplace_back(booleanVariable.getExpressionVariable(), booleanVariable.getInitialValueExpression().evaluateAsBool(), bitOffset); |
|
||||
++bitOffset; |
|
||||
variableInformation.booleanVariableToIndexMap[booleanVariable.getExpressionVariable()] = variableInformation.booleanVariables.size() - 1; |
|
||||
} |
|
||||
for (auto const& integerVariable : module.getIntegerVariables()) { |
|
||||
int_fast64_t lowerBound = integerVariable.getLowerBoundExpression().evaluateAsInt(); |
|
||||
int_fast64_t upperBound = integerVariable.getUpperBoundExpression().evaluateAsInt(); |
|
||||
uint_fast64_t bitwidth = static_cast<uint_fast64_t>(std::ceil(std::log2(upperBound - lowerBound + 1))); |
|
||||
variableInformation.integerVariables.emplace_back(integerVariable.getExpressionVariable(), integerVariable.getInitialValueExpression().evaluateAsInt(), lowerBound, upperBound, bitOffset, bitwidth); |
|
||||
bitOffset += bitwidth; |
|
||||
variableInformation.integerVariableToIndexMap[integerVariable.getExpressionVariable()] = variableInformation.integerVariables.size() - 1; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
// Create the structure for storing the reachable state space. |
|
||||
uint64_t bitsPerState = ((bitOffset / 64) + 1) * 64; |
|
||||
StateInformation stateInformation(bitsPerState); |
|
||||
|
|
||||
// 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.getModelType() == storm::prism::Program::ModelType::DTMC || program.getModelType() == storm::prism::Program::ModelType::CTMC; |
|
||||
|
|
||||
// Build the transition and reward matrices. |
|
||||
storm::storage::SparseMatrixBuilder<ValueType> transitionMatrixBuilder(0, 0, 0, false, !deterministicModel, 0); |
|
||||
storm::storage::SparseMatrixBuilder<ValueType> transitionRewardMatrixBuilder(0, 0, 0, false, !deterministicModel, 0); |
|
||||
modelComponents.choiceLabeling = buildMatrices(program, variableInformation, rewardModel.getTransitionRewards(), stateInformation, deterministicModel, transitionMatrixBuilder, transitionRewardMatrixBuilder); |
|
||||
|
|
||||
// Finalize the resulting matrices. |
|
||||
modelComponents.transitionMatrix = transitionMatrixBuilder.build(); |
|
||||
modelComponents.transitionRewardMatrix = transitionRewardMatrixBuilder.build(modelComponents.transitionMatrix.getRowCount(), modelComponents.transitionMatrix.getColumnCount(), modelComponents.transitionMatrix.getRowGroupCount()); |
|
||||
|
|
||||
// Now build the state labeling. |
|
||||
modelComponents.stateLabeling = buildStateLabeling(program, variableInformation, stateInformation); |
|
||||
|
|
||||
// Finally, construct the state rewards. |
|
||||
modelComponents.stateRewards = buildStateRewards(program, variableInformation, rewardModel.getStateRewards(), stateInformation); |
|
||||
|
|
||||
return modelComponents; |
|
||||
} |
|
||||
|
|
||||
/*! |
|
||||
* Builds the state labeling for the given program. |
|
||||
* |
|
||||
* @param program The program for which to build the state labeling. |
|
||||
* @param variableInformation Information about the variables in the program. |
|
||||
* @param stateInformation Information about the state space of the program. |
|
||||
* @return The state labeling of the given program. |
|
||||
*/ |
|
||||
static storm::models::AtomicPropositionsLabeling buildStateLabeling(storm::prism::Program const& program, VariableInformation const& variableInformation, StateInformation const& stateInformation) { |
|
||||
storm::expressions::ExprtkExpressionEvaluator evaluator(program.getManager()); |
|
||||
|
|
||||
std::vector<storm::prism::Label> const& labels = program.getLabels(); |
|
||||
|
|
||||
storm::models::AtomicPropositionsLabeling result(stateInformation.reachableStates.size(), labels.size() + 1); |
|
||||
|
|
||||
// Initialize labeling. |
|
||||
for (auto const& label : labels) { |
|
||||
result.addAtomicProposition(label.getName()); |
|
||||
} |
|
||||
for (uint_fast64_t index = 0; index < stateInformation.reachableStates.size(); index++) { |
|
||||
unpackStateIntoEvaluator(stateInformation.reachableStates[index], variableInformation, evaluator); |
|
||||
for (auto const& label : labels) { |
|
||||
// Add label to state, if the corresponding expression is true. |
|
||||
if (evaluator.asBool(label.getStatePredicateExpression())) { |
|
||||
result.addAtomicPropositionToState(label.getName(), index); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
// Also label the initial state with the special label "init". |
|
||||
result.addAtomicProposition("init"); |
|
||||
for (auto index : stateInformation.initialStateIndices) { |
|
||||
result.addAtomicPropositionToState("init", index); |
|
||||
} |
|
||||
|
|
||||
return result; |
|
||||
} |
|
||||
|
|
||||
/*! |
|
||||
* Builds the state rewards for the given state space. |
|
||||
* |
|
||||
* @param rewards A vector of state rewards to consider. |
|
||||
* @param stateInformation Information about the state space. |
|
||||
* @return A vector containing the state rewards for the state space. |
|
||||
*/ |
|
||||
static std::vector<ValueType> buildStateRewards(storm::prism::Program const& program, VariableInformation const& variableInformation, std::vector<storm::prism::StateReward> const& rewards, StateInformation const& stateInformation) { |
|
||||
storm::expressions::ExprtkExpressionEvaluator evaluator(program.getManager()); |
|
||||
|
|
||||
std::vector<ValueType> result(stateInformation.reachableStates.size()); |
|
||||
for (uint_fast64_t index = 0; index < stateInformation.reachableStates.size(); index++) { |
|
||||
result[index] = storm::utility::zero<ValueType>(); |
|
||||
unpackStateIntoEvaluator(stateInformation.reachableStates[index], variableInformation, evaluator); |
|
||||
for (auto const& reward : rewards) { |
|
||||
|
|
||||
// Add this reward to the state if the state is included in the state reward. |
|
||||
if (evaluator.asBool(reward.getStatePredicateExpression())) { |
|
||||
result[index] += ValueType(evaluator.asDouble(reward.getRewardValueExpression())); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
return result; |
|
||||
} |
|
||||
}; |
|
||||
|
|
||||
} // namespace adapters |
|
||||
} // namespace storm |
|
||||
|
|
||||
#endif /* STORM_ADAPTERS_EXPLICITMODELADAPTER_H */ |
|
@ -0,0 +1,616 @@ |
|||||
|
#include "src/builder/ExplicitPrismModelBuilder.h"
|
||||
|
|
||||
|
namespace storm { |
||||
|
namespace builder { |
||||
|
template <typename ValueType, typename IndexType> |
||||
|
ExplicitPrismModelBuilder<ValueType, IndexType>::StateInformation::StateInformation(uint64_t bitsPerState) : stateStorage(bitsPerState, 1000000), bitsPerState(bitsPerState), reachableStates() { |
||||
|
// Intentionally left empty.
|
||||
|
} |
||||
|
|
||||
|
template <typename ValueType, typename IndexType> |
||||
|
ExplicitPrismModelBuilder<ValueType, IndexType>::VariableInformation::BooleanVariableInformation::BooleanVariableInformation(storm::expressions::Variable const& variable, bool initialValue, uint_fast64_t bitOffset) : variable(variable), initialValue(initialValue), bitOffset(bitOffset) { |
||||
|
// Intentionally left empty.
|
||||
|
} |
||||
|
|
||||
|
template <typename ValueType, typename IndexType> |
||||
|
ExplicitPrismModelBuilder<ValueType, IndexType>::VariableInformation::IntegerVariableInformation::IntegerVariableInformation(storm::expressions::Variable const& variable, int_fast64_t initialValue, int_fast64_t lowerBound, int_fast64_t upperBound, uint_fast64_t bitOffset, uint_fast64_t bitWidth) : variable(variable), initialValue(initialValue), lowerBound(lowerBound), upperBound(upperBound), bitOffset(bitOffset), bitWidth(bitWidth) { |
||||
|
// Intentionally left empty.
|
||||
|
} |
||||
|
|
||||
|
template <typename ValueType, typename IndexType> |
||||
|
uint_fast64_t ExplicitPrismModelBuilder<ValueType, IndexType>::VariableInformation::getBitOffset(storm::expressions::Variable const& variable) const { |
||||
|
auto const& booleanIndex = booleanVariableToIndexMap.find(variable); |
||||
|
if (booleanIndex != booleanVariableToIndexMap.end()) { |
||||
|
return booleanVariables[booleanIndex].bitOffset; |
||||
|
} |
||||
|
auto const& integerIndex = integerVariableToIndexMap.find(variable); |
||||
|
if (integerIndex != integerVariableToIndexMap.end()) { |
||||
|
return integerVariables[integerIndex].bitOffset; |
||||
|
} |
||||
|
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Cannot look-up bit index of unknown variable."); |
||||
|
} |
||||
|
|
||||
|
template <typename ValueType, typename IndexType> |
||||
|
uint_fast64_t ExplicitPrismModelBuilder<ValueType, IndexType>::VariableInformation::getBitWidth(storm::expressions::Variable const& variable) const { |
||||
|
auto const& integerIndex = integerVariableToIndexMap.find(variable); |
||||
|
if (integerIndex != integerVariableToIndexMap.end()) { |
||||
|
return integerVariables[integerIndex].bitWidth; |
||||
|
} |
||||
|
STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Cannot look-up bit width of unknown variable."); |
||||
|
} |
||||
|
|
||||
|
template <typename ValueType, typename IndexType> |
||||
|
ExplicitPrismModelBuilder<ValueType, IndexType>::ModelComponents::ModelComponents() : transitionMatrix(), stateLabeling(), stateRewards(), transitionRewardMatrix(), choiceLabeling() { |
||||
|
// Intentionally left empty.
|
||||
|
} |
||||
|
|
||||
|
template <typename ValueType, typename IndexType> |
||||
|
std::unique_ptr<storm::models::AbstractModel<ValueType>> ExplicitPrismModelBuilder<ValueType, IndexType>::translateProgram(storm::prism::Program program, bool rewards, std::string const& rewardModelName, std::string const& constantDefinitionString) { |
||||
|
// Start by defining the undefined constants in the model.
|
||||
|
// First, we need to parse the constant definition string.
|
||||
|
std::map<storm::expressions::Variable, storm::expressions::Expression> constantDefinitions = storm::utility::prism::parseConstantDefinitionString(program, constantDefinitionString); |
||||
|
|
||||
|
storm::prism::Program preparedProgram = program.defineUndefinedConstants(constantDefinitions); |
||||
|
STORM_LOG_THROW(!preparedProgram.hasUndefinedConstants(), storm::exceptions::InvalidArgumentException, "Program still contains undefined constants."); |
||||
|
|
||||
|
// Now that we have defined all the constants in the program, we need to substitute their appearances in
|
||||
|
// all expressions in the program so we can then evaluate them without having to store the values of the
|
||||
|
// constants in the state (i.e., valuation).
|
||||
|
preparedProgram = preparedProgram.substituteConstants(); |
||||
|
storm::prism::RewardModel rewardModel = storm::prism::RewardModel(); |
||||
|
|
||||
|
// Select the appropriate reward model.
|
||||
|
if (rewards) { |
||||
|
// If a specific reward model was selected or one with the empty name exists, select it.
|
||||
|
if (rewardModelName != "" || preparedProgram.hasRewardModel(rewardModelName)) { |
||||
|
rewardModel = preparedProgram.getRewardModel(rewardModelName); |
||||
|
} else if (preparedProgram.hasRewardModel()) { |
||||
|
// Otherwise, we select the first one.
|
||||
|
rewardModel = preparedProgram.getRewardModel(0); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
ModelComponents modelComponents = buildModelComponents(preparedProgram, rewardModel); |
||||
|
|
||||
|
std::unique_ptr<storm::models::AbstractModel<ValueType>> result; |
||||
|
switch (program.getModelType()) { |
||||
|
case storm::prism::Program::ModelType::DTMC: |
||||
|
result = std::unique_ptr<storm::models::AbstractModel<ValueType>>(new storm::models::Dtmc<ValueType>(std::move(modelComponents.transitionMatrix), std::move(modelComponents.stateLabeling), rewardModel.hasStateRewards() ? std::move(modelComponents.stateRewards) : boost::optional<std::vector<ValueType>>(), rewardModel.hasTransitionRewards() ? std::move(modelComponents.transitionRewardMatrix) : boost::optional<storm::storage::SparseMatrix<ValueType>>(), std::move(modelComponents.choiceLabeling))); |
||||
|
break; |
||||
|
case storm::prism::Program::ModelType::CTMC: |
||||
|
result = std::unique_ptr<storm::models::AbstractModel<ValueType>>(new storm::models::Ctmc<ValueType>(std::move(modelComponents.transitionMatrix), std::move(modelComponents.stateLabeling), rewardModel.hasStateRewards() ? std::move(modelComponents.stateRewards) : boost::optional<std::vector<ValueType>>(), rewardModel.hasTransitionRewards() ? std::move(modelComponents.transitionRewardMatrix) : boost::optional<storm::storage::SparseMatrix<ValueType>>(), std::move(modelComponents.choiceLabeling))); |
||||
|
break; |
||||
|
case storm::prism::Program::ModelType::MDP: |
||||
|
result = std::unique_ptr<storm::models::AbstractModel<ValueType>>(new storm::models::Mdp<ValueType>(std::move(modelComponents.transitionMatrix), std::move(modelComponents.stateLabeling), rewardModel.hasStateRewards() ? std::move(modelComponents.stateRewards) : boost::optional<std::vector<ValueType>>(), rewardModel.hasTransitionRewards() ? std::move(modelComponents.transitionRewardMatrix) : boost::optional<storm::storage::SparseMatrix<ValueType>>(), std::move(modelComponents.choiceLabeling))); |
||||
|
break; |
||||
|
case storm::prism::Program::ModelType::CTMDP: |
||||
|
result = std::unique_ptr<storm::models::AbstractModel<ValueType>>(new storm::models::Ctmdp<ValueType>(std::move(modelComponents.transitionMatrix), std::move(modelComponents.stateLabeling), rewardModel.hasStateRewards() ? std::move(modelComponents.stateRewards) : boost::optional<std::vector<ValueType>>(), rewardModel.hasTransitionRewards() ? std::move(modelComponents.transitionRewardMatrix) : boost::optional<storm::storage::SparseMatrix<ValueType>>(), std::move(modelComponents.choiceLabeling))); |
||||
|
break; |
||||
|
default: |
||||
|
LOG4CPLUS_ERROR(logger, "Error while creating model from probabilistic program: cannot handle this model type."); |
||||
|
throw storm::exceptions::WrongFormatException() << "Error while creating model from probabilistic program: cannot handle this model type."; |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
template <typename ValueType, typename IndexType> |
||||
|
void ExplicitPrismModelBuilder<ValueType, IndexType>::unpackStateIntoEvaluator(storm::storage::BitVector const& currentState, VariableInformation const& variableInformation, storm::expressions::ExprtkExpressionEvaluator& evaluator) { |
||||
|
for (auto const& booleanVariable : variableInformation.booleanVariables) { |
||||
|
evaluator.setBooleanValue(booleanVariable.variable, currentState.get(booleanVariable.bitOffset)); |
||||
|
} |
||||
|
for (auto const& integerVariable : variableInformation.integerVariables) { |
||||
|
evaluator.setIntegerValue(integerVariable.variable, currentState.getAsInt(integerVariable.bitOffset, integerVariable.bitWidth) + integerVariable.lowerBound); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
template <typename ValueType, typename IndexType> |
||||
|
typename ExplicitPrismModelBuilder<ValueType, IndexType>::CompressedState ExplicitPrismModelBuilder<ValueType, IndexType>::applyUpdate(VariableInformation const& variableInformation, CompressedState const& state, storm::prism::Update const& update, storm::expressions::ExprtkExpressionEvaluator const& evaluator) { |
||||
|
return applyUpdate(variableInformation, state, state, update, evaluator); |
||||
|
} |
||||
|
|
||||
|
template <typename ValueType, typename IndexType> |
||||
|
typename ExplicitPrismModelBuilder<ValueType, IndexType>::CompressedState ExplicitPrismModelBuilder<ValueType, IndexType>::applyUpdate(VariableInformation const& variableInformation, CompressedState const& state, CompressedState const& baseState, storm::prism::Update const& update, storm::expressions::ExprtkExpressionEvaluator const& evaluator) { |
||||
|
CompressedState newState(state); |
||||
|
|
||||
|
auto assignmentIt = update.getAssignments().begin(); |
||||
|
auto assignmentIte = update.getAssignments().end(); |
||||
|
|
||||
|
// Iterate over all boolean assignments and carry them out.
|
||||
|
auto boolIt = variableInformation.booleanVariables.begin(); |
||||
|
for (; assignmentIt != assignmentIte && assignmentIt->getExpression().hasBooleanType(); ++assignmentIt) { |
||||
|
while (assignmentIt->getVariable() != boolIt->variable) { |
||||
|
++boolIt; |
||||
|
} |
||||
|
newState.set(boolIt->bitOffset, evaluator.asBool(assignmentIt->getExpression())); |
||||
|
} |
||||
|
|
||||
|
// Iterate over all integer assignments and carry them out.
|
||||
|
auto integerIt = variableInformation.integerVariables.begin(); |
||||
|
for (; assignmentIt != assignmentIte && assignmentIt->getExpression().hasIntegerType(); ++assignmentIt) { |
||||
|
while (assignmentIt->getVariable() != integerIt->variable) { |
||||
|
++integerIt; |
||||
|
} |
||||
|
newState.setFromInt(integerIt->bitOffset, integerIt->bitWidth, evaluator.asInt(assignmentIt->getExpression()) - integerIt->lowerBound); |
||||
|
} |
||||
|
|
||||
|
// Check that we processed all assignments.
|
||||
|
STORM_LOG_ASSERT(assignmentIt == assignmentIte, "Not all assignments were consumed."); |
||||
|
|
||||
|
return newState; |
||||
|
} |
||||
|
|
||||
|
template <typename ValueType, typename IndexType> |
||||
|
IndexType ExplicitPrismModelBuilder<ValueType, IndexType>::getOrAddStateIndex(CompressedState const& state, StateInformation& stateInformation, std::queue<storm::storage::BitVector>& stateQueue) { |
||||
|
uint32_t newIndex = stateInformation.reachableStates.size(); |
||||
|
|
||||
|
// Check, if the state was already registered.
|
||||
|
std::pair<uint32_t, std::size_t> actualIndexBucketPair = stateInformation.stateStorage.findOrAddAndGetBucket(state, newIndex); |
||||
|
|
||||
|
if (actualIndexBucketPair.first == newIndex) { |
||||
|
stateQueue.push(state); |
||||
|
stateInformation.reachableStates.push_back(state); |
||||
|
} |
||||
|
|
||||
|
return actualIndexBucketPair.first; |
||||
|
} |
||||
|
|
||||
|
template <typename ValueType, typename IndexType> |
||||
|
boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>> ExplicitPrismModelBuilder<ValueType, IndexType>::getActiveCommandsByActionIndex(storm::prism::Program const& program,storm::expressions::ExprtkExpressionEvaluator const& evaluator, uint_fast64_t const& actionIndex) { |
||||
|
boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>> result((std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>())); |
||||
|
|
||||
|
// Iterate over all modules.
|
||||
|
for (uint_fast64_t i = 0; i < program.getNumberOfModules(); ++i) { |
||||
|
storm::prism::Module const& module = program.getModule(i); |
||||
|
|
||||
|
// If the module has no command labeled with the given action, we can skip this module.
|
||||
|
if (!module.hasActionIndex(actionIndex)) { |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
std::set<uint_fast64_t> const& commandIndices = module.getCommandIndicesByActionIndex(actionIndex); |
||||
|
|
||||
|
// If the module contains the action, but there is no command in the module that is labeled with
|
||||
|
// this action, we don't have any feasible command combinations.
|
||||
|
if (commandIndices.empty()) { |
||||
|
return boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>>(); |
||||
|
} |
||||
|
|
||||
|
std::vector<std::reference_wrapper<storm::prism::Command const>> commands; |
||||
|
|
||||
|
// Look up commands by their indices and add them if the guard evaluates to true in the given state.
|
||||
|
for (uint_fast64_t commandIndex : commandIndices) { |
||||
|
storm::prism::Command const& command = module.getCommand(commandIndex); |
||||
|
if (evaluator.asBool(command.getGuardExpression())) { |
||||
|
commands.push_back(command); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// If there was no enabled command although the module has some command with the required action label,
|
||||
|
// we must not return anything.
|
||||
|
if (commands.size() == 0) { |
||||
|
return boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>>(); |
||||
|
} |
||||
|
|
||||
|
result.get().push_back(std::move(commands)); |
||||
|
} |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
template <typename ValueType, typename IndexType> |
||||
|
static std::vector<Choice<ValueType>> ExplicitPrismModelBuilder<ValueType, IndexType>::getUnlabeledTransitions(storm::prism::Program const& program, StateInformation& stateInformation, VariableInformation const& variableInformation, storm::storage::BitVector const& currentState, storm::expressions::ExprtkExpressionEvaluator const& evaluator, std::queue<storm::storage::BitVector>& stateQueue) { |
||||
|
std::vector<Choice<ValueType>> result; |
||||
|
|
||||
|
// Iterate over all modules.
|
||||
|
for (uint_fast64_t i = 0; i < program.getNumberOfModules(); ++i) { |
||||
|
storm::prism::Module const& module = program.getModule(i); |
||||
|
|
||||
|
// Iterate over all commands.
|
||||
|
for (uint_fast64_t j = 0; j < module.getNumberOfCommands(); ++j) { |
||||
|
storm::prism::Command const& command = module.getCommand(j); |
||||
|
|
||||
|
// Only consider unlabeled commands.
|
||||
|
if (command.isLabeled()) continue; |
||||
|
|
||||
|
// Skip the command, if it is not enabled.
|
||||
|
if (!evaluator.asBool(command.getGuardExpression())) { |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
result.push_back(Choice<ValueType>()); |
||||
|
Choice<ValueType>& choice = result.back(); |
||||
|
choice.addChoiceLabel(command.getGlobalIndex()); |
||||
|
|
||||
|
// Iterate over all updates of the current command.
|
||||
|
double probabilitySum = 0; |
||||
|
for (uint_fast64_t k = 0; k < command.getNumberOfUpdates(); ++k) { |
||||
|
storm::prism::Update const& update = command.getUpdate(k); |
||||
|
|
||||
|
// Obtain target state index and add it to the list of known states. If it has not yet been
|
||||
|
// seen, we also add it to the set of states that have yet to be explored.
|
||||
|
uint32_t stateIndex = getOrAddStateIndex(applyUpdate(variableInformation, currentState, update, evaluator), stateInformation, stateQueue); |
||||
|
|
||||
|
// Update the choice by adding the probability/target state to it.
|
||||
|
ValueType probability = evaluator.asDouble(update.getLikelihoodExpression()); |
||||
|
choice.addProbability(stateIndex, probability); |
||||
|
probabilitySum += probability; |
||||
|
} |
||||
|
|
||||
|
// Check that the resulting distribution is in fact a distribution.
|
||||
|
STORM_LOG_THROW(std::abs(1 - probabilitySum) < storm::settings::generalSettings().getPrecision(), storm::exceptions::WrongFormatException, "Probabilities do not sum to one for command '" << command << "' (actually sum to " << probabilitySum << ")."); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
static std::vector<Choice<ValueType>> getLabeledTransitions(storm::prism::Program const& program, StateInformation& stateInformation, VariableInformation const& variableInformation, storm::storage::BitVector const& currentState, storm::expressions::ExprtkExpressionEvaluator const& evaluator, std::queue<storm::storage::BitVector>& stateQueue) { |
||||
|
std::vector<Choice<ValueType>> result; |
||||
|
|
||||
|
for (uint_fast64_t actionIndex : program.getActionIndices()) { |
||||
|
boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>> optionalActiveCommandLists = getActiveCommandsByActionIndex(program, evaluator, actionIndex); |
||||
|
|
||||
|
// Only process this action label, if there is at least one feasible solution.
|
||||
|
if (optionalActiveCommandLists) { |
||||
|
std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>> const& activeCommandList = optionalActiveCommandLists.get(); |
||||
|
std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>::const_iterator> iteratorList(activeCommandList.size()); |
||||
|
|
||||
|
// Initialize the list of iterators.
|
||||
|
for (size_t i = 0; i < activeCommandList.size(); ++i) { |
||||
|
iteratorList[i] = activeCommandList[i].cbegin(); |
||||
|
} |
||||
|
|
||||
|
// As long as there is one feasible combination of commands, keep on expanding it.
|
||||
|
bool done = false; |
||||
|
while (!done) { |
||||
|
std::unordered_map<CompressedState, ValueType>* currentTargetStates = new std::unordered_map<CompressedState, ValueType>(); |
||||
|
std::unordered_map<CompressedState, ValueType>* newTargetStates = new std::unordered_map<CompressedState, ValueType>(); |
||||
|
currentTargetStates->emplace(currentState, storm::utility::one<ValueType>()); |
||||
|
|
||||
|
// FIXME: This does not check whether a global variable is written multiple times. While the
|
||||
|
// behaviour for this is undefined anyway, a warning should be issued in that case.
|
||||
|
for (uint_fast64_t i = 0; i < iteratorList.size(); ++i) { |
||||
|
storm::prism::Command const& command = *iteratorList[i]; |
||||
|
|
||||
|
for (uint_fast64_t j = 0; j < command.getNumberOfUpdates(); ++j) { |
||||
|
storm::prism::Update const& update = command.getUpdate(j); |
||||
|
|
||||
|
for (auto const& stateProbabilityPair : *currentTargetStates) { |
||||
|
// Compute the new state under the current update and add it to the set of new target states.
|
||||
|
CompressedState newTargetState = applyUpdate(variableInformation, stateProbabilityPair.first, currentState, update, evaluator); |
||||
|
newTargetStates->emplace(newTargetState, stateProbabilityPair.second * evaluator.asDouble(update.getLikelihoodExpression())); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// If there is one more command to come, shift the target states one time step back.
|
||||
|
if (i < iteratorList.size() - 1) { |
||||
|
delete currentTargetStates; |
||||
|
currentTargetStates = newTargetStates; |
||||
|
newTargetStates = new std::unordered_map<CompressedState, ValueType>(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// At this point, we applied all commands of the current command combination and newTargetStates
|
||||
|
// contains all target states and their respective probabilities. That means we are now ready to
|
||||
|
// add the choice to the list of transitions.
|
||||
|
result.push_back(Choice<ValueType>(actionIndex)); |
||||
|
|
||||
|
// Now create the actual distribution.
|
||||
|
Choice<ValueType>& choice = result.back(); |
||||
|
|
||||
|
// Add the labels of all commands to this choice.
|
||||
|
for (uint_fast64_t i = 0; i < iteratorList.size(); ++i) { |
||||
|
choice.addChoiceLabel(iteratorList[i]->get().getGlobalIndex()); |
||||
|
} |
||||
|
|
||||
|
double probabilitySum = 0; |
||||
|
for (auto const& stateProbabilityPair : *newTargetStates) { |
||||
|
uint32_t actualIndex = getOrAddStateIndex(stateProbabilityPair.first, stateInformation, stateQueue); |
||||
|
choice.addProbability(actualIndex, stateProbabilityPair.second); |
||||
|
probabilitySum += stateProbabilityPair.second; |
||||
|
} |
||||
|
|
||||
|
// Check that the resulting distribution is in fact a distribution.
|
||||
|
STORM_LOG_THROW(std::abs(1 - probabilitySum) <= storm::settings::generalSettings().getPrecision(), storm::exceptions::WrongFormatException, "Sum of update probabilities do not some to one for some command (actually sum to " << probabilitySum << ")."); |
||||
|
|
||||
|
// Dispose of the temporary maps.
|
||||
|
delete currentTargetStates; |
||||
|
delete newTargetStates; |
||||
|
|
||||
|
// Now, check whether there is one more command combination to consider.
|
||||
|
bool movedIterator = false; |
||||
|
for (int_fast64_t j = iteratorList.size() - 1; j >= 0; --j) { |
||||
|
++iteratorList[j]; |
||||
|
if (iteratorList[j] != activeCommandList[j].end()) { |
||||
|
movedIterator = true; |
||||
|
} else { |
||||
|
// Reset the iterator to the beginning of the list.
|
||||
|
iteratorList[j] = activeCommandList[j].begin(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
done = !movedIterator; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
static std::vector<boost::container::flat_set<uint_fast64_t>> buildMatrices(storm::prism::Program const& program, VariableInformation const& variableInformation, std::vector<storm::prism::TransitionReward> const& transitionRewards, StateInformation& stateInformation, bool deterministicModel, storm::storage::SparseMatrixBuilder<ValueType>& transitionMatrixBuilder, storm::storage::SparseMatrixBuilder<ValueType>& transitionRewardMatrixBuilder) { |
||||
|
std::vector<boost::container::flat_set<uint_fast64_t>> choiceLabels; |
||||
|
|
||||
|
// Initialize a queue and insert the initial state.
|
||||
|
std::queue<storm::storage::BitVector> stateQueue; |
||||
|
CompressedState initialState(stateInformation.bitsPerState); |
||||
|
|
||||
|
// We need to initialize the values of the variables to their initial value.
|
||||
|
for (auto const& booleanVariable : variableInformation.booleanVariables) { |
||||
|
initialState.set(booleanVariable.bitOffset, booleanVariable.initialValue); |
||||
|
} |
||||
|
for (auto const& integerVariable : variableInformation.integerVariables) { |
||||
|
initialState.setFromInt(integerVariable.bitOffset, integerVariable.bitWidth, static_cast<uint_fast64_t>(integerVariable.initialValue - integerVariable.lowerBound)); |
||||
|
} |
||||
|
|
||||
|
// Insert the initial state in the global state to index mapping and state queue.
|
||||
|
uint32_t stateIndex = getOrAddStateIndex(initialState, stateInformation, stateQueue); |
||||
|
stateInformation.initialStateIndices.push_back(stateIndex); |
||||
|
|
||||
|
// Now explore the current state until there is no more reachable state.
|
||||
|
uint_fast64_t currentRow = 0; |
||||
|
storm::expressions::ExprtkExpressionEvaluator evaluator(program.getManager()); |
||||
|
while (!stateQueue.empty()) { |
||||
|
// Get the current state and unpack it.
|
||||
|
storm::storage::BitVector currentState = stateQueue.front(); |
||||
|
stateQueue.pop(); |
||||
|
ValueType stateIndex = stateInformation.stateToIndexMap.getValue(currentState); |
||||
|
unpackStateIntoEvaluator(currentState, variableInformation, evaluator); |
||||
|
|
||||
|
// Retrieve all choices for the current state.
|
||||
|
std::vector<Choice<ValueType>> allUnlabeledChoices = getUnlabeledTransitions(program, stateInformation, variableInformation, currentState, evaluator, stateQueue); |
||||
|
std::vector<Choice<ValueType>> allLabeledChoices = getLabeledTransitions(program, stateInformation, variableInformation, currentState, evaluator, stateQueue); |
||||
|
|
||||
|
uint_fast64_t totalNumberOfChoices = allUnlabeledChoices.size() + allLabeledChoices.size(); |
||||
|
|
||||
|
// If the current state does not have a single choice, we equip it with a self-loop if that was
|
||||
|
// requested and issue an error otherwise.
|
||||
|
if (totalNumberOfChoices == 0) { |
||||
|
if (!storm::settings::generalSettings().isDontFixDeadlocksSet()) { |
||||
|
// Insert empty choice labeling for added self-loop transitions.
|
||||
|
choiceLabels.push_back(boost::container::flat_set<uint_fast64_t>()); |
||||
|
transitionMatrixBuilder.addNextValue(currentRow, stateIndex, storm::utility::one<ValueType>()); |
||||
|
++currentRow; |
||||
|
} else { |
||||
|
LOG4CPLUS_ERROR(logger, "Error while creating sparse matrix from probabilistic program: found deadlock state. For fixing these, please provide the appropriate option."); |
||||
|
throw storm::exceptions::WrongFormatException() << "Error while creating sparse matrix from probabilistic program: found deadlock state. For fixing these, please provide the appropriate option."; |
||||
|
} |
||||
|
} else { |
||||
|
// Then, based on whether the model is deterministic or not, either add the choices individually
|
||||
|
// or compose them to one choice.
|
||||
|
if (deterministicModel) { |
||||
|
Choice<ValueType> globalChoice; |
||||
|
std::map<uint32_t, ValueType> stateToRewardMap; |
||||
|
|
||||
|
// Combine all the choices and scale them with the total number of choices of the current state.
|
||||
|
for (auto const& choice : allUnlabeledChoices) { |
||||
|
globalChoice.addChoiceLabels(choice.getChoiceLabels()); |
||||
|
for (auto const& stateProbabilityPair : choice) { |
||||
|
globalChoice.getOrAddEntry(stateProbabilityPair.first) += stateProbabilityPair.second / totalNumberOfChoices; |
||||
|
|
||||
|
// Now add all rewards that match this choice.
|
||||
|
for (auto const& transitionReward : transitionRewards) { |
||||
|
if (!transitionReward.isLabeled() && evaluator.asBool(transitionReward.getStatePredicateExpression())) { |
||||
|
stateToRewardMap[stateProbabilityPair.first] += ValueType(evaluator.asDouble(transitionReward.getRewardValueExpression())); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
for (auto const& choice : allLabeledChoices) { |
||||
|
globalChoice.addChoiceLabels(choice.getChoiceLabels()); |
||||
|
for (auto const& stateProbabilityPair : choice) { |
||||
|
globalChoice.getOrAddEntry(stateProbabilityPair.first) += stateProbabilityPair.second / totalNumberOfChoices; |
||||
|
|
||||
|
// Now add all rewards that match this choice.
|
||||
|
for (auto const& transitionReward : transitionRewards) { |
||||
|
if (transitionReward.getActionIndex() == choice.getActionIndex() && evaluator.asBool(transitionReward.getStatePredicateExpression())) { |
||||
|
stateToRewardMap[stateProbabilityPair.first] += ValueType(evaluator.asDouble(transitionReward.getRewardValueExpression())); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
// Now add the resulting distribution as the only choice of the current state.
|
||||
|
choiceLabels.push_back(globalChoice.getChoiceLabels()); |
||||
|
|
||||
|
for (auto const& stateProbabilityPair : globalChoice) { |
||||
|
transitionMatrixBuilder.addNextValue(currentRow, stateProbabilityPair.first, stateProbabilityPair.second); |
||||
|
} |
||||
|
|
||||
|
// Add all transition rewards to the matrix and add dummy entry if there is none.
|
||||
|
if (stateToRewardMap.size() > 0) { |
||||
|
for (auto const& stateRewardPair : stateToRewardMap) { |
||||
|
transitionRewardMatrixBuilder.addNextValue(currentRow, stateRewardPair.first, stateRewardPair.second); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
++currentRow; |
||||
|
} else { |
||||
|
// If the model is nondeterministic, we add all choices individually.
|
||||
|
transitionMatrixBuilder.newRowGroup(currentRow); |
||||
|
transitionRewardMatrixBuilder.newRowGroup(currentRow); |
||||
|
|
||||
|
// First, process all unlabeled choices.
|
||||
|
for (auto const& choice : allUnlabeledChoices) { |
||||
|
std::map<uint_fast64_t, ValueType> stateToRewardMap; |
||||
|
choiceLabels.emplace_back(std::move(choice.getChoiceLabels())); |
||||
|
|
||||
|
for (auto const& stateProbabilityPair : choice) { |
||||
|
transitionMatrixBuilder.addNextValue(currentRow, stateProbabilityPair.first, stateProbabilityPair.second); |
||||
|
|
||||
|
// Now add all rewards that match this choice.
|
||||
|
for (auto const& transitionReward : transitionRewards) { |
||||
|
if (!transitionReward.isLabeled() && evaluator.asBool(transitionReward.getStatePredicateExpression())) { |
||||
|
stateToRewardMap[stateProbabilityPair.first] += ValueType(evaluator.asDouble(transitionReward.getRewardValueExpression())); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
// Add all transition rewards to the matrix and add dummy entry if there is none.
|
||||
|
if (stateToRewardMap.size() > 0) { |
||||
|
for (auto const& stateRewardPair : stateToRewardMap) { |
||||
|
transitionRewardMatrixBuilder.addNextValue(currentRow, stateRewardPair.first, stateRewardPair.second); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
++currentRow; |
||||
|
} |
||||
|
|
||||
|
// Then, process all labeled choices.
|
||||
|
for (auto const& choice : allLabeledChoices) { |
||||
|
std::map<uint_fast64_t, ValueType> stateToRewardMap; |
||||
|
choiceLabels.emplace_back(std::move(choice.getChoiceLabels())); |
||||
|
|
||||
|
for (auto const& stateProbabilityPair : choice) { |
||||
|
transitionMatrixBuilder.addNextValue(currentRow, stateProbabilityPair.first, stateProbabilityPair.second); |
||||
|
|
||||
|
// Now add all rewards that match this choice.
|
||||
|
for (auto const& transitionReward : transitionRewards) { |
||||
|
if (transitionReward.getActionIndex() == choice.getActionIndex() && evaluator.asBool(transitionReward.getStatePredicateExpression())) { |
||||
|
stateToRewardMap[stateProbabilityPair.first] += ValueType(evaluator.asDouble(transitionReward.getRewardValueExpression())); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
// Add all transition rewards to the matrix and add dummy entry if there is none.
|
||||
|
if (stateToRewardMap.size() > 0) { |
||||
|
for (auto const& stateRewardPair : stateToRewardMap) { |
||||
|
transitionRewardMatrixBuilder.addNextValue(currentRow, stateRewardPair.first, stateRewardPair.second); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
++currentRow; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return choiceLabels; |
||||
|
} |
||||
|
|
||||
|
static ModelComponents buildModelComponents(storm::prism::Program const& program, storm::prism::RewardModel const& rewardModel) { |
||||
|
ModelComponents modelComponents; |
||||
|
|
||||
|
uint_fast64_t bitOffset = 0; |
||||
|
VariableInformation variableInformation; |
||||
|
for (auto const& booleanVariable : program.getGlobalBooleanVariables()) { |
||||
|
variableInformation.booleanVariables.emplace_back(booleanVariable.getExpressionVariable(), booleanVariable.getInitialValueExpression().evaluateAsBool(), bitOffset); |
||||
|
++bitOffset; |
||||
|
variableInformation.booleanVariableToIndexMap[booleanVariable.getExpressionVariable()] = variableInformation.booleanVariables.size() - 1; |
||||
|
} |
||||
|
for (auto const& integerVariable : program.getGlobalIntegerVariables()) { |
||||
|
int_fast64_t lowerBound = integerVariable.getLowerBoundExpression().evaluateAsInt(); |
||||
|
int_fast64_t upperBound = integerVariable.getUpperBoundExpression().evaluateAsInt(); |
||||
|
uint_fast64_t bitwidth = static_cast<uint_fast64_t>(std::ceil(std::log2(upperBound - lowerBound + 1))); |
||||
|
variableInformation.integerVariables.emplace_back(integerVariable.getExpressionVariable(), integerVariable.getInitialValueExpression().evaluateAsInt(), lowerBound, upperBound, bitOffset, bitwidth); |
||||
|
bitOffset += bitwidth; |
||||
|
variableInformation.integerVariableToIndexMap[integerVariable.getExpressionVariable()] = variableInformation.integerVariables.size() - 1; |
||||
|
} |
||||
|
for (auto const& module : program.getModules()) { |
||||
|
for (auto const& booleanVariable : module.getBooleanVariables()) { |
||||
|
variableInformation.booleanVariables.emplace_back(booleanVariable.getExpressionVariable(), booleanVariable.getInitialValueExpression().evaluateAsBool(), bitOffset); |
||||
|
++bitOffset; |
||||
|
variableInformation.booleanVariableToIndexMap[booleanVariable.getExpressionVariable()] = variableInformation.booleanVariables.size() - 1; |
||||
|
} |
||||
|
for (auto const& integerVariable : module.getIntegerVariables()) { |
||||
|
int_fast64_t lowerBound = integerVariable.getLowerBoundExpression().evaluateAsInt(); |
||||
|
int_fast64_t upperBound = integerVariable.getUpperBoundExpression().evaluateAsInt(); |
||||
|
uint_fast64_t bitwidth = static_cast<uint_fast64_t>(std::ceil(std::log2(upperBound - lowerBound + 1))); |
||||
|
variableInformation.integerVariables.emplace_back(integerVariable.getExpressionVariable(), integerVariable.getInitialValueExpression().evaluateAsInt(), lowerBound, upperBound, bitOffset, bitwidth); |
||||
|
bitOffset += bitwidth; |
||||
|
variableInformation.integerVariableToIndexMap[integerVariable.getExpressionVariable()] = variableInformation.integerVariables.size() - 1; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// Create the structure for storing the reachable state space.
|
||||
|
uint64_t bitsPerState = ((bitOffset / 64) + 1) * 64; |
||||
|
StateInformation stateInformation(bitsPerState); |
||||
|
|
||||
|
// 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.getModelType() == storm::prism::Program::ModelType::DTMC || program.getModelType() == storm::prism::Program::ModelType::CTMC; |
||||
|
|
||||
|
// Build the transition and reward matrices.
|
||||
|
storm::storage::SparseMatrixBuilder<ValueType> transitionMatrixBuilder(0, 0, 0, false, !deterministicModel, 0); |
||||
|
storm::storage::SparseMatrixBuilder<ValueType> transitionRewardMatrixBuilder(0, 0, 0, false, !deterministicModel, 0); |
||||
|
modelComponents.choiceLabeling = buildMatrices(program, variableInformation, rewardModel.getTransitionRewards(), stateInformation, deterministicModel, transitionMatrixBuilder, transitionRewardMatrixBuilder); |
||||
|
|
||||
|
// Finalize the resulting matrices.
|
||||
|
modelComponents.transitionMatrix = transitionMatrixBuilder.build(); |
||||
|
modelComponents.transitionRewardMatrix = transitionRewardMatrixBuilder.build(modelComponents.transitionMatrix.getRowCount(), modelComponents.transitionMatrix.getColumnCount(), modelComponents.transitionMatrix.getRowGroupCount()); |
||||
|
|
||||
|
// Now build the state labeling.
|
||||
|
modelComponents.stateLabeling = buildStateLabeling(program, variableInformation, stateInformation); |
||||
|
|
||||
|
// Finally, construct the state rewards.
|
||||
|
modelComponents.stateRewards = buildStateRewards(program, variableInformation, rewardModel.getStateRewards(), stateInformation); |
||||
|
|
||||
|
return modelComponents; |
||||
|
} |
||||
|
|
||||
|
static storm::models::AtomicPropositionsLabeling buildStateLabeling(storm::prism::Program const& program, VariableInformation const& variableInformation, StateInformation const& stateInformation) { |
||||
|
storm::expressions::ExprtkExpressionEvaluator evaluator(program.getManager()); |
||||
|
|
||||
|
std::vector<storm::prism::Label> const& labels = program.getLabels(); |
||||
|
|
||||
|
storm::models::AtomicPropositionsLabeling result(stateInformation.reachableStates.size(), labels.size() + 1); |
||||
|
|
||||
|
// Initialize labeling.
|
||||
|
for (auto const& label : labels) { |
||||
|
result.addAtomicProposition(label.getName()); |
||||
|
} |
||||
|
for (uint_fast64_t index = 0; index < stateInformation.reachableStates.size(); index++) { |
||||
|
unpackStateIntoEvaluator(stateInformation.reachableStates[index], variableInformation, evaluator); |
||||
|
for (auto const& label : labels) { |
||||
|
// Add label to state, if the corresponding expression is true.
|
||||
|
if (evaluator.asBool(label.getStatePredicateExpression())) { |
||||
|
result.addAtomicPropositionToState(label.getName(), index); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// Also label the initial state with the special label "init".
|
||||
|
result.addAtomicProposition("init"); |
||||
|
for (auto index : stateInformation.initialStateIndices) { |
||||
|
result.addAtomicPropositionToState("init", index); |
||||
|
} |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
static std::vector<ValueType> buildStateRewards(storm::prism::Program const& program, VariableInformation const& variableInformation, std::vector<storm::prism::StateReward> const& rewards, StateInformation const& stateInformation) { |
||||
|
storm::expressions::ExprtkExpressionEvaluator evaluator(program.getManager()); |
||||
|
|
||||
|
std::vector<ValueType> result(stateInformation.reachableStates.size()); |
||||
|
for (uint_fast64_t index = 0; index < stateInformation.reachableStates.size(); index++) { |
||||
|
result[index] = storm::utility::zero<ValueType>(); |
||||
|
unpackStateIntoEvaluator(stateInformation.reachableStates[index], variableInformation, evaluator); |
||||
|
for (auto const& reward : rewards) { |
||||
|
|
||||
|
// Add this reward to the state if the state is included in the state reward.
|
||||
|
if (evaluator.asBool(reward.getStatePredicateExpression())) { |
||||
|
result[index] += ValueType(evaluator.asDouble(reward.getRewardValueExpression())); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
// Explicitly instantiate the class.
|
||||
|
template class ExplicitPrismModelBuilder<double, uint32_t>; |
||||
|
} |
||||
|
} |
@ -0,0 +1,248 @@ |
|||||
|
#ifndef STORM_ADAPTERS_EXPLICITPRISMMODELBUILDER_H |
||||
|
#define STORM_ADAPTERS_EXPLICITPRISMMODELBUILDER_H |
||||
|
|
||||
|
#include <memory> |
||||
|
#include <unordered_map> |
||||
|
#include <utility> |
||||
|
#include <vector> |
||||
|
#include <queue> |
||||
|
#include <cstdint> |
||||
|
#include <boost/functional/hash.hpp> |
||||
|
#include <boost/container/flat_set.hpp> |
||||
|
#include <boost/container/flat_map.hpp> |
||||
|
#include <boost/algorithm/string.hpp> |
||||
|
|
||||
|
#include "src/storage/prism/Program.h" |
||||
|
#include "src/storage/expressions/SimpleValuation.h" |
||||
|
#include "src/storage/expressions/ExprtkExpressionEvaluator.h" |
||||
|
#include "src/storage/BitVectorHashMap.h" |
||||
|
#include "src/utility/PrismUtility.h" |
||||
|
#include "src/models/AbstractModel.h" |
||||
|
#include "src/models/Dtmc.h" |
||||
|
#include "src/models/Ctmc.h" |
||||
|
#include "src/models/Mdp.h" |
||||
|
#include "src/models/Ctmdp.h" |
||||
|
#include "src/models/AtomicPropositionsLabeling.h" |
||||
|
#include "src/storage/SparseMatrix.h" |
||||
|
#include "src/settings/SettingsManager.h" |
||||
|
#include "src/utility/macros.h" |
||||
|
#include "src/exceptions/WrongFormatException.h" |
||||
|
|
||||
|
namespace storm { |
||||
|
namespace builder { |
||||
|
|
||||
|
using namespace storm::utility::prism; |
||||
|
|
||||
|
template<typename ValueType, typename IndexType = uint32_t> |
||||
|
class ExplicitPrismModelBuilder { |
||||
|
public: |
||||
|
typedef storm::storage::BitVector CompressedState; |
||||
|
|
||||
|
// A structure holding information about the reachable state space. |
||||
|
struct StateInformation { |
||||
|
StateInformation(uint64_t bitsPerState); |
||||
|
|
||||
|
// This member stores all the states and maps them to their unique indices. |
||||
|
storm::storage::BitVectorHashMap<IndexType> stateStorage; |
||||
|
|
||||
|
// A list of initial states in terms of their global indices. |
||||
|
std::vector<IndexType> initialStateIndices; |
||||
|
|
||||
|
// The number of bits of each state. |
||||
|
uint64_t bitsPerState; |
||||
|
|
||||
|
// A list of reachable states as indices in the stateToIndexMap. |
||||
|
std::vector<storm::storage::BitVector> reachableStates; |
||||
|
}; |
||||
|
|
||||
|
// A structure storing information about the used variables of the program. |
||||
|
struct VariableInformation { |
||||
|
struct BooleanVariableInformation { |
||||
|
BooleanVariableInformation(storm::expressions::Variable const& variable, bool initialValue, uint_fast64_t bitOffset); |
||||
|
|
||||
|
// The boolean variable. |
||||
|
storm::expressions::Variable variable; |
||||
|
|
||||
|
// Its initial value. |
||||
|
bool initialValue; |
||||
|
|
||||
|
// Its bit offset in the compressed state. |
||||
|
uint_fast64_t bitOffset; |
||||
|
}; |
||||
|
|
||||
|
struct IntegerVariableInformation { |
||||
|
IntegerVariableInformation(storm::expressions::Variable const& variable, int_fast64_t initialValue, int_fast64_t lowerBound, int_fast64_t upperBound, uint_fast64_t bitOffset, uint_fast64_t bitWidth); |
||||
|
|
||||
|
// The integer variable. |
||||
|
storm::expressions::Variable variable; |
||||
|
|
||||
|
// Its initial value. |
||||
|
int_fast64_t initialValue; |
||||
|
|
||||
|
// The lower bound of its range. |
||||
|
int_fast64_t lowerBound; |
||||
|
|
||||
|
// The upper bound of its range. |
||||
|
int_fast64_t upperBound; |
||||
|
|
||||
|
// Its bit offset in the compressed state. |
||||
|
uint_fast64_t bitOffset; |
||||
|
|
||||
|
// Its bit width in the compressed state. |
||||
|
uint_fast64_t bitWidth; |
||||
|
}; |
||||
|
|
||||
|
// Provide methods to access the bit offset and width of variables in the compressed state. |
||||
|
uint_fast64_t getBitOffset(storm::expressions::Variable const& variable) const; |
||||
|
uint_fast64_t getBitWidth(storm::expressions::Variable const& variable) const; |
||||
|
|
||||
|
// The known boolean variables. |
||||
|
boost::container::flat_map<storm::expressions::Variable, uint_fast64_t> booleanVariableToIndexMap; |
||||
|
std::vector<BooleanVariableInformation> booleanVariables; |
||||
|
|
||||
|
// The known integer variables. |
||||
|
boost::container::flat_map<storm::expressions::Variable, uint_fast64_t> integerVariableToIndexMap; |
||||
|
std::vector<IntegerVariableInformation> integerVariables; |
||||
|
}; |
||||
|
|
||||
|
// A structure holding the individual components of a model. |
||||
|
struct ModelComponents { |
||||
|
ModelComponents(); |
||||
|
|
||||
|
// The transition matrix. |
||||
|
storm::storage::SparseMatrix<ValueType> transitionMatrix; |
||||
|
|
||||
|
// The state labeling. |
||||
|
storm::models::AtomicPropositionsLabeling stateLabeling; |
||||
|
|
||||
|
// The state reward vector. |
||||
|
std::vector<ValueType> stateRewards; |
||||
|
|
||||
|
// A matrix storing the reward for particular transitions. |
||||
|
storm::storage::SparseMatrix<ValueType> transitionRewardMatrix; |
||||
|
|
||||
|
// A vector that stores a labeling for each choice. |
||||
|
std::vector<boost::container::flat_set<uint_fast64_t>> choiceLabeling; |
||||
|
}; |
||||
|
|
||||
|
/*! |
||||
|
* Convert the program given at construction time to an abstract model. The type of the model is the one |
||||
|
* specified in the program. The given reward model name selects the rewards that the model will contain. |
||||
|
* |
||||
|
* @param program The program to translate. |
||||
|
* @param constantDefinitionString A string that contains a comma-separated definition of all undefined |
||||
|
* constants in the model. |
||||
|
* @param rewardModel The reward model that is to be built. |
||||
|
* @return The explicit model that was given by the probabilistic program. |
||||
|
*/ |
||||
|
static std::unique_ptr<storm::models::AbstractModel<ValueType>> translateProgram(storm::prism::Program program, bool rewards = true, std::string const& rewardModelName = "", std::string const& constantDefinitionString = ""); |
||||
|
|
||||
|
private: |
||||
|
static void unpackStateIntoEvaluator(storm::storage::BitVector const& currentState, VariableInformation const& variableInformation, storm::expressions::ExprtkExpressionEvaluator& evaluator); |
||||
|
|
||||
|
/*! |
||||
|
* Applies an update to the given state and returns the resulting new state object. This methods does not |
||||
|
* modify the given state but returns a new one. |
||||
|
* |
||||
|
* @params state The state to which to apply the update. |
||||
|
* @params update The update to apply. |
||||
|
* @return The resulting state. |
||||
|
*/ |
||||
|
static CompressedState applyUpdate(VariableInformation const& variableInformation, CompressedState const& state, storm::prism::Update const& update, storm::expressions::ExprtkExpressionEvaluator const& evaluator); |
||||
|
|
||||
|
/*! |
||||
|
* Applies an update to the given state and returns the resulting new state object. The update is evaluated |
||||
|
* over the variable values of the given base state. This methods does not modify the given state but |
||||
|
* returns a new one. |
||||
|
* |
||||
|
* @param state The state to which to apply the update. |
||||
|
* @param baseState The state used for evaluating the update. |
||||
|
* @param update The update to apply. |
||||
|
* @return The resulting state. |
||||
|
*/ |
||||
|
static CompressedState applyUpdate(VariableInformation const& variableInformation, CompressedState const& state, CompressedState const& baseState, storm::prism::Update const& update, storm::expressions::ExprtkExpressionEvaluator const& evaluator); |
||||
|
|
||||
|
/*! |
||||
|
* Retrieves the state id of the given state. If the state has not been encountered yet, it will be added to |
||||
|
* the lists of all states with a new id. If the state was already known, the object that is pointed to by |
||||
|
* the given state pointer is deleted and the old state id is returned. Note that the pointer should not be |
||||
|
* used after invoking this method. |
||||
|
* |
||||
|
* @param state A pointer to a state for which to retrieve the index. This must not be used after the call. |
||||
|
* @param stateInformation The information about the already explored part of the reachable state space. |
||||
|
* @return A pair indicating whether the state was already discovered before and the state id of the state. |
||||
|
*/ |
||||
|
static IndexType getOrAddStateIndex(CompressedState const& state, StateInformation& stateInformation, std::queue<storm::storage::BitVector>& stateQueue); |
||||
|
|
||||
|
/*! |
||||
|
* Retrieves all commands that are labeled with the given label and enabled in the given state, grouped by |
||||
|
* modules. |
||||
|
* |
||||
|
* This function will iterate over all modules and retrieve all commands that are labeled with the given |
||||
|
* action and active (i.e. enabled) in the current state. The result is a list of lists of commands in which |
||||
|
* the inner lists contain all commands of exactly one module. If a module does not have *any* (including |
||||
|
* disabled) commands, there will not be a list of commands of that module in the result. If, however, the |
||||
|
* module has a command with a relevant label, but no enabled one, nothing is returned to indicate that there |
||||
|
* is no legal transition possible. |
||||
|
* |
||||
|
* @param The program in which to search for active commands. |
||||
|
* @param state The current state. |
||||
|
* @param actionIndex The index of the action label to select. |
||||
|
* @return A list of lists of active commands or nothing. |
||||
|
*/ |
||||
|
static boost::optional<std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>>> getActiveCommandsByActionIndex(storm::prism::Program const& program,storm::expressions::ExprtkExpressionEvaluator const& evaluator, uint_fast64_t const& actionIndex); |
||||
|
|
||||
|
static std::vector<Choice<ValueType>> getUnlabeledTransitions(storm::prism::Program const& program, StateInformation& stateInformation, VariableInformation const& variableInformation, storm::storage::BitVector const& currentState, storm::expressions::ExprtkExpressionEvaluator const& evaluator, std::queue<storm::storage::BitVector>& stateQueue); |
||||
|
|
||||
|
static std::vector<Choice<ValueType>> getLabeledTransitions(storm::prism::Program const& program, StateInformation& stateInformation, VariableInformation const& variableInformation, storm::storage::BitVector const& currentState, storm::expressions::ExprtkExpressionEvaluator const& evaluator, std::queue<storm::storage::BitVector>& stateQueue); |
||||
|
/*! |
||||
|
* Builds the transition matrix and the transition reward matrix based for the given program. |
||||
|
* |
||||
|
* @param program The program for which to build the matrices. |
||||
|
* @param variableInformation A structure containing information about the variables in the program. |
||||
|
* @param transitionRewards A list of transition rewards that are to be considered in the transition reward |
||||
|
* matrix. |
||||
|
* @param stateInformation A structure containing information about the states of the program. |
||||
|
* @param deterministicModel A flag indicating whether the model is supposed to be deterministic or not. |
||||
|
* @param transitionMatrix A reference to an initialized matrix which is filled with all transitions by this |
||||
|
* function. |
||||
|
* @param transitionRewardMatrix A reference to an initialized matrix which is filled with all transition |
||||
|
* rewards by this function. |
||||
|
* @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. |
||||
|
*/ |
||||
|
static std::vector<boost::container::flat_set<uint_fast64_t>> buildMatrices(storm::prism::Program const& program, VariableInformation const& variableInformation, std::vector<storm::prism::TransitionReward> const& transitionRewards, StateInformation& stateInformation, bool deterministicModel, storm::storage::SparseMatrixBuilder<ValueType>& transitionMatrixBuilder, storm::storage::SparseMatrixBuilder<ValueType>& transitionRewardMatrixBuilder); |
||||
|
|
||||
|
/*! |
||||
|
* Explores the state space of the given program and returns the components of the model as a result. |
||||
|
* |
||||
|
* @param program The program whose state space to explore. |
||||
|
* @param rewardModel The reward model that is to be considered. |
||||
|
* @return A structure containing the components of the resulting model. |
||||
|
*/ |
||||
|
static ModelComponents buildModelComponents(storm::prism::Program const& program, storm::prism::RewardModel const& rewardModel); |
||||
|
|
||||
|
/*! |
||||
|
* Builds the state labeling for the given program. |
||||
|
* |
||||
|
* @param program The program for which to build the state labeling. |
||||
|
* @param variableInformation Information about the variables in the program. |
||||
|
* @param stateInformation Information about the state space of the program. |
||||
|
* @return The state labeling of the given program. |
||||
|
*/ |
||||
|
static storm::models::AtomicPropositionsLabeling buildStateLabeling(storm::prism::Program const& program, VariableInformation const& variableInformation, StateInformation const& stateInformation); |
||||
|
|
||||
|
/*! |
||||
|
* Builds the state rewards for the given state space. |
||||
|
* |
||||
|
* @param rewards A vector of state rewards to consider. |
||||
|
* @param stateInformation Information about the state space. |
||||
|
* @return A vector containing the state rewards for the state space. |
||||
|
*/ |
||||
|
static std::vector<ValueType> buildStateRewards(storm::prism::Program const& program, VariableInformation const& variableInformation, std::vector<storm::prism::StateReward> const& rewards, StateInformation const& stateInformation); |
||||
|
}; |
||||
|
|
||||
|
} // namespace adapters |
||||
|
} // namespace storm |
||||
|
|
||||
|
#endif /* STORM_ADAPTERS_EXPLICITPRISMMODELBUILDER_H */ |
Write
Preview
Loading…
Cancel
Save
Reference in new issue