fastgr.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. /*************************************************************************
  2. * Copyright (c) 2011 AT&T Intellectual Property
  3. * All rights reserved. This program and the accompanying materials
  4. * are made available under the terms of the Eclipse Public License v1.0
  5. * which accompanies this distribution, and is available at
  6. * https://www.eclipse.org/legal/epl-v10.html
  7. *
  8. * Contributors: Details at https://graphviz.org
  9. *************************************************************************/
  10. #include <dotgen/dot.h>
  11. #include <stdbool.h>
  12. #include <stddef.h>
  13. #include <util/alloc.h>
  14. #include <util/unused.h>
  15. /*
  16. * operations on the fast internal graph.
  17. */
  18. static edge_t *ffe(node_t * u, elist uL, node_t * v, elist vL)
  19. {
  20. int i;
  21. edge_t *e;
  22. if ((uL.size > 0) && (vL.size > 0)) {
  23. if (uL.size < vL.size) {
  24. for (i = 0; (e = uL.list[i]); i++)
  25. if (aghead(e) == v)
  26. break;
  27. } else {
  28. for (i = 0; (e = vL.list[i]); i++)
  29. if (agtail(e) == u)
  30. break;
  31. }
  32. } else
  33. e = 0;
  34. return e;
  35. }
  36. edge_t *find_fast_edge(node_t * u, node_t * v)
  37. {
  38. return ffe(u, ND_out(u), v, ND_in(v));
  39. }
  40. static UNUSED node_t *find_fast_node(graph_t *g, node_t *n) {
  41. node_t *v;
  42. for (v = GD_nlist(g); v; v = ND_next(v))
  43. if (v == n)
  44. break;
  45. return v;
  46. }
  47. edge_t *find_flat_edge(node_t * u, node_t * v)
  48. {
  49. return ffe(u, ND_flat_out(u), v, ND_flat_in(v));
  50. }
  51. /* safe_list_append - append e to list L only if e not already a member */
  52. static void
  53. safe_list_append(edge_t * e, elist * L)
  54. {
  55. for (size_t i = 0; i < L->size; i++)
  56. if (e == L->list[i])
  57. return;
  58. elist_append(e, (*L));
  59. }
  60. edge_t *fast_edge(edge_t * e)
  61. {
  62. #ifdef DEBUG
  63. int i;
  64. edge_t *f;
  65. for (i = 0; (f = ND_out(agtail(e)).list[i]); i++) {
  66. if (e == f) {
  67. fprintf(stderr, "duplicate fast edge\n");
  68. return 0;
  69. }
  70. assert(aghead(e) != aghead(f));
  71. }
  72. for (i = 0; (f = ND_in(aghead(e)).list[i]); i++) {
  73. if (e == f) {
  74. fprintf(stderr, "duplicate fast edge\n");
  75. return 0;
  76. }
  77. assert(agtail(e) != agtail(f));
  78. }
  79. #endif
  80. elist_append(e, ND_out(agtail(e)));
  81. elist_append(e, ND_in(aghead(e)));
  82. return e;
  83. }
  84. /* zapinlist - remove e from list and fill hole with last member of list */
  85. void zapinlist(elist * L, edge_t * e)
  86. {
  87. for (size_t i = 0; i < L->size; i++) {
  88. if (L->list[i] == e) {
  89. L->size--;
  90. L->list[i] = L->list[L->size];
  91. L->list[L->size] = NULL;
  92. break;
  93. }
  94. }
  95. }
  96. /* disconnects e from graph */
  97. void delete_fast_edge(edge_t * e)
  98. {
  99. assert(e != NULL);
  100. zapinlist(&(ND_out(agtail(e))), e);
  101. zapinlist(&(ND_in(aghead(e))), e);
  102. }
  103. void other_edge(edge_t * e)
  104. {
  105. elist_append(e, ND_other(agtail(e)));
  106. }
  107. void safe_other_edge(edge_t * e)
  108. {
  109. safe_list_append(e, &(ND_other(agtail(e))));
  110. }
  111. /* new_virtual_edge:
  112. * Create and return a new virtual edge e attached to orig.
  113. * ED_to_orig(e) = orig
  114. * ED_to_virt(orig) = e if e is the first virtual edge attached.
  115. * orig might be an input edge, reverse of an input edge, or virtual edge
  116. */
  117. edge_t *new_virtual_edge(node_t * u, node_t * v, edge_t * orig)
  118. {
  119. edge_t *e;
  120. Agedgepair_t* e2 = gv_alloc(sizeof(Agedgepair_t));
  121. AGTYPE(&(e2->in)) = AGINEDGE;
  122. AGTYPE(&(e2->out)) = AGOUTEDGE;
  123. e2->out.base.data = gv_alloc(sizeof(Agedgeinfo_t));
  124. e = &(e2->out);
  125. agtail(e) = u;
  126. aghead(e) = v;
  127. ED_edge_type(e) = VIRTUAL;
  128. if (orig) {
  129. AGSEQ(e) = AGSEQ(orig);
  130. AGSEQ(&(e2->in)) = AGSEQ(orig);
  131. ED_count(e) = ED_count(orig);
  132. ED_xpenalty(e) = ED_xpenalty(orig);
  133. ED_weight(e) = ED_weight(orig);
  134. ED_minlen(e) = ED_minlen(orig);
  135. if (agtail(e) == agtail(orig))
  136. ED_tail_port(e) = ED_tail_port(orig);
  137. else if (agtail(e) == aghead(orig))
  138. ED_tail_port(e) = ED_head_port(orig);
  139. if (aghead(e) == aghead(orig))
  140. ED_head_port(e) = ED_head_port(orig);
  141. else if (aghead(e) == agtail(orig))
  142. ED_head_port(e) = ED_tail_port(orig);
  143. if (ED_to_virt(orig) == NULL)
  144. ED_to_virt(orig) = e;
  145. ED_to_orig(e) = orig;
  146. } else {
  147. ED_weight(e) = 1;
  148. ED_xpenalty(e) = 1;
  149. ED_count(e) = 1;
  150. ED_minlen(e) = 1;
  151. }
  152. return e;
  153. }
  154. edge_t *virtual_edge(node_t * u, node_t * v, edge_t * orig)
  155. {
  156. return fast_edge(new_virtual_edge(u, v, orig));
  157. }
  158. void fast_node(graph_t * g, Agnode_t * n)
  159. {
  160. #ifdef DEBUG
  161. assert(find_fast_node(g, n) == NULL);
  162. #endif
  163. ND_next(n) = GD_nlist(g);
  164. if (ND_next(n))
  165. ND_prev(ND_next(n)) = n;
  166. GD_nlist(g) = n;
  167. ND_prev(n) = NULL;
  168. assert(n != ND_next(n));
  169. }
  170. void delete_fast_node(graph_t * g, node_t * n)
  171. {
  172. assert(find_fast_node(g, n));
  173. if (ND_next(n))
  174. ND_prev(ND_next(n)) = ND_prev(n);
  175. if (ND_prev(n))
  176. ND_next(ND_prev(n)) = ND_next(n);
  177. else
  178. GD_nlist(g) = ND_next(n);
  179. }
  180. node_t *virtual_node(graph_t *g) {
  181. node_t *n = gv_alloc(sizeof(node_t));
  182. AGTYPE(n) = AGNODE;
  183. n->base.data = gv_alloc(sizeof(Agnodeinfo_t));
  184. n->root = agroot(g);
  185. ND_node_type(n) = VIRTUAL;
  186. ND_lw(n) = ND_rw(n) = 1;
  187. ND_ht(n) = 1;
  188. ND_UF_size(n) = 1;
  189. alloc_elist(4, ND_in(n));
  190. alloc_elist(4, ND_out(n));
  191. fast_node(g, n);
  192. return n;
  193. }
  194. void flat_edge(graph_t * g, edge_t * e)
  195. {
  196. elist_append(e, ND_flat_out(agtail(e)));
  197. elist_append(e, ND_flat_in(aghead(e)));
  198. GD_has_flat_edges(dot_root(g)) = GD_has_flat_edges(g) = true;
  199. }
  200. void delete_flat_edge(edge_t * e)
  201. {
  202. assert(e != NULL);
  203. if (ED_to_orig(e) && ED_to_virt(ED_to_orig(e)) == e)
  204. ED_to_virt(ED_to_orig(e)) = NULL;
  205. zapinlist(&(ND_flat_out(agtail(e))), e);
  206. zapinlist(&(ND_flat_in(aghead(e))), e);
  207. }
  208. #ifdef DEBUG
  209. static char *NAME(node_t * n)
  210. {
  211. static char buf[20];
  212. if (ND_node_type(n) == NORMAL)
  213. return agnameof(n);
  214. snprintf(buf, sizeof(buf), "V%p", n);
  215. return buf;
  216. }
  217. void fastgr(graph_t * g)
  218. {
  219. int i, j;
  220. node_t *n, *w;
  221. edge_t *e, *f;
  222. for (n = GD_nlist(g); n; n = ND_next(n)) {
  223. fprintf(stderr, "%s %d: (", NAME(n), ND_rank(n));
  224. for (i = 0; (e = ND_out(n).list[i]); i++) {
  225. fprintf(stderr, " %s:%d", NAME(aghead(e)), ED_count(e));
  226. w = aghead(e);
  227. if (g == agroot(g)) {
  228. for (j = 0; (f = ND_in(w).list[j]); j++)
  229. if (e == f)
  230. break;
  231. assert(f != NULL);
  232. }
  233. }
  234. fprintf(stderr, " ) (");
  235. for (i = 0; (e = ND_in(n).list[i]); i++) {
  236. fprintf(stderr, " %s:%d", NAME(agtail(e)), ED_count(e));
  237. w = agtail(e);
  238. if (g == agroot(g)) {
  239. for (j = 0; (f = ND_out(w).list[j]); j++)
  240. if (e == f)
  241. break;
  242. assert(f != NULL);
  243. }
  244. }
  245. fprintf(stderr, " )\n");
  246. }
  247. }
  248. #endif
  249. static void
  250. basic_merge(edge_t * e, edge_t * rep)
  251. {
  252. if (ED_minlen(rep) < ED_minlen(e))
  253. ED_minlen(rep) = ED_minlen(e);
  254. while (rep) {
  255. ED_count(rep) += ED_count(e);
  256. ED_xpenalty(rep) += ED_xpenalty(e);
  257. ED_weight(rep) += ED_weight(e);
  258. rep = ED_to_virt(rep);
  259. }
  260. }
  261. void
  262. merge_oneway(edge_t * e, edge_t * rep)
  263. {
  264. if (rep == ED_to_virt(e) || e == ED_to_virt(rep)) {
  265. agwarningf("merge_oneway glitch\n");
  266. return;
  267. }
  268. assert(ED_to_virt(e) == NULL);
  269. ED_to_virt(e) = rep;
  270. basic_merge(e, rep);
  271. }