Graphviz  2.29.20120523.0446
lib/fdpgen/comp.c
Go to the documentation of this file.
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 /* comp.c:
00016  * Written by Emden R. Gansner
00017  *
00018  * Support for "connected components". Components are either connected
00019  * or have a port node or have a pinned node.
00020  *
00021  */
00022 
00023 /* use PRIVATE interface */
00024 #define FDP_PRIVATE 1
00025 
00026 #include <fdp.h>
00027 #include <comp.h>
00028 #include <pack.h>
00029 #include <assert.h>
00030 
00031 #define MARK(n) (marks[ND_id(n)])
00032 
00033 static void dfs(Agraph_t * g, Agnode_t * n, Agraph_t * out, char *marks)
00034 {
00035     Agedge_t *e;
00036     Agnode_t *other;
00037 
00038     MARK(n) = 1;
00039 #ifndef WITH_CGRAPH
00040     aginsert(out, n);
00041 #else /* WITH_CGRAPH */
00042     agsubnode(out,n,1);
00043 #endif /* WITH_CGRAPH */
00044     for (e = agfstedge(g, n); e; e = agnxtedge(g, e, n)) {
00045         if ((other = agtail(e)) == n)
00046             other = aghead(e);
00047         if (!MARK(other))
00048             dfs(g, other, out, marks);
00049     }
00050 }
00051 
00052 /* findCComp:
00053  * Finds generalized connected components of graph g.
00054  * This merges all components containing a port node or a pinned node.
00055  * Assumes nodes have unique id's in range [0,agnnodes(g)-1].
00056  * Components are stored as subgraphs of g, with name sg_<i>.
00057  * Returns 0-terminated array of components.
00058  * If cnt is non-0, count of components is stored there.
00059  * If pinned is non-0, *pinned is set to 1 if there are pinned nodes.
00060  * Note that if ports and/or pinned nodes exists, they will all be
00061  * in the first component returned by findCComp.
00062  */
00063 static int C_cnt = 0;
00064 graph_t **findCComp(graph_t * g, int *cnt, int *pinned)
00065 {
00066     node_t *n;
00067     graph_t *subg;
00068     char name[128];
00069     int c_cnt = 0;
00070     char *marks;
00071     bport_t *pp;
00072     graph_t **comps;
00073     graph_t **cp;
00074 #ifndef WITH_CGRAPH
00075     graph_t *mg;
00076     node_t *mn;
00077     edge_t *me;
00078 #endif
00079     int pinflag = 0;
00080 
00081 /* fprintf (stderr, "comps of %s starting at %d \n", g->name, c_cnt); */
00082     marks = N_NEW(agnnodes(g), char);   /* freed below */
00083 
00084     /* Create component based on port nodes */
00085     subg = 0;
00086     if ((pp = PORTS(g))) {
00087         sprintf(name, "cc%s_%d", agnameof(g), c_cnt++ + C_cnt);
00088 #ifndef WITH_CGRAPH
00089         subg = agsubg(g, name);
00090 #else /* WITH_CGRAPH */
00091         subg = agsubg(g, name,1);
00092         agbindrec(subg, "Agraphinfo_t", sizeof(Agraphinfo_t), TRUE);
00093 #endif /* WITH_CGRAPH */
00094         GD_alg(subg) = (void *) NEW(gdata);
00095         PORTS(subg) = pp;
00096         NPORTS(subg) = NPORTS(g);
00097         for (; pp->n; pp++) {
00098             if (MARK(pp->n))
00099                 continue;
00100             dfs(g, pp->n, subg, marks);
00101         }
00102     }
00103 
00104     /* Create/extend component based on pinned nodes */
00105     /* Note that ports cannot be pinned */
00106     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00107         if (MARK(n))
00108             continue;
00109         if (ND_pinned(n) != P_PIN)
00110             continue;
00111         if (!subg) {
00112             sprintf(name, "cc%s_%d", agnameof(g), c_cnt++ + C_cnt);
00113 #ifndef WITH_CGRAPH
00114             subg = agsubg(g, name);
00115 #else /* WITH_CGRAPH */
00116             subg = agsubg(g, name,1);
00117                 agbindrec(subg, "Agraphinfo_t", sizeof(Agraphinfo_t), TRUE);
00118 #endif /* WITH_CGRAPH */
00119             GD_alg(subg) = (void *) NEW(gdata);
00120         }
00121         pinflag = 1;
00122         dfs(g, n, subg, marks);
00123     }
00124     if (subg)
00125         nodeInduce(subg);
00126 
00127     /* Pick up remaining components */
00128     for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
00129         if (MARK(n))
00130             continue;
00131         sprintf(name, "cc%s+%d", agnameof(g), c_cnt++ + C_cnt);
00132 #ifndef WITH_CGRAPH
00133         subg = agsubg(g, name);
00134 #else /* WITH_CGRAPH */
00135         subg = agsubg(g, name,1);
00136         agbindrec(subg, "Agraphinfo_t", sizeof(Agraphinfo_t), TRUE);    //node custom data
00137 #endif /* WITH_CGRAPH */
00138         GD_alg(subg) = (void *) NEW(gdata);
00139         dfs(g, n, subg, marks);
00140         nodeInduce(subg);
00141     }
00142     free(marks);
00143     C_cnt += c_cnt;
00144 
00145     if (cnt)
00146         *cnt = c_cnt;
00147     if (pinned)
00148         *pinned = pinflag;
00149     /* freed in layout */
00150     comps = cp = N_NEW(c_cnt + 1, graph_t *);
00151 #ifndef WITH_CGRAPH
00152     mg = g->meta_node->graph;
00153     for (me = agfstout(mg, g->meta_node); me; me = agnxtout(mg, me)) {
00154         mn = me->head;
00155         *cp++ = agusergraph(mn);
00156 #else /* WITH_CGRAPH */
00157     for (subg = agfstsubg(g); subg; subg = agnxtsubg(subg)) {
00158         *cp++ = subg;
00159 #endif /* WITH_CGRAPH */
00160         c_cnt--;
00161     }
00162     assert(c_cnt == 0);
00163     *cp = 0;
00164 
00165     return comps;
00166 }