1 /* glpapi16.c (graph and network analysis routines) */
3 /***********************************************************************
4 * This code is part of GLPK (GNU Linear Programming Kit).
6 * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
7 * 2009, 2010 Andrew Makhorin, Department for Applied Informatics,
8 * Moscow Aviation Institute, Moscow, Russia. All rights reserved.
9 * E-mail: <mao@gnu.org>.
11 * GLPK is free software: you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by
13 * the Free Software Foundation, either version 3 of the License, or
14 * (at your option) any later version.
16 * GLPK is distributed in the hope that it will be useful, but WITHOUT
17 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
19 * License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with GLPK. If not, see <http://www.gnu.org/licenses/>.
23 ***********************************************************************/
28 /***********************************************************************
31 * glp_weak_comp - find all weakly connected components of graph
35 * int glp_weak_comp(glp_graph *G, int v_num);
39 * The routine glp_weak_comp finds all weakly connected components of
40 * the specified graph.
42 * The parameter v_num specifies an offset of the field of type int
43 * in the vertex data block, to which the routine stores the number of
44 * a (weakly) connected component containing that vertex. If v_num < 0,
45 * no component numbers are stored.
47 * The components are numbered in arbitrary order from 1 to nc, where
48 * nc is the total number of components found, 0 <= nc <= |V|.
52 * The routine returns nc, the total number of components found. */
54 int glp_weak_comp(glp_graph *G, int v_num)
57 int f, i, j, nc, nv, pos1, pos2, *prev, *next, *list;
58 if (v_num >= 0 && v_num > G->v_size - (int)sizeof(int))
59 xerror("glp_weak_comp: v_num = %d; invalid offset\n", v_num);
65 /* allocate working arrays */
66 prev = xcalloc(1+nv, sizeof(int));
67 next = xcalloc(1+nv, sizeof(int));
68 list = xcalloc(1+nv, sizeof(int));
69 /* if vertex i is unlabelled, prev[i] is the index of previous
70 unlabelled vertex, and next[i] is the index of next unlabelled
71 vertex; if vertex i is labelled, then prev[i] < 0, and next[i]
72 is the connected component number */
73 /* initially all vertices are unlabelled */
75 for (i = 1; i <= nv; i++)
76 prev[i] = i - 1, next[i] = i + 1;
78 /* main loop (until all vertices have been labelled) */
81 { /* take an unlabelled vertex */
83 /* and remove it from the list of unlabelled vertices */
85 if (f != 0) prev[f] = 0;
86 /* label the vertex; it begins a new component */
87 prev[i] = -1, next[i] = ++nc;
88 /* breadth first search */
89 list[1] = i, pos1 = pos2 = 1;
91 { /* dequeue vertex i */
93 /* consider all arcs incoming to vertex i */
94 for (a = G->v[i]->in; a != NULL; a = a->h_next)
95 { /* vertex j is adjacent to vertex i */
98 { /* vertex j is unlabelled */
99 /* remove it from the list of unlabelled vertices */
103 next[prev[j]] = next[j];
107 prev[next[j]] = prev[j];
108 /* label the vertex */
109 prev[j] = -1, next[j] = nc;
110 /* and enqueue it for further consideration */
114 /* consider all arcs outgoing from vertex i */
115 for (a = G->v[i]->out; a != NULL; a = a->t_next)
116 { /* vertex j is adjacent to vertex i */
119 { /* vertex j is unlabelled */
120 /* remove it from the list of unlabelled vertices */
124 next[prev[j]] = next[j];
128 prev[next[j]] = prev[j];
129 /* label the vertex */
130 prev[j] = -1, next[j] = nc;
131 /* and enqueue it for further consideration */
137 /* store component numbers */
139 { for (i = 1; i <= nv; i++)
141 memcpy((char *)v->data + v_num, &next[i], sizeof(int));
144 /* free working arrays */
151 /***********************************************************************
154 * glp_strong_comp - find all strongly connected components of graph
158 * int glp_strong_comp(glp_graph *G, int v_num);
162 * The routine glp_strong_comp finds all strongly connected components
163 * of the specified graph.
165 * The parameter v_num specifies an offset of the field of type int
166 * in the vertex data block, to which the routine stores the number of
167 * a strongly connected component containing that vertex. If v_num < 0,
168 * no component numbers are stored.
170 * The components are numbered in arbitrary order from 1 to nc, where
171 * nc is the total number of components found, 0 <= nc <= |V|. However,
172 * the component numbering has the property that for every arc (i->j)
173 * in the graph the condition num(i) >= num(j) holds.
177 * The routine returns nc, the total number of components found. */
179 int glp_strong_comp(glp_graph *G, int v_num)
182 int i, k, last, n, na, nc, *icn, *ip, *lenr, *ior, *ib, *lowl,
184 if (v_num >= 0 && v_num > G->v_size - (int)sizeof(int))
185 xerror("glp_strong_comp: v_num = %d; invalid offset\n",
193 icn = xcalloc(1+na, sizeof(int));
194 ip = xcalloc(1+n, sizeof(int));
195 lenr = xcalloc(1+n, sizeof(int));
196 ior = xcalloc(1+n, sizeof(int));
197 ib = xcalloc(1+n, sizeof(int));
198 lowl = xcalloc(1+n, sizeof(int));
199 numb = xcalloc(1+n, sizeof(int));
200 prev = xcalloc(1+n, sizeof(int));
202 for (i = 1; i <= n; i++)
205 for (a = v->out; a != NULL; a = a->t_next)
206 icn[k++] = a->head->i;
210 nc = mc13d(n, icn, ip, lenr, ior, ib, lowl, numb, prev);
212 { xassert(ib[1] == 1);
213 for (k = 1; k <= nc; k++)
214 { last = (k < nc ? ib[k+1] : n+1);
215 xassert(ib[k] < last);
216 for (i = ib[k]; i < last; i++)
218 memcpy((char *)v->data + v_num, &k, sizeof(int));
233 /***********************************************************************
236 * glp_top_sort - topological sorting of acyclic digraph
240 * int glp_top_sort(glp_graph *G, int v_num);
244 * The routine glp_top_sort performs topological sorting of vertices of
245 * the specified acyclic digraph.
247 * The parameter v_num specifies an offset of the field of type int in
248 * the vertex data block, to which the routine stores the vertex number
249 * assigned. If v_num < 0, vertex numbers are not stored.
251 * The vertices are numbered from 1 to n, where n is the total number
252 * of vertices in the graph. The vertex numbering has the property that
253 * for every arc (i->j) in the graph the condition num(i) < num(j)
254 * holds. Special case num(i) = 0 means that vertex i is not assigned a
255 * number, because the graph is *not* acyclic.
259 * If the graph is acyclic and therefore all the vertices have been
260 * assigned numbers, the routine glp_top_sort returns zero. Otherwise,
261 * if the graph is not acyclic, the routine returns the number of
262 * vertices which have not been numbered, i.e. for which num(i) = 0. */
264 static int top_sort(glp_graph *G, int num[])
266 int i, j, cnt, top, *stack, *indeg;
267 /* allocate working arrays */
268 indeg = xcalloc(1+G->nv, sizeof(int));
269 stack = xcalloc(1+G->nv, sizeof(int));
270 /* determine initial indegree of each vertex; push into the stack
271 the vertices having zero indegree */
273 for (i = 1; i <= G->nv; i++)
274 { num[i] = indeg[i] = 0;
275 for (a = G->v[i]->in; a != NULL; a = a->h_next)
280 /* assign numbers to vertices in the sorted order */
283 { /* pull vertex i from the stack */
285 /* it has zero indegree in the current graph */
286 xassert(indeg[i] == 0);
287 /* so assign it a next number */
288 xassert(num[i] == 0);
290 /* remove vertex i from the current graph, update indegree of
291 its adjacent vertices, and push into the stack new vertices
292 whose indegree becomes zero */
293 for (a = G->v[i]->out; a != NULL; a = a->t_next)
295 /* there exists arc (i->j) in the graph */
296 xassert(indeg[j] > 0);
302 /* free working arrays */
308 int glp_top_sort(glp_graph *G, int v_num)
311 if (v_num >= 0 && v_num > G->v_size - (int)sizeof(int))
312 xerror("glp_top_sort: v_num = %d; invalid offset\n", v_num);
317 num = xcalloc(1+G->nv, sizeof(int));
318 cnt = top_sort(G, num);
320 { for (i = 1; i <= G->nv; i++)
322 memcpy((char *)v->data + v_num, &num[i], sizeof(int));