Peano
Loading...
Searching...
No Matches
test_splittrees_optimize_hierarchy.py
Go to the documentation of this file.
1import itertools
2import pytest
3
4from toolbox.loadbalancing.api.input.RegularGridGenerator import RegularGridGenerator
5import toolbox.loadbalancing.api.strategies.SplitTrees as split_strategy
6
7
8def _child_coords(parent_coords):
9 """Return all 3^d child coordinates for a parent coordinate tuple."""
10 ranges = [range(3 * coord, 3 * coord + 3) for coord in parent_coords]
11 return list(itertools.product(*ranges))
12
13
14@pytest.mark.parametrize(
15 "dimensions,parent_coords",
16 [
17 (2, (0, 0)),
18 (3, (0, 0, 0)),
19 ],
20)
22 dimensions, parent_coords
23):
24 """
25 Stage III invariant in 2D and 3D:
26 If a parent has a full set of mixed children and a dominant subtree that
27 differs from the parent subtree and improves split pressure, parent is promoted.
28 """
30 name=f"pytest-tree-stage-iii-promote-{dimensions}d", max_level=2, dimensions=dimensions
31 )
32
33 parent_level = 0
34 child_level = 1
35
36 # Parent starts in subtree 0.
37 assert tree._tree_arrays[parent_level][parent_coords] == (1, 0)
38
39 children = _child_coords(parent_coords)
40 total_children = len(children)
41 dominant_count = total_children // 2 + 1
42 parent_count = total_children - dominant_count - 1
43
44 # Create mixed children where subtree 2 is dominant:
45 # - dominant_count children in subtree 2
46 # - parent_count children in subtree 0 (parent subtree)
47 # - 1 child in subtree 1
48 for coords in children[:dominant_count]:
49 tree._tree_arrays[child_level][coords] = (1, 2)
50 for coords in children[dominant_count:dominant_count + parent_count]:
51 tree._tree_arrays[child_level][coords] = (1, 0)
52 tree._tree_arrays[child_level][children[-1]] = (1, 1)
53
54 # Act: Stage III only
55 split_strategy._optimize_hierarchy(tree)
56
57 # Parent should be promoted to dominant subtree 2.
58 assert tree._tree_arrays[parent_level][parent_coords] == (1, 2)
59
60
61@pytest.mark.parametrize(
62 "dimensions,parent_coords",
63 [
64 (2, (1, 1)),
65 (3, (1, 1, 1)),
66 ],
67)
69 dimensions, parent_coords
70):
71 """
72 Stage III safety invariant in 2D and 3D:
73 Parent ownership is never moved backward to a smaller subtree id.
74 """
76 name=f"pytest-tree-stage-iii-backward-{dimensions}d", max_level=2, dimensions=dimensions
77 )
78
79 parent_level = 0
80 child_level = 1
81
82 # Set parent to subtree 2.
83 tree._tree_arrays[parent_level][parent_coords] = (1, 2)
84
85 children = _child_coords(parent_coords)
86 total_children = len(children)
87 dominant_count = total_children // 2 + 1
88 parent_count = total_children - dominant_count - 1
89
90 # Mixed children with dominant subtree 0 (backward relative to parent subtree 2).
91 for coords in children[:dominant_count]:
92 tree._tree_arrays[child_level][coords] = (1, 0)
93 for coords in children[dominant_count:dominant_count + parent_count]:
94 tree._tree_arrays[child_level][coords] = (1, 2)
95 tree._tree_arrays[child_level][children[-1]] = (1, 1)
96
97 # Act: Stage III only
98 split_strategy._optimize_hierarchy(tree)
99
100 # Parent should remain unchanged due to backward-move guard.
101 assert tree._tree_arrays[parent_level][parent_coords] == (1, 2)
102
103
104@pytest.mark.parametrize(
105 "dimensions,parent_coords",
106 [
107 (2, (2, 2)),
108 (3, (2, 2, 2)),
109 ],
110)
112 dimensions, parent_coords
113):
114 """
115 Stage III safety invariant in 2D and 3D:
116 No promotion occurs unless all 3^d children of a parent exist.
117 """
119 name=f"pytest-tree-stage-iii-incomplete-{dimensions}d", max_level=2, dimensions=dimensions
120 )
121
122 parent_level = 0
123 child_level = 1
124
125 assert tree._tree_arrays[parent_level][parent_coords] == (1, 0)
126
127 children = _child_coords(parent_coords)
128 total_children = len(children)
129 dominant_count = total_children // 2 + 1
130 parent_count = total_children - dominant_count - 1
131
132 # Build a would-be promotable mixed pattern...
133 for coords in children[:dominant_count]:
134 tree._tree_arrays[child_level][coords] = (1, 2)
135 for coords in children[dominant_count:dominant_count + parent_count]:
136 tree._tree_arrays[child_level][coords] = (1, 0)
137 tree._tree_arrays[child_level][children[-1]] = (1, 1)
138
139 # ...then remove one child (weight=0), invalidating full-child-set precondition.
140 tree._tree_arrays[child_level][children[0]] = (0, 0)
141
142 # Act: Stage III only
143 split_strategy._optimize_hierarchy(tree)
144
145 # Parent must remain unchanged.
146 assert tree._tree_arrays[parent_level][parent_coords] == (1, 0)
147
148
149@pytest.mark.parametrize(
150 "dimensions,parent_coords",
151 [
152 (2, (2, 2)),
153 (3, (2, 2, 2)),
154 ],
155)
157 dimensions, parent_coords
158):
159 """
160 Stage III relaxed mode in 2D and 3D:
161 If full-child-set gating is disabled, mixed partial child sets can still
162 promote a parent to the dominant subtree.
163 """
165 name=f"pytest-tree-stage-iii-incomplete-allowed-{dimensions}d", max_level=2, dimensions=dimensions
166 )
167
168 parent_level = 0
169 child_level = 1
170
171 assert tree._tree_arrays[parent_level][parent_coords] == (1, 0)
172
173 children = _child_coords(parent_coords)
174 total_children = len(children)
175 dominant_count = total_children // 2 + 1
176 parent_count = total_children - dominant_count - 1
177
178 # Build a would-be promotable mixed pattern.
179 for coords in children[:dominant_count]:
180 tree._tree_arrays[child_level][coords] = (1, 2)
181 for coords in children[dominant_count:dominant_count + parent_count]:
182 tree._tree_arrays[child_level][coords] = (1, 0)
183 tree._tree_arrays[child_level][children[-1]] = (1, 1)
184
185 # Remove one child so the set is incomplete.
186 tree._tree_arrays[child_level][children[0]] = (0, 0)
187
188 # Act: Stage III relaxed mode
189 split_strategy._optimize_hierarchy(tree, require_all_children=False)
190
191 # Parent is now allowed to be promoted to dominant subtree 2.
192 assert tree._tree_arrays[parent_level][parent_coords] == (1, 2)
193
194
195@pytest.mark.parametrize("dimensions", [2, 3])
197 """
198 Stage III invariant in 2D and 3D:
199 Optimisation modifies only subtree ids, never node existence flags (weights).
200 """
202 name=f"pytest-tree-stage-iii-weights-{dimensions}d", max_level=2, dimensions=dimensions
203 )
204
205 # Introduce mixed assignments to trigger potential promotions.
206 parent_coords = (0, 0) if dimensions == 2 else (0, 0, 0)
207 child_level = 1
208 children = _child_coords(parent_coords)
209 total_children = len(children)
210 dominant_count = total_children // 2 + 1
211 parent_count = total_children - dominant_count - 1
212 for coords in children[:dominant_count]:
213 tree._tree_arrays[child_level][coords] = (1, 2)
214 for coords in children[dominant_count:dominant_count + parent_count]:
215 tree._tree_arrays[child_level][coords] = (1, 0)
216 tree._tree_arrays[child_level][children[-1]] = (1, 1)
217
218 # Capture all weights before Stage III.
219 weights_before = {}
220 for level in range(tree._max_level):
221 size = 3 ** (level + 1)
222 if dimensions == 2:
223 for a in range(size):
224 for b in range(size):
225 weight, _ = tree._tree_arrays[level][a][b]
226 weights_before[(level, a, b)] = weight
227 else:
228 for a in range(size):
229 for b in range(size):
230 for c in range(size):
231 weight, _ = tree._tree_arrays[level][a][b][c]
232 weights_before[(level, a, b, c)] = weight
233
234 # Act: Stage III only
235 split_strategy._optimize_hierarchy(tree)
236
237 # Assert all weights unchanged.
238 for coords, weight_before in weights_before.items():
239 if dimensions == 2:
240 level, a, b = coords
241 weight_after, _ = tree._tree_arrays[level][a][b]
242 else:
243 level, a, b, c = coords
244 weight_after, _ = tree._tree_arrays[level][a][b][c]
245
246 assert weight_after == weight_before, (
247 f"Node {coords} weight changed from {weight_before} to {weight_after}"
248 )
test_optimize_hierarchy_preserves_node_existence_weights(dimensions)
Stage III invariant in 2D and 3D: Optimisation modifies only subtree ids, never node existence flags ...
test_optimize_hierarchy_promotes_parent_to_dominant_child_subtree(dimensions, parent_coords)
Stage III invariant in 2D and 3D: If a parent has a full set of mixed children and a dominant subtree...
_child_coords(parent_coords)
Return all 3^d child coordinates for a parent coordinate tuple.
test_optimize_hierarchy_does_not_promote_when_children_are_incomplete(dimensions, parent_coords)
Stage III safety invariant in 2D and 3D: No promotion occurs unless all 3^d children of a parent exis...
test_optimize_hierarchy_can_promote_with_incomplete_children_when_enabled(dimensions, parent_coords)
Stage III relaxed mode in 2D and 3D: If full-child-set gating is disabled, mixed partial child sets c...
test_optimize_hierarchy_does_not_promote_when_move_would_be_backward(dimensions, parent_coords)
Stage III safety invariant in 2D and 3D: Parent ownership is never moved backward to a smaller subtre...