os/ossrv/stdcpp/tsrc/Boost_test/graph/src/matching_test.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 //=======================================================================
     2 // Copyright (c) 2005 Aaron Windsor
     3 //
     4 // Distributed under the Boost Software License, Version 1.0. 
     5 // (See accompanying file LICENSE_1_0.txt or copy at
     6 // http://www.boost.org/LICENSE_1_0.txt)
     7 //
     8 //=======================================================================
     9 
    10 /*
    11  * © Portions copyright (c) 2006-2007 Nokia Corporation.  All rights reserved.
    12 */
    13 
    14 #include <boost/graph/max_cardinality_matching.hpp>
    15 
    16 #include <iostream>                      // for std::cout
    17 #include <boost/vector_property_map.hpp>
    18 #include <boost/graph/adjacency_list.hpp>
    19 #include <boost/graph/adjacency_matrix.hpp>
    20 #include <boost/graph/random.hpp>
    21 #include <ctime>
    22 #include <boost/random.hpp>
    23 #include <boost/test/minimal.hpp>
    24 #ifdef __SYMBIAN32__
    25 #include "std_log_result.h"
    26 #define LOG_FILENAME_LINE __FILE__, __LINE__
    27 #endif
    28 using namespace boost;
    29 
    30 typedef adjacency_list<vecS, 
    31                        vecS, 
    32                        undirectedS, 
    33                        property<vertex_index_t, int> >  undirected_graph;
    34 
    35 typedef adjacency_list<listS,
    36                        listS,
    37                        undirectedS,
    38                        property<vertex_index_t, int> >  undirected_list_graph;
    39 
    40 typedef adjacency_matrix<undirectedS, 
    41                          property<vertex_index_t,int> > undirected_adjacency_matrix_graph;
    42 
    43 
    44 template <typename Graph>
    45 struct vertex_index_installer 
    46 {
    47   static void install(Graph& g) {}
    48 };
    49 
    50 
    51 template <>
    52 struct vertex_index_installer<undirected_list_graph>
    53 {
    54   static void install(undirected_list_graph& g) 
    55   {
    56     typedef graph_traits<undirected_list_graph>::vertex_iterator vertex_iterator_t;
    57     typedef graph_traits<undirected_list_graph>::vertices_size_type v_size_t;
    58     
    59     vertex_iterator_t vi, vi_end;
    60     v_size_t i = 0;
    61     for(tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi, ++i)
    62       put(vertex_index, g, *vi, i);
    63   }
    64 };
    65 
    66 
    67 
    68 template <typename Graph>
    69 void complete_graph(Graph& g, int n)
    70 {
    71   //creates the complete graph on n vertices
    72   typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator_t;
    73 
    74   g = Graph(n);
    75   vertex_iterator_t vi, vi_end, wi;
    76   tie(vi,vi_end) = vertices(g);
    77   for(tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi)
    78     {
    79       wi = vi;
    80       ++wi;
    81       for(; wi != vi_end; ++wi)
    82         add_edge(*vi,*wi,g);      
    83     }
    84 }
    85 
    86 
    87 
    88 template <typename Graph>
    89 void gabows_graph(Graph& g, int n)
    90 {
    91   //creates a graph with 2n vertices, consisting of the complete graph
    92   //on n vertices plus n vertices of degree one, each adjacent to one
    93   //vertex in the complete graph. without any initial matching, this 
    94   //graph forces edmonds' algorithm into worst-case behavior.
    95 
    96   typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator_t;
    97 
    98   g = Graph(2* n);
    99 
   100   vertex_iterator_t vi, vi_end, ui, ui_end, halfway;
   101 
   102   tie(ui,ui_end) = vertices(g);
   103 
   104   halfway = ui;
   105   for(int i = 0; i < n; ++i)
   106     ++halfway;
   107 
   108 
   109   while(ui != halfway)
   110     {
   111       vi = ui;
   112       ++vi;
   113       while (vi != halfway)
   114         {
   115           add_edge(*ui,*vi,g);
   116           ++vi;
   117         }
   118       ++ui;
   119     }
   120 
   121   tie(ui,ui_end) = vertices(g);
   122 
   123   while(halfway != ui_end)
   124     {
   125       add_edge(*ui, *halfway, g);
   126       ++ui;
   127       ++halfway;
   128     }
   129 
   130 }
   131 
   132 
   133 
   134 template <typename Graph>
   135 void matching_test(std::size_t num_v, const std::string& graph_name)
   136 {
   137   typedef typename property_map<Graph,vertex_index_t>::type vertex_index_map_t;
   138   typedef vector_property_map< typename graph_traits<Graph>::vertex_descriptor, vertex_index_map_t > mate_t;
   139   typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator_t;
   140   typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor_t;
   141   typedef typename graph_traits<Graph>::vertices_size_type v_size_t;
   142 
   143   const std::size_t double_num_v = num_v * 2;
   144 
   145   bool all_tests_passed = true;
   146 
   147   //form the complete graph on 2*n vertices; the maximum cardinality matching, greedy matching,
   148   //and extra greedy matching should all be the same - a matching of size n.
   149 
   150   Graph g(double_num_v);
   151   complete_graph(g,double_num_v);
   152 
   153   vertex_index_installer<Graph>::install(g);
   154 
   155   mate_t edmonds_mate(double_num_v);
   156   mate_t greedy_mate(double_num_v);
   157   mate_t extra_greedy_mate(double_num_v);
   158   
   159   //find a maximum cardinality matching using edmonds' blossom-shrinking algorithm, starting
   160   //with an empty matching.
   161   bool edmonds_result =
   162     matching < Graph, mate_t, vertex_index_map_t,
   163                edmonds_augmenting_path_finder, empty_matching, maximum_cardinality_matching_verifier>
   164     (g,edmonds_mate, get(vertex_index,g));
   165 
   166   BOOST_CHECK (edmonds_result);
   167   if (!edmonds_result)
   168     {
   169       std::cout << "Verifier reporting a problem finding a perfect matching on" << std::endl
   170                 << "the complete graph using " << graph_name << std::endl;
   171       all_tests_passed = false;
   172     }
   173   
   174   //find a greedy matching
   175   bool greedy_result =
   176     matching<Graph, mate_t, vertex_index_map_t,
   177              no_augmenting_path_finder, greedy_matching, maximum_cardinality_matching_verifier>
   178     (g,greedy_mate, get(vertex_index,g));
   179 
   180   BOOST_CHECK (greedy_result);
   181   if (!greedy_result)
   182     {
   183       std::cout << "Verifier reporting a problem finding a greedy matching on" << std::endl
   184                 << "the complete graph using " << graph_name << std::endl;
   185       all_tests_passed = false;
   186     }
   187 
   188   //find an extra greedy matching
   189   bool extra_greedy_result =
   190     matching<Graph, mate_t, vertex_index_map_t,
   191              no_augmenting_path_finder, extra_greedy_matching, maximum_cardinality_matching_verifier>
   192     (g,extra_greedy_mate,get(vertex_index,g));
   193 
   194   BOOST_CHECK (extra_greedy_result);
   195   if (!extra_greedy_result)
   196     {
   197       std::cout << "Verifier reporting a problem finding an extra greedy matching on" << std::endl
   198                 << "the complete graph using " << graph_name << std::endl;
   199       all_tests_passed = false;
   200     }
   201 
   202   //as a sanity check, make sure that each of the matchings returned is a valid matching and has
   203   //1000 edges.
   204 
   205   bool edmonds_sanity_check = 
   206     is_a_matching(g,edmonds_mate) && matching_size(g,edmonds_mate) == num_v;
   207   
   208   BOOST_CHECK (edmonds_sanity_check);
   209   if (edmonds_result && !edmonds_sanity_check)
   210     {
   211       std::cout << "Verifier okayed edmonds' algorithm on the complete graph, but" << std::endl
   212                 << "the matching returned either wasn't a valid matching or wasn't" << std::endl
   213                 << "actually a maximum cardinality matching." << std::endl;
   214       all_tests_passed = false;
   215     }
   216 
   217   bool greedy_sanity_check = 
   218     is_a_matching(g,greedy_mate) && matching_size(g,greedy_mate) == num_v;  
   219 
   220   BOOST_CHECK (greedy_sanity_check);
   221   if (greedy_result && !greedy_sanity_check)
   222     {
   223       std::cout << "Verifier okayed greedy algorithm on the complete graph, but" << std::endl
   224                 << "the matching returned either wasn't a valid matching or wasn't" << std::endl
   225                 << "actually a maximum cardinality matching." << std::endl;
   226       all_tests_passed = false;
   227     }
   228   
   229   bool extra_greedy_sanity_check =
   230     is_a_matching(g,extra_greedy_mate) && matching_size(g,extra_greedy_mate) == num_v;
   231   
   232   BOOST_CHECK (extra_greedy_sanity_check);
   233   if (extra_greedy_result && !extra_greedy_sanity_check)
   234     {
   235       std::cout << "Verifier okayed extra greedy algorithm on the complete graph, but" << std::endl
   236                 << "the matching returned either wasn't a valid matching or wasn't" << std::endl
   237                 << "actually a maximum cardinality matching." << std::endl;
   238       all_tests_passed = false;
   239     }
   240   
   241   //Now remove an edge from the edmonds_mate matching.
   242   vertex_iterator_t vi,vi_end;
   243   for(tie(vi,vi_end) = vertices(g); vi != vi_end; ++vi)
   244     if (edmonds_mate[*vi] != graph_traits<Graph>::null_vertex())
   245       break;
   246   
   247   edmonds_mate[edmonds_mate[*vi]] = graph_traits<Graph>::null_vertex();
   248   edmonds_mate[*vi] = graph_traits<Graph>::null_vertex();
   249   
   250   //...and run the matching verifier - it should tell us that the matching isn't
   251   //a maximum matching.
   252   bool modified_edmonds_verification_result =
   253     maximum_cardinality_matching_verifier<Graph,mate_t,vertex_index_map_t>::verify_matching(g,edmonds_mate,get(vertex_index,g));
   254   
   255   BOOST_CHECK (!modified_edmonds_verification_result);
   256   if (modified_edmonds_verification_result)
   257     {
   258       std::cout << "Verifier was fooled into thinking that a non-maximum matching was maximum" << std::endl;
   259       all_tests_passed = false;
   260     }
   261   
   262   Graph h(double_num_v);
   263   gabows_graph(h,num_v);
   264 
   265   vertex_index_installer<Graph>::install(h);
   266 
   267   //gabow's graph always has a perfect matching. it's also a good example of why
   268   //one should initialize with the extra_greedy_matching in most cases.
   269   
   270   mate_t gabow_mate(double_num_v);
   271   
   272   bool gabows_graph_result = checked_edmonds_maximum_cardinality_matching(h,gabow_mate);
   273   
   274   BOOST_CHECK (gabows_graph_result);
   275   if (!gabows_graph_result)
   276     {
   277       std::cout << "Problem on Gabow's Graph with " << graph_name << ":" << std::endl
   278                 << "   Verifier reporting a maximum cardinality matching not found." << std::endl;
   279       all_tests_passed = false;
   280     }
   281   
   282   BOOST_CHECK (matching_size(h,gabow_mate) == num_v);
   283   if (gabows_graph_result && matching_size(h,gabow_mate) != num_v)
   284     {
   285       std::cout << "Problem on Gabow's Graph with " << graph_name << ":" << std::endl
   286                 << "   Verifier reported a maximum cardinality matching found," << std::endl
   287                 << "   but matching size is " << matching_size(h,gabow_mate)
   288                 << " when it should be " << num_v << std::endl;
   289       all_tests_passed = false;
   290     }
   291 
   292   Graph j(double_num_v);
   293   vertex_index_installer<Graph>::install(j);
   294 
   295   typedef boost::mt19937 base_generator_type;
   296   base_generator_type generator(static_cast<unsigned int>(std::time(0)));
   297   boost::uniform_int<> distribution(0, double_num_v-1);
   298   boost::variate_generator<base_generator_type&, boost::uniform_int<> > rand_num(generator, distribution);
   299 
   300   std::size_t num_edges = 0;
   301   bool success;
   302 
   303   while (num_edges < 4*double_num_v)
   304     {
   305       vertex_descriptor_t u = random_vertex(j,rand_num);
   306       vertex_descriptor_t v = random_vertex(j,rand_num);
   307       if (u != v)
   308         {
   309           tie(tuples::ignore, success) = add_edge(u, v, j);
   310           if (success)
   311             num_edges++;
   312         }
   313     }
   314 
   315   mate_t random_mate(double_num_v);
   316   bool random_graph_result = checked_edmonds_maximum_cardinality_matching(j,random_mate);  
   317 
   318   BOOST_CHECK(random_graph_result);
   319   if (!random_graph_result)
   320     {
   321       std::cout << "Matching in random graph not maximum for " << graph_name << std::endl;
   322       all_tests_passed = false;
   323     }
   324 
   325   //Now remove an edge from the random_mate matching.
   326   for(tie(vi,vi_end) = vertices(j); vi != vi_end; ++vi)
   327     if (random_mate[*vi] != graph_traits<Graph>::null_vertex())
   328       break;
   329   
   330   random_mate[random_mate[*vi]] = graph_traits<Graph>::null_vertex();
   331   random_mate[*vi] = graph_traits<Graph>::null_vertex();
   332   
   333   //...and run the matching verifier - it should tell us that the matching isn't
   334   //a maximum matching.
   335   bool modified_random_verification_result =
   336     maximum_cardinality_matching_verifier<Graph,mate_t,vertex_index_map_t>::verify_matching(j,random_mate,get(vertex_index,j));
   337   
   338   BOOST_CHECK(!modified_random_verification_result);
   339   if (modified_random_verification_result)
   340     {
   341       std::cout << "Verifier was fooled into thinking that a non-maximum matching was maximum" << std::endl;
   342       all_tests_passed = false;
   343     }
   344 
   345   BOOST_CHECK(all_tests_passed);
   346   if (all_tests_passed)
   347     {
   348       std::cout << graph_name << " passed all tests for n = " << num_v << '.' << std::endl;
   349     }
   350 
   351 }
   352 
   353 
   354 
   355 
   356 int test_main(int argc, char* argv[])
   357 {
   358 
   359   matching_test<undirected_graph>(10, "adjacency_list (using vectors)");
   360   matching_test<undirected_list_graph>(10, "adjacency_list (using lists)");
   361   matching_test<undirected_adjacency_matrix_graph>(10, "adjacency_matrix");
   362 
   363   matching_test<undirected_graph>(50, "adjacency_list (using vectors)");
   364   matching_test<undirected_list_graph>(50, "adjacency_list (using lists)");
   365   matching_test<undirected_adjacency_matrix_graph>(50, "adjacency_matrix");
   366 
   367   matching_test<undirected_graph>(51, "adjacency_list (using vectors)");
   368   matching_test<undirected_list_graph>(51, "adjacency_list (using lists)");
   369   matching_test<undirected_adjacency_matrix_graph>(51, "adjacency_matrix");
   370  
   371 #ifdef __SYMBIAN32__
   372 std_log(LOG_FILENAME_LINE,"[End Test Case ]");
   373 
   374 	testResultXml("matching_test");
   375 	close_log_file();
   376 #endif
   377   return 0;
   378 }
   379 
   380