|
1 | 1 | """The more general fusion strategy. Fuse two rows if actually one row where |
2 | 2 | you can draw a line somewhere.""" |
3 | | -from collections import defaultdict |
4 | | - |
5 | 3 | from comb_spec_searcher import Rule |
6 | | -from permuta import Perm |
7 | | -from tilings import Obstruction, Tiling |
| 4 | +from tilings.algorithms import ComponentFusion |
| 5 | + |
| 6 | +from .fusion import general_fusion_iterator |
8 | 7 |
|
9 | 8 |
|
10 | 9 | def fusion_with_interleaving(tiling, **kwargs): |
11 | | - """Yield rules found by fusing rows and columns of a tiling, where the |
| 10 | + """ |
| 11 | + Yield rules found by fusing rows and columns of a tiling, where the |
12 | 12 | unfused tiling obtained by drawing a line through certain heights/indices |
13 | | - of the row/column.""" |
| 13 | + of the row/column. |
| 14 | + """ |
14 | 15 | if tiling.requirements: |
15 | 16 | return |
16 | | - bases = tiling.cell_basis() |
17 | | - for row_index in range(tiling.dimensions[1] - 1): |
18 | | - if fusable(tiling, row_index, bases, True, **kwargs): |
19 | | - yield Rule(("Fuse rows fancily {} and {}|{}|." |
20 | | - "").format(row_index, row_index + 1, row_index), |
21 | | - [fuse_tiling(tiling, row_index, True)], |
22 | | - inferable=[True], workable=[True], |
23 | | - possibly_empty=[False], constructor='other') |
24 | | - for col_index in range(tiling.dimensions[0] - 1): |
25 | | - if fusable(tiling, col_index, bases, False, **kwargs): |
26 | | - # if not original_fusable(tiling, col_index, False): |
27 | | - # print("================================") |
28 | | - # print("On the tiling:") |
29 | | - # print(tiling) |
30 | | - # print("Column {} is fancy fusable but not ordinary fusable. |
31 | | - # Explain.".format(col_index)) |
32 | | - yield Rule(("Fuse columns fancily {} and {}|{}|." |
33 | | - "").format(col_index, col_index + 1, col_index), |
34 | | - [fuse_tiling(tiling, col_index, False)], |
35 | | - inferable=[True], workable=[True], |
36 | | - possibly_empty=[False], constructor='other') |
37 | | - # elif original_fusable(tiling, col_index, False): |
38 | | - # print("================================") |
39 | | - # print("On the tiling:") |
40 | | - # print(tiling) |
41 | | - # print("Column {} is ordinary fusable but not fancy fusable. |
42 | | - # Explain.".format(col_index)) |
43 | | - |
44 | | - |
45 | | -def fusable(tiling, row_index, bases, row=True, **kwargs): |
46 | | - """Return true if adjacent rows can be viewed as one row where you draw a |
47 | | - horizontal line through the permutation.""" |
48 | | - first_row = (tiling.cells_in_row(row_index) |
49 | | - if row else tiling.cells_in_col(row_index)) |
50 | | - # only consider rows of size one |
51 | | - if len(first_row) > 1: |
52 | | - return False |
53 | | - second_row = (tiling.cells_in_row(row_index + 1) |
54 | | - if row else tiling.cells_in_col(row_index + 1)) |
55 | | - # adjacent cells in rows must not be empty |
56 | | - if len(first_row) != len(second_row): |
57 | | - return False |
58 | | - first_cell = list(first_row)[0] |
59 | | - second_cell = list(second_row)[0] |
60 | | - # ensure the other cell is adjacent |
61 | | - if ((row and first_cell[0] != second_cell[0]) or |
62 | | - (not row and first_cell[1] != second_cell[1])): |
63 | | - return False |
64 | | - # ensure other cells basis is the same, and not the same as the root basis |
65 | | - if (bases[first_cell][0] != bases[second_cell][0]): |
66 | | - return False |
67 | | - obstructions_to_add = [] |
68 | | - for ob in tiling.obstructions: |
69 | | - # for each obstruction that occupies the first cell, draw a line |
70 | | - # through it in every way so that it crosses to the secoond cell |
71 | | - # TODO: Should we be worried about obstruction going only to the |
72 | | - # second cell? |
73 | | - if ob.occupies(first_cell): |
74 | | - # ignore the obstructions that imply skew or sum components |
75 | | - if len(ob) == 2 and ob.occupies(second_cell): |
76 | | - continue |
77 | | - # the point in the first cell |
78 | | - in_cell = [(idx, val) for idx, val in enumerate(ob.patt) |
79 | | - if ob.pos[idx] == first_cell] |
80 | | - if row: |
81 | | - in_cell = sorted(in_cell, key=lambda x: (x[1], x[0])) |
82 | | - special_cell = second_cell |
83 | | - # place i points in bottom cell, rest in top. |
84 | | - for i in range(len(in_cell)): |
85 | | - maxdex = [point[0] for point in in_cell[i:]] |
86 | | - pos = [special_cell if i in maxdex else c |
87 | | - for i, c in enumerate(ob.pos)] |
88 | | - obstructions_to_add.append(Obstruction(ob.patt, pos)) |
89 | | - if ob.occupies(second_cell): |
90 | | - in_cell = [(idx, val) for idx, val in enumerate(ob.patt) |
91 | | - if ob.pos[idx] == second_cell] |
92 | | - if row: |
93 | | - in_cell = sorted(in_cell, key=lambda x: -x[1]) |
94 | | - else: |
95 | | - in_cell = sorted(in_cell, key=lambda x: -x[0]) |
96 | | - special_cell = first_cell |
97 | | - # place i points in bottom cell, rest in top. |
98 | | - for i in range(len(in_cell)): |
99 | | - maxdex = [point[0] for point in in_cell[i:]] |
100 | | - pos = [special_cell if i in maxdex else c |
101 | | - for i, c in enumerate(ob.pos)] |
102 | | - obstructions_to_add.append(Obstruction(ob.patt, pos)) |
103 | | - |
104 | | - # if the tiling is unchanged, then the previous obstruction imply all those |
105 | | - # obstructions that needed to be added, and therefore we can think of this |
106 | | - # as one row with a line drawn through it |
107 | | - if tiling == Tiling(list(tiling.obstructions) + obstructions_to_add, |
108 | | - tiling.requirements): |
109 | | - # return True |
110 | | - if (Obstruction(Perm((0, 1)), |
111 | | - (first_cell, second_cell)) in tiling.obstructions or |
112 | | - Obstruction(Perm((0, 1)), |
113 | | - (second_cell, first_cell)) in tiling.obstructions or |
114 | | - Obstruction(Perm((1, 0)), |
115 | | - (first_cell, second_cell)) in tiling.obstructions or |
116 | | - Obstruction(Perm((1, 0)), |
117 | | - (second_cell, first_cell)) in tiling.obstructions): |
118 | | - return True |
119 | | - |
120 | | - |
121 | | -def fuse_tiling(tiling, row_index, row=True, **kwargs): |
122 | | - """ |
123 | | - Return the tiling where rows 'row_index' and 'row_index + 1' are fused. |
124 | | -
|
125 | | - If row=False, then it does the same for columns. |
126 | | -
|
127 | | - (Note unlike fusion file, we ignore obstruction using the other cell) |
128 | | - """ |
129 | | - fused_obstructions = [fuse_gridded_perm(ob, row_index, row) |
130 | | - for ob in tiling.obstructions |
131 | | - if ((row and |
132 | | - all(c[1] != row_index + 1 for c in ob.pos)) or |
133 | | - (not row and |
134 | | - all(c[0] != row_index + 1 for c in ob.pos)))] |
135 | | - fused_requirements = [[fuse_gridded_perm(req, row_index, row) |
136 | | - for req in req_list] |
137 | | - for req_list in tiling.requirements] |
138 | | - fused_tiling = Tiling(fused_obstructions, fused_requirements) |
139 | | - if kwargs.get('regions', False): |
140 | | - cell_to_region = {} |
141 | | - for cell in tiling.active_cells: |
142 | | - x, y = cell |
143 | | - if row and y > row_index: |
144 | | - y -= 1 |
145 | | - elif not row and x > row_index: |
146 | | - x -= 1 |
147 | | - cell_to_region[cell] = set([(x, y)]) |
148 | | - return ([fused_tiling], [cell_to_region]) |
149 | | - return fused_tiling |
150 | | - |
151 | | - |
152 | | -def fuse_gridded_perm(gp, row_index, row=True): |
153 | | - """Fuses rows 'row_index' and 'row_index + 1'.""" |
154 | | - fused_pos = [] |
155 | | - for cell in gp.pos: |
156 | | - x, y = cell |
157 | | - if row and y > row_index: |
158 | | - y -= 1 |
159 | | - elif not row and x > row_index: |
160 | | - x -= 1 |
161 | | - fused_pos.append((x, y)) |
162 | | - return gp.__class__(gp.patt, fused_pos) |
| 17 | + yield from general_fusion_iterator(tiling, ComponentFusion) |
0 commit comments