// // C++ Interface: graph // // Description: // // // Author: Alex Brandt , (C) 2007 // // Copyright: See COPYING file that comes with this distribution // // #ifndef GRAPH_H #define GRAPH_H #include #include #include #include #include #include #include #include #include #include #include #include #include "vertex.h" /** @brief The Graphs namespace for all of our graphing tools. This namespace is where all corrollary objects to a Graph should be placed. It will keep our programming cleaner, and tighter. */ namespace Graphs { /** @brief Weighting enum for keywording the Graph. This enum allows us to pass the keyword to the graph upon instantiation. This sets up the graph in the desired way so that we have more control in whether it is weighted. */ enum Weighting { Weighted, //!< Weighted Graph will be created. Unweighted //!< Unweighted Graph will be created. }; /** @brief Direction enum for keywording the Graph. This enum allows us to pass the keyword to the graph upon instantiation. This sets up the graph in the desired way so that we have more control in whether it is weighted. */ enum Direction { Directed, //!< Directed Graph will be created. Undirected //!< Undirected Graph will be created. }; /** Fun Things... */ template class Graph; template std::ostream &operator <<(std::ostream &, const Graph &); const int Infinity = static_cast(pow(2,32)); /** @class Graph graph.h @brief Graph class to store networks in memory. @author Alex Brandt This Graph can be Weighted, Unweighted, Directed, or Undirected. */ template class Graph { public: /** Constructor */ Graph(Weighting weighting = Unweighted, Direction direction = Undirected); /** Constructor */ Graph(Direction direction = Undirected, Weighting weighting = Unweighted); /** Constructor */ explicit Graph(); /** Destructor */ ~Graph(); /** Copy Constructor */ Graph(const Graph &otherGraph); /** Assignment Operator */ Graph &operator=(const Graph &otherGraph); /** Delete all edges and vertices. */ void Destroy(void); /** @return True if the Graph is empty; otherwise false. Determine if the Graph is empty. */ bool IsEmpty(void) const; /** @return The number of edges. @sa VertexCount() Count of the number of edges in the graph. */ int EdgeCount(void) const; /** @return The number of vertices. @sa EdgeCount() Count of the number of vertices in the Graph. */ int VertexCount(void) const; /** @param otherVertex Vertex to insert into the Graph. @sa InsertEdge() Insert a vertex into the graph. NOTE: This allocates a new vertex to ensure the reference doesn't go out of scope. */ Vertex & InsertVertex(const Vertex &otherVertex); /** @param data The data to insert in the new vertex. @sa InsertVertex() Pass the data to the Insert method allowing the vertex to be created as it's inserted. */ Vertex & InsertNewVertex(const T &data); /** @param vertexA Starting vertex for the edge. @param vertexB Finishing vertex for the edge. @param weight The weight of the new edge. @sa InsertVertex() Insert an edge into the Graph. */ void InsertEdge(Vertex &vertexA, Vertex &vertexB, const int weight = 1); /** @param vertexA Starting vertex for the edge. @param vertexB Finishing vertex for the edge. @param weight The weight of the new edge. @sa InsertVertex() @sa InsertEdge() Insert a bidirectional edge into the graph. */ void InsertBidirectionalEdge(Vertex &vertexA, Vertex &vertexB, const int weight = 1); /** @param vertexA Starting vertex for the edge. @param vertexB Finishing vertex for the edge. @sa DeleteVertex() Delete a specific edge from the graph. */ void DeleteEdge(Vertex &vertexA, Vertex &vertexB); /** @param otherVertex Vertex to remove from the graph. @sa DeleteEdge Delete a specified vertex, and it's associated edges. */ void DeleteVertex(const Vertex &otherVertex); /** Simply dumps out the graph's contents. */ std::ostream &Dump(std::ostream &) const; /** @param predicate Predicate function to determine when we've found an item in question. @return Set of references to the matched items. Finds all the instances matched by the predicate used, and places references in a set to be returned. */ std::list &> FindAll(boost::function &)> predicate); /** @param predicate Predicate function to determine when we've found an item in question. @return A reference to the first instance that matches. Finds the first instance matched by the predicate used, and returns a reference. */ Vertex & FindVertex(boost::function &)> predicate); /** @param predicate Predicate function to determine when we've found an item in question. @return A reference to the first instance that matches. Finds the first instance matched by the predicate used, and returns a reference. */ Vertex & FindVertex(boost::function *)> predicate); /** @param predicate Predicate function to determine when we'be found an item in question. @return A reference to the first instance that matches. Finds the first instance matched by the predicate used, and returns a reference. */ Vertex & Find(boost::function predicate); /** @param vertexA The source vertex. @param vertexB The destination vertex. @return A queue that is the path to follow. Dijkstra's shortest path from one node to another. */ std::queue*> ShortestPath(const Vertex &vertexA, const Vertex &vertexB); private: std::set*> vertices; //!< The vertices of the graph. Weighting weighting; //!< Weighted graph? Direction direction; //!< Directed graph? int edgeCount; //!< Number of edges. }; template Graph::Graph(Weighting weighting, Direction direction) :vertices(std::set*>()), weighting(weighting), direction(direction), edgeCount(0) { } template Graph::Graph(Direction direction, Weighting weighting) :vertices(std::set*>()), weighting(weighting), direction(direction), edgeCount(0) { } template Graph::Graph() :vertices(std::set*>()), weighting(Unweighted), direction(Undirected), edgeCount(0) { } template Graph::~Graph() { } template Graph::Graph(const Graph &otherGraph) :vertices(otherGraph.vertices), weighting(otherGraph.weighting), direction(otherGraph.direction), edgeCount(otherGraph.edgeCount) { transform(otherGraph.vertices.begin(), otherGraph.vertices.end(), vertices.begin(), boost::lambda::bind(&(new Vertex), otherGraph.vertices, boost::lambda::_1)); } template void Graph::DeleteEdge(Vertex &vertexA, Vertex &vertexB) { vertexA.DeleteNeighbor(vertexB); if (direction == Undirected) vertexB.DeleteNeighbor(vertexA); edgeCount--; return; } template void Graph::DeleteVertex(const Vertex &otherVertex) { vertices.erase(const_cast*>(&otherVertex)); return; } template void Graph::Destroy(void) { vertices.clear(); return; } template std::ostream &Graph::Dump(std::ostream &out) const { out << "Dumping graph:" << std::endl; out << "\tNumber of Vertices: " << VertexCount() << "\tNumber of Edges: " << EdgeCount() << "\n"; for_each(vertices.begin(), vertices.end(), boost::lambda::var(out) << *boost::lambda::_1 << boost::lambda::constant("\n")); return out; } template int Graph::EdgeCount(void) const { return edgeCount; } template void Graph::InsertEdge(Vertex &vertexA, Vertex &vertexB, const int weight) { vertexA.CreateNeighbor(vertexB, weight); if (direction == Undirected) vertexB.CreateNeighbor(vertexA, weight); edgeCount++; return; } template void Graph::InsertBidirectionalEdge(Vertex &vertexA, Vertex &vertexB, const int weight) { vertexA.CreateNeighbor(vertexB, weight); vertexB.CreateNeighbor(vertexA, weight); edgeCount++; edgeCount++; return; } template Vertex & Graph::InsertVertex(const Vertex &otherVertex) { return **vertices.insert(new Vertex(otherVertex)).first; } template Vertex & Graph::InsertNewVertex(const T &data) { return InsertVertex(Vertex(data)); } template bool Graph::IsEmpty(void) const { return vertices.empty(); } template Graph &Graph::operator=(const Graph &otherGraph) { if (this != &otherGraph) { this->direction = otherGraph.direction; this->edgeCount = otherGraph.edgeCount; this->vertexCount = otherGraph.vertexCount; this->vertices = transform(otherGraph.vertices.begin(), otherGraph.vertices.end(), vertices.begin(), boost::lambda::bind(&(new Vertex, boost::lambda::_1))); this->weighting = otherGraph.weighting; } return *this; } template int Graph::VertexCount(void) const { return vertices.size(); } template std::list &> Graph::FindAll(boost::function &)> predicate) { std::list &> foundItems; // The items we have found using the predicate provided. for_each(vertices.begin(), vertices.end(), if_(predicate(boost::lambda::_1))[boost::lambda::bind(&std::list &>::push_back, foundItems, boost::lambda::_1)]); return foundItems; } template Vertex & Graph::FindVertex(boost::function &)> predicate) { return FindVertex(static_cast*)> >(boost::lambda::bind(predicate, *boost::lambda::_1))); } template Vertex & Graph::FindVertex(boost::function *)> predicate) { return **find_if(vertices.begin(), vertices.end(), predicate); } template Vertex & Graph::Find(boost::function predicate) { return FindVertex(static_cast*)> >(boost::lambda::bind(predicate, boost::lambda::bind(&Vertex::Get, *boost::lambda::_1)))); } template std::ostream &operator <<(std::ostream &out, const Graph &graph) { return graph.Dump(out); } template std::queue*> Graph::ShortestPath(const Vertex &vertexA, const Vertex &vertexB) { using namespace boost::lambda; using boost::function; using namespace std; list*> shortestPathList, // The found shortest path. unvisitedNodes; // The nodes we need to visit. map*, int> distance; // The distance map. map*, Vertex*> parents; // The parent lookup list. queue*> shortestPath; // The found shortest path (clean). /* Initialize the sources. */ for_each ( vertices.begin(), vertices.end(), ( var(distance)[_1] = constant(Infinity), var(parents)[_1] = constant(static_cast*>(NULL)) ) ); distance[&vertexA] = 0; /* Make the priority queue with all of our vertices in it. */ for_each ( vertices.begin(), vertices.end(), bind(&list*>::push_back, var(unvisitedNodes), _1) ); /* Dijkstra's Algorithm (modified to end when we hit the target: */ while (!unvisitedNodes.empty() && *min_element(unvisitedNodes.begin(), unvisitedNodes.end(), var(distance)[_1] < var(distance)[_2]) != &vertexB) { Vertex *current = *min_element(unvisitedNodes.begin(), unvisitedNodes.end(), var(distance)[_1] < var(distance)[_2]); unvisitedNodes.remove(current); shortestPathList.push_back(current); list*> neighbors = current->Neighbors(); for_each ( neighbors.begin(), neighbors.end(), if_( var(distance)[_1] > (var(distance[current]) + bind(&Vertex::GetWeight, var(current), *_1)) ) [ var(distance)[_1] = var(distance[current]) + bind(&Vertex::GetWeight, var(parents)[_1] = var(current), *_1) ] ); } shortestPathList.push_back(*min_element(unvisitedNodes.begin(), unvisitedNodes.end(), var(distance)[_1] < var(distance)[_2])); /* Remove extra crappy nodes. */ reverse(shortestPathList.begin(), shortestPathList.end()); for (typename list*>::iterator i = shortestPathList.begin(); *i != &vertexA;) { if (parents[*i] != *(++i)) { shortestPathList.remove(*i); i = shortestPathList.begin(); } } reverse(shortestPathList.begin(), shortestPathList.end()); for_each ( shortestPathList.begin(), shortestPathList.end(), bind(&queue*>::push, var(shortestPath), _1) ); return shortestPath; } } #endif