use super::Adf;
use crate::datatypes::{Term, Var};
use rand::{Rng, RngCore};
use strum::{EnumString, EnumVariantNames};
pub type RetVal = Option<(Var, Term)>;
pub type HeuristicFn = dyn Fn(&Adf, &[Term]) -> RetVal + Sync;
pub(crate) fn heu_simple(_adf: &Adf, interpr: &[Term]) -> Option<(Var, Term)> {
for (idx, term) in interpr.iter().enumerate() {
if !term.is_truth_value() {
return Some((Var(idx), Term::TOP));
}
}
None
}
pub(crate) fn heu_mc_minpaths_maxvarimp(adf: &Adf, interpr: &[Term]) -> Option<(Var, Term)> {
interpr
.iter()
.enumerate()
.filter(|(_var, term)| !term.is_truth_value())
.min_by(|(vara, &terma), (varb, &termb)| {
match adf
.bdd
.paths(terma, true)
.minimum()
.cmp(&adf.bdd.paths(termb, true).minimum())
{
std::cmp::Ordering::Equal => adf
.bdd
.passive_var_impact(Var::from(*vara), interpr)
.cmp(&adf.bdd.passive_var_impact(Var::from(*varb), interpr)),
value => value,
}
})
.map(|(var, term)| {
(
Var::from(var),
adf.bdd.paths(*term, true).more_models().into(),
)
})
}
pub(crate) fn heu_mc_maxvarimp_minpaths(adf: &Adf, interpr: &[Term]) -> Option<(Var, Term)> {
interpr
.iter()
.enumerate()
.filter(|(_var, term)| !term.is_truth_value())
.min_by(|(vara, &terma), (varb, &termb)| {
match adf
.bdd
.passive_var_impact(Var::from(*vara), interpr)
.cmp(&adf.bdd.passive_var_impact(Var::from(*varb), interpr))
{
std::cmp::Ordering::Equal => adf
.bdd
.paths(terma, true)
.minimum()
.cmp(&adf.bdd.paths(termb, true).minimum()),
value => value,
}
})
.map(|(var, term)| {
(
Var::from(var),
adf.bdd.paths(*term, true).more_models().into(),
)
})
}
pub(crate) fn heu_rand(adf: &Adf, interpr: &[Term]) -> Option<(Var, Term)> {
let possible = interpr
.iter()
.enumerate()
.filter(|(_var, term)| !term.is_truth_value())
.collect::<Vec<_>>();
if possible.is_empty() {
return None;
}
let mut rng = adf.rng.borrow_mut();
if let Ok(position) = usize::try_from(rng.next_u64() % (possible.len() as u64)) {
Some((Var::from(position), rng.gen_bool(0.5).into()))
} else {
None
}
}
#[derive(EnumString, EnumVariantNames, Copy, Clone)]
pub enum Heuristic<'a> {
Simple,
MinModMinPathsMaxVarImp,
MinModMaxVarImpMinPaths,
Rand,
#[strum(disabled)]
Custom(&'a HeuristicFn),
}
impl Default for Heuristic<'_> {
fn default() -> Self {
Self::Simple
}
}
impl std::fmt::Debug for Heuristic<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Simple => write!(f, "Simple"),
Self::MinModMinPathsMaxVarImp => write!(f, "Maximal model-path count as value and minimum paths with maximal variable impact as variable choice"),
Self::MinModMaxVarImpMinPaths => write!(f, "Maximal model-path count as value and maximal variable impact with minimum paths as variable choice"),
Self::Rand => write!(f, "Random heuristics"),
Self::Custom(_) => f.debug_tuple("Custom function").finish(),
}
}
}
impl Heuristic<'_> {
pub(crate) fn get_heuristic(&self) -> &(dyn Fn(&Adf, &[Term]) -> RetVal + '_) {
match self {
Heuristic::Simple => &heu_simple,
Heuristic::MinModMinPathsMaxVarImp => &heu_mc_minpaths_maxvarimp,
Heuristic::MinModMaxVarImpMinPaths => &heu_mc_maxvarimp_minpaths,
Heuristic::Rand => &heu_rand,
Self::Custom(f) => f,
}
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::datatypes::Term;
use crate::datatypes::Var;
#[test]
fn debug_out() {
dbg!(Heuristic::Simple);
dbg!(Heuristic::MinModMaxVarImpMinPaths);
dbg!(Heuristic::MinModMinPathsMaxVarImp);
dbg!(Heuristic::Rand);
dbg!(Heuristic::Custom(&|_adf: &Adf,
_int: &[Term]|
-> Option<(Var, Term)> { None }));
}
}