Storm
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
LraViHelper.cpp
Go to the documentation of this file.
1#include "LraViHelper.h"
2
4
7
12
16
18
19namespace storm {
20namespace modelchecker {
21namespace helper {
22namespace internal {
23
24template<typename ValueType, typename ComponentType, LraViTransitionsType TransitionsType>
26 storm::storage::SparseMatrix<ValueType> const& transitionMatrix,
27 ValueType const& aperiodicFactor, storm::storage::BitVector const* timedStates,
28 std::vector<ValueType> const* exitRates)
29 : _transitionMatrix(transitionMatrix),
30 _timedStates(timedStates),
31 _hasInstantStates(TransitionsType == LraViTransitionsType::DetTsNondetIs || TransitionsType == LraViTransitionsType::DetTsDetIs),
32 _Tsx1IsCurrent(false) {
33 setComponent(component);
34
35 // Run through the component and collect some data:
36 // We create two submodels, one consisting of the timed states of the component and one consisting of the instant states of the component.
37 // For this, we create a state index map that point from state indices of the input model to indices of the corresponding submodel of that state.
38 std::map<uint64_t, uint64_t> toSubModelStateMapping;
39 // We also obtain state and choices counts of the two submodels
40 uint64_t numTsSubModelStates(0), numTsSubModelChoices(0);
41 uint64_t numIsSubModelStates(0), numIsSubModelChoices(0);
42 // We will need to uniformize the timed MEC states by introducing a selfloop.
43 // For this, we need to find a uniformization rate which will be a little higher (given by aperiodicFactor) than the maximum rate occurring in the
44 // component.
45 _uniformizationRate = exitRates == nullptr ? storm::utility::one<ValueType>() : storm::utility::zero<ValueType>();
46 // Now run over the MEC and collect the required data.
47 for (auto const& element : _component) {
48 uint64_t componentState = element.first;
49 if (isTimedState(componentState)) {
50 toSubModelStateMapping.emplace(componentState, numTsSubModelStates);
51 ++numTsSubModelStates;
52 numTsSubModelChoices += element.second.size();
53 STORM_LOG_ASSERT(nondetTs() || element.second.size() == 1, "Timed state has multiple choices but only a single choice was expected.");
54 if (exitRates) {
55 _uniformizationRate = std::max(_uniformizationRate, (*exitRates)[componentState]);
56 }
57 } else {
58 toSubModelStateMapping.emplace(componentState, numIsSubModelStates);
59 ++numIsSubModelStates;
60 numIsSubModelChoices += element.second.size();
61 STORM_LOG_ASSERT(nondetIs() || element.second.size() == 1, "Instant state has multiple choices but only a single choice was expected.");
62 }
63 }
64 assert(numIsSubModelStates + numTsSubModelStates == _component.size());
65 assert(_hasInstantStates || numIsSubModelStates == 0);
66 STORM_LOG_ASSERT(nondetTs() || numTsSubModelStates == numTsSubModelChoices, "Unexpected choice count of deterministic timed submodel.");
67 STORM_LOG_ASSERT(nondetIs() || numIsSubModelStates == numIsSubModelChoices, "Unexpected choice count of deterministic instant submodel.");
68 _hasInstantStates = _hasInstantStates && numIsSubModelStates > 0;
70 numTsSubModelStates > 0, storm::exceptions::InvalidOperationException,
71 "Bottom Component has no timed states. Computation of Long Run Average values not supported. Is this a Markov Automaton with Zeno behavior?");
72
73 // We make sure that every timed state gets a selfloop to make the model aperiodic
74 _uniformizationRate *= storm::utility::one<ValueType>() + aperiodicFactor;
75
76 // Now build the timed and the instant submodels.
77 // In addition, we also need the transitions between the two.
78 storm::storage::SparseMatrixBuilder<ValueType> tsTransitionsBuilder(numTsSubModelChoices, numTsSubModelStates, 0, true, nondetTs(),
79 nondetTs() ? numTsSubModelStates : 0);
80 storm::storage::SparseMatrixBuilder<ValueType> tsToIsTransitionsBuilder, isTransitionsBuilder, isToTsTransitionsBuilder;
81 if (_hasInstantStates) {
82 tsToIsTransitionsBuilder = storm::storage::SparseMatrixBuilder<ValueType>(numTsSubModelChoices, numIsSubModelStates, 0, true, nondetTs(),
83 nondetTs() ? numTsSubModelStates : 0);
84 isTransitionsBuilder = storm::storage::SparseMatrixBuilder<ValueType>(numIsSubModelChoices, numIsSubModelStates, 0, true, nondetIs(),
85 nondetIs() ? numIsSubModelStates : 0);
86 isToTsTransitionsBuilder = storm::storage::SparseMatrixBuilder<ValueType>(numIsSubModelChoices, numTsSubModelStates, 0, true, nondetIs(),
87 nondetIs() ? numIsSubModelStates : 0);
88 _IsChoiceValues.reserve(numIsSubModelChoices);
89 }
90 ValueType uniformizationFactor = storm::utility::one<ValueType>() / _uniformizationRate;
91 uint64_t currTsRow = 0;
92 uint64_t currIsRow = 0;
93 for (auto const& element : _component) {
94 uint64_t componentState = element.first;
95 if (isTimedState(componentState)) {
96 // The currently processed state is timed.
97 if (nondetTs()) {
98 tsTransitionsBuilder.newRowGroup(currTsRow);
99 if (_hasInstantStates) {
100 tsToIsTransitionsBuilder.newRowGroup(currTsRow);
101 }
102 }
103 // If there are exit rates, the uniformization factor needs to be updated.
104 if (exitRates) {
105 uniformizationFactor = (*exitRates)[componentState] / _uniformizationRate;
106 }
107 // We need to uniformize which means that a diagonal entry for the selfloop will be inserted.
108 ValueType selfLoopProb = storm::utility::one<ValueType>() - uniformizationFactor;
109 for (auto const& componentChoice : element.second) {
110 tsTransitionsBuilder.addDiagonalEntry(currTsRow, selfLoopProb);
111 for (auto const& entry : this->_transitionMatrix.getRow(componentChoice)) {
112 uint64_t subModelColumn = toSubModelStateMapping[entry.getColumn()];
113 if (isTimedState(entry.getColumn())) {
114 // We have a transition from a timed state to a timed state
115 STORM_LOG_ASSERT(subModelColumn < numTsSubModelStates, "Invalid state for timed submodel");
116 tsTransitionsBuilder.addNextValue(currTsRow, subModelColumn, uniformizationFactor * entry.getValue());
117 } else {
118 // We have a transition from a timed to a instant state
119 STORM_LOG_ASSERT(subModelColumn < numIsSubModelStates, "Invalid state for instant submodel");
120 tsToIsTransitionsBuilder.addNextValue(currTsRow, subModelColumn, uniformizationFactor * entry.getValue());
121 }
122 }
123 ++currTsRow;
124 }
125 } else {
126 // The currently processed state is instant
127 if (nondetIs()) {
128 isTransitionsBuilder.newRowGroup(currIsRow);
129 isToTsTransitionsBuilder.newRowGroup(currIsRow);
130 }
131 for (auto const& componentChoice : element.second) {
132 for (auto const& entry : this->_transitionMatrix.getRow(componentChoice)) {
133 uint64_t subModelColumn = toSubModelStateMapping[entry.getColumn()];
134 if (isTimedState(entry.getColumn())) {
135 // We have a transition from an instant state to a timed state
136 STORM_LOG_ASSERT(subModelColumn < numTsSubModelStates, "Invalid state for timed submodel");
137 isToTsTransitionsBuilder.addNextValue(currIsRow, subModelColumn, entry.getValue());
138 } else {
139 // We have a transition from an instant to an instant state
140 STORM_LOG_ASSERT(subModelColumn < numIsSubModelStates, "Invalid state for instant submodel");
141 isTransitionsBuilder.addNextValue(currIsRow, subModelColumn, entry.getValue());
142 }
143 }
144 ++currIsRow;
145 }
146 }
147 }
148 _TsTransitions = tsTransitionsBuilder.build();
149 if (_hasInstantStates) {
150 _TsToIsTransitions = tsToIsTransitionsBuilder.build();
151 _IsTransitions = isTransitionsBuilder.build();
152 _IsToTsTransitions = isToTsTransitionsBuilder.build();
153 }
154}
155
156template<typename ValueType, typename ComponentType, LraViTransitionsType TransitionsType>
158 _component.clear();
159 for (auto const& element : component) {
160 uint64_t componentState = getComponentElementState(element);
161 std::set<uint64_t> componentChoices;
162 for (auto componentChoiceIt = getComponentElementChoicesBegin(element); componentChoiceIt != getComponentElementChoicesEnd(element);
163 ++componentChoiceIt) {
164 componentChoices.insert(*componentChoiceIt);
165 }
166 _component.emplace(std::move(componentState), std::move(componentChoices));
167 }
168}
169
170template<typename ValueType, typename ComponentType, LraViTransitionsType TransitionsType>
172 ValueGetter const& actionValueGetter,
173 std::vector<ValueType> const* exitRates,
175 std::vector<uint64_t>* choices) {
176 initializeNewValues(stateValueGetter, actionValueGetter, exitRates);
177 ValueType precision = storm::utility::convertNumber<ValueType>(env.solver().lra().getPrecision());
178 bool relative = env.solver().lra().getRelativeTerminationCriterion();
179 boost::optional<uint64_t> maxIter;
180 if (env.solver().lra().isMaximalIterationCountSet()) {
181 maxIter = env.solver().lra().getMaximalIterationCount();
182 }
183
184 // start the iterations
185 ValueType result = storm::utility::zero<ValueType>();
186 uint64_t iter = 0;
187 while (!maxIter.is_initialized() || iter < maxIter.get()) {
188 ++iter;
189 performIterationStep(env, dir);
190
191 // Check if we are done
192 auto convergenceCheckResult = checkConvergence(relative, precision);
193 result = convergenceCheckResult.currentValue;
194 if (convergenceCheckResult.isPrecisionAchieved) {
195 break;
196 }
198 break;
199 }
200 // If there will be a next iteration, we have to prepare it.
201 prepareNextIteration(env);
202 }
203 if (maxIter.is_initialized() && iter == maxIter.get()) {
204 STORM_LOG_WARN("LRA computation did not converge within " << iter << " iterations.");
206 STORM_LOG_WARN("LRA computation aborted after " << iter << " iterations.");
207 } else {
208 STORM_LOG_TRACE("LRA computation converged after " << iter << " iterations.");
209 }
210
211 if (choices) {
212 // We will be doing one more iteration step and track scheduler choices this time.
213 prepareNextIteration(env);
214 performIterationStep(env, dir, choices);
215 }
216 return result;
217}
218
219template<typename ValueType, typename ComponentType, LraViTransitionsType TransitionsType>
220void LraViHelper<ValueType, ComponentType, TransitionsType>::initializeNewValues(ValueGetter const& stateValueGetter, ValueGetter const& actionValueGetter,
221 std::vector<ValueType> const* exitRates) {
222 // clear potential old values and reserve enough space for new values
223 _TsChoiceValues.clear();
224 _TsChoiceValues.reserve(_TsTransitions.getRowCount());
225 if (_hasInstantStates) {
226 _IsChoiceValues.clear();
227 _IsChoiceValues.reserve(_IsTransitions.getRowCount());
228 }
229
230 // Set the new choice-based values
231 ValueType actionRewardScalingFactor = storm::utility::one<ValueType>() / _uniformizationRate;
232 for (auto const& element : _component) {
233 uint64_t componentState = element.first;
234 if (isTimedState(componentState)) {
235 if (exitRates) {
236 actionRewardScalingFactor = (*exitRates)[componentState] / _uniformizationRate;
237 }
238 for (auto const& componentChoice : element.second) {
239 // Compute the values obtained for this choice.
240 _TsChoiceValues.push_back(stateValueGetter(componentState) / _uniformizationRate +
241 actionValueGetter(componentChoice) * actionRewardScalingFactor);
242 }
243 } else {
244 for (auto const& componentChoice : element.second) {
245 // Compute the values obtained for this choice.
246 // State values do not count here since no time passes in instant states.
247 _IsChoiceValues.push_back(actionValueGetter(componentChoice));
248 }
249 }
250 }
251
252 // Set-up new iteration vectors for timed states
253 _Tsx1.assign(_TsTransitions.getRowGroupCount(), storm::utility::zero<ValueType>());
254 _Tsx2 = _Tsx1;
255
256 if (_hasInstantStates) {
257 // Set-up vectors for storing intermediate results for instant states.
258 _Isx.resize(_IsTransitions.getRowGroupCount(), storm::utility::zero<ValueType>());
259 _Isb = _IsChoiceValues;
260 }
261}
262
263template<typename ValueType, typename ComponentType, LraViTransitionsType TransitionsType>
264void LraViHelper<ValueType, ComponentType, TransitionsType>::prepareSolversAndMultipliers(const Environment& env,
266 _TsMultiplier = storm::solver::MultiplierFactory<ValueType>().create(env, _TsTransitions);
267 if (_hasInstantStates) {
268 if (_IsTransitions.getNonzeroEntryCount() > 0) {
269 // Set-up a solver for transitions within instant states
270 _IsSolverEnv = std::make_unique<storm::Environment>(env);
271 if (env.solver().isForceSoundness()) {
272 // To get correct results, the inner equation systems are solved exactly.
273 // TODO investigate how an error would propagate
274 _IsSolverEnv->solver().setForceExact(true);
275 }
276 bool isAcyclic = !storm::utility::graph::hasCycle(_IsTransitions);
277 if (isAcyclic) {
278 STORM_LOG_INFO("Instant transitions are acyclic.");
279 _IsSolverEnv->solver().minMax().setMethod(storm::solver::MinMaxMethod::Acyclic);
280 _IsSolverEnv->solver().setLinearEquationSolverType(storm::solver::EquationSolverType::Acyclic);
281 }
282 if (nondetIs()) {
284 _NondetIsSolver = factory.create(*_IsSolverEnv, _IsTransitions);
285 _NondetIsSolver->setHasUniqueSolution(true); // Assume non-zeno MA
286 _NondetIsSolver->setHasNoEndComponents(true); // assume non-zeno MA
287 _NondetIsSolver->setCachingEnabled(true);
288 auto req = _NondetIsSolver->getRequirements(*_IsSolverEnv, *dir);
289 req.clearUniqueSolution();
290 if (isAcyclic) {
291 req.clearAcyclic();
292 }
293 // Computing a priori lower/upper bounds is not particularly easy, as there might be selfloops with high probabilities
294 // Which accumulate a lot of reward. Moreover, the right-hand-side of the equation system changes dynamically.
295 STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UnmetRequirementException,
296 "The solver requirement " << req.getEnabledRequirementsAsString() << " has not been cleared.");
297 _NondetIsSolver->setRequirementsChecked(true);
298 } else {
301 // We need to convert the transition matrix connecting instant states
302 // TODO: This could have been done already during construction of the matrix.
303 // Insert diagonal entries.
304 storm::storage::SparseMatrix<ValueType> converted(_IsTransitions, true);
305 // Compute A' = 1-A
306 converted.convertToEquationSystem();
307 STORM_LOG_WARN("The selected equation solver requires to create a temporary " << converted.getDimensionsAsString());
308 // Note that the solver has ownership of the converted matrix.
309 _DetIsSolver = factory.create(*_IsSolverEnv, std::move(converted));
310 } else {
311 _DetIsSolver = factory.create(*_IsSolverEnv, _IsTransitions);
312 }
313 _DetIsSolver->setCachingEnabled(true);
314 auto req = _DetIsSolver->getRequirements(*_IsSolverEnv);
315 if (isAcyclic) {
316 req.clearAcyclic();
317 }
318 // A priori lower/upper bounds are hard (see MinMax version of this above)
319 STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UnmetRequirementException,
320 "The solver requirement " << req.getEnabledRequirementsAsString() << " has not been cleared.");
321 }
322 }
323
324 // Set up multipliers for transitions connecting timed and instant states
325 _TsToIsMultiplier = storm::solver::MultiplierFactory<ValueType>().create(env, _TsToIsTransitions);
326 _IsToTsMultiplier = storm::solver::MultiplierFactory<ValueType>().create(env, _IsToTsTransitions);
327 }
328}
329
330template<typename ValueType, typename ComponentType, LraViTransitionsType TransitionsType>
331void LraViHelper<ValueType, ComponentType, TransitionsType>::setInputModelChoices(std::vector<uint64_t>& choices, std::vector<uint64_t> const& localMecChoices,
332 bool setChoiceZeroToTimedStates, bool setChoiceZeroToInstantStates) const {
333 // Transform the local choices (within this mec) to choice indices for the input model
334 uint64_t localState = 0;
335 for (auto const& element : _component) {
336 uint64_t elementState = element.first;
337 if ((setChoiceZeroToTimedStates && isTimedState(elementState)) || (setChoiceZeroToInstantStates && !isTimedState(elementState))) {
338 choices[elementState] = 0;
339 } else {
340 uint64_t choice = localMecChoices[localState];
341 STORM_LOG_ASSERT(choice < element.second.size(), "The selected choice does not seem to exist.");
342 auto globalChoiceIndexIt = element.second.begin();
343 for (uint64_t i = 0; i < choice; ++i) {
344 ++globalChoiceIndexIt;
345 }
346 uint64_t globalChoiceIndex = *(globalChoiceIndexIt);
347 choices[elementState] = globalChoiceIndex - _transitionMatrix.getRowGroupIndices()[elementState];
348 ++localState;
349 }
350 }
351 STORM_LOG_ASSERT(localState == localMecChoices.size(), "Did not traverse all component states.");
352}
353
354template<typename ValueType, typename ComponentType, LraViTransitionsType TransitionsType>
355void LraViHelper<ValueType, ComponentType, TransitionsType>::performIterationStep(Environment const& env, storm::solver::OptimizationDirection const* dir,
356 std::vector<uint64_t>* choices) {
357 STORM_LOG_ASSERT(!((nondetTs() || nondetIs()) && dir == nullptr), "No optimization direction provided for model with nondeterminism");
358 // Initialize value vectors, multiplers, and solver if this has not been done, yet
359 if (!_TsMultiplier) {
360 prepareSolversAndMultipliers(env, dir);
361 }
362
363 // Compute new x values for the timed states
364 // Flip what is new and what is old
365 _Tsx1IsCurrent = !_Tsx1IsCurrent;
366 // At this point, xOld() points to what has been computed in the most recent call of performIterationStep (initially, this is the 0-vector).
367 // The result of this ongoing computation will be stored in xNew()
368
369 // Compute the values obtained by a single uniformization step between timed states only
370 if (nondetTs()) {
371 if (choices == nullptr) {
372 _TsMultiplier->multiplyAndReduce(env, *dir, xOld(), &_TsChoiceValues, xNew());
373 } else {
374 // Also keep track of the choices made.
375 std::vector<uint64_t> tsChoices(_TsTransitions.getRowGroupCount());
376 _TsMultiplier->multiplyAndReduce(env, *dir, xOld(), &_TsChoiceValues, xNew(), &tsChoices);
377 // Note that nondeterminism within the timed states means that there can not be instant states (We either have MDPs or MAs)
378 // Hence, in this branch we don't have to care for choices at instant states.
379 STORM_LOG_ASSERT(!_hasInstantStates, "Nondeterministic timed states are only supported if there are no instant states.");
380 setInputModelChoices(*choices, tsChoices);
381 }
382 } else {
383 _TsMultiplier->multiply(env, xOld(), &_TsChoiceValues, xNew());
384 }
385 if (_hasInstantStates) {
386 // Add the values obtained by taking a single uniformization step that leads to an instant state followed by arbitrarily many instant steps.
387 // First compute the total values when taking arbitrarily many instant transitions (in no time)
388 if (_NondetIsSolver) {
389 // We might need to track the optimal choices.
390 if (choices == nullptr) {
391 _NondetIsSolver->solveEquations(*_IsSolverEnv, *dir, _Isx, _Isb);
392 } else {
393 _NondetIsSolver->setTrackScheduler();
394 _NondetIsSolver->solveEquations(*_IsSolverEnv, *dir, _Isx, _Isb);
395 setInputModelChoices(*choices, _NondetIsSolver->getSchedulerChoices(), true);
396 }
397 } else if (_DetIsSolver) {
398 _DetIsSolver->solveEquations(*_IsSolverEnv, _Isx, _Isb);
399 } else {
400 STORM_LOG_ASSERT(_IsTransitions.getNonzeroEntryCount() == 0, "If no solver was initialized, an empty matrix would have been expected.");
401 if (nondetIs()) {
402 if (choices == nullptr) {
403 storm::utility::vector::reduceVectorMinOrMax(*dir, _Isb, _Isx, _IsTransitions.getRowGroupIndices());
404 } else {
405 std::vector<uint64_t> psChoices(_IsTransitions.getRowGroupCount());
406 storm::utility::vector::reduceVectorMinOrMax(*dir, _Isb, _Isx, _IsTransitions.getRowGroupIndices(), &psChoices);
407 setInputModelChoices(*choices, psChoices, true);
408 }
409 } else {
410 // For deterministic instant states, there is nothing to reduce, i.e., we could just set _Isx = _Isb.
411 // For efficiency reasons, we do a swap instead:
412 _Isx.swap(_Isb);
413 // Note that at this point we have changed the contents of _Isb, but they will be overwritten anyway.
414 if (choices) {
415 // Set choice 0 to all states.
416 setInputModelChoices(*choices, {}, true, true);
417 }
418 }
419 }
420 // Now add the (weighted) values of the instant states to the values of the timed states.
421 _TsToIsMultiplier->multiply(env, _Isx, &xNew(), xNew());
422 }
423}
424
425template<typename ValueType, typename ComponentType, LraViTransitionsType TransitionsType>
426typename LraViHelper<ValueType, ComponentType, TransitionsType>::ConvergenceCheckResult
427LraViHelper<ValueType, ComponentType, TransitionsType>::checkConvergence(bool relative, ValueType precision) const {
428 STORM_LOG_ASSERT(_TsMultiplier, "tried to check for convergence without doing an iteration first.");
429 // All values are scaled according to the uniformizationRate.
430 // We need to 'revert' this scaling when computing the absolute precision.
431 // However, for relative precision, the scaling cancels out.
432 ValueType threshold = relative ? precision : ValueType(precision / _uniformizationRate);
433
434 ConvergenceCheckResult res = {true, storm::utility::one<ValueType>()};
435 // Now check whether the currently produced results are precise enough
436 STORM_LOG_ASSERT(threshold > storm::utility::zero<ValueType>(), "Did not expect a non-positive threshold.");
437 auto x1It = xOld().begin();
438 auto x1Ite = xOld().end();
439 auto x2It = xNew().begin();
440 ValueType maxDiff = (*x2It - *x1It);
441 ValueType minDiff = maxDiff;
442 // The difference between maxDiff and minDiff is zero at this point. Thus, it doesn't make sense to check the threshold now.
443 for (++x1It, ++x2It; x1It != x1Ite; ++x1It, ++x2It) {
444 ValueType diff = (*x2It - *x1It);
445 // Potentially update maxDiff or minDiff
446 bool skipCheck = false;
447 if (maxDiff < diff) {
448 maxDiff = diff;
449 } else if (minDiff > diff) {
450 minDiff = diff;
451 } else {
452 skipCheck = true;
453 }
454 // Check convergence
455 if (!skipCheck && (maxDiff - minDiff) > (relative ? (threshold * minDiff) : threshold)) {
456 res.isPrecisionAchieved = false;
457 break;
458 }
459 }
460
461 // Compute the average of the maximal and the minimal difference.
462 ValueType avgDiff = (maxDiff + minDiff) / (storm::utility::convertNumber<ValueType>(2.0));
463
464 // "Undo" the scaling of the values
465 res.currentValue = avgDiff * _uniformizationRate;
466 return res;
467}
468
469template<typename ValueType, typename ComponentType, LraViTransitionsType TransitionsType>
470void LraViHelper<ValueType, ComponentType, TransitionsType>::prepareNextIteration(Environment const& env) {
471 // To avoid large (and numerically unstable) x-values, we substract a reference value.
472 ValueType referenceValue = xNew().front();
473 storm::utility::vector::applyPointwise<ValueType, ValueType>(xNew(), xNew(),
474 [&referenceValue](ValueType const& x_i) -> ValueType { return x_i - referenceValue; });
475 if (_hasInstantStates) {
476 // Update the RHS of the equation system for the instant states by taking the new values of timed states into account.
477 STORM_LOG_ASSERT(!nondetTs(), "Nondeterministic timed states not expected when there are also instant states.");
478 _IsToTsMultiplier->multiply(env, xNew(), &_IsChoiceValues, _Isb);
479 }
480}
481
482template<typename ValueType, typename ComponentType, LraViTransitionsType TransitionsType>
483bool LraViHelper<ValueType, ComponentType, TransitionsType>::isTimedState(uint64_t const& inputModelStateIndex) const {
484 STORM_LOG_ASSERT(!_hasInstantStates || _timedStates != nullptr, "Model has instant states but no partition into timed and instant states is given.");
485 STORM_LOG_ASSERT(!_hasInstantStates || inputModelStateIndex < _timedStates->size(),
486 "Unable to determine whether state " << inputModelStateIndex << " is timed.");
487 return !_hasInstantStates || _timedStates->get(inputModelStateIndex);
488}
489
490template<typename ValueType, typename ComponentType, LraViTransitionsType TransitionsType>
491std::vector<ValueType>& LraViHelper<ValueType, ComponentType, TransitionsType>::xNew() {
492 return _Tsx1IsCurrent ? _Tsx1 : _Tsx2;
493}
494
495template<typename ValueType, typename ComponentType, LraViTransitionsType TransitionsType>
496std::vector<ValueType> const& LraViHelper<ValueType, ComponentType, TransitionsType>::xNew() const {
497 return _Tsx1IsCurrent ? _Tsx1 : _Tsx2;
498}
499
500template<typename ValueType, typename ComponentType, LraViTransitionsType TransitionsType>
501std::vector<ValueType>& LraViHelper<ValueType, ComponentType, TransitionsType>::xOld() {
502 return _Tsx1IsCurrent ? _Tsx2 : _Tsx1;
503}
504
505template<typename ValueType, typename ComponentType, LraViTransitionsType TransitionsType>
506std::vector<ValueType> const& LraViHelper<ValueType, ComponentType, TransitionsType>::xOld() const {
507 return _Tsx1IsCurrent ? _Tsx2 : _Tsx1;
508}
509
510template<typename ValueType, typename ComponentType, LraViTransitionsType TransitionsType>
511bool LraViHelper<ValueType, ComponentType, TransitionsType>::nondetTs() const {
512 return TransitionsType == LraViTransitionsType::NondetTsNoIs;
513}
514
515template<typename ValueType, typename ComponentType, LraViTransitionsType TransitionsType>
516bool LraViHelper<ValueType, ComponentType, TransitionsType>::nondetIs() const {
517 return TransitionsType == LraViTransitionsType::DetTsNondetIs;
518}
519
520template class LraViHelper<double, storm::storage::MaximalEndComponent, LraViTransitionsType::NondetTsNoIs>;
521template class LraViHelper<storm::RationalNumber, storm::storage::MaximalEndComponent, LraViTransitionsType::NondetTsNoIs>;
522template class LraViHelper<double, storm::storage::MaximalEndComponent, LraViTransitionsType::DetTsNondetIs>;
523template class LraViHelper<storm::RationalNumber, storm::storage::MaximalEndComponent, LraViTransitionsType::DetTsNondetIs>;
524
525template class LraViHelper<double, storm::storage::StronglyConnectedComponent, LraViTransitionsType::DetTsNoIs>;
526template class LraViHelper<storm::RationalNumber, storm::storage::StronglyConnectedComponent, LraViTransitionsType::DetTsNoIs>;
527
528} // namespace internal
529} // namespace helper
530} // namespace modelchecker
531} // namespace storm
SolverEnvironment & solver()
storm::RationalNumber const & getPrecision() const
LongRunAverageSolverEnvironment & lra()
Helper class that performs iterations of the value iteration method.
Definition LraViHelper.h:42
ValueType performValueIteration(Environment const &env, ValueGetter const &stateValueGetter, ValueGetter const &actionValueGetter, std::vector< ValueType > const *exitRates=nullptr, storm::solver::OptimizationDirection const *dir=nullptr, std::vector< uint64_t > *choices=nullptr)
Performs value iteration with the given state- and action values.
LraViHelper(ComponentType const &component, storm::storage::SparseMatrix< ValueType > const &transitionMatrix, ValueType const &aperiodicFactor, storm::storage::BitVector const *timedStates=nullptr, std::vector< ValueType > const *exitRates=nullptr)
Initializes a new VI helper for the provided MEC or BSCC.
std::function< ValueType(uint64_t)> ValueGetter
Function mapping from indices to values.
Definition LraViHelper.h:45
virtual std::unique_ptr< LinearEquationSolver< ValueType > > create(Environment const &env) const override
Creates an equation solver with the current settings, but without a matrix.
virtual std::unique_ptr< MinMaxLinearEquationSolver< ValueType, SolutionType > > create(Environment const &env) const override
virtual LinearEquationSolverProblemFormat getEquationProblemFormat(Environment const &env) const
Retrieves the problem format that the solver expects if it was created with the current settings.
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
A class that can be used to build a sparse matrix by adding value by value.
void addNextValue(index_type row, index_type column, value_type const &value)
Sets the matrix entry at the given row and column to the given value.
void newRowGroup(index_type startingRow)
Starts a new row group in the matrix.
void addDiagonalEntry(index_type row, ValueType const &value)
Makes sure that a diagonal entry will be inserted at the given row.
SparseMatrix< value_type > build(index_type overriddenRowCount=0, index_type overriddenColumnCount=0, index_type overriddenRowGroupCount=0)
A class that holds a possibly non-square matrix in the compressed row storage format.
#define STORM_LOG_INFO(message)
Definition logging.h:29
#define STORM_LOG_WARN(message)
Definition logging.h:30
#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
uint64_t getComponentElementState(typename storm::storage::StronglyConnectedComponent::value_type const &element)
Auxiliary functions that deal with the different kinds of components (MECs on potentially nondetermin...
uint64_t const * getComponentElementChoicesEnd(typename storm::storage::StronglyConnectedComponent::value_type const &element)
LraViTransitionsType
Specifies differnt kinds of transition types with which this helper can be used Ts means timed states...
Definition LraViHelper.h:22
@ NondetTsNoIs
deterministic choice at timed states, deterministic choice at instant states (as in Markov Automata w...
@ DetTsNondetIs
deterministic choice at timed states, no instant states (as in DTMCs and CTMCs)
@ DetTsDetIs
deterministic choice at timed states, nondeterministic choice at instant states (as in Markov Automat...
uint64_t const * getComponentElementChoicesBegin(typename storm::storage::StronglyConnectedComponent::value_type const &element)
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
bool isTerminate()
Check whether the program should terminate (due to some abort signal).
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
LabParser.cpp.
Definition cli.cpp:18