source: routing/routing.h @ f24fc8d

Last change on this file since f24fc8d was f24fc8d, checked in by Ted Faber <faber@…>, 12 years ago

Routing under here, too

  • Property mode set to 100644
File size: 8.9 KB
Line 
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)
5class 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
219static inline ostream& operator<<(ostream& f, const routing& r) {
220    return r.print(f);
221}
222
Note: See TracBrowser for help on using the repository browser.