constraint_theory_core/
percolation.rs1use std::collections::HashMap;
4
5pub struct RigidityResult {
10 pub is_rigid: bool,
12 pub rank: usize,
14 pub deficiency: usize,
16 pub n_clusters: usize,
18 pub rigid_fraction: f32,
20}
21
22pub struct FastPercolation {
27 parent: Vec<usize>,
28 rank: Vec<usize>,
29 size: Vec<usize>,
30}
31
32impl FastPercolation {
33 pub fn new(n: usize) -> Self {
35 Self {
36 parent: (0..n).collect(),
37 rank: vec![0; n],
38 size: vec![1; n],
39 }
40 }
41
42 fn find(&mut self, x: usize) -> usize {
43 if self.parent[x] != x {
44 self.parent[x] = self.find(self.parent[x]);
45 }
46 self.parent[x]
47 }
48
49 fn union(&mut self, x: usize, y: usize) {
50 let xr = self.find(x);
51 let yr = self.find(y);
52
53 if xr == yr {
54 return;
55 }
56
57 if self.rank[xr] < self.rank[yr] {
58 self.parent[xr] = yr;
59 self.size[yr] += self.size[xr];
60 } else if self.rank[xr] > self.rank[yr] {
61 self.parent[yr] = xr;
62 self.size[xr] += self.size[yr];
63 } else {
64 self.parent[yr] = xr;
65 self.rank[xr] += 1;
66 self.size[xr] += self.size[yr];
67 }
68 }
69
70 pub fn compute_rigidity(&mut self, edges: &[(usize, usize)], n_nodes: usize) -> RigidityResult {
85 for &(u, v) in edges {
86 if u < n_nodes && v < n_nodes {
87 self.union(u, v);
88 }
89 }
90
91 let mut clusters: HashMap<usize, usize> = HashMap::new();
92 for i in 0..n_nodes {
93 let root = self.find(i);
94 *clusters.entry(root).or_insert(0) += 1;
95 }
96
97 let n_clusters = clusters.len();
98 let n_edges = edges.len();
99
100 let (is_rigid, rank, deficiency) = if n_nodes < 3 {
103 (false, n_edges, if n_edges > 0 { n_edges } else { 0 })
105 } else {
106 let expected_edges = 2 * n_nodes - 3;
107 let is_rigid = n_edges >= expected_edges;
108 let rank = n_edges.min(expected_edges);
109 let deficiency = if n_edges >= 2 * n_nodes - 2 {
110 n_edges - expected_edges
111 } else {
112 expected_edges - n_edges
113 };
114 (is_rigid, rank, deficiency)
115 };
116
117 let rigid_nodes: usize = clusters.values().filter(|&&s| s >= 3).sum();
118
119 let rigid_fraction = rigid_nodes as f32 / n_nodes as f32;
120
121 RigidityResult {
122 is_rigid,
123 rank,
124 deficiency,
125 n_clusters,
126 rigid_fraction,
127 }
128 }
129}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134
135 #[test]
136 fn test_percolation() {
137 let mut perc = FastPercolation::new(5);
138 let edges = [(0, 1), (1, 2), (2, 3), (3, 4)];
139 let result = perc.compute_rigidity(&edges, 5);
140
141 assert!(result.rigid_fraction > 0.0);
142 }
143}