From 0f6f88b2d4edcc78fcc824e8e25db1c0c6ac9341 Mon Sep 17 00:00:00 2001 From: Daniel Lemire Date: Tue, 7 Mar 2017 15:36:10 -0500 Subject: [PATCH] Implemented equality. --- include/concise.h | 117 ++++++++++++++++++++++++++++++++++++++++++ include/conciseutil.h | 14 ++--- tests/unit.cpp | 8 +++ 3 files changed, 133 insertions(+), 6 deletions(-) diff --git a/include/concise.h b/include/concise.h index d15d251..c0ec79e 100644 --- a/include/concise.h +++ b/include/concise.h @@ -304,6 +304,96 @@ template class ConciseSet { return; } + bool equals(const ConciseSet &other) const { + return logicalxorEmpty(other); + } + + bool logicalxorEmpty(const ConciseSet &other) const { + if (this->isEmpty()) { + return other.isEmpty(); + } + if (other.isEmpty()) { + return this->isEmpty(); + } + // scan "this" and "other" + WordIterator thisItr(*this); + WordIterator otherItr(other); + while (true) { + if (!thisItr.IsLiteral) { + if (!otherItr.IsLiteral) { + int minCount = std::min(thisItr.count, otherItr.count); + if(concise_xor(thisItr.word, otherItr.word) & SEQUENCE_BIT) + return false; + if (!thisItr.prepareNext(minCount) | + !otherItr.prepareNext(minCount)) // NOT || + break; + } else { + if(!isLiteralZero(concise_xor(thisItr.toLiteral(), otherItr.word))) return false; + thisItr.word--; + if (!thisItr.prepareNext(1) | + !otherItr.prepareNext()) // do NOT use "||" + break; + } + } else if (!otherItr.IsLiteral) { + if(!isLiteralZero(concise_xor(thisItr.word, otherItr.toLiteral()))) return false; + otherItr.word--; + if (!thisItr.prepareNext() | + !otherItr.prepareNext(1)) // do NOT use "||" + break; + } else { + if(!isLiteralZero(concise_xor(thisItr.word, otherItr.word))) return false; + if (!thisItr.prepareNext() | !otherItr.prepareNext()) // do NOT use "||" + break; + } + } + if(thisItr.flushEmpty() && otherItr.flushEmpty()) return true; + return false; + } + + size_t logicalxorCount(const ConciseSet &other) const { + if (this->isEmpty()) { + return other.size(); + } + if (other.isEmpty()) { + return this->size(); + } + size_t answer = 0; + // scan "this" and "other" + WordIterator thisItr(*this); + WordIterator otherItr(other); + while (true) { + if (!thisItr.IsLiteral) { + if (!otherItr.IsLiteral) { + int minCount = std::min(thisItr.count, otherItr.count); + if(concise_xor(thisItr.word, otherItr.word) & SEQUENCE_BIT) + answer += 31 * minCount; + if (!thisItr.prepareNext(minCount) | + !otherItr.prepareNext(minCount)) // NOT || + break; + } else { + answer += getLiteralBitCount(concise_xor(thisItr.toLiteral(), otherItr.word)); + thisItr.word--; + if (!thisItr.prepareNext(1) | + !otherItr.prepareNext()) // do NOT use "||" + break; + } + } else if (!otherItr.IsLiteral) { + answer += getLiteralBitCount(concise_xor(thisItr.word, otherItr.toLiteral())); + otherItr.word--; + if (!thisItr.prepareNext() | + !otherItr.prepareNext(1)) // do NOT use "||" + break; + } else { + answer += getLiteralBitCount(concise_xor(thisItr.word, otherItr.word)); + if (!thisItr.prepareNext() | !otherItr.prepareNext()) // do NOT use "||" + break; + } + } + answer += thisItr.flushCount(); + answer += otherItr.flushCount(); + return answer; + } + void clear() { reset(); } void add(uint32_t e) { @@ -854,6 +944,33 @@ template class WordIterator { */ uint32_t count; + + + uint32_t flushCount() { + uint32_t cardsize = 0; + while(!exhausted()) { + if (IsLiteral) { + cardsize += getLiteralBitCount(word); + } else { + if(word & SEQUENCE_BIT) + cardsize += 31 * count; + } + } while (prepareNext()); + return cardsize; + } + + bool flushEmpty() { + while(!exhausted()) { + if (IsLiteral) { + if(!isLiteralZero(word)) return false; + } else { + if(word & SEQUENCE_BIT) + return false; + } + } while (prepareNext()); + return true; + } + bool flush(ConciseSet &s) { // nothing to flush if (exhausted()) diff --git a/include/conciseutil.h b/include/conciseutil.h index 2f84de7..d15d0dd 100644 --- a/include/conciseutil.h +++ b/include/conciseutil.h @@ -143,13 +143,7 @@ static inline int getFlippedBit(uint32_t word) { // set return ((word >> 25) & UINT32_C(0x0000001F)) - 1; } -static inline uint32_t concise_or(uint32_t literal1, uint32_t literal2) { - return ALL_ZEROS_LITERAL | (literal1 | literal2); -} -static inline uint32_t concise_and(uint32_t literal1, uint32_t literal2) { - return ALL_ZEROS_LITERAL | (literal1 & literal2); -} static inline uint32_t concise_xor(uint32_t literal1, uint32_t literal2) { return ALL_ZEROS_LITERAL | (literal1 ^ literal2); } @@ -157,6 +151,10 @@ static inline uint32_t concise_andnot(uint32_t literal1, uint32_t literal2) { return ALL_ZEROS_LITERAL | (literal1 & (~literal2)); } +static inline uint32_t concise_and(uint32_t literal1, uint32_t literal2) { + return ALL_ZEROS_LITERAL | (literal1 & literal2); +} + /** * Gets the bits contained within the literal word */ @@ -170,4 +168,8 @@ static inline int getLiteralBitCount(uint32_t word) { return __builtin_popcount(getLiteralBits(word)); } +static inline bool isLiteralZero(uint32_t word) { + return getLiteralBits(word) == 0; +} + #endif diff --git a/tests/unit.cpp b/tests/unit.cpp index 843f070..1a69436 100644 --- a/tests/unit.cpp +++ b/tests/unit.cpp @@ -545,6 +545,13 @@ template void realtest() { test2.add(data2[k]); set2.insert(data2[k]); } + + + assert(test1.equals(test1)); + assert(test2.equals(test2)); + assert(!test2.equals(test1)); + assert(!test1.equals(test2)); + std::set trueunion = unite(set1, set2); std::set trueinter = intersect(set1, set2); std::set truesubtract = subtract(set1, set2); @@ -552,6 +559,7 @@ template void realtest() { ConciseSet union1; ConciseSet union2; + union1 = test1.logicalor(test2); union2 = test1.logicalor(test2); assert(equals(trueunion, union1));