#![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, )] //! Bug #28: Unused import warning for Device in softmax.rs //! //! This test ensures ml/src/dqn/softmax.rs compiles without warnings //! after fixing the conditional compilation of Device import. //! //! Post-migration: softmax functions now operate on host &[f32] slices, //! not on GPU Tensors. No Device import needed. use ml::dqn::softmax::{softmax_with_temperature, sample_from_softmax, softmax_entropy}; #[test] fn test_bug28_softmax_imports_clean() { // Verify softmax.rs compiles without unused import warnings // This test exercises all public functions to ensure they work correctly // Test 1: softmax_with_temperature (now takes &[f32] slices) let q_values = [1.0f32, 2.0, 3.0]; let probs = softmax_with_temperature(&q_values, 1.0) .expect("Failed to compute softmax"); // Verify probabilities sum to 1.0 let sum: f32 = probs.iter().sum(); assert!( (sum - 1.0).abs() < 1e-5, "Probabilities should sum to 1.0, got {}", sum ); // Test 2: sample_from_softmax let action = sample_from_softmax(&q_values, 1.0) .expect("Failed to sample action"); assert!(action < 3, "Action should be in range [0, 3), got {}", action); // Test 3: softmax_entropy let entropy = softmax_entropy(&q_values, 1.0) .expect("Failed to compute entropy"); assert!(entropy > 0.0, "Entropy should be positive, got {}", entropy); assert!(entropy < 2.0, "Entropy should be < log2(3) ~= 1.585, got {}", entropy); } #[test] fn test_bug28_softmax_numerical_stability() { // Test the log-sum-exp trick for numerical stability // Large Q-values that would overflow without stability trick let q_values = [100.0f32, 200.0, 300.0]; let probs = softmax_with_temperature(&q_values, 1.0) .expect("Failed to compute softmax with large values"); // Should still sum to 1.0 despite large values let sum: f32 = probs.iter().sum(); assert!( (sum - 1.0).abs() < 1e-5, "Probabilities should sum to 1.0 even with large Q-values, got {}", sum ); // Verify no NaN or Inf assert!(probs.iter().all(|&p| p.is_finite()), "All probabilities should be finite"); } #[test] fn test_bug28_temperature_control() { // Test temperature parameter effect on exploration let q_values = [1.0f32, 2.0, 3.0]; // Low temperature (greedy) let entropy_low = softmax_entropy(&q_values, 0.1) .expect("Failed to compute entropy with low temp"); // High temperature (exploratory) let entropy_high = softmax_entropy(&q_values, 10.0) .expect("Failed to compute entropy with high temp"); // High temperature should produce higher entropy assert!( entropy_high > entropy_low, "High temperature ({}) should produce higher entropy than low temperature ({})", entropy_high, entropy_low ); }