Replace cyclic rotation with Latin-square design so groups meet once

The fixed +1/-4 offsets in get_courses only produced a collision-free
rotation for certain group counts; for n=9 (three groups per course) the
pairwise gaps collapsed and 9 pairs of groups met twice.

Replace it with a resolvable transversal design (_rotation_hosts): slots
form a k x 3 grid, each course is a parallel class partitioning all groups
into transversal tables of three, guaranteeing every pair meets at most
once for any n >= 9. n=3/6 are combinatorially impossible and fall back to
a degenerate same-row rotation that still satisfies the structural
invariants. Add a regression test asserting no pair meets more than once.
This commit is contained in:
2026-07-10 18:15:37 +02:00
parent 6b0fca0100
commit e7bb0b9c69
3 changed files with 75 additions and 7 deletions
+14
View File
@@ -73,6 +73,20 @@ class TestGetCourses:
assert len(guests) == 3
assert {g % 3 for g in guests} == {0, 1, 2}
@pytest.mark.parametrize("n", [n for n in GROUP_COUNTS if n >= 9])
def test_no_two_groups_meet_more_than_once(self, n):
# The whole point of the Latin-square rotation: for n >= 9 (>= 3 groups per
# course) every pair of groups shares a table at most once across the evening.
# (n = 3 and 6 are combinatorially impossible and deliberately excluded.)
hosts_of = {i: set(get_courses(i, n)) for i in range(n)}
meetings = Counter()
for host in range(n):
guests = sorted(g for g in range(n) if host in hosts_of[g])
for a, b in itertools.combinations(guests, 2):
meetings[(a, b)] += 1
repeats = {pair: c for pair, c in meetings.items() if c > 1}
assert repeats == {}, f"pairs meeting more than once: {repeats}"
class TestFastTotalTime:
def test_matches_hand_computed_value_n3(self):