vf2_sub_graph_iso_test.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. //=======================================================================
  2. // Boost.Graph library vf2_sub_graph_iso test
  3. // Adapted from isomorphism.cpp and mcgregor_subgraphs_test.cpp
  4. //
  5. // Copyright (C) 2012 Flavio De Lorenzi (fdlorenzi@gmail.com)
  6. //
  7. // Distributed under the Boost Software License, Version 1.0. (See
  8. // accompanying file LICENSE_1_0.txt or copy at
  9. // http://www.boost.org/LICENSE_1_0.txt)
  10. //=======================================================================
  11. // Revision History:
  12. // 8 April 2013: Fixed a typo in random_functor. (Flavio De Lorenzi)
  13. #include <iostream>
  14. #include <fstream>
  15. #include <map>
  16. #include <algorithm>
  17. #include <cstdlib>
  18. #include <time.h>
  19. #include <boost/test/minimal.hpp>
  20. #include <boost/graph/adjacency_list.hpp>
  21. #include <boost/graph/vf2_sub_graph_iso.hpp>
  22. #include <boost/graph/random.hpp>
  23. #include <boost/property_map/property_map.hpp>
  24. #include <boost/random.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. #include <boost/graph/graphviz.hpp>
  31. #ifndef BOOST_NO_CXX11_HDR_RANDOM
  32. #include <random>
  33. typedef std::mt19937 random_generator_type;
  34. #else
  35. typedef boost::mt19937 random_generator_type;
  36. #endif
  37. using namespace boost;
  38. #ifndef BOOST_NO_CXX98_RANDOM_SHUFFLE
  39. template <typename Generator>
  40. struct random_functor {
  41. random_functor(Generator& g) : g(g) { }
  42. std::size_t operator()(std::size_t n) {
  43. boost::uniform_int<std::size_t> distrib(0, n-1);
  44. boost::variate_generator<Generator&, boost::uniform_int<std::size_t> >
  45. x(g, distrib);
  46. return x();
  47. }
  48. Generator& g;
  49. };
  50. #endif
  51. template<typename Graph1, typename Graph2>
  52. void randomly_permute_graph(Graph1& g1, const Graph2& g2) {
  53. BOOST_REQUIRE(num_vertices(g1) <= num_vertices(g2));
  54. BOOST_REQUIRE(num_edges(g1) == 0);
  55. typedef typename graph_traits<Graph1>::vertex_descriptor vertex1;
  56. typedef typename graph_traits<Graph2>::vertex_descriptor vertex2;
  57. typedef typename graph_traits<Graph1>::vertex_iterator vertex_iterator;
  58. typedef typename graph_traits<Graph2>::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<vertex2> orig_vertices;
  65. std::copy(vertices(g2).first, vertices(g2).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<vertex2, vertex1> vertex_map;
  72. std::size_t i = 0;
  73. for (vertex_iterator vi = vertices(g1).first;
  74. vi != vertices(g1).second; ++i, ++vi) {
  75. vertex_map[orig_vertices[i]] = *vi;
  76. put(vertex_name_t(), g1, *vi, get(vertex_name_t(), g2, orig_vertices[i]));
  77. }
  78. for (edge_iterator ei = edges(g2).first; ei != edges(g2).second; ++ei) {
  79. typename std::map<vertex2, vertex1>::iterator si = vertex_map.find(source(*ei, g2)),
  80. ti = vertex_map.find(target(*ei, g2));
  81. if ((si != vertex_map.end()) && (ti != vertex_map.end()))
  82. add_edge(si->second, ti->second, get(edge_name_t(), g2, *ei), g1);
  83. }
  84. }
  85. template<typename Graph>
  86. void generate_random_digraph(Graph& g, double edge_probability,
  87. int max_parallel_edges, double parallel_edge_probability,
  88. int max_edge_name, int max_vertex_name) {
  89. BOOST_REQUIRE((0 <= edge_probability) && (edge_probability <= 1));
  90. BOOST_REQUIRE((0 <= parallel_edge_probability) && (parallel_edge_probability <= 1));
  91. BOOST_REQUIRE(0 <= max_parallel_edges);
  92. BOOST_REQUIRE(0 <= max_edge_name);
  93. BOOST_REQUIRE(0 <= max_vertex_name);
  94. typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator;
  95. random_generator_type random_gen;
  96. boost::uniform_real<double> dist_real(0.0, 1.0);
  97. boost::variate_generator<random_generator_type&, boost::uniform_real<double> >
  98. random_real_dist(random_gen, dist_real);
  99. for (vertex_iterator u = vertices(g).first; u != vertices(g).second; ++u) {
  100. for (vertex_iterator v = vertices(g).first; v != vertices(g).second; ++v) {
  101. if (random_real_dist() <= edge_probability) {
  102. add_edge(*u, *v, g);
  103. for (int i = 0; i < max_parallel_edges; ++i) {
  104. if (random_real_dist() <= parallel_edge_probability)
  105. add_edge(*u, *v, g);
  106. }
  107. }
  108. }
  109. }
  110. {
  111. boost::uniform_int<int> dist_int(0, max_edge_name);
  112. boost::variate_generator<random_generator_type&, boost::uniform_int<int> >
  113. random_int_dist(random_gen, dist_int);
  114. randomize_property<vertex_name_t>(g, random_int_dist);
  115. }
  116. {
  117. boost::uniform_int<int> dist_int(0, max_vertex_name);
  118. boost::variate_generator<random_generator_type&, boost::uniform_int<int> >
  119. random_int_dist(random_gen, dist_int);
  120. randomize_property<edge_name_t>(g, random_int_dist);
  121. }
  122. }
  123. template <typename Graph1,
  124. typename Graph2,
  125. typename EdgeEquivalencePredicate,
  126. typename VertexEquivalencePredicate>
  127. struct test_callback {
  128. test_callback(const Graph1& graph1, const Graph2& graph2,
  129. EdgeEquivalencePredicate edge_comp,
  130. VertexEquivalencePredicate vertex_comp, bool output)
  131. : graph1_(graph1), graph2_(graph2), edge_comp_(edge_comp), vertex_comp_(vertex_comp),
  132. output_(output) {}
  133. template <typename CorrespondenceMap1To2,
  134. typename CorrespondenceMap2To1>
  135. bool operator()(CorrespondenceMap1To2 f, CorrespondenceMap2To1) {
  136. bool verified;
  137. BOOST_CHECK(verified = verify_vf2_subgraph_iso(graph1_, graph2_, f, edge_comp_, vertex_comp_));
  138. // Output (sub)graph isomorphism map
  139. if (!verified || output_) {
  140. std::cout << "Verfied: " << std::boolalpha << verified << std::endl;
  141. std::cout << "Num vertices: " << num_vertices(graph1_) << ' ' << num_vertices(graph2_) << std::endl;
  142. BGL_FORALL_VERTICES_T(v, graph1_, Graph1)
  143. std::cout << '(' << get(vertex_index_t(), graph1_, v) << ", "
  144. << get(vertex_index_t(), graph2_, get(f, v)) << ") ";
  145. std::cout << std::endl;
  146. }
  147. return true;
  148. }
  149. private:
  150. const Graph1& graph1_;
  151. const Graph2& graph2_;
  152. EdgeEquivalencePredicate edge_comp_;
  153. VertexEquivalencePredicate vertex_comp_;
  154. bool output_;
  155. };
  156. // we pretend this is something more complicated which calculates indices somehow
  157. template<typename G>
  158. struct IndirectIndexMap {
  159. typedef std::size_t value_type;
  160. typedef value_type reference;
  161. typedef typename boost::graph_traits<G>::vertex_descriptor key_type;
  162. typedef boost::readable_property_map_tag category;
  163. explicit IndirectIndexMap(const G &g) : g(g) {}
  164. public:
  165. const G &g;
  166. };
  167. template<typename G>
  168. std::size_t get(const IndirectIndexMap<G> &map, typename boost::graph_traits<G>::vertex_descriptor v) {
  169. // we pretend this is something more complicated which calculates indices somehow
  170. return get(vertex_index_t(), map.g, v);
  171. }
  172. void test_vf2_sub_graph_iso(int n1, int n2, double edge_probability,
  173. int max_parallel_edges, double parallel_edge_probability,
  174. int max_edge_name, int max_vertex_name, bool output) {
  175. typedef property<edge_name_t, int> edge_property;
  176. typedef property<vertex_name_t, int, property<vertex_index_t, int> > vertex_property;
  177. typedef adjacency_list<listS, listS, bidirectionalS, vertex_property, edge_property> graph1;
  178. typedef adjacency_list<vecS, vecS, bidirectionalS, vertex_property, edge_property> graph2;
  179. graph1 g1(n1);
  180. graph2 g2(n2);
  181. generate_random_digraph(g2, edge_probability, max_parallel_edges, parallel_edge_probability,
  182. max_edge_name, max_vertex_name);
  183. randomly_permute_graph(g1, g2);
  184. int v_idx = 0;
  185. for (graph_traits<graph1>::vertex_iterator vi = vertices(g1).first;
  186. vi != vertices(g1).second; ++vi) {
  187. put(vertex_index_t(), g1, *vi, v_idx++);
  188. }
  189. // Create vertex and edge predicates
  190. typedef property_map<graph1, vertex_name_t>::type vertex_name_map1;
  191. typedef property_map<graph2, vertex_name_t>::type vertex_name_map2;
  192. typedef property_map_equivalent<vertex_name_map1, vertex_name_map2> vertex_predicate;
  193. vertex_predicate vertex_comp =
  194. make_property_map_equivalent(get(vertex_name, g1), get(vertex_name, g2));
  195. typedef property_map<graph1, edge_name_t>::type edge_name_map1;
  196. typedef property_map<graph2, edge_name_t>::type edge_name_map2;
  197. typedef property_map_equivalent<edge_name_map1, edge_name_map2> edge_predicate;
  198. edge_predicate edge_comp =
  199. make_property_map_equivalent(get(edge_name, g1), get(edge_name, g2));
  200. std::clock_t start = std::clock();
  201. // Create callback
  202. test_callback<graph1, graph2, edge_predicate, vertex_predicate>
  203. callback(g1, g2, edge_comp, vertex_comp, output);
  204. std::cout << std::endl;
  205. BOOST_CHECK(vf2_subgraph_iso(g1, g2, callback, vertex_order_by_mult(g1),
  206. edges_equivalent(edge_comp).vertices_equivalent(vertex_comp)));
  207. BOOST_CHECK(vf2_subgraph_iso(g1, g2, callback,
  208. IndirectIndexMap<graph1>(g1),
  209. IndirectIndexMap<graph2>(g2),
  210. vertex_order_by_mult(g1),
  211. edge_comp, vertex_comp));
  212. std::clock_t end1 = std::clock();
  213. std::cout << "vf2_subgraph_iso: elapsed time (clock cycles): " << (end1 - start) << std::endl;
  214. if (num_vertices(g1) == num_vertices(g2)) {
  215. std::cout << std::endl;
  216. BOOST_CHECK(vf2_graph_iso(g1, g2, callback, vertex_order_by_mult(g1),
  217. edges_equivalent(edge_comp).vertices_equivalent(vertex_comp)));
  218. std::clock_t end2 = std::clock();
  219. std::cout << "vf2_graph_iso: elapsed time (clock cycles): " << (end2 - end1) << std::endl;
  220. }
  221. if (output) {
  222. std::fstream file_graph1("graph1.dot", std::fstream::out);
  223. write_graphviz(file_graph1, g1,
  224. make_label_writer(get(boost::vertex_name, g1)),
  225. make_label_writer(get(boost::edge_name, g1)));
  226. std::fstream file_graph2("graph2.dot", std::fstream::out);
  227. write_graphviz(file_graph2, g2,
  228. make_label_writer(get(boost::vertex_name, g2)),
  229. make_label_writer(get(boost::edge_name, g2)));
  230. }
  231. }
  232. int test_main(int argc, char* argv[]) {
  233. int num_vertices_g1 = 10;
  234. int num_vertices_g2 = 20;
  235. double edge_probability = 0.4;
  236. int max_parallel_edges = 2;
  237. double parallel_edge_probability = 0.4;
  238. int max_edge_name = 5;
  239. int max_vertex_name = 5;
  240. bool output = false;
  241. if (argc > 1) {
  242. num_vertices_g1 = boost::lexical_cast<int>(argv[1]);
  243. }
  244. if (argc > 2) {
  245. num_vertices_g2 = boost::lexical_cast<int>(argv[2]);
  246. }
  247. if (argc > 3) {
  248. edge_probability = boost::lexical_cast<double>(argv[3]);
  249. }
  250. if (argc > 4) {
  251. max_parallel_edges = boost::lexical_cast<int>(argv[4]);
  252. }
  253. if (argc > 5) {
  254. parallel_edge_probability = boost::lexical_cast<double>(argv[5]);
  255. }
  256. if (argc > 6) {
  257. max_edge_name = boost::lexical_cast<int>(argv[6]);
  258. }
  259. if (argc > 7) {
  260. max_vertex_name = boost::lexical_cast<int>(argv[7]);
  261. }
  262. if (argc > 8) {
  263. output = boost::lexical_cast<bool>(argv[8]);
  264. }
  265. test_vf2_sub_graph_iso(num_vertices_g1, num_vertices_g2, edge_probability,
  266. max_parallel_edges, parallel_edge_probability,
  267. max_edge_name, max_vertex_name, output);
  268. return 0;
  269. }