Last active
December 14, 2018 22:25
-
-
Save kurtbrose/e191ddf1bcf0b5d1574c7bef43594627 to your computer and use it in GitHub Desktop.
some utilities for walking over all possible sets of pairs with a minimum number of creations / deletions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import itertools, math | |
| def pairwise_walk(items): | |
| ''' | |
| given a list of items, return a list of instructions of which | |
| ordered pairs of relationships to add or remove, in order to | |
| go over every possible set of pairwise relationships existing | |
| or not existing while only adding or removing one at a time | |
| assumes that reflexive pairs of an item to itself should be excluded | |
| >>> pairwise_walk('abc') | |
| [('+', ('a', 'b')), ('+', ('a', 'c')), ('-', ('a', 'b')), ('+', ('b', 'c')), | |
| ('+', ('a', 'b')), ('-', ('a', 'c')), ('-', ('a', 'b'))] | |
| ''' | |
| pairs = [ | |
| pair for pair in itertools.product(items[:-1], items[1:]) | |
| if pair[0] != pair[1]] | |
| walk = gray_walk(len(pairs)) | |
| return [(step[0], pairs[step[1]]) for step in walk] | |
| def gray_walk(n): | |
| ''' | |
| given a number of elements n, returns a "gray walk" | |
| which uses gray encoding to add or remove one element' | |
| at a time such that each possible permutation of n | |
| is visited once | |
| (assuming you start from having no elements) | |
| elements are encoded as '+' or '-' for add or remove, | |
| and then the integer of the index | |
| >>> gray_walk(3) | |
| [('+', 0), ('+', 1), ('-', 0), ('+', 2), ('+', 0), ('-', 1), ('-', 0)] | |
| this should be interpreted as | |
| "add the 0th element, add the 1st element, remove the 0th element" | |
| ''' | |
| # https://en.wikipedia.org/wiki/Gray_code | |
| gray_codes = [i ^ (i >> 1) for i in range(2**n)] | |
| # >>> ["{:03b}".format(i ^ (i >> 1)) for i in range(2**3)] | |
| # ['000', '001', '011', '010', '110', '111', '101', '100'] | |
| walk = [] | |
| for pre, post in zip(gray_codes[:-1], gray_codes[1:]): | |
| if post > pre: | |
| walk.append(('+', int(math.log(post - pre, 2)))) | |
| if pre > post: | |
| walk.append(('-', int(math.log(pre - post, 2)))) | |
| return walk |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment