FA-94456 / Exam timetabling constraints / Open access
Extended sittings compared in input order · case 01
A student's exams listed out of order produce spurious or missed conflicts.
ROOT CAUSE
Sittings are not sorted by start before pairing.
VERIFIED REPAIR
Sort sittings by start time, ties by id.
Unsuccessful approach: Sorting by exam id is not chronological.
Case contract
A student's exams [id, start, duration] and an extra-time percentage. Extended duration = ceil(duration * (100 + pct) / 100), then rounded up to a multiple of 5 minutes. In start order (ties by id) a pair conflicts if the next start is earlier than the previous extended end plus the rest minutes. Return [[id, extended end] in order, conflicting pairs].
Why this case matters
Access arrangements extend sittings; the timetable must still leave rest between a student's exams.
1 / The failure
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(exams, pct, rest):
rows = []
for eid, st, dur in exams:
ext = -(-dur * (100 + pct) // 100)
ext = -(-ext // 5) * 5
rows.append([eid, st, st + ext])
conf = []
for a, b in zip(rows, rows[1:]):
if b[1] < a[2] + rest:
conf.append([a[0], b[0]])
return [[[r[0], r[2]] for r in rows], conf]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: chronological order 1', [[['B', 800, 60], ['A', 540, 90]], 15, 30],
[[['A', 645], ['B', 870]], []]),
('regression variant: chronological order 2',
[[['P1', 740, 120], ['P0', 540, 44], ['W2', 940, 72]], 15, 30],
[[['P0', 595], ['P1', 880], ['W2', 1025]], []]),
('partial repair guard 3', [[['T1', 720, 120], ['V0', 600, 180]], 33, 15],
[[['V0', 840], ['T1', 880]], [['V0', 'T1']]]),
('boundary control 4', [[['A', 540, 120], ['B', 720, 90]], 50, 0], [[['A', 720], ['B', 855]], []]),
('boundary control 5', [[['A', 540, 73], ['B', 640, 60]], 10, 15], [[['A', 625], ['B', 710]], []]),
('normal control 6', [[['R2', 960, 90], ['T3', 1160, 90], ['V1', 780, 150], ['W0', 600, 73]], 10, 30],
[[['W0', 685], ['V1', 945], ['R2', 1060], ['T3', 1260]], [['V1', 'R2']]]),
('normal control 7', [[['W2', 940, 88], ['T0', 540, 180], ['W1', 740, 180], ['R3', 1090, 150]], 25, 15],
[[['T0', 765], ['W1', 965], ['W2', 1050], ['R3', 1280]], [['T0', 'W1'], ['W1', 'W2']]]),
('normal control 8', [[['R3', 1080, 60], ['U0', 600, 100], ['V2', 930, 180], ['R1', 750, 88]], 25, 30],
[[['U0', 725], ['R1', 860], ['V2', 1155], ['R3', 1155]], [['U0', 'R1'], ['V2', 'R3']]])],
[('regression: chronological order 1',
[[['P1', 690, 150], ['S2', 890, 72], ['Q0', 600, 150], ['R3', 1010, 90]], 50, 15],
[[['Q0', 825], ['P1', 915], ['S2', 1000], ['R3', 1145]], [['Q0', 'P1'], ['P1', 'S2'], ['S2', 'R3']]]),
('regression variant: chronological order 2',
[[['P3', 1080, 180], ['U2', 930, 100], ['W1', 690, 72], ['T0', 540, 72]], 10, 15],
[[['T0', 620], ['W1', 770], ['U2', 1040], ['P3', 1280]], []]),
('partial repair guard 3', [[['V0', 600, 182], ['T1', 690, 73]], 10, 30],
[[['V0', 805], ['T1', 775]], [['V0', 'T1']]]),
('boundary control 4', [[['A', 540, 91]], 10, 30], [[['A', 645]], []]),
('boundary control 5', [[['A', 540, 100], ['B', 699, 60]], 25, 30], [[['A', 665], ['B', 774]], []]),
('normal control 6', [[['T0', 600, 72], ['P2', 1040, 100], ['T3', 1190, 182], ['Q1', 840, 100]], 10, 15],
[[['T0', 680], ['Q1', 950], ['P2', 1150], ['T3', 1395]], []]),
('normal control 7', [[['Q2', 840, 91], ['S0', 600, 88], ['R1', 750, 73]], 50, 30],
[[['S0', 735], ['R1', 860], ['Q2', 980]], [['S0', 'R1'], ['R1', 'Q2']]]),
('normal control 8', [[['S1', 630, 100], ['V3', 930, 88], ['V0', 540, 180], ['R2', 750, 73]], 50, 30],
[[['V0', 810], ['S1', 780], ['R2', 860], ['V3', 1065]], [['V0', 'S1'], ['S1', 'R2']]])],
[('regression: chronological order 1', [[['T1', 840, 72], ['R0', 600, 44]], 33, 30],
[[['R0', 660], ['T1', 940]], []]),
('regression variant: chronological order 2',
[[['U0', 540, 150], ['P2', 870, 60], ['Q1', 780, 88]], 10, 30],
[[['U0', 705], ['Q1', 880], ['P2', 940]], [['Q1', 'P2']]]),
('partial repair guard 3',
[[['S2', 810, 100], ['Q0', 600, 72], ['V1', 690, 100], ['R3', 990, 120]], 33, 15],
[[['Q0', 700], ['V1', 825], ['S2', 945], ['R3', 1150]], [['Q0', 'V1'], ['V1', 'S2']]]),
('boundary control 4', [[['A', 540, 88]], 25, 30], [[['A', 650]], []]),
('boundary control 5', [[['A', 540, 72]], 33, 15], [[['A', 640]], []]),
('normal control 6', [[['S0', 540, 90], ['U1', 740, 90]], 15, 30], [[['S0', 645], ['U1', 845]], []]),
('normal control 7', [[['Q2', 810, 120], ['S3', 1050, 73], ['V0', 540, 90], ['V1', 630, 73]], 25, 30],
[[['V0', 655], ['V1', 725], ['Q2', 960], ['S3', 1145]], [['V0', 'V1']]]),
('normal control 8', [[['V1', 630, 182], ['Q0', 540, 120]], 50, 30],
[[['Q0', 720], ['V1', 905]], [['Q0', 'V1']]])],
[('regression: chronological order 1',
[[['S2', 900, 73], ['P1', 780, 60], ['U3', 1050, 44], ['W0', 540, 72]], 50, 30],
[[['W0', 650], ['P1', 870], ['S2', 1010], ['U3', 1120]], []]),
('regression variant: chronological order 2', [[['P1', 780, 150], ['U0', 600, 90]], 50, 15],
[[['U0', 735], ['P1', 1005]], []]),
('partial repair guard 3',
[[['V0', 600, 90], ['R2', 990, 91], ['S1', 840, 120], ['Q3', 1110, 100]], 33, 30],
[[['V0', 720], ['S1', 1000], ['R2', 1115], ['Q3', 1245]], [['S1', 'R2'], ['R2', 'Q3']]]),
('boundary control 4', [[['A', 540, 120], ['B', 720, 90]], 50, 0], [[['A', 720], ['B', 855]], []]),
('boundary control 5', [[['A', 540, 73], ['B', 640, 60]], 10, 15], [[['A', 625], ['B', 710]], []]),
('normal control 6', [[['T1', 780, 180], ['P0', 540, 88]], 50, 30], [[['P0', 675], ['T1', 1050]], []]),
('normal control 7', [[['P3', 1110, 44], ['V1', 720, 72], ['S2', 870, 72], ['P0', 540, 91]], 15, 15],
[[['P0', 645], ['V1', 805], ['S2', 955], ['P3', 1165]], []]),
('normal control 8', [[['P0', 600, 150], ['R2', 840, 90], ['S1', 720, 90]], 50, 30],
[[['P0', 825], ['S1', 855], ['R2', 975]], [['P0', 'S1'], ['S1', 'R2']]])],
[('regression: chronological order 1',
[[['V2', 810, 180], ['U0', 540, 44], ['V3', 1010, 72], ['T1', 720, 100]], 33, 30],
[[['U0', 600], ['T1', 855], ['V2', 1050], ['V3', 1110]], [['T1', 'V2'], ['V2', 'V3']]]),
('regression variant: chronological order 2',
[[['Q1', 780, 150], ['P2', 1020, 73], ['V3', 1220, 150], ['W0', 540, 180]], 15, 15],
[[['W0', 750], ['Q1', 955], ['P2', 1105], ['V3', 1395]], []]),
('partial repair guard 3',
[[['U2', 840, 44], ['W3', 1080, 150], ['V1', 660, 180], ['V0', 540, 91]], 33, 30],
[[['V0', 665], ['V1', 900], ['U2', 900], ['W3', 1280]], [['V0', 'V1'], ['V1', 'U2']]]),
('boundary control 4', [[['A', 540, 91]], 10, 30], [[['A', 645]], []]),
('boundary control 5', [[['A', 540, 100], ['B', 699, 60]], 25, 30], [[['A', 665], ['B', 774]], []]),
('normal control 6', [[['Q1', 660, 44], ['Q0', 540, 60]], 15, 30], [[['Q0', 610], ['Q1', 715]], []]),
('normal control 7', [[['R1', 740, 72], ['U2', 920, 100], ['T3', 1120, 90], ['W0', 540, 120]], 10, 30],
[[['W0', 675], ['R1', 820], ['U2', 1030], ['T3', 1220]], []]),
('normal control 8', [[['U1', 750, 88], ['R2', 900, 182], ['U0', 600, 90]], 10, 15],
[[['U0', 700], ['U1', 850], ['R2', 1105]], []])]]
for label, args, expected in fixtures[N-1]:
check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression: chronological order 1 | [[['B', 870], ['A', 645]], [['B', 'A']]] | [[['A', 645], ['B', 870]], []] | Failed |
| regression variant: chronological order 2 | [[['P1', 880], ['P0', 595], ['W2', 1025]], [['P1', 'P0']]] | [[['P0', 595], ['P1', 880], ['W2', 1025]], []] | Failed |
| partial repair guard 3 | [[['T1', 880], ['V0', 840]], [['T1', 'V0']]] | [[['V0', 840], ['T1', 880]], [['V0', 'T1']]] | Failed |
| boundary control 4 | [[['A', 720], ['B', 855]], []] | [[['A', 720], ['B', 855]], []] | Passed |
| boundary control 5 | [[['A', 625], ['B', 710]], []] | [[['A', 625], ['B', 710]], []] | Passed |
| normal control 6 | [[['R2', 1060], ['T3', 1260], ['V1', 945], ['W0', 685]], [['T3', 'V1'], ['V1', 'W0']]] | [[['W0', 685], ['V1', 945], ['R2', 1060], ['T3', 1260]], [['V1', 'R2']]] | Failed |
| normal control 7 | [[['W2', 1050], ['T0', 765], ['W1', 965], ['R3', 1280]], [['W2', 'T0'], ['T0', 'W1']]] | [[['T0', 765], ['W1', 965], ['W2', 1050], ['R3', 1280]], [['T0', 'W1'], ['W1', 'W2']]] | Failed |
| normal control 8 | [[['R3', 1155], ['U0', 725], ['V2', 1155], ['R1', 860]], [['R3', 'U0'], ['V2', 'R1']]] | [[['U0', 725], ['R1', 860], ['V2', 1155], ['R3', 1155]], [['U0', 'R1'], ['V2', 'R3']]] | Failed |
SHA-256 / 0d3e9ca12e78ab7c66d3699c47b5224a39b49ba9a9f8bbc9ced0fd91c439567a
2 / The unsuccessful fix
Exit 1"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(exams, pct, rest):
rows = []
for eid, st, dur in sorted(exams, key=lambda x: x[0]):
ext = -(-dur * (100 + pct) // 100)
ext = -(-ext // 5) * 5
rows.append([eid, st, st + ext])
conf = []
for a, b in zip(rows, rows[1:]):
if b[1] < a[2] + rest:
conf.append([a[0], b[0]])
return [[[r[0], r[2]] for r in rows], conf]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: chronological order 1', [[['B', 800, 60], ['A', 540, 90]], 15, 30],
[[['A', 645], ['B', 870]], []]),
('regression variant: chronological order 2',
[[['P1', 740, 120], ['P0', 540, 44], ['W2', 940, 72]], 15, 30],
[[['P0', 595], ['P1', 880], ['W2', 1025]], []]),
('partial repair guard 3', [[['T1', 720, 120], ['V0', 600, 180]], 33, 15],
[[['V0', 840], ['T1', 880]], [['V0', 'T1']]]),
('boundary control 4', [[['A', 540, 120], ['B', 720, 90]], 50, 0], [[['A', 720], ['B', 855]], []]),
('boundary control 5', [[['A', 540, 73], ['B', 640, 60]], 10, 15], [[['A', 625], ['B', 710]], []]),
('normal control 6', [[['R2', 960, 90], ['T3', 1160, 90], ['V1', 780, 150], ['W0', 600, 73]], 10, 30],
[[['W0', 685], ['V1', 945], ['R2', 1060], ['T3', 1260]], [['V1', 'R2']]]),
('normal control 7', [[['W2', 940, 88], ['T0', 540, 180], ['W1', 740, 180], ['R3', 1090, 150]], 25, 15],
[[['T0', 765], ['W1', 965], ['W2', 1050], ['R3', 1280]], [['T0', 'W1'], ['W1', 'W2']]]),
('normal control 8', [[['R3', 1080, 60], ['U0', 600, 100], ['V2', 930, 180], ['R1', 750, 88]], 25, 30],
[[['U0', 725], ['R1', 860], ['V2', 1155], ['R3', 1155]], [['U0', 'R1'], ['V2', 'R3']]])],
[('regression: chronological order 1',
[[['P1', 690, 150], ['S2', 890, 72], ['Q0', 600, 150], ['R3', 1010, 90]], 50, 15],
[[['Q0', 825], ['P1', 915], ['S2', 1000], ['R3', 1145]], [['Q0', 'P1'], ['P1', 'S2'], ['S2', 'R3']]]),
('regression variant: chronological order 2',
[[['P3', 1080, 180], ['U2', 930, 100], ['W1', 690, 72], ['T0', 540, 72]], 10, 15],
[[['T0', 620], ['W1', 770], ['U2', 1040], ['P3', 1280]], []]),
('partial repair guard 3', [[['V0', 600, 182], ['T1', 690, 73]], 10, 30],
[[['V0', 805], ['T1', 775]], [['V0', 'T1']]]),
('boundary control 4', [[['A', 540, 91]], 10, 30], [[['A', 645]], []]),
('boundary control 5', [[['A', 540, 100], ['B', 699, 60]], 25, 30], [[['A', 665], ['B', 774]], []]),
('normal control 6', [[['T0', 600, 72], ['P2', 1040, 100], ['T3', 1190, 182], ['Q1', 840, 100]], 10, 15],
[[['T0', 680], ['Q1', 950], ['P2', 1150], ['T3', 1395]], []]),
('normal control 7', [[['Q2', 840, 91], ['S0', 600, 88], ['R1', 750, 73]], 50, 30],
[[['S0', 735], ['R1', 860], ['Q2', 980]], [['S0', 'R1'], ['R1', 'Q2']]]),
('normal control 8', [[['S1', 630, 100], ['V3', 930, 88], ['V0', 540, 180], ['R2', 750, 73]], 50, 30],
[[['V0', 810], ['S1', 780], ['R2', 860], ['V3', 1065]], [['V0', 'S1'], ['S1', 'R2']]])],
[('regression: chronological order 1', [[['T1', 840, 72], ['R0', 600, 44]], 33, 30],
[[['R0', 660], ['T1', 940]], []]),
('regression variant: chronological order 2',
[[['U0', 540, 150], ['P2', 870, 60], ['Q1', 780, 88]], 10, 30],
[[['U0', 705], ['Q1', 880], ['P2', 940]], [['Q1', 'P2']]]),
('partial repair guard 3',
[[['S2', 810, 100], ['Q0', 600, 72], ['V1', 690, 100], ['R3', 990, 120]], 33, 15],
[[['Q0', 700], ['V1', 825], ['S2', 945], ['R3', 1150]], [['Q0', 'V1'], ['V1', 'S2']]]),
('boundary control 4', [[['A', 540, 88]], 25, 30], [[['A', 650]], []]),
('boundary control 5', [[['A', 540, 72]], 33, 15], [[['A', 640]], []]),
('normal control 6', [[['S0', 540, 90], ['U1', 740, 90]], 15, 30], [[['S0', 645], ['U1', 845]], []]),
('normal control 7', [[['Q2', 810, 120], ['S3', 1050, 73], ['V0', 540, 90], ['V1', 630, 73]], 25, 30],
[[['V0', 655], ['V1', 725], ['Q2', 960], ['S3', 1145]], [['V0', 'V1']]]),
('normal control 8', [[['V1', 630, 182], ['Q0', 540, 120]], 50, 30],
[[['Q0', 720], ['V1', 905]], [['Q0', 'V1']]])],
[('regression: chronological order 1',
[[['S2', 900, 73], ['P1', 780, 60], ['U3', 1050, 44], ['W0', 540, 72]], 50, 30],
[[['W0', 650], ['P1', 870], ['S2', 1010], ['U3', 1120]], []]),
('regression variant: chronological order 2', [[['P1', 780, 150], ['U0', 600, 90]], 50, 15],
[[['U0', 735], ['P1', 1005]], []]),
('partial repair guard 3',
[[['V0', 600, 90], ['R2', 990, 91], ['S1', 840, 120], ['Q3', 1110, 100]], 33, 30],
[[['V0', 720], ['S1', 1000], ['R2', 1115], ['Q3', 1245]], [['S1', 'R2'], ['R2', 'Q3']]]),
('boundary control 4', [[['A', 540, 120], ['B', 720, 90]], 50, 0], [[['A', 720], ['B', 855]], []]),
('boundary control 5', [[['A', 540, 73], ['B', 640, 60]], 10, 15], [[['A', 625], ['B', 710]], []]),
('normal control 6', [[['T1', 780, 180], ['P0', 540, 88]], 50, 30], [[['P0', 675], ['T1', 1050]], []]),
('normal control 7', [[['P3', 1110, 44], ['V1', 720, 72], ['S2', 870, 72], ['P0', 540, 91]], 15, 15],
[[['P0', 645], ['V1', 805], ['S2', 955], ['P3', 1165]], []]),
('normal control 8', [[['P0', 600, 150], ['R2', 840, 90], ['S1', 720, 90]], 50, 30],
[[['P0', 825], ['S1', 855], ['R2', 975]], [['P0', 'S1'], ['S1', 'R2']]])],
[('regression: chronological order 1',
[[['V2', 810, 180], ['U0', 540, 44], ['V3', 1010, 72], ['T1', 720, 100]], 33, 30],
[[['U0', 600], ['T1', 855], ['V2', 1050], ['V3', 1110]], [['T1', 'V2'], ['V2', 'V3']]]),
('regression variant: chronological order 2',
[[['Q1', 780, 150], ['P2', 1020, 73], ['V3', 1220, 150], ['W0', 540, 180]], 15, 15],
[[['W0', 750], ['Q1', 955], ['P2', 1105], ['V3', 1395]], []]),
('partial repair guard 3',
[[['U2', 840, 44], ['W3', 1080, 150], ['V1', 660, 180], ['V0', 540, 91]], 33, 30],
[[['V0', 665], ['V1', 900], ['U2', 900], ['W3', 1280]], [['V0', 'V1'], ['V1', 'U2']]]),
('boundary control 4', [[['A', 540, 91]], 10, 30], [[['A', 645]], []]),
('boundary control 5', [[['A', 540, 100], ['B', 699, 60]], 25, 30], [[['A', 665], ['B', 774]], []]),
('normal control 6', [[['Q1', 660, 44], ['Q0', 540, 60]], 15, 30], [[['Q0', 610], ['Q1', 715]], []]),
('normal control 7', [[['R1', 740, 72], ['U2', 920, 100], ['T3', 1120, 90], ['W0', 540, 120]], 10, 30],
[[['W0', 675], ['R1', 820], ['U2', 1030], ['T3', 1220]], []]),
('normal control 8', [[['U1', 750, 88], ['R2', 900, 182], ['U0', 600, 90]], 10, 15],
[[['U0', 700], ['U1', 850], ['R2', 1105]], []])]]
for label, args, expected in fixtures[N-1]:
check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression: chronological order 1 | [[['A', 645], ['B', 870]], []] | [[['A', 645], ['B', 870]], []] | Passed |
| regression variant: chronological order 2 | [[['P0', 595], ['P1', 880], ['W2', 1025]], []] | [[['P0', 595], ['P1', 880], ['W2', 1025]], []] | Passed |
| partial repair guard 3 | [[['T1', 880], ['V0', 840]], [['T1', 'V0']]] | [[['V0', 840], ['T1', 880]], [['V0', 'T1']]] | Failed |
| boundary control 4 | [[['A', 720], ['B', 855]], []] | [[['A', 720], ['B', 855]], []] | Passed |
| boundary control 5 | [[['A', 625], ['B', 710]], []] | [[['A', 625], ['B', 710]], []] | Passed |
| normal control 6 | [[['R2', 1060], ['T3', 1260], ['V1', 945], ['W0', 685]], [['T3', 'V1'], ['V1', 'W0']]] | [[['W0', 685], ['V1', 945], ['R2', 1060], ['T3', 1260]], [['V1', 'R2']]] | Failed |
| normal control 7 | [[['R3', 1280], ['T0', 765], ['W1', 965], ['W2', 1050]], [['R3', 'T0'], ['T0', 'W1'], ['W1', 'W2']]] | [[['T0', 765], ['W1', 965], ['W2', 1050], ['R3', 1280]], [['T0', 'W1'], ['W1', 'W2']]] | Failed |
| normal control 8 | [[['R1', 860], ['R3', 1155], ['U0', 725], ['V2', 1155]], [['R3', 'U0']]] | [[['U0', 725], ['R1', 860], ['V2', 1155], ['R3', 1155]], [['U0', 'R1'], ['V2', 'R3']]] | Failed |
SHA-256 / be3dda019d35a90ca4b5a3b8c0a4f7b9d44eaa2f5541b51170e53613d2fd9856
3 / The verified repair
Exit 0"""Failure Map reference implementation. Python standard library only."""
import json
N = 1
observations = []
def solve(exams, pct, rest):
rows = []
for eid, st, dur in sorted(exams, key=lambda x: (x[1], x[0])):
ext = -(-dur * (100 + pct) // 100)
ext = -(-ext // 5) * 5
rows.append([eid, st, st + ext])
conf = []
for a, b in zip(rows, rows[1:]):
if b[1] < a[2] + rest:
conf.append([a[0], b[0]])
return [[[r[0], r[2]] for r in rows], conf]
def check(label, actual, expected):
observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('regression: chronological order 1', [[['B', 800, 60], ['A', 540, 90]], 15, 30],
[[['A', 645], ['B', 870]], []]),
('regression variant: chronological order 2',
[[['P1', 740, 120], ['P0', 540, 44], ['W2', 940, 72]], 15, 30],
[[['P0', 595], ['P1', 880], ['W2', 1025]], []]),
('partial repair guard 3', [[['T1', 720, 120], ['V0', 600, 180]], 33, 15],
[[['V0', 840], ['T1', 880]], [['V0', 'T1']]]),
('boundary control 4', [[['A', 540, 120], ['B', 720, 90]], 50, 0], [[['A', 720], ['B', 855]], []]),
('boundary control 5', [[['A', 540, 73], ['B', 640, 60]], 10, 15], [[['A', 625], ['B', 710]], []]),
('normal control 6', [[['R2', 960, 90], ['T3', 1160, 90], ['V1', 780, 150], ['W0', 600, 73]], 10, 30],
[[['W0', 685], ['V1', 945], ['R2', 1060], ['T3', 1260]], [['V1', 'R2']]]),
('normal control 7', [[['W2', 940, 88], ['T0', 540, 180], ['W1', 740, 180], ['R3', 1090, 150]], 25, 15],
[[['T0', 765], ['W1', 965], ['W2', 1050], ['R3', 1280]], [['T0', 'W1'], ['W1', 'W2']]]),
('normal control 8', [[['R3', 1080, 60], ['U0', 600, 100], ['V2', 930, 180], ['R1', 750, 88]], 25, 30],
[[['U0', 725], ['R1', 860], ['V2', 1155], ['R3', 1155]], [['U0', 'R1'], ['V2', 'R3']]])],
[('regression: chronological order 1',
[[['P1', 690, 150], ['S2', 890, 72], ['Q0', 600, 150], ['R3', 1010, 90]], 50, 15],
[[['Q0', 825], ['P1', 915], ['S2', 1000], ['R3', 1145]], [['Q0', 'P1'], ['P1', 'S2'], ['S2', 'R3']]]),
('regression variant: chronological order 2',
[[['P3', 1080, 180], ['U2', 930, 100], ['W1', 690, 72], ['T0', 540, 72]], 10, 15],
[[['T0', 620], ['W1', 770], ['U2', 1040], ['P3', 1280]], []]),
('partial repair guard 3', [[['V0', 600, 182], ['T1', 690, 73]], 10, 30],
[[['V0', 805], ['T1', 775]], [['V0', 'T1']]]),
('boundary control 4', [[['A', 540, 91]], 10, 30], [[['A', 645]], []]),
('boundary control 5', [[['A', 540, 100], ['B', 699, 60]], 25, 30], [[['A', 665], ['B', 774]], []]),
('normal control 6', [[['T0', 600, 72], ['P2', 1040, 100], ['T3', 1190, 182], ['Q1', 840, 100]], 10, 15],
[[['T0', 680], ['Q1', 950], ['P2', 1150], ['T3', 1395]], []]),
('normal control 7', [[['Q2', 840, 91], ['S0', 600, 88], ['R1', 750, 73]], 50, 30],
[[['S0', 735], ['R1', 860], ['Q2', 980]], [['S0', 'R1'], ['R1', 'Q2']]]),
('normal control 8', [[['S1', 630, 100], ['V3', 930, 88], ['V0', 540, 180], ['R2', 750, 73]], 50, 30],
[[['V0', 810], ['S1', 780], ['R2', 860], ['V3', 1065]], [['V0', 'S1'], ['S1', 'R2']]])],
[('regression: chronological order 1', [[['T1', 840, 72], ['R0', 600, 44]], 33, 30],
[[['R0', 660], ['T1', 940]], []]),
('regression variant: chronological order 2',
[[['U0', 540, 150], ['P2', 870, 60], ['Q1', 780, 88]], 10, 30],
[[['U0', 705], ['Q1', 880], ['P2', 940]], [['Q1', 'P2']]]),
('partial repair guard 3',
[[['S2', 810, 100], ['Q0', 600, 72], ['V1', 690, 100], ['R3', 990, 120]], 33, 15],
[[['Q0', 700], ['V1', 825], ['S2', 945], ['R3', 1150]], [['Q0', 'V1'], ['V1', 'S2']]]),
('boundary control 4', [[['A', 540, 88]], 25, 30], [[['A', 650]], []]),
('boundary control 5', [[['A', 540, 72]], 33, 15], [[['A', 640]], []]),
('normal control 6', [[['S0', 540, 90], ['U1', 740, 90]], 15, 30], [[['S0', 645], ['U1', 845]], []]),
('normal control 7', [[['Q2', 810, 120], ['S3', 1050, 73], ['V0', 540, 90], ['V1', 630, 73]], 25, 30],
[[['V0', 655], ['V1', 725], ['Q2', 960], ['S3', 1145]], [['V0', 'V1']]]),
('normal control 8', [[['V1', 630, 182], ['Q0', 540, 120]], 50, 30],
[[['Q0', 720], ['V1', 905]], [['Q0', 'V1']]])],
[('regression: chronological order 1',
[[['S2', 900, 73], ['P1', 780, 60], ['U3', 1050, 44], ['W0', 540, 72]], 50, 30],
[[['W0', 650], ['P1', 870], ['S2', 1010], ['U3', 1120]], []]),
('regression variant: chronological order 2', [[['P1', 780, 150], ['U0', 600, 90]], 50, 15],
[[['U0', 735], ['P1', 1005]], []]),
('partial repair guard 3',
[[['V0', 600, 90], ['R2', 990, 91], ['S1', 840, 120], ['Q3', 1110, 100]], 33, 30],
[[['V0', 720], ['S1', 1000], ['R2', 1115], ['Q3', 1245]], [['S1', 'R2'], ['R2', 'Q3']]]),
('boundary control 4', [[['A', 540, 120], ['B', 720, 90]], 50, 0], [[['A', 720], ['B', 855]], []]),
('boundary control 5', [[['A', 540, 73], ['B', 640, 60]], 10, 15], [[['A', 625], ['B', 710]], []]),
('normal control 6', [[['T1', 780, 180], ['P0', 540, 88]], 50, 30], [[['P0', 675], ['T1', 1050]], []]),
('normal control 7', [[['P3', 1110, 44], ['V1', 720, 72], ['S2', 870, 72], ['P0', 540, 91]], 15, 15],
[[['P0', 645], ['V1', 805], ['S2', 955], ['P3', 1165]], []]),
('normal control 8', [[['P0', 600, 150], ['R2', 840, 90], ['S1', 720, 90]], 50, 30],
[[['P0', 825], ['S1', 855], ['R2', 975]], [['P0', 'S1'], ['S1', 'R2']]])],
[('regression: chronological order 1',
[[['V2', 810, 180], ['U0', 540, 44], ['V3', 1010, 72], ['T1', 720, 100]], 33, 30],
[[['U0', 600], ['T1', 855], ['V2', 1050], ['V3', 1110]], [['T1', 'V2'], ['V2', 'V3']]]),
('regression variant: chronological order 2',
[[['Q1', 780, 150], ['P2', 1020, 73], ['V3', 1220, 150], ['W0', 540, 180]], 15, 15],
[[['W0', 750], ['Q1', 955], ['P2', 1105], ['V3', 1395]], []]),
('partial repair guard 3',
[[['U2', 840, 44], ['W3', 1080, 150], ['V1', 660, 180], ['V0', 540, 91]], 33, 30],
[[['V0', 665], ['V1', 900], ['U2', 900], ['W3', 1280]], [['V0', 'V1'], ['V1', 'U2']]]),
('boundary control 4', [[['A', 540, 91]], 10, 30], [[['A', 645]], []]),
('boundary control 5', [[['A', 540, 100], ['B', 699, 60]], 25, 30], [[['A', 665], ['B', 774]], []]),
('normal control 6', [[['Q1', 660, 44], ['Q0', 540, 60]], 15, 30], [[['Q0', 610], ['Q1', 715]], []]),
('normal control 7', [[['R1', 740, 72], ['U2', 920, 100], ['T3', 1120, 90], ['W0', 540, 120]], 10, 30],
[[['W0', 675], ['R1', 820], ['U2', 1030], ['T3', 1220]], []]),
('normal control 8', [[['U1', 750, 88], ['R2', 900, 182], ['U0', 600, 90]], 10, 15],
[[['U0', 700], ['U1', 850], ['R2', 1105]], []])]]
for label, args, expected in fixtures[N-1]:
check(label, solve(*args), expected)
print(json.dumps({"observations": observations, "passed": all(x["passed"] for x in observations)}, ensure_ascii=False))
raise SystemExit(0 if all(x["passed"] for x in observations) else 1)
| Boundary fixture | Actual | Expected | Outcome |
|---|---|---|---|
| regression: chronological order 1 | [[['A', 645], ['B', 870]], []] | [[['A', 645], ['B', 870]], []] | Passed |
| regression variant: chronological order 2 | [[['P0', 595], ['P1', 880], ['W2', 1025]], []] | [[['P0', 595], ['P1', 880], ['W2', 1025]], []] | Passed |
| partial repair guard 3 | [[['V0', 840], ['T1', 880]], [['V0', 'T1']]] | [[['V0', 840], ['T1', 880]], [['V0', 'T1']]] | Passed |
| boundary control 4 | [[['A', 720], ['B', 855]], []] | [[['A', 720], ['B', 855]], []] | Passed |
| boundary control 5 | [[['A', 625], ['B', 710]], []] | [[['A', 625], ['B', 710]], []] | Passed |
| normal control 6 | [[['W0', 685], ['V1', 945], ['R2', 1060], ['T3', 1260]], [['V1', 'R2']]] | [[['W0', 685], ['V1', 945], ['R2', 1060], ['T3', 1260]], [['V1', 'R2']]] | Passed |
| normal control 7 | [[['T0', 765], ['W1', 965], ['W2', 1050], ['R3', 1280]], [['T0', 'W1'], ['W1', 'W2']]] | [[['T0', 765], ['W1', 965], ['W2', 1050], ['R3', 1280]], [['T0', 'W1'], ['W1', 'W2']]] | Passed |
| normal control 8 | [[['U0', 725], ['R1', 860], ['V2', 1155], ['R3', 1155]], [['U0', 'R1'], ['V2', 'R3']]] | [[['U0', 725], ['R1', 860], ['V2', 1155], ['R3', 1155]], [['U0', 'R1'], ['V2', 'R3']]] | Passed |
SHA-256 / 16eb22da13a914ae6069d8b159d766500623831fb5f311b793ae25f2a467c12d
Verification & scope
Stipulated toy exam-timetabling rule set for a bounded model; it does not claim conformance with any institution's regulations or a benchmark specification, and it performs no search or optimisation. This reproducer isolates one failure mechanism. Results cover the supplied fixtures. Variants within a family share a test contract and should remain grouped when constructing evaluation splits. Related mechanisms with a shared evaluation_group must also remain together; these controlled models are not independent production incidents.
Observations recorded using Python 3.12.14 at 2026-09-29T14:52:04.586485+00:00.
Case digest / cf130013be213b0df6077963331cb87b2dd01cf24e829ed625885d3e576561bb