isl_tarjan.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. /*
  2. * Copyright 2010-2011 INRIA Saclay
  3. * Copyright 2012 Ecole Normale Superieure
  4. *
  5. * Use of this software is governed by the MIT license
  6. *
  7. * Written by Sven Verdoolaege, INRIA Saclay - Ile-de-France,
  8. * Parc Club Orsay Universite, ZAC des vignes, 4 rue Jacques Monod,
  9. * 91893 Orsay, France
  10. * and Ecole Normale Superieure, 45 rue d’Ulm, 75230 Paris, France
  11. */
  12. #include <stdlib.h>
  13. #include <isl/ctx.h>
  14. #include <isl_tarjan.h>
  15. struct isl_tarjan_graph *isl_tarjan_graph_free(struct isl_tarjan_graph *g)
  16. {
  17. if (!g)
  18. return NULL;
  19. free(g->node);
  20. free(g->stack);
  21. free(g->order);
  22. free(g);
  23. return NULL;
  24. }
  25. static struct isl_tarjan_graph *isl_tarjan_graph_alloc(isl_ctx *ctx, int len)
  26. {
  27. struct isl_tarjan_graph *g;
  28. int i;
  29. g = isl_calloc_type(ctx, struct isl_tarjan_graph);
  30. if (!g)
  31. return NULL;
  32. g->len = len;
  33. g->node = isl_alloc_array(ctx, struct isl_tarjan_node, len);
  34. if (len && !g->node)
  35. goto error;
  36. for (i = 0; i < len; ++i)
  37. g->node[i].index = -1;
  38. g->stack = isl_alloc_array(ctx, int, len);
  39. if (len && !g->stack)
  40. goto error;
  41. g->order = isl_alloc_array(ctx, int, 2 * len);
  42. if (len && !g->order)
  43. goto error;
  44. g->sp = 0;
  45. g->index = 0;
  46. g->op = 0;
  47. return g;
  48. error:
  49. isl_tarjan_graph_free(g);
  50. return NULL;
  51. }
  52. /* Perform Tarjan's algorithm for computing the strongly connected components
  53. * in the graph with g->len nodes and with edges defined by "follows".
  54. */
  55. static isl_stat isl_tarjan_components(struct isl_tarjan_graph *g, int i,
  56. isl_bool (*follows)(int i, int j, void *user), void *user)
  57. {
  58. int j;
  59. g->node[i].index = g->index;
  60. g->node[i].min_index = g->index;
  61. g->node[i].on_stack = 1;
  62. g->index++;
  63. g->stack[g->sp++] = i;
  64. for (j = g->len - 1; j >= 0; --j) {
  65. isl_bool f;
  66. if (j == i)
  67. continue;
  68. if (g->node[j].index >= 0 &&
  69. (!g->node[j].on_stack ||
  70. g->node[j].index > g->node[i].min_index))
  71. continue;
  72. f = follows(i, j, user);
  73. if (f < 0)
  74. return isl_stat_error;
  75. if (!f)
  76. continue;
  77. if (g->node[j].index < 0) {
  78. isl_tarjan_components(g, j, follows, user);
  79. if (g->node[j].min_index < g->node[i].min_index)
  80. g->node[i].min_index = g->node[j].min_index;
  81. } else if (g->node[j].index < g->node[i].min_index)
  82. g->node[i].min_index = g->node[j].index;
  83. }
  84. if (g->node[i].index != g->node[i].min_index)
  85. return isl_stat_ok;
  86. do {
  87. j = g->stack[--g->sp];
  88. g->node[j].on_stack = 0;
  89. g->order[g->op++] = j;
  90. } while (j != i);
  91. g->order[g->op++] = -1;
  92. return isl_stat_ok;
  93. }
  94. /* Decompose the graph with "len" nodes and edges defined by "follows"
  95. * into strongly connected components (SCCs).
  96. * follows(i, j, user) should return 1 if "i" follows "j" and 0 otherwise.
  97. * It should return -1 on error.
  98. *
  99. * If SCC a contains a node i that follows a node j in another SCC b
  100. * (i.e., follows(i, j, user) returns 1), then SCC a will appear after SCC b
  101. * in the result.
  102. */
  103. struct isl_tarjan_graph *isl_tarjan_graph_init(isl_ctx *ctx, int len,
  104. isl_bool (*follows)(int i, int j, void *user), void *user)
  105. {
  106. int i;
  107. struct isl_tarjan_graph *g = NULL;
  108. g = isl_tarjan_graph_alloc(ctx, len);
  109. if (!g)
  110. return NULL;
  111. for (i = len - 1; i >= 0; --i) {
  112. if (g->node[i].index >= 0)
  113. continue;
  114. if (isl_tarjan_components(g, i, follows, user) < 0)
  115. return isl_tarjan_graph_free(g);
  116. }
  117. return g;
  118. }
  119. /* Decompose the graph with "len" nodes and edges defined by "follows"
  120. * into the strongly connected component (SCC) that contains "node"
  121. * as well as all SCCs that are followed by this SCC.
  122. * follows(i, j, user) should return 1 if "i" follows "j" and 0 otherwise.
  123. * It should return -1 on error.
  124. *
  125. * The SCC containing "node" will appear as the last component
  126. * in g->order.
  127. */
  128. struct isl_tarjan_graph *isl_tarjan_graph_component(isl_ctx *ctx, int len,
  129. int node, isl_bool (*follows)(int i, int j, void *user), void *user)
  130. {
  131. struct isl_tarjan_graph *g;
  132. g = isl_tarjan_graph_alloc(ctx, len);
  133. if (!g)
  134. return NULL;
  135. if (isl_tarjan_components(g, node, follows, user) < 0)
  136. return isl_tarjan_graph_free(g);
  137. return g;
  138. }