use warp_types_sat::literal::Lit;
#[derive(Debug, Clone)]
pub struct Frame {
clauses: Vec<Vec<Lit>>,
}
impl Frame {
pub fn new() -> Self {
Frame {
clauses: Vec::new(),
}
}
pub fn from_clauses(clauses: Vec<Vec<Lit>>) -> Self {
Frame { clauses }
}
pub fn add_clause(&mut self, clause: Vec<Lit>) {
let mut sorted: Vec<u32> = clause.iter().map(|l| l.code()).collect();
sorted.sort();
let is_dup = self.clauses.iter().any(|existing| {
let mut ex_sorted: Vec<u32> = existing.iter().map(|l| l.code()).collect();
ex_sorted.sort();
ex_sorted == sorted
});
if !is_dup {
self.clauses.push(clause);
}
}
pub fn clauses(&self) -> &[Vec<Lit>] {
&self.clauses
}
pub fn len(&self) -> usize {
self.clauses.len()
}
pub fn is_empty(&self) -> bool {
self.clauses.is_empty()
}
}
impl Default for Frame {
fn default() -> Self {
Self::new()
}
}
pub struct FrameSequence {
frames: Vec<Frame>,
}
impl FrameSequence {
pub fn new() -> Self {
FrameSequence {
frames: Vec::new(),
}
}
pub fn push(&mut self, frame: Frame) {
self.frames.push(frame);
}
pub fn frontier(&self) -> usize {
self.frames.len().saturating_sub(1)
}
pub fn len(&self) -> usize {
self.frames.len()
}
pub fn frame(&self, level: usize) -> &Frame {
&self.frames[level]
}
pub fn frame_mut(&mut self, level: usize) -> &mut Frame {
&mut self.frames[level]
}
pub fn add_blocked_clause(&mut self, level: usize, clause: Vec<Lit>) {
for i in 1..=level {
if i < self.frames.len() {
self.frames[i].add_clause(clause.clone());
}
}
}
pub fn check_convergence(&self) -> Option<usize> {
if self.frames.len() < 3 {
return None; }
for i in 1..self.frames.len() - 1 {
if frames_equal(&self.frames[i], &self.frames[i + 1]) {
return Some(i);
}
}
None
}
}
impl Default for FrameSequence {
fn default() -> Self {
Self::new()
}
}
fn frames_equal(a: &Frame, b: &Frame) -> bool {
if a.len() != b.len() {
return false;
}
let normalize = |f: &Frame| -> Vec<Vec<u32>> {
let mut clauses: Vec<Vec<u32>> = f
.clauses()
.iter()
.map(|c| {
let mut sorted: Vec<u32> = c.iter().map(|l| l.code()).collect();
sorted.sort();
sorted
})
.collect();
clauses.sort();
clauses
};
normalize(a) == normalize(b)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn frame_add_and_read() {
let mut frame = Frame::new();
frame.add_clause(vec![Lit::pos(0), Lit::neg(1)]);
assert_eq!(frame.len(), 1);
assert_eq!(frame.clauses()[0].len(), 2);
}
#[test]
fn frames_equal_order_independent() {
let mut a = Frame::new();
a.add_clause(vec![Lit::pos(0)]);
a.add_clause(vec![Lit::neg(1)]);
let mut b = Frame::new();
b.add_clause(vec![Lit::neg(1)]);
b.add_clause(vec![Lit::pos(0)]);
assert!(frames_equal(&a, &b));
}
#[test]
fn convergence_detected() {
let mut seq = FrameSequence::new();
seq.push(Frame::new());
let mut f1 = Frame::new();
f1.add_clause(vec![Lit::neg(0)]);
seq.push(f1);
let mut f2 = Frame::new();
f2.add_clause(vec![Lit::neg(0)]);
seq.push(f2);
assert_eq!(seq.check_convergence(), Some(1));
}
#[test]
fn no_convergence_when_different() {
let mut seq = FrameSequence::new();
seq.push(Frame::new());
let mut f1 = Frame::new();
f1.add_clause(vec![Lit::neg(0)]);
seq.push(f1);
let f2 = Frame::new(); seq.push(f2);
assert_eq!(seq.check_convergence(), None);
}
}