Technical guide The maths, worked through Live results Pitch deck GitHub

Health-a-thon 2026 · Cancer track · Meeting prep

How RAD-SMART works, in plain language

Every moving part, why we chose it, what it does in the prototype today, and what to say when someone asks. Read the one-minute version first; open the question list at the bottom before a meeting. The sub-page works the maths through with small numbers you can play with.

Start here

The whole idea in one minute

A radiotherapy machine is a shared, expensive room that must be used in the right order. Today the day is booked by hand using appointment times. We plan it by machine-minutes instead, using four steps.

Say it simply “Today, patients are booked at clock times, but sessions don't take the same time, so the queue builds up and the evening runs late. RAD-SMART predicts how long each session will take, builds the day so that every department rule is guaranteed, tests that day against thousands of things going wrong, and tells staff and patients in their own language when something changes. People approve; the software proposes.”
1 · Predict How many minutes willeach session take? Machine learning(gradient boosting) P50 · P80 · expected 2 · Optimise Build the day so everyhard rule holds. Mathematical optimisation(MILP / CP-SAT) + independent checker 3 · Simulate What if patients are late,or the machine breaks? Monte Carlo digital twin(300 simulated days) waits · load · re-plans 4 · Explain Tell people why, intheir language. Language AI (Sarvam)via LangGraph talks · never decides Doctor or technologist approves every plan and every live change · one-tap override · manual fallback

Not a black box

The only “prediction” is how long a machine session lasts. The plan itself comes from an optimiser that follows written rules, so every placement has a reason you can read.

Rules are guaranteed

“New starts finish by 17:00” is a constraint the solver cannot break, and a second program re-checks it. A language model could not promise that.

Built in layers

The optimiser works alone from week one with the department's average durations. Machine learning, simulation and the copilot each add value and can be switched off without breaking the rest.

A day in the life of the system

Evening before Standing slots + new starts →check rules → twin test → approve →message each patient their time “Please come at 09:41” During the day Event (fault, late patient, urgentstart) → freeze what started →re-solve the rest → approve → update “New time 11:25. No need to come earlier.” After the day Real arrival, room-entry and exittimes are logged → durations andarrival habits are re-learned weekly The plan gets more accurate each week

Big picture

Architecture: what talks to what

Think of three layers. Data comes in on the left, the engine in the middle makes and tests the plan, and results go out to people on the right. The language model sits beside the engine, not inside it.

INPUTSENGINE (Python · a CARE plugin · PostgreSQL)OUTPUTS Patient listtechnique, fraction no., flags Department rulesconfiguration, not code Live eventscheck-in, room entry, fault Patient repliestext or voice, any language Duration predictorscikit-learn OptimiserHiGHS now · CP-SAT later Independent checkerre-verifies the hard rules Live re-plannersame solver, fewer changes Digital twinNumPy Monte Carlo Capacity forecastnew-start advisor Shared resourcesABC, breast board, CT sim Audit logappend-only, versioned CARE pagesbutton on the visit page Queue boardTV in the waiting area Patient messagesWhatsApp · SMS · voice Approval stepdoctor · technologist Sarvam AI layer · Translate, Bulbul v3 voice, Sarvam-105B Translates and voices approved patient messages; explains a plan in plain words from the engine's reasons. Every output is checked for times. Cannot write a schedule, send a message on its own, or see names and phone numbers. One Docker imageLive on Microsoft Azure; thesame image on a hospital server
Language and frameworkPython · Django · ReactPython for the engine and the plugin's API inside CARE; React and TypeScript for the pages.
StoragePostgreSQLCARE's own database: courses, plans, approvals, recorded times and messages. Managed on Azure, with daily backups.
DeliveryDocker · Microsoft AzureOne image, live on Azure Container Apps today; the same image runs on a hospital server for the pilot.

Concept by concept

The eight modules

Each card has the same shape: what it does, how it works without jargon, what runs in the prototype today versus the build, and the question most likely to come up.

1

Duration predictor: “how long will this session take?”

now: scikit-learn HistGradientBoostingfallback: lookup table of averages
Say it simplyAn experienced RTT knows a wheelchair patient, a first fraction or an SBRT takes longer. The model learns the same thing from past sessions and gives a number for every patient, plus how sure it is.

How it works

It looks at ten facts about the session: technique, body site, whether it is the first fraction, mobility, imaging type, age, elderly, inpatient, machine and number of accessories. It learns from past sessions by building many small decision trees, each one fixing the mistakes of the previous ones. That is gradient boosting.

It is trained three times, to give three answers: the expected minutes, the median (P50) and the P80, the length that 8 sessions in 10 stay under. The training target for P50 and P80 is a quantile loss, which punishes under- and over-estimating unequally (worked example on the maths page).

Why it matters

Session lengths are skewed: a few run long. If you reserve the median, the day is under-booked and queues build. So the plan reserves the expected minutes, and P80 is used to judge risk and to size buffers.

Prototype result (held-out sessions)

  • Average error 2.15 min against 2.62 for a table of averages
  • 62% of predictions within 2 min (51% for the table)
  • P80 covers 78.6% of sessions, close to the 80% it promises
Be honest about thisThe prototype is trained on synthetic sessions, because the department does not yet record room entry and exit. The accuracy above shows the method works; the real figure comes from the first 2 weeks of logging in the pilot. Until then the system plans from the department's own table of estimates.
If they ask“Is this clinical AI?” No. It predicts how long the machine is occupied, never anything about the patient's disease, dose or outcome.
2

Optimiser: “build a day that obeys every rule”

now: SciPy MILP, HiGHS solverbuild: Google OR-Tools CP-SAT
Say it simplyIt is a timetable puzzle with strict rules and many wishes. We write the rules as maths, tell the solver what “a good day” means as a single score, and it searches for the best-scoring timetable that breaks no rule, then proves how close to the best possible it is.

How it works

For every patient, machine and 2-minute start time we make a yes/no variable: x[p, m, s] = 1 means “patient p starts on machine m at time s”. Rules become inequalities on those variables, for example “each patient starts exactly once” and “no two sessions overlap on a machine”. Each choice also has a cost (how far from the patient's usual time, how late the day ends, and so on). The solver finds the cheapest allowed choice. This is a mixed-integer linear program (MILP).

A single huge model is slow, so we solve in two stages (diagram below).

What you can quote

  • 87 patients: about 4,700 yes/no variables and 1,660 constraints
  • Solved in 7 s (ML durations) to 31 s (averages) on a laptop
  • The solver proves the plan is within 0.03% of the best possible score under our cost definition (0.13% with averages)
  • No patient left unplanned; if someone cannot fit, they are flagged for a human, never silently dropped
Stage 1 · Load levelling Put every patient into a 15-minutebucket so that the minutes in nobucket exceed what the machinecan deliver. Fast. Decides roughly when. Stage 2a · The “big rocks” Place complex cases, new startsand hospice (MHRC) patients exactly,near their bucket, then lock them. Like packing big rocks into a jarbefore the sand: the protectedslots are never squeezed out. Stage 2b · Everyone else Place the rest at 2-minuteprecision, each searched only within±50 min of their bucket. Small search window = fast,still proven near-optimal.
Standing slots (24 Oct)The department keeps each patient's time until the course ends. So when the doctor approves a course, a slot allocator picks a new-start slot before 17:00 and one standing slot for every later fraction: a time free on every treatment date that keeps every hard rule and leaves 150 minutes before 17:00 for future new starts. Most later fractions go to the evening. A patient who asks for another time gets the nearest one that keeps every rule, from a chosen date, once someone approves. The day optimiser above handles breakdowns and full re-plans.
A better time as slots free up (27 Oct)Patients ask for a part of the day (morning, afternoon or evening), not an exact minute; a stated part replaces the “older patients earlier” wish. A new patient often starts wherever there is room. Whenever a slot is freed (a course ends, a patient moves), RAD-SMART looks for each patient outside their part of the day: a time inside it, on the same machine, free on every remaining date from the next treatment day, keeping every hard rule and the 150-minute new-start reserve. Offers go first to whoever gains most (the patient's preference weight × fractions left × minutes outside), and each offered slot is held, so two patients are never offered the same one. It becomes an offer to staff (“a morning slot is free from Wednesday: ask the patient”), never an automatic move. A declined offer is not repeated unless the patient's preference changes; an offer whose slot is taken is withdrawn; nobody with 3 or fewer fractions left, or on a twice-daily course, is asked to move.
If they ask“Why not a normal scheduling rule?” Rules like “fill the first free slot” cannot balance a dozen competing rules at once, cannot show how good the result is, and cannot be re-configured without programming. “Will it scale?” The model maps one-to-one onto CP-SAT interval variables (NoOverlap, Cumulative), which removes the two-stage split at larger sizes.
3

Independent checker: “don't trust, verify”

now: check_plan(), written separately from the solver
Say it simplyA second program, written separately, reads the finished plan and ticks the eight hard rules one by one. A plan that fails is never published. For the solver and the checker to both be wrong in the same way, they would have to share the same bug, and they share no code.

The eight rules it re-checks

  • New starts finish by 17:00
  • Complex cases inside the 10:00–17:00 senior-staff window
  • MHRC patients inside 16:00–16:55 (back on the 17:00 bus)
  • Public-transport patients finish by 21:00
  • Time windows set by the doctor (e.g. sedation, chemotherapy)
  • Blood-irradiation block 13:30–14:00 stays free
  • One patient at a time on each machine
  • Accessories (ABC, breast board) never double-booked with the CT simulator

Result

On the 87-patient prototype day: 8 rules checked, 87 sessions checked, 0 violations, 0 unplanned, for both the average-duration plan and the machine-learning plan. On days built from standing slots it adds a ninth rule, everyone in their standing slot: 0 violations over 20 days of the 12-week test.

The solver also keeps a safety buffer: it aims to finish 25 minutes before a hard deadline so ordinary delays do not break it.

4

Live re-planning: “the day went wrong, now what?”

now: the same MILP with a different cost
Say it simplyWhen the machine stops, we freeze everything already treated or under way and re-solve the rest. The trick is what we count as bad: a patient already sitting in the waiting room waiting longer is far worse than telling someone still at home a new time.

How it works

  • Freeze sessions that have started (the locked input).
  • Re-cost the rest: moving someone not yet here costs 3 points per 10 min; making someone already here wait costs 20 points per 10 min, and 50 more beyond an hour. So waiting is about 7 times as costly as moving, and long waits much more.
  • Message only when worth it: only patients whose time is at least 45 min away and moves by at least 5 min.
  • Never ask anyone to come earlier than they were told unless they can be reached in time.
  • Propose, don't impose: the approver sees who is affected, by how much, and any proposed deferral.

Department downtime rules (built in)

  • Breakdowns last 15 min to 48 h; the technologist enters the expected downtime
  • Up to 60 min: nobody sent home; everyone treated today, with up to 60 min of overtime
  • Over 60 min: only as many patients sent back as the downtime needs, those not yet travelling first; never a gap-sensitive course or a hospice patient without the oncologist; the fraction is added at the end of the course
  • New starts wait until the machine works, or move to the next working day
  • Patients not yet reported are told to postpone travel
  • A technologist or doctor approves

Prototype result (median wait, minutes)

FaultNo re-planRe-planned
45 min5337
150 min10439
Early and late patients (27 Oct)Patients rarely come at exactly their time, and the department does not keep a machine idle waiting: it treats whoever is ready. So the day board keeps the plan as the order, not a timetable. Each machine shows who is in the room, Call next (the first patient in plan order who has arrived; from 16:00 hospice patients first, for the 17:00 bus) and how far it runs behind (the longest wait past their time among those here). A patient past their time and not here shows Not here yet · N min past; one late in 3 of their last 5 visits shows Often late. A technologist can take anyone in at any time: RAD-SMART asks why in one tap (came early, next patient not here, clinical reason), shows what to check (bladder preparation, senior staff before 10:00, an ABC unit or breast board in use elsewhere), records out of turn and whom they went ahead of, and never blocks. Nobody else's time changes, so no messages are needed; a breakdown is still a re-plan.
5

Digital twin: “rehearse the day 300 times”

now: NumPy Monte Carlo, discrete-event
Say it simplyA plan always looks good on paper because every session ends on time. The twin plays the plan through a virtual day with real-life randomness: sessions overrun, patients come early or late, someone does not show, an urgent patient appears. It does this 300 times and reports the spread, not a single lucky answer.

What is random in each simulated day

  • Actual session length (each technique has its own spread)
  • When each patient arrives, drawn from the department's recorded arrival habits
  • No-shows (2%), urgent same-day starts (average 1.2 a day, at most 3), imaging holds (2% of sessions)
  • Whether a patient reads an update message (85% do)
  • Machine faults, in the downtime tests

The key trick: common random numbers

To compare today's practice with RAD-SMART fairly, both are played with the same random draws: the same patient is equally early and has the same session length under both. So any difference comes from the plan, not luck. The maths page lets you see how much this shrinks the noise.

Twin inputs come from aggregates of the department's records: how appointment times spread over the day, and how early or late people arrive at each hour.

6

Capacity forecast and new-start advisor

now: rolling-horizon admission
Say it simplyEvery patient on treatment has a known number of sessions left, so the load on the machine for the next weeks is already largely known. We add that up per day, subtract the minutes held for urgent cases and TBI, and recommend how many new patients can start each day without any future day going over capacity.

How it works

  • Committed minutes on day k = sum of the predicted minutes of every patient who still has sessions on day k
  • Capacity = available minutes × 92% target use − urgent holds (− 180 min on a TBI day)
  • Admit each waiting patient on the earliest day (decided about two days ahead) where the next 15 days all stay under capacity, choosing the machine with most free minutes

It balances minutes, not head-counts: ten complex patients are not the same as ten routine ones.

Prototype result (two machines, three weeks, one TBI course)

Head-count splitRAD-SMART
Peak planned load, Versa HD154%98%
Days over capacity100
Peak load in TBI week111%98%
7

Shared resources: the breast board, the ABC unit and the CT scanner

now: constraints inside the optimiser and the checker
Say it simplyThere is one breast board and one ABC breathing-control unit, and the CT simulator uses them too. So two breast patients cannot be on two machines at once, and a CT booking blocks the accessory. We treat each accessory like a small extra machine with one seat.

How it works

  • In stage 1, accessory minutes in each 15-minute bucket cannot exceed units owned minus what the CT simulator holds
  • In stage 2, no overlap in time, with 2 minutes added each side for the transfer between rooms
  • Some windows are reserved for the linac (for example before CT opens at 11:00)

Why it matters

Today these clashes are discovered at the machine, when the accessory is not there. In the model they are impossible, and the checker confirms none was missed.

8

Copilot and multilingual messages (Sarvam AI)

build: Sarvam-105B · Bulbul v3 · Saaras v3 · Translate · Vision OCRLangGraph
Say it simplyThe language model is the interpreter, not the planner. It explains why a patient was moved, turns “from Monday the blood slot is 2 to 2:30 on Fridays” into a rule for a human to approve, and sends patients short messages in Kannada, Malayalam, Hindi or English. It is not allowed to make or change a schedule by itself.

What each part does

Sarvam-105BReasoning and tool calling; Indian-language model
Saaras v3Speech to text (patient voice replies, code-mixed speech)
Bulbul v3Text to speech (automated voice calls)
Translate / MayuraMessage translation
VisionReads paper registers (document OCR)
LangGraphThe framework that wires the model to a fixed list of allowed tools as a controlled graph of steps

Guardrails

  • Allow-listed tools only: read plans, run the forecast or twin, propose a rule change. No write access to schedules, no direct sending.
  • No identifiers: the model sees pseudonymous IDs; names and phone numbers are added on the hospital server at send time.
  • Fixed templates: each translated template is approved once by a native speaker; the model only fills in times.
  • Safe if it fails: with no model or internet, the console shows raw reason codes and templates still go out. Scheduling never depends on the model.
  • No clinical content: any health question gets “please speak to your doctor or nurse”.
Staff orpatient CopilotSarvam-105B · LangGraphpseudonymous IDs only Allowed toolsread plan · reason codes · forecast · twin · propose rule Not allowedwrite schedule · send message · see names Human approvesthen the engine acts
If they ask“What about Tulu?” Sarvam's current speech models do not cover Tulu. Tulu speakers get the text in Kannada script plus a short voice note recorded once by Tulu-speaking staff, with the time spliced from recorded number clips. Spoken Tulu replies reach the console as audio for a staff member to hear. If a provider adds Tulu, generated speech replaces the recordings.

The most useful idea to understand

Hard rules and soft wishes

Everything the department told us becomes one of two kinds of statement. Knowing which is which answers most “but what if…” questions.

Hard rule

Must never be broken

A plan that breaks one does not exist as far as the solver is concerned. If everyone cannot be placed, the answer is “these patients need a human decision”, never “we bent a rule”.

  • New starts end by 17:00
  • Complex cases only with senior staff, 10:00–17:00, one team at a time
  • MHRC patients in their 16:00–17:00 slots
  • Public-transport patients home by 21:00
  • Blood-irradiation block kept free
  • One patient per machine; accessories not double-booked
  • A patient keeps one standing slot for the whole course
Soft wish

Traded off with a price

Each wish has a weight (cost per 10 minutes away from ideal). The department can change the weights; the solver finds the cheapest overall balance.

  • Stay near the patient's usual time (free within 30 min; paying patients 15 min, weighted ×4)
  • Inside the patient's preferred part of the day: morning 08:30–12:00, afternoon 12:00–17:00 or evening 17:00–21:00 (weight 2)
  • Otherwise, older patients before 13:00
  • Flexible patients (inpatients, dormitory, nearby) take the late evening
  • Others finish by 21:00 where possible; the day ends as early as it can
  • Complex cases in the 12:00–13:30 protected block
  • Minimise overtime (weight 6)
If they ask“Who decides the weights?” The department does. They live in a configuration file today and in plain-language sliders (“Rule Studio”) in the build. We report waits by group, so a weight that makes any group worse off is visible.

Evidence

How we tested it, and what the numbers mean

We could not use real patients, so the prototype uses synthetic patients under the department's real rules and booking and arrival habits taken from aggregates of its anonymised records. We compare a simulated RAD-SMART day with the department's recorded busiest days.

90th-percentile wait130 → 76 minbusiest recorded days vs RAD-SMART
More than 1 h late27% → 6%of sessions
Within ±15 min30% → 53%of appointment time
After 19:00, median wait66 → 36 minevening build-up

With and without RAD-SMART, on both datasets

DatasetP90 wait, without → withMore than 1 h late
Original: the department's 55 recorded days, re-planned in the twin108.6 → 70.4 min (−35%)22% → 6%
Simulated: 12 weeks of synthetic courses with standing slots82 → 49 min (−40%)19% → 4%

The price over 12 weeks: the last patient finishes about 00:07 instead of 21:55; one new start in five begins a little later (0.4 working days); a time the patient asks for is kept within 15 minutes 4% of the time, against 31% today. Details: docs/RAD-SMART_Impact_Analysis.pdf.

The records behind the calibration

The department's anonymised arrival and treatment records: 3,137 patient-days, 263 patients, 15 Oct–31 Dec 2024, Versa HD. Entries stored as 12:00 AM were treated as missing (416 removed) and 2,685 waits were usable. Median wait 34 min, 90th percentile 109 min. Only aggregates are used or published; no row-level data is in the repository.

Reading the numbers

P90 (90th percentile) means 9 patients in 10 wait less than this. It is our headline because the long waits are what patients and staff feel, and the average hides them.

Why the median does not fall (38 vs 36 min): by design, patients report 20 minutes before their machine slot, or 45 for the bladder-filling protocol. That built-in early arrival is the floor on the median. What falls is the unpredictable tail.

Known limitations. Say these before they are found
  • Synthetic patients. Session lengths and the patient mix are our estimates; the pilot replaces them with measured values.
  • The twin is not perfect. Over all 55 recorded days it gives a P90 of 106 against 109 min, but it under-predicts the longest waits on quieter days (82 vs 98 min on 45–59-patient days), so our tail may be a little optimistic. On busy days it over-predicts today's waits, so today's figures are quoted from the records, not from the twin.
  • Standing slots have a price. They keep each patient's time for the whole course, but over 12 weeks the evening runs about two hours later, one new start in five waits a little, and requested times are kept less often. The 12-week test also starts from an empty machine; the pilot starts from today's patients.
  • Behaviour is assumed. The benefit assumes patients stop arriving very early once times are kept, and that 85% act on updates. With today's habits the P90 would be 110 min, not 76. The pilot measures both.
  • One machine simulated live. Two-machine work so far covers the forecast; simultaneous live sequencing is in the build.

So the pilot target is conservative: P90 at least 25% lower than the records' 109 min, against 35% on the department's own days re-planned and 40% over 12 synthetic weeks.

Design choices

Why this design and not the alternatives

We scored five ways of building it on safety, impact, adaptivity, feasibility, explainability, ease of use and reuse.

ApproachGood atWhy we did not choose it aloneScore /5
A · Fixed slot templatesSimple, transparentCannot absorb variation or recover from disruption3.10
B · LLM writes the scheduleFlexible, easy to talk toCannot guarantee hard rules, weak arithmetic, different answers each time, hard to audit2.60
C · Static optimisationGuarantees rulesNo learning, no live recovery, no way to talk to people3.60
D · Deep reinforcement learningAdaptive in principleNeeds huge data, black box, no rule guarantee, hard to reconfigure2.45
E · Hybrid (chosen)Each technique does what it is best atMore parts, so we build in layers4.85
The one-line answerUse machine learning where there is data to learn from, optimisation where rules must hold, simulation where you need to rehearse, and language models only where you need to talk. Each of the four can be switched off without breaking the others.

The published literature supports each piece separately: MILP scheduling in radiotherapy centres, prediction of treatment durations, and recent attempts at reinforcement learning and LLM schedulers. As far as we found, no system combines all four in a light-integration package for this setting.

Trust

Safety, data and deployment

Human in control

  • Every output is a proposal: plans, re-plans, deferrals, new-start advice, rule changes
  • The doctor approves each course, its machine and its slots; a technologist or doctor approves the day and every breakdown response
  • One-tap override with a reason; overrides are reviewed weekly
  • Independent checker before anything is published
  • Append-only audit log: who, when, which rule and model version, every message
  • Printed fallback list and a one-click return to manual mode

Data and privacy

  • Operational data only: technique, fraction number, flags, times. No diagnoses, doses, images or clinical notes
  • Pseudonymous patient tokens; names and phones stay on the hospital server
  • Roles checked on the server at every step; HTTPS; daily database backups; hosted on the hospital's server or in an Indian cloud region for the pilot
  • Consent before WhatsApp; SMS through registered templates
  • Designed for India's DPDP Rules 2025 (main obligations from May 2027)

Integration path

  • Now: runs inside CARE (Open Healthcare Network) as a backend and a frontend plugin, with a RADSMART button on the visit page; the same pattern fits the hospital EMR
  • Pilot start: QR check-in and tablet taps for arrival, room entry and exit
  • Phase 2: read-only HL7 v2 / FHIR R4 feed from the oncology information system (MOSAIQ / ARIA)
  • It never writes into the treatment record

Performance targets

  • Evening plan for 90 patients in under 60 s
  • Live re-plan in under 30 s
  • Console responses under 1 s
  • Keeps working on the hospital LAN without internet; messages queue and fall back to SMS or voice
If they ask“Is it a medical device?” Its intended purpose is operational scheduling, so we expect it falls outside software-as-a-medical-device classification. We will confirm that with the institution's regulatory team before the pilot.

Meeting prep

Questions you may get, with answers you can say

Open a question to see a one-sentence answer first, then the detail behind it.

Is it running anywhere, or only on a laptop?

It is live on Microsoft Azure, and anyone can try it.

The whole application is one Docker image: CARE's own production build with both RAD-SMART plugins, nginx and gunicorn. It runs on Azure Container Apps over HTTPS, with Azure Database for PostgreSQL (daily backups), Azure Container Registry and a daily job. One script builds, migrates and deploys it. The public server uses synthetic patients and one-click roles.

Is it production-ready?

The software and its deployment are; using it with real patients is the pilot, after the hospital's approvals.

The pilot runs the same image with demonstration mode off: staff sign in with their own CARE accounts, the data is kept, and it runs on the hospital's server or in an Indian Azure region so data stays in India. Before that: the head of department's approval, hospital IT and data-protection sign-off, the ethics committee, and patient consent for messaging. Then 2 weeks measuring, 3 weeks in shadow mode, and 8 weeks live.

Where exactly is the AI in this?

Three places, and each does a different job.

Machine learning predicts session minutes. Mathematical optimisation (classical operations research) builds the plan. A language model explains and communicates. The plan itself is not written by a language model.

Why not just ask ChatGPT or another LLM to make the schedule?

Because it cannot promise that a rule will hold.

Language models are weak at precise packing, give different answers to the same input and are hard to audit. A missed rule here could mean a complex case without senior staff. The solver guarantees the rules and a second program checks them.

Why not reinforcement learning?

It needs far more data than a single department has, it is a black box, and it offers no guarantee on hard rules.

It also cannot be re-configured by editing a rule. Our optimiser can be reconfigured by changing a number in a file.

What is a MILP, in one sentence?

A way to ask a computer for the cheapest plan that satisfies a list of yes/no and arithmetic rules.

“Mixed-integer” means some choices are whole-number yes/no decisions (starts at 09:10 or not). “Linear” means the rules and costs are sums, which lets the solver prove how close its answer is to the best possible. The maths page works a four-patient example.

How do you guarantee the rules are not broken?

Twice: in the solver and again in a separate checker.

Hard rules are constraints, so a plan that breaks them is not a valid answer. Then a second program, which shares no code with the solver, re-verifies eight rules on every session. On the prototype day: 87 sessions checked, 0 violations.

What if there is no way to fit everyone?

The system says so and a human decides.

Every patient must either start once or be flagged as unplanned at a very high cost, so unplanned is a last resort. In a breakdown over 60 minutes, patients are sent back in a defined order (those not yet travelling first, palliative before other radical courses) and a technologist or doctor approves. A gap-sensitive course or a hospice patient is never sent back automatically: the oncologist decides.

How long does it take, and will it scale?

7 to 31 seconds for 87 patients on a laptop; a breakdown re-plan in 10 to 14; faster, scalable software is the plan.

The prototype uses an open-source solver (HiGHS) via SciPy. The build moves to Google OR-Tools CP-SAT, designed for scheduling with intervals. The target is a full evening plan for 90 patients in under 60 seconds and a live re-plan in under 30.

How accurate is the duration model?

On synthetic test data: average error 2.15 minutes, versus 2.62 for a table of averages.

62% within 2 minutes; the P80 covers 78.6% of sessions (promise: 80%). These are synthetic so they prove the method, not the clinic. The pilot target is an error of at most 2.5 minutes on real data.

Is the data real?

The patients are synthetic; the behaviour is calibrated on aggregates of real anonymised records.

The hackathon allows only fake or fully anonymised data. The department's anonymised records (3,137 patient-days) were summarised into aggregates, such as how appointment times spread over the day and how early people arrive. Only those aggregates are in the repository. The head of department's sign-off on publishing them is on our checklist.

How do you know the simulation matches reality?

We tested it against recorded days and are open about where it falls short.

Replaying today's booking over all 55 recorded days, the twin gives a P90 of 106 min against 109 recorded. It under-predicts the longest waits on quieter days, and on the busiest days it over-predicts. So we quote today's numbers from the records, not the twin, and set a pilot target well below the prototype result.

Why doesn't the median wait come down?

Because of reporting early, by design: 20 minutes before the slot, 45 for pelvic patients.

That gives a floor on the median. The improvement is in the tail: P90 falls from 130 to 76 minutes and the share more than an hour late from 27% to 6%.

Why does one patient in the prototype move from 08:50 to 19:24?

Only in the single-day test. Since 24 October each course gets a standing slot.

The single-day test draws a fresh “current” time from the department's recorded booking pattern, then plans the day anew, so times can jump. With standing slots, a patient's time is fixed when the doctor approves the course and stays until it ends, unless the patient asks to change it.

What happens when the machine is down for hours?

Up to 60 minutes everyone is treated with overtime; longer, only as many are sent back as the downtime needs.

Those who have not left home are chosen first and told to postpone travel; their fraction is added at the end of the course. New starts wait for the machine. A technologist or doctor approves before anyone is told. In the prototype, a 150-minute fault sent back one patient and moved two new starts.

What if a patient comes early, or has not come at their time?

The technologist treats whoever is ready; RAD-SMART keeps the order and records the exception.

The board shows who to call next among those who have arrived, so the machine never waits for an absent patient. Taking someone in ahead of the plan asks for a one-tap reason and shows what to check (bladder preparation, senior staff, shared accessories), but is never blocked. Out-of-turn treatments are counted, so the pilot can see whether times need adjusting.

Patients want the morning or the evening. Can it do that?

Yes: morning, afternoon or evening is asked at intake, and RAD-SMART offers a better time when one frees up.

Hard rules and new starts come first, so a new patient may start outside their preferred part of the day. As other courses finish, RAD-SMART finds a slot inside it that is free on every remaining treatment day and offers it to staff, who ask the patient. Nothing moves until staff approve, and a patient who says no is not asked again.

What if a patient doesn't read WhatsApp or can't read?

SMS or an automated voice call; staff can call; nearby patients can be called in.

We assume 85% act on updates and will measure it in the pilot. Messages carry times only, in the patient's language, with a caregiver copy if the patient agrees.

How do you handle Tulu?

Text in Kannada script plus a short recorded voice note.

Sarvam's current speech models do not include Tulu. Tulu-speaking staff record each approved template once, and the time comes from recorded number clips.

Does patient data go to the language model?

No names, no phone numbers.

The model sees pseudonymous IDs and operational tags. Personal details are added on the hospital's server when a message is sent. Patient messages come from fixed, pre-approved templates, so the model only fills in a time.

Who is responsible if the system is wrong?

The approving clinician stays in control, and everything is logged.

All outputs are proposals; the doctor approves courses and a technologist or doctor approves breakdown responses; any plan can be overridden in one tap; a printed fallback list exists; and the audit log records the rule and model versions behind every plan. The pilot has stopping rules: if a hard rule is broken in practice, or balancing KPIs worsen for two weeks, we revert to manual.

How will it connect to our existing systems?

Inside the hospital information system, with a button on the visit page.

The build runs inside CARE as a plugin; the same pattern fits the hospital's own EMR. The pilot adds QR check-in and tablet taps. Phase 2 adds a read-only HL7/FHIR feed from MOSAIQ or ARIA. It never writes into the treatment record.

What about paying patients, is it fair?

Every priority is an explicit, visible weight chosen by the department.

Paying patients are weighted higher for keeping their preferred time (×4, within 15 minutes). The same weight orders the better-time offers, together with fractions left and minutes outside the preferred part of the day, and every offer still needs staff approval. We report waits by group (elderly, transport-dependent, language, paying vs non-paying), and a rule that makes any group worse off is treated as a problem to review.

How will you prove it works in the pilot?

One headline measure: 90th-percentile wait at least 25% lower than the records' 109 minutes by day 90.

The 90-day pilot has three phases: 14 days baseline logging, 3 weeks shadow mode where it plans but staff schedule as usual, then live on the Versa HD. Analysis is a segmented regression of the daily P90 wait with weekly control charts, plus secondary and balancing measures (punctuality, new starts on time, equity, override rate).

Can another department reuse it?

Yes. Every rule is configuration, not code.

Operating hours, windows, accessories, weights and downtime rules sit in one configuration structure. In the build, the Rule Studio edits it in plain language with a before/after diff and a twin impact estimate, and saves a new version only after approval.

What is your biggest risk?

That patients do not stop arriving very early once times are kept.

With today's arrival habits our simulated P90 is 110 minutes rather than 76. We show both results, which is why the pilot target is 25% rather than the prototype's 42%. Second: duration data, which the first two weeks of logging address.

Cheat sheet

Numbers to remember

FactValue
Department records used3,137 patient-days · 263 patients · 15 Oct–31 Dec 2024 · aggregates only
Today (all recorded days)Median wait 34 min · P90 109 min · 29% within ±15 min
Today (busiest recorded days)P90 130 min · 27% more than an hour late · evening median 66 min
Prototype day87 patients + 0–3 urgent · 890 expected machine-minutes of 960 available (92.7%)
RAD-SMART (simulated, 300 days)P90 76 min · 6% more than an hour late · 53% within ±15 min · evening median 36 min
Duration modelError 2.15 min vs 2.62 · P80 covers 78.6%
Original dataset (55 recorded days, with vs without)P90 108.6 → 70.4 min (−35%) · more than 1 h late 22% → 6%
Simulated, 12 weeks with standing slotsP90 82 → 49 min (−40%) · last patient 21:55 → 00:07
Optimiser size and speed~4,700 variables · ~1,660 constraints · 7–31 s · gap ≤ 0.13%
Checker8 rules (9 with standing slots) · 87 sessions · 0 violations
Fault median wait (no re-plan → re-plan)45 min fault: 53 → 37 · 150 min fault: 104 → 39
Forecast (two machines, TBI week)Peak load 154% → 98% · days over capacity 10 → 0
Sarvam AI evaluation112 of 112 translations in 4 languages kept every time · 20 of 20 explanations accepted, 0 invented times
Live deploymentMicrosoft Azure: Container Apps (one Docker image), PostgreSQL with daily backups, Container Registry, a daily job · 45 automated tests (37 plugin, 8 engine)
Pilot headline targetP90 at least 25% below 109 min within a 90-day pilot
TeamDr Akshay Dinesan (team leader, doctor partner) · Abhinand T M (technical lead) · P S Raghotham Rao (lead engineer) · Dr Shirley Lewis Salins and Dr Umesh Velu (doctor partners)

Next: the maths, with numbers you can change

Quantile loss, boosting, the optimisation puzzle, the Monte Carlo trick and the forecast arithmetic.

Open the maths page →