Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
graph-tool
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
40
Issues
40
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Incidents
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Tiago Peixoto
graph-tool
Commits
fb37166a
Commit
fb37166a
authored
Feb 17, 2017
by
Tiago Peixoto
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add support for iterating over all vertices in {dfs,bfs,dijkstra}_{search,iterator}()
parent
5752f5eb
Pipeline
#262
passed with stage
in 184 minutes and 22 seconds
Changes
6
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
189 additions
and
69 deletions
+189
-69
src/graph/graph_bind.cc
src/graph/graph_bind.cc
+3
-0
src/graph/search/graph_bfs.cc
src/graph/search/graph_bfs.cc
+41
-12
src/graph/search/graph_dfs.cc
src/graph/search/graph_dfs.cc
+27
-20
src/graph/search/graph_dijkstra.cc
src/graph/search/graph_dijkstra.cc
+52
-8
src/graph_tool/__init__.py
src/graph_tool/__init__.py
+1
-0
src/graph_tool/search/__init__.py
src/graph_tool/search/__init__.py
+65
-29
No files found.
src/graph/graph_bind.cc
View file @
fb37166a
...
...
@@ -576,4 +576,7 @@ BOOST_PYTHON_MODULE(libgraph_tool_core)
.
add_property
(
"gcc_version"
,
&
LibInfo
::
GetGCCVersion
);
def
(
"get_graph_type"
,
&
get_graph_type
);
def
(
"get_null_vertex"
,
+
[](){
return
graph_traits
<
GraphInterface
::
multigraph_t
>::
null_vertex
();});
}
src/graph/search/graph_bfs.cc
View file @
fb37166a
...
...
@@ -106,20 +106,28 @@ private:
boost
::
python
::
object
_vis
;
};
struct
do_bfs
{
template
<
class
Graph
,
class
Visitor
>
void
operator
()(
Graph
&
g
,
size_t
s
,
Visitor
vis
)
const
{
breadth_first_search
(
g
,
vertex
(
s
,
g
),
visitor
(
vis
));
}
};
void
bfs_search
(
GraphInterface
&
g
,
size_t
s
,
python
::
object
vis
)
void
bfs_search
(
GraphInterface
&
g
i
,
size_t
s
,
python
::
object
vis
)
{
run_action
<
graph_tool
::
all_graph_views
,
mpl
::
true_
>
()
(
g
,
std
::
bind
(
do_bfs
(),
std
::
placeholders
::
_1
,
s
,
BFSVisitorWrapper
(
g
,
vis
)))();
(
gi
,
[
&
](
auto
&
g
)
{
typedef
typename
std
::
remove_reference
<
decltype
(
g
)
>::
type
g_t
;
typename
vprop_map_t
<
default_color_type
>::
type
color
(
get
(
vertex_index_t
(),
g
));
auto
visw
=
BFSVisitorWrapper
(
gi
,
vis
);
auto
v
=
vertex
(
s
,
g
);
if
(
v
==
graph_traits
<
g_t
>::
null_vertex
())
{
for
(
auto
u
:
vertices_range
(
g
))
breadth_first_search
(
g
,
u
,
visitor
(
visw
).
color_map
(
color
));
}
else
{
breadth_first_visit
(
g
,
v
,
visitor
(
visw
).
color_map
(
color
));
}
})();
}
#ifdef HAVE_BOOST_COROUTINE
...
...
@@ -152,7 +160,28 @@ boost::python::object bfs_search_generator(GraphInterface& g, size_t s)
{
BFSGeneratorVisitor
vis
(
g
,
yield
);
run_action
<
graph_tool
::
all_graph_views
,
mpl
::
true_
>
()
(
g
,
std
::
bind
(
do_bfs
(),
std
::
placeholders
::
_1
,
s
,
vis
))();
(
g
,
[
&
](
auto
&
g
)
{
typedef
typename
std
::
remove_reference
<
decltype
(
g
)
>::
type
g_t
;
typename
vprop_map_t
<
default_color_type
>::
type
color
(
get
(
vertex_index_t
(),
g
));
auto
v
=
vertex
(
s
,
g
);
if
(
v
==
graph_traits
<
g_t
>::
null_vertex
())
{
for
(
auto
u
:
vertices_range
(
g
))
{
if
(
color
[
u
]
==
color_traits
<
default_color_type
>::
black
())
continue
;
breadth_first_visit
(
g
,
u
,
visitor
(
vis
).
color_map
(
color
));
}
}
else
{
breadth_first_visit
(
g
,
v
,
visitor
(
vis
).
color_map
(
color
));
}
})();
};
return
boost
::
python
::
object
(
CoroGenerator
(
dispatch
));
#else
...
...
src/graph/search/graph_dfs.cc
View file @
fb37166a
...
...
@@ -90,25 +90,22 @@ private:
python
::
object
_vis
;
};
struct
do_dfs
void
dfs_search
(
GraphInterface
&
gi
,
size_t
s
,
python
::
object
vis
)
{
template
<
class
Graph
,
class
VertexIndexMap
,
class
Visitor
>
void
operator
()(
Graph
&
g
,
VertexIndexMap
vertex_index
,
size_t
s
,
Visitor
vis
)
const
{
typename
property_map_type
::
apply
<
default_color_type
,
VertexIndexMap
>::
type
color
(
vertex_index
);
depth_first_visit
(
g
,
vertex
(
s
,
g
),
vis
,
color
);
}
};
void
dfs_search
(
GraphInterface
&
g
,
size_t
s
,
python
::
object
vis
)
{
run_action
<
graph_tool
::
all_graph_views
,
mpl
::
true_
>
()
(
g
,
std
::
bind
(
do_dfs
(),
std
::
placeholders
::
_1
,
g
.
get_vertex_index
(),
s
,
DFSVisitorWrapper
(
g
,
vis
)))();
run_action
<
graph_tool
::
all_graph_views
,
mpl
::
true_
>
()
(
gi
,
[
&
](
auto
&
g
)
{
typedef
typename
std
::
remove_reference
<
decltype
(
g
)
>::
type
g_t
;
typename
vprop_map_t
<
default_color_type
>::
type
color
(
get
(
vertex_index_t
(),
g
));
auto
visw
=
DFSVisitorWrapper
(
gi
,
vis
);
auto
v
=
vertex
(
s
,
g
);
if
(
v
==
graph_traits
<
g_t
>::
null_vertex
())
depth_first_search
(
g
,
visw
,
color
);
else
depth_first_visit
(
g
,
v
,
visw
,
color
);
})();
}
#ifdef HAVE_BOOST_COROUTINE
...
...
@@ -142,8 +139,18 @@ boost::python::object dfs_search_generator(GraphInterface& g, size_t s)
{
DFSGeneratorVisitor
vis
(
g
,
yield
);
run_action
<
graph_tool
::
all_graph_views
,
mpl
::
true_
>
()
(
g
,
std
::
bind
(
do_dfs
(),
std
::
placeholders
::
_1
,
g
.
get_vertex_index
(),
s
,
vis
))();
(
g
,
[
&
](
auto
&
g
)
{
typedef
typename
std
::
remove_reference
<
decltype
(
g
)
>::
type
g_t
;
typename
vprop_map_t
<
default_color_type
>::
type
color
(
get
(
vertex_index_t
(),
g
));
auto
v
=
vertex
(
s
,
g
);
if
(
v
==
graph_traits
<
g_t
>::
null_vertex
())
depth_first_search
(
g
,
vis
,
color
);
else
depth_first_visit
(
g
,
v
,
vis
,
color
);
})();
};
return
boost
::
python
::
object
(
CoroGenerator
(
dispatch
));
#else
...
...
src/graph/search/graph_dijkstra.cc
View file @
fb37166a
...
...
@@ -140,11 +140,33 @@ struct do_djk_search
typedef
typename
graph_traits
<
Graph
>::
edge_descriptor
edge_t
;
DynamicPropertyMapWrap
<
dtype_t
,
edge_t
>
weight
(
aweight
,
edge_properties
());
dijkstra_shortest_paths_no_color_map
(
g
,
vertex
(
s
,
g
),
visitor
(
vis
).
weight_map
(
weight
).
predecessor_map
(
pred_map
).
distance_map
(
dist
).
distance_compare
(
cmp
).
distance_combine
(
cmb
).
distance_inf
(
i
).
distance_zero
(
z
));
if
(
vertex
(
s
,
g
)
==
graph_traits
<
Graph
>::
null_vertex
())
{
for
(
auto
u
:
vertices_range
(
g
))
{
vis
.
initialize_vertex
(
u
,
g
);
put
(
dist
,
u
,
i
);
put
(
pred_map
,
u
,
u
);
}
for
(
auto
u
:
vertices_range
(
g
))
{
if
(
dist
[
u
]
!=
i
)
continue
;
dist
[
u
]
=
z
;
dijkstra_shortest_paths_no_color_map_no_init
(
g
,
u
,
pred_map
,
dist
,
weight
,
get
(
vertex_index_t
(),
g
),
cmp
,
cmb
,
i
,
z
,
vis
);
}
}
else
{
dijkstra_shortest_paths_no_color_map
(
g
,
vertex
(
s
,
g
),
visitor
(
vis
).
weight_map
(
weight
).
predecessor_map
(
pred_map
).
distance_map
(
dist
).
distance_compare
(
cmp
).
distance_combine
(
cmb
).
distance_inf
(
i
).
distance_zero
(
z
));
}
}
};
...
...
@@ -158,9 +180,31 @@ struct do_djk_search_fast
typedef
typename
property_traits
<
DistanceMap
>::
value_type
dtype_t
;
dtype_t
z
=
python
::
extract
<
dtype_t
>
(
range
.
first
);
dtype_t
i
=
python
::
extract
<
dtype_t
>
(
range
.
second
);
dijkstra_shortest_paths_no_color_map
(
g
,
vertex
(
s
,
g
),
visitor
(
vis
).
weight_map
(
weight
).
distance_map
(
dist
).
distance_inf
(
i
).
distance_zero
(
z
));
if
(
vertex
(
s
,
g
)
==
graph_traits
<
Graph
>::
null_vertex
())
{
for
(
auto
u
:
vertices_range
(
g
))
{
vis
.
initialize_vertex
(
u
,
g
);
put
(
dist
,
u
,
i
);
}
for
(
auto
u
:
vertices_range
(
g
))
{
if
(
dist
[
u
]
!=
i
)
continue
;
dist
[
u
]
=
z
;
dijkstra_shortest_paths_no_color_map_no_init
(
g
,
u
,
dummy_property_map
(),
dist
,
weight
,
get
(
vertex_index_t
(),
g
),
std
::
less
<
dtype_t
>
(),
boost
::
closed_plus
<
dtype_t
>
(),
i
,
z
,
vis
);
}
}
else
{
dijkstra_shortest_paths_no_color_map
(
g
,
vertex
(
s
,
g
),
visitor
(
vis
).
weight_map
(
weight
).
distance_map
(
dist
).
distance_inf
(
i
).
distance_zero
(
z
));
}
}
};
...
...
src/graph_tool/__init__.py
View file @
fb37166a
...
...
@@ -3261,6 +3261,7 @@ VertexBase.is_valid = Vertex.is_valid
Vertex
=
VertexBase
Vertex
.
__name__
=
"Vertex"
_get_null_vertex
=
libcore
.
get_null_vertex
# Add convenience function to vector classes
def
_get_array_view
(
self
):
...
...
src/graph_tool/search/__init__.py
View file @
fb37166a
...
...
@@ -92,7 +92,7 @@ if sys.version_info < (3,):
from
..
dl_import
import
dl_import
dl_import
(
"from . import libgraph_tool_search"
)
from
..
import
_prop
,
_python_type
from
..
import
_prop
,
_python_type
,
_get_null_vertex
import
weakref
import
numpy
...
...
@@ -157,15 +157,17 @@ class BFSVisitor(object):
return
def
bfs_search
(
g
,
source
,
visitor
=
BFSVisitor
()):
def
bfs_search
(
g
,
source
=
None
,
visitor
=
BFSVisitor
()):
r
"""Breadth-first traversal of a directed or undirected graph.
Parameters
----------
g : :class:`~graph_tool.Graph`
Graph to be used.
source : :class:`~graph_tool.Vertex`
Source vertex.
source : :class:`~graph_tool.Vertex` (optional, default: ``None``)
Source vertex. If unspecified, all vertices will be traversed, by
iterating over starting vertices according to their index in increasing
order.
visitor : :class:`~graph_tool.search.BFSVisitor` (optional, default: ``BFSVisitor()``)
A visitor object that is invoked at the event points inside the
algorithm. This should be a subclass of
...
...
@@ -284,12 +286,16 @@ def bfs_search(g, source, visitor=BFSVisitor()):
"""
try
:
if
source
is
None
:
source
=
_get_null_vertex
()
else
:
source
=
int
(
source
)
libgraph_tool_search
.
bfs_search
(
g
.
_Graph__graph
,
int
(
source
)
,
visitor
)
source
,
visitor
)
except
StopSearch
:
pass
def
bfs_iterator
(
g
,
source
):
def
bfs_iterator
(
g
,
source
=
None
):
r
"""Return an iterator of the edges corresponding to a breath-first traversal of
the graph.
...
...
@@ -297,8 +303,10 @@ def bfs_iterator(g, source):
----------
g : :class:`~graph_tool.Graph`
Graph to be used.
source : :class:`~graph_tool.Vertex`
Source vertex.
source : :class:`~graph_tool.Vertex` (optional, default: ``None``)
Source vertex. If unspecified, all vertices will be traversed, by
iterating over starting vertices according to their index in increasing
order.
Returns
-------
...
...
@@ -341,8 +349,11 @@ def bfs_iterator(g, source):
.. [bfs-bgl] http://www.boost.org/doc/libs/release/libs/graph/doc/breadth_first_search.html
.. [bfs-wikipedia] http://en.wikipedia.org/wiki/Breadth-first_search
"""
return
libgraph_tool_search
.
bfs_search_generator
(
g
.
_Graph__graph
,
int
(
source
))
if
source
is
None
:
source
=
_get_null_vertex
()
else
:
source
=
int
(
source
)
return
libgraph_tool_search
.
bfs_search_generator
(
g
.
_Graph__graph
,
source
)
class
DFSVisitor
(
object
):
...
...
@@ -415,15 +426,17 @@ class DFSVisitor(object):
return
def
dfs_search
(
g
,
source
,
visitor
=
DFSVisitor
()):
def
dfs_search
(
g
,
source
=
None
,
visitor
=
DFSVisitor
()):
r
"""Depth-first traversal of a directed or undirected graph.
Parameters
----------
g : :class:`~graph_tool.Graph`
Graph to be used.
source : :class:`~graph_tool.Vertex`
Source vertex.
source : :class:`~graph_tool.Vertex` (optional, default: ``None``)
Source vertex. If unspecified, all vertices will be traversed, by
iterating over starting vertices according to their index in increasing
order.
visitor : :class:`~graph_tool.search.DFSVisitor` (optional, default: ``DFSVisitor()``)
A visitor object that is invoked at the event points inside the
algorithm. This should be a subclass of
...
...
@@ -563,15 +576,20 @@ def dfs_search(g, source, visitor=DFSVisitor()):
----------
.. [dfs-bgl] http://www.boost.org/doc/libs/release/libs/graph/doc/depth_first_search.html
.. [dfs-wikipedia] http://en.wikipedia.org/wiki/Depth-first_search
"""
try
:
if
source
is
None
:
source
=
_get_null_vertex
()
else
:
source
=
int
(
source
)
libgraph_tool_search
.
dfs_search
(
g
.
_Graph__graph
,
int
(
source
)
,
visitor
)
source
,
visitor
)
except
StopSearch
:
pass
def
dfs_iterator
(
g
,
source
):
def
dfs_iterator
(
g
,
source
=
None
):
r
"""Return an iterator of the edges corresponding to a depth-first traversal of
the graph.
...
...
@@ -579,8 +597,10 @@ def dfs_iterator(g, source):
----------
g : :class:`~graph_tool.Graph`
Graph to be used.
source : :class:`~graph_tool.Vertex`
Source vertex.
source : :class:`~graph_tool.Vertex` (optional, default: ``None``)
Source vertex. If unspecified, all vertices will be traversed, by
iterating over starting vertices according to their index in increasing
order.
Returns
-------
...
...
@@ -622,7 +642,11 @@ def dfs_iterator(g, source):
.. [dfs-wikipedia] http://en.wikipedia.org/wiki/Depth-first_search
"""
return
libgraph_tool_search
.
dfs_search_generator
(
g
.
_Graph__graph
,
int
(
source
))
if
source
is
None
:
source
=
_get_null_vertex
()
else
:
source
=
int
(
source
)
return
libgraph_tool_search
.
dfs_search_generator
(
g
.
_Graph__graph
,
source
)
class
DijkstraVisitor
(
object
):
r
"""A visitor object that is invoked at the event-points inside the
...
...
@@ -686,7 +710,7 @@ class DijkstraVisitor(object):
return
def
dijkstra_search
(
g
,
source
,
weight
,
visitor
=
DijkstraVisitor
(),
dist_map
=
None
,
def
dijkstra_search
(
g
,
weight
,
source
=
None
,
visitor
=
DijkstraVisitor
(),
dist_map
=
None
,
pred_map
=
None
,
combine
=
lambda
a
,
b
:
a
+
b
,
compare
=
lambda
a
,
b
:
a
<
b
,
zero
=
0
,
infinity
=
numpy
.
inf
):
r
"""Dijsktra traversal of a directed or undirected graph, with non-negative weights.
...
...
@@ -695,10 +719,12 @@ def dijkstra_search(g, source, weight, visitor=DijkstraVisitor(), dist_map=None,
----------
g : :class:`~graph_tool.Graph`
Graph to be used.
source : :class:`~graph_tool.Vertex`
Source vertex.
weight : :class:`~graph_tool.PropertyMap`
Edge property map with weight values.
source : :class:`~graph_tool.Vertex` (optional, default: ``None``)
Source vertex. If unspecified, all vertices will be traversed, by
iterating over starting vertices according to their index in increasing
order.
visitor : :class:`~graph_tool.search.DijkstraVisitor` (optional, default: ``DijkstraVisitor()``)
A visitor object that is invoked at the event points inside the
algorithm. This should be a subclass of
...
...
@@ -815,7 +841,7 @@ def dijkstra_search(g, source, weight, visitor=DijkstraVisitor(), dist_map=None,
With the above class defined, we can perform the Dijkstra search as follows.
>>> time = g.new_vertex_property("int")
>>> dist, pred = gt.dijkstra_search(g,
g.vertex(0), weight
, VisitorExample(name, time))
>>> dist, pred = gt.dijkstra_search(g,
weight, g.vertex(0)
, VisitorExample(name, time))
--> Bob has been discovered!
edge (Bob, Eve) has been examined...
edge (Bob, Eve) has been relaxed...
...
...
@@ -910,8 +936,12 @@ def dijkstra_search(g, source, weight, visitor=DijkstraVisitor(), dist_map=None,
infinity
=
_python_type
(
dist_map
.
value_type
())(
infinity
)
try
:
if
source
is
None
:
source
=
_get_null_vertex
()
else
:
source
=
int
(
source
)
libgraph_tool_search
.
dijkstra_search
(
g
.
_Graph__graph
,
int
(
source
)
,
source
,
_prop
(
"v"
,
g
,
dist_map
),
_prop
(
"v"
,
g
,
pred_map
),
_prop
(
"e"
,
g
,
weight
),
visitor
,
...
...
@@ -921,7 +951,7 @@ def dijkstra_search(g, source, weight, visitor=DijkstraVisitor(), dist_map=None,
return
dist_map
,
pred_map
def
dijkstra_iterator
(
g
,
source
,
weight
,
dist_map
=
None
,
combine
=
None
,
def
dijkstra_iterator
(
g
,
weight
,
source
=
None
,
dist_map
=
None
,
combine
=
None
,
compare
=
None
,
zero
=
0
,
infinity
=
numpy
.
inf
):
r
"""Return an iterator of the edges corresponding to a Dijkstra traversal of
the graph.
...
...
@@ -930,10 +960,12 @@ def dijkstra_iterator(g, source, weight, dist_map=None, combine=None,
----------
g : :class:`~graph_tool.Graph`
Graph to be used.
source : :class:`~graph_tool.Vertex`
Source vertex.
weight : :class:`~graph_tool.PropertyMap`
Edge property map with weight values.
source : :class:`~graph_tool.Vertex` (optional, default: ``None``)
Source vertex. If unspecified, all vertices will be traversed, by
iterating over starting vertices according to their index in increasing
order.
dist_map : :class:`~graph_tool.PropertyMap` (optional, default: ``None``)
A vertex property map where the distances from the source will be
stored.
...
...
@@ -972,7 +1004,7 @@ def dijkstra_iterator(g, source, weight, dist_map=None, combine=None,
Examples
--------
>>> for e in gt.dijkstra_iterator(g,
g.vertex(0), weight
):
>>> for e in gt.dijkstra_iterator(g,
weight, g.vertex(0)
):
... print(name[e.source()], "->", name[e.target()])
Bob -> Eve
Bob -> Chuck
...
...
@@ -1009,9 +1041,13 @@ def dijkstra_iterator(g, source, weight, dist_map=None, combine=None,
infinity
=
(
weight
.
a
.
max
()
+
1
)
*
g
.
num_vertices
()
infinity
=
_python_type
(
dist_map
.
value_type
())(
infinity
)
if
source
is
None
:
source
=
_get_null_vertex
()
else
:
source
=
int
(
source
)
if
compare
is
None
and
combine
is
None
:
return
libgraph_tool_search
.
dijkstra_generator_fast
(
g
.
_Graph__graph
,
int
(
source
)
,
source
,
_prop
(
"v"
,
g
,
dist_map
),
_prop
(
"e"
,
g
,
weight
),
zero
,
infinity
)
...
...
@@ -1021,7 +1057,7 @@ def dijkstra_iterator(g, source, weight, dist_map=None, combine=None,
if
combine
is
None
:
combine
=
lambda
a
,
b
:
a
+
b
return
libgraph_tool_search
.
dijkstra_generator
(
g
.
_Graph__graph
,
int
(
source
)
,
source
,
_prop
(
"v"
,
g
,
dist_map
),
_prop
(
"e"
,
g
,
weight
),
compare
,
combine
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment