Beispiel #1
0
    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)
Beispiel #2
0
    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)
Beispiel #3
0
    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
Beispiel #4
0
 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)
Beispiel #5
0
 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)
Beispiel #6
0
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)
Beispiel #7
0
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)