35template<
typename ValueType>
48template<
typename ValueType>
52 auto const rewardFitsInt64 = [&rewardLimit](ValueType
const& reward) {
return reward < rewardLimit; };
65 if (!rewardFitsInt64(reward)) {
78template<
typename ValueType>
82 "Reward bound unfolding requires shared left and right state subformulas across all dimensions.");
84 "Only propositional right subformulas are supported.");
86 "Only propositional left subformulas are supported.");
87 std::vector<Dimension<ValueType>> dimensions;
88 for (uint64_t formulaDim = 0; formulaDim < boundedUntilFormula.
getDimension(); ++formulaDim) {
89 STORM_LOG_THROW(formulaDim >= levelWidths.size() || levelWidths[formulaDim] <=
static_cast<uint64_t
>(std::numeric_limits<int64_t>::max()),
90 storm::exceptions::InvalidArgumentException,
"Level width in dimension " << formulaDim <<
" exceeds INT64_MAX.");
91 int64_t
const levelWidth = formulaDim < levelWidths.size() ?
static_cast<int64_t
>(levelWidths[formulaDim]) : 0;
93 STORM_LOG_THROW(tbr.isRewardBound(), storm::exceptions::NotSupportedException,
"The bounded formula is not a reward-bounded formula.");
95 !tbr.hasRewardAccumulation(), storm::exceptions::NotSupportedException,
96 "The reward model for bound reference " << formulaDim <<
" has non-trivial reward accumulation which is not supported in this context.");
98 std::string
const rewardModelName = tbr.getOptionalRewardModelName().get_value_or(
"");
101 STORM_LOG_THROW(!rewardModel.hasTransitionRewards(), storm::exceptions::NotSupportedException,
102 "The reward model for bound reference " << formulaDim <<
" uses transition rewards. These are currently unsupported.");
104 STORM_LOG_THROW(!rewardModel.hasStateRewards() || std::all_of(rewardModel.getStateRewardVector().begin(), rewardModel.getStateRewardVector().end(),
106 storm::exceptions::NotSupportedException,
"State rewards in reward model " << rewardModelName <<
" are not integers.");
108 !rewardModel.hasStateActionRewards() || std::all_of(rewardModel.getStateActionRewardVector().begin(),
110 storm::exceptions::NotSupportedException,
"State action rewards in reward model " << rewardModelName <<
" are not integers.");
113 STORM_LOG_THROW(!rewardModel.hasNegativeRewards(), storm::exceptions::NotSupportedException,
114 "Reward model " << rewardModelName <<
" contains negative rewards. These are currently unsupported.");
116 "Rewards in reward model " << rewardModelName <<
" for bound reference " << formulaDim <<
" exceed INT64_MAX.");
119 auto getFreshIdentifier = [&]() {
120 std::string prefix =
"dim" + std::to_string(dimensions.size()) + (levelWidth == 0 ?
"_active" :
"_levelReward");
121 auto identifier = prefix;
122 for (uint64_t i = 0; (levelWidth == 0 ? model.
hasLabel(identifier) : model.
hasRewardModel(identifier)); ++i) {
123 identifier = prefix +
"_" + std::to_string(i);
130 "Bound " << formulaDim <<
" is not an integer");
132 int64_t
const adjustment = boundedUntilFormula.
isUpperBoundStrict(formulaDim) ? int64_t{1} : int64_t{0};
133 STORM_LOG_THROW(bound >= adjustment, storm::exceptions::NotSupportedException,
134 "Upper reward bound in dimension " << formulaDim <<
" is not satisfiable.");
135 int64_t
const threshold = bound - adjustment;
136 dimensions.push_back(
141 "Bound " << formulaDim <<
" is not an integer");
143 int64_t
const adjustment = boundedUntilFormula.
isLowerBoundStrict(formulaDim) ? int64_t{0} : int64_t{1};
144 if (bound >= adjustment) {
145 int64_t
const threshold = bound - adjustment;
146 dimensions.push_back(
149 STORM_LOG_WARN(
"Lower reward bound in dimension " << formulaDim <<
" is trivially satisfied and therefore dropped.");
160int64_t
mod(int64_t a, int64_t b) {
161 int64_t
const remainder = a % b;
162 return remainder < 0 ? remainder + b : remainder;
165template<
typename ValueType>
168 epoch.reserve(dimensions.size());
169 for (
auto const& dim : dimensions) {
170 if (dim.levelWidth == 0) {
171 epoch.push_back(dim.threshold);
173 epoch.push_back(
mod(dim.threshold, dim.levelWidth));
179template<
typename ValueType>
183 for (
auto eIt = successorEpoch.begin();
auto const& dim : dimensions) {
184 auto const& rew = dim.rewardModel;
190 *eIt -= integerReward;
193 return successorEpoch;
196template<
typename ValueType,
typename LevelRewardSetterType>
198 for (uint64_t dimIndex = 0; dimIndex < dimensions.size(); ++dimIndex) {
199 auto const lvlWidth = dimensions[dimIndex].levelWidth;
204 << reward <<
". Succ epoch is " << successorEpoch[dimIndex] <<
" and lvlWidth is "
207 setLevelReward(dimIndex, reward);
212template<
typename ValueType>
214 for (
auto eIt = epoch.begin();
auto const& dim : dimensions) {
216 if (dim.levelWidth == 0) {
219 epoch.assign(epoch.size(), -1);
224 *eIt =
mod(*eIt, dim.levelWidth);
231template<
typename ValueType,
typename ActiveDimensionSetterType>
233 for (uint64_t dimIndex = 0; dimIndex < dimensions.size(); ++dimIndex) {
234 auto const& dim = dimensions[dimIndex];
235 if (dim.levelWidth == 0) {
236 bool const inBottomEpoch = epoch[dimIndex] < 0;
238 setActiveDimension(dimIndex);
250 return {idIt->second, isNewEntry};
256template<
typename ValueType>
265template<
typename ValueType>
268 bool const hasRowGroups = !ogMatrix.hasTrivialRowGrouping();
273 std::vector<std::vector<ValueType>> levelRewardsForDimensions(dimensions.size());
274 std::vector<storm::storage::BitVector> activeDimensions(dimensions.size());
277 std::queue<StateIdType> queue;
281 auto processNewStateEpoch = [&queue, &stateEpochCollector](
StateIdType stateId,
EpochType epoch) {
292 auto initId = processNewStateEpoch(initState, initEpoch);
293 initialStateIds.
grow(initId + 1);
294 initialStateIds.
set(initId);
298 uint64_t numChoicesInUnfolding = 0;
299 while (!queue.empty()) {
301 auto const currentStateEpochId = queue.front();
303 auto [currentState, currentEpoch] = stateEpochCollector.
idToStateEpochPair[currentStateEpochId];
307 computeActiveDimensions(currentEpoch, dimensions, [&activeDimensions, ¤tStateEpochId](uint64_t dimIndex) {
308 activeDimensions[dimIndex].grow(currentStateEpochId + 1);
309 activeDimensions[dimIndex].set(currentStateEpochId);
316 for (
auto const choice : ogMatrix.getRowGroupIndices(currentState)) {
320 computeLevelReward(successorEpoch, dimensions, [&levelRewardsForDimensions](uint64_t dimIndex, ValueType levelReward) {
321 levelRewardsForDimensions[dimIndex].push_back(levelReward);
325 for (
auto const& entry : ogMatrix.getRow(choice)) {
330 auto successorInUnfolding = processNewStateEpoch(entry.getColumn(), successorEpoch);
331 matrixBuilder.
addNextValue(numChoicesInUnfolding, successorInUnfolding, entry.getValue());
333 ++numChoicesInUnfolding;
338 STORM_LOG_ASSERT(matrix.hasOnlyPositiveEntries(),
"Resulting transition matrix has non-positive entries.");
340 return ExplorationResult<ValueType>{std::move(matrix), std::move(initialStateIds), std::move(levelRewardsForDimensions), std::move(activeDimensions),
344template<
typename ValueType>
347 std::set<std::string>
const& preservedRewardModels,
351 uint64_t
const numStates = explorationResult.matrix.getColumnCount();
352 uint64_t
const numChoices = explorationResult.matrix.getRowCount();
357 auto forEachState = [&explorationResult, &numStates](
auto const& f) {
358 for (uint64_t unfoldingState = 0; unfoldingState < numStates; ++unfoldingState) {
359 f(unfoldingState, explorationResult.stateIdToOgStateEpochPair[unfoldingState].first);
362 auto forEachChoice = [&originalModel, &components, &explorationResult, &numStates](
auto const& f) {
363 for (uint64_t unfoldingState = 0; unfoldingState < numStates; ++unfoldingState) {
364 uint64_t
const originalState = explorationResult.stateIdToOgStateEpochPair[unfoldingState].first;
366 "Number of choices in unfolding and original model differ.");
368 for (
auto unfoldingChoice : components.
transitionMatrix.getRowGroupIndices(unfoldingState)) {
369 f(unfoldingChoice, origChoice);
376 explorationResult.initialStates.resize(numStates);
379 if (label ==
"init") {
384 forEachState([&newLabel, &originalLabel](uint64_t unfoldingState,
StateIdType originalState) {
385 if (originalLabel.get(originalState)) {
386 newLabel.
set(unfoldingState);
391 for (uint64_t dimIndex = 0; dimIndex < dimensions.size(); ++dimIndex) {
392 if (dimensions[dimIndex].levelWidth == 0) {
393 explorationResult.activeDimensions[dimIndex].resize(numStates);
394 components.
stateLabeling.
addLabel(dimensions[dimIndex].freshLevelRewardOrActiveLabelName, std::move(explorationResult.activeDimensions[dimIndex]));
404 forEachChoice([&newLabel, &originalLabel](uint64_t unfoldingChoice, uint64_t originalChoice) {
405 if (originalLabel.get(originalChoice)) {
406 newLabel.
set(unfoldingChoice);
414 if (!preservedRewardModels.contains(name)) {
417 STORM_LOG_THROW(!rewmodel.hasTransitionRewards(), storm::exceptions::NotSupportedException,
418 "Transition rewards are currently not supported in this context.");
419 std::optional<std::vector<ValueType>> stateRewards, stateActionRewards;
420 if (rewmodel.hasStateRewards()) {
421 stateRewards.emplace();
422 stateRewards->reserve(numStates);
424 [&stateRewards, &rewmodel](uint64_t _,
StateIdType originalState) { stateRewards->push_back(rewmodel.getStateReward(originalState)); });
426 if (rewmodel.hasStateActionRewards()) {
427 stateActionRewards.emplace();
428 stateActionRewards->reserve(numChoices);
429 forEachChoice([&stateActionRewards, &rewmodel](uint64_t _,
StateIdType originalChoice) {
430 stateActionRewards->push_back(rewmodel.getStateActionReward(originalChoice));
435 for (uint64_t dimIndex = 0; dimIndex < dimensions.size(); ++dimIndex) {
436 if (dimensions[dimIndex].levelWidth != 0) {
437 explorationResult.levelRewardsForDimensions[dimIndex].shrink_to_fit();
439 dimensions[dimIndex].freshLevelRewardOrActiveLabelName,
447 std::vector<uint32_t> unfoldingStateObservations;
448 unfoldingStateObservations.reserve(numStates);
449 forEachState([&unfoldingStateObservations, &
pomdp](
auto _,
StateIdType originalState) {
450 unfoldingStateObservations.push_back(
pomdp.getObservation(originalState));
457 storm::exceptions::NotSupportedException,
"Unfolding is only supported for POMDPs, MDPs and DTMCs.");
462template<
typename ValueType>
469 if (dimensions.empty()) {
470 return std::make_shared<storm::logic::UntilFormula>(std::move(lhs), std::move(rhs));
472 std::vector<std::optional<storm::logic::TimeBound>> lowerBounds, upperBounds;
473 std::vector<storm::logic::TimeBoundReference> timeBoundReferences;
475 auto const& exprManager =
477 for (
auto const& dim : dimensions) {
478 if (dim.levelWidth == 0) {
480 auto activeFormula = std::make_shared<storm::logic::AtomicLabelFormula>(dim.freshLevelRewardOrActiveLabelName);
482 std::move(activeFormula));
484 auto activeFormula = std::make_shared<storm::logic::AtomicLabelFormula>(dim.freshLevelRewardOrActiveLabelName);
486 std::move(activeFormula));
494 lowerBounds.emplace_back();
496 upperBounds.emplace_back();
499 timeBoundReferences.emplace_back(dim.freshLevelRewardOrActiveLabelName);
505 if (timeBoundReferences.empty()) {
506 return std::make_shared<storm::logic::UntilFormula>(lhs, rhs);
508 return std::make_shared<storm::logic::BoundedUntilFormula>(lhs, rhs, std::move(lowerBounds), std::move(upperBounds), std::move(timeBoundReferences));
514template<
typename ValueType>
519 storm::exceptions::NotSupportedException,
"Reward bound unfolding is only supported for POMDPs, MDPs and DTMCs.");
523 auto result =
transform(model, opFormula.getSubformula(), options);
524 result.formula = std::make_shared<storm::logic::ProbabilityOperatorFormula>(std::move(result.formula), opFormula.getOperatorInformation());
int_fast64_t evaluateAsInt(Valuation const *valuation=nullptr) const
Evaluates the expression under the valuation of variables given by the valuation and returns the resu...
ExpressionManager const & getManager() const
Retrieves the manager responsible for this expression.
virtual ModelType getType() const
Return the actual type of the model.
bool isOfType(storm::models::ModelType const &modelType) const
Checks whether the model is of the given type.
storm::storage::BitVector const & getChoices(std::string const &label) const
Returns the labeling of choices associated with the given label.
std::set< std::string > getLabels() const
Retrieves the set of labels contained in this labeling.
void addLabel(std::string const &label)
Adds a new label to the labelings.
Base class for all sparse models.
storm::models::sparse::ChoiceLabeling const & getChoiceLabeling() const
Retrieves the labels for the choices of the model.
storm::storage::SparseMatrix< ValueType > const & getTransitionMatrix() const
Retrieves the matrix representing the transitions of the model.
std::unordered_map< std::string, RewardModelType > const & getRewardModels() const
Retrieves the reward models.
bool hasStateValuations() const
Retrieves whether this model was build with state valuations.
bool hasChoiceLabeling() const
Retrieves whether this model has a labeling of the choices.
virtual bool hasRewardModel(std::string const &rewardModelName) const override
Retrieves whether the model has a reward model with the given name.
storm::models::sparse::StateLabeling const & getStateLabeling() const
Returns the state labeling associated with this model.
bool hasChoiceOrigins() const
Retrieves whether this model was build with choice origins.
virtual uint_fast64_t getNumberOfStates() const override
Returns the number of states of the model.
bool hasLabel(std::string const &label) const
Retrieves whether the given label is a valid label in this model.
RewardModelType const & getRewardModel(std::string const &rewardModelName) const
Retrieves the reward model with the given name, if one exists.
storm::storage::BitVector const & getInitialStates() const
Retrieves the initial states of the model.
This class represents a partially observable Markov decision process.
void setIsCanonic(bool newValue=true)
ValueType const & getStateReward(uint_fast64_t state) const
std::vector< ValueType > const & getStateActionRewardVector() const
Retrieves the state-action rewards of the reward model.
std::vector< ValueType > const & getStateRewardVector() const
Retrieves the state rewards of the reward model.
ValueType const & getStateActionReward(uint_fast64_t choiceIndex) const
Retrieves the state-action reward for the given choice.
bool hasStateRewards() const
Retrieves whether the reward model has state rewards.
bool hasStateActionRewards() const
Retrieves whether the reward model has state-action rewards.
This class manages the labeling of the state space with a number of (atomic) labels.
storm::storage::BitVector const & getStates(std::string const &label) const
Returns the labeling of states associated with the given label.
A bit vector that is internally represented as a vector of 64-bit values.
void grow(uint64_t minimumLength, bool init=false)
Enlarges the bit vector such that it holds at least the given number of bits (but possibly more).
void set(uint64_t index, bool value=true)
Sets the given truth value at the given index.
A class that can be used to build a sparse matrix by adding value by value.
void addNextValue(index_type row, index_type column, value_type const &value)
Sets the matrix entry at the given row and column to the given value.
void newRowGroup(index_type startingRow)
Starts a new row group in the matrix.
SparseMatrix< value_type > build(index_type overriddenRowCount=0, index_type overriddenColumnCount=0, index_type overriddenRowGroupCount=0)
A class that holds a possibly non-square matrix in the compressed row storage format.
#define STORM_LOG_WARN(message)
#define STORM_LOG_ASSERT(cond, message)
#define STORM_LOG_WARN_COND(cond, message)
#define STORM_LOG_THROW(cond, exception, message)
FragmentSpecification propositional()
std::shared_ptr< storm::models::sparse::Model< ValueType, RewardModelType > > buildModelFromComponents(storm::models::ModelType modelType, storm::storage::sparse::ModelComponents< ValueType, RewardModelType > &&components)
ValueType floor(ValueType const &number)
bool isZero(ValueType const &a)
ValueType ceil(ValueType const &number)
bool isInteger(ValueType const &number)
TargetType convertNumber(SourceType const &number)
std::unordered_map< std::string, RewardModelType > rewardModels
storm::storage::SparseMatrix< ValueType > transitionMatrix
std::optional< storm::models::sparse::ChoiceLabeling > choiceLabeling
storm::models::sparse::StateLabeling stateLabeling
std::optional< std::vector< uint32_t > > observabilityClasses