Tasks/Optimization, Planning & Control

City-Scale Traffic Signal Control Optimization

Coordinate phases, green times, and offsets across ~600 junctions under unseen traffic demand

Optimization, Planning & Controltraffic controlcity-scale optimization
Background

Urban traffic signal control has a standing problem: locally sensible timing propagates queues and gridlock downstream. The starting point is a full-city microsimulation whose six hundred signalised junctions run fixed timing plans that never observe a queue. The work is to redesign that control — phase choice, green times, and offsets between neighbouring junctions — so the network clears more vehicles at peak demand. The inherited plan is a stubborn local optimum: relief on one corridor costs more downstream, and gains must survive unseen demand levels.

instruction.mdthis is what the agent is given

You inherit a full-city traffic microsimulation — a real metropolitan road network with ~600 signalised junctions and a synthetic morning-peak demand — running on its original, un-optimised static signal timing. Improve the signal control so the whole city moves better under load, minimising this frozen cost (the exact definition lives in sim/eval_core.py):

Cost =     1 · Σ timeLoss     seconds of delay over arrived vehicles
     +   160 · teleports      SUMO teleports, charged the time-to-teleport
     +    20 · Σ stops        number of stops (energy / emission proxy)
     +  3600 · unfinished     vehicles still in-network or pending at END

Note the last term: 3600 · unfinished is the largest component at every load in this band, so serving vehicles at all matters more than shaving delay off the ones that already get through. You submit a signal program and/or an online controller; it is re-run on sealed hidden load and seed settings and scored by the same frozen cost, lower is better.

Hard Constraints

  • You may change signals only — phase selection, phase durations, and offsets. You may not modify the network, the demand, or vehicle models.
  • Your submission is the directory methods/main/. It may contain:
  • controller.py exposing class Controller with setup(conn) (called once with the live libsumo connection) and step(t) (called every simulation step), and/or
  • tls.add.xml, a static tlLogic program loaded as a SUMO additional file. It may only contain tlLogic/phase/param elements. The verifier snapshots the file and checks the snapshot against that whitelist before the simulation starts, so any other additional-file element (rerouter, calibrator, ...) — which would change the demand or the network — makes the run invalid (baseline score for every case).
  • Signal programs are handed to SUMO as-is: it is the simulator, not a separate rule checker, that decides what a program does. There is no min-green / yellow-transition / conflict-matrix / cycle-length validator — a program SUMO accepts will run, and you are scored on the traffic it produces, not on whether it looks conventional. A solution that crashes, or whose additional-file is rejected, scores the baseline for that case.
  • An online controller must be light: per-step decisions run inside the sim loop.

What You Have

  • sim/eval_core.py — the exact, frozen scoring core (the cost formula, demand window, and SUMO flags). Read it to understand precisely how you are scored.
  • methods/main/controller.py — the weak baseline you edit (a no-op: the city runs its original static timing). methods/main/tls_info.json — per-junction phase/link structure you can use to build programs or controllers.
  • selfcheck.py — runs your current solution on the visible load settings (scale 0.25 and 0.37) and prints the raw cost. Iterate against it.
  • The full city network and demand are in the container, under $SCENARIO_DATA.

What You Submit

Your edited methods/main/ (a controller.py and/or a tls.add.xml, plus any helper files it reads). The verifier re-runs it on the hidden settings using only the contract above.

How It Is Judged

The sealed verifier runs your solution on several hidden (load-scale, seed) cases drawn from the same load band as the visible ones — some lighter, some heavier — and recomputes the frozen cost per case. Each case's cost is then divided by that case's own no-op baseline cost (the inherited static timing on the identical settings) before averaging — so no single heavy case carries hidden extra weight, and the no-op baseline scores exactly 1.0 by construction. Lower mean normalised cost is better; your score rises monotonically as it drops. Beating the inherited static timing is the goal, and the headroom is real: the inherited timing is a fixed plan that never looks at a queue, on a network where queues build very unevenly. It is also a genuine local optimum — a change that helps one corridor routinely costs more somewhere downstream, so a method has to be judged city-wide, not junction by junction.

Time budget. The budget is simulation time, not wall clock: every run simulates exactly the fixed window in sim/eval_core.py (BEGIN=25200 to END=28200, demand until DEMAND_END=27000), then stops. Vehicles not served by END are charged W_UNFINISHED = 3600 s each — a smooth penalty, not a disqualification — so the cost of a given submission is bit-identical on any machine. Separately, each hidden case has a 1200 s wall-clock backstop: a pathologically slow controller that overruns it scores the baseline (normalised 1.0) for that case. Honest controllers with light per-step work finish well inside it.

Rollouts

221 minWall clock
$37.23Spend
63.0MTokens
22Versions, 8 kept

On the visible set

18.0M 19.5M 21.0M 22.5M 0 150 300 450 Agent step Normalised cost ↓ v0 v1 v2 v3 v4 v5 v6 v7 v8 v9 v10 v15 v17 v18 v19 v20 v21
keptrolled backsubmitted
  1. v0The agent measured the inherited no-op timing as the baseline.visible mean normalized cost 1.0000008 min · $1.05
  2. v1Max-pressure cut delay but blocked enough vehicles to raise total cost.scale 0.25/42 normalized cost 1.02442513 min · $1.54
  3. v2Three-second yellow transitions lowered cost at both visible loads.visible mean normalized cost 0.95819119 min · $2.26
  4. v3Permanent major-green phases sharply increased throughput despite more teleports.visible mean normalized cost 0.79861525 min · $2.94
  5. v4Permissive-green links reduced teleports but lost too much heavy-load throughput.visible mean normalized cost 0.88383332 min · $3.67
  6. v5Signal-off encoding behaved exactly like major-green, so the clearer v3 remained.scale 0.25/42 normalized cost 0.770810, identical to v335 min · $4.03
  7. v6Rotating major and permissive priority reduced throughput at both loads.visible mean normalized cost 0.84317545 min · $5.18
  8. v7Keeping only never-protected links permissive narrowly improved the visible mean.visible mean normalized cost 0.79812152 min · $6.15
  9. v8An early-load selector combined v7 for light traffic with v3 for heavy traffic.visible mean 0.797443; four-case mean 0.79468593 min · $12.25
  10. v9Demoting only four-phase minor links made the light case worse.scale 0.25/42 normalized cost 0.77387995 min · $12.68
  11. v10Demoting the complementary links won one seed but regressed the next.four-case mean normalized cost 0.795067103 min · $13.94
  12. v11A wider middle-load branch cut cost by 256,227 at scale 0.26.scale 0.26/42 cost 18,057,335 vs v3 18,313,562105 min · $14.44
  13. v12Extending the middle branch to scale 0.28 triggered nonlinear overload.scale 0.28/42 cost 21,459,357 vs v3 20,009,823108 min · $14.95
  14. v13Three demand bands kept the robust extremes and added the useful middle branch.four-case mean 0.794685; scale 0.27/42 cost 19,420,824115 min · $16.37
  15. v14Retiming signals after demand ended added more delay than it drained.scale 0.50/42 cost 78,504,784 vs v13 77,492,469154 min · $22.44
  16. v15Density switching improved target loads but regressed the very-light case.four-case mean 0.792757; scale 0.20/42 cost 13,258,939184 min · $28.76
  17. v16A lower guard exposed the density rule's crossover between scales 0.24 and 0.245.scale 0.24 cost 16,312,443; scale 0.245 cost 16,704,942196 min · $31.35
  18. v17A 300-departure guard selected the measured winner at every tested load.visible mean 0.795282; four-case mean 0.792757197 min · $31.57
  19. v18Extending density switching to every minor link made performance worse.scale 0.25/42 cost 17,212,066 vs v17 17,132,362199 min · $32.15
  20. v19Twenty-second decisions reacted too slowly and left 55 more vehicles unfinished.scale 0.25/42 cost 17,360,765 vs v17 17,132,362202 min · $32.73
  21. v20Five-second decisions changed priority too often and left 94 more vehicles unfinished.scale 0.25/42 cost 17,491,145 vs v17 17,132,362205 min · $33.31
  22. v21Wider hysteresis held the wrong priority too long and left 108 more vehicles unfinished.scale 0.25/42 cost 17,531,728 vs v17 17,132,362213 min · $35.35

On the hidden set

Original metricNormalised score
Starter1.00.0
Frontier-calibrated reference0.7980070.6
This run (GPT-5.6-sol)0.8135430.5539
278 minWall clock
$22.19Spend
31.5MTokens
11Versions, 3 kept

On the visible set

0.80 0.85 0.90 0.95 1.00 0 2 5 8 10 Agent step Normalised cost ↓ v0 v1 v2 v3 v4 v5 v6 v7 v8 v9 v10
keptrolled backsubmitted
  1. v0The agent inherited the city's 2013 fixed-time signal plan1$1.03
  2. v1The agent held every link green at all 625 signalized junctionsSUMO alone arbitrates and --no-internal-links leaves junctions zero-size, so never going red costs no conflicts.0.798522 min · $2.07
  3. v2The agent made every link yield instead of run green0.88474 min · $6.24
  4. v3The agent punched a three-second all-red gap every thirty seconds0.804$6.79
  5. v4The agent lengthened the all-red pulse to five seconds every minute0.8065$7.34
  6. v5The agent stretched the pulse to eight seconds every two minutes0.805$7.89
  7. v6The agent held upstream lights red when a starved approach backed upAll-green meters nothing into a jammed lane, so gap the upstream signals that feed the worst-starved approaches.0.7888111 min · $8.44
  8. v7The agent offset the metering reds by travel time to align gaps0.8705177 min · $14.08
  9. v8The agent searched seven hops upstream instead of four for metering lights0.7904187 min · $15.25
  10. v9The agent rewrote the winning metering in its simplest guarded form0.7888218 min · $19.05
  11. v10The agent triggered metering on waiting time instead of queue length0.7983277 min · $21.82

On the hidden set

Original metricNormalised score
Starter1.00.0
Frontier-calibrated reference0.7980070.6
This run (Opus 5)0.7980070.6000
161 minWall clock
$3.55Spend
13.2MTokens
13Versions, 2 kept

On the visible set

1.000 1.025 1.050 1.075 1.100 1.125 0 2 5 8 10 Agent step Normalised cost ↓ v0 v1 v2 v3 v4 v5 v6 v7 v8 v9 v10 v11 v12
keptrolled backsubmitted
  1. v0The agent inherited the city's original static 2013 signal timing1
  2. v1The agent switched every junction to SUMO's stock actuated timing1.0121
  3. v2The agent recomputed the green splits with the textbook Webster formula1.0125
  4. v3The agent added static green-wave offsets along a minimum spanning tree1.0798
  5. v4The agent let queues gap out and extend each green online1.0132
  6. v5The agent protected arterial greens while letting side streets adaptSplit junctions by role: arterial greens long enough to carry a platoon, side streets short and demand-driven.0.9964
  7. v6The agent weighted greens by pressure and shielded arriving platoonsRank phases by upstream-minus-downstream pressure, and hold green for vehicles already approaching the stop line.0.991
  8. v7The agent split the policy into two load regimes with bottleneck filtering0.995
  9. v8The agent refined the regimes into multi-tier platoon shielding0.9994
  10. v9The agent layered static Webster splits back under its controller1.1136
  11. v10The agent balanced queues by max-pressure across the whole city1.0103
  12. v11The agent tried asymmetric platoon shielding and reproduced the baseline exactly1
  13. v12The agent guarded progression with recalibrated thresholds0.9995

On the hidden set

Original metricNormalised score
Starter1.00.0
Frontier-calibrated reference0.7980070.6
This run (Gemini 3.7 Flash)1.00320.0000
651 minWall clock
$5.47Spend
6.7MTokens
18Versions, 6 kept

On the visible set

0.900 0.925 0.950 0.975 1.000 1.025 0 4 8 12 16 Agent step Normalised cost ↓ v0 v1 v2 v2heavy v3 v4 v5 v6 v7 v8 v8b v9 v10 v11 v12 v13 v14 v15
keptrolled backsubmitted
  1. v0The agent inherited the city's static signal plan1$0.25
  2. v1The agent installed acyclic max-pressure control at every junction1.0137$0.63
  3. v2The agent slowed the switching and forced every stage to be servedSwitching cost, not phase choice, sank v1: longer minimum green and a wider margin stop the yellow churn.0.9388$0.75
  4. v2heavyThe agent retested its winner on heavy hidden-band load probes0.9894$0.86
  5. v3The agent let long-waiting stages preempt the saturated ones1.0288$0.98
  6. v4The agent tried fewer, longer greens with a 25-second minimum0.9333$1.09
  7. v5The agent added a downstream blocking veto that never fired0.9388$1.39
  8. v6The agent counted approaching vehicles too, not only halted onesHalting counts see a platoon only once it stops; counting approaching vehicles buys the green before the queue forms.0.9119$1.67
  9. v7The agent doubled the downstream weight and uncovered a lane-indexing bug0.9119$2.30
  10. v8The agent fixed the out-lane lookup so downstream gating finally workedWith q_out live the pressure term becomes soft gating, holding green off lanes that cannot drain at heavy load.0.9608$2.30
  11. v8bThe agent measured the fixed controller across the full load curve0.9105$2.60
  12. v9The agent weakened the downstream gating weight0.9755$2.90
  13. v10The agent pushed the downstream gating weight much higher0.9804$3.22
  14. v11The agent loosened the switching thresholds and shortened minimum green0.9091$3.64
  15. v12The agent made the switching thresholds adapt to local congestion0.9162$4.06
  16. v13The agent deduplicated the shared lanes within each stage1.025$4.48
  17. v14The agent weighted moving vehicles as heavily as halted ones0.9203$4.90
  18. v15The agent capped green at 45 seconds to bound stage waits0.9223$5.29

On the hidden set

Original metricNormalised score
Starter1.00.0
Frontier-calibrated reference0.7980070.6
This run (Kimi K3)0.9218980.2320
230 minWall clock
$12.00Spend
20.0MTokens
24Versions, 6 kept

On the visible set

0.88 0.92 0.96 1.00 0 5 10 15 20 Agent step Normalised cost ↓ v0 v2 v3 v4 v5 v6 v7 v8 v9 v10 v11 v12 v13 v14 v15 v16 v17 v18 v19 v20 v21 v22 v23
keptrolled backsubmitted
  1. v0The agent inherited the city's original static 2013 signal timings1
  2. v1The agent overwrote program zero and SUMO refused to load itSUMO crash, invalid
  3. v2The agent installed its own actuated plans under a fresh program id0.9885
  4. v3The agent collapsed every multi-phase plan into two or three greensEach short protected phase is a subset of a major's permissive green, so dropping it buys green seconds and blocks no movement.0.901
  5. v4The agent split the greens by demand instead of leaving it to actuation0.8784
  6. v5The agent shortened every yellow from four seconds to three0.8955
  7. v6The agent swapped gap-out actuation for time-loss detectors0.8813
  8. v7The agent raised the maximum green from fifty to sixty seconds0.8895
  9. v8The agent dropped the minimum green so empty approaches end sooner0.886
  10. v9The agent aligned junction offsets into green waves along the corridorsActuation only sees one junction; offsets are the one city-wide term, chaining the corridors into a tree of aligned arrivals.0.8815
  11. v10The agent stretched the green ceiling to seventy seconds0.9124
  12. v11The agent cut the minimum green to five seconds0.8642
  13. v12The agent added a spillback cutoff controller that never fired0.8815
  14. v13The agent tried a long fixed cycle with max-pressure early cuts1.0143
  15. v14The agent tried a pure fixed cycle with no actuation at all0.9361
  16. v15The agent tightened the gap-out headway to 2.5 seconds0.8645
  17. v16The agent loosened the gap-out headway to 3.5 seconds0.8701
  18. v17The agent keyed yellow length to each junction's original clearance time0.865
  19. v18The agent wrote a queue-stealing controller that silently did nothing0.8815
  20. v19The agent let hungry approaches steal green from the running phasePut one feedback term back on the fixed offsets: let a starved approach cut in instead of waiting the gap timer out.0.897
  21. v20The agent gated the stealing to short queues at quiet junctions0.889
  22. v21The agent spared the green-wave junctions from the stealing rule0.8674
  23. v22The agent kept the lagging left-turn greens alive through the transition0.9122
  24. v23The agent allowed stealing only while the network was still filling0.886

On the hidden set

Original metricNormalised score
Starter1.00.0
Frontier-calibrated reference0.7980070.6
This run (Grok 4.6)0.9049960.2822
379 minWall clock
$3.19Spend
39.3MTokens
8Versions, 0 kept

On the visible set

0.95 1.00 1.05 1.10 1.15 0 75 150 225 300 Agent step Normalised cost ↓ v1 v2 v3 v4 v5 v6 v7 v8
keptrolled backsubmitted
  1. v1The agent sized greens in proportion to the in-lane halting queues1.0753 min · $0.66
  2. v2The agent scored phases by pressure with soft spillback protection1.169862 min · $0.83
  3. v3The agent retimed splits to demand and capped the yellows0.999562 min · $0.83
  4. v4The agent forced one common ninety-second cycle with phase-aware offsets0.99784 min · $1.15
  5. v5The agent trimmed empty or blocked greens without ever jumping phase1.13110 min · $1.47
  6. v6The agent gated its green trimming on measured network load1.0706155 min · $1.81
  7. v7The agent detected spillback by queue tail length instead of occupancy0.9946193 min · $2.05
  8. v8The agent capped the long inherited yellows at three seconds0.965346 min · $2.88

On the hidden set

Original metricNormalised score
Starter1.00.0
Frontier-calibrated reference0.7980070.6
This run (DeepSeek V4 Pro)0.9703230.0882
472 minWall clock
$38.53Spend
74.8MTokens
27Versions, 12 kept

On the visible set

1.0 1.2 1.4 1.6 1.8 0 8 15 22 Agent step Normalised cost ↓ v0 v1 v2 v3 v4 v5 v6 v7 v8 v9 v10 v11 v12 v13 v14 v15 v17 v18 v19 v20 v21 v22 v23 v25 v26
keptrolled backsubmitted
  1. v0The agent inherited the city's static signal plan111 min · $0.57
  2. v1The agent installed acyclic max-pressure control at every junction1.6116 min · $0.97
  3. v2The agent kept the cyclic order but sized greens to demand1.01976 min · $3.23
  4. v3The agent counted all approaching vehicles so the freeways stopped starving1.016106 min · $4.81
  5. v4The agent added gap-out extension and one stage monopolized the junction1.759105 min · $4.76
  6. v5The agent left the rush hour alone and optimized only the drain0.9884133 min · $6.17
  7. v6The agent reached back into the rush hour with uncapped green extension1.751155 min · $7.84
  8. v7The agent capped the runaway greens at eighty seconds1.0835173 min · $8.94
  9. v8The agent synchronized each junction's start phase to the static plan1.0315183 min · $9.93
  10. v9The agent drained aggressively only when the city was not already jammed0.9787234 min · $13.49
  11. v10The agent gave jammed cities a gentler static-plus drain instead0.9787261 min · $15.80
  12. v11The agent took junctions over only at quiet green boundaries1.0138307 min · $19.65
  13. v12The agent capped the drain yellows at four seconds0.9663$20.85
  14. v13The agent cut the drain yellows to three seconds0.9505$22.04
  15. v14The agent cut the drain yellows to two seconds0.9294348 min · $23.24
  16. v15The agent cut the drain yellow down to a single second0.9284$23.24
  17. v16The agent removed yellow entirely and the run nearly blew the wall-clock budgetaborted, >16 min CPU348 min · $23.24
  18. v17The agent raised the drain green cap to 150 seconds0.9284379 min · $27.40
  19. v18The agent allotted 2.5 seconds of green per queued vehicle0.9325$28.40
  20. v19The agent forced the aggressive drain on at mid load0.9295$29.39
  21. v20The agent forced the same drain on at heavy load0.976$30.39
  22. v21The agent dropped the congestion switch and always evacuated at demand end0.9285$31.38
  23. v22The agent lowered the drain minimum green to five seconds0.9323$32.38
  24. v23The agent lowered the trickle occupancy gate to ninety-five percent0.9284$33.38
  25. v24The agent snapshotted its shipped controller without logging or measuring itsnapshot only$34.37
  26. v25The agent served the longest queue first instead of cycling fairly1.1362446 min · $35.37
  27. v26The agent allotted 1.7 seconds of green per queued vehicle0.9386453 min · $36.57

On the hidden set

Original metricNormalised score
Starter1.00.0
Frontier-calibrated reference0.7980070.6
This run (Qwen3.8 Max)0.9498180.1491
293 minWall clock
$13.20Spend
45.8MTokens
7Versions, 3 kept

On the visible set

0.8 0.9 1.0 1.1 1.2 0 2 3 4 6 Agent step Normalised cost ↓ v0 v1 v2 v3 v4 duty50 shortcycle
keptrolled backsubmitted
  1. v0The agent inherited the city's fixed-time 2013 signal plan112 min · $0.36
  2. v1The agent held every link green at all 625 signalized junctions0.7985$1.62
  3. v2The agent gated links online whenever the lane they fed grew dense0.895967 min · $2.89
  4. v3The agent gated the metering on a raw vehicle-count threshold0.976$7.79
  5. v4The agent metered only the lights feeding the busiest unsignalized junctions0.7911286 min · $12.70
  6. duty50The agent pulsed the whole city thirty seconds green, thirty red0.9772$12.95
  7. shortcycleThe agent kept the original phases on a short eight-second cycle1.2009$12.95

On the hidden set

Original metricNormalised score
Starter1.00.0
Frontier-calibrated reference0.7980070.6
This run (GLM 5.3)0.8118890.5588
253 minWall clock
$16.09Spend
25.0MTokens
21Versions, 10 kept

On the visible set

0.88 0.92 0.96 1.00 1.04 1.08 0 5 10 15 20 Agent step Normalised cost ↓ v0 v1 v2 v3 v4 v5 v6 v7 v8 v9 v10 v11 v12 v13 v14 v15 v16 v17 v18 v19 v20
keptrolled backsubmitted
  1. v0The agent inherited the city's no-op fixed-time signal timing18 min · $0.38
  2. v1The agent tried online max-pressure control over the original green phases1.064215 min · $0.95
  3. v2The agent shortened the yellows and gave the time back to green0.961824 min · $1.69
  4. v3The agent pushed the yellows down to a tenth of a second0.978427 min · $1.98
  5. v4The agent shortened the yellows without redistributing the saved time0.933335 min · $2.44
  6. v5The agent scaled every green to three quarters of its length0.907542 min · $2.87
  7. v6The agent halved every green duration0.896449 min · $3.29
  8. v7The agent settled on sixty percent of the original green lengths0.893757 min · $3.73
  9. v8The agent probed fifty-five percent green scaling0.897565 min · $4.17
  10. v9The agent probed sixty-five percent green scaling0.905272 min · $4.62
  11. v10The agent put a four-second floor under the shortest phases0.899280 min · $5.08
  12. v11The agent scattered the cycle offsets pseudo-randomly across the junctions0.896788 min · $5.77
  13. v12The agent added mild actuation on top of its static plan0.899597 min · $6.45
  14. v13The agent read the load at startup and picked between two plans0.8915176 min · $9.79
  15. v14The agent scaled the greens to forty percent of their length0.8843206 min · $12.01
  16. v15The agent scaled them to thirty percent and starved the mid-load movements0.9006206 min · $12.01
  17. v16The agent rebuilt the load switch around its forty-percent plan0.8843217 min · $12.79
  18. v17The agent tried thirty-five percent green scaling0.8793239 min · $14.35
  19. v18The agent gave each of three load bands its own green scaling0.874252 min · $15.79
  20. v19The agent nudged the light branch up to thirty-six percent0.8746$15.94
  21. v20The agent nudged the light branch down to thirty-four percent0.8753$15.94

On the hidden set

Original metricNormalised score
Starter1.00.0
Frontier-calibrated reference0.7980070.6
This run (GPT-5.5)0.9044340.2839

Leaderboard

Where each run landed on the sealed held-out set, on the same normalised-score scale as the anchors above.

0 0.3 0.6 1.0 1 Opus 5 claude code · max 0.600 2 GLM 5.3 claude code · max 0.559 3 GPT-5.6-sol codex · max 0.554 4 GPT-5.5 codex · xhigh 0.284 5 Grok 4.6 grok · xhigh 0.282 6 Kimi K3 kimi cli · max 0.232 7 Qwen3.8 Max qwen coder · xhigh 0.149 8 DeepSeek V4 Pro claude code · max 0.088 9 Gemini 3.7 Flash antigravity · high 0.000