Skip to content

Commit fb2e75f

Browse files
authored
Merge pull request #46 from PermutaTriangle/req-placements
Req placements
2 parents ddcd6f5 + 53580cc commit fb2e75f

File tree

8 files changed

+114
-442
lines changed

8 files changed

+114
-442
lines changed

tests/strategies/equivalence_strategies/test_point_placements.py

Lines changed: 45 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
from permuta import Perm
22
from permuta.misc import DIR_EAST, DIR_NORTH, DIR_SOUTH, DIR_WEST, DIRS
33
from tilescopethree.strategies import point_placement, requirement_placement
4-
from tilescopethree.strategies.equivalence_strategies.point_placements import \
5-
place_point_of_requirement
64
from tilings import Obstruction, Requirement, Tiling
75

86
pytest_plugins = [
@@ -15,16 +13,16 @@
1513

1614
def test_point_placement(diverse_tiling, no_point_tiling):
1715
strats = list(point_placement(diverse_tiling))
18-
assert len(strats) == 3 * len(DIRS)
19-
16+
assert len(strats) == 5 * len(DIRS)
2017
strats = list(requirement_placement(no_point_tiling))
21-
assert len(strats) == 3 * len(DIRS)
18+
assert len(strats) == 9 * len(DIRS)
2219
strats = list(point_placement(no_point_tiling))
23-
assert len(strats) == 0
20+
assert len(strats) == 3 * len(DIRS)
2421

2522

2623
def test_place_point_of_requirement_point_only(diverse_tiling):
27-
tiling = place_point_of_requirement(diverse_tiling, 0, 0, DIR_WEST)
24+
tiling = diverse_tiling.place_point_of_gridded_permutation(
25+
diverse_tiling.requirements[0][0], 0, DIR_WEST)
2826
assert tiling == Tiling(
2927
obstructions=[
3028
Obstruction(Perm((0,)), [(1, 0)]),
@@ -53,13 +51,43 @@ def test_place_point_of_requirement_point_only(diverse_tiling):
5351
Requirement(Perm((0, 2, 1)), [(0, 3), (0, 4), (1, 4)]),
5452
Requirement(Perm((0, 2, 1)), [(0, 3), (0, 4), (3, 4)])]])
5553

56-
assert tiling == place_point_of_requirement(diverse_tiling, 0, 0, DIR_EAST)
57-
assert tiling == place_point_of_requirement(
58-
diverse_tiling, 0, 0, DIR_NORTH)
59-
assert tiling == place_point_of_requirement(
60-
diverse_tiling, 0, 0, DIR_SOUTH)
54+
assert tiling == diverse_tiling.place_point_of_gridded_permutation(
55+
diverse_tiling.requirements[0][0], 0, DIR_EAST)
56+
assert tiling == diverse_tiling.place_point_of_gridded_permutation(
57+
diverse_tiling.requirements[0][0], 0, DIR_NORTH)
58+
assert tiling == diverse_tiling.place_point_of_gridded_permutation(
59+
diverse_tiling.requirements[0][0], 0, DIR_SOUTH)
6160

62-
tiling = place_point_of_requirement(diverse_tiling, 1, 0, DIR_WEST)
61+
print(Tiling(
62+
obstructions=[
63+
Obstruction(Perm((0,)), [(2, 0)]),
64+
Obstruction(Perm((0,)), [(2, 2)]),
65+
Obstruction(Perm((0, 1)), [(1, 0), (1, 0)]),
66+
Obstruction(Perm((0, 1)), [(1, 0), (1, 2)]),
67+
Obstruction(Perm((0, 1)), [(1, 2), (1, 2)]),
68+
Obstruction(Perm((0, 1)), [(3, 1), (3, 1)]),
69+
Obstruction(Perm((0, 1)), [(2, 3), (2, 3)]),
70+
Obstruction(Perm((0, 1)), [(2, 3), (4, 3)]),
71+
Obstruction(Perm((0, 1)), [(4, 3), (4, 3)]),
72+
Obstruction(Perm((1, 0)), [(1, 0), (1, 0)]),
73+
Obstruction(Perm((1, 0)), [(1, 2), (1, 0)]),
74+
Obstruction(Perm((1, 0)), [(1, 2), (1, 2)]),
75+
Obstruction(Perm((1, 0)), [(3, 1), (3, 1)]),
76+
Obstruction(Perm((1, 0)), [(2, 3), (2, 3)]),
77+
Obstruction(Perm((1, 0)), [(2, 3), (4, 3)]),
78+
Obstruction(Perm((1, 0)), [(4, 3), (4, 3)]),
79+
Obstruction(Perm((0, 1, 2)), [(0, 0), (1, 3), (1, 3)]),
80+
Obstruction(Perm((0, 2, 3, 1)), [(0, 2), (1, 3), (1, 3), (4, 2)])],
81+
requirements=[
82+
[Requirement(Perm((0,)), [(3, 1)])],
83+
[Requirement(Perm((0,)), [(1, 0)]),
84+
Requirement(Perm((0,)), [(1, 2)])],
85+
[Requirement(Perm((0,)), [(2, 3)]),
86+
Requirement(Perm((0,)), [(4, 3)])],
87+
[Requirement(Perm((1, 0)), [(0, 4), (0, 3)]),
88+
Requirement(Perm((0, 2, 1)), [(0, 3), (0, 4), (1, 4)])]]))
89+
tiling = diverse_tiling.place_point_of_gridded_permutation(
90+
diverse_tiling.requirements[1][0], 0, DIR_WEST)
6391
assert tiling == Tiling(
6492
obstructions=[
6593
Obstruction(Perm((0,)), [(2, 0)]),
@@ -90,14 +118,16 @@ def test_place_point_of_requirement_point_only(diverse_tiling):
90118
Requirement(Perm((0, 2, 1)), [(0, 3), (0, 4), (1, 4)])]])
91119

92120
tiling = Tiling(requirements=[[Requirement(Perm((0,)), [(0, 0)])]])
93-
assert place_point_of_requirement(tiling, 0, 0, DIR_SOUTH) == Tiling(
121+
assert tiling.place_point_of_gridded_permutation(tiling.requirements[0][0],
122+
0, DIR_SOUTH) == Tiling(
94123
obstructions=[Obstruction(Perm((0, 1)), [(0, 0), (0, 0)]),
95124
Obstruction(Perm((1, 0)), [(0, 0), (0, 0)])],
96125
requirements=[[Requirement(Perm((0,)), [(0, 0)])]])
97126

98127

99128
def test_place_point_of_requirement(no_point_tiling):
100-
tiling = place_point_of_requirement(no_point_tiling, 2, 1, DIR_WEST)
129+
tiling = no_point_tiling.place_point_of_gridded_permutation(
130+
no_point_tiling.requirements[2][0], 1, DIR_WEST)
101131
tiling2 = Tiling(
102132
obstructions=[
103133
Obstruction(Perm((0, 1)), [(0, 1), (1, 3)]),

tilescopethree/strategies/batch_strategies/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@
44
all_requirement_insertions, all_row_insertions,
55
root_requirement_insertion)
66
from .list_requirement_placements import (col_placements,
7+
partial_col_placements,
8+
partial_row_and_col_placements,
9+
partial_row_placements,
710
requirement_list_placement,
11+
row_and_col_placements,
812
row_placements)
913
from .requirement_corroboration import requirement_corroboration
1014
from .targeted_cell_insertion import targeted_cell_insertion
Lines changed: 35 additions & 191 deletions
Original file line numberDiff line numberDiff line change
@@ -1,208 +1,52 @@
1-
from itertools import chain
1+
from itertools import product
22

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
76

87

98
def requirement_list_placement(tiling, **kwargs):
109
"""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)))
2517

2618

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()
4021

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 = []
4822

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()
6525

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')
11626

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()
11731

118-
def col_placements(tiling, **kwargs):
119-
yield from row_placements(tiling, row=False, **kwargs)
12032

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()
12138

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
18739

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()
18845

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.")
20746

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()

tilescopethree/strategies/equivalence_strategies/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@
33
from .fusion_with_interleaving import fusion_with_interleaving
44
from .partial_point_placements import (partial_point_placement,
55
partial_requirement_placement)
6-
from .point_placements import point_placement, requirement_placement
6+
from .point_placements import (all_placements, point_placement,
7+
requirement_placement)
Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,12 @@
11
from comb_spec_searcher import EquivalenceRule
22
from permuta.misc import DIR_WEST
3-
from tilescopethree.strategies.batch_strategies.point_placements import \
4-
place_point_of_requirement
3+
from tilings.algorithms import RequirementPlacement
54

65

76
def point_isolations(tiling, **kwargs):
8-
point_cells = tiling.point_cells
9-
for ri, reqs in enumerate(tiling.requirements):
10-
if len(reqs) > 1:
11-
continue
12-
cell = reqs[0].is_point_perm()
13-
if cell is None or cell not in point_cells:
14-
continue
15-
yield EquivalenceRule(
16-
formal_step=("Isolating point at {} into its own row and "
17-
"column").format(cell),
18-
# Direction does not matter
19-
comb_class=place_point_of_requirement(tiling, ri, 0, DIR_WEST))
7+
req_placement = RequirementPlacement(tiling)
8+
for cell in tiling.point_cells:
9+
if not tiling.only_cell_in_row_and_col():
10+
isolated_tiling = req_placement.place_point_in_cell(cell, DIR_WEST)
11+
yield EquivalenceRule("Isolate point at cell {}.".format(cell),
12+
isolated_tiling)

0 commit comments

Comments
 (0)