A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
adjacency-matrix-example.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2025 CTTC
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Author: Gabriel Ferreira <gabrielcarvfer@gmail.com>
7 */
8
9/**
10 * @file
11 * @ingroup antenna-examples
12 * Example program illustrating one application of symmetric adjacency matrices for routing
13 */
14
15#include "ns3/command-line.h"
16#include "ns3/symmetric-adjacency-matrix.h"
17
18#include <algorithm>
19#include <iostream>
20#include <limits>
21#include <map>
22
23int
24main(int argc, char** argv)
25{
26 char srcNodeOpt = 'A'; // 0
27 char dstNodeOpt = 'I'; // 8
28 ns3::CommandLine cmd(__FILE__);
29 cmd.AddValue("srcNode", "Source node [0-9]", srcNodeOpt);
30 cmd.AddValue("dstNode", "Destination node [0-9]", dstNodeOpt);
31 cmd.Parse(argc, argv);
32
33 NS_ABORT_MSG_IF(srcNodeOpt < 'A' || srcNodeOpt > 'J', "Invalid source node");
34 NS_ABORT_MSG_IF(dstNodeOpt < 'A' || dstNodeOpt > 'J', "Invalid destination node");
35
36 // -A(65) remove the skew from 0
37 srcNodeOpt -= 'A';
38 dstNodeOpt -= 'A';
39
40 constexpr float maxFloat = std::numeric_limits<float>::max();
41 // Create routing weight matrix for 10 nodes and initialize weights to infinity (disconnected)
42 ns3::SymmetricAdjacencyMatrix<float> routeWeights(10, maxFloat);
43
44 /* Let's add the entries of this network topology to the matrix
45 *
46 * Node | Corresponding matrix row
47 * A | 0
48 * B | 1
49 * C | 2
50 * D | 3
51 * E | 4
52 * F | 5
53 * G | 6
54 * H | 7
55 * I | 8
56 * J | 9
57 *
58 * A------5-------B-------------14-------C
59 * \ \ /1|
60 * \ 3 J |
61 * \ \ /1 | 7
62 * 4 E-2-F--4---G--3--H |
63 * \ 8 / \ |
64 * D-------- 10--I
65 */
66
67 // Distance from nodes to other nodes
68 routeWeights.SetValue(0, 1, 5); // A-B=5
69 routeWeights.SetValue(1, 2, 14); // B-C=14
70 routeWeights.SetValue(0, 3, 4); // A-D=4
71 routeWeights.SetValue(1, 5, 3); // B-F=3
72 routeWeights.SetValue(2, 9, 1); // C-J=1
73 routeWeights.SetValue(9, 7, 1); // J-H=1
74 routeWeights.SetValue(2, 8, 7); // C-I=7
75 routeWeights.SetValue(3, 4, 8); // D-E=8
76 routeWeights.SetValue(4, 5, 2); // E-F=2
77 routeWeights.SetValue(5, 6, 4); // F-G=4
78 routeWeights.SetValue(6, 7, 3); // G-H=3
79 routeWeights.SetValue(7, 8, 10); // H-I=10
80
81 // Distance from nodes to themselves is zero
82 for (size_t i = 0; i < routeWeights.GetRows(); i++)
83 {
84 routeWeights.SetValue(i, i, 0);
85 }
86
87 std::map<std::pair<int, int>, std::vector<int>> routeMap;
88 // Initialize routes
89 for (size_t i = 0; i < routeWeights.GetRows(); i++)
90 {
91 for (size_t j = 0; j < routeWeights.GetRows(); j++)
92 {
93 if (routeWeights.GetValue(i, j) != maxFloat)
94 {
95 if (i != j)
96 {
97 routeMap[{i, j}] = {(int)i, (int)j};
98 }
99 else
100 {
101 routeMap[{i, j}] = {(int)i};
102 }
103 }
104 }
105 }
106 // Compute every single shortest route between the nodes of the graph (represented by the
107 // adjacency matrix) We do this in multiple iterations, until we fill the entire matrix
108 for (size_t bridgeNode = 0; bridgeNode < routeWeights.GetRows(); bridgeNode++)
109 {
110 for (size_t srcNode = 0; srcNode < routeWeights.GetRows(); srcNode++)
111 {
112 for (size_t dstNode = 0; dstNode < routeWeights.GetRows(); dstNode++)
113 {
114 auto weightA = routeWeights.GetValue(srcNode, bridgeNode);
115 auto weightB = routeWeights.GetValue(bridgeNode, dstNode);
116 // If there is a path between A and bridge, plus bridge and B
117 if (std::max(weightA, weightB) == maxFloat)
118 {
119 continue;
120 }
121 // Check if sum of weights is lower than existing path
122 auto weightAB = routeWeights.GetValue(srcNode, dstNode);
123 if (weightA + weightB < weightAB)
124 {
125 // If it is, update adjacency matrix with the new weight of the shortest
126 // path
127 routeWeights.SetValue(srcNode, dstNode, weightA + weightB);
128
129 // Retrieve the partial routes A->bridge and bridge->C,
130 // and assemble the new route A->bridge->C
131 const auto srcToBridgeRoute = routeMap.at({srcNode, bridgeNode});
132 const auto bridgeToDstRoute = routeMap.at({bridgeNode, dstNode});
133 std::vector<int> dst;
134 dst.insert(dst.end(), srcToBridgeRoute.begin(), srcToBridgeRoute.end());
135 dst.insert(dst.end(), bridgeToDstRoute.begin() + 1, bridgeToDstRoute.end());
136 routeMap[{srcNode, dstNode}] = dst;
137
138 // We also include the reverse path, since the graph is bidirectional
139 std::vector<int> invDst(dst.rbegin(), dst.rend());
140 routeMap[{dstNode, srcNode}] = invDst;
141 }
142 }
143 }
144 }
145
146 // Now we can print the shortest route between srcNode and dstNode
147 std::cout << "shortest route between " << (char)(srcNodeOpt + 'A') << " and "
148 << (char)(dstNodeOpt + 'A') << " (length "
149 << routeWeights.GetValue(srcNodeOpt, dstNodeOpt) << "):";
150 auto lastNodeNumber = srcNodeOpt;
151 for (auto nodeNumber : routeMap.at({srcNodeOpt, dstNodeOpt}))
152 {
153 std::cout << "--" << routeWeights.GetValue(lastNodeNumber, nodeNumber) << "-->"
154 << (char)('A' + nodeNumber);
155 lastNodeNumber = nodeNumber;
156 }
157 std::cout << std::endl;
158 return 0;
159}
Parse command-line arguments.
A class representing a symmetric adjacency matrix.
#define NS_ABORT_MSG_IF(cond, msg)
Abnormal program termination if a condition is true, with a message.
Definition abort.h:97