Files
foxhunt/ml/tests/liquid_networks_test.rs
jgrusewski 6093eac7bf 🔧 Tonic 0.14 Upgrade: Auto-generated and build system changes
Wave 64-65 cleanup: Proto regeneration and build system updates from Tonic 0.12→0.14 upgrade

Files updated:
- Cargo.lock: Dependency resolution for Tonic 0.14.2
- All build.rs: Updated for tonic-prost-build
- Proto files: Regenerated with tonic-prost 0.14
- Examples/tests: Updated for new gRPC API

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-03 07:34:26 +02:00

342 lines
9.7 KiB
Rust

//! Liquid Networks Integration Tests
//!
//! Tests for Liquid Time-constant (LTC) and Closed-form Continuous-time (CfC)
//! neural networks with fixed-point arithmetic.
#![allow(unused_crate_dependencies)]
use ml::liquid::{
cells::{CfCConfig, LTCConfig},
ode_solvers::SolverType,
ActivationType, FixedPoint, LiquidNetworkConfig, NetworkType,
};
#[tokio::test]
async fn test_fixed_point_arithmetic() {
// Test basic fixed-point operations with Result handling
let a = FixedPoint::from_f64(1.5);
let b = FixedPoint::from_f64(2.5);
let sum = (a + b).expect("addition should not overflow");
assert!((sum.to_f64() - 4.0).abs() < 1e-6);
let diff = (b - a).expect("subtraction should not overflow");
assert!((diff.to_f64() - 1.0).abs() < 1e-6);
let product = (a * b).expect("multiplication should not overflow");
assert!((product.to_f64() - 3.75).abs() < 1e-6);
let quotient = (b / a).expect("division should not overflow");
assert!((quotient.to_f64() - (5.0 / 3.0)).abs() < 1e-6);
// Test precision handling
let precise = FixedPoint::from_f64(0.12345678);
let recovered = precise.to_f64();
assert!((recovered - 0.12345678).abs() < 1e-7);
}
#[tokio::test]
async fn test_fixed_point_special_values() {
let zero = FixedPoint::zero();
assert_eq!(zero.to_f64(), 0.0);
let one = FixedPoint::one();
assert!((one.to_f64() - 1.0).abs() < 1e-8);
// Test is_finite
assert!(zero.is_finite());
assert!(one.is_finite());
assert!(FixedPoint::from_f64(1000.0).is_finite());
}
#[tokio::test]
async fn test_fixed_point_overflow_handling() {
let large = FixedPoint::from_f64(1e10);
let result = large * large;
// Should return an error for overflow
assert!(result.is_err());
}
#[tokio::test]
async fn test_fixed_point_division_by_zero() {
let a = FixedPoint::from_f64(1.0);
let zero = FixedPoint::zero();
let result = a / zero;
assert!(result.is_err());
}
#[tokio::test]
async fn test_ltc_config_creation() {
let config = LTCConfig {
input_size: 10,
hidden_size: 20,
tau_min: FixedPoint::from_f64(0.1),
tau_max: FixedPoint::from_f64(1.0),
use_bias: true,
solver_type: SolverType::Euler,
activation: ActivationType::Tanh,
};
assert_eq!(config.input_size, 10);
assert_eq!(config.hidden_size, 20);
assert!(config.use_bias);
}
#[tokio::test]
async fn test_cfc_config_creation() {
let config = CfCConfig {
input_size: 15,
hidden_size: 30,
backbone_layers: vec![64, 32],
mixed_memory: true,
use_gate: true,
solver_type: SolverType::RK4,
};
assert_eq!(config.input_size, 15);
assert_eq!(config.hidden_size, 30);
assert_eq!(config.backbone_layers.len(), 2);
assert!(config.mixed_memory);
assert!(config.use_gate);
}
#[tokio::test]
async fn test_liquid_network_config_creation() {
let config = LiquidNetworkConfig {
network_type: NetworkType::LTC,
input_size: 64,
output_size: 32,
layer_configs: vec![],
output_layer: ml::liquid::network::OutputLayerConfig {
use_linear_output: true,
output_activation: Some(ActivationType::Linear),
dropout_rate: None,
},
default_dt: FixedPoint::from_f64(0.01),
market_regime_adaptation: false,
};
assert_eq!(config.input_size, 64);
assert_eq!(config.output_size, 32);
assert!(matches!(config.network_type, NetworkType::LTC));
}
#[tokio::test]
async fn test_fixed_point_comparison() {
let a = FixedPoint::from_f64(1.5);
let b = FixedPoint::from_f64(2.5);
let c = FixedPoint::from_f64(1.5);
assert!(a < b);
assert!(b > a);
assert_eq!(a, c);
assert_ne!(a, b);
}
#[tokio::test]
async fn test_fixed_point_ordering() {
let mut values = vec![
FixedPoint::from_f64(3.0),
FixedPoint::from_f64(1.0),
FixedPoint::from_f64(2.0),
];
values.sort();
assert_eq!(values[0].to_f64(), 1.0);
assert_eq!(values[1].to_f64(), 2.0);
assert_eq!(values[2].to_f64(), 3.0);
}
#[tokio::test]
async fn test_activation_types() {
// Test that all activation types can be created
let activations = vec![
ActivationType::Tanh,
ActivationType::Sigmoid,
ActivationType::ReLU,
ActivationType::LeakyReLU,
ActivationType::Linear,
];
for activation in activations {
// Just verify they can be constructed
let config = LTCConfig {
input_size: 4,
hidden_size: 8,
tau_min: FixedPoint::from_f64(0.1),
tau_max: FixedPoint::from_f64(1.0),
use_bias: true,
solver_type: SolverType::Euler,
activation,
};
assert_eq!(config.input_size, 4);
}
}
#[tokio::test]
async fn test_solver_types() {
let solvers = vec![SolverType::Euler, SolverType::RK4, SolverType::Adaptive];
for solver in solvers {
let config = LTCConfig {
input_size: 5,
hidden_size: 10,
tau_min: FixedPoint::from_f64(0.1),
tau_max: FixedPoint::from_f64(1.0),
use_bias: false,
solver_type: solver,
activation: ActivationType::Tanh,
};
assert_eq!(config.hidden_size, 10);
}
}
#[tokio::test]
async fn test_network_types() {
let types = vec![NetworkType::LTC, NetworkType::CfC, NetworkType::Mixed];
for network_type in types {
let config = LiquidNetworkConfig {
network_type,
input_size: 16,
output_size: 8,
layer_configs: vec![],
output_layer: ml::liquid::network::OutputLayerConfig {
use_linear_output: true,
output_activation: Some(ActivationType::Linear),
dropout_rate: None,
},
default_dt: FixedPoint::from_f64(0.01),
market_regime_adaptation: false,
};
assert_eq!(config.input_size, 16);
}
}
#[tokio::test]
async fn test_fixed_point_negative_values() {
let neg = FixedPoint::from_f64(-5.5);
let pos = FixedPoint::from_f64(3.0);
let sum = (neg + pos).expect("addition should work");
assert!((sum.to_f64() - (-2.5)).abs() < 1e-6);
let product = (neg * pos).expect("multiplication should work");
assert!((product.to_f64() - (-16.5)).abs() < 1e-6);
}
#[tokio::test]
async fn test_fixed_point_chain_operations() {
let a = FixedPoint::from_f64(2.0);
let b = FixedPoint::from_f64(3.0);
let c = FixedPoint::from_f64(4.0);
// Test: (a + b) * c
let sum = (a + b).expect("addition should work");
let result = (sum * c).expect("multiplication should work");
assert!((result.to_f64() - 20.0).abs() < 1e-6);
// Test: (a * b) + c
let product = (a * b).expect("multiplication should work");
let result2 = (product + c).expect("addition should work");
assert!((result2.to_f64() - 10.0).abs() < 1e-6);
}
#[tokio::test]
async fn test_config_with_varying_sizes() {
let sizes = vec![(2, 4), (10, 20), (50, 100), (128, 256)];
for (input_size, hidden_size) in sizes {
let config = LTCConfig {
input_size,
hidden_size,
tau_min: FixedPoint::from_f64(0.1),
tau_max: FixedPoint::from_f64(1.0),
use_bias: true,
solver_type: SolverType::Euler,
activation: ActivationType::Tanh,
};
assert_eq!(config.input_size, input_size);
assert_eq!(config.hidden_size, hidden_size);
}
}
#[tokio::test]
async fn test_time_constant_ranges() {
let tau_ranges = vec![(0.01, 0.1), (0.1, 1.0), (1.0, 10.0)];
for (tau_min, tau_max) in tau_ranges {
let config = LTCConfig {
input_size: 8,
hidden_size: 16,
tau_min: FixedPoint::from_f64(tau_min),
tau_max: FixedPoint::from_f64(tau_max),
use_bias: true,
solver_type: SolverType::Euler,
activation: ActivationType::Tanh,
};
assert!((config.tau_min.to_f64() - tau_min).abs() < 1e-6);
assert!((config.tau_max.to_f64() - tau_max).abs() < 1e-6);
assert!(config.tau_min < config.tau_max);
}
}
#[tokio::test]
async fn test_cfc_backbone_configurations() {
let backbone_configs = vec![vec![32], vec![64, 32], vec![128, 64, 32]];
for backbone in backbone_configs {
let expected_len = backbone.len();
let config = CfCConfig {
input_size: 16,
hidden_size: 32,
backbone_layers: backbone.clone(),
mixed_memory: true,
use_gate: true,
solver_type: SolverType::RK4,
};
assert_eq!(config.backbone_layers.len(), expected_len);
assert_eq!(config.backbone_layers, backbone);
}
}
#[tokio::test]
async fn test_fixed_point_precision_limits() {
// Test values near precision limits
let small = FixedPoint::from_f64(1e-7);
assert!(small.to_f64() > 0.0);
assert!(small.to_f64() < 1e-6);
let large = FixedPoint::from_f64(1e6);
assert!(large.to_f64() > 999999.0);
assert!(large.to_f64() < 1000001.0);
}
#[tokio::test]
async fn test_dt_values() {
let dt_values = vec![0.001, 0.01, 0.05, 0.1];
for dt in dt_values {
let config = LiquidNetworkConfig {
network_type: NetworkType::LTC,
input_size: 10,
output_size: 5,
layer_configs: vec![],
output_layer: ml::liquid::network::OutputLayerConfig {
use_linear_output: true,
output_activation: Some(ActivationType::Linear),
dropout_rate: None,
},
default_dt: FixedPoint::from_f64(dt),
market_regime_adaptation: false,
};
assert!((config.default_dt.to_f64() - dt).abs() < 1e-8);
}
}