After generating a graph with n nodes, and adding the edges at random, how would I go around getting all the neighbours of a specific node. Is there a function similar to NetworkX's G.neighbors(i)?
This is what I've got so far, creating adjacency list
#include <iostream>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/connected_components.hpp>
using namespace boost;
using namespace std;
int main() {
int N = 10000;
struct status_t{
typedef vertex_property_tag kind;
};
typedef
property <status_t, string> status;
typedef
adjacency_list<vecS, vecS, undirectedS, status> MyGraph;
MyGraph g (N);
// add some random edges
add_edge(0, 1, g);
add_edge(100, 153, g);
add_edge(634, 12, g);
add_edge(94, 3, g);
property_map<MyGraph, status_t>::type status_map = get(status_t(), g);
for (int i = 0; i < 10; i++){
status_map[i] = "S";
}
return 0;
}
auto neighbours = boost::adjacent_vertices(94, g);
Print them like e.g.
for (auto vd : make_iterator_range(neighbours))
std::cout << "94 has adjacent vertex " << vd << "\n";
Prints
94 has adjacent vertex 93
94 has adjacent vertex 3
If you wanted outgoing edges only, that assumes directedS or bidirectionalS, in which case you can also do:
for (auto ed : make_iterator_range(boost::out_edges(94, g)))
std::cout << "outgoing: " << ed << "\n";
for (auto ed : make_iterator_range(boost::in_edges(94, g)))
std::cout << "incident: " << ed << "\n";
Live Demo
Live On Coliru
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/connected_components.hpp>
#include <iostream>
using namespace boost;
using namespace std;
int main() {
int N = 10000;
struct status_t { typedef vertex_property_tag kind; };
typedef property<status_t, string> status;
typedef adjacency_list<vecS, vecS, bidirectionalS, status> MyGraph;
MyGraph g(N);
// add some random edges
add_edge(0, 1, g);
add_edge(100, 153, g);
add_edge(634, 12, g);
add_edge(93, 94, g);
add_edge(94, 3, g);
property_map<MyGraph, status_t>::type status_map = get(status_t(), g);
for (int i = 0; i < 10; i++) {
status_map[i] = "S";
}
{
auto neighbours = boost::adjacent_vertices(94, g);
for (auto vd : make_iterator_range(neighbours))
std::cout << "94 has adjacent vertex " << vd << "\n";
// prints
// for undirected:
// 94 has adjacent vertex 93
// 94 has adjacent vertex 3
// for directed/bidirectionalS:
// 94 has adjacent vertex 3
}
{ // for bidirectionalS:
for (auto ed : make_iterator_range(boost::out_edges(94, g)))
std::cout << "outgoing: " << ed << "\n";
for (auto ed : make_iterator_range(boost::in_edges(94, g)))
std::cout << "incident: " << ed << "\n";
}
}
Printing
94 has adjacent vertex 3
outgoing: (94,3)
incident: (93,94)
I want to use boost's dijkstra algorithm (since I'm using boost in other parts of my program). The problem I'm having is adding custom objects (I believe they are referred to as property) to the adjacency_list.
Essentially I have a custom edge class that maintains all sorts of information regarding the edge and the vertices that are connected through it. I want to store my custom data object with the edge properties that are required by the adjaceny_list
I've successfully implemented the toy example that boost provides. I've tried to use custom properties to no avail (boost example, boost properties). I'm fine with just encapsulating my VEdge data structure in a struct or something, I just need to be able to retrieve it. But I haven't been able to figure out how to include my custom data structure into the boost adjaceny_list structure.
In my case I have the following program:
Main.cpp:
#include <iostream>
#include <fstream>
#include "dijkstra.h"
#include <vector>
int
main(int, char *[])
{
// Generate the vector of edges from elsewhere in the program
std::vector<VEdge*> edges; //someclass.get_edges();
td* test = new td(edges);
test->run_d();
test->print_path();
return EXIT_SUCCESS;
}
Dijkstra.cpp:
#include <iostream>
#include <fstream>
#include "dijkstra.h"
using namespace boost;
td::td() {
kNumArcs = sizeof(kEdgeArray) / sizeof(Edge);
kNumNodes = 5;
}
td::td(std::vector<VEdge*> edges) {
// add edges to the edge property here
for(VEdge* e : edges) {
// for each edge, add to the kEdgeArray variable in some way
// The boost example forces the input to be an array of edge_property type.
// So here is where I will convert my raw VEdge data structure to
// the custom edge_property that I am struggling to understand how to create.
}
kNumArcs = sizeof(kEdgeArray) / sizeof(Edge);
kNumNodes = 5;
}
void td::run_d() {
kGraph = graph_t(kEdgeArray, kEdgeArray + kNumArcs, kWeights, kNumNodes);
kWeightMap = get(edge_weight, kGraph);
kP = std::vector<vertex_descriptor >(num_vertices(kGraph));
kD = std::vector<int>(num_vertices(kGraph));
kS = vertex(A, kGraph);
dijkstra_shortest_paths(kGraph, kS,
predecessor_map(boost::make_iterator_property_map(kP.begin(), get(boost::vertex_index, kGraph))).
distance_map(boost::make_iterator_property_map(kD.begin(), get(boost::vertex_index, kGraph))));
}
void td::print_path() {
std::cout << "distances and parents:" << std::endl;
graph_traits < graph_t >::vertex_iterator vi, vend;
for (boost::tie(vi, vend) = vertices(kGraph); vi != vend; ++vi) {
std::cout << "distance(" << kName[*vi] << ") = " << kD[*vi] << ", ";
std::cout << "parent(" << kName[*vi] << ") = " << kName[kP[*vi]] << std::
endl;
}
}
void td::generate_dot_file() {
std::cout << std::endl;
std::ofstream dot_file("figs/dijkstra-eg.dot");
dot_file << "digraph D {\n"
<< " rankdir=LR\n"
<< " size=\"4,3\"\n"
<< " ratio=\"fill\"\n"
<< " edge[style=\"bold\"]\n" << " node[shape=\"circle\"]\n";
graph_traits < graph_t >::edge_iterator ei, ei_end;
for (boost::tie(ei, ei_end) = edges(kGraph); ei != ei_end; ++ei) {
graph_traits < graph_t >::edge_descriptor e = *ei;
graph_traits < graph_t >::vertex_descriptor
u = source(e, kGraph), v = target(e, kGraph);
dot_file << kName[u] << " -> " << kName[v]
<< "[label=\"" << get(kWeightMap, e) << "\"";
if (kP[v] == u)
dot_file << ", color=\"black\"";
else
dot_file << ", color=\"grey\"";
dot_file << "]";
}
dot_file << "}";
}
Dijkstra.h:
#ifndef _TEMPD_H_
#define _TEMPD_H_
#pragma once
#include <boost/config.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <boost/property_map/property_map.hpp>
using namespace boost;
typedef adjacency_list < listS, vecS, directedS,
no_property, property < edge_weight_t, int > > graph_t;
typedef graph_traits < graph_t >::vertex_descriptor vertex_descriptor;
typedef std::pair<int, int> Edge;
struct VEdge{
// custom variables here
VNode start;
VNode end;
int weight;
int id;
// other irrelevant data pertinent to my program that must be preserved
};
struct VNode {
// custom variables here
int x;
int y;
int id;
// other irrelevant data pertinent to my program that must be preserved
}
enum nodes { A, B, C, D, E };
class td {
public:
td();
td(std::vector<VEdge*>);
~td();
void run_d();
void print_path();
void generate_dot_file();
private:
Edge kEdgeArray[9] = { Edge(A, C), Edge(B, B), Edge(B, D), Edge(B, E),
Edge(C, B), Edge(C, D), Edge(D, E), Edge(E, A), Edge(E, B)
};
char kName[5] = {'A','B','C','D','E'};
int kWeights[9] = { 1, 2, 1, 2, 7, 3, 1, 1, 1 };
int kNumArcs;
int kNumNodes;
vertex_descriptor kS;
graph_t kGraph;
std::vector<int> kD;
std::vector<vertex_descriptor> kP;
property_map<graph_t, edge_weight_t>::type kWeightMap;
};
#endif
I know my example is a bit contrived, but it communicates what I'm trying to accomplish. I know I need a custom data structure for my edge_descriptor which gets sent to the graph_t typedef.
So I'm looking to alter my Dijkstra.h file to look something like this:
struct vertex_label_t {vertex_property_tag kind;};
struct edge_label_t {edge_property_tag kind;};
typedef property <vertex_custom_t, VNode*>,
property <vertex_label_t, string>,
property <vertex_root_t, ing> > > vertex_p;
typedef property <edge_custom_t, VEdge*>,
property <edge_label_t, string > > edge_p;
typedef adjacency_list < listS, vecS, directedS,
vertex_p, edge_p > graph_t;
typedef graph_traits < graph_t >::vertex_descriptor vertex_descriptor;
Okay. You've come a long ways since https://stackoverflow.com/questions/28889423/boost-adjacency-list-swap-errors-when-using-boost-dijkstra; the sample is self-contained and can compile¹
I figured I could just connect some dots and hope this would be helpful.
1. Using VEdge
For the simplest option, I'd use Bundled Properties, and define VEdge as follows:
struct VEdge {
int id;
int source, target;
double weight;
// custom variables here
};
Now, we define the graph as
using graph_t = boost::adjacency_list<boost::listS, boost::vecS,
boost::directedS, boost::no_property, VEdge>;
using weight_map_t = boost::property_map<graph_t, double VEdge::*>::type;
As you can see the weight-map has a little more complicated type, as documented under Properties maps from bundled properties. You can get the actual map:
weight_map_t kWeightMap = boost::get(&VEdge::weight, kGraph);
Now, let's recreate the test data from your question in a vector of VEdge (A=0...E=4):
std::vector<VEdge> edges {
{ 2100, 0, 2, 1 },
{ 2101, 1, 1, 2 },
{ 2102, 1, 3, 1 },
{ 2103, 1, 4, 2 },
{ 2104, 2, 1, 7 },
{ 2105, 2, 3, 3 },
{ 2106, 3, 4, 1 },
{ 2107, 4, 0, 1 },
{ 2108, 4, 1, 1 },
};
test_dijkstra test(edges);
The constructor has a little bit of complication to find the number of vertices from just the edges. I used Boost Range algorithms to find the maximum vertex node id and pass that:
test_dijkstra::test_dijkstra(std::vector<VEdge> edges) {
using namespace boost::adaptors;
size_t max_node;
boost::partial_sort_copy(
edges | transformed([](VEdge const &e) -> size_t { return std::max(e.source, e.target); }),
boost::make_iterator_range(&max_node, &max_node + 1),
std::greater<size_t>());
auto e = edges | transformed([](VEdge const &ve) { return std::make_pair(ve.source, ve.target); });
kGraph = graph_t(e.begin(), e.end(), edges.begin(), max_node + 1);
}
Note how edges.begin() can be passed: it is not "forced to be a an array of edge_property type". An iterator will be fine.
Now the dijkstra needs to get the weight_map argument because it's no longer the default internal property:
void test_dijkstra::run_dijkstra() {
weight_map_t kWeightMap = boost::get(&VEdge::weight, kGraph);
vertex_descriptor kS = vertex(0, kGraph);
kP = std::vector<vertex_descriptor>(num_vertices(kGraph));
kD = std::vector<int>(num_vertices(kGraph));
dijkstra_shortest_paths(
kGraph, kS,
predecessor_map(boost::make_iterator_property_map(kP.begin(), get(boost::vertex_index, kGraph)))
.distance_map(boost::make_iterator_property_map(kD.begin(), get(boost::vertex_index, kGraph)))
.weight_map(kWeightMap));
}
For this sample, I translated A to 0 as the starting vertex. The result path is exactly the same as for the original²
Full Program
Live On Coliru
#include <boost/config.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/range/algorithm.hpp>
#include <boost/range/adaptors.hpp>
#include <fstream>
#include <iostream>
struct VEdge {
int id;
int source, target;
double weight;
// custom variables here
};
class test_dijkstra {
using graph_t = boost::adjacency_list<boost::listS, boost::vecS, boost::directedS, boost::no_property, VEdge>;
using vertex_descriptor = boost::graph_traits<graph_t>::vertex_descriptor;
using edge_descriptor = boost::graph_traits<graph_t>::edge_descriptor;
using weight_map_t = boost::property_map<graph_t, double VEdge::*>::type;
public:
test_dijkstra(std::vector<VEdge>);
~test_dijkstra() {}
void run_dijkstra();
void print_path();
void generate_dot_file();
private:
graph_t kGraph;
std::vector<int> kD;
std::vector<vertex_descriptor> kP;
};
test_dijkstra::test_dijkstra(std::vector<VEdge> edges) {
using namespace boost::adaptors;
size_t max_node;
boost::partial_sort_copy(
edges | transformed([](VEdge const &e) -> size_t { return std::max(e.source, e.target); }),
boost::make_iterator_range(&max_node, &max_node + 1),
std::greater<size_t>());
auto e = edges | transformed([](VEdge const &ve) { return std::make_pair(ve.source, ve.target); });
kGraph = graph_t(e.begin(), e.end(), edges.begin(), max_node + 1);
}
void test_dijkstra::run_dijkstra() {
weight_map_t kWeightMap = boost::get(&VEdge::weight, kGraph);
vertex_descriptor kS = vertex(0, kGraph);
kP = std::vector<vertex_descriptor>(num_vertices(kGraph));
kD = std::vector<int>(num_vertices(kGraph));
dijkstra_shortest_paths(
kGraph, kS,
predecessor_map(boost::make_iterator_property_map(kP.begin(), get(boost::vertex_index, kGraph)))
.distance_map(boost::make_iterator_property_map(kD.begin(), get(boost::vertex_index, kGraph)))
.weight_map(kWeightMap));
}
void test_dijkstra::print_path() {
std::cout << "distances and parents:" << std::endl;
boost::graph_traits<graph_t>::vertex_iterator vi, vend;
for (boost::tie(vi, vend) = vertices(kGraph); vi != vend; ++vi) {
std::cout << "distance(" << *vi << ") = " << kD[*vi] << ", ";
std::cout << "parent(" << *vi << ") = " << kP[*vi] << "\n";
}
}
void test_dijkstra::generate_dot_file() {
weight_map_t kWeightMap = boost::get(&VEdge::weight, kGraph);
std::ofstream dot_file("figs/dijkstra-eg.dot");
dot_file << "digraph D {\n"
<< " rankdir=LR\n"
<< " size=\"4,3\"\n"
<< " ratio=\"fill\"\n"
<< " edge[style=\"bold\"]\n"
<< " node[shape=\"circle\"]\n";
boost::graph_traits<graph_t>::edge_iterator ei, ei_end;
for (boost::tie(ei, ei_end) = edges(kGraph); ei != ei_end; ++ei) {
boost::graph_traits<graph_t>::edge_descriptor e = *ei;
boost::graph_traits<graph_t>::vertex_descriptor u = source(e, kGraph), v = target(e, kGraph);
dot_file << u << " -> " << v << "[label=\"" << get(kWeightMap, e) << "\"";
if (kP[v] == u)
dot_file << ", color=\"black\"";
else
dot_file << ", color=\"grey\"";
dot_file << "]";
}
dot_file << "}";
}
int main() {
std::vector<VEdge> edges {
{ 2100, 0, 2, 1 },
{ 2101, 1, 1, 2 },
{ 2102, 1, 3, 1 },
{ 2103, 1, 4, 2 },
{ 2104, 2, 1, 7 },
{ 2105, 2, 3, 3 },
{ 2106, 3, 4, 1 },
{ 2107, 4, 0, 1 },
{ 2108, 4, 1, 1 },
};
test_dijkstra test(edges);
test.run_dijkstra();
test.print_path();
test.generate_dot_file();
}
2. Using VEdge*
If you insist on using the pointers in the properties a few things become more complicated:
you'll need to manage the lifetime of the elements
you can't use the double VEdge::* weight_map_t. Instead, you'll need to adapt a custom propertymap for this:
auto kWeightMap = boost::make_transform_value_property_map(
[](VEdge* ve) { return ve->weight; },
boost::get(boost::edge_bundle, kGraph)
);
On the bright side, you can use the short-hand indexer notation to evaluate edge properties from an edge_descriptor as shown in generate_dot_file():
dot_file << u << " -> " << v << "[label=\"" << kGraph[e]->weight << "\"";
Of course this approach avoids copying the VEdge objects into the bundle, so it could be more efficient
Without further ado (and without bothering about the memory leaks):
Live On Coliru
#include <boost/config.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/range/algorithm.hpp>
#include <boost/range/adaptors.hpp>
#include <boost/property_map/transform_value_property_map.hpp>
#include <fstream>
#include <iostream>
struct VEdge {
int id;
int source, target;
double weight;
// custom variables here
};
class test_dijkstra {
using graph_t = boost::adjacency_list<boost::listS, boost::vecS, boost::directedS, boost::no_property, VEdge*>;
using vertex_descriptor = boost::graph_traits<graph_t>::vertex_descriptor;
using edge_descriptor = boost::graph_traits<graph_t>::edge_descriptor;
public:
test_dijkstra(std::vector<VEdge*>);
~test_dijkstra() {}
void run_dijkstra();
void print_path();
void generate_dot_file();
private:
graph_t kGraph;
std::vector<int> kD;
std::vector<vertex_descriptor> kP;
};
test_dijkstra::test_dijkstra(std::vector<VEdge*> edges) {
using namespace boost::adaptors;
size_t max_node;
boost::partial_sort_copy(
edges | transformed([](VEdge const* e) -> size_t { return std::max(e->source, e->target); }),
boost::make_iterator_range(&max_node, &max_node + 1),
std::greater<size_t>());
auto e = edges | transformed([](VEdge const *ve) { return std::make_pair(ve->source, ve->target); });
kGraph = graph_t(e.begin(), e.end(), edges.begin(), max_node + 1);
}
void test_dijkstra::run_dijkstra() {
auto kWeightMap = boost::make_transform_value_property_map(
[](VEdge* ve) { return ve->weight; },
boost::get(boost::edge_bundle, kGraph)
);
vertex_descriptor kS = vertex(0, kGraph);
kP = std::vector<vertex_descriptor>(num_vertices(kGraph));
kD = std::vector<int>(num_vertices(kGraph));
dijkstra_shortest_paths(
kGraph, kS,
predecessor_map(boost::make_iterator_property_map(kP.begin(), get(boost::vertex_index, kGraph)))
.distance_map(boost::make_iterator_property_map(kD.begin(), get(boost::vertex_index, kGraph)))
.weight_map(kWeightMap));
}
void test_dijkstra::print_path() {
std::cout << "distances and parents:" << std::endl;
boost::graph_traits<graph_t>::vertex_iterator vi, vend;
for (boost::tie(vi, vend) = vertices(kGraph); vi != vend; ++vi) {
std::cout << "distance(" << *vi << ") = " << kD[*vi] << ", ";
std::cout << "parent(" << *vi << ") = " << kP[*vi] << "\n";
}
}
void test_dijkstra::generate_dot_file() {
std::ofstream dot_file("figs/dijkstra-eg.dot");
dot_file << "digraph D {\n"
<< " rankdir=LR\n"
<< " size=\"4,3\"\n"
<< " ratio=\"fill\"\n"
<< " edge[style=\"bold\"]\n"
<< " node[shape=\"circle\"]\n";
boost::graph_traits<graph_t>::edge_iterator ei, ei_end;
for (boost::tie(ei, ei_end) = edges(kGraph); ei != ei_end; ++ei) {
boost::graph_traits<graph_t>::edge_descriptor e = *ei;
boost::graph_traits<graph_t>::vertex_descriptor u = source(e, kGraph), v = target(e, kGraph);
dot_file << u << " -> " << v << "[label=\"" << kGraph[e]->weight << "\"";
if (kP[v] == u)
dot_file << ", color=\"black\"";
else
dot_file << ", color=\"grey\"";
dot_file << "]";
}
dot_file << "}";
}
int main() {
std::vector<VEdge*> edges {
new VEdge { 2100, 0, 2, 1 },
new VEdge { 2101, 1, 1, 2 },
new VEdge { 2102, 1, 3, 1 },
new VEdge { 2103, 1, 4, 2 },
new VEdge { 2104, 2, 1, 7 },
new VEdge { 2105, 2, 3, 3 },
new VEdge { 2106, 3, 4, 1 },
new VEdge { 2107, 4, 0, 1 },
new VEdge { 2108, 4, 1, 1 },
};
test_dijkstra test(edges);
test.run_dijkstra();
test.print_path();
test.generate_dot_file();
}
¹ after swatting silly typos
² self-contained Live On Coliru
I'm new to boost graphs and are researching the graph that best fits my need. I need to create a dependency graph and given a vertex, I need access to in and out edges. An adjacency_list with Directed=bidirectionalS is what I'm thinking.
But I need to make sure when I call add_edge and that causes a circular reference then it has to error out. I can't seem to find how to do this.
In general, there's only one way to discover whether a graph is a-cyclic: traverse all nodes.
So you'd just need to check whether the graph is still a-cyclic after adding each edge.
However, depending on how you are adding the nodes, you can optimize. If, e.g. you add edges by traversing nodes from a source in DFS order, you can just keep track of nodes "seen" in the current path and refuse to add an out edge to those.
Simplistic example based on topological_sort Live On Coliru:
#include <iostream> // for std::cout
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graphviz.hpp>
#include <boost/graph/topological_sort.hpp>
#include <boost/function_output_iterator.hpp>
using namespace boost;
int main()
{
srand(time(0));
typedef adjacency_list<vecS, vecS, bidirectionalS> Graph;
const int num_vertices = 10;
Graph g(num_vertices);
// add random edges to the graph object
for (size_t i = 0; i < 10; ++i)
{
auto f = rand()%num_vertices,
s = rand()%num_vertices;
add_edge(f, s, g);
try {
topological_sort(g, boost::make_function_output_iterator([](int){}));
} catch(not_a_dag const& e)
{
remove_edge(f, s, g);
std::cerr << "dropped edge: " << e.what() << "\n";
}
}
write_graphviz(std::cout, g);
}
Creates random DAGs like
In boost graph BidirectinalS indicates that the edge will be having soruce and target vertices both.
Here is the example for it:
#include <QtCore/QCoreApplication>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/subgraph.hpp>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
using namespace std;
using namespace boost;
typedef boost::subgraph<boost::adjacency_list< boost::listS,
boost::vecS,
boost::bidirectionalS,
boost::property<boost::vertex_index_t, int , property<boost::vertex_color_t, boost::default_color_type > > ,
boost::property<boost::edge_index_t,int, property<boost::edge_color_t , default_color_type> > > >
Graph;
const int num_vertices = 5;
Graph g(num_vertices);
add_edge(0, 1, g);
add_edge(1, 2, g);
add_edge(1, 3, g);
add_edge(2, 4, g);
add_edge(3, 4, g);
boost::graph_traits<Graph>::vertex_iterator VertexItr, VertexItr_end;
boost::graph_traits<Graph>::in_edge_iterator in, in_end;
boost::graph_traits<Graph>::out_edge_iterator out,out_end;
typedef boost::graph_traits < Graph >::adjacency_iterator adjacency_iterator;
// This loop is for getting in edges at vertex
cout<<"In Edge :- "<<endl;
for(boost::tie(VertexItr,VertexItr_end) = vertices(g); VertexItr != VertexItr_end; ++VertexItr) {
cout << *VertexItr << " <-- ";
for (boost::tie(in,in_end) = in_edges(*VertexItr, g); in != in_end; ++in)
cout << source(*in, g) << " ";
cout << endl;
}
// This loop is for getting out edges from vertex
cout<<endl<<"Out Edge :- "<<endl;
for(boost::tie(VertexItr,VertexItr_end) = vertices(g); VertexItr != VertexItr_end; ++VertexItr) {
cout<<*VertexItr<<"--->";
for (boost::tie(out,out_end) = out_edges(*VertexItr, g); out != out_end; ++out)
cout << target(*out, g) << " ";
cout << endl;
}
// This loop is for getting the neighbour vertices of vertex
typedef boost::property_map<Graph, boost::vertex_index_t>::type IndexMap;
IndexMap index = get(boost::vertex_index, g);
cout<<"Adjacent vertices"<<endl;
for(boost::tie(VertexItr,VertexItr_end) = vertices(g); VertexItr != VertexItr_end; ++VertexItr) {
cout<<*VertexItr<<"--->";
std::pair<adjacency_iterator, adjacency_iterator> neighbors =
boost::adjacent_vertices(vertex(*VertexItr,g), g);
for(; neighbors.first != neighbors.second; ++neighbors.first)
{
std::cout << index[*neighbors.first] << " ";
}
cout<<endl;
}
return a.exec();
}
I found this section on the boost documentation discussing how to detect dependencies:
http://www.boost.org/doc/libs/1_55_0/libs/graph/doc/file_dependency_example.html#sec:cycles
But for the adjacency_list the VertexList and EdgeList have to be of type vecS. There's discussion about this here:
How to print a boost graph in graphviz with one of the properties displayed?
I found http://www.boost.org/doc/libs/1_49_0/libs/graph/example/incremental_components.cpp and want to check if it will work for me. How to convert this example to cope with cartesian points with (x,y) or (x,y,z). I can't find such example in documentation of boost.
I see that i must redefine vertice in some way, so change in adjacency_list is needed. Tried to change vecS with Point definifion, but i think also some changes in add_edge functions are needed.
I made a couple minor changes to the example you pointed too. Specifically setting the 4th & fifth template parameters on the adjacency_list to be the a type containing any additional vertex and edge properties. See docs here: http://www.boost.org/doc/libs/1_48_0/libs/graph/doc/adjacency_list.html
struct point
{
int x;
int y;
int z;
};
typedef adjacency_list <vecS, vecS, undirectedS, point > Graph;
After nodes & vertices the additional point data can be set like this:
graph[0].x = 42;
And retrieved at the end after the components have been computed:
std::cout << child_index << " " << "x=" << graph[current_index].x << " ";
Full code:
//=======================================================================
// Copyright 1997, 1998, 1999, 2000 University of Notre Dame.
// Copyright 2009 Trustees of Indiana University.
// Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek, Michael Hansen
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================
#include <iostream>
#include <vector>
#include <boost/foreach.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graph_utility.hpp>
#include <boost/graph/incremental_components.hpp>
#include <boost/pending/disjoint_sets.hpp>
/*
This example shows how to use the disjoint set data structure
to compute the connected components of an undirected, changing
graph.
Sample output:
An undirected graph:
0 <--> 1 4
1 <--> 0 4
2 <--> 5
3 <-->
4 <--> 1 0
5 <--> 2
representative[0] = 1
representative[1] = 1
representative[2] = 5
representative[3] = 3
representative[4] = 1
representative[5] = 5
component 0 contains: 4 1 0
component 1 contains: 3
component 2 contains: 5 2
*/
using namespace boost;
struct point
{
point() : x(0), y(0), z(0) {}
int x;
int y;
int z;
};
int main(int argc, char* argv[])
{
typedef adjacency_list <vecS, vecS, undirectedS, point > Graph;
typedef graph_traits<Graph>::vertex_descriptor Vertex;
typedef graph_traits<Graph>::vertices_size_type VertexIndex;
const int VERTEX_COUNT = 6;
Graph graph(VERTEX_COUNT);
std::vector<VertexIndex> rank(num_vertices(graph));
std::vector<Vertex> parent(num_vertices(graph));
typedef VertexIndex* Rank;
typedef Vertex* Parent;
disjoint_sets<Rank, Parent> ds(&rank[0], &parent[0]);
initialize_incremental_components(graph, ds);
incremental_components(graph, ds);
graph_traits<Graph>::edge_descriptor edge;
bool flag;
boost::tie(edge, flag) = add_edge(0, 1, graph);
ds.union_set(0,1);
boost::tie(edge, flag) = add_edge(1, 4, graph);
ds.union_set(1,4);
boost::tie(edge, flag) = add_edge(4, 0, graph);
ds.union_set(4,0);
boost::tie(edge, flag) = add_edge(2, 5, graph);
ds.union_set(2,5);
graph[0].x = 42;
std::cout << "An undirected graph:" << std::endl;
print_graph(graph, get(boost::vertex_index, graph));
std::cout << std::endl;
BOOST_FOREACH(Vertex current_vertex, vertices(graph)) {
std::cout << "representative[" << current_vertex << "] = " <<
ds.find_set(current_vertex) << std::endl;
}
std::cout << std::endl;
typedef component_index<VertexIndex> Components;
// NOTE: Because we're using vecS for the graph type, we're
// effectively using identity_property_map for a vertex index map.
// If we were to use listS instead, the index map would need to be
// explicitly passed to the component_index constructor.
Components components(parent.begin(), parent.end());
// Iterate through the component indices
BOOST_FOREACH(VertexIndex current_index, components) {
std::cout << "component " << current_index << " contains: ";
// Iterate through the child vertex indices for [current_index]
BOOST_FOREACH(VertexIndex child_index,
components[current_index])
{
std::cout << child_index
<< " {" << graph[child_index].x
<< "," << graph[child_index].y
<< "," << graph[child_index].z << "} ";
}
std::cout << std::endl;
}
return (0);
}