Part of cdcl

This commit is contained in:
hal8174 2024-10-23 19:43:48 +02:00
parent 830a3387b0
commit cdb1e893ab
7 changed files with 232 additions and 28 deletions

9
sat/wikipedia.sat Normal file
View file

@ -0,0 +1,9 @@
x1 | !x4
x1 | !x3 | !x4
x1 | x8 | x12
x2 | x11
!x7 | !x3 | x9
!x7 | x8 | !x9
x7 | x8 | !x10
x7 | x10 | !x12
x1

View file

@ -1,21 +1,158 @@
use crate::{dpll::Index, normal_form::NormalForm}; use crate::{
dpll::Index,
normal_form::{NormalForm, NormalFormIteratorItem},
};
enum Result { #[derive(Debug, Clone, Copy)]
Complete, enum StateItem {
Conflict(Vec<Index>), True,
False,
Unknown,
} }
fn cdcl_internal( #[derive(Debug, Clone)]
cnf: &NormalForm, struct State {
solution: &mut Vec<Index>, map: Vec<StateItem>,
graph: Vec<(Index, Index)>, graph: Vec<(Index, Index)>,
) -> Result {
todo!()
} }
pub fn cdcl(cnf: &NormalForm, solution: &mut Vec<Index>) -> bool { impl State {
match cdcl_internal(cnf, solution, vec![]) { fn new(num_literals: Index) -> Self {
Result::Complete => true, Self {
Result::Conflict(_) => false, map: vec![StateItem::Unknown; num_literals as usize],
graph: Vec::new(),
}
}
fn get_arbitrary_literal(&self) -> Option<Index> {
self.map
.iter()
.position(|i| matches!(i, StateItem::Unknown))
.map(|i| i as Index + 1)
}
fn add_literal_arbitrary(&mut self, l: Index) {
assert!(self.is_unknown_literal(l));
self.set_literal(l);
}
fn add_literal_propagate(&mut self, l: Index, cnf: &NormalForm) -> Result<(), Vec<Index>> {
self.set_literal(l);
Ok(())
}
fn get_literal(&self, l: Index) -> StateItem {
self.map[l.unsigned_abs() as usize - 1]
}
fn set_literal_item(&mut self, l: Index, item: StateItem) {
self.map[l.unsigned_abs() as usize - 1] = item;
}
fn is_unknown_literal(&self, l: Index) -> bool {
matches!(self.get_literal(l), StateItem::Unknown)
}
fn set_literal(&mut self, l: Index) {
self.set_literal_item(
l,
if l > 0 {
StateItem::True
} else {
StateItem::False
},
);
}
fn get_solution(&self) -> Vec<Index> {
let mut res = Vec::new();
for (i, item) in self.map.iter().enumerate() {
let i = (i + 1) as Index;
match item {
StateItem::True => res.push(i),
StateItem::False => res.push(-i),
StateItem::Unknown => panic!(),
}
}
res
}
fn is_complete(&self) -> bool {
!self.map.iter().any(|l| matches!(l, StateItem::Unknown))
}
}
fn unit_propagate(cnf: &NormalForm, state: &mut State) -> Result<(), Vec<Index>> {
if let Some(nfii) = cnf.iter().find(
|NormalFormIteratorItem {
slice,
len: _,
index: _,
}| {
slice
.iter()
.filter(|&&l| state.is_unknown_literal(l))
.count()
== 1
},
) {
let i = nfii
.slice
.iter()
.position(|&i| state.is_unknown_literal(i))
.unwrap();
let l = nfii.slice[i];
state.add_literal_propagate(l, cnf)?;
unit_propagate(cnf, state)
} else {
Ok(())
}
}
fn cdcl_internal(cnf: &mut NormalForm, mut state: State) -> Result<State, Vec<Index>> {
unit_propagate(cnf, &mut state)?;
dbg!(&state);
if state.is_complete() {
return Ok(state);
}
let l = state.get_arbitrary_literal().unwrap();
let mut state_clone = state.clone();
state_clone.add_literal_arbitrary(l);
match cdcl_internal(cnf, state_clone) {
Ok(_) => todo!(),
Err(_) => todo!(),
};
let mut state_clone = state.clone();
state_clone.add_literal_arbitrary(-l);
match cdcl_internal(cnf, state_clone) {
Ok(_) => todo!(),
Err(_) => todo!(),
};
Ok(state)
}
pub fn cdcl(mut cnf: &mut NormalForm) -> Option<Vec<Index>> {
let num_literals = cnf.get_num_literals();
match cdcl_internal(&mut cnf, State::new(num_literals)) {
Ok(state) => {
if state.is_complete() {
Some(state.get_solution())
} else {
None
}
}
Err(_) => None,
} }
} }

View file

@ -1,6 +1,9 @@
use std::{cell::RefCell, collections::HashSet}; use std::{cell::RefCell, collections::HashSet};
use crate::{dpll::Index, normal_form::NormalForm}; use crate::{
dpll::Index,
normal_form::{NormalForm, NormalFormIteratorItem},
};
fn unit_propagate(cnf: &mut NormalForm, solution: &mut Vec<Index>) { fn unit_propagate(cnf: &mut NormalForm, solution: &mut Vec<Index>) {
if let Some((s, _)) = cnf.iter_len(1).next() { if let Some((s, _)) = cnf.iter_len(1).next() {
@ -19,8 +22,13 @@ fn pure_literal_assign(cnf: &mut NormalForm, solution: &mut Vec<Index>) {
let mut literals = LITERALS.take(); let mut literals = LITERALS.take();
literals.clear(); literals.clear();
for (s, _, _) in cnf.iter() { for NormalFormIteratorItem {
literals.extend(s.iter()); slice,
len: _,
index: _,
} in cnf.iter()
{
literals.extend(slice.iter());
} }
for &l in &literals { for &l in &literals {
@ -59,7 +67,7 @@ pub fn dpll(cnf: &NormalForm, solution: &mut Vec<Index>) -> bool {
return false; return false;
} }
let literal = own_cnf.iter().next().unwrap().0[0]; let literal = own_cnf.iter().next().unwrap().slice[0];
own_cnf.push_litearl_clause(literal); own_cnf.push_litearl_clause(literal);
if dpll(&own_cnf, solution) { if dpll(&own_cnf, solution) {

View file

@ -1,4 +1,8 @@
use crate::{dpll::Index, mapping::Mapping, normal_form::NormalForm}; use crate::{
dpll::Index,
mapping::Mapping,
normal_form::{NormalForm, NormalFormIteratorItem},
};
use miette::{miette, Context, Result}; use miette::{miette, Context, Result};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -262,8 +266,13 @@ impl<'s> Expr<'s> {
.into_iter() .into_iter()
.map(|e| Expr::Not(Box::new(e)).disjunctive_normal_form2(mapping)) .map(|e| Expr::Not(Box::new(e)).disjunctive_normal_form2(mapping))
{ {
for (s, _, _) in e.iter() { for NormalFormIteratorItem {
n.add_clause(s); slice,
len: _,
index: _,
} in e.iter()
{
n.add_clause(slice);
} }
} }
n n
@ -285,8 +294,18 @@ impl<'s> Expr<'s> {
for on in v { for on in v {
let mut new_n = NormalForm::new(); let mut new_n = NormalForm::new();
for (old_s, _, _) in n.iter() { for NormalFormIteratorItem {
for (new_s, _, _) in on.iter() { slice: old_s,
len: _,
index: _,
} in n.iter()
{
for NormalFormIteratorItem {
slice: new_s,
len: _,
index: _,
} in on.iter()
{
scratch.clear(); scratch.clear();
scratch.extend_from_slice(old_s); scratch.extend_from_slice(old_s);
scratch.extend_from_slice(new_s); scratch.extend_from_slice(new_s);
@ -305,8 +324,13 @@ impl<'s> Expr<'s> {
let mut n = NormalForm::new(); let mut n = NormalForm::new();
for e in v { for e in v {
let on = e.disjunctive_normal_form2(mapping); let on = e.disjunctive_normal_form2(mapping);
for (s, _, _) in on.iter() { for NormalFormIteratorItem {
n.add_clause(s); slice,
len: _,
index: _,
} in on.iter()
{
n.add_clause(slice);
} }
} }

View file

@ -45,8 +45,16 @@ fn main() -> Result<()> {
(crate::dpll_normal_form::dpll(&cnf, &mut solution), map) (crate::dpll_normal_form::dpll(&cnf, &mut solution), map)
} }
Method::Cdcl => { Method::Cdcl => {
let (cnf, map) = e.cnf_normal_form(); let (mut cnf, map) = e.cnf_normal_form();
(crate::cdcl::cdcl(&cnf, &mut solution), map) dbg!(&map);
match crate::cdcl::cdcl(&mut cnf) {
Some(s) => {
solution.extend_from_slice(&s);
(true, map)
}
None => (false, map),
}
} }
}; };
let elapsed = start.elapsed(); let elapsed = start.elapsed();

View file

@ -2,6 +2,7 @@ use std::collections::HashMap;
use crate::dpll::Index; use crate::dpll::Index;
#[derive(Debug, Clone)]
pub struct Mapping<'s> { pub struct Mapping<'s> {
forward: HashMap<&'s str, Index>, forward: HashMap<&'s str, Index>,
backward: Vec<&'s str>, backward: Vec<&'s str>,

View file

@ -120,6 +120,13 @@ impl NormalForm {
} }
} }
pub fn get_num_literals(&self) -> Index {
self.iter()
.flat_map(|i| i.slice.iter().map(|l| l.abs()))
.max()
.unwrap()
}
pub fn stats(&self) { pub fn stats(&self) {
println!("Normal form stats:"); println!("Normal form stats:");
let mut sum = 0; let mut sum = 0;
@ -147,8 +154,14 @@ impl<'nf> NormalFormIterator<'nf> {
} }
} }
pub struct NormalFormIteratorItem<'nf> {
pub slice: &'nf [Index],
pub len: usize,
pub index: usize,
}
impl<'nf> Iterator for NormalFormIterator<'nf> { impl<'nf> Iterator for NormalFormIterator<'nf> {
type Item = (&'nf [Index], usize, usize); type Item = NormalFormIteratorItem<'nf>;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
while self.len < self.nf.data.len() while self.len < self.nf.data.len()
@ -162,7 +175,11 @@ impl<'nf> Iterator for NormalFormIterator<'nf> {
self.index += 1; self.index += 1;
Some((s, self.len, self.index - 1)) Some(NormalFormIteratorItem {
slice: s,
len: self.len,
index: self.index - 1,
})
} else { } else {
None None
} }