From fb7aa46e03c6a36af176c4cbd1bd9cf536833215 Mon Sep 17 00:00:00 2001 From: ProofOfConcept Date: Tue, 3 Mar 2026 12:09:02 -0500 Subject: [PATCH] graph: schema_fit is algebraically identical to clustering_coefficient MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both functions count connected pairs among a node's neighbors: cc = 2*triangles / (deg*(deg-1)) density = inter_edges / (n*(n-1)/2) = 2*inter_edges / (n*(n-1)) Since inter_edges == triangles and n == deg, density == cc. schema_fit was (density + cc) / 2.0 = (cc + cc) / 2.0 = cc. Verified empirically: assert!((density - cc).abs() < 1e-6) passed on all 2401 nodes before this change. Keep schema_fit as a semantic alias — CC is a graph metric, schema fit is a cognitive one — but eliminate the redundant O(n²) pairwise computation that was running for every node. --- src/graph.rs | 37 ++++++++----------------------------- 1 file changed, 8 insertions(+), 29 deletions(-) diff --git a/src/graph.rs b/src/graph.rs index cba9b27..1f25452 100644 --- a/src/graph.rs +++ b/src/graph.rs @@ -500,41 +500,20 @@ fn label_propagation( labels } -/// Schema fit: for a node, measure how well-connected its neighbors are -/// to each other. High density + high CC among neighbors = good schema fit. +/// Schema fit for a node: how well-integrated into its local neighborhood. +/// +/// Algebraically identical to clustering_coefficient — both measure the +/// fraction of neighbor pairs that are connected. Kept as an alias for +/// semantic clarity: CC is a graph metric, schema fit is a cognitive one +/// (how well does this node fit the surrounding schema?). pub fn schema_fit(graph: &Graph, key: &str) -> f32 { - let neighbors = graph.neighbor_keys(key); - let n = neighbors.len(); - if n < 2 { - return 0.0; // isolated or leaf — no schema context - } - - // Count edges among neighbors - let neighbor_vec: Vec<&str> = neighbors.iter().copied().collect(); - let mut inter_edges = 0u32; - for i in 0..neighbor_vec.len() { - for j in (i + 1)..neighbor_vec.len() { - let ni_neighbors = graph.neighbor_keys(neighbor_vec[i]); - if ni_neighbors.contains(neighbor_vec[j]) { - inter_edges += 1; - } - } - } - - let max_edges = (n * (n - 1)) / 2; - let density = if max_edges == 0 { 0.0 } else { - inter_edges as f32 / max_edges as f32 - }; - - // Combine neighborhood density with own CC - let cc = graph.clustering_coefficient(key); - (density + cc) / 2.0 + graph.clustering_coefficient(key) } /// Compute schema fit for all nodes pub fn schema_fit_all(graph: &Graph) -> HashMap { graph.nodes().iter() - .map(|key| (key.clone(), schema_fit(graph, key))) + .map(|key| (key.clone(), graph.clustering_coefficient(key))) .collect() }