pub(super) const NO_BAG: u32 = u32::MAX;
#[derive(Clone, Debug)]
pub struct BagMetadata {
num_vars: u32,
var_bag: Vec<u32>,
bag_rank: Vec<u32>,
treewidth: u32,
}
impl BagMetadata {
pub(super) fn from_assignment(
num_vars: u32,
var_bag_usize: &[usize],
bfs_order: &[usize],
num_bags: usize,
treewidth: u32,
) -> Self {
debug_assert_eq!(
bfs_order.len(),
num_bags,
"BagMetadata::from_assignment: BFS order must cover every bag exactly once",
);
let mut bag_rank = vec![0u32; num_bags];
let n = bfs_order.len();
for (i, &bag) in bfs_order.iter().enumerate() {
bag_rank[bag] = (n - 1 - i) as u32;
}
let var_bag: Vec<u32> = var_bag_usize
.iter()
.map(|&b| if b == usize::MAX { NO_BAG } else { b as u32 })
.collect();
debug_assert_eq!(var_bag.len(), num_vars as usize);
Self {
num_vars,
var_bag,
bag_rank,
treewidth,
}
}
pub fn num_vars(&self) -> u32 {
self.num_vars
}
pub fn num_bags(&self) -> u32 {
self.bag_rank.len() as u32
}
pub fn treewidth(&self) -> u32 {
self.treewidth
}
pub fn var_bag(&self, v: u32) -> Option<u32> {
match self.var_bag.get(v as usize) {
Some(&b) if b != NO_BAG => Some(b),
_ => None,
}
}
pub fn var_bag_rank(&self, v: u32) -> Option<u32> {
self.var_bag(v).map(|b| self.bag_rank[b as usize])
}
pub fn clause_bag_rank(&self, vars: impl IntoIterator<Item = u32>) -> Option<u32> {
vars.into_iter().filter_map(|v| self.var_bag_rank(v)).max()
}
}