NAC_Blockchain/xtzh-ai/src/utils.rs

382 lines
9.4 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! 工具函数
//!
//! 本模块提供XTZH AI系统中常用的工具函数。
use crate::constants::*;
use crate::error::{Error, Result};
use blake3::Hasher;
use chrono::Timelike;
// ============================================================================
// 哈希工具遵循ARCH_003Blake3哈希统一
// ============================================================================
/// 计算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);
}
}