# ProcSet API¶

class procset.ProcSet(*intervals)[source]

Set of non-overlapping (i.e., disjoint) non-negative integer intervals.

A ProcSet can be initialized with either nothing (empty set), any number of non-negative integer, any number of ProcInt-compatible iterable (iterable of exactly two int), any number of ProcSet, or any combination of such objects.

The resulting ProcSet is the union of all the intervals passed to the constructor. There is no restriction on the domains of the intervals passed to the constructor: the domains may overlap.

>>> ProcSet()  # empty set
ProcSet()
>>> ProcSet(1)
ProcSet(1)
>>> ProcSet(ProcInt(0, 1))
ProcSet((0, 1))
>>> ProcSet(ProcInt(0, 1), ProcInt(2, 3))
ProcSet((0, 3))
>>> ProcSet((0, 1), [2, 3])  # identical to previous call
ProcSet((0, 3))
>>> ProcSet(ProcInt(0, 1), *[0, 3])  # mixing ProcInt and lists
ProcSet((0, 1), 3)


Implementation detail: A ProcSet is implemented as a sorted list of ProcInt. The memory complexity is hence linear in the number of disjoint intervals contained in the set.

Changed in version 1.0: The constructor now supports ProcSet objects.

classmethod from_str(string, insep='-', outsep=' ')[source]

Build a ProcSet from a string representation of an interval set. The parsed string need not to be in canonical form.

Parameters: string (str) – string representation to parse insep (str) – delimiter character between the boundaries of a single interval (defaults to -, ascii dash symbol 0x2d) outsep (str) – delimiter character between two intervals (defaults to ␣, ascii space symbol 0x20)
>>> ProcSet.from_str('1-3 5 7')
ProcSet((1, 3), 5, 7)
>>> ProcSet.from_str('5 2-2 7 1-3')
ProcSet((1, 3), 5, 7)
>>> ProcSet.from_str('1:3,5,7', insep=':', outsep=',')
ProcSet((1, 3), 5, 7)


Note

from_str() only supports single character strings for insep and outsep delimiters.

str(pset)
format(pset[, format_spec])

Return the canonical string representation of pset.

When using str() or format() without format_spec, the default delimiters are used (default inner delimiter is -, default outer delimiter is ␣).

When using format(), the parameter format_spec may be used to change the delimiters. The format specification is a length-2 string, where the first character encodes the inner delimiter, and the second character encodes the outer delimiter.

>>> pset = ProcSet((1, 3), 5, 7)
>>> str(pset)
'1-3 5 7'
>>> format(pset)
'1-3 5 7'
>>> format(pset, ':,')
'1:3,5,7'

i in pset

Test whether processor i is in pset.

>>> 3 in ProcSet((0, 7))
True
>>> 8 in ProcSet((0, 7))
False

len(pset)

Return the number of processors contained in pset.

count()[source]

Return the number of disjoint intervals in the ProcSet.

>>> pset = ProcSet((1, 3), 5, 7)
>>> len(pset)  # 5 processors
5
>>> pset.count()  # 3 disjoint intervals
3

iter(pset)
reversed(pset)

Iterate over the processors in pset.

>>> pset = ProcSet((1, 3), 5, 7)
>>> list(iter(pset))
[1, 2, 3, 5, 7]
>>> list(reversed(pset))
[7, 5, 3, 2, 1]

pset[i]
pset[i:j]
pset[i:j:k]

Access processors of pset by position. ProcSet supports element index lookup, slicing and negative indices.

The semantic of the [] operator is defined to behave the same as if pset was a list of integers.

When used with an int i, pset[i] returns the processor at the i-th position.

When used with a slice, pset[i:j:k] returns the corresponding list of processors (see also iter_slice()).

>>> pset = ProcSet(ProcInt(0), ProcInt(2, 5), ProcInt(7, 13))
>>> pset[0], pset[2], pset[-1]
(0, 3, 13)
>>> pset[1:5]
[2, 3, 4, 5]
>>> pset[:-3]
[0, 2, 3, 4, 5, 7, 8, 9, 10]
>>> pset[::2]
[0, 3, 5, 8, 10, 12]
>>> pset[3::3]
[4, 8, 11]
>>> pset[3::-3]
[4, 0]

iter_slice(start=None, stop=None, step=None)[source]

Iterate over the processors in the ProcSet from start (included) to stop (excluded) by steps of step.

This method iterate over the same set of processors as pset[start:stop:step]. In contrast to using [], we do not build the list of processors: the memory complexity is hence constant rather than linear in the number of iterated processors.

>>> pset = ProcSet(ProcInt(0), ProcInt(2, 5), ProcInt(7, 13))
>>> pset.iter_slice()
<generator object ProcSet.iter_slice at 0x7f0dd6afb8b8>
>>> list(pset.iter_slice())
[0, 2, 3, 4, 5, 7, 8, 9, 10, 11, 12, 13]

isdisjoint(other)[source]

Return True if the ProcSet has no processor in common with other.

issubset(other)[source]
pset <= other

Test whether every element in the ProcSet is in other.

pset < other

Test whether the ProcSet is a proper subset of other, that is pset <= other and pset != other.

issuperset(other)[source]
pset >= other

Test whether every element in other is in the ProcSet.

pset > other

Test whether the ProcSet is a proper superset of other, that is pset >= other and pset != other.

union(*others)[source]
pset | other | ...

Return a new ProcSet with elements from the ProcSet and all others.

intersection(*others)[source]
pset & other & ...

Return a new ProcSet with elements common to the ProcSet and all others.

difference(*others)[source]
pset - other - ...

Return a new ProcSet with elements in the ProcSet that are not in the others.

symmetric_difference(other)[source]
pset ^ other

Return a new ProcSet with elements in either the ProcSet or other, but not in both.

copy()[source]

Return a new ProcSet with a shallow copy of the ProcSet.

Note

The non-operator versions of union(), intersection(), difference(), symmetric_difference() methods accept as argument any combination of objects that may be used to initialize a ProcSet.

In contrast, their operator based counterparts require their arguments to be ProcSet. This avoid error-prone constructions, and favors readability.

update(*others)[source]
insert(*others)
pset |= other | ...

Update the ProcSet, adding elements from all others.

intersection_update(*others)[source]
pset &= other & ...

Update the ProcSet, keeping only elements found in the ProcSet and all others.

difference_update(*others)[source]
discard(*others)
pset -= other | ...

Update the ProcSet, removing elements found in others.

symmetric_difference_update(other)[source]
pset ^= other

Update the ProcSet, keeping only elements found in either the ProcSet or other, but not in both.

clear()[source]

Empty the ProcSet, removing all elements from it.

Note

The non-operator versions of update(), intersection_update(), difference_update(), symmetric_difference_update() methods accept as argument any combination of objects that may be used to initialize a ProcSet.

In contrast, their operator based counterparts require their arguments to be ProcSet. This avoid error-prone constructions, and favors readability.

iscontiguous()[source]

Return True if the ProcSet is made of a unique interval.

>>> ProcSet().iscontiguous()
True
>>> ProcSet((1, 3)).iscontiguous()
True
>>> ProcSet((1, 3), 4).iscontiguous()
True
>>> ProcSet((1, 3), 5, 7).iscontiguous()
False

aggregate()[source]

Return a new ProcSet that is the convex hull of the ProcSet.

The convex hull of an empty ProcSet is the empty ProcSet.

The convex hull of a non-empty ProcSet is the contiguous ProcSet made of the smallest unique interval containing all intervals from the non-empty ProcSet.

>>> ProcSet().aggregate()
ProcSet()
>>> ProcSet((1, 3), 5, 7).aggregate()
ProcSet((1, 7))

intervals()[source]

Return an iterator over the intervals of the ProcSet in increasing order.

>>> pset = ProcSet((1, 3), 5)
>>> list(pset.intervals())
[ProcInt(inf=1, sup=3), ProcInt(inf=5, sup=5)]

min

The first processor in the ProcSet (in increasing order).

max

The last processor in the ProcSet (in increasing order).