Storm 1.14.0.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>
42void SparseModelMemoryProduct<ValueType, RewardModelType>::initialize() {
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 (uint64_t 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>
127void SparseModelMemoryProduct<ValueType, RewardModelType>::computeMemorySuccessors() {
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 (uint64_t 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 (uint64_t 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 (uint64_t 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 (uint64_t 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 (uint64_t 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 (uint64_t 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 (uint64_t 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 (uint64_t 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 if (memory.isOnlyInitialStatesRelevantSet()) {
390 for (uint64_t modelInit : model.getInitialStates()) {
391 initialStates.set(getResultState(modelInit, *memoryInitIt), true);
392 ++memoryInitIt;
393 }
394 } else {
395 for (uint_fast64_t modelState = 0; modelState < model.getNumberOfStates(); ++modelState) {
396 initialStates.set(getResultState(modelState, *memoryInitIt), true);
397 ++memoryInitIt;
398 }
399 }
400 resultLabeling.addLabel("init", std::move(initialStates));
401
402 return resultLabeling;
403}
404
405template<typename ValueType, typename RewardModelType>
406std::unordered_map<std::string, RewardModelType> SparseModelMemoryProduct<ValueType, RewardModelType>::buildRewardModels(
407 storm::storage::SparseMatrix<ValueType> const& resultTransitionMatrix) {
408 typedef typename RewardModelType::ValueType RewardValueType;
409
410 std::unordered_map<std::string, RewardModelType> result;
411 uint64_t numResStates = resultTransitionMatrix.getRowGroupCount();
412
413 for (auto const& rewardModel : model.getRewardModels()) {
414 std::optional<std::vector<RewardValueType>> stateRewards;
415 if (rewardModel.second.hasStateRewards()) {
416 stateRewards = std::vector<RewardValueType>(numResStates, storm::utility::zero<RewardValueType>());
417 uint64_t modelState = 0;
418 for (auto const& modelStateReward : rewardModel.second.getStateRewardVector()) {
419 if (!storm::utility::isZero(modelStateReward)) {
420 for (uint64_t memoryState = 0; memoryState < memoryStateCount; ++memoryState) {
421 if (isStateReachable(modelState, memoryState)) {
422 stateRewards.value()[getResultState(modelState, memoryState)] = modelStateReward;
423 }
424 }
425 }
426 ++modelState;
427 }
428 }
429 std::optional<std::vector<RewardValueType>> stateActionRewards;
430 if (rewardModel.second.hasStateActionRewards()) {
431 stateActionRewards = std::vector<RewardValueType>(resultTransitionMatrix.getRowCount(), storm::utility::zero<RewardValueType>());
432 uint64_t modelState = 0;
433 uint64_t modelRow = 0;
434 for (auto const& modelStateActionReward : rewardModel.second.getStateActionRewardVector()) {
435 if (!storm::utility::isZero(modelStateActionReward)) {
436 while (modelRow >= model.getTransitionMatrix().getRowGroupIndices()[modelState + 1]) {
437 ++modelState;
438 }
439 uint64_t rowOffset = modelRow - model.getTransitionMatrix().getRowGroupIndices()[modelState];
440 for (uint64_t memoryState = 0; memoryState < memoryStateCount; ++memoryState) {
441 if (isStateReachable(modelState, memoryState)) {
442 if (scheduler && scheduler->getChoice(modelState, memoryState).isDefined()) {
443 ValueType factor = scheduler->getChoice(modelState, memoryState).getChoiceAsDistribution().getProbability(rowOffset);
444 stateActionRewards.value()[resultTransitionMatrix.getRowGroupIndices()[getResultState(modelState, memoryState)]] +=
445 factor * modelStateActionReward;
446 } else {
447 stateActionRewards.value()[resultTransitionMatrix.getRowGroupIndices()[getResultState(modelState, memoryState)] + rowOffset] =
448 modelStateActionReward;
449 }
450 }
451 }
452 }
453 ++modelRow;
454 }
455 }
456 std::optional<storm::storage::SparseMatrix<RewardValueType>> transitionRewards;
457 if (rewardModel.second.hasTransitionRewards()) {
458 bool const useRowGrouping = !resultTransitionMatrix.hasTrivialRowGrouping();
459 storm::storage::SparseMatrixBuilder<RewardValueType> builder(resultTransitionMatrix.getRowCount(), resultTransitionMatrix.getColumnCount(), 0ull,
460 true, useRowGrouping,
461 useRowGrouping ? resultTransitionMatrix.getRowGroupCount() : 0ull);
462 uint64_t stateIndex = 0;
463 for (auto const& resState : toResultStateMapping) {
464 if (resState < numResStates) {
465 uint64_t modelState = stateIndex / memoryStateCount;
466 uint64_t memoryState = stateIndex % memoryStateCount;
467 uint64_t rowGroupSize = resultTransitionMatrix.getRowGroupSize(resState);
468 if (useRowGrouping) {
469 builder.newRowGroup(resultTransitionMatrix.getRowGroupIndices()[resState]);
470 }
471 if (scheduler && scheduler->getChoice(modelState, memoryState).isDefined()) {
472 std::map<uint64_t, RewardValueType> rewards;
473 for (uint64_t rowOffset = 0; rowOffset < rowGroupSize; ++rowOffset) {
474 uint64_t modelRowIndex = model.getTransitionMatrix().getRowGroupIndices()[modelState] + rowOffset;
475 auto transitionEntryIt = model.getTransitionMatrix().getRow(modelRowIndex).begin();
476 for (auto const& rewardEntry : rewardModel.second.getTransitionRewardMatrix().getRow(modelRowIndex)) {
477 while (transitionEntryIt->getColumn() != rewardEntry.getColumn()) {
478 STORM_LOG_ASSERT(transitionEntryIt != model.getTransitionMatrix().getRow(modelRowIndex).end(),
479 "The reward transition matrix is not a submatrix of the model transition matrix.");
480 ++transitionEntryIt;
481 }
482 uint64_t transitionId = transitionEntryIt - model.getTransitionMatrix().begin();
483 uint64_t successorMemoryState = memorySuccessors[transitionId * memoryStateCount + memoryState];
484 auto insertionRes =
485 rewards.insert(std::make_pair(getResultState(rewardEntry.getColumn(), successorMemoryState), rewardEntry.getValue()));
486 if (!insertionRes.second) {
487 insertionRes.first->second += rewardEntry.getValue();
488 }
489 }
490 }
491 uint64_t resRowIndex = resultTransitionMatrix.getRowGroupIndices()[resState];
492 for (auto& reward : rewards) {
493 builder.addNextValue(resRowIndex, reward.first, reward.second);
494 }
495 } else {
496 for (uint64_t rowOffset = 0; rowOffset < rowGroupSize; ++rowOffset) {
497 uint64_t resRowIndex = resultTransitionMatrix.getRowGroupIndices()[resState] + rowOffset;
498 uint64_t modelRowIndex = model.getTransitionMatrix().getRowGroupIndices()[modelState] + rowOffset;
499 auto transitionEntryIt = model.getTransitionMatrix().getRow(modelRowIndex).begin();
500 for (auto const& rewardEntry : rewardModel.second.getTransitionRewardMatrix().getRow(modelRowIndex)) {
501 while (transitionEntryIt->getColumn() != rewardEntry.getColumn()) {
502 STORM_LOG_ASSERT(transitionEntryIt != model.getTransitionMatrix().getRow(modelRowIndex).end(),
503 "The reward transition matrix is not a submatrix of the model transition matrix.");
504 ++transitionEntryIt;
505 }
506 uint64_t transitionId = transitionEntryIt - model.getTransitionMatrix().begin();
507 uint64_t successorMemoryState = memorySuccessors[transitionId * memoryStateCount + memoryState];
508 builder.addNextValue(resRowIndex, getResultState(rewardEntry.getColumn(), successorMemoryState), rewardEntry.getValue());
509 }
510 }
511 }
512 }
513 ++stateIndex;
514 }
515 transitionRewards = builder.build();
516 }
517 result.insert(std::make_pair(rewardModel.first, RewardModelType(std::move(stateRewards), std::move(stateActionRewards), std::move(transitionRewards))));
518 }
519 return result;
520}
521
522template<typename ValueType, typename RewardModelType>
523std::shared_ptr<storm::models::sparse::Model<ValueType, RewardModelType>> SparseModelMemoryProduct<ValueType, RewardModelType>::buildResult(
524 storm::storage::SparseMatrix<ValueType>&& matrix, storm::models::sparse::StateLabeling&& labeling,
525 std::unordered_map<std::string, RewardModelType>&& rewardModels, bool preserveModelType) {
526 storm::storage::sparse::ModelComponents<ValueType, RewardModelType> components(std::move(matrix), std::move(labeling), std::move(rewardModels));
527
528 auto targetModelType = model.getType();
529 if (model.isOfType(storm::models::ModelType::Ctmc)) {
530 components.rateTransitions = true;
531 } else if (model.isOfType(storm::models::ModelType::Mdp)) {
532 if (!preserveModelType && components.transitionMatrix.hasTrivialRowGrouping()) {
533 targetModelType = storm::models::ModelType::Dtmc;
534 }
535 } else if (model.isOfType(storm::models::ModelType::MarkovAutomaton)) {
536 // We also need to translate the exit rates and the Markovian states
537 uint64_t numResStates = components.transitionMatrix.getRowGroupCount();
538 std::vector<ValueType> resultExitRates;
539 resultExitRates.reserve(components.transitionMatrix.getRowGroupCount());
540 storm::storage::BitVector resultMarkovianStates(numResStates, false);
541 auto const& modelExitRates = dynamic_cast<storm::models::sparse::MarkovAutomaton<ValueType, RewardModelType> const&>(model).getExitRates();
542 auto const& modelMarkovianStates = dynamic_cast<storm::models::sparse::MarkovAutomaton<ValueType, RewardModelType> const&>(model).getMarkovianStates();
543
544 uint64_t stateIndex = 0;
545 for (auto const& resState : toResultStateMapping) {
546 if (resState < numResStates) {
547 STORM_LOG_ASSERT(resState == resultExitRates.size(), "Result state index mismatch.");
548 uint64_t modelState = stateIndex / memoryStateCount;
549 resultExitRates.push_back(modelExitRates[modelState]);
550 if (modelMarkovianStates.get(modelState)) {
551 resultMarkovianStates.set(resState, true);
552 }
553 }
554 ++stateIndex;
555 }
556 components.markovianStates = std::move(resultMarkovianStates);
557 components.exitRates = std::move(resultExitRates);
558 }
559
560 return storm::utility::builder::buildModelFromComponents(targetModelType, std::move(components));
561}
562
563template<typename ValueType, typename RewardModelType>
567
568template<typename ValueType, typename RewardModelType>
572
573template<typename ValueType, typename RewardModelType>
575 STORM_LOG_ASSERT(isInitialized, "The product model has not been built yet. Cannot extract reverse data.");
576 return SparseModelMemoryProductReverseData(getOriginalModel().getNumberOfStates(), getMemory(), toResultStateMapping);
577}
578
586
587} // namespace storage
588} // namespace storm
Base class for all sparse models.
Definition Model.h:30
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
uint64_t getNumberOfSetBits() const
Returns the number of bits that are set to true in this bit vector.
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.
storm::storage::Distribution< ValueType, uint_fast64_t > const & getChoiceAsDistribution() const
Retrieves this choice in the form of a probability distribution.
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
A class that holds a possibly non-square matrix in the compressed row storage format.
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:9
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:28
SFTBDDChecker::ValueType ValueType
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:42
ValueType zero()
Definition constants.cpp:24