splr 0.17.0

A modern CDCL SAT solver in Rust
Documentation
use {
    super::ClauseId,
    crate::types::*,
    std::{
        collections::HashMap,
        ops::{Index, IndexMut},
    },
};

/// storage of binary links
pub type BinaryLinkList = Vec<(Lit, ClauseId)>;

impl Index<Lit> for Vec<BinaryLinkList> {
    type Output = BinaryLinkList;
    #[inline]
    fn index(&self, l: Lit) -> &Self::Output {
        #[cfg(feature = "unsafe_access")]
        unsafe {
            self.get_unchecked(usize::from(l))
        }
        #[cfg(not(feature = "unsafe_access"))]
        &self[usize::from(l)]
    }
}

impl IndexMut<Lit> for Vec<BinaryLinkList> {
    #[inline]
    fn index_mut(&mut self, l: Lit) -> &mut Self::Output {
        #[cfg(feature = "unsafe_access")]
        unsafe {
            self.get_unchecked_mut(usize::from(l))
        }
        #[cfg(not(feature = "unsafe_access"))]
        &mut self[usize::from(l)]
    }
}

/// storage with mapper to `ClauseId` of binary links
#[derive(Clone, Debug, Default)]
pub struct BinaryLinkDB {
    hash: HashMap<(Lit, Lit), ClauseId>,
    list: Vec<BinaryLinkList>,
}

impl Instantiate for BinaryLinkDB {
    fn instantiate(_conf: &Config, cnf: &CNFDescription) -> Self {
        let num_lit = 2 * (cnf.num_of_variables + 1);
        BinaryLinkDB {
            hash: HashMap::new(),
            list: vec![Vec::new(); num_lit],
        }
    }
    fn handle(&mut self, _e: SolverEvent) {}
}

pub trait BinaryLinkIF {
    /// add a mapping from a pair of Lit to a `ClauseId`
    fn add(&mut self, lit0: Lit, lit1: Lit, cid: ClauseId);
    /// remove a pair of `Lit`s
    fn remove(&mut self, lit0: Lit, lit1: Lit) -> MaybeInconsistent;
    /// return 'ClauseId` linked from a pair of `Lit`s
    fn search(&self, lit0: Lit, lit1: Lit) -> Option<&ClauseId>;
    /// return the all links that include `Lit`.
    /// Note this is not a `watch_list`. The other literal has an opposite phase.
    fn connect_with(&self, lit: Lit) -> &BinaryLinkList;
    /// add new var
    fn add_new_var(&mut self);
    // /// sort links based on var activities
    // fn reorder(&mut self, asg: &impl AssignIF);
}

impl BinaryLinkIF for BinaryLinkDB {
    fn add(&mut self, lit0: Lit, lit1: Lit, cid: ClauseId) {
        let l0 = lit0.min(lit1);
        let l1 = lit0.max(lit1);
        self.hash.insert((l0, l1), cid);
        self.list[lit0].push((lit1, cid));
        self.list[lit1].push((lit0, cid));
    }
    fn remove(&mut self, lit0: Lit, lit1: Lit) -> MaybeInconsistent {
        let l0 = lit0.min(lit1);
        let l1 = lit0.max(lit1);
        self.hash.remove(&(l0, l1));
        self.list[lit0].delete_unstable(|p| p.0 == lit1);
        self.list[lit1].delete_unstable(|p| p.0 == lit0);
        Ok(())
    }
    fn search(&self, lit0: Lit, lit1: Lit) -> Option<&ClauseId> {
        let l0 = lit0.min(lit1);
        let l1 = lit0.max(lit1);
        self.hash.get(&(l0, l1))
    }
    fn connect_with(&self, lit: Lit) -> &BinaryLinkList {
        &self.list[lit]
    }
    fn add_new_var(&mut self) {
        for _ in 0..2 {
            self.list.push(Vec::new());
        }
    }
    /*
    fn reorder(&mut self, asg: &impl AssignIF) {
        let nv = self.list.len() / 2;
        let thr: f64 = (1usize..nv).map(|i| asg.activity(i)).sum::<f64>()
            / (1usize..nv)
                .filter(|i| {
                    !asg.var(*i).is(FlagVar::ELIMINATED)
                        && asg.reason(*i) != AssignReason::Decision(0)
                })
                .count() as f64;
        'next_lit: for (l, vec) in self.list.iter_mut().enumerate().skip(2) {
            if asg.var(Lit::from(l).vi()).is(FlagVar::ELIMINATED) {
                continue 'next_lit;
            }
            if 0.5 * thr <= asg.activity(Lit::from(l).vi()) {
                vec.sort_by_cached_key(|p|
                                       (asg.activity(p.0.vi()) * -100_000.0) as isize);
            } else {
                // Run just the first stage of quick sort.
                let len = vec.len();
                let mut i = 0;
                let mut j = len;
                while i < j {
                    loop {
                        if len == i {
                            continue 'next_lit;
                        }
                        if asg.activity(vec[i].0.vi()) < thr {
                            break;
                        }
                        i += 1;
                    }
                    loop {
                        if j == 0 {
                            continue 'next_lit;
                        }
                        j -= 1;
                        if thr < asg.activity(vec[j].0.vi()) {
                            break;
                        }
                    }
                    vec.swap(i, j);
                    i += 1;
                }
            }
        }
    }
    */
}