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