///|
/// Construct a stable benchmark scenario.
pub fn stable_scenario() -> ScenarioConfig {
{
..default_scenario_config(),
steps: 18,
congestion: 0.1,
noise_magnitude: 0.0,
}
}
///|
/// Construct a high-variance benchmark scenario.
pub fn noisy_scenario() -> ScenarioConfig {
{
..default_scenario_config(),
steps: 18,
congestion: 0.45,
noise_stride: 3,
noise_magnitude: 95.0,
}
}
///|
/// Construct a slow-route benchmark scenario.
pub fn delayed_scenario() -> ScenarioConfig {
{
..default_scenario_config(),
steps: 14,
interval_seconds: 90.0,
base_speed: 6.5,
congestion: 0.55,
noise_magnitude: 28.0,
}
}
///|
/// Construct a severe congestion benchmark scenario.
pub fn congested_scenario() -> ScenarioConfig {
{
..default_scenario_config(),
steps: 20,
base_speed: 5.5,
congestion: 0.9,
noise_magnitude: 66.0,
}
}
///|
/// Return named scenarios for external benchmark runners.
pub fn standard_scenarios() -> Array[(String, ScenarioConfig)] {
[
("stable", stable_scenario()),
("noisy", noisy_scenario()),
("delayed", delayed_scenario()),
("congested", congested_scenario()),
]
}
///|
/// Return a scenario with a single observation, useful for smoke tests.
pub fn singleton_scenario() -> ScenarioConfig {
{
..default_scenario_config(),
steps: 1,
interval_seconds: 1.0,
noise_magnitude: 0.0,
}
}
///|
/// Return a scenario that reaches the route end quickly.
pub fn completion_scenario() -> ScenarioConfig {
{
..default_scenario_config(),
steps: 3,
interval_seconds: 600.0,
base_speed: 40.0,
congestion: 0.0,
noise_magnitude: 0.0,
}
}
///|
/// Generate a trace for a named standard scenario.
pub fn named_scenario(name : String) -> ScenarioTrace {
let config = if name == "stable" {
stable_scenario()
} else if name == "noisy" {
noisy_scenario()
} else if name == "delayed" {
delayed_scenario()
} else if name == "congested" {
congested_scenario()
} else {
default_scenario_config()
}
generate_scenario(demo_route(), config)
}
///|
/// Check that a scenario remains within route and time bounds.
pub fn scenario_is_well_formed(
trace : ScenarioTrace,
route : RouteProfile,
) -> Bool {
if trace.observations.length() != trace.actual_remaining.length() {
false
} else {
let mut valid = true
let distance = route.total_distance()
let mut previous_time = -1.0
for observation in trace.observations {
if observation.timestamp < previous_time ||
observation.distance < 0.0 ||
observation.distance > distance {
valid = false
}
previous_time = observation.timestamp
}
valid
}
}
///|
/// Compare benchmark output cardinality for two scenarios.
pub fn scenario_size_delta(left : ScenarioTrace, right : ScenarioTrace) -> Int {
left.observations.length() - right.observations.length()
}