anthem 2.0.0

A command-line application for assisting in the verification of answer set programs
Documentation
use crate::{
    convenience::apply::Apply as _,
    syntax_tree::fol::sigma_0::{
        AtomicFormula, BinaryConnective, Formula, Theory, UnaryConnective,
    },
};

pub trait Gamma {
    fn gamma(self) -> Self;
}

impl Gamma for Theory {
    fn gamma(self) -> Self {
        self.into_iter().map(Gamma::gamma).collect()
    }
}

impl Gamma for Formula {
    fn gamma(self) -> Self {
        match self {
            x @ Formula::AtomicFormula(_) => x.here(),

            Formula::UnaryFormula {
                connective: connective @ UnaryConnective::Negation,
                formula,
            } => Formula::UnaryFormula {
                connective,
                formula: formula.there().into(),
            },

            Formula::BinaryFormula {
                connective:
                    connective @ BinaryConnective::Conjunction
                    | connective @ BinaryConnective::Disjunction,
                lhs,
                rhs,
            } => Formula::BinaryFormula {
                connective,
                lhs: lhs.gamma().into(),
                rhs: rhs.gamma().into(),
            },

            Formula::BinaryFormula {
                connective:
                    connective @ BinaryConnective::Implication
                    | connective @ BinaryConnective::ReverseImplication
                    | connective @ BinaryConnective::Equivalence,
                lhs,
                rhs,
            } => Formula::BinaryFormula {
                connective: BinaryConnective::Conjunction,
                lhs: Formula::BinaryFormula {
                    connective: connective.clone(),
                    lhs: lhs.clone().gamma().into(),
                    rhs: rhs.clone().gamma().into(),
                }
                .into(),
                rhs: Formula::BinaryFormula {
                    connective,
                    lhs: lhs.there().into(),
                    rhs: rhs.there().into(),
                }
                .into(),
            },

            Formula::QuantifiedFormula {
                quantification,
                formula,
            } => Formula::QuantifiedFormula {
                quantification,
                formula: formula.gamma().into(),
            },
        }
    }
}

pub trait Here {
    fn here(self) -> Self;
}

impl Here for Formula {
    fn here(self) -> Self {
        prepend_predicate(self, "h")
    }
}

pub trait There {
    fn there(self) -> Self;
}

impl There for Formula {
    fn there(self) -> Self {
        prepend_predicate(self, "t")
    }
}

fn prepend_predicate(formula: Formula, prefix: &'static str) -> Formula {
    formula.apply(&mut |formula| match formula {
        Formula::AtomicFormula(AtomicFormula::Atom(mut a)) => {
            a.predicate_symbol.insert_str(0, prefix);
            Formula::AtomicFormula(AtomicFormula::Atom(a))
        }
        x => x,
    })
}

#[cfg(test)]
mod tests {
    use {super::Gamma as _, crate::syntax_tree::fol::sigma_0::Formula};

    #[test]
    fn test_gamma() {
        for (src, target) in [
            ("#true", "#true"),
            ("a", "ha"),
            ("a(a)", "ha(a)"),
            ("X > 1", "X > 1"),
            ("not a", "not ta"),
            ("not X > 1", "not X > 1"),
            ("a and not b", "ha and not tb"),
            ("a or not b", "ha or not tb"),
            ("a -> b", "(ha -> hb) and (ta -> tb)"),
            ("a <- b", "(ha <- hb) and (ta <- tb)"),
            ("a <-> b", "(ha <-> hb) and (ta <-> tb)"),
            ("forall X p(X)", "forall X hp(X)"),
            ("exists X p(X)", "exists X hp(X)"),
        ] {
            let left = src.parse::<Formula>().unwrap().gamma();
            let right = target.parse().unwrap();

            assert!(
                left == right,
                "assertion `left == right` failed:\n left:\n{left}\n right:\n{right}"
            );
        }
    }
}