edge_index zero for all edges? - c++

Defining my boost::graph like the following, I get edge indices zero for all edges. Why? What am I doing wrong?
#include <iostream>
#include <boost/graph/adjacency_list.hpp>
int main() {
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS, boost::no_property, boost::property<boost::edge_index_t, std::size_t> > Graph;
typedef boost::graph_traits<Graph>::edge_descriptor Edge;
Graph g(3);
Edge e1 = boost::add_edge(0, 1, g).first;
Edge e2 = boost::add_edge(1, 2, g).first;
Edge e3 = boost::add_edge(2, 0, g).first;
boost::property_map<Graph, boost::edge_index_t>::type eim = boost::get(boost::edge_index, g);
size_t e1n = eim[e1],
e2n = eim[e2],
e3n = eim[e3];
return 0;
}
As far as I can tell from documentation and examples, this should work.

An adjacency_list doesn't have an edge index associated with it, only a vertex index. Which is quite logical once you think about how the graph is stored.
To have an edge index, you need to manually add it to the graph description, and then manually handle it.

Related

How to use boost make_label_writer to write edge properties?

I have a simple graph, I suceeded writing properties with the vertex, but when I use make_label_writer to write properties to the edges, the complier always complains. Could someone help with it?
My code is as following:
int main (int argc, char * argv[]) {
typedef std::pair<int ,int> Edge;
std::vector<Edge> used_by = {Edge(1, 0), Edge(2, 1),
Edge(1,2), Edge(2, 0)};
using namespace boost;
typedef adjacency_list<vecS, vecS, directedS
> Graph;
Graph g(used_by.begin(), used_by.end(), 3);
std::ofstream dmp;
dmp.open("dmp.dot");
//name for vertex
std::vector<std::string> name{"one", "two", "three"};
//name for edge
std::vector<std::string> name1{"e1", "e2", "e3", "e4"};
write_graphviz(std::cout, g, make_label_writer(&name[0])
,make_label_writer(&name1[0]));
}
The write_graphviz() will ofc called the template, which is perfectly fine :
template <typename Graph, typename VertexWriter, typename
EdgeWriter>
inline void
write_graphviz(std::ostream& out, const Graph& g,
VertexWriter vw, EdgeWriter ew
BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,vertex_list_graph_tag))
{
default_writer gw;
write_graphviz(out, g, vw, ew, gw);
}
So the problem is now: when I only write the vertex properties using make_label_writer(&name[0]]]), the code runs perfectly. But when I add make_label_writer(&name1[0]), there is error.
The default vertex index is integral, which is why you can use the address of the first vertex name as implied associative property map.
The edge descriptor is a different beast and requires you to either
create an explicit iterator property map (using an extra index property map to map from edge descriptor to the integral index into the name1 vector)
or use a model of the Associative PropertyMap concept.
In this case you should property do the later using a std::map<edge_descriptor, std::string>.
Please also consider making your life with properties a lot simpler by using Bundled Properties.
Associative Property Map
Live On Coliru
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graphviz.hpp>
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS> Graph;
int main() {
Graph g(3);
auto e1 = add_edge(1, 0, g).first;
auto e2 = add_edge(2, 1, g).first;
auto e3 = add_edge(1, 2, g).first;
auto e4 = add_edge(2, 0, g).first;
std::vector<std::string> vname{ "one", "two", "three" };
std::map<Graph::edge_descriptor, std::string> ename{
{ e1, "e1" },
{ e2, "e2" },
{ e3, "e3" },
{ e4, "e4" },
};
write_graphviz(std::cout, g,
boost::make_label_writer(&vname[0]),
make_label_writer(boost::make_assoc_property_map(ename)));
}
Prints
Bundled Properties Instead
Live On Coliru
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graphviz.hpp>
struct VertexProps { std::string name; };
struct EdgeProps { std::string name; };
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS, VertexProps, EdgeProps> Graph;
int main() {
Graph g(3);
g[0].name = "one";
g[1].name = "two";
g[2].name = "three";
add_edge(1, 0, {"e1"}, g);
add_edge(2, 1, {"e2"}, g);
add_edge(1, 2, {"e3"}, g);
add_edge(2, 0, {"e4"}, g);
write_graphviz(std::cout, g,
make_label_writer(get(&VertexProps::name, g)),
make_label_writer(get(&EdgeProps::name, g)));
}
Prints the same

How to set the same edge weight in a graph using a loop using Boost Graph Library?

As the Boost documentation might include this but it seems very hard to understand those parameters in my knowledge of programming, from the documentation and some examples I came up with a question: What If I want to set all edge weights to be the same (for example: 1)?
Obviously I don't want to use
boost::add_edge(vertice1, vertice2, weight, graph);
for endless time if the graph is big enough to have many many edges.
It would be appreciate if someone can offer some examples to run.
You don't show any code (except what you don't want to write...).
The exact form would depend on that. E.g. here's with a bundled weight property:
Live On Coliru
#include <boost/graph/adjacency_list.hpp>
#include <boost/range/iterator_range.hpp>
struct VertexProps { };
struct EdgeProps { double weight; };
int main() {
boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS, VertexProps, EdgeProps> g;
for (auto ed : boost::make_iterator_range(edges(g)))
g[ed].weight = 1.0;
}
Of course, you could basically achieve the same with a proper default:
struct EdgeProps { double weight = 1.0; };
and you wouldn't even need a loop.
With a property map
First adapting from the above:
auto weight_map = get(&EdgeProps::weight, g);
for (auto ed : boost::make_iterator_range(edges(g)))
weight_map[ed] = 1.0;
Interior Properties
Which would also work with something else than bundled properties:
Live On Coliru
#include <boost/graph/adjacency_list.hpp>
#include <boost/range/iterator_range.hpp>
int main() {
boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS, boost::no_property, boost::property<boost::edge_weight_t, double> > g;
auto weight_map = get(boost::edge_weight, g);
for (auto ed : boost::make_iterator_range(edges(g)))
weight_map[ed] = 1.0;
}
External Properties
Or with completely external properties
using Graph = boost::adjacency_list<>;
Graph g(10);
std::map<Graph::edge_descriptor, double> weights;
auto weight_map = boost::make_assoc_property_map(weights);
for (auto ed : boost::make_iterator_range(edges(g)))
weight_map[ed] = 1.0;
Lastly
If the goal is just to have identical weights, just use a constant map:
auto weight_map = boost::make_constant_property<Graph::edge_descriptor>(1.0);

in boost graph lib, how do I get a specific out-edge of a vertex without iterating over all the out-edges of that vertex?

Let's say I have a graph, with edges each containing a char. From a vertex, I want to get a specific out-edge with a specific char. Since the edge container can be set to a set or a hash-set, I assume there is a way to do this without iterating through the vertex's out-edges. I'm also assuming/hoping the edge container is keyed on the type the edge contains.
#include <boost/graph/adjacency_list.hpp>
using namespace boost;
typedef boost::adjacency_list<setS, vecS, directedS, std::string, char> MyGraph;
typedef boost::graph_traits<MyGraph>::vertex_descriptor Vertex;
typedef boost::graph_traits<MyGraph>::edge_descriptor Edge;
MyGraph g;
//setup
add_vertex(std::string("xxx"), g);
Vertex currentVertex = g.vertex_set()[0];
Vertex endVertex = add_vertex(std::string("yyy"), g);
add_edge(currentVertex, endVertex, 'i', g);
//later...
//Now I want that edge containing the letter 'i'.
//out_edges returns a pair of edge iterators.
std::pair<iterator, iterator> iterators = out_edges(currentVertex, g); // do not want!
Edge iEdge = how_do_I_get_This?(currentVertex, g); // want!
Is there a way to do this, or is iterating through the out-edges the only option?
update:
I think this will get me the container.
std::set<?> edges = g.out_edge_list(currentVertex);
Now I cannot figure out what the ? template type is.
update2:
This seems to compile, but I need an edge_descriptor, not an edge_property to pass to target.
std::set<boost::detail::stored_edge_property<long unsigned int, char> > edges = fGraph.out_edge_list(currentVertex);
update3:
Guess I don't need an edge descriptor. Got what I needed like this:
std::set<boost::detail::stored_edge_property<long unsigned int, char> > edges = fGraph.out_edge_list(currentVertex);
std::_Rb_tree_const_iterator<boost::detail::stored_edge_property<long unsigned int, char> > edge = edges.find(*i);
Vertex target = edge.get_target();
This all compiles and seems to work, but it is massively ugly.
Are you looking for how to use edge descriptors?
Edge i_edge = add_edge(currentVertex, endVertex, 'i', g).first;
i_edge is the vertex-descriptor for the 'i' edge.
// later...
// Now I want that edge containing the letter 'i'.
char yougotit = g[i_edge];
Check it:
assert('i' == yougotit);
See it Live On Coliru
If you really want to search, and can use c++1y you might find this elegant: Also Live
#include <boost/graph/adjacency_list.hpp>
#include <boost/range/algorithm.hpp>
#include <boost/range/adaptors.hpp>
#include <iostream>
using namespace boost::adaptors;
using namespace boost;
typedef boost::adjacency_list<setS, vecS, directedS, std::string, char> MyGraph;
typedef boost::graph_traits<MyGraph>::vertex_descriptor Vertex;
typedef boost::graph_traits<MyGraph>::edge_descriptor Edge;
int main() {
MyGraph g;
// setup
add_vertex(std::string("xxx"), g);
Vertex currentVertex = g.vertex_set()[0];
Vertex endVertex = add_vertex(std::string("yyy"), g);
add_edge(currentVertex, endVertex, 'i', g);
for (auto matching : boost::edges(g) | filtered([&g](auto const& e) { return g[e] == 'i'; }))
std::cout << matching << " --> " << g[matching] << "\n";
}
Output:
(0,1) --> i

Limited depth search in BGL without O(number_of_vertices) used memory or time?

Is it possible to do a depth or breadth first search/visit up to some distance from a vertex in BGL without accessing, filtering, indexing, etc. all vertices in the graph?
The closest thing I've managed to write is (creates the graph 0<->1<->2<->3<->4<->5 but only visits vertices 0 to 3):
#include <iostream>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/depth_first_search.hpp>
using namespace std;
struct custom_dfs_visitor : public boost::default_dfs_visitor {
template < typename Vertex, typename Graph >
void discover_vertex(const Vertex& v, const Graph& g) const {
std::cout << v << std::endl;
}
};
struct Terminator {
template<class Vertex, class Graph>
bool operator()(const Vertex& v, const Graph& g) {
return v > 2;
}
};
int main()
{
typedef boost::adjacency_list<
boost::vecS,
boost::vecS,
boost::undirectedS
> Graph_T;
Graph_T g(6);
boost::add_edge(0, 1, g);
boost::add_edge(1, 2, g);
boost::add_edge(2, 3, g);
boost::add_edge(3, 4, g);
boost::add_edge(4, 5, g);
std::vector<boost::default_color_type> color_map(boost::num_vertices(g));
boost::depth_first_visit(
g,
boost::vertex(0, g),
custom_dfs_visitor(),
boost::make_iterator_property_map(
color_map.begin(),
boost::get(boost::vertex_index, g),
color_map[0]
),
Terminator()
);
return 0;
}
which does only print 0 1 2 3 instead of visiting all vertices, but the code still requires a color map as large as the whole graph (boost::num_vertices(g)). Is there a way to make the search complexity not be at all comparable to the total number of edges/vertices in the graph?
Using a bundled color would be acceptable because many searches would be done in different parts of the graph, but is it possible to reduce the complexity of each individual search in the same graph from O(number_of_vertices)?
Initial coloring of vertices will hopefully also stop when Terminator returns true but that seems to be taken care of already.
Maybe a related question: What about indexing if the graph uses something else than vecS? Can BFS/DFS do without indexing in that case?
Thanks for any help.
Turns out using bundled properties is the easiest way to accomplish this. The fact that the color property is included in every vertex is better than creating the color property for each vertex every time a dfs is done. The graph type should be
typedef boost::adjacency_list<
boost::vecS,
boost::vecS,
boost::undirectedS,
property<vertex_color_t, boost::default_color_type>
> Graph_T;
and the call to dfv is
depth_first_visit(
g,
vertex(0, g),
custom_dfs_visitor(),
get(vertex_color_t(), g),
Terminator()
);
With the above, doing a limited dfs in a graph with 100 M vertices doesn't increase memory consumption (76.2 % of total memory) while with an external vector of colors memory usage increases from 76.2 % to 78.5 % while searching.

Passing only an element of a std::vector property to a BGL algorithm

I have a graph with multiple edge weightings stored as
namespace boost {
enum edge_weightvector_t {
edge_weightvector = 1337
};
BOOST_INSTALL_PROPERTY(edge, weightvector);
}
typedef boost::adjacency_list<
boost::vecS,
boost::vecS,
boost::undirectedS,
boost::no_property,
boost::property<boost::edge_weightvector_t, std::vector<int> >
> graph_t;
The weightings are all pushed onto the vector.
Now I want to call the prim_minimum_spanning_tree() function on the graph, with the first elements in the vector used as weightings.
How can I perform a correct function call?
I've did it now by first copying the desired weightings to an additional property, then running the algorithm and copying back afterwards. It is ugly, but it does the trick in my case.
I recently tried to do the same (to use a vector property) and failed to run algorithms only with one of the values. However, I found that using exterior properties is a good approach that won't lead to unnecessary copy actions and to pass the property map explicitly to the algorithm.
If you use random access containers you can use boost::iterator_property_map that will wrap that container and make it a property_map. Instead of edge descriptors it requires 0-based edge indices for the efficient mapping between edges and property values. Here is the punchline, further done you find the complete example:
// ...
EdgeIndexMap edgeIds = get(edge_index, g);
// ...
typedef std::vector<int> Weights;
typedef std::vector<Weights> WeightsVector;
typedef iterator_property_map <Weights::iterator, EdgeIndexMap> WeightMap;
// ...
Weights weights; // = ...
WeightMap wm(weights.begin(), edgeIds);
// ...
some_bgl_algorithm(g, wm);
And here a complete example:
using namespace boost;
void sampleExteriorProperties()
{
typedef adjacency_list<vecS, vecS, undirectedS,
no_property,
//property<edge_index_t, int, property<edge_weight_t, int> >
property<edge_index_t, std::size_t>
> Graph;
typedef graph_traits<Graph>::edge_descriptor Edge;
typedef graph_traits<Graph>::edge_iterator EdgeIterator;
typedef property_map<Graph, edge_index_t>::type EdgeIndexMap;
//typedef property_map<Graph, edge_weight_t>::type WeightMap;
const int NVERTICES = 5;
const int NEDGES = 8;
Graph g(NVERTICES);
// Add edges WITH indexes.
int edgeIndex = 0;
add_edge(0, 1, edgeIndex++, g);
add_edge(0, 2, edgeIndex++, g);
add_edge(0, 3, edgeIndex++, g);
add_edge(1, 2, edgeIndex++, g);
add_edge(1, 4, edgeIndex++, g);
add_edge(2, 3, edgeIndex++, g);
add_edge(2, 4, edgeIndex++, g);
add_edge(3, 4, edgeIndex++, g);
// Weights: there must be a weight for every edge.
// Weights will be later on accessed by edge index.
assert(num_edges(g) == NEDGES);
typedef std::vector<int> Weights;
typedef std::vector<Weights> WeightsVector;
WeightsVector weightVector({ { 2, 3, 5, 7, 9, 11, 13, 17 },
{ 8, 7, 6, 5, 4, 3, 2, 1 }
});
EdgeIndexMap edgeIds = get(edge_index, g);
for (Weights &weights : weightVector)
{
// Use the iterator_property_map to read the properties from a
// random access container. Remember: Edge ids are used to access
// the correct value from the container!
typedef iterator_property_map <Weights::iterator, EdgeIndexMap> WeightMap;
WeightMap wm(weights.begin(), edgeIds);
EdgeIterator eIt, eItEnd;
tie(eIt, eItEnd) = edges(g);
while (eIt!=eItEnd)
{
std::cout << *eIt << ": " << wm[*eIt] << " ";
++eIt;
}
std::cout << std::endl;
// Explicitly pass the exterior map to the algorithm.
std::vector<Edge> mstEdges;
kruskal_minimum_spanning_tree(g, std::back_inserter(mstEdges),
weight_map(wm));
std::for_each(mstEdges.begin(), mstEdges.end(),
[](const Edge &val){std::cout << val << " ";});
std::cout << std::endl;
}
}