Opened 18 years ago

Closed 18 years ago

#268 closed Bugs (Invalid)

incomplete connected components with disjoint_sets

Reported by: nobody Owned by: Douglas Gregor
Milestone: Component: graph
Version: None Severity:
Keywords: Cc:

Description

I am trying to understand why the order in which I add 
edges to an adjacency_list graph has some effect on 
the connected components I get using 
incremental_components.  Using the listing below, with 
Boost release 1.30.0 (also 1.31.0) with g++ 2.95 
(cygwin) I get the following:

> g++ -I./boost_1_31_0 -o ok -ftemplate-depth-40 
incremental-components-eg-bug.cpp

> ./ok

rank[0] = 0
rank[1] = 0
rank[2] = 0
rank[3] = 1
rank[4] = 0
parent[0] = 3
parent[1] = 3
parent[2] = 3
parent[3] = 3
parent[4] = 3
component 0 contains: 4 3 2 1 0

This is what I expect.  If I change the order in which I 
add edges to the graph, I get a different answer:

> g++ -I./boost_1_31_0 -DSHOWBUG -o bug -ftemplate-
depth-40 incremental-components-eg-bug.cpp

> ./bug

rank[0] = 0
rank[1] = 0
rank[2] = 1
rank[3] = 2
rank[4] = 0
parent[0] = 3
parent[1] = 2
parent[2] = 3
parent[3] = 3
parent[4] = 3
component 0 contains: 4 3 2 0

This is not what I expect.  The single connected 
component has lost a vertex.  But it should be the same 
graph, the only difference being the order in which I 
called add_edge().

Is this a bug or a misunderstanding on my part?  Any 
advice would be appreciated...

Jeff

#include <iostream>
#include <vector>
#include <algorithm>
#include <utility>
#include <boost/graph/adjacency_list.hpp>
#include <boost/pending/disjoint_sets.hpp>
#include <boost/graph/incremental_components.hpp>

int
main(int, char *[])
{
  using namespace boost;
  // Create a graph
  typedef adjacency_list < vecS, vecS, undirectedS > 
Graph;
  typedef graph_traits < Graph >::vertex_descriptor 
Vertex;
  const int N = 5;
  Graph G(N);
  add_edge(0, 3, G);
  add_edge(0, 4, G);
#ifndef SHOWBUG
  add_edge(1, 4, G);
  add_edge(1, 2, G);
#else
  add_edge(1, 2, G);
  add_edge(1, 4, G);
#endif

  // create the disjoint-sets object, which requires rank 
and parent vertex properties
  std::vector < Vertex > rank(num_vertices(G));
  std::vector < Vertex > parent(num_vertices(G));
  typedef graph_traits<Graph>::vertices_size_type* 
Rank;
  typedef Vertex* Parent;
  disjoint_sets < Rank, Parent > ds(&rank[0], &parent
[0]);

  // determine the connected components, storing the 
results in the disjoint-sets object
  initialize_incremental_components(G, ds);
  incremental_components(G, ds);
  for (unsigned int i = 0; i < rank.size(); ++i) {
    std::cout << "rank[" << i << "] = " << rank[i] << 
std::endl;
  }
  for (unsigned int i = 0; i < parent.size(); ++i) {
    std::cout << "parent[" << i << "] = " << parent[i] << 
std::endl;
  }

  typedef component_index < unsigned int >Components;
  Components components(parent.begin(), parent.end());
  for (Components::size_type i = 0; i < components.size
(); ++i) {
    std::cout << "component " << i << " contains: ";
    for (Components::value_type::iterator j = components
[i].begin();
         j != components[i].end(); ++j)
      std::cout << *j << " ";
    std::cout << std::endl;
  }

  return EXIT_SUCCESS;
}
 

Change History (2)

comment:1 by nobody, 18 years ago

Logged In: NO 

Sorry I forgot my e-mail:  kommers@alum.mit.edu

comment:2 by Douglas Gregor, 18 years ago

Status: assignedclosed
Logged In: YES 
user_id=249098

This is actually not a bug. The problem is that, before using 
component_index to figure out what components exist, one needs to 
perform a "find_set" on each vertex to compress the representation. For 
instance, the example code does this:

graph_traits<Graph>::vertex_iterator i,end;
for (boost::tie(i, end) = vertices(G); i != end; ++i)
  cout << "representative[" << *i << "] = " << 
    ds.find_set(*i) << endl;;
cout << endl;

Alternatively, one can use the "compress_sets" function in the disjoint 
sets data structure to do this more easily, e.g.,

  ds.compress_sets(vertices(g).first, vertices(g).second);

There is arguably a problem with the interface to incremental 
components because this is a subtle issue, but we should address that 
separately.
Note: See TracTickets for help on using tickets.