/*
This software may only be used by you under license from AT&T Corp.
("AT&T"). A copy of AT&T's Source Code Agreement is available at
AT&T's Internet website having the URL:
<http://www.research.att.com/sw/tools/graphviz/license/source.html>
If you received this software without first entering into a license
with AT&T, you have an infringing copy of this software and cannot use
it without violating AT&T's intellectual property rights.
*/
#pragma prototyped
#include "dot.h"
/*
* operations on the fast internal graph.
*/
static edge_t* ffe(node_t *u, elist uL, node_t *v, elist vL)
{
int i;
edge_t *e;
if ((uL.size > 0) && (vL.size > 0)) {
if (uL.size < vL.size) {
for (i = 0; (e = uL.list[i]); i++)
if (e->head == v) break;
}
else {
for (i = 0; (e = vL.list[i]); i++)
if (e->tail == u) break;
}
}
else e = 0;
return e;
}
edge_t* find_fast_edge(node_t *u,node_t *v)
{
return ffe(u,ND_out(u),v,ND_in(v));
}
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;
}
edge_t* find_flat_edge(node_t *u, node_t *v)
{
return ffe(u,ND_flat_out(u),v,ND_flat_in(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)
{
int i;
for (i = 0; i < L->size; i++) if (e == L->list[i]) return;
elist_append(e,(*L));
}
edge_t*
fast_edge(edge_t *e)
{
#ifdef DEBUG
int i;
edge_t *f;
for (i = 0; (f = ND_out(e->tail).list[i]); i++) {
if (e == f) {fprintf(stderr,"duplicate fast edge\n"); return;}
assert (e->head != f->head);
}
for (i = 0; (f = ND_in(e->head).list[i]); i++) {
if (e == f) {fprintf(stderr,"duplicate fast edge\n"); return;}
assert (e->tail != f->tail);
}
#endif
elist_append(e,ND_out(e->tail));
elist_append(e,ND_in(e->head));
return e;
}
/* zapinlist - remove e from list and fill hole with last member of list */
void zapinlist(elist *L, edge_t *e)
{
int i;
for (i = 0; i < L->size; i++) {
if (L->list[i] == e) {
L->size--;
L->list[i] = L->list[L->size];
L->list[L->size] = NULL;
break;
}
}
}
/* 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);
}
void safe_delete_fast_edge(edge_t *e)
{
int i;
edge_t *f;
assert(e != NULL);
for (i = 0; (f = ND_out(e->tail).list[i]); i++)
if (f == e) zapinlist(&(ND_out(e->tail)),e);
for (i = 0; (f = ND_in(e->head).list[i]); i++)
if (f == e) zapinlist(&(ND_in(e->head)),e);
}
void other_edge(edge_t *e)
{
elist_append(e,ND_other(e->tail));
}
void safe_other_edge(edge_t *e)
{
safe_list_append(e,&(ND_other(e->tail)));
}
void delete_other_edge(edge_t *e)
{
assert(e != NULL);
zapinlist(&(ND_other(e->tail)),e);
}
/* 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)
{
edge_t *e;
e = NEW(edge_t);
e->tail = u;
e->head = v;
ED_edge_type(e) = VIRTUAL;
if (orig) {
ED_count(e) = ED_count(orig);
ED_xpenalty(e) = ED_xpenalty(orig);
ED_weight(e) = ED_weight(orig);
ED_minlen(e) = ED_minlen(orig);
if (e->tail == orig->tail) ED_tail_port(e) = ED_tail_port(orig);
else if (e->tail == orig->head) ED_tail_port(e) = ED_head_port(orig);
if (e->head == orig->head) ED_head_port(e) = ED_head_port(orig);
else if (e->head == orig->tail) ED_head_port(e) = ED_tail_port(orig);
if (ED_to_virt(orig) == NULL) ED_to_virt(orig) = e;
ED_to_orig(e) = orig;
}
else ED_minlen(e) = ED_count(e) = ED_xpenalty(e) = ED_weight(e) = 1;
return e;
}
edge_t*
virtual_edge(node_t *u, node_t *v, edge_t *orig)
{
return fast_edge(new_virtual_edge(u,v,orig));
}
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));
}
void fast_nodeapp(node_t *u, node_t *v)
{
assert (u != v);
assert (ND_next(v) == NULL);
ND_next(v) = ND_next(u);
if (ND_next(u)) ND_next(u)->u.prev = v;
ND_prev(v) = u;
ND_next(u) = v;
}
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);
}
node_t* virtual_node(graph_t *g)
{
node_t *n;
n = NEW(node_t);
n->name = "virtual";
n->graph = g;
ND_node_type(n) = VIRTUAL;
ND_lw_i(n) = ND_rw_i(n) = 1;
ND_ht_i(n) = 1;
ND_UF_size(n) = 1;
alloc_elist(4,ND_in(n));
alloc_elist(4,ND_out(n));
fast_node(g,n);
GD_n_nodes(g)++;
return n;
}
void flat_edge(graph_t *g, edge_t *e)
{
elist_append(e,ND_flat_out(e->tail));
elist_append(e,ND_flat_in(e->head));
GD_has_flat_edges(g->root) = GD_has_flat_edges(g) = TRUE;
}
void delete_flat_edge(edge_t *e)
{
assert(e != NULL);
if (ED_to_orig(e) && ED_to_virt(ED_to_orig(e)) == e)
ED_to_virt(ED_to_orig(e)) = NULL;
zapinlist(&(ND_flat_out(e->tail)),e);
zapinlist(&(ND_flat_in(e->head)),e);
}
#ifdef DEBUG
static char*
NAME(node_t *n)
{
static char buf[20];
if (ND_node_type(n) == NORMAL) return n->name;
sprintf(buf,"V%x",n);
return buf;
}
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");
}
}
#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)
{
if (ED_minlen(rep) < ED_minlen(e))
ED_minlen(rep) = ED_minlen(e);
while (rep) {
ED_count(rep) += ED_count(e);
ED_xpenalty(rep) += ED_xpenalty(e);
ED_weight(rep) += ED_weight(e);
rep = ED_to_virt(rep);
}
}
static void unrep(edge_t *rep, edge_t *e)
{
ED_count(rep) -= ED_count(e);
ED_xpenalty(rep) -= ED_xpenalty(e);
ED_weight(rep) -= ED_weight(e);
}
void unmerge_oneway(edge_t *e)
{
edge_t *rep,*nextrep;
for (rep = ED_to_virt(e); rep; rep = nextrep) {
unrep(rep,e);
nextrep = ED_to_virt(rep);
if (ED_count(rep) == 0) safe_delete_fast_edge(rep); /* free(rep)? */
/* unmerge from a virtual edge chain */
while ((ED_edge_type(rep) == VIRTUAL)
&& (ND_node_type(rep->head) == VIRTUAL)
&& (ND_out(rep->head).size == 1)) {
rep = ND_out(rep->head).list[0];
unrep(rep,e);
}
}
ED_to_virt(e) = NULL;
}
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;
}
|