use std::ops::Not;
use crate::{
clause,
types::{
constraints::{CardConstraint, PbConstraint},
Clause, Lit,
},
};
#[must_use]
pub fn lit_impl_lit(a: Lit, b: Lit) -> Clause {
clause![!a, b]
}
#[must_use]
pub fn lit_impl_clause(a: Lit, b: &[Lit]) -> Clause {
let mut cl = Clause::from(b);
cl.add(!a);
cl
}
#[must_use]
pub fn cube_impl_lit(a: &[Lit], b: Lit) -> Clause {
let mut cl: Clause = a.iter().copied().map(Not::not).collect();
cl.add(b);
cl
}
#[must_use]
pub fn cube_impl_clause(a: &[Lit], b: &[Lit]) -> Clause {
let mut cl = Clause::from(b);
cl.extend(a.iter().copied().map(Not::not));
cl
}
pub fn lit_impl_cube(a: Lit, b: &[Lit]) -> impl Iterator<Item = Clause> + '_ {
b.iter().map(move |bi| clause![!a, *bi])
}
pub fn clause_impl_lit(a: &[Lit], b: Lit) -> impl Iterator<Item = Clause> + '_ {
a.iter().map(move |ai| clause![!*ai, b])
}
pub fn clause_impl_clause<'all>(
a: &'all [Lit],
b: &'all [Lit],
) -> impl Iterator<Item = Clause> + 'all {
a.iter().map(move |ai| {
let mut cl = Clause::from(b);
cl.add(!*ai);
cl
})
}
pub fn clause_impl_cube<'all>(
a: &'all [Lit],
b: &'all [Lit],
) -> impl Iterator<Item = Clause> + 'all {
a.iter()
.flat_map(move |ai| b.iter().map(|bi| clause![!*ai, *bi]))
}
pub fn cube_impl_cube<'all>(a: &'all [Lit], b: &'all [Lit]) -> impl Iterator<Item = Clause> + 'all {
b.iter().map(move |bi| {
let mut cl: Clause = a.iter().copied().map(Not::not).collect();
cl.add(*bi);
cl
})
}
#[must_use]
pub fn lit_impl_card(lit: Lit, card: &CardConstraint) -> PbConstraint {
assert!(
!card.is_unsat(),
"the constraint must be satisfiable to reify it: {card}"
);
match card {
CardConstraint::Ub(c) => {
let (lits, bound) = c.decompose_ref();
let bound = lits.len() + bound;
let mut lits: Vec<_> = lits.iter().map(|lit| (*lit, 1)).collect();
lits.push((lit, lits.len()));
PbConstraint::new_ub_unsigned(
lits,
isize::try_from(bound).expect("cannot handle bounds larger than `isize::MAX`"),
)
}
CardConstraint::Lb(c) => {
let (lits, bound) = c.decompose_ref();
let mut lits: Vec<_> = lits.iter().map(|lit| (*lit, 1)).collect();
lits.push((!lit, *bound));
PbConstraint::new_lb_unsigned(
lits,
isize::try_from(*bound).expect("cannot handle bounds larger than `isize::MAX`"),
)
}
CardConstraint::Eq(_) => panic!("equality constraint cannot be trivially reified"),
}
}
#[must_use]
pub fn card_impl_lit(card: &CardConstraint, lit: Lit) -> PbConstraint {
assert!(
!card.is_unsat(),
"the constraint must be satisfiable to reify it: {card}"
);
match card {
CardConstraint::Ub(c) => {
let (lits, bound) = c.decompose_ref();
let bound = 2 * lits.len() - bound - 1;
let mut lits: Vec<_> = lits.iter().map(|lit| (!*lit, 1)).collect();
lits.push((!lit, lits.len()));
PbConstraint::new_ub_unsigned(
lits,
isize::try_from(bound).expect("cannot handle bounds larger than `isize::MAX`"),
)
}
CardConstraint::Lb(c) => {
let (lits, bound) = c.decompose_ref();
let bound = lits.len() - bound + 1;
let mut lits: Vec<_> = lits.iter().map(|lit| (!*lit, 1)).collect();
lits.push((lit, bound));
PbConstraint::new_lb_unsigned(
lits,
isize::try_from(bound).expect("cannot handle bounds larger than `isize::MAX`"),
)
}
CardConstraint::Eq(_) => panic!("equality constraint cannot be trivially reified"),
}
}
#[must_use]
pub fn lit_impl_pb(lit: Lit, pb: &PbConstraint) -> PbConstraint {
assert!(
!pb.is_unsat(),
"the constraint must be satisfiable to reify it: {pb}"
);
let mut pb = pb.clone();
match pb {
PbConstraint::Ub(_) => {
let ws = isize::try_from(pb.weight_sum())
.expect("cannot handle sums of weight larger than `isize::MAX`");
pb.add([(lit, ws)]);
pb.set_bound(pb.bound() + ws);
}
PbConstraint::Lb(_) => {
pb.add([(!lit, pb.bound())]);
}
PbConstraint::Eq(_) => panic!("equality constraint cannot be trivially reified"),
}
pb
}
#[must_use]
pub fn pb_impl_lit(pb: &PbConstraint, lit: Lit) -> PbConstraint {
assert!(
!pb.is_unsat(),
"the constraint must be satisfiable to reify it: {pb}"
);
match pb {
PbConstraint::Ub(c) => {
let ws = isize::try_from(pb.weight_sum())
.expect("cannot handle sums of weight larger than `isize::MAX`");
let (lits, bound) = c.decompose_ref();
let bound = 2 * ws - bound - 1;
let mut lits: Vec<_> = lits.iter().map(|(lit, w)| (!*lit, *w)).collect();
lits.push((!lit, pb.weight_sum()));
PbConstraint::new_ub_unsigned(lits, bound)
}
PbConstraint::Lb(c) => {
let ws = isize::try_from(pb.weight_sum())
.expect("cannot handle sums of weight larger than `isize::MAX`");
let (lits, bound) = c.decompose_ref();
let bound = ws - bound + 1;
let mut lits: Vec<_> = lits
.iter()
.map(|(lit, w)| (!*lit, isize::try_from(*w).unwrap()))
.collect();
lits.push((lit, bound));
PbConstraint::new_lb(lits, bound)
}
PbConstraint::Eq(_) => panic!("equality constraint cannot be trivially reified"),
}
}