+++ /dev/null
-# $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*
+++ /dev/null
-#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);
-}
+++ /dev/null
-#include "newdot.h"
-#include <math.h>
-
-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);
-}
+++ /dev/null
-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);
+++ /dev/null
-/* 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 <cgraph.h>
-#include <radix.h>
-#include <stdlib.h>
-
-#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<q) firstindex *= 2;
- treesize = 2*firstindex - 1; /* number of tree nodes */
- firstindex -= 1; /* index of leftmost leaf */
- tree = (int *) malloc(treesize*sizeof(int));
- for (t=0; t<treesize; t++) tree[t] = 0;
-
- /* count the crossings */
- crosscount = 0; /* number of crossings */
- for (k=0; k<r; k++) { /* insert edge k */
- index = southsequence[k] + firstindex;
- tree[index]++;
- while (index > 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);
-}
+++ /dev/null
-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 <cgraph.h>
-#include <stdlib.h>
-#include <radix.h>
-
-#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<q) firstindex *= 2;
- treesize = 2*firstindex - 1; /* number of tree nodes */
- firstindex -= 1; /* index of leftmost leaf */
- tree = (int *) malloc(treesize*sizeof(int));
- for (t=0; t<treesize; t++) tree[t] = 0;
-
- /* count the crossings */
- crosscount = 0; /* number of crossings */
- for (k=0; k<r; k++) { /* insert edge k */
- index = southsequence[k] + firstindex;
- tree[index]++;
- while (index > 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);
-}
+++ /dev/null
-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);
-}
+++ /dev/null
-#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; t<north->treesize; 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;
-}
+++ /dev/null
-/* $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();
- }
- }
-}
+++ /dev/null
-/* $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 */
+++ /dev/null
-/* $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
+++ /dev/null
-/* $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;
-}
+++ /dev/null
-/* 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);
-}
+++ /dev/null
-/* $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);
-
- }
-}
-
+++ /dev/null
-/* $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 <minc.h>
-
-extern void createGroups(Agraph_t* g);
-extern void nodesToClusters(Agraph_t* g);
-extern void graphGroups(Agraph_t* sg);
-
-#endif
+++ /dev/null
-/* $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);
-}
+++ /dev/null
-#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;
-}
+++ /dev/null
-#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);
-}
+++ /dev/null
-/* $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
+++ /dev/null
-/* $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 <cairo/cairo.h>
-#include <pango/pangocairo.h>
-#include <png.h>
-
-static int
-writer(void *closure, const unsigned char *data, unsigned int length)
-{
- if (length == fwrite(data, 1, length, (FILE *) closure)) {
- return CAIRO_STATUS_SUCCESS;
- }
-
- return CAIRO_STATUS_WRITE_ERROR;
-}
-
-static void drawMatrix(mcGraph * mcG, char *fileName, char *label)
-{
- int ind = 0;
- mcLevel *l;
- mcLevel *nextl;
- mcNode *n;
- mcNode *nn;
- mcEdge *e;
- int id, idx, id2;
- int x = 0;
- int y = 10;
- int ex = 0;
- int ey = 0;
- FILE *output_file;
- cairo_t *cr;
- int c = 1;
- int rectW = 30;
- int rectH = 30;
- char buf[512];
-
- int verDist = (DOC_HEIGHT - 150) / (mcG->lvl_cnt - 1);
- cairo_surface_t *surface =
- cairo_image_surface_create(CAIRO_FORMAT_ARGB32, DOC_WIDTH + 100,
- DOC_HEIGHT);
- cr = cairo_create(surface);
- cairo_select_font_face(cr, "Arial", CAIRO_FONT_SLANT_NORMAL,
- CAIRO_FONT_WEIGHT_NORMAL);
-
- for (idx = 0; idx < mcG->lvl_cnt; idx++) {
- int crossing = -1;
- l = mcG->lvls[idx];
- c = 1;
-/*
- nextl=dtnext(mcG->levels,l);
- if(nextl)
- {
- crossing=countx(l,nextl);
- sprintf(buf,"cross:(%d)",crossing);
- cairo_set_font_size(cr,(double)16);
- cairo_move_to (cr, 0, y+rectH-3);
- cairo_text_path(cr,buf);
- cairo_stroke (cr);
-
- }
-*/
- for (id = 0; id < l->nodecnt; id++) {
- static flip = 0;
- n = l->nodes[id];
- sprintf(buf, "%s(%0.1f)", agnameof(n->node), n->order);
- x = (DOC_WIDTH / (l->nodecnt + 1)) * c;
- if (n->group)
- cairo_set_source_rgb(cr, 1, 0, 0);
- else
- cairo_set_source_rgb(cr, 0, 0, 0);
-
- cairo_rectangle(cr, x, y, rectW, rectH);
- cairo_set_font_size(cr, (double) 18);
- cairo_move_to(cr, x + 3, y + rectH - 3 + flip * 20);
- cairo_text_path(cr, buf);
- cairo_stroke(cr);
- n->x = x;
- n->y = y;
- c++;
- if (flip == 0)
- flip = 1;
- else
- flip = 0;
- }
- y = y + verDist;
-
- }
- cairo_set_source_rgb(cr, 0, 0, 0);
- cairo_set_font_size(cr, (double) 16);
- cairo_move_to(cr, 0, 30);
- cairo_text_path(cr, label);
- cairo_stroke(cr);
- for (idx = 0; idx < mcG->lvl_cnt; idx++) {
- l = mcG->lvls[idx];
- if (idx < mcG->lvl_cnt - 1)
- nextl = mcG->lvls[idx + 1];
- else
- nextl = NULL;
- for (id = 0; id < l->nodecnt; id++) {
- n = l->nodes[id];
- if (nextl) {
- x = n->x;
- y = n->y;
- for (id2 = 0; id2 < n->high_edgs_cnt; id2++) {
- e = n->high_edgs[id2];
- nn = e->higherN;
- ex = nn->x;
- ey = nn->y;
- cairo_move_to(cr, x + rectW / 2, y + rectH);
- if (e->penalty > 1)
- cairo_set_source_rgb(cr, 1, 0, 0);
- else
- cairo_set_source_rgb(cr, 0, 0, 0);
-
- cairo_line_to(cr, ex, ey);
- cairo_stroke(cr);
- }
- }
- }
-
- }
-
- sprintf(buf, "c:/temp/%s.png", fileName);
- output_file = fopen(buf, "wb+");
-
- if (output_file) {
- cairo_surface_write_to_png_stream(surface, writer, output_file);
- }
- fclose(output_file);
-}
-#endif
-
-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 <l->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));
-}
-
+++ /dev/null
-/* $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;
-}
-
+++ /dev/null
-/*********** external interfaces *********/
-#ifdef NOTDEF
-#include <vmalloc.h>
-#endif
-#include <assert.h>
-#include <string.h>
-//#include <strings.h>
-#include <stdio.h>
-#include <stdlib.h>
-/* #include <values.h> */
-#include <cdt.h>
-#include <cgraph.h>
-#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"
+++ /dev/null
-/* $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 */
+++ /dev/null
-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()
-{
-}
+++ /dev/null
-#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;
-}
+++ /dev/null
-/*
-From: Andre Reinald <Andre.Reinald@vtcom.fr>
-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 <stdlib.h>
-#include <assert.h>
-#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
+++ /dev/null
-typedef struct radixrec_s {
- unsigned long key;
- void *data;
-} radixrec_t;
-
-void radix_sort(radixrec_t *source, unsigned long N);
+++ /dev/null
-#include <stdlib.h>
-#include <assert.h>
-
-// 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);
-}
+++ /dev/null
-/*
- http://www.cubic.org/~submissive/sourcerer/radix.htm
- http://www.cubic.org/~submissive/sourcerer/download/radix_ar_2001.c
-*/
-
-#include <stdlib.h>
-#include <assert.h>
-
-// 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);
-}
+++ /dev/null
-#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);
-}
+++ /dev/null
-#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);
-}
+++ /dev/null
-#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);
-}
+++ /dev/null
-#include <vmalloc.h>
-main()
-{
- Vmalloc_t *region;
-
- region = vmmopen("/tmp/north123",0,1024*1024);
- printf("%x\n",malloc(100));
-}
+++ /dev/null
-main()
-{
-
- printf("%x\n",sbrk(0));
-}
+++ /dev/null
-#ifndef _WIN32
-
-//#include <unistd.h>
-#include <sys/types.h>
-#include <sys/times.h>
-#include <sys/param.h>
-#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 <time.h>
-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;
-}
+++ /dev/null
-#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);
-}
+++ /dev/null
-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);
-}
+++ /dev/null
-#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;
- }
- }
-}