GRASS 8 Programmer's Manual 8.6.0dev(2026)-1878fdfec5
Loading...
Searching...
No Matches
flow.c
Go to the documentation of this file.
1/*!
2 \file vector/neta/flow.c
3
4 \brief Network Analysis library - flow in graph
5
6 Computes the length of the shortest path between all pairs of nodes
7 in the network.
8
9 SPDX-FileCopyrightText: 2009-2010 Daniel Bundala
10 SPDX-FileCopyrightText: GRASS Development Team
11 SPDX-License-Identifier: GPL-2.0-or-later
12
13 \author Daniel Bundala (Google Summer of Code 2009)
14 */
15
16#include <stdio.h>
17#include <stdlib.h>
18#include <grass/gis.h>
19#include <grass/vector.h>
20#include <grass/glocale.h>
21#include <grass/dgl/graph.h>
22#include <grass/neta.h>
23
25{
26 if (x >= 0)
27 return 1;
28 return -1;
29}
30
31/*!
32 \brief Get max flow from source to sink.
33
34 Array flow stores flow for each edge. Negative flow corresponds to a
35 flow in opposite direction. The function assumes that the edge costs
36 correspond to edge capacities.
37
38 \param graph input graph
39 \param source_list list of sources
40 \param sink_list list of sinks
41 \param[out] flow max flows
42
43 \return number of flows
44 \return -1 on failure
45 */
47 struct ilist *sink_list, int *flow)
48{
49 int nnodes, nlines, i;
52 dglInt32_t **prev;
53 char *is_source, *is_sink;
54 int begin, end, total_flow;
57
59 nlines = dglGet_EdgeCount(graph) /
60 2; /*each line corresponds to two edges. One in each direction */
61 queue = (dglInt32_t *)G_calloc(nnodes + 3, sizeof(dglInt32_t));
62 prev = (dglInt32_t **)G_calloc(nnodes + 3, sizeof(dglInt32_t *));
63 is_source = (char *)G_calloc(nnodes + 3, sizeof(char));
64 is_sink = (char *)G_calloc(nnodes + 3, sizeof(char));
65 if (!queue || !prev || !is_source || !is_sink) {
66 G_fatal_error(_("Out of memory"));
67 return -1;
68 }
69
70 for (i = 0; i < source_list->n_values; i++)
71 is_source[source_list->value[i]] = 1;
72 for (i = 0; i < sink_list->n_values; i++)
73 is_sink[sink_list->value[i]] = 1;
74
75 for (i = 0; i <= nlines; i++)
76 flow[i] = 0;
77
78 ncost = 0;
80
81 total_flow = 0;
82 while (1) {
84 int found = -1;
85
86 begin = end = 0;
87 for (i = 0; i < source_list->n_values; i++)
88 queue[end++] = source_list->value[i];
89
90 for (i = 1; i <= nnodes; i++) {
91 prev[i] = NULL;
92 }
93 while (begin != end && found == -1) {
95 dglInt32_t *edge, *node = dglGetNode(graph, vertex);
96
99 for (edge = dglEdgeset_T_First(&et); edge;
100 edge = dglEdgeset_T_Next(&et)) {
102 dglInt32_t id = dglEdgeGet_Id(graph, edge);
103 dglInt32_t to =
105 if (!is_source[to] && prev[to] == NULL &&
106 cap > sign(id) * flow[labs(id)]) {
107 prev[to] = edge;
108 if (is_sink[to]) {
109 found = to;
110 break;
111 }
112 /* do not go through closed nodes */
113 if (have_node_costs) {
114 memcpy(&ncost,
116 dglEdgeGet_Tail(graph, edge)),
117 sizeof(ncost));
118 }
119 if (ncost >= 0)
120 queue[end++] = to;
121 }
122 }
124 }
125 if (found == -1)
126 break; /*no augmenting path */
127 /*find minimum residual capacity along the augmenting path */
128 node = found;
129 edge_id = dglEdgeGet_Id(graph, prev[node]);
130 min_residue = dglEdgeGet_Cost(graph, prev[node]) -
132 while (!is_source[node]) {
134
135 edge_id = dglEdgeGet_Id(graph, prev[node]);
136 residue = dglEdgeGet_Cost(graph, prev[node]) -
138 if (residue < min_residue)
140 node = dglNodeGet_Id(graph, dglEdgeGet_Head(graph, prev[node]));
141 }
143 /*update flow along the augmenting path */
144 node = found;
145 while (!is_source[node]) {
146 edge_id = dglEdgeGet_Id(graph, prev[node]);
148 node = dglNodeGet_Id(graph, dglEdgeGet_Head(graph, prev[node]));
149 }
150 }
151
152 G_free(queue);
153 G_free(prev);
156
157 return total_flow;
158}
159
160/*!
161 \brief Calculates minimum cut between source(s) and sink(s).
162
163 Flow is the array produced by NetA_flow() method when called with
164 source_list and sink_list as the input. The output of this and
165 NetA_flow() method should be the same.
166
167 \param graph input graph
168 \param source_list list of sources
169 \param sink_list list of sinks (unused)
170 \param flow
171 \param[out] cut list of edges (cut)
172
173 \return number of edges
174 \return -1 on failure
175 */
177 struct ilist *sink_list G_UNUSED, int *flow, struct ilist *cut)
178{
179 int nnodes, i;
182 char *visited;
183 int begin, end, total_flow;
184
186 queue = (dglInt32_t *)G_calloc(nnodes + 3, sizeof(dglInt32_t));
187 visited = (char *)G_calloc(nnodes + 3, sizeof(char));
188 if (!queue || !visited) {
189 G_fatal_error(_("Out of memory"));
190 return -1;
191 }
192
193 total_flow = begin = end = 0;
194
195 for (i = 1; i <= nnodes; i++)
196 visited[i] = 0;
197
198 for (i = 0; i < source_list->n_values; i++) {
199 queue[end++] = source_list->value[i];
200 visited[source_list->value[i]] = 1;
201 }
202
203 /* find vertices reachable from source(s) using only non-saturated edges */
204 while (begin != end) {
206 dglInt32_t *edge, *node = dglGetNode(graph, vertex);
207
209 for (edge = dglEdgeset_T_First(&et); edge;
210 edge = dglEdgeset_T_Next(&et)) {
212 dglInt32_t id = dglEdgeGet_Id(graph, edge);
214 if (!visited[to] && cap > sign(id) * flow[labs(id)]) {
215 visited[to] = 1;
216 queue[end++] = to;
217 }
218 }
220 }
221 /*saturated edges from reachable vertices to non-reachable ones form a
222 * minimum cost */
224 for (i = 1; i <= nnodes; i++) {
225 if (!visited[i])
226 continue;
227 dglInt32_t *node, *edgeset, *edge;
228
229 node = dglGetNode(graph, i);
232 for (edge = dglEdgeset_T_First(&et); edge;
233 edge = dglEdgeset_T_Next(&et)) {
235
238 if (!visited[to] && flow[edge_id] != 0) {
241 }
242 }
244 }
245
247 G_free(queue);
248 return total_flow;
249}
250
251/*!
252 \brief Splits each vertex of in graph into two vertices
253
254 The method splits each vertex of in graph into two vertices: in
255 vertex and out vertex. Also, it adds an edge from an in vertex to
256 the corresponding out vertex (capacity=2) and it adds an edge from
257 out vertex to in vertex for each edge present in the in graph
258 (forward capacity=1, backward capacity=0). If the id of a vertex is
259 v then id of in vertex is 2*v-1 and of out vertex 2*v.
260
261 \param in from graph
262 \param out to graph
263 \param node_costs list of node costs
264
265 \return number of undirected edges in the graph
266 \return -1 on failure
267 */
268int NetA_split_vertices(dglGraph_s *in, dglGraph_s *out, int *node_costs)
269{
270 dglInt32_t opaqueset[16] = {360000, 0, 0, 0, 0, 0, 0, 0,
271 0, 0, 0, 0, 0, 0, 0, 0};
275
278 edge_cnt = 0;
280
284
285 edge_cnt++;
286 dglInt32_t cost = 1;
287
288 if (node_costs)
289 cost = node_costs[v];
290 /* skip closed nodes */
291 if (cost < 0)
292 continue;
293 if (cost > max_node_cost)
294 max_node_cost = cost;
295 dglAddEdge(out, 2 * v - 1, 2 * v, cost, edge_cnt);
296 dglAddEdge(out, 2 * v, 2 * v - 1, (dglInt32_t)0, -edge_cnt);
297 }
303 dglInt32_t *edge;
305 dglInt32_t cost = 1;
306
307 if (node_costs)
308 cost = node_costs[v];
309 /* skip closed nodes */
310 if (cost < 0)
311 continue;
312
314 for (edge = dglEdgeset_T_First(&et); edge;
315 edge = dglEdgeset_T_Next(&et)) {
316 dglInt32_t to;
317
318 to = dglNodeGet_Id(in, dglEdgeGet_Tail(in, edge));
319 edge_cnt++;
320 dglAddEdge(out, 2 * v, 2 * to - 1, max_node_cost + 1, edge_cnt);
321 dglAddEdge(out, 2 * to - 1, 2 * v, (dglInt32_t)0, -edge_cnt);
322 }
324 }
326 if (dglFlatten(out) < 0)
327 G_fatal_error(_("GngFlatten error"));
328 return edge_cnt;
329}
#define NULL
Definition ccmath.h:32
Definition queue.h:43
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
int Vect_list_append(struct ilist *, int)
Append new item to the end of list if not yet present.
int Vect_reset_list(struct ilist *)
Reset ilist structure.
int NetA_min_cut(dglGraph_s *graph, struct ilist *source_list, struct ilist *sink_list, int *flow, struct ilist *cut)
Calculates minimum cut between source(s) and sink(s).
Definition flow.c:176
dglInt32_t sign(dglInt32_t x)
Definition flow.c:24
int NetA_flow(dglGraph_s *graph, struct ilist *source_list, struct ilist *sink_list, int *flow)
Get max flow from source to sink.
Definition flow.c:46
int NetA_split_vertices(dglGraph_s *in, dglGraph_s *out, int *node_costs)
Splits each vertex of in graph into two vertices.
Definition flow.c:268
#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 _(str)
Definition glocale.h:10
List of integers.
Definition gis.h:712
Definition path.h:10
unsigned char dglByte_t
Definition type.h:23
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 dglAddEdge(dglGraph_s *pGraph, dglInt32_t nHead, dglInt32_t nTail, dglInt32_t nCost, dglInt32_t nEdge)
int dglEdgeset_T_Initialize(dglEdgesetTraverser_s *pT, dglGraph_s *pGraph, dglInt32_t *pnEdgeset)
int dglNode_T_Initialize(dglNodeTraverser_s *pT, dglGraph_s *pGraph)
dglInt32_t dglEdgeGet_Id(dglGraph_s *pGraph, dglInt32_t *pnEdge)
dglInt32_t * dglEdgeset_T_First(dglEdgesetTraverser_s *pT)
int dglInitialize(dglGraph_s *pGraph, dglByte_t Version, dglInt32_t NodeAttrSize, dglInt32_t EdgeAttrSize, dglInt32_t *pOpaqueSet)
int dglGet_EdgeCount(dglGraph_s *pgraph)
dglInt32_t * dglEdgeset_T_Next(dglEdgesetTraverser_s *pT)
dglInt32_t * dglNodeGet_Attr(dglGraph_s *pGraph, dglInt32_t *pnNode)
int dglGet_NodeCount(dglGraph_s *pgraph)
int dglFlatten(dglGraph_s *pGraph)
dglInt32_t dglEdgeGet_Cost(dglGraph_s *pGraph, dglInt32_t *pnEdge)
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)
#define x