I have lived in Bangalore and Hyderabad, where traffic congestion is a daily problem. Most fixes I read about focus on adding public transport or building more roads. I wanted to test a different idea: that a lot of congestion comes from the structure of the road network itself, not just the volume of traffic. To do this I had to learn graph theory, which was the part I enjoyed most. The longer term goal is to analyse a specific area and give its local authorities a few concrete structural insights they can act on.
Can a road network get congested even when the total amount of traffic is moderate? I modelled roads as a graph: nodes are junctions, edges are roads, and each edge has a capacity in vehicles per step. I tested the question across three stages.
I built a weak, tree like network where all three lanes feed into a single Connector node, so only one path exists. I sent in 24 vehicles (8, 9 and 7 across the lanes), while the Connector exit road has a capacity of 20. Because demand (24) was above capacity (20), congestion was forced by the layout, not by heavy traffic.
Result: the Load Concentration Ratio (LCR) was 1.0, meaning 100% of traffic was pushed onto one path.
I redesigned the network with extra roads so each lane had more than one path (redundancy). I then added greedy capacity based routing, which sends vehicles to the highest capacity road first, since this spreads load instead of concentrating it. I used the same demand of 24 vehicles.
Results:
- The Load Concentration Index (LCI) fell to 0.38, below the 0.4 line I treated as healthy, so the busiest road now carried 38% of traffic instead of 100%.
- The Connector Dependency Ratio (CDR) stayed at 1.0, because every vehicle still passed through the Connector at some point. Redundancy spread the load, but it did not remove the dependence on that one hub. I did not expect this, and it became the most useful finding in the project.
I simulated the fixed network over 10 time steps with a constant inflow of 15 vehicles per step (5, 6 and 4 across the lanes), because real traffic arrives continuously rather than in one batch. I tracked the queue at each node.
Results:
- The Bridge node has no exit, so its queue grew by 15 every step (0, 15, 30, and so on up to 120). The Connector and Main Road also stayed backed up at 15 each.
- The total delay over 10 steps was 825, and it kept rising.
- This showed that a good structure is still unstable when inflow stays above exit capacity.
Outcome: three runnable experiments (structural_failure.py, flow_fix.py, dynamic_simulation.py) that produce the metrics below and the network diagrams in results/.
| Metric | Stage 1 | Stage 2 |
|---|---|---|
| Load Concentration Ratio (LCR) | 1.0 | |
| Load Concentration Index (LCI) | 0.38 | |
| Connector Dependency Ratio (CDR) | 1.0 | |
| Total delay over 10 steps | 825 |
- Congestion can come from structure, not just volume. A bad layout jams even under moderate demand.
- A tree like network creates a guaranteed bottleneck, because all traffic is forced through one node.
- Redundancy lowers load concentration (LCI from 1.0 to 0.38) but does not remove hub dependency (CDR stayed 1.0).
- A network stays stable over time only when average inflow is at or below the effective exit capacity.
All lanes feed into a single Connector node, so one path exists.
Extra paths added. Lanes connect directly to Main Road and Side Road.
The same resilient network simulated across 10 time steps with constant inflow.
urban-flow/
network.py # weak and resilient network definitions
routing.py # greedy capacity based routing and metrics
simulation.py # time based queue simulation
visualize.py # graph diagrams using igraph
experiments/
structural_failure.py # Stage 1
flow_fix.py # Stage 2
dynamic_simulation.py # Stage 3
results/ # network diagrams
requirements.txt
pip install -r requirements.txt
python experiments/structural_failure.py
python experiments/flow_fix.py
python experiments/dynamic_simulation.py- Python
- igraph, for graph modelling and diagrams
- matplotlib, for plotting


