def generate_of_length(self, n, input):

        rule = list(self.rule.items())
        h = max( k[0] for k,v in rule ) + 1 if rule else 1
        w = max( k[1] for k,v in rule ) + 1 if rule else 1

        def permute(arr, perm):
            res = [None] * len(arr)
            for i in range(len(arr)):
                res[i] = arr[perm[i] - 1]
            return res

        def count_assignments(at, left):

            if at == len(rule):
                if left == 0:
                    yield []
            elif type(rule[at][1]) is PointPermutationSet:
                # this doesn't need to be handled separately,
                # it's just an optimization
                if left > 0:
                    for ass in count_assignments(at + 1, left - 1):
                        yield [1] + ass
            else:
                for cur in range(left+1):
                    for ass in count_assignments(at + 1, left - cur):
                        yield [cur] + ass

        for count_ass in count_assignments(0, n):

            cntz = [ [ 0 for j in range(w) ] for i in range(h) ]

            for i, k in enumerate(count_ass):
                cntz[rule[i][0][0]][rule[i][0][1]] = k

            rowcnt = [ sum( cntz[row][col] for col in range(w) ) for row in range(h) ]
            colcnt = [ sum( cntz[row][col] for row in range(h) ) for col in range(w) ]

            for colpart in product(*[ ordered_set_partitions(range(colcnt[col]), [ cntz[row][col] for row in range(h) ]) for col in range(w) ]):
                scolpart = [ [ sorted(colpart[i][j]) for j in range(h) ] for i in range(w) ]
                for rowpart in product(*[ ordered_set_partitions(range(rowcnt[row]), [ cntz[row][col] for col in range(w) ]) for row in range(h) ]):
                    srowpart = [ [ sorted(rowpart[i][j]) for j in range(w) ] for i in range(h) ]
                    for perm_ass in product(*[ s[1].generate_of_length(cnt, input) for cnt, s in zip(count_ass, rule) ]):
                        arr = [ [ [] for j in range(w) ] for i in range(h) ]

                        for i, perm in enumerate(perm_ass):
                            arr[rule[i][0][0]][rule[i][0][1]] = perm

                        res = [ [None]*colcnt[col] for col in range(w) ]

                        cumul = 1
                        for row in range(h-1,-1,-1):
                            for col in range(w):
                                for idx, val in zip(scolpart[col][row], permute(srowpart[row][col], arr[row][col])):
                                    res[col][idx] = cumul + val

                            cumul += rowcnt[row]

                        yield Permutation(flatten(res))
 def test_flatten(self):
     self.assertEqual([], flatten([]))
     self.assertEqual([1,2,3], flatten([1,2,3]))
     self.assertEqual([1,2,3], flatten([[1],2,3]))
     self.assertEqual([1,2,3], flatten([[1],(2,3)]))
     self.assertEqual([1,2,3], flatten([[1],([[(2,)]],3)]))
     self.assertEqual([1,2,3], flatten((1,2,[[[[[3]]]]])))
    def generate_of_length(self, n, input):

        rule = list(self.rule.items())
        h = max(k[0] for k, v in rule) + 1 if rule else 1
        w = max(k[1] for k, v in rule) + 1 if rule else 1

        def permute(arr, perm):
            res = [None] * len(arr)
            for i in range(len(arr)):
                res[i] = arr[perm[i] - 1]
            return res

        def count_assignments(at, left):

            if at == len(rule):
                if left == 0:
                    yield []
            elif type(rule[at][1]) is PointPermutationSet:
                # this doesn't need to be handled separately,
                # it's just an optimization
                if left > 0:
                    for ass in count_assignments(at + 1, left - 1):
                        yield [1] + ass
            else:
                for cur in range(left + 1):
                    for ass in count_assignments(at + 1, left - cur):
                        yield [cur] + ass

        for count_ass in count_assignments(0, n):
            for perm_ass in product(*[
                    s[1].generate_of_length(cnt, input)
                    for cnt, s in zip(count_ass, rule)
            ]):

                arr = [[[] for j in range(w)] for i in range(h)]

                for i, perm in enumerate(perm_ass):
                    arr[rule[i][0][0]][rule[i][0][1]] = perm

                rowcnt = [
                    sum(len(arr[row][col]) for col in range(w))
                    for row in range(h)
                ]
                colcnt = [
                    sum(len(arr[row][col]) for row in range(h))
                    for col in range(w)
                ]

                for colpart in product(*[
                        ordered_set_partitions(
                            range(colcnt[col]),
                            [len(arr[row][col]) for row in range(h)])
                        for col in range(w)
                ]):
                    for rowpart in product(*[
                            ordered_set_partitions(
                                range(rowcnt[row]),
                                [len(arr[row][col]) for col in range(w)])
                            for row in range(h)
                    ]):

                        ok = True

                        for idxs, perm_set in self.overlay:
                            res = [[None] * colcnt[col] for col in range(w)]

                            cumul = 1
                            for row in range(h - 1, -1, -1):
                                for col in range(w):

                                    if (row, col) in idxs:
                                        for idx, val in zip(
                                                sorted(colpart[col][row]),
                                                permute(
                                                    sorted(rowpart[row][col]),
                                                    arr[row][col])):
                                            res[col][idx] = cumul + val

                                cumul += rowcnt[row]

                            perm = Permutation.to_standard(flatten(res))
                            if not perm_set.contains(perm):
                                ok = False
                                break

                        if not ok:
                            continue

                        res = [[None] * colcnt[col] for col in range(w)]

                        cumul = 1
                        for row in range(h - 1, -1, -1):
                            for col in range(w):
                                for idx, val in zip(
                                        sorted(colpart[col][row]),
                                        permute(sorted(rowpart[row][col]),
                                                arr[row][col])):
                                    res[col][idx] = cumul + val

                            cumul += rowcnt[row]

                        yield Permutation(flatten(res))
Beispiel #4
0
    def get_elmnts(self, of_size):
        # Return permutations of length 'of_size' on a MeshTiling like this:
        #
        #      ------------------------
        #     |          | o |         |
        #     |----------+---+---------|
        #     | Av(31#2) |   | Av(1#2) |
        #      ------------------------
        #
        # The following code was shamelessly ported and adapted from
        # PermutaTriangle/grids repo, grids/Tilings.py file

        w = self.columns
        h = self.rows

        tiling = self.tiling

        def permute(arr, perm):
            res = [None] * len(arr)
            for i in range(len(arr)):
                res[i] = arr[perm[i]]
            return res

        def count_assignments(at, left):
            if at == len(self):
                # base case in recursion
                if left == 0:
                    yield []
            else:
                if tiling[at].is_point():
                    # one point in cell
                    if left > 0:
                        for ass in count_assignments(at + 1, left - 1):
                            yield [1] + ass
                elif tiling[at].is_empty():
                    # no point in cell
                    for ass in count_assignments(at + 1, left):
                        yield [0] + ass
                else:
                    for cur in range(left + 1):
                        for ass in count_assignments(at + 1, left - cur):
                            yield [cur] + ass

        elmnts_list = []
        for count_ass in count_assignments(0, of_size):
            cntz = [[0 for j in range(w)] for i in range(h)]

            for i, k in enumerate(count_ass):
                (col, row) = self.convert_linear_number_to_coordinates(i)
                cntz[row][col] = k

            rowcnt = [sum(cntz[ro][co] for co in range(w)) for ro in range(h)]
            colcnt = [sum(cntz[ro][co] for ro in range(h)) for co in range(w)]

            for colpart in product(*[
                    ordered_set_partitions(range(
                        colcnt[col]), [cntz[row][col] for row in range(h)])
                    for col in range(w)
            ]):
                scolpart = [[sorted(colpart[i][j]) for j in range(h)]
                            for i in range(w)]
                for rowpart in product(*[
                        ordered_set_partitions(range(
                            rowcnt[row]), [cntz[row][col] for col in range(w)])
                        for row in range(h)
                ]):
                    srowpart = [[sorted(rowpart[i][j]) for j in range(w)]
                                for i in range(h)]
                    for perm_ass in product(*[
                            s.get_permclass().of_length(cnt)
                            for cnt, s in zip(count_ass, tiling)
                    ]):
                        arr = [[[] for j in range(w)] for i in range(h)]

                        for i, perm in enumerate(perm_ass):
                            (col, row
                             ) = self.convert_linear_number_to_coordinates(i)
                            arr[row][col] = perm

                        res = [[None] * colcnt[col] for col in range(w)]

                        cumul = 0
                        for row in range(h):
                            for col in range(w):
                                for idx, val in zip(
                                        scolpart[col][row],
                                        permute(srowpart[row][col],
                                                arr[row][col])):
                                    res[col][idx] = cumul + val
                            cumul += rowcnt[row]
                        elmnts_list.append(Perm(flatten(res)))

        return elmnts_list