How to use boost make_label_writer to write edge properties? - c++

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

Related

can boost vf2 deal with muti-graph like this situation?

I want to use vf2 in this situation.
Graph gsmall,glarge;
add_vertex(vertex_prop('a'),gsmall);
add_vertex(vertex_prop('b'),gsmall);
add_edge(0, 1, edge_prop('m'), gsmall);
add_vertex(vertex_prop('a'),glarge);
add_vertex(vertex_prop('b'),glarge);
add_edge(0, 1, edge_prop('m'), glarge);
add_edge(0, 1, edge_prop('n'), glarge);
std::cout << is_subgraph_isomorphic(gsmall,glarge) << std::endl;
If the pattern's property of edge can match with graph's part of properties of edge, then return true, but now it must match all. That example returns false. I want to make it true, so how?
Edit:
I solved this question. Use vector and overload operator "=="
http://coliru.stacked-crooked.com/a/6307210b2861bc63
But I found another problem. It will give wrong results when there is self-loops in graph.
http://coliru.stacked-crooked.com/a/46d336ecfddbbab9 is true
but http://coliru.stacked-crooked.com/a/413d56146ceffd42 is false.
I think they are both ture. I can't understand how it could be like this.
Please help me again! Thanks!
Boost can deal with it. However, you're not looking for a isomorphism in the sense of the library:
An isomorphism between two graphs G1=(V1, E1) and G2=(V2, E2) is a bijective mapping M of the vertices of one graph to vertices of the other graph that preserves the edge structure of the graphs
So, for all corresponding vertices, the same edges need to be present. In other words, the subgraph may be smaller (lower order) but each vertex must have equivalent structure (this implies the same number of edges).
In your case the small graph is structurally different because the large graph has a self loop, but the small doesn't. (The self loop is significant because both vertices exist in the subgraph).
If you really think for your purpose you need to ignore self loops, you'll have to filter them out.
Here's an example that employs the filtered_graph adaptor to achieve that:
Live On Coliru
#include <vector>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/vf2_sub_graph_iso.hpp>
#include <boost/graph/filtered_graph.hpp>
#include <boost/container/flat_set.hpp>
#include <boost/container/small_vector.hpp>
template <typename SortedRange1, typename SortedRange2,
typename V = std::common_type_t<typename boost::range_value<SortedRange1>::type, typename boost::range_value<SortedRange2>::type>,
typename Cmp = std::less<V> >
static inline bool has_intersection(SortedRange1 const& a, SortedRange2 const& b, Cmp cmp = {}) {
auto equivalent = [cmp](V const& a, V const& b)
{ return !cmp(a,b) && !cmp(b,a); };
auto ai = a.begin();
auto bi = b.begin();
while (ai != a.end() && (bi = b.lower_bound(*ai)) != b.end())
if (equivalent(*ai++, *bi))
return true;
return false;
}
// Define graph type
using Label = char;
struct EdgeProperties {
using Labels = boost::container::flat_set<char, std::less<>, boost::container::small_vector<char, 3> >;
EdgeProperties(std::initializer_list<Label> elabels = {}) :_elabels(elabels) {}
bool operator==(EdgeProperties const& other) const {
return has_intersection(_elabels, other._elabels);
}
Labels _elabels;
};
typedef boost::property<boost::edge_name_t, EdgeProperties> edge_prop;
typedef boost::property<boost::vertex_name_t, long/*, boost::property<boost::vertex_index_t, int>*/ > vertex_prop;
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS, vertex_prop, edge_prop> Graph;
int main()
{
Graph gsmall, glarge;
add_vertex(vertex_prop('a'),gsmall);
add_vertex(vertex_prop('b'),gsmall);
add_edge(0, 1, edge_prop({'m'}), gsmall);
//add_edge(0, 0, edge_prop({'n'}), gsmall);
add_vertex(vertex_prop('a'),glarge);
add_vertex(vertex_prop('b'),glarge);
add_vertex(vertex_prop('c'),glarge);
add_edge(0, 1, edge_prop({'m'}), glarge);
add_edge(0, 0, edge_prop({'n'}), glarge);
add_edge(0, 2, edge_prop({'o'}), glarge);
// Create predicate of edge
auto edge_comp = make_property_map_equivalent(
get(boost::edge_name, gsmall),
get(boost::edge_name, glarge));
// Create callback
boost::vf2_print_callback<Graph, Graph> callback(gsmall, glarge);
struct FilterSelfEdges {
Graph const* _g;
bool operator()(Graph::edge_descriptor ed) const {
return source(ed, *_g) != target(ed, *_g);
}
};
using Filtered = boost::filtered_graph<Graph, FilterSelfEdges>;
// Execute
const bool result = boost::vf2_subgraph_iso(
gsmall, Filtered(glarge, FilterSelfEdges{&glarge}), callback, boost::vertex_order_by_mult(gsmall),
boost::edges_equivalent(edge_comp));
std::cout << "subgraph isomorphic? " << std::boolalpha << result << std::endl;
}
Prints
(0, 0) (1, 1)
subgraph isomorphic? true

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

Creating graph in loop from Boost library c++

I am trying to convert myself from R to C++ and am struggling with a particular graph problem. I have a String Matrix called "Gra" as below.
int main(){
string Gra[4][5] = {{"V0", "V1", "V2", "V3", "V4"},
{"V5", "V6", "NA", "NA", "V7"},
{"V8", "V9", "NA", "NA", "V10"},
{"V11", "V12", "V13", "V14", "V15"}};
Where "V0" represents a node and "NA" is not. This matrix came from the matrix called "base"
int base[4][5] = {{1, 1, 1, 1, 1},
{1, 1, 0, 0, 1},
{1, 1, 0, 0, 1},
{1, 1, 1, 1, 1}};
typedef float Weight;
typedef boost::property<boost::edge_weight_t, Weight> WeightProperty;
typedef boost::property<boost::vertex_name_t, std::string> NameProperty;
typedef boost::adjacency_list < boost::listS, boost::vecS, boost::directedS,
NameProperty, WeightProperty > Graph;
typedef boost::graph_traits < Graph >::vertex_descriptor Vertex;
typedef boost::property_map < Graph, boost::vertex_index_t >::type IndexMap;
typedef boost::property_map < Graph, boost::vertex_name_t >::type NameMap;
typedef boost::iterator_property_map < Vertex*, IndexMap, Vertex, Vertex& > PredecessorMap;
typedef boost::iterator_property_map < Weight*, IndexMap, Weight, Weight& > DistanceMap;
Graph g;
Where the problem is, trying to describe the graph in a loop. I would like to declare the nodes as
Vertex V0 = boost::add_vertex(std::string("V0"), g); // Struggling to implement this in a loop
Vertex V1 = boost::add_vertex(std::string("V1"), g);
Vertex V2 = boost::add_vertex(std::string("V2"), g);
Vertex V3 = boost::add_vertex(std::string("V3"), g);
Vertex V4 = boost::add_vertex(std::string("V4"), g);
Vertex V5 = boost::add_vertex(std::string("V5"), g);
Vertex V6 = boost::add_vertex(std::string("V6"), g);
Vertex V7 = boost::add_vertex(std::string("V7"), g);
Vertex V8 = boost::add_vertex(std::string("V8"), g);
Vertex V9 = boost::add_vertex(std::string("V9"), g);
Vertex V10 = boost::add_vertex(std::string("V10"), g);
Vertex V11 = boost::add_vertex(std::string("V11"), g);
Vertex V12 = boost::add_vertex(std::string("V12"), g);
Vertex V13 = boost::add_vertex(std::string("V13"), g);
Vertex V14 = boost::add_vertex(std::string("V14"), g);
Vertex V15 = boost::add_vertex(std::string("V15"), g);
How I have tried to replicate this is through a loop like this.
for ( int i=0; i < 4; i++) // So this will run along all elements of our base vector
{
for ( int j=0; j < 5; j++) // Length is the number of elements in our array
{
if( !(Gra[i][j] == "NA")) // Whilst going along each element inspecting whether it is a true node
{
Vertex Gra[i][j] = boost::add_vertex(std::Gra[i][j], g); // This is where the problem is
}
}
}
So the problem comes from using a string to define this object of class Vertex. Could any body help me? I'm pretty sure this is a naming convention issue that I'm struggling with. If this is solved then I can solve the rest of my problems in terms of creating the edges which I also have the same problem of trying to call an object of class "vertex" using a string.
Thanks in advance Cyrill
The expression !Gra[i][j] == "NA" will not do what you expect it to. It will first check that Gra[i][j] is not "false" and then compare the boolean result with the string "NA".
Instead either use parentheses around the equality check, or do a not-equal check. So either
!(Gra[i][j] == "NA")
or
Gra[i][j] != "NA"
There's also the problem that you declare a local array-of-arrays variable Gra inside the inner loop, which will cause clashes with your outer Gra variable. I guess that's why you use std::Gra there, but Gra is not declared in the standard namespace. Neither can you use ::Gra because Gra is not declared in the global namespace either.
Instead of declaring a new variable inside the inner loop, declare an array Vertexes outside the loop:
Vertex Vertexes[4][5];
Then use that variable to store the result of boost::add_vertex.

edge_index zero for all edges?

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.

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;
}
}