use warp_types_sat::literal::Lit;
#[derive(Debug, Clone)]
pub struct Cube {
pub lits: Vec<Lit>,
}
impl Cube {
pub fn new(lits: Vec<Lit>) -> Self {
Cube { lits }
}
pub fn negate(&self) -> Vec<Lit> {
self.lits.iter().map(|l| l.complement()).collect()
}
pub fn shift(&self, offset: u32) -> Cube {
Cube {
lits: self.lits.iter().map(|&l| shift_lit(l, offset)).collect(),
}
}
pub fn from_assignment(assignment: &[bool], num_state_vars: u32) -> Cube {
let lits: Vec<Lit> = (0..num_state_vars)
.map(|v| {
if assignment[v as usize] {
Lit::pos(v)
} else {
Lit::neg(v)
}
})
.collect();
Cube { lits }
}
pub fn from_assignment_next_state(
assignment: &[bool],
num_state_vars: u32,
) -> Cube {
let offset = num_state_vars as usize;
let lits: Vec<Lit> = (0..num_state_vars)
.map(|v| {
if assignment[offset + v as usize] {
Lit::pos(v)
} else {
Lit::neg(v)
}
})
.collect();
Cube { lits }
}
pub fn to_state_vec(&self, num_state_vars: u32) -> Vec<bool> {
let mut state = vec![false; num_state_vars as usize];
for &lit in &self.lits {
let v = lit.var() as usize;
if v < state.len() {
state[v] = !lit.is_negated();
}
}
state
}
}
pub(crate) fn shift_lit(lit: Lit, offset: u32) -> Lit {
let var = lit.var() + offset;
if lit.is_negated() {
Lit::neg(var)
} else {
Lit::pos(var)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn cube_negate() {
let cube = Cube::new(vec![Lit::pos(0), Lit::neg(1)]);
let clause = cube.negate();
assert_eq!(clause.len(), 2);
assert_eq!(clause[0], Lit::neg(0));
assert_eq!(clause[1], Lit::pos(1));
}
#[test]
fn cube_shift() {
let cube = Cube::new(vec![Lit::pos(0), Lit::neg(1)]);
let shifted = cube.shift(3);
assert_eq!(shifted.lits[0], Lit::pos(3));
assert_eq!(shifted.lits[1], Lit::neg(4));
}
#[test]
fn cube_from_assignment() {
let assign = vec![true, false, true];
let cube = Cube::from_assignment(&assign, 3);
assert_eq!(cube.lits[0], Lit::pos(0));
assert_eq!(cube.lits[1], Lit::neg(1));
assert_eq!(cube.lits[2], Lit::pos(2));
}
#[test]
fn cube_roundtrip() {
let assign = vec![true, false, true, false];
let cube = Cube::from_assignment(&assign, 4);
let state = cube.to_state_vec(4);
assert_eq!(state, assign);
}
}