Lab 1¶
import passengersim as pax
cfg = pax.Config.from_yaml(pax.demo_network("3MKT/DEMO"))
Understanding the Impact of RM¶
We are going to run a series of experiments, so we’ll set up an Experiments
class to keep track of and compare the results.
from passengersim.experiments import Experiments
experiments = Experiments(cfg, output_dir="lab-1-output")
First Come, First Served¶
First, let’s suppose that neither carrier uses any RM optimization, and just offers all fare classes as first come, first served, subject only to the existing restrictions (fare rules and advance purchase). To simulate this, we’ll create an RM system that does nothing and set the config so that both carriers use this system.
from passengersim.rm import RmAction, RmSys, register_rm_system
class Nothing(RmAction):
"""An RM step that does nothing."""
frequency = "dcp"
def run(self, sim: pax.Simulation, days_prior: int):
return
@register_rm_system
class Z(RmSys):
"""A custom RM system that applies zero optimization."""
availability_control = "leg"
actions = [Nothing]
@experiments
def ZZ(cfg: pax.Config) -> pax.Config:
cfg.carriers.AL1.rm_system = "Z"
cfg.carriers.AL2.rm_system = "Z"
return cfg
summary = experiments.run()
Loaded ZZ from lab-1-output/ZZ/ZZ.20260612-140809.pxsim, but the PassengerSim version has changed: running 0.81, found 0.80
╭─────────────────────────────────────╮ │ licensed for jpn │ │ until 2036-05-28 15:49:32+00:00 UTC │ │ maximum 42000 legs in network │ ╰─────────────────────────────────────╯
summary.fig_carrier_revenues()
summary.fig_carrier_load_factors()
summary.fig_bookings_by_timeframe(by_carrier="AL1", by_class=True)
AL1 implements EMSR-B¶
Now let’s have one of the carriers implement EMSR-B, with EM demand untruncation and standard forecasting.
@experiments
def EZ(cfg: pax.Config) -> pax.Config:
cfg.carriers.AL1.rm_system = "E"
cfg.carriers.AL2.rm_system = "Z"
return cfg
summary = experiments.run()
Using cached results for experiment ZZ
Loaded EZ from lab-1-output/EZ/EZ.20260612-140813.pxsim, but the PassengerSim version has changed: running 0.81, found 0.80
summary.fig_carrier_revenues()
summary.fig_carrier_load_factors()
summary.fig_bookings_by_timeframe(by_carrier="AL1", by_class=True, source_labels=True)
summary.fig_bookings_by_timeframe(by_carrier="AL2", by_class=True, source_labels=True)
Both Carriers implement EMSR-B¶
@experiments
def EE(cfg: pax.Config) -> pax.Config:
cfg.carriers.AL1.rm_system = "E"
cfg.carriers.AL2.rm_system = "E"
return cfg
summary = experiments.run()
Using cached results for experiment ZZ
Using cached results for experiment EZ
Loaded EE from lab-1-output/EE/EE.20260612-140817.pxsim, but the PassengerSim version has changed: running 0.81, found 0.80
summary.fig_carrier_revenues()
summary.fig_bookings_by_timeframe(by_carrier="AL1", by_class=True, source_labels=True)
Understanding Relative Fares¶
For this section, we’ll start a new collection of experiments.
ex_fares = Experiments(cfg, output_dir="lab-1b-output")
We start with a baseline experiment where both carriers are using the “normal” fare structures and the “E” RM system.
@ex_fares
def Baseline(cfg: pax.Config) -> pax.Config:
return cfg
summary = ex_fares.run()
summary.fig_carrier_revenues()
Loaded Baseline from lab-1b-output/Baseline/Baseline.20260612-140821.pxsim, but the PassengerSim version has changed: running 0.81, found 0.80
@ex_fares
def TopFareUp_OrdLax(cfg: pax.Config) -> pax.Config:
for fare in cfg.fares:
if fare.booking_class == "Y0" and fare.orig == "ORD" and fare.dest == "LAX":
fare.price *= 1.1
return cfg
summary = ex_fares.run()
summary.fig_carrier_revenues()
Using cached results for experiment Baseline
Loaded TopFareUp_OrdLax from lab-1b-output/TopFareUp_OrdLax/TopFareUp_OrdLax.20260612-140825.pxsim, but the PassengerSim version has changed: running 0.81, found 0.80
summary.fig_fare_class_mix()
summary.fig_bookings_by_timeframe(by_carrier="AL1", by_class=True)
Questions¶
What happens if you mark up the price of the top fare in the BOS-ORD market instead? Why is this different?
What about BOS-LAX?
What if only AL1 makes this pricing change?