AntHocNet 2.0.0
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: 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,
94 Time time, NodeAddress firstHop, double factor,
95 double factorNewHop);
96
97 /// Claim one broadcast of this generation *at this node* (#173). Returns
98 /// false once `maxBroadcasts` have already been claimed; `maxBroadcasts < 0`
99 /// means unlimited.
100 ///
101 /// This is the flood bound for reactive forward ants. `accept()` cannot
102 /// serve as one: it admits rather than suppresses, so in a dense graph a
103 /// node keeps re-broadcasting the same generation as comparable copies
104 /// arrive from each neighbour, and each re-broadcast seeds more admissible
105 /// copies. Counting *per (node, generation)* bounds that without limiting
106 /// reach — unlike a budget carried on the ant and decremented at each hop,
107 /// which is a hop limit on discovery (#169).
108 bool allowBroadcast(NodeAddress src, std::uint32_t seqNum, int maxBroadcasts);
109
110 /// Generations currently resident. Mirrors AntHistoryTracker::size(); the
111 /// cap it is checked against is the golden-rule-5 bound (#166).
112 std::size_t size() const { return best_.size(); }
113
114 void clear();
115
116private:
117 struct Best {
118 std::uint32_t hops;
119 Time time;
120 int broadcasts;
121 /// First hops of the ants admitted for this generation, capped at
122 /// kMaxFirstHops. A vector, not a set: it holds <= 8 elements, so a
123 /// linear scan beats a node-per-entry container.
124 std::vector<NodeAddress> firstHops;
125 };
126 using Key = std::pair<NodeAddress, std::uint32_t>;
127
128 std::size_t maxEntries_;
129 std::map<Key, Best> best_;
130 std::deque<Key> insertionOrder_; // for FIFO eviction
131};
132
133} // namespace core
134} // namespace anthocnet
135
136#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