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