rust_rule_miner/
types.rs

1use serde::{Deserialize, Serialize};
2use std::time::Duration;
3
4/// An itemset (set of items)
5pub type ItemSet = Vec<String>;
6
7/// Frequent itemset with support value
8#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct FrequentItemset {
10    pub items: ItemSet,
11    pub support: f64,
12}
13
14/// Association rule: A → B
15#[derive(Debug, Clone, Serialize, Deserialize)]
16pub struct AssociationRule {
17    pub antecedent: ItemSet,
18    pub consequent: ItemSet,
19    pub metrics: PatternMetrics,
20}
21
22/// Sequential pattern (ordered itemsets with time constraints)
23#[derive(Debug, Clone, Serialize, Deserialize)]
24pub struct SequentialPattern {
25    pub sequence: Vec<ItemSet>,
26    pub time_gaps: Vec<Duration>,
27    pub support: f64,
28}
29
30/// Pattern quality metrics
31#[derive(Debug, Clone, Serialize, Deserialize)]
32pub struct PatternMetrics {
33    /// Confidence: P(consequent | antecedent)
34    /// How often B happens when A happens
35    pub confidence: f64,
36
37    /// Support: P(antecedent ∧ consequent)
38    /// How common the pattern is overall
39    pub support: f64,
40
41    /// Lift: confidence / P(consequent)
42    /// Strength of correlation (>1: positive, <1: negative, =1: independent)
43    pub lift: f64,
44
45    /// Conviction: P(A) * P(¬B) / P(A ∧ ¬B)
46    /// How much more often A implies B than expected by chance
47    pub conviction: f64,
48
49    /// Optional: time-based metrics
50    #[serde(skip_serializing_if = "Option::is_none")]
51    pub avg_time_gap: Option<Duration>,
52
53    #[serde(skip_serializing_if = "Option::is_none")]
54    pub time_variance: Option<Duration>,
55}
56
57/// Discovered pattern
58#[derive(Debug, Clone, Serialize, Deserialize)]
59pub struct Pattern {
60    pub pattern_type: PatternType,
61    pub items: Vec<String>,
62    pub metrics: PatternMetrics,
63    pub evidence: Vec<String>, // Transaction IDs
64}
65
66#[derive(Debug, Clone, Serialize, Deserialize)]
67pub enum PatternType {
68    /// Frequent itemset (co-occurrence)
69    FrequentItemset,
70
71    /// Sequential pattern (ordered)
72    Sequential { time_constraints: Vec<Duration> },
73
74    /// Association rule (A → B)
75    AssociationRule {
76        antecedent: Vec<String>,
77        consequent: Vec<String>,
78    },
79}
80
81impl AssociationRule {
82    /// Calculate quality score for ranking
83    pub fn quality_score(&self) -> f64 {
84        // Weighted combination of metrics
85        self.metrics.confidence * 0.5 + self.metrics.lift * 0.3 + self.metrics.support * 0.2
86    }
87}
88
89#[cfg(test)]
90mod tests {
91    use super::*;
92
93    #[test]
94    fn test_quality_score() {
95        let rule = AssociationRule {
96            antecedent: vec!["A".to_string()],
97            consequent: vec!["B".to_string()],
98            metrics: PatternMetrics {
99                confidence: 0.8,
100                support: 0.6,
101                lift: 1.5,
102                conviction: 2.0,
103                avg_time_gap: None,
104                time_variance: None,
105            },
106        };
107
108        let score = rule.quality_score();
109        assert!(score > 0.0 && score <= 1.0);
110    }
111}