Graphviz 13.0.0~dev.20241220.2304
Loading...
Searching...
No Matches
ccomps.c
Go to the documentation of this file.
1/*************************************************************************
2 * Copyright (c) 2011 AT&T Intellectual Property
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors: Details at https://graphviz.org
9 *************************************************************************/
10
11#include <cgraph/cgraph.h>
12#include <cgraph/list.h>
13#include <common/render.h>
14#include <common/utils.h>
15#include <limits.h>
16#include <pack/pack.h>
17#include <stdbool.h>
18#include <stdlib.h>
19#include <util/agxbuf.h>
20#include <util/alloc.h>
21#include <util/gv_ctype.h>
22#include <util/prisize_t.h>
23
24DEFINE_LIST(node_stack, Agnode_t *)
25
26typedef struct {
27 node_stack_t data;
28 void (*actionfn)(Agnode_t *, void *);
29 bool (*markfn)(Agnode_t *, int);
30} stk_t;
31
33static bool marked(const stk_t *stk, Agnode_t *n) { return stk->markfn(n, -1); }
34
36static void mark(const stk_t *stk, Agnode_t *n) { stk->markfn(n, 1); }
37
39static void unmark(const stk_t *stk, Agnode_t *n) { stk->markfn(n, 0); }
40
41static void initStk(stk_t *sp, void (*actionfn)(Agnode_t *, void *),
42 bool (*markfn)(Agnode_t *, int)) {
43 sp->data = (node_stack_t){0};
44 sp->actionfn = actionfn;
45 sp->markfn = markfn;
46}
47
48static void freeStk(stk_t *sp) { node_stack_free(&sp->data); }
49
50static void push(stk_t *sp, Agnode_t *np) {
51 mark(sp, np);
52 node_stack_push_back(&sp->data, np);
53}
54
55static Agnode_t *pop(stk_t *sp) {
56 if (node_stack_is_empty(&sp->data)) {
57 return NULL;
58 }
59
60 return node_stack_pop_back(&sp->data);
61}
62
63static size_t dfs(Agraph_t *g, Agnode_t *n, void *state, stk_t *stk) {
64 Agedge_t *e;
65 Agnode_t *other;
66 size_t cnt = 0;
67
68 push(stk, n);
69 while ((n = pop(stk))) {
70 cnt++;
71 if (stk->actionfn)
72 stk->actionfn(n, state);
73 for (e = agfstedge(g, n); e; e = agnxtedge(g, e, n)) {
74 if ((other = agtail(e)) == n)
75 other = aghead(e);
76 if (!marked(stk, other))
77 push(stk, other);
78 }
79 }
80 return cnt;
81}
82
83static bool isLegal(const char *p) {
84 char c;
85
86 while ((c = *p++)) {
87 if (c != '_' && !gv_isalnum(c))
88 return false;
89 }
90
91 return true;
92}
93
94static void insertFn(Agnode_t *n, void *state) { agsubnode(state, n, 1); }
95
96static bool markFn(Agnode_t *n, int v) {
97 if (v < 0)
98 return ND_mark(n) != 0;
99 const size_t ret = ND_mark(n);
100 ND_mark(n) = v != 0;
101 return ret != 0;
102}
103
104static void setPrefix(agxbuf *xb, const char *pfx) {
105 if (!pfx || !isLegal(pfx)) {
106 pfx = "_cc_";
107 }
108 agxbput(xb, pfx);
109}
110
111DEFINE_LIST(Agraphs, Agraph_t *)
112
113/* pccomps:
114 * Return an array of subgraphs consisting of the connected
115 * components of graph g. The number of components is returned in ncc.
116 * All pinned nodes are in one component.
117 * If pfx is non-null and a legal graph name, we use it as the prefix
118 * for the name of the subgraphs created. If not, a simple default is used.
119 * If pinned is non-null, *pinned set to 1 if pinned nodes found
120 * and the first component is the one containing the pinned nodes.
121 * Note that the component subgraphs do not contain any edges. These must
122 * be obtained from the root graph.
123 * Return NULL if graph is empty.
124 */
125Agraph_t **pccomps(Agraph_t *g, size_t *ncc, char *pfx, bool *pinned) {
126 agxbuf name = {0};
127 Agraph_t *out = NULL;
128 Agnode_t *n;
129 bool pin = false;
130 stk_t stk;
131
132 if (agnnodes(g) == 0) {
133 *ncc = 0;
134 return NULL;
135 }
136
137 Agraphs_t ccs = {0};
138
139 initStk(&stk, insertFn, markFn);
140 for (n = agfstnode(g); n; n = agnxtnode(g, n))
141 unmark(&stk, n);
142
143 /* Component with pinned nodes */
144 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
145 if (marked(&stk, n) || !isPinned(n))
146 continue;
147 if (!out) {
148 setPrefix(&name, pfx);
149 agxbprint(&name, "%" PRISIZE_T, Agraphs_size(&ccs));
150 out = agsubg(g, agxbuse(&name), 1);
151 agbindrec(out, "Agraphinfo_t", sizeof(Agraphinfo_t),
152 true); // node custom data
153 Agraphs_append(&ccs, out);
154 pin = true;
155 }
156 dfs(g, n, out, &stk);
157 }
158
159 /* Remaining nodes */
160 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
161 if (marked(&stk, n))
162 continue;
163 setPrefix(&name, pfx);
164 agxbprint(&name, "%" PRISIZE_T, Agraphs_size(&ccs));
165 out = agsubg(g, agxbuse(&name), 1);
166 agbindrec(out, "Agraphinfo_t", sizeof(Agraphinfo_t),
167 true); // node custom data
168 dfs(g, n, out, &stk);
169 Agraphs_append(&ccs, out);
170 }
171 freeStk(&stk);
172 agxbfree(&name);
173 *ncc = Agraphs_size(&ccs);
174 *pinned = pin;
175 return Agraphs_detach(&ccs);
176}
177
178/* ccomps:
179 * Return an array of subgraphs consisting of the connected
180 * components of graph g. The number of components is returned in ncc.
181 * If pfx is non-null and a legal graph name, we use it as the prefix
182 * for the name of the subgraphs created. If not, a simple default is used.
183 * Note that the component subgraphs do not contain any edges. These must
184 * be obtained from the root graph.
185 * Returns NULL on error or if graph is empty.
186 */
187Agraph_t **ccomps(Agraph_t *g, size_t *ncc, char *pfx) {
188 agxbuf name = {0};
189 Agraph_t *out;
190 Agnode_t *n;
191 stk_t stk;
192
193 if (agnnodes(g) == 0) {
194 *ncc = 0;
195 return NULL;
196 }
197
198 Agraphs_t ccs = {0};
199 initStk(&stk, insertFn, markFn);
200 for (n = agfstnode(g); n; n = agnxtnode(g, n))
201 unmark(&stk, n);
202
203 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
204 if (marked(&stk, n))
205 continue;
206 setPrefix(&name, pfx);
207 agxbprint(&name, "%" PRISIZE_T, Agraphs_size(&ccs));
208 out = agsubg(g, agxbuse(&name), 1);
209 agbindrec(out, "Agraphinfo_t", sizeof(Agraphinfo_t),
210 true); // node custom data
211 dfs(g, n, out, &stk);
212 Agraphs_append(&ccs, out);
213 }
214 freeStk(&stk);
215 agxbfree(&name);
216 *ncc = Agraphs_size(&ccs);
217 return Agraphs_detach(&ccs);
218}
219
220typedef struct {
222 char cc_subg; /* true iff subgraph corresponds to a component */
224
225typedef struct {
227 char mark;
228 union {
231 void *v;
232 } ptr;
234
235#define GRECNAME "ccgraphinfo"
236#define NRECNAME "ccgnodeinfo"
237#define GD_cc_subg(g) (((ccgraphinfo_t *)aggetrec(g, GRECNAME, 0))->cc_subg)
238#ifdef DEBUG
241 if (ip)
242 return ip->ptr.n;
243 fprintf(stderr, "nodeinfo undefined\n");
244 return NULL;
245}
246void dnodeSet(Agnode_t *v, Agnode_t *n) {
247 ((ccgnodeinfo_t *)aggetrec(v, NRECNAME, 0))->ptr.n = n;
248}
249#else
250#define dnodeOf(v) (((ccgnodeinfo_t *)aggetrec(v, NRECNAME, 0))->ptr.n)
251#define dnodeSet(v, w) (((ccgnodeinfo_t *)aggetrec(v, NRECNAME, 0))->ptr.n = w)
252#endif
253
254#define ptrOf(np) (((ccgnodeinfo_t *)((np)->base.data))->ptr.v)
255#define nodeOf(np) (((ccgnodeinfo_t *)((np)->base.data))->ptr.n)
256#define clustOf(np) (((ccgnodeinfo_t *)((np)->base.data))->ptr.g)
257#define clMark(n) (((ccgnodeinfo_t *)(n->base.data))->mark)
258
259/* deriveClusters:
260 * Construct nodes in derived graph corresponding top-level clusters.
261 * Since a cluster might be wrapped in a subgraph, we need to traverse
262 * down into the tree of subgraphs
263 */
264static void deriveClusters(Agraph_t *dg, Agraph_t *g) {
265 Agraph_t *subg;
266 Agnode_t *dn;
267 Agnode_t *n;
268
269 for (subg = agfstsubg(g); subg; subg = agnxtsubg(subg)) {
270 if (is_a_cluster(subg)) {
271 dn = agnode(dg, agnameof(subg), 1);
272 agbindrec(dn, NRECNAME, sizeof(ccgnodeinfo_t), true);
273 clustOf(dn) = subg;
274 for (n = agfstnode(subg); n; n = agnxtnode(subg, n)) {
275 if (dnodeOf(n)) {
276 fprintf(stderr,
277 "Error: node \"%s\" belongs to two non-nested clusters "
278 "\"%s\" and \"%s\"\n",
279 agnameof(n), agnameof(subg), agnameof(dnodeOf(n)));
280 }
281 dnodeSet(n, dn);
282 }
283 } else {
284 deriveClusters(dg, subg);
285 }
286 }
287}
288
289/* deriveGraph:
290 * Create derived graph dg of g where nodes correspond to top-level nodes
291 * or clusters, and there is an edge in dg if there is an edge in g
292 * between any nodes in the respective clusters.
293 */
295 Agraph_t *dg;
296 Agnode_t *dn;
297 Agnode_t *n;
298
299 dg = agopen("dg", Agstrictundirected, NULL);
300
301 deriveClusters(dg, g);
302
303 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
304 if (dnodeOf(n))
305 continue;
306 dn = agnode(dg, agnameof(n), 1);
307 agbindrec(dn, NRECNAME, sizeof(ccgnodeinfo_t), true);
308 nodeOf(dn) = n;
309 dnodeSet(n, dn);
310 }
311
312 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
313 Agedge_t *e;
314 Agnode_t *hd;
315 Agnode_t *tl = dnodeOf(n);
316 for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
317 hd = aghead(e);
318 hd = dnodeOf(hd);
319 if (hd == tl)
320 continue;
321 if (hd > tl)
322 agedge(dg, tl, hd, NULL, 1);
323 else
324 agedge(dg, hd, tl, NULL, 1);
325 }
326 }
327
328 return dg;
329}
330
331/* unionNodes:
332 * Add all nodes in cluster nodes of dg to g
333 */
334static void unionNodes(Agraph_t *dg, Agraph_t *g) {
335 Agnode_t *n;
336 Agnode_t *dn;
337 Agraph_t *clust;
338
339 for (dn = agfstnode(dg); dn; dn = agnxtnode(dg, dn)) {
340 if (AGTYPE(ptrOf(dn)) == AGNODE) {
341 agsubnode(g, nodeOf(dn), 1);
342 } else {
343 clust = clustOf(dn);
344 for (n = agfstnode(clust); n; n = agnxtnode(clust, n))
345 agsubnode(g, n, 1);
346 }
347 }
348}
349
350static bool clMarkFn(Agnode_t *n, int v) {
351 int ret;
352 if (v < 0)
353 return clMark(n) != 0;
354 ret = clMark(n);
355 clMark(n) = (char)v;
356 return ret != 0;
357}
358
359typedef struct {
362} orig_t;
363
364#define ORIG_REC "orig"
365
367 orig_t *op = (orig_t *)aggetrec(cl, ORIG_REC, 0);
368 assert(op);
369 return op->orig;
370}
371
372/* projectG:
373 * If any nodes of subg are in g, create a subgraph of g
374 * and fill it with all nodes of subg in g and their induced
375 * edges in subg. Copy the attributes of subg to g. Return the subgraph.
376 * If not, return null.
377 * If subg is a cluster, the new subgraph will contain a pointer to it
378 * in the record "orig".
379 */
380static Agraph_t *projectG(Agraph_t *subg, Agraph_t *g, int inCluster) {
381 Agraph_t *proj = NULL;
382 Agnode_t *n;
383 Agnode_t *m;
384 orig_t *op;
385
386 for (n = agfstnode(subg); n; n = agnxtnode(subg, n)) {
387 if ((m = agfindnode(g, agnameof(n)))) {
388 if (proj == NULL) {
389 proj = agsubg(g, agnameof(subg), 1);
390 }
391 agsubnode(proj, m, 1);
392 }
393 }
394 if (!proj && inCluster) {
395 proj = agsubg(g, agnameof(subg), 1);
396 }
397 if (proj) {
398 (void)graphviz_node_induce(proj, subg);
399 agcopyattr(subg, proj);
400 if (is_a_cluster(proj)) {
401 op = agbindrec(proj, ORIG_REC, sizeof(orig_t), false);
402 op->orig = subg;
403 }
404 }
405
406 return proj;
407}
408
409/* subgInduce:
410 * Project subgraphs of root graph on subgraph.
411 * If non-empty, add to subgraph.
412 */
413static void subgInduce(Agraph_t *root, Agraph_t *g, int inCluster) {
414 Agraph_t *subg;
415 Agraph_t *proj;
416 int in_cluster;
417
418 for (subg = agfstsubg(root); subg; subg = agnxtsubg(subg)) {
419 if (GD_cc_subg(subg))
420 continue;
421 if ((proj = projectG(subg, g, inCluster))) {
422 in_cluster = (inCluster || is_a_cluster(subg));
423 subgInduce(subg, proj, in_cluster);
424 }
425 }
426}
427
428static void subGInduce(Agraph_t *g, Agraph_t *out) { subgInduce(g, out, 0); }
429
430/* cccomps:
431 * Decompose g into "connected" components, where nodes are connected
432 * either by an edge or by being in the same cluster. The components
433 * are returned in an array of subgraphs. ncc indicates how many components
434 * there are. The subgraphs use the prefix pfx in their names, if non-NULL.
435 * Note that cluster subgraph of the main graph, corresponding to a component,
436 * is cloned within the subgraph. Each cloned cluster contains a record pointing
437 * to the real cluster.
438 */
439Agraph_t **cccomps(Agraph_t *g, size_t *ncc, char *pfx) {
440 Agraph_t *dg;
441 size_t n_cnt, e_cnt;
442 agxbuf name = {0};
443 Agraph_t *out;
444 Agraph_t *dout;
445 Agnode_t *dn;
446 stk_t stk;
447 int sz = (int)sizeof(ccgraphinfo_t);
448
449 if (agnnodes(g) == 0) {
450 *ncc = 0;
451 return NULL;
452 }
453
454 /* Bind ccgraphinfo to graph and all subgraphs */
455 aginit(g, AGRAPH, GRECNAME, -sz, false);
456
457 /* Bind ccgraphinfo to graph and all subgraphs */
458 aginit(g, AGNODE, NRECNAME, sizeof(ccgnodeinfo_t), false);
459
460 dg = deriveGraph(g);
461
462 size_t ccs_length = (size_t)agnnodes(dg);
463 Agraphs_t ccs = {0};
464 Agraphs_reserve(&ccs, ccs_length);
465 initStk(&stk, insertFn, clMarkFn);
466
467 for (dn = agfstnode(dg); dn; dn = agnxtnode(dg, dn)) {
468 if (marked(&stk, dn))
469 continue;
470 setPrefix(&name, pfx);
471 agxbprint(&name, "%" PRISIZE_T, Agraphs_size(&ccs));
472 char *name_str = agxbuse(&name);
473 dout = agsubg(dg, name_str, 1);
474 out = agsubg(g, name_str, 1);
475 agbindrec(out, GRECNAME, sizeof(ccgraphinfo_t), false);
476 GD_cc_subg(out) = 1;
477 n_cnt = dfs(dg, dn, dout, &stk);
478 unionNodes(dout, out);
479 e_cnt = graphviz_node_induce(out, NULL);
480 subGInduce(g, out);
481 Agraphs_append(&ccs, out);
482 agdelete(dg, dout);
483 if (Verbose)
484 fprintf(stderr,
485 "(%4" PRISIZE_T ") %7" PRISIZE_T " nodes %7" PRISIZE_T " edges\n",
486 Agraphs_size(&ccs) - 1, n_cnt, e_cnt);
487 }
488
489 if (Verbose)
490 fprintf(stderr,
491 " %7d nodes %7d edges %7" PRISIZE_T " components %s\n",
492 agnnodes(g), agnedges(g), Agraphs_size(&ccs), agnameof(g));
493
494 agclose(dg);
497 freeStk(&stk);
498 agxbfree(&name);
499 *ncc = Agraphs_size(&ccs);
500 return Agraphs_detach(&ccs);
501}
502
503/* isConnected:
504 * Returns 1 if the graph is connected.
505 * Returns 0 if the graph is not connected.
506 * Returns -1 if the graph is error.
507 */
509 Agnode_t *n;
510 int ret = 1;
511 size_t cnt = 0;
512 stk_t stk;
513
514 if (agnnodes(g) == 0)
515 return 1;
516
517 initStk(&stk, NULL, markFn);
518 for (n = agfstnode(g); n; n = agnxtnode(g, n))
519 unmark(&stk, n);
520
521 n = agfstnode(g);
522 cnt = dfs(g, agfstnode(g), NULL, &stk);
523 freeStk(&stk);
524 if (cnt != (size_t)agnnodes(g))
525 ret = 0;
526 return ret;
527}
static void out(agerrlevel_t level, const char *fmt, va_list args)
Report messages using a user-supplied or default write function.
Definition agerror.c:84
static void agxbfree(agxbuf *xb)
free any malloced resources
Definition agxbuf.h:78
static int agxbprint(agxbuf *xb, const char *fmt,...)
Printf-style output to an agxbuf.
Definition agxbuf.h:234
static WUR char * agxbuse(agxbuf *xb)
Definition agxbuf.h:307
Memory allocation wrappers that exit on failure.
abstract graph C library, Cgraph API
static Agnode_t * pop(void)
Definition ccomps.c:231
static void deriveClusters(Agraph_t *dg, Agraph_t *g)
Definition ccomps.c:366
static Agraph_t * deriveGraph(Agraph_t *g)
Definition ccomps.c:396
static void unionNodes(Agraph_t *dg, Agraph_t *g)
Definition ccomps.c:435
static Agraph_t * projectG(Agraph_t *subg, Agraph_t *g, int inCluster)
Definition ccomps.c:306
static void subGInduce(Agraph_t *g, Agraph_t *out)
Definition ccomps.c:353
static void subgInduce(Agraph_t *root, Agraph_t *g, int inCluster)
Definition ccomps.c:336
static int dfs(Agraph_t *g, Agnode_t *n, Agraph_t *out)
Definition ccomps.c:239
static void push(Agnode_t *np)
Definition ccomps.c:225
#define GD_cc_subg(g)
Definition ccomps.c:49
bool is_a_cluster(Agraph_t *g)
Definition utils.c:690
static bool Verbose
Definition gml2gv.c:23
node NULL
Definition grammar.y:163
static int cnt(Dict_t *d, Dtlink_t **set)
Definition graph.c:210
int agnedges(Agraph_t *g)
Definition graph.c:175
int agnnodes(Agraph_t *g)
Definition graph.c:169
size_t graphviz_node_induce(Agraph_t *g, Agraph_t *edgeset)
Definition node_induce.c:9
int agcopyattr(void *oldobj, void *newobj)
copies all of the attributes from one object to another
Definition attr.c:549
Agedge_t * agedge(Agraph_t *g, Agnode_t *t, Agnode_t *h, char *name, int createflag)
Definition edge.c:260
Agedge_t * agfstout(Agraph_t *g, Agnode_t *n)
Definition edge.c:24
#define agtail(e)
Definition cgraph.h:880
Agedge_t * agnxtedge(Agraph_t *g, Agedge_t *e, Agnode_t *n)
Definition edge.c:94
#define aghead(e)
Definition cgraph.h:881
Agedge_t * agnxtout(Agraph_t *g, Agedge_t *e)
Definition edge.c:39
Agedge_t * agfstedge(Agraph_t *g, Agnode_t *n)
Definition edge.c:85
Agdesc_t Agstrictundirected
strict undirected
Definition graph.c:287
int agclose(Agraph_t *g)
deletes a graph, freeing its associated storage
Definition graph.c:102
Agraph_t * agopen(char *name, Agdesc_t desc, Agdisc_t *disc)
creates a new graph with the given name and kind
Definition graph.c:44
Agnode_t * agnode(Agraph_t *g, char *name, int createflag)
Definition node.c:145
Agnode_t * agnxtnode(Agraph_t *g, Agnode_t *n)
Definition node.c:47
Agnode_t * agfstnode(Agraph_t *g)
Definition node.c:40
Agnode_t * agsubnode(Agraph_t *g, Agnode_t *n, int createflag)
Definition node.c:259
#define agfindnode(g, n)
Definition types.h:611
char * agnameof(void *)
returns a string descriptor for the object.
Definition id.c:158
#define AGTYPE(obj)
returns AGRAPH, AGNODE, or AGEDGE depending on the type of the object
Definition cgraph.h:216
int agdelete(Agraph_t *g, void *obj)
deletes object. Equivalent to agclose, agdelnode, and agdeledge for obj being a graph,...
Definition obj.c:20
@ AGNODE
Definition cgraph.h:207
@ AGRAPH
Definition cgraph.h:207
Agrec_t * aggetrec(void *obj, const char *name, int move_to_front)
find record in circular list and do optional move-to-front and lock
Definition rec.c:41
void aginit(Agraph_t *g, int kind, const char *rec_name, int rec_size, int move_to_front)
attach new records to objects of specified kind
Definition rec.c:170
void * agbindrec(void *obj, const char *name, unsigned int recsize, int move_to_front)
attaches a new record of the given size to the object
Definition rec.c:89
void agclean(Agraph_t *g, int kind, char *rec_name)
calls agdelrec for all objects of the same class in an entire graph
Definition rec.c:202
Agraph_t * agfstsubg(Agraph_t *g)
Definition subg.c:78
Agraph_t * agnxtsubg(Agraph_t *subg)
Definition subg.c:83
Agraph_t * agsubg(Agraph_t *g, char *name, int cflag)
Definition subg.c:58
replacements for ctype.h functions
static bool gv_isalnum(int c)
Definition gv_ctype.h:43
agxbput(xb, staging)
#define ND_mark(n)
Definition acyclic.c:28
static void unmark(const stk_t *stk, Agnode_t *n)
unset a mark on n
Definition ccomps.c:39
static bool marked(const stk_t *stk, Agnode_t *n)
does n have a mark set?
Definition ccomps.c:33
#define clMark(n)
Definition ccomps.c:257
static void freeStk(stk_t *sp)
Definition ccomps.c:48
Agraph_t ** pccomps(Agraph_t *g, size_t *ncc, char *pfx, bool *pinned)
Definition ccomps.c:125
static void setPrefix(agxbuf *xb, const char *pfx)
Definition ccomps.c:104
#define dnodeOf(v)
Definition ccomps.c:250
static void mark(const stk_t *stk, Agnode_t *n)
set a mark on n
Definition ccomps.c:36
static void insertFn(Agnode_t *n, void *state)
Definition ccomps.c:94
static bool markFn(Agnode_t *n, int v)
Definition ccomps.c:96
#define GRECNAME
Definition ccomps.c:235
#define nodeOf(np)
Definition ccomps.c:255
#define ORIG_REC
Definition ccomps.c:364
Agraph_t ** ccomps(Agraph_t *g, size_t *ncc, char *pfx)
Definition ccomps.c:187
int isConnected(Agraph_t *g)
Definition ccomps.c:508
Agraph_t ** cccomps(Agraph_t *g, size_t *ncc, char *pfx)
Definition ccomps.c:439
#define clustOf(np)
Definition ccomps.c:256
static bool clMarkFn(Agnode_t *n, int v)
Definition ccomps.c:350
static bool isLegal(const char *p)
Definition ccomps.c:83
static void initStk(stk_t *sp, void(*actionfn)(Agnode_t *, void *), bool(*markfn)(Agnode_t *, int))
Definition ccomps.c:41
#define dnodeSet(v, w)
Definition ccomps.c:251
#define NRECNAME
Definition ccomps.c:236
#define ptrOf(np)
Definition ccomps.c:254
Agraph_t * mapClust(Agraph_t *cl)
Definition ccomps.c:366
#define DEFINE_LIST(name, type)
Definition list.h:26
#define isPinned(n)
Definition macros.h:17
support for connected components
#define PRISIZE_T
PRIu64 alike for printing size_t
Definition prisize_t.h:27
graph or subgraph
Definition cgraph.h:425
implementation of Agrec_t
Definition cgraph.h:172
Agrec_t h
Definition ccomps.c:226
Agraph_t * g
Definition ccomps.c:229
void * v
Definition ccomps.c:231
union ccgnodeinfo_t::@100 ptr
Agnode_t * n
Definition ccomps.c:230
char cc_subg
Definition ccomps.c:222
Agrec_t h
Definition ccomps.c:221
Agrec_t h
Definition ccomps.c:360
Agraph_t * orig
Definition ccomps.c:361
Definition ccomps.c:26
void(* actionfn)(Agnode_t *, void *)
Definition ccomps.c:28
node_stack_t data
Definition ccomps.c:27
bool(* markfn)(Agnode_t *, int)
Definition ccomps.c:29