コード例 #1
0
ファイル: compute.py プロジェクト: dpetrovych/nonopy
        def inplace():
            self.metrics.add_event(('sub_collapse', 'inplace'))
            move_space = calculate_moves(task, len(field_line))
            if len(task) == 1 and move_space == 0:
                return CollapseResult.filled(len(field_line), 1)

            count = calculate_count(task, len(field_line))
            if move_space >= max(task):
                return CollapseResult.empty(len(field_line), count)

            def stack_left_ends():
                start = 0
                for block in task:
                    yield start + block
                    start += block + MIN_BLOCK_SPACE

            def stack_right_starts():
                start = move_space
                for block in task:
                    yield start
                    start += block + MIN_BLOCK_SPACE

            filled_indecies = [
                i
                for start, end in zip(stack_right_starts(), stack_left_ends())
                for i in range(start, end)
            ]

            line = np.full(len(field_line), Cell.EMPTY, Cell.dtype)
            line[filled_indecies] = Cell.FILLED
            return CollapseResult(line, count)
コード例 #2
0
ファイル: reducer.py プロジェクト: dpetrovych/nonopy
    def test_5_results(self):
        reducer = SlimReducer()

        result = reducer.reduce([
            CollapseResult(stoline('|001110 |'), 2),
            None,
            CollapseResult(stoline('|  00111|'), 5),
            None,
            CollapseResult(stoline('|   111 |'), 7)
        ], 7)

        self.assertArrayEqual(result.line, stoline('|    1  |'))
        self.assertEqual(result.count, 14)
コード例 #3
0
ファイル: compute.py プロジェクト: dpetrovych/nonopy
            def task_division(block_index, block_pos):
                def bum(cond):
                    return MIN_BLOCK_SPACE if cond else 0

                block = task[block_index]
                block_end = block_pos + block
                left_bum = bum(block_index > 0)
                right_bum = bum(block_index < (len(task) - 1))

                left_edge = block_pos - left_bum
                right_edge = block_end + right_bum

                if (left_edge < 0 or right_edge > len(field_line) or
                    (field_line[left_edge:block_pos] == Cell.FILLED).any() or
                    (field_line[block_end:right_edge] == Cell.FILLED).any()):
                    return None

                left_result, right_result, total_count = self.run_sides(
                    left=CollapseRun(task[:block_index],
                                     field_line[:left_edge]),
                    right=CollapseRun(task[block_index + 1:],
                                      field_line[right_edge:]))

                if total_count == 0:
                    return None

                return CollapseResult.join(*left_result.line,
                                           *Cells.x(left_bum),
                                           *Cells.f(block),
                                           *Cells.x(right_bum),
                                           *right_result.line,
                                           count=total_count)
コード例 #4
0
    def reduce(self, results, length):
        '''Combine results from multiple divisions

        Args:
            combinations (Iterable[CollapsedResult|None]): iterable of all division results
            length (int): length of a line/section

        Returns:
            CollapseResult|None: a reduction result
        '''
        non_empty_results = [
            *filter(lambda result: result is not None, results)
        ]
        if len(non_empty_results) == 0:
            return None

        count = sum(l.count for l in non_empty_results)
        collapsed = np.array([l.line for l in non_empty_results], Cell.dtype)

        reduced = (Cell.FILLED if
                   (column == Cell.FILLED).all() else Cell.CROSSED if
                   (column == Cell.CROSSED).all() else Cell.EMPTY
                   for column in collapsed.T)

        return CollapseResult(np.fromiter(reduced, Cell.dtype, length), count)
コード例 #5
0
    def reduce(self, results, length):
        '''Combine results from multiple divisions as steam on each cycle to a single accumulated value

        Args:
            combinations (Iterable[CollapsedResult|None]): iterable of all division results
            length (int): length of a line/section

        Returns:
            CollapseResult|None: a reduction result
        '''
        accumulated = None
        count = 0
        for result in results:
            if result is None:
                continue

            count += result.count

            if accumulated is None:
                accumulated = result.line.copy()
                continue

            for i in range(length):
                if accumulated[i] != result.line[i]:
                    accumulated[i] = Cell.EMPTY

        return CollapseResult(accumulated, count) if accumulated is not None else None
コード例 #6
0
ファイル: reducer.py プロジェクト: dpetrovych/nonopy
    def test_2_results(self):
        reducer = SlimReducer()

        result = reducer.reduce(
            [CollapseResult(stoline('|0011100|'), 1), None], 7)

        self.assertArrayEqual(result.line, stoline('|0011100|'))
        self.assertEqual(result.count, 1)
コード例 #7
0
ファイル: compute.py プロジェクト: dpetrovych/nonopy
            def task_division(i):
                left_result, right_result, total_count = self.run_sides(
                    left=CollapseRun(task[:i], field_line[:x_start]),
                    right=CollapseRun(task[i:], field_line[x_end:]))

                if total_count == 0:
                    return None

                return CollapseResult.join(*left_result.line,
                                           *Cells.x(x_end - x_start),
                                           *right_result.line,
                                           count=total_count)
コード例 #8
0
ファイル: compute.py プロジェクト: dpetrovych/nonopy
    def __collapse(self, task: Task, field_line: FieldLine):
        """Recursive function that calculates (collapses) all combinations of a segment of tasks 
            on a specific segment of field line.

        Args:
            task (Task): line task or a segment of the task
            field_line (FieldLine): line on the field or its continuos segment

        Returns:
            CollapsedResult: a new state of a line or its segment
        """
        def divide_by_crossed(x_start, x_end):
            self.metrics.add_event(('sub_collapse', 'divide_by_crossed'))

            def task_division(i):
                left_result, right_result, total_count = self.run_sides(
                    left=CollapseRun(task[:i], field_line[:x_start]),
                    right=CollapseRun(task[i:], field_line[x_end:]))

                if total_count == 0:
                    return None

                return CollapseResult.join(*left_result.line,
                                           *Cells.x(x_end - x_start),
                                           *right_result.line,
                                           count=total_count)

            division_results = (task_division(i)
                                for i in range(len(task), -1, -1))

            return self.__reduce(division_results, len(field_line))

        def divide_by_filled(f_start, f_end):
            self.metrics.add_event(('sub_collapse', 'divide_by_filled'))

            def task_division(block_index, block_pos):
                def bum(cond):
                    return MIN_BLOCK_SPACE if cond else 0

                block = task[block_index]
                block_end = block_pos + block
                left_bum = bum(block_index > 0)
                right_bum = bum(block_index < (len(task) - 1))

                left_edge = block_pos - left_bum
                right_edge = block_end + right_bum

                if (left_edge < 0 or right_edge > len(field_line) or
                    (field_line[left_edge:block_pos] == Cell.FILLED).any() or
                    (field_line[block_end:right_edge] == Cell.FILLED).any()):
                    return None

                left_result, right_result, total_count = self.run_sides(
                    left=CollapseRun(task[:block_index],
                                     field_line[:left_edge]),
                    right=CollapseRun(task[block_index + 1:],
                                      field_line[right_edge:]))

                if total_count == 0:
                    return None

                return CollapseResult.join(*left_result.line,
                                           *Cells.x(left_bum),
                                           *Cells.f(block),
                                           *Cells.x(right_bum),
                                           *right_result.line,
                                           count=total_count)

            blocks_placement = [(i, f_end - block, f_start)
                                for i, block in enumerate(task)
                                if block >= (f_end - f_start)]

            division_results = (task_division(i, pos)
                                for i, pos_start, pos_end in blocks_placement
                                for pos in range(pos_start, pos_end + 1))

            return self.__reduce(division_results, len(field_line))

        def inplace():
            self.metrics.add_event(('sub_collapse', 'inplace'))
            move_space = calculate_moves(task, len(field_line))
            if len(task) == 1 and move_space == 0:
                return CollapseResult.filled(len(field_line), 1)

            count = calculate_count(task, len(field_line))
            if move_space >= max(task):
                return CollapseResult.empty(len(field_line), count)

            def stack_left_ends():
                start = 0
                for block in task:
                    yield start + block
                    start += block + MIN_BLOCK_SPACE

            def stack_right_starts():
                start = move_space
                for block in task:
                    yield start
                    start += block + MIN_BLOCK_SPACE

            filled_indecies = [
                i
                for start, end in zip(stack_right_starts(), stack_left_ends())
                for i in range(start, end)
            ]

            line = np.full(len(field_line), Cell.EMPTY, Cell.dtype)
            line[filled_indecies] = Cell.FILLED
            return CollapseResult(line, count)

        if len(task) == 0 or (len(task) == 1 and task[0] == 0):
            return CollapseResult.crossed(len(field_line), 1)

        if (pos_x := field_line.find_center_crossed()) != (None, None):
            return divide_by_crossed(*pos_x)