Boost minimum spanning tree with some edges included/excluded - boost

I'm trying to implement the list of all possible spanning trees of a graph in order of increasing cost. I'm using the algorithm by Sorensen and Janssens (2005). The graph is initialized as follows:
typedef property<edge_weight_t, int> EdgeWeightProperty;
typedef adjacency_list<vecS, vecS, undirectedS, no_property, EdgeWeightProperty> Graph;
typedef Graph::edge_descriptor Edge;
typedef Graph::vertex_descriptor Vertex;
typedef boost::graph_traits<Graph>::edge_iterator EdgeIterator;
typedef std::pair<EdgeIterator, EdgeIterator> EdgePair;
Graph g;
add_edge(1, 2, 3, g);
add_edge(1, 3, 1, g);
add_edge(1, 4, 2, g);
add_edge(2, 3, 3, g);
add_edge(2, 4, 1, g);
After this it's necessary to find the minimum spanning tree of a graph with some limitations, for instance Edge(2)-(4) shouldn't be in MST and Edge(1)-(2) should be there.
For the edge exclusion it's possible to use remove_edge_if(..) to delete the edge from the graph.
template<typename WMap>
class Remover
{
public:
Remover(const WMap& weights, int threshold)
: m_weights(weights), m_threshold(threshold) {}
template<typename ED>
bool operator()(ED w) const { return m_weights[w] <= m_threshold; }
private:
const WMap& m_weights;
int m_threshold;
};
....
// remove edges of weight < 1
Remover< property_map<Graph, edge_weight_t>::type> r(get(edge_weight, g), 1);
remove_edge_if(r, g);
....
std::list < Edge > spanning_treeT;
kruskal_minimum_spanning_tree(g, std::back_inserter(spanning_treeT));
But how should I ensure that one of the edges is always in the spanning tree? I was trying just to add some Edge into output of the Kruskal function, but it didn't work apparently. It yields MST of the graph + added edge:
std::list < Edge > spanning_tree_g2;
Vertex u, v;
EdgePair ep = edges(g2);
u = source(*ep.first, g2);
v = target(*ep.first, g2);
Edge ed = edge(u, v, g2).first;
spanning_tree_g2.push_front(ed);
kruskal_minimum_spanning_tree(g2, std::back_inserter(spanning_tree_g2));
Is it possible to mark the edges in a way that Kruskal algorithm knows what to include and what not to?

I seems you could force the inclusion of a certain edge by splitting this edge and inserting two "artificial" vertices in the middle.
The MST algorithm is already required to produce a tree of edges that covers all vertices.
Because the artifical vertices have been purposely added by you, it's easy to make sure it's never reachable using any other edges.
Before:
------------------[e:w1+w2]------------------
After:
----[e1:w1]---(v1)---[em:0]---(v2)---[e2:w2]----
(where v1 and v2 are the vertices inserted).
After the fact you "collapse" any sequence of (e1,em,e2) or (e2,em,e1) into (e).
You might end up with a tree that reaches v1 and v2 but never traverses em. In that case you can simply drop one of e1 and e2 and replace it with e unconditionally.

Related

minimum collection of vertice disjoint path that covers a given vertice set

Problem
Given:
A directed graph G
A source vertex s in G and a target vertex t in G
A set S of vertices of G
I want to find a collection of paths from s to t that covers S.
Then I want to partition the collection of paths into subcollections of vertex-disjoint paths.
Under these constraints, the objective is to minimise the number of subcollections.
Example
For instance, [C1 = {p1,p2,p3}, C2= {p4,p5}, C3= {p6,p7}] is a solution if:
each p_i is a path from s to t
p1,p2,p3 have no vertices in common except s and t;
p4, p5 have no vertices in common except s and t;
p6,p7 have no vertices in common except s and t;
collectively, the 7 paths cover all vertices of S.
In that case, the number of subcollections is 3.
Question
What are some good algorithms or heuristics for this optimisation problem?
I already know min cost flow, and disjoint path algos, but they don't apply in my settings.
I tried min cost flow / node disjoint paths but one run only gives one collection at a time. I don't know how to adjust cost to cover the unexplored vertices.
Given:
A directed graph G
A source vertex s in G and a target vertex t in G
A set S of vertices of G
I want to find a collection of paths from s to t that covers S.
Use Dijkstra's algorithm to find a path from s to every vertex in S and from every point in S to t.
Connect the paths to and from each S vertex into one path from s to t via a point in S.
You now have a collection of paths that, together, cover S. Let's call it CS.
Then I want to partition the collection of paths into subcollections
of vertex-disjoint paths.
Note that if s, the source vertex, has an out degree of sOD, there can be no more than sOD paths in each vertex disjoint collection.
Construct vVDP, an empty vector of vertex disjoint path collections
LOOP P over paths in CS
SET found FALSE
LOOP cs over collections in vVDP
IF P is vertex disjoint with every path in cs
add P to cs
SET found TRUE
BREAK out of LOOP cs
IF found == false
ADD collection containing P to vVDP
Here is a C++ implementation of this algorithm
void cProblem::collect()
{
// loop over paths
for (auto &P : vpath)
{
// loop over collections
bool found = false;
for (auto &cs : vVDP)
{
//loop over paths in collection
bool disjoint;
for (auto &csPath : cs)
{
// check that P is vertex disjoint with path in collection
disjoint = true;
for (auto vc : csPath)
{
for (auto &vp : P)
{
if (vp == vc) {
disjoint = false;
break;
}
}
}
if( ! disjoint )
break;
}
if (disjoint)
{
// P is vertex disjoint from every path in collection
// add P to the collection
cs.push_back(P);
found = true;
break;
}
}
if (!found)
{
// P was NOT vertex disjoint with the paths in any collection
// start a new collection with P
std::vector<std::vector<int>> collection;
collection.push_back(P);
vVDP.push_back(collection);
}
}
}
The complete application is at https://github.com/JamesBremner/so75419067
Detailed documentation id the required input file format at
https://github.com/JamesBremner/so75419067/wiki
If you post a real example in the correct format, I will run the algorithm on it for you.

boost::adjacency_list<> and boost::listS

the documentation says:
listS selects std::list
The same is being used in an example I'm trying to adapt.
I don't see anywhere in the example where the edge and the vertex type are being passed to boost::adjacency_list<>.
And unsurprisingly constructing the graph using a begin-end pair into a container of edges does not compile for me.
How can one tell the graph library about the type of edges and vertices one intends to use?
I created a copy of the graph with plain std::size_t for vertices and std::pair<std::size_t, std::size_t> for edges.
I'm unclear why I have to do this, as the graph library is a template library.
Q. I don't see anywhere in the example where the edge and the vertex type are being passed to boost::adjacency_list<>.
You choose all the properties of the graph with the template arguments.
The first two choose how edges and vertexes are to be stored. For adjacency-lists, the adjacency-list is a given, but you can choose the edge container selector (which stores the adjacencies (out-edges) per source vertex) and the actual vertex container selector (which stores the vertices themselves).
The other template arguments include the vertex/edge and graph properties. So, where the container selectors choose how to store graph entities, the properties describe what should be stored.
HOW everything is being stored is ultimately an implementation detail.
Q. And unsurprisingly constructing the graph using a begin-end pair into a container of edges does not compile for me.
We can't say anything about that, because we don't know what you mean by "a container of edges". Do you already have your graph in some other format?¹
The constructor arguments are not required to build a graph. E.g.:
#include <boost/graph/adjacency_list.hpp>
using G = boost::adjacency_list<>;
int main() {
G g(10);
}
Is the simplest possible program that creates a graph with 10, unconnected, vertices. To also print it: Live
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graph_utility.hpp>
using G = boost::adjacency_list<>;
int main() {
G g(10);
print_graph(g);
}
Output shows 10 vertices with no adjacencies:
0 -->
1 -->
2 -->
3 -->
4 -->
5 -->
6 -->
7 -->
8 -->
9 -->
How can one tell the graph library about the type of edges and vertices one intends to use?
Let me start with the "using", then modify the types a little:
Instead you can add edges/vertices after construction: Live
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graph_utility.hpp>
using G = boost::adjacency_list<>;
using V = G::vertex_descriptor;
using E = G::edge_descriptor;
int main() {
G g;
V v1 = add_vertex(g);
V v2 = add_vertex(g);
E e1 = add_edge(v1, v2, g).first;
// or:
auto [ed, inserted] = add_edge(v1, v2, g);
std::cout << "Second insertion happened: " << std::boolalpha << inserted << "\n";
print_graph(g);
}
Output:
Second insertion happened: true
0 --> 1 1
1 -->
Now, let's immediately show the effect of setS as edge storage:
using G = boost::adjacency_list<boost::setS>;
Output becomes - because the setS doesn't admit duplicate out-edges:
Second insertion happened: false
0 --> 1
1 -->
Now, let's also try a different vertex container selector?
using G = boost::adjacency_list<boost::setS, boost::listS>;
Uhoh, now there is trouble printing the graph, because, as you might have read already in the linked documentation:
If the VertexList of the graph is vecS, then the graph has a builtin vertex indices accessed via the property map for the vertex_index_t property. The indices fall in the range [0, num_vertices(g)) and are contiguous. When a vertex is removed the indices are adjusted so that they retain these properties. Some care must be taken when using these indices to access exterior property storage. The property map for vertex index is a model of Readable Property Map.
If you use listS then there is no implicit vertex index. Of course, we can add an index, but let's instead add a name property to our vertex.
There are many ways to add properties, but let me show you the more versatile/friendly version: bundled properties:
struct VertexProps {
std::string name;
};
using G = boost::adjacency_list<boost::setS, boost::listS, boost::undirectedS, VertexProps>;
Now, all we need to do is tell print_graph to use the name property from the bundle instead of the vertex index (which isn't usable for printing since listS):
print_graph(g, get(&VertexProps::name, g));
Of course, it becomes nicer when you actually give the vertices names:
V v1 = add_vertex(VertexProps{"v1"}, g);
V v2 = add_vertex(VertexProps{"v2"}, g);
But of course, names can be changed:
g[v2].name += "(changed)";
See it all together: Live
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graph_utility.hpp>
struct VertexProps {
std::string name;
};
using G = boost::adjacency_list<boost::setS, boost::listS, boost::undirectedS, VertexProps>;
using V = G::vertex_descriptor;
using E = G::edge_descriptor;
int main() {
G g;
V v1 = add_vertex(VertexProps{"v1"}, g);
V v2 = add_vertex(VertexProps{"v2"}, g);
E e1 = add_edge(v1, v2, g).first;
// or:
auto [ed, inserted] = add_edge(v1, v2, g);
g[v2].name += "(changed)";
std::cout << "Second insertion happened: " << std::boolalpha << inserted << "\n";
print_graph(g, get(&VertexProps::name, g));
}
Prints
Second insertion happened: false
v1 <--> v2(changed)
v2(changed) <--> v1
¹ You may not need to copy anything at all, just adapt/use the existing graph)

Back edges in a graph

I'm having a hard time understanding Tarjan's algorithm for articulation points. I'm currently following this tutorial here: https://www.hackerearth.com/practice/algorithms/graphs/articulation-points-and-bridges/tutorial/. What I really can't see, and couldn't see in any other tutorial, is what exactly a "back edge" means. Considering the graph given there, I know 3-1 and 4-2 are back edges, but are 2-1, 3-2, and 4-3 back edges too? Thank you.
...a Back Edge is an edge that connects a vertex to a vertex that is discovered before it's parent.
from your source.
Think about it like this: When you apply a DFS on a graph you fix some path that the algorithm chooses. Now in the given case: 0->1->2->3->4. As in the article mentioned, the source graph contains the edges 4-2 and 3-1. When the DFS reaches 3 it could choose 1 but 1 is already in your path so it is a back edge and therefore, as mentioned in the source, a possible alternative path.
Addressing your second question: Are 2-1, 3-2, and 4-3 back edges too? For a different path they can be. Suppose your DFS chooses 0->1->3->2->4 then 2-1 and 4-3 are back edges.
Consider the following (directed) graph traversal with DFS. Here the colors of the nodes represent the following:
The floral-white nodes are the ones that are yet to be visited
The gray nodes are the nodes that are visited and on stack
The black nodes are the ones that are popped from the stack.
Notice that when the node 13 discovers the node 0 through the edge 13->0 the node 0 is still on the stack. Here, 13->0 is a back edge and it denotes the existence of a cycle (the triangle 0->1->13).
In essence, when you do a DFS, if there are cycles in your graph between nodes A, B and C and you have discovered the edges A-B, later you discover the edge B-C, then, since you have reached node C, you will discover the edge C-A, but you need to ignore this path in your search to avoid infinite loops. So, in your search A-B and B-C were not back edges, but C-A is a back edge, since this edge forms a cycle back to an already visited node.
From article mentioned:
Given a DFS tree of a graph, a Back Edge is an edge that connects a
vertex to a vertex that is discovered before it's parent.
2-1, 3-2, 4-3 are not "Back edge" because they link the vertices with their parents in DFS tree.
Here is the code for a better understand:
#include<bits/stdc++.h>
using namespace std;
struct vertex{
int node;
int start;
int finish;
int color;
int parent;
};
int WHITE=0, BLACK=1, GREY=2;
vector<int> adjList[8];
int num_of_verts = 8;
struct vertex vertices[8];
int t=0;
bool DFS_visit(int u){
bool cycleExists = false;
vertices[u].color=GREY;
t++;
vertices[u].start= t;
for( int i=0; adjList[u][i]!=-1; i++){
if( vertices[adjList[u][i]].color == WHITE ){
if(!cycleExists) cycleExists = DFS_visit(adjList[u][i]);
else DFS_visit(adjList[u][i]);
}
else {
cout << "Cycle detected at edge - ("<<u<<", "<<adjList[u][i]<<")"<<endl;
cycleExists = true;
}
}
vertices[u].color=BLACK;
t++;
vertices[u].finish= t;
return cycleExists;
}
void DFS(){
for(int i=0;i<num_of_verts;i++){
vertices[i].color=WHITE;
vertices[i].parent=NULL;
}
t=0;
for(int i=0;i<num_of_verts;i++){
if(vertices[i].color==WHITE){
cout << "Traversing component "<<i<<"-"<<endl;
bool cycle = DFS_visit(i);
cycle==1? cout<<"Cycle Exists\n\n":cout <<"Cycle does not exist\n\n";
}
}
}
int main(){
adjList[0] = {4, -1};
adjList[1] = {0, 5, -1};
adjList[2] = {1, 5, -1};
adjList[3] = {6, 7, -1};
adjList[4] = {1, -1};
adjList[5] = {-1};
adjList[6] = {2, 5, -1};
adjList[7] = {3, 6, -1};
DFS();
return 0;
}

sort graph by distance to end nodes

I have a list of nodes which belong in a graph. The graph is directed and does not contain cycles. Also, some of the nodes are marked as "end" nodes. Every node has a set of input nodes I can use.
The question is the following: How can I sort (ascending) the nodes in the list by the biggest distance to any reachable end node? Here is an example off how the graph could look like.
I have already added the calculated distance after which I can sort the nodes (grey). The end nodes have the distance 0 while C, D and G have the distance 1. However, F has the distance of 3 because the approach over D would be shorter (2).
I have made a concept of which I think, the problem would be solved. Here is some pseudo-code:
sortedTable<Node, depth> // used to store nodes and their currently calculated distance
tempTable<Node>// used to store nodes
currentDepth = 0;
- fill tempTable with end nodes
while( tempTable is not empty)
{
- create empty newTempTable<Node node>
// add tempTable to sortedTable
for (every "node" in tempTable)
{
if("node" is in sortedTable)
{
- overwrite depth in sortedTable with currentDepth
}
else
{
- add (node, currentDepth) to sortedTable
}
// get the node in the next layer
for ( every "newNode" connected to node)
{
- add newNode to newTempTable
}
- tempTable = newTempTable
}
currentDepth++;
}
This approach should work. However, the problem with this algorithm is that it basicly creates a tree from the graph based from every end node and then corrects old distance-calculations for every depth. For example: G would have the depth 1 (calculatet directly over B), then the depth 3 (calculated over A, D and F) and then depth 4 (calculated over A, C, E and F).
Do you have a better solution to this problem?
It can be done with dynamic programming.
The graph is a DAG, so first do a topological sort on the graph, let the sorted order be v1,v2,v3,...,vn.
Now, set D(v)=0 for all "end node", and from last to first (according to topological order) do:
D(v) = max { D(u) + 1, for each edge (v,u) }
It works because the graph is a DAG, and when done in reversed to the topological order, the values of all D(u) for all outgoing edges (v,u) is already known.
Example on your graph:
Topological sort (one possible):
H,G,B,F,D,E,C,A
Then, the algorithm:
init:
D(B)=D(A)=0
Go back from last to first:
D(A) - no out edges, done
D(C) = max{D(A) + 1} = max{0+1}=1
D(E) = max{D(C) + 1} = 2
D(D) = max{D(A) + 1} = 1
D(F) = max{D(E)+1, D(D)+1} = max{2+1,1+1} = 3
D(B) = 0
D(G) = max{D(B)+1,D(F)+1} = max{1,4}=4
D(H) = max{D(G) + 1} = 5
As a side note, if the graph is not a DAG, but a general graph, this is a variant of the Longest Path Problem, which is NP-Complete.
Luckily, it does have an efficient solution when our graph is a DAG.

What does boost::out_edges( v, g ) in Boost.Graph do?

I am not able to comprehend the documentation for this function, I have seen several times the following
tie (ei,ei_end) = out_edges(*(vi+a),g);
**g**<-graph
**vi**<-beginning vertex of graph
**a**<- a node
**ei and ei_end** <- edge iterators
What does the function return,and what does it do,when could I use?
Can I find all edges from a node for example?
Provides iterators to iterate over the out-going edges of node u from graph g, e.g.:
typename graph_traits < Graph >::out_edge_iterator ei, ei_end;
for (boost::tie(ei, ei_end) = out_edges(u, g); ei != ei_end; ++ei) {
auto source = boost::source ( *ei, g );
auto target = boost::target ( *ei, g );
std::cout << "There is an edge from " << source << " to " << target << std::endl;
}
where Graph is your type definition of the graph an g is an instance of that. However, out_edges is only applicable for graphs with directed edges. The opposite of out_edges is in_edges that provides you iterators to compute in-coming edges of a node.
In an undirected graph both out_edges and in_edges will return all the edges connecting to the node in question.
However, more information can be easily found on http://www.boost.org/doc/libs/1_55_0/libs/graph/doc/graph_concepts.html or just in the Boost.Graph examples/tests.
As explained above, for a directed graph, out_edges accepts a "vertex_descriptor and the graph(adjacency list) to be examined" and returns "all the edges that emanate (directed from) the given vertex_descriptor", by means of an iterator-range.
As described in https://www.boost.org/doc/libs/1_69_0/libs/graph/doc/adjacency_list.html
std::pair<out_edge_iterator, out_edge_iterator>
out_edges(vertex_descriptor u, const adjacency_list& g)
Returns an iterator-range providing access to the out-edges of vertex
u in graph g. If the graph is undirected, this iterator-range provides
access to all edges incident on vertex u. For both directed and
undirected graphs, for an out-edge e, source(e, g) == u and target(e,
g) == v where v is a vertex adjacent to u.
In short, to answer some of your questions,
Yes, you can use it to find all edges from a node.
For undirected graphs, the behavior is as explained in the link above, it returns all the edges incident on the vertex (all edges connected to it)

Resources