use anyhow::{Result, anyhow};
#[derive(Debug, Clone)]
pub struct BcConfig {
pub learning_rate: f64,
pub batch_size: usize,
pub epochs: usize,
pub seed: u64,
}
impl Default for BcConfig {
fn default() -> Self {
Self { learning_rate: 1e-3, batch_size: 64, epochs: 10, seed: 0 }
}
}
impl BcConfig {
pub fn new() -> Self {
Self::default()
}
pub fn validate(&self) -> Result<()> {
if self.learning_rate <= 0.0 {
return Err(anyhow!("learning_rate must be positive, got {}", self.learning_rate));
}
if self.batch_size == 0 {
return Err(anyhow!("batch_size must be positive"));
}
if self.epochs == 0 {
return Err(anyhow!("epochs must be positive"));
}
Ok(())
}
pub fn learning_rate(mut self, lr: f64) -> Self {
self.learning_rate = lr;
self
}
pub fn batch_size(mut self, batch_size: usize) -> Self {
self.batch_size = batch_size;
self
}
pub fn epochs(mut self, epochs: usize) -> Self {
self.epochs = epochs;
self
}
pub fn seed(mut self, seed: u64) -> Self {
self.seed = seed;
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_config() {
let config = BcConfig::default();
assert!(config.validate().is_ok());
assert_eq!(config.learning_rate, 1e-3);
assert_eq!(config.batch_size, 64);
assert_eq!(config.epochs, 10);
assert_eq!(config.seed, 0);
}
#[test]
fn test_config_validation() {
let config = BcConfig::new();
assert!(config.validate().is_ok());
assert!(BcConfig::new().learning_rate(0.0).validate().is_err());
assert!(BcConfig::new().learning_rate(-1.0).validate().is_err());
assert!(BcConfig::new().batch_size(0).validate().is_err());
assert!(BcConfig::new().epochs(0).validate().is_err());
}
#[test]
fn test_config_builder() {
let config = BcConfig::new().learning_rate(5e-4).batch_size(128).epochs(25).seed(42);
assert!(config.validate().is_ok());
assert_eq!(config.learning_rate, 5e-4);
assert_eq!(config.batch_size, 128);
assert_eq!(config.epochs, 25);
assert_eq!(config.seed, 42);
}
}