Storm 1.14.0.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
BitVector.cpp
Go to the documentation of this file.
2
3#include <algorithm>
4#include <bit>
5#include <bitset>
6#include <boost/functional/hash.hpp>
7#include <cstddef>
8#include <iostream>
9#include <utility>
10
13
14// Uncomment the following line to enable additional assertions for debugging bitvector operations.
15// #define ASSERT_BITVECTOR
16
17namespace storm {
18namespace storage {
19
20BitVector::const_iterator::const_iterator() : dataPtr(nullptr), currentIndex(0), endIndex(0) {};
21
22BitVector::const_iterator::const_iterator(uint64_t const* dataPtr, uint64_t startIndex, uint64_t endIndex, bool setOnFirstBit)
23 : dataPtr(dataPtr), endIndex(endIndex) {
24 if (setOnFirstBit) {
25 // Set the index of the first set bit in the vector.
26 currentIndex = getNextIndexWithValue<true>(dataPtr, startIndex, endIndex);
27 } else {
28 currentIndex = startIndex;
29 }
30}
31
32BitVector::const_iterator::const_iterator(const_iterator const& other) : dataPtr(other.dataPtr), currentIndex(other.currentIndex), endIndex(other.endIndex) {
33 // Intentionally left empty.
34}
35
37 // Only assign contents if the source and target are not the same.
38 if (this != &other) {
39 dataPtr = other.dataPtr;
40 currentIndex = other.currentIndex;
41 endIndex = other.endIndex;
42 }
43 return *this;
44}
45
47 currentIndex = getNextIndexWithValue<true>(dataPtr, ++currentIndex, endIndex);
48 return *this;
49}
50
52 BitVector::const_iterator copy{*this};
53 ++(*this);
54 return copy;
55}
56
58 for (size_t i = 0; i < n; ++i) {
59 currentIndex = getNextIndexWithValue<true>(dataPtr, ++currentIndex, endIndex);
60 }
61 return *this;
62}
63
65 return currentIndex;
66}
67
69 return currentIndex != other.currentIndex;
70}
71
73 return currentIndex == other.currentIndex;
74}
75
76BitVector::const_reverse_iterator::const_reverse_iterator() : dataPtr(nullptr), currentIndex(0), lowerBound(0) {};
77
78BitVector::const_reverse_iterator::const_reverse_iterator(uint64_t const* dataPtr, uint64_t upperBound, uint64_t lowerBound, bool setOnFirstBit)
79 : dataPtr(dataPtr), lowerBound(lowerBound) {
80 if (setOnFirstBit) {
81 // Set the index of the first set bit in the vector.
82 currentIndex = getNextIndexWithValue<true, true>(dataPtr, lowerBound, upperBound);
83 } else {
84 currentIndex = upperBound;
85 }
86}
87
89 : dataPtr(other.dataPtr), currentIndex(other.currentIndex), lowerBound(other.lowerBound) {
90 // Intentionally left empty.
91}
92
94 // Only assign contents if the source and target are not the same.
95 if (this != &other) {
96 dataPtr = other.dataPtr;
97 currentIndex = other.currentIndex;
98 lowerBound = other.lowerBound;
99 }
100 return *this;
101}
102
104 currentIndex = getNextIndexWithValue<true, true>(dataPtr, lowerBound, --currentIndex);
105 return *this;
106}
112
114 for (size_t i = 0; i < n; ++i) {
115 currentIndex = getNextIndexWithValue<true, true>(dataPtr, lowerBound, --currentIndex);
116 }
117 return *this;
118}
119
121 return currentIndex - 1; // the stored index is off-by-one!
122}
123
125 return currentIndex != other.currentIndex;
126}
127
129 return currentIndex == other.currentIndex;
130}
131
132BitVector::BitVector() : bitCount(0), buckets(nullptr) {
133 // Intentionally left empty.
134}
135
136BitVector::BitVector(uint64_t length, bool init) : bitCount(length), buckets(nullptr) {
137 // Compute the correct number of buckets needed to store the given number of bits.
138 uint64_t bucketCount = length >> 6;
139 if ((length & mod64mask) != 0) {
140 ++bucketCount;
141 }
142
143 // Initialize the storage with the required values.
144 if (init) {
145 buckets = new uint64_t[bucketCount];
146 std::fill_n(buckets, bucketCount, -1ull);
147 truncateLastBucket();
148 } else {
149 buckets = new uint64_t[bucketCount]();
150 }
151}
152
154 delete[] buckets;
155}
156
157template<typename InputIterator>
158BitVector::BitVector(uint64_t length, InputIterator begin, InputIterator end) : BitVector(length) {
159 set(begin, end);
160}
161
162BitVector::BitVector(uint64_t length, std::vector<uint64_t> setEntries) : BitVector(length, setEntries.begin(), setEntries.end()) {
163 // Intentionally left empty.
164}
165
166BitVector::BitVector(uint64_t bucketCount, uint64_t bitCount) : bitCount(bitCount), buckets(nullptr) {
167 STORM_LOG_ASSERT((bucketCount << 6) == bitCount, "Bit count does not match number of buckets.");
168 buckets = new uint64_t[bucketCount]();
169}
170
171BitVector::BitVector(BitVector const& other) : bitCount(other.bitCount), buckets(nullptr) {
172 buckets = new uint64_t[other.bucketCount()];
173 std::copy_n(other.buckets, other.bucketCount(), buckets);
174}
175
177 // Only perform the assignment if the source and target are not identical.
178 if (this != &other) {
179 if (buckets && bucketCount() != other.bucketCount()) {
180 delete[] buckets;
181 buckets = nullptr;
182 }
183 bitCount = other.bitCount;
184 if (!buckets) {
185 buckets = new uint64_t[other.bucketCount()];
186 }
187 std::copy_n(other.buckets, other.bucketCount(), buckets);
188 }
189 return *this;
190}
191
192bool BitVector::operator<(BitVector const& other) const {
193 if (this->size() < other.size()) {
194 return true;
195 } else if (this->size() > other.size()) {
196 return false;
197 }
198
199 uint64_t* first1 = this->buckets;
200 uint64_t* last1 = this->buckets + this->bucketCount();
201 uint64_t* first2 = other.buckets;
202
203 for (; first1 != last1; ++first1, ++first2) {
204 if (*first1 < *first2) {
205 return true;
206 } else if (*first1 > *first2) {
207 return false;
208 }
209 }
210 return false;
211}
212
213BitVector::BitVector(BitVector&& other) : bitCount(other.bitCount), buckets(other.buckets) {
214 other.bitCount = 0;
215 other.buckets = nullptr;
216}
217
219 // Only perform the assignment if the source and target are not identical.
220 if (this != &other) {
221 bitCount = other.bitCount;
222 other.bitCount = 0;
223 delete[] this->buckets;
224 this->buckets = other.buckets;
225 other.buckets = nullptr;
226 }
227
228 return *this;
229}
230
231bool BitVector::operator==(BitVector const& other) const {
232 // If the lengths of the vectors do not match, they are considered unequal.
233 if (this->bitCount != other.bitCount) {
234 return false;
235 }
236
237 // If the lengths match, we compare the buckets one by one.
238 return std::equal(this->buckets, this->buckets + this->bucketCount(), other.buckets);
239}
240
241bool BitVector::operator!=(BitVector const& other) const {
242 return !(*this == other);
243}
244
245void BitVector::set(uint64_t index, bool value) {
246 STORM_LOG_ASSERT(index < bitCount, "Invalid call to BitVector::set: written index " << index << " out of bounds.");
247 uint64_t bucket = index >> 6;
248
249 uint64_t mask = 1ull << (63 - (index & mod64mask));
250 if (value) {
251 buckets[bucket] |= mask;
252 } else {
253 buckets[bucket] &= ~mask;
254 }
255}
256
257template<typename InputIterator>
258void BitVector::set(InputIterator begin, InputIterator end, bool value) {
259 for (InputIterator it = begin; it != end; ++it) {
260 this->set(*it, value);
261 }
262}
263
264bool BitVector::operator[](uint64_t index) const {
265 uint64_t bucket = index >> 6;
266 uint64_t mask = 1ull << (63 - (index & mod64mask));
267 return (this->buckets[bucket] & mask) == mask;
268}
269
270bool BitVector::get(uint64_t index) const {
271 STORM_LOG_ASSERT(index < bitCount, "Invalid call to BitVector::get: read index " << index << " out of bounds.");
272 return (*this)[index];
273}
274
275void BitVector::resize(uint64_t newLength, bool init) {
276 if (newLength > bitCount) {
277 uint64_t newBucketCount = newLength >> 6;
278 if ((newLength & mod64mask) != 0) {
279 ++newBucketCount;
280 }
281
282 if (newBucketCount > this->bucketCount()) {
283 uint64_t* newBuckets = new uint64_t[newBucketCount];
284 std::copy_n(buckets, this->bucketCount(), newBuckets);
285 if (init) {
286 if (this->bucketCount() > 0) {
287 newBuckets[this->bucketCount() - 1] |= ((1ull << (64 - (bitCount & mod64mask))) - 1ull);
288 }
289 std::fill_n(newBuckets + this->bucketCount(), newBucketCount - this->bucketCount(), -1ull);
290 } else {
291 std::fill_n(newBuckets + this->bucketCount(), newBucketCount - this->bucketCount(), 0);
292 }
293 delete[] buckets;
294 buckets = newBuckets;
295 bitCount = newLength;
296 } else {
297 // If the underlying storage does not need to grow, we have to insert the missing bits.
298 if (init) {
299 buckets[this->bucketCount() - 1] |= ((1ull << (64 - (bitCount & mod64mask))) - 1ull);
300 }
301 bitCount = newLength;
302 }
303 truncateLastBucket();
304 } else {
305 uint64_t newBucketCount = newLength >> 6;
306 if ((newLength & mod64mask) != 0) {
307 ++newBucketCount;
308 }
309
310 // If the number of buckets needs to be reduced, we resize it now. Otherwise, we can just truncate the
311 // last bucket.
312 if (newBucketCount < this->bucketCount()) {
313 uint64_t* newBuckets = new uint64_t[newBucketCount];
314 std::copy_n(buckets, newBucketCount, newBuckets);
315 delete[] buckets;
316 buckets = newBuckets;
317 bitCount = newLength;
318 }
319 bitCount = newLength;
320 truncateLastBucket();
321 }
322}
323
324void BitVector::concat(BitVector const& other) {
325 STORM_LOG_ASSERT(size() % 64 == 0, "We expect the length of the left bitvector to be a multiple of 64.");
326 // TODO this assumption is due to the implementation of BitVector::set().
327 BitVector tmp(size() + other.size());
328 tmp.set(size(), other);
329 resize(size() + other.size(), false);
330 *this |= tmp;
331}
332
333void BitVector::expandSize(bool init) {
334 // size_t oldBitCount = bitCount;
335 bitCount = bucketCount() * 64;
336 if (init) {
337 STORM_LOG_ASSERT(false, "Not implemented as we do not foresee any need.");
338 }
339}
340
341void BitVector::grow(uint64_t minimumLength, bool init) {
342 if (minimumLength > bitCount) {
343 // We double the bitcount as long as it is less then the minimum length.
344 uint64_t newLength = std::max(static_cast<uint64_t>(64), bitCount);
345 // Note that newLength has to be initialized with a non-zero number.
346 while (newLength < minimumLength) {
347 newLength = newLength << 1;
348 }
349 resize(newLength, init);
350 }
351}
352
354 STORM_LOG_ASSERT(bitCount == other.bitCount, "Length of the bit vectors does not match.");
355 BitVector result(bitCount);
356 std::transform(this->buckets, this->buckets + this->bucketCount(), other.buckets, result.buckets,
357 [](uint64_t const& a, uint64_t const& b) { return a & b; });
358 return result;
359}
360
362 STORM_LOG_ASSERT(bitCount == other.bitCount, "Length of the bit vectors does not match.");
363 std::transform(this->buckets, this->buckets + this->bucketCount(), other.buckets, this->buckets,
364 [](uint64_t const& a, uint64_t const& b) { return a & b; });
365 return *this;
366}
367
369 STORM_LOG_ASSERT(bitCount == other.bitCount, "Length of the bit vectors does not match.");
370 BitVector result(bitCount);
371 std::transform(this->buckets, this->buckets + this->bucketCount(), other.buckets, result.buckets,
372 [](uint64_t const& a, uint64_t const& b) { return a | b; });
373 return result;
374}
375
377 STORM_LOG_ASSERT(bitCount == other.bitCount, "Length of the bit vectors does not match.");
378 std::transform(this->buckets, this->buckets + this->bucketCount(), other.buckets, this->buckets,
379 [](uint64_t const& a, uint64_t const& b) { return a | b; });
380 return *this;
381}
382
384 STORM_LOG_ASSERT(bitCount == other.bitCount, "Length of the bit vectors does not match.");
385 BitVector result(bitCount);
386 std::transform(this->buckets, this->buckets + this->bucketCount(), other.buckets, result.buckets,
387 [](uint64_t const& a, uint64_t const& b) { return a ^ b; });
388 return result;
389}
390
392 STORM_LOG_ASSERT(bitCount == other.bitCount, "Length of the bit vectors does not match.");
393 std::transform(this->buckets, this->buckets + this->bucketCount(), other.buckets, this->buckets,
394 [](uint64_t const& a, uint64_t const& b) { return a ^ b; });
395 return *this;
396}
397
399 STORM_LOG_ASSERT(bitCount == filter.bitCount, "Length of the bit vectors does not match.");
400
401 BitVector result(filter.getNumberOfSetBits());
402
403 // If the current bit vector has not too many elements compared to the given bit vector we prefer iterating
404 // over its elements.
405 if (filter.getNumberOfSetBits() / 10 < this->getNumberOfSetBits()) {
406 uint64_t position = 0;
407 for (uint64_t bit : filter) {
408 if ((*this)[bit]) {
409 result.set(position);
410 }
411 ++position;
412 }
413 } else {
414 // If the given bit vector had much fewer elements, we iterate over its elements and accept calling the
415 // more costly operation getNumberOfSetBitsBeforeIndex on the current bit vector.
416 for (uint64_t bit : (*this)) {
417 if (filter[bit]) {
418 result.set(filter.getNumberOfSetBitsBeforeIndex(bit));
419 }
420 }
421 }
422
423 return result;
424}
425
427 BitVector result(this->bitCount);
428 std::transform(this->buckets, this->buckets + this->bucketCount(), result.buckets, [](uint64_t const& a) { return ~a; });
429 result.truncateLastBucket();
430 return result;
431}
432
434 std::transform(this->buckets, this->buckets + this->bucketCount(), this->buckets, [](uint64_t const& a) { return ~a; });
435 truncateLastBucket();
436}
437
439 uint64_t firstUnsetIndex = getNextUnsetIndex(0);
440
441 // If there is no unset index, we clear the whole vector
442 if (firstUnsetIndex == this->bitCount) {
443 this->clear();
444 } else {
445 // All previous buckets have to be set to zero
446 uint64_t bucketIndex = firstUnsetIndex >> 6;
447 std::fill_n(buckets, bucketIndex, 0);
448
449 // modify the bucket in which the unset entry lies in
450 uint64_t& bucket = this->buckets[bucketIndex];
451 uint64_t indexInBucket = firstUnsetIndex & mod64mask;
452 if (indexInBucket > 0) {
453 // Clear all bits before the index
454 uint64_t mask = ~(-1ull << (64 - indexInBucket));
455 bucket &= mask;
456 }
457
458 // Set the bit at the index
459 uint64_t mask = 1ull << (63 - indexInBucket);
460 bucket |= mask;
461 }
462}
463
465 STORM_LOG_ASSERT(bitCount == other.bitCount, "Length of the bit vectors does not match.");
466
467 BitVector result(bitCount);
468 std::transform(this->buckets, this->buckets + this->bucketCount(), other.buckets, result.buckets,
469 [](uint64_t const& a, uint64_t const& b) { return (~a | b); });
470 result.truncateLastBucket();
471 return result;
472}
473
474bool BitVector::isSubsetOf(BitVector const& other) const {
475 STORM_LOG_ASSERT(bitCount == other.bitCount, "Length of the bit vectors does not match.");
476
477 uint64_t const* it1 = buckets;
478 uint64_t const* ite1 = buckets + bucketCount();
479 uint64_t const* it2 = other.buckets;
480
481 for (; it1 != ite1; ++it1, ++it2) {
482 if ((*it1 & *it2) != *it1) {
483 return false;
484 }
485 }
486 return true;
487}
488
489bool BitVector::isDisjointFrom(BitVector const& other) const {
490 STORM_LOG_ASSERT(bitCount == other.bitCount, "Length of the bit vectors does not match.");
491
492 uint64_t const* it1 = buckets;
493 uint64_t const* ite1 = buckets + bucketCount();
494 uint64_t const* it2 = other.buckets;
495
496 for (; it1 != ite1; ++it1, ++it2) {
497 if ((*it1 & *it2) != 0) {
498 return false;
499 }
500 }
501 return true;
502}
503
504bool BitVector::matches(uint64_t bitIndex, BitVector const& other) const {
505 STORM_LOG_ASSERT((bitIndex & mod64mask) == 0, "Bit index must be a multiple of 64.");
506 STORM_LOG_ASSERT(other.size() <= this->size() - bitIndex, "Bit vector argument is too long.");
507
508 // Compute the first bucket that needs to be checked and the number of buckets.
509 uint64_t index = bitIndex >> 6;
510
511 uint64_t const* first1 = buckets + index;
512 uint64_t const* first2 = other.buckets;
513 uint64_t const* last2 = other.buckets + other.bucketCount();
514
515 for (; first2 != last2; ++first1, ++first2) {
516 if (*first1 != *first2) {
517 return false;
518 }
519 }
520 return true;
521}
522
523BitVector BitVector::permute(std::vector<uint64_t> const& inversePermutation) const {
524 BitVector result(this->size());
525 for (uint64_t i = 0; i < this->size(); ++i) {
526 if (this->get(inversePermutation[i])) {
527 result.set(i, true);
528 }
529 }
530 return result;
531}
532
533BitVector BitVector::permuteGroupedVector(const std::vector<uint64_t>& inversePermutation, const std::vector<uint64_t>& rowGroupIndices) const {
534 STORM_LOG_ASSERT(inversePermutation.size() == rowGroupIndices.size() - 1, "Inverse permutation and row group indices do not match.");
535 BitVector result(this->size(), false);
536 uint64_t targetIndex = 0u;
537 for (auto const sourceGroupIndex : inversePermutation) {
538 for (uint64_t sourceIndex = rowGroupIndices[sourceGroupIndex]; sourceIndex < rowGroupIndices[sourceGroupIndex + 1]; ++sourceIndex, ++targetIndex) {
539 if (this->get(sourceIndex)) {
540 result.set(targetIndex, true);
541 }
542 }
543 }
544 STORM_LOG_ASSERT(targetIndex == result.size(), "Target index does not match the size of the result.");
545 return result;
546}
547
548void BitVector::set(uint64_t bitIndex, BitVector const& other) {
549 STORM_LOG_ASSERT((bitIndex & mod64mask) == 0, "Bit index must be a multiple of 64.");
550 STORM_LOG_ASSERT(other.size() <= this->size() - bitIndex, "Bit vector argument is too long.");
551
552 // Compute the first bucket that needs to be checked and the number of buckets.
553 uint64_t index = bitIndex >> 6;
554
555 uint64_t* first1 = buckets + index;
556 uint64_t const* first2 = other.buckets;
557 uint64_t const* last2 = other.buckets + other.bucketCount();
558
559 for (; first2 != last2; ++first1, ++first2) {
560 *first1 = *first2;
561 }
562}
563
564void BitVector::setMultiple(uint64_t bitIndex, uint64_t nrOfBits, bool newValue) {
565 // TODO we may want to optimize this code for large nrs of bits.
566 uint64_t endPos = std::min(bitIndex + nrOfBits, bitCount);
567 for (uint64_t tmpIndex = bitIndex; tmpIndex < endPos; ++tmpIndex) {
568 set(tmpIndex, newValue);
569 }
570}
571
572storm::storage::BitVector BitVector::get(uint64_t bitIndex, uint64_t numberOfBits) const {
573 uint64_t numberOfBuckets = numberOfBits >> 6;
574 uint64_t index = bitIndex >> 6;
575 STORM_LOG_ASSERT(index + numberOfBuckets <= this->bucketCount(), "Argument is out-of-range.");
576
577 storm::storage::BitVector result(numberOfBuckets, numberOfBits);
578 std::copy(this->buckets + index, this->buckets + index + numberOfBuckets, result.buckets);
579 result.truncateLastBucket();
580 return result;
581}
582
583uint64_t BitVector::getAsInt(uint64_t bitIndex, uint64_t numberOfBits) const {
584 if (numberOfBits == 0) { // It is necessary to catch this case as we might have an empty bitvector (i.e. uninitialized buckets).
585 return 0;
586 }
587 STORM_LOG_ASSERT(numberOfBits <= 64, "Number of bits must be <= 64.");
588 uint64_t const firstBucket = bitIndex >> 6; // the bucket where the value starts
589 uint8_t const bitIndexInFirstBucket = bitIndex & mod64mask; // the index within that bucket
590 uint8_t const availableBitsInFirstBucket = static_cast<uint8_t>(64 - bitIndexInFirstBucket); // number of available bits in that bucket
591
592 // First get the result in the form rr...rrxx...xx (r = result, x = garbage)
593 uint64_t result = buckets[firstBucket] << bitIndexInFirstBucket;
594 // We might have to look at the next bucket, too
595 if (availableBitsInFirstBucket < numberOfBits) {
596 result |= buckets[firstBucket + 1] >> availableBitsInFirstBucket;
597 }
598 // Get rid of the garbage bits and return the result.
599 return result >> (64 - numberOfBits);
600}
601
602uint64_t BitVector::getTwoBitsAligned(uint64_t bitIndex) const {
603 // Check whether it is aligned.
604 STORM_LOG_ASSERT(bitIndex % 64 != 63, "Bits not aligned.");
605 uint64_t bucket = bitIndex >> 6;
606 uint64_t bitIndexInBucket = bitIndex & mod64mask;
607
608 uint64_t mask;
609 if (bitIndexInBucket == 0) {
610 mask = -1ull;
611 } else {
612 mask = (1ull << (64 - bitIndexInBucket)) - 1ull;
613 }
614
615 if (bitIndexInBucket < 62) { // bitIndexInBucket + 2 < 64
616 // If the value stops before the end of the bucket, we need to erase some lower bits.
617 mask &= ~((1ull << (62 - (bitIndexInBucket))) - 1ull);
618 return (buckets[bucket] & mask) >> (62 - bitIndexInBucket);
619 } else {
620 // In this case, it suffices to take the current mask.
621 return buckets[bucket] & mask;
622 }
623}
624
625void BitVector::setFromInt(uint64_t bitIndex, uint64_t numberOfBits, uint64_t value) {
626 STORM_LOG_ASSERT(numberOfBits <= 64, "Number of bits must be <= 64.");
627 STORM_LOG_ASSERT(numberOfBits == 64 || (value >> numberOfBits) == 0,
628 "Integer value (" << value << ") too large to fit in the given number of bits (" << numberOfBits << ").");
629
630 uint64_t bucket = bitIndex >> 6;
631 uint64_t bitIndexInBucket = bitIndex & mod64mask;
632
633 uint64_t mask;
634 if (bitIndexInBucket == 0) {
635 mask = -1ull;
636 } else {
637 mask = (1ull << (64 - bitIndexInBucket)) - 1ull;
638 }
639
640 if (bitIndexInBucket + numberOfBits < 64) {
641 // If the value stops before the end of the bucket, we need to erase some lower bits.
642 mask &= ~((1ull << (64 - (bitIndexInBucket + numberOfBits))) - 1ull);
643 buckets[bucket] = (buckets[bucket] & ~mask) | (value << (64 - (bitIndexInBucket + numberOfBits)));
644 } else if (bitIndexInBucket + numberOfBits > 64) {
645 // Write the part of the value that falls into the first bucket.
646 buckets[bucket] = (buckets[bucket] & ~mask) | (value >> (numberOfBits + (bitIndexInBucket - 64)));
647 ++bucket;
648
649 // Compute the remaining number of bits.
650 numberOfBits -= (64 - bitIndexInBucket);
651
652 // Shift the bits of the value such that the already set bits disappear.
653 value <<= (64 - numberOfBits);
654
655 // Put the remaining bits in their place.
656 mask = ((1ull << (64 - numberOfBits)) - 1ull);
657 buckets[bucket] = (buckets[bucket] & mask) | value;
658 } else {
659 buckets[bucket] = (buckets[bucket] & ~mask) | value;
660 }
661}
662
663bool BitVector::empty() const {
664 uint64_t* last = buckets + bucketCount();
665 uint64_t* it = std::find_if(buckets, last, [](uint64_t const& a) { return a != 0; });
666 return it == last;
667}
668
669bool BitVector::full() const {
670 if (bitCount == 0) {
671 return true;
672 }
673 // Check that all buckets except the last one have all bits set.
674 uint64_t* last = buckets + bucketCount() - 1;
675 for (uint64_t const* it = buckets; it < last; ++it) {
676 if (*it != -1ull) {
677 return false;
678 }
679 }
680
681 // Now check whether the relevant bits are set in the last bucket.
682 uint64_t mask = ~((1ull << (64 - (bitCount & mod64mask))) - 1ull);
683 if ((*last & mask) != mask) {
684 return false;
685 }
686 return true;
687}
688
690 std::fill_n(buckets, this->bucketCount(), 0);
691}
692
694 std::fill_n(buckets, this->bucketCount(), -1ull);
695 truncateLastBucket();
696}
697
699 return getNumberOfSetBitsBeforeIndex(bitCount);
700}
701
702uint64_t BitVector::getNumberOfSetBitsBeforeIndex(uint64_t index) const {
703 STORM_LOG_ASSERT(index <= bitCount, "Invalid call to BitVector::getNumberOfSetBitsBeforeIndex: read index " << index << " out of bounds.");
704 uint64_t const lastBucketIndex = index >> 6;
705 uint64_t result = 0;
706
707 // First, count all full buckets.
708 for (uint64_t i = 0; i < lastBucketIndex; ++i) {
709 result += std::popcount(buckets[i]);
710 }
711
712 // Now check if we have to count part of a bucket.
713 uint8_t const endIndexInLastBucket = index & mod64mask;
714 if (endIndexInLastBucket != 0) {
715 result += std::popcount(buckets[lastBucketIndex] >> (64 - endIndexInLastBucket));
716 }
717
718 return result;
719}
720
721std::vector<uint64_t> BitVector::getNumberOfSetBitsBeforeIndices() const {
722 std::vector<uint64_t> bitsSetBeforeIndices;
723 bitsSetBeforeIndices.reserve(this->size());
724 uint64_t lastIndex = 0;
725 uint64_t currentNumberOfSetBits = 0;
726 for (uint64_t index : *this) {
727 while (lastIndex <= index) {
728 bitsSetBeforeIndices.push_back(currentNumberOfSetBits);
729 ++lastIndex;
730 }
731 ++currentNumberOfSetBits;
732 }
733 while (lastIndex < this->size()) {
734 bitsSetBeforeIndices.push_back(currentNumberOfSetBits);
735 ++lastIndex;
736 }
737 return bitsSetBeforeIndices;
738}
739
741 return getNumberOfSetBits() == 1;
742}
743
744size_t BitVector::size() const {
745 return static_cast<size_t>(bitCount);
746}
747
748std::size_t BitVector::getSizeInBytes() const {
749 return sizeof(*this) + sizeof(uint64_t) * bucketCount();
750}
751
753 size_t result = (bitCount >> 6);
754 if ((bitCount & mod64mask) != 0) {
755 ++result;
756 }
757 return result;
758}
759
760void BitVector::setBucket(uint64_t bucketIndex, uint64_t value) {
761 STORM_LOG_ASSERT(bucketIndex < bucketCount(), "Invalid call to BitVector::setBucket: bucket index " << bucketIndex << " out of bounds.");
762 buckets[bucketIndex] = value;
763 if (bucketIndex == bucketCount() - 1) {
764 truncateLastBucket();
765 }
766}
767
768uint64_t BitVector::getBucket(uint64_t bucketIndex) const {
769 STORM_LOG_ASSERT(bucketIndex < bucketCount(), "Invalid call to BitVector::getBucket: bucket index " << bucketIndex << " out of bounds.");
770 STORM_LOG_ASSERT(bucketIndex < bucketCount() - 1 || (bitCount & mod64mask) == 0ull || (buckets[bucketIndex] << (bitCount & mod64mask)) == 0ull,
771 "Bitvector in invalid state: last bucket contains bits beyond bitCount.");
772 if (bucketIndex == bucketCount() - 1) {
773 return buckets[bucketIndex] & ~((1ll << (64 - (bitCount & mod64mask))) - 1ll);
774 }
775 return buckets[bucketIndex];
776}
777
779 return const_iterator(buckets, 0, bitCount);
780}
781
782BitVector::const_iterator BitVector::begin(uint64_t lowerBound) const {
783 return const_iterator(buckets, lowerBound, bitCount);
784}
785
787 return const_iterator(buckets, bitCount, bitCount, false);
788}
789
794 return const_reverse_iterator(buckets, upperBound);
795}
796
798 return const_reverse_iterator(buckets, 0ull, 0ull, false);
799}
800
801uint64_t BitVector::getNextSetIndex(uint64_t startingIndex) const {
802 return getNextIndexWithValue<true>(buckets, startingIndex, bitCount);
803}
804
805uint64_t BitVector::getNextUnsetIndex(uint64_t startingIndex) const {
806#ifdef ASSERT_BITVECTOR
807 STORM_LOG_ASSERT(getNextIndexWithValue<false>(buckets, startingIndex, bitCount) == (~(*this)).getNextSetIndex(startingIndex),
808 "The result is inconsistent with the next set index of the complement of this bitvector");
809#endif
810 return getNextIndexWithValue<false>(buckets, startingIndex, bitCount);
811}
812
813uint64_t BitVector::getStartOfZeroSequenceBefore(uint64_t endIndex) const {
814 return getNextIndexWithValue<true, true>(buckets, 0, endIndex);
815}
816
817uint64_t BitVector::getStartOfOneSequenceBefore(uint64_t endIndex) const {
818#ifdef ASSERT_BITVECTOR
819 STORM_LOG_ASSERT((getNextIndexWithValue<false, true>(buckets, 0, endIndex) == (~(*this)).getStartOfZeroSequenceBefore(endIndex)),
820 "The result is inconsistent with the next set index of the complement of this bitvector");
821#endif
822 return getNextIndexWithValue<false, true>(buckets, 0, endIndex);
823}
824
825template<bool Value, bool Backward>
826uint64_t BitVector::getNextIndexWithValue(uint64_t const* dataPtr, uint64_t startingIndex, uint64_t endIndex) {
827 if (startingIndex >= endIndex) {
828 return Backward ? startingIndex : endIndex;
829 }
830
831 uint64_t currentBucketIndexOffset = Backward ? endIndex - 1 : startingIndex;
832 uint_fast8_t currentBitInBucket = currentBucketIndexOffset & mod64mask;
833 uint64_t const* bucketIt = dataPtr + (currentBucketIndexOffset >> 6);
834 currentBucketIndexOffset = (currentBucketIndexOffset >> 6 << 6);
835
836 // Get relevant contents of the first bucket (the one that contains the bit with index currentBucketIndexOffset + currentBitInBucket)
837 uint64_t relevantBitsInBucket;
838 if constexpr (Backward) {
839 relevantBitsInBucket = -1ull << (63 - currentBitInBucket); // 111..111'1'000...000 where the last '1' is at the currentBitInBucket
840 } else {
841 relevantBitsInBucket = -1ull >> currentBitInBucket; // 000..000'1'111..111 where the first '1' is at the currentBitInBucket
842 }
843 uint64_t currentBucket = Value ? (*bucketIt & relevantBitsInBucket) : (*bucketIt | ~relevantBitsInBucket);
844
845 // Find the right bucket
846 if (currentBucket == (Value ? 0ull : -1ull)) {
847 // The first bucket does not contain a bit with the desired value...
848 do {
849 // Move to next bucket (if there is some)
850 if constexpr (Backward) {
851 if (currentBucketIndexOffset <= startingIndex) {
852 // No bucket found!
853 return startingIndex;
854 }
855 --bucketIt;
856 currentBucketIndexOffset -= 64; // does not underflow: currentBucketIndexOffset is greater than startIndex and always a multiple of 64
857 } else {
858 ++bucketIt;
859 currentBucketIndexOffset += 64;
860 if (currentBucketIndexOffset >= endIndex) {
861 // No bucket found!
862 return endIndex;
863 }
864 }
865 // Check if the bucket contains our bit
866 } while ((*bucketIt) == (Value ? 0ull : -1ull));
867 // At this point we have found our bucket, but it is not the first one
868 currentBucket = *bucketIt;
869 currentBitInBucket = Backward ? 63u : 0u; // search within the bucket starting at the last or at the first bit
870 }
871
872 if constexpr (!Value) {
873 currentBucket = ~currentBucket; // invert so that we always search for a '1' from this point
874 }
875 // At this point, currentBucket definitely contains a 1-bit and all bits (Backward ? after : before) the currentBitInBucket are zero
876 STORM_LOG_ASSERT(currentBucket != 0ull, "Bitvector's getNextIndexWithValue method in invalid state.");
877
878 if constexpr (Backward) {
879 // take max since the startIndex might point somewhere into the current bucket so the found bit might come before the startIndex
880 return std::max<uint64_t>(startingIndex,
881 currentBucketIndexOffset + 64ull - std::countr_zero(currentBucket)); // make sure to return +1 index after the found 1
882 } else {
883 // take min since the endIndex might point somewhere into the current bucket so the found bit might come after the endIndex
884 return std::min<uint64_t>(endIndex, currentBucketIndexOffset + std::countl_zero(currentBucket));
885 }
886}
887
888storm::storage::BitVector BitVector::getAsBitVector(uint64_t start, uint64_t length) const {
889 STORM_LOG_ASSERT(start + length <= bitCount, "Invalid range.");
890#ifdef ASSERT_BITVECTOR
891 BitVector original(*this);
892#endif
893 storm::storage::BitVector result(length, false);
894
895 uint64_t offset = start % 64;
896 uint64_t* getBucket = buckets + (start / 64);
897 uint64_t* insertBucket = result.buckets;
898 uint64_t getValue;
899 uint64_t writeValue = 0;
900 uint64_t noBits = 0;
901 if (offset == 0) {
902 // Copy complete buckets
903 for (; noBits + 64 <= length; ++getBucket, ++insertBucket, noBits += 64) {
904 *insertBucket = *getBucket;
905 }
906 } else {
907 // Get first bits up until next bucket
908 getValue = *getBucket;
909 writeValue = (getValue << offset);
910 noBits += (64 - offset);
911 ++getBucket;
912
913 // Get complete buckets
914 for (; noBits + 64 <= length; ++getBucket, ++insertBucket, noBits += 64) {
915 getValue = *getBucket;
916 // Get bits till write bucket is full
917 writeValue |= (getValue >> (64 - offset));
918 *insertBucket = writeValue;
919 // Get bits up until next bucket
920 writeValue = (getValue << offset);
921 }
922 }
923
924 // Write last bits
925 uint64_t remainingBits = length - noBits;
926 STORM_LOG_ASSERT(getBucket != buckets + bucketCount(), "Bucket index incorrect.");
927 // Get remaining bits
928 getValue = (*getBucket >> (64 - remainingBits)) << (64 - remainingBits);
929 STORM_LOG_ASSERT(remainingBits < 64, "Too many remaining bits.");
930 // Write bucket
931 STORM_LOG_ASSERT(insertBucket != result.buckets + result.bucketCount(), "Bucket index incorrect.");
932 if (offset == 0) {
933 *insertBucket = getValue;
934 } else {
935 writeValue |= getValue >> (64 - offset);
936 *insertBucket = writeValue;
937 if (remainingBits > offset) {
938 // Write last bits in new value
939 writeValue = (getValue << offset);
940 ++insertBucket;
941 STORM_LOG_ASSERT(insertBucket != result.buckets + result.bucketCount(), "Bucket index incorrect.");
942 *insertBucket = writeValue;
943 }
944 }
945
946#ifdef ASSERT_BITVECTOR
947 // Check correctness of getter
948 for (uint64_t i = 0; i < length; ++i) {
949 if (result.get(i) != get(start + i)) {
950 STORM_LOG_ERROR("Getting of bits not correct for index " << i);
951 STORM_LOG_ERROR("Getting from " << start << " with length " << length);
952 std::stringstream stream;
953 printBits(stream);
954 stream << '\n';
955 result.printBits(stream);
956 STORM_LOG_ERROR(stream.str());
957 STORM_LOG_ASSERT(false, "Getting of bits not correct.");
958 }
959 }
960 for (uint64_t i = 0; i < bitCount; ++i) {
961 if (i < start || i >= start + length) {
962 if (original.get(i) != get(i)) {
963 STORM_LOG_ERROR("Getting did change bitvector at index " << i);
964 STORM_LOG_ERROR("Getting from " << start << " with length " << length);
965 std::stringstream stream;
966 printBits(stream);
967 stream << '\n';
968 original.printBits(stream);
969 STORM_LOG_ERROR(stream.str());
970 STORM_LOG_ASSERT(false, "Getting of bits not correct.");
971 }
972 }
973 }
974
975#endif
976 return result;
977}
978
979void BitVector::setFromBitVector(uint64_t start, BitVector const& other) {
980#ifdef ASSERT_BITVECTOR
981 BitVector original(*this);
982#endif
983 STORM_LOG_ASSERT(start + other.bitCount <= bitCount, "Range invalid.");
984
985 uint64_t offset = start % 64;
986 uint64_t* insertBucket = buckets + (start / 64);
987 uint64_t* getBucket = other.buckets;
988 uint64_t getValue;
989 uint64_t writeValue = 0;
990 uint64_t noBits = 0;
991 if (offset == 0) {
992 // Copy complete buckets
993 for (; noBits + 64 <= other.bitCount; ++insertBucket, ++getBucket, noBits += 64) {
994 *insertBucket = *getBucket;
995 }
996 } else {
997 // Get first bits up until next bucket
998 getValue = *getBucket;
999 writeValue = (*insertBucket >> (64 - offset)) << (64 - offset);
1000 writeValue |= (getValue >> offset);
1001 *insertBucket = writeValue;
1002 noBits += (64 - offset);
1003 ++insertBucket;
1004
1005 // Get complete buckets
1006 for (; noBits + 64 <= other.bitCount; ++insertBucket, noBits += 64) {
1007 // Get all remaining bits from other bucket
1008 writeValue = getValue << (64 - offset);
1009 // Get bits from next bucket
1010 ++getBucket;
1011 getValue = *getBucket;
1012 writeValue |= getValue >> offset;
1013 *insertBucket = writeValue;
1014 }
1015 }
1016
1017 // Write last bits
1018 uint64_t remainingBits = other.bitCount - noBits;
1019 STORM_LOG_ASSERT(remainingBits < 64, "Too many remaining bits.");
1020 STORM_LOG_ASSERT(insertBucket != buckets + bucketCount(), "Bucket index incorrect.");
1021 STORM_LOG_ASSERT(getBucket != other.buckets + other.bucketCount(), "Bucket index incorrect.");
1022 // Get remaining bits of bucket
1023 getValue = *getBucket;
1024 if (offset > 0) {
1025 getValue = getValue << (64 - offset);
1026 }
1027 // Get unchanged part of bucket
1028 writeValue = (*insertBucket << remainingBits) >> remainingBits;
1029 if (remainingBits > offset && offset > 0) {
1030 // Remaining bits do not come from one bucket -> consider next bucket
1031 ++getBucket;
1032 STORM_LOG_ASSERT(getBucket != other.buckets + other.bucketCount(), "Bucket index incorrect.");
1033 getValue |= *getBucket >> offset;
1034 }
1035 // Write completely
1036 writeValue |= getValue;
1037 *insertBucket = writeValue;
1038
1039#ifdef ASSERT_BITVECTOR
1040 // Check correctness of setter
1041 for (uint64_t i = 0; i < other.bitCount; ++i) {
1042 if (other.get(i) != get(start + i)) {
1043 STORM_LOG_ERROR("Setting of bits not correct for index " << i);
1044 STORM_LOG_ERROR("Setting from " << start << " with length " << other.bitCount);
1045 std::stringstream stream;
1046 printBits(stream);
1047 stream << '\n';
1048 other.printBits(stream);
1049 STORM_LOG_ERROR(stream.str());
1050 STORM_LOG_ASSERT(false, "Setting of bits not correct.");
1051 }
1052 }
1053 for (uint64_t i = 0; i < bitCount; ++i) {
1054 if (i < start || i >= start + other.bitCount) {
1055 if (original.get(i) != get(i)) {
1056 STORM_LOG_ERROR("Setting did change bitvector at index " << i);
1057 STORM_LOG_ERROR("Setting from " << start << " with length " << other.bitCount);
1058 std::stringstream stream;
1059 printBits(stream);
1060 stream << '\n';
1061 original.printBits(stream);
1062 STORM_LOG_ERROR(stream.str());
1063 STORM_LOG_ASSERT(false, "Setting of bits not correct.");
1064 }
1065 }
1066 }
1067#endif
1068}
1069
1070bool BitVector::compareAndSwap(uint64_t start1, uint64_t start2, uint64_t length) {
1071 if (length < 64) {
1072 // Just use one number
1073 uint64_t elem1 = getAsInt(start1, length);
1074 uint64_t elem2 = getAsInt(start2, length);
1075 if (elem1 < elem2) {
1076 // Swap elements
1077 setFromInt(start1, length, elem2);
1078 setFromInt(start2, length, elem1);
1079 return true;
1080 }
1081 return false;
1082 } else {
1083 // Use bit vectors
1084 BitVector elem1 = getAsBitVector(start1, length);
1085 BitVector elem2 = getAsBitVector(start2, length);
1086
1087 if (!(elem1 < elem2)) {
1088 // Elements already sorted
1089#ifdef ASSERT_BITVECTOR
1090 // Check that sorted
1091 for (uint64_t i = 0; i < length; ++i) {
1092 if (get(start1 + i) > get(start2 + i)) {
1093 break;
1094 }
1095 STORM_LOG_ASSERT(get(start1 + i) >= get(start2 + i), "Bit vector not sorted for indices " << start1 + i << " and " << start2 + i);
1096 }
1097#endif
1098 return false;
1099 }
1100
1101#ifdef ASSERT_BITVECTOR
1102 BitVector check(*this);
1103#endif
1104
1105 // Swap elements
1106 setFromBitVector(start1, elem2);
1107 setFromBitVector(start2, elem1);
1108
1109#ifdef ASSERT_BITVECTOR
1110 // Check correctness of swapping
1111 bool tmp;
1112 for (uint64_t i = 0; i < length; ++i) {
1113 tmp = check.get(i + start1);
1114 check.set(i + start1, check.get(i + start2));
1115 check.set(i + start2, tmp);
1116 }
1117 STORM_LOG_ASSERT(*this == check, "Swapping not correct.");
1118
1119 // Check that sorted
1120 for (uint64_t i = 0; i < length; ++i) {
1121 if (get(start1 + i) > get(start2 + i)) {
1122 break;
1123 }
1124 STORM_LOG_ASSERT(get(start1 + i) >= get(start2 + i), "Bit vector not sorted for indices " << start1 + i << " and " << start2 + i);
1125 }
1126#endif
1127
1128 return true;
1129 }
1130}
1131
1132void BitVector::truncateLastBucket() {
1133 if ((bitCount & mod64mask) != 0) {
1134 buckets[bucketCount() - 1] &= ~((1ll << (64 - (bitCount & mod64mask))) - 1ll);
1135 }
1136}
1137
1138std::ostream& operator<<(std::ostream& out, BitVector const& bitvector) {
1139 out << "bit vector(" << bitvector.getNumberOfSetBits() << "/" << bitvector.bitCount << ") [";
1140 for (uint64_t index : bitvector) {
1141 out << index << " ";
1142 }
1143 out << "]";
1144
1145 return out;
1146}
1147
1148void BitVector::printBits(std::ostream& out) const {
1149 out << "bit vector(" << getNumberOfSetBits() << "/" << bitCount << ") ";
1150 uint64_t index = 0;
1151 for (; index * 64 + 64 <= bitCount; ++index) {
1152 std::bitset<64> tmp(buckets[index]);
1153 out << tmp << "|";
1154 }
1155
1156 // Print last bits
1157 if (index * 64 < bitCount) {
1158 STORM_LOG_ASSERT(index == bucketCount() - 1, "Not last bucket.");
1159 std::bitset<64> tmp(buckets[index]);
1160 for (size_t i = 0; i + index * 64 < bitCount; ++i) {
1161 // Bits are counted from rightmost in bitset
1162 out << tmp[63 - i];
1163 }
1164 }
1165 out << '\n';
1166}
1167
1169 std::size_t seed = 14695981039346656037ull;
1170
1171 uint8_t* it = reinterpret_cast<uint8_t*>(bv.buckets);
1172 uint8_t const* ite = it + 8 * bv.bucketCount();
1173
1174 while (it < ite) {
1175 seed ^= *it++;
1176
1177 // Multiplication with magic prime.
1178 seed += (seed << 1) + (seed << 4) + (seed << 5) + (seed << 7) + (seed << 8) + (seed << 40);
1179 }
1180
1181 return seed;
1182}
1183
1184inline __attribute__((always_inline)) uint32_t fmix32(uint32_t h) {
1185 h ^= h >> 16;
1186 h *= 0x85ebca6b;
1187 h ^= h >> 13;
1188 h *= 0xc2b2ae35;
1189 h ^= h >> 16;
1190
1191 return h;
1192}
1193
1194inline __attribute__((always_inline)) uint64_t fmix64(uint64_t k) {
1195 k ^= k >> 33;
1196 k *= 0xff51afd7ed558ccdull;
1197 k ^= k >> 33;
1198 k *= 0xc4ceb9fe1a85ec53ull;
1199 k ^= k >> 33;
1200
1201 return k;
1202}
1203
1204inline uint32_t rotl32(uint32_t x, int8_t r) {
1205 return (x << r) | (x >> (32 - r));
1206}
1207
1208inline uint64_t rotl64(uint64_t x, int8_t r) {
1209 return (x << r) | (x >> (64 - r));
1210}
1211
1212inline __attribute__((always_inline)) uint32_t getblock32(uint32_t const* p, int i) {
1213 return p[i];
1214}
1215
1216inline __attribute__((always_inline)) uint32_t getblock64(uint64_t const* p, int i) {
1217 return p[i];
1218}
1219
1220// Murmur3 hash functions.
1221// based on https://github.com/aappleby/smhasher/blob/master/src/MurmurHash3.cpp
1222template<>
1224 uint8_t const* data = reinterpret_cast<uint8_t const*>(bv.buckets);
1225 uint32_t len = bv.bucketCount() * 8;
1226 const int nblocks = bv.bucketCount() * 2;
1227
1228 // Using 0 as seed.
1229 uint32_t h1 = 0;
1230
1231 const uint32_t c1 = 0xcc9e2d51;
1232 const uint32_t c2 = 0x1b873593;
1233
1234 //----------
1235 // body
1236
1237 const uint32_t* blocks = reinterpret_cast<uint32_t const*>(data + static_cast<std::ptrdiff_t>(nblocks) * 4);
1238
1239 for (int i = -nblocks; i; i++) {
1240 uint32_t k1 = getblock32(blocks, i);
1241
1242 k1 *= c1;
1243 k1 = rotl32(k1, 15);
1244 k1 *= c2;
1245
1246 h1 ^= k1;
1247 h1 = rotl32(h1, 13);
1248 h1 = h1 * 5 + 0xe6546b64;
1249 }
1250
1251 //----------
1252 // finalization
1253
1254 h1 ^= len;
1255
1256 h1 = fmix32(h1);
1257
1258 return h1;
1259}
1260
1261template<>
1263 uint8_t const* data = reinterpret_cast<uint8_t const*>(bv.buckets);
1264 uint64_t len = bv.bucketCount() * 8;
1265 const int nblocks = bv.bucketCount() / 2;
1266
1267 uint64_t h1 = 0;
1268 uint64_t h2 = 0;
1269
1270 const uint64_t c1 = 0x87c37b91114253d5ull;
1271 const uint64_t c2 = 0x4cf5ad432745937full;
1272
1273 //----------
1274 // body
1275
1276 uint64_t const* blocks = bv.buckets;
1277
1278 for (int i = 0; i < nblocks; i++) {
1279 uint64_t k1 = getblock64(blocks, i * 2 + 0);
1280 uint64_t k2 = getblock64(blocks, i * 2 + 1);
1281
1282 k1 *= c1;
1283 k1 = rotl64(k1, 31);
1284 k1 *= c2;
1285 h1 ^= k1;
1286
1287 h1 = rotl64(h1, 27);
1288 h1 += h2;
1289 h1 = h1 * 5 + 0x52dce729;
1290
1291 k2 *= c2;
1292 k2 = rotl64(k2, 33);
1293 k2 *= c1;
1294 h2 ^= k2;
1295
1296 h2 = rotl64(h2, 31);
1297 h2 += h1;
1298 h2 = h2 * 5 + 0x38495ab5;
1299 }
1300
1301 //----------
1302 // tail
1303
1304 uint8_t const* tail = reinterpret_cast<uint8_t const*>(data + static_cast<std::ptrdiff_t>(nblocks) * 16);
1305
1306 uint64_t k1 = 0;
1307 uint64_t k2 = 0;
1308 // Loop unrolling via Duff's device
1309 // Cases are supposed to fall-through
1310 switch (len & 15) {
1311 case 15:
1312 k2 ^= ((uint64_t)tail[14]) << 48;
1313 [[fallthrough]];
1314 case 14:
1315 k2 ^= ((uint64_t)tail[13]) << 40;
1316 [[fallthrough]];
1317 case 13:
1318 k2 ^= ((uint64_t)tail[12]) << 32;
1319 [[fallthrough]];
1320 case 12:
1321 k2 ^= ((uint64_t)tail[11]) << 24;
1322 [[fallthrough]];
1323 case 11:
1324 k2 ^= ((uint64_t)tail[10]) << 16;
1325 [[fallthrough]];
1326 case 10:
1327 k2 ^= ((uint64_t)tail[9]) << 8;
1328 [[fallthrough]];
1329 case 9:
1330 k2 ^= ((uint64_t)tail[8]) << 0;
1331 k2 *= c2;
1332 k2 = rotl64(k2, 33);
1333 k2 *= c1;
1334 h2 ^= k2;
1335 [[fallthrough]];
1336
1337 case 8:
1338 k1 ^= ((uint64_t)tail[7]) << 56;
1339 [[fallthrough]];
1340 case 7:
1341 k1 ^= ((uint64_t)tail[6]) << 48;
1342 [[fallthrough]];
1343 case 6:
1344 k1 ^= ((uint64_t)tail[5]) << 40;
1345 [[fallthrough]];
1346 case 5:
1347 k1 ^= ((uint64_t)tail[4]) << 32;
1348 [[fallthrough]];
1349 case 4:
1350 k1 ^= ((uint64_t)tail[3]) << 24;
1351 [[fallthrough]];
1352 case 3:
1353 k1 ^= ((uint64_t)tail[2]) << 16;
1354 [[fallthrough]];
1355 case 2:
1356 k1 ^= ((uint64_t)tail[1]) << 8;
1357 [[fallthrough]];
1358 case 1:
1359 k1 ^= ((uint64_t)tail[0]) << 0;
1360 // fallthrough
1361 k1 *= c1;
1362 k1 = rotl64(k1, 31);
1363 k1 *= c2;
1364 h1 ^= k1;
1365 [[fallthrough]];
1366 default:
1367 // Intentionally left empty
1368 break;
1369 }
1370
1371 //----------
1372 // finalization
1373
1374 h1 ^= len;
1375 h2 ^= len;
1376
1377 h1 += h2;
1378 h2 += h1;
1379
1380 h1 = fmix64(h1);
1381 h2 = fmix64(h2);
1382
1383 h1 += h2;
1384 h2 += h1;
1385
1386 return h1 ^ h2;
1387}
1388
1389void BitVector::store(std::ostream& os) const {
1390 os << bitCount;
1391 for (uint64_t i = 0; i < bucketCount(); ++i) {
1392 os << " " << buckets[i];
1393 }
1394}
1395
1396BitVector BitVector::load(std::string const& description) {
1397 std::vector<std::string> splitted;
1398 std::stringstream ss(description);
1399 ss >> std::noskipws;
1400 std::string field;
1401 char ws_delim;
1402 while (true) {
1403 if (ss >> field) {
1404 splitted.push_back(field);
1405 } else if (ss.eof()) {
1406 break;
1407 } else {
1408 splitted.push_back(std::string());
1409 }
1410 ss.clear();
1411 ss >> ws_delim;
1412 }
1413 BitVector bv(std::stoul(splitted[0]));
1414 for (uint64_t i = 0; i < splitted.size() - 1; ++i) {
1415 bv.buckets[i] = std::stoul(splitted[i + 1]);
1416 }
1417 return bv;
1418}
1419
1420// All necessary explicit template instantiations.
1421template BitVector::BitVector(uint64_t length, std::vector<uint64_t>::iterator begin, std::vector<uint64_t>::iterator end);
1422template BitVector::BitVector(uint64_t length, std::vector<uint64_t>::const_iterator begin, std::vector<uint64_t>::const_iterator end);
1425template void BitVector::set(std::vector<uint64_t>::iterator begin, std::vector<uint64_t>::iterator end, bool value);
1426template void BitVector::set(std::vector<uint64_t>::const_iterator begin, std::vector<uint64_t>::const_iterator end, bool value);
1429
1430template struct Murmur3BitVectorHash<uint32_t>;
1431template struct Murmur3BitVectorHash<uint64_t>;
1432} // namespace storage
1433} // namespace storm
1434
1435namespace std {
1436std::size_t hash<storm::storage::BitVector>::operator()(storm::storage::BitVector const& bitvector) const {
1437 return boost::hash_range(bitvector.buckets, bitvector.buckets + bitvector.bucketCount());
1438}
1439} // namespace std
A class that enables iterating over the indices of the bit vector whose corresponding bits are set to...
Definition BitVector.h:23
uint64_t operator*() const
Returns the index of the current bit to which this iterator points.
Definition BitVector.cpp:64
const_iterator & operator++()
Increases the position of the iterator to the position of the next bit that is set to true in the und...
Definition BitVector.cpp:46
bool operator==(const_iterator const &other) const
Compares the iterator with another iterator for equality.
Definition BitVector.cpp:72
const_iterator & operator+=(size_t n)
Increases the position of the iterator to the position of the n'th next bit that is set to true in th...
Definition BitVector.cpp:57
const_iterator & operator=(const_iterator const &other)
Assigns the contents of the given iterator to the current one via copying the former's contents.
Definition BitVector.cpp:36
bool operator!=(const_iterator const &other) const
Compares the iterator with another iterator for inequality.
Definition BitVector.cpp:68
A class that enables iterating over the indices of the bit vector whose corresponding bits are set to...
Definition BitVector.h:123
bool operator==(const_reverse_iterator const &other) const
Compares the iterator with another iterator for equality.
uint64_t operator*() const
Returns the index of the current bit to which this iterator points.
const_reverse_iterator()
Constructs a reverse iterator over the indices of the set bits in the given bit vector,...
Definition BitVector.cpp:76
const_reverse_iterator & operator+=(size_t n)
Lets the iterator point to the n'th previous bit with value 1.
const_reverse_iterator & operator++()
Lets the iterator point to the previous bit with value 1.
const_reverse_iterator & operator=(const_reverse_iterator const &other)
Definition BitVector.cpp:93
bool operator!=(const_reverse_iterator const &other) const
Compares the iterator with another iterator for inequality.
A bit vector that is internally represented as a vector of 64-bit values.
Definition BitVector.h:16
~BitVector()
Deconstructs a bit vector by deleting the underlying storage.
void complement()
Negates all bits in the bit vector.
BitVector & operator|=(BitVector const &other)
Performs a logical "or" with the given bit vector and assigns the result to the current bit vector.
uint64_t getBucket(uint64_t bucketIndex) const
Gets the bits in the given bucket.
BitVector operator^(BitVector const &other) const
Performs a logical "xor" with the given bit vector.
void setMultiple(uint64_t bitIndex, uint64_t nrOfBits, bool newValue=true)
Sets multiple bits to the given value.
bool operator<(BitVector const &other) const
Retrieves whether the current bit vector is (in some order) smaller than the given one.
const_reverse_iterator rbegin() const
Returns a reverse iterator to the indices of the set bits in the bit vector.
void fill()
Sets all bits from the bit vector.
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 getTwoBitsAligned(uint64_t bitIndex) const
bool isDisjointFrom(BitVector const &other) const
Checks whether none of the bits that are set in the current bit vector are also set in the given bit ...
bool full() const
Retrieves whether all bits are set in this bit vector.
std::vector< uint64_t > getNumberOfSetBitsBeforeIndices() const
Retrieves a vector that holds at position i the number of bits set before index i.
const_reverse_iterator rend() const
Returns a reverse iterator pointing at the element past the front of the bit vector.
BitVector()
Constructs an empty bit vector of length 0.
const_iterator end() const
Returns an iterator pointing at the element past the back of the bit vector.
void grow(uint64_t minimumLength, bool init=false)
Enlarges the bit vector such that it holds at least the given number of bits (but possibly more).
void store(std::ostream &) const
BitVector operator%(BitVector const &filter) const
Computes a bit vector that contains only the values of the bits given by the filter.
BitVector operator|(BitVector const &other) const
Performs a logical "or" with the given bit vector.
BitVector & operator^=(BitVector const &other)
Performs a logical "xor" with the given bit vector and assigns the result to the current bit vector.
bool empty() const
Retrieves whether no bits are set to true in this bit vector.
std::size_t getSizeInBytes() const
Returns (an approximation of) the size of the bit vector measured in bytes.
void clear()
Removes all set bits from the bit vector.
bool isSubsetOf(BitVector const &other) const
Checks whether all bits that are set in the current bit vector are also set in the given bit vector.
BitVector implies(BitVector const &other) const
Performs a logical "implies" with the given bit vector.
BitVector & operator=(BitVector const &other)
Assigns the contents of the given bit vector to the current bit vector via a deep copy.
uint64_t getNumberOfSetBits() const
Returns the number of bits that are set to true in this bit vector.
uint64_t getNextUnsetIndex(uint64_t startingIndex) const
Retrieves the index of the bit that is the next bit set to false in the bit vector.
bool compareAndSwap(uint64_t start1, uint64_t start2, uint64_t length)
Compare two intervals [start1, start1+length] and [start2, start2+length] and swap them if the second...
BitVector operator&(BitVector const &other) const
Performs a logical "and" with the given bit vector.
void setFromInt(uint64_t bitIndex, uint64_t numberOfBits, uint64_t value)
Sets the selected number of lowermost bits of the provided value at the given bit index.
BitVector permute(std::vector< uint64_t > const &inversePermutation) const
Apply a permutation of entries.
void set(uint64_t index, bool value=true)
Sets the given truth value at the given index.
void increment()
Increments the (unsigned) number represented by this BitVector by one.
size_t bucketCount() const
Retrieves the number of buckets of the underlying storage.
bool matches(uint64_t bitIndex, BitVector const &other) const
Checks whether the given bit vector matches the bits starting from the given index in the current bit...
const_iterator begin() const
Returns an iterator to the indices of the set bits in the bit vector.
uint64_t getStartOfZeroSequenceBefore(uint64_t endIndex) const
Retrieves the smallest index i such that all bits in the range [i,endIndex) are 0.
uint64_t getAsInt(uint64_t bitIndex, uint64_t numberOfBits) const
Retrieves the content of the current bit vector at the given index for the given number of bits as an...
BitVector operator~() const
Performs a logical "not" on the bit vector.
void setBucket(uint64_t bucketIndex, uint64_t value)
Sets the bits in the given bucket to the given value.
bool operator!=(BitVector const &other) const
Compares the given bit vector with the current one.
size_t size() const
Retrieves the number of bits this bit vector can store.
void resize(uint64_t newLength, bool init=false)
Resizes the bit vector to hold the given new number of bits.
BitVector & operator&=(BitVector const &other)
Performs a logical "and" with the given bit vector and assigns the result to the current bit vector.
static BitVector load(std::string const &description)
void expandSize(bool init=false)
bool get(uint64_t index) const
Retrieves the truth value of the bit at the given index and performs a bound check.
bool operator==(BitVector const &other) const
Compares the given bit vector with the current one.
uint64_t getNumberOfSetBitsBeforeIndex(uint64_t index) const
Retrieves the number of bits set in this bit vector with an index strictly smaller than the given one...
BitVector permuteGroupedVector(std::vector< uint64_t > const &inversePermutation, std::vector< uint64_t > const &rowGroupIndices) const
Apply a permutation of entries assuming a grouped vector.
uint64_t getStartOfOneSequenceBefore(uint64_t endIndex) const
Retrieves the smallest index i such that all bits in the range [i,endIndex) are 1.
bool operator[](uint64_t index) const
Retrieves the truth value of the bit at the given index.
void concat(BitVector const &extension)
Concatenate this bitvector with another bitvector.
#define STORM_LOG_ERROR(message)
Definition logging.h:36
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:9
void writeValue(std::ostream &os, ValueType value, std::unordered_map< ValueType, std::string > const &placeholders)
Write value to stream while using the placeholders.
boost::container::flat_set< Key, std::less< Key >, boost::container::new_allocator< Key > > FlatSet
Redefinition of flat_set was needed, because from Boost 1.70 on the default allocator is set to void.
Definition BoostTypes.h:13
uint32_t rotl32(uint32_t x, int8_t r)
uint64_t rotl64(uint64_t x, int8_t r)
__attribute__((always_inline)) uint32_t fmix32(uint32_t h)
std::ostream & operator<<(std::ostream &out, ParameterRegion< ParametricType > const &region)
std::size_t operator()(storm::storage::BitVector const &bv) const
StateType operator()(storm::storage::BitVector const &bv) const