--- /dev/null
+/* $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 */
--- /dev/null
+/* $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
--- /dev/null
+/* $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;
+}
--- /dev/null
+/* $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);
+
+ }
+}
+
--- /dev/null
+/* $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
-#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);
}
--- /dev/null
+/* $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
--- /dev/null
+/* $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
--- /dev/null
+/* $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;
+}
+
+/* $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 */