AntHocNet 2.0.0
Paper-faithful ant-colony ad hoc routing: the shared core and its adapters
Loading...
Searching...
No Matches
shortest_path.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 * Single-source shortest paths over an explicit graph (issue #296 item 1,
6 * #216).
7 *
8 * This is NOT part of the AntHocNet protocol and no protocol code calls it.
9 * It is the computation behind the **oracle control arm** — the
10 * global-knowledge upper bound the benchmark suites lack: Dijkstra over the
11 * ground-truth topology, replayed as an ns-3 routing protocol
12 * (`ns3/oracle/`). It lives in `core/` for one reason: it is
13 * simulator-agnostic logic, and AGENTS.md rule 7 wants logic covered by a
14 * core unit test rather than only by a simulator run.
15 *
16 * What it computes
17 * ----------------
18 * `computeFrom(source)` runs Dijkstra and stores, for every node, the
19 * distance from the source and the **first hop** on a shortest path — the
20 * neighbour the source must hand the packet to. First-hop-from-source is
21 * exactly what a routing table needs, and propagating it during relaxation
22 * (`firstHop[v] = (u == source) ? v : firstHop[u]`) avoids walking a
23 * predecessor chain per destination.
24 *
25 * Determinism
26 * -----------
27 * Equal-cost shortest paths are ubiquitous in the topologies this serves (a
28 * +Grid ISL torus is almost nothing but ties, and a dense wifi field has
29 * many). An arbitrary tie-break would make the oracle's routes depend on
30 * container iteration order, i.e. on the ns-3 build — the reproducibility
31 * failure #352 was about, in a different guise. So the tie-break is part of
32 * the contract: **among equal-cost shortest paths the one with the
33 * numerically smallest first hop wins**, which makes the whole next-hop table
34 * a pure function of the edge set.
35 *
36 * Weights are non-negative doubles; the oracle uses 1.0 per edge (hop count),
37 * which is what makes "the oracle's hop count is a lower bound on every
38 * protocol's" an assertion rather than an expectation.
39 */
40#ifndef ANTHOCNET_CORE_SHORTEST_PATH_H
41#define ANTHOCNET_CORE_SHORTEST_PATH_H
42
43#include <cstddef>
44#include <limits>
45#include <vector>
46
47namespace anthocnet {
48namespace core {
49
51 public:
52 /// Returned by firstHopTo() when there is no path (and for the source).
53 static const int kNoNode = -1;
54 /// Returned by distanceTo() when there is no path.
55 static double unreachable() { return std::numeric_limits<double>::infinity(); }
56
57 /// A graph over node ids [0, nodeCount).
59
60 int nodeCount() const { return static_cast<int>(m_adj.size()); }
61
62 /**
63 * Add a DIRECTED edge. Callers modelling a bidirectional radio/ISL link
64 * add both directions; the oracle does, because a one-way link is not a
65 * usable route.
66 *
67 * Throws std::invalid_argument on an out-of-range endpoint or a negative
68 * weight — both are caller bugs that would otherwise surface as a wrong
69 * route rather than as a failure.
70 */
71 void addEdge(int from, int to, double weight = 1.0);
72
73 /// Number of directed edges added (the oracle reports it as a diagnostic).
74 std::size_t edgeCount() const { return m_edges; }
75
76 /// Run Dijkstra from `source`. Results are readable until the next call.
78
79 /// The source of the last computeFrom(), or kNoNode before the first.
80 int source() const { return m_source; }
81
82 /// Cost of the shortest path source -> node, or unreachable().
83 double distanceTo(int node) const;
84
85 /**
86 * The node after `source` on the chosen shortest path to `node`:
87 * kNoNode when unreachable, and kNoNode for the source itself (a node
88 * needs no first hop to reach itself).
89 */
90 int firstHopTo(int node) const;
91
92 private:
93 struct Edge {
94 int to;
95 double weight;
96 };
97
98 std::vector<std::vector<Edge> > m_adj;
99 std::vector<double> m_dist;
100 std::vector<int> m_firstHop;
101 std::size_t m_edges;
102 int m_source;
103};
104
105} // namespace core
106} // namespace anthocnet
107
108#endif // ANTHOCNET_CORE_SHORTEST_PATH_H
int source() const
The source of the last computeFrom(), or kNoNode before the first.
static const int kNoNode
Returned by firstHopTo() when there is no path (and for the source).
void computeFrom(int source)
Run Dijkstra from source. Results are readable until the next call.
double distanceTo(int node) const
Cost of the shortest path source -> node, or unreachable().
void addEdge(int from, int to, double weight=1.0)
Add a DIRECTED edge.
ShortestPathGraph(int nodeCount)
A graph over node ids [0, nodeCount).
int firstHopTo(int node) const
The node after source on the chosen shortest path to node: kNoNode when unreachable,...
std::size_t edgeCount() const
Number of directed edges added (the oracle reports it as a diagnostic).
static double unreachable()
Returned by distanceTo() when there is no path.
AntHistoryTracker: (src, seqNum) duplicate detection.
Definition ant_history.h:24