iset
index
/home/jacob/src/iset/iset.py

The iset module supports the use of sets of intervals.  These are 
implemented by ISet instances.
 
ISets can be created directly, or they can be created from the helper 
functions ne, lt, le, eq, ge, gt, incInterval, and exInterval.  These 
simple ISets can be combined by union (+, |) intersection (&), xor (^), or
subtraction (-).  To get the inverse of an ISet, use the ~ operator.  You 
can test a value's membership in an ISet using the "in" operator.
 
ISets don't have to contain just numbers.  They can contain any data that is
comparable via the Python operators <, <=, ==, >=, and >.  Here's an example
of how strings can be used with ISets:
>>> volume1 = incInterval("A", "Foe")
>>> volume2 = incInterval("Fog", "McAfee")
>>> volume3 = incInterval("McDonalds", "Space")
>>> volume4 = incInterval("Spade", "Zygote")
>>> encyclopedia = volume1 + volume2 + volume3 + volume4
>>> mySet = volume1 + volume3 + volume4
>>> "Meteor" in encyclopedia
True
>>> "Goose" in encyclopedia
True
>>> "Goose" in mySet
False
>>> volume2 in (encyclopedia ^ mySet)
True
 
Here's an example of how times can be used with continuous sets:
>>> officeHours = incInterval("08:00", "17:00")
>>> myLunch = incInterval("11:30", "12:30")
>>> myHours = incInterval("08:30", "19:30") - myLunch
>>> myHours in officeHours
False
>>> "12:00" in myHours
False
>>> "15:30" in myHours
True
>>> inOffice = officeHours & myHours
>>> print inOffice
ISet: ['08:30','11:30'),('12:30','17:00']
>>> overtime = myHours - officeHours
>>> print overtime
ISet: ('17:00','19:30']

 
Modules
       
copy

 
Classes
       
ISet
Interval

 
class ISet
    ISet is a class representing sets of continuous values, as opposed to a
discrete set, which is already implemented by the set type in Python.
 
ISets can be bounded, unbounded, and non-continuous.  They were designed
to accomodate any sort of mathematical set dealing with continuous 
values.  This will usually mean numbers, but any Python type that has 
valid comparison operations can be used in an ISet.
 
  Methods defined here:
__add__(self, other)
This function returns the union of two ISets.  It does the same 
thing as the __or__ function.  A set or a single value can also be
added.
 
>>> empty     = ISet()
>>> negatives = ISet(Interval(None, False, 0, False))
>>> positives = ISet(Interval(0, False, None, False))
>>> naturals  = ISet(Interval(0, True,  None, False))
>>> evens     = ISet(-8, -6, -4, -2, 0, 2, 4, 6, 8)
>>> zero      = ISet(0)
>>> nonzero   = ne(0)
>>> print evens + positives
ISet: -8,-6,-4,-2,[0,~)
>>> print negatives + zero
ISet: (-~,0]
>>> print empty + negatives
ISet: (-~,0)
>>> print empty + naturals
ISet: [0,~)
>>> print nonzero + evens
ISet: (-~,~)
>>> print evens + set((1,3))
ISet: -8,-6,-4,-2,0,1,2,3,4,6,8
>>> nonzero + 0 == all
True
__and__(self, other)
This function returns the intersection of self and other.
 
>>> empty     = ISet()
>>> negatives = ISet(Interval(None, False, 0, False))
>>> positives = ISet(Interval(0, False, None, False))
>>> naturals  = ISet(Interval(0, True,  None, False))
>>> evens     = ISet(-8, -6, -4, -2, 0, 2, 4, 6, 8)
>>> zero      = ISet(0)
>>> nonzero   = ne(0)
>>> print naturals and naturals
ISet: [0,~)
>>> print evens & zero
ISet: 0
>>> print negatives & zero
ISet: <Empty>
>>> print nonzero & positives
ISet: (0,~)
>>> print empty & zero
ISet: <Empty>
>>> print evens & set((4, -2, 0, 3))
ISet: -2,0,4
>>> print evens & 5
ISet: <Empty>
>>> print evens & 2
ISet: 2
__contains__(self, obj)
Returns True if obj is a subset of self.
 
>>> empty = ISet()
>>> all = ISet(Interval(None, False, None, False))
>>> some = ISet(
...   2, 8, Interval(12, True, 17, False),
...   Interval(17, False, None, False))
>>> 17 in empty
False
>>> 17 in all
True
>>> 17 in some
False
>>> r = Interval(100, True, 400, False)
>>> r in empty
False
>>> r in all
True
>>> r in some
True
>>> empty in all
False
>>> empty in some
False
>>> all in empty
False
>>> all in some
False
>>> some in empty
False
>>> some in all
True
__eq__(self, other)
Two ISets are identical if they contain the exact same sets.  Note
that an empty set is never equal to any other set, even an empty 
one.
 
>>> ISet(4) == ISet(1)
False
>>> ISet(5) == ISet(5)
True
>>> s1 = ISet(Interval(4, True, 7, True))
>>> s2 = ISet(Interval(4, True, 7, False))
>>> s1 == s2
False
>>> s2.append(7)
>>> s1 == s2
True
__init__(self, *args)
This function initializes an ISet.  There can be an arbitrary number
of arguments to the initializer.
 
If no parameters are provided, then an empty ISet is constructed.
>>> print ISet() # An empty set
ISet: <Empty>
 
Interval objects arguments are added directly to the ISet.
>>> print ISet(Interval(4, False, 6, True))
ISet: (4,6]
>>> print ISet(Interval(None, False, 2, True))
ISet: (-~,2]
 
Other ISet objects are expanded and added to the ISet, as though
they were or'ed together.
>>> s1 = ISet(Interval(3, True, 29, True))
>>> print ISet(6, 2, s1)
ISet: 2,[3,29]
 
Each value of a set object is added as a discrete value.  
>>> print ISet(set((3, 7, 2, 1)))
ISet: 1,2,3,7
 
All other arguments are added as discrete values.
>>> print ISet("Bob", "Fred", "Mary")
ISet: 'Bob','Fred','Mary'
__invert__(self)
This function returns the disjoint set of self.  In other words,
all values self doesn't include are in the returned set.
 
>>> empty     = ISet()
>>> negatives = ISet(Interval(None, False, 0, False))
>>> positives = ISet(Interval(0, False, None, False))
>>> naturals  = ISet(Interval(0, True,  None, False))
>>> evens     = ISet(-8, -6, -4, -2, 0, 2, 4, 6, 8)
>>> zero      = ISet(0)
>>> nonzero   = ne(0)
>>> print ~empty
ISet: (-~,~)
>>> ~negatives == naturals
True
>>> print ~positives
ISet: (-~,0]
>>> ~naturals == negatives
True
>>> print ~evens
ISet: (-~,-8),(-8,-6),(-6,-4),(-4,-2),(-2,0),(0,2),(2,4),(4,6),(6,8),(8,~)
>>> ~zero == nonzero
True
>>> ~nonzero == zero
True
__nonzero__(self)
An empty ISet is the zero-like value.
 
>>> empty = ISet()
>>> nonempty = ISet(3)
>>> if empty:
...     print "Non-empty"
>>> if nonempty:
...     print "Non-empty"
Non-empty
__or__(self, other)
This function returns the union of two ISets.  It does the same
thing as the __add__ function.  It can also accept sets or single
values.
 
>>> empty     = ISet()
>>> negatives = ISet(Interval(None, False, 0, False))
>>> positives = ISet(Interval(0, False, None, False))
>>> naturals  = ISet(Interval(0, True,  None, False))
>>> evens     = ISet(-8, -6, -4, -2, 0, 2, 4, 6, 8)
>>> zero      = ISet(0)
>>> nonzero   = ne(0)
>>> print evens | positives
ISet: -8,-6,-4,-2,[0,~)
>>> print negatives | zero
ISet: (-~,0]
>>> print empty | negatives
ISet: (-~,0)
>>> print empty | naturals
ISet: [0,~)
>>> print nonzero | evens
ISet: (-~,~)
>>> print evens | set((-3, -5))
ISet: -8,-6,-5,-4,-3,-2,0,2,4,6,8
>>> print nonzero | 0 == all
True
__str__(self)
This function shows a string representation of an ISet.  The string 
is shown sorted, with all intervals normalized.
 
>>> print ISet()
ISet: <Empty>
>>> print ISet(62)
ISet: 62
>>> print ISet(62, 56)
ISet: 56,62
>>> print ISet(23, Interval(26, True, 32, False))
ISet: 23,[26,32)
>>> print lt(3) + gt(3)
ISet: (-~,3),(3,~)
>>> print ISet(Interval(None, False, 6, True))
ISet: (-~,6]
__sub__(self, other)
Returns all values of self minus all matching values in other.
 
>>> empty     = ISet()
>>> all       = ISet(Interval(None, False, None, False))
>>> negatives = ISet(Interval(None, False, 0, False))
>>> positives = ISet(Interval(0, False, None, False))
>>> naturals  = ISet(Interval(0, True,  None, False))
>>> evens     = ISet(-8, -6, -4, -2, 0, 2, 4, 6, 8)
>>> zero      = ISet(0)
>>> nonzero   = ne(0)
>>> print evens - nonzero
ISet: 0
>>> print empty - naturals
ISet: <Empty>
>>> print zero - naturals
ISet: <Empty>
>>> print positives - zero
ISet: (0,~)
>>> print naturals - negatives
ISet: [0,~)
>>> print all - zero
ISet: (-~,0),(0,~)
>>> all - zero == nonzero
True
>>> print evens - set((2, 4, 6, 8))
ISet: -8,-6,-4,-2,0
>>> print evens - 8
ISet: -8,-6,-4,-2,0,2,4,6
>>> print le(40) - 40
ISet: (-~,40)
__xor__(self, other)
This function returns the exclusive or of two ISets.  Regular sets 
or single values can also be xor'ed.
 
>>> empty     = ISet()
>>> negatives = ISet(Interval(None, False, 0, False))
>>> positives = ISet(Interval(0, False, None, False))
>>> naturals  = ISet(Interval(0, True,  None, False))
>>> evens     = ISet(-8, -6, -4, -2, 0, 2, 4, 6, 8)
>>> zero      = ISet(0)
>>> nonzero   = ne(0)
>>> print nonzero ^ naturals
ISet: (-~,0]
>>> print zero ^ negatives
ISet: (-~,0]
>>> print positives ^ empty
ISet: (0,~)
>>> print evens ^ zero
ISet: -8,-6,-4,-2,2,4,6,8
>>> print evens ^ set((2, 4, 6, 8, 10))
ISet: -8,-6,-4,-2,0,10
>>> print zero ^ 0
ISet: <Empty>
>>> print zero ^ 42
ISet: 0,42
append(self, obj)
This function adds an Interval, discrete, or ISet to an ISet.
 
>>> r = ISet()
>>> r.append(4)
>>> print r
ISet: 4
>>> r.append(Interval(23, False, 39, True))
>>> print r
ISet: 4,(23,39]
>>> r.append(Interval(None, False, 25, False))
>>> print r
ISet: (-~,39]
>>> r2 = ISet(Interval(None, False, None, False))
>>> r.append(r2)
>>> print r
ISet: (-~,~)

 
class Interval
    An Interval is an internal component of an ISet.  ISets are made up of
zero (for an empty set) to many Intervals.
 
An Interval is composed of the lower bound, an inclusive lower bound 
flag, an upper bound, and an inclusive upper bound flag.  For an 
unbound interval, the bound is set to None.
 
  Methods defined here:
__add__(self, other)
Yields an Interval that encompasses self and other.  If the 
Intervals don't overlap, then an exception is raised.  
>>> r1  = Interval(None, False, -100, False)
>>> r2  = Interval(None, False, -100, True)
>>> r3  = Interval(None, False,  100, False)
>>> r4  = Interval(None, False,  100, True)
>>> r5  = Interval(None, False, None, False)
>>> r6  = Interval(-100, False,  100, False)
>>> r7  = Interval(-100, False,  100, True)
>>> r8  = Interval(-100, False, None, False)
>>> r9  = Interval(-100, True,  -100, True)
>>> r10 = Interval(-100, True,   100, False)
>>> r11 = Interval(-100, True,   100, True)
>>> r12 = Interval(-100, True,  None, False)
>>> r13 = Interval( 100, False, None, False)
>>> r14 = Interval( 100, True,   100, True)
>>> r15 = Interval( 100, True,  None, False)
>>> print r4 + r9
(-~,100]
>>> print r1 + r10
(-~,100)
>>> print r8 + r15
(-100,~)
>>> print r13 + r15
[100,~)
>>> print r7 + r11
[-100,100]
>>> print r12 + r15
[-100,~)
>>> print r2 + r13
Traceback (most recent call last):
    ...
ArithmeticError: The Intervals are disjoint.
>>> print r5 + r6
(-~,~)
>>> print r5 + r14
(-~,~)
>>> print r3 + r4
(-~,100]
__cmp__(self, other)
self is "less than" other if its lower bound is less than other's
smallest value.  If the smallest value is the same, then the 
Interval with the smallest upper bound is lesser.  Otherwise, they 
are equal.
 
>>> Interval(1, True, 1, True) < Interval(4, True, 4, True)
True
>>> Interval(None, False, 1, True) < Interval(4, True, 4, True)
True
>>> Interval(None, False, 5, True) < Interval(None, False, 5, False)
False
>>> Interval(None, False, 5, True) > Interval(None, False, 5, False)
True
>>> Interval(None, False, 5, True) == Interval(None, False, 5, True)
True
__contains__(self, obj)
Returns True if obj lies wholly within the Interval.
 
>>> all    = Interval(None, False, None, False)
>>> lt     = Interval(None, False, 10,   False)
>>> le     = Interval(None, False, 10,   True)
>>> some   = Interval(10,   False, 20,   True)
>>> single = Interval(10,   True,  10,   True)
>>> ge     = Interval(10,   True,  None, False)
>>> gt     = Interval(10,   False, None, False)
>>> ne     = Interval(17,   True,  17,   True)
>>> 10 in all
True
>>> 10 in lt
False
>>> 10 in le
True
>>> 10 in some
False
>>> 10 in single
True
>>> 10 in ge
True
>>> 10 in gt
False
>>> 10 in ne
False
>>> all in some
False
>>> lt in all
True
>>> lt in some
False
>>> single in ge
True
>>> ne in some
True
>>> set((4, 2, 6)) in some
False
>>> set((11, 13, 15)) in some
True
__init__(self, lbound, linc, ubound, uinc)
An Interval can represent an infinite set.
>>> r = Interval(None, False, None, False) # All values
 
An unbound portion of an Interval cannot be included; negative and
positive infinity are not true values.
>>> r = Interval(None, True, None, False) # Invalid Interval
Traceback (most recent call last):
    ...
ValueError: Unbound ends cannot be included in an interval.
>>> r = Interval(None, False, None, True) # Invalid Interval
Traceback (most recent call last):
    ...
ValueError: Unbound ends cannot be included in an interval.
 
An Interval can represent sets unbounded on an end.
>>> r = Interval(None, False, 62, False)
>>> r = Interval(None, False, 37, True)
>>> r = Interval(246, True, None, False)
>>> r = Interval(2468, False, None, False)
 
An Interval can represent a set of values up to, but not including a
value.
>>> r = Interval(25, False, 28, False)
 
An Interval can represent a set of values that have an inclusive
boundary.
>>> r = Interval(29, True, 216, True)
 
An Interval can represent a single value
>>> r = Interval(82, True, 82, True)
 
Intervals that are not normalized, i.e. that have a lower bound
exceeding an upper bound, are silently normalized.
>>> print Interval(5, False, 2, True)
[2,5)
 
Intervals can represent an empty set.
>>> r = Interval(5, False, 5, False)
__nonzero__(self)
An interval is non-zero if the interval is not empty.
 
>>> if Interval(12, False, 12, False):
...   print "Non-empty"
>>> if Interval(12, False, 12, True):
...   print "Non-empty"
>>> if Interval(12, True, 12, True):
...   print "Non-empty"
Non-empty
__str__(self)
This function yields a graphical representation of an Interval.  It 
is included in the __repr__ of an ISet.  Non-inclusive boundaries 
are bordered by a ( or ).  Inclusive boundaries are bordered by [ 
or ].  Unbound lower values are shown as -~, representing negative 
infinity.  Unbound upper values are shown as ~, representing 
infinity.  Intervals consisting of only a single value are shown as
that value.
 
>>> print Interval(None, False, None, False)
(-~,~)
>>> print Interval(None, False, 100, False)
(-~,100)
>>> print Interval(None, False, 2593, True)
(-~,2593]
>>> print Interval(2378, False, None, False)
(2378,~)
>>> print Interval(26, False, 8234, False)
(26,8234)
>>> print Interval(237, False, 2348, True)
(237,2348]
>>> print Interval(347, True, None, False)
[347,~)
>>> print Interval(237, True, 278, False)
[237,278)
>>> print Interval(723, True, 2378, True)
[723,2378]
>>> print Interval(5, True, 5, True)
5
adjacentTo(self, other)
Returns True if self is adjacent to other, meaning that if they were
joined, there would be no discontinuity.  They cannot overlap.
 
>>> r1  = Interval(None, False, -100, False)
>>> r2  = Interval(None, False, -100, True)
>>> r3  = Interval(None, False,  100, False)
>>> r4  = Interval(None, False,  100, True)
>>> r5  = Interval(None, False, None, False)
>>> r6  = Interval(-100, False,  100, False)
>>> r7  = Interval(-100, False,  100, True)
>>> r8  = Interval(-100, False, None, False)
>>> r9  = Interval(-100, True,  -100, True)
>>> r10 = Interval(-100, True,   100, False)
>>> r11 = Interval(-100, True,   100, True)
>>> r12 = Interval(-100, True,  None, False)
>>> r13 = Interval( 100, False, None, False)
>>> r14 = Interval( 100, True,   100, True)
>>> r15 = Interval( 100, True,  None, False)
>>> r1.adjacentTo(r6)
False
>>> r6.adjacentTo(r11)
False
>>> r7.adjacentTo(r9)
True
>>> r3.adjacentTo(r10)
False
>>> r5.adjacentTo(r14)
False
>>> r6.adjacentTo(r15)
True
>>> r1.adjacentTo(r8)
False
>>> r12.adjacentTo(r14)
False
>>> r6.adjacentTo(r13)
False
>>> r2.adjacentTo(r15)
False
>>> r1.adjacentTo(r4)
False
overlaps(self, other)
Returns True if the one range overlaps another.
 
>>> r1  = Interval(None, False, -100, False)
>>> r2  = Interval(None, False, -100, True)
>>> r3  = Interval(None, False,  100, False)
>>> r4  = Interval(None, False,  100, True)
>>> r5  = Interval(None, False, None, False)
>>> r6  = Interval(-100, False,  100, False)
>>> r7  = Interval(-100, False,  100, True)
>>> r8  = Interval(-100, False, None, False)
>>> r9  = Interval(-100, True,  -100, True)
>>> r10 = Interval(-100, True,   100, False)
>>> r11 = Interval(-100, True,   100, True)
>>> r12 = Interval(-100, True,  None, False)
>>> r13 = Interval( 100, False, None, False)
>>> r14 = Interval( 100, True,   100, True)
>>> r15 = Interval( 100, True,  None, False)
>>> r8.overlaps(r9)
False
>>> r12.overlaps(r6)
True
>>> r7.overlaps(r8)
True
>>> r8.overlaps(r4)
True
>>> r14.overlaps(r11)
True
>>> r10.overlaps(r13)
False
>>> r5.overlaps(r1)
True
>>> r5.overlaps(r2)
True
>>> r15.overlaps(r6)
False
>>> r3.overlaps(r1)
True

 
Functions
       
eq(n)
Returns an ISet of all values equal to n.
 
>>> print eq(0)
ISet: 0
>>> print eq(-23)
ISet: -23
exInterval(a, b)
Returns an ISet of all values between but excluding a and b.
 
>>> print exInterval(0, 100)
ISet: (0,100)
>>> print exInterval(-1, 1)
ISet: (-1,1)
ge(n)
Returns an ISet of all values greater than or equal to n.
 
>>> print ge(0)
ISet: [0,~)
>>> print ge(-23)
ISet: [-23,~)
gt(n)
Returns an ISet of all values greater than n.
 
>>> print gt(0)
ISet: (0,~)
>>> print gt(-23)
ISet: (-23,~)
incInterval(a, b)
Returns an ISet of all values between and including a and b.
 
>>> print incInterval(0, 100)
ISet: [0,100]
>>> print incInterval(-1, 1)
ISet: [-1,1]
le(n)
Returns an ISet of all values less than or equal to n.
 
>>> print le(0)
ISet: (-~,0]
>>> print le(-23)
ISet: (-~,-23]
lt(n)
Returns an ISet of all values less than n.
 
>>> print lt(0)
ISet: (-~,0)
>>> print lt(-23)
ISet: (-~,-23)
ne(n)
Returns an ISet of all values not equal to n.
 
>>> print ne(0)
ISet: (-~,0),(0,~)
>>> print ne(-23)
ISet: (-~,-23),(-23,~)

 
Data
        all = <iset.ISet instance>
empty = <iset.ISet instance>
none = <iset.ISet instance>