Projects Product · Operations research
RouteOpt
Route and workforce optimisation for service companies whose staff get around on foot, by metro and by bus.
- Role
- Creator · engine, product and deployment
- Year
- 2025–2026
- Tools
- Python · Google OR-Tools · Flask · Next.js · Leaflet · GTFS Madrid · OSRM · SQLite · AWS EC2
- Status
- In production · internal use
How to use it
It reproduces the RouteOpt panel: the map of Madrid with one coloured route per worker, the list of routes on the left and the days of the week at the top. Metro legs are dashed, use real stations, and each stop shows its arrival time. Press “Optimise” to go from the initial allocation to the optimised one (allocation by proximity, nearest neighbour and 2-opt improvement), change the day, the number of stops or workers, and click a route to see it on its own. It is a reduced version of the engine, written for this page, with made-up stops.
Routing software is built for vans. The staff of a cleaning company travel on foot, by metro and by bus, carrying their equipment. RouteOpt solves that problem: who goes where, in what order and how many people you actually need.
- 950+
- Weekly services planned, none left unassigned
- −32%
- Idle hours per week (from 160.8 to 109.2)
- 93.6%
- Productivity, versus 90.8% for the hand-made plan
- €27,000+
- Estimated annual saving (51.6 h per week at €10/h)
The problem
A Madrid cleaning company planned around a thousand services a week by hand, in Excel: residential buildings, offices, garages. Each service has its time window and duration, and each worker chains several a day, moving around Madrid by public transport.
Done by hand, the result is crossed journeys, waits between one service and the next, and a question with no clear answer: how many people do we really need?
In technical terms it is a vehicle routing problem with time windows (VRPTW): sharing stops among “vehicles” while respecting schedules and shifts. The textbook case has a twist here: the vehicle is a person and the map is Madrid’s transport network.
How it works inside
- A multimodal travel-time map. I loaded the open data (GTFS) for Metro, Light Rail and EMT buses and calculated, for each pair of services, the best way to get there: walking (with OSRM on real streets and a 4.2 km/h fallback, because staff walk with cleaning equipment), by metro (up to 1.8 km on foot to the station) or by bus (one transfer at most, with a 4-minute penalty). Beyond 2.2 km, walking is ruled out to force public transport.
- Phase A: each day’s routes. Each day is solved as a VRPTW with Google OR-Tools: an initial solution by cheapest arc, then guided local search for 20 seconds. Each service has a time window with some flexibility, each shift a maximum number of minutes and each journey a maximum time.
- No service is left out. Leaving a stop unassigned costs 1,000 million in the objective function. It is a way of writing a business rule in mathematics: every building is a signed contract, and rather than leave it without service, the system prefers to ask for one more person.
- Phase B: from routes to contracts. Daily routes are packed into real weekly contracts (20 to 35 hours) with a first-fit decreasing algorithm: nobody does two routes on the same day and overtime is capped and costs extra. It works in two modes: design the optimal workforce from scratch, or fit the work into the current workforce and flag what doesn’t fit.
Measured result
Reference run (17 March 2026) against the company’s real planning, with the same services (over 950) and the same hours of actual work:
| Indicator | Hand-made plan | With RouteOpt |
|---|---|---|
| Productivity (work / total time) | 90.8% | 93.6% |
| Idle hours per week | 160.8 h | 109.2 h |
| Average wait between services | 13.5 min | 9.9 min |
| Unassigned services | — | 0 |
Working hours don’t change (1,594.6 h): what disappears is the time lost between services. In the run, 535 legs are walked and 125 go by metro.
The product
It is in production today and used inside the company as a private tool.
- Next.js web panel with maps (Leaflet and OpenStreetMap): adding workers and locations, a comparison between the current and the optimised plan, and a route viewer.
- Multi-company: each company only sees its own data and passwords are stored hashed with scrypt. The engine is an internal Flask API that only the panel talks to.
- Engineering: contract tests between panel and engine, a prioritised risk matrix, an operations manual with rollback, and deployment on AWS with Nginx and systemd.
What I take away
A textbook algorithm isn’t enough: the value lies in translating the business rules (“no building without service”, “nobody does two routes on the same day”) into the solver’s language, and in measuring the result against the real planning.