|
1 | | -from itertools import chain |
| 1 | +from itertools import product |
2 | 2 |
|
3 | | -from comb_spec_searcher import Rule |
4 | | -from permuta import Perm |
5 | | -from permuta.misc import DIR_EAST, DIR_NONE, DIR_NORTH, DIR_SOUTH, DIR_WEST |
6 | | -from tilings import Obstruction, Requirement, Tiling |
| 3 | +from comb_spec_searcher import BatchRule |
| 4 | +from permuta.misc import DIR_EAST, DIR_NORTH, DIR_SOUTH, DIR_WEST |
| 5 | +from tilings.algorithms import RequirementPlacement |
7 | 6 |
|
8 | 7 |
|
9 | 8 | def requirement_list_placement(tiling, **kwargs): |
10 | 9 | """Places all requirements on the tiling in every direction.""" |
11 | | - for req in tiling.requirements: |
12 | | - for direction in [DIR_NORTH, DIR_SOUTH, DIR_EAST, DIR_WEST]: |
13 | | - tilings = place_requirement_list(tiling, req, direction) |
14 | | - if tilings is None: |
15 | | - continue |
16 | | - yield Rule( |
17 | | - formal_step=("Place requirement {} in direction {}." |
18 | | - "".format(req, direction)), |
19 | | - comb_classes=tilings, |
20 | | - ignore_parent=False, |
21 | | - possibly_empty=[True for _ in tilings], |
22 | | - inferable=[True for _ in tilings], |
23 | | - workable=[True for _ in tilings], |
24 | | - constructor='disjoint') |
| 10 | + req_placement = RequirementPlacement(tiling) |
| 11 | + directions = (DIR_EAST, DIR_NORTH, DIR_SOUTH, DIR_WEST) |
| 12 | + for req, direction in product(tiling.requirements, directions): |
| 13 | + yield BatchRule(req_placement.place_point_of_req_list(req, direction), |
| 14 | + "Inserting {} point of requirement list ({})".format( |
| 15 | + req_placement._direction_string(direction), |
| 16 | + ", ".join(str(r) for r in req))) |
25 | 17 |
|
26 | 18 |
|
27 | | -def row_placements(tiling, row=True, positive=True, regions=False, **kwargs): |
28 | | - """Places the points in a row (or col if row=False) in the given |
29 | | - direction.""" |
30 | | - if row: |
31 | | - x = tiling.dimensions[1] |
32 | | - y = tiling.dimensions[0] |
33 | | - only_cell_in_col = tiling.only_cell_in_col |
34 | | - directions = [DIR_NORTH, DIR_SOUTH] |
35 | | - else: |
36 | | - x = tiling.dimensions[0] |
37 | | - y = tiling.dimensions[1] |
38 | | - only_cell_in_col = tiling.only_cell_in_row |
39 | | - directions = [DIR_EAST, DIR_WEST] |
| 19 | +def row_placements(tiling, **kwargs): |
| 20 | + yield from RequirementPlacement(tiling).all_row_placement_rules() |
40 | 21 |
|
41 | | - rows = range(x) |
42 | | - if kwargs.get("index") is not None: |
43 | | - rows = [kwargs.get("index")] |
44 | | - if kwargs.get("direction") is not None: |
45 | | - directions = [kwargs["direction"]] |
46 | | - if regions: |
47 | | - forward_maps = [] |
48 | 22 |
|
49 | | - direction = kwargs.get('direction') |
50 | | - if direction is not None: |
51 | | - if row: |
52 | | - if direction == DIR_NORTH: |
53 | | - directions = [DIR_NORTH] |
54 | | - elif direction == DIR_SOUTH: |
55 | | - directions = [DIR_SOUTH] |
56 | | - else: |
57 | | - raise ValueError("Can't place rows in direction.") |
58 | | - else: |
59 | | - if direction == DIR_EAST: |
60 | | - directions = [DIR_EAST] |
61 | | - elif direction == DIR_WEST: |
62 | | - directions = [DIR_WEST] |
63 | | - else: |
64 | | - raise ValueError("Can't place cols in direction.") |
| 23 | +def col_placements(tiling, **kwargs): |
| 24 | + yield from RequirementPlacement(tiling).all_col_placement_rules() |
65 | 25 |
|
66 | | - for i in rows: |
67 | | - place = True |
68 | | - cells_in_row = [] |
69 | | - for j in range(y): |
70 | | - cell = (j, i) if row else (i, j) |
71 | | - if positive and cell not in tiling.positive_cells: |
72 | | - place = False |
73 | | - break |
74 | | - cells_in_row.append(cell) |
75 | | - if place: |
76 | | - if (len(cells_in_row) != 1 or |
77 | | - not cells_in_row[0] in tiling.point_cells or |
78 | | - not only_cell_in_col(cells_in_row[0])): |
79 | | - req_list = tuple(Requirement(Perm((0,)), (cell,)) |
80 | | - for cell in cells_in_row) |
81 | | - if not positive: |
82 | | - """Adding the empty row case.""" |
83 | | - empty_row_tiling = Tiling(tiling.obstructions + |
84 | | - tuple(Obstruction(Perm((0,)), |
85 | | - (cell,)) |
86 | | - for cell in cells_in_row), |
87 | | - tiling.requirements) |
88 | | - if regions: |
89 | | - forward_maps.append({c: frozenset([c]) |
90 | | - for c in tiling.active_cells}) |
91 | | - for direction in directions: |
92 | | - if regions: |
93 | | - tilings, placed_maps = place_requirement_list( |
94 | | - tiling, req_list, direction, |
95 | | - regions=regions) |
96 | | - if not positive: |
97 | | - tilings = [empty_row_tiling] + tilings |
98 | | - forward_maps.extend(placed_maps) |
99 | | - yield tilings, forward_maps |
100 | | - else: |
101 | | - tilings = place_requirement_list(tiling, req_list, |
102 | | - direction) |
103 | | - if not positive: |
104 | | - tilings = [empty_row_tiling] + tilings |
105 | | - yield Rule( |
106 | | - formal_step=("Placing {} {} in direction {}." |
107 | | - "".format("row" if row else "col", |
108 | | - i, direction, |
109 | | - i, direction, int(positive))), |
110 | | - comb_classes=tilings, |
111 | | - ignore_parent=False, |
112 | | - possibly_empty=[True for _ in tilings], |
113 | | - inferable=[True for _ in tilings], |
114 | | - workable=[True for _ in tilings], |
115 | | - constructor='disjoint') |
116 | 26 |
|
| 27 | +def row_and_col_placements(tiling, **kwargs): |
| 28 | + req_placements = RequirementPlacement(tiling) |
| 29 | + yield from req_placements.all_row_placement_rules() |
| 30 | + yield from req_placements.all_col_placement_rules() |
117 | 31 |
|
118 | | -def col_placements(tiling, **kwargs): |
119 | | - yield from row_placements(tiling, row=False, **kwargs) |
120 | 32 |
|
| 33 | +def partial_row_placements(tiling, **kwargs): |
| 34 | + req_placements = (RequirementPlacement(tiling, own_row=False), |
| 35 | + RequirementPlacement(tiling, own_col=False)) |
| 36 | + for req_placement in req_placements: |
| 37 | + yield from req_placement.all_row_placement_rules() |
121 | 38 |
|
122 | | -def place_requirement_list(tiling, req_list, direction, regions=False): |
123 | | - """Return the list of tilings obtained by placing the direction-most point |
124 | | - of a requirement list. This represents a batch strategy, where the |
125 | | - direction-most point of each requirement in the list is placed.""" |
126 | | - # Compute the points furthest in the given direction. |
127 | | - min_points = minimum_points(req_list, direction) |
128 | | - if len([c for _, c in min_points]) != len(set([c for _, c in min_points])): |
129 | | - # Can't handle list requirements with more than req farthest in the |
130 | | - # direction in same cell. |
131 | | - return None |
132 | | - # For each tiling, compute the tiling where this point is placed furthest |
133 | | - # in that direction. |
134 | | - res = [] |
135 | | - if regions: |
136 | | - forward_maps = [] |
137 | | - for (idx, cell), req in zip(min_points, req_list): |
138 | | - # Placing the forced occurrence of the point in the requirement |
139 | | - new_req, forced_obstructions = req.place_forced_point(idx, direction) |
140 | | - assert len(new_req) == 1 |
141 | | - # Add the forced obstruction to ensure no other requirement has a point |
142 | | - # further in that direction. |
143 | | - forced_obstructions = (forced_obstructions + |
144 | | - list(chain.from_iterable( |
145 | | - r.other_req_forced_point(cell, direction) |
146 | | - for r in req_list if r != req))) |
147 | | - # New indices of the point |
148 | | - point_cell = (cell[0] + 1, cell[1] + 1) |
149 | | - # The set of new obstructions, consisting of the forced obstructions, |
150 | | - # other obstructions where the point placement has been taken into |
151 | | - # account and the 12, 21 in the cell. |
152 | | - newobs = forced_obstructions + list(chain.from_iterable( |
153 | | - ob.place_point(cell, DIR_NONE) for ob in tiling.obstructions)) + [ |
154 | | - Obstruction.single_cell(Perm((0, 1)), point_cell), |
155 | | - Obstruction.single_cell(Perm((1, 0)), point_cell)] |
156 | | - # The rest of the requirements |
157 | | - other_reqs = [reqs for reqs in tiling.requirements if reqs != req_list] |
158 | | - # The new requirements, consisting of the requirement with the point |
159 | | - # placed, other requirements where point placement has been taken into |
160 | | - # account and the point requirement in the cell. |
161 | | - newreqs = [list(chain.from_iterable(r.place_point(cell, DIR_NONE) |
162 | | - for r in reqs)) |
163 | | - for reqs in other_reqs] + [new_req] + [ |
164 | | - [Requirement.single_cell(Perm((0,)), point_cell)]] |
165 | | - placed_tiling = Tiling(newobs, newreqs) |
166 | | - res.append(placed_tiling) |
167 | | - if regions: |
168 | | - def cell_map(c): |
169 | | - mindex, minval = c |
170 | | - maxdex = mindex + 1 |
171 | | - maxval = minval + 1 |
172 | | - if mindex >= cell[0]: |
173 | | - maxdex += 2 |
174 | | - if minval >= cell[1]: |
175 | | - maxval += 2 |
176 | | - if mindex > cell[0]: |
177 | | - mindex += 2 |
178 | | - if minval > cell[1]: |
179 | | - minval += 2 |
180 | | - return frozenset([(x, y) for x in range(mindex, maxdex) |
181 | | - for y in range(minval, maxval)]) |
182 | | - forward_maps.append({c: cell_map(c) for c in tiling.active_cells}) |
183 | | - if regions: |
184 | | - return res, forward_maps |
185 | | - else: |
186 | | - return res |
187 | 39 |
|
| 40 | +def partial_col_placements(tiling, **kwargs): |
| 41 | + req_placements = (RequirementPlacement(tiling, own_row=False), |
| 42 | + RequirementPlacement(tiling, own_col=False)) |
| 43 | + for req_placement in req_placements: |
| 44 | + yield from req_placement.all_col_placement_rules() |
188 | 45 |
|
189 | | -def minimum_points(req_list, direction): |
190 | | - """Return a list of tuple containing the index and cell of the point in the |
191 | | - requirement furthest to the geiven direction.""" |
192 | | - res = [] |
193 | | - if direction == DIR_WEST: |
194 | | - res = [(0, req.pos[0]) for req in req_list] |
195 | | - elif direction == DIR_EAST: |
196 | | - res = [(len(req) - 1, req.pos[-1]) for req in req_list] |
197 | | - elif direction == DIR_SOUTH: |
198 | | - for req in req_list: |
199 | | - mindex = req.patt.index(0) |
200 | | - res.append((mindex, req.pos[mindex])) |
201 | | - elif direction == DIR_NORTH: |
202 | | - for req in req_list: |
203 | | - maxdex = req.patt.index(0) |
204 | | - res.append((maxdex, req.pos[maxdex])) |
205 | | - else: |
206 | | - raise ValueError("Must choose north, south, east or west.") |
207 | 46 |
|
208 | | - return res |
| 47 | +def partial_row_and_col_placements(tiling, **kwargs): |
| 48 | + req_placements = (RequirementPlacement(tiling, own_row=False), |
| 49 | + RequirementPlacement(tiling, own_col=False)) |
| 50 | + for req_placement in req_placements: |
| 51 | + yield from req_placement.all_row_placement_rules() |
| 52 | + yield from req_placement.all_col_placement_rules() |
0 commit comments