Skip to main content

holographic_memory/core/engine/
concepts.rs

1// Copyright 2024-2026 WritersLogic Contributors
2// SPDX-License-Identifier: Apache-2.0
3
4use super::HmsCore;
5use crate::core::entangled::EntangledHVec;
6use crate::core::types::ConceptCandidate;
7
8impl HmsCore {
9    /// Cluster similar vectors and return concept candidates with centroids and coherence scores.
10    pub fn synthesize_concepts(&self) -> Vec<ConceptCandidate> {
11        let cfg = &self.config.concepts;
12        let mut all_ids = Vec::new();
13        let mut all_vectors = Vec::new();
14
15        let shards = self.shards.read();
16        shards.for_each_shard(|shard| {
17            let (ids, vectors) = shard.load_all_vectors();
18            all_ids.extend(ids);
19            all_vectors.extend(vectors);
20        });
21
22        if all_ids.len() < cfg.min_cluster_size {
23            return vec![];
24        }
25
26        let n = all_vectors.len();
27        let mut used = vec![false; n];
28        let mut concepts = Vec::new();
29
30        for i in 0..n {
31            if used[i] {
32                continue;
33            }
34            let mut cluster = vec![i];
35            for j in (i + 1)..n {
36                if used[j] {
37                    continue;
38                }
39                if all_vectors[i].similarity(&all_vectors[j]) > cfg.similarity_threshold {
40                    cluster.push(j);
41                }
42            }
43            if cluster.len() >= cfg.min_cluster_size {
44                for &idx in &cluster {
45                    used[idx] = true;
46                }
47                let cluster_vecs: Vec<&EntangledHVec> =
48                    cluster.iter().map(|&idx| &all_vectors[idx]).collect();
49                let centroid = self.bundle(&cluster_vecs);
50                let coherence: f64 = cluster_vecs
51                    .iter()
52                    .map(|v| v.similarity(&centroid))
53                    .sum::<f64>()
54                    / cluster_vecs.len() as f64;
55                let member_ids: Vec<String> =
56                    cluster.iter().map(|&idx| all_ids[idx].clone()).collect();
57
58                concepts.push(ConceptCandidate {
59                    centroid_id: member_ids.first().cloned().unwrap_or_default(),
60                    member_count: cluster.len() as u32,
61                    coherence,
62                    member_ids,
63                });
64            }
65            used[i] = true;
66        }
67        concepts
68    }
69}