English ← Lorenzo Ferlito

Un servizio di ridesharing può sopravvivere su una rete quasi senza traffico?

Sì, e la parte interessante è quanto costa. Su un corridoio rurale del Galles centrale, tredici autisti iscritti servono l'85% di trentadue passeggeri a 6,8 chilometri-veicolo per passeggero trasportato. Portare la flotta a trentadue veicoli guadagna altri dieci punti di tasso di servizio e costa 13,9 km per passeggero. Portarla a centotrentadue non aggiunge nulla e costa 58,7 km per passeggero. Un servizio di ridesharing a basso flusso è economico finché è a corto di veicoli e rovinoso nel momento in cui ne ha abbastanza.

Questa è la risposta data da 600 run simulate su quattro esperimenti versionati nel repository, ognuno riproducibile offline e senza chiave API. Quello che segue è l'argomentazione.

Il corridoio

Ceredigion settentrionale verso Aberystwyth: cinque aree censuarie, 44.485 residenti, una città che assorbe il lavoro e sette stazioni distribuite su 23 km di A487 e A44. Tra le cinque aree corrono 11.772 spostamenti casa-lavoro; la coppia più grande vale 1.235 persone al giorno, e il 62% guida da solo. È il caso a basso flusso: abbastanza rarefatto perché condividere un passaggio sia un vero problema di coordinamento e non una coda.

La domanda viene dal dataset degli spostamenti casa-lavoro del censimento 2011, la più recente rilevazione area-area a licenza aperta che riporti una scomposizione per modo: distingue chi guida un'auto da chi la occupa come passeggero, quindi il corridoio porta con sé una quota di passeggeri auto osservata del 9,95% degli spostamenti in auto. È l'unico numero esterno disponibile per chiedersi se un'occupazione simulata sia plausibile, e non un obiettivo su cui calibrare, il che renderebbe tutto circolare. Le stazioni vengono da OpenStreetMap, selezionate per regola e non a mano. Due numeri del corridoio sono inventati ed entrambi sono dichiarati apertamente: uno scenario campiona un ventesimo del flusso osservato e iscrive un automobilista su dieci.

Come vanno letti questi confronti

Ogni esperimento esegue gli stessi dieci semi su ogni punto del suo asse, quindi due configurazioni non vengono mai confrontate come due medie con bande sovrapposte: la differenza viene calcolata seme per seme e riportata come media, deviazione standard e conteggio di quanti semi si sono mossi in ciascun verso. Non è un test di significatività e non viene presentato come tale.

Due conclusioni di questo progetto hanno cambiato segno sotto questa lente, ed erano già state scritte come risultati: un incrocio fra due regole di dispatch che si è rivelato rumore, e una cifra sulla soglia di cammino rimasta indietro di diverse revisioni.

I posti valgono più dei veicoli, di un fattore cinque

Tasso di servizio rispetto alla dimensione della flotta, con veicoli da due e da cinque posti. Cinque posti arrivano a 0,85 con tredici veicoli; due posti ne richiedono sessantasei.
Tasso di servizio rispetto alla dimensione della flotta, per capacità del veicolo. Media su dieci semi, con l'intervallo tra semi come banda.

Con sei veicoli, due posti servono il 16% dei passeggeri e cinque posti il 55%. Sugli stessi identici 83,9 chilometri, perché quegli autisti stavano facendo quei viaggi comunque e i posti in più non costano distanza. La stessa quota di servizio si può raggiungere aggiungendo veicoli invece che posti, ma il conto cambia: dove cinque posti bastano con tredici veicoli, due posti ne richiedono sessantasei, e sessantasei veicoli percorrono 891 km contro 183. Cinque volte la distanza per lo stesso servizio.

È un'affermazione su un corridoio con domanda rarefatta e sparsa. Un veicolo che passa da una stazione è comune; due passeggeri che vogliono la stessa stazione nello stesso momento no.

Il tetto è la distanza a piedi, non l'abbinamento

Tasso di servizio rispetto alla flotta a cinque soglie di cammino. A 1200 secondi la curva è piatta: più veicoli non aiutano.
Tasso di servizio rispetto alla flotta, per quanto un passeggero è disposto a camminare (le due tratte a piedi contano insieme). Dieci semi per punto.

Il vincolo che lega questo servizio non è il dispatcher e non è la flotta: è quanto lontano una persona è disposta a camminare fino a una stazione. A venti minuti di cammino totale, aggiungere veicoli smette di funzionare: il servizio va 0,278 → 0,381 → 0,375 al crescere di una flotta che più che quintuplica, quindi trentadue veicoli servono le stesse persone di tredici e costano 37,9 km per passeggero contro 16,9. Un passeggero senza nessuna linea entro la propria soglia di cammino non si registra mai, quindi nessun aumento dell'offerta lo raggiunge.

Gli scenari versionati assumono un massimo di quaranta minuti di camminata sulle due tratte: rispetto ai trenta minuti di default del motore valgono undici punti di tasso di servizio in più, in tutti e dieci i semi. Le stazioni stanno fino a due chilometri da dove la popolazione vive davvero, perché è lì che stanno nel Galles rurale.

La direzione batte la densità

Tasso di servizio rispetto alla flotta per quattro costruzioni di rete. Free-form e flow-ranked si sovrappongono; Delaunay e l'albero minimo perdono 0,2 di servizio.
Quattro modi di derivare un insieme di linee dalle stesse sette stazioni. Dieci semi per punto.

Quattro costruzioni derivano le linee dalle stazioni del corridoio: free-form collega tutte le 21 coppie, Delaunay 14, flow-ranked 13 (l'unica che legge il dataset) e l'albero ricoprente minimo 6. L'ipotesi era che strutturare la rete pagasse. Il risultato è inaspettato.

Dimezzare la rete è gratis. Le 13 coppie di flow-ranked contro le 21 di free-form differiscono per meno di 0,01 di servizio a ogni dimensione della flotta, e la maggioranza dei semi dà risultati identici. Ridurla a un quarto no. Delaunay e l'albero perdono da 0,18 a 0,24 di servizio a ogni dimensione della flotta sopra i sei veicoli, in tutti e dieci i semi. L'albero percorre meno chilometri, ma solo perché serve meno persone.

E ogni costruzione perde contro sei linee disegnate a mano. La rete dichiarata a mano del corridoio è fatta di sei linee a senso unico, tutte verso Aberystwyth. Confrontata seme per seme batte free-form di 0,106 con sei veicoli e di 0,109 con tredici, in tutti e dieci i semi, e smette di vincere solo quando i veicoli sono così tanti che il ranking trova comunque tutti. Sei linee orientate battono quarantadue linee orientate.

Il meccanismo è la direzione: ogni costruzione qui è simmetrica, e su un pendolarismo radiale del mattino metà delle sue linee corre via dal lavoro, dove il dispatcher a volte manda un autista. Quindi quello che paga non è la struttura ma conoscere la direzione della domanda, che nessuna delle quattro costruzioni legge.

Inseguire la domanda non paga

Quota di distanza a vuoto rispetto alla flotta per due regole di dispatch. La regola che insegue la domanda è peggiore a ogni dimensione della flotta.
Quota di chilometri percorsi senza nessuno a bordo, per due regole di dispatch. Dieci semi per punto.

La seconda regola di dispatch abbandona il criterio condiviso e manda ogni autista sulla linea dove ci sono già passeggeri in attesa. Confrontata seme per seme, non vince mai in modo misurabile sul servizio e perde sul costo dappertutto: la sua quota di distanza a vuoto è peggiore a ogni dimensione della flotta, e con trentadue veicoli percorre 234 chilometri in più, il 55%, per un servizio leggermente inferiore. Un autista che devia verso qualcuno in attesa a una stazione è un autista che allunga, e su linee di 23 km è il termine dominante.

Vale la pena essere precisi su una correzione, perché è il tipo di cosa che diventa senso comune senza che nessuno se ne accorga. Guardando le medie, le due regole sembrano incrociarsi: quella che insegue la domanda è avanti con flotte piccole e indietro con flotte grandi, e questo era stato letto come la firma di due euristiche che vedono ciascuna quello che manca all'altra. Ma il vantaggio con flotte piccole non regge il confronto seme per seme: i semi non sono d'accordo su quale delle due regole sia avanti, quindi quel vantaggio è rumore e sopravvive solo la differenza di costo. A nessuna delle due regole manca un meccanismo che ha l'altra: a entrambe manca valutare direttamente le coppie autista-passeggero invece di indicizzare l'abbinamento su una linea, che è la sezione seguente.

Valutare le coppie paga solo dove i veicoli scarseggiano

Tasso di servizio rispetto alla flotta per tre regole di dispatch. La valutazione delle coppie è avanti a entrambe le regole fisse con sei e tredici veicoli, e dietro alla regola del ranking da sessantasei in su.
Tasso di servizio rispetto alla dimensione della flotta, per tre regole di dispatch. Dieci semi per punto.

Entrambe le regole viste sopra indicizzano l'abbinamento sulla linea su cui si sono registrate tutte e due le parti, quindi un passeggero la cui linea migliore non ha autisti resta non servito anche quando un autista sulla sua seconda scelta lo avrebbe preso volentieri. La terza regola abbandona la linea come chiave dell'abbinamento e la tiene solo come geometria: il passeggero si registra ancora sulla sua prima scelta e comincia comunque a camminare verso quella, ma smette di appartenerle. Qualunque autista può dirottarlo, a patto che il cammino che gli resterebbe comunque da fare, da dove è arrivato in quel momento, stia dentro la soglia che quel passeggero ha dichiarato. Il punteggio è un punteggio di coppia: la deviazione dell'autista come frazione dell'andare dritto, più il cammino residuo del passeggero come frazione del suo limite. Nessuna delle due parti legge l'unità di misura dell'altra, e nessuna delle due soglie può essere scavalcata dal dispatcher.

È la prima regola qui a battere il ranking sul servizio con un segno stabile, e lo fa solo in fondo all'asse della flotta: +0,075 con sei veicoli (sette semi su dieci in positivo) e +0,053 con tredici (otto su dieci). Con trentadue la differenza è esattamente zero. Con sessantasei e centotrentadue va nel verso opposto: −0,037 e −0,025, e nessun seme si muove a suo favore. Il meccanismo spiega l'inversione: dove i veicoli scarseggiano la linea scelta da un passeggero spesso non ha nessuno sopra, e liberarlo verso chiunque possa raggiungerlo è un passaggio che altrimenti non avverrebbe; dove i veicoli abbondano c'è già un autista su ogni linea, quindi dirottare i passeggeri li sposta soltanto.

Sul costo non vince mai. La sua quota di distanza a vuoto è peggiore di quella del ranking in tutti i semi in tre delle cinque dimensioni della flotta, e l'occupazione è peggiore in tutti i semi in quattro, e con tredici veicoli percorre 8,6 km per passeggero contro 6,8. Mandare un autista a raccogliere qualcuno che stava camminando da un'altra parte è una deviazione vera, e anche il secondo cammino del passeggero lo è. Contro la regola che insegue la domanda, invece, domina: più servizio con tredici e trentadue veicoli (otto semi su dieci, e sette), attese più brevi a ogni dimensione della flotta, e con trentadue lo fa percorrendo 25 km in meno. Su questo corridoio, però, non inseguire la domanda resta più economico di entrambe le regole.

Due limiti, entrambi deliberati. Ogni autista decide da solo senza vedere il resto della flotta, quindi due possono puntare allo stesso passeggero e il primo se lo prende; assegnare l'intera flotta in un colpo solo è la metà che non è costruita. E un passeggero viene dirottato al massimo una volta, e solo mentre sta ancora camminando: mandare altrove chi è già fermo a una stazione azzererebbe l'orologio con cui si misura la sua pazienza e gonfierebbe di nascosto ogni cifra di servizio di questa pagina.

La flotta a chiamata perde su ogni asse

Lo stesso corridoio gestito come flotta di robotaxi porta-a-porta serve 24 passeggeri su 32 in 335 chilometri, il 56% dei quali a vuoto, con un'occupazione media di 0,44. Il servizio di carpooling serve 27 degli stessi 32 in 183 km con un'occupazione di 1,35, cioè metà della distanza per passeggero. Il meccanismo è una sola differenza strutturale: un veicolo di flotta non ha un viaggio proprio, quindi ogni chilometro a vuoto è un costo che il servizio paga, mentre i chilometri a vuoto di un autista in carpooling sono il pendolarismo di qualcuno. Aggiungere veicoli non corregge questa differenza.

Due appunti, e tirano nella stessa direzione della conclusione. Queste sono run singole a un solo seme e non uno sweep da dieci, quindi a differenza di tutto quello che precede non portano nessuna banda. E ogni tratta porta-a-porta è misurata in linea d'aria mentre le tratte di carpooling usano geometria stradale reale: la distanza della flotta è sottostimata e il divario vero è più ampio.

Il dispatcher è una giunzione, e una delle implementazioni è un modello

Niente di quello che precede coinvolge un modello linguistico, e nessuna cifra da un modello esiste ancora. Ogni numero di questa pagina è stato prodotto da una regola fissa, offline, in modo deterministico. Quello che segue è un'affermazione ingegneristica su come si misurerebbe un modello onestamente, non un risultato su un modello.

Il dispatcher sta dietro un trait con quattro decisioni: quale linea prende un autista, se spendere un veicolo di garanzia su un passeggero che ha atteso troppo, quale veicolo libero raccoglie quale passeggero, e dove aspetta un veicolo libero. Cinque implementazioni si innestano sulla stessa giunzione: le tre regole fisse viste sopra, un modello su ogni decisione, e un modello solo dove le prime due regole fisse sono in disaccordo. È la stessa giunzione che usano le regole fisse, misurata sulle stesse colonne di mobilità, con il costo per decisione e il tasso di azioni non valide riportati accanto.

Due elementi rendono economicamente sostenibili le implementazioni a modello, ed entrambi sono misurati e non asseriti. Ogni decisione è guidata dagli eventi, quindi nulla costa una chiamata per tick o per agente per tick; e ogni risposta è memoizzata sui byte esatti del suo contesto, il che funziona solo perché nessun contesto porta l'orologio: una domanda che porta l'orologio è una domanda diversa ogni secondo e non potrebbe mai essere riusata. Il risultato: 3.913 decisioni in 44 chiamate, o 2.239 in 22 per la variante che chiede solo sulle eccezioni. Quei conteggi sono misurati contro uno stub che risponde con una regola, quindi misurano il meccanismo e non dicono niente su un modello.

Il confronto richiede l'esecuzione di un solo comando, al costo di circa 11 dollari di token, e le soglie che deve superare sono scritte prima della run e non dopo. Per la scelta della linea ora è 0,906 con tredici veicoli, cioè la valutazione delle coppie e non gli 0,853 della regola del ranking, perché l'asticella si è alzata quando è arrivata la terza regola; e c'è una baseline di costo che non deve sforare. Per la progettazione della rete sono gli 0,853 delle sei linee a senso unico disegnate a mano e non gli 0,750 della migliore costruzione, perché una vittoria contro l'avversario più debole non sarebbe un risultato. Riposizionare un veicolo libero compete contro non fare niente, che è un'asticella bassa. Se vince la regola fissa, è quello il numero che viene riportato.

L'ordine di lavoro è questo: definire prima la metrica, costruire la baseline, aggiungere il modello, misurare il delta, pubblicare il numero anche quando non fa una bella figura. Un'azione non valida viene contata e rifiutata, mai ritentata, perché rifare la stessa domanda è il retry, e un ciclo di retry nasconderebbe esattamente il numero che vale la pena avere. Un processo del modello che muore fa fallire la run invece di finirla sotto una regola fissa con il nome del modello addosso.

Cosa non modella

Nessuna risposta comportamentale all'incentivo: un compenso muove due colonne contabili e nient'altro, ed è questo che mantiene validi tutti gli altri confronti tra schemi. Nessuna assegnazione sull'intera flotta: la valutazione delle coppie è greedy per singolo autista, quindi due autisti possono puntare allo stesso passeggero, e concatenare più discese in un solo viaggio è lo stesso calcolo mancante. Due tipi di agente sono dichiarati e inerti, e l'unico scenario che li contiene finisce al limite dell'orologio e viene riportato come troncato invece di essere mediato in un risultato. I cammini verso le stazioni e ogni tratta porta-a-porta usano un fallback in linea d'aria, che coglie il tempo e sottostima la distanza.

Due cose che questo testo cerca di non fare. Un effetto che non si separa non è un effetto escluso: dove dieci semi non riescono a distinguere due regole, è questo che viene riportato. E una metrica da una run che ha toccato il limite dell'orologio non è un risultato; il motore conta gli agenti rimasti in strada separatamente, così una run troncata non può essere mediata dentro di nascosto.

Il motore

Rust, un solo binario, nessun client HTTP e nessun runtime asincrono: l'unico comando che ha bisogno di geometria stradale invoca curl e versiona il suo output, e il modello vive dietro un sidecar Python che parla JSON riga per riga su una pipe. Gli agenti stanno in un vettore piatto e si riferiscono l'uno all'altro per indice; decidere è una funzione pura che restituisce un'influenza risolta da un passaggio successivo, ed è questo che ha reso il dispatcher sostituibile senza toccare una macchina a stati. Un solo generatore con seme possiede ogni estrazione, quindi una run sotto una regola fissa è una funzione pura del suo scenario e del suo seme: lo stesso seme scrive output identici byte per byte, e così fa un grafico rigenerato.

Predecessore: un simulatore multi-agente in Python e un articolo a PFIA 2025 sulla strutturazione di rete per la mobilità autonoma a chiamata. Questa è una riscrittura che pone la domanda sui costi a cui il lavoro precedente non poteva rispondere.