//! 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); } }