Boost connected components not working - c++

I'm having trouble getting boost's connected components algorithm working reliably. I want to use it to separate collections of 3D point data. I have a data set where there is are two obvious 'clusters' of 3D points separated by a large distance.
I create an undirected Boost graph object with bundled information which is a simple 'point' class, this contains an x, y and z property and a method to calculate distance of this point from another.
adjacency_list<vecS, vecS, undirectedS,Point> Graph;
I have a vector of point information (Point_dat) which I now transfer to vertices of the graph
for (size_t i = 0; i < Inter_dat.size(); i++)
{
// Create a new vertex for every element of the original data
add_vertex(Graph);
(Graph)[i] = Point_dat[i];
}
I now iterate through the vertices of the graph (in two loops) to calculate the distance from each vertex to each other vertex (I know there are more efficient ways of doing this but this is a first stab)
If the distance between two points is below a threshold, I add an edge between the two vertices.
typedef adjacency_list<vecS, vecS, undirectedS, Point>::vertex_iterator iterator;
std::pair<iterator, iterator> p = vertices(Graph);
for (iterator it = p.first; it != p.second; it++)
{
for (iterator it2 = it; it2 != p.second; it2++)
{
double thisdist = Graph[*it].Distance(Graph[*it2]);
if (thisdist < distance_thresh & thisdist > 0)
{
add_edge(*it,*it2, Graph);
}
}
}
I then calculate the connected components.
std::vector<int> comp(num_vertices(Graph));
int num = connected_components(Graph, &comp[0]);
The problem is, the data isn't being separated into the two clusters. The main cluster still contains some of the second. In fact if I re-run the analysis using the largest component (as selected by Boost) it finds a number of new components.
Why isn't it working? Do I need to add different parameters?
UPDATE: To give more context, I'm trying to implement a process I developed in Matlab in C++. To try and see the root of the problem I saved the edges of my graph
std::ofstream myfile("D:\\edges.txt");
auto q = edges(Graph);
for (auto it = q.first; it != q.second; ++it)
myfile << *it << std::endl;
myfile.close();
and imported the resulting data into Matlab. I then used Matlab's connected components process on this edge information and it gave me exactly the right answer. It seems that I'm setting the graph up correctly but Boosts connected components isn't giving me the right answer.

Related

Have a DAG graph in boost without vertex descriptor invalidation

I am trying to implement a direct acyclic graph with the boost::adjacency_list<> class. For that I re-implemented the idea from this question: boost graph that doesn't allow circular references
using Graph = boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS>;
using Vertex = Graph::vertex_descriptor;
With that I was able to call the topological_sort after each add_edge to confirm I have a DAG:
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/topological_sort.hpp>
#include <boost/iterator/function_output_iterator.hpp>
int main()
{
Graph g;
// 1. build a graph structure
auto v1 = boost::add_vertex(g);
auto v2 = boost::add_vertex(g);
auto v3 = boost::add_vertex(g);
boost::add_edge(v1, v2, g);
boost::topological_sort(g, boost::make_function_output_iterator([](int) {}));
boost::add_edge(v2, v3, g);
boost::topological_sort(g, boost::make_function_output_iterator([](int) {}));
}
An additional requirement I have is to enable some undo/redo support on actions I do on my graph. One of the operation could be to remove a vertex and deleting all incoming and outgoing edges from the specified vertex. A sample code could look like this:
static void Print(const Graph& g)
{
std::cout << "Vertices: " << std::endl;
for (auto vertices = boost::vertices(g); vertices.first != vertices.second; ++vertices.first)
{
std::cout << *vertices.first << std::endl;
}
std::cout << "Edges: " << std::endl;
for (auto edges = boost::edges(g); edges.first != edges.second; ++edges.first)
{
auto edgeDescriptor = *edges.first;
std::cout << edgeDescriptor.m_source << "->" << edgeDescriptor.m_target << std::endl;
}
std::cout << std::endl;
}
int main()
{
Graph g;
// 1. build a graph structure
auto v1 = boost::add_vertex(g);
auto v2 = boost::add_vertex(g);
auto v3 = boost::add_vertex(g);
boost::add_edge(v1, v2, g);
boost::add_edge(v2, v3, g);
Print(g);
// 2. prepare for deletion of v2
std::vector<Vertex> outVertices;
for(auto vertices = boost::adjacent_vertices(v2, g); vertices.first != vertices.second; ++vertices.first)
{
outVertices.push_back(*vertices.first);
}
std::vector<Vertex> inVertices;
for (auto vertices = boost::inv_adjacent_vertices(v2, g); vertices.first != vertices.second; ++vertices.first)
{
inVertices.push_back(*vertices.first);
}
// 3. delete v2
boost::clear_vertex(v2, g);
boost::remove_vertex(v2, g);
Print(g);
// 4 undo the operation
v2 = boost::add_vertex(g);
for(auto& outVertex : outVertices)
{
boost::add_edge(v2, outVertex, g);
}
for (auto& inVertex : inVertices)
{
boost::add_edge(inVertex, v2, g);
}
Print(g);
}
Output:
Vertices:
0
1
2
Edges:
0->1
1->2
Vertices:
0
1
Edges:
Vertices:
0
1
2
Edges:
2->2
0->2
This doesn't work of course because the remove_vertex call invalidates my earlier saved vertex_descriptors. A solution I found for this problem was how to call "boost::remove_vertex" without re-indexing the vertices?
Here it proposed to use a list instead of a vector for saving the vertices and therefore the vertex_descriptors do not get invalidated.
using Graph = boost::adjacency_list<boost::listS, boost::listS, boost::bidirectionalS>;
This does work as expected and gives the desired output where the undo works:
Vertices:
000001DD1902AC90
000001DD19028F70
000001DD19028D80
Edges:
000001DD1902AC90->000001DD19028F70
000001DD19028F70->000001DD19028D80
Vertices:
000001DD1902AC90
000001DD19028D80
Edges:
Vertices:
000001DD1902AC90
000001DD19028D80
000001DD19028F70
Edges:
000001DD19028F70->000001DD19028D80
000001DD1902AC90->000001DD19028F70
The problem I have now is that the topological_sort does not compile anymore with my new Graph definition. For full error message: https://godbolt.org/z/WKjeK3ddP
The question I have (or the problem I am trying to solve is) how can I implement a direct acyclic graph in boost without invalidating the vertex_descriptors while removing vertices and having the topological_sort possibility?
Or maybe not that specific: How to impelement a DAG with boost on where I can enable/implement undo/redo possibilities?
Excellent question.
The topological sort
It fails because there's no longer an implicit vertex index. Topological sort requires it to get a default color map, so things that work:
std::map<Vertex, int> index;
for (auto v : boost::make_iterator_range(vertices(g)))
index.emplace(v, index.size());
boost::topological_sort(
g, boost::make_function_output_iterator([](Vertex) {}),
boost::vertex_index_map(boost::make_assoc_property_map(index)));
Or, just provide a color map directly, which is probably a better idea:
std::map<Vertex, boost::default_color_type> colors;
boost::topological_sort(
g, boost::make_function_output_iterator([](Vertex) {}),
boost::color_map(boost::make_assoc_property_map(colors)));
There's some more thinking behind this problem here:
What is required for a custom BGL graph to work with topological sort?
Big Picture
The thing I like most about your question is that after a very high level of detailed analysis, you still go back and wonder whether there's something else. This is you, trying to avoid tunnel vision or X/Y problem.
Or maybe not that specific: How to impelement a DAG with boost on where I can enable/implement undo/redo possibilities?
To be completely honest, I think you're shoe-horning a very specific datastructure into something BGL should have. And that's just improbable. I'd reverse the design priorities.
BGL is expressly designed to be almost completely generic. This means you can use the algorithms on your own data structures given the right instrumentation/adaptation.
Your requirements feel more like a versioned tree/forest. A Sean-Parent-style tree with shared_ptr<const T> nodes seems more applicable.
A quick demonstration of the concept, focusing on Copy-On-Write deep modification of sub-trees: Transforming trees in C++
A more advanced strategy could be e.g. splay trees, but I'd have to freshen up on theory myself before recommening/implementing anything like that.
Now, all of this doesn't really touch on any requirements for graph algorithms. The linked answer above incidentally shows topological sort on a custom graph model, so you can have a look and see whether that looks viable. At some point you might decide it's better to "just implement" BFS for your own datastructure.

How do you access the coordinates in a boost graph topology layout?

I'm trying to create an application which displays a simple graph and since I'm using boost::graph for the underlying data structure, I'd like to use the layouting algorithms available in the library as well.
The answer presented here explains how to use a layout algorithm within the boost library to lay out vertices of graph:
How does the attractive force of Fruchterman Reingold work with Boost Graph Library
But sadly it does not explain how - after the layout has been calculated - the coordinates of the vertices can actually be accessed. Even though we get a vector of positions (or rather points), the float components are private, so that doesn't help. The boost::graph documentation also doesn't address this topic.
So how can simple (X,Y) coordinates of each vertex be retrieved after a layouting algorithm has been applied?
After reviewing the boost graph source code it turned out that this isn't so hard after all.
We can use a property map to iterate over the PositionsMap and the [] operator to access the coordinates:
template<typename Graph, typename Positions>
void print_positions(const Graph &g, const Positions &positions) {
auto index_map = boost::get(boost::vertex_index, graph);
using PropertyMap = boost::iterator_property_map<Positions::iterator, decltype(index_map)>;
PropertyMap position_map(positions.begin(), index_map);
BGL_FORALL_VERTICES(v, graph, Graph) {
Position pos = position_map[v];
cout << v << ": " << pos[0] << "|" << pos[1] << endl;
}
}

Dynamically adding to a graph data structure

Let me first state that I just want direction, not necessarily actual code, unless a small snippet is the only way to get the point across.
I need to create a DIRECTED graph data structure using an adjacency list or matrix in C++, and add vertices/edges from standard input, which means dynamically.
I think I'd be able to create a graph fine if I was able to instantiate a set of Vertices first, then create edges and add them to the graph, but I don't understand how it is possible to add an edge which contains a vertex that hasn't been instantiated yet.
for example, the first line from standard input reads:
Miami -> New York/1100 -> Washington/1000 -> albuquerque/1700
How am I supposed to add an edge from Miami to New York if the New York vertex hasn't been added to the graph yet?
Thanks for the direction everyone!
how it is possible to add an edge which
contains a vertex that hasn't been instantiated yet.
Simple: instantiate it..
I do not see any issue with this. Assume V to be the vertex set seen so far. V is initially empty. As you read the input x->y, you get its end points (x and y). If any one of them is not instantiated (i.e., not in V), you instantiate it and add it to the vertex set.
Another way to look to it: imagine we are defining the graph by its edge set E. By definition any edge is a pair of vertices which in turn defines the vertex set of the graph.
How about you resize the adjacency list each time a new unique node comes in? You can maintain a set of unique node values and use its size to adjust the size of the adjacency list each time you have to add a node. Below is a some code that does the same.
class Graph
{
public:
// Add links in the graph
void addLink(int id1, int id2){
// Add to hashset
uniqueNodes.insert(id1);
uniqueNodes.insert(id2);
// Resize on the adjacency list based on how many nodes exists in the uniqueNodes set
adjList.resize(uniqueNodes.size());
// Make the connections assuming undirected graph
adjList[id1].push_back(id2);
adjList[id2].push_back(id1);
}
// Print the graph
void printGraph(){
for(int i = 0; i < adjList.size(); i++){
cout << i << ":";
for(auto it = adjList[i].begin(); it != adjList[i].end(); it++)
cout << *it << "->";
cout << "NULL\n";
}
}
private:
// Adjacency list for the graph
vector<list<int>> adjList;
// Hashset to help define the size of the adjacency list as nodes come in
set<int> uniqueNodes;
};

Segmentation fault raised from stl_list.h : 731

I've got a very weird segmentation fault with my code. Actually, when I run my executable, it aborts. When I run it with gdb, it also aborts. But when I run it with valgrind, it terminates successfully and gives me the correct result.
That's for the introduction. Now here's a description of my algorithm. What I want to do is extracting the subsurface of a mesh that looks similar to another one, given a certain threshold, r. The key idea of my algorithm is looping on each point of the mesh (let's say, p). If I find a point of the reference mesh included in the sphere of center p and radius r, I don't do anything and I go to the next point. Otherwise, I delete the point and every element of the mesh including it (which means, edges, and triangles of the mesh to which the point belongs).
Now I jump to a short description of my classes. I have four classes to represent elements of the mesh :
Vertex. This class includes two attributes (I don't mention the getters and setters) : a position and a list, belongsTo, which contains pointers to all of the edges to which the vertex belongs.
Edge. This class includes three attributes : the two vertices delimiting the edge, and a list, also called belongsTo, wichi contains pointers to all of the triangles to which an edge belongs.
Triangle. This class includes three attributes : the three edges delimiting the triangle, and a normal vector (I mentioned it, but it doesn't really matter here : I only use it to render the triangle using OpenGL).
And, finally :
Mesh. This class includes a vector v of Vertex objets, a vector e of Edge objects and finally a vector t of Triangles.
Now here is the prototype of my function :
class Mesh {
...
void extractIdenticalSubsurfaces(Mesh *a, double threshold);
}
As you may have already guessed, this function takes two parameters into account : the reference mesh and a threshold (actually the radius of the sphere I build to determine if I have to delete the point from the mesh). Is everything clear ?
Description of my algorithm : I loop on each point of the mesh (on each point of v, actually). For each point, I build a sphere of radius 'threshold' centered in this point and I verify it there is a point of a in this sphere. If I find a point, I don't do anything. Otherwise, I delete it from v.
But before doing that, I have some operations to do.
Indeed, I have to loop on each edge to which the point belongs (using the list 'belongsTo') and then on each triangle to which the point belongs (once again using the list 'belongsTo').
For each of these triangles, I loop on the three edges delimiting it and I delete the address of the triangle from the list of edges to which this triangle belongs (because I want to delete this triangle, so I have to anticipate).
Once it's done, I do the same with the current edge of the loop : I delete the adress of the edge from the 'belongsTo' list associated to the two vertices of the edge.
But I also have to delete both suppressed edges and triangles from the vectors e and t !
It may seem not so easy to understand (I think it's better if you have a sheet of paper just in front of you and if you draw a mesh and consider a point that you want to suppress) but I am quite sure of the exactitude of this algorithm : actually, when I run my program with valgrind, it displays the good sub-mesh on my screen.
But the problem is that if I don't use valgrind, it fails.
Here's the error message displayed by gdb :
Program received signal SIGSEGV, Segmentation fault.
0x0000000000406f3a in std::list<Triangle*, std::allocator<Triangle*> >::begin (this=0x39) at /usr/include/c++/4.6/bits/stl_list.h:731
731 { return iterator(this->_M_impl._M_node._M_next); }
The backtrace :
(gdb) bt
#0 0x0000000000406f3a in std::list<Triangle*, std::allocator<Triangle*> >::begin (this=0x39) at /usr/include/c++/4.6/bits/stl_list.h:731
#1 0x0000000000406e37 in std::list<Triangle*, std::allocator<Triangle*> >::remove (this=0x39, __value=#0x7fffffffc860) at /usr/include/c++/4.6/bits/list.tcc:242
#2 0x00000000004062a1 in Edge::deleteTriangle (this=0x21, t=0xcf4ed0) at elements.cpp:109
#3 0x0000000000408aa4 in Mesh::extractIdenticalSubsurfaces (this=0xc14b10, a=0xc0f900, threshold=0) at mesh.cpp:174
#4 0x0000000000404687 in Scene::extractIdenticalSurfaces (this=0xbad8c0, threshold=0) at scene.cpp:36
#5 0x00000000004051c6 in Viewer::keyPressEvent (this=0x7fffffffde80, e=0x7fffffffd020) at viewer.cpp:104
...
As you can see, getting an error is logical here, because the system seems to try to apply the 'deleteTriangle' method on an object whose 'this' address is 0x21. But what I am wondering is, how on earth can it be 0x21. I tried to dislay the adresses of the pointers to edges and vertices included in all of the Triangles and Edges objects, and they seems to be correct (after all I can display all of the elements of my mesh using OpenGL, so...). But at a moment this 0x21 comes in and I definitely don't know why.
This is my code :
void Mesh::extractIdenticalSubsurfaces (Mesh *a, double threshold) {
vector<Vertex *>::iterator it1 = v.begin() ;
while (it1 != v.end()) {
if (a->emptySphere((*it1), threshold)) {
list<Edge *> edgesToDelete = list<Edge *>();
list<Triangle *> trianglesToDelete = list<Triangle *>();
for (list<Edge *>::iterator it2 = (*it1)->getIteratorBegin() ; it2 != (*it1)->getIteratorEnd() ; it2++) {
for (list<Triangle *>::iterator it3 = (*it2)->getIteratorBegin() ; it3 != (*it2)->getIteratorEnd() ; it3++) {
Triangle *argT = (*it3);
(*it3)->getFirstEdge()->deleteTriangle(argT);
(*it3)->getSecondEdge()->deleteTriangle(argT);
(*it3)->getThirdEdge()->deleteTriangle(argT);
trianglesToDelete.push_back(argT);
}
Edge *argE = (*it2);
(*it2)->getFirstVertex()->deleteEdge(argE);
(*it2)->getSecondVertex()->deleteEdge(argE);
edgesToDelete.push_back(argE);
}
edgesToDelete.unique();
trianglesToDelete.unique();
vector<Edge *>::iterator it4 = e.begin();
while (it4 != e.end()) {
bool isEqual = false;
for (list<Edge *>::iterator it5 = edgesToDelete.begin() ; it5 != edgesToDelete.end() ; it5++) {
if ((*it4) == (*it5)) {
isEqual = true;
edgesToDelete.erase(it5);
break;
}
}
if (isEqual) {
e.erase(it4);
} else {
it4++;
}
}
vector<Triangle *>::iterator it6 = t.begin();
while (it6 != t.end()) {
bool isEqual = false;
for (list<Triangle *>::iterator it7 = trianglesToDelete.begin() ; it7 != trianglesToDelete.end() ; it7++) {
if ((*it6) == (*it7)) {
isEqual = true;
trianglesToDelete.erase(it7);
break;
}
}
if (isEqual) {
t.erase(it6);
} else {
it6++;
}
}
v.erase(it1);
} else {
it1++;
}
}
}
(Well, not very pretty sometimes, I agree but this isn't the subject of my question (on first sight))
So, do you have any idea of why I get this error ?

How to draw a polygon in C++ such that the lines do not intersect?

I need to draw a polygon in C++. I set random points in vector and then connect them via lines. But sometimes those lines intersect and i get something like this.
Is there any formula or something like that, so that the lines wouldn't cross?
Here is part of the code:
void draw_picture(Canvas & canvas) {
PairXY a,b,c,d,e;
int k;
vector <PairXY> vertex;
vertex.push_back(PairXY(drandom(k),drandom(k)));
vertex.push_back(PairXY(drandom(k),drandom(k)));
vertex.push_back(PairXY(drandom(k),drandom(k)));
vertex.push_back(PairXY(drandom(k),drandom(k)));
vertex.push_back(PairXY(drandom(k),drandom(k)));
vector <PairXY>::const_iterator iter;
iter = vertex.begin();
a=*iter;
iter = vertex.begin()+1;
b=*iter;
iter = vertex.begin()+2;
c=*iter;
iter = vertex.begin()+3;
d=*iter;
iter = vertex.begin()+4;
e=*iter;
Line l1(a,b);
draw_line(l1,canvas);
Line l2(b,c);
draw_line(l2,canvas);
Line l3(c,d);
draw_line(l3,canvas);
Line l4(d,e);
draw_line(l4,canvas);
Line l5(e,a);
draw_line(l5,canvas);
}
Sounds like you want a convex hull.
As far as calculating them goes, you have several options.
I've had good luck with the monotone chain algorithm.
It sounds like what you are probably looking for is a "Simple" (as opposed to "Complex") Polygon:
http://en.wikipedia.org/wiki/Simple_polygon
There's not necessarily a unique solution to that:
Sort point list into polygon
This is why the ordering of points or path segments typically matters in polygon drawing engines. If you are so inclined--however--you can find at least one non-complex polygon for a set of points:
http://www.computational-geometry.org/mailing-lists/compgeom-announce/2003-March/000727.html
http://www.computational-geometry.org/mailing-lists/compgeom-announce/2003-March/000732.html
Others have pointed out your code is repetitive as written. You also don't define k in the excerpt you shared, and it's better to use a plural term for a vector of objects ("vertices") rather than one suggesting it is singular ("vertex"). Here's one fairly simple-to-understand set of changes that should generalize to any number of vertices:
void draw_picture(Canvas & canvas, int k, int numVertices = 5) {
vector<PairXY> vertices;
for (int index = 0; index < numVertices; index++) {
vertices.push_back(PairXY(drandom(k),drandom(k)));
}
vector<PairXY>::const_iterator iter = vertices.begin();
while (iter != vertices.end()) {
PairXY startPoint = *iter;
iter++;
if (iter == vertices.end()) {
Line edgeLine (startPoint, vertices[0]);
draw_line(edgeLine, canvas);
} else {
Line edgeLine (startPoint, *iter);
draw_line(edgeLine, canvas);
}
}
}
There are a lot of ways to manage iterations in C++, although many of them are more verbose than their counterparts in other languages. Recently a nice range-based for loop was added in C++11, but your build environment may not support it yet.
sort the array before drawing it
Find the left most point
than go CCW from there
ie
leftmost where point y < first point y until none found
rightmost point until none found