Network bid prices
At a hub, one seat on a long-haul flight can go to a local passenger or to a passenger connecting from a smaller city, who also needs a seat on the feeder flight. Leg-based revenue management decides flight by flight and fare class by fare class, so it can't tell the two apart. Origin-destination (O&D) control gives every flight a bid price, the value of its last seat across the whole network, and accepts a booking only if the fare covers the bid prices of every flight it uses. Below, a linear program works out those bid prices for a small hub at Montréal, then one stream of booking requests is run through three kinds of control. This is the hands-on companion to RM 101, chapter 06.
The network, fares, demand and capacities are illustrative assumptions, not any airline's data.
Loading the network and the LP solver…
1. The network and its bid prices
The airline sells eight itineraries on four flights, each in three fare classes. The linear program decides how many passengers of each kind it would take if demand turned up exactly as forecast, and its shadow prices on the four seat limits are the bid prices. Edit any white cell and everything below updates.
The hub
Bid price and seats per flight at the opening of salesFlights
Capacity is editableDemand is the forecast of every local and connecting passenger who needs a seat on the flight. The bid price is the dual value of the flight's seat constraint. As a check, the last column re-solves the LP with one more seat on the flight: the revenue it adds should match the bid price.
LP inputs: fares and demand forecast
Fare in CA$, one way · demand in passengers per departureLP solution
For each itinerary and class: passengers the LP accepts out of the forecast, and the net contribution, the fare minus the bid prices of the flights used. Positive means the booking is worth more than the seats it takes away from someone else, so it is open. Negative means closed. Zero is the marginal product, the one that sets the bid price.
The model, with these numbers
2. One booking stream, three controls
Requests arrive one at a time, mostly discount fares early and flexible fares late, with some randomness. The same stream goes through no control (sell while seats remain), leg-based control (EMSR-b booking limits on each flight, a connecting booking needs its class open on both) and O&D bid-price control (accept if the fare covers the sum of bid prices). Both controls re-optimise on the seats left and the demand still to come.
Step through the stream
One request at a time, as the three controls see itBid prices as seats sell
O&D control, CA$ per seatLoad factor by flight
End of the booking windowWho got the seats
Local and connecting passengers per flight typeResults for this stream
3. Is it luck? 100 booking streams
One stream can flatter either control. The same comparison on 100 streams drawn from the same forecast shows how often, and by how much, O&D control beats leg-based control.
O&D gain over leg-based, stream by stream
% of revenueHow it works
The network
An invented airline with a hub at Montréal (YUL): two feeder flights in from Québec City (YQB) and Ottawa (YOW), two long-haul flights out to Paris (CDG) and London (LHR), one direction and one departure day, economy cabin only. That gives eight itineraries: four local (one flight) and four connecting (a feeder plus a long-haul flight), each sold in three fare classes, Y (flexible), M (standard) and Q (discount). Fares, forecasts and capacities come from bidprice.json and are illustrative assumptions.
The linear program and the bid prices
Let j be a product (an itinerary in a class) with fare fj and expected demand dj, and cl the seats on flight l. The deterministic LP (Williamson, 1992) is: maximise Σj fj xj subject to Σj uses l xj ≤ cl for every flight and 0 ≤ xj ≤ dj. The bid price πl of flight l is the dual value of its seat constraint: how much the optimal revenue would rise with one more seat on it. A request for product j is accepted if fj ≥ Σl in j πl and a seat is left on every flight it uses. The sum of the bid prices is the displacement cost of the booking, the revenue it is expected to push out of the network. The LP is solved in your browser by GLPK, compiled to WebAssembly by glpk.js 5.0.0, which returns the duals of the simplex solution directly.
The booking stream
Each product's demand for one departure is a Poisson draw whose mean is itself random (a gamma factor with a 25% coefficient of variation), so the variance is d + (0.25 d)2. Each request then gets a booking time between 0 (sales open) and 1 (departure) from a beta distribution that depends on the class: Beta(2, 5) for Q, Beta(3, 3) for M and Beta(5, 2) for Y, so discount requests come mostly early and flexible ones mostly late, with overlap. Requests are processed in time order. The generator is seeded, so the page opens on the same stream every time; "New booking stream" changes the seed.
The three controls
- No control: accept while there is a seat on every flight the itinerary uses.
- Leg-based EMSR-b: each flight runs its own three-class EMSR-b, as on the booking limits page. A flight's class demand is the demand of every local and connecting product in that class using the flight. A connecting fare is split between its two flights in proportion to the local fares of the same class (so YQB–CDG in M credits 210 / (210 + 820) of its fare to YQB–YUL), and the class fare on a flight is the demand-weighted average of the fares it is credited. Protection levels are nested: class k is open while the seats left exceed the seats protected for the classes above it. A connecting booking needs its class open on both flights.
- O&D bid price: the LP above, re-solved with the seats left and the expected demand still to come.
Both controls re-optimise at the same points: at the first request and then every N requests. The expected demand still to come for product j at time t is dj · (1 − Fk(t)), where Fk is the beta distribution of its class. Perfect hindsight is the same LP solved once on the demand that actually turned up, the most any control could have earned from that stream. Its solution is always in whole passengers because every itinerary uses at most one feeder and one long-haul flight, which makes the constraint matrix totally unimodular.
Sources
- Williamson, E. L. (1992), Airline network seat inventory control: methodologies and revenue impacts, PhD thesis, MIT. The deterministic LP and its bid prices; in her simulations network control gained nothing over good leg-based control below an average load factor of about 85%, and on the order of 2–4% above it (checked September 2026).
- Talluri, K. and van Ryzin, G. (1998), "An analysis of bid-price controls for network revenue management", Management Science 44(11).
- Talluri, K. and van Ryzin, G. (2004), The Theory and Practice of Revenue Management, Springer, chapter 3 (network capacity control).
- Belobaba, P. (1992), "Optimal vs. heuristic methods for nested seat allocation", AGIFORS Reservations and Yield Management Study Group (EMSR-b).
- Solver: glpk.js 5.0.0 (GPL-3.0), loaded from jsDelivr; charts with D3 7.9.0.
Limitations
- The LP uses expected demand only, so its bid prices ignore uncertainty. They tend to come out as round steps equal to some product's fare, and they drop to zero on any flight the forecast doesn't fill. Real systems use stochastic or dynamic-programming bid prices, and turn bid prices into availability with virtual nesting or DAVN (RM 101, chapter 06).
- When a flight is exactly full in the LP solution the dual can be any value in a range; the solver returns one of them. The "+1 seat" check in the flight table shows the revenue from an extra seat, which can differ from the dual in that case.
- Demand in each product is independent of what is open: passengers never buy down to a cheaper class or switch itinerary (RM 101, chapter 05). No cancellations, no-shows, overbooking or groups.
- Leg-based control here is a fair but simple version: real airlines add rules such as closing connecting fares on busy long-haul flights by hand, which this page doesn't model. Proration by local fares is one of several conventions; mileage-based proration credits even less to the feeder.
- One direction, one day, one cabin. A real hub has hundreds of flights, return trips and several banks of connections, and the gain from O&D control is usually a few percent of revenue rather than the larger gaps in the extreme scenarios.
This is a personal project and isn't affiliated with any airline.