Grafalgo
Library of useful data structures and algorithms
/Users/jst/src/grafalgo/cpp/graphAlgorithms/match/fastEdmonds.cpp
00001 #include "fastEdmonds.h"
00002 
00003 using namespace grafalgo;
00004 
00005 // Find a maximum size matching in the graph graf and
00006 // return it as a list of edges.
00007 fastEdmonds::fastEdmonds(Graph& graf1, Dlist& match1, int &size)
00008                  : graf(&graf1), match(&match1) {
00009         vertex u, v; edge e;
00010         blossoms = new Partition(graf->n()); // set per blossom
00011         augpath = new RlistSet(graf->m());    // reversible list
00012         origin = new vertex[graf->n()+1];    // original vertex for each blossom
00013         bridge = new BridgePair[graf->n()+1];// edge that formed a blossom
00014         state = new stype[graf->n()+1];      // state used in path search
00015         pEdge = new edge[graf->n()+1];       // edge to parent in tree
00016         mEdge = new edge[graf->n()+1];       // incident matching edge (if any)
00017         mark = new bool[graf->n()+1];        // mark bits used by nca
00018 
00019         // auxiliary data structures for reducing initialization overhead
00020         // in findpath
00021         searchNum = 0;
00022         latestSearch = new int[graf->n()+1]; // equals search number if reached
00023         nextEdge = new edge[graf->n()+1];    // next edge to search at u
00024         pending = new List(graf->n());     // used by findpath
00025         unmatched = new Dlist(graf->n());  // list of unmatched vertices
00026 
00027         mSize = stepCount = blossomCount = pathInitTime = pathFindTime = 0;
00028         int t1, t2, t3;
00029         t1 = Util::getTime();
00030         // Create initial maximal (not maximum) matching
00031         for (u = 1; u <= graf->n(); u++) {
00032                 mEdge[u] = 0; mark[u] = false; latestSearch[u] = 0;
00033                 nextEdge[u] = graf->firstAt(u);
00034                 unmatched->addLast(u);
00035         }
00036         match->clear(); size = 0;
00037         for (u = 1; u <= graf->n(); u++) {
00038                 if (mEdge[u] != 0) continue;
00039                 for (e = graf->firstAt(u); e != 0; e = graf->nextAt(u,e)) {
00040                         v = graf->mate(u,e);
00041                         if (mEdge[v] == 0) {
00042                                 mEdge[u] = mEdge[v] = e;
00043                                 match->addLast(e); mSize++;
00044                                 unmatched->remove(u);
00045                                 unmatched->remove(v);
00046                                 break;
00047                         }
00048                 }
00049         }
00050         iSize = mSize;
00051                 
00052         t2 = Util::getTime();
00053         imatchTime = (t2-t1);
00054         while((e = findpath()) != 0) { augment(e); mSize++; }
00055         size = mSize;
00056         t3 = Util::getTime();
00057         rmatchTime = (t3-t2);
00058 
00059         delete blossoms; delete augpath; delete [] origin;
00060         delete [] bridge; delete [] pEdge; delete [] mEdge; delete[] mark;
00061 }
00062 
00063 // Modify the matching by augmenting along the path defined by
00064 // the list in the augpath data structure whose last element is e.
00065 void fastEdmonds::augment(edge e) {
00066         edge e1;
00067         while (true) {
00068                 e1 = augpath->first(e);
00069                 if (match->member(e1)) match->remove(e1);
00070                 else {
00071                         match->addLast(e1);
00072                         mEdge[graf->left(e1)] = mEdge[graf->right(e1)] = e1;
00073                 }
00074                 if (e == augpath->first(e)) break;
00075                 e = augpath->pop(e);
00076         }
00077 }
00078 
00079 // If u and v are in the same tree, return their nearest common
00080 // ancestor in the current "condensed graph". To avoid excessive
00081 // search time, search upwards from both vertices in parallel, using
00082 // mark bits to identify the nca. Before returning, clear the mark
00083 // bits by traversing the paths a second time. The mark bits are
00084 // initialized in the constructor.
00085 vertex fastEdmonds::nca(vertex u, vertex v) {
00086         vertex x,px,y,py,result;
00087 
00088         // first pass to find the nca
00089         x = u; px = (pEdge[x] != 0 ? graf->mate(x,pEdge[x]) : 0);
00090         y = v; py = (pEdge[y] != 0 ? graf->mate(y,pEdge[y]) : 0);
00091         while (true) {
00092                 if (x == y) { result = x; break; }
00093                 if (px == 0 &&  py == 0) { result = 0; break; }
00094                 if (px != 0) {
00095                         if (mark[x]) { result = x; break; }
00096                         mark[x] = true;
00097                         x = origin[blossoms->find(px)];
00098                         px = (pEdge[x] != 0 ? graf->mate(x,pEdge[x]) : 0);
00099                 }
00100                 if (py != 0) {
00101                         if (mark[y]) { result = y; break; }
00102                         mark[y] = true;
00103                         y = origin[blossoms->find(py)];
00104                         py = (pEdge[y] != 0 ? graf->mate(y,pEdge[y]) : 0);
00105                 }
00106         }
00107         // second pass to clear mark bits
00108         x = u, y = v; 
00109         while (mark[x] || mark[y]) {
00110                 mark[x] = mark[y] = false;
00111                 px = (pEdge[x] != 0 ? graf->mate(x,pEdge[x]) : 0);
00112                 py = (pEdge[y] != 0 ? graf->mate(y,pEdge[y]) : 0);
00113                 x = (px == 0 ? x : origin[blossoms->find(px)]);
00114                 y = (py == 0 ? y : origin[blossoms->find(py)]);
00115         }
00116         return result;
00117 }
00118 
00119 // Find path joining a and b defined by parent pointers and bridges.
00120 // A is assumed to be a descendant of b, and the path to b from a
00121 // is assumed to pass through the matching edge incident to a.
00122 // Return path in the augpath data structure.
00123 edge fastEdmonds::path(vertex a, vertex b) {
00124         vertex pa, p2a, da; edge e, e1, e2;
00125         if (a == b) { return 0; }
00126         if (state[a] == even) {
00127                 e1 = pEdge[a];  
00128                 pa = graf->mate(a,e1);
00129                 if (pa == b) { return e1; }
00130                 e2 = pEdge[pa]; 
00131                 p2a = graf->mate(pa,e2);
00132                 e = augpath->join(e1,e2);
00133                 e = augpath->join(e,path(p2a,b));
00134                 return e;
00135         } else {
00136                 e = bridge[a].e; da = bridge[a].v;
00137                 e = augpath->join(augpath->reverse(path(da,a)),e);
00138                 e = augpath->join(e,path(graf->mate(da,e),b));
00139                 return e;
00140         }
00141 }
00142 
00143 // Search for an augmenting path in the graph graf.
00144 // On success, the path data structure will include a list
00145 // that forms the augmenting path. In this case, the last
00146 // edge in the list is returned as the function value.
00147 // On failure, returns 0.
00148 edge fastEdmonds::findpath() {
00149         vertex u,v,vp,w,wp,x,y; edge e;
00150 
00151         int t1, t2, t3;
00152         t1 = Util::getTime();
00153 
00154         searchNum++;
00155         pending->clear();
00156         vertex nextUnmatched = unmatched->first();
00157 
00158         t2 = Util::getTime();
00159         pathInitTime += (t2-t1);
00160         while (true) {
00161                 if (nextUnmatched != 0) {
00162                         // initialize the next unmatched vertex and add
00163                         // it to pending
00164                         // doing it this way to reduce initialization overhead
00165                         // when search ends fast
00166                         pending->addLast(nextUnmatched);
00167                         state[nextUnmatched] = even;
00168                         pEdge[nextUnmatched] = 0;
00169                         origin[nextUnmatched] = nextUnmatched;
00170                         blossoms->clear(nextUnmatched);
00171                         latestSearch[nextUnmatched] = searchNum;
00172                         nextEdge[nextUnmatched] = graf->firstAt(nextUnmatched);
00173                         nextUnmatched = unmatched->next(nextUnmatched);
00174                 }
00175                 if (pending->empty()) break;
00176                         
00177                 v = pending->first(); e = nextEdge[v];
00178                 if (e == 0) {
00179                         pending->removeFirst(); continue;
00180                 } else {
00181                         nextEdge[v] = graf->nextAt(v,e);
00182                 }
00183                 stepCount++;
00184                 w = graf->mate(v,e);
00185                 if (latestSearch[w] != searchNum && mEdge[w] != 0) {
00186                         // w not yet reached in this search, so can't be
00187                         // part of any blossom yet
00188                         // extend the tree
00189                         x = graf->mate(w,mEdge[w]);
00190                         state[w] = odd;  pEdge[w] = e;
00191                         state[x] = even; pEdge[x] = mEdge[w];
00192                         origin[w] = w; origin[x] = x;
00193                         latestSearch[w] = latestSearch[x] = searchNum;
00194                         blossoms->clear(w); blossoms->clear(x);
00195                         pending->addLast(x);
00196                         nextEdge[x] = graf->firstAt(x);
00197                         continue;
00198                 }
00199                 if (latestSearch[w] != searchNum) {
00200                         // w is a tree root that hasn't been initialized yet
00201                         // so, initialize and add to pending
00202                         pending->addLast(w);
00203                         state[w] = even;
00204                         pEdge[w] = 0;
00205                         origin[w] = w;
00206                         blossoms->clear(w);
00207                         latestSearch[w] = searchNum;
00208                         nextEdge[w] = graf->firstAt(w);
00209                 }
00210                 vp = origin[blossoms->find(v)];
00211                 wp = origin[blossoms->find(w)];
00212                 if (vp == wp) continue; // skip internal edges in a blossom
00213                 u = nca(vp,wp);
00214                 if ((state[wp] == even || latestSearch[w] != searchNum) &&
00215                     u == 0) {
00216                         // vp, wp are different trees - construct path & return
00217                         x = vp;
00218                         while (pEdge[x] != 0) {
00219                                 x = origin[blossoms->find(
00220                                                 graf->mate(x,pEdge[x])
00221                                         )];
00222                         }
00223                         y = wp;
00224                         while (pEdge[y] != 0) {
00225                                 y = origin[blossoms->find(
00226                                                 graf->mate(y,pEdge[y])
00227                                         )];
00228                         }
00229                         e = augpath->join(augpath->reverse(path(v,x)),e);
00230                         e = augpath->join(e,path(w,y));
00231                         // x and y will soon be matched
00232                         unmatched->remove(x); unmatched->remove(y);
00233                         t3 = Util::getTime();
00234                         pathFindTime += (t3-t2);
00235                         return e;
00236                 } else if (state[wp] == even) {
00237                         // vp and wp are in same tree - collapse blossom
00238                         blossomCount++;
00239                         x = vp;
00240                         while (x != u) {
00241                                 origin[blossoms->link(
00242                                         blossoms->find(x),
00243                                         blossoms->find(u))] = u;
00244                                 if (state[x] == odd) {
00245                                         bridge[x].e = e; bridge[x].v = v;
00246                                         if (!pending->member(x))
00247                                                 pending->addLast(x);
00248                                 }
00249                                 x = origin[blossoms->find(
00250                                         graf->mate(x,pEdge[x]))];
00251                         }
00252                         x = wp;
00253                         while (x != u) {
00254                                 origin[blossoms->link(
00255                                         blossoms->find(x),
00256                                         blossoms->find(u))] = u;
00257                                 if (state[x] == odd) {
00258                                         bridge[x].e = e; bridge[x].v = w;
00259                                         if (!pending->member(x))
00260                                                 pending->addLast(x);
00261                                 }
00262                                 x = origin[blossoms->find(
00263                                         graf->mate(x,pEdge[x]))];
00264                         }
00265                 } 
00266         }
00267         t3 = Util::getTime();
00268         pathFindTime += (t3-t2);
00269         return 0;
00270 }
00271 
00278 string& fastEdmonds::statString(bool verbose, string& s) {
00279         stringstream ss;
00280         if (verbose) {
00281                 ss << "iSize=" << iSize << " ";
00282                 ss << "mSize=" << mSize << " ";
00283                 ss << "stepCount=" << stepCount << " ";
00284                 ss << "blossomCount=" << blossomCount << " ";
00285                 ss << "imatchTime=" << imatchTime << " ";
00286                 ss << "rmatchTime=" << rmatchTime << " ";
00287                 ss << "pathInitTime=" << pathInitTime << " ";
00288                 ss << "pathFindTime=" << pathFindTime;
00289         } else {
00290                 ss << iSize << " " << mSize << " ";
00291                 ss << stepCount << " " << blossomCount << " ";
00292                 ss << imatchTime << " "<< rmatchTime << " ";
00293                 ss << pathInitTime << " " << pathFindTime;
00294         }
00295         s = ss.str();
00296         return s;
00297 }
 All Classes Files Functions Variables Typedefs Friends