glpapi16.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. /* glpapi16.c (graph and network analysis routines) */
  2. /***********************************************************************
  3. * This code is part of GLPK (GNU Linear Programming Kit).
  4. *
  5. * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
  6. * 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
  7. * Moscow Aviation Institute, Moscow, Russia. All rights reserved.
  8. * E-mail: <mao@gnu.org>.
  9. *
  10. * GLPK is free software: you can redistribute it and/or modify it
  11. * under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation, either version 3 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * GLPK is distributed in the hope that it will be useful, but WITHOUT
  16. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  17. * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  18. * License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with GLPK. If not, see <http://www.gnu.org/licenses/>.
  22. ***********************************************************************/
  23. #include "glpapi.h"
  24. #include "glpnet.h"
  25. /***********************************************************************
  26. * NAME
  27. *
  28. * glp_weak_comp - find all weakly connected components of graph
  29. *
  30. * SYNOPSIS
  31. *
  32. * int glp_weak_comp(glp_graph *G, int v_num);
  33. *
  34. * DESCRIPTION
  35. *
  36. * The routine glp_weak_comp finds all weakly connected components of
  37. * the specified graph.
  38. *
  39. * The parameter v_num specifies an offset of the field of type int
  40. * in the vertex data block, to which the routine stores the number of
  41. * a (weakly) connected component containing that vertex. If v_num < 0,
  42. * no component numbers are stored.
  43. *
  44. * The components are numbered in arbitrary order from 1 to nc, where
  45. * nc is the total number of components found, 0 <= nc <= |V|.
  46. *
  47. * RETURNS
  48. *
  49. * The routine returns nc, the total number of components found. */
  50. int glp_weak_comp(glp_graph *G, int v_num)
  51. { glp_vertex *v;
  52. glp_arc *a;
  53. int f, i, j, nc, nv, pos1, pos2, *prev, *next, *list;
  54. if (v_num >= 0 && v_num > G->v_size - (int)sizeof(int))
  55. xerror("glp_weak_comp: v_num = %d; invalid offset\n", v_num);
  56. nv = G->nv;
  57. if (nv == 0)
  58. { nc = 0;
  59. goto done;
  60. }
  61. /* allocate working arrays */
  62. prev = xcalloc(1+nv, sizeof(int));
  63. next = xcalloc(1+nv, sizeof(int));
  64. list = xcalloc(1+nv, sizeof(int));
  65. /* if vertex i is unlabelled, prev[i] is the index of previous
  66. unlabelled vertex, and next[i] is the index of next unlabelled
  67. vertex; if vertex i is labelled, then prev[i] < 0, and next[i]
  68. is the connected component number */
  69. /* initially all vertices are unlabelled */
  70. f = 1;
  71. for (i = 1; i <= nv; i++)
  72. prev[i] = i - 1, next[i] = i + 1;
  73. next[nv] = 0;
  74. /* main loop (until all vertices have been labelled) */
  75. nc = 0;
  76. while (f != 0)
  77. { /* take an unlabelled vertex */
  78. i = f;
  79. /* and remove it from the list of unlabelled vertices */
  80. f = next[i];
  81. if (f != 0) prev[f] = 0;
  82. /* label the vertex; it begins a new component */
  83. prev[i] = -1, next[i] = ++nc;
  84. /* breadth first search */
  85. list[1] = i, pos1 = pos2 = 1;
  86. while (pos1 <= pos2)
  87. { /* dequeue vertex i */
  88. i = list[pos1++];
  89. /* consider all arcs incoming to vertex i */
  90. for (a = G->v[i]->in; a != NULL; a = a->h_next)
  91. { /* vertex j is adjacent to vertex i */
  92. j = a->tail->i;
  93. if (prev[j] >= 0)
  94. { /* vertex j is unlabelled */
  95. /* remove it from the list of unlabelled vertices */
  96. if (prev[j] == 0)
  97. f = next[j];
  98. else
  99. next[prev[j]] = next[j];
  100. if (next[j] == 0)
  101. ;
  102. else
  103. prev[next[j]] = prev[j];
  104. /* label the vertex */
  105. prev[j] = -1, next[j] = nc;
  106. /* and enqueue it for further consideration */
  107. list[++pos2] = j;
  108. }
  109. }
  110. /* consider all arcs outgoing from vertex i */
  111. for (a = G->v[i]->out; a != NULL; a = a->t_next)
  112. { /* vertex j is adjacent to vertex i */
  113. j = a->head->i;
  114. if (prev[j] >= 0)
  115. { /* vertex j is unlabelled */
  116. /* remove it from the list of unlabelled vertices */
  117. if (prev[j] == 0)
  118. f = next[j];
  119. else
  120. next[prev[j]] = next[j];
  121. if (next[j] == 0)
  122. ;
  123. else
  124. prev[next[j]] = prev[j];
  125. /* label the vertex */
  126. prev[j] = -1, next[j] = nc;
  127. /* and enqueue it for further consideration */
  128. list[++pos2] = j;
  129. }
  130. }
  131. }
  132. }
  133. /* store component numbers */
  134. if (v_num >= 0)
  135. { for (i = 1; i <= nv; i++)
  136. { v = G->v[i];
  137. memcpy((char *)v->data + v_num, &next[i], sizeof(int));
  138. }
  139. }
  140. /* free working arrays */
  141. xfree(prev);
  142. xfree(next);
  143. xfree(list);
  144. done: return nc;
  145. }
  146. /***********************************************************************
  147. * NAME
  148. *
  149. * glp_strong_comp - find all strongly connected components of graph
  150. *
  151. * SYNOPSIS
  152. *
  153. * int glp_strong_comp(glp_graph *G, int v_num);
  154. *
  155. * DESCRIPTION
  156. *
  157. * The routine glp_strong_comp finds all strongly connected components
  158. * of the specified graph.
  159. *
  160. * The parameter v_num specifies an offset of the field of type int
  161. * in the vertex data block, to which the routine stores the number of
  162. * a strongly connected component containing that vertex. If v_num < 0,
  163. * no component numbers are stored.
  164. *
  165. * The components are numbered in arbitrary order from 1 to nc, where
  166. * nc is the total number of components found, 0 <= nc <= |V|. However,
  167. * the component numbering has the property that for every arc (i->j)
  168. * in the graph the condition num(i) >= num(j) holds.
  169. *
  170. * RETURNS
  171. *
  172. * The routine returns nc, the total number of components found. */
  173. int glp_strong_comp(glp_graph *G, int v_num)
  174. { glp_vertex *v;
  175. glp_arc *a;
  176. int i, k, last, n, na, nc, *icn, *ip, *lenr, *ior, *ib, *lowl,
  177. *numb, *prev;
  178. if (v_num >= 0 && v_num > G->v_size - (int)sizeof(int))
  179. xerror("glp_strong_comp: v_num = %d; invalid offset\n",
  180. v_num);
  181. n = G->nv;
  182. if (n == 0)
  183. { nc = 0;
  184. goto done;
  185. }
  186. na = G->na;
  187. icn = xcalloc(1+na, sizeof(int));
  188. ip = xcalloc(1+n, sizeof(int));
  189. lenr = xcalloc(1+n, sizeof(int));
  190. ior = xcalloc(1+n, sizeof(int));
  191. ib = xcalloc(1+n, sizeof(int));
  192. lowl = xcalloc(1+n, sizeof(int));
  193. numb = xcalloc(1+n, sizeof(int));
  194. prev = xcalloc(1+n, sizeof(int));
  195. k = 1;
  196. for (i = 1; i <= n; i++)
  197. { v = G->v[i];
  198. ip[i] = k;
  199. for (a = v->out; a != NULL; a = a->t_next)
  200. icn[k++] = a->head->i;
  201. lenr[i] = k - ip[i];
  202. }
  203. xassert(na == k-1);
  204. nc = mc13d(n, icn, ip, lenr, ior, ib, lowl, numb, prev);
  205. if (v_num >= 0)
  206. { xassert(ib[1] == 1);
  207. for (k = 1; k <= nc; k++)
  208. { last = (k < nc ? ib[k+1] : n+1);
  209. xassert(ib[k] < last);
  210. for (i = ib[k]; i < last; i++)
  211. { v = G->v[ior[i]];
  212. memcpy((char *)v->data + v_num, &k, sizeof(int));
  213. }
  214. }
  215. }
  216. xfree(icn);
  217. xfree(ip);
  218. xfree(lenr);
  219. xfree(ior);
  220. xfree(ib);
  221. xfree(lowl);
  222. xfree(numb);
  223. xfree(prev);
  224. done: return nc;
  225. }
  226. /***********************************************************************
  227. * NAME
  228. *
  229. * glp_top_sort - topological sorting of acyclic digraph
  230. *
  231. * SYNOPSIS
  232. *
  233. * int glp_top_sort(glp_graph *G, int v_num);
  234. *
  235. * DESCRIPTION
  236. *
  237. * The routine glp_top_sort performs topological sorting of vertices of
  238. * the specified acyclic digraph.
  239. *
  240. * The parameter v_num specifies an offset of the field of type int in
  241. * the vertex data block, to which the routine stores the vertex number
  242. * assigned. If v_num < 0, vertex numbers are not stored.
  243. *
  244. * The vertices are numbered from 1 to n, where n is the total number
  245. * of vertices in the graph. The vertex numbering has the property that
  246. * for every arc (i->j) in the graph the condition num(i) < num(j)
  247. * holds. Special case num(i) = 0 means that vertex i is not assigned a
  248. * number, because the graph is *not* acyclic.
  249. *
  250. * RETURNS
  251. *
  252. * If the graph is acyclic and therefore all the vertices have been
  253. * assigned numbers, the routine glp_top_sort returns zero. Otherwise,
  254. * if the graph is not acyclic, the routine returns the number of
  255. * vertices which have not been numbered, i.e. for which num(i) = 0. */
  256. static int top_sort(glp_graph *G, int num[])
  257. { glp_arc *a;
  258. int i, j, cnt, top, *stack, *indeg;
  259. /* allocate working arrays */
  260. indeg = xcalloc(1+G->nv, sizeof(int));
  261. stack = xcalloc(1+G->nv, sizeof(int));
  262. /* determine initial indegree of each vertex; push into the stack
  263. the vertices having zero indegree */
  264. top = 0;
  265. for (i = 1; i <= G->nv; i++)
  266. { num[i] = indeg[i] = 0;
  267. for (a = G->v[i]->in; a != NULL; a = a->h_next)
  268. indeg[i]++;
  269. if (indeg[i] == 0)
  270. stack[++top] = i;
  271. }
  272. /* assign numbers to vertices in the sorted order */
  273. cnt = 0;
  274. while (top > 0)
  275. { /* pull vertex i from the stack */
  276. i = stack[top--];
  277. /* it has zero indegree in the current graph */
  278. xassert(indeg[i] == 0);
  279. /* so assign it a next number */
  280. xassert(num[i] == 0);
  281. num[i] = ++cnt;
  282. /* remove vertex i from the current graph, update indegree of
  283. its adjacent vertices, and push into the stack new vertices
  284. whose indegree becomes zero */
  285. for (a = G->v[i]->out; a != NULL; a = a->t_next)
  286. { j = a->head->i;
  287. /* there exists arc (i->j) in the graph */
  288. xassert(indeg[j] > 0);
  289. indeg[j]--;
  290. if (indeg[j] == 0)
  291. stack[++top] = j;
  292. }
  293. }
  294. /* free working arrays */
  295. xfree(indeg);
  296. xfree(stack);
  297. return G->nv - cnt;
  298. }
  299. int glp_top_sort(glp_graph *G, int v_num)
  300. { glp_vertex *v;
  301. int i, cnt, *num;
  302. if (v_num >= 0 && v_num > G->v_size - (int)sizeof(int))
  303. xerror("glp_top_sort: v_num = %d; invalid offset\n", v_num);
  304. if (G->nv == 0)
  305. { cnt = 0;
  306. goto done;
  307. }
  308. num = xcalloc(1+G->nv, sizeof(int));
  309. cnt = top_sort(G, num);
  310. if (v_num >= 0)
  311. { for (i = 1; i <= G->nv; i++)
  312. { v = G->v[i];
  313. memcpy((char *)v->data + v_num, &num[i], sizeof(int));
  314. }
  315. }
  316. xfree(num);
  317. done: return cnt;
  318. }
  319. /* eof */