ladanyi@666: /*! ladanyi@666: ladanyi@666: \page graphs How to use graphs ladanyi@666: alpar@756: The primary data structures of HugoLib are the graph classes. They all alpar@756: provide a node list - edge list interface, i.e. they have alpar@756: functionalities to list the nodes and the edges of the graph as well alpar@756: as in incoming and outgoing edges of a given node. alpar@756: alpar@756: alpar@756: Each graph should meet the \ref ConstGraph concept. This concept does alpar@756: makes it possible to change the graph (i.e. it is not possible to add alpar@756: or delete edges or nodes). Most of the graph algorithms will run on alpar@756: these graphs. alpar@756: alpar@756: The graphs meeting the \ref ExtendableGraph concept allow node and alpar@756: edge addition. You can also "clear" (i.e. erase all edges and nodes) alpar@756: such a graph. alpar@756: alpar@756: In case of graphs meeting the full feature \ref ErasableGraph concept alpar@756: you can also erase individual edges and node in arbitrary order. alpar@756: alpar@756: The implemented graph structures are the following. alpar@756: \li \ref hugo::ListGraph "ListGraph" is the most versatile graph class. It meets alpar@756: the ErasableGraph concept and it also have some convenience features. alpar@756: \li \ref hugo::SmartGraph "SmartGraph" is a more memory alpar@756: efficient version of \ref hugo::ListGraph "ListGraph". The alpar@756: price of it is that it only meets the \ref ExtendableGraph concept, alpar@756: so you cannot delete individual edges or nodes. alpar@756: \li \ref hugo::SymListGraph "SymListGraph" and alpar@756: \ref hugo::SymSmartGraph "SymSmartGraph" classes are very similar to alpar@756: \ref hugo::ListGraph "ListGraph" and \ref hugo::SmartGraph "SmartGraph". alpar@756: The difference is that whenever you add a alpar@756: new edge to the graph, it actually adds a pair of oppositely directed edges. alpar@756: They are linked together so it is possible to access the counterpart of an alpar@756: edge. An even more important feature is that using these classes you can also alpar@756: attach data to the edges in such a way that the stored data alpar@756: are shared by the edge pairs. alpar@756: \li \ref hugo::FullGraph "FullGraph" alpar@756: implements a full graph. It is a \ref ConstGraph, so you cannot alpar@756: change the number of nodes once it is constructed. It is extremely memory alpar@756: efficient: it uses constant amount of memory independently from the number of alpar@756: the nodes of the graph. Of course, the size of the \ref maps "NodeMap"'s and alpar@756: \ref maps "EdgeMap"'s will depend on the number of nodes. alpar@756: alpar@756: \li \ref hugo::NodeSet "NodeSet" implements a graph with no edges. This class alpar@756: can be used as a base class of \ref hugo::EdgeSet "EdgeSet". alpar@756: \li \ref hugo::EdgeSet "EdgeSet" can be used to create a new graph on alpar@756: the edge set of another graph. The base graph can be an arbitrary graph and it alpar@756: is possible to attach several \ref hugo::EdgeSet "EdgeSet"'s to a base graph. alpar@756: alpar@756: \todo Don't we need SmartNodeSet and SmartEdgeSet? alpar@756: \todo Some cross-refs are wrong. alpar@756: alpar@756: alpar@756: The graph structures itself can not store data attached alpar@756: to the edges and nodes. However they all provide alpar@756: \ref maps "map classes" alpar@756: to dynamically attach data the to graph components. alpar@756: alpar@756: alpar@756: alpar@756: ladanyi@666: The following program demonstrates the basic features of HugoLib's graph ladanyi@666: structures. ladanyi@666: ladanyi@666: \code ladanyi@666: #include ladanyi@666: #include ladanyi@666: ladanyi@666: using namespace hugo; ladanyi@666: ladanyi@666: int main() ladanyi@666: { ladanyi@666: typedef ListGraph Graph; ladanyi@666: \endcode ladanyi@666: ladanyi@666: ListGraph is one of HugoLib's graph classes. It is based on linked lists, ladanyi@666: therefore iterating throuh its edges and nodes is fast. ladanyi@666: ladanyi@666: \code ladanyi@666: typedef Graph::Edge Edge; ladanyi@666: typedef Graph::InEdgeIt InEdgeIt; ladanyi@666: typedef Graph::OutEdgeIt OutEdgeIt; ladanyi@666: typedef Graph::EdgeIt EdgeIt; ladanyi@666: typedef Graph::Node Node; ladanyi@666: typedef Graph::NodeIt NodeIt; ladanyi@666: ladanyi@666: Graph g; ladanyi@666: ladanyi@666: for (int i = 0; i < 3; i++) ladanyi@666: g.addNode(); ladanyi@666: ladanyi@666: for (NodeIt i(g); g.valid(i); g.next(i)) ladanyi@666: for (NodeIt j(g); g.valid(j); g.next(j)) ladanyi@666: if (i != j) g.addEdge(i, j); ladanyi@666: \endcode ladanyi@666: ladanyi@666: After some convenience typedefs we create a graph and add three nodes to it. ladanyi@666: Then we add edges to it to form a full graph. ladanyi@666: ladanyi@666: \code ladanyi@666: std::cout << "Nodes:"; ladanyi@666: for (NodeIt i(g); g.valid(i); g.next(i)) ladanyi@666: std::cout << " " << g.id(i); ladanyi@666: std::cout << std::endl; ladanyi@666: \endcode ladanyi@666: ladanyi@666: Here we iterate through all nodes of the graph. We use a constructor of the ladanyi@666: node iterator to initialize it to the first node. The next member function is ladanyi@666: used to step to the next node, and valid is used to check if we have passed the ladanyi@666: last one. ladanyi@666: ladanyi@666: \code ladanyi@666: std::cout << "Nodes:"; ladanyi@666: NodeIt n; ladanyi@666: for (g.first(n); n != INVALID; g.next(n)) ladanyi@666: std::cout << " " << g.id(n); ladanyi@666: std::cout << std::endl; ladanyi@666: \endcode ladanyi@666: ladanyi@666: Here you can see an alternative way to iterate through all nodes. Here we use a ladanyi@666: member function of the graph to initialize the node iterator to the first node ladanyi@666: of the graph. Using next on the iterator pointing to the last node invalidates ladanyi@666: the iterator i.e. sets its value to INVALID. Checking for this value is ladanyi@666: equivalent to using the valid member function. ladanyi@666: ladanyi@666: Both of the previous code fragments print out the same: ladanyi@666: ladanyi@666: \code ladanyi@666: Nodes: 2 1 0 ladanyi@666: \endcode ladanyi@666: ladanyi@666: \code ladanyi@666: std::cout << "Edges:"; ladanyi@666: for (EdgeIt i(g); g.valid(i); g.next(i)) ladanyi@666: std::cout << " (" << g.id(g.tail(i)) << "," << g.id(g.head(i)) << ")"; ladanyi@666: std::cout << std::endl; ladanyi@666: \endcode ladanyi@666: ladanyi@666: \code ladanyi@666: Edges: (0,2) (1,2) (0,1) (2,1) (1,0) (2,0) ladanyi@666: \endcode ladanyi@666: ladanyi@666: We can also iterate through all edges of the graph very similarly. The head and ladanyi@666: tail member functions can be used to access the endpoints of an edge. ladanyi@666: ladanyi@666: \code ladanyi@666: NodeIt first_node(g); ladanyi@666: ladanyi@666: std::cout << "Out-edges of node " << g.id(first_node) << ":"; ladanyi@666: for (OutEdgeIt i(g, first_node); g.valid(i); g.next(i)) ladanyi@666: std::cout << " (" << g.id(g.tail(i)) << "," << g.id(g.head(i)) << ")"; ladanyi@666: std::cout << std::endl; ladanyi@666: ladanyi@666: std::cout << "In-edges of node " << g.id(first_node) << ":"; ladanyi@666: for (InEdgeIt i(g, first_node); g.valid(i); g.next(i)) ladanyi@666: std::cout << " (" << g.id(g.tail(i)) << "," << g.id(g.head(i)) << ")"; ladanyi@666: std::cout << std::endl; ladanyi@666: \endcode ladanyi@666: ladanyi@666: \code ladanyi@666: Out-edges of node 2: (2,0) (2,1) ladanyi@666: In-edges of node 2: (0,2) (1,2) ladanyi@666: \endcode ladanyi@666: ladanyi@666: We can also iterate through the in and out-edges of a node. In the above ladanyi@666: example we print out the in and out-edges of the first node of the graph. ladanyi@666: ladanyi@666: \code ladanyi@666: Graph::EdgeMap m(g); ladanyi@666: ladanyi@666: for (EdgeIt e(g); g.valid(e); g.next(e)) ladanyi@666: m.set(e, 10 - g.id(e)); ladanyi@666: ladanyi@666: std::cout << "Id Edge Value" << std::endl; ladanyi@666: for (EdgeIt e(g); g.valid(e); g.next(e)) ladanyi@666: std::cout << g.id(e) << " (" << g.id(g.tail(e)) << "," << g.id(g.head(e)) ladanyi@666: << ") " << m[e] << std::endl; ladanyi@666: \endcode ladanyi@666: ladanyi@666: \code ladanyi@666: Id Edge Value ladanyi@666: 4 (0,2) 6 ladanyi@666: 2 (1,2) 8 ladanyi@666: 5 (0,1) 5 ladanyi@666: 0 (2,1) 10 ladanyi@666: 3 (1,0) 7 ladanyi@666: 1 (2,0) 9 ladanyi@666: \endcode ladanyi@666: ladanyi@666: In generic graph optimization programming graphs are not containers rather ladanyi@666: incidence structures which are iterable in many ways. HugoLib introduces ladanyi@666: concepts that allow us to attach containers to graphs. These containers are ladanyi@666: called maps. ladanyi@666: ladanyi@666: In the example above we create an EdgeMap which assigns an int value to all ladanyi@666: edges of the graph. We use the set member function of the map to write values ladanyi@666: into the map and the operator[] to retrieve them. ladanyi@666: ladanyi@666: Here we used the maps provided by the ListGraph class, but you can also write ladanyi@666: your own maps. You can read more about using maps \ref maps "here". ladanyi@666: ladanyi@666: */