use std::collections::BTreeSet;
use std::fmt;
use super::symbols::{PredicateSymbol, VariableSymbol};
use super::term::Term;
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Atom {
pub predicate: PredicateSymbol,
pub terms: Vec<Term>,
}
impl Atom {
#[must_use]
pub fn arity(&self) -> usize {
self.terms.len()
}
#[must_use]
pub(super) fn variables(&self) -> BTreeSet<VariableSymbol> {
let mut acc = BTreeSet::new();
self.collect_variables(&mut acc);
acc
}
fn collect_variables(&self, acc: &mut BTreeSet<VariableSymbol>) {
for term in &self.terms {
collect_term_variables(term, acc);
}
}
#[must_use]
pub(super) fn contains_skolem(&self) -> bool {
self.terms.iter().any(term_contains_skolem)
}
#[must_use]
pub(super) fn nesting_depth(&self) -> usize {
self.terms
.iter()
.map(Term::nesting_depth)
.max()
.unwrap_or(0)
}
}
fn collect_term_variables(term: &Term, acc: &mut BTreeSet<VariableSymbol>) {
match term {
Term::Variable(var) => {
acc.insert(var.clone());
}
Term::Constant(_) => {}
Term::TripleTerm(inner) => {
for child in &inner.terms {
collect_term_variables(child, acc);
}
}
Term::Skolem { args, .. } => {
for arg in args {
collect_term_variables(arg, acc);
}
}
}
}
fn term_contains_skolem(term: &Term) -> bool {
match term {
Term::Skolem { .. } => true,
Term::TripleTerm(inner) => inner.terms.iter().any(term_contains_skolem),
Term::Variable(_) | Term::Constant(_) => false,
}
}
impl fmt::Display for Atom {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}(", self.predicate.as_str())?;
for (idx, term) in self.terms.iter().enumerate() {
if idx > 0 {
write!(f, ", ")?;
}
write!(f, "{term}")?;
}
write!(f, ")")
}
}