use std::marker::PhantomData;
use super::VarId;
use super::space::{Local, Original, Reduced, Space};
use crate::error::VitriError;
pub struct ShowSet<S: Space>(Vec<u32>, PhantomData<S>);
impl<S: Space> ShowSet<S> {
pub fn empty() -> Self {
ShowSet(Vec::new(), PhantomData)
}
pub fn from_dimacs_ids(ids: &[u32]) -> Result<Self, VitriError> {
let mut vars = Vec::with_capacity(ids.len());
for &id in ids {
let var = id.checked_sub(1).ok_or_else(|| {
VitriError::input("0 is not a show variable (it terminates a `c p show` line)")
})?;
vars.push(var);
}
Ok(Self::from_zero_based(vars))
}
pub fn from_zero_based(vars: impl IntoIterator<Item = u32>) -> Self {
let mut vars: Vec<u32> = vars.into_iter().collect();
vars.sort_unstable();
vars.dedup();
ShowSet(vars, PhantomData)
}
pub fn contains(&self, var: VarId) -> bool {
self.0.binary_search(&var.0).is_ok()
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn iter_vars(&self) -> impl ExactSizeIterator<Item = VarId> + '_ {
self.0.iter().map(|&v| VarId(v))
}
pub fn as_zero_based(&self) -> &[u32] {
&self.0
}
pub fn to_dimacs(&self) -> Vec<u32> {
self.0.iter().map(|&v| v + 1).collect()
}
pub fn mask(&self, num_vars: u32) -> ShowMask {
let mut bits = vec![false; num_vars as usize];
for &v in &self.0 {
if let Some(slot) = bits.get_mut(v as usize) {
*slot = true;
}
}
ShowMask(bits)
}
pub fn insert(&mut self, var: VarId) {
if let Err(at) = self.0.binary_search(&var.0) {
self.0.insert(at, var.0);
}
}
pub fn remove(&mut self, var: VarId) {
if let Ok(at) = self.0.binary_search(&var.0) {
self.0.remove(at);
}
}
}
impl ShowSet<Original> {
pub(crate) fn assume_reduced_identity(self) -> ShowSet<Reduced> {
ShowSet(self.0, PhantomData)
}
}
impl<S: Space> Clone for ShowSet<S> {
fn clone(&self) -> Self {
ShowSet(self.0.clone(), PhantomData)
}
}
impl<S: Space> std::fmt::Debug for ShowSet<S> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("ShowSet").field(&self.0).finish()
}
}
impl<S: Space> PartialEq for ShowSet<S> {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl<S: Space> Eq for ShowSet<S> {}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct ShowMask(Vec<bool>);
impl ShowMask {
pub fn is_show(&self, var: VarId) -> bool {
self.0.get(var.idx()).copied().unwrap_or(false)
}
pub fn as_slice(&self) -> &[bool] {
&self.0
}
pub fn count(&self) -> usize {
self.0.iter().filter(|&&b| b).count()
}
pub fn restrict(&self, local_to_global: &[VarId]) -> ShowSet<Local> {
ShowSet(
local_to_global
.iter()
.enumerate()
.filter(|&(_, &global)| self.is_show(global))
.map(|(local, _)| local as u32)
.collect(),
PhantomData,
)
}
}
pub(crate) mod dimacs {
use super::{ShowSet, Space};
use serde::de::Error as _;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
pub(crate) fn serialize<S: Space, Ser: Serializer>(
set: &Option<ShowSet<S>>,
ser: Ser,
) -> Result<Ser::Ok, Ser::Error> {
set.as_ref().map(ShowSet::to_dimacs).serialize(ser)
}
pub(crate) fn deserialize<'de, S: Space, D: Deserializer<'de>>(
de: D,
) -> Result<Option<ShowSet<S>>, D::Error> {
match Option::<Vec<u32>>::deserialize(de)? {
Some(ids) => ShowSet::from_dimacs_ids(&ids)
.map(Some)
.map_err(D::Error::custom),
None => Ok(None),
}
}
}