static int dfs(Agraph_t * g, Agnode_t * t, int hasCycle) { Agedge_t *e; Agedge_t *f; Agnode_t *h; ND_mark(t) = 1; ND_onstack(t) = 1; for (e = agfstout(g, t); e; e = f) { f = agnxtout(g, e); if (e->tail == e->head) continue; h = e->head; if (ND_onstack(h)) { if (AG_IS_STRICT(g)) { if (agfindedge(g, h, t) == 0) addRevEdge(g, e); } else addRevEdge(g, e); agdelete(g, e); hasCycle = 1; } else if (ND_mark(h) == 0) hasCycle = dfs(g, h, hasCycle); } ND_onstack(t) = 0; return hasCycle; }
Agedge_t *findedge(Agnode_t *t, Agnode_t *h) { if (!t || !h) return NULL; if (AGTYPE(t) == AGRAPH || AGTYPE(h) == AGRAPH) return NULL; return agfindedge(agraphof(t), t, h); }
edge_t * debug_getedge(graph_t *g, char *s0, char *s1) { node_t *n0,*n1; n0 = agfindnode(g,s0); n1 = agfindnode(g,s1); if (n0 && n1) return agfindedge(g,n0,n1); else return NULL; }
static void reverse_edge(graph_t *g, edge_t *e) { edge_t *rev; rev = agfindedge(g,e->head,e->tail); if (!rev) rev = agedge(g,e->head,e->tail); merge(rev,ED_minlen(e),ED_weight(e)); agdelete(g,e); }
void class1(graph_t * g) { node_t *n, *t, *h; edge_t *e, *rep; mark_clusters(g); for (n = agfstnode(g); n; n = agnxtnode(g, n)) { for (e = agfstout(g, n); e; e = agnxtout(g, e)) { /* skip edges already processed */ if (ED_to_virt(e)) continue; /* skip edges that we want to ignore in this phase */ if (nonconstraint_edge(e)) continue; t = UF_find(agtail(e)); h = UF_find(aghead(e)); /* skip self, flat, and intra-cluster edges */ if (t == h) continue; /* inter-cluster edges require special treatment */ if (ND_clust(t) || ND_clust(h)) { interclust1(g, agtail(e), aghead(e), e); continue; } if ((rep = find_fast_edge(t, h))) merge_oneway(e, rep); else virtual_edge(t, h, e); #ifdef NOTDEF if ((t == agtail(e)) && (h == aghead(e))) { if (rep = find_fast_edge(t, h)) merge_oneway(e, rep); else virtual_edge(t, h, e); } else { f = agfindedge(g, t, h); if (f && (ED_to_virt(f) == NULL)) rep = virtual_edge(t, h, f); else rep = find_fast_edge(t, h); if (rep) merge_oneway(e, rep); else virtual_edge(t, h, e); } #endif } } }
/* a given edge can have several other edges (forward or backward) between the same endpoints. here, we choose one of these to be the canonical representative of those edges. */ static Agedge_t* canonical_edge(Agedge_t* e) { Agraph_t *g; Agedge_t *canon; g = e->tail->graph; if (ND_rank(e->head) > ND_rank(e->tail)) canon = agfindedge(g,e->tail,e->head); else { if } }
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); }
Agnode_t *nexthead(Agnode_t *n, Agnode_t *h) { Agedge_t *e; if (!n || !h) return NULL; e = agfindedge(n->graph, n, h); if (!e) return NULL; do { e = agnxtout(n->graph, e); if (!e) return NULL; } while (e->head == h); return e->head; }
Agnode_t *nexttail(Agnode_t *n, Agnode_t *t) { Agedge_t *e; if (!n || !t) return NULL; e = agfindedge(n->graph, t, n); if (!e) return NULL; do { e = agnxtout(n->graph, e); if (!e) return NULL; } while (e->tail == t); return e->tail; }
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; } }
Agnode_t *nexttail(Agnode_t *n, Agnode_t *t) { Agedge_t *e; Agraph_t *g; if (!n || !t) return NULL; g = agraphof(n); e = agfindedge(g, t, n); if (!e) return NULL; do { e = agnxtin(g, e); if (!e) return NULL; } while (agtail(e) == t); return agtail(e); }
Agnode_t *nexthead(Agnode_t *n, Agnode_t *h) { Agedge_t *e; Agraph_t *g; if (!n || !h) return NULL; g = agraphof(n); e = agfindedge(g, n, h); if (!e) return NULL; do { e = agnxtout(g, e); if (!e) return NULL; } while (aghead(e) == h); return aghead(e); }
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; } }
Agraph_t *nextsupg(Agraph_t *g, Agraph_t *sg) { Agraph_t *mg; Agnode_t *ng, *nsg; Agedge_t *e; if (!g || !sg) return NULL; ng = g->meta_node; nsg = sg->meta_node; if (!ng || !nsg) return NULL; mg = ng->graph; if (!mg) return NULL; e = agfindedge(mg, nsg, ng); if (!e) return NULL; e = agnxtin(mg, e); if (!e) return NULL; return agusergraph(e->tail); }
/*-------------------------------------------------------------------------*\ * Method: e, tail, head = n.edge(self, node, label, flag) * Finds or creates an edge. The given node becomes the tail of the edge. * Label is optional. * The optional flag nocreate=true inhibits auto-creation. * Any node given by name is implicitly created and it's userdata returned * as additional results - even if nocreate is not set. * Example: * e, tail, head = e:node(n2, "edge-1") * e, err = g:edge(...) \*-------------------------------------------------------------------------*/ static int gr_edge(lua_State *L) { Agedge_t *e; gr_edge_t *edge; int rv; char *label; char sbuf[32]; Agraph_t *g; gr_node_t *head; gr_node_t *tail = tonode(L, 1, STRICT); if (lua_isuserdata(L, 2)) head = tonode(L, 2, STRICT); else { /* Create a node given by name */ lua_pushcfunction(L, gr_create_node); /* tail, nhead, (label), func */ get_object(L, tail->n->graph); /* tail, nhead, (label), func, graph */ lua_pushstring(L, (const char *) luaL_checkstring(L, 2)); /* ... func, graph, nhead */ if (lua_isboolean(L, 4)) lua_pushvalue(L, 4); else lua_pushboolean(L, 0); /* g.node(self, name, flag) */ lua_call(L, 3, 1); /* tail, nhead, (label), head */ head = tonode(L, -1, STRICT); lua_pop(L,1); /* tail, nhead, (label) */ } g = tail->n->graph; if (tail->n->graph != head->n->graph){ luaL_error(L, "head/tail not in same graph"); } label = (char *) luaL_optstring(L, 3, ""); /* ud, peer, name, (flag) */ if ((e = agfindedge(g, tail->n, head->n)) != NULL){ /* Edge exists */ rv = get_object(L, e); /* ud, peer, name, (flag), edge */ if (lua_isnil(L, -rv)){ lua_pop(L, rv); /* ud, peer, name, (flag) */ /* Edge not yet registered */ edge = lua_newuserdata(L, sizeof(gr_edge_t)); /* ud, peer, name, (flag), edge */ edge->e = e; if (strlen(label) > 0) agset(e, "label", label); sprintf(sbuf, "edge@%d", AGID(e)); edge->name = strdup(sbuf); edge->type = AGEDGE; set_object(L, e); /* ud, peer, name, (flag), edge */ new_edge(L); lua_pushlightuserdata(L, tail); lua_pushlightuserdata(L, head); /* ud, peer, name, (flag), edge, tail, head */ return 3; } else { /* Edge already registered */ lua_pushlightuserdata(L, tail); lua_pushlightuserdata(L, head); return rv + 2; /* ud, peer, name, (flag), edge, tail, head */ } } else { /* Edge does not exist */ if (lua_toboolean(L, 4)){ lua_pushnil(L); lua_pushstring(L, "edge not found"); return 2; } edge = lua_newuserdata(L, sizeof(gr_edge_t)); if (!(edge->e = agedge(g, tail->n, head->n))){ luaL_error(L, "agedge failed"); return 0; } if (strlen(label) > 0) agset(edge->e, "label", label); sprintf(sbuf, "edge@%d", AGID(edge->e)); edge->name = strdup(sbuf); edge->type = AGEDGE; set_object(L, edge->e); new_edge(L); lua_pushlightuserdata(L, tail); lua_pushlightuserdata(L, head); return 3; } }
Agedge_t *findedge(Agnode_t *t, Agnode_t *h) { if (!t || !h) return NULL; return agfindedge(t->graph, t, h); }
/* 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; }
void class2(graph_t* g) { int c; node_t *n,*t,*h; edge_t *e,*prev,*opp; g->u.nlist = NULL; g->u.n_nodes = 0; /* new */ mark_clusters(g); for (c = 1; c <= g->u.n_cluster; c++) build_skeleton(g,g->u.clust[c]); for (n = agfstnode(g); n; n = agnxtnode(g,n)) for (e = agfstout(g,n); e; e = agnxtout(g,e)) { if (e->head->u.weight_class <= 2) e->head->u.weight_class++; if (e->tail->u.weight_class <= 2) e->tail->u.weight_class++; } for (n = agfstnode(g); n; n = agnxtnode(g,n)) { if ((n->u.clust == NULL) && (n == UF_find(n))) {fast_node(g,n); g->u.n_nodes++;} prev = NULL; for (e = agfstout(g,n); e; e = agnxtout(g,e)) { /* already processed */ if (e->u.to_virt) continue; /* edges involving sub-clusters of g */ if (is_cluster_edge(e)) { /* following is new cluster multi-edge code */ if (mergeable(prev,e)) { if (prev->u.to_virt) { merge_chain(g,e,prev->u.to_virt,FALSE); other_edge(e); } else if (e->tail->u.rank == e->head->u.rank) { merge_oneway(e,prev); other_edge(e); } /* else is an intra-cluster edge */ continue; } interclrep(g,e); prev = e; continue; } /* merge multi-edges */ if (prev && (e->tail == prev->tail) && (e->head == prev->head)) { if (e->tail->u.rank == e->head->u.rank) { merge_oneway(e,prev); other_edge(e); continue; } if ((e->u.label == NULL) && (prev->u.label == NULL) && ports_eq(e,prev)) { if (Concentrate) e->u.edge_type = IGNORED; else{ merge_chain(g,e,prev->u.to_virt,TRUE); other_edge(e); } continue; } /* parallel edges with different labels fall through here */ } /* self edges */ if (e->tail == e->head) { other_edge(e); prev = e; continue; } t = UF_find(e->tail); h = UF_find(e->head); /* non-leader leaf nodes */ if ((e->tail != t) || (e->head != h)) { /* ### need to merge stuff */ continue; } /* flat edges */ if (e->tail->u.rank == e->head->u.rank) { flat_edge(g,e); prev = e; continue; } /* forward edges */ if (e->head->u.rank > e->tail->u.rank) { make_chain(g,e->tail,e->head,e); prev = e; continue; } /* backward edges */ else { /*other_edge(e);*/ if ((opp = agfindedge(g,e->head,e->tail))) { /* shadows a forward edge */ if (opp->u.to_virt == NULL) make_chain(g,opp->tail,opp->head,opp); if ((e->u.label == NULL) && (opp->u.label == NULL) && ports_eq(e,opp)) { if (Concentrate) { e->u.edge_type = IGNORED; opp->u.conc_opp_flag = TRUE; } else{ /* see above. this is getting out of hand */ other_edge(e); merge_chain(g,e,opp->u.to_virt,TRUE); } continue; } } make_chain(g,e->head,e->tail,e); prev = e; } } } /* since decompose() is not called on subgraphs */ if (g != g->root) { g->u.comp.list = ALLOC(1,g->u.comp.list,node_t*); g->u.comp.list[0] = g->u.nlist; }
/* find_pair_edges: */ static void find_pair_edges(Agraph_t * g, Agnode_t * n, Agraph_t * outg) { Agnode_t **neighbors_with; Agnode_t **neighbors_without; Agedge_t *e; Agedge_t *ep; Agedge_t *ex; Agnode_t *n1; Agnode_t *n2; int has_pair_edge; int diff; int has_pair_count = 0; int no_pair_count = 0; int node_degree; int edge_cnt = 0; node_degree = DEGREE(n); neighbors_with = N_GNEW(node_degree, Agnode_t *); neighbors_without = N_GNEW(node_degree, Agnode_t *); for (e = agfstedge(g, n); e; e = agnxtedge(g, e, n)) { n1 = e->head; if (n1 == n) n1 = e->tail; has_pair_edge = 0; for (ep = agfstedge(g, n); ep; ep = agnxtedge(g, ep, n)) { if (ep == e) continue; n2 = ep->head; if (n2 == n) n2 = ep->tail; ex = agfindedge(g, n1, n2); if (ex) { has_pair_edge = 1; if (n1 < n2) { /* count edge only once */ edge_cnt++; if (ORIGE(ex)) { agdelete(outg, ORIGE(ex)); ORIGE(ex) = 0; /* delete only once */ } } } } if (has_pair_edge) { neighbors_with[has_pair_count] = n1; has_pair_count++; } else { neighbors_without[no_pair_count] = n1; no_pair_count++; } } diff = node_degree - 1 - edge_cnt; if (diff > 0) { int mark; Agnode_t *hp; Agnode_t *tp; if (diff < no_pair_count) { for (mark = 0; mark < no_pair_count; mark += 2) { if ((mark + 1) >= no_pair_count) break; tp = neighbors_without[mark]; hp = neighbors_without[mark + 1]; agedge(g, tp, hp); DEGREE(tp)++; DEGREE(hp)++; diff--; } mark = 2; while (diff > 0) { tp = neighbors_without[0]; hp = neighbors_without[mark]; agedge(g, tp, hp); DEGREE(tp)++; DEGREE(hp)++; mark++; diff--; } } else if (diff == no_pair_count) { tp = neighbors_with[0]; for (mark = 0; mark < no_pair_count; mark++) { hp = neighbors_without[mark]; agedge(g, tp, hp); DEGREE(tp)++; DEGREE(hp)++; } } } free(neighbors_without); free(neighbors_with); }