Skip to main content

ringkernel_accnet/kernels/
transformation.rs

1//! Journal entry transformation kernels (Methods A-E).
2//!
3//! These kernels transform double-entry journal entries into
4//! directed graph flows using the methods from Ivertowski et al., 2024.
5
6use crate::fabric::GeneratedEntry;
7use crate::models::{SolvingMethod, TransactionFlow};
8
9/// Configuration for transformation kernels.
10#[derive(Debug, Clone)]
11pub struct TransformationConfig {
12    /// Block size for GPU dispatch.
13    pub block_size: u32,
14    /// Maximum entries per batch.
15    pub max_batch_size: u32,
16    /// Enable confidence scoring.
17    pub compute_confidence: bool,
18}
19
20impl Default for TransformationConfig {
21    fn default() -> Self {
22        Self {
23            block_size: 256,
24            max_batch_size: 65536,
25            compute_confidence: true,
26        }
27    }
28}
29
30/// Result of journal transformation.
31#[derive(Debug, Clone)]
32pub struct TransformationResult {
33    /// Generated flows.
34    pub flows: Vec<TransactionFlow>,
35    /// Method used for each entry.
36    pub methods: Vec<SolvingMethod>,
37    /// Statistics about the transformation.
38    pub stats: TransformationStats,
39}
40
41/// Statistics from transformation.
42#[derive(Debug, Clone, Default)]
43pub struct TransformationStats {
44    /// Entries processed.
45    pub entries_processed: usize,
46    /// Flows generated.
47    pub flows_generated: usize,
48    /// Method A count.
49    pub method_a_count: usize,
50    /// Method B count.
51    pub method_b_count: usize,
52    /// Method C count.
53    pub method_c_count: usize,
54    /// Method D count.
55    pub method_d_count: usize,
56    /// Method E count.
57    pub method_e_count: usize,
58    /// Average confidence score.
59    pub avg_confidence: f64,
60}
61
62/// Journal transformation kernel dispatcher.
63pub struct TransformationKernel {
64    #[allow(dead_code)]
65    config: TransformationConfig,
66}
67
68impl TransformationKernel {
69    /// Create a new transformation kernel.
70    pub fn new(config: TransformationConfig) -> Self {
71        Self { config }
72    }
73
74    /// Transform generated entries to flows (CPU fallback).
75    pub fn transform(&self, entries: &[GeneratedEntry]) -> TransformationResult {
76        let mut flows = Vec::new();
77        let mut methods = Vec::new();
78        let mut stats = TransformationStats::default();
79
80        for entry in entries {
81            // Use the expected flows from the generator (source, target, amount)
82            for &(source_idx, target_idx, amount) in &entry.expected_flows {
83                let flow = TransactionFlow::new(
84                    source_idx,
85                    target_idx,
86                    amount,
87                    entry.entry.id,
88                    entry.entry.posting_date,
89                );
90                flows.push(flow);
91            }
92
93            // Determine method from entry
94            let method = entry.entry.solving_method;
95            methods.push(method);
96
97            match method {
98                SolvingMethod::MethodA => stats.method_a_count += 1,
99                SolvingMethod::MethodB => stats.method_b_count += 1,
100                SolvingMethod::MethodC => stats.method_c_count += 1,
101                SolvingMethod::MethodD => stats.method_d_count += 1,
102                SolvingMethod::MethodE => stats.method_e_count += 1,
103                SolvingMethod::Pending => {}
104            }
105        }
106
107        stats.entries_processed = entries.len();
108        stats.flows_generated = flows.len();
109        stats.avg_confidence = if !flows.is_empty() {
110            flows.iter().map(|f| f.confidence as f64).sum::<f64>() / flows.len() as f64
111        } else {
112            0.0
113        };
114
115        TransformationResult {
116            flows,
117            methods,
118            stats,
119        }
120    }
121}
122
123impl Default for TransformationKernel {
124    fn default() -> Self {
125        Self::new(TransformationConfig::default())
126    }
127}
128
129#[cfg(test)]
130mod tests {
131    use super::*;
132
133    #[test]
134    fn test_transformation_kernel_creation() {
135        let kernel = TransformationKernel::default();
136        assert_eq!(kernel.config.block_size, 256);
137    }
138}