Storm
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
BucketPriorityQueue.cpp
Go to the documentation of this file.
4
5#include <cmath>
6
7namespace storm::dft {
8namespace storage {
9
10template<typename PriorityType>
11BucketPriorityQueue<PriorityType>::BucketPriorityQueue(size_t nrBuckets, double lowerValue, double ratio, bool higher)
12 : buckets(nrBuckets), currentBucket(nrBuckets), nrUnsortedItems(0), lowerValue(lowerValue), higher(higher), logBase(std::log(ratio)), nrBuckets(nrBuckets) {
13 compare = ([](PriorityTypePointer a, PriorityTypePointer b) { return *a < *b; });
14}
15
16template<typename PriorityType>
18 if (currentBucket < nrBuckets && nrUnsortedItems > buckets[currentBucket].size() / 10) {
19 // Sort current bucket
20 std::make_heap(buckets[currentBucket].begin(), buckets[currentBucket].end(), compare);
21 nrUnsortedItems = 0;
22 }
23}
24
25template<typename PriorityType>
27 return currentBucket == nrBuckets && immediateBucket.empty();
28}
29
30template<typename PriorityType>
32 size_t size = immediateBucket.size();
33 for (size_t i = currentBucket; currentBucket < nrBuckets; ++i) {
34 size += buckets[i].size();
35 }
36 return size;
37}
38
39template<typename PriorityType>
40typename BucketPriorityQueue<PriorityType>::PriorityTypePointer const& BucketPriorityQueue<PriorityType>::top() const {
41 if (!immediateBucket.empty()) {
42 return immediateBucket.back();
43 }
44 STORM_LOG_ASSERT(!empty(), "BucketPriorityQueue is empty");
45 return buckets[currentBucket].front();
46}
47
48template<typename PriorityType>
49void BucketPriorityQueue<PriorityType>::push(PriorityTypePointer const& item) {
50 if (item->isExpand()) {
51 immediateBucket.push_back(item);
52 return;
53 }
54 size_t bucket = getBucket(item->getPriority());
55 if (bucket < currentBucket) {
56 currentBucket = bucket;
57 nrUnsortedItems = 0;
58 }
59 buckets[bucket].push_back(item);
60 if (bucket == currentBucket) {
61 // Inserted in first bucket
62 if (AUTOSORT) {
63 std::push_heap(buckets[currentBucket].begin(), buckets[currentBucket].end(), compare);
64 } else {
65 ++nrUnsortedItems;
66 }
67 }
68}
69
70template<typename PriorityType>
71void BucketPriorityQueue<PriorityType>::update(PriorityTypePointer const& item, double oldPriority) {
72 STORM_LOG_ASSERT(!item->isExpand(), "Item is marked for expansion");
73 size_t newBucket = getBucket(item->getPriority());
74 size_t oldBucket = getBucket(oldPriority);
75
76 if (oldBucket == newBucket) {
77 if (currentBucket < newBucket) {
78 // No change as the bucket is not sorted yet
79 } else {
80 if (AUTOSORT) {
81 // Sort first bucket
82 fix();
83 } else {
84 ++nrUnsortedItems;
85 }
86 }
87 } else {
88 // Move to new bucket
89 STORM_LOG_ASSERT(newBucket < oldBucket, "Will update item " << item->getId() << " from " << oldBucket << " to higher bucket " << newBucket);
90 if (newBucket < currentBucket) {
91 currentBucket = newBucket;
92 nrUnsortedItems = 0;
93 }
94 // Remove old entry by swap-and-pop
95 if (buckets[oldBucket].size() >= 2) {
96 // Find old index by linear search
97 // Notice: using a map to remember index was not efficient
98 size_t oldIndex = 0;
99 for (; oldIndex < buckets[oldBucket].size(); ++oldIndex) {
100 if (buckets[oldBucket][oldIndex]->getId() == item->getId()) {
101 break;
102 }
103 }
104 STORM_LOG_ASSERT(oldIndex < buckets[oldBucket].size(), "Id " << item->getId() << " not found");
105 std::iter_swap(buckets[oldBucket].begin() + oldIndex, buckets[oldBucket].end() - 1);
106 }
107 buckets[oldBucket].pop_back();
108 // Insert new element
109 buckets[newBucket].push_back(item);
110 if (newBucket == currentBucket) {
111 if (AUTOSORT) {
112 // Sort in first bucket
113 std::push_heap(buckets[currentBucket].begin(), buckets[currentBucket].end(), compare);
114 } else {
115 ++nrUnsortedItems;
116 }
117 }
118 }
119}
120
121template<typename PriorityType>
122typename BucketPriorityQueue<PriorityType>::PriorityTypePointer BucketPriorityQueue<PriorityType>::pop() {
123 if (!immediateBucket.empty()) {
124 PriorityTypePointer item = immediateBucket.back();
125 immediateBucket.pop_back();
126 return item;
127 }
128 STORM_LOG_ASSERT(!empty(), "BucketPriorityQueue is empty");
129 std::pop_heap(buckets[currentBucket].begin(), buckets[currentBucket].end(), compare);
130 PriorityTypePointer item = buckets[currentBucket].back();
131 buckets[currentBucket].pop_back();
132 if (buckets[currentBucket].empty()) {
133 // Find next bucket with elements
134 for (; currentBucket < nrBuckets; ++currentBucket) {
135 if (!buckets[currentBucket].empty()) {
136 nrUnsortedItems = buckets[currentBucket].size();
137 if (AUTOSORT) {
138 fix();
139 }
140 break;
141 }
142 }
143 }
144 return item;
145}
146
147template<typename PriorityType>
148size_t BucketPriorityQueue<PriorityType>::getBucket(double priority) const {
149 STORM_LOG_ASSERT(priority >= lowerValue, "Priority " << priority << " is too low");
150
151 // For possible values greater 1
152 double tmpBucket = std::log(priority - lowerValue) / logBase;
153 tmpBucket += buckets.size() / 2;
154 if (tmpBucket < 0) {
155 tmpBucket = 0;
156 }
157 size_t newBucket = static_cast<size_t>(tmpBucket);
158 // For values ensured to be lower 1
159 if (newBucket >= nrBuckets) {
160 newBucket = nrBuckets - 1;
161 }
162 if (!higher) {
163 newBucket = nrBuckets - 1 - newBucket;
164 }
165 STORM_LOG_ASSERT(newBucket < nrBuckets, "Priority " << priority << " is too high");
166 return newBucket;
167}
168
169template<typename PriorityType>
170void BucketPriorityQueue<PriorityType>::print(std::ostream& out) const {
171 out << "Bucket priority queue with size " << buckets.size() << ", lower value: " << lowerValue << " and logBase: " << logBase << '\n';
172 out << "Immediate bucket: ";
173 for (auto item : immediateBucket) {
174 out << item->getId() << ", ";
175 }
176 out << '\n';
177 out << "Current bucket (" << currentBucket << ") has " << nrUnsortedItems << " unsorted items\n";
178 for (size_t bucket = 0; bucket < buckets.size(); ++bucket) {
179 if (!buckets[bucket].empty()) {
180 out << "Bucket " << bucket << ":\n";
181 for (auto item : buckets[bucket]) {
182 out << "\t" << item->getId() << ": " << item->getPriority() << '\n';
183 }
184 }
185 }
186}
187
188template<typename PriorityType>
190 out << "Bucket sizes: " << immediateBucket.size() << " | ";
191 for (size_t bucket = 0; bucket < buckets.size(); ++bucket) {
192 out << buckets[bucket].size() << " ";
193 }
194 out << '\n';
195}
196
197// Template instantiations
202
207
208} // namespace storage
209} // namespace storm::dft
Priority queue based on buckets.
void update(PriorityTypePointer const &item, double oldPriority)
Update existing element.
void print(std::ostream &out) const
Print info about priority queue.
void push(PriorityTypePointer const &item)
Add element.
PriorityTypePointer const & top() const
Get element with highest priority.
PriorityTypePointer pop()
Get element with highest priority and remove it from the queue.
std::size_t size() const
Return number of entries.
BucketPriorityQueue(size_t nrBuckets, double lowerValue, double ratio, bool higher)
Create new priority queue.
void printSizes(std::ostream &out) const
Print sizes of buckets.
bool empty() const
Check whether queue is empty.
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:11