ShGraphImpl.hpp

00001 // Sh: A GPU metaprogramming language.
00002 //
00003 // Copyright 2003-2005 Serious Hack Inc.
00004 // 
00005 // This library is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU Lesser General Public
00007 // License as published by the Free Software Foundation; either
00008 // version 2.1 of the License, or (at your option) any later version.
00009 //
00010 // This library is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 // Lesser General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU Lesser General Public
00016 // License along with this library; if not, write to the Free Software
00017 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 
00018 // MA  02110-1301, USA
00020 #ifndef SHGRAPHIMPL_HPP 
00021 #define SHGRAPHIMPL_HPP 
00022 
00023 #include "ShGraph.hpp"
00024 #include <stack>
00025 #include <map>
00026 
00027 namespace SH {
00028 
00029 // TODO should clear arguments passed in by reference to the different
00030 // algs like shortest path and trans closuer
00031 
00032 
00033 template<typename G>
00034 ShGraphVertex<G>::ShGraphVertex()
00035   : marked(false)
00036 {}
00037 
00038 template<typename G>
00039 ShGraphVertex<G>::ShGraphVertex(const ShGraphVertex<G> &other)
00040   : marked(other.marked)
00041 {}
00042 
00043 template<typename G>
00044 std::ostream& ShGraphVertex<G>::graphvizDump(std::ostream &out) const
00045 {
00046   out << " [label=\"\", shape=circle, height=0.25]";
00047   return out;
00048 }
00049 
00050 template<typename G>
00051 ShGraphEdge<G>::ShGraphEdge()
00052   : start(0), end(0)
00053 {}
00054 
00055 template<typename G>
00056 ShGraphEdge<G>::ShGraphEdge(typename G::Vertex *start, typename G::Vertex *end)
00057   : start(start), end(end)
00058 {}
00059 
00060 template<typename G>
00061 ShGraphEdge<G>::ShGraphEdge(const ShGraphEdge<G> &other)
00062   : start(0), end(0) 
00063 {}
00064 
00065 template<typename G>
00066 std::ostream& ShGraphEdge<G>::graphvizDump(std::ostream &out) const
00067 {
00068   return out; // use default edge
00069 }
00070 
00071 template<typename G>
00072 ShGraph<G>::ShGraph()
00073 {}
00074 
00075 template<typename G>
00076 ShGraph<G>::ShGraph(const ShGraph<G> &other)
00077 {
00078   *this = other;
00079 }
00080 
00081 template<typename G>
00082 ShGraph<G>::~ShGraph()
00083 {
00084   clear();
00085 }
00086 
00087 template<typename G>
00088 void ShGraph<G>::addVertex(typename G::Vertex *v)
00089 {
00090   verts.insert(v);
00091 }
00092 
00093 template<typename G>
00094 void ShGraph<G>::addEdge(typename G::Edge *e)
00095 {
00096   edges.insert(e);
00097   e->start->edges.push_back(e);
00098 }
00099 
00100 template<typename G>
00101 void ShGraph<G>::removeVertex(typename G::Vertex *v)
00102 {
00103   for(typename EdgeList::iterator E = v->edges.begin(); E != v->edges.end(); ++E) {
00104     edges.erase(*E);
00105   }
00106   verts.erase(v);
00107 }
00108 
00109 template<typename G>
00110 void ShGraph<G>::removeEdge(typename G::Edge *e)
00111 {
00112   edges.erase(e);
00113   e->start->edges.remove(e);
00114   delete e;
00115 }
00116 
00117 template<typename G>
00118 void ShGraph<G>::clear()
00119 {
00120   for(typename VertexSet::iterator V = verts.begin(); V != verts.end(); ++V) delete *V;
00121   for(typename EdgeSet::iterator E = edges.begin(); E != edges.end(); ++E) delete *E;
00122  
00123   verts.clear();
00124   edges.clear();
00125 }
00126 
00127 template<typename G>
00128 void ShGraph<G>::clearMarked()
00129 {
00130   for(typename VertexSet::iterator V = verts.begin(); V != verts.end(); ++V) (*V)->marked = false;
00131 }
00132 
00133 template<typename G>
00134 ShGraph<G>& ShGraph<G>::operator=(const ShGraph<G> &other)
00135 {
00136   clear();
00137 
00138   VertexMap<Vertex *> vmap;
00139 
00140   // mappings for null pointers
00141   vmap[0] = 0;
00142 
00143   for(typename VertexSet::const_iterator V = other.verts.begin(); V != other.verts.end(); ++V) {
00144     typename G::Vertex *newv = new Vertex(**V);
00145     vmap[*V] = newv;
00146     addVertex(newv);
00147   }
00148 
00149   for(typename EdgeSet::const_iterator E = other.edges.begin(); E != other.edges.end(); ++E) {
00150     typename G::Edge *newe = new Edge(**E);
00151     newe->start = vmap[(*E)->start];
00152     newe->end = vmap[(*E)->end];
00153     addEdge(newe);
00154   }
00155 
00156   return *this;
00157 }
00158 
00159 template<typename G>
00160 template<typename F>
00161 void ShGraph<G>::dfs(typename G::Vertex *start, F &functor)
00162 {
00163   std::stack<typename G::Vertex *> worklist;
00164 
00165   for(worklist.push(start); !worklist.empty(); worklist.pop()) {
00166     typename G::Vertex *workVertex = worklist.top();
00167     if(workVertex->marked) continue; // useful for cycle detection
00168     workVertex->marked = true;
00169 
00170     for(typename EdgeList::iterator E = workVertex->edges.begin(); E != workVertex->edges.end(); ++E) {
00171       worklist.push(E->end);
00172     }
00173     functor(workVertex);
00174   }
00175 }
00176 
00177 template<typename G>
00178 template<typename W>
00179 typename W::WeightType ShGraph<G>::bellmanFord(typename G::Vertex *start, typename G::Vertex *end, W &weigher, EdgeList *path) 
00180 {
00181   // essentially the same as above, with predecessors
00182   // TODO refactor so the algorithm shows up only once
00183   std::map<typename G::Vertex *, typename W::WeightType> dist;
00184   std::map<typename G::Vertex *, typename G::Edge *> pred; // edge going back to predecessor in SP so far
00185 
00186   for(typename VertexSet::const_iterator V = verts.begin(); V != verts.end(); ++V) {
00187     dist[*V] = W::LARGE;
00188     pred[*V] = 0;
00189   }
00190 
00191   dist[start] = W::ZERO; 
00192 
00193   for(int i = 0; i < verts.size(); ++i) {
00194     for(typename EdgeSet::iterator E = edges.begin(); E != edges.end(); ++E) {
00195       Edge &e = **E;
00196 
00197       typename W::WeightType testDist = dist[e.start] + weigher(e);
00198       if(testDist < dist[e.end]) {
00199         dist[e.end] = testDist;
00200         pred[e.end] = &e;
00201       }
00202     }
00203   }
00204 
00205   // trace shortest path
00206   if(path) {
00207     path->clear();
00208     for(typename G::Edge *finger = pred[end]; finger != 0; finger = pred[finger->start]) {
00209       path->push_front(finger);
00210     }
00211   }
00212 
00213   return dist[end];
00214 }
00215 
00216 template<typename G>
00217 template<typename W>
00218 void ShGraph<G>::floydWarshall(W &weigher, VertexPairMap<typename W::WeightType> &dist, FirstStepMap *path) 
00219 {
00220   typename VertexSet::const_iterator V, U, X; 
00221   typename EdgeSet::iterator E;
00222 
00223   dist.clear();
00224   if(path) path->clear();
00225 
00226   // initialize distances to LARGE for distinct pairs
00227   for(V = verts.begin(); V != verts.end(); ++V) for(U = verts.begin(); U != verts.end(); ++U) {
00228     if(V == U) dist(*V, *U) = W::ZERO; 
00229     else dist(*V, *U) = W::LARGE;
00230   }
00231 
00232   // initialize to minimum edge weight for adjacent vertices
00233   for(E = edges.begin(); E != edges.end(); ++E) {
00234     Edge& e = **E;
00235     typename W::WeightType &testDist = dist(e.start, e.end);
00236     if(testDist > weigher(e)) {
00237       testDist = weigher(e);
00238       if(path) (*path)(e.start, e.end) = &e;
00239     }
00240   }
00241 
00242   // do the bottom-up dynamic programming
00243   // loop invariant of the outer loop
00244   //    dist(A, B) contains the shortest path from A to B using only the
00245   //        nodes in verts.begin() to V as intermediates
00246   //    path(A, B) contains the first edge in the above shortest path
00247   for(V = verts.begin(); V != verts.end(); ++V) {
00248     for(U = verts.begin(); U != verts.end(); ++U) {
00249       for(X = verts.begin(); X != verts.end(); ++X) {
00250         typename W::WeightType &oldDist = dist(*U, *X);
00251         typename W::WeightType testDist = dist(*U, *V) + dist(*V, *X);
00252         if(oldDist > testDist && (dist(*U, *V) != W::LARGE && 
00253               dist(*V, *X) != W::LARGE)) {
00254           oldDist = testDist;
00255           if(path) (*path)(*U, *X) = (*path)(*U, *V);
00256         }
00257       }
00258     }
00259   }
00260 }
00261 
00262 
00263 template<typename G>
00264 void ShGraph<G>::transitiveClosure(TransitiveClosureMap &tcm)
00265 {
00266   typename VertexSet::const_iterator V, U, X; 
00267   typename EdgeSet::iterator E;
00268   typedef VertexPairMap<bool> TCMap; // transitive closure map
00269 
00270   // initialize to minimum edge weight for adjacent vertices
00271   tcm.clear();
00272   for(V = verts.begin(); V != verts.end(); ++V) tcm(*V, *V) = true;
00273 
00274   for(E = edges.begin(); E != edges.end(); ++E) {
00275     Edge& e = **E;
00276     tcm(e.start, e.end) = true;
00277   }
00278 
00279   // do bottom-up dynamic programming
00280   for(V = verts.begin(); V != verts.end(); ++V) {
00281     for(U = verts.begin(); U != verts.end(); ++U) {
00282       for(X = verts.begin(); X != verts.end(); ++X) {
00283         tcm(*U, *X) = tcm(*U, *X) || (tcm(*U, *V) && tcm(*V, *X));
00284       }
00285     }
00286   }
00287 }
00288 
00289 template<typename G>
00290 void ShGraph<G>::rootSet(VertexSet &roots) {
00291   roots = verts;
00292   typename EdgeSet::const_iterator E;
00293   for(E = edges.begin(); E != edges.end(); ++E) {
00294     roots.erase((*E)->end);
00295   }
00296 }
00297 
00298 template<typename G>
00299 struct NegativeWeigher {
00300   typedef int WeightType;
00301   static const int LARGE=2000000000; // TODO MAX_INT
00302   static const int ZERO=0;
00303   int operator()(const typename G::Edge &e) { return -1; }
00304 }; 
00305 
00306 template<typename G>
00307 void ShGraph<G>::vertexHeight(const VertexSet &roots, HeightMap &heights) {
00308   heights.clear();
00309   VertexPairMap<int> dist;
00310   NegativeWeigher<G> weigher;
00311   typename VertexSet::const_iterator U, V;
00312 
00313   floydWarshall(weigher, dist);
00314   for(U = verts.begin(); U != verts.end(); ++U) {
00315     for(V = roots.begin(); V != roots.end(); ++V) {
00316       heights[*U] = std::max(heights[*U], -dist(*V, *U));
00317     }
00318   }
00319 }
00320 
00321 
00322 template<typename G>
00323 void ShGraph<G>::leastCommonAncestor(LCAMap &ancestor)
00324 {
00325   typename VertexSet::const_iterator U, V, W;
00326   typename EdgeSet::const_iterator E;
00327 
00328   // First step, identify the "roots" of the DAG (those that have no
00329   // ancestors) 
00330   VertexSet roots;
00331   rootSet(roots);
00332 
00333   // Find the height of each node by longest path distance from any root
00334   HeightMap heights;
00335   vertexHeight(roots, heights);
00336 
00337   // Calculate the transitive closure matrix 
00338   TransitiveClosureMap tcm;
00339   transitiveClosure(tcm);
00340 
00341   // Identify a candidate least common ancestor (greatest height)
00342   // for each pair of verts 
00343   ancestor.clear();
00344   for(U = verts.begin(); U != verts.end(); ++U) {
00345     for(V = verts.begin(); V != verts.end(); ++V) {
00346       int maxHeight = -1;
00347       for(W = verts.begin(); W != verts.end(); ++W) {
00348         // if W is an ancestor of both U and V, check if its the LCA so far 
00349         if(tcm(*W, *U) && tcm(*W, *V) && heights[*W] > maxHeight) {
00350           ancestor(*U, *V) = ancestor(*V, *U) = *W;
00351           maxHeight = heights[*W]; 
00352         }
00353       }
00354     }
00355   }
00356 }
00357 
00358 template<typename G>
00359 std::ostream& ShGraphDefaultDumper<G>::operator()(std::ostream& out, const typename G::Vertex *v)
00360 {
00361   return v->graphvizDump(out);
00362 }
00363 
00364 template<typename G>
00365 std::ostream& ShGraphDefaultDumper<G>::operator()(std::ostream& out, const typename G::Edge *e)
00366 {
00367   return e->graphvizDump(out);
00368 }
00369 
00370 template<typename G>
00371 std::ostream& graphvizDump(std::ostream &out, const ShGraph<G> &g)
00372 {
00373   ShGraphDefaultDumper<G> dumper;
00374   return graphvizDump(out, g, dumper); 
00375 }
00376 
00377 template<typename G, typename D>
00378 std::ostream& graphvizDump(std::ostream &out, const ShGraph<G> &g, D &dumpFunctor)
00379 {
00380   out << "digraph {" << std::endl;
00381     typename ShGraph<G>::VertexSet::const_iterator V = g.verts.begin();
00382     for(; V != g.verts.end(); ++V) {
00383       out << "\"" << *V << "\" ";
00384       dumpFunctor(out, *V);
00385       out << ";" << std::endl;
00386       out << std::endl;
00387     }
00388 
00389     typename ShGraph<G>::EdgeSet::const_iterator E = g.edges.begin();
00390     for(; E != g.edges.end(); ++E) {
00391       const typename G::Edge &e = **E;
00392       out << "\"" << e.start << "\" ";
00393       out << "-> ";
00394       out << "\"" << e.end << "\" ";
00395       dumpFunctor(out, *E);
00396       out << ";" << std::endl;
00397       out << std::endl;
00398     }
00399   out << "}" << std::endl;
00400 
00401   return out;
00402 }
00403 
00404 }
00405 
00406 #endif

Generated on Wed Nov 9 15:29:32 2005 for Sh by  doxygen 1.4.5