2
This software may only be used by you under license from AT&T Corp.
3
("AT&T"). A copy of AT&T's Source Code Agreement is available at
4
AT&T's Internet website having the URL:
5
<http://www.research.att.com/sw/tools/graphviz/license/source.html>
6
If you received this software without first entering into a license
7
with AT&T, you have an infringing copy of this software and cannot use
8
it without violating AT&T's intellectual property rights.
12
* Written by Stephen North
13
* Updated by Emden Gansner
17
* This is a filter that reads a graph, searches for strongly
18
* connected components, and writes each as a separate graph
19
* along with a map of the components.
31
#define INF ((unsigned int)(-1))
33
typedef struct Agraphinfo_t {
38
typedef struct Agnodeinfo_t {
45
#define getrep(g) (((Agraphinfo_t*)(g->base.data))->rep)
46
#define setrep(g,rep) (getrep(g) = rep)
47
#define getscc(n) (((Agnodeinfo_t*)((n)->base.data))->scc)
48
#define setscc(n,sub) (getscc(n) = sub)
49
#define getval(n) (((Agnodeinfo_t*)((n)->base.data))->val)
50
#define setval(n,newval) (getval(n) = newval)
55
return (((Agraphinfo_t*)(g->base.data))->rep);
58
setrep(Agraph_t *g, Agnode_t *rep)
60
((Agraphinfo_t*)(g->base.data))->rep = rep;
65
return (((Agnodeinfo_t*)(n->base.data))->scc);
68
setscc(Agnode_t *n, Agraph_t *scc)
70
((Agnodeinfo_t*)(n->base.data))->scc = scc;
75
return (((Agnodeinfo_t*)(n->base.data))->val);
78
setval(Agnode_t *n, int v)
80
((Agnodeinfo_t*)(n->base.data))->val = v;
84
/********* stack ***********/
91
initStack (Stack* sp, int sz)
93
sp->data = (Agnode_t**)malloc(sz*sizeof(Agnode_t*));
104
#define push(sp,n) (*((sp)->ptr++) = n)
105
#define top(sp) (*((sp)->ptr - 1))
106
#define pop(sp) (*(--((sp)->ptr)))
109
push (Stack* sp, Agnode_t* n)
117
return *(sp->ptr - 1);
129
/********* end stack ***********/
134
int N_nodes_in_nontriv_SCC;
137
int wantDegenerateComp;
144
nodeInduce(Agraph_t *g)
149
for (n = agfstnode(g); n; n = agnxtnode(n)) {
150
rootn = agsubnode(agroot(g),n,FALSE);
151
for (e = agfstout(rootn); e; e = agnxtout(e)) {
152
if (agsubnode(g,aghead(e),FALSE)) agsubedge(g,e,TRUE);
154
if (getscc(aghead(e)) && getscc(agtail(e)))
155
agedge(getrep(getscc(agtail(e))),getrep(getscc(aghead(e))),
163
visit(Agnode_t *n, Agraph_t* map, Stack* sp, sccstate* st)
174
for (e = agfstout(n); e; e = agnxtout(e)) {
176
if (getval(t) == 0) m = visit(t,map,sp,st);
178
if (m < min) min = m;
181
if (getval(n) == min) {
182
if (!wantDegenerateComp && (top(sp) == n)) {
188
Agraph_t* G = agraphof(n);;
189
sprintf(name,"cluster_%d",(st->Comp)++);
190
subg = agsubg(G,name,TRUE);
191
agbindrec(subg,"scc_graph",sizeof(Agraphinfo_t),TRUE);
192
setrep(subg,agnode(map,name,TRUE));
195
agsubnode(subg,t,TRUE);
198
st->N_nodes_in_nontriv_SCC++;
201
if (!Silent) agwrite(subg,stdout);
208
label(Agnode_t *n, int nodecnt, int* edgecnt)
214
for (e = agfstedge(n); e; e = agnxtedge(e,n)) {
216
if (e->node == n) e = agopp(e);
217
if (!getval(e->node))
218
nodecnt = label(e->node,nodecnt,edgecnt);
224
countComponents(Agraph_t *g, int* max_degree, float *nontree_frac)
234
for (n = agfstnode(g); n; n = agnxtnode(n)) {
238
n_nodes = label(n,0,&n_edges);
239
sum_edges += n_edges;
240
sum_nontree += (n_edges - n_nodes + 1);
245
for (n = agfstnode(g); n; n = agnxtnode(n)) {
246
deg = agdegree(n,TRUE,TRUE);
247
if (maxd < deg) maxd = deg;
253
if (sum_edges > 0) *nontree_frac = (float)sum_nontree / (float)sum_edges;
254
else *nontree_frac = 0.0;
270
aginit(G,AGRAPH,"scc_graph",sizeof(Agraphinfo_t),TRUE);
271
aginit(G,AGNODE,"scc_node",sizeof(Agnodeinfo_t),TRUE);
272
state.Comp = state.ID = 0;
273
state.N_nodes_in_nontriv_SCC = 0;
276
nc = countComponents(G,&Maxdegree,&nontree_frac);
278
initStack(&stack, agnnodes(G) + 1);
279
map = agopen("scc_map",Agdirected,(Agdisc_t *)0);
280
for (n = agfstnode(G); n; n = agnxtnode(n))
281
if (getval(n) == 0) visit(n,map,&stack,&state);
283
if (!Silent) agwrite(map,stdout);
287
fprintf(stderr,"%d %d %d %d %.4lf %d %.4f\n",
288
agnnodes(G), agnedges(G), nc, state.Comp,
289
state.N_nodes_in_nontriv_SCC / (double) agnnodes(G), Maxdegree,
292
fprintf(stderr,"%d nodes, %d edges, %d strong components\n",
293
agnnodes(G), agnedges(G), state.Comp);
297
static char* useString =
298
"Usage: %s [-sdv?] <files>\n\
300
-d - allow degenerate components\n\
303
If no files are specified, stdin is used\n";
308
printf (useString, CmdName);
313
scanArgs(int argc,char **argv)
318
while ((c = getopt(argc,argv,":?sdv")) != EOF) {
323
wantDegenerateComp = 1; break;
327
if (optopt == '?') usage(0);
328
else fprintf(stderr,"%s: option -%c unrecognized - ignored\n",
336
if (argc) Files = argv;
342
return agread(fp,(Agdisc_t*)0);
346
main(int argc, char **argv)
352
newIngraph (&ig, Files, gread);
354
while ((g = nextGraph(&ig)) != 0) {
355
if (agisdirected(g)) process (g);
356
else fprintf (stderr, "Graph %s in %s is undirected - ignored\n",
357
agnameof(g), fileName(&ig));