def is_crossing_len2(self, gp: GriddedPerm) -> bool: """ Return True if the gridded permutation `gp` is a length 2 obstruction crossing between the first and second cell. """ return ( len(gp) == 2 and gp.occupies(self.first_cell) and gp.occupies(self.second_cell) )
def new_assumption(self): """ Return the assumption that needs to be counted in order to enumerate. """ fcell = self.first_cell scell = self.second_cell gps = (GriddedPerm.single_cell(Perm((0,)), fcell),) if self._fuse_row: sum_ob = GriddedPerm(Perm((1, 0)), (scell, fcell)) else: sum_ob = GriddedPerm(Perm((1, 0)), (fcell, scell)) if sum_ob in self._tiling.obstructions: return SumComponentAssumption(gps) return SkewComponentAssumption(gps)
def positive_left_right_requirements(self): """ Return the pair of requirements that ensures the left contains at least one point, and the right contains at least one point. """ left, right = [], [] for (x, y) in self._tiling.active_cells: if self._fuse_row and y == self._row_idx: left.append(GriddedPerm.single_cell(Perm((0,)), (x, y))) right.append(GriddedPerm.single_cell(Perm((0,)), (x, y + 1))) if not self._fuse_row and x == self._col_idx: left.append(GriddedPerm.single_cell(Perm((0,)), (x, y))) right.append(GriddedPerm.single_cell(Perm((0,)), (x + 1, y))) return tuple(sorted(left)), tuple(sorted(right))
def _get_cell_insertion_input( ) -> Tuple[Tiling, VerificationTactics, GriddedPerm]: data = _get_request_json() try: tiling = decode_key(data["tiling"]) verification_tactics = VerificationTactics.from_response_dictionary( data["verify"]) x: int = data["x"] y: int = data["y"] patt: str = data["patt"] except (TypeError, KeyError, ValueError, TilingDecodeException) as exc: raise BadRequest() from exc if not (isinstance(x, int) and isinstance(y, int) and isinstance(patt, str)): raise BadRequest() if not patt.isdecimal(): raise BadRequest() _x, _y = tiling.dimensions if x < 0 or x >= _x or y < 0 or y >= _y: raise BadRequest() n, value_set = len(patt), set(map(int, patt)) if len(value_set) != n or not all( i in value_set for i in (range(n) if 0 in value_set else range(1, n + 1))): raise BadRequest() return ( tiling, verification_tactics, GriddedPerm.single_cell(Perm.to_standard(patt), (x, y)), )
def insert_next_point( self, gp: GriddedPerm, col: int, ) -> Iterator[GriddedPerm]: """ Insert the next point in the given column in all possible way. """ active_cell_in_col = (cell for cell in self._active_cells if cell[0] == col) for cell in active_cell_in_col: _, _, minval, maxval = gp.get_bounding_box(cell) for val in range(minval, maxval + 1): next_gp = GriddedPerm(gp.patt.insert(new_element=val), gp.pos + (cell, )) yield next_gp
def guess_obstructions(gps: Iterable[GriddedPerm], max_len: int = -1) -> Set[GriddedPerm]: """Generate minimal obstructions avoided by the provided gridded perms, if possible. We check to a fixed length.""" gps = set(gps) c, r, longest = _get_dimensions(gps) max_len = longest if max_len == -1 else min(max_len, longest) return _search(deque([GriddedPerm()]), gps, c, r, max_len)
def has_crossing_len2_ob(self): """ Return True if the tiling contains a crossing length 2 obstruction between `self.first_cell` and `self.second_cell`. """ fcell = self.first_cell scell = self.second_cell if self._fuse_row: possible_obs = [ GriddedPerm(Perm((0, 1)), (fcell, scell)), GriddedPerm(Perm((1, 0)), (scell, fcell)), ] else: possible_obs = [ GriddedPerm(Perm((0, 1)), (fcell, scell)), GriddedPerm(Perm((1, 0)), (fcell, scell)), ] return any(ob in possible_obs for ob in self._tiling.obstructions)
def new_assumption(self): """ Return the assumption that needs to counted in order to enumerate. """ return TrackingAssumption( GriddedPerm.single_cell(Perm((0,)), cell) for cell in self._tiling.active_cells if (self._fuse_row and cell[1] == self._row_idx) or (not self._fuse_row and cell[0] == self._col_idx) )
def unfuse_gridded_perm( self, gp: GriddedPerm, left_points: Optional[int] = None ) -> Iterator[GriddedPerm]: """ Generator of all the possible ways to unfuse a gridded permutations. If left_points is given, the iterator contains only one gridded permutations with said number of left points. """ def stretch_above(p): return p if p[1] < self._row_idx else (p[0], p[1] + 1) def stretch_left(p): return p if p[0] < self._col_idx else (p[0] + 1, p[1]) if self._fuse_row: stretch = stretch_above editable_pos_idx = [ i for i, p in enumerate(gp.pos) if p[1] == self._row_idx ] editable_pos_idx.sort(key=lambda i: gp.patt[i]) else: stretch = stretch_left editable_pos_idx = [ i for i, p in enumerate(gp.pos) if p[0] == self._col_idx ] editable_pos_idx.sort() pos = list(map(stretch, gp.pos)) if left_points is None or left_points == 0: yield gp.__class__(gp.patt, pos) if left_points == 0: return row_shift = int(self._fuse_row) col_shift = 1 - int(self._fuse_row) for left_points_so_far, i in enumerate(editable_pos_idx): pos[i] = (pos[i][0] - col_shift, pos[i][1] - row_shift) if left_points is None or left_points_so_far + 1 == left_points: yield gp.__class__(gp.patt, pos) if left_points_so_far + 1 == left_points: break
def new_positive_requirement(self): cells = [ (x, y) for (x, y) in self._tiling.active_cells if (self._fuse_row and y == self._row_idx) or (not self._fuse_row and x == self._col_idx) ] if self._positive_left and self._positive_right: cells.sort() res = [] for idx, c1 in enumerate(cells): for c2 in cells[idx:]: res.append(GriddedPerm(Perm((0, 1)), (c1, c2))) if self._fuse_row: res.append(GriddedPerm(Perm((1, 0)), (c1, c2))) else: res.append(GriddedPerm(Perm((1, 0)), (c2, c1))) return sorted(res) if self._positive_left or self._positive_right: return sorted(GriddedPerm.single_cell(Perm((0,)), cell) for cell in cells) raise ValueError("no positive left right requirement")
def fuse_gridded_perm(self, gp: GriddedPerm) -> GriddedPerm: """ Fuse the gridded permutation `gp`. """ fused_pos = [] for x, y in gp.pos: if self._fuse_row and y > self._row_idx: y -= 1 elif not self._fuse_row and x > self._col_idx: x -= 1 fused_pos.append((x, y)) return gp.__class__(gp.patt, fused_pos)
def _get_add_assumption_input( ) -> Tuple[Tiling, VerificationTactics, List[GriddedPerm]]: data = _get_request_json() try: tiling = decode_key(data["tiling"]) verification_tactics = VerificationTactics.from_response_dictionary( data["verify"]) pos: List[List[int]] = data["pos"] except (TypeError, KeyError, ValueError, TilingDecodeException) as exc: raise BadRequest() from exc if not isinstance(pos, list) or len(pos) == 0: raise BadRequest() _x, _y = tiling.dimensions gps: List[GriddedPerm] = [] for coord in pos: if not isinstance(coord, list) or len(coord) != 2: raise BadRequest() x, y = coord if not (isinstance(x, int) and isinstance(y, int)): raise BadRequest() if x < 0 or y < 0 or x >= _x or y >= _y: raise BadRequest() gps.append(GriddedPerm.single_cell((0, ), (x, y))) return tiling, verification_tactics, gps
def __iter__(self) -> Iterator[GriddedPerm]: if not GriddedPerm(Perm(tuple()), tuple()) in self._obstructions: yield from self.backtracking(GriddedPerm.empty_perm(), 0, self._requirements)
def can_satisfy(gp: GriddedPerm, col: int, req: GriddedPerm) -> bool: return req.get_subperm_left_col(col) in gp