Storm 1.11.1.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
SparseModelMemoryProduct.cpp
Go to the documentation of this file.
2
3#include <boost/optional.hpp>
4
16
17namespace storm {
18namespace storage {
19
20template<typename ValueType, typename RewardModelType>
22 storm::storage::MemoryStructure const& memoryStructure)
23 : isInitialized(false), memoryStateCount(memoryStructure.getNumberOfStates()), model(sparseModel), memory(memoryStructure), scheduler(boost::none) {
24 reachableStates = storm::storage::BitVector(model.getNumberOfStates() * memoryStateCount, false);
25}
26
27template<typename ValueType, typename RewardModelType>
30 : isInitialized(false),
31 memoryStateCount(scheduler.getNumberOfMemoryStates()),
32 model(sparseModel),
33 localMemory(scheduler.getMemoryStructure() ? boost::optional<MemoryStructure>()
34 : boost::optional<MemoryStructure>(
35 storm::storage::MemoryStructureBuilder<ValueType, RewardModelType>::buildTrivialMemoryStructure(model))),
36 memory(scheduler.getMemoryStructure() ? scheduler.getMemoryStructure().get() : localMemory.get()),
37 scheduler(scheduler) {
38 reachableStates = storm::storage::BitVector(model.getNumberOfStates() * memoryStateCount, false);
39}
40
41template<typename ValueType, typename RewardModelType>
43 if (!isInitialized) {
44 uint64_t modelStateCount = model.getNumberOfStates();
45
46 computeMemorySuccessors();
47
48 // Get the initial states and reachable states. A stateIndex s corresponds to the model state (s / memoryStateCount) and memory state (s %
49 // memoryStateCount)
50 storm::storage::BitVector initialStates(modelStateCount * memoryStateCount, false);
51 auto memoryInitIt = memory.getInitialMemoryStates().begin();
52 if (memory.isOnlyInitialStatesRelevantSet()) {
53 for (auto modelInit : model.getInitialStates()) {
54 initialStates.set(modelInit * memoryStateCount + *memoryInitIt, true);
55 ++memoryInitIt;
56 }
57 } else {
58 // Build Product from all model states
59 for (uint_fast64_t modelState = 0; modelState < model.getNumberOfStates(); ++modelState) {
60 initialStates.set(modelState * memoryStateCount + *memoryInitIt, true);
61 ++memoryInitIt;
62 }
63 }
64 STORM_LOG_ASSERT(memoryInitIt == memory.getInitialMemoryStates().end(), "Unexpected number of initial states.");
65
66 computeReachableStates(initialStates);
67
68 // Compute the mapping to the states of the result
69 uint64_t reachableStateCount = 0;
70 toResultStateMapping = std::vector<uint64_t>(model.getNumberOfStates() * memoryStateCount, std::numeric_limits<uint64_t>::max());
71 for (auto reachableState : reachableStates) {
72 toResultStateMapping[reachableState] = reachableStateCount;
73 ++reachableStateCount;
74 }
75
76 isInitialized = true;
77 }
78}
79
80template<typename ValueType, typename RewardModelType>
81void SparseModelMemoryProduct<ValueType, RewardModelType>::addReachableState(uint64_t const& modelState, uint64_t const& memoryState) {
82 isInitialized = false;
83 reachableStates.set(modelState * memoryStateCount + memoryState, true);
84}
85
86template<typename ValueType, typename RewardModelType>
88 isInitialized = false;
89 reachableStates.fill();
90}
91
92template<typename ValueType, typename RewardModelType>
93std::shared_ptr<storm::models::sparse::Model<ValueType, RewardModelType>> SparseModelMemoryProduct<ValueType, RewardModelType>::build(bool preserveModelType) {
94 initialize();
95
96 // Build the model components
98 if (scheduler) {
99 transitionMatrix = buildTransitionMatrixForScheduler();
100 } else if (model.getTransitionMatrix().hasTrivialRowGrouping()) {
101 transitionMatrix = buildDeterministicTransitionMatrix();
102 } else {
103 transitionMatrix = buildNondeterministicTransitionMatrix();
104 }
105 storm::models::sparse::StateLabeling labeling = buildStateLabeling(transitionMatrix);
106 std::unordered_map<std::string, RewardModelType> rewardModels = buildRewardModels(transitionMatrix);
107
108 return buildResult(std::move(transitionMatrix), std::move(labeling), std::move(rewardModels), preserveModelType);
109}
110
111template<typename ValueType, typename RewardModelType>
112bool SparseModelMemoryProduct<ValueType, RewardModelType>::isStateReachable(uint64_t const& modelState, uint64_t const& memoryState) {
113 STORM_LOG_ASSERT(modelState < getOriginalModel().getNumberOfStates(), "Invalid model state: " << modelState << ".");
114 STORM_LOG_ASSERT(memoryState < memoryStateCount, "Invalid memory state: " << memoryState << ".");
115 initialize();
116 return reachableStates.get(modelState * memoryStateCount + memoryState);
117}
118
119template<typename ValueType, typename RewardModelType>
120uint64_t const& SparseModelMemoryProduct<ValueType, RewardModelType>::getResultState(uint64_t const& modelState, uint64_t const& memoryState) {
121 initialize();
122 STORM_LOG_ASSERT(isStateReachable(modelState, memoryState), "Tried to get unreachable product state (" << modelState << "," << memoryState << ")");
123 return toResultStateMapping[modelState * memoryStateCount + memoryState];
124}
125
126template<typename ValueType, typename RewardModelType>
128 uint64_t modelTransitionCount = model.getTransitionMatrix().getEntryCount();
129 memorySuccessors = std::vector<uint64_t>(modelTransitionCount * memoryStateCount, std::numeric_limits<uint64_t>::max());
130
131 for (uint64_t memoryState = 0; memoryState < memoryStateCount; ++memoryState) {
132 for (uint64_t transitionGoal = 0; transitionGoal < memoryStateCount; ++transitionGoal) {
133 auto const& memoryTransition = memory.getTransitionMatrix()[memoryState][transitionGoal];
134 if (memoryTransition) {
135 for (auto modelTransitionIndex : memoryTransition.get()) {
136 memorySuccessors[modelTransitionIndex * memoryStateCount + memoryState] = transitionGoal;
137 }
138 }
139 }
140 }
141}
142
143template<typename ValueType, typename RewardModelType>
144void SparseModelMemoryProduct<ValueType, RewardModelType>::computeReachableStates(storm::storage::BitVector const& initialStates) {
145 // Explore the reachable states via DFS.
146 // A state s on the stack corresponds to the model state (s / memoryStateCount) and memory state (s % memoryStateCount)
147 reachableStates |= initialStates;
148 if (!reachableStates.full()) {
149 std::vector<uint64_t> stack(reachableStates.begin(), reachableStates.end());
150 while (!stack.empty()) {
151 uint64_t stateIndex = stack.back();
152 stack.pop_back();
153 uint64_t modelState = stateIndex / memoryStateCount;
154 uint64_t memoryState = stateIndex % memoryStateCount;
155
156 if (scheduler) {
157 auto choices = scheduler->getChoice(modelState, memoryState).getChoiceAsDistribution();
158 uint64_t groupStart = model.getTransitionMatrix().getRowGroupIndices()[modelState];
159 for (auto const& choice : choices) {
160 STORM_LOG_ASSERT(groupStart + choice.first < model.getTransitionMatrix().getRowGroupIndices()[modelState + 1],
161 "Invalid choice " << choice.first << " at model state " << modelState << ".");
162 auto const& row = model.getTransitionMatrix().getRow(groupStart + choice.first);
163 for (auto modelTransitionIt = row.begin(); modelTransitionIt != row.end(); ++modelTransitionIt) {
164 if (!storm::utility::isZero(modelTransitionIt->getValue())) {
165 uint64_t successorModelState = modelTransitionIt->getColumn();
166 uint64_t modelTransitionId = modelTransitionIt - model.getTransitionMatrix().begin();
167 uint64_t successorMemoryState = memorySuccessors[modelTransitionId * memoryStateCount + memoryState];
168 uint64_t successorStateIndex = successorModelState * memoryStateCount + successorMemoryState;
169 if (!reachableStates.get(successorStateIndex)) {
170 reachableStates.set(successorStateIndex, true);
171 stack.push_back(successorStateIndex);
172 }
173 }
174 }
175 }
176 } else {
177 auto const& rowGroup = model.getTransitionMatrix().getRowGroup(modelState);
178 for (auto modelTransitionIt = rowGroup.begin(); modelTransitionIt != rowGroup.end(); ++modelTransitionIt) {
179 if (!storm::utility::isZero(modelTransitionIt->getValue())) {
180 uint64_t successorModelState = modelTransitionIt->getColumn();
181 uint64_t modelTransitionId = modelTransitionIt - model.getTransitionMatrix().begin();
182 uint64_t successorMemoryState = memorySuccessors[modelTransitionId * memoryStateCount + memoryState];
183 uint64_t successorStateIndex = successorModelState * memoryStateCount + successorMemoryState;
184 if (!reachableStates.get(successorStateIndex)) {
185 reachableStates.set(successorStateIndex, true);
186 stack.push_back(successorStateIndex);
187 }
188 }
189 }
190 }
191 }
192 }
193}
194
195template<typename ValueType, typename RewardModelType>
196storm::storage::SparseMatrix<ValueType> SparseModelMemoryProduct<ValueType, RewardModelType>::buildDeterministicTransitionMatrix() {
197 uint64_t numResStates = reachableStates.getNumberOfSetBits();
198 uint64_t numResTransitions = 0;
199 for (auto stateIndex : reachableStates) {
200 numResTransitions += model.getTransitionMatrix().getRow(stateIndex / memoryStateCount).getNumberOfEntries();
201 }
202
203 storm::storage::SparseMatrixBuilder<ValueType> builder(numResStates, numResStates, numResTransitions, true);
204 uint64_t currentRow = 0;
205 for (auto stateIndex : reachableStates) {
206 uint64_t modelState = stateIndex / memoryStateCount;
207 uint64_t memoryState = stateIndex % memoryStateCount;
208 auto const& modelRow = model.getTransitionMatrix().getRow(modelState);
209 for (auto entryIt = modelRow.begin(); entryIt != modelRow.end(); ++entryIt) {
210 uint64_t transitionId = entryIt - model.getTransitionMatrix().begin();
211 uint64_t successorMemoryState = memorySuccessors[transitionId * memoryStateCount + memoryState];
212 builder.addNextValue(currentRow, getResultState(entryIt->getColumn(), successorMemoryState), entryIt->getValue());
213 }
214 ++currentRow;
215 }
216
217 return builder.build();
218}
219
220template<typename ValueType, typename RewardModelType>
221storm::storage::SparseMatrix<ValueType> SparseModelMemoryProduct<ValueType, RewardModelType>::buildNondeterministicTransitionMatrix() {
222 uint64_t numResStates = reachableStates.getNumberOfSetBits();
223 uint64_t numResChoices = 0;
224 uint64_t numResTransitions = 0;
225 for (auto stateIndex : reachableStates) {
226 uint64_t modelState = stateIndex / memoryStateCount;
227 for (uint64_t modelRow = model.getTransitionMatrix().getRowGroupIndices()[modelState];
228 modelRow < model.getTransitionMatrix().getRowGroupIndices()[modelState + 1]; ++modelRow) {
229 ++numResChoices;
230 numResTransitions += model.getTransitionMatrix().getRow(modelRow).getNumberOfEntries();
231 }
232 }
233
234 storm::storage::SparseMatrixBuilder<ValueType> builder(numResChoices, numResStates, numResTransitions, true, true, numResStates);
235 uint64_t currentRow = 0;
236 for (auto stateIndex : reachableStates) {
237 uint64_t modelState = stateIndex / memoryStateCount;
238 uint64_t memoryState = stateIndex % memoryStateCount;
239 builder.newRowGroup(currentRow);
240 for (uint64_t modelRowIndex = model.getTransitionMatrix().getRowGroupIndices()[modelState];
241 modelRowIndex < model.getTransitionMatrix().getRowGroupIndices()[modelState + 1]; ++modelRowIndex) {
242 auto const& modelRow = model.getTransitionMatrix().getRow(modelRowIndex);
243 for (auto entryIt = modelRow.begin(); entryIt != modelRow.end(); ++entryIt) {
244 uint64_t transitionId = entryIt - model.getTransitionMatrix().begin();
245 uint64_t successorMemoryState = memorySuccessors[transitionId * memoryStateCount + memoryState];
246 builder.addNextValue(currentRow, getResultState(entryIt->getColumn(), successorMemoryState), entryIt->getValue());
247 }
248 ++currentRow;
249 }
250 }
251
252 return builder.build();
253}
254
255template<typename ValueType, typename RewardModelType>
256storm::storage::SparseMatrix<ValueType> SparseModelMemoryProduct<ValueType, RewardModelType>::buildTransitionMatrixForScheduler() {
257 uint64_t numResStates = reachableStates.getNumberOfSetBits();
258 uint64_t numResChoices = 0;
259 uint64_t numResTransitions = 0;
260 bool hasTrivialNondeterminism = true;
261 for (auto stateIndex : reachableStates) {
262 uint64_t modelState = stateIndex / memoryStateCount;
263 uint64_t memoryState = stateIndex % memoryStateCount;
264 storm::storage::SchedulerChoice<ValueType> choice = scheduler->getChoice(modelState, memoryState);
265 if (choice.isDefined()) {
266 ++numResChoices;
267 if (choice.isDeterministic()) {
268 uint64_t modelRow = model.getTransitionMatrix().getRowGroupIndices()[modelState] + choice.getDeterministicChoice();
269 numResTransitions += model.getTransitionMatrix().getRow(modelRow).getNumberOfEntries();
270 } else {
271 std::set<uint64_t> successors;
272 for (auto const& choiceIndex : choice.getChoiceAsDistribution()) {
273 if (!storm::utility::isZero(choiceIndex.second)) {
274 uint64_t modelRow = model.getTransitionMatrix().getRowGroupIndices()[modelState] + choiceIndex.first;
275 for (auto const& entry : model.getTransitionMatrix().getRow(modelRow)) {
276 successors.insert(entry.getColumn());
277 }
278 }
279 }
280 numResTransitions += successors.size();
281 }
282 } else {
283 uint64_t modelRow = model.getTransitionMatrix().getRowGroupIndices()[modelState];
284 uint64_t groupEnd = model.getTransitionMatrix().getRowGroupIndices()[modelState + 1];
285 hasTrivialNondeterminism = hasTrivialNondeterminism && (groupEnd == modelRow + 1);
286 for (; modelRow < groupEnd; ++modelRow) {
287 ++numResChoices;
288 numResTransitions += model.getTransitionMatrix().getRow(modelRow).getNumberOfEntries();
289 }
290 }
291 }
292
293 storm::storage::SparseMatrixBuilder<ValueType> builder(numResChoices, numResStates, numResTransitions, true, !hasTrivialNondeterminism,
294 hasTrivialNondeterminism ? 0 : numResStates);
295 uint64_t currentRow = 0;
296 for (auto stateIndex : reachableStates) {
297 uint64_t modelState = stateIndex / memoryStateCount;
298 uint64_t memoryState = stateIndex % memoryStateCount;
299 if (!hasTrivialNondeterminism) {
300 builder.newRowGroup(currentRow);
301 }
302 storm::storage::SchedulerChoice<ValueType> choice = scheduler->getChoice(modelState, memoryState);
303 if (choice.isDefined()) {
304 if (choice.isDeterministic()) {
305 uint64_t modelRowIndex = model.getTransitionMatrix().getRowGroupIndices()[modelState] + choice.getDeterministicChoice();
306 auto const& modelRow = model.getTransitionMatrix().getRow(modelRowIndex);
307 for (auto entryIt = modelRow.begin(); entryIt != modelRow.end(); ++entryIt) {
308 uint64_t transitionId = entryIt - model.getTransitionMatrix().begin();
309 uint64_t successorMemoryState = memorySuccessors[transitionId * memoryStateCount + memoryState];
310 builder.addNextValue(currentRow, getResultState(entryIt->getColumn(), successorMemoryState), entryIt->getValue());
311 }
312 } else {
313 std::map<uint64_t, ValueType> transitions;
314 for (auto const& choiceIndex : choice.getChoiceAsDistribution()) {
315 if (!storm::utility::isZero(choiceIndex.second)) {
316 uint64_t modelRowIndex = model.getTransitionMatrix().getRowGroupIndices()[modelState] + choiceIndex.first;
317 auto const& modelRow = model.getTransitionMatrix().getRow(modelRowIndex);
318 for (auto entryIt = modelRow.begin(); entryIt != modelRow.end(); ++entryIt) {
319 uint64_t transitionId = entryIt - model.getTransitionMatrix().begin();
320 uint64_t successorMemoryState = memorySuccessors[transitionId * memoryStateCount + memoryState];
321 ValueType transitionValue = choiceIndex.second * entryIt->getValue();
322 auto insertionRes = transitions.insert(std::make_pair(getResultState(entryIt->getColumn(), successorMemoryState), transitionValue));
323 if (!insertionRes.second) {
324 insertionRes.first->second += transitionValue;
325 }
326 }
327 }
328 }
329 for (auto const& transition : transitions) {
330 builder.addNextValue(currentRow, transition.first, transition.second);
331 }
332 }
333 ++currentRow;
334 } else {
335 for (uint64_t modelRowIndex = model.getTransitionMatrix().getRowGroupIndices()[modelState];
336 modelRowIndex < model.getTransitionMatrix().getRowGroupIndices()[modelState + 1]; ++modelRowIndex) {
337 auto const& modelRow = model.getTransitionMatrix().getRow(modelRowIndex);
338 for (auto entryIt = modelRow.begin(); entryIt != modelRow.end(); ++entryIt) {
339 uint64_t transitionId = entryIt - model.getTransitionMatrix().begin();
340 uint64_t successorMemoryState = memorySuccessors[transitionId * memoryStateCount + memoryState];
341 builder.addNextValue(currentRow, getResultState(entryIt->getColumn(), successorMemoryState), entryIt->getValue());
342 }
343 ++currentRow;
344 }
345 }
346 }
347
348 return builder.build();
349}
350
351template<typename ValueType, typename RewardModelType>
352storm::models::sparse::StateLabeling SparseModelMemoryProduct<ValueType, RewardModelType>::buildStateLabeling(
353 storm::storage::SparseMatrix<ValueType> const& resultTransitionMatrix) {
354 uint64_t modelStateCount = model.getNumberOfStates();
355
356 uint64_t numResStates = resultTransitionMatrix.getRowGroupCount();
357 storm::models::sparse::StateLabeling resultLabeling(numResStates);
358
359 for (std::string modelLabel : model.getStateLabeling().getLabels()) {
360 if (modelLabel != "init") {
361 storm::storage::BitVector resLabeledStates(numResStates, false);
362 for (auto modelState : model.getStateLabeling().getStates(modelLabel)) {
363 for (uint64_t memoryState = 0; memoryState < memoryStateCount; ++memoryState) {
364 if (isStateReachable(modelState, memoryState)) {
365 resLabeledStates.set(getResultState(modelState, memoryState), true);
366 }
367 }
368 }
369 resultLabeling.addLabel(modelLabel, std::move(resLabeledStates));
370 }
371 }
372 for (std::string memoryLabel : memory.getStateLabeling().getLabels()) {
373 STORM_LOG_THROW(!resultLabeling.containsLabel(memoryLabel), storm::exceptions::InvalidOperationException,
374 "Failed to build the product of model and memory structure: State labelings are not disjoint as both structures contain the label "
375 << memoryLabel << ".");
376 storm::storage::BitVector resLabeledStates(numResStates, false);
377 for (auto memoryState : memory.getStateLabeling().getStates(memoryLabel)) {
378 for (uint64_t modelState = 0; modelState < modelStateCount; ++modelState) {
379 if (isStateReachable(modelState, memoryState)) {
380 resLabeledStates.set(getResultState(modelState, memoryState), true);
381 }
382 }
383 }
384 resultLabeling.addLabel(memoryLabel, std::move(resLabeledStates));
385 }
386
387 storm::storage::BitVector initialStates(numResStates, false);
388 auto memoryInitIt = memory.getInitialMemoryStates().begin();
389 for (auto modelInit : model.getInitialStates()) {
390 initialStates.set(getResultState(modelInit, *memoryInitIt), true);
391 ++memoryInitIt;
392 }
393 resultLabeling.addLabel("init", std::move(initialStates));
394
395 return resultLabeling;
396}
397
398template<typename ValueType, typename RewardModelType>
399std::unordered_map<std::string, RewardModelType> SparseModelMemoryProduct<ValueType, RewardModelType>::buildRewardModels(
400 storm::storage::SparseMatrix<ValueType> const& resultTransitionMatrix) {
401 typedef typename RewardModelType::ValueType RewardValueType;
402
403 std::unordered_map<std::string, RewardModelType> result;
404 uint64_t numResStates = resultTransitionMatrix.getRowGroupCount();
405
406 for (auto const& rewardModel : model.getRewardModels()) {
407 std::optional<std::vector<RewardValueType>> stateRewards;
408 if (rewardModel.second.hasStateRewards()) {
409 stateRewards = std::vector<RewardValueType>(numResStates, storm::utility::zero<RewardValueType>());
410 uint64_t modelState = 0;
411 for (auto const& modelStateReward : rewardModel.second.getStateRewardVector()) {
412 if (!storm::utility::isZero(modelStateReward)) {
413 for (uint64_t memoryState = 0; memoryState < memoryStateCount; ++memoryState) {
414 if (isStateReachable(modelState, memoryState)) {
415 stateRewards.value()[getResultState(modelState, memoryState)] = modelStateReward;
416 }
417 }
418 }
419 ++modelState;
420 }
421 }
422 std::optional<std::vector<RewardValueType>> stateActionRewards;
423 if (rewardModel.second.hasStateActionRewards()) {
424 stateActionRewards = std::vector<RewardValueType>(resultTransitionMatrix.getRowCount(), storm::utility::zero<RewardValueType>());
425 uint64_t modelState = 0;
426 uint64_t modelRow = 0;
427 for (auto const& modelStateActionReward : rewardModel.second.getStateActionRewardVector()) {
428 if (!storm::utility::isZero(modelStateActionReward)) {
429 while (modelRow >= model.getTransitionMatrix().getRowGroupIndices()[modelState + 1]) {
430 ++modelState;
431 }
432 uint64_t rowOffset = modelRow - model.getTransitionMatrix().getRowGroupIndices()[modelState];
433 for (uint64_t memoryState = 0; memoryState < memoryStateCount; ++memoryState) {
434 if (isStateReachable(modelState, memoryState)) {
435 if (scheduler && scheduler->getChoice(modelState, memoryState).isDefined()) {
436 ValueType factor = scheduler->getChoice(modelState, memoryState).getChoiceAsDistribution().getProbability(rowOffset);
437 stateActionRewards.value()[resultTransitionMatrix.getRowGroupIndices()[getResultState(modelState, memoryState)]] +=
438 factor * modelStateActionReward;
439 } else {
440 stateActionRewards.value()[resultTransitionMatrix.getRowGroupIndices()[getResultState(modelState, memoryState)] + rowOffset] =
441 modelStateActionReward;
442 }
443 }
444 }
445 }
446 ++modelRow;
447 }
448 }
449 std::optional<storm::storage::SparseMatrix<RewardValueType>> transitionRewards;
450 if (rewardModel.second.hasTransitionRewards()) {
451 bool const useRowGrouping = !resultTransitionMatrix.hasTrivialRowGrouping();
452 storm::storage::SparseMatrixBuilder<RewardValueType> builder(resultTransitionMatrix.getRowCount(), resultTransitionMatrix.getColumnCount(), 0ull,
453 true, useRowGrouping,
454 useRowGrouping ? resultTransitionMatrix.getRowGroupCount() : 0ull);
455 uint64_t stateIndex = 0;
456 for (auto const& resState : toResultStateMapping) {
457 if (resState < numResStates) {
458 uint64_t modelState = stateIndex / memoryStateCount;
459 uint64_t memoryState = stateIndex % memoryStateCount;
460 uint64_t rowGroupSize = resultTransitionMatrix.getRowGroupSize(resState);
461 if (useRowGrouping) {
462 builder.newRowGroup(resultTransitionMatrix.getRowGroupIndices()[resState]);
463 }
464 if (scheduler && scheduler->getChoice(modelState, memoryState).isDefined()) {
465 std::map<uint64_t, RewardValueType> rewards;
466 for (uint64_t rowOffset = 0; rowOffset < rowGroupSize; ++rowOffset) {
467 uint64_t modelRowIndex = model.getTransitionMatrix().getRowGroupIndices()[modelState] + rowOffset;
468 auto transitionEntryIt = model.getTransitionMatrix().getRow(modelRowIndex).begin();
469 for (auto const& rewardEntry : rewardModel.second.getTransitionRewardMatrix().getRow(modelRowIndex)) {
470 while (transitionEntryIt->getColumn() != rewardEntry.getColumn()) {
471 STORM_LOG_ASSERT(transitionEntryIt != model.getTransitionMatrix().getRow(modelRowIndex).end(),
472 "The reward transition matrix is not a submatrix of the model transition matrix.");
473 ++transitionEntryIt;
474 }
475 uint64_t transitionId = transitionEntryIt - model.getTransitionMatrix().begin();
476 uint64_t successorMemoryState = memorySuccessors[transitionId * memoryStateCount + memoryState];
477 auto insertionRes =
478 rewards.insert(std::make_pair(getResultState(rewardEntry.getColumn(), successorMemoryState), rewardEntry.getValue()));
479 if (!insertionRes.second) {
480 insertionRes.first->second += rewardEntry.getValue();
481 }
482 }
483 }
484 uint64_t resRowIndex = resultTransitionMatrix.getRowGroupIndices()[resState];
485 for (auto& reward : rewards) {
486 builder.addNextValue(resRowIndex, reward.first, reward.second);
487 }
488 } else {
489 for (uint64_t rowOffset = 0; rowOffset < rowGroupSize; ++rowOffset) {
490 uint64_t resRowIndex = resultTransitionMatrix.getRowGroupIndices()[resState] + rowOffset;
491 uint64_t modelRowIndex = model.getTransitionMatrix().getRowGroupIndices()[modelState] + rowOffset;
492 auto transitionEntryIt = model.getTransitionMatrix().getRow(modelRowIndex).begin();
493 for (auto const& rewardEntry : rewardModel.second.getTransitionRewardMatrix().getRow(modelRowIndex)) {
494 while (transitionEntryIt->getColumn() != rewardEntry.getColumn()) {
495 STORM_LOG_ASSERT(transitionEntryIt != model.getTransitionMatrix().getRow(modelRowIndex).end(),
496 "The reward transition matrix is not a submatrix of the model transition matrix.");
497 ++transitionEntryIt;
498 }
499 uint64_t transitionId = transitionEntryIt - model.getTransitionMatrix().begin();
500 uint64_t successorMemoryState = memorySuccessors[transitionId * memoryStateCount + memoryState];
501 builder.addNextValue(resRowIndex, getResultState(rewardEntry.getColumn(), successorMemoryState), rewardEntry.getValue());
502 }
503 }
504 }
505 }
506 ++stateIndex;
507 }
508 transitionRewards = builder.build();
509 }
510 result.insert(std::make_pair(rewardModel.first, RewardModelType(std::move(stateRewards), std::move(stateActionRewards), std::move(transitionRewards))));
511 }
512 return result;
513}
514
515template<typename ValueType, typename RewardModelType>
516std::shared_ptr<storm::models::sparse::Model<ValueType, RewardModelType>> SparseModelMemoryProduct<ValueType, RewardModelType>::buildResult(
518 std::unordered_map<std::string, RewardModelType>&& rewardModels, bool preserveModelType) {
519 storm::storage::sparse::ModelComponents<ValueType, RewardModelType> components(std::move(matrix), std::move(labeling), std::move(rewardModels));
520
521 auto targetModelType = model.getType();
522 if (model.isOfType(storm::models::ModelType::Ctmc)) {
523 components.rateTransitions = true;
524 } else if (model.isOfType(storm::models::ModelType::Mdp)) {
525 if (!preserveModelType && matrix.hasTrivialRowGrouping()) {
526 targetModelType = storm::models::ModelType::Dtmc;
527 }
528 } else if (model.isOfType(storm::models::ModelType::MarkovAutomaton)) {
529 // We also need to translate the exit rates and the Markovian states
530 uint64_t numResStates = components.transitionMatrix.getRowGroupCount();
531 std::vector<ValueType> resultExitRates;
532 resultExitRates.reserve(components.transitionMatrix.getRowGroupCount());
533 storm::storage::BitVector resultMarkovianStates(numResStates, false);
534 auto const& modelExitRates = dynamic_cast<storm::models::sparse::MarkovAutomaton<ValueType, RewardModelType> const&>(model).getExitRates();
535 auto const& modelMarkovianStates = dynamic_cast<storm::models::sparse::MarkovAutomaton<ValueType, RewardModelType> const&>(model).getMarkovianStates();
536
537 uint64_t stateIndex = 0;
538 for (auto const& resState : toResultStateMapping) {
539 if (resState < numResStates) {
540 assert(resState == resultExitRates.size());
541 uint64_t modelState = stateIndex / memoryStateCount;
542 resultExitRates.push_back(modelExitRates[modelState]);
543 if (modelMarkovianStates.get(modelState)) {
544 resultMarkovianStates.set(resState, true);
545 }
546 }
547 ++stateIndex;
548 }
549 components.markovianStates = std::move(resultMarkovianStates);
550 components.exitRates = std::move(resultExitRates);
551 }
552
553 return storm::utility::builder::buildModelFromComponents(targetModelType, std::move(components));
554}
555
556template<typename ValueType, typename RewardModelType>
560
561template<typename ValueType, typename RewardModelType>
565
566template<typename ValueType, typename RewardModelType>
568 STORM_LOG_ASSERT(isInitialized, "The product model has not been built yet. Cannot extract reverse data.");
569 return SparseModelMemoryProductReverseData(getOriginalModel().getNumberOfStates(), getMemory(), toResultStateMapping);
570}
571
577
578} // namespace storage
579} // namespace storm
This class represents a Markov automaton.
Base class for all sparse models.
Definition Model.h:32
This class manages the labeling of the state space with a number of (atomic) labels.
A bit vector that is internally represented as a vector of 64-bit values.
Definition BitVector.h:16
void set(uint64_t index, bool value=true)
Sets the given truth value at the given index.
This class represents a (deterministic) memory structure that can be used to encode certain events (s...
uint_fast64_t getDeterministicChoice() const
If this choice is deterministic, this function returns the selected (local) choice index.
bool isDeterministic() const
Returns true iff this scheduler choice is deterministic (i.e., not randomized)
bool isDefined() const
Returns true iff this scheduler choice is defined.
This class defines which action is chosen in a particular state of a non-deterministic model.
Definition Scheduler.h:18
index_type getNumberOfEntries() const
Retrieves the number of entries in the rows.
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.
const_rows getRow(index_type row) const
Returns an object representing the given row.
index_type getRowGroupCount() const
Returns the number of row groups in the matrix.
index_type getColumnCount() const
Returns the number of columns of the matrix.
bool hasTrivialRowGrouping() const
Retrieves whether the matrix has a trivial row grouping.
std::vector< index_type > const & getRowGroupIndices() const
Returns the grouping of rows of this matrix.
index_type getRowGroupSize(index_type group) const
Returns the size of the given row group.
index_type getRowCount() const
Returns the number of rows of the matrix.
This class builds the product of the given sparse model and the given memory structure.
storm::storage::MemoryStructure const & getMemory() const
std::shared_ptr< storm::models::sparse::Model< ValueType, RewardModelType > > build(bool preserveModelType=false)
Invokes the building of the product under the specified scheduler (if given).
void addReachableState(uint64_t const &modelState, uint64_t const &memoryState)
SparseModelMemoryProduct(storm::models::sparse::Model< ValueType, RewardModelType > const &sparseModel, storm::storage::MemoryStructure const &memoryStructure)
SparseModelMemoryProductReverseData computeReverseData() const
Extracts the reverse data that can be used to apply results for the product model back to the origina...
storm::models::sparse::Model< ValueType, RewardModelType > const & getOriginalModel() const
bool isStateReachable(uint64_t const &modelState, uint64_t const &memoryState)
uint64_t const & getResultState(uint64_t const &modelState, uint64_t const &memoryState)
Data to restore memory incorporation applied with SparseModelMemoryProduct.
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:11
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:30
SFTBDDChecker::ValueType ValueType
storm::storage::BitVector getStates(storm::logic::Formula const &propositionalFormula, bool formulaInverted, PomdpType const &pomdp)
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::pair< storm::dd::Bdd< Type >, uint64_t > computeReachableStates(storm::dd::Bdd< Type > const &initialStates, storm::dd::Bdd< Type > const &transitions, std::set< storm::expressions::Variable > const &rowMetaVariables, std::set< storm::expressions::Variable > const &columnMetaVariables)
Definition dd.cpp:13
bool isZero(ValueType const &a)
Definition constants.cpp:39