Prevedere bene non significa decidere bene
Tre richieste arrivano insieme a un servizio logistico. Un modello AI stima il tempo necessario a ciascun mezzo per raggiungere ciascun cliente. Le stime, nel nostro primo esempio, sono perfino esatte. Basta allora scegliere ogni volta la coppia mezzo-cliente più vicina? No: assegnare un mezzo a una richiesta lo rende indisponibile alle altre. Una scelta conveniente da sola può consumare la risorsa che sarebbe stata molto più utile altrove. Il problema non è necessariamente nel modello predittivo, ma nella regola che trasforma le sue stime in azioni.
Abstract. Costruiamo un caso riproducibile su una linea, confrontiamo una scelta ingorda con l’assegnazione di costo minimo e dimostriamo l’ottimalità del risultato attraverso un limite inferiore verificabile. Aggiungiamo poi un’incompatibilità mezzo-richiesta, che trasforma una scelta localmente sensata in un vicolo cieco, e studiamo quanto un errore nei costi possa cambiare la decisione. L’obiettivo è distinguere previsione, ottimizzazione e fattibilità. Nessun dato proviene da flotte o clienti reali; non misuriamo prestazioni di un modello AI o risparmi aziendali.
Un esempio abbastanza piccolo da poterlo controllare
Immaginiamo una strada rettilinea percorribile in entrambi i sensi. I mezzi V1, V2 e V3 si trovano ai chilometri 0, 3 e 8. Le richieste A, B e C sono ai chilometri 1, −2 e 10. Il segno negativo indica soltanto una posizione a sinistra dell’origine. Assumiamo velocità uniforme di 1 km/min, assenza di traffico e servizio immediato all’arrivo. Ogni mezzo riceve esattamente una richiesta e ogni richiesta esattamente un mezzo. Non stiamo costruendo un itinerario con più fermate.
Per ricavare il costo cᵢⱼ della coppia i,j prendiamo la distanza assoluta fra le posizioni e la dividiamo per la velocità. Con la velocità scelta, i numeri della distanza in chilometri coincidono con quelli del tempo in minuti. La matrice seguente contiene tutti i tempi alternativi, non nove viaggi che verranno eseguiti. Sceglieremo soltanto tre celle, una per riga e una per colonna.
| Mezzo | A (min) | B (min) | C (min) |
|---|---|---|---|
| V1 | 1 | 2 | 10 |
| V2 | 2 | 5 | 7 |
| V3 | 7 | 10 | 2 |
La scelta ingorda e il costo dell’occasione persa
Definiamo senza ambiguità la regola locale: fra tutte le coppie ancora disponibili prendiamo quella con costo minore, poi rimuoviamo quel mezzo e quella richiesta. È una strategia ingorda, o greedy, perché non riconsidera le scelte precedenti. Parte da V1→A, costo 1. Fra le coppie rimaste sceglie V3→C, costo 2. Restano V2 e B, costo 5. Il totale è 8 minuti-veicolo, cioè la somma dei tempi dei tre mezzi; non sono otto minuti di durata complessiva quando viaggiano contemporaneamente.
Proviamo invece V1→B, V2→A e V3→C: 2+2+2=6. La prima assegnazione costa un minuto in più, ma permette a V2 di raggiungere A in due minuti anziché B in cinque. Paghiamo uno per risparmiarne tre. La differenza globale è di due minuti-veicolo. Questo controesempio basta a confutare la regola “scegliere sempre il minimo locale produce il minimo globale”; non dimostra che ogni scelta ingorda sia cattiva o che il miglioramento percentuale si ripeta su una flotta reale.
Scrivere il problema rende visibili i vincoli
Introduciamo xᵢⱼ, che vale 1 se il mezzo i viene assegnato alla richiesta j e 0 altrimenti. Vogliamo minimizzare la somma dei costi delle celle selezionate. Le due famiglie di vincoli impediscono di assegnare un mezzo due volte o di lasciare una richiesta senza servizio:
Σ significa sommare sugli indici indicati; ∀ significa “per ciascuno”. In parole: ogni riga e ogni colonna devono contenere esattamente una scelta. L’obiettivo è il tempo totale, non il tempo del cliente peggio servito, il profitto o l’equità. Cambiare obiettivo può cambiare la soluzione. Anche se nel nostro esempio il piano da 6 migliora pure il tempo massimo, questa coincidenza non rende intercambiabili somma e massimo in generale.
Con tre mezzi esistono 3!=6 assegnazioni complete. Il punto esclamativo indica il fattoriale: tre possibilità per il primo mezzo, due per il secondo, una per il terzo. Il programma le enumera tutte e trova costi 6, 8, 16, 18, 22 e 22. Il minimo non dipende quindi da un tentativo fortunato. L’enumerazione costa O(n·n!) se per ciascuna permutazione sommiamo n costi: è trasparente per tre mezzi, ma non è la strategia da trasferire a grandi flotte.
Come dimostrare che sei è davvero il minimo
Possiamo fornire anche una prova più compatta dell’elenco completo. Assegniamo a ogni mezzo un numero uᵢ e a ogni richiesta un numero vⱼ, scegliendoli in modo che uᵢ+vⱼ non superi mai il costo cᵢⱼ. Non sono prezzi fatturati: sono quantità matematiche ausiliarie. Per qualunque piano completo, la somma di questi numeri è un limite inferiore al costo, perché ogni mezzo e ogni richiesta compaiono esattamente una volta.
Controlliamo la prima riga: u₁+v dà [1,2,2], che non supera [1,2,10]. La seconda dà [2,3,3], sotto [2,5,7]; la terza [1,2,2], sotto [7,10,2]. Ogni piano costa dunque almeno 6. Abbiamo già un piano che costa 6: non può esisterne uno migliore. Il numero negativo −1 è lecito perché i numeri ausiliari non rappresentano tempi fisici. Questa costruzione è un certificato duale: una prova dell’ottimo controllabile con nove confronti e una somma, senza fidarsi del nome di un algoritmo.
Il certificato dimostra l’ottimalità rispetto alla matrice e ai vincoli scritti. Non dimostra che le previsioni dei tempi siano corrette o che abbiamo incluso tutti i vincoli aziendali. È una distinzione essenziale quando un agente AI presenta un piano come “ottimo”: bisogna sapere rispetto a quali dati, a quale obiettivo e a quale insieme di scelte ammesse. Una prova matematica può essere impeccabile e descrivere comunque il problema operativo sbagliato.
Quando la scelta locale lascia una richiesta senza mezzo
Aggiungiamo un vincolo ipotetico: V2 non può servire B, per esempio perché non possiede un requisito tecnico richiesto da quel servizio. L’incompatibilità è un dato del caso, non un giudizio su una persona. Imporre x₂B=0 è più chiaro che inventare un tempo molto alto e sperare che l’algoritmo lo eviti. Se un costo finito resta ammesso, in un problema difficile potrebbe comunque essere scelto.
La regola ingorda sceglie ancora V1→A e V3→C. Si ferma poi davanti all’unica coppia rimasta, che ora è vietata. Il programma segnala piano incompleto, non costo infinito di un servizio realmente eseguito. Eppure la soluzione V1→B, V2→A, V3→C resta fattibile e costa 6. Il fallimento riguarda quindi la sequenza di scelte irrevocabili, non l’esistenza di una soluzione del problema. Un’eventuale riparazione deve poter riassegnare decisioni precedenti.
Se i tempi sono previsti, quanto deve sbagliare l’AI per cambiare il piano?
Finora la geometria produceva tempi esatti. Per una sensibilità separata trattiamo ora i tempi come costi previsti e modifichiamo soltanto V2→A: chiamiamo λ il nuovo valore in minuti. Non pretendiamo che questa modifica isolata derivi dalla stessa strada ideale; rappresenta un aggiornamento astratto della previsione, lasciando ferme le altre celle. Il piano iniziale ingordo costa sempre 8. Il piano con scambio di A e B costa λ+4. Si equivalgono a λ=4: sotto questa soglia conviene lo scambio, sopra conviene l’altro piano.

Per leggere il grafico seguiamo il ramo più basso. La scansione usa 101 valori da 0 a 10 minuti con passo 0,1 e controlla tutte le assegnazioni, non soltanto le due disegnate. Una variazione piccola può essere irrilevante lontano dall’incrocio e decisiva vicino all’incrocio. Perciò un errore medio sui tempi, considerato da solo, non descrive quanto sono stabili le decisioni: conta dove cade l’errore rispetto alle alternative quasi equivalenti.
Un limite semplice per gli errori distribuiti su tutte le coppie
Torniamo alla matrice iniziale. La migliore assegnazione costa 6 e la seconda 8: il divario Δ è 2 minuti-veicolo. Supponiamo ora che ogni costo possa cambiare in valore assoluto al massimo di ε minuti. Un piano di n assegnazioni può cambiare al massimo di nε; confrontando due piani, il peggiore cambiamento della differenza è al massimo 2nε. Una condizione sufficiente per conservare il vincitore è quindi:
Il significato è prudente: se ogni errore resta sotto un terzo di minuto, nessuna assegnazione concorrente può recuperare tutto il divario, usando questa maggiorazione. Non è una soglia necessaria: abbiamo contato anche errori su coppie condivise da due piani, che nel confronto si cancellano. Inoltre il limite su ogni costo è un’ipotesi forte; non si deduce da un errore medio basso. Va verificato o sostituito con un modello d’incertezza appropriato.
Nel codice poniamo ε=0,3 minuti e proviamo tutte le 2⁹=512 combinazioni estreme dei nove errori, ciascuno pari a +ε oppure −ε. Il vincitore resta lo stesso. Per una differenza di costi lineare, gli estremi su questa scatola di incertezza si raggiungono ai vertici: il controllo ha quindi un significato per il modello dichiarato, non è una prova casuale su 512 clienti. Non abbiamo stimato una probabilità di successo o una distribuzione degli errori reali.
Dal caso didattico a un sistema operativo
Per problemi più grandi si usano algoritmi di assegnamento, non l’enumerazione fattoriale. La documentazione SciPy 1.18.0 di linear_sum_assignment descrive un risolutore per matrici anche rettangolari basato su una variante Jonker–Volgenant. Abbiamo letto definizione, vincoli e note dell’API; qui non abbiamo eseguito SciPy né riprodotto il paper citato dalla documentazione. Il nostro risultato è verificato dal codice standard Python e dal certificato esplicito.
Le richieste che arrivano nel tempo cambiano il problema: attendere può migliorare l’abbinamento ma ritardare un cliente. Più fermate per mezzo introducono itinerari e dipendenze fra viaggi. Capacità, finestre temporali, ricarica, turni e vincoli di servizio richiedono formulazioni aggiuntive. Una matrice aggiornata non basta se il mezzo è già partito: occorre distinguere decisioni ancora modificabili da impegni già eseguiti. La nostra analisi è un singolo istante di assegnazione, senza questi fenomeni dinamici.
La risposta e ciò che il codice permette di controllare
Il mezzo più vicino può essere la scelta giusta per un cliente e quella sbagliata per il gruppo. Nel nostro caso una rinuncia locale di un minuto evita tre minuti altrove; con un’incompatibilità, evita persino di lasciare una richiesta senza mezzo. L’AI può stimare costi, ma il sistema deve anche rappresentare vincoli e confrontare piani completi. La qualità della previsione e la qualità della decisione sono collegate attraverso questo passaggio, non equivalenti. Non occorre un modello più grande per correggere un algoritmo che ignora le alternative.
Il listato breve enumera i sei piani e verifica il certificato. L’archivio completo aggiunge la regola ingorda, il vincolo vietato, la scansione di λ e le 512 perturbazioni. L’ordinamento dei pareggi è deterministico; non c’è generazione casuale e il seed non si applica. Conserviamo tutte le permutazioni, quindi l’esempio usa memoria O(n·n!) per rappresentarle, oltre alla matrice O(n²). Il grafico è prodotto dai risultati salvati, non da una copertina generativa. Chi esegue il programma può controllare sia il numero migliore sia il motivo per cui le alternative falliscono.
Riferimento tecnico e riproducibilità
SciPy 1.18.0 — scipy.optimize.linear_sum_assignment.
from itertools import permutations
C = [[1, 2, 10], [2, 5, 7], [7, 10, 2]]
plans = sorted((sum(C[i][j] for i, j in enumerate(p)), p)
for p in permutations(range(3)))
print(plans)
u, v = [2, 3, 2], [-1, 0, 0]
assert all(u[i] + v[j] <= C[i][j] for i in range(3) for j in range(3))
assert sum(u) + sum(v) == plans[0][0] == 6
Codice, dati e istruzioni · JSON. Calcoli didattici eseguiti con Python 3.14.0; figure con Matplotlib 3.11.2. Analisi con assistenza AI, senza dichiarare peer review o revisione umana. Copertina originale ImageGen, illustrativa: non documenta persone, sedi o installazioni EL-AI. Fonti consultate il 3 ottobre 2026.

