Definition · A directed network with capacities and costsA directed network is a set of nodes together with a list of arcs. Each arc has a tail, a head, a capacity u (possibly no upper bound) and a cost c per unit. Each node i carries a supply bᵢ, positive where goods enter the network and negative where they leave.
A flow is one number xⱼ ≥ 0 for each arc. It is feasible when it conserves at every node and respects every capacity.
The lab takes a network as text, one clause per arc: s>a 5:2 is an arc from s to a with capacity 5 and cost 2. A * in the capacity field means no upper bound; 7/2 is seven halves, exactly, because the field separator is a colon and a slash is therefore free to mean division. A clause running from a node back to itself is refused rather than drawn, and so is a negative capacity.
the network the supplies a proposed flow
s>a 5:2 s : 4 s>a 4
a>b 4:2 t : -4 a>b 2
b>a 3:5 b>a 0
a>t 3:1 a>t 2
b>t 4:3 b>t 2
conservation, node by node: out − in supplied
s 4 − 0 = 4 4 ✓
a 2 + 2 − 4 = 0 0 ✓
b 0 + 2 − 2 = 0 0 ✓
t 0 − 4 = −4 −4 ✓
capacity: 4 ≤ 5, 2 ≤ 4, 0 ≤ 3, 2 ≤ 3, 2 ≤ 4 ✓
cost: 4(2) + 2(2) + 0(5) + 2(1) + 2(3) = 20
Two arcs in that list join the same pair of nodes. a>b carries up to 4 at a price of 2; b>a carries up to 3 at a price of 5. They are two variables. Sending one unit forward and two back costs 12; sending two forward and one back costs 9 — same total movement, different bill, because the directions are priced separately. The lab draws the pair in its own colour so that the two arrows cannot be read as one edge.
Conservation fails locally, and the total will not tell you
Example · A flow that balances overall and is not a flowChange one number in the flow above — a>b from 2 to 1 — and the net outflows become 4, −1, 1, −4 against supplies 4, 0, 0, −4. Node a now takes in one more unit than it sends on, and node b sends on one more than it takes in.
Those two errors are equal and opposite, so the imbalances still sum to zero, and any check that adds them up passes. The lab names a and b instead, and shades the two of them, because a verdict of “this flow is invalid” is not something a reader can act on.
Example · A flow that conserves everywhere and is still impossibleSet the supplies to s: 5, t: −5 and the flow to s>a 5, a>b 5, b>a 0, a>t 0, b>t 5. Every node balances exactly.
Two arcs are over capacity: a>b is asked for 5 where it holds 4, and b>t for 5 where it holds 4. Conservation cannot see this, because the node equations contain no capacities at all. The two tests are separate and the lab runs them separately.
Two things the data can get wrong before any flow does
Add the node equations together. Every arc leaves exactly one node and enters exactly one, so its variable appears once with a plus and once with a minus and cancels. What is left is Σᵢ bᵢ = 0. So if the supplies do not sum to zero, the equations contradict each other and no flow of any kind exists — a test that costs one addition and needs no algorithm.
Example · Six in, four outLeave the network alone and set the supplies to s: 6, t: −4. The lab reports a total of 2 and stops: adding the four node equations gives 2 = 0.
This is worth meeting before the programme is written rather than after a solver reports infeasibility, because the diagnosis is completely different. Nothing is wrong with the network; the demand does not match the supply, and the fix is to say what happens to the surplus.
The second is quieter. A flow may only name arcs that exist: write s>c 1 on a network with no such arc and the lab refuses it rather than creating one. This sounds pedantic until you have spent twenty minutes on a transportation problem in which a route you assumed was available was never in the data.
Everything from here on is this object with an objective attached. The arcs become the columns of a matrix, the nodes become its rows, the supplies become the right-hand side, and the whole of the rest of the course is what that matrix turns out to be like.