use std::{
collections::{BTreeMap, BTreeSet},
fmt::{Debug, Display},
};
use derive_more::derive::{AsRef, Deref, DerefMut, From};
use itertools::Itertools;
use crate::{
common::{Arrow, Imply, KnownTagState, Tag, TagKnowledge, Vector},
dnf::{BooleanLike, Conjunction, SignedLitteral},
};
pub trait StateTrait {
fn get_tag_knowledge(&self, tag: &Tag) -> TagKnowledge;
fn height(&self) -> usize;
}
#[derive(PartialEq, Eq, Deref, Clone, DerefMut, PartialOrd, Ord, AsRef, From)]
pub struct EffectiveState(BTreeMap<Tag, KnownTagState>);
#[derive(Debug)]
pub enum EffectiveStateError {
FalseValue,
}
impl EffectiveState {
pub fn try_from_conjunction(conj: Conjunction<Tag>) -> Result<Self, EffectiveStateError> {
if conj.is_true() {
Ok(BTreeMap::new().into())
} else if conj.is_false() {
Err(EffectiveStateError::FalseValue)
} else {
Ok(conj
.iter()
.map(|x| match x {
SignedLitteral::Val { litteral, sign } => (litteral.clone(), sign.as_other()),
_ => unreachable!(),
})
.collect::<BTreeMap<_, _>>()
.into())
}
}
pub fn compute_vector(&self, other: &Self) -> Arrow {
let vector = Vector::from(
other
.iter()
.filter_map(|(t, s)| {
if self.get(t).is_some_and(|v| v == s) {
None
} else {
Some((t.clone(), s.as_other()))
}
})
.collect::<BTreeMap<_, _>>(),
);
Arrow {
source: self.clone(),
vector,
}
}
pub fn as_query(&self) -> String {
self.iter()
.map(|(t, ts)| format!("({}tag:{})", if ts.as_bool() { "" } else { "not " }, t))
.join(" and ")
}
}
impl Debug for EffectiveState {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Debug::fmt(&Conjunction::from(self.clone()), f)
}
}
impl From<EffectiveState> for Conjunction<Tag> {
fn from(value: EffectiveState) -> Self {
value
.iter()
.map(|(t, s)| <SignedLitteral<Tag>>::from((t.clone(), s.clone())))
.collect::<BTreeSet<_>>()
.into()
}
}
impl StateTrait for EffectiveState {
fn get_tag_knowledge(&self, tag: &Tag) -> TagKnowledge {
self.get(tag).map(|s| (*s).into()).unwrap_or_default()
}
fn height(&self) -> usize {
self.0.len()
}
}
impl Display for EffectiveState {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", Conjunction::from(self.clone()).to_string())
}
}
impl Imply for EffectiveState {
fn implies(&self, other: &EffectiveState) -> bool {
other
.iter()
.all(|(t, s)| self.get(t).is_some_and(|ss| ss == s))
}
}