Advertisement
Guest User

Dijkstra's single-source shortest-path using OpenMP

a guest
May 10th, 2011
697
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 13.66 KB | None | 0 0
  1. /*
  2.  * WeightedGraph.h
  3.  *
  4.  *  Created on: Apr 24, 2011
  5.  *      Author: cirvante
  6.  */
  7.  
  8. #ifndef WEIGHTEDGRAPH_H_
  9. #define WEIGHTEDGRAPH_H_
  10.  
  11. #include <limits>
  12. #include <algorithm>
  13. #include <stdexcept>
  14. #include <string>
  15. #include <list>
  16. #include <vector>
  17. #include <map>
  18.  
  19. using namespace std;
  20.  
  21. class Vertex;
  22. class Edge;
  23.  
  24. typedef list<Edge*>::iterator                               AdjListIterator;
  25. typedef map<string, Vertex*>::iterator                      GraphIterator;
  26. typedef map<pair<Vertex*, Vertex*>, Edge* >::iterator       GraphEdgeIterator;
  27. enum EdgeState { UNVISITED, DISCOVERY, BACK };
  28.  
  29.  
  30. class WeightedGraph {
  31.     public:
  32.         WeightedGraph();
  33.         ~WeightedGraph();
  34.         int size() const;
  35.         bool isEmpty() const;
  36.         void insertVertex(string id);
  37.         void insertEdge(string src, string dst, double cost);
  38.         Vertex* opposite(Vertex* v, Edge* e) throw (logic_error);
  39.         Vertex* getVertex(string id) throw (logic_error);
  40.         map<string, Vertex*>* getVertices();
  41.         vector<string> getVertexNames();
  42.         double getDistance(Vertex* src, Vertex* dst) throw (logic_error);
  43.         bool areAdjacent(Vertex* u, Vertex* v);
  44.         void clearVisited();
  45.         void printGraph();
  46.     private:
  47.         map<string, Vertex*> _internalVertexMap;
  48.         map<pair<Vertex*, Vertex*>, Edge* > _globalEdgeMap;
  49.         int _size;
  50. };
  51.  
  52. class Vertex {
  53.     public:
  54.         string name;
  55.  
  56.         Vertex(const string n): name(n), _parent(NULL), _visited(false){}
  57.  
  58.         list<Edge*> neighbors() const;
  59.         void addNeighbor(Edge* e);
  60.         Vertex* parent() const;
  61.         void setParent(Vertex* v);
  62.         bool visited() const;
  63.         void setVisited(bool visitState);
  64.  
  65.     private:
  66.         list <Edge*> _neighbors;
  67.         Vertex* _parent;
  68.         bool _visited;
  69. };
  70.  
  71. class Edge {
  72.     public:
  73.  
  74.         Edge(const double c, Vertex* s, Vertex* d): _cost(c), _src(s), _dest(d), _state(UNVISITED){}
  75.  
  76.         double cost() const;
  77.         enum EdgeState currentState() const;
  78.         void setState(EdgeState state);
  79.         Vertex* fromVertex() const;
  80.         Vertex* toVertex() const;
  81.         void setSource(Vertex* sourceVertex);
  82.         void setDest(Vertex* destVertex);
  83.         void setCost(double weight);
  84.  
  85.     private:
  86.         double _cost;
  87.         Vertex* _src;
  88.         Vertex* _dest;
  89.         EdgeState _state;
  90. };
  91. /*
  92. * Just a small object to pass as a comparator for std::priority_queue. This is needed so the priority queue
  93. * works as a min-heap and not a max-heap, as is the default implementation. That, and I never overloaded
  94. * any operators in my Edge class.
  95. */
  96. class PathCompare {
  97.     public:
  98.         bool operator()(const Edge* lhs, const Edge* rhs) const {
  99.             return (lhs->cost() > rhs->cost());
  100.         }
  101. };
  102.  
  103. #endif /* WEIGHTEDGRAPH_H_ */
  104.  
  105.  
  106. /*
  107.  * WeightedGraph.cpp
  108.  *
  109.  *  Created on: Apr 25, 2011
  110.  *      Author: cirvante
  111.  */
  112.  
  113. #include <iostream>
  114. #include "WeightedGraph.h"
  115.  
  116. /*
  117.  * Implementation of class WeightedGraph
  118.  */
  119.  
  120.  
  121. WeightedGraph::WeightedGraph() { //Constructor
  122.     _size = 0;
  123. }
  124.  
  125. WeightedGraph::~WeightedGraph() {}
  126.  
  127. int WeightedGraph::size() const { //Returns the number of vertices
  128.     return _size;
  129. }
  130.  
  131. bool WeightedGraph::isEmpty() const { //Returns whether the graph is empty or not
  132.     return _size == 0;
  133. }
  134.  
  135. void WeightedGraph::insertVertex(string id) { //Inserts a vertex into the internal map
  136.     Vertex* newVertex = new Vertex(id);
  137.     _internalVertexMap[id] = newVertex;
  138.     ++_size;
  139.     /*
  140.     for(GraphIterator itr = _internalVertexMap.begin(); itr != _internalVertexMap.end(); ++itr) {
  141.         cout << itr->second->name << endl;
  142.     }
  143.  
  144.     cout << endl;
  145.     */
  146. }
  147.  
  148. Vertex* WeightedGraph::getVertex(string id) throw (logic_error) {
  149.     if (_internalVertexMap.empty()) throw logic_error("Graph is empty.");
  150.     Vertex* vtr = _internalVertexMap[id];
  151.     if (vtr == NULL) throw logic_error("Vertex does not exist.");
  152.     return vtr;
  153. }
  154.  
  155. map<string, Vertex*>* WeightedGraph::getVertices() {
  156.     return &_internalVertexMap;
  157. }
  158.  
  159. vector<string> WeightedGraph::getVertexNames() {
  160.     vector<string> vtr;
  161.     for (GraphIterator itr = _internalVertexMap.begin(); itr != _internalVertexMap.end(); ++itr) {
  162.         vtr.push_back(itr->first);
  163.     }
  164.     return vtr;
  165. }
  166.  
  167. //inserts an edge connecting the given vertices and adds said edge to both vertices' adjacency lists
  168. void WeightedGraph::insertEdge(string src, string dst, double cost) {
  169.  
  170.     Vertex* srcVertex = _internalVertexMap[src];
  171.     Vertex* dstVertex = _internalVertexMap[dst];
  172.     Edge* newEdge = new Edge(cost, srcVertex, dstVertex);          //create a new edge
  173.     srcVertex->addNeighbor(newEdge);                    //add edge to incidence lists of both vertices
  174.     dstVertex->addNeighbor(newEdge);
  175.     _globalEdgeMap[make_pair(srcVertex, dstVertex)] = newEdge;          //add edge to the global list (for printing purposes)
  176.  
  177.     /*
  178.     for(GraphIterator itr = _internalVertexMap.begin(); itr != _internalVertexMap.end(); ++itr) {
  179.         cout << "Opposite of " << itr->second->name << " is ";
  180.         try {
  181.             cout << opposite(itr->second, newEdge)->name << endl;
  182.         }
  183.         catch (logic_error &incidenceFailure) {
  184.             cout << incidenceFailure.what() << endl;
  185.         }
  186.     }
  187.     */
  188. }
  189.  
  190. //returns the weight of the edge between two vertices. If the vertices are not adjacent, then the largest possible double is returned.
  191. double WeightedGraph::getDistance(Vertex* src, Vertex* dst) throw (logic_error) {
  192.  
  193.     //if one or both vertices have no incident edges, throw an exception.
  194.     if (src->neighbors().empty() || dst->neighbors().empty()) throw logic_error("Vertex is a singleton");
  195.     else if (src == dst) return 0.0;
  196.     if (areAdjacent(src, dst))
  197.         return _globalEdgeMap[make_pair(src, dst)]->cost();
  198.     else if (areAdjacent(dst, src))
  199.         return _globalEdgeMap[make_pair(dst, src)]->cost();
  200.     else return numeric_limits<double>::infinity();
  201. }
  202.  
  203. //returns a pointer to the vertex opposite to v along the given edge e
  204. Vertex* WeightedGraph::opposite(Vertex* v, Edge* e) throw (logic_error) {
  205.     //if the vertex has no neighbors (i.e., it is the only vertex in the graph, it has no opposite
  206.     //we throw an exception instead of returning a null pointer
  207.     if (v->neighbors().empty()) throw logic_error("Vertex is a singleton");
  208.     if (v == e->fromVertex())
  209.         return e->toVertex();        //if v is the edge's source vertex, return its destination vertex
  210.     else if (v == e->toVertex())
  211.         return e->fromVertex();      //if v is the edge's destination vertex, return its source vertex
  212.     //if the edge is not incident on the vertex, throw an exception
  213.     else throw logic_error("Edge is not incident on the given vertex");
  214. }
  215.  
  216. //returns whether or not two vertices are adjacent
  217. bool WeightedGraph::areAdjacent(Vertex* u, Vertex* v) {
  218.  
  219.     if (_globalEdgeMap.find(make_pair(u, v)) != _globalEdgeMap.end()) return true;
  220.     else return false;
  221. }
  222.  
  223. //Makes all previously visited nodes and edges un-visited.
  224. void WeightedGraph::clearVisited() {
  225.     for(GraphIterator itr = _internalVertexMap.begin(); itr != _internalVertexMap.end(); ++itr) {
  226.         itr->second->setVisited(false);
  227.     }
  228.  
  229.     for (GraphEdgeIterator itr2 = _globalEdgeMap.begin(); itr2 != _globalEdgeMap.end(); ++itr2) {
  230.         itr2->second->setState(UNVISITED);
  231.     }
  232. }
  233.  
  234. //Prints all edges in the graph and their weights.
  235. void WeightedGraph::printGraph() {
  236.  
  237.     cout << "Printing all edges currently in graph: " << endl;
  238.     //for each edge on the list, print its cost and the names of its end vertices
  239.     for(GraphEdgeIterator itr = _globalEdgeMap.begin(); itr != _globalEdgeMap.end(); ++itr) {
  240.         cout << "(" << itr->second->fromVertex()->name << ", " << itr->second->toVertex()->name << ") : cost " << itr->second->cost() << endl;
  241.     }
  242.     cout << endl;
  243. }
  244.  
  245. /*
  246.  * Implementation of class Vertex
  247.  */
  248.  
  249. //returns the adjacency list of the vertex
  250. list<Edge*> Vertex::neighbors() const {
  251.     return _neighbors;
  252. }
  253.  
  254. //adds an edge to the vertex's adjacency list
  255. void Vertex::addNeighbor(Edge* e) {
  256.     _neighbors.push_back(e);
  257. }
  258.  
  259. //returns a pointer to this vertex's parent vertex (for traversal purposes)
  260. Vertex* Vertex::parent() const {
  261.     return _parent;
  262. }
  263.  
  264. //sets the vertex's parent vertex (for traversal purposes)
  265. void Vertex::setParent(Vertex* v) {
  266.     _parent = v;
  267. }
  268.  
  269. //returns whether this vertex has been visited previously in a traversal
  270. bool Vertex::visited() const {
  271.     return _visited;
  272. }
  273.  
  274. void Vertex::setVisited(bool visitState) {
  275.     _visited = visitState;
  276. }
  277.  
  278. /*
  279.  * Implementation of class Edge
  280.  */
  281.  
  282. //returns the edge weight
  283. double Edge::cost() const {
  284.     return _cost;
  285. }
  286.  
  287. //returns the edge's current state (for traversal purposes)
  288. enum EdgeState Edge::currentState() const {
  289.     return _state;
  290. }
  291.  
  292. //sets the edge's current state to either discovery or back (for traversal purposes)
  293. void Edge::setState(EdgeState state) {
  294.     _state = state;
  295. }
  296.  
  297. //returns the edge's source vertex
  298. Vertex* Edge::fromVertex() const {
  299.     return _src;
  300. }
  301.  
  302. //returns the edge's destination vertex
  303. Vertex* Edge::toVertex() const {
  304.     return _dest;
  305. }
  306.  
  307. //sets the edge's source vertex
  308. void Edge::setSource(Vertex* sourceVertex) {
  309.     _src = sourceVertex;
  310. }
  311.  
  312. //sets the edge's destination vertex
  313. void Edge::setDest(Vertex* destVertex) {
  314.     _dest = destVertex;
  315. }
  316.  
  317. //sets the edge weight
  318. void Edge::setCost(double weight) {
  319.     _cost = weight;
  320. }
  321.  
  322. /*
  323.  * GraphTest.cpp
  324.  *
  325.  *  Created on: Apr 30, 2011
  326.  *      Author: cirvante
  327.  */
  328.  
  329. #include <stack>
  330. #include <queue>
  331. #include <iostream>
  332. #include <fstream>
  333. #include <omp.h>
  334. #include "WeightedGraph.h"
  335.  
  336. void depthFirstSearch(WeightedGraph& graph, string startV, string endV);
  337. void enqueueAll(WeightedGraph& graph, Vertex* v, list<Edge*> adjList, queue<Vertex*>& nq);
  338.  
  339. void DijkstraShortestPath(WeightedGraph& graph, string sourceV);
  340. void printPQ(priority_queue< Edge*, vector<Edge*>, PathCompare > pq);
  341.  
  342. int main() {
  343.  
  344.     WeightedGraph wg = WeightedGraph();
  345.  
  346.     char filename[64];
  347.     cout << "Enter filename: ";
  348.     cin >> filename;
  349.    
  350.     ifstream inFile(filename, ios::in);
  351.     if (!inFile) {
  352.         cout << "ERROR: File not found, terminating..." << endl;
  353.         return 1;
  354.     }
  355.  
  356.     char v1[64];
  357.     char v2[64];
  358.     double wt;
  359.  
  360.     while (inFile >> v1 >> v2 >> wt) {
  361.         wg.insertVertex(v1);
  362.         wg.insertVertex(v2);
  363.         wg.insertEdge(v1, v2, wt);
  364.     }
  365.    
  366.     //uncommenting this and commenting the file-handling code makes it work right
  367.     /*
  368.     wg.insertVertex("narf");
  369.     wg.insertVertex("balls");
  370.     wg.insertVertex("narf");
  371.     wg.insertVertex("foo");
  372.     wg.insertVertex("derp");
  373.     wg.insertVertex("pie");
  374.     wg.insertVertex("cox");
  375.     wg.insertEdge("foo", "derp", 50);
  376.     wg.insertEdge("narf", "balls", 30);
  377.     wg.insertEdge("foo", "balls", 20);
  378.     wg.insertEdge("balls", "derp", 60);
  379.     wg.insertEdge("derp", "narf", 40);
  380.     wg.insertEdge("derp", "cox", 30);
  381.     wg.insertEdge("foo", "narf", 50);
  382.     wg.insertEdge("narf", "pie", 99);
  383.     wg.insertEdge("cox", "pie", 15);
  384.     wg.insertEdge("cox", "narf", 10);
  385.     */
  386.  
  387.     wg.printGraph();
  388.  
  389.     vector<string> vid = wg.getVertexNames();
  390.    
  391.     #pragma omp parallel for ordered
  392.     for (int i = 0; i < vid.size(); ++i) {
  393.         #pragma omp ordered
  394.         cout << "[thread:" << omp_get_thread_num() << "] ";
  395.         DijkstraShortestPath(wg, vid[i]);
  396.     }
  397.  
  398.     return 0;
  399.  
  400. }
  401.  
  402. void depthFirstSearch(WeightedGraph& graph, string startV, string endV) {
  403.  
  404.  
  405.     stack<Vertex*, vector<Vertex*> > vStack;
  406.     queue<Vertex*> vQueue;
  407.     bool found = false;
  408.  
  409.     Vertex *start, *end, *u, *v;
  410.  
  411.     start = graph.getVertex(startV);
  412.     end = graph.getVertex(endV);
  413.  
  414.     graph.clearVisited();
  415.     vStack.push(start);
  416.  
  417.     cout << "Performing depth-first search of vertex " << end->name << " from vertex " << start->name << endl;
  418.  
  419.     do {
  420.         u = vStack.top();
  421.         vStack.pop();
  422.         if (u == end) {
  423.             cout << u->name << endl;;
  424.             found = true;
  425.         }
  426.         else {
  427.             if (u->visited() == false) {
  428.                 u->setVisited(true);
  429.                 cout << u->name << " --> ";
  430.                 enqueueAll(graph, u, u->neighbors(), vQueue);
  431.  
  432.                 while (!vQueue.empty()) {
  433.                     v = vQueue.front();
  434.                     vQueue.pop();
  435.                     if (v->visited() == false) vStack.push(v);
  436.                 }
  437.             }
  438.         }
  439.     }
  440.     while (!vStack.empty() && !found);
  441.  
  442.     if (!found) cout << "Vertex was not found.";
  443.     cout << endl;
  444.  
  445. }
  446.  
  447. void enqueueAll(WeightedGraph& graph, Vertex* v, list<Edge*> adjList, queue<Vertex*>& nq) {
  448.     for (AdjListIterator itr = adjList.begin(); itr != adjList.end(); ++itr) {
  449.         Vertex* vte = graph.opposite(v, *itr);
  450.         nq.push(vte);
  451.     }
  452. }
  453.  
  454. void DijkstraShortestPath(WeightedGraph& graph, string sourceV) {
  455.  
  456.     Vertex* src = graph.getVertex(sourceV);
  457.     Edge* pathEdge = new Edge(0.0, src, src);
  458.     double minDist;
  459.     priority_queue< Edge*, vector<Edge*>, PathCompare > pq;
  460.     queue<Vertex*> vQueue;
  461.     Vertex* v;
  462.  
  463.     graph.clearVisited();
  464.     pq.push(pathEdge);
  465.  
  466.     cout << "Showing single-source shortest path run for source vertex " << src->name << ". Format is (start, end) : cost." << endl;
  467.  
  468.     do {
  469.         pathEdge = pq.top();
  470.         pq.pop();
  471.         //Vertex* from = pathEdge->fromVertex();
  472.         Vertex* to = pathEdge->toVertex();
  473.         if (to->visited() == false) {
  474.             to->setVisited(true);
  475.             //cout << "(" << from->name << ", " << to->name << " : cost " << pathEdge->cost() << ")" << endl;
  476.             cout << "(" << src->name << ", " << to->name << " : cost " << pathEdge->cost() << ")" << endl;
  477.             pathEdge->setSource(to);
  478.             minDist = pathEdge->cost();
  479.  
  480.             enqueueAll(graph, pathEdge->fromVertex(), pathEdge->fromVertex()->neighbors(), vQueue);
  481.  
  482.             while (!vQueue.empty()) {
  483.                 v = vQueue.front();
  484.                 vQueue.pop();
  485.  
  486.                 if (v->visited() == false) {
  487.                     pathEdge->setDest(v);
  488.                     //cout << from->name << " " << v->name <<endl;
  489.                     //cout << pathEdge->cost() << endl;
  490.                     pathEdge->setCost(minDist + graph.getDistance(pathEdge->fromVertex(), v));
  491.                     //cout << pathEdge->cost() << endl;
  492.                     pq.push(new Edge(pathEdge->cost(), pathEdge->fromVertex(), pathEdge->toVertex()));
  493.                     //printPQ(pq);
  494.                 }
  495.             }
  496.         }
  497.     }
  498.     while(!pq.empty());
  499.  
  500.     cout << endl;
  501.  
  502. }
  503.  
  504. void printPQ(priority_queue< Edge*, vector<Edge*>, PathCompare > pq) {
  505.     cout << "Printing contents of edge priority queue: " << endl;
  506.     while (!pq.empty()) {
  507.         Edge* e = pq.top();
  508.         cout << e->fromVertex()->name << " " << e->toVertex()->name << " " << e->cost() << endl;
  509.         pq.pop();
  510.     }
  511.     cout << endl;
  512. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement