SIGN IN SIGN UP
google / or-tools UNCLAIMED

Google's Operations Research tools:

0 0 687 C++
// Copyright 2010-2025 Google LLC
2010-09-15 12:42:33 +00:00
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Various utility functions on bitsets.
2025-11-05 10:13:48 +01:00
#ifndef ORTOOLS_UTIL_BITSET_H_
#define ORTOOLS_UTIL_BITSET_H_
2010-09-15 12:42:33 +00:00
#include <string.h>
#include <algorithm>
#include <cstddef>
2024-01-23 14:15:18 +01:00
#include <cstdint>
#include <iterator>
#include <string>
#include <tuple>
2010-09-15 12:42:33 +00:00
#include <vector>
#include "absl/log/check.h"
2010-09-15 12:42:33 +00:00
namespace operations_research {
// Basic bit operations
// Useful constants: word and double word will all bits set.
2021-04-01 12:13:35 +02:00
static const uint64_t kAllBits64 = uint64_t{0xFFFFFFFFFFFFFFFF};
static const uint64_t kAllBitsButLsb64 = uint64_t{0xFFFFFFFFFFFFFFFE};
static const uint32_t kAllBits32 = 0xFFFFFFFFU;
2010-09-15 12:42:33 +00:00
// Returns a word with only bit pos set.
2021-04-01 12:13:35 +02:00
inline uint64_t OneBit64(int pos) { return uint64_t{1} << pos; }
inline uint32_t OneBit32(int pos) { return 1U << pos; }
2010-09-15 12:42:33 +00:00
// Returns the number of bits set in n.
2021-04-01 12:13:35 +02:00
inline uint64_t BitCount64(uint64_t n) {
const uint64_t m1 = uint64_t{0x5555555555555555};
const uint64_t m2 = uint64_t{0x3333333333333333};
const uint64_t m4 = uint64_t{0x0F0F0F0F0F0F0F0F};
const uint64_t h01 = uint64_t{0x0101010101010101};
2010-09-15 12:42:33 +00:00
n -= (n >> 1) & m1;
n = (n & m2) + ((n >> 2) & m2);
n = (n + (n >> 4)) & m4;
n = (n * h01) >> 56;
return n;
}
inline uint32_t BitCount32(uint32_t n) {
2010-09-15 12:42:33 +00:00
n -= (n >> 1) & 0x55555555UL;
n = (n & 0x33333333) + ((n >> 2) & 0x33333333UL);
n = (n + (n >> 4)) & 0x0F0F0F0FUL;
n = n + (n >> 8);
n = n + (n >> 16);
return n & 0x0000003FUL;
}
// Returns a word with only the least significant bit of n set.
2021-04-01 12:13:35 +02:00
inline uint64_t LeastSignificantBitWord64(uint64_t n) { return n & ~(n - 1); }
inline uint32_t LeastSignificantBitWord32(uint32_t n) { return n & ~(n - 1); }
2010-09-15 12:42:33 +00:00
// Returns the least significant bit position in n.
2015-06-15 11:46:24 +02:00
// Discussion around lsb computation:
// De Bruijn is almost as fast as the bsr/bsf-instruction-based intrinsics.
// Both are always much faster than the Default algorithm.
2020-10-22 23:36:58 +02:00
#define USE_DEBRUIJN true // if true, use de Bruijn bit forward scanner.
2015-06-15 11:46:24 +02:00
#if defined(__GNUC__) || defined(__llvm__)
2020-10-22 23:36:58 +02:00
#define USE_FAST_LEAST_SIGNIFICANT_BIT true // if true, use fast lsb.
2010-09-15 12:42:33 +00:00
#endif
2015-06-15 11:46:24 +02:00
#if defined(USE_FAST_LEAST_SIGNIFICANT_BIT)
2021-04-01 12:13:35 +02:00
inline int LeastSignificantBitPosition64Fast(uint64_t n) {
2022-11-22 17:44:54 +01:00
return __builtin_ctzll(n);
}
#endif
2021-04-01 12:13:35 +02:00
inline int LeastSignificantBitPosition64DeBruijn(uint64_t n) {
static const uint64_t kSeq = uint64_t{0x0218a392dd5fb34f};
2010-09-15 12:42:33 +00:00
static const int kTab[64] = {
2020-10-22 23:36:58 +02:00
// initialized by 'kTab[(kSeq << i) >> 58] = i
0, 1, 2, 7, 3, 13, 8, 19, 4, 25, 14, 28, 9, 52, 20, 58,
5, 17, 26, 56, 15, 38, 29, 40, 10, 49, 53, 31, 21, 34, 59, 42,
63, 6, 12, 18, 24, 27, 51, 57, 16, 55, 37, 39, 48, 30, 33, 41,
62, 11, 23, 50, 54, 36, 47, 32, 61, 22, 35, 46, 60, 45, 44, 43,
2018-06-08 16:40:43 +02:00
};
return kTab[((n & (~n + 1)) * kSeq) >> 58];
}
2021-04-01 12:13:35 +02:00
inline int LeastSignificantBitPosition64Default(uint64_t n) {
2022-11-22 17:44:54 +01:00
DCHECK_NE(n, 0);
2010-09-15 12:42:33 +00:00
int pos = 63;
if (n & 0x00000000FFFFFFFFLL) {
pos -= 32;
} else {
n >>= 32;
}
if (n & 0x000000000000FFFFLL) {
pos -= 16;
} else {
n >>= 16;
}
if (n & 0x00000000000000FFLL) {
2014-01-08 12:01:58 +00:00
pos -= 8;
2010-09-15 12:42:33 +00:00
} else {
2014-01-08 12:01:58 +00:00
n >>= 8;
2010-09-15 12:42:33 +00:00
}
if (n & 0x000000000000000FLL) {
2014-01-08 12:01:58 +00:00
pos -= 4;
2010-09-15 12:42:33 +00:00
} else {
2014-01-08 12:01:58 +00:00
n >>= 4;
2010-09-15 12:42:33 +00:00
}
if (n & 0x0000000000000003LL) {
2014-01-08 12:01:58 +00:00
pos -= 2;
2010-09-15 12:42:33 +00:00
} else {
2014-01-08 12:01:58 +00:00
n >>= 2;
2010-09-15 12:42:33 +00:00
}
if (n & 0x0000000000000001LL) {
2014-01-08 12:01:58 +00:00
pos -= 1;
2010-09-15 12:42:33 +00:00
}
return pos;
}
2021-04-01 12:13:35 +02:00
inline int LeastSignificantBitPosition64(uint64_t n) {
DCHECK_NE(n, 0);
2015-06-15 11:46:24 +02:00
#ifdef USE_FAST_LEAST_SIGNIFICANT_BIT
return LeastSignificantBitPosition64Fast(n);
#elif defined(USE_DEBRUIJN)
return LeastSignificantBitPosition64DeBruijn(n);
#else
return LeastSignificantBitPosition64Default(n);
#endif
}
2015-06-15 11:46:24 +02:00
#if defined(USE_FAST_LEAST_SIGNIFICANT_BIT)
inline int LeastSignificantBitPosition32Fast(uint32_t n) {
2022-11-22 17:44:54 +01:00
return __builtin_ctzl(n);
}
#endif
inline int LeastSignificantBitPosition32DeBruijn(uint32_t n) {
static const uint32_t kSeq = 0x077CB531U; // de Bruijn sequence
2020-10-22 23:36:58 +02:00
static const int kTab[32] = {// initialized by 'kTab[(kSeq << i) >> 27] = i
0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20,
15, 25, 17, 4, 8, 31, 27, 13, 23, 21, 19,
16, 7, 26, 12, 18, 6, 11, 5, 10, 9};
return kTab[((n & (~n + 1)) * kSeq) >> 27];
}
inline int LeastSignificantBitPosition32Default(uint32_t n) {
2022-11-22 17:44:54 +01:00
DCHECK_NE(n, 0);
2010-09-15 12:42:33 +00:00
int pos = 31;
if (n & 0x0000FFFFL) {
pos -= 16;
} else {
n >>= 16;
}
if (n & 0x000000FFL) {
2014-01-08 12:01:58 +00:00
pos -= 8;
2010-09-15 12:42:33 +00:00
} else {
2014-01-08 12:01:58 +00:00
n >>= 8;
2010-09-15 12:42:33 +00:00
}
if (n & 0x0000000FL) {
2014-01-08 12:01:58 +00:00
pos -= 4;
2010-09-15 12:42:33 +00:00
} else {
2014-01-08 12:01:58 +00:00
n >>= 4;
2010-09-15 12:42:33 +00:00
}
if (n & 0x00000003L) {
2014-01-08 12:01:58 +00:00
pos -= 2;
2010-09-15 12:42:33 +00:00
} else {
2014-01-08 12:01:58 +00:00
n >>= 2;
2010-09-15 12:42:33 +00:00
}
if (n & 0x00000001L) {
2014-01-08 12:01:58 +00:00
pos -= 1;
2010-09-15 12:42:33 +00:00
}
return pos;
}
inline int LeastSignificantBitPosition32(uint32_t n) {
DCHECK_NE(n, 0);
2015-06-15 11:46:24 +02:00
#ifdef USE_FAST_LEAST_SIGNIFICANT_BIT
return LeastSignificantBitPosition32Fast(n);
#elif defined(USE_DEBRUIJN)
return LeastSignificantBitPosition32DeBruijn(n);
#else
return LeastSignificantBitPosition32Default(n);
2010-09-15 12:42:33 +00:00
#endif
}
// Returns the most significant bit position in n.
2015-06-15 11:46:24 +02:00
#if USE_FAST_LEAST_SIGNIFICANT_BIT
2021-04-01 12:13:35 +02:00
inline int MostSignificantBitPosition64Fast(uint64_t n) {
2015-06-15 11:46:24 +02:00
// __builtin_clzll(1) should always return 63. There is no penalty in
// using offset, and the code looks more like its uint32_t counterpart.
2015-06-15 11:46:24 +02:00
const int offset = __builtin_clzll(1);
return n == 0 ? 0 : (offset - __builtin_clzll(n));
2015-06-15 11:46:24 +02:00
}
2010-09-15 12:42:33 +00:00
#endif
2015-06-15 11:46:24 +02:00
2021-04-01 12:13:35 +02:00
inline int MostSignificantBitPosition64Default(uint64_t n) {
2010-09-15 12:42:33 +00:00
int b = 0;
if (0 != (n & (kAllBits64 << (1 << 5)))) {
b |= (1 << 5);
n >>= (1 << 5);
}
if (0 != (n & (kAllBits64 << (1 << 4)))) {
b |= (1 << 4);
n >>= (1 << 4);
}
if (0 != (n & (kAllBits64 << (1 << 3)))) {
b |= (1 << 3);
n >>= (1 << 3);
}
if (0 != (n & (kAllBits64 << (1 << 2)))) {
b |= (1 << 2);
n >>= (1 << 2);
}
if (0 != (n & (kAllBits64 << (1 << 1)))) {
b |= (1 << 1);
n >>= (1 << 1);
}
if (0 != (n & (kAllBits64 << (1 << 0)))) {
b |= (1 << 0);
}
return b;
}
2021-04-01 12:13:35 +02:00
inline int MostSignificantBitPosition64(uint64_t n) {
2015-06-15 11:46:24 +02:00
#ifdef USE_FAST_LEAST_SIGNIFICANT_BIT
return MostSignificantBitPosition64Fast(n);
2010-09-15 12:42:33 +00:00
#else
2015-06-15 11:46:24 +02:00
return MostSignificantBitPosition64Default(n);
#endif
}
#if USE_FAST_LEAST_SIGNIFICANT_BIT
inline int MostSignificantBitPosition32Fast(uint32_t n) {
2015-06-15 11:46:24 +02:00
// The constant here depends on whether we are on a 32-bit or 64-bit machine.
// __builtin_clzl(1) returns 63 on a 64-bit machine and 31 on a 32-bit
// machine.
const int offset = __builtin_clzl(1);
return n == 0 ? 0 : (offset - __builtin_clzl(n));
2015-06-15 11:46:24 +02:00
}
#endif
inline int MostSignificantBitPosition32Default(uint32_t n) {
2010-09-15 12:42:33 +00:00
int b = 0;
if (0 != (n & (kAllBits32 << (1 << 4)))) {
b |= (1 << 4);
n >>= (1 << 4);
}
if (0 != (n & (kAllBits32 << (1 << 3)))) {
b |= (1 << 3);
n >>= (1 << 3);
}
if (0 != (n & (kAllBits32 << (1 << 2)))) {
b |= (1 << 2);
n >>= (1 << 2);
}
if (0 != (n & (kAllBits32 << (1 << 1)))) {
b |= (1 << 1);
n >>= (1 << 1);
}
if (0 != (n & (kAllBits32 << (1 << 0)))) {
b |= (1 << 0);
}
return b;
2015-06-15 11:46:24 +02:00
}
inline int MostSignificantBitPosition32(uint32_t n) {
2015-06-15 11:46:24 +02:00
#ifdef USE_FAST_LEAST_SIGNIFICANT_BIT
return MostSignificantBitPosition32Fast(n);
#else
return MostSignificantBitPosition32Default(n);
2010-09-15 12:42:33 +00:00
#endif
}
#undef USE_DEBRUIJN
2015-06-15 11:46:24 +02:00
#undef USE_FAST_LEAST_SIGNIFICANT_BIT
2010-09-15 12:42:33 +00:00
// Returns a word with bits from s to e set.
2021-04-01 12:13:35 +02:00
inline uint64_t OneRange64(uint64_t s, uint64_t e) {
2010-09-15 12:42:33 +00:00
DCHECK_LE(s, 63);
DCHECK_LE(e, 63);
DCHECK_LE(s, e);
return (kAllBits64 << s) ^ ((kAllBits64 - 1) << e);
}
inline uint32_t OneRange32(uint32_t s, uint32_t e) {
2010-09-15 12:42:33 +00:00
DCHECK_LE(s, 31);
DCHECK_LE(e, 31);
DCHECK_LE(s, e);
return (kAllBits32 << s) ^ ((kAllBits32 - 1) << e);
}
// Returns a word with s least significant bits unset.
2021-04-01 12:13:35 +02:00
inline uint64_t IntervalUp64(uint64_t s) {
2010-09-15 12:42:33 +00:00
DCHECK_LE(s, 63);
return kAllBits64 << s;
}
inline uint32_t IntervalUp32(uint32_t s) {
2010-09-15 12:42:33 +00:00
DCHECK_LE(s, 31);
return kAllBits32 << s;
}
// Returns a word with the s most significant bits unset.
2021-04-01 12:13:35 +02:00
inline uint64_t IntervalDown64(uint64_t s) {
2010-09-15 12:42:33 +00:00
DCHECK_LE(s, 63);
return kAllBits64 >> (63 - s);
}
inline uint32_t IntervalDown32(uint32_t s) {
2010-09-15 12:42:33 +00:00
DCHECK_LE(s, 31);
return kAllBits32 >> (31 - s);
}
// ----- Bitset operators -----
2024-03-15 16:38:25 +01:00
// Bitset: array of uint32_t/uint64_t words
2010-09-15 12:42:33 +00:00
// Bit operators used to manipulates bitsets.
// Returns the bit number in the word computed by BitOffsetXX,
// corresponding to the bit at position pos in the bitset.
// Note: '& 63' is faster than '% 64'
// TODO(user): rename BitPos and BitOffset to something more understandable.
inline uint32_t BitPos64(uint64_t pos) { return (pos & 63); }
inline uint32_t BitPos32(uint32_t pos) { return (pos & 31); }
2010-09-15 12:42:33 +00:00
// Returns the word number corresponding to bit number pos.
2021-04-01 12:13:35 +02:00
inline uint64_t BitOffset64(uint64_t pos) { return (pos >> 6); }
inline uint32_t BitOffset32(uint32_t pos) { return (pos >> 5); }
2010-09-15 12:42:33 +00:00
// Returns the number of words needed to store size bits.
2021-04-01 12:13:35 +02:00
inline uint64_t BitLength64(uint64_t size) { return ((size + 63) >> 6); }
inline uint32_t BitLength32(uint32_t size) { return ((size + 31) >> 5); }
2010-09-15 12:42:33 +00:00
// Returns the bit number in the bitset of the first bit of word number v.
2021-04-01 12:13:35 +02:00
inline uint64_t BitShift64(uint64_t v) { return v << 6; }
inline uint32_t BitShift32(uint32_t v) { return v << 5; }
2010-09-15 12:42:33 +00:00
// Returns true if the bit pos is set in bitset.
2021-04-01 12:13:35 +02:00
inline bool IsBitSet64(const uint64_t* const bitset, uint64_t pos) {
2010-09-15 12:42:33 +00:00
return (bitset[BitOffset64(pos)] & OneBit64(BitPos64(pos)));
}
inline bool IsBitSet32(const uint32_t* const bitset, uint32_t pos) {
2010-09-15 12:42:33 +00:00
return (bitset[BitOffset32(pos)] & OneBit32(BitPos32(pos)));
}
// Sets the bit pos to true in bitset.
2021-04-01 12:13:35 +02:00
inline void SetBit64(uint64_t* const bitset, uint64_t pos) {
2010-09-15 12:42:33 +00:00
bitset[BitOffset64(pos)] |= OneBit64(BitPos64(pos));
}
inline void SetBit32(uint32_t* const bitset, uint32_t pos) {
2010-09-15 12:42:33 +00:00
bitset[BitOffset32(pos)] |= OneBit32(BitPos32(pos));
}
// Sets the bit pos to false in bitset.
2021-04-01 12:13:35 +02:00
inline void ClearBit64(uint64_t* const bitset, uint64_t pos) {
2010-09-15 12:42:33 +00:00
bitset[BitOffset64(pos)] &= ~OneBit64(BitPos64(pos));
}
inline void ClearBit32(uint32_t* const bitset, uint32_t pos) {
2010-09-15 12:42:33 +00:00
bitset[BitOffset32(pos)] &= ~OneBit32(BitPos32(pos));
}
// Returns the number of bits set in bitset between positions start and end.
2023-05-24 15:34:42 +02:00
uint64_t BitCountRange64(const uint64_t* bitset, uint64_t start, uint64_t end);
uint32_t BitCountRange32(const uint32_t* bitset, uint32_t start, uint32_t end);
2010-09-15 12:42:33 +00:00
// Returns true if no bits are set in bitset between start and end.
2023-05-24 15:34:42 +02:00
bool IsEmptyRange64(const uint64_t* bitset, uint64_t start, uint64_t end);
bool IsEmptyRange32(const uint32_t* bitset, uint32_t start, uint32_t end);
2010-09-15 12:42:33 +00:00
// Returns the first bit set in bitset between start and max_bit.
2023-05-24 15:34:42 +02:00
int64_t LeastSignificantBitPosition64(const uint64_t* bitset, uint64_t start,
uint64_t end);
int LeastSignificantBitPosition32(const uint32_t* bitset, uint32_t start,
uint32_t end);
2010-09-15 12:42:33 +00:00
// Returns the last bit set in bitset between min_bit and start.
2023-05-24 15:34:42 +02:00
int64_t MostSignificantBitPosition64(const uint64_t* bitset, uint64_t start,
uint64_t end);
int MostSignificantBitPosition32(const uint32_t* bitset, uint32_t start,
uint32_t end);
2010-09-15 12:42:33 +00:00
// Unsafe versions of the functions above where respectively end and start
// are supposed to be set.
2023-05-24 15:34:42 +02:00
int64_t UnsafeLeastSignificantBitPosition64(const uint64_t* bitset,
2021-04-08 18:26:38 +02:00
uint64_t start, uint64_t end);
2023-05-24 15:34:42 +02:00
int32_t UnsafeLeastSignificantBitPosition32(const uint32_t* bitset,
2021-04-08 18:26:38 +02:00
uint32_t start, uint32_t end);
2010-09-15 12:42:33 +00:00
2023-05-24 15:34:42 +02:00
int64_t UnsafeMostSignificantBitPosition64(const uint64_t* bitset,
2021-04-08 18:26:38 +02:00
uint64_t start, uint64_t end);
2023-05-24 15:34:42 +02:00
int32_t UnsafeMostSignificantBitPosition32(const uint32_t* bitset,
2021-04-08 18:26:38 +02:00
uint32_t start, uint32_t end);
2010-09-15 12:42:33 +00:00
// Returns a mask with the bits pos % 64 and (pos ^ 1) % 64 sets.
2021-04-08 18:26:38 +02:00
inline uint64_t TwoBitsFromPos64(uint64_t pos) {
return uint64_t{3} << (pos & 62);
}
// This class is like an ITIVector<IndexType, bool> except that it provides a
// more efficient way to iterate over the positions set to true. It achieves
2021-04-01 12:13:35 +02:00
// this by caching the current uint64_t bucket in the Iterator and using
// LeastSignificantBitPosition64() to iterate over the positions at 1 in this
// bucket.
2021-04-01 12:13:35 +02:00
template <typename IndexType = int64_t>
2020-10-22 23:36:58 +02:00
class Bitset64 {
public:
using value_type = IndexType;
// When speed matter, caching the base pointer helps.
2022-11-22 17:44:54 +01:00
class ConstView {
public:
explicit ConstView(const Bitset64* bitset) : data_(bitset->data_.data()) {}
bool operator[](IndexType i) const {
return data_[BitOffset64(Value(i))] & OneBit64(BitPos64(Value(i)));
}
const uint64_t* data() const { return data_; }
private:
const uint64_t* const data_;
};
class View {
public:
explicit View(Bitset64* bitset) : data_(bitset->data_.data()) {}
bool operator[](IndexType i) const {
return data_[BitOffset64(Value(i))] & OneBit64(BitPos64(Value(i)));
}
void Clear(IndexType i) {
data_[BitOffset64(Value(i))] &= ~OneBit64(BitPos64(Value(i)));
}
void Set(IndexType i) {
data_[BitOffset64(Value(i))] |= OneBit64(BitPos64(Value(i)));
}
private:
uint64_t* const data_;
};
2022-11-22 17:44:54 +01:00
Bitset64() : size_(), data_() {}
explicit Bitset64(IndexType size)
2014-03-21 18:01:18 +00:00
: size_(Value(size) > 0 ? size : IndexType(0)),
2022-11-22 17:44:54 +01:00
data_(BitLength64(Value(size_))) {}
ConstView const_view() const { return ConstView(this); }
View view() { return View(this); }
// Returns how many bits this Bitset64 can hold.
IndexType size() const { return size_; }
2013-06-11 14:53:20 +00:00
// Appends value at the end of the bitset.
void PushBack(bool value) {
++size_;
2014-03-21 18:01:18 +00:00
data_.resize(BitLength64(Value(size_)), 0);
2013-06-11 14:53:20 +00:00
Set(size_ - 1, value);
}
2014-03-21 18:01:18 +00:00
// Resizes the Bitset64 to the given number of bits. New bits are sets to 0.
2023-02-06 17:19:44 +01:00
void resize(int size) { Resize(IndexType(size)); }
void Resize(IndexType size) {
2014-03-21 18:01:18 +00:00
DCHECK_GE(Value(size), 0);
2024-01-23 14:15:18 +01:00
IndexType new_size = Value(size) > 0 ? size : IndexType(0);
if (new_size < size_ && Value(new_size) > 0) {
const int64_t new_data_size = BitLength64(Value(new_size));
const uint64_t bitmask = kAllBitsButLsb64
<< BitPos64(Value(new_size) - 1);
data_[new_data_size - 1] &= ~bitmask;
}
size_ = new_size;
2014-03-21 18:01:18 +00:00
data_.resize(BitLength64(Value(size_)), 0);
}
// Changes the number of bits the Bitset64 can hold and set all of them to 0.
void ClearAndResize(IndexType size) {
2014-03-21 18:01:18 +00:00
DCHECK_GE(Value(size), 0);
size_ = Value(size) > 0 ? size : IndexType(0);
// Memset is 4x faster than data_.assign() as of 19/03/2014.
// TODO(user): Ideally if a realloc happens, we don't need to copy the old
// data...
const size_t bit_length = static_cast<size_t>(BitLength64(Value(size_)));
const size_t to_clear = std::min(data_.size(), bit_length);
data_.resize(bit_length, 0);
2021-04-01 12:13:35 +02:00
memset(data_.data(), 0, to_clear * sizeof(int64_t));
}
// Sets all bits to 0.
2021-04-01 12:13:35 +02:00
void ClearAll() { memset(data_.data(), 0, data_.size() * sizeof(int64_t)); }
// Sets the bit at position i to 0.
void Clear(IndexType i) {
2014-03-21 18:01:18 +00:00
DCHECK_GE(Value(i), 0);
2017-04-19 16:20:56 +02:00
DCHECK_LT(Value(i), Value(size_));
2025-01-30 14:25:55 +01:00
data_.data()[BitOffset64(Value(i))] &= ~OneBit64(BitPos64(Value(i)));
}
// Sets bucket containing bit i to 0.
void ClearBucket(IndexType i) {
DCHECK_GE(Value(i), 0);
2017-04-19 16:20:56 +02:00
DCHECK_LT(Value(i), Value(size_));
data_.data()[BitOffset64(Value(i))] = 0;
}
// Clears the bits at position i and i ^ 1.
void ClearTwoBits(IndexType i) {
2014-03-21 18:01:18 +00:00
DCHECK_GE(Value(i), 0);
2017-04-19 16:20:56 +02:00
DCHECK_LT(Value(i), Value(size_));
data_[BitOffset64(Value(i))] &= ~TwoBitsFromPos64(Value(i));
}
// Returns true if the bit at position i or the one at position i ^ 1 is set.
bool AreOneOfTwoBitsSet(IndexType i) const {
2014-03-21 18:01:18 +00:00
DCHECK_GE(Value(i), 0);
2017-04-19 16:20:56 +02:00
DCHECK_LT(Value(i), Value(size_));
2025-01-30 14:25:55 +01:00
return data_.data()[BitOffset64(Value(i))] & TwoBitsFromPos64(Value(i));
}
// Returns true if the bit at position i is set.
bool IsSet(IndexType i) const {
2014-03-21 18:01:18 +00:00
DCHECK_GE(Value(i), 0);
2017-04-19 16:20:56 +02:00
DCHECK_LT(Value(i), Value(size_));
2025-01-30 14:25:55 +01:00
return data_.data()[BitOffset64(Value(i))] & OneBit64(BitPos64(Value(i)));
}
2014-03-21 18:01:18 +00:00
// Same as IsSet().
bool operator[](IndexType i) const { return IsSet(i); }
// Sets the bit at position i to 1.
void Set(IndexType i) {
2014-03-21 18:01:18 +00:00
DCHECK_GE(Value(i), 0);
DCHECK_LT(Value(i), size_);
2024-09-27 11:10:42 +02:00
// The c++ hardening is costly here, so we disable it.
2025-01-30 14:25:55 +01:00
data_.data()[BitOffset64(Value(i))] |= OneBit64(BitPos64(Value(i)));
}
// If value is true, sets the bit at position i to 1, sets it to 0 otherwise.
void Set(IndexType i, bool value) {
if (value) {
Set(i);
} else {
Clear(i);
}
}
// Copies bucket containing bit i from "other" to "this".
2020-10-29 14:25:39 +01:00
void CopyBucket(const Bitset64<IndexType>& other, IndexType i) {
2021-04-01 12:13:35 +02:00
const uint64_t offset = BitOffset64(Value(i));
data_[offset] = other.data_[offset];
}
// Copies "other" to "this". The bitsets do not have to be of the same size.
// If "other" is smaller, high order bits are not changed. If "other" is
// larger, its high order bits are ignored. In any case "this" is not resized.
2017-04-19 16:20:56 +02:00
template <typename OtherIndexType>
2020-10-29 14:25:39 +01:00
void SetContentFromBitset(const Bitset64<OtherIndexType>& other) {
2021-04-01 12:13:35 +02:00
const int64_t min_size = std::min(data_.size(), other.data_.size());
2020-10-22 23:36:58 +02:00
if (min_size == 0) return;
2021-04-01 12:13:35 +02:00
const uint64_t last_common_bucket = data_[min_size - 1];
memcpy(data_.data(), other.data_.data(), min_size * sizeof(uint64_t));
if (data_.size() >= other.data_.size()) {
2021-04-01 12:13:35 +02:00
const uint64_t bitmask = kAllBitsButLsb64
2021-04-08 18:26:38 +02:00
<< BitPos64(other.Value(other.size() - 1));
data_[min_size - 1] &= ~bitmask;
data_[min_size - 1] |= (bitmask & last_common_bucket);
}
}
// Same as SetContentFromBitset where "this" and "other" have the same size.
2017-04-19 16:20:56 +02:00
template <typename OtherIndexType>
2020-10-29 14:25:39 +01:00
void SetContentFromBitsetOfSameSize(const Bitset64<OtherIndexType>& other) {
2017-04-19 16:20:56 +02:00
DCHECK_EQ(Value(size()), other.Value(other.size()));
2021-04-01 12:13:35 +02:00
memcpy(data_.data(), other.data_.data(), data_.size() * sizeof(uint64_t));
}
// Sets "this" to be the intersection of "this" and "other". The
// bitsets do not have to be the same size. If other is smaller, all
// the higher order bits are assumed to be 0.
2020-10-29 14:25:39 +01:00
void Intersection(const Bitset64<IndexType>& other) {
const int min_size = std::min(data_.size(), other.data_.size());
uint64_t* const d = data_.data();
const uint64_t* const o = other.data_.data();
for (int i = 0; i < min_size; ++i) {
d[i] &= o[i];
}
for (int i = min_size; i < data_.size(); ++i) {
d[i] = 0;
}
}
2024-09-27 11:10:42 +02:00
// This one assume both given bitset to be of the same size.
void SetToIntersectionOf(const Bitset64<IndexType>& a,
const Bitset64<IndexType>& b) {
DCHECK_EQ(a.size(), b.size());
Resize(a.size());
// Copy buckets.
const int num_buckets = a.data_.size();
for (int i = 0; i < num_buckets; ++i) {
data_[i] = a.data_[i] & b.data_[i];
}
}
// Sets "this" to be the union of "this" and "other". The
// bitsets do not have to be the same size. If other is smaller, all
// the higher order bits are assumed to be 0.
2020-10-29 14:25:39 +01:00
void Union(const Bitset64<IndexType>& other) {
const int min_size = std::min(data_.size(), other.data_.size());
for (int i = 0; i < min_size; ++i) {
data_[i] |= other.data_[i];
}
}
// Class to iterate over the bit positions at 1 of a Bitset64.
2014-03-21 18:01:18 +00:00
//
2021-04-01 12:13:35 +02:00
// IMPORTANT: Because the iterator "caches" the current uint64_t bucket, this
2014-03-21 18:01:18 +00:00
// will probably not do what you want if Bitset64 is modified while iterating.
class Iterator {
2020-10-22 23:36:58 +02:00
public:
// Make this iterator a std::forward_iterator, so it works with std::sample,
// std::max_element, etc.
Iterator() : data_(nullptr), size_(0) {}
Iterator(Iterator&& other) = default;
Iterator(const Iterator& other) = default;
Iterator& operator=(const Iterator& other) = default;
using difference_type = std::ptrdiff_t;
using iterator_category = std::forward_iterator_tag;
using value_type = IndexType;
using size_type = std::size_t;
using reference = value_type&;
using pointer = value_type*;
2022-11-22 17:44:54 +01:00
explicit Iterator(const Bitset64& bitset)
: data_(bitset.data_.data()), size_(bitset.data_.size()) {
if (!bitset.data_.empty()) {
current_ = data_[0];
this->operator++();
}
}
static Iterator EndIterator(const Bitset64& bitset) {
return Iterator(bitset.data_.data());
}
2024-01-31 16:19:50 +01:00
bool operator==(const Iterator& other) const { return !(*this != other); }
bool operator!=(const Iterator& other) const {
if (other.size_ == 0) {
return size_ != 0;
}
return std::tie(index_, current_) !=
std::tie(other.index_, other.current_);
}
2022-11-22 17:44:54 +01:00
IndexType operator*() const { return IndexType(index_); }
Iterator operator++(int) {
Iterator other = *this;
2024-01-31 16:19:50 +01:00
++(*this);
return other;
}
Iterator& operator++() {
2022-11-22 17:44:54 +01:00
int bucket = BitOffset64(index_);
while (current_ == 0) {
bucket++;
if (bucket == size_) {
size_ = 0;
return *this;
}
2022-11-22 17:44:54 +01:00
current_ = data_[bucket];
}
// Computes the index and clear the least significant bit of current_.
2022-11-22 17:44:54 +01:00
index_ = BitShift64(bucket) | LeastSignificantBitPosition64(current_);
current_ &= current_ - 1;
return *this;
}
2020-10-22 23:36:58 +02:00
private:
explicit Iterator(const uint64_t* data) : data_(data), size_(0) {}
const uint64_t* data_;
2022-11-22 17:44:54 +01:00
int size_;
int index_ = 0;
uint64_t current_ = 0;
};
2013-06-11 14:53:20 +00:00
// Allows range-based "for" loop on the non-zero positions:
// for (const IndexType index : bitset) {}
Iterator begin() const { return Iterator(*this); }
Iterator end() const { return Iterator::EndIterator(*this); }
2013-06-11 14:53:20 +00:00
2021-04-14 14:33:47 +02:00
// Cryptic function! This is just an optimized version of a given piece of
// code and has probably little general use.
static uint64_t ConditionalXorOfTwoBits(IndexType i, uint64_t use1,
Bitset64<IndexType>::ConstView set1,
2021-04-14 14:33:47 +02:00
uint64_t use2,
Bitset64<IndexType>::ConstView set2) {
DCHECK(use1 == 0 || use1 == 1);
DCHECK(use2 == 0 || use2 == 1);
2014-03-21 18:01:18 +00:00
const int bucket = BitOffset64(Value(i));
const int pos = BitPos64(Value(i));
return ((use1 << pos) & set1.data()[bucket]) ^
((use2 << pos) & set2.data()[bucket]);
}
// Returns a 0/1 string representing the bitset.
std::string DebugString() const {
std::string output;
for (IndexType i(0); i < size(); ++i) {
output += IsSet(i) ? "1" : "0";
}
return output;
}
bool IsAllFalse() const {
return std::all_of(data_.begin(), data_.end(),
[](uint64_t v) { return v == 0; });
}
2020-10-22 23:36:58 +02:00
private:
2014-03-21 18:01:18 +00:00
// Returns the value of the index type.
2021-04-01 12:13:35 +02:00
// This function is specialized below to work with IntType and int64_t.
static int Value(IndexType input);
2014-03-21 18:01:18 +00:00
IndexType size_;
2021-04-01 12:13:35 +02:00
std::vector<uint64_t> data_;
2020-10-22 23:36:58 +02:00
template <class OtherIndexType>
friend class Bitset64;
};
// Specialized version of Bitset64 that allows to query the last bit set more
// efficiently.
class BitQueue64 {
2020-10-22 23:36:58 +02:00
public:
BitQueue64() : size_(), top_(-1), data_() {}
explicit BitQueue64(int size)
: size_(size), top_(-1), data_(BitLength64(size), 0) {}
2023-08-30 10:04:47 -04:00
// This type is neither copyable nor movable.
BitQueue64(const BitQueue64&) = delete;
BitQueue64& operator=(const BitQueue64&) = delete;
void IncreaseSize(int size) {
CHECK_GE(size, size_);
size_ = size;
data_.resize(BitLength64(size), 0);
}
void ClearAndResize(int size) {
top_ = -1;
size_ = size;
data_.assign(BitLength64(size), 0);
}
void Set(int i) {
DCHECK_GE(i, 0);
DCHECK_LT(i, size_);
top_ = std::max(top_, i);
data_[BitOffset64(i)] |= OneBit64(BitPos64(i));
}
2017-11-24 11:07:21 +01:00
// Sets all the bits from 0 up to i-1 to 1.
void SetAllBefore(int i) {
DCHECK_GE(i, 0);
DCHECK_LT(i, size_);
top_ = std::max(top_, i - 1);
int bucket_index = static_cast<int>(BitOffset64(i));
2017-11-24 11:07:21 +01:00
data_[bucket_index] |= OneBit64(BitPos64(i)) - 1;
for (--bucket_index; bucket_index >= 0; --bucket_index) {
data_[bucket_index] = kAllBits64;
}
}
// Returns the position of the highest bit set in O(1) or -1 if no bit is set.
int Top() const { return top_; }
// Clears the Top() bit and recomputes the position of the next Top().
void ClearTop() {
DCHECK_NE(top_, -1);
int bucket_index = static_cast<int>(BitOffset64(top_));
2021-04-01 12:13:35 +02:00
uint64_t bucket = data_[bucket_index] &= ~OneBit64(BitPos64(top_));
while (!bucket) {
if (bucket_index == 0) {
top_ = -1;
return;
}
bucket = data_[--bucket_index];
}
// Note(user): I experimented with reversing the bit order in a bucket to
// use LeastSignificantBitPosition64() and it is only slightly faster at the
2021-08-15 23:11:16 +07:00
// cost of a lower Set() speed. So I preferred this version.
top_ = static_cast<int>(BitShift64(bucket_index) +
MostSignificantBitPosition64(bucket));
}
2020-10-22 23:36:58 +02:00
private:
int size_;
int top_;
2021-04-01 12:13:35 +02:00
std::vector<uint64_t> data_;
};
2021-04-01 12:13:35 +02:00
// The specialization of Value() for IntType and int64_t.
2014-03-21 18:01:18 +00:00
template <typename IntType>
inline int Bitset64<IntType>::Value(IntType input) {
2014-03-21 18:01:18 +00:00
DCHECK_GE(input.value(), 0);
return input.value();
}
2020-10-22 23:36:58 +02:00
template <>
inline int Bitset64<int>::Value(int input) {
DCHECK_GE(input, 0);
return input;
}
template <>
inline int Bitset64<int64_t>::Value(int64_t input) {
2014-03-21 18:01:18 +00:00
DCHECK_GE(input, 0);
return input;
}
2024-09-23 16:04:53 +02:00
template <>
inline int Bitset64<size_t>::Value(size_t input) {
return input;
}
2014-03-21 18:01:18 +00:00
// A simple utility class to set/unset integer in a range [0, size).
// This is optimized for sparsity.
2021-04-01 12:13:35 +02:00
template <typename IntegerType = int64_t>
2020-10-22 23:36:58 +02:00
class SparseBitset {
public:
SparseBitset() {}
2014-03-21 18:01:18 +00:00
explicit SparseBitset(IntegerType size) : bitset_(size) {}
2023-08-30 10:04:47 -04:00
// This type is neither copyable nor movable.
SparseBitset(const SparseBitset&) = delete;
SparseBitset& operator=(const SparseBitset&) = delete;
2014-03-21 18:01:18 +00:00
IntegerType size() const { return bitset_.size(); }
2025-03-05 14:03:49 +01:00
void ResetAllToFalse() { ClearAndResize(size()); }
void ClearAndResize(IntegerType size) {
2014-03-21 18:01:18 +00:00
// As of 19/03/2014, experiments show that this is a reasonable threshold.
const int kSparseThreshold = 300;
if (to_clear_.size() * kSparseThreshold < size) {
2025-03-05 14:03:49 +01:00
for (const IntegerType i : to_clear_) bitset_.ClearBucket(i);
to_clear_.clear();
2014-03-21 18:01:18 +00:00
bitset_.Resize(size);
} else {
bitset_.ClearAndResize(size);
to_clear_.clear();
}
}
2014-07-29 00:58:38 +00:00
void Resize(IntegerType size) {
if (size < bitset_.size()) {
int new_index = 0;
for (IntegerType index : to_clear_) {
if (index < size) {
to_clear_[new_index] = index;
++new_index;
}
}
to_clear_.resize(new_index);
}
bitset_.Resize(size);
}
2014-03-21 18:01:18 +00:00
bool operator[](IntegerType index) const { return bitset_[index]; }
void Set(IntegerType index) {
2014-03-21 18:01:18 +00:00
if (!bitset_[index]) {
bitset_.Set(index);
to_clear_.push_back(index);
}
}
2024-09-27 11:10:42 +02:00
2025-10-16 13:29:59 +02:00
void CopyFrom(const SparseBitset& other) {
bitset_.ClearAndResize(other.size());
bitset_.SetContentFromBitsetOfSameSize(other.bitset_);
to_clear_.assign(other.to_clear_.begin(), other.to_clear_.end());
}
2024-09-27 11:10:42 +02:00
// A bit hacky for really hot loop.
typename Bitset64<IntegerType>::View BitsetView() { return bitset_.view(); }
typename Bitset64<IntegerType>::ConstView BitsetConstView() {
return bitset_.const_view();
}
2024-09-27 11:10:42 +02:00
void SetUnsafe(typename Bitset64<IntegerType>::View view, IntegerType index) {
view.Set(index);
2023-02-06 19:02:44 +01:00
to_clear_.push_back(index);
}
2024-09-27 11:10:42 +02:00
2014-03-21 18:01:18 +00:00
void Clear(IntegerType index) { bitset_.Clear(index); }
int NumberOfSetCallsWithDifferentArguments() const {
return to_clear_.size();
}
2020-10-29 14:25:39 +01:00
const std::vector<IntegerType>& PositionsSetAtLeastOnce() const {
return to_clear_;
}
2014-07-29 00:58:38 +00:00
// Tells the class that all its bits are cleared, so it can reset to_clear_
// to the empty vector. Note that this call is "unsafe" since the fact that
// the class is actually all cleared is only checked in debug mode.
//
// This is useful to iterate on the "set" positions while clearing them for
// instance. This way, after the loop, a client can call this for efficiency.
void NotifyAllClear() {
2025-02-24 22:59:21 +01:00
#if !defined(NDEBUG)
for (IntegerType index : to_clear_) CHECK(!bitset_[index]);
#endif
2014-07-29 00:58:38 +00:00
to_clear_.clear();
}
2023-02-06 19:02:44 +01:00
typename Bitset64<IntegerType>::ConstView const_view() const {
return bitset_.const_view();
}
2020-10-22 23:36:58 +02:00
private:
2014-03-21 18:01:18 +00:00
Bitset64<IntegerType> bitset_;
std::vector<IntegerType> to_clear_;
};
2020-10-22 23:36:58 +02:00
} // namespace operations_research
2010-09-15 12:42:33 +00:00
2025-11-05 10:13:48 +01:00
#endif // ORTOOLS_UTIL_BITSET_H_