# 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]
```