Advertisement
JoelSjogren

bintri.py

Mar 28th, 2016
197
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 2.72 KB | None | 0 0
  1. from collections import Counter
  2. from itertools import product
  3.  
  4. def naive_encode(n):
  5.     return '[' + '[]'*n + ']'
  6.  
  7. def encode(n):
  8.     assert n == int(n) and n >= 0
  9.     terms = []
  10.     while n > 0:
  11.         terms.append(encode(log2(n)))
  12.         n -= 2**log2(n)
  13.     return '[' + ''.join(terms) + ']'
  14.  
  15. def decode(xs):
  16.     return sum(2**decode(i) for i in parse(xs))
  17.  
  18. def add(xs, ys):
  19.     return xs[:-1] + ys[1:]
  20.  
  21. def mul(xs, ys):
  22.     terms = (add(i, j) for i, j in product(parse(xs), parse(ys)))
  23.     return '[' + ''.join(terms) + ']'
  24.  
  25. def canonicalize(xs):
  26.     terms = map(canonicalize, parse(xs))
  27.     iterate = True
  28.     while iterate:
  29.         new_terms = []
  30.         iterate = False
  31.         for i, j in Counter(terms).items():
  32.             if j == 1:
  33.                 new_terms.append(i)
  34.             else:
  35.                 fewer = (canonicalize(add(i, k)) for k in parse(encode(j)))
  36.                 new_terms.extend(fewer)
  37.                 iterate = True
  38.         terms = new_terms
  39.     return '[' + ''.join(sorted(terms)) + ']'
  40.  
  41. def log2(n):
  42.     x = 0
  43.     while 2**x <= n:
  44.         x += 1
  45.     return x - 1
  46.  
  47. def parse(xs):
  48.     # parse("[[a][b][c]]") = ["[a]", "[b]", "[c]"]
  49.     terms = []
  50.     depth = 0
  51.     for i, j in enumerate(xs):
  52.         if j == '[':
  53.             depth += 1
  54.             if depth == 2:
  55.                 start = i
  56.         if j == ']':
  57.             depth -= 1
  58.             if depth == 1:
  59.                 end = i+1
  60.                 terms.append(xs[start:end])
  61.         assert depth > 0 or i == len(xs)-1, 'Bad string {}'.format(xs)
  62.     assert depth == 0, 'Bad string {}'.format(xs)
  63.     return terms
  64.  
  65. def run_tests():
  66.     for i in range(1000):
  67.         # No information is lost
  68.         assert i == decode(encode(i))
  69.        
  70.         # Canonicalization is not needed after encode
  71.         assert encode(i) == canonicalize(naive_encode(i))
  72.        
  73.         # Todo: randomize binary strings xs and assert that
  74.         #       canonicalize(xs) == encode(decode(xs)).
  75.     print('All OK')
  76.  
  77. def verify_youtube_examples():
  78.     examples = (
  79.         (1, ('[[]]',)),
  80.         (2, ('[[][]]', '[[[]]]')),
  81.         (3, ('[[][][]]', '[[[]][]]')),
  82.         (4, ('[[][][][]]', '[[[]][[]]]', '[[[[]]]]')),
  83.         (5, ('[[][][][][]]', '[[[]][[]][]]', '[[[[]]][]]')),
  84.         (65536, ('[[[[[[]]]]]]',)),
  85.         (2**65536, ('[[[[[[[]]]]]]]',))
  86.     )
  87.     for i, j in examples:
  88.         print(i if i != 2**65536 else '2^65536', end=' ')
  89.         for k in j:
  90.             assert i == decode(k)
  91.             print('=', k, end=' ')
  92.         assert j[-1] == canonicalize(j[-1])
  93.         print('(canonical)')
  94.  
  95. def scroll(n, delay=0):
  96.     import time
  97.     for i in range(n):
  98.         print(encode(i))
  99.         time.sleep(delay)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement