use std::collections::HashMap;
#[derive(Clone, Debug)]
pub struct TannerGraphDegree2 {
active_var_ids: Vec<usize>,
check_adjacent: Vec<Vec<usize>>,
var_adjacent: Vec<Vec<usize>>,
}
impl TannerGraphDegree2 {
pub fn from_active_and_equations(active_var_ids: &[usize], equations: &[Vec<usize>]) -> Self {
let n_var = active_var_ids.len();
let global_to_local: HashMap<usize, usize> = active_var_ids
.iter()
.enumerate()
.map(|(i, &v)| (v, i))
.collect();
let mut var_adjacent = vec![Vec::new(); n_var];
let check_adjacent: Vec<Vec<usize>> = equations
.iter()
.map(|eq_vars| {
eq_vars
.iter()
.filter_map(|&v| global_to_local.get(&v).copied())
.collect()
})
.collect();
for (c, adj) in check_adjacent.iter().enumerate() {
for &v_local in adj {
var_adjacent[v_local].push(c);
}
}
Self {
active_var_ids: active_var_ids.to_vec(),
check_adjacent,
var_adjacent,
}
}
fn remove_variable(&mut self, var_local: usize) -> usize {
let mut solved = 1;
let var_adj = self.var_adjacent[var_local].clone();
self.var_adjacent[var_local].clear();
for &c in &var_adj {
if let Some(pos) = self.check_adjacent[c].iter().position(|&x| x == var_local) {
self.check_adjacent[c].swap_remove(pos);
}
if self.check_adjacent[c].len() == 1 {
let other_var = self.check_adjacent[c][0];
solved += self.remove_variable(other_var);
}
}
solved
}
pub fn run_bp_with_inactivation(&mut self, var_local: usize) -> usize {
self.remove_variable(var_local)
}
pub fn best_inactivation_by_trial_run(&mut self) -> Option<usize> {
let mut best_var_id = None;
let mut best_count = 0_usize;
let num_vars = self.var_adjacent.len();
for v_local in 0..num_vars {
if self.var_adjacent[v_local].is_empty() {
continue;
}
let count = self.run_bp_with_inactivation(v_local);
if count > best_count {
best_count = count;
best_var_id = Some(self.active_var_ids[v_local]);
}
}
best_var_id
}
pub fn size(&self) -> usize {
self.check_adjacent.len()
}
}