From 2e9ccb3d9877c56f5098edf6ab0a4e4a6875bc3b Mon Sep 17 00:00:00 2001 From: schmi710 <55195426+schmi710@users.noreply.github.com> Date: Fri, 26 Jun 2020 18:58:27 -0400 Subject: [PATCH 1/9] Add files via upload --- source/tools/BitVector.h | 610 ++++++++++++++++++++++++++------------- 1 file changed, 413 insertions(+), 197 deletions(-) diff --git a/source/tools/BitVector.h b/source/tools/BitVector.h index 9e1ab91ff4..1aa1d45608 100644 --- a/source/tools/BitVector.h +++ b/source/tools/BitVector.h @@ -9,9 +9,6 @@ * * Compile with -O3 and -msse4.2 for fast bit counting. * - * @todo Most of the operators don't check to make sure that both Bitvextors are the same size. - * We should create versions (Intersection() and Union()?) that adjust sizes if needed. - * * @todo Do small BitVector optimization. Currently we have number of bits (8 bytes) and a * pointer to the memory for the bitset (another 8 bytes), but we could use those 16 bytes * as 1 byte of size info followed by 15 bytes of bitset (120 bits!) @@ -19,9 +16,6 @@ * @todo Implement append(), resize()... * @todo Implement techniques to push bits (we have pop) * @todo Implement techniques to insert or remove bits from middle. - * @todo Think about how itertors should work for BitVector. It should probably go bit-by-bit, - * but there are very few circumstances where that would be useful. Going through the - * positions of all ones would be more useful, but perhaps less intuitive. * * @note This class is 15-20% slower than emp::BitSet, but more flexible & run-time configurable. */ @@ -36,6 +30,7 @@ #include "../base/assert.h" #include "../base/Ptr.h" #include "../base/vector.h" +#include "../base/array.h" #include "bitset_utils.h" #include "functions.h" @@ -60,7 +55,11 @@ namespace emp { static constexpr size_t FIELD_BITS = sizeof(field_t)*8; ///< How many bits are in a field? size_t num_bits; ///< How many total bits are we using? - Ptr bit_set; ///< What is the status of each bit? + //Ptr bit_set; ///< What is the status of each bit? + // emp::array bit_set; ///< What is the status of each bit? + emp::Ptr bit_set; + + static constexpr const size_t SHORT_THRESHOLD = 64; /// End position of the stored bits in the last field; 0 if perfect fit. size_t LastBitID() const { return num_bits & (FIELD_BITS - 1); } @@ -163,16 +162,16 @@ namespace emp { /// Assume that the size of the bit_set has already been adjusted to be the size of the one /// being copied and only the fields need to be copied over. - void RawCopy(const Ptr in_set) { + void RawCopy(Ptr in_set) { #ifdef EMP_TRACK_MEM emp_assert(in_set.IsNull() == false); - emp_assert(bit_set.DebugIsArray() && in_set.DebugIsArray()); - emp_assert(bit_set.DebugGetArrayBytes() == in_set.DebugGetArrayBytes(), - bit_set.DebugGetArrayBytes(), in_set.DebugGetArrayBytes()); + emp_assert(BitSetPtr().DebugIsArray() && in_set.DebugIsArray()); + emp_assert(BitSetPtr().DebugGetArrayBytes() == in_set.DebugGetArrayBytes(), + BitSetPtr().DebugGetArrayBytes(), in_set.DebugGetArrayBytes()); #endif - + const size_t NUM_FIELDS = NumFields(); - for (size_t i = 0; i < NUM_FIELDS; i++) bit_set[i] = in_set[i]; + for (size_t i = 0; i < NUM_FIELDS; i++) BitSetPtr()[i] = in_set[i]; } /// Helper: call SHIFT with positive number @@ -181,32 +180,34 @@ namespace emp { const size_t bit_shift = shift_size % FIELD_BITS; const size_t bit_overflow = FIELD_BITS - bit_shift; const size_t NUM_FIELDS = NumFields(); - - // Loop through each field, from L to R, and update it. - if (field_shift) { - for (size_t i = NUM_FIELDS; i > field_shift; --i) { - bit_set[i-1] = bit_set[i - field_shift - 1]; + if (num_bits > SHORT_THRESHOLD) { + // Loop through each field, from L to R, and update it. + if (field_shift) { + for (size_t i = NUM_FIELDS; i > field_shift; --i) { + BitSetPtr()[i-1] = BitSetPtr()[i - field_shift - 1]; + } + for (size_t i = field_shift; i > 0; --i) BitSetPtr()[i-1] = 0; } - for (size_t i = field_shift; i > 0; --i) bit_set[i-1] = 0; - } - // account for bit_shift - if (bit_shift) { - for (size_t i = NUM_FIELDS - 1; i > field_shift; --i) { - bit_set[i] <<= bit_shift; - bit_set[i] |= (bit_set[i-1] >> bit_overflow); + // account for bit_shift + if (bit_shift) { + for (size_t i = NUM_FIELDS - 1; i > field_shift; --i) { + BitSetPtr()[i] <<= bit_shift; + BitSetPtr()[i] |= (BitSetPtr()[i-1] >> bit_overflow); + } + // Handle final field (field_shift position) + BitSetPtr()[field_shift] <<= bit_shift; } - // Handle final field (field_shift position) - bit_set[field_shift] <<= bit_shift; - } - // Mask out any bits that have left-shifted away - const size_t last_bit_id = LastBitID(); - constexpr field_t val_one = 1; - if (last_bit_id) { bit_set[NUM_FIELDS - 1] &= (val_one << last_bit_id) - val_one; } + // Mask out any bits that have left-shifted away + const size_t last_bit_id = LastBitID(); + constexpr field_t val_one = 1; + if (last_bit_id) { BitSetPtr()[NUM_FIELDS - 1] &= (val_one << last_bit_id) - val_one; } + } else { + *BitSetPtr().Raw() <<= bit_shift; + } } - /// Helper for calling SHIFT with negative number void ShiftRight(const size_t shift_size) { const size_t field_shift = shift_size / FIELD_BITS; @@ -215,55 +216,79 @@ namespace emp { const size_t NUM_FIELDS = NumFields(); const size_t field_shift2 = NUM_FIELDS - field_shift; + if (num_bits > SHORT_THRESHOLD) { // account for field_shift - if (field_shift) { - for (size_t i = 0; i < field_shift2; ++i) { - bit_set[i] = bit_set[i + field_shift]; + if (field_shift) { + for (size_t i = 0; i < field_shift2; ++i) { + BitSetPtr()[i] = BitSetPtr()[i + field_shift]; + } + for (size_t i = field_shift2; i < NUM_FIELDS; i++) BitSetPtr()[i] = 0U; } - for (size_t i = field_shift2; i < NUM_FIELDS; i++) bit_set[i] = 0U; - } - // account for bit_shift - if (bit_shift) { - for (size_t i = 0; i < (field_shift2 - 1); ++i) { - bit_set[i] >>= bit_shift; - bit_set[i] |= (bit_set[i+1] << bit_overflow); + // account for bit_shift + if (bit_shift) { + for (size_t i = 0; i < (field_shift2 - 1); ++i) { + BitSetPtr()[i] >>= bit_shift; + BitSetPtr()[i] |= (BitSetPtr()[i+1] << bit_overflow); + } + BitSetPtr()[field_shift2 - 1] >>= bit_shift; } - bit_set[field_shift2 - 1] >>= bit_shift; + } else { + *BitSetPtr().Raw() >>= bit_shift; } } public: /// Build a new BitVector with specified bit count (default 0) and initialization (default 0) - BitVector(size_t in_num_bits=0, bool init_val=false) : num_bits(in_num_bits), bit_set(nullptr) { - if (num_bits) bit_set = NewArrayPtr(NumFields()); + BitVector(size_t in_num_bits=0, bool init_val=false) + : num_bits(in_num_bits), bit_set() + { + //if (num_bits) bit_set = emp::array(); + + if (num_bits > SHORT_THRESHOLD) { + //bit_set = emp::NewArrayPtr(8); + //BitSetPtr() = NewArrayPtr(NumFields()); + bit_set = NewArrayPtr(NumFields()).Cast(); + } if (init_val) SetAll(); else Clear(); } /// Copy constructor of existing bit field. - BitVector(const BitVector & in_set) : num_bits(in_set.num_bits), bit_set(nullptr) { + BitVector(const BitVector & in_set) + : num_bits(in_set.num_bits), bit_set() + { #ifdef EMP_TRACK_MEM - emp_assert(in_set.bit_set.IsNull() || in_set.bit_set.DebugIsArray()); - emp_assert(in_set.bit_set.OK()); + if (num_bits > SHORT_THRESHOLD) { + emp_assert(in_set.bit_set.IsNull() || in_set.bit_set.DebugIsArray()); + emp_assert(in_set.bit_set.OK()); + } #endif - // There is only something to copy if there are a non-zero number of bits! if (num_bits) { #ifdef EMP_TRACK_MEM - emp_assert(!in_set.bit_set.IsNull() && in_set.bit_set.DebugIsArray(), in_set.bit_set.IsNull(), in_set.bit_set.DebugIsArray()); + if (in_set.num_bits > SHORT_THRESHOLD) + emp_assert(!in_set.bit_set.IsNull() && in_set.bit_set.DebugIsArray(), in_set.bit_set.IsNull(), in_set.bit_set.DebugIsArray()); #endif - bit_set = NewArrayPtr(NumFields()); - RawCopy(in_set.bit_set); + if (num_bits > SHORT_THRESHOLD) + { + bit_set = NewArrayPtr(NumFields()).Cast(); + } + if (in_set.num_bits > SHORT_THRESHOLD){ + RawCopy(in_set.BitSetPtr()); + } else { + *BitSetPtr().Raw() = *(in_set.BitSetPtr().Raw()); + } } } /// Move constructor of existing bit field. BitVector(BitVector && in_set) : num_bits(in_set.num_bits), bit_set(in_set.bit_set) { #ifdef EMP_TRACK_MEM - emp_assert(bit_set == nullptr || bit_set.DebugIsArray()); - emp_assert(bit_set.OK()); + if (in_set.num_bits > SHORT_THRESHOLD) { + emp_assert(bit_set == nullptr || bit_set.DebugIsArray()); + emp_assert(bit_set.OK()); + } #endif - in_set.bit_set = nullptr; in_set.num_bits = 0; } @@ -276,31 +301,44 @@ namespace emp { /// Destructor ~BitVector() { if (bit_set) { // A move constructor can make bit_set == nullptr - bit_set.DeleteArray(); - bit_set = nullptr; + if (num_bits > SHORT_THRESHOLD) { + BitSetPtr().DeleteArray(); + } } } /// Assignment operator. BitVector & operator=(const BitVector & in_set) { #ifdef EMP_TRACK_MEM - emp_assert(in_set.bit_set == nullptr || in_set.bit_set.DebugIsArray()); - emp_assert(in_set.bit_set != nullptr || in_set.num_bits == 0); - emp_assert(in_set.bit_set.OK()); + if (in_set.num_bits > SHORT_THRESHOLD) { + emp_assert(in_set.BitSetPtr() == nullptr || in_set.BitSetPtr().DebugIsArray()); + emp_assert(in_set.BitSetPtr() != nullptr || in_set.num_bits == 0); + emp_assert(in_set.BitSetPtr().OK()); + } #endif - + if (&in_set == this) return *this; const size_t in_num_fields = in_set.NumFields(); const size_t prev_num_fields = NumFields(); - num_bits = in_set.num_bits; if (in_num_fields != prev_num_fields) { - if (bit_set) bit_set.DeleteArray(); - if (num_bits) bit_set = NewArrayPtr(in_num_fields); - else bit_set = nullptr; + if (bit_set) { + if (num_bits > SHORT_THRESHOLD) { + BitSetPtr().DeleteArray(); + } else { + *BitSetPtr().Raw() = 0; + } + } + } + num_bits = in_set.num_bits; + if (in_num_fields != prev_num_fields && in_set.num_bits > SHORT_THRESHOLD) { + bit_set = NewArrayPtr(NumFields()).Cast(); + } + if (num_bits > SHORT_THRESHOLD){ + RawCopy(in_set.BitSetPtr()); + } else { + *BitSetPtr().Raw() = *(in_set.BitSetPtr().Raw()); } - - if (num_bits) RawCopy(in_set.bit_set); return *this; } @@ -308,7 +346,7 @@ namespace emp { /// Move operator. BitVector & operator=(BitVector && in_set) { emp_assert(&in_set != this); // in_set is an r-value, so this shouldn't be possible... - if (bit_set) bit_set.DeleteArray(); // If we already had a bitset, get rid of it. + if (num_bits > SHORT_THRESHOLD && BitSetPtr()) BitSetPtr().DeleteArray(); // If we already had a bitset, get rid of it. num_bits = in_set.num_bits; // Update the number of bits... bit_set = in_set.bit_set; // And steal the old memory for what those bits are. in_set.bit_set = nullptr; // Prepare in_set for deletion without deallocating. @@ -328,6 +366,7 @@ namespace emp { /// Resize this BitVector to have the specified number of bits. BitVector & Resize(size_t new_bits) { + const size_t old_num_bits = num_bits; const size_t old_num_fields = NumFields(); num_bits = new_bits; const size_t NUM_FIELDS = NumFields(); @@ -335,19 +374,46 @@ namespace emp { if (NUM_FIELDS == old_num_fields) { // We can use our existing bit field num_bits = new_bits; // If there are extra bits, zero them out. - if (LastBitID() > 0) bit_set[NUM_FIELDS - 1] &= MaskLow(LastBitID()); + if (LastBitID() > 0) { + if (num_bits > SHORT_THRESHOLD) { + BitSetPtr()[NUM_FIELDS - 1] &= MaskLow(LastBitID()); + } else { + *BitSetPtr().Raw() &= MaskLow(LastBitID()); + } + } } - + else { // We have to change the number of bitfields. Resize & copy old info. - Ptr old_bit_set = bit_set; - if (num_bits > 0) bit_set = NewArrayPtr(NUM_FIELDS); - else bit_set = nullptr; + auto old_bit_set = bit_set; + + if (num_bits > SHORT_THRESHOLD) { + bit_set = NewArrayPtr(NUM_FIELDS).Cast(); + } else { + bit_set = Ptr(); + Clear(); + } const size_t min_fields = std::min(old_num_fields, NUM_FIELDS); - for (size_t i = 0; i < min_fields; i++) bit_set[i] = old_bit_set[i]; - for (size_t i = min_fields; i < NUM_FIELDS; i++) bit_set[i] = 0U; - if (old_bit_set) old_bit_set.DeleteArray(); - } + if (num_bits > SHORT_THRESHOLD) { + if (old_num_bits > SHORT_THRESHOLD) { + for (size_t i = 0; i < min_fields; i++) BitSetPtr()[i] = BitSetPtr(old_bit_set, old_num_bits)[i]; + } else { + BitSetPtr()[0] = *BitSetPtr(old_bit_set, old_num_bits).Raw(); + } + for (size_t i = min_fields; i < NUM_FIELDS; i++) BitSetPtr()[i] = 0U; + + } else { + if (old_num_bits > SHORT_THRESHOLD) { + *BitSetPtr().Raw() = BitSetPtr(old_bit_set, old_num_bits)[0]; + } else { + bit_set = old_bit_set; + } + for (size_t i = min_fields; i < NUM_FIELDS; i++) bit_set[i] = std::byte(0); + + } + if (old_bit_set && old_num_bits > SHORT_THRESHOLD) BitSetPtr(old_bit_set, old_num_bits).DeleteArray(); + + } return *this; } @@ -357,7 +423,11 @@ namespace emp { const size_t NUM_FIELDS = NumFields(); for (size_t i = 0; i < NUM_FIELDS; ++i) { - if (bit_set[i] != in_set.bit_set[i]) return false; + if (num_bits > SHORT_THRESHOLD) { + if (BitSetPtr()[i] != in_set.BitSetPtr()[i]) return false; + } else { + if (*BitSetPtr().Raw() != *(in_set.BitSetPtr().Raw())) return false; + } } return true; } @@ -365,12 +435,13 @@ namespace emp { /// Compare the would-be numerical values of two bit vectors. bool operator<(const BitVector & in_set) const { if (num_bits != in_set.num_bits) return num_bits < in_set.num_bits; + if (num_bits <= SHORT_THRESHOLD) return (*BitSetPtr().Raw() < *(in_set.BitSetPtr().Raw())); const size_t NUM_FIELDS = NumFields(); for (size_t i = NUM_FIELDS; i > 0; --i) { // Start loop at the largest field. const size_t pos = i-1; - if (bit_set[pos] == in_set.bit_set[pos]) continue; // If same, keep looking! - return (bit_set[pos] < in_set.bit_set[pos]); // Otherwise, do comparison + if (BitSetPtr()[pos] == in_set.BitSetPtr()[pos]) continue; // If same, keep looking! + return (BitSetPtr()[pos] < in_set.BitSetPtr()[pos]); // Otherwise, do comparison } return false; } @@ -378,12 +449,13 @@ namespace emp { /// Compare the would-be numerical values of two bit vectors. bool operator<=(const BitVector & in_set) const { if (num_bits != in_set.num_bits) return num_bits <= in_set.num_bits; + if (num_bits <= SHORT_THRESHOLD) return (*BitSetPtr().Raw() <= *(in_set.BitSetPtr().Raw())); const size_t NUM_FIELDS = NumFields(); for (size_t i = NUM_FIELDS; i > 0; --i) { // Start loop at the largest field. const size_t pos = i-1; - if (bit_set[pos] == in_set.bit_set[pos]) continue; // If same, keep looking! - return (bit_set[pos] < in_set.bit_set[pos]); // Otherwise, do comparison + if (BitSetPtr()[pos] == in_set.BitSetPtr()[pos]) continue; // If same, keep looking! + return (BitSetPtr()[pos] < in_set.BitSetPtr()[pos]); // Otherwise, do comparison } return true; } @@ -399,13 +471,50 @@ namespace emp { /// How many bits do we currently have? size_t GetSize() const { return num_bits; } + + /// Return the proper casting of bit_set (but const) + emp::Ptr BitSetPtr() const{ + // For large bit sets, the bit_set pointer tells you where it is. + if (num_bits > SHORT_THRESHOLD) { + return bit_set.Cast(); + } + + // For small bit_sets assume they all fit in the space of the bit_set pointer. + return emp::Ptr((const field_t*) &bit_set); + } + + /// Return the proper casting of bit_set + emp::Ptr BitSetPtr() { + // For large bit sets, the bit_set pointer tells you where it is. + if (num_bits > SHORT_THRESHOLD) { + return bit_set.Cast(); + } + + // For small bit_sets assume they all fit in the space of the bit_set pointer. + return emp::Ptr((field_t*) &bit_set); + } + + /// Return the proper casting of a supplied bit_set and number of bits + emp::Ptr BitSetPtr(emp::Ptr p, size_t num) { + // For large bit sets, the bit_set pointer tells you where it is. + if (num > SHORT_THRESHOLD) { + return p.Cast(); + } + + // For small bit_sets assume they all fit in the space of the bit_set pointer. + return emp::Ptr((field_t*) &p); + } + /// Retrive the bit value from the specified index. bool Get(size_t index) const { emp_assert(index < num_bits, index, num_bits); const size_t field_id = FieldID(index); const size_t pos_id = FieldPos(index); - return (bit_set[field_id] & (static_cast(1) << pos_id)) != 0; + if (num_bits > SHORT_THRESHOLD) { + return (BitSetPtr()[field_id] & (static_cast(1) << pos_id)) != 0; + } + return (*BitSetPtr().Raw() & (static_cast(1) << pos_id)) != 0; } /// Update the bit value at the specified index. @@ -416,18 +525,27 @@ namespace emp { constexpr field_t val_one = 1; const field_t pos_mask = val_one << pos_id; - if (value) bit_set[field_id] |= pos_mask; - else bit_set[field_id] &= ~pos_mask; - + if (num_bits > SHORT_THRESHOLD) { + if (value) BitSetPtr()[field_id] |= pos_mask; + else BitSetPtr()[field_id] &= ~pos_mask; + } else { + if (value) *BitSetPtr().Raw() |= pos_mask; + else *BitSetPtr().Raw() &= ~pos_mask; + } + return *this; } /// A simple hash function for bit vectors. std::size_t Hash() const { std::size_t hash_val = 0; - const size_t NUM_FIELDS = NumFields(); - for (size_t i = 0; i < NUM_FIELDS; i++) { - hash_val ^= bit_set[i]; + if (num_bits > SHORT_THRESHOLD) { + const size_t NUM_FIELDS = NumFields(); + for (size_t i = 0; i < NUM_FIELDS; i++) { + hash_val ^= BitSetPtr()[i]; + } + } else { + hash_val ^= *BitSetPtr().Raw(); } return hash_val ^ ((97*num_bits) << 8); } @@ -435,25 +553,32 @@ namespace emp { /// Retrive the byte at the specified byte index. uint8_t GetByte(size_t index) const { emp_assert(index < NumBytes(), index, NumBytes()); - const size_t field_id = Byte2Field(index); const size_t pos_id = Byte2FieldPos(index); - return (bit_set[field_id] >> pos_id) & 255U; + if (num_bits > SHORT_THRESHOLD) { + const size_t field_id = Byte2Field(index); + return (BitSetPtr()[field_id] >> pos_id) & 255U; + } else { + return (*BitSetPtr().Raw() >> pos_id) & 255U; + } } /// Update the byte at the specified byte index. void SetByte(size_t index, uint8_t value) { emp_assert(index < NumBytes(), index, NumBytes()); - const size_t field_id = Byte2Field(index); const size_t pos_id = Byte2FieldPos(index); const field_t val_uint = value; - bit_set[field_id] = (bit_set[field_id] & ~(static_cast(255) << pos_id)) | (val_uint << pos_id); + if (num_bits > SHORT_THRESHOLD) { + const size_t field_id = Byte2Field(index); + BitSetPtr()[field_id] = (BitSetPtr()[field_id] & ~(static_cast(255) << pos_id)) | (val_uint << pos_id); + } else { + *BitSetPtr().Raw() = (*BitSetPtr().Raw() & ~(static_cast(255) << pos_id)) | (val_uint << pos_id); + } } - /// Retrieve the 32-bit uint from the specified uint index. - /* + /// Retrive the 32-bit uint from the specifeid uint index. uint32_t GetUInt(size_t index) const { // If the fields are already 32 bits, return. - if constexpr (sizeof(field_t) == 4) return bit_set[index]; + if constexpr (sizeof(field_t) == 4) return BitSetPtr()[index]; emp_assert(sizeof(field_t) == 8); @@ -462,60 +587,31 @@ namespace emp { emp_assert(field_id < NumFields()); - return (uint32_t) (bit_set[field_id] >> (field_pos * 32)); - } - */ - // Retrieve the 32-bit uint from the specified uint index. - // new implementation based on bitset.h GetUInt32 - uint32_t GetUInt(size_t index) const { - emp_assert(index * 32 < num_bits); - - uint32_t res; - - std::memcpy( - &res, - bit_set.Cast().Raw() + index * (32/8), - sizeof(res) - ); + if (num_bits > SHORT_THRESHOLD) { + return (uint32_t) (BitSetPtr()[field_id] >> (field_pos * 32)); + } else { + return (uint32_t) (*BitSetPtr().Raw() >> (field_pos * 32)); + } - return res; + } /// Update the 32-bit uint at the specified uint index. - void SetUInt(const size_t index, uint32_t value) { - emp_assert(index * 32 < num_bits); - - std::memcpy( - bit_set.Cast().Raw() + index * (32/8), - &value, - sizeof(value) - ); - - // check to make sure there are no leading ones in the unused bits - // or if LastBitID is 0 everything should pass too - emp_assert( - LastBitID() == 0 - || ( - bit_set[NumFields() - 1] - & ~MaskLow(LastBitID()) - ) == 0 - ); - - } - - void SetUIntAtBit(size_t index, uint32_t value) { - if constexpr (sizeof(field_t) == 4) bit_set[index] = value; - + void SetUInt(size_t index, uint32_t value) { + if constexpr (sizeof(field_t) == 4) BitSetPtr()[index] = value; emp_assert(sizeof(field_t) == 8); - - const size_t field_id = FieldID(index); - const size_t field_pos = FieldPos(index); + const size_t field_pos = 1 - (index & 1); const field_t mask = ((field_t) ((uint32_t) -1)) << (1-field_pos); - emp_assert(field_id < NumFields()); - - bit_set[field_id] &= mask; // Clear out bits that we are setting. - bit_set[field_id] |= ((field_t) value) << (field_pos * 32); + if (num_bits > SHORT_THRESHOLD) { + const size_t field_id = index/2; + emp_assert(field_id < NumFields()); + BitSetPtr()[field_id] &= mask; // Clear out bits that we are setting. + BitSetPtr()[field_id] |= ((field_t) value) << (field_pos * 32); + } else { + *BitSetPtr().Raw() &= mask; // Clear out bits that we are setting. + *BitSetPtr().Raw() |= ((field_t) value) << (field_pos * 32); + } } /// Retrive the 32-bit uint at the specified BIT index. @@ -524,11 +620,11 @@ namespace emp { // emp_assert(index < num_bits); const size_t field_id = FieldID(index); const size_t pos_id = FieldPos(index); - if (pos_id == 0) return (uint32_t) bit_set[field_id]; + if (pos_id == 0) return (uint32_t) BitSetPtr()[field_id]; const size_t NUM_FIELDS = NumFields(); - const uint32_t part1 = (uint32_t) (bit_set[field_id] >> pos_id); + const uint32_t part1 = (uint32_t) (BitSetPtr()[field_id] >> pos_id); const uint32_t part2 = - (uint32_t)((field_id+1 < NUM_FIELDS) ? bit_set[field_id+1] << (FIELD_BITS-pos_id) : 0); + (uint32_t)((field_id+1 < NUM_FIELDS) ? BitSetPtr()[field_id+1] << (FIELD_BITS-pos_id) : 0); return part1 | part2; } @@ -544,7 +640,11 @@ namespace emp { bool Any() const { const size_t NUM_FIELDS = NumFields(); for (size_t i = 0; i < NUM_FIELDS; i++) { - if (bit_set[i]) return true; + if (num_bits > SHORT_THRESHOLD) { + if (BitSetPtr()[i]) return true; + } else { + if (*BitSetPtr().Raw()) return true; + } } return false; } @@ -567,15 +667,30 @@ namespace emp { /// Set all bits to 0. void Clear() { const size_t NUM_FIELDS = NumFields(); - for (size_t i = 0; i < NUM_FIELDS; i++) bit_set[i] = 0U; + if (num_bits > SHORT_THRESHOLD) { + for (size_t i = 0; i < NUM_FIELDS; i++) BitSetPtr()[i] = 0U; + } else { + *BitSetPtr().Raw() = 0U; + } } /// Set all bits to 1. void SetAll() { const size_t NUM_FIELDS = NumFields(); constexpr field_t all0 = 0; - for (size_t i = 0; i < NUM_FIELDS; i++) bit_set[i] = ~all0; - if (LastBitID() > 0) { bit_set[NUM_FIELDS - 1] &= MaskLow(LastBitID()); } + if (num_bits > SHORT_THRESHOLD) { + for (size_t i = 0; i < NUM_FIELDS; i++) BitSetPtr()[i] = ~all0; + } else { + *BitSetPtr().Raw() = ~all0; + } + if (LastBitID() > 0) { + if (num_bits > SHORT_THRESHOLD) { + BitSetPtr()[NUM_FIELDS - 1] &= MaskLow(LastBitID()); + } else { + *BitSetPtr().Raw() &= MaskLow(LastBitID()); + } + + } } /// Regular print function (from most significant bit to least) @@ -606,8 +721,16 @@ namespace emp { size_t CountOnes_Sparse() const { const size_t NUM_FIELDS = NumFields(); size_t bit_count = 0; - for (size_t i = 0; i < NUM_FIELDS; i++) { - field_t cur_field = bit_set[i]; + if (num_bits > SHORT_THRESHOLD) { + for (size_t i = 0; i < NUM_FIELDS; i++) { + field_t cur_field = BitSetPtr()[i]; + while (cur_field) { + cur_field &= (cur_field-1); // Peel off a single 1. + bit_count++; // And increment the counter + } + } + } else { + field_t cur_field = *BitSetPtr().Raw(); while (cur_field) { cur_field &= (cur_field-1); // Peel off a single 1. bit_count++; // And increment the counter @@ -619,11 +742,17 @@ namespace emp { size_t CountOnes_Mixed() const { const field_t NUM_FIELDS = (1 + ((num_bits - 1) / FIELD_BITS)); size_t bit_count = 0; - for (size_t i = 0; i < NUM_FIELDS; i++) { + + if (num_bits > SHORT_THRESHOLD) { + for (size_t i = 0; i < NUM_FIELDS; i++) { // when compiling with -O3 and -msse4.2, this is the fastest population count method. - std::bitset std_bs(bit_set[i]); + std::bitset std_bs(BitSetPtr()[i]); bit_count += std_bs.count(); - } + } + } else { + std::bitset std_bs(*BitSetPtr().Raw()); + bit_count += std_bs.count(); + } return bit_count; } @@ -638,22 +767,35 @@ namespace emp { int FindBit() const { const size_t NUM_FIELDS = NumFields(); size_t field_id = 0; - while (field_id < NUM_FIELDS && bit_set[field_id]==0) field_id++; - return (field_id < NUM_FIELDS) ? - (int) (find_bit(bit_set[field_id]) + (field_id * FIELD_BITS)) : -1; + if (num_bits > SHORT_THRESHOLD) { + while (field_id < NUM_FIELDS && BitSetPtr()[field_id]==0) field_id++; + return (field_id < NUM_FIELDS) ? + (int) (find_bit(BitSetPtr()[field_id]) + (field_id * FIELD_BITS)) : -1; + } else { + return (field_id < NUM_FIELDS) ? + (int) (find_bit(*BitSetPtr().Raw()) + (field_id * FIELD_BITS)) : -1; + } + } /// Return the position of the first one and change it to a zero. Return -1 if no ones. int PopBit() { const size_t NUM_FIELDS = NumFields(); size_t field_id = 0; - while (field_id < NUM_FIELDS && bit_set[field_id]==0) field_id++; - if (field_id == NUM_FIELDS) return -1; // Failed to find bit! - - const size_t pos_found = find_bit(bit_set[field_id]); - constexpr field_t val_one = 1; - bit_set[field_id] &= ~(val_one << pos_found); - return (int) (pos_found + (field_id * FIELD_BITS)); + if (num_bits > SHORT_THRESHOLD) { + while (field_id < NUM_FIELDS && BitSetPtr()[field_id]==0) field_id++; + if (field_id == NUM_FIELDS) return -1; // Failed to find bit! + + const size_t pos_found = find_bit(BitSetPtr()[field_id]); + constexpr field_t val_one = 1; + BitSetPtr()[field_id] &= ~(val_one << pos_found); + return (int) (pos_found + (field_id * FIELD_BITS)); + } else { + const size_t pos_found = find_bit(*BitSetPtr().Raw()); + constexpr field_t val_one = 1; + *BitSetPtr().Raw() &= ~(val_one << pos_found); + return (int) (pos_found + (field_id * FIELD_BITS)); + } } /// Return the position of the first one after start_pos; return -1 if no ones in vector. @@ -665,17 +807,35 @@ namespace emp { if (start_pos >= num_bits) return -1; size_t field_id = FieldID(start_pos); // What field do we start in? const size_t field_pos = FieldPos(start_pos); // What position in that field? - if (field_pos && (bit_set[field_id] & ~(MaskLow(field_pos)))) { // First field hit! - return (int) (find_bit(bit_set[field_id] & ~(MaskLow(field_pos))) + + + + + + + if (num_bits > SHORT_THRESHOLD) { + if (field_pos && (BitSetPtr()[field_id] & ~(MaskLow(field_pos)))) { // First field hit! + return (int) (find_bit(BitSetPtr()[field_id] & ~(MaskLow(field_pos))) + field_id * FIELD_BITS); - } + } - // Search other fields... - const size_t NUM_FIELDS = NumFields(); - if (field_pos) field_id++; - while (field_id < NUM_FIELDS && bit_set[field_id]==0) field_id++; - return (field_id < NUM_FIELDS) ? - (int) (find_bit(bit_set[field_id]) + (field_id * FIELD_BITS)) : -1; + // Search other fields... + const size_t NUM_FIELDS = NumFields(); + if (field_pos) field_id++; + while (field_id < NUM_FIELDS && BitSetPtr()[field_id]==0) field_id++; + return (field_id < NUM_FIELDS) ? + (int) (find_bit(BitSetPtr()[field_id]) + (field_id * FIELD_BITS)) : -1; + } else { + if (field_pos && (*BitSetPtr().Raw() & ~(MaskLow(field_pos)))) { // First field hit! + return (int) (find_bit(*BitSetPtr().Raw() & ~(MaskLow(field_pos))) + + field_id * FIELD_BITS); + } + + // Search other fields... + const size_t NUM_FIELDS = NumFields(); + if (field_pos) field_id++; + return (field_id < NUM_FIELDS) ? + (int) (find_bit(*BitSetPtr().Raw()) + (field_id * FIELD_BITS)) : -1; + } } /// Return positions of all ones. @@ -693,8 +853,12 @@ namespace emp { BitVector NOT() const { const size_t NUM_FIELDS = NumFields(); BitVector out_set(*this); - for (size_t i = 0; i < NUM_FIELDS; i++) out_set.bit_set[i] = ~bit_set[i]; - if (LastBitID() > 0) out_set.bit_set[NUM_FIELDS - 1] &= MaskLow(LastBitID()); + if (num_bits > SHORT_THRESHOLD) { + for (size_t i = 0; i < NUM_FIELDS; i++) out_set.BitSetPtr()[i] = ~BitSetPtr()[i]; + if (LastBitID() > 0) out_set.BitSetPtr()[NUM_FIELDS - 1] &= MaskLow(LastBitID()); + } else { + *(out_set.BitSetPtr().Raw()) = ~(*(BitSetPtr().Raw())); + } return out_set; } @@ -702,7 +866,11 @@ namespace emp { BitVector AND(const BitVector & set2) const { const size_t NUM_FIELDS = NumFields(); BitVector out_set(*this); - for (size_t i = 0; i < NUM_FIELDS; i++) out_set.bit_set[i] = bit_set[i] & set2.bit_set[i]; + if (num_bits > SHORT_THRESHOLD) { + for (size_t i = 0; i < NUM_FIELDS; i++) out_set.BitSetPtr()[i] = BitSetPtr()[i] & set2.BitSetPtr()[i]; + } else { + *(out_set.BitSetPtr().Raw()) = *BitSetPtr().Raw() & *(set2.BitSetPtr().Raw()); + } return out_set; } @@ -710,7 +878,11 @@ namespace emp { BitVector OR(const BitVector & set2) const { const size_t NUM_FIELDS = NumFields(); BitVector out_set(*this); - for (size_t i = 0; i < NUM_FIELDS; i++) out_set.bit_set[i] = bit_set[i] | set2.bit_set[i]; + if (num_bits > SHORT_THRESHOLD) { + for (size_t i = 0; i < NUM_FIELDS; i++) out_set.BitSetPtr()[i] = BitSetPtr()[i] | set2.BitSetPtr()[i]; + } else { + *(out_set.BitSetPtr().Raw()) = *BitSetPtr().Raw() | *set2.BitSetPtr().Raw(); + } return out_set; } @@ -718,8 +890,12 @@ namespace emp { BitVector NAND(const BitVector & set2) const { const size_t NUM_FIELDS = NumFields(); BitVector out_set(*this); - for (size_t i = 0; i < NUM_FIELDS; i++) out_set.bit_set[i] = ~(bit_set[i] & set2.bit_set[i]); - if (LastBitID() > 0) out_set.bit_set[NUM_FIELDS - 1] &= MaskLow(LastBitID()); + if (num_bits > SHORT_THRESHOLD) { + for (size_t i = 0; i < NUM_FIELDS; i++) out_set.BitSetPtr()[i] = ~(BitSetPtr()[i] & set2.BitSetPtr()[i]); + if (LastBitID() > 0) out_set.BitSetPtr()[NUM_FIELDS - 1] &= MaskLow(LastBitID()); + } else { + *(out_set.BitSetPtr().Raw()) = ~(*BitSetPtr().Raw() & *set2.BitSetPtr().Raw()); + } return out_set; } @@ -727,8 +903,12 @@ namespace emp { BitVector NOR(const BitVector & set2) const { const size_t NUM_FIELDS = NumFields(); BitVector out_set(*this); - for (size_t i = 0; i < NUM_FIELDS; i++) out_set.bit_set[i] = ~(bit_set[i] | set2.bit_set[i]); - if (LastBitID() > 0) out_set.bit_set[NUM_FIELDS - 1] &= MaskLow(LastBitID()); + if (num_bits > SHORT_THRESHOLD) { + for (size_t i = 0; i < NUM_FIELDS; i++) out_set.BitSetPtr()[i] = ~(BitSetPtr()[i] | set2.BitSetPtr()[i]); + if (LastBitID() > 0) out_set.BitSetPtr()[NUM_FIELDS - 1] &= MaskLow(LastBitID()); + } else { + *(out_set.BitSetPtr().Raw()) = ~(*BitSetPtr().Raw() | *set2.BitSetPtr().Raw()); + } return out_set; } @@ -736,7 +916,11 @@ namespace emp { BitVector XOR(const BitVector & set2) const { const size_t NUM_FIELDS = NumFields(); BitVector out_set(*this); - for (size_t i = 0; i < NUM_FIELDS; i++) out_set.bit_set[i] = bit_set[i] ^ set2.bit_set[i]; + if (num_bits > SHORT_THRESHOLD) { + for (size_t i = 0; i < NUM_FIELDS; i++) out_set.BitSetPtr()[i] = BitSetPtr()[i] ^ set2.BitSetPtr()[i]; + }else { + *(out_set.BitSetPtr().Raw()) = *BitSetPtr().Raw() ^ *set2.BitSetPtr().Raw(); + } return out_set; } @@ -744,8 +928,12 @@ namespace emp { BitVector EQU(const BitVector & set2) const { const size_t NUM_FIELDS = NumFields(); BitVector out_set(*this); - for (size_t i = 0; i < NUM_FIELDS; i++) out_set.bit_set[i] = ~(bit_set[i] ^ set2.bit_set[i]); - if (LastBitID() > 0) out_set.bit_set[NUM_FIELDS - 1] &= MaskLow(LastBitID()); + if (num_bits > SHORT_THRESHOLD) { + for (size_t i = 0; i < NUM_FIELDS; i++) out_set.BitSetPtr()[i] = ~(BitSetPtr()[i] ^ set2.BitSetPtr()[i]); + if (LastBitID() > 0) out_set.BitSetPtr()[NUM_FIELDS - 1] &= MaskLow(LastBitID()); + } else { + *(out_set.BitSetPtr().Raw()) = ~(*BitSetPtr().Raw() ^ *set2.BitSetPtr().Raw()); + } return out_set; } @@ -753,53 +941,81 @@ namespace emp { /// Perform a Boolean NOT with this BitVector, store result here, and return this object. BitVector & NOT_SELF() { const size_t NUM_FIELDS = NumFields(); - for (size_t i = 0; i < NUM_FIELDS; i++) bit_set[i] = ~bit_set[i]; - if (LastBitID() > 0) bit_set[NUM_FIELDS - 1] &= MaskLow(LastBitID()); + if (num_bits > SHORT_THRESHOLD) { + for (size_t i = 0; i < NUM_FIELDS; i++) BitSetPtr()[i] = ~BitSetPtr()[i]; + if (LastBitID() > 0) BitSetPtr()[NUM_FIELDS - 1] &= MaskLow(LastBitID()); + } else { + *BitSetPtr().Raw() = ~*BitSetPtr().Raw(); + } return *this; } /// Perform a Boolean AND with this BitVector, store result here, and return this object. BitVector & AND_SELF(const BitVector & set2) { const size_t NUM_FIELDS = NumFields(); - for (size_t i = 0; i < NUM_FIELDS; i++) bit_set[i] = bit_set[i] & set2.bit_set[i]; + if (num_bits > SHORT_THRESHOLD) { + for (size_t i = 0; i < NUM_FIELDS; i++) BitSetPtr()[i] = BitSetPtr()[i] & set2.BitSetPtr()[i]; + } else { + *BitSetPtr().Raw() = *BitSetPtr().Raw() & *set2.BitSetPtr().Raw(); + } return *this; } /// Perform a Boolean OR with this BitVector, store result here, and return this object. BitVector & OR_SELF(const BitVector & set2) { const size_t NUM_FIELDS = NumFields(); - for (size_t i = 0; i < NUM_FIELDS; i++) bit_set[i] = bit_set[i] | set2.bit_set[i]; + if (num_bits > SHORT_THRESHOLD) { + for (size_t i = 0; i < NUM_FIELDS; i++) BitSetPtr()[i] = BitSetPtr()[i] | set2.BitSetPtr()[i]; + } else { + *BitSetPtr().Raw() = *BitSetPtr().Raw() | *set2.BitSetPtr().Raw(); + } return *this; } /// Perform a Boolean NAND with this BitVector, store result here, and return this object. BitVector & NAND_SELF(const BitVector & set2) { const size_t NUM_FIELDS = NumFields(); - for (size_t i = 0; i < NUM_FIELDS; i++) bit_set[i] = ~(bit_set[i] & set2.bit_set[i]); - if (LastBitID() > 0) bit_set[NUM_FIELDS - 1] &= MaskLow(LastBitID()); + if (num_bits > SHORT_THRESHOLD) { + for (size_t i = 0; i < NUM_FIELDS; i++) BitSetPtr()[i] = ~(BitSetPtr()[i] & set2.BitSetPtr()[i]); + if (LastBitID() > 0) BitSetPtr()[NUM_FIELDS - 1] &= MaskLow(LastBitID()); + } else { + *BitSetPtr().Raw() = ~(*BitSetPtr().Raw() & *set2.BitSetPtr().Raw()); + } return *this; } /// Perform a Boolean NOR with this BitVector, store result here, and return this object. BitVector & NOR_SELF(const BitVector & set2) { const size_t NUM_FIELDS = NumFields(); - for (size_t i = 0; i < NUM_FIELDS; i++) bit_set[i] = ~(bit_set[i] | set2.bit_set[i]); - if (LastBitID() > 0) bit_set[NUM_FIELDS - 1] &= MaskLow(LastBitID()); + if (num_bits > SHORT_THRESHOLD) { + for (size_t i = 0; i < NUM_FIELDS; i++) BitSetPtr()[i] = ~(BitSetPtr()[i] | set2.BitSetPtr()[i]); + if (LastBitID() > 0) BitSetPtr()[NUM_FIELDS - 1] &= MaskLow(LastBitID()); + } else { + *BitSetPtr().Raw() = ~(*BitSetPtr().Raw() | *set2.BitSetPtr().Raw()); + } return *this; } /// Perform a Boolean XOR with this BitVector, store result here, and return this object. BitVector & XOR_SELF(const BitVector & set2) { const size_t NUM_FIELDS = NumFields(); - for (size_t i = 0; i < NUM_FIELDS; i++) bit_set[i] = bit_set[i] ^ set2.bit_set[i]; + if (num_bits > SHORT_THRESHOLD) { + for (size_t i = 0; i < NUM_FIELDS; i++) BitSetPtr()[i] = BitSetPtr()[i] ^ set2.BitSetPtr()[i]; + } else { + *BitSetPtr().Raw() = *BitSetPtr().Raw() ^ *set2.BitSetPtr().Raw(); + } return *this; } /// Perform a Boolean EQU with this BitVector, store result here, and return this object. BitVector & EQU_SELF(const BitVector & set2) { const size_t NUM_FIELDS = NumFields(); - for (size_t i = 0; i < NUM_FIELDS; i++) bit_set[i] = ~(bit_set[i] ^ set2.bit_set[i]); - if (LastBitID() > 0) bit_set[NUM_FIELDS - 1] &= MaskLow(LastBitID()); + if (num_bits > SHORT_THRESHOLD) { + for (size_t i = 0; i < NUM_FIELDS; i++) BitSetPtr()[i] = ~(BitSetPtr()[i] ^ set2.BitSetPtr()[i]); + if (LastBitID() > 0) BitSetPtr()[NUM_FIELDS - 1] &= MaskLow(LastBitID()); + } else { + *BitSetPtr().Raw() = ~(*BitSetPtr().Raw() ^ *set2.BitSetPtr().Raw()); + } return *this; } From 6a09899b12284ffbb4c5313b206f59607c1276bb Mon Sep 17 00:00:00 2001 From: schmi710 <55195426+schmi710@users.noreply.github.com> Date: Fri, 26 Jun 2020 18:59:28 -0400 Subject: [PATCH 2/9] Short BitVector Optimizations I hope I didn't mess anything up. From ae9689e299235474b102e9c5fda62337bb93d897 Mon Sep 17 00:00:00 2001 From: schmi710 <55195426+schmi710@users.noreply.github.com> Date: Sat, 4 Jul 2020 14:18:48 -0400 Subject: [PATCH 3/9] Bug Fix hopefully --- source/tools/BitVector.h | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/source/tools/BitVector.h b/source/tools/BitVector.h index 1aa1d45608..f47a95db6a 100644 --- a/source/tools/BitVector.h +++ b/source/tools/BitVector.h @@ -164,10 +164,12 @@ namespace emp { /// being copied and only the fields need to be copied over. void RawCopy(Ptr in_set) { #ifdef EMP_TRACK_MEM - emp_assert(in_set.IsNull() == false); - emp_assert(BitSetPtr().DebugIsArray() && in_set.DebugIsArray()); - emp_assert(BitSetPtr().DebugGetArrayBytes() == in_set.DebugGetArrayBytes(), - BitSetPtr().DebugGetArrayBytes(), in_set.DebugGetArrayBytes()); + if (num_bits > SHORT_THRESHOLD) { + emp_assert(in_set.IsNull() == false); + emp_assert(BitSetPtr().DebugIsArray() && in_set.DebugIsArray()); + emp_assert(BitSetPtr().DebugGetArrayBytes() == in_set.DebugGetArrayBytes(), + BitSetPtr().DebugGetArrayBytes(), in_set.DebugGetArrayBytes()); + } #endif const size_t NUM_FIELDS = NumFields(); @@ -407,7 +409,9 @@ namespace emp { } else { bit_set = old_bit_set; } - for (size_t i = min_fields; i < NUM_FIELDS; i++) bit_set[i] = std::byte(0); + std::cout << *BitSetPtr().Raw() << std::endl; + std::cout << (0xFFFFFFFFFFFFFFFF >> (SHORT_THRESHOLD - num_bits)) << std::endl; + *BitSetPtr().Raw() = *BitSetPtr().Raw() & (0xFFFFFFFFFFFFFFFF >> (SHORT_THRESHOLD - num_bits)); } if (old_bit_set && old_num_bits > SHORT_THRESHOLD) BitSetPtr(old_bit_set, old_num_bits).DeleteArray(); @@ -618,14 +622,20 @@ namespace emp { uint32_t GetUIntAtBit(size_t index) { // @CAO Need proper assert for non-32-size bit fields! // emp_assert(index < num_bits); - const size_t field_id = FieldID(index); - const size_t pos_id = FieldPos(index); - if (pos_id == 0) return (uint32_t) BitSetPtr()[field_id]; - const size_t NUM_FIELDS = NumFields(); - const uint32_t part1 = (uint32_t) (BitSetPtr()[field_id] >> pos_id); - const uint32_t part2 = - (uint32_t)((field_id+1 < NUM_FIELDS) ? BitSetPtr()[field_id+1] << (FIELD_BITS-pos_id) : 0); - return part1 | part2; + if (num_bits > SHORT_THRESHOLD) { + const size_t field_id = FieldID(index); + const size_t pos_id = FieldPos(index); + if (pos_id == 0) return (uint32_t) BitSetPtr()[field_id]; + const size_t NUM_FIELDS = NumFields(); + const uint32_t part1 = (uint32_t) (BitSetPtr()[field_id] >> pos_id); + const uint32_t part2 = + (uint32_t)((field_id+1 < NUM_FIELDS) ? BitSetPtr()[field_id+1] << (FIELD_BITS-pos_id) : 0); + return part1 | part2; + } + if (index == 0) { + return (uint32_t) *BitSetPtr().Raw() & 0xFFFFFFFF; + } + return (uint32_t) (*BitSetPtr().Raw() >> 32) & 0xFFFFFFFF; } /// Retrieve the specified number of bits (stored in the field type) at the target bit index. From 8dd82f14fc83852645d92e62a657b29cbf5d9ade Mon Sep 17 00:00:00 2001 From: schmi710 <55195426+schmi710@users.noreply.github.com> Date: Sat, 4 Jul 2020 14:54:52 -0400 Subject: [PATCH 4/9] Bug Fix --- source/tools/BitVector.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/source/tools/BitVector.h b/source/tools/BitVector.h index f47a95db6a..14f5751e7d 100644 --- a/source/tools/BitVector.h +++ b/source/tools/BitVector.h @@ -618,6 +618,31 @@ namespace emp { } } + void SetUIntAtBit(size_t index, uint32_t value) { + if (num_bits > SHORT_THRESHOLD) { + if constexpr (sizeof(field_t) == 4) BitSetPtr()[index] = value; + + emp_assert(sizeof(field_t) == 8); + + const size_t field_id = FieldID(index); + const size_t field_pos = FieldPos(index); + const field_t mask = ((field_t) ((uint32_t) -1)) << (1-field_pos); + + emp_assert(field_id < NumFields()); + + BitSetPtr()[field_id] &= mask; // Clear out bits that we are setting. + BitSetPtr()[field_id] |= ((field_t) value) << (field_pos * 32); + } else { + if (index == 0) { + *BitSetPtr().Raw() &= 0xFFFFFFFF00000000; + *BitSetPtr().Raw() += (field_t) value; + } else { + *BitSetPtr().Raw() &= 0x00000000FFFFFFFF; + *BitSetPtr().Raw() += ( ((field_t) value) << 32); + } + } + } + /// Retrive the 32-bit uint at the specified BIT index. uint32_t GetUIntAtBit(size_t index) { // @CAO Need proper assert for non-32-size bit fields! From d108180479879fd40b175af82fdc0ec88868edd0 Mon Sep 17 00:00:00 2001 From: schmi710 <55195426+schmi710@users.noreply.github.com> Date: Sat, 4 Jul 2020 15:38:08 -0400 Subject: [PATCH 5/9] Bug Fixes --- source/tools/BitVector.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/source/tools/BitVector.h b/source/tools/BitVector.h index 14f5751e7d..e2dbf6bb47 100644 --- a/source/tools/BitVector.h +++ b/source/tools/BitVector.h @@ -688,7 +688,17 @@ namespace emp { bool None() const { return !Any(); } /// Return true if ALL bits are set to 1, otherwise return false. - bool All() const { return (~(*this)).None(); } + bool All() const { + const size_t NUM_FIELDS = NumFields(); + for (size_t i = 0; i < NUM_FIELDS; i++) { + if (num_bits > SHORT_THRESHOLD) { + if (~(BitSetPtr()[i])) return false; + } else { + if (~(*BitSetPtr().Raw())) return false; + } + } + return true; + } /// Casting a bit array to bool identifies if ANY bits are set to 1. explicit operator bool() const { return Any(); } From 4f7e6997d5f2d0e46ece8628250418c6e3118139 Mon Sep 17 00:00:00 2001 From: schmi710 <55195426+schmi710@users.noreply.github.com> Date: Sat, 4 Jul 2020 17:26:29 -0400 Subject: [PATCH 6/9] Major Bug Fixes Fixed the masking for bit operations that was causing bits to appear outside the "official" BitVector bits for short BitVectors. --- source/tools/BitVector.h | 72 ++++++++++++++++++++++++++++------------ 1 file changed, 50 insertions(+), 22 deletions(-) diff --git a/source/tools/BitVector.h b/source/tools/BitVector.h index e2dbf6bb47..611424ff4e 100644 --- a/source/tools/BitVector.h +++ b/source/tools/BitVector.h @@ -409,15 +409,17 @@ namespace emp { } else { bit_set = old_bit_set; } - std::cout << *BitSetPtr().Raw() << std::endl; - std::cout << (0xFFFFFFFFFFFFFFFF >> (SHORT_THRESHOLD - num_bits)) << std::endl; - *BitSetPtr().Raw() = *BitSetPtr().Raw() & (0xFFFFFFFFFFFFFFFF >> (SHORT_THRESHOLD - num_bits)); + } if (old_bit_set && old_num_bits > SHORT_THRESHOLD) BitSetPtr(old_bit_set, old_num_bits).DeleteArray(); } + + if (num_bits <= SHORT_THRESHOLD) { + *BitSetPtr().Raw() &= (0xFFFFFFFFFFFFFFFF >> (SHORT_THRESHOLD - num_bits)); + } return *this; } @@ -594,27 +596,31 @@ namespace emp { if (num_bits > SHORT_THRESHOLD) { return (uint32_t) (BitSetPtr()[field_id] >> (field_pos * 32)); } else { - return (uint32_t) (*BitSetPtr().Raw() >> (field_pos * 32)); + return (uint32_t) (*BitSetPtr().Raw() >> (index * 32)); } - } /// Update the 32-bit uint at the specified uint index. void SetUInt(size_t index, uint32_t value) { - if constexpr (sizeof(field_t) == 4) BitSetPtr()[index] = value; + //if constexpr (sizeof(field_t) == 4) BitSetPtr()[index] = value; emp_assert(sizeof(field_t) == 8); - const size_t field_pos = 1 - (index & 1); - const field_t mask = ((field_t) ((uint32_t) -1)) << (1-field_pos); - + if (num_bits > SHORT_THRESHOLD) { + const size_t field_pos = 1 - (index & 1); + const field_t mask = ((field_t) ((uint32_t) -1)) << (1-field_pos); const size_t field_id = index/2; emp_assert(field_id < NumFields()); BitSetPtr()[field_id] &= mask; // Clear out bits that we are setting. BitSetPtr()[field_id] |= ((field_t) value) << (field_pos * 32); } else { - *BitSetPtr().Raw() &= mask; // Clear out bits that we are setting. - *BitSetPtr().Raw() |= ((field_t) value) << (field_pos * 32); + if (num_bits < 32) { + emp_assert(value == (value & (0xFFFFFFFF >> (32 - num_bits)))); + } else { + emp_assert(value == (value & (0xFFFFFFFF >> (64 - num_bits)))); + } + *BitSetPtr().Raw() &= (0x00000000FFFFFFFF << (32 * (1-index))); // Clear out bits that we are setting. + *BitSetPtr().Raw() |= ((field_t) value) << (index * 32); } } @@ -660,7 +666,7 @@ namespace emp { if (index == 0) { return (uint32_t) *BitSetPtr().Raw() & 0xFFFFFFFF; } - return (uint32_t) (*BitSetPtr().Raw() >> 32) & 0xFFFFFFFF; + return (uint32_t) (*BitSetPtr().Raw() >> 32) ; } /// Retrieve the specified number of bits (stored in the field type) at the target bit index. @@ -674,12 +680,12 @@ namespace emp { /// Return true if ANY bits are set to 1, otherwise return false. bool Any() const { const size_t NUM_FIELDS = NumFields(); - for (size_t i = 0; i < NUM_FIELDS; i++) { - if (num_bits > SHORT_THRESHOLD) { + if (num_bits > SHORT_THRESHOLD) { + for (size_t i = 0; i < NUM_FIELDS; i++) { if (BitSetPtr()[i]) return true; - } else { - if (*BitSetPtr().Raw()) return true; - } + } + } else { + if (*BitSetPtr().Raw()) return true; } return false; } @@ -690,12 +696,12 @@ namespace emp { /// Return true if ALL bits are set to 1, otherwise return false. bool All() const { const size_t NUM_FIELDS = NumFields(); - for (size_t i = 0; i < NUM_FIELDS; i++) { - if (num_bits > SHORT_THRESHOLD) { + if (num_bits > SHORT_THRESHOLD) { + for (size_t i = 0; i < NUM_FIELDS; i++) { if (~(BitSetPtr()[i])) return false; - } else { - if (~(*BitSetPtr().Raw())) return false; } + } else { + if (~(*BitSetPtr().Raw() | (0xFFFFFFFFFFFFFFFF << num_bits))) return false; } return true; } @@ -732,7 +738,7 @@ namespace emp { if (num_bits > SHORT_THRESHOLD) { BitSetPtr()[NUM_FIELDS - 1] &= MaskLow(LastBitID()); } else { - *BitSetPtr().Raw() &= MaskLow(LastBitID()); + *BitSetPtr().Raw() |= (0xFFFFFFFFFFFFFFFF >> (64 - num_bits)); } } @@ -817,6 +823,7 @@ namespace emp { return (field_id < NUM_FIELDS) ? (int) (find_bit(BitSetPtr()[field_id]) + (field_id * FIELD_BITS)) : -1; } else { + if (field_id < NUM_FIELDS && *BitSetPtr().Raw()==0) field_id++; return (field_id < NUM_FIELDS) ? (int) (find_bit(*BitSetPtr().Raw()) + (field_id * FIELD_BITS)) : -1; } @@ -836,6 +843,9 @@ namespace emp { BitSetPtr()[field_id] &= ~(val_one << pos_found); return (int) (pos_found + (field_id * FIELD_BITS)); } else { + if (field_id < NUM_FIELDS && *BitSetPtr().Raw()==0) field_id++; + if (field_id == NUM_FIELDS) return -1; // Failed to find bit! + const size_t pos_found = find_bit(*BitSetPtr().Raw()); constexpr field_t val_one = 1; *BitSetPtr().Raw() &= ~(val_one << pos_found); @@ -903,6 +913,8 @@ namespace emp { if (LastBitID() > 0) out_set.BitSetPtr()[NUM_FIELDS - 1] &= MaskLow(LastBitID()); } else { *(out_set.BitSetPtr().Raw()) = ~(*(BitSetPtr().Raw())); + if (num_bits <= SHORT_THRESHOLD) *out_set.BitSetPtr().Raw() &= (0xFFFFFFFFFFFFFFFF >> (SHORT_THRESHOLD - num_bits)); + } return out_set; } @@ -915,6 +927,7 @@ namespace emp { for (size_t i = 0; i < NUM_FIELDS; i++) out_set.BitSetPtr()[i] = BitSetPtr()[i] & set2.BitSetPtr()[i]; } else { *(out_set.BitSetPtr().Raw()) = *BitSetPtr().Raw() & *(set2.BitSetPtr().Raw()); + if (num_bits <= SHORT_THRESHOLD) *out_set.BitSetPtr().Raw() &= (0xFFFFFFFFFFFFFFFF >> (SHORT_THRESHOLD - num_bits)); } return out_set; } @@ -927,6 +940,7 @@ namespace emp { for (size_t i = 0; i < NUM_FIELDS; i++) out_set.BitSetPtr()[i] = BitSetPtr()[i] | set2.BitSetPtr()[i]; } else { *(out_set.BitSetPtr().Raw()) = *BitSetPtr().Raw() | *set2.BitSetPtr().Raw(); + if (num_bits <= SHORT_THRESHOLD) *out_set.BitSetPtr().Raw() &= (0xFFFFFFFFFFFFFFFF >> (SHORT_THRESHOLD - num_bits)); } return out_set; } @@ -940,6 +954,7 @@ namespace emp { if (LastBitID() > 0) out_set.BitSetPtr()[NUM_FIELDS - 1] &= MaskLow(LastBitID()); } else { *(out_set.BitSetPtr().Raw()) = ~(*BitSetPtr().Raw() & *set2.BitSetPtr().Raw()); + if (num_bits <= SHORT_THRESHOLD) *out_set.BitSetPtr().Raw() &= (0xFFFFFFFFFFFFFFFF >> (SHORT_THRESHOLD - num_bits)); } return out_set; } @@ -953,6 +968,7 @@ namespace emp { if (LastBitID() > 0) out_set.BitSetPtr()[NUM_FIELDS - 1] &= MaskLow(LastBitID()); } else { *(out_set.BitSetPtr().Raw()) = ~(*BitSetPtr().Raw() | *set2.BitSetPtr().Raw()); + if (num_bits <= SHORT_THRESHOLD) *out_set.BitSetPtr().Raw() &= (0xFFFFFFFFFFFFFFFF >> (SHORT_THRESHOLD - num_bits)); } return out_set; } @@ -965,6 +981,7 @@ namespace emp { for (size_t i = 0; i < NUM_FIELDS; i++) out_set.BitSetPtr()[i] = BitSetPtr()[i] ^ set2.BitSetPtr()[i]; }else { *(out_set.BitSetPtr().Raw()) = *BitSetPtr().Raw() ^ *set2.BitSetPtr().Raw(); + if (num_bits <= SHORT_THRESHOLD) *out_set.BitSetPtr().Raw() &= (0xFFFFFFFFFFFFFFFF >> (SHORT_THRESHOLD - num_bits)); } return out_set; } @@ -978,6 +995,7 @@ namespace emp { if (LastBitID() > 0) out_set.BitSetPtr()[NUM_FIELDS - 1] &= MaskLow(LastBitID()); } else { *(out_set.BitSetPtr().Raw()) = ~(*BitSetPtr().Raw() ^ *set2.BitSetPtr().Raw()); + if (num_bits <= SHORT_THRESHOLD) *out_set.BitSetPtr().Raw() &= (0xFFFFFFFFFFFFFFFF >> (SHORT_THRESHOLD - out_set.GetSize())); } return out_set; } @@ -991,6 +1009,7 @@ namespace emp { if (LastBitID() > 0) BitSetPtr()[NUM_FIELDS - 1] &= MaskLow(LastBitID()); } else { *BitSetPtr().Raw() = ~*BitSetPtr().Raw(); + if (num_bits <= SHORT_THRESHOLD) *BitSetPtr().Raw() &= (0xFFFFFFFFFFFFFFFF >> (SHORT_THRESHOLD - num_bits)); } return *this; } @@ -1002,6 +1021,7 @@ namespace emp { for (size_t i = 0; i < NUM_FIELDS; i++) BitSetPtr()[i] = BitSetPtr()[i] & set2.BitSetPtr()[i]; } else { *BitSetPtr().Raw() = *BitSetPtr().Raw() & *set2.BitSetPtr().Raw(); + if (num_bits <= SHORT_THRESHOLD) *BitSetPtr().Raw() &= (0xFFFFFFFFFFFFFFFF >> (SHORT_THRESHOLD - num_bits)); } return *this; } @@ -1013,6 +1033,7 @@ namespace emp { for (size_t i = 0; i < NUM_FIELDS; i++) BitSetPtr()[i] = BitSetPtr()[i] | set2.BitSetPtr()[i]; } else { *BitSetPtr().Raw() = *BitSetPtr().Raw() | *set2.BitSetPtr().Raw(); + if (num_bits <= SHORT_THRESHOLD) *BitSetPtr().Raw() &= (0xFFFFFFFFFFFFFFFF >> (SHORT_THRESHOLD - num_bits)); } return *this; } @@ -1025,6 +1046,7 @@ namespace emp { if (LastBitID() > 0) BitSetPtr()[NUM_FIELDS - 1] &= MaskLow(LastBitID()); } else { *BitSetPtr().Raw() = ~(*BitSetPtr().Raw() & *set2.BitSetPtr().Raw()); + if (num_bits <= SHORT_THRESHOLD) *BitSetPtr().Raw() &= (0xFFFFFFFFFFFFFFFF >> (SHORT_THRESHOLD - num_bits)); } return *this; } @@ -1037,6 +1059,7 @@ namespace emp { if (LastBitID() > 0) BitSetPtr()[NUM_FIELDS - 1] &= MaskLow(LastBitID()); } else { *BitSetPtr().Raw() = ~(*BitSetPtr().Raw() | *set2.BitSetPtr().Raw()); + if (num_bits <= SHORT_THRESHOLD) *BitSetPtr().Raw() &= (0xFFFFFFFFFFFFFFFF >> (SHORT_THRESHOLD - num_bits)); } return *this; } @@ -1048,6 +1071,7 @@ namespace emp { for (size_t i = 0; i < NUM_FIELDS; i++) BitSetPtr()[i] = BitSetPtr()[i] ^ set2.BitSetPtr()[i]; } else { *BitSetPtr().Raw() = *BitSetPtr().Raw() ^ *set2.BitSetPtr().Raw(); + if (num_bits <= SHORT_THRESHOLD) *BitSetPtr().Raw() &= (0xFFFFFFFFFFFFFFFF >> (SHORT_THRESHOLD - num_bits)); } return *this; } @@ -1060,6 +1084,8 @@ namespace emp { if (LastBitID() > 0) BitSetPtr()[NUM_FIELDS - 1] &= MaskLow(LastBitID()); } else { *BitSetPtr().Raw() = ~(*BitSetPtr().Raw() ^ *set2.BitSetPtr().Raw()); + if (num_bits <= SHORT_THRESHOLD) *BitSetPtr().Raw() &= (0xFFFFFFFFFFFFFFFF >> (SHORT_THRESHOLD - num_bits)); + } return *this; } @@ -1069,6 +1095,7 @@ namespace emp { BitVector out_set(*this); if (shift_size > 0) out_set.ShiftRight((size_t) shift_size); else if (shift_size < 0) out_set.ShiftLeft((size_t) -shift_size); + if (num_bits <= SHORT_THRESHOLD) *out_set.BitSetPtr().Raw() &= (0xFFFFFFFFFFFFFFFF >> (SHORT_THRESHOLD - num_bits)); return out_set; } @@ -1076,6 +1103,7 @@ namespace emp { BitVector & SHIFT_SELF(const int shift_size) { if (shift_size > 0) ShiftRight((size_t) shift_size); else if (shift_size < 0) ShiftLeft((size_t) -shift_size); + if (num_bits <= SHORT_THRESHOLD) *BitSetPtr().Raw() &= (0xFFFFFFFFFFFFFFFF >> (SHORT_THRESHOLD - num_bits)); return *this; } From c6a1962fad4d90ab45167745c8afaab92e360fc9 Mon Sep 17 00:00:00 2001 From: schmi710 <55195426+schmi710@users.noreply.github.com> Date: Sat, 4 Jul 2020 18:42:20 -0400 Subject: [PATCH 7/9] Mask fix --- source/tools/BitVector.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/source/tools/BitVector.h b/source/tools/BitVector.h index 611424ff4e..705ef7e723 100644 --- a/source/tools/BitVector.h +++ b/source/tools/BitVector.h @@ -732,13 +732,11 @@ namespace emp { if (num_bits > SHORT_THRESHOLD) { for (size_t i = 0; i < NUM_FIELDS; i++) BitSetPtr()[i] = ~all0; } else { - *BitSetPtr().Raw() = ~all0; + *BitSetPtr().Raw() = (0xFFFFFFFFFFFFFFFF >> (64 - num_bits)); } if (LastBitID() > 0) { if (num_bits > SHORT_THRESHOLD) { BitSetPtr()[NUM_FIELDS - 1] &= MaskLow(LastBitID()); - } else { - *BitSetPtr().Raw() |= (0xFFFFFFFFFFFFFFFF >> (64 - num_bits)); } } From 9aeea812b9304e964a4009f85c557d32ebc24148 Mon Sep 17 00:00:00 2001 From: schmi710 <55195426+schmi710@users.noreply.github.com> Date: Thu, 9 Jul 2020 19:43:00 -0400 Subject: [PATCH 8/9] Fixed Old Bug Previously, a resize which decreased the number of fields would not properly clear the values in the last field if the number of bits was not evenly divisible by 64. This bug persisted for long BitVectors. --- source/tools/BitVector.h | 1 + 1 file changed, 1 insertion(+) diff --git a/source/tools/BitVector.h b/source/tools/BitVector.h index 705ef7e723..775b1161ca 100644 --- a/source/tools/BitVector.h +++ b/source/tools/BitVector.h @@ -398,6 +398,7 @@ namespace emp { if (num_bits > SHORT_THRESHOLD) { if (old_num_bits > SHORT_THRESHOLD) { for (size_t i = 0; i < min_fields; i++) BitSetPtr()[i] = BitSetPtr(old_bit_set, old_num_bits)[i]; + BitSetPtr()[min_fields - 1] = BitSetPtr()[min_fields - 1] & (0xFFFFFFFFFFFFFFFF >> (FIELD_BITS - (num_bits % FIELD_BITS))); } else { BitSetPtr()[0] = *BitSetPtr(old_bit_set, old_num_bits).Raw(); } From 3df22fde6ed2e0c1bddbebbe1f9ec21175349803 Mon Sep 17 00:00:00 2001 From: schmi710 <55195426+schmi710@users.noreply.github.com> Date: Thu, 9 Jul 2020 19:48:32 -0400 Subject: [PATCH 9/9] Updated the BitVector test suite added a section to check for overflow in a variety of cases and methods. --- tests/tools/BitVector.cc | 63 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/tests/tools/BitVector.cc b/tests/tools/BitVector.cc index fe1cf9bc0d..7fe5221da3 100644 --- a/tests/tools/BitVector.cc +++ b/tests/tools/BitVector.cc @@ -259,6 +259,69 @@ TEST_CASE("Test BitVector", "[tools]") REQUIRE(bv_f.count() == 1); bv_f <<= 1; REQUIRE(bv_f.none()); + + + // The new series of tests which covers all subcases of the short/long BitVector and all methods. + std::vector bvs{bv, bv1, bv2, bv3, bv4, bv5, bv_a, bv_b, bv_c, bv_d, bv_e, bv_f}; + + for (int i = 0; i < bvs.size(); i ++) { + for (int j = 0; j < bvs[i].GetSize(); j ++) { + bvs[i][j] = 1; // clear them all (checks for leaks in those methods) + } + } + + emp::BitVector bva(100, true); // long resize minorly smaller + emp::BitVector bvb(200, true); // long resize smaller + emp::BitVector bvc(100, true); // long resize to short + emp::BitVector bvd(10, true); // short resize minorly smaller + emp::BitVector bve(60, true); // short resize smaller + emp::BitVector bvf(10, true); // short resize to long + + bva.resize(90); + bvb.resize(90); + bvc.resize(20); + bvd.resize(5); + bve.resize(5); + bvf.resize(100); + for (int i=10; i<100; i++) bvf[i] = 1; + + bvs.push_back(bva); + bvs.push_back(bvb); + bvs.push_back(bvc); + bvs.push_back(bvd); + bvs.push_back(bve); + bvs.push_back(bvf); + + for (int i = 0; i < bvs.size(); i ++) { // checks to see if assigned properly + REQUIRE((bvs[i].FindBit() == 0)); + REQUIRE((bvs[i].CountOnes() == bvs[i].GetSize())); + REQUIRE((bvs[i].FindBit(bvs[i].GetSize() / 2 - 1) == bvs[i].GetSize() / 2 - 1)); + REQUIRE((bvs[i].PopBit() == 0)); + } + + std::vector bvstemp{bva, bvb, bvc, bvd, bve, bvf}; + + for (int i = 0; i < 6; i ++) { // do all generations for bit operations + bvs.push_back(bvstemp[i].NOT()); + bvs.push_back((~bvstemp[i]).AND(~bvstemp[i])); + bvs.push_back(bvstemp[i].OR(~bvstemp[i])); + bvs.push_back(bvstemp[i].NAND(bvstemp[i])); + bvs.push_back(bvstemp[i].NOR(bvstemp[i])); + bvs.push_back(bvstemp[i].XOR(~bvstemp[i])); + bvs.push_back(bvstemp[i].EQU(bvstemp[i])); + bvs.push_back(bvstemp[i].SHIFT(-2)); + bvs.push_back(bvstemp[i].SHIFT(2)); + } + + for (int i = 0; i < bvs.size(); i ++) { // checks to see if overflow occurred + for (int j = 0; j < bvs[i].GetSize(); j ++){ + bvs[i][j] = 0; + } + REQUIRE((bvs[i].FindBit() == -1)); + REQUIRE((bvs[i].CountOnes() == 0)); + REQUIRE((bvs[i].FindBit(5) == -1)); + REQUIRE((bvs[i].PopBit() == -1)); + } } TEST_CASE("Another Test BitVector", "[tools]")