broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(settings, samples):
    pos = 0
    out = []
    for co2, occupied in samples:
        if co2 <= settings['co2_low']:
            target = settings['min_pos']
        elif co2 >= settings['co2_high']:
            target = settings['max_pos']
        else:
            span = settings['co2_high'] - settings['co2_low']
            num = (co2 - settings['co2_low']) * (settings['max_pos'] - settings['min_pos'])
            target = settings['min_pos'] + (2 * num + span) // (2 * span)
        if target > pos:
            pos = min(target, pos + 10)
        else:
            pos = max(target, pos - 10)
        out.append(pos)
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: occupied day',
   [{'min_pos': 20, 'max_pos': 80, 'co2_low': 700, 'co2_high': 1100},
    [[650, True],
     [650, True],
     [900, True],
     [900, True],
     [900, True],
     [900, True],
     [1300, True],
     [1300, False]]],
   [10, 20, 30, 40, 50, 50, 60, 50]],
  ['regression: unoccupied high co2',
   [{'min_pos': 20, 'max_pos': 80, 'co2_low': 700, 'co2_high': 1100},
    [[1200, False], [1200, False], [1200, True]]],
   [0, 0, 10]],
  ['regression: crowd arrives',
   [{'min_pos': 20, 'max_pos': 80, 'co2_low': 700, 'co2_high': 1100},
    [[1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, False],
     [1500, False]]],
   [10, 20, 30, 40, 50, 60, 70, 80, 80, 70, 60]],
  ['control: moderate co2',
   [{'min_pos': 20, 'max_pos': 80, 'co2_low': 700, 'co2_high': 1100},
    [[800, True], [800, True], [800, True], [800, True], [800, True], [750, True], [750, True]]],
   [10, 20, 30, 35, 35, 28, 28]],
  ['control: scenario 1',
   [{'min_pos': 20, 'max_pos': 100, 'co2_low': 600, 'co2_high': 1000},
    [[424, True], [551, True], [655, True], [713, True], [740, True], [769, True], [840, True], [858, True]]],
   [10, 20, 30, 40, 48, 54, 64, 72]],
  ['regression: scenario 2',
   [{'min_pos': 10, 'max_pos': 60, 'co2_low': 700, 'co2_high': 1000},
    [[1150, True],
     [1009, True],
     [1044, True],
     [985, False],
     [1131, False],
     [982, True],
     [895, True],
     [828, False]]],
   [10, 20, 30, 20, 10, 20, 30, 20]],
  ['regression: scenario 3',
   [{'min_pos': 15, 'max_pos': 80, 'co2_low': 600, 'co2_high': 1000},
    [[1300, False],
     [1254, True],
     [1354, True],
     [1400, False],
     [1471, True],
     [1498, True],
     [1500, False],
     [1488, True],
     [1500, False],
     [1500, True],
     [1500, False],
     [1464, True]]],
   [0, 10, 20, 10, 20, 30, 20, 30, 20, 30, 20, 30]],
  ['regression: scenario 4',
   [{'min_pos': 10, 'max_pos': 100, 'co2_low': 700, 'co2_high': 1000},
    [[802, True],
     [856, True],
     [954, True],
     [853, True],
     [816, True],
     [847, False],
     [865, True],
     [741, True],
     [680, True],
     [592, True],
     [485, True]]],
   [10, 20, 30, 40, 45, 35, 45, 35, 25, 15, 10]]],
 [['regression: crowd arrives',
   [{'min_pos': 20, 'max_pos': 80, 'co2_low': 700, 'co2_high': 1100},
    [[1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, False],
     [1500, False]]],
   [10, 20, 30, 40, 50, 60, 70, 80, 80, 70, 60]],
  ['regression: scenario 1',
   [{'min_pos': 20, 'max_pos': 100, 'co2_low': 600, 'co2_high': 1200},
    [[631, True],
     [545, True],
     [465, True],
     [503, True],
     [568, True],
     [550, True],
     [450, False],
     [459, True],
     [434, True],
     [539, True],
     [480, True],
     [462, False],
     [400, True],
     [400, True]]],
   [10, 20, 20, 20, 20, 20, 10, 20, 20, 20, 20, 10, 20, 20]],
  ['regression: occupied day',
   [{'min_pos': 20, 'max_pos': 80, 'co2_low': 700, 'co2_high': 1100},
    [[650, True],
     [650, True],
     [900, True],
     [900, True],
     [900, True],
     [900, True],
     [1300, True],
     [1300, False]]],
   [10, 20, 30, 40, 50, 50, 60, 50]],
  ['control: moderate co2',
   [{'min_pos': 20, 'max_pos': 80, 'co2_low': 700, 'co2_high': 1100},
    [[800, True], [800, True], [800, True], [800, True], [800, True], [750, True], [750, True]]],
   [10, 20, 30, 35, 35, 28, 28]],
  ['regression: unoccupied high co2',
   [{'min_pos': 20, 'max_pos': 80, 'co2_low': 700, 'co2_high': 1100},
    [[1200, False], [1200, False], [1200, True]]],
   [0, 0, 10]],
  ['control: scenario 2',
   [{'min_pos': 15, 'max_pos': 80, 'co2_low': 700, 'co2_high': 1000},
    [[775, True],
     [743, True],
     [851, True],
     [853, True],
     [893, True],
     [872, True],
     [870, True],
     [781, False],
     [813, True],
     [851, True],
     [955, True]]],
   [10, 20, 30, 40, 50, 52, 52, 42, 39, 48, 58]],
  ['regression: scenario 3',
   [{'min_pos': 10, 'max_pos': 100, 'co2_low': 700, 'co2_high': 1200},
    [[1109, True],
     [1033, False],
     [1170, False],
     [1235, True],
     [1208, True],
     [1230, True],
     [1178, True],
     [1182, True],
     [1206, False],
     [1261, True],
     [1328, True],
     [1474, True]]],
   [10, 0, 0, 10, 20, 30, 40, 50, 40, 50, 60, 70]],
  ['regression: scenario 4',
   [{'min_pos': 20, 'max_pos': 80, 'co2_low': 600, 'co2_high': 1200},
    [[1028, True],
     [998, True],
     [1129, True],
     [1164, True],
     [1200, True],
     [1276, False],
     [1335, True],
     [1192, True],
     [1105, True],
     [1194, True],
     [1207, True]]],
   [10, 20, 30, 40, 50, 40, 50, 60, 70, 79, 80]]],
 [['regression: unoccupied high co2',
   [{'min_pos': 20, 'max_pos': 80, 'co2_low': 700, 'co2_high': 1100},
    [[1200, False], [1200, False], [1200, True]]],
   [0, 0, 10]],
  ['regression: scenario 4',
   [{'min_pos': 10, 'max_pos': 60, 'co2_low': 600, 'co2_high': 1000},
    [[675, True],
     [548, False],
     [502, True],
     [455, False],
     [400, True],
     [462, True],
     [400, True],
     [400, True],
     [400, True],
     [402, False],
     [447, True]]],
   [10, 0, 10, 0, 10, 10, 10, 10, 10, 0, 10]],
  ['regression: occupied day',
   [{'min_pos': 20, 'max_pos': 80, 'co2_low': 700, 'co2_high': 1100},
    [[650, True],
     [650, True],
     [900, True],
     [900, True],
     [900, True],
     [900, True],
     [1300, True],
     [1300, False]]],
   [10, 20, 30, 40, 50, 50, 60, 50]],
  ['regression: crowd arrives',
   [{'min_pos': 20, 'max_pos': 80, 'co2_low': 700, 'co2_high': 1100},
    [[1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, False],
     [1500, False]]],
   [10, 20, 30, 40, 50, 60, 70, 80, 80, 70, 60]],
  ['control: moderate co2',
   [{'min_pos': 20, 'max_pos': 80, 'co2_low': 700, 'co2_high': 1100},
    [[800, True], [800, True], [800, True], [800, True], [800, True], [750, True], [750, True]]],
   [10, 20, 30, 35, 35, 28, 28]],
  ['regression: scenario 1',
   [{'min_pos': 10, 'max_pos': 60, 'co2_low': 700, 'co2_high': 1000},
    [[523, True],
     [506, True],
     [620, False],
     [668, True],
     [557, True],
     [453, True],
     [400, True],
     [400, True],
     [409, True],
     [455, False],
     [443, False],
     [561, True]]],
   [10, 10, 0, 10, 10, 10, 10, 10, 10, 0, 0, 10]],
  ['regression: scenario 2',
   [{'min_pos': 20, 'max_pos': 60, 'co2_low': 600, 'co2_high': 1000},
    [[640, True],
     [668, False],
     [658, True],
     [602, False],
     [640, False],
     [525, False],
     [604, True],
     [456, True],
     [591, True],
     [611, True]]],
   [10, 0, 10, 0, 0, 0, 10, 20, 20, 21]],
  ['regression: scenario 3',
   [{'min_pos': 20, 'max_pos': 60, 'co2_low': 700, 'co2_high': 1000},
    [[1018, True],
     [1052, True],
     [988, True],
     [1071, True],
     [1109, True],
     [1124, True],
     [1196, True],
     [1221, False],
     [1203, True]]],
   [10, 20, 30, 40, 50, 60, 60, 50, 60]]],
 [['regression: scenario 1',
   [{'min_pos': 15, 'max_pos': 60, 'co2_low': 700, 'co2_high': 1200},
    [[1121, True],
     [1144, True],
     [1172, True],
     [1223, True],
     [1138, True],
     [1273, True],
     [1319, True],
     [1227, False],
     [1253, True]]],
   [10, 20, 30, 40, 50, 60, 60, 50, 60]],
  ['regression: scenario 8',
   [{'min_pos': 20, 'max_pos': 100, 'co2_low': 700, 'co2_high': 1200},
    [[1134, False],
     [1275, True],
     [1185, True],
     [1223, True],
     [1341, True],
     [1446, True],
     [1500, True],
     [1466, True],
     [1500, False]]],
   [0, 10, 20, 30, 40, 50, 60, 70, 60]],
  ['regression: occupied day',
   [{'min_pos': 20, 'max_pos': 80, 'co2_low': 700, 'co2_high': 1100},
    [[650, True],
     [650, True],
     [900, True],
     [900, True],
     [900, True],
     [900, True],
     [1300, True],
     [1300, False]]],
   [10, 20, 30, 40, 50, 50, 60, 50]],
  ['regression: crowd arrives',
   [{'min_pos': 20, 'max_pos': 80, 'co2_low': 700, 'co2_high': 1100},
    [[1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, False],
     [1500, False]]],
   [10, 20, 30, 40, 50, 60, 70, 80, 80, 70, 60]],
  ['control: moderate co2',
   [{'min_pos': 20, 'max_pos': 80, 'co2_low': 700, 'co2_high': 1100},
    [[800, True], [800, True], [800, True], [800, True], [800, True], [750, True], [750, True]]],
   [10, 20, 30, 35, 35, 28, 28]],
  ['regression: unoccupied high co2',
   [{'min_pos': 20, 'max_pos': 80, 'co2_low': 700, 'co2_high': 1100},
    [[1200, False], [1200, False], [1200, True]]],
   [0, 0, 10]],
  ['regression: scenario 2',
   [{'min_pos': 20, 'max_pos': 60, 'co2_low': 600, 'co2_high': 1200},
    [[570, True],
     [539, True],
     [432, True],
     [498, True],
     [536, True],
     [559, True],
     [607, True],
     [706, False],
     [703, False],
     [767, True],
     [618, False],
     [742, False],
     [796, True]]],
   [10, 20, 20, 20, 20, 20, 20, 10, 0, 10, 0, 0, 10]],
  ['regression: scenario 3',
   [{'min_pos': 20, 'max_pos': 60, 'co2_low': 600, 'co2_high': 1000},
    [[853, True],
     [828, True],
     [845, True],
     [890, False],
     [973, True],
     [895, True],
     [751, True],
     [855, True],
     [839, False],
     [909, True],
     [1031, True],
     [926, True],
     [1032, True]]],
   [10, 20, 30, 20, 30, 40, 35, 45, 35, 45, 55, 53, 60]]],
 [['regression: scenario 2',
   [{'min_pos': 15, 'max_pos': 100, 'co2_low': 700, 'co2_high': 1000},
    [[788, True],
     [835, True],
     [980, True],
     [906, False],
     [1052, True],
     [960, False],
     [1028, True],
     [1053, False],
     [1100, True],
     [1140, False]]],
   [10, 20, 30, 20, 30, 20, 30, 20, 30, 20]],
  ['regression: scenario 9',
   [{'min_pos': 15, 'max_pos': 80, 'co2_low': 600, 'co2_high': 1000},
    [[1157, False],
     [1218, True],
     [1323, True],
     [1229, False],
     [1145, True],
     [1200, True],
     [1197, False],
     [1302, True]]],
   [0, 10, 20, 10, 20, 30, 20, 30]],
  ['regression: occupied day',
   [{'min_pos': 20, 'max_pos': 80, 'co2_low': 700, 'co2_high': 1100},
    [[650, True],
     [650, True],
     [900, True],
     [900, True],
     [900, True],
     [900, True],
     [1300, True],
     [1300, False]]],
   [10, 20, 30, 40, 50, 50, 60, 50]],
  ['regression: crowd arrives',
   [{'min_pos': 20, 'max_pos': 80, 'co2_low': 700, 'co2_high': 1100},
    [[1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, False],
     [1500, False]]],
   [10, 20, 30, 40, 50, 60, 70, 80, 80, 70, 60]],
  ['control: moderate co2',
   [{'min_pos': 20, 'max_pos': 80, 'co2_low': 700, 'co2_high': 1100},
    [[800, True], [800, True], [800, True], [800, True], [800, True], [750, True], [750, True]]],
   [10, 20, 30, 35, 35, 28, 28]],
  ['regression: unoccupied high co2',
   [{'min_pos': 20, 'max_pos': 80, 'co2_low': 700, 'co2_high': 1100},
    [[1200, False], [1200, False], [1200, True]]],
   [0, 0, 10]],
  ['regression: scenario 1',
   [{'min_pos': 15, 'max_pos': 80, 'co2_low': 700, 'co2_high': 1200},
    [[1383, True],
     [1500, True],
     [1500, True],
     [1483, True],
     [1492, True],
     [1500, False],
     [1500, True],
     [1500, True],
     [1500, False],
     [1465, True],
     [1443, False],
     [1458, False],
     [1430, True]]],
   [10, 20, 30, 40, 50, 40, 50, 60, 50, 60, 50, 40, 50]],
  ['regression: scenario 3',
   [{'min_pos': 20, 'max_pos': 100, 'co2_low': 600, 'co2_high': 1200},
    [[1068, True],
     [969, True],
     [993, True],
     [1093, True],
     [1019, True],
     [1021, True],
     [1037, False],
     [990, True],
     [876, False],
     [997, True],
     [984, True],
     [903, False],
     [822, False]]],
   [10, 20, 30, 40, 50, 60, 50, 60, 50, 60, 70, 60, 50]]]]
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)

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(settings, samples):
    pos = 0
    out = []
    for co2, occupied in samples:
        if not occupied:
            target = settings['min_pos']
        elif co2 <= settings['co2_low']:
            target = settings['min_pos']
        elif co2 >= settings['co2_high']:
            target = settings['max_pos']
        else:
            span = settings['co2_high'] - settings['co2_low']
            num = (co2 - settings['co2_low']) * (settings['max_pos'] - settings['min_pos'])
            target = settings['min_pos'] + (2 * num + span) // (2 * span)
        if target > pos:
            pos = min(target, pos + 10)
        else:
            pos = max(target, pos - 10)
        out.append(pos)
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: occupied day',
   [{'min_pos': 20, 'max_pos': 80, 'co2_low': 700, 'co2_high': 1100},
    [[650, True],
     [650, True],
     [900, True],
     [900, True],
     [900, True],
     [900, True],
     [1300, True],
     [1300, False]]],
   [10, 20, 30, 40, 50, 50, 60, 50]],
  ['regression: unoccupied high co2',
   [{'min_pos': 20, 'max_pos': 80, 'co2_low': 700, 'co2_high': 1100},
    [[1200, False], [1200, False], [1200, True]]],
   [0, 0, 10]],
  ['regression: crowd arrives',
   [{'min_pos': 20, 'max_pos': 80, 'co2_low': 700, 'co2_high': 1100},
    [[1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, False],
     [1500, False]]],
   [10, 20, 30, 40, 50, 60, 70, 80, 80, 70, 60]],
  ['control: moderate co2',
   [{'min_pos': 20, 'max_pos': 80, 'co2_low': 700, 'co2_high': 1100},
    [[800, True], [800, True], [800, True], [800, True], [800, True], [750, True], [750, True]]],
   [10, 20, 30, 35, 35, 28, 28]],
  ['control: scenario 1',
   [{'min_pos': 20, 'max_pos': 100, 'co2_low': 600, 'co2_high': 1000},
    [[424, True], [551, True], [655, True], [713, True], [740, True], [769, True], [840, True], [858, True]]],
   [10, 20, 30, 40, 48, 54, 64, 72]],
  ['regression: scenario 2',
   [{'min_pos': 10, 'max_pos': 60, 'co2_low': 700, 'co2_high': 1000},
    [[1150, True],
     [1009, True],
     [1044, True],
     [985, False],
     [1131, False],
     [982, True],
     [895, True],
     [828, False]]],
   [10, 20, 30, 20, 10, 20, 30, 20]],
  ['regression: scenario 3',
   [{'min_pos': 15, 'max_pos': 80, 'co2_low': 600, 'co2_high': 1000},
    [[1300, False],
     [1254, True],
     [1354, True],
     [1400, False],
     [1471, True],
     [1498, True],
     [1500, False],
     [1488, True],
     [1500, False],
     [1500, True],
     [1500, False],
     [1464, True]]],
   [0, 10, 20, 10, 20, 30, 20, 30, 20, 30, 20, 30]],
  ['regression: scenario 4',
   [{'min_pos': 10, 'max_pos': 100, 'co2_low': 700, 'co2_high': 1000},
    [[802, True],
     [856, True],
     [954, True],
     [853, True],
     [816, True],
     [847, False],
     [865, True],
     [741, True],
     [680, True],
     [592, True],
     [485, True]]],
   [10, 20, 30, 40, 45, 35, 45, 35, 25, 15, 10]]],
 [['regression: crowd arrives',
   [{'min_pos': 20, 'max_pos': 80, 'co2_low': 700, 'co2_high': 1100},
    [[1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, False],
     [1500, False]]],
   [10, 20, 30, 40, 50, 60, 70, 80, 80, 70, 60]],
  ['regression: scenario 1',
   [{'min_pos': 20, 'max_pos': 100, 'co2_low': 600, 'co2_high': 1200},
    [[631, True],
     [545, True],
     [465, True],
     [503, True],
     [568, True],
     [550, True],
     [450, False],
     [459, True],
     [434, True],
     [539, True],
     [480, True],
     [462, False],
     [400, True],
     [400, True]]],
   [10, 20, 20, 20, 20, 20, 10, 20, 20, 20, 20, 10, 20, 20]],
  ['regression: occupied day',
   [{'min_pos': 20, 'max_pos': 80, 'co2_low': 700, 'co2_high': 1100},
    [[650, True],
     [650, True],
     [900, True],
     [900, True],
     [900, True],
     [900, True],
     [1300, True],
     [1300, False]]],
   [10, 20, 30, 40, 50, 50, 60, 50]],
  ['control: moderate co2',
   [{'min_pos': 20, 'max_pos': 80, 'co2_low': 700, 'co2_high': 1100},
    [[800, True], [800, True], [800, True], [800, True], [800, True], [750, True], [750, True]]],
   [10, 20, 30, 35, 35, 28, 28]],
  ['regression: unoccupied high co2',
   [{'min_pos': 20, 'max_pos': 80, 'co2_low': 700, 'co2_high': 1100},
    [[1200, False], [1200, False], [1200, True]]],
   [0, 0, 10]],
  ['control: scenario 2',
   [{'min_pos': 15, 'max_pos': 80, 'co2_low': 700, 'co2_high': 1000},
    [[775, True],
     [743, True],
     [851, True],
     [853, True],
     [893, True],
     [872, True],
     [870, True],
     [781, False],
     [813, True],
     [851, True],
     [955, True]]],
   [10, 20, 30, 40, 50, 52, 52, 42, 39, 48, 58]],
  ['regression: scenario 3',
   [{'min_pos': 10, 'max_pos': 100, 'co2_low': 700, 'co2_high': 1200},
    [[1109, True],
     [1033, False],
     [1170, False],
     [1235, True],
     [1208, True],
     [1230, True],
     [1178, True],
     [1182, True],
     [1206, False],
     [1261, True],
     [1328, True],
     [1474, True]]],
   [10, 0, 0, 10, 20, 30, 40, 50, 40, 50, 60, 70]],
  ['regression: scenario 4',
   [{'min_pos': 20, 'max_pos': 80, 'co2_low': 600, 'co2_high': 1200},
    [[1028, True],
     [998, True],
     [1129, True],
     [1164, True],
     [1200, True],
     [1276, False],
     [1335, True],
     [1192, True],
     [1105, True],
     [1194, True],
     [1207, True]]],
   [10, 20, 30, 40, 50, 40, 50, 60, 70, 79, 80]]],
 [['regression: unoccupied high co2',
   [{'min_pos': 20, 'max_pos': 80, 'co2_low': 700, 'co2_high': 1100},
    [[1200, False], [1200, False], [1200, True]]],
   [0, 0, 10]],
  ['regression: scenario 4',
   [{'min_pos': 10, 'max_pos': 60, 'co2_low': 600, 'co2_high': 1000},
    [[675, True],
     [548, False],
     [502, True],
     [455, False],
     [400, True],
     [462, True],
     [400, True],
     [400, True],
     [400, True],
     [402, False],
     [447, True]]],
   [10, 0, 10, 0, 10, 10, 10, 10, 10, 0, 10]],
  ['regression: occupied day',
   [{'min_pos': 20, 'max_pos': 80, 'co2_low': 700, 'co2_high': 1100},
    [[650, True],
     [650, True],
     [900, True],
     [900, True],
     [900, True],
     [900, True],
     [1300, True],
     [1300, False]]],
   [10, 20, 30, 40, 50, 50, 60, 50]],
  ['regression: crowd arrives',
   [{'min_pos': 20, 'max_pos': 80, 'co2_low': 700, 'co2_high': 1100},
    [[1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, False],
     [1500, False]]],
   [10, 20, 30, 40, 50, 60, 70, 80, 80, 70, 60]],
  ['control: moderate co2',
   [{'min_pos': 20, 'max_pos': 80, 'co2_low': 700, 'co2_high': 1100},
    [[800, True], [800, True], [800, True], [800, True], [800, True], [750, True], [750, True]]],
   [10, 20, 30, 35, 35, 28, 28]],
  ['regression: scenario 1',
   [{'min_pos': 10, 'max_pos': 60, 'co2_low': 700, 'co2_high': 1000},
    [[523, True],
     [506, True],
     [620, False],
     [668, True],
     [557, True],
     [453, True],
     [400, True],
     [400, True],
     [409, True],
     [455, False],
     [443, False],
     [561, True]]],
   [10, 10, 0, 10, 10, 10, 10, 10, 10, 0, 0, 10]],
  ['regression: scenario 2',
   [{'min_pos': 20, 'max_pos': 60, 'co2_low': 600, 'co2_high': 1000},
    [[640, True],
     [668, False],
     [658, True],
     [602, False],
     [640, False],
     [525, False],
     [604, True],
     [456, True],
     [591, True],
     [611, True]]],
   [10, 0, 10, 0, 0, 0, 10, 20, 20, 21]],
  ['regression: scenario 3',
   [{'min_pos': 20, 'max_pos': 60, 'co2_low': 700, 'co2_high': 1000},
    [[1018, True],
     [1052, True],
     [988, True],
     [1071, True],
     [1109, True],
     [1124, True],
     [1196, True],
     [1221, False],
     [1203, True]]],
   [10, 20, 30, 40, 50, 60, 60, 50, 60]]],
 [['regression: scenario 1',
   [{'min_pos': 15, 'max_pos': 60, 'co2_low': 700, 'co2_high': 1200},
    [[1121, True],
     [1144, True],
     [1172, True],
     [1223, True],
     [1138, True],
     [1273, True],
     [1319, True],
     [1227, False],
     [1253, True]]],
   [10, 20, 30, 40, 50, 60, 60, 50, 60]],
  ['regression: scenario 8',
   [{'min_pos': 20, 'max_pos': 100, 'co2_low': 700, 'co2_high': 1200},
    [[1134, False],
     [1275, True],
     [1185, True],
     [1223, True],
     [1341, True],
     [1446, True],
     [1500, True],
     [1466, True],
     [1500, False]]],
   [0, 10, 20, 30, 40, 50, 60, 70, 60]],
  ['regression: occupied day',
   [{'min_pos': 20, 'max_pos': 80, 'co2_low': 700, 'co2_high': 1100},
    [[650, True],
     [650, True],
     [900, True],
     [900, True],
     [900, True],
     [900, True],
     [1300, True],
     [1300, False]]],
   [10, 20, 30, 40, 50, 50, 60, 50]],
  ['regression: crowd arrives',
   [{'min_pos': 20, 'max_pos': 80, 'co2_low': 700, 'co2_high': 1100},
    [[1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, False],
     [1500, False]]],
   [10, 20, 30, 40, 50, 60, 70, 80, 80, 70, 60]],
  ['control: moderate co2',
   [{'min_pos': 20, 'max_pos': 80, 'co2_low': 700, 'co2_high': 1100},
    [[800, True], [800, True], [800, True], [800, True], [800, True], [750, True], [750, True]]],
   [10, 20, 30, 35, 35, 28, 28]],
  ['regression: unoccupied high co2',
   [{'min_pos': 20, 'max_pos': 80, 'co2_low': 700, 'co2_high': 1100},
    [[1200, False], [1200, False], [1200, True]]],
   [0, 0, 10]],
  ['regression: scenario 2',
   [{'min_pos': 20, 'max_pos': 60, 'co2_low': 600, 'co2_high': 1200},
    [[570, True],
     [539, True],
     [432, True],
     [498, True],
     [536, True],
     [559, True],
     [607, True],
     [706, False],
     [703, False],
     [767, True],
     [618, False],
     [742, False],
     [796, True]]],
   [10, 20, 20, 20, 20, 20, 20, 10, 0, 10, 0, 0, 10]],
  ['regression: scenario 3',
   [{'min_pos': 20, 'max_pos': 60, 'co2_low': 600, 'co2_high': 1000},
    [[853, True],
     [828, True],
     [845, True],
     [890, False],
     [973, True],
     [895, True],
     [751, True],
     [855, True],
     [839, False],
     [909, True],
     [1031, True],
     [926, True],
     [1032, True]]],
   [10, 20, 30, 20, 30, 40, 35, 45, 35, 45, 55, 53, 60]]],
 [['regression: scenario 2',
   [{'min_pos': 15, 'max_pos': 100, 'co2_low': 700, 'co2_high': 1000},
    [[788, True],
     [835, True],
     [980, True],
     [906, False],
     [1052, True],
     [960, False],
     [1028, True],
     [1053, False],
     [1100, True],
     [1140, False]]],
   [10, 20, 30, 20, 30, 20, 30, 20, 30, 20]],
  ['regression: scenario 9',
   [{'min_pos': 15, 'max_pos': 80, 'co2_low': 600, 'co2_high': 1000},
    [[1157, False],
     [1218, True],
     [1323, True],
     [1229, False],
     [1145, True],
     [1200, True],
     [1197, False],
     [1302, True]]],
   [0, 10, 20, 10, 20, 30, 20, 30]],
  ['regression: occupied day',
   [{'min_pos': 20, 'max_pos': 80, 'co2_low': 700, 'co2_high': 1100},
    [[650, True],
     [650, True],
     [900, True],
     [900, True],
     [900, True],
     [900, True],
     [1300, True],
     [1300, False]]],
   [10, 20, 30, 40, 50, 50, 60, 50]],
  ['regression: crowd arrives',
   [{'min_pos': 20, 'max_pos': 80, 'co2_low': 700, 'co2_high': 1100},
    [[1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, True],
     [1500, False],
     [1500, False]]],
   [10, 20, 30, 40, 50, 60, 70, 80, 80, 70, 60]],
  ['control: moderate co2',
   [{'min_pos': 20, 'max_pos': 80, 'co2_low': 700, 'co2_high': 1100},
    [[800, True], [800, True], [800, True], [800, True], [800, True], [750, True], [750, True]]],
   [10, 20, 30, 35, 35, 28, 28]],
  ['regression: unoccupied high co2',
   [{'min_pos': 20, 'max_pos': 80, 'co2_low': 700, 'co2_high': 1100},
    [[1200, False], [1200, False], [1200, True]]],
   [0, 0, 10]],
  ['regression: scenario 1',
   [{'min_pos': 15, 'max_pos': 80, 'co2_low': 700, 'co2_high': 1200},
    [[1383, True],
     [1500, True],
     [1500, True],
     [1483, True],
     [1492, True],
     [1500, False],
     [1500, True],
     [1500, True],
     [1500, False],
     [1465, True],
     [1443, False],
     [1458, False],
     [1430, True]]],
   [10, 20, 30, 40, 50, 40, 50, 60, 50, 60, 50, 40, 50]],
  ['regression: scenario 3',
   [{'min_pos': 20, 'max_pos': 100, 'co2_low': 600, 'co2_high': 1200},
    [[1068, True],
     [969, True],
     [993, True],
     [1093, True],
     [1019, True],
     [1021, True],
     [1037, False],
     [990, True],
     [876, False],
     [997, True],
     [984, True],
     [903, False],
     [822, False]]],
   [10, 20, 30, 40, 50, 60, 50, 60, 50, 60, 70, 60, 50]]]]
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)

prompt:
Residual CO2 after everyone leaves keeps the outdoor damper open overnight.

CO2 demand-controlled ventilation per sample; samples are [co2_ppm, occupied]. Unoccupied target is 0%. Occupied: min_pos at or below co2_low, max_pos at or above co2_high, and linear in between rounded half up to whole percent. The damper moves toward the target by at most 10 percentage points per sample in either direction. Return the damper position per sample.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(cph, band, setpoint, temps):
    period = 60 / cph
    out = []
    on_left = 0
    for minute, temp in enumerate(temps):
        if minute % period == 0:
            err = setpoint - temp
            num = max(0, min(err, band)) * period
            on = (2 * num + band) // (2 * band)
            if 0 < on < 2:
                on = 2
            if 0 < period - on < 2:
                on = period
            on_left = on
        out.append(on_left > 0)
        if on_left > 0:
            on_left -= 1
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: seven cycles per hour',
   [7,
    20,
    700,
    [690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     685,
     685,
     685,
     685,
     685,
     685,
     685,
     685,
     685,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695]],
   [True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    True,
    True,
    False,
    False,
    True,
    True,
    False]],
  ['regression: scenario 3',
   [7,
    30,
    700,
    [693,
     691,
     695,
     691,
     695,
     698,
     697,
     700,
     702,
     704,
     706,
     708,
     709,
     707,
     706,
     702,
     702,
     701,
     698,
     701,
     700,
     704,
     703,
     702,
     702,
     699,
     695,
     694,
     696,
     699,
     696,
     692,
     694,
     693,
     694,
     697,
     700]],
   [True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    False,
    False,
    False]],
  ['control: three cycles',
   [5,
    20,
    700,
    [690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681]],
   [True,
    True,
    True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True]],
  ['control: tiny error',
   [6,
    30,
    700,
    [696, 696, 696, 696, 696, 696, 696, 696, 696, 696, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698]],
   [True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False]],
  ['control: above setpoint',
   [4,
    10,
    700,
    [705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695]],
   [False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False]],
  ['control: scenario 1',
   [4,
    10,
    700,
    [673,
     669,
     665,
     669,
     667,
     665,
     664,
     662,
     659,
     662,
     661,
     659,
     660,
     656,
     659,
     660,
     656,
     652,
     654,
     652,
     656,
     657,
     653,
     653,
     653,
     653,
     654,
     653,
     650,
     650,
     650,
     650,
     651,
     654,
     651,
     650,
     650,
     650,
     650]],
   [True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True]],
  ['control: scenario 2',
   [6,
    30,
    700,
    [697,
     695,
     691,
     695,
     691,
     692,
     693,
     692,
     690,
     690,
     690,
     687,
     684,
     683,
     687,
     688,
     688,
     691,
     690,
     692,
     693,
     689,
     692]],
   [True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    False]],
  ['control: scenario 4',
   [4,
    10,
    700,
    [680,
     684,
     685,
     683,
     684,
     685,
     686,
     682,
     681,
     679,
     677,
     681,
     680,
     681,
     677,
     681,
     680,
     682,
     682,
     678,
     677,
     673,
     672,
     676,
     673,
     670,
     669,
     665,
     662]],
   [True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True]]],
 [['regression: scenario 5',
   [9,
    10,
    700,
    [684,
     682,
     680,
     682,
     681,
     682,
     686,
     685,
     684,
     682,
     679,
     682,
     686,
     688,
     688,
     689,
     689,
     689,
     693,
     689,
     685,
     682,
     681,
     682,
     684,
     685]],
   [True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    False,
    False,
    True,
    True]],
  ['regression: scenario 4',
   [9,
    30,
    700,
    [705,
     708,
     704,
     703,
     700,
     701,
     701,
     702,
     699,
     698,
     698,
     697,
     698,
     702,
     699,
     700,
     701,
     697,
     700,
     697,
     694,
     695,
     696]],
   [False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False]],
  ['control: three cycles',
   [5,
    20,
    700,
    [690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681]],
   [True,
    True,
    True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True]],
  ['regression: seven cycles per hour',
   [7,
    20,
    700,
    [690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     685,
     685,
     685,
     685,
     685,
     685,
     685,
     685,
     685,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695]],
   [True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    True,
    True,
    False,
    False,
    True,
    True,
    False]],
  ['control: tiny error',
   [6,
    30,
    700,
    [696, 696, 696, 696, 696, 696, 696, 696, 696, 696, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698]],
   [True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False]],
  ['control: above setpoint',
   [4,
    10,
    700,
    [705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695]],
   [False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False]],
  ['control: scenario 1',
   [6,
    30,
    700,
    [690,
     689,
     690,
     691,
     689,
     685,
     682,
     686,
     682,
     680,
     684,
     687,
     690,
     693,
     692,
     689,
     688,
     685,
     683,
     685,
     687,
     683,
     684,
     688,
     691,
     689,
     686,
     683,
     679,
     679,
     682,
     680,
     680,
     684]],
   [True,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True]],
  ['control: scenario 2',
   [6,
    10,
    700,
    [686,
     687,
     685,
     682,
     682,
     678,
     681,
     677,
     676,
     673,
     674,
     676,
     672,
     670,
     669,
     673,
     674,
     676,
     675,
     673,
     675,
     672,
     673,
     674,
     670,
     672]],
   [True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True]]],
 [['regression: scenario 2',
   [9,
    20,
    700,
    [702,
     703,
     707,
     703,
     700,
     697,
     699,
     698,
     696,
     693,
     696,
     695,
     694,
     690,
     692,
     695,
     697,
     700,
     698,
     699,
     701,
     704,
     708,
     712,
     710,
     709,
     713,
     709,
     710,
     714,
     711,
     711,
     707,
     706,
     706]],
   [False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    False,
    False,
    False,
    False,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False]],
  ['regression: scenario 3',
   [7,
    30,
    700,
    [701,
     704,
     708,
     708,
     709,
     711,
     707,
     709,
     710,
     706,
     707,
     703,
     701,
     697,
     697,
     698,
     698,
     701,
     700,
     699,
     699,
     695,
     696,
     700,
     698,
     701,
     700]],
   [False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    False]],
  ['control: three cycles',
   [5,
    20,
    700,
    [690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681]],
   [True,
    True,
    True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True]],
  ['regression: seven cycles per hour',
   [7,
    20,
    700,
    [690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     685,
     685,
     685,
     685,
     685,
     685,
     685,
     685,
     685,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695]],
   [True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    True,
    True,
    False,
    False,
    True,
    True,
    False]],
  ['control: tiny error',
   [6,
    30,
    700,
    [696, 696, 696, 696, 696, 696, 696, 696, 696, 696, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698]],
   [True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False]],
  ['control: above setpoint',
   [4,
    10,
    700,
    [705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695]],
   [False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False]],
  ['regression: scenario 1',
   [7,
    20,
    700,
    [688,
     691,
     689,
     691,
     692,
     691,
     687,
     691,
     692,
     691,
     695,
     695,
     692,
     689,
     688,
     684,
     682,
     681,
     679,
     678,
     682,
     682,
     680,
     682,
     686,
     689,
     687,
     687,
     690,
     686,
     687,
     691]],
   [True,
    True,
    True,
    True,
    True,
    False,
    False,
    False,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    False,
    False]],
  ['control: scenario 4',
   [4,
    30,
    700,
    [675,
     676,
     675,
     674,
     673,
     676,
     674,
     672,
     673,
     672,
     674,
     677,
     674,
     671,
     668,
     664,
     668,
     667,
     668,
     670,
     668,
     670,
     672]],
   [True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    False,
    False,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True]]],
 [['regression: scenario 8',
   [7,
    30,
    700,
    [680,
     684,
     686,
     690,
     693,
     690,
     694,
     694,
     695,
     695,
     691,
     694,
     694,
     696,
     699,
     700,
     701,
     702,
     706,
     709,
     710,
     713,
     715,
     713,
     715,
     715,
     715,
     715,
     712]],
   [True,
    True,
    True,
    True,
    True,
    False,
    False,
    False,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False]],
  ['regression: scenario 25',
   [8,
    20,
    700,
    [686,
     685,
     683,
     680,
     677,
     673,
     671,
     669,
     666,
     666,
     666,
     664,
     664,
     664,
     667,
     663,
     663,
     662,
     661,
     663,
     667,
     666,
     663,
     664,
     663,
     665,
     668,
     664,
     667,
     670,
     669,
     670,
     667,
     666,
     664,
     667,
     670,
     666,
     670,
     669]],
   [True,
    True,
    True,
    True,
    True,
    False,
    False,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True]],
  ['control: three cycles',
   [5,
    20,
    700,
    [690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681]],
   [True,
    True,
    True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True]],
  ['regression: seven cycles per hour',
   [7,
    20,
    700,
    [690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     685,
     685,
     685,
     685,
     685,
     685,
     685,
     685,
     685,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695]],
   [True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    True,
    True,
    False,
    False,
    True,
    True,
    False]],
  ['control: tiny error',
   [6,
    30,
    700,
    [696, 696, 696, 696, 696, 696, 696, 696, 696, 696, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698]],
   [True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False]],
  ['control: above setpoint',
   [4,
    10,
    700,
    [705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695]],
   [False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False]],
  ['control: scenario 1',
   [6,
    10,
    700,
    [702,
     699,
     703,
     707,
     704,
     708,
     705,
     701,
     698,
     700,
     703,
     703,
     700,
     697,
     696,
     697,
     697,
     701,
     703,
     703,
     704,
     705,
     708,
     704,
     706,
     705,
     702,
     706,
     707,
     704,
     708,
     707,
     703,
     706,
     707,
     703,
     703,
     706,
     707,
     706]],
   [False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False]],
  ['control: scenario 2',
   [3,
    20,
    700,
    [682, 683, 684, 687, 687, 686, 682, 683, 680, 676, 680, 683, 679, 675, 674, 671, 671, 672, 670, 672]],
   [True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    False,
    False]]],
 [['regression: scenario 11',
   [9,
    10,
    700,
    [681,
     685,
     683,
     685,
     683,
     682,
     681,
     682,
     686,
     688,
     685,
     688,
     686,
     684,
     686,
     688,
     690,
     688,
     692,
     696,
     697,
     695,
     694,
     692,
     696,
     694,
     698,
     702,
     703,
     703,
     700,
     698,
     700,
     696,
     699,
     698]],
   [True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False]],
  ['regression: scenario 12',
   [7,
    30,
    700,
    [696,
     694,
     690,
     693,
     689,
     689,
     691,
     693,
     689,
     687,
     685,
     682,
     686,
     689,
     688,
     692,
     689,
     689,
     689,
     689,
     692,
     694,
     696,
     697,
     698,
     698,
     695,
     698,
     699,
     702,
     706,
     708,
     710,
     714,
     715]],
   [True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False]],
  ['control: three cycles',
   [5,
    20,
    700,
    [690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681]],
   [True,
    True,
    True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True]],
  ['regression: seven cycles per hour',
   [7,
    20,
    700,
    [690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     685,
     685,
     685,
     685,
     685,
     685,
     685,
     685,
     685,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695]],
   [True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    True,
    True,
    False,
    False,
    True,
    True,
    False]],
  ['control: tiny error',
   [6,
    30,
    700,
    [696, 696, 696, 696, 696, 696, 696, 696, 696, 696, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698]],
   [True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False]],
  ['control: above setpoint',
   [4,
    10,
    700,
    [705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695]],
   [False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False]],
  ['control: scenario 1',
   [5,
    10,
    700,
    [698,
     700,
     702,
     701,
     700,
     700,
     699,
     697,
     694,
     696,
     698,
     694,
     697,
     697,
     694,
     698,
     700,
     698,
     699,
     700,
     703,
     707,
     708,
     706,
     708,
     712,
     710,
     706,
     702,
     700,
     696,
     696,
     692]],
   [True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False]],
  ['control: scenario 2',
   [3,
    10,
    700,
    [669,
     665,
     665,
     665,
     666,
     665,
     663,
     665,
     667,
     665,
     667,
     663,
     663,
     667,
     667,
     668,
     664,
     664,
     664,
     663,
     661,
     661,
     661,
     664,
     666,
     664,
     668]],
   [True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True]]]]
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)

meaning: Fixture-count band, not measured model difficulty

deps: stdlib

source:
"""Failure Map reference implementation. Python standard library only."""
import json

N = 1
observations = []
def solve(cph, band, setpoint, temps):
    period = round(60 / cph)
    out = []
    on_left = 0
    for minute, temp in enumerate(temps):
        if minute % period == 0:
            err = setpoint - temp
            num = max(0, min(err, band)) * period
            on = (2 * num + band) // (2 * band)
            if 0 < on < 2:
                on = 2
            if 0 < period - on < 2:
                on = period
            on_left = on
        out.append(on_left > 0)
        if on_left > 0:
            on_left -= 1
    return out
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[['regression: seven cycles per hour',
   [7,
    20,
    700,
    [690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     685,
     685,
     685,
     685,
     685,
     685,
     685,
     685,
     685,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695]],
   [True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    True,
    True,
    False,
    False,
    True,
    True,
    False]],
  ['regression: scenario 3',
   [7,
    30,
    700,
    [693,
     691,
     695,
     691,
     695,
     698,
     697,
     700,
     702,
     704,
     706,
     708,
     709,
     707,
     706,
     702,
     702,
     701,
     698,
     701,
     700,
     704,
     703,
     702,
     702,
     699,
     695,
     694,
     696,
     699,
     696,
     692,
     694,
     693,
     694,
     697,
     700]],
   [True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    False,
    False,
    False]],
  ['control: three cycles',
   [5,
    20,
    700,
    [690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681]],
   [True,
    True,
    True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True]],
  ['control: tiny error',
   [6,
    30,
    700,
    [696, 696, 696, 696, 696, 696, 696, 696, 696, 696, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698]],
   [True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False]],
  ['control: above setpoint',
   [4,
    10,
    700,
    [705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695]],
   [False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False]],
  ['control: scenario 1',
   [4,
    10,
    700,
    [673,
     669,
     665,
     669,
     667,
     665,
     664,
     662,
     659,
     662,
     661,
     659,
     660,
     656,
     659,
     660,
     656,
     652,
     654,
     652,
     656,
     657,
     653,
     653,
     653,
     653,
     654,
     653,
     650,
     650,
     650,
     650,
     651,
     654,
     651,
     650,
     650,
     650,
     650]],
   [True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True]],
  ['control: scenario 2',
   [6,
    30,
    700,
    [697,
     695,
     691,
     695,
     691,
     692,
     693,
     692,
     690,
     690,
     690,
     687,
     684,
     683,
     687,
     688,
     688,
     691,
     690,
     692,
     693,
     689,
     692]],
   [True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    False]],
  ['control: scenario 4',
   [4,
    10,
    700,
    [680,
     684,
     685,
     683,
     684,
     685,
     686,
     682,
     681,
     679,
     677,
     681,
     680,
     681,
     677,
     681,
     680,
     682,
     682,
     678,
     677,
     673,
     672,
     676,
     673,
     670,
     669,
     665,
     662]],
   [True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True]]],
 [['regression: scenario 5',
   [9,
    10,
    700,
    [684,
     682,
     680,
     682,
     681,
     682,
     686,
     685,
     684,
     682,
     679,
     682,
     686,
     688,
     688,
     689,
     689,
     689,
     693,
     689,
     685,
     682,
     681,
     682,
     684,
     685]],
   [True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    False,
    False,
    True,
    True]],
  ['regression: scenario 4',
   [9,
    30,
    700,
    [705,
     708,
     704,
     703,
     700,
     701,
     701,
     702,
     699,
     698,
     698,
     697,
     698,
     702,
     699,
     700,
     701,
     697,
     700,
     697,
     694,
     695,
     696]],
   [False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False]],
  ['control: three cycles',
   [5,
    20,
    700,
    [690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681]],
   [True,
    True,
    True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True]],
  ['regression: seven cycles per hour',
   [7,
    20,
    700,
    [690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     685,
     685,
     685,
     685,
     685,
     685,
     685,
     685,
     685,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695]],
   [True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    True,
    True,
    False,
    False,
    True,
    True,
    False]],
  ['control: tiny error',
   [6,
    30,
    700,
    [696, 696, 696, 696, 696, 696, 696, 696, 696, 696, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698]],
   [True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False]],
  ['control: above setpoint',
   [4,
    10,
    700,
    [705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695]],
   [False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False]],
  ['control: scenario 1',
   [6,
    30,
    700,
    [690,
     689,
     690,
     691,
     689,
     685,
     682,
     686,
     682,
     680,
     684,
     687,
     690,
     693,
     692,
     689,
     688,
     685,
     683,
     685,
     687,
     683,
     684,
     688,
     691,
     689,
     686,
     683,
     679,
     679,
     682,
     680,
     680,
     684]],
   [True,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True]],
  ['control: scenario 2',
   [6,
    10,
    700,
    [686,
     687,
     685,
     682,
     682,
     678,
     681,
     677,
     676,
     673,
     674,
     676,
     672,
     670,
     669,
     673,
     674,
     676,
     675,
     673,
     675,
     672,
     673,
     674,
     670,
     672]],
   [True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True]]],
 [['regression: scenario 2',
   [9,
    20,
    700,
    [702,
     703,
     707,
     703,
     700,
     697,
     699,
     698,
     696,
     693,
     696,
     695,
     694,
     690,
     692,
     695,
     697,
     700,
     698,
     699,
     701,
     704,
     708,
     712,
     710,
     709,
     713,
     709,
     710,
     714,
     711,
     711,
     707,
     706,
     706]],
   [False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    False,
    False,
    False,
    False,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False]],
  ['regression: scenario 3',
   [7,
    30,
    700,
    [701,
     704,
     708,
     708,
     709,
     711,
     707,
     709,
     710,
     706,
     707,
     703,
     701,
     697,
     697,
     698,
     698,
     701,
     700,
     699,
     699,
     695,
     696,
     700,
     698,
     701,
     700]],
   [False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    False]],
  ['control: three cycles',
   [5,
    20,
    700,
    [690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681]],
   [True,
    True,
    True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True]],
  ['regression: seven cycles per hour',
   [7,
    20,
    700,
    [690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     685,
     685,
     685,
     685,
     685,
     685,
     685,
     685,
     685,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695]],
   [True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    True,
    True,
    False,
    False,
    True,
    True,
    False]],
  ['control: tiny error',
   [6,
    30,
    700,
    [696, 696, 696, 696, 696, 696, 696, 696, 696, 696, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698]],
   [True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False]],
  ['control: above setpoint',
   [4,
    10,
    700,
    [705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695]],
   [False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False]],
  ['regression: scenario 1',
   [7,
    20,
    700,
    [688,
     691,
     689,
     691,
     692,
     691,
     687,
     691,
     692,
     691,
     695,
     695,
     692,
     689,
     688,
     684,
     682,
     681,
     679,
     678,
     682,
     682,
     680,
     682,
     686,
     689,
     687,
     687,
     690,
     686,
     687,
     691]],
   [True,
    True,
    True,
    True,
    True,
    False,
    False,
    False,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    False,
    False]],
  ['control: scenario 4',
   [4,
    30,
    700,
    [675,
     676,
     675,
     674,
     673,
     676,
     674,
     672,
     673,
     672,
     674,
     677,
     674,
     671,
     668,
     664,
     668,
     667,
     668,
     670,
     668,
     670,
     672]],
   [True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    False,
    False,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True]]],
 [['regression: scenario 8',
   [7,
    30,
    700,
    [680,
     684,
     686,
     690,
     693,
     690,
     694,
     694,
     695,
     695,
     691,
     694,
     694,
     696,
     699,
     700,
     701,
     702,
     706,
     709,
     710,
     713,
     715,
     713,
     715,
     715,
     715,
     715,
     712]],
   [True,
    True,
    True,
    True,
    True,
    False,
    False,
    False,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False]],
  ['regression: scenario 25',
   [8,
    20,
    700,
    [686,
     685,
     683,
     680,
     677,
     673,
     671,
     669,
     666,
     666,
     666,
     664,
     664,
     664,
     667,
     663,
     663,
     662,
     661,
     663,
     667,
     666,
     663,
     664,
     663,
     665,
     668,
     664,
     667,
     670,
     669,
     670,
     667,
     666,
     664,
     667,
     670,
     666,
     670,
     669]],
   [True,
    True,
    True,
    True,
    True,
    False,
    False,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True]],
  ['control: three cycles',
   [5,
    20,
    700,
    [690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681]],
   [True,
    True,
    True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True]],
  ['regression: seven cycles per hour',
   [7,
    20,
    700,
    [690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     685,
     685,
     685,
     685,
     685,
     685,
     685,
     685,
     685,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695]],
   [True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    True,
    True,
    False,
    False,
    True,
    True,
    False]],
  ['control: tiny error',
   [6,
    30,
    700,
    [696, 696, 696, 696, 696, 696, 696, 696, 696, 696, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698]],
   [True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False]],
  ['control: above setpoint',
   [4,
    10,
    700,
    [705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695]],
   [False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False]],
  ['control: scenario 1',
   [6,
    10,
    700,
    [702,
     699,
     703,
     707,
     704,
     708,
     705,
     701,
     698,
     700,
     703,
     703,
     700,
     697,
     696,
     697,
     697,
     701,
     703,
     703,
     704,
     705,
     708,
     704,
     706,
     705,
     702,
     706,
     707,
     704,
     708,
     707,
     703,
     706,
     707,
     703,
     703,
     706,
     707,
     706]],
   [False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False]],
  ['control: scenario 2',
   [3,
    20,
    700,
    [682, 683, 684, 687, 687, 686, 682, 683, 680, 676, 680, 683, 679, 675, 674, 671, 671, 672, 670, 672]],
   [True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    False,
    False]]],
 [['regression: scenario 11',
   [9,
    10,
    700,
    [681,
     685,
     683,
     685,
     683,
     682,
     681,
     682,
     686,
     688,
     685,
     688,
     686,
     684,
     686,
     688,
     690,
     688,
     692,
     696,
     697,
     695,
     694,
     692,
     696,
     694,
     698,
     702,
     703,
     703,
     700,
     698,
     700,
     696,
     699,
     698]],
   [True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False]],
  ['regression: scenario 12',
   [7,
    30,
    700,
    [696,
     694,
     690,
     693,
     689,
     689,
     691,
     693,
     689,
     687,
     685,
     682,
     686,
     689,
     688,
     692,
     689,
     689,
     689,
     689,
     692,
     694,
     696,
     697,
     698,
     698,
     695,
     698,
     699,
     702,
     706,
     708,
     710,
     714,
     715]],
   [True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False]],
  ['control: three cycles',
   [5,
    20,
    700,
    [690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     700,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681,
     681]],
   [True,
    True,
    True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True]],
  ['regression: seven cycles per hour',
   [7,
    20,
    700,
    [690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     690,
     685,
     685,
     685,
     685,
     685,
     685,
     685,
     685,
     685,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695]],
   [True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    True,
    True,
    False,
    False,
    True,
    True,
    False]],
  ['control: tiny error',
   [6,
    30,
    700,
    [696, 696, 696, 696, 696, 696, 696, 696, 696, 696, 698, 698, 698, 698, 698, 698, 698, 698, 698, 698]],
   [True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False]],
  ['control: above setpoint',
   [4,
    10,
    700,
    [705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     705,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695,
     695]],
   [False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False]],
  ['control: scenario 1',
   [5,
    10,
    700,
    [698,
     700,
     702,
     701,
     700,
     700,
     699,
     697,
     694,
     696,
     698,
     694,
     697,
     697,
     694,
     698,
     700,
     698,
     699,
     700,
     703,
     707,
     708,
     706,
     708,
     712,
     710,
     706,
     702,
     700,
     696,
     696,
     692]],
   [True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    True,
    True,
    True,
    True,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False,
    False]],
  ['control: scenario 2',
   [3,
    10,
    700,
    [669,
     665,
     665,
     665,
     666,
     665,
     663,
     665,
     667,
     665,
     667,
     663,
     663,
     667,
     667,
     668,
     664,
     664,
     664,
     663,
     661,
     661,
     661,
     664,
     666,
     664,
     668]],
   [True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True,
    True]]]]
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)

prompt:
With 7 or 9 cycles per hour the heater only cycles once, at minute 0, and then stays off.

Time-proportioning heating thermostat with a cycles-per-hour setting, sampled per minute. The cycle length is 60 // cph minutes. At each cycle start the error (setpoint - temp) is clamped to 0..band and the on time is error/band of the cycle rounded half up; an on time of 1 minute is extended to the 2-minute minimum, and an off time of 1 minute is eliminated (full on). The output is on for the first on-time minutes of the cycle. Return the heat output per minute.

split: open-access