Storm 1.14.0.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
TransitionToActionRewardTransformer.cpp
Go to the documentation of this file.
2
15
16namespace storm::transformer {
17
18namespace detail {
19template<typename RewardValueType>
20using MultiRewardVector = std::vector<RewardValueType>;
21
22template<typename ValueType, typename RewardModelType = storm::models::sparse::StandardRewardModel<ValueType>>
24 public:
26
27 void addRewardModel(RewardModelType const& rewardModel) {
28 if (rewardModel.hasTransitionRewards()) {
29 transitionRewards.emplace_back(rewardModel.getTransitionRewardMatrix());
30 STORM_LOG_ASSERT(transitionRewards.back()->isSubmatrixOf(transitionMatrix), "Invalid reward matrix.");
31 } else {
32 transitionRewards.emplace_back();
33 }
34 }
35
36 template<typename CallBackType>
37 void forEachRowEntry(uint64_t rowIndex, bool skip0RewardEntries, CallBackType&& callBack) {
38 // Set-up iterators
39 std::vector<typename storm::storage::SparseMatrix<typename RewardModelType::ValueType>::const_iterator> rewardIterators;
40 std::vector<typename storm::storage::SparseMatrix<typename RewardModelType::ValueType>::const_iterator> rewardIteratorsEnd;
41 for (auto const& rewardMatrix : transitionRewards) {
42 if (rewardMatrix) {
43 rewardIterators.push_back(rewardMatrix->begin(rowIndex));
44 rewardIteratorsEnd.push_back(rewardMatrix->end(rowIndex));
45 } else {
46 rewardIterators.emplace_back();
47 rewardIteratorsEnd.emplace_back();
48 }
49 }
50
51 std::vector<typename RewardModelType::ValueType> rewards(transitionRewards.size());
52 for (auto const& entry : transitionMatrix.getRow(rowIndex)) {
53 // Fill in rewards for this entry
54 bool skipEntry = skip0RewardEntries;
55 for (uint64_t i = 0; i < transitionRewards.size(); ++i) {
56 if (rewardIterators[i] != rewardIteratorsEnd[i] && rewardIterators[i]->getColumn() == entry.getColumn()) {
57 rewards[i] = rewardIterators[i]->getValue();
58 ++rewardIterators[i];
59 skipEntry = skipEntry && storm::utility::isZero(rewards[i]);
60 } else {
62 }
63 }
64 if (!skipEntry) {
65 callBack(entry.getColumn(), entry.getValue(), rewards);
66 }
67 }
68 }
69
70 private:
71 storm::storage::SparseMatrix<ValueType> const& transitionMatrix;
72 std::vector<storm::OptionalRef<storm::storage::SparseMatrix<typename RewardModelType::ValueType> const>> transitionRewards;
73};
74
75} // namespace detail
76
77template<typename ValueType, typename RewardModelType>
79 std::shared_ptr<storm::models::sparse::Model<ValueType, RewardModelType>> originalModel, std::vector<std::string> const& relevantRewardModelNames) {
80 using RewardValueType = RewardModelType::ValueType;
81 STORM_LOG_ASSERT(originalModel, "Model must not be null.");
82 detail::RewardTransitionIterator<ValueType, RewardModelType> rewardTransitionIterator(originalModel->getTransitionMatrix());
83 bool hasTransitionRewards = false;
84 for (auto const& rewardModelName : relevantRewardModelNames) {
85 auto const& rewardModel = originalModel->getRewardModel(rewardModelName);
86 if (rewardModel.hasTransitionRewards()) {
87 hasTransitionRewards = true;
88 }
89 rewardTransitionIterator.addRewardModel(rewardModel);
90 }
91 if (!hasTransitionRewards) {
92 return {originalModel->template as<storm::models::sparse::Model<ValueType, RewardModelType>>(),
93 {storm::utility::vector::buildVectorForRange<uint64_t>(0, originalModel->getNumberOfStates())}};
94 }
95
96 // Make a pass to find the different unique rewards with which a state is entered.
97 // We do not use std::set here as the interval ordering is not a strict weak ordering for overlapping intervals.
98 // Equality-based deduplication preserves distinct overlapping rewards.
99 std::vector<std::vector<detail::MultiRewardVector<RewardValueType>>> incomingRewards(originalModel->getNumberOfStates());
100 auto const& transitions = originalModel->getTransitionMatrix();
101 for (uint64_t row = 0; row < transitions.getRowCount(); ++row) {
102 rewardTransitionIterator.forEachRowEntry(
103 row, true, [&incomingRewards](uint64_t column, ValueType, detail::MultiRewardVector<RewardValueType> const& rewards) {
105 });
106 }
107
108 // Create a mapping from original to new indices
109 std::vector<uint64_t> originalToNewIndex;
110 uint64_t numStates = 0;
111 for (auto const& incomingRewardVectors : incomingRewards) {
112 numStates += incomingRewardVectors.size();
113 originalToNewIndex.push_back(numStates);
114 ++numStates;
115 }
116
117 // Populate the new transition matrix and (action) rewards for intermediate states
118 uint64_t const numIntermediateStates = numStates - originalModel->getNumberOfStates();
119 bool const useGroups = !transitions.hasTrivialRowGrouping();
120 storm::storage::SparseMatrixBuilder<ValueType> newTransitionsBuilder(transitions.getRowCount() + numIntermediateStates, numStates,
121 transitions.getEntryCount() + numIntermediateStates, true, useGroups,
122 useGroups ? numStates : 0ull);
123 std::vector<std::vector<RewardValueType>> newActionRewards(relevantRewardModelNames.size(),
124 std::vector<RewardValueType>(transitions.getRowCount() + numIntermediateStates));
125 uint64_t currNewRow = 0;
126 for (uint64_t currOrigState = 0; currOrigState < originalModel->getNumberOfStates(); ++currOrigState) {
127 uint64_t const currNewState = originalToNewIndex[currOrigState];
128 // First add the transitions and rewards for the intermediate states
129 for (auto const& incomingRewardVector : incomingRewards[currOrigState]) {
130 if (useGroups) {
131 newTransitionsBuilder.newRowGroup(currNewRow);
132 }
133 newTransitionsBuilder.addNextValue(currNewRow, currNewState, storm::utility::one<ValueType>());
134 auto newRewIt = newActionRewards.begin();
135 for (auto const& rew : incomingRewardVector) {
136 (*newRewIt)[currNewRow] = rew;
137 ++newRewIt;
138 }
139 ++currNewRow;
140 }
141 // Add the transitions and rewards for the original state
142 if (useGroups) {
143 newTransitionsBuilder.newRowGroup(currNewRow);
144 }
145 for (auto origRowIndex : transitions.getRowGroupIndices(currOrigState)) {
146 rewardTransitionIterator.forEachRowEntry(
147 origRowIndex, false,
148 [&newTransitionsBuilder, &originalToNewIndex, &incomingRewards, &currNewRow](uint64_t column, ValueType prob,
150 if (std::all_of(rewards.begin(), rewards.end(), [](RewardValueType const& r) { return storm::utility::isZero(r); })) {
151 // No transition reward collected so use original state
152 newTransitionsBuilder.addNextValue(currNewRow, originalToNewIndex[column], prob);
153 } else {
154 // Redirect to intermediate state
155 auto incomingRewardsIt = std::find(incomingRewards[column].begin(), incomingRewards[column].end(), rewards);
156 STORM_LOG_ASSERT(incomingRewardsIt != incomingRewards[column].end(), "Invalid incoming rewards.");
157 uint64_t const intermediateStateIndex =
158 originalToNewIndex[column] - incomingRewards[column].size() + std::distance(incomingRewards[column].begin(), incomingRewardsIt);
159 newTransitionsBuilder.addNextValue(currNewRow, intermediateStateIndex, prob);
160 }
161 });
162 ++currNewRow;
163 }
164 }
165
166 // create new state labels and init components
167 storm::models::sparse::StateLabeling newLabeling(numStates);
168 for (auto const& l : originalModel->getStateLabeling().getLabels()) {
169 newLabeling.addLabel(l);
170 for (auto origIndex : originalModel->getStateLabeling().getStates(l)) {
171 newLabeling.addLabelToState(l, originalToNewIndex[origIndex]);
172 }
173 }
174 storm::storage::sparse::ModelComponents<ValueType, RewardModelType> components(newTransitionsBuilder.build(), std::move(newLabeling));
175
176 // create new reward models
177 uint64_t rewardIndex = 0;
178 for (auto const& rewardModelName : relevantRewardModelNames) {
179 auto& newActionRewardVector = newActionRewards[rewardIndex++];
180 auto const& oldRewardModel = originalModel->getRewardModel(rewardModelName);
181 for (uint64_t oldState = 0; oldState < originalModel->getNumberOfStates(); ++oldState) {
182 uint64_t const oldStartRow = transitions.getRowGroupIndices()[oldState];
183 uint64_t const newState = originalToNewIndex[oldState];
184 uint64_t const newStartRow = useGroups ? components.transitionMatrix.getRowGroupIndices()[newState] : newState;
185 uint64_t const numRowsInGroup = useGroups ? transitions.getRowGroupSize(oldState) : 1ull;
186 for (uint64_t groupOffset = 0; groupOffset < numRowsInGroup; ++groupOffset) {
187 auto& rewValue = newActionRewardVector[newStartRow + groupOffset];
188 if (originalModel->isDiscreteTimeModel() && oldRewardModel.hasStateRewards()) {
189 rewValue += oldRewardModel.getStateReward(oldState);
190 }
191 if (oldRewardModel.hasStateActionRewards()) {
192 rewValue += oldRewardModel.getStateActionReward(oldStartRow + groupOffset);
193 }
194 }
195 }
196 std::optional<std::vector<typename RewardModelType::ValueType>> newStateRewards;
197 if (!originalModel->isDiscreteTimeModel() && oldRewardModel.hasStateRewards()) {
198 newStateRewards.emplace(numStates, storm::utility::zero<ValueType>());
199 for (uint64_t origState = 0; origState < originalModel->getNumberOfStates(); ++origState) {
200 uint64_t const newState = originalToNewIndex[origState];
201 newStateRewards.value()[newState] = oldRewardModel.getStateReward(origState);
202 }
203 }
204 RewardModelType newRewardModel(std::move(newStateRewards), std::move(newActionRewardVector));
205 components.rewardModels.emplace(rewardModelName, std::move(newRewardModel));
206 }
207
208 STORM_LOG_WARN_COND(!originalModel->hasChoiceLabeling(), "Choice labellings will be dropped as the transformation is currently not implemented.");
209 STORM_LOG_WARN_COND(!originalModel->hasStateValuations(), "State valuations will be dropped as the transformation is currently not implemented.");
210 STORM_LOG_WARN_COND(!originalModel->hasChoiceOrigins(), "Choice origins will be dropped as the transformation is currently not implemented.");
211
212 // Model type specific components
213 if (originalModel->isOfType(storm::models::ModelType::MarkovAutomaton)) {
214 auto const& ma = *originalModel->template as<storm::models::sparse::MarkovAutomaton<ValueType>>();
215 components.markovianStates = storm::storage::BitVector(numStates);
216 components.exitRates = std::vector<ValueType>(numStates, storm::utility::zero<ValueType>());
217 for (uint64_t origState = 0; origState < originalModel->getNumberOfStates(); ++origState) {
218 uint64_t const newState = originalToNewIndex[origState];
219 if (ma.isMarkovianState(origState)) {
220 components.markovianStates->set(newState, true);
221 components.exitRates->at(newState) = ma.getExitRate(origState);
222 }
223 }
224 components.rateTransitions = false; // Note that originalModel->getTransitionMatrix() contains probabilities
225 } else if (originalModel->isOfType(storm::models::ModelType::Ctmc)) {
226 components.rateTransitions = true;
227 } else {
228 STORM_LOG_THROW(originalModel->isOfType(storm::models::ModelType::Dtmc) || originalModel->isOfType(storm::models::ModelType::Mdp),
229 storm::exceptions::UnexpectedException, "Unhandled model type.");
230 }
231 return {storm::utility::builder::buildModelFromComponents(originalModel->getType(), std::move(components)), std::move(originalToNewIndex)};
232}
233
234template struct TransitionToActionRewardTransformerReturnType<double>;
235template struct TransitionToActionRewardTransformerReturnType<storm::RationalNumber>;
236template struct TransitionToActionRewardTransformerReturnType<storm::RationalFunction>;
237template struct TransitionToActionRewardTransformerReturnType<storm::Interval>;
238template struct TransitionToActionRewardTransformerReturnType<storm::RationalInterval>;
239template struct TransitionToActionRewardTransformerReturnType<double, storm::models::sparse::StandardRewardModel<storm::Interval>>;
240template struct TransitionToActionRewardTransformerReturnType<storm::RationalNumber, storm::models::sparse::StandardRewardModel<storm::RationalInterval>>;
241
243 std::shared_ptr<storm::models::sparse::Model<double>> originalModel, std::vector<std::string> const& relevantRewardModelNames);
246 std::shared_ptr<storm::models::sparse::Model<storm::RationalNumber>> originalModel, std::vector<std::string> const& relevantRewardModelNames);
249 std::shared_ptr<storm::models::sparse::Model<storm::RationalFunction>> originalModel, std::vector<std::string> const& relevantRewardModelNames);
252 std::shared_ptr<storm::models::sparse::Model<storm::Interval>> originalModel, std::vector<std::string> const& relevantRewardModelNames);
255 std::shared_ptr<storm::models::sparse::Model<storm::RationalInterval>> originalModel, std::vector<std::string> const& relevantRewardModelNames);
258 std::shared_ptr<storm::models::sparse::Model<double, storm::models::sparse::StandardRewardModel<storm::Interval>>> originalModel,
259 std::vector<std::string> const& relevantRewardModelNames);
262 std::shared_ptr<storm::models::sparse::Model<storm::RationalNumber, storm::models::sparse::StandardRewardModel<storm::RationalInterval>>> originalModel,
263 std::vector<std::string> const& relevantRewardModelNames);
264
265} // namespace storm::transformer
void addLabel(std::string const &label)
Adds a new label to the labelings.
Base class for all sparse models.
Definition Model.h:34
This class manages the labeling of the state space with a number of (atomic) labels.
void addLabelToState(std::string const &label, storm::storage::sparse::state_type state)
Adds a label to a given state.
A bit vector that is internally represented as a vector of 64-bit values.
Definition BitVector.h:16
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.
RewardTransitionIterator(storm::storage::SparseMatrix< ValueType > const &m)
void forEachRowEntry(uint64_t rowIndex, bool skip0RewardEntries, CallBackType &&callBack)
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:9
#define STORM_LOG_WARN_COND(cond, message)
Definition macros.h:54
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:39
std::vector< RewardValueType > MultiRewardVector
TransitionToActionRewardTransformerReturnType< ValueType, RewardModelType > transformTransitionToActionRewards(std::shared_ptr< storm::models::sparse::Model< ValueType, RewardModelType > > originalModel, std::vector< std::string > const &relevantRewardModelNames)
Replaces transition branch rewards from all given reward models and replaces them by equivalent state...
std::shared_ptr< storm::models::sparse::Model< ValueType, RewardModelType > > buildModelFromComponents(storm::models::ModelType modelType, storm::storage::sparse::ModelComponents< ValueType, RewardModelType > &&components)
Definition builder.cpp:20
std::size_t findOrInsert(std::vector< T > &vector, T &&element)
Finds the given element in the given vector.
Definition vector.h:45
std::vector< T > buildVectorForRange(T min, T max)
Constructs a vector [min, min+1, ...., max-1].
Definition vector.h:130
bool isZero(ValueType const &a)
Definition constants.cpp:44
ValueType zero()
Definition constants.cpp:26
ValueType one()
Definition constants.cpp:21
std::unordered_map< std::string, RewardModelType > rewardModels
storm::storage::SparseMatrix< ValueType > transitionMatrix
boost::optional< storm::storage::BitVector > markovianStates
boost::optional< std::vector< ValueType > > exitRates