skip to navigation
skip to content

bitsets 0.5

Ordered subsets over a predefined domain

Latest Version: 0.7.12

Bitsets are ordered sets which are subsets of a predefined finite domain of hashable items.

They are implemented as pure Python integers representing the rank of the set in colexicographical order (a.k.a bit strings, powers of two, binary strings). Hence, they can be very space-efficient, e.g. if a large number of subsets from a collection needs to be present in memory. Furthermore, they can be compared, intersected, etc. using normal bitwise operations of integers (&, |, ^, ~).


$ pip install bitsets


Use the bitset function to create a class representing ordered subsets from a fixed set of items (the domain):

>>> from bitsets import bitset

>>> Pythons = bitset('Pythons', ('Chapman', 'Cleese', 'Gilliam', 'Idle', 'Jones', 'Palin'))

The domain collection needs to be a hashable sequence (e.g. a tuple).

The resulting class is an integer (long) subclass, so its instances (being integers) are immutable and hashable and thus in many ways similar to pythons built-in frozenset.

>>> issubclass(Pythons, long)

The domain items are mapped to powers of two (their rank in colexicographical order):

>>> Pythons.fromint(0)

>>> [Pythons.fromint(1), Pythons.fromint(2), Pythons.fromint(4)]
[Pythons(['Chapman']), Pythons(['Cleese']), Pythons(['Gilliam'])]

>>> Pythons.fromint(2 ** 6 - 1)
Pythons(['Chapman', 'Cleese', 'Gilliam', 'Idle', 'Jones', 'Palin'])

>>> Pythons.fromint((1 << 0) + (1 << 5))
Pythons(['Chapman', 'Palin'])

The class provides access to the minimal (infimum) and maximal (supremum) sets from its domain:

>>> Pythons.infimum

>>> Pythons.supremum
Pythons(['Chapman', 'Cleese', 'Gilliam', 'Idle', 'Jones', 'Palin'])

Basic usage

Bitsets can be created from members, bit strings, boolean sequences, and integers:

>>> Pythons(['Palin', 'Cleese'])
Pythons(['Cleese', 'Palin'])

>>> Pythons.frombits('101000')
Pythons(['Chapman', 'Gilliam'])

>>> Pythons.frombools([True, False, True, False, False, False])
Pythons(['Chapman', 'Gilliam'])

>>> Pythons.fromint(5)
Pythons(['Chapman', 'Gilliam'])

Members always occur in the definition order.

Bitsets cannot contain items other than those from their domain:

>>> Pythons(['Brian'])
Traceback (most recent call last):
KeyError: 'Brian'

Bitsets can be converted to members, bit strings, boolean sequences and integers:

>>> Pythons(['Chapman', 'Gilliam']).members()
('Chapman', 'Gilliam')

>>> Pythons(['Chapman', 'Gilliam']).bits()

>>> Pythons(['Chapman', 'Gilliam']).bools()
(True, False, True, False, False, False)

>>> int(Pythons(['Chapman', 'Gilliam']))


To facilitate sorting collections of bitsets, they have key methods for different sort orders (shortlex, longlex, shortcolex, and longcolex):

>>> Pythons(['Idle']).shortlex() < Pythons(['Palin']).shortlex()

Sorting a collection of bitsets without using a key function will order them in colexicographical order.


Iterate over a bitsets’ powerset in short lexicographic order:

>>> for p in Pythons(['Palin', 'Idle']).powerset():
...     print p.members()
('Idle', 'Palin')

frozenset compatibility

For convenience, bitsets provide the same methods as frozenset (i.e. issubset, issuperset, isdisjoint, intersection, union, difference, symmetric_difference, __len__, __iter__, __nonzero__, and __contains__).

>>> 'Cleese' in Pythons(['Idle'])

>>> 'Idle' in Pythons(['Idle'])

>>> Pythons(['Chapman', 'Idle']).intersection(Pythons(['Idle', 'Palin']))

Note, however that all the operators methods (+, -, &, | etc.) retain their integer semantics:

>>> Pythons(['Chapman', 'Idle']) - Pythons(['Idle'])

In tight loops it might be worth to use bitwise expressions (&, |, ^, ~) for set comparisons/operations instead of the frozenset-compatible methods:

>>> # is subset ?
>>> Pythons(['Idle']) & Pythons(['Chapman', 'Idle']) == Pythons(['Idle'])

Added functionality

Differing from frozenset, you can also retrieve the complement set of a bitset:

>>> Pythons(['Idle']).complement()
Pythons(['Chapman', 'Cleese', 'Gilliam', 'Jones', 'Palin'])

>>> Pythons().complement().complement()

Test if a bitset is maximal (supremum):

>>> Pythons(['Idle']).all()

>>> Pythons(['Chapman', 'Cleese', 'Gilliam', 'Idle', 'Jones', 'Palin']).all()

Test if a bitset is non-minimal (infimum), same as bool(bitset):

>>> Pythons(['Idle']).any()

>>> Pythons().any()


With the help of the optional Graphviz graph layout library and this Python interface, the bitsets.visualize module can create hasse diagrams of all bitsets from your domain:

Download and install Graphviz. Then install the Python interface:

$ pip install graphviz==0.2

Make sure that the bin directory of Graphviz is on your system path.

>>> from bitsets import visualize
>>> Four = bitset('four', (1, 2, 3, 4))

>>> dot = visualize.bitset(Four)

>>> print dot.source  # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
// <class bitsets.meta.bitset('four', (1, 2, 3, 4), 0x..., BitSet, None, None)>
digraph four {
edge [dir=none]
    b0 [label=0000]
            b1 -> b0
            b2 -> b0

Show members instead of bits:

>>> dot = visualize.bitset(Four, member_label=True)

>>> print dot.source  # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
// <class bitsets.meta.bitset('four', (1, 2, 3, 4), 0x..., BitSet, None, None)>
digraph four {
edge [dir=none]
    b0 [label="{}"]
            b1 -> b0
            b2 -> b0

Remember that the graphs have 2 ** domain_size nodes.

Advanced usage

To use a customized bitset, extend a class from the bitsets.bases module and pass it to the bitset function.

>>> import bitsets

>>> class ProperSet(bitsets.bases.BitSet):
...     def issubset_proper(self, other):
...         return self & other == self != other

>>> Ints = bitsets.bitset('Ints', tuple(range(1, 7)), base=ProperSet)

>>> issubclass(Ints, ProperSet)

>>> Ints([1]).issubset_proper(Ints([1, 2]))

>>> Ints([1, 2]).issubset_proper(Ints([1, 2]))

When activated, each bitset class comes with tailored collection classes (bitset list and bitset tuple) for its instances.

>>> Letters = bitsets.bitset('Letters', 'abcdef', list=True)

>>> Letters.List.frommembers(['a', 'bcd', 'ef'])
LettersList('100000', '011100', '000011')

To use a customized bitset collection class, extend a class from the bitsets.series module and pass it to the bitset function

>>> class ReduceList(bitsets.series.List):
...     def intersection(self):
...         return self.BitSet.fromint(reduce(long.__and__, self))
...     def union(self):
...         return self.BitSet.fromint(reduce(long.__or__, self))

>>> Nums = bitsets.bitset('Nums', (1, 2, 3), list=ReduceList)

>>> issubclass(Nums.List, ReduceList)

>>> numslist = Nums.List.frommembers([(1, 2, 3), (1, 2), (2, 3)])

>>> numslist.intersection()

>>> numslist.union()
Nums([1, 2, 3])

Since version 0.4, this very functionality was added to the bitsets.series classes as reduce_and and reduce_or methods.

Bitset classes, collection classes and their instances are pickleable:

>>> import pickle

>>> pickle.loads(pickle.dumps(Pythons)) is Pythons

>>> pickle.loads(pickle.dumps(Pythons()))

>>> pickle.loads(pickle.dumps(Nums.List)) is Nums.List  # doctest: +SKIP

>>> pickle.loads(pickle.dumps(Nums.List()))  # doctest: +SKIP

See also

  • bitarray – efficient boolean array implemented as C extension
  • bitstring – pure-Python bit string based on bytearray
  • BitVector – pure-Python bit array based on unsigned short array


Bitsets is distributed under the MIT license.

File Type Py Version Uploaded on Size (md5) Source 2014-01-21 99KB