pub struct RsrDispatch {
pub eta_weight: f64,
pub wrong_direction_penalty: f64,
pub coincident_car_call_bonus: f64,
pub load_penalty_coeff: f64,
pub peak_direction_multiplier: f64,
}Expand description
Additive RSR-style cost stack. Lower scores win the Hungarian assignment.
See module docs for the cost shape. All weights default to 0.0
except eta_weight (1.0), giving a baseline that mirrors
NearestCarDispatch until terms are
opted in.
§Weight invariants
Every weight field must be finite and non-negative. The
with_* builder methods enforce this with assert!; direct field
mutation bypasses the check and is a caller responsibility. A NaN weight propagates through the multiply-add
chain and silently collapses every pair’s cost to zero (Rust’s
NaN.max(0.0) == 0.0), producing an arbitrary but type-valid
assignment from the Hungarian solver — a hard bug to diagnose.
Fields§
§eta_weight: f64Weight on travel_time = distance / max_speed (seconds).
Default 1.0; raising it shifts the blend toward travel time.
wrong_direction_penalty: f64Constant added when the candidate stop lies opposite the car’s committed travel direction.
Default 0.0; the Otis RSR lineage uses a large value so any
right-direction candidate outranks any wrong-direction one.
Ignored for cars in ElevatorPhase::Idle or stopped phases,
since an idle car has no committed direction to be opposite to.
coincident_car_call_bonus: f64Bonus subtracted when the candidate stop is already a car-call inside this car.
Merges the new pickup with an existing dropoff instead of
spawning an unrelated trip. Default 0.0. Read from
DispatchManifest::car_calls_for.
load_penalty_coeff: f64Coefficient on a smooth load-fraction penalty
(load_penalty_coeff · load_ratio).
Fires for partially loaded cars below the bypass_load_*_pct
threshold enforced by pair_can_do_work;
lets you prefer emptier cars for new pickups without an on/off cliff.
Default 0.0.
peak_direction_multiplier: f64Multiplier applied to wrong_direction_penalty when the
TrafficDetector classifies the current tick as
TrafficMode::UpPeak or TrafficMode::DownPeak.
Default 1.0 (mode-agnostic — behaviour identical to pre-peak
tuning). Raising it strengthens directional commitment during
peaks where a car carrying a lobby-bound load shouldn’t be
pulled backwards to grab a new pickup. Off-peak periods keep
the unscaled penalty, leaving inter-floor assignments free
to reverse cheaply.
Silently reduces to 1.0 when no TrafficDetector resource
is installed — tests and custom sims that bypass the auto-install
stay unaffected.
Implementations§
Source§impl RsrDispatch
impl RsrDispatch
Sourcepub const fn new() -> Self
pub const fn new() -> Self
Create a new RsrDispatch with the baseline weights
(eta_weight = 1.0, all penalties/bonuses disabled).
This is the additive-composition baseline — every penalty
and bonus is zero, so the rank reduces to
NearestCarDispatch on distance
alone. Useful for tests that want to measure a single term in
isolation (RsrDispatch::new().with_wrong_direction_penalty(…)).
For the opinionated “out-of-the-box RSR” configuration used by
BuiltinStrategy::Rsr and the
playground, use RsrDispatch::default instead. Default ships
with the full penalty stack turned on; new() is the empty
canvas you build on top of.
Sourcepub const fn tuned() -> Self
pub const fn tuned() -> Self
Return the opinionated tuned configuration — equivalent to
Default::default but usable in const contexts.
See RsrDispatch::default for the rationale behind each
weight. The tuned stack ships with every penalty/bonus turned
on so picking RSR out of the box is strictly richer than
NearestCar, not identical to it.
Sourcepub fn with_wrong_direction_penalty(self, weight: f64) -> Self
pub fn with_wrong_direction_penalty(self, weight: f64) -> Self
Set the wrong-direction penalty.
§Panics
Panics on non-finite or negative weights — a negative penalty would invert the direction ordering, silently preferring wrong-direction candidates.
Sourcepub fn with_coincident_car_call_bonus(self, weight: f64) -> Self
pub fn with_coincident_car_call_bonus(self, weight: f64) -> Self
Set the coincident-car-call bonus.
§Panics
Panics on non-finite or negative weights — the bonus is subtracted, so a negative value would become a penalty.
Sourcepub fn with_load_penalty_coeff(self, weight: f64) -> Self
pub fn with_load_penalty_coeff(self, weight: f64) -> Self
Sourcepub fn with_eta_weight(self, weight: f64) -> Self
pub fn with_eta_weight(self, weight: f64) -> Self
Set the ETA weight.
§Panics
Panics on non-finite or negative weights. Zero is allowed and reduces the strategy to penalty/bonus tiebreaking alone.
Sourcepub fn with_peak_direction_multiplier(self, factor: f64) -> Self
pub fn with_peak_direction_multiplier(self, factor: f64) -> Self
Set the peak-direction multiplier.
§Panics
Panics on non-finite or sub-1.0 values. A multiplier below 1.0
would weaken the direction penalty during peaks (the opposite
of the intent) — explicitly disallowed so a typo doesn’t silently
invert the tuning.
Trait Implementations§
Source§impl Default for RsrDispatch
impl Default for RsrDispatch
Source§fn default() -> Self
fn default() -> Self
The opinionated “pick RSR from the dropdown” configuration.
Defaults to RsrDispatch::tuned — every penalty and bonus
turned on with values calibrated to a 20-stop commercial bank.
Before this default was tuned, RsrDispatch::default()
reduced to the raw NearestCarDispatch
baseline: picking “RSR” in the playground produced worse
behaviour than picking “Nearest Car” (no direction discipline,
no load balancing, no car-call merging). The tuned default
fixes that without making any term mandatory — consumers
wanting the zero baseline can still call
RsrDispatch::new.
Source§impl<'de> Deserialize<'de> for RsrDispatch
impl<'de> Deserialize<'de> for RsrDispatch
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Source§impl DispatchStrategy for RsrDispatch
impl DispatchStrategy for RsrDispatch
Source§fn builtin_id(&self) -> Option<BuiltinStrategy>
fn builtin_id(&self) -> Option<BuiltinStrategy>
Simulation::new can stamp the
correct BuiltinStrategy into the group’s snapshot identity. Read moreSource§fn snapshot_config(&self) -> Option<String>
fn snapshot_config(&self) -> Option<String>
restore_config can apply to a
freshly-instantiated instance. Read moreSource§fn restore_config(&mut self, serialized: &str) -> Result<(), String>
fn restore_config(&mut self, serialized: &str) -> Result<(), String>
snapshot_config on the same
strategy variant. Called by
crate::snapshot::WorldSnapshot::restore immediately after
BuiltinStrategy::instantiate builds the default instance,
so the restore writes over the defaults. Read more