IntSet
IntSet is an immutable set specialized for non-negative integers. It is backed by a
Roaring bitmap, so union, intersection, and difference run
entirely in Rust over compressed bitmaps — there is no per-element Python loop and no GIL
contention during the operation. Reach for it when you are combining large sets of integer
IDs and a regular ISet of boxed ints is the bottleneck.
The same engine sits underneath analytics systems like Druid, Lucene, and ClickHouse for exactly this reason: bulk set algebra over integer IDs.
Construction and membership
Section titled “Construction and membership”from pyrula import IntSet
s = IntSet([1, 2, 3, 3, 2]) # from any iterable of ints; duplicates droppedlen(s) # 3s.contains(2) # True2 in s # True (__contains__)
IntSet().is_empty() # TrueValues must be non-negative and fit in a 64-bit unsigned integer. Negative values, values
above 2**64 - 1, and non-integers raise ValueError / TypeError.
Immutability
Section titled “Immutability”add and remove always return a new IntSet; the original is unchanged. remove
is a no-op for absent values.
s = IntSet([1, 2])s.add(3).to_list() # [1, 2, 3]s.to_list() # [1, 2] -- unchangedSet algebra
Section titled “Set algebra”This is the fast path. Each operation runs over compressed bitmaps in Rust.
a = IntSet([1, 2, 3, 4])b = IntSet([3, 4, 5])
a.union(b) # IntSet([1, 2, 3, 4, 5])a.intersection(b) # IntSet([3, 4])a.difference(b) # IntSet([1, 2])a.symmetric_difference(b) # IntSet([1, 2, 5])
IntSet([3, 4]).is_subset(a) # TrueIntSet([7, 8]).is_disjoint(a) # Truea.cardinality() # 4to_list returns a plain Python list[int] in ascending order.
Serialization
Section titled “Serialization”to_bytes writes the set in the Roaring portable byte format; from_bytes reads it back.
The bytes are compact (the bitmap is already compressed) and interoperable with other
Roaring implementations, which makes IntSet usable as durable checkpoint state — for
example, a persisted “seen” set on an exactly-once path.
s = IntSet([1, 5, 9, 2**40])blob = s.to_bytes() # bytes, Roaring portable formatIntSet.from_bytes(blob).to_list() # [1, 5, 9, 1099511627776]When to use it
Section titled “When to use it”IntSet shines when the integers are dense or clustered — entity IDs, row offsets,
feature flags, graph adjacency — where the Roaring bitmap compresses well and set algebra
is hundreds to thousands of times faster than a Python set.
For uniformly random integers spread across the full 64-bit range, the bitmap cannot
compress and Roaring is the wrong tool — a plain set or ISet will be faster. Real ID
sets almost always cluster, which is the case IntSet is built for.
Scala equivalent
Section titled “Scala equivalent”IntSet mirrors the role of Scala’s scala.collection.immutable.BitSet — an immutable set
specialized for non-negative integers with compact storage and fast bulk operations.
| Pyrula | Scala |
|---|---|
IntSet([1, 2, 3]) | BitSet(1, 2, 3) |
s.add(x) | s + x |
s.remove(x) | s - x |
s.contains(x) | s.contains(x) |
s.union(t) | s ++ t / s.union(t) |
s.intersection(t) | s.intersect(t) |
s.difference(t) | s.diff(t) |
s.symmetric_difference(t) | s.xor(t) |
s.is_subset(t) | s.subsetOf(t) |