GRASS 8 Programmer's Manual 8.6.0dev(2026)-4bb960b182
Loading...
Searching...
No Matches
span-template.c
Go to the documentation of this file.
1/* LIBDGL -- a Directed Graph Library implementation
2 * SPDX-FileCopyrightText: 2002 Roberto Micarelli
3 * SPDX-FileCopyrightText: GRASS Development Team
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7/*
8 * best view with tabstop=4
9 */
10
11#include <grass/gis.h>
12
13/*
14 * Build the depth-first spanning tree of 'pgraphIn' into 'pgraphOut'
15 * - pgraphOut must have been previously initialized by the caller and is
16 * returned in TREE state
17 * - I prefer using a iterative approach with a stack for 'waiting edges'
18 * instead of recursion: it's cheaper to stack 8 bytes for each edge than the
19 * whole function stack
20 * - The visited network is passed by the caller because this function can be
21 * used for two purposes:
22 * 1. generate a single spanning tree (dglDepthSpanning)
23 * 2. part of a loop for generating connected-components of the graph
24 * (dglDepthComponents)
25 */
28 void *pvVisited, dglSpanClip_fn fnClip,
29 void *pvClipArg)
30{
31 struct _stackItem {
33 dglInt32_t *pnEdge;
34 int iWay;
35 };
36
37 struct _stackItem stackItem;
38 struct _stackItem *pStackItem;
39
44 long istack = 0;
45 unsigned char *pstack = NULL;
46 int nret;
50
51 if ((pHead = dglGetNode(pgraphIn, nVertex)) == NULL) {
53 goto dfs_error;
54 }
55
56 /*
57 * the simplest case is when vertex node is alone or has no outgoing edges,
58 * the result of the spanning is a graph having only one node
59 */
65 if (nret < 0) {
66 goto dfs_error;
67 }
68 return 0;
69 }
70
71 if ((DGL_NODE_STATUS(pHead) & DGL_NS_HEAD) || pgraphIn->Version == 3) {
72
74
76 goto dfs_error;
77 }
80 stackItem.pnHead = pHead;
81 stackItem.pnEdge = pEdge;
82 stackItem.iWay = 0;
83 if ((pstack = dgl_mempush(pstack, &istack, sizeof(stackItem),
84 &stackItem)) == NULL) {
86 goto dfs_error;
87 }
88 }
90
91 if (pgraphIn->Version == 3) {
93
95 goto dfs_error;
96 }
100 continue;
101 stackItem.pnHead = pHead;
102 stackItem.pnEdge = pEdge;
103 stackItem.iWay = 1;
104 if ((pstack = dgl_mempush(pstack, &istack, sizeof(stackItem),
105 &stackItem)) == NULL) {
107 goto dfs_error;
108 }
109 }
111 }
112
113 if (dglTreeNodeAdd(pvVisited, DGL_NODE_ID(pHead)) == NULL) {
115 goto dfs_error;
116 }
117 }
118
119 while ((pStackItem = (struct _stackItem *)dgl_mempop(
120 pstack, &istack, sizeof(stackItem))) != NULL) {
121 pHead = pStackItem->pnHead;
122 pEdge = pStackItem->pnEdge;
123
124 if (pStackItem->iWay == 0)
126 else
128
130 if (avl_find(pvVisited, &findVisited)) { /* already visited */
131 continue;
132 }
133
134 if (fnClip) {
135 clipInput.pnNodeFrom = pHead;
136 clipInput.pnEdge = pEdge;
137 clipInput.pnNodeTo = pTail;
139 continue;
140 }
141
142 if (dglTreeNodeAdd(pvVisited, DGL_NODE_ID(pTail)) == NULL) {
144 goto dfs_error;
145 }
146
147 /* add this edge */
152
153 if (nret < 0) {
154 goto dfs_error;
155 }
156
157 if ((DGL_NODE_STATUS(pHead) & DGL_NS_HEAD) || pgraphIn->Version == 3) {
158
161 goto dfs_error;
162 }
165 stackItem.pnHead = pTail;
166 stackItem.pnEdge = pEdge;
167 stackItem.iWay = 0;
168 if ((pstack = dgl_mempush(pstack, &istack, sizeof(stackItem),
169 &stackItem)) == NULL) {
171 goto dfs_error;
172 }
173 }
175
176 if (pgraphIn->Version == 3) {
179 0) {
180 goto dfs_error;
181 }
185 continue;
186 stackItem.pnHead = pTail;
187 stackItem.pnEdge = pEdge;
188 stackItem.iWay = 1;
190 sizeof(stackItem), &stackItem)) ==
191 NULL) {
193 goto dfs_error;
194 }
195 }
197 }
198 }
199 }
200
201 if (pstack)
202 free(pstack);
203 return 0;
204
206 if (pstack)
207 free(pstack);
208 return -pgraphIn->iErrno;
209}
210
211/*
212 * Use a edge prioritized, tree growing scheme (aka Prim algorithm) in order to
213 * be applicable to both undirected graphs (minimum spanning tree - MST) and
214 * digraphs (minimum arborescense tree - MAT)
215 * The vertex argument is ignored in MST (when algorithm is applied to a
216 * version 3 undirected graph).
217 */
221 void *pvClipArg G_UNUSED)
222{
229 int nret;
230
232
233 if (pgraphIn->Version == 3) { /* undirected: pick up the first node */
235
239 }
240 else { /* directed: pick up the arborescense origin */
242 }
243
244 if (pHead == NULL) {
246 goto mst_error;
247 }
248
251
253 (DGL_NODE_STATUS(pHead) & DGL_NS_ALONE) || pgraphIn->Version == 3) {
255 DGL_NODE_ATTR_PTR(pHead), 0) < 0) {
256 goto mst_error;
257 }
258
261 return 0;
262 }
263
266 goto mst_error;
267 }
270 HeapData.pv = pEdge;
272 HeapData) < 0) {
273 pgraphIn->iErrno = DGL_ERR_HeapError;
274 goto mst_error;
275 }
276 }
278 if (pgraphIn->Version == 3) {
281 0) {
282 goto mst_error;
283 }
287 continue;
288 HeapData.pv = pEdge;
290 1, HeapData) < 0) {
291 pgraphIn->iErrno = DGL_ERR_HeapError;
292 goto mst_error;
293 }
294 }
296 }
297 }
298 }
299 else {
300 pgraphIn->iErrno = DGL_ERR_BadEdge;
301 goto mst_error;
302 }
303
304 while (dglHeapExtractMin(&FrontEdgeHeap, &HeapItem) == 1) {
305 pEdge = HeapItem.value.pv;
306
307 if (HeapItem.flags == 0) {
310 goto mst_error;
311 }
314 goto mst_error;
315 }
316 }
317 else if (pgraphIn->Version == 3) {
320 goto mst_error;
321 }
324 goto mst_error;
325 }
326 }
327 else
328 continue;
329
330 findItem.nKey = DGL_NODE_ID(pTail);
331
332 if ((pPredistItem = avl_find(pgraphOut->pNodeTree, &findItem)) !=
333 NULL) {
334 continue;
335 }
336
341
342 if (nret < 0) {
343 goto mst_error;
344 }
345
346 pHead = pTail;
347
348 if ((DGL_NODE_STATUS(pHead) & DGL_NS_HEAD) || pgraphIn->Version == 3) {
351 goto mst_error;
352 }
355 HeapData.pv = pEdge;
357 HeapData) < 0) {
358 pgraphIn->iErrno = DGL_ERR_HeapError;
359 goto mst_error;
360 }
361 }
362 if (pgraphIn->Version == 3) {
366 0) {
367 goto mst_error;
368 }
372 continue;
373 HeapData.pv = pEdge;
375 1, HeapData) < 0) {
376 pgraphIn->iErrno = DGL_ERR_HeapError;
377 goto mst_error;
378 }
379 }
381 }
382 }
383 }
385 return 0;
386
389 return -pgraphIn->iErrno;
390}
#define NULL
Definition ccmath.h:32
#define G_UNUSED
A macro for an attribute, if attached to a variable, indicating that the variable is not used.
Definition gis.h:43
#define DGL_NS_TAIL
Definition graph.h:48
#define DGL_NS_ALONE
Definition graph.h:49
#define DGL_ERR_MemoryExhausted
Definition graph.h:242
#define DGL_NS_HEAD
Definition graph.h:47
#define DGL_ERR_HeadNodeNotFound
Definition graph.h:249
#define DGL_ERR_UnexpectedNullPointer
Definition graph.h:256
#define DGL_ERR_BadEdge
Definition graph.h:251
int(* dglSpanClip_fn)(dglGraph_s *, dglGraph_s *, dglSpanClipInput_s *, dglSpanClipOutput_s *, void *)
Definition graph.h:173
#define DGL_ERR_HeapError
Definition graph.h:243
#define DGL_ES_DIRECTED
Definition graph.h:54
void dglHeapInit(dglHeap_s *pheap)
Definition heap.c:15
int dglHeapInsertMin(dglHeap_s *pheap, long key, unsigned char flags, dglHeapData_u value)
Definition heap.c:38
void dglHeapFree(dglHeap_s *pheap, dglHeapCancelItem_fn pfnCancelItem)
Definition heap.c:23
int dglHeapExtractMin(dglHeap_s *pheap, dglHeapNode_s *pnoderet)
Definition heap.c:64
unsigned char * dgl_mempop(unsigned char *pstack, long *istack, long size)
Definition helpers.c:35
unsigned char * dgl_mempush(unsigned char *pstack, long *istack, long size, void *pv)
Definition helpers.c:22
int DGL_SPAN_MINIMUM_SPANNING_FUNC(dglGraph_s *pgraphIn, dglGraph_s *pgraphOut, dglInt32_t nVertex, dglSpanClip_fn fnClip, void *pvClipArg)
int DGL_SPAN_DEPTHFIRST_SPANNING_FUNC(dglGraph_s *pgraphIn, dglGraph_s *pgraphOut, dglInt32_t nVertex, void *pvVisited, dglSpanClip_fn fnClip, void *pvClipArg)
void free(void *)
dglTreeNode_s * dglTreeNodeAdd(void *pavl, dglInt32_t nKey)
Definition tree.c:54
#define avl_find
Definition tree.h:26
long dglInt32_t
Definition type.h:24
#define DGL_EDGESET_T_FIRST_FUNC
Definition v1-defs.h:100
#define DGL_NODE_T_RELEASE_FUNC
Definition v1-defs.h:94
#define DGL_NODE_T_INITIALIZE_FUNC
Definition v1-defs.h:93
#define DGL_NODE_STATUS
Definition v1-defs.h:114
#define DGL_ADD_NODE_FUNC
Definition v1-defs.h:78
#define DGL_NODE_ID
Definition v1-defs.h:115
#define DGL_NODE_T_FIRST_FUNC
Definition v1-defs.h:95
#define DGL_GET_NODE_FUNC
Definition v1-defs.h:80
#define DGL_EDGE_ATTR_PTR
Definition v1-defs.h:127
#define DGL_EDGE_STATUS(p)
Definition v1-defs.h:124
#define DGL_EDGESET_T_RELEASE_FUNC
Definition v1-defs.h:99
#define DGL_EDGESET_T_INITIALIZE_FUNC
Definition v1-defs.h:98
#define DGL_NODE_ATTR_PTR
Definition v1-defs.h:116
#define DGL_EDGE_ID
Definition v1-defs.h:126
#define DGL_ADD_EDGE_FUNC
Definition v1-defs.h:84
#define DGL_EDGESET_T_NEXT_FUNC
Definition v1-defs.h:101
#define DGL_EDGE_COST
Definition v1-defs.h:125
dglInt32_t * dglGetNode(dglGraph_s *pGraph, dglInt32_t nNodeId)