Graphviz 14.1.2~dev.20260118.1035
Loading...
Searching...
No Matches
cluster.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 "config.h"
12
13#include <assert.h>
14#include <dotgen/dot.h>
15#include <stdbool.h>
16#include <stddef.h>
17#include <util/alloc.h>
18
19static node_t*
21{
22 node_t *rv;
23
24 if (ND_clust(n) == NULL || GD_expanded(ND_clust(n)))
25 rv = n;
26 else
27 rv = GD_rankleader(ND_clust(n))[ND_rank(n)];
28 return rv;
29}
30
31/* make d slots starting at position pos (where 1 already exists) */
32static void
33make_slots(graph_t * root, int r, int pos, int d)
34{
35 int i;
36 node_t *v, **vlist;
37 vlist = GD_rank(root)[r].v;
38 if (d <= 0) {
39 for (i = pos - d + 1; i < GD_rank(root)[r].n; i++) {
40 v = vlist[i];
41 ND_order(v) = i + d - 1;
42 vlist[ND_order(v)] = v;
43 }
44 for (i = GD_rank(root)[r].n + d - 1; i < GD_rank(root)[r].n; i++)
45 vlist[i] = NULL;
46 } else {
47/*assert(ND_rank(root)[r].n + d - 1 <= ND_rank(root)[r].an);*/
48 for (i = GD_rank(root)[r].n - 1; i > pos; i--) {
49 v = vlist[i];
50 ND_order(v) = i + d - 1;
51 vlist[ND_order(v)] = v;
52 }
53 for (i = pos + 1; i < pos + d; i++)
54 vlist[i] = NULL;
55 }
56 GD_rank(root)[r].n += d - 1;
57}
58
59static node_t*
61{
62 const int r = ND_rank(vn);
63 make_slots(g, r, ND_order(vn), 2);
64 node_t *const rv = virtual_node(g);
65 ND_lw(rv) = ND_lw(vn);
66 ND_rw(rv) = ND_rw(vn);
67 ND_rank(rv) = ND_rank(vn);
68 ND_order(rv) = ND_order(vn) + 1;
69 GD_rank(g)[r].v[ND_order(rv)] = rv;
70 return rv;
71}
72
73static void
74map_path(node_t * from, node_t * to, edge_t * orig, edge_t * ve, int type)
75{
76 int r;
77 node_t *u, *v;
78 edge_t *e;
79
80 assert(ND_rank(from) < ND_rank(to));
81
82 if (agtail(ve) == from && aghead(ve) == to)
83 return;
84
85 if (ED_count(ve) > 1) {
86 ED_to_virt(orig) = NULL;
87 if (ND_rank(to) - ND_rank(from) == 1) {
88 if ((e = find_fast_edge(from, to)) && ports_eq(orig, e)) {
89 merge_oneway(orig, e);
90 if (ND_node_type(from) == NORMAL && ND_node_type(to) == NORMAL)
91 other_edge(orig);
92 return;
93 }
94 }
95 u = from;
96 for (r = ND_rank(from); r < ND_rank(to); r++) {
97 if (r < ND_rank(to) - 1)
98 v = clone_vn(dot_root(from), aghead(ve));
99 else
100 v = to;
101 e = virtual_edge(u, v, orig);
102 ED_edge_type(e) = type;
103 u = v;
104 ED_count(ve)--;
105 ve = ND_out(aghead(ve)).list[0];
106 }
107 } else {
108 if (ND_rank(to) - ND_rank(from) == 1) {
109 if ((ve = find_fast_edge(from, to)) && ports_eq(orig, ve)) {
110 /*ED_to_orig(ve) = orig; */
111 ED_to_virt(orig) = ve;
112 ED_edge_type(ve) = type;
113 ED_count(ve)++;
114 if (ND_node_type(from) == NORMAL && ND_node_type(to) == NORMAL)
115 other_edge(orig);
116 } else {
117 ED_to_virt(orig) = NULL;
118 ve = virtual_edge(from, to, orig);
119 ED_edge_type(ve) = type;
120 }
121 }
122 if (ND_rank(to) - ND_rank(from) > 1) {
123 if (agtail(ve) != from) {
124 ED_to_virt(orig) = NULL;
125 e = ED_to_virt(orig) = virtual_edge(from, aghead(ve), orig);
127 } else
128 e = ve;
129 while (ND_rank(aghead(e)) != ND_rank(to))
130 e = ND_out(aghead(e)).list[0];
131 if (aghead(e) != to) {
132 ve = e;
133 e = virtual_edge(agtail(e), to, orig);
134 ED_edge_type(e) = type;
136 }
137 }
138 }
139}
140
141static void make_interclust_chain(node_t * from, node_t * to, edge_t * orig) {
142 int newtype;
143 node_t *u, *v;
144
145 u = map_interclust_node(from);
146 v = map_interclust_node(to);
147 if (u == from && v == to)
148 newtype = VIRTUAL;
149 else
150 newtype = CLUSTER_EDGE;
151 map_path(u, v, orig, ED_to_virt(orig), newtype);
152}
153
154/*
155 * attach and install edges between clusters.
156 * essentially, class2() for interclust edges.
157 */
158static void interclexp(graph_t * subg)
159{
160 edge_t *next;
161
162 graph_t *const g = dot_root(subg);
163 for (node_t *n = agfstnode(subg); n; n = agnxtnode(subg, n)) {
164
165 /* N.B. n may be in a sub-cluster of subg */
166 edge_t *prev = NULL;
167 for (edge_t *e = agfstedge(g, n); e; e = next) {
168 next = agnxtedge(g, e, n);
169 if (agcontains(subg, e))
170 continue;
171
172 /* canonicalize edge */
173 e = AGMKOUT(e);
174 /* short/flat multi edges */
175 if (mergeable(prev, e)) {
176 if (ND_rank(agtail(e)) == ND_rank(aghead(e)))
177 ED_to_virt(e) = prev;
178 else
179 ED_to_virt(e) = NULL;
180 if (ED_to_virt(prev) == NULL)
181 continue; /* internal edge */
182 ED_to_virt(e) = NULL;
183 merge_chain(subg, e, ED_to_virt(prev), false);
185 continue;
186 }
187
188 /* flat edges */
189 if (ND_rank(agtail(e)) == ND_rank(aghead(e))) {
190 edge_t* fe;
191 if ((fe = find_flat_edge(agtail(e), aghead(e))) == NULL) {
192 if (!ED_to_virt(e)) {
193 flat_edge(g, e);
194 }
195 prev = e;
196 } else if (e != fe) {
198 if (!ED_to_virt(e)) merge_oneway(e, fe);
199 }
200 continue;
201 }
202
203 /* forward edges */
204 if (ND_rank(aghead(e)) > ND_rank(agtail(e))) {
206 prev = e;
207 continue;
208 }
209
210 /* backward edges */
212 prev = e;
213 }
214 }
215}
216
217static void
219{
220 int i, d, r, pos, ipos;
221 node_t *v;
222 graph_t *root;
223
224 assert(GD_minrank(subg) <= GD_maxrank(subg) && "corrupted rank bounds");
225
226 root = dot_root(subg);
227 if (GD_minrank(subg) > 0)
228 GD_rank(root)[GD_minrank(subg) - 1].valid = false;
229 for (r = GD_minrank(subg); r <= GD_maxrank(subg); r++) {
230 d = GD_rank(subg)[r].n;
231 ipos = pos = ND_order(GD_rankleader(subg)[r]);
232 make_slots(root, r, pos, d);
233 for (i = 0; i < GD_rank(subg)[r].n; i++) {
234 v = GD_rank(root)[r].v[pos] = GD_rank(subg)[r].v[i];
235 ND_order(v) = pos++;
236 /* real nodes automatically have v->root = root graph */
237 if (ND_node_type(v) == VIRTUAL)
238 v->root = agroot(root);
239 delete_fast_node(subg, v);
240 fast_node(root, v);
241 }
242 GD_rank(subg)[r].v = GD_rank(root)[r].v + ipos;
243 GD_rank(root)[r].valid = false;
244 }
245 if (r < GD_maxrank(root))
246 GD_rank(root)[r].valid = false;
247 GD_expanded(subg) = true;
248}
249
250static void
252{
253 int r;
254 node_t *v;
255 edge_t *e;
256
257 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) {
258 v = GD_rankleader(g)[r];
259
260 /* remove the entire chain */
261 while ((e = ND_out(v).list[0])) {
263 free(e->base.data);
264 free(e);
265 }
266 while ((e = ND_in(v).list[0])) {
268 free(e);
269 }
271 free(ND_in(v).list);
272 free(ND_out(v).list);
273 free(v->base.data);
274 free(v);
275 GD_rankleader(g)[r] = NULL;
276 }
277}
278
279/* delete virtual nodes of a cluster, and install real nodes or sub-clusters */
281 /* build internal structure of the cluster */
282 class2(subg);
283 GD_comp(subg).size = 1;
284 GD_comp(subg).list[0] = GD_nlist(subg);
285 allocate_ranks(subg);
286 const int rc = build_ranks(subg, 0);
287 if (rc != 0) {
288 return rc;
289 }
290 merge_ranks(subg);
291
292 /* build external structure of the cluster */
293 interclexp(subg);
294 remove_rankleaders(subg);
295 return 0;
296}
297
298/* this function marks every node in <g> with its top-level cluster under <g> */
300{
301 int c;
302 node_t *n, *nn, *vn;
303 edge_t *orig, *e;
304 graph_t *clust;
305
306 /* remove sub-clusters below this level */
307 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
308 if (ND_ranktype(n) == CLUSTER)
309 UF_singleton(n);
310 ND_clust(n) = NULL;
311 }
312
313 for (c = 1; c <= GD_n_cluster(g); c++) {
314 clust = GD_clust(g)[c];
315 for (n = agfstnode(clust); n; n = nn) {
316 nn = agnxtnode(clust,n);
317 if (ND_ranktype(n) != NORMAL) {
319 "%s was already in a rankset, deleted from cluster %s\n",
320 agnameof(n), agnameof(g));
321 agdelete(clust,n);
322 continue;
323 }
324 UF_setname(n, GD_leader(clust));
325 ND_clust(n) = clust;
326 ND_ranktype(n) = CLUSTER;
327
328 /* here we mark the vnodes of edges in the cluster */
329 for (orig = agfstout(clust, n); orig;
330 orig = agnxtout(clust, orig)) {
331 if ((e = ED_to_virt(orig))) {
332 while (e && ND_node_type(vn =aghead(e)) == VIRTUAL) {
333 ND_clust(vn) = clust;
334 e = ND_out(aghead(e)).list[0];
335 /* trouble if concentrators and clusters are mixed */
336 }
337 }
338 }
339 }
340 }
341}
342
344{
345 int r;
346 node_t *v, *prev, *rl;
347 edge_t *e;
348
349 prev = NULL;
350 GD_rankleader(subg) = gv_calloc(GD_maxrank(subg) + 2, sizeof(node_t*));
351 for (r = GD_minrank(subg); r <= GD_maxrank(subg); r++) {
352 v = GD_rankleader(subg)[r] = virtual_node(g);
353 ND_rank(v) = r;
354 ND_ranktype(v) = CLUSTER;
355 ND_clust(v) = subg;
356 if (prev) {
357 e = virtual_edge(prev, v, NULL);
358 ED_xpenalty(e) *= CL_CROSS;
359 }
360 prev = v;
361 }
362
363 /* set the counts on virtual edges of the cluster skeleton */
364 for (v = agfstnode(subg); v; v = agnxtnode(subg, v)) {
365 rl = GD_rankleader(subg)[ND_rank(v)];
366 ND_UF_size(rl)++;
367 for (e = agfstout(subg, v); e; e = agnxtout(subg, e)) {
368 for (r = ND_rank(agtail(e)); r < ND_rank(aghead(e)); r++) {
369 ED_count(ND_out(rl).list[0])++;
370 }
371 }
372 }
373 for (r = GD_minrank(subg); r <= GD_maxrank(subg); r++) {
374 rl = GD_rankleader(subg)[r];
375 if (ND_UF_size(rl) > 1)
376 ND_UF_size(rl)--;
377 }
378}
379
380int install_cluster(graph_t *g, node_t *n, int pass, node_queue_t *q) {
381 int r;
382 graph_t *clust;
383
384 clust = ND_clust(n);
385 if (GD_installed(clust) != pass + 1) {
386 for (r = GD_minrank(clust); r <= GD_maxrank(clust); r++) {
387 const int rc = install_in_rank(g, GD_rankleader(clust)[r]);
388 if (rc != 0) {
389 return rc;
390 }
391 }
392 for (r = GD_minrank(clust); r <= GD_maxrank(clust); r++)
393 enqueue_neighbors(q, GD_rankleader(clust)[r], pass);
394 GD_installed(clust) = pass + 1;
395 }
396 return 0;
397}
398
399static void mark_lowcluster_basic(Agraph_t * g);
401{
402 Agnode_t *n, *vn;
403 Agedge_t *orig, *e;
404
405 /* first, zap any previous cluster labelings */
406 for (n = agfstnode(root); n; n = agnxtnode(root, n)) {
407 ND_clust(n) = NULL;
408 for (orig = agfstout(root, n); orig; orig = agnxtout(root, orig)) {
409 if ((e = ED_to_virt(orig))) {
410 while (e && ND_node_type(vn = aghead(e)) == VIRTUAL) {
411 ND_clust(vn) = NULL;
412 e = ND_out(aghead(e)).list[0];
413 }
414 }
415 }
416 }
417
418 /* do the recursion */
420}
421
423{
424 Agraph_t *clust;
425 Agnode_t *n, *vn;
426 Agedge_t *orig, *e;
427 int c;
428
429 for (c = 1; c <= GD_n_cluster(g); c++) {
430 clust = GD_clust(g)[c];
432 }
433 /* see what belongs to this graph that wasn't already marked */
434 for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
435 if (ND_clust(n) == NULL)
436 ND_clust(n) = g;
437 for (orig = agfstout(g, n); orig; orig = agnxtout(g, orig)) {
438 if ((e = ED_to_virt(orig))) {
439 while (e && ND_node_type(vn = aghead(e)) == VIRTUAL) {
440 if (ND_clust(vn) == NULL)
441 ND_clust(vn) = g;
442 e = ND_out(aghead(e)).list[0];
443 }
444 }
445 }
446 }
447}
Memory allocation wrappers that exit on failure.
static void * gv_calloc(size_t nmemb, size_t size)
Definition alloc.h:26
void merge_chain(graph_t *g, edge_t *e, edge_t *f, bool update_count)
Definition class2.c:130
void class2(graph_t *g)
Definition class2.c:155
bool mergeable(edge_t *e, edge_t *f)
Definition class2.c:150
void UF_setname(node_t *u, node_t *v)
Definition utils.c:149
void UF_singleton(node_t *u)
Definition utils.c:142
#define NORMAL
Definition const.h:24
#define VIRTUAL
Definition const.h:25
#define CLUSTER_EDGE
Definition const.h:29
#define CLUSTER
Definition const.h:40
#define CL_CROSS
Definition const.h:144
Agraph_t * dot_root(void *p)
Definition dotinit.c:515
void other_edge(Agedge_t *)
Definition fastgr.c:116
void delete_fast_node(Agraph_t *, Agnode_t *)
Definition fastgr.c:189
int build_ranks(Agraph_t *, int)
Definition mincross.c:1295
Agedge_t * virtual_edge(Agnode_t *, Agnode_t *, Agedge_t *)
Definition fastgr.c:170
void safe_other_edge(Agedge_t *)
Definition fastgr.c:121
void enqueue_neighbors(node_queue_t *q, node_t *n0, int pass)
Definition mincross.c:1371
void allocate_ranks(Agraph_t *)
Definition mincross.c:1219
void flat_edge(Agraph_t *, Agedge_t *)
Definition fastgr.c:215
void fast_node(Agraph_t *, Agnode_t *)
Definition fastgr.c:175
void delete_fast_edge(Agedge_t *)
Definition fastgr.c:109
void merge_oneway(Agedge_t *, Agedge_t *)
Definition fastgr.c:289
int install_in_rank(Agraph_t *, Agnode_t *)
Definition mincross.c:1247
int ports_eq(edge_t *, edge_t *)
Definition position.c:999
Agedge_t * find_flat_edge(Agnode_t *, Agnode_t *)
Definition fastgr.c:56
Agedge_t * find_fast_edge(Agnode_t *, Agnode_t *)
Definition fastgr.c:43
Agnode_t * virtual_node(Agraph_t *)
Definition fastgr.c:200
expr procedure type
Definition exparse.y:208
void free(void *)
node NULL
Definition grammar.y:181
#define AGMKOUT(e)
Definition cgraph.h:971
#define ED_xpenalty(e)
Definition types.h:601
Agedge_t * agfstout(Agraph_t *g, Agnode_t *n)
Definition edge.c:28
#define ED_count(e)
Definition types.h:580
#define agtail(e)
Definition cgraph.h:977
#define ED_edge_type(e)
Definition types.h:582
Agedge_t * agnxtedge(Agraph_t *g, Agedge_t *e, Agnode_t *n)
Definition edge.c:98
#define aghead(e)
Definition cgraph.h:978
Agedge_t * agnxtout(Agraph_t *g, Agedge_t *e)
Definition edge.c:43
Agedge_t * agfstedge(Agraph_t *g, Agnode_t *n)
Definition edge.c:89
#define ED_to_virt(e)
Definition types.h:599
void agwarningf(const char *fmt,...)
Definition agerror.c:175
#define GD_minrank(g)
Definition types.h:384
#define GD_maxrank(g)
Definition types.h:382
#define GD_clust(g)
Definition types.h:360
#define GD_installed(g)
Definition types.h:373
#define GD_rank(g)
Definition types.h:395
#define GD_nlist(g)
Definition types.h:393
#define GD_n_cluster(g)
Definition types.h:389
#define GD_expanded(g)
Definition types.h:364
#define GD_leader(g)
Definition types.h:375
#define GD_comp(g)
Definition types.h:362
#define GD_rankleader(g)
Definition types.h:396
#define ND_rank(n)
Definition types.h:523
Agnode_t * agnxtnode(Agraph_t *g, Agnode_t *n)
Definition node.c:50
Agnode_t * agfstnode(Agraph_t *g)
Definition node.c:43
#define ND_clust(n)
Definition types.h:489
#define ND_rw(n)
Definition types.h:525
#define ND_node_type(n)
Definition types.h:511
#define ND_lw(n)
Definition types.h:506
#define ND_order(n)
Definition types.h:513
#define ND_UF_size(n)
Definition types.h:487
#define ND_ranktype(n)
Definition types.h:524
#define ND_in(n)
Definition types.h:501
#define ND_out(n)
Definition types.h:515
char * agnameof(void *)
returns a string descriptor for the object.
Definition id.c:145
int agdelete(Agraph_t *g, void *obj)
deletes object. Equivalent to agclose, agdelnode, and agdeledge for obj being a graph,...
Definition obj.c:22
int agcontains(Agraph_t *, void *obj)
returns non-zero if obj is a member of (sub)graph
Definition obj.c:235
Agraph_t * agroot(void *obj)
Definition obj.c:170
$2 prev
Definition htmlparse.y:291
static void mark_lowcluster_basic(Agraph_t *g)
Definition cluster.c:422
static void merge_ranks(graph_t *subg)
Definition cluster.c:218
static void map_path(node_t *from, node_t *to, edge_t *orig, edge_t *ve, int type)
Definition cluster.c:74
static void make_slots(graph_t *root, int r, int pos, int d)
Definition cluster.c:33
int install_cluster(graph_t *g, node_t *n, int pass, node_queue_t *q)
Definition cluster.c:380
static void remove_rankleaders(graph_t *g)
Definition cluster.c:251
static void interclexp(graph_t *subg)
Definition cluster.c:158
int expand_cluster(graph_t *subg)
Definition cluster.c:280
static node_t * clone_vn(graph_t *g, node_t *vn)
Definition cluster.c:60
static node_t * map_interclust_node(node_t *n)
Definition cluster.c:20
void mark_lowclusters(Agraph_t *root)
Definition cluster.c:400
void build_skeleton(graph_t *g, graph_t *subg)
Definition cluster.c:343
void mark_clusters(graph_t *g)
Definition cluster.c:299
static void make_interclust_chain(node_t *from, node_t *to, edge_t *orig)
Definition cluster.c:141
Agobj_t base
Definition cgraph.h:269
Agraph_t * root
Definition cgraph.h:261
Agobj_t base
Definition cgraph.h:260
Agrec_t * data
stores programmer-defined data, access with AGDATA
Definition cgraph.h:212
graph or subgraph
Definition cgraph.h:424