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