Grafalgo
Library of useful data structures and algorithms
/Users/jst/src/grafalgo/cpp/graphAlgorithms/sPath/sptUpdate.cpp
00001 // usage: sptUpdate n m maxLen repCount seed
00002 //
00003 // sptUpdate generates a random graph on n vertices with m edges.
00004 // It then computes a shortest path tree of the graph then repeatedly
00005 // modifies the shortest path tree by randomly changing the weight
00006 // of one of the edges. The edge lengths are distributed in [1,maxLen].
00007 //
00008 // This program is not bullet-proof. Caveat emptor.
00009 
00010 #include "stdinc.h"
00011 #include "List.h"
00012 #include "Dheap.h"
00013 #include "Wdigraph.h"
00014 
00015 using namespace grafalgo;
00016 
00017 void dijkstra(Wdigraph&, vertex, vertex*, int*);
00018 int sptUpdate(Wdigraph&, vertex*, int*, edge, int);
00019 void check(Wdigraph&, Wdigraph&);
00020 
00021 int main(int argc, char* argv[]) {
00022         int i, n, m, maxLen, repCount, retVal, seed;
00023         int notZero, minTsiz, maxTsiz, avgTsiz;
00024         edge e; Wdigraph dig;
00025 
00026         if (argc != 6 ||
00027             sscanf(argv[1],"%d",&n) != 1 ||
00028             sscanf(argv[2],"%d",&m) != 1 ||
00029             sscanf(argv[3],"%d",&maxLen) != 1 ||
00030             sscanf(argv[4],"%d",&repCount) != 1 ||
00031             sscanf(argv[5],"%d",&seed) != 1)
00032                 Util::fatal("usage: sptUpdate n m maxLen repCount seed");
00033 
00034         srandom(seed);
00035         dig.rgraph(n,m); dig.randLength(0,maxLen);
00036 
00037         vertex *p = new int[n+1]; int *d = new int[n+1];
00038         dijkstra(dig,1,p,d);
00039 
00040         notZero = 0; minTsiz = dig.n(); maxTsiz = 0; avgTsiz = 0;
00041         for (i = 1; i <= repCount; i++) {
00042                 e = Util::randint(1,dig.m());
00043                 retVal = sptUpdate(dig,p,d,e,Util::randint(1,maxLen));
00044                 if (retVal > 0) {
00045                         notZero++;
00046                         minTsiz = min(retVal,minTsiz);
00047                         avgTsiz += retVal;
00048                         maxTsiz = max(retVal,maxTsiz);
00049                 }
00050         }
00051 
00052         cout << setw(6) << notZero << " " << setw(2) << minTsiz
00053              << " " << (notZero > 0 ? double(avgTsiz)/notZero : 0.0)
00054              << " " << setw(4) << maxTsiz;
00055 }
00056 
00057 int sptUpdate(Wdigraph& dig, vertex p[], int d[], edge e, int nuLen) {
00058 // Given a graph dig and an SPT sptree, update the SPT and distance vector to
00059 // reflect the change in the weight of edge e to nuLen.
00060 // Return 0 if no change is needed. Otherwise, return the number
00061 // of vertices in the subtree affected by the update.
00062         vertex u, v, x, y; edge f;
00063         int oldLen, tSiz;
00064         static int n=0; static Dheap *nheap; static List *stList;
00065 
00066         // Allocate new heap and List if necessary.
00067         // For repeated calls on same graph, this is only done once.
00068         if (dig.n() > n) { 
00069                 if (n > 0) { delete nheap; delete stList; }
00070                 n = dig.n();
00071                 nheap = new Dheap(dig.n(),2);
00072                 stList = new List(dig.n());
00073         }
00074 
00075         u = dig.tail(e); v = dig.head(e);
00076         oldLen = dig.length(e); dig.setLength(e,nuLen);
00077 
00078         // case 1 - non-tree edge gets more expensive
00079         if (p[v] != u && nuLen >= oldLen) return 0;
00080 
00081         // case 2 - non-tree edge gets less expensive, but not enough
00082         // to change anything
00083         if (p[v] != u && d[u] + nuLen >= d[v]) return 0;
00084 
00085         // In the above two cases, nv=0 and the running time is O(1)
00086         // as required.
00087 
00088         // case 3 - edge gets less expensive and things change
00089         if (nuLen < oldLen) {
00090                 // start Dijkstra's algorithm from v
00091                 p[v] = u; d[v] = d[u] + nuLen;
00092                 nheap->insert(v,d[v]);
00093                 tSiz = 0;
00094                 while (!nheap->empty()) {
00095                         x = nheap->deletemin();
00096                         for (f = dig.firstOut(x); f !=0; f = dig.nextOut(x,f)) {
00097                                 y = dig.head(f);
00098                                 if (d[y] > d[x] + dig.length(f)) {
00099                                         d[y] = d[x] + dig.length(f); p[y] = x;
00100                                         if (nheap->member(y))
00101                                                 nheap->changekey(y,d[y]);
00102                                         else
00103                                                 nheap->insert(y,d[y]);
00104                                 }
00105                         }
00106                         tSiz++;
00107                 }
00108                 return tSiz;
00109         }
00110         // In case 3, the vertices affected by the update are those that
00111         // get inserted into the heap. Hence, the number of executions of
00112         // the outer loop is O(nv). The inner loop iterates over edges
00113         // incident to the vertices for which the distance changes, hence
00114         // the number of calls to changekey is O(mv). The d-heap parameter
00115         // is 2, which gives us an overall running time of O((mv log nv).
00116 
00117         // case 4 - tree edge gets more expensive
00118 
00119         // Put vertices in subtree into list.
00120         stList->clear(); stList->addLast(v); x = v; tSiz = 0;
00121         do {
00122                 tSiz++;
00123                 for (f = dig.firstOut(x); f != 0; f = dig.nextOut(x,f)) {
00124                         y = dig.head(f);
00125                         if (p[y] == x) {
00126                                 if (stList->member(y)) {
00127                                         string s1;
00128                                         cout <<  "u=" << u << " v=" << v
00129                                              << " x=" << x << " y=" << y 
00130                                              << endl << stList->toString(s1);
00131                                 }
00132                                 stList->addLast(y);
00133                         }
00134                 }
00135                 x = stList->next(x);
00136         } while (x != 0);
00137 
00138         // The time for the above loop is O(nv+mv)
00139 
00140         // Insert vertices in the subtree with incoming edges into heap.
00141         for (x = stList->first(); x != 0; x = stList->next(x)) {
00142                 // find best incoming edge for vertex x
00143                 p[x] = 0; d[x] = Util::BIGINT32;
00144                 for (f = dig.firstIn(x); f != 0; f = dig.nextIn(x,f)) {
00145                         y = dig.tail(f);
00146                         if (!stList->member(y) && d[y] + dig.length(f) < d[x]) {
00147                                 p[x] = y; d[x] = d[y] + dig.length(f);
00148                         } 
00149                 }
00150                 if (p[x] != 0) nheap->insert(x,d[x]);
00151         }
00152 
00153         // The time for the above loop is  O(mv + nvlog nv)
00154 
00155         // Run Dijkstra's algorithm on the vertices in the subtree.
00156         while (!nheap->empty()) {
00157                 x = nheap->deletemin();
00158                 for (f = dig.firstOut(x); f != 0; f = dig.nextOut(x,f)) {
00159                         y = dig.head(f);
00160                         if (d[y] > d[x] + dig.length(f)) {
00161                                 d[y] = d[x] + dig.length(f); p[y] = x;
00162                                 if (nheap->member(y)) nheap->changekey(y,d[y]);
00163                                 else nheap->insert(y,d[y]);
00164                         }
00165                 }
00166         }
00167         // Same as earlier case. The outer loop is executed nv times,
00168         // the inner loop mv times. So the overall running time is
00169         // O(mv log nv).
00170         return tSiz;
00171 }
00172 
00173 void check(int s, Wdigraph& dig, Wdigraph& sptree) {
00174 // Verify that sptree is a shortest path tree of dig.
00175         vertex u,v; edge e, f;
00176 
00177         // check size of sptree matches dig
00178         if (sptree.n() != dig.n() || sptree.m() != sptree.n()-1)
00179                 Util::fatal("spt_check: size error, aborting");
00180 
00181         // check that sptree is a subgraph of dig
00182         for (v = 1; v <= sptree.n(); v++) {
00183                 if (v == s) continue;
00184                 f = sptree.firstIn(v);
00185                 if (f == 0) 
00186                         cout << "check: non-root vertex " << v
00187                              << " has no incoming edge\n";
00188                 u = sptree.tail(f);
00189                 for (e = dig.firstIn(v); ; e = dig.nextIn(v,e)) {
00190                         if (e == 0) {
00191                                 cout << "check: edge (" << u << "," << v
00192                                      << ") in sptree is not in dig\n";
00193                         }
00194                         if (dig.tail(e) == u) break;
00195                 }
00196         }
00197 
00198         // check that sptree reaches all the vertices
00199         bool* mark = new bool[sptree.n()+1]; int marked;
00200         for (u = 1; u <= sptree.n(); u++) mark[u] = false;
00201         mark[s] = true; marked = 1;
00202         List q(dig.n()); q.addLast(s);
00203         while (!q.empty()) {
00204                 u = q.first(); q.removeFirst();
00205                 for (e = sptree.firstOut(u); e != 0; e = sptree.nextOut(u,e)) {
00206                         v = sptree.head(e);
00207                         if (!mark[v]) {
00208                                 q.addLast(v); mark[v] = true; marked++;
00209                         }
00210                 }
00211         }
00212         if (marked != sptree.n()) {
00213                 cout << "check: sptree does not reach all vertices\n";
00214                 return;
00215         }
00216 
00217         // check that tree is minimum
00218         int du, dv; string s1;
00219         for (u = 1; u <= dig.n(); u++) {
00220                 du = sptree.firstIn(u) == 0 ?
00221                      0 : sptree.length(sptree.firstIn(u));
00222                 for (e = dig.firstOut(u); e != 0; e = dig.nextOut(u,e)) {
00223                         v = dig.head(e); edge vpe = sptree.firstIn(v);
00224                         dv = vpe == 0 ?  0 : sptree.length(vpe);
00225                         if (dv > du + dig.length(e))
00226                                 cout << "check: " << dig.edge2string(e,s1)
00227                                      << " violates spt condition\n";
00228                         if (vpe != 0 && sptree.tail(vpe) == u && 
00229                             dv != du + dig.length(e))
00230                                 cout << "check: tree edge "
00231                                      << sptree.edge2string(vpe,s1)
00232                                      << " violates spt condition\n";
00233                 }
00234         }
00235 }
 All Classes Files Functions Variables Typedefs Friends