comp.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  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. /* comp.c:
  11. * Written by Emden R. Gansner
  12. *
  13. * Support for "connected components". Components are either connected
  14. * or have a port node or have a pinned node.
  15. *
  16. */
  17. /* use PRIVATE interface */
  18. #define FDP_PRIVATE 1
  19. #include <cgraph/cgraph.h>
  20. #include <fdpgen/fdp.h>
  21. #include <fdpgen/comp.h>
  22. #include <pack/pack.h>
  23. #include <assert.h>
  24. #include <stdbool.h>
  25. #include <stddef.h>
  26. #include <util/agxbuf.h>
  27. #include <util/alloc.h>
  28. #include <util/bitarray.h>
  29. #include <util/prisize_t.h>
  30. static void dfs(Agraph_t *g, Agnode_t *n, Agraph_t *out, bitarray_t *marks) {
  31. Agedge_t *e;
  32. Agnode_t *other;
  33. bitarray_set(marks, ND_id(n), true);
  34. agsubnode(out,n,1);
  35. for (e = agfstedge(g, n); e; e = agnxtedge(g, e, n)) {
  36. if ((other = agtail(e)) == n)
  37. other = aghead(e);
  38. if (!bitarray_get(*marks, ND_id(other)))
  39. dfs(g, other, out, marks);
  40. }
  41. }
  42. /* findCComp:
  43. * Finds generalized connected components of graph g.
  44. * This merges all components containing a port node or a pinned node.
  45. * Assumes nodes have unique id's in range [0,agnnodes(g)-1].
  46. * Components are stored as subgraphs of g, with name sg_<i>.
  47. * Returns 0-terminated array of components.
  48. * If cnt is non-0, count of components is stored there.
  49. * If pinned is non-0, *pinned is set to 1 if there are pinned nodes.
  50. * Note that if ports and/or pinned nodes exists, they will all be
  51. * in the first component returned by findCComp.
  52. */
  53. static size_t C_cnt = 0;
  54. graph_t **findCComp(graph_t *g, size_t *cnt, int *pinned) {
  55. node_t *n;
  56. graph_t *subg;
  57. agxbuf name = {0};
  58. size_t c_cnt = 0;
  59. bport_t *pp;
  60. graph_t **comps;
  61. graph_t **cp;
  62. int pinflag = 0;
  63. assert(agnnodes(g) >= 0);
  64. bitarray_t marks = bitarray_new((size_t)agnnodes(g));
  65. /* Create component based on port nodes */
  66. subg = 0;
  67. if ((pp = PORTS(g))) {
  68. agxbprint(&name, "cc%s_%" PRISIZE_T, agnameof(g), c_cnt++ + C_cnt);
  69. subg = agsubg(g, agxbuse(&name), 1);
  70. agbindrec(subg, "Agraphinfo_t", sizeof(Agraphinfo_t), true);
  71. GD_alg(subg) = gv_alloc(sizeof(gdata));
  72. PORTS(subg) = pp;
  73. NPORTS(subg) = NPORTS(g);
  74. for (; pp->n; pp++) {
  75. if (bitarray_get(marks, ND_id(pp->n)))
  76. continue;
  77. dfs(g, pp->n, subg, &marks);
  78. }
  79. }
  80. /* Create/extend component based on pinned nodes */
  81. /* Note that ports cannot be pinned */
  82. for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
  83. if (bitarray_get(marks, ND_id(n)))
  84. continue;
  85. if (ND_pinned(n) != P_PIN)
  86. continue;
  87. if (!subg) {
  88. agxbprint(&name, "cc%s_%" PRISIZE_T, agnameof(g), c_cnt++ + C_cnt);
  89. subg = agsubg(g, agxbuse(&name), 1);
  90. agbindrec(subg, "Agraphinfo_t", sizeof(Agraphinfo_t), true);
  91. GD_alg(subg) = gv_alloc(sizeof(gdata));
  92. }
  93. pinflag = 1;
  94. dfs(g, n, subg, &marks);
  95. }
  96. if (subg)
  97. (void)graphviz_node_induce(subg, NULL);
  98. /* Pick up remaining components */
  99. for (n = agfstnode(g); n; n = agnxtnode(g, n)) {
  100. if (bitarray_get(marks, ND_id(n)))
  101. continue;
  102. agxbprint(&name, "cc%s+%" PRISIZE_T, agnameof(g), c_cnt++ + C_cnt);
  103. subg = agsubg(g, agxbuse(&name), 1);
  104. agbindrec(subg, "Agraphinfo_t", sizeof(Agraphinfo_t), true); //node custom data
  105. GD_alg(subg) = gv_alloc(sizeof(gdata));
  106. dfs(g, n, subg, &marks);
  107. (void)graphviz_node_induce(subg, NULL);
  108. }
  109. bitarray_reset(&marks);
  110. agxbfree(&name);
  111. C_cnt += c_cnt;
  112. if (cnt)
  113. *cnt = c_cnt;
  114. if (pinned)
  115. *pinned = pinflag;
  116. /* freed in layout */
  117. comps = cp = gv_calloc(c_cnt + 1, sizeof(graph_t*));
  118. for (subg = agfstsubg(g); subg; subg = agnxtsubg(subg)) {
  119. *cp++ = subg;
  120. c_cnt--;
  121. }
  122. assert(c_cnt == 0);
  123. *cp = 0;
  124. return comps;
  125. }