use crate::gmns::types::AgentType;
#[derive(Debug, Clone)]
pub struct ModeUtility {
pub agent_type: AgentType,
pub asc: f64,
pub coeff_time: f64,
pub coeff_distance: f64,
pub coeff_cost: f64,
}
impl ModeUtility {
pub fn new(agent_type: AgentType) -> ModeUtilityBuilder {
ModeUtilityBuilder {
instance: ModeUtility {
agent_type,
asc: 0.0,
coeff_time: -0.03,
coeff_distance: 0.0,
coeff_cost: 0.0,
},
}
}
pub fn compute(&self, time: f64, distance: f64, cost: f64) -> f64 {
self.asc + self.coeff_time * time + self.coeff_distance * distance + self.coeff_cost * cost
}
}
pub struct ModeUtilityBuilder {
instance: ModeUtility,
}
impl ModeUtilityBuilder {
pub fn with_asc(mut self, asc: f64) -> Self {
self.instance.asc = asc;
self
}
pub fn with_coeff_time(mut self, coeff: f64) -> Self {
self.instance.coeff_time = coeff;
self
}
pub fn with_coeff_distance(mut self, coeff: f64) -> Self {
self.instance.coeff_distance = coeff;
self
}
pub fn with_coeff_cost(mut self, coeff: f64) -> Self {
self.instance.coeff_cost = coeff;
self
}
pub fn build(self) -> ModeUtility {
self.instance
}
}
#[cfg(test)]
mod tests {
use super::*;
const EPS: f64 = 1e-10;
#[test]
fn compute_zero_attributes_returns_asc() {
let u = ModeUtility::new(AgentType::Walk)
.with_asc(-2.0)
.build();
assert_eq!(u.compute(0.0, 0.0, 0.0), -2.0);
}
#[test]
fn compute_time_only() {
let u = ModeUtility::new(AgentType::Auto)
.with_asc(0.0)
.with_coeff_time(-0.03)
.build();
assert!((u.compute(10.0, 0.0, 0.0) - (-0.3)).abs() < EPS);
}
#[test]
fn compute_all_coefficients() {
let u = ModeUtility::new(AgentType::Auto)
.with_asc(0.5)
.with_coeff_time(-0.04)
.with_coeff_distance(-0.01)
.with_coeff_cost(-0.02)
.build();
let v = u.compute(10.0, 5.0, 3.0);
assert!((v - (-0.01)).abs() < EPS);
}
#[test]
fn builder_defaults() {
let u = ModeUtility::new(AgentType::Bike).build();
assert_eq!(u.agent_type, AgentType::Bike);
assert_eq!(u.asc, 0.0);
assert_eq!(u.coeff_time, -0.03);
assert_eq!(u.coeff_distance, 0.0);
assert_eq!(u.coeff_cost, 0.0);
}
}