def odd_even_mergesort(self, A): if len(A) == 1: return A if int(log2(len(A))) != log2(len(A)): # accurate to about 2**48 raise ValueError("Length of list must be a power of 2 to odd-even merge sort") evens = A[::2] odds = A[1::2] sorted_evens = self.odd_even_mergesort(evens) sorted_odds = self.odd_even_mergesort(odds) return self.odd_even_merge(sorted_evens, sorted_odds)
def Sorter_(self, equation, polarity=None): explode = sum(([a] * c for c, a in equation), []) nterms = len(explode) explode.extend([False] * (2**ceil(log2(nterms)) - nterms)) def cmp(a, b): aa, bb = explode[a], explode[b] explode[a], explode[b] = self.Or(aa, bb, polarity), self.And(aa, bb, polarity) def merge(lo, hi, r): step = r * 2 if step < hi - lo: merge(lo, hi, step) merge(lo + r, hi, step) for i in range(lo + r, hi - r, step): cmp(i, i + r) else: cmp(lo, lo + r) def sort(lo, hi): if hi - lo >= 1: mid = lo + ((hi - lo) // 2) sort(lo, mid) sort(mid + 1, hi) merge(lo, hi, 1) sort(0, len(explode) - 1) return explode
def build_sorter(self, linear): if not linear: return [] sorter_input = [] for coeff, atom in linear.equation: sorter_input += [atom] * coeff next_power_of_2 = 2**ceil(log2(len(sorter_input))) sorter_input += [false] * (next_power_of_2 - len(sorter_input)) return self.odd_even_mergesort(sorter_input)
def build_sorter(self, linear): if not linear: return [] sorter_input = [] for coeff, atom in linear.equation: sorter_input += [atom]*coeff next_power_of_2 = 2**ceil(log2(len(sorter_input))) sorter_input += [false]*(next_power_of_2 - len(sorter_input)) return self.odd_even_mergesort(sorter_input)
def test_odd_even_mergesort(): for n in [1, 2, 4, 8]: A = list(range(1, n + 1)) C = Clauses(n) S = C.odd_even_mergesort(A) # Note, the zero-one principle states we only need to test lists of # 0's and # 1's. https://en.wikipedia.org/wiki/Sorting_network#Zero-one_principle. for sol in my_itersolve(C.clauses): a = [i in sol for i in A] s = [i in sol for i in S] assert s == sorted(a, reverse=True) # TODO: n > 8 takes too long to test all combinations, but maybe we should test # some random combinations. assert raises(ValueError, lambda: Clauses(5).odd_even_mergesort([1, 2, 3, 4, 5])) # Make sure it works with booleans for n in [1, 2, 4]: for item in product(*[[true, false]] * n): assert list(Clauses(0).odd_even_mergesort(item)) == sorted( item, reverse=True) # The most important use-case is extending a non-power of 2 length list # with false. for n in range(1, 9): next_power_of_2 = 2**ceil(log2(n)) assert n <= next_power_of_2 for item in product(*[[true, false]] * (next_power_of_2 - n)): A = list(range(1, n + 1)) + list(item) C = Clauses(n) S = C.odd_even_mergesort(A) for sol in my_itersolve(C.clauses): a = [ boolize(i) if isinstance(boolize(i), bool) else i in sol for i in A ] s = [ boolize(i) if isinstance(boolize(i), bool) else i in sol for i in S ] assert s == sorted(a, reverse=True), (a, s, sol)
def test_odd_even_mergesort(): for n in [1, 2, 4, 8]: A = list(range(1, n+1)) C = Clauses(n) S = C.odd_even_mergesort(A) # Note, the zero-one principle states we only need to test lists of # 0's and # 1's. https://en.wikipedia.org/wiki/Sorting_network#Zero-one_principle. for sol in my_itersolve(C.clauses): a = [i in sol for i in A] s = [i in sol for i in S] assert s == sorted(a, reverse=True) # TODO: n > 8 takes too long to test all combinations, but maybe we should test # some random combinations. assert raises(ValueError, lambda: Clauses(5).odd_even_mergesort([1, 2, 3, 4, 5])) # Make sure it works with booleans for n in [1, 2, 4]: for item in product(*[[true, false]]*n): assert list(Clauses(0).odd_even_mergesort(item)) == sorted(item, reverse=True) # The most important use-case is extending a non-power of 2 length list # with false. for n in range(1, 9): next_power_of_2 = 2**ceil(log2(n)) assert n <= next_power_of_2 for item in product(*[[true, false]]*(next_power_of_2 - n)): A = list(range(1, n + 1)) + list(item) C = Clauses(n) S = C.odd_even_mergesort(A) for sol in my_itersolve(C.clauses): a = [boolize(i) if isinstance(boolize(i), bool) else i in sol for i in A] s = [boolize(i) if isinstance(boolize(i), bool) else i in sol for i in S] assert s == sorted(a, reverse=True), (a, s, sol)