Storm 1.14.0.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
SparseDtmcPrctlHelper.cpp
Go to the documentation of this file.
2
10#include "storm/io/export.h"
23#include "storm/utility/graph.h"
26
27namespace storm {
28namespace modelchecker {
29namespace helper {
30
31template<>
34 std::shared_ptr<storm::logic::OperatorFormula const> /*rewardBoundedFormula*/) {
35 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "The specified property is not supported by this value type.");
36 return std::vector<storm::RationalFunction>();
37}
38
39template<typename ValueType, typename RewardModelType, typename SolutionType>
41 Environment const& env, storm::models::sparse::Dtmc<ValueType> const& model, std::shared_ptr<storm::logic::OperatorFormula const> rewardBoundedFormula) {
43 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "We do not support computing reward bounded values with interval models.");
44 } else {
45 storm::utility::Stopwatch swAll(true), swBuild, swCheck;
46
48
49 // Get lower and upper bounds for the solution.
50 auto lowerBound = rewardUnfolding.getLowerObjectiveBound();
51 auto upperBound = rewardUnfolding.getUpperObjectiveBound();
52
53 // Initialize epoch models
54 auto initEpoch = rewardUnfolding.getStartEpoch();
55 auto epochOrder = rewardUnfolding.getEpochComputationOrder(initEpoch);
56
57 // initialize data that will be needed for each epoch
58 std::vector<ValueType> x, b;
59 std::unique_ptr<storm::solver::LinearEquationSolver<ValueType>> linEqSolver;
60
61 Environment preciseEnv = env;
62 // Only iterative linear equation solvers have a precision (elimination does not).
63 if (auto const linearEquationSolverPrecision = env.solver().getPrecisionOfLinearEquationSolver(env.solver().getLinearEquationSolverType()).first;
64 linearEquationSolverPrecision) {
65 ValueType precision =
66 rewardUnfolding.getRequiredEpochModelPrecision(initEpoch, storm::utility::convertNumber<ValueType>(*linearEquationSolverPrecision));
68 }
69
70 // In case of cdf export we store the necessary data.
71 std::vector<std::vector<ValueType>> cdfData;
72
73 // Set the correct equation problem format.
75 rewardUnfolding.setEquationSystemFormatForEpochModel(linearEquationSolverFactory.getEquationProblemFormat(preciseEnv));
76
78 progress.setMaxCount(epochOrder.size());
79 progress.startNewMeasurement(0);
80 uint64_t numCheckedEpochs = 0;
81 for (auto const& epoch : epochOrder) {
82 swBuild.start();
83 auto& epochModel = rewardUnfolding.setCurrentEpoch(epoch);
84 swBuild.stop();
85 swCheck.start();
86 rewardUnfolding.setSolutionForCurrentEpoch(epochModel.analyzeSingleObjective(preciseEnv, x, b, linEqSolver, lowerBound, upperBound));
87 swCheck.stop();
88 if (env.modelchecker().isExportCdfSet() && !rewardUnfolding.getEpochManager().hasBottomDimension(epoch)) {
89 std::vector<ValueType> cdfEntry;
90 for (uint64_t i = 0; i < rewardUnfolding.getEpochManager().getDimensionCount(); ++i) {
91 uint64_t offset = rewardUnfolding.getDimension(i).boundType == helper::rewardbounded::DimensionBoundType::LowerBound ? 1 : 0;
92 cdfEntry.push_back(storm::utility::convertNumber<ValueType>(rewardUnfolding.getEpochManager().getDimensionOfEpoch(epoch, i) + offset) *
93 rewardUnfolding.getDimension(i).scalingFactor);
94 }
95 cdfEntry.push_back(rewardUnfolding.getInitialStateResult(epoch));
96 cdfData.push_back(std::move(cdfEntry));
97 }
98 ++numCheckedEpochs;
99 progress.updateProgress(numCheckedEpochs);
101 break;
102 }
103 }
104
105 std::vector<ValueType> result;
106 result.reserve(model.getInitialStates().getNumberOfSetBits());
107 for (auto initState : model.getInitialStates()) {
108 result.push_back(rewardUnfolding.getInitialStateResult(initEpoch, initState));
109 }
110
111 swAll.stop();
112
113 if (env.modelchecker().isExportCdfSet()) {
114 std::vector<std::string> headers;
115 for (uint64_t i = 0; i < rewardUnfolding.getEpochManager().getDimensionCount(); ++i) {
116 headers.push_back(rewardUnfolding.getDimension(i).formula->toString());
117 }
118 headers.push_back("Result");
120 }
121
122 STORM_LOG_STATISTICS("---------------------------------\n");
123 STORM_LOG_STATISTICS("Statistics:\n");
124 STORM_LOG_STATISTICS("---------------------------------\n");
125 STORM_LOG_STATISTICS(" #checked epochs: " << epochOrder.size() << ".\n");
126 STORM_LOG_STATISTICS(" overall Time: " << swAll << ".\n");
127 STORM_LOG_STATISTICS("Epoch Model building Time: " << swBuild << ".\n");
128 STORM_LOG_STATISTICS("Epoch Model checking Time: " << swCheck << ".\n");
129 STORM_LOG_STATISTICS("---------------------------------\n");
130
131 return result;
132 }
133}
134
135template<typename ValueType, typename SolutionType>
137 storm::storage::SparseMatrix<ValueType>&& submatrix, std::vector<ValueType> const& b,
138 bool computeReward, storm::solver::SolutionBounds<SolutionType>& solutionBounds) {
139 // Initialize the solution vector.
140 std::vector<SolutionType> x = std::vector<SolutionType>(submatrix.getRowGroupCount(), storm::utility::zero<SolutionType>());
141
142 // Set up the solver.
144 // The goal is consumed by the solver configuration, so capture what is needed first.
145 auto const uncertaintyResolutionMode = goal.getUncertaintyResolutionMode();
146 std::unique_ptr<storm::solver::MinMaxLinearEquationSolver<ValueType, SolutionType>> solver = storm::solver::configureMinMaxLinearEquationSolver(
147 env, std::move(goal), minMaxLinearEquationSolverFactory, std::move(submatrix),
148 convert(OptimizationDirection::Maximize)); // default to maximize for IDTMCs; does not affect the result
149 solver->setUncertaintyResolutionMode(uncertaintyResolutionMode);
150 solver->setHasUniqueSolution(computeReward); // As we check for graph-preservation, in case of rewards on IDTMCs, we have a unique solution
151 solver->setHasNoEndComponents(false);
152
153 // check requirements of solver
154 auto req = solver->getRequirements(env);
155 if (!computeReward) {
158 req.clearBounds();
159 }
160 STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException,
161 "Solver requirements " + req.getEnabledRequirementsAsString() + " not checked.");
162
163 solver->setRequirementsChecked();
164
165 // Solve the corresponding system of equations.
166 solver->solveEquations(env, x, b);
167
168 // This goes through the same MinMax solvers the MDP helper uses, so it gets the same bounds out of them.
169 solutionBounds = solver->getSolutionBounds();
170
171 return x;
172}
173
174template<typename ValueType, typename RewardModelType, typename SolutionType>
177 storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates,
178 bool qualitative, ModelCheckerHint const& hint) {
180 std::vector<SolutionType> result(transitionMatrix.getRowCount(), storm::utility::zero<SolutionType>());
181
182 // We need to identify the maybe states (states which have a probability for satisfying the until formula
183 // that is strictly between 0 and 1) and the states that satisfy the formula with probability 1.
184 storm::storage::BitVector maybeStates, statesWithProbability1;
185
186 if (hint.isExplicitModelCheckerHint() && hint.template asExplicitModelCheckerHint<ValueType>().getComputeOnlyMaybeStates()) {
187 maybeStates = hint.template asExplicitModelCheckerHint<ValueType>().getMaybeStates();
188
189 // Treat the states with probability one
190 std::vector<ExtendedSolutionType> const& resultsForNonMaybeStates = hint.template asExplicitModelCheckerHint<SolutionType>().getResultHint();
191 statesWithProbability1 = storm::storage::BitVector(maybeStates.size(), false);
192 storm::storage::BitVector nonMaybeStates = ~maybeStates;
193 for (uint64_t state : nonMaybeStates) {
194 if (storm::utility::isOne(resultsForNonMaybeStates[state])) {
195 statesWithProbability1.set(state, true);
196 result[state] = storm::utility::one<SolutionType>();
197 } else {
198 STORM_LOG_THROW(storm::utility::isZero(resultsForNonMaybeStates[state]), storm::exceptions::IllegalArgumentException,
199 "Expected that the result hint specifies probabilities in {0,1} for non-maybe states.");
200 }
201 }
202
203 STORM_LOG_INFO("Preprocessing: " << statesWithProbability1.getNumberOfSetBits() << " states with probability 1 (" << maybeStates.getNumberOfSetBits()
204 << " states remaining).");
205 } else {
206 // Get all states that have probability 0 and 1 of satisfying the until-formula.
207 std::pair<storm::storage::BitVector, storm::storage::BitVector> statesWithProbability01 =
208 storm::utility::graph::performProb01(backwardTransitions, phiStates, psiStates);
209 storm::storage::BitVector statesWithProbability0 = std::move(statesWithProbability01.first);
210 statesWithProbability1 = std::move(statesWithProbability01.second);
211 maybeStates = ~(statesWithProbability0 | statesWithProbability1);
212
213 STORM_LOG_INFO("Preprocessing: " << statesWithProbability1.getNumberOfSetBits() << " states with probability 1, "
214 << statesWithProbability0.getNumberOfSetBits() << " with probability 0 (" << maybeStates.getNumberOfSetBits()
215 << " states remaining).");
216
217 // Set values of resulting vector that are known exactly.
220 }
221
222 // Check if the values of the maybe states are relevant for the SolveGoal
223 bool maybeStatesNotRelevant = goal.hasRelevantValues() && goal.relevantValues().isDisjointFrom(maybeStates);
224
225 // Check whether we need to compute exact probabilities for some states.
226 if (qualitative || maybeStatesNotRelevant) {
227 // Set the values for all maybe-states to 0.5 to indicate that their probability values are neither 0 nor 1.
229 } else {
230 if (!maybeStates.empty()) {
231 // In this case we have to compute the probabilities.
232 if constexpr (storm::IsIntervalType<ValueType>) {
233 // Compute probabilities in a robust fashion by using the logic as for MDPs
235 std::vector<ValueType> b;
236
237 submatrix = transitionMatrix.filterEntries(transitionMatrix.getRowFilter(maybeStates));
238
239 // Prepare the right-hand side of the equation system. For entry i this corresponds to
240 // the accumulated probability of going from state i to some state that has probability 1.
241 storm::utility::vector::setAllValues(b, transitionMatrix.getRowFilter(statesWithProbability1));
242
243 std::vector<SolutionType> resultForMaybeStates =
244 computeRobustValuesForMaybeStates(env, std::move(goal), std::move(submatrix), b, false, solutionBounds);
245
246 // For interval models, the result for maybe states indeed also holds values for all qualitative states.
247 STORM_LOG_ASSERT(resultForMaybeStates.size() == transitionMatrix.getColumnCount(), "Dimensions do not match.");
248 result = std::move(resultForMaybeStates);
249 } else {
250 // Check whether we need to convert the input to equation system format.
252 bool convertToEquationSystem =
254
255 // We can eliminate the rows and columns from the original transition probability matrix.
256 storm::storage::SparseMatrix<ValueType> submatrix = transitionMatrix.getSubmatrix(true, maybeStates, maybeStates, convertToEquationSystem);
257 if (convertToEquationSystem) {
258 // Converting the matrix from the fixpoint notation to the form needed for the equation
259 // system. That is, we go from x = A*x + b to (I-A)x = b.
260 submatrix.convertToEquationSystem();
261 }
262
263 // Initialize the x vector with the hint (if available) or with 0.5 for each element.
264 // This is the initial guess for the iterative solvers. It should be safe as for all
265 // 'maybe' states we know that the probability is strictly larger than 0.
266 std::vector<SolutionType> x;
267 if (hint.isExplicitModelCheckerHint() && hint.template asExplicitModelCheckerHint<ValueType>().hasResultHint()) {
269 storm::utility::vector::filterVector(hint.template asExplicitModelCheckerHint<SolutionType>().getResultHint(), maybeStates));
270 } else {
271 x = std::vector<SolutionType>(maybeStates.getNumberOfSetBits(), storm::utility::convertNumber<SolutionType>(0.5));
272 }
273
274 // Prepare the right-hand side of the equation system. For entry i this corresponds to
275 // the accumulated probability of going from state i to some 'yes' state.
276 std::vector<SolutionType> b = transitionMatrix.getConstrainedRowSumVector(maybeStates, statesWithProbability1);
277
278 // Now solve the created system of linear equations.
279 goal.restrictRelevantValues(maybeStates);
280 std::unique_ptr<storm::solver::LinearEquationSolver<ValueType>> solver =
281 storm::solver::configureLinearEquationSolver(env, std::move(goal), linearEquationSolverFactory, std::move(submatrix));
283 solver->solveEquations(env, x, b);
284
285 // The copy of result supplies the exact values outside the maybe states.
286 auto embedBound = [&result, &maybeStates](std::vector<SolutionType> const& boundForMaybeStates) {
287 std::vector<SolutionType> bound(result);
288 storm::utility::vector::setVectorValues<SolutionType>(bound, maybeStates, boundForMaybeStates);
289 return bound;
290 };
291 solutionBounds = solver->getSolutionBounds().transform(embedBound);
292
293 // Set values of resulting vector according to result.
294 storm::utility::vector::setVectorValues(result, maybeStates, x);
295 }
296 }
297 }
298 if (maybeStates.empty()) {
299 // The qualitative precomputation already decided every state, so all values are exact.
300 solutionBounds.setExact(result);
301 }
302 DTMCSparseModelCheckingHelperReturnType<SolutionType> returnValue(std::move(result));
303 returnValue.solutionBounds = std::move(solutionBounds);
304 return returnValue;
305}
306
307template<typename ValueType, typename RewardModelType, typename SolutionType>
310 storm::storage::BitVector const& initialStates, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates) {
311 if constexpr (storm::IsIntervalType<ValueType>) {
312 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "We do not support computing all until probabilities with interval models.");
313 } else {
314 uint_fast64_t numberOfStates = transitionMatrix.getRowCount();
315 std::vector<SolutionType> result(numberOfStates, storm::utility::zero<SolutionType>());
316
317 // All states are relevant
318 storm::storage::BitVector relevantStates(numberOfStates, true);
319
320 // Compute exact probabilities for some states.
321 if (!relevantStates.empty()) {
322 // Check whether we need to convert the input to equation system format.
324 bool convertToEquationSystem =
326
327 storm::storage::SparseMatrix<ValueType> submatrix(transitionMatrix);
328 submatrix.makeRowsAbsorbing(phiStates);
329 submatrix.makeRowsAbsorbing(psiStates);
330 // submatrix.deleteDiagonalEntries(psiStates);
331 // storm::storage::BitVector failState(numberOfStates, false);
332 // failState.set(0, true);
333 submatrix.deleteDiagonalEntries();
334 submatrix = submatrix.transpose();
335 submatrix = submatrix.getSubmatrix(true, relevantStates, relevantStates, convertToEquationSystem);
336
337 if (convertToEquationSystem) {
338 // Converting the matrix from the fixpoint notation to the form needed for the equation
339 // system. That is, we go from x = A*x + b to (I-A)x = b.
340 submatrix.convertToEquationSystem();
341 }
342
343 // Initialize the x vector with 0.5 for each element.
344 // This is the initial guess for the iterative solvers. It should be safe as for all
345 // 'maybe' states we know that the probability is strictly larger than 0.
346 std::vector<SolutionType> x = std::vector<SolutionType>(relevantStates.getNumberOfSetBits(), storm::utility::convertNumber<SolutionType>(0.5));
347
348 // Prepare the right-hand side of the equation system.
349 std::vector<SolutionType> b(relevantStates.getNumberOfSetBits(), storm::utility::zero<SolutionType>());
350 // Set initial states
351 size_t i = 0;
353 for (uint64_t state : relevantStates) {
354 if (initialStates.get(state)) {
355 b[i] = initDist;
356 }
357 ++i;
358 }
359
360 // Now solve the created system of linear equations.
361 goal.restrictRelevantValues(relevantStates);
362 std::unique_ptr<storm::solver::LinearEquationSolver<ValueType>> solver =
363 storm::solver::configureLinearEquationSolver(env, std::move(goal), linearEquationSolverFactory, std::move(submatrix));
365 solver->solveEquations(env, x, b);
366
367 // Set values of resulting vector according to result.
369 }
370 return result;
371 }
372}
373
374template<typename ValueType, typename RewardModelType, typename SolutionType>
377 storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& psiStates, bool qualitative) {
378 if constexpr (storm::IsIntervalType<ValueType>) {
379 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "We do not support computing globally probabilities with interval models.");
380 } else {
381 goal.oneMinus();
383 computeUntilProbabilities(env, std::move(goal), transitionMatrix, backwardTransitions,
384 storm::storage::BitVector(transitionMatrix.getRowCount(), true), ~psiStates, qualitative);
386 returnValue.solutionBounds.invertProbabilityBounds();
387 return returnValue;
388 }
389}
390
391template<typename ValueType, typename RewardModelType, typename SolutionType>
393 Environment const& env, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::BitVector const& nextStates) {
394 if constexpr (storm::IsIntervalType<ValueType>) {
395 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "We do not support next probabilities with interval models.");
396 } else {
397 // Create the vector with which to multiply and initialize it correctly.
398 std::vector<ValueType> result(transitionMatrix.getRowCount());
400
401 // Perform one single matrix-vector multiplication.
402 auto multiplier = storm::solver::MultiplierFactory<ValueType>().create(env, transitionMatrix);
403 multiplier->multiply(env, result, nullptr, result);
404 return result;
405 }
406}
407
408template<typename ValueType, typename RewardModelType, typename SolutionType>
411 RewardModelType const& rewardModel, uint_fast64_t stepBound) {
412 if constexpr (storm::IsIntervalType<ValueType>) {
413 STORM_LOG_ASSERT(storm::solver::isSet(goal.getUncertaintyResolutionMode()), "Interval model given, but no uncertainty resolution mode is specified.");
414 STORM_LOG_THROW(!rewardModel.hasTransitionRewards(), storm::exceptions::NotSupportedException,
415 "Cumulative rewards on interval models do not support transition rewards.");
416 }
417 // Initialize result to the zero vector.
418 std::vector<SolutionType> result(transitionMatrix.getRowCount(), storm::utility::zero<SolutionType>());
419
420 // Compute the reward vector to add in each step based on the available reward models.
421 // The reward vector may contain intervals. The multiplier picks the bound that is consistent with the uncertainty resolution mode.
422 std::vector<ValueType> totalRewardVector = rewardModel.getTotalRewardVector(transitionMatrix);
423
424 // Perform the matrix vector multiplication as often as required by the formula bound.
425 auto multiplier = storm::solver::MultiplierFactory<ValueType, SolutionType>().create(env, transitionMatrix);
426 if constexpr (storm::IsIntervalType<ValueType>) {
427 // The optimization direction only serves to select how uncertainty is resolved (default is to maximize the result).
428 multiplier->repeatedMultiplyAndReduce(env, storm::OptimizationDirection::Maximize, result, &totalRewardVector, stepBound,
429 goal.getUncertaintyResolutionMode());
430 } else {
431 multiplier->repeatedMultiply(env, result, &totalRewardVector, stepBound);
432 }
433 return result;
434}
435
436template<typename ValueType, typename RewardModelType, typename SolutionType>
439 RewardModelType const& rewardModel, uint_fast64_t stepCount) {
440 if constexpr (storm::IsIntervalType<ValueType>) {
441 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "We do not support instantaneous rewards with interval models.");
442 } else {
443 // Only compute the result if the model has a state-based reward this->getModel().
444 STORM_LOG_THROW(rewardModel.hasStateRewards(), storm::exceptions::InvalidPropertyException,
445 "Computing instantaneous rewards for a reward model that does not define any state-rewards. The result is trivially 0.");
446
447 // Initialize result to state rewards of the model.
448 std::vector<ValueType> result = rewardModel.getStateRewardVector();
449
450 // Perform the matrix vector multiplication as often as required by the formula bound.
451 auto multiplier = storm::solver::MultiplierFactory<ValueType>().create(env, transitionMatrix);
452 multiplier->repeatedMultiply(env, result, nullptr, stepCount);
453
454 return result;
455 }
456}
457
458template<typename ValueType, typename RewardModelType, typename SolutionType>
462 storm::storage::SparseMatrix<ValueType> const& backwardTransitions, RewardModelType const& rewardModel, bool qualitative, ModelCheckerHint const& hint) {
463 if constexpr (storm::IsIntervalType<ValueType>) {
464 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "We do not support computing total rewards with interval models.");
465 } else {
466 // Identify the states from which only states with zero reward are reachable.
467 // We can then compute reachability rewards assuming these states as target set.
468 storm::storage::BitVector statesWithoutReward = rewardModel.getStatesWithZeroReward(transitionMatrix);
469 storm::storage::BitVector rew0States = storm::utility::graph::performProbGreater0(backwardTransitions, statesWithoutReward, ~statesWithoutReward);
470 rew0States.complement();
471 return computeReachabilityRewards(env, std::move(goal), transitionMatrix, backwardTransitions, rewardModel, rew0States, qualitative, hint);
472 }
473}
474
475template<>
479 storm::models::sparse::StandardRewardModel<storm::RationalFunction> const& rewardModel, uint_fast64_t stepBound, storm::RationalFunction discountFactor) {
480 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "The specified property is not supported by this value type.");
481 return {};
482}
483
484template<typename ValueType, typename RewardModelType, typename SolutionType>
487 RewardModelType const& rewardModel, uint_fast64_t stepBound, ValueType discountFactor) {
488 if constexpr (storm::IsIntervalType<ValueType>) {
489 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "We do not support discounted cumulative rewards with interval models.");
490 } else {
491 // Only compute the result if the model has at least one reward this->getModel().
492 STORM_LOG_THROW(!rewardModel.empty(), storm::exceptions::InvalidPropertyException, "Missing reward model for formula. Skipping formula.");
493
494 // Compute the reward vector to add in each step based on the available reward models.
495 std::vector<ValueType> totalRewardVector = rewardModel.getTotalRewardVector(transitionMatrix);
496
497 // Initialize result to the zero vector.
498 std::vector<SolutionType> result(transitionMatrix.getRowGroupCount(), storm::utility::zero<SolutionType>());
499
500 auto multiplier = storm::solver::MultiplierFactory<SolutionType>().create(env, transitionMatrix);
501 multiplier->repeatedMultiplyWithFactor(env, result, &totalRewardVector, stepBound, discountFactor);
502
503 return result;
504 }
505}
506
507template<>
512 storm::models::sparse::StandardRewardModel<storm::RationalFunction> const& rewardModel, bool qualitative, storm::RationalFunction discountFactor,
513 ModelCheckerHint const& hint) {
514 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "The specified property is not supported by this value type.");
515 return {};
516}
517
518template<typename ValueType, typename RewardModelType, typename SolutionType>
521 storm::storage::SparseMatrix<ValueType> const& backwardTransitions, RewardModelType const& rewardModel, bool qualitative, ValueType discountFactor,
522 ModelCheckerHint const& hint) {
523 if constexpr (storm::IsIntervalType<ValueType>) {
524 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "We do not support discounted total rewards with interval models.");
525 } else {
526 // If the solver is set to force exact results, throw an error if the method is not explicitly set to a value iteration type.
527 STORM_LOG_THROW(!env.solver().isForceExact(), storm::exceptions::NotSupportedException,
528 "Exact solving of discounted total reward objectives is currently not supported.");
529
530 // Reduce to reachability rewards
531 std::vector<ValueType> b;
532
533 std::vector<ValueType> x = std::vector<ValueType>(transitionMatrix.getRowGroupCount(), storm::utility::zero<ValueType>());
534 b = rewardModel.getTotalRewardVector(transitionMatrix);
535 storm::modelchecker::helper::DiscountingHelper<SolutionType, true> discountingHelper(transitionMatrix, discountFactor);
536 discountingHelper.solveWithDiscountedValueIteration(env, std::nullopt, x, b);
537 return std::vector<SolutionType>(std::move(x));
538 }
539}
540
541template<typename ValueType, typename RewardModelType, typename SolutionType>
545 storm::storage::SparseMatrix<ValueType> const& backwardTransitions, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates,
546 bool qualitative, ModelCheckerHint const& hint) {
548 env, std::move(goal), transitionMatrix, backwardTransitions,
549 [&](uint_fast64_t numberOfRows, storm::storage::SparseMatrix<ValueType> const& transitionMatrix, storm::storage::BitVector const& maybeStates) {
550 return rewardModel.getTotalRewardVector(numberOfRows, transitionMatrix, maybeStates);
551 },
552 targetStates, qualitative, [&]() { return rewardModel.getStatesWithZeroReward(transitionMatrix); }, hint);
553}
554
555template<typename ValueType, typename RewardModelType, typename SolutionType>
559 storm::storage::SparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& totalStateRewardVector,
560 storm::storage::BitVector const& targetStates, bool qualitative, ModelCheckerHint const& hint) {
562 env, std::move(goal), transitionMatrix, backwardTransitions,
563 [&](uint_fast64_t numberOfRows, storm::storage::SparseMatrix<ValueType> const&, storm::storage::BitVector const& maybeStates) {
564 std::vector<ValueType> result(numberOfRows, storm::utility::zero<ValueType>());
565 storm::utility::vector::selectVectorValues(result, maybeStates, totalStateRewardVector);
566 return result;
567 },
568 targetStates, qualitative, [&]() { return storm::utility::vector::filterZero(totalStateRewardVector); }, hint);
569}
570
571template<typename ValueType, typename RewardModelType, typename SolutionType>
575 storm::storage::SparseMatrix<ValueType> const& transitionMatrix,
576 storm::storage::SparseMatrix<ValueType> const& backwardTransitions,
577 storm::storage::BitVector const& targetStates, bool qualitative,
578 ModelCheckerHint const& hint) {
580 env, std::move(goal), transitionMatrix, backwardTransitions,
581 [&](uint_fast64_t numberOfRows, storm::storage::SparseMatrix<ValueType> const&, storm::storage::BitVector const&) {
582 return std::vector<ValueType>(numberOfRows, storm::utility::one<ValueType>());
583 },
584 targetStates, qualitative, [&]() { return storm::storage::BitVector(transitionMatrix.getRowGroupCount(), false); }, hint);
585}
586
587// This function computes an upper bound on the reachability rewards (see Baier et al, CAV'17).
588template<typename ValueType, typename SolutionType>
589std::vector<SolutionType> computeUpperRewardBounds(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<ValueType> const& rewards,
590 std::vector<SolutionType> const& oneStepTargetProbabilities) {
591 if constexpr (storm::IsIntervalType<ValueType>) {
592 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "We do not support computing upper reward bounds with interval models.");
593 } else {
594 DsMpiDtmcUpperRewardBoundsComputer<ValueType> dsmpi(transitionMatrix, rewards, oneStepTargetProbabilities);
595 std::vector<ValueType> bounds = dsmpi.computeUpperBounds();
596 return bounds;
597 }
598}
599
600template<>
601std::vector<storm::RationalFunction> computeUpperRewardBounds(storm::storage::SparseMatrix<storm::RationalFunction> const& /*transitionMatrix*/,
602 std::vector<storm::RationalFunction> const& /*rewards*/,
603 std::vector<storm::RationalFunction> const& /*oneStepTargetProbabilities*/) {
604 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Computing upper reward bounds is not supported for rational functions.");
605}
606
607template<typename ValueType, typename RewardModelType, typename SolutionType>
608DTMCSparseModelCheckingHelperReturnType<typename SparseDtmcPrctlHelper<ValueType, RewardModelType, SolutionType>::ExtendedSolutionType>
611 storm::storage::SparseMatrix<ValueType> const& backwardTransitions,
612 std::function<std::vector<ValueType>(uint_fast64_t, storm::storage::SparseMatrix<ValueType> const&, storm::storage::BitVector const&)> const&
613 totalStateRewardVectorGetter,
614 storm::storage::BitVector const& targetStates, bool qualitative, std::function<storm::storage::BitVector()> const& zeroRewardStatesGetter,
615 ModelCheckerHint const& hint) {
616 std::vector<ExtendedSolutionType> result(transitionMatrix.getRowCount(), storm::utility::zero<ExtendedSolutionType>());
618
619 // Determine which states have reward zero
620 storm::storage::BitVector rew0States;
621 if (env.modelchecker().isFilterRewZeroSet()) {
622 rew0States = storm::utility::graph::performProb1(backwardTransitions, zeroRewardStatesGetter(), targetStates);
623 } else {
624 rew0States = targetStates;
625 }
626
627 // Determine which states have a reward that is less than infinity.
628 storm::storage::BitVector maybeStates;
629 if (hint.isExplicitModelCheckerHint() && hint.template asExplicitModelCheckerHint<ValueType>().getComputeOnlyMaybeStates()) {
630 maybeStates = hint.template asExplicitModelCheckerHint<ValueType>().getMaybeStates();
632
633 STORM_LOG_INFO("Preprocessing: " << rew0States.getNumberOfSetBits() << " States with reward zero (" << maybeStates.getNumberOfSetBits()
634 << " states remaining).");
635 } else {
636 storm::storage::BitVector trueStates(transitionMatrix.getRowCount(), true);
637 storm::storage::BitVector infinityStates = storm::utility::graph::performProb1(backwardTransitions, trueStates, rew0States);
638 infinityStates.complement();
639 maybeStates = ~(rew0States | infinityStates);
640
641 STORM_LOG_INFO("Preprocessing: " << infinityStates.getNumberOfSetBits() << " states with reward infinity, " << rew0States.getNumberOfSetBits()
642 << " states with reward zero (" << maybeStates.getNumberOfSetBits() << " states remaining).");
643
645 }
646
647 // Check if the values of the maybe states are relevant for the SolveGoal
648 bool maybeStatesNotRelevant = goal.hasRelevantValues() && goal.relevantValues().isDisjointFrom(maybeStates);
649
650 // Check whether we need to compute exact rewards for some states.
651 if (qualitative || maybeStatesNotRelevant) {
652 // Set the values for all maybe-states to 1 to indicate that their reward values
653 // are neither 0 nor infinity.
655 } else {
656 if (!maybeStates.empty()) {
657 if constexpr (storm::IsIntervalType<ValueType>) {
658 // In this case we have to compute the reward values for the remaining states.
659 // We can eliminate the rows and columns from the original transition probability matrix.
660 storm::storage::SparseMatrix<ValueType> submatrix = transitionMatrix.filterEntries(transitionMatrix.getRowFilter(maybeStates));
661
662 // Prepare the right-hand side of the equation system.
663 // The system keeps the rows of all states, so b must be indexed by the rows of the original matrix. We compute the rewards for all
664 // states and set the entries of non-maybe states to zero.
665 std::vector<ValueType> b = totalStateRewardVectorGetter(submatrix.getRowCount(), transitionMatrix,
666 storm::storage::BitVector(transitionMatrix.getRowGroupCount(), true));
668
669 // Compute values for maybe states.
670 storm::solver::SolutionBounds<SolutionType> boundsForMaybeStates;
671 std::vector<SolutionType> x = computeRobustValuesForMaybeStates(env, std::move(goal), std::move(submatrix), b, true, boundsForMaybeStates);
672
673 // The copy of result supplies the exact values outside the maybe states.
674 auto embedBound = [&result, &maybeStates](std::vector<SolutionType> const& boundForMaybeStates) {
675 std::vector<ExtendedSolutionType> bound(result);
676 storm::utility::vector::setVectorValues(bound, maybeStates, boundForMaybeStates);
677 return bound;
678 };
679 solutionBounds = boundsForMaybeStates.transform(embedBound);
680
681 // The solution has an entry for every state. We only take the values of the maybe states.
682 STORM_LOG_ASSERT(x.size() == transitionMatrix.getColumnCount(), "Dimensions do not match.");
683 for (auto const state : maybeStates) {
684 result[state] = x[state];
685 }
686 } else {
687 // Check whether we need to convert the input to equation system format.
688 storm::solver::GeneralLinearEquationSolverFactory<ValueType> linearEquationSolverFactory;
689 bool convertToEquationSystem =
691
692 // In this case we have to compute the reward values for the remaining states.
693 // We can eliminate the rows and columns from the original transition probability matrix.
694 storm::storage::SparseMatrix<ValueType> submatrix = transitionMatrix.getSubmatrix(true, maybeStates, maybeStates, convertToEquationSystem);
695
696 // Initialize the x vector with the hint (if available) or with 1 for each element.
697 // This is the initial guess for the iterative solvers.
698 std::vector<ValueType> x;
699 if (hint.isExplicitModelCheckerHint() && hint.template asExplicitModelCheckerHint<ValueType>().hasResultHint()) {
701 storm::utility::vector::filterVector(hint.template asExplicitModelCheckerHint<ValueType>().getResultHint(), maybeStates),
703 } else {
704 x = std::vector<ValueType>(submatrix.getColumnCount(), storm::utility::one<ValueType>());
705 }
706
707 // Prepare the right-hand side of the equation system.
708 std::vector<ValueType> b = totalStateRewardVectorGetter(submatrix.getRowCount(), transitionMatrix, maybeStates);
709
710 storm::solver::LinearEquationSolverRequirements requirements = linearEquationSolverFactory.getRequirements(env);
711 boost::optional<std::vector<ValueType>> upperRewardBounds;
712 requirements.clearLowerBounds();
713 if (requirements.upperBounds()) {
714 upperRewardBounds = computeUpperRewardBounds(submatrix, b, transitionMatrix.getConstrainedRowSumVector(maybeStates, rew0States));
715 requirements.clearUpperBounds();
716 }
717 STORM_LOG_THROW(!requirements.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException,
718 "Solver requirements " + requirements.getEnabledRequirementsAsString() + " not checked.");
719
720 // If necessary, convert the matrix from the fixpoint notation to the form needed for the equation system.
721 if (convertToEquationSystem) {
722 // go from x = A*x + b to (I-A)x = b.
723 submatrix.convertToEquationSystem();
724 }
725
726 // Create the solver.
727 goal.restrictRelevantValues(maybeStates);
728 std::unique_ptr<storm::solver::LinearEquationSolver<ValueType>> solver =
729 storm::solver::configureLinearEquationSolver(env, std::move(goal), linearEquationSolverFactory, std::move(submatrix));
730 solver->setLowerBound(storm::utility::zero<ValueType>());
731 if (upperRewardBounds) {
732 solver->setUpperBounds(std::move(upperRewardBounds.get()));
733 }
734
735 // Now solve the resulting equation system.
736 solver->solveEquations(env, x, b);
737
738 // The copy of result supplies the exact values outside the maybe states.
739 auto embedBound = [&result, &maybeStates](std::vector<ValueType> const& boundForMaybeStates) {
740 std::vector<ExtendedSolutionType> bound(result);
741 storm::utility::vector::setVectorValues(bound, maybeStates, boundForMaybeStates);
742 return bound;
743 };
744 solutionBounds = solver->getSolutionBounds().transform(embedBound);
745
746 // Set values of resulting vector according to result.
747 storm::utility::vector::setVectorValues(result, maybeStates, x);
748 }
749 }
750 }
751 if (maybeStates.empty()) {
752 // The qualitative precomputation already decided every state, so all values are exact.
753 solutionBounds.setExact(result);
754 }
756 returnValue.solutionBounds = std::move(solutionBounds);
757 return returnValue;
758}
759
760template<typename ValueType, typename RewardModelType, typename SolutionType>
761typename SparseDtmcPrctlHelper<ValueType, RewardModelType, SolutionType>::BaierTransformedModel
762SparseDtmcPrctlHelper<ValueType, RewardModelType, SolutionType>::computeBaierTransformation(Environment const& env,
763 storm::storage::SparseMatrix<ValueType> const& transitionMatrix,
764 storm::storage::SparseMatrix<ValueType> const& backwardTransitions,
765 storm::storage::BitVector const& targetStates,
766 storm::storage::BitVector const& conditionStates,
767 boost::optional<std::vector<ValueType>> const& stateRewards) {
768 if constexpr (storm::IsIntervalType<ValueType>) {
769 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "We do not support baier transformation with interval models.");
770 } else {
771 BaierTransformedModel result;
772
773 // Start by computing all 'before' states, i.e. the states for which the conditional probability is defined.
774 std::vector<ValueType> probabilitiesToReachConditionStates =
775 computeUntilProbabilities(env, storm::solver::SolveGoal<ValueType>(), transitionMatrix, backwardTransitions,
776 storm::storage::BitVector(transitionMatrix.getRowCount(), true), conditionStates, false)
777 .values;
778
779 result.beforeStates = storm::storage::BitVector(targetStates.size(), true);
780 uint_fast64_t state = 0;
781 uint_fast64_t beforeStateIndex = 0;
782 for (auto const& value : probabilitiesToReachConditionStates) {
783 if (value == storm::utility::zero<ValueType>()) {
784 result.beforeStates.set(state, false);
785 } else {
786 probabilitiesToReachConditionStates[beforeStateIndex] = value;
787 ++beforeStateIndex;
788 }
789 ++state;
790 }
791 probabilitiesToReachConditionStates.resize(beforeStateIndex);
792
793 if (targetStates.empty()) {
794 result.noTargetStates = true;
795 return result;
796 } else if (!result.beforeStates.empty()) {
797 // If there are some states for which the conditional probability is defined and there are some
798 // states that can reach the target states without visiting condition states first, we need to
799 // do more work.
800
801 // First, compute the relevant states and some offsets.
802 storm::storage::BitVector allStates(targetStates.size(), true);
803 std::vector<uint_fast64_t> numberOfBeforeStatesUpToState = result.beforeStates.getNumberOfSetBitsBeforeIndices();
804 storm::storage::BitVector statesWithProbabilityGreater0 = storm::utility::graph::performProbGreater0(backwardTransitions, allStates, targetStates);
805 statesWithProbabilityGreater0 &= storm::utility::graph::getReachableStates(transitionMatrix, conditionStates, allStates, targetStates);
806 uint_fast64_t normalStatesOffset = result.beforeStates.getNumberOfSetBits();
807 std::vector<uint_fast64_t> numberOfNormalStatesUpToState = statesWithProbabilityGreater0.getNumberOfSetBitsBeforeIndices();
808
809 // All transitions going to states with probability zero, need to be redirected to a deadlock state.
810 bool addDeadlockState = false;
811 uint_fast64_t deadlockState = normalStatesOffset + statesWithProbabilityGreater0.getNumberOfSetBits();
812
813 // Now, we create the matrix of 'before' and 'normal' states.
814 storm::storage::SparseMatrixBuilder<ValueType> builder;
815
816 // Start by creating the transitions of the 'before' states.
817 uint_fast64_t currentRow = 0;
818 for (auto beforeState : result.beforeStates) {
819 if (conditionStates.get(beforeState)) {
820 // For condition states, we move to the 'normal' states.
821 ValueType zeroProbability = storm::utility::zero<ValueType>();
822 for (auto const& successorEntry : transitionMatrix.getRow(beforeState)) {
823 if (statesWithProbabilityGreater0.get(successorEntry.getColumn())) {
824 builder.addNextValue(currentRow, normalStatesOffset + numberOfNormalStatesUpToState[successorEntry.getColumn()],
825 successorEntry.getValue());
826 } else {
827 zeroProbability += successorEntry.getValue();
828 }
829 }
830 if (!storm::utility::isZero(zeroProbability)) {
831 builder.addNextValue(currentRow, deadlockState, zeroProbability);
832 }
833 } else {
834 // For non-condition states, we scale the probabilities going to other before states.
835 for (auto const& successorEntry : transitionMatrix.getRow(beforeState)) {
836 if (result.beforeStates.get(successorEntry.getColumn())) {
837 builder.addNextValue(currentRow, numberOfBeforeStatesUpToState[successorEntry.getColumn()],
838 successorEntry.getValue() *
839 probabilitiesToReachConditionStates[numberOfBeforeStatesUpToState[successorEntry.getColumn()]] /
840 probabilitiesToReachConditionStates[currentRow]);
841 }
842 }
843 }
844 ++currentRow;
845 }
846
847 // Then, create the transitions of the 'normal' states.
848 for (uint64_t state : statesWithProbabilityGreater0) {
849 ValueType zeroProbability = storm::utility::zero<ValueType>();
850 for (auto const& successorEntry : transitionMatrix.getRow(state)) {
851 if (statesWithProbabilityGreater0.get(successorEntry.getColumn())) {
852 builder.addNextValue(currentRow, normalStatesOffset + numberOfNormalStatesUpToState[successorEntry.getColumn()],
853 successorEntry.getValue());
854 } else {
855 zeroProbability += successorEntry.getValue();
856 }
857 }
858 if (!storm::utility::isZero(zeroProbability)) {
859 addDeadlockState = true;
860 builder.addNextValue(currentRow, deadlockState, zeroProbability);
861 }
862 ++currentRow;
863 }
864 if (addDeadlockState) {
865 builder.addNextValue(deadlockState, deadlockState, storm::utility::one<ValueType>());
866 }
867
868 // Build the new transition matrix and the new targets.
869 result.transitionMatrix = builder.build(addDeadlockState ? (deadlockState + 1) : deadlockState);
870 storm::storage::BitVector newTargetStates = targetStates % result.beforeStates;
871 newTargetStates.resize(result.transitionMatrix.get().getRowCount());
872 for (uint64_t state : targetStates % statesWithProbabilityGreater0) {
873 newTargetStates.set(normalStatesOffset + state, true);
874 }
875 result.targetStates = std::move(newTargetStates);
876
877 // If a reward model was given, we need to compute the rewards for the transformed model.
878 if (stateRewards) {
879 std::vector<ValueType> newStateRewards(result.beforeStates.getNumberOfSetBits());
880 storm::utility::vector::selectVectorValues(newStateRewards, result.beforeStates, stateRewards.get());
881
882 newStateRewards.reserve(result.transitionMatrix.get().getRowCount());
883 for (uint64_t state : statesWithProbabilityGreater0) {
884 newStateRewards.push_back(stateRewards.get()[state]);
885 }
886 // Add a zero reward to the deadlock state.
887 if (addDeadlockState) {
888 newStateRewards.push_back(storm::utility::zero<ValueType>());
889 }
890 result.stateRewards = std::move(newStateRewards);
891 }
892 }
893
894 return result;
895 }
896}
897
898template<typename ValueType, typename RewardModelType, typename SolutionType>
899storm::storage::BitVector SparseDtmcPrctlHelper<ValueType, RewardModelType, SolutionType>::BaierTransformedModel::getNewRelevantStates() const {
900 storm::storage::BitVector newRelevantStates(transitionMatrix.get().getRowCount());
901 for (uint64_t i = 0; i < this->beforeStates.getNumberOfSetBits(); ++i) {
902 newRelevantStates.set(i);
903 }
904 return newRelevantStates;
905}
906
907template<typename ValueType, typename RewardModelType, typename SolutionType>
908storm::storage::BitVector SparseDtmcPrctlHelper<ValueType, RewardModelType, SolutionType>::BaierTransformedModel::getNewRelevantStates(
909 storm::storage::BitVector const& oldRelevantStates) const {
910 storm::storage::BitVector result = oldRelevantStates % this->beforeStates;
911 result.resize(transitionMatrix.get().getRowCount());
912 return result;
913}
914
915template<typename ValueType, typename RewardModelType, typename SolutionType>
916std::vector<typename SparseDtmcPrctlHelper<ValueType, RewardModelType, SolutionType>::ExtendedSolutionType>
919 storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& targetStates,
920 storm::storage::BitVector const& conditionStates, bool qualitative) {
921 if constexpr (storm::IsIntervalType<ValueType>) {
922 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "We do not support computing conditional probabilities with interval models.");
923 } else {
924 // The conditional value is only defined for states that reach the condition with positive probability.
925 storm::storage::BitVector const conditionProbGreater0States =
926 storm::utility::graph::performProbGreater0(backwardTransitions, storm::storage::BitVector(conditionStates.size(), true), conditionStates);
927 STORM_LOG_THROW(goal.hasRelevantValues() ? goal.relevantValues().isSubsetOf(conditionProbGreater0States) : !conditionProbGreater0States.empty(),
928 storm::exceptions::InvalidPropertyException, "Trying to compute an undefined conditional value: the condition is not reachable.");
929
930 // Prepare result vector.
931 std::vector<ExtendedSolutionType> result(transitionMatrix.getRowCount(), storm::utility::positiveInfinity<SolutionType>());
932
933 BaierTransformedModel transformedModel =
934 computeBaierTransformation(env, transitionMatrix, backwardTransitions, targetStates, conditionStates, boost::none);
935
936 if (transformedModel.noTargetStates) {
937 storm::utility::vector::setVectorValues(result, transformedModel.beforeStates, storm::utility::zero<ValueType>());
938 } else {
939 // At this point, we do not need to check whether there are 'before' states, since the condition
940 // states were non-empty so there is at least one state with a positive probability of satisfying
941 // the condition.
942
943 // Now compute reachability probabilities in the transformed model.
944 storm::storage::SparseMatrix<ValueType> const& newTransitionMatrix = transformedModel.transitionMatrix.get();
945 storm::storage::BitVector newRelevantValues;
946 if (goal.hasRelevantValues()) {
947 newRelevantValues = transformedModel.getNewRelevantStates(goal.relevantValues());
948 } else {
949 newRelevantValues = transformedModel.getNewRelevantStates();
950 }
951 goal.setRelevantValues(std::move(newRelevantValues));
952 std::vector<ValueType> conditionalProbabilities =
953 computeUntilProbabilities(env, std::move(goal), newTransitionMatrix, newTransitionMatrix.transpose(),
954 storm::storage::BitVector(newTransitionMatrix.getRowCount(), true), transformedModel.targetStates.get(), qualitative)
955 .values;
956
957 storm::utility::vector::setVectorValues(result, transformedModel.beforeStates, conditionalProbabilities);
958 }
959
960 return result;
961 }
962}
963
964template<typename ValueType, typename RewardModelType, typename SolutionType>
965std::vector<typename SparseDtmcPrctlHelper<ValueType, RewardModelType, SolutionType>::ExtendedSolutionType>
968 storm::storage::SparseMatrix<ValueType> const& backwardTransitions, RewardModelType const& rewardModel, storm::storage::BitVector const& targetStates,
969 storm::storage::BitVector const& conditionStates, bool qualitative) {
970 if constexpr (storm::IsIntervalType<ValueType>) {
971 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "We do not support computing conditional rewards with interval models.");
972 } else {
973 // The conditional value is only defined for states that reach the condition with positive probability.
974 storm::storage::BitVector const conditionProbGreater0States =
975 storm::utility::graph::performProbGreater0(backwardTransitions, storm::storage::BitVector(conditionStates.size(), true), conditionStates);
976 STORM_LOG_THROW(goal.hasRelevantValues() ? goal.relevantValues().isSubsetOf(conditionProbGreater0States) : !conditionProbGreater0States.empty(),
977 storm::exceptions::InvalidPropertyException, "Trying to compute an undefined conditional value: the condition is not reachable.");
978
979 // Prepare result vector.
980 std::vector<ExtendedSolutionType> result(transitionMatrix.getRowCount(), storm::utility::positiveInfinity<SolutionType>());
981
982 BaierTransformedModel transformedModel = computeBaierTransformation(env, transitionMatrix, backwardTransitions, targetStates, conditionStates,
983 rewardModel.getTotalRewardVector(transitionMatrix));
984
985 if (transformedModel.noTargetStates) {
986 storm::utility::vector::setVectorValues(result, transformedModel.beforeStates, storm::utility::zero<ValueType>());
987 } else {
988 // At this point, we do not need to check whether there are 'before' states, since the condition
989 // states were non-empty so there is at least one state with a positive probability of satisfying
990 // the condition.
991
992 // Now compute reachability probabilities in the transformed model.
993 storm::storage::SparseMatrix<ValueType> const& newTransitionMatrix = transformedModel.transitionMatrix.get();
994 storm::storage::BitVector newRelevantValues;
995 if (goal.hasRelevantValues()) {
996 newRelevantValues = transformedModel.getNewRelevantStates(goal.relevantValues());
997 } else {
998 newRelevantValues = transformedModel.getNewRelevantStates();
999 }
1000 goal.setRelevantValues(std::move(newRelevantValues));
1001 std::vector<ExtendedSolutionType> conditionalRewards =
1002 computeReachabilityRewards(env, std::move(goal), newTransitionMatrix, newTransitionMatrix.transpose(), transformedModel.stateRewards.get(),
1003 transformedModel.targetStates.get(), qualitative)
1004 .values;
1005 storm::utility::vector::setVectorValues(result, transformedModel.beforeStates, conditionalRewards);
1006 }
1007
1008 return result;
1009 }
1010}
1011
1012template class SparseDtmcPrctlHelper<double>;
1013
1018} // namespace helper
1019} // namespace modelchecker
1020} // namespace storm
SolverEnvironment & solver()
ModelCheckerEnvironment & modelchecker()
std::string const & getExportCdfDirectory() const
storm::solver::EquationSolverType const & getLinearEquationSolverType() const
void setLinearEquationSolverPrecision(boost::optional< storm::RationalNumber > const &newPrecision, boost::optional< bool > const &relativePrecision=boost::none)
uint64_t getShowProgressDelay() const
std::pair< boost::optional< storm::RationalNumber >, boost::optional< bool > > getPrecisionOfLinearEquationSolver(storm::solver::EquationSolverType const &solverType) const
This class contains information that might accelerate the model checking process.
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.
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)
static DTMCSparseModelCheckingHelperReturnType< ExtendedSolutionType > 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, ModelCheckerHint const &hint=ModelCheckerHint())
static std::vector< SolutionType > 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, ValueType discountFactor, ModelCheckerHint const &hint=ModelCheckerHint())
static std::vector< SolutionType > computeRewardBoundedValues(Environment const &env, storm::models::sparse::Dtmc< ValueType > const &model, std::shared_ptr< storm::logic::OperatorFormula const > rewardBoundedFormula)
static std::vector< SolutionType > computeAllUntilProbabilities(Environment const &env, storm::solver::SolveGoal< ValueType, SolutionType > &&goal, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::BitVector const &initialStates, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates)
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 > computeInstantaneousRewards(Environment const &env, storm::solver::SolveGoal< ValueType, SolutionType > &&goal, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, RewardModelType const &rewardModel, uint_fast64_t stepCount)
static DTMCSparseModelCheckingHelperReturnType< ExtendedSolutionType > 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, ModelCheckerHint const &hint=ModelCheckerHint())
static std::vector< ExtendedSolutionType > computeConditionalProbabilities(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, storm::storage::BitVector const &conditionStates, bool qualitative)
static std::vector< SolutionType > computeNextProbabilities(Environment const &env, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::BitVector const &nextStates)
static DTMCSparseModelCheckingHelperReturnType< ExtendedSolutionType > 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, ModelCheckerHint const &hint=ModelCheckerHint())
static DTMCSparseModelCheckingHelperReturnType< 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, ModelCheckerHint const &hint=ModelCheckerHint())
static DTMCSparseModelCheckingHelperReturnType< 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)
static std::vector< ExtendedSolutionType > computeConditionalRewards(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, storm::storage::BitVector const &conditionStates, bool qualitative)
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...
void setEquationSystemFormatForEpochModel(storm::solver::LinearEquationSolverProblemFormat eqSysFormat)
This class represents a discrete-time Markov chain.
Definition Dtmc.h:16
storm::storage::BitVector const & getInitialStates() const
Retrieves the initial states of the model.
Definition Model.cpp:206
LinearEquationSolverRequirements getRequirements(Environment const &env) const
Retrieves the requirements of the solver if it was created with the current settings.
virtual LinearEquationSolverProblemFormat getEquationProblemFormat(Environment const &env) const
Retrieves the problem format that the solver expects if it was created with the current settings.
std::string getEnabledRequirementsAsString() const
Checks whether there are no critical requirements left.
std::unique_ptr< Multiplier< ValueType, SolutionType > > create(Environment const &env, storm::storage::SparseMatrix< ValueType > const &matrix)
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.
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 ...
std::vector< uint64_t > getNumberOfSetBitsBeforeIndices() const
Retrieves a vector that holds at position i the number of bits set before index i.
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.
void resize(uint64_t newLength, bool init=false)
Resizes the bit vector to hold the given new number of bits.
bool get(uint64_t index) const
Retrieves the truth value of the bit at the given index and performs a bound check.
void addNextValue(index_type row, index_type column, value_type const &value)
Sets the matrix entry at the given row and column to the given value.
SparseMatrix< value_type > build(index_type overriddenRowCount=0, index_type overriddenColumnCount=0, index_type overriddenRowGroupCount=0)
A class that holds a possibly non-square matrix in the compressed row storage format.
void convertToEquationSystem()
Transforms the matrix into an equation system.
const_rows getRow(index_type row) const
Returns an object representing the given row.
void makeRowsAbsorbing(storm::storage::BitVector const &rows, bool dropZeroEntries=false)
This function makes the given rows absorbing.
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...
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.
void deleteDiagonalEntries(bool dropZeroEntries=false)
Sets all diagonal elements to zero.
storm::storage::SparseMatrix< value_type > transpose(bool joinGroups=false, bool keepZeros=false) const
Transposes the matrix.
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.
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_STATISTICS(message)
Definition logging.h:48
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:9
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:39
SFTBDDChecker::ValueType ValueType
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
std::vector< SolutionType > computeRobustValuesForMaybeStates(Environment const &env, storm::solver::SolveGoal< ValueType, SolutionType > &&goal, storm::storage::SparseMatrix< ValueType > &&submatrix, std::vector< ValueType > const &b, bool computeReward, storm::solver::SolutionBounds< SolutionType > &solutionBounds)
std::vector< ValueType > computeUpperRewardBounds(storm::storage::SparseMatrix< ValueType > const &transitionMatrix, std::vector< ValueType > const &rewards, std::vector< ValueType > const &oneStepTargetProbabilities)
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
std::unique_ptr< storm::solver::LinearEquationSolver< ValueType > > configureLinearEquationSolver(Environment const &env, SolveGoal< ValueType, SolutionType > &&goal, storm::solver::LinearEquationSolverFactory< ValueType > const &factory, MatrixType &&matrix)
std::pair< storm::storage::BitVector, storm::storage::BitVector > performProb01(storm::models::sparse::DeterministicModel< T > const &model, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates)
Computes the sets of states that have probability 0 or 1, respectively, of satisfying phi until psi i...
Definition graph.cpp:394
storm::storage::BitVector getReachableStates(storm::storage::SparseMatrix< T > const &transitionMatrix, storm::storage::BitVector const &initialStates, storm::storage::BitVector const &constraintStates, storm::storage::BitVector const &targetStates, bool useStepBound, uint_fast64_t maximalSteps, boost::optional< storm::storage::BitVector > const &choiceFilter)
Performs a forward depth-first search through the underlying graph structure to identify the states t...
Definition graph.cpp:42
storm::storage::BitVector performProbGreater0(storm::storage::SparseMatrix< T > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates, bool useStepBound, uint_fast64_t maximalSteps)
Performs a backward depth-first search trough the underlying graph structure of the given model to de...
Definition graph.cpp:316
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
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
storm::storage::BitVector filterZero(std::vector< T > const &values)
Retrieves a bit vector containing all the indices for which the value at this position is equal to ze...
Definition vector.h:520
void subtractFromConstantOneVector(std::vector< T > &vector)
Subtracts the given vector from the constant one-vector and writes the result to the input vector.
Definition vector.h:278
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
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
TargetType convertNumber(SourceType const &number)
constexpr bool IsIntervalType
Helper to check if a type is an interval.
carl::RationalFunction< Polynomial, true > RationalFunction
The outcome of a quantitative model checking query on a sparse DTMC.
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.