boost grid_graph and graph cut on image - c++

I'm trying to use Boost Graph Library to use graph cut on a 2D image. My goal is to represent each pixel as a node with 4 float edges (less on the borders). Neighborhood pixels' edge will have a value dependant on gradiant or intensity or something.
To do so, I tried using boost::grid_graph with boost::boykov_kolmogorov_max_flow(), without success. The doc says that grid_graph models "Vertex List", "Edge List" and "Incidence graph", which are the requirements for boykov_kolmogorov_max_flow, so I think it should work.
Here's my code:
const unsigned int D = 2;
typedef boost::grid_graph<D> Graph;
typedef boost::graph_traits<Graph>::vertex_descriptor VertexDescriptor;
boost::array<unsigned int, D> lengths = { { 3, 3 } };
Graph graph(lengths, false);
// Add edge's value between pixels
VertexDescriptor s, t; // Should be initialized, I know.
float flow = boost::boykov_kolmogorov_max_flow(graph, s, t);
// error C2039: 'edge_property_type' is not a member of 'boost::grid_graph<Dimensions>'
I know s and t should be initialized, but I only want the program to compile. Is it possible to use grid_graph with boykov_kolmogorov_max_flow? If so, how? If not, then I guess I'm forced to use the more generic (and probably slower) boost::adjacency_list? Thanks.

The problem you have with the other answer is probably caused by an older version of Visual Studio (its code works fine with Visual Studio 2012 Express/g++ 4.8.0 and boost 1.53.0). If that problem is the only one with your compiler it can easily be sidestepped by creating another custom property map similar to the one that uses capacity. The changes required are marked with //ADDED and //CHANGED.
#include <iostream>
#include <boost/graph/grid_graph.hpp>
#include <boost/graph/boykov_kolmogorov_max_flow.hpp>
#include <boost/graph/iteration_macros.hpp>
int main()
{
const unsigned int D = 2;
typedef boost::grid_graph<D> Graph;
typedef boost::graph_traits<Graph>::vertex_descriptor VertexDescriptor;
typedef boost::graph_traits<Graph>::edge_descriptor EdgeDescriptor;//ADDED
typedef boost::graph_traits<Graph>::vertices_size_type VertexIndex;
typedef boost::graph_traits<Graph>::edges_size_type EdgeIndex;
boost::array<std::size_t, D> lengths = { { 3, 3 } };
Graph graph(lengths, false);
float pixel_intensity[]={10.0f,15.0f,25.0f,
5.0f,220.0f,240.0f,
12.0f,15.0,230.0f};
std::vector<int> groups(num_vertices(graph));
std::vector<float> residual_capacity(num_edges(graph)); //this needs to be initialized to 0
std::vector<float> capacity(num_edges(graph)); //this is initialized below, I believe the capacities of an edge and its reverse should be equal, but I'm not sure
std::vector<EdgeDescriptor> reverse_edges(num_edges(graph));//ADDED
BGL_FORALL_EDGES(e,graph,Graph)
{
VertexDescriptor src = source(e,graph);
VertexDescriptor tgt = target(e,graph);
VertexIndex source_idx = get(boost::vertex_index,graph,src);
VertexIndex target_idx = get(boost::vertex_index,graph,tgt);
EdgeIndex edge_idx = get(boost::edge_index,graph,e);
capacity[edge_idx] = 255.0f - fabs(pixel_intensity[source_idx]-pixel_intensity[target_idx]); //you should change this to your "gradiant or intensity or something"
reverse_edges[edge_idx]=edge(tgt,src,graph).first;//ADDED
}
VertexDescriptor s=vertex(0,graph), t=vertex(8,graph);
//in the boykov_kolmogorov_max_flow header it says that you should use this overload with an explicit color property map parameter if you are interested in finding the minimum cut
boykov_kolmogorov_max_flow(graph,
make_iterator_property_map(&capacity[0], get(boost::edge_index, graph)),
make_iterator_property_map(&residual_capacity[0], get(boost::edge_index, graph)),
make_iterator_property_map(&reverse_edges[0], get(boost::edge_index, graph)), //CHANGED
make_iterator_property_map(&groups[0], get(boost::vertex_index, graph)),
get(boost::vertex_index, graph),
s,
t
);
for(size_t index=0; index < groups.size(); ++index)
{
if((index%lengths[0]==0)&&index)
std::cout << std::endl;
std::cout << groups[index] << " ";
}
return 0;
}
Working on Coliru.
PS: One thing that the Boost.Graph documentation fails to clarify is that the concept requirements described there apply to the case when you explicitly pass every one of the arguments. Some of the default arguments may introduce further requirements.

#include <iostream>
#include <boost/graph/grid_graph.hpp>
#include <boost/graph/boykov_kolmogorov_max_flow.hpp>
#include <boost/graph/iteration_macros.hpp>
int main()
{
const unsigned int D = 2;
typedef boost::grid_graph<D> Graph;
typedef boost::graph_traits<Graph>::vertex_descriptor VertexDescriptor;
typedef boost::graph_traits<Graph>::vertices_size_type VertexIndex;
typedef boost::graph_traits<Graph>::edges_size_type EdgeIndex;
boost::array<unsigned int, D> lengths = { { 3, 3 } };
Graph graph(lengths, false);
float pixel_intensity[]={10.0f,15.0f,25.0f,
5.0f,220.0f,240.0f,
12.0f,15.0,230.0f};
std::vector<int> groups(num_vertices(graph));
std::vector<float> residual_capacity(num_edges(graph)); //this needs to be initialized to 0
std::vector<float> capacity(num_edges(graph)); //this is initialized below, I believe the capacities of an edge and its reverse should be equal, but I'm not sure
BGL_FORALL_EDGES(e,graph,Graph)
{
VertexDescriptor src = source(e,graph);
VertexDescriptor tgt = target(e,graph);
VertexIndex source_idx = get(boost::vertex_index,graph,src);
VertexIndex target_idx = get(boost::vertex_index,graph,tgt);
EdgeIndex edge_idx = get(boost::edge_index,graph,e);
capacity[edge_idx] = 255.0f - fabs(pixel_intensity[source_idx]-pixel_intensity[target_idx]); //you should change this to your "gradiant or intensity or something"
}
VertexDescriptor s=vertex(0,graph), t=vertex(8,graph);
//in the boykov_kolmogorov_max_flow header it says that you should use this overload with an explicit color property map parameter if you are interested in finding the minimum cut
boykov_kolmogorov_max_flow(graph,
make_iterator_property_map(&capacity[0], get(boost::edge_index, graph)),
make_iterator_property_map(&residual_capacity[0], get(boost::edge_index, graph)),
get(boost::edge_reverse, graph),
make_iterator_property_map(&groups[0], get(boost::vertex_index, graph)),
get(boost::vertex_index, graph),
s,
t
);
for(size_t index=0; index < groups.size(); ++index)
{
if((index%lengths[0]==0)&&index)
std::cout << std::endl;
std::cout << groups[index] << " ";
}
return 0;
}

Related

What should be the return value of a custom function addEdge in a new class based on BGL?

I try to implement a graph class based on https://stackoverflow.com/a/950173/7558038. When adding an edge I return the edge descriptor of the added edge, but if the edge already exists, it shouldn't be added. What shall I return then? Unfortunately, null_edge() does not exist (unlike null_vertex()). It could be an std::pair<e_it_t,bool> with an appropriate edge iterator type e_it_t, but how can I get an iterator to the new edge?
Don't use that class that is almost 10 years old. It is obsolete.
Bundled properties have come to BGL as long as I know, which is... probably since at least 2010. Nothing there is fundamentally easier than straight boost.
Another weird property is that somehow only complementary edges can be inserted in that graph. This might be what you want, but it doesn't warrant having the complete class, IMO.
In fact, having the custom type removes ADL, which makes things more tedious unless you go and add each other operation (like, you know, out_edges or in_edges, which presumably is what you wanted a bidirectional graph for in the first place; maybe you actually wish to have iterable ranges instead of pair<iterator, iterator> which requires you to write old-fashioned for loops).
Now that I've warmed up a bit, lets demonstrate:
Using The Obsolete Wrapper class
The linked wrapper affords usage like this:
struct VertexProperties { int i; };
struct EdgeProperties { double weight; };
int main() {
using MyGraph = Graph<VertexProperties, EdgeProperties>;
MyGraph g;
VertexProperties vp;
vp.i = 42;
MyGraph::Vertex v1 = g.AddVertex(vp);
g.properties(v1).i = 23;
MyGraph::Vertex v2 = g.AddVertex(vp);
g.properties(v2).i = 67;
g.AddEdge(v1, v2, EdgeProperties{1.0}, EdgeProperties{0.0});
for (auto vr = g.getVertices(); vr.first!=vr.second; ++vr.first) {
auto& vp = g.properties(*vr.first);
std::cout << "Vertex " << vp.i << "\n";
for (auto er = g.getAdjacentVertices(*vr.first); er.first!=er.second; ++er.first) {
auto s = *vr.first;
auto t = *er.first;
// erm how to get edge properties now?
std::cout << "Edge " << g.properties(s).i << " -> " << g.properties(t).i << " (weight?!?)\n";
}
}
}
Which prints:
Vertex 23
Edge 23 -> 67 (weight?!?)
Vertex 67
Edge 67 -> 23 (weight?!?)
Note I didn't exactly bother to solve the problem of getting the edge-weight (we don't readily get edge descriptors from the interface at all).
The for loops throw us back in time at least 6 years. And that's not nearly the worst problem. Presumably, you need your graph for something. Let's assume you want minimum cut, or a shortest path. This means you want to invoke an algorithm that requires the edge weight. This would look like so:
// let's find a shortest path:
// build the vertex index map
boost::property_map<MyGraph::GraphContainer, vertex_properties_t>::const_type vpmap =
boost::get(vertex_properties, g.getGraph());
// oops we need the id from it. No problem, it takes only rocket science:
struct GetId {
int operator()(VertexProperties const& vp) const {
return vp.i;
}
};
GetId get_id;
boost::transform_value_property_map<GetId,
boost::property_map<MyGraph::GraphContainer, vertex_properties_t>::const_type,
int> id_map
= boost::make_transform_value_property_map<int>(get_id, vpmap);
// build the weight map
boost::property_map<MyGraph::GraphContainer, edge_properties_t>::const_type epmap =
boost::get(edge_properties, g.getGraph());
// oops we need the weight from it. No problem, it takes only rocket science:
struct GetWeight {
double operator()(EdgeProperties const& ep) const {
return ep.weight;
}
};
GetWeight get_weight;
boost::transform_value_property_map<GetWeight,
boost::property_map<MyGraph::GraphContainer, edge_properties_t>::const_type,
double> weight_map
= boost::make_transform_value_property_map<double>(get_weight, epmap);
// and now we "simply" use Dijkstra:
MyGraph::vertex_range_t vertices = g.getVertices();
//size_t n_vertices = g.getVertexCount();
MyGraph::Vertex source = *vertices.first;
std::map<MyGraph::Vertex, MyGraph::Vertex> predecessors;
std::map<MyGraph::Vertex, double> distance;
boost::dijkstra_shortest_paths(g.getGraph(), source,
boost::predecessor_map(boost::make_assoc_property_map(predecessors))
.distance_map(boost::make_assoc_property_map(distance))
.weight_map(weight_map)
.vertex_index_map(id_map));
This is not my idea of usability. Just to show it all compiles and runs:
Live On Coliru
Replace The Wrapper In 2 Lines Of C++11
Let's replace the whole Graph class template in modern BGL style:
template <typename VertexProperties, typename EdgeProperties>
using Graph = adjacency_list<setS, listS, bidirectionalS, VertexProperties, EdgeProperties>;
Really. That is a solid replacement, I'll demonstrate it right away.
In fact, let's not do using namespace boost; because it pollutes our namespace with all manner of names we might find really useful (like, you know source or num_vertices) and invites ambiguous symbols:
template <typename VertexProperties, typename EdgeProperties>
using Graph = boost::adjacency_list<boost::setS, boost::listS, boost::bidirectionalS, VertexProperties, EdgeProperties>;
The Same Use-Cases - creation and dijkstra
They are still as simple, or in fact simpler. The full code goes down from 249 lines of code to just 57:
Live On Coliru
#include <boost/graph/adjacency_list.hpp>
namespace MyLib {
template <typename VertexProperties, typename EdgeProperties>
using Graph = boost::adjacency_list<boost::setS, boost::listS, boost::bidirectionalS, VertexProperties, EdgeProperties>;
}
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <iostream>
struct VertexProperties { int i; };
struct EdgeProperties { double weight; };
int main() {
using boost::make_iterator_range;
using MyGraph = MyLib::Graph<VertexProperties, EdgeProperties>;
MyGraph g;
auto v1 = add_vertex({42}, g);
auto v2 = add_vertex({42}, g);
g[v1].i = 23;
g[v2].i = 67;
add_edge(v1, v2, EdgeProperties{ 1.0 }, g);
add_edge(v2, v1, EdgeProperties{ 0.0 }, g);
for (auto v : make_iterator_range(vertices(g))) {
std::cout << "Vertex " << g[v].i << "\n";
}
for (auto e : make_iterator_range(boost::edges(g))) {
auto s = source(e, g);
auto t = target(e, g);
std::cout << "Edge " << g[s].i << " -> " << g[t].i << " (weight = " << g[e].weight << ")\n";
}
// let's find a shortest path:
auto id_map = get(&VertexProperties::i, g);
auto weight_map = get(&EdgeProperties::weight, g);
auto source = *vertices(g).first;
using Vertex = MyGraph::vertex_descriptor;
std::map<Vertex, Vertex> predecessors;
std::map<Vertex, double> distance;
std::map<Vertex, boost::default_color_type> colors;
boost::dijkstra_shortest_paths(
g, source,
boost::vertex_color_map(boost::make_assoc_property_map(colors))
.predecessor_map(boost::make_assoc_property_map(predecessors))
.distance_map(boost::make_assoc_property_map(distance))
.weight_map(weight_map)
.vertex_index_map(id_map));
}
I'd say
that is superior.
it's just as elegant despite not relying on using namespace boost (ADL is the key here)
and we actually printed the edge weight!
And It Can Be Cleaner Still
If you switch to a vertex container selector that has implicit vertex index (like vecS):
Live On Coliru
#include <boost/graph/adjacency_list.hpp>
namespace MyLib {
template <typename VertexProperties, typename EdgeProperties>
using Graph = boost::adjacency_list<boost::setS, boost::vecS, boost::bidirectionalS, VertexProperties, EdgeProperties>;
}
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <iostream>
struct VertexProperties { int i; };
struct EdgeProperties { double weight; };
int main() {
using boost::make_iterator_range;
using MyGraph = MyLib::Graph<VertexProperties, EdgeProperties>;
MyGraph g;
add_vertex({23}, g);
add_vertex({67}, g);
add_edge(0, 1, EdgeProperties{ 1.0 }, g);
add_edge(1, 0, EdgeProperties{ 0.0 }, g);
for (auto v : make_iterator_range(vertices(g))) {
std::cout << "Vertex " << g[v].i << "\n";
}
for (auto e : make_iterator_range(boost::edges(g))) {
auto s = source(e, g);
auto t = target(e, g);
std::cout << "Edge " << g[s].i << " -> " << g[t].i << " (weight = " << g[e].weight << ")\n";
}
// let's find a shortest path:
std::vector<size_t> predecessors(num_vertices(g));
std::vector<double> distance(num_vertices(g));
boost::dijkstra_shortest_paths(g, *vertices(g).first,
boost::predecessor_map(predecessors.data()).distance_map(distance.data())
.weight_map(get(&EdgeProperties::weight, g)));
}
Output:
Vertex 23
Vertex 67
Edge 23 -> 67 (weight = 1)
Edge 67 -> 23 (weight = 0)
WAIT - Don't Forget About The Question!
I won't! I think the above shows the problem was an X/Y problem.
If you hadn't had the handicap of custom class wrapping, detecting duplicate edges was a given (see if add_vertex in BGL checks for the existence of the vertex for background):
struct { size_t from, to; double weight; } edge_data[] = {
{0, 1, 1.0},
{1, 0, 0.0},
{0, 1, 99.999} // oops, a duplicate
};
for(auto request : edge_data) {
auto addition = add_edge(request.from, request.to, { request.weight }, g);
if (!addition.second) {
auto& weight = g[addition.first].weight;
std::cout << "Edge already existed, changing weight from " << weight << " to " << request.weight << "\n";
weight = request.weight;
}
}
This will print Live On Coliru:
Edge already existed, changing weight from 1 to 99.999
If you prefer you can of course write things more expressively:
Graph::edge_descriptor e;
bool inserted;
boost::tie(e, inserted) = add_edge(request.from, request.to, { request.weight }, g);
Or, with some c++17 flair:
auto [e, inserted] = add_edge(request.from, request.to, { request.weight }, g);
More From Here
Also, in all likelihood you need to do uniqueness checks on the vertices too, so you end up with graph creation code like you can see in this answer: Boost BGL BFS Find all unique paths from Source to Target
Graph read_graph() {
std::istringstream iss(R"(
0 1 0.001
0 2 0.1
0 3 0.001
1 5 0.001
2 3 0.001
3 4 0.1
1 482 0.1
482 635 0.001
4 705 0.1
705 5 0.1
1 1491 0.01
1 1727 0.01
1 1765 0.01)");
Graph g;
std::map<int,Vertex> idx; // temporary lookup of existing vertices
auto vertex = [&](int id) mutable {
auto it = idx.find(id);
if (it != idx.end())
return it->second;
return idx.emplace(id, add_vertex(id, g)).first->second;
};
for (std::string line; getline(iss, line);) {
std::istringstream ls(line);
int s,t; double w;
if (ls >> s >> t >> w) {
add_edge(vertex(s), vertex(t), w, g);
} else {
std::cerr << "Skipped invalid line '" << line << "'\n";
}
}
return g;
}
Other examples show how you can insert both a -> b and b -> a while maintaining a mapping between the forward and back edges: Accessing specific edges in boost::graph with integer index
Summary
Coming full circle, I recommend getting acquainted with the newer, more elegant Boost Graph features. In the end, it's perfectly normal to encapsulate your graph, and you might end up with an even more polished interface.

Boost.Graph - algo.is_optimal() assertion

I am trying to implement a program that detects arbitrage trading opportunities using a minimum cost flow algorithm. This algorithm is implemented in Boost.Graph in the form of boost::push_relabel_max_flow() followed by a call to boost::cycle_canceling().
The following is the code I have already, leaving out the boost::cycle_canceling-part because my program dies before reaching the function.
#include <boost/graph/adjacency_list.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/graph/push_relabel_max_flow.hpp>
#include <boost/graph/cycle_canceling.hpp>
#include <boost/graph/directed_graph.hpp>
#include <boost/config.hpp>
#include <iostream>
#include <string>
typedef boost::adjacency_list_traits<boost::vecS, boost::vecS, boost::directedS> Traits;
struct st_order {
double price;
double amount;
std::string type;
};
struct VertexProps {
unsigned int id;
};
struct EdgeProps {
double capacity;
double residual_capacity;
double weight;
Traits::edge_descriptor reverse;
};
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS, VertexProps, EdgeProps > DirectedGraph;
int main() {
DirectedGraph g;
// ETH / BTC
std::vector<st_order> trades{
st_order{0.0101,10.0,"SELL"},
st_order{0.01,3.0,"BUY"},
st_order{0.0102,5.0,"SELL"},
st_order{0.2,42.0,"BUY"},
};
std::vector<boost::graph_traits<DirectedGraph>::vertex_descriptor> vertices;
for(unsigned int vertex_index = 0; vertex_index < trades.size(); vertex_index++)
{
vertices.push_back(boost::add_vertex({vertex_index}, g));
}
std::map<DirectedGraph::vertex_descriptor, std::map<DirectedGraph::vertex_descriptor, Traits::edge_descriptor>> edges;
int ifirst = 0;
for(auto& first : vertices)
{
int isecond = 0;
for(auto& second : vertices)
{
if(first == second || trades[ifirst].type.compare(trades[isecond].type) == 0)
{
isecond++;
continue;
}
double amount = trades[isecond].amount;
if(trades[isecond].type.compare("SELL") == 0)
amount = amount * trades[isecond].price;
edges[first][second] = boost::add_edge(first, second, {amount, amount, (trades[isecond].price / trades[ifirst].price)} , g).first;
std::cout << "Add Edge: From " << first << " to " << second << std::endl;
isecond++;
}
ifirst++;
}
for(auto& i : vertices)
{
for(auto& j : vertices)
{
if(i == j)
continue;
if(edges.find(i) != edges.end() && edges[i].find(j) != edges[i].end())
{
if(edges.find(j) == edges.end() || edges[j].find(i) == edges[j].end())
{
throw std::runtime_error("No return edge found: "+std::to_string(i)+" "+std::to_string(j));
}
auto edge = boost::edge(i,j,g).first;
g[edge].reverse = edges[i][j];
}
}
}
double flow = boost::push_relabel_max_flow(g, vertices[0], vertices[1],
boost::get(&EdgeProps::capacity, g),
boost::get(&EdgeProps::residual_capacity, g),
boost::get(&EdgeProps::reverse, g),
boost::get(boost::vertex_index, g)
);
// Now boost::cycle_canceling() would follow
std::cout << "END << std::endl;
return 0;
};
The "normal" output of my program is:
Add Edge: From 0 to 1
Add Edge: From 0 to 3
Add Edge: From 1 to 0
Add Edge: From 1 to 2
Add Edge: From 2 to 1
Add Edge: From 2 to 3
Add Edge: From 3 to 0
Add Edge: From 3 to 2
As flowchart:
My program asserts in the push_relabel_max_flow-function. The following is the complete error code (which is printed at runtime):
/usr/local/include/boost/graph/push_relabel_max_flow.hpp:707: typename
boost::property_traits<IndexMap>::value_type
boost::push_relabel_max_flow(Graph&, typename
boost::graph_traits<Graph>::vertex_descriptor, typename
boost::graph_traits<Graph>::vertex_descriptor, CapacityEdgeMap,
ResidualCapacityEdgeMap, ReverseEdgeMap, VertexIndexMap) [with Graph =
boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS,
VertexProps, EdgeProps>; CapacityEdgeMap =
boost::adj_list_edge_property_map<boost::directed_tag, double, double&, long
unsigned int, EdgeProps, double EdgeProps::*>; ResidualCapacityEdgeMap =
boost::adj_list_edge_property_map<boost::directed_tag, double, double&, long
unsigned int, EdgeProps, double EdgeProps::*>; ReverseEdgeMap =
boost::adj_list_edge_property_map<boost::directed_tag,
boost::detail::edge_desc_impl<boost::directed_tag, long unsigned int>,
boost::detail::edge_desc_impl<boost::directed_tag, long unsigned int>&, long
unsigned int, EdgeProps, boost::detail::edge_desc_impl<boost::directed_tag,
long unsigned int> EdgeProps::*>; VertexIndexMap =
boost::vec_adj_list_vertex_id_map<VertexProps, long unsigned int>; typename
boost::property_traits<IndexMap>::value_type = double; typename
boost::graph_traits<Graph>::vertex_descriptor = long unsigned int]: Assertion
`algo.is_optimal()' failed.
At the very end of the message you can see Assertion: algo.is_optimal() failed. I have absolutly no idea what this means.
In the source file (boost/graph/push_relabel_max_flow.hpp) it is defined as:
bool is_optimal() {
// check if mincut is saturated...
global_distance_update();
return get(distance, src) >= n;
}
I have googled it and didn't find anything. Did I pass my parameters the wrong way? Is it because I use double as capacity (although, if I recall correctly, the "documentation" described it as possible to use a double for the capacity)?
Also, I have discovered this sentence in the documentation:
The CapacityEdgeMap argument cap must map each edge in E to a positive
number, and each edge in E^T to 0.
What does the bold part mean? Does it mean that I have to set the capacity of all outgoing edges from the sink-vertex to 0?
You need to set the reverse edges' capacities to 0.
So you need:
auto edge = boost::edge(i,j,g).first;
g[edge].reverse = edges[i][j];
g[edges[i][j]].capacity = 0;
I'm not sure why this is though. Looking into read_dimacs.hpp I noticed that they create their reverse edges and give them 0 capacity. About 3/4 of the way down the page:
capacity[e1] = cap;
capacity[e2] = 0;
reverse_edge[e1] = e2;
reverse_edge[e2] = e1;
Likely without this constraint, the algorithm will try to treat these as normal edges. The portion of the documentation that you quote describes this, but it's not completely obvious.
There are several special requirements on the input graph and property
map parameters for this algorithm. First, the directed graph G=(V,E)
that represents the network must be augmented to include the reverse
edge for every edge in E. That is, the input graph should be Gin =
(V,{E U E^T}). The ReverseEdgeMap argument rev must map each edge in
the original graph to its reverse edge, that is (u,v) -> (v,u) for all
(u,v) in E. The CapacityEdgeMap argument cap must map each edge in E
to a positive number, and each edge in E^T to 0.
I think here E^T means transpose not target. You have to know that the transpose of a directed adjacency matrix is actually the reverse of the all the edges. That is why they say that the input graph is G = {V, E U E^T}. The edges plus the reverse ones that need to be added.
Side note: changing long to double in the push-relable example worked perfectly fine.

Boost graph library - adjacent_vertices function not found

I am trying to write an algorithm to (greedily) find the chromatic number of a graph. For this I need to be able to query the adjacent vertices of a given vertex.
My function is the following:
int Network::greedy_colouring() {
// create an undirected graph with the vertices and edges of the first one
UndirectedGraph g;
copy_graph(network, g);
int vertices_amount = num_vertices(g);
// Assign the first color to first vertex
std::map<std::string, int> vertex_colouring;
vertex_pair_iterators vp = vertices(g);
vertex_colouring[g[*vp.first].name] = 0;
++vp.first; // start from second vertex
for (; vp.first != vp.second; ++vp.first)
vertex_colouring[g[*vp.first].name] = -1;
// A temporary array to store the available colors. True
// value of available[cr] would mean that the color cr is
// assigned to one of its adjacent vertices
bool available[vertices_amount];
for (int cr = 0; cr < vertices_amount; cr++)
available[cr] = false;
// Assign colors to remaining V-1 vertices
vp = vertices(g); // reset to beginning
++vp.first; // start from second vertex
for (; vp.first != vp.second; ++vp.first) {
// Process all adjacent vertices and flag their colors
// as unavailable
for (std::pair<adjacency_it, adjacency_it> neighbours = boost::adjacent_vertices(g[*vp.first], g);
neighbours.first != neighbours.second; ++neighbours.first)
if (vertex_colouring[g[*neighbours.first].name] != -1)
available[vertex_colouring[g[*neighbours.first].name]] = true;
// Find the first available color
int cr;
for (cr = 0; cr < vertices_amount; cr++)
if (available[cr] == false)
break;
vertex_colouring[g[*vp.first].name] = cr; // Assign the found color
// Reset the values back to false for the next iteration
neighbours = boost::adjacent_vertices(g[*vp.first], g); // reset to beginning
for (; neighbours.first != neighbours.second; ++neighbours.first)
if (vertex_colouring[g[*neighbours.first].name] != -1)
available[vertex_colouring[g[*neighbours.first].name]] = false;
}
// print the result and find colour number
unsigned colour_number = 0;
for (std::map<std::string, int>::iterator it = vertex_colouring.begin(); it != vertex_colouring.end(); ++it) {
std::cout << "Vertex " << it->first << " ---> Color " << it->second << std::endl;
if (it->second > colour_number)
colour_number = it->second;
}
return colour_number;
}
The error I get is related to the call to:
std::pair<adjacency_it, adjacency_it> neighbours = boost::adjacent_vertices(g[*vp.first],g)
Which gives the following compile error: "error: no matching function for call to ‘boost::adjacency_iterator ... " (partial copy).
Commenting out the code related to the function adjacency lets it compile, so I am sure that this is the problem code.
Some typedefs that are being used in the function:
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS, Vertex, Edge > Graph;
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, Vertex, Edge > UndirectedGraph;
typedef std::pair<Vertex ,Vertex > vert_p;
typedef boost::graph_traits<Graph>::vertex_descriptor vertex_t;
typedef std::pair<boost::graph_traits<Graph>::edge_descriptor, bool> edge_t;
typedef boost::graph_traits<Graph>::in_edge_iterator in_edge_it;
typedef boost::graph_traits<Graph>::vertex_iterator vertex_iter;
typedef boost::graph_traits<Graph>::edge_iterator edge_iter;
typedef boost::property_map<Graph, boost::vertex_index_t>::type IndexMap;
typedef std::pair<vertex_iter, vertex_iter> vertex_pair_iterators;
typedef std::pair<in_edge_it, in_edge_it> edge_pair_iterators;
typedef boost::graph_traits<Graph>::adjacency_iterator adjacency_it;
Can anyone give me a clue what I am doing wrong?
Two issues:
the first argument needs to be a vertex descriptor, not the property bundle. Change
boost::adjacent_vertices(g[*vp.first], g)
into
boost::adjacent_vertices(*vp.first, g)
the return type is std::pair<adjacency_iterator, adjacency_iterator>. However, you defined adjacency_iterator as
typedef boost::graph_traits<Graph>::adjacency_iterator adjacency_it;
when it needs to be
typedef boost::graph_traits<UndirectedGraph>::adjacency_iterator adjacency_it;
Further notes:
It's easier to work with separate iterators instead of vp.first and vp.second (use boost::tie to assign both at once)
You have a "poisonous" unsigned value in your comparison, write it explicitly as
if(it->second > static_cast<int>(colour_number))
Or review the logic with possible -1 values in the map.
it's likely very inefficient to keep the colour map indexed by Vertex::name (which is a string). You should consider indexing by vertex_descriptor.
Now, since your vertex model uses vecS for the VertexContainer, you could actually use the fact that this descriptor is an integral index in the range [0, num_vertices(g)).
Therefore you can replace the map<> (which has bad memory locality) with a vector<int> (where the vertex descriptor is the vector index).
If you want to support other graph models, you can let the caller pass in an IndexMap that maps vertex-descriptor to similar consecutive indices. Lots of algorithms in the BGL use this approach.
Obviously, bool[] could (should) be std::bitset or even std::vector<bool>. Boost has the dynamic_bitset which is probably best here.
(I'd need to understand your algorithm a lot better. Perhaps a set of "taken" colour would be even better. And implemented as an unsorted contiguous collection for speed, unless you anticipate the number of colour to get big enough that an ordered/hash lookup would be faster (?!).
Always make your code selfcontained:
Live On Coliru
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/copy.hpp>
#include <iostream>
struct Vertex {
std::string name;
};
struct Edge {
};
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS, Vertex, Edge > Graph;
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::undirectedS, Vertex, Edge > UndirectedGraph;
Graph network;
int greedy_colouring() {
using namespace boost;
typedef boost::graph_traits<UndirectedGraph>::vertex_descriptor vertex_descriptor;
static_assert(is_integral<vertex_descriptor>::value, "IndexMap not provided yet TODO");
typedef boost::graph_traits<UndirectedGraph>::vertex_iterator vertex_iter;
typedef boost::graph_traits<UndirectedGraph>::adjacency_iterator adjacency_it;
// create an undirected graph with the vertices and edges of the first one
UndirectedGraph g;
copy_graph(network, g);
vertex_iter vit, vend;
tie(vit, vend) = vertices(g);
size_t const vertices_amount = num_vertices(g);
std::vector<int> vertex_colouring(vertices_amount, -1);
vertex_colouring[*vit] = 0; // Assign the first color to first vertex
// A temporary array to store the available colors.
// - available[cr]: assigned to one of its adjacent vertices
std::vector<bool> available(vertices_amount, false);
for (++vit; vit!=vend; ++vit)
{
// Process all adjacent vertices and flag their colors as unavailable
adjacency_it neighbour, neighbour_end;
for (tie(neighbour, neighbour_end) = adjacent_vertices(*vit, g); neighbour != neighbour_end; ++neighbour)
if (vertex_colouring[*neighbour] != -1)
available[vertex_colouring[*neighbour]] = true;
// Find the first available color
vertex_colouring[*vit] = distance(available.begin(), std::find(available.begin(), available.end(), false));
// Reset the values back to false for the next iteration
for (tie(neighbour, neighbour_end) = adjacent_vertices(*vit, g); neighbour != neighbour_end; ++neighbour)
if (vertex_colouring[*neighbour] != -1)
available[vertex_colouring[*neighbour]] = false;
}
// print the result and find colour number
for (vertex_descriptor v = 0; v < vertices_amount; ++v)
std::cout << "Vertex " << v << " ---> Color " << vertex_colouring[v] << std::endl;
return *std::max_element(vertex_colouring.begin(), vertex_colouring.end());
}
int main() { }

Fast way to look if edge is important for graphs connectivity

I have a set of edges E, and I want to know if I can safely remove edge i in E, meaning if I remove it from the graph, the graph should still be connected.
In my understanding that implies that edge i, has to lie on a circle.
The output should be a list of indices of all edges I can't remove.
The problem:
My different solutions seem to do the right thing, but are far too slow (inefficient).
One of my solutions was:
1. Loop through all edges i in E
2. Loop through all edges x in V
3. Add edge x to the graph (excluding edge i) until nodes of i are connected or end reached
4. If no connection possible, edge is not removable and added to the list
This way was way too slow.
I then decided to rewrite my code and use breadth-first-search to look if another path is possible without edge i.
I thought it would be performant enough, but it seems it's not. Either I have implemented in a very bad way or that's also the wrong algorithm for this task.
Here is the algorithm in the C++ code I have (removed some not important parts):
struct connection {
int a, b;
};
void expand(int x, connection *&arr, std::set<int> &exp, int size) {
for (int i = 0; i < size; i++) {
if (x == arr[i].a) {
exp.insert(arr[i].b);
}
else if (x == arr[i].b) {
exp.insert(arr[i].a);
}
}
return;
}
// recursive breadth-first-seach
bool BFSr(std::set<int> &group, std::set<int> &visited, int goal, connection *&arr, int size) {
if (group.empty()) return false;
if (group.find(goal) != group.end()) return true;
std::set<int> tempa;
for (std::set<int>::iterator it = group.begin(); it != group.end(); ++it) {
expand(*it, arr, tempa size);
}
for (std::set<int>::iterator it = visited.begin(); it != visited.end(); ++it) {
tempa.erase(*it);
}
tempb = visited;
tempb.insert(group.begin(), group.end());
return BFSr(tempa, tempb, goal, arr, size);
}
bool BFS(int start, int goal, connection *&arr, int size) {
std::set<int> tempa;
std::set<int> tempb;
tempa.insert(start);
return BFSr(tempa, tempb, goal, arr, size);
}
int main()
{
connection *arr = new connection[m];
connection *con = new connection[m - 1];
// fill arr with connections arr.a < arr.b ....
for (int j = 0; j < (m - 1); j++) {
con[j] = arr[j + 1];
}
// 1. edge for performance reasons extra
if (!BFS(arr[0].a, arr[0].b, con, (m - 1))) {
// connection is important therefore add to list
printf(" %d", 1);
}
// Look if nodes still connected after removing connection
for (int s = 1; s < m; s++) {
con[s - 1] = arr[s - 1];
if (!BFS(arr[s].a, arr[s].b, con, (m-1))) {
// connection is important therefore add to list
printf(" %d", s + 1);
}
}
printf("\n");
free(arr);
free(con);
return 0;
}
Do you know any solutions for me to make it faster, or do you know a better algorithm for my problem?
An edge whose deletion disconnects two connected components is called a bridge and there are linear-time algorithms for finding all the bridges in a graph (usually based on depth-first search). The Wikipedia article lists one of them (due to Tarjan) as an example. This paper also gives a simple algorithm for listing all the bridges in a graph and seems to be a bit simpler than Tarjan's algorithm.
Hope this helps!
Here is another version of your algorithm (I guess you will get industry standard optimization implementation of graph and various algorithm for free):
I am referring to this image as graph model.
Gist (from this post)
find articulation points
all points with single out-edge are
articulation points (boost graph won't return these)- these edges
are automatically bridging edges
for each articulation point-
loop over each outedge, if outedge already not bridging edge- then
remove the edge and check for graph components and add the edge back
again
At the end it will print Edge(a,g) connects components in graph
#include <iostream>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/biconnected_components.hpp>
#include <boost/graph/connected_components.hpp>
#include <functional>
#include <string>
#include <vector>
#include <unordered_map>
#include <unordered_set>
typedef boost::adjacency_list <boost::vecS, boost::vecS, boost::undirectedS> Graph;
typedef boost::graph_traits<Graph>::vertex_descriptor vertex_t;
typedef boost::graph_traits<Graph>::edge_descriptor edge_t;
// reference:
// http://lists.boost.org/boost-users/2005/08/13098.php
//
struct edge_t_hasher
{
std::size_t operator()(const edge_t& e) const
{
auto prop = e.get_property();
std::hash<decltype(prop)> hasher;
return hasher(prop);
}
};
typedef std::unordered_set<edge_t, edge_t_hasher> UnorderedBoostEdgeSet;
Graph getGraph()
{
Graph g;
vertex_t aVtx = boost::add_vertex(g);
vertex_t bVtx = boost::add_vertex(g);
vertex_t cVtx = boost::add_vertex(g);
vertex_t dVtx = boost::add_vertex(g);
vertex_t eVtx = boost::add_vertex(g);
vertex_t fVtx = boost::add_vertex(g);
vertex_t gVtx = boost::add_vertex(g);
vertex_t hVtx = boost::add_vertex(g);
vertex_t iVtx = boost::add_vertex(g);
boost::add_edge(dVtx, cVtx, g);
boost::add_edge(dVtx, bVtx, g);
boost::add_edge(cVtx, bVtx, g);
boost::add_edge(aVtx, bVtx, g);
boost::add_edge(bVtx, eVtx, g);
boost::add_edge(eVtx, fVtx, g);
boost::add_edge(aVtx, fVtx, g);
boost::add_edge(aVtx, gVtx, g);// edge connecting components
boost::add_edge(gVtx, iVtx, g);
boost::add_edge(gVtx, hVtx, g);
boost::add_edge(hVtx, iVtx, g);
return g;
}
UnorderedBoostEdgeSet bridgingEdgesForGraph(const Graph& graph)
{
UnorderedBoostEdgeSet bridgeEdges;
std::unordered_set<vertex_t> articulationVertices;
boost::articulation_points(graph, std::inserter(articulationVertices, articulationVertices.end()));
// add all the single connected vertices to the articulation vertices
auto vtxIters = boost::vertices(graph);
for (auto it = vtxIters.first, end = vtxIters.second; it != end; ++it)
{
if (boost::out_degree(*it, graph) == 1)
bridgeEdges.insert(*(boost::out_edges(*it, graph).first));
}
std::vector<vertex_t> componentsInGraph(boost::num_vertices(graph));
int numComponentsInGraph = boost::connected_components(graph, &componentsInGraph[0]);
// for each articulation vertex now get edges and check if removing that
// edge causes graph change in connected components
//
// copy the graph- so we can iterate over the outeges of vertices
// we will be fiddling with the copy- since the vtx descriptors are
// ints- they stay same across copy and removing edge operation
auto graph2 = graph;
for (auto vtx : articulationVertices)
{
auto outEdges = boost::out_edges(vtx, graph);
for (auto it = outEdges.first, end = outEdges.second; it != end; ++it)
{
auto edge = *it;
if (bridgeEdges.find(edge) != bridgeEdges.end())
continue;
// map this edge to graph2 edge- for removal and eventual addition
auto src = boost::source(edge, graph);
auto tgt = boost::target(edge, graph);
auto edge2 = boost::edge(src, tgt, graph2).first;
boost::remove_edge(edge2, graph2);
std::vector<vertex_t> componentsInGraph2(boost::num_vertices(graph2));
int numComponentsInGraph2 = boost::connected_components(graph2, &componentsInGraph2[0]);
// bridging edge- graph #components changed
if (numComponentsInGraph != numComponentsInGraph2)
bridgeEdges.insert(edge);
// add the edge back to graph2
boost::add_edge(src, tgt, graph2);
}
}
return bridgeEdges;
}
int main()
{
const Graph& graph = getGraph();
const auto& bridgingEdges = bridgingEdgesForGraph(graph);
const char* array = {"ABCDEFGHI"};
for (auto edge : bridgingEdges)
{
std::cout << "Edge(" << array[boost::source(edge, graph)] << ", " << array[boost::target(edge, graph)]
<< ") is a bridging edge" << std::endl;
}
return 0;
}
Meanwhile I found out how those special edges are called: Bridges.
And therefore I found a site giving an DFS algorithm for finding all bridges.
It's fast enough for my purposes.
DFS algorithm for finding Bridges in a undirected Graph
Thank you Sarang, your post made me find the correct search words for the site.

Removing edges temporarily from a boost graph

I have written an algorithm which does (some sort of) 'topological sorting' (not exact). This algorithm copies the given graph and then manipulates the copy (by removing edges). On a million node boost graph, if my algorithm takes 3.1 seconds, 2.19 seconds are consumed by copying the given graph into a new one.
Can I remove edges without actually removing them permanently e.g. sort of masking in boost::graph library? And when algorithm is done, I unmask all edges the graph regains it original state. I suspect this should make my algorithm run much faster.
Boost.Graph's filtered_graph seems a good fit for what you want. Unfortunately I really have no idea if it will perform better than your current approach (I suspect it will). If you decide to implement this approach I would love to hear about the results.
Example on LWS.
#include <iostream>
#include <tuple>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/filtered_graph.hpp>
#include <boost/graph/topological_sort.hpp>
#include <boost/unordered_set.hpp>
struct Vertex
{
Vertex(){}
Vertex(int val):name(val){}
int name;
};
typedef boost::adjacency_list<boost::vecS,boost::vecS,boost::directedS,Vertex> graph_type;
typedef boost::graph_traits<graph_type>::vertex_descriptor vertex_descriptor;
typedef boost::graph_traits<graph_type>::edge_descriptor edge_descriptor;
// A hash function for edges.
struct edge_hash:std::unary_function<edge_descriptor, std::size_t>
{
edge_hash(graph_type const& g):g(g){}
std::size_t operator()(edge_descriptor const& e) const {
std::size_t seed = 0;
boost::hash_combine(seed, source(e,g));
boost::hash_combine(seed, target(e,g));
//if you don't use vecS as your VertexList container
//you will need to create and initialize a vertex_index property and then use:
//boost::hash_combine(seed,get(boost::vertex_index, g, source(e,g)));
//boost::hash_combine(seed,get(boost::vertex_index, g, target(e,g)));
return seed;
}
graph_type const& g;
};
typedef boost::unordered_set<edge_descriptor, edge_hash> edge_set;
typedef boost::filtered_graph<graph_type,boost::is_not_in_subset<edge_set> > filtered_graph_type;
template <typename Graph>
void print_topological_order(Graph const& g)
{
std::vector<vertex_descriptor> output;
topological_sort(g,std::back_inserter(output));
std::vector<vertex_descriptor>::reverse_iterator iter=output.rbegin(),end=output.rend();
for(;iter!=end;++iter)
std::cout << g[*iter].name << " ";
std::cout << std::endl;
}
int main()
{
graph_type g;
//BUILD THE GRAPH
vertex_descriptor v0 = add_vertex(0,g);
vertex_descriptor v1 = add_vertex(1,g);
vertex_descriptor v2 = add_vertex(2,g);
vertex_descriptor v3 = add_vertex(3,g);
vertex_descriptor v4 = add_vertex(4,g);
vertex_descriptor v5 = add_vertex(5,g);
edge_descriptor e4,e5;
add_edge(v0,v1,g);
add_edge(v0,v3,g);
add_edge(v2,v4,g);
add_edge(v1,v4,g);
std::tie(e4,std::ignore) = add_edge(v4,v3,g);
std::tie(e5,std::ignore) = add_edge(v2,v5,g);
//GRAPH BUILT
std::cout << "Original graph:" << std::endl;
print_topological_order(g);
edge_hash hasher(g);
edge_set removed(0,hasher); //need to pass "hasher" in the constructor since it is not default constructible
filtered_graph_type fg(g,removed); //creates the filtered graph
removed.insert(e4); //you can "remove" edges from the graph by adding them to this set
removed.insert(e5);
std::cout << "Filtered Graph after \"removing\" 2 edges" << std::endl;
print_topological_order(fg);
removed.clear(); //clearing the set restores your original graph
std::cout << "Filtered Graph after resetting" << std::endl;
print_topological_order(fg);
}