aip-sci 0.1.0

Affective Interaction Programming - 情感交互编程
Documentation
use std::collections::HashMap;

pub const FEATURE_COUNT: usize = 15;

pub const FEATURE_TAP_FREQUENCY: u32 = 0;
pub const FEATURE_SWIPE_SPEED: u32 = 1;
pub const FEATURE_MULTI_TOUCH_RATIO: u32 = 2;
pub const FEATURE_DEVICE_TILT_STD: u32 = 3;
pub const FEATURE_RETRY_DELAY: u32 = 4;
pub const FEATURE_PAUSE_DURATION: u32 = 5;
pub const FEATURE_HESITATION_TIME: u32 = 6;
pub const FEATURE_PATH_EFFICIENCY: u32 = 7;
pub const FEATURE_CANCEL_RATE: u32 = 8;
pub const FEATURE_COMPLETION_RATE: u32 = 9;
pub const FEATURE_AVG_PRESSURE: u32 = 10;
pub const FEATURE_PRESSURE_STD: u32 = 11;
pub const FEATURE_ACTION_PRECISION: u32 = 12;
pub const FEATURE_AVG_REACTION_TIME: u32 = 13;
pub const FEATURE_REACTION_TIME_STD: u32 = 14;

pub struct FeatureExtractor;

impl FeatureExtractor {
    pub fn normalize_z_score(features: &mut HashMap<u32, f32>, mean: &HashMap<u32, f32>, std: &HashMap<u32, f32>) {
        for (&key, value) in features.iter_mut() {
            if let (Some(&m), Some(&s)) = (mean.get(&key), std.get(&key)) {
                if s > 0.0 {
                    *value = (*value - m) / s;
                }
            }
        }
    }
    
    pub fn to_vector(features: &HashMap<u32, f32>) -> Vec<f32> {
        let mut vec = vec![0.0f32; FEATURE_COUNT];
        for (&key, &value) in features {
            if (key as usize) < FEATURE_COUNT {
                vec[key as usize] = value;
            }
        }
        vec
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_feature_count() {
        assert_eq!(FEATURE_COUNT, 15);
    }
    
    #[test]
    fn test_feature_constants() {
        assert_eq!(FEATURE_TAP_FREQUENCY, 0);
        assert_eq!(FEATURE_SWIPE_SPEED, 1);
        assert_eq!(FEATURE_MULTI_TOUCH_RATIO, 2);
        assert_eq!(FEATURE_DEVICE_TILT_STD, 3);
        assert_eq!(FEATURE_RETRY_DELAY, 4);
        assert_eq!(FEATURE_PAUSE_DURATION, 5);
        assert_eq!(FEATURE_HESITATION_TIME, 6);
        assert_eq!(FEATURE_PATH_EFFICIENCY, 7);
        assert_eq!(FEATURE_CANCEL_RATE, 8);
        assert_eq!(FEATURE_COMPLETION_RATE, 9);
        assert_eq!(FEATURE_AVG_PRESSURE, 10);
        assert_eq!(FEATURE_PRESSURE_STD, 11);
        assert_eq!(FEATURE_ACTION_PRECISION, 12);
        assert_eq!(FEATURE_AVG_REACTION_TIME, 13);
        assert_eq!(FEATURE_REACTION_TIME_STD, 14);
    }
    
    #[test]
    fn test_to_vector() {
        let mut features = HashMap::new();
        features.insert(0, 1.0);
        features.insert(5, 2.0);
        features.insert(14, 3.0);
        
        let vec = FeatureExtractor::to_vector(&features);
        assert_eq!(vec.len(), FEATURE_COUNT);
        assert!((vec[0] - 1.0).abs() < 1e-6);
        assert!((vec[5] - 2.0).abs() < 1e-6);
        assert!((vec[14] - 3.0).abs() < 1e-6);
        assert!((vec[1] - 0.0).abs() < 1e-6);
    }
    
    #[test]
    fn test_normalize_z_score() {
        let mut features = HashMap::new();
        features.insert(0, 10.0);
        features.insert(1, 20.0);
        
        let mean = HashMap::from([(0, 5.0), (1, 10.0)]);
        let std = HashMap::from([(0, 5.0), (1, 10.0)]);
        
        FeatureExtractor::normalize_z_score(&mut features, &mean, &std);
        
        assert!((features.get(&0).unwrap() - 1.0).abs() < 1e-6);
        assert!((features.get(&1).unwrap() - 1.0).abs() < 1e-6);
    }
}