I am trying to run the fruchterman_reingold_force_directed_layout algorithm on a boost::adjacency_list<boost::listS, boost::listS, boost::bidirectionalS, Vertex, Edge> graph.
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/fruchterman_reingold.hpp>
#include <boost/graph/random_layout.hpp>
typedef boost::rectangle_topology<> RectTopology;
typedef RectTopology::point_type point;
struct Vertex {
Vertex(int i) : index(i) {};
int index;
point position;
};
struct Edge {
double weight;
};
typedef boost::adjacency_list<boost::listS, boost::listS, boost::bidirectionalS, Vertex, Edge> Graph;
int main() {
Graph graph;
auto vertexIdPropertyMap = boost::get(&Vertex::index, graph);
Vertex n1(0);
boost::add_vertex(std::move(n1), graph);
Vertex n2(1);
boost::add_vertex(std::move(n2), graph);
Vertex n3(2);
boost::add_vertex(std::move(n3), graph);
boost::add_edge(boost::vertex(0, graph), boost::vertex(1, graph), Edge(), graph);
boost::add_edge(boost::vertex(0, graph), boost::vertex(2, graph), Edge(), graph);
boost::minstd_rand gen;
RectTopology rectangleTopology(gen, -25, -25, 25, 25);
boost::random_graph_layout(graph, boost::get(&Vertex::position, graph), rectangleTopology);
boost::fruchterman_reingold_force_directed_layout(graph, boost::get(&Vertex::position, graph), rectangleTopology);
return 0;
}
When compiling, the first error is the following:
error: forming reference to void
typedef value_type& reference;
I have done some research and apparently this is due to the fact that it is a listS vertex list - with vecS it works.
However, I still want to use a listS and apparently it is possible:
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/fruchterman_reingold.hpp>
#include <boost/graph/random_layout.hpp>
enum vertex_position_t { vertex_position };
namespace boost { BOOST_INSTALL_PROPERTY(vertex, position); }
typedef boost::rectangle_topology<> RectTopology;
typedef RectTopology::point_type point;
struct simple_edge {
int first, second;
};
int main() {
enum { A, B, C };
simple_edge triangular_edges[2] = {
{A, B}, {A, C}
};
typedef boost::adjacency_list<boost::listS, boost::listS, boost::bidirectionalS,
// Vertex properties
boost::property<boost::vertex_index_t, int,
boost::property<vertex_position_t, point> >,
// Edge properties
boost::property<boost::edge_weight_t, double>> Graph;
Graph g(&triangular_edges[0], &triangular_edges[1], 3);
boost::minstd_rand gen;
RectTopology rect_top(gen, -25, -25, 25, 25);
boost::random_graph_layout(g, boost::get(vertex_position, g), rect_top);
boost::fruchterman_reingold_force_directed_layout(g, boost::get(vertex_position, g), rect_top);
return 0;
}
The problem here is that I don't want to use the "old-style" properties but the bundled properties instead. Here someone was attempting something similar, but the fruchterman_reingold_force_directed_layout does not offer this index map if I am not mistaking.
Related
The following code is not compiled.
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/topological_sort.hpp>
#include <boost/function_output_iterator.hpp>
typedef boost::adjacency_list<
boost::setS, // outedge list
boost::setS, // vertex list
boost::directedS, // undirected
boost::no_property, // vertex prop
boost::no_property, // edge prop
boost::no_property, // graph prop
boost::setS // edgelist
> Graph;
bool hasCycle(const Graph& aG)
{
try {
boost::topological_sort(
aG,
boost::make_function_output_iterator([](int){}));
} catch(boost::not_a_dag const&)
{
return true;
}
return false;
}
It works after changing vertice lists to be vecS
http://coliru.stacked-crooked.com/a/abeb9e3f96e92af0
Is this limitation because DFS needs a deterministic visits?
Thank you,
The "limitation" is documented as the need for a vertex index. You could add one (note that you also should replace int by Graph::vertex_descriptor), or adjust the graph type to include one:
Adding an external index property map
Live On Coliru
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/topological_sort.hpp>
#include <boost/function_output_iterator.hpp>
typedef boost::adjacency_list<
boost::setS, // outedge list
boost::setS, // vertex list
boost::directedS, // undirected
boost::no_property, // vertex prop
boost::no_property, // edge prop
boost::no_property, // graph prop
boost::setS // edgelist
> Graph;
bool hasCycle(const Graph& aG)
{
try {
std::map<Graph::vertex_descriptor, size_t> index;
auto pmap = boost::make_assoc_property_map(index);
for (auto vd : boost::make_iterator_range(boost::vertices(aG)))
index[vd] = index.size();
boost::topological_sort(
aG,
boost::make_function_output_iterator([](Graph::vertex_descriptor){}),
boost::vertex_index_map(pmap));
}
catch (boost::not_a_dag const&)
{
return true;
}
return false;
}
int main() {
}
Adding an internal index property map
This amounts to shifting the burden to the caller. This might make (a lot of) sense depending on the performance requirements for you application.
Live On Coliru
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/topological_sort.hpp>
#include <boost/function_output_iterator.hpp>
typedef boost::adjacency_list<
boost::setS, // outedge list
boost::setS, // vertex list
boost::directedS, // undirected
boost::property<boost::vertex_index_t, int>, // vertex prop
boost::no_property, // edge prop
boost::no_property, // graph prop
boost::setS // edgelist
> Graph;
bool hasCycle(const Graph& aG)
{
try {
boost::topological_sort(
aG,
boost::make_function_output_iterator([](Graph::vertex_descriptor){})
);
}
catch (boost::not_a_dag const&)
{
return true;
}
return false;
}
#include <boost/graph/random.hpp>
#include <random>
int main() {
std::mt19937 prng{ std::random_device{}() };
Graph g;
boost::generate_random_graph(g, 100, 200, prng);
auto index = boost::get(boost::vertex_index, g);
int gen_id = 0;
for (auto vd : boost::make_iterator_range(boost::vertices(g))) {
boost::put(index, vd, gen_id++);
std::cout << "Vertex " << boost::get(index, vd) << "\n";
}
bool check = hasCycle(g);
}
The following code has errors:
cannot bind ‘std::basic_ostream’ lvalue to ‘std::basic_ostream&&
#include <boost/graph/graphviz.hpp>
void foo(int,char*[])
{
using namespace boost;
typedef boost::adjacency_list<
boost::setS, // outedge list
boost::setS, // vertex list
boost::directedS, // undirected
boost::no_property, // vertex prop
boost::no_property, // edge prop
boost::no_property, // graph prop
boost::setS // edgelistc
> Graph;
Graph g;
std::ostringstream dotname;
dotname << "a.dot";
std::ofstream dot(dotname.str());
write_graphviz(dot, g);
}
It works when
boost::vecS, // vertex list
Is it expected?
Change the vertex container selector to setS changes the vertex descriptor into a type that is not streamable.
You should, as with many many other algorithms in BGL, pass a separate vertex index:
IN: VertexAndEdgeListGraph& g
A directed or undirected graph. The graph's type must be a model of
VertexAndEdgeListGraph. In most cases, the graph must have an internal
vertex_index property map.
External Vertex Id mapping
Live On Coliru
#include <boost/graph/graphviz.hpp>
#include <boost/graph/random.hpp>
#include <random>
int main(int,char*[])
{
using namespace boost;
typedef boost::adjacency_list<setS, setS, directedS> Graph;
Graph g;
std::mt19937 prng{std::random_device{}()};
generate_random_graph(g, 3, 5, prng);
std::map<Graph::vertex_descriptor, size_t> ids;
for (auto u : make_iterator_range(vertices(g)))
ids[u] = ids.size();
default_writer w;
write_graphviz(std::cout, g, w, w, w, make_assoc_property_map(ids));
}
Prints e.g.
digraph G {
1;
2;
3;
1->2 ;
2->1 ;
2->3 ;
3->1 ;
3->2 ;
}
Internal property map:
You can put the property internally without much changing:
Live On Coliru
#include <boost/graph/graphviz.hpp>
#include <boost/graph/random.hpp>
#include <random>
int main(int,char*[])
{
using namespace boost;
typedef boost::adjacency_list<setS, setS, directedS, property<vertex_index_t, size_t> > Graph;
Graph g;
std::mt19937 prng{std::random_device{}()};
generate_random_graph(g, 3, 5, prng);
auto ids = get(vertex_index, g);
size_t num = 0;
for (auto u : make_iterator_range(vertices(g)))
put(ids, u, num++);
write_graphviz(std::cout, g);
}
I'm struggling trying to manually colouring graph's vertices using boost. I wrote the code below but I can't figure it out why the generated file does not have any colour.
int main(int,char*[]) {
typedef property<edge_name_t, string> EdgeProperties;
typedef property<vertex_name_t, string, property<vertex_color_t, default_color_type>> VertexProperties;
typedef adjacency_list<vecS, vecS, directedS, VertexProperties, EdgeProperties> Graph;
typedef graph_traits<Graph>::vertex_descriptor Vertex;
typedef graph_traits<Graph>::edge_descriptor Edge;
Graph g;
property_map<Graph, vertex_name_t>::type vertex_label = get(vertex_name, g);
property_map<Graph, vertex_color_t>::type color_map = get(vertex_color, g);
property_map<Graph, edge_name_t>::type edge_label = get(edge_name, g);
Vertex v1 = add_vertex(g);
vertex_label[v1] = "v1";
put(color_map, v1, boost::red_color);
std::ofstream outf("example.gv");
write_graphviz(outf, g,
make_label_writer(vertex_label),
make_label_writer(edge_label)
);
return 0;
}
Vertex colourings are really an algorithmic detail. There is no "automatic" provision to translate it to graphviz, as far as I know.
You can add custom attributes though.
I'd usually change it around to use dynamic properties:
std::ofstream outf("example.gv");
dynamic_properties dp;
dp.property("node_id", get(vertex_index, g));
dp.property("label", vertex_label);
dp.property("label", edge_label);
write_graphviz_dp(outf, g, dp);
Now it's as simple as adding a new vertex attribute to the dynamic set:
dp.property("color", make_transform_value_property_map(&color_to_string, color_map));
The only complication is that you need to supply the conversion from default_color_type to text. This is another symptom of the fact that the color maps aren't usually used for representational purposes. Here's a fully working sample:
Live On Coliru
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graphviz.hpp>
#include <iostream>
using namespace boost;
inline char const* color_to_string(default_color_type c) {
switch(c) {
case default_color_type::red_color: return "red";
case default_color_type::green_color: return "green";
case default_color_type::gray_color: return "gray";
case default_color_type::white_color: return "white";
case default_color_type::black_color: return "black";
}
return ""; // not known
}
int main() {
typedef property<edge_name_t, std::string> EdgeProperties;
typedef property<vertex_name_t, std::string, property<vertex_color_t, default_color_type>> VertexProperties;
typedef adjacency_list<vecS, vecS, directedS, VertexProperties, EdgeProperties> Graph;
typedef graph_traits<Graph>::vertex_descriptor Vertex;
Graph g;
property_map<Graph, vertex_name_t>::type vertex_label = get(vertex_name, g);
property_map<Graph, vertex_color_t>::type color_map = get(vertex_color, g);
property_map<Graph, edge_name_t>::type edge_label = get(edge_name, g);
Vertex v1 = add_vertex(g);
vertex_label[v1] = "v1";
put(color_map, v1, boost::red_color);
dynamic_properties dp;
dp.property("node_id", get(vertex_index, g));
dp.property("label", vertex_label);
dp.property("label", edge_label);
dp.property("color", make_transform_value_property_map(&color_to_string, color_map));
write_graphviz_dp(std::cout, g, dp);
}
Prints:
digraph G {
0 [color=red, label=v1];
}
int main()
{
using namespace std;
using namespace boost;
typedef adjacency_list< listS, vecS, directedS > digraph;
// instantiate a digraph object with 8 vertices
digraph g;
// add some edges
add_edge(0, 1, g);
add_edge(1, 5, g);
add_edge(5, 6, g);``
add_edge(2, 3, g);
add_edge(2, 4, g);
// represent graph in DOT format and send to cout
write_graphviz(cout, g);
return 0;
}
Please tell me how to add coloured edge not coloured vertex.
for example edge between vertex 0 and 1 I want it to give some colour to it for example red
so all other edges should be of different colour and edge between vertex 0 and 1 should be red colour, how can I set that property.
You can do this with a property writer.
Something along these lines will do the job:
#include <iostream>
#include <boost/graph/graphviz.hpp>
using namespace std;
using namespace boost;
typedef adjacency_list< listS, vecS, directedS > digraph;
// define a property writer to color the edges as required
class color_writer {
public:
// constructor - needs reference to graph we are coloring
color_writer( digraph& g ) : myGraph( g ) {}
// functor that does the coloring
template <class VertexOrEdge>
void operator()(std::ostream& out, const VertexOrEdge& e) const {
// check if this is the edge we want to color red
if( source( e, myGraph ) == 0 &&
target( e, myGraph ) == 1 )
out << "[color=red]";
}
private:
digraph& myGraph;
};
int main()
{
using namespace std;
// instantiate a digraph object with 8 vertices
digraph g;
// add some edges
add_edge(0, 1, g);
add_edge(1, 5, g);
add_edge(5, 6, g);
add_edge(2, 3, g);
add_edge(2, 4, g);
// represent graph in DOT format and send to cout
write_graphviz(cout, g,
default_writer(), // default ( do nothing ) vertex property writer
color_writer( g ) ); // edge color property writer
return 0;
}
Running this produces
digraph G {
0;
1;
2;
3;
4;
5;
6;
0->1 [color=red];
1->5 ;
2->3 ;
2->4 ;
5->6 ;
}
which when input to the dot program gives:
The manual says this should work with a PropertyWriter.
I use below mentioned code to make colour edges using boost graph api:
#include <iostream>
#include <string>
#include <boost/graph/directed_graph.hpp>
#include <boost/graph/labeled_graph.hpp>
#include <boost/graph/graphviz.hpp>
#include <boost/config.hpp>
#include <boost/graph/adjacency_list.hpp>
using namespace boost;
using namespace std;
template < typename Graph, typename VertexNameMap, typename EdgeNameMap > void
print_dependencies(std::ostream & out, const Graph & g,
VertexNameMap name_map,EdgeNameMap edge_map)
{
//property_map<Graph, edge_name_t>::type name = get(edge_map, g);
typename graph_traits < Graph >::edge_iterator ei, ei_end;
cout<<"digraph G {"<<"\n";
//for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei)
// out << get(name_map, source(*ei, g)) <<" ;" <<std::endl;
for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei)
out << get(name_map, source(*ei, g)) << "->"
<< get(name_map, target(*ei, g)) << " [color= "<<edge_map[*ei] <<"]"<<" ;" <<std::endl;
cout<<"}"<<"\n";
}
int main() {
using namespace boost;
typedef boost::adjacency_list
<
//Store all edges as a std::vector
boost::vecS,
//Store all vertices in a std::vector
boost::vecS,
//Relations are both ways (in this example)
//(note: but you can freely change it to boost::directedS)
boost::directedS,
//All vertices are person names of type std::string
boost::property<boost::vertex_name_t,std::string>,
//All edges are weights equal to the encounter frequencies
// boost::property<boost::edge_weight_t,double>,
boost::property<boost::edge_name_t,std::string>,
//Graph itself has a std::string name
// boost::property< vertex_color_t, default_color_type >,
boost::property<boost::graph_name_t,std::string>
> Graph;
Graph g;
typedef boost::graph_traits<Graph>::edge_descriptor ed;
typedef std::pair<ed, bool> edgeName;
typedef property<edge_name_t, string> EdgeProperty;
string ab = "test";
string cd = "hello";
//All vertex names
//Note: cannot use spaces
std::vector<std::string> names;
names.push_back("MrA");
names.push_back("Mrs_B");
names.push_back("Dr_C");
names.push_back("Prof_D");
// Graph::vertex_descriptor
const Graph::vertex_descriptor v0 = boost::add_vertex(names[0],g);
const Graph::vertex_descriptor v1 = boost::add_vertex(names[1],g);
const Graph::vertex_descriptor v2 = boost::add_vertex(names[2],g);
const Graph::vertex_descriptor v3 = boost::add_vertex(names[3],g);
const Graph::vertex_descriptor v4 = boost::add_vertex(ab,g);
boost::add_vertex(cd,g);
boost::add_edge(v0, v1,EdgeProperty("red"), g);
boost::add_edge(v1,v2,EdgeProperty("yellow"),g);
boost::add_edge(v2,v3,EdgeProperty("red"),g);
boost::add_edge(v3,v4,EdgeProperty("green"),g);
boost::add_edge(0,5,EdgeProperty("blue"),g);
//write_graphviz(cout, g);
print_dependencies(std::cout, g, get(vertex_name, g), get(edge_name, g) );
}
I have defined a Graph using the Boost graph library,
typedef boost::property<boost::edge_weight_t, int> EdgeWeightProperty;
typedef boost::adjacency_list<boost::listS, boost::vecS,boost::undirectedS,boost::no_property,EdgeWeightProperty> Graph;
It is fairly straightforward to add edges using
boost::add_edge(vertice1, vertice2, weight, graph);
I have yet to figure out how to change the edge weight once it has been set. One possible solution would be to delete the edge and re-add it with the updated the weight value, however, that seems a bit excessive.
One solution is to do the following
typedef boost::adjacency_list<boost::setS, boost::vecS, boost::undirectedS,boost::no_property,EdgeWeightProperty> Graph;
typedef Graph::edge_descriptor Edge;
Graph g;
std::pair<Edge, bool> ed = boost::edge(v1,v2,g);
int weight = get(boost::edge_weight_t(), g, ed.first);
int weightToAdd = 10;
boost::put(boost::edge_weight_t(), g, ed.first, weight+weightToAdd);
An alternate solution would be to use property maps. Here's an example.
// Edge weight.
typedef boost::property<boost::edge_weight_t, int> EdgeWeightProperty;
// Graph.
typedef boost::adjacency_list< boost::listS,
boost::vecS,
boost::undirectedS,
boost::no_property,
EdgeWeightProperty > Graph;
// Vertex descriptor.
typedef typename boost::graph_traits<Graph>::vertex_descriptor Vertex;
// The Graph object
Graph g;
// Populates the graph.
Vertex v1 = boost::add_vertex(g);
Vertex v2 = boost::add_vertex(g);
Vertex v3 = boost::add_vertex(g);
boost::add_edge(v1, v2, EdgeWeightProperty(2), g);
boost::add_edge(v1, v3, EdgeWeightProperty(4), g);
boost::add_edge(v2, v3, EdgeWeightProperty(5), g);
// The property map associated with the weights.
boost::property_map < Graph,
boost::edge_weight_t >::type EdgeWeightMap = get(boost::edge_weight, g);
// Loops over all edges and add 10 to their weight.
boost::graph_traits< Graph >::edge_iterator e_it, e_end;
for(std::tie(e_it, e_end) = boost::edges(g); e_it != e_end; ++e_it)
{
EdgeWeightMap[*e_it] += 10;
}
// Prints the weighted edgelist.
for(std::tie(e_it, e_end) = boost::edges(g); e_it != e_end; ++e_it)
{
std::cout << boost::source(*e_it, g) << " "
<< boost::target(*e_it, g) << " "
<< EdgeWeightMap[*e_it] << std::endl;
}