use serde::{Deserialize, Serialize};
use std::{fmt::Display, ops::Deref};
use crate::adfbiodivine::AdfOperations;
#[derive(Debug, Eq, PartialEq, PartialOrd, Ord, Hash, Copy, Clone, Serialize, Deserialize)]
pub struct Term(pub usize);
impl Deref for Term {
type Target = usize;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl From<usize> for Term {
fn from(val: usize) -> Self {
Self(val)
}
}
impl From<bool> for Term {
fn from(val: bool) -> Self {
if val {
Self::TOP
} else {
Self::BOT
}
}
}
impl From<&biodivine_lib_bdd::Bdd> for Term {
fn from(val: &biodivine_lib_bdd::Bdd) -> Self {
if val.is_true() {
Term::TOP
} else if val.is_false() {
Term::BOT
} else {
Term::UND
}
}
}
impl Display for Term {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Term({})", self.0)
}
}
impl Term {
pub const BOT: Term = Term(0);
pub const TOP: Term = Term(1);
pub const UND: Term = Term(2);
pub fn value(self) -> usize {
self.0
}
pub fn is_truth_value(&self) -> bool {
self.0 <= Term::TOP.0
}
pub fn is_true(&self) -> bool {
*self == Self::TOP
}
pub fn compare_inf(&self, other: &Self) -> bool {
self.is_truth_value() == other.is_truth_value() && self.is_true() == other.is_true()
}
pub fn no_inf_inconsistency(&self, other: &Self) -> bool {
if self.compare_inf(other) {
return true;
}
!self.is_truth_value()
}
pub fn cmp_information(&self, other: &biodivine_lib_bdd::Bdd) -> bool {
self.is_truth_value() == other.is_truth_value() && self.is_true() == other.is_true()
}
}
#[derive(Debug, Eq, PartialEq, PartialOrd, Ord, Hash, Clone, Copy, Serialize, Deserialize)]
pub struct Var(pub usize);
impl Deref for Var {
type Target = usize;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl From<usize> for Var {
fn from(val: usize) -> Self {
Self(val)
}
}
impl Display for Var {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Var({})", self.0)
}
}
impl Var {
pub const TOP: Var = Var(usize::MAX);
pub const BOT: Var = Var(usize::MAX - 1);
pub fn value(self) -> usize {
self.0
}
pub fn is_constant(&self) -> bool {
self.value() >= Var::BOT.value()
}
}
#[derive(Debug, Eq, PartialEq, PartialOrd, Ord, Hash, Clone, Copy, Serialize, Deserialize)]
pub(crate) struct BddNode {
var: Var,
lo: Term,
hi: Term,
}
impl Display for BddNode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "BddNode: {}, lo: {}, hi: {}", self.var, self.lo, self.hi)
}
}
impl BddNode {
pub fn new(var: Var, lo: Term, hi: Term) -> Self {
Self { var, lo, hi }
}
pub fn var(self) -> Var {
self.var
}
pub fn lo(self) -> Term {
self.lo
}
pub fn hi(self) -> Term {
self.hi
}
pub fn bot_node() -> Self {
Self {
var: Var::BOT,
lo: Term::BOT,
hi: Term::BOT,
}
}
pub fn top_node() -> Self {
Self {
var: Var::TOP,
lo: Term::TOP,
hi: Term::TOP,
}
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord)]
pub struct ModelCounts {
pub cmodels: usize,
pub models: usize,
}
impl ModelCounts {
pub fn top() -> ModelCounts {
(0, 1).into()
}
pub fn bot() -> ModelCounts {
(1, 0).into()
}
pub fn minimum(&self) -> usize {
self.models.min(self.cmodels)
}
pub fn more_models(&self) -> bool {
self.models >= self.minimum()
}
}
impl From<(usize, usize)> for ModelCounts {
fn from(tuple: (usize, usize)) -> Self {
ModelCounts {
cmodels: tuple.0,
models: tuple.1,
}
}
}
pub type CountNode = (ModelCounts, ModelCounts, usize);
pub type FacetCounts = (usize, usize);
#[cfg(test)]
mod test {
use super::*;
use quickcheck_macros::quickcheck;
use test_log::test;
#[test]
fn cmp() {
assert!(!Term::BOT.compare_inf(&Term::TOP));
assert!(!Term::TOP.compare_inf(&Term::BOT));
assert!(!Term::TOP.compare_inf(&Term(22)));
assert!(!Term(22).compare_inf(&Term::BOT));
assert!(Term(22).compare_inf(&Term(12323)));
assert!(Term::TOP.compare_inf(&Term::TOP));
assert!(Term::BOT.compare_inf(&Term::BOT));
assert!(Term(22).compare_inf(&Term(22)));
}
#[quickcheck]
fn deref_display_from(value: usize) -> bool {
let term: Term = Term::from(value);
let var = Var::from(value);
assert_eq!(format!("{}", term), format!("Term({})", value));
assert_eq!(format!("{}", var), format!("Var({})", value));
assert_eq!(value, *term);
true
}
#[quickcheck]
fn bdd_node(var: usize, lo: usize, hi: usize) -> bool {
let node = BddNode::new(Var::from(var), Term::from(lo), Term::from(hi));
assert_eq!(*node.var(), var);
assert_eq!(*node.lo(), lo);
assert_eq!(*node.hi(), hi);
match node.var() {
Var::TOP => {
assert!(node.var().is_constant());
}
Var::BOT => {
assert!(node.var().is_constant());
}
val => {
assert!(!val.is_constant());
}
}
true
}
}