]> granicus.if.org Git - graphviz/commitdiff
Add new source files
authorerg <devnull@localhost>
Thu, 1 Jul 2010 20:34:23 +0000 (20:34 +0000)
committererg <devnull@localhost>
Thu, 1 Jul 2010 20:34:23 +0000 (20:34 +0000)
lib/dotgen2/dot2.h [new file with mode: 0644]
lib/dotgen2/dot2procs.h [new file with mode: 0644]
lib/dotgen2/dotinit.c [new file with mode: 0644]
lib/dotgen2/groups.c [new file with mode: 0644]
lib/dotgen2/groups.h [new file with mode: 0644]
lib/dotgen2/level.c
lib/dotgen2/minc.h [new file with mode: 0644]
lib/dotgen2/minc2.c [new file with mode: 0644]
lib/dotgen2/minc_utils.c [new file with mode: 0644]
lib/dotgen2/ns.c

diff --git a/lib/dotgen2/dot2.h b/lib/dotgen2/dot2.h
new file mode 100644 (file)
index 0000000..6215bdb
--- /dev/null
@@ -0,0 +1,34 @@
+/* $Id$Revision: */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+*      This software is part of the graphviz package      *
+*                http://www.graphviz.org/                 *
+*                                                         *
+*            Copyright (c) 1994-2004 AT&T Corp.           *
+*                and is licensed under the                *
+*            Common Public License, Version 1.0           *
+*                      by AT&T Corp.                      *
+*                                                         *
+*        Information and Software Systems Research        *
+*              AT&T Research, Florham Park NJ             *
+**********************************************************/
+
+
+#ifndef         DOT2_H
+#define         DOT2_H
+
+#include        "render.h"
+#include        "dot2procs.h"
+
+/* tags for representative (model) objects */
+/* 0 is reserved for undefined */
+#define STDNODE         1       /* a real node on only one rank */
+#define TALLNODE        2       /* a real node on two or more ranks */
+#define EXTNODE         3       /* a node external to a cluster */
+#define SKELETON        4
+#define PATH            5
+#define INTNODE         6       /*internal temporary nodes to fill rank gaps*/
+#define LBLNODE         7       /*internal temp nodes for edge labels*/
+
+#endif                          /* DOT_H */
diff --git a/lib/dotgen2/dot2procs.h b/lib/dotgen2/dot2procs.h
new file mode 100644 (file)
index 0000000..2eccd89
--- /dev/null
@@ -0,0 +1,47 @@
+/* $Id$Revision: */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+*      This software is part of the graphviz package      *
+*                http://www.graphviz.org/                 *
+*                                                         *
+*            Copyright (c) 1994-2004 AT&T Corp.           *
+*                and is licensed under the                *
+*            Common Public License, Version 1.0           *
+*                      by AT&T Corp.                      *
+*                                                         *
+*        Information and Software Systems Research        *
+*              AT&T Research, Florham Park NJ             *
+**********************************************************/
+
+#ifndef DOT2PROCS_H
+#define DOT2PROCS_H
+
+#ifdef _BEGIN_EXTERNS_
+_BEGIN_EXTERNS_                 /* public data */
+#endif
+/* tabs at 8, or you're a sorry loser */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int is_nonconstraint(edge_t * e);
+
+#if defined(_BLD_dot) && defined(_DLL)
+#   define extern __EXPORT__
+#endif
+    extern Agraph_t* dot2_mincross(Agraph_t *);
+    /* extern void dot_position(Agraph_t *, aspect_t*); */
+    extern void dot2_levels(Agraph_t *);
+    /* extern void dot_sameports(Agraph_t *); */
+    /* extern void dot_splines(Agraph_t *); */
+#undef extern
+
+#ifdef _END_EXTERNS_
+     _END_EXTERNS_
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/dotgen2/dotinit.c b/lib/dotgen2/dotinit.c
new file mode 100644 (file)
index 0000000..afaed73
--- /dev/null
@@ -0,0 +1,126 @@
+/* $Id$Revision: */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+*      This software is part of the graphviz package      *
+*                http://www.graphviz.org/                 *
+*                                                         *
+*            Copyright (c) 1994-2004 AT&T Corp.           *
+*                and is licensed under the                *
+*            Common Public License, Version 1.0           *
+*                      by AT&T Corp.                      *
+*                                                         *
+*        Information and Software Systems Research        *
+*              AT&T Research, Florham Park NJ             *
+**********************************************************/
+
+#include "dot2.h"
+
+#define DEBUG
+#ifdef DEBUG
+static void attach_attributes(graph_t *g)
+{
+    node_t     *n;
+    Agsym_t    *rank, *order;
+    char       buf[64];
+
+    rank = agattr(g,AGNODE,"rank","");
+    order = agattr(g,AGNODE,"order","");
+    for (n = agfstnode(g); n; n = agnxtnode(g,n)) {
+       sprintf(buf,"%d",ND_rank(n));
+       agxset(n,rank,buf);
+       sprintf(buf,"%d",ND_order(n));
+       agxset(n,order,buf);
+    }
+}
+#endif
+
+static void dot_init_node(node_t * n)
+{
+    common_init_node(n);
+    gv_nodesize(n, GD_flip(agraphof(n)));
+/*
+    alloc_elist(4, ND_in(n));
+    alloc_elist(4, ND_out(n));
+    alloc_elist(2, ND_flat_in(n));
+    alloc_elist(2, ND_flat_out(n));
+    alloc_elist(2, ND_other(n));
+    ND_UF_size(n) = 1;
+*/
+}
+
+static void dot_init_edge(edge_t * e)
+{
+    char *tailgroup, *headgroup;
+    common_init_edge(e);
+
+    ED_weight(e) = late_double(e, E_weight, 1.0, 0.0);
+    tailgroup = late_string(agtail(e), N_group, "");
+    headgroup = late_string(aghead(e), N_group, "");
+    ED_count(e) = ED_xpenalty(e) = 1;
+    /* FIX: does new ranking and mincross handle these? */
+    if (tailgroup[0] && (tailgroup == headgroup)) {
+       ED_xpenalty(e) = CL_CROSS;
+       ED_weight(e) *= 100;
+    }
+    if (is_nonconstraint(e)) {
+       ED_xpenalty(e) = 0;
+       ED_weight(e) = 0;
+    }
+
+    ED_showboxes(e) = late_int(e, E_showboxes, 0, 0);
+    ED_minlen(e) = late_int(e, E_minlen, 1, 0);
+}
+
+static void initGraph(graph_t * g)
+{
+    aginit(g, AGRAPH, "Agraphinfo_t", -sizeof(Agraphinfo_t), TRUE);
+    aginit(g, AGNODE, "Agnodeinfo_t", -sizeof(Agnodeinfo_t), TRUE);
+    aginit(g, AGEDGE, "Agedgeinfo_t", -sizeof(Agedgeinfo_t), TRUE);
+}
+
+static void dot_init_node_edge(graph_t * g)
+{
+    node_t *n;
+    edge_t *e;
+
+    initGraph (g);
+    for (n = agfstnode(g); n; n = agnxtnode(g, n))
+       dot_init_node(n);
+    for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
+       for (e = agfstout(g, n); e; e = agnxtout(g, e))
+           dot_init_edge(e);
+    }
+}
+
+/* dot2_layout:
+ * FIX:
+ *  connected components
+ *  multiedges ?
+ *  concentrator ?
+ *  aspect ?
+ */
+void dot2_layout(Agraph_t * g)
+{
+    Agraph_t *tempG;
+
+    fprintf(stderr, "dot_layout\n");
+    dot_init_node_edge(g);
+
+    dot2_levels(g);
+    /* agwrite(g, stdout); */
+    tempG = dot2_mincross(g);
+#ifdef DEBUG
+    attach_attributes(tempG);
+#endif
+//    agwrite(tempG,stdout);
+
+    return;
+}
+
+void dot2_cleanup(graph_t * g)
+{
+    /* FIX */
+    printf("dot_cleanup\n");
+    return;
+}
diff --git a/lib/dotgen2/groups.c b/lib/dotgen2/groups.c
new file mode 100644 (file)
index 0000000..a0023be
--- /dev/null
@@ -0,0 +1,138 @@
+/* $Id$Revision: */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+*      This software is part of the graphviz package      *
+*                http://www.graphviz.org/                 *
+*                                                         *
+*            Copyright (c) 1994-2004 AT&T Corp.           *
+*                and is licensed under the                *
+*            Common Public License, Version 1.0           *
+*                      by AT&T Corp.                      *
+*                                                         *
+*        Information and Software Systems Research        *
+*              AT&T Research, Florham Park NJ             *
+**********************************************************/
+
+#include "dot2.h"
+#include "groups.h"
+#include "utils.h"
+
+static int comparePos(Dt_t* dt, float* key1, float* key2, Dtdisc_t* disc)
+{
+    float a,b;
+    a = *key1;
+    b = *key2;
+    if(a < b) return -1;
+    else return 1;
+}
+
+/*group discipline */
+Dtdisc_t discGroup = {
+    0,
+    0,
+    -1,
+    NIL(Dtmake_f),
+    NIL(Dtfree_f),
+    NIL(Dtcompar_f),
+    NIL(Dthash_f),
+    NIL(Dtmemory_f),
+    NIL(Dtevent_f)
+};
+
+
+/*node discipline , sorted set*/
+Dtdisc_t discNode = {
+    offsetof(mcNode,order),
+    sizeof(float),
+    -1,
+    NIL(Dtmake_f),
+    NIL(Dtfree_f),
+    (Dtcompar_f)comparePos,
+    NIL(Dthash_f),
+    NIL(Dtmemory_f),
+    NIL(Dtevent_f)
+};
+
+static mcGroup* initMcGroup(mcGroup_t type)
+{
+    mcGroup* rv = NEW(mcGroup);
+    rv->alignType=mcBoth;
+    rv->cnt=0;
+    rv->nodes=dtopen(&discNode,Dtset);
+#if 0
+    rv->children=dtopen(&discGroup,Dtset);
+#endif
+    rv->type=type;
+    return rv;
+}
+
+/* createGroups:
+ * run after temp nodes are created
+*/
+void createGroups(Agraph_t* sg)
+{
+    mcGroup* gr;
+    Agraph_t* subg;
+    Agnode_t* v;
+    mcNode* leader;
+    mcNode* mcn;
+    for (subg = agfstsubg(sg); subg; subg = agnxtsubg(subg)) 
+    {
+       if(is_a_cluster(subg)) {
+           int isLeader=1;
+           gr=initMcGroup(mcGrStrict);
+           for (v = agfstnode(subg); v; v = agnxtnode(subg, v)) {
+               mcn = MND_mcn(v);
+               dtappend(gr->nodes,mcn);
+               mcn->group=gr;
+               mcn->groupOrder=0;/*this will be removed eventually */
+               mcn->isLeader=isLeader;
+
+               if(isLeader==1) {
+                   leader = mcn;
+                   isLeader = 0;
+               }
+               mcn->leader = leader;
+           }
+       }
+       else
+           createGroups (subg);
+    }
+}
+
+/* nodesToClusters:
+ * If dummy nodes belong to a cluster, add them.
+ */
+void nodesToClusters(Agraph_t* g)
+{
+    Agnode_t* v;
+    Agraph_t* c;
+    for (v = agfstnode(g); v; v = agnxtnode(g, v)) 
+    {
+       if ((c = MND_highCluster(v)))
+           agsubnode(c,v,1); /*i hope this routine is optimized!*/
+    }
+}
+
+/* graphGroups:
+ * The highCluster attribute of a node is set to the highest containing
+ * cluster, or NULL if not in a cluster.
+ * Run this before creating mincross temp nodes
+ */
+
+void graphGroups(Agraph_t* sg)
+{
+    Agraph_t* subg;
+    Agnode_t* v;
+    for (subg = agfstsubg(sg); subg; subg = agnxtsubg(subg)) 
+    {
+       if(is_a_cluster(subg))
+           for (v = agfstnode(subg); v; v = agnxtnode(subg, v)) 
+               MND_highCluster(v)=subg;
+       else
+           graphGroups (subg);
+
+    }
+}
+
diff --git a/lib/dotgen2/groups.h b/lib/dotgen2/groups.h
new file mode 100644 (file)
index 0000000..ddc9adc
--- /dev/null
@@ -0,0 +1,26 @@
+/* $Id$Revision: */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+*      This software is part of the graphviz package      *
+*                http://www.graphviz.org/                 *
+*                                                         *
+*            Copyright (c) 1994-2004 AT&T Corp.           *
+*                and is licensed under the                *
+*            Common Public License, Version 1.0           *
+*                      by AT&T Corp.                      *
+*                                                         *
+*        Information and Software Systems Research        *
+*              AT&T Research, Florham Park NJ             *
+**********************************************************/
+
+#ifndef GROUPS_H
+#define GROUPS_H
+
+#include <minc.h>
+
+extern void createGroups(Agraph_t* g);
+extern void nodesToClusters(Agraph_t* g);
+extern void graphGroups(Agraph_t* sg);
+
+#endif
index 9813dcca50a9f82f1e63ab5554b433b27ca67e57..4959f144333fadfe1f4fc8842a7972955ef43bb8 100644 (file)
-#include "newdot.h"
-
-static int is_a_cluster(graph_t *g);
-static int is_a_strong_cluster(graph_t *g);
-static void compile_samerank(graph_t *ug, graph_t *parent_clust);
-static int is_internal_to_cluster(edge_t *e);
-static void compile_nodes(graph_t *g, graph_t *Xg);
-static void strong(graph_t *g, node_t *t, node_t *h, edge_t *orig);
-static void weak(graph_t *g, node_t *t, node_t *h, edge_t *orig);
-static void compile_edges(graph_t *ug, graph_t *Xg);
-static void compile_clusters(graph_t *g, graph_t *Xg);
-static void dfs(graph_t *g, node_t *n);
-static void break_cycles(graph_t *g);
-static void readout_levels(graph_t *g, graph_t *Xg);
-static void connect_components(graph_t *g);
-
-void dot_levels(graph_t *g)
+/* $Id$Revision: */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+*      This software is part of the graphviz package      *
+*                http://www.graphviz.org/                 *
+*                                                         *
+*            Copyright (c) 1994-2004 AT&T Corp.           *
+*                and is licensed under the                *
+*            Common Public License, Version 1.0           *
+*                      by AT&T Corp.                      *
+*                                                         *
+*        Information and Software Systems Research        *
+*              AT&T Research, Florham Park NJ             *
+**********************************************************/
+
+#include "dot2.h"
+#include "utils.h"
+
+#define        BACKWARD_PENALTY        1000
+#define STRONG_CLUSTER_WEIGHT   1000
+#define        NORANK          6
+
+static int is_a_strong_cluster(graph_t * g);
+static void compile_samerank(graph_t * ug, graph_t * parent_clust);
+static int is_internal_to_cluster(edge_t * e);
+static void compile_nodes(graph_t * g, graph_t * Xg);
+static void strong(graph_t * g, node_t * t, node_t * h, edge_t * orig);
+static void weak(graph_t * g, node_t * t, node_t * h, edge_t * orig);
+static void compile_edges(graph_t * ug, graph_t * Xg);
+static void compile_clusters(graph_t * g, graph_t * Xg);
+static void dfs(graph_t * g, node_t * n);
+static void break_cycles(graph_t * g);
+static void readout_levels(graph_t * g, graph_t * Xg);
+static void connect_components(graph_t * g);
+
+static void my_init_node(Agraph_t *g, Agobj_t *node, void *arg)
+{ int *sz = arg; agbindrec(node,"level node rec",sz[1],TRUE); }
+static void my_init_edge(Agraph_t *g, Agobj_t *edge, void *arg)
+{ int *sz = arg; agbindrec(edge,"level edge rec",sz[2],TRUE); }
+static void my_init_graph(Agraph_t *g, Agobj_t *graph, void *arg)
+{ int *sz = arg; agbindrec(graph,"level graph rec",sz[0],TRUE); }
+static Agcbdisc_t mydisc = { {my_init_graph,0,0}, {my_init_node,0,0}, {my_init_edge,0,0} };
+
+static void agautoinit(Agraph_t *g, int graphinfo_size, int nodeinfo_size, int edgeinfo_size) 
 {
-       graph_t         *Xg = agopen("level assignment constraints",Agstrictdirected,0);
-
-       agautoinit(Xg,sizeof(Agraphinfo_t),sizeof(Agnodeinfo_t),sizeof(Agedgeinfo_t));
-       compile_samerank(g,0);
-       compile_nodes(g,Xg);
-       compile_edges(g,Xg);
-       compile_clusters(g,Xg);
-       break_cycles(Xg);
-       connect_components(Xg);
-       rank(Xg,1,MAXINT);
-       readout_levels(g,Xg);
-}
+    int *s;
 
-static int is_empty(graph_t *g)
-{
-       return (agfstnode(g) == NILnode);
+    s = N_NEW(3,int);  /* until we fix something, this is a storage leak */
+    s[0] = graphinfo_size; s[1] = nodeinfo_size; s[2] = edgeinfo_size;
+    agpushdisc(g,&mydisc,s);
 }
 
-static int is_a_cluster(graph_t *g)
+void dot2_levels(graph_t * g)
 {
-       return ((g == g->root) || (!strncasecmp(agnameof(g),"cluster",7)));
+    int ssize;
+    char* s;
+    graph_t *Xg =
+       agopen("level assignment constraints", Agstrictdirected, 0);
+
+    agautoinit(Xg, sizeof(Agraphinfo_t), sizeof(Agnodeinfo_t),
+              sizeof(Agedgeinfo_t));
+    compile_samerank(g, 0);
+    compile_nodes(g, Xg);
+    compile_edges(g, Xg);
+    compile_clusters(g, Xg);
+    break_cycles(Xg);
+    connect_components(Xg);
+    if ((s = agget(g,"searchsize")))
+       ssize = atoi (s);
+    else
+       ssize = -1;
+    rank2(Xg, 1, INT_MAX, ssize);
+    readout_levels(g, Xg);
 }
 
-static int is_a_strong_cluster(graph_t *g)
+static int is_empty(graph_t * g)
 {
-       char    *str;
-       str = agget(g,"compact");
-       return mapbool((str),TRUE);
+    return (agfstnode(g) == NILnode);
 }
 
-static int rankset_kind(graph_t *g)
+static int is_a_strong_cluster(graph_t * g)
 {
-       char    *str = agget(g,"rank");
-
-       if (str && str[0]) {
-               if (!strcmp(str,"min")) return MINRANK;
-               if (!strcmp(str,"source")) return SOURCERANK;
-               if (!strcmp(str,"max")) return MAXRANK;
-               if (!strcmp(str,"sink")) return SINKRANK;
-               if (!strcmp(str,"same")) return SAMERANK;
-       }
-       return NORANK;
+    char *str = agget(g, "compact");
+    return mapBool((str), TRUE);
 }
 
-static int is_nonconstraint(edge_t *e)
+static int rankset_kind(graph_t * g)
 {
-       char    *str;
-       str = agget(e,"constraint");
-       return mapbool((str),FALSE);
+    char *str = agget(g, "rank");
+
+    if (str && str[0]) {
+       if (!strcmp(str, "min"))
+           return MINRANK;
+       if (!strcmp(str, "source"))
+           return SOURCERANK;
+       if (!strcmp(str, "max"))
+           return MAXRANK;
+       if (!strcmp(str, "sink"))
+           return SINKRANK;
+       if (!strcmp(str, "same"))
+           return SAMERANK;
+    }
+    return NORANK;
 }
 
-static node_t *find(node_t *n)
+int is_nonconstraint(edge_t * e)
 {
-       node_t          *set;
-       if ((set = ND_set(n))) {
-               if (set != n) set = ND_set(n) = find(set);
-       }
-       else set = ND_set(n) = n;
-       return set;
+    char *constr;
+
+    if (E_constr && (constr = agxget(e, E_constr))) {
+       if (constr[0] && mapbool(constr) == FALSE)
+           return TRUE;
+    }
+    return FALSE;
 }
 
-static node_t *union_one(node_t *leader, node_t *n)
+static node_t *find(node_t * n)
 {
-       if (n) return (ND_set(find(n)) = find(leader));
-       else return leader;
+    node_t *set;
+    if ((set = ND_set(n))) {
+       if (set != n)
+           set = ND_set(n) = find(set);
+    } else
+       set = ND_set(n) = n;
+    return set;
 }
 
-static node_t *union_all(graph_t *g)
+static node_t *union_one(node_t * leader, node_t * n)
 {
-       node_t  *n, *leader;
-
-       n = agfstnode(g);
-       if (!n) return n;
-       leader = find(n);
-       while ((n = agnxtnode(g,n)))
-               union_one(leader,n);
+    if (n)
+       return (ND_set(find(n)) = find(leader));
+    else
        return leader;
 }
 
-static void compile_samerank(graph_t *ug, graph_t *parent_clust)
+static node_t *union_all(graph_t * g)
 {
-    graph_t    *s;                     /* subgraph being scanned */
-    graph_t    *clust;         /* cluster that contains the rankset */
-               node_t  *n, *leader;
-
-       if (is_a_cluster(ug)) {
-               clust = ug;
-               GD_parent(ug) = parent_clust;
-               if (parent_clust) GD_level(ug) = GD_level(parent_clust) + 1;
-               else GD_level(ug) = 0;
-       }
-       else clust = parent_clust;
-       if (is_empty(ug)) return;
-
-       /* process subgraphs of this subgraph */
-       for (s = agfstsubg(ug); s; s = agnxtsubg(s))
-               compile_samerank(s,clust);
+    node_t *n, *leader;
+
+    n = agfstnode(g);
+    if (!n)
+       return n;
+    leader = find(n);
+    while ((n = agnxtnode(g, n)))
+       union_one(leader, n);
+    return leader;
+}
 
-       /* process this subgraph as a cluster */
-       if (is_a_cluster(ug)) {
-               for (n = agfstnode(ug); n; n = agnxtnode(ug,n)) {
-                       if (ND_cluster(n) == NILgraph) ND_cluster(n) = ug;
-               }
+static void compile_samerank(graph_t * ug, graph_t * parent_clust)
+{
+    graph_t *s;                        /* subgraph being scanned */
+    graph_t *clust;            /* cluster that contains the rankset */
+    node_t *n, *leader;
+
+    if (is_a_cluster(ug)) {
+       clust = ug;
+       GD_parent(ug) = parent_clust;
+       if (parent_clust)
+           GD_level(ug) = GD_level(parent_clust) + 1;
+       else
+           GD_level(ug) = 0;
+    } else
+       clust = parent_clust;
+    if (is_empty(ug))
+       return;
+
+    /* process subgraphs of this subgraph */
+    for (s = agfstsubg(ug); s; s = agnxtsubg(s))
+       compile_samerank(s, clust);
+
+    /* process this subgraph as a cluster */
+    if (is_a_cluster(ug)) {
+       for (n = agfstnode(ug); n; n = agnxtnode(ug, n)) {
+           if (ND_clust(n) == NILgraph)
+               ND_clust(n) = ug;
+#ifdef DEBUG
+           fprintf(stderr, "(%s) %s  %p\n", agnameof(ug), agnameof(n),
+                   ND_clust(n));
+#endif
        }
+    }
 
     /* process this subgraph as a rankset */
-       switch(rankset_kind(ug)) {
-               case SOURCERANK: GD_has_sourcerank(clust) = TRUE; /* fall through */
-               case MINRANK:
-                       leader = union_all(ug);
-                       GD_minrep(clust) = union_one(leader, GD_minrep(clust));
-                       break;
-               case SINKRANK: GD_has_sinkrank(clust) = TRUE; /* fall through */
-               case MAXRANK:
-                       leader = union_all(ug);
-                       GD_maxrep(clust) = union_one(leader, GD_maxrep(clust));
-                       break;
-               case SAMERANK:
-                       leader = union_all(ug);
-                       /* do we need to record these ranksets? */
-                       break;
-               case NORANK:
-                       break;
-               default:        /* unrecognized - warn and do nothing */
-                       warn3("%s has unrecognized rank=%s",agnameof(ug),agget(ug,"rank"));
-       }
+    switch (rankset_kind(ug)) {
+    case SOURCERANK:
+       GD_has_sourcerank(clust) = TRUE;        /* fall through */
+    case MINRANK:
+       leader = union_all(ug);
+       GD_minrep(clust) = union_one(leader, GD_minrep(clust));
+       break;
+    case SINKRANK:
+       GD_has_sinkrank(clust) = TRUE;  /* fall through */
+    case MAXRANK:
+       leader = union_all(ug);
+       GD_maxrep(clust) = union_one(leader, GD_maxrep(clust));
+       break;
+    case SAMERANK:
+       leader = union_all(ug);
+       /* do we need to record these ranksets? */
+       break;
+    case NORANK:
+       break;
+    default:                   /* unrecognized - warn and do nothing */
+       agerr (AGWARN, "%s has unrecognized rank=%s", agnameof(ug), agget(ug, "rank"));
+    }
 
-       /* a cluster may become degenerate */
+    /* a cluster may become degenerate */
     if (is_a_cluster(ug) && GD_minrep(ug)) {
-               if (GD_minrep(ug) == GD_maxrep(ug)) {
-                       GD_minrep(ug) = GD_maxrep(ug) = union_all(ug);
-               }
+       if (GD_minrep(ug) == GD_maxrep(ug)) {
+           GD_minrep(ug) = GD_maxrep(ug) = union_all(ug);
        }
+    }
 }
 
-graph_t *dot_lca(graph_t *c0, graph_t *c1)
+static graph_t *dot_lca(graph_t * c0, graph_t * c1)
 {
-       while (c0 != c1) {
-               if (GD_level(c0) >= GD_level(c1))
-                       c0 = GD_parent(c0);
-               else c1 = GD_parent(c1);
-       }
-       return c0;
+    while (c0 != c1) {
+       if (GD_level(c0) >= GD_level(c1))
+           c0 = GD_parent(c0);
+       else
+           c1 = GD_parent(c1);
+    }
+    return c0;
 }
 
-static int is_internal_to_cluster(edge_t *e)
+static int is_internal_to_cluster(edge_t * e)
 {
-       graph_t *par,*ct,*ch;
-       ct = ND_cluster(agtail(e));
-       ch = ND_cluster(aghead(e));
-       if (ct == ch) return TRUE;
-       par = dot_lca(ct,ch);
-       if (par == agroot(par)) return FALSE;
-       if ((par == ct) || (par == ch)) return TRUE;
+    graph_t *par, *ct, *ch;
+    ct = ND_clust(agtail(e));
+    ch = ND_clust(aghead(e));
+    if (ct == ch)
+       return TRUE;
+    par = dot_lca(ct, ch);
+    if (par == agroot(par))
        return FALSE;
+    if ((par == ct) || (par == ch))
+       return TRUE;
+    return FALSE;
 }
 
-static void compile_nodes(graph_t *g, graph_t *Xg)
+static void compile_nodes(graph_t * g, graph_t * Xg)
 {
-       /* build variables */
-       node_t  *n;
-       for (n = agfstnode(g); n; n = agnxtnode(g,n)) {
-               if (find(n) == n) ND_rep(n) = agnode(Xg,agnameof(n),TRUE);
-       }
-       for (n = agfstnode(g); n; n = agnxtnode(g,n)) {
-               if (ND_rep(n) == NILnode) ND_rep(n) = ND_rep(find(n));
-       }
+    /* build variables */
+    node_t *n;
+    for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
+       if (find(n) == n)
+           ND_rep(n) = agnode(Xg, agnameof(n), TRUE);
+    }
+    for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
+       if (ND_rep(n) == NILnode)
+           ND_rep(n) = ND_rep(find(n));
+    }
 }
 
-static void merge(edge_t *e, int minlen, int weight)
+static void merge(edge_t * e, int minlen, int weight)
 {
-       ED_minlen(e) = MAX(ED_minlen(e),minlen);
-       ED_weight(e) += weight;
+    ED_minlen(e) = MAX(ED_minlen(e), minlen);
+    ED_weight(e) += weight;
 }
 
-static void strong(graph_t *g, node_t *t, node_t *h, edge_t *orig)
+/*Agedge_t* agfindedge(Agraph_t *g, Agnode_t *t, Agnode_t *h)
+{
+       return agedge(g,t,h,0,0);
+}*/
+
+static void strong(graph_t * g, node_t * t, node_t * h, edge_t * orig)
 {
-       edge_t  *e;
-       if ((e = agfindedge(g,t,h)) ||
-               (e = agfindedge(g,h,t)) ||
-               (e = agedge(g,t,h,(char*)0,TRUE)))
-           merge(e,ED_minlen(orig),ED_weight(orig));
-       else abort();
+    edge_t *e;
+    if ((e = agfindedge(g, t, h)) ||
+       (e = agfindedge(g, h, t)) ||
+       (e = agedge(g, t, h, (char *) 0, TRUE)))
+       merge(e, ED_minlen(orig), ED_weight(orig));
+    else
+       abort();
 }
 
-static void weak(graph_t *g, node_t *t, node_t *h, edge_t *orig)
+static void weak(graph_t * g, node_t * t, node_t * h, edge_t * orig)
 {
-       node_t  *v;
-       edge_t  *e,*f;
-
-       for (e = agfstin(g,t); e; e = agnxtin(g,e)) {
-               /* merge with existing weak edge (e,f) */
-               v = agtail(e);
-               if ((f = agfstout(g,v)) && (aghead(f) == h)) {
-                       return;
-               }
-       }
-       if (!e) {
-               v = agnode(g,0,TRUE);
-               e = agedge(g,v,t,(char*)0,TRUE);
-               f = agedge(g,v,h,(char*)0,TRUE);
+    node_t *v;
+    edge_t *e, *f;
+
+    for (e = agfstin(g, t); e; e = agnxtin(g, e)) {
+       /* merge with existing weak edge (e,f) */
+       v = agtail(e);
+       if ((f = agfstout(g, v)) && (aghead(f) == h)) {
+           return;
        }
-       ED_minlen(e) = MAX(ED_minlen(e),0);     /* effectively a nop */
-       ED_weight(e) += ED_weight(orig) * BACKWARD_PENALTY;
-       ED_minlen(f) = MAX(ED_minlen(f),ED_minlen(orig));
-       ED_weight(f) += ED_weight(orig);
+    }
+    if (!e) {
+       v = agnode(g, 0, TRUE);
+       e = agedge(g, v, t, (char *) 0, TRUE);
+       f = agedge(g, v, h, (char *) 0, TRUE);
+    }
+    ED_minlen(e) = MAX(ED_minlen(e), 0);       /* effectively a nop */
+    ED_weight(e) += ED_weight(orig) * BACKWARD_PENALTY;
+    ED_minlen(f) = MAX(ED_minlen(f), ED_minlen(orig));
+    ED_weight(f) += ED_weight(orig);
 }
 
-static void compile_edges(graph_t *ug, graph_t *Xg)
+static void compile_edges(graph_t * ug, graph_t * Xg)
 {
-       node_t  *n;
-       edge_t  *e;
-       node_t  *Xt,*Xh;
-       graph_t *tc,*hc;
-
-       /* build edge constraints */
-       for (n = agfstnode(ug); n; n = agnxtnode(ug,n)) {
-               Xt = ND_rep(n);
-               for (e = agfstout(ug,n); e; e = agnxtout(ug,e)) {
-                       if (is_nonconstraint(e)) continue;
-                       Xh = ND_rep(find(aghead(e)));
-                       if (Xt == Xh) continue;
-
-                       tc = ND_cluster(agtail(e));
-                       hc = ND_cluster(aghead(e));
-
-                       if (is_internal_to_cluster(e)) {
-                               /* determine if graph requires reversed edge */
-                               if ((find(agtail(e)) == GD_maxrep(ND_cluster(agtail(e))))
-                                || (find(aghead(e)) == GD_minrep(ND_cluster(aghead(e))))) {
-                                       node_t *temp = Xt; Xt = Xh; Xh = temp;
-                               }
-                               strong(Xg,Xt,Xh,e);
-                       }
-                       else {
-                               if (is_a_strong_cluster(tc) || is_a_strong_cluster(hc))
-                                       weak(Xg,Xt,Xh,e);
-                               else
-                                       strong(Xg,Xt,Xh,e);
-                       }
+    node_t *n;
+    edge_t *e;
+    node_t *Xt, *Xh;
+    graph_t *tc, *hc;
+
+    /* build edge constraints */
+    for (n = agfstnode(ug); n; n = agnxtnode(ug, n)) {
+       Xt = ND_rep(n);
+       for (e = agfstout(ug, n); e; e = agnxtout(ug, e)) {
+           if (is_nonconstraint(e))
+               continue;
+           Xh = ND_rep(find(aghead(e)));
+           if (Xt == Xh)
+               continue;
+
+           tc = ND_clust(agtail(e));
+           hc = ND_clust(aghead(e));
+
+           if (is_internal_to_cluster(e)) {
+               /* determine if graph requires reversed edge */
+               if ((find(agtail(e)) == GD_maxrep(ND_clust(agtail(e))))
+                   || (find(aghead(e)) ==
+                       GD_minrep(ND_clust(aghead(e))))) {
+                   node_t *temp = Xt;
+                   Xt = Xh;
+                   Xh = temp;
                }
+               strong(Xg, Xt, Xh, e);
+           } else {
+               if (is_a_strong_cluster(tc) || is_a_strong_cluster(hc))
+                   weak(Xg, Xt, Xh, e);
+               else
+                   strong(Xg, Xt, Xh, e);
+           }
        }
+    }
 }
 
-static char *synthname(Agraph_t *g, char *prefix, char *suffix)
+static char *synthname(Agraph_t * g, char *prefix, char *suffix)
 {
-       char *rv = agalloc(g,strlen(prefix) + strlen(suffix) + 1);
-       strcpy(rv,prefix);
-       strcat(rv,suffix);
-       return rv;
+    char *rv = agalloc(g, strlen(prefix) + strlen(suffix) + 1);
+    strcpy(rv, prefix);
+    strcat(rv, suffix);
+    return rv;
 }
 
-static void compile_clusters(graph_t *g, graph_t *Xg)
+static void compile_clusters(graph_t * g, graph_t * Xg)
 {
-       node_t          *n;
-       node_t          *rep, *top = 0, *bot = 0;
-       edge_t          *e;
-       graph_t         *sub;
-       char            *sname;
-
-       if (is_a_cluster(g) && is_a_strong_cluster(g)) {
-               for (n = agfstnode(g); n; n = agnxtnode(g,n)) {
-                       if (agfstin(g,n) == NILedge) {
-                               rep = ND_rep(find(n));
-                               if (!top) {
-                                       sname = synthname(g,agnameof(g),"_top\177");
-                                       top = agnode(Xg,sname,TRUE);
-                                       agedge(Xg,top,rep,(char*)0,TRUE);
-                                       agfree(g,sname);
-                               }
-                       }
-                       if (agfstout(g,n) == NILedge) {
-                               rep = ND_rep(find(n));
-                               if (!bot) {
-                                       sname = synthname(g,agnameof(g),"_bottom\177");
-                                       bot = agnode(Xg,sname,TRUE);
-                                       agedge(Xg,rep,bot,(char*)0,TRUE);
-                                       agfree(g,sname);
-                               }
-                       }
+    node_t *n;
+    node_t *rep, *top = 0, *bot = 0;
+    edge_t *e;
+    graph_t *sub;
+    char *sname;
+
+    if (is_a_cluster(g) && is_a_strong_cluster(g)) {
+       for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
+           if (agfstin(g, n) == NILedge) {
+               rep = ND_rep(find(n));
+               if (!top) {
+                   sname = synthname(g, agnameof(g), "_top\177");
+                   top = agnode(Xg, sname, TRUE);
+                   agedge(Xg, top, rep, (char *) 0, TRUE);
+                   agfree(g, sname);
                }
-               if (top && bot) {
-                       e = agedge(Xg,top,bot,(char*)0,TRUE);
-                       merge(e,0,STRONG_CLUSTER_WEIGHT);
+           }
+           if (agfstout(g, n) == NILedge) {
+               rep = ND_rep(find(n));
+               if (!bot) {
+                   sname = synthname(g, agnameof(g), "_bottom\177");
+                   bot = agnode(Xg, sname, TRUE);
+                   agedge(Xg, rep, bot, (char *) 0, TRUE);
+                   agfree(g, sname);
                }
+           }
+       }
+       if (top && bot) {
+           e = agedge(Xg, top, bot, (char *) 0, TRUE);
+           merge(e, 0, STRONG_CLUSTER_WEIGHT);
        }
+    }
     for (sub = agfstsubg(g); sub; sub = agnxtsubg(sub))
-               compile_clusters(sub,Xg);
+       compile_clusters(sub, Xg);
 }
 
-static void reverse_edge(graph_t *g, edge_t *e)
+static void reverse_edge(graph_t * g, edge_t * e)
 {
-       edge_t  *rev;
+    edge_t *rev;
 
-       rev = agfindedge(g,aghead(e),agtail(e));
-       if (!rev) rev = agedge(g,aghead(e),agtail(e),(char*)0,TRUE);
-       merge(rev,ED_minlen(e),ED_weight(e));
-       agdelete(g,e);
+    rev = agfindedge(g, aghead(e), agtail(e));
+    if (!rev)
+       rev = agedge(g, aghead(e), agtail(e), (char *) 0, TRUE);
+    merge(rev, ED_minlen(e), ED_weight(e));
+    agdelete(g, e);
 }
 
-static void dfs(graph_t *g, node_t *v)
+static void dfs(graph_t * g, node_t * v)
 {
-    edge_t  *e, *f;
-    node_t  *w;
-                                                                                
-    if (ND_mark(v)) return;
+    edge_t *e, *f;
+    node_t *w;
+
+    if (ND_mark(v))
+       return;
     ND_mark(v) = TRUE;
     ND_onstack(v) = TRUE;
-       for (e = agfstout(g,v); e; e = f) {
-               f = agnxtout(g,e);
-        w = aghead(e);
-        if (ND_onstack(w)) reverse_edge(g,e);
-        else { if (ND_mark(w) == FALSE) dfs(g,w); }
+    for (e = agfstout(g, v); e; e = f) {
+       f = agnxtout(g, e);
+       w = aghead(e);
+       if (ND_onstack(w))
+           reverse_edge(g, e);
+       else {
+           if (ND_mark(w) == FALSE)
+               dfs(g, w);
+       }
     }
     ND_onstack(v) = FALSE;
 }
 
-static void break_cycles(graph_t *g)
+static void break_cycles(graph_t * g)
 {
-       node_t  *n;
+    node_t *n;
 
-       for (n = agfstnode(g); n; n = agnxtnode(g,n))
-               ND_mark(n) = ND_onstack(n) = FALSE;
-       for (n = agfstnode(g); n; n = agnxtnode(g,n))
-               dfs(g,n);
+    for (n = agfstnode(g); n; n = agnxtnode(g, n))
+       ND_mark(n) = ND_onstack(n) = FALSE;
+    for (n = agfstnode(g); n; n = agnxtnode(g, n))
+       dfs(g, n);
 }
 
-static void readout_levels(graph_t *g, graph_t *Xg)
+static void readout_levels(graph_t * g, graph_t * Xg)
 {
-       node_t  *n;
-       for (n = agfstnode(g); n; n = agnxtnode(g,n)) {
-               ND_rank(n) = ND_rank(ND_rep(find(n)));
-       }
+    node_t *n;
+    for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
+       ND_rank(n) = ND_rank(ND_rep(find(n)));
+    }
 }
 
-static void dfscc(graph_t *g, node_t *n, int cc)
+static void dfscc(graph_t * g, node_t * n, int cc)
 {
-       edge_t  *e;
-       if (ND_mark(n) == 0) {
-               ND_mark(n) = cc;
-               for (e = agfstout(g,n); e; e = agnxtout(g,e))
-                       dfscc(g,aghead(e),cc);
-               for (e = agfstin(g,n); e; e = agnxtin(g,e))
-                       dfscc(g,agtail(e),cc);
-       }
+    edge_t *e;
+    if (ND_mark(n) == 0) {
+       ND_mark(n) = cc;
+       for (e = agfstout(g, n); e; e = agnxtout(g, e))
+           dfscc(g, aghead(e), cc);
+       for (e = agfstin(g, n); e; e = agnxtin(g, e))
+           dfscc(g, agtail(e), cc);
+    }
 }
 
-static void connect_components(graph_t *g)
+static void connect_components(graph_t * g)
 {
-       int             cc = 1;
-       node_t  *n;
-       for (n = agfstnode(g); n; n = agnxtnode(g,n))
-               ND_mark(n) = 0;
-       for (n = agfstnode(g); n; n = agnxtnode(g,n))
-               if (ND_mark(n) == 0) dfscc(g,n,cc++);
-       if (cc > 1) {
-               node_t  *root = agnode(g,"\177root",TRUE);
-               int             ncc = 1;
-               for (n = agfstnode(g); n; n = agnxtnode(g,n)) {
-                       if (ND_mark(n) == ncc) {
-                               (void) agedge(g,root,n,(char*)0,TRUE);
-                               ncc++;
-                       }
-               }
+    int cc = 1;
+    node_t *n;
+    for (n = agfstnode(g); n; n = agnxtnode(g, n))
+       ND_mark(n) = 0;
+    for (n = agfstnode(g); n; n = agnxtnode(g, n))
+       if (ND_mark(n) == 0)
+           dfscc(g, n, cc++);
+    if (cc > 1) {
+       node_t *root = agnode(g, "\177root", TRUE);
+       int ncc = 1;
+       for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
+           if (ND_mark(n) == ncc) {
+               (void) agedge(g, root, n, (char *) 0, TRUE);
+               ncc++;
+           }
        }
+    }
 }
 
-static void aaa(graph_t *g)
+static void aaa(graph_t * g)
 {
-       node_t  *n;
-       edge_t  *e;
-       Agsym_t *weight, *minlen, *label;
-       char    buf[64];
-
-       weight = agattr(g,AGEDGE,"weight","");
-       minlen = agattr(g,AGEDGE,"minlen","");
-       label = agattr(g,AGEDGE,"label","");
-       for (n = agfstnode(g); n; n = agnxtnode(g,n)) {
-               for (e = agfstout(g,n); e; e = agnxtout(g,e)) {
-                       sprintf(buf,"%f",ED_weight(e));
-                       agxset(e,weight,buf);
-                       sprintf(buf,"%f",ED_minlen(e));
-                       agxset(e,minlen,buf);
-                       sprintf(buf,"%.3f,%.3f",ED_weight(e),ED_minlen(e));
-                       agxset(e,label,buf);
-               }
+    node_t *n;
+    edge_t *e;
+    Agsym_t *weight, *minlen, *label;
+    char buf[64];
+
+    weight = agattr(g, AGEDGE, "weight", "");
+    minlen = agattr(g, AGEDGE, "minlen", "");
+    label = agattr(g, AGEDGE, "label", "");
+    for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
+       for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
+           sprintf(buf, "%f", ED_weight(e));
+           agxset(e, weight, buf);
+           sprintf(buf, "%d", ED_minlen(e));
+           agxset(e, minlen, buf);
+           sprintf(buf, "%.02f,%d", ED_weight(e), ED_minlen(e));
+           agxset(e, label, buf);
        }
+    }
 }
-void printgraph(Agraph_t *g) {
-       aaa(g);
-       agwrite(g,stderr);
+static void printgraph(Agraph_t * g)
+{
+    aaa(g);
+    agwrite(g, stderr);
 }
 
-int nd_rank(Agnode_t *n) {
-       return ND_rank(n);
+static int nd_rank(Agnode_t * n)
+{
+    return ND_rank(n);
 }
diff --git a/lib/dotgen2/minc.h b/lib/dotgen2/minc.h
new file mode 100644 (file)
index 0000000..42dcc38
--- /dev/null
@@ -0,0 +1,133 @@
+/* $Id$Revision: */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+*      This software is part of the graphviz package      *
+*                http://www.graphviz.org/                 *
+*                                                         *
+*            Copyright (c) 1994-2004 AT&T Corp.           *
+*                and is licensed under the                *
+*            Common Public License, Version 1.0           *
+*                      by AT&T Corp.                      *
+*                                                         *
+*        Information and Software Systems Research        *
+*              AT&T Research, Florham Park NJ             *
+**********************************************************/
+
+
+#ifndef         MINC_H
+#define         MINC_H
+
+typedef enum {mcGrVer,mcGrHor,mcBoth} mcGroupAlign_t;
+typedef enum {mcGrLoose,mcGrStrict} mcGroup_t;
+typedef enum {mcCountLower,mcCountHigher,mcCountAll} mcCountMethod;
+
+typedef struct mcNode mcNode;
+typedef struct {
+    mcGroupAlign_t alignType;
+    mcGroup_t type;
+    int cnt;
+    Dt_t* nodes;
+#if 0
+    Dt_t* children;
+#endif
+} mcGroup;
+
+typedef struct {
+    Agedge_t* e; /*pointer to cgraph edge*/
+    mcNode* lowerN;
+    mcNode* higherN;
+    port lowerPort;
+    port higherPort;
+    float penalty;
+} mcEdge;
+
+struct mcNode {
+    float order;
+    float groupOrder;
+    int rank;
+    int isLeader;
+    mcNode* leader;
+    float prevOrder[3];
+    float x;
+    float y;
+    float w;    /*weight*/
+    mcEdge** low_edgs;
+    mcEdge** high_edgs;
+    int high_edgs_cnt;
+    int low_edgs_cnt;
+    Agnode_t* node;
+    mcGroup* group;
+    void* level;
+    int flag; /*general purpose flag*/
+    char* name;
+};
+
+typedef struct {
+    int rank;
+    mcNode** nodes;
+    int nodecnt;
+    int lowerEdgeCount;
+    int higherEdgeCount;
+    int lowCnt;   /*cached crossing counts*/
+    int highCnt;   /*cached crossing counts*/
+    int candidate;
+} mcLevel;
+
+typedef struct {
+    mcLevel** lvls;
+    int lvl_cnt;
+    int crossCnt;
+    Agraph_t* g;
+} mcGraph;
+
+typedef struct {
+    Agrec_t hdr;
+    node_t  *set;                           /* for union-find */
+    graph_t *cluster;                       /* lowest containing cluster */
+    union {
+       node_t  *v;
+       edge_t  *e;
+       graph_t *g;
+    } rep;
+    Agnode_t* orig;
+    int     type;
+    int     rank;
+    int     order;
+    float orderr;
+    mcNode* mcn;
+    graph_t *highCluster;                   /* highest containing cluster */
+    int inBucket;
+} mcnodeinfo_t;
+
+#define MND_FIELD(g,field)  (((mcnodeinfo_t*)((g)->base.data))->field)
+#define MND_orig(n)    MND_FIELD(n,orig)
+#define MND_type(n)    MND_FIELD(n,type)
+#define MND_rank(n)    MND_FIELD(n,rank)
+#define MND_order(n)   MND_FIELD(n,order)
+#define MND_orderr(n)  MND_FIELD(n,orderr)
+#define MND_mcn(n)     MND_FIELD(n,mcn)
+#define MND_inBucket(n)        MND_FIELD(n,inBucket)
+#define MND_highCluster(n)     MND_FIELD(n,highCluster)
+
+typedef struct {
+    Agrec_t hdr;
+    Agedge_t* orig;
+    port  tail_port, head_port;
+    int deleteFlag;
+    int cutval;
+    int type;
+} mcedgeinfo_t;
+
+#define MED_FIELD(g,field)  (((mcedgeinfo_t*)((g)->base.data))->field)
+#define MED_type(n)    MED_FIELD(n,type)
+#define MED_orig(n)    MED_FIELD(n,orig)
+#define MED_deleteFlag(n)      MED_FIELD(n,deleteFlag)
+#define MED_head_port(n)       MED_FIELD(n,head_port)
+#define MED_tail_port(n)       MED_FIELD(n,tail_port)
+
+extern Agraph_t* mkMCGraph (Agraph_t*);
+extern Agnode_t *mkMCNode (Agraph_t * g, int type, char *name);
+extern Agedge_t* mkMCEdge (Agraph_t* g, Agnode_t* tail, Agnode_t* head, char*, int type, Agedge_t* orige);
+
+#endif
diff --git a/lib/dotgen2/minc2.c b/lib/dotgen2/minc2.c
new file mode 100644 (file)
index 0000000..8b9ed84
--- /dev/null
@@ -0,0 +1,1432 @@
+/* $Id$Revision: */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+*      This software is part of the graphviz package      *
+*                http://www.graphviz.org/                 *
+*                                                         *
+*            Copyright (c) 1994-2004 AT&T Corp.           *
+*                and is licensed under the                *
+*            Common Public License, Version 1.0           *
+*                      by AT&T Corp.                      *
+*                                                         *
+*        Information and Software Systems Research        *
+*              AT&T Research, Florham Park NJ             *
+**********************************************************/
+
+#include "dot2.h"
+#include "utils.h"
+#include "minc.h"
+#include "groups.h"
+
+/* #include "transpose.h" */
+/* #include "stdio.h" */
+
+#ifdef DEBUG_CAIRO
+static void drawMatrix(mcGraph * mcG, char *fileName, char *label);
+#define DOC_HEIGHT  1600
+#define DOC_WIDTH  2400
+#endif
+#define DEBUG
+#ifdef DEBUG
+static void dumpGraph (mcGraph* mcG, char* fname);
+#endif
+
+static int MAGIC_NUMBER = 4;
+
+static int higher_cross(mcNode * v, mcNode * w)
+{
+    mcEdge *e;
+    mcEdge *e2;
+    float x1, xx1;
+    float x2, xx2;
+    int idx, idx2;
+    int cnt = 0;
+    for (idx = 0; idx < v->high_edgs_cnt; idx++) {
+       e = v->high_edgs[idx];
+       x1 = e->lowerPort.p.x + e->lowerN->order;
+       xx1 = e->higherPort.p.x + e->higherN->order;
+       for (idx2 = 0; idx2 < w->high_edgs_cnt; idx2++) {
+           e2 = w->high_edgs[idx2];
+
+           x2 = e2->lowerPort.p.x + e2->lowerN->order;
+           xx2 = e2->higherPort.p.x + e2->higherN->order;
+           if (((x1 < x2) && (xx1 > xx2)) || ((x2 < x1) && (xx2 > xx1))) {
+               if (e->penalty > e2->penalty)
+                   cnt = cnt + e->penalty;
+               else
+                   cnt = cnt + e2->penalty;
+           }
+       }
+    }
+    return cnt;
+}
+
+static int lower_cross(mcNode * v, mcNode * w)
+{
+
+    mcEdge *e;
+    mcEdge *e2;
+    float x1, xx1;
+    float x2, xx2;
+    int idx, idx2;
+    int cnt = 0;
+    for (idx = 0; idx < v->low_edgs_cnt; idx++) {
+       e = v->low_edgs[idx];
+       x1 = e->lowerPort.p.x + e->lowerN->order;
+       xx1 = e->higherPort.p.x + e->higherN->order;
+       for (idx2 = 0; idx2 < w->low_edgs_cnt; idx2++) {
+           e2 = w->low_edgs[idx2];
+
+           x2 = e2->lowerPort.p.x + e2->lowerN->order;
+           xx2 = e2->higherPort.p.x + e2->higherN->order;
+           if (((x1 < x2) && (xx1 > xx2)) || ((x2 < x1) && (xx2 > xx1))) {
+               if (e->penalty > e2->penalty)
+                   cnt = cnt + e->penalty;
+               else
+                   cnt = cnt + e2->penalty;
+           }
+       }
+    }
+    return cnt;
+}
+
+static int pair_cross(mcNode * v, mcNode * w, int lowToHigh)
+{
+    if (lowToHigh)
+       return lower_cross(v, w);
+    else
+       return higher_cross(v, w);
+}
+
+/*counts all crossings*/
+static int countAllX(mcGraph * mcG)
+{
+    mcLevel *l;
+    mcNode *n;
+    mcNode *n2;
+    int cnt = 0;
+    int id0, id1;
+    int idx;
+
+    for (idx = 0; idx < mcG->lvl_cnt; idx++) {
+       l = mcG->lvls[idx];
+       for (id0 = 0; id0 < l->nodecnt; id0++) {
+           n = l->nodes[id0];
+           for (id1 = 0; id1 < l->nodecnt; id1++) {
+               n2 = l->nodes[id1];
+               if (id0 != id1) {
+                   int aa;
+                   aa = pair_cross(n, n2, 1);
+                   if (aa > 0) {
+                       aa = pair_cross(n, n2, 1);
+                       cnt = cnt + aa;
+
+                   }
+               }
+           }
+       }
+    }
+    return cnt / 2;
+
+}
+
+int node_cmp(const mcNode ** a, const mcNode ** b)
+{
+    float ia;
+    float ib;
+
+    ia = (*a)->order;
+    ib = (*b)->order;
+    if (ia < ib)
+       return -1;
+    else if (ia > ib)
+       return 1;
+    else
+       return 0;
+}
+
+void reOrderLevel(mcLevel * l)
+{
+    qsort(l->nodes, l->nodecnt, sizeof(mcNode *), (qsort_cmpf) node_cmp);
+}
+
+/*returns relative improvement*/
+
+static int transpose(mcLevel * l, int lowToHigh)
+{
+    mcNode *n;
+    mcNode *n2;
+    float temp;
+    int id;
+    int improvement = 0;
+
+     /*DEBUG*/
+/*    
+    for (n=dtfirst(l->nodes);n;n=dtnext(l->nodes,n))
+       printf("%s %f\n",agnameof(n->node),n->order);
+*/
+        /*DEBUG*/ for (id = 0; id < l->nodecnt - 1; id++) {
+
+       int c, cc, d, dd;
+       n = l->nodes[id];
+       n2 = l->nodes[id + 1];
+//        printf ("comparing %s %s \n",agnameof(n->node),agnameof(n2->node));
+       c = pair_cross(n, n2, lowToHigh);
+       d = pair_cross(n, n2, !lowToHigh);
+       /*test swap */
+       temp = n2->order;
+       n2->order = n->order;
+       n->order = temp;
+
+       cc = pair_cross(n, n2, lowToHigh);
+       dd = pair_cross(n, n2, !lowToHigh);
+//      if(((  cc-c) + (dd-d)) >= 0)
+       if ((c - cc) <= 0) {
+           temp = n2->order;
+           n2->order = n->order;
+           n->order = temp;
+           improvement = 0;
+       } else {
+           improvement = (cc - c);
+           l->nodes[id] = n2;
+           l->nodes[id + 1] = n;
+       }
+    }
+    reOrderLevel(l);
+//    printf ("improvement value :%d\n",improvement);
+    return improvement;
+}
+
+/*
+    lowToHigh=1;
+    0 0 0 0 0   <-----------l
+    XX||XX||
+
+    lowToHigh=0;
+    XX||XX||
+    0 0 0 0 0   <-----------l
+*/
+#if 0
+static int countx(mcLevel * l, int lowToHigh)
+{
+    mcNode *n;
+    mcNode *n2;
+    int cnt = 0;
+    int id0, id1;
+    for (id0 = 0; id0 < l->nodecnt; id0++) {
+       n = l->nodes[id0];
+       for (id1 = 0; id1 < l->nodecnt; id1++) {
+           n2 = l->nodes[id1];
+           if (id0 != id1) {
+               int aa;
+               aa = pair_cross(n, n2, lowToHigh);
+               if (aa > 0) {
+                   aa = pair_cross(n, n2, lowToHigh);
+                   cnt = cnt + aa;
+
+               }
+           }
+       }
+    }
+    return cnt;
+}
+#endif
+
+/*
+    adds maxRank-minRank nodes to given edge
+    g:newly created graph, not the original one ,
+    e:edge needs to be splitted in new graph
+    reference edge in original graph
+
+*/
+
+static void add_node(Agraph_t * g, Agedge_t * e, int labels)
+{
+    /*find out how the ranks increase ,it may not always be from tail to head! */
+
+    int rankDiff;
+    int i;
+    Agnode_t *tmpN;
+    Agedge_t *tmpE;
+    Agnode_t *tail;
+    Agnode_t *head;
+    Agraph_t *cluster = NULL;
+    Agraph_t *tempC1 = NULL;
+    Agraph_t *tempC2 = NULL;
+
+    int type = INTNODE;
+
+    head = aghead(e);
+    tail = agtail(e);
+#if 0
+    if ((strcmp(agnameof(head), "T1") == 0)
+       && (strcmp(agnameof(tail), "23") == 0))
+       fprintf(stderr, "found \n");
+    if ((strcmp(agnameof(head), "23") == 0)
+       && (strcmp(agnameof(tail), "T1") == 0))
+       fprintf(stderr, "found \n");
+#endif
+
+    /*check whether edge is a cluster */
+    tempC1 = MND_highCluster(head);
+    tempC2 = MND_highCluster(tail);
+
+    if (tempC1 == tempC2)
+       cluster = tempC1;
+
+    rankDiff = MND_rank(head) - MND_rank(tail);
+    if ((rankDiff == 1) || (rankDiff == -1))
+       return;
+    if (rankDiff == 0)
+       return;
+
+    if (rankDiff > 0)          /*expected */
+       for (i = MND_rank(tail) + 1; i < MND_rank(head); i++) {
+
+           if (labels) {
+               if (type == LBLNODE)
+                   type = INTNODE;
+               else
+                   type = LBLNODE;
+           } else
+               type = INTNODE;
+           tmpN = mkMCNode (g, type, (char *) 0);
+
+           MND_rank(tmpN) = i;
+           MND_type(tmpN) = type;
+           MND_highCluster(tmpN) = cluster;
+           MND_orderr(tmpN) = MND_orderr(tail);
+           /*create internal edge */
+           tmpE = mkMCEdge (g, tail, tmpN, 0, VIRTUAL, MED_orig(e));
+           tail = tmpN;
+    } else
+       for (i = MND_rank(tail) - 1; i > MND_rank(head); i--) {
+           if (labels) {
+               if (type == LBLNODE)
+                   type = INTNODE;
+               else
+                   type = LBLNODE;
+           } else
+               type = INTNODE;
+           tmpN = mkMCNode (g, type, (char *) 0);
+
+           MND_rank(tmpN) = i;
+           MND_type(tmpN) = type;
+           MND_highCluster(tmpN) = cluster;
+           /*create internal edge */
+           tmpE = mkMCEdge (g, tail, tmpN, 0, VIRTUAL, MED_orig(e));
+           tail = tmpN;
+       }
+    tmpE = mkMCEdge (g, tail, head, 0, VIRTUAL, MED_orig(e));
+    /*mark the long edge for deletion */
+    MED_deleteFlag(e) = 1;
+}
+
+/*
+  creates temporary nodes to the graph , 
+  if hasLabels is true (1) all ranks are doubled and every edge is splitted to 2
+*/
+static void addNodes(Agraph_t * g, int hasLabels)
+{
+    Agnode_t *v;
+    Agedge_t *e;
+    Agedge_t *ee = NULL;
+    Agedge_t **eList = NULL;           /*for technical reasons i add dummy edges after the loop */
+    int tempEdgeCnt = 0;
+    int id = 0;
+
+    for (v = agfstnode(g); v; v = agnxtnode(g, v)) {
+       int type = MND_type(v);
+       if (type != STDNODE)
+           continue;
+       for (e = agfstout(g, v); e; e = agnxtout(g, e)) {
+           if (MED_type(e) == VIRTUAL)
+               continue;
+           eList = RALLOC(tempEdgeCnt + 1, eList, Agedge_t *);
+           eList[tempEdgeCnt] = e;
+           tempEdgeCnt++;
+       }
+    }
+    for (id = 0; id < tempEdgeCnt; id++)
+       add_node(g, eList[id], hasLabels);
+
+    /*delete long edges */
+    for (v = agfstnode(g); v; v = agnxtnode(g, v)) {
+       for (e = agfstout(g, v); e; e = agnxtout(g, e)) {
+           if (ee)
+               agdelete(g, ee);
+           if (MED_deleteFlag(e) == 1)
+               ee = e;
+           else
+               ee = NULL;
+       }
+    }
+}
+
+/*double all ranks if one or more edge have label*/
+static void double_ranks(Agraph_t * g)
+{
+    Agnode_t *v;
+    for (v = agfstnode(g); v; v = agnxtnode(g, v))
+       MND_rank(v) = MND_rank(v) * 2;
+}
+
+/*constructions for data structe */
+
+static void
+free_mcGroup (mcGroup* g)
+{
+    dtclose (g->nodes);
+#if 0
+    dtclose (g->children);
+#endif
+    free (g);
+}
+
+static void
+free_mcEdge (mcEdge* e)
+{
+    free (e);
+}
+
+static void
+free_mcNode (mcNode* n)
+{
+    int i;
+
+    if (n->isLeader)
+       free_mcGroup (n->group);
+    for (i = 0; i < n->low_edgs_cnt; i++)
+       free_mcEdge (n->low_edgs[i]);
+    for (i = 0; i < n->high_edgs_cnt; i++)
+       free_mcEdge (n->high_edgs[i]);
+    free (n->low_edgs);
+    free (n->high_edgs);
+    free (n->name);
+    free (n);
+}
+
+static void
+free_mcLevel (mcLevel* l)
+{
+    int i;
+
+    for (i = 0; i < l->nodecnt; i++)
+       free_mcNode (l->nodes[i]);
+    l->nodecnt++;
+    free (l->nodes);
+    free (l);
+}
+
+static void
+free_mcGraph (mcGraph* mcg)
+{
+    int idx;
+
+    for (idx = 0; idx < mcg->lvl_cnt; idx++)
+       free_mcLevel (mcg->lvls[idx]);
+    free (mcg->lvls);
+    free (mcg);
+}
+
+static mcNode *initMcNode(Agnode_t * n)
+{
+    mcNode *rv;
+    rv = NEW(mcNode);
+    rv->group = NULL;
+    if (MND_orderr(n) < 0)
+       MND_orderr(n) = 0;
+    rv->order = MND_orderr(n);
+    rv->w = 0;
+    rv->node = n;
+    MND_mcn(n) = rv;
+    MND_type(n) = STDNODE;
+    rv->groupOrder = 0;
+    rv->groupOrder = -1;
+    rv->isLeader = 0;
+    rv->leader = NULL;
+    rv->name = strdup(agnameof(n));
+    rv->high_edgs_cnt = 0;
+    rv->low_edgs = NULL;
+    rv->low_edgs_cnt = 0;
+    rv->high_edgs = NULL;
+    return rv;
+}
+
+static mcEdge *initMcEdge(Agedge_t * e)
+{
+    mcEdge *rv;
+    rv = NEW(mcEdge);
+    rv->e = e;
+    rv->lowerN = NULL;
+    rv->higherN = NULL;
+    rv->penalty = 1;
+    return rv;
+
+}
+
+static mcLevel *initMcLevel(int rank)
+{
+    mcLevel *rv;
+    rv = NEW(mcLevel);
+    rv->nodes = NULL;
+    rv->nodecnt = 0;
+    rv->rank = rank;
+    rv->higherEdgeCount = 0;
+    rv->lowerEdgeCount = 0;
+    rv->highCnt = 1000000000;
+    rv->lowCnt = 1000000000;
+    return rv;
+}
+
+static void addEdgeToNode(mcNode * n, mcEdge * e, int lowEdge)
+{
+    if (lowEdge) {
+       n->low_edgs_cnt++;
+       n->low_edgs = RALLOC(n->low_edgs_cnt, n->low_edgs, mcEdge *);
+       n->low_edgs[n->low_edgs_cnt - 1] = e;
+    } else {
+       n->high_edgs_cnt++;
+       n->high_edgs = RALLOC(n->high_edgs_cnt, n->high_edgs, mcEdge *);
+       n->high_edgs[n->high_edgs_cnt - 1] = e;
+    }
+}
+
+static void addAdjEdges(Agnode_t * n)
+{
+    Agnode_t *av;
+    Agedge_t *e;
+    Agraph_t *g;
+    int rank;
+    mcNode *mcN;
+    mcEdge *mcE;
+    mcLevel *l;
+    g = agraphof(n);
+    rank = MND_rank(n);
+    mcN = MND_mcn(n);
+    l = mcN->level;
+
+    for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
+       av = aghead(e);
+       mcE = initMcEdge(e);
+       if (MND_rank(av) <= rank) {
+           addEdgeToNode(mcN, mcE, 1);
+           mcE->lowerN = MND_mcn(av);
+           mcE->higherN = mcN;
+           mcE->lowerPort = MED_head_port(e);
+           mcE->higherPort = MED_tail_port(e);
+
+       } else {
+           addEdgeToNode(mcN, mcE, 0);
+           mcE->higherN = MND_mcn(av);
+           mcE->lowerN = mcN;
+           mcE->lowerPort = MED_tail_port(e);
+           mcE->higherPort = MED_head_port(e);
+       }
+    }
+    for (e = agfstin(g, n); e; e = agnxtin(g, e)) {
+       av = agtail(e);
+       mcE = initMcEdge(e);
+       if (MND_rank(av) < rank) {
+           addEdgeToNode(mcN, mcE, 1);
+           mcE->lowerN = MND_mcn(av);
+           mcE->higherN = mcN;
+           mcE->lowerPort = MED_tail_port(e);
+           mcE->higherPort = MED_head_port(e);
+       } else {
+           addEdgeToNode(mcN, mcE, 0);
+           mcE->higherN = MND_mcn(av);
+           mcE->lowerN = mcN;
+           mcE->lowerPort = MED_head_port(e);
+           mcE->higherPort = MED_tail_port(e);
+       }
+    }
+
+    l->higherEdgeCount = mcN->high_edgs_cnt;
+    l->lowerEdgeCount = mcN->high_edgs_cnt;
+
+}
+
+#if 0
+static void addToMcGroup(mcGroup * group, mcNode * mcN)
+{
+    if ((!group) || (!mcN))
+       return;
+    dtappend(group->nodes, mcN);
+}
+#endif
+
+static mcGraph *newMcGraph(Agraph_t * g)
+{
+    int maxRank = 0;
+    Agnode_t *v;
+    mcGraph *rv;
+    int ind = 0;
+
+    for (v = agfstnode(g); v; v = agnxtnode(g, v)) {
+       if (MND_rank(v) > maxRank)
+           maxRank = MND_rank(v);
+    }
+
+    rv = NEW(mcGraph);
+
+    rv->lvls = NULL;
+    rv->lvl_cnt = 0;
+    rv->crossCnt = 0;
+    rv->g = g;
+
+    for (ind = 0; ind <= maxRank; ind++) {
+       mcLevel *l = initMcLevel(ind);
+       rv->lvl_cnt++;
+       rv->lvls = RALLOC(rv->lvl_cnt, rv->lvls, mcLevel*);
+       rv->lvls[rv->lvl_cnt - 1] = l;
+    }
+    return rv;
+
+}
+static void addToLevel(mcNode * n, mcGraph * mcG)
+{
+    int rank = MND_rank(n->node);
+    mcLevel *l;
+    l = mcG->lvls[rank];
+    n->order = l->nodecnt;
+    l->nodecnt++;
+    l->nodes = RALLOC (l->nodecnt, l->nodes, mcNode*);
+    l->nodes[l->nodecnt - 1] = n;
+    MND_orderr(n->node) = n->order;
+    n->level = l;
+}
+
+/*
+ creates the data structure for mincross algorithms
+ -mcGraph
+ --mcLevel
+ ---mcNode
+ ----mcNode (lower adj. nodes)
+ ----mcNode (upper adj. nodes)
+*/
+static int inEdgeCnt(Agnode_t * n, Agraph_t * g)
+{
+    Agedge_t *e;
+    int cnt = 0;
+    for (e = agfstin(g, n); e; e = agnxtin(g, e))
+       cnt++;
+    return cnt;
+}
+
+static int outEdgeCnt(Agnode_t * n, Agraph_t * g)
+{
+    Agedge_t *e;
+    int cnt = 0;
+    for (e = agfstout(g, n); e; e = agnxtout(g, e))
+       cnt++;
+    return cnt;
+}
+
+static void install_node(Agnode_t * n, mcGraph * mcg)
+{
+    static int cnt = 0;
+    mcNode *mcn;
+    mcn = initMcNode(n);
+    addToLevel(mcn, mcg);
+    cnt++;
+}
+
+Agnode_t *nodeByName(Agraph_t * g, char *name)
+{
+    Agnode_t *v;
+    for (v = agfstnode(g); v; v = agnxtnode(g, v)) {
+       if (strcmp(agnameof(v), name) == 0)
+           return v;
+    }
+    return NULL;
+}
+
+
+#if 0
+static createMatrixWithNames(Agraph_t * g, mcGraph * mcG)
+{
+    char *nodeNames[] = { "asasdasdsad", "adadsd" };
+    int cnt = 23;
+    int id;
+    Agnode_t *v;
+    for (id = 0; id < cnt; id++) {
+       v = nodeByName(g, nodeNames[id]);
+       if (v)
+           install_node(v, mcG);
+    }
+
+    for (id = 0; id < cnt; id++) {
+       v = nodeByName(g, nodeNames[id]);
+       if (v)
+           addAdjEdges(v);
+    }
+    id = countAllX(mcG);
+}
+#endif
+
+static int transposeAllL2H(mcGraph * mcG)
+{
+    int cnt = 0;
+    mcLevel *l;
+    int rank;
+    int improved = 0;
+    int idx;
+    for (idx = 0; idx < mcG->lvl_cnt; idx++)
+       mcG->lvls[idx]->candidate = 1;
+    rank = 0;
+    l = mcG->lvls[0];
+    idx = 0;
+    do {
+       if (l->candidate) {
+           int a;
+
+           a = transpose(l, 1);
+           cnt = cnt + a;
+           if (a < 0) {
+               l->candidate = 1;
+               if (idx > 0)
+                   mcG->lvls[idx - 1]->candidate = 1;
+               if (idx < (mcG->lvl_cnt - 1))
+                   mcG->lvls[idx + 1]->candidate = 1;
+
+               improved = 1;
+           } else
+               l->candidate = 0;
+
+       }
+       idx++;
+       if (idx == mcG->lvl_cnt) {
+           if (!improved)
+               break;
+
+           idx = 0;
+           improved = 0;
+       }
+       l = mcG->lvls[idx];
+
+    } while (1);
+    return cnt;
+}
+static int transposeAllH2L(mcGraph * mcG)
+{
+    int cnt = 0;
+    mcLevel *l;
+    int rank;
+    int improved = 0;
+    int idx;
+    for (idx = 0; idx < mcG->lvl_cnt; idx++)
+       mcG->lvls[idx]->candidate = 1;
+    rank = 0;
+    l = mcG->lvls[mcG->lvl_cnt - 1];
+    idx = mcG->lvl_cnt - 1;
+    do {
+       if (l->candidate) {
+           int a;
+
+           a = transpose(l, 0);
+           cnt = cnt + a;
+           if (a < 0) {
+               l->candidate = 1;
+               if (idx > 0)
+                   mcG->lvls[idx - 1]->candidate = 1;
+               if (idx < (mcG->lvl_cnt - 1))
+                   mcG->lvls[idx + 1]->candidate = 1;
+
+               improved = 1;
+           } else
+               l->candidate = 0;
+
+       }
+       idx--;
+       if (idx == -1) {
+           if (!improved)
+               break;
+
+           idx = mcG->lvl_cnt - 1;
+           improved = 0;
+       }
+       l = mcG->lvls[idx];
+
+    } while (1);
+    return cnt;
+}
+
+
+static mcGraph *createMatrixIn(Agraph_t * g)
+{
+    Agedge_t *e;
+    Agnode_t *v;
+    Agnode_t *v0;
+    nodequeue *b;
+    Agnode_t *head;
+    mcGraph *mcG;
+    int id = 0;
+    b = new_queue(agnnodes(g));
+    mcG = newMcGraph(g);
+    for (v = agfstnode(g); v; v = agnxtnode(g, v)) {
+       if ((inEdgeCnt(v, g) == 0) && (MND_inBucket(v) != 1)) {
+           enqueue(b, v);
+           MND_inBucket(v) = 1;
+
+           while ((v0 = dequeue(b))) {
+               if (Verbose)
+                   fprintf(stderr, "installing %s\n", agnameof(v0));
+               install_node(v0, mcG);
+               for (e = agfstout(g, v0); e; e = agnxtout(g, e)) {
+                   head = aghead(e);
+                   if ((MND_inBucket(head) != 1)) {
+                       enqueue(b, head);
+                       MND_inBucket(head) = 1;
+                   }
+               }
+           }
+
+       }
+    }
+    free_queue (b); 
+    for (v = agfstnode(g); v; v = agnxtnode(g, v))
+       addAdjEdges(v);
+    id = countAllX(mcG);
+#ifdef DEBUG
+    dumpGraph (mcG, "before.gv");
+#endif
+    transposeAllL2H(mcG);
+    id = countAllX(mcG);
+
+    return mcG;
+
+}
+static mcGraph *createMatrixOut(Agraph_t * g)
+{
+    Agedge_t *e;
+    Agnode_t *v;
+    Agnode_t *v0;
+    nodequeue *b;
+    Agnode_t *tail;
+    mcGraph *mcG;
+    b = new_queue(agnnodes(g));
+    mcG = newMcGraph(g);
+    for (v = agfstnode(g); v; v = agnxtnode(g, v)) {
+       if ((outEdgeCnt(v, g) == 0) && (MND_inBucket(v) != 1)) {
+           enqueue(b, v);
+           MND_inBucket(v) = 1;
+
+           while ((v0 = dequeue(b))) {
+               install_node(v0, mcG);
+               if (Verbose)
+                   fprintf(stderr, "installing %s\n", agnameof(v0));
+
+               for (e = agfstin(g, v0); e; e = agnxtin(g, e)) {
+                   tail = agtail(e);
+                   if ((MND_inBucket(tail) != 1)) {
+                       enqueue(b, tail);
+                       MND_inBucket(tail) = 1;
+                   }
+               }
+           }
+
+       }
+    }
+    free_queue (b); 
+    for (v = agfstnode(g); v; v = agnxtnode(g, v))
+       addAdjEdges(v);
+    transposeAllH2L(mcG);
+
+
+    return mcG;
+}
+
+/*
+    calculates new positions of nodes by using median values,
+    inOrder=1 direction is from lower rank to higher rank
+    inorder=0 direction is from higher rank to lower rank
+    this functions returns the local crossing count (count of passed level)
+*/
+static int int_cmp(const void *a, const void *b)
+{
+    const int *ia = (const int *) a;   // casting pointer types
+    const int *ib = (const int *) b;
+    return *ia - *ib;
+    /* integer comparison: returns negative if b > a 
+       and positive if a > b */
+}
+
+
+static int nodeMedian(mcNode * n, int lowToHigh)
+{
+    int P[1024];
+    int id = 0;
+    int m;
+    int ps;
+    mcEdge **edges;
+    int left;
+    int right;
+    mcEdge *e;
+    if (lowToHigh) {
+       edges = n->low_edgs;
+       m = n->low_edgs_cnt;
+
+    } else {
+       edges = n->high_edgs;
+       m = n->high_edgs_cnt;
+
+    }
+    ps = m;
+    m = m / 2;
+    for (id = 0; id < ps; id++) {
+       e = edges[id];
+       if (lowToHigh)
+           P[id] = e->lowerN->order;
+       else
+           P[id] = e->higherN->order;
+    };
+    qsort(P, ps, sizeof(int), int_cmp);
+    if (ps == 0)
+       return -1;
+    if ((ps % 2) == 1)
+       return P[m];
+    if (ps == 2) {
+       return (P[0] + P[1]) / 2;
+    }
+    left = P[m - 1] - P[0];
+    right = P[ps - 1] - P[m];
+    return (P[m - 1] * right + P[m] * left) / (left + right);
+
+
+
+
+
+/*
+12. procedure median_value(v,adj_rank)
+13. P = adj_position(v,adj_rank);
+14. m = Ãº Pú /2;
+15. if Ãº Pú = 0 then
+16. return -1.0;
+17. elseif Ãº Pú mod 2 == 1 then
+18. return P[m];
+19. elseif Ãº Pú = 2 then
+20. return (P[0] + P[1])/2;
+21. else
+22. left = P[m-1] - P[0];
+23. right = P[ú Pú -1] - P[m];
+24. return (P[m-1]*right + P[m]*left)/(left+right);
+25. endif
+26. end
+*/
+
+
+}
+
+
+static int nodeMedian2(mcNode * n, int lowToHigh)
+{
+/*    int edgeCnt;
+    int median;
+    int even=0;
+    float newOrder;
+    Dt_t* edges;
+    mcEdge* e;
+    if (lowToHigh)
+        edges=n->low_edgs;
+    else
+        edges=n->high_edgs;
+    edgeCnt=dtsize(edges);
+    if(edgeCnt==0)
+       return -1;
+    if(edgeCnt % 2 == 0)
+           even=1;
+    edgeCnt=edgeCnt /2;
+    for(e=dtfirst(edges);edgeCnt > 0;edgeCnt--)
+        e=dtnext(edges,e);
+    if(lowToHigh)
+        newOrder=e->lowerN->order;
+    else
+        newOrder=e->higherN->order;
+    if(even)
+    {
+        e=dtprev(edges,e);
+        if(lowToHigh)
+           newOrder=(newOrder+e->lowerN->order)/2;
+        else
+           newOrder=(newOrder+e->higherN->order)/2;
+    }
+//    return newOrder;
+    return nodeMedian2( n,lowToHigh);*/
+    return 0;
+}
+
+static void normalizeLevel(mcLevel * l)
+{
+    int id = 0;
+    mcNode *n;
+    for (id = 0; id < l->nodecnt; id++) {
+       n = l->nodes[id];
+       n->order = id;
+    }
+
+}
+static void reSetNodePos(mcGraph * mcG, mcLevel * l, int lowToHigh)
+{
+    mcNode *n;
+    int id = 0;
+    float order;
+    float order2;
+    for (id = 0; id < l->nodecnt; id++) {
+       n = l->nodes[id];
+       order = nodeMedian(n, lowToHigh);
+       order2 = nodeMedian(n, (lowToHigh + 1) % 2);
+       if (order == -1)
+           order = n->order;
+       if (order2 == -1)
+           order2 = order;
+       if (MAGIC_NUMBER != 0)
+           n->order = (order + order2 / MAGIC_NUMBER);
+       else
+           n->order = order;
+       MND_orderr(n->node) = n->order;
+    }
+    //normalize
+
+    reOrderLevel(l);
+    normalizeLevel(l);
+}
+
+static void cacheOrders(mcGraph * mcg, int cacheId)
+{
+    mcNode *n;
+    mcLevel *l;
+    int id = 0;
+    int idx;
+    for (idx = 0; idx < mcg->lvl_cnt; idx++) {
+       l = mcg->lvls[idx];
+       for (id = 0; id < l->nodecnt; id++) {
+           n = l->nodes[id];
+           n->prevOrder[cacheId] = n->order;
+       }
+    }
+}
+
+static void loadOrders(mcGraph * mcg, int cacheId)
+{
+    mcNode *n;
+    mcLevel *l;
+    int id = 0;
+    int idx;
+    for (idx = 0; idx < mcg->lvl_cnt; idx++) {
+       l = mcg->lvls[idx];
+       for (id = 0; id < l->nodecnt; id++) {
+           n = l->nodes[id];
+           n->order = n->prevOrder[cacheId];
+       }
+    }
+}
+
+static void wMedianLevel(mcLevel * l, mcGraph * mg, int lowToHigh)
+{
+    if (lowToHigh)
+       reSetNodePos(mg, l, 1);
+    else
+       reSetNodePos(mg, l, 0);
+
+}
+static void dumbcross(mcGraph * mcG, int pass)
+{
+    mcLevel *l;
+    int idx;
+    int it = 0;
+    int lowToHigh = 0;
+    int best;
+    for (idx = 0; idx < mcG->lvl_cnt; idx++) {
+       l = mcG->lvls[idx];
+       reOrderLevel(l);
+       normalizeLevel(l);
+    }
+    cacheOrders(mcG, 0);       /*save init pos */
+    best = mcG->crossCnt = countAllX(mcG);
+    fprintf(stderr, "original crossing count : %d\n", mcG->crossCnt);
+    for (it = 0; it < pass; it++) {
+       if (lowToHigh == 0)
+           lowToHigh = 1;
+       else
+           lowToHigh = 0;
+       /*low to high */
+       if (lowToHigh) {
+           int cnt = 0;
+           cacheOrders(mcG, 0);
+           for (idx = 0; idx < mcG->lvl_cnt; idx++) {
+               l = mcG->lvls[idx];
+               wMedianLevel(l, mcG, lowToHigh);
+           }
+           cnt = countAllX(mcG);
+           transposeAllL2H(mcG);
+           cnt = countAllX(mcG);
+           if (cnt < best) {
+               best = cnt;
+               cacheOrders(mcG, 0);
+
+           } else
+               loadOrders(mcG, 0);
+           fprintf(stderr, "%d -> %d\n\n", best, cnt);
+       } else {
+           int cnt = 0;
+           cacheOrders(mcG, 0);
+           for (idx = mcG->lvl_cnt - 1; idx >= 0; idx--) {
+               l = mcG->lvls[idx];
+               wMedianLevel(l, mcG, lowToHigh);
+           }
+           transposeAllL2H(mcG);
+           cnt = countAllX(mcG);
+           if (cnt < best) {
+               best = cnt;
+               cacheOrders(mcG, 0);
+
+           } else
+               loadOrders(mcG, 0);
+           fprintf(stderr, "%d -> %d\n\n", best, cnt);
+       }
+    }
+
+}
+
+void clusterEdges(mcGraph * mcG)
+{
+    mcLevel *l;
+    mcNode *n = NULL;
+    mcEdge *e = NULL;
+    int id, id2;
+    Agnode_t *n1;
+    Agnode_t *n2;
+    int idx = 0;
+    for (idx = 0; idx < mcG->lvl_cnt; idx++) {
+       l = mcG->lvls[idx];
+       for (id = 0; id < l->nodecnt; id++) {
+           n = l->nodes[id];
+           for (id2 = 0; id2 < n->low_edgs_cnt; id2++) {
+               e = n->low_edgs[id2];
+               n1 = e->higherN->node;
+               n2 = e->lowerN->node;
+               if (MND_highCluster(n1) == MND_highCluster(n2))
+                   if (MND_highCluster(n1)) {
+                       e->penalty = 10000;
+                       e->higherN->order = -1;
+                       e->lowerN->order = -1;
+
+                   }
+
+           }
+       }
+
+    }
+
+
+    for (idx = mcG->lvl_cnt - 1; idx >= 0; idx--) {
+       l = mcG->lvls[idx];
+
+       for (id = 0; id < l->nodecnt; id++) {
+           n = l->nodes[id];
+           for (id2 = 0; id2 < n->high_edgs_cnt; id2++) {
+               e = n->high_edgs[id2];
+               n1 = e->higherN->node;
+               n2 = e->lowerN->node;
+               if (MND_highCluster(n1) == MND_highCluster(n2))
+                   if (MND_highCluster(n1)) {
+                       e->penalty = 10000;
+                       e->higherN->order = -1;
+                       e->lowerN->order = -1;
+
+                   }
+
+           }
+       }
+
+    }
+
+
+
+    for (idx = 0; idx < mcG->lvl_cnt; idx++) {
+
+       reOrderLevel(l);
+       normalizeLevel(l);
+    }
+
+
+
+}
+
+/*temp function to compare old and new dot*/
+static void readOrders(Agraph_t * g)
+{
+    Agnode_t *v;
+    char *bf;
+    for (v = agfstnode(g); v; v = agnxtnode(g, v)) {
+       bf = agget(v, "order");
+       if (bf) {
+           MND_order(v) = atoi(bf);
+//              MND_rank(v)=atoi(bf);
+           fprintf(stderr, "retrieved order :%d\n", MND_order(v));
+       }
+    }
+}
+
+static void mincross(mcGraph * mcG)
+{
+    int id;
+    //   drawMatrix(mcG,"I0-original.png","a_original");
+#ifdef DEBUG
+    /* dumpGraph (mcG, "before.gv"); */
+#endif
+    for (id = 20; id >= 0; id--) {
+       MAGIC_NUMBER = id;
+       dumbcross(mcG, 25);
+    }
+    for (id = 0; id <= 15; id++) {
+       MAGIC_NUMBER = id;
+       dumbcross(mcG, 10);
+    }
+    for (id = 0; id < 10; id++) {
+       transposeAllL2H(mcG);
+       transposeAllH2L(mcG);
+    }
+    fprintf(stderr,"after transpose final count %d...\n", countAllX(mcG));
+#ifdef DEBUG_CAIRO
+    drawMatrix(mcG, "after.png", "after mincross");
+#endif
+#ifdef DEBUG
+    dumpGraph (mcG, "after.gv");
+#endif
+}
+
+Agraph_t *dot2_mincross (Agraph_t * srcGraph)
+{
+    mcGraph *mcG;
+    Agraph_t *g = mkMCGraph (srcGraph);
+//    readOrders(srcGraph);
+
+/*
+    for (v = agfstnode(g); v; v = agnxtnode(g, v)) {
+       fprintf(stderr,"order:%d  rank:%d\n",MND_order(v),MND_rank(v));
+    }
+*/
+
+    graphGroups(g);
+    if (agattr(srcGraph, AGEDGE, "label", (char *) 0)) {
+       double_ranks(g);
+       addNodes(g, 1);
+    } else
+       addNodes(g, 0);
+    nodesToClusters(g);
+
+    mcG = createMatrixIn(g);
+    fprintf(stderr, "in :%d\n", countAllX(mcG));
+/*    mcG=createMatrixOut(g);
+    fprintf(stderr, ("out :%d\n",countAllX(mcG));*/
+
+    createGroups(mcG->g);
+    clusterEdges(mcG);
+    mincross(mcG);
+
+    /* store order info in g */
+    free_mcGraph (mcG);
+    return g;
+}
+
+#ifdef DEBUG
+static void dumpGraph (mcGraph* mcG, char* fname)
+{
+    FILE* fp = fopen (fname, "w");
+    int id, id2, idx;
+    mcLevel *l;
+    mcLevel *nextl;
+    mcNode *n;
+    mcNode *nn;
+    mcEdge *e;
+    int dely = 72;
+    int delx = 100;
+    char* color;
+    char buf[512];
+    char buf2[512];
+    int width, maxl;
+
+    if (!fp) {
+       fprintf (stderr, "Could not open %s for writing\n", fname);
+       return;
+    }
+    fputs ("digraph {\n", fp);
+    fputs ("  node[shape=box fontsize=8]\n", fp);
+    maxl = 0;
+    for (idx = 0; idx < mcG->lvl_cnt; idx++) {
+       l = mcG->lvls[idx];
+       if (l->nodecnt > maxl) maxl = l->nodecnt;
+
+    }
+    width = delx*(maxl+2);
+    for (idx = 0; idx < mcG->lvl_cnt; idx++) {
+       l = mcG->lvls[idx];
+        delx = width/(l->nodecnt + 1); 
+       for (id = 0; id < l->nodecnt; id++) {
+           n = l->nodes[id];
+           sprintf(buf, "%s(%0.1f)", agnameof(n->node), n->order);
+           if (n->group)
+               color = "red";
+           else
+               color = "black";
+           fprintf (fp, "  \"%s\" [pos=\"%d,%d\" color=%s]\n", buf, (id+1)*delx, -dely*idx, color);
+       }
+
+    }
+    for (idx = 0; idx < mcG->lvl_cnt-1; idx++) {
+       l = mcG->lvls[idx];
+       nextl = mcG->lvls[idx + 1];
+       for (id = 0; id < l->nodecnt; id++) {
+           n = l->nodes[id];
+           sprintf(buf, "%s(%0.1f)", agnameof(n->node), n->order);
+           for (id2 = 0; id2 < n->high_edgs_cnt; id2++) {
+               e = n->high_edgs[id2];
+               nn = e->higherN;
+               sprintf(buf2, "%s(%0.1f)", agnameof(nn->node), nn->order);
+               if (e->penalty > 1)
+                   color = "red";
+               else
+                   color = "black";
+               fprintf (fp, "  \"%s\" -> \"%s\" [color=%s]\n", buf, buf2, color);
+           }
+       }
+    }
+    fputs ("}\n", fp);
+    fclose (fp);
+}
+#endif
+
+#ifdef DEBUG_CAIRO
+#include <cairo/cairo.h>
+#include <pango/pangocairo.h>
+#include <png.h>
+
+static int
+writer(void *closure, const unsigned char *data, unsigned int length)
+{
+    if (length == fwrite(data, 1, length, (FILE *) closure)) {
+       return CAIRO_STATUS_SUCCESS;
+    }
+
+    return CAIRO_STATUS_WRITE_ERROR;
+}
+
+static void drawMatrix(mcGraph * mcG, char *fileName, char *label)
+{
+    int ind = 0;
+    mcLevel *l;
+    mcLevel *nextl;
+    mcNode *n;
+    mcNode *nn;
+    mcEdge *e;
+    int id, idx, id2;
+    int x = 0;
+    int y = 10;
+    int ex = 0;
+    int ey = 0;
+    FILE *output_file;
+    cairo_t *cr;
+    int c = 1;
+    int rectW = 30;
+    int rectH = 30;
+    char buf[512];
+
+    int verDist = (DOC_HEIGHT - 150) / (mcG->lvl_cnt - 1);
+    cairo_surface_t *surface =
+       cairo_image_surface_create(CAIRO_FORMAT_ARGB32, DOC_WIDTH + 100,
+                                  DOC_HEIGHT);
+    cr = cairo_create(surface);
+    cairo_select_font_face(cr, "Arial", CAIRO_FONT_SLANT_NORMAL,
+                          CAIRO_FONT_WEIGHT_NORMAL);
+
+    for (idx = 0; idx < mcG->lvl_cnt; idx++) {
+       int crossing = -1;
+       l = mcG->lvls[idx];
+       c = 1;
+/*
+        nextl=dtnext(mcG->levels,l);
+       if(nextl)
+       {
+           crossing=countx(l,nextl);
+           sprintf(buf,"cross:(%d)",crossing);
+           cairo_set_font_size(cr,(double)16);
+           cairo_move_to (cr, 0, y+rectH-3);
+           cairo_text_path(cr,buf);
+           cairo_stroke (cr);
+
+       }
+*/
+       for (id = 0; id < l->nodecnt; id++) {
+           static flip = 0;
+           n = l->nodes[id];
+           sprintf(buf, "%s(%0.1f)", agnameof(n->node), n->order);
+           x = (DOC_WIDTH / (l->nodecnt + 1)) * c;
+           if (n->group)
+               cairo_set_source_rgb(cr, 1, 0, 0);
+           else
+               cairo_set_source_rgb(cr, 0, 0, 0);
+
+           cairo_rectangle(cr, x, y, rectW, rectH);
+           cairo_set_font_size(cr, (double) 18);
+           cairo_move_to(cr, x + 3, y + rectH - 3 + flip * 20);
+           cairo_text_path(cr, buf);
+           cairo_stroke(cr);
+           n->x = x;
+           n->y = y;
+           c++;
+           if (flip == 0)
+               flip = 1;
+           else
+               flip = 0;
+       }
+       y = y + verDist;
+
+    }
+    cairo_set_source_rgb(cr, 0, 0, 0);
+    cairo_set_font_size(cr, (double) 16);
+    cairo_move_to(cr, 0, 30);
+    cairo_text_path(cr, label);
+    cairo_stroke(cr);
+    for (idx = 0; idx < mcG->lvl_cnt; idx++) {
+       l = mcG->lvls[idx];
+       if (idx < mcG->lvl_cnt - 1)
+           nextl = mcG->lvls[idx + 1];
+       else
+           nextl = NULL;
+       for (id = 0; id < l->nodecnt; id++) {
+           n = l->nodes[id];
+           if (nextl) {
+               x = n->x;
+               y = n->y;
+               for (id2 = 0; id2 < n->high_edgs_cnt; id2++) {
+                   e = n->high_edgs[id2];
+                   nn = e->higherN;
+                   ex = nn->x;
+                   ey = nn->y;
+                   cairo_move_to(cr, x + rectW / 2, y + rectH);
+                   if (e->penalty > 1)
+                       cairo_set_source_rgb(cr, 1, 0, 0);
+                   else
+                       cairo_set_source_rgb(cr, 0, 0, 0);
+
+                   cairo_line_to(cr, ex, ey);
+                   cairo_stroke(cr);
+               }
+           }
+       }
+
+    }
+
+    sprintf(buf, "c:/temp/%s.png", fileName);
+    output_file = fopen(buf, "wb+");
+
+    if (output_file) {
+       cairo_surface_write_to_png_stream(surface, writer, output_file);
+    }
+    fclose(output_file);
+}
+#endif
diff --git a/lib/dotgen2/minc_utils.c b/lib/dotgen2/minc_utils.c
new file mode 100644 (file)
index 0000000..4ad8834
--- /dev/null
@@ -0,0 +1,167 @@
+/* $Id$Revision: */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+*      This software is part of the graphviz package      *
+*                http://www.graphviz.org/                 *
+*                                                         *
+*            Copyright (c) 1994-2004 AT&T Corp.           *
+*                and is licensed under the                *
+*            Common Public License, Version 1.0           *
+*                      by AT&T Corp.                      *
+*                                                         *
+*        Information and Software Systems Research        *
+*              AT&T Research, Florham Park NJ             *
+**********************************************************/
+
+#include "dot2.h"
+#include "minc.h"
+
+typedef struct {
+    Dtlink_t link;
+    Agedge_t *key;
+    Agedge_t *val;
+} edgepair_t;
+
+static Agedge_t*
+mapEdge (Dt_t* emap, Agedge_t* e)
+{
+     edgepair_t* ep = dtmatch (emap, &e);
+     if (ep) return ep->val;
+     else return NULL;
+}
+
+static int cmppair(Dt_t * d, Agedge_t** key1, Agedge_t** key2, Dtdisc_t * disc)
+{
+    if (*key1 > *key2) return 1;
+    else if (*key1 < *key2) return -1;
+    else return 0;
+}
+
+static Dtdisc_t edgepair = {
+    offsetof(edgepair_t, key),
+    sizeof(Agedge_t*),
+    offsetof(edgepair_t, link),
+    NIL(Dtmake_f),
+    NIL(Dtfree_f),
+    (Dtcompar_f) cmppair,
+    NIL(Dthash_f),
+    NIL(Dtmemory_f),
+    NIL(Dtevent_f)
+};
+
+static void
+cloneSubg (Agraph_t* parent, Agraph_t* sg, Dt_t* emap)
+{
+    Agraph_t* subg;
+    Agnode_t* t;
+    Agedge_t* e;
+    Agnode_t* newt;
+    Agedge_t* newe;
+    Agraph_t* newg;
+
+    if (is_a_cluster(sg)) {
+       newg = agsubg (parent, agnameof(sg), 1);
+       parent = newg; 
+
+       for (t = agfstnode(sg); t; t = agnxtnode(sg, t)) {
+           newt = agnode(newg, agnameof(t), 0);
+            agsubnode(newg, newt, 1);
+           /* if e is in sg, both end points are, so we can use out edges */
+           for (e = agfstout(sg, t); e; e = agnxtout(sg, e)) {
+               newe = mapEdge (emap, e);
+               agsubedge(newg, newe, 1);
+           }
+       }
+    }
+
+    for (subg = agfstsubg(sg); subg; subg = agnxtsubg(subg)) {
+       cloneSubg(parent, subg, emap);
+    }
+}
+
+/* mkMCGraph:
+ * Clone original graph. We only need the nodes, edges and clusters.
+ * Copy
+ */
+Agraph_t* 
+mkMCGraph (Agraph_t* g)
+{
+    Agnode_t* t;
+    Agnode_t* newt;
+    Agnode_t* newh;
+    Agedge_t* e;
+    Agedge_t* newe;
+    Agraph_t* sg;
+    Agraph_t* newg = agopen (agnameof(g), g->desc, 0);
+    Dt_t* emap = dtopen (&edgepair, Dtoset);;
+    edgepair_t* data = N_NEW(agnedges(g), edgepair_t);
+    edgepair_t* ep = data;
+
+    for (t = agfstnode(g); t; t = agnxtnode(g, t)) {
+       newt = mkMCNode (newg, STDNODE, agnameof(t));
+       assert(newt);
+        MND_orig(newt) = t;
+        MND_rank(newt) = ND_rank(t);
+    }
+
+    for (t = agfstnode(g); t; t = agnxtnode(g, t)) {
+        newt = agnode (newg, agnameof(t), 0);
+       for (e = agfstout(g, t); e; e = agnxtout(g, e)) {
+           newh = agnode (newg, agnameof(aghead(e)), 0);
+           assert(newh);
+            newe = mkMCEdge (newg, newt, newh, agnameof (e), NORMAL, e); 
+           assert(newe);
+           ep->key = e;
+           ep->val = newe;
+           dtinsert (emap, ep++);
+       }
+    }
+
+    for (sg = agfstsubg(g); sg; sg = agnxtsubg(sg)) {
+       cloneSubg(newg, sg, emap);
+    }
+
+    dtclose (emap);
+    free (data);
+
+    return newg;
+}
+
+/* mkMCNode:
+    returns a new node
+    unless a name is provided, depending on the node type either a temporary node or a temp label node is returned
+    otherwise a regular node is returned.
+    it is caller's responsibility to set necessary edges
+*/
+Agnode_t *mkMCNode (Agraph_t * g, int type, char *name)
+{
+    static int k = 0;
+    Agnode_t *rv;
+    char buf[512];
+    switch (type) {
+    case INTNODE:
+       sprintf(buf, "____tempN%d", k++);       /*unique node name for internal nodes */
+       rv = agnode(g, buf, 1);
+       break;
+    case LBLNODE:
+       sprintf(buf, "____lblN%d", k++);        /*unique node name for labels */
+       rv = agnode(g, buf, 1);
+       break;
+    default:
+       rv = agnode(g, name, 1);
+    }
+    agbindrec(rv, "mcnodeinfo_t", sizeof(mcnodeinfo_t), TRUE);
+    MND_type(rv) = type;
+    return rv;
+}
+
+Agedge_t* mkMCEdge (Agraph_t* g, Agnode_t* tail, Agnode_t* head, char* name, int type, Agedge_t* orige)
+{
+    Agedge_t* tmpE = agedge(g, tail, head, name, 1);
+    agbindrec(tmpE, "mcedgeinfo_t", sizeof(mcedgeinfo_t), TRUE);
+    MED_type(tmpE) = type;
+    MED_orig(tmpE) = orige;
+    return tmpE;
+}
+
index 1abaeeb7142ab80e9c212621565ac169eee9f4e0..61c87ef7a5c1118f67a993a3bea30cb1d09a5435 100644 (file)
+/* $Id$Revision: */
+/* vim:set shiftwidth=4 ts=8: */
+
+/**********************************************************
+*      This software is part of the graphviz package      *
+*                http://www.graphviz.org/                 *
+*                                                         *
+*            Copyright (c) 1994-2004 AT&T Corp.           *
+*                and is licensed under the                *
+*            Common Public License, Version 1.0           *
+*                      by AT&T Corp.                      *
+*                                                         *
+*        Information and Software Systems Research        *
+*              AT&T Research, Florham Park NJ             *
+**********************************************************/
+
 /* 
  * Network Simplex Algorithm for Ranking Nodes of a DAG
  */
 
-#include "newdot.h"
+#include "render.h"
 
 static int init_graph(graph_t *);
-static void dfs_cutval(node_t* v, edge_t* par);
-static int dfs_range(node_t* v, edge_t* par, int low);
-static int x_val(edge_t* e, node_t* v, int dir);
+static void dfs_cutval(node_t * v, edge_t * par);
+static int dfs_range(node_t * v, edge_t * par, int low);
+static int x_val(edge_t * e, node_t * v, int dir);
 
 #define LENGTH(e)              (ND_rank(aghead(e)) - ND_rank(agtail(e)))
 #define SLACK(e)               (LENGTH(e) - ED_minlen(e))
 #define SEQ(a,b,c)             (((a) <= (b)) && ((b) <= (c)))
 #define TREE_EDGE(e)   (ED_tree_index(e) >= 0)
 
-static graph_t *G;
-static int             N_nodes,N_edges;
-static int             Minrank,Maxrank;
-static int             S_i;            /* search index for enter_edge */
-static int             Search_size;
+static graph_t *G;
+static int N_nodes, N_edges;
+static int Minrank, Maxrank;
+static int S_i;                        /* search index for enter_edge */
+static int Search_size;
 #define SEARCHSIZE 30
-static elist_t Tree_edge;
-static nlist_t Tree_node;
+static elist Tree_edge;
+static nlist_t Tree_node;
 
-static void 
-add_tree_edge(edge_t* e)
+static void add_tree_edge(edge_t * e)
 {
-       node_t  *n;
-       if (TREE_EDGE(e)) abort();
-       ED_tree_index(e) = Tree_edge.size;
-       Tree_edge.list[Tree_edge.size++] = e;
-       if (ND_mark(agtail(e)) == FALSE) Tree_node.list[Tree_node.size++] = agtail(e);
-       if (ND_mark(aghead(e)) == FALSE) Tree_node.list[Tree_node.size++] = aghead(e);
-       n = agtail(e);
-       ND_mark(n) = TRUE;
-       ND_tree_out(n).list[ND_tree_out(n).size++] = e;
-       ND_tree_out(n).list[ND_tree_out(n).size] = NULL;
-       n = aghead(e);
-       ND_mark(n) = TRUE;
-       ND_tree_in(n).list[ND_tree_in(n).size++] = e;
-       ND_tree_in(n).list[ND_tree_in(n).size] = NULL;
+    node_t *n;
+    if (TREE_EDGE(e))
+       abort();
+    ED_tree_index(e) = Tree_edge.size;
+    Tree_edge.list[Tree_edge.size++] = e;
+    if (ND_mark(agtail(e)) == FALSE)
+       Tree_node.list[Tree_node.size++] = agtail(e);
+    if (ND_mark(aghead(e)) == FALSE)
+       Tree_node.list[Tree_node.size++] = aghead(e);
+    n = agtail(e);
+    ND_mark(n) = TRUE;
+    ND_tree_out(n).list[ND_tree_out(n).size++] = e;
+    ND_tree_out(n).list[ND_tree_out(n).size] = NULL;
+    n = aghead(e);
+    ND_mark(n) = TRUE;
+    ND_tree_in(n).list[ND_tree_in(n).size++] = e;
+    ND_tree_in(n).list[ND_tree_in(n).size] = NULL;
 }
 
-static void 
-exchange_tree_edges(edge_t *e,edge_t *f)
+static void exchange_tree_edges(edge_t * e, edge_t * f)
 {
-       int             i,j;
-       node_t  *n;
-
-       ED_tree_index(f) = ED_tree_index(e);
-       Tree_edge.list[ED_tree_index(e)] = f;
-       ED_tree_index(e) = -1;
-
-       n = agtail(e);
-       i = --(ND_tree_out(n).size);
-       for (j = 0; j <= i; j++) if (ND_tree_out(n).list[j] == e) break;
-       ND_tree_out(n).list[j] = ND_tree_out(n).list[i];
-       ND_tree_out(n).list[i] = NULL;
-       n = aghead(e);
-       i = --(ND_tree_in(n).size);
-       for (j = 0; j <= i; j++) if (ND_tree_in(n).list[j] == e) break;
-       ND_tree_in(n).list[j] = ND_tree_in(n).list[i];
-       ND_tree_in(n).list[i] = NULL;
-
-       n = agtail(f);
-       ND_tree_out(n).list[ND_tree_out(n).size++] = f;
-       ND_tree_out(n).list[ND_tree_out(n).size] = NULL;
-       n = aghead(f);
-       ND_tree_in(n).list[ND_tree_in(n).size++] = f;
-       ND_tree_in(n).list[ND_tree_in(n).size] = NULL;
+    int i, j;
+    node_t *n;
+
+    ED_tree_index(f) = ED_tree_index(e);
+    Tree_edge.list[ED_tree_index(e)] = f;
+    ED_tree_index(e) = -1;
+
+    n = agtail(e);
+    i = --(ND_tree_out(n).size);
+    for (j = 0; j <= i; j++)
+       if (ND_tree_out(n).list[j] == e)
+           break;
+    ND_tree_out(n).list[j] = ND_tree_out(n).list[i];
+    ND_tree_out(n).list[i] = NULL;
+    n = aghead(e);
+    i = --(ND_tree_in(n).size);
+    for (j = 0; j <= i; j++)
+       if (ND_tree_in(n).list[j] == e)
+           break;
+    ND_tree_in(n).list[j] = ND_tree_in(n).list[i];
+    ND_tree_in(n).list[i] = NULL;
+
+    n = agtail(f);
+    ND_tree_out(n).list[ND_tree_out(n).size++] = f;
+    ND_tree_out(n).list[ND_tree_out(n).size] = NULL;
+    n = aghead(f);
+    ND_tree_in(n).list[ND_tree_in(n).size++] = f;
+    ND_tree_in(n).list[ND_tree_in(n).size] = NULL;
 }
 
 static
 void init_rank(void)
 {
-       int                     ctr;
-       queue           *Q;
-       node_t          *v;
-       edge_t          *e;
-
-       Q = new_queue(N_nodes);
-       ctr = 0;
-
-       for (v = agfstnode(G); v; v = agnxtnode(G,v)) {
-               if (ND_priority(v) == 0) enqueue(Q,v);
-       }
-
-       while ((v = dequeue(Q))) {
-               ND_rank(v) = 0;
-               ctr++;
-               for (e = agfstin(G,v); e; e = agnxtin(G,e))
-                       ND_rank(v) = MAX(ND_rank(v),ND_rank(agtail(e)) + ED_minlen(e));
-               for (e = agfstout(G,v); e; e = agnxtout(G,e))
-                       if (--(ND_priority(aghead(e))) <= 0) enqueue(Q,aghead(e));
+    int ctr;
+    nodequeue *Q;
+    node_t *v;
+    edge_t *e;
+
+    Q = new_queue(N_nodes);
+    ctr = 0;
+
+    for (v = agfstnode(G); v; v = agnxtnode(G, v)) {
+       if (ND_priority(v) == 0)
+           enqueue(Q, v);
+    }
+
+    while ((v = dequeue(Q))) {
+       ND_rank(v) = 0;
+       ctr++;
+       for (e = agfstin(G, v); e; e = agnxtin(G, e))
+           ND_rank(v) =
+               MAX(ND_rank(v), ND_rank(agtail(e)) + ED_minlen(e));
+       for (e = agfstout(G, v); e; e = agnxtout(G, e))
+           if (--(ND_priority(aghead(e))) <= 0)
+               enqueue(Q, aghead(e));
+    }
+    if (ctr != N_nodes) {
+       agerr(AGERR, "trouble in init_rank\n");
+       for (v = agfstnode(G); v; v = agnxtnode(G, v)) {
+           if (ND_priority(v))
+               agerr(AGPREV, "\t%s %d\n", agnameof(v), ND_priority(v));
        }
-       if (ctr != N_nodes) {
-               agerr(AGERR, "trouble in init_rank\n");
-               for (v = agfstnode(G); v; v = agnxtnode(G,v)) {
-                       if (ND_priority(v))
-                               agerr(AGPREV, "\t%s %d\n",agnameof(v),ND_priority(v));
-               }
-       }
-       free_queue(Q);
+    }
+    free_queue(Q);
 }
 
-static node_t *
-incident(edge_t* e)
+static node_t *incident(edge_t * e)
 {
-       if (ND_mark(agtail(e))) {
-               if (ND_mark(aghead(e)) == FALSE)
-                       return agtail(e);
-       }
-       else {
-               if (ND_mark(aghead(e)))
-                       return aghead(e);
-       }
-       return NULL;
+    if (ND_mark(agtail(e))) {
+       if (ND_mark(aghead(e)) == FALSE)
+           return agtail(e);
+    } else {
+       if (ND_mark(aghead(e)))
+           return aghead(e);
+    }
+    return NULL;
 }
 
-static edge_t *
-leave_edge (void)
+static edge_t *leave_edge(void)
 {
-       edge_t                  *f,*rv = NULL;
-       int                             j,cnt = 0;
-
-       j = S_i;
-       while (S_i < Tree_edge.size) {
-               if (ED_cutval((f = Tree_edge.list[S_i])) < 0) {
-                       if (rv) {
-                               if (ED_cutval(rv) > ED_cutval(f)) rv = f;
-                       }
-                       else rv = Tree_edge.list[S_i];
-                       if (++cnt >= Search_size) return rv;
-               }
-               S_i++;
+    edge_t *f, *rv = NULL;
+    int j, cnt = 0;
+
+    j = S_i;
+    while (S_i < Tree_edge.size) {
+       if (ED_cutvalue((f = Tree_edge.list[S_i])) < 0) {
+           if (rv) {
+               if (ED_cutvalue(rv) > ED_cutvalue(f))
+                   rv = f;
+           } else
+               rv = Tree_edge.list[S_i];
+           if (++cnt >= Search_size)
+               return rv;
        }
-       if (j > 0) {
-               S_i = 0;
-               while (S_i < j) {
-                       if (ED_cutval((f = Tree_edge.list[S_i])) < 0) {
-                               if (rv) {
-                                       if (ED_cutval(rv) > ED_cutval(f)) rv = f;
-                               }
-                               else rv = Tree_edge.list[S_i];
-                               if (++cnt >= Search_size) return rv;
-                       }
-                       S_i++;
-               }
+       S_i++;
+    }
+    if (j > 0) {
+       S_i = 0;
+       while (S_i < j) {
+           if (ED_cutvalue((f = Tree_edge.list[S_i])) < 0) {
+               if (rv) {
+                   if (ED_cutvalue(rv) > ED_cutvalue(f))
+                       rv = f;
+               } else
+                   rv = Tree_edge.list[S_i];
+               if (++cnt >= Search_size)
+                   return rv;
+           }
+           S_i++;
        }
-       return rv;
+    }
+    return rv;
 }
 
-static edge_t  *Enter;
-static int             Low,Lim,Slack;
+static edge_t *Enter;
+static int Low, Lim, Slack;
 
-static void 
-dfs_enter_outedge(node_t* v)
+static void dfs_enter_outedge(node_t * v)
 {
-       int             i, slack;
-       edge_t  *e;
-
-       for (e = agfstout(G,v); e; e = agnxtout(G,e)) {
-               if (TREE_EDGE(e) == FALSE) {
-                       if (!SEQ(Low,ND_lim(aghead(e)),Lim)) {
-                               slack = SLACK(e);
-                               if ((slack < Slack) || (Enter == NULL)) {
-                                       Enter = e;
-                                       Slack = slack;
-                               }
-                       }
+    int i, slack;
+    edge_t *e;
+
+    for (e = agfstout(G, v); e; e = agnxtout(G, e)) {
+       if (TREE_EDGE(e) == FALSE) {
+           if (!SEQ(Low, ND_lim(aghead(e)), Lim)) {
+               slack = SLACK(e);
+               if ((slack < Slack) || (Enter == NULL)) {
+                   Enter = e;
+                   Slack = slack;
                }
-               else if (ND_lim(aghead(e)) < ND_lim(v)) dfs_enter_outedge(aghead(e));
-       }
-       for (i = 0; (e = ND_tree_in(v).list[i]) && (Slack > 0); i++)
-               if (ND_lim(agtail(e)) < ND_lim(v)) dfs_enter_outedge(agtail(e));
+           }
+       } else if (ND_lim(aghead(e)) < ND_lim(v))
+           dfs_enter_outedge(aghead(e));
+    }
+    for (i = 0; (e = ND_tree_in(v).list[i]) && (Slack > 0); i++)
+       if (ND_lim(agtail(e)) < ND_lim(v))
+           dfs_enter_outedge(agtail(e));
 }
 
-static void 
-dfs_enter_inedge(node_t* v)
+static void dfs_enter_inedge(node_t * v)
 {
-       int             i,slack;
-       edge_t  *e;
-
-       for (e = agfstin(G,v); e; e = agnxtin(G,e)) {
-               if (TREE_EDGE(e) == FALSE) {
-                       if (!SEQ(Low,ND_lim(agtail(e)),Lim)) {
-                               slack = SLACK(e);
-                               if ((slack < Slack) || (Enter == NULL)) {
-                                       Enter = e;
-                                       Slack = slack;
-                               }
-                       }
+    int i, slack;
+    edge_t *e;
+
+    for (e = agfstin(G, v); e; e = agnxtin(G, e)) {
+       if (TREE_EDGE(e) == FALSE) {
+           if (!SEQ(Low, ND_lim(agtail(e)), Lim)) {
+               slack = SLACK(e);
+               if ((slack < Slack) || (Enter == NULL)) {
+                   Enter = e;
+                   Slack = slack;
                }
-               else if (ND_lim(agtail(e)) < ND_lim(v)) dfs_enter_inedge(agtail(e));
-       }
-       for (i = 0; (e = ND_tree_out(v).list[i]) && (Slack > 0); i++)
-               if (ND_lim(aghead(e)) < ND_lim(v)) dfs_enter_inedge(aghead(e));
+           }
+       } else if (ND_lim(agtail(e)) < ND_lim(v))
+           dfs_enter_inedge(agtail(e));
+    }
+    for (i = 0; (e = ND_tree_out(v).list[i]) && (Slack > 0); i++)
+       if (ND_lim(aghead(e)) < ND_lim(v))
+           dfs_enter_inedge(aghead(e));
 }
 
-static edge_t *
-enter_edge(edge_t* e)
+static edge_t *enter_edge(edge_t * e)
 {
-       node_t  *v;
-       int             outsearch;
-
-       /* v is the down node */
-       if (ND_lim(agtail(e)) < ND_lim(aghead(e))) {v = agtail(e); outsearch = FALSE;}
-       else {v = aghead(e);outsearch = TRUE;}
-       Enter = NULL;
-       Slack = MAXINT;
-       Low = ND_low(v);
-       Lim = ND_lim(v);
-       if (outsearch) dfs_enter_outedge(v);
-       else dfs_enter_inedge(v);
-       return Enter;
+    node_t *v;
+    int outsearch;
+
+    /* v is the down node */
+    if (ND_lim(agtail(e)) < ND_lim(aghead(e))) {
+       v = agtail(e);
+       outsearch = FALSE;
+    } else {
+       v = aghead(e);
+       outsearch = TRUE;
+    }
+    Enter = NULL;
+    Slack = INT_MAX;
+    Low = ND_low(v);
+    Lim = ND_lim(v);
+    if (outsearch)
+       dfs_enter_outedge(v);
+    else
+       dfs_enter_inedge(v);
+    return Enter;
 }
 
-static int 
-treesearch(node_t* v)
+static int treesearch(node_t * v)
 {
-       edge_t  *e;
+    edge_t *e;
 
-       for (e = agfstout(G,v); e; e = agnxtout(G,e)) {
-               if ((ND_mark(aghead(e)) == FALSE) && (SLACK(e) == 0)) {
-                       add_tree_edge(e);
-                       if ((Tree_edge.size == N_nodes-1) || treesearch(aghead(e))) return TRUE;
-               }
+    for (e = agfstout(G, v); e; e = agnxtout(G, e)) {
+       if ((ND_mark(aghead(e)) == FALSE) && (SLACK(e) == 0)) {
+           add_tree_edge(e);
+           if ((Tree_edge.size == N_nodes - 1) || treesearch(aghead(e)))
+               return TRUE;
        }
-       for (e = agfstin(G,v); e; e = agnxtin(G,e)) {
-               if ((ND_mark(agtail(e)) == FALSE) && (SLACK(e) == 0)) {
-                       add_tree_edge(e);
-                       if ((Tree_edge.size == N_nodes-1) || treesearch(agtail(e))) return TRUE;
-               }
+    }
+    for (e = agfstin(G, v); e; e = agnxtin(G, e)) {
+       if ((ND_mark(agtail(e)) == FALSE) && (SLACK(e) == 0)) {
+           add_tree_edge(e);
+           if ((Tree_edge.size == N_nodes - 1) || treesearch(agtail(e)))
+               return TRUE;
        }
-       return FALSE;
+    }
+    return FALSE;
 }
 
-static int
-tight_tree(void)
+static int tight_tree(void)
 {
-       int             i;
-       node_t  *n;
-
-       for (n = agfstnode(G); n; n = agnxtnode(G,n)) {
-               ND_mark(n) = FALSE;
-               ND_tree_in(n).list[0] = ND_tree_out(n).list[0] = NULL;
-               ND_tree_in(n).size = ND_tree_out(n).size = 0;
-       }
-       for (i = 0; i < Tree_edge.size; i++) ED_tree_index(Tree_edge.list[i]) = -1;
-
-       Tree_node.size = Tree_edge.size = 0;
-       for (n = agfstnode(G); n && (Tree_edge.size == 0); n = agnxtnode(G,n))
-               treesearch(n);
-       return Tree_node.size;
+    int i;
+    node_t *n;
+
+    for (n = agfstnode(G); n; n = agnxtnode(G, n)) {
+       ND_mark(n) = FALSE;
+       ND_tree_in(n).list[0] = ND_tree_out(n).list[0] = NULL;
+       ND_tree_in(n).size = ND_tree_out(n).size = 0;
+    }
+    for (i = 0; i < Tree_edge.size; i++)
+       ED_tree_index(Tree_edge.list[i]) = -1;
+
+    Tree_node.size = Tree_edge.size = 0;
+    for (n = agfstnode(G); n && (Tree_edge.size == 0); n = agnxtnode(G, n))
+       treesearch(n);
+    return Tree_node.size;
 }
 
-static void 
-init_cutvalues(void)
+static void init_cutvalues(void)
 {
-       dfs_range(agfstnode(G),NULL,1);
-       dfs_cutval(agfstnode(G),NULL);
+    dfs_range(agfstnode(G), NULL, 1);
+    dfs_cutval(agfstnode(G), NULL);
 }
 
-static void 
-feasible_tree(void)
+static void feasible_tree(void)
 {
-       int                     i,delta;
-       node_t          *n;
-       edge_t          *e,*f;
-
-       if (N_nodes <= 1) return;
-       while (tight_tree() < N_nodes) {
-               e = NULL;
-               for (n = agfstnode(G); n; n = agnxtnode(G,n)) {
-                       for (f = agfstout(G,n); f; f = agnxtout(G,f)) {
-                               if ((TREE_EDGE(f) == FALSE) && incident(f) && ((e == NULL)
-                                       || (SLACK(f) < SLACK(e)))) e = f;
-                       }
-               }
-               if (e) {
-                       delta = SLACK(e);
-                       if (delta) {
-                               if (incident(e) == aghead(e)) delta = -delta;
-                               for (i = 0; i < Tree_node.size; i++)
-                                       ND_rank(Tree_node.list[i]) += delta;
-                       }
-               }
-               else {
+    int i, delta;
+    node_t *n;
+    edge_t *e, *f;
+
+    if (N_nodes <= 1)
+       return;
+    while (tight_tree() < N_nodes) {
+       e = NULL;
+       for (n = agfstnode(G); n; n = agnxtnode(G, n)) {
+           for (f = agfstout(G, n); f; f = agnxtout(G, f)) {
+               if ((TREE_EDGE(f) == FALSE) && incident(f) && ((e == NULL)
+                                                              || (SLACK(f)
+                                                                  <
+                                                                  SLACK
+                                                                  (e))))
+                   e = f;
+           }
+       }
+       if (e) {
+           delta = SLACK(e);
+           if (delta) {
+               if (incident(e) == aghead(e))
+                   delta = -delta;
+               for (i = 0; i < Tree_node.size; i++)
+                   ND_rank(Tree_node.list[i]) += delta;
+           }
+       } else {
 #ifdef DEBUG
-                       fprintf(stderr,"not in tight tree:\n");
-                       for (n = agfstnode(G); n; n = agnxtnode(G,n)) {
-                               for (i = 0; i < Tree_node.size; i++)
-                                       if (Tree_node.list[i] == n) break;
-                               if (i >= Tree_node.size) fprintf(stderr,"\t%s\n",agnameof(n));
-                       }
+           fprintf(stderr, "not in tight tree:\n");
+           for (n = agfstnode(G); n; n = agnxtnode(G, n)) {
+               for (i = 0; i < Tree_node.size; i++)
+                   if (Tree_node.list[i] == n)
+                       break;
+               if (i >= Tree_node.size)
+                   fprintf(stderr, "\t%s\n", agnameof(n));
+           }
 #endif
-                       abort();
-               }
+           abort();
        }
-       init_cutvalues();
+    }
+    init_cutvalues();
 }
 
 /* walk up from v to LCA(v,w), setting new cutvalues. */
-static node_t *
-treeupdate(node_t *v, node_t *w, int cutvalue, int dir)
+static node_t *treeupdate(node_t * v, node_t * w, int cutvalue, int dir)
 {
-       edge_t  *e;
-       int             d;
-
-       while (!SEQ(ND_low(v),ND_lim(w),ND_lim(v))) {
-               e = ND_par(v);
-               if (v == agtail(e)) d = dir; else d = NOT(dir);
-               if (d) ED_cutval(e) += cutvalue; else ED_cutval(e) -= cutvalue;
-               if (ND_lim(agtail(e)) > ND_lim(aghead(e))) v = agtail(e); else v = aghead(e);
-       }
-       return v;
+    edge_t *e;
+    int d;
+
+    while (!SEQ(ND_low(v), ND_lim(w), ND_lim(v))) {
+       e = ND_par(v);
+       if (v == agtail(e))
+           d = dir;
+       else
+           d = NOT(dir);
+       if (d)
+           ED_cutvalue(e) += cutvalue;
+       else
+           ED_cutvalue(e) -= cutvalue;
+       if (ND_lim(agtail(e)) > ND_lim(aghead(e)))
+           v = agtail(e);
+       else
+           v = aghead(e);
+    }
+    return v;
 }
 
-static void 
-rerank(node_t* v, int delta)
+static void rerank(node_t * v, int delta)
 {
-       int             i;
-       edge_t  *e;
-
-       ND_rank(v) -= delta;
-       for (i = 0; (e = ND_tree_out(v).list[i]); i++) 
-               if (e != ND_par(v)) rerank(aghead(e),delta);
-       for (i = 0; (e = ND_tree_in(v).list[i]); i++) 
-               if (e != ND_par(v)) rerank(agtail(e),delta);
+    int i;
+    edge_t *e;
+
+    ND_rank(v) -= delta;
+    for (i = 0; (e = ND_tree_out(v).list[i]); i++)
+       if (e != ND_par(v))
+           rerank(aghead(e), delta);
+    for (i = 0; (e = ND_tree_in(v).list[i]); i++)
+       if (e != ND_par(v))
+           rerank(agtail(e), delta);
 }
 
 /* e is the tree edge that is leaving and f is the nontree edge that
  * is entering.  compute new cut values, ranks, and exchange e and f.
  */
-void 
-update(edge_t *e, edge_t *f)
+static void update(edge_t * e, edge_t * f)
 {
-       int             cutvalue,delta;
-       node_t  *lca;
-
-       delta = SLACK(f);
-       /* "for (v = in nodes in tail side of e) do ND_rank(v) -= delta;" */
-       if (delta > 0) {
-               int s;
-               s = ND_tree_in(agtail(e)).size + ND_tree_out(agtail(e)).size;
-               if (s == 1) rerank(agtail(e),delta);
-               else {
-                       s = ND_tree_in(aghead(e)).size + ND_tree_out(aghead(e)).size;
-                       if (s == 1) rerank(aghead(e),-delta);
-                       else {
-                               if (ND_lim(agtail(e)) < ND_lim(aghead(e))) rerank(agtail(e),delta);
-                               else rerank(aghead(e),-delta);
-                       }
-               }
+    int cutvalue, delta;
+    node_t *lca;
+
+    delta = SLACK(f);
+    /* "for (v = in nodes in tail side of e) do ND_rank(v) -= delta;" */
+    if (delta > 0) {
+       int s;
+       s = ND_tree_in(agtail(e)).size + ND_tree_out(agtail(e)).size;
+       if (s == 1)
+           rerank(agtail(e), delta);
+       else {
+           s = ND_tree_in(aghead(e)).size + ND_tree_out(aghead(e)).size;
+           if (s == 1)
+               rerank(aghead(e), -delta);
+           else {
+               if (ND_lim(agtail(e)) < ND_lim(aghead(e)))
+                   rerank(agtail(e), delta);
+               else
+                   rerank(aghead(e), -delta);
+           }
        }
-
-       cutvalue = ED_cutval(e);
-       lca = treeupdate(agtail(f),aghead(f),cutvalue,1);
-       if (treeupdate(aghead(f),agtail(f),cutvalue,0) != lca) abort();
-       ED_cutval(f) = -cutvalue;
-       ED_cutval(e) = 0;
-       exchange_tree_edges(e,f);
-       dfs_range(lca,ND_par(lca),ND_low(lca));
+    }
+
+    cutvalue = ED_cutvalue(e);
+    lca = treeupdate(agtail(f), aghead(f), cutvalue, 1);
+    if (treeupdate(aghead(f), agtail(f), cutvalue, 0) != lca)
+       abort();
+    ED_cutvalue(f) = -cutvalue;
+    ED_cutvalue(e) = 0;
+    exchange_tree_edges(e, f);
+    dfs_range(lca, ND_par(lca), ND_low(lca));
 }
 
-static void 
-scan_and_normalize(void)
+static void scan_and_normalize(void)
 {
-       node_t  *n;
-
-       Minrank = MAXINT;
-       Maxrank = -MAXINT;
-       for (n = agfstnode(G); n; n = agnxtnode(G,n)) {
-               Minrank = MIN(Minrank,ND_rank(n));
-               Maxrank = MAX(Maxrank,ND_rank(n));
-       }
-       if (Minrank != 0) {
-               for (n = agfstnode(G); n; n = agnxtnode(G,n))
-                       ND_rank(n) -= Minrank;
-               Maxrank -= Minrank;
-               Minrank = 0;
-       }
+    node_t *n;
+
+    Minrank = INT_MAX;
+    Maxrank = -INT_MAX;
+    for (n = agfstnode(G); n; n = agnxtnode(G, n)) {
+       Minrank = MIN(Minrank, ND_rank(n));
+       Maxrank = MAX(Maxrank, ND_rank(n));
+    }
+    if (Minrank != 0) {
+       for (n = agfstnode(G); n; n = agnxtnode(G, n))
+           ND_rank(n) -= Minrank;
+       Maxrank -= Minrank;
+       Minrank = 0;
+    }
 }
 
-static void 
-LR_balance(void)
+static void LR_balance(void)
 {
-       int             i,delta;
-       node_t  *n;
-       edge_t  *e,*f;
-
-       for (i = 0; i < Tree_edge.size; i++) {
-               e = Tree_edge.list[i];
-               if (ED_cutval(e) == 0) {
-                       f = enter_edge(e);
-                       if (f == NULL) continue;
-                       delta = SLACK(f);
-                       if (delta <= 1) continue;
-                       if (ND_lim(agtail(e)) < ND_lim(aghead(e))) rerank(agtail(e),delta/2);
-                       else rerank(aghead(e),-delta/2);
-               }
-       }
-       for (n = agfstnode(G); n; n = agnxtnode(G,n)) {
-               free_list(ND_tree_in(n));
-               free_list(ND_tree_out(n));
-               ND_mark(n) = FALSE;
+    int i, delta;
+    node_t *n;
+    edge_t *e, *f;
+
+    for (i = 0; i < Tree_edge.size; i++) {
+       e = Tree_edge.list[i];
+       if (ED_cutvalue(e) == 0) {
+           f = enter_edge(e);
+           if (f == NULL)
+               continue;
+           delta = SLACK(f);
+           if (delta <= 1)
+               continue;
+           if (ND_lim(agtail(e)) < ND_lim(aghead(e)))
+               rerank(agtail(e), delta / 2);
+           else
+               rerank(aghead(e), -delta / 2);
        }
+    }
+    for (n = agfstnode(G); n; n = agnxtnode(G, n)) {
+       free_list(ND_tree_in(n));
+       free_list(ND_tree_out(n));
+       ND_mark(n) = FALSE;
+    }
 }
 
-static int
-countable_node(node_t *n)
+static int countable_node(node_t * n)
 {
-       return TRUE;            /* could be false for slacknodes */
+    return TRUE;               /* could be false for slacknodes */
 }
 
-static void 
-TB_balance(void)
+static void TB_balance(void)
 {
-       node_t  *n;
-       edge_t  *e;
-       int             i,low,high,choice,*nrank;
-       int             inweight,outweight;
-
-       scan_and_normalize();
-
-       /* find nodes that are not tight and move to less populated ranks */
-       nrank = N_NEW(Maxrank+1,int);
-       for (i = 0; i <= Maxrank; i++) nrank[i] = 0;
-       for (n = agfstnode(G); n; n = agnxtnode(G,n))
-               if (countable_node(n)) nrank[ND_rank(n)]++;
-       for (n = agfstnode(G); n; n = agnxtnode(G,n)) {
-               if (!countable_node(n)) continue;
-               inweight = outweight = 0;
-               low = 0;
-               high = Maxrank;
-               for (e = agfstin(G,n); e; e = agnxtin(G,e)) {
-                       inweight += ED_weight(e);
-                       low = MAX(low,ND_rank(agtail(e)) + ED_minlen(e));
-               }
-               for (e = agfstout(G,n); e; e = agnxtout(G,e)) {
-                       outweight += ED_weight(e);
-                       high = MIN(high,ND_rank(aghead(e)) - ED_minlen(e));
-               }
-               if (low < 0) low = 0;   /* vnodes can have ranks < 0 */
-               if (inweight == outweight) {
-                       choice = low;
-                       for (i = low + 1; i <= high; i++)
-                               if (nrank[i] < nrank[choice]) choice = i;
-                       nrank[ND_rank(n)]--; nrank[choice]++;
-                       ND_rank(n) = choice;
-               }
-               free_list(ND_tree_in(n));
-               free_list(ND_tree_out(n));
-               ND_mark(n) = FALSE;
+    node_t *n;
+    edge_t *e;
+    int i, low, high, choice, *nrank;
+    int inweight, outweight;
+
+    scan_and_normalize();
+
+    /* find nodes that are not tight and move to less populated ranks */
+    nrank = N_NEW(Maxrank + 1, int);
+    for (i = 0; i <= Maxrank; i++)
+       nrank[i] = 0;
+    for (n = agfstnode(G); n; n = agnxtnode(G, n))
+       if (countable_node(n))
+           nrank[ND_rank(n)]++;
+    for (n = agfstnode(G); n; n = agnxtnode(G, n)) {
+       if (!countable_node(n))
+           continue;
+       inweight = outweight = 0;
+       low = 0;
+       high = Maxrank;
+       for (e = agfstin(G, n); e; e = agnxtin(G, e)) {
+           inweight += ED_weight(e);
+           low = MAX(low, ND_rank(agtail(e)) + ED_minlen(e));
+       }
+       for (e = agfstout(G, n); e; e = agnxtout(G, e)) {
+           outweight += ED_weight(e);
+           high = MIN(high, ND_rank(aghead(e)) - ED_minlen(e));
        }
-       free(nrank);
+       if (low < 0)
+           low = 0;            /* vnodes can have ranks < 0 */
+       if (inweight == outweight) {
+           choice = low;
+           for (i = low + 1; i <= high; i++)
+               if (nrank[i] < nrank[choice])
+                   choice = i;
+           nrank[ND_rank(n)]--;
+           nrank[choice]++;
+           ND_rank(n) = choice;
+       }
+       free_list(ND_tree_in(n));
+       free_list(ND_tree_out(n));
+       ND_mark(n) = FALSE;
+    }
+    free(nrank);
 }
 
-static int
-init_graph(graph_t* g)
+static int init_graph(graph_t * g)
 {
-       int             i,feasible;
-       node_t  *n;
-       edge_t  *e;
-
-       G = g;
-       N_nodes = N_edges = S_i = 0;
-       for (n = agfstnode(g); n; n = agnxtnode(g,n)) {
-               ND_mark(n) = FALSE;
-               N_nodes++;
-               for (e = agfstout(g,n); e; e = agnxtout(g,e)) N_edges++;
-       }
-
-       Tree_node.list = ALLOC(N_nodes,Tree_node.list,node_t*);
-       Tree_node.size = 0;
-       Tree_edge.list = ALLOC(N_nodes,Tree_edge.list,edge_t*);
-       Tree_edge.size = 0;
-
-       feasible = TRUE;
-       for (n = agfstnode(G); n; n = agnxtnode(G,n)) {
-               ND_priority(n) = 0;
-               i = 0;
-               for (e = agfstin(G,n); e; e = agnxtin(G,e)) {
-                       i++;
-                       ND_priority(n)++;
-                       ED_cutval(e) = 0;
-                       ED_tree_index(e) = -1;
-                       if (feasible && (ND_rank(aghead(e)) - ND_rank(agtail(e)) < ED_minlen(e)))
-                               feasible = FALSE;
-               }
-               ND_tree_in(n).list = N_NEW(i+1,edge_t*);
-               ND_tree_in(n).size = 0;
-               for (e = agfstout(G,n); e; e = agnxtout(G,e)) i++;
-               ND_tree_out(n).list = N_NEW(i+1,edge_t*);
-               ND_tree_out(n).size = 0;
+    int i, feasible;
+    node_t *n;
+    edge_t *e;
+
+    G = g;
+    N_nodes = N_edges = S_i = 0;
+    for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
+       ND_mark(n) = FALSE;
+       N_nodes++;
+       for (e = agfstout(g, n); e; e = agnxtout(g, e))
+           N_edges++;
+    }
+
+    Tree_node.list = ALLOC(N_nodes, Tree_node.list, node_t *);
+    Tree_node.size = 0;
+    Tree_edge.list = ALLOC(N_nodes, Tree_edge.list, edge_t *);
+    Tree_edge.size = 0;
+
+    feasible = TRUE;
+    for (n = agfstnode(G); n; n = agnxtnode(G, n)) {
+       ND_priority(n) = 0;
+       i = 0;
+       for (e = agfstin(G, n); e; e = agnxtin(G, e)) {
+           i++;
+           ND_priority(n)++;
+           ED_cutvalue(e) = 0;
+           ED_tree_index(e) = -1;
+           if (feasible
+               && (ND_rank(aghead(e)) - ND_rank(agtail(e)) <
+                   ED_minlen(e)))
+               feasible = FALSE;
        }
-       return feasible;
+       ND_tree_in(n).list = N_NEW(i + 1, edge_t *);
+       ND_tree_in(n).size = 0;
+       for (e = agfstout(G, n); e; e = agnxtout(G, e))
+           i++;
+       ND_tree_out(n).list = N_NEW(i + 1, edge_t *);
+       ND_tree_out(n).size = 0;
+    }
+    return feasible;
 }
 
-void 
-rank(graph_t *g, int balance, int maxiter)
+void rank2(graph_t * g, int balance, int maxiter, int searchsize)
 {
-       int     iter = 0,feasible;
-       char    *s,*ns = "network simplex: ";
-       edge_t  *e,*f;
-
-       if (dot_Verbose) start_timer();
-       feasible = init_graph(g);
-       if (!feasible) init_rank();
-       if (maxiter <= 0) return;
-
-       if ((s = agget(g,"searchsize"))) Search_size = atoi(s);
-       else Search_size = SEARCHSIZE;
-
-       feasible_tree();
-       while ((e = leave_edge())) {
-               f = enter_edge(e);
-               update(e,f);
-               iter++;
-               if (dot_Verbose && (iter % 100 == 0)) {
-                       if (iter % 1000 == 100) fputs(ns,stderr);
-                       fprintf(stderr,"%d ",iter);
-                       if (iter % 1000 == 0) fputc('\n',stderr);
-               }
-               if (iter >= maxiter) break;
-       }
-       switch(balance){
-       case 1: TB_balance(); break;
-       case 2: LR_balance(); break;
-       default: scan_and_normalize(); break;
-       }
-       if (dot_Verbose) {
-               if (iter >= 100) fputc('\n',stderr);
-               fprintf(stderr,"%s%d nodes %d edges %d iter %.2f sec\n",
-                       ns,N_nodes,N_edges,iter,elapsed_sec());
+    int iter = 0, feasible;
+    char *s, *ns = "network simplex: ";
+    edge_t *e, *f;
+
+    if (Verbose)
+       start_timer();
+    feasible = init_graph(g);
+    if (!feasible)
+       init_rank();
+    if (maxiter <= 0)
+       return;
+
+    if (searchsize >= 0)
+       Search_size = searchsize;
+    else
+       Search_size = SEARCHSIZE;
+
+    feasible_tree();
+    while ((e = leave_edge())) {
+       f = enter_edge(e);
+       update(e, f);
+       iter++;
+       if (Verbose && (iter % 100 == 0)) {
+           if (iter % 1000 == 100)
+               fputs(ns, stderr);
+           fprintf(stderr, "%d ", iter);
+           if (iter % 1000 == 0)
+               fputc('\n', stderr);
        }
+       if (iter >= maxiter)
+           break;
+    }
+    switch (balance) {
+    case 1:
+       TB_balance();
+       break;
+    case 2:
+       LR_balance();
+       break;
+    default:
+       scan_and_normalize();
+       break;
+    }
+    if (Verbose) {
+       if (iter >= 100)
+           fputc('\n', stderr);
+       fprintf(stderr, "%s%d nodes %d edges %d iter %.2f sec\n",
+               ns, N_nodes, N_edges, iter, elapsed_sec());
+    }
 }
 
 /* set cut value of f, assuming values of edges on one side were already set */
-static void 
-x_cutval(edge_t* f)
+static void x_cutval(edge_t * f)
 {
-       node_t  *v;
-       edge_t  *e;
-       int             sum,dir;
-
-       /* set v to the node on the side of the edge already searched */
-       if (ND_par(agtail(f)) == f) { v = agtail(f); dir = 1; }
-       else { v = aghead(f); dir = -1; }
-
-       sum = 0;
-       for (e = agfstout(G,v); e; e = agnxtout(G,e)) sum += x_val(e,v,dir);
-       for (e = agfstin(G,v); e; e = agnxtin(G,e)) sum += x_val(e,v,dir);
-       ED_cutval(f) = sum;
+    node_t *v;
+    edge_t *e;
+    int sum, dir;
+
+    /* set v to the node on the side of the edge already searched */
+    if (ND_par(agtail(f)) == f) {
+       v = agtail(f);
+       dir = 1;
+    } else {
+       v = aghead(f);
+       dir = -1;
+    }
+
+    sum = 0;
+    for (e = agfstout(G, v); e; e = agnxtout(G, e))
+       sum += x_val(e, v, dir);
+    for (e = agfstin(G, v); e; e = agnxtin(G, e))
+       sum += x_val(e, v, dir);
+    ED_cutvalue(f) = sum;
 }
 
-static int 
-x_val(edge_t* e, node_t* v, int dir)
+static int x_val(edge_t * e, node_t * v, int dir)
 {
-       node_t  *other;
-       int             d,rv,f;
-
-       if (agtail(e) == v) other = aghead(e); else other = agtail(e);
-       if (!(SEQ(ND_low(v),ND_lim(other),ND_lim(v)))) {f = 1; rv = ED_weight(e);}
-       else {
-               f = 0;
-               if (TREE_EDGE(e)) rv = ED_cutval(e);
-               else rv = 0;
-               rv -= ED_weight(e);
-       }
-       if (dir > 0) {if (aghead(e) == v) d = 1; else d = -1;}
-       else {if (agtail(e) == v) d = 1; else d = -1; }
-       if (f) d = -d;
-       if (d < 0) rv = -rv;
-       return rv;
+    node_t *other;
+    int d, rv, f;
+
+    if (agtail(e) == v)
+       other = aghead(e);
+    else
+       other = agtail(e);
+    if (!(SEQ(ND_low(v), ND_lim(other), ND_lim(v)))) {
+       f = 1;
+       rv = ED_weight(e);
+    } else {
+       f = 0;
+       if (TREE_EDGE(e))
+           rv = ED_cutvalue(e);
+       else
+           rv = 0;
+       rv -= ED_weight(e);
+    }
+    if (dir > 0) {
+       if (aghead(e) == v)
+           d = 1;
+       else
+           d = -1;
+    } else {
+       if (agtail(e) == v)
+           d = 1;
+       else
+           d = -1;
+    }
+    if (f)
+       d = -d;
+    if (d < 0)
+       rv = -rv;
+    return rv;
 }
 
-static void 
-dfs_cutval(node_t* v, edge_t* par)
+static void dfs_cutval(node_t * v, edge_t * par)
 {
-       int             i;
-       edge_t  *e;
-
-       for (i = 0; (e = ND_tree_out(v).list[i]); i++)
-               if (e != par) dfs_cutval(aghead(e),e);
-       for (i = 0; (e = ND_tree_in(v).list[i]); i++)
-               if (e != par) dfs_cutval(agtail(e),e);
-       if (par) x_cutval(par);
+    int i;
+    edge_t *e;
+
+    for (i = 0; (e = ND_tree_out(v).list[i]); i++)
+       if (e != par)
+           dfs_cutval(aghead(e), e);
+    for (i = 0; (e = ND_tree_in(v).list[i]); i++)
+       if (e != par)
+           dfs_cutval(agtail(e), e);
+    if (par)
+       x_cutval(par);
 }
 
-static int 
-dfs_range(node_t* v, edge_t* par, int low)
+static int dfs_range(node_t * v, edge_t * par, int low)
 {
-       edge_t  *e;
-       int             i,lim;
-
-       lim = low;
-       ND_par(v) = par;
-       ND_low(v) = low;
-       for (i = 0; (e = ND_tree_out(v).list[i]); i++)
-               if (e != par) lim = dfs_range(aghead(e),e,lim);
-       for (i = 0; (e = ND_tree_in(v).list[i]); i++)
-               if (e != par) lim = dfs_range(agtail(e),e,lim);
-       ND_lim(v) = lim;
-       return lim + 1;
+    edge_t *e;
+    int i, lim;
+
+    lim = low;
+    ND_par(v) = par;
+    ND_low(v) = low;
+    for (i = 0; (e = ND_tree_out(v).list[i]); i++)
+       if (e != par)
+           lim = dfs_range(aghead(e), e, lim);
+    for (i = 0; (e = ND_tree_in(v).list[i]); i++)
+       if (e != par)
+           lim = dfs_range(agtail(e), e, lim);
+    ND_lim(v) = lim;
+    return lim + 1;
 }
 
 #ifdef DEBUG
 void tchk(void)
 {
-       int             i,n_cnt,e_cnt;
-       node_t  *n;
-       edge_t  *e;
-
-       n_cnt = 0;
-       e_cnt = 0;
-       for (n = agfstnode(G); n; n = agnxtnode(G,n)) {
-               n_cnt++;
-               for (i = 0; (e = ND_tree_out(n).list[i]); i++) {
-                       e_cnt++;
-                       if (SLACK(e) > 0)
-                               printf("not a tight tree %p",(void*)e);
-               }
+    int i, n_cnt, e_cnt;
+    node_t *n;
+    edge_t *e;
+
+    n_cnt = 0;
+    e_cnt = 0;
+    for (n = agfstnode(G); n; n = agnxtnode(G, n)) {
+       n_cnt++;
+       for (i = 0; (e = ND_tree_out(n).list[i]); i++) {
+           e_cnt++;
+           if (SLACK(e) > 0)
+               printf("not a tight tree %p", (void *) e);
        }
-       if ((n_cnt != Tree_node.size)  || (e_cnt != Tree_edge.size))
-               printf("something missing\n");
+    }
+    if ((n_cnt != Tree_node.size) || (e_cnt != Tree_edge.size))
+       printf("something missing\n");
 }
 
 void check_cutvalues(void)
 {
-       node_t  *v;
-       edge_t  *e;
-       int             i,save;
-
-       for (v = agfstnode(G); v; v = agnxtnode(G,v)) {
-               for (i = 0; (e = ND_tree_out(v).list[i]); i++) {
-                       save = ED_cutval(e);
-                       x_cutval(e);
-                       if (save != ED_cutval(e)) abort();
-               }
+    node_t *v;
+    edge_t *e;
+    int i, save;
+
+    for (v = agfstnode(G); v; v = agnxtnode(G, v)) {
+       for (i = 0; (e = ND_tree_out(v).list[i]); i++) {
+           save = ED_cutvalue(e);
+           x_cutval(e);
+           if (save != ED_cutvalue(e))
+               abort();
        }
+    }
 }
 
-int
-check_ranks(void)
+int check_ranks(void)
 {
-       int             cost = 0;
-       node_t  *n;
-       edge_t  *e;
-
-       for (n = agfstnode(G); n; n = agnxtnode(G,n)) {
-               for (e = agfstout(G,n); e; e = agnxtout(G,e)) {
-                       cost += (ED_weight(e))*abs(LENGTH(e));
-       if (ND_rank(aghead(e)) - ND_rank(agtail(e)) - ED_minlen(e) < 0) abort();
-               }
+    int cost = 0;
+    node_t *n;
+    edge_t *e;
+
+    for (n = agfstnode(G); n; n = agnxtnode(G, n)) {
+       for (e = agfstout(G, n); e; e = agnxtout(G, e)) {
+           cost += (ED_weight(e)) * abs(LENGTH(e));
+           if (ND_rank(aghead(e)) - ND_rank(agtail(e)) - ED_minlen(e) < 0)
+               abort();
        }
-       fprintf(stderr,"rank cost %d\n",cost);
-       return cost;
+    }
+    fprintf(stderr, "rank cost %d\n", cost);
+    return cost;
 }
 
 void checktree(void)
 {
-       int             i,n = 0,m = 0;
-       node_t  *v;
-       edge_t  *e;
-
-       for (v = agfstnode(G); v; v = agnxtnode(G,v)) {
-               for (i = 0; (e = ND_tree_out(v).list[i]); i++) n++;
-               if (i != ND_tree_out(v).size) abort();
-               for (i = 0; (e = ND_tree_in(v).list[i]); i++) m++;
-               if (i != ND_tree_in(v).size) abort();
-       }
-       printf("%d %d %d\n",Tree_edge.size,n,m);
+    int i, n = 0, m = 0;
+    node_t *v;
+    edge_t *e;
+
+    for (v = agfstnode(G); v; v = agnxtnode(G, v)) {
+       for (i = 0; (e = ND_tree_out(v).list[i]); i++)
+           n++;
+       if (i != ND_tree_out(v).size)
+           abort();
+       for (i = 0; (e = ND_tree_in(v).list[i]); i++)
+           m++;
+       if (i != ND_tree_in(v).size)
+           abort();
+    }
+    printf("%d %d %d\n", Tree_edge.size, n, m);
 }
 
-void checkdfs(node_t* n)
+void checkdfs(node_t * n)
 {
-       edge_t  *e;
-       node_t  *w;
-
-       if (ND_mark(n)) return;
-       ND_mark(n) = TRUE;
-       ND_onstack(n) = TRUE;
-       for (e = agfstout(G,n); e; e = agnxtout(G,e)) {
-               w = aghead(e);
-               if (ND_onstack(w))
-                       fprintf(stderr,"cycle involving %s %s\n",agnameof(n),agnameof(w));
-               else {
-                       if (ND_mark(w) == FALSE) checkdfs(w);
-               }
+    edge_t *e;
+    node_t *w;
+
+    if (ND_mark(n))
+       return;
+    ND_mark(n) = TRUE;
+    ND_onstack(n) = TRUE;
+    for (e = agfstout(G, n); e; e = agnxtout(G, e)) {
+       w = aghead(e);
+       if (ND_onstack(w))
+           fprintf(stderr, "cycle involving %s %s\n", agnameof(n),
+                   agnameof(w));
+       else {
+           if (ND_mark(w) == FALSE)
+               checkdfs(w);
        }
-       ND_onstack(n) = FALSE;
+    }
+    ND_onstack(n) = FALSE;
 }
 
-void check_cycles(graph_t* g)
+void check_cycles(graph_t * g)
 {
-       node_t  *n;
-       for (n = agfstnode(G); n; n = agnxtnode(G,n))
-               ND_mark(n) = ND_onstack(n) = FALSE;
-       for (n = agfstnode(G); n; n = agnxtnode(G,n))
-               checkdfs(n);
+    node_t *n;
+    for (n = agfstnode(G); n; n = agnxtnode(G, n))
+       ND_mark(n) = ND_onstack(n) = FALSE;
+    for (n = agfstnode(G); n; n = agnxtnode(G, n))
+       checkdfs(n);
 }
-#endif /* DEBUG */
+#endif                         /* DEBUG */