1 | |
---|
2 | // This computes the all paris shortest paths between the various nodes in the |
---|
3 | // graph. It can be used to induce a graph from another (that is, to remove |
---|
4 | // edges not used by the shortest paths) |
---|
5 | class routing { |
---|
6 | public: |
---|
7 | typedef vector<graph::node *> idx_to_node_t; |
---|
8 | typedef vector<string> idx_to_node_name_t; |
---|
9 | typedef map<string, int> node_name_to_idx_t; |
---|
10 | typedef enum {SHORT, LONG, NONE} output_format; |
---|
11 | |
---|
12 | protected: |
---|
13 | const graph& g; // The graph to route in |
---|
14 | int size; // The graph size (number of nodes) |
---|
15 | int **cost; // The cost of the path from node i to j |
---|
16 | int **path; // The next hop from i to j (an index) |
---|
17 | idx_to_node_t idx_to_node; // Map from the index to the node in g |
---|
18 | idx_to_node_name_t idx_to_node_name;// map from index to name in g |
---|
19 | node_name_to_idx_t node_name_to_idx;// Map from name to idx |
---|
20 | static const int infinity = 1000000; |
---|
21 | |
---|
22 | // Print the path from from to to into str, recursively as nodenames |
---|
23 | // separated by slashes. |
---|
24 | void pathstring(int from, int to, ostringstream& str) const { |
---|
25 | if (path[from][to] !=-1) { |
---|
26 | pathstring(from, path[from][to], str); |
---|
27 | str << idx_to_node_name[path[from][to]] << "/"; |
---|
28 | pathstring(path[from][to], to, str); |
---|
29 | } |
---|
30 | } |
---|
31 | |
---|
32 | // Print the path from from to to into str, recursively as indices |
---|
33 | // separated by slashes. |
---|
34 | void path_ints(int from, int to, ostringstream& str) const { |
---|
35 | |
---|
36 | if (path[from][to] !=-1) { |
---|
37 | path_ints(from, path[from][to], str); |
---|
38 | str << path[from][to] << "/"; |
---|
39 | path_ints(path[from][to], to, str); |
---|
40 | } |
---|
41 | } |
---|
42 | |
---|
43 | // Put the path from from to to into v in order, as indices |
---|
44 | void path_ints_deque(int from, int to, deque<int>& v) const { |
---|
45 | if (path[from][to] != -1) { |
---|
46 | path_ints_deque(from, path[from][to], v); |
---|
47 | v.push_back(path[from][to]); |
---|
48 | path_ints_deque(path[from][to], to, v); |
---|
49 | } |
---|
50 | } |
---|
51 | |
---|
52 | int next_hop(int src, int dest) const { |
---|
53 | // Find the next hop between src and dest. The path member stores |
---|
54 | // this, but in an unusual way. path[i][j] is a node |
---|
55 | // through which the shortest path between i and j passes, but may |
---|
56 | // not be adjacent to i (or j). This member recursively asks for |
---|
57 | // the path until it finds a node adjacent to src in the graph. |
---|
58 | if (path[src][dest] == dest || path[src][dest] == -1) return dest; |
---|
59 | else return next_hop(src, path[src][dest]); |
---|
60 | } |
---|
61 | |
---|
62 | public: |
---|
63 | // The initializer does the all pairs shortest path calculation |
---|
64 | // (Floyd's algorithm). This is n^3 in size of the graph, so don't |
---|
65 | // make a routing object until/unless you need one. If debug is set, |
---|
66 | // the number of times through the outer loop is printed to it. |
---|
67 | routing(const graph& gg, ostream *debug=0) : |
---|
68 | g(gg), size(g.size()), |
---|
69 | cost(new int *[size]), path(new int *[size]), idx_to_node(size), |
---|
70 | idx_to_node_name(size), node_name_to_idx() { |
---|
71 | int i=0; // Scratch |
---|
72 | |
---|
73 | // Walk g and create indices |
---|
74 | for (graph::nodemap_t::const_iterator ni = g.begin(); |
---|
75 | ni != g.end(); ni++) { |
---|
76 | node_name_to_idx[(*ni).second->get_name()] = i; |
---|
77 | idx_to_node[i] = (*ni).second; |
---|
78 | idx_to_node_name[i] = (*ni).second->get_name(); |
---|
79 | i++; |
---|
80 | } |
---|
81 | |
---|
82 | // Now initialize the path and cost matrices. |
---|
83 | for (i = 0; i < size; i++) { |
---|
84 | graph::node *n = idx_to_node[i]; |
---|
85 | int *row = new int[size]; |
---|
86 | int *irow = new int[size]; |
---|
87 | |
---|
88 | for (int j = 0; j < size; j++) { |
---|
89 | row[j] = infinity; |
---|
90 | irow[j] = -1; // Direct link |
---|
91 | } |
---|
92 | |
---|
93 | // Fill in real valies for edges. |
---|
94 | for (set<graph::edge>::iterator ei = n->begin(); |
---|
95 | ei != n->end(); ei ++) { |
---|
96 | string nn = (*ei).get_node_name(); |
---|
97 | |
---|
98 | row[node_name_to_idx[nn]] = (*ei).get_wt(); |
---|
99 | row[i] = 0.0; |
---|
100 | } |
---|
101 | cost[i] = row; |
---|
102 | path[i] = irow; |
---|
103 | } |
---|
104 | |
---|
105 | // Here's Floyd's algorithm. |
---|
106 | for (int k = 0; k < size; k++) { |
---|
107 | if (debug) *debug << k << '\r'; |
---|
108 | for (int i = 0; i< size; i++) |
---|
109 | for (int j = 0; j < size; j++ ) |
---|
110 | if (cost[i][j] > cost[i][k] + cost[k][j]) { |
---|
111 | cost[i][j] = cost[i][k] + cost[k][j]; |
---|
112 | path[i][j] = k; |
---|
113 | } |
---|
114 | } |
---|
115 | if (debug) *debug << endl; |
---|
116 | } |
---|
117 | |
---|
118 | int path_cost(const string& src, const string& dest) const { |
---|
119 | //Return the cost of the computed path between src and dest. There |
---|
120 | //are similar const issues as beloe in next_hop. |
---|
121 | node_name_to_idx_t::const_iterator f = node_name_to_idx.find(src); |
---|
122 | node_name_to_idx_t::const_iterator t = node_name_to_idx.find(dest); |
---|
123 | |
---|
124 | if ( f != node_name_to_idx.end() && t != node_name_to_idx.end()) |
---|
125 | return cost[(*f).second][(*t).second]; |
---|
126 | else |
---|
127 | return infinity; |
---|
128 | } |
---|
129 | |
---|
130 | string next_hop(const string& src, const string& dest) const { |
---|
131 | // Convert the requests to ints and use the internal next hop. |
---|
132 | // The use of find and iterators is to avoid the potential side |
---|
133 | // effects of the more straightforward node_name_to_idx[src] |
---|
134 | // syntax. |
---|
135 | node_name_to_idx_t::const_iterator f = node_name_to_idx.find(src); |
---|
136 | node_name_to_idx_t::const_iterator t = node_name_to_idx.find(dest); |
---|
137 | int d = next_hop((*f).second, (*t).second); |
---|
138 | |
---|
139 | return idx_to_node_name[d]; |
---|
140 | } |
---|
141 | |
---|
142 | // Print results |
---|
143 | ostream& print(ostream& f, output_format fmt=SHORT) const { |
---|
144 | if ( fmt == SHORT ) |
---|
145 | for (int i = 0; i < size; i++) |
---|
146 | f << i << ":" << idx_to_node_name[i] << endl; |
---|
147 | for (int i = 0; i < size; i++) { |
---|
148 | for (int j = 0; j < size; j++) { |
---|
149 | ostringstream s; |
---|
150 | if (fmt == LONG) { |
---|
151 | pathstring(i, j, s); |
---|
152 | f << idx_to_node_name[i] << "->" |
---|
153 | << idx_to_node_name[j] << ":" |
---|
154 | << cost[i][j] << ":" |
---|
155 | << idx_to_node_name[i] << "/" << s.str() |
---|
156 | << idx_to_node_name[j] << endl; |
---|
157 | } |
---|
158 | else if ( fmt == SHORT) { |
---|
159 | path_ints(i, j, s); |
---|
160 | f << i << "->" << j << ":"<< cost[i][j] << ":" |
---|
161 | << i << "/" << s.str() << j << endl; |
---|
162 | } |
---|
163 | } |
---|
164 | } |
---|
165 | return f; |
---|
166 | } |
---|
167 | |
---|
168 | static string null_map(const string& s) { return s; } |
---|
169 | |
---|
170 | // form a graph in induced that is g without any edges not in the all |
---|
171 | // pairs shortest path graph. If inducing_dest is set, eliminate all |
---|
172 | // edges that are not on a shortest path from some node to that node. |
---|
173 | // Additionally, if newnode is passed in, apply it to rename all nodes |
---|
174 | // in the new graph. |
---|
175 | void induce(graph &induced, string *inducing_dest=0, |
---|
176 | string (*newnode)(const string&)=null_map) const { |
---|
177 | int ind_idx = -1; // The index of the inducing node |
---|
178 | |
---|
179 | // Make sure the inducing dest is there and set ind_idx |
---|
180 | if (inducing_dest ) { |
---|
181 | node_name_to_idx_t::const_iterator i = |
---|
182 | node_name_to_idx.find(*inducing_dest); |
---|
183 | |
---|
184 | if (i != node_name_to_idx.end()) ind_idx = (*i).second; |
---|
185 | else throw runtime_error("No such dest "); |
---|
186 | } |
---|
187 | |
---|
188 | // Insert all the nodes into induced using the side effects of |
---|
189 | // get_node. This also maps the nodenames. |
---|
190 | for (int i = 0; i < size; i++) |
---|
191 | induced.get_node(newnode(idx_to_node_name[i])); |
---|
192 | |
---|
193 | // Now add the edges along each shortest path. |
---|
194 | for (int i =0; i< size; i++) { |
---|
195 | int jinit = ind_idx != -1 ? ind_idx : 0; |
---|
196 | int jlim = inducing_dest ? jinit + 1: size; |
---|
197 | |
---|
198 | for (int j = jinit; j< jlim; j++) { |
---|
199 | deque<int> v; |
---|
200 | if ( i == j ) continue; |
---|
201 | if (cost[i][j] >= infinity) continue; |
---|
202 | path_ints_deque(i, j, v); |
---|
203 | v.push_back(j); |
---|
204 | int ii = i; |
---|
205 | while (v.size()) { |
---|
206 | graph::node *n = |
---|
207 | induced.get_node(newnode(idx_to_node_name[ii])); |
---|
208 | int jj = v.front(); |
---|
209 | |
---|
210 | v.pop_front(); |
---|
211 | n->add_edge(newnode(idx_to_node_name[jj])); |
---|
212 | ii = jj; |
---|
213 | } |
---|
214 | } |
---|
215 | } |
---|
216 | } |
---|
217 | }; |
---|
218 | |
---|
219 | static inline ostream& operator<<(ostream& f, const routing& r) { |
---|
220 | return r.print(f); |
---|
221 | } |
---|
222 | |
---|