Skip to main content

converge_analytics/packs/segmentation/
types.rs

1use converge_pack::gate::GateResult as Result;
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
5pub struct SegmentationInput {
6    pub records: Vec<Vec<f64>>,
7    pub k: usize,
8    #[serde(default = "default_max_iterations")]
9    pub max_iterations: usize,
10    pub seed: Option<u64>,
11}
12
13fn default_max_iterations() -> usize {
14    100
15}
16
17impl SegmentationInput {
18    pub fn validate(&self) -> Result<()> {
19        if self.records.is_empty() {
20            return Err(converge_pack::GateError::invalid_input(
21                "At least one record required",
22            ));
23        }
24        if self.k == 0 {
25            return Err(converge_pack::GateError::invalid_input("k must be >= 1"));
26        }
27        if self.k > self.records.len() {
28            return Err(converge_pack::GateError::invalid_input(
29                "k cannot exceed number of records",
30            ));
31        }
32        if self.max_iterations == 0 {
33            return Err(converge_pack::GateError::invalid_input(
34                "max_iterations must be >= 1",
35            ));
36        }
37        let dim = self.records[0].len();
38        if dim == 0 {
39            return Err(converge_pack::GateError::invalid_input(
40                "Records must have at least one feature",
41            ));
42        }
43        for (i, record) in self.records.iter().enumerate() {
44            if record.len() != dim {
45                return Err(converge_pack::GateError::invalid_input(format!(
46                    "Record {} has {} features, expected {}",
47                    i,
48                    record.len(),
49                    dim
50                )));
51            }
52        }
53        Ok(())
54    }
55}
56
57#[derive(Debug, Clone, Serialize, Deserialize)]
58pub struct SegmentationOutput {
59    pub assignments: Vec<usize>,
60    pub centroids: Vec<Vec<f64>>,
61    pub iterations_used: usize,
62    pub inertia: f64,
63}
64
65impl SegmentationOutput {
66    pub fn summary(&self) -> String {
67        format!(
68            "Segmented {} records into {} clusters in {} iterations (inertia: {:.2})",
69            self.assignments.len(),
70            self.centroids.len(),
71            self.iterations_used,
72            self.inertia,
73        )
74    }
75}