Storm 1.14.0.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
Order.cpp
Go to the documentation of this file.
2
3#include <iostream>
4#include <queue>
5
7
8namespace storm {
9namespace analysis {
10Order::Order(storm::storage::BitVector const& topStates, storm::storage::BitVector const& bottomStates, uint_fast64_t numberOfStates,
11 storage::Decomposition<storage::StronglyConnectedComponent> decomposition, std::vector<uint_fast64_t> statesSorted) {
12 init(numberOfStates, decomposition);
13 this->numberOfAddedStates = 0;
14 this->onlyBottomTopOrder = true;
15 for (auto i : topStates) {
16 this->doneStates.set(i);
17 this->bottom->statesAbove.set(i);
18 this->top->states.insert(i);
19 this->nodes[i] = top;
20 numberOfAddedStates++;
21 }
22 this->statesSorted = statesSorted;
23
24 for (auto i : bottomStates) {
25 this->doneStates.set(i);
26 this->bottom->states.insert(i);
27 this->nodes[i] = bottom;
28 numberOfAddedStates++;
29 }
30 STORM_LOG_ASSERT(numberOfAddedStates <= numberOfStates, "More states were added to the order than it has room for.");
31 STORM_LOG_ASSERT(doneStates.getNumberOfSetBits() == (topStates.getNumberOfSetBits() + bottomStates.getNumberOfSetBits()),
32 "Number of done states does not match the number of given top and bottom states.");
33 if (numberOfAddedStates == numberOfStates) {
34 doneBuilding = doneStates.full();
35 }
36}
37
38Order::Order(uint_fast64_t topState, uint_fast64_t bottomState, uint_fast64_t numberOfStates,
39 storage::Decomposition<storage::StronglyConnectedComponent> decomposition, std::vector<uint_fast64_t> statesSorted) {
40 init(numberOfStates, decomposition);
41
42 this->onlyBottomTopOrder = true;
43 this->doneStates.set(topState);
44
45 this->bottom->statesAbove.set(topState);
46 this->top->states.insert(topState);
47 this->nodes[topState] = top;
48
49 this->doneStates.set(bottomState);
50
51 this->bottom->states.insert(bottomState);
52 this->nodes[bottomState] = bottom;
53 this->numberOfAddedStates = 2;
54 STORM_LOG_ASSERT(numberOfAddedStates <= numberOfStates, "More states were added to the order than it has room for.");
55
56 this->statesSorted = statesSorted;
57 STORM_LOG_ASSERT(doneStates.getNumberOfSetBits() == 2, "Expected exactly the given top and bottom state to be done.");
58 if (numberOfAddedStates == numberOfStates) {
59 doneBuilding = doneStates.full();
60 }
61}
62
63Order::Order() : invalid(false), doneBuilding(false), onlyBottomTopOrder(false), top(nullptr), bottom(nullptr), numberOfStates(0), numberOfAddedStates(0) {}
64
65Order::Order(Order const& other)
66 : invalid(other.invalid),
67 doneBuilding(other.doneBuilding),
68 onlyBottomTopOrder(other.onlyBottomTopOrder),
69 doneStates(other.doneStates),
70 trivialStates(other.trivialStates),
71 nodes(other.numberOfStates, nullptr),
72 statesToHandle(other.statesToHandle),
73 top(nullptr),
74 bottom(nullptr),
75 numberOfStates(other.numberOfStates),
76 numberOfAddedStates(other.numberOfAddedStates),
77 statesSorted(other.statesSorted) {
78 storm::storage::BitVector seenStates(numberOfStates, false);
79 for (uint_fast64_t state = 0; state < numberOfStates; ++state) {
80 Node* oldNode = other.nodes.at(state);
81 if (oldNode != nullptr && !oldNode->states.empty() && !seenStates[*oldNode->states.begin()]) {
82 Node* newNode = allocateNode();
83 if (oldNode == other.top) {
84 top = newNode;
85 } else if (oldNode == other.bottom) {
86 bottom = newNode;
87 }
88 newNode->statesAbove = oldNode->statesAbove;
89 for (auto const& i : oldNode->states) {
90 newNode->states.insert(i);
91 seenStates.set(i);
92 nodes[i] = newNode;
93 }
94 }
95 }
96 // A sentinel without states is not discovered through a state's node. Copy it explicitly so that
97 // the copy never ends up with a null top/bottom where the original had a sentinel.
98 if (top == nullptr && other.top != nullptr) {
99 top = allocateNode();
100 top->statesAbove = other.top->statesAbove;
101 top->states = other.top->states;
102 }
103 if (bottom == nullptr && other.bottom != nullptr) {
104 bottom = allocateNode();
105 bottom->statesAbove = other.bottom->statesAbove;
106 bottom->states = other.bottom->states;
107 }
108}
109
111 swap(*this, other);
112 return *this;
113}
114
115void swap(Order& first, Order& second) noexcept {
116 using std::swap;
117 swap(first.invalid, second.invalid);
118 swap(first.doneBuilding, second.doneBuilding);
119 swap(first.onlyBottomTopOrder, second.onlyBottomTopOrder);
120 swap(first.doneStates, second.doneStates);
121 swap(first.trivialStates, second.trivialStates);
122 swap(first.nodes, second.nodes);
123 swap(first.nodeStorage, second.nodeStorage);
124 swap(first.statesToHandle, second.statesToHandle);
125 swap(first.top, second.top);
126 swap(first.bottom, second.bottom);
127 swap(first.numberOfStates, second.numberOfStates);
128 swap(first.numberOfAddedStates, second.numberOfAddedStates);
129 swap(first.statesSorted, second.statesSorted);
130}
131
132Order::Node* Order::allocateNode() {
133 nodeStorage.push_back(std::make_unique<Node>());
134 return nodeStorage.back().get();
135}
136
137/*** Modifying the order ***/
138
139void Order::add(uint_fast64_t state) {
140 STORM_LOG_ASSERT(nodes[state] == nullptr, "State " << state << " is already in the order.");
141 addBetween(state, top, bottom);
142 addStateToHandle(state);
143}
144
145void Order::addAbove(uint_fast64_t state, Node* node) {
146 STORM_LOG_INFO("Add " << state << " above " << *node->states.begin() << '\n');
147
148 STORM_LOG_ASSERT(nodes[state] == nullptr, "State " << state << " is already in the order.");
149 Node* newNode = allocateNode();
150 nodes[state] = newNode;
151
152 newNode->states.insert(state);
153 newNode->statesAbove = storm::storage::BitVector(numberOfStates, false);
154 for (auto const& state : top->states) {
155 newNode->statesAbove.set(state);
156 }
157 node->statesAbove.set(state);
158 numberOfAddedStates++;
159 onlyBottomTopOrder = false;
160 if (numberOfAddedStates == numberOfStates) {
161 doneBuilding = doneStates.full();
162 }
163}
164
165void Order::addBelow(uint_fast64_t state, Node* node) {
166 STORM_LOG_INFO("Add " << state << " below " << *node->states.begin() << '\n');
167
168 STORM_LOG_ASSERT(nodes[state] == nullptr, "State " << state << " is already in the order.");
169 Node* newNode = allocateNode();
170 nodes[state] = newNode;
171 newNode->states.insert(state);
173 for (auto statesAbove : node->states) {
174 newNode->statesAbove.set(statesAbove);
175 }
176 bottom->statesAbove.set(state);
177 numberOfAddedStates++;
178 onlyBottomTopOrder = false;
179 if (numberOfAddedStates == numberOfStates) {
180 doneBuilding = doneStates.full();
181 }
182 STORM_LOG_ASSERT(numberOfAddedStates <= numberOfStates, "More states were added to the order than it has room for.");
183}
184
185void Order::addBetween(uint_fast64_t state, Node* above, Node* below) {
186 STORM_LOG_INFO("Add " << state << " between (above) " << *above->states.begin() << " and " << *below->states.begin() << '\n');
187
188 STORM_LOG_ASSERT(compare(above, below) == ABOVE, "Expected the first node/state to be above the second.");
189 STORM_LOG_ASSERT(above != nullptr && below != nullptr, "Both nodes must exist.");
190 if (nodes[state] == nullptr) {
191 // State is not in the order yet
192 Node* newNode = allocateNode();
193 nodes[state] = newNode;
194
195 newNode->states.insert(state);
196 newNode->statesAbove = storm::storage::BitVector(above->statesAbove);
197 for (auto aboveStates : above->states) {
198 newNode->statesAbove.set(aboveStates);
199 }
200 below->statesAbove.set(state);
201 numberOfAddedStates++;
202 onlyBottomTopOrder = false;
203 if (numberOfAddedStates == numberOfStates) {
204 doneBuilding = doneStates.full();
205 }
206 STORM_LOG_ASSERT(numberOfAddedStates <= numberOfStates, "More states were added to the order than it has room for.");
207 } else {
208 // State is in the order already, so we add the new relations
209 addRelationNodes(above, nodes[state]);
210 addRelationNodes(nodes[state], below);
211 }
212}
213
214void Order::addBetween(uint_fast64_t state, uint_fast64_t above, uint_fast64_t below) {
215 STORM_LOG_ASSERT(getNode(below)->states.find(below) != getNode(below)->states.end(), "State " << below << " is not in its own node.");
216 STORM_LOG_ASSERT(getNode(above)->states.find(above) != getNode(above)->states.end(), "State " << above << " is not in its own node.");
217
218 addBetween(state, getNode(above), getNode(below));
219}
220
221void Order::addRelation(uint_fast64_t above, uint_fast64_t below, bool allowMerge) {
222 STORM_LOG_ASSERT(getNode(above) != nullptr && getNode(below) != nullptr, "Both states must already be in the order.");
223 addRelationNodes(getNode(above), getNode(below), allowMerge);
224}
225
226void Order::addRelationNodes(Order::Node* above, Order::Node* below, bool allowMerge) {
227 STORM_LOG_ASSERT(allowMerge || compare(above, below) != BELOW, "The first node/state is already known to be below the second.");
228
229 STORM_LOG_INFO("Add relation between (above) " << *above->states.begin() << " and " << *below->states.begin() << '\n');
230
231 if (allowMerge) {
232 if (compare(below, above) == ABOVE) {
233 mergeNodes(above, below);
234 return;
235 }
236 }
237 below->statesAbove |= ((above->statesAbove));
238 for (auto const& state : above->states) {
239 below->statesAbove.set(state);
240 }
241 STORM_LOG_ASSERT(compare(above, below) == ABOVE, "Expected the first node/state to be above the second.");
242}
243
244void Order::addToNode(uint_fast64_t state, Node* node) {
245 STORM_LOG_INFO("Add " << state << " to between (above) " << *node->states.begin() << '\n');
246
247 if (nodes[state] == nullptr) {
248 // State is not in the order yet
249 node->states.insert(state);
250 nodes[state] = node;
251 numberOfAddedStates++;
252 if (numberOfAddedStates == numberOfStates) {
253 doneBuilding = doneStates.full();
254 }
255 STORM_LOG_ASSERT(numberOfAddedStates <= numberOfStates, "More states were added to the order than it has room for.");
256
257 } else {
258 // State is in the order already, so we merge the nodes
259 mergeNodes(nodes[state], node);
260 }
261}
262
264 STORM_LOG_INFO("Merge " << *node1->states.begin() << " and " << *node2->states.begin() << '\n');
265
266 // Merges node2 into node 1
267 // everything above n2 also above n1
268 node1->statesAbove |= ((node2->statesAbove));
269 // add states of node 2 to node 1
270 node1->states.insert(node2->states.begin(), node2->states.end());
271
272 for (auto const& i : node2->states) {
273 nodes[i] = node1;
274 }
275
276 for (auto const& node : nodes) {
277 if (node != nullptr) {
278 for (auto state2 : node2->states) {
279 if (node->statesAbove[state2]) {
280 for (auto state1 : node1->states) {
281 node->statesAbove.set(state1);
282 }
283 break;
284 }
285 }
286 }
287 }
288 for (uint_fast64_t i = 0; i < numberOfStates; ++i) {
289 if (nodes[i] == nullptr) {
290 continue;
291 }
292 for (uint_fast64_t j = i + 1; j < numberOfStates; ++j) {
293 if (nodes[j] == nullptr) {
294 continue;
295 }
296 auto comp1 = compare(i, j);
297 auto comp2 = compare(j, i);
298 if (!((comp1 == BELOW && comp2 == ABOVE) || (comp1 == ABOVE && comp2 == BELOW) || (comp1 == UNKNOWN && comp2 == UNKNOWN) ||
299 (comp1 == SAME && comp2 == SAME))) {
300 invalid = true;
301 return false;
302 }
303 }
304 }
305 return !invalid;
306}
307
308bool Order::merge(uint_fast64_t var1, uint_fast64_t var2) {
309 return mergeNodes(getNode(var1), getNode(var2));
310}
311
312/*** Checking on the order ***/
313
314Order::NodeComparison Order::compare(uint_fast64_t state1, uint_fast64_t state2, NodeComparison hypothesis) {
315 return compare(getNode(state1), getNode(state2), hypothesis);
316}
317
318Order::NodeComparison Order::compareFast(uint_fast64_t state1, uint_fast64_t state2, NodeComparison hypothesis) const {
319 auto res = compareFast(getNode(state1), getNode(state2), hypothesis);
320 return res;
321}
322
324 if (node1 != nullptr && node2 != nullptr) {
325 if (node1 == node2) {
326 return SAME;
327 }
328
329 if ((hypothesis == UNKNOWN || hypothesis == ABOVE) && ((node1 == top || node2 == bottom) || aboveFast(node1, node2))) {
330 return ABOVE;
331 }
332
333 if ((hypothesis == UNKNOWN || hypothesis == BELOW) && ((node2 == top || node1 == bottom) || aboveFast(node2, node1))) {
334 return BELOW;
335 }
336 } else if (node1 == top || node2 == bottom) {
337 return ABOVE;
338 } else if (node2 == top || node1 == bottom) {
339 return BELOW;
340 }
341 return UNKNOWN;
342}
343
345 if (node1 != nullptr && node2 != nullptr) {
346 auto comp = compareFast(node1, node2, hypothesis);
347 if (comp != UNKNOWN) {
348 return comp;
349 }
350 if ((hypothesis == UNKNOWN || hypothesis == ABOVE) && above(node1, node2)) {
351 // This does not require !above(node2, node1): mergeNodes calls compare() on every
352 // pair in both directions to detect exactly that antisymmetry violation and reject
353 // the merge, so this function must tolerate it transiently rather than fail here.
354 return ABOVE;
355 }
356
357 if ((hypothesis == UNKNOWN || hypothesis == BELOW) && above(node2, node1)) {
358 return BELOW;
359 }
360 } else if (node1 == top || node2 == bottom) {
361 return ABOVE;
362 } else if (node2 == top || node1 == bottom) {
363 return BELOW;
364 }
365 return UNKNOWN;
366}
367
368bool Order::contains(uint_fast64_t state) const {
369 return state < numberOfStates && nodes[state] != nullptr;
370}
371
373 return bottom;
374}
375
377 STORM_LOG_ASSERT(!doneStates.full() || numberOfAddedStates == numberOfStates,
378 "All states are marked done, but not all states have been added to the order.");
379 return doneStates.full();
380}
381
382uint_fast64_t Order::getNextDoneState(uint_fast64_t state) const {
383 return doneStates.getNextSetIndex(state + 1);
384}
385
386Order::Node* Order::getNode(uint_fast64_t stateNumber) const {
387 assert(stateNumber < numberOfStates);
388 return nodes[stateNumber];
389}
390
391std::vector<Order::Node*> Order::getNodes() const {
392 return nodes;
393}
394
395std::vector<uint_fast64_t>& Order::getStatesSorted() {
396 return statesSorted;
397}
398
400 return top;
401}
402
403uint_fast64_t Order::getNumberOfAddedStates() const {
404 return numberOfAddedStates;
405}
406
407uint_fast64_t Order::getNumberOfStates() const {
408 return numberOfStates;
409}
410
411bool Order::isBottomState(uint_fast64_t state) const {
412 auto states = bottom->states;
413 return states.find(state) != states.end();
414}
415
416bool Order::isTopState(uint_fast64_t state) const {
417 auto states = top->states;
418 return states.find(state) != states.end();
419}
420
422 return onlyBottomTopOrder;
423}
424
425std::vector<uint_fast64_t> Order::sortStates(std::vector<uint_fast64_t>* states) {
426 STORM_LOG_ASSERT(states != nullptr, "States to sort must be given.");
427 uint_fast64_t numberOfStatesToSort = states->size();
428 std::vector<uint_fast64_t> result;
429 // Go over all states
430 for (auto state : *states) {
431 bool unknown = false;
432 if (result.size() == 0) {
433 result.push_back(state);
434 } else {
435 bool added = false;
436 for (auto itr = result.begin(); itr != result.end(); ++itr) {
437 auto compareRes = compare(state, (*itr));
438 if (compareRes == ABOVE || compareRes == SAME) {
439 // insert at current pointer (while keeping other values)
440 result.insert(itr, state);
441 added = true;
442 break;
443 } else if (compareRes == UNKNOWN) {
444 unknown = true;
445 break;
446 }
447 }
448 if (unknown) {
449 break;
450 }
451 if (!added) {
452 result.push_back(state);
453 }
454 }
455 }
456 while (result.size() < numberOfStatesToSort) {
457 result.push_back(numberOfStates);
458 }
459 STORM_LOG_ASSERT(result.size() == numberOfStatesToSort, "Not all states could be sorted (or padded with the sentinel value).");
460 return result;
461}
462
463std::pair<std::pair<uint_fast64_t, uint_fast64_t>, std::vector<uint_fast64_t>> Order::sortStatesForForward(uint_fast64_t currentState,
464 std::vector<uint_fast64_t> const& states) {
465 std::vector<uint_fast64_t> statesSorted;
466 statesSorted.push_back(currentState);
467 // Go over all states
468 bool oneUnknown = false;
469 bool unknown = false;
470 uint_fast64_t s1 = numberOfStates;
471 uint_fast64_t s2 = numberOfStates;
472 for (auto& state : states) {
473 unknown = false;
474 bool added = false;
475 for (auto itr = statesSorted.begin(); itr != statesSorted.end(); ++itr) {
476 auto compareRes = compare(state, (*itr));
477 if (compareRes == ABOVE || compareRes == SAME) {
478 if (!contains(state) && compareRes == ABOVE) {
479 add(state);
480 }
481 added = true;
482 // insert at current pointer (while keeping other values)
483 statesSorted.insert(itr, state);
484 break;
485 } else if (compareRes == UNKNOWN && !oneUnknown) {
486 // We miss state in the result.
487 s1 = state;
488 s2 = *itr;
489 oneUnknown = true;
490 added = true;
491 break;
492 } else if (compareRes == UNKNOWN && oneUnknown) {
493 unknown = true;
494 added = true;
495 break;
496 }
497 }
498 if (!added) {
499 // State will be last in the list
500 statesSorted.push_back(state);
501 }
502 if (unknown && oneUnknown) {
503 break;
504 }
505 }
506 if (!unknown && oneUnknown) {
507 STORM_LOG_ASSERT(statesSorted.size() == states.size(), "Expected all but the single unresolved state to have been sorted.");
508 s2 = numberOfStates;
509 }
510 STORM_LOG_ASSERT(s1 == numberOfStates || (s1 != numberOfStates && s2 == numberOfStates && statesSorted.size() == states.size()) ||
511 (s1 != numberOfStates && s2 != numberOfStates && statesSorted.size() < states.size()),
512 "Inconsistent result: (s1, s2) and the number of sorted states must agree on how far sorting got.");
513
514 return {{s1, s2}, statesSorted};
515}
516
517std::pair<std::pair<uint_fast64_t, uint_fast64_t>, std::vector<uint_fast64_t>> Order::sortStatesUnorderedPair(const std::vector<uint_fast64_t>* states) {
518 STORM_LOG_ASSERT(states != nullptr, "States to sort must be given.");
519 [[maybe_unused]] uint_fast64_t numberOfStatesToSort = states->size();
520 std::vector<uint_fast64_t> result;
521 // Go over all states
522 for (auto state : *states) {
523 bool unknown = false;
524 if (result.size() == 0) {
525 result.push_back(state);
526 } else {
527 bool added = false;
528 for (auto itr = result.begin(); itr != result.end(); ++itr) {
529 auto compareRes = compare(state, (*itr));
530 if (compareRes == ABOVE || compareRes == SAME) {
531 // insert at current pointer (while keeping other values)
532 result.insert(itr, state);
533 added = true;
534 break;
535 } else if (compareRes == UNKNOWN) {
536 return {{(*itr), state}, std::move(result)};
537 }
538 }
539 if (unknown) {
540 break;
541 }
542 if (!added) {
543 result.push_back(state);
544 }
545 }
546 }
547
548 STORM_LOG_ASSERT(result.size() == numberOfStatesToSort, "Not all states could be sorted.");
549 return {{numberOfStates, numberOfStates}, std::move(result)};
550}
551
552std::vector<uint_fast64_t> Order::sortStates(storm::storage::BitVector* states) {
553 uint_fast64_t numberOfStatesToSort = states->getNumberOfSetBits();
554 std::vector<uint_fast64_t> result;
555 // Go over all states
556 for (auto state : *states) {
557 bool unknown = false;
558 if (result.size() == 0) {
559 result.push_back(state);
560 } else {
561 bool added = false;
562 for (auto itr = result.begin(); itr != result.end(); ++itr) {
563 auto compareRes = compare(state, (*itr));
564 if (compareRes == ABOVE || compareRes == SAME) {
565 // insert at current pointer (while keeping other values)
566 result.insert(itr, state);
567 added = true;
568 break;
569 } else if (compareRes == UNKNOWN) {
570 unknown = true;
571 break;
572 }
573 }
574 if (unknown) {
575 break;
576 }
577 if (!added) {
578 result.push_back(state);
579 }
580 }
581 }
582 while (result.size() < numberOfStatesToSort) {
583 result.push_back(numberOfStates);
584 }
585 STORM_LOG_ASSERT(result.size() == numberOfStatesToSort, "Not all states could be sorted (or padded with the sentinel value).");
586 return result;
587}
588
589/*** Checking on helpfunctionality for building of order ***/
590
591std::shared_ptr<Order> Order::copy() const {
592 STORM_LOG_ASSERT(!isInvalid(), "Cannot copy an invalid order.");
593 return std::make_shared<Order>(*this);
594}
595
596/*** Setters ***/
597void Order::setDoneState(uint_fast64_t stateNumber) {
598 doneStates.set(stateNumber);
599}
600
601/*** Output ***/
602
603void Order::toDotOutput() const {
604 // This emits a Graphviz DOT document to stdout for external consumption, not a log message.
605 std::cout << "Dot Output:\n"
606 << "digraph model {\n";
607
608 // Vertices of the digraph
609 storm::storage::BitVector stateCoverage = storm::storage::BitVector(doneStates);
610 for (uint_fast64_t i = 0; i < numberOfStates; ++i) {
611 if (nodes[i] != nullptr) {
612 stateCoverage.set(i);
613 }
614 }
615 for (uint_fast64_t i = stateCoverage.getNextSetIndex(0); i != numberOfStates; i = stateCoverage.getNextSetIndex(i + 1)) {
616 for (uint_fast64_t j = i + 1; j < numberOfStates; j++) {
617 if (getNode(j) == getNode(i)) {
618 stateCoverage.set(j, false);
619 }
620 }
621 std::cout << "\t" << nodeName(*getNode(i)) << " [ label = \"" << nodeLabel(*getNode(i)) << "\" ];\n";
622 }
623
624 // Edges of the digraph
625 for (uint_fast64_t i = stateCoverage.getNextSetIndex(0); i != numberOfStates; i = stateCoverage.getNextSetIndex(i + 1)) {
626 storm::storage::BitVector v = storm::storage::BitVector(numberOfStates, false);
627 Node* currentNode = getNode(i);
628 for (uint_fast64_t s1 : getNode(i)->statesAbove) {
629 v |= (currentNode->statesAbove & getNode(s1)->statesAbove);
630 }
631
632 std::set<Node*> seenNodes;
633 for (uint_fast64_t state : currentNode->statesAbove) {
634 Node* n = getNode(state);
635 if (std::find(seenNodes.begin(), seenNodes.end(), n) == seenNodes.end()) {
636 seenNodes.insert(n);
637 if (!v[state]) {
638 std::cout << "\t" << nodeName(*currentNode) << " -> " << nodeName(*getNode(state)) << ";\n";
639 }
640 }
641 }
642 }
643 // Graphviz Output end
644 std::cout << "}\n";
645}
646
647void Order::dotOutputToFile(std::ofstream& dotOutfile) const {
648 // Graphviz Output start
649 dotOutfile << "Dot Output:\n"
650 << "digraph model {\n";
651
652 // Vertices of the digraph
653 storm::storage::BitVector stateCoverage = storm::storage::BitVector(numberOfStates, true);
654 for (uint_fast64_t i = stateCoverage.getNextSetIndex(0); i != numberOfStates; i = stateCoverage.getNextSetIndex(i + 1)) {
655 if (getNode(i) == nullptr) {
656 continue;
657 }
658 for (uint_fast64_t j = i + 1; j < numberOfStates; j++) {
659 if (getNode(j) == getNode(i)) {
660 stateCoverage.set(j, false);
661 }
662 }
663
664 dotOutfile << "\t" << nodeName(*getNode(i)) << " [ label = \"" << nodeLabel(*getNode(i)) << "\" ];\n";
665 }
666
667 // Edges of the digraph
668 for (uint_fast64_t i = stateCoverage.getNextSetIndex(0); i != numberOfStates; i = stateCoverage.getNextSetIndex(i + 1)) {
669 storm::storage::BitVector v = storm::storage::BitVector(numberOfStates, false);
670 Node* currentNode = getNode(i);
671 if (currentNode == nullptr) {
672 continue;
673 }
674
675 for (uint_fast64_t s1 : getNode(i)->statesAbove) {
676 v |= (currentNode->statesAbove & getNode(s1)->statesAbove);
677 }
678
679 std::set<Node*> seenNodes;
680 for (uint_fast64_t state : currentNode->statesAbove) {
681 Node* n = getNode(state);
682 if (std::find(seenNodes.begin(), seenNodes.end(), n) == seenNodes.end()) {
683 seenNodes.insert(n);
684 if (!v[state]) {
685 dotOutfile << "\t" << nodeName(*currentNode) << " -> " << nodeName(*getNode(state)) << ";\n";
686 }
687 }
688 }
689 }
690
691 // Graphviz Output end
692 dotOutfile << "}\n";
693}
694
695/*** Private methods ***/
696
697void Order::init(uint_fast64_t numberOfStates, storage::Decomposition<storage::StronglyConnectedComponent> decomposition, bool doneBuilding) {
698 this->numberOfStates = numberOfStates;
699 this->invalid = false;
700 this->nodes = std::vector<Node*>(numberOfStates, nullptr);
701 this->doneStates = storm::storage::BitVector(numberOfStates, false);
702 STORM_LOG_ASSERT(doneStates.getNumberOfSetBits() == 0, "A freshly initialized order must not have any done states yet.");
703 if (decomposition.size() == 0) {
704 this->trivialStates = storm::storage::BitVector(numberOfStates, true);
705 } else {
706 this->trivialStates = storm::storage::BitVector(numberOfStates, false);
707 for (auto& scc : decomposition) {
708 if (scc.size() == 1) {
709 trivialStates.set(*(scc.begin()));
710 }
711 }
712 }
713 this->top = allocateNode();
714 this->bottom = allocateNode();
715 this->top->statesAbove = storm::storage::BitVector(numberOfStates, false);
716 this->bottom->statesAbove = storm::storage::BitVector(numberOfStates, false);
717 this->doneBuilding = doneBuilding;
718}
719
720bool Order::aboveFast(Node* node1, Node* node2) const {
721 bool found = false;
722 for (auto const& state : node1->states) {
723 found = ((node2->statesAbove))[state];
724 if (found) {
725 break;
726 }
727 }
728 return found;
729}
730
731bool Order::above(Node* node1, Node* node2) {
732 assert(!aboveFast(node1, node2));
733 // Check whether node1 is above node2 by going over all states that are above state 2
734 bool above = false;
735 // Only do this when we have to deal with forward reasoning or we are not yet done with the building of the order
736 if (!trivialStates.full() || !doneBuilding) {
737 // First gather all states that are above node 2;
738
739 storm::storage::BitVector statesSeen((node2->statesAbove));
740 std::queue<uint_fast64_t> statesToHandle;
741 for (auto state : statesSeen) {
742 statesToHandle.push(state);
743 }
744 while (!above && !statesToHandle.empty()) {
745 // Get first item from the queue
746 auto state = statesToHandle.front();
747 statesToHandle.pop();
748 auto node = getNode(state);
749 if (aboveFast(node1, node)) {
750 above = true;
751 continue;
752 }
753 for (auto newState : node->statesAbove) {
754 if (!statesSeen[newState]) {
755 statesToHandle.push(newState);
756 statesSeen.set(newState);
757 }
758 }
759 }
760 }
761 if (above) {
762 for (auto state : node1->states) {
763 node2->statesAbove.set(state);
764 }
765 }
766 return above;
767}
768
769std::string Order::nodeName(Node n) const {
770 auto itr = n.states.begin();
771 std::string name = "n" + std::to_string(*itr);
772 return name;
773}
774
775std::string Order::nodeLabel(Node n) const {
776 if (n.states == top->states) {
777 return "=)";
778 }
779 if (n.states == bottom->states) {
780 return "=(";
781 }
782 auto itr = n.states.begin();
783 std::string label = "s" + std::to_string(*itr);
784 ++itr;
785 if (itr != n.states.end()) {
786 label = "[" + label + "]";
787 }
788 return label;
789}
790
792 return !doneStates.full();
793}
794
795bool Order::isTrivial(uint_fast64_t state) {
796 return trivialStates[state];
797}
798
799std::pair<uint_fast64_t, bool> Order::getNextStateNumber() {
800 while (!statesSorted.empty()) {
801 auto state = statesSorted.back();
802 statesSorted.pop_back();
803 if (!doneStates[state]) {
804 return {state, true};
805 }
806 }
807 return {numberOfStates, true};
808}
809
810std::pair<uint_fast64_t, bool> Order::getStateToHandle() {
811 STORM_LOG_ASSERT(existsStateToHandle(), "No state to handle exists.");
812 auto state = statesToHandle.back();
813 statesToHandle.pop_back();
814 return {state, false};
815}
816
818 while (!statesToHandle.empty() && doneStates[statesToHandle.back()]) {
819 statesToHandle.pop_back();
820 }
821 return !statesToHandle.empty();
822}
823
824void Order::addStateToHandle(uint_fast64_t state) {
825 if (!doneStates[state]) {
826 statesToHandle.push_back(state);
827 }
828}
829
830void Order::addStateSorted(uint_fast64_t state) {
831 statesSorted.push_back(state);
832}
833
834std::pair<bool, bool> Order::allAboveBelow(std::vector<uint_fast64_t> const states, uint_fast64_t state) {
835 auto allAbove = true;
836 auto allBelow = true;
837 for (auto& checkState : states) {
838 auto comp = compare(checkState, state);
839 allAbove &= (comp == ABOVE || comp == SAME);
840 allBelow &= (comp == BELOW || comp == SAME);
841 }
842 return {allAbove, allBelow};
843}
844
845uint_fast64_t Order::getNumberOfDoneStates() const {
846 return doneStates.getNumberOfSetBits();
847}
848
849bool Order::isInvalid() const {
850 return invalid;
851}
852} // namespace analysis
853} // namespace storm
uint_fast64_t getNumberOfDoneStates() const
Definition Order.cpp:845
void addAbove(uint_fast64_t state, Node *node)
Adds a node with the given state above the given node.
Definition Order.cpp:145
bool isTrivial(uint_fast64_t state)
Definition Order.cpp:795
void addStateSorted(uint_fast64_t state)
Definition Order.cpp:830
Node * getBottom() const
Retrieves the bottom node of the order.
Definition Order.cpp:372
bool contains(uint_fast64_t state) const
Check if state is already contained in order.
Definition Order.cpp:368
bool isInvalid() const
Definition Order.cpp:849
Order::NodeComparison compareFast(uint_fast64_t state1, uint_fast64_t state2, NodeComparison hypothesis=UNKNOWN) const
Definition Order.cpp:318
Order::NodeComparison compare(uint_fast64_t state1, uint_fast64_t state2, NodeComparison hypothesis=UNKNOWN)
Compares the level of the nodes of the states.
Definition Order.cpp:314
std::pair< uint_fast64_t, bool > getStateToHandle()
Definition Order.cpp:810
std::vector< uint_fast64_t > & getStatesSorted()
Definition Order.cpp:395
friend void swap(Order &first, Order &second) noexcept
Definition Order.cpp:115
std::vector< uint_fast64_t > sortStates(std::vector< uint_fast64_t > *states)
Sorts the given states if possible.
Definition Order.cpp:425
NodeComparison
Constants for comparison of nodes/states.
Definition Order.h:18
Order()
Constructs a new Order.
Definition Order.cpp:63
void toDotOutput() const
Prints the dot output to stdout.
Definition Order.cpp:603
void dotOutputToFile(std::ofstream &dotOutfile) const
Writes dotoutput to the given file.
Definition Order.cpp:647
Order(storm::storage::BitVector const &topStates, storm::storage::BitVector const &bottomStates, uint_fast64_t numberOfStates, storage::Decomposition< storage::StronglyConnectedComponent > sccsSorted, std::vector< uint_fast64_t > statesSorted)
Constructs an order with the given top and bottom states.
Definition Order.cpp:10
void addRelation(uint_fast64_t above, uint_fast64_t below, bool allowMerge=false)
Adds a new relation between two states to the order.
Definition Order.cpp:221
Node * getNode(uint_fast64_t state) const
Retrieves the pointer to a Node at which the state occurs.
Definition Order.cpp:386
bool merge(uint_fast64_t var1, uint_fast64_t var2)
Merges node of var2 into node of var1.
Definition Order.cpp:308
std::vector< Node * > getNodes() const
Returns the vector with the nodes of the order.
Definition Order.cpp:391
bool mergeNodes(Node *node1, Node *node2)
Merges node2 into node1.
Definition Order.cpp:263
std::pair< bool, bool > allAboveBelow(std::vector< uint_fast64_t > const states, uint_fast64_t state)
Definition Order.cpp:834
uint_fast64_t getNextDoneState(uint_fast64_t state) const
Returns the next done state of the order, returns the number of state if end of done states is reache...
Definition Order.cpp:382
bool getDoneBuilding() const
Returns true if done building the order.
Definition Order.cpp:376
void addToNode(uint_fast64_t state, Node *node)
Adds state to the states of the given node.
Definition Order.cpp:244
bool isTopState(uint_fast64_t) const
Checks if the given state is a top state.
Definition Order.cpp:416
std::pair< std::pair< uint_fast64_t, uint_fast64_t >, std::vector< uint_fast64_t > > sortStatesForForward(uint_fast64_t currentState, std::vector< uint_fast64_t > const &successors)
Sorts the given states if possible.
Definition Order.cpp:463
std::pair< std::pair< uint_fast64_t, uint_fast64_t >, std::vector< uint_fast64_t > > sortStatesUnorderedPair(const std::vector< uint_fast64_t > *states)
Sorts the given states if possible.
Definition Order.cpp:517
void addStateToHandle(uint_fast64_t state)
Definition Order.cpp:824
void addBetween(uint_fast64_t state, Node *node1, Node *node2)
Adds a node with the given state below node1 and above node2.
Definition Order.cpp:185
Order & operator=(Order other)
Definition Order.cpp:110
uint_fast64_t getNumberOfStates() const
Returns the number of possible states in the order.
Definition Order.cpp:407
void addBelow(uint_fast64_t state, Node *node)
Adds a node with the given state below the given node.
Definition Order.cpp:165
void setDoneState(uint_fast64_t sccNumber)
Definition Order.cpp:597
std::pair< uint_fast64_t, bool > getNextStateNumber()
Definition Order.cpp:799
std::shared_ptr< Order > copy() const
Creates a copy of the calling Order.
Definition Order.cpp:591
bool isOnlyBottomTopOrder() const
Returns if the order only consists of bottom and top states (so no in-between nodes).
Definition Order.cpp:421
uint_fast64_t getNumberOfAddedStates() const
Returns the number of added states.
Definition Order.cpp:403
bool isBottomState(uint_fast64_t) const
Checks if the given state is a bottom state.
Definition Order.cpp:411
Node * getTop() const
Retrieves the top node of the order.
Definition Order.cpp:399
void add(uint_fast64_t state)
Adds state between the top and bottom node of the order.
Definition Order.cpp:139
void addRelationNodes(storm::analysis::Order::Node *above, storm::analysis::Order::Node *below, bool allowMerge=false)
Adds a new relation between two nodes to the order.
Definition Order.cpp:226
A bit vector that is internally represented as a vector of 64-bit values.
Definition BitVector.h:16
uint64_t getNextSetIndex(uint64_t startingIndex) const
Retrieves the index of the bit that is the next bit set to true in the bit vector.
uint64_t getNumberOfSetBits() const
Returns the number of bits that are set to true in this bit vector.
void set(uint64_t index, bool value=true)
Sets the given truth value at the given index.
This class represents the decomposition of a model into blocks which are of the template type.
std::size_t size() const
Retrieves the number of blocks of this decomposition.
#define STORM_LOG_INFO(message)
Definition logging.h:34
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:9
void swap(Order &first, Order &second) noexcept
Definition Order.cpp:115
Nodes of the Reachability Order.
Definition Order.h:28
boost::container::flat_set< uint_fast64_t > states
Definition Order.h:29
storm::storage::BitVector statesAbove
Definition Order.h:30