def simple_trans_row_len3(): return Tiling(obstructions=[Obstruction(Perm((0, 1)), [(0, 0), (1, 0)]), Obstruction(Perm((0, 1)), [(1, 0), (2, 0)]), Obstruction(Perm((0, 1)), [(2, 0), (3, 0)]), Obstruction(Perm((0, 1)), [(3, 0), (4, 0)])], requirements=[[Requirement(Perm((0,)), [(1, 0)])], [Requirement(Perm((0,)), [(2, 0)])], [Requirement(Perm((0,)), [(3, 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, ))
def all_requirement_insertions(tiling, **kwargs): """Insert all possible requirements the obstruction allow.""" if kwargs.get("no_reqs", True) and tiling.requirements: return maxlen = kwargs.get("maxlen", 2) ignore_parent = kwargs.get("ignore_parent", False) obs_tiling = Tiling(tiling.obstructions, remove_empty=False, derive_empty=False, minimize=False, sorted_input=True) for length in range(1, maxlen + 1): for gp in obs_tiling.gridded_perms_of_length(length): if len(gp.factors()) == 1: av = Tiling( (tiling.obstructions + (Obstruction(gp.patt, gp.pos), )), tiling.requirements) co = Tiling(tiling.obstructions, (tiling.requirements) + ((Requirement(gp.patt, gp.pos), ), )) yield Rule(formal_step="Insert {}.".format(str(gp)), comb_classes=[av, co], ignore_parent=ignore_parent, inferable=[True for _ in range(2)], possibly_empty=[True for _ in range(2)], workable=[True for _ in range(2)], constructor='disjoint')
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)
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)
def diverse_tiling(): """Returns a simple, but diverse tiling. The tiling has positive, possibly empty and empty cells and also few requirements and a long obstructions.""" return Tiling(obstructions=[ Obstruction(Perm((0, 2, 3, 1)), [(0, 0), (1, 1), (1, 1), (2, 0)]), Obstruction(Perm((0, 1)), [(1, 0), (1, 0)]), Obstruction(Perm((1, 0)), [(1, 0), (1, 0)]), Obstruction(Perm((0, 1)), [(2, 1), (2, 1)]), Obstruction(Perm((1, 0)), [(2, 1), (2, 1)]) ], requirements=[[ Requirement(Perm((0, 2, 1)), [(0, 1), (0, 2), (1, 2)]), Requirement(Perm((1, 0)), [(0, 2), (0, 1)]) ], [Requirement(Perm((0, )), [(1, 0)])], [Requirement(Perm((0, )), [(2, 0)])], [Requirement(Perm((0, )), [(2, 1)])]])
def compute_ineq_ob(left, right): """Given an inequality of cells left < right, compute an obstruction.""" if left[0] == right[0]: # same column if left[1] < right[1]: return Obstruction(Perm((1, 0)), [right, left]) else: return Obstruction(Perm((0, 1)), [right, left]) elif left[1] == right[1]: # same row if left[0] < right[0]: return Obstruction(Perm((1, 0)), [left, right]) else: return Obstruction(Perm((0, 1)), [right, left]) else: raise ValueError(( "Can not construct an obstruction from inequality {} < {}").format( left, right))
def no_point_tiling(): """Returns a simple tiling with length of all obs and reqs at least 2. """ return Tiling(obstructions=[ Obstruction(Perm((1, 0)), [(0, 1), (0, 1)]), Obstruction(Perm((0, 1, 2)), [(0, 0), (1, 0), (1, 0)]), Obstruction(Perm((0, 1, 2)), [(1, 0), (1, 0), (2, 0)]), Obstruction(Perm((0, 2, 1)), [(0, 2), (0, 2), (1, 2)]), Obstruction(Perm((0, 2, 1)), [(0, 2), (1, 2), (1, 2)]) ], requirements=[[ Requirement(Perm((0, 1)), [(0, 0), (0, 0)]), Requirement(Perm((0, 1)), [(0, 0), (2, 0)]) ], [Requirement(Perm((0, 2, 1)), [(0, 1), (1, 1), (1, 1)])], [ Requirement(Perm((0, 1)), [(1, 1), (2, 1)]), Requirement(Perm((0, 1)), [(1, 1), (2, 2)]) ]])
def test_all_cell_insertions_points(simple_tiling): strats = [ s.comb_classes for s in all_cell_insertions(simple_tiling, maxreqlen=1) ] assert all(len(s) == 2 for s in strats) s = strats[0] assert s[0] == Tiling(obstructions=[Obstruction(Perm((0, )), [(0, 1)])], requirements=[[ Requirement(Perm((0, 1)), [(0, 0), (1, 0)]), Requirement(Perm((0, 1)), [(0, 0), (1, 1)]) ]]) assert s[1] == Tiling( obstructions=[Obstruction(Perm((0, )), [(1, 0)])], requirements=[[Requirement(Perm((0, )), [(0, 1)])], [Requirement(Perm((0, 1)), [(0, 0), (1, 1)])]]) s = strats[1] assert s[0] == Tiling( obstructions=[ Obstruction(Perm((0, )), ((0, 1), )), Obstruction(Perm((0, )), ((1, 0), )) ], requirements=[[Requirement(Perm((0, 1)), ((0, 0), (1, 1)))]]) assert s[1] == Tiling( obstructions=[Obstruction(Perm((0, )), ((0, 1), ))], requirements=[[Requirement(Perm((0, )), ((1, 0), ))], [ Requirement(Perm((0, 1)), ((0, 0), (1, 0))), Requirement(Perm((0, 1)), ((0, 0), (1, 1))) ]]) s = strats[2] assert s[0] == Tiling(obstructions=[Obstruction(Perm(tuple()), tuple())]) assert s[1] == Tiling( obstructions=[Obstruction(Perm((1, 0)), ((0, 1), (1, 0)))], requirements=[[Requirement(Perm((0, )), ((0, 0), ))], [ Requirement(Perm((0, 1)), ((0, 0), (1, 0))), Requirement(Perm((0, 1)), ((0, 0), (1, 1))) ]]) s = strats[3] assert s[0] == Tiling( requirements=[[Requirement(Perm((0, 1)), ((0, 0), (1, 0)))]]) assert s[1] == Tiling( obstructions=[Obstruction(Perm((1, 0)), ((0, 1), (1, 0)))], requirements=[[Requirement(Perm((0, )), ((1, 1), ))], [ Requirement(Perm((0, 1)), ((0, 0), (1, 0))), Requirement(Perm((0, 1)), ((0, 0), (1, 1))) ]])
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]))
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)
def all_factor_insertions(tiling, **kwargs): ignore_parent = kwargs.get("ignore_parent", False) for gp in sorted(set(chain(tiling.obstructions, *tiling.requirements))): factors = gp.factors() if len(factors) != 1: for gp in factors: av = Tiling( (tiling.obstructions + (Obstruction(gp.patt, gp.pos), )), tiling.requirements) co = Tiling(tiling.obstructions, (tiling.requirements) + ((Requirement(gp.patt, gp.pos), ), )) yield Rule(formal_step="Insert {}.".format(str(gp)), comb_classes=[av, co], ignore_parent=ignore_parent, inferable=[True for _ in range(2)], possibly_empty=[True for _ in range(2)], workable=[True for _ in range(2)], constructor='disjoint')
def test_factor_no_unions(simple_tiling, diverse_tiling, no_point_tiling): assert len(list(factor(simple_tiling))) == 0 assert len(list(factor(diverse_tiling))) == 0 tiling = Tiling(obstructions=[Obstruction(Perm((0, 1)), [(0, 0), (0, 0)])], requirements=[[ Requirement(Perm((0, 1)), [(1, 1), (1, 1)]), Requirement(Perm((0, 1)), [(1, 1), (1, 2)]) ]]) strats = [s.comb_classes for s in factor(tiling)] assert len(strats) == 1 factors = strats[0] assert set(factors) == set([ Tiling(requirements=[[ Requirement(Perm((0, 1)), [(0, 0), (0, 0)]), Requirement(Perm((0, 1)), [(0, 0), (0, 1)]) ]]), Tiling(obstructions=[Obstruction(Perm((0, 1)), [(0, 0), (0, 0)])]) ]) strats = [ s.comb_classes for s in factor(diverse_tiling, interleaving=True) ] assert len(strats) == 1 factors = strats[0] assert len(factors) == 4 print(diverse_tiling) assert set(factors) == set([ Tiling(obstructions=[ Obstruction(Perm((0, 2, 3, 1)), [(0, 0), (1, 1), (1, 1), (2, 0)]) ], requirements=[[Requirement(Perm((0, )), [(2, 0)])]]), Tiling(obstructions=[ Obstruction(Perm((0, 1)), [(0, 0), (0, 0)]), Obstruction(Perm((1, 0)), [(0, 0), (0, 0)]) ], requirements=[[Requirement(Perm((0, )), [(0, 0)])]]), Tiling(obstructions=[ Obstruction(Perm((0, 1)), [(0, 0), (0, 0)]), Obstruction(Perm((1, 0)), [(0, 0), (0, 0)]) ], requirements=[[Requirement(Perm((0, )), [(0, 0)])]]), Tiling(requirements=[[ Requirement(Perm((1, 0)), [(0, 2), (0, 1)]), Requirement(Perm((0, 2, 1)), [(0, 1), (0, 2), (1, 2)]) ]]) ])
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, )) ]
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 test_all_cell_insertions(typical_redundant_requirements, typical_redundant_obstructions): tiling = Tiling(obstructions=typical_redundant_obstructions, requirements=typical_redundant_requirements) strats = list(all_cell_insertions(tiling, maxreqlen=3)) assert all(len(s.comb_classes) == 2 for s in strats) s = strats[-1] print(tiling) print(s.formal_step) print(s.comb_classes[0]) print(s.comb_classes[1]) assert s.comb_classes[0] == Tiling( obstructions=typical_redundant_obstructions + [Obstruction(Perm((0, 1, 2)), [(0, 1), (0, 1), (0, 1)])], requirements=typical_redundant_requirements) assert s.comb_classes[1] == Tiling( obstructions=typical_redundant_obstructions, requirements=typical_redundant_requirements + [[Requirement(Perm((0, 1, 2)), [(0, 1), (0, 1), (0, 1)])]])
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))
def test_place_point_of_requirement_point_only(diverse_tiling): tiling = place_point_of_requirement(diverse_tiling, 0, 0, DIR_WEST) assert tiling == Tiling( obstructions=[ Obstruction(Perm((0, )), [(1, 0)]), Obstruction(Perm((0, )), [(1, 2)]), Obstruction(Perm((0, )), [(2, 0)]), Obstruction(Perm((0, )), [(2, 2)]), Obstruction(Perm((0, 1)), [(2, 1), (2, 1)]), Obstruction(Perm((0, 1)), [(4, 3), (4, 3)]), Obstruction(Perm((1, 0)), [(2, 1), (2, 1)]), Obstruction(Perm((1, 0)), [(4, 3), (4, 3)]), Obstruction(Perm((0, 2, 3, 1)), [(0, 0), (1, 3), (1, 3), (4, 0)]), Obstruction(Perm((0, 2, 3, 1)), [(0, 0), (1, 3), (1, 3), (4, 2)]), Obstruction(Perm((0, 2, 3, 1)), [(0, 0), (1, 3), (3, 3), (4, 0)]), Obstruction(Perm((0, 2, 3, 1)), [(0, 0), (1, 3), (3, 3), (4, 2)]), Obstruction(Perm((0, 2, 3, 1)), [(0, 0), (3, 3), (3, 3), (4, 0)]), Obstruction(Perm((0, 2, 3, 1)), [(0, 0), (3, 3), (3, 3), (4, 2)]), Obstruction(Perm((0, 2, 3, 1)), [(0, 2), (1, 3), (1, 3), (4, 2)]), Obstruction(Perm((0, 2, 3, 1)), [(0, 2), (1, 3), (3, 3), (4, 2)]), Obstruction(Perm((0, 2, 3, 1)), [(0, 2), (3, 3), (3, 3), (4, 2)]) ], requirements=[[Requirement(Perm((0, )), [(2, 1)])], [Requirement(Perm((0, )), [(4, 3)])], [ Requirement(Perm((0, )), [(4, 0)]), Requirement(Perm((0, )), [(4, 2)]) ], [ Requirement(Perm((1, 0)), [(0, 4), (0, 3)]), Requirement(Perm((0, 2, 1)), [(0, 3), (0, 4), (1, 4)]), Requirement(Perm((0, 2, 1)), [(0, 3), (0, 4), (3, 4)]) ]]) assert tiling == place_point_of_requirement(diverse_tiling, 0, 0, DIR_EAST) assert tiling == place_point_of_requirement(diverse_tiling, 0, 0, DIR_NORTH) assert tiling == place_point_of_requirement(diverse_tiling, 0, 0, DIR_SOUTH) tiling = place_point_of_requirement(diverse_tiling, 1, 0, DIR_WEST) assert tiling == Tiling( obstructions=[ Obstruction(Perm((0, )), [(2, 0)]), Obstruction(Perm((0, )), [(2, 2)]), Obstruction(Perm((0, 1)), [(1, 0), (1, 0)]), Obstruction(Perm((0, 1)), [(1, 0), (1, 2)]), Obstruction(Perm((0, 1)), [(1, 2), (1, 2)]), Obstruction(Perm((0, 1)), [(3, 1), (3, 1)]), Obstruction(Perm((0, 1)), [(2, 3), (2, 3)]), Obstruction(Perm((0, 1)), [(2, 3), (4, 3)]), Obstruction(Perm((0, 1)), [(4, 3), (4, 3)]), Obstruction(Perm((1, 0)), [(1, 0), (1, 0)]), Obstruction(Perm((1, 0)), [(1, 2), (1, 0)]), Obstruction(Perm((1, 0)), [(1, 2), (1, 2)]), Obstruction(Perm((1, 0)), [(3, 1), (3, 1)]), Obstruction(Perm((1, 0)), [(2, 3), (2, 3)]), Obstruction(Perm((1, 0)), [(2, 3), (4, 3)]), Obstruction(Perm((1, 0)), [(4, 3), (4, 3)]), Obstruction(Perm((0, 1, 2)), [(0, 0), (1, 3), (1, 3)]), Obstruction(Perm((0, 2, 3, 1)), [(0, 2), (1, 3), (1, 3), (4, 2)]) ], requirements=[[Requirement(Perm((0, )), [(3, 1)])], [ Requirement(Perm((0, )), [(1, 0)]), Requirement(Perm((0, )), [(1, 2)]) ], [ Requirement(Perm((0, )), [(2, 3)]), Requirement(Perm((0, )), [(4, 3)]) ], [ Requirement(Perm((1, 0)), [(0, 4), (0, 3)]), Requirement(Perm((0, 2, 1)), [(0, 3), (0, 4), (1, 4)]) ]]) tiling = Tiling(requirements=[[Requirement(Perm((0, )), [(0, 0)])]]) assert place_point_of_requirement(tiling, 0, 0, DIR_SOUTH) == Tiling( obstructions=[ Obstruction(Perm((0, 1)), [(0, 0), (0, 0)]), Obstruction(Perm((1, 0)), [(0, 0), (0, 0)]) ], requirements=[[Requirement(Perm((0, )), [(0, 0)])]])
def row_placements(tiling, row=True, positive=True, regions=False, **kwargs): """Places the points in a row (or col if row=False) in the given direction.""" if row: x = tiling.dimensions[1] y = tiling.dimensions[0] only_cell_in_col = tiling.only_cell_in_col directions = [DIR_NORTH, DIR_SOUTH] else: x = tiling.dimensions[0] y = tiling.dimensions[1] only_cell_in_col = tiling.only_cell_in_row directions = [DIR_EAST, DIR_WEST] rows = range(x) if kwargs.get("index") is not None: rows = [kwargs.get("index")] if kwargs.get("direction") is not None: directions = [kwargs["direction"]] if regions: forward_maps = [] direction = kwargs.get('direction') if direction is not None: if row: if direction == DIR_NORTH: directions = [DIR_NORTH] elif direction == DIR_SOUTH: directions = [DIR_SOUTH] else: raise ValueError("Can't place rows in direction.") else: if direction == DIR_EAST: directions = [DIR_EAST] elif direction == DIR_WEST: directions = [DIR_WEST] else: raise ValueError("Can't place cols in direction.") for i in rows: place = True cells_in_row = [] for j in range(y): cell = (j, i) if row else (i, j) if positive and cell not in tiling.positive_cells: place = False break cells_in_row.append(cell) if place: if (len(cells_in_row) != 1 or not cells_in_row[0] in tiling.point_cells or not only_cell_in_col(cells_in_row[0])): req_list = tuple( Requirement(Perm((0, )), (cell, )) for cell in cells_in_row) if not positive: """Adding the empty row case.""" empty_row_tiling = Tiling( tiling.obstructions + tuple( Obstruction(Perm((0, )), (cell, )) for cell in cells_in_row), tiling.requirements) if regions: forward_maps.append( {c: frozenset([c]) for c in tiling.active_cells}) for direction in directions: if regions: tilings, placed_maps = place_requirement_list( tiling, req_list, direction, regions=regions) if not positive: tilings = [empty_row_tiling] + tilings forward_maps.extend(placed_maps) yield tilings, forward_maps else: tilings = place_requirement_list( tiling, req_list, direction) if not positive: tilings = [empty_row_tiling] + tilings yield Rule(formal_step=("Placing {} {} in direction {}." "".format("row" if row else "col", i, direction, i, direction, int(positive))), comb_classes=tilings, ignore_parent=False, possibly_empty=[True for _ in tilings], inferable=[True for _ in tilings], workable=[True for _ in tilings], constructor='disjoint')
def simple_trans_col(): return Tiling(obstructions=[Obstruction(Perm((0, 1)), [(0, 0), (0, 1)]), Obstruction(Perm((0, 1)), [(0, 1), (0, 2)])], requirements=[[Requirement(Perm((0,)), [(0, 1)])]])
def test_place_point_of_requirement(no_point_tiling): tiling = place_point_of_requirement(no_point_tiling, 2, 1, DIR_WEST) tiling2 = Tiling( obstructions=[ Obstruction(Perm((0, 1)), [(0, 1), (1, 3)]), Obstruction(Perm((0, 1)), [(2, 2), (2, 2)]), Obstruction(Perm((1, 0)), [(0, 1), (0, 1)]), Obstruction(Perm((1, 0)), [(0, 3), (0, 1)]), Obstruction(Perm((1, 0)), [(0, 3), (0, 3)]), Obstruction(Perm((1, 0)), [(2, 2), (2, 2)]), Obstruction(Perm((0, 1, 2)), [(0, 0), (1, 0), (1, 0)]), Obstruction(Perm((0, 1, 2)), [(0, 0), (1, 0), (3, 0)]), Obstruction(Perm((0, 1, 2)), [(0, 0), (3, 0), (3, 0)]), Obstruction(Perm((0, 1, 2)), [(1, 0), (1, 0), (4, 0)]), Obstruction(Perm((0, 1, 2)), [(1, 0), (3, 0), (4, 0)]), Obstruction(Perm((0, 1, 2)), [(3, 0), (3, 0), (4, 0)]), Obstruction(Perm((0, 2, 1)), [(0, 1), (1, 1), (1, 1)]), Obstruction(Perm((0, 2, 1)), [(0, 1), (1, 1), (3, 1)]), Obstruction(Perm((0, 2, 1)), [(0, 3), (1, 3), (1, 3)]), Obstruction(Perm((0, 2, 1)), [(0, 3), (1, 3), (3, 3)]), Obstruction(Perm((0, 2, 1)), [(0, 4), (0, 4), (1, 4)]), Obstruction(Perm((0, 2, 1)), [(0, 4), (0, 4), (3, 4)]), Obstruction(Perm((0, 2, 1)), [(0, 4), (1, 4), (1, 4)]), Obstruction(Perm((0, 2, 1)), [(0, 4), (1, 4), (3, 4)]), Obstruction(Perm((0, 2, 1)), [(0, 4), (3, 4), (3, 4)]) ], requirements=[[Requirement(Perm((0, )), [(2, 2)])], [ Requirement(Perm((0, 1)), [(0, 0), (0, 0)]), Requirement(Perm((0, 1)), [(0, 0), (4, 0)]) ], [Requirement(Perm((0, 1)), [(0, 1), (3, 1)])], [ Requirement(Perm((0, 1)), [(1, 1), (4, 1)]), Requirement(Perm((0, )), [(4, 3)]), Requirement(Perm((0, )), [(4, 4)]), Requirement(Perm((0, 1)), [(3, 1), (4, 1)]) ]]) assert tiling == tiling2
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
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)
def typical_obstructions_with_local(): return [ Obstruction(Perm((0, 1)), ((1, 0), (1, 0))), Obstruction(Perm((0, 1)), ((1, 0), (2, 0))), Obstruction(Perm((0, 1)), ((1, 0), (3, 0))), Obstruction(Perm((0, 1)), ((2, 0), (2, 0))), Obstruction(Perm((0, 1)), ((2, 0), (3, 0))), Obstruction(Perm((0, 1)), ((3, 1), (3, 1))), Obstruction(Perm((0, 2, 1)), ((3, 0), (3, 0), (3, 0))), Obstruction(Perm((0, 1, 2)), ((3, 0), (3, 0), (3, 1))), Obstruction(Perm((1, 2, 0)), ((1, 0), (1, 0), (1, 0))), Obstruction(Perm((3, 2, 1, 0)), ((1, 1), (2, 0), (2, 0), (2, 0))), Obstruction(Perm((3, 2, 1, 0)), ((2, 1), (2, 1), (3, 0), (3, 0))) ]
def typical_redundant_obstructions(): """Returns a very typical list of obstructions clustered together in a corner of a tiling. """ return [ Obstruction(Perm((0, 1)), ((1, 0), (1, 0))), Obstruction(Perm((0, 1)), ((1, 0), (2, 0))), Obstruction(Perm((0, 1)), ((1, 0), (3, 0))), Obstruction(Perm((0, 1)), ((2, 0), (2, 0))), Obstruction(Perm((0, 1)), ((2, 0), (3, 0))), Obstruction(Perm((0, 1)), ((3, 1), (3, 1))), Obstruction(Perm((1, 0)), ((3, 0), (3, 0))), Obstruction(Perm((1, 0)), ((3, 1), (3, 0))), Obstruction(Perm((1, 0)), ((3, 1), (3, 1))), Obstruction(Perm((0, 1, 2)), ((3, 0), (3, 0), (3, 0))), Obstruction(Perm((0, 1, 2)), ((3, 0), (3, 0), (3, 1))), Obstruction(Perm((2, 1, 0)), ((1, 0), (1, 0), (1, 0))), Obstruction(Perm((2, 1, 0)), ((1, 0), (1, 0), (2, 0))), Obstruction(Perm((2, 1, 0)), ((1, 0), (1, 0), (3, 0))), Obstruction(Perm((2, 1, 0)), ((1, 0), (2, 0), (2, 0))), Obstruction(Perm((2, 1, 0)), ((1, 0), (2, 0), (3, 0))), Obstruction(Perm((2, 1, 0)), ((2, 0), (2, 0), (2, 0))), Obstruction(Perm((2, 1, 0)), ((2, 0), (2, 0), (3, 0))), Obstruction(Perm((3, 2, 1, 0)), ((1, 1), (2, 0), (2, 0), (2, 0))), Obstruction(Perm((3, 2, 1, 0)), ((2, 1), (2, 1), (3, 0), (3, 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)
def test_obstruction_transitivity(simple_trans_row, simple_trans_col, simple_trans_row_len2, simple_trans_row_len3): strat = obstruction_transitivity(simple_trans_row) assert strat.comb_classes[0] == Tiling( obstructions=[ Obstruction(Perm((0, 1)), [(0, 0), (1, 0)]), Obstruction(Perm((0, 1)), [(1, 0), (2, 0)]), Obstruction(Perm((0, 1)), [(0, 0), (2, 0)]) ], requirements=[[Requirement(Perm((0, )), [(1, 0)])]]) strat = obstruction_transitivity(simple_trans_col) assert strat.comb_classes[0] == Tiling( obstructions=[ Obstruction(Perm((0, 1)), [(0, 0), (0, 1)]), Obstruction(Perm((0, 1)), [(0, 1), (0, 2)]), Obstruction(Perm((0, 1)), [(0, 0), (0, 2)]) ], requirements=[[Requirement(Perm((0, )), [(0, 1)])]]) strat = obstruction_transitivity(simple_trans_row_len2) assert strat.comb_classes[0] == Tiling( obstructions=[ Obstruction(Perm((0, 1)), [(0, 0), (1, 0)]), Obstruction(Perm((0, 1)), [(0, 0), (2, 0)]), Obstruction(Perm((0, 1)), [(0, 0), (3, 0)]), Obstruction(Perm((0, 1)), [(1, 0), (2, 0)]), Obstruction(Perm((0, 1)), [(1, 0), (3, 0)]), Obstruction(Perm((0, 1)), [(2, 0), (3, 0)]) ], requirements=[[Requirement(Perm((0, )), [(1, 0)])], [Requirement(Perm((0, )), [(2, 0)])]]) strat = obstruction_transitivity(simple_trans_row_len3) assert strat.comb_classes[0] == Tiling( obstructions=[ Obstruction(Perm((0, 1)), [(0, 0), (1, 0)]), Obstruction(Perm((0, 1)), [(0, 0), (2, 0)]), Obstruction(Perm((0, 1)), [(0, 0), (3, 0)]), Obstruction(Perm((0, 1)), [(0, 0), (4, 0)]), Obstruction(Perm((0, 1)), [(1, 0), (2, 0)]), Obstruction(Perm((0, 1)), [(1, 0), (3, 0)]), Obstruction(Perm((0, 1)), [(1, 0), (4, 0)]), Obstruction(Perm((0, 1)), [(2, 0), (3, 0)]), Obstruction(Perm((0, 1)), [(2, 0), (4, 0)]), Obstruction(Perm((0, 1)), [(3, 0), (4, 0)]) ], requirements=[[Requirement(Perm((0, )), [(1, 0)])], [Requirement(Perm((0, )), [(2, 0)])], [Requirement(Perm((0, )), [(3, 0)])]])
def simple_tiling(): return Tiling(obstructions=[Obstruction(Perm((1, 0)), [(0, 1), (1, 0)])], requirements=[[ Requirement(Perm((0, 1)), [(0, 0), (1, 0)]), Requirement(Perm((0, 1)), [(0, 0), (1, 1)]) ]])
def positive_one_by_one(): return Tiling( obstructions=[Obstruction(Perm((0, 2, 1)), [(0, 0), (0, 0), (0, 0)])], requirements=[[Requirement(Perm((0, )), [(0, 0)])]])
def test_requirement_corroboration(typical_redundant_requirements, typical_redundant_obstructions): tiling = Tiling(obstructions=[Obstruction(Perm((1, 0)), [(0, 1), (1, 0)])], requirements=[[ Requirement(Perm((0, 1)), [(0, 0), (1, 0)]), Requirement(Perm((0, 1)), [(0, 0), (1, 1)]) ]]) reqins = list(strat.comb_classes for strat in requirement_corroboration(tiling, None)) assert len(reqins) == 2 strat1, strat2 = reqins assert len(strat1) == 2 til1, til2 = strat1 assert til1 == Tiling(obstructions=[ Obstruction(Perm((0, 1)), [(0, 0), (1, 0)]), Obstruction(Perm((1, 0)), [(0, 1), (1, 0)]) ], requirements=[[Requirement(Perm((0, )), [(0, 0)])], [Requirement(Perm((0, )), [(1, 1)])]]) assert til2 == Tiling( obstructions=[], requirements=[[Requirement(Perm((0, 1)), [(0, 0), (1, 0)])]]) tiling = Tiling(obstructions=typical_redundant_obstructions, requirements=typical_redundant_requirements) reqins = list(strat.comb_classes for strat in requirement_corroboration(tiling, None)) assert len(reqins) == sum( len(reqs) for reqs in tiling.requirements if len(reqs) > 1) til1, til2 = reqins[0] assert (set([til1, til2]) == set([ Tiling(requirements=[ [Requirement(Perm((0, 1)), ((2, 0), (3, 1)))], [Requirement(Perm((1, 0)), ((3, 2), (3, 1)))], [Requirement(Perm((0, 1, 2)), ((0, 0), (1, 0), (2, 2)))], [ Requirement(Perm((0, 1, 2)), ((2, 2), (2, 2), (2, 2))), Requirement(Perm((1, 0, 2)), ((0, 0), (0, 0), (0, 0))) ] ], obstructions=typical_redundant_obstructions), Tiling(requirements=[[Requirement(Perm((0, 1)), ((2, 0), (3, 1)))], [Requirement(Perm((1, 0)), ((3, 2), (3, 1)))], [ Requirement(Perm((0, 1, 2)), ((0, 0), (1, 0), (2, 3))), Requirement(Perm((1, 0, 2)), ((0, 0), (1, 0), (2, 2))), Requirement(Perm((1, 0, 2)), ((0, 1), (1, 0), (2, 2))) ], [ Requirement(Perm((0, 1, 2)), ((2, 2), (2, 2), (2, 2))), Requirement(Perm((1, 0, 2)), ((0, 0), (0, 0), (0, 0))) ]], obstructions=( typical_redundant_obstructions + [Obstruction(Perm((0, 1, 2)), ((0, 0), (1, 0), (2, 2)))])) ]))