isomorphism.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. // Boost.Graph library isomorphism test
  2. // Copyright (C) 2001-20044 Douglas Gregor (dgregor at cs dot indiana dot edu)
  3. //
  4. // Distributed under the Boost Software License, Version 1.0. (See
  5. // accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt)
  7. // For more information, see http://www.boost.org
  8. //
  9. // Revision History:
  10. //
  11. // 29 Nov 2001 Jeremy Siek
  12. // Changed to use Boost.Random.
  13. // 29 Nov 2001 Doug Gregor
  14. // Initial checkin.
  15. #include <iostream>
  16. #include <fstream>
  17. #include <map>
  18. #include <algorithm>
  19. #include <cstdlib>
  20. #include <time.h> // clock used without std:: qualifier?
  21. #include <boost/test/minimal.hpp>
  22. #include <boost/graph/adjacency_list.hpp>
  23. #include <boost/graph/isomorphism.hpp>
  24. #include <boost/property_map/property_map.hpp>
  25. #include <boost/random/variate_generator.hpp>
  26. #include <boost/random/uniform_real.hpp>
  27. #include <boost/random/uniform_int.hpp>
  28. #include <boost/random/mersenne_twister.hpp>
  29. #include <boost/lexical_cast.hpp>
  30. #ifndef BOOST_NO_CXX11_HDR_RANDOM
  31. #include <random>
  32. typedef std::mt19937 random_generator_type;
  33. #else
  34. typedef boost::mt19937 random_generator_type;
  35. #endif
  36. using namespace boost;
  37. #ifndef BOOST_NO_CXX98_RANDOM_SHUFFLE
  38. template <typename Generator>
  39. struct random_functor {
  40. random_functor(Generator& g) : g(g) { }
  41. std::size_t operator()(std::size_t n) {
  42. boost::uniform_int<std::size_t> distrib(0, n-1);
  43. boost::variate_generator<random_generator_type&, boost::uniform_int<std::size_t> >
  44. x(g, distrib);
  45. return x();
  46. }
  47. Generator& g;
  48. };
  49. #endif
  50. template<typename Graph1, typename Graph2>
  51. void randomly_permute_graph(const Graph1& g1, Graph2& g2)
  52. {
  53. // Need a clean graph to start with
  54. BOOST_REQUIRE(num_vertices(g2) == 0);
  55. BOOST_REQUIRE(num_edges(g2) == 0);
  56. typedef typename graph_traits<Graph1>::vertex_descriptor vertex1;
  57. typedef typename graph_traits<Graph2>::vertex_descriptor vertex2;
  58. typedef typename graph_traits<Graph1>::edge_iterator edge_iterator;
  59. random_generator_type gen;
  60. #ifndef BOOST_NO_CXX98_RANDOM_SHUFFLE
  61. random_functor<random_generator_type> rand_fun(gen);
  62. #endif
  63. // Decide new order
  64. std::vector<vertex1> orig_vertices;
  65. std::copy(vertices(g1).first, vertices(g1).second, std::back_inserter(orig_vertices));
  66. #ifndef BOOST_NO_CXX98_RANDOM_SHUFFLE
  67. std::random_shuffle(orig_vertices.begin(), orig_vertices.end(), rand_fun);
  68. #else
  69. std::shuffle(orig_vertices.begin(), orig_vertices.end(), gen);
  70. #endif
  71. std::map<vertex1, vertex2> vertex_map;
  72. for (std::size_t i = 0; i < num_vertices(g1); ++i) {
  73. vertex_map[orig_vertices[i]] = add_vertex(g2);
  74. }
  75. for (edge_iterator e = edges(g1).first; e != edges(g1).second; ++e) {
  76. add_edge(vertex_map[source(*e, g1)], vertex_map[target(*e, g1)], g2);
  77. }
  78. }
  79. template<typename Graph>
  80. void generate_random_digraph(Graph& g, double edge_probability)
  81. {
  82. typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
  83. random_generator_type random_gen;
  84. boost::uniform_real<double> distrib(0.0, 1.0);
  85. boost::variate_generator<random_generator_type&, boost::uniform_real<double> >
  86. random_dist(random_gen, distrib);
  87. for (vertex_iterator u = vertices(g).first; u != vertices(g).second; ++u) {
  88. vertex_iterator v = u;
  89. ++v;
  90. for (; v != vertices(g).second; ++v) {
  91. if (random_dist() <= edge_probability)
  92. add_edge(*u, *v, g);
  93. }
  94. }
  95. }
  96. void test_isomorphism2()
  97. {
  98. using namespace boost::graph::keywords;
  99. typedef adjacency_list<vecS, vecS, bidirectionalS> graph1;
  100. typedef adjacency_list<listS, listS, bidirectionalS,
  101. property<vertex_index_t, int> > graph2;
  102. graph1 g1(2);
  103. add_edge(vertex(0, g1), vertex(1, g1), g1);
  104. add_edge(vertex(1, g1), vertex(1, g1), g1);
  105. graph2 g2;
  106. randomly_permute_graph(g1, g2);
  107. int v_idx = 0;
  108. for (graph2::vertex_iterator v = vertices(g2).first;
  109. v != vertices(g2).second; ++v) {
  110. put(vertex_index_t(), g2, *v, v_idx++);
  111. }
  112. std::map<graph1::vertex_descriptor, graph2::vertex_descriptor> mapping;
  113. bool isomorphism_correct;
  114. clock_t start = clock();
  115. BOOST_CHECK(isomorphism_correct = boost::graph::isomorphism
  116. (g1, g2, _vertex_index1_map = get(vertex_index, g1),
  117. _isomorphism_map = make_assoc_property_map(mapping)));
  118. clock_t end = clock();
  119. std::cout << "Elapsed time (clock cycles): " << (end - start) << std::endl;
  120. bool verify_correct;
  121. BOOST_CHECK(verify_correct =
  122. verify_isomorphism(g1, g2, make_assoc_property_map(mapping)));
  123. if (!isomorphism_correct || !verify_correct) {
  124. // Output graph 1
  125. {
  126. std::ofstream out("isomorphism_failure.bg1");
  127. out << num_vertices(g1) << std::endl;
  128. for (graph1::edge_iterator e = edges(g1).first;
  129. e != edges(g1).second; ++e) {
  130. out << get(vertex_index_t(), g1, source(*e, g1)) << ' '
  131. << get(vertex_index_t(), g1, target(*e, g1)) << std::endl;
  132. }
  133. }
  134. // Output graph 2
  135. {
  136. std::ofstream out("isomorphism_failure.bg2");
  137. out << num_vertices(g2) << std::endl;
  138. for (graph2::edge_iterator e = edges(g2).first;
  139. e != edges(g2).second; ++e) {
  140. out << get(vertex_index_t(), g2, source(*e, g2)) << ' '
  141. << get(vertex_index_t(), g2, target(*e, g2)) << std::endl;
  142. }
  143. }
  144. }
  145. }
  146. void test_isomorphism(int n, double edge_probability)
  147. {
  148. using namespace boost::graph::keywords;
  149. typedef adjacency_list<vecS, vecS, bidirectionalS> graph1;
  150. typedef adjacency_list<listS, listS, bidirectionalS,
  151. property<vertex_index_t, int> > graph2;
  152. graph1 g1(n);
  153. generate_random_digraph(g1, edge_probability);
  154. graph2 g2;
  155. randomly_permute_graph(g1, g2);
  156. int v_idx = 0;
  157. for (graph2::vertex_iterator v = vertices(g2).first;
  158. v != vertices(g2).second; ++v) {
  159. put(vertex_index_t(), g2, *v, v_idx++);
  160. }
  161. std::map<graph1::vertex_descriptor, graph2::vertex_descriptor> mapping;
  162. bool isomorphism_correct;
  163. clock_t start = clock();
  164. BOOST_CHECK(isomorphism_correct = boost::graph::isomorphism
  165. (g1, g2, _isomorphism_map = make_assoc_property_map(mapping)));
  166. clock_t end = clock();
  167. std::cout << "Elapsed time (clock cycles): " << (end - start) << std::endl;
  168. bool verify_correct;
  169. BOOST_CHECK(verify_correct =
  170. verify_isomorphism(g1, g2, make_assoc_property_map(mapping)));
  171. if (!isomorphism_correct || !verify_correct) {
  172. // Output graph 1
  173. {
  174. std::ofstream out("isomorphism_failure.bg1");
  175. out << num_vertices(g1) << std::endl;
  176. for (graph1::edge_iterator e = edges(g1).first;
  177. e != edges(g1).second; ++e) {
  178. out << get(vertex_index_t(), g1, source(*e, g1)) << ' '
  179. << get(vertex_index_t(), g1, target(*e, g1)) << std::endl;
  180. }
  181. }
  182. // Output graph 2
  183. {
  184. std::ofstream out("isomorphism_failure.bg2");
  185. out << num_vertices(g2) << std::endl;
  186. for (graph2::edge_iterator e = edges(g2).first;
  187. e != edges(g2).second; ++e) {
  188. out << get(vertex_index_t(), g2, source(*e, g2)) << ' '
  189. << get(vertex_index_t(), g2, target(*e, g2)) << std::endl;
  190. }
  191. }
  192. }
  193. }
  194. int test_main(int argc, char* argv[])
  195. {
  196. if (argc < 3) {
  197. test_isomorphism(30, 0.45);
  198. return 0;
  199. }
  200. int n = boost::lexical_cast<int>(argv[1]);
  201. double edge_prob = boost::lexical_cast<double>(argv[2]);
  202. test_isomorphism(n, edge_prob);
  203. return 0;
  204. }