diff --git a/doc/graph_tool.rst b/doc/graph_tool.rst index f9473bc7e40dceba82093531377e517672370b03..3d8cfe9d66f575e220c3e2b1b35f39a3eeea1e4c 100644 --- a/doc/graph_tool.rst +++ b/doc/graph_tool.rst @@ -18,11 +18,24 @@ See :ref:`sec_iteration` for more documentation and examples. - Iterator-based interface: + Iterator-based interface with descriptors: .. automethod:: vertices .. automethod:: edges + Iterator-based interface without descriptors: + + .. automethod:: iter_vertices + .. automethod:: iter_edges + + .. automethod:: iter_out_edges + .. automethod:: iter_in_edges + .. automethod:: iter_all_edges + + .. automethod:: iter_out_neighbors + .. automethod:: iter_in_neighbors + .. automethod:: iter_all_neighbors + Array-based interface: .. automethod:: get_vertices diff --git a/doc/quickstart.rst b/doc/quickstart.rst index bcb9bf8a810abb43a498a2f279e5adea4ce46916..2fa9543fe089968cb5d3c3935b58d0933ccc3d2d 100644 --- a/doc/quickstart.rst +++ b/doc/quickstart.rst @@ -348,13 +348,76 @@ vertices in the graph. is being used. Removal during iteration will cause bad things to happen. -Fast iteration over vertices and edges -"""""""""""""""""""""""""""""""""""""" +Faster iteration over vertices and edges without descriptor +""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +The mode of iteration considered above is convenient, but requires the +creation of vertex and edge descriptor objects, which incurs a +performance overhead. A faster approach involves the use of the methods +:meth:`~graph_tool.Graph.iter_vertices`, +:meth:`~graph_tool.Graph.iter_edges`, +:meth:`~graph_tool.Graph.iter_out_edges`, +:meth:`~graph_tool.Graph.iter_in_edges`, +:meth:`~graph_tool.Graph.iter_all_edges`, +:meth:`~graph_tool.Graph.iter_out_neighbors`, +:meth:`~graph_tool.Graph.iter_in_neighbors`, +:meth:`~graph_tool.Graph.iter_all_neighbors`, which return vertex +indexes and pairs thereof, instead of descriptors objects, to specify +vertex and edges, respectively. + +The equivalent of the above examples can be obtained as: -While convenient, looping over the graph as described in the previous -section is not the most efficient approach. This is because the loops -are performed in pure Python, and hence it undermines the main feature -of the library, which is the offloading of loops from Python to +.. testcode:: + + for v in g.iter_vertices(): + print(v) + for e in g.iter_edges(): + print(e) + +.. testoutput:: + :hide: + + 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + (0, 1) + (2, 3) + +and likewise for the iteration over the neighborhood of a vertex: + +.. testcode:: + + for v in g.iter_vertices(): + for e in g.iter_out_edges(v): + print(e) + for w in g.iter_out_neighbors(v): + print(w) + +.. testoutput:: + :hide: + + (0, 1) + 1 + (2, 3) + 3 + + +Even faster iteration over vertices and edges using arrays +"""""""""""""""""""""""""""""""""""""""""""""""""""""""""" + +While more convenient, looping over the graph as described in the +previous sections are not the most efficient approaches. This is because +the loops are performed in pure Python, and hence it undermines the main +feature of the library, which is the offloading of loops from Python to C++. Following the :mod:`numpy` philosophy, :mod:`graph_tool` also provides an array-based interface that avoids loops in Python. This is done with the :meth:`~graph_tool.Graph.get_vertices`, diff --git a/src/graph_tool/__init__.py b/src/graph_tool/__init__.py index 6002dc2fdec1480d62066b49b545995f153ddec9..52f549d22c8a1fe5e50b492637293824eb676b57 100644 --- a/src/graph_tool/__init__.py +++ b/src/graph_tool/__init__.py @@ -1787,7 +1787,9 @@ class Graph(object): >>> assert(vlist == vlist2) """ - return libcore.get_vertices(self.__graph) + viter = libcore.get_vertices(self.__graph) + viter._g = self + return viter def iter_vertices(self, vprops=[]): """Return an iterator over the vertex indices, and optional vertex properties @@ -1814,8 +1816,10 @@ class Graph(object): 5 """ - return libcore.get_vertex_iter(self.__graph, 0, - [vp._get_any() for vp in vprops]) + viter = libcore.get_vertex_iter(self.__graph, 0, + [vp._get_any() for vp in vprops]) + viter._g = self + return viter def get_vertices(self, vprops=[]): """Return a :class:`numpy.ndarray` containing the vertex indices, and optional @@ -1902,7 +1906,9 @@ class Graph(object): ordering. """ - return libcore.get_edges(self.__graph) + eiter = libcore.get_edges(self.__graph) + eiter._g = self + return eiter def iter_edges(self, eprops=[]): """Return an iterator over the edge ```(source, target)`` pairs, and optional @@ -1916,16 +1922,19 @@ class Graph(object): Examples -------- - >>> g = gt.random_graph(6, lambda: 1, directed=False) - >>> for s, t, i in g.iter_edges([g.edge_index]) + >>> g = gt.collection.data["karate"] + >>> for s, t, i in g.iter_edges([g.edge_index]): ... print(s, t, i) + ... if s == 5: + ... break 2 1 2 3 4 0 5 0 1 - """ - return libcore.get_edge_iter(self.__graph, 0, - [ep._get_any() for ep in eprops]) + eiter = libcore.get_edge_iter(self.__graph, 0, + [ep._get_any() for ep in eprops]) + eiter._g = self + return eiter def get_edges(self, eprops=[]): """Return a :class:`numpy.ndarray` containing the edges, and optional edge @@ -1964,15 +1973,18 @@ class Graph(object): Examples -------- >>> g = gt.collection.data["pgp-strong-2009"] - >>> for s, t, i in g.iter_out_edges(66, [g.edge_index]) + >>> for s, t, i in g.iter_out_edges(66, [g.edge_index]): ... print(s, t, i) - 2 1 2 - 3 4 0 - 5 0 1 - + 66 63 5266 + 66 20369 5267 + 66 13980 5268 + 66 8687 5269 + 66 38674 5270 """ - return libcore.get_out_edge_iter(self.__graph, int(v), - [ep._get_any() for ep in eprops]) + eiter = libcore.get_out_edge_iter(self.__graph, int(v), + [ep._get_any() for ep in eprops]) + eiter._g = self + return eiter def get_out_edges(self, v, eprops=[]): """Return a :class:`numpy.ndarray` containing the out-edges of vertex ``v``, and @@ -2009,15 +2021,16 @@ class Graph(object): Examples -------- >>> g = gt.collection.data["pgp-strong-2009"] - >>> for s, t, i in g.iter_in_edges(66, [g.edge_index]) + >>> for s, t, i in g.iter_in_edges(66, [g.edge_index]): ... print(s, t, i) - 2 1 2 - 3 4 0 - 5 0 1 - + 8687 66 179681 + 20369 66 255033 + 38674 66 300230 """ - return libcore.get_out_edge_iter(self.__graph, int(v), + eiter = libcore.get_in_edge_iter(self.__graph, int(v), [ep._get_any() for ep in eprops]) + eiter._g = self + return eiter def get_in_edges(self, v, eprops=[]): """Return a :class:`numpy.ndarray` containing the in-edges of vertex ``v``, and @@ -2045,21 +2058,27 @@ class Graph(object): .. note:: This mode of iteration is more efficient than using - :meth:`~graph_tool.Vertex.in_edges`, as descriptor objects are not + :meth:`~graph_tool.Vertex.all_edges`, as descriptor objects are not created. Examples -------- >>> g = gt.collection.data["pgp-strong-2009"] - >>> for s, t, i in g.iter_all_edges(66, [g.edge_index]) + >>> for s, t, i in g.iter_all_edges(66, [g.edge_index]): ... print(s, t, i) - 2 1 2 - 3 4 0 - 5 0 1 - + 66 63 5266 + 66 20369 5267 + 66 13980 5268 + 66 8687 5269 + 66 38674 5270 + 8687 66 179681 + 20369 66 255033 + 38674 66 300230 """ - return libcore.get_out_edge_iter(self.__graph, int(v), - [ep._get_any() for ep in eprops]) + eiter = libcore.get_all_edge_iter(self.__graph, int(v), + [ep._get_any() for ep in eprops]) + eiter._g = self + return eiter def get_all_edges(self, v, eprops=[]): """Return a :class:`numpy.ndarray` containing the in- and out-edges of vertex v, @@ -2099,15 +2118,18 @@ class Graph(object): Examples -------- >>> g = gt.collection.data["pgp-strong-2009"] - >>> for s, t, i in g.iter_out_neighbors(66, [g.vp.uid]) - ... print(s, t, i) - 2 1 2 - 3 4 0 - 5 0 1 - + >>> for u, i in g.iter_out_neighbors(66, [g.vp.uid]): + ... print(u, i) + 63 ['paul wilders '] + 20369 ['Zhen-Xjell '] + 13980 ['Hooman '] + 8687 ['H. Loeung (howe81) ', 'howe81 ', 'Howie L (howe81) '] + 38674 ['Howie L (howe81) '] """ - return libcore.get_out_neighbors_iter(self.__graph, int(v), - [vp._get_any() for vp in vprops]) + viter = libcore.get_out_neighbors_iter(self.__graph, int(v), + [vp._get_any() for vp in vprops]) + viter._g = self + return viter iter_out_neighbours = iter_out_neighbors @@ -2148,15 +2170,16 @@ class Graph(object): Examples -------- >>> g = gt.collection.data["pgp-strong-2009"] - >>> for s, t, i in g.iter_in_neighbors(66, [g.vp.uid]) - ... print(s, t, i) - 2 1 2 - 3 4 0 - 5 0 1 - + >>> for u, i in g.iter_in_neighbors(66, [g.vp.uid]): + ... print(u, i) + 8687 ['H. Loeung (howe81) ', 'howe81 ', 'Howie L (howe81) '] + 20369 ['Zhen-Xjell '] + 38674 ['Howie L (howe81) '] """ - return libcore.get_in_neighbors_iter(self.__graph, int(v), - [vp._get_any() for vp in vprops]) + viter = libcore.get_in_neighbors_iter(self.__graph, int(v), + [vp._get_any() for vp in vprops]) + viter._g = self + return viter iter_in_neighbours = iter_in_neighbors @@ -2197,15 +2220,21 @@ class Graph(object): Examples -------- >>> g = gt.collection.data["pgp-strong-2009"] - >>> for s, t, i in g.iter_all_neighbors(66, [g.vp.uid]) - ... print(s, t, i) - 2 1 2 - 3 4 0 - 5 0 1 - + >>> for u, i in g.iter_all_neighbors(66, [g.vp.uid]): + ... print(u, i) + 63 ['paul wilders '] + 20369 ['Zhen-Xjell '] + 13980 ['Hooman '] + 8687 ['H. Loeung (howe81) ', 'howe81 ', 'Howie L (howe81) '] + 38674 ['Howie L (howe81) '] + 8687 ['H. Loeung (howe81) ', 'howe81 ', 'Howie L (howe81) '] + 20369 ['Zhen-Xjell '] + 38674 ['Howie L (howe81) '] """ - return libcore.get_in_neighbors_iter(self.__graph, int(v), - [vp._get_any() for vp in vprops]) + viter = libcore.get_all_neighbors_iter(self.__graph, int(v), + [vp._get_any() for vp in vprops]) + viter._g = self + return viter iter_all_neighbours = iter_all_neighbors