//! Utility functions and helpers use crate::error::{Result, TemporalNeuralError}; use nalgebra::DMatrix; use std::time::{Duration, Instant}; /// Timer for performance measurement pub struct Timer { start: Instant, name: String, } impl Timer { pub fn new(name: &str) -> Self { Self { start: Instant::now(), name: name.to_string(), } } pub fn elapsed(&self) -> Duration { self.start.elapsed() } pub fn elapsed_ms(&self) -> f64 { self.elapsed().as_secs_f64() * 1000.0 } pub fn elapsed_micros(&self) -> f64 { self.elapsed().as_secs_f64() * 1_000_000.0 } } impl Drop for Timer { fn drop(&mut self) { println!("{}: {:.3}ms", self.name, self.elapsed_ms()); } } /// Mathematical utilities pub mod math { use super::*; /// Compute softmax activation pub fn softmax(input: &[f64]) -> Vec { let max_val = input.iter().fold(f64::NEG_INFINITY, |a, &b| a.max(b)); let exp_vals: Vec = input.iter().map(|&x| (x - max_val).exp()).collect(); let sum: f64 = exp_vals.iter().sum(); exp_vals.iter().map(|&x| x / sum).collect() } /// Compute ReLU activation pub fn relu(x: f64) -> f64 { x.max(0.0) } /// Compute tanh activation pub fn tanh_activation(x: f64) -> f64 { x.tanh() } /// Compute sigmoid activation pub fn sigmoid(x: f64) -> f64 { 1.0 / (1.0 + (-x).exp()) } /// Compute mean squared error pub fn mse(predicted: &[f64], actual: &[f64]) -> Result { if predicted.len() != actual.len() { return Err(TemporalNeuralError::DimensionMismatch { message: "Predicted and actual arrays have different lengths".to_string(), expected: Some(actual.len().to_string()), actual: Some(predicted.len().to_string()), context: Some("mse computation".to_string()), }); } let sum_sq_error: f64 = predicted .iter() .zip(actual.iter()) .map(|(&p, &a)| (p - a).powi(2)) .sum(); Ok(sum_sq_error / predicted.len() as f64) } /// Compute mean absolute error pub fn mae(predicted: &[f64], actual: &[f64]) -> Result { if predicted.len() != actual.len() { return Err(TemporalNeuralError::DimensionMismatch { message: "Predicted and actual arrays have different lengths".to_string(), expected: Some(actual.len().to_string()), actual: Some(predicted.len().to_string()), context: Some("mae computation".to_string()), }); } let sum_abs_error: f64 = predicted .iter() .zip(actual.iter()) .map(|(&p, &a)| (p - a).abs()) .sum(); Ok(sum_abs_error / predicted.len() as f64) } } /// Memory utilities pub mod memory { use super::*; /// Get current memory usage in bytes pub fn get_memory_usage() -> Result { // Placeholder for memory monitoring // In real implementation, would use system calls Ok(0) } /// Calculate matrix memory footprint pub fn matrix_memory_size(matrix: &DMatrix) -> usize { matrix.nrows() * matrix.ncols() * std::mem::size_of::() } } /// Validation utilities pub mod validation { use super::*; /// Validate matrix dimensions for operations pub fn validate_matrix_dims( a: &DMatrix, b: &DMatrix, operation: &str, ) -> Result<()> { match operation { "multiply" => { if a.ncols() != b.nrows() { return Err(TemporalNeuralError::DimensionMismatch { message: "Matrix dimensions incompatible for multiplication".to_string(), expected: Some(a.ncols().to_string()), actual: Some(b.nrows().to_string()), context: Some("matrix multiplication".to_string()), }); } } "add" | "subtract" => { if a.shape() != b.shape() { return Err(TemporalNeuralError::DimensionMismatch { message: "Matrix shapes must match for addition/subtraction".to_string(), expected: Some(format!("{}x{}", a.nrows(), a.ncols())), actual: Some(format!("{}x{}", b.nrows(), b.ncols())), context: Some(operation.to_string()), }); } } _ => { return Err(TemporalNeuralError::ConfigurationError { message: format!("Unknown operation: {}", operation), field: Some("operation".to_string()), }); } } Ok(()) } /// Validate prediction bounds pub fn validate_prediction_bounds(prediction: &[f64], bounds: (f64, f64)) -> Result<()> { for &value in prediction { if value < bounds.0 || value > bounds.1 { return Err(TemporalNeuralError::ValidationError { message: format!( "Prediction value {} outside bounds [{}, {}]", value, bounds.0, bounds.1 ), expected: Some(format!("[{}, {}]", bounds.0, bounds.1)), actual: Some(value.to_string()), rule: Some("bounds_check".to_string()), }); } } Ok(()) } }