Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libvgraph/grbranching.c
1808 views
1
#include "grhdr.h"
2
3
/******************************************************************************
4
Chu-Liu-Edmonds algorithm to compute a maximum branching for a
5
directed graph with edge weights. The algorithm alters the edge
6
lists to contain just the branching edges.
7
8
Written by Kiem-Phong Vo (02/01/2006)
9
******************************************************************************/
10
11
typedef struct _brcycl_s
12
{ Gredge_t* cycl; /* the cycle of strong components */
13
Gredge_t* emin; /* the minimum weight edge of cycle */
14
Gredge_t* entr; /* the edge that came in to the cycle */
15
} Brcycl_t;
16
17
typedef struct _brnode_s
18
{ Grdata_t data;
19
ssize_t mark; /* mark 1 if already searched */
20
} Brnode_t;
21
22
typedef struct _bredge_s
23
{ Grdata_t data;
24
ssize_t wght; /* the original edge weight */
25
ssize_t wadj; /* adjusted weight during construction */
26
Grnode_t* root; /* strong component before collapsing */
27
Gredge_t* edge; /* branching edge that this represents */
28
} Bredge_t;
29
30
#define BRNODE(n) ((Brnode_t*)grdtnode((n), Grbranching) )
31
#define BREDGE(e) ((Bredge_t*)grdtedge((e), Grbranching) )
32
33
/* compute the representative node in the shadowed union structure */
34
#define GRLINK(n) ((n)->link == (n) ? (n) : grlink(n))
35
static Grnode_t* grlink(Grnode_t* n)
36
{ while(n->link != n)
37
n = n->link;
38
return n;
39
}
40
41
#ifdef DEBUG
42
static int Fd = 2;
43
static int predge(Gredge_t* ed)
44
{
45
if(!ed)
46
{ PRINT(Fd,"Null edge\n",0);
47
return 0;
48
}
49
PRINT(Fd,"%d", (int)ed->tail->label); PRINT(Fd,"(%d) -> ", (int)grfind(ed->tail)->label );
50
PRINT(Fd,"%d", (int)ed->head->label); PRINT(Fd,"(%d), ", (int)grfind(ed->head)->label );
51
PRINT(Fd,"root=%d, ", BREDGE(ed)->root ? (int)BREDGE(ed)->root->label : -1 );
52
PRINT(Fd,"wght=%d, ", (int)BREDGE(ed)->wght); PRINT(Fd,"wadj=%d\n", (int)BREDGE(ed)->wadj);
53
return 0;
54
}
55
static int prlink(Gredge_t* e)
56
{ for(; e; e = e->link)
57
{ PRINT(Fd, "\t", 0); predge(e); }
58
PRINT(Fd,"\n",0);
59
}
60
static int prinext(Gredge_t* e)
61
{ for(; e; e = e->inext)
62
{ PRINT(Fd, "\t", 0); predge(e); }
63
PRINT(Fd,"\n",0);
64
}
65
static int pronext(Gredge_t* e)
66
{ for(; e; e = e->onext)
67
{ PRINT(Fd, "\t", 0); predge(e); }
68
PRINT(Fd,"\n",0);
69
}
70
static int prnode(Grnode_t* nd)
71
{
72
if(!nd)
73
{ PRINT(Fd,"Null node\n",0);
74
return 0;
75
}
76
PRINT(Fd,"node = %d", (int)nd->label); PRINT(Fd,"(%d), ", grfind(nd)->label);
77
PRINT(Fd,"link = %d, ", nd->link ? (int)nd->link->label : -1);
78
PRINT(Fd,"mark = %d\n", (int)BRNODE(nd)->mark);
79
return 0;
80
}
81
static int prid(Graph_t* gr, ssize_t id)
82
{
83
return prnode(grnode(gr, (void*)id, 0));
84
}
85
static int prcycl(Brcycl_t* cl)
86
{
87
Gredge_t *e;
88
PRINT(Fd,"Emin: ",0); predge(cl->emin);
89
PRINT(Fd,"Entr: ",0); predge(cl->entr);
90
prlink(cl->cycl);
91
return 0;
92
}
93
static int prgraph(Graph_t* gr)
94
{ Grnode_t *nd;
95
Gredge_t *ed;
96
for(nd = (Grnode_t*)dtflatten(gr->nodes); nd; nd = (Grnode_t*)dtlink(gr->nodes,nd) )
97
{ if(nd != grfind(nd))
98
continue;
99
prnode(nd);
100
for(ed = nd->iedge; ed; ed = ed->inext)
101
{ PRINT(Fd,"\t",0); predge(ed); }
102
}
103
}
104
#endif
105
106
ssize_t grbranching(Graph_t* gr)
107
{
108
Grnode_t *n, *nc;
109
Gredge_t *e, *ec, *ep, *en, *path, *emin;
110
Brcycl_t *clist, *cl, *endcl;
111
ssize_t w;
112
113
for(w = 0, n = (Grnode_t*)dtflatten(gr->nodes); n; w += 1, n = (Grnode_t*)dtlink(gr->nodes,n) )
114
{ n->link = n->fold = n; /* union structures: link kept as-is, fold does path-compression */
115
n->oedge = NIL(Gredge_t*); /* wipe the out-edges */
116
BRNODE(n)->mark = 0;
117
118
/* compute heaviest weight ec and move it to front */
119
for(ep = en = NIL(Gredge_t*), ec = e = n->iedge; e; en = e, e = e->inext )
120
{ e->link = NIL(Gredge_t*);
121
BREDGE(e)->edge = e; /* at start, representing self */
122
if((BREDGE(e)->wadj = BREDGE(e)->wght) > BREDGE(ec)->wadj )
123
{ ec = e; ep = en; }
124
}
125
if(ep)
126
{ ep->inext = ec->inext; ec->inext = n->iedge; n->iedge = ec; }
127
}
128
if(w == 0)
129
return 0;
130
131
/* space to keep cycle structures */
132
if(!(clist = cl = (Brcycl_t*)calloc(w+1,sizeof(Brcycl_t))) )
133
return -1;
134
endcl = cl+w+1;
135
136
/* search and collapse cycles */
137
for(n = (Grnode_t*)dtflatten(gr->nodes); n; n = (Grnode_t*)dtlink(gr->nodes,n) )
138
{ nc = grfind(n);
139
if(BRNODE(nc)->mark) /* already searched */
140
continue;
141
142
for(path = NIL(Gredge_t*); nc; ) /* depth-first search */
143
{ if(!BRNODE(nc)->mark) /* not searched yet */
144
{ BRNODE(nc)->mark = 1;
145
146
if(!(ec = nc->iedge) ) /* this path cannot be a cycle */
147
break;
148
else /* continue to build the path */
149
{ ec->link = path; path = ec;
150
nc = grfind(ec->tail);
151
continue; /* dfs recursion */
152
}
153
}
154
155
/* potential cycle, check that out and also compute min edge */
156
for(emin = NIL(Gredge_t*), ec = path; ec; ec = ec->link)
157
{ if(!emin || BREDGE(ec)->wadj < BREDGE(emin)->wadj )
158
emin = ec;
159
if(grfind(ec->head) == nc) /* end of cycle */
160
break;
161
}
162
if(!ec) /* run up against an old path */
163
break;
164
165
if(cl >= endcl) /* hmm, this should not happen */
166
{ /**/ASSERT(cl < endcl);
167
free(clist);
168
return -1;
169
}
170
171
cl->cycl = path;
172
path = ec->link; /* will restart search from here */
173
ec->link = NIL(Gredge_t*);
174
175
/* make list of incoming edges and adjust their weights */
176
en = NIL(Gredge_t*);
177
for(ec = cl->cycl; ec; ec = ec->link)
178
{ BREDGE(ec)->root = grfind(ec->head); /* save node union structure */
179
180
w = BREDGE(ec)->wadj - BREDGE(emin)->wadj;
181
for(ep = NIL(Gredge_t*), e = grfind(ec->head)->iedge; e; e = e->inext)
182
{ BREDGE(e)->wadj -= w;
183
if(!e->inext) /* last of list */
184
ep = e;
185
}
186
ep->inext = en; en = grfind(ec->head)->iedge; /* catenate lists */
187
grfind(ec->head)->iedge = NIL(Gredge_t*);
188
}
189
190
/* collapsing cycle onto nc */
191
for(ec = cl->cycl; ec; ec = ec->link)
192
{ if(grfind(ec->head) == nc)
193
continue;
194
grfind(ec->head)->link = nc; /* union history kept as-is */
195
grfind(ec->head)->fold = nc; /* union with path-compression */
196
}
197
nc->fold = nc->link = nc;
198
199
/* make new edge list, keep heaviest edge in front */
200
for(e = en; e; e = en)
201
{ en = e->inext;
202
if(BREDGE(e)->wadj <= 0 || grfind(e->head) == grfind(e->tail) )
203
continue;
204
if(!nc->iedge || BREDGE(nc->iedge)->wadj <= BREDGE(e)->wadj )
205
{ e->inext = nc->iedge; nc->iedge = e; }
206
else { e->inext = nc->iedge->inext; nc->iedge->inext = e; }
207
}
208
209
cl->emin = emin;
210
cl->entr = nc->iedge;
211
cl += 1;
212
BRNODE(nc)->mark = 0; /* force nc to be searched again */
213
}
214
}
215
216
/* move the remaining branching edges to their real nodes */
217
path = NIL(Gredge_t*);
218
for(n = (Grnode_t*)dtflatten(gr->nodes); n; n = (Grnode_t*)dtlink(gr->nodes,n) )
219
{ if(!(e = n->iedge) )
220
continue;
221
e->link = path; path = e;
222
}
223
for(ec = path; ec; ec = ec->link)
224
ec->head->iedge = ec;
225
226
/* unroll collapsed cycles in reverse order to construct branching */
227
for(cl -= 1; cl >= clist; --cl )
228
{ /* restore the union structure to just before this cycle collapsed */
229
for(ec = cl->cycl; ec; ec = ec->link)
230
BREDGE(ec)->root->link = BREDGE(ec)->root;
231
232
if((en = cl->entr) )
233
en = BREDGE(en)->edge;
234
for(ec = cl->cycl; ec; ec = ec->link)
235
{ if(en && GRLINK(ec->head) == GRLINK(en->head))
236
BREDGE(ec)->edge = en;
237
else ec->head->iedge = ec;
238
}
239
if(!en) /* isolated cycle, remove minimum edge */
240
{ cl->emin->head->iedge = NIL(Gredge_t*);
241
if(BREDGE(cl->emin)->edge == cl->emin)
242
BREDGE(cl->emin)->edge = NIL(Gredge_t*);
243
}
244
}
245
246
w = 0; /* construct the external branching representation */
247
for(n = (Grnode_t*)dtflatten(gr->nodes); n; n = (Grnode_t*)dtlink(gr->nodes,n) )
248
{ if(!(e = n->iedge) )
249
continue;
250
e->inext = NIL(Gredge_t*);
251
e->onext = e->tail->oedge; e->tail->oedge = e;
252
w += BREDGE(e)->wght;
253
}
254
255
free(clist);
256
257
return w;
258
}
259
260
261
ssize_t grbrweight(Gredge_t* e, ssize_t w)
262
{
263
if(w > 0)
264
BREDGE(e)->wght = w;
265
return BREDGE(e)->wght;
266
}
267
268
269
static Grdata_t* brdata(Gralgo_t* algo, int type, Grdata_t* data)
270
{
271
Brnode_t* brn;
272
Bredge_t* bre;
273
274
if(algo != Grbranching)
275
return NIL(Grdata_t*);
276
277
switch(type)
278
{ default:
279
return NIL(Grdata_t*);
280
281
case GR_NODE|GR_CLOSING:
282
case GR_EDGE|GR_CLOSING:
283
if(data)
284
free(data);
285
return NIL(Grdata_t*);
286
287
case GR_NODE|GR_OPENING:
288
if(!(brn = (Brnode_t*)calloc(1, sizeof(Brnode_t))) )
289
return NIL(Grdata_t*);
290
return (Grdata_t*)brn;
291
292
case GR_EDGE|GR_OPENING:
293
if(!(bre = (Bredge_t*)calloc(1, sizeof(Bredge_t))) )
294
return NIL(Grdata_t*);
295
return (Grdata_t*)bre;
296
}
297
}
298
299
static Gralgo_t _Grbranching = { brdata, 0 };
300
Gralgo_t* Grbranching = &_Grbranching;
301
302
#ifdef KPVTEST
303
#include <stdio.h>
304
main(int argc, char** argv)
305
{
306
Graph_t *gr;
307
Grnode_t *n, *hn, *tn;
308
Gredge_t *e;
309
int h, t, w;
310
char buf[1024];
311
int type = 0;
312
313
if(argc > 1 && strcmp(argv[1],"-l") == 0)
314
type = -1;
315
if(argc > 1 && strcmp(argv[1],"-r") == 0)
316
type = 1;
317
318
gr = gropen(0);
319
while(fgets(buf,sizeof(buf),stdin))
320
{ if(buf[0] == '#')
321
continue;
322
if(sscanf(buf,"%d,%d,%d", &t, &h, &w) != 3)
323
continue;
324
tn = grnode(gr, t, 1);
325
hn = grnode(gr, h, 1);
326
if(type > 0 && t >= h) /* only use edges with t < h */
327
continue;
328
if(type < 0 && t <= h) /* only use edges with t > h */
329
continue;
330
e = gredge(gr, tn, hn, 0, 1);
331
grbrweight(e, w);
332
}
333
334
printf("\nTotal weight=%d\n", grbranching(gr));
335
for(n = (Grnode_t*)dtflatten(gr->nodes); n; n = (Grnode_t*)dtlink(gr->nodes, n) )
336
if((e = n->iedge) )
337
fprintf(stderr, "%d -> %d [%d]\n", e->tail->label, e->head->label, grbrweight(e, 0) );
338
}
339
#endif
340
341