Storm 1.14.0.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
SparseMdpPrctlHelper.cpp
Go to the documentation of this file.
2
11#include "storm/io/export.h"
29#include "storm/utility/graph.h"
32
33namespace storm {
34namespace modelchecker {
35namespace helper {
36
37template<typename ValueType, typename SolutionType>
40 storm::storage::BitVector const& initialStates) {
42 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "We do not support computing reward bounded values with interval models.");
43 } else {
44 storm::utility::Stopwatch swAll(true), swBuild, swCheck;
45
46 // Get lower and upper bounds for the solution.
47 auto lowerBound = rewardUnfolding.getLowerObjectiveBound();
48 auto upperBound = rewardUnfolding.getUpperObjectiveBound();
49
50 // Initialize epoch models
51 auto initEpoch = rewardUnfolding.getStartEpoch();
52 auto epochOrder = rewardUnfolding.getEpochComputationOrder(initEpoch);
53
54 // initialize data that will be needed for each epoch
55 std::vector<ValueType> x, b;
56 std::unique_ptr<storm::solver::MinMaxLinearEquationSolver<ValueType>> minMaxSolver;
57
58 // The MinMax solver environment always carries a precision.
59 ValueType precision =
61 Environment preciseEnv = env;
63
64 // In case of cdf export we store the necessary data.
65 std::vector<std::vector<ValueType>> cdfData;
66
68 progress.setMaxCount(epochOrder.size());
69 progress.startNewMeasurement(0);
70 uint64_t numCheckedEpochs = 0;
71 for (auto const& epoch : epochOrder) {
72 swBuild.start();
73 auto& epochModel = rewardUnfolding.setCurrentEpoch(epoch);
74 swBuild.stop();
75 swCheck.start();
76 rewardUnfolding.setSolutionForCurrentEpoch(epochModel.analyzeSingleObjective(preciseEnv, dir, x, b, minMaxSolver, lowerBound, upperBound));
77 swCheck.stop();
78 if (env.modelchecker().isExportCdfSet() && !rewardUnfolding.getEpochManager().hasBottomDimension(epoch)) {
79 std::vector<ValueType> cdfEntry;
80 for (uint64_t i = 0; i < rewardUnfolding.getEpochManager().getDimensionCount(); ++i) {
81 uint64_t offset = rewardUnfolding.getDimension(i).boundType == helper::rewardbounded::DimensionBoundType::LowerBound ? 1 : 0;
82 cdfEntry.push_back(storm::utility::convertNumber<ValueType>(rewardUnfolding.getEpochManager().getDimensionOfEpoch(epoch, i) + offset) *
83 rewardUnfolding.getDimension(i).scalingFactor);
84 }
85 cdfEntry.push_back(rewardUnfolding.getInitialStateResult(epoch));
86 cdfData.push_back(std::move(cdfEntry));
87 }
88 ++numCheckedEpochs;
89 progress.updateProgress(numCheckedEpochs);
91 break;
92 }
93 }
94
95 std::vector<ValueType> result;
96 result.reserve(initialStates.getNumberOfSetBits());
97 for (uint64_t initState : initialStates) {
98 result.push_back(rewardUnfolding.getInitialStateResult(initEpoch, initState));
99 }
100
101 swAll.stop();
102
103 if (env.modelchecker().isExportCdfSet()) {
104 std::vector<std::string> headers;
105 for (uint64_t i = 0; i < rewardUnfolding.getEpochManager().getDimensionCount(); ++i) {
106 headers.push_back(rewardUnfolding.getDimension(i).formula->toString());
107 }
108 headers.push_back("Result");
110 }
111
112 STORM_LOG_STATISTICS("---------------------------------\n");
113 STORM_LOG_STATISTICS("Statistics:\n");
114 STORM_LOG_STATISTICS("---------------------------------\n");
115 STORM_LOG_STATISTICS(" #checked epochs: " << epochOrder.size() << ".\n");
116 STORM_LOG_STATISTICS(" overall Time: " << swAll << ".\n");
117 STORM_LOG_STATISTICS("Epoch Model building Time: " << swBuild << ".\n");
118 STORM_LOG_STATISTICS("Epoch Model checking Time: " << swCheck << ".\n");
119 STORM_LOG_STATISTICS("---------------------------------\n");
120
121 return result;
122 }
123}
124
125template<typename ValueType, typename SolutionType>
127 Environment const& env, OptimizationDirection dir, UncertaintyResolutionMode uncertaintyResolutionMode,
128 storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::BitVector const& nextStates) {
129 // Create the vector with which to multiply and initialize it correctly.
130 std::vector<SolutionType> result(transitionMatrix.getRowGroupCount());
132
133 auto multiplier = storm::solver::MultiplierFactory<ValueType, SolutionType>().create(env, transitionMatrix);
134 multiplier->multiplyAndReduce(env, dir, result, nullptr, result, uncertaintyResolutionMode);
135
136 return result;
137}
138
139template<typename ValueType, typename SolutionType = ValueType>
140std::vector<uint_fast64_t> computeValidSchedulerHint(Environment const& env, SemanticSolutionType const& type,
141 storm::storage::SparseMatrix<ValueType> const& transitionMatrix,
142 storm::storage::SparseMatrix<ValueType> const& backwardTransitions,
143 storm::storage::BitVector const& maybeStates, storm::storage::BitVector const& filterStates,
144 storm::storage::BitVector const& targetStates,
145 boost::optional<storm::storage::BitVector> const& selectedChoices) {
146 storm::storage::Scheduler<SolutionType> validScheduler(maybeStates.size());
147
149 storm::utility::graph::computeSchedulerProbGreater0E(transitionMatrix, backwardTransitions, filterStates, targetStates, validScheduler,
150 selectedChoices);
151 } else if (type == SemanticSolutionType::ExpectedRewards) {
152 storm::utility::graph::computeSchedulerProb1E(maybeStates | targetStates, transitionMatrix, backwardTransitions, filterStates, targetStates,
153 validScheduler, selectedChoices);
154 } else {
155 STORM_LOG_ASSERT(false, "Unexpected equation system type.");
156 }
157
158 // Extract the relevant parts of the scheduler for the solver.
159 std::vector<uint64_t> schedulerHint;
160 schedulerHint.reserve(maybeStates.getNumberOfSetBits());
161 if (selectedChoices) {
162 // There might be unselected choices so the local choice indices from the scheduler need to be adapted
163 for (uint64_t maybeState : maybeStates) {
164 auto choice = validScheduler.getChoice(maybeState).getDeterministicChoice();
165 auto const groupStart = transitionMatrix.getRowGroupIndices()[maybeState];
166 auto const origGlobalChoiceIndex = groupStart + choice;
167 STORM_LOG_ASSERT(selectedChoices->get(origGlobalChoiceIndex), "The computed scheduler selects an illegal choice.");
168 // Count the number of unselected choices in [groupStart, origGlobalChoiceIndex) and subtract that from choice
169 for (auto pos = selectedChoices->getNextUnsetIndex(groupStart); pos < origGlobalChoiceIndex; pos = selectedChoices->getNextUnsetIndex(pos + 1)) {
170 --choice;
171 }
172 schedulerHint.push_back(choice);
173 }
174 } else {
175 for (uint64_t maybeState : maybeStates) {
176 schedulerHint.push_back(validScheduler.getChoice(maybeState).getDeterministicChoice());
177 }
178 }
179 return schedulerHint;
180}
181
182template<typename ValueType>
185 // Intentionally left empty.
186 }
187
188 bool hasSchedulerHint() const {
189 return static_cast<bool>(schedulerHint);
190 }
191
192 bool hasValueHint() const {
193 return static_cast<bool>(valueHint);
194 }
195
196 bool hasLowerResultBound() const {
197 return static_cast<bool>(lowerResultBound);
198 }
199
200 ValueType const& getLowerResultBound() const {
201 return lowerResultBound.get();
202 }
203
204 bool hasUpperResultBound() const {
205 return static_cast<bool>(upperResultBound);
206 }
207
208 bool hasUpperResultBounds() const {
209 return static_cast<bool>(upperResultBounds);
210 }
211
212 ValueType const& getUpperResultBound() const {
213 return upperResultBound.get();
214 }
215
216 std::vector<ValueType>& getUpperResultBounds() {
217 return upperResultBounds.get();
218 }
219
220 std::vector<ValueType> const& getUpperResultBounds() const {
221 return upperResultBounds.get();
222 }
223
224 std::vector<uint64_t>& getSchedulerHint() {
225 return schedulerHint.get();
226 }
227
228 std::vector<ValueType>& getValueHint() {
229 return valueHint.get();
230 }
231
234 }
235
237 return computeUpperBounds;
238 }
239
240 bool hasUniqueSolution() const {
241 return uniqueSolution;
242 }
243
244 bool hasNoEndComponents() const {
245 return noEndComponents;
246 }
247
248 boost::optional<std::vector<uint64_t>> schedulerHint;
249 boost::optional<std::vector<ValueType>> valueHint;
250 boost::optional<ValueType> lowerResultBound;
251 boost::optional<ValueType> upperResultBound;
252 boost::optional<std::vector<ValueType>> upperResultBounds;
257};
258
259template<typename ValueType, typename SolutionType>
261 storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& maybeStates,
262 boost::optional<storm::storage::BitVector> const& selectedChoices, ModelCheckerHint const& hint,
263 bool skipECWithinMaybeStatesCheck) {
264 // Deal with scheduler hint.
265 if (hint.isExplicitModelCheckerHint() && hint.template asExplicitModelCheckerHint<ValueType>().hasSchedulerHint()) {
266 if (hintStorage.hasSchedulerHint()) {
267 STORM_LOG_WARN("A scheduler hint was provided, but the solver requires a specific one. The provided scheduler hint will be ignored.");
268 } else {
269 auto const& schedulerHint = hint.template asExplicitModelCheckerHint<ValueType>().getSchedulerHint();
270 std::vector<uint64_t> hintChoices;
271
272 // The scheduler hint is only applicable if it induces no BSCC consisting of maybe states.
273 bool hintApplicable;
274 if (!skipECWithinMaybeStatesCheck) {
275 hintChoices.reserve(maybeStates.size());
276 for (uint_fast64_t state = 0; state < maybeStates.size(); ++state) {
277 hintChoices.push_back(schedulerHint.getChoice(state).getDeterministicChoice());
278 }
279 hintApplicable =
280 storm::utility::graph::performProb1(transitionMatrix.transposeSelectedRowsFromRowGroups(hintChoices), maybeStates, ~maybeStates).full();
281 } else {
282 hintApplicable = true;
283 }
284
285 if (hintApplicable) {
286 // Compute the hint w.r.t. the given subsystem.
287 hintChoices.clear();
288 hintChoices.reserve(maybeStates.getNumberOfSetBits());
289 for (uint64_t state : maybeStates) {
290 uint_fast64_t hintChoice = schedulerHint.getChoice(state).getDeterministicChoice();
291 if (selectedChoices) {
292 uint_fast64_t firstChoice = transitionMatrix.getRowGroupIndices()[state];
293 uint_fast64_t lastChoice = firstChoice + hintChoice;
294 hintChoice = 0;
295 for (uint_fast64_t choice = selectedChoices->getNextSetIndex(firstChoice); choice < lastChoice;
296 choice = selectedChoices->getNextSetIndex(choice + 1)) {
297 ++hintChoice;
298 }
299 }
300 hintChoices.push_back(hintChoice);
301 }
302 hintStorage.schedulerHint = std::move(hintChoices);
303 }
304 }
305 }
306
307 // Deal with solution value hint. Only applicable if there are no End Components consisting of maybe states.
308 if (hint.isExplicitModelCheckerHint() && hint.template asExplicitModelCheckerHint<ValueType>().hasResultHint() &&
309 (skipECWithinMaybeStatesCheck || hintStorage.hasSchedulerHint() ||
310 storm::utility::graph::performProb1A(transitionMatrix, transitionMatrix.getRowGroupIndices(), backwardTransitions, maybeStates, ~maybeStates)
311 .full())) {
313 storm::utility::vector::filterVector(hint.template asExplicitModelCheckerHint<SolutionType>().getResultHint(), maybeStates),
315 }
316}
317
318template<typename ValueType, typename SolutionType>
321 storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& maybeStates,
322 storm::storage::BitVector const& phiStates, storm::storage::BitVector const& targetStates, bool produceScheduler,
323 boost::optional<storm::storage::BitVector> const& selectedChoices = boost::none, bool hasUniqueSolution = false) {
325
326 // There are no end components if we minimize until probabilities or
327 // maximize reachability rewards or if the hint tells us so.
328 result.noEndComponents = (dir == storm::solver::OptimizationDirection::Minimize && type == SemanticSolutionType::UntilProbabilities) ||
329 (dir == storm::solver::OptimizationDirection::Maximize && type == SemanticSolutionType::ExpectedRewards) ||
330 (hint.isExplicitModelCheckerHint() && hint.asExplicitModelCheckerHint<ValueType>().getNoEndComponentsInMaybeStates());
331
332 // If there are no end components, the solution is unique. (Note that the other direction does not hold,
333 // e.g., end components in which infinite reward is collected.
334 result.uniqueSolution = result.hasNoEndComponents() || hasUniqueSolution;
335
336 // Check for requirements of the solver.
337 bool hasSchedulerHint = hint.isExplicitModelCheckerHint() && hint.template asExplicitModelCheckerHint<ValueType>().hasSchedulerHint();
340 minMaxLinearEquationSolverFactory.getRequirements(env, result.uniqueSolution, result.noEndComponents, dir, hasSchedulerHint, produceScheduler);
341 if (requirements.hasEnabledRequirement()) {
342 // If the solver still requires no end-components, we have to eliminate them later.
343 if (requirements.uniqueSolution()) {
345 "The solver requires to eliminate the end components although the solution is already assumed to be unique.");
346 STORM_LOG_DEBUG("Scheduling EC elimination, because the solver requires a unique solution.");
347 result.eliminateEndComponents = true;
348 // If end components have been eliminated we can assume a unique solution.
349 result.uniqueSolution = true;
350 requirements.clearUniqueSolution();
351 // If we compute until probabilities, we can even assume the absence of end components.
352 // Note that in the case of minimizing expected rewards there might still be end components in which reward is collected.
354 }
355
356 // If the solver requires an initial scheduler, compute one now. Note that any scheduler is valid if there are no end components.
357 if (requirements.validInitialScheduler() && !result.noEndComponents) {
358 STORM_LOG_DEBUG("Computing valid scheduler, because the solver requires it.");
359 result.schedulerHint = computeValidSchedulerHint<ValueType, SolutionType>(env, type, transitionMatrix, backwardTransitions, maybeStates, phiStates,
360 targetStates, selectedChoices);
361 requirements.clearValidInitialScheduler();
362 }
363
364 // Finally, we have information on the bounds depending on the problem type.
366 requirements.clearBounds();
367 } else if (type == SemanticSolutionType::ExpectedRewards) {
368 requirements.clearLowerBounds();
369 }
370 if (requirements.upperBounds()) {
371 result.computeUpperBounds = true;
372 requirements.clearUpperBounds();
373 }
374 STORM_LOG_THROW(!requirements.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException,
375 "Solver requirements " + requirements.getEnabledRequirementsAsString() + " not checked.");
376 } else {
377 STORM_LOG_DEBUG("Solver has no requirements.");
378 }
379
380 // Only if there is no end component decomposition that we will need to do later, we use value and scheduler
381 // hints from the provided hint.
382 if (!result.eliminateEndComponents) {
383 extractValueAndSchedulerHint(result, transitionMatrix, backwardTransitions, maybeStates, selectedChoices, hint, result.uniqueSolution);
384 } else {
385 if (hint.isEmpty()) {
386 STORM_LOG_TRACE("Warn A non-empty hint was provided, but its information will be disregarded.");
387 }
388 }
389
390 // Only set bounds if we did not obtain them from the hint.
391 if (!result.hasLowerResultBound()) {
393 }
396 }
397
398 // If we received an upper bound, we can drop the requirement to compute one.
399 if (result.hasUpperResultBound()) {
400 result.computeUpperBounds = false;
401 }
402
403 return result;
404}
405
406template<typename ValueType>
408 MaybeStateResult(std::vector<ValueType>&& values) : values(std::move(values)) {
409 // Intentionally left empty.
410 }
411
412 bool hasScheduler() const {
413 return static_cast<bool>(scheduler);
414 }
415
416 std::vector<uint64_t> const& getScheduler() const {
417 return scheduler.get();
418 }
419
420 std::vector<ValueType> const& getValues() const {
421 return values;
422 }
423
424 std::vector<ValueType> values;
425 boost::optional<std::vector<uint64_t>> scheduler;
426
428};
429
430template<typename ValueType, typename SolutionType>
432 storm::storage::SparseMatrix<ValueType>&& submatrix, std::vector<ValueType> const& b,
433 bool produceScheduler, SparseMdpHintType<SolutionType>& hint) {
434 // Initialize the solution vector.
435 std::vector<SolutionType> x =
436 hint.hasValueHint() ? std::move(hint.getValueHint())
437 : std::vector<SolutionType>(submatrix.getRowGroupCount(),
439
440 // Capture the uncertainty resolution mode before the goal is consumed by the solver configuration.
441 auto const uncertaintyResolutionMode = goal.getUncertaintyResolutionMode();
442 // Set up the solver.
444 std::unique_ptr<storm::solver::MinMaxLinearEquationSolver<ValueType, SolutionType>> solver =
445 storm::solver::configureMinMaxLinearEquationSolver(env, std::move(goal), minMaxLinearEquationSolverFactory, std::move(submatrix));
446 solver->setRequirementsChecked();
447 solver->setUncertaintyResolutionMode(uncertaintyResolutionMode);
448 solver->setHasUniqueSolution(hint.hasUniqueSolution());
449 solver->setHasNoEndComponents(hint.hasNoEndComponents());
450 if (hint.hasLowerResultBound()) {
451 solver->setLowerBound(hint.getLowerResultBound());
452 }
453 if (hint.hasUpperResultBound()) {
454 solver->setUpperBound(hint.getUpperResultBound());
455 }
456 if (hint.hasUpperResultBounds()) {
457 solver->setUpperBounds(std::move(hint.getUpperResultBounds()));
458 }
459 if (hint.hasSchedulerHint()) {
460 solver->setInitialScheduler(std::move(hint.getSchedulerHint()));
461 }
462 solver->setTrackScheduler(produceScheduler);
463
464 // Solve the corresponding system of equations.
465 solver->solveEquations(env, x, b);
466
467#ifndef NDEBUG
468 // As a sanity check, make sure our local upper bounds were in fact correct.
470 uint64_t relevantState = solver->hasRelevantValues() ? solver->getRelevantValues().getNextSetIndex(0ull) : 0ull;
471 std::function<void()> getNextRelevantStateIndex;
472 if (solver->hasRelevantValues()) {
473 storm::storage::BitVector const& relevantValues = solver->getRelevantValues();
474 getNextRelevantStateIndex = [&relevantState, &relevantValues]() { relevantState = relevantValues.getNextSetIndex(++relevantState); };
475 } else {
476 getNextRelevantStateIndex = [&relevantState]() { ++relevantState; };
477 }
478 for (; relevantState < solver->getUpperBounds().size(); getNextRelevantStateIndex()) {
479 STORM_LOG_ASSERT(x.at(relevantState) <=
480 solver->getUpperBounds().at(relevantState) + storm::utility::convertNumber<ValueType>(env.solver().minMax().getPrecision()),
481 "Expecting result value for state " << relevantState << " to be <= " << solver->getUpperBounds().at(relevantState) << ", but got "
482 << x.at(relevantState) << ".");
483 }
484 }
485#endif
486
487 // Create result.
488 MaybeStateResult<SolutionType> result(std::move(x));
489 if (solver->hasSolutionLowerBounds()) {
490 result.solutionBounds.lower = solver->getSolutionLowerBounds();
491 }
492 if (solver->hasSolutionUpperBounds()) {
493 result.solutionBounds.upper = solver->getSolutionUpperBounds();
494 }
495
496 // If requested, return the requested scheduler.
497 if (produceScheduler) {
498 result.scheduler = std::move(solver->getSchedulerChoices());
499 }
500 return result;
501}
502
508
509template<typename ValueType>
512 result.maybeStates = hint.template asExplicitModelCheckerHint<ValueType>().getMaybeStates();
513
514 // Treat the states with probability zero/one.
515 std::vector<storm::utility::ExtendedValueType<ValueType>> const& resultsForNonMaybeStates =
516 hint.template asExplicitModelCheckerHint<ValueType>().getResultHint();
519 storm::storage::BitVector nonMaybeStates = ~result.maybeStates;
520 for (uint64_t state : nonMaybeStates) {
521 if (storm::utility::isOne(resultsForNonMaybeStates[state])) {
522 result.statesWithProbability1.set(state, true);
523 } else {
524 STORM_LOG_THROW(storm::utility::isZero(resultsForNonMaybeStates[state]), storm::exceptions::IllegalArgumentException,
525 "Expected that the result hint specifies probabilities in {0,1} for non-maybe states.");
526 result.statesWithProbability0.set(state, true);
527 }
528 }
529
530 return result;
531}
532
533template<typename ValueType, typename SolutionType>
535 storm::storage::SparseMatrix<ValueType> const& transitionMatrix,
536 storm::storage::SparseMatrix<ValueType> const& backwardTransitions,
537 storm::storage::BitVector const& phiStates,
538 storm::storage::BitVector const& psiStates) {
540
541 // Get all states that have probability 0 and 1 of satisfying the until-formula.
542 std::pair<storm::storage::BitVector, storm::storage::BitVector> statesWithProbability01;
543 if (goal.minimize()) {
544 statesWithProbability01 =
545 storm::utility::graph::performProb01Min(transitionMatrix, transitionMatrix.getRowGroupIndices(), backwardTransitions, phiStates, psiStates);
546 } else {
547 statesWithProbability01 =
548 storm::utility::graph::performProb01Max(transitionMatrix, transitionMatrix.getRowGroupIndices(), backwardTransitions, phiStates, psiStates);
549 }
550 result.statesWithProbability0 = std::move(statesWithProbability01.first);
551 result.statesWithProbability1 = std::move(statesWithProbability01.second);
553
554 return result;
555}
556
557template<typename ValueType, typename SolutionType>
559 storm::storage::SparseMatrix<ValueType> const& transitionMatrix,
560 storm::storage::SparseMatrix<ValueType> const& backwardTransitions,
561 storm::storage::BitVector const& phiStates,
562 storm::storage::BitVector const& psiStates, ModelCheckerHint const& hint) {
563 if (hint.isExplicitModelCheckerHint() && hint.template asExplicitModelCheckerHint<ValueType>().getComputeOnlyMaybeStates()) {
565 } else {
566 return computeQualitativeStateSetsUntilProbabilities(goal, transitionMatrix, backwardTransitions, phiStates, psiStates);
567 }
568}
569
570template<typename SolutionType, bool subChoicesCoverOnlyMaybeStates = true>
571void extractSchedulerChoices(storm::storage::Scheduler<SolutionType>& scheduler, std::vector<uint64_t> const& subChoices,
572 storm::storage::BitVector const& maybeStates) {
573 if constexpr (subChoicesCoverOnlyMaybeStates) {
574 auto subChoiceIt = subChoices.begin();
575 for (uint64_t maybeState : maybeStates) {
576 scheduler.setChoice(*subChoiceIt, maybeState);
577 ++subChoiceIt;
578 }
579 STORM_LOG_ASSERT(subChoiceIt == subChoices.end(), "Subchoice iterator not at end.");
580 } else {
581 // See computeFixedPointSystemUntilProbabilities, where we create a different equation system.
582 // Consequentially, we run a slightly different code here for interval-based models.
583 STORM_LOG_ASSERT(maybeStates.size() == subChoices.size(), "Sizes do not coincide.");
584 for (uint64_t maybeState : maybeStates) {
585 scheduler.setChoice(subChoices[maybeState], maybeState);
586 }
587 }
588}
589
590template<typename ValueType, typename SolutionType>
592 storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions,
593 storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates) {
594 // Finally, if we need to produce a scheduler, we also need to figure out the parts of the scheduler for
595 // the states with probability 1 or 0 (depending on whether we maximize or minimize).
596 // We also need to define some arbitrary choice for the remaining states to obtain a fully defined scheduler.
597 if (minimize) {
598 storm::utility::graph::computeSchedulerProb0E(qualitativeStateSets.statesWithProbability0, transitionMatrix, scheduler);
599 for (uint64_t prob1State : qualitativeStateSets.statesWithProbability1) {
600 scheduler.setChoice(0, prob1State);
601 }
602 } else {
603 storm::utility::graph::computeSchedulerProb1E(qualitativeStateSets.statesWithProbability1, transitionMatrix, backwardTransitions, phiStates, psiStates,
604 scheduler);
605 for (uint64_t prob0State : qualitativeStateSets.statesWithProbability0) {
606 scheduler.setChoice(0, prob0State);
607 }
608 }
609}
610
611template<typename ValueType, typename SolutionType>
613 storm::storage::SparseMatrix<ValueType> const& transitionMatrix,
614 QualitativeStateSetsUntilProbabilities const& qualitativeStateSets,
615 storm::storage::SparseMatrix<ValueType>& submatrix, std::vector<ValueType>& b) {
616 if constexpr (storm::IsIntervalType<ValueType>) {
617 // For non-interval based models, we can eliminate the rows and columns from the original transition probability matrix for states
618 // whose probabilities are already known... However, there is information in the transition to those states.
619 // Thus, we cannot eliminate them all.
620 // We can however drop all the outgoing transitions from these states.
621 // TODO: we can drop more than those entries and actually remove many states (all but the ones reachable in one step from the maybe states),
622 // TODO ctned: however, there is quite some bookkeeping involved in projecting the right vectors.
623 // TODO ctned: Instead is likely easier to just do a pass and make a unique sink and a unique target state.
624 // TODO ctned: If this is ever changed, extractSchedulerChoices must also be updated.
625 submatrix = transitionMatrix.filterEntries(transitionMatrix.getRowFilter(qualitativeStateSets.maybeStates));
626
627 // Prepare the right-hand side of the equation system. For entry i this corresponds to
628 // the accumulated probability of going from state i to some state that has probability 1.
629 storm::utility::vector::setAllValues(b, transitionMatrix.getRowFilter(qualitativeStateSets.statesWithProbability1));
630 } else {
631 // First, we can eliminate the rows and columns from the original transition probability matrix for states
632 // whose probabilities are already known.
633 submatrix = transitionMatrix.getSubmatrix(true, qualitativeStateSets.maybeStates, qualitativeStateSets.maybeStates, false);
634
635 // Prepare the right-hand side of the equation system. For entry i this corresponds to
636 // the accumulated probability of going from state i to some state that has probability 1.
637 b = transitionMatrix.getConstrainedRowGroupSumVector(qualitativeStateSets.maybeStates, qualitativeStateSets.statesWithProbability1);
638 }
639 // If the solve goal has relevant values, we need to adjust them.
640 goal.restrictRelevantValues(qualitativeStateSets.maybeStates);
641}
642
643template<typename ValueType, typename SolutionType>
644boost::optional<SparseMdpEndComponentInformation<ValueType>> computeFixedPointSystemUntilProbabilitiesEliminateEndComponents(
646 storm::storage::SparseMatrix<ValueType> const& backwardTransitions, QualitativeStateSetsUntilProbabilities const& qualitativeStateSets,
647 storm::storage::SparseMatrix<ValueType>& submatrix, std::vector<ValueType>& b, bool produceScheduler) {
648 // Get the set of states that (under some scheduler) can stay in the set of maybestates forever
650 transitionMatrix, transitionMatrix.getRowGroupIndices(), backwardTransitions, qualitativeStateSets.maybeStates, ~qualitativeStateSets.maybeStates);
651
652 bool doDecomposition = !candidateStates.empty();
653
655 if (doDecomposition) {
656 // Compute the states that are in MECs.
657 endComponentDecomposition = storm::storage::MaximalEndComponentDecomposition<ValueType>(transitionMatrix, backwardTransitions, candidateStates);
658 STORM_LOG_INFO(endComponentDecomposition.statistics(transitionMatrix.getRowGroupCount()));
659 }
660
661 // Only do more work if there are actually end-components.
662 if (doDecomposition && !endComponentDecomposition.empty()) {
663 STORM_LOG_DEBUG("Eliminating " << endComponentDecomposition.size() << " EC(s).");
665 endComponentDecomposition, transitionMatrix, qualitativeStateSets.maybeStates, &qualitativeStateSets.statesWithProbability1, nullptr, nullptr,
666 submatrix, &b, nullptr, produceScheduler);
667
668 // If the solve goal has relevant values, we need to adjust them.
669 if (goal.hasRelevantValues()) {
670 storm::storage::BitVector newRelevantValues(submatrix.getRowGroupCount());
671 for (auto state : goal.relevantValues()) {
672 if (qualitativeStateSets.maybeStates.get(state)) {
673 newRelevantValues.set(result.getRowGroupAfterElimination(state));
674 }
675 }
676 if (!newRelevantValues.empty()) {
677 goal.setRelevantValues(std::move(newRelevantValues));
678 }
679 }
680
681 return result;
682 } else {
683 STORM_LOG_DEBUG("Not eliminating ECs as there are none.");
684 computeFixedPointSystemUntilProbabilities(goal, transitionMatrix, qualitativeStateSets, submatrix, b);
685
686 return boost::none;
687 }
688}
689
690template<typename ValueType, typename SolutionType>
693 storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates,
694 bool qualitative, bool produceScheduler, ModelCheckerHint const& hint) {
695 STORM_LOG_THROW(!qualitative || !produceScheduler, storm::exceptions::InvalidSettingsException,
696 "Cannot produce scheduler when performing qualitative model checking only.");
697
698 // Prepare resulting vector.
699 std::vector<SolutionType> result(transitionMatrix.getRowGroupCount(), storm::utility::zero<SolutionType>());
700
702
703 // We need to identify the maybe states (states which have a probability for satisfying the until formula
704 // that is strictly between 0 and 1) and the states that satisfy the formula with probablity 1 and 0, respectively.
705 QualitativeStateSetsUntilProbabilities qualitativeStateSets =
706 getQualitativeStateSetsUntilProbabilities(goal, transitionMatrix, backwardTransitions, phiStates, psiStates, hint);
707
708 STORM_LOG_INFO("Preprocessing: " << qualitativeStateSets.statesWithProbability1.getNumberOfSetBits() << " states with probability 1, "
709 << qualitativeStateSets.statesWithProbability0.getNumberOfSetBits() << " with probability 0 ("
710 << qualitativeStateSets.maybeStates.getNumberOfSetBits() << " states remaining).");
711
712 // Set values of resulting vector that are known exactly.
714
715 // Check if the values of the maybe states are relevant for the SolveGoal
716 bool maybeStatesNotRelevant = goal.hasRelevantValues() && goal.relevantValues().isDisjointFrom(qualitativeStateSets.maybeStates);
717
718 // Capture the goal direction before the goal is consumed by the solver configuration.
719 bool const minimize = goal.minimize();
720 // If requested, we will produce a scheduler.
721 std::unique_ptr<storm::storage::Scheduler<SolutionType>> scheduler;
722 if (produceScheduler) {
723 scheduler = std::make_unique<storm::storage::Scheduler<SolutionType>>(transitionMatrix.getRowGroupCount());
724 // If maybeStatesNotRelevant is true, we have to set the scheduler for maybe states as "dontCare"
725 if (maybeStatesNotRelevant) {
726 for (uint64_t state : qualitativeStateSets.maybeStates) {
727 scheduler->setDontCare(state);
728 }
729 }
730 }
731
732 // Check whether we need to compute exact probabilities for some states.
733 if (qualitative || maybeStatesNotRelevant) {
734 // Set the values for all maybe-states to 0.5 to indicate that their probability values are neither 0 nor 1.
736 } else {
737 if (!qualitativeStateSets.maybeStates.empty()) {
738 // In this case we have have to compute the remaining probabilities.
739
740 // Obtain proper hint information either from the provided hint or from requirements of the solver.
742 env, SemanticSolutionType::UntilProbabilities, hint, goal.direction(), transitionMatrix, backwardTransitions, qualitativeStateSets.maybeStates,
743 phiStates, qualitativeStateSets.statesWithProbability1, produceScheduler);
744
745 // Declare the components of the equation system we will solve.
747 std::vector<ValueType> b;
748
749 // If the hint information tells us that we have to eliminate MECs, we do so now.
750 boost::optional<SparseMdpEndComponentInformation<ValueType>> ecInformation;
751 if (hintInformation.getEliminateEndComponents()) {
752 ecInformation = computeFixedPointSystemUntilProbabilitiesEliminateEndComponents(goal, transitionMatrix, backwardTransitions,
753 qualitativeStateSets, submatrix, b, produceScheduler);
754 } else {
755 // Otherwise, we compute the standard equations.
756 computeFixedPointSystemUntilProbabilities(goal, transitionMatrix, qualitativeStateSets, submatrix, b);
757 }
758
759 // Now compute the results for the maybe states.
760 MaybeStateResult<SolutionType> resultForMaybeStates =
761 computeValuesForMaybeStates(env, std::move(goal), std::move(submatrix), b, produceScheduler, hintInformation);
762
763 // If we eliminated end components, we need to extract the result differently.
764 if (ecInformation && ecInformation.get().getEliminatedEndComponents()) {
765 if constexpr (storm::IsIntervalType<ValueType>) {
766 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "We do not support this end component with interval models.");
767 } else {
768 // The copy of result supplies the exact values outside the maybe states.
769 auto liftBound = [&result, &qualitativeStateSets, &ecInformation](std::vector<SolutionType> const& boundInEcQuotient) {
770 std::vector<SolutionType> bound(result);
771 ecInformation.get().setValues(bound, qualitativeStateSets.maybeStates, boundInEcQuotient);
772 return bound;
773 };
774 resultBounds = resultForMaybeStates.solutionBounds.transform(liftBound);
775 ecInformation.get().setValues(result, qualitativeStateSets.maybeStates, resultForMaybeStates.getValues());
776 if (produceScheduler) {
777 ecInformation.get().setScheduler(*scheduler, qualitativeStateSets.maybeStates, transitionMatrix, backwardTransitions,
778 resultForMaybeStates.getScheduler());
779 }
780 }
781 } else {
782 // Set values of resulting vector according to result.
783 if constexpr (!storm::IsIntervalType<ValueType>) {
784 // For non-interval models, we only operated on the maybe states, and we must recover the qualitative values for the other state.
785 // The copy of result supplies the exact values outside the maybe states.
786 auto embedBound = [&result, &qualitativeStateSets](std::vector<SolutionType> const& boundForMaybeStates) {
787 std::vector<SolutionType> bound(result);
788 storm::utility::vector::setVectorValues<SolutionType>(bound, qualitativeStateSets.maybeStates, boundForMaybeStates);
789 return bound;
790 };
791 resultBounds = resultForMaybeStates.solutionBounds.transform(embedBound);
792 storm::utility::vector::setVectorValues<SolutionType>(result, qualitativeStateSets.maybeStates, resultForMaybeStates.getValues());
793 } else {
794 // For interval models, the result for maybe states indeed also holds values for all qualitative states.
795 STORM_LOG_ASSERT(resultForMaybeStates.getValues().size() == transitionMatrix.getColumnCount(), "Dimensions do not match.");
796 result = resultForMaybeStates.getValues();
797 resultBounds = std::move(resultForMaybeStates.solutionBounds);
798 }
799 if (produceScheduler) {
801 qualitativeStateSets.maybeStates);
802 }
803 }
804 }
805 }
806
807 if (qualitativeStateSets.maybeStates.empty()) {
808 // The qualitative precomputation already decided every state, so all values are exact.
809 resultBounds.setExact(result);
810 }
811
812 // Extend scheduler with choices for the states in the qualitative state sets.
813 if (produceScheduler) {
814 extendScheduler(*scheduler, minimize, qualitativeStateSets, transitionMatrix, backwardTransitions, phiStates, psiStates);
815 }
816
817 // Sanity check for created scheduler.
818 STORM_LOG_ASSERT(!produceScheduler || scheduler, "Expected that a scheduler was obtained.");
819 STORM_LOG_ASSERT((!produceScheduler && !scheduler) || !scheduler->isPartialScheduler(), "Expected a fully defined scheduler.");
820 STORM_LOG_ASSERT((!produceScheduler && !scheduler) || scheduler->isDeterministicScheduler(), "Expected a deterministic scheduler.");
821 STORM_LOG_ASSERT((!produceScheduler && !scheduler) || scheduler->isMemorylessScheduler(), "Expected a memoryless scheduler.");
822
823 // Return result.
824 MDPSparseModelCheckingHelperReturnType<SolutionType> returnValue(std::move(result), std::move(scheduler));
825 returnValue.solutionBounds = std::move(resultBounds);
826 return returnValue;
827}
828
829template<typename ValueType, typename SolutionType>
832 storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& psiStates, bool qualitative, bool produceScheduler,
833 bool useMecBasedTechnique) {
834 if (useMecBasedTechnique) {
835 // TODO: does this really work for minimizing objectives?
836 storm::storage::MaximalEndComponentDecomposition<ValueType> mecDecomposition(transitionMatrix, backwardTransitions, psiStates);
837 storm::storage::BitVector statesInPsiMecs(transitionMatrix.getRowGroupCount());
838 for (auto const& mec : mecDecomposition) {
839 for (auto const& stateActionsPair : mec) {
840 statesInPsiMecs.set(stateActionsPair.first, true);
841 }
842 }
843
844 return computeUntilProbabilities(env, std::move(goal), transitionMatrix, backwardTransitions, psiStates, statesInPsiMecs, qualitative,
845 produceScheduler);
846 } else {
847 goal.oneMinus();
848 auto result =
849 computeUntilProbabilities(env, std::move(goal), transitionMatrix, backwardTransitions,
850 storm::storage::BitVector(transitionMatrix.getRowGroupCount(), true), ~psiStates, qualitative, produceScheduler);
851 for (auto& element : result.values) {
852 element = storm::utility::one<SolutionType>() - element;
853 }
854 result.solutionBounds.invertProbabilityBounds();
855 return result;
856 }
857}
858
859template<typename ValueType, typename SolutionType>
860template<typename RewardModelType>
863 RewardModelType const& rewardModel, uint_fast64_t stepCount) {
864 if constexpr (storm::IsIntervalType<ValueType>) {
865 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "We do not support instantenous rewards with interval models.");
866 } else {
867 // Only compute the result if the model has a state-based reward this->getModel().
868 STORM_LOG_THROW(rewardModel.hasStateRewards(), storm::exceptions::InvalidPropertyException,
869 "Computing instantaneous rewards for a reward model that does not define any state-rewards. The result is trivially 0.");
870 // Initialize result to state rewards of the this->getModel().
871 std::vector<SolutionType> result(rewardModel.getStateRewardVector());
872
873 auto multiplier = storm::solver::MultiplierFactory<ValueType>().create(env, transitionMatrix);
874 multiplier->repeatedMultiplyAndReduce(env, goal.direction(), result, nullptr, stepCount, goal.getUncertaintyResolutionMode());
875
876 return result;
877 }
878}
879
880template<typename ValueType, typename SolutionType>
881template<typename RewardModelType>
884 RewardModelType const& rewardModel, uint_fast64_t stepBound) {
885 // Only compute the result if the model has at least one reward this->getModel().
886 STORM_LOG_THROW(!rewardModel.empty(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula.");
887 if constexpr (storm::IsIntervalType<ValueType>) {
888 STORM_LOG_ASSERT(storm::solver::isSet(goal.getUncertaintyResolutionMode()), "Interval model given, but no uncertainty resolution mode is specified.");
889 STORM_LOG_THROW(!rewardModel.hasTransitionRewards(), storm::exceptions::NotSupportedException,
890 "Cumulative rewards on interval models do not support transition rewards.");
891 }
892
893 // Compute the reward vector to add in each step based on the available reward models.
894 // For interval models, this vector may contain intervals. The multiplier picks the bound that is consistent with the uncertainty resolution mode.
895 std::vector<ValueType> totalRewardVector = rewardModel.getTotalRewardVector(transitionMatrix);
896
897 // Initialize result to the zero vector.
898 std::vector<SolutionType> result(transitionMatrix.getRowGroupCount(), storm::utility::zero<SolutionType>());
899
900 auto multiplier = storm::solver::MultiplierFactory<ValueType, SolutionType>().create(env, transitionMatrix);
901 multiplier->repeatedMultiplyAndReduce(env, goal.direction(), result, &totalRewardVector, stepBound, goal.getUncertaintyResolutionMode());
902
903 return result;
904}
905
906template<typename ValueType, typename SolutionType>
907template<typename RewardModelType>
910 storm::storage::SparseMatrix<ValueType> const& backwardTransitions, RewardModelType const& rewardModel, bool qualitative, bool produceScheduler,
911 ModelCheckerHint const& hint) {
912 STORM_LOG_THROW(!rewardModel.hasNegativeRewards(), storm::exceptions::NotImplementedException,
913 "The reward model contains negative rewards. This is not implemented by the total rewards computation.");
914 // Reduce to reachability rewards
915 if (goal.minimize()) {
916 // Identify the states from which no reward can be collected under some scheduler
917 storm::storage::BitVector choicesWithoutReward = rewardModel.getChoicesWithZeroReward(transitionMatrix);
918 storm::storage::BitVector statesWithZeroRewardChoice(transitionMatrix.getRowGroupCount(), false);
919 for (uint64_t state = 0; state < transitionMatrix.getRowGroupCount(); ++state) {
920 if (choicesWithoutReward.getNextSetIndex(transitionMatrix.getRowGroupIndices()[state]) < transitionMatrix.getRowGroupIndices()[state + 1]) {
921 statesWithZeroRewardChoice.set(state);
922 }
923 }
924 storm::storage::BitVector rew0EStates =
925 storm::utility::graph::performProbGreater0A(transitionMatrix, transitionMatrix.getRowGroupIndices(), backwardTransitions,
926 statesWithZeroRewardChoice, ~statesWithZeroRewardChoice, false, 0, choicesWithoutReward);
927 rew0EStates.complement();
928 auto result = computeReachabilityRewards(env, std::move(goal), transitionMatrix, backwardTransitions, rewardModel, rew0EStates, qualitative,
929 produceScheduler, hint);
930 if (result.scheduler) {
931 storm::utility::graph::computeSchedulerStayingInStates(rew0EStates, transitionMatrix, *result.scheduler, choicesWithoutReward);
932 }
933 return result;
934 } else {
935 // Identify the states from which only states with zero reward are reachable.
936 storm::storage::BitVector statesWithoutReward = rewardModel.getStatesWithZeroReward(transitionMatrix);
937 storm::storage::BitVector rew0AStates = storm::utility::graph::performProbGreater0E(backwardTransitions, statesWithoutReward, ~statesWithoutReward);
938 rew0AStates.complement();
939
940 // There might be end components that consists only of states/choices with zero rewards. The reachability reward semantics would assign such
941 // end components reward infinity. To avoid this, we potentially need to eliminate such end components
942 storm::storage::BitVector trueStates(transitionMatrix.getRowGroupCount(), true);
943 if (storm::utility::graph::performProb1A(transitionMatrix, transitionMatrix.getRowGroupIndices(), backwardTransitions, trueStates, rew0AStates)
944 .full()) {
945 return computeReachabilityRewards(env, std::move(goal), transitionMatrix, backwardTransitions, rewardModel, rew0AStates, qualitative,
946 produceScheduler, hint);
947 } else {
948 // The transformation of schedulers for the ec-eliminated system back to the original one is not implemented.
949 STORM_LOG_ERROR_COND(!produceScheduler, "Can not produce scheduler for this property (functionality not implemented");
950 storm::storage::BitVector choicesWithoutReward = rewardModel.getChoicesWithZeroReward(transitionMatrix);
952 transitionMatrix, storm::storage::BitVector(transitionMatrix.getRowGroupCount(), true), choicesWithoutReward, rew0AStates, true);
953 storm::storage::BitVector newRew0AStates(ecElimResult.matrix.getRowGroupCount(), false);
954 for (uint64_t oldRew0AState : rew0AStates) {
955 newRew0AStates.set(ecElimResult.oldToNewStateMapping[oldRew0AState]);
956 }
957
958 if (goal.hasRelevantValues()) {
959 storm::storage::BitVector newRelevantValues(ecElimResult.matrix.getRowGroupCount(), false);
960 for (auto oldRelevantState : goal.relevantValues()) {
961 newRelevantValues.set(ecElimResult.oldToNewStateMapping[oldRelevantState]);
962 }
963 goal.relevantValues() = std::move(newRelevantValues);
964 }
965
966 ExtendedReturnType result = computeReachabilityRewardsHelper(
967 env, std::move(goal), ecElimResult.matrix, ecElimResult.matrix.transpose(true),
968 [&](uint_fast64_t rowCount, storm::storage::SparseMatrix<ValueType> const& newTransitionMatrix, storm::storage::BitVector const& maybeStates) {
969 std::vector<ValueType> result;
970 std::vector<ValueType> oldChoiceRewards = rewardModel.getTotalRewardVector(transitionMatrix);
971 result.reserve(rowCount);
972 for (uint64_t newState : maybeStates) {
973 for (auto newChoice : newTransitionMatrix.getRowGroupIndices(newState)) {
974 uint64_t oldChoice = ecElimResult.newToOldRowMapping[newChoice];
975 result.push_back(oldChoiceRewards[oldChoice]);
976 }
977 }
978 STORM_LOG_ASSERT(result.size() == rowCount, "Unexpected size of reward vector.");
979 return result;
980 },
981 newRew0AStates, qualitative, false,
982 [&]() {
983 storm::storage::BitVector newStatesWithoutReward(ecElimResult.matrix.getRowGroupCount(), false);
984 for (uint64_t oldStateWithoutRew : statesWithoutReward) {
985 newStatesWithoutReward.set(ecElimResult.oldToNewStateMapping[oldStateWithoutRew]);
986 }
987 return newStatesWithoutReward;
988 },
989 [&]() {
990 storm::storage::BitVector newChoicesWithoutReward(ecElimResult.matrix.getRowGroupCount(), false);
991 for (uint64_t newChoice = 0; newChoice < ecElimResult.matrix.getRowCount(); ++newChoice) {
992 if (choicesWithoutReward.get(ecElimResult.newToOldRowMapping[newChoice])) {
993 newChoicesWithoutReward.set(newChoice);
994 }
995 }
996 return newChoicesWithoutReward;
997 });
998
999 // All states of an eliminated end component share their quotient state's value, and its bounds.
1000 auto liftFromEcQuotient = [&ecElimResult](std::vector<ExtendedSolutionType> const& valuesInEcQuotient) {
1001 std::vector<ExtendedSolutionType> lifted(ecElimResult.oldToNewStateMapping.size());
1002 storm::utility::vector::selectVectorValues(lifted, ecElimResult.oldToNewStateMapping, valuesInEcQuotient);
1003 return lifted;
1004 };
1005 result.solutionBounds = result.solutionBounds.transform(liftFromEcQuotient);
1006 result.values = liftFromEcQuotient(result.values);
1007 return result;
1008 }
1009 }
1010}
1011
1012template<typename ValueType, typename SolutionType>
1013template<typename RewardModelType>
1016 RewardModelType const& rewardModel, uint_fast64_t stepBound, ValueType discountFactor) {
1017 // Only compute the result if the model has at least one reward this->getModel().
1018 STORM_LOG_THROW(!rewardModel.empty(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula.");
1019
1020 // Compute the reward vector to add in each step based on the available reward models.
1021 std::vector<SolutionType> totalRewardVector = rewardModel.getTotalRewardVector(transitionMatrix);
1022
1023 // Initialize result to the zero vector.
1024 std::vector<SolutionType> result(transitionMatrix.getRowGroupCount(), storm::utility::zero<ValueType>());
1025
1026 auto multiplier = storm::solver::MultiplierFactory<ValueType>().create(env, transitionMatrix);
1027 multiplier->repeatedMultiplyAndReduceWithFactor(env, goal.direction(), result, &totalRewardVector, stepBound, discountFactor,
1028 goal.getUncertaintyResolutionMode());
1029
1030 return result;
1031}
1032
1033template<typename ValueType, typename SolutionType>
1034template<typename RewardModelType>
1037 storm::storage::SparseMatrix<ValueType> const& backwardTransitions, RewardModelType const& rewardModel, bool qualitative, bool produceScheduler,
1038 ValueType discountFactor, ModelCheckerHint const& hint) {
1039 // If the solver is set to force exact results, throw an error
1040 STORM_LOG_THROW(!env.solver().isForceExact(), storm::exceptions::NotSupportedException,
1041 "Exact solving of discounted total reward objectives is currently not supported.");
1042
1043 std::vector<ValueType> b;
1044
1045 std::vector<SolutionType> x = std::vector<SolutionType>(transitionMatrix.getRowGroupCount(), storm::utility::zero<SolutionType>());
1046 b = rewardModel.getTotalRewardVector(transitionMatrix);
1047 storm::modelchecker::helper::DiscountingHelper<ValueType> discountingHelper(transitionMatrix, discountFactor, produceScheduler);
1048
1049 discountingHelper.solveWithDiscountedValueIteration(env, goal.direction(), x, b);
1050
1051 std::unique_ptr<storm::storage::Scheduler<SolutionType>> scheduler;
1052 if (produceScheduler) {
1053 scheduler = std::make_unique<storm::storage::Scheduler<ValueType>>(discountingHelper.computeScheduler());
1054 }
1055 STORM_LOG_ASSERT(!produceScheduler || scheduler, "Expected that a scheduler was obtained.");
1056 STORM_LOG_ASSERT((!produceScheduler && !scheduler) || !scheduler->isPartialScheduler(), "Expected a fully defined scheduler.");
1057 STORM_LOG_ASSERT((!produceScheduler && !scheduler) || scheduler->isDeterministicScheduler(), "Expected a deterministic scheduler.");
1058 STORM_LOG_ASSERT((!produceScheduler && !scheduler) || scheduler->isMemorylessScheduler(), "Expected a memoryless scheduler.");
1059 return ExtendedReturnType(storm::utility::widen(std::move(x)), std::move(scheduler));
1060}
1061
1062template<typename ValueType, typename SolutionType>
1063template<typename RewardModelType>
1066 storm::storage::SparseMatrix<ValueType> const& backwardTransitions, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates,
1067 bool qualitative, bool produceScheduler, ModelCheckerHint const& hint) {
1068 // Only compute the result if the model has at least one reward this->getModel().
1069 STORM_LOG_THROW(!rewardModel.empty(), storm::exceptions::InvalidPropertyException, "Reward model for formula is empty. Skipping formula.");
1070 return computeReachabilityRewardsHelper(
1071 env, std::move(goal), transitionMatrix, backwardTransitions,
1072 [&rewardModel](uint_fast64_t rowCount, storm::storage::SparseMatrix<ValueType> const& transMatrix, storm::storage::BitVector const& maybeStates) {
1073 return rewardModel.getTotalRewardVector(rowCount, transMatrix, maybeStates);
1074 },
1075 targetStates, qualitative, produceScheduler, [&]() { return rewardModel.getStatesWithZeroReward(transitionMatrix); },
1076 [&]() { return rewardModel.getChoicesWithZeroReward(transitionMatrix); }, hint);
1077}
1078
1079template<typename ValueType, typename SolutionType>
1082 storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler,
1083 ModelCheckerHint const& hint) {
1084 return computeReachabilityRewardsHelper(
1085 env, std::move(goal), transitionMatrix, backwardTransitions,
1086 [](uint_fast64_t rowCount, storm::storage::SparseMatrix<ValueType> const&, storm::storage::BitVector const&) {
1087 return std::vector<ValueType>(rowCount, storm::utility::one<ValueType>());
1088 },
1089 targetStates, qualitative, produceScheduler, [&]() { return storm::storage::BitVector(transitionMatrix.getRowGroupCount(), false); },
1090 [&]() { return storm::storage::BitVector(transitionMatrix.getRowCount(), false); }, hint);
1091}
1092
1093template<typename ValueType, typename SolutionType>
1094template<typename IntervalRewardType>
1095std::vector<typename SparseMdpPrctlHelper<ValueType, SolutionType>::ExtendedSolutionType>
1098 storm::storage::SparseMatrix<ValueType> const& backwardTransitions,
1099 storm::models::sparse::StandardRewardModel<IntervalRewardType> const& intervalRewardModel, bool lowerBoundOfIntervals,
1100 storm::storage::BitVector const& targetStates, bool qualitative) {
1101 // Only compute the result if the reward model is not empty.
1102 STORM_LOG_THROW(!intervalRewardModel.empty(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula.");
1103 if constexpr (!std::is_same_v<IntervalBaseType<ValueType>, IntervalBaseType<IntervalRewardType>>) {
1104 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "We do not support a valuetype and reward type having different base types.");
1105 } else {
1106 return computeReachabilityRewardsHelper(
1107 env, std::move(goal), transitionMatrix, backwardTransitions,
1108 [&](uint_fast64_t rowCount, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::BitVector const& maybeStates) {
1109 std::vector<ValueType> result;
1110 result.reserve(rowCount);
1111 std::vector<IntervalRewardType> subIntervalVector = intervalRewardModel.getTotalRewardVector(rowCount, transitionMatrix, maybeStates);
1112 for (auto const& interval : subIntervalVector) {
1113 result.push_back(lowerBoundOfIntervals ? interval.lower() : interval.upper());
1114 }
1115 return result;
1116 },
1117 targetStates, qualitative, false,
1118 [&]() {
1119 return intervalRewardModel.getStatesWithFilter(transitionMatrix, [&](IntervalRewardType const& i) {
1120 return storm::utility::isZero(lowerBoundOfIntervals ? i.lower() : i.upper());
1121 });
1122 },
1123 [&]() {
1124 return intervalRewardModel.getChoicesWithFilter(transitionMatrix, [&](IntervalRewardType const& i) {
1125 return storm::utility::isZero(lowerBoundOfIntervals ? i.lower() : i.upper());
1126 });
1127 })
1128 .values;
1129 }
1130}
1131
1137
1138template<typename ValueType>
1140 storm::storage::BitVector const& targetStates) {
1142 result.maybeStates = hint.template asExplicitModelCheckerHint<ValueType>().getMaybeStates();
1143
1144 // Treat the states with reward zero/infinity.
1145 std::vector<storm::utility::ExtendedValueType<ValueType>> const& resultsForNonMaybeStates =
1146 hint.template asExplicitModelCheckerHint<ValueType>().getResultHint();
1149 storm::storage::BitVector nonMaybeStates = ~result.maybeStates;
1150 for (uint64_t state : nonMaybeStates) {
1151 if (storm::utility::isZero(resultsForNonMaybeStates[state])) {
1152 result.rewardZeroStates.set(state, true);
1153 } else {
1154 STORM_LOG_THROW(storm::utility::isInfinity(resultsForNonMaybeStates[state]), storm::exceptions::IllegalArgumentException,
1155 "Expected that the result hint specifies probabilities in {0,infinity} for non-maybe states.");
1156 result.infinityStates.set(state, true);
1157 }
1158 }
1159 return result;
1160}
1161
1162template<typename ValueType, typename SolutionType>
1165 storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& targetStates,
1166 std::function<storm::storage::BitVector()> const& zeroRewardStatesGetter, std::function<storm::storage::BitVector()> const& zeroRewardChoicesGetter) {
1168 storm::storage::BitVector trueStates(transitionMatrix.getRowGroupCount(), true);
1169 if (goal.minimize()) {
1170 result.infinityStates =
1171 storm::utility::graph::performProb1E(transitionMatrix, transitionMatrix.getRowGroupIndices(), backwardTransitions, trueStates, targetStates);
1172 } else {
1173 result.infinityStates =
1174 storm::utility::graph::performProb1A(transitionMatrix, transitionMatrix.getRowGroupIndices(), backwardTransitions, trueStates, targetStates);
1175 }
1176 result.infinityStates.complement();
1177
1178 if (env.modelchecker().isFilterRewZeroSet()) {
1179 if (goal.minimize()) {
1180 result.rewardZeroStates = storm::utility::graph::performProb1E(transitionMatrix, transitionMatrix.getRowGroupIndices(), backwardTransitions,
1181 trueStates, targetStates, zeroRewardChoicesGetter());
1182 } else {
1183 result.rewardZeroStates = storm::utility::graph::performProb1A(transitionMatrix, transitionMatrix.getRowGroupIndices(), backwardTransitions,
1184 zeroRewardStatesGetter(), targetStates);
1185 }
1186 } else {
1187 result.rewardZeroStates = targetStates;
1188 }
1189 result.maybeStates = ~(result.rewardZeroStates | result.infinityStates);
1190 return result;
1191}
1192
1193template<typename ValueType, typename SolutionType>
1196 storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& targetStates, ModelCheckerHint const& hint,
1197 std::function<storm::storage::BitVector()> const& zeroRewardStatesGetter, std::function<storm::storage::BitVector()> const& zeroRewardChoicesGetter) {
1198 if (hint.isExplicitModelCheckerHint() && hint.template asExplicitModelCheckerHint<ValueType>().getComputeOnlyMaybeStates()) {
1200 } else {
1201 return computeQualitativeStateSetsReachabilityRewards(env, goal, transitionMatrix, backwardTransitions, targetStates, zeroRewardStatesGetter,
1202 zeroRewardChoicesGetter);
1203 }
1204}
1205
1206template<typename ValueType, typename SolutionType>
1208 storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::SparseMatrix<ValueType> const& backwardTransitions,
1209 storm::storage::BitVector const& targetStates, std::function<storm::storage::BitVector()> const& zeroRewardChoicesGetter) {
1210 // Finally, if we need to produce a scheduler, we also need to figure out the parts of the scheduler for
1211 // the states with reward zero/infinity.
1212 if (minimize) {
1213 storm::utility::graph::computeSchedulerProb1E(qualitativeStateSets.rewardZeroStates, transitionMatrix, backwardTransitions,
1214 qualitativeStateSets.rewardZeroStates, targetStates, scheduler, zeroRewardChoicesGetter());
1215 for (uint64_t state : qualitativeStateSets.infinityStates) {
1216 scheduler.setChoice(0, state);
1217 }
1218 } else {
1219 storm::utility::graph::computeSchedulerRewInf(qualitativeStateSets.infinityStates, transitionMatrix, backwardTransitions, scheduler);
1220 for (uint64_t state : qualitativeStateSets.rewardZeroStates) {
1221 scheduler.setChoice(0, state);
1222 }
1223 }
1224}
1225
1226template<typename ValueType, typename SolutionType>
1228 std::vector<uint_fast64_t> const& subChoices, storm::storage::BitVector const& maybeStates,
1229 boost::optional<storm::storage::BitVector> const& selectedChoices) {
1230 auto subChoiceIt = subChoices.begin();
1231 if (selectedChoices) {
1232 for (uint64_t maybeState : maybeStates) {
1233 // find the rowindex that corresponds to the selected row of the submodel
1234 uint_fast64_t firstRowIndex = transitionMatrix.getRowGroupIndices()[maybeState];
1235 uint_fast64_t selectedRowIndex = selectedChoices->getNextSetIndex(firstRowIndex);
1236 for (uint_fast64_t choice = 0; choice < *subChoiceIt; ++choice) {
1237 selectedRowIndex = selectedChoices->getNextSetIndex(selectedRowIndex + 1);
1238 }
1239 scheduler.setChoice(selectedRowIndex - firstRowIndex, maybeState);
1240 ++subChoiceIt;
1241 }
1242 } else {
1243 for (uint64_t maybeState : maybeStates) {
1244 scheduler.setChoice(*subChoiceIt, maybeState);
1245 ++subChoiceIt;
1246 }
1247 }
1248 STORM_LOG_ASSERT(subChoiceIt == subChoices.end(), "Subchoice iterator not at end.");
1249}
1250
1251template<typename ValueType, typename SolutionType>
1254 QualitativeStateSetsReachabilityRewards const& qualitativeStateSets, boost::optional<storm::storage::BitVector> const& selectedChoices,
1255 std::function<std::vector<ValueType>(uint_fast64_t, storm::storage::SparseMatrix<ValueType> const&, storm::storage::BitVector const&)> const&
1256 totalStateRewardVectorGetter,
1257 storm::storage::SparseMatrix<ValueType>& submatrix, std::vector<ValueType>& b, std::vector<ValueType>* oneStepTargetProbabilities = nullptr) {
1258 if constexpr (storm::IsIntervalType<ValueType>) {
1259 // For interval models, we must not remove the columns of states whose reward values are already known (i.e., target states): the probability
1260 // mass that is moved to these states is constrained by the transition intervals, which is relevant for resolving the uncertainty at predecessors.
1261 // We thus keep all columns (so the system has one row group for every state) and drop all outgoing transitions of non-maybe states.
1262 // The values of non-maybe states are then 0 by construction (no transitions, no reward), which is the correct value for target states.
1263 // Infinity states are never reached via the choices we keep.
1264 submatrix = transitionMatrix.filterEntries(transitionMatrix.getRowFilter(qualitativeStateSets.maybeStates));
1265 // The rows of non-maybe states carry no reward. Note that b must be indexed by the rows of the original matrix, so we compute the rewards for all
1266 // states and set the entries of non-maybe states to zero.
1267 b = totalStateRewardVectorGetter(transitionMatrix.getRowCount(), transitionMatrix,
1268 storm::storage::BitVector(transitionMatrix.getRowGroupCount(), true));
1270 if (!qualitativeStateSets.infinityStates.empty()) {
1271 // Remove the choices of maybe states that lead to infinity states. The (empty) rows of non-maybe states are kept.
1272 storm::storage::BitVector const rowsToKeep = *selectedChoices | transitionMatrix.getRowFilter(~qualitativeStateSets.maybeStates);
1273 submatrix = submatrix.restrictRows(rowsToKeep);
1275 }
1276 if (oneStepTargetProbabilities) {
1277 if (qualitativeStateSets.infinityStates.empty()) {
1278 (*oneStepTargetProbabilities) =
1279 transitionMatrix.getConstrainedRowGroupSumVector(qualitativeStateSets.maybeStates, qualitativeStateSets.rewardZeroStates);
1280 } else {
1281 (*oneStepTargetProbabilities) = transitionMatrix.getConstrainedRowSumVector(*selectedChoices, qualitativeStateSets.rewardZeroStates);
1282 }
1283 }
1284 // Note that the solution vector has an entry for each state, so the relevant values of the solve goal are not restricted to the maybe states.
1285 return;
1286 }
1287 // Remove rows and columns from the original transition probability matrix for states whose reward values are already known.
1288 // If there are infinity states, we additionally have to remove choices of maybeState that lead to infinity.
1289 if (qualitativeStateSets.infinityStates.empty()) {
1290 submatrix = transitionMatrix.getSubmatrix(true, qualitativeStateSets.maybeStates, qualitativeStateSets.maybeStates, false);
1291 b = totalStateRewardVectorGetter(submatrix.getRowCount(), transitionMatrix, qualitativeStateSets.maybeStates);
1292 if (oneStepTargetProbabilities) {
1293 (*oneStepTargetProbabilities) =
1294 transitionMatrix.getConstrainedRowGroupSumVector(qualitativeStateSets.maybeStates, qualitativeStateSets.rewardZeroStates);
1295 }
1296 } else {
1297 submatrix = transitionMatrix.getSubmatrix(false, *selectedChoices, qualitativeStateSets.maybeStates, false);
1298 b = totalStateRewardVectorGetter(transitionMatrix.getRowCount(), transitionMatrix,
1299 storm::storage::BitVector(transitionMatrix.getRowGroupCount(), true));
1301 if (oneStepTargetProbabilities) {
1302 (*oneStepTargetProbabilities) = transitionMatrix.getConstrainedRowSumVector(*selectedChoices, qualitativeStateSets.rewardZeroStates);
1303 }
1304 }
1305
1306 // If the solve goal has relevant values, we need to adjust them.
1307 goal.restrictRelevantValues(qualitativeStateSets.maybeStates);
1308}
1309
1310template<typename ValueType, typename SolutionType>
1311boost::optional<SparseMdpEndComponentInformation<ValueType>> computeFixedPointSystemReachabilityRewardsEliminateEndComponents(
1313 storm::storage::SparseMatrix<ValueType> const& backwardTransitions, QualitativeStateSetsReachabilityRewards const& qualitativeStateSets,
1314 boost::optional<storm::storage::BitVector> const& selectedChoices,
1315 std::function<std::vector<ValueType>(uint_fast64_t, storm::storage::SparseMatrix<ValueType> const&, storm::storage::BitVector const&)> const&
1316 totalStateRewardVectorGetter,
1317 storm::storage::SparseMatrix<ValueType>& submatrix, std::vector<ValueType>& b, boost::optional<std::vector<ValueType>>& oneStepTargetProbabilities,
1318 bool produceScheduler) {
1319 // Start by computing the choices with reward 0, as we only want ECs within this fragment.
1320 storm::storage::BitVector zeroRewardChoices(transitionMatrix.getRowCount());
1321
1322 // Get the rewards of all choices.
1323 std::vector<ValueType> rewardVector =
1324 totalStateRewardVectorGetter(transitionMatrix.getRowCount(), transitionMatrix, storm::storage::BitVector(transitionMatrix.getRowGroupCount(), true));
1325
1326 uint64_t index = 0;
1327 for (auto const& e : rewardVector) {
1328 if (storm::utility::isZero(e)) {
1329 zeroRewardChoices.set(index);
1330 }
1331 ++index;
1332 }
1333
1334 // Compute the states that have some zero reward choice.
1335 storm::storage::BitVector candidateStates(qualitativeStateSets.maybeStates);
1336 for (uint64_t state : qualitativeStateSets.maybeStates) {
1337 bool keepState = false;
1338
1339 for (auto row = transitionMatrix.getRowGroupIndices()[state], rowEnd = transitionMatrix.getRowGroupIndices()[state + 1]; row < rowEnd; ++row) {
1340 if (zeroRewardChoices.get(row)) {
1341 keepState = true;
1342 break;
1343 }
1344 }
1345
1346 if (!keepState) {
1347 candidateStates.set(state, false);
1348 }
1349 }
1350
1351 // Only keep the candidate states that (under some scheduler) can stay in the set of candidates forever
1352 candidateStates =
1353 storm::utility::graph::performProb0E(transitionMatrix, transitionMatrix.getRowGroupIndices(), backwardTransitions, candidateStates, ~candidateStates);
1354
1355 bool doDecomposition = !candidateStates.empty();
1356
1358 if (doDecomposition) {
1359 // Then compute the states that are in MECs with zero reward.
1360 endComponentDecomposition =
1361 storm::storage::MaximalEndComponentDecomposition<ValueType>(transitionMatrix, backwardTransitions, candidateStates, zeroRewardChoices);
1362 STORM_LOG_INFO(endComponentDecomposition.statistics(transitionMatrix.getRowGroupCount()));
1363 }
1364
1365 // Only do more work if there are actually end-components.
1366 if (doDecomposition && !endComponentDecomposition.empty()) {
1367 STORM_LOG_DEBUG("Eliminating " << endComponentDecomposition.size() << " ECs.");
1369 endComponentDecomposition, transitionMatrix, qualitativeStateSets.maybeStates,
1370 oneStepTargetProbabilities ? &qualitativeStateSets.rewardZeroStates : nullptr, selectedChoices ? &selectedChoices.get() : nullptr, &rewardVector,
1371 submatrix, oneStepTargetProbabilities ? &oneStepTargetProbabilities.get() : nullptr, &b, produceScheduler);
1372
1373 // If the solve goal has relevant values, we need to adjust them.
1374 if (goal.hasRelevantValues()) {
1375 storm::storage::BitVector newRelevantValues(submatrix.getRowGroupCount());
1376 for (auto state : goal.relevantValues()) {
1377 if (qualitativeStateSets.maybeStates.get(state)) {
1378 newRelevantValues.set(result.getRowGroupAfterElimination(state));
1379 }
1380 }
1381 if (!newRelevantValues.empty()) {
1382 goal.setRelevantValues(std::move(newRelevantValues));
1383 }
1384 }
1385
1386 return result;
1387 } else {
1388 STORM_LOG_DEBUG("Not eliminating ECs as there are none.");
1389 computeFixedPointSystemReachabilityRewards(goal, transitionMatrix, qualitativeStateSets, selectedChoices, totalStateRewardVectorGetter, submatrix, b,
1390 oneStepTargetProbabilities ? &oneStepTargetProbabilities.get() : nullptr);
1391 return boost::none;
1392 }
1393}
1394
1395template<typename ValueType, typename SolutionType>
1397 storm::storage::SparseMatrix<ValueType> const& submatrix, std::vector<ValueType> const& choiceRewards,
1398 std::vector<ValueType> const& oneStepTargetProbabilities) {
1399 if constexpr (storm::IsIntervalType<ValueType>) {
1400 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "We do not support computing upper reward bounds with interval models.");
1401 } else {
1402 // For the min-case, we use DS-MPI, for the max-case variant 2 of the Baier et al. paper (CAV'17).
1403 if (direction == storm::OptimizationDirection::Minimize) {
1404 DsMpiMdpUpperRewardBoundsComputer<ValueType> dsmpi(submatrix, choiceRewards, oneStepTargetProbabilities);
1405 hintInformation.upperResultBounds = dsmpi.computeUpperBounds();
1406 } else {
1407 BaierUpperRewardBoundsComputer<ValueType> baier(submatrix, oneStepTargetProbabilities);
1408 hintInformation.upperResultBound = baier.computeTotalRewardBounds(choiceRewards).upper;
1409 }
1410 }
1411}
1412
1413template<typename ValueType, typename SolutionType>
1414typename SparseMdpPrctlHelper<ValueType, SolutionType>::ExtendedReturnType SparseMdpPrctlHelper<ValueType, SolutionType>::computeReachabilityRewardsHelper(
1416 storm::storage::SparseMatrix<ValueType> const& backwardTransitions,
1417 std::function<std::vector<ValueType>(uint_fast64_t, storm::storage::SparseMatrix<ValueType> const&, storm::storage::BitVector const&)> const&
1418 totalStateRewardVectorGetter,
1419 storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler,
1420 std::function<storm::storage::BitVector()> const& zeroRewardStatesGetter, std::function<storm::storage::BitVector()> const& zeroRewardChoicesGetter,
1421 ModelCheckerHint const& hint) {
1422 // Prepare resulting vector.
1423 std::vector<ExtendedSolutionType> result(transitionMatrix.getRowGroupCount(), storm::utility::zero<ExtendedSolutionType>());
1425
1426 // Determine which states have a reward that is infinity or less than infinity.
1427 QualitativeStateSetsReachabilityRewards qualitativeStateSets = getQualitativeStateSetsReachabilityRewards(
1428 env, goal, transitionMatrix, backwardTransitions, targetStates, hint, zeroRewardStatesGetter, zeroRewardChoicesGetter);
1429
1430 STORM_LOG_INFO("Preprocessing: " << qualitativeStateSets.infinityStates.getNumberOfSetBits() << " states with reward infinity, "
1431 << qualitativeStateSets.rewardZeroStates.getNumberOfSetBits() << " states with reward zero ("
1432 << qualitativeStateSets.maybeStates.getNumberOfSetBits() << " states remaining).");
1433
1435
1436 // If requested, we will produce a scheduler.
1437 std::unique_ptr<storm::storage::Scheduler<SolutionType>> scheduler;
1438 if (produceScheduler) {
1439 if constexpr (storm::IsIntervalType<ValueType>) {
1440 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "We do not support producing schedulers in this function with interval models.");
1441 } else {
1442 scheduler = std::make_unique<storm::storage::Scheduler<SolutionType>>(transitionMatrix.getRowGroupCount());
1443 }
1444 }
1445
1446 // Check if the values of the maybe states are relevant for the SolveGoal
1447 bool maybeStatesNotRelevant = goal.hasRelevantValues() && goal.relevantValues().isDisjointFrom(qualitativeStateSets.maybeStates);
1448
1449 // Capture the goal direction before the goal is consumed by the solver configuration.
1450 bool const minimize = goal.minimize();
1451 // Check whether we need to compute exact rewards for some states.
1452 if (qualitative || maybeStatesNotRelevant) {
1453 STORM_LOG_INFO("The rewards for the initial states were determined in a preprocessing step. No exact rewards were computed.");
1454 // Set the values for all maybe-states to 1 to indicate that their reward values
1455 // are neither 0 nor infinity.
1457 } else {
1458 if (!qualitativeStateSets.maybeStates.empty()) {
1459 // In this case we have to compute the reward values for the remaining states.
1460
1461 // Store the choices that lead to non-infinity values. If none, all choices im maybe states can be selected.
1462 boost::optional<storm::storage::BitVector> selectedChoices;
1463 if (!qualitativeStateSets.infinityStates.empty()) {
1464 selectedChoices = transitionMatrix.getRowFilter(qualitativeStateSets.maybeStates, ~qualitativeStateSets.infinityStates);
1465 }
1466
1467 // Obtain proper hint information either from the provided hint or from requirements of the solver.
1468 bool hasUniqueSolution = goal.direction() == storm::solver::OptimizationDirection::Maximize;
1469 if constexpr (storm::IsIntervalType<ValueType>) {
1470 // For interval models, it is worth checking if the solution is unique, since we have no support for upper-bounds computation.
1471 if (!hasUniqueSolution) {
1472 auto zeroRewardChoices = zeroRewardChoicesGetter();
1473 auto oneStepZeroRewardStates = qualitativeStateSets.maybeStates & transitionMatrix.getRowGroupFilter(zeroRewardChoices, false);
1474 // The solution is not unique iff there is a 0-reward EC iff there is a state from which we always stay inside oneStepZeroRewardStates
1475 // while taking only zeroRewardChoices.
1476 hasUniqueSolution =
1477 storm::utility::graph::performProbGreater0A(transitionMatrix, transitionMatrix.getRowGroupIndices(), backwardTransitions,
1478 oneStepZeroRewardStates, ~oneStepZeroRewardStates, false, 0, std::move(zeroRewardChoices))
1479 .full();
1480 }
1481 }
1482 SparseMdpHintType<SolutionType> hintInformation = computeHints<ValueType, SolutionType>(
1483 env, SemanticSolutionType::ExpectedRewards, hint, goal.direction(), transitionMatrix, backwardTransitions, qualitativeStateSets.maybeStates,
1484 ~qualitativeStateSets.rewardZeroStates, qualitativeStateSets.rewardZeroStates, produceScheduler, selectedChoices, hasUniqueSolution);
1485
1486 // Declare the components of the equation system we will solve.
1487 storm::storage::SparseMatrix<ValueType> submatrix;
1488 std::vector<ValueType> b;
1489
1490 // If we need to compute upper bounds on the reward values, we need the one step probabilities
1491 // to a target state.
1492 boost::optional<std::vector<ValueType>> oneStepTargetProbabilities;
1493 if (hintInformation.getComputeUpperBounds()) {
1494 oneStepTargetProbabilities = std::vector<ValueType>();
1495 }
1496
1497 // If the hint information tells us that we have to eliminate MECs, we do so now.
1498 boost::optional<SparseMdpEndComponentInformation<ValueType>> ecInformation;
1499 if (hintInformation.getEliminateEndComponents()) {
1500 if constexpr (storm::IsIntervalType<ValueType>) {
1501 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "We do not support eliminating end components with interval models.");
1502 } else {
1504 goal, transitionMatrix, backwardTransitions, qualitativeStateSets, selectedChoices, totalStateRewardVectorGetter, submatrix, b,
1505 oneStepTargetProbabilities, produceScheduler);
1506 }
1507 } else {
1508 // Otherwise, we compute the standard equations.
1509 computeFixedPointSystemReachabilityRewards(goal, transitionMatrix, qualitativeStateSets, selectedChoices, totalStateRewardVectorGetter,
1510 submatrix, b, oneStepTargetProbabilities ? &oneStepTargetProbabilities.get() : nullptr);
1511 }
1512
1513 // If we need to compute upper bounds, do so now.
1514 if (hintInformation.getComputeUpperBounds()) {
1515 STORM_LOG_ASSERT(oneStepTargetProbabilities, "Expecting one step target probability vector to be available.");
1516 computeUpperRewardBounds(hintInformation, goal.direction(), submatrix, b, oneStepTargetProbabilities.get());
1517 }
1518
1519 // Now compute the results for the maybe states.
1520 MaybeStateResult<SolutionType> resultForMaybeStates =
1521 computeValuesForMaybeStates(env, std::move(goal), std::move(submatrix), b, produceScheduler, hintInformation);
1522
1523 // If we eliminated end components, we need to extract the result differently.
1524 if (ecInformation && ecInformation.get().getEliminatedEndComponents()) {
1525 if constexpr (storm::IsIntervalType<ValueType>) {
1526 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "We do not support eliminating end components with interval models.");
1527 } else {
1528 std::vector<ExtendedSolutionType> const maybeStateValues = storm::utility::widen<SolutionType>(std::move(resultForMaybeStates.values));
1529 ecInformation.get().setValues(result, qualitativeStateSets.maybeStates, maybeStateValues);
1530 if (produceScheduler) {
1531 ecInformation.get().setScheduler(*scheduler, qualitativeStateSets.maybeStates, transitionMatrix, backwardTransitions,
1532 resultForMaybeStates.getScheduler());
1533 }
1534 }
1535 } else {
1536 // The copy of result supplies the exact values outside the maybe states.
1537 auto embedBound = [&result, &qualitativeStateSets](std::vector<SolutionType> const& boundForMaybeStates) {
1538 std::vector<ExtendedSolutionType> bound(result);
1539 storm::utility::vector::setVectorValues(bound, qualitativeStateSets.maybeStates, boundForMaybeStates);
1540 return bound;
1541 };
1542 resultBounds = resultForMaybeStates.solutionBounds.transform(embedBound);
1543 // Set values of resulting vector according to result.
1544 if constexpr (storm::IsIntervalType<ValueType>) {
1545 // For interval models, the solution has an entry for every state. We only take the values of the maybe states.
1546 STORM_LOG_ASSERT(resultForMaybeStates.getValues().size() == transitionMatrix.getRowGroupCount(), "Dimensions do not match.");
1548 result, qualitativeStateSets.maybeStates,
1549 storm::utility::vector::filterVector(resultForMaybeStates.getValues(), qualitativeStateSets.maybeStates));
1550 } else {
1551 storm::utility::vector::setVectorValues(result, qualitativeStateSets.maybeStates, resultForMaybeStates.getValues());
1552 }
1553 if (produceScheduler) {
1554 extractSchedulerChoices(*scheduler, transitionMatrix, resultForMaybeStates.getScheduler(), qualitativeStateSets.maybeStates,
1555 selectedChoices);
1556 }
1557 }
1558 }
1559 }
1560
1561 // Extend scheduler with choices for the states in the qualitative state sets.
1562 if (produceScheduler) {
1563 extendScheduler(*scheduler, minimize, qualitativeStateSets, transitionMatrix, backwardTransitions, targetStates, zeroRewardChoicesGetter);
1564 }
1565
1566 // Sanity check for created scheduler.
1567 STORM_LOG_ASSERT(!produceScheduler || scheduler, "Expected that a scheduler was obtained.");
1568 STORM_LOG_ASSERT((!produceScheduler && !scheduler) || !scheduler->isPartialScheduler(), "Expected a fully defined scheduler.");
1569 STORM_LOG_ASSERT((!produceScheduler && !scheduler) || scheduler->isDeterministicScheduler(), "Expected a deterministic scheduler.");
1570 STORM_LOG_ASSERT((!produceScheduler && !scheduler) || scheduler->isMemorylessScheduler(), "Expected a memoryless scheduler.");
1571
1572 if (qualitativeStateSets.maybeStates.empty()) {
1573 // The qualitative precomputation already decided every state, so all values are exact.
1574 resultBounds.setExact(result);
1575 }
1576
1577 if constexpr (storm::IsIntervalType<ValueType>) {
1578 ExtendedReturnType returnValue(std::move(result));
1579 returnValue.solutionBounds = std::move(resultBounds);
1580 return returnValue;
1581 } else {
1582 ExtendedReturnType returnValue(std::move(result), std::move(scheduler));
1583 returnValue.solutionBounds = std::move(resultBounds);
1584 return returnValue;
1585 }
1586}
1587
1588template class SparseMdpPrctlHelper<double>;
1589template std::vector<double> SparseMdpPrctlHelper<double>::computeInstantaneousRewards(Environment const& env, storm::solver::SolveGoal<double>&& goal,
1590 storm::storage::SparseMatrix<double> const& transitionMatrix,
1591 storm::models::sparse::StandardRewardModel<double> const& rewardModel,
1592 uint_fast64_t stepCount);
1593template std::vector<double> SparseMdpPrctlHelper<double>::computeCumulativeRewards(Environment const& env, storm::solver::SolveGoal<double>&& goal,
1594 storm::storage::SparseMatrix<double> const& transitionMatrix,
1595 storm::models::sparse::StandardRewardModel<double> const& rewardModel,
1596 uint_fast64_t stepBound);
1597template std::vector<double> SparseMdpPrctlHelper<double>::computeDiscountedCumulativeRewards(
1598 Environment const& env, storm::solver::SolveGoal<double>&& goal, storm::storage::SparseMatrix<double> const& transitionMatrix,
1599 storm::models::sparse::StandardRewardModel<double> const& rewardModel, uint_fast64_t stepBound, double discountFactor);
1600template MDPSparseModelCheckingHelperReturnType<double, storm::utility::ExtendedValueType<double>> SparseMdpPrctlHelper<double>::computeReachabilityRewards(
1601 Environment const& env, storm::solver::SolveGoal<double>&& goal, storm::storage::SparseMatrix<double> const& transitionMatrix,
1602 storm::storage::SparseMatrix<double> const& backwardTransitions, storm::models::sparse::StandardRewardModel<double> const& rewardModel,
1603 storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler, ModelCheckerHint const& hint);
1604template MDPSparseModelCheckingHelperReturnType<double, storm::utility::ExtendedValueType<double>> SparseMdpPrctlHelper<double>::computeTotalRewards(
1605 Environment const& env, storm::solver::SolveGoal<double>&& goal, storm::storage::SparseMatrix<double> const& transitionMatrix,
1606 storm::storage::SparseMatrix<double> const& backwardTransitions, storm::models::sparse::StandardRewardModel<double> const& rewardModel, bool qualitative,
1607 bool produceScheduler, ModelCheckerHint const& hint);
1608template MDPSparseModelCheckingHelperReturnType<double, storm::utility::ExtendedValueType<double>> SparseMdpPrctlHelper<double>::computeDiscountedTotalRewards(
1609 Environment const& env, storm::solver::SolveGoal<double>&& goal, storm::storage::SparseMatrix<double> const& transitionMatrix,
1610 storm::storage::SparseMatrix<double> const& backwardTransitions, storm::models::sparse::StandardRewardModel<double> const& rewardModel, bool qualitative,
1611 bool produceScheduler, double discountFactor, ModelCheckerHint const& hint);
1612
1613template class SparseMdpPrctlHelper<storm::RationalNumber>;
1614template std::vector<storm::RationalNumber> SparseMdpPrctlHelper<storm::RationalNumber>::computeInstantaneousRewards(
1615 Environment const& env, storm::solver::SolveGoal<storm::RationalNumber>&& goal, storm::storage::SparseMatrix<storm::RationalNumber> const& transitionMatrix,
1616 storm::models::sparse::StandardRewardModel<storm::RationalNumber> const& rewardModel, uint_fast64_t stepCount);
1617template std::vector<storm::RationalNumber> SparseMdpPrctlHelper<storm::RationalNumber>::computeCumulativeRewards(
1618 Environment const& env, storm::solver::SolveGoal<storm::RationalNumber>&& goal, storm::storage::SparseMatrix<storm::RationalNumber> const& transitionMatrix,
1619 storm::models::sparse::StandardRewardModel<storm::RationalNumber> const& rewardModel, uint_fast64_t stepBound);
1620template std::vector<storm::RationalNumber> SparseMdpPrctlHelper<storm::RationalNumber>::computeDiscountedCumulativeRewards(
1621 Environment const& env, storm::solver::SolveGoal<storm::RationalNumber>&& goal, storm::storage::SparseMatrix<storm::RationalNumber> const& transitionMatrix,
1622 storm::models::sparse::StandardRewardModel<storm::RationalNumber> const& rewardModel, uint_fast64_t stepBound, storm::RationalNumber discountFactor);
1623template MDPSparseModelCheckingHelperReturnType<storm::RationalNumber, storm::ExtendedRationalNumber>
1624SparseMdpPrctlHelper<storm::RationalNumber>::computeReachabilityRewards(Environment const& env, storm::solver::SolveGoal<storm::RationalNumber>&& goal,
1625 storm::storage::SparseMatrix<storm::RationalNumber> const& transitionMatrix,
1626 storm::storage::SparseMatrix<storm::RationalNumber> const& backwardTransitions,
1627 storm::models::sparse::StandardRewardModel<storm::RationalNumber> const& rewardModel,
1628 storm::storage::BitVector const& targetStates, bool qualitative, bool produceScheduler,
1629 ModelCheckerHint const& hint);
1630template MDPSparseModelCheckingHelperReturnType<storm::RationalNumber, storm::ExtendedRationalNumber>
1631SparseMdpPrctlHelper<storm::RationalNumber>::computeTotalRewards(Environment const& env, storm::solver::SolveGoal<storm::RationalNumber>&& goal,
1632 storm::storage::SparseMatrix<storm::RationalNumber> const& transitionMatrix,
1633 storm::storage::SparseMatrix<storm::RationalNumber> const& backwardTransitions,
1634 storm::models::sparse::StandardRewardModel<storm::RationalNumber> const& rewardModel,
1635 bool qualitative, bool produceScheduler, ModelCheckerHint const& hint);
1636template MDPSparseModelCheckingHelperReturnType<storm::RationalNumber, storm::ExtendedRationalNumber>
1637SparseMdpPrctlHelper<storm::RationalNumber>::computeDiscountedTotalRewards(Environment const& env, storm::solver::SolveGoal<storm::RationalNumber>&& goal,
1638 storm::storage::SparseMatrix<storm::RationalNumber> const& transitionMatrix,
1639 storm::storage::SparseMatrix<storm::RationalNumber> const& backwardTransitions,
1640 storm::models::sparse::StandardRewardModel<storm::RationalNumber> const& rewardModel,
1641 bool qualitative, bool produceScheduler, storm::RationalNumber discountFactor,
1642 ModelCheckerHint const& hint);
1643
1644template class SparseMdpPrctlHelper<storm::Interval, double>;
1645template std::vector<double> SparseMdpPrctlHelper<storm::Interval, double>::computeInstantaneousRewards(
1646 Environment const& env, storm::solver::SolveGoal<storm::Interval, double>&& goal, storm::storage::SparseMatrix<storm::Interval> const& transitionMatrix,
1647 storm::models::sparse::StandardRewardModel<storm::Interval> const& rewardModel, uint_fast64_t stepCount);
1648template std::vector<double> SparseMdpPrctlHelper<storm::Interval, double>::computeCumulativeRewards(
1649 Environment const& env, storm::solver::SolveGoal<storm::Interval, double>&& goal, storm::storage::SparseMatrix<storm::Interval> const& transitionMatrix,
1650 storm::models::sparse::StandardRewardModel<storm::Interval> const& rewardModel, uint_fast64_t stepBound);
1651template std::vector<double> SparseMdpPrctlHelper<storm::Interval, double>::computeReachabilityRewards<storm::Interval>(
1652 Environment const& env, storm::solver::SolveGoal<storm::Interval, double>&& goal, storm::storage::SparseMatrix<storm::Interval> const& transitionMatrix,
1653 storm::storage::SparseMatrix<storm::Interval> const& backwardTransitions, storm::models::sparse::StandardRewardModel<storm::Interval> const& rewardModel,
1654 bool lowerBoundOfIntervals, storm::storage::BitVector const& targetStates, bool qualitative);
1655template MDPSparseModelCheckingHelperReturnType<double, storm::utility::ExtendedValueType<double>>
1656SparseMdpPrctlHelper<storm::Interval, double>::computeTotalRewards(Environment const& env, storm::solver::SolveGoal<storm::Interval, double>&& goal,
1657 storm::storage::SparseMatrix<storm::Interval> const& transitionMatrix,
1658 storm::storage::SparseMatrix<storm::Interval> const& backwardTransitions,
1659 storm::models::sparse::StandardRewardModel<storm::Interval> const& rewardModel,
1660 bool qualitative, bool produceScheduler, ModelCheckerHint const& hint);
1661
1662template class SparseMdpPrctlHelper<storm::RationalInterval, storm::RationalNumber>;
1663template std::vector<storm::RationalNumber> SparseMdpPrctlHelper<storm::RationalInterval, storm::RationalNumber>::computeInstantaneousRewards(
1664 Environment const& env, storm::solver::SolveGoal<storm::RationalInterval, storm::RationalNumber>&& goal,
1665 storm::storage::SparseMatrix<storm::RationalInterval> const& transitionMatrix,
1666 storm::models::sparse::StandardRewardModel<storm::RationalInterval> const& rewardModel, uint_fast64_t stepCount);
1667template std::vector<storm::RationalNumber> SparseMdpPrctlHelper<storm::RationalInterval, storm::RationalNumber>::computeCumulativeRewards(
1668 Environment const& env, storm::solver::SolveGoal<storm::RationalInterval, storm::RationalNumber>&& goal,
1669 storm::storage::SparseMatrix<storm::RationalInterval> const& transitionMatrix,
1670 storm::models::sparse::StandardRewardModel<storm::RationalInterval> const& rewardModel, uint_fast64_t stepBound);
1671template std::vector<storm::ExtendedRationalNumber> SparseMdpPrctlHelper<storm::RationalInterval, storm::RationalNumber>::computeReachabilityRewards<
1672 storm::RationalInterval>(Environment const& env, storm::solver::SolveGoal<storm::RationalInterval, storm::RationalNumber>&& goal,
1673 storm::storage::SparseMatrix<storm::RationalInterval> const& transitionMatrix,
1674 storm::storage::SparseMatrix<storm::RationalInterval> const& backwardTransitions,
1675 storm::models::sparse::StandardRewardModel<storm::RationalInterval> const& rewardModel, bool lowerBoundOfIntervals,
1676 storm::storage::BitVector const& targetStates, bool qualitative);
1677template MDPSparseModelCheckingHelperReturnType<storm::RationalNumber, storm::ExtendedRationalNumber>
1678SparseMdpPrctlHelper<storm::RationalInterval, storm::RationalNumber>::computeTotalRewards(
1679 Environment const& env, storm::solver::SolveGoal<storm::RationalInterval, storm::RationalNumber>&& goal,
1680 storm::storage::SparseMatrix<storm::RationalInterval> const& transitionMatrix,
1681 storm::storage::SparseMatrix<storm::RationalInterval> const& backwardTransitions,
1682 storm::models::sparse::StandardRewardModel<storm::RationalInterval> const& rewardModel, bool qualitative, bool produceScheduler,
1683 ModelCheckerHint const& hint);
1684
1685} // namespace helper
1686} // namespace modelchecker
1687} // namespace storm
SolverEnvironment & solver()
ModelCheckerEnvironment & modelchecker()
storm::RationalNumber const & getPrecision() const
void setPrecision(storm::RationalNumber value)
std::string const & getExportCdfDirectory() const
MinMaxSolverEnvironment & minMax()
uint64_t getShowProgressDelay() const
This class contains information that might accelerate the model checking process.
ExplicitModelCheckerHint< ValueType > & asExplicitModelCheckerHint()
Bounds computeTotalRewardBounds(std::vector< ValueType > const &rewards)
Computes a lower and an upper bound on the expected total rewards.
storm::storage::Scheduler< ValueType > computeScheduler() const
Retrieves the generated scheduler.
bool solveWithDiscountedValueIteration(Environment const &env, std::optional< OptimizationDirection > dir, std::vector< ValueType > &x, std::vector< ValueType > const &b) const
std::vector< ValueType > computeUpperBounds()
Computes upper bounds on the expected rewards.
uint64_t getRowGroupAfterElimination(uint64_t state) const
Retrieves the row group of the state after end component elimination.
static SparseMdpEndComponentInformation< ValueType > eliminateEndComponents(storm::storage::MaximalEndComponentDecomposition< ValueType > const &endComponentDecomposition, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::BitVector const &maybeStates, storm::storage::BitVector const *sumColumns, storm::storage::BitVector const *selectedChoices, std::vector< ValueType > const *summand, storm::storage::SparseMatrix< ValueType > &submatrix, std::vector< ValueType > *columnSumVector, std::vector< ValueType > *summandResultVector, bool gatherExitChoices=false)
static ExtendedReturnType computeDiscountedTotalRewards(Environment const &env, storm::solver::SolveGoal< ValueType, SolutionType > &&goal, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::SparseMatrix< ValueType > const &backwardTransitions, RewardModelType const &rewardModel, bool qualitative, bool produceScheduler, ValueType discountFactor, ModelCheckerHint const &hint=ModelCheckerHint())
static ExtendedReturnType computeReachabilityRewards(Environment const &env, storm::solver::SolveGoal< ValueType, SolutionType > &&goal, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::SparseMatrix< ValueType > const &backwardTransitions, RewardModelType const &rewardModel, storm::storage::BitVector const &targetStates, bool qualitative, bool produceScheduler, ModelCheckerHint const &hint=ModelCheckerHint())
static MDPSparseModelCheckingHelperReturnType< SolutionType > computeGloballyProbabilities(Environment const &env, storm::solver::SolveGoal< ValueType, SolutionType > &&goal, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::SparseMatrix< ValueType > const &backwardTransitions, storm::storage::BitVector const &psiStates, bool qualitative, bool produceScheduler, bool useMecBasedTechnique=false)
static ExtendedReturnType computeTotalRewards(Environment const &env, storm::solver::SolveGoal< ValueType, SolutionType > &&goal, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::SparseMatrix< ValueType > const &backwardTransitions, RewardModelType const &rewardModel, bool qualitative, bool produceScheduler, ModelCheckerHint const &hint=ModelCheckerHint())
static std::vector< SolutionType > computeNextProbabilities(Environment const &env, OptimizationDirection dir, UncertaintyResolutionMode uncertaintyResolutionMode, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::BitVector const &nextStates)
static ExtendedReturnType computeReachabilityTimes(Environment const &env, storm::solver::SolveGoal< ValueType, SolutionType > &&goal, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::SparseMatrix< ValueType > const &backwardTransitions, storm::storage::BitVector const &targetStates, bool qualitative, bool produceScheduler, ModelCheckerHint const &hint=ModelCheckerHint())
MDPSparseModelCheckingHelperReturnType< SolutionType, ExtendedSolutionType > ExtendedReturnType
static std::vector< SolutionType > computeInstantaneousRewards(Environment const &env, storm::solver::SolveGoal< ValueType, SolutionType > &&goal, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, RewardModelType const &rewardModel, uint_fast64_t stepCount)
static MDPSparseModelCheckingHelperReturnType< SolutionType > computeUntilProbabilities(Environment const &env, storm::solver::SolveGoal< ValueType, SolutionType > &&goal, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::SparseMatrix< ValueType > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates, bool qualitative, bool produceScheduler, ModelCheckerHint const &hint=ModelCheckerHint())
static std::vector< SolutionType > computeRewardBoundedValues(Environment const &env, OptimizationDirection dir, rewardbounded::MultiDimensionalRewardUnfolding< ValueType, true > &rewardUnfolding, storm::storage::BitVector const &initialStates)
static std::vector< SolutionType > computeCumulativeRewards(Environment const &env, storm::solver::SolveGoal< ValueType, SolutionType > &&goal, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, RewardModelType const &rewardModel, uint_fast64_t stepBound)
static std::vector< SolutionType > computeDiscountedCumulativeRewards(Environment const &env, storm::solver::SolveGoal< ValueType, SolutionType > &&goal, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, RewardModelType const &rewardModel, uint_fast64_t stepBound, ValueType discountFactor)
uint64_t getDimensionOfEpoch(Epoch const &epoch, uint64_t const &dimension) const
Epoch getStartEpoch(bool setUnknownDimsToBottom=false)
Retrieves the desired epoch that needs to be analyzed to compute the reward bounded values.
EpochModel< ValueType, SingleObjectiveMode > & setCurrentEpoch(Epoch const &epoch)
std::vector< Epoch > getEpochComputationOrder(Epoch const &startEpoch, bool stopAtComputedEpochs=false)
Computes a sequence of epochs that need to be analyzed to get a result at the start epoch.
ValueType getRequiredEpochModelPrecision(Epoch const &startEpoch, ValueType const &precision)
Returns the precision required for the analyzis of each epoch model in order to achieve the given ove...
boost::optional< ValueType > getUpperObjectiveBound(uint64_t objectiveIndex=0)
Returns an upper/lower bound for the objective result in every state (if this bound could be computed...
bool empty() const
Retrieves whether the reward model is empty, i.e.
std::vector< ValueType > getTotalRewardVector(storm::storage::SparseMatrix< MatrixValueType > const &transitionMatrix) const
Creates a vector representing the complete reward vector based on the state-, state-action- and trans...
storm::storage::BitVector getChoicesWithFilter(storm::storage::SparseMatrix< MatrixValueType > const &transitionMatrix, std::function< bool(ValueType const &)> const &filter) const
Returns the set of choices for which all associated rewards (state, action or transition rewards) sat...
storm::storage::BitVector getStatesWithFilter(storm::storage::SparseMatrix< MatrixValueType > const &transitionMatrix, std::function< bool(ValueType const &)> const &filter) const
Returns the set of states for which all associated rewards (state, action or transition rewards) sati...
MinMaxLinearEquationSolverRequirements getRequirements(Environment const &env, bool hasUniqueSolution=false, bool hasNoEndComponents=false, boost::optional< storm::solver::OptimizationDirection > const &direction=boost::none, bool hasInitialScheduler=false, bool trackScheduler=false) const
Retrieves the requirements of the solver that would be created when calling create() right now.
std::string getEnabledRequirementsAsString() const
Returns a string that enumerates the enabled requirements.
std::unique_ptr< Multiplier< ValueType, SolutionType > > create(Environment const &env, storm::storage::SparseMatrix< ValueType > const &matrix)
bool hasRelevantValues() const
void restrictRelevantValues(storm::storage::BitVector const &filter)
storm::storage::BitVector & relevantValues()
void setRelevantValues(storm::storage::BitVector &&values)
OptimizationDirection direction() const
Definition SolveGoal.cpp:89
A bit vector that is internally represented as a vector of 64-bit values.
Definition BitVector.h:16
void complement()
Negates all bits in the bit vector.
uint64_t getNextSetIndex(uint64_t startingIndex) const
Retrieves the index of the bit that is the next bit set to true in the bit vector.
bool isDisjointFrom(BitVector const &other) const
Checks whether none of the bits that are set in the current bit vector are also set in the given bit ...
bool full() const
Retrieves whether all bits are set in this bit vector.
bool empty() const
Retrieves whether no bits are set to true in this bit vector.
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.
size_t size() const
Retrieves the number of bits this bit vector can store.
bool get(uint64_t index) const
Retrieves the truth value of the bit at the given index and performs a bound check.
bool empty() const
Checks if the decomposition is empty.
std::size_t size() const
Retrieves the number of blocks of this decomposition.
This class represents the decomposition of a nondeterministic model into its maximal end components.
std::string statistics(uint64_t totalNumberOfStates) const
Returns a string containing statistics about the MEC decomposition, e.g., the number of (trivial/non-...
This class defines which action is chosen in a particular state of a non-deterministic model.
Definition Scheduler.h:18
SchedulerChoice< ValueType > const & getChoice(uint_fast64_t modelState, uint_fast64_t memoryState=0) const
Gets the choice defined by the scheduler for the given model and memory state.
Definition Scheduler.cpp:94
void setChoice(SchedulerChoice< ValueType > const &choice, uint_fast64_t modelState, uint_fast64_t memoryState=0)
Sets the choice defined by the scheduler for the given state.
Definition Scheduler.cpp:38
A class that holds a possibly non-square matrix in the compressed row storage format.
SparseMatrix getSubmatrix(bool useGroups, storm::storage::BitVector const &rowConstraint, storm::storage::BitVector const &columnConstraint, bool insertDiagonalEntries=false, storm::storage::BitVector const &makeZeroColumns=storm::storage::BitVector()) const
Creates a submatrix of the current matrix by dropping all rows and columns whose bits are not set to ...
std::vector< value_type > getConstrainedRowSumVector(storm::storage::BitVector const &rowConstraint, storm::storage::BitVector const &columnConstraint) const
Computes a vector whose i-th entry is the sum of the entries in the i-th selected row where only thos...
SparseMatrix restrictRows(storm::storage::BitVector const &rowsToKeep, bool allowEmptyRowGroups=false) const
Restrict rows in grouped rows matrix.
SparseMatrix< ValueType > transposeSelectedRowsFromRowGroups(std::vector< uint64_t > const &rowGroupChoices, bool keepZeros=false) const
Transposes the matrix w.r.t.
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.
storm::storage::BitVector getRowGroupFilter(storm::storage::BitVector const &rowConstraint, bool setIfForAllRowsInGroup) const
Returns the indices of all row groups selected by the row constraints.
std::vector< index_type > const & getRowGroupIndices() const
Returns the grouping of rows of this matrix.
std::vector< value_type > getConstrainedRowGroupSumVector(storm::storage::BitVector const &rowGroupConstraint, storm::storage::BitVector const &columnConstraint) const
Computes a vector whose entries represent the sums of selected columns for all rows in selected row g...
index_type getRowCount() const
Returns the number of rows of the matrix.
storm::storage::BitVector getRowFilter(storm::storage::BitVector const &groupConstraint) const
Returns a bitvector representing the set of rows, with all indices set that correspond to one of the ...
SparseMatrix filterEntries(storm::storage::BitVector const &rowFilter) const
Returns a copy of this matrix that only considers entries in the selected rows.
static EndComponentEliminatorReturnType transform(storm::storage::SparseMatrix< ValueType > const &originalMatrix, storm::storage::MaximalEndComponentDecomposition< ValueType > ecs, storm::storage::BitVector const &subsystemStates, storm::storage::BitVector const &addSinkRowStates, bool addSelfLoopAtSinkStates=false)
A class that provides convenience operations to display run times.
bool updateProgress(uint64_t count)
Updates the progress to the current count and logs it (on the progress log channel) if the delay pass...
void setMaxCount(uint64_t maxCount)
Sets the maximal possible count.
void startNewMeasurement(uint64_t startCount)
Starts a new measurement, dropping all progress information collected so far.
A class that provides convenience operations to display run times.
Definition Stopwatch.h:13
void start()
Start stopwatch (again) and start measuring time.
Definition Stopwatch.cpp:48
void stop()
Stop stopwatch and add measured time to total time.
Definition Stopwatch.cpp:42
#define STORM_LOG_INFO(message)
Definition logging.h:34
#define STORM_LOG_WARN(message)
Definition logging.h:35
#define STORM_LOG_DEBUG(message)
Definition logging.h:28
#define STORM_LOG_STATISTICS(message)
Definition logging.h:48
#define STORM_LOG_TRACE(message)
Definition logging.h:22
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:9
#define STORM_LOG_ERROR_COND(cond, message)
Definition macros.h:68
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:39
void exportDataToCSVFile(std::string filepath, std::vector< std::vector< DataType > > const &data, boost::optional< std::vector< Header1Type > > const &header1=boost::none, boost::optional< std::vector< Header2Type > > const &header2=boost::none)
Definition export.h:13
SparseMdpHintType< SolutionType > computeHints(Environment const &env, SemanticSolutionType const &type, ModelCheckerHint const &hint, storm::OptimizationDirection const &dir, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::SparseMatrix< ValueType > const &backwardTransitions, storm::storage::BitVector const &maybeStates, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &targetStates, bool produceScheduler, boost::optional< storm::storage::BitVector > const &selectedChoices=boost::none, bool hasUniqueSolution=false)
void extractSchedulerChoices(storm::storage::Scheduler< SolutionType > &scheduler, std::vector< uint64_t > const &subChoices, storm::storage::BitVector const &maybeStates)
boost::optional< SparseMdpEndComponentInformation< ValueType > > computeFixedPointSystemUntilProbabilitiesEliminateEndComponents(storm::solver::SolveGoal< ValueType, SolutionType > &goal, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::SparseMatrix< ValueType > const &backwardTransitions, QualitativeStateSetsUntilProbabilities const &qualitativeStateSets, storm::storage::SparseMatrix< ValueType > &submatrix, std::vector< ValueType > &b, bool produceScheduler)
QualitativeStateSetsUntilProbabilities computeQualitativeStateSetsUntilProbabilities(storm::solver::SolveGoal< ValueType, SolutionType > const &goal, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::SparseMatrix< ValueType > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates)
void extractValueAndSchedulerHint(SparseMdpHintType< SolutionType > &hintStorage, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::SparseMatrix< ValueType > const &backwardTransitions, storm::storage::BitVector const &maybeStates, boost::optional< storm::storage::BitVector > const &selectedChoices, ModelCheckerHint const &hint, bool skipECWithinMaybeStatesCheck)
void extendScheduler(storm::storage::Scheduler< SolutionType > &scheduler, bool minimize, QualitativeStateSetsUntilProbabilities const &qualitativeStateSets, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::SparseMatrix< ValueType > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates)
std::vector< uint_fast64_t > computeValidSchedulerHint(Environment const &env, SemanticSolutionType const &type, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::SparseMatrix< ValueType > const &backwardTransitions, storm::storage::BitVector const &maybeStates, storm::storage::BitVector const &filterStates, storm::storage::BitVector const &targetStates, boost::optional< storm::storage::BitVector > const &selectedChoices)
QualitativeStateSetsUntilProbabilities getQualitativeStateSetsUntilProbabilitiesFromHint(ModelCheckerHint const &hint)
std::vector< ValueType > computeUpperRewardBounds(storm::storage::SparseMatrix< ValueType > const &transitionMatrix, std::vector< ValueType > const &rewards, std::vector< ValueType > const &oneStepTargetProbabilities)
QualitativeStateSetsReachabilityRewards getQualitativeStateSetsReachabilityRewards(Environment const &env, storm::solver::SolveGoal< ValueType, SolutionType > const &goal, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::SparseMatrix< ValueType > const &backwardTransitions, storm::storage::BitVector const &targetStates, ModelCheckerHint const &hint, std::function< storm::storage::BitVector()> const &zeroRewardStatesGetter, std::function< storm::storage::BitVector()> const &zeroRewardChoicesGetter)
void computeFixedPointSystemUntilProbabilities(storm::solver::SolveGoal< ValueType, SolutionType > &goal, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, QualitativeStateSetsUntilProbabilities const &qualitativeStateSets, storm::storage::SparseMatrix< ValueType > &submatrix, std::vector< ValueType > &b)
MaybeStateResult< SolutionType > computeValuesForMaybeStates(Environment const &env, storm::solver::SolveGoal< ValueType, SolutionType > &&goal, storm::storage::SparseMatrix< ValueType > &&submatrix, std::vector< ValueType > const &b, bool produceScheduler, SparseMdpHintType< SolutionType > &hint)
QualitativeStateSetsReachabilityRewards getQualitativeStateSetsReachabilityRewardsFromHint(ModelCheckerHint const &hint, storm::storage::BitVector const &targetStates)
boost::optional< SparseMdpEndComponentInformation< ValueType > > computeFixedPointSystemReachabilityRewardsEliminateEndComponents(storm::solver::SolveGoal< ValueType, SolutionType > &goal, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::SparseMatrix< ValueType > const &backwardTransitions, QualitativeStateSetsReachabilityRewards const &qualitativeStateSets, boost::optional< storm::storage::BitVector > const &selectedChoices, std::function< std::vector< ValueType >(uint_fast64_t, storm::storage::SparseMatrix< ValueType > const &, storm::storage::BitVector const &)> const &totalStateRewardVectorGetter, storm::storage::SparseMatrix< ValueType > &submatrix, std::vector< ValueType > &b, boost::optional< std::vector< ValueType > > &oneStepTargetProbabilities, bool produceScheduler)
QualitativeStateSetsReachabilityRewards computeQualitativeStateSetsReachabilityRewards(Environment const &env, storm::solver::SolveGoal< ValueType, SolutionType > const &goal, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::SparseMatrix< ValueType > const &backwardTransitions, storm::storage::BitVector const &targetStates, std::function< storm::storage::BitVector()> const &zeroRewardStatesGetter, std::function< storm::storage::BitVector()> const &zeroRewardChoicesGetter)
QualitativeStateSetsUntilProbabilities getQualitativeStateSetsUntilProbabilities(storm::solver::SolveGoal< ValueType, SolutionType > const &goal, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::SparseMatrix< ValueType > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates, ModelCheckerHint const &hint)
void computeFixedPointSystemReachabilityRewards(storm::solver::SolveGoal< ValueType, SolutionType > &goal, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, QualitativeStateSetsReachabilityRewards const &qualitativeStateSets, boost::optional< storm::storage::BitVector > const &selectedChoices, std::function< std::vector< ValueType >(uint_fast64_t, storm::storage::SparseMatrix< ValueType > const &, storm::storage::BitVector const &)> const &totalStateRewardVectorGetter, storm::storage::SparseMatrix< ValueType > &submatrix, std::vector< ValueType > &b, std::vector< ValueType > *oneStepTargetProbabilities=nullptr)
bool isSet(OptimizationDirectionSetting s)
std::unique_ptr< storm::solver::MinMaxLinearEquationSolver< ValueType, SolutionType > > configureMinMaxLinearEquationSolver(Environment const &env, SolveGoal< ValueType, SolutionType > &&goal, storm::solver::MinMaxLinearEquationSolverFactory< ValueType, SolutionType > const &factory, MatrixType &&matrix, OptimizationDirectionSetting optimizationDirectionSetting=OptimizationDirectionSetting::Unset)
Definition SolveGoal.h:110
bool constexpr minimize(OptimizationDirection d)
std::pair< storm::storage::BitVector, storm::storage::BitVector > performProb01Max(storm::storage::SparseMatrix< T > const &transitionMatrix, std::vector< uint_fast64_t > const &nondeterministicChoiceIndices, storm::storage::SparseMatrix< T > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates)
Definition graph.cpp:855
void computeSchedulerStayingInStates(storm::storage::BitVector const &states, storm::storage::SparseMatrix< T > const &transitionMatrix, storm::storage::Scheduler< SchedulerValueType > &scheduler, boost::optional< storm::storage::BitVector > const &rowFilter)
Computes a scheduler for the given states that chooses an action that stays completely in the very sa...
Definition graph.cpp:484
void computeSchedulerProbGreater0E(storm::storage::SparseMatrix< T > const &transitionMatrix, storm::storage::SparseMatrix< T > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates, storm::storage::Scheduler< SchedulerValueType > &scheduler, boost::optional< storm::storage::BitVector > const &rowFilter)
Computes a scheduler for the ProbGreater0E-States such that in the induced system the given psiStates...
Definition graph.cpp:536
storm::storage::BitVector performProbGreater0A(storm::storage::SparseMatrix< T > const &transitionMatrix, std::vector< uint_fast64_t > const &nondeterministicChoiceIndices, storm::storage::SparseMatrix< T > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates, bool useStepBound, uint_fast64_t maximalSteps, boost::optional< storm::storage::BitVector > const &choiceConstraint)
Computes the sets of states that have probability greater 0 of satisfying phi until psi under any pos...
Definition graph.cpp:881
void computeSchedulerProb1E(storm::storage::BitVector const &prob1EStates, storm::storage::SparseMatrix< T > const &transitionMatrix, storm::storage::SparseMatrix< T > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates, storm::storage::Scheduler< SchedulerValueType > &scheduler, boost::optional< storm::storage::BitVector > const &rowFilter)
Computes a scheduler for the given prob1EStates such that in the induced system the given psiStates a...
Definition graph.cpp:609
storm::storage::BitVector performProb1A(storm::models::sparse::NondeterministicModel< T, RM > const &model, storm::storage::SparseMatrix< T > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates)
Computes the sets of states that have probability 1 of satisfying phi until psi under all possible re...
Definition graph.cpp:1019
storm::storage::BitVector performProbGreater0E(storm::storage::SparseMatrix< T > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates, bool useStepBound, uint_fast64_t maximalSteps)
Computes the sets of states that have probability greater 0 of satisfying phi until psi under at leas...
Definition graph.cpp:674
storm::storage::BitVector performProb1(storm::storage::SparseMatrix< T > const &backwardTransitions, storm::storage::BitVector const &, storm::storage::BitVector const &psiStates, storm::storage::BitVector const &statesWithProbabilityGreater0)
Computes the set of states of the given model for which all paths lead to the given set of target sta...
Definition graph.cpp:377
storm::storage::BitVector performProb0E(storm::models::sparse::NondeterministicModel< T, RM > const &model, storm::storage::SparseMatrix< T > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates)
Computes the sets of states that have probability 0 of satisfying phi until psi under at least one po...
Definition graph.cpp:998
void computeSchedulerProb0E(storm::storage::BitVector const &prob0EStates, storm::storage::SparseMatrix< T > const &transitionMatrix, storm::storage::Scheduler< SchedulerValueType > &scheduler)
Computes a scheduler for the given states that have a scheduler that has a probability 0.
Definition graph.cpp:587
std::pair< storm::storage::BitVector, storm::storage::BitVector > performProb01Min(storm::storage::SparseMatrix< T > const &transitionMatrix, std::vector< uint_fast64_t > const &nondeterministicChoiceIndices, storm::storage::SparseMatrix< T > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates)
Definition graph.cpp:1101
storm::storage::BitVector performProb1E(storm::storage::SparseMatrix< T > const &transitionMatrix, std::vector< uint_fast64_t > const &nondeterministicChoiceIndices, storm::storage::SparseMatrix< T > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates, boost::optional< storm::storage::BitVector > const &choiceConstraint)
Computes the sets of states that have probability 1 of satisfying phi until psi under at least one po...
Definition graph.cpp:740
void computeSchedulerRewInf(storm::storage::BitVector const &rewInfStates, storm::storage::SparseMatrix< T > const &transitionMatrix, storm::storage::SparseMatrix< T > const &backwardTransitions, storm::storage::Scheduler< SchedulerValueType > &scheduler)
Computes a scheduler for the given states that have a scheduler that has a reward infinity.
Definition graph.cpp:593
bool isTerminate()
Check whether the program should terminate (due to some abort signal).
void setVectorValues(std::vector< T > &vector, storm::storage::BitVector const &positions, std::vector< S > const &values)
Sets the provided values at the provided positions in the given vector.
Definition vector.h:79
void setAllValues(std::vector< T > &vec, storm::storage::BitVector const &positions, T const &positiveValue=storm::utility::one< T >(), T const &negativeValue=storm::utility::zero< T >())
Definition vector.h:54
void selectVectorValues(std::vector< T > &vector, storm::storage::BitVector const &positions, std::vector< T > const &values)
Selects the elements from a vector at the specified positions and writes them consecutively into anot...
Definition vector.h:185
void filterVectorInPlace(std::vector< Type > &v, storm::storage::BitVector const &filter)
Definition vector.h:1080
std::vector< Type > filterVector(std::vector< Type > const &in, storm::storage::BitVector const &filter)
Definition vector.h:1069
ExtendedValueType< ValueType > positiveInfinity()
bool isOne(ValueType const &a)
Definition constants.cpp:39
std::vector< ExtendedValueType< ValueType > > widen(std::vector< ValueType > &&values)
Widens a vector of finite values into the extended value type.
bool isZero(ValueType const &a)
Definition constants.cpp:44
ValueType zero()
Definition constants.cpp:26
std::vector< ValueType > narrowFinite(std::vector< ExtendedValueType< ValueType > > &&values)
The counterpart of widen for a vector all of whose values are finite.
ValueType one()
Definition constants.cpp:21
bool isInfinity(ValueType const &a)
TargetType convertNumber(SourceType const &number)
carl::Interval< storm::RationalNumber > RationalInterval
solver::UncertaintyResolutionMode UncertaintyResolutionMode
solver::OptimizationDirection OptimizationDirection
constexpr bool IsIntervalType
Helper to check if a type is an interval.
typename detail::IntervalMetaProgrammingHelper< ValueType >::BaseType IntervalBaseType
Helper to access the type in which interval boundaries are stored.
storm::solver::SolutionBounds< ValueType > solutionBounds
boost::optional< std::vector< uint64_t > > scheduler
MaybeStateResult(std::vector< ValueType > &&values)
std::vector< uint64_t > const & getScheduler() const
std::vector< ValueType > const & getValues() const
boost::optional< std::vector< uint64_t > > schedulerHint
boost::optional< std::vector< ValueType > > valueHint
std::vector< ValueType > const & getUpperResultBounds() const
boost::optional< std::vector< ValueType > > upperResultBounds
Sound lower and upper bounds on a solution vector.
auto transform(Function const &function) const
Applies the given function to whichever of the bounds are set, e.g.
void setExact(std::vector< ValueType > const &values)
Sets both bounds to the given values, i.e.