Storm
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
ExplicitDFTModelBuilder.cpp
Go to the documentation of this file.
2
3#include <map>
4
17
19
20namespace storm::dft {
21namespace builder {
22
23template<typename ValueType, typename StateType>
24ExplicitDFTModelBuilder<ValueType, StateType>::ModelComponents::ModelComponents()
25 : transitionMatrix(), stateLabeling(), markovianStates(), exitRates(), choiceLabeling() {
26 // Intentionally left empty.
27}
28
29template<typename ValueType, typename StateType>
30ExplicitDFTModelBuilder<ValueType, StateType>::MatrixBuilder::MatrixBuilder(bool canHaveNondeterminism)
31 : mappingOffset(0), stateRemapping(), currentRowGroup(0), currentRow(0), canHaveNondeterminism((canHaveNondeterminism)) {
32 // Create matrix builder
33 builder = storm::storage::SparseMatrixBuilder<ValueType>(0, 0, 0, false, canHaveNondeterminism, 0);
34}
35
36template<typename ValueType, typename StateType>
38 storm::dft::storage::DftSymmetries const& symmetries)
39 : dft(dft),
40 stateGenerationInfo(std::make_shared<storm::dft::storage::DFTStateGenerationInfo>(dft.buildStateGenerationInfo(symmetries))),
41 generator(dft, *stateGenerationInfo),
42 matrixBuilder(!generator.isDeterministicModel()),
43 stateStorage(dft.stateBitVectorSize()),
44 explorationQueue(1, 0, 0.9, false) {
45 // Set relevant events
46 STORM_LOG_DEBUG("Relevant events: " << this->dft.getRelevantEventsString());
47 if (dft.getRelevantEvents().size() <= 1) {
48 STORM_LOG_ASSERT(dft.getRelevantEvents()[0] == dft.getTopLevelIndex(), "TLE is not relevant");
49 // Only interested in top level event -> introduce unique failed state
50 this->uniqueFailedState = true;
51 STORM_LOG_DEBUG("Using unique failed state with id 0.");
52 }
53
54 // Compute independent subtrees
56 // We only support this for approximation with top level element OR
57 for (auto const& child : dft.getGate(dft.getTopLevelIndex())->children()) {
58 // Consider all children of the top level gate
59 std::vector<size_t> isubdft;
60 if (child->nrParents() > 1 || child->hasOutgoingDependencies()) {
61 STORM_LOG_TRACE("child " << child->name() << " does not allow modularisation.");
62 isubdft.clear();
63 } else if (dft.isGate(child->id())) {
64 isubdft = dft.getGate(child->id())->independentSubDft(false);
65 } else {
66 STORM_LOG_ASSERT(dft.isBasicElement(child->id()), "Child is no BE.");
67 if (dft.getBasicElement(child->id())->hasIngoingDependencies()) {
68 STORM_LOG_TRACE("child " << child->name() << " does not allow modularisation.");
69 isubdft.clear();
70 } else {
71 isubdft = {child->id()};
72 }
73 }
74 if (isubdft.empty()) {
75 subtreeBEs.clear();
76 break;
77 } else {
78 // Add new independent subtree
79 std::vector<size_t> subtree;
80 for (size_t id : isubdft) {
81 if (dft.isBasicElement(id)) {
82 subtree.push_back(id);
83 }
84 }
85 subtreeBEs.push_back(subtree);
86 }
87 }
88 }
89 if (subtreeBEs.empty()) {
90 // Consider complete tree
91 std::vector<size_t> subtree;
92 for (size_t id = 0; id < dft.nrElements(); ++id) {
93 if (dft.isBasicElement(id)) {
94 subtree.push_back(id);
95 }
96 }
97 subtreeBEs.push_back(subtree);
98 }
99
100 for (auto tree : subtreeBEs) {
101 std::stringstream stream;
102 stream << "Subtree: ";
103 for (size_t id : tree) {
104 stream << id << ", ";
105 }
106 STORM_LOG_TRACE(stream.str());
107 }
108}
109
110template<typename ValueType, typename StateType>
111void ExplicitDFTModelBuilder<ValueType, StateType>::buildModel(size_t iteration, double approximationThreshold,
112 storm::dft::builder::ApproximationHeuristic approximationHeuristic) {
113 STORM_LOG_TRACE("Generating DFT state space");
114 usedHeuristic = approximationHeuristic;
115
116 if (approximationThreshold > 0 && !this->uniqueFailedState) {
117 // Approximation requires unique failed states
118 // TODO lift this restriction
119 STORM_LOG_WARN("Approximation requires unique failed state. Forcing use of unique failed state.");
120 this->uniqueFailedState = true;
121 }
122
123 if (iteration < 1) {
124 // Initialize
125 switch (usedHeuristic) {
127 explorationQueue = storm::dft::storage::BucketPriorityQueue<ExplorationHeuristic>(dft.nrElements() + 1, 0, 0.9, false);
128 break;
130 explorationQueue = storm::dft::storage::BucketPriorityQueue<ExplorationHeuristic>(200, 0, 0.9, true);
131 break;
133 explorationQueue = storm::dft::storage::BucketPriorityQueue<ExplorationHeuristic>(200, 0, 0.9, true);
134 break;
135 default:
136 STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentException, "Heuristic not known.");
137 }
138 modelComponents.markovianStates = storm::storage::BitVector(INITIAL_BITVECTOR_SIZE);
139
140 if (this->uniqueFailedState) {
141 // Introduce explicit fail state
142 storm::generator::StateBehavior<ValueType, StateType> behavior = generator.createMergeFailedState([this](DFTStatePointer const& state) {
143 size_t failedStateId = newIndex++;
144 STORM_LOG_ASSERT(failedStateId == 0, "Unique failed id is not 0.");
145 matrixBuilder.stateRemapping.push_back(0);
146 return failedStateId;
147 });
148
149 matrixBuilder.setRemapping(0);
150 STORM_LOG_ASSERT(!behavior.empty(), "Behavior is empty.");
151 matrixBuilder.newRowGroup();
152 setMarkovian(behavior.begin()->isMarkovian());
153
154 // Now add self loop.
155 // TODO: maybe use general method.
156 STORM_LOG_ASSERT(behavior.getNumberOfChoices() == 1, "Wrong number of choices for failed state.");
157 STORM_LOG_ASSERT(behavior.begin()->size() == 1, "Wrong number of transitions for failed state.");
158 std::pair<StateType, ValueType> stateProbabilityPair = *(behavior.begin()->begin());
159 STORM_LOG_ASSERT(stateProbabilityPair.first == 0, "No self loop for failed state.");
160 STORM_LOG_ASSERT(storm::utility::isOne<ValueType>(stateProbabilityPair.second), "Probability for failed state != 1.");
161 matrixBuilder.addTransition(stateProbabilityPair.first, stateProbabilityPair.second);
162 matrixBuilder.finishRow();
163 }
164
165 // Build initial state
166 this->stateStorage.initialStateIndices =
167 generator.getInitialStates(std::bind(&ExplicitDFTModelBuilder::getOrAddStateIndex, this, std::placeholders::_1));
168 STORM_LOG_ASSERT(stateStorage.initialStateIndices.size() == 1, "Only one initial state assumed.");
169 initialStateIndex = stateStorage.initialStateIndices[0];
170 STORM_LOG_TRACE("Initial state: " << initialStateIndex);
171
172 // DFT may be instantly failed due to a constant failure
173 // in this case a model only consisting of the uniqueFailedState suffices
174 if (initialStateIndex == 0 && this->uniqueFailedState) {
175 modelComponents.markovianStates.resize(1);
176 modelComponents.deterministicModel = generator.isDeterministicModel();
177
178 STORM_LOG_TRACE("Markovian states: " << modelComponents.markovianStates);
179 STORM_LOG_DEBUG("Model has 1 state");
180 STORM_LOG_DEBUG("Model is " << (generator.isDeterministicModel() ? "deterministic" : "non-deterministic"));
181
182 // Build transition matrix
183 modelComponents.transitionMatrix = matrixBuilder.builder.build(1, 1);
184 STORM_LOG_TRACE("Transition matrix: \n" << modelComponents.transitionMatrix);
185
186 buildLabeling();
187 return;
188 }
189
190 // Initialize heuristic values for inital state
191 STORM_LOG_ASSERT(!statesNotExplored.at(initialStateIndex).second, "Heuristic for initial state is already initialized");
192 ExplorationHeuristicPointer heuristic;
193 switch (usedHeuristic) {
195 heuristic = std::make_shared<DFTExplorationHeuristicDepth<ValueType>>(initialStateIndex);
196 break;
198 heuristic = std::make_shared<DFTExplorationHeuristicProbability<ValueType>>(initialStateIndex);
199 break;
201 heuristic = std::make_shared<DFTExplorationHeuristicBoundDifference<ValueType>>(initialStateIndex);
202 break;
203 default:
204 STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentException, "Heuristic not known.");
205 }
206 heuristic->markExpand();
207 statesNotExplored[initialStateIndex].second = heuristic;
208 explorationQueue.push(heuristic);
209 } else {
210 initializeNextIteration();
211 }
212
213 if (approximationThreshold > 0.0) {
214 switch (usedHeuristic) {
216 approximationThreshold = iteration + 1;
217 break;
220 approximationThreshold = std::pow(2, -(double)iteration); // Need conversion to avoid overflow when negating
221 break;
222 default:
223 STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentException, "Heuristic not known.");
224 }
225 }
226
228 if (ftSettings.isMaxDepthSet()) {
229 STORM_LOG_ASSERT(usedHeuristic == storm::dft::builder::ApproximationHeuristic::DEPTH, "MaxDepth requires 'depth' exploration heuristic.");
230 approximationThreshold = ftSettings.getMaxDepth();
231 }
232
233 exploreStateSpace(approximationThreshold);
234
235 size_t stateSize = stateStorage.getNumberOfStates() + (this->uniqueFailedState ? 1 : 0);
236 modelComponents.markovianStates.resize(stateSize);
237 modelComponents.deterministicModel = generator.isDeterministicModel();
238
239 // Fix the entries in the transition matrix according to the mapping of ids to row group indices
240 STORM_LOG_ASSERT(matrixBuilder.getRemapping(initialStateIndex) == initialStateIndex, "Initial state should not be remapped.");
241 // TODO: do not consider all rows?
242 STORM_LOG_TRACE("Remap matrix: " << matrixBuilder.stateRemapping << ", offset: " << matrixBuilder.mappingOffset);
243 matrixBuilder.remap();
244
245 STORM_LOG_TRACE("State remapping: " << matrixBuilder.stateRemapping);
246 STORM_LOG_TRACE("Markovian states: " << modelComponents.markovianStates);
247 STORM_LOG_DEBUG("Model has " << stateSize << " states");
248 STORM_LOG_DEBUG("Model is " << (generator.isDeterministicModel() ? "deterministic" : "non-deterministic"));
249
250 // Build transition matrix
251 modelComponents.transitionMatrix = matrixBuilder.builder.build(stateSize, stateSize);
252 if (stateSize <= 15) {
253 STORM_LOG_TRACE("Transition matrix: \n" << modelComponents.transitionMatrix);
254 } else {
255 STORM_LOG_TRACE("Transition matrix: too big to print");
256 }
257
258 buildLabeling();
259}
260
261template<typename ValueType, typename StateType>
263 STORM_LOG_TRACE("Refining DFT state space");
264
265 // TODO: should be easier now as skipped states all are at the end of the matrix
266 // Push skipped states to explore queue
267 // TODO: remove
268 for (auto const& skippedState : skippedStates) {
269 statesNotExplored[skippedState.second.first->getId()] = skippedState.second;
270 explorationQueue.push(skippedState.second.second);
271 }
272
273 // Initialize matrix builder again
274 // TODO: avoid copy
275 std::vector<uint_fast64_t> copyRemapping = matrixBuilder.stateRemapping;
276 matrixBuilder = MatrixBuilder(!generator.isDeterministicModel());
277 matrixBuilder.stateRemapping = copyRemapping;
278 StateType nrStates = modelComponents.transitionMatrix.getRowGroupCount();
279 STORM_LOG_ASSERT(nrStates == matrixBuilder.stateRemapping.size(), "No. of states does not coincide with mapping size.");
280
281 // Start by creating a remapping from the old indices to the new indices
282 std::vector<StateType> indexRemapping = std::vector<StateType>(nrStates, 0);
283 auto iterSkipped = skippedStates.begin();
284 size_t skippedBefore = 0;
285 for (size_t i = 0; i < indexRemapping.size(); ++i) {
286 while (iterSkipped != skippedStates.end() && iterSkipped->first <= i) {
287 STORM_LOG_ASSERT(iterSkipped->first < indexRemapping.size(), "Skipped is too high.");
288 ++skippedBefore;
289 ++iterSkipped;
290 }
291 indexRemapping[i] = i - skippedBefore;
292 }
293
294 // Set remapping
295 size_t nrExpandedStates = nrStates - skippedBefore;
296 matrixBuilder.mappingOffset = nrStates;
297 STORM_LOG_TRACE("# expanded states: " << nrExpandedStates);
298 StateType skippedIndex = nrExpandedStates;
299 std::map<StateType, std::pair<DFTStatePointer, ExplorationHeuristicPointer>> skippedStatesNew;
300 for (size_t id = 0; id < matrixBuilder.stateRemapping.size(); ++id) {
301 StateType index = matrixBuilder.getRemapping(id);
302 auto itFind = skippedStates.find(index);
303 if (itFind != skippedStates.end()) {
304 // Set new mapping for skipped state
305 matrixBuilder.stateRemapping[id] = skippedIndex;
306 skippedStatesNew[skippedIndex] = itFind->second;
307 indexRemapping[index] = skippedIndex;
308 ++skippedIndex;
309 } else {
310 // Set new mapping for expanded state
311 matrixBuilder.stateRemapping[id] = indexRemapping[index];
312 }
313 }
314 STORM_LOG_TRACE("New state remapping: " << matrixBuilder.stateRemapping);
315 std::stringstream ss;
316 ss << "Index remapping:\n";
317 for (auto tmp : indexRemapping) {
318 ss << tmp << " ";
319 }
320 STORM_LOG_TRACE(ss.str());
321
322 // Remap markovian states
323 storm::storage::BitVector markovianStatesNew = storm::storage::BitVector(modelComponents.markovianStates.size(), true);
324 // Iterate over all not set bits
325 modelComponents.markovianStates.complement();
326 size_t index = modelComponents.markovianStates.getNextSetIndex(0);
327 while (index < modelComponents.markovianStates.size()) {
328 markovianStatesNew.set(indexRemapping[index], false);
329 index = modelComponents.markovianStates.getNextSetIndex(index + 1);
330 }
331 STORM_LOG_ASSERT(modelComponents.markovianStates.size() - modelComponents.markovianStates.getNumberOfSetBits() == markovianStatesNew.getNumberOfSetBits(),
332 "Remapping of markovian states is wrong.");
333 STORM_LOG_ASSERT(markovianStatesNew.size() == nrStates, "No. of states does not coincide with markovian size.");
334 modelComponents.markovianStates = markovianStatesNew;
335
336 // Build submatrix for expanded states
337 // TODO: only use row groups when necessary
338 for (StateType oldRowGroup = 0; oldRowGroup < modelComponents.transitionMatrix.getRowGroupCount(); ++oldRowGroup) {
339 if (indexRemapping[oldRowGroup] < nrExpandedStates) {
340 // State is expanded -> copy to new matrix
341 matrixBuilder.newRowGroup();
342 for (StateType oldRow = modelComponents.transitionMatrix.getRowGroupIndices()[oldRowGroup];
343 oldRow < modelComponents.transitionMatrix.getRowGroupIndices()[oldRowGroup + 1]; ++oldRow) {
344 for (typename storm::storage::SparseMatrix<ValueType>::const_iterator itEntry = modelComponents.transitionMatrix.begin(oldRow);
345 itEntry != modelComponents.transitionMatrix.end(oldRow); ++itEntry) {
346 auto itFind = skippedStates.find(itEntry->getColumn());
347 if (itFind != skippedStates.end()) {
348 // Set id for skipped states as we remap it later
349 matrixBuilder.addTransition(matrixBuilder.mappingOffset + itFind->second.first->getId(), itEntry->getValue());
350 } else {
351 // Set newly remapped index for expanded states
352 matrixBuilder.addTransition(indexRemapping[itEntry->getColumn()], itEntry->getValue());
353 }
354 }
355 matrixBuilder.finishRow();
356 }
357 }
358 }
359
360 skippedStates = skippedStatesNew;
361
362 STORM_LOG_ASSERT(matrixBuilder.getCurrentRowGroup() == nrExpandedStates, "Row group size does not match.");
363 skippedStates.clear();
364}
365
366template<typename ValueType, typename StateType>
367void ExplicitDFTModelBuilder<ValueType, StateType>::exploreStateSpace(double approximationThreshold) {
368 size_t nrExpandedStates = 0;
369 size_t nrSkippedStates = 0;
370 storm::utility::ProgressMeasurement progress("explored states");
371 progress.startNewMeasurement(0);
372 // TODO: do not empty queue every time but break before
373 while (!explorationQueue.empty()) {
374 // Get the first state in the queue
375 ExplorationHeuristicPointer currentExplorationHeuristic = explorationQueue.pop();
376 StateType currentId = currentExplorationHeuristic->getId();
377 auto itFind = statesNotExplored.find(currentId);
378 STORM_LOG_ASSERT(itFind != statesNotExplored.end(), "Id " << currentId << " not found");
379 DFTStatePointer currentState = itFind->second.first;
380 STORM_LOG_ASSERT(currentExplorationHeuristic == itFind->second.second, "Exploration heuristics do not match");
381 STORM_LOG_ASSERT(currentState->getId() == currentId, "Ids do not match");
382 // Remove it from the list of not explored states
383 statesNotExplored.erase(itFind);
384 STORM_LOG_ASSERT(stateStorage.stateToId.contains(currentState->status()), "State is not contained in state storage.");
385 STORM_LOG_ASSERT(stateStorage.stateToId.getValue(currentState->status()) == currentId, "Ids of states do not coincide.");
386
387 // Get concrete state if necessary
388 if (currentState->isPseudoState()) {
389 // Create concrete state from pseudo state
390 currentState->construct();
391 }
392 STORM_LOG_ASSERT(!currentState->isPseudoState(), "State is pseudo state.");
393
394 // Remember that the current row group was actually filled with the transitions of a different state
395 matrixBuilder.setRemapping(currentId);
396
397 matrixBuilder.newRowGroup();
398
399 // Try to explore the next state
400 generator.load(currentState);
401
402 // if (approximationThreshold > 0.0 && nrExpandedStates > approximationThreshold && !currentExplorationHeuristic->isExpand()) {
403 if (approximationThreshold > 0.0 && currentExplorationHeuristic->isSkip(approximationThreshold)) {
404 // Skip the current state
405 ++nrSkippedStates;
406 STORM_LOG_TRACE("Skip expansion of state: " << dft.getStateString(currentState));
407 setMarkovian(true);
408 // Add transition to target state with temporary value 0
409 // TODO: what to do when there is no unique target state?
410 // STORM_LOG_ASSERT(this->uniqueFailedState, "Approximation only works with unique failed state");
411 matrixBuilder.addTransition(0, storm::utility::zero<ValueType>());
412 // Remember skipped state
413 skippedStates[matrixBuilder.getCurrentRowGroup() - 1] = std::make_pair(currentState, currentExplorationHeuristic);
414 matrixBuilder.finishRow();
415 } else {
416 // Explore the current state
417 ++nrExpandedStates;
419 generator.expand(std::bind(&ExplicitDFTModelBuilder::getOrAddStateIndex, this, std::placeholders::_1));
420 STORM_LOG_ASSERT(!behavior.empty(), "Behavior is empty.");
421 setMarkovian(behavior.begin()->isMarkovian());
422
423 // Now add all choices.
424 for (auto const& choice : behavior) {
425 // Add the probabilistic behavior to the matrix.
426 for (auto const& stateProbabilityPair : choice) {
427 STORM_LOG_ASSERT(!storm::utility::isZero(stateProbabilityPair.second), "Probability zero.");
428 // Set transition to state id + offset. This helps in only remapping all previously skipped states.
429 matrixBuilder.addTransition(matrixBuilder.mappingOffset + stateProbabilityPair.first, stateProbabilityPair.second);
430 // Set heuristic values for reached states
431 auto iter = statesNotExplored.find(stateProbabilityPair.first);
432 if (iter != statesNotExplored.end()) {
433 // Update heuristic values
434 DFTStatePointer state = iter->second.first;
435 if (!iter->second.second) {
436 // Initialize heuristic values
437 ExplorationHeuristicPointer heuristic;
438 switch (usedHeuristic) {
440 heuristic =
441 std::make_shared<DFTExplorationHeuristicDepth<ValueType>>(stateProbabilityPair.first, *currentExplorationHeuristic);
442 break;
444 heuristic = std::make_shared<DFTExplorationHeuristicProbability<ValueType>>(
445 stateProbabilityPair.first, *currentExplorationHeuristic, stateProbabilityPair.second, choice.getTotalMass());
446 break;
448 heuristic = std::make_shared<DFTExplorationHeuristicBoundDifference<ValueType>>(
449 stateProbabilityPair.first, *currentExplorationHeuristic, stateProbabilityPair.second, choice.getTotalMass());
450 break;
451 default:
452 STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentException, "Heuristic not known.");
453 }
454
455 iter->second.second = heuristic;
456 // if (state->hasFailed(dft.getTopLevelIndex()) || state->isFailsafe(dft.getTopLevelIndex()) ||
457 // state->getFailableElements().hasDependencies() || (!state->getFailableElements().hasDependencies() &&
458 // !state->getFailableElements().hasBEs())) {
459 if (state->getFailableElements().hasDependencies() ||
460 (!state->getFailableElements().hasDependencies() && !state->getFailableElements().hasBEs())) {
461 // Do not skip absorbing state or if reached by dependencies
462 iter->second.second->markExpand();
463 }
465 // Compute bounds for heuristic now
466 if (state->isPseudoState()) {
467 // Create concrete state from pseudo state
468 state->construct();
469 }
470 STORM_LOG_ASSERT(!currentState->isPseudoState(), "State is pseudo state.");
471
472 // Initialize bounds
473 // TODO: avoid hack
474 ValueType lowerBound = getLowerBound(state);
475 ValueType upperBound = getUpperBound(state);
476 heuristic->setBounds(lowerBound, upperBound);
477 }
478
479 explorationQueue.push(heuristic);
480 } else if (!iter->second.second->isExpand()) {
481 bool changedPriority = false;
482 double oldPriority = iter->second.second->getPriority();
483 switch (usedHeuristic) {
485 changedPriority = iter->second.second->updateHeuristicValues(*currentExplorationHeuristic,
486 /* next values are irrelevant */ stateProbabilityPair.second,
487 stateProbabilityPair.second);
488 break;
490 changedPriority = iter->second.second->updateHeuristicValues(*currentExplorationHeuristic, stateProbabilityPair.second,
491 choice.getTotalMass());
492 break;
494 changedPriority = iter->second.second->updateHeuristicValues(*currentExplorationHeuristic, stateProbabilityPair.second,
495 choice.getTotalMass());
496 break;
497 default:
498 STORM_LOG_THROW(false, storm::exceptions::IllegalArgumentException, "Heuristic not known.");
499 }
500 if (changedPriority) {
501 // Update priority queue
502 explorationQueue.update(iter->second.second, oldPriority);
503 }
504 }
505 }
506 }
507 matrixBuilder.finishRow();
508 }
509 }
511 break;
512 }
513 // Output number of currently explored states
514 if (nrExpandedStates % 100 == 0) {
515 progress.updateProgress(nrExpandedStates);
516 }
517 } // end exploration
518
519 STORM_LOG_INFO("Expanded " << nrExpandedStates << " states");
520 STORM_LOG_INFO("Skipped " << nrSkippedStates << " states");
521 STORM_LOG_ASSERT(nrSkippedStates == skippedStates.size(), "Nr skipped states is wrong");
522}
523
524template<typename ValueType, typename StateType>
525void ExplicitDFTModelBuilder<ValueType, StateType>::buildLabeling() {
526 bool isAddLabelsClaiming = storm::settings::getModule<storm::dft::settings::modules::FaultTreeSettings>().isAddLabelsClaiming();
527
528 // Build state labeling
529 modelComponents.stateLabeling = storm::models::sparse::StateLabeling(modelComponents.transitionMatrix.getRowGroupCount());
530 // Initial state
531 modelComponents.stateLabeling.addLabel("init");
532 STORM_LOG_ASSERT(matrixBuilder.getRemapping(initialStateIndex) == initialStateIndex, "Initial state should not be remapped.");
533 modelComponents.stateLabeling.addLabelToState("init", initialStateIndex);
534 // System failure
535 modelComponents.stateLabeling.addLabel("failed");
536
537 // Label all states corresponding to their status (failed, don't care BE)
538 // Collect labels for all necessary elements
539 for (size_t id = 0; id < dft.nrElements(); ++id) {
540 std::shared_ptr<storm::dft::storage::elements::DFTElement<ValueType> const> element = dft.getElement(id);
541 if (element->isRelevant()) {
542 modelComponents.stateLabeling.addLabel(element->name() + "_failed");
543 modelComponents.stateLabeling.addLabel(element->name() + "_dc");
544 }
545 }
546 std::vector<std::shared_ptr<storm::dft::storage::elements::DFTGate<ValueType> const>> spares; // Only filled if needed
547 if (isAddLabelsClaiming) {
548 // Collect labels for claiming
549 for (size_t spareId : dft.getSpareIndices()) {
550 auto const& spare = dft.getGate(spareId);
551 spares.push_back(spare);
552 for (auto const& child : spare->children()) {
553 modelComponents.stateLabeling.addLabel(spare->name() + "_claimed_" + child->name());
554 }
555 }
556 }
557
558 // Set labels to states
559 if (this->uniqueFailedState) {
560 // Unique failed state has label 0
561 modelComponents.stateLabeling.addLabelToState("failed", 0);
562 std::shared_ptr<storm::dft::storage::elements::DFTElement<ValueType> const> element = dft.getElement(dft.getTopLevelIndex());
563 STORM_LOG_ASSERT(element->isRelevant(), "TLE should be relevant if unique failed state is used.");
564 modelComponents.stateLabeling.addLabelToState(element->name() + "_failed", 0);
565 }
566 for (auto const& stateIdPair : stateStorage.stateToId) {
567 storm::storage::BitVector state = stateIdPair.first;
568 size_t stateId = matrixBuilder.getRemapping(stateIdPair.second);
569 if (dft.hasFailed(state, *stateGenerationInfo)) {
570 modelComponents.stateLabeling.addLabelToState("failed", stateId);
571 }
572 // Set failed/don't care status for each necessary element
573 for (size_t id = 0; id < dft.nrElements(); ++id) {
574 std::shared_ptr<storm::dft::storage::elements::DFTElement<ValueType> const> element = dft.getElement(id);
575 if (element->isRelevant()) {
577 storm::dft::storage::DFTState<ValueType>::getElementState(state, *stateGenerationInfo, element->id());
578 switch (elementState) {
580 modelComponents.stateLabeling.addLabelToState(element->name() + "_failed", stateId);
581 break;
583 modelComponents.stateLabeling.addLabelToState(element->name() + "_dc", stateId);
584 break;
587 // do nothing
588 break;
589 default:
590 STORM_LOG_ASSERT(false, "Unknown element state " << elementState);
591 }
592 }
593 }
594 if (isAddLabelsClaiming) {
595 for (auto const& spare : spares) {
596 size_t claimedChildId = dft.uses(state, *stateGenerationInfo, spare->id());
597 if (claimedChildId != spare->id()) {
598 modelComponents.stateLabeling.addLabelToState(spare->name() + "_claimed_" + dft.getElement(claimedChildId)->name(), stateId);
599 }
600 }
601 }
602 }
603
604 STORM_LOG_TRACE(modelComponents.stateLabeling);
605}
606
607template<typename ValueType, typename StateType>
608std::shared_ptr<storm::models::sparse::Model<ValueType>> ExplicitDFTModelBuilder<ValueType, StateType>::getModel() {
609 if (storm::settings::getModule<storm::dft::settings::modules::FaultTreeSettings>().isMaxDepthSet() && skippedStates.size() > 0) {
610 // Give skipped states separate label "skipped"
611 modelComponents.stateLabeling.addLabel("skipped");
612 for (auto it = skippedStates.begin(); it != skippedStates.end(); ++it) {
613 modelComponents.stateLabeling.addLabelToState("skipped", it->first);
614 }
615 } else {
616 STORM_LOG_ASSERT(skippedStates.size() == 0, "Concrete model has skipped states");
617 }
618
619 return createModel(false);
620}
621
622template<typename ValueType, typename StateType>
623std::shared_ptr<storm::models::sparse::Model<ValueType>> ExplicitDFTModelBuilder<ValueType, StateType>::getModelApproximation(bool lowerBound,
624 bool expectedTime) {
625 if (expectedTime) {
626 // TODO: handle case with no skipped states
627 changeMatrixBound(modelComponents.transitionMatrix, lowerBound);
628 return createModel(true);
629 } else {
630 // Change model for probabilities
631 // TODO: make nicer
632 storm::storage::SparseMatrix<ValueType> matrix = modelComponents.transitionMatrix;
633 storm::models::sparse::StateLabeling labeling = modelComponents.stateLabeling;
634 if (lowerBound) {
635 // Set self loop for lower bound
636 for (auto it = skippedStates.begin(); it != skippedStates.end(); ++it) {
637 auto matrixEntry = matrix.getRow(it->first, 0).begin();
638 STORM_LOG_ASSERT(matrixEntry->getColumn() == 0, "Transition has wrong target state.");
639 STORM_LOG_ASSERT(!it->second.first->isPseudoState(), "State is still pseudo state.");
640 matrixEntry->setValue(storm::utility::one<ValueType>());
641 matrixEntry->setColumn(it->first);
642 }
643 } else {
644 // Make skipped states failed states for upper bound
645 storm::storage::BitVector failedStates = modelComponents.stateLabeling.getStates("failed");
646 for (auto it = skippedStates.begin(); it != skippedStates.end(); ++it) {
647 failedStates.set(it->first);
648 }
649 labeling.setStates("failed", failedStates);
650 }
651
652 std::shared_ptr<storm::models::sparse::Model<ValueType>> model;
653 if (modelComponents.deterministicModel) {
654 model = std::make_shared<storm::models::sparse::Ctmc<ValueType>>(std::move(matrix), std::move(labeling));
655 } else {
656 // Build MA
657 // Compute exit rates
658 // TODO: avoid computing multiple times
659 modelComponents.exitRates = std::vector<ValueType>(modelComponents.markovianStates.size());
660 std::vector<typename storm::storage::SparseMatrix<ValueType>::index_type> indices = matrix.getRowGroupIndices();
661 for (StateType stateIndex = 0; stateIndex < modelComponents.markovianStates.size(); ++stateIndex) {
662 if (modelComponents.markovianStates[stateIndex]) {
663 modelComponents.exitRates[stateIndex] = matrix.getRowSum(indices[stateIndex]);
664 } else {
665 modelComponents.exitRates[stateIndex] = storm::utility::zero<ValueType>();
666 }
667 }
668 STORM_LOG_TRACE("Exit rates: " << modelComponents.exitRates);
669
670 storm::storage::sparse::ModelComponents<ValueType> maComponents(std::move(matrix), std::move(labeling));
671 maComponents.rateTransitions = true;
672 maComponents.markovianStates = modelComponents.markovianStates;
673 maComponents.exitRates = modelComponents.exitRates;
674 std::shared_ptr<storm::models::sparse::MarkovAutomaton<ValueType>> ma =
675 std::make_shared<storm::models::sparse::MarkovAutomaton<ValueType>>(std::move(maComponents));
676 if (ma->hasOnlyTrivialNondeterminism()) {
677 // Markov automaton can be converted into CTMC
680 } else {
681 model = ma;
682 }
683 }
684
685 if (model->getNumberOfStates() <= 15) {
686 STORM_LOG_TRACE("Transition matrix: \n" << model->getTransitionMatrix());
687 } else {
688 STORM_LOG_TRACE("Transition matrix: too big to print");
689 }
690 return model;
691 }
692}
693
694template<typename ValueType, typename StateType>
695std::shared_ptr<storm::models::sparse::Model<ValueType>> ExplicitDFTModelBuilder<ValueType, StateType>::createModel(bool copy) {
696 std::shared_ptr<storm::models::sparse::Model<ValueType>> model;
697
698 if (modelComponents.deterministicModel) {
699 // Build CTMC
700 if (copy) {
701 model = std::make_shared<storm::models::sparse::Ctmc<ValueType>>(modelComponents.transitionMatrix, modelComponents.stateLabeling);
702 } else {
703 model =
704 std::make_shared<storm::models::sparse::Ctmc<ValueType>>(std::move(modelComponents.transitionMatrix), std::move(modelComponents.stateLabeling));
705 }
706 } else {
707 // Build MA
708 // Compute exit rates
709 // TODO: avoid computing multiple times
710 modelComponents.exitRates = std::vector<ValueType>(modelComponents.markovianStates.size());
711 std::vector<typename storm::storage::SparseMatrix<ValueType>::index_type> indices = modelComponents.transitionMatrix.getRowGroupIndices();
712 for (StateType stateIndex = 0; stateIndex < modelComponents.markovianStates.size(); ++stateIndex) {
713 if (modelComponents.markovianStates[stateIndex]) {
714 modelComponents.exitRates[stateIndex] = modelComponents.transitionMatrix.getRowSum(indices[stateIndex]);
715 } else {
716 modelComponents.exitRates[stateIndex] = storm::utility::zero<ValueType>();
717 }
718 }
719 STORM_LOG_TRACE("Exit rates: " << modelComponents.exitRates);
720
721 std::shared_ptr<storm::models::sparse::MarkovAutomaton<ValueType>> ma;
722 if (copy) {
723 storm::storage::sparse::ModelComponents<ValueType> maComponents(modelComponents.transitionMatrix, modelComponents.stateLabeling);
724 maComponents.rateTransitions = true;
725 maComponents.markovianStates = modelComponents.markovianStates;
726 maComponents.exitRates = modelComponents.exitRates;
727 ma = std::make_shared<storm::models::sparse::MarkovAutomaton<ValueType>>(std::move(maComponents));
728 } else {
729 storm::storage::sparse::ModelComponents<ValueType> maComponents(std::move(modelComponents.transitionMatrix),
730 std::move(modelComponents.stateLabeling));
731 maComponents.rateTransitions = true;
732 maComponents.markovianStates = std::move(modelComponents.markovianStates);
733 maComponents.exitRates = std::move(modelComponents.exitRates);
734 ma = std::make_shared<storm::models::sparse::MarkovAutomaton<ValueType>>(std::move(maComponents));
735 }
736 if (ma->hasOnlyTrivialNondeterminism()) {
737 // Markov automaton can be converted into CTMC
740 } else {
741 model = ma;
742 }
743 }
744
745 if (model->getNumberOfStates() <= 15) {
746 STORM_LOG_TRACE("Transition matrix: \n" << model->getTransitionMatrix());
747 } else {
748 STORM_LOG_TRACE("Transition matrix: too big to print");
749 }
750 return model;
751}
752
753template<typename ValueType, typename StateType>
754void ExplicitDFTModelBuilder<ValueType, StateType>::changeMatrixBound(storm::storage::SparseMatrix<ValueType>& matrix, bool lowerBound) const {
755 // Set lower bound for skipped states
756 for (auto it = skippedStates.begin(); it != skippedStates.end(); ++it) {
757 auto matrixEntry = matrix.getRow(it->first, 0).begin();
758 STORM_LOG_ASSERT(matrixEntry->getColumn() == 0, "Transition has wrong target state.");
759 STORM_LOG_ASSERT(!it->second.first->isPseudoState(), "State is still pseudo state.");
760
761 // Change bound
762 // TODO: cache values inbetween iterations
763 if (lowerBound) {
764 matrixEntry->setValue(getLowerBound(it->second.first));
765 } else {
766 matrixEntry->setValue(getUpperBound(it->second.first));
767 }
768 }
769}
770
771template<typename ValueType, typename StateType>
772ValueType ExplicitDFTModelBuilder<ValueType, StateType>::getLowerBound(DFTStatePointer const& state) const {
773 // Get the lower bound by considering the failure of all possible BEs
774 ValueType lowerBound = storm::utility::zero<ValueType>();
775 STORM_LOG_ASSERT(!state->getFailableElements().hasDependencies(), "Lower bound should only be computed if dependencies were already handled.");
776 for (auto it = state->getFailableElements().begin(); it != state->getFailableElements().end(); ++it) {
777 lowerBound += state->getBERate(*it);
778 }
779 STORM_LOG_TRACE("Lower bound is " << lowerBound << " for state " << state->getId());
780 return lowerBound;
781}
782
783template<typename ValueType, typename StateType>
784ValueType ExplicitDFTModelBuilder<ValueType, StateType>::getUpperBound(DFTStatePointer const& state) const {
785 if (state->hasFailed(dft.getTopLevelIndex())) {
786 return storm::utility::zero<ValueType>();
787 }
788
789 // Get the upper bound by considering the failure of all BEs
790 ValueType upperBound = storm::utility::one<ValueType>();
791 ValueType rateSum = storm::utility::zero<ValueType>();
792
793 // Compute for each independent subtree
794 for (std::vector<size_t> const& subtree : subtreeBEs) {
795 // Get all possible rates
796 std::vector<ValueType> rates;
797 storm::storage::BitVector coldBEs(subtree.size(), false);
798 for (size_t i = 0; i < subtree.size(); ++i) {
799 size_t id = subtree[i];
800 // Consider only still operational BEs
801 if (state->isOperational(id)) {
802 auto be = dft.getBasicElement(id);
803 switch (be->beType()) {
805 // Ignore BE which cannot fail
806 continue;
808 // Get BE rate
809 ValueType rate = state->getBERate(id);
810 if (storm::utility::isZero<ValueType>(rate)) {
811 // Get active failure rate for cold BE
812 auto beExp = std::static_pointer_cast<storm::dft::storage::elements::BEExponential<ValueType> const>(be);
813 rate = beExp->activeFailureRate();
814 STORM_LOG_ASSERT(!storm::utility::isZero<ValueType>(rate), "Failure rate should not be zero.");
815 // Mark BE as cold
816 coldBEs.set(i, true);
817 }
818 rates.push_back(rate);
819 rateSum += rate;
820 break;
821 }
822 default:
823 STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "BE of type '" << be->beType() << "' is not known.");
824 break;
825 }
826 }
827 }
828 STORM_LOG_ASSERT(rates.size() > 0, "No rates failable");
829
830 // Sort rates
831 std::sort(rates.begin(), rates.end());
832 std::vector<size_t> rateCount(rates.size(), 0);
833 size_t lastIndex = 0;
834 for (size_t i = 0; i < rates.size(); ++i) {
835 if (rates[lastIndex] != rates[i]) {
836 lastIndex = i;
837 }
838 ++rateCount[lastIndex];
839 }
840
841 for (size_t i = 0; i < rates.size(); ++i) {
842 // Cold BEs cannot fail in the first step
843 if (!coldBEs.get(i) && rateCount[i] > 0) {
844 std::iter_swap(rates.begin() + i, rates.end() - 1);
845 // Compute AND MTTF of subtree without current rate and scale with current rate
846 upperBound += rates.back() * rateCount[i] * computeMTTFAnd(rates, rates.size() - 1);
847 // Swap back
848 // TODO try to avoid swapping back
849 std::iter_swap(rates.begin() + i, rates.end() - 1);
850 }
851 }
852 }
853
854 STORM_LOG_TRACE("Upper bound is " << (rateSum / upperBound) << " for state " << state->getId());
855 STORM_LOG_ASSERT(!storm::utility::isZero(upperBound), "Upper bound is 0");
856 STORM_LOG_ASSERT(!storm::utility::isZero(rateSum), "State is absorbing");
857 return rateSum / upperBound;
858}
859
860template<typename ValueType, typename StateType>
861ValueType ExplicitDFTModelBuilder<ValueType, StateType>::computeMTTFAnd(std::vector<ValueType> const& rates, size_t size) const {
862 ValueType result = storm::utility::zero<ValueType>();
863 if (size == 0) {
864 return result;
865 }
866
867 // TODO: works only for <64 BEs!
868 // WARNING: this code produces wrong results for more than 32 BEs
869 /*for (size_t i = 1; i < 4 && i <= rates.size(); ++i) {
870 size_t permutation = smallestIntWithNBitsSet(static_cast<size_t>(i));
871 ValueType sum = storm::utility::zero<ValueType>();
872 do {
873 ValueType permResult = storm::utility::zero<ValueType>();
874 for(size_t j = 0; j < rates.size(); ++j) {
875 if(permutation & static_cast<size_t>(1 << static_cast<size_t>(j))) {
876 // WARNING: if the first bit is set, it also recognizes the 32nd bit as set
877 // TODO: fix
878 permResult += rates[j];
879 }
880 }
881 permutation = nextBitPermutation(permutation);
882 STORM_LOG_ASSERT(!storm::utility::isZero(permResult), "PermResult is 0");
883 sum += storm::utility::one<ValueType>() / permResult;
884 } while(permutation < (static_cast<size_t>(1) << rates.size()) && permutation != 0);
885 if (i % 2 == 0) {
886 result -= sum;
887 } else {
888 result += sum;
889 }
890 }*/
891
892 // Compute result with permutations of size <= 3
893 ValueType one = storm::utility::one<ValueType>();
894 for (size_t i1 = 0; i1 < size; ++i1) {
895 // + 1/a
896 ValueType sum = rates[i1];
897 result += one / sum;
898 for (size_t i2 = 0; i2 < i1; ++i2) {
899 // - 1/(a+b)
900 ValueType sum2 = sum + rates[i2];
901 result -= one / sum2;
902 for (size_t i3 = 0; i3 < i2; ++i3) {
903 // + 1/(a+b+c)
904 result += one / (sum2 + rates[i3]);
905 }
906 }
907 }
908
909 STORM_LOG_ASSERT(!storm::utility::isZero(result), "UpperBound is 0");
910 return result;
911}
912
913template<typename ValueType, typename StateType>
914StateType ExplicitDFTModelBuilder<ValueType, StateType>::getOrAddStateIndex(DFTStatePointer const& state) {
915 StateType stateId;
916 bool changed = false;
917
918 if (stateGenerationInfo->hasSymmetries()) {
919 // Order state by symmetry
920 STORM_LOG_TRACE("Check for symmetry: " << dft.getStateString(state));
921 changed = state->orderBySymmetry();
922 STORM_LOG_TRACE("State " << (changed ? "changed to " : "did not change") << (changed ? dft.getStateString(state) : ""));
923 }
924
925 if (stateStorage.stateToId.contains(state->status())) {
926 // State already exists
927 stateId = stateStorage.stateToId.getValue(state->status());
928 STORM_LOG_TRACE("State " << dft.getStateString(state) << " with id " << stateId << " already exists");
929 if (!changed) {
930 // Check if state is pseudo state
931 // If state is explored already the possible pseudo state was already constructed
932 auto iter = statesNotExplored.find(stateId);
933 if (iter != statesNotExplored.end() && iter->second.first->isPseudoState()) {
934 // Create pseudo state now
935 STORM_LOG_ASSERT(iter->second.first->getId() == stateId, "Ids do not match.");
936 STORM_LOG_ASSERT(iter->second.first->status() == state->status(), "Pseudo states do not coincide.");
937 state->setId(stateId);
938 // Update mapping to map to concrete state now
939 // TODO: just change pointer?
940 statesNotExplored[stateId] = std::make_pair(state, iter->second.second);
941 // We do not push the new state on the exploration queue as the pseudo state was already pushed
942 STORM_LOG_TRACE("Created pseudo state " << dft.getStateString(state));
943 }
944 }
945 } else {
946 // State does not exist yet
947 STORM_LOG_ASSERT(state->isPseudoState() == changed, "State type (pseudo/concrete) wrong.");
948 // Create new state
949 state->setId(newIndex++);
950 stateId = stateStorage.stateToId.findOrAdd(state->status(), state->getId());
951 STORM_LOG_ASSERT(stateId == state->getId(), "Ids do not match.");
952 // Insert state as not yet explored
953 ExplorationHeuristicPointer nullHeuristic;
954 statesNotExplored[stateId] = std::make_pair(state, nullHeuristic);
955 // Reserve one slot for the new state in the remapping
956 matrixBuilder.stateRemapping.push_back(0);
957 STORM_LOG_TRACE("New " << (state->isPseudoState() ? "pseudo" : "concrete") << " state: " << dft.getStateString(state));
958 }
959 return stateId;
960}
961
962template<typename ValueType, typename StateType>
963void ExplicitDFTModelBuilder<ValueType, StateType>::setMarkovian(bool markovian) {
964 if (matrixBuilder.getCurrentRowGroup() > modelComponents.markovianStates.size()) {
965 // Resize BitVector
966 modelComponents.markovianStates.resize(modelComponents.markovianStates.size() + INITIAL_BITVECTOR_SIZE);
967 }
968 modelComponents.markovianStates.set(matrixBuilder.getCurrentRowGroup() - 1, markovian);
969}
970
971template<typename ValueType, typename StateType>
972void ExplicitDFTModelBuilder<ValueType, StateType>::printNotExplored() const {
973 std::cout << "states not explored:\n";
974 for (auto it : statesNotExplored) {
975 std::cout << it.first << " -> " << dft.getStateString(it.second.first) << '\n';
976 }
977}
978
979// Explicitly instantiate the class.
980template class ExplicitDFTModelBuilder<double>;
981template class ExplicitDFTModelBuilder<storm::RationalFunction>;
982
983} // namespace builder
984} // namespace storm::dft
std::shared_ptr< storm::models::sparse::Model< ValueType > > getModelApproximation(bool lowerBound, bool expectedTime)
Get the built approximation model for either the lower or upper bound.
std::shared_ptr< storm::models::sparse::Model< ValueType > > getModel()
Get the built model.
void buildModel(size_t iteration, double approximationThreshold=0.0, storm::dft::builder::ApproximationHeuristic approximationHeuristic=storm::dft::builder::ApproximationHeuristic::DEPTH)
Build model from DFT.
Priority queue based on buckets.
Represents a Dynamic Fault Tree.
Definition DFT.h:52
size_t getTopLevelIndex() const
Definition DFT.h:106
std::string getRelevantEventsString() const
Get a string containing the list of all relevant events.
Definition DFT.cpp:716
std::shared_ptr< storm::dft::storage::elements::DFTBE< ValueType > const > getBasicElement(size_t index) const
Definition DFT.h:209
storm::dft::storage::elements::DFTElementType getTopLevelType() const
Definition DFT.h:110
size_t nrElements() const
Definition DFT.h:94
std::shared_ptr< storm::dft::storage::elements::DFTGate< ValueType > const > getGate(size_t index) const
Definition DFT.h:218
bool isGate(size_t index) const
Definition DFT.h:197
std::vector< size_t > const & getRelevantEvents() const
Get all relevant events.
Definition DFT.cpp:711
bool isBasicElement(size_t index) const
Definition DFT.h:193
DFTElementState getElementState(size_t id) const
Definition DFTState.cpp:109
bool empty() const
Retrieves whether the behavior is empty in the sense that there are no available choices.
std::vector< Choice< ValueType, StateType > >::const_iterator begin() const
Retrieves an iterator to the choices available in the behavior.
std::size_t getNumberOfChoices() const
Retrieves the number of choices in the behavior.
This class manages the labeling of the state space with a number of (atomic) labels.
void setStates(std::string const &label, storage::BitVector const &labeling)
Sets the labeling of states associated with the given label.
A bit vector that is internally represented as a vector of 64-bit values.
Definition BitVector.h:18
void set(uint_fast64_t index, bool value=true)
Sets the given truth value at the given index.
size_t size() const
Retrieves the number of bits this bit vector can store.
uint_fast64_t getNumberOfSetBits() const
Returns the number of bits that are set to true in this bit vector.
const_iterator begin() const
Retrieves an iterator that points to the beginning of the rows.
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.
value_type getRowSum(index_type row) const
Computes the sum of the entries in a given row.
std::vector< MatrixEntry< index_type, value_type > >::const_iterator const_iterator
std::vector< index_type > const & getRowGroupIndices() const
Returns the grouping of rows of this matrix.
static std::shared_ptr< models::sparse::Model< ValueType, RewardModelType > > eliminateNonmarkovianStates(std::shared_ptr< models::sparse::MarkovAutomaton< ValueType, RewardModelType > > ma, EliminationLabelBehavior labelBehavior=EliminationLabelBehavior::KeepLabels)
Generates a model with the same basic behavior as the input, but eliminates non-Markovian chains.
A class that provides convenience operations to display run times.
#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
ApproximationHeuristic
Enum representing the heuristic used for deciding which states to expand.
SFTBDDChecker::ValueType ValueType
Expression sum(std::vector< storm::expressions::Expression > const &expressions)
SettingsType const & getModule()
Get module.
bool isTerminate()
Check whether the program should terminate (due to some abort signal).
bool isZero(ValueType const &a)
Definition constants.cpp:41
ValueType one()
Definition constants.cpp:21
LabParser.cpp.
Definition cli.cpp:18
boost::optional< storm::storage::BitVector > markovianStates
boost::optional< std::vector< ValueType > > exitRates