graph levelization using BGL - boost-graph

Can you please post example code to levelize a directed graph using BGL?
Definition of levelization: Vertex has a property "int level". During BFS traversal of the graph, when a vertex is being "examined", look at its predecessor vertices' levels, take max of these, increment, and assign this to the "level" of this vertex.

If you mean the BFS depth then this is already built in to boost BFS and can be gotten easily.
Just use a vector to store the depths and a depth BFS visitor like this example I made:
#include <iostream>
#include <vector>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/breadth_first_search.hpp>
using namespace std;
using namespace boost;
typedef adjacency_list < vecS, vecS, directedS,
property< vertex_index_t, size_t> ,
property< edge_index_t, size_t > > Graph;
typedef graph_traits<Graph>::vertex_descriptor Vertex;
typedef graph_traits<Graph>::edge_descriptor Edge;
int main(int argc, char* argv[]){
Graph G;
vector<Vertex> verts;
for(size_t i = 0; i < 9; ++i){
Vertex v = add_vertex(G);
verts.push_back(v);
}
/*
0 0
/ \
1 1 4
/ \
2 2 5
/ \
3 3 6
\
4 7
\
5 8
*/
add_edge(verts.at(0),verts.at(1),G);
add_edge(verts.at(1),verts.at(2),G);
add_edge(verts.at(2),verts.at(3),G);
add_edge(verts.at(0),verts.at(4),G);
add_edge(verts.at(4),verts.at(5),G);
add_edge(verts.at(5),verts.at(6),G);
add_edge(verts.at(6),verts.at(7),G);
add_edge(verts.at(7),verts.at(8),G);
cout << "vertices " << num_vertices(G) << endl;
cout << "edges " << num_edges(G) << endl;
//store depths
vector<size_t> d(num_vertices(G));
//get an index map, from Graph definition property< vertex_index_t, size_t>
typedef boost::property_map< Graph, boost::vertex_index_t>::type VertexIndexMap;
VertexIndexMap v_index = get(boost::vertex_index, G);
// Create the external property map, this map wraps the storage vector d
boost::iterator_property_map< std::vector< size_t >::iterator, VertexIndexMap >
d_map(d.begin(), v_index);
//Start at 0
boost::breadth_first_search(G, verts.at(0),
boost::visitor(boost::make_bfs_visitor(
boost::record_distances(d_map, boost::on_tree_edge())
)));
cout << "Starting at 0" << endl;
for(size_t i = 0; i < 9; ++i){
//depth (level) of BFS
cout << "vertex " << i << "\t" << d.at(i) << endl;
}
vector<size_t> d2(num_vertices(G));
cout << "Starting at 4" << endl;
// Create the external property map, this map wraps the storage vector d
boost::iterator_property_map< std::vector< size_t >::iterator, VertexIndexMap >
d2_map(d2.begin(), v_index);
//start at 4
boost::breadth_first_search(G, verts.at(4),
boost::visitor(boost::make_bfs_visitor(
boost::record_distances(d2_map, boost::on_tree_edge())
)));
for(size_t i = 0; i < 9; ++i){
//depth (level) of BFS
cout << "vertex " << i << "\t" << d2.at(i) << endl;
}
}
Output should look like this:
vertices 9
edges 8
Starting at 0
vertex 0 0
vertex 1 1
vertex 2 2
vertex 3 3
vertex 4 1
vertex 5 2
vertex 6 3
vertex 7 4
vertex 8 5
Starting at 4
vertex 0 0
vertex 1 0
vertex 2 0
vertex 3 0
vertex 4 0
vertex 5 1
vertex 6 2
vertex 7 3
vertex 8 4
When you start at 4 the other vertices are not reachable (directed) so the vector contains default values (0 in this case). This should work for undirected too.

Related

How to use Boost MST Algorithm on a complete Graph [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 1 year ago.
Improve this question
I am very new to the BGL. I have the following problem: I've got a very large complete Graph and weights for every edge and need to evaluate a Minimum Spanning Tree.
I would like to use the Boost Graph Libraries implementation. What structures should I use to represent my complete graph and how would I call the Algorithm? Also I'd like to store the resulting subgraph in some graph structure so that I can perform different operations on the MST afterwards.
Thank you very much.
Here's a simple example. I'd suggest an adjacency matrix since the graph is going to be complete, so the matrix is very dense.
using Graph =
boost::adjacency_matrix<boost::undirectedS, boost::no_property,
boost::property<boost::edge_weight_t, double>>;
using Vertex = Graph::vertex_descriptor;
using Edge = Graph::edge_descriptor;
Now let's create a graph
int main() {
Graph g(23);
Picking an arbitrary number (23) of vertices for this example. Let's use randomly generated weights:
auto weight_distribution = std::bind(
std::lognormal_distribution<>{0, 0.25},
std::mt19937{std::random_device{}()});
Creating all the edges to make the graph complete:
for (Vertex v = 0; v < num_vertices(g); ++v)
for (Vertex u = v + 1; u < num_vertices(g); ++u)
add_edge(v, u, 100*weight_distribution(), g);
Now, let's use Prim's algorithm (since all the weights are non-negative):
std::vector<Vertex> parent(num_vertices(g));
prim_minimum_spanning_tree(g, parent.data());
This writes the predecessor for each vertex in the parent vector (which is called the predecessor map).
Adding Some Output
For more interesting results, let's add some checks and output:
assert(std::ranges::all_of(
make_iterator_range(edges(g)),
[ew = get(boost::edge_weight, g)](auto e) { return ew[e] > 0; }));
Making sure the data satisfies the weight pre-condition. You might also do a completeness check depending on how you get your input data.
std::vector<Vertex> parent(num_vertices(g));
std::map<Vertex, double> distance;
auto root = vertex(0, g); // or just 0
Let's pass the optional arguments distance_map and root_vertex:
prim_minimum_spanning_tree(g, parent.data(),
boost::root_vertex(root)
.distance_map(boost::make_assoc_property_map(distance)));
That uses named parameters (starting with boost::root_vertex and chaining with .other_parameter(...).even_more(...). You can of course start with any named parameter).
Now we can use the recorded data:
double total_path_weight = 9;
for (Vertex v = 0; v < num_vertices(g); ++v) {
auto p = parent[v];
auto weight = distance[v];
std::cout << p << " -> " << v << " weight " << weight
<< (p == v ? " ROOT" : "") << "\n";
total_path_weight += weight;
}
std::cout << "Total path weight " << total_path_weight << "\n";
DEMO
Live On Coliru
#include <boost/graph/adjacency_matrix.hpp>
#include <boost/graph/prim_minimum_spanning_tree.hpp>
#include <random>
#include <iostream>
using Graph =
boost::adjacency_matrix<boost::undirectedS, boost::no_property,
boost::property<boost::edge_weight_t, double>>;
using Vertex = Graph::vertex_descriptor;
using Edge = Graph::edge_descriptor;
using boost::make_iterator_range;
int main() {
Graph g(23);
auto weight_distribution = std::bind(std::lognormal_distribution<>{0, 0.25},
std::mt19937{std::random_device{}()});
for (Vertex v = 0; v < num_vertices(g); ++v)
for (Vertex u = v + 1; u < num_vertices(g); ++u)
add_edge(v, u, 100*weight_distribution(), g);
assert(std::ranges::all_of(
make_iterator_range(edges(g)),
[ew = get(boost::edge_weight, g)](auto e) { return ew[e] > 0; }));
std::vector<Vertex> parent(num_vertices(g));
std::map<Vertex, double> distance;
auto root = vertex(0, g); // or just 0
prim_minimum_spanning_tree(g, parent.data(),
boost::root_vertex(root)
.distance_map(boost::make_assoc_property_map(distance)));
double total_path_weight = 9;
for (Vertex v = 0; v < num_vertices(g); ++v) {
auto p = parent[v];
auto weight = distance[v];
std::cout << p << " -> " << v << " weight " << weight
<< (p == v ? " ROOT" : "") << "\n";
total_path_weight += weight;
}
std::cout << "Total path weight " << total_path_weight << "\n";
}
Printing e.g.
0 -> 0 weight 0 ROOT
15 -> 1 weight 64.6241
21 -> 2 weight 62.1609
1 -> 3 weight 69.207
5 -> 4 weight 71.9255
2 -> 5 weight 68.3983
14 -> 6 weight 66.6639
17 -> 7 weight 69.5045
20 -> 8 weight 78.9941
6 -> 9 weight 69.3287
4 -> 10 weight 62.7512
0 -> 11 weight 65.9305
15 -> 12 weight 70.2627
4 -> 13 weight 67.9708
22 -> 14 weight 73.3816
14 -> 15 weight 61.069
6 -> 16 weight 63.5795
5 -> 17 weight 66.0981
6 -> 18 weight 54.6061
14 -> 19 weight 73.9725
5 -> 20 weight 74.7002
0 -> 21 weight 71.8757
17 -> 22 weight 68.6378
Total path weight 1504.64

taking input until end of file in c++

I am solving a graph problem where I have to take input from a file. Below is my input.txt file.
12
1 2
2 3
2 4
2 5
3 6
4 5
4 7
5 2
5 6
5 7
6 3
6 8
7 8
7 10
8 7
9 7
10 9
10 11
11 12
12 10
In the above input.txt file first input is no of vertices and the others till the end of the file are directed edge of Graph. The first one is the source and the second one is the destination. All the input will be read from the input.txt file.
#include <bits/stdc++.h>
#include <fstream>
using namespace std;
class Graph {
private:
int V;
list<int> *l;
public:
Graph(int V) {
this->V = V;
l = new list<int>[V];
}
void addEdge(int source, int destination) {
// As it is a directed graph edge will be source to destination only
l[source].push_back(destination);
}
void printAdjList() {
for(int i = 1; i <= V; i++) {
cout << "Vertex " << i << "-> " ;
for(int previous: l[i]) {
cout << previous << " " ;
}
cout << endl;
}
}
};
int main() {
// freopen("input.txt", "r", stdin);
// freopen("output.txt", "w", stdout);
ifstream inputFile;
inputFile.open("input.txt");
int noOfVertex, s, d, noOfEdge=20;
inputFile >> noOfVertex ;
// cout << noOfVertex << endl;
Graph g(noOfEdge);
// while(cin.eof()) {
// // cout << s << " " << d << endl;
// cin >> s >> d;
// g.addEdge(s, d);
// }
if(inputFile) {
while(inputFile >> s >> d) {
// cout << s << " " << d << endl;
g.addEdge(s, d);
}
inputFile.close();
}
else {
cout << "Error opening input file" << endl;
}
g.printAdjList();
return 0;
}
I am getting this result after running the code
Vertex 1-> 2
Vertex 2-> 3 4 5
Vertex 3-> 6
Vertex 4-> 5 7
Vertex 5-> 2 6 7
Vertex 6-> 3 8
Vertex 7-> 8 10
Vertex 8-> 7
Vertex 9-> 7
Vertex 10-> 9 11
Vertex 11-> 12
Vertex 12-> 10
Vertex 13->
Vertex 14->
Vertex 15->
Vertex 16->
Vertex 17->
Vertex 18->
Vertex 19->
I can not take the number of edge for this problem. The number of vetices and given directed edges will be taken one by one line from the file and it will show an adjacency list like that
Vertex 1-> 2
Vertex 2-> 3 4 5
Vertex 3-> 6
Vertex 4-> 5 7
Vertex 5-> 2 6 7
Vertex 6-> 3 8
Vertex 7-> 8 10
Vertex 8-> 7
Vertex 9-> 7
Vertex 10-> 9 11
Vertex 11-> 12
Vertex 12-> 10
How can I take input from the file so that I can get the above output? I have applied many methods but nothing is working.
Your code is wrong for 2 reasons:
you use a hardcoded number of edges when should use the number of vertex
you use an array with an index starting at 0 when the number of the vertex is read from file and does not start at 0
If you want to be safe, you should use a map (or unordered map) int -> list:
...
class Graph {
private:
int V;
unordered_map<int, list<int> > l; // change here
public:
Graph(int V) {
this->V = V;
l.reserve(V); // here
}
...
int noOfVertex, s, d, noOfEdge = 20;
inputFile >> noOfVertex;
// cout << noOfVertex << endl;
Graph g(noOfVertex); // and here
...
That is enough to get as expected:
Vertex 1-> 2
Vertex 2-> 3 4 5
Vertex 3-> 6
Vertex 4-> 5 7
Vertex 5-> 2 6 7
Vertex 6-> 3 8
Vertex 7-> 8 10
Vertex 8-> 7
Vertex 9-> 7
Vertex 10-> 9 11
Vertex 11-> 12
Vertex 12-> 10
I suggest you make your addEdge method more flexible and easier to use. As one problem, if the source input is larger than the size of list your program will crash. The logic should be:
if there is no source vertex, add it
if there is no destination vertex, add it
add link from source to destination.
Here is a more detailed description of the suggested procedure.
/// find vertex "n", returning vertex index, or -1 if missing
int find( int n )
{
loop over graph
if vertex is "n
return index
return -1
}
/// find vertex "n", or add it if not present
int findoradd( int n )
{
int i = find( n );
if( i >= 0 )
return i
return addvertex( n )
}
/// add link between vertices
void addLink( int u, int v )
{
addEdge(
findoradd( u ),
findoradd( v ) );
}

Boost graph: Iterating through all vertices and printing adjacent vertices

I want to print all vertices with their adjacent vertices. I found some examples online on how to do that, yet it won't work for me. I am getting the error, that the ++ operator cannot be used on ai. Also I think it needs to be vertex_idMap[*ai] and not vertex_idMap[ai] but this prompts an error. Does anyone know why this is wrong?
typedef adjacency_list<vecS, listS, directedS, VertexIDPorperty, EdgeWeight> Graph; //the type of g
graph_traits <Graph>::vertex_iterator i, end;
graph_traits <Graph>::adjacency_iterator ai, a_end;
for (boost::tie(i, end) = vertices(g); i != end; ++i) {
std::cout << vertex_idMap[*i];
for (; ai != a_end; ++ai) { //the ++ai seems to be wrong?
std::cout << vertex_idMap[ai];
if (boost::next(ai) != a_end)
std::cout << ", ";
}
std::cout << std::endl;
Observations:
Where's the rest of the code? It obviously depends on the types used.
ai and a_end aren't initialized (perhaps you didn't actually mean the code doesn't compile, and this was your whole problem)
vertex_idMap[ai] will not compile, as a vertex_iterator is not a valid vertex_descriptor
Here's a fixed example with the missing bits imagined:
Live On Coliru
#include <boost/graph/adjacency_list.hpp>
#include <iostream>
using VertexIDPorperty = boost::property<boost::vertex_index_t, int>;
using EdgeWeight = boost::property<boost::edge_weight_t, double>;
typedef boost::adjacency_list<boost::vecS, boost::listS, boost::directedS, VertexIDPorperty, EdgeWeight> Graph;
Graph sample();
int main() {
Graph g = sample();
auto vertex_idMap = get(boost::vertex_index, g);
boost::graph_traits <Graph>::vertex_iterator i, end;
boost::graph_traits <Graph>::adjacency_iterator ai, a_end;
for (boost::tie(i, end) = vertices(g); i != end; ++i) {
std::cout << vertex_idMap[*i] << ": ";
for (boost::tie(ai, a_end) = adjacent_vertices(*i, g); ai != a_end; ++ai) {
std::cout << vertex_idMap[*ai];
if (boost::next(ai) != a_end)
std::cout << ", ";
}
std::cout << std::endl;
}
}
Implementing sample() to create a random graph:
#include <boost/graph/random.hpp>
#include <random>
Graph sample() {
Graph g;
std::mt19937 prng { std::random_device{}() };
generate_random_graph(g, 10, 20, prng);
int id = 0;
for (auto vd : boost::make_iterator_range(vertices(g))) {
put(boost::vertex_index, g, vd, ++id);
}
return g;
}
It prints something like:
1: 9, 9, 4
2: 6
3:
4:
5: 9, 9, 8, 9
6: 9, 3, 1
7: 2, 10
8: 6
9: 8
10: 7, 3, 8, 1, 4
Out Of The Box
Printing a graph can be done simpler:
#include <boost/graph/graph_utility.hpp>
// ...
int main() {
print_graph(sample());
}
Live On Coliru
1 -->
2 --> 3 10 9 6 6 10
3 --> 8
4 -->
5 --> 4
6 --> 1 5 8
7 --> 4 9 2 2 1
8 --> 6
9 --> 5 7
10 --> 7

How to simultaneously compress a vector (with duplicates) while keeping track of the original indices?

Say I have a vector {1,3,1,5,4,2,3,4,5,2} (the vector size could be very big),
indices --> 1 2 3 4 5 6 7 8 9 10
values --> 1 3 1 5 4 2 3 4 5 2
Which has a relation as:
1 --> {1,3}
2 --> {6,10}
3 --> {2,7}
4 --> {5,8}
5 --> {4,9}
Now using set, I can reduce it to {1,2,3,4,5} by,
std::set<int> uniqNumbersSet;
for(unsigned int i = 0; i < uniqNumbers.size(); ++i )
{
uniqNumbersSet.insert(uniqNumbers[i]);
}
uniqNumbers.assign(uniqNumbersSet.begin(), uniqNumbersSet.end());
But how can I keep track of their original relations? Any efficient ways using STL?
You could use a map of vector.
#include <map>
#include <vector>
std::map<int, std::vector<unsigned> > uniqNumMap;
for (unsigned i = 0; i < uniqNumbers.size(); ++i) {
uniqNumMap[uniqNumbers[i]].push_back(i+1);
}
for (std::map<int, std::vector<unsigned> >::const_iterator i = uniqNumMap.begin(); i != uniqNumMap.end(); ++i) {
std::cout << i->first << " --> {";
for (std::vector<unsigned>::const_iterator j = i->second.begin(); j != i->second.end(); ++j) {
if (j != i->second.begin()) std::cout << ",";
std::cout << *j;
}
std::cout << "}\n";
}

CGAL - Retrieve Vertex Index After Delaunay Triangulation

I am computing the 2D delaunay triangulation of a few thousand points. Each point has more data associated with it beyond x and y coordinates. Therefore, I was wondering if it is possible to retrieve the index of each point so that I can access my own point struct in another vector.
Currently, as I access vertices from a Face_handle, it returns a point (i.e. x,y coordinates) How can I return each vertex by its ID (index) instead of its x,y coordinates? Thank you.
#include <vector>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Delaunay_triangulation_2.h>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef CGAL::Delaunay_triangulation_2<Kernel> Delaunay;
typedef Kernel::Point_2 Point;
void example() {
std::vector<Point> points;
points.push_back(Point(1,1)); //index 0
points.push_back(Point(1,2)); //index 1
points.push_back(Point(1,3)); //index 2
points.push_back(Point(2,1)); //index 3
points.push_back(Point(2,2)); //index 4
points.push_back(Point(2,3)); //index 5
Delaunay triangulation;
triangulation.insert(points.begin(),points.end());
for(Delaunay::Finite_faces_iterator fit = triangulation.finite_faces_begin();
fit != triangulation.finite_faces_end(); ++fit) {
Delaunay::Face_handle face = fit;
std::cout << "Triangle:\t" << triangulation.triangle(face) << std::endl;
std::cout << "Vertex 0:\t" << triangulation.triangle(face)[0] << std::endl;
}
}
Output (x,y coordinates):
Triangle: 1 3 1 2 2 2
Vertex 0: 1 3
Triangle: 1 2 1 1 2 1
Vertex 0: 1 2
Triangle: 1 3 2 2 2 3
Vertex 0: 1 3
Triangle: 1 2 2 1 2 2
Vertex 0: 1 2
Desired Output (indices):
Triangle: 2 1 4
Vertex 0: 2
Triangle: 1 0 3
Vertex 0: 1
Triangle: 2 4 5
Vertex 0: 2
Triangle: 1 3 4
Vertex 0: 1
You can attach any information to vertices in a triangulation. For example to add indices (unsigned int) you could do the following:
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Delaunay_triangulation_2.h>
#include <CGAL/Triangulation_vertex_base_with_info_2.h>
#include <vector>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
typedef CGAL::Triangulation_vertex_base_with_info_2<unsigned int, Kernel> Vb;
typedef CGAL::Triangulation_data_structure_2<Vb> Tds;
typedef CGAL::Delaunay_triangulation_2<Kernel, Tds> Delaunay;
typedef Kernel::Point_2 Point;
int main() {
std::vector< std::pair<Point,unsigned> > points;
points.push_back( std::make_pair( Point(1,1), 0 ) );
points.push_back( std::make_pair( Point(1,2), 1 ) );
points.push_back( std::make_pair( Point(1,3), 2 ) );
points.push_back( std::make_pair( Point(2,1), 3 ) );
points.push_back( std::make_pair( Point(2,2), 4 ) );
points.push_back( std::make_pair( Point(2,3), 5 ) );
Delaunay triangulation;
triangulation.insert(points.begin(),points.end());
for(Delaunay::Finite_faces_iterator fit = triangulation.finite_faces_begin();
fit != triangulation.finite_faces_end(); ++fit) {
Delaunay::Face_handle face = fit;
std::cout << "Triangle:\t" << triangulation.triangle(face) << std::endl;
std::cout << "Vertex 0:\t" << triangulation.triangle(face)[0] << std::endl;
std::cout << "Vertex 0:\t" << face->vertex(0)->info() << std::endl;
}
}