I have two vectors of objects that I need to make a tree structure from them. Let's assume we have vector <obj> parents and vector <obj> leaves. Therefore, each element of vector <obj> parents has several leaves that sits at the end of the tree. What I am doing is defining Vertex properties and Edges properties as below, and then define a bidirectional graph:
struct VertexData
{
std::string obj_name; // concatenation of labels
std::string obj_class_num;
int num;
vector <int> segments_list;
bool is_leaf=false;
};
struct EdgeData
{
std::string edge_name;
double confidence;
};
typedef boost::adjacency_list<boost::vecS, boost::vecS,
boost::bidirectionalS,
VertexData,
boost::property<boost::edge_weight_t, double, EdgeData> > Graph;
Graph graph;
First approach: looping through the vector <obj> leaves, for each member, I find the parent and make an edge. Then assign properties to the edge and vertices. But then for next leaf, I should check if already it has a parent in the tree or I should add a new vertex for its parent.
Second approach: another thing that I tried, was looping through the vector <obj> parents, and for each element try to make its leaves. But I am not sure what is the correct way to do this.
Here is a link:
adding custom vertices to a boost graph that I try to do the same but with iterations.
Code added for 1st approach:
vector <class1> parents; // this has some objects of type class1
vector <class2> leaves; // this has some objects of type class2
/// declare the graph
typedef boost::adjacency_list<boost::vecS, boost::vecS,
boost::bidirectionalS,
VertexData,
boost::property<boost::edge_weight_t, double, EdgeData> > Graph;
/// instantiate the graph
Graph graph;
typedef boost::graph_traits<Graph>::vertex_descriptor vertex_t;
typedef boost::graph_traits<Graph>::edge_descriptor edge_t;
vector<vertex_t> obj_vertices;
vector<string> parents_labels_v;
bool parent_exist=false;
/// loop through leaves and make edges with associated parent
for (auto leaf: leaves) {
int leaf_nr = leaf.Number;
vertex_t v = boost::add_vertex(graph); // this is the leaf vertex
graph[v].num = leaf_nr; // leaf number
graph[v].is_leaf = true;
/// access the parent label by leaf number
string label1 = parents[leaf_nr].label;
/// check if the parent already exist, using its label
if(std::find(parents_labels_v.begin(), parents_labels_v.end(), label1)
!= parents_labels_v.end()){
parent_exist = true;
}else{
parents_labels_v.push_back(label1);
}
if(parent_exist) {
// find already_exist parent vertex to make the edge
vertex_t u = ??? here i have problem
// Create an edge connecting those two vertices
edge_t e; bool b;
boost::tie(e,b) = boost::add_edge(u,v,graph);
} else{
// if parent-vertex there is not, add it to the graph
vertex_t u = boost::add_vertex(graph); // this is the parent vertex
graph[u].obj_name = label1;
graph[u].segments_list.push_back(leaf_nr);
obj_vertices.push_back(u);
// Create an edge connecting those two vertices
edge_t e; bool b;
boost::tie(e,b) = boost::add_edge(u,v,graph);
}
}
Related
I have implemented an undirected graph using adjacency matrix. Now I want to find the edges in the minimum spanning tree that can be obtained by using Prim's Algorithm (along with priority queue). I did that using classic method, but it is highly inefficient (giving correct results). On larger data sets (of vertices and the vertices that they are connected to.).
This is the implementation of Prim's algorithm using priority queue as i used in my code. (This is the code from site geeksforgeeks, the code i wrote is an inspiration from this.)
void Graph::primMST()
{
// Create a priority queue to store vertices that
// are being primMST. This is weird syntax in C++.
// Refer below link for details of this syntax
// http://geeksquiz.com/implement-min-heap-using-stl/
priority_queue< iPair, vector <iPair> , greater<iPair> > pq;
int src = 0; // Taking vertex 0 as source
// Create a vector for keys and initialize all
// keys as infinite (INF)
vector<int> key(V, INF);
// To store parent array which in turn store MST
vector<int> parent(V, -1);
// To keep track of vertices included in MST
vector<bool> inMST(V, false);
// Insert source itself in priority queue and initialize
// its key as 0.
pq.push(make_pair(0, src));
key[src] = 0;
/* Looping till priority queue becomes empty */
while (!pq.empty())
{
// The first vertex in pair is the minimum key
// vertex, extract it from priority queue.
// vertex label is stored in second of pair (it
// has to be done this way to keep the vertices
// sorted key (key must be first item
// in pair)
int u = pq.top().second;
pq.pop();
//Different key values for same vertex may exist in the priority queue.
//The one with the least key value is always processed first.
//Therefore, ignore the rest.
if(inMST[u] == true){
continue;
}
inMST[u] = true; // Include vertex in MST
// 'i' is used to get all adjacent vertices of a vertex
list< pair<int, int> >::iterator i;
for (i = adj[u].begin(); i != adj[u].end(); ++i)
{
// Get vertex label and weight of current adjacent
// of u.
int v = (*i).first;
int weight = (*i).second;
// If v is not in MST and weight of (u,v) is smaller
// than current key of v
if (inMST[v] == false && key[v] > weight)
{
// Updating key of v
key[v] = weight;
pq.push(make_pair(key[v], v));
parent[v] = u;
}
}
}
// Print edges of MST using parent array
for (int i = 1; i < V; ++i)
printf("%d - %d\n", parent[i], i);
}
Thanks in advance.
I am interested in finding sets of vertices that are not ordered in a directed acyclic graph (in the sense of a topological order).
That is, for example: two vertices in non-connected subgraphs, or the pairs (B,C), (B,D) in cases such as :
The naive possibility I thought of was to enumerate all the topological sorts (in this case [ A, B, C, D ] and [ A, C, D, B ] & find all pairs whose order ends up being different in at least two sorts, but this would be pretty expensive computationally.
Are there other, faster possibilities for what I want to achieve ? I am using boost.graph.
Basically what you want is the pair of nodes (u,v) such that there is no path from u to v, and no path from v to u. You can find for each node, all nodes that are reachable from that node using DFS. Total Complexity O(n(n+m)).
Now all you have to do is for each pair check if neither of the 2 nodes are reachable by the other.
You can start with a simple topological sort. Boost's implementation conveniently returns a reverse ordered list of vertices.
You can iterate that list, marking each initial leaf node with a new branch id until a shared node is encountered.
Demo Time
Let's start with the simplests of graph models:
#include <boost/graph/adjacency_list.hpp>
using Graph = boost::adjacency_list<>;
We wish to map branches:
using BranchID = int;
using BranchMap = std::vector<BranchID>; // maps vertex id -> branch id
We want to build, map and visualize the mappings:
Graph build();
BranchMap map_branches(Graph const&);
void visualize(Graph const&, BranchMap const& branch_map);
int main() {
// sample data
Graph g = build();
// do the topo sort and distinguish branches
BranchMap mappings = map_branches(g);
// output
visualize(g, mappings);
}
Building Graph
Just the sample data from the question:
Graph build() {
Graph g(4);
enum {A,B,C,D};
add_edge(A, B, g);
add_edge(A, C, g);
add_edge(C, D, g);
return g;
}
Mapping The Branches
As described in the introduction:
#include <boost/graph/topological_sort.hpp>
std::vector<BranchID> map_branches(Graph const& g) {
std::vector<Vertex> reverse_topo;
boost::topological_sort(g, back_inserter(reverse_topo));
// traverse the output to map to unique branch ids
std::vector<BranchID> branch_map(num_vertices(g));
BranchID branch_id = 0;
for (auto v : reverse_topo) {
auto degree = out_degree(v, g);
if (0 == degree) // is leaf?
++branch_id;
if (degree < 2) // "unique" path
branch_map[v] = branch_id;
}
return branch_map;
}
Visualizing
Let's write a graph-viz representation with each branch colored:
#include <boost/graph/graphviz.hpp>
#include <iostream>
void visualize(Graph const& g, BranchMap const& branch_map) {
// display helpers
std::vector<std::string> const colors { "gray", "red", "green", "blue" };
auto name = [](Vertex v) -> char { return 'A'+v; };
auto color = [&](Vertex v) -> std::string { return colors[branch_map.at(v) % colors.size()]; };
// write graphviz:
boost::dynamic_properties dp;
dp.property("node_id", transform(name));
dp.property("color", transform(color));
write_graphviz_dp(std::cout, g, dp);
}
This uses a tiny shorthand helper to create the transforming property maps:
// convenience short-hand to write transformed property maps
template <typename F>
static auto transform(F f) { return boost::make_transform_value_property_map(f, boost::identity_property_map{}); };
To compile this on a non-c++14 compiler you can replace the call to transform with the expanded body
Full Listing
Live On Coliru
#include <boost/graph/adjacency_list.hpp>
using Graph = boost::adjacency_list<>;
using BranchID = int;
using BranchMap = std::vector<BranchID>; // maps vertex id -> branch id
Graph build();
BranchMap map_branches(Graph const&);
void visualize(Graph const&, BranchMap const& branch_map);
int main() {
// sample data
Graph g = build();
// do the topo sort and distinguish branches
BranchMap mappings = map_branches(g);
// output
visualize(g, mappings);
}
using Vertex = Graph::vertex_descriptor;
Graph build() {
Graph g(4);
enum {A,B,C,D};
add_edge(A, B, g);
add_edge(A, C, g);
add_edge(C, D, g);
return g;
}
#include <boost/graph/topological_sort.hpp>
std::vector<BranchID> map_branches(Graph const& g) {
std::vector<Vertex> reverse_topo;
boost::topological_sort(g, back_inserter(reverse_topo));
// traverse the output to map to unique branch ids
std::vector<BranchID> branch_map(num_vertices(g));
BranchID branch_id = 0;
for (auto v : reverse_topo) {
auto degree = out_degree(v, g);
if (0 == degree) // is leaf?
++branch_id;
if (degree < 2) // "unique" path
branch_map[v] = branch_id;
}
return branch_map;
}
#include <boost/property_map/transform_value_property_map.hpp>
// convenience short-hand to write transformed property maps
template <typename F>
static auto transform(F f) { return boost::make_transform_value_property_map(f, boost::identity_property_map{}); };
#include <boost/graph/graphviz.hpp>
#include <iostream>
void visualize(Graph const& g, BranchMap const& branch_map) {
// display helpers
std::vector<std::string> const colors { "gray", "red", "green", "blue" };
auto name = [](Vertex v) -> char { return 'A'+v; };
auto color = [&](Vertex v) -> std::string { return colors[branch_map.at(v) % colors.size()]; };
// write graphviz:
boost::dynamic_properties dp;
dp.property("node_id", transform(name));
dp.property("color", transform(color));
write_graphviz_dp(std::cout, g, dp);
}
Printing
digraph G {
A [color=gray];
B [color=red];
C [color=green];
D [color=green];
A->B ;
A->C ;
C->D ;
}
And the rendered graph:
Summary
Nodes in branches with different colors cannot be compared.
Can anyone show, with a working example, how one might determine the actual edges used by path obtained from an astar_search() on a graph of type: adjacency_list<multisetS,vecS,directedS,location,route> when parallel edges (multiple routes between the same adjacent source and target vertex) are likely to be present (with different "costs")?
location and route are custom structures that I have as bundled properties for vertices and edges.
I originally was going to use a listS (specifically a std::list) as the type for the outEdgesList but I understand that if I wanted to use out_edge_range(source, target, graph) to retrieve all the edges linking source and target, it needs to be a multisetS (an "ordered set" which permits duplicate values?) - in the worst case I would have to step back through the vertexes of the found path from destination to start, and use the current and previous vertexes with that to recall all the possible edges involved and then pick the one with the lowest "cost" - but that seems a bit non-optimal if the search has already done just that to find the path...!
I am led to believe an edge_predecessor_recorder visitor might be a way to note down the particular edge selected but I have not been able to find a code sample that shows it in use - can that particular visitor even be used on the predecessor map from an A* search?
I should say that I am not totally familiar with the boost libraries - and I'm not that strong on C++ (C: yes, C++: gulp !) The way that the BGL typedefs things and provides some data structures automagically may, indeed, maximise the flexibility to utilise it - but it is a little confusing for the inexperienced (me, for example) to pin down the actual types of elements used or needed for a particular use IMVHO.
I think you're on the right track. This worked for me:
struct location_t { // vertex properties
std::string name;
};
struct route_t { // edge properties
std::size_t distance;
};
typedef adjacency_list<listS,vecS,directedS,location_t,route_t> graph_t;
typedef graph_traits<graph_t>::edge_descriptor edge_t;
typedef graph_traits<graph_t>::vertex_descriptor vertex_t;
struct heuristic {
heuristic(vertex_t dest) : dest_(dest) {}
std::size_t operator()(vertex_t src) {
// only needs to be "optimistic", so:
return (src == dest_) ? 0 : 1 ;
}
private:
vertex_t dest_;
};
typedef std::map<vertex_t, edge_t> pred_edge_map_t;
typedef associative_property_map<pred_edge_map_t> pred_edge_pmap_t;
int main() {
graph_t g;
// insert four vertices and a mix of singular and parallel edges
vertex_t zero = add_vertex(location_t{"A"}, g); // source
vertex_t one = add_vertex(location_t{"B"}, g);
vertex_t two = add_vertex(location_t{"C"}, g);
vertex_t three = add_vertex(location_t{"D"}, g); // sink
// optimal path: 0->2->3 (cost 6)
add_edge(zero, one, route_t{3}, g);
add_edge(zero, one, route_t{5}, g); // parallel to previous edge
add_edge(zero, two, route_t{4}, g);
add_edge(one, three, route_t{4}, g);
add_edge(two, three, route_t{2}, g);
add_edge(two, three, route_t{4}, g); // parallel to previous edge
// construct predecessor map
pred_edge_map_t pred;
pred_edge_pmap_t pred_pmap(pred);
// construct visitor that uses it
auto recorder = record_edge_predecessors(pred_pmap, on_edge_relaxed());
astar_visitor<decltype(recorder)> visitor(recorder);
astar_search(g, zero, heuristic(three),
weight_map(get(&route_t::distance, g)).
visitor(visitor));
// extract route (in reverse order)
for (vertex_t v = three; v != zero; v = source(pred_pmap[v], g)) {
auto e = pred_pmap[v];
std::cout << g[source(e, g)].name << "->" << g[target(e, g)].name << " with weight " << g[pred_pmap[v]].distance << std::endl;
}
}
I know how to represent a graph with an adjacency list representation and I also know the matrix representation (Reference: Algorithms Design Manual)
The adjacency list representation is simply:
struct edge {
int y;
int weight;
struct edge *next;
};
struct graph {
int n;
struct edge *edges[N];
}
But now I want to put the values in the vertex while the edges have no values
struct vertex {
int value; // to be used for sums later
struct vertex *parent;
struct vertex *child;
}
struct edge {
struct vertex *start;
struct vertex *end;
}
struct graph {
int n;
struct vertex *v[N]; // array of vertices
// How do I link the vertices and the edges?
// struct edge
}
My question is how do I link the vertices with the edges?
struct graph {
int n_nodes;
struct node {
int value;
int n_adjacents;
int *adjacent_indices;
} **nodes;
} graph;
I am trying to iterate through the edges of a graph and output their edge weights. I am confused though. I know how to output the "edges", but this is actually just a (vertex, vertex) which defines the edge. So do I index *edgePair.first into the EdgeWeightMap to get the weight of the edge starting from vertex *edgePair.first? This doesn't compile : "no match for operator<<".
#include <iostream>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>
typedef boost::property<boost::edge_weight_t, double> EdgeWeightProperty;
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, EdgeWeightProperty> Graph;
int main(int,char*[])
{
// Create a graph object
Graph g(2);
EdgeWeightProperty e = 5;
add_edge(0, 1, e, g);
boost::property_map<Graph, boost::edge_weight_t>::type EdgeWeightMap = get(boost::edge_weight_t(), g);
typedef boost::graph_traits<Graph>::edge_iterator edge_iter;
std::pair<edge_iter, edge_iter> edgePair;
for(edgePair = edges(g); edgePair.first != edgePair.second; ++edgePair.first)
{
std::cout << EdgeWeightMap[*edgePair.first] << " ";
}
return 0;
}
Any thoughts?
Thanks,
David
In this code, EdgeWeightProperty is declared as a vertex property rather than an edge property, and so it doesn't make sense to insert edges with that property. Try adding boost::no_property before EdgeWeightProperty in your adjacency_list typedef. Also, you might want to use get(EdgeWeightMap, *edgePair.first) rather than operator[] because that will work with more property map types.