//! 工具函数 //! //! 本模块提供XTZH AI系统中常用的工具函数。 use crate::constants::*; use crate::error::{Error, Result}; use blake3::Hasher; use chrono::Timelike; // ============================================================================ // 哈希工具(遵循ARCH_003:Blake3哈希统一) // ============================================================================ /// 计算Blake3哈希 /// /// # 参数 /// /// * `data` - 待哈希的数据 /// /// # 返回 /// /// 32字节Blake3哈希值 /// /// # 示例 /// /// ``` /// use xtzh_ai::utils::blake3_hash; /// /// let data = b"Hello, NAC!"; /// let hash = blake3_hash(data); /// assert_eq!(hash.len(), 32); /// ``` pub fn blake3_hash(data: &[u8]) -> [u8; 32] { let mut hasher = Hasher::new(); hasher.update(data); hasher.finalize().into() } /// 计算Blake3哈希并返回十六进制字符串 /// /// # 参数 /// /// * `data` - 待哈希的数据 /// /// # 返回 /// /// 64字符十六进制字符串 pub fn blake3_hash_hex(data: &[u8]) -> String { let hash = blake3_hash(data); hex::encode(hash) } // ============================================================================ // 数值转换工具 // ============================================================================ /// 将浮点数汇率转换为定点数(1e6精度) /// /// # 参数 /// /// * `rate` - 浮点数汇率(例如:1.034) /// /// # 返回 /// /// 定点数汇率(例如:1034000) /// /// # 示例 /// /// ``` /// use xtzh_ai::utils::rate_to_fixed; /// /// let rate = 1.034; /// let fixed = rate_to_fixed(rate); /// assert_eq!(fixed, 1034000); /// ``` pub fn rate_to_fixed(rate: f64) -> u64 { (rate * RATE_PRECISION as f64).round() as u64 } /// 将定点数汇率转换为浮点数 /// /// # 参数 /// /// * `fixed` - 定点数汇率(例如:1034000) /// /// # 返回 /// /// 浮点数汇率(例如:1.034) pub fn fixed_to_rate(fixed: u64) -> f64 { fixed as f64 / RATE_PRECISION as f64 } /// 将百分比权重转换为基点 /// /// # 参数 /// /// * `percentage` - 百分比权重(例如:38.5) /// /// # 返回 /// /// 基点权重(例如:3850) /// /// # 示例 /// /// ``` /// use xtzh_ai::utils::percentage_to_bps; /// /// let percentage = 38.5; /// let bps = percentage_to_bps(percentage); /// assert_eq!(bps, 3850); /// ``` pub fn percentage_to_bps(percentage: f64) -> u32 { (percentage * 100.0).round() as u32 } /// 将基点权重转换为百分比 /// /// # 参数 /// /// * `bps` - 基点权重(例如:3850) /// /// # 返回 /// /// 百分比权重(例如:38.5) pub fn bps_to_percentage(bps: u32) -> f64 { bps as f64 / 100.0 } // ============================================================================ // 量化工具 // ============================================================================ /// 将浮点数特征量化为INT8 /// /// # 参数 /// /// * `value` - 浮点数特征值 /// /// # 返回 /// /// INT8量化值 /// /// # 示例 /// /// ``` /// use xtzh_ai::utils::quantize_to_int8; /// /// let value = 0.5; /// let quantized = quantize_to_int8(value); /// assert!(quantized >= -128 && quantized <= 127); /// ``` pub fn quantize_to_int8(value: f64) -> i8 { let scaled = (value / QUANTIZATION_SCALE as f64).round(); scaled.clamp(INT8_MIN as f64, INT8_MAX as f64) as i8 } /// 将INT8量化值反量化为浮点数 /// /// # 参数 /// /// * `quantized` - INT8量化值 /// /// # 返回 /// /// 浮点数特征值 pub fn dequantize_from_int8(quantized: i8) -> f64 { quantized as f64 * QUANTIZATION_SCALE as f64 } // ============================================================================ // 验证工具 // ============================================================================ /// 验证权重和是否等于100% /// /// # 参数 /// /// * `w_fx` - 货币层权重(基点) /// * `w_au` - 黄金层权重(基点) /// * `w_com` - 商品层权重(基点) /// /// # 返回 /// /// 如果权重和等于10000基点(100%),返回Ok(()),否则返回错误 pub fn validate_weight_sum(w_fx: u32, w_au: u32, w_com: u32) -> Result<()> { let sum = w_fx + w_au + w_com; if sum == WEIGHT_SUM { Ok(()) } else { Err(Error::DataValidationError(format!( "权重和错误: 期望 {}, 实际 {}", WEIGHT_SUM, sum ))) } } /// 验证黄金层权重是否在宪法约束范围内 /// /// # 参数 /// /// * `w_au` - 黄金层权重(基点) /// /// # 返回 /// /// 如果黄金层权重在5%-20%范围内,返回Ok(()),否则返回错误 pub fn validate_gold_weight(w_au: u32) -> Result<()> { if w_au >= W_AU_MIN && w_au <= W_AU_MAX { Ok(()) } else { Err(Error::DataValidationError(format!( "黄金层权重超出宪法约束: 期望 [{}, {}], 实际 {}", W_AU_MIN, W_AU_MAX, w_au ))) } } /// 验证商品偏离系数是否在范围内 /// /// # 参数 /// /// * `delta` - 商品偏离系数 /// /// # 返回 /// /// 如果偏离系数在[-30, 30]范围内,返回Ok(()),否则返回错误 pub fn validate_commodity_delta(delta: i8) -> Result<()> { if delta >= DELTA_MIN && delta <= DELTA_MAX { Ok(()) } else { Err(Error::DataValidationError(format!( "商品偏离系数超出范围: 期望 [{}, {}], 实际 {}", DELTA_MIN, DELTA_MAX, delta ))) } } /// 验证商品偏离系数的零和约束 /// /// # 参数 /// /// * `deltas` - 18维商品偏离系数 /// * `betas` - 18维商品权重(基点) /// /// # 返回 /// /// 如果∑β·Δ = 0,返回Ok(()),否则返回错误 pub fn validate_zero_sum_constraint(deltas: &[i8], betas: &[u32]) -> Result<()> { if deltas.len() != COMMODITY_DELTA_DIM || betas.len() != COMMODITY_DELTA_DIM { return Err(Error::DataValidationError(format!( "维度错误: deltas={}, betas={}, 期望={}", deltas.len(), betas.len(), COMMODITY_DELTA_DIM ))); } let sum: i64 = deltas .iter() .zip(betas.iter()) .map(|(d, b)| *d as i64 * *b as i64) .sum(); if sum == 0 { Ok(()) } else { Err(Error::DataValidationError(format!( "商品偏离零和约束违反: ∑β·Δ = {}", sum ))) } } // ============================================================================ // 时间工具 // ============================================================================ /// 获取当前UTC时间戳(秒) pub fn current_timestamp() -> u64 { chrono::Utc::now().timestamp() as u64 } /// 检查是否为数据更新时间(UTC 12:00) pub fn is_data_update_time() -> bool { let now = chrono::Utc::now(); now.hour() == DATA_UPDATE_HOUR } // ============================================================================ // 测试 // ============================================================================ #[cfg(test)] mod tests { use super::*; #[test] fn test_blake3_hash() { let data = b"Hello, NAC!"; let hash = blake3_hash(data); assert_eq!(hash.len(), 32); // 相同输入应产生相同哈希 let hash2 = blake3_hash(data); assert_eq!(hash, hash2); } #[test] fn test_blake3_hash_hex() { let data = b"Hello, NAC!"; let hex = blake3_hash_hex(data); assert_eq!(hex.len(), 64); } #[test] fn test_rate_conversion() { let rate = 1.034; let fixed = rate_to_fixed(rate); assert_eq!(fixed, 1034000); let rate2 = fixed_to_rate(fixed); assert!((rate2 - rate).abs() < 1e-6); } #[test] fn test_percentage_bps_conversion() { let percentage = 38.5; let bps = percentage_to_bps(percentage); assert_eq!(bps, 3850); let percentage2 = bps_to_percentage(bps); assert!((percentage2 - percentage).abs() < 1e-6); } #[test] fn test_quantization() { let value = 0.5; let quantized = quantize_to_int8(value); let dequantized = dequantize_from_int8(quantized); assert!((dequantized - value).abs() < QUANTIZATION_SCALE as f64); } #[test] fn test_validate_weight_sum() { assert!(validate_weight_sum(4000, 1000, 5000).is_ok()); assert!(validate_weight_sum(4000, 1000, 4999).is_err()); } #[test] fn test_validate_gold_weight() { assert!(validate_gold_weight(1000).is_ok()); assert!(validate_gold_weight(500).is_ok()); assert!(validate_gold_weight(2000).is_ok()); assert!(validate_gold_weight(400).is_err()); assert!(validate_gold_weight(2100).is_err()); } #[test] fn test_validate_commodity_delta() { assert!(validate_commodity_delta(0).is_ok()); assert!(validate_commodity_delta(-30).is_ok()); assert!(validate_commodity_delta(30).is_ok()); assert!(validate_commodity_delta(-31).is_err()); assert!(validate_commodity_delta(31).is_err()); } #[test] fn test_validate_zero_sum_constraint() { let deltas = vec![10, -5, -5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; let betas = vec![ 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, ]; assert!(validate_zero_sum_constraint(&deltas, &betas).is_ok()); } #[test] fn test_current_timestamp() { let ts = current_timestamp(); assert!(ts > 0); } }