use rand::seq::SliceRandom;
use rand::thread_rng;
use rand::Rng;
use std::collections::{HashSet, VecDeque};
fn satisfies(assignment: &[bool], clauses: &[(i32, i32)]) -> bool {
for &(a, b) in clauses {
let lit_a = if a > 0 {
assignment[(a - 1) as usize]
} else {
!assignment[(-a - 1) as usize]
};
let lit_b = if b > 0 {
assignment[(b - 1) as usize]
} else {
!assignment[(-b - 1) as usize]
};
if !(lit_a || lit_b) {
return false;
}
}
true
}
fn assignment_to_key(assignment: &[bool]) -> u64 {
let mut key = 0u64;
for &b in assignment {
key = (key << 1) | (if b { 1 } else { 0 });
}
key
}
pub fn randomized_bfs_2sat(clauses: &[(i32, i32)], num_vars: usize) -> Option<Vec<bool>> {
let mut rng = thread_rng();
let mut queue = VecDeque::new();
let initial: Vec<bool> = (0..num_vars).map(|_| rng.gen()).collect();
queue.push_back(initial.clone());
let mut visited = HashSet::new();
visited.insert(assignment_to_key(&initial));
while !queue.is_empty() {
let idx = rng.gen_range(0..queue.len());
let current = queue.remove(idx).unwrap();
if satisfies(¤t, clauses) {
return Some(current);
}
let mut neighbors = Vec::new();
for i in 0..num_vars {
let mut neighbor = current.clone();
neighbor[i] = !neighbor[i];
let key = assignment_to_key(&neighbor);
if !visited.contains(&key) {
visited.insert(key);
neighbors.push(neighbor);
}
}
neighbors.shuffle(&mut rng);
for n in neighbors {
queue.push_back(n);
}
}
None
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_randomized_bfs_2sat_satisfiable() {
let clauses = vec![(1, 2), (-1, 3), (-2, -3)];
let num_vars = 3;
let assignment = randomized_bfs_2sat(&clauses, num_vars);
assert!(assignment.is_some());
let asgn = assignment.unwrap();
assert!(satisfies(&asgn, &clauses));
}
#[test]
fn test_randomized_bfs_2sat_unsatisfiable() {
let clauses = vec![(1, 1), (-1, -1)];
let num_vars = 1;
let assignment = randomized_bfs_2sat(&clauses, num_vars);
assert!(assignment.is_none());
}
}