/misc/src/release/graphviz-2.18-1/src/graphviz-2.18/lib/dotgen/cluster.c

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

Generated on Mon Mar 31 19:03:25 2008 for Graphviz by  doxygen 1.5.1