|
5 | 5 | #include <plugins/askrene/algorithm.h> |
6 | 6 | #include <plugins/askrene/priorityqueue.h> |
7 | 7 |
|
| 8 | +static const s64 INFINITE = INT64_MAX; |
| 9 | + |
8 | 10 | #define MAX(x, y) (((x) > (y)) ? (x) : (y)) |
9 | 11 | #define MIN(x, y) (((x) < (y)) ? (x) : (y)) |
10 | 12 |
|
@@ -169,3 +171,154 @@ bool dijkstra_path(const tal_t *ctx, const struct graph *graph, |
169 | 171 | tal_free(this_ctx); |
170 | 172 | return target_found; |
171 | 173 | } |
| 174 | + |
| 175 | +/* Get the max amount of flow one can send from source to target along the path |
| 176 | + * encoded in `prev`. */ |
| 177 | +static s64 get_augmenting_flow(const struct graph *graph, |
| 178 | + const struct node source, |
| 179 | + const struct node target, const s64 *capacity, |
| 180 | + const struct arc *prev) |
| 181 | +{ |
| 182 | + const size_t max_num_nodes = graph_max_num_nodes(graph); |
| 183 | + const size_t max_num_arcs = graph_max_num_arcs(graph); |
| 184 | + assert(max_num_nodes == tal_count(prev)); |
| 185 | + assert(max_num_arcs == tal_count(capacity)); |
| 186 | + |
| 187 | + /* count the number of arcs in the path */ |
| 188 | + int path_length = 0; |
| 189 | + s64 flow = INFINITE; |
| 190 | + |
| 191 | + struct node cur = target; |
| 192 | + while (cur.idx != source.idx) { |
| 193 | + assert(cur.idx < max_num_nodes); |
| 194 | + const struct arc arc = prev[cur.idx]; |
| 195 | + assert(arc.idx < max_num_arcs); |
| 196 | + flow = MIN(flow, capacity[arc.idx]); |
| 197 | + |
| 198 | + /* we are traversing in the opposite direction to the flow, |
| 199 | + * hence the next node is at the tail of the arc. */ |
| 200 | + cur = arc_tail(graph, arc); |
| 201 | + |
| 202 | + /* We may never have a path exceeds the number of nodes, it this |
| 203 | + * happens it means we have an infinite loop. */ |
| 204 | + path_length++; |
| 205 | + if(path_length >= max_num_nodes){ |
| 206 | + flow = -1; |
| 207 | + break; |
| 208 | + } |
| 209 | + } |
| 210 | + |
| 211 | + assert(flow < INFINITE && flow > 0); |
| 212 | + return flow; |
| 213 | +} |
| 214 | + |
| 215 | +/* Augment a `flow` amount along the path defined by `prev`.*/ |
| 216 | +static void augment_flow(const struct graph *graph, |
| 217 | + const struct node source, |
| 218 | + const struct node target, |
| 219 | + const struct arc *prev, |
| 220 | + s64 *capacity, |
| 221 | + s64 flow) |
| 222 | +{ |
| 223 | + const size_t max_num_nodes = graph_max_num_nodes(graph); |
| 224 | + const size_t max_num_arcs = graph_max_num_arcs(graph); |
| 225 | + assert(max_num_nodes == tal_count(prev)); |
| 226 | + assert(max_num_arcs == tal_count(capacity)); |
| 227 | + |
| 228 | + struct node cur = target; |
| 229 | + /* count the number of arcs in the path */ |
| 230 | + int path_length = 0; |
| 231 | + |
| 232 | + while (cur.idx != source.idx) { |
| 233 | + assert(cur.idx < max_num_nodes); |
| 234 | + const struct arc arc = prev[cur.idx]; |
| 235 | + const struct arc dual = arc_dual(graph, arc); |
| 236 | + |
| 237 | + assert(arc.idx < max_num_arcs); |
| 238 | + assert(dual.idx < max_num_arcs); |
| 239 | + |
| 240 | + capacity[arc.idx] -= flow; |
| 241 | + capacity[dual.idx] += flow; |
| 242 | + |
| 243 | + assert(capacity[arc.idx] >= 0); |
| 244 | + |
| 245 | + /* we are traversing in the opposite direction to the flow, |
| 246 | + * hence the next node is at the tail of the arc. */ |
| 247 | + cur = arc_tail(graph, arc); |
| 248 | + |
| 249 | + /* We may never have a path exceeds the number of nodes, it this |
| 250 | + * happens it means we have an infinite loop. */ |
| 251 | + path_length++; |
| 252 | + if(path_length >= max_num_nodes) |
| 253 | + break; |
| 254 | + } |
| 255 | + assert(path_length < max_num_nodes); |
| 256 | +} |
| 257 | + |
| 258 | +bool simple_feasibleflow(const tal_t *ctx, |
| 259 | + const struct graph *graph, |
| 260 | + const struct node source, |
| 261 | + const struct node destination, |
| 262 | + s64 *capacity, |
| 263 | + s64 amount) |
| 264 | +{ |
| 265 | + tal_t *this_ctx = tal(ctx, tal_t); |
| 266 | + const size_t max_num_arcs = graph_max_num_arcs(graph); |
| 267 | + const size_t max_num_nodes = graph_max_num_nodes(graph); |
| 268 | + |
| 269 | + /* check preconditions */ |
| 270 | + if (amount < 0) |
| 271 | + goto finish; |
| 272 | + |
| 273 | + if (!graph || source.idx >= max_num_nodes || |
| 274 | + destination.idx >= max_num_nodes || !capacity) |
| 275 | + goto finish; |
| 276 | + |
| 277 | + if (tal_count(capacity) != max_num_arcs) |
| 278 | + goto finish; |
| 279 | + |
| 280 | + /* path information |
| 281 | + * prev: is the id of the arc that lead to the node. */ |
| 282 | + struct arc *prev = tal_arr(this_ctx, struct arc, max_num_nodes); |
| 283 | + if (!prev) |
| 284 | + goto finish; |
| 285 | + |
| 286 | + while (amount > 0) { |
| 287 | + /* find a path from source to target */ |
| 288 | + if (!BFS_path(this_ctx, graph, source, destination, capacity, 1, |
| 289 | + prev)) |
| 290 | + goto finish; |
| 291 | + |
| 292 | + /* traverse the path and see how much flow we can send */ |
| 293 | + s64 delta = get_augmenting_flow(graph, source, destination, |
| 294 | + capacity, prev); |
| 295 | + |
| 296 | + /* commit that flow to the path */ |
| 297 | + delta = MIN(amount, delta); |
| 298 | + assert(delta > 0 && delta <= amount); |
| 299 | + |
| 300 | + augment_flow(graph, source, destination, prev, capacity, delta); |
| 301 | + amount -= delta; |
| 302 | + } |
| 303 | +finish: |
| 304 | + tal_free(this_ctx); |
| 305 | + return amount == 0; |
| 306 | +} |
| 307 | + |
| 308 | +s64 node_balance(const struct graph *graph, |
| 309 | + const struct node node, |
| 310 | + const s64 *capacity) |
| 311 | +{ |
| 312 | + s64 balance = 0; |
| 313 | + |
| 314 | + for (struct arc arc = node_adjacency_begin(graph, node); |
| 315 | + !node_adjacency_end(arc); arc = node_adjacency_next(graph, arc)) { |
| 316 | + struct arc dual = arc_dual(graph, arc); |
| 317 | + |
| 318 | + if (arc_is_dual(graph, arc)) |
| 319 | + balance += capacity[arc.idx]; |
| 320 | + else |
| 321 | + balance -= capacity[dual.idx]; |
| 322 | + } |
| 323 | + return balance; |
| 324 | +} |
0 commit comments