Exemple #1
0
def components(tiling):
    """Return the component of a tiling. Two cells are in the same component if
    they are in the same row or column."""
    n, m = tiling.dimensions

    def cell_to_int(cell):
        return cell[0] * m + cell[1]

    def int_to_cell(i):
        return (i // m, i % m)

    cells = list(tiling.active_cells)
    uf = UnionFind(n * m)
    for i in range(len(cells)):
        for j in range(i + 1, len(cells)):
            c1, c2 = cells[i], cells[j]
            if c1[0] == c2[0] or c1[1] == c2[1]:
                uf.unite(cell_to_int(c1), cell_to_int(c2))

    # Collect the connected components of the cells
    all_components = {}
    for cell in cells:
        i = uf.find(cell_to_int(cell))
        if i in all_components:
            all_components[i].append(cell)
        else:
            all_components[i] = [cell]
    component_cells = list(set(cells) for cells in all_components.values())
    return component_cells
Exemple #2
0
 def __init__(self, tiling: "Tiling") -> None:
     self._tiling = tiling
     self._active_cells = tiling.active_cells
     nrow = tiling.dimensions[1]
     ncol = tiling.dimensions[0]
     self._cell_unionfind = UnionFind(nrow * ncol)
     self._components: Optional[Tuple[Set[Cell], ...]] = None
     self._factors_obs_and_reqs: Optional[List[Tuple[Tuple[
         GriddedPerm, ...], Tuple[ReqList, ...], Tuple[TrackingAssumption,
                                                       ...], ]]] = None
 def factors(self) -> List["GriddedPerm"]:
     """Return a list containing the factors of a gridded permutation.
     A factor is a sub gridded permutation that is isolated on its own rows
     and columns."""
     uf = UnionFind(len(self.pos))
     for j, (_, (x_r, y_r)) in enumerate(self):
         for i, (_, (x_l, y_l)) in enumerate(islice(self, j)):
             if x_l == x_r or y_l == y_r:
                 uf.unite(i, j)
     # Collect the connected factors of the cells
     all_factors: Dict[int, List[Cell]] = {}
     for i, cell in enumerate(self.pos):
         x = uf.find(i)
         if x in all_factors:
             all_factors[x].append(cell)
         else:
             all_factors[x] = [cell]
     factor_cells = list(set(cells) for cells in all_factors.values())
     return [self.get_gridded_perm_in_cells(comp) for comp in factor_cells]
Exemple #4
0
 def factors(self) -> List["GriddedPerm"]:
     """Return a list containing the factors of a gridded permutation.
     A factor is a sub gridded permutation that is isolated on its own rows
     and columns."""
     uf = UnionFind(len(self.pos))
     for i in range(len(self.pos)):
         for j in range(i + 1, len(self.pos)):
             c1, c2 = self.pos[i], self.pos[j]
             if c1[0] == c2[0] or c1[1] == c2[1]:
                 uf.unite(i, j)
     # Collect the connected factors of the cells
     all_factors: Dict[Cell, List[Cell]] = {}
     for i, cell in enumerate(self.pos):
         x = uf.find(i)
         if x in all_factors:
             all_factors[x].append(cell)
         else:
             all_factors[x] = [cell]
     factor_cells = list(set(cells) for cells in all_factors.values())
     return [self.get_gridded_perm_in_cells(comp) for comp in factor_cells]
Exemple #5
0
def is_boundary_anchored(patt):
    inv = patt.pattern.inverse()
    right, top, left, bottom = patt.has_anchored_point()
    in_bound = set()
    if not right and not left and not top and not bottom:
        return False
    if right:
        in_bound.add(len(patt) - 1)
    if left:
        in_bound.add(0)
    if top:
        in_bound.add(inv[len(patt) - 1])
    if bottom:
        in_bound.add(inv[0])
    uf = UnionFind(len(patt))
    for i in range(1, len(patt)):
        if all((i, j) in patt.shading for j in range(len(patt) + 1)):
            uf.unite(i - 1, i)
        if all((j, i) in patt.shading for j in range(len(patt) + 1)):
            uf.unite(inv[i - 1], inv[i])
    # print(uf.leaders)
    return uf.leaders == set(uf.find(b) for b in in_bound)
Exemple #6
0
def factor(tiling, **kwargs):
    """
    The factor strategy that decomposes a tiling into its connected factors.

    The factors are the connected components of the graph of the tiling, where
    vertices are the cells. Two vertices are connected if there exists a
    obstruction or requirement occupying both cells. Two cells are also
    connected if they share the same row or column unless the interleaving or
    point_interleaving keyword arguments are set to True.
    When point interleavings are allowed, two cells in the same row or column
    are not connected. When general interleavings are allowed, two cells in the
    same row or column are not connected.
    """
    interleaving = kwargs.get("interleaving", False)
    point_interleaving = kwargs.get("point_interleaving", False)
    n, m = tiling.dimensions

    def cell_to_int(cell):
        return cell[0] * m + cell[1]

    def int_to_cell(i):
        return (i // m, i % m)

    cells = list(tiling.active_cells)
    uf = UnionFind(n * m)

    # Unite by obstructions
    for ob in tiling.obstructions:
        for i in range(len(ob.pos)):
            for j in range(i+1, len(ob.pos)):
                uf.unite(cell_to_int(ob.pos[i]), cell_to_int(ob.pos[j]))

    # Unite by requirements
    for req_list in tiling.requirements:
        req_cells = list(union_reduce(req.pos for req in req_list))
        for i in range(len(req_cells)):
            for j in range(i + 1, len(req_cells)):
                uf.unite(cell_to_int(req_cells[i]), cell_to_int(req_cells[j]))

    # If interleaving not allowed, unite by row/col
    if not interleaving:
        for i in range(len(cells)):
            for j in range(i+1, len(cells)):
                c1, c2 = cells[i], cells[j]
                if (point_interleaving and
                        (c1 in tiling.point_cells or
                         c2 in tiling.point_cells)):
                    continue
                if c1[0] == c2[0] or c1[1] == c2[1]:
                    uf.unite(cell_to_int(c1), cell_to_int(c2))

    # Collect the connected components of the cells
    all_components = {}
    for cell in cells:
        i = uf.find(cell_to_int(cell))
        if i in all_components:
            all_components[i].append(cell)
        else:
            all_components[i] = [cell]
    component_cells = list(set(cells) for cells in all_components.values())

    # If the tiling is a single connected component
    if len(component_cells) <= 1:
        return

    # Collect the factors of the tiling
    factors = []
    strategy = []  # the vanilla factors
    for cell_component in component_cells:
        obstructions = [ob for ob in tiling.obstructions
                        if ob.pos[0] in cell_component]
        requirements = [req for req in tiling.requirements
                        if req[0].pos[0] in cell_component]

        if obstructions or requirements:
            factors.append((obstructions, requirements))
            strategy.append(Tiling(obstructions=obstructions,
                                   requirements=requirements,
                                   minimize=False))

    if kwargs.get("workable", True):
        work = [True for _ in strategy]
    else:
        work = [False for _ in strategy]

    yield Rule("The factors of the tiling.", strategy,
               inferable=[False for _ in strategy], workable=work,
               possibly_empty=[False for _ in strategy],
               ignore_parent=kwargs.get("workable", True),
               constructor='cartesian')

    if kwargs.get("unions", False):
        for partition in partition_list(factors):
            strategy = []
            for part in partition:
                obstructions, requirements = zip(*part)
                strategy.append(Tiling(obstructions=chain(*obstructions),
                                       requirements=chain(*requirements),
                                       minimize=False))
            yield Rule("The union of factors of the tiling",
                       strategy,
                       possibly_empty=[False for _ in strategy],
                       inferable=[False for _ in strategy],
                       workable=[False for _ in strategy],
                       constructor='cartesian')