Пример #1
0
def deflated_tiling(tiling, cell, sum_decomp=True):
    """Return tiling where cell is deflated."""
    if sum_decomp:
        extra = Obstruction.single_cell(Perm((1, 0)), cell)
    else:
        extra = Obstruction.single_cell(Perm((0, 1)), cell)
    return Tiling(requirements=tiling.requirements,
                  obstructions=tiling.obstructions + (extra, ))
Пример #2
0
    def __init__(self, n=None, k=None, strategy_pack=None, flogger_kwargs={'processname': 'runner'},**kwargs):
        self.start_tilings = []
        if filename is not None:
            assert n == None and k == None
            f = open(filename, 'r')
            for line in f:
                line = line.strip()
                self.start_tilings.append(Tiling.from_string(line))
            f.close()
        else:
            for basis in combinations(PermSet(n), k):
                self.start_tilings.append(Tiling([Obstruction.single_cell(patt, (0, 0)) for patt in basis]))

        strategy_pack.ver_strats = [verify_points]

        function_kwargs = {"basis": []}
        function_kwargs.update(kwargs.get('kwargs', dict()))

        CombinatorialSpecificationSearcher.__init__(
            self,
            self.start_tilings[0],
            strategy_pack,
            function_kwargs=function_kwargs,
            **kwargs)

        self.start_labels = []
        for start_tiling in self.start_tilings:
            self.classdb.add(start_tiling, expandable=True)
            self.start_labels.append(self.classdb.get_label(start_tiling))
        for label in self.start_labels:
            self.classqueue.add_to_working(label)
Пример #3
0
def twist_one_by_ones(tiling):
    """
    Returns all tilings which can reached by twisting a single cell.
    """
    if tiling.requirements:
        raise NotImplementedError("Can't handle requirements")
    one_by_ones = set(tiling.active_cells)
    for ob in tiling.obstructions:
        if not one_by_ones:
            break
        if not ob.is_single_cell():
            for c in ob.pos:
                one_by_ones.discard(c)

    sym_sets = [
        antidiagonal_set, complement_set, inverse_set, rotate_90_clockwise_set,
        rotate_180_clockwise_set, rotate_270_clockwise_set
    ]
    cell_basis = tiling.cell_basis()
    twists = set()
    for cell in one_by_ones:
        av, _ = cell_basis[cell]
        for sym_set in sym_sets:
            sym_av = sym_set(av)
            twisted_obs = (
                [ob for ob in tiling.obstructions if cell not in ob.pos] +
                [Obstruction.single_cell(p, cell) for p in sym_av])
            twists.add(Tiling(twisted_obs))
    return set(twists)
Пример #4
0
def can_deflate(tiling, cell, sum_decomp):
    alone_in_row = tiling.only_cell_in_row(cell)
    alone_in_col = tiling.only_cell_in_col(cell)

    if alone_in_row and alone_in_col:
        return False

    deflate_patt = Obstruction.single_cell(
        Perm((1, 0)) if sum_decomp else Perm((0, 1)), cell)

    # we must be sure that no cell in a row or column can interleave
    # with any reinflated components, so collect cells that do not.
    cells_not_interleaving = set([cell])

    for ob in tiling.obstructions:
        if ob == deflate_patt:
            return False
        if ob.is_single_cell() or not ob.occupies(cell):
            continue
        number_points_in_cell = sum(1 for c in ob.pos if c == cell)
        if number_points_in_cell == 1:
            if len(ob) == 2:
                # not interleaving with cell as separating if
                # in same row or column
                other_cell = [c for c in ob.pos if c != cell][0]
                cells_not_interleaving.add(other_cell)
        elif number_points_in_cell == 2:
            if len(ob) != 3:
                return False
            patt_in_cell = ob.get_gridded_perm_in_cells((cell, ))
            if patt_in_cell != deflate_patt:
                # you can interleave with components
                return False
            # we need the other cell to be in between the intended deflate
            # patt in either the row or column
            other_cell = [c for c in ob.pos if c != cell][0]
            if (point_in_between(ob, True, cell, other_cell)
                    or point_in_between(ob, False, cell, other_cell)):
                # this cell does not interleave with inflated components
                cells_not_interleaving.add(other_cell)
            else:
                return False
        elif number_points_in_cell >= 3:
            # you can interleave with components
            return False
    # check that do not interleave with any cells in row or column.
    return (cells_not_interleaving >= tiling.cells_in_row(cell[1])
            and cells_not_interleaving >= tiling.cells_in_col(cell[0]))
Пример #5
0
    def __init__(self,
                 start_class,
                 strategy_pack,
                 # symmetry=False,
                 forward_equivalence=False,
                 logger_kwargs={'processname': 'runner'},
                 **kwargs):
        """Initialise TileScope."""
        if isinstance(start_class, str):
            basis = Basis([Perm.to_standard([int(c) for c in p])
                           for p in start_class.split('_')])
        elif isinstance(start_class, list):
            basis = Basis(start_class)
        elif isinstance(start_class, Tiling):
            start_tiling = start_class
            if start_class.dimensions == (1, 1):
                basis = Basis([o.patt for o in start_class.obstructions])
            else:
                basis = []

        if not isinstance(start_class, Tiling):
            start_tiling = Tiling(
                            obstructions=[Obstruction.single_cell(patt, (0, 0))
                                          for patt in basis])
        if strategy_pack.symmetries==True:
            symmetries = [Tiling.inverse, Tiling.reverse, Tiling.complement,
                          Tiling.antidiagonal, Tiling.rotate90,
                          Tiling.rotate180, Tiling.rotate270]
            # symmetries = [sym for sym in symmetries
                          # if sym(start_tiling) == start_tiling]
            strategy_pack.symmetries = symmetries
        else:
            symmetries = []

        function_kwargs = {"basis": basis}
        function_kwargs.update(kwargs.get('kwargs', dict()))

        CombinatorialSpecificationSearcher.__init__(
            self,
            start_tiling,
            strategy_pack,
            symmetry=symmetries,
            forward_equivalence=forward_equivalence,
            function_kwargs=function_kwargs,
            logger_kwargs=logger_kwargs,
            **kwargs)
Пример #6
0
def col_insertion_helper(tiling, col, col_cells, regions=False):
    if col_cells is None:
        col_cells = tiling.cells_in_col(col)
    col_req = tuple(Requirement.single_cell(Perm((0, )), c) for c in col_cells)
    col_obs = tuple(Obstruction.single_cell(Perm((0, )), c) for c in col_cells)
    if regions:
        return ([
            Tiling(tiling.obstructions + col_obs, tiling.requirements),
            Tiling(tiling.obstructions, tiling.requirements + (col_req, ))
        ], [{c: frozenset([c])
             for c in tiling.active_cells},
            {c: frozenset([c])
             for c in tiling.active_cells}])
    else:
        return [
            Tiling(tiling.obstructions + col_obs, tiling.requirements),
            Tiling(tiling.obstructions, tiling.requirements + (col_req, ))
        ]
Пример #7
0
def row_insertion_helper(tiling, row, row_cells, regions=False):
    if row_cells is None:
        row_cells = tiling.cells_in_row(row)
    row_req = tuple(Requirement.single_cell(Perm((0, )), c) for c in row_cells)
    row_obs = tuple(Obstruction.single_cell(Perm((0, )), c) for c in row_cells)
    if regions:
        return ([
            Tiling(tiling.obstructions + row_obs, tiling.requirements),
            Tiling(tiling.obstructions, tiling.requirements + (row_req, ))
        ], [{c: frozenset([c])
             for c in tiling.active_cells},
            {c: frozenset([c])
             for c in tiling.active_cells}])
    else:
        return [
            Tiling(tiling.obstructions + row_obs, tiling.requirements),
            Tiling(tiling.obstructions, tiling.requirements + (row_req, ))
        ]
def empty_cell_inferral(tiling, **kwargs):
    """The empty cell inferral strategy.

    The strategy considers each active but non-positive cell and inserts a
    point requirement. If the resulting tiling is empty, then a point
    obstruction can be added into the cell, i.e. the cell is empty."""
    active = set(tiling.active_cells)
    positive = set(tiling.positive_cells)
    empty_cells = []
    for cell in active - positive:
        reqtil = tiling.insert_cell(cell)
        if reqtil.is_empty():
            empty_cells.append(cell)
    newobs = [Obstruction.single_cell(Perm((0,)), cell)
              for cell in empty_cells]
    return InferralRule(
        "The cells {} are empty".format(", ".join(map(str, empty_cells))),
        Tiling(obstructions=tiling.obstructions + tuple(newobs),
               requirements=tiling.requirements))
Пример #9
0
 def __init__(self, avoids=tuple(), contains=tuple()):
     obs, reqs = stretch_av_and_co(avoids, contains, [(0, 0)])
     obs.extend([Obstruction.single_cell(Perm((0, 1)), (0, 0)),
                  Obstruction.single_cell(Perm((1, 0)), (0, 0))])
     reqs.extend([[Requirement.single_cell(Perm((0,)), (0, 0))]])
     self.tiling = Tiling(obs, reqs)
Пример #10
0
def place_requirement_list(tiling, req_list, direction, regions=False):
    """Return the list of tilings obtained by placing the direction-most point
    of a requirement list. This represents a batch strategy, where the
    direction-most point of each requirement in the list is placed."""
    # Compute the points furthest in the given direction.
    min_points = minimum_points(req_list, direction)
    if len([c for _, c in min_points]) != len(set([c for _, c in min_points])):
        # Can't handle list requirements with more than req farthest in the
        # direction in same cell.
        return None
    # For each tiling, compute the tiling where this point is placed furthest
    # in that direction.
    res = []
    if regions:
        forward_maps = []
    for (idx, cell), req in zip(min_points, req_list):
        # Placing the forced occurrence of the point in the requirement
        new_req, forced_obstructions = req.place_forced_point(idx, direction)
        assert len(new_req) == 1
        # Add the forced obstruction to ensure no other requirement has a point
        # further in that direction.
        forced_obstructions = (forced_obstructions + list(
            chain.from_iterable(
                r.other_req_forced_point(cell, direction)
                for r in req_list if r != req)))
        # New indices of the point
        point_cell = (cell[0] + 1, cell[1] + 1)
        # The set of new obstructions, consisting of the forced obstructions,
        # other obstructions where the point placement has been taken into
        # account and the 12, 21 in the cell.
        newobs = forced_obstructions + list(
            chain.from_iterable(
                ob.place_point(cell, DIR_NONE)
                for ob in tiling.obstructions)) + [
                    Obstruction.single_cell(Perm((0, 1)), point_cell),
                    Obstruction.single_cell(Perm((1, 0)), point_cell)
                ]
        # The rest of the requirements
        other_reqs = [reqs for reqs in tiling.requirements if reqs != req_list]
        # The new requirements, consisting of the requirement with the point
        # placed, other requirements where point placement has been taken into
        # account and the point requirement in the cell.
        newreqs = [
            list(
                chain.from_iterable(
                    r.place_point(cell, DIR_NONE) for r in reqs))
            for reqs in other_reqs
        ] + [new_req] + [[Requirement.single_cell(Perm((0, )), point_cell)]]
        placed_tiling = Tiling(newobs, newreqs)
        res.append(placed_tiling)
        if regions:

            def cell_map(c):
                mindex, minval = c
                maxdex = mindex + 1
                maxval = minval + 1
                if mindex >= cell[0]: maxdex += 2
                if minval >= cell[1]: maxval += 2
                if mindex > cell[0]: mindex += 2
                if minval > cell[1]: minval += 2
                return frozenset([(x, y) for x in range(mindex, maxdex)
                                  for y in range(minval, maxval)])

            forward_maps.append({c: cell_map(c) for c in tiling.active_cells})
    if regions:
        return res, forward_maps
    else:
        return res
Пример #11
0
def partial_place_point_of_requirement(tiling, req_index, point_index,
                                       force_dir):
    """
    Places the point at point_index in requirement at req_index into tiling on
    its own row or onto its own column depending on force_dir.
    """
    if len(tiling.requirements[req_index]) > 1:
        raise ValueError(
            "Requirement list at {} contains more than 1 requirement.".format(
                req_index))
    # Determine if placing onto own row or column
    row = (force_dir == DIR_NORTH or force_dir == DIR_SOUTH)
    # The requirement
    requirement = tiling.requirements[req_index][0]
    # The cell containing the point
    cell = requirement.pos[point_index]
    # The rest of the requirements
    other_reqs = [
        tiling.requirements[i] for i in range(len(tiling.requirements))
        if i != req_index
    ]
    # Placing the forced occurrence of the point in the requirement
    new_req, forced_obstructions = requirement.partial_place_forced_point(
        point_index, force_dir)
    assert len(new_req) == 1
    # New indices of the point.
    point_cell = (cell[0] if row else cell[0] + 1,
                  cell[1] + 1 if row else cell[1])
    # The set of new obstructions, consisting of the forced obstructions, other
    # obstructions where the point placement has been taken into account and
    # the 12, 21 in the cell.
    newobs = forced_obstructions + list(
        chain.from_iterable(
            ob.place_point(cell, DIR_NONE, partial=True, row=row)
            for ob in tiling.obstructions)) + [
                Obstruction.single_cell(Perm((0, 1)), point_cell),
                Obstruction.single_cell(Perm((1, 0)), point_cell)
            ]
    # If a point cell, make sure neighbouring cells are empty by adding the
    # point obstructions.
    if cell in tiling.point_cells:
        if force_dir == DIR_EAST or force_dir == DIR_WEST:
            newobs = (newobs + [
                Obstruction.single_cell(Perm((0, )),
                                        (point_cell[0] + 1, point_cell[1])),
                Obstruction.single_cell(Perm((0, )),
                                        (point_cell[0] - 1, point_cell[1]))
            ])
        elif force_dir == DIR_NORTH or force_dir == DIR_SOUTH:
            newobs = (newobs + [
                Obstruction.single_cell(Perm((0, )),
                                        (point_cell[0], point_cell[1] + 1)),
                Obstruction.single_cell(Perm((0, )),
                                        (point_cell[0], point_cell[1] - 1))
            ])
    # The new requirements, consisting of the requirement with the point
    # placed, other requirements where point placement has been taken into
    # account and the point requirement in the cell.
    newreqs = [
        list(
            chain.from_iterable(
                req.place_point(cell, DIR_NONE, partial=True, row=row)
                for req in reqs)) for reqs in other_reqs
    ] + [new_req] + [[Requirement.single_cell(Perm((0, )), point_cell)]]
    return Tiling(obstructions=newobs, requirements=newreqs)
Пример #12
0
def place_point_of_requirement(tiling, req_index, point_index, force_dir,
                               **kwargs):
    """
    Places the point at point_index in requirement at req_index into tiling.
    """
    if len(tiling.requirements[req_index]) > 1:
        raise ValueError(
            "Requirement list at {} contains more than 1 requirement.".format(
                req_index))
    # The requirement
    requirement = tiling.requirements[req_index][0]
    # The cell containing the point
    cell = requirement.pos[point_index]
    # The rest of the requirements
    other_reqs = [
        tiling.requirements[i] for i in range(len(tiling.requirements))
        if i != req_index
    ]
    # Placing the forced occurrence of the point in the requirement
    new_req, forced_obstructions = requirement.place_forced_point(
        point_index, force_dir)
    assert len(new_req) == 1
    # New indices of the point
    point_cell = (cell[0] + 1, cell[1] + 1)

    # The set of new obstructions, consisting of the forced obstructions, other
    # obstructions where the point placement has been taken into account and
    # the 12, 21 in the cell.
    newobs = forced_obstructions + list(
        chain.from_iterable(
            ob.place_point(cell, DIR_NONE) for ob in tiling.obstructions)) + [
                Obstruction.single_cell(Perm((0, 1)), point_cell),
                Obstruction.single_cell(Perm((1, 0)), point_cell)
            ]
    # The new requirements, consisting of the requirement with the point
    # placed, other requirements where point placement has been taken into
    # account and the point requirement in the cell.
    newreqs = [
        list(
            chain.from_iterable(
                req.place_point(cell, DIR_NONE) for req in reqs))
        for reqs in other_reqs
    ] + [new_req] + [[Requirement.single_cell(Perm((0, )), point_cell)]]

    placed_tiling = Tiling(obstructions=newobs, requirements=newreqs)
    if kwargs.get('regions', False):

        def cell_map(c):
            mindex, minval = c
            maxdex = mindex + 1
            maxval = minval + 1
            if mindex >= cell[0]:
                maxdex += 2
            if minval >= cell[1]:
                maxval += 2
            if mindex > cell[0]:
                mindex += 2
            if minval > cell[1]:
                minval += 2
            return set([
                placed_tiling.forward_map[(x, y)]
                for x in range(mindex, maxdex) for y in range(minval, maxval)
                if ((x, y) in placed_tiling.forward_map and placed_tiling.
                    forward_map[(x, y)] in placed_tiling.active_cells)
            ])

        return [placed_tiling], [{c: cell_map(c) for c in tiling.active_cells}]

    return placed_tiling