Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 131 additions & 0 deletions test/biconnected_components_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,109 @@ bool test_graph(Graph& g)
return any_errors;
}


template < typename Graph, typename Vertex >
void check_components_index_for_multi_edges(const Graph& g, const std::vector< Vertex >& art_points)
{
std::vector< int > components(num_vertices(g));
int basic_comps = connected_components(g,
make_iterator_property_map(
components.begin(), get(vertex_index, g), int()));

std::map<std::pair<std::size_t, std::size_t>, std::size_t> edge_component_map;

bool multiple_edges_are_in_same_component = true;

typename graph_traits<Graph>::edge_iterator ei, ei_end;
for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) {
// Create canonical representation of edge (ordered pair)
std::pair<std::size_t, std::size_t> edge(source(*ei, g), target(*ei, g));
std::size_t component = g[*ei].component;

// This is a multi-edge if we've seen the same vertex pair before
// All parallel edges between the same vertices must have the same component index
if (edge_component_map.count(edge)) {
std::size_t expected_component = edge_component_map.at(edge);
if (expected_component != component)
multiple_edges_are_in_same_component = false;
}
else {
edge_component_map[edge] = component;
}

}

BOOST_TEST(multiple_edges_are_in_same_component == true);

if (!multiple_edges_are_in_same_component)
{
std::cerr << "ERROR!" << std::endl;
std::cerr << "\tComputed: \n";
std::size_t multiedge_component_index;
for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei)
std::cout << (char)(source(*ei, g) + 'A') << " -- "
<< (char)(target(*ei, g) + 'A')
<< " " << g[*ei].component << "\n";

std::cout << std::endl << "\tExpected: \n";
for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei)
{
std::pair<std::size_t, std::size_t> edge(source(*ei, g), target(*ei, g));

// Print source and target vertices and expected component index
std::cout << (char)(source(*ei, g) + 'A') << " -- "
<< (char)(target(*ei, g) + 'A')
<< " " << (char)('0' + edge_component_map[edge])
<< "\n";
}
std::cout << std::endl;
any_errors = true;
}
else
std::cout << "OK." << std::endl;
}

/// @brief Verify that all edges in biconnected components consisting only of multi-edges have valid EdgeProperty values
bool test_graph_with_multi_edges(Graph& g)
{ // Returns false on failure
std::vector< Vertex > art_points;

std::cout << "Computing biconnected components & articulation points... ";
std::cout.flush();

std::size_t num_comps = biconnected_components(
g, get(&EdgeProperty::component, g), std::back_inserter(art_points))
.first;

std::cout << "done.\n\t" << num_comps << " biconnected components.\n"
<< "\t" << art_points.size() << " articulation points.\n"
<< "\tTesting edge properties of multi-edges ...";
std::cout.flush();

check_components_index_for_multi_edges(g, art_points);

if (any_errors)
{
std::ofstream out("biconnected_components_on_multiedges_test_failed.dot");

out << "graph A {\n"
<< " node[shape=\"circle\"]\n";

for (std::size_t i = 0; i < art_points.size(); ++i)
{
out << art_points[i] << " [ style=\"filled\" ];" << std::endl;
}

graph_traits< Graph >::edge_iterator ei, ei_end;
for (boost::tie(ei, ei_end) = edges(g); ei != ei_end; ++ei)
out << source(*ei, g) << " -- " << target(*ei, g) << "[label=\""
<< g[*ei].component << "\"]\n";
out << "}\n";
}

return any_errors;
}

int main(int argc, char* argv[])
{
std::size_t n = 100;
Expand Down Expand Up @@ -150,5 +253,33 @@ int main(int argc, char* argv[])
return 1;
}

// Test case: Multiple edges forming biconnected components
// This test verifies that parallel edges (multi-edges) within biconnected components
// are correctly assigned the same component index
{
Graph g(5);

// block of parallel edges
add_edge(0, 1, g);
add_edge(0, 1, g);
add_edge(0, 1, g);

// bridge
add_edge(1, 2, g);

// block of parallel edges
add_edge(2, 3, g);
add_edge(2, 3, g);
add_edge(2, 3, g);

// another bridges
add_edge(3, 4, g);
add_edge(4, 5, g);

if (test_graph_with_multi_edges(g))
return 1;

}

return boost::report_errors();
}
Loading