AntHocNet 2.6.1
Paper-faithful ant-colony ad hoc routing: the shared core and its adapters
Loading...
Searching...
No Matches
ant_history.h
Go to the documentation of this file.
1// SPDX-License-Identifier: MIT OR GPL-2.0-only
2// Copyright (C) 2026 Daniel Henrique Joppi
3
4/**
5 * AntHistoryTracker: (src, seqNum) duplicate detection.
6 *
7 * Replaces the unbounded std::set<AntHistory> that lived in AntNest. The set
8 * grew for the entire run; here it is capped (FIFO eviction) so memory stays
9 * bounded on long simulations.
10 */
11#ifndef ANTHOCNET_CORE_ANT_HISTORY_H
12#define ANTHOCNET_CORE_ANT_HISTORY_H
13
14#include <cstddef>
15#include <cstdint>
16#include <deque>
17#include <map>
18#include <set>
19#include <utility>
20#include <vector>
21
23
24namespace anthocnet {
25namespace core {
26
28public:
29 /// maxEntries == 0 means unbounded.
30 explicit AntHistoryTracker(std::size_t maxEntries) : maxEntries_(maxEntries) {}
31
32 /// Record (src, seq). Returns true if it was new, false if already seen
33 /// (i.e. a looping/duplicate ant that should be dropped).
34 bool record(NodeAddress src, std::uint32_t seqNum);
35
36 /// Read-only membership test.
37 bool seen(NodeAddress src, std::uint32_t seqNum) const;
38
39 std::size_t size() const { return entries_.size(); }
40 void clear();
41
42private:
43 using Key = std::pair<NodeAddress, std::uint32_t>;
44
45 std::size_t maxEntries_;
46 std::set<Key> entries_;
47 std::deque<Key> insertionOrder_; // for FIFO eviction
48};
49
50/// Multipath acceptance filter for reactive forward ants ([1] §3.1, issue #96).
51/// Tracks, per (src, seq) generation, the best (fewest-hop / least-time) ant
52/// seen, and admits a later same-generation ant only when both its hops and its
53/// travel time are within an acceptance factor of that best — so several *good*
54/// paths get laid down instead of only the first-arriving one. Bounded FIFO like
55/// AntHistoryTracker (golden rule 5).
56///
57/// The factor is not a single number (#177). The 2007 thesis applies a
58/// *low* base factor a1 (0.9) to ants whose first hop has already been seen, and
59/// a *higher* factor a2 (2.0) to an ant arriving over a first hop no previously
60/// accepted ant of that generation used — "to boost the creation of disjoint
61/// paths" (thesis lines 4655-4659 and 4667-4671, quoted in config.h). So the
62/// tracker also records, per generation, which first hops it has admitted.
64public:
65 /// Cap on the per-generation set of admitted first hops (golden rule 5).
66 ///
67 /// The set only has to answer "have I already admitted an ant that came in
68 /// via this first hop?", and it is consulted only to *relax* the band, so a
69 /// small cap costs nothing but bounds the memory a single generation can
70 /// pin. 8 is the neighbourhood scale these grids/scenarios run at (the
71 /// 8-connected testbench grid has interior degree 8), i.e. large enough
72 /// that a node normally never reaches it.
73 ///
74 /// Behaviour at the cap is deliberately the *restrictive* one: once 8
75 /// distinct first hops have been admitted for a generation, further unseen
76 /// first hops are treated as already seen and judged against a1. The node
77 /// has by then already granted the disjointness boost eight times, and the
78 /// alternative — keep granting a2 to every new first hop forever — would
79 /// make the relaxation the very unbounded term the cap exists to prevent.
80 static const std::size_t kMaxFirstHops = 8;
81
82 /// maxEntries == 0 means unbounded.
83 explicit GenerationTracker(std::size_t maxEntries) : maxEntries_(maxEntries) {}
84
85 /// Decide whether to forward a reactive forward ant carrying `hops`/`time`
86 /// and whose path's first hop after the source is `firstHop`.
87 ///
88 /// The first ant of a generation is always admitted; a later one only if
89 /// `hops <= f*bestHops && time <= f*bestTime`, where `f` is `factorNewHop`
90 /// (a2) when `firstHop` is not among those already admitted for this
91 /// generation and `factor` (a1) when it is. Admitted ants refresh the
92 /// per-metric minimums and record their first hop. Returns false to drop.
93 bool accept(NodeAddress src, std::uint32_t seqNum, std::uint32_t hops, Time time,
94 NodeAddress firstHop, double factor, double factorNewHop);
95
96 /// Claim one broadcast of this generation *at this node* (#173). Returns
97 /// false once `maxBroadcasts` have already been claimed; `maxBroadcasts < 0`
98 /// means unlimited.
99 ///
100 /// This is the flood bound for reactive forward ants. `accept()` cannot
101 /// serve as one: it admits rather than suppresses, so in a dense graph a
102 /// node keeps re-broadcasting the same generation as comparable copies
103 /// arrive from each neighbour, and each re-broadcast seeds more admissible
104 /// copies. Counting *per (node, generation)* bounds that without limiting
105 /// reach — unlike a budget carried on the ant and decremented at each hop,
106 /// which is a hop limit on discovery (#169).
107 bool allowBroadcast(NodeAddress src, std::uint32_t seqNum, int maxBroadcasts);
108
109 /// Generations currently resident. Mirrors AntHistoryTracker::size(); the
110 /// cap it is checked against is the golden-rule-5 bound (#166).
111 std::size_t size() const { return best_.size(); }
112
113 void clear();
114
115private:
116 struct Best {
117 std::uint32_t hops;
118 Time time;
119 int broadcasts;
120 /// First hops of the ants admitted for this generation, capped at
121 /// kMaxFirstHops. A vector, not a set: it holds <= 8 elements, so a
122 /// linear scan beats a node-per-entry container.
123 std::vector<NodeAddress> firstHops;
124 };
125 using Key = std::pair<NodeAddress, std::uint32_t>;
126
127 std::size_t maxEntries_;
128 std::map<Key, Best> best_;
129 std::deque<Key> insertionOrder_; // for FIFO eviction
130};
131
132} // namespace core
133} // namespace anthocnet
134
135#endif // ANTHOCNET_CORE_ANT_HISTORY_H
AntHistoryTracker(std::size_t maxEntries)
maxEntries == 0 means unbounded.
Definition ant_history.h:30
bool seen(NodeAddress src, std::uint32_t seqNum) const
Read-only membership test.
bool record(NodeAddress src, std::uint32_t seqNum)
Record (src, seq).
Multipath acceptance filter for reactive forward ants ([1] §3.1, issue #96).
Definition ant_history.h:63
GenerationTracker(std::size_t maxEntries)
maxEntries == 0 means unbounded.
Definition ant_history.h:83
std::size_t size() const
Generations currently resident.
bool allowBroadcast(NodeAddress src, std::uint32_t seqNum, int maxBroadcasts)
Claim one broadcast of this generation at this node (#173).
bool accept(NodeAddress src, std::uint32_t seqNum, std::uint32_t hops, Time time, NodeAddress firstHop, double factor, double factorNewHop)
Decide whether to forward a reactive forward ant carrying hops/time and whose path's first hop after ...
static const std::size_t kMaxFirstHops
Cap on the per-generation set of admitted first hops (golden rule 5).
Definition ant_history.h:80
double Time
Simulation time, in seconds.
Definition types.h:24
std::int32_t NodeAddress
Network-layer node address.
Definition types.h:21
AntHistoryTracker: (src, seqNum) duplicate detection.
Definition ant_history.h:24