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