pub struct DisjointSet {
fa: Vec<usize>,
value_zero: Option<usize>,
value_one: Option<usize>
}
impl DisjointSet {
pub fn with_capacity(c: usize) -> DisjointSet {
DisjointSet{
fa: Vec::with_capacity(c),
value_zero: None,
value_one: None
}
}
fn find(&mut self, mut u: usize) -> usize {
if self.fa.len() <= u {
self.fa.extend(self.fa.len()..=u);
}
let mut s = u;
while self.fa[s] != s {
s = self.fa[s];
}
while self.fa[u] != s {
let t = self.fa[u];
self.fa[u] = s;
u = t;
}
s
}
pub fn merge(&mut self, a: usize, b: usize) {
let (a, b) = (self.find(a), self.find(b));
self.fa[a] = b;
}
pub fn set_value(&mut self, a: usize, v: bool) {
macro_rules! cas {
($($v:expr => $field:ident),+) => {
match v {
$($v => match self.$field {
None => self.$field = Some(a),
Some(b) => self.merge(a, b)
}),+
}
}
}
cas! {
false => value_zero,
true => value_one
}
}
pub fn finalize(mut self, num_nodes: usize) -> Option<(
usize, Vec<usize>,
Option<usize>, Option<usize>
)> {
self.fa.truncate(num_nodes);
self.fa.extend(self.fa.len()..num_nodes);
let mut set_indices = vec![0; num_nodes];
let mut num_sets = 0;
for (i, f) in self.fa.iter().enumerate() {
if i == *f {
set_indices[i] = num_sets;
num_sets += 1;
}
}
for i in 0..self.fa.len() {
if i != self.fa[i] {
set_indices[i] = set_indices[self.find(i)];
}
}
let id_zero = self.value_zero.map(|i| set_indices[i]);
let id_one = self.value_one.map(|i| set_indices[i]);
if matches!((id_zero, id_one), (Some(a), Some(b)) if a == b) {
clilog::error!(NL_SV_LIT, "Constant zero and one connected");
return None
}
Some((num_sets, set_indices, id_zero, id_one))
}
}