T-Baar: Reducing Empty Returns in Iran's Road-Freight Network
Roughly 30% of trucking capacity in Iran is lost to empty return trips — but this is not, at root, a routing problem. It is a coordination failure driven by information asymmetry, trust deficits, and settlement friction in an informal market. I built T-Baar to diagnose those mechanisms and to test whether targeted interventions could close the gap while respecting how drivers actually behave.
01. The problem — a coordination failure, not a routing one
Field research put hard numbers on the inefficiency: across an estimated 465,000 commercial vehicles, empty returns account for about 30% of capacity, over 20M ton-kilometers of wasted transport a year, and more than $300,000 in preventable loss per corridor. The tempting read is that trucks return empty because no return load exists. The data says otherwise.
When I attributed each empty trip to a cause, only about a fifth were genuinely structural (no load existed). The rest — roughly four in five — were addressable: drivers couldn't see available return loads (information asymmetry), wouldn't risk an unpaid backhaul with a stranger (trust and settlement friction), or were reluctant to enter load-sharing arrangements at all (behavioral resistance). Settlement delays were the sharpest signal of the trust deficit: nearly 30% of trips waited five or more days to be paid.
02. Approach — interventions matched to mechanisms
Because each failure mode has a different root cause, a single algorithm wouldn't fix it. The pilot pairs an optimization layer with institutional design, so each intervention targets a specific coordination failure rather than the symptom.
Optimization layer
A bipartite load–driver matching model (Hungarian assignment, minimizing deadhead toward each driver's home) plus predictive analytics for where return loads will appear — attacking information asymmetry directly.
Institutional layer
Escrow settlement to remove payment risk, digital waybills to make loads visible and verifiable, and a lightweight queue-management API — addressing the trust and behavioral barriers an algorithm alone can't.
03. What I built
- A data pipeline consolidating multi-source freight, routing, and pricing data into clean analytical tables.
- A bipartite load–driver matching model with a tunable deadhead-and-timing cost function (solved with the Hungarian algorithm).
- A coordination-failure attribution that classifies each empty trip as information, trust, behavioral, or structural — quantifying what is actually addressable.
- A 90-day pilot design coupling four interventions — algorithmic matching, escrow settlement, digital waybills, queue-management API — to pre-registered success metrics so impact could be measured, not asserted.
04. Impact
On conservative projections, the pilot cuts the empty-return rate by a full 10 points (30% → 20%), recovers on the order of 35M+ ton-kilometers of capacity a year, lifts on-time delivery by 5 points, and — through escrow — collapses the share of 5+ day settlements from 29% to about 2%. That translates to roughly $0.9M in captured savings across the pilot corridors, against a preventable-loss opportunity several times larger at full rollout.
The deeper takeaway is methodological: efficiency gains in informal supply chains come from understanding how human behavior, institutional constraints, and information flows interact — not from optimization alone. That is the same causal, mechanism-first discipline I bring to A/B testing and experimental analysis.
05. Modeling & analysis — the matching engine, quantified
The optimization layer is a bipartite assignment problem: drivers ending a delivery on one side, available return loads on the other, and an edge cost equal to the deadhead distance a driver would travel toward home to pick up that load, plus a penalty for arriving late. Solving it with the Hungarian algorithm yields the globally cost-minimizing set of matches — turning empty return legs into paid trips.
# Bipartite load-driver matching: fill each empty return leg
# Cost = deadhead km toward the driver's home base + a lateness penalty.
import numpy as np
from scipy.optimize import linear_sum_assignment # Hungarian algorithm
def match_returns(drivers, loads, home, due):
C = np.zeros((len(drivers), len(loads)))
for i, d in enumerate(drivers):
for j, l in enumerate(loads):
deadhead = dist(d.at, l.origin) + dist(l.dest, home[d.id])
late = max(0, eta(d, l) - due[l.id])
C[i, j] = deadhead + LATE_PENALTY * late
rows, cols = linear_sum_assignment(C) # minimize total cost
return list(zip(rows, cols)), C[rows, cols].sum()
To separate what is addressable from what is structural, every empty trip is attributed to one of four mechanisms — information (the load existed but wasn't visible), trust (payment or counterparty risk blocked the match), behavioral (driver preferences/timing), or structural (no load exists on that lane). Only the first three are recoverable by software-plus-institutions; the matching model targets them directly.
| metric | baseline | with matching | change |
|---|---|---|---|
| empty-return rate | 63.8% | 38.4% | −25.4 pts |
| return legs filled | 36.2% | 76.1% | +39.9 pts |
| on-time delivery | 78.2% | 89.1% | +11.0 pts |
| total empty (deadhead) km | 6.50M | 3.08M | −53% |
Run across the full trip log, the engine cuts total empty kilometres by 53% (6.50M → 3.08M km), more than doubles the share of return legs that carry a paying load (36.2% → 76.1%), and lifts on-time delivery to 89.1%.
06. Interactive — the matching-adoption simulator
Adoption is never 100% on day one. Drag the levers below to see how the recovered savings scale with driver uptake and the operating cost of an empty kilometre — the same back-of-envelope the pilot used to size the prize. Everything is computed live from the 11,594-trip log.