| Viewing file:  test.py (45.45 KB)      -rw-r--r-- Select action/file-type:
 
  (+) |  (+) |  (+) | Code (+) | Session (+) |  (+) | SDB (+) |  (+) |  (+) |  (+) |  (+) |  (+) | 
 
# Tests for nybitset
 # Note: uses assert statements for brevity,
 # so wouldn't check so much with python -O.
 
 from guppy.sets import *
 import pickle
 from time import process_time as clock
 import gc
 import random
 import sys
 try:
 import numpy.random
 except ImportError:
 has_numpy = 0
 else:
 has_numpy = 1
 
 if has_numpy:
 def random_integers_list(low, high, length):
 return list(map(int, numpy.random.random_integers(low, high, [length])))
 else:
 def random_integers_list(low, high, length):
 return [random.randint(low, high) for i in range(length)]
 
 
 Empty = immbitset()
 Omega = ~Empty
 bitsmut = mutbitset
 bitset = immbitset
 bitrange = immbitrange
 bitsingle = immbit
 
 
 def absorption(a, b):
 assert a & (a | b) == a
 assert a | (a & b) == a
 
 
 def associative(a, b, c):
 assert (a & b) & c == a & (b & c)
 assert (a | b) | c == a | (b | c)
 
 
 def commutative(a, b):
 assert a & b == b & a
 assert a | b == b | a
 
 
 def deMorgan(a, b, c=None):
 if c is None:
 assert ~(a & b) == ~a | ~b
 assert ~(a | b) == ~a & ~b
 else:
 assert c - (a & b) == (c - a) | (c - b)
 assert c - (a | b) == (c - a) & (c - b)
 
 
 def idempotence(a):
 assert a & a == a
 assert a | a == a
 
 
 def inclusion(a, b):
 assert a & b <= a
 assert a & b <= b
 assert a | b >= a
 assert a | b >= b
 
 
 def distributive(a, b, c):
 assert a | (b & c) == (a | b) & (a | c)
 assert a & (b | c) == (a & b) | (a & c)
 assert (a & b) | (b & c) | (c & a) == (a | b) & (b | c) & (c | a)
 assert not (a & b == a & c and a | b == a | c) or (b == c)
 
 
 def test_set_operations(as_, bs, cs):
 for a in as_:
 idempotence(a)
 for b in bs:
 inclusion(a, b)
 commutative(a, b)
 absorption(a, b)
 for c in cs:
 associative(a, b, c)
 distributive(a, b, c)
 deMorgan(a, b, c)
 
 
 def test_set_sub(as_, bs):
 def imp(a, b):
 assert not a or b
 for a in as_:
 for b in bs:
 imp(len(a) != len(b), a != b)
 imp(a < b, b > a and (not b < a))
 imp(a <= b, b >= a and (a < b or a == b) and not a > b)
 imp(a == b, a <= b and a >= b and not a != b and not b != a)
 imp(a != b, not a == b and not b == a)
 imp(a > b, b < a and not b > a)
 imp(a >= b, b <= a and (b < a or a == b) and not a < b)
 
 
 def test_set_len(as_, bs):
 # If a set can provide a len(), it should be convertible to a list
 for a in as_:
 assert len(a) == len(list(a))
 assert len(a & a) == len(a)
 assert len(a | a) == len(a)
 for b in bs:
 
 # Test len of binary ops
 
 assert len(a | b) == len(list(a | b))
 assert len(a & b) == len(list(a & b))
 assert len(a - b) == len(list(a - b))
 assert len(a ^ b) == len(list(a ^ b))
 
 
 def test_set_convert(as_, bs):
 for a in as_:
 for b in bs:
 # Conversions
 
 assert a | list(b) == a | b
 assert a - tuple(b) == a - b
 assert a & list(b) == a & b
 assert a ^ tuple(b) == a ^ b
 
 
 def eltime(f, args=(), N=1, retx=0):
 r = list(range(N))
 starttime = clock()
 for i in r:
 x = f(*args)
 endtime = clock()
 elapsed = endtime - starttime
 if retx:
 return elapsed, x
 else:
 return elapsed
 
 
 '.nython on'
 
 
 class IdSet(bitsmut):
 def append(self, x):
 bitsmut.append(self, id(x) // 12)
 
 def remove(self, x):
 bitsmut.remove(self, id(x) // 12)
 
 def __contains__(self, x):
 return bitsmut.__contains__(self, id(x) // 12)
 
 
 '.nython off'
 
 
 def add(a, b):
 c = b
 while c:
 a, c = a ^ c, (a & c) << 1
 print(a, c)
 return a
 
 
 def randint(lim=1 << 30):
 # Return a random signed int
 return int(random.randrange(-lim, lim))
 
 
 def randlong():
 a = randint()
 b = randint()
 ash = randint() & 255
 c = randint()
 d = randint()
 bsh = randint() & 255
 r = (a * b << ash) + (c * d << bsh)
 return r
 
 
 def dictset(l):
 ds = {}
 for e in l:
 if e not in ds:
 ds[e] = 1
 return ds
 
 
 def dslist(l):
 ds = dictset(l)
 ks = list(ds.keys())
 ks.sort()
 return ks
 
 
 def randlist(n, amp):
 ' randlist(n, amp) -> list of n unique random ints in [-amp,amp]'
 ds = {}
 rng = []  # To become a non-sorted list of unique random ints
 for i in range(10000):
 while 1:
 b = randint(50000)
 if b not in ds:
 rng.append(b)
 ds[b] = 1
 break
 return rng
 
 
 '.nython on'
 
 
 def t_append(a, b):
 ap = a.append
 for bit in b:
 ap(bit)
 
 
 def t_append_id(a, b):
 ap = a.append
 for bit in b:
 ap(id(bit) // 12)
 
 
 '.nython off'
 
 
 class Test:
 # Set to 1 if test should be faster (less exhaustive) than normally
 faster = 1
 
 def test0(self):
 pass
 
 def test1(self):
 import io
 f = io.StringIO()
 
 bitset([1, 3, 4]) | []
 bitset([1, 3, 4]) & []
 #bitset([1,3,4]) | {}
 # bitset([1,3,4]) & {}
 bitset([1, 3, 4]) | [5]
 bitset([1, 3, 4]) | list(range(100))
 bitset([1, 3, 4]) | list(range(100, -1, -1))
 
 empties = (
 bitset(),
 bitset([]),
 bitset(()),
 bitset(0),
 bitset(0),
 bitset(bitset())
 )
 print(empties, file=f)
 for e in empties:
 assert e is Empty
 
 bitset(0x1 << 30)
 bitset(0x1 << 32)
 
 print(bitset(0x8000), file=f)
 print(bitset((4,)), file=f)
 print(~bitset(0x8000), file=f)
 print(bitset([1]) | bitset(3), file=f)
 print(int(bitset([1])), file=f)
 print(int(bitset([1])), file=f)
 
 ms = bitset(0).mutcopy()
 msa = ms
 ms |= 1
 print(list(ms), file=f)
 ms |= 0x4000
 print(list(ms), file=f)
 ms |= [3, 4]
 print(list(ms), file=f)
 ms |= (6, 8)
 print(list(ms), file=f)
 ms |= bitset([7])
 print(list(ms), ms, file=f)
 ms |= bitset([37])
 ts = bitset(ms)
 print(ts, file=f)
 ms &= ts
 print(ms, file=f)
 
 ms &= 1
 print(ms, file=f)
 ms |= ts
 ms &= 0x4000
 print(list(ms), file=f)
 ms |= ts
 ms &= [3, 4]
 print(list(ms), file=f)
 ms |= ts
 ms &= (6, 8)
 print(list(ms), file=f)
 ms |= ts
 ms &= bitset([7])
 print(ms, file=f)
 
 ms |= ts
 ms &= ~bitset([6])
 print(ms, 'ts&.', ts & ~bitset([6]), file=f)
 
 ms ^= 1
 print(ms, file=f)
 ms ^= 0x4000
 print(list(ms), file=f)
 ms ^= [3, 4]
 print(list(ms), file=f)
 ms ^= (6, 8)
 print(list(ms), file=f)
 ms ^= bitset([7])
 
 print(ms, file=f)
 
 ms &= 0
 ms |= ts
 
 ms |= ~ts
 print(ms, 'mt', ms | ~ ts, ts | ~ts, ~bitset([]) | ~ts, file=f)
 
 xs = bitset(ms)
 
 ms |= 1
 print(ms, xs | 1, int(xs), int(xs), file=f)
 
 ms ^= ms
 print(ms, file=f)
 
 ms &= ~ms
 print(ms, int(ms), int(ms), file=f)
 
 ms |= -1
 print(ms, int(ms), file=f)
 ms &= -2
 print(ms, int(ms), file=f)
 ms ^= -4
 print(ms, int(ms), file=f)
 
 ms |= -1
 print(ms, int(ms), file=f)
 ms &= -2
 print(ms, int(ms), file=f)
 ms ^= -4
 print(ms, int(ms), file=f)
 
 ms |= bitset(-1)
 print(ms, int(ms), file=f)
 ms &= bitset(-2)
 print(ms, int(ms), file=f)
 
 assert ms is msa
 
 print(bitset(-1), file=f)
 print(bitset([-1]), file=f)
 print(bitset([-1]) | bitset([4]), file=f)
 
 assert f.getvalue() == """\
 (ImmBitSet([]), ImmBitSet([]), ImmBitSet([]), ImmBitSet([]), ImmBitSet([]), ImmBitSet([]))
 ImmBitSet([15])
 ImmBitSet([4])
 (~ImmBitSet([15]))
 ImmBitSet([0, 1])
 2
 2
 [0]
 [0, 14]
 [0, 3, 4, 14]
 [0, 3, 4, 6, 8, 14]
 [0, 3, 4, 6, 7, 8, 14] MutBitSet([0, 3, 4, 6, 7, 8, 14])
 ImmBitSet([0, 3, 4, 6, 7, 8, 14, 37])
 MutBitSet([0, 3, 4, 6, 7, 8, 14, 37])
 MutBitSet([0])
 [14]
 [3, 4]
 [6, 8]
 MutBitSet([7])
 MutBitSet([0, 3, 4, 7, 8, 14, 37]) ts&. ImmBitSet([0, 3, 4, 7, 8, 14, 37])
 MutBitSet([3, 4, 7, 8, 14, 37])
 [3, 4, 7, 8, 37]
 [7, 8, 37]
 [6, 7, 37]
 MutBitSet([6, 37])
 MutBitSet(~ImmBitSet([])) mt (~ImmBitSet([])) (~ImmBitSet([])) (~ImmBitSet([]))
 MutBitSet(~ImmBitSet([])) (~ImmBitSet([])) -1 -1
 MutBitSet([])
 MutBitSet([]) 0 0
 MutBitSet(~ImmBitSet([])) -1
 MutBitSet(~ImmBitSet([0])) -2
 MutBitSet([1]) 2
 MutBitSet(~ImmBitSet([])) -1
 MutBitSet(~ImmBitSet([0])) -2
 MutBitSet([1]) 2
 MutBitSet(~ImmBitSet([])) -1
 MutBitSet(~ImmBitSet([0])) -2
 (~ImmBitSet([]))
 ImmBitSet([-1])
 ImmBitSet([-1, 4])
 """
 
 def test2(self):
 # Test standard operators (not-inplace)
 for a in [randlong() for i in range(10)]:
 for b in [randlong() for j in range(10)]:
 ts = []
 for ta in (a, bitset(a), bitsmut(a)):
 for tb in (b, bitset(b), bitsmut(b)):
 tr = []
 tr.append(ta | tb)
 tr.append(ta & tb)
 tr.append(ta ^ tb)
 
 tr.append(ta | ~tb)
 tr.append(ta & ~tb)
 tr.append(ta ^ ~tb)
 
 tr.append(~ta | tb)
 tr.append(~ta & tb)
 tr.append(~ta ^ tb)
 
 tr.append(~ta | ~tb)
 tr.append(~ta & ~tb)
 tr.append(~ta ^ ~tb)
 ts.append(tr)
 
 for tr in ts[1:]:
 for r, x in zip(tr, ts[0]):
 assert int(r) == x
 
 def test3(self):
 # Test in-place operators
 p = randlong()
 op = randint()
 a = randlong()
 b = randlong()
 ts = []
 for tp in (p, bitset(p), bitsmut(p)):
 for ta in (a, bitset(a), bitsmut(a)):
 if op & 1:
 ta |= tp
 elif op & 2:
 ta &= tp
 elif op & 4:
 ta ^= tp
 for tb in (b, bitset(b), bitsmut(b)):
 tr = []
 tb |= ta
 tr.append(int(tb))
 tb &= ta
 tr.append(int(tb))
 tb ^= ta
 tr.append(int(tb))
 
 tb |= ~ta
 tr.append(int(tb))
 tb &= ~ta
 tr.append(int(tb))
 tb ^= ~ta
 tr.append(int(tb))
 ts.append(tr)
 
 for tr in ts[1:]:
 for r, x in zip(tr, ts[0]):
 assert int(r) == x
 
 def test4(self):
 # Some performance test
 def f1(n, x, y):
 while n > 0:
 x |= y
 x |= y
 x |= y
 x |= y
 x |= y
 n -= 1
 
 x = 0
 for exp in range(0, 1024*32, 16*32*(1+self.faster*31)):
 y = 1 << exp
 print(exp, eltime(f1, (1000, x, y)),
 eltime(f1, (1000, bitset(x), y)),
 eltime(f1, (1000, bitset(x), bitset(y))),
 eltime(f1, (1000, bitsmut(x), y)),
 eltime(f1, (1000, bitsmut(x), bitsmut(y))),
 eltime(f1, (1000, bitsmut(x), bitset(y))))
 
 def test5(self):
 # Bitset from sequences in different ways
 
 bits = {}
 for i in range(50):
 bit = randint()
 bits[bit] = 1
 bits[bit+randint() % 15] = 1
 bits[bit+randint() % 15] = 1
 bits[bit-randint() % 15] = 1
 bits[bit-randint() % 15] = 1
 bits = list(bits)
 sbits = list(bits)
 sbits.sort()
 
 def dictset(bits):
 return dict([(bit, 1) for bit in bits])
 
 seqs = [bits, tuple(bits), dictset(bits)]
 for seq in seqs:
 assert list(bitset(seq)) == sbits
 
 bs = Empty
 bs = bs | seq
 assert list(bs) == sbits
 bs = Empty
 bs = seq | bs
 assert list(bs) == sbits
 bs = Empty
 bs |= seq
 assert list(bs) == sbits
 bs = bitsmut(Empty)
 bs |= seq
 assert list(bs) == sbits
 
 bs = Empty
 bs = bs ^ seq
 assert list(bs) == sbits
 bs = Empty
 bs = seq ^ bs
 assert list(bs) == sbits
 bs = Empty
 bs ^= seq
 assert list(bs) == sbits
 bs = bitsmut(Empty)
 bs ^= seq
 assert list(bs) == sbits
 
 bs = Omega
 bs = bs & seq
 assert list(bs) == sbits
 bs = Omega
 bs = seq & bs
 assert list(bs) == sbits
 bs = Omega
 bs &= seq
 assert list(bs) == sbits
 bs = bitsmut(Omega)
 bs &= seq
 assert list(bs) == sbits
 
 bs = Omega
 bs = bs ^ seq
 bs = ~bs
 assert list(bs) == sbits
 bs = Omega
 bs = seq ^ bs
 bs = ~bs
 assert list(bs) == sbits
 bs = Omega
 bs ^= seq
 bs = ~bs
 assert list(bs) == sbits
 bs = bitsmut(Omega)
 bs ^= seq
 bs = ~bs
 assert list(bs) == sbits
 
 def test6(self):
 # Comparisons
 for a in (randlong(),):
 for b in (a, ~a, randlong()):
 assert ((bitset(a) == bitset(b)) == (a == b))
 assert ((bitset(a) != bitset(b)) == (a != b))
 assert ((bitset(a) == ~bitset(b)) == (a == ~b))
 assert ((bitset(a) != ~bitset(b)) == (a != ~b))
 assert ((~bitset(a) == bitset(b)) == (~a == b))
 assert ((~bitset(a) != bitset(b)) == (~a != b))
 assert ((~bitset(a) == ~bitset(b)) == (~a == ~b))
 assert ((~bitset(a) != ~bitset(b)) == (~a != ~b))
 
 assert ((bitsmut(a) == bitsmut(b)) == (a == b))
 assert ((bitsmut(a) != bitsmut(b)) == (a != b))
 
 assert ((bitsmut(a) == bitset(b)) == (a == b))
 assert ((bitsmut(a) != bitset(b)) == (a != b))
 
 assert ((bitset(a) == bitsmut(b)) == (a == b))
 assert ((bitset(a) != bitsmut(b)) == (a != b))
 
 def test7(self):
 # Bitsmut gymnastics
 import io
 f = io.StringIO()
 
 a = bitsmut(0)
 print(str(a), file=f)
 a.append(1)
 print(str(a), a.pop(), str(a), file=f)
 a.append(1)
 print(str(a), a.pop(-1), str(a), file=f)
 a.append(1)
 print(str(a), a.pop(0), str(a), file=f)
 a.append(1)
 a.append(2)
 a.append(3)
 print(str(a), a.pop(), str(a), file=f)
 print(str(a), a.pop(0), str(a), file=f)
 a.remove(2)
 print(str(a), file=f)
 
 print(f.getvalue())
 assert f.getvalue() == """\
 MutBitSet([])
 MutBitSet([1]) 1 MutBitSet([])
 MutBitSet([1]) 1 MutBitSet([])
 MutBitSet([1]) 1 MutBitSet([])
 MutBitSet([1, 2, 3]) 3 MutBitSet([1, 2])
 MutBitSet([1, 2]) 1 MutBitSet([2])
 MutBitSet([])
 """
 
 def f(a, b):
 ap = a.append
 for bit in b:
 ap(bit)
 
 def flu(a, b):
 s = 0
 for bit in b:
 if bit in a:
 s += 1
 return s
 
 def g(a, b):
 for bit in b:
 a[bit] = 1
 
 def h(a, b):
 for bit in b:
 a |= bitsingle(bit)
 
 def tms(rng, f=f):
 ms = bitsmut(0)
 t = eltime(f, (ms, rng))
 srng = list(rng)
 srng.sort()
 assert ms == bitset(srng)
 return t
 
 def tmslu(rng, n=None):
 if n is None:
 n = len(rng)
 ms = bitsmut(rng[:n])
 elt, s = eltime(flu, (ms, rng), retx=1)
 assert s == n
 return elt
 
 def tbslu(rng, n=None):
 if n is None:
 n = len(rng)
 ms = bitset(rng[:n])
 elt, s = eltime(flu, (ms, rng), retx=1)
 assert s == n
 return elt
 
 def tlo(rng):
 lo = 0
 
 def f(a, b):
 for bit in b:
 a |= 1 << b
 return eltime(h, (lo, rng))
 
 def tbs(rng):
 lo = bitset()
 
 def f(a, b):
 for bit in b:
 a |= bitsingle(b)
 return eltime(h, (lo, rng))
 
 def tls(rng):
 ls = []
 return eltime(f, (ls, rng))
 
 def tds(rng):
 ds = {}
 return eltime(g, (ds, rng))
 
 def tdslu(rng, n=None):
 if n is None:
 n = len(rng)
 ds = dict([(x, 1) for x in rng[:n]])
 elt, s = eltime(flu, (ds, rng), retx=1)
 assert s == n
 return elt
 
 step = (1 + self.faster*5)
 
 for rng in (list(range(0, 10000, step)),
 list(range(0, 100000, step)),
 list(range(10000, -1, -1*step)),
 randlist(10000, 50000-self.faster*40000)):
 print(tms(rng), tds(rng), tls(rng), tms(rng, h),
 tmslu(rng), tbslu(rng), tdslu(rng),
 tmslu(rng, 100), tbslu(rng, 100), tdslu(rng, 100))
 
 rng = list(range(10000))
 print(tlo(rng), tbs(rng))
 
 def test8(self):
 # Subclassing a bitsmut
 BS = IdSet
 for bs in (BS(), BS([]), BS([0])):
 os = ((), [], {})
 for o in os:
 bs.append(o)
 for o in os:
 assert o in bs
 for o in os:
 bs.remove(o)
 for o in os:
 assert o not in bs
 
 def test9(self):
 # Making bigger bitsmuts - testing the split
 for i in (1000, 10000, 100000):
 r = list(range(i))
 m = bitsmut(r)
 assert list(m) == r
 
 la = random_integers_list(-i, i, i)
 m = bitsmut(la)
 las = dslist(la)
 bs = bitset(m)
 assert list(bs) == las
 
 def test10(self):
 
 # Performance test
 
 def tests(la):
 for i in (1000, 10000, 100000, 400000):
 print('eltime(bitset, (la[:%d],))' % i)
 print(eltime(bitset, (la[:i],)))
 la = list(range(400000))
 print('la = range(400000)')
 tests(la)
 la.reverse()
 print('la.reverse()')
 tests(la)
 la = random_integers_list(-400000, 400000, 400000)
 print('la=random_integers_list(-400000,400000,400000))')
 tests(la)
 
 def test11(self, n=1):
 # A specific bug showed when setting splitting_size
 la = random_integers_list(-400000, 400000, 400000)
 while n > 0:
 ms = bitsmut([])
 ms._splitting_size = 100
 ms |= la
 print('test11', n, ms._indisize, ms._num_seg)
 n -= 1
 
 def test12(self):
 # append should be able to reuse space that was pop()'d
 # even for other bit ranges
 # Due to allocation strategy, the size may differ an
 # initial round but should then be stable.
 
 for N in (32, 64, 128, 256, 31, 33, 63, 65, 255, 257):
 ms = bitsmut()
 
 # Train it
 rng = list(range(N))
 ms |= rng
 for popix in (-1, 0):
 for j in range(N):
 ms.pop(popix)
 ms |= rng
 # Now should be stable..
 indisize = ms._indisize
 for popix in (-1, 0):
 for i in range(0, N*10, N):
 pops = []
 for j in range(N):
 pops.append(ms.pop(popix))
 assert list(ms) == []
 if popix == -1:
 pops.reverse()
 assert pops == rng
 rng = list(range(i, i+N))
 ms |= rng
 assert indisize == ms._indisize
 assert list(ms) == rng
 
 def test13(self):
 # append, remove for inverted bitsmuts,
 # have inverted sense. 'nonzero' is always true.
 # (pop is not supported - it seems it conceptually should give infite range of bits)
 
 ms = bitsmut()
 assert not ms
 ms ^= ~0        # Make it inverted - contains 'all bits'
 assert ms
 ms.remove(0)
 assert ms
 assert list(~ms) == [0]
 try:
 ms.remove(0)
 except ValueError:
 pass
 else:
 raise AssertionError('expected ValueError for remove')
 ms.append(0)
 assert list(~ms) == []
 try:
 ms.append(0)
 except ValueError:
 pass
 else:
 raise AssertionError('expected ValueError for append')
 
 ms.remove(0)
 try:
 ms.pop()
 except ValueError:
 pass
 else:
 raise AssertionError('expected ValueError for pop')
 
 def test14(self):
 # Test the bitrange() constructor
 xs = (-1000, -100, -33, -32, -31, -10, -
 1, 0, 1, 10, 31, 32, 33, 100, 1000)
 for lo in xs:
 assert list(bitrange(lo)) == list(range(lo))
 for hi in xs:
 assert list(bitrange(lo, hi)) == list(range(lo, hi))
 for step in (1, 2, 3, 4, 5, 6, 7, 31, 32, 33):
 r = list(range(lo, hi, step))
 assert list(bitrange(lo, hi, step)) == r
 
 def test15(self):
 # Test the indexing
 # Only index 0 or -1 is currently supported, for first or last bit -
 # the others would take more work and might appear surprisingly slow.
 
 for a in range(-33, 34):
 for b in range(a+1, a+35):
 rng = list(range(a, b))
 bs = bitrange(a, b)
 assert bs[0] == a
 assert bs[-1] == b-1
 ms = bitsmut(bs)
 assert ms[0] == a
 assert ms[-1] == b-1
 i = 0
 while ms:
 x = ms[i]
 assert x == ms.pop(i)
 assert x == rng.pop(i)
 i = -1 - i
 
 def test16(self):
 # Test shifting
 for sh in range(64):
 for v in range(64):
 assert int(bitset(v) << sh) == int(v) << sh
 
 maxint = sys.maxsize
 minint = -maxint - 1
 
 b = bitset([0])
 
 for sh in (maxint, -maxint, minint):
 assert b << sh == bitset([sh])
 
 def tsv(bs, sh):
 try:
 bs << sh
 except OverflowError:
 pass
 else:
 raise AssertionError('expected OverflowError')
 
 tsv(bitset([maxint]), 1)
 tsv(bitset([minint]), -1)
 tsv(bitset([-maxint]) << (-1), -1)
 
 for a, b in ((0, 10), (0, 10000), (-1000, 1000)):
 for sh in (-257, -256, -255, -1, 0, 1, 255, 256, 257):
 for step in (1, 2, 3):
 assert bitrange(a, b, step) << sh == bitrange(
 a+sh, b+sh, step)
 
 def test17(self):
 # Comparisons: inclusion tests
 
 for a in (0, 1, 2, list(range(31)), list(range(32)), list(range(33)), randlong()):
 for b in (0, 1, 2, list(range(31)), list(range(32)), list(range(33)), randlong()):
 for as_ in (bitset(a), ~bitset(a), bitsmut(a), bitsmut(~bitset(a))):
 for bs in (as_, ~as_, bitset(b), ~bitset(b), bitsmut(b), bitsmut(~bitset(b))):
 t = as_ <= bs
 assert t == (bs >= as_)
 assert t == ((as_ & bs) == as_)
 assert t == ((int(as_) & int(bs)) == int(as_))
 
 t = as_ < bs
 assert t == (bs > as_)
 assert t == ((as_ <= bs) and (as_ != bs))
 assert t == ((as_ <= bs) and (int(as_) != int(bs)))
 
 def test18(self):
 # Testing internal consistency, with test values
 # that may not be practical to convert to longs.
 # Using Properties of Boolean algebras
 # (from 'Mathematichal Handbook'... tables p.30, p.15)
 # Some tests should be quite redundant given others passed,
 # but are kept anyway for reference & doublechecking.
 
 any = [bitset(abs(randlong())) << randint(),
 bitset(abs(randlong())) << randint(),
 bitset(abs(randlong())) << randint() | bitset(
 abs(randlong())) << randint(),
 bitset(abs(randlong())) << randint() | bitset(
 abs(randlong())) << randint(),
 ]
 
 any = [Empty, Omega, bitset([0]),
 bitset(randlong()),
 bitset(randlong())] + [a ^ randlong() for a in any]
 any = any + [bitsmut(a) for a in any]
 for a in any:
 # Empty and Omega are the least and greatest elements
 assert Empty <= a <= Omega
 assert a & Empty == Empty
 assert a | Omega == Omega
 # Identity elements for & and |
 assert a & Omega == a
 assert a | Empty == a
 # Complement laws
 assert a & ~a == Empty
 assert a | ~a == Omega
 assert ~Empty == Omega
 assert ~Omega == Empty
 assert ~(~a) == a
 
 idempotence(a)
 for b in any:
 # Relative complement, definition
 assert a & ~b == a - b
 # ...
 absorption(a, b)
 commutative(a, b)
 deMorgan(a, b)
 inclusion(a, b)
 for c in any:
 associative(a, b, c)
 distributive(a, b, c)
 
 # ...
 assert ((a <= b) == (a & b == a) == (a | b == b) ==
 (a & ~b == Empty) == (~b <= ~a) == (~a | b == Omega))
 
 # Symmetric difference
 # From p. 15
 assert a ^ b == b ^ a
 for c in any:
 assert (a ^ b) ^ c == a ^ (b ^ c)
 deMorgan(a, b, c)
 assert a ^ Empty == a
 assert a ^ a == Empty
 assert a ^ b == (a & ~b) | (b & ~a)
 
 def test19(self):
 # Finding prime numbers using the Sieve of Eratosthenes
 # - an excercise for eg bitrange().
 
 N = 4000
 
 primes = ([2] | bitrange(3, N, 2)).mutcopy()
 for i in bitrange(3, N // 2, 2):
 primes &= ~bitrange(2 * i, N, i)
 
 primes = list(primes)
 assert len(primes) == 550
 assert primes[:10] == [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
 assert primes[399] == 2741
 assert primes[549] == 3989
 return primes
 
 def test20(self):
 # Some bitrange arguments used when debugging its optimized version.
 # Entered here, in case some wasn't covered by previous tests.
 maxint = sys.maxsize
 minint = -maxint - 1
 for a in (
 (32,),
 (31,),
 (33,),
 (13,),
 (1, 33),
 (1, 33, 2),
 (1, 63, 2),
 (0, 64, 32),
 (0, 64+17, 32),
 (0, 32*3, 32),
 (0, 32*3+1, 32),
 (0, 32*4, 32),
 (0, 32*4, 16),
 (0, 32*2, 16),
 (0, 32*3, 16),
 (maxint-32, maxint),
 (maxint-32, maxint, 2),
 (maxint-32, maxint, 4),
 (maxint-32, maxint, 16),
 (maxint-32, maxint, 20),
 (maxint-320, maxint),
 (maxint-320, maxint, 2),
 (maxint-320, maxint, 4),
 (maxint-320, maxint, 16),
 (maxint-320, maxint, 20),
 (-1, maxint, maxint),
 (0, maxint, maxint),
 (1, maxint, maxint),
 (minint, maxint, maxint),
 (minint, maxint, maxint//32),
 (minint, maxint, maxint//320),
 (minint, maxint, -(minint//32)),
 (minint, maxint, -(minint//320)),
 ):
 br = bitrange(*a)
 assert list(br) == list(range(*a))
 
 try:
 bitrange(minint, maxint, 1)
 except OverflowError:
 pass
 else:
 raise AssertionError('expected OverflowError')
 
 # a more exhaustive check,
 # it tests some > 70000 combinations if not self.faster
 if not self.faster:
 print('bitrange testing many combinations, this may take some time...')
 for a in range(0, 34, 1 + 8*self.faster):
 print('a', a, end=' ')
 sys.stdout.flush()
 for l in range(1000, 1034, 1 + 8*self.faster):
 for st in range(1, 34, 1 + 8*self.faster):
 for arg in ((maxint - l, maxint - a, st),
 (minint + a, minint + l, st)):
 br = bitrange(*arg)
 assert list(br) == list(range(*arg))
 print('done')
 
 def test21(self):
 # Test bitset as dict key - i.e. hashing, equality
 D = {}
 a = bitrange(1)
 b = bitrange(1)
 c = ~a
 d = ~b
 D[a] = 1
 D[c] = -1
 assert D[b] == D[a] == 1
 assert D[c] == D[d] == -1
 
 def test22(self):
 # Test pickling
 any = [bitset() for x in range(10)]
 any = any + [bitrange(x, y, z)
 for x in (-1000, 0, 1000)
 for y in (2000,)
 for z in (1, 3, 300)]
 any = any + [~x for x in any]
 any = any + [bitsmut(x) for x in any]
 for a in any:
 for bin in (0, 1):
 da = pickle.dumps(a, bin)
 aa = pickle.loads(da)
 assert aa == a
 assert type(aa) is type(a)
 
 def test23(self):
 # bitset from general sequence with iterator
 # We already special-cased list, tuple & dict
 
 class T:
 def __init__(self, data):
 self.data = data
 
 def __iter__(self):
 return iter(self.data)
 
 l = list(range(10))
 t = T(l)
 b = bitset(t)
 assert list(b) == l
 
 bo100 = b | T([100])
 assert list(bo100) == l + [100]
 
 ms = bitsmut(t)
 assert ms == b
 
 ms |= T([100])
 assert ms == bo100
 
 def test24(self):
 # tests to do with the copy-on-write optimizations
 # this should show in improved timing for some operation sequences
 
 def f1(n):
 return bitrange(n).mutcopy()[0]
 
 t, v = eltime(f1, (10000000,), retx=1)
 print(t)
 assert v == 0
 
 bs = bitrange(10000000)
 
 def f2(bs):
 ms = bs.mutcopy()
 ms &= ~1
 return ms[0], bs[0]
 
 t, v = eltime(f2, (bs,), retx=1)
 print(t)
 assert v == (1, 0)
 
 ms = bs.mutcopy()
 
 # Test that a temporary immutable copy can be fast
 
 def f3(ms):
 bs = bitset(ms)
 return ms[0], bs[0],
 
 t, v = eltime(f3, (ms,), retx=1)
 print(t)
 assert v == (0, 0)
 
 def f4(ms):
 bs = bitset(ms)
 ms &= ~1
 return ms[0], bs[0],
 
 def f4b(ms):
 # make sure cur_field is cleared when bitset is made
 ms |= 1
 bs = bitset(ms)
 ms ^= 1
 return ms[0], bs[0],
 
 for f in (f4, f4b):
 ms = bs.mutcopy()
 
 t, v = eltime(f, (ms,), retx=1)
 print(t)
 assert v == (1, 0)
 
 ms = bs.mutcopy()
 
 # Test that a temporary mutable copy of a bitsmut can be fast
 
 def f5(ms):
 mc = ms.mutcopy()
 return mc[0], ms[0],
 
 t, v = eltime(f5, (ms,), retx=1)
 print(t)
 assert v == (0, 0)
 
 # Test that a temporary mutable copy of a bitsmut can be fast
 # and still be separately updated
 
 def f6(ms):
 ms &= ~bitrange(15)
 mc = ms.mutcopy()
 mc |= [2]
 ms |= [4]
 return mc[0], ms[0],
 
 def f6a(ms):
 # as f6 but updating in the other order - tried to induce a bug
 ms &= ~bitrange(15)
 mc = ms.mutcopy()
 ms |= [4]
 mc |= [2]
 return mc[0], ms[0],
 
 def f6b(ms):
 # working harder and managed to provoke test of a noticed copy-on-write
 # requirement (cur_field had to be cleared when the set was borrowed)
 ms &= ~bitrange(15)
 ms |= [8]
 mc = ms.mutcopy()
 ms |= [1, 4]
 mc |= [2]
 ms &= ~bitsingle(1)
 return mc[0], ms[0],
 
 for f in (f6, f6a, f6b):
 t, v = eltime(f, (ms,), retx=1)
 print(t)
 assert v == (2, 4)
 
 # Temporary mutable copy of splitted bitsmut
 
 for f in (f6, f6a, f6b):
 bs = bitrange(100000) | bitrange(200000, 300000)
 ms = bs.mutcopy()
 
 ms |= bitsingle(150000)     # Force a split
 
 assert ms._num_seg > 1
 print('num_seg', ms._num_seg)
 
 t, v = eltime(f, (ms,), retx=1)
 print(t)
 assert v == (2, 4)
 
 def test25(self):
 # Thing that came up
 # converting to int should fail here, not become negative.
 # (Assuming 'standard' 2-complement int representation)
 
 bs = bitset(int(sys.maxsize)+1)
 # try:
 #     a = int(bs)
 # except OverflowError:
 #     pass
 # else:
 #     raise AssertionError('expected OverflowError')
 
 assert int(bs) == int(sys.maxsize)+1
 
 # These border cases should pass
 assert int(bitset(sys.maxsize)) == sys.maxsize
 assert int(bitset(-sys.maxsize - 1)) == - sys.maxsize - 1
 
 def test26(self):
 # len() tests
 
 for thelen in [0, 15, 17, 31, 33, 1023, 1024, 1025, int(1e7)]:
 for args in [(thelen,), (0, thelen * 3, 3)]:
 bs = bitrange(*args)
 t, v = eltime(len, (bs,), retx=1)
 if t > 0.01:
 print(t, v)
 assert v == thelen
 
 bs = bitsmut(bs)
 
 t, v = eltime(len, (bs,), retx=1)
 if t > 0.01:
 print(t, v)
 assert v == thelen
 
 def test27(self):
 # slices
 for b in (bitset(64), bitrange(64), bitset(abs(randlong()))):
 for st in (b, b.mutcopy()):
 for i in (1, 2, 3, 30, 31, 32, 33, 34, 63, 64, 65):
 assert b[:i] == bitset(list(b)[:i])
 assert b[-i:] == bitset(list(b)[-i:])
 
 def test28(self):
 # test & set; test & clr
 for s in (bitsmut(), bitsmut(~bitset() & ~bitset([14]))):
 assert s.tas(14) == 0
 assert s.tas(14) == 1
 assert s.tac(14) == 1
 assert s.tac(14) == 0
 
 def test29(self):
 # Compatibility functions added:
 # add, discard, -, -=
 # Also tests S.mutcopy() where S is mutable with 1 or 2 segments
 
 def t(p):
 q = p.mutcopy()
 p.add(17)
 assert p != q
 q.append(17)
 assert p == q
 
 p.discard(-1)
 assert p == q
 p.discard(17)
 assert p != q
 q.remove(17)
 assert p == q
 
 r = p - q
 assert r == bitsmut([])
 
 ms = bitsmut(12345)
 t(ms)
 
 bs = bitrange(20, 100000) | bitrange(200000, 300000)
 ms = bs.mutcopy()
 
 ms |= bitsingle(150000)  # Force a split
 assert ms._num_seg > 1
 
 t(ms)
 
 all = 0, -1, 1, -2, 2, randlong(), -randlong()
 all = [bitsmut(a) for a in all]
 all = all + [bitsmut(a) for a in all]
 for a in all:
 a = a.mutcopy()
 aa = a.mutcopy()
 for b in all:
 a -= b
 aa &= ~b
 assert a == aa
 
 def test30(self):
 # Test nodeset
 
 nodeset = immnodeset
 ns = mutnodeset()
 ns0 = ns
 a = []
 b = ()
 c = {}
 d = 0
 e = ''
 
 # Test 5 ways to add elements
 
 ns.add(a)
 ns.append(b)
 ns |= nodeset([c])
 assert not ns.tas(d)
 ns ^= [e]
 
 assert ns == nodeset([a, b, c, d, e])
 
 # Test 5 ways to remove elements
 
 ns ^= [e]
 assert ns == nodeset([a, b, c, d])
 assert ns.tac(d)
 assert ns == nodeset([a, b, c])
 ns -= nodeset([c])
 assert ns == nodeset([a, b])
 ns.remove(b)
 assert ns == nodeset([a])
 ns.discard(a)
 assert ns == nodeset([])
 
 # Test pop
 ns.add(a)
 assert ns.pop() is a
 try:
 ns.pop()
 except ValueError:
 pass
 else:
 raise AssertionError('expected ValueError')
 
 assert ns0 is ns
 
 ns = immnodeset(ns)
 
 ns |= nodeset([a])
 assert ns == nodeset([a])
 assert ns is not ns0
 
 # ns is now immutable
 # this is like bitset
 # see note per Wed Jan 21 16:13:55 MET 2004
 # The change was made after that.
 
 ns1 = ns
 
 ns -= nodeset([a])
 
 # See note above. The following check
 # applies since mutability behaviour is as for bitset
 
 assert ns is not ns1
 
 assert ns == nodeset([])
 
 # Test clear
 
 ns = mutnodeset([1, 2, 3])
 assert len(ns) == 3
 ns.clear()
 assert len(ns) == 0
 assert list(ns) == []
 
 def test31(self):
 # Test nodeset, element-wise operations & object deallocation w. gc
 
 H = mutnodeset
 from sys import getrefcount as grc
 
 e1 = []
 e2 = []
 e3 = []
 r1 = grc(e1)
 r2 = grc(e2)
 r3 = grc(e3)
 
 s = H()
 s.add(e1)
 assert e1 in s
 assert e2 not in s
 s.append(e2)
 assert e2 in s
 assert s.tas(e3) == 0
 
 assert e3 in s
 
 assert r1 + 1 == grc(e1)
 assert r2 + 1 == grc(e2)
 assert r3 + 1 == grc(e3)
 
 assert s.tas(e3) == 1
 assert s.tac(e3) == 1
 assert s.tac(e3) == 0
 s.discard(e3)
 s.remove(e2)
 
 try:
 s.append(e1)
 except ValueError:
 pass
 else:
 raise AssertionError('no exception from append')
 
 s.remove(e1)
 
 try:
 s.remove(e1)
 except ValueError:
 pass
 else:
 raise AssertionError('no exception from remove')
 
 assert r1 == grc(e1)
 assert r2 == grc(e2)
 assert r3 == grc(e3)
 
 s.add(e1)
 s.add(e2)
 s.add(e3)
 
 s = None
 
 assert r1 == grc(e1)
 assert r2 == grc(e2)
 assert r3 == grc(e3)
 
 # Test gc support
 
 import gc
 
 s = H()
 s.append(e1)
 s.append(s)     # Make it cyclic
 assert s in s
 s = None
 gc.collect()
 assert r1 == grc(e1)
 
 s = H()
 s.append(e1)
 s.append(e2)
 e2.append(s)    # Make it cyclic
 s = None
 e2 = None
 gc.collect()
 assert r1 == grc(e1)
 
 def test32(self):
 # Test extended NodeSet functionality
 
 H = immnodeset
 import gc
 from sys import getrefcount as grc
 
 gc.collect()
 e1 = []
 e2 = []
 e3 = []
 r1 = grc(e1)
 r2 = grc(e2)
 r3 = grc(e3)
 
 s = H([e1, e2])
 
 assert e1 in s and e2 in s and not e3 in s
 
 s3 = H([e1, e3])
 
 s |= s3
 assert e3 in s
 assert e2 in s
 s &= s3
 assert e2 not in s
 assert e1 in s
 
 la = [], [e1], [e1, e2], [e1, e2, e3], [e2], [e2, e3], [e3], [e1, e3, e3, e1]
 
 ss = [H(x) for x in la]
 
 test_set_operations(ss, ss, ss)
 test_set_len(ss, ss)
 test_set_sub(ss, ss)
 test_set_convert(ss, ss)
 
 for a in ss:
 for b in ss:
 
 # Not supported...yet..
 for x in (
 'assert list(b) | a == a | b',
 'assert list(b) & a == a & b',
 ):
 try:
 exec(x, {'a': a, 'b': b}, {})
 except TypeError:
 pass
 else:
 raise Exception('Expected TypeError')
 
 ss = s = s3 = la = a = b = c = x = None
 gc.collect()
 gc.collect()
 
 assert r1 == grc(e1)
 assert r2 == grc(e2)
 assert r3 == grc(e3)
 
 def test33(self):
 # Test with multiple segments - so that code
 # in union_realloc is covered
 # I am unsure if any of the other tests used more segments than 2
 # It is a bit tricky (and implementation-dependent)
 # to make it make a specific number of segments.
 
 # The testing with 20 segments will make 3 reallocations:
 # to make place for 8, 16 and 24 segments.
 
 numseg = 20
 
 bs = bitset()
 
 for i in range(numseg):
 bs |= bitrange(i*2*100000+20, (i*2+1)*100000)
 
 ms = bs.mutcopy()
 mss = []
 
 assert ms._num_seg == 1
 
 for i in range(numseg-1):
 mss.append(ms.mutcopy())
 ms |= bitsingle((i*2+1)*100000+50000)
 assert ms._num_seg == i+2
 
 # Test that the copies were separate copies (Testing copy-on-write)
 
 for i in range(numseg-1):
 assert mss[i] == bs
 bs |= bitsingle((i*2+1)*100000+50000)
 
 def test34(self):
 # Test nodeset inheritance
 # This leaks in Python 2.3.3; whether or not H is MutNodeSet or list.
 H = MutNodeSet
 e1 = []
 
 class X(H):
 def extend(self, y):
 for e in y:
 self.append(e)
 
 s = X()
 assert e1 not in s
 s.extend([e1])
 assert e1 in s
 
 def test35(self):
 # Test bitset inheritance
 
 for i in range(2):
 # An error didn't show until second time around
 
 for H in ImmBitSet, MutBitSet:
 class X(H):
 bitnames = ['red', 'green', 'blue']
 
 def __new__(clas, *args):
 return H.__new__(clas, [clas.bitnames.index(x) for x in args])
 
 def __iter__(self):
 for bit in H.__iter__(self):
 yield self.bitnames[bit]
 
 def __str__(self):
 return '{%s}' % (', '.join(self))
 
 def __eq__(self, other):
 return str(self) == str(other)
 
 x = X()
 x = X('red', 'blue')
 assert list(x) == ['red', 'blue']
 
 # Test different kinds of construction args
 
 assert (H.__new__(X, )) == '{}'
 assert (H.__new__(X, immbitset(1))) == '{red}'
 assert (H.__new__(X, mutbitset(2))) == '{green}'
 assert (H.__new__(X, 3)) == '{red, green}'
 assert (H.__new__(X, 4)) == '{blue}'
 
 if H is ImmBitSet:
 x = X('red', 'blue')
 import guppy.sets.setsc
 # See that we can pass a subtype to CplBitSet
 assert(str(guppy.sets.setsc.CplBitSet(x))
 == "(~ImmBitSet(['red', 'blue']))")
 
 
 class MemStat:
 def __init__(self):
 self.nrefs = {}
 from guppy import Root
 self.R = R = Root()
 self.V = R.guppy.heapy.View
 self.P = R.guppy.heapy.Path
 self.xmemstats = R.guppy.heapy.heapyc.xmemstats
 #self.alset = R.guppy.heapy.heapyc.set_alset()
 
 # self.mark()
 
 def mark(self):
 self.R.gc.collect()
 h = self.V.horizon()
 h.update(gc.get_objects())
 self.h = h
 
 def dump(self):
 gc.collect()
 self.xmemstats()
 
 V = self.V
 R = self.R
 P = self.P
 nrefs = self.nrefs
 
 try:
 co = sys.getcounts()
 except AttributeError:
 pass
 else:
 for (name, allo, free, max) in co:
 nref = allo - free
 if name not in nrefs or nref != nrefs[name]:
 print((name, nref), end=' ', file=sys.stderr)
 nrefs[name] = nref
 print(file=sys.stderr)
 h = self.h = n = co = name = allo = free = max = l = i = None
 # self.mark()
 #self.alset = None
 # R.guppy.heapy.heapyc.clr_alset()
 gc.collect()
 #self.alset = R.guppy.heapy.heapyc.set_alset()
 
 
 def test_nums(numbers, dump=None):
 enufuncs = []
 for n in numbers:
 enufuncs.append((n, getattr(t, 'test%d' % n)))
 for n, f in enufuncs:
 print('Test #%d' % n)
 f()
 if dump is not None:
 dump()
 
 
 def test_leak():
 import gc
 # Test 34 is known to leak in Python 2.3.3.
 nums = list(range(36))
 nums.remove(34)
 ms = MemStat()
 i = 0
 while 1:
 test_nums(nums, ms.dump)
 gc.collect()
 i += 1
 
 
 def test_main():
 test_nums(list(range(36)))
 
 
 t = Test()
 
 if __name__ == '__main__':
 # test_leak()
 # t.test25()
 # t.test30()
 test_main()
 # test_nums(range(30, 36))
 # test_nums(range(13,35))
 
 |