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()
╭─────────────────────────────────────╮ │ 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
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
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()
/Users/jpn/Git/pax/.venv/lib/python3.12/site-packages/wakepy/core/mode.py:835: ThreadSafetyWarning: Using the Mode keep.running with id (4744899248) in thread 6286241792 but it was created in thread 8378408576. Wakepy Modes are not thread-safe!
self._thread_check()
Using the Mode keep.running with id (4744899248) in thread 6286241792 but it was created in thread 8378408576. Wakepy Modes are not thread-safe!
Exception ignored in: <generator object keep_awake at 0x11ac9b920>
Traceback (most recent call last):
File "/Users/jpn/Git/pax/packages/passengersim-public/src/passengersim/utils/caffeine.py", line 19, in keep_awake
with wakepy.keep.running():
^^^^^^^^^^^^^^^^^^^^^
File "/Users/jpn/Git/pax/.venv/lib/python3.12/site-packages/wakepy/core/mode.py", line 548, in __exit__
self._unset_current_mode()
File "/Users/jpn/Git/pax/.venv/lib/python3.12/site-packages/wakepy/core/mode.py", line 683, in _unset_current_mode
_current_mode.reset(self._context_token)
ValueError: <Token var=<ContextVar name='wakepy._current_mode' at 0x11a445ad0> at 0x11abde140> was created in a different Context
@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
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?