Exemple #1
0
/* this function marks every node in <g> with its top-level cluster under <g> */
void mark_clusters(graph_t * g)
{
    int c;
    node_t *n, *nn, *vn;
    edge_t *orig, *e;
    graph_t *clust;

    /* remove sub-clusters below this level */
    for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
	if (ND_ranktype(n) == CLUSTER)
	    UF_singleton(n);
	ND_clust(n) = NULL;
    }

    for (c = 1; c <= GD_n_cluster(g); c++) {
	clust = GD_clust(g)[c];
	for (n = agfstnode(clust); n; n = nn) {
		nn = agnxtnode(clust,n);
	    if (ND_ranktype(n) != NORMAL) {
		agerr(AGWARN,
		      "%s was already in a rankset, deleted from cluster %s\n",
		      agnameof(n), agnameof(g));
		agdelete(clust,n);
		continue;
	    }
	    UF_setname(n, GD_leader(clust));
	    ND_clust(n) = clust;
	    ND_ranktype(n) = CLUSTER;

	    /* here we mark the vnodes of edges in the cluster */
	    for (orig = agfstout(clust, n); orig;
		 orig = agnxtout(clust, orig)) {
		if ((e = ED_to_virt(orig))) {
#ifndef WITH_CGRAPH
		    while (e && (vn = e->head)->u.node_type == VIRTUAL) {
#else /* WITH_CGRAPH */
		    while (e && ND_node_type(vn =aghead(e)) == VIRTUAL) {
#endif /* WITH_CGRAPH */
			ND_clust(vn) = clust;
			e = ND_out(aghead(e)).list[0];
			/* trouble if concentrators and clusters are mixed */
		    }
		}
	    }
	}
    }
}

void build_skeleton(graph_t * g, graph_t * subg)
{
    int r;
    node_t *v, *prev, *rl;
    edge_t *e;

    prev = NULL;
    GD_rankleader(subg) = N_NEW(GD_maxrank(subg) + 2, node_t *);
    for (r = GD_minrank(subg); r <= GD_maxrank(subg); r++) {
	v = GD_rankleader(subg)[r] = virtual_node(g);
	ND_rank(v) = r;
	ND_ranktype(v) = CLUSTER;
	ND_clust(v) = subg;
	if (prev) {
	    e = virtual_edge(prev, v, NULL);
	    ED_xpenalty(e) *= CL_CROSS;
	}
	prev = v;
    }

    /* set the counts on virtual edges of the cluster skeleton */
    for (v = agfstnode(subg); v; v = agnxtnode(subg, v)) {
	rl = GD_rankleader(subg)[ND_rank(v)];
	ND_UF_size(rl)++;
	for (e = agfstout(subg, v); e; e = agnxtout(subg, e)) {
	    for (r = ND_rank(agtail(e)); r < ND_rank(aghead(e)); r++) {
		ED_count(ND_out(rl).list[0])++;
	    }
	}
    }
    for (r = GD_minrank(subg); r <= GD_maxrank(subg); r++) {
	rl = GD_rankleader(subg)[r];
	if (ND_UF_size(rl) > 1)
	    ND_UF_size(rl)--;
    }
}
Exemple #2
0
static bool upcandidate(node_t * v)
{
    return ((ND_node_type(v) == VIRTUAL) && (ND_out(v).size == 1)
	    && (ND_in(v).size == 1) && (ND_label(v) == NULL));
}
Exemple #3
0
static void 
map_path(node_t * from, node_t * to, edge_t * orig, edge_t * ve, int type)
{
    int r;
    node_t *u, *v;
    edge_t *e;

    assert(ND_rank(from) < ND_rank(to));

    if ((agtail(ve) == from) && (aghead(ve) == to))
	return;

    if (ED_count(ve) > 1) {
	ED_to_virt(orig) = NULL;
	if (ND_rank(to) - ND_rank(from) == 1) {
	    if ((e = find_fast_edge(from, to)) && (ports_eq(orig, e))) {
		merge_oneway(orig, e);
		if ((ND_node_type(from) == NORMAL)
		    && (ND_node_type(to) == NORMAL))
		    other_edge(orig);
		return;
	    }
	}
	u = from;
	for (r = ND_rank(from); r < ND_rank(to); r++) {
	    if (r < ND_rank(to) - 1)
		v = clone_vn(agraphof(from), aghead(ve));
	    else
		v = to;
	    e = virtual_edge(u, v, orig);
	    ED_edge_type(e) = type;
	    u = v;
	    ED_count(ve)--;
	    ve = ND_out(aghead(ve)).list[0];
	}
    } else {
	if (ND_rank(to) - ND_rank(from) == 1) {
	    if ((ve = find_fast_edge(from, to)) && (ports_eq(orig, ve))) {
		/*ED_to_orig(ve) = orig; */
		ED_to_virt(orig) = ve;
		ED_edge_type(ve) = type;
		ED_count(ve)++;
		if ((ND_node_type(from) == NORMAL)
		    && (ND_node_type(to) == NORMAL))
		    other_edge(orig);
	    } else {
		ED_to_virt(orig) = NULL;
		ve = virtual_edge(from, to, orig);
		ED_edge_type(ve) = type;
	    }
	}
	if (ND_rank(to) - ND_rank(from) > 1) {
	    e = ve;
	    if (agtail(ve) != from) {
		ED_to_virt(orig) = NULL;
		e = ED_to_virt(orig) = virtual_edge(from, aghead(ve), orig);
		delete_fast_edge(ve);
	    } else
		e = ve;
	    while (ND_rank(aghead(e)) != ND_rank(to))
		e = ND_out(aghead(e)).list[0];
	    if (aghead(e) != to) {
		ve = e;
		e = virtual_edge(agtail(e), to, orig);
		ED_edge_type(e) = type;
		delete_fast_edge(ve);
	    }
	}
    }
}
Exemple #4
0
edge_t *find_fast_edge(node_t * u, node_t * v)
{
    return ffe(u, ND_out(u), v, ND_in(v));
}
Exemple #5
0
/* disconnects e from graph */
void delete_fast_edge(edge_t * e)
{
    assert(e != NULL);
    zapinlist(&(ND_out(e->tail)), e);
    zapinlist(&(ND_in(e->head)), e);
}
Exemple #6
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);
}
Exemple #7
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;
}
Exemple #8
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;
}