[f24fc8d] | 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 | |
---|