use std::fmt::Display;
use std::hash::{BuildHasher, Hash};
use nanorand::Rng;
use crate::util::num::F64;
use crate::util::{
AllocResult, Borrowed, EdgeDropGuard, NodeSet, OptBool, SatCountCache, SatCountNumber,
Substitution,
};
use crate::{DiagramRules, Edge, InnerNode, LevelNo, Manager, ManagerRef, Node, VarNo};
pub type EdgeOfFunc<'id, F> = <<F as Function>::Manager<'id> as Manager>::Edge;
pub type ETagOfFunc<'id, F> = <<F as Function>::Manager<'id> as Manager>::EdgeTag;
pub type INodeOfFunc<'id, F> = <<F as Function>::Manager<'id> as Manager>::InnerNode;
pub type TermOfFunc<'id, F> = <<F as Function>::Manager<'id> as Manager>::Terminal;
pub unsafe trait Function: Clone + Ord + Hash {
const REPR_ID: &str;
type Manager<'id>: Manager;
type ManagerRef: for<'id> ManagerRef<Manager<'id> = Self::Manager<'id>>;
fn from_edge<'id>(manager: &Self::Manager<'id>, edge: EdgeOfFunc<'id, Self>) -> Self;
#[inline(always)]
fn from_edge_ref<'id>(manager: &Self::Manager<'id>, edge: &EdgeOfFunc<'id, Self>) -> Self {
Self::from_edge(manager, manager.clone_edge(edge))
}
fn as_edge<'id>(&self, manager: &Self::Manager<'id>) -> &EdgeOfFunc<'id, Self>;
fn into_edge<'id>(self, manager: &Self::Manager<'id>) -> EdgeOfFunc<'id, Self>;
fn manager_ref(&self) -> Self::ManagerRef;
fn with_manager_shared<F, T>(&self, f: F) -> T
where
F: for<'id> FnOnce(&Self::Manager<'id>, &EdgeOfFunc<'id, Self>) -> T;
fn with_manager_exclusive<F, T>(&self, f: F) -> T
where
F: for<'id> FnOnce(&mut Self::Manager<'id>, &EdgeOfFunc<'id, Self>) -> T;
fn node_count(&self) -> usize {
fn inner<M: Manager>(manager: &M, e: &M::Edge, set: &mut M::NodeSet) {
if set.insert(e) {
if let Node::Inner(node) = manager.get_node(e) {
for e in node.children() {
inner(manager, &*e, set)
}
}
}
}
self.with_manager_shared(|manager, edge| {
let mut set = Default::default();
inner(manager, edge, &mut set);
set.len()
})
}
}
pub trait FunctionSubst: Function {
fn substitute<'a>(
&'a self,
substitution: impl Substitution<Replacement = &'a Self>,
) -> AllocResult<Self> {
if substitution.pairs().len() == 0 {
return Ok(self.clone());
}
self.with_manager_shared(|manager, edge| {
Ok(Self::from_edge(
manager,
Self::substitute_edge(
manager,
edge,
substitution.map(|(v, r)| (v, r.as_edge(manager).borrowed())),
)?,
))
})
}
#[must_use]
fn substitute_edge<'id, 'a>(
manager: &'a Self::Manager<'id>,
edge: &'a EdgeOfFunc<'id, Self>,
substitution: impl Substitution<Replacement = Borrowed<'a, EdgeOfFunc<'id, Self>>>,
) -> AllocResult<EdgeOfFunc<'id, Self>>;
}
pub trait BooleanFunction: Function {
fn f<'id>(manager: &Self::Manager<'id>) -> Self {
Self::from_edge(manager, Self::f_edge(manager))
}
fn t<'id>(manager: &Self::Manager<'id>) -> Self {
Self::from_edge(manager, Self::t_edge(manager))
}
fn var<'id>(manager: &Self::Manager<'id>, var: VarNo) -> AllocResult<Self> {
Ok(Self::from_edge(manager, Self::var_edge(manager, var)?))
}
fn not_var<'id>(manager: &Self::Manager<'id>, var: VarNo) -> AllocResult<Self> {
Ok(Self::from_edge(manager, Self::not_var_edge(manager, var)?))
}
fn cofactors(&self) -> Option<(Self, Self)> {
self.with_manager_shared(|manager, f| {
let (ft, ff) = Self::cofactors_edge(manager, f)?;
Some((
Self::from_edge_ref(manager, &ft),
Self::from_edge_ref(manager, &ff),
))
})
}
fn cofactor_true(&self) -> Option<Self> {
self.with_manager_shared(|manager, f| {
let (ft, _) = Self::cofactors_edge(manager, f)?;
Some(Self::from_edge_ref(manager, &ft))
})
}
fn cofactor_false(&self) -> Option<Self> {
self.with_manager_shared(|manager, f| {
let (_, ff) = Self::cofactors_edge(manager, f)?;
Some(Self::from_edge_ref(manager, &ff))
})
}
fn not(&self) -> AllocResult<Self> {
self.with_manager_shared(|manager, edge| {
Ok(Self::from_edge(manager, Self::not_edge(manager, edge)?))
})
}
fn not_owned(self) -> AllocResult<Self> {
self.not()
}
fn and(&self, rhs: &Self) -> AllocResult<Self> {
self.with_manager_shared(|manager, lhs| {
let e = Self::and_edge(manager, lhs, rhs.as_edge(manager))?;
Ok(Self::from_edge(manager, e))
})
}
fn or(&self, rhs: &Self) -> AllocResult<Self> {
self.with_manager_shared(|manager, lhs| {
let e = Self::or_edge(manager, lhs, rhs.as_edge(manager))?;
Ok(Self::from_edge(manager, e))
})
}
fn nand(&self, rhs: &Self) -> AllocResult<Self> {
self.with_manager_shared(|manager, lhs| {
let e = Self::nand_edge(manager, lhs, rhs.as_edge(manager))?;
Ok(Self::from_edge(manager, e))
})
}
fn nor(&self, rhs: &Self) -> AllocResult<Self> {
self.with_manager_shared(|manager, lhs| {
let e = Self::nor_edge(manager, lhs, rhs.as_edge(manager))?;
Ok(Self::from_edge(manager, e))
})
}
fn xor(&self, rhs: &Self) -> AllocResult<Self> {
self.with_manager_shared(|manager, lhs| {
let e = Self::xor_edge(manager, lhs, rhs.as_edge(manager))?;
Ok(Self::from_edge(manager, e))
})
}
fn equiv(&self, rhs: &Self) -> AllocResult<Self> {
self.with_manager_shared(|manager, lhs| {
let e = Self::equiv_edge(manager, lhs, rhs.as_edge(manager))?;
Ok(Self::from_edge(manager, e))
})
}
fn imp(&self, rhs: &Self) -> AllocResult<Self> {
self.with_manager_shared(|manager, lhs| {
let e = Self::imp_edge(manager, lhs, rhs.as_edge(manager))?;
Ok(Self::from_edge(manager, e))
})
}
fn imp_strict(&self, rhs: &Self) -> AllocResult<Self> {
self.with_manager_shared(|manager, lhs| {
let e = Self::imp_strict_edge(manager, lhs, rhs.as_edge(manager))?;
Ok(Self::from_edge(manager, e))
})
}
fn f_edge<'id>(manager: &Self::Manager<'id>) -> EdgeOfFunc<'id, Self>;
fn t_edge<'id>(manager: &Self::Manager<'id>) -> EdgeOfFunc<'id, Self>;
fn var_edge<'id>(
manager: &Self::Manager<'id>,
var: VarNo,
) -> AllocResult<EdgeOfFunc<'id, Self>>;
fn not_var_edge<'id>(
manager: &Self::Manager<'id>,
var: VarNo,
) -> AllocResult<EdgeOfFunc<'id, Self>> {
Self::not_edge_owned(manager, Self::var_edge(manager, var)?)
}
#[inline]
#[allow(clippy::type_complexity)]
fn cofactors_edge<'a, 'id>(
manager: &'a Self::Manager<'id>,
f: &'a EdgeOfFunc<'id, Self>,
) -> Option<(
Borrowed<'a, EdgeOfFunc<'id, Self>>,
Borrowed<'a, EdgeOfFunc<'id, Self>>,
)> {
if let Node::Inner(node) = manager.get_node(f) {
Some(Self::cofactors_node(f.tag(), node))
} else {
None
}
}
#[inline]
fn cofactors_node<'a, 'id>(
tag: ETagOfFunc<'id, Self>,
node: &'a INodeOfFunc<'id, Self>,
) -> (
Borrowed<'a, EdgeOfFunc<'id, Self>>,
Borrowed<'a, EdgeOfFunc<'id, Self>>,
) {
let cofactor = <<Self::Manager<'id> as Manager>::Rules as DiagramRules<_, _, _>>::cofactor;
(cofactor(tag, node, 0), cofactor(tag, node, 1))
}
#[must_use]
fn not_edge<'id>(
manager: &Self::Manager<'id>,
edge: &EdgeOfFunc<'id, Self>,
) -> AllocResult<EdgeOfFunc<'id, Self>>;
#[must_use]
fn not_edge_owned<'id>(
manager: &Self::Manager<'id>,
edge: EdgeOfFunc<'id, Self>,
) -> AllocResult<EdgeOfFunc<'id, Self>> {
let edge = EdgeDropGuard::new(manager, edge);
Self::not_edge(manager, &edge)
}
#[must_use]
fn and_edge<'id>(
manager: &Self::Manager<'id>,
lhs: &EdgeOfFunc<'id, Self>,
rhs: &EdgeOfFunc<'id, Self>,
) -> AllocResult<EdgeOfFunc<'id, Self>>;
#[must_use]
fn or_edge<'id>(
manager: &Self::Manager<'id>,
lhs: &EdgeOfFunc<'id, Self>,
rhs: &EdgeOfFunc<'id, Self>,
) -> AllocResult<EdgeOfFunc<'id, Self>>;
#[must_use]
fn nand_edge<'id>(
manager: &Self::Manager<'id>,
lhs: &EdgeOfFunc<'id, Self>,
rhs: &EdgeOfFunc<'id, Self>,
) -> AllocResult<EdgeOfFunc<'id, Self>>;
#[must_use]
fn nor_edge<'id>(
manager: &Self::Manager<'id>,
lhs: &EdgeOfFunc<'id, Self>,
rhs: &EdgeOfFunc<'id, Self>,
) -> AllocResult<EdgeOfFunc<'id, Self>>;
#[must_use]
fn xor_edge<'id>(
manager: &Self::Manager<'id>,
lhs: &EdgeOfFunc<'id, Self>,
rhs: &EdgeOfFunc<'id, Self>,
) -> AllocResult<EdgeOfFunc<'id, Self>>;
#[must_use]
fn equiv_edge<'id>(
manager: &Self::Manager<'id>,
lhs: &EdgeOfFunc<'id, Self>,
rhs: &EdgeOfFunc<'id, Self>,
) -> AllocResult<EdgeOfFunc<'id, Self>>;
#[must_use]
fn imp_edge<'id>(
manager: &Self::Manager<'id>,
lhs: &EdgeOfFunc<'id, Self>,
rhs: &EdgeOfFunc<'id, Self>,
) -> AllocResult<EdgeOfFunc<'id, Self>>;
#[must_use]
fn imp_strict_edge<'id>(
manager: &Self::Manager<'id>,
lhs: &EdgeOfFunc<'id, Self>,
rhs: &EdgeOfFunc<'id, Self>,
) -> AllocResult<EdgeOfFunc<'id, Self>>;
fn satisfiable(&self) -> bool {
self.with_manager_shared(|manager, edge| {
let f = EdgeDropGuard::new(manager, Self::f_edge(manager));
edge != &*f
})
}
fn valid(&self) -> bool {
self.with_manager_shared(|manager, edge| {
let t = EdgeDropGuard::new(manager, Self::t_edge(manager));
edge == &*t
})
}
fn ite(&self, then_case: &Self, else_case: &Self) -> AllocResult<Self> {
self.with_manager_shared(|manager, if_edge| {
let then_edge = then_case.as_edge(manager);
let else_edge = else_case.as_edge(manager);
let res = Self::ite_edge(manager, if_edge, then_edge, else_edge)?;
Ok(Self::from_edge(manager, res))
})
}
#[must_use]
fn ite_edge<'id>(
manager: &Self::Manager<'id>,
if_edge: &EdgeOfFunc<'id, Self>,
then_edge: &EdgeOfFunc<'id, Self>,
else_edge: &EdgeOfFunc<'id, Self>,
) -> AllocResult<EdgeOfFunc<'id, Self>> {
let f = EdgeDropGuard::new(manager, Self::and_edge(manager, if_edge, then_edge)?);
let g = EdgeDropGuard::new(manager, Self::imp_strict_edge(manager, if_edge, else_edge)?);
Self::or_edge(manager, &*f, &*g)
}
fn sat_count<N: SatCountNumber, S: std::hash::BuildHasher>(
&self,
vars: LevelNo,
cache: &mut SatCountCache<N, S>,
) -> N {
self.with_manager_shared(|manager, edge| Self::sat_count_edge(manager, edge, vars, cache))
}
fn sat_count_edge<'id, N: SatCountNumber, S: std::hash::BuildHasher>(
manager: &Self::Manager<'id>,
edge: &EdgeOfFunc<'id, Self>,
vars: LevelNo,
cache: &mut SatCountCache<N, S>,
) -> N;
fn pick_cube(
&self,
choice: impl for<'id> FnMut(&Self::Manager<'id>, &EdgeOfFunc<'id, Self>, LevelNo) -> bool,
) -> Option<Vec<OptBool>> {
self.with_manager_shared(|manager, edge| Self::pick_cube_edge(manager, edge, choice))
}
fn pick_cube_dd(
&self,
choice: impl for<'id> FnMut(&Self::Manager<'id>, &EdgeOfFunc<'id, Self>, LevelNo) -> bool,
) -> AllocResult<Self> {
self.with_manager_shared(|manager, edge| {
let res = Self::pick_cube_dd_edge(manager, edge, choice)?;
Ok(Self::from_edge(manager, res))
})
}
fn pick_cube_dd_set(&self, literal_set: &Self) -> AllocResult<Self> {
self.with_manager_shared(|manager, edge| {
let res = Self::pick_cube_dd_set_edge(manager, edge, literal_set.as_edge(manager))?;
Ok(Self::from_edge(manager, res))
})
}
fn pick_cube_edge<'id>(
manager: &Self::Manager<'id>,
edge: &EdgeOfFunc<'id, Self>,
choice: impl FnMut(&Self::Manager<'id>, &EdgeOfFunc<'id, Self>, LevelNo) -> bool,
) -> Option<Vec<OptBool>>;
fn pick_cube_dd_edge<'id>(
manager: &Self::Manager<'id>,
edge: &EdgeOfFunc<'id, Self>,
choice: impl FnMut(&Self::Manager<'id>, &EdgeOfFunc<'id, Self>, LevelNo) -> bool,
) -> AllocResult<EdgeOfFunc<'id, Self>>;
fn pick_cube_dd_set_edge<'id>(
manager: &Self::Manager<'id>,
edge: &EdgeOfFunc<'id, Self>,
literal_set: &EdgeOfFunc<'id, Self>,
) -> AllocResult<EdgeOfFunc<'id, Self>>;
fn pick_cube_uniform<S: BuildHasher>(
&self,
cache: &mut SatCountCache<F64, S>,
rng: &mut crate::util::Rng,
) -> Option<Vec<OptBool>> {
self.with_manager_shared(|manager, edge| {
Self::pick_cube_uniform_edge(manager, edge, cache, rng)
})
}
fn pick_cube_uniform_edge<'id, S: BuildHasher>(
manager: &Self::Manager<'id>,
edge: &EdgeOfFunc<'id, Self>,
cache: &mut SatCountCache<F64, S>,
rng: &mut crate::util::Rng,
) -> Option<Vec<OptBool>> {
let vars = manager.num_levels();
Self::pick_cube_edge(manager, edge, |manager, edge, _| {
let tag = edge.tag();
let node = manager.get_node(edge).unwrap_inner();
let (t, e) = Self::cofactors_node(tag, node);
let t_count = Self::sat_count_edge(manager, &*t, vars, cache).0;
let e_count = Self::sat_count_edge(manager, &*e, vars, cache).0;
rng.generate::<f64>() < t_count / (t_count + e_count)
})
}
fn eval(&self, args: impl IntoIterator<Item = (VarNo, bool)>) -> bool {
self.with_manager_shared(|manager, edge| Self::eval_edge(manager, edge, args))
}
fn eval_edge<'id>(
manager: &Self::Manager<'id>,
edge: &EdgeOfFunc<'id, Self>,
args: impl IntoIterator<Item = (VarNo, bool)>,
) -> bool;
}
#[cfg_attr(
all(),
doc = "
The operators are used by the combined apply and quantification operations of
the [`BooleanFunctionQuant`] trait. The operators themselves correspond to the
ones defined in [`BooleanFunction`]."
)]
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[repr(u8)]
pub enum BooleanOperator {
And,
Or,
Xor,
Equiv,
Nand,
Nor,
Imp,
ImpStrict,
}
unsafe impl crate::Countable for BooleanOperator {
const MAX_VALUE: usize = BooleanOperator::ImpStrict as usize;
fn as_usize(self) -> usize {
self as usize
}
fn from_usize(value: usize) -> Self {
use BooleanOperator::*;
match () {
_ if value == And as usize => And,
_ if value == Or as usize => Or,
_ if value == Xor as usize => Xor,
_ if value == Equiv as usize => Equiv,
_ if value == Nand as usize => Nand,
_ if value == Nor as usize => Nor,
_ if value == Imp as usize => Imp,
_ if value == ImpStrict as usize => ImpStrict,
_ => panic!("{value} does not correspond to a Boolean operator"),
}
}
}
impl Display for BooleanOperator {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use BooleanOperator::*;
match self {
And => write!(f, "∧"),
Or => write!(f, "∨"),
Xor => write!(f, "⊕"),
Equiv => write!(f, "↔"),
Nand => write!(f, "⊼"),
Nor => write!(f, "⊽"),
Imp => write!(f, "→"),
ImpStrict => write!(f, "<"),
}
}
}
pub trait BooleanFunctionQuant: BooleanFunction {
fn restrict(&self, vars: &Self) -> AllocResult<Self> {
self.with_manager_shared(|manager, root| {
let e = Self::restrict_edge(manager, root, vars.as_edge(manager))?;
Ok(Self::from_edge(manager, e))
})
}
fn forall(&self, vars: &Self) -> AllocResult<Self> {
self.with_manager_shared(|manager, root| {
let e = Self::forall_edge(manager, root, vars.as_edge(manager))?;
Ok(Self::from_edge(manager, e))
})
}
fn exists(&self, vars: &Self) -> AllocResult<Self> {
self.with_manager_shared(|manager, root| {
let e = Self::exists_edge(manager, root, vars.as_edge(manager))?;
Ok(Self::from_edge(manager, e))
})
}
#[deprecated]
fn exist(&self, vars: &Self) -> AllocResult<Self> {
self.exists(vars)
}
fn unique(&self, vars: &Self) -> AllocResult<Self> {
self.with_manager_shared(|manager, root| {
let e = Self::unique_edge(manager, root, vars.as_edge(manager))?;
Ok(Self::from_edge(manager, e))
})
}
fn apply_forall(&self, op: BooleanOperator, rhs: &Self, vars: &Self) -> AllocResult<Self> {
self.with_manager_shared(|manager, root| {
let e = Self::apply_forall_edge(
manager,
op,
root,
rhs.as_edge(manager),
vars.as_edge(manager),
)?;
Ok(Self::from_edge(manager, e))
})
}
fn apply_exists(&self, op: BooleanOperator, rhs: &Self, vars: &Self) -> AllocResult<Self> {
self.with_manager_shared(|manager, root| {
let e = Self::apply_exists_edge(
manager,
op,
root,
rhs.as_edge(manager),
vars.as_edge(manager),
)?;
Ok(Self::from_edge(manager, e))
})
}
#[deprecated]
#[must_use]
fn apply_exist(&self, op: BooleanOperator, rhs: &Self, vars: &Self) -> AllocResult<Self> {
self.apply_exists(op, rhs, vars)
}
fn apply_unique(&self, op: BooleanOperator, rhs: &Self, vars: &Self) -> AllocResult<Self> {
self.with_manager_shared(|manager, root| {
let e = Self::apply_unique_edge(
manager,
op,
root,
rhs.as_edge(manager),
vars.as_edge(manager),
)?;
Ok(Self::from_edge(manager, e))
})
}
#[must_use]
fn restrict_edge<'id>(
manager: &Self::Manager<'id>,
root: &EdgeOfFunc<'id, Self>,
vars: &EdgeOfFunc<'id, Self>,
) -> AllocResult<EdgeOfFunc<'id, Self>>;
#[must_use]
fn forall_edge<'id>(
manager: &Self::Manager<'id>,
root: &EdgeOfFunc<'id, Self>,
vars: &EdgeOfFunc<'id, Self>,
) -> AllocResult<EdgeOfFunc<'id, Self>>;
#[must_use]
fn exists_edge<'id>(
manager: &Self::Manager<'id>,
root: &EdgeOfFunc<'id, Self>,
vars: &EdgeOfFunc<'id, Self>,
) -> AllocResult<EdgeOfFunc<'id, Self>>;
#[must_use]
#[deprecated]
fn exist_edge<'id>(
manager: &Self::Manager<'id>,
root: &EdgeOfFunc<'id, Self>,
vars: &EdgeOfFunc<'id, Self>,
) -> AllocResult<EdgeOfFunc<'id, Self>> {
Self::exists_edge(manager, root, vars)
}
#[must_use]
fn unique_edge<'id>(
manager: &Self::Manager<'id>,
root: &EdgeOfFunc<'id, Self>,
vars: &EdgeOfFunc<'id, Self>,
) -> AllocResult<EdgeOfFunc<'id, Self>>;
#[must_use]
fn apply_forall_edge<'id>(
manager: &Self::Manager<'id>,
op: BooleanOperator,
lhs: &EdgeOfFunc<'id, Self>,
rhs: &EdgeOfFunc<'id, Self>,
vars: &EdgeOfFunc<'id, Self>,
) -> AllocResult<EdgeOfFunc<'id, Self>> {
use BooleanOperator::*;
let inner = EdgeDropGuard::new(
manager,
match op {
And => Self::and_edge(manager, lhs, rhs),
Or => Self::or_edge(manager, lhs, rhs),
Xor => Self::xor_edge(manager, lhs, rhs),
Equiv => Self::equiv_edge(manager, lhs, rhs),
Nand => Self::nand_edge(manager, lhs, rhs),
Nor => Self::nor_edge(manager, lhs, rhs),
Imp => Self::imp_edge(manager, lhs, rhs),
ImpStrict => Self::imp_strict_edge(manager, lhs, rhs),
}?,
);
Self::forall_edge(manager, &inner, vars)
}
#[must_use]
fn apply_exists_edge<'id>(
manager: &Self::Manager<'id>,
op: BooleanOperator,
lhs: &EdgeOfFunc<'id, Self>,
rhs: &EdgeOfFunc<'id, Self>,
vars: &EdgeOfFunc<'id, Self>,
) -> AllocResult<EdgeOfFunc<'id, Self>> {
use BooleanOperator::*;
let inner = EdgeDropGuard::new(
manager,
match op {
And => Self::and_edge(manager, lhs, rhs),
Or => Self::or_edge(manager, lhs, rhs),
Xor => Self::xor_edge(manager, lhs, rhs),
Equiv => Self::equiv_edge(manager, lhs, rhs),
Nand => Self::nand_edge(manager, lhs, rhs),
Nor => Self::nor_edge(manager, lhs, rhs),
Imp => Self::imp_edge(manager, lhs, rhs),
ImpStrict => Self::imp_strict_edge(manager, lhs, rhs),
}?,
);
Self::exists_edge(manager, &inner, vars)
}
#[deprecated]
#[must_use]
fn apply_exist_edge<'id>(
manager: &Self::Manager<'id>,
op: BooleanOperator,
lhs: &EdgeOfFunc<'id, Self>,
rhs: &EdgeOfFunc<'id, Self>,
vars: &EdgeOfFunc<'id, Self>,
) -> AllocResult<EdgeOfFunc<'id, Self>> {
Self::apply_exists_edge(manager, op, lhs, rhs, vars)
}
#[must_use]
fn apply_unique_edge<'id>(
manager: &Self::Manager<'id>,
op: BooleanOperator,
lhs: &EdgeOfFunc<'id, Self>,
rhs: &EdgeOfFunc<'id, Self>,
vars: &EdgeOfFunc<'id, Self>,
) -> AllocResult<EdgeOfFunc<'id, Self>> {
use BooleanOperator::*;
let inner = EdgeDropGuard::new(
manager,
match op {
And => Self::and_edge(manager, lhs, rhs),
Or => Self::or_edge(manager, lhs, rhs),
Xor => Self::xor_edge(manager, lhs, rhs),
Equiv => Self::equiv_edge(manager, lhs, rhs),
Nand => Self::nand_edge(manager, lhs, rhs),
Nor => Self::nor_edge(manager, lhs, rhs),
Imp => Self::imp_edge(manager, lhs, rhs),
ImpStrict => Self::imp_strict_edge(manager, lhs, rhs),
}?,
);
Self::unique_edge(manager, &inner, vars)
}
}
pub trait BooleanVecSet: Function {
fn singleton<'id>(manager: &Self::Manager<'id>, var: VarNo) -> AllocResult<Self> {
Ok(Self::from_edge(
manager,
Self::singleton_edge(manager, var)?,
))
}
fn empty<'id>(manager: &Self::Manager<'id>) -> Self {
Self::from_edge(manager, Self::empty_edge(manager))
}
fn base<'id>(manager: &Self::Manager<'id>) -> Self {
Self::from_edge(manager, Self::base_edge(manager))
}
fn subset0(&self, var: VarNo) -> AllocResult<Self> {
self.with_manager_shared(|manager, set| {
let e = Self::subset0_edge(manager, set, var)?;
Ok(Self::from_edge(manager, e))
})
}
fn subset1(&self, var: VarNo) -> AllocResult<Self> {
self.with_manager_shared(|manager, set| {
let e = Self::subset1_edge(manager, set, var)?;
Ok(Self::from_edge(manager, e))
})
}
fn change(&self, var: VarNo) -> AllocResult<Self> {
self.with_manager_shared(|manager, set| {
let e = Self::change_edge(manager, set, var)?;
Ok(Self::from_edge(manager, e))
})
}
fn union(&self, rhs: &Self) -> AllocResult<Self> {
self.with_manager_shared(|manager, lhs| {
let e = Self::union_edge(manager, lhs, rhs.as_edge(manager))?;
Ok(Self::from_edge(manager, e))
})
}
fn intsec(&self, rhs: &Self) -> AllocResult<Self> {
self.with_manager_shared(|manager, lhs| {
let e = Self::intsec_edge(manager, lhs, rhs.as_edge(manager))?;
Ok(Self::from_edge(manager, e))
})
}
fn diff(&self, rhs: &Self) -> AllocResult<Self> {
self.with_manager_shared(|manager, lhs| {
let e = Self::diff_edge(manager, lhs, rhs.as_edge(manager))?;
Ok(Self::from_edge(manager, e))
})
}
fn singleton_edge<'id>(
manager: &Self::Manager<'id>,
var: VarNo,
) -> AllocResult<EdgeOfFunc<'id, Self>>;
fn empty_edge<'id>(manager: &Self::Manager<'id>) -> EdgeOfFunc<'id, Self>;
fn base_edge<'id>(manager: &Self::Manager<'id>) -> EdgeOfFunc<'id, Self>;
fn subset0_edge<'id>(
manager: &Self::Manager<'id>,
set: &EdgeOfFunc<'id, Self>,
var: VarNo,
) -> AllocResult<EdgeOfFunc<'id, Self>>;
fn subset1_edge<'id>(
manager: &Self::Manager<'id>,
set: &EdgeOfFunc<'id, Self>,
var: VarNo,
) -> AllocResult<EdgeOfFunc<'id, Self>>;
fn change_edge<'id>(
manager: &Self::Manager<'id>,
set: &EdgeOfFunc<'id, Self>,
var: VarNo,
) -> AllocResult<EdgeOfFunc<'id, Self>>;
fn union_edge<'id>(
manager: &Self::Manager<'id>,
lhs: &EdgeOfFunc<'id, Self>,
rhs: &EdgeOfFunc<'id, Self>,
) -> AllocResult<EdgeOfFunc<'id, Self>>;
fn intsec_edge<'id>(
manager: &Self::Manager<'id>,
lhs: &EdgeOfFunc<'id, Self>,
rhs: &EdgeOfFunc<'id, Self>,
) -> AllocResult<EdgeOfFunc<'id, Self>>;
fn diff_edge<'id>(
manager: &Self::Manager<'id>,
lhs: &EdgeOfFunc<'id, Self>,
rhs: &EdgeOfFunc<'id, Self>,
) -> AllocResult<EdgeOfFunc<'id, Self>>;
}
pub trait NumberBase: Clone + Eq + Hash + PartialOrd {
fn zero() -> Self;
fn one() -> Self;
fn nan() -> Self;
fn is_zero(&self) -> bool {
self == &Self::zero()
}
fn is_one(&self) -> bool {
self == &Self::one()
}
fn is_nan(&self) -> bool {
self == &Self::nan()
}
fn add(&self, rhs: &Self) -> Self;
fn sub(&self, rhs: &Self) -> Self;
fn mul(&self, rhs: &Self) -> Self;
fn div(&self, rhs: &Self) -> Self;
}
pub trait PseudoBooleanFunction: Function {
type Number: NumberBase;
fn constant<'id>(manager: &Self::Manager<'id>, value: Self::Number) -> AllocResult<Self> {
Ok(Self::from_edge(
manager,
Self::constant_edge(manager, value)?,
))
}
fn var<'id>(manager: &Self::Manager<'id>, var: VarNo) -> AllocResult<Self> {
Ok(Self::from_edge(manager, Self::var_edge(manager, var)?))
}
fn add(&self, rhs: &Self) -> AllocResult<Self> {
self.with_manager_shared(|manager, lhs| {
let e = Self::add_edge(manager, lhs, rhs.as_edge(manager))?;
Ok(Self::from_edge(manager, e))
})
}
fn sub(&self, rhs: &Self) -> AllocResult<Self> {
self.with_manager_shared(|manager, lhs| {
let e = Self::sub_edge(manager, lhs, rhs.as_edge(manager))?;
Ok(Self::from_edge(manager, e))
})
}
fn mul(&self, rhs: &Self) -> AllocResult<Self> {
self.with_manager_shared(|manager, lhs| {
let e = Self::mul_edge(manager, lhs, rhs.as_edge(manager))?;
Ok(Self::from_edge(manager, e))
})
}
fn div(&self, rhs: &Self) -> AllocResult<Self> {
self.with_manager_shared(|manager, lhs| {
let e = Self::div_edge(manager, lhs, rhs.as_edge(manager))?;
Ok(Self::from_edge(manager, e))
})
}
fn min(&self, rhs: &Self) -> AllocResult<Self> {
self.with_manager_shared(|manager, lhs| {
let e = Self::min_edge(manager, lhs, rhs.as_edge(manager))?;
Ok(Self::from_edge(manager, e))
})
}
fn max(&self, rhs: &Self) -> AllocResult<Self> {
self.with_manager_shared(|manager, lhs| {
let e = Self::max_edge(manager, lhs, rhs.as_edge(manager))?;
Ok(Self::from_edge(manager, e))
})
}
fn constant_edge<'id>(
manager: &Self::Manager<'id>,
value: Self::Number,
) -> AllocResult<EdgeOfFunc<'id, Self>>;
fn var_edge<'id>(
manager: &Self::Manager<'id>,
var: VarNo,
) -> AllocResult<EdgeOfFunc<'id, Self>>;
fn add_edge<'id>(
manager: &Self::Manager<'id>,
lhs: &EdgeOfFunc<'id, Self>,
rhs: &EdgeOfFunc<'id, Self>,
) -> AllocResult<EdgeOfFunc<'id, Self>>;
fn sub_edge<'id>(
manager: &Self::Manager<'id>,
lhs: &EdgeOfFunc<'id, Self>,
rhs: &EdgeOfFunc<'id, Self>,
) -> AllocResult<EdgeOfFunc<'id, Self>>;
fn mul_edge<'id>(
manager: &Self::Manager<'id>,
lhs: &EdgeOfFunc<'id, Self>,
rhs: &EdgeOfFunc<'id, Self>,
) -> AllocResult<EdgeOfFunc<'id, Self>>;
fn div_edge<'id>(
manager: &Self::Manager<'id>,
lhs: &EdgeOfFunc<'id, Self>,
rhs: &EdgeOfFunc<'id, Self>,
) -> AllocResult<EdgeOfFunc<'id, Self>>;
fn min_edge<'id>(
manager: &Self::Manager<'id>,
lhs: &EdgeOfFunc<'id, Self>,
rhs: &EdgeOfFunc<'id, Self>,
) -> AllocResult<EdgeOfFunc<'id, Self>>;
fn max_edge<'id>(
manager: &Self::Manager<'id>,
lhs: &EdgeOfFunc<'id, Self>,
rhs: &EdgeOfFunc<'id, Self>,
) -> AllocResult<EdgeOfFunc<'id, Self>>;
fn eval(&self, args: impl IntoIterator<Item = (VarNo, bool)>) -> Self::Number {
self.with_manager_shared(|manager, edge| Self::eval_edge(manager, edge, args))
}
fn eval_edge<'id>(
manager: &Self::Manager<'id>,
edge: &EdgeOfFunc<'id, Self>,
args: impl IntoIterator<Item = (VarNo, bool)>,
) -> Self::Number;
}
pub trait TVLFunction: Function {
fn f<'id>(manager: &Self::Manager<'id>) -> Self {
Self::from_edge(manager, Self::f_edge(manager))
}
fn t<'id>(manager: &Self::Manager<'id>) -> Self {
Self::from_edge(manager, Self::t_edge(manager))
}
fn u<'id>(manager: &Self::Manager<'id>) -> Self {
Self::from_edge(manager, Self::t_edge(manager))
}
fn cofactors(&self) -> Option<(Self, Self, Self)> {
self.with_manager_shared(|manager, f| {
let (ft, fu, ff) = Self::cofactors_edge(manager, f)?;
Some((
Self::from_edge_ref(manager, &ft),
Self::from_edge_ref(manager, &fu),
Self::from_edge_ref(manager, &ff),
))
})
}
fn cofactor_true(&self) -> Option<Self> {
self.with_manager_shared(|manager, f| {
let (ft, _, _) = Self::cofactors_edge(manager, f)?;
Some(Self::from_edge_ref(manager, &ft))
})
}
fn cofactor_unknown(&self) -> Option<Self> {
self.with_manager_shared(|manager, f| {
let (_, fu, _) = Self::cofactors_edge(manager, f)?;
Some(Self::from_edge_ref(manager, &fu))
})
}
fn cofactor_false(&self) -> Option<Self> {
self.with_manager_shared(|manager, f| {
let (_, _, ff) = Self::cofactors_edge(manager, f)?;
Some(Self::from_edge_ref(manager, &ff))
})
}
fn var<'id>(manager: &Self::Manager<'id>, var: VarNo) -> AllocResult<Self> {
Ok(Self::from_edge(manager, Self::var_edge(manager, var)?))
}
fn not(&self) -> AllocResult<Self> {
self.with_manager_shared(|manager, edge| {
Ok(Self::from_edge(manager, Self::not_edge(manager, edge)?))
})
}
fn not_owned(self) -> AllocResult<Self> {
self.not()
}
fn and(&self, rhs: &Self) -> AllocResult<Self> {
self.with_manager_shared(|manager, lhs| {
let e = Self::and_edge(manager, lhs, rhs.as_edge(manager))?;
Ok(Self::from_edge(manager, e))
})
}
fn or(&self, rhs: &Self) -> AllocResult<Self> {
self.with_manager_shared(|manager, lhs| {
let e = Self::or_edge(manager, lhs, rhs.as_edge(manager))?;
Ok(Self::from_edge(manager, e))
})
}
fn nand(&self, rhs: &Self) -> AllocResult<Self> {
self.with_manager_shared(|manager, lhs| {
let e = Self::nand_edge(manager, lhs, rhs.as_edge(manager))?;
Ok(Self::from_edge(manager, e))
})
}
fn nor(&self, rhs: &Self) -> AllocResult<Self> {
self.with_manager_shared(|manager, lhs| {
let e = Self::nor_edge(manager, lhs, rhs.as_edge(manager))?;
Ok(Self::from_edge(manager, e))
})
}
fn xor(&self, rhs: &Self) -> AllocResult<Self> {
self.with_manager_shared(|manager, lhs| {
let e = Self::xor_edge(manager, lhs, rhs.as_edge(manager))?;
Ok(Self::from_edge(manager, e))
})
}
fn equiv(&self, rhs: &Self) -> AllocResult<Self> {
self.with_manager_shared(|manager, lhs| {
let e = Self::equiv_edge(manager, lhs, rhs.as_edge(manager))?;
Ok(Self::from_edge(manager, e))
})
}
fn imp(&self, rhs: &Self) -> AllocResult<Self> {
self.with_manager_shared(|manager, lhs| {
let e = Self::imp_edge(manager, lhs, rhs.as_edge(manager))?;
Ok(Self::from_edge(manager, e))
})
}
fn imp_strict(&self, rhs: &Self) -> AllocResult<Self> {
self.with_manager_shared(|manager, lhs| {
let e = Self::imp_strict_edge(manager, lhs, rhs.as_edge(manager))?;
Ok(Self::from_edge(manager, e))
})
}
fn f_edge<'id>(manager: &Self::Manager<'id>) -> EdgeOfFunc<'id, Self>;
fn t_edge<'id>(manager: &Self::Manager<'id>) -> EdgeOfFunc<'id, Self>;
fn u_edge<'id>(manager: &Self::Manager<'id>) -> EdgeOfFunc<'id, Self>;
#[inline]
#[allow(clippy::type_complexity)]
fn cofactors_edge<'a, 'id>(
manager: &'a Self::Manager<'id>,
f: &'a EdgeOfFunc<'id, Self>,
) -> Option<(
Borrowed<'a, EdgeOfFunc<'id, Self>>,
Borrowed<'a, EdgeOfFunc<'id, Self>>,
Borrowed<'a, EdgeOfFunc<'id, Self>>,
)> {
if let Node::Inner(node) = manager.get_node(f) {
Some(Self::cofactors_node(f.tag(), node))
} else {
None
}
}
#[inline]
#[allow(clippy::type_complexity)]
fn cofactors_node<'a, 'id>(
tag: ETagOfFunc<'id, Self>,
node: &'a INodeOfFunc<'id, Self>,
) -> (
Borrowed<'a, EdgeOfFunc<'id, Self>>,
Borrowed<'a, EdgeOfFunc<'id, Self>>,
Borrowed<'a, EdgeOfFunc<'id, Self>>,
) {
let cofactor = <<Self::Manager<'id> as Manager>::Rules as DiagramRules<_, _, _>>::cofactor;
(
cofactor(tag, node, 0),
cofactor(tag, node, 1),
cofactor(tag, node, 2),
)
}
fn var_edge<'id>(
manager: &Self::Manager<'id>,
var: VarNo,
) -> AllocResult<EdgeOfFunc<'id, Self>>;
#[must_use]
fn not_edge<'id>(
manager: &Self::Manager<'id>,
edge: &EdgeOfFunc<'id, Self>,
) -> AllocResult<EdgeOfFunc<'id, Self>>;
#[must_use]
fn not_edge_owned<'id>(
manager: &Self::Manager<'id>,
edge: EdgeOfFunc<'id, Self>,
) -> AllocResult<EdgeOfFunc<'id, Self>> {
Self::not_edge(manager, &edge)
}
#[must_use]
fn and_edge<'id>(
manager: &Self::Manager<'id>,
lhs: &EdgeOfFunc<'id, Self>,
rhs: &EdgeOfFunc<'id, Self>,
) -> AllocResult<EdgeOfFunc<'id, Self>>;
#[must_use]
fn or_edge<'id>(
manager: &Self::Manager<'id>,
lhs: &EdgeOfFunc<'id, Self>,
rhs: &EdgeOfFunc<'id, Self>,
) -> AllocResult<EdgeOfFunc<'id, Self>>;
#[must_use]
fn nand_edge<'id>(
manager: &Self::Manager<'id>,
lhs: &EdgeOfFunc<'id, Self>,
rhs: &EdgeOfFunc<'id, Self>,
) -> AllocResult<EdgeOfFunc<'id, Self>>;
#[must_use]
fn nor_edge<'id>(
manager: &Self::Manager<'id>,
lhs: &EdgeOfFunc<'id, Self>,
rhs: &EdgeOfFunc<'id, Self>,
) -> AllocResult<EdgeOfFunc<'id, Self>>;
#[must_use]
fn xor_edge<'id>(
manager: &Self::Manager<'id>,
lhs: &EdgeOfFunc<'id, Self>,
rhs: &EdgeOfFunc<'id, Self>,
) -> AllocResult<EdgeOfFunc<'id, Self>>;
#[must_use]
fn equiv_edge<'id>(
manager: &Self::Manager<'id>,
lhs: &EdgeOfFunc<'id, Self>,
rhs: &EdgeOfFunc<'id, Self>,
) -> AllocResult<EdgeOfFunc<'id, Self>>;
#[must_use]
fn imp_edge<'id>(
manager: &Self::Manager<'id>,
lhs: &EdgeOfFunc<'id, Self>,
rhs: &EdgeOfFunc<'id, Self>,
) -> AllocResult<EdgeOfFunc<'id, Self>>;
#[must_use]
fn imp_strict_edge<'id>(
manager: &Self::Manager<'id>,
lhs: &EdgeOfFunc<'id, Self>,
rhs: &EdgeOfFunc<'id, Self>,
) -> AllocResult<EdgeOfFunc<'id, Self>>;
fn ite(&self, then_case: &Self, else_case: &Self) -> AllocResult<Self> {
self.with_manager_shared(|manager, if_edge| {
let then_edge = then_case.as_edge(manager);
let else_edge = else_case.as_edge(manager);
let res = Self::ite_edge(manager, if_edge, then_edge, else_edge)?;
Ok(Self::from_edge(manager, res))
})
}
#[must_use]
fn ite_edge<'id>(
manager: &Self::Manager<'id>,
if_edge: &EdgeOfFunc<'id, Self>,
then_edge: &EdgeOfFunc<'id, Self>,
else_edge: &EdgeOfFunc<'id, Self>,
) -> AllocResult<EdgeOfFunc<'id, Self>> {
let f = EdgeDropGuard::new(manager, Self::and_edge(manager, if_edge, then_edge)?);
let g = EdgeDropGuard::new(manager, Self::imp_strict_edge(manager, if_edge, else_edge)?);
Self::or_edge(manager, &*f, &*g)
}
fn eval(&self, args: impl IntoIterator<Item = (VarNo, Option<bool>)>) -> Option<bool> {
self.with_manager_shared(|manager, edge| Self::eval_edge(manager, edge, args))
}
fn eval_edge<'id>(
manager: &Self::Manager<'id>,
edge: &EdgeOfFunc<'id, Self>,
args: impl IntoIterator<Item = (VarNo, Option<bool>)>,
) -> Option<bool>;
}