broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json
import math
from fractions import Fraction
N = 1
observations = []
def solve(x):
    tgt, cur = Fraction(str(x['target'])), Fraction(str(x['current']))
    f = Fraction(str(x['f']))
    u = x['unit_mg']
    vd = Fraction(str(x['vd_l_kg']))
    wt = Fraction(str(x['weight_kg']))
    cl = Fraction(x['cl_ml_min']) * 60 / 1000
    def rnd(v):
        return float(math.floor(v / u) * u)
    load = max(Fraction(0), (tgt - cur) * vd * wt / f)
    maint = tgt * cl * x['tau_h'] / f
    return {'loading_mg': rnd(load), 'maintenance_mg': rnd(maint)}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('drug-naive loading',
   {'target': 15,
    'current': 0,
    'vd_l_kg': '0.7',
    'weight_kg': 71,
    'f': 1,
    'cl_ml_min': 100,
    'tau_h': 12,
    'unit_mg': 50},
   {'loading_mg': 750.0, 'maintenance_mg': 1100.0}),
  ('partial existing level credited',
   {'target': 20,
    'current': 6,
    'vd_l_kg': '0.5',
    'weight_kg': 80,
    'f': '0.8',
    'cl_ml_min': 80,
    'tau_h': 8,
    'unit_mg': 25},
   {'loading_mg': 700.0, 'maintenance_mg': 950.0}),
  ('level above target gives no load',
   {'target': 10,
    'current': 13,
    'vd_l_kg': '0.6',
    'weight_kg': 70,
    'f': 1,
    'cl_ml_min': 90,
    'tau_h': 12,
    'unit_mg': 50},
   {'loading_mg': 0.0, 'maintenance_mg': 650.0}),
  ('oral bioavailability maintenance',
   {'target': 2,
    'current': 0,
    'vd_l_kg': '1.0',
    'weight_kg': 60,
    'f': '0.5',
    'cl_ml_min': 50,
    'tau_h': 24,
    'unit_mg': 5},
   {'loading_mg': 240.0, 'maintenance_mg': 290.0}),
  ('half unit rounds up',
   {'target': 5,
    'current': 0,
    'vd_l_kg': '0.5',
    'weight_kg': 65,
    'f': 1,
    'cl_ml_min': 25,
    'tau_h': 6,
    'unit_mg': 25},
   {'loading_mg': 175.0, 'maintenance_mg': 50.0}),
  ('slow clearance long interval',
   {'target': 1,
    'current': 0,
    'vd_l_kg': '0.2',
    'weight_kg': 50,
    'f': 1,
    'cl_ml_min': 10,
    'tau_h': 24,
    'unit_mg': 1},
   {'loading_mg': 10.0, 'maintenance_mg': 14.0})],
 [('drug-naive loading',
   {'target': 15,
    'current': 0,
    'vd_l_kg': '0.7',
    'weight_kg': 72,
    'f': 1,
    'cl_ml_min': 100,
    'tau_h': 12,
    'unit_mg': 50},
   {'loading_mg': 750.0, 'maintenance_mg': 1100.0}),
  ('partial existing level credited',
   {'target': 20,
    'current': 7,
    'vd_l_kg': '0.5',
    'weight_kg': 80,
    'f': '0.8',
    'cl_ml_min': 80,
    'tau_h': 8,
    'unit_mg': 25},
   {'loading_mg': 650.0, 'maintenance_mg': 950.0}),
  ('level above target gives no load',
   {'target': 10,
    'current': 14,
    'vd_l_kg': '0.6',
    'weight_kg': 70,
    'f': 1,
    'cl_ml_min': 90,
    'tau_h': 12,
    'unit_mg': 50},
   {'loading_mg': 0.0, 'maintenance_mg': 650.0}),
  ('oral bioavailability maintenance',
   {'target': 2,
    'current': 0,
    'vd_l_kg': '1.0',
    'weight_kg': 60,
    'f': '0.8',
    'cl_ml_min': 50,
    'tau_h': 24,
    'unit_mg': 5},
   {'loading_mg': 150.0, 'maintenance_mg': 180.0}),
  ('half unit rounds up',
   {'target': 5,
    'current': 0,
    'vd_l_kg': '0.5',
    'weight_kg': 25,
    'f': 1,
    'cl_ml_min': 25,
    'tau_h': 6,
    'unit_mg': 25},
   {'loading_mg': 75.0, 'maintenance_mg': 50.0}),
  ('slow clearance long interval',
   {'target': 1,
    'current': 0,
    'vd_l_kg': '0.2',
    'weight_kg': 50,
    'f': 1,
    'cl_ml_min': 20,
    'tau_h': 24,
    'unit_mg': 1},
   {'loading_mg': 10.0, 'maintenance_mg': 29.0})],
 [('drug-naive loading',
   {'target': 15,
    'current': 0,
    'vd_l_kg': '0.7',
    'weight_kg': 73,
    'f': 1,
    'cl_ml_min': 100,
    'tau_h': 12,
    'unit_mg': 50},
   {'loading_mg': 750.0, 'maintenance_mg': 1100.0}),
  ('partial existing level credited',
   {'target': 20,
    'current': 8,
    'vd_l_kg': '0.5',
    'weight_kg': 80,
    'f': '0.8',
    'cl_ml_min': 80,
    'tau_h': 8,
    'unit_mg': 25},
   {'loading_mg': 600.0, 'maintenance_mg': 950.0}),
  ('level above target gives no load',
   {'target': 10,
    'current': 15,
    'vd_l_kg': '0.6',
    'weight_kg': 70,
    'f': 1,
    'cl_ml_min': 90,
    'tau_h': 12,
    'unit_mg': 50},
   {'loading_mg': 0.0, 'maintenance_mg': 650.0}),
  ('oral bioavailability maintenance',
   {'target': 2,
    'current': 0,
    'vd_l_kg': '1.0',
    'weight_kg': 60,
    'f': '0.25',
    'cl_ml_min': 50,
    'tau_h': 24,
    'unit_mg': 5},
   {'loading_mg': 480.0, 'maintenance_mg': 575.0}),
  ('half unit rounds up',
   {'target': 5,
    'current': 0,
    'vd_l_kg': '0.5',
    'weight_kg': 45,
    'f': 1,
    'cl_ml_min': 25,
    'tau_h': 6,
    'unit_mg': 25},
   {'loading_mg': 125.0, 'maintenance_mg': 50.0}),
  ('slow clearance long interval',
   {'target': 1,
    'current': 0,
    'vd_l_kg': '0.2',
    'weight_kg': 50,
    'f': 1,
    'cl_ml_min': 30,
    'tau_h': 24,
    'unit_mg': 1},
   {'loading_mg': 10.0, 'maintenance_mg': 43.0})],
 [('drug-naive loading',
   {'target': 15,
    'current': 0,
    'vd_l_kg': '0.7',
    'weight_kg': 74,
    'f': 1,
    'cl_ml_min': 100,
    'tau_h': 12,
    'unit_mg': 50},
   {'loading_mg': 800.0, 'maintenance_mg': 1100.0}),
  ('partial existing level credited',
   {'target': 20,
    'current': 9,
    'vd_l_kg': '0.5',
    'weight_kg': 80,
    'f': '0.8',
    'cl_ml_min': 80,
    'tau_h': 8,
    'unit_mg': 25},
   {'loading_mg': 550.0, 'maintenance_mg': 950.0}),
  ('level above target gives no load',
   {'target': 10,
    'current': 16,
    'vd_l_kg': '0.6',
    'weight_kg': 70,
    'f': 1,
    'cl_ml_min': 90,
    'tau_h': 12,
    'unit_mg': 50},
   {'loading_mg': 0.0, 'maintenance_mg': 650.0}),
  ('oral bioavailability maintenance',
   {'target': 2,
    'current': 0,
    'vd_l_kg': '1.0',
    'weight_kg': 60,
    'f': '0.4',
    'cl_ml_min': 50,
    'tau_h': 24,
    'unit_mg': 5},
   {'loading_mg': 300.0, 'maintenance_mg': 360.0}),
  ('half unit rounds up',
   {'target': 5,
    'current': 0,
    'vd_l_kg': '0.5',
    'weight_kg': 85,
    'f': 1,
    'cl_ml_min': 25,
    'tau_h': 6,
    'unit_mg': 25},
   {'loading_mg': 225.0, 'maintenance_mg': 50.0}),
  ('slow clearance long interval',
   {'target': 1,
    'current': 0,
    'vd_l_kg': '0.2',
    'weight_kg': 50,
    'f': 1,
    'cl_ml_min': 40,
    'tau_h': 24,
    'unit_mg': 1},
   {'loading_mg': 10.0, 'maintenance_mg': 58.0})],
 [('drug-naive loading',
   {'target': 15,
    'current': 0,
    'vd_l_kg': '0.7',
    'weight_kg': 75,
    'f': 1,
    'cl_ml_min': 100,
    'tau_h': 12,
    'unit_mg': 50},
   {'loading_mg': 800.0, 'maintenance_mg': 1100.0}),
  ('partial existing level credited',
   {'target': 20,
    'current': 10,
    'vd_l_kg': '0.5',
    'weight_kg': 80,
    'f': '0.8',
    'cl_ml_min': 80,
    'tau_h': 8,
    'unit_mg': 25},
   {'loading_mg': 500.0, 'maintenance_mg': 950.0}),
  ('level above target gives no load',
   {'target': 10,
    'current': 17,
    'vd_l_kg': '0.6',
    'weight_kg': 70,
    'f': 1,
    'cl_ml_min': 90,
    'tau_h': 12,
    'unit_mg': 50},
   {'loading_mg': 0.0, 'maintenance_mg': 650.0}),
  ('oral bioavailability maintenance',
   {'target': 2,
    'current': 0,
    'vd_l_kg': '1.0',
    'weight_kg': 60,
    'f': '0.6',
    'cl_ml_min': 50,
    'tau_h': 24,
    'unit_mg': 5},
   {'loading_mg': 200.0, 'maintenance_mg': 240.0}),
  ('half unit rounds up',
   {'target': 5,
    'current': 0,
    'vd_l_kg': '0.5',
    'weight_kg': 105,
    'f': 1,
    'cl_ml_min': 25,
    'tau_h': 6,
    'unit_mg': 25},
   {'loading_mg': 275.0, 'maintenance_mg': 50.0}),
  ('slow clearance long interval',
   {'target': 1,
    'current': 0,
    'vd_l_kg': '0.2',
    'weight_kg': 50,
    'f': 1,
    'cl_ml_min': 50,
    'tau_h': 24,
    'unit_mg': 1},
   {'loading_mg': 10.0, 'maintenance_mg': 72.0})]]
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
import math
from fractions import Fraction
N = 1
observations = []
def solve(x):
    tgt, cur = Fraction(str(x['target'])), Fraction(str(x['current']))
    f = Fraction(str(x['f']))
    u = x['unit_mg']
    vd = Fraction(str(x['vd_l_kg']))
    wt = Fraction(str(x['weight_kg']))
    cl = Fraction(x['cl_ml_min']) * 60 / 1000
    def rnd(v):
        return float(round(v / u) * u)
    load = max(Fraction(0), (tgt - cur) * vd * wt / f)
    maint = tgt * cl * x['tau_h'] / f
    return {'loading_mg': rnd(load), 'maintenance_mg': rnd(maint)}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('drug-naive loading',
   {'target': 15,
    'current': 0,
    'vd_l_kg': '0.7',
    'weight_kg': 71,
    'f': 1,
    'cl_ml_min': 100,
    'tau_h': 12,
    'unit_mg': 50},
   {'loading_mg': 750.0, 'maintenance_mg': 1100.0}),
  ('partial existing level credited',
   {'target': 20,
    'current': 6,
    'vd_l_kg': '0.5',
    'weight_kg': 80,
    'f': '0.8',
    'cl_ml_min': 80,
    'tau_h': 8,
    'unit_mg': 25},
   {'loading_mg': 700.0, 'maintenance_mg': 950.0}),
  ('level above target gives no load',
   {'target': 10,
    'current': 13,
    'vd_l_kg': '0.6',
    'weight_kg': 70,
    'f': 1,
    'cl_ml_min': 90,
    'tau_h': 12,
    'unit_mg': 50},
   {'loading_mg': 0.0, 'maintenance_mg': 650.0}),
  ('oral bioavailability maintenance',
   {'target': 2,
    'current': 0,
    'vd_l_kg': '1.0',
    'weight_kg': 60,
    'f': '0.5',
    'cl_ml_min': 50,
    'tau_h': 24,
    'unit_mg': 5},
   {'loading_mg': 240.0, 'maintenance_mg': 290.0}),
  ('half unit rounds up',
   {'target': 5,
    'current': 0,
    'vd_l_kg': '0.5',
    'weight_kg': 65,
    'f': 1,
    'cl_ml_min': 25,
    'tau_h': 6,
    'unit_mg': 25},
   {'loading_mg': 175.0, 'maintenance_mg': 50.0}),
  ('slow clearance long interval',
   {'target': 1,
    'current': 0,
    'vd_l_kg': '0.2',
    'weight_kg': 50,
    'f': 1,
    'cl_ml_min': 10,
    'tau_h': 24,
    'unit_mg': 1},
   {'loading_mg': 10.0, 'maintenance_mg': 14.0})],
 [('drug-naive loading',
   {'target': 15,
    'current': 0,
    'vd_l_kg': '0.7',
    'weight_kg': 72,
    'f': 1,
    'cl_ml_min': 100,
    'tau_h': 12,
    'unit_mg': 50},
   {'loading_mg': 750.0, 'maintenance_mg': 1100.0}),
  ('partial existing level credited',
   {'target': 20,
    'current': 7,
    'vd_l_kg': '0.5',
    'weight_kg': 80,
    'f': '0.8',
    'cl_ml_min': 80,
    'tau_h': 8,
    'unit_mg': 25},
   {'loading_mg': 650.0, 'maintenance_mg': 950.0}),
  ('level above target gives no load',
   {'target': 10,
    'current': 14,
    'vd_l_kg': '0.6',
    'weight_kg': 70,
    'f': 1,
    'cl_ml_min': 90,
    'tau_h': 12,
    'unit_mg': 50},
   {'loading_mg': 0.0, 'maintenance_mg': 650.0}),
  ('oral bioavailability maintenance',
   {'target': 2,
    'current': 0,
    'vd_l_kg': '1.0',
    'weight_kg': 60,
    'f': '0.8',
    'cl_ml_min': 50,
    'tau_h': 24,
    'unit_mg': 5},
   {'loading_mg': 150.0, 'maintenance_mg': 180.0}),
  ('half unit rounds up',
   {'target': 5,
    'current': 0,
    'vd_l_kg': '0.5',
    'weight_kg': 25,
    'f': 1,
    'cl_ml_min': 25,
    'tau_h': 6,
    'unit_mg': 25},
   {'loading_mg': 75.0, 'maintenance_mg': 50.0}),
  ('slow clearance long interval',
   {'target': 1,
    'current': 0,
    'vd_l_kg': '0.2',
    'weight_kg': 50,
    'f': 1,
    'cl_ml_min': 20,
    'tau_h': 24,
    'unit_mg': 1},
   {'loading_mg': 10.0, 'maintenance_mg': 29.0})],
 [('drug-naive loading',
   {'target': 15,
    'current': 0,
    'vd_l_kg': '0.7',
    'weight_kg': 73,
    'f': 1,
    'cl_ml_min': 100,
    'tau_h': 12,
    'unit_mg': 50},
   {'loading_mg': 750.0, 'maintenance_mg': 1100.0}),
  ('partial existing level credited',
   {'target': 20,
    'current': 8,
    'vd_l_kg': '0.5',
    'weight_kg': 80,
    'f': '0.8',
    'cl_ml_min': 80,
    'tau_h': 8,
    'unit_mg': 25},
   {'loading_mg': 600.0, 'maintenance_mg': 950.0}),
  ('level above target gives no load',
   {'target': 10,
    'current': 15,
    'vd_l_kg': '0.6',
    'weight_kg': 70,
    'f': 1,
    'cl_ml_min': 90,
    'tau_h': 12,
    'unit_mg': 50},
   {'loading_mg': 0.0, 'maintenance_mg': 650.0}),
  ('oral bioavailability maintenance',
   {'target': 2,
    'current': 0,
    'vd_l_kg': '1.0',
    'weight_kg': 60,
    'f': '0.25',
    'cl_ml_min': 50,
    'tau_h': 24,
    'unit_mg': 5},
   {'loading_mg': 480.0, 'maintenance_mg': 575.0}),
  ('half unit rounds up',
   {'target': 5,
    'current': 0,
    'vd_l_kg': '0.5',
    'weight_kg': 45,
    'f': 1,
    'cl_ml_min': 25,
    'tau_h': 6,
    'unit_mg': 25},
   {'loading_mg': 125.0, 'maintenance_mg': 50.0}),
  ('slow clearance long interval',
   {'target': 1,
    'current': 0,
    'vd_l_kg': '0.2',
    'weight_kg': 50,
    'f': 1,
    'cl_ml_min': 30,
    'tau_h': 24,
    'unit_mg': 1},
   {'loading_mg': 10.0, 'maintenance_mg': 43.0})],
 [('drug-naive loading',
   {'target': 15,
    'current': 0,
    'vd_l_kg': '0.7',
    'weight_kg': 74,
    'f': 1,
    'cl_ml_min': 100,
    'tau_h': 12,
    'unit_mg': 50},
   {'loading_mg': 800.0, 'maintenance_mg': 1100.0}),
  ('partial existing level credited',
   {'target': 20,
    'current': 9,
    'vd_l_kg': '0.5',
    'weight_kg': 80,
    'f': '0.8',
    'cl_ml_min': 80,
    'tau_h': 8,
    'unit_mg': 25},
   {'loading_mg': 550.0, 'maintenance_mg': 950.0}),
  ('level above target gives no load',
   {'target': 10,
    'current': 16,
    'vd_l_kg': '0.6',
    'weight_kg': 70,
    'f': 1,
    'cl_ml_min': 90,
    'tau_h': 12,
    'unit_mg': 50},
   {'loading_mg': 0.0, 'maintenance_mg': 650.0}),
  ('oral bioavailability maintenance',
   {'target': 2,
    'current': 0,
    'vd_l_kg': '1.0',
    'weight_kg': 60,
    'f': '0.4',
    'cl_ml_min': 50,
    'tau_h': 24,
    'unit_mg': 5},
   {'loading_mg': 300.0, 'maintenance_mg': 360.0}),
  ('half unit rounds up',
   {'target': 5,
    'current': 0,
    'vd_l_kg': '0.5',
    'weight_kg': 85,
    'f': 1,
    'cl_ml_min': 25,
    'tau_h': 6,
    'unit_mg': 25},
   {'loading_mg': 225.0, 'maintenance_mg': 50.0}),
  ('slow clearance long interval',
   {'target': 1,
    'current': 0,
    'vd_l_kg': '0.2',
    'weight_kg': 50,
    'f': 1,
    'cl_ml_min': 40,
    'tau_h': 24,
    'unit_mg': 1},
   {'loading_mg': 10.0, 'maintenance_mg': 58.0})],
 [('drug-naive loading',
   {'target': 15,
    'current': 0,
    'vd_l_kg': '0.7',
    'weight_kg': 75,
    'f': 1,
    'cl_ml_min': 100,
    'tau_h': 12,
    'unit_mg': 50},
   {'loading_mg': 800.0, 'maintenance_mg': 1100.0}),
  ('partial existing level credited',
   {'target': 20,
    'current': 10,
    'vd_l_kg': '0.5',
    'weight_kg': 80,
    'f': '0.8',
    'cl_ml_min': 80,
    'tau_h': 8,
    'unit_mg': 25},
   {'loading_mg': 500.0, 'maintenance_mg': 950.0}),
  ('level above target gives no load',
   {'target': 10,
    'current': 17,
    'vd_l_kg': '0.6',
    'weight_kg': 70,
    'f': 1,
    'cl_ml_min': 90,
    'tau_h': 12,
    'unit_mg': 50},
   {'loading_mg': 0.0, 'maintenance_mg': 650.0}),
  ('oral bioavailability maintenance',
   {'target': 2,
    'current': 0,
    'vd_l_kg': '1.0',
    'weight_kg': 60,
    'f': '0.6',
    'cl_ml_min': 50,
    'tau_h': 24,
    'unit_mg': 5},
   {'loading_mg': 200.0, 'maintenance_mg': 240.0}),
  ('half unit rounds up',
   {'target': 5,
    'current': 0,
    'vd_l_kg': '0.5',
    'weight_kg': 105,
    'f': 1,
    'cl_ml_min': 25,
    'tau_h': 6,
    'unit_mg': 25},
   {'loading_mg': 275.0, 'maintenance_mg': 50.0}),
  ('slow clearance long interval',
   {'target': 1,
    'current': 0,
    'vd_l_kg': '0.2',
    'weight_kg': 50,
    'f': 1,
    'cl_ml_min': 50,
    'tau_h': 24,
    'unit_mg': 1},
   {'loading_mg': 10.0, 'maintenance_mg': 72.0})]]
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:
A 162.5 mg requirement with 25 mg units is given as 150 mg.

Input {target, current, vd_l_kg, weight_kg, f, cl_ml_min, tau_h, unit_mg}. Toy one-compartment rule: loading = max(0, (target-current)*Vd*weight/F); maintenance = target*CL*tau/F with CL in L/h = cl_ml_min*60/1000. Both are rounded half-up to a multiple of unit_mg. Return {loading_mg, maintenance_mg}.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json
import math
from fractions import Fraction
N = 1
observations = []
def solve(x):
    gtt = Fraction(x['volume_ml'] * 60, x['duration_min'])
    gtt_i = math.floor(gtt + Fraction(1, 2))
    mlh = Fraction(x['volume_ml'] * 60, x['duration_min'])
    mlh_t = math.floor(mlh * 10 + Fraction(1, 2))
    h, m = map(int, x['start'].split(':'))
    total = h * 60 + m + x['duration_min']
    day = total // 1440
    total = total % 1440
    return {'gtt_min': gtt_i, 'ml_h': mlh_t / 10, 'end': '%02d:%02d' % (total // 60, total % 60), 'day_offset': day}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 15, 'start': '14:05'},
   {'gtt_min': 31, 'ml_h': 125.0, 'end': '22:05', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 15, 'start': '08:00'},
   {'gtt_min': 38, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 103, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 34, 'ml_h': 103.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 150, 'drop_factor': 20, 'start': '22:00'},
   {'gtt_min': 67, 'ml_h': 200.0, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 2940, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 41, 'ml_h': 40.8, 'end': '14:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 31, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 97, 'ml_h': 96.8, 'end': '11:16', 'day_offset': 0})],
 [('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 20, 'start': '14:10'},
   {'gtt_min': 42, 'ml_h': 125.0, 'end': '22:10', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 15, 'start': '08:00'},
   {'gtt_min': 38, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 106, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 35, 'ml_h': 106.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 180, 'drop_factor': 20, 'start': '21:30'},
   {'gtt_min': 56, 'ml_h': 166.7, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 3000, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 40, 'ml_h': 40.0, 'end': '15:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 32, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 94, 'ml_h': 93.8, 'end': '11:17', 'day_offset': 0})],
 [('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 10, 'start': '14:15'},
   {'gtt_min': 21, 'ml_h': 125.0, 'end': '22:15', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 10, 'start': '08:00'},
   {'gtt_min': 25, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 109, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 36, 'ml_h': 109.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 210, 'drop_factor': 20, 'start': '21:00'},
   {'gtt_min': 48, 'ml_h': 142.9, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 3060, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 39, 'ml_h': 39.2, 'end': '16:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 33, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 91, 'ml_h': 90.9, 'end': '11:18', 'day_offset': 0})],
 [('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 15, 'start': '14:20'},
   {'gtt_min': 31, 'ml_h': 125.0, 'end': '22:20', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 20, 'start': '08:00'},
   {'gtt_min': 50, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 112, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 37, 'ml_h': 112.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 240, 'drop_factor': 20, 'start': '20:30'},
   {'gtt_min': 42, 'ml_h': 125.0, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 3120, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 38, 'ml_h': 38.5, 'end': '17:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 34, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 88, 'ml_h': 88.2, 'end': '11:19', 'day_offset': 0})],
 [('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 20, 'start': '14:25'},
   {'gtt_min': 42, 'ml_h': 125.0, 'end': '22:25', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 15, 'start': '08:00'},
   {'gtt_min': 38, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 115, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 38, 'ml_h': 115.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 270, 'drop_factor': 20, 'start': '20:00'},
   {'gtt_min': 37, 'ml_h': 111.1, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 3180, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 38, 'ml_h': 37.7, 'end': '18:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 35, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 86, 'ml_h': 85.7, 'end': '11:20', 'day_offset': 0})]]
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
import math
from fractions import Fraction
N = 1
observations = []
def solve(x):
    gtt = Fraction(x['volume_ml'] * x['drop_factor'], 60)
    gtt_i = math.floor(gtt + Fraction(1, 2))
    mlh = Fraction(x['volume_ml'] * 60, x['duration_min'])
    mlh_t = math.floor(mlh * 10 + Fraction(1, 2))
    h, m = map(int, x['start'].split(':'))
    total = h * 60 + m + x['duration_min']
    day = total // 1440
    total = total % 1440
    return {'gtt_min': gtt_i, 'ml_h': mlh_t / 10, 'end': '%02d:%02d' % (total // 60, total % 60), 'day_offset': day}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 15, 'start': '14:05'},
   {'gtt_min': 31, 'ml_h': 125.0, 'end': '22:05', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 15, 'start': '08:00'},
   {'gtt_min': 38, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 103, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 34, 'ml_h': 103.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 150, 'drop_factor': 20, 'start': '22:00'},
   {'gtt_min': 67, 'ml_h': 200.0, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 2940, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 41, 'ml_h': 40.8, 'end': '14:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 31, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 97, 'ml_h': 96.8, 'end': '11:16', 'day_offset': 0})],
 [('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 20, 'start': '14:10'},
   {'gtt_min': 42, 'ml_h': 125.0, 'end': '22:10', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 15, 'start': '08:00'},
   {'gtt_min': 38, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 106, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 35, 'ml_h': 106.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 180, 'drop_factor': 20, 'start': '21:30'},
   {'gtt_min': 56, 'ml_h': 166.7, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 3000, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 40, 'ml_h': 40.0, 'end': '15:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 32, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 94, 'ml_h': 93.8, 'end': '11:17', 'day_offset': 0})],
 [('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 10, 'start': '14:15'},
   {'gtt_min': 21, 'ml_h': 125.0, 'end': '22:15', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 10, 'start': '08:00'},
   {'gtt_min': 25, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 109, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 36, 'ml_h': 109.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 210, 'drop_factor': 20, 'start': '21:00'},
   {'gtt_min': 48, 'ml_h': 142.9, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 3060, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 39, 'ml_h': 39.2, 'end': '16:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 33, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 91, 'ml_h': 90.9, 'end': '11:18', 'day_offset': 0})],
 [('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 15, 'start': '14:20'},
   {'gtt_min': 31, 'ml_h': 125.0, 'end': '22:20', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 20, 'start': '08:00'},
   {'gtt_min': 50, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 112, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 37, 'ml_h': 112.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 240, 'drop_factor': 20, 'start': '20:30'},
   {'gtt_min': 42, 'ml_h': 125.0, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 3120, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 38, 'ml_h': 38.5, 'end': '17:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 34, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 88, 'ml_h': 88.2, 'end': '11:19', 'day_offset': 0})],
 [('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 20, 'start': '14:25'},
   {'gtt_min': 42, 'ml_h': 125.0, 'end': '22:25', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 15, 'start': '08:00'},
   {'gtt_min': 38, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 115, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 38, 'ml_h': 115.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 270, 'drop_factor': 20, 'start': '20:00'},
   {'gtt_min': 37, 'ml_h': 111.1, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 3180, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 38, 'ml_h': 37.7, 'end': '18:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 35, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 86, 'ml_h': 85.7, 'end': '11:20', 'day_offset': 0})]]
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:
A 15 gtt/mL macrodrip set is counted as if it were a 60 gtt/mL microdrip set.

Input {volume_ml, duration_min, drop_factor (gtt/mL), start "HH:MM" 24-hour}. drops/min = volume*drop_factor/duration rounded half-up to a whole drop; mL/h = volume*60/duration rounded half-up to 0.1; end = start + duration on a 24-hour clock with day_offset = number of midnights crossed (ending exactly at 00:00 counts as the next day). Return {gtt_min, ml_h, end, day_offset}.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json
import math
from fractions import Fraction
N = 1
observations = []
def solve(x):
    gtt = Fraction(x['volume_ml'] * x['drop_factor'], x['duration_min'])
    gtt_i = math.floor(gtt)
    mlh = Fraction(x['volume_ml'] * 60, x['duration_min'])
    mlh_t = math.floor(mlh * 10 + Fraction(1, 2))
    h, m = map(int, x['start'].split(':'))
    total = h * 60 + m + x['duration_min']
    day = total // 1440
    total = total % 1440
    return {'gtt_min': gtt_i, 'ml_h': mlh_t / 10, 'end': '%02d:%02d' % (total // 60, total % 60), 'day_offset': day}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 15, 'start': '14:05'},
   {'gtt_min': 31, 'ml_h': 125.0, 'end': '22:05', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 15, 'start': '08:00'},
   {'gtt_min': 38, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 103, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 34, 'ml_h': 103.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 150, 'drop_factor': 20, 'start': '22:00'},
   {'gtt_min': 67, 'ml_h': 200.0, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 2940, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 41, 'ml_h': 40.8, 'end': '14:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 31, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 97, 'ml_h': 96.8, 'end': '11:16', 'day_offset': 0})],
 [('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 20, 'start': '14:10'},
   {'gtt_min': 42, 'ml_h': 125.0, 'end': '22:10', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 15, 'start': '08:00'},
   {'gtt_min': 38, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 106, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 35, 'ml_h': 106.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 180, 'drop_factor': 20, 'start': '21:30'},
   {'gtt_min': 56, 'ml_h': 166.7, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 3000, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 40, 'ml_h': 40.0, 'end': '15:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 32, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 94, 'ml_h': 93.8, 'end': '11:17', 'day_offset': 0})],
 [('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 10, 'start': '14:15'},
   {'gtt_min': 21, 'ml_h': 125.0, 'end': '22:15', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 10, 'start': '08:00'},
   {'gtt_min': 25, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 109, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 36, 'ml_h': 109.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 210, 'drop_factor': 20, 'start': '21:00'},
   {'gtt_min': 48, 'ml_h': 142.9, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 3060, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 39, 'ml_h': 39.2, 'end': '16:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 33, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 91, 'ml_h': 90.9, 'end': '11:18', 'day_offset': 0})],
 [('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 15, 'start': '14:20'},
   {'gtt_min': 31, 'ml_h': 125.0, 'end': '22:20', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 20, 'start': '08:00'},
   {'gtt_min': 50, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 112, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 37, 'ml_h': 112.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 240, 'drop_factor': 20, 'start': '20:30'},
   {'gtt_min': 42, 'ml_h': 125.0, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 3120, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 38, 'ml_h': 38.5, 'end': '17:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 34, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 88, 'ml_h': 88.2, 'end': '11:19', 'day_offset': 0})],
 [('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 20, 'start': '14:25'},
   {'gtt_min': 42, 'ml_h': 125.0, 'end': '22:25', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 15, 'start': '08:00'},
   {'gtt_min': 38, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 115, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 38, 'ml_h': 115.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 270, 'drop_factor': 20, 'start': '20:00'},
   {'gtt_min': 37, 'ml_h': 111.1, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 3180, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 38, 'ml_h': 37.7, 'end': '18:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 35, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 86, 'ml_h': 85.7, 'end': '11:20', 'day_offset': 0})]]
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
import math
from fractions import Fraction
N = 1
observations = []
def solve(x):
    gtt = Fraction(x['volume_ml'] * x['drop_factor'], x['duration_min'])
    gtt_i = math.ceil(gtt)
    mlh = Fraction(x['volume_ml'] * 60, x['duration_min'])
    mlh_t = math.floor(mlh * 10 + Fraction(1, 2))
    h, m = map(int, x['start'].split(':'))
    total = h * 60 + m + x['duration_min']
    day = total // 1440
    total = total % 1440
    return {'gtt_min': gtt_i, 'ml_h': mlh_t / 10, 'end': '%02d:%02d' % (total // 60, total % 60), 'day_offset': day}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 15, 'start': '14:05'},
   {'gtt_min': 31, 'ml_h': 125.0, 'end': '22:05', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 15, 'start': '08:00'},
   {'gtt_min': 38, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 103, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 34, 'ml_h': 103.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 150, 'drop_factor': 20, 'start': '22:00'},
   {'gtt_min': 67, 'ml_h': 200.0, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 2940, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 41, 'ml_h': 40.8, 'end': '14:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 31, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 97, 'ml_h': 96.8, 'end': '11:16', 'day_offset': 0})],
 [('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 20, 'start': '14:10'},
   {'gtt_min': 42, 'ml_h': 125.0, 'end': '22:10', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 15, 'start': '08:00'},
   {'gtt_min': 38, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 106, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 35, 'ml_h': 106.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 180, 'drop_factor': 20, 'start': '21:30'},
   {'gtt_min': 56, 'ml_h': 166.7, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 3000, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 40, 'ml_h': 40.0, 'end': '15:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 32, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 94, 'ml_h': 93.8, 'end': '11:17', 'day_offset': 0})],
 [('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 10, 'start': '14:15'},
   {'gtt_min': 21, 'ml_h': 125.0, 'end': '22:15', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 10, 'start': '08:00'},
   {'gtt_min': 25, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 109, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 36, 'ml_h': 109.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 210, 'drop_factor': 20, 'start': '21:00'},
   {'gtt_min': 48, 'ml_h': 142.9, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 3060, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 39, 'ml_h': 39.2, 'end': '16:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 33, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 91, 'ml_h': 90.9, 'end': '11:18', 'day_offset': 0})],
 [('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 15, 'start': '14:20'},
   {'gtt_min': 31, 'ml_h': 125.0, 'end': '22:20', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 20, 'start': '08:00'},
   {'gtt_min': 50, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 112, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 37, 'ml_h': 112.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 240, 'drop_factor': 20, 'start': '20:30'},
   {'gtt_min': 42, 'ml_h': 125.0, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 3120, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 38, 'ml_h': 38.5, 'end': '17:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 34, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 88, 'ml_h': 88.2, 'end': '11:19', 'day_offset': 0})],
 [('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 20, 'start': '14:25'},
   {'gtt_min': 42, 'ml_h': 125.0, 'end': '22:25', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 15, 'start': '08:00'},
   {'gtt_min': 38, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 115, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 38, 'ml_h': 115.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 270, 'drop_factor': 20, 'start': '20:00'},
   {'gtt_min': 37, 'ml_h': 111.1, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 3180, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 38, 'ml_h': 37.7, 'end': '18:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 35, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 86, 'ml_h': 85.7, 'end': '11:20', 'day_offset': 0})]]
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:
A calculated 37.5 gtt/min is counted as 37.

Input {volume_ml, duration_min, drop_factor (gtt/mL), start "HH:MM" 24-hour}. drops/min = volume*drop_factor/duration rounded half-up to a whole drop; mL/h = volume*60/duration rounded half-up to 0.1; end = start + duration on a 24-hour clock with day_offset = number of midnights crossed (ending exactly at 00:00 counts as the next day). Return {gtt_min, ml_h, end, day_offset}.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json
import math
from fractions import Fraction
N = 1
observations = []
def solve(x):
    gtt = Fraction(x['volume_ml'] * x['drop_factor'], x['duration_min'])
    gtt_i = math.floor(gtt + Fraction(1, 2))
    mlh = Fraction(x['volume_ml'], x['duration_min'])
    mlh_t = math.floor(mlh * 10 + Fraction(1, 2))
    h, m = map(int, x['start'].split(':'))
    total = h * 60 + m + x['duration_min']
    day = total // 1440
    total = total % 1440
    return {'gtt_min': gtt_i, 'ml_h': mlh_t / 10, 'end': '%02d:%02d' % (total // 60, total % 60), 'day_offset': day}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 15, 'start': '14:05'},
   {'gtt_min': 31, 'ml_h': 125.0, 'end': '22:05', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 15, 'start': '08:00'},
   {'gtt_min': 38, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 103, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 34, 'ml_h': 103.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 150, 'drop_factor': 20, 'start': '22:00'},
   {'gtt_min': 67, 'ml_h': 200.0, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 2940, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 41, 'ml_h': 40.8, 'end': '14:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 31, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 97, 'ml_h': 96.8, 'end': '11:16', 'day_offset': 0})],
 [('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 20, 'start': '14:10'},
   {'gtt_min': 42, 'ml_h': 125.0, 'end': '22:10', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 15, 'start': '08:00'},
   {'gtt_min': 38, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 106, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 35, 'ml_h': 106.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 180, 'drop_factor': 20, 'start': '21:30'},
   {'gtt_min': 56, 'ml_h': 166.7, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 3000, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 40, 'ml_h': 40.0, 'end': '15:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 32, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 94, 'ml_h': 93.8, 'end': '11:17', 'day_offset': 0})],
 [('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 10, 'start': '14:15'},
   {'gtt_min': 21, 'ml_h': 125.0, 'end': '22:15', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 10, 'start': '08:00'},
   {'gtt_min': 25, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 109, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 36, 'ml_h': 109.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 210, 'drop_factor': 20, 'start': '21:00'},
   {'gtt_min': 48, 'ml_h': 142.9, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 3060, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 39, 'ml_h': 39.2, 'end': '16:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 33, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 91, 'ml_h': 90.9, 'end': '11:18', 'day_offset': 0})],
 [('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 15, 'start': '14:20'},
   {'gtt_min': 31, 'ml_h': 125.0, 'end': '22:20', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 20, 'start': '08:00'},
   {'gtt_min': 50, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 112, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 37, 'ml_h': 112.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 240, 'drop_factor': 20, 'start': '20:30'},
   {'gtt_min': 42, 'ml_h': 125.0, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 3120, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 38, 'ml_h': 38.5, 'end': '17:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 34, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 88, 'ml_h': 88.2, 'end': '11:19', 'day_offset': 0})],
 [('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 20, 'start': '14:25'},
   {'gtt_min': 42, 'ml_h': 125.0, 'end': '22:25', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 15, 'start': '08:00'},
   {'gtt_min': 38, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 115, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 38, 'ml_h': 115.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 270, 'drop_factor': 20, 'start': '20:00'},
   {'gtt_min': 37, 'ml_h': 111.1, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 3180, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 38, 'ml_h': 37.7, 'end': '18:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 35, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 86, 'ml_h': 85.7, 'end': '11:20', 'day_offset': 0})]]
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
import math
from fractions import Fraction
N = 1
observations = []
def solve(x):
    gtt = Fraction(x['volume_ml'] * x['drop_factor'], x['duration_min'])
    gtt_i = math.floor(gtt + Fraction(1, 2))
    mlh = Fraction(x['volume_ml'], max(1, x['duration_min'] // 60))
    mlh_t = math.floor(mlh * 10 + Fraction(1, 2))
    h, m = map(int, x['start'].split(':'))
    total = h * 60 + m + x['duration_min']
    day = total // 1440
    total = total % 1440
    return {'gtt_min': gtt_i, 'ml_h': mlh_t / 10, 'end': '%02d:%02d' % (total // 60, total % 60), 'day_offset': day}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 15, 'start': '14:05'},
   {'gtt_min': 31, 'ml_h': 125.0, 'end': '22:05', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 15, 'start': '08:00'},
   {'gtt_min': 38, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 103, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 34, 'ml_h': 103.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 150, 'drop_factor': 20, 'start': '22:00'},
   {'gtt_min': 67, 'ml_h': 200.0, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 2940, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 41, 'ml_h': 40.8, 'end': '14:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 31, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 97, 'ml_h': 96.8, 'end': '11:16', 'day_offset': 0})],
 [('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 20, 'start': '14:10'},
   {'gtt_min': 42, 'ml_h': 125.0, 'end': '22:10', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 15, 'start': '08:00'},
   {'gtt_min': 38, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 106, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 35, 'ml_h': 106.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 180, 'drop_factor': 20, 'start': '21:30'},
   {'gtt_min': 56, 'ml_h': 166.7, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 3000, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 40, 'ml_h': 40.0, 'end': '15:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 32, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 94, 'ml_h': 93.8, 'end': '11:17', 'day_offset': 0})],
 [('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 10, 'start': '14:15'},
   {'gtt_min': 21, 'ml_h': 125.0, 'end': '22:15', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 10, 'start': '08:00'},
   {'gtt_min': 25, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 109, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 36, 'ml_h': 109.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 210, 'drop_factor': 20, 'start': '21:00'},
   {'gtt_min': 48, 'ml_h': 142.9, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 3060, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 39, 'ml_h': 39.2, 'end': '16:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 33, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 91, 'ml_h': 90.9, 'end': '11:18', 'day_offset': 0})],
 [('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 15, 'start': '14:20'},
   {'gtt_min': 31, 'ml_h': 125.0, 'end': '22:20', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 20, 'start': '08:00'},
   {'gtt_min': 50, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 112, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 37, 'ml_h': 112.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 240, 'drop_factor': 20, 'start': '20:30'},
   {'gtt_min': 42, 'ml_h': 125.0, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 3120, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 38, 'ml_h': 38.5, 'end': '17:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 34, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 88, 'ml_h': 88.2, 'end': '11:19', 'day_offset': 0})],
 [('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 20, 'start': '14:25'},
   {'gtt_min': 42, 'ml_h': 125.0, 'end': '22:25', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 15, 'start': '08:00'},
   {'gtt_min': 38, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 115, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 38, 'ml_h': 115.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 270, 'drop_factor': 20, 'start': '20:00'},
   {'gtt_min': 37, 'ml_h': 111.1, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 3180, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 38, 'ml_h': 37.7, 'end': '18:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 35, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 86, 'ml_h': 85.7, 'end': '11:20', 'day_offset': 0})]]
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:
The mL/h display shows mL per minute.

Input {volume_ml, duration_min, drop_factor (gtt/mL), start "HH:MM" 24-hour}. drops/min = volume*drop_factor/duration rounded half-up to a whole drop; mL/h = volume*60/duration rounded half-up to 0.1; end = start + duration on a 24-hour clock with day_offset = number of midnights crossed (ending exactly at 00:00 counts as the next day). Return {gtt_min, ml_h, end, day_offset}.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json
import math
from fractions import Fraction
N = 1
observations = []
def solve(x):
    gtt = Fraction(x['volume_ml'] * x['drop_factor'], x['duration_min'])
    gtt_i = math.floor(gtt + Fraction(1, 2))
    mlh = Fraction(x['volume_ml'] * 60, x['duration_min'])
    mlh_t = math.floor(mlh * 10 + Fraction(1, 2))
    h, m = map(int, x['start'].split(':'))
    total = h * 60 + m + x['duration_min']
    day = int(total > 1440)
    total = total % 1440
    return {'gtt_min': gtt_i, 'ml_h': mlh_t / 10, 'end': '%02d:%02d' % (total // 60, total % 60), 'day_offset': day}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 15, 'start': '14:05'},
   {'gtt_min': 31, 'ml_h': 125.0, 'end': '22:05', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 15, 'start': '08:00'},
   {'gtt_min': 38, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 103, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 34, 'ml_h': 103.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 150, 'drop_factor': 20, 'start': '22:00'},
   {'gtt_min': 67, 'ml_h': 200.0, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 2940, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 41, 'ml_h': 40.8, 'end': '14:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 31, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 97, 'ml_h': 96.8, 'end': '11:16', 'day_offset': 0})],
 [('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 20, 'start': '14:10'},
   {'gtt_min': 42, 'ml_h': 125.0, 'end': '22:10', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 15, 'start': '08:00'},
   {'gtt_min': 38, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 106, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 35, 'ml_h': 106.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 180, 'drop_factor': 20, 'start': '21:30'},
   {'gtt_min': 56, 'ml_h': 166.7, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 3000, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 40, 'ml_h': 40.0, 'end': '15:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 32, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 94, 'ml_h': 93.8, 'end': '11:17', 'day_offset': 0})],
 [('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 10, 'start': '14:15'},
   {'gtt_min': 21, 'ml_h': 125.0, 'end': '22:15', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 10, 'start': '08:00'},
   {'gtt_min': 25, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 109, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 36, 'ml_h': 109.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 210, 'drop_factor': 20, 'start': '21:00'},
   {'gtt_min': 48, 'ml_h': 142.9, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 3060, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 39, 'ml_h': 39.2, 'end': '16:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 33, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 91, 'ml_h': 90.9, 'end': '11:18', 'day_offset': 0})],
 [('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 15, 'start': '14:20'},
   {'gtt_min': 31, 'ml_h': 125.0, 'end': '22:20', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 20, 'start': '08:00'},
   {'gtt_min': 50, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 112, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 37, 'ml_h': 112.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 240, 'drop_factor': 20, 'start': '20:30'},
   {'gtt_min': 42, 'ml_h': 125.0, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 3120, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 38, 'ml_h': 38.5, 'end': '17:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 34, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 88, 'ml_h': 88.2, 'end': '11:19', 'day_offset': 0})],
 [('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 20, 'start': '14:25'},
   {'gtt_min': 42, 'ml_h': 125.0, 'end': '22:25', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 15, 'start': '08:00'},
   {'gtt_min': 38, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 115, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 38, 'ml_h': 115.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 270, 'drop_factor': 20, 'start': '20:00'},
   {'gtt_min': 37, 'ml_h': 111.1, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 3180, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 38, 'ml_h': 37.7, 'end': '18:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 35, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 86, 'ml_h': 85.7, 'end': '11:20', 'day_offset': 0})]]
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
import math
from fractions import Fraction
N = 1
observations = []
def solve(x):
    gtt = Fraction(x['volume_ml'] * x['drop_factor'], x['duration_min'])
    gtt_i = math.floor(gtt + Fraction(1, 2))
    mlh = Fraction(x['volume_ml'] * 60, x['duration_min'])
    mlh_t = math.floor(mlh * 10 + Fraction(1, 2))
    h, m = map(int, x['start'].split(':'))
    total = h * 60 + m + x['duration_min']
    day = int(total >= 1440)
    total = total % 1440
    return {'gtt_min': gtt_i, 'ml_h': mlh_t / 10, 'end': '%02d:%02d' % (total // 60, total % 60), 'day_offset': day}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 15, 'start': '14:05'},
   {'gtt_min': 31, 'ml_h': 125.0, 'end': '22:05', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 15, 'start': '08:00'},
   {'gtt_min': 38, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 103, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 34, 'ml_h': 103.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 150, 'drop_factor': 20, 'start': '22:00'},
   {'gtt_min': 67, 'ml_h': 200.0, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 2940, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 41, 'ml_h': 40.8, 'end': '14:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 31, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 97, 'ml_h': 96.8, 'end': '11:16', 'day_offset': 0})],
 [('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 20, 'start': '14:10'},
   {'gtt_min': 42, 'ml_h': 125.0, 'end': '22:10', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 15, 'start': '08:00'},
   {'gtt_min': 38, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 106, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 35, 'ml_h': 106.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 180, 'drop_factor': 20, 'start': '21:30'},
   {'gtt_min': 56, 'ml_h': 166.7, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 3000, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 40, 'ml_h': 40.0, 'end': '15:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 32, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 94, 'ml_h': 93.8, 'end': '11:17', 'day_offset': 0})],
 [('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 10, 'start': '14:15'},
   {'gtt_min': 21, 'ml_h': 125.0, 'end': '22:15', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 10, 'start': '08:00'},
   {'gtt_min': 25, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 109, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 36, 'ml_h': 109.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 210, 'drop_factor': 20, 'start': '21:00'},
   {'gtt_min': 48, 'ml_h': 142.9, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 3060, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 39, 'ml_h': 39.2, 'end': '16:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 33, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 91, 'ml_h': 90.9, 'end': '11:18', 'day_offset': 0})],
 [('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 15, 'start': '14:20'},
   {'gtt_min': 31, 'ml_h': 125.0, 'end': '22:20', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 20, 'start': '08:00'},
   {'gtt_min': 50, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 112, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 37, 'ml_h': 112.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 240, 'drop_factor': 20, 'start': '20:30'},
   {'gtt_min': 42, 'ml_h': 125.0, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 3120, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 38, 'ml_h': 38.5, 'end': '17:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 34, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 88, 'ml_h': 88.2, 'end': '11:19', 'day_offset': 0})],
 [('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 20, 'start': '14:25'},
   {'gtt_min': 42, 'ml_h': 125.0, 'end': '22:25', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 15, 'start': '08:00'},
   {'gtt_min': 38, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 115, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 38, 'ml_h': 115.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 270, 'drop_factor': 20, 'start': '20:00'},
   {'gtt_min': 37, 'ml_h': 111.1, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 3180, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 38, 'ml_h': 37.7, 'end': '18:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 35, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 86, 'ml_h': 85.7, 'end': '11:20', 'day_offset': 0})]]
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:
An infusion finishing exactly at 00:00 is reported as ending today.

Input {volume_ml, duration_min, drop_factor (gtt/mL), start "HH:MM" 24-hour}. drops/min = volume*drop_factor/duration rounded half-up to a whole drop; mL/h = volume*60/duration rounded half-up to 0.1; end = start + duration on a 24-hour clock with day_offset = number of midnights crossed (ending exactly at 00:00 counts as the next day). Return {gtt_min, ml_h, end, day_offset}.

split: open-access


broken_source:
"""Failure Map reference implementation. Python standard library only."""
import json
import math
from fractions import Fraction
N = 1
observations = []
def solve(x):
    gtt = Fraction(x['volume_ml'] * x['drop_factor'], x['duration_min'])
    gtt_i = math.floor(gtt + Fraction(1, 2))
    mlh = Fraction(x['volume_ml'] * 60, x['duration_min'])
    mlh_t = math.floor(mlh * 10 + Fraction(1, 2))
    h, m = map(int, x['start'].split(':'))
    total = h * 100 + m + x['duration_min']
    day = total // 1440
    total = total % 1440
    return {'gtt_min': gtt_i, 'ml_h': mlh_t / 10, 'end': '%02d:%02d' % (total // 60, total % 60), 'day_offset': day}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 15, 'start': '14:05'},
   {'gtt_min': 31, 'ml_h': 125.0, 'end': '22:05', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 15, 'start': '08:00'},
   {'gtt_min': 38, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 103, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 34, 'ml_h': 103.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 150, 'drop_factor': 20, 'start': '22:00'},
   {'gtt_min': 67, 'ml_h': 200.0, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 2940, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 41, 'ml_h': 40.8, 'end': '14:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 31, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 97, 'ml_h': 96.8, 'end': '11:16', 'day_offset': 0})],
 [('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 20, 'start': '14:10'},
   {'gtt_min': 42, 'ml_h': 125.0, 'end': '22:10', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 15, 'start': '08:00'},
   {'gtt_min': 38, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 106, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 35, 'ml_h': 106.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 180, 'drop_factor': 20, 'start': '21:30'},
   {'gtt_min': 56, 'ml_h': 166.7, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 3000, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 40, 'ml_h': 40.0, 'end': '15:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 32, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 94, 'ml_h': 93.8, 'end': '11:17', 'day_offset': 0})],
 [('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 10, 'start': '14:15'},
   {'gtt_min': 21, 'ml_h': 125.0, 'end': '22:15', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 10, 'start': '08:00'},
   {'gtt_min': 25, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 109, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 36, 'ml_h': 109.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 210, 'drop_factor': 20, 'start': '21:00'},
   {'gtt_min': 48, 'ml_h': 142.9, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 3060, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 39, 'ml_h': 39.2, 'end': '16:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 33, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 91, 'ml_h': 90.9, 'end': '11:18', 'day_offset': 0})],
 [('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 15, 'start': '14:20'},
   {'gtt_min': 31, 'ml_h': 125.0, 'end': '22:20', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 20, 'start': '08:00'},
   {'gtt_min': 50, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 112, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 37, 'ml_h': 112.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 240, 'drop_factor': 20, 'start': '20:30'},
   {'gtt_min': 42, 'ml_h': 125.0, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 3120, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 38, 'ml_h': 38.5, 'end': '17:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 34, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 88, 'ml_h': 88.2, 'end': '11:19', 'day_offset': 0})],
 [('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 20, 'start': '14:25'},
   {'gtt_min': 42, 'ml_h': 125.0, 'end': '22:25', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 15, 'start': '08:00'},
   {'gtt_min': 38, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 115, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 38, 'ml_h': 115.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 270, 'drop_factor': 20, 'start': '20:00'},
   {'gtt_min': 37, 'ml_h': 111.1, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 3180, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 38, 'ml_h': 37.7, 'end': '18:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 35, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 86, 'ml_h': 85.7, 'end': '11:20', 'day_offset': 0})]]
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
import math
from fractions import Fraction
N = 1
observations = []
def solve(x):
    gtt = Fraction(x['volume_ml'] * x['drop_factor'], x['duration_min'])
    gtt_i = math.floor(gtt + Fraction(1, 2))
    mlh = Fraction(x['volume_ml'] * 60, x['duration_min'])
    mlh_t = math.floor(mlh * 10 + Fraction(1, 2))
    h, m = map(int, x['start'].split(':'))
    total = (h % 12) * 60 + m + x['duration_min']
    day = total // 1440
    total = total % 1440
    return {'gtt_min': gtt_i, 'ml_h': mlh_t / 10, 'end': '%02d:%02d' % (total // 60, total % 60), 'day_offset': day}
def check(label, actual, expected):
    observations.append({"check": label, "actual": actual, "expected": expected, "passed": actual == expected})
fixtures = [[('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 15, 'start': '14:05'},
   {'gtt_min': 31, 'ml_h': 125.0, 'end': '22:05', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 15, 'start': '08:00'},
   {'gtt_min': 38, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 103, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 34, 'ml_h': 103.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 150, 'drop_factor': 20, 'start': '22:00'},
   {'gtt_min': 67, 'ml_h': 200.0, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 2940, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 41, 'ml_h': 40.8, 'end': '14:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 31, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 97, 'ml_h': 96.8, 'end': '11:16', 'day_offset': 0})],
 [('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 20, 'start': '14:10'},
   {'gtt_min': 42, 'ml_h': 125.0, 'end': '22:10', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 15, 'start': '08:00'},
   {'gtt_min': 38, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 106, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 35, 'ml_h': 106.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 180, 'drop_factor': 20, 'start': '21:30'},
   {'gtt_min': 56, 'ml_h': 166.7, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 3000, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 40, 'ml_h': 40.0, 'end': '15:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 32, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 94, 'ml_h': 93.8, 'end': '11:17', 'day_offset': 0})],
 [('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 10, 'start': '14:15'},
   {'gtt_min': 21, 'ml_h': 125.0, 'end': '22:15', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 10, 'start': '08:00'},
   {'gtt_min': 25, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 109, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 36, 'ml_h': 109.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 210, 'drop_factor': 20, 'start': '21:00'},
   {'gtt_min': 48, 'ml_h': 142.9, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 3060, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 39, 'ml_h': 39.2, 'end': '16:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 33, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 91, 'ml_h': 90.9, 'end': '11:18', 'day_offset': 0})],
 [('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 15, 'start': '14:20'},
   {'gtt_min': 31, 'ml_h': 125.0, 'end': '22:20', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 20, 'start': '08:00'},
   {'gtt_min': 50, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 112, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 37, 'ml_h': 112.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 240, 'drop_factor': 20, 'start': '20:30'},
   {'gtt_min': 42, 'ml_h': 125.0, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 3120, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 38, 'ml_h': 38.5, 'end': '17:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 34, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 88, 'ml_h': 88.2, 'end': '11:19', 'day_offset': 0})],
 [('macrodrip set afternoon start',
   {'volume_ml': 1000, 'duration_min': 480, 'drop_factor': 20, 'start': '14:25'},
   {'gtt_min': 42, 'ml_h': 125.0, 'end': '22:25', 'day_offset': 0}),
  ('drop rate rounds half up',
   {'volume_ml': 250, 'duration_min': 100, 'drop_factor': 15, 'start': '08:00'},
   {'gtt_min': 38, 'ml_h': 150.0, 'end': '09:40', 'day_offset': 0}),
  ('fractional drop rate rounds down',
   {'volume_ml': 115, 'duration_min': 60, 'drop_factor': 20, 'start': '09:30'},
   {'gtt_min': 38, 'ml_h': 115.0, 'end': '10:30', 'day_offset': 0}),
  ('ends exactly at midnight',
   {'volume_ml': 500, 'duration_min': 270, 'drop_factor': 20, 'start': '20:00'},
   {'gtt_min': 37, 'ml_h': 111.1, 'end': '00:30', 'day_offset': 1}),
  ('multi-day infusion',
   {'volume_ml': 2000, 'duration_min': 3180, 'drop_factor': 60, 'start': '13:15'},
   {'gtt_min': 38, 'ml_h': 37.7, 'end': '18:15', 'day_offset': 2}),
  ('short microdrip before noon',
   {'volume_ml': 50, 'duration_min': 35, 'drop_factor': 60, 'start': '10:45'},
   {'gtt_min': 86, 'ml_h': 85.7, 'end': '11:20', 'day_offset': 0})]]
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:
End times are wildly wrong for afternoon starts.

Input {volume_ml, duration_min, drop_factor (gtt/mL), start "HH:MM" 24-hour}. drops/min = volume*drop_factor/duration rounded half-up to a whole drop; mL/h = volume*60/duration rounded half-up to 0.1; end = start + duration on a 24-hour clock with day_offset = number of midnights crossed (ending exactly at 00:00 counts as the next day). Return {gtt_min, ml_h, end, day_offset}.

split: open-access