Storm 1.14.0.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
SparseMarkovAutomatonCslHelper.cpp
Go to the documentation of this file.
2
24#include "storm/utility/graph.h"
27
28namespace storm {
29namespace modelchecker {
30namespace helper {
31
32template<typename ValueType>
33std::unique_ptr<storm::solver::MinMaxLinearEquationSolver<ValueType>> setUpProbabilisticStatesSolver(
35 std::unique_ptr<storm::solver::MinMaxLinearEquationSolver<ValueType>> solver;
36 // The min-max system has no end components as we assume non-zeno MAs.
37 if (transitions.getNonzeroEntryCount() > 0) {
39 bool isAcyclic = !storm::utility::graph::hasCycle(transitions);
40 if (isAcyclic) {
41 env.solver().minMax().setMethod(storm::solver::MinMaxMethod::Acyclic);
42 }
43 solver = factory.create(env, transitions);
44 solver->setHasUniqueSolution(true); // Assume non-zeno MA
45 solver->setHasNoEndComponents(true); // assume non-zeno MA
47 solver->setUpperBound(storm::utility::one<ValueType>());
48 solver->setCachingEnabled(true);
49 solver->setRequirementsChecked(true);
50 auto req = solver->getRequirements(env, dir);
51 req.clearBounds();
52 req.clearUniqueSolution();
53 if (isAcyclic) {
54 req.clearAcyclic();
55 }
56 STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException,
57 "The solver requirement " << req.getEnabledRequirementsAsString() << " has not been checked.");
58 }
59 return solver;
60}
61
62template<typename ValueType>
64 public:
65 UnifPlusHelper(storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<ValueType> const& exitRateVector,
66 storm::storage::BitVector const& markovianStates)
67 : transitionMatrix(transitionMatrix), exitRateVector(exitRateVector), markovianStates(markovianStates) {
68 // Intentionally left empty
69 }
70
72 storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates,
73 std::optional<ValueType> const& upperTimeBound,
74 boost::optional<storm::storage::BitVector> const& relevantStates = boost::none) {
75 // Since there is no lower time bound, we can treat the psiStates as if they are absorbing.
76
77 // Compute some important subsets of states
78 storm::storage::BitVector maybeStates = ~(getProb0States(dir, phiStates, psiStates) | psiStates);
79 storm::storage::BitVector markovianMaybeStates = markovianStates & maybeStates;
80 storm::storage::BitVector probabilisticMaybeStates = ~markovianStates & maybeStates;
81 storm::storage::BitVector markovianStatesModMaybeStates = markovianMaybeStates % maybeStates;
82 storm::storage::BitVector probabilisticStatesModMaybeStates = probabilisticMaybeStates % maybeStates;
83 // Catch the case where this query can be solved by solving the untimed variant instead.
84 // This is the case if there is no Markovian maybe state (e.g. if the initial state is already a psi state) or if there is no time bound.
85 if (markovianMaybeStates.empty() || !upperTimeBound) {
86 return SparseMarkovAutomatonCslHelper::computeUntilProbabilities<ValueType>(env, dir, transitionMatrix, transitionMatrix.transpose(true), phiStates,
87 psiStates, false, false)
88 .values;
89 }
90
91 boost::optional<storm::storage::BitVector> relevantMaybeStates;
92 storm::storage::BitVector relevantMarkovianMaybeStates;
93 if (relevantStates) {
94 if (!relevantStates->isSubsetOf(markovianStates)) {
95 // Enhance the relevant states to also include Markovian states that are reachable in zero time from relevant probabilistic states
96 auto const enhancedRelevantStates =
97 storm::utility::graph::getReachableStates(transitionMatrix, *relevantStates, ~markovianStates, markovianStates);
98 relevantMaybeStates = enhancedRelevantStates % maybeStates;
99 } else {
100 relevantMaybeStates = relevantStates.get() % maybeStates;
101 }
102 relevantMarkovianMaybeStates = relevantMaybeStates.get() & markovianStatesModMaybeStates;
103 } else {
104 relevantMarkovianMaybeStates = markovianStatesModMaybeStates;
105 }
106 // Store the best solution known so far (useful in cases where the computation gets aborted)
107 std::vector<ValueType> bestKnownSolution;
108 if (relevantMaybeStates) {
109 bestKnownSolution.resize(relevantMaybeStates->getNumberOfSetBits());
110 }
111
112 // Get the exit rates restricted to only markovian maybe states.
113 std::vector<ValueType> markovianExitRates = storm::utility::vector::filterVector(exitRateVector, markovianMaybeStates);
114
115 // Obtain parameters of the algorithm
117 // Truncation error
119 // Precision to be achieved
120 ValueType epsilon = two * storm::utility::convertNumber<ValueType>(env.solver().timeBounded().getPrecision());
121 bool relativePrecision = env.solver().timeBounded().getRelativeTerminationCriterion();
122 // Uniformization rate
123 ValueType lambda = *std::max_element(markovianExitRates.begin(), markovianExitRates.end());
124 STORM_LOG_DEBUG("Initial lambda is " << lambda << ".");
125
126 // Split the transitions into various part
127 // The (uniformized) probabilities to go from a Markovian state to a psi state in one step
128 std::vector<std::pair<uint64_t, ValueType>> markovianToPsiProbabilities = getSparseOneStepProbabilities(markovianMaybeStates, psiStates);
129 for (auto& entry : markovianToPsiProbabilities) {
130 entry.second *= markovianExitRates[entry.first] / lambda;
131 }
132 // Uniformized transitions from Markovian maybe states to all other maybe states. Inserts selfloop entries.
133 storm::storage::SparseMatrix<ValueType> markovianToMaybeTransitions =
134 getUniformizedMarkovianTransitions(markovianExitRates, lambda, maybeStates, markovianMaybeStates);
135 // Transitions from probabilistic maybe states to probabilistic maybe states.
136 storm::storage::SparseMatrix<ValueType> probabilisticToProbabilisticTransitions =
137 transitionMatrix.getSubmatrix(true, probabilisticMaybeStates, probabilisticMaybeStates, false);
138 // Transitions from probabilistic maybe states to Markovian maybe states.
139 storm::storage::SparseMatrix<ValueType> probabilisticToMarkovianTransitions =
140 transitionMatrix.getSubmatrix(true, probabilisticMaybeStates, markovianMaybeStates, false);
141 // The probabilities to go from a probabilistic state to a psi state in one step
142 std::vector<std::pair<uint64_t, ValueType>> probabilisticToPsiProbabilities = getSparseOneStepProbabilities(probabilisticMaybeStates, psiStates);
143
144 // Set up a solver for the transitions between probabilistic states (if there are some)
145 Environment solverEnv = env;
146 solverEnv.solver().setForceExact(true); // Errors within the inner iterations can propagate significantly
147 auto solver = setUpProbabilisticStatesSolver(solverEnv, dir, probabilisticToProbabilisticTransitions);
148
149 // Allocate auxiliary memory that can be used during the iterations
150 std::vector<ValueType> maybeStatesValuesLower(maybeStates.getNumberOfSetBits(), storm::utility::zero<ValueType>()); // should be zero initially
151 std::vector<ValueType> maybeStatesValuesWeightedUpper(maybeStates.getNumberOfSetBits(), storm::utility::zero<ValueType>()); // should be zero initially
152 std::vector<ValueType> maybeStatesValuesUpper(maybeStates.getNumberOfSetBits(), storm::utility::zero<ValueType>()); // should be zero initially
153 std::vector<ValueType> nextMarkovianStateValues = std::move(
154 markovianExitRates); // At this point, the markovianExitRates are no longer needed, so we 'move' them away instead of allocating new memory
155 std::vector<ValueType> nextProbabilisticStateValues(probabilisticToProbabilisticTransitions.getRowGroupCount());
156 std::vector<ValueType> eqSysRhs(probabilisticToProbabilisticTransitions.getRowCount());
157
158 // Start the outer iterations which increase the uniformization rate until lower and upper bound on the result vector is sufficiently small
159 storm::utility::ProgressMeasurement progressIterations("iterations", env.solver().getShowProgressDelay());
160 uint64_t iteration = 0;
161 progressIterations.startNewMeasurement(iteration);
162 bool converged = false;
163 bool abortedInnerIterations = false;
164 while (!converged) {
165 // Maximal step size
166 uint64_t N = storm::utility::ceil(lambda * *upperTimeBound * std::exp(2) - storm::utility::log(kappa * epsilon));
167 // Compute poisson distribution.
168 // The division by 8 is similar to what is done for CTMCs (probably to reduce numerical impacts?)
169 auto foxGlynnResult =
170 storm::utility::numerical::foxGlynn(lambda * *upperTimeBound, epsilon * kappa / storm::utility::convertNumber<ValueType>(8.0));
171 // Scale the weights so they sum to one.
172 // storm::utility::vector::scaleVectorInPlace(foxGlynnResult.weights, storm::utility::one<ValueType>() / foxGlynnResult.totalWeight);
173
174 // Set up multiplier
175 auto markovianToMaybeMultiplier = storm::solver::MultiplierFactory<ValueType>().create(env, markovianToMaybeTransitions);
176 auto probabilisticToMarkovianMultiplier = storm::solver::MultiplierFactory<ValueType>().create(env, probabilisticToMarkovianTransitions);
177
178 // Perform inner iterations first for upper, then for lower bound
179 STORM_LOG_ASSERT(!storm::utility::vector::hasNonZeroEntry(maybeStatesValuesUpper), "Current values need to be initialized with zero.");
180 for (bool computeLowerBound : {false, true}) {
181 auto& maybeStatesValues = computeLowerBound ? maybeStatesValuesLower : maybeStatesValuesWeightedUpper;
182 ValueType targetValue = computeLowerBound ? storm::utility::zero<ValueType>() : storm::utility::one<ValueType>();
184 "steps in iteration " + std::to_string(iteration) + " for " + std::string(computeLowerBound ? "lower" : "upper") + " bounds.",
186 progressSteps.setMaxCount(N);
187 progressSteps.startNewMeasurement(0);
188 bool firstIteration = true; // The first iterations can be irrelevant, because they will only produce zeroes anyway.
189 int64_t k = N;
190 // Iteration k = N is always non-relevant
191 for (--k; k >= 0; --k) {
192 // Check whether the iteration is relevant, that is, whether it will contribute non-zero values to the overall result
193 if (computeLowerBound) {
194 // Check whether the value for visiting a target state will be zero.
195 if (static_cast<uint64_t>(k) > foxGlynnResult.right) {
196 // Reaching this point means that we are in one of the earlier iterations where fox glynn told us to cut off
197 continue;
198 }
199 } else {
200 uint64_t i = N - 1 - k;
201 if (i > foxGlynnResult.right) {
202 // Reaching this point means that we are in a later iteration which will not contribute to the upper bound
203 // Since i will only get larger in subsequent iterations, we can directly break here.
204 break;
205 }
206 }
207
208 // Compute the values at Markovian maybe states.
209 if (firstIteration) {
210 firstIteration = false;
211 // Reaching this point means that this is the very first relevant iteration.
212 // If we are in the very first relevant iteration, we know that all states from the previous iteration have value zero.
213 // It is therefore valid (and necessary) to just set the values of Markovian states to zero.
214 std::fill(nextMarkovianStateValues.begin(), nextMarkovianStateValues.end(), storm::utility::zero<ValueType>());
215 } else {
216 // Compute the values at Markovian maybe states.
217 markovianToMaybeMultiplier->multiply(env, maybeStatesValues, nullptr, nextMarkovianStateValues);
218 for (auto const& oneStepProb : markovianToPsiProbabilities) {
219 nextMarkovianStateValues[oneStepProb.first] += oneStepProb.second * targetValue;
220 }
221 }
222
223 // Update the value when reaching a psi state.
224 // This has to be done after updating the Markovian state values since we needed the 'old' target value above.
225 if (computeLowerBound && static_cast<uint64_t>(k) >= foxGlynnResult.left) {
226 STORM_LOG_ASSERT(static_cast<uint64_t>(k) <= foxGlynnResult.right,
227 "K exceeds left bound."); // has to hold since this iteration is relevant
228 targetValue += foxGlynnResult.weights[k - foxGlynnResult.left];
229 }
230
231 // Compute the values at probabilistic states.
232 probabilisticToMarkovianMultiplier->multiply(env, nextMarkovianStateValues, nullptr, eqSysRhs);
233 for (auto const& oneStepProb : probabilisticToPsiProbabilities) {
234 eqSysRhs[oneStepProb.first] += oneStepProb.second * targetValue;
235 }
236 if (solver) {
237 solver->solveEquations(solverEnv, dir, nextProbabilisticStateValues, eqSysRhs);
238 } else {
239 storm::utility::vector::reduceVectorMinOrMax(dir, eqSysRhs, nextProbabilisticStateValues,
240 probabilisticToProbabilisticTransitions.getRowGroupIndices());
241 }
242
243 // Create the new values for the maybestates
244 // Fuse the results together
245 storm::utility::vector::setVectorValues(maybeStatesValues, markovianStatesModMaybeStates, nextMarkovianStateValues);
246 storm::utility::vector::setVectorValues(maybeStatesValues, probabilisticStatesModMaybeStates, nextProbabilisticStateValues);
247 if (!computeLowerBound) {
248 // Add the scaled values to the actual result vector
249 uint64_t i = N - 1 - k;
250 if (i >= foxGlynnResult.left) {
251 STORM_LOG_ASSERT(i <= foxGlynnResult.right, "I exceeds right bound."); // has to hold since this iteration is considered relevant.
252 ValueType const& weight = foxGlynnResult.weights[i - foxGlynnResult.left];
253 storm::utility::vector::addScaledVector(maybeStatesValuesUpper, maybeStatesValuesWeightedUpper, weight);
254 }
255 }
256
257 progressSteps.updateProgress(N - k);
259 abortedInnerIterations = true;
260 break;
261 }
262 }
263
264 if (computeLowerBound) {
265 storm::utility::vector::scaleVectorInPlace(maybeStatesValuesLower, storm::utility::one<ValueType>() / foxGlynnResult.totalWeight);
266 } else {
267 storm::utility::vector::scaleVectorInPlace(maybeStatesValuesUpper, storm::utility::one<ValueType>() / foxGlynnResult.totalWeight);
268 }
269
270 if (abortedInnerIterations || storm::utility::resources::isTerminate()) {
271 break;
272 }
273
274 // Check if the lower and upper bound are sufficiently close to each other
275 converged = checkConvergence(maybeStatesValuesLower, maybeStatesValuesUpper, relevantMarkovianMaybeStates, epsilon, relativePrecision, kappa);
276 if (converged) {
277 break;
278 }
279
280 // Store the best solution we have found so far.
281 if (relevantMaybeStates) {
282 auto currentSolIt = bestKnownSolution.begin();
283 for (uint64_t state : relevantMaybeStates.get()) {
284 // We take the average of the lower and upper bounds
285 *currentSolIt = (maybeStatesValuesLower[state] + maybeStatesValuesUpper[state]) / two;
286 ++currentSolIt;
287 }
288 }
289 }
290
291 if (!converged) {
292 // Increase the uniformization rate and prepare the next run
293
294 // Double lambda.
295 ValueType oldLambda = lambda;
296 lambda *= two;
297 STORM_LOG_DEBUG("Increased lambda to " << lambda << ".");
298
299 if (relativePrecision) {
300 // Reduce kappa a bit
301 ValueType minValue;
302 if (relevantMaybeStates) {
303 minValue = storm::utility::vector::min_if(maybeStatesValuesUpper, relevantMaybeStates.get());
304 } else {
305 minValue = *std::min_element(maybeStatesValuesUpper.begin(), maybeStatesValuesUpper.end());
306 }
308 kappa = std::min(kappa, minValue);
309 STORM_LOG_DEBUG("Decreased kappa to " << kappa << ".");
310 }
311
312 // Apply uniformization with new rate
313 uniformize(markovianToMaybeTransitions, markovianToPsiProbabilities, oldLambda, lambda, markovianStatesModMaybeStates);
314
315 // Reset the values of the maybe states to zero.
316 std::fill(maybeStatesValuesUpper.begin(), maybeStatesValuesUpper.end(), storm::utility::zero<ValueType>());
317 }
318 progressIterations.updateProgress(++iteration);
320 STORM_LOG_WARN("Aborted unif+ in iteration " << iteration << ".");
321 break;
322 }
323 }
324
325 // Prepare the result vector
326 std::vector<ValueType> result(transitionMatrix.getRowGroupCount(), storm::utility::zero<ValueType>());
327 // Set values of target states to 1
329
330 if (abortedInnerIterations && iteration > 1 && relevantMaybeStates && relevantStates) {
331 // We should take the stored solution instead of the current (probably more incorrect) lower/upper values
332 storm::utility::vector::setVectorValues(result, relevantMaybeStates.get(), bestKnownSolution);
333 } else {
334 // Set the values for Markovian "maybe" states
335 STORM_LOG_ASSERT(markovianMaybeStates.getNumberOfSetBits() == markovianStatesModMaybeStates.getNumberOfSetBits(),
336 "Unexpected number of Markovian maybe states.");
337 auto subStateIt = markovianStatesModMaybeStates.begin();
338 for (uint64_t markovianState : markovianMaybeStates) {
339 result[markovianState] = (maybeStatesValuesLower[*subStateIt] + maybeStatesValuesUpper[*subStateIt]) / two;
340 ++subStateIt;
341 }
342 // At this point, we only need to set the values for probabilistic "maybe" states.
343 // We derive the values from the values of the other states, which are reached in zero time.
344 uint64_t probSubState = 0;
345 for (uint64_t probabilisticState : probabilisticMaybeStates) {
346 for (auto const probStateRow : transitionMatrix.getRowGroupIndices(probabilisticState)) {
347 eqSysRhs[probSubState] = transitionMatrix.multiplyRowWithVector(probStateRow, result);
348 ++probSubState;
349 }
350 }
351 if (solver) {
352 solver->solveEquations(solverEnv, dir, nextProbabilisticStateValues, eqSysRhs);
353 } else {
354 storm::utility::vector::reduceVectorMinOrMax(dir, eqSysRhs, nextProbabilisticStateValues,
355 probabilisticToProbabilisticTransitions.getRowGroupIndices());
356 }
357 storm::utility::vector::setVectorValues(result, probabilisticMaybeStates, nextProbabilisticStateValues);
358 }
359 return result;
360 }
361
362 private:
363 bool checkConvergence(std::vector<ValueType> const& lower, std::vector<ValueType> const& upper, storm::storage::BitVector const& relevantValues,
364 ValueType const& epsilon, bool relative, ValueType& kappa) {
365 STORM_LOG_ASSERT(relevantValues.size() == lower.size(), "Relevant values size mismatch.");
366 if (!relative) {
367 return storm::utility::vector::equalModuloPrecision(lower, upper, relevantValues, epsilon * (storm::utility::one<ValueType>() - kappa), false);
368 }
369 ValueType truncationError = epsilon * kappa;
370 for (uint64_t const i : relevantValues) {
371 if (lower[i] == upper[i]) {
372 continue;
373 }
374 if (lower[i] <= truncationError) {
375 return false;
376 }
377 ValueType absDiff = upper[i] - lower[i] + truncationError;
378 ValueType relDiff = absDiff / lower[i];
379 if (relDiff > epsilon) {
380 return false;
381 }
382 STORM_LOG_ASSERT(absDiff > storm::utility::zero<ValueType>(), "Upper bound " << upper[i] << " is smaller than lower bound " << lower[i] << ".");
383 }
384 return true;
385 }
386
387 storm::storage::SparseMatrix<ValueType> getUniformizedMarkovianTransitions(std::vector<ValueType> const& oldRates, ValueType uniformizationRate,
388 storm::storage::BitVector const& maybeStates,
389 storm::storage::BitVector const& markovianMaybeStates) {
390 // We need a submatrix whose rows correspond to the markovian states and columns correpsond to the maybestates.
391 // In addition, we need 'selfloop' entries for the markovian maybe states.
392
393 // First build a submatrix without selfloop entries
394 auto submatrix = transitionMatrix.getSubmatrix(true, markovianMaybeStates, maybeStates);
395 STORM_LOG_ASSERT(submatrix.getRowCount() == submatrix.getRowGroupCount(), "Submatrix row count != row group count.");
396
397 // Now add selfloop entries at the correct positions and apply uniformization
398 storm::storage::SparseMatrixBuilder<ValueType> builder(submatrix.getRowCount(), submatrix.getColumnCount());
399 auto markovianStateColumns = markovianMaybeStates % maybeStates;
400 uint64_t row = 0;
401 for (uint64_t selfloopColumn : markovianStateColumns) {
402 ValueType const& oldExitRate = oldRates[row];
403 bool foundSelfoop = false;
404 for (auto const& entry : submatrix.getRow(row)) {
405 if (entry.getColumn() == selfloopColumn) {
406 foundSelfoop = true;
407 ValueType newSelfLoop = uniformizationRate - oldExitRate + entry.getValue() * oldExitRate;
408 builder.addNextValue(row, entry.getColumn(), newSelfLoop / uniformizationRate);
409 } else {
410 builder.addNextValue(row, entry.getColumn(), entry.getValue() * oldExitRate / uniformizationRate);
411 }
412 }
413 if (!foundSelfoop) {
414 ValueType newSelfLoop = uniformizationRate - oldExitRate;
415 builder.addNextValue(row, selfloopColumn, newSelfLoop / uniformizationRate);
416 }
417 ++row;
418 }
419 STORM_LOG_ASSERT(row == submatrix.getRowCount(), "Row count mismatch for submatrix.");
420
421 return builder.build();
422 }
423
424 void uniformize(storm::storage::SparseMatrix<ValueType>& matrix, std::vector<std::pair<uint64_t, ValueType>>& oneSteps,
425 std::vector<ValueType> const& oldRates, ValueType uniformizationRate, storm::storage::BitVector const& selfloopColumns) {
426 uint64_t row = 0;
427 for (uint64_t selfloopColumn : selfloopColumns) {
428 ValueType const& oldExitRate = oldRates[row];
429 if (oldExitRate == uniformizationRate) {
430 // Already uniformized.
431 ++row;
432 continue;
433 }
434 for (auto& v : matrix.getRow(row)) {
435 if (v.getColumn() == selfloopColumn) {
436 ValueType newSelfLoop = uniformizationRate - oldExitRate + v.getValue() * oldExitRate;
437 v.setValue(newSelfLoop / uniformizationRate);
438 } else {
439 v.setValue(v.getValue() * oldExitRate / uniformizationRate);
440 }
441 }
442 ++row;
443 }
444 STORM_LOG_ASSERT(row == matrix.getRowCount(), "Row count mismatch after uniformization.");
445 for (auto& oneStep : oneSteps) {
446 oneStep.second *= oldRates[oneStep.first] / uniformizationRate;
447 }
448 }
449
452 void uniformize(storm::storage::SparseMatrix<ValueType>& matrix, std::vector<std::pair<uint64_t, ValueType>>& oneSteps, ValueType oldUniformizationRate,
453 ValueType newUniformizationRate, storm::storage::BitVector const& selfloopColumns) {
454 if (oldUniformizationRate != newUniformizationRate) {
455 STORM_LOG_ASSERT(oldUniformizationRate < newUniformizationRate, "Old uniformization rate must be less than new.");
456 ValueType rateDiff = newUniformizationRate - oldUniformizationRate;
457 ValueType rateFraction = oldUniformizationRate / newUniformizationRate;
458 uint64_t row = 0;
459 for (uint64_t selfloopColumn : selfloopColumns) {
460 for (auto& v : matrix.getRow(row)) {
461 if (v.getColumn() == selfloopColumn) {
462 ValueType newSelfLoop = rateDiff + v.getValue() * oldUniformizationRate;
463 v.setValue(newSelfLoop / newUniformizationRate);
464 } else {
465 v.setValue(v.getValue() * rateFraction);
466 }
467 }
468 ++row;
469 }
470 STORM_LOG_ASSERT(row == matrix.getRowCount(), "Row count mismatch after uniformization.");
471 for (auto& oneStep : oneSteps) {
472 oneStep.second *= rateFraction;
473 }
474 }
475 }
476
477 storm::storage::BitVector getProb0States(OptimizationDirection dir, storm::storage::BitVector const& phiStates,
478 storm::storage::BitVector const& psiStates) const {
479 if (dir == storm::solver::OptimizationDirection::Maximize) {
480 return storm::utility::graph::performProb0A(transitionMatrix.transpose(true), phiStates, psiStates);
481 } else {
482 return storm::utility::graph::performProb0E(transitionMatrix, transitionMatrix.getRowGroupIndices(), transitionMatrix.transpose(true), phiStates,
483 psiStates);
484 }
485 }
486
492 std::vector<std::pair<uint64_t, ValueType>> getSparseOneStepProbabilities(storm::storage::BitVector const& sourceStateConstraint,
493 storm::storage::BitVector const& targetStateConstraint) const {
494 auto denseResult = transitionMatrix.getConstrainedRowGroupSumVector(sourceStateConstraint, targetStateConstraint);
495 std::vector<std::pair<uint64_t, ValueType>> sparseResult;
496 for (uint64_t i = 0; i < denseResult.size(); ++i) {
497 auto const& val = denseResult[i];
498 if (!storm::utility::isZero(val)) {
499 sparseResult.emplace_back(i, val);
500 }
501 }
502 return sparseResult;
503 }
504
505 storm::storage::SparseMatrix<ValueType> const& transitionMatrix;
506 std::vector<ValueType> const& exitRateVector;
507 storm::storage::BitVector const& markovianStates;
508};
509
510template<typename ValueType>
512 storm::storage::SparseMatrix<ValueType> const& transitionMatrix, std::vector<ValueType> const& exitRates,
513 storm::storage::BitVector const& goalStates, storm::storage::BitVector const& markovianNonGoalStates,
514 storm::storage::BitVector const& probabilisticNonGoalStates, std::vector<ValueType>& markovianNonGoalValues,
515 std::vector<ValueType>& probabilisticNonGoalValues, ValueType delta, uint64_t numberOfSteps) {
516 // Start by computing four sparse matrices:
517 // * a matrix aMarkovian with all (discretized) transitions from Markovian non-goal states to all Markovian non-goal states.
518 // * a matrix aMarkovianToProbabilistic with all (discretized) transitions from Markovian non-goal states to all probabilistic non-goal states.
519 // * a matrix aProbabilistic with all (non-discretized) transitions from probabilistic non-goal states to other probabilistic non-goal states.
520 // * a matrix aProbabilisticToMarkovian with all (non-discretized) transitions from probabilistic non-goal states to all Markovian non-goal states.
521 typename storm::storage::SparseMatrix<ValueType> aMarkovian = transitionMatrix.getSubmatrix(true, markovianNonGoalStates, markovianNonGoalStates, true);
522
523 bool existProbabilisticStates = !probabilisticNonGoalStates.empty();
524 typename storm::storage::SparseMatrix<ValueType> aMarkovianToProbabilistic;
525 typename storm::storage::SparseMatrix<ValueType> aProbabilistic;
526 typename storm::storage::SparseMatrix<ValueType> aProbabilisticToMarkovian;
527 if (existProbabilisticStates) {
528 aMarkovianToProbabilistic = transitionMatrix.getSubmatrix(true, markovianNonGoalStates, probabilisticNonGoalStates);
529 aProbabilistic = transitionMatrix.getSubmatrix(true, probabilisticNonGoalStates, probabilisticNonGoalStates);
530 aProbabilisticToMarkovian = transitionMatrix.getSubmatrix(true, probabilisticNonGoalStates, markovianNonGoalStates);
531 }
532
533 // The matrices with transitions from Markovian states need to be digitized.
534 // Digitize aMarkovian. Based on whether the transition is a self-loop or not, we apply the two digitization rules.
535 uint64_t rowIndex = 0;
536 for (uint64_t state : markovianNonGoalStates) {
537 for (auto& element : aMarkovian.getRow(rowIndex)) {
538 ValueType eTerm = std::exp(-exitRates[state] * delta);
539 if (element.getColumn() == rowIndex) {
540 element.setValue((storm::utility::one<ValueType>() - eTerm) * element.getValue() + eTerm);
541 } else {
542 element.setValue((storm::utility::one<ValueType>() - eTerm) * element.getValue());
543 }
544 }
545 ++rowIndex;
546 }
547
548 // Digitize aMarkovianToProbabilistic. As there are no self-loops in this case, we only need to apply the digitization formula for regular successors.
549 if (existProbabilisticStates) {
550 rowIndex = 0;
551 for (uint64_t state : markovianNonGoalStates) {
552 for (auto& element : aMarkovianToProbabilistic.getRow(rowIndex)) {
553 element.setValue((1 - std::exp(-exitRates[state] * delta)) * element.getValue());
554 }
555 ++rowIndex;
556 }
557 }
558
559 // Initialize the two vectors that hold the variable one-step probabilities to all target states for probabilistic and Markovian (non-goal) states.
560 std::vector<ValueType> bProbabilistic(existProbabilisticStates ? aProbabilistic.getRowCount() : 0);
561 std::vector<ValueType> bMarkovian(markovianNonGoalStates.getNumberOfSetBits());
562
563 // Compute the two fixed right-hand side vectors, one for Markovian states and one for the probabilistic ones.
564 std::vector<ValueType> bProbabilisticFixed;
565 if (existProbabilisticStates) {
566 bProbabilisticFixed = transitionMatrix.getConstrainedRowGroupSumVector(probabilisticNonGoalStates, goalStates);
567 }
568 std::vector<ValueType> bMarkovianFixed;
569 bMarkovianFixed.reserve(markovianNonGoalStates.getNumberOfSetBits());
570 for (uint64_t state : markovianNonGoalStates) {
571 bMarkovianFixed.push_back(storm::utility::zero<ValueType>());
572
573 for (auto& element : transitionMatrix.getRowGroup(state)) {
574 if (goalStates.get(element.getColumn())) {
575 bMarkovianFixed.back() += (1 - std::exp(-exitRates[state] * delta)) * element.getValue();
576 }
577 }
578 }
579
580 // Create a solver object (only if there are actually transitions between probabilistic states)
581 auto solverEnv = env;
582 solverEnv.solver().setForceExact(true);
583 auto solver = setUpProbabilisticStatesSolver(solverEnv, dir, aProbabilistic);
584
585 // Perform the actual value iteration
586 // * loop until the step bound has been reached
587 // * in the loop:
588 // * perform value iteration using A_PSwG, v_PS and the vector b where b = (A * 1_G)|PS + A_PStoMS * v_MS
589 // and 1_G being the characteristic vector for all goal states.
590 // * perform one timed-step using v_MS := A_MSwG * v_MS + A_MStoPS * v_PS + (A * 1_G)|MS
591 std::vector<ValueType> markovianNonGoalValuesSwap(markovianNonGoalValues);
592 for (uint64_t currentStep = 0; currentStep < numberOfSteps; ++currentStep) {
593 if (existProbabilisticStates) {
594 // Start by (re-)computing bProbabilistic = bProbabilisticFixed + aProbabilisticToMarkovian * vMarkovian.
595 aProbabilisticToMarkovian.multiplyWithVector(markovianNonGoalValues, bProbabilistic);
596 storm::utility::vector::addVectors(bProbabilistic, bProbabilisticFixed, bProbabilistic);
597
598 // Now perform the inner value iteration for probabilistic states.
599 if (solver) {
600 solver->solveEquations(solverEnv, dir, probabilisticNonGoalValues, bProbabilistic);
601 } else {
602 storm::utility::vector::reduceVectorMinOrMax(dir, bProbabilistic, probabilisticNonGoalValues, aProbabilistic.getRowGroupIndices());
603 }
604
605 // (Re-)compute bMarkovian = bMarkovianFixed + aMarkovianToProbabilistic * vProbabilistic.
606 aMarkovianToProbabilistic.multiplyWithVector(probabilisticNonGoalValues, bMarkovian);
607 storm::utility::vector::addVectors(bMarkovian, bMarkovianFixed, bMarkovian);
608 }
609
610 aMarkovian.multiplyWithVector(markovianNonGoalValues, markovianNonGoalValuesSwap);
611 std::swap(markovianNonGoalValues, markovianNonGoalValuesSwap);
612 if (existProbabilisticStates) {
613 storm::utility::vector::addVectors(markovianNonGoalValues, bMarkovian, markovianNonGoalValues);
614 } else {
615 storm::utility::vector::addVectors(markovianNonGoalValues, bMarkovianFixed, markovianNonGoalValues);
616 }
618 break;
619 }
620 }
621
622 if (existProbabilisticStates) {
623 // After the loop, perform one more step of the value iteration for PS states.
624 aProbabilisticToMarkovian.multiplyWithVector(markovianNonGoalValues, bProbabilistic);
625 storm::utility::vector::addVectors(bProbabilistic, bProbabilisticFixed, bProbabilistic);
626 if (solver) {
627 solver->solveEquations(solverEnv, dir, probabilisticNonGoalValues, bProbabilistic);
628 } else {
629 storm::utility::vector::reduceVectorMinOrMax(dir, bProbabilistic, probabilisticNonGoalValues, aProbabilistic.getRowGroupIndices());
630 }
631 }
632}
633
634template<typename ValueType>
636 storm::storage::SparseMatrix<ValueType> const& transitionMatrix,
637 std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates,
638 storm::storage::BitVector const& psiStates,
639 std::pair<double, std::optional<double>> const& boundsPair) {
640 STORM_LOG_TRACE("Using IMCA's technique to compute bounded until probabilities.");
641
642 uint64_t numberOfStates = transitionMatrix.getRowGroupCount();
643
644 // 'Unpack' the bounds to make them more easily accessible.
645 STORM_LOG_THROW(boundsPair.second.has_value(), storm::exceptions::NotSupportedException,
646 "IMCA's technique requires an upper time bound, but the given property has none.");
647 double lowerBound = boundsPair.first;
648 double upperBound = *boundsPair.second;
649
650 // (1) Compute the accuracy we need to achieve the required error bound.
651 ValueType maxExitRate = 0;
652 for (auto value : exitRateVector) {
653 maxExitRate = std::max(maxExitRate, value);
654 }
655 ValueType delta = (2.0 * storm::utility::convertNumber<ValueType>(env.solver().timeBounded().getPrecision())) / (upperBound * maxExitRate * maxExitRate);
656
657 // (2) Compute the number of steps we need to make for the interval.
658 uint64_t numberOfSteps = static_cast<uint64_t>(std::ceil((upperBound - lowerBound) / delta));
659 STORM_LOG_INFO("Performing " << numberOfSteps << " iterations (delta=" << delta << ") for interval [" << lowerBound << ", " << upperBound << "].\n");
660
661 // (3) Compute the non-goal states and initialize two vectors
662 // * vProbabilistic holds the probability values of probabilistic non-goal states.
663 // * vMarkovian holds the probability values of Markovian non-goal states.
664 storm::storage::BitVector const& markovianNonGoalStates = markovianStates & ~psiStates;
665 storm::storage::BitVector const& probabilisticNonGoalStates = ~markovianStates & ~psiStates;
666 std::vector<ValueType> vProbabilistic(probabilisticNonGoalStates.getNumberOfSetBits());
667 std::vector<ValueType> vMarkovian(markovianNonGoalStates.getNumberOfSetBits());
668
669 computeBoundedReachabilityProbabilitiesImca(env, dir, transitionMatrix, exitRateVector, psiStates, markovianNonGoalStates, probabilisticNonGoalStates,
670 vMarkovian, vProbabilistic, delta, numberOfSteps);
671
672 // (4) If the lower bound of interval was non-zero, we need to take the current values as the starting values for a subsequent value iteration.
673 if (lowerBound != storm::utility::zero<ValueType>()) {
674 std::vector<ValueType> vAllProbabilistic((~markovianStates).getNumberOfSetBits());
675 std::vector<ValueType> vAllMarkovian(markovianStates.getNumberOfSetBits());
676
677 // Create the starting value vectors for the next value iteration based on the results of the previous one.
678 storm::utility::vector::setVectorValues<ValueType>(vAllProbabilistic, psiStates % ~markovianStates, storm::utility::one<ValueType>());
679 storm::utility::vector::setVectorValues<ValueType>(vAllProbabilistic, ~psiStates % ~markovianStates, vProbabilistic);
680 storm::utility::vector::setVectorValues<ValueType>(vAllMarkovian, psiStates % markovianStates, storm::utility::one<ValueType>());
681 storm::utility::vector::setVectorValues<ValueType>(vAllMarkovian, ~psiStates % markovianStates, vMarkovian);
682
683 // Compute the number of steps to reach the target interval.
684 numberOfSteps = static_cast<uint64_t>(std::ceil(lowerBound / delta));
685 STORM_LOG_INFO("Performing " << numberOfSteps << " iterations (delta=" << delta << ") for interval [0, " << lowerBound << "].\n");
686
687 // Compute the bounded reachability for interval [0, b-a].
688 computeBoundedReachabilityProbabilitiesImca(env, dir, transitionMatrix, exitRateVector, storm::storage::BitVector(numberOfStates), markovianStates,
689 ~markovianStates, vAllMarkovian, vAllProbabilistic, delta, numberOfSteps);
690
691 // Create the result vector out of vAllProbabilistic and vAllMarkovian and return it.
692 std::vector<ValueType> result(numberOfStates, storm::utility::zero<ValueType>());
693 storm::utility::vector::setVectorValues(result, ~markovianStates, vAllProbabilistic);
694 storm::utility::vector::setVectorValues(result, markovianStates, vAllMarkovian);
695
696 return result;
697 } else {
698 // Create the result vector out of 1_G, vProbabilistic and vMarkovian and return it.
699 std::vector<ValueType> result(numberOfStates);
701 storm::utility::vector::setVectorValues(result, probabilisticNonGoalStates, vProbabilistic);
702 storm::utility::vector::setVectorValues(result, markovianNonGoalStates, vMarkovian);
703 return result;
704 }
705}
706
707template<typename ValueType, typename std::enable_if<storm::NumberTraits<ValueType>::SupportsExponential, int>::type>
710 std::vector<ValueType> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& phiStates,
711 storm::storage::BitVector const& psiStates, std::pair<double, std::optional<double>> const& boundsPair) {
712 STORM_LOG_THROW(!env.solver().isForceExact(), storm::exceptions::InvalidOperationException,
713 "Exact computations not possible for bounded until probabilities.");
714
715 // Choose the applicable method
716 auto method = env.solver().timeBounded().getMaMethod();
717 if (method == storm::solver::MaBoundedReachabilityMethod::Imca) {
718 if (!phiStates.full()) {
719 STORM_LOG_WARN("Using Unif+ method because IMCA method does not support (phi Until psi) for non-trivial phi");
720 method = storm::solver::MaBoundedReachabilityMethod::UnifPlus;
721 }
722 } else {
723 STORM_LOG_ASSERT(method == storm::solver::MaBoundedReachabilityMethod::UnifPlus, "Unknown solution method.");
724 if (!storm::utility::isZero(boundsPair.first)) {
725 STORM_LOG_WARN("Using IMCA method because Unif+ does not support a lower bound > 0.");
726 method = storm::solver::MaBoundedReachabilityMethod::Imca;
727 }
728 }
729
730 if (method == storm::solver::MaBoundedReachabilityMethod::Imca) {
731 return computeBoundedUntilProbabilitiesImca(env, goal.direction(), transitionMatrix, exitRateVector, markovianStates, psiStates, boundsPair);
732 } else {
733 UnifPlusHelper<ValueType> helper(transitionMatrix, exitRateVector, markovianStates);
734 boost::optional<storm::storage::BitVector> relevantValues;
735 if (goal.hasRelevantValues()) {
736 relevantValues = std::move(goal.relevantValues());
737 }
738 return helper.computeBoundedUntilProbabilities(env, goal.direction(), phiStates, psiStates, boundsPair.second, relevantValues);
739 }
740}
741
742template<typename ValueType, typename std::enable_if<!storm::NumberTraits<ValueType>::SupportsExponential, int>::type>
745 std::vector<ValueType> const&, storm::storage::BitVector const&,
747 std::pair<double, std::optional<double>> const&) {
748 STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Computing bounded until probabilities is unsupported for this value type.");
749}
750
751template<typename ValueType>
753 Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix,
754 storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates,
755 bool qualitative, bool produceScheduler) {
756 return storm::modelchecker::helper::SparseMdpPrctlHelper<ValueType>::computeUntilProbabilities(env, dir, transitionMatrix, backwardTransitions, phiStates,
757 psiStates, qualitative, produceScheduler);
758}
759
760template<typename ValueType, typename RewardModelType>
762 Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix,
763 storm::storage::SparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& exitRateVector,
764 storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel, bool produceScheduler) {
765 // Get a reward model where the state rewards are scaled accordingly
766 std::vector<ValueType> stateRewardWeights(transitionMatrix.getRowGroupCount(), storm::utility::zero<ValueType>());
767 for (uint64_t markovianState : markovianStates) {
768 stateRewardWeights[markovianState] = storm::utility::one<ValueType>() / exitRateVector[markovianState];
769 }
770 std::vector<ValueType> totalRewardVector = rewardModel.getTotalActionRewardVector(transitionMatrix, stateRewardWeights);
771 RewardModelType scaledRewardModel(std::nullopt, std::move(totalRewardVector));
772
773 return SparseMdpPrctlHelper<ValueType>::computeTotalRewards(env, dir, transitionMatrix, backwardTransitions, scaledRewardModel, false, produceScheduler);
774}
775
776template<typename ValueType, typename RewardModelType>
778 Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix,
779 storm::storage::SparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& exitRateVector,
780 storm::storage::BitVector const& markovianStates, RewardModelType const& rewardModel, storm::storage::BitVector const& psiStates, bool produceScheduler) {
781 // Get a reward model where the state rewards are scaled accordingly
782 std::vector<ValueType> stateRewardWeights(transitionMatrix.getRowGroupCount(), storm::utility::zero<ValueType>());
783 for (uint64_t markovianState : markovianStates) {
784 stateRewardWeights[markovianState] = storm::utility::one<ValueType>() / exitRateVector[markovianState];
785 }
786 std::vector<ValueType> totalRewardVector = rewardModel.getTotalActionRewardVector(transitionMatrix, stateRewardWeights);
787 RewardModelType scaledRewardModel(std::nullopt, std::move(totalRewardVector));
788
789 return SparseMdpPrctlHelper<ValueType>::computeReachabilityRewards(env, dir, transitionMatrix, backwardTransitions, scaledRewardModel, psiStates, false,
790 produceScheduler);
791}
792
793template<typename ValueType>
795 Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix<ValueType> const& transitionMatrix,
796 storm::storage::SparseMatrix<ValueType> const& backwardTransitions, std::vector<ValueType> const& exitRateVector,
797 storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, bool produceScheduler) {
798 // Get a reward model representing expected sojourn times
799 std::vector<ValueType> rewardValues(transitionMatrix.getRowCount(), storm::utility::zero<ValueType>());
800 for (uint64_t markovianState : markovianStates) {
801 rewardValues[transitionMatrix.getRowGroupIndices()[markovianState]] = storm::utility::one<ValueType>() / exitRateVector[markovianState];
802 }
803 storm::models::sparse::StandardRewardModel<ValueType> rewardModel(std::nullopt, std::move(rewardValues));
804
805 return SparseMdpPrctlHelper<ValueType>::computeReachabilityRewards(env, dir, transitionMatrix, backwardTransitions, rewardModel, psiStates, false,
806 produceScheduler);
807}
808
811 std::vector<double> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& phiStates,
812 storm::storage::BitVector const& psiStates, std::pair<double, std::optional<double>> const& boundsPair);
813
815 Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix<double> const& transitionMatrix,
816 storm::storage::SparseMatrix<double> const& backwardTransitions, storm::storage::BitVector const& phiStates, storm::storage::BitVector const& psiStates,
817 bool qualitative, bool produceScheduler);
818
820 Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix<double> const& transitionMatrix,
821 storm::storage::SparseMatrix<double> const& backwardTransitions, std::vector<double> const& exitRateVector,
822 storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel<double> const& rewardModel,
823 storm::storage::BitVector const& psiStates, bool produceScheduler);
824
826 Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix<double> const& transitionMatrix,
827 storm::storage::SparseMatrix<double> const& backwardTransitions, std::vector<double> const& exitRateVector,
828 storm::storage::BitVector const& markovianStates, storm::models::sparse::StandardRewardModel<double> const& rewardModel, bool produceScheduler);
829
831 Environment const& env, OptimizationDirection dir, storm::storage::SparseMatrix<double> const& transitionMatrix,
832 storm::storage::SparseMatrix<double> const& backwardTransitions, std::vector<double> const& exitRateVector,
833 storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, bool produceScheduler);
834
835template std::vector<storm::RationalNumber> SparseMarkovAutomatonCslHelper::computeBoundedUntilProbabilities(
837 std::vector<storm::RationalNumber> const& exitRateVector, storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& phiStates,
838 storm::storage::BitVector const& psiStates, std::pair<double, std::optional<double>> const& boundsPair);
839
842 storm::storage::SparseMatrix<storm::RationalNumber> const& backwardTransitions, storm::storage::BitVector const& phiStates,
843 storm::storage::BitVector const& psiStates, bool qualitative, bool produceScheduler);
844
849 std::vector<storm::RationalNumber> const& exitRateVector,
850 storm::storage::BitVector const& markovianStates,
852 storm::storage::BitVector const& psiStates, bool produceScheduler);
853
856 storm::storage::SparseMatrix<storm::RationalNumber> const& backwardTransitions, std::vector<storm::RationalNumber> const& exitRateVector,
858 bool produceScheduler);
859
862 storm::storage::SparseMatrix<storm::RationalNumber> const& backwardTransitions, std::vector<storm::RationalNumber> const& exitRateVector,
863 storm::storage::BitVector const& markovianStates, storm::storage::BitVector const& psiStates, bool produceScheduler);
864} // namespace helper
865} // namespace modelchecker
866} // namespace storm
SolverEnvironment & solver()
void setMethod(storm::solver::MinMaxMethod value, bool isSetFromDefault=false)
MinMaxSolverEnvironment & minMax()
uint64_t getShowProgressDelay() const
TimeBoundedSolverEnvironment & timeBounded()
storm::RationalNumber const & getPrecision() const
storm::RationalNumber const & getUnifPlusKappa() const
storm::solver::MaBoundedReachabilityMethod const & getMaMethod() const
static std::vector< ValueType > computeBoundedUntilProbabilities(Environment const &env, storm::solver::SolveGoal< ValueType > &&goal, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, std::vector< ValueType > const &exitRateVector, storm::storage::BitVector const &markovianStates, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates, std::pair< double, std::optional< double > > const &boundsPair)
static MDPSparseModelCheckingHelperReturnType< ValueType > computeUntilProbabilities(Environment const &env, OptimizationDirection dir, 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)
static MDPSparseModelCheckingHelperReturnType< ValueType, storm::utility::ExtendedValueType< ValueType > > computeTotalRewards(Environment const &env, OptimizationDirection dir, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::SparseMatrix< ValueType > const &backwardTransitions, std::vector< ValueType > const &exitRateVector, storm::storage::BitVector const &markovianStates, RewardModelType const &rewardModel, bool produceScheduler)
static MDPSparseModelCheckingHelperReturnType< ValueType, storm::utility::ExtendedValueType< ValueType > > computeReachabilityTimes(Environment const &env, OptimizationDirection dir, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::SparseMatrix< ValueType > const &backwardTransitions, std::vector< ValueType > const &exitRateVector, storm::storage::BitVector const &markovianStates, storm::storage::BitVector const &psiStates, bool produceScheduler)
static MDPSparseModelCheckingHelperReturnType< ValueType, storm::utility::ExtendedValueType< ValueType > > computeReachabilityRewards(Environment const &env, OptimizationDirection dir, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::SparseMatrix< ValueType > const &backwardTransitions, std::vector< ValueType > const &exitRateVector, storm::storage::BitVector const &markovianStates, RewardModelType const &rewardModel, storm::storage::BitVector const &psiStates, bool produceScheduler)
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 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 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())
std::vector< ValueType > computeBoundedUntilProbabilities(storm::Environment const &env, OptimizationDirection dir, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates, std::optional< ValueType > const &upperTimeBound, boost::optional< storm::storage::BitVector > const &relevantStates=boost::none)
UnifPlusHelper(storm::storage::SparseMatrix< ValueType > const &transitionMatrix, std::vector< ValueType > const &exitRateVector, storm::storage::BitVector const &markovianStates)
virtual std::unique_ptr< MinMaxLinearEquationSolver< ValueType, SolutionType > > create(Environment const &env) const override
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
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.
const_iterator begin() const
Returns an iterator to the indices of the set bits in the bit vector.
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.
A class that holds a possibly non-square matrix in the compressed row storage format.
const_rows getRow(index_type row) const
Returns an object representing the given row.
void multiplyWithVector(std::vector< value_type > const &vector, std::vector< value_type > &result, std::vector< value_type > const *summand=nullptr) const
Multiplies the matrix with the given vector and writes the result to the given result vector.
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 ...
const_rows getRowGroup(index_type rowGroup) const
Returns an object representing the given row group.
index_type getRowGroupCount() const
Returns the number of row groups in the matrix.
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.
index_type getNonzeroEntryCount() const
Returns the cached number of nonzero entries in the matrix.
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.
#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_TRACE(message)
Definition logging.h:22
#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 computeBoundedReachabilityProbabilitiesImca(Environment const &env, OptimizationDirection dir, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, std::vector< ValueType > const &exitRates, storm::storage::BitVector const &goalStates, storm::storage::BitVector const &markovianNonGoalStates, storm::storage::BitVector const &probabilisticNonGoalStates, std::vector< ValueType > &markovianNonGoalValues, std::vector< ValueType > &probabilisticNonGoalValues, ValueType delta, uint64_t numberOfSteps)
std::unique_ptr< storm::solver::MinMaxLinearEquationSolver< ValueType > > setUpProbabilisticStatesSolver(storm::Environment &env, OptimizationDirection dir, storm::storage::SparseMatrix< ValueType > const &transitions)
std::vector< ValueType > computeBoundedUntilProbabilitiesImca(Environment const &env, OptimizationDirection dir, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, std::vector< ValueType > const &exitRateVector, storm::storage::BitVector const &markovianStates, storm::storage::BitVector const &psiStates, std::pair< double, std::optional< double > > const &boundsPair)
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
bool hasCycle(storm::storage::SparseMatrix< T > const &transitionMatrix, boost::optional< storm::storage::BitVector > const &subsystem)
Returns true if the graph represented by the given matrix has a cycle.
Definition graph.cpp:137
storm::storage::BitVector performProb0A(storm::storage::SparseMatrix< T > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates)
Definition graph.cpp:732
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
FoxGlynnResult< ValueType > foxGlynn(ValueType lambda, ValueType epsilon)
bool isTerminate()
Check whether the program should terminate (due to some abort signal).
VT min_if(std::vector< VT > const &values, storm::storage::BitVector const &filter)
Computes the minimum of the entries from the values that are selected by the (non-empty) filter.
Definition vector.h:592
void addVectors(std::vector< InValueType1 > const &firstOperand, std::vector< InValueType2 > const &secondOperand, std::vector< OutValueType > &target)
Adds the two given vectors and writes the result to the target vector.
Definition vector.h:400
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
bool equalModuloPrecision(T const &val1, T const &val2, T const &precision, bool relativeError=true)
Compares the given elements and determines whether they are equal modulo the given precision.
Definition vector.h:732
void reduceVectorMinOrMax(storm::solver::OptimizationDirection dir, std::vector< T > const &source, std::vector< T > &target, std::vector< uint_fast64_t > const &rowGrouping, std::vector< uint_fast64_t > *choices=nullptr)
Reduces the given source vector by selecting either the smallest or the largest out of each row group...
Definition vector.h:712
void addScaledVector(std::vector< InValueType1 > &firstOperand, std::vector< InValueType2 > const &secondOperand, InValueType3 const &factor)
Computes x:= x + a*y, i.e., adds each element of the first vector and (the corresponding element of t...
Definition vector.h:461
void scaleVectorInPlace(std::vector< ValueType1 > &target, ValueType2 const &factor)
Multiplies each element of the given vector with the given factor and writes the result into the vect...
Definition vector.h:448
bool hasNonZeroEntry(std::vector< T > const &v)
Definition vector.h:1142
std::vector< Type > filterVector(std::vector< Type > const &in, storm::storage::BitVector const &filter)
Definition vector.h:1069
bool isZero(ValueType const &a)
Definition constants.cpp:44
ValueType ceil(ValueType const &number)
ValueType zero()
Definition constants.cpp:26
ValueType one()
Definition constants.cpp:21
ValueType log(ValueType const &number)
TargetType convertNumber(SourceType const &number)
solver::OptimizationDirection OptimizationDirection