def potential_new_obs(self) -> Set[GriddedPerm]: """ Return the set of all subobstructions of the tiling. """ subobs: Set[GriddedPerm] = set() for ob in self._tiling.obstructions: subobs.update(ob.all_subperms(proper=True)) subobs.remove(GriddedPerm.empty_perm()) return subobs
def test_empty_perm(): gp = GriddedPerm.empty_perm() assert gp.patt == Perm(()) assert gp.pos == () assert len(gp._cells) == 0 assert GriddedPerm() == gp == GriddedPerm((), ())
def minimal_gridded_perms(self, yield_non_minimal: bool = False ) -> Iterator[GriddedPerm]: """ Yield all minimal gridded perms on the tiling. If `yield_non_minimal` is True, then it will yield some gridded perms that are non-minimal, found by the initial_gp method. Even though it may not be minimal, this is useful when trying to determine whether or not a tiling is empty. """ if not self.requirements: if GriddedPerm.empty_perm() not in self.obstructions: yield GriddedPerm.empty_perm() return if len(self.requirements) == 1: yield from self.requirements[0] return # a priority queue sorted by length of the gridded perm. This is # ensured by overwriting the __lt__ operator in the Info class. queue: List[QueuePacket] = [] heapify(queue) initial_gps_to_auto_yield: Dict[int, Set[GriddedPerm]] = defaultdict(set) yielded: Set[GriddedPerm] = set() for gp in self._prepare_queue(queue): if yield_non_minimal: yielded.add(gp) yield gp else: initial_gps_to_auto_yield[len(gp)].add(gp) def yielded_subgridded_perm(gp: GriddedPerm) -> bool: """Return True if a subgridded perm was yielded.""" return gp.contains(*yielded) def _process_work_packet( qpacket: QueuePacket, queue: List[QueuePacket], ) -> Iterator[GriddedPerm]: # now we try inserting a new point into the cell for (cell, localised) in self._get_cells_to_try(qpacket): # The `localised` bool tells us if we inserted into # a cell as it didn't contain the patterns in the # cell. If not, then we update the last cell, to # ensure we only insert into greater or equal cells next_cell = qpacket.last_cell if localised else cell # Insert a point in every way possible into cell, to the right # of any previously placed points in that cell. for idx, nextgp in self.insert_point( qpacket.gp, cell, qpacket.mindices.get(cell, 0)): # The work_packets_done is used to ensure the same # task is not processed twice. key = (nextgp, qpacket.gps, next_cell) if key in work_packets_done: continue work_packets_done.add(key) # Only work with gridded permutations avoiding the # obstructions, and those which we haven't yielded a # subgridded permutation. if yielded_subgridded_perm( nextgp) or not self.satisfies_obstructions( nextgp, must_contain=cell): continue # Update the nextgp about the patterns that are # contained in the subgridded permutation gp. self.known_patts[nextgp].update( self.known_patts[qpacket.gp]) # If it satisfies the requirements, then it is a # a minimal gridded permutation if self.satisfies_requirements(nextgp): # Keep track to ensure we don't yield a gridded # perm containing it. yielded.add(nextgp) yield nextgp else: # Update the minimum index that we inserted a # a point into each cell. next_mindices = { c: i if i <= idx else i + 1 for c, i in qpacket.mindices.items() if c != cell } next_mindices[cell] = idx + 1 # Add the work to the queue heappush( queue, QueuePacket( nextgp, qpacket.gps, next_cell, localised, next_mindices, ), ) work_packets_done: Set[WorkPackets] = set() curr_len = -1 while queue: # take the next gridded permutation of the queue, together with the # theoretical counts to create a gridded permutation containing # each of gps. qpacket = heappop(queue) # if gp was one of the initial_gps that satisfied obs/reqs, but # we weren't sure at the time if it was minimal, then now is the # time to check and yield if curr_len != len(qpacket.gp): new_len = len(qpacket.gp) initial_to_yield = chain.from_iterable( initial_gps_to_auto_yield.pop(i, tuple()) for i in range(curr_len + 1, new_len + 2)) for gp in initial_to_yield: if not yielded_subgridded_perm(gp): yielded.add(gp) yield gp curr_len = len(qpacket.gp) yield from _process_work_packet(qpacket, queue) # We yield any initial left after working on the work packet. # This happens in particular if you don't have any WP. initial_to_yield = chain.from_iterable( initial_gps_to_auto_yield.pop(i, tuple()) for i in sorted(initial_gps_to_auto_yield)) for gp in initial_to_yield: if not yielded_subgridded_perm(gp): yielded.add(gp) yield gp
def test_all_cell_insertions_points(simple_tiling): point_insertion = CellInsertionFactory(maxreqlen=1) assert str(point_insertion) == "point insertion" rules = set( [tuple(s(simple_tiling).children) for s in point_insertion(simple_tiling)] ) assert all(len(s) == 2 for s in rules) actual = set() actual.add( ( Tiling( obstructions=[GriddedPerm(Perm((0,)), [(0, 1)])], requirements=[ [ GriddedPerm(Perm((0, 1)), [(0, 0), (1, 0)]), GriddedPerm(Perm((0, 1)), [(0, 0), (1, 1)]), ] ], ), Tiling( obstructions=[GriddedPerm(Perm((0,)), [(1, 0)])], requirements=[ [GriddedPerm(Perm((0,)), [(0, 1)])], [GriddedPerm(Perm((0, 1)), [(0, 0), (1, 1)])], ], ), ) ) actual.add( ( Tiling( obstructions=[ GriddedPerm(Perm((0,)), ((0, 1),)), GriddedPerm(Perm((0,)), ((1, 0),)), ], requirements=[[GriddedPerm(Perm((0, 1)), ((0, 0), (1, 1)))]], ), Tiling( obstructions=[GriddedPerm(Perm((0,)), ((0, 1),))], requirements=[ [GriddedPerm(Perm((0,)), ((1, 0),))], [ GriddedPerm(Perm((0, 1)), ((0, 0), (1, 0))), GriddedPerm(Perm((0, 1)), ((0, 0), (1, 1))), ], ], ), ) ) actual.add( ( Tiling(obstructions=[GriddedPerm.empty_perm()]), Tiling( obstructions=[GriddedPerm(Perm((1, 0)), ((0, 1), (1, 0)))], requirements=[ [GriddedPerm(Perm((0,)), ((0, 0),))], [ GriddedPerm(Perm((0, 1)), ((0, 0), (1, 0))), GriddedPerm(Perm((0, 1)), ((0, 0), (1, 1))), ], ], ), ) ) actual.add( ( Tiling(requirements=[[GriddedPerm(Perm((0, 1)), ((0, 0), (1, 0)))]]), Tiling( obstructions=[GriddedPerm(Perm((1, 0)), ((0, 1), (1, 0)))], requirements=[ [GriddedPerm(Perm((0,)), ((1, 1),))], [ GriddedPerm(Perm((0, 1)), ((0, 0), (1, 0))), GriddedPerm(Perm((0, 1)), ((0, 0), (1, 1))), ], ], ), ) ) assert rules == actual
def test_empty_perm(): gp = GriddedPerm.empty_perm() assert gp.patt == Perm(()) assert gp.pos == ()