The Maximum Flow algorithm finds the maximum amount of flow that can be sent from a source node to a sink node through a network, respecting edge capacities. Unlike Minimum Cost Flow which also minimizes cost, this algorithm only maximizes flow.
Applications:
In a flow network, each edge has a capacity (the maximum flow it can carry). The maximum flow is the largest total flow that can be routed from source to sink without exceeding any edge's capacity.
This implementation uses the Push-Relabel algorithm:
Using this network with capacity and cost on each edge:
Step 1 (Flood): Push maximum flow from S to neighbors: 10 units to A, 8 units to B. Now A has 10 excess, B has 8 excess.
Step 2 (Push toward sink): Each node pushes excess greedily to its outgoing edges in no particular order — the algorithm doesn't know the optimal split in advance. For example,
A now has 10 excess, it might split as 5 to B and 5 to C, or 3 to B and 7 to C. Suppose A pushes 5 to B and 5 to C.B now has 13 excess (8 from S + 5 from A). Pushes 6 to T. B's excess = 7.C has 5 excess. Pushes 5 to T. T receives 11 total.Step 3 (Redistribute): Using reverse edges, B pushes 2 units back to A. A redirects these 2 units to C (A→C still has 2 remaining capacity). C pushes 2 more to T. The remaining 5 excess at B drains back to S.
Result: Maximum flow = 13. Final flow per edge:
| Edge | Capacity | Flow |
|---|---|---|
| S→A | 10 | 7 |
| S→B | 8 | 6 |
| A→B | 5 | 0 |
| A→C | 7 | 7 |
| B→T | 6 | 6 |
| C→T | 10 | 7 |
NOTEThe actual flow distribution per edge may vary depending on the order nodes push their excess, but the maximum flow value is always the same.
capacityProperty is not specified, all edges have unit capacity (1.0).GQLINSERT (S:default {_id: "S"}), (A:default {_id: "A"}), (B:default {_id: "B"}), (C:default {_id: "C"}), (D:default {_id: "D"}), (T:default {_id: "T"}), (S)-[:default {cap: 8}]->(A), (S)-[:default {cap: 6}]->(B), (A)-[:default {cap: 4}]->(C), (A)-[:default {cap: 5}]->(D), (B)-[:default {cap: 3}]->(C), (B)-[:default {cap: 5}]->(D), (C)-[:default {cap: 7}]->(T), (D)-[:default {cap: 6}]->(T)
| Name | Type | Default | Description |
|---|---|---|---|
sourceNode | STRING | / | Required. Source node _id. |
sinkNode | STRING | / | Required. Sink node _id. |
capacityProperty | STRING | / | Edge property to use as capacity. If unset, all edges have unit capacity. |
Returns:
| Column | Type | Description |
|---|---|---|
maxFlow | FLOAT | Total maximum flow value |
sourceId | STRING | Source node of the edge |
targetId | STRING | Target node of the edge |
flow | FLOAT | Flow through this edge |
capacity | FLOAT | Capacity of this edge |
GQLCALL algo.maxflow({ sourceNode: "S", sinkNode: "T", capacityProperty: "cap" }) YIELD maxFlow, sourceId, targetId, flow, capacity
Result:
| maxFlow | sourceId | targetId | flow | capacity |
|---|---|---|---|---|
| 13 | S | T | 13 | 0 |
| 13 | S | A | 7 | 8 |
| 13 | S | B | 6 | 6 |
| 13 | A | C | 4 | 4 |
| 13 | A | D | 3 | 5 |
| 13 | B | C | 3 | 3 |
| 13 | B | D | 3 | 5 |
| 13 | C | T | 7 | 7 |
| 13 | D | T | 6 | 6 |
Returns the same columns as run mode, streamed for memory efficiency.
GQLCALL algo.maxflow.stream({ sourceNode: "S", sinkNode: "T", capacityProperty: "cap" }) YIELD sourceId, targetId, flow FILTER sourceId = "S" AND targetId = "T" RETURN sourceId, targetId, flow
Result:
| sourceId | targetId | flow |
|---|---|---|
| S | T | 13 |
Returns:
| Column | Type | Description |
|---|---|---|
maxFlow | FLOAT | Total maximum flow value |
edgeCount | INT | Number of edges carrying flow |
GQLCALL algo.maxflow.stats({ sourceNode: "S", sinkNode: "T", capacityProperty: "cap" }) YIELD maxFlow, edgeCount
Result:
| maxFlow | edgeCount |
|---|---|
| 13 | 8 |