From a9dcc289d650925ceafde783fed19c53846fdb18 Mon Sep 17 00:00:00 2001 From: "lperron@google.com" Date: Fri, 4 Apr 2014 09:13:02 +0000 Subject: [PATCH] more work on src/util, mainly on the bitset class --- src/util/bitset.h | 63 +++++++++++++++++++++++++++++++-- src/util/fp_utils.h | 7 ++++ src/util/saturated_arithmetic.h | 7 ++-- 3 files changed, 73 insertions(+), 4 deletions(-) diff --git a/src/util/bitset.h b/src/util/bitset.h index d0b3dc2091..f910bd0dd3 100644 --- a/src/util/bitset.h +++ b/src/util/bitset.h @@ -30,6 +30,7 @@ namespace operations_research { // Useful constants: word and double word will all bits set. static const uint64 kAllBits64 = GG_ULONGLONG(0xFFFFFFFFFFFFFFFF); +static const uint64 kAllBitsButLsb64 = GG_ULONGLONG(0xFFFFFFFFFFFFFFFE); static const uint32 kAllBits32 = 0xFFFFFFFFU; // Returns a word with only bit pos set. @@ -426,6 +427,11 @@ class Bitset64 { memset(data_.data(), 0, to_clear * sizeof(int64)); } + // Sets all bits to 0. + void ClearAll() { + memset(data_.data(), 0, data_.size() * sizeof(int64)); + } + // Sets the bit at position i to 0. void Clear(IndexType i) { DCHECK_GE(Value(i), 0); @@ -433,6 +439,13 @@ class Bitset64 { data_[BitOffset64(Value(i))] &= ~OneBit64(BitPos64(Value(i))); } + // Sets bucket containing bit i to 0. + void ClearBucket(IndexType i) { + DCHECK_GE(Value(i), 0); + DCHECK_LT(Value(i), size_); + data_[BitOffset64(Value(i))] = 0; + } + // Copies the bits at position i and i ^ 1 and then clear them. void CopyAndClearTwoBits(IndexType i, Bitset64* to) { DCHECK_GE(Value(i), 0); @@ -476,6 +489,35 @@ class Bitset64 { } } + // Copies bucket containing bit i from "other" to "this". + void CopyBucket(const Bitset64& other, IndexType i) { + const uint64 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. + void SetContentFromBitset(const Bitset64& other) { + const int min_size = std::min(data_.size(), other.data_.size()); + if (min_size == 0) return; + const uint64 last_common_bucket = data_[min_size - 1]; + memcpy(data_.data(), other.data_.data(), min_size * sizeof(uint64)); + if (data_.size() >= other.data_.size()) { + const uint64 bitmask = + kAllBitsButLsb64 << BitPos64(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. + void SetContentFromBitsetOfSameSize(const Bitset64& other) { + DCHECK_EQ(size(), other.size()); + memcpy(data_.data(), other.data_.data(), data_.size() * sizeof(uint64)); + } + + // 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. @@ -585,6 +627,15 @@ class Bitset64 { ((use2 << pos) & other2.data_[bucket]); } + // Returns a 0/1 std::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; + } + private: // Returns the value of the index type. // This function is specialized below to work with IntType and int64. @@ -620,16 +671,24 @@ class SparseBitset { SparseBitset() {} explicit SparseBitset(IntegerType size) : bitset_(size) {} IntegerType size() const { return bitset_.size(); } + void SparseClearAll() { + for (const IntegerType i : to_clear_) bitset_.ClearBucket(i); + to_clear_.clear(); + } + void ClearAll() { + bitset_.ClearAll(); + to_clear_.clear(); + } void ClearAndResize(IntegerType size) { // As of 19/03/2014, experiments show that this is a reasonable threshold. const int kSparseThreshold = 300; if (to_clear_.size() * kSparseThreshold < size) { - for (const IntegerType i : to_clear_) Clear(i); + SparseClearAll(); bitset_.Resize(size); } else { bitset_.ClearAndResize(size); + to_clear_.clear(); } - to_clear_.clear(); } bool operator[](IntegerType index) const { return bitset_[index]; } void Set(IntegerType index) { diff --git a/src/util/fp_utils.h b/src/util/fp_utils.h index 35bdb32e7c..c30790a534 100644 --- a/src/util/fp_utils.h +++ b/src/util/fp_utils.h @@ -165,6 +165,13 @@ void GetBestScalingOfDoublesToInt64(const std::vector& x, double* scaling_factor, double* relative_error); +// Returns the Greatest Common Divisor of the numbers +// round(fabs(x[i] * scaling_factor)). The numbers 0 are ignored and if they are +// all zero then the result is 1. Note that round(fabs()) is the same as +// fabs(round()) since the numbers are rounded away from zero. +int64 ComputeGcdOfRoundedDoubles(const std::vector& x, + double scaling_factor); + } // namespace operations_research #endif // OR_TOOLS_UTIL_FP_UTILS_H_ diff --git a/src/util/saturated_arithmetic.h b/src/util/saturated_arithmetic.h index 473077f839..c345e30d7c 100644 --- a/src/util/saturated_arithmetic.h +++ b/src/util/saturated_arithmetic.h @@ -21,12 +21,15 @@ namespace operations_research { // ---------- Overflow utility functions ---------- // Performs *b += a and returns false iff the addition overflow or underflow. +// This function only works for typed integer type (IntType<>). template bool SafeAddInto(IntegerType a, IntegerType* b) { if (a > 0) { - if (*b > std::numeric_limits::max() - a) return false; + if (*b > std::numeric_limits::max() - a) + return false; } else { - if (*b < std::numeric_limits::min() - a) return false; + if (*b < std::numeric_limits::min() - a) + return false; } *b += a; return true;