# ProcSet API

class procset.ProcSet(*intervals)

  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=' ')

    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.

    See also

    String representation of interval sets

  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()

    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)

    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)

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

  issubset(other)
  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)
  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)
  pset | other | ...

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

  intersection(*others)
  pset & other & ...

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

  difference(*others)
  pset - other - ...

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

  symmetric_difference(other)
  pset ^ other

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

  copy()

    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)
  insert(*others)
  pset |= other | ...

    Update the ProcSet, adding elements from all others.

  intersection_update(*others)
  pset &= other & ...

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

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

    Update the ProcSet, removing elements found in others.

  symmetric_difference_update(other)
  pset ^= other

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

  clear()

    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()

    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()

    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()

    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).