|
Graphviz
2.31.20130524.0447
|
00001 /* $Id$ $Revision$ */ 00002 /* vim:set shiftwidth=4 ts=8: */ 00003 00004 /************************************************************************* 00005 * Copyright (c) 2011 AT&T Intellectual Property 00006 * All rights reserved. This program and the accompanying materials 00007 * are made available under the terms of the Eclipse Public License v1.0 00008 * which accompanies this distribution, and is available at 00009 * http://www.eclipse.org/legal/epl-v10.html 00010 * 00011 * Contributors: See CVS logs. Details at http://www.graphviz.org/ 00012 *************************************************************************/ 00013 00014 00015 #include "dot.h" 00016 00017 static node_t* 00018 map_interclust_node(node_t * n) 00019 { 00020 node_t *rv; 00021 00022 #ifndef WITH_CGRAPH 00023 if ((ND_clust(n) == NULL) || (ND_clust(n)->u.expanded)) 00024 #else /* WITH_CGRAPH */ 00025 if ((ND_clust(n) == NULL) || ( GD_expanded(ND_clust(n))) ) 00026 #endif /* WITH_CGRAPH */ 00027 rv = n; 00028 else 00029 #ifndef WITH_CGRAPH 00030 rv = ND_clust(n)->u.rankleader[ND_rank(n)]; 00031 #else /* WITH_CGRAPH */ 00032 rv = GD_rankleader(ND_clust(n))[ND_rank(n)]; 00033 #endif /* WITH_CGRAPH */ 00034 return rv; 00035 } 00036 00037 /* make d slots starting at position pos (where 1 already exists) */ 00038 static void 00039 make_slots(graph_t * root, int r, int pos, int d) 00040 { 00041 int i; 00042 node_t *v, **vlist; 00043 #ifndef WITH_CGRAPH 00044 vlist = ND_rank(root)[r].v; 00045 #else /* WITH_CGRAPH */ 00046 vlist = GD_rank(root)[r].v; 00047 #endif /* WITH_CGRAPH */ 00048 if (d <= 0) { 00049 #ifndef WITH_CGRAPH 00050 for (i = pos - d + 1; i < ND_rank(root)[r].n; i++) { 00051 #else /* WITH_CGRAPH */ 00052 for (i = pos - d + 1; i < GD_rank(root)[r].n; i++) { 00053 #endif /* WITH_CGRAPH */ 00054 v = vlist[i]; 00055 ND_order(v) = i + d - 1; 00056 vlist[ND_order(v)] = v; 00057 } 00058 #ifndef WITH_CGRAPH 00059 for (i = ND_rank(root)[r].n + d - 1; i < ND_rank(root)[r].n; i++) 00060 #else /* WITH_CGRAPH */ 00061 for (i = GD_rank(root)[r].n + d - 1; i < GD_rank(root)[r].n; i++) 00062 #endif /* WITH_CGRAPH */ 00063 vlist[i] = NULL; 00064 } else { 00065 /*assert(ND_rank(root)[r].n + d - 1 <= ND_rank(root)[r].an);*/ 00066 #ifndef WITH_CGRAPH 00067 for (i = ND_rank(root)[r].n - 1; i > pos; i--) { 00068 #else /* WITH_CGRAPH */ 00069 for (i = GD_rank(root)[r].n - 1; i > pos; i--) { 00070 #endif /* WITH_CGRAPH */ 00071 v = vlist[i]; 00072 ND_order(v) = i + d - 1; 00073 vlist[ND_order(v)] = v; 00074 } 00075 for (i = pos + 1; i < pos + d; i++) 00076 vlist[i] = NULL; 00077 } 00078 #ifndef WITH_CGRAPH 00079 ND_rank(root)[r].n += d - 1; 00080 #else /* WITH_CGRAPH */ 00081 GD_rank(root)[r].n += d - 1; 00082 #endif /* WITH_CGRAPH */ 00083 } 00084 00085 static node_t* 00086 clone_vn(graph_t * g, node_t * vn) 00087 { 00088 node_t *rv; 00089 int r; 00090 00091 r = ND_rank(vn); 00092 make_slots(g, r, ND_order(vn), 2); 00093 rv = virtual_node(g); 00094 ND_lw(rv) = ND_lw(vn); 00095 ND_rw(rv) = ND_rw(vn); 00096 ND_rank(rv) = ND_rank(vn); 00097 ND_order(rv) = ND_order(vn) + 1; 00098 GD_rank(g)[r].v[ND_order(rv)] = rv; 00099 return rv; 00100 } 00101 00102 static void 00103 map_path(node_t * from, node_t * to, edge_t * orig, edge_t * ve, int type) 00104 { 00105 int r; 00106 node_t *u, *v; 00107 edge_t *e; 00108 00109 assert(ND_rank(from) < ND_rank(to)); 00110 00111 if ((agtail(ve) == from) && (aghead(ve) == to)) 00112 return; 00113 00114 if (ED_count(ve) > 1) { 00115 ED_to_virt(orig) = NULL; 00116 if (ND_rank(to) - ND_rank(from) == 1) { 00117 if ((e = find_fast_edge(from, to)) && (ports_eq(orig, e))) { 00118 merge_oneway(orig, e); 00119 if ((ND_node_type(from) == NORMAL) 00120 && (ND_node_type(to) == NORMAL)) 00121 other_edge(orig); 00122 return; 00123 } 00124 } 00125 u = from; 00126 for (r = ND_rank(from); r < ND_rank(to); r++) { 00127 if (r < ND_rank(to) - 1) 00128 v = clone_vn(agraphof(from), aghead(ve)); 00129 else 00130 v = to; 00131 e = virtual_edge(u, v, orig); 00132 ED_edge_type(e) = type; 00133 u = v; 00134 ED_count(ve)--; 00135 ve = ND_out(aghead(ve)).list[0]; 00136 } 00137 } else { 00138 if (ND_rank(to) - ND_rank(from) == 1) { 00139 if ((ve = find_fast_edge(from, to)) && (ports_eq(orig, ve))) { 00140 /*ED_to_orig(ve) = orig; */ 00141 ED_to_virt(orig) = ve; 00142 ED_edge_type(ve) = type; 00143 ED_count(ve)++; 00144 if ((ND_node_type(from) == NORMAL) 00145 && (ND_node_type(to) == NORMAL)) 00146 other_edge(orig); 00147 } else { 00148 ED_to_virt(orig) = NULL; 00149 ve = virtual_edge(from, to, orig); 00150 ED_edge_type(ve) = type; 00151 } 00152 } 00153 if (ND_rank(to) - ND_rank(from) > 1) { 00154 e = ve; 00155 if (agtail(ve) != from) { 00156 ED_to_virt(orig) = NULL; 00157 e = ED_to_virt(orig) = virtual_edge(from, aghead(ve), orig); 00158 delete_fast_edge(ve); 00159 } else 00160 e = ve; 00161 while (ND_rank(aghead(e)) != ND_rank(to)) 00162 e = ND_out(aghead(e)).list[0]; 00163 if (aghead(e) != to) { 00164 ve = e; 00165 e = virtual_edge(agtail(e), to, orig); 00166 ED_edge_type(e) = type; 00167 delete_fast_edge(ve); 00168 } 00169 } 00170 } 00171 } 00172 00173 static void 00174 make_interclust_chain(graph_t * g, node_t * from, node_t * to, edge_t * orig) 00175 { 00176 int newtype; 00177 node_t *u, *v; 00178 00179 u = map_interclust_node(from); 00180 v = map_interclust_node(to); 00181 if ((u == from) && (v == to)) 00182 newtype = VIRTUAL; 00183 else 00184 newtype = CLUSTER_EDGE; 00185 map_path(u, v, orig, ED_to_virt(orig), newtype); 00186 } 00187 00188 /* 00189 * attach and install edges between clusters. 00190 * essentially, class2() for interclust edges. 00191 */ 00192 void interclexp(graph_t * subg) 00193 { 00194 graph_t *g; 00195 node_t *n; 00196 edge_t *e, *prev, *next; 00197 00198 g = agroot(subg); 00199 for (n = agfstnode(subg); n; n = agnxtnode(subg, n)) { 00200 00201 /* N.B. n may be in a sub-cluster of subg */ 00202 prev = NULL; 00203 for (e = agfstedge(agroot(subg), n); e; e = next) { 00204 next = agnxtedge(agroot(subg), e, n); 00205 if (agcontains(subg, e)) 00206 continue; 00207 00208 #ifdef WITH_CGRAPH 00209 /* canonicalize edge */ 00210 e = AGMKOUT(e); 00211 #endif 00212 /* short/flat multi edges */ 00213 if (mergeable(prev, e)) { 00214 if (ND_rank(agtail(e)) == ND_rank(aghead(e))) 00215 ED_to_virt(e) = prev; 00216 else 00217 ED_to_virt(e) = NULL; 00218 if (ED_to_virt(prev) == NULL) 00219 continue; /* internal edge */ 00220 merge_chain(subg, e, ED_to_virt(prev), FALSE); 00221 safe_other_edge(e); 00222 continue; 00223 } 00224 00225 /* flat edges */ 00226 if (ND_rank(agtail(e)) == ND_rank(aghead(e))) { 00227 edge_t* fe; 00228 if ((fe = find_flat_edge(agtail(e), aghead(e))) == NULL) { 00229 flat_edge(g, e); 00230 prev = e; 00231 } else if (e != fe) { 00232 safe_other_edge(e); 00233 if (!ED_to_virt(e)) merge_oneway(e, fe); 00234 } 00235 continue; 00236 } 00237 00238 /* This assertion is still valid if the new ranking is not used */ 00239 #ifndef WITH_CGRAPH 00240 assert(ED_to_virt(e) != NULL); 00241 #endif 00242 00243 /* forward edges */ 00244 if (ND_rank(aghead(e)) > ND_rank(agtail(e))) { 00245 make_interclust_chain(g, agtail(e), aghead(e), e); 00246 prev = e; 00247 continue; 00248 } 00249 00250 /* backward edges */ 00251 else { 00252 /* 00253 I think that make_interclust_chain should create call other_edge(e) anyway 00254 if (agcontains(subg,agtail(e)) 00255 && agfindedge(subg->root,aghead(e),agtail(e))) other_edge(e); 00256 */ 00257 make_interclust_chain(g, aghead(e), agtail(e), e); 00258 prev = e; 00259 } 00260 } 00261 } 00262 } 00263 00264 static void 00265 merge_ranks(graph_t * subg) 00266 { 00267 int i, d, r, pos, ipos; 00268 node_t *v; 00269 graph_t *root; 00270 00271 root = agroot(subg); 00272 if (GD_minrank(subg) > 0) 00273 #ifndef WITH_CGRAPH 00274 ND_rank(root)[GD_minrank(subg) - 1].valid = FALSE; 00275 #else /* WITH_CGRAPH */ 00276 GD_rank(root)[GD_minrank(subg) - 1].valid = FALSE; 00277 #endif /* WITH_CGRAPH */ 00278 for (r = GD_minrank(subg); r <= GD_maxrank(subg); r++) { 00279 d = GD_rank(subg)[r].n; 00280 #ifndef WITH_CGRAPH 00281 ipos = pos = GD_rankleader(subg)[r]->u.order; 00282 #else /* WITH_CGRAPH */ 00283 ipos = pos = ND_order(GD_rankleader(subg)[r]); 00284 #endif /* WITH_CGRAPH */ 00285 make_slots(root, r, pos, d); 00286 for (i = 0; i < GD_rank(subg)[r].n; i++) { 00287 #ifndef WITH_CGRAPH 00288 v = ND_rank(root)[r].v[pos] = GD_rank(subg)[r].v[i]; 00289 #else /* WITH_CGRAPH */ 00290 v = GD_rank(root)[r].v[pos] = GD_rank(subg)[r].v[i]; 00291 #endif /* WITH_CGRAPH */ 00292 ND_order(v) = pos++; 00293 #ifndef WITH_CGRAPH 00294 v->graph = subg->root; 00295 #else /* WITH_CGRAPH */ 00296 /* real nodes automatically have v->root = root graph */ 00297 if (ND_node_type(v) == VIRTUAL) 00298 v->root = root; 00299 #endif /* WITH_CGRAPH */ 00300 delete_fast_node(subg, v); 00301 fast_node(agroot(subg), v); 00302 GD_n_nodes(agroot(subg))++; 00303 } 00304 #ifndef WITH_CGRAPH 00305 GD_rank(subg)[r].v = ND_rank(root)[r].v + ipos; 00306 ND_rank(root)[r].valid = FALSE; 00307 #else /* WITH_CGRAPH */ 00308 GD_rank(subg)[r].v = GD_rank(root)[r].v + ipos; 00309 GD_rank(root)[r].valid = FALSE; 00310 #endif /* WITH_CGRAPH */ 00311 } 00312 if (r < GD_maxrank(root)) 00313 GD_rank(root)[r].valid = FALSE; 00314 GD_expanded(subg) = TRUE; 00315 } 00316 00317 static void 00318 remove_rankleaders(graph_t * g) 00319 { 00320 int r; 00321 node_t *v; 00322 edge_t *e; 00323 00324 for (r = GD_minrank(g); r <= GD_maxrank(g); r++) { 00325 v = GD_rankleader(g)[r]; 00326 00327 /* remove the entire chain */ 00328 while ((e = ND_out(v).list[0])) 00329 delete_fast_edge(e); 00330 while ((e = ND_in(v).list[0])) 00331 delete_fast_edge(e); 00332 delete_fast_node(agroot(g), v); 00333 GD_rankleader(g)[r] = NULL; 00334 } 00335 } 00336 00337 /* delete virtual nodes of a cluster, and install real nodes or sub-clusters */ 00338 void expand_cluster(graph_t * subg) 00339 { 00340 /* build internal structure of the cluster */ 00341 class2(subg); 00342 GD_comp(subg).size = 1; 00343 GD_comp(subg).list[0] = GD_nlist(subg); 00344 allocate_ranks(subg); 00345 build_ranks(subg, 0); 00346 merge_ranks(subg); 00347 00348 /* build external structure of the cluster */ 00349 interclexp(subg); 00350 remove_rankleaders(subg); 00351 } 00352 00353 /* this function marks every node in <g> with its top-level cluster under <g> */ 00354 void mark_clusters(graph_t * g) 00355 { 00356 int c; 00357 node_t *n, *nn, *vn; 00358 edge_t *orig, *e; 00359 graph_t *clust; 00360 00361 /* remove sub-clusters below this level */ 00362 for (n = agfstnode(g); n; n = agnxtnode(g, n)) { 00363 if (ND_ranktype(n) == CLUSTER) 00364 UF_singleton(n); 00365 ND_clust(n) = NULL; 00366 } 00367 00368 for (c = 1; c <= GD_n_cluster(g); c++) { 00369 clust = GD_clust(g)[c]; 00370 for (n = agfstnode(clust); n; n = nn) { 00371 nn = agnxtnode(clust,n); 00372 if (ND_ranktype(n) != NORMAL) { 00373 agerr(AGWARN, 00374 "%s was already in a rankset, deleted from cluster %s\n", 00375 agnameof(n), agnameof(g)); 00376 agdelete(clust,n); 00377 continue; 00378 } 00379 UF_setname(n, GD_leader(clust)); 00380 ND_clust(n) = clust; 00381 ND_ranktype(n) = CLUSTER; 00382 00383 /* here we mark the vnodes of edges in the cluster */ 00384 for (orig = agfstout(clust, n); orig; 00385 orig = agnxtout(clust, orig)) { 00386 if ((e = ED_to_virt(orig))) { 00387 #ifndef WITH_CGRAPH 00388 while (e && (vn = e->head)->u.node_type == VIRTUAL) { 00389 #else /* WITH_CGRAPH */ 00390 while (e && ND_node_type(vn =aghead(e)) == VIRTUAL) { 00391 #endif /* WITH_CGRAPH */ 00392 ND_clust(vn) = clust; 00393 e = ND_out(aghead(e)).list[0]; 00394 /* trouble if concentrators and clusters are mixed */ 00395 } 00396 } 00397 } 00398 } 00399 } 00400 } 00401 00402 void build_skeleton(graph_t * g, graph_t * subg) 00403 { 00404 int r; 00405 node_t *v, *prev, *rl; 00406 edge_t *e; 00407 00408 prev = NULL; 00409 GD_rankleader(subg) = N_NEW(GD_maxrank(subg) + 2, node_t *); 00410 for (r = GD_minrank(subg); r <= GD_maxrank(subg); r++) { 00411 v = GD_rankleader(subg)[r] = virtual_node(g); 00412 ND_rank(v) = r; 00413 ND_ranktype(v) = CLUSTER; 00414 ND_clust(v) = subg; 00415 if (prev) { 00416 e = virtual_edge(prev, v, NULL); 00417 ED_xpenalty(e) *= CL_CROSS; 00418 } 00419 prev = v; 00420 } 00421 00422 /* set the counts on virtual edges of the cluster skeleton */ 00423 for (v = agfstnode(subg); v; v = agnxtnode(subg, v)) { 00424 rl = GD_rankleader(subg)[ND_rank(v)]; 00425 ND_UF_size(rl)++; 00426 for (e = agfstout(subg, v); e; e = agnxtout(subg, e)) { 00427 for (r = ND_rank(agtail(e)); r < ND_rank(aghead(e)); r++) { 00428 ED_count(ND_out(rl).list[0])++; 00429 } 00430 } 00431 } 00432 for (r = GD_minrank(subg); r <= GD_maxrank(subg); r++) { 00433 rl = GD_rankleader(subg)[r]; 00434 if (ND_UF_size(rl) > 1) 00435 ND_UF_size(rl)--; 00436 } 00437 } 00438 00439 void install_cluster(graph_t * g, node_t * n, int pass, nodequeue * q) 00440 { 00441 int r; 00442 graph_t *clust; 00443 00444 clust = ND_clust(n); 00445 if (GD_installed(clust) != pass + 1) { 00446 for (r = GD_minrank(clust); r <= GD_maxrank(clust); r++) 00447 install_in_rank(g, GD_rankleader(clust)[r]); 00448 for (r = GD_minrank(clust); r <= GD_maxrank(clust); r++) 00449 enqueue_neighbors(q, GD_rankleader(clust)[r], pass); 00450 GD_installed(clust) = pass + 1; 00451 } 00452 } 00453 00454 static void mark_lowcluster_basic(Agraph_t * g); 00455 void mark_lowclusters(Agraph_t * root) 00456 { 00457 Agnode_t *n, *vn; 00458 Agedge_t *orig, *e; 00459 00460 /* first, zap any previous cluster labelings */ 00461 for (n = agfstnode(root); n; n = agnxtnode(root, n)) { 00462 ND_clust(n) = NULL; 00463 for (orig = agfstout(root, n); orig; orig = agnxtout(root, orig)) { 00464 if ((e = ED_to_virt(orig))) { 00465 #ifndef WITH_CGRAPH 00466 while (e && (vn = e->head)->u.node_type == VIRTUAL) { 00467 #else /* WITH_CGRAPH */ 00468 while (e && (ND_node_type(vn = aghead(e))) == VIRTUAL) { 00469 #endif /* WITH_CGRAPH */ 00470 ND_clust(vn) = NULL; 00471 e = ND_out(aghead(e)).list[0]; 00472 } 00473 } 00474 } 00475 } 00476 00477 /* do the recursion */ 00478 mark_lowcluster_basic(root); 00479 } 00480 00481 static void mark_lowcluster_basic(Agraph_t * g) 00482 { 00483 Agraph_t *clust; 00484 Agnode_t *n, *vn; 00485 Agedge_t *orig, *e; 00486 int c; 00487 00488 for (c = 1; c <= GD_n_cluster(g); c++) { 00489 clust = GD_clust(g)[c]; 00490 mark_lowcluster_basic(clust); 00491 } 00492 /* see what belongs to this graph that wasn't already marked */ 00493 for (n = agfstnode(g); n; n = agnxtnode(g, n)) { 00494 if (ND_clust(n) == NULL) 00495 ND_clust(n) = g; 00496 for (orig = agfstout(g, n); orig; orig = agnxtout(g, orig)) { 00497 if ((e = ED_to_virt(orig))) { 00498 #ifndef WITH_CGRAPH 00499 while (e && (vn = e->head)->u.node_type == VIRTUAL) { 00500 #else /* WITH_CGRAPH */ 00501 while (e && (ND_node_type(vn = aghead(e))) == VIRTUAL) { 00502 #endif /* WITH_CGRAPH */ 00503 if (ND_clust(vn) == NULL) 00504 ND_clust(vn) = g; 00505 e = ND_out(aghead(e)).list[0]; 00506 } 00507 } 00508 } 00509 } 00510 }
1.7.5