#![allow( clippy::assertions_on_constants, clippy::assertions_on_result_states, clippy::clone_on_copy, clippy::decimal_literal_representation, clippy::doc_markdown, clippy::empty_line_after_doc_comments, clippy::field_reassign_with_default, clippy::get_unwrap, clippy::identity_op, clippy::inconsistent_digit_grouping, clippy::indexing_slicing, clippy::integer_division, clippy::len_zero, clippy::let_underscore_must_use, clippy::manual_div_ceil, clippy::manual_let_else, clippy::manual_range_contains, clippy::modulo_arithmetic, clippy::needless_range_loop, clippy::non_ascii_literal, clippy::redundant_clone, clippy::shadow_reuse, clippy::shadow_same, clippy::shadow_unrelated, clippy::single_match_else, clippy::str_to_string, clippy::string_slice, clippy::tests_outside_test_module, clippy::too_many_lines, clippy::unnecessary_wraps, clippy::unseparated_literal_suffix, clippy::use_debug, clippy::useless_vec, clippy::wildcard_enum_match_arm, clippy::else_if_without_else, clippy::expect_used, clippy::missing_const_for_fn, clippy::similar_names, clippy::type_complexity, clippy::collapsible_else_if, clippy::doc_lazy_continuation, clippy::items_after_test_module, clippy::map_clone, clippy::multiple_unsafe_ops_per_block, clippy::unwrap_or_default, clippy::assign_op_pattern, clippy::needless_borrow, clippy::println_empty_string, clippy::unnecessary_cast, clippy::used_underscore_binding, clippy::create_dir, clippy::implicit_saturating_sub, clippy::exit, clippy::expect_fun_call, clippy::too_many_arguments, clippy::unnecessary_map_or, clippy::unwrap_used, dead_code, unused_imports, unused_variables, clippy::cloned_ref_to_slice_refs, clippy::neg_multiply, clippy::while_let_loop, clippy::bool_assert_comparison, clippy::excessive_precision, clippy::trivially_copy_pass_by_ref, clippy::op_ref, clippy::redundant_closure, clippy::unnecessary_lazy_evaluations, clippy::if_then_some_else_none, clippy::unnecessary_to_owned, clippy::single_component_path_imports, )] //! 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)] #![allow( clippy::assertions_on_result_states, clippy::doc_markdown, clippy::indexing_slicing, clippy::tests_outside_test_module, clippy::useless_vec, )] 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); } }