2026-03-24 | Pinperepette

Il Treno Arriva Con La Matematica

Referendum, code ai seggi, e un politico che propone l'ordine alfabetico. Nobile. Ma la C ha 34 volte piu' cognomi della Q. Teoria delle code con dati reali: TfL Londra (NUMBAT, 432 stazioni, 15 min), MTA New York, simulazioni Monte Carlo. 7 script Python, 12 grafici.

Queueing Theory TfL / MTA Simulazione Kingman

// Il Seggio

Sezione 00. Come pensa un pirata

Referendum sulla giustizia. Separazione delle carriere. Ha vinto il no. Io ho votato si'.

Sulla magistratura non ho opinioni forti. Pero' sono un informatico, e un informatico vede che un sistema dove lo stesso nodo e' giudice e parte, dove chi accusa e chi decide condividono lo stesso pool, ha un problema di architettura. La questione e' di separation of concerns, prima che di politica.

Ma non e' di questo che voglio parlare.

Voglio parlare di una cosa che e' successa ai seggi. Un politico scrive, soddisfatto: "Nei seggi abbiamo visto per la prima volta gli elettori non piu' divisi tra maschi e femmine, ma secondo l'ordine alfabetico."

Intento nobile. Moderno. Progressista. Via la divisione binaria, dentro l'uguaglianza.

Io ho letto quella frase e ho pensato: avete appena rotto le code.

L'uguaglianza qui c'entra poco. So come si comportano le code, e quello che ho visto mi ha fatto pensare. L'ho scritto, l'ho detto, e in tantissimi sembravano non capire dove fosse il problema. Quindi ho deciso di farci un articolo.

Attenzione: ai seggi non puoi fare la coda unica. Ogni tavolo ha il suo registro degli elettori. I documenti sono fisicamente divisi. Lo scrutatore del tavolo A-F non ha i fogli del tavolo G-M. La divisione in gruppi e' un vincolo logistico, non una scelta di design. E' come lo sharding di un database: i dati stanno su nodi diversi, e devi mandare la query al nodo giusto.

Ma proprio perche' devi dividere, il modo in cui dividi conta. E l'ordine alfabetico dei cognomi italiani e' tutto tranne che una distribuzione uniforme. Un disastro, a voler essere gentili.

Tesi. La divisione M/F funzionava come load balancer per puro caso biologico: due gruppi al 50%. L'ordine alfabetico crea gruppi sbilanciati, a meno che non bilanci i tagli sulla distribuzione reale dei cognomi. Cosa che nessuno fa. Se il modello e' sbagliato, il resto viene dietro.

// Il Cognome Non E' Uniforme

Sezione 01. 42,271 cognomi dicono la stessa cosa

Ho preso l'archivio completo dei cognomi italiani. 42,271 cognomi distinti. E ho contato quanti iniziano per ogni lettera. Nota: questa e' una distribuzione per tipi, non per frequenze. I cognomi piu' comuni (Rossi, Russo, Romano, Ferrari) amplificano ulteriormente lo skew perche' si concentrano nelle lettere gia' sovrarappresentate. La distribuzione reale pesata per popolazione sarebbe ancora piu' sbilanciata. Questi numeri sono una stima conservativa.

Distribuzione cognomi italiani per lettera iniziale

La lettera C da sola copre il 13% dei cognomi. B l'11.2%. M il 9.4%. Dall'altra parte, Q sta allo 0.38%. U allo 0.41%. E allo 0.59%.

La C ha 34 volte piu' cognomi della Q.

Al mio seggio ho visto i cartelli: A-L e M-Z. Due tavoli, due registri. Sembra equo. Meta' dell'alfabeto di qua, meta' di la'. Ma i numeri dicono altro:

56.3%
A - L
43.7%
M - Z

56/44. Il tavolo A-L ha il 30% in piu' di elettori rispetto all'M-Z. Stessi sportelli, stesse risorse, carico diverso.

E la vecchia divisione M/F? Due gruppi da ~50% ciascuno. La biologia e' un load balancer migliore dell'alfabeto.

Avevate un sistema che funzionava (50/50). L'avete rotto (57/43). E non ve ne siete neanche accorti.

// La Simulazione

Sezione 02. 900 elettori, 2 tavoli, prima e dopo

Ho simulato un seggio elettorale. 900 elettori, 2 tavoli con 2 sportelli ciascuno, 12 ore di apertura. Arrivi modellati come processo di Poisson non omogeneo (NHPP) con λ(t) a doppio picco gaussiano (mattina σ=35min, pomeriggio σ=40min). Servizio ~ Exp(μ=2.5 min). Il confronto: quello che c'era prima (M/F) e quello che c'e' adesso (A-L / M-Z).

Simulazione seggio: M/F vs A-L/M-Z
StrategiaDistribuzioneAttesa mediap95
M/F (prima)50% / 50%57 min111 min
A-L / M-Z (adesso)57% / 43%70 min173 min

Il p95 e' il numero che conta: e' il tempo che aspetti se sei sfortunato. Con A-L/M-Z aspetti fino a quasi 3 ore. Con il vecchio M/F era meno di 2. Hanno peggiorato le code in nome dell'uguaglianza.

E questo e' il caso medio. Gli elettori non arrivano uniformemente: arrivano a ondate, con picchi la mattina e il tardo pomeriggio. Durante il picco lo sbilanciamento si moltiplica. Il tavolo A-L si satura mentre l'M-Z ha ancora margine. Kingman dice che non conta il carico medio giornaliero. Conta il carico istantaneo durante il picco. E quello, con un 57/43, esplode.

Il problema e' lo sharding key. Ai seggi i registri sono fisicamente separati per tavolo, come shard di un database. La coda unica non la puoi fare, come una query cross-shard senza costi. Ma se scegli una chiave di partizionamento con skew (e l'alfabeto dei cognomi italiani ha uno skew del 57/43 al taglio L/M) ti ritrovi con uno shard bollente e l'altro sottoutilizzato. L'M/F funzionava perche' la distribuzione di genere e' ~50/50: sharding perfetto, per puro caso biologico. Tagliare a meta' dell'alfabeto non e' tagliare a meta' degli elettori.

Il seggio e' solo l'inizio. La stessa matematica governa le metropolitane, i server, le autostrade, i pronto soccorso. E ha una proprieta' che quasi nessuno conosce: il tempo di attesa non cresce in modo lineare. Esplode.

// La Curva Che Esplode

Sezione 03. Kingman's formula

La cosa che tutti credono di sapere sulle code: se un sistema e' al 50% di carico, aspetti un po'. Al 70%, aspetti un po' di piu'. Al 90%, aspetti il doppio. Crescita lineare. Proporzionale. Intuitiva.

Sbagliato.

La crescita e' iperbolica. Al 50% aspetti 1 unita'. Al 80% aspetti 4. Al 90% ne aspetti 9. Al 95%, 19. Al 99%, 99. La curva non sale: esplode.

Kingman's formula (G/G/1 approssimata) E[W] ≈ (ρ / (1 - ρ)) × ((ca² + cs²) / 2) × E[S]

Dove ρ e' l'utilizzazione (domanda/capacita'), ca e cs sono i coefficienti di variazione degli arrivi e del servizio, E[S] e' il tempo medio di servizio. Il termine che uccide e' ρ / (1 - ρ). E' un iperbole. Quando ρ si avvicina a 1, il denominatore va a zero e il tempo va all'infinito.

Kingman formula: confronto M/M/1, M/D/1, M/G/1, G/G/1

Le quattro curve mostrano scenari diversi:

In tutti i casi, oltre ρ = 0.8 si entra nella zona di pericolo. La differenza tra 80% e 90% di carico non e' un 12.5% in piu' di attesa, e' 2-3 volte tanto. Nessuno lo misura finche' non succede.

Questo spiega perche' il tuo server risponde in 50ms al 70% di CPU e in 2 secondi al 85%. E' Kingman, non un bug.

// La Teoria Tiene?

Sezione 04. 50,000 clienti simulati

Ho messo la formula alla prova. Simulazione Monte Carlo di una coda M/M/1 con 50,000 clienti per ogni valore di ρ, da 0.1 a 0.95.

Teoria M/M/1 vs simulazione Monte Carlo

I punti verdi (simulazione) seguono la curva viola (teoria) quasi perfettamente. Tecnicamente Kingman e' un'approssimazione, non un risultato esatto. Ma e' un'approssimazione sorprendentemente accurata.

// I Dati di Londra

Sezione 05. 432 stazioni, intervalli da 15 minuti

La teoria e' bella. Ma funziona nel mondo reale? Ho preso i dati NUMBAT 2024 di Transport for London: i flussi di passeggeri in entrata per ogni stazione della metro di Londra, ogni 15 minuti, per un giorno feriale tipo (martedi'-giovedi').

432
Stazioni
96
Slot da 15 min
1,215
Link treno
NUMBAT
Dataset TfL

Il primo grafico e' il profilo di domanda nell'arco delle 24 ore. Nove stazioni, da Waterloo a Canary Wharf.

Profilo domanda 24h, Londra, giorno feriale tipo

Due picchi netti: AM Peak (07:00-09:30) e PM Peak (16:30-19:00). Waterloo schizza a quasi 6,000 ingressi per quarto d'ora al mattino. Il modello stazionario, quello che assume un tasso di arrivo costante, e' una bugia. La domanda varia di un fattore 10x nell'arco della giornata.

Per ogni stazione ho calcolato ρ = λ / μ, dove λ e' il picco di arrivi nel quarto d'ora piu' affollato dell'AM Peak e μ e' la capacita' (treni per 15 min × 800 passeggeri/treno). Poi ho piazzato ogni stazione sulla curva di Kingman.

Stazioni di Londra sulla curva di Kingman

La maggior parte delle stazioni della Tube sta nella zona verde (ρ < 0.3). Il sistema e' ben dimensionato. Ma Clapham Junction (Overground, non Tube) sfonda ρ = 1. Piu' gente che arriva di quanta ne possa partire. E le stazioni di Richmond, Wimbledon, Brixton stanno nella fascia 0.2-0.5 dove il sistema tiene, ma non ha margine per imprevisti.

Il dato piu' utile e' il carico effettivo sui treni, tratta per tratta:

Carico treni, top 5 tratte piu' affollate

Questo e' il motivo per cui a Oxford Circus alle 8:30 lasci passare il primo treno. E' ρ che lavora.

// New York Conferma

Sezione 06. MTA, la stessa forma dall'altra parte dell'oceano

Per verificare che il pattern non sia specifico di Londra, ho scaricato i dati orari della MTA, la metro di New York. Conteggi per stazione, per ora, per classe tariffaria.

Profilo orario metro New York

Stessa forma. Due picchi, stesso rapporto tra peak e off-peak. La domanda di trasporto nelle grandi citta' e' universale: segue il ciclo lavoro-casa, non il modello Poisson dei libri di testo.

E qui c'e' il punto critico. Ho preso tutti gli arrivi AM peak (ore 7-9) da tutte le stazioni e ho confrontato la distribuzione empirica con un modello Poisson e un log-normal.

Distribuzione arrivi MTA: Poisson vs realta'

Il QQ plot a destra e' il verdetto: la coda destra devia. I valori estremi sono piu' frequenti di quanto Poisson predica. Traduzione: le raffiche di arrivi (50 persone che escono tutte dallo stesso bus, un treno regionale che svuota 300 pendolari sulla banchina) succedono piu' spesso del previsto. E Kingman dice che piu' la varianza degli arrivi e' alta, peggio e'.

// Il Paradosso dell'Autobus

Sezione 07. L'intuizione mente, la simulazione no

L'autobus passa ogni 10 minuti. Quanto aspetti in media alla fermata?

Risposta intuitiva: 5 minuti. Meta' dell'intervallo. Se arrivi in un momento casuale, in media sei a meta' tra due autobus.

Risposta corretta: dipende. Se gli autobus sono perfettamente puntuali (intervallo sempre 10 min), si', aspetti 5 minuti. Ma se gli intervalli variano (e nel mondo reale variano sempre) aspetti di piu'. Con intervalli esponenziali (il caso teorico), aspetti 10 minuti. Non 5. Il doppio.

Si chiama inspection paradox. Quando arrivi in un momento casuale, hai piu' probabilita' di cadere in un intervallo lungo che in uno corto. I grandi intervalli "catturano" piu' passeggeri. L'attesa media non e' E[H]/2 ma:

Tempo di attesa con intervalli variabili E[W] = (E[H] / 2) × (1 + CV²)

Dove CV = σ/μ e' il coefficiente di variazione. Con CV = 0 (deterministico), E[W] = E[H]/2. Con CV = 1 (esponenziale), E[W] = E[H]. Con CV = 2 (iperesponenziale), E[W] = 2.5 × E[H]/2.

Ho simulato 100,000 arrivi casuali per 5 distribuzioni diverse degli intervalli, tutte con media 10 minuti:

Paradosso dell'autobus, simulazione

La barra gialla tratteggiata e' quello che tutti credono (5 minuti). Nessuna distribuzione reale ci sta sotto, tranne quella perfettamente deterministica. Con intervalli iperesponenziali, quelli che descrivono i bus nelle citta' con traffico pesante, aspetti piu' del doppio di quello che pensi.

La prossima volta che l'app dice "autobus ogni 10 minuti" e ne aspetti 15, l'inspection paradox sta facendo il suo lavoro.

// La Coda Con Priorita'

Sezione 08. Qualcuno muore di fame

Pronto soccorso. Codice rosso, codice giallo, codice verde. I rossi passano prima. Sembra giusto. Lo e'. Ma ha un prezzo che nessuno dichiara: al crescere del carico, i codici verdi non aspettano un po' di piu'. Aspettano esponenzialmente di piu'.

Ho simulato una coda con due classi di priorita'. Il 60% del traffico e' high priority, il 40% e' low. Stesso server.

Priority queue, starvation della bassa priorita'

La linea verde (high priority) sale piano. La rossa (low priority) esplode. A ρ = 0.9, la bassa priorita' aspetta decine di volte piu' della alta. Ordini di grandezza, non fattori due o tre.

Questo e' il motivo per cui aspetti 6 ore al pronto soccorso col codice verde anche se il reparto "non e' pieno". In media non e' pieno. Per chi e' in fondo alla coda, lo e' eccome.

In informatica lo chiamiamo starvation. Nei sistemi operativi, nei load balancer, nelle pipeline CI/CD. Il task a bassa priorita' che non viene mai schedulato. La soluzione esiste (aging, fair queuing, deficit round-robin) ma ha un costo: devi accettare che i task ad alta priorita' rallentino un po'. La conservation law di Kleinrock dice che il tempo medio pesato e' costante. Migliorare una classe costa a un'altra, sempre. Equita' ed efficienza sono matematicamente incompatibili, lo dice la conservation law.

// L'Effetto Cascata

Sezione 09. Un nodo lento avvelena il sistema

Ultimo pezzo. Cinque stazioni in serie. La Victoria Line da Brixton a Victoria. Un treno parte da Brixton, si ferma a ogni stazione, arriva a Victoria. Tutto regolare. Poi Vauxhall ha un problema: porta bloccata, passeggero che sviene, sosta raddoppiata.

Cosa succede a valle?

Effetto cascata, propagazione del ritardo

Il ritardo non resta a Vauxhall. Si propaga. Pimlico e Victoria ricevono un ritardo amplificato, perche' ogni treno successivo trova la stazione ancora occupata dal precedente. I treni si ammassano. Gli headway diventano irregolari. I passeggeri si accumulano sulla banchina, rallentando ulteriormente la salita. Feedback positivo.

Questo e' esattamente quello che succede nei microservizi. Un endpoint lento a monte non rallenta solo se stesso. Avvelena tutti i servizi a valle. Le connessioni si accumulano, i timeout cascadano, il circuit breaker scatta troppo tardi. Il sistema non si degrada gradualmente. Collassa.

// Gli Script

Sezione 10. Riproduci tutto
$ ls scripts/il-treno-arriva-con-la-matematica/ 01_extract_numbat.py # Estrai dati NUMBAT TfL (station entries, frequencies, rho) 02_kingman_curve.py # Curva di Kingman + stazioni su curva 03_demand_profile.py # Profilo domanda 24h + carico treni 04_mta_analysis.py # Analisi MTA New York (orario + distribuzione) 05_simulation.py # Monte Carlo: paradosso autobus, priority, M/M/1 vs teoria 06_cascade.py # Effetto cascata (5 stazioni in serie) 07_cognomi.py # Distribuzione cognomi + simulazione seggio $ ls data/ numbat_twt.xlsx # NUMBAT 2024 TfL (Tue-Wed-Thu, 12MB) train_loading.csv # Carico treni per tratta (TfL Crowding) mta_hourly_sample.csv # MTA Subway Hourly Ridership 2022 station_entries_15min.csv # Output: 432 stazioni x 96 slot link_frequencies.csv # Output: 1,215 link con frequenze station_rho.csv # Output: rho per stazione (AM Peak) $ python3 01_extract_numbat.py [+] 432 stazioni salvate in station_entries_15min.csv [+] 1215 link salvati in link_frequencies.csv [+] rho calcolato per 430 stazioni $ python3 07_cognomi.py [+] Gruppo AL: 513 elettori (57.0%) [+] Gruppo MZ: 387 elettori (43.0%) [*] M/F: media=57 min p95=111 min [*] A-L/M-Z: media=70 min p95=173 min

Tutto il codice e' nella cartella scripts/il-treno-arriva-con-la-matematica. Servono numpy, matplotlib, scipy, openpyxl. I dati NUMBAT e MTA sono scaricabili liberamente. Nessuna API key.

// Conclusione

Fine trasmissione

Sono partito da un seggio elettorale e sono arrivato alla Victoria Line. Il filo e' lo stesso: le code non funzionano come pensi.

Crescono in modo iperbolico. Si sbilanciano in base agli input. E la varianza non la assorbono: la amplificano.

Il politico voleva l'uguaglianza e ha rotto le code (e francamente, ormai, anche le balle). Avevano un sistema bilanciato al 50/50, l'hanno sostituito con un 57/43. Il p95 e' passato da 111 a 173 minuti. Un'ora in piu' di attesa per chi e' sfortunato. L'ingegnere TfL voleva orari piu' densi e ha scoperto che oltre ρ = 0.8 il sistema collassa. Il passeggero alla fermata aspetta il doppio di quello che crede. Il codice verde in pronto soccorso non aspetta un po' di piu': aspetta ordini di grandezza di piu'.

Sono tutte conseguenze della stessa formula. Una formula che ha 60 anni, e' in qualsiasi libro di ricerca operativa del primo anno. Fuori da quel corso, quasi nessuno l'ha mai vista.

Il modello e' sbagliato. E la coda non perdona.

"ρ / (1 - ρ) non si negozia.
O guardi i dati, o la coda decide per te."

Dati: TfL NUMBAT 2024, MTA NYC 2022, Cognomix.it. Tutto pubblico, tutto riproducibile.