articulation_point.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. /*!
  2. \file vector/neta/articulation_point.c
  3. \brief Network Analysis library - connected components
  4. Computes network articulation points.
  5. (C) 2009-2010 by Daniel Bundala, and the GRASS Development Team
  6. This program is free software under the GNU General Public License
  7. (>=v2). Read the file COPYING that comes with GRASS for details.
  8. \author Daniel Bundala (Google Summer of Code 2009)
  9. */
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <grass/gis.h>
  13. #include <grass/vector.h>
  14. #include <grass/glocale.h>
  15. #include <grass/dgl/graph.h>
  16. /*!
  17. \brief Get number of articulation points in the graph
  18. \param graph input graph
  19. \param[out] articulation_list list of articulation points
  20. \return number of points
  21. \return -1 on error
  22. */
  23. int NetA_articulation_points(dglGraph_s * graph,
  24. struct ilist *articulation_list)
  25. {
  26. int nnodes;
  27. int points = 0;
  28. dglEdgesetTraverser_s *current; /*edge to be processed when the node is visited */
  29. int *tin, *min_tin; /*time in, and smallest tin over all successors. 0 if not yet visited */
  30. dglInt32_t **parent; /*parents of the nodes */
  31. dglInt32_t **stack; /*stack of nodes */
  32. dglInt32_t **current_edge; /*current edge for each node */
  33. int *mark; /*marked articulation points */
  34. dglNodeTraverser_s nt;
  35. dglInt32_t *current_node;
  36. int stack_size;
  37. int i, time;
  38. nnodes = dglGet_NodeCount(graph);
  39. current =
  40. (dglEdgesetTraverser_s *) G_calloc(nnodes + 1,
  41. sizeof(dglEdgesetTraverser_s));
  42. tin = (int *)G_calloc(nnodes + 1, sizeof(int));
  43. min_tin = (int *)G_calloc(nnodes + 1, sizeof(int));
  44. parent = (dglInt32_t **) G_calloc(nnodes + 1, sizeof(dglInt32_t *));
  45. stack = (dglInt32_t **) G_calloc(nnodes + 1, sizeof(dglInt32_t *));
  46. current_edge = (dglInt32_t **) G_calloc(nnodes + 1, sizeof(dglInt32_t *));
  47. mark = (int *)G_calloc(nnodes + 1, sizeof(int));
  48. if (!tin || !min_tin || !parent || !stack || !current || !mark) {
  49. G_fatal_error(_("Out of memory"));
  50. return -1;
  51. }
  52. for (i = 1; i <= nnodes; i++) {
  53. dglEdgeset_T_Initialize(&current[i], graph,
  54. dglNodeGet_OutEdgeset(graph,
  55. dglGetNode(graph, i)));
  56. current_edge[i] = dglEdgeset_T_First(&current[i]);
  57. tin[i] = mark[i] = 0;
  58. }
  59. dglNode_T_Initialize(&nt, graph);
  60. time = 0;
  61. for (current_node = dglNode_T_First(&nt); current_node;
  62. current_node = dglNode_T_Next(&nt)) {
  63. dglInt32_t current_id = dglNodeGet_Id(graph, current_node);
  64. if (tin[current_id] == 0) {
  65. int children = 0; /*number of subtrees rooted at the root/current_node */
  66. stack[0] = current_node;
  67. stack_size = 1;
  68. parent[current_id] = NULL;
  69. while (stack_size) {
  70. dglInt32_t *node = stack[stack_size - 1];
  71. dglInt32_t node_id = dglNodeGet_Id(graph, node);
  72. if (tin[node_id] == 0) /*vertex visited for the first time */
  73. min_tin[node_id] = tin[node_id] = ++time;
  74. else { /*return from the recursion */
  75. dglInt32_t to = dglNodeGet_Id(graph,
  76. dglEdgeGet_Tail(graph,
  77. current_edge
  78. [node_id]));
  79. if (min_tin[to] >= tin[node_id]) /*no path from the subtree above the current node */
  80. mark[node_id] = 1; /*so the current node must be an articulation point */
  81. if (min_tin[to] < min_tin[node_id])
  82. min_tin[node_id] = min_tin[to];
  83. current_edge[node_id] = dglEdgeset_T_Next(&current[node_id]); /*proceed to the next edge */
  84. }
  85. /*try next edges */
  86. for (; current_edge[node_id]; current_edge[node_id] = dglEdgeset_T_Next(&current[node_id])) {
  87. dglInt32_t *to =
  88. dglEdgeGet_Tail(graph, current_edge[node_id]);
  89. if (to == parent[node_id])
  90. continue; /*skip parent */
  91. int to_id = dglNodeGet_Id(graph, to);
  92. if (tin[to_id]) { /*back edge, cannot be a bridge/articualtion point */
  93. if (tin[to_id] < min_tin[node_id])
  94. min_tin[node_id] = tin[to_id];
  95. }
  96. else { /*forward edge */
  97. if (node_id == current_id)
  98. children++; /*if root, increase number of children */
  99. parent[to_id] = node;
  100. stack[stack_size++] = to;
  101. break;
  102. }
  103. }
  104. if (!current_edge[node_id])
  105. stack_size--; /*current node completely processed */
  106. }
  107. if (children > 1)
  108. mark[current_id] = 1; /*if the root has more than 1 subtrees rooted at it, then it is an
  109. * articulation point */
  110. }
  111. }
  112. for (i = 1; i <= nnodes; i++)
  113. if (mark[i]) {
  114. points++;
  115. Vect_list_append(articulation_list, i);
  116. }
  117. dglNode_T_Release(&nt);
  118. for (i = 1; i <= nnodes; i++)
  119. dglEdgeset_T_Release(&current[i]);
  120. G_free(current);
  121. G_free(tin);
  122. G_free(min_tin);
  123. G_free(parent);
  124. G_free(stack);
  125. G_free(current_edge);
  126. return points;
  127. }