Compare commits

...

1 Commits

2 changed files with 64 additions and 31 deletions

View File

@@ -58,18 +58,11 @@ class Interval:
raise IntervalError("not a subset") raise IntervalError("not a subset")
return Interval(start, end) return Interval(start, end)
def set_difference(a, b): def _interval_math_helper(a, b, op, subset = True):
""" """Helper for set_difference, intersection functions,
Compute the difference (a \\ b) between the intervals in 'a' and to compute interval subsets based on a math operator on ranges
the intervals in 'b'; i.e., the ranges that are present in 'self' present in A and B. Subsets are computed from A, or new intervals
but not 'other'. are generated if subset = False."""
'a' and 'b' must both be iterables.
Returns a generator that yields each interval in turn.
Output intervals are built as subsets of the intervals in the
first argument (a).
"""
# Iterate through all starts and ends in sorted order. Add a # Iterate through all starts and ends in sorted order. Add a
# tag to the iterator so that we can figure out which one they # tag to the iterator so that we can figure out which one they
# were, after sorting. # were, after sorting.
@@ -84,31 +77,57 @@ def set_difference(a, b):
# At each point, evaluate which type of end it is, to determine # At each point, evaluate which type of end it is, to determine
# how to build up the output intervals. # how to build up the output intervals.
a_interval = None a_interval = None
b_interval = None in_a = False
in_b = False
out_start = None out_start = None
for (ts, k, i) in nilmdb.utils.iterator.imerge(a_iter, b_iter): for (ts, k, i) in nilmdb.utils.iterator.imerge(a_iter, b_iter):
if k == 0: if k == 0:
# start a interval
a_interval = i a_interval = i
if b_interval is None: in_a = True
out_start = ts
elif k == 1: elif k == 1:
# start b interval in_b = True
b_interval = i
if out_start is not None and out_start != ts:
yield a_interval.subset(out_start, ts)
out_start = None
elif k == 2: elif k == 2:
# end a interval in_a = False
if out_start is not None and out_start != ts:
yield a_interval.subset(out_start, ts)
out_start = None
a_interval = None
elif k == 3: elif k == 3:
# end b interval in_b = False
b_interval = None include = op(in_a, in_b)
if a_interval: if include and out_start is None:
out_start = ts out_start = ts
elif not include:
if out_start is not None and out_start != ts:
if subset:
yield a_interval.subset(out_start, ts)
else:
yield Interval(out_start, ts)
out_start = None
def set_difference(a, b):
"""
Compute the difference (a \\ b) between the intervals in 'a' and
the intervals in 'b'; i.e., the ranges that are present in 'self'
but not 'other'.
'a' and 'b' must both be iterables.
Returns a generator that yields each interval in turn.
Output intervals are built as subsets of the intervals in the
first argument (a).
"""
return _interval_math_helper(a, b, (lambda a, b: a and not b))
def intersection(a, b):
"""
Compute the intersection between the intervals in 'a' and the
intervals in 'b'; i.e., the ranges that are present in both 'a'
and 'b'.
'a' and 'b' must both be iterables.
Returns a generator that yields each interval in turn.
Output intervals are built as subsets of the intervals in the
first argument (a).
"""
return _interval_math_helper(a, b, (lambda a, b: a and b))
def optimize(it): def optimize(it):
""" """

View File

@@ -234,13 +234,16 @@ class TestInterval:
x = makeset("[--)") & 1234 x = makeset("[--)") & 1234
def do_test(a, b, c, d): def do_test(a, b, c, d):
# a & b == c # a & b == c (using nilmdb.server.interval)
ab = IntervalSet() ab = IntervalSet()
for x in b: for x in b:
for i in (a & x): for i in (a & x):
ab += i ab += i
eq_(ab,c) eq_(ab,c)
# a & b == c (using nilmdb.utils.interval)
eq_(IntervalSet(nilmdb.utils.interval.intersection(a,b)), c)
# a \ b == d # a \ b == d
eq_(IntervalSet(nilmdb.utils.interval.set_difference(a,b)), d) eq_(IntervalSet(nilmdb.utils.interval.set_difference(a,b)), d)
@@ -310,6 +313,17 @@ class TestInterval:
eq_(nilmdb.utils.interval.set_difference( eq_(nilmdb.utils.interval.set_difference(
a.intersection(list(c)[0]), b.intersection(list(c)[0])), d) a.intersection(list(c)[0]), b.intersection(list(c)[0])), d)
# Fill out test coverage for non-subsets
def diff2(a,b, subset):
return nilmdb.utils.interval._interval_math_helper(
a, b, (lambda a, b: b and not a), subset=subset)
with assert_raises(nilmdb.utils.interval.IntervalError):
list(diff2(a,b,True))
list(diff2(a,b,False))
# Empty second set
eq_(nilmdb.utils.interval.set_difference(a, IntervalSet()), a)
# Empty second set # Empty second set
eq_(nilmdb.utils.interval.set_difference(a, IntervalSet()), a) eq_(nilmdb.utils.interval.set_difference(a, IntervalSet()), a)