]> granicus.if.org Git - graphviz/commitdiff
break out libns_C.la and libintset_C.la to resolve linker issues on MinGW
authorJohn Ellson <ellson@research.att.com>
Fri, 17 Aug 2012 03:24:47 +0000 (23:24 -0400)
committerJohn Ellson <ellson@research.att.com>
Fri, 17 Aug 2012 03:24:47 +0000 (23:24 -0400)
28 files changed:
cmd/dot/Makefile.am
configure.ac
lib/Makefile.am
lib/common/Makefile.am
lib/common/colxlate.c
lib/common/htmltable.c
lib/common/render.h
lib/dotgen/Makefile.am
lib/dotgen2/level.c
lib/dotgen2/ns.c
lib/expr/exeval.c
lib/fdpgen/tlayout.c
lib/gvc/Makefile.am
lib/intset/Makefile.am [new file with mode: 0644]
lib/intset/intset.c [new file with mode: 0644]
lib/intset/intset.h [new file with mode: 0644]
lib/neatogen/Makefile.am
lib/neatogen/constraint.c
lib/neatogen/neatosplines.c
lib/neatogen/stress.c
lib/neatogen/stuff.c
lib/ns/Makefile.am [new file with mode: 0644]
lib/ns/ns.c [new file with mode: 0644]
lib/ns/ns.h [new file with mode: 0644]
lib/ortho/Makefile.am
lib/ortho/partition.c
plugin/dot_layout/Makefile.am
plugin/neato_layout/Makefile.am

index db6bd7f97261759ae9282fd9c13e123129a943c3..7dcb5d9068fdb410f3dedad229e24d3ec12572d9 100644 (file)
@@ -86,6 +86,8 @@ dot_static_LDADD = \
        $(top_builddir)/plugin/neato_layout/libgvplugin_neato_layout_C.la \
        $(top_builddir)/plugin/core/libgvplugin_core_C.la \
        $(top_builddir)/lib/gvc/libgvc_C.la \
+       $(top_builddir)/lib/ns/libns_C.la \
+       $(top_builddir)/lib/intset/libintset_C.la \
        $(top_builddir)/lib/pathplan/libpathplan_C.la \
        $(top_builddir)/lib/$(GRAPH)/lib$(GRAPH)_C.la \
        $(top_builddir)/lib/xdot/libxdot_C.la \
index 62264d2d3927f3306fa29fce02ad24a88b7b7f25..9f2eee6674d458fda9dcb2e00d12a498eae048aa 100644 (file)
@@ -482,7 +482,7 @@ AC_SUBST([LIBGEN_LIBS])
 # Checks for library functions
 AC_FUNC_ALLOCA
 
-AC_CHECK_FUNCS([lrand48 drand48 srand48 setmode setenv getenv \
+AC_CHECK_FUNCS([lrand48 drand48 srand48 srand rand setmode setenv getenv \
        __freadable _sysconf getrusage strerror cbrt lsqrt vsnprintf \
        strtoul strtoll strtoull uname memset nl_langinfo pow sqrt \
        strchr strdup strerror strstr strtok_r regexec _NSGetEnviron])
@@ -3120,6 +3120,8 @@ AC_CONFIG_FILES(Makefile
        lib/patchwork/Makefile
        lib/pack/Makefile
        lib/ortho/Makefile
+       lib/intset/Makefile
+       lib/ns/Makefile
        lib/expr/Makefile
        lib/expr/libexpr.pc
        lib/common/Makefile
index 792a1342471cf8ae78a9ab443907b6ee481243ac..25e679f728d1f653cbc5c143ad0973bf93848f2d 100644 (file)
@@ -2,8 +2,9 @@
 ## Process this file with automake to produce Makefile.in
 
 SUBDIRS = cdt graph cgraph pathplan sfio vmalloc ast \
-       vpsc rbtree ortho sparse patchwork expr common \
+       vpsc rbtree ns intset ortho sparse patchwork expr common \
        pack xdot label gvc ingraphs topfish glcomp \
-       circogen dotgen dotgen2 fdpgen neatogen twopigen sfdpgen osage gvpr
+       circogen dotgen dotgen2 fdpgen neatogen \
+       twopigen sfdpgen osage gvpr
 
 EXTRA_DIST = Makefile.old gvc.vcproj gvc.def 
index f27e0bd8cab528bb0db0bc92565b19f096c291dd..1c32077481d3c8d39e9d4a12c85f7e7f116e5fbf 100644 (file)
@@ -16,6 +16,8 @@ AM_CPPFLAGS = \
        -I$(top_srcdir)/lib/fdpgen \
        -I$(top_srcdir)/lib/pathplan \
        -I$(top_srcdir)/lib/ast \
+       -I$(top_srcdir)/lib/ns \
+       -I$(top_srcdir)/lib/intset \
        -I$(top_srcdir)/lib/$(GRAPH) \
        -I$(top_srcdir)/lib/cdt $(GD_INCLUDES) $(EXPAT_INCLUDES) $(Z_INCLUDES)
 
@@ -29,13 +31,13 @@ BUILT_SOURCES = colortbl.h ps_font_equiv.h htmlparse.h
 pkginclude_HEADERS = arith.h geom.h color.h types.h textpara.h usershape.h
 noinst_HEADERS = render.h utils.h memory.h \
        geomprocs.h colorprocs.h colortbl.h entities.h globals.h \
-       logic.h const.h macros.h htmllex.h htmltable.h pointset.h intset.h
+       logic.h const.h macros.h htmllex.h htmltable.h pointset.h
 noinst_LTLIBRARIES = libcommon_C.la
 
 libcommon_C_la_SOURCES = arrows.c colxlate.c ellipse.c fontmetrics.c \
        args.c memory.c globals.c htmllex.c htmlparse.y htmltable.c input.c \
-       pointset.c intset.c postproc.c routespl.c splines.c psusershape.c \
-       timing.c labels.c ns.c shapes.c utils.c geom.c taper.c \
+       pointset.c postproc.c routespl.c splines.c psusershape.c \
+       timing.c labels.c shapes.c utils.c geom.c taper.c \
        output.c emit.c ps_font_equiv.txt ps_fontmap.txt fontmap.cfg \
        color_names
 
index 0188d5bdac60c92ee74fb5b084ad626f309e30df..e3b5c217ac1869e8aeb07d0270c0e8162c072b2a 100644 (file)
  * Contributors: See CVS logs. Details at http://www.graphviz.org/
  *************************************************************************/
 
-#include <stdio.h>
-
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
 
+#include <stdio.h>
 #include <stdlib.h>
+
 #ifdef WIN32
 #include <string.h>
 #include <ctype.h>
 #include "compat.h"
 #endif
+
 #include <string.h>
 #include <ctype.h>
 
 #include "colortbl.h"
 #include "memory.h"
 
-static char* colorscheme;
-
-#ifdef WIN32
-extern int strcasecmp(const char *s1, const char *s2);
-extern int strncasecmp(const char *s1, const char *s2, unsigned int n);
+#ifndef HAVE_STRCASECMP
+    extern int strcasecmp(const char *s1, const char *s2);
+#endif
+#ifndef HAVE_STRNCASECMP
+    extern int strncasecmp(const char *s1, const char *s2, size_t n);
 #endif
 
+static char* colorscheme;
 
 static void hsv2rgb(double h, double s, double v,
                        double *r, double *g, double *b)
index 1b56639227946d3deb3f9dea1d7aae7f710267dc..fd525bdbf6996e37e5b53abb642cefd9e5ceef75 100644 (file)
@@ -37,6 +37,7 @@
 #include "agxbuf.h"
 #include "pointset.h"
 #include "intset.h"
+#include "ns.h"
 
 #define DEFAULT_BORDER    1
 #define DEFAULT_CELLPADDING  2
index 4b25a725f862d6e246e9b1a37bd87282a166bc96..a8e2d7157af0f4b3f8824598516edd83e798554a 100644 (file)
@@ -139,7 +139,6 @@ extern "C" {
     extern void addEdgeLabels(graph_t* g, edge_t * e, pointf rp, pointf rq);
     extern void pop_obj_state(GVJ_t *job);
     extern obj_state_t* push_obj_state(GVJ_t *job);
-    extern int rank(graph_t * g, int balance, int maxiter);
     extern port resolvePort(node_t*  n, node_t* other, port* oldport);
     extern void resolvePorts (edge_t* e);
     extern void round_corners(GVJ_t*, pointf*, int, int,int);
index f0e794295becac076fe00029c745337bf9aa472d..a8f9dbfef08ac2ee7833f4c2fd313abfe32e64c5 100644 (file)
@@ -12,6 +12,7 @@ AM_CPPFLAGS = \
         -I$(top_srcdir)/lib/common \
         -I$(top_srcdir)/lib/gvc \
         -I$(top_srcdir)/lib/ortho \
+        -I$(top_srcdir)/lib/ns \
        -I$(top_srcdir)/lib/$(GRAPH) \
        -I$(top_srcdir)/lib/cdt \
        -I$(top_srcdir)/lib/pathplan
@@ -29,8 +30,11 @@ libdotgen_C_la_SOURCES = acyclic.c class1.c class2.c cluster.c compound.c \
        conc.c decomp.c fastgr.c flat.c dotinit.c mincross.c \
        position.c rank.c sameport.c dotsplines.c aspect.c
 
-if WITH_ORTHO
 libdotgen_C_la_DEPENDENCIES = \
+        $(top_builddir)/lib/ns/libns_C.la
+
+if WITH_ORTHO
+libdotgen_C_la_DEPENDENCIES += \
         $(top_builddir)/lib/ortho/libortho_C.la
 endif
 
index 3845cd97e53c4dfb8a0ae2229c402013493ddde6..71df3a887d98312f2323804c1ebeb964f053913a 100644 (file)
@@ -68,7 +68,11 @@ void dot2_levels(graph_t * g)
        ssize = atoi (s);
     else
        ssize = -1;
-    rank2(Xg, 1, INT_MAX, ssize);
+
+/* FIXME - template clashes with the other rank2() in lib/ns/ns.c */
+/*       - work around by renaming to new_rank2()  also in lib/dotgen2/ns.c */
+    new_rank2(Xg, 1, INT_MAX, ssize);
+
     readout_levels(g, Xg);
 }
 
index ed366de7e71462c111d6d2cf858b5b65ae923b87..b04be75a55860b8817da0847d73c2b903f35e29c 100644 (file)
@@ -556,7 +556,9 @@ static int init_graph(graph_t * g)
     return feasible;
 }
 
-void rank2(graph_t * g, int balance, int maxiter, int searchsize)
+/* FIXME - template clashes with the other rank2() in lib/ns/ns.c */
+/*       - work around by renaming to new_rank2()  - also in lib/dotgen2/level.c */
+void new_rank2(graph_t * g, int balance, int maxiter, int searchsize)
 {
     int iter = 0, feasible;
     char *s, *ns = "network simplex: ";
index 29dfaeba0ddb462d60dedfd95dddab2d70b4078d..0a3e3ece87c413c4515face6ed3d334f1ab92bec 100644 (file)
 #include <string.h>
 #include <assert.h>
 #include <time.h>
-#ifdef WIN32
 #include <stdlib.h>
+
+#if !defined(HAVE_SRAND48) && defined(HAVE_SRAND)
 #define srand48 srand
+#endif
+#if !defined(HAVE_DRAND48) && defined(HAVE_RAND)
 #define drand48 rand
 #endif
 
index 9216bc310b5ed029a3da41449d76968857754040..ea7ea0a690576a189f0e4d2bb291db07d3066a44 100644 (file)
 #include <grid.h>
 #include <neato.h>
 
-#ifndef HAVE_SRAND48
+#if !defined(HAVE_SRAND48) && defined(HAVE_SRAND)
 #define srand48 srand
 #endif
-#ifndef HAVE_DRAND48
-extern double drand48(void);
+#if !defined(HAVE_DRAND48) && defined(HAVE_RAND)
+#define drand48 rand
 #endif
 
 #include "tlayout.h"
index c35508a2fbadd21313bb776b496a9f8d9b8222a6..7c48ae2289fe9daf25399369bac090689a329658 100644 (file)
@@ -51,6 +51,8 @@ libgvc_C_la_DEPENDENCIES = \
        $(top_builddir)/lib/pack/libpack_C.la \
        $(top_builddir)/lib/xdot/libxdot_C.la \
        $(top_builddir)/lib/label/liblabel_C.la \
+       $(top_builddir)/lib/ns/libns_C.la \
+       $(top_builddir)/lib/intset/libintset_C.la \
        $(top_builddir)/lib/common/libcommon_C.la
 if ENABLE_LTDL
 libgvc_C_la_LIBADD += @LIBLTDL@ $(LIBLTDL_LDFLAGS)
@@ -63,6 +65,8 @@ libgvc_la_LIBADD = $(libgvc_C_la_LIBADD) \
        $(top_builddir)/lib/cdt/libcdt.la \
        $(top_builddir)/lib/$(GRAPH)/lib$(GRAPH).la \
        $(top_builddir)/lib/pathplan/libpathplan.la \
+       $(top_builddir)/lib/ns/libns_C.la \
+       $(top_builddir)/lib/intset/libintset_C.la \
        $(EXPAT_LIBS) $(Z_LIBS) $(MATH_LIBS)
 libgvc_la_DEPENDENCIES = $(libgvc_C_la_DEPENDENCIES)
 
diff --git a/lib/intset/Makefile.am b/lib/intset/Makefile.am
new file mode 100644 (file)
index 0000000..0b65fcf
--- /dev/null
@@ -0,0 +1,28 @@
+# $Id$Revision: 
+## Process this file with automake to produce Makefile.in
+
+if WITH_CGRAPH
+GRAPH = cgraph
+else
+GRAPH = graph
+endif
+
+AM_CPPFLAGS = \
+        -I$(top_srcdir) \
+        -I$(top_srcdir)/lib/common \
+       -I$(top_srcdir)/lib/gvc \
+       -I$(top_srcdir)/lib/neatogen \
+       -I$(top_srcdir)/lib/pack \
+       -I$(top_srcdir)/lib/pathplan \
+       -I$(top_srcdir)/lib/$(GRAPH) \
+       -I$(top_srcdir)/lib/cdt
+
+AM_CFLAGS = -D_BLD_gvc=1
+
+noinst_HEADERS = intset.h
+noinst_LTLIBRARIES = libintset_C.la
+
+libintset_C_la_SOURCES = intset.c
+
+EXTRA_DIST = 
diff --git a/lib/intset/intset.c b/lib/intset/intset.c
new file mode 100644 (file)
index 0000000..4409370
--- /dev/null
@@ -0,0 +1,76 @@
+/* $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/
+ *************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stddef.h>
+#include <intset.h>
+#include <memory.h>
+
+static Void_t*
+mkIntItem(Dt_t* d,intitem* obj,Dtdisc_t* disc)
+{ 
+    intitem* np = NEW(intitem);
+    np->id = obj->id;
+    return (Void_t*)np;
+}
+
+static void
+freeIntItem(Dt_t* d,intitem* obj,Dtdisc_t* disc)
+{
+    free (obj);
+}
+
+static int
+cmpid(Dt_t* d, int* key1, int* key2, Dtdisc_t* disc)
+{
+  if (*key1 > *key2) return 1;
+  else if (*key1 < *key2) return -1;
+  else return 0;
+}   
+
+static Dtdisc_t intSetDisc = {
+    offsetof(intitem,id),
+    sizeof(int),
+    offsetof(intitem,link),
+    (Dtmake_f)mkIntItem,
+    (Dtfree_f)freeIntItem,
+    (Dtcompar_f)cmpid,
+    0,
+    0,
+    0
+};
+
+Dt_t* 
+openIntSet (void)
+{
+    return dtopen(&intSetDisc,Dtoset);
+}
+
+void 
+addIntSet (Dt_t* is, int v)
+{
+    intitem obj;
+
+    obj.id = v;
+    dtinsert(is, &obj);
+}
+
+int 
+inIntSet (Dt_t* is, int v)
+{
+    return (dtmatch (is, &v) != 0);
+}
+
diff --git a/lib/intset/intset.h b/lib/intset/intset.h
new file mode 100644 (file)
index 0000000..433f897
--- /dev/null
@@ -0,0 +1,27 @@
+/* $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 INTSET_H
+#define INTSET_H
+
+#include <cdt.h>
+
+typedef struct {
+    int       id;
+    Dtlink_t  link;
+} intitem;
+
+extern Dt_t* openIntSet (void);
+extern void addIntSet (Dt_t*, int);
+extern int inIntSet (Dt_t*, int);
+#endif
index deead2ce250482da8a53a3fa1b3811dd86dee390..4f05b2a7a351ed267bfc3cbd881c9a2b593dd6a3 100644 (file)
@@ -14,6 +14,8 @@ AM_CPPFLAGS = \
         -I$(top_srcdir)/lib/pack \
         -I$(top_srcdir)/lib/ortho \
         -I$(top_srcdir)/lib/pathplan \
+        -I$(top_srcdir)/lib/ns \
+        -I$(top_srcdir)/lib/intset \
         -I$(top_srcdir)/lib/$(GRAPH) \
        -I$(top_srcdir)/lib/sparse \
        -I$(top_srcdir)/lib/rbtree \
@@ -45,9 +47,13 @@ libneatogen_C_la_SOURCES = adjust.c circuit.c edges.c geometry.c \
     overlap.c call_tri.c \
        compute_hierarchy.c delaunay.c multispline.c $(WITH_IPSEPCOLA_SOURCES)
 
-if WITH_ORTHO
 libneatogen_C_la_DEPENDENCIES = \
-       $(top_builddir)/lib/ortho/libortho_C.la
+       $(top_builddir)/lib/ns/libns_C.la
+
+if WITH_ORTHO
+libneatogen_C_la_DEPENDENCIES += \
+       $(top_builddir)/lib/ortho/libortho_C.la \
+       $(top_builddir)/lib/intset/libintset_C.la
 endif
 
 EXTRA_DIST = Makefile.old $(IPSEPCOLA_SOURCES) gvneatogen.vcproj
index 578fae6edbb454c4f8b120d21db5893de4f91b84..95891b7d4721d5e2395237cb25fcee4878ede570 100644 (file)
@@ -18,6 +18,7 @@
 
 #include "neato.h"
 #include "adjust.h"
+#include "ns.h"
 
 /* For precision, scale up before algorithms, then scale down */
 #define SCALE 10   
index 0b5b37d8a19d88c0a54fdb9d2a4d3060b3439c00..ca5f82fd76dcf5e281565d485a8e5c969d3289f8 100644 (file)
 #include "pathplan.h"
 #include "vispath.h"
 #include "multispline.h"
-#ifndef HAVE_DRAND48
-extern double drand48(void);
+
+#if !defined(HAVE_SRAND48) && defined(HAVE_SRAND)
+#define srand48 srand
+#endif
+#if !defined(HAVE_DRAND48) && defined(HAVE_RAND)
+#define drand48 rand
 #endif
 
 #ifdef ORTHO
index ba6565783adea73dce8964a2765379988c6778d0..c65267372922a8985a10d99c352233a5e52957c6 100644 (file)
 #include <stdlib.h>
 #include <time.h>
 
-
-#ifndef HAVE_DRAND48
-extern double drand48(void);
+#if !defined(HAVE_SRAND48) && defined(HAVE_SRAND)
+#define srand48 srand
+#endif
+#if !defined(HAVE_DRAND48) && defined(HAVE_RAND)
+#define drand48 rand
 #endif
 
 #define Dij2                   /* If defined, the terms in the stress energy are normalized 
index 7277da4965219b12257031a50f9f22b7188c4c6f..8ddeacd1381ade59a2d850eb6a08c52b49826a52 100644 (file)
 #include       <unistd.h>
 #endif
 
+#if !defined(HAVE_SRAND48) && defined(HAVE_SRAND)
+#define srand48 srand
+#endif
+#if !defined(HAVE_DRAND48) && defined(HAVE_RAND)
+#define drand48 rand
+#endif
+
 static double Epsilon2;
 
 
diff --git a/lib/ns/Makefile.am b/lib/ns/Makefile.am
new file mode 100644 (file)
index 0000000..b00d03e
--- /dev/null
@@ -0,0 +1,28 @@
+# $Id$Revision: 
+## Process this file with automake to produce Makefile.in
+
+if WITH_CGRAPH
+GRAPH = cgraph
+else
+GRAPH = graph
+endif
+
+AM_CPPFLAGS = \
+        -I$(top_srcdir) \
+        -I$(top_srcdir)/lib/common \
+       -I$(top_srcdir)/lib/gvc \
+       -I$(top_srcdir)/lib/neatogen \
+       -I$(top_srcdir)/lib/pack \
+       -I$(top_srcdir)/lib/pathplan \
+       -I$(top_srcdir)/lib/$(GRAPH) \
+       -I$(top_srcdir)/lib/cdt
+
+AM_CFLAGS = -D_BLD_gvc=1
+
+noinst_HEADERS = ns.h
+noinst_LTLIBRARIES = libns_C.la
+
+libns_C_la_SOURCES = ns.c
+
+EXTRA_DIST = 
diff --git a/lib/ns/ns.c b/lib/ns/ns.c
new file mode 100644 (file)
index 0000000..2b11449
--- /dev/null
@@ -0,0 +1,951 @@
+/* $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 <setjmp.h>
+#include "ns.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);
+#ifdef DEBUG
+static void check_cycles(graph_t * g);
+#endif
+
+#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 jmp_buf jbuf;
+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 nlist_t Tree_node;
+static elist Tree_edge;
+
+static void add_tree_edge(edge_t * e)
+{
+    node_t *n;
+    if (TREE_EDGE(e)) {
+       agerr(AGERR, "add_tree_edge: missing tree edge\n");
+       longjmp (jbuf, 1);
+    }
+    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;
+    if (ND_out(n).list[ND_tree_out(n).size - 1] == 0) {
+       agerr(AGERR, "add_tree_edge: empty outedge list\n");
+       longjmp (jbuf, 1);
+    }
+    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;
+    if (ND_in(n).list[ND_tree_in(n).size - 1] == 0) {
+       agerr(AGERR, "add_tree_edge: empty inedge list\n");
+       longjmp (jbuf, 1);
+    }
+}
+
+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 i, ctr;
+    nodequeue *Q;
+    node_t *v;
+    edge_t *e;
+
+    Q = new_queue(N_nodes);
+    ctr = 0;
+
+    for (v = GD_nlist(G); v; v = ND_next(v)) {
+       if (ND_priority(v) == 0)
+           enqueue(Q, v);
+    }
+
+    while ((v = dequeue(Q))) {
+       ND_rank(v) = 0;
+       ctr++;
+       for (i = 0; (e = ND_in(v).list[i]); i++)
+           ND_rank(v) = MAX(ND_rank(v), ND_rank(agtail(e)) + ED_minlen(e));
+       for (i = 0; (e = ND_out(v).list[i]); i++) {
+           if (--(ND_priority(aghead(e))) <= 0)
+               enqueue(Q, aghead(e));
+       }
+    }
+    if (ctr != N_nodes) {
+       agerr(AGERR, "trouble in init_rank\n");
+       for (v = GD_nlist(G); v; v = ND_next(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 (i = 0; (e = ND_out(v).list[i]); i++) {
+       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 (i = 0; (e = ND_in(v).list[i]); i++) {
+       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)
+{
+    int i;
+    edge_t *e;
+
+    for (i = 0; (e = ND_out(v).list[i]); i++) {
+       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 (i = 0; (e = ND_in(v).list[i]); i++) {
+       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 = GD_nlist(G); n; n = ND_next(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 = GD_nlist(G); n && (Tree_edge.size == 0); n = ND_next(n))
+       treesearch(n);
+    return Tree_node.size;
+}
+
+static void init_cutvalues(void)
+{
+    dfs_range(GD_nlist(G), NULL, 1);
+    dfs_cutval(GD_nlist(G), NULL);
+}
+
+static int feasible_tree(void)
+{
+    int i, delta;
+    node_t *n;
+    edge_t *e, *f;
+
+    if (N_nodes <= 1)
+       return 0;
+    while (tight_tree() < N_nodes) {
+       e = NULL;
+       for (n = GD_nlist(G); n; n = ND_next(n)) {
+           for (i = 0; (f = ND_out(n).list[i]); i++) {
+               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 = GD_nlist(G); n; n = ND_next(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", n->name);
+           }
+#endif
+           return 1;
+       }
+    }
+    init_cutvalues();
+    return 0;
+}
+
+/* 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) {
+       agerr(AGERR, "update: mismatched lca in treeupdates\n");
+       longjmp (jbuf, 1);
+    }
+    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 = GD_nlist(G); n; n = ND_next(n)) {
+       if (ND_node_type(n) == NORMAL) {
+           Minrank = MIN(Minrank, ND_rank(n));
+           Maxrank = MAX(Maxrank, ND_rank(n));
+       }
+    }
+    if (Minrank != 0) {
+       for (n = GD_nlist(G); n; n = ND_next(n))
+           ND_rank(n) -= Minrank;
+       Maxrank -= Minrank;
+       Minrank = 0;
+    }
+}
+
+static void
+freeTreeList (graph_t* g)
+{
+    node_t *n;
+    for (n = GD_nlist(G); n; n = ND_next(n)) {
+       free_list(ND_tree_in(n));
+       free_list(ND_tree_out(n));
+       ND_mark(n) = FALSE;
+    }
+}
+
+static void LR_balance(void)
+{
+    int i, delta;
+    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);
+       }
+    }
+    freeTreeList (G);
+}
+
+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 = GD_nlist(G); n; n = ND_next(n))
+       if (ND_node_type(n) == NORMAL)
+           nrank[ND_rank(n)]++;
+    for (n = GD_nlist(G); n; n = ND_next(n)) {
+       if (ND_node_type(n) != NORMAL)
+           continue;
+       inweight = outweight = 0;
+       low = 0;
+       high = Maxrank;
+       for (i = 0; (e = ND_in(n).list[i]); i++) {
+           inweight += ED_weight(e);
+           low = MAX(low, ND_rank(agtail(e)) + ED_minlen(e));
+       }
+       for (i = 0; (e = ND_out(n).list[i]); i++) {
+           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 = GD_nlist(g); n; n = ND_next(n)) {
+       ND_mark(n) = FALSE;
+       N_nodes++;
+       for (i = 0; (e = ND_out(n).list[i]); i++)
+           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 = GD_nlist(g); n; n = ND_next(n)) {
+       ND_priority(n) = 0;
+       for (i = 0; (e = ND_in(n).list[i]); 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 (i = 0; (e = ND_out(n).list[i]); i++);
+       ND_tree_out(n).list = N_NEW(i + 1, edge_t *);
+       ND_tree_out(n).size = 0;
+    }
+    return feasible;
+}
+
+/* graphSize:
+ * Compute no. of nodes and edges in the graph
+ */
+static void
+graphSize (graph_t * g, int* nn, int* ne)
+{
+    int i, nnodes, nedges;
+    node_t *n;
+    edge_t *e;
+   
+    nnodes = nedges = 0;
+    for (n = GD_nlist(g); n; n = ND_next(n)) {
+       nnodes++;
+       for (i = 0; (e = ND_out(n).list[i]); i++) {
+           nedges++;
+       }
+    }
+    *nn = nnodes;
+    *ne = nedges;
+}
+
+/* rank:
+ * Apply network simplex to rank the nodes in a graph.
+ * Uses ED_minlen as the internode constraint: if a->b with minlen=ml,
+ * rank b - rank a >= ml.
+ * Assumes the graph has the following additional structure:
+ *   A list of all nodes, starting at GD_nlist, and linked using ND_next.
+ *   Out and in edges lists stored in ND_out and ND_in, even if the node
+ *  doesn't have any out or in edges.
+ * The node rank values are stored in ND_rank.
+ * Returns 0 if successful; returns 1 if `he graph was not connected;
+ * returns 2 if something seriously wrong;
+ */
+int rank2(graph_t * g, int balance, int maxiter, int search_size)
+{
+    int iter = 0, feasible;
+    char *ns = "network simplex: ";
+    edge_t *e, *f;
+
+#ifdef DEBUG
+    check_cycles(g);
+#endif
+    if (Verbose) {
+       int nn, ne;
+       graphSize (g, &nn, &ne);
+       fprintf(stderr, "%s %d nodes %d edges maxiter=%d balance=%d\n", ns,
+           nn, ne, maxiter, balance);
+       start_timer();
+    }
+    feasible = init_graph(g);
+    if (!feasible)
+       init_rank();
+    if (maxiter <= 0) {
+       freeTreeList (g);
+       return 0;
+    }
+
+    if (search_size >= 0)
+       Search_size = search_size;
+    else
+       Search_size = SEARCHSIZE;
+
+    if (setjmp (jbuf)) {
+       return 2;
+    }
+
+    if (feasible_tree()) {
+       freeTreeList (g);
+       return 1;
+    }
+    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();
+       freeTreeList (G);
+       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());
+    }
+    return 0;
+}
+
+int rank(graph_t * g, int balance, int maxiter)
+{
+    char *s;
+    int search_size;
+
+    if ((s = agget(g, "searchsize")))
+       search_size = atoi(s);
+    else
+       search_size = SEARCHSIZE;
+
+    return rank2 (g, balance, maxiter, search_size);
+}
+
+/* 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 i, 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 (i = 0; (e = ND_out(v).list[i]); i++)
+       sum += x_val(e, v, dir);
+    for (i = 0; (e = ND_in(v).list[i]); i++)
+       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)
+               fprintf(stderr, "not a tight tree %p", e);
+       }
+    }
+    if ((n_cnt != Tree_node.size) || (e_cnt != Tree_edge.size))
+       fprintf(stderr, "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();
+    }
+    fprintf(stderr, "%d %d %d\n", Tree_edge.size, n, m);
+}
+
+void check_fast_node(node_t * n)
+{
+    node_t *nptr;
+    nptr = GD_nlist(agraphof(n));
+    while (nptr && nptr != n)
+       nptr = ND_next(nptr);
+    assert(nptr != NULL);
+}
+
+static void dump_graph (graph_t* g)
+{
+    int i;
+    edge_t *e;
+    node_t *n,*w;
+    FILE* fp = fopen ("ns.gv", "w");
+    fprintf (fp, "digraph %s {\n", g->name);
+    for (n = GD_nlist(g); n; n = ND_next(n)) {
+       if (streq(n->name,"virtual"))
+           fprintf (fp, "  \"%p\"\n", n);
+       else
+           fprintf (fp, "  \"%s\"\n", n->name);
+    }
+    for (n = GD_nlist(g); n; n = ND_next(n)) {
+       for (i = 0; (e = ND_out(n).list[i]); i++) {
+           if (streq(n->name,"virtual"))
+               fprintf (fp, "  \"%p\"", n);
+           else
+               fprintf (fp, "  \"%s\"", n->name);
+           w = aghead(e);
+           if (streq(w->name,"virtual"))
+               fprintf (fp, " -> \"%p\"\n", w);
+           else
+               fprintf (fp, " -> \"%s\"\n", w->name);
+       }
+    }
+
+    fprintf (fp, "}\n");
+    fclose (fp);
+}
+
+static node_t *checkdfs(graph_t* g, node_t * n)
+{
+    edge_t *e;
+    node_t *w,*x;
+    int i;
+
+    if (ND_mark(n))
+       return 0;
+    ND_mark(n) = TRUE;
+    ND_onstack(n) = TRUE;
+    for (i = 0; (e = ND_out(n).list[i]); i++) {
+       w = aghead(e);
+       if (ND_onstack(w)) {
+           dump_graph (g);
+           fprintf(stderr, "cycle: last edge %lx %s(%lx) %s(%lx)\n",
+               (unsigned long int)e,
+               agnameof(n), (unsigned long int)n,
+               agnameof(w), (unsigned long int)w);
+           return w;
+       }
+       else {
+           if (ND_mark(w) == FALSE) {
+               x = checkdfs(g, w);
+               if (x) {
+                   fprintf(stderr,"unwind %lx %s(%lx)\n",
+                       (unsigned long int)e,
+                       agnameof(n), (unsigned long int)n);
+                   if (x != n) return x;
+                   fprintf(stderr,"unwound to root\n");
+                   fflush(stderr);
+                   abort();
+                   return 0;
+               }
+           }
+       }
+    }
+    ND_onstack(n) = FALSE;
+    return 0;
+}
+
+void check_cycles(graph_t * g)
+{
+    node_t *n;
+    for (n = GD_nlist(g); n; n = ND_next(n))
+       ND_mark(n) = ND_onstack(n) = FALSE;
+    for (n = GD_nlist(g); n; n = ND_next(n))
+       checkdfs(g, n);
+}
+#endif                         /* DEBUG */
diff --git a/lib/ns/ns.h b/lib/ns/ns.h
new file mode 100644 (file)
index 0000000..0111ed4
--- /dev/null
@@ -0,0 +1,17 @@
+/*************************************************************************
+ * 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 NS_H
+#define NS_H
+
+extern int rank(graph_t * g, int balance, int maxiter);
+extern int rank2(graph_t * g, int balance, int maxiter, int search_size);
+
+#endif
index dc5a52e46bcf01afbc7afef9a4664508f5189e14..33256c338af9a30c3f6666bd1a15b98b72ccc897 100644 (file)
@@ -14,6 +14,8 @@ AM_CPPFLAGS = \
        -I$(top_srcdir)/lib/neatogen \
        -I$(top_srcdir)/lib/pack \
        -I$(top_srcdir)/lib/pathplan \
+       -I$(top_srcdir)/lib/ns \
+       -I$(top_srcdir)/lib/intset \
        -I$(top_srcdir)/lib/$(GRAPH) \
        -I$(top_srcdir)/lib/cdt
 
index 0223f3508edf82fdefa2101af5554fc00db186f0..12acf201b6776069cd4dd46966ff9b96239f92e7 100644 (file)
 #define CROSS_SINE(v0, v1) ((v0).x * (v1).y - (v1).x * (v0).y)
 #define LENGTH(v0) (sqrt((v0).x * (v0).x + (v0).y * (v0).y))
 
-#ifndef HAVE_SRAND48
+#if !defined(HAVE_SRAND48) && defined(HAVE_SRAND)
 #define srand48 srand
 #endif
-#ifndef HAVE_DRAND48
+#if !defined(HAVE_DRAND48) && defined(HAVE_RAND)
 #define drand48 rand
 #endif
 
index 7d03d722b4c198fad136efc9732cd52209c29802..df131e0529c866ff3ca69de36ad9470bfe25b21d 100644 (file)
@@ -37,6 +37,8 @@ libgvplugin_dot_layout_la_LIBADD = $(libgvplugin_dot_layout_C_la_LIBADD) \
        $(top_builddir)/lib/gvc/libgvc.la \
        $(top_builddir)/lib/$(GRAPH)/lib$(GRAPH).la \
        $(top_builddir)/lib/cdt/libcdt.la \
+       $(top_builddir)/lib/ns/libns_C.la \
+       $(top_builddir)/lib/intset/libintset_C.la \
        $(top_builddir)/lib/pathplan/libpathplan.la $(MATH_LIBS)
        
 if WITH_ORTHO
@@ -46,7 +48,8 @@ endif
 
 if WITH_WIN32
 libgvplugin_dot_layout_la_LDFLAGS += -no-undefined
-libgvplugin_dot_layout_la_LIBADD += $(top_builddir)/lib/$(GRAPH)/lib$(GRAPH).la
+libgvplugin_dot_layout_la_LIBADD += 
+       $(top_builddir)/lib/$(GRAPH)/lib$(GRAPH).la
 endif
 
 if WITH_DARWIN9
index 2c019c46a3211364fa757c41e86d8a3f8530ad94..2682715be5610a58d866ab98d6d26566e46e3689 100644 (file)
@@ -31,6 +31,7 @@ libgvplugin_neato_layout_C_la_LIBADD = \
        $(top_builddir)/lib/neatogen/libneatogen_C.la \
        $(top_builddir)/lib/twopigen/libtwopigen_C.la \
        $(top_builddir)/lib/patchwork/libpatchwork_C.la \
+        $(top_builddir)/lib/intset/libintset_C.la \
        $(top_builddir)/lib/osage/libosage_C.la \
        $(top_builddir)/lib/fdpgen/libfdpgen_C.la \
        $(top_builddir)/lib/sparse/libsparse_C.la \
@@ -43,6 +44,7 @@ libgvplugin_neato_layout_la_LIBADD = $(libgvplugin_neato_layout_C_la_LIBADD) \
        $(top_builddir)/lib/gvc/libgvc.la \
        $(top_builddir)/lib/$(GRAPH)/lib$(GRAPH).la \
        $(top_builddir)/lib/cdt/libcdt.la \
+       $(top_builddir)/lib/ns/libns_C.la \
        $(top_builddir)/lib/pathplan/libpathplan.la \
        $(GTS_LIBS) $(IPSEPCOLA_LIBS) $(MATH_LIBS)
        
@@ -52,12 +54,15 @@ libgvplugin_neato_layout_la_LIBADD += \
 endif
 
 if WITH_SFDP
-libgvplugin_neato_layout_C_la_LIBADD += $(top_builddir)/lib/sfdpgen/libsfdpgen_C.la
+libgvplugin_neato_layout_C_la_LIBADD += \
+       $(top_builddir)/lib/sfdpgen/libsfdpgen_C.la
 endif
 
 if WITH_WIN32
 libgvplugin_neato_layout_la_LDFLAGS += -no-undefined
-libgvplugin_neato_layout_la_LIBADD += $(top_builddir)/lib/$(GRAPH)/lib$(GRAPH).la $(top_builddir)/lib/cdt/libcdt.la
+libgvplugin_neato_layout_la_LIBADD += \
+       $(top_builddir)/lib/$(GRAPH)/lib$(GRAPH).la \
+       $(top_builddir)/lib/cdt/libcdt.la
 endif
 
 if WITH_DARWIN9