#[derive(Debug, Clone, Copy, PartialEq)]
pub struct DiscountParams {
pub alpha: f32,
pub beta: f32,
pub gamma: f32,
}
impl DiscountParams {
pub const LCFR: Self = Self {
alpha: 1.0,
beta: 1.0,
gamma: 1.0,
};
pub const RECOMMENDED: Self = Self {
alpha: 1.5,
beta: 0.0,
gamma: 2.0,
};
pub const PRUNING_SAFE: Self = Self {
alpha: 1.5,
beta: 0.5,
gamma: 2.0,
};
#[must_use]
pub const fn new(alpha: f32, beta: f32, gamma: f32) -> Self {
Self { alpha, beta, gamma }
}
#[must_use]
pub fn discount_factor(t: usize, exp: f32) -> f32 {
let t_f = t as f32;
let t_pow = t_f.powf(exp);
t_pow / (t_pow + 1.0)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_discount_factor_zero_exp() {
assert!((DiscountParams::discount_factor(1, 0.0) - 0.5).abs() < 1e-6);
assert!((DiscountParams::discount_factor(10, 0.0) - 0.5).abs() < 1e-6);
assert!((DiscountParams::discount_factor(100, 0.0) - 0.5).abs() < 1e-6);
}
#[test]
fn test_discount_factor_one_exp() {
assert!((DiscountParams::discount_factor(1, 1.0) - 0.5).abs() < 1e-6);
assert!((DiscountParams::discount_factor(2, 1.0) - 2.0 / 3.0).abs() < 1e-6);
assert!((DiscountParams::discount_factor(9, 1.0) - 0.9).abs() < 1e-6);
}
#[test]
fn test_discount_factor_increases_with_t() {
for exp in [0.5, 1.0, 1.5, 2.0] {
let d1 = DiscountParams::discount_factor(1, exp);
let d2 = DiscountParams::discount_factor(10, exp);
let d3 = DiscountParams::discount_factor(100, exp);
assert!(d1 < d2);
assert!(d2 < d3);
}
}
#[test]
fn test_presets() {
assert_eq!(DiscountParams::LCFR.alpha, 1.0);
assert_eq!(DiscountParams::LCFR.beta, 1.0);
assert_eq!(DiscountParams::LCFR.gamma, 1.0);
assert_eq!(DiscountParams::RECOMMENDED.alpha, 1.5);
assert_eq!(DiscountParams::RECOMMENDED.beta, 0.0);
assert_eq!(DiscountParams::RECOMMENDED.gamma, 2.0);
assert_eq!(DiscountParams::PRUNING_SAFE.alpha, 1.5);
assert_eq!(DiscountParams::PRUNING_SAFE.beta, 0.5);
assert_eq!(DiscountParams::PRUNING_SAFE.gamma, 2.0);
}
}