roaringrel
Implementation of integer relations based on roaring bitmaps.
Entry
Rel
- final class Rel(shape, data=None)[source]
Bases:
objectA low-level mutable data structure to store a finite relation between finite sets:
\[R \subseteq X_1 \times ... \times X_n\]It presumes that the component sets \(X_1,...,X_n\) are finite zero-based contiguous integer ranges, in the form \(X_j = \lbrace 0,...,s_j-1 \rbrace\). The tuple \((s_1,...,s_n)\) of component set sizes is referred to as the shape of the relation \(R\), while the tuples \((x_1,...x_n) \in R\) are referred to as its entries.
Relations are implemented using 64-bit roaring bitmaps to store the underlying set of entries.
See
Rel.__new__for the constructor.Entry normalisation. This class is designed for use in performance-critical code, so entries are normalised rather than validated: no method which takes entries ever rejects them. An entry is converted into the index of its slot as follows:
the element in position \(j\) is reduced modulo the component set size \(s_j\), so that negative elements index from the end of the component set (as is usual in Python) and out-of-range elements wrap around;
if the entry is shorter than the shape, the missing trailing elements are taken to be zero;
if the entry is longer than the shape, the surplus elements are ignored.
Because every integer is reduced into the range of its own component set, this is a total operation: no entry whatsoever can take a relation outside of its own shape, and the invariants of the data structure hold for arbitrary integer input. An out-of-range entry silently addresses a well-defined different entry, it does not corrupt the relation.
Callers which cannot guarantee that their entries are in range should check them with
Rel.validate_entry, which exists for exactly this purpose and is never called internally. Validation is therefore entirely opt-in, and code which understands the tradeoff above pays nothing for it.Equality, ordering and hashing. Relations of different shape are never equal, but they are not ordered either:
Rel.__eq__returnsFalseon a shape mismatch, whereasRel.__lt__andRel.__le__raiseValueError. This is deliberate. Equality is total, because unrelated objects are simply unequal, while containment between relations of different shape is a question about incomparable domains, which is much more likely to indicate a bug in the caller than a meaningful query.Relations are mutable, and therefore unhashable: defining
Rel.__eq__withoutobject.__hash__is what makes them so, by the same convention that applies tosetandlist. Usefrozensetof the entries where a hashable snapshot of a relation is required.- __and__(other)[source]
Returns the intersection of this relation and a given relation of same shape.
- Raises:
ValueError – if the two relations have different shapes.
- Parameters:
other (
Rel)- Return type:
- __contains__(entry)[source]
Whether the given entry is in the relation.
The entry is normalised, not validated: see Entry normalisation. An entry which is out of range is therefore not reported as absent, it is taken to be the entry it normalises to.
- __eq__(other)[source]
Equality comparison between relations, as sets of entries.
Relations of different shape are never equal, but no error is raised: unlike the containment comparisons, equality is total. Note that defining this method makes relations unhashable, as befits a mutable container.
- __getnewargs__()[source]
Returns the arguments to
Rel.__new__used to unpickle the relation, namely its shape. The entries are restored separately, byRel.__setstate__.
- __getstate__()[source]
Returns the state used to pickle the relation, as the serialised form of the underlying bitmap. The shape is not part of the state, because it is already restored by
Rel.__getnewargs__.- Return type:
- __iand__(other)[source]
Inplace version of
Rel.__and__, mutating the lhs relation.
- __invert__()[source]
Returns the relation’s complement within the set of all possible entries for the relation’s own shape.
- Return type:
- __ior__(other)[source]
Inplace version of
Rel.__or__, mutating the lhs relation.
- __isub__(other)[source]
Inplace version of
Rel.__sub__, mutating the lhs relation.
- __ixor__(other)[source]
Inplace version of
Rel.__xor__, mutating the lhs relation.
- __le__(other)[source]
Containment comparison between relations, as sets of entries.
Unlike
Rel.__eq__, this raises on a shape mismatch rather than returningFalse: seeRel.__lt__.- Raises:
ValueError – if the two relations have different shapes.
- Parameters:
other (
Any)- Return type:
- __lt__(other)[source]
Strict containment comparison between relations, as sets of entries.
Unlike
Rel.__eq__, this raises on a shape mismatch rather than returningFalse: containment between relations over different domains is much more likely to indicate a bug than a meaningful query.- Raises:
ValueError – if the two relations have different shapes.
- Parameters:
other (
Any)- Return type:
- static __new__(cls, shape, data=None)[source]
Creates a relation with the given shape and initial data:
if
datais aRelinstance, performs a copy of that relation;if
datais an iterable of entries, creates a relation with those entries;if
datais a BitMap64, creates a relation using the bitmap for the underlying set of entries;if
dataisNone(default), an empty relation is created.
Entries taken from an iterable are normalised, as described in Entry normalisation. Indices taken from a
Relor a bitmap are validated instead, because they bypass normalisation entirely: this permits a relation to be reinterpreted under any shape large enough to hold its indices, while ruling out indices which would fall outside the new shape.- Raises:
ValueError – if any component set size is not strictly positive.
ValueError – if a given relation or bitmap contains an index which is out of range for the given shape.
NotImplementedError – if the product of the component set sizes is too large to be indexed by a 64-bit bitmap.
- Parameters:
- Return type:
- __or__(other)[source]
Returns the union of this relation and a given relation of same shape.
- Raises:
ValueError – if the two relations have different shapes.
- Parameters:
other (
Rel)- Return type:
- __setstate__(state)[source]
Restores the entries of a relation being unpickled, from the state returned by
Rel.__getstate__. The shape and strides have already been set byRel.__new__, viaRel.__getnewargs__.
- __sub__(other)[source]
Returns the difference of this relation and a given relation of same shape.
- Raises:
ValueError – if the two relations have different shapes.
- Parameters:
other (
Rel)- Return type:
- __xor__(other)[source]
Returns the symmetric diff of this relation and a given relation of same shape.
- Raises:
ValueError – if the two relations have different shapes.
- Parameters:
other (
Rel)- Return type:
- add(entry)[source]
Adds the given entry to the relation.
The entry is normalised, not validated: see Entry normalisation.
- difference_update(*entry_sets)[source]
Removes all entries from all given iterables from the relation.
Entries are normalised, not validated: see Entry normalisation.
- flip(entry)[source]
Removes the entry from the relation if it is in the relation; otherwise, adds the entry to the relation.
The entry is normalised, not validated: see Entry normalisation.
- remove(entry)[source]
Removes the given entry from the relation.
The entry is normalised, not validated: see Entry normalisation.
- property shape
The shape of the relation, i.e. the tuple of sizes for its component sets.
- Return type:
- symmetric_difference_update(*entry_sets)[source]
Flips all entries from all given iterables within the relation. That is, removes from the relation all given entries which are in the relation, and adds to the relation all given entries which are not in the relation.
Note that the given entries are considered without repetition, so that multiple occurrences of the same entry in the given iterables don’t result in multiple flips. Because entries are normalised rather than validated (see Entry normalisation), entries which normalise to the same slot count as repetitions of each other.
- update(*entry_sets)[source]
Adds all entries from all given iterables to the relation.
Entries are normalised, not validated: see Entry normalisation.
- validate_entry(entry)[source]
Validates the given entry against the shape of the relation.
This method is never called internally: the methods of this class normalise entries instead of validating them, as described in Entry normalisation. It is provided as a convenience for callers which cannot otherwise guarantee that an entry is in range, and which would rather have an error than address a different entry by accident. Validating every entry is significantly more expensive than the operations it guards, so it is left to the caller to decide where that cost is worth paying.
- Raises:
ValueError – if the entry is not valid for the shape.
- Parameters:
entry (
Entry)- Return type: