GRASS 8 Programmer's Manual 8.6.0dev(2026)-1878fdfec5
Loading...
Searching...
No Matches
components.c
Go to the documentation of this file.
1/*!
2 \file vector/neta/components.c
3
4 \brief Network Analysis library - graph components
5
6 Computes strongly and weakly connected components.
7
8 SPDX-FileCopyrightText: 2009-2010 Daniel Bundala
9 SPDX-FileCopyrightText: GRASS Development Team
10 SPDX-License-Identifier: GPL-2.0-or-later
11
12 \author Daniel Bundala (Google Summer of Code 2009)
13 \author Markus Metz
14 */
15
16/* example:
17 *
18 * X -->-- X ---- X --<-- X ---- X
19 * N1 N2 N3 N4 N5
20 *
21 * -->--, --<-- one-way
22 * ---- both ways
23 *
24 * weakly connected:
25 * all 5 nodes, even though there is no direct path from N1 to N4, 5
26 * but N1 connects to N2, 3, and N4, 5 also connect to N2, 3
27 *
28 * strongly connected:
29 * no path from N2 to N1, no path from N3 to N4
30 * component 1: N1
31 * component 2: N2, 3
32 * Component3: N4, 5
33 */
34
35#include <stdio.h>
36#include <stdlib.h>
37#include <grass/gis.h>
38#include <grass/vector.h>
39#include <grass/glocale.h>
40#include <grass/dgl/graph.h>
41
42/*!
43 \brief Computes weakly connected components
44
45 \param graph input graph
46 \param[out] component array of component ids
47
48 \return number of components
49 \return -1 on failure
50 */
52{
53 int nnodes, i;
60
61 if (graph->Version < 2) {
62 G_warning("Directed graph must be version 2 or 3 for "
63 "NetA_weakly_connected_components()");
64 return -1;
65 }
66
67 components = 0;
69 stack = (dglInt32_t *)G_calloc(nnodes + 1, sizeof(dglInt32_t));
70 if (!stack) {
71 G_fatal_error(_("Out of memory"));
72 return -1;
73 }
74
75 for (i = 1; i <= nnodes; i++)
76 component[i] = 0;
77
78 ncost = 0;
80
82
86
87 if (!component[cur_node_id]) {
88 stack[0] = cur_node_id;
89 stack_size = 1;
91 while (stack_size) {
92 dglInt32_t *node, *edgeset, *edge;
94
95 node = dglGetNode(graph, stack[--stack_size]);
98 for (edge = dglEdgeset_T_First(&et); edge;
99 edge = dglEdgeset_T_Next(&et)) {
100 dglInt32_t to;
101
103 if (!component[to]) {
104 component[to] = components;
105 /* do not go through closed nodes */
106 if (have_node_costs) {
107 memcpy(&ncost,
109 graph, dglEdgeGet_Tail(graph, edge)),
110 sizeof(ncost));
111 }
112 if (ncost >= 0)
113 stack[stack_size++] = to;
114 }
115 }
117
120 for (edge = dglEdgeset_T_First(&et); edge;
121 edge = dglEdgeset_T_Next(&et)) {
122 dglInt32_t to;
123
125 if (!component[to]) {
126 component[to] = components;
127 /* do not go through closed nodes */
128 if (have_node_costs) {
129 memcpy(&ncost,
131 graph, dglEdgeGet_Tail(graph, edge)),
132 sizeof(ncost));
133 }
134 if (ncost >= 0)
135 stack[stack_size++] = to;
136 }
137 }
139 }
140 }
141 }
143
144 G_free(stack);
145 return components;
146}
147
148/*!
149 \brief Computes strongly connected components with Kosaraju's
150 two-pass algorithm
151
152 \param graph input graph
153 \param[out] component array of component ids
154
155 \return number of components
156 \return -1 on failure
157 */
159{
160 int nnodes, i;
162 int *processed;
166 int have_node_costs;
168
169 if (graph->Version < 2) {
170 G_warning("Directed graph must be version 2 or 3 for "
171 "NetA_strongly_connected_components()");
172 return -1;
173 }
174
175 components = 0;
177 stack = (dglInt32_t *)G_calloc(nnodes + 1, sizeof(dglInt32_t));
178 order = (dglInt32_t *)G_calloc(nnodes + 1, sizeof(dglInt32_t));
179 processed = (int *)G_calloc(nnodes + 1, sizeof(int));
180 if (!stack || !order || !processed) {
181 G_fatal_error(_("Out of memory"));
182 return -1;
183 }
184
185 for (i = 1; i <= nnodes; i++) {
186 component[i] = 0;
187 }
188
189 ncost = 0;
191
192 order_size = 0;
194
198
199 if (!component[cur_node_id]) {
201 stack[0] = cur_node_id;
202 stack_size = 1;
203 while (stack_size) {
204 dglInt32_t *node, *edgeset, *edge;
207
208 if (processed[node_id]) {
209 stack_size--;
211 continue;
212 }
213 processed[node_id] = 1;
214
215 node = dglGetNode(graph, node_id);
218 for (edge = dglEdgeset_T_First(&et); edge;
219 edge = dglEdgeset_T_Next(&et)) {
220 dglInt32_t to;
221
223 if (!component[to]) {
224 component[to] = components;
225 /* do not go through closed nodes */
226 if (have_node_costs) {
227 memcpy(&ncost,
229 graph, dglEdgeGet_Tail(graph, edge)),
230 sizeof(ncost));
231 }
232 if (ncost < 0)
233 processed[to] = 1;
234
235 stack[stack_size++] = to;
236 }
237 }
239 }
240 }
241 }
242
244
245 components = 0;
247
248 while (order_size) {
251
252 if (cur_comp < 1) {
254 stack[0] = cur_node_id;
255 stack_size = 1;
256 while (stack_size) {
257 dglInt32_t *node, *edgeset, *edge;
260
261 node = dglGetNode(graph, node_id);
264 for (edge = dglEdgeset_T_First(&et); edge;
265 edge = dglEdgeset_T_Next(&et)) {
266 dglInt32_t to;
267
269 if (component[to] == cur_comp) {
270 component[to] = components;
271 /* do not go through closed nodes */
272 if (have_node_costs) {
273 memcpy(&ncost,
275 graph, dglEdgeGet_Head(graph, edge)),
276 sizeof(ncost));
277 }
278 if (ncost >= 0)
279 stack[stack_size++] = to;
280 }
281 }
283 }
284 }
285 }
287
288 G_free(stack);
289 G_free(order);
291 return components;
292}
int order(int i_x, int i_y, int yNum)
int NetA_strongly_connected_components(dglGraph_s *graph, int *component)
Computes strongly connected components with Kosaraju's two-pass algorithm.
Definition components.c:158
int NetA_weakly_connected_components(dglGraph_s *graph, int *component)
Computes weakly connected components.
Definition components.c:51
void G_free(void *)
Free allocated memory.
Definition gis/alloc.c:145
#define G_calloc(m, n)
Definition defs/gis.h:137
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
void G_warning(const char *,...) __attribute__((format(printf
#define _(str)
Definition glocale.h:10
long dglInt32_t
Definition type.h:24
dglInt32_t * dglNode_T_Next(dglNodeTraverser_s *pT)
dglInt32_t * dglNode_T_First(dglNodeTraverser_s *pT)
dglInt32_t * dglGetNode(dglGraph_s *pGraph, dglInt32_t nNodeId)
int dglGet_NodeAttrSize(dglGraph_s *pgraph)
dglInt32_t * dglNodeGet_OutEdgeset(dglGraph_s *pGraph, dglInt32_t *pnNode)
int dglEdgeset_T_Initialize(dglEdgesetTraverser_s *pT, dglGraph_s *pGraph, dglInt32_t *pnEdgeset)
dglInt32_t * dglNodeGet_InEdgeset(dglGraph_s *pGraph, dglInt32_t *pnNode)
int dglNode_T_Initialize(dglNodeTraverser_s *pT, dglGraph_s *pGraph)
dglInt32_t * dglEdgeset_T_First(dglEdgesetTraverser_s *pT)
dglInt32_t * dglEdgeset_T_Next(dglEdgesetTraverser_s *pT)
dglInt32_t * dglNodeGet_Attr(dglGraph_s *pGraph, dglInt32_t *pnNode)
int dglGet_NodeCount(dglGraph_s *pgraph)
void dglNode_T_Release(dglNodeTraverser_s *pT)
void dglEdgeset_T_Release(dglEdgesetTraverser_s *pT)
dglInt32_t * dglEdgeGet_Head(dglGraph_s *pGraph, dglInt32_t *pnEdge)
dglInt32_t * dglEdgeGet_Tail(dglGraph_s *pGraph, dglInt32_t *pnEdge)
dglInt32_t dglNodeGet_Id(dglGraph_s *pGraph, dglInt32_t *pnNode)