Beispiel #1
0
static void 
cleanup1(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);
	    /* 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.
	     */
	    if (f && (e == ED_to_orig(f))) {
		edge_t *e1, *f1;
#ifndef WITH_CGRAPH
		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;
			}
		    }
		}
#else
		node_t *n1;
		for (n1 = agfstnode(g); n1; n1 = agnxtnode(g, n1)) {
		    for (e1 = agfstout(g, n1); e1; e1 = agnxtout(g, e1)) {
			if (e != e1) {
			    f1 = ED_to_virt(e1);
			    if (f1 && (f == f1)) {
				ED_to_virt(e1) = NULL;
			    }
			}
		    }
		}
		free(f->base.data);
#endif
		free(f);
	    }
	    ED_to_virt(e) = NULL;
	}
    }
    free(GD_comp(g).list);
    GD_comp(g).list = NULL;
    GD_comp(g).size = 0;
}
Beispiel #2
0
void fast_node(graph_t *g, Agnode_t *n)
{

#ifdef DEBUG
	assert (find_fast_node(g,n) == NULL);
#endif
	ND_next(n) = GD_nlist(g);
	if (ND_next(n)) ND_next(n)->u.prev = n;
	GD_nlist(g) = n;
	ND_prev(n) = NULL;
	assert (n != ND_next(n));
}
Beispiel #3
0
void fastgr(graph_t * g)
{
    int i, j;
    node_t *n, *w;
    edge_t *e, *f;

    for (n = GD_nlist(g); n; n = ND_next(n)) {
	fprintf(stderr, "%s %d: (", NAME(n), ND_rank(n));
	for (i = 0; e = ND_out(n).list[i]; i++) {
	    fprintf(stderr, " %s:%d", NAME(e->head), ED_count(e));
	    w = e->head;
	    if (g == g->root) {
		for (j = 0; f = ND_in(w).list[j]; j++)
		    if (e == f)
			break;
		assert(f != NULL);
	    }
	}
	fprintf(stderr, " ) (");
	for (i = 0; e = ND_in(n).list[i]; i++) {
	    fprintf(stderr, " %s:%d", NAME(e->tail), ED_count(e));
	    w = e->tail;
	    if (g == g->root) {
		for (j = 0; f = ND_out(w).list[j]; j++)
		    if (e == f)
			break;
		assert(f != NULL);
	    }
	}
	fprintf(stderr, " )\n");
    }
}
Beispiel #4
0
node_t* find_fast_node(graph_t *g, node_t *n)
{
	node_t		*v;
	for (v = GD_nlist(g); v; v = ND_next(v))
		if (v == n) break;
	return v;
}
Beispiel #5
0
void delete_fast_node(graph_t *g, node_t *n)
{
	assert(find_fast_node(g,n));
	if (ND_next(n)) ND_next(n)->u.prev = ND_prev(n);
	if (ND_prev(n)) ND_prev(n)->u.next = ND_next(n);
	else GD_nlist(g) = ND_next(n);
}
Beispiel #6
0
int
fastn (graph_t * g)
{
    node_t* u;
    int cnt = 0;
    for (u = GD_nlist(g); u; u = ND_next(u)) cnt++;
    return cnt;
}
Beispiel #7
0
int is_fast_node(graph_t *g, node_t *v)
{
	node_t		*n;

	for (n = GD_nlist(g); n; n = ND_next(n))
		if (v == n) return TRUE;
	return FALSE;
}
Beispiel #8
0
/* closeGraphs:
 * Clean up graphs made for setting column and row widths.
 */
static void closeGraphs(graph_t * rowg, graph_t * colg)
{
    node_t *n;
    for (n = GD_nlist(colg); n; n = ND_next(n)) {
	free_list(ND_in(n));
	free_list(ND_out(n));
    }

    agclose(rowg);
    agclose(colg);
}
Beispiel #9
0
/* setSizes:
 * Use rankings to determine cell dimensions. The rank values
 * give the coordinate, so to get the width/height, we have
 * to subtract the previous value.
 */
void setSizes(htmltbl_t * tbl, graph_t * rowg, graph_t * colg)
{
    int i;
    node_t *n;
    int prev;

    prev = 0;
    n = GD_nlist(rowg);
    for (i = 0, n = ND_next(n); n; i++, n = ND_next(n)) {
	tbl->heights[i] = ND_rank(n) - prev;
	prev = ND_rank(n);
    }
    prev = 0;
    n = GD_nlist(colg);
    for (i = 0, n = ND_next(n); n; i++, n = ND_next(n)) {
	tbl->widths[i] = ND_rank(n) - prev;
	prev = ND_rank(n);
    }

}
Beispiel #10
0
/* 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 */
	}
}
Beispiel #11
0
/* delete virtual nodes of a cluster, and install real nodes or sub-clusters */
void expand_cluster(graph_t * subg)
{
    /* build internal structure of the cluster */
    class2(subg);
    GD_comp(subg).size = 1;
    GD_comp(subg).list[0] = GD_nlist(subg);
    allocate_ranks(subg);
    build_ranks(subg, 0);
    merge_ranks(subg);

    /* build external structure of the cluster */
    interclexp(subg);
    remove_rankleaders(subg);
}
Beispiel #12
0
/* delete the layout (but retain the underlying graph) */
void dot_cleanup(graph_t * g)
{
    node_t *n;
    edge_t *e;

    free_virtual_node_list(GD_nlist(g));
    for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
	for (e = agfstout(g, n); e; e = agnxtout(g, e)) {
	    gv_cleanup_edge(e);
	}
	dot_cleanup_node(n);
    }
    dot_cleanup_graph(g);
}
Beispiel #13
0
static void checkChain(graph_t * g)
{
    node_t *t;
    node_t *h;
    edge_t *e;
    t = GD_nlist(g);
    for (h = ND_next(t); h; h = ND_next(h)) {
	if (!agfindedge(g, t, h)) {
	    e = agedge(g, t, h);
	    ED_minlen(e) = 0;
	    elist_append(e, ND_out(t));
	    elist_append(e, ND_in(h));
	}
	t = h;
    }
}
Beispiel #14
0
static void checkChain(graph_t * g)
{
    node_t *t;
    node_t *h;
    edge_t *e;
    t = GD_nlist(g);
    for (h = ND_next(t); h; h = ND_next(h)) {
	if (!agfindedge(g, t, h)) {
#ifdef WITH_CGRAPH
            e = agedge(g, t, h, NULL, 1);
	    agbindrec(e, "Agedgeinfo_t", sizeof(Agedgeinfo_t), TRUE);
#else
	    e = agedge(g, t, h);
#endif
	    ED_minlen(e) = 0;
	    elist_append(e, ND_out(t));
	    elist_append(e, ND_in(h));
	}
	t = h;
    }
}
Beispiel #15
0
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(clust); n; n = agnxtnode(clust, n)) {
	assert((ND_UF_size(n) <= 1) || (n == leader));
	UF_union(n, leader);
	ND_ranktype(n) = CLUSTER;
    }
}
Beispiel #16
0
static void
validate(graph_t * g)
{
    node_t *n;
    edge_t *e;
    int    i, cnt;
  
    cnt = 0;
    for (n = GD_nlist(g);n; n = ND_next(n)) {
      assert(outdegree(g,n) == ND_out(n).size);
      for (i = 0; (e = ND_out(n).list[i]); i++) {
        assert(agtail(e) == n);
        assert( e == agfindedge(g, n, aghead(e))); 
      }
      assert(indegree(g,n) == ND_in(n).size);
      for (i = 0; (e = ND_in(n).list[i]); i++) {
        assert(aghead(e) == n);
        assert( e == agfindedge(g, agtail(e), n)); 
      }
      cnt++;
    }

    assert (agnnodes(g) == cnt); 
}
Beispiel #17
0
/* mkNConstraintG:
 * Similar to mkConstraintG, except it doesn't enforce orthogonal
 * ordering. If there is overlap, as defined by intersect, the
 * nodes will kept/pushed apart in the current order. If not, no
 * constraint is enforced. If a constraint edge is added, and it
 * corresponds to a real edge, we increase the weight in an attempt
 * to keep the resulting shift short. 
 */
static graph_t *mkNConstraintG(graph_t * g, Dt_t * list,
			      intersectfn intersect, distfn dist)
{
    nitem *p;
    nitem *nxp;
    node_t *n;
    edge_t *e;
    node_t *lastn = NULL;
#ifndef WITH_CGRAPH
    graph_t *cg = agopen("cg", AGDIGRAPHSTRICT);
#else
    graph_t *cg = agopen("cg", Agstrictdirected, NIL(Agdisc_t *));
    agbindrec(cg, "Agraphinfo_t", sizeof(Agraphinfo_t), TRUE);  // graph custom data
#endif

    for (p = (nitem *) dtflatten(list); p;
	 p = (nitem *) dtlink(list, (Dtlink_t *) p)) {
#ifndef WITH_CGRAPH
	n = agnode(cg, agnameof(p->np));	/* FIX */
#else
	n = agnode(cg, agnameof(p->np), 1);      /* FIX */
	agbindrec(n, "Agnodeinfo_t", sizeof(Agnodeinfo_t), TRUE); //node custom data
#endif
	ND_alg(n) = p;
	p->cnode = n;
	alloc_elist(0, ND_in(n));
	alloc_elist(0, ND_out(n));
	if (lastn) {
	    ND_next(lastn) = n;
	    lastn = n;
	} else {
	    lastn = GD_nlist(cg) = n;
	}
    }
    for (p = (nitem *) dtflatten(list); p;
	 p = (nitem *) dtlink(list, (Dtlink_t *) p)) {
	for (nxp = (nitem *) dtlink(link, (Dtlink_t *) p); nxp;
	     nxp = (nitem *) dtlink(list, (Dtlink_t *) nxp)) {
	    e = NULL;
	    if (intersect(p, nxp)) {
	        double delta = dist(&p->bb, &nxp->bb);
#ifndef WITH_CGRAPH
	        e = agedge(cg, p->cnode, nxp->cnode);
#else
	        e = agedge(cg, p->cnode, nxp->cnode, NULL, 1);
		agbindrec(e, "Agedgeinfo_t", sizeof(Agedgeinfo_t), TRUE);   // edge custom data
#endif
		assert (delta <= 0xFFFF);
		ED_minlen(e) = delta;
		ED_weight(e) = 1;
	    }
	    if (e && agfindedge(g,p->np, nxp->np)) {
		ED_weight(e) = 100;
            }
#if 0
	    if (agfindedge(g,p->np, nxp->np)) {
		if (e == NULL)
	            e = agedge(cg, p->cnode, nxp->cnode);
		ED_weight(e) = 100;
                /* If minlen < SCALE, the nodes can't conflict or there's
                 * an overlap but it will be removed in the orthogonal pass.
                 * So we just keep the node's basically where they are.
                 */
		if (SCALE > ED_minlen(e))
		    ED_minlen(e) = SCALE;
	    }
#endif
	}
    }
   
    for (p = (nitem *) dtflatten(list); p;
	 p = (nitem *) dtlink(list, (Dtlink_t *) p)) {
	n = p->cnode;
	for (e = agfstout(cg,n); e; e = agnxtout(cg,e)) {
	    elist_append(e, ND_out(n));
	    elist_append(e, ND_in(aghead(e)));
	}
    }

    /* We could remove redundant constraints here. However, the cost of doing 
     * this may be a good deal more than the time saved in network simplex. 
     * Also, if the graph is changed, the ND_in and ND_out data has to be 
     * updated.
     */
    return cg;
}
Beispiel #18
0
/* mkConstraintG:
 */
static graph_t *mkConstraintG(graph_t * g, Dt_t * list,
			      intersectfn intersect, distfn dist)
{
    nitem *p;
    nitem *nxt = NULL;
    nitem *nxp;
    graph_t *vg;
    node_t *prev = NULL;
    node_t *root = NULL;
    node_t *n = NULL;
    edge_t *e;
    int lcnt, cnt;
    int oldval = -INT_MAX;
#ifdef OLD
    double root_val;
#endif
    node_t *lastn = NULL;
#ifndef WITH_CGRAPH
    graph_t *cg = agopen("cg", AGDIGRAPHSTRICT);
#else
    graph_t *cg = agopen("cg", Agstrictdirected, NIL(Agdisc_t *));
    agbindrec(cg, "Agraphinfo_t", sizeof(Agraphinfo_t), TRUE);  // graph custom data
#endif

    /* count distinct nodes */
    cnt = 0;
    for (p = (nitem *) dtflatten(list); p;
	 p = (nitem *) dtlink(list, (Dtlink_t *) p)) {
	if (oldval != p->val) {
	    oldval = p->val;
	    cnt++;
	}
    }

    /* construct basic chain to enforce left to right order */
    oldval = -INT_MAX;
    lcnt = 0;
    for (p = (nitem *) dtflatten(list); p;
	 p = (nitem *) dtlink(list, (Dtlink_t *) p)) {
	if (oldval != p->val) {
	    oldval = p->val;
	    /* n = newNode (cg); */
#ifndef WITH_CGRAPH
	    n = agnode(cg, agnameof(p->np));	/* FIX */
#else
	    n = agnode(cg, agnameof(p->np), 1);	/* FIX */
	    agbindrec(n, "Agnodeinfo_t", sizeof(Agnodeinfo_t), TRUE); //node custom data
#endif
	    ND_alg(n) = p;
	    if (root) {
		ND_next(lastn) = n;
		lastn = n;
	    } else {
		root = n;
#ifdef OLD
		root_val = p->val;
#endif
		lastn = GD_nlist(cg) = n;
	    }
	    alloc_elist(lcnt, ND_in(n));
	    if (prev) {
		if (prev == root)
		    alloc_elist(2 * (cnt - 1), ND_out(prev));
		else
		    alloc_elist(cnt - lcnt - 1, ND_out(prev));
#ifndef WITH_CGRAPH
		e = agedge(cg, prev, n);
#else
		e = agedge(cg, prev, n, NULL, 1);
		agbindrec(e, "Agedgeinfo_t", sizeof(Agedgeinfo_t), TRUE);   // edge custom data
#endif
		ED_minlen(e) = SCALE;
		ED_weight(e) = 1;
		elist_append(e, ND_out(prev));
		elist_append(e, ND_in(n));
	    }
	    lcnt++;
	    prev = n;
	}
	p->cnode = n;
    }
    alloc_elist(0, ND_out(prev));

    /* add immediate right neighbor constraints
     * Construct visibility graph, then perform transitive reduction.
     * Remaining outedges are immediate right neighbors.
     * FIX: Incremental algorithm to construct trans. reduction?
     */
#ifndef WITH_CGRAPH
    vg = agopen("vg", AGDIGRAPHSTRICT);
#else
    vg = agopen("vg", Agstrictdirected, NIL(Agdisc_t *));
#endif
    for (p = (nitem *) dtflatten(list); p;
	 p = (nitem *) dtlink(list, (Dtlink_t *) p)) {
#ifndef WITH_CGRAPH
	n = agnode(vg, agnameof(p->np));     /* FIX */
#else
	n = agnode(vg, agnameof(p->np), 1);  /* FIX */
	agbindrec(n, "Agnodeinfo_t", sizeof(Agnodeinfo_t), TRUE);  //node custom data
#endif
	p->vnode = n;
	ND_alg(n) = p;
    }
    oldval = -INT_MAX;
    for (p = (nitem *) dtflatten(list); p;
	 p = (nitem *) dtlink(list, (Dtlink_t *) p)) {
	if (oldval != p->val) {	/* new pos: reset nxt */
	    oldval = p->val;
	    for (nxt = (nitem *) dtlink(link, (Dtlink_t *) p); nxt;
		 nxt = (nitem *) dtlink(list, (Dtlink_t *) nxt)) {
		if (nxt->val != oldval)
		    break;
	    }
	    if (!nxt)
		break;
	}
	for (nxp = nxt; nxp;
	     nxp = (nitem *) dtlink(list, (Dtlink_t *) nxp)) {
	    if (intersect(p, nxp))
#ifndef WITH_CGRAPH
		agedge(vg, p->vnode, nxp->vnode);
#else
		agedge(vg, p->vnode, nxp->vnode, NULL, 1);
#endif
	}
    }

    /* Remove redundant constraints here. However, the cost of doing this
     * may be a good deal more than the time saved in network simplex. Also,
     * if the graph is changed, the ND_in and ND_out data has to be updated.
     */
    mapGraphs(vg, cg, dist);
    agclose(vg);

    /* add dummy constraints for absolute values and initial positions */
#ifdef OLD
    for (n = agfstnode(cg); n; n = agnxtnode(cg, n)) {
	node_t *vn;		/* slack node for absolute value */
	node_t *an;		/* node representing original position */

	p = (nitem *) ND_alg(n);
	if ((n == root) || (!p))
	    continue;
	vn = newNode(cg);
	ND_next(lastn) = vn;
	lastn = vn;
	alloc_elist(0, ND_out(vn));
	alloc_elist(2, ND_in(vn));
	an = newNode(cg);
	ND_next(lastn) = an;
	lastn = an;
	alloc_elist(1, ND_in(an));
	alloc_elist(1, ND_out(an));

#ifndef WITH_CGRAPH
	e = agedge(cg, root, an);
#else
	e = agedge(cg, root, an, 1);
#endif
	ED_minlen(e) = p->val - root_val;
	elist_append(e, ND_out(root));
	elist_append(e, ND_in(an));

#ifndef WITH_CGRAPH
	e = agedge(cg, an, vn);
#else
	e = agedge(cg, an, vn, 1);
#endif
	elist_append(e, ND_out(an));
	elist_append(e, ND_in(vn));

#ifndef WITH_CGRAPH
	e = agedge(cg, n, vn);
#else
	e = agedge(cg, n, vn, 1);
#endif
	elist_append(e, ND_out(n));
	elist_append(e, ND_in(vn));
    }
#endif  /* OLD */

    return cg;
}
Beispiel #19
0
/* makeGraphs:
 * Generate dags modeling the row and column constraints.
 * If the table has cc columns, we create the graph
 *  0 -> 1 -> 2 -> ... -> cc
 * and if a cell starts in column c with span cspan, with
 * width w, we add the edge c -> c+cspan [minlen = w].
 *
 * We might simplify the graph by removing multiedges,
 * using the max minlen, but will affect the balancing?
 */
void makeGraphs(htmltbl_t * tbl, graph_t * rowg, graph_t * colg)
{
    htmlcell_t *cp;
    htmlcell_t **cells;
    node_t *t;
    node_t *lastn;
    node_t *h;
    edge_t *e;
    int i;
    int* minc;
    int* minr;

    lastn = NULL;
    for (i = 0; i <= tbl->cc; i++) {
	t = agnode(colg, nToName(i));
	alloc_elist(tbl->rc, ND_in(t));
	alloc_elist(tbl->rc, ND_out(t));
	if (lastn) {
	    ND_next(lastn) = t;
	    lastn = t;
	} else {
	    lastn = GD_nlist(colg) = t;
	}
    }
    lastn = NULL;
    for (i = 0; i <= tbl->rc; i++) {
	t = agnode(rowg, nToName(i));
	alloc_elist(tbl->cc, ND_in(t));
	alloc_elist(tbl->cc, ND_out(t));
	if (lastn) {
	    ND_next(lastn) = t;
	    lastn = t;
	} else {
	    lastn = GD_nlist(rowg) = t;
	}
    }
    minr = N_NEW(tbl->rc, int);
    minc = N_NEW(tbl->cc, int);
    for (cells = tbl->u.n.cells; *cells; cells++) {
        int x, y, c, r;
	cp = *cells;
        x = (cp->data.box.UR.x + (cp->cspan-1))/cp->cspan;
        for (c = 0; c < cp->cspan; c++)
          minc[cp->col + c] = MAX(minc[cp->col + c],x);
        y = (cp->data.box.UR.y + (cp->rspan-1))/cp->rspan;
        for (r = 0; r < cp->rspan; r++)
          minr[cp->row + r] = MAX(minr[cp->row + r],y);
    }
    for (cells = tbl->u.n.cells; *cells; cells++) {
        int x, y, c, r;
	cp = *cells;
	t = agfindnode(colg, nToName(cp->col));
	h = agfindnode(colg, nToName(cp->col + cp->cspan));
	e = agedge(colg, t, h);
        x = 0;
        for (c = 0; c < cp->cspan; c++)
            x += minc[cp->col + c];
	ED_minlen(e) = x;
	/* ED_minlen(e) = cp->data.box.UR.x; */
#ifdef DEBUG
	fprintf(stderr, "col edge %s -> %s %d\n", t->name, h->name,
		ED_minlen(e));
#endif
	elist_append(e, ND_out(t));
	elist_append(e, ND_in(h));

	t = agfindnode(rowg, nToName(cp->row));
	h = agfindnode(rowg, nToName(cp->row + cp->rspan));
	e = agedge(rowg, t, h);
        y = 0;
        for (r = 0; r < cp->rspan; r++)
            y += minr[cp->row + r];
	ED_minlen(e) = y;
	/* ED_minlen(e) = cp->data.box.UR.y; */
#ifdef DEBUG
	fprintf(stderr, "row edge %s -> %s %d\n", t->name, h->name,
		ED_minlen(e));
#endif
	elist_append(e, ND_out(t));
	elist_append(e, ND_in(h));
    }

    /* Make sure that 0 <= 1 <= 2 ...k. This implies graph connected. */
    checkChain(colg);
    checkChain(rowg);

    free (minc);
    free (minr);
}