trying to track down who can be called.
ND_ht_i(n) = POINTS(y);
}
-void dot_init_node(node_t * n)
+static void
+dot_init_node(node_t * n)
{
common_init_node(n);
dot_nodesize(n, GD_flip(n->graph));
ND_UF_size(n) = 1;
}
-void dot_init_edge(edge_t * e)
+static void
+dot_init_edge(edge_t * e)
{
char *tailgroup, *headgroup;
ED_minlen(e) = late_int(e, E_minlen, 1, 0);
}
-void dot_init_node_edge(graph_t * g)
+static void
+dot_init_node_edge(graph_t * g)
{
node_t *n;
edge_t *e;
}
#endif
-void dot_cleanup_node(node_t * n)
+static void
+dot_cleanup_node(node_t * n)
{
free_list(ND_in(n));
free_list(ND_out(n));
memset(&(n->u), 0, sizeof(Agnodeinfo_t));
}
-void dot_free_splines(edge_t * e)
+static void
+dot_free_splines(edge_t * e)
{
int i;
if (ED_spl(e)) {
ED_spl(e) = NULL;
}
-void dot_cleanup_edge(edge_t * e)
+static void
+dot_cleanup_edge(edge_t * e)
{
dot_free_splines(e);
free_label(ED_label(e));
}
}
-void dot_cleanup_graph(graph_t * g)
+static void
+dot_cleanup_graph(graph_t * g)
{
int i, c;
graph_t *clust;
dot_cleanup_graph(g);
}
-void dot_init_graph(Agraph_t * g)
+static void
+dot_init_graph(Agraph_t * g)
{
UseRankdir = TRUE;
graph_init(g);
#endif
extern void acyclic(Agraph_t *);
- extern void add_to_component(Agnode_t *);
extern void allocate_ranks(Agraph_t *);
- extern void basic_merge(Agedge_t *, Agedge_t *);
- extern void begin_component(void);
extern void build_ranks(Agraph_t *, int);
extern void build_skeleton(Agraph_t *, Agraph_t *);
extern void class1(Agraph_t *);
extern void class2(Agraph_t *);
- extern void cleanup1(Agraph_t *);
- extern Agnode_t *clone_vn(Agraph_t *, Agnode_t *);
- extern void cluster_leader(Agraph_t *);
- extern void collapse_cluster(Agraph_t *, Agraph_t *);
- extern void collapse_leaves(Agraph_t *);
- extern void collapse_rankset(Agraph_t *, Agraph_t *, int);
- extern void collapse_sets(Agraph_t *);
extern void decompose(Agraph_t *, int);
extern void delete_fast_edge(Agedge_t *);
extern void delete_fast_node(Agraph_t *, Agnode_t *);
extern void delete_flat_edge(Agedge_t *);
- extern void delete_other_edge(Agedge_t *);
- extern void dfs(Agnode_t *);
- extern void do_ordering(Agraph_t *, int);
extern void dot_cleanup(graph_t * g);
- extern void dot_cleanup_edge(edge_t * e);
- extern void dot_cleanup_graph(graph_t * g);
- extern void dot_cleanup_node(node_t * n);
- extern void dot_free_splines(edge_t * e);
- extern void dot_init_node_edge(Agraph_t *);
- extern void dot_init_edge(Agedge_t *);
- extern void dot_init_node(Agnode_t *);
extern void dot_layout(Agraph_t * g);
- extern void dot_init_graph(graph_t * g);
- extern void edgelabel_ranks(Agraph_t *);
- extern void end_component(void);
- extern void exchange(Agnode_t *, Agnode_t *);
extern void expand_cluster(Agraph_t *);
- extern void expand_ranksets(Agraph_t *);
extern Agedge_t *fast_edge(Agedge_t *);
extern void fast_node(Agraph_t *, Agnode_t *);
extern void fast_nodeapp(Agnode_t *, Agnode_t *);
- extern void find_clusters(Agraph_t *);
extern Agedge_t *find_fast_edge(Agnode_t *, Agnode_t *);
- extern Agnode_t *find_fast_node(Agraph_t *, Agnode_t *);
extern Agedge_t *find_flat_edge(Agnode_t *, Agnode_t *);
extern void flat_edge(Agraph_t *, Agedge_t *);
extern int flat_edges(Agraph_t *);
- extern int flat_mval(Agnode_t *);
- extern int in_cross(Agnode_t *, Agnode_t *);
- extern void incr_width(Agraph_t *, Agnode_t *);
- extern int inside_cluster(Agraph_t *, Agnode_t *);
extern void install_cluster(Agraph_t *, Agnode_t *, int, queue *);
extern void install_in_rank(Agraph_t *, Agnode_t *);
- extern void interclexp(Agraph_t *);
- extern void interclrep(Agraph_t *, Agedge_t *);
- extern void interclust1(Agraph_t *, Agnode_t *, Agnode_t *,
- Agedge_t *);
- extern int is_a_normal_node_of(Agraph_t *, Agnode_t *);
- extern int is_a_vnode_of_an_edge_of(Agraph_t *, Agnode_t *);
extern int is_cluster(Agraph_t *);
- extern int is_cluster_edge(Agedge_t *);
- extern int is_fast_node(Agraph_t *, Agnode_t *);
- extern Agnode_t *label_vnode(Agraph_t *, Agedge_t *);
- extern Agnode_t *leader_of(Agraph_t *, Agnode_t *);
- extern int left2right(Agraph_t *, Agnode_t *, Agnode_t *);
- extern int local_cross(elist, int);
extern void dot_compoundEdges(Agraph_t *);
extern Agedge_t *make_aux_edge(Agnode_t *, Agnode_t *, int, int);
- extern void make_chain(Agraph_t *, Agnode_t *, Agnode_t *, Agedge_t *);
- extern void make_interclust_chain(Agraph_t *, Agnode_t *, Agnode_t *,
- Agedge_t *);
- extern int make_new_cluster(Agraph_t *, Agraph_t *);
- extern void make_slots(Agraph_t *, int, int, int);
- extern Agnode_t *map_interclust_node(Agnode_t *);
- extern void map_path(Agnode_t *, Agnode_t *, Agedge_t *, Agedge_t *,
- int);
extern void mark_clusters(Agraph_t *);
extern void mark_lowclusters(Agraph_t *);
extern int mergeable(edge_t * e, edge_t * f);
extern void merge_chain(Agraph_t *, Agedge_t *, Agedge_t *, int);
- extern void merge_components(Agraph_t *);
- extern Agnode_t *merge_leaves(Agraph_t *, Agnode_t *, Agnode_t *);
extern void merge_oneway(Agedge_t *, Agedge_t *);
- extern void merge_ranks(Agraph_t *);
- extern void minmax_edges(Agraph_t *);
extern int ncross(Agraph_t *);
extern Agedge_t *new_virtual_edge(Agnode_t *, Agnode_t *, Agedge_t *);
- extern void node_induce(Agraph_t *, Agraph_t *);
extern int nonconstraint_edge(Agedge_t *);
- extern int ordercmpf(int *, int *);
- extern void ordered_edges(Agraph_t *);
extern void other_edge(Agedge_t *);
- extern int out_cross(Agnode_t *, Agnode_t *);
- extern Agnode_t *plain_vnode(Agraph_t *, Agedge_t *);
extern int portcmp(port p0, port p1);
- extern void potential_leaf(Agraph_t *, Agedge_t *, Agnode_t *);
extern int ports_eq(edge_t *, edge_t *);
- extern void rank1(Agraph_t *);
extern void rank(Agraph_t *, int, int);
- extern int rank_set_class(Agraph_t *);
- extern int rcross(Agraph_t *, int);
extern void rec_reset_vlists(Agraph_t *);
extern void rec_save_vlists(Agraph_t *);
- extern void remove_rankleaders(Agraph_t *);
- extern void renewlist(elist *);
- extern void reorder(Agraph_t *, int, int, int);
extern void reverse_edge(Agedge_t *);
- extern void safe_delete_fast_edge(Agedge_t *);
- extern void safe_list_append(Agedge_t *, elist *);
extern void safe_other_edge(Agedge_t *);
extern void save_vlist(Agraph_t *);
- extern void scan_ranks(Agraph_t *);
- extern void scan_result(void);
- extern void search_component(Agraph_t *, Agnode_t *);
- extern void set_minmax(Agraph_t *);
- extern void setup_page(Agraph_t *, point);
- extern int strccnt(char *, char);
- extern void transpose(Agraph_t *, int);
- extern int transpose_step(Agraph_t *, int, int);
extern void unmerge_oneway(Agedge_t *);
- extern void update(Agedge_t *, Agedge_t *);
- extern void update_bb(Agraph_t *, point);
extern Agedge_t *virtual_edge(Agnode_t *, Agnode_t *, Agedge_t *);
extern Agnode_t *virtual_node(Agraph_t *);
extern void virtual_weight(Agedge_t *);
return ffe(u, ND_out(u), v, ND_in(v));
}
-node_t *find_fast_node(graph_t * g, node_t * n)
+static node_t*
+find_fast_node(graph_t * g, node_t * n)
{
node_t *v;
for (v = GD_nlist(g); v; v = ND_next(v))
}
/* safe_list_append - append e to list L only if e not already a member */
-void safe_list_append(edge_t * e, elist * L)
+static void
+safe_list_append(edge_t * e, elist * L)
{
int i;
zapinlist(&(ND_in(e->head)), e);
}
-void safe_delete_fast_edge(edge_t * e)
+static void
+safe_delete_fast_edge(edge_t * e)
{
int i;
edge_t *f;
safe_list_append(e, &(ND_other(e->tail)));
}
-void delete_other_edge(edge_t * e)
+#ifdef OBSOLETET
+static void
+delete_other_edge(edge_t * e)
{
assert(e != NULL);
zapinlist(&(ND_other(e->tail)), e);
}
+#endif
/* orig might be an input edge, reverse of an input edge, or virtual edge */
edge_t *new_virtual_edge(node_t * u, node_t * v, edge_t * orig)
}
#endif
-void merge_oneway(edge_t * e, edge_t * rep)
-{
- if (rep == ED_to_virt(e)) {
- agerr(AGWARN, "merge_oneway glitch\n");
- return;
- }
- assert(ED_to_virt(e) == NULL);
- ED_to_virt(e) = rep;
- basic_merge(e, rep);
-}
-
-void basic_merge(edge_t * e, edge_t * rep)
+static void
+basic_merge(edge_t * e, edge_t * rep)
{
if (ED_minlen(rep) < ED_minlen(e))
ED_minlen(rep) = ED_minlen(e);
}
}
-static void unrep(edge_t * rep, edge_t * e)
+void
+merge_oneway(edge_t * e, edge_t * rep)
+{
+ if (rep == ED_to_virt(e)) {
+ agerr(AGWARN, "merge_oneway glitch\n");
+ return;
+ }
+ assert(ED_to_virt(e) == NULL);
+ ED_to_virt(e) = rep;
+ basic_merge(e, rep);
+}
+
+static void
+unrep(edge_t * rep, edge_t * e)
{
ED_count(rep) -= ED_count(e);
ED_xpenalty(rep) -= ED_xpenalty(e);
ED_to_virt(e) = NULL;
}
-int is_fast_node(graph_t * g, node_t * v)
+#ifdef OBSOLETET
+static int
+is_fast_node(graph_t * g, node_t * v)
{
node_t *n;
return TRUE;
return FALSE;
}
+#endif
static int *TI_list;
static boolean ReMincross;
+static void
+dumpRanks (graph_t * g)
+{
+ int i, j;
+ node_t* u;
+ rank_t *rank = GD_rank(g);
+ for (i = GD_minrank(g); i <= GD_maxrank(g); i++) {
+ fprintf (stderr, "[%d] :", i);
+ for (j = 0; j < rank[i].n; j++) {
+ u = rank[i].v[j];
+ fprintf (stderr, " %s", u->name);
+
+ }
+ fprintf (stderr, "\n");
+ }
+}
+
void dot_mincross(graph_t * g)
{
int c, nc;
#endif
}
cleanup2(g, nc);
+ dumpRanks (g);
}
static adjmatrix_t *new_matrix(int i, int j)
#define ELT(M,i,j) (M->data[((i)*M->ncols)+(j)])
-static void init_mccomp(graph_t * g, int c)
+static void
+init_mccomp(graph_t * g, int c)
{
int r;
}
}
-static int mincross_clust(graph_t * par, graph_t * g)
+static int betweenclust(edge_t * e)
+{
+ while (ED_to_orig(e))
+ e = ED_to_orig(e);
+ return (ND_clust(e->tail) != ND_clust(e->head));
+}
+
+static void
+do_ordering(graph_t * g, int outflag)
+{
+ int i, ne;
+ node_t *n, *u, *v;
+ edge_t *e, *f, *fe;
+ edge_t **sortlist = TE_list;
+
+ for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
+ if (ND_clust(n))
+ continue;
+ if (outflag) {
+ for (i = ne = 0; (e = ND_out(n).list[i]); i++)
+ if (!betweenclust(e))
+ sortlist[ne++] = e;
+ } else {
+ for (i = ne = 0; (e = ND_in(n).list[i]); i++)
+ if (!betweenclust(e))
+ sortlist[ne++] = e;
+ }
+ if (ne <= 1)
+ continue;
+ /* write null terminator at end of list.
+ requires +1 in TE_list alloccation */
+ sortlist[ne] = 0;
+ qsort(sortlist, ne, sizeof(sortlist[0]), (qsort_cmpf) edgeidcmpf);
+ for (ne = 1; (f = sortlist[ne]); ne++) {
+ e = sortlist[ne - 1];
+ if (outflag) {
+ u = e->head;
+ v = f->head;
+ } else {
+ u = e->tail;
+ v = f->tail;
+ }
+ if (find_flat_edge(u, v))
+ continue;
+ fe = new_virtual_edge(u, v, NULL);
+ ED_edge_type(fe) = FLATORDER;
+ flat_edge(g, fe);
+ }
+ }
+}
+
+static void
+ordered_edges(graph_t * g)
+{
+ char *ordering;
+
+ if ((ordering = agget(g, "ordering"))) {
+ if (streq(ordering, "out"))
+ do_ordering(g, TRUE);
+ else if (streq(ordering, "in"))
+ do_ordering(g, FALSE);
+ else if (ordering[0])
+ agerr(AGERR, "ordering '%s' not recognized.\n", ordering);
+ }
+
+ else {
+ /* search meta-graph to find subgraphs that may be ordered */
+ graph_t *mg, *subg;
+ node_t *mm, *mn;
+ edge_t *me;
+
+ mm = g->meta_node;
+ mg = mm->graph;
+ for (me = agfstout(mg, mm); me; me = agnxtout(mg, me)) {
+ mn = me->head;
+ subg = agusergraph(mn);
+ /* clusters are processed by seperate calls to ordered_edges */
+ if (!is_cluster(subg))
+ ordered_edges(subg);
+ }
+ }
+}
+
+static int
+mincross_clust(graph_t * par, graph_t * g)
{
int c, nc;
return nc;
}
+static int
+left2right(graph_t * g, node_t * v, node_t * w)
+{
+ adjmatrix_t *M;
+ int rv;
+
+ /* CLUSTER indicates orig nodes of clusters, and vnodes of skeletons */
+ if (ReMincross == FALSE) {
+ if ((ND_clust(v) != ND_clust(w)) && (ND_clust(v)) && (ND_clust(w))) {
+ /* the following allows cluster skeletons to be swapped */
+ if ((ND_ranktype(v) == CLUSTER)
+ && (ND_node_type(v) == VIRTUAL))
+ return FALSE;
+ if ((ND_ranktype(w) == CLUSTER)
+ && (ND_node_type(w) == VIRTUAL))
+ return FALSE;
+ return TRUE;
+ /*return ((ND_ranktype(v) != CLUSTER) && (ND_ranktype(w) != CLUSTER)); */
+ }
+ } else {
+ if ((ND_clust(v)) != (ND_clust(w)))
+ return TRUE;
+ }
+ 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));
+ }
+ return rv;
+}
+
+static int
+in_cross(node_t * v, node_t * w)
+{
+ register edge_t **e1, **e2;
+ register int inv, cross = 0, t;
+
+ for (e2 = ND_in(w).list; *e2; e2++) {
+ register int cnt = (*e2)->u.xpenalty;
+ inv = ((*e2)->tail)->u.order;
+
+ for (e1 = ND_in(v).list; *e1; e1++) {
+ t = ((*e1)->tail)->u.order - inv;
+ if ((t > 0)
+ || ((t == 0)
+ && ((*e1)->u.tail_port.p.x > (*e2)->u.tail_port.p.x)))
+ cross += (*e1)->u.xpenalty * cnt;
+ }
+ }
+ return cross;
+}
+
+static int
+out_cross(node_t * v, node_t * w)
+{
+ register edge_t **e1, **e2;
+ register int inv, cross = 0, t;
+
+ for (e2 = ND_out(w).list; *e2; e2++) {
+ register int cnt = (*e2)->u.xpenalty;
+ inv = ((*e2)->head)->u.order;
+
+ for (e1 = ND_out(v).list; *e1; e1++) {
+ t = ((*e1)->head)->u.order - inv;
+ if ((t > 0)
+ || ((t == 0)
+ && ((*e1)->u.head_port.p.x > (*e2)->u.head_port.p.x)))
+ cross += (*e1)->u.xpenalty * cnt;
+ }
+ }
+ return cross;
+
+}
+
+static void
+exchange(node_t * v, node_t * w)
+{
+ int vi, wi, r;
+
+ r = ND_rank(v);
+ vi = ND_order(v);
+ wi = ND_order(w);
+ ND_order(v) = wi;
+ GD_rank(Root)[r].v[wi] = v;
+ ND_order(w) = vi;
+ GD_rank(Root)[r].v[vi] = w;
+}
+
+static int
+transpose_step(graph_t * g, int r, int 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 > 0) {
+ c0 += in_cross(v, w);
+ c1 += in_cross(w, v);
+ }
+ if (GD_rank(g)[r + 1].n > 0) {
+ c0 += out_cross(v, w);
+ c1 += out_cross(w, v);
+ }
+ if ((c1 < c0) || ((c0 > 0) && reverse && (c1 == c0))) {
+ exchange(v, w);
+ rv += (c0 - c1);
+ GD_rank(Root)[r].valid = FALSE;
+ GD_rank(g)[r].candidate = TRUE;
+
+ if (r > GD_minrank(g)) {
+ GD_rank(Root)[r - 1].valid = FALSE;
+ GD_rank(g)[r - 1].candidate = TRUE;
+ }
+ if (r < GD_maxrank(g)) {
+ GD_rank(Root)[r + 1].valid = FALSE;
+ GD_rank(g)[r + 1].candidate = TRUE;
+ }
+ }
+ }
+ return rv;
+}
+
+static void
+transpose(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;
+#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 = GD_minrank(g); r <= GD_maxrank(g); r++)
+ if (GD_rank(g)[r].candidate)
+ delta += transpose_step(g, r, reverse);
+ /*} while (delta > ncross(g)*(1.0 - Convergence)); */
+ } while (delta >= 1);
+}
+
static int mincross(graph_t * g, int startpass, int endpass)
{
int maxthispass, iter, trying, pass;
saveorder(n) = ND_order(n);
}
-/* merge connected components, create globally consistent rank lists */
-static void merge2(graph_t * g)
+/* merges the connected components of g */
+static void
+merge_components(graph_t * g)
{
- int i, r;
- node_t *v;
-
- /* merge the components and rank limits */
- merge_components(g);
+ int c;
+ node_t *u, *v;
- /* install complete ranks */
- for (r = GD_minrank(g); r <= GD_maxrank(g); r++) {
- GD_rank(g)[r].n = GD_rank(g)[r].an;
- GD_rank(g)[r].v = GD_rank(g)[r].av;
- for (i = 0; i < GD_rank(g)[r].n; i++) {
- v = GD_rank(g)[r].v[i];
- if (v == NULL) {
- if (Verbose)
- fprintf(stderr,
- "merge2: graph %s, rank %d has only %d < %d nodes\n",
- g->name, r, i, GD_rank(g)[r].n);
- GD_rank(g)[r].n = i;
- break;
+ if (GD_comp(g).size <= 1)
+ return;
+ u = NULL;
+ for (c = 0; c < GD_comp(g).size; c++) {
+ v = GD_comp(g).list[c];
+ if (u)
+ ND_next(u) = v;
+ ND_prev(v) = u;
+ while (ND_next(v)) {
+ v = ND_next(v);
+ }
+ u = v;
+ }
+ GD_comp(g).size = 1;
+ GD_nlist(g) = GD_comp(g).list[0];
+ GD_minrank(g) = GlobalMinRank;
+ GD_maxrank(g) = GlobalMaxRank;
+}
+
+/* merge connected components, create globally consistent rank lists */
+static void merge2(graph_t * g)
+{
+ int i, r;
+ node_t *v;
+
+ /* merge the components and rank limits */
+ merge_components(g);
+
+ /* install complete ranks */
+ for (r = GD_minrank(g); r <= GD_maxrank(g); r++) {
+ GD_rank(g)[r].n = GD_rank(g)[r].an;
+ GD_rank(g)[r].v = GD_rank(g)[r].av;
+ for (i = 0; i < GD_rank(g)[r].n; i++) {
+ v = GD_rank(g)[r].v[i];
+ if (v == NULL) {
+ if (Verbose)
+ fprintf(stderr,
+ "merge2: graph %s, rank %d has only %d < %d nodes\n",
+ g->name, r, i, GD_rank(g)[r].n);
+ GD_rank(g)[r].n = i;
+ break;
}
ND_order(v) = i;
}
return rv;
}
-int inside_cluster(graph_t * g, node_t * v)
-{
- return (is_a_normal_node_of(g, v) | is_a_vnode_of_an_edge_of(g, v));
-}
-
-int is_a_normal_node_of(graph_t * g, node_t * v)
+static int
+is_a_normal_node_of(graph_t * g, node_t * v)
{
return ((ND_node_type(v) == NORMAL) && agcontains(g, v));
}
-int is_a_vnode_of_an_edge_of(graph_t * g, node_t * v)
+static int
+is_a_vnode_of_an_edge_of(graph_t * g, node_t * v)
{
if ((ND_node_type(v) == VIRTUAL)
&& (ND_in(v).size == 1) && (ND_out(v).size == 1)) {
return FALSE;
}
+static int
+inside_cluster(graph_t * g, node_t * v)
+{
+ return (is_a_normal_node_of(g, v) | is_a_vnode_of_an_edge_of(g, v));
+}
+
static node_t *furthestnode(graph_t * g, node_t * v, int dir)
{
node_t *u, *rv;
}
}
-int left2right(graph_t * g, node_t * v, node_t * w)
-{
- adjmatrix_t *M;
- int rv;
-
- /* CLUSTER indicates orig nodes of clusters, and vnodes of skeletons */
- if (ReMincross == FALSE) {
- if ((ND_clust(v) != ND_clust(w)) && (ND_clust(v)) && (ND_clust(w))) {
- /* the following allows cluster skeletons to be swapped */
- if ((ND_ranktype(v) == CLUSTER)
- && (ND_node_type(v) == VIRTUAL))
- return FALSE;
- if ((ND_ranktype(w) == CLUSTER)
- && (ND_node_type(w) == VIRTUAL))
- return FALSE;
- return TRUE;
- /*return ((ND_ranktype(v) != CLUSTER) && (ND_ranktype(w) != CLUSTER)); */
- }
- } else {
- if ((ND_clust(v)) != (ND_clust(w)))
- return TRUE;
- }
- 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));
- }
- return rv;
-}
-
void allocate_ranks(graph_t * g)
{
int r, low, high, *cn;
free(temprank);
}
-static void mincross_step(graph_t * g, int pass)
+static void
+reorder(graph_t * g, int r, int reverse, int hasfixed)
+{
+ int changed = 0, nelt;
+ boolean muststay, sawclust;
+ node_t **vlist = GD_rank(g)[r].v;
+ node_t **lp, **rp, **ep = vlist + GD_rank(g)[r].n;
+
+ for (nelt = GD_rank(g)[r].n - 1; nelt >= 0; nelt--) {
+ lp = vlist;
+ while (lp < ep) {
+ /* find leftmost node that can be compared */
+ while ((lp < ep) && ((*lp)->u.mval < 0))
+ lp++;
+ if (lp >= ep)
+ break;
+ /* find the node that can be compared */
+ sawclust = muststay = FALSE;
+ for (rp = lp + 1; rp < ep; rp++) {
+ if (sawclust && (*rp)->u.clust)
+ continue; /* ### */
+ if (left2right(g, *lp, *rp)) {
+ muststay = TRUE;
+ break;
+ }
+ if ((*rp)->u.mval >= 0)
+ break;
+ if ((*rp)->u.clust)
+ sawclust = TRUE; /* ### */
+ }
+ if (rp >= ep)
+ break;
+ if (muststay == FALSE) {
+ register int p1 = ((*lp)->u.mval);
+ register int p2 = ((*rp)->u.mval);
+ if ((p1 > p2) || ((p1 == p2) && (reverse))) {
+ exchange(*lp, *rp);
+ changed++;
+ }
+ }
+ lp = rp;
+ }
+ if ((hasfixed == FALSE) && (reverse == FALSE))
+ ep--;
+ }
+
+ if (changed) {
+ GD_rank(Root)[r].valid = FALSE;
+ if (r > 0)
+ GD_rank(Root)[r - 1].valid = FALSE;
+ }
+}
+
+static void
+mincross_step(graph_t * g, int pass)
{
int r, other, first, last, dir;
int hasfixed, reverse;
transpose(g, NOT(reverse));
}
-void transpose(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;
-#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 = GD_minrank(g); r <= GD_maxrank(g); r++)
- if (GD_rank(g)[r].candidate)
- delta += transpose_step(g, r, reverse);
- /*} while (delta > ncross(g)*(1.0 - Convergence)); */
- } while (delta >= 1);
-}
-
-int local_cross(elist l, int dir)
+static int
+local_cross(elist l, int dir)
{
int i, j, is_out;
int cross = 0;
return cross;
}
-int rcross(graph_t * g, int r)
+static int
+rcross(graph_t * g, int r)
{
static int *Count, C;
int top, bot, cross, max, i, k;
return count;
}
-int ordercmpf(int *i0, int *i1)
+static int
+ordercmpf(int *i0, int *i1)
{
return (*i0) - (*i1);
}
-int out_cross(node_t * v, node_t * w)
+static int
+flat_mval(node_t * n)
{
- register edge_t **e1, **e2;
- register int inv, cross = 0, t;
-
- for (e2 = ND_out(w).list; *e2; e2++) {
- register int cnt = (*e2)->u.xpenalty;
- inv = ((*e2)->head)->u.order;
-
- for (e1 = ND_out(v).list; *e1; e1++) {
- t = ((*e1)->head)->u.order - inv;
- if ((t > 0)
- || ((t == 0)
- && ((*e1)->u.head_port.p.x > (*e2)->u.head_port.p.x)))
- cross += (*e1)->u.xpenalty * cnt;
- }
- }
- return cross;
-
-}
-
-int in_cross(node_t * v, node_t * w)
-{
- register edge_t **e1, **e2;
- register int inv, cross = 0, t;
-
- for (e2 = ND_in(w).list; *e2; e2++) {
- register int cnt = (*e2)->u.xpenalty;
- inv = ((*e2)->tail)->u.order;
+ int i;
+ edge_t *e, **fl;
+ node_t *nn;
- for (e1 = ND_in(v).list; *e1; e1++) {
- t = ((*e1)->tail)->u.order - inv;
- if ((t > 0)
- || ((t == 0)
- && ((*e1)->u.tail_port.p.x > (*e2)->u.tail_port.p.x)))
- cross += (*e1)->u.xpenalty * cnt;
+ if ((ND_in(n).size == 0) && (ND_out(n).size == 0)) {
+ if (ND_flat_in(n).size > 0) {
+ fl = ND_flat_in(n).list;
+ nn = fl[0]->tail;
+ for (i = 1; (e = fl[i]); i++)
+ if (ND_order(e->tail) > ND_order(nn))
+ nn = e->tail;
+ ND_mval(n) = ND_mval(nn) + 1;
+ return FALSE;
+ } else if (ND_flat_out(n).size > 0) {
+ fl = ND_flat_out(n).list;
+ nn = fl[0]->head;
+ for (i = 1; (e = fl[i]); i++)
+ if (ND_order(e->head) < ND_order(nn))
+ nn = e->head;
+ ND_mval(n) = ND_mval(nn) - 1;
+ return FALSE;
}
}
- return cross;
+ return TRUE;
}
#define VAL(node,port) (MC_SCALE * (node)->u.order + (port).order)
return hasfixed;
}
-int transpose_step(graph_t * g, int r, int 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 > 0) {
- c0 += in_cross(v, w);
- c1 += in_cross(w, v);
- }
- if (GD_rank(g)[r + 1].n > 0) {
- c0 += out_cross(v, w);
- c1 += out_cross(w, v);
- }
- if ((c1 < c0) || ((c0 > 0) && reverse && (c1 == c0))) {
- exchange(v, w);
- rv += (c0 - c1);
- GD_rank(Root)[r].valid = FALSE;
- GD_rank(g)[r].candidate = TRUE;
-
- if (r > GD_minrank(g)) {
- GD_rank(Root)[r - 1].valid = FALSE;
- GD_rank(g)[r - 1].candidate = TRUE;
- }
- if (r < GD_maxrank(g)) {
- GD_rank(Root)[r + 1].valid = FALSE;
- GD_rank(g)[r + 1].candidate = TRUE;
- }
- }
- }
- return rv;
-}
-
-void exchange(node_t * v, node_t * w)
-{
- int vi, wi, r;
-
- r = ND_rank(v);
- vi = ND_order(v);
- wi = ND_order(w);
- ND_order(v) = wi;
- GD_rank(Root)[r].v[wi] = v;
- ND_order(w) = vi;
- GD_rank(Root)[r].v[vi] = w;
-}
-
-void reorder(graph_t * g, int r, int reverse, int hasfixed)
-{
- int changed = 0, nelt;
- boolean muststay, sawclust;
- node_t **vlist = GD_rank(g)[r].v;
- node_t **lp, **rp, **ep = vlist + GD_rank(g)[r].n;
-
- for (nelt = GD_rank(g)[r].n - 1; nelt >= 0; nelt--) {
- lp = vlist;
- while (lp < ep) {
- /* find leftmost node that can be compared */
- while ((lp < ep) && ((*lp)->u.mval < 0))
- lp++;
- if (lp >= ep)
- break;
- /* find the node that can be compared */
- sawclust = muststay = FALSE;
- for (rp = lp + 1; rp < ep; rp++) {
- if (sawclust && (*rp)->u.clust)
- continue; /* ### */
- if (left2right(g, *lp, *rp)) {
- muststay = TRUE;
- break;
- }
- if ((*rp)->u.mval >= 0)
- break;
- if ((*rp)->u.clust)
- sawclust = TRUE; /* ### */
- }
- if (rp >= ep)
- break;
- if (muststay == FALSE) {
- register int p1 = ((*lp)->u.mval);
- register int p2 = ((*rp)->u.mval);
- if ((p1 > p2) || ((p1 == p2) && (reverse))) {
- exchange(*lp, *rp);
- changed++;
- }
- }
- lp = rp;
- }
- if ((hasfixed == FALSE) && (reverse == FALSE))
- ep--;
- }
-
- if (changed) {
- GD_rank(Root)[r].valid = FALSE;
- if (r > 0)
- GD_rank(Root)[r - 1].valid = FALSE;
- }
-}
-
static int nodeposcmpf(node_t ** n0, node_t ** n1)
{
return ((*n0)->u.order - (*n1)->u.order);
ED_weight(e) *= t;
}
-void ordered_edges(graph_t * g)
-{
- char *ordering;
-
- if ((ordering = agget(g, "ordering"))) {
- if (streq(ordering, "out"))
- do_ordering(g, TRUE);
- else if (streq(ordering, "in"))
- do_ordering(g, FALSE);
- else if (ordering[0])
- agerr(AGERR, "ordering '%s' not recognized.\n", ordering);
- }
-
- else {
- /* search meta-graph to find subgraphs that may be ordered */
- graph_t *mg, *subg;
- node_t *mm, *mn;
- edge_t *me;
-
- mm = g->meta_node;
- mg = mm->graph;
- for (me = agfstout(mg, mm); me; me = agnxtout(mg, me)) {
- mn = me->head;
- subg = agusergraph(mn);
- /* clusters are processed by seperate calls to ordered_edges */
- if (!is_cluster(subg))
- ordered_edges(subg);
- }
- }
-}
-
-static int betweenclust(edge_t * e)
-{
- while (ED_to_orig(e))
- e = ED_to_orig(e);
- return (ND_clust(e->tail) != ND_clust(e->head));
-}
-
-void do_ordering(graph_t * g, int outflag)
-{
- int i, ne;
- node_t *n, *u, *v;
- edge_t *e, *f, *fe;
- edge_t **sortlist = TE_list;
-
- for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
- if (ND_clust(n))
- continue;
- if (outflag) {
- for (i = ne = 0; (e = ND_out(n).list[i]); i++)
- if (!betweenclust(e))
- sortlist[ne++] = e;
- } else {
- for (i = ne = 0; (e = ND_in(n).list[i]); i++)
- if (!betweenclust(e))
- sortlist[ne++] = e;
- }
- if (ne <= 1)
- continue;
- /* write null terminator at end of list.
- requires +1 in TE_list alloccation */
- sortlist[ne] = 0;
- qsort(sortlist, ne, sizeof(sortlist[0]), (qsort_cmpf) edgeidcmpf);
- for (ne = 1; (f = sortlist[ne]); ne++) {
- e = sortlist[ne - 1];
- if (outflag) {
- u = e->head;
- v = f->head;
- } else {
- u = e->tail;
- v = f->tail;
- }
- if (find_flat_edge(u, v))
- continue;
- fe = new_virtual_edge(u, v, NULL);
- ED_edge_type(fe) = FLATORDER;
- flat_edge(g, fe);
- }
- }
-}
-
-/* merges the connected components of g */
-void merge_components(graph_t * g)
-{
- int c;
- node_t *u, *v;
-
- if (GD_comp(g).size <= 1)
- return;
- u = NULL;
- for (c = 0; c < GD_comp(g).size; c++) {
- v = GD_comp(g).list[c];
- if (u)
- ND_next(u) = v;
- ND_prev(v) = u;
- while (ND_next(v)) {
- v = ND_next(v);
- }
- u = v;
- }
- GD_comp(g).size = 1;
- GD_nlist(g) = GD_comp(g).list[0];
- GD_minrank(g) = GlobalMinRank;
- GD_maxrank(g) = GlobalMaxRank;
-}
-
#ifdef DEBUG
void check_rs(graph_t * g, int null_ok)
{
}
}
-int flat_mval(node_t * n)
-{
- int i;
- edge_t *e, **fl;
- node_t *nn;
-
- if ((ND_in(n).size == 0) && (ND_out(n).size == 0)) {
- if (ND_flat_in(n).size > 0) {
- fl = ND_flat_in(n).list;
- nn = fl[0]->tail;
- for (i = 1; (e = fl[i]); i++)
- if (ND_order(e->tail) > ND_order(nn))
- nn = e->tail;
- ND_mval(n) = ND_mval(nn) + 1;
- return FALSE;
- } else if (ND_flat_out(n).size > 0) {
- fl = ND_flat_out(n).list;
- nn = fl[0]->head;
- for (i = 1; (e = fl[i]); i++)
- if (ND_order(e->head) < ND_order(nn))
- nn = e->head;
- ND_mval(n) = ND_mval(nn) - 1;
- return FALSE;
- }
- }
- return TRUE;
-}
-
#ifdef DEBUG
void check_exchange(node_t * v, node_t * w)
{
static void contain_nodes(graph_t * g);
static int idealsize(graph_t * g, double);
+static void
+dumpNS (graph_t * g)
+{
+ node_t* n = GD_nlist(g);
+ elist el;
+ edge_t* e;
+ int i;
+
+ while (n) {
+ el = ND_out(n);
+ for (i = 0; i < el.size; i++) {
+ e = el.list[i];
+ fprintf (stderr, "%s(%x) -> %s(%x) : %d\n", e->tail->name,e->tail, e->head->name, e->head,
+ ED_minlen(e));
+ }
+ n = ND_next(n);
+ }
+}
+
void dot_position(graph_t * g)
{
if (GD_nlist(g) == NULL)
if (flat_edges(g))
set_ycoords(g);
create_aux_edges(g);
+/* dumpNS (g); */
rank(g, 2, nsiter2(g)); /* LR balance == 2 */
set_xcoords(g);
set_aspect(g);
u = rank[i].v[j];
ND_mval(u) = ND_rw_i(u); /* keep it somewhere safe */
if (ND_other(u).size > 0) { /* compute self size */
+ /* FIX: dot assumes all self-edges go to the right. This
+ * is no longer true, though makeSelfEdge still attempts to
+ * put as many as reasonable on the right. The dot code
+ * should be modified to allow a box reflecting the placement
+ * of all self-edges, and use that to reposition the nodes.
+ * Note that this would not only affect left and right
+ * positioning but may also affect interrank spacing.
+ */
sw = 0;
for (k = 0; (e = ND_other(u).list[k]); k++) {
if (e->tail == e->head) {
- sw += SELF_EDGE_SIZE;
- if (ED_label(e)) {
- double label_width;
- label_width =
- GD_flip(g) ? ED_label(e)->dimen.
- y : ED_label(e)->dimen.x;
- sw += label_width;
- }
+ sw += selfRightSpace (e);
}
}
ND_rw_i(u) += sw; /* increment to include self edges */
#include "dot.h"
+static void
+renewlist(elist * L)
+{
+ int i;
+ for (i = L->size; i >= 0; i--)
+ L->list[i] = NULL;
+ L->size = 0;
+}
-void dot_rank(graph_t * g)
+static void
+cleanup1(graph_t * g)
{
- edgelabel_ranks(g);
- collapse_sets(g);
- /*collapse_leaves(g); */
- class1(g);
- minmax_edges(g);
- decompose(g, 0);
- acyclic(g);
- rank1(g);
- expand_ranksets(g);
- cleanup1(g);
+ node_t *n;
+ edge_t *e, *f;
+ int c;
+
+ for (c = 0; c < GD_comp(g).size; c++) {
+ GD_nlist(g) = GD_comp(g).list[c];
+ for (n = GD_nlist(g); n; n = ND_next(n)) {
+ renewlist(&ND_in(n));
+ renewlist(&ND_out(n));
+ ND_mark(n) = FALSE;
+ }
+ }
+ for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
+ for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
+ f = ED_to_virt(e);
+ if (f && (e == ED_to_orig(f))) {
+ /* Null out any other references to f to make sure we don't handle it
+ * a second time. For example, parallel multiedges share a virtual edge.
+ */
+ edge_t *e1, *f1;
+ for (e1 = agfstout(g, n); e1; e1 = agnxtout(g, e1)) {
+ if (e != e1) {
+ f1 = ED_to_virt(e1);
+ if (f1 && (f == f1)) {
+ ED_to_virt(e1) = NULL;
+ }
+ }
+ }
+ free(f);
+ }
+ ED_to_virt(e) = NULL;
+ }
+ }
+ free(GD_comp(g).list);
+ GD_comp(g).list = NULL;
+ GD_comp(g).size = 0;
}
/* When there are edge labels, extra ranks are reserved here for the virtual
* nodes of the labels. This is done by doubling the input edge lengths.
* The input rank separation is adjusted to compensate.
*/
-void edgelabel_ranks(graph_t * g)
+static void
+edgelabel_ranks(graph_t * g)
{
node_t *n;
edge_t *e;
}
}
-/* Run the network simplex algorithm on each component. */
-void rank1(graph_t * g)
-{
- int maxiter = MAXINT;
- int c;
- char *s;
-
- if ((s = agget(g, "nslimit1")))
- maxiter = atof(s) * agnnodes(g);
- for (c = 0; c < GD_comp(g).size; c++) {
- GD_nlist(g) = GD_comp(g).list[c];
- rank(g, (GD_n_cluster(g) == 0 ? 1 : 0), maxiter); /* TB balance */
- }
-}
-
-int is_cluster(graph_t * g)
-{
- return (strncmp(g->name, "cluster", 7) == 0);
-}
-
-int rank_set_class(graph_t * g)
-{
- static char *name[] = { "same", "min", "source", "max", "sink", NULL };
- static int class[] =
- { SAMERANK, MINRANK, SOURCERANK, MAXRANK, SINKRANK, 0 };
- int val;
-
- if (is_cluster(g))
- return CLUSTER;
- val = maptoken(agget(g, "rank"), name, class);
- GD_set_type(g) = val;
- return val;
-}
-
-/* Execute union commands for "same rank" subgraphs and clusters. */
-void collapse_sets(graph_t * g)
-{
- int c;
- graph_t *mg, *subg;
- node_t *mn, *n;
- edge_t *me;
-
- mg = g->meta_node->graph;
- for (me = agfstout(mg, g->meta_node); me; me = agnxtout(mg, me)) {
- mn = me->head;
- subg = agusergraph(mn);
-
- c = rank_set_class(subg);
- if (c) {
- if ((c == CLUSTER) && CL_type == LOCAL)
- collapse_cluster(g, subg);
- else
- collapse_rankset(g, subg, c);
- }
-
- /* mark nodes with ordered edges so their leaves are not collapsed */
- if (agget(subg, "ordering"))
- for (n = agfstnode(subg); n; n = agnxtnode(subg, n))
- ND_order(n) = 1;
- }
-}
-
/* Merge the nodes of a min, max, or same rank set. */
-void collapse_rankset(graph_t * g, graph_t * subg, int kind)
+static void
+collapse_rankset(graph_t * g, graph_t * subg, int kind)
{
node_t *u, *v;
}
}
-node_t *merge_leaves(graph_t * g, node_t * cur, node_t * new)
+static int
+rank_set_class(graph_t * g)
{
- node_t *rv;
+ static char *name[] = { "same", "min", "source", "max", "sink", NULL };
+ static int class[] =
+ { SAMERANK, MINRANK, SOURCERANK, MAXRANK, SINKRANK, 0 };
+ int val;
- if (cur == NULL)
- rv = new;
- else {
- rv = UF_union(cur, new);
- ND_ht_i(rv) = MAX(ND_ht_i(cur), ND_ht_i(new));
- ND_lw_i(rv) = ND_lw_i(cur) + ND_lw_i(new) + GD_nodesep(g) / 2;
- ND_rw_i(rv) = ND_rw_i(cur) + ND_rw_i(new) + GD_nodesep(g) / 2;
- }
- return rv;
+ if (is_cluster(g))
+ return CLUSTER;
+ val = maptoken(agget(g, "rank"), name, class);
+ GD_set_type(g) = val;
+ return val;
}
-void potential_leaf(graph_t * g, edge_t * e, node_t * leaf)
+static int
+make_new_cluster(graph_t * g, graph_t * subg)
{
- node_t *par;
-
- if ((ED_tail_port(e).p.x) || (ED_head_port(e).p.x))
- return;
- if ((ED_minlen(e) != 1) || (ND_order(e->tail) > 0))
- return;
- par = ((leaf != e->head) ? e->head : e->tail);
- ND_ranktype(leaf) = LEAFSET;
- if (par == e->tail)
- GD_outleaf(par) = merge_leaves(g, GD_outleaf(par), leaf);
- else
- GD_inleaf(par) = merge_leaves(g, GD_inleaf(par), leaf);
+ int cno;
+ cno = ++(GD_n_cluster(g));
+ GD_clust(g) = ZALLOC(cno + 1, GD_clust(g), graph_t *, GD_n_cluster(g));
+ GD_clust(g)[cno] = subg;
+ do_graph_label(subg);
+ return cno;
}
-void collapse_leaves(graph_t * g)
+static void
+node_induce(graph_t * par, graph_t * g)
{
- node_t *n;
+ node_t *n, *nn;
edge_t *e;
+ int i;
- for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
-
- /* consider n as a potential leaf of some other node. */
- if ((ND_ranktype(n) != NOCMD) || (ND_order(n)))
+ /* enforce that a node is in at most one cluster at this level */
+ for (n = agfstnode(g); n; n = nn) {
+ nn = agnxtnode(g, n);
+ if (ND_ranktype(n)) {
+ agdelete(g, n);
continue;
- if (agfstout(g, n) == NULL) {
- if ((e = agfstin(g, n)) && (agnxtin(g, e) == NULL)) {
- potential_leaf(g, e, n);
- continue;
- }
}
- if (agfstin(g, n) == NULL) {
- if ((e = agfstout(g, n)) && (agnxtout(g, e) == NULL)) {
- potential_leaf(g, e, n);
- continue;
- }
+ for (i = 1; i < GD_n_cluster(par); i++)
+ if (agcontains(GD_clust(par)[i], n))
+ break;
+ if (i < GD_n_cluster(par))
+ agdelete(g, n);
+ ND_clust(n) = NULL;
+ }
+
+ for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
+ for (e = agfstout(g->root, n); e; e = agnxtout(g->root, e)) {
+ if (agcontains(g, e->head))
+ aginsert(g, e);
}
}
}
-/* To ensure that min and max rank nodes always have the intended rank
- * assignment, reverse any incompatible edges.
- */
-void minmax_edges(graph_t * g)
+static void
+scan_ranks(graph_t * g)
{
- node_t *n;
- edge_t *e;
- int srclen, sinklen;
-
- srclen = sinklen = 0;
- if ((GD_maxset(g) == NULL) && (GD_minset(g) == NULL))
- return;
- if (GD_minset(g) != NULL)
- GD_minset(g) = UF_find(GD_minset(g));
- if (GD_maxset(g) != NULL)
- GD_maxset(g) = UF_find(GD_maxset(g));
-
- if ((n = GD_maxset(g))) {
- sinklen = (GD_maxset(g)->u.ranktype == SINKRANK);
- while ((e = ND_out(n).list[0])) {
- assert(e->head == UF_find(e->head));
- reverse_edge(e);
+ node_t *n, *leader = NULL;
+ GD_minrank(g) = MAXSHORT;
+ GD_maxrank(g) = -1;
+ 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 (leader == NULL)
+ leader = n;
+ else {
+ if (ND_rank(n) < ND_rank(leader))
+ leader = n;
}
}
- if ((n = GD_minset(g))) {
- srclen = (GD_minset(g)->u.ranktype == SOURCERANK);
- while ((e = ND_in(n).list[0])) {
- assert(e->tail == UF_find(e->tail));
- reverse_edge(e);
- }
+ GD_leader(g) = leader;
+}
+
+static void
+cluster_leader(graph_t * clust)
+{
+ node_t *leader, *n;
+ int maxrank = 0;
+
+ /* find number of ranks and select a leader */
+ leader = NULL;
+ for (n = GD_nlist(clust); n; n = ND_next(n)) {
+ if ((ND_rank(n) == 0) && (ND_node_type(n) == NORMAL))
+ leader = n;
+ if (maxrank < ND_rank(n))
+ maxrank = ND_rank(n);
}
+ assert(leader != NULL);
+ GD_leader(clust) = leader;
- for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
- if (n != UF_find(n))
- continue;
- if ((ND_out(n).size == 0) && GD_maxset(g) && (n != GD_maxset(g)))
- virtual_edge(n, GD_maxset(g), NULL)->u.minlen = sinklen;
- if ((ND_in(n).size == 0) && GD_minset(g) && (n != GD_minset(g)))
- virtual_edge(GD_minset(g), n, NULL)->u.minlen = srclen;
+ for (n = agfstnode(clust); n; n = agnxtnode(clust, n)) {
+ assert((ND_UF_size(n) <= 1) || (n == leader));
+ UF_union(n, leader);
+ ND_ranktype(n) = CLUSTER;
}
}
* 3) In class1(), any inter-cluster edges are converted using
* the "virtual node + 2 edges" trick.
*/
-void collapse_cluster(graph_t * g, graph_t * subg)
+static void
+collapse_cluster(graph_t * g, graph_t * subg)
{
if (GD_cluster_was_collapsed(subg))
return;
scan_ranks(subg);
}
-int make_new_cluster(graph_t * g, graph_t * subg)
+/* Execute union commands for "same rank" subgraphs and clusters. */
+static void
+collapse_sets(graph_t * g)
{
- int cno;
- cno = ++(GD_n_cluster(g));
- GD_clust(g) = ZALLOC(cno + 1, GD_clust(g), graph_t *, GD_n_cluster(g));
- GD_clust(g)[cno] = subg;
- do_graph_label(subg);
- return cno;
+ int c;
+ graph_t *mg, *subg;
+ node_t *mn, *n;
+ edge_t *me;
+
+ mg = g->meta_node->graph;
+ for (me = agfstout(mg, g->meta_node); me; me = agnxtout(mg, me)) {
+ mn = me->head;
+ subg = agusergraph(mn);
+
+ c = rank_set_class(subg);
+ if (c) {
+ if ((c == CLUSTER) && CL_type == LOCAL)
+ collapse_cluster(g, subg);
+ else
+ collapse_rankset(g, subg, c);
+ }
+
+ /* mark nodes with ordered edges so their leaves are not collapsed */
+ if (agget(subg, "ordering"))
+ for (n = agfstnode(subg); n; n = agnxtnode(subg, n))
+ ND_order(n) = 1;
+ }
}
-void node_induce(graph_t * par, graph_t * g)
+static void
+find_clusters(graph_t * g)
{
- node_t *n, *nn;
+ graph_t *mg, *subg;
+ node_t *mn;
+ edge_t *me;
+
+ mg = g->meta_node->graph;
+ for (me = agfstout(mg, g->meta_node); me; me = agnxtout(mg, me)) {
+ mn = me->head;
+ subg = agusergraph(mn);
+
+ if (GD_set_type(subg) == CLUSTER)
+ collapse_cluster(g, subg);
+ }
+}
+
+static void
+set_minmax(graph_t * g)
+{
+ int c;
+
+ GD_minrank(g) += GD_leader(g)->u.rank;
+ GD_maxrank(g) += GD_leader(g)->u.rank;
+ for (c = 1; c <= GD_n_cluster(g); c++)
+ set_minmax(GD_clust(g)[c]);
+}
+
+/* To ensure that min and max rank nodes always have the intended rank
+ * assignment, reverse any incompatible edges.
+ */
+static void
+minmax_edges(graph_t * g)
+{
+ node_t *n;
edge_t *e;
- int i;
+ int srclen, sinklen;
- /* enforce that a node is in at most one cluster at this level */
- for (n = agfstnode(g); n; n = nn) {
- nn = agnxtnode(g, n);
- if (ND_ranktype(n)) {
- agdelete(g, n);
- continue;
+ srclen = sinklen = 0;
+ if ((GD_maxset(g) == NULL) && (GD_minset(g) == NULL))
+ return;
+ if (GD_minset(g) != NULL)
+ GD_minset(g) = UF_find(GD_minset(g));
+ if (GD_maxset(g) != NULL)
+ GD_maxset(g) = UF_find(GD_maxset(g));
+
+ if ((n = GD_maxset(g))) {
+ sinklen = (GD_maxset(g)->u.ranktype == SINKRANK);
+ while ((e = ND_out(n).list[0])) {
+ assert(e->head == UF_find(e->head));
+ reverse_edge(e);
+ }
+ }
+ if ((n = GD_minset(g))) {
+ srclen = (GD_minset(g)->u.ranktype == SOURCERANK);
+ while ((e = ND_in(n).list[0])) {
+ assert(e->tail == UF_find(e->tail));
+ reverse_edge(e);
}
- for (i = 1; i < GD_n_cluster(par); i++)
- if (agcontains(GD_clust(par)[i], n))
- break;
- if (i < GD_n_cluster(par))
- agdelete(g, n);
- ND_clust(n) = NULL;
}
for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
- for (e = agfstout(g->root, n); e; e = agnxtout(g->root, e)) {
- if (agcontains(g, e->head))
- aginsert(g, e);
- }
+ if (n != UF_find(n))
+ continue;
+ if ((ND_out(n).size == 0) && GD_maxset(g) && (n != GD_maxset(g)))
+ virtual_edge(n, GD_maxset(g), NULL)->u.minlen = sinklen;
+ if ((ND_in(n).size == 0) && GD_minset(g) && (n != GD_minset(g)))
+ virtual_edge(GD_minset(g), n, NULL)->u.minlen = srclen;
}
}
-void cluster_leader(graph_t * clust)
+/* Run the network simplex algorithm on each component. */
+static void
+rank1(graph_t * g)
{
- node_t *leader, *n;
- int maxrank = 0;
-
- /* find number of ranks and select a leader */
- leader = NULL;
- for (n = GD_nlist(clust); n; n = ND_next(n)) {
- if ((ND_rank(n) == 0) && (ND_node_type(n) == NORMAL))
- leader = n;
- if (maxrank < ND_rank(n))
- maxrank = ND_rank(n);
- }
- assert(leader != NULL);
- GD_leader(clust) = leader;
+ int maxiter = MAXINT;
+ int c;
+ char *s;
- for (n = agfstnode(clust); n; n = agnxtnode(clust, n)) {
- assert((ND_UF_size(n) <= 1) || (n == leader));
- UF_union(n, leader);
- ND_ranktype(n) = CLUSTER;
+ if ((s = agget(g, "nslimit1")))
+ maxiter = atof(s) * agnnodes(g);
+ for (c = 0; c < GD_comp(g).size; c++) {
+ GD_nlist(g) = GD_comp(g).list[c];
+ rank(g, (GD_n_cluster(g) == 0 ? 1 : 0), maxiter); /* TB balance */
}
}
}
}
-void renewlist(elist * L)
+void dot_rank(graph_t * g)
{
- int i;
- for (i = L->size; i >= 0; i--)
- L->list[i] = NULL;
- L->size = 0;
+ edgelabel_ranks(g);
+ collapse_sets(g);
+ /*collapse_leaves(g); */
+ class1(g);
+ minmax_edges(g);
+ decompose(g, 0);
+ acyclic(g);
+ rank1(g);
+ expand_ranksets(g);
+ cleanup1(g);
}
-void cleanup1(graph_t * g)
+int is_cluster(graph_t * g)
{
- node_t *n;
- edge_t *e, *f;
- int c;
-
- for (c = 0; c < GD_comp(g).size; c++) {
- GD_nlist(g) = GD_comp(g).list[c];
- for (n = GD_nlist(g); n; n = ND_next(n)) {
- renewlist(&ND_in(n));
- renewlist(&ND_out(n));
- ND_mark(n) = FALSE;
- }
- }
- for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
- for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
- f = ED_to_virt(e);
- if (f && (e == ED_to_orig(f))) {
- /* Null out any other references to f to make sure we don't handle it
- * a second time. For example, parallel multiedges share a virtual edge.
- */
- edge_t *e1, *f1;
- for (e1 = agfstout(g, n); e1; e1 = agnxtout(g, e1)) {
- if (e != e1) {
- f1 = ED_to_virt(e1);
- if (f1 && (f == f1)) {
- ED_to_virt(e1) = NULL;
- }
- }
- }
- free(f);
- }
- ED_to_virt(e) = NULL;
- }
- }
- free(GD_comp(g).list);
- GD_comp(g).list = NULL;
- GD_comp(g).size = 0;
+ return (strncmp(g->name, "cluster", 7) == 0);
}
-void set_minmax(graph_t * g)
+static node_t*
+merge_leaves(graph_t * g, node_t * cur, node_t * new)
{
- int c;
+ node_t *rv;
- GD_minrank(g) += GD_leader(g)->u.rank;
- GD_maxrank(g) += GD_leader(g)->u.rank;
- for (c = 1; c <= GD_n_cluster(g); c++)
- set_minmax(GD_clust(g)[c]);
+ if (cur == NULL)
+ rv = new;
+ else {
+ rv = UF_union(cur, new);
+ ND_ht_i(rv) = MAX(ND_ht_i(cur), ND_ht_i(new));
+ ND_lw_i(rv) = ND_lw_i(cur) + ND_lw_i(new) + GD_nodesep(g) / 2;
+ ND_rw_i(rv) = ND_rw_i(cur) + ND_rw_i(new) + GD_nodesep(g) / 2;
+ }
+ return rv;
}
-void scan_ranks(graph_t * g)
+static void
+potential_leaf(graph_t * g, edge_t * e, node_t * leaf)
{
- node_t *n, *leader = NULL;
- GD_minrank(g) = MAXSHORT;
- GD_maxrank(g) = -1;
- 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 (leader == NULL)
- leader = n;
- else {
- if (ND_rank(n) < ND_rank(leader))
- leader = n;
- }
- }
- GD_leader(g) = leader;
+ node_t *par;
+
+ if ((ED_tail_port(e).p.x) || (ED_head_port(e).p.x))
+ return;
+ if ((ED_minlen(e) != 1) || (ND_order(e->tail) > 0))
+ return;
+ par = ((leaf != e->head) ? e->head : e->tail);
+ ND_ranktype(leaf) = LEAFSET;
+ if (par == e->tail)
+ GD_outleaf(par) = merge_leaves(g, GD_outleaf(par), leaf);
+ else
+ GD_inleaf(par) = merge_leaves(g, GD_inleaf(par), leaf);
}
-void find_clusters(graph_t * g)
+#ifdef OBSOLETE
+static void
+collapse_leaves(graph_t * g)
{
- graph_t *mg, *subg;
- node_t *mn;
- edge_t *me;
+ node_t *n;
+ edge_t *e;
- mg = g->meta_node->graph;
- for (me = agfstout(mg, g->meta_node); me; me = agnxtout(mg, me)) {
- mn = me->head;
- subg = agusergraph(mn);
+ for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
- if (GD_set_type(subg) == CLUSTER)
- collapse_cluster(g, subg);
+ /* consider n as a potential leaf of some other node. */
+ if ((ND_ranktype(n) != NOCMD) || (ND_order(n)))
+ continue;
+ if (agfstout(g, n) == NULL) {
+ if ((e = agfstin(g, n)) && (agnxtin(g, e) == NULL)) {
+ potential_leaf(g, e, n);
+ continue;
+ }
+ }
+ if (agfstin(g, n) == NULL) {
+ if ((e = agfstout(g, n)) && (agnxtout(g, e) == NULL)) {
+ potential_leaf(g, e, n);
+ continue;
+ }
+ }
}
}
+#endif
+
curve[3].x = ROUND(x2);
curve[3].y = ROUND(y2);
- shape_clip(u, curve, 0);
+ shape_clip(u, curve);
x1 = curve[0].x - ND_coord_i(u).x;
y1 = curve[0].y - ND_coord_i(u).y;
}
prt.theta = 0;
prt.side = 0;
-#ifdef OLD
+#ifdef OBSOLETE
This code appears obsolete and wrong. First, we don't use arr_prt
anymore, as we have previously ifdef'ed out the code below where it
is used. In addition, it resets the rank height. But we've already
for (i = 0; i < l->size; i++) {
e = l->list[i];
arrow_flags(e, &sflag, &eflag);
-#ifndef OLD
+#ifndef OBSOLETE
for (; e; e = ED_to_virt(e)) { /* assign to all virt edges of e */
for (f = e; f;
f = ED_edge_type(f) == VIRTUAL &&