You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

330 lines
11 KiB

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