use crate::{
clause::{puts_clause_with_id, Clause, ClauseIdentifierType},
literal::Literal,
memory::{HeapSpace, Offset, Vector},
};
use rate_macros::HeapSpace;
use std::{
convert::TryFrom,
mem::size_of,
ops::{Index, IndexMut, Range},
};
pub trait ClauseStorage {
fn open_clause(&mut self) -> Clause;
fn push_literal(&mut self, literal: Literal, verbose: bool);
}
pub const PADDING_START: usize = 2;
pub const FIELDS_OFFSET: usize = 1;
pub const PADDING_END: usize = 1;
#[derive(Debug, PartialEq, HeapSpace)]
pub struct ClauseDatabase {
data: Vector<Literal>,
offset: Vector<usize>,
have_sentinel: bool,
}
impl ClauseStorage for ClauseDatabase {
fn open_clause(&mut self) -> Clause {
requires!(self.have_sentinel);
let id = self.number_of_clauses();
self.pop_sentinel();
let clause = Clause::new(id);
self.offset.push(self.data.len()); self.data.push(Literal::from_raw(id));
self.data.push(Literal::from_raw(0)); clause
}
fn push_literal(&mut self, literal: Literal, verbose: bool) {
if literal.is_zero() {
self.close_clause(verbose)
} else {
self.data.push(literal)
}
}
}
impl Default for ClauseDatabase {
fn default() -> ClauseDatabase {
let mut db = ClauseDatabase {
data: Vector::new(),
offset: Vector::new(),
have_sentinel: false,
};
db.push_sentinel(db.data.len());
db
}
}
impl ClauseDatabase {
#[cfg(test)]
pub fn from(data: Vector<Literal>, offset: Vector<usize>) -> ClauseDatabase {
let mut db = ClauseDatabase {
data,
offset,
have_sentinel: false,
};
db.push_sentinel(db.data.len());
db
}
pub fn number_of_clauses(&self) -> ClauseIdentifierType {
requires!(self.have_sentinel);
let sentinel_size = 1;
let number = self.offset.len() - sentinel_size;
requires!(ClauseIdentifierType::try_from(number).is_ok());
number as ClauseIdentifierType
}
pub fn last_clause(&self) -> Clause {
requires!(self.have_sentinel);
requires!(self.number_of_clauses() > 0);
Clause::new(self.number_of_clauses() - 1)
}
fn last_clause_no_sentinel(&self) -> Clause {
requires!(!self.have_sentinel);
let index = self.offset.len() - 1;
Clause::from_usize(index)
}
fn push_sentinel(&mut self, offset: usize) {
requires!(!self.have_sentinel);
self.offset.push(offset);
self.have_sentinel = true;
}
fn pop_sentinel(&mut self) {
requires!(self.have_sentinel);
self.offset.pop();
self.have_sentinel = false;
}
fn close_clause(&mut self, verbose: bool) {
requires!(!self.have_sentinel);
let clause = self.last_clause_no_sentinel();
let start = self.offset[clause.as_offset()] + PADDING_START;
let end = self.data.len();
sort_clause(&mut self.data[start..end]);
let mut duplicate = false;
let mut length = 0;
for i in start..end {
if i + 1 < end && self[i] == self[i + 1] {
duplicate = true;
} else {
self[start + length] = self[i];
length += 1;
}
}
self.data.truncate(start + length);
if length == 1 {
self.data.push(Literal::BOTTOM);
}
self.data.push(Literal::new(0));
self.push_sentinel(self.data.len());
if verbose && duplicate {
as_warning!({
puts!("c removed duplicate literals in ");
puts_clause_with_id(clause, self.clause(clause));
puts!("\n");
});
}
}
pub fn pop_clause(&mut self) {
requires!(self.have_sentinel);
let last_clause = self.last_clause();
let last_clause_offset = self.offset[last_clause.as_offset()];
self.data.truncate(last_clause_offset);
self.pop_sentinel();
self.offset.pop(); self.push_sentinel(last_clause_offset);
}
pub fn clause_to_string(&self, clause: Clause) -> String {
format!(
"[{}]{} 0",
clause,
self.clause(clause)
.iter()
.filter(|&literal| *literal != Literal::BOTTOM)
.map(|&literal| format!(" {}", literal))
.collect::<Vector<_>>()
.join("")
)
}
pub fn clause(&self, clause: Clause) -> &[Literal] {
&self.data[self.clause_range(clause)]
}
pub fn clause_range(&self, clause: Clause) -> Range<usize> {
requires!(self.have_sentinel);
self.offset[clause.as_offset()] + PADDING_START
..self.offset[clause.as_offset() + 1] - PADDING_END
}
pub fn watches(&self, head: usize) -> [Literal; 2] {
[self[head], self[head + 1]]
}
pub fn clause2offset(&self, clause: Clause) -> usize {
self.clause_range(clause).start
}
pub fn offset2clause(&self, head: usize) -> Clause {
Clause::new(self[head - PADDING_START].encoding)
}
pub fn swap(&mut self, a: usize, b: usize) {
self.data.swap(a, b);
}
pub fn fields(&self, clause: Clause) -> &u32 {
&self.data[self.offset[clause.as_offset()] + FIELDS_OFFSET].encoding
}
pub fn fields_mut(&mut self, clause: Clause) -> &mut u32 {
&mut self.data[self.offset[clause.as_offset()] + FIELDS_OFFSET].encoding
}
pub fn fields_from_offset(&self, offset: usize) -> &u32 {
&self.data[offset - 1].encoding
}
pub fn fields_mut_from_offset(&mut self, offset: usize) -> &mut u32 {
&mut self.data[offset - 1].encoding
}
pub fn shrink_to_fit(&mut self) {
self.data.push(Literal::new(0));
self.data.shrink_to_fit();
self.data.pop();
self.offset.push(0);
self.offset.shrink_to_fit();
self.offset.pop();
}
#[allow(dead_code)]
fn metrics(&self) {
let _db_size = self.data.capacity() * size_of::<Literal>();
let _drat_trim_clause_db_size = size_of::<Literal>()
* (
self.data.capacity() - (0..self.number_of_clauses()).map(Clause::new).filter(|&c| is_size_1_clause(self.clause(c))).count()
+ self.number_of_clauses() as usize - (2 + 1) + 1
);
}
}
impl Index<usize> for ClauseDatabase {
type Output = Literal;
fn index(&self, offset: usize) -> &Literal {
&self.data[offset]
}
}
impl IndexMut<usize> for ClauseDatabase {
fn index_mut(&mut self, offset: usize) -> &mut Literal {
&mut self.data[offset]
}
}
#[derive(Debug, PartialEq, HeapSpace)]
pub struct WitnessDatabase {
data: Vector<Literal>,
offset: Vector<usize>,
}
impl ClauseStorage for WitnessDatabase {
fn open_clause(&mut self) -> Clause {
self.offset.pop();
let witness = Clause::from_usize(self.offset.len());
self.offset.push(self.data.len());
witness
}
fn push_literal(&mut self, literal: Literal, _verbose: bool) {
if literal.is_zero() {
self.close_witness();
} else {
self.data.push(literal);
}
}
}
impl Default for WitnessDatabase {
fn default() -> WitnessDatabase {
let mut db = WitnessDatabase {
data: Vector::new(),
offset: Vector::new(),
};
db.offset.push(0);
db
}
}
impl WitnessDatabase {
#[cfg(test)]
pub fn from(data: Vector<Literal>, offset: Vector<usize>) -> WitnessDatabase {
WitnessDatabase { data, offset }
}
fn close_witness(&mut self) {
self.offset.push(self.data.len())
}
pub fn witness_to_string(&self, clause: Clause) -> String {
format!(
"Witness for [{}]:{} 0",
clause,
self.witness(clause)
.iter()
.map(|&literal| format!(" {}", literal))
.collect::<Vec<_>>()
.join("")
)
}
pub fn witness(&self, clause: Clause) -> &[Literal] {
&self.data[self.witness_range(clause)]
}
pub fn witness_range(&self, clause: Clause) -> Range<usize> {
self.offset[clause.as_offset()]..self.offset[clause.as_offset() + 1]
}
pub fn shrink_to_fit(&mut self) {
self.data.push(Literal::new(0));
self.data.shrink_to_fit();
self.data.pop();
self.offset.push(0);
self.offset.shrink_to_fit();
self.offset.pop();
}
}
impl Index<usize> for WitnessDatabase {
type Output = Literal;
fn index(&self, offset: usize) -> &Literal {
&self.data[offset]
}
}
impl IndexMut<usize> for WitnessDatabase {
fn index_mut(&mut self, offset: usize) -> &mut Literal {
&mut self.data[offset]
}
}
fn is_size_1_clause(clause: &[Literal]) -> bool {
clause.len() == 2 && (clause[0] == Literal::BOTTOM || clause[1] == Literal::BOTTOM)
}
fn sort_clause(clause: &mut [Literal]) {
let _sort_literally = |&literal: &Literal| literal.decode();
let _sort_magnitude = |&literal: &Literal| literal.encoding;
clause.sort_unstable_by_key(_sort_literally);
}