Source code for passengersim.rm.probp
from __future__ import annotations
from typing import TYPE_CHECKING
from passengersim_core import ProBP
from passengersim.snapshot.filtering import NetworkSnapshotFilter
from ._common import RmAction
if TYPE_CHECKING:
from passengersim.config import Config
from passengersim.driver import Simulation
[docs]
class ProbabilisticBidPrice(RmAction):
"""
ProBP (ProbabilisticBidPrice) is a path-based optimization algorithm.
"""
requires: set[str] = {"path_forecast"}
frequency = "daily_pre_dep"
snapshot_filter_type = NetworkSnapshotFilter
def __init__(
self,
*,
carrier: str = "",
cabins: str | list[str] | None = None,
minimum_sample: int = 10,
cfg: Config | None = None,
capacity_sharing: bool | None = False,
capacity_sharing_start_dcp_index: int | None = 0,
capacity_sharing_start_lf: float | None = 0.0,
use_adjusted_fares: bool = False,
bid_price_vector: bool | None = False,
maxiter: int = 10,
use_sub_bp: bool = False,
snapshot_filters: NetworkSnapshotFilter | list[NetworkSnapshotFilter] | None = None,
):
super().__init__(
carrier=carrier,
minimum_sample=minimum_sample,
cfg=cfg,
snapshot_filters=snapshot_filters,
)
self._pro_bp_engine = None
self.cabins = cabins
"""Optional list of cabin codes to optimize.
If not provided, this tool will optimize on the leg as a whole."""
self.capacity_sharing = capacity_sharing
""" Capacity sharing flag between cabins.
When set to True, will use method 3 from Peter Belobaba's presentation.
Higher cabin(s) will get max of combined cabins or itself alone.
Lower cabin(s) will get min of combined cabins or itself alone."""
self.capacity_sharing_start_dcp_index = capacity_sharing_start_dcp_index
self.capacity_sharing_start_lf = capacity_sharing_start_lf
"""We can optionally turn on capacity sharing when the coach cabin
reaches a specified load factor. Based on a suggestion by Darius (PROS)"""
self.use_adjusted_fares = use_adjusted_fares
"""
If True, ProBP will use the adjusted fares for the optimization.
The default is False, which means that ProBP will use the original fares. This
should be set to True if fare adjustment is being used for this carrier.
"""
self.bid_price_vector = bid_price_vector
"""
If True, we create a bid price vector in ProBP,
rather than just keep a constant bid-price untiol daily re-optimization
"""
self.maxiter = maxiter
"""
The maximum number of iterations to run ProBP.
If the algorithm has not converged by the time this number of iterations has
been reached, it will stop and return the current results.
"""
self.use_sub_bp: bool = use_sub_bp
"""Whether to use SubBP (True) or ProBP (False)."""
[docs]
def rm_engine(self, sim: Simulation) -> ProBP:
# We a reference to a ProBP object, as the CoreProBP code caches
# the data structures it needs for each iteration
if self._pro_bp_engine is None:
engine = ProBP(sim.eng, self.carrier)
if self.use_sub_bp:
engine.use_sub_bp = True
self._pro_bp_engine = engine
return self._pro_bp_engine
[docs]
def run(self, sim: Simulation, days_prior: int):
if not self.should_run(sim, days_prior):
return
# Make sure each sample is initialized
if sim.eng.last_dcp_index <= 1:
for leg in sim.eng.legs.set_filters(carrier=self.carrier):
leg.capacity_sharing = False
if self.capacity_sharing:
if self.capacity_sharing_start_dcp_index >= sim.eng.last_dcp_index:
for leg in sim.eng.legs.set_filters(carrier=self.carrier):
leg.capacity_sharing = True
elif self.capacity_sharing_start_lf > 0.01:
for leg in sim.eng.legs.set_filters(carrier=self.carrier):
for cab in leg.cabins:
if cab.name == "Y" and cab.sold / cab.capacity >= self.capacity_sharing_start_lf:
leg.capacity_sharing = True
z = self.rm_engine(sim)
# Update the decision fares if needed
dcp_index = self.get_dcp_index(days_prior, allow_between=True)
if self.use_adjusted_fares:
z.update_decision_fares(dcp_index)
snapshot_instruction = self.apply_snapshot_filters(sim, days_prior)
# num_cabins = len(self.cabins) if self.cabins is not None else 0
debug_output = z.run(
"", maxiter=self.maxiter, bid_price_vector=self.bid_price_vector, snapshot_instruction=snapshot_instruction
)
if self.cabins:
for c in self.cabins:
debug_output = z.run(
c,
maxiter=self.maxiter,
bid_price_vector=self.bid_price_vector,
snapshot_instruction=snapshot_instruction,
)
if debug_output:
print(debug_output)