You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Since PR #170 (the #169 hop-cap fix) landed on main, a single route discovery in a dense graph cost a combinatorial number of control packets — 30,090 reactive ants in a 7×7 testbench grid. In ns-3 it collapsed the two dense/large scenarios:
scenario
PDR before → after
NRL before → after
large-scale (100 nodes)
75.8 → 21.7
99.9 → 3071.1 (30×)
heavy-load (40 flows)
85.0 → 51.4
6.1 → 28.6
paper-base
81.7 → 82.2
59.1 → 84.8
high-mobility
82.4 → 85.8
55.9 → 72.2
dense-small
37.4 → 37.3
4.4 → 5.0
sparse-static
83.8 → 93.0
48.3 → 46.5
AODV/OLSR/DSDV were byte-identical across the two runs (untouched code, identical seeds), so this was ours. Source: the per-merge benchmarks refresh, 7835df4 → 60ab6ff, the first taxonomy measured after both #167 and #170.
#169's diagnosis was right and was not reverted — the sparse-static row is the proof: 83.8 → 93.0, ahead of AODV's 81.9, with the static/sparse inversion gone. The bug was that removing that bound left reactive forward ants with no flood bound.
Root cause: #96 and #170 each removed one of the two bounds
With enableMultipath on (the default), a reactive forward ant took the first branch and so never touched history_ — strict (src,seq) duplicate suppression did not apply to it. GenerationTracker::accept() is not a suppressor: it admits any later same-generation copy within antAcceptanceFactor (1.5) of the best so far. In a dense graph a node receives the same generation from many neighbours at comparable cost, admits repeatedly, and each re-broadcast seeds more admissible copies.
Until PR #170 this was truncated by reactiveMaxBroadcasts = 2. Once that became -1, the only remaining ceiling was maxPathLength = 100 — no bound at all at these node counts. Each change was individually justified; nobody checked the interaction, and #169's own test used a line topology, where nothing can multiply.
Reproduction
core/tests/test_reactive_flood_bound.cpp — an 8-connected grid (dense and with a distant destination; a line shows nothing, a full mesh makes the destination a direct neighbour so discovery never runs):
Bound re-broadcasts per (node, generation) instead of per ant-path: GenerationTracker gains a broadcast counter per generation, reactiveMaxBroadcasts is re-specified as that per-node bound (default 2), and a node that exhausts its allowance may still unicast-forward along pheromone, so reach is unaffected — verified by test_reactive_hop_reach.cpp, which still passes at 9 hops.
Summary
Since PR #170 (the #169 hop-cap fix) landed on
main, a single route discovery in a dense graph cost a combinatorial number of control packets — 30,090 reactive ants in a 7×7 testbench grid. In ns-3 it collapsed the two dense/large scenarios:AODV/OLSR/DSDV were byte-identical across the two runs (untouched code, identical seeds), so this was ours. Source: the per-merge
benchmarksrefresh,7835df4→60ab6ff, the first taxonomy measured after both #167 and #170.#169's diagnosis was right and was not reverted — the
sparse-staticrow is the proof: 83.8 → 93.0, ahead of AODV's 81.9, with the static/sparse inversion gone. The bug was that removing that bound left reactive forward ants with no flood bound.Root cause: #96 and #170 each removed one of the two bounds
core/src/ant_router_logic.cpp:With
enableMultipathon (the default), a reactive forward ant took the first branch and so never touchedhistory_— strict(src,seq)duplicate suppression did not apply to it.GenerationTracker::accept()is not a suppressor: it admits any later same-generation copy withinantAcceptanceFactor(1.5) of the best so far. In a dense graph a node receives the same generation from many neighbours at comparable cost, admits repeatedly, and each re-broadcast seeds more admissible copies.Until PR #170 this was truncated by
reactiveMaxBroadcasts = 2. Once that became-1, the only remaining ceiling wasmaxPathLength = 100— no bound at all at these node counts. Each change was individually justified; nobody checked the interaction, and #169's own test used a line topology, where nothing can multiply.Reproduction
core/tests/test_reactive_flood_bound.cpp— an 8-connected grid (dense and with a distant destination; a line shows nothing, a full mesh makes the destination a direct neighbour so discovery never runs):multipath=offFix (PR #174)
Bound re-broadcasts per
(node, generation)instead of per ant-path:GenerationTrackergains a broadcast counter per generation,reactiveMaxBroadcastsis re-specified as that per-node bound (default 2), and a node that exhausts its allowance may still unicast-forward along pheromone, so reach is unaffected — verified bytest_reactive_hop_reach.cpp, which still passes at 9 hops.ns-3 verification
Run 30165318267, PDR / NRL:
mainClosing as the regression is resolved:
large-scale21.7 → 77.9 with NRL down 18×, and every scenario at or above v1.0.0 exceptheavy-load.Two things are explicitly not claimed, and both are carried forward in #177:
heavy-loadis not fully recovered — 80.1 vs 85.0 pre-fix(core): stop bounding reactive floods — a broadcast budget is a hop limit (#169) #170, still behind AODV's 86.6.pdr_sdis 4.56 at 2 runs so some is dispersion, but not all of it.runs=5.All numbers above are 2-run
--quickvalues and need aruns=5confirmation before being quoted anywhere.