cycle_ratio_tests.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. // Copyright (C) 2006-2009 Dmitry Bufistov and Andrey Parfenov
  2. // Use, modification and distribution is subject to the Boost Software
  3. // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  4. // http://www.boost.org/LICENSE_1_0.txt)
  5. #include <sstream>
  6. #include <boost/graph/adjacency_list.hpp>
  7. #include <boost/graph/adjacency_matrix.hpp>
  8. #include <boost/graph/graphviz.hpp>
  9. #include <boost/graph/iteration_macros.hpp>
  10. #include <boost/graph/graph_utility.hpp>
  11. #include <boost/graph/property_iter_range.hpp>
  12. #include <boost/graph/howard_cycle_ratio.hpp>
  13. #include <boost/test/minimal.hpp>
  14. /**
  15. * @author Dmitry Bufistov
  16. * @author Andrey Parfenov
  17. */
  18. /*!
  19. * The graph has two equal cycles with ratio 2/3
  20. */
  21. static const char test_graph1[] = "digraph G {\
  22. edge [w1=1, w2=1];\
  23. 1->2\
  24. 2->3 [w1=0]\
  25. 3->4\
  26. 4->2\
  27. 1->5\
  28. 5->6\
  29. 6->7 [w1=0]\
  30. 7->5 \
  31. }";
  32. /*!
  33. * The graph has no cycles
  34. */
  35. static const std::string test_graph2 = "digraph G {edge [w1=1]; 1->3 [w2=1]; 1->2 [w2=2]; 1->4 [w2=7]; }";
  36. /*!
  37. * Example from the paper "Nunerical computation of spectral elements"
  38. * Maximum cycle ratio is 5.5
  39. */
  40. static const char test_graph3[] = "\
  41. digraph article {\
  42. edge [w2 =2];\
  43. 1->1 [w1 = 1];\
  44. 1->2 [w1 = 2];\
  45. 1->4 [w1 = 7];\
  46. 2->2 [w1 = 3];\
  47. 2->3 [w1 = 5];\
  48. 3->2 [w1 = 4];\
  49. 3->4 [w1 = 3];\
  50. 4->2 [w1 = 2];\
  51. 4->3 [w1 = 8];\
  52. }";
  53. /*!
  54. * Simple multigraph.
  55. * Maximum cycle ratio is 2.5, minimum 0.5
  56. */
  57. static const char test_graph4[] = "digraph G {\
  58. edge [w2=1];\
  59. a->b [w1=1];\
  60. b->a [w1=0];\
  61. a->b [w1=2];\
  62. b->a [w1=3];\
  63. }";
  64. /*!
  65. * The big graph with two equal cycles
  66. */
  67. static const char test_graph5[]= "digraph G { edge [w2=1, w1=1]; n94->n8; n95->n8; n93->n8; n93->n9; n42->n9; n23->n13;\
  68. n29->n13; n95->n14; n37->n14; n95->n19; n37->n19; n94->n23; n60->n26; n76->n26; n94->n29; n9->n33 [w1=0]; n80->n33;\
  69. n14->n34 [w1=0];n19->n34; n94->n37; n94->n42; n95->n42; n8->n60; n26->n60; n26->n76; n106->n76; n93->n80; n42->n80;\
  70. n33->n93; n60->n93; n13->n94; n60->n94; n34->n95; n60->n95; n94->n106; n95->n106; n93->n106;\
  71. }";
  72. /*!
  73. * Random graph generated by hands.
  74. * Maximum cycle ratio is 3.58, minimum is 0.294118
  75. */
  76. static const char test_graph6[]= "digraph test_graph6 {\
  77. 16;\
  78. 17;\
  79. \
  80. 1->2 [w1=1, w2=0.1];\
  81. 2->3 [w1 = 2, w2=3.6];\
  82. 3->4 [w1=7, w2=8];\
  83. 4->5 [w1=3.1,w2=0.8];\
  84. 4->5 [w1 = 4.2, w2=0.6];\
  85. 4->5 [w1 = 5.3, w2=0.4];\
  86. 5->6 [w1=-10, w2 = 34.75]\
  87. 6->1 [w1=100, w2 = 20]\
  88. \
  89. 1->7 [w1=10, w2 = 20];\
  90. 7->8 [w1=3.75, w2 = 1.25];\
  91. 7->8 [w1=30, w2 = 22.2];\
  92. 8->9 [w1=10, w2 = 20];\
  93. 9->10 [w1=-2.1, w2 = 30]\
  94. 10->6 [w1=10, w2 = 20]\
  95. \
  96. 11->12 [w1 = 5, w2=0.45];\
  97. 12->13 [w1 = 4, w2=0.2];\
  98. 13->14 [w1 = 3, w2=15.75];\
  99. 14->11 [w1 = -2.5, w2=0.6];\
  100. 11->10 [w1 = -8, w2=0.9];\
  101. 11->10 [w1 = -15, w2=2.9];\
  102. \
  103. 18 -> 19 [w1=18, w2=6];\
  104. 18 -> 20 [w1=16.3, w2=8.2];\
  105. 18 -> 21 [w1=-3, w2=15];\
  106. 18 -> 18 [w1=2, w2=1];\
  107. 19 -> 18 [w1=0.06, w2=0.01];\
  108. 19 -> 19 [w1=1, w2=1.2];\
  109. 19 -> 20 [w1=5, w2=2];\
  110. 19 -> 21 [w1=3, w2=0.1];\
  111. 20 -> 18 [w1=4, w2=0.2];\
  112. 20 -> 19 [w1=11, w2=21];\
  113. 20 -> 20 [w1=6, w2=5];\
  114. 20 -> 21 [w1=7, w2=1];\
  115. 21 -> 18 [w1=8, w2=2];\
  116. 21 -> 19 [w1=12, w2=6];\
  117. 21 -> 20 [w1=7.5, w2=4.3];\
  118. 21 -> 21 [w1=1.25, w2=2.15];\
  119. }";
  120. using namespace boost;
  121. typedef property<vertex_index_t, int, property<boost::vertex_name_t, std::string> > vertex_props_t;
  122. template <typename TW1, typename TW2> struct Graph
  123. {
  124. typedef typename boost::property<
  125. boost::edge_weight_t, TW1,
  126. typename boost::property<
  127. boost::edge_weight2_t, TW2, property<boost::edge_index_t, int>
  128. >
  129. > edge_props_t;
  130. typedef typename boost::adjacency_list<
  131. boost::listS, boost::listS, boost::directedS, vertex_props_t,
  132. edge_props_t>
  133. type;
  134. };
  135. typedef Graph<int, int>::type diGraphInt;
  136. typedef Graph<double, double>::type diGraphReal;
  137. template <typename TW1, typename TW2>
  138. struct CEdgeProps
  139. {
  140. CEdgeProps(TW1 w1 = 1, TW2 w2 = 2) :
  141. m_w1(w1), m_w2(w2), m_edge_index((std::numeric_limits<int>::max)())
  142. {}
  143. TW1 m_w1;
  144. TW2 m_w2;
  145. int m_edge_index;
  146. };
  147. typedef adjacency_matrix<directedS, no_property, CEdgeProps<int, int> > GraphMInt;
  148. ///Create "tokens_map" for reading graph properties from .dot file
  149. template <typename TG>
  150. void make_dynamic_properties(TG &g, dynamic_properties &p)
  151. {
  152. p.property("node_id", get(vertex_name, g));
  153. p.property("label", get(edge_weight, g));
  154. p.property("w1", get(edge_weight, g));
  155. p.property("w2", get(edge_weight2, g));
  156. }
  157. template <typename TG>
  158. void read_data1(std::istream &is, TG &g)
  159. {
  160. dynamic_properties p;
  161. make_dynamic_properties(g, p);
  162. read_graphviz(is, g, p);
  163. std::cout << "Number of vertices: " << num_vertices(g) << std::endl;
  164. std::cout << "Number of edges: " << num_edges(g) << std::endl;
  165. int i = 0;
  166. BGL_FORALL_VERTICES_T(vd, g, TG)
  167. {
  168. put(vertex_index, g, vd, i++);
  169. }
  170. i=0;
  171. BGL_FORALL_EDGES_T(ed, g, TG)
  172. {
  173. put(edge_index, g, ed, i++);
  174. }
  175. }
  176. template <typename TG>
  177. void read_data(const char *file, TG &g)
  178. {
  179. std::cout << "Reading data from file: " << file << std::endl;
  180. std::ifstream ifs(file);
  181. BOOST_REQUIRE(ifs.good());
  182. read_data1(ifs, g);
  183. }
  184. struct my_float : boost::mcr_float<>
  185. {
  186. static double infinity()
  187. {
  188. return 1000;
  189. }
  190. };
  191. struct my_float2 : boost::mcr_float<>
  192. {
  193. static double infinity() { return 2; }
  194. };
  195. int test_main(int argc, char* argv[])
  196. {
  197. assert (argc >= 2);
  198. using std::endl; using std::cout;
  199. const double epsilon = 0.005;
  200. double min_cr, max_cr; ///Minimum and maximum cycle ratio
  201. typedef std::vector<graph_traits<diGraphInt>::edge_descriptor> ccInt_t;
  202. typedef std::vector<graph_traits<diGraphReal>::edge_descriptor> ccReal_t;
  203. ccInt_t cc; ///critical cycle
  204. diGraphInt tg;
  205. property_map<diGraphInt, vertex_index_t>::type vim = get(vertex_index, tg);
  206. property_map<diGraphInt, edge_weight_t>::type ew1m = get(edge_weight, tg);
  207. property_map<diGraphInt, edge_weight2_t>::type ew2m = get(edge_weight2, tg);
  208. {
  209. std::istringstream iss(test_graph1);
  210. assert(iss.good());
  211. read_data1(iss, tg);
  212. max_cr = maximum_cycle_ratio(tg, vim, ew1m, ew2m);
  213. cout << "Maximum cycle ratio is " << max_cr << endl;
  214. BOOST_CHECK(std::abs( max_cr - 0.666666666) < epsilon );
  215. tg.clear();
  216. }
  217. {
  218. std::istringstream iss(test_graph2);
  219. read_data1(iss, tg);
  220. // TODO: This is causing a failuire, but I'm not really sure what it's doing per se.
  221. // Commented out for now.
  222. // BOOST_CHECK(std::abs(maximum_cycle_ratio(tg, vim, ew1m, ew2m) + (std::numeric_limits<double>::max)()) < epsilon );
  223. BOOST_CHECK(std::abs(boost::maximum_cycle_ratio(tg, vim, ew1m, ew2m,
  224. static_cast<ccInt_t*>(0), my_float()) + 1000) < epsilon );
  225. tg.clear();
  226. }
  227. {
  228. std::istringstream iss(test_graph3);
  229. diGraphInt tgi;
  230. read_data1(iss, tgi);
  231. double max_cr = maximum_cycle_ratio(tgi, vim, ew1m, ew2m,
  232. static_cast<ccInt_t*>(0));
  233. cout << "Maximum cycle ratio is " << max_cr << endl;
  234. BOOST_CHECK(std::abs( max_cr - 2.75) < epsilon );
  235. double maxmc = maximum_cycle_mean(tgi, vim, ew1m, get(edge_index, tgi));
  236. cout << "Maximum cycle mean is " << maxmc << endl;
  237. BOOST_CHECK(std::abs( maxmc - 5.5) < epsilon );
  238. tg.clear();
  239. }
  240. {
  241. std::istringstream iss(test_graph4);
  242. read_data1(iss, tg);
  243. max_cr = maximum_cycle_ratio(tg, vim, ew1m, ew2m);
  244. cout << "Maximum cycle ratio is " << max_cr << endl;
  245. BOOST_CHECK(std::abs( max_cr - 2.5) < epsilon );
  246. min_cr = minimum_cycle_ratio(tg, vim, ew1m, ew2m);
  247. cout << "Minimum cycle ratio is " << min_cr << endl;
  248. BOOST_CHECK(std::abs( min_cr - 0.5) < epsilon );
  249. tg.clear();
  250. }
  251. {
  252. std::istringstream iss(test_graph5);
  253. read_data1(iss, tg);
  254. min_cr = minimum_cycle_ratio(tg, vim, ew1m, ew2m, &cc, my_float());
  255. BOOST_CHECK(std::abs( min_cr - 0.666666666) < epsilon );
  256. cout << "Minimum cycle ratio is " << min_cr << endl;
  257. cout << "Critical cycle is:\n";
  258. for (ccInt_t::iterator itr = cc.begin(); itr != cc.end(); ++itr)
  259. {
  260. cout << "(" << get(vertex_name, tg, source(*itr, tg)) <<
  261. "," << get(vertex_name, tg, target(*itr, tg)) << ") ";
  262. }
  263. cout << endl;
  264. tg.clear();
  265. }
  266. {
  267. read_data(argv[1], tg);
  268. min_cr = boost::minimum_cycle_ratio(tg, vim, ew1m, ew2m, &cc, my_float2());
  269. cout << "Minimum cycle ratio is " << min_cr << endl;
  270. BOOST_CHECK(std::abs(min_cr - 0.33333333333) < epsilon );
  271. cout << "Critical cycle is:" << endl;
  272. for (ccInt_t::iterator it = cc.begin(); it != cc.end(); ++it)
  273. {
  274. cout << "(" << get(vertex_name, tg, source(*it, tg)) << "," <<
  275. get(vertex_name, tg, target(*it, tg)) << ") ";
  276. }
  277. cout << endl;
  278. tg.clear();
  279. }
  280. {
  281. diGraphReal tgr;
  282. ccReal_t cc1;
  283. std::istringstream iss(test_graph6);
  284. read_data1(iss, tgr);
  285. max_cr = maximum_cycle_ratio(tgr, get(vertex_index, tgr), get(edge_weight, tgr), get(edge_weight2, tgr));
  286. cout << "Maximum cycle ratio is " << max_cr << endl;
  287. min_cr = minimum_cycle_ratio(tgr, get(vertex_index, tgr), get(edge_weight, tgr),
  288. get(edge_weight2, tgr), &cc);
  289. cout << "Minimal cycle ratio is " << min_cr << endl;
  290. std::pair<double, double> cr(.0,.0);
  291. cout << "Critical cycle is:\n";
  292. for (ccReal_t::iterator itr = cc.begin(); itr != cc.end(); ++itr)
  293. {
  294. cr.first += get(edge_weight, tgr, *itr); cr.second += get(edge_weight2, tgr, *itr);
  295. cout << "(" << get(vertex_name, tgr, source(*itr, tgr)) << "," <<
  296. get(vertex_name, tgr, target(*itr, tgr)) << ") ";
  297. }
  298. BOOST_CHECK(std::abs(cr.first / cr.second - min_cr) < epsilon);
  299. cout << endl;
  300. }
  301. {
  302. GraphMInt gm(10);
  303. typedef graph_traits<GraphMInt>::vertex_iterator VertexItM;
  304. VertexItM vi1, vi2, vi_end;
  305. for (boost::tie(vi1, vi_end) = vertices(gm); vi1 != vi_end; ++vi1)
  306. {
  307. for (vi2 = vertices(gm).first; vi2 != vi_end; ++vi2)
  308. add_edge(*vi1, *vi2, gm);
  309. }
  310. max_cr = maximum_cycle_ratio(gm, get(vertex_index, gm),
  311. get(&CEdgeProps<int, int>::m_w1, gm), get(&CEdgeProps<int, int>::m_w2, gm));
  312. BOOST_CHECK(std::abs(max_cr - 0.5) < epsilon);
  313. }
  314. return 0;
  315. }