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