Sets

In addition to constraint satisfaction, Constraining Order also contains an implementation of Intervals and IntervalSets over the real numbers and datastructures for sets in several dimensions.

DiscreteSet

The use of the DiscreteSet is very similar to the built in frozenset:

>>> from constrainingorder.sets import DiscreteSet
>>> a = DiscreteSet([1,2,'a','b'])
>>> b = DiscreteSet([1,'a','c',3])

DiscreteSets support the usual set operations and membership tests

>>> a.union(b)
DiscreteSet([1,2,3,'a','b','c'])
>>> a.intersection(b)
DiscreteSet([1,'a'])
>>> a.difference(b)
DiscreteSet([2,'b'])
>>> 1 in a
True
>>> "Foo" in b
False

The main difference is that a DiscreteSet can represent a set of “everything”, which makes sense sometimes

>>> c = DiscreteSet.everything()
>>> c.union(a)
DiscreteSet.everything()
>>> c.intersection(a)
DiscreteSet([1,2,'a','b'])

One can also iterate over all members

>>> [m for m in a.iter_members()]
[1, 2, 'a', 'b']

Interval

To initialize a Interval one passes the bounds and indicates whether they are included in the interval, or alternatively one of the convenience class methods

>>> from constrainingorder.sets import Interval
>>> a = Interval((0,1),(True,True))
>>> b = Interval.open(1,3)
>>> c = Interval.leftopen(2,4)

Intervals only support the intersection operation, as for the others the result might not be a single connected interval.

>>> b.intersection(c)
Interval((2, 3),(False, False))

One can check membership in Intervals

>>> 0.3 in a
True
>>> 1.3 in a
False

Intervals can also represent the full real axis and a single point:

>>> d = Interval.everything()
>>> e = Interval.from_value(2.4)

IntervalSets

The main use of Intervals is in IntervalSets, which can represent fairly general sets of real numbers. They get initialized by a sequence of Intervals, or one of the convenience functions

>>> from constrainingorder.sets import Interval,IntervalSet
>>> a = IntervalSet([Interval.open(0,3), Interval.open(5,8)])
>>> b = IntervalSet([Interval.closed(2,3), Interval.closed(7,10)])
>>> c = IntervalSet.from_values([4, -1])
>>> d = IntervalSet.everything()

In contrast to Intervals, IntervalSets support all of the common set operations

>>> a.union(b)
IntervalSet([Interval((0, 3),(False, True)),Interval((5, 10),(False, True))])
>>> a.intersection(b)
IntervalSet([Interval((2, 3),(True, False)),Interval((7, 8),(True, False))])
>>> a.difference(b)
IntervalSet([Interval((0, 2),(False, False)),Interval((5, 7),(False, False))])

Membership tests work as expected

>>> 2 in a
True
>>> 4 in a
False
>>> -1 in c
True

Like DiscreteSets, one can iterate over the members if the IntervalSet only contains isolated points

>>> c.is_discrete()
True
>>> [m for m in c.iter_members()]
[-1, 4]