sl@0: //======================================================================= sl@0: // Copyright (c) 2005 Aaron Windsor sl@0: // sl@0: // Distributed under the Boost Software License, Version 1.0. sl@0: // (See accompanying file LICENSE_1_0.txt or copy at sl@0: // http://www.boost.org/LICENSE_1_0.txt) sl@0: // sl@0: //======================================================================= sl@0: sl@0: /* sl@0: * © Portions copyright (c) 2006-2007 Nokia Corporation. All rights reserved. sl@0: */ sl@0: sl@0: #include sl@0: sl@0: #include // for std::cout sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #ifdef __SYMBIAN32__ sl@0: #include "std_log_result.h" sl@0: #define LOG_FILENAME_LINE __FILE__, __LINE__ sl@0: #endif sl@0: using namespace boost; sl@0: sl@0: typedef adjacency_list > undirected_graph; sl@0: sl@0: typedef adjacency_list > undirected_list_graph; sl@0: sl@0: typedef adjacency_matrix > undirected_adjacency_matrix_graph; sl@0: sl@0: sl@0: template sl@0: struct vertex_index_installer sl@0: { sl@0: static void install(Graph& g) {} sl@0: }; sl@0: sl@0: sl@0: template <> sl@0: struct vertex_index_installer sl@0: { sl@0: static void install(undirected_list_graph& g) sl@0: { sl@0: typedef graph_traits::vertex_iterator vertex_iterator_t; sl@0: typedef graph_traits::vertices_size_type v_size_t; sl@0: sl@0: vertex_iterator_t vi, vi_end; sl@0: v_size_t i = 0; sl@0: for(tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi, ++i) sl@0: put(vertex_index, g, *vi, i); sl@0: } sl@0: }; sl@0: sl@0: sl@0: sl@0: template sl@0: void complete_graph(Graph& g, int n) sl@0: { sl@0: //creates the complete graph on n vertices sl@0: typedef typename graph_traits::vertex_iterator vertex_iterator_t; sl@0: sl@0: g = Graph(n); sl@0: vertex_iterator_t vi, vi_end, wi; sl@0: tie(vi,vi_end) = vertices(g); sl@0: for(tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi) sl@0: { sl@0: wi = vi; sl@0: ++wi; sl@0: for(; wi != vi_end; ++wi) sl@0: add_edge(*vi,*wi,g); sl@0: } sl@0: } sl@0: sl@0: sl@0: sl@0: template sl@0: void gabows_graph(Graph& g, int n) sl@0: { sl@0: //creates a graph with 2n vertices, consisting of the complete graph sl@0: //on n vertices plus n vertices of degree one, each adjacent to one sl@0: //vertex in the complete graph. without any initial matching, this sl@0: //graph forces edmonds' algorithm into worst-case behavior. sl@0: sl@0: typedef typename graph_traits::vertex_iterator vertex_iterator_t; sl@0: sl@0: g = Graph(2* n); sl@0: sl@0: vertex_iterator_t vi, vi_end, ui, ui_end, halfway; sl@0: sl@0: tie(ui,ui_end) = vertices(g); sl@0: sl@0: halfway = ui; sl@0: for(int i = 0; i < n; ++i) sl@0: ++halfway; sl@0: sl@0: sl@0: while(ui != halfway) sl@0: { sl@0: vi = ui; sl@0: ++vi; sl@0: while (vi != halfway) sl@0: { sl@0: add_edge(*ui,*vi,g); sl@0: ++vi; sl@0: } sl@0: ++ui; sl@0: } sl@0: sl@0: tie(ui,ui_end) = vertices(g); sl@0: sl@0: while(halfway != ui_end) sl@0: { sl@0: add_edge(*ui, *halfway, g); sl@0: ++ui; sl@0: ++halfway; sl@0: } sl@0: sl@0: } sl@0: sl@0: sl@0: sl@0: template sl@0: void matching_test(std::size_t num_v, const std::string& graph_name) sl@0: { sl@0: typedef typename property_map::type vertex_index_map_t; sl@0: typedef vector_property_map< typename graph_traits::vertex_descriptor, vertex_index_map_t > mate_t; sl@0: typedef typename graph_traits::vertex_iterator vertex_iterator_t; sl@0: typedef typename graph_traits::vertex_descriptor vertex_descriptor_t; sl@0: typedef typename graph_traits::vertices_size_type v_size_t; sl@0: sl@0: const std::size_t double_num_v = num_v * 2; sl@0: sl@0: bool all_tests_passed = true; sl@0: sl@0: //form the complete graph on 2*n vertices; the maximum cardinality matching, greedy matching, sl@0: //and extra greedy matching should all be the same - a matching of size n. sl@0: sl@0: Graph g(double_num_v); sl@0: complete_graph(g,double_num_v); sl@0: sl@0: vertex_index_installer::install(g); sl@0: sl@0: mate_t edmonds_mate(double_num_v); sl@0: mate_t greedy_mate(double_num_v); sl@0: mate_t extra_greedy_mate(double_num_v); sl@0: sl@0: //find a maximum cardinality matching using edmonds' blossom-shrinking algorithm, starting sl@0: //with an empty matching. sl@0: bool edmonds_result = sl@0: matching < Graph, mate_t, vertex_index_map_t, sl@0: edmonds_augmenting_path_finder, empty_matching, maximum_cardinality_matching_verifier> sl@0: (g,edmonds_mate, get(vertex_index,g)); sl@0: sl@0: BOOST_CHECK (edmonds_result); sl@0: if (!edmonds_result) sl@0: { sl@0: std::cout << "Verifier reporting a problem finding a perfect matching on" << std::endl sl@0: << "the complete graph using " << graph_name << std::endl; sl@0: all_tests_passed = false; sl@0: } sl@0: sl@0: //find a greedy matching sl@0: bool greedy_result = sl@0: matching sl@0: (g,greedy_mate, get(vertex_index,g)); sl@0: sl@0: BOOST_CHECK (greedy_result); sl@0: if (!greedy_result) sl@0: { sl@0: std::cout << "Verifier reporting a problem finding a greedy matching on" << std::endl sl@0: << "the complete graph using " << graph_name << std::endl; sl@0: all_tests_passed = false; sl@0: } sl@0: sl@0: //find an extra greedy matching sl@0: bool extra_greedy_result = sl@0: matching sl@0: (g,extra_greedy_mate,get(vertex_index,g)); sl@0: sl@0: BOOST_CHECK (extra_greedy_result); sl@0: if (!extra_greedy_result) sl@0: { sl@0: std::cout << "Verifier reporting a problem finding an extra greedy matching on" << std::endl sl@0: << "the complete graph using " << graph_name << std::endl; sl@0: all_tests_passed = false; sl@0: } sl@0: sl@0: //as a sanity check, make sure that each of the matchings returned is a valid matching and has sl@0: //1000 edges. sl@0: sl@0: bool edmonds_sanity_check = sl@0: is_a_matching(g,edmonds_mate) && matching_size(g,edmonds_mate) == num_v; sl@0: sl@0: BOOST_CHECK (edmonds_sanity_check); sl@0: if (edmonds_result && !edmonds_sanity_check) sl@0: { sl@0: std::cout << "Verifier okayed edmonds' algorithm on the complete graph, but" << std::endl sl@0: << "the matching returned either wasn't a valid matching or wasn't" << std::endl sl@0: << "actually a maximum cardinality matching." << std::endl; sl@0: all_tests_passed = false; sl@0: } sl@0: sl@0: bool greedy_sanity_check = sl@0: is_a_matching(g,greedy_mate) && matching_size(g,greedy_mate) == num_v; sl@0: sl@0: BOOST_CHECK (greedy_sanity_check); sl@0: if (greedy_result && !greedy_sanity_check) sl@0: { sl@0: std::cout << "Verifier okayed greedy algorithm on the complete graph, but" << std::endl sl@0: << "the matching returned either wasn't a valid matching or wasn't" << std::endl sl@0: << "actually a maximum cardinality matching." << std::endl; sl@0: all_tests_passed = false; sl@0: } sl@0: sl@0: bool extra_greedy_sanity_check = sl@0: is_a_matching(g,extra_greedy_mate) && matching_size(g,extra_greedy_mate) == num_v; sl@0: sl@0: BOOST_CHECK (extra_greedy_sanity_check); sl@0: if (extra_greedy_result && !extra_greedy_sanity_check) sl@0: { sl@0: std::cout << "Verifier okayed extra greedy algorithm on the complete graph, but" << std::endl sl@0: << "the matching returned either wasn't a valid matching or wasn't" << std::endl sl@0: << "actually a maximum cardinality matching." << std::endl; sl@0: all_tests_passed = false; sl@0: } sl@0: sl@0: //Now remove an edge from the edmonds_mate matching. sl@0: vertex_iterator_t vi,vi_end; sl@0: for(tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi) sl@0: if (edmonds_mate[*vi] != graph_traits::null_vertex()) sl@0: break; sl@0: sl@0: edmonds_mate[edmonds_mate[*vi]] = graph_traits::null_vertex(); sl@0: edmonds_mate[*vi] = graph_traits::null_vertex(); sl@0: sl@0: //...and run the matching verifier - it should tell us that the matching isn't sl@0: //a maximum matching. sl@0: bool modified_edmonds_verification_result = sl@0: maximum_cardinality_matching_verifier::verify_matching(g,edmonds_mate,get(vertex_index,g)); sl@0: sl@0: BOOST_CHECK (!modified_edmonds_verification_result); sl@0: if (modified_edmonds_verification_result) sl@0: { sl@0: std::cout << "Verifier was fooled into thinking that a non-maximum matching was maximum" << std::endl; sl@0: all_tests_passed = false; sl@0: } sl@0: sl@0: Graph h(double_num_v); sl@0: gabows_graph(h,num_v); sl@0: sl@0: vertex_index_installer::install(h); sl@0: sl@0: //gabow's graph always has a perfect matching. it's also a good example of why sl@0: //one should initialize with the extra_greedy_matching in most cases. sl@0: sl@0: mate_t gabow_mate(double_num_v); sl@0: sl@0: bool gabows_graph_result = checked_edmonds_maximum_cardinality_matching(h,gabow_mate); sl@0: sl@0: BOOST_CHECK (gabows_graph_result); sl@0: if (!gabows_graph_result) sl@0: { sl@0: std::cout << "Problem on Gabow's Graph with " << graph_name << ":" << std::endl sl@0: << " Verifier reporting a maximum cardinality matching not found." << std::endl; sl@0: all_tests_passed = false; sl@0: } sl@0: sl@0: BOOST_CHECK (matching_size(h,gabow_mate) == num_v); sl@0: if (gabows_graph_result && matching_size(h,gabow_mate) != num_v) sl@0: { sl@0: std::cout << "Problem on Gabow's Graph with " << graph_name << ":" << std::endl sl@0: << " Verifier reported a maximum cardinality matching found," << std::endl sl@0: << " but matching size is " << matching_size(h,gabow_mate) sl@0: << " when it should be " << num_v << std::endl; sl@0: all_tests_passed = false; sl@0: } sl@0: sl@0: Graph j(double_num_v); sl@0: vertex_index_installer::install(j); sl@0: sl@0: typedef boost::mt19937 base_generator_type; sl@0: base_generator_type generator(static_cast(std::time(0))); sl@0: boost::uniform_int<> distribution(0, double_num_v-1); sl@0: boost::variate_generator > rand_num(generator, distribution); sl@0: sl@0: std::size_t num_edges = 0; sl@0: bool success; sl@0: sl@0: while (num_edges < 4*double_num_v) sl@0: { sl@0: vertex_descriptor_t u = random_vertex(j,rand_num); sl@0: vertex_descriptor_t v = random_vertex(j,rand_num); sl@0: if (u != v) sl@0: { sl@0: tie(tuples::ignore, success) = add_edge(u, v, j); sl@0: if (success) sl@0: num_edges++; sl@0: } sl@0: } sl@0: sl@0: mate_t random_mate(double_num_v); sl@0: bool random_graph_result = checked_edmonds_maximum_cardinality_matching(j,random_mate); sl@0: sl@0: BOOST_CHECK(random_graph_result); sl@0: if (!random_graph_result) sl@0: { sl@0: std::cout << "Matching in random graph not maximum for " << graph_name << std::endl; sl@0: all_tests_passed = false; sl@0: } sl@0: sl@0: //Now remove an edge from the random_mate matching. sl@0: for(tie(vi,vi_end) = vertices(j); vi != vi_end; ++vi) sl@0: if (random_mate[*vi] != graph_traits::null_vertex()) sl@0: break; sl@0: sl@0: random_mate[random_mate[*vi]] = graph_traits::null_vertex(); sl@0: random_mate[*vi] = graph_traits::null_vertex(); sl@0: sl@0: //...and run the matching verifier - it should tell us that the matching isn't sl@0: //a maximum matching. sl@0: bool modified_random_verification_result = sl@0: maximum_cardinality_matching_verifier::verify_matching(j,random_mate,get(vertex_index,j)); sl@0: sl@0: BOOST_CHECK(!modified_random_verification_result); sl@0: if (modified_random_verification_result) sl@0: { sl@0: std::cout << "Verifier was fooled into thinking that a non-maximum matching was maximum" << std::endl; sl@0: all_tests_passed = false; sl@0: } sl@0: sl@0: BOOST_CHECK(all_tests_passed); sl@0: if (all_tests_passed) sl@0: { sl@0: std::cout << graph_name << " passed all tests for n = " << num_v << '.' << std::endl; sl@0: } sl@0: sl@0: } sl@0: sl@0: sl@0: sl@0: sl@0: int test_main(int argc, char* argv[]) sl@0: { sl@0: sl@0: matching_test(10, "adjacency_list (using vectors)"); sl@0: matching_test(10, "adjacency_list (using lists)"); sl@0: matching_test(10, "adjacency_matrix"); sl@0: sl@0: matching_test(50, "adjacency_list (using vectors)"); sl@0: matching_test(50, "adjacency_list (using lists)"); sl@0: matching_test(50, "adjacency_matrix"); sl@0: sl@0: matching_test(51, "adjacency_list (using vectors)"); sl@0: matching_test(51, "adjacency_list (using lists)"); sl@0: matching_test(51, "adjacency_matrix"); sl@0: sl@0: #ifdef __SYMBIAN32__ sl@0: std_log(LOG_FILENAME_LINE,"[End Test Case ]"); sl@0: sl@0: testResultXml("matching_test"); sl@0: close_log_file(); sl@0: #endif sl@0: return 0; sl@0: } sl@0: sl@0: