use crate::cnf::VarId;
use crate::cnf::{Clause, CnfFormula, Literal};
#[derive(Clone, Debug)]
pub(crate) struct Renumber {
to_new: Vec<Option<VarId>>,
to_old: Vec<VarId>,
}
impl Renumber {
pub(crate) fn keeping(num_old_vars: usize, keep: impl Fn(VarId) -> bool) -> Self {
Renumber::of_kept(
num_old_vars,
(0..num_old_vars as u32).map(VarId).filter(|&v| keep(v)),
)
}
pub(crate) fn of_kept(num_old_vars: usize, kept: impl IntoIterator<Item = VarId>) -> Self {
let mut to_new: Vec<Option<VarId>> = vec![None; num_old_vars];
let mut to_old: Vec<VarId> = Vec::new();
for old in kept {
debug_assert!(
old.idx() < num_old_vars,
"kept variable {old:?} is not a variable of the old formula",
);
debug_assert!(
to_old.last().is_none_or(|prev| prev.0 < old.0),
"kept variables must be strictly ascending, got {old:?} after {:?}",
to_old.last(),
);
to_new[old.idx()] = Some(VarId(to_old.len() as u32));
to_old.push(old);
}
Renumber { to_new, to_old }
}
pub(crate) fn num_old_vars(&self) -> usize {
self.to_new.len()
}
pub(crate) fn num_new_vars(&self) -> u32 {
self.to_old.len() as u32
}
pub(crate) fn new_id(&self, old: VarId) -> Option<VarId> {
self.to_new.get(old.idx()).copied().flatten()
}
pub(crate) fn old_id(&self, new: VarId) -> VarId {
self.to_old[new.idx()]
}
pub(crate) fn kept(&self) -> &[VarId] {
&self.to_old
}
pub(crate) fn compose(&self, inner: &Renumber) -> Renumber {
debug_assert_eq!(
inner.num_old_vars(),
self.num_new_vars() as usize,
"`inner` must renumber the new space this renumbering produced",
);
Renumber::of_kept(
self.num_old_vars(),
inner.kept().iter().map(|&mid| self.old_id(mid)),
)
}
pub(crate) fn apply_lit(&self, lit: Literal) -> Option<Literal> {
self.new_id(lit.var).map(|v| Literal::new(v, lit.positive))
}
pub(crate) fn apply_inverse_lit(&self, lit: Literal) -> Literal {
Literal::new(self.old_id(lit.var), lit.positive)
}
}
pub(crate) fn renumber_clauses(
num_old_vars: usize,
clauses: Vec<Clause>,
keep: impl Fn(VarId) -> bool,
) -> (CnfFormula, Renumber) {
let renumbering = Renumber::keeping(num_old_vars, keep);
let mut new_clauses: Vec<Clause> = Vec::with_capacity(clauses.len());
let mut unsat = false;
for clause in clauses {
let new_lits: Vec<Literal> = clause
.literals
.iter()
.filter_map(|&lit| renumbering.apply_lit(lit))
.collect();
if new_lits.is_empty() {
unsat = true;
} else {
new_clauses.push(Clause::new(new_lits));
}
}
if unsat {
new_clauses.push(Clause::new(Vec::new()));
}
let formula = CnfFormula {
num_vars: renumbering.num_new_vars(),
clauses: new_clauses,
};
(formula, renumbering)
}