From 4dca18634be00338c4321ef1443fa1e3ecd43337 Mon Sep 17 00:00:00 2001 From: Matthew Fernandez Date: Mon, 18 May 2020 17:14:27 -0700 Subject: [PATCH] remove unused dotgen2 --- lib/dotgen2/Makefile.am | 19 - lib/dotgen2/acyclic.c | 38 - lib/dotgen2/au_.c | 80 -- lib/dotgen2/au_.h | 18 - lib/dotgen2/bjm.c | 86 -- lib/dotgen2/bjm0.c | 92 --- lib/dotgen2/ce.c | 16 - lib/dotgen2/countx.c | 76 -- lib/dotgen2/decomp.c | 131 --- lib/dotgen2/dot2.h | 31 - lib/dotgen2/dot2procs.h | 37 - lib/dotgen2/dotinit.c | 122 --- lib/dotgen2/flat.c | 61 -- lib/dotgen2/groups.c | 135 --- lib/dotgen2/groups.h | 23 - lib/dotgen2/level.c | 501 ------------ lib/dotgen2/main.c | 68 -- lib/dotgen2/minc.c | 1334 ------------------------------ lib/dotgen2/minc.h | 130 --- lib/dotgen2/minc2.c | 1680 -------------------------------------- lib/dotgen2/minc_utils.c | 166 ---- lib/dotgen2/newdot.h | 287 ------- lib/dotgen2/ns.c | 810 ------------------ lib/dotgen2/pos.c | 68 -- lib/dotgen2/queue.c | 41 - lib/dotgen2/radix.c | 119 --- lib/dotgen2/radix.h | 6 - lib/dotgen2/radix0.c | 95 --- lib/dotgen2/radix1.c | 105 --- lib/dotgen2/save2_minc.c | 970 ---------------------- lib/dotgen2/save_minc.c | 1281 ----------------------------- lib/dotgen2/t.c | 1128 ------------------------- lib/dotgen2/t1.c | 8 - lib/dotgen2/t2.c | 5 - lib/dotgen2/timing.c | 41 - lib/dotgen2/trysort.c | 16 - lib/dotgen2/xcoord.c | 15 - lib/dotgen2/xpos.c | 135 --- 38 files changed, 9974 deletions(-) delete mode 100644 lib/dotgen2/Makefile.am delete mode 100644 lib/dotgen2/acyclic.c delete mode 100644 lib/dotgen2/au_.c delete mode 100644 lib/dotgen2/au_.h delete mode 100644 lib/dotgen2/bjm.c delete mode 100644 lib/dotgen2/bjm0.c delete mode 100644 lib/dotgen2/ce.c delete mode 100644 lib/dotgen2/countx.c delete mode 100644 lib/dotgen2/decomp.c delete mode 100644 lib/dotgen2/dot2.h delete mode 100644 lib/dotgen2/dot2procs.h delete mode 100644 lib/dotgen2/dotinit.c delete mode 100644 lib/dotgen2/flat.c delete mode 100644 lib/dotgen2/groups.c delete mode 100644 lib/dotgen2/groups.h delete mode 100644 lib/dotgen2/level.c delete mode 100644 lib/dotgen2/main.c delete mode 100644 lib/dotgen2/minc.c delete mode 100644 lib/dotgen2/minc.h delete mode 100644 lib/dotgen2/minc2.c delete mode 100644 lib/dotgen2/minc_utils.c delete mode 100644 lib/dotgen2/newdot.h delete mode 100644 lib/dotgen2/ns.c delete mode 100644 lib/dotgen2/pos.c delete mode 100644 lib/dotgen2/queue.c delete mode 100644 lib/dotgen2/radix.c delete mode 100644 lib/dotgen2/radix.h delete mode 100644 lib/dotgen2/radix0.c delete mode 100644 lib/dotgen2/radix1.c delete mode 100644 lib/dotgen2/save2_minc.c delete mode 100644 lib/dotgen2/save_minc.c delete mode 100644 lib/dotgen2/t.c delete mode 100644 lib/dotgen2/t1.c delete mode 100644 lib/dotgen2/t2.c delete mode 100644 lib/dotgen2/timing.c delete mode 100644 lib/dotgen2/trysort.c delete mode 100644 lib/dotgen2/xcoord.c delete mode 100644 lib/dotgen2/xpos.c diff --git a/lib/dotgen2/Makefile.am b/lib/dotgen2/Makefile.am deleted file mode 100644 index 57e0fc345..000000000 --- a/lib/dotgen2/Makefile.am +++ /dev/null @@ -1,19 +0,0 @@ -# $Id$Revision$ -## Process this file with automake to produce Makefile.in - -AM_CPPFLAGS = \ - -I$(top_srcdir) \ - -I$(top_srcdir)/lib/common \ - -I$(top_srcdir)/lib/gvc \ - -I$(top_srcdir)/lib/ortho \ - -I$(top_srcdir)/lib/cgraph \ - -I$(top_srcdir)/lib/cdt \ - -I$(top_srcdir)/lib/pathplan - -noinst_HEADERS = dot2.h dot2procs.h groups.h minc.h -noinst_LTLIBRARIES = libdotgen2_C.la - -libdotgen2_C_la_LDFLAGS = -no-undefined -libdotgen2_C_la_SOURCES = dotinit.c level.c minc2.c ns.c groups.c minc_utils.c decomp.c - -# EXTRA_DIST = dotgen2.vcxproj* diff --git a/lib/dotgen2/acyclic.c b/lib/dotgen2/acyclic.c deleted file mode 100644 index 78dc96274..000000000 --- a/lib/dotgen2/acyclic.c +++ /dev/null @@ -1,38 +0,0 @@ -#include "newdot.h" - -static void reverse_edge(graph_t *g, edge_t *e) -{ - edge_t *rev; - - rev = agfindedge(g,e->head,e->tail); - if (!rev) rev = agedge(g,e->head,e->tail); - merge(rev,ED_minlen(e),ED_weight(e)); - agdelete(g,e); -} - -static void dfs(graph_t *g, node_t *v) -{ - 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 = e->head; - 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) -{ - 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); -} diff --git a/lib/dotgen2/au_.c b/lib/dotgen2/au_.c deleted file mode 100644 index 7f97eda04..000000000 --- a/lib/dotgen2/au_.c +++ /dev/null @@ -1,80 +0,0 @@ -#include "newdot.h" -#include - -int mapbool(char *str, int defval) -{ - if (str && str[0]) { - if (!strcasecmp(str,"false")) return FALSE; - if (!strcasecmp(str,"true")) return TRUE; - return atoi(str); - } - return defval; -} - -void *zmalloc(size_t nbytes) -{ - char *rv = malloc(nbytes); - if (nbytes == 0) return 0; - if (rv == NULL) {fprintf(stderr, "out of memory\n"); abort();} - memset(rv,0,nbytes); - return rv; -} - -void *zrealloc(void *ptr, size_t size, size_t elt, size_t osize) -{ - void *p = realloc(ptr,size*elt); - if (p == NULL && size) {fprintf(stderr, "out of memory\n"); abort();} - if (osize < size) memset((char*)p+(osize*elt),'\0',(size-osize)*elt); - return p; -} - -int dot_Verbose; -char *CmdName = "newdot"; - -void warn3(char *s0, char *s1, char *s2) -{ - fprintf(stderr,"%s: ",CmdName); - fprintf(stderr,s0,s1,s2); -} - -int gvround(double arg) -{ - return (int)(arg + (arg > 0?.5:-.5)); -} - -int gvgetint(void *obj, char *str, int defval) -{ - char *valstr; - int rv; - double frac; - - valstr = agget(obj,str); - if (valstr && valstr[0]) { - if (sscanf(valstr,"%lf%%",&frac)) rv = gvround(frac * defval); - else if (!sscanf(valstr,"%d",&rv)) rv = defval; - } - else rv = defval; - return rv; -} - -Agedge_t *agfindedge(Agraph_t *g, Agnode_t *t, Agnode_t *h) -{ - return agedge(g,t,h,0,0); -} - -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} }; - -void agautoinit(Agraph_t *g, int graphinfo_size, int nodeinfo_size, int edgeinfo_size) -{ - int *s; - - 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); -} diff --git a/lib/dotgen2/au_.h b/lib/dotgen2/au_.h deleted file mode 100644 index 2e595cdb6..000000000 --- a/lib/dotgen2/au_.h +++ /dev/null @@ -1,18 +0,0 @@ -int gvgetint(void *obj, char *str, int defval); -int gvround(double arg); - -extern queue *new_queue(int); -extern void enqueue(queue *, Agnode_t *); -extern void enqueue_neighbors(queue *, Agnode_t *, int); -extern Agnode_t *dequeue(queue *); -extern void free_queue(queue *); -extern void *zmalloc(size_t); - -extern void start_timer(void); -extern double elapsed_sec(void); - -void warn3(char *s0, char *s1, char *s2); - -int crossings_below(Agraph_t *g, int northlevel); -Agedge_t *agfindedge(Agraph_t *g, Agnode_t *t, Agnode_t *h); -void agautoinit(Agraph_t *g, int, int, int); diff --git a/lib/dotgen2/bjm.c b/lib/dotgen2/bjm.c deleted file mode 100644 index f03df860d..000000000 --- a/lib/dotgen2/bjm.c +++ /dev/null @@ -1,86 +0,0 @@ -/* Simple and Efficient BiLayer Cross Counting by Barth, Mutzel and Junger */ -typedef struct Agnodeinfo_s { - int order; -} Agnodeinfo_t; -typedef struct Agedgeinfo_s { - int useless; -} Agedgeinfo_t; -typedef struct Agraphinfo_s { - int useless; -} Agraphinfo_t; -#include -#include -#include - -#define ND_order(n) ((n)->u.order) - -int crossings(int r, int southsequence[], int q) -{ - int crosscount, firstindex, *tree, treesize; - int t, k, index; - - /* build the accumulator tree */ - firstindex = 1; - while (firstindex 0) { - if (index%2) crosscount += tree[index+1]; - index = (index - 1)/2; - tree[index]++; - } - } - printf("Number of crossings: %d\n",crosscount); - free(tree); - return crosscount; -} - -static int edgecmpf(void *arg0, void *arg1) -{ - int major, minor; - Agedge_t *e0, *e1; - - e0 = *(Agedge_t**)arg0; - e1 = *(Agedge_t**)arg1; - major = ND_order(e0->tail) - ND_order(e1->tail); - if (major) return major; - minor = ND_order(e0->head) - ND_order(e1->head); - return minor; -} - - -int main(int argc, char **argv) -{ - Agraph_t *g; - Agnode_t *n; - Agedge_t *e, **edgelist; - int i, ne, p, q, my_order; - int *southseq; - char junk; - - aginit(); - g = agread(stdin); /* must be two-layer */ - i = ne = p = q = 0; - for (n = agfstnode(g); n; n = agnxtnode(g,n)) { - sscanf(n->name,"%c%d",&junk,&my_order); - ND_order(n) = my_order; - if (agfstout(g,n)) p++; - else q++; - } - southseq = malloc(agnnodes(g) * sizeof(int)); - edgelist = malloc(agnedges(g) * sizeof(Agedge_t*)); - for (n = agfstnode(g); n; n = agnxtnode(g,n)) - for (e = agfstout(g,n); e; e = agnxtout(g,e)) - edgelist[ne++] = e; - qsort(edgelist,i,sizeof(Agedge_t*),edgecmpf); - for (i = 0; i < ne; i++) southseq[i] = ND_order(edgelist[i]->head); - crossings(ne, southseq, q); -} diff --git a/lib/dotgen2/bjm0.c b/lib/dotgen2/bjm0.c deleted file mode 100644 index 4bbabafd2..000000000 --- a/lib/dotgen2/bjm0.c +++ /dev/null @@ -1,92 +0,0 @@ -typedef struct Agnodeinfo_s { - int order; -} Agnodeinfo_t; -typedef struct Agedgeinfo_s { - int useless; -} Agedgeinfo_t; -typedef struct Agraphinfo_s { - int useless; -} Agraphinfo_t; -#include -#include -#include - -#define ND_order(n) ((n)->u.order) - -int crossings(int r, int southsequence[], int q) -{ - int crosscount, firstindex, *tree, treesize; - int t, k, index; - - /* build the accumulator tree */ - firstindex = 1; - while (firstindex 0) { - if (index%2) crosscount += tree[index+1]; - index = (index - 1)/2; - tree[index]++; - } - } - printf("Number of crossings: %d\n",crosscount); - free(tree); - return crosscount; -} - -static int edgecmpf(void *arg0, void *arg1) -{ - int major, minor; - Agedge_t *e0, *e1; - - e0 = *(Agedge_t**)arg0; - e1 = *(Agedge_t**)arg1; - major = ND_order(e0->tail) - ND_order(e1->tail); - if (major) return major; - minor = ND_order(e0->head) - ND_order(e1->head); - return minor; -} - -int main(int argc, char **argv) -{ - Agraph_t *g; - Agnode_t *n; - Agedge_t *e; - radixrec_t *edgelist; - int i, ne, p, q, my_order; - int *southseq; - char junk; - - aginit(); - g = agread(stdin); /* must be two-layer */ - i = ne = p = q = 0; - for (n = agfstnode(g); n; n = agnxtnode(g,n)) { - sscanf(n->name,"%c%d",&junk,&my_order); - ND_order(n) = my_order; - if (agfstout(g,n)) p++; - else q++; - } - southseq = malloc(agnnodes(g) * sizeof(int)); - edgelist = malloc(agnedges(g) * sizeof(radixrec_t)); - for (n = agfstnode(g); n; n = agnxtnode(g,n)) - for (e = agfstout(g,n); e; e = agnxtout(g,e), ne++) - { edgelist[ne].key = (ND_order(e->tail) << 16) + ND_order(e->head); - edgelist[ne].data = e; } - /*qsort(edgelist,i,sizeof(Agedge_t*),edgecmpf);*/ - radix_sort(edgelist,ne); - for (i = 0; i < ne; i++) printf("%d %d %s %s\n", - ((edgelist[i].key & 0xffff0000) >> 16), - ((edgelist[i].key & 0x0000ffff) >> 0), - ((Agedge_t*)(edgelist[i].data))->tail->name, - ((Agedge_t*)(edgelist[i].data))->head->name); - for (i = 0; i < ne; i++) southseq[i] = ND_order(((Agedge_t*)(edgelist[i].data))->head); - crossings(ne, southseq, q); -} diff --git a/lib/dotgen2/ce.c b/lib/dotgen2/ce.c deleted file mode 100644 index 7e66b5176..000000000 --- a/lib/dotgen2/ce.c +++ /dev/null @@ -1,16 +0,0 @@ -static int Base = -1; /* zero-based arrays */ -#define Odd(n) ((n) % 2) -static int CountEdges(int Tree[], int n, int last) -{ - int Pos, Sum; - - if (n == last) return 0; - Pos = n + Base + 1; - Sum = 0; - while (Pos >= 1) { - if (Odd(Pos)) - Sum = Sum + Tree[Pos - 1]; - Pos = Pos / 2; - } - return (Tree[1 + Base] - Sum); -} diff --git a/lib/dotgen2/countx.c b/lib/dotgen2/countx.c deleted file mode 100644 index 87808ff5b..000000000 --- a/lib/dotgen2/countx.c +++ /dev/null @@ -1,76 +0,0 @@ -#include "newdot.h" - -/* Simple and Efficient BiLayer Cross Counting by Barth, Mutzel and Junger */ - -static int count_crossings(rank_t *north, rank_t *south) -{ - int crosscount, firstindex; - int t, k, index; - static int trip; - - trip++; - /* build the accumulator tree */ - if (north->tree == 0) { - firstindex = 1; - while (firstindex < south->n) firstindex *= 2; - north->treesize = 2*firstindex - 1; /* number of tree nodes */ - north->tree = N_NEW(north->treesize,int); - firstindex -= 1; - } - else { - firstindex = (north->treesize + 1) / 2 - 1; /* index of leftmost leaf */ - } - for (t=0; ttreesize; t++) north->tree[t] = 0; - - /* count the crossings */ - crosscount = 0; /* number of crossings */ - for (k=0; k < north->ne; k++) { /* insert edge k */ - index = ND_order(aghead(((Agedge_t*)(north->edgelist[k].data)))) + firstindex; - north->tree[index]++; - while (index > 0) { - if (index%2) crosscount += north->tree[index+1]; - index = (index - 1)/2; - north->tree[index]++; - } - } - return crosscount; -} - -int crossings_below(Agraph_t *g, int northlevel) -{ - int c; - rank_t *r; - node_t **v; - edge_t *e; - - r = &GD_rank(g)[northlevel]; - if (r->crossing_cache.valid) - return r->crossing_cache.count; - - if (northlevel == GD_maxrank(g)) c = 0; - else { - if (!r->edgelist) { /* set up edgelist */ - /* count the edges */ - c = 0; - for (v = r->v; *v; v++) - for (e = agfstout(g,*v); e; e = agnxtout(g,e)) c++; - r->edgelist = N_NEW(c+1,radixrec_t); - /* install the edges */ - c = 0; - for (v = r->v; *v; v++) - for (e = agfstout(g,*v); e; e = agnxtout(g,e)) { - r->edgelist[c].key = (ND_order(agtail(e)) << 16) + ND_order(aghead(e)); - r->edgelist[c].data = e; - c++; - } - r->ne = c; - } - if (r->ne > 0) { - radix_sort(r->edgelist,r->ne); - c = count_crossings(r,&GD_rank(g)[northlevel+1]); - } - } - r->crossing_cache.count = c; - r->crossing_cache.valid = TRUE; - return c; -} diff --git a/lib/dotgen2/decomp.c b/lib/dotgen2/decomp.c deleted file mode 100644 index eb3631298..000000000 --- a/lib/dotgen2/decomp.c +++ /dev/null @@ -1,131 +0,0 @@ -/* $Id$ $Revision$ */ -/* vim:set shiftwidth=4 ts=8: */ - -/************************************************************************* - * Copyright (c) 2011 AT&T Intellectual Property - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: See CVS logs. Details at http://www.graphviz.org/ - *************************************************************************/ - - -/* - * Decompose finds the connected components of a graph. - * It searches the temporary edges and ignores non-root nodes. - * The roots of the search are the real nodes of the graph, - * but any virtual nodes discovered are also included in the - * component. - */ -#include "dot2.h" - -static Agraph_t *G; -static Agnode_t *Last_node; -static char Cmark; - -static void -begin_component(void) -{ - Last_node = GD_nlist(G) = NULL; -} - -static void -add_to_component(node_t * n) -{ - GD_n_nodes(G)++; - ND_mark(n) = Cmark; - if (Last_node) { - ND_prev(n) = Last_node; - ND_next(Last_node) = n; - } else { - ND_prev(n) = NULL; - GD_nlist(G) = n; - } - Last_node = n; - ND_next(n) = NULL; -} - -static void -end_component(void) -{ - int i; - - i = GD_comp(G).size++; - GD_comp(G).list = ALLOC(GD_comp(G).size, GD_comp(G).list, Agnode_t *); - GD_comp(G).list[i] = GD_nlist(G); -} - -static void -search_component(graph_t * g, node_t * n) -{ - int c, i; - elist vec[4]; - node_t *other; - edge_t *e; - - Agedge_t* tempE; - static int count=0; - - add_to_component(n); - vec[0] = ND_out(n); - vec[1] = ND_in(n); - vec[2] = ND_flat_out(n); - vec[3] = ND_flat_in(n); - - for (e = agfstout(g, n); e; e = agnxtout(g, e)) - { - Agedge_t* tempE=e; - if ((other = aghead(e)) == n) - other = agtail(e); - if (ND_mark(other) != Cmark) - search_component(g, other); - e=tempE; - } - for (e = agfstin(g, n); e; e = agnxtin(g, e)) - { - - count++; - if(count ==53) - printf("dgfdg"); - if ((other = aghead(e)) == n) - other = agtail(e); - if (ND_mark(other) != Cmark) - search_component(g, other); - tempE=e; - } - //implementflat in and flat out versions - - -/* for (c = 0; c <= 3; c++) { - if (vec[c].list) - for (i = 0; (e = vec[c].list[i]); i++) { - if ((other = aghead(e)) == n) - other = agtail(e); - if (ND_mark(other) != Cmark) - if(other == UF_find(other)) - search_component(g, other); - } - }*/ -} - -void decompose(graph_t * g, int pass) -{ - graph_t *subg; - node_t *n, *v; - - G = g; - if (++Cmark == 0) - Cmark = 1; - GD_n_nodes(g) = GD_comp(g).size = 0; - for (n = agfstnode(g); n; n = agnxtnode(g, n)) { - v = n; - - if (ND_mark(v) != Cmark) { - begin_component(); - search_component(g, v); - end_component(); - } - } -} diff --git a/lib/dotgen2/dot2.h b/lib/dotgen2/dot2.h deleted file mode 100644 index 41e9f179e..000000000 --- a/lib/dotgen2/dot2.h +++ /dev/null @@ -1,31 +0,0 @@ -/* $Id$Revision: */ -/* vim:set shiftwidth=4 ts=8: */ - -/************************************************************************* - * Copyright (c) 2011 AT&T Intellectual Property - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: See CVS logs. Details at http://www.graphviz.org/ - *************************************************************************/ - - -#ifndef DOT2_H -#define DOT2_H - -#include "render.h" -#include "dot2procs.h" - -/* tags for representative (model) objects */ -/* 0 is reserved for undefined */ -#define STDNODE 1 /* a real node on only one rank */ -#define TALLNODE 2 /* a real node on two or more ranks */ -#define EXTNODE 3 /* a node external to a cluster */ -#define SKELETON 4 -#define PATH 5 -#define INTNODE 6 /*internal temporary nodes to fill rank gaps*/ -#define LBLNODE 7 /*internal temp nodes for edge labels*/ - -#endif /* DOT_H */ diff --git a/lib/dotgen2/dot2procs.h b/lib/dotgen2/dot2procs.h deleted file mode 100644 index 622fe6dc6..000000000 --- a/lib/dotgen2/dot2procs.h +++ /dev/null @@ -1,37 +0,0 @@ -/* $Id$Revision: */ -/* vim:set shiftwidth=4 ts=8: */ - -/************************************************************************* - * Copyright (c) 2011 AT&T Intellectual Property - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: See CVS logs. Details at http://www.graphviz.org/ - *************************************************************************/ - -#ifndef DOT2PROCS_H -#define DOT2PROCS_H - -#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 __cplusplus -} -#endif - -#endif diff --git a/lib/dotgen2/dotinit.c b/lib/dotgen2/dotinit.c deleted file mode 100644 index aac4b1052..000000000 --- a/lib/dotgen2/dotinit.c +++ /dev/null @@ -1,122 +0,0 @@ -/* $Id$Revision: */ -/* vim:set shiftwidth=4 ts=8: */ - -/************************************************************************* - * Copyright (c) 2011 AT&T Intellectual Property - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: See CVS logs. Details at http://www.graphviz.org/ - *************************************************************************/ - -#include "dot2.h" -#define DEBUG -#ifdef DEBUG -static void attach_attributes(graph_t *g) -{ - node_t *n; - Agsym_t *rank, *order; - char buf[64]; - - rank = agattr(g,AGNODE,"rank",""); - order = agattr(g,AGNODE,"order",""); - for (n = agfstnode(g); n; n = agnxtnode(g,n)) { - sprintf(buf,"%d",ND_rank(n)); - agxset(n,rank,buf); - sprintf(buf,"%d",ND_order(n)); - agxset(n,order,buf); - } -} -#endif - -static void dot_init_node(node_t * n) -{ - common_init_node(n); - gv_nodesize(n, GD_flip(agraphof(n))); -/* - alloc_elist(4, ND_in(n)); - alloc_elist(4, ND_out(n)); - alloc_elist(2, ND_flat_in(n)); - alloc_elist(2, ND_flat_out(n)); - alloc_elist(2, ND_other(n)); - ND_UF_size(n) = 1; -*/ -} - -static void dot_init_edge(edge_t * e) -{ - char *tailgroup, *headgroup; - common_init_edge(e); - - ED_weight(e) = late_double(e, E_weight, 1.0, 0.0); - tailgroup = late_string(agtail(e), N_group, ""); - headgroup = late_string(aghead(e), N_group, ""); - ED_count(e) = ED_xpenalty(e) = 1; - /* FIX: does new ranking and mincross handle these? */ - if (tailgroup[0] && (tailgroup == headgroup)) { - ED_xpenalty(e) = CL_CROSS; - ED_weight(e) *= 100; - } - if (is_nonconstraint(e)) { - ED_xpenalty(e) = 0; - ED_weight(e) = 0; - } - - ED_showboxes(e) = late_int(e, E_showboxes, 0, 0); - ED_minlen(e) = late_int(e, E_minlen, 1, 0); -} - -static void initGraph(graph_t * g) -{ - aginit(g, AGRAPH, "Agraphinfo_t", -sizeof(Agraphinfo_t), TRUE); - aginit(g, AGNODE, "Agnodeinfo_t", -sizeof(Agnodeinfo_t), TRUE); - aginit(g, AGEDGE, "Agedgeinfo_t", -sizeof(Agedgeinfo_t), TRUE); -} - -static void dot_init_node_edge(graph_t * g) -{ - node_t *n; - edge_t *e; - - initGraph (g); - for (n = agfstnode(g); n; n = agnxtnode(g, n)) - dot_init_node(n); - for (n = agfstnode(g); n; n = agnxtnode(g, n)) { - for (e = agfstout(g, n); e; e = agnxtout(g, e)) - dot_init_edge(e); - } -} - -/* dot2_layout: - * FIX: - * connected components - * multiedges ? - * concentrator ? - * aspect ? - */ -void dot2_layout(Agraph_t * g) -{ - Agraph_t *tempG; - - fprintf(stderr, "dot_layout\n"); - dot_init_node_edge(g); - - dot2_levels(g); - /* agwrite(g, stdout); */ - tempG = dot2_mincross(g); -#ifdef DEBUG - attach_attributes(tempG); -#endif -// agwrite(tempG,stdout); - - return; -} - -void dot2_cleanup(graph_t * g) -{ - /* FIX */ - printf("dot_cleanup\n"); - return; -} diff --git a/lib/dotgen2/flat.c b/lib/dotgen2/flat.c deleted file mode 100644 index e232ba087..000000000 --- a/lib/dotgen2/flat.c +++ /dev/null @@ -1,61 +0,0 @@ -/* this function will have to be modified if we go for - * multi-level nodes */ -int is_flat_edge(Agedge_t *e) -{ - if (ND_rank(agtail(e)) = ND_rank(aghead(e)) return TRUE; - return FALSE; -} - -void model_flat_edge(Agraph_t *flat, Agedge_t *orig) -{ - Agnode_t *u, *v; - u = model_flat_node(flat, agtail(orig)); - v = model_flat_node(flat, aghead(orig)); - e = agedge(flat,u,v,0,TRUE); /* could merge edges if multiple? */ -} - -Agraph_t *flat_init(Agraph_t *user) -{ - flat = agopen("flatgraph",Agstrictdirected,0); - for (u = agfstnode(user); u; u = agnxtnode(user,u)) { - for (e = agfstout(user,u); e; e = agnxtout(user,e)) { - if (is_flat_edge(e)) - model_flat_edge(flat,e); - } - } -} - -void flat_dfs(Agraph_t *flat, Agnode_t *n) -{ - ND_mark(n) = TRUE; - ND_onstack(n) = TRUE; - for (e = agfstout(flat,n); e; e = next_e) { - next_e = agnxtout(g,e); - if (ND_onstack(aghead(e))) agdelete(flat,e); - } - ND_onstack(n) = FALSE; -} - -void flat_breakcycles(Agraph_t *flat) -{ - for (n = agfstnode(flat); n; n = agnxtnode(flat,n)) - ND_mark(n) = 0; - for (n = agfstnode(flat); n; n = agnxtnode(flat,n)) - if (!ND_mark(n)) flat_dfs(flat,n); -} - -static void reverse_edge(Agraph_t *g, edge_t *e) -{ - 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); -} - -void flat_phase(Agraph_t *user) -{ - flat = flat_init(user); - flat_breakcycles(flat); -} diff --git a/lib/dotgen2/groups.c b/lib/dotgen2/groups.c deleted file mode 100644 index ca7dd1185..000000000 --- a/lib/dotgen2/groups.c +++ /dev/null @@ -1,135 +0,0 @@ -/* $Id$Revision: */ -/* vim:set shiftwidth=4 ts=8: */ - -/************************************************************************* - * Copyright (c) 2011 AT&T Intellectual Property - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: See CVS logs. Details at http://www.graphviz.org/ - *************************************************************************/ - -#include "dot2.h" -#include "groups.h" -#include "utils.h" - -static int comparePos(Dt_t* dt, float* key1, float* key2, Dtdisc_t* disc) -{ - float a,b; - a = *key1; - b = *key2; - if(a < b) return -1; - else return 1; -} - -/*group discipline */ -Dtdisc_t discGroup = { - 0, - 0, - -1, - NIL(Dtmake_f), - NIL(Dtfree_f), - NIL(Dtcompar_f), - NIL(Dthash_f), - NIL(Dtmemory_f), - NIL(Dtevent_f) -}; - - -/*node discipline , sorted set*/ -Dtdisc_t discNode = { - offsetof(mcNode,order), - sizeof(float), - -1, - NIL(Dtmake_f), - NIL(Dtfree_f), - (Dtcompar_f)comparePos, - NIL(Dthash_f), - NIL(Dtmemory_f), - NIL(Dtevent_f) -}; - -static mcGroup* initMcGroup(mcGroup_t type) -{ - mcGroup* rv = NEW(mcGroup); - rv->alignType=mcBoth; - rv->cnt=0; - rv->nodes=dtopen(&discNode,Dtset); -#if 0 - rv->children=dtopen(&discGroup,Dtset); -#endif - rv->type=type; - return rv; -} - -/* createGroups: - * run after temp nodes are created -*/ -void createGroups(Agraph_t* sg) -{ - mcGroup* gr; - Agraph_t* subg; - Agnode_t* v; - mcNode* leader; - mcNode* mcn; - for (subg = agfstsubg(sg); subg; subg = agnxtsubg(subg)) - { - if(is_a_cluster(subg)) { - int isLeader=1; - gr=initMcGroup(mcGrStrict); - for (v = agfstnode(subg); v; v = agnxtnode(subg, v)) { - mcn = MND_mcn(v); - dtappend(gr->nodes,mcn); - mcn->group=gr; - mcn->groupOrder=0;/*this will be removed eventually */ - mcn->isLeader=isLeader; - - if(isLeader==1) { - leader = mcn; - isLeader = 0; - } - mcn->leader = leader; - } - } - else - createGroups (subg); - } -} - -/* nodesToClusters: - * If dummy nodes belong to a cluster, add them. - */ -void nodesToClusters(Agraph_t* g) -{ - Agnode_t* v; - Agraph_t* c; - for (v = agfstnode(g); v; v = agnxtnode(g, v)) - { - if ((c = MND_highCluster(v))) - agsubnode(c,v,1); /*i hope this routine is optimized!*/ - } -} - -/* graphGroups: - * The highCluster attribute of a node is set to the highest containing - * cluster, or NULL if not in a cluster. - * Run this before creating mincross temp nodes - */ - -void graphGroups(Agraph_t* sg) -{ - Agraph_t* subg; - Agnode_t* v; - for (subg = agfstsubg(sg); subg; subg = agnxtsubg(subg)) - { - if(is_a_cluster(subg)) - for (v = agfstnode(subg); v; v = agnxtnode(subg, v)) - MND_highCluster(v)=subg; - else - graphGroups (subg); - - } -} - diff --git a/lib/dotgen2/groups.h b/lib/dotgen2/groups.h deleted file mode 100644 index 56643bfa1..000000000 --- a/lib/dotgen2/groups.h +++ /dev/null @@ -1,23 +0,0 @@ -/* $Id$Revision: */ -/* vim:set shiftwidth=4 ts=8: */ - -/************************************************************************* - * Copyright (c) 2011 AT&T Intellectual Property - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: See CVS logs. Details at http://www.graphviz.org/ - *************************************************************************/ - -#ifndef GROUPS_H -#define GROUPS_H - -#include - -extern void createGroups(Agraph_t* g); -extern void nodesToClusters(Agraph_t* g); -extern void graphGroups(Agraph_t* sg); - -#endif diff --git a/lib/dotgen2/level.c b/lib/dotgen2/level.c deleted file mode 100644 index babef7761..000000000 --- a/lib/dotgen2/level.c +++ /dev/null @@ -1,501 +0,0 @@ -/* $Id$Revision: */ -/* vim:set shiftwidth=4 ts=8: */ - -/************************************************************************* - * Copyright (c) 2011 AT&T Intellectual Property - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: See CVS logs. Details at http://www.graphviz.org/ - *************************************************************************/ - -#include "dot2.h" -#include "utils.h" -#include "arith.h" - -#define BACKWARD_PENALTY 1000 -#define STRONG_CLUSTER_WEIGHT 1000 -#define NORANK 6 - -extern void rank2(graph_t * g, int balance, int maxiter, int searchsize); - -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) -{ - int *s; - - 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); -} - -void dot2_levels(graph_t * g) -{ - 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_empty(graph_t * g) -{ - return (agfstnode(g) == NILnode); -} - -static int is_a_strong_cluster(graph_t * g) -{ - char *str = agget(g, "compact"); - return mapBool((str), TRUE); -} - -static int rankset_kind(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; -} - -int is_nonconstraint(edge_t * e) -{ - char *constr; - - if (E_constr && (constr = agxget(e, E_constr))) { - if (constr[0] && mapbool(constr) == FALSE) - return TRUE; - } - return FALSE; -} - -static node_t *find(node_t * n) -{ - 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_one(node_t * leader, node_t * n) -{ - if (n) - return (ND_set(find(n)) = find(leader)); - else - return leader; -} - -static node_t *union_all(graph_t * g) -{ - 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; -} - -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 */ - agerr (AGWARN, "%s has unrecognized rank=%s", agnameof(ug), agget(ug, "rank")); - } - - /* 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); - } - } -} - -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; -} - -static int is_internal_to_cluster(edge_t * e) -{ - 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) -{ - /* 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) -{ - ED_minlen(e) = MAX(ED_minlen(e), minlen); - ED_weight(e) += weight; -} - -/*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(); -} - -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); - } - 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) -{ - 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) -{ - 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) -{ - 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); - } - } - } - 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); -} - -static void reverse_edge(graph_t * g, edge_t * e) -{ - 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); -} - -static void dfs(graph_t * g, node_t * v) -{ - 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); - } - } - ND_onstack(v) = FALSE; -} - -static void break_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)) - dfs(g, n); -} - -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))); - } -} - -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); - } -} - -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++; - } - } - } -} - -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, "%d", ED_minlen(e)); - agxset(e, minlen, buf); - sprintf(buf, "%.02f,%d", ED_weight(e), ED_minlen(e)); - agxset(e, label, buf); - } - } -} -static void printgraph(Agraph_t * g) -{ - aaa(g); - agwrite(g, stderr); -} - -static int nd_rank(Agnode_t * n) -{ - return ND_rank(n); -} diff --git a/lib/dotgen2/main.c b/lib/dotgen2/main.c deleted file mode 100644 index 1b2d959f5..000000000 --- a/lib/dotgen2/main.c +++ /dev/null @@ -1,68 +0,0 @@ -#include "newdot.h" - -#ifdef _WIN32 /*dependencies*/ - #pragma comment( lib, "cgraph.lib" ) - #pragma comment( lib, "cdt.lib" ) - #pragma comment( lib, "ltdl.lib" ) - #pragma comment( lib, "xml2.lib" ) - #pragma comment( lib, "libexpat.lib" ) - #pragma comment( lib, "regex_win32.lib" ) - #pragma comment( lib, "z.lib" ) -#endif - - - -void readin_attrs(graph_t *g) -{ - node_t *n; - edge_t *e; - Agsym_t *ap_weight, *ap_minlen; - - ap_weight = agattr(g,AGEDGE,"weight","1"); - ap_minlen = agattr(g,AGEDGE,"minlen","1"); - for (n = agfstnode(g); n; n = agnxtnode(g,n)) { - for (e = agfstout(g,n); e; e = agnxtout(g,e)) { - ED_weight(e) =atoi(agxget(e,ap_weight)); - ED_minlen(e) = atoi(agxget(e,ap_minlen)); - } - } -} - -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); - } -} - -void init_graph(graph_t *g) -{ - aginit(g,AGRAPH,"graphviz",sizeof(Agraphinfo_t),TRUE); - aginit(g,AGNODE,"graphviz",sizeof(Agnodeinfo_t),TRUE); - aginit(g,AGEDGE,"graphviz",sizeof(Agedgeinfo_t),TRUE); -} - -int main(int argc, char *argv[]) -{ - graph_t *g; - FILE *in; - if (argc > 1) in = fopen(argv[1],"r"); - else in = stdin; - g = agread(in,0); - init_graph(g); - readin_attrs(g); - dot_levels(g); -// if (argc <= 2) dot_mincross(g); - attach_attributes(g); - agwrite(g,stdout); - return 1; -} diff --git a/lib/dotgen2/minc.c b/lib/dotgen2/minc.c deleted file mode 100644 index 5653e4e4a..000000000 --- a/lib/dotgen2/minc.c +++ /dev/null @@ -1,1334 +0,0 @@ -#include "newdot.h" - -/* given: - * ND_rank(v) int integer level assignments - * ND_ranksize(v) int number of levels (assumed >= 1) - * ED_xpenalty(e) float crossing penalty factor - * find: - * ND_order(v) int index within rank - * ND_pos(v) coord (define: is this the center point?) - * ED_pos(e) coord* (define: polyline?) - * - * todo: node, edge, graph labels, flat edges - */ - -/* internal graph variables: - * user graph - * ND_cluster(v) graph* lowest containing cluster - * GD_model(g) graph* model graph - * GD_parent(g) graph* parent cluster - * GD_level int distance from layout root - * - * model graph objects - * GD_usergraph(g) graph* original graph or one of its clusters - * GD_minrank(g) int lowest rank index incl. external edges - * GD_maxrank(g) int highest rank index incl. external edges - * GD_minlocalrank(g) int lowest rank index of internal nodes - * GD_maxlocalrank(g) int highest rank index of internal nodes - * GD_level int distance from layout root - * GD_rank(g) rank_t[] - * GD_repdict(g) Dict_t* local representatives of user objects - * ND_component(v) int connected component number - * ND_order(v) int order within rank - * ND_type(v) int - * NODE, TALLNODE primitive node - * EXTNODE represents endpoint of an external cluster edge - * SKELETON represents an internal cluster - * PATH for virtual nodes in edges of all kinds - * ND_cluster(v) graph* for EXTNODE, its lowest user cluster - for SKELETON, its user cluster - for PATH, NODE, TALLNODE 0? - * ND_sortweight(v) for mincross and presort before mincross - * ND_sortweight_defined(v) (sortweight undefined if up/down degree==0) - * ND_isglobal(v) marks objects for the global merged graph - */ - -/* TODO - where do we use port.defined? - */ - -/* forward declarations */ -static void transpose_sweep(Agraph_t* g, int reverse); -static void mincross_sweep(Agraph_t* g, int dir, boolean reverse); -static void restorebest(graph_t *g); -static Agraph_t *globalize(Agraph_t *user); -static int crossings(graph_t *g); -static void rec_cluster_init(Agraph_t *ug); -static int left2right(Agraph_t *g, node_t *v, node_t *w); -static int in_cross(node_t *v,node_t *w); -static int out_cross(node_t *v, node_t *w); -static boolean medians(Agraph_t *g, int r0, int r1); -static void reorder(graph_t *g, int r, boolean reverse, boolean hasfixed); -static void savebest(graph_t *g); -static Agnode_t *choosenode(Agnode_t *fst, Agnode_t *snd); -static void cluster_ranksetup(Agraph_t *user); -static void cluster_extents(Agraph_t *g); -static void cluster_rankstorage(Agraph_t *g); -static Agnode_t *bindnode(Agraph_t *model, Agnode_t *orignode); - - -/*** basic user<->model association maps ***/ -/* determine canonical order of n0, n1 */ -static void getlowhigh(Agnode_t **n0, Agnode_t **n1) -{ - Agnode_t *temp; - int d; - d = ND_rank(*n1) - ND_rank(*n0); - if ((d < 0) || ((d == 0) && (AGID(*n1)< AGID(*n0)))) - {temp = *n0; *n0 = *n1; *n1 = temp;} -} - -static int inrange(int a, int b, int c) -{ - return ((a <= b) && (b <= c)); -} - -static int repkeycmp(Dt_t *d, void *arg0, void *arg1, Dtdisc_t *disc) -{ - void *key0 = ((repkey_t*)arg0)->key; - void *key1 = ((repkey_t*)arg1)->key; - int rv; -#ifdef NOTDEF - /* not sure why I coded this - SCN 12/27/2005 */ - switch(agobjkind(key0)) { - case AGNODE: - rv = AGID(*(Agnode_t*)key1) - AGID(*(Agnode_t*)key0); - break; - case AGEDGE: - rv = AGID(*(Agedge_t*)key1) - AGID(*(Agedge_t*)key0); - break; - case AGRAPH: - /* in libgraph we don't seem to have graph ids, so use pointer */ - rv = (unsigned long)key1 - (unsigned long) key0; - break; - default: - rv = 0; - } -#else - rv = (int)((unsigned long)key1 - (unsigned long) key0); -#endif - return rv; -} - -static Dtdisc_t Repdisc = { - 0, /* pass whole object as key */ - 0, /* key size and type */ - -1, /* link offset */ - (Dtmake_f)0, - (Dtfree_f)0, - (Dtcompar_f) repkeycmp, - (Dthash_f)0, - (Dtmemory_f)0, - (Dtevent_f)0 -}; - -static Dict_t *repdict(Agraph_t *model) -{ - Dict_t *dict; - - dict = GD_repdict(model); - if (!dict) dict = GD_repdict(model) = dtopen(&Repdisc,Dttree); - return dict; -} - -static rep_t association(Agraph_t *model, void *obj) -{ - Dict_t *dict; - repkey_t key, rv, *p; - - dict = repdict(model); - key.key = obj; /* i hate when other people code like this */ - if ((p = dtsearch(dict,&key))) rv = *p; - else {rv.val.type = 0; rv.val.p = 0;} - return rv.val; -} - -static void associate(Agraph_t *model, void *key, rep_t val) -{ - Dict_t *dict; - repkey_t *newelt; - - assert(association(model,key).type == 0); - dict = repdict(model); - newelt = NEW(repkey_t); - newelt->key = key; - newelt->val = val; - dtinsert(dict,newelt); - if (association(model,key).type == 0) abort(); -} - -/* given a value, find (some) rep (including the key) that maps to it. - * for now we'll brute force it. note that val may always be an external - * edge path, so we wouldn't necessarily need the full inverse map. - */ -static repkey_t invassociation(Agraph_t *model, void *val) -{ - Dict_t *dict; - repkey_t *p; - dict = repdict(model); - for (p = dtfirst(dict); p; p = dtnext(dict,p)) { - if (p->val.p == val) break; - } - assert(p); - return *p; -} - -typedef struct component_s { - int n; - node_t **root; - int r; -} component_t; - - - -/* from level.c - eventually clean this up. */ -static int is_a_cluster(Agraph_t *g) -{ - return ((g == g->root) || (!strncasecmp(agnameof(g),"cluster",7))); -} - -/* find the cluster of n that is an immediate child of g */ -static Agraph_t *subclustof(Agnode_t *n, Agraph_t *g) -{ - Agraph_t *rv; - for (rv = ND_cluster(n); rv && (GD_parent(rv) != g); rv = GD_parent(rv)); - return rv; -} - -static void *T_array(int low, int high, int size) -{ - char *rv; - - rv = calloc((high - low + 1),size); - rv = rv - (low * size); - return rv; -} - -static void *T_base(void *array, int low, int size) -{ - char *rv; - rv = array; - rv = rv + low * size; - return rv; -} - -static void freearray(void *array, int low, int size) -{ - free(T_base(array,low,size)); -} - -static Agnode_t **nodearray(int low, int high) -{ return (Agnode_t**) T_array(low,high,sizeof(Agnode_t*)); } - -static Agedge_t **edgearray(int low, int high) -{ return (Agedge_t**) T_array(low,high,sizeof(Agedge_t*)); } - -static int *intarray(int low, int high) -{ return (int*) T_array(low,high,sizeof(int)); } - -/* internal functions for model graph construction and maintenance */ -static vpath_t *newpath(Agraph_t *model, Agnode_t *u, int low, Agnode_t *v, int high) -{ - vpath_t *path; - int i; - path = NEW(vpath_t); - path->low = low; path->high = high; - path->v = nodearray(low, high); - path->e = edgearray(low, high); - for (i = low; i <= high; i++) { - if ((i == low) && u) path->v[i] = u; - else if ((i == high) && v) path->v[i] = v; - else { - path->v[i] = agnode(model,0,TRUE); - ND_rank(path->v[i]) = i; - } - if (i > low) path->e[i-1] = agedge(model,path->v[i-1],path->v[i],0,TRUE); - } - return path; -} - -static void attributepath(vpath_t *path, int nodetype, Agraph_t *clust) -{ - int i; - for (i = path->low; i <= path->high; i++) { - ND_type(path->v[i]) = nodetype; - ND_cluster(path->v[i]) = clust; - } -} - -static rep_t model_edge(Agraph_t *model, Agedge_t *orig) -{ - Agedge_t *e; - Agnode_t *low, *high, *u, *v; - port_t lowport, highport; - vpath_t *path; - rep_t rep; - int i; - - rep = association(model,orig); - if (rep.type == 0) { - low = agtail(orig); high = aghead(orig); - getlowhigh(&low,&high); - u = bindnode(model,low); - assert(u); - v = bindnode(model,high); - assert(v); - path = newpath(model,u,ND_rank(low),v,ND_rank(high)); - rep.type = PATH; - rep.p = path; - associate(model,orig,rep); - } - else path = rep.p; - - /* merge the attributes of orig */ - for (i = path->low; i < path->high; i++) { - e = path->e[i]; - ED_xpenalty(e) += ED_xpenalty(orig); - ED_weight(e) += ED_weight(orig); - } - - /* deal with ports. note that ends could be swapped. */ - if (ND_rank(agtail(orig)) <= ND_rank(aghead(orig))) { - lowport = ED_tailport(orig); - highport = ED_headport(orig); - } - else { - highport = ED_tailport(orig); - lowport = ED_headport(orig); - } - if (lowport.defined) - path->avgtailport = ((path->weight * path->avgtailport) + ED_weight(orig) * lowport.p.x) / (path->weight + ED_weight(orig)); - if (highport.defined) - path->avgheadport = ((path->weight * path->avgheadport) + ED_weight(orig) * highport.p.x) / (path->weight + ED_weight(orig)); - path->weight += ED_weight(orig); - return rep; -} - -/* bind/construct representative of an internal node in a model graph */ -static rep_t model_intnode(Agraph_t *model, Agnode_t *orig) -{ - int nr; - rep_t rep; - Agnode_t *v; - - rep = association(model,orig); - if (rep.type) return rep; - - nr = ND_ranksize(orig); - if (nr <= 1) { /* simple case */ - rep.type = NODE; - v = rep.p = agnode(model,agnameof(orig),TRUE); - ND_rank(v) = ND_rank(orig); - } - else { /* multi-rank node case */ - rep.type = TALLNODE; - rep.p = newpath(model,NILnode,ND_rank(orig),NILnode,ND_rank(orig)+nr-1); - attributepath(rep.p,TALLNODE,0); - } - associate(model,orig,rep); - return rep; -} - -/* bind/construct representative of an external endpoint to a model graph */ -static rep_t model_extnode(Agraph_t *model, Agnode_t *orig) -{ - Agnode_t *v; - rep_t rep; - - rep = association(model,orig); - if (rep.type) return rep; - - /* assume endpoint is represented by one node, even if orig is multi-rank. - * also we aren't keeping track of ports yet */ - rep.p = v = agnode(model,agnameof(orig),TRUE); - rep.type = EXTNODE; - ND_rank(v) = ND_rank(orig); /* should be ND_rank(orig)+ranksize(orig)? */ - associate(model,orig,rep); - return rep; -} - -/* bind/construct representative of an internal cluster of a model graph */ -static rep_t model_clust(Agraph_t *model, Agraph_t *origclust) -{ - rep_t rep; - vpath_t *path; - - rep = association(model,origclust); - if (rep.type) return rep; - - rep.p = path = newpath(model,NILnode,GD_minrank(origclust),NILnode,GD_maxrank(origclust)); - rep.type = SKELETON; - associate(model,origclust,rep); - return rep; -} - -/* helper functions for model_edge */ -static rep_t rep_of_node(Agraph_t *model, Agnode_t *orignode) -{ - rep_t rep; - if (agcontains(GD_usergraph(model),orignode)) - rep = model_intnode(model,orignode); - else - rep = model_extnode(model,orignode); - return rep; -} - -static Agnode_t *bindnode(Agraph_t *model, Agnode_t *orignode) -{ - rep_t rep; - rep = rep_of_node(model,orignode); - switch (rep.type) { - case NODE: case EXTNODE: return (Agnode_t*)(rep.p); - default: return ((vpath_t*)(rep.p))->v[ND_rank(orignode)]; - } -} - -static int leftmost(Agraph_t *model, int r) { return 0; } -static int rightmost(Agraph_t *model, int r) {return GD_rank(model)[r].n - 1;} - -static void flat_edges(Agraph_t *clust) -{ -#ifdef NOTDEF - for (n = agfstnode(clust); n; n = agnxtnode(clust)) { - for (e = agfstedge(root,n); e; e = agnxtedge(root,e,n)) { - } - } - ordered_edges(); -#endif -} - -static void search_component(Agraph_t *g, Agnode_t *n, int c) -{ - Agedge_t *e; - ND_component(n) = c; - for (e = agfstout(g,n); e; e = agnxtout(g,e)) - if (ND_component(aghead(e)) < 0) - search_component(g,aghead(e),c); - for (e = agfstin(g,n); e; e = agnxtin(g,e)) - if (ND_component(agtail(e)) < 0) - search_component(g,agtail(e),c); -} - -static int ND_comp_cmpf(const void *arg0, const void *arg1) -{ - return ND_component(*(Agnode_t**)arg1) - ND_component(*(Agnode_t**)arg0); -} - -static component_t build_components(Agraph_t *g, boolean down) -{ - component_t rv; - node_t *n; - int r, rootcnt, compcnt, deg; - - for (n = agfstnode(g); n; n = agnxtnode(g,n)) - ND_component(n) = -1; /* initialize to unknown component */ - - compcnt = 0; rootcnt = 0; - for (n = agfstnode(g); n; n = agnxtnode(g,n)) { - /* set priority for subsequent BFS to install nodes, and record roots */ - if (down) deg = ND_indeg(n); - else deg = ND_outdeg(n); - ND_priority(n) = deg; - if (deg == 0) rootcnt++; - /* count and mark components */ - if (ND_component(n) < 0) - search_component(g,n,compcnt++); - } - - rv.n = compcnt; - rv.r = rootcnt; - rv.root = N_NEW(rv.r,Agnode_t*); - r = 0; - /* install roots in root list */ - for (n = agfstnode(g); n; n = agnxtnode(g,n)) - if (ND_priority(n) == 0) rv.root[r++] = n; - /* sort root list so components are contiguous */ - qsort(rv.root,rv.n,sizeof(node_t*),ND_comp_cmpf); - return rv; -} - -static void install(Agraph_t *g, Agnode_t *n) -{ - int rank; - rank_t *r; - - rank = ND_rank(n); - r = &GD_rank(g)[rank]; - r->v[r->n] = n; - ND_order(n) = r->n++; -} - -/* - populates rank lists of g. there are some key details: - 1) the input graph ordering must be respected (in left to right initialization) - 2) connected components are separated and marked with indices - 3) series-parallel graphs (includes trees, obviously) must not have crossings -*/ -static void build_ranks(Agraph_t *ug, boolean down) -{ - queue *q; - component_t c; - int r; - Agnode_t *n; - Agedge_t *e; - Agraph_t *g; - - g = GD_model(ug); - c = build_components(g, down); - - /* process each each component */ - q = new_queue(agnnodes(g)+1); - for (r = 0; r < c.r; r++) { - enqueue(q,c.root[r]); - if ((r + 1 >= c.r)||(ND_component(c.root[r])!=ND_component(c.root[r+1]))) { - while ((n = dequeue(q))) { - install(g,n); - if (down) { - for (e = agfstout(g,n); e; e = agnxtout(g,e)) - if (--ND_priority(aghead(e)) == 0) enqueue(q,aghead(e)); - } - else { - for (e = agfstin(g,n); e; e = agnxtin(g,e)) - if (--ND_priority(agtail(e)) == 0) enqueue(q,aghead(e)); - } - } - } - } - free_queue(q); -} - -/* this predicate indicates if mincross should be run on this cluster */ -static boolean run(Agraph_t *mg) -{ - if (GD_pass(mg) > GD_maxpass(mg)) return FALSE; - if (GD_pass(mg) - GD_lastwin(mg) > GD_mintry(mg)) return FALSE; - GD_pass(mg) = GD_pass(mg) + 1; - return TRUE; -} - -static void set_presortkey(Agnode_t *n) -{ - int key; - vpath_t *skel; - Agraph_t *model, *parmodel; - Agnode_t *orignode, *parnode; - - model = agraphof(n); - parmodel = GD_model(GD_parent(GD_usergraph(model))); - skel = association(parmodel,GD_usergraph(model)).p; - switch(ND_type(n)) { - case EXTNODE: - orignode = association(model,n).p; - parnode = association(parmodel,orignode).p; - if ((skel->low <= ND_rank(n)) && (ND_rank(n) <= skel->high)) { - int r = ND_rank(n); - if (ND_order(parnode) < ND_order(skel->v[r])) - key = ND_order(GD_rank(model)[r].v[leftmost(model,ND_rank(n))]) - - (ND_order(skel->v[ND_rank(n)]) - ND_order(parnode)); - break; - } - else { - key = ND_order(parnode); - } - break; - default: - key = ND_order(n); - break; - } - ND_sortweight(n) = key; - ND_sortweight_defined(n) = TRUE; -} - -/* helper function */ -static int presort_cmpf(const void *arg0, const void *arg1) -{ - return ND_sortweight(*(Agnode_t**)arg1) - ND_sortweight(*(Agnode_t**)arg0); -} - -/* - * sort the nodes of a subgraph so EXTNODEs are adjusted - * according to the parent cluster before the main mincross - * phase runs. - */ -static void presort(Agraph_t *ug) -{ - int r; - int i; - Agraph_t *mg; - - if (ug == ug->root) return; - mg = GD_model(ug); - for (r = GD_minrank(mg); r <= GD_maxrank(mg); r++) { - for (i = leftmost(mg,r); i < rightmost(mg,r); i++) - set_presortkey(GD_rank(mg)[r].v[i]); - qsort(GD_rank(mg)[r].v,GD_rank(mg)[r].n,sizeof(Agnode_t*),presort_cmpf); - for (i = leftmost(mg,r); i < rightmost(mg,r); i++) - ND_order(GD_rank(mg)[r].v[i]) = i; - } -} - -/* sets ports that represent connections to subclusters */ -static void subclustports(Agraph_t *ug) -{ - Agraph_t *model, *clustmodel; - Agnode_t *x; - Agedge_t *e; - vpath_t *p; - repkey_t *ent; - Dict_t *d; - double frac; - - /* walk all the paths */ - model = GD_model(ug); - d = repdict(model); - for (ent = dtfirst(d); ent; ent = dtnext(d,ent)) { - if (ent->val.type != PATH) continue; - p = ent->val.p; - if ((ND_type(p->v[p->low])) == SKELETON) { - x = p->v[p->low]; - clustmodel = GD_model(ND_cluster(x)); - frac = (ND_order(x) + 1) / GD_rank(clustmodel)[ND_rank(x)].n; - e = p->e[p->low]; - ED_tailport(e).p.x = 2 * PORTRANGE * (frac - 0.5) + p->avgtailport; - } - if ((ND_type(p->v[p->high])) == SKELETON) { - x = p->v[p->high]; - clustmodel = GD_model(ND_cluster(x)); - frac = (ND_order(x) + 1) / GD_rank(clustmodel)[ND_rank(x)].n; - e = p->e[p->high-1]; - ED_headport(e).p.x = 2 * PORTRANGE * (frac - 0.5) + p->avgheadport; - } - } -} - -static void mincross_clust(Agraph_t *ug) -{ - Agraph_t *g; - g = GD_model(ug); - if (run(g)) { - presort(ug); /* move the external nodes */ - subclustports(ug); - do { - mincross_sweep(g,GD_pass(g)%2,GD_pass(g)%4<2); - } while (run(g)); - transpose_sweep(g,TRUE); - restorebest(g); - } -} - -static void globalopt(Agraph_t *root) -{ - Agraph_t *glob; - - glob = globalize(root); - fprintf(stderr,"%s: %d crossings\n",agnameof(root),crossings(glob)); -} - -/* this assumes one level per node - no mega-nodes */ -static void apply_model(Agraph_t *ug) -{ - Agnode_t *un; - rep_t rep; - for (un = agfstnode(ug); un; un = agnxtnode(ug,un)) { - rep = association(GD_globalgraph(ug),un); - switch (rep.type) { - case NODE: - ND_order(un) = ND_order((Agnode_t*)(rep.p)); - break; - case TALLNODE: - ND_order(un) = ND_order(((vpath_t*)rep.p)->v[0]); - break; - default: - abort(); - break; - } - } -} - -/* this is a first cut at a top-level planner. it's lame. */ -static void rec_cluster_run(Agraph_t *ug) -{ - Agraph_t *subg; - - if (is_a_cluster(ug)) mincross_clust(ug); - for (subg = agfstsubg(ug); subg; subg = agnxtsubg(subg)) - rec_cluster_run(subg); - if (is_a_cluster(ug)) mincross_clust(ug); -} - -/* this is the top level mincross entry point */ -void dot_mincross(Agraph_t *user) -{ - rec_cluster_init(user); - rec_cluster_run(user); - globalopt(user); - apply_model(user); -} - -static void invalidate(Agraph_t *g, int rank) -{ - if (rank > GD_minrank(g)) GD_rank(g)[rank-1].crossing_cache.valid = FALSE; - if (rank > GD_minrank(g)) GD_rank(g)[rank-1].candidate = TRUE; - if (rank < GD_maxrank(g)) GD_rank(g)[rank+1].candidate = TRUE; -} - -/* swaps two nodes in the same level */ -static void exchange(Agraph_t *g, Agnode_t *u, Agnode_t *v) -{ - rank_t *r; - int ui,vi,rank; - - assert(ND_rank(u) == ND_rank(v)); - rank = ND_rank(u); - r = &GD_rank(g)[rank]; - ui = ND_order(u); - vi = ND_order(v); - ND_order(v) = ui; - ND_order(u) = vi; - r->v[ND_order(u)] = u; - r->v[ND_order(v)] = v; - r->crossing_cache.valid = FALSE; - r->changed = TRUE; - r->candidate = TRUE; /* old dot had this. i have qualms. sn */ - invalidate(g,rank); -} - -int transpose_onerank(Agraph_t* g, int r, boolean reverse) -{ - int i,c0,c1,rv; - node_t *v,*w; - - rv = 0; - GD_rank(g)[r].candidate = FALSE; - for (i = leftmost(g,r); i < rightmost(g,r); i++) { - v = GD_rank(g)[r].v[i]; - w = GD_rank(g)[r].v[i+1]; - assert (ND_order(v) < ND_order(w)); - if (left2right(g,v,w)) continue; - c0 = c1 = 0; - if (r > GD_minrank(g)) { - c0 += in_cross(v,w); - c1 += in_cross(w,v); - } - if (r < GD_maxrank(g)) { - c0 += out_cross(v,w); - c1 += out_cross(w,v); - } - if ((c1 < c0) || ((c0 > 0) && reverse && (c1 == c0))) { - exchange(g,v,w); - rv += (c0 - c1); - } - } - return rv; -} - -static void transpose_sweep(Agraph_t* g, int reverse) -{ - int r,delta; - - for (r = GD_minrank(g); r <= GD_maxrank(g); r++) - GD_rank(g)[r].candidate = TRUE; - do { - delta = 0; - for (r = GD_minrank(g); r <= GD_maxrank(g); r++) - if (GD_rank(g)[r].candidate) delta += transpose_onerank(g,r,reverse); - } - while (delta >= 1); - /* while (delta > crossings(g)*(1.0 - Convergence));*/ -} - -static void mincross_sweep(Agraph_t* g, int dir, boolean reverse) -{ - int r,other,low,high,first,last; - int hasfixed; - - low = GD_minrank(g); - high = GD_maxrank(g); - if (dir == 0) return; - if (dir > 0) { first = low + 1; last = high; dir = 1;} /* down */ - else { first = high - 1; last = low; dir = -1;} /* up */ - - for (r = first; r != last + dir; r += dir) { - other = r - dir; - hasfixed = medians(g,r,other); - reorder(g,r,reverse,hasfixed); - } - transpose_sweep(g,NOT(reverse)); - savebest(g); -} - - -static int left2right(Agraph_t *g, node_t *v, node_t *w) -{ - int rv; - -#ifdef NOTDEF - adjmatrix_t *M; - M = GD_rank(g)[ND_rank(v)].flat; - if (M == NULL) rv = FALSE; - else { - if (GD_flip(g)) {node_t *t = v; v = w; w = t;} - rv = ELT(M,flatindex(v),flatindex(w)); - } -#else - rv = FALSE; -#endif - return rv; -} - -static void build_flat_graphs(Agraph_t *g) -{ -} - -static int out_cross(node_t *v, node_t *w) -{ - register edge_t *e1,*e2; - register int inv, cross = 0,t; - - for (e2 = agfstout(agraphof(w),w); e2; e2 = agnxtout(agraphof(w),e2)) { - register int cnt = ED_xpenalty(e2); - inv = ND_order(aghead(e2)); - for (e1 = agfstout(agraphof(v),v); e1; e1 = agnxtout(agraphof(v),e1)) { - t = ND_order(aghead(e1)) - inv; - if ((t > 0) || ((t == 0) && (ED_headport(e1).p.x > ED_headport(e2).p.x))) - cross += ED_xpenalty(e1) * cnt; - } - } - return cross; -} - -static int in_cross(node_t *v,node_t *w) -{ - register edge_t *e1,*e2; - register int inv, cross = 0, t; - - for (e2 = agfstin(agraphof(w),w); e2; e2 = agnxtin(agraphof(w),e2)) { - register int cnt = ED_xpenalty(e2); - inv = ND_order(agtail(e2)); - for (e1 = agfstin(agraphof(v),v); e1; e1 = agnxtin(agraphof(v),e1)) { - t = ND_order(agtail(e1)) - inv; - if ((t > 0) || ((t == 0) && (ED_tailport(e1).p.x > ED_tailport(e2).p.x))) - cross += ED_xpenalty(e1) * cnt; - } - } - return cross; -} - -static int int_cmpf(const void *arg0, const void *arg1) -{ - return *(int*)arg1 - *(int*)arg0; -} - -/* 8 is the number of bits in port.order, an unsigned char */ -#define VAL(node,port) ((ND_order(node) << 8) + (port).order) - -/* - * defines ND_sortweight of each node in r0 w.r.t. r1 - * returns... - */ -static boolean medians(Agraph_t *g, int r0, int r1) -{ - static int *list; - static int list_extent; - int i,j,lm,rm,lspan,rspan; - node_t *n,**v; - edge_t *e; - boolean hasfixed = FALSE; - - if (list_extent < GD_maxinoutdeg(g->root)) { - list_extent = GD_maxinoutdeg(g->root); - if (!list) list = realloc(list,sizeof(list[0])*list_extent); - else list = realloc(list,sizeof(list[0])*list_extent); - } - v = GD_rank(g)[r0].v; - for (i = leftmost(g,r0); i <= rightmost(g,r0); i++) { - n = v[i]; j = 0; - if (r1 > r0) for (e = agfstout(g,n); e; e = agnxtout(g,e)) - {if (ED_xpenalty(e) > 0) list[j++] = VAL(aghead(e),ED_headport(e));} - else for (e = agfstin(g,n); e; e = agnxtin(g,e)) - {if (ED_xpenalty(e) > 0) list[j++] = VAL(agtail(e),ED_tailport(e));} - switch(j) { - case 0: - ND_sortweight(n) = MAXINT; /* no neighbor - median undefined */ - ND_sortweight_defined(n) = FALSE; - break; - case 1: - ND_sortweight(n) = list[0]; - ND_sortweight_defined(n) = TRUE; - break; - case 2: - ND_sortweight(n) = (list[0] + list[1])/2; - ND_sortweight_defined(n) = TRUE; - break; - default: - qsort(list,j,sizeof(int),int_cmpf); - if (j % 2) ND_sortweight(n) = list[j/2]; - else { - /* weighted median */ - rm = j/2; - lm = rm - 1; - rspan = list[j-1] - list[rm]; - lspan = list[lm] - list[0]; - if (lspan == rspan) - ND_sortweight(n) = (list[lm] + list[rm])/2; - else { - int w = list[lm]*rspan + list[rm]*lspan; - ND_sortweight(n) = w / (lspan + rspan); - } - } - ND_sortweight_defined(n) = TRUE; - } - } -#ifdef NOTDEF - /* this code was in the old mincross */ - for (i = 0; i < GD_rank(g)[r0].n; i++) { - n = v[i]; - if ((ND_out(n).size == 0) && (ND_in(n).size == 0)) - hasfixed |= flat_sortweight(n); - } -#endif - return hasfixed; -} - -static void reorder(graph_t *g, int r, boolean reverse, boolean hasfixed) -{ - boolean changed, muststay; - node_t **vlist, **lp, **rp, **ep; - int i; - - changed = FALSE; - vlist = GD_rank(g)[r].v; - ep = &vlist[rightmost(g,r)]; - - for (i = leftmost(g,r); i <= rightmost(g,r); i++) { - lp = &vlist[leftmost(g,r)]; - /* find leftmost node that can be compared */ - while ((lp < ep) && (!ND_sortweight_defined(*lp))) lp++; - if (lp >= ep) break; - /* find the node that can be compared */ - muststay = FALSE; - for (rp = lp + 1; rp < ep; rp++) { - if (left2right(g,*lp,*rp)) { muststay = TRUE; break; } - if (ND_sortweight_defined(*rp)) break; /* weight defined; it's comparable */ - } - if (rp >= ep) break; - if (muststay == FALSE) { - register int p1 = ND_sortweight(*lp); - register int p2 = ND_sortweight(*rp); - if ((p1 > p2) || ((p1 == p2) && (reverse))) { - exchange(g,*lp,*rp); - changed = TRUE; - } - } - lp = rp; - if ((hasfixed == FALSE) && (reverse == FALSE)) ep--; - } - - if (changed) { - GD_rank(g)[r].changed = TRUE; - GD_rank(g)[r].crossing_cache.valid = FALSE; - if (r > 0) GD_rank(g)[r-1].crossing_cache.valid = FALSE; - if (r + 1 > GD_rank(g)[r+1].n) GD_rank(g)[r-1].crossing_cache.valid = FALSE; - } -} - -static void savebest(graph_t *g) -{ - int nc; - Agnode_t *n; - - nc = crossings(g); - if (nc < GD_bestcrossings(g)) { - for (n = agfstnode(g); n; n = agnxtnode(g,n)) - ND_saveorder(n) = ND_order(n); - GD_bestcrossings(g) = nc; - GD_lastwin(g) = GD_pass(g); - } -} - -static int ND_order_cmpf(const void *arg0, const void *arg1) -{ - return ND_order(*(Agnode_t**)arg1) - ND_order(*(Agnode_t**)arg0); -} - -static void restorebest(graph_t *g) -{ - Agnode_t *n; - int i; - - for (i = GD_minrank(g); i <= GD_maxrank(g); i++) - GD_rank(g)[i].changed = FALSE; - for (n = agfstnode(g); n; n = agnxtnode(g,n)) { - if (ND_order(n) != ND_saveorder(n)) { - invalidate(g,ND_rank(n)); - GD_rank(g)[i].changed = TRUE; - ND_order(n) = ND_saveorder(n); - } - } - for (i = GD_minrank(g); i <= GD_maxrank(g); i++) { - if (GD_rank(g)[i].changed) - qsort(GD_rank(g)[i].v,GD_rank(g)[i].n,sizeof(Agnode_t*),ND_order_cmpf); - } -} - -static int crossings(graph_t *g) -{ - int i, rv; - - rv = 0; - for (i = GD_minrank(g); i < GD_maxrank(g); i++) { - rv += crossings_below(g,i); - } - return rv; -} - -/* support function for globalize. merge two external edge vnode vectors. - * generally, we will prefer the vnode from the lowest (closest to a leaf) - * cluster, but there can be ties so we work from both ends of the vector - * to get symmetry. - */ -static void mergevec(Agnode_t **v0, Agnode_t **v1, int low, int high) -{ - int i,j; - - i = low; - j = high; - while (i <= j) { - v0[i] = choosenode(v0[i],v1[i]); - v0[j] = choosenode(v1[j],v0[j]); - i++; - j--; - } -} - -/* see above. fst has to win ties. */ -static Agnode_t *choosenode(Agnode_t *fst, Agnode_t *snd) -{ - if (GD_level(agraphof(fst)) <= GD_level(agraphof(snd))) return fst; - return snd; -} - -/* get the vnodes of an edge to an EXTNODE but where the - * edge 'leaves' the cluster, ascend to its parent. - * I am not sure this is really necessary or if it would - * suffice to just take the vpath of the edge. - */ -static Agnode_t **peel(Agraph_t *model, vpath_t *path) -{ - Agnode_t **rv, *v; - Agraph_t *pmodel; - int r; - repkey_t repkey; - Agedge_t *origedge; - vpath_t *parpath; - - rv = nodearray(path->low, path->high); - for (r = path->low; r <= path->high; r++) { - v = path->v[r]; - if (inrange(GD_minrank(model),r,GD_maxrank(model))) rv[r] = v; - else { - pmodel = GD_parent(model); - while (!inrange(GD_minrank(pmodel),r,GD_maxrank(model)) ) - model = GD_parent(model); - /* we seem to be assuming 1-1 relationship between origedges and vpath */ - repkey = invassociation(model,path); - origedge = repkey.key; - parpath = association(pmodel,origedge).p; - v = parpath->v[r]; - rv[r] = v; - } - } - return rv; -} - -/* helper function for globalize */ -static void installglobalobjects(Agraph_t *src, Agraph_t *dst, int r) -{ - int i; - Agnode_t *v, *vx; - Agraph_t *clustmodel; - - for (i = leftmost(src,r); i <= rightmost(src,r); i++) { - v = GD_rank(src)[r].v[i]; - if ((vx = ND_globalobj(v))) - install(dst,vx); - else { - if (ND_type(v) == SKELETON) { - clustmodel = GD_model(ND_cluster(v)); - installglobalobjects(clustmodel,dst,r); - } - else {} /* ignore various external edges */ - } - } -} - -/* build the global (flat) graph of the universe. this is 'flat' -in the sense that there is one data structure for the entire graph -(not 'flat' in the sense of flat edges within the same level.) -*/ -static Agraph_t *globalize(Agraph_t *user) -{ - Agraph_t *glob; - Agnode_t *v; - vpath_t *path, *globpath; - int i, r; - Agnode_t *n; - Agedge_t *e; - rep_t rep; - rep_t globrep, trep, hrep; - Agraph_t *model, *tmodel, *hmodel; - Agnode_t **tvec, **hvec; - - glob = agopen("globalgraph",Agstrictdirected,0); - GD_usergraph(glob) = user; - - /* mark the global objects from various clusters */ - for (n = agfstnode(user); n; n = agnxtnode(user,n)) { - globrep = model_intnode(glob, n); - model = GD_model(ND_cluster(n)); - rep = association(model,n); - switch(rep.type) { - case NODE: - ND_globalobj(v = rep.p) = globrep.p; - break; - case TALLNODE: - path = rep.p; - globpath = globrep.p; - for (i = path->low; i < path->high; i++) - ND_globalobj(path->v[i]) = globpath->v[i]; - break; - default: abort(); - } - } - for (n = agfstnode(user); n; n = agnxtnode(user,n)) { - for (e = agfstout(user,n); e; e = agnxtout(user,e)) { - globrep = model_edge(glob,e); - tmodel = GD_model(ND_cluster(agtail(e))); - hmodel = GD_model(ND_cluster(aghead(e))); - if (tmodel == hmodel) { /* easy case */ - rep = association(tmodel,e); - assert(rep.type == PATH); - path = rep.p; - globpath = globrep.p; - for (i = path->low; i < path->high; i++) - ND_globalobj(path->v[i]) = globpath->v[i]; - } - else { - trep = association(tmodel,e); - tvec = peel(tmodel,trep.p); - hrep = association(hmodel,e); - hvec = peel(hmodel,hrep.p); - path = (vpath_t*)(trep.p); - mergevec(tvec,hvec,path->low,path->high); - globpath = globrep.p; - for (i = path->low; i <= path->high; i++) - ND_globalobj(tvec[i]) = globpath->v[i]; - freearray(tvec,path->low,sizeof(tvec[0])); - freearray(hvec,path->low,sizeof(hvec[0])); - } - } - } - - cluster_extents(glob); - cluster_rankstorage(glob); - - /* install new representative objects */ - for (r = GD_minrank(glob); r <= GD_maxrank(glob); r++) - installglobalobjects(GD_model(user),glob,r); - GD_globalgraph(user) = glob; - return glob; -} - -static void countup(Agraph_t *g, rank_t *globr) -{ - Agnode_t *n; - Agedge_t *e; - int r0, r1, low, high, i; - - for (n = agfstnode(g); n; n = agnxtnode(g,n)) { - for (i = 0; i < ND_ranksize(n); i++) - globr[ND_rank(n)+i].n += 1; - for (e = agfstout(g,n); e; e = agnxtout(g,e)) { - r0 = ND_rank(agtail(e)); - r1 = ND_rank(aghead(e)); - low = MIN(r0,r1); - high = MAX(r0,r1); - for (i = low + 1; i < high; i++) - globr[i].n += 1; - } - } -} - -/* --------- */ - -static void rec_model_subclusts(Agraph_t *model, Agraph_t *user) -{ - Agraph_t *subg; - - if (is_a_cluster(user)) - (void) model_clust(model,user); - /* note there can be non-cluster subgraphs that contain lower clusters */ - for (subg = agfstsubg(user); subg; subg = agnxtsubg(subg)) - rec_model_subclusts(model,subg); -} - -static void cluster_contents(Agraph_t *ug) -{ - Agraph_t *mg, *root, *subg; - char *name; - Agnode_t *n; - Agedge_t *e; - - assert(is_a_cluster(ug)); - assert(GD_model(ug) == 0); - - name = malloc(strlen(agnameof(ug))+10); - sprintf(name,"model_%s",agnameof(ug)); - GD_model(ug) = mg = agopen(name,Agstrictdirected,0); - free(name); - GD_usergraph(mg) = ug; - GD_level(mg) = GD_level(ug); - - /* install internal nodes */ - for (n = agfstnode(ug); n; n = agnxtnode(ug,n)) { - if (ND_cluster(n) == ug) - model_intnode(mg,n); - } - - /* install cluster skeletons */ - for (subg = agfstsubg(ug); subg; subg = agnxtsubg(subg)) - rec_model_subclusts(mg,subg); - - /* install external edge endpoints */ - root = ug->root; - for (n = agfstnode(ug); n; n = agnxtnode(ug,n)) { - for (e = agfstout(root,n); e; e = agnxtout(root,e)) { - if (!agcontains(ug,agtail(e))) - model_extnode(mg,agtail(e)); - if (!agcontains(ug,aghead(e))) - model_extnode(mg,aghead(e)); - } - } - - /* install edges */ - for (n = agfstnode(ug); n; n = agnxtnode(ug,n)) { - for (e = agfstout(root,n); e; e = agnxtout(root,e)) { - model_edge(mg,e); /* amazing if this is all it takes */ - } - /* also need to scan in-edges not seen above */ - for (e = agfstin(root,n); e; e = agnxtin(root,e)) { - if (!agcontains(ug,agtail(e))) - model_edge(mg,e); - } - } -} - -static void cluster_init(Agraph_t *ug) -{ - cluster_contents(ug); - cluster_ranksetup(ug); - flat_edges(ug); - build_ranks(ug,TRUE); -} - -static void rec_cluster_init(Agraph_t *ug) -{ - Agraph_t *subg; - - if (is_a_cluster(ug)) cluster_init(ug); - for (subg = agfstsubg(ug); subg; subg = agnxtsubg(subg)) - rec_cluster_init(subg); -} - -#ifdef NOTDEF -/* a given edge can have several other edges (forward or backward) - between the same endpoints. here, we choose one of these to be - the canonical representative of those edges. */ -static Agedge_t* canonical_edge(Agedge_t* e) -{ - Agraph_t *g; - Agedge_t *canon; - - g = agraphof(e); - if (ND_rank(aghead(e)) > ND_rank(agtail(e))) - canon = agfindedge(g,agtail(e),aghead(e)); - else { - if - } -} -#endif - -static void cluster_extents(Agraph_t *g) -{ - Agnode_t *n; - Agedge_t *e; - short indeg, outdeg; - - /* find minrank, maxrank, in/out/max node degrees */ - n = agfstnode(g); - GD_minrank(g) = GD_maxrank(g) = ND_rank(n); - GD_maxinoutdeg(g) = 0; - for (n = agfstnode(g); n; n = agnxtnode(g,n)) { - if (GD_maxrank(g) < ND_rank(n)) GD_maxrank(g) = ND_rank(n); - if (GD_minrank(g) > ND_rank(n)) GD_minrank(g) = ND_rank(n); - if (ND_indeg(n) == 0) { - indeg = 0; for (e = agfstin(g,n); e; e = agnxtin(g,e)) indeg++; - ND_indeg(n) = indeg; - } - if (ND_outdeg(n) == 0) { - outdeg = 0; for (e = agfstout(g,n); e; e = agnxtout(g,e)) outdeg++; - ND_outdeg(n) = outdeg; - } - GD_maxinoutdeg(g) = MAX(GD_maxinoutdeg(g),MAX(indeg,outdeg)); - } -} - -/* utility function to allocate GD_rank and GD_rank(g)[r].v */ -static void cluster_rankstorage(Agraph_t *g) /* g is a model graph */ -{ - Agnode_t *n; - int minr,maxr,r,*ranksize; - - /* initialize storage for ranks in the model; nodes are installed later */ - minr = GD_minrank(g); - maxr = GD_maxrank(g); - ranksize = intarray(minr,maxr); - for (n = agfstnode(g); n; n = agnxtnode(g,n)) - ranksize[ND_rank(n)]++; - GD_rank(g) = T_array(minr,maxr,sizeof(rank_t)); - for (r = minr; r <= maxr; r++) - GD_rank(g)[r].v = N_NEW(ranksize[r]+1,Agnode_t*); /* NIL at end */ - freearray(ranksize,minr,sizeof(ranksize[0])); -} - -/* set GD_minrank, GD_maxrank, ND_indeg, ND_outdeg, GD_maxinoutdeg - * allocate GD_rank and GD_rank(g)[r].v - */ -static void cluster_ranksetup(Agraph_t *ug) -{ - Agraph_t *g; - - g = GD_model(ug); - if (agfstnode(g) == NILnode) return; - - cluster_extents(g); - cluster_rankstorage(g); - - /* set up mincross running parameters */ - GD_pass(g) = 0; - GD_lastwin(g) = 0; - GD_mintry(g) = gvgetint(ug,"minpass",24); - GD_maxpass(g) = gvgetint(ug,"maxpass",1024); - GD_bestcrossings(g) = MAXINT; -} - -static int printfn(Dict_t *dict, void *arg, void *data) -{ - repkey_t *rk = arg; - printf("%lx=>%d,%lx\n",(uint64_t)(rk->key),rk->val.type,(uint64_t)(rk->val.p)); - return 0; -} -static void dumpdict(Agraph_t *model) -{ - dtwalk(repdict(model),printfn, 0); -} diff --git a/lib/dotgen2/minc.h b/lib/dotgen2/minc.h deleted file mode 100644 index 90a7d2ac4..000000000 --- a/lib/dotgen2/minc.h +++ /dev/null @@ -1,130 +0,0 @@ -/* $Id$Revision: */ -/* vim:set shiftwidth=4 ts=8: */ - -/************************************************************************* - * Copyright (c) 2011 AT&T Intellectual Property - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: See CVS logs. Details at http://www.graphviz.org/ - *************************************************************************/ - - -#ifndef MINC_H -#define MINC_H - -typedef enum {mcGrVer,mcGrHor,mcBoth} mcGroupAlign_t; -typedef enum {mcGrLoose,mcGrStrict} mcGroup_t; -typedef enum {mcCountLower,mcCountHigher,mcCountAll} mcCountMethod; - -typedef struct mcNode mcNode; -typedef struct { - mcGroupAlign_t alignType; - mcGroup_t type; - int cnt; - Dt_t* nodes; -#if 0 - Dt_t* children; -#endif -} mcGroup; - -typedef struct { - Agedge_t* e; /*pointer to cgraph edge*/ - mcNode* lowerN; - mcNode* higherN; - port lowerPort; - port higherPort; - float penalty; -} mcEdge; - -struct mcNode { - float order; - float groupOrder; - int rank; - int isLeader; - mcNode* leader; - float prevOrder[3]; - float x; - float y; - float w; /*weight*/ - mcEdge** low_edgs; - mcEdge** high_edgs; - int high_edgs_cnt; - int low_edgs_cnt; - Agnode_t* node; - mcGroup* group; - void* level; - int flag; /*general purpose flag*/ - char* name; -}; - -typedef struct { - int rank; - mcNode** nodes; - int nodecnt; - int lowerEdgeCount; - int higherEdgeCount; - int lowCnt; /*cached crossing counts*/ - int highCnt; /*cached crossing counts*/ - int candidate; -} mcLevel; - -typedef struct { - mcLevel** lvls; - int lvl_cnt; - int crossCnt; - Agraph_t* g; -} mcGraph; - -typedef struct { - Agrec_t hdr; - node_t *set; /* for union-find */ - graph_t *cluster; /* lowest containing cluster */ - union { - node_t *v; - edge_t *e; - graph_t *g; - } rep; - Agnode_t* orig; - int type; - int rank; - int order; - float orderr; - mcNode* mcn; - graph_t *highCluster; /* highest containing cluster */ - int inBucket; -} mcnodeinfo_t; - -#define MND_FIELD(g,field) (((mcnodeinfo_t*)((g)->base.data))->field) -#define MND_orig(n) MND_FIELD(n,orig) -#define MND_type(n) MND_FIELD(n,type) -#define MND_rank(n) MND_FIELD(n,rank) -#define MND_order(n) MND_FIELD(n,order) -#define MND_orderr(n) MND_FIELD(n,orderr) -#define MND_mcn(n) MND_FIELD(n,mcn) -#define MND_inBucket(n) MND_FIELD(n,inBucket) -#define MND_highCluster(n) MND_FIELD(n,highCluster) - -typedef struct { - Agrec_t hdr; - Agedge_t* orig; - port tail_port, head_port; - int deleteFlag; - int cutval; - int type; -} mcedgeinfo_t; - -#define MED_FIELD(g,field) (((mcedgeinfo_t*)((g)->base.data))->field) -#define MED_type(n) MED_FIELD(n,type) -#define MED_orig(n) MED_FIELD(n,orig) -#define MED_deleteFlag(n) MED_FIELD(n,deleteFlag) -#define MED_head_port(n) MED_FIELD(n,head_port) -#define MED_tail_port(n) MED_FIELD(n,tail_port) - -extern Agraph_t* mkMCGraph (Agraph_t*); -extern Agnode_t *mkMCNode (Agraph_t * g, int type, char *name); -extern Agedge_t* mkMCEdge (Agraph_t* g, Agnode_t* tail, Agnode_t* head, char*, int type, Agedge_t* orige); - -#endif diff --git a/lib/dotgen2/minc2.c b/lib/dotgen2/minc2.c deleted file mode 100644 index 66094f3f2..000000000 --- a/lib/dotgen2/minc2.c +++ /dev/null @@ -1,1680 +0,0 @@ -/* $Id$Revision: */ -/* vim:set shiftwidth=4 ts=8: */ - -/************************************************************************* - * Copyright (c) 2011 AT&T Intellectual Property - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: See CVS logs. Details at http://www.graphviz.org/ - *************************************************************************/ - -#include "dot2.h" -#include "utils.h" -#include "minc.h" -#include "groups.h" - -#define MARK(v) (ND_mark(v)) - - -/* #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 void _transpose(mcGraph * mcG, int reverse); -static void fast_node(graph_t * g, Agnode_t * n); - -static int MAGIC_NUMBER = 4; - -static int higher_cross(mcNode * v, mcNode * w) -{ - mcEdge *e; - mcEdge *e2; - double x1, xx1; - double 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 + (int)e->penalty; - else - cnt = cnt + (int)e2->penalty; - } - } - } - return cnt; -} - -static int lower_cross(mcNode * v, mcNode * w) -{ - - mcEdge *e; - mcEdge *e2; - double x1, xx1; - double 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 +(int) e->penalty; - else - cnt = cnt + (int)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++; -#ifdef _DEBUG - printf ("%s\n",agnameof(n)); - -#endif - -} - -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; -} - -void decompose(graph_t * g, int pass); -static mcGraph *createMatrixIn(Agraph_t * g) -{ -#define ARRAY_SZ 37 - Agedge_t *e; - Agnode_t *v; - Agnode_t *v0; - nodequeue *b; - Agnode_t *head; - mcGraph *mcG; - int id = 0; - char* nodes[]= -{ - "d0", -"e1", -"e2", -"f0", -"f1", -"g0", -"a1", -"b1", -"b2", -"c2", -"c5", -"c8", -"c3", -"c4", -"c6", -"c7", -"d2", -"d4", -"d6", -"d5", -"e3", -"e4", -"e5", -"e6", -"e8", -"e7", -"f4", -"f2", -"f3", -"f5", -"a0", -"b0", -"c0", -"c1", -"d1", -"d3", -"e0" }; - GD_nlist(g)=(node_t*)malloc(sizeof(node_t)*agnnodes(g)); - GD_nlist(g)=NULL; - for (v = agfstnode(g); v; v = agnxtnode(g, v)) - { - printf ("%s\n",agnameof(v)); - fast_node(g,v); - } - decompose(g,1); - for (v = GD_nlist(g); v; v = ND_next(v)) - { - printf ("_%s\n",agnameof(v)); - } - b = new_queue(agnnodes(g)); - mcG = newMcGraph(g); - - - for (v = GD_nlist(g); v; v = ND_next(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; - } - } - } - - } - - - } - - -/* 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; - } - } - } - - } - } - -*/ -/* for (id=0;id < ARRAY_SZ; id++) - { - install_node(nodeByName(g,nodes[id]),mcG); - }*/ - free_queue (b); - for (v = agfstnode(g); v; v = agnxtnode(g, v)) - addAdjEdges(v); - id = countAllX(mcG); -#ifdef DEBUG - #ifdef _WIN32 - dumpGraph (mcG, "c:/temp/before.gv"); - #else - dumpGraph (mcG, "before.gv"); - #endif -#endif - _transpose(mcG, 0); -// transposeAllL2H(mcG); - - -#ifdef DEBUG - #ifdef _WIN32 - dumpGraph (mcG, "c:/temp/after_trans.gv"); - #else - dumpGraph (mcG, "after_trans.gv"); - #endif -#endif - - - 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] = (int)e->lowerN->order; - else - P[id] = (int)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 = (float)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 = (float)nodeMedian(n, lowToHigh); - order2 = (float)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]; - } - } - for (idx = 0; idx < mcg->lvl_cnt; idx++) { - l = mcg->lvls[idx]; - reOrderLevel(l); - normalizeLevel(l); - } -} - -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); - 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); - } - 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); - } - - dumpGraph (mcG, "c:/temp/before_final_trans.gv"); - _transpose(mcG,0); - fprintf(stderr,"after transpose final count %d...\n", countAllX(mcG)); -#ifdef DEBUG_CAIRO - drawMatrix(mcG, "after.png", "after mincross"); -#endif -#ifdef DEBUG - dumpGraph (mcG, "c:/temp/after.gv"); -#endif -} - -Agraph_t *dot2_mincross (Agraph_t * srcGraph) -{ - mcGraph *mcG; - Agraph_t *g = mkMCGraph (srcGraph); - 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 -#include -#include - -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 - -static void exchange(mcNode* v, mcNode* w) -{ - - int vi, wi; - vi=(int)v->order; - wi=(int)w->order; - v->order=(float)wi; - w->order=(float)vi; -// reOrderLevel((mcLevel*)v->level); - -} - -static int in_cross(mcNode* v, mcNode* w) -{ - register mcEdge* e1, *e2; - register int inv, cross = 0, t; - int id,id2; - - for (id=0;id < w->low_edgs_cnt; id++) - { - register int cnt; - e2=w->low_edgs[id]; - cnt=(int)e2->penalty; - inv =(int) e2->lowerN->order; - for (id2=0;id2 < v->low_edgs_cnt; id2++) - { - e1=v->low_edgs[id2]; - t =(int)e1->lowerN->order-inv; - if ((t > 0) - || ((t == 0) - && ( ED_tail_port(e1->lowerN->node).p.x > ED_tail_port(e2->lowerN->node).p.x))) - - cross += (int)e1->penalty * cnt; - } - } - return cross; -} -static int out_cross(mcNode* v, mcNode* w) -{ - register mcEdge* e1, *e2; - register int inv, cross = 0, t; - int id,id2; - - for (id=0;id < w->high_edgs_cnt; id++) - { - register int cnt; - e2=w->high_edgs[id]; - cnt=(int)e2->penalty; - inv = (int)e2->higherN->order; - for (id2=0;id2 < v->high_edgs_cnt; id2++) - { - e1=v->high_edgs[id2]; - t =(int)e1->higherN->order-inv; - if ((t > 0) - || ((t == 0) - && ( ED_head_port(e1->higherN->node).p.x > ED_head_port(e2->higherN->node).p.x))) - - cross +=(int) e1->penalty * cnt; - } - } - return cross; -} - - - -static int transpose_step(mcGraph* mcG, int r, int reverse) -{ - int i, c0, c1, rv; - mcNode *v,*w; - mcLevel* l= mcG->lvls[r]; - - rv = 0; - l->candidate=FALSE; - - for (i = 0; i nodecnt-1;i++) { - v=l->nodes[i]; - w=l->nodes[i+1]; - assert(v->order < w->order); - /*if (left2right(mcG, v, w)) - continue;*/ - c0 = c1 = 0; - if (r > 0) { - c0 += in_cross(v, w); - c1 += in_cross(w, v); - } - if (mcG->lvl_cnt > (r+1)) - { - c0 += out_cross(v, w); - c1 += out_cross(w, v); - } - if ((c1 < c0) || ((c0 > 0) && reverse && (c1 == c0))) - { - exchange(v, w); - rv += (c0 - c1); - l->candidate=TRUE; - if (r > 0) - mcG->lvls[r-1]->candidate=TRUE; - if (r < mcG->lvl_cnt-1) - mcG->lvls[r+1]->candidate = TRUE; - } - } - reOrderLevel( mcG->lvls[r]); - return rv; -} - - -static void _transpose(mcGraph * mcG, int reverse) -{ - int r, delta; - - for (r = 0; r <= mcG->lvl_cnt-1;r++) - mcG->lvls[r]->candidate= TRUE; - do { - delta = 0; -#ifdef NOTDEF - /* don't run both the upward and downward passes- they cancel. - i tried making it depend on whether an odd or even pass, - but that didn't help. */ - for (r = GD_maxrank(g); r >= GD_minrank(g); r--) - if (GD_rank(g)[r].candidate) - delta += transpose_step(g, r, reverse); -#endif - for (r = 0; r <= mcG->lvl_cnt-1;r++) - { - if (mcG->lvls[r]->candidate) - { - delta += transpose_step(mcG, r, reverse); - } - } - /*} while (delta > ncross(g)*(1.0 - Convergence)); */ - } while (delta >= 1); -} - - - - -static void fast_node(graph_t * g, Agnode_t * n) -{ - ND_next(n) = GD_nlist(g); - if (ND_next(n)) - ND_prev(ND_next(n)) = n; - GD_nlist(g) = n; - ND_prev(n) = NULL; - assert(n != ND_next(n)); -} - diff --git a/lib/dotgen2/minc_utils.c b/lib/dotgen2/minc_utils.c deleted file mode 100644 index c5f20389c..000000000 --- a/lib/dotgen2/minc_utils.c +++ /dev/null @@ -1,166 +0,0 @@ -/* $Id$Revision: */ -/* vim:set shiftwidth=4 ts=8: */ - -/************************************************************************* - * Copyright (c) 2011 AT&T Intellectual Property - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: See CVS logs. Details at http://www.graphviz.org/ - *************************************************************************/ - -#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; - edgepair_t* data; - edgepair_t* ep; - Agraph_t* newg = agopen (agnameof(g), g->desc, 0); - Dt_t* emap = dtopen (&edgepair, Dtoset);; - data = N_NEW(agnedges(g), 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; -} - diff --git a/lib/dotgen2/newdot.h b/lib/dotgen2/newdot.h deleted file mode 100644 index 16072aea1..000000000 --- a/lib/dotgen2/newdot.h +++ /dev/null @@ -1,287 +0,0 @@ -/*********** external interfaces *********/ -#ifdef NOTDEF -#include -#endif -#include -#include -//#include -#include -#include -/* #include */ -#include -#include -#include "radix.h" - -/*********** a few useful types *********/ -typedef unsigned char boolean; -typedef struct {double x, y;} point; -typedef struct {point LL, UR;} box; - -typedef struct Agraph_s graph_t; -typedef struct Agnode_s node_t; -typedef struct Agedge_s edge_t; - -/*********** types needed by graphs *********/ -typedef struct adjmatrix_t { /* for flat edge constraints */ - int nrows,ncols; - char *data; -} adjmatrix_t; -#define ELT(M,i,j) (M->data[((i)*M->ncols)+(j)]) - -typedef struct rank_s { /* describes the contents of a rank */ - node_t **v; /* the vertex list */ - int n; /* its extent */ - - /* for counting edge crossings */ - radixrec_t *edgelist; /* list of out (south) edges */ - int ne; /* extent of this list */ - int *tree, treesize; /* the crossing accumulator tree */ - - adjmatrix_t *flat; /* transitive closure of the left-right constraints */ - - struct crossing_cache_s { - int count; /* crossings between this level and this + 1 */ - boolean valid; - } crossing_cache; - - boolean candidate; /* true if an adjacent level changed */ - boolean changed; -} rank_t; - -typedef struct rep_s { - void *p; /* must always be an Agraph_t*, Agnode_t*, Agedge_t* */ - int type; /* NODE, TALLNODE, PATH, SKELETON, EXTNODE */ -} rep_t; - -typedef struct repkey_s { - void *key; - rep_t val; -} repkey_t; - -typedef struct vpath_s { - int low, high; - node_t **v; /* virtual nodes of path */ - edge_t **e; /* virtual edges of path indexed by tail rank */ - float avgtailport, avgheadport; /* total port offsets */ - float weight; -} vpath_t; - - -/*********** graphs *********/ -typedef struct Agraphinfo_s { - Agrec_t hdr; - struct Agraph_s *parent; /* containing cluster (not parent subgraph) */ - union { - struct Agraph_s *user; /* points from a model graph back to client obj */ - struct Agraph_s *global; /* points from user root graph to global model */ - } graph; - int level; /* cluster nesting level (not node level!) */ - node_t *minrep, *maxrep; /* set leaders for min and max rank */ - boolean has_sourcerank, has_sinkrank; - int minrank,maxrank; - - /* these control mincross */ - struct Agraph_s *graphrep; /* graph that models this cluster for mincross */ - rank_t *rank; - int pass; /* a simple counter */ - int lastwin; /* last pass that was an improvement */ - int mintry; /* limit to losing passes */ - int maxpass; /* limit to total passes */ - int bestcrossings; /* current best solution */ - Dict_t *repdict; - - /* other mincross values */ - int maxinoutdeg; /* maximum of all in and out degrees */ -} Agraphinfo_t; - - -#define GD_FIELD(g,field) (((Agraphinfo_t*)((g)->base.data))->field) -#define GD_parent(g) GD_FIELD(g,parent) -#define GD_level(g) GD_FIELD(g,level) -#define GD_minrep(g) GD_FIELD(g,minrep) -#define GD_maxrep(g) GD_FIELD(g,maxrep) -#define GD_has_sourcerank(g) GD_FIELD(g,has_sourcerank) -#define GD_has_sinkrank(g) GD_FIELD(g,has_sinkrank) -#define GD_model(g) GD_FIELD(g,graphrep) -#define GD_rank(g) GD_FIELD(g,rank) -#define GD_minrank(g) GD_FIELD(g,minrank) -#define GD_maxrank(g) GD_FIELD(g,maxrank) -#define GD_pass(g) GD_FIELD(g,pass) -#define GD_lastwin(g) GD_FIELD(g,lastwin) -#define GD_mintry(g) GD_FIELD(g,mintry) -#define GD_maxpass(g) GD_FIELD(g,maxpass) -#define GD_bestcrossings(g) GD_FIELD(g,bestcrossings) -#define GD_maxinoutdeg(g) GD_FIELD(g,maxinoutdeg) -#define GD_repdict(g) GD_FIELD(g,repdict) -#define GD_usergraph(g) GD_FIELD(g,graph.user) -#define GD_globalgraph(g) GD_FIELD(g,graph.global) - -typedef struct nlist_s { - int size; - node_t **list; -} nlist_t; - -typedef struct elist_s { - int size; - edge_t **list; -} elist_t; - -typedef struct queue { - node_t **store,**limit,**head,**tail; -} queue; - -/*********** nodes *********/ -typedef struct Agnodeinfo_s { - Agrec_t hdr; - int rank; /* network simplex solver */ - graph_t *cluster; /* lowest containing cluster */ - node_t *set; /* for union-find */ - - union { - node_t *v; - edge_t *e; - graph_t *g; - } rep; - int type; - -/* tags for representative (model) objects */ -/* 0 is reserved for undefined */ -#define NODE 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 - - /* for network-simplex */ - elist_t tree_in; - elist_t tree_out; - int priority; - int low,lim; - edge_t *par; - - /* for mincross */ - short indeg, outdeg; - int order; - int saveorder; /* for saving the best solution */ - int component; - int ranksize; /* height as counted in number of levels */ - int sortweight; /* median, barycenter, etc. */ - boolean mark, onstack, sortweight_defined; -} Agnodeinfo_t; - -#define ND_FIELD(n,field) (((Agnodeinfo_t*)((n)->base.data))->field) -#define ND_globalobj(n) ND_FIELD(n,rep.v) -#define ND_rep(n) ND_FIELD(n,rep.v) -#define ND_cluster(n) ND_FIELD(n,cluster) -#define ND_cluster(n) ND_FIELD(n,cluster) -#define ND_type(n) ND_FIELD(n,type) -#define ND_set(n) ND_FIELD(n,set) -#define ND_mark(n) ND_FIELD(n,mark) -#define ND_onstack(n) ND_FIELD(n,onstack) -#define ND_rank(n) ND_FIELD(n,rank) -#define ND_tree_in(n) ND_FIELD(n,tree_in) -#define ND_tree_out(n) ND_FIELD(n,tree_out) -#define ND_priority(n) ND_FIELD(n,priority) -#define ND_low(n) ND_FIELD(n,low) -#define ND_lim(n) ND_FIELD(n,lim) -#define ND_par(n) ND_FIELD(n,par) -#define ND_indeg(n) ND_FIELD(n,indeg) -#define ND_outdeg(n) ND_FIELD(n,outdeg) -#define ND_order(n) ND_FIELD(n,order) -#define ND_saveorder(n) ND_FIELD(n,saveorder) -#define ND_component(n) ND_FIELD(n,component) -#define ND_sortweight(n) ND_FIELD(n,sortweight) -#define ND_sortweight_defined(n) ND_FIELD(n,sortweight_defined) -#define ND_ranksize(n) ND_FIELD(n,ranksize) - -/********** edges **********/ -typedef struct port_s { /* internal edge endpoint specification */ - point p; /* aiming point */ - double theta; /* slope in radians */ - box* bp; /* if not null, points to bbox of - * rectangular area that is port target - */ - boolean constrained,defined; - unsigned char order; /* for mincross (?) */ -} port_t; - -typedef struct Agedgeinfo_s { - Agrec_t hdr; - /* to assign levels */ - float minlen; - float weight; - int tree_index; - int cutval; - - /* to run mincross */ - int xpenalty; /* crossing weight */ - port_t tailport, headport; - - vpath_t *path; - -} Agedgeinfo_t; - -#define ED_FIELD(e,field) (((Agedgeinfo_t*)((e)->base.data))->field) -#define ED_minlen(e) ED_FIELD(e,minlen) -#define ED_weight(e) ED_FIELD(e,weight) -#define ED_tree_index(e) ED_FIELD(e,tree_index) -#define ED_cutval(e) ED_FIELD(e,cutval) -#define ED_xpenalty(e) ED_FIELD(e,xpenalty) -#define ED_tailport(e) ED_FIELD(e,tailport) -#define ED_headport(e) ED_FIELD(e,headport) -#define ED_orig(e) ED_FIELD(e,orig) - - -/********** variable constants **********/ -#define BACKWARD_PENALTY 1000 -#define STRONG_CLUSTER_WEIGHT 1000 -#define VEDGE_PENALTY 1 -#define CEDGE_PENALTY (1<<30)-1 -#define PORTRANGE 1e+6 /* port coordinates cannot be bigger than this */ - - /* xpos phase */ -#define SHORT_FACTOR 1 -#define LONG_FACTOR 2 -#define LONG_END_FACTOR 4 - -/********** useful symbols **********/ -#define MINRANK 1 -#define SOURCERANK 2 -#define MAXRANK 3 -#define SINKRANK 4 -#define SAMERANK 5 -#define NORANK 6 - - - -/********** libgraph extensions **********/ -int mapbool(char *str, int defval); - -#ifndef NIL -#define NIL(t) ((t)0) /* agrees with CDT */ -#endif -#define NILgraph NIL(Agraph_t*) -#define NILnode NIL(Agnode_t*) -#define NILedge NIL(Agedge_t*) - - -/********** useful macros **********/ -#ifndef MAXINT -#define MAXINT (int)(~((int)0) ^ (1 << (sizeof(int)*8-1))) -#endif -#define MAX(a,b) ((a)>=(b)?(a):(b)) -#define MIN(a,b) ((a)<=(b)?(a):(b)) -#define NEW(t) ((t*)zmalloc(sizeof(t))) -#define N_NEW(n,t) ((t*)zmalloc((n)*sizeof(t))) -#define alloc_elist(n,L) do {L.size = 0; L.list = N_NEW(n + 1,edge_t*); } while (0) -#define free_list(L) do {if (L.list) free(L.list);} while (0) -#define ALLOC(size,ptr,type) (ptr? (type*)realloc(ptr,(size)*sizeof(type)):(type*)malloc((size)*sizeof(type))) - - -/********** graphviz entry points **********/ -extern int dot_Verbose; -void rank(graph_t *g, int balance, int maxiter); - -Agraph_t *dot_lca(Agraph_t *c0, Agraph_t *c1); - -#include "au_.h" diff --git a/lib/dotgen2/ns.c b/lib/dotgen2/ns.c deleted file mode 100644 index ed366de7e..000000000 --- a/lib/dotgen2/ns.c +++ /dev/null @@ -1,810 +0,0 @@ -/* $Id$Revision: */ -/* vim:set shiftwidth=4 ts=8: */ - -/************************************************************************* - * Copyright (c) 2011 AT&T Intellectual Property - * All rights reserved. This program and the accompanying materials - * are made available under the terms of the Eclipse Public License v1.0 - * which accompanies this distribution, and is available at - * http://www.eclipse.org/legal/epl-v10.html - * - * Contributors: See CVS logs. Details at http://www.graphviz.org/ - *************************************************************************/ - -/* - * Network Simplex Algorithm for Ranking Nodes of a DAG - */ - -#include "render.h" -#include "arith.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); - -#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; -#define SEARCHSIZE 30 -static elist Tree_edge; -static nlist_t Tree_node; - -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; -} - -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; -} - -static -void init_rank(void) -{ - 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)); - } - } - free_queue(Q); -} - -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; -} - -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_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++; - } - 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; -} - -static edge_t *Enter; -static int Low, Lim, Slack; - -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; - } - } - } 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) -{ - 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)); -} - -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 = 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) -{ - 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 = 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; -} - -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; -} - -static void init_cutvalues(void) -{ - dfs_range(agfstnode(G), NULL, 1); - dfs_cutval(agfstnode(G), NULL); -} - -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 { -#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)); - } -#endif - abort(); - } - } - 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) -{ - 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) -{ - 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. - */ -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); - } - } - } - - 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) -{ - 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) -{ - 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) -{ - return TRUE; /* could be false for slacknodes */ -} - -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; - } - free(nrank); -} - -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_cutvalue(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; - } - return feasible; -} - -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 (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) -{ - 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) -{ - 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) -{ - 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) -{ - 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); - } - } - 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_cutvalue(e); - x_cutval(e); - if (save != ED_cutvalue(e)) - abort(); - } - } -} - -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(); - } - } - 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); -} - -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); - } - } - ND_onstack(n) = FALSE; -} - -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); -} -#endif /* DEBUG */ diff --git a/lib/dotgen2/pos.c b/lib/dotgen2/pos.c deleted file mode 100644 index f40fc06e3..000000000 --- a/lib/dotgen2/pos.c +++ /dev/null @@ -1,68 +0,0 @@ -void dot_position(Agraph_t *model) -{ - make_variables(); - node_separation_constraints(); - cluster_containment_constraints(); - edge_cost_constraints(); -} - -/* g is a model graph */ -static void node_separation_constraints(Agraph_t *g) -{ - rank_t *r; - - - for (i = GD_minrank(g); i <= GD_maxrank(g); i++) { - r = GD_rank(g)[i]; - left = NILnode; - for (j = leftmost(g,r); j <= rightmost(g,r); j++) { - right = r->v[j]; - node_sep(left,right); - right = left; - } - } -} - -/* - * this function has to traverse the subgraph hierarchy from the - * user graph because we flattened out the model subgraphs. - */ -static void cluster_containment_constraints(Agraph_t *upar, Agraph_t *ug) -{ - Agraph_t *container; - - if (is_a_cluster(upar) && is_a_cluster(ug)) - cluster_contain(upar,ug); - container = is_a_cluster(ug)? ug : upar; - for (subg = agfstsub(ug); subg; subg = agnxtsubg(ug,subg)) - cluster_containment_constraints(container,subg); -} - -static void cluster_contain(Agraph_t *u_outer, Agraph_t *u_inner) -{ - Agraph_t *Xg; - int sep; - Agnode_t *outer_left, *outer_right, *inner_left, *inner_right; - - sep = user_cluster_sep(u_inner); - Xg = constraint_graph(u_outer); - outer_left = leftvar(GD_model(u_outer)); - outer_right = rightvar(GD_model(u_outer)); - inner_left = leftvar(GD_model(u_inner)); - inner_right = rightvar(GD_model(u_inner)); - clust_sep_edge(outer_left,inner_left); - clust_sep_edge(inner_right,outer_right); -} - -static void clust_sep_edge(Agraph_t *Xg, Agnode_t *left, Agnode_t *right, int sep) -{ - Agedge_t *e; - - e = agedge(Xg, left, right); - ED_weight(e) = 0; - ED_minlen(e) = sep; -} - -static void edge_cost_constraints() -{ -} diff --git a/lib/dotgen2/queue.c b/lib/dotgen2/queue.c deleted file mode 100644 index 1eda3cadb..000000000 --- a/lib/dotgen2/queue.c +++ /dev/null @@ -1,41 +0,0 @@ -#include "newdot.h" - -/* - * a queue of nodes - */ -queue * -new_queue(int sz) -{ - queue *q = NEW(queue); - - if (sz <= 1) sz = 2; - q->head = q->tail = q->store = N_NEW(sz,node_t*); - q->limit = q->store + sz; - return q; -} - -void -free_queue(queue* q) -{ - free(q->store); - free(q); -} - -void -enqueue(queue* q, node_t* n) -{ - *(q->tail++) = n; - if (q->tail >= q->limit) q->tail = q->store; -} - -node_t * -dequeue(queue* q) -{ - node_t *n; - if (q->head == q->tail) n = NULL; - else { - n = *(q->head++); - if (q->head >= q->limit) q->head = q->store; - } - return n; -} diff --git a/lib/dotgen2/radix.c b/lib/dotgen2/radix.c deleted file mode 100644 index 602bd73ba..000000000 --- a/lib/dotgen2/radix.c +++ /dev/null @@ -1,119 +0,0 @@ -/* -From: Andre Reinald -To: submissive@cubic.org - -I though you might be intersted by some modifications I brought to your -code in order to improve legibility and slightly speed. - -Well, my source is commented and I often wrote 4 lines where you had -only one, but the generated code is smaller and it gives more -opportunity to check intermediate steps while debugging. - -By the way, I did so on a PowerMac with CodeWarrior compiler, so your -source is really portable. -*/ - -/* hacked by north to support a data pointer with each record */ - -#include -#include -#include "radix.h" - -/* complicated expression better fits as macro (or inline in C++) */ -#define ByteOf(x) (((x) >> bitsOffset) & 0xff) - -typedef unsigned long ulong; -typedef radixrec_t rec; - -/* replaced byte with bitsOffset to avoid *8 operation in loop */ -static void radix (short bitsOffset, ulong N, rec *source, rec *dest) -{ -/* suppressed the need for index as it is reported in count */ - ulong count[256]; -/* added temp variables to simplify writing, understanding and compiler optimization job */ -/* most of them will be allocated as registers */ - ulong *cp, c, i, s; - rec *sp, srec; - -/* faster than MemSet */ - cp = count; - for (i = 256; i > 0; --i, ++cp) - *cp = 0; - -/* count occurrences of every byte value */ - sp = source; - for (i = N; i > 0; --i, ++sp) { - cp = count + ByteOf (sp->key); - ++(*cp); - } - -/* transform count into index by summing elements and storing into same array */ - s = 0; - cp = count; - for (i = 256; i > 0; --i, ++cp) { - c = *cp; - *cp = s; - s += c; - } - -/* fill dest with the right values in the right place */ - sp = source; - for (i = N; i > 0; --i, ++sp) { - srec = *sp; - cp = count + ByteOf (srec.key); - dest[*cp] = srec; - ++(*cp); - } -} - -void radix_sort (rec *source, ulong N) -{ -/* allocate heap memory to avoid the need of additional parameter */ - rec *temp = malloc (N * sizeof (rec)); - assert (temp != NULL); - - radix (0, N, source, temp); - radix (8, N, temp, source); - radix (16, N, source, temp); - radix (24, N, temp, source); - - free (temp); -} - -#ifdef MAIN -static void make_random (rec *data, ulong N) -{ - for ( ; N > 0; --N, ++data) { - data->key = rand () | (rand () << 16); - data->data = (void*)((data->key)^0xdeadbeef); - } -} - -static void check_order (rec *data, ulong N) -{ -/* only signal errors if any (should not be) */ - --N; - for ( ; N > 0; --N, ++data) { - assert (data[0].key <= data[1].key); - assert (data->data == (void*)((data->key)^0xdeadbeef)); - } -} - -/* test for big number of elements */ -static void test_radix (ulong N) -{ - rec *data = malloc (N * sizeof (rec)); - assert (data != NULL); - - make_random (data, N); - radix_sort (data, N); - check_order (data, N); - - free (data); -} - -void main (void) -{ - test_radix (10000000); -} -#endif diff --git a/lib/dotgen2/radix.h b/lib/dotgen2/radix.h deleted file mode 100644 index e39fae206..000000000 --- a/lib/dotgen2/radix.h +++ /dev/null @@ -1,6 +0,0 @@ -typedef struct radixrec_s { - unsigned long key; - void *data; -} radixrec_t; - -void radix_sort(radixrec_t *source, unsigned long N); diff --git a/lib/dotgen2/radix0.c b/lib/dotgen2/radix0.c deleted file mode 100644 index 61cbb32c4..000000000 --- a/lib/dotgen2/radix0.c +++ /dev/null @@ -1,95 +0,0 @@ -#include -#include - -// complicated expression better fits as macro (or inline in C++) -#define ByteOf(x) (*(uchar *) (x)) - -typedef unsigned long ulong; -typedef unsigned char uchar; - -// replaced byte with bitsOffset to avoid *8 operation in loop -static void radix (short byteOffset, ulong N, ulong *source, ulong *dest) -{ -// suppressed the need for index as it is reported in count - ulong count[256]; -// added temp variables to simplify writing, understanding and compiler optimization job -// most of them will be allocated as registers - ulong *sp, *cp, s, c, i; - uchar *bp; - -// faster than MemSet - cp = count; - for (i = 256; i > 0; --i, ++cp) - *cp = 0; - -// count occurrences of every byte value - bp = ((uchar *) source) + byteOffset; - for (i = N; i > 0; --i, bp += 4) { - cp = count + *bp; - ++(*cp); - } - -// transform count into index by summing elements and storing into same array - s = 0; - cp = count; - for (i = 256; i > 0; --i, ++cp) { - c = *cp; - *cp = s; - s += c; - } - -// fill dest with the right values in the right place - bp = ((uchar *) source) + byteOffset; - sp = source; - for (i = N; i > 0; --i, bp += 4, ++sp) { - cp = count + *bp; - dest[*cp] = *sp; - ++(*cp); - } -} - -static void radix_sort (ulong *source, ulong N) -{ -// allocate heap memory to avoid the need of additional parameter - ulong *temp = (ulong *) malloc (N * sizeof (ulong)); - assert (temp != NULL); - - radix (3, N, source, temp); - radix (2, N, temp, source); - radix (1, N, source, temp); - radix (0, N, temp, source); - - free (temp); -} - -static void make_random (ulong *data, ulong N) -{ - for ( ; N > 0; --N, ++data) - *data = rand () | (rand () << 16); -} - -static void check_order (ulong *data, ulong N) -{ -// only signal errors if any (should not be) - --N; - for ( ; N > 0; --N, ++data) - assert (data[0] <= data[1]); -} - -// test for big number of elements -static void test_radix (ulong N) -{ - ulong *data = (ulong *) malloc (N * sizeof (ulong)); - assert (data != NULL); - - make_random (data, N); - radix_sort (data, N); - check_order (data, N); - - free (data); -} - -int main (int argc, const char ** argv ) -{ - test_radix (5000000); -} diff --git a/lib/dotgen2/radix1.c b/lib/dotgen2/radix1.c deleted file mode 100644 index e4cc9b772..000000000 --- a/lib/dotgen2/radix1.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - http://www.cubic.org/~submissive/sourcerer/radix.htm - http://www.cubic.org/~submissive/sourcerer/download/radix_ar_2001.c -*/ - -#include -#include - -// complicated expression better fits as macro (or inline in C++) -#define ByteOf(x) (*(uchar *) (x)) - -typedef unsigned long ulong; -typedef unsigned char uchar; - -typedef struct rec_s { - ulong key; -} rec; - -// replaced byte with bitsOffset to avoid *8 operation in loop -static void radix (short byteOffset, ulong N, rec *source, rec *dest) -{ -// suppressed the need for index as it is reported in count - ulong count[256]; -// added temp variables to simplify writing, understanding and compiler optimization job -// most of them will be allocated as registers - ulong *cp, s, c, i; - uchar *bp; - rec *sp; - -// faster than MemSet - cp = count; - for (i = 256; i > 0; --i, ++cp) - *cp = 0; - -// count occurrences of every byte value - bp = ((uchar *) source) + byteOffset; - for (i = N; i > 0; --i, bp += sizeof(rec)) { - cp = count + *bp; - ++(*cp); - } - -// transform count into index by summing elements and storing into same array - s = 0; - cp = count; - for (i = 256; i > 0; --i, ++cp) { - c = *cp; - *cp = s; - s += c; - } - -// fill dest with the right values in the right place - bp = ((uchar *) source) + byteOffset; - sp = source; - for (i = N; i > 0; --i, bp += sizeof(rec), ++sp) { - cp = count + *bp; - dest[*cp] = *sp; - ++(*cp); - } -} - -static void radix_sort (rec *source, ulong N) -{ -// allocate heap memory to avoid the need of additional parameter - rec *temp = (rec *) malloc (N * sizeof (rec)); - assert (temp != NULL); - - radix (3, N, source, temp); - radix (2, N, temp, source); - radix (1, N, source, temp); - radix (0, N, temp, source); - - free (temp); -} - -static void make_random (rec *data, ulong N) -{ - for ( ; N > 0; --N, ++data) - data->key = rand () | (rand () << 16); -} - -static void check_order (rec *data, ulong N) -{ -// only signal errors if any (should not be) - --N; - for ( ; N > 0; --N, ++data) - assert (data[0].key <= data[1].key); -} - -// test for big number of elements -static void test_radix (ulong N) -{ - rec *data = (rec *) malloc (N * sizeof (rec)); - assert (data != NULL); - - make_random (data, N); - radix_sort (data, N); - check_order (data, N); - - free (data); -} - -int main (int argc, const char ** argv) -{ - test_radix (5000000); -} diff --git a/lib/dotgen2/save2_minc.c b/lib/dotgen2/save2_minc.c deleted file mode 100644 index 93cb37e0b..000000000 --- a/lib/dotgen2/save2_minc.c +++ /dev/null @@ -1,970 +0,0 @@ -#include "newdot.h" - -/* given: - * ND_rank(v) int integer level assignments - * ND_ranksize(v) int number of levels (>= 1) - * ED_xpenalty(e) float crossing penalty factor - * find: - * ND_pos(v) coord - * ED_pos(e) coord* - * - * todo: graph, edge labels, flat edges - */ - -/* internal graph variables: - * user graph - * ND_cluster(v) graph* lowest containing cluster - * GD_model(g) graph* model graph - * GD_parent(g) graph* parent cluster - * GD_level int distance from layout root - * - * model graph objects - * GD_usergraph(g) graph* original graph or one of its clusters - * GD_minrank(g) int lowest rank index incl. external edges - * GD_maxrank(g) int highest rank index incl. external edges - * GD_minlocalrank(g) int lowest rank index of internal nodes - * GD_maxlocalrank(g) int highest rank index of internal nodes - * GD_rank(g) rank_t[] - * GD_repdict(g) Dict_t* local representatives of user objects - * ND_component(v) int connected component number - * ND_order(v) int order within rank - * ND_cluster(v) graph* for EXTNODE, its (lowest) user cluster - */ - -/* TODO - where do we use port.defined? - */ - -/*** basic user<->model association maps ***/ -/* determine canonical order of n0, n1 */ -static void getlowhigh(Agnode_t **n0, Agnode_t **n1) -{ - Agnode_t *temp; - int d; - d = ND_rank(*n0) - ND_rank(*n1); - if ((d < 0) || ((d == 0) && ((*n0)->id > (*n1)->id))) - {temp = *n0; *n0 = *n1; *n1 = temp;} -} - -static int repkeycmp(Dt_t *d, void *arg0, void *arg1, Dtdisc_t *disc) -{ - void *key0 = ((repkey_t*)arg0)->key; - void *key1 = ((repkey_t*)arg1)->key; - int rv; - switch(agobjkind(key0)) { - case AGNODE: - rv = ((Agnode_t*)key0)->id - ((Agnode_t*)key1)->id; - break; - case AGEDGE: - rv = ((Agedge_t*)key0)->id - ((Agedge_t*)key1)->id; - break; - case AGRAPH: - /* in libgraph we don't seem to have graph ids, so use pointer */ - rv = (unsigned long)key0 - (unsigned long) key1; - break; - default: - rv = 0; - } - return rv; -} - -static Dtdisc_t Repdisc = { - 0, /* pass whole object as key */ - 0, /* key size and type */ - -1, /* link offset */ - (Dtmake_f)0, - (Dtfree_f)0, - (Dtcompar_f) repkeycmp, - (Dthash_f)0, - (Dtmemory_f)0, - (Dtevent_f)0 -}; - -static Dict_t *repdict(Agraph_t *model) -{ - Dict_t *dict; - - dict = GD_repdict(model); - if (!dict) dict = GD_repdict(model) = dtopen(&Repdisc,Dttree); - return dict; -} - -static rep_t association(Agraph_t *model, void *obj) -{ - Dict_t *dict; - repkey_t key, rv, *p; - - dict = repdict(model); - key.key = obj; /* i hate when other people code like this */ - if ((p = dtsearch(dict,&key))) rv = *p; - else {rv.val.type = 0; rv.val.p = 0;} - return rv.val; -} - -static void associate(Agraph_t *model, void *key, rep_t val) -{ - Dict_t *dict; - repkey_t *newelt; - - assert(association(model,key).type == 0); - dict = repdict(model); - newelt = NEW(repkey_t); - newelt->key = key; - newelt->val = val; - dtinsert(dict,newelt); -} - -typedef struct component_s { - int n; - node_t **root; - int r; -} component_t; - - - -/* from level.c - eventually clean this up. */ -static int is_a_cluster(Agraph_t *g) -{ - return ((g == g->root) || (!strncasecmp(g->name,"cluster",7))); -} - -/* find the cluster of n that is an immediate child of g */ -static Agraph_t *subclustof(Agnode_t *n, Agraph_t *g) -{ - Agraph_t *rv; - for (rv = ND_cluster(n); rv && (GD_parent(rv) != g); rv = GD_parent(rv)); - return rv; -} - -static void *T_array(int low, int high, int size) -{ - char *rv; - - rv = calloc((high - low + 1),size); - rv = rv - (low * size); - return rv; -} - -static Agnode_t **nodearray(int low, int high) -{ return (Agnode_t**) T_array(low,high,sizeof(Agnode_t*)); } - -static Agedge_t **edgearray(int low, int high) -{ return (Agedge_t**) T_array(low,high,sizeof(Agedge_t*)); } - -static int *intarray(int low, int high) -{ return (int*) T_array(low,high,sizeof(int)); } - -/* internal functions for model graph construction and maintenance */ -static vpath_t *newpath(Agraph_t *model, Agnode_t *u, int low, Agnode_t *v, int high) -{ - vpath_t *path; - int i; - path = NEW(vpath_t); - path->v = nodearray(low, high); - path->e = edgearray(low, high); - for (i = low; i <= high; i++) { - if ((i == low) && u) path->v[i] = u; - else if ((i == high) && v) path->v[i] = v; - else path->v[i] = agnode(model,0); - if (i > low) path->e[i-1] = agedge(model,path->v[i-1],path->v[i]); - } - return path; -} - -/* a given edge can have several other edges (forward or backward) - between the same endpoints. here, we choose one of these to be - the canonical representative of those edges. */ -static Agedge_t* canonical_edge(Agedge_t* e) -{ - Agraph_t *g; - Agedge_t *canon; - - g = e->tail->graph; - if (ND_rank(e->head) > ND_rank(e->tail)) - canon = agfindedge(g,e->tail,e->head); - else { - if - } -} - -static void model_edge(Agraph_t *model, Agedge_t *orig) -{ - Agedge_t *e; - Agnode_t *low, *high, *u, *v; - port_t lowport, highport; - vpath_t *path; - rep_t rep; - int i; - - rep = association(model,orig); - if (rep.type == 0) { - low = orig->tail; high = orig->head; - getlowhigh(&low,&high); - u = association(model,low).p; assert(u); - v = association(model,high).p; assert(v); - path = newpath(model,u,ND_rank(low),v,ND_rank(high)); - rep.type = PATH; - rep.p = path; - associate(model,orig,rep); - } - else path = rep.p; - - /* merge the attributes of orig */ - for (i = path->low; i < path->high; i++) { - e = path->e[i]; - ED_xpenalty(e) += ED_xpenalty(orig); - ED_weight(e) += ED_weight(orig); - } - - /* deal with ports. note that ends could be swapped! */ - if (ND_rank(orig->tail) <= ND_rank(orig->head)) { - lowport = ED_tailport(orig); - highport = ED_headport(orig); - } - else { - highport = ED_tailport(orig); - lowport = ED_headport(orig); - } - if (lowport.defined) - path->avgtailport = ((path->weight * path->avgtailport) + ED_weight(orig) * lowport.p.x) / (path->weight + ED_weight(orig)); - if (highport.defined) - path->avgheadport = ((path->weight * path->avgheadport) + ED_weight(orig) * highport.p.x) / (path->weight + ED_weight(orig)); - path->weight += ED_weight(orig); -} - -/* bind/construct representative of an internal node in a model graph */ -static rep_t model_intnode(Agraph_t *model, Agnode_t *orig) -{ - int nr; - rep_t rep; - Agnode_t *v; - - rep = association(model,orig); - if (rep.type) return rep; - - nr = ND_ranksize(orig); - if (nr <= 1) { /* simple case */ - v = rep.p = agnode(model,orig->name); - rep.type = NODE; - ND_rank(v) = ND_rank(orig); - } - else { /* multi-rank node case */ - rep.p = newpath(model,NILnode,ND_rank(orig),NILnode,ND_rank(orig)+nr-1); - rep.type = TALLNODE; - } - associate(model,orig,rep); - return rep; -} - -/* bind/construct representative of an external endpoint to a model graph */ -static rep_t model_extnode(Agraph_t *model, Agnode_t *orig) -{ - Agnode_t *v; - rep_t rep; - - rep = association(model,orig); - if (rep.type) return rep; - - /* assume endpoint is represented by one node, even if orig is multi-rank */ - rep.p = v = agnode(model,orig->name); - rep.type = EXTNODE; - ND_rank(v) = ND_rank(orig); /* should be ND_rank(orig)+ranksize(orig)? */ - associate(model,orig,rep); - return rep; -} - -/* bind/construct representative of an internal cluster of a model graph */ -static rep_t model_clust(Agraph_t *model, Agraph_t *origclust) -{ - rep_t rep; - - rep = association(model,origclust); - if (rep.type) return rep; - - rep.p = newpath(model,NILnode,GD_minrank(origclust),NILnode,GD_maxrank(origclust)); - rep.type = SKELETON; - associate(model,origclust,rep); - return rep; -} - -#ifdef NOTDEF - /* i think we ditched this because we assume nodes are always - built before edges */ -/* helper functions for model_edge */ -static rep_t bindnode(Agraph_t *model, Agnode_t *orignode) -{ - rep_t rep; - if (agcontains(GD_originalgraph(model),orignode)) - rep = model_intnode(model,orignode); - else - rep = model_extnode(model,orignode); - return rep; -} -#endif - -static int leftmost(Agraph_t *model, int r) { return 0; } -static int rightmost(Agraph_t *model, int r) {return GD_rank(model)[r].n - 1;} - -static void flat_edges(Agraph_t *clust) -{ -#ifdef NOTDEF - for (n = agfstnode(clust); n; n = agnxtnode(clust)) { - for (e = agfstedge(root,n); e; e = agnxtedge(root,e,n)) { - } - } - ordered_edges(); -#endif -} - -static void search_component(Agraph_t *g, Agnode_t *n, int c) -{ - Agedge_t *e; - ND_component(n) = c; - for (e = agfstout(g,n); e; e = agnxtout(g,e)) - if (ND_component(e->head) < 0) - search_component(g,e->head,c); - for (e = agfstin(g,n); e; e = agnxtin(g,e)) - if (ND_component(e->tail) < 0) - search_component(g,e->tail,c); -} - -static int ND_comp_cmpf(const void *arg0, const void *arg1) -{ - return ND_component(*(Agnode_t**)arg0) - ND_component(*(Agnode_t**)arg1); -} - -static component_t build_components(Agraph_t *g, boolean down) -{ - component_t rv; - node_t *n; - int r, rootcnt, compcnt, deg; - - for (n = agfstnode(g); n; n = agnxtnode(g,n)) - ND_component(n) = -1; /* initialize to unknown component */ - - compcnt = 0; rootcnt = 0; - for (n = agfstnode(g); n; n = agnxtnode(g,n)) { - /* set priority for subsequent BFS to install nodes, and record roots */ - if (down) deg = ND_indeg(n); - else deg = ND_outdeg(n); - ND_priority(n) = deg; - if (deg == 0) rootcnt++; - /* count and mark components */ - if (ND_component(n) < 0) search_component(g,n,compcnt++); - } - - rv.n = compcnt; - rv.r = rootcnt; - rv.root = N_NEW(rv.r,Agnode_t*); - r = 0; - /* install roots in root list */ - for (n = agfstnode(g); n; n = agnxtnode(g,n)) - if (ND_priority(n) == 0) rv.root[r++] = n; - /* sort root list so components are contiguous */ - qsort(rv.root,rv.n,sizeof(node_t*),ND_comp_cmpf); - return rv; -} - -static void install(Agraph_t *g, Agnode_t *n) -{ - int rank; - rank_t *r; - - rank = ND_rank(n); - r = &GD_rank(g)[rank]; - r->v[r->n] = n; - ND_order(n) = r->n++; -} - -/* - populates rank lists of g. there are some key details: - 1) the input graph ordering must be respected (in left to right initialization) - 2) connected components are separated and marked with indices - 3) series-parallel graphs (includes trees, obviously) must not have crossings -*/ -static void build_ranks(Agraph_t *g, boolean down) -{ - queue *q; - component_t c; - int r; - Agnode_t *n; - Agedge_t *e; - - c = build_components(g, down); - - /* process each each component */ - q = new_queue(agnnodes(g)+1); - for (r = 0; r < c.r; r++) { - enqueue(q,c.root[r]); - if ((r + 1 >= c.r)||(ND_component(c.root[r])!=ND_component(c.root[r+1]))) { - while ((n = dequeue(q))) { - install(g,n); - if (down) { - for (e = agfstout(g,n); e; e = agnxtout(g,e)) - if (--ND_priority(e->head) == 0) enqueue(q,e->head); - } - else { - for (e = agfstin(g,n); e; e = agnxtin(g,e)) - if (--ND_priority(e->tail) == 0) enqueue(q,e->head); - } - } - } - } - free_queue(q); -} - -/* this predicate indicates if mincross should be run on this cluster */ -static boolean run(Agraph_t *mg) -{ - if (GD_pass(mg) > GD_maxpass(mg)) return FALSE; - if (GD_pass(mg) - GD_lastwin(mg) > GD_mintry(mg)) return FALSE; - GD_pass(mg) = GD_pass(mg) + 1; - return TRUE; -} - -static int presort_cmpf(const void *arg0, const void *arg1) -{ - Agnode_t *n0, *n1; - Agraph_t *c0, *c1; - - n0 = *(Agnode_t**)arg0; - n1 = *(Agnode_t**)arg1; - c0 = ND_cluster(n0); - c1 = ND_cluster(n1); - if (c0 == c1) return 0; - assert(ND_rank(n0) == ND_rank(n1)); - n0 = GD_skel(c0)->v[ND_rank(n0)]; - n1 = GD_skel(c1)->v[ND_rank(n1)]; - return ND_order(n0) - ND_order(n1); -} - -static void presort(Agraph_t *ug) -{ - int r; - int i; - Agraph_t *mg; - - if (ug == ug->root) return; - mg = GD_model(ug); - for (r = GD_minrank(mg); r <= GD_maxrank(mg); r++) { - qsort(GD_rank(mg)[r].v,GD_rank(mg)[r].n,sizeof(Agnode_t*),presort_cmpf); - for (i = leftmost(mg,r); i < rightmost(mg,r); i++) - ND_order(GD_rank(mg)[r].v[i]) = i; - } -} - -/* sets ports that represent connections to subclusters */ -static void subclustports(Agraph_t *ug) -{ - Agraph_t *model, *clustmodel; - Agnode_t *x; - Agedge_t *e; - vpath_t *p; - Dict_t *d; - double frac; - - /* walk all the paths */ - model = GD_model(ug); - d = repdict(model); - for (p = dtfirst(d); p; p = dtnext(d,p)) { - if ((ND_type(p->v[p->low])) == NODETYPE_CNODE) { - x = p->v[p->low]; - clustmodel = GD_model(ND_cluster(x)); - frac = (ND_order(x) + 1) / GD_rank(clustmodel)[ND_rank(x)].n; - e = p->e[p->low]; - ED_tailport(e).p.x = 2 * PORTCLAMP * (frac - 0.5) + p->tailport; - } - if ((ND_type(p->v[p->high])) == NODETYPE_CNODE) { - x = p->v[p->high]; - clustmodel = GD_model(ND_cluster(x)); - frac = (ND_order(x) + 1) / GD_rank(clustmodel)[ND_rank(x)].n; - e = p->e[p->high-1]; - ED_headport(e).p.x = 2 * PORTCLAMP * (frac - 0.5) + p->headport; - } - } -} - -static void mincross_clust(Agraph_t *ug) -{ - Agraph_t *g; - g = GD_model(ug); - if (run(g)) { - presort(ug); /* move the external nodes */ - subclustports(ug); - do { - mincross_sweep(g,GD_pass(g)%2,GD_pass(g)%4<2); - } while (run(g)); - transpose_sweep(g,TRUE); - restorebest(g); - } -} - -static void globalopt(Agraph_t *root) -{ - Agraph_t *g; - rank_t *glob; - - g = GD_model(root); - glob = globalize(root,g); - GD_rank(g) = glob; - fprintf(stderr,"%s: %d crossings\n",root->name,crossings(g)); -} - -/* this assumes one level per node - no mega-nodes */ -static void apply_model(Agraph_t *ug) -{ - Agnode_t *un; - for (un = agfstnode(ug); un; un = agnxtnode(ug,un)) - ND_order(un) = ND_order(ND_rep(un)); -} - -/* this is a first cut at a top-level planner. it's lame. */ -static void rec_cluster_run(Agraph_t *ug) -{ - Agraph_t *subg; - - if (is_a_cluster(ug)) mincross_clust(ug); - for (subg = agfstsubg(ug); subg; subg = agnxtsubg(ug,subg)) - rec_cluster_run(subg); - if (is_a_cluster(ug)) mincross_clust(ug); -} - -/* this is the top level mincross entry point */ -void dot_mincross(Agraph_t *user) -{ - rec_cluster_init(user); - rec_cluster_run(user); - globalopt(user); - apply_model(user); -} - -static void invalidate(Agraph_t *g, int rank) -{ - if (rank > GD_minrank(g)) GD_rank(g)[rank-1].crossing_cache.valid = FALSE; - if (rank > GD_minrank(g)) GD_rank(g)[rank-1].candidate = TRUE; - if (rank < GD_maxrank(g)) GD_rank(g)[rank+1].candidate = TRUE; -} - -/* swaps two nodes in the same level */ -static void exchange(Agraph_t *g, Agnode_t *u, Agnode_t *v) -{ - rank_t *r; - int ui,vi,rank; - - assert(ND_rank(u) == ND_rank(v)); - rank = ND_rank(u); - r = &GD_rank(g)[rank]; - ui = ND_order(u); - vi = ND_order(v); - ND_order(v) = ui; - ND_order(u) = vi; - r->v[ND_order(u)] = u; - r->v[ND_order(v)] = v; - r->crossing_cache.valid = FALSE; - r->changed = TRUE; - r->candidate = TRUE; /* old dot had this. i have qualms. sn */ - invalidate(g,rank); -} - -int transpose_onerank(Agraph_t* g, int r, boolean reverse) -{ - int i,c0,c1,rv; - node_t *v,*w; - - rv = 0; - GD_rank(g)[r].candidate = FALSE; - for (i = leftmost(g,r); i < rightmost(g,r); i++) { - v = GD_rank(g)[r].v[i]; - w = GD_rank(g)[r].v[i+1]; - assert (ND_order(v) < ND_order(w)); - if (left2right(g,v,w)) continue; - c0 = c1 = 0; - if (r > GD_minrank(g)) { - c0 += in_cross(v,w); - c1 += in_cross(w,v); - } - if (r < GD_maxrank(g)) { - c0 += out_cross(v,w); - c1 += out_cross(w,v); - } - if ((c1 < c0) || ((c0 > 0) && reverse && (c1 == c0))) { - exchange(g,v,w); - rv += (c0 - c1); - } - } - return rv; -} - -static void transpose_sweep(Agraph_t* g, int reverse) -{ - int r,delta; - - for (r = GD_minrank(g); r <= GD_maxrank(g); r++) - GD_rank(g)[r].candidate = TRUE; - do { - delta = 0; - for (r = GD_minrank(g); r <= GD_maxrank(g); r++) - if (GD_rank(g)[r].candidate) delta += transpose_onerank(g,r,reverse); - } - while (delta >= 1); - /* while (delta > crossings(g)*(1.0 - Convergence));*/ -} - -static void mincross_sweep(Agraph_t* g, int dir, boolean reverse) -{ - int r,other,low,high,first,last; - int hasfixed; - - low = GD_minrank(g); - high = GD_maxrank(g); - if (dir == 0) return; - if (dir > 0) { first = low + 1; last = high; dir = 1;} /* down */ - else { first = high - 1; last = low; dir = -1;} /* up */ - - for (r = first; r != last + dir; r += dir) { - other = r - dir; - hasfixed = medians(g,r,other); - reorder(g,r,reverse,hasfixed); - } - transpose_sweep(g,NOT(reverse)); - savebest(g); -} - - -static int left2right(Agraph_t *g, node_t *v, node_t *w) -{ - int rv; - -#ifdef NOTDEF - adjmatrix_t *M; - M = GD_rank(g)[ND_rank(v)].flat; - if (M == NULL) rv = FALSE; - else { - if (GD_flip(g)) {node_t *t = v; v = w; w = t;} - rv = ELT(M,flatindex(v),flatindex(w)); - } -#else - rv = FALSE; -#endif - return rv; -} - -static void build_flat_graphs(Agraph_t *g) -{ -} - -static int out_cross(node_t *v, node_t *w) -{ - register edge_t *e1,*e2; - register int inv, cross = 0,t; - - for (e2 = agfstout(w->graph,w); e2; e2 = agnxtout(w->graph,e2)) { - register int cnt = ED_xpenalty(e2); - inv = ND_order(e2->head); - for (e1 = agfstout(v->graph,v); e1; e1 = agnxtout(v->graph,e1)) { - t = ND_order(e1->head) - inv; - if ((t > 0) || ((t == 0) && (ED_headport(e1).p.x > ED_headport(e2).p.x))) - cross += ED_xpenalty(e1) * cnt; - } - } - return cross; -} - -static int in_cross(node_t *v,node_t *w) -{ - register edge_t *e1,*e2; - register int inv, cross = 0, t; - - for (e2 = agfstin(w->graph,w); e2; e2 = agnxtin(w->graph,e2)) { - register int cnt = ED_xpenalty(e2); - inv = ND_order(e2->tail); - for (e1 = agfstin(v->graph,v); e1; e1 = agnxtin(v->graph,e1)) { - t = ND_order(e1->tail) - inv; - if ((t > 0) || ((t == 0) && (ED_tailport(e1).p.x > ED_tailport(e2).p.x))) - cross += ED_xpenalty(e1) * cnt; - } - } - return cross; -} - -static int int_cmpf(const void *arg0, const void *arg1) -{ - return *(int*)arg0 - *(int*)arg1; -} - - -/* 8 is the number of bits in port.order, an unsigned char */ -#define VAL(node,port) (((node)->u.order << 8) + (port).order) - -/* - * defines ND_sortweight of each node in r0 w.r.t. r1 - * returns... - */ -static boolean medians(Agraph_t *g, int r0, int r1) -{ - static int *list; - static int list_extent; - int i,j,lm,rm,lspan,rspan; - node_t *n,**v; - edge_t *e; - boolean hasfixed = FALSE; - - if (list_extent < GD_maxinoutdeg(g->root)) { - list_extent = GD_maxinoutdeg(g->root); - if (!list) list = realloc(list,sizeof(list[0])*list_extent); - else list = realloc(list,sizeof(list[0])*list_extent); - } - v = GD_rank(g)[r0].v; - for (i = leftmost(g,r0); i <= rightmost(g,r0); i++) { - n = v[i]; j = 0; - if (r1 > r0) for (e = agfstout(g,n); e; e = agnxtout(g,e)) - {if (ED_xpenalty(e) > 0) list[j++] = VAL(e->head,ED_headport(e));} - else for (e = agfstin(g,n); e; e = agnxtin(g,e)) - {if (ED_xpenalty(e) > 0) list[j++] = VAL(e->tail,ED_tailport(e));} - switch(j) { - case 0: - ND_sortweight(n) = -1; /* no neighbor - median undefined */ - break; - case 1: - ND_sortweight(n) = list[0]; - break; - case 2: - ND_sortweight(n) = (list[0] + list[1])/2; - break; - default: - qsort(list,j,sizeof(int),int_cmpf); - if (j % 2) ND_sortweight(n) = list[j/2]; - else { - /* weighted median */ - rm = j/2; - lm = rm - 1; - rspan = list[j-1] - list[rm]; - lspan = list[lm] - list[0]; - if (lspan == rspan) - ND_sortweight(n) = (list[lm] + list[rm])/2; - else { - int w = list[lm]*rspan + list[rm]*lspan; - ND_sortweight(n) = w / (lspan + rspan); - } - } - } - } -#ifdef NOTDEF - /* this code was in the old mincross */ - for (i = 0; i < GD_rank(g)[r0].n; i++) { - n = v[i]; - if ((ND_out(n).size == 0) && (ND_in(n).size == 0)) - hasfixed |= flat_sortweight(n); - } -#endif - return hasfixed; -} - -static void reorder(graph_t *g, int r, boolean reverse, boolean hasfixed) -{ - boolean changed, muststay; - node_t **vlist, **lp, **rp, **ep; - int i; - - changed = FALSE; - vlist = GD_rank(g)[r].v; - ep = &vlist[rightmost(g,r)]; - - for (i = leftmost(g,r); i <= rightmost(g,r); i++) { - lp = &vlist[leftmost(g,r)]; - /* find leftmost node that can be compared */ - while ((lp < ep) && (ND_sortweight(*lp) < 0)) lp++; - if (lp >= ep) break; - /* find the node that can be compared */ - muststay = FALSE; - for (rp = lp + 1; rp < ep; rp++) { - if (left2right(g,*lp,*rp)) { muststay = TRUE; break; } - if (ND_sortweight(*rp) >= 0) break; /* weight defined; it's comparable */ - } - if (rp >= ep) break; - if (muststay == FALSE) { - register int p1 = ND_sortweight(*lp); - register int p2 = ND_sortweight(*rp); - if ((p1 > p2) || ((p1 == p2) && (reverse))) { - exchange(g,*lp,*rp); - changed = TRUE; - } - } - lp = rp; - if ((hasfixed == FALSE) && (reverse == FALSE)) ep--; - } - - if (changed) { - GD_rank(g)[r].changed = TRUE; - GD_rank(g)[r].crossing_cache.valid = FALSE; - if (r > 0) GD_rank(g)[r-1].crossing_cache.valid = FALSE; - if (r + 1 > GD_rank(g)[r+1].n) GD_rank(g)[r-1].crossing_cache.valid = FALSE; - } -} - -static void savebest(graph_t *g) -{ - int nc; - Agnode_t *n; - - nc = crossings(g); - if (nc < GD_bestcrossings(g)) { - for (n = agfstnode(g); n; n = agnxtnode(g,n)) - ND_saveorder(n) = ND_order(n); - GD_bestcrossings(g) = nc; - GD_lastwin(g) = GD_pass(g); - } -} - -static int ND_order_cmpf(const void *arg0, const void *arg1) -{ - return ND_order(*(Agnode_t**)arg0) - ND_order(*(Agnode_t**)arg1); -} - -static void restorebest(graph_t *g) -{ - Agnode_t *n; - int i; - - for (i = GD_minrank(g); i <= GD_maxrank(g); i++) - GD_rank(g)[i].changed = FALSE; - for (n = agfstnode(g); n; n = agnxtnode(g,n)) { - if (ND_order(n) != ND_saveorder(n)) { - invalidate(g,ND_rank(n)); - GD_rank(g)[i].changed = TRUE; - ND_order(n) = ND_saveorder(n); - } - } - for (i = GD_minrank(g); i <= GD_maxrank(g); i++) { - if (GD_rank(g)[i].changed) - qsort(GD_rank(g)[i].v,GD_rank(g)[i].n,sizeof(Agnode_t*),ND_order_cmpf); - } -} - -static int crossings(graph_t *g) -{ - int i, rv; - - rv = 0; - for (i = GD_minrank(g); i < GD_maxrank(g); i++) { - rv += crossings_below(g,i); - } - return rv; -} - -/* build the global (flat) graph of the universe. this is 'flat' -in the sense that there is one data structure for the entire graph -(not 'flat' in the sense of flat edges within the same level.) -*/ -static rank_t *globalize(Agraph_t *user, Agraph_t *topmodel) -{ - rank_t *globrank; - int minr,maxr,r; - - /* setup bookkeeping */ - interclusterpaths(user, topmodel); - - /* allocate global ranks */ - minr = GD_minrank(topmodel); - maxr = GD_maxrank(topmodel); - globrank = T_array(minr,maxr,sizeof(rank_t)); - countup(user,globrank); - for (r = minr; r <= maxr; r++) { - globrank[r].v = N_NEW(globrank[r].n+1,Agnode_t*); /* NIL at end */ - globrank[r].n = 0; /* reset it */ - } - - /* installation */ - for (r = minr; r <= maxr; r++) - installglob(user,topmodel,globrank,r); - - removejunk(user, topmodel); - reconnect(user, topmodel); - - /* optimization */ - return globrank; -} - -static void countup(Agraph_t *g, rank_t *globr) -{ - Agnode_t *n; - Agedge_t *e; - int r0, r1, low, high, i; - - for (n = agfstnode(g); n; n = agnxtnode(g,n)) { - for (i = 0; i < ND_ranksize(n); i++) - globr[ND_rank(n)+i].n += 1; - for (e = agfstout(g,n); e; e = agnxtout(g,e)) { - r0 = ND_rank(e->tail); - r1 = ND_rank(e->head); - low = MIN(r0,r1); - high = MAX(r0,r1); - for (i = low + 1; i < high; i++) - globr[i].n += 1; - } - } -} - -static void rec_model_subclusts(Agraph_t *model, Agraph_t *user) -{ - Agraph_t *subg; - - if (is_a_cluster(user)) - (void) model_clust(model,user); - /* note there can be non-cluster subgraphs that contain lower clusters */ - for (subg = agfstsubg(ug); subg; subg = agnxtsubg(ug,subg)) - rec_model_subclusts(model,subg); -} - -static void cluster_contents(Agraph_t *ug) -{ - Agraph_t *mg; - char *name; - - assert(is_a_cluster(ug)); - assert(GD_model(ug) == 0); - - name = malloc(strlen(ug->name)+10); - sprintf(name,"model_%s",ug->name); - GD_model(ug) = mg = agopen(name,AGDIGRAPHSTRICT); - free(name); - - /* install internal nodes */ - for (n = agfstnode(ug); n; n = agnxtnode(ug,n)) { - if (ND_cluster(n) == ug) model_intnode(mg,n); - } - - /* install cluster skeletons */ - rec_model_subclusts(mg,ug); - - /* install external edge endpoints */ - root = GD_layoutroot(ug); - for (n = agfstnode(ug); n; n = agnxtnode(ug,n)) { - for (e = agfstout(root,n); e; e = agnxtout(root,e)) { - if (!agcontains(ug,e->tail)) - model_extnode(mg,e->tail); - if (!agcontains(ug,e->head)) - model_extnode(mg,e->head); - } - } - - /* install edges */ - for (n = agfstnode(ug); n; n = agnxtnode(ug,n)) - for (e = agfstout(root,n); e; e = agnxtout(root,e)) - model_edge(mg,e); /* amazing if this is all it takes */ -} - -static void cluster_init(Agraph_t *ug) -{ - cluster_contents(ug); - flat_edges(ug); -} - -static void rec_cluster_init(Agraph_t *ug) -{ - Agraph_t *subg; - - if (is_a_cluster(ug)) cluster_init(ug); - for (subg = agfstsubg(ug); subg; subg = agnxtsubg(ug,subg)) - rec_cluster_init(subg); -} diff --git a/lib/dotgen2/save_minc.c b/lib/dotgen2/save_minc.c deleted file mode 100644 index 5902c3f0e..000000000 --- a/lib/dotgen2/save_minc.c +++ /dev/null @@ -1,1281 +0,0 @@ -#include "newdot.h" - -/* given: - * ND_level(v) int integer level assignments - * ND_something(v) int number of levels (if > 1) - * ED_xpenalty(e) float crossing penalty factor - * find: - * ND_pos(v) coord - * ED_pos(e) coord* - * - * todo: graph, edge labels - */ - -/* computed values: - * user graph - * ND_cluster(v) graph* lowest containing cluster - * GD_model(g) graph* model graph - * GD_parent(g) graph* parent cluster - * - * model graph objects - * GD_minrank(g) int - * GD_maxrank(g) int - * GD_rank(g) rank_t[] - * GD_skel(g) vpath_t* path representing g in its parent - * ND_component(v) int connected component number - */ - - * ND_vrep(user node) <-> ND_vrep(model node : REAL) - * ND_erep(model node : XNODE) == user edge - * ND_erep(model node : VNODE) == user edge - * ND_grep(model node : CNODE) == user cluster - */ - -/* TODO - where do we use port.defined? - */ - -typedef struct component_s { - int n; - node_t **root; - int r; -} component_t; - -static Agraph_t *subclustof(Agnode_t *n, Agraph_t *clust); -static void *T_array(int low, int high, int size); -static Agnode_t **nodearray(int low, int high); -static int *intarray(int low, int high); -static void cluster_model(Agraph_t *clust); -static void flat_edges(Agraph_t *clust); -static void search_component(Agraph_t *g, Agnode_t *n, int c); -static int ND_comp_cmpf(const void *arg0, const void *arg1); -static component_t build_components(Agraph_t *g, boolean down); -static void install(Agraph_t *g, Agnode_t *n); -static void build_ranks(Agraph_t *ug, boolean down); -static void rec_cluster_init(Agraph_t *userclust); -static boolean run(Agraph_t *g); -static void mincross_clust(Agraph_t *clust); -static void globalopt(Agraph_t *ug); -static void rec_cluster_run(Agraph_t *ug); -static void exchange(Agraph_t *g, Agnode_t *u, Agnode_t *v); -static void transpose_sweep(Agraph_t* g, int reverse); -static void mincross_sweep(Agraph_t* g, int dir, boolean reverse); -static int left2right(Agraph_t *g, node_t *v, node_t *w); -static void build_flat_graphs(Agraph_t *g); -static boolean medians(Agraph_t *g, int r0, int r1); -static void reorder(Agraph_t *g, int r, boolean reverse, boolean hasfixed); -static void savebest(Agraph_t *g); -static void restorebest(Agraph_t *g); -static int crossings(Agraph_t *g); -static int in_cross(node_t *v,node_t *w); -static int out_cross(node_t *v,node_t *w); -static rank_t *globalize(Agraph_t *user, Agraph_t *model); -static void installglob(Agraph_t *user, Agraph_t *fromgraph, rank_t *globr, int r); -static void countup(Agraph_t *g, rank_t *globr); - -static Agnode_t *model_getrep(Agraph_t *ug, Agnode_t *n, Agedge_t *e); -static Agraph_t *universegraph(Agraph_t *ug); -static vpath_t *model_skel(Agraph_t *uclust, Agraph_t *model); -static void removejunk(Agraph_t *ug, Agraph_t *topmodel); -static void reconnect(Agraph_t *ug, Agraph_t *topmodel); - -/* from level.c - eventually clean this up. */ -static int is_a_cluster(Agraph_t *g) -{ - return ((g == g->root) || (!strncasecmp(g->name,"cluster",7))); -} - -/* find the cluster of n that is an immediate child of g */ -static Agraph_t *subclustof(Agnode_t *n, Agraph_t *g) -{ - Agraph_t *rv; - for (rv = ND_cluster(n); rv && (GD_parent(rv) != g); rv = GD_parent(rv)); - return rv; -} - -static void *T_array(int low, int high, int size) -{ - char *rv; - - rv = calloc((high - low + 1),size); - rv = rv - (low * size); - return rv; -} - -static Agnode_t **nodearray(int low, int high) -{ return (Agnode_t**) T_array(low,high,sizeof(Agnode_t*)); } - -static Agedge_t **edgearray(int low, int high) -{ return (Agedge_t**) T_array(low,high,sizeof(Agedge_t*)); } - -static int *intarray(int low, int high) -{ return (int*) T_array(low,high,sizeof(int)); } - -static Agnode_t *model_realnode(Agraph_t *modelgraph, Agnode_t *orig) -{ - Agnode_t *rep; - /* this is OK because realnode can only be in one model graph/subgraph */ - rep = agnode(modelgraph,orig->name); - ND_rank(rep) = ND_rank(orig); - ND_cluster(rep) = modelgraph; - ND_vrep(orig) = rep; - ND_vrep(rep) = orig; - ND_type(rep) = NODETYPE_REAL; - /* other initializations may need to go here */ - return rep; -} - -static Agnode_t *model_extnode(Agraph_t *modelgraph, Agnode_t *orig, Agedge_t *ue) -{ - char name[1024]; - Agnode_t *rep; - - sprintf(name,"ext_%s_%s",modelgraph->name,orig->name); - /* can't be anonymous - needs to be repeatable */ - rep = agnode(modelgraph,name); - ND_rank(rep) = ND_rank(orig); - ND_cluster(rep) = modelgraph; - ND_erep(rep) = ue; - ND_type(rep) = NODETYPE_XNODE; - /* other initializations may need to go here */ - return rep; -} - -static Agnode_t *model_vnode(Agraph_t *modelgraph, Agedge_t *uedge, int level) -{ - Agnode_t *rep; - rep = agnode(modelgraph,0); - ND_rank(rep) = level; - ND_cluster(rep) = modelgraph; - ND_erep(rep) = uedge; /* this may be bogus, what if multiple? */ - ND_type(rep) = NODETYPE_VNODE; - /* other initializations may need to go here */ - return rep; -} - -static Agnode_t *model_cnode(Agraph_t *modelgraph, Agraph_t *uclust, int level) -{ - Agnode_t *rep; - rep = agnode(modelgraph,0); - ND_rank(rep) = level; - ND_cluster(rep) = uclust; - ND_grep(rep) = uclust; - ND_type(rep) = NODETYPE_CNODE; - /* other initializations may need to go here */ - return rep; -} - -static Agedge_t *model_vedge(Agraph_t *modelgraph, Agnode_t *tx, Agnode_t *hx, Agedge_t *orig) -{ - Agedge_t *e; - - e = agedge(modelgraph,tx,hx); - ED_xpenalty(e) = VEDGE_PENALTY * ED_xpenalty(orig); - ED_weight(e) = ED_weight(orig); - return e; -} - -static Agedge_t *model_cedge(Agraph_t *modelgraph, Agnode_t *tx, Agnode_t *hx) -{ - Agedge_t *e; - - e = agedge(modelgraph,tx,hx); - ED_xpenalty(e) = CEDGE_PENALTY; - ED_weight(e) = 1; - return e; -} - -static void getlowhigh(Agnode_t **n0, Agnode_t **n1) -{ - Agnode_t *temp; - if (ND_rank(*n0) > ND_rank(*n1)) - {temp = *n0; *n0 = *n1; *n1 = temp;} -} - -vpath_t *newpath(Agnode_t *u, Agnode_t *v) -{ - Agnode_t *low = u, *high = v; - vpath_t *p; - - getlowhigh(&low,&high); - p = NEW(vpath_t); - p->key.tail = low; - p->key.head = high; - p->low = ND_rank(low); - p->high = ND_rank(high); - p->v = nodearray(p->low, p->high); - p->v[p->low] = low; - p->v[p->high] = high; - p->e = edgearray(p->low, p->high); - return p; -} - -static int pathcmp(Dt_t *d, void *arg0, void *arg1, Dtdisc_t *disc) -{ - int rv; - if ((rv = ((vpath_t*)arg0)->key.tail - ((vpath_t*)arg1)->key.tail) == 0) - rv = ((vpath_t*)arg0)->key.head - ((vpath_t*)arg1)->key.head; - return rv; -} - -static Dtdisc_t Vpathdisc = { - 0, /* pass whole object as key */ - 0, /* key size and type */ - -1, /* link offset */ - (Dtmake_f)0, - (Dtfree_f)0, - (Dtcompar_f) pathcmp, - (Dthash_f)0, - (Dtmemory_f)0, - (Dtevent_f)0 -}; - -static Dict_t *pathdict(Agraph_t *model) -{ - Dict_t *dict; - - dict = GD_pathdict(model); - if (!dict) dict = GD_pathdict(model) = dtopen(&Vpathdisc,Dttree); - return dict; -} - -static void pathinsert(Agraph_t *model, vpath_t *p) -{ - Dict_t *dict; - dict = pathdict(model); - p = dtinsert(dict,p); -} - -static vpath_t *pathsearch(Agraph_t *modelgraph, Agnode_t *origlow, Agnode_t *orighigh) -{ - Dict_t *dict; - vpath_t path, *p; - - dict = pathdict(modelgraph); - path.key.tail = origlow; - path.key.head = orighigh; - p = dtsearch(dict,&path); - return p; - -} - -vpath_t *model_path(Agraph_t *modelgraph, Agnode_t *tv, Agnode_t *hv, Agedge_t *orig) -{ - vpath_t *p; - Agnode_t *origlow, *orighigh; - double old, new, tot, hx, tx; - port tp, hp; - int i; - - getlowhigh(&tv,&hv); - origlow = orig->tail; orighigh = orig->head; - getlowhigh(&origlow,&orighigh); - - p = pathsearch(modelgraph,origlow,orighigh); - if (!p) { - p = newpath(origlow,orighigh); - for (i = p->low; i <= p->high; i++) { - if (i == p->low) p->v[i] = tv; - else if (i == p->high) p->v[i] = hv; - else p->v[i] = model_vnode(modelgraph,orig,i); - if (i > p->low) - p->e[i-1] = model_vedge(modelgraph,p->v[i-1],p->v[i],orig); - } - pathinsert(modelgraph,p); - } - /* merge the weights on the vedges */ - /* SN: I think this code is only correct if the parallel edges all - * refer to the same original endpoint, which is not necessarily true. - * However, the correct value will be computed later by subclustports() - */ - old = p->weight; new = ED_weight(orig); tot = old + new; - if (origlow == orig->tail) {tp = ED_tailport(orig); hp = ED_headport(orig);} - else {tp = ED_headport(orig); hp = ED_tailport(orig);} - tx = tp.p.x; if (tx > PORTCLAMP) tx = PORTCLAMP; if (tx < -PORTCLAMP) tx = -PORTCLAMP; - hx = hp.p.x; if (hx > PORTCLAMP) hx = PORTCLAMP; if (hx < -PORTCLAMP) hx = -PORTCLAMP; - p->tailport = (old/tot)*tx + (new/tot)*p->tailport; - p->headport = (old/tot)*hx + (new/tot)*p->headport; - p->weight = tot; - return p; -} - -/* get model node for an endpoint (can be external to the clust). assumes -each node and cluster has a unique parent, and nodes have unique names. -clust and node are from a user graph, not an internal model graph. -*/ -static Agnode_t *model_getrep(Agraph_t *uclust, Agnode_t *un, Agedge_t *ue) -{ - Agraph_t *model = GD_model(uclust); - Agraph_t *subclust; - vpath_t *skel; - Agnode_t *rep; - - if (agcontains(uclust,un)) { /* internal */ - if (ND_cluster(un) == uclust) { /* primitive */ - rep = ND_rep(un); - if (!rep) { - /* i don't believe this should ever really happen because - all real nodes were already processed; consider this safety code */ - rep = model_realnode(model,un); - } - } - else { /* in a subcluster */ - subclust = subclustof(un,uclust); - skel = model_skel(model,subclust); - rep = skel->v[ND_rank(un)]; - } - } - else { /* external */ - rep = model_extnode(model,un,ue); - } - return rep; -} - -static vpath_t *model_skel(Agraph_t *model, Agraph_t *uclust) -{ - vpath_t *skel; - int i; - - if (!((skel = GD_skel(uclust)))) { - skel = GD_skel(uclust) = NEW(vpath_t); - skel->key.tail = skel->key.head = NILnode; /* skeletons aren't indexed */ - skel->low = GD_minrank(uclust); - skel->high = GD_maxrank(uclust); - skel->v = nodearray(skel->low,skel->high); - skel->e = edgearray(skel->low,skel->high); - for (i = skel->low; i <= skel->high; i++) { - skel->v[i] = model_cnode(model,uclust,i); - if (i > skel->low) - skel->e[i - 1] = model_cedge(model,skel->v[i-1],skel->v[i]); - } - } - return skel; -} - -static void rec_open_modelgraphs(Agraph_t *ug) -{ - Agraph_t *universe, *model, *subg; - Agnode_t *n; - - char nametmp[1024]; /* fix this! */ - - if (is_a_cluster(ug)) { - universe = universegraph(ug); - sprintf(nametmp,"model_of_%s",ug->name); - model = GD_model(ug) = agsubg(universe,nametmp); - if (!(n = agfstnode(ug))) return; - GD_minrank(ug) = GD_maxrank(ug) = ND_rank(n); - while ((n = agnxtnode(ug,n))) { - if (GD_maxrank(ug) < ND_rank(n)) GD_maxrank(ug) = ND_rank(n); - if (GD_minrank(ug) > ND_rank(n)) GD_minrank(ug) = ND_rank(n); - } - GD_minrank(model) = GD_minrank(ug); - GD_maxrank(model) = GD_maxrank(ug); - } - for (subg = agfstsubg(ug); subg; subg = agnxtsubg(ug,subg)) - rec_open_modelgraphs(subg); -} - -static void rec_skel(Agraph_t *uclust) -{ - Agraph_t *model; - - if (!uclust) return; - model = GD_model(uclust); - if (GD_skel(model)) return; /* already done ???? */ - /* skeleton is made within the model of the parent of uclust */ - if (GD_parent(uclust)) - (void) model_skel(GD_model(GD_parent(uclust)), uclust); - rec_skel(GD_parent(uclust)); -} - -static void make_nodes(Agraph_t *ug) -{ - Agnode_t *n; - Agraph_t *model; - - if ((n = agfstnode(ug)) == NILnode) return; - rec_open_modelgraphs(ug); - model = GD_model(ug); - - /* the following creates real and cluster skeleton nodes - in their original graph order. vnodes get done later. */ - for (n = agfstnode(ug); n; n = agnxtnode(ug,n)) { - (void) model_realnode(GD_model(ND_cluster(n)),n); - if (ND_cluster(n) != ug) rec_skel(ND_cluster(n)); - } -} - -static int leftmost(Agraph_t *model, int r) { return 0; } -static int rightmost(Agraph_t *model, int r) {return GD_rank(model)[r].n - 1;} - -/* Build a model graph for each cluster + its ext edges. - The model is a subgraph of a 'universal graph' for all - the objects of a graph and its clusters. This makes it - possible to merge the cluster (models) later. Fortunately - each primitive node only belongs to one cluster. On the - other hand, naming all the virtual objects uniquely is so much - useless overhead. (This is one thing libAgraph handles reasonably - and that it might make sense to port back to libgraph.) - - Note that the cluster models are not themselves nested subgraphs. - This is because we don't want internal objects of a cluster to - propagate to its enclosing clusters. - */ -static void rec_cluster_model(Agraph_t *ug) -{ - graph_t *model,*subg; - node_t *n; - edge_t *e; - node_t *tx, *hx; - int minr,maxr,r,*ranksize; - - if (is_a_cluster(ug)) { - /* get model graph */ - model = GD_model(ug); - - /* edges (including external ones) */ - for (n = agfstnode(ug); n; n = agnxtnode(ug,n)) { - for (e = agfstedge(ug->root,n); e; e = agnxtedge(ug->root,e,n)) { - tx = model_getrep(ug,e->tail,e); - hx = model_getrep(ug,e->head,e); - if (tx == hx) continue; - /* skip edges that are within some subcluster */ - if ((ND_type(tx)==NODETYPE_CNODE) && (ND_type(hx)==NODETYPE_CNODE) && - (ND_cluster(tx) == ND_cluster(hx))) continue; - (void) model_path(model,tx,hx,e); - } - } - - /* initialize storage for later installation of nodes */ - - /* external nodes can be outside the internal min/max rank bounds */ - minr = GD_minrank(model); - maxr = GD_maxrank(model); - for (n = agfstnode(model); n; n = agnxtnode(model,n)) { - minr = MIN(minr,ND_rank(n)); - maxr = MAX(maxr,ND_rank(n)); - } - - ranksize = intarray(minr,maxr); - for (n = agfstnode(model); n; n = agnxtnode(model,n)) - ranksize[ND_rank(n)]++; - GD_rank(model) = T_array(minr,maxr,sizeof(rank_t)); - for (r = minr; r <= maxr; r++) /* see leftmost() and rightmost() */ - GD_rank(model)[r].v = N_NEW(ranksize[r]+1,Agnode_t*); /* NIL at end */ - } - for (subg = agfstsubg(ug); subg; subg = agnxtsubg(ug,subg)) - rec_cluster_model(subg); -} - -static void cluster_model(Agraph_t *ug) -{ - Agraph_t *g; - Agnode_t *n; - Agedge_t *e; - int indeg, outdeg; - - rec_cluster_model(ug); - - g = GD_model(ug); - for (n = agfstnode(g); n; n = agnxtnode(g,n)) { - indeg = outdeg = 0; - if (ND_indeg(n) == 0) { - for (e = agfstin(g,n); e; e = agnxtin(g,e)) indeg++; - ND_indeg(n) = indeg; - } - if (ND_outdeg(n) == 0) { - for (e = agfstout(g,n); e; e = agnxtout(g,e)) outdeg++; - ND_outdeg(n) = outdeg; - } - GD_maxinoutdeg(g->root) = MAX(GD_maxinoutdeg(g->root),MAX(indeg,outdeg)); - } - - /* set up mincross running parameters */ - GD_pass(g) = 0; - GD_lastwin(g) = 0; - GD_mintry(g) = gvgetint(ug,"minpass",24); - GD_maxpass(g) = gvgetint(ug,"maxpass",1024); - GD_bestcrossings(g) = MAXINT; -} - -static Agraph_t *universegraph(Agraph_t *ug) -{ - graph_t *root = ug->root; - graph_t *univ,*model; - if ((model = GD_model(root))) - univ = model->root; - else { - univ = agopen("_universe\001_",AGDIGRAPHSTRICT); - } - return univ; -} - -static void flat_edges(Agraph_t *clust) -{ -#ifdef NOTDEF - for (n = agfstnode(clust); n; n = agnxtnode(clust)) { - for (e = agfstedge(root,n); e; e = agnxtedge(root,e,n)) { - } - } - ordered_edges(); -#endif -} - -static void search_component(Agraph_t *g, Agnode_t *n, int c) -{ - Agedge_t *e; - ND_component(n) = c; - for (e = agfstout(g,n); e; e = agnxtout(g,e)) - if (ND_component(e->head) < 0) - search_component(g,e->head,c); - for (e = agfstin(g,n); e; e = agnxtin(g,e)) - if (ND_component(e->tail) < 0) - search_component(g,e->tail,c); -} - -static int ND_comp_cmpf(const void *arg0, const void *arg1) -{ - return ND_component(*(Agnode_t**)arg0) - ND_component(*(Agnode_t**)arg1); -} - -static component_t build_components(Agraph_t *g, boolean down) -{ - component_t rv; - node_t *n; - int r, rootcnt, compcnt, deg; - - for (n = agfstnode(g); n; n = agnxtnode(g,n)) - ND_component(n) = -1; /* initialize to unknown component */ - - compcnt = 0; rootcnt = 0; - for (n = agfstnode(g); n; n = agnxtnode(g,n)) { - /* set priority for subsequent BFS to install nodes, and record roots */ - if (down) deg = ND_indeg(n); - else deg = ND_outdeg(n); - ND_priority(n) = deg; - if (deg == 0) rootcnt++; - /* count and mark components */ - if (ND_component(n) < 0) search_component(g,n,compcnt++); - } - - rv.n = compcnt; - rv.r = rootcnt; - rv.root = N_NEW(rv.r,Agnode_t*); - r = 0; - /* install roots in root list */ - for (n = agfstnode(g); n; n = agnxtnode(g,n)) - if (ND_priority(n) == 0) rv.root[r++] = n; - /* sort root list so components are contiguous */ - qsort(rv.root,rv.n,sizeof(node_t*),ND_comp_cmpf); - return rv; -} - -static void install(Agraph_t *g, Agnode_t *n) -{ - int rank; - rank_t *r; - - rank = ND_rank(n); - r = &GD_rank(g)[rank]; - r->v[r->n] = n; - ND_order(n) = r->n++; -} - -/* - populates rank lists of g. there are some key details: - 1) the input graph ordering must be respected (in left to right initialization) - 2) connected components are separated and marked with indices - 3) series-parallel graphs (includes trees, obviously) must not have crossings -*/ -static void build_ranks(Agraph_t *g, boolean down) -{ - queue *q; - component_t c; - int r; - Agnode_t *n; - Agedge_t *e; - - c = build_components(g, down); - - /* process each each component */ - q = new_queue(agnnodes(g)+1); - for (r = 0; r < c.r; r++) { - enqueue(q,c.root[r]); - if ((r + 1 >= c.r)||(ND_component(c.root[r])!=ND_component(c.root[r+1]))) { - while ((n = dequeue(q))) { - install(g,n); - if (down) { - for (e = agfstout(g,n); e; e = agnxtout(g,e)) - if (--ND_priority(e->head) == 0) enqueue(q,e->head); - } - else { - for (e = agfstin(g,n); e; e = agnxtin(g,e)) - if (--ND_priority(e->tail) == 0) enqueue(q,e->head); - } - } - } - } - free_queue(q); -} - -/* this predicate indicates if mincross should be run on this cluster */ -static boolean run(Agraph_t *mg) -{ - if (GD_pass(mg) > GD_maxpass(mg)) return FALSE; - if (GD_pass(mg) - GD_lastwin(mg) > GD_mintry(mg)) return FALSE; - GD_pass(mg) = GD_pass(mg) + 1; - return TRUE; -} - -static int presort_cmpf(const void *arg0, const void *arg1) -{ - Agnode_t *n0, *n1; - Agraph_t *c0, *c1; - - n0 = *(Agnode_t**)arg0; - n1 = *(Agnode_t**)arg1; - c0 = ND_cluster(n0); - c1 = ND_cluster(n1); - if (c0 == c1) return 0; - assert(ND_rank(n0) == ND_rank(n1)); - n0 = GD_skel(c0)->v[ND_rank(n0)]; - n1 = GD_skel(c1)->v[ND_rank(n1)]; - return ND_order(n0) - ND_order(n1); -} - -static void presort(Agraph_t *ug) -{ - int r; - int i; - Agraph_t *mg; - - if (ug == ug->root) return; - mg = GD_model(ug); - for (r = GD_minrank(mg); r <= GD_maxrank(mg); r++) { - qsort(GD_rank(mg)[r].v,GD_rank(mg)[r].n,sizeof(Agnode_t*),presort_cmpf); - for (i = leftmost(mg,r); i < rightmost(mg,r); i++) - ND_order(GD_rank(mg)[r].v[i]) = i; - } -} - -/* sets ports that represent connections to subclusters */ -static void subclustports(Agraph_t *ug) -{ - Agraph_t *model, *clustmodel; - Agnode_t *x; - Agedge_t *e; - vpath_t *p; - Dict_t *d; - double frac; - - /* walk all the paths */ - model = GD_model(ug); - d = pathdict(model); - for (p = dtfirst(d); p; p = dtnext(d,p)) { - if ((ND_type(p->v[p->low])) == NODETYPE_CNODE) { - x = p->v[p->low]; - clustmodel = GD_model(ND_cluster(x)); - frac = (ND_order(x) + 1) / GD_rank(clustmodel)[ND_rank(x)].n; - e = p->e[p->low]; - ED_tailport(e).p.x = 2 * PORTCLAMP * (frac - 0.5) + p->tailport; - } - if ((ND_type(p->v[p->high])) == NODETYPE_CNODE) { - x = p->v[p->high]; - clustmodel = GD_model(ND_cluster(x)); - frac = (ND_order(x) + 1) / GD_rank(clustmodel)[ND_rank(x)].n; - e = p->e[p->high-1]; - ED_headport(e).p.x = 2 * PORTCLAMP * (frac - 0.5) + p->headport; - } - } -} - -static void mincross_clust(Agraph_t *ug) -{ - Agraph_t *g; - g = GD_model(ug); - if (run(g)) { - presort(ug); /* move the external nodes */ - subclustports(ug); - do { - mincross_sweep(g,GD_pass(g)%2,GD_pass(g)%4<2); - } while (run(g)); - transpose_sweep(g,TRUE); - restorebest(g); - } -} - -static void globalopt(Agraph_t *root) -{ - Agraph_t *g; - rank_t *glob; - - g = GD_model(root); - glob = globalize(root,g); - GD_rank(g) = glob; - fprintf(stderr,"%s: %d crossings\n",root->name,crossings(g)); -} - -/* this assumes one level per node - no mega-nodes */ -static void apply_model(Agraph_t *ug) -{ - Agnode_t *un; - for (un = agfstnode(ug); un; un = agnxtnode(ug,un)) - ND_order(un) = ND_order(ND_rep(un)); -} - -/* this is a first cut at a top-level planner. it's lame. */ -static void rec_cluster_run(Agraph_t *ug) -{ - Agraph_t *subg; - - if (is_a_cluster(ug)) mincross_clust(ug); - for (subg = agfstsubg(ug); subg; subg = agnxtsubg(ug,subg)) - rec_cluster_run(subg); - if (is_a_cluster(ug)) mincross_clust(ug); -} - -/* this is the top level mincross entry point */ -void dot_mincross(Agraph_t *user) -{ - rec_cluster_init(user); - rec_cluster_run(user); - globalopt(user); - apply_model(user); -} - -static void invalidate(Agraph_t *g, int rank) -{ - if (rank > GD_minrank(g)) GD_rank(g)[rank-1].crossing_cache.valid = FALSE; - if (rank > GD_minrank(g)) GD_rank(g)[rank-1].candidate = TRUE; - if (rank < GD_maxrank(g)) GD_rank(g)[rank+1].candidate = TRUE; -} - -/* swaps two nodes in the same level */ -static void exchange(Agraph_t *g, Agnode_t *u, Agnode_t *v) -{ - rank_t *r; - int ui,vi,rank; - - assert(ND_rank(u) == ND_rank(v)); - rank = ND_rank(u); - r = &GD_rank(g)[rank]; - ui = ND_order(u); - vi = ND_order(v); - ND_order(v) = ui; - ND_order(u) = vi; - r->v[ND_order(u)] = u; - r->v[ND_order(v)] = v; - r->crossing_cache.valid = FALSE; - r->changed = TRUE; - r->candidate = TRUE; /* old dot had this. i have qualms. sn */ - invalidate(g,rank); -} - -int transpose_onerank(Agraph_t* g, int r, boolean reverse) -{ - int i,c0,c1,rv; - node_t *v,*w; - - rv = 0; - GD_rank(g)[r].candidate = FALSE; - for (i = leftmost(g,r); i < rightmost(g,r); i++) { - v = GD_rank(g)[r].v[i]; - w = GD_rank(g)[r].v[i+1]; - assert (ND_order(v) < ND_order(w)); - if (left2right(g,v,w)) continue; - c0 = c1 = 0; - if (r > GD_minrank(g)) { - c0 += in_cross(v,w); - c1 += in_cross(w,v); - } - if (r < GD_maxrank(g)) { - c0 += out_cross(v,w); - c1 += out_cross(w,v); - } - if ((c1 < c0) || ((c0 > 0) && reverse && (c1 == c0))) { - exchange(g,v,w); - rv += (c0 - c1); - } - } - return rv; -} - -static void transpose_sweep(Agraph_t* g, int reverse) -{ - int r,delta; - - for (r = GD_minrank(g); r <= GD_maxrank(g); r++) - GD_rank(g)[r].candidate = TRUE; - do { - delta = 0; - for (r = GD_minrank(g); r <= GD_maxrank(g); r++) - if (GD_rank(g)[r].candidate) delta += transpose_onerank(g,r,reverse); - } - while (delta >= 1); - /* while (delta > crossings(g)*(1.0 - Convergence));*/ -} - -static void mincross_sweep(Agraph_t* g, int dir, boolean reverse) -{ - int r,other,low,high,first,last; - int hasfixed; - - low = GD_minrank(g); - high = GD_maxrank(g); - if (dir == 0) return; - if (dir > 0) { first = low + 1; last = high; dir = 1;} /* down */ - else { first = high - 1; last = low; dir = -1;} /* up */ - - for (r = first; r != last + dir; r += dir) { - other = r - dir; - hasfixed = medians(g,r,other); - reorder(g,r,reverse,hasfixed); - } - transpose_sweep(g,NOT(reverse)); - savebest(g); -} - - -static int left2right(Agraph_t *g, node_t *v, node_t *w) -{ - int rv; - -#ifdef NOTDEF - adjmatrix_t *M; - M = GD_rank(g)[ND_rank(v)].flat; - if (M == NULL) rv = FALSE; - else { - if (GD_flip(g)) {node_t *t = v; v = w; w = t;} - rv = ELT(M,flatindex(v),flatindex(w)); - } -#else - rv = FALSE; -#endif - return rv; -} - -static void build_flat_graphs(Agraph_t *g) -{ -} - -static int out_cross(node_t *v, node_t *w) -{ - register edge_t *e1,*e2; - register int inv, cross = 0,t; - - for (e2 = agfstout(w->graph,w); e2; e2 = agnxtout(w->graph,e2)) { - register int cnt = ED_xpenalty(e2); - inv = ND_order(e2->head); - for (e1 = agfstout(v->graph,v); e1; e1 = agnxtout(v->graph,e1)) { - t = ND_order(e1->head) - inv; - if ((t > 0) || ((t == 0) && (ED_headport(e1).p.x > ED_headport(e2).p.x))) - cross += ED_xpenalty(e1) * cnt; - } - } - return cross; -} - -static int in_cross(node_t *v,node_t *w) -{ - register edge_t *e1,*e2; - register int inv, cross = 0, t; - - for (e2 = agfstin(w->graph,w); e2; e2 = agnxtin(w->graph,e2)) { - register int cnt = ED_xpenalty(e2); - inv = ND_order(e2->tail); - for (e1 = agfstin(v->graph,v); e1; e1 = agnxtin(v->graph,e1)) { - t = ND_order(e1->tail) - inv; - if ((t > 0) || ((t == 0) && (ED_tailport(e1).p.x > ED_tailport(e2).p.x))) - cross += ED_xpenalty(e1) * cnt; - } - } - return cross; -} - -static int int_cmpf(const void *arg0, const void *arg1) -{ - return *(int*)arg0 - *(int*)arg1; -} - - -/* 8 is the number of bits in port.order, an unsigned char */ -#define VAL(node,port) (((node)->u.order << 8) + (port).order) - -/* - * defines ND_sortweight of each node in r0 w.r.t. r1 - * returns... - */ -static boolean medians(Agraph_t *g, int r0, int r1) -{ - static int *list; - static int list_extent; - int i,j,lm,rm,lspan,rspan; - node_t *n,**v; - edge_t *e; - boolean hasfixed = FALSE; - - if (list_extent < GD_maxinoutdeg(g->root)) { - list_extent = GD_maxinoutdeg(g->root); - if (!list) list = realloc(list,sizeof(list[0])*list_extent); - else list = realloc(list,sizeof(list[0])*list_extent); - } - v = GD_rank(g)[r0].v; - for (i = leftmost(g,r0); i <= rightmost(g,r0); i++) { - n = v[i]; j = 0; - if (r1 > r0) for (e = agfstout(g,n); e; e = agnxtout(g,e)) - {if (ED_xpenalty(e) > 0) list[j++] = VAL(e->head,ED_headport(e));} - else for (e = agfstin(g,n); e; e = agnxtin(g,e)) - {if (ED_xpenalty(e) > 0) list[j++] = VAL(e->tail,ED_tailport(e));} - switch(j) { - case 0: - ND_sortweight(n) = -1; /* no neighbor - median undefined */ - break; - case 1: - ND_sortweight(n) = list[0]; - break; - case 2: - ND_sortweight(n) = (list[0] + list[1])/2; - break; - default: - qsort(list,j,sizeof(int),int_cmpf); - if (j % 2) ND_sortweight(n) = list[j/2]; - else { - /* weighted median */ - rm = j/2; - lm = rm - 1; - rspan = list[j-1] - list[rm]; - lspan = list[lm] - list[0]; - if (lspan == rspan) - ND_sortweight(n) = (list[lm] + list[rm])/2; - else { - int w = list[lm]*rspan + list[rm]*lspan; - ND_sortweight(n) = w / (lspan + rspan); - } - } - } - } -#ifdef NOTDEF - /* this code was in the old mincross */ - for (i = 0; i < GD_rank(g)[r0].n; i++) { - n = v[i]; - if ((ND_out(n).size == 0) && (ND_in(n).size == 0)) - hasfixed |= flat_sortweight(n); - } -#endif - return hasfixed; -} - -static void reorder(graph_t *g, int r, boolean reverse, boolean hasfixed) -{ - boolean changed, muststay; - node_t **vlist, **lp, **rp, **ep; - int i; - - changed = FALSE; - vlist = GD_rank(g)[r].v; - ep = &vlist[rightmost(g,r)]; - - for (i = leftmost(g,r); i <= rightmost(g,r); i++) { - lp = &vlist[leftmost(g,r)]; - /* find leftmost node that can be compared */ - while ((lp < ep) && (ND_sortweight(*lp) < 0)) lp++; - if (lp >= ep) break; - /* find the node that can be compared */ - muststay = FALSE; - for (rp = lp + 1; rp < ep; rp++) { - if (left2right(g,*lp,*rp)) { muststay = TRUE; break; } - if (ND_sortweight(*rp) >= 0) break; /* weight defined; it's comparable */ - } - if (rp >= ep) break; - if (muststay == FALSE) { - register int p1 = ND_sortweight(*lp); - register int p2 = ND_sortweight(*rp); - if ((p1 > p2) || ((p1 == p2) && (reverse))) { - exchange(g,*lp,*rp); - changed = TRUE; - } - } - lp = rp; - if ((hasfixed == FALSE) && (reverse == FALSE)) ep--; - } - - if (changed) { - GD_rank(g)[r].changed = TRUE; - GD_rank(g)[r].crossing_cache.valid = FALSE; - if (r > 0) GD_rank(g)[r-1].crossing_cache.valid = FALSE; - if (r + 1 > GD_rank(g)[r+1].n) GD_rank(g)[r-1].crossing_cache.valid = FALSE; - } -} - -static void savebest(graph_t *g) -{ - int nc; - Agnode_t *n; - - nc = crossings(g); - if (nc < GD_bestcrossings(g)) { - for (n = agfstnode(g); n; n = agnxtnode(g,n)) - ND_saveorder(n) = ND_order(n); - GD_bestcrossings(g) = nc; - GD_lastwin(g) = GD_pass(g); - } -} - -static int ND_order_cmpf(const void *arg0, const void *arg1) -{ - return ND_order(*(Agnode_t**)arg0) - ND_order(*(Agnode_t**)arg1); -} - -static void restorebest(graph_t *g) -{ - Agnode_t *n; - int i; - - for (i = GD_minrank(g); i <= GD_maxrank(g); i++) - GD_rank(g)[i].changed = FALSE; - for (n = agfstnode(g); n; n = agnxtnode(g,n)) { - if (ND_order(n) != ND_saveorder(n)) { - invalidate(g,ND_rank(n)); - GD_rank(g)[i].changed = TRUE; - ND_order(n) = ND_saveorder(n); - } - } - for (i = GD_minrank(g); i <= GD_maxrank(g); i++) { - if (GD_rank(g)[i].changed) - qsort(GD_rank(g)[i].v,GD_rank(g)[i].n,sizeof(Agnode_t*),ND_order_cmpf); - } -} - -static int crossings(graph_t *g) -{ - int i, rv; - - rv = 0; - for (i = GD_minrank(g); i < GD_maxrank(g); i++) { - rv += crossings_below(g,i); - } - return rv; -} - -/* returns level of (model) node's cluster */ -static int lev(Agnode_t *n) -{ - if (!n) return -1; - return (GD_level(ND_cluster(n))); -} - -/* - * allocates a vpath_t per original user edge. later the path - * contents will be set to define vnode chains of intercluster edges. - */ -static void interclusterpaths(Agraph_t *ug, Agraph_t *topmodel) -{ - Agnode_t *n, *n0; - Agedge_t *e, *ue; - vpath_t *p; - - for (n = agfstnode(ug); n; n = agnxtnode(ug,n)) { - for (e = agfstout(ug,n); e; e = agnxtout(ug,e)) { - if (ND_cluster(e->tail) != ND_cluster(e->head)) { - if (!(p = pathsearch(topmodel->root,e->tail,e->head))) { - p = newpath(e->tail, e->head); - pathinsert(topmodel->root,p); - } - } - } - } - - /* scan all vnodes of model graph and make decisions */ - for (n = agfstnode(topmodel); n; n = agnxtnode(topmodel,n)) { - if (ND_type(n) == NODETYPE_VNODE) { - ue = ND_erep(n); - p = pathsearch(topmodel->root,ue->tail,ue->head); - if (p) { - if (!(n0 = p->v[ND_rank(n)]) || (lev(n0) < lev(n))) - p->v[ND_rank(n)] = n; - } - } - } - /* need to remove the other edges of these vnodes!! */ -} - -/* build the global (flat) graph of the universe. this is 'flat' -in the sense that there is one data structure for the entire graph -(not 'flat' in the sense of flat edges within the same level.) -*/ -static rank_t *globalize(Agraph_t *user, Agraph_t *topmodel) -{ - rank_t *globrank; - int minr,maxr,r; - - /* setup bookkeeping */ - interclusterpaths(user, topmodel); - - /* allocate global ranks */ - minr = GD_minrank(topmodel); - maxr = GD_maxrank(topmodel); - globrank = T_array(minr,maxr,sizeof(rank_t)); - countup(user,globrank); - for (r = minr; r <= maxr; r++) { - globrank[r].v = N_NEW(globrank[r].n+1,Agnode_t*); /* NIL at end */ - globrank[r].n = 0; /* reset it */ - } - - /* installation */ - for (r = minr; r <= maxr; r++) - installglob(user,topmodel,globrank,r); - - removejunk(user, topmodel); - reconnect(user, topmodel); - - /* optimization */ - return globrank; -} - - -static void countup(Agraph_t *g, rank_t *globr) -{ - Agnode_t *n; - Agedge_t *e; - int r0, r1, low, high, i; - - for (n = agfstnode(g); n; n = agnxtnode(g,n)) { - globr[ND_rank(n)].n += 1; - for (e = agfstout(g,n); e; e = agnxtout(g,e)) { - r0 = ND_rank(e->tail); - r1 = ND_rank(e->head); - low = MIN(r0,r1); - high = MAX(r0,r1); - for (i = low + 1; i < high; i++) - globr[i].n += 1; - } - } -} - -/* install nodes from rank r of (g or its clusters) into globr. */ -static void installglob(Agraph_t *ug, Agraph_t *fromgraph, rank_t *globr, int r) -{ - rank_t *myrank; - int i; - Agnode_t *v; - Agedge_t *uedge; - vpath_t *path; - - if (is_a_cluster(fromgraph)) { - myrank = &GD_rank(fromgraph)[r]; - i = 0; - while ((v = myrank->v[i++])) { - switch (ND_type(v)) { - case NODETYPE_REAL: - /* install primitive nodes */ - globr[r].v[globr[r].n++] = v; - ND_isglobal(v) = TRUE; - break; - case NODETYPE_VNODE: - /* install vnode for non-intercluster edges, and for intercluster - edges if this vnode was chosen as the path representative */ - uedge = ND_erep(v); - path = pathsearch(fromgraph->root,uedge->tail,uedge->head); - if (!path || (path->v[r] == v)) { - globr[r].v[globr[r].n++] = v; - ND_isglobal(v) = TRUE; - } - break; - case NODETYPE_CNODE: - /* install clusters recursively */ - installglob(ug,ND_cluster(v),globr,r); - break; - case NODETYPE_XNODE: - /* we're ignoring these */ - break; - } - } - } -} - -/* - after making the global graph, delete all non-global objects. - */ -static void removejunk(Agraph_t *ug, Agraph_t *topmodel) -{ - Agnode_t *v,*vv; - - for (v = agfstnode(topmodel); v; v = vv) { - vv = agnxtnode(topmodel,v); - if (!ND_isglobal(v)) agdelete(topmodel,v); - } -} - -/* - fix up the user edge paths in the global graph. -*/ -static void reconnect(Agraph_t *ug, Agraph_t *topmodel) -{ - Agnode_t *n, *n0, *n1; - Agedge_t *e, *e0; - vpath_t *p; - int i; - - for (n = agfstnode(ug); n; n = agnxtnode(ug,n)) { - for (e = agfstout(ug,n); e; e = agnxtout(ug,e)) { - if (ND_cluster(e->tail) != ND_cluster(e->head)) { - p = pathsearch(topmodel->root,e->tail,e->head); - n0 = p->v[p->low]; - for (i = p->low + 1; i <= p->high; i++) { - n1 = p->v[i]; - if (!(e0 = p->e[i])) e0 = agedge(topmodel,n0,n1); - ED_weight(e0) += ED_weight(e); - ED_xpenalty(e0) += ED_xpenalty(e); - n0 = n1; - } - } - } - } -} - -#ifdef NOTDEF -/* (no parallel edges, all forward edges, flat cycles broken) */ -void build_main_graph(Agraph_t *g) -{ - Agraph_t *gprime,*gprimeflat; - Agnode_t *v,*vprime; - Agedge_t *eprev; - - gprime = agopen("model",AGDIGRAPHSTRICT); - for (v = agfstnode(g); v; v = agnxtnode(g,v)) { - vprime = agnode(gprime,v->name); - for (e = agfstout(v); e; e = agxntout(g,e)) { - tail = e->tail; - head = e->head; - if (ND_rank(tail) > ND_rank(head)) {Agnode_t *t = head; head = tail; tail = t;} - if (!(eprev = agfindedge(gprime,tail,head))) eprev = agedge(gprime,tail,head); - merge(eprev,e); - associate(e,eprev); - } - } - break_cycles(gprime); -} -#endif - -/* I. initialization */ -static void cluster_init(Agraph_t *ug) - -{ - Agraph_t *mg; - - make_nodes(ug); - cluster_model(ug); - mg = GD_model(ug); - flat_edges(mg); - build_ranks(mg,TRUE); -} - -static void rec_cluster_init(Agraph_t *ug) -{ - Agraph_t *subg; - - if (is_a_cluster(ug)) cluster_init(ug); - for (subg = agfstsubg(ug); subg; subg = agnxtsubg(ug,subg)) - rec_cluster_init(subg); -} diff --git a/lib/dotgen2/t.c b/lib/dotgen2/t.c deleted file mode 100644 index 2ae497c0b..000000000 --- a/lib/dotgen2/t.c +++ /dev/null @@ -1,1128 +0,0 @@ -#include "newdot.h" - -/* given: - * each node and cluster has a unique containing cluster. - * ND_level is the integer level of each node. - * ND_cluster is the lowest containing cluster of each node. - * ED_xpenalty is the crossing weight for an edge. - * find: - * GD_rank - the levels of the graph - * ND_order - the global order of each node - */ - -typedef struct component_s { - int n; - node_t **root; - int r; -} component_t; - -static Agraph_t *subclustof(Agnode_t *n, Agraph_t *clust); -static void *T_array(int low, int high, int size); -static Agnode_t **nodearray(int low, int high); -static int *intarray(int low, int high); -static Agraph_t *cluster_model(Agraph_t *clust); -static void flat_edges(Agraph_t *clust); -static void search_component(Agraph_t *g, Agnode_t *n, int c); -static int ND_comp_cmpf(const void *arg0, const void *arg1); -static component_t build_components(Agraph_t *g, boolean down); -static void install(Agraph_t *g, Agnode_t *n); -static void build_ranks(Agraph_t *ug, boolean down); -static void cluster_init(Agraph_t *userclust); -static void rec_cluster_init(Agraph_t *userclust); -static boolean run(Agraph_t *g); -static void mincross_clust(Agraph_t *clust); -static void globalopt(Agraph_t *ug); -static void rec_cluster_run(Agraph_t *ug); -static void exchange(Agraph_t *g, Agnode_t *u, Agnode_t *v); -static void transpose_sweep(graph_t* g, int reverse); -static void mincross_sweep(graph_t* g, int dir, boolean reverse); -static int left2right(graph_t *g, node_t *v, node_t *w); -static void build_flat_graphs(graph_t *g); -static boolean medians(graph_t *g, int r0, int r1); -static void reorder(graph_t *g, int r, boolean reverse, boolean hasfixed); -static void savebest(graph_t *g); -static void restorebest(graph_t *g); -static int crossings(graph_t *g); -static int in_cross(node_t *v,node_t *w); -static int out_cross(node_t *v,node_t *w); -static rank_t *globalize(Agraph_t *user, Agraph_t *model); -static void installglob(Agraph_t *user, Agraph_t *fromgraph, rank_t *globr, int r); -static void countup(Agraph_t *g, rank_t *globr); - -static Agnode_t *model_getrep(Agraph_t *ug, Agnode_t *n, Agedge_t *e); -static Agraph_t *universegraph(Agraph_t *ug); -static vpath_t *model_skel(Agraph_t *uclust, Agraph_t *model); -static void clusterchains(Agraph_t *model, Agraph_t *ug); -static void removejunk(Agraph_t *ug, Agraph_t *topmodel); -static void reconnect(Agraph_t *ug, Agraph_t *topmodel); - -/* from level.c - eventually clean this up. */ -static int is_a_cluster(graph_t *g) -{ - return ((g == g->root) || (!strncasecmp(g->name,"cluster",7))); -} - -/* find the cluster of n that is an immediate child of g */ -static Agraph_t *subclustof(Agnode_t *n, Agraph_t *g) -{ - Agraph_t *rv; - for (rv = ND_cluster(n); rv && (GD_parent(rv) != g); rv = GD_parent(rv)); - return rv; -} - -static void *T_array(int low, int high, int size) -{ - char *rv; - - rv = calloc((high - low + 1),size); - rv = rv - (low * size); - return rv; -} - -static Agnode_t **nodearray(int low, int high) -{ return (Agnode_t**) T_array(low,high,sizeof(Agnode_t*)); } - -static Agedge_t **edgearray(int low, int high) -{ return (Agedge_t**) T_array(low,high,sizeof(Agedge_t*)); } - -static int *intarray(int low, int high) -{ return (int*) T_array(low,high,sizeof(int)); } - -static Agnode_t *model_realnode(Agraph_t *modelgraph, Agnode_t *orig) -{ - Agnode_t *rep; - /* this is OK because realnode can only be in one model graph/subgraph */ - rep = agnode(modelgraph,orig->name); - ND_rank(rep) = ND_rank(orig); - ND_cluster(rep) = modelgraph; - ND_vrep(orig) = rep; - ND_vrep(rep) = orig; - ND_type(rep) = NODETYPE_REAL; - /* other initializations may need to go here */ - return rep; -} - -static Agnode_t *model_extnode(Agraph_t *modelgraph, Agnode_t *orig, Agedge_t *e) -{ - char name[1024]; - Agnode_t *rep; - - sprintf(name,"ext_%s_%s",modelgraph->name,orig->name); - /* can't be anonymous - needs to be repeatable */ - rep = agnode(modelgraph,name); - ND_rank(rep) = ND_rank(orig); - ND_cluster(rep) = modelgraph; - ND_erep(rep) = e; - ND_type(rep) = NODETYPE_XNODE; - /* other initializations may need to go here */ - return rep; -} - -static Agnode_t *model_vnode(Agraph_t *modelgraph, Agedge_t *longedge, int level) -{ - Agnode_t *rep; - rep = agnode(modelgraph,0); - ND_rank(rep) = level; - ND_cluster(rep) = modelgraph; - ND_erep(rep) = longedge; - ND_type(rep) = NODETYPE_VNODE; - /* other initializations may need to go here */ - return rep; -} - -static Agnode_t *model_cnode(Agraph_t *modelgraph, Agraph_t *clust, int level) -{ - Agnode_t *rep; - rep = agnode(modelgraph,0); - ND_rank(rep) = level; - ND_cluster(rep) = clust; - ND_grep(rep) = clust; - ND_type(rep) = NODETYPE_CNODE; - /* other initializations may need to go here */ - return rep; -} - -static Agedge_t *model_vedge(Agraph_t *modelgraph, Agnode_t *tx, Agnode_t *hx, Agedge_t *orig) -{ - Agedge_t *e; - - e = agedge(modelgraph,tx,hx); - ED_xpenalty(e) = VEDGE_PENALTY * ED_xpenalty(orig); - ED_weight(e) = ED_weight(orig); - return e; -} - -static Agedge_t *model_cedge(Agraph_t *modelgraph, Agnode_t *tx, Agnode_t *hx) -{ - Agedge_t *e; - - e = agedge(modelgraph,tx,hx); - ED_xpenalty(e) = CEDGE_PENALTY; - ED_weight(e) = 1; - return e; -} - -static void getlowhigh(Agnode_t **n0, Agnode_t **n1) -{ - Agnode_t *temp; - if (ND_rank(*n0) > ND_rank(*n1)) - {temp = *n0; *n0 = *n1; *n1 = temp;} -} - -vpath_t *newpath(Agnode_t *u, Agnode_t *v) -{ - Agnode_t *origlow = u, *orighigh = v; - vpath_t *p; - - getlowhigh(&origlow,&orighigh); - p = NEW(vpath_t); - p->key.tail = origlow; - p->key.head = orighigh; - p->low = ND_rank(origlow); - p->high = ND_rank(orighigh); - p->v = nodearray(p->low, p->high); - p->e = edgearray(p->low, p->high); - return p; -} - -static int pathcmp(Dt_t *d, void *arg0, void *arg1, Dtdisc_t *disc) -{ - int rv; - if ((rv = ((vpath_t*)arg0)->key.tail - ((vpath_t*)arg1)->key.tail) == 0) - rv = ((vpath_t*)arg0)->key.head - ((vpath_t*)arg1)->key.head; - return rv; -} - -static Dtdisc_t Vpathdisc = { - 0, /* pass whole object as key */ - 0, /* key size and type */ - -1, /* link offset */ - (Dtmake_f)0, - (Dtfree_f)0, - (Dtcompar_f) pathcmp, - (Dthash_f)0, - (Dtmemory_f)0, - (Dtevent_f)0 -}; - -static Dict_t *pathdict(Agraph_t *g) -{ - Dict_t *dict; - dict = GD_pathdict(g); - if (!dict) dict = GD_pathdict(g) = dtopen(&Vpathdisc,Dttree); - return dict; -} - -static vpath_t *pathsearch(Agraph_t *g, Agnode_t *u, Agnode_t *v) -{ - vpath_t *p,path; - Dict_t *dict; - Agnode_t *origlow = u, *orighigh = v; - - getlowhigh(&origlow, &orighigh); - dict = pathdict(g); - path.key.tail = origlow; - path.key.head = orighigh; - p = dtsearch(dict,&path); - return p; -} - -static void pathinsert(Agraph_t *g, vpath_t *p) -{ - Dict_t *dict; - dict = pathdict(g); - p = dtinsert(dict,p); -} - -vpath_t *model_path(Agraph_t *modelgraph, Agnode_t *tx, Agnode_t *hx, Agedge_t *orig) -{ - vpath_t *p; - Agnode_t *origlow, *orighigh; - int i; - - getlowhigh(&tx,&hx); - origlow = orig->tail; orighigh = orig->head; - getlowhigh(&origlow,&orighigh); - - p = pathsearch(modelgraph,origlow,orighigh); - if (!p) { - p = newpath(origlow,orighigh); - for (i = p->low; i <= p->high; i++) { - if (i == p->low) p->v[i] = tx; - else if (i == p->high) p->v[i] = hx; - else p->v[i] = model_vnode(modelgraph,orig,i); - if (i > p->low) - p->e[i] = model_vedge(modelgraph,p->v[i-1],p->v[i],orig); - } - pathinsert(modelgraph,p); - } - return p; -} - -/* get model node for an endpoint (can be external to the clust). assumes -each node and cluster has a unique parent, and nodes have unique names. -clust and node are from a user graph, not an internal model graph. -*/ -static Agnode_t *model_getrep(Agraph_t *uclust, Agnode_t *un, Agedge_t *ue) -{ - Agraph_t *model = GD_model(uclust); - Agraph_t *subclust; - vpath_t *skel; - Agnode_t *rep; - - if (agcontains(uclust,un)) { /* internal */ - if (ND_cluster(un) == uclust) { /* primitive */ - rep = ND_rep(un); - if (!rep) { - /* i don't believe this should ever really happen because - all real nodes were already processed; consider this safety code */ - rep = model_realnode(model,un); - } - } - else { /* in a subcluster */ - subclust = subclustof(un,uclust); - skel = model_skel(model,subclust); - rep = skel->v[ND_rank(un)]; - } - } - else { /* external */ - rep = model_extnode(model,un,ue); - } - return rep; -} - -static vpath_t *model_skel(Agraph_t *model, Agraph_t *uclust) -{ - vpath_t *skel; - int i; - - if (!((skel = GD_skel(uclust)))) { - skel = GD_skel(uclust) = NEW(vpath_t); - skel->key.tail = skel->key.head = NILnode; /* skeletons aren't indexed */ - skel->low = GD_minrank(uclust); - skel->high = GD_maxrank(uclust); - skel->v = nodearray(skel->low,skel->high); - skel->e = edgearray(skel->low,skel->high); - for (i = skel->low; i <= skel->high; i++) { - skel->v[i] = model_cnode(model,uclust,i); - if (i > skel->low) - skel->e[i - 1] = model_cedge(model,skel->v[i-1],skel->v[i]); - } - } - return skel; -} - -static void scangraph(Agraph_t *g) -{ - Agnode_t *n; - Agedge_t *e; - short indeg, outdeg; - - if ((n = agfstnode(g)) == NILnode) return; - - model = universegraph(g); - GD_minrank(g) = GD_maxrank(g) = ND_rank(n); - GD_maxinoutdeg(g) = 0; - for (n = agfstnode(g); n; n = agnxtnode(g,n)) { - if (GD_maxrank(g) < ND_rank(n)) GD_maxrank(g) = ND_rank(n); - if (GD_minrank(g) > ND_rank(n)) GD_minrank(g) = ND_rank(n); - if (ND_indeg(n) == 0) { - indeg = 0; for (e = agfstin(g,n); e; e = agnxtin(g,e)) indeg++; - ND_indeg(n) = indeg; - } - if (ND_outdeg(n) == 0) { - outdeg = 0; for (e = agfstout(g,n); e; e = agnxtout(g,e)) outdeg++; - ND_outdeg(n) = outdeg; - } - GD_maxinoutdeg(g) = MAX(GD_maxinoutdeg(g),MAX(indeg,outdeg)); - } -} - -/* Build a model graph for each cluster + its ext edges. - The model is a subgraph of a 'universal graph' for all - the objects of a graph and its clusters. This makes it - possible to merge the cluster (models) later. Fortunately - each primitive node only belongs to one cluster. On the - other hand, naming all the virtual objects uniquely is so much - useless overhead. (This is one thing libAgraph handles reasonably - and that it might make sense to port back to libgraph.) - - Note that the cluster models are not thesmselves nested subgraphs. - This is because we don't want internal objects of a cluster to - propagate to its enclosing clusters. - */ -static Agraph_t *cluster_model(Agraph_t *ug) -{ - graph_t *model,*universe; - node_t *n; - edge_t *e; - node_t *tx, *hx; - int minr,maxr,r,*ranksize; - - /* get model graph */ - if (GD_model(ug)) abort(); /* double initialization? not yet re-entrant. */ - universe = universegraph(ug); - model = GD_model(ug) = agsubg(universe,ug->name); - - /* create nodes explicitly. this copies the search order of original nodes - and ensures singletons (including those in subclusters) are created */ - for (n = agfstnode(ug); n; n = agnxtnode(ug,n)) { - if (ND_cluster(n) == ug) (void) model_realnode(model,n); - else clusterchains(model,subclustof(n,ug)); - } - - /* edges (including external ones) */ - for (n = agfstnode(ug); n; n = agnxtnode(ug,n)) { - for (e = agfstedge(ug->root,n); e; e = agnxtedge(ug->root,e,n)) { - tx = model_getrep(ug,e->tail,e); - hx = model_getrep(ug,e->head,e); - if (tx == hx) continue; - /* skip edges that are within some subcluster */ - if ((ND_type(tx) == NODETYPE_CNODE) && (ND_type(hx) == NODETYPE_CNODE) && - (ND_cluster(tx) == ND_cluster(hx))) continue; - (void) model_path(model,tx,hx,e); - } - } - - /* initialize storage for ranks in the model; nodes are installed later */ - GD_minrank(model) = GD_minrank(ug); - GD_maxrank(model) = GD_maxrank(ug); - minr = GD_minrank(model); - maxr = GD_maxrank(model); - ranksize = intarray(minr,maxr); - for (n = agfstnode(model); n; n = agnxtnode(model,n)) - ranksize[ND_rank(n)]++; - GD_rank(model) = T_array(minr,maxr,sizeof(rank_t)); - for (r = minr; r <= maxr; r++) - GD_rank(model)[r].v = N_NEW(ranksize[r]+1,Agnode_t*); /* NIL at end */ - - /* set up mincross running parameters */ - GD_pass(model) = 0; - GD_lastwin(model) = 0; - GD_mintry(model) = gvgetint(ug,"minpass",24); - GD_maxpass(model) = gvgetint(ug,"maxpass",1024); - GD_bestcrossings(model) = MAXINT; - return model; -} - -static Agraph_t *universegraph(Agraph_t *ug) -{ - graph_t *root = ug->root; - graph_t *univ,*model; - if ((model = GD_model(root))) - univ = model->root; - else { - univ = agopen("_universe\001_",AGDIGRAPHSTRICT); - } - return univ; -} - -static void clusterchains(Agraph_t *model, Agraph_t *ug) -{ - if (GD_clusterchainsdone(ug)) return; - if (is_a_cluster(ug)) - (void) model_skel(model,ug); - GD_clusterchainsdone(ug) = TRUE; -} - -static void flat_edges(Agraph_t *clust) -{ -#ifdef NOTDEF - for (n = agfstnode(clust); n; n = agnxtnode(clust)) { - for (e = agfstedge(root,n); e; e = agnxtedge(root,e,n)) { - } - } - ordered_edges(); -#endif -} - -static void search_component(Agraph_t *g, Agnode_t *n, int c) -{ - Agedge_t *e; - ND_component(n) = c; - for (e = agfstout(g,n); e; e = agnxtout(g,e)) - if (ND_component(e->head) < 0) - search_component(g,e->head,c); - for (e = agfstin(g,n); e; e = agnxtin(g,e)) - if (ND_component(e->tail) < 0) - search_component(g,e->tail,c); -} - -static int ND_comp_cmpf(const void *arg0, const void *arg1) -{ - return ND_component(*(Agnode_t**)arg0) - ND_component(*(Agnode_t**)arg1); -} - -static component_t build_components(Agraph_t *g, boolean down) -{ - component_t rv; - node_t *n; - int r, rootcnt, compcnt, deg; - - for (n = agfstnode(g); n; n = agnxtnode(g,n)) - ND_component(n) = -1; /* initialize to unknown component */ - - compcnt = 0; rootcnt = 0; - for (n = agfstnode(g); n; n = agnxtnode(g,n)) { - /* set priority for subsequent BFS to install nodes, and record roots */ - if (down) deg = ND_indeg(n); - else deg = ND_outdeg(n); - ND_priority(n) = deg; - if (deg == 0) rootcnt++; - /* count and mark components */ - if (ND_component(n) < 0) search_component(g,n,compcnt++); - } - - rv.n = compcnt; - rv.r = rootcnt; - rv.root = N_NEW(rv.r,Agnode_t*); - r = 0; - /* install roots in root list */ - for (n = agfstnode(g); n; n = agnxtnode(g,n)) - if (ND_priority(n) == 0) rv.root[r++] = n; - /* sort root list so components are contiguous */ - qsort(rv.root,rv.n,sizeof(node_t*),ND_comp_cmpf); - return rv; -} - -static void install(Agraph_t *g, Agnode_t *n) -{ - int rank; - rank_t *r; - - rank = ND_rank(n); - r = &GD_rank(g)[rank]; - r->v[r->n] = n; - ND_order(n) = r->n++; -} - -/* - populates rank lists of g. there are some key details: - 1) the input graph ordering must be respected (in left to right initialization) - 2) connected components are separated and marked with indices - 3) series-parallel graphs (includes trees, obviously) must not have crossings -*/ -static void build_ranks(Agraph_t *g, boolean down) -{ - queue *q; - component_t c; - int r; - Agnode_t *n; - Agedge_t *e; - - c = build_components(g, down); - - /* process each each component */ - q = new_queue(agnnodes(g)+1); - for (r = 0; r < c.r; r++) { - enqueue(q,c.root[r]); - if ((r + 1 >= c.r)||(ND_component(c.root[r])!=ND_component(c.root[r+1]))) { - while ((n = dequeue(q))) { - install(g,n); - if (down) { - for (e = agfstout(g,n); e; e = agnxtout(g,e)) - if (--ND_priority(e->head) == 0) enqueue(q,e->head); - } - else { - for (e = agfstin(g,n); e; e = agnxtin(g,e)) - if (--ND_priority(e->tail) == 0) enqueue(q,e->head); - } - } - } - } - free_queue(q); -} - -static boolean run(Agraph_t *mg) -{ - if (GD_pass(mg) > GD_maxpass(mg)) return FALSE; - if (GD_pass(mg) - GD_lastwin(mg) > GD_mintry(mg)) return FALSE; - GD_pass(mg) = GD_pass(mg) + 1; - return TRUE; -} - -static void mincross_clust(Agraph_t *ug) -{ - Agraph_t *g; - g = GD_model(ug); - if (run(g)) { - do { - mincross_sweep(g,GD_pass(g)%2,GD_pass(g)%4<2); - } while (run(g)); - transpose_sweep(g,TRUE); - restorebest(g); - } -} - -static void globalopt(Agraph_t *root) -{ - Agraph_t *g; - rank_t *glob; - - g = GD_model(root); - glob = globalize(root,g); - GD_rank(g) = glob; - fprintf(stderr,"%s: %d crossings\n",root->name,crossings(g)); -} - -/* this assumes one level per node - no mega-nodes */ -static void apply_model(Agraph_t *g) -{ - Agnode_t *n; - for (n = agfstnode(g); n; n = agnxtnode(g,n)) - ND_order(n) = ND_order(ND_rep(n)); -} - -/* this is a first cut at a top-level planner. it's lame. */ -static void rec_cluster_run(Agraph_t *ug) -{ - Agraph_t *subg; - - if (is_a_cluster(ug)) mincross_clust(ug); - for (subg = agfstsubg(ug); subg; subg = agnxtsubg(ug,subg)) - rec_cluster_run(subg); - if (is_a_cluster(ug)) mincross_clust(ug); -} - -/* this is the top level mincross entry point */ -void dot_mincross(Agraph_t *user) -{ - rec_cluster_init(user); - rec_cluster_run(user); - globalopt(user); - apply_model(user); -} - -static void invalidate(Agraph_t *g, int rank) -{ - if (rank > GD_minrank(g)) GD_rank(g)[rank-1].crossing_cache.valid = FALSE; - if (rank > GD_minrank(g)) GD_rank(g)[rank-1].candidate = TRUE; - if (rank < GD_maxrank(g)) GD_rank(g)[rank+1].candidate = TRUE; -} - -/* swaps two nodes in the same level */ -static void exchange(Agraph_t *g, Agnode_t *u, Agnode_t *v) -{ - rank_t *r; - int ui,vi,rank; - - assert(ND_rank(u) == ND_rank(v)); - rank = ND_rank(u); - r = &GD_rank(g)[rank]; - ui = ND_order(u); - vi = ND_order(v); - ND_order(v) = ui; - ND_order(u) = vi; - r->v[ND_order(u)] = u; - r->v[ND_order(v)] = v; - r->crossing_cache.valid = FALSE; - r->changed = TRUE; - r->candidate = TRUE; /* old dot had this. i have qualms. sn */ - invalidate(g,rank); -} - -int transpose_onerank(graph_t* g, int r, boolean reverse) -{ - int i,c0,c1,rv; - node_t *v,*w; - - rv = 0; - GD_rank(g)[r].candidate = FALSE; - for (i = 0; i < GD_rank(g)[r].n - 1; i++) { - v = GD_rank(g)[r].v[i]; - w = GD_rank(g)[r].v[i+1]; - assert (ND_order(v) < ND_order(w)); - if (left2right(g,v,w)) continue; - c0 = c1 = 0; - if (r > GD_minrank(g)) { - c0 += in_cross(v,w); - c1 += in_cross(w,v); - } - if (r < GD_maxrank(g)) { - c0 += out_cross(v,w); - c1 += out_cross(w,v); - } - if ((c1 < c0) || ((c0 > 0) && reverse && (c1 == c0))) { - exchange(g,v,w); - rv += (c0 - c1); - } - } - return rv; -} - -static void transpose_sweep(graph_t* g, int reverse) -{ - int r,delta; - - for (r = GD_minrank(g); r <= GD_maxrank(g); r++) - GD_rank(g)[r].candidate = TRUE; - do { - delta = 0; - for (r = GD_minrank(g); r <= GD_maxrank(g); r++) - if (GD_rank(g)[r].candidate) delta += transpose_onerank(g,r,reverse); - } - while (delta >= 1); - /* while (delta > crossings(g)*(1.0 - Convergence));*/ -} - -static void mincross_sweep(graph_t* g, int dir, boolean reverse) -{ - int r,other,low,high,first,last; - int hasfixed; - - low = GD_minrank(g); - high = GD_maxrank(g); - if (dir == 0) return; - if (dir > 0) { first = low + 1; last = high; dir = 1;} /* down */ - else { first = high - 1; last = low; dir = -1;} /* up */ - - for (r = first; r != last + dir; r += dir) { - other = r - dir; - hasfixed = medians(g,r,other); - reorder(g,r,reverse,hasfixed); - } - transpose_sweep(g,NOT(reverse)); - savebest(g); -} - - -static int left2right(graph_t *g, node_t *v, node_t *w) -{ - int rv; - -#ifdef NOTDEF - adjmatrix_t *M; - M = GD_rank(g)[ND_rank(v)].flat; - if (M == NULL) rv = FALSE; - else { - if (GD_flip(g)) {node_t *t = v; v = w; w = t;} - rv = ELT(M,flatindex(v),flatindex(w)); - } -#else - rv = FALSE; -#endif - return rv; -} - -static void build_flat_graphs(graph_t *g) -{ -} - -static int out_cross(node_t *v, node_t *w) -{ - register edge_t *e1,*e2; - register int inv, cross = 0,t; - - for (e2 = agfstout(w->graph,w); e2; e2 = agnxtout(w->graph,e2)) { - register int cnt = ED_xpenalty(e2); - inv = ND_order(e2->head); - for (e1 = agfstout(v->graph,v); e1; e1 = agnxtout(v->graph,e1)) { - t = ND_order(e1->head) - inv; - if ((t > 0) || ((t == 0) && (ED_headport(e1).p.x > ED_headport(e2).p.x))) - cross += ED_xpenalty(e1) * cnt; - } - } - return cross; -} - -static int in_cross(node_t *v,node_t *w) -{ - register edge_t *e1,*e2; - register int inv, cross = 0, t; - - for (e2 = agfstin(w->graph,w); e2; e2 = agnxtin(w->graph,e2)) { - register int cnt = ED_xpenalty(e2); - inv = ND_order(e2->tail); - for (e1 = agfstin(v->graph,v); e1; e1 = agnxtin(v->graph,e1)) { - t = ND_order(e1->tail) - inv; - if ((t > 0) || ((t == 0) && (ED_tailport(e1).p.x > ED_tailport(e2).p.x))) - cross += ED_xpenalty(e1) * cnt; - } - } - return cross; -} - -static int int_cmpf(const void *arg0, const void *arg1) -{ - return *(int*)arg0 - *(int*)arg1; -} - - -/* 8 is the number of bits in port.order, an unsigned char */ -#define VAL(node,port) (((node)->u.order << 8) + (port).order) - -/* - * defines ND_sortweight of each node in r0 w.r.t. r1 - * returns... - */ -static boolean medians(graph_t *g, int r0, int r1) -{ - static int *list; - static int list_extent; - int i,j,lm,rm,lspan,rspan; - node_t *n,**v; - edge_t *e; - boolean hasfixed = FALSE; - - if (list_extent < GD_maxinoutdeg(g)) { - list_extent = GD_maxinoutdeg(g); - if (!list) list = realloc(list,sizeof(list[0])*list_extent); - else list = realloc(list,sizeof(list[0])*list_extent); - } - v = GD_rank(g)[r0].v; - for (i = 0; i < GD_rank(g)[r0].n; i++) { - n = v[i]; j = 0; - if (r1 > r0) for (e = agfstout(g,n); e; e = agnxtout(g,e)) - {if (ED_xpenalty(e) > 0) list[j++] = VAL(e->head,ED_headport(e));} - else for (e = agfstin(g,n); e; e = agnxtin(g,e)) - {if (ED_xpenalty(e) > 0) list[j++] = VAL(e->tail,ED_tailport(e));} - switch(j) { - case 0: - ND_sortweight(n) = -1; /* no neighbor - median undefined */ - break; - case 1: - ND_sortweight(n) = list[0]; - break; - case 2: - ND_sortweight(n) = (list[0] + list[1])/2; - break; - default: - qsort(list,j,sizeof(int),int_cmpf); - if (j % 2) ND_sortweight(n) = list[j/2]; - else { - /* weighted median */ - rm = j/2; - lm = rm - 1; - rspan = list[j-1] - list[rm]; - lspan = list[lm] - list[0]; - if (lspan == rspan) - ND_sortweight(n) = (list[lm] + list[rm])/2; - else { - int w = list[lm]*rspan + list[rm]*lspan; - ND_sortweight(n) = w / (lspan + rspan); - } - } - } - } -#ifdef NOTDEF - /* this code was in the old mincross */ - for (i = 0; i < GD_rank(g)[r0].n; i++) { - n = v[i]; - if ((ND_out(n).size == 0) && (ND_in(n).size == 0)) - hasfixed |= flat_sortweight(n); - } -#endif - return hasfixed; -} - -static void reorder(graph_t *g, int r, boolean reverse, boolean hasfixed) -{ - boolean changed, muststay; - node_t **vlist, **lp, **rp, **ep; - int i; - - changed = FALSE; - vlist = GD_rank(g)[r].v; - ep = &vlist[GD_rank(g)[r].n]; - - for (i = 0; i < GD_rank(g)[r].n; i++) { - lp = &vlist[0]; - /* find leftmost node that can be compared */ - while ((lp < ep) && (ND_sortweight(*lp) < 0)) lp++; - if (lp >= ep) break; - /* find the node that can be compared */ - muststay = FALSE; - for (rp = lp + 1; rp < ep; rp++) { - if (left2right(g,*lp,*rp)) { muststay = TRUE; break; } - if (ND_sortweight(*rp) >= 0) break; /* weight defined; it's comparable */ - } - if (rp >= ep) break; - if (muststay == FALSE) { - register int p1 = ND_sortweight(*lp); - register int p2 = ND_sortweight(*rp); - if ((p1 > p2) || ((p1 == p2) && (reverse))) { - exchange(g,*lp,*rp); - changed = TRUE; - } - } - lp = rp; - if ((hasfixed == FALSE) && (reverse == FALSE)) ep--; - } - - if (changed) { - GD_rank(g)[r].changed = TRUE; - GD_rank(g)[r].crossing_cache.valid = FALSE; - if (r > 0) GD_rank(g)[r-1].crossing_cache.valid = FALSE; - if (r + 1 > GD_rank(g)[r+1].n) GD_rank(g)[r-1].crossing_cache.valid = FALSE; - } -} - -static void savebest(graph_t *g) -{ - int nc; - Agnode_t *n; - - nc = crossings(g); - if (nc < GD_bestcrossings(g)) { - for (n = agfstnode(g); n; n = agnxtnode(g,n)) - ND_saveorder(n) = ND_order(n); - GD_bestcrossings(g) = nc; - GD_lastwin(g) = GD_pass(g); - } -} - -static int ND_order_cmpf(const void *arg0, const void *arg1) -{ - return ND_order(*(Agnode_t**)arg0) - ND_order(*(Agnode_t**)arg1); -} - -static void restorebest(graph_t *g) -{ - Agnode_t *n; - int i; - - for (i = GD_minrank(g); i <= GD_maxrank(g); i++) - GD_rank(g)[i].changed = FALSE; - for (n = agfstnode(g); n; n = agnxtnode(g,n)) { - if (ND_order(n) != ND_saveorder(n)) { - invalidate(g,ND_rank(n)); - GD_rank(g)[i].changed = TRUE; - ND_order(n) = ND_saveorder(n); - } - } - for (i = GD_minrank(g); i <= GD_maxrank(g); i++) { - if (GD_rank(g)[i].changed) - qsort(GD_rank(g)[i].v,GD_rank(g)[i].n,sizeof(Agnode_t*),ND_order_cmpf); - } -} - -static int crossings(graph_t *g) -{ - int i, rv; - - rv = 0; - for (i = GD_minrank(g); i < GD_maxrank(g); i++) { - rv += crossings_below(g,i); - } - return rv; -} - -/* returns level of (model) node's cluster */ -static int lev(Agnode_t *n) -{ - if (!n) return -1; - return (GD_level(ND_cluster(n))); -} - -/* - * allocates a vpath_t per original user edge. later the path - * contents will be set to define vnode chains of intercluster edges. - */ -static void interclusterpaths(Agraph_t *ug, Agraph_t *topmodel) -{ - Agnode_t *n, *n0; - Agedge_t *e, *ue; - vpath_t *p; - - for (n = agfstnode(ug); n; n = agnxtnode(ug,n)) { - for (e = agfstout(ug,n); e; e = agnxtout(ug,e)) { - if (ND_cluster(e->tail) != ND_cluster(e->head)) { - if (!(p = pathsearch(ug,e->tail,e->head))) { - p = newpath(e->tail, e->head); - pathinsert(topmodel->root,p); - } - } - } - } - - /* scan all vnodes of model graph and make decisions */ - for (n = agfstnode(topmodel); n; n = agnxtnode(topmodel,n)) { - if (ND_type(n) == NODETYPE_VNODE) { - ue = ND_erep(n); - p = pathsearch(topmodel->root,ue->tail,ue->head); - if (p) { - if (!(n0 = p->v[ND_rank(n)]) || (lev(n0) < lev(n))) - p->v[ND_rank(n)] = n; - } - } - } - /* need to remove the other edges of these vnodes!! */ -} - -/* build the global (flat) graph of the universe. this is 'flat' -in the sense that there is one data structure for the entire graph -(not 'flat' in the sense of flat edges within the same level.) -*/ -static rank_t *globalize(Agraph_t *user, Agraph_t *topmodel) -{ - rank_t *globrank; - int minr,maxr,r; - - /* setup bookkeeping */ - interclusterpaths(user, topmodel); - - /* allocate global ranks */ - minr = GD_minrank(topmodel); - maxr = GD_maxrank(topmodel); - globrank = T_array(minr,maxr,sizeof(rank_t)); - countup(user,globrank); - for (r = minr; r <= maxr; r++) { - globrank[r].v = N_NEW(globrank[r].n+1,Agnode_t*); /* NIL at end */ - globrank[r].n = 0; /* reset it */ - } - - /* installation */ - for (r = minr; r <= maxr; r++) - installglob(user,topmodel,globrank,r); - - removejunk(user, topmodel); - reconnect(user, topmodel); - - /* optimization */ - return globrank; -} - - -static void countup(Agraph_t *g, rank_t *globr) -{ - Agnode_t *n; - Agedge_t *e; - int r0, r1, low, high, i; - - for (n = agfstnode(g); n; n = agnxtnode(g,n)) { - globr[ND_rank(n)].n += 1; - for (e = agfstout(g,n); e; e = agnxtout(g,e)) { - r0 = ND_rank(e->tail); - r1 = ND_rank(e->head); - low = MIN(r0,r1); - high = MAX(r0,r1); - for (i = low + 1; i < high; i++) - globr[i].n += 1; - } - } -} - -/* install nodes from rank r of (g or its clusters) into globr. */ -static void installglob(Agraph_t *ug, Agraph_t *fromgraph, rank_t *globr, int r) -{ - rank_t *myrank; - int i; - Agnode_t *v; - Agedge_t *uedge; - vpath_t *path; - - if (is_a_cluster(fromgraph)) { - myrank = &GD_rank(fromgraph)[r]; - i = 0; - while ((v = myrank->v[i++])) { - switch (ND_type(v)) { - case NODETYPE_REAL: - /* install primitive nodes */ - globr[r].v[globr[r].n++] = v; - ND_isglobal(v) = TRUE; - break; - case NODETYPE_VNODE: - /* install vnode for non-intercluster edges, and for intercluster - edges if this vnode was chosen as the path representative */ - uedge = ND_erep(v); - path = pathsearch(fromgraph->root,uedge->tail,uedge->head); - if (!path || (path->v[r] == v)) { - globr[r].v[globr[r].n++] = v; - ND_isglobal(v) = TRUE; - } - break; - case NODETYPE_CNODE: - /* install clusters recursively */ - installglob(ug,ND_cluster(v),globr,r); - break; - case NODETYPE_XNODE: - /* we're ignoring these */ - break; - } - } - } -} - -/* - after making the global graph, delete all non-global objects. - */ -static void removejunk(Agraph_t *ug, Agraph_t *topmodel) -{ - Agnode_t *v,*vv; - - for (v = agfstnode(topmodel); v; v = vv) { - vv = agnxtnode(topmodel,v); - if (!ND_isglobal(v)) agdelete(topmodel,v); - } -} - -/* - fix up the user edge paths in the global graph. -*/ -static void reconnect(Agraph_t *ug, Agraph_t *topmodel) -{ - Agnode_t *n, *n0, *n1; - Agedge_t *e, *e0; - vpath_t *p; - int i; - - for (n = agfstnode(ug); n; n = agnxtnode(ug,n)) { - for (e = agfstout(ug,n); e; e = agnxtout(ug,e)) { - if (ND_cluster(e->tail) != ND_cluster(e->head)) { - p = pathsearch(ug,e->tail,e->head); - n0 = p->v[p->low]; - for (i = p->low + 1; i <= p->high; i++) { - n1 = p->v[i]; - if (!(e0 = p->e[i])) e0 = agedge(topmodel,n0,n1); - ED_weight(e0) += ED_weight(e); - ED_xpenalty(e0) += ED_xpenalty(e); - n0 = n1; - } - } - } - } -} - -#ifdef NOTDEF -/* (no parallel edges, all forward edges, flat cycles broken) */ -void build_main_graph(Agraph_t *g) -{ - Agraph_t *gprime,*gprimeflat; - Agnode_t *v,*vprime; - Agedge_t *eprev; - - gprime = agopen("model",AGDIGRAPHSTRICT); - for (v = agfstnode(g); v; v = agnxtnode(g,v)) { - vprime = agnode(gprime,v->name); - for (e = agfstout(v); e; e = agxntout(g,e)) { - tail = e->tail; - head = e->head; - if (ND_rank(tail) > ND_rank(head)) {Agnode_t *t = head; head = tail; tail = t;} - if (!(eprev = agfindedge(gprime,tail,head))) eprev = agedge(gprime,tail,head); - merge(eprev,e); - associate(e,eprev); - } - } - break_cycles(gprime); -} -#endif - -/* I. initialization */ -static void cluster_init(Agraph_t *ug) - -{ - Agraph_t *mg; - scangraph(ug); - mg = cluster_model(ug); - flat_edges(mg); - build_ranks(mg,TRUE); -} - -static void rec_cluster_init(Agraph_t *ug) -{ - Agraph_t *subg; - - if (is_a_cluster(ug)) cluster_init(ug); - for (subg = agfstsubg(ug); subg; subg = agnxtsubg(ug,subg)) - rec_cluster_init(subg); -} diff --git a/lib/dotgen2/t1.c b/lib/dotgen2/t1.c deleted file mode 100644 index 491bffd73..000000000 --- a/lib/dotgen2/t1.c +++ /dev/null @@ -1,8 +0,0 @@ -#include -main() -{ - Vmalloc_t *region; - - region = vmmopen("/tmp/north123",0,1024*1024); - printf("%x\n",malloc(100)); -} diff --git a/lib/dotgen2/t2.c b/lib/dotgen2/t2.c deleted file mode 100644 index b4c788f9e..000000000 --- a/lib/dotgen2/t2.c +++ /dev/null @@ -1,5 +0,0 @@ -main() -{ - - printf("%x\n",sbrk(0)); -} diff --git a/lib/dotgen2/timing.c b/lib/dotgen2/timing.c deleted file mode 100644 index db2bdec76..000000000 --- a/lib/dotgen2/timing.c +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef _WIN32 - -//#include -#include -#include -#include -#ifndef HZ -#define HZ 60 -#endif -typedef struct tms mytime_t; -#define GET_TIME(S) times(&(S)) -#define DIFF_IN_SECS(S,T) ((S.tms_utime + S.tms_stime - T.tms_utime - T.tms_stime)/(double)HZ) - -#else - -#include -typedef clock_t mytime_t; -#define GET_TIME(S) S = clock() -#define DIFF_IN_SECS(S,T) ((S - T) / (double)CLOCKS_PER_SEC) - -#endif - - -static mytime_t T; - -void -start_timer(void) -{ - GET_TIME(T); -} - -double -elapsed_sec(void) -{ - mytime_t S; - double rv; - - GET_TIME(S); - rv = DIFF_IN_SECS(S,T); - return rv; -} diff --git a/lib/dotgen2/trysort.c b/lib/dotgen2/trysort.c deleted file mode 100644 index f81d7c1e4..000000000 --- a/lib/dotgen2/trysort.c +++ /dev/null @@ -1,16 +0,0 @@ -#include "newdot.h" - -typedef struct rsort_s { - unsigned char key[5]; - Agedge_t *e; -} rsort_t; - -main() -{ - Agraph_t *g; - Agnode_t *n; - Agedge_t *e, **edgelist; - g = agread(stdin); - edgelist = alledges(g); - radixsort(edgelist, agnedges(g), 0, endchar); -} diff --git a/lib/dotgen2/xcoord.c b/lib/dotgen2/xcoord.c deleted file mode 100644 index 2818b1b75..000000000 --- a/lib/dotgen2/xcoord.c +++ /dev/null @@ -1,15 +0,0 @@ -void dot_X(Agraph_t *ug) -{ - graph_t *Xg = agopen(AGSTRICTDIRECTED,"constraints"); - - make_nodevars(ug,Xg); - make_edgevars(ug,Xg); - make_clustvars(ug,Xg); - constrain_nodenode(ug,Xg); - constrain_edgelen(ug,Xg); - constraint_nodeclust(ug,Xg); - constraint_clustclust(ug,Xg); - solve(); - read_nodevars(ug,Xg); - read_clustvars(ug,Xg); -} diff --git a/lib/dotgen2/xpos.c b/lib/dotgen2/xpos.c deleted file mode 100644 index cd8f84b4d..000000000 --- a/lib/dotgen2/xpos.c +++ /dev/null @@ -1,135 +0,0 @@ -#include "newdot.h" - -static Agraph_t *constraint_graph(Agraph_t *model); -static void node_separation_constraints(Agraph_t *user); -static void cluster_containment_constraints(Agraph_t *upar, Agraph_t *ug); -static void edge_cost_constraints(Agraph_t *user); - -void dot_position(Agraph_t *user) -{ - Agraph_t *cg; - cg = constraint_graph(user); - node_separation_constraints(user); - cluster_containment_constraints(user); - edge_cost_constraints(user); - rank(cg); - readout(user); - agclose(cg); -} - -static Agraph_t *constraint_graph(Agraph_t *model) -{ - if (!GD_model(model->root)) - GD_model(model->root) = agopen("Xconstraint",AGDIGRAPHSTRICT); - return GD_model(model->root); -} - -static void node_sep(Agraph_t *g, Agnode_t *left, Agnode_t *right) -{ - Agraph_t *Xg; - Agnode_t_ *leftvar; *rightvar; - double d0, d1; - - d0 = ND_xsize(left) / 2.0; - d1 = ND_xsize(right) / 2.0; - /* what about self edge sizes */ - Xg = constraint_graph(g); - leftvar = nodevar(left); - rightvar = nodevar(right); - e = agedge(Xg, leftvar, rightvar); - ED_weight(e) = 0; - ED_minlen(e) = XSCALE(d0 + d1); -} - -/* g is a model graph */ -static void node_separation_constraints(Agraph_t *user) -{ - Agraph_t *g; - rank_t *r; - - g = GD_model(user); - for (i = GD_minrank(g); i <= GD_maxrank(g); i++) { - r = GD_rank(g)[i]; - left = NILnode; - for (j = leftmost(g,r); j <= rightmost(g,r); j++) { - right = r->v[j]; - node_sep(g,left,right); - right = left; - } - } -} - -/* - * this function has to traverse the subgraph hierarchy from the - * user graph because we flattened out the model subgraphs. - */ -static void cluster_containment_constraints(Agraph_t *upar, Agraph_t *ug) -{ - Agraph_t *container; - - if (is_a_cluster(upar) && is_a_cluster(ug)) - cluster_contain(upar,ug); - container = is_a_cluster(ug)? ug : upar; - for (subg = agfstsub(ug); subg; subg = agnxtsubg(ug,subg)) - cluster_containment_constraints(container,subg); -} - -static void cluster_contain(Agraph_t *u_outer, Agraph_t *u_inner) -{ - Agraph_t *Xg; - int sep; - Agnode_t *outer_left, *outer_right, *inner_left, *inner_right; - - sep = user_cluster_sep(u_inner); - Xg = constraint_graph(GD_model(u_outer)); - outer_left = leftvar(GD_model(u_outer)); - outer_right = rightvar(GD_model(u_outer)); - inner_left = leftvar(GD_model(u_inner)); - inner_right = rightvar(GD_model(u_inner)); - clust_sep_edge(outer_left,inner_left); - clust_sep_edge(inner_right,outer_right); -} - -static void clust_sep_edge(Agraph_t *Xg, Agnode_t *left, Agnode_t *right, int sep) -{ - Agedge_t *e; - - e = agedge(Xg, left, right); - ED_weight(e) = 0; - ED_minlen(e) = sep; -} - -static int vedge_cost(int r, int low, int high) -{ - if (low + 1 == high) return SHORT_FACTOR; - if ((r == low) || (r == high)) return LONG_END_FACTOR; - return LONG_FACTOR; -} - -static void edge_cost_constraints(Agraph_t *user) -{ - Agraph_t *model; - Agraph_t *Xg; /* constraints */ - Dict_t *dict; /* set of paths in the model graph */ - vpath_t *p; - - model = GD_model(user); - Xg = constraint_graph(model); - dict = GD_pathdict(model); - for (p = dtfirst(dict); p; p = dtnext(dict,p)) { - v0 = nodevar(p->v[p->low]); - for (i = p->low; i < p->high; i++) { - v1 = nodevar(p->v[i+1]); - vx = agnode(Xg,0); - e0 = agedge(Xg,vx,v0); - e1 = agedge(Xg,vx,v1); - ED_weight(e0) = ED_weight(e1) = p->weight * vedge_factor(i,low,high); - - tp = (i == p->low?) p->tailport : 0; - hp = (i == p->high - 1?) p->headport : 0; - m0 = hp - tp; - if (m0 > 0) ED_minlen(e0) = m0; - else ED_minlen(e1) = -m0; - } - } -} -- 2.40.0