Skip to main content

docvortex_core/
columns.rs

1//! 按当前 CPython 的求和顺序增量聚类,不重排锚点或首命中簇。
2
3#[derive(Clone)]
4pub struct Column {
5    pub mean: f64,
6    pub hi: f64,
7    pub lo: f64,
8    pub count: usize,
9    pub rows: usize,
10    last_row: usize,
11}
12
13pub struct Columns {
14    pub groups: [Vec<Column>; 3],
15    pub row_count: usize,
16    compensated: bool,
17    valid: bool,
18}
19
20impl Columns {
21    /// 首个锚点的均值保持原值;累计器模拟 Python 整数零加首个浮点值。
22    pub fn new(compensated: bool) -> Self {
23        Self {
24            groups: Default::default(),
25            row_count: 0,
26            compensated,
27            valid: true,
28        }
29    }
30
31    /// 单调追加行并保持每簇去重后的行覆盖量,溢出后丢弃整个原生状态。
32    pub fn extend(&mut self, rows: &[Vec<(f64, f64)>], tolerance: f64) -> Option<(usize, f64)> {
33        self.extend_rows(rows, tolerance)
34    }
35
36    /// 自有页面锚点通过借用片段追加,不再为每个区间复制嵌套数值数组。
37    pub fn extend_refs(&mut self, rows: &[&[(f64, f64)]], tolerance: f64) -> Option<(usize, f64)> {
38        self.extend_rows(rows, tolerance)
39    }
40
41    /// 两种传输形式共用完全相同的累计与稳定聚类实现,保留浮点求和顺序。
42    fn extend_rows<T: AsRef<[(f64, f64)]>>(
43        &mut self,
44        rows: &[T],
45        tolerance: f64,
46    ) -> Option<(usize, f64)> {
47        if !self.valid || !tolerance.is_finite() || tolerance < 0.0 {
48            return None;
49        }
50        for alignment in 0..3 {
51            let clusters = &mut self.groups[alignment];
52            for (offset, fragments) in rows.iter().enumerate() {
53                let row = self.row_count + offset;
54                for &(left, right) in fragments.as_ref() {
55                    let anchor = match alignment {
56                        0 => left,
57                        1 => (left + right) / 2.0,
58                        _ => right,
59                    };
60                    if !left.is_finite() || !right.is_finite() || !anchor.is_finite() {
61                        self.valid = false;
62                        return None;
63                    }
64                    if let Some(cluster) = clusters
65                        .iter_mut()
66                        .find(|c| (anchor - c.mean).abs() <= tolerance)
67                    {
68                        let t = cluster.hi + anchor;
69                        if self.compensated {
70                            cluster.lo += if cluster.hi.abs() >= anchor.abs() {
71                                (cluster.hi - t) + anchor
72                            } else {
73                                (anchor - t) + cluster.hi
74                            };
75                        }
76                        cluster.hi = t;
77                        cluster.count += 1;
78                        let sum = if self.compensated && cluster.lo != 0.0 && cluster.lo.is_finite()
79                        {
80                            cluster.hi + cluster.lo
81                        } else {
82                            cluster.hi
83                        };
84                        cluster.mean = sum / cluster.count as f64;
85                        if !cluster.mean.is_finite()
86                            || !cluster.hi.is_finite()
87                            || !cluster.lo.is_finite()
88                        {
89                            self.valid = false;
90                            return None;
91                        }
92                        if cluster.last_row != row {
93                            cluster.rows += 1;
94                            cluster.last_row = row;
95                        }
96                    } else {
97                        clusters.push(Column {
98                            mean: anchor,
99                            hi: 0.0 + anchor,
100                            lo: 0.0,
101                            count: 1,
102                            rows: 1,
103                            last_row: row,
104                        });
105                    }
106                }
107            }
108        }
109        self.row_count += rows.len();
110        let mut best = (0, 0.0);
111        if self.row_count == 0 {
112            return Some(best);
113        }
114        for clusters in &self.groups {
115            let mut count = 0;
116            let mut minimum: f64 = 1.0;
117            for cluster in clusters {
118                let coverage = cluster.rows as f64 / self.row_count as f64;
119                if coverage >= 0.5 {
120                    count += 1;
121                    minimum = minimum.min(coverage);
122                }
123            }
124            let result = (count, if count == 0 { 0.0 } else { minimum });
125            if result > best {
126                best = result;
127            }
128        }
129        Some(best)
130    }
131}