datalog_structural_model/ir/
atom.rs1use std::collections::BTreeSet;
4use std::fmt;
5
6use super::symbols::{PredicateSymbol, VariableSymbol};
7use super::term::Term;
8
9#[derive(Clone, Debug, Eq, Hash, PartialEq)]
11pub struct Atom {
12 pub predicate: PredicateSymbol,
14 pub terms: Vec<Term>,
16}
17
18impl Atom {
19 #[must_use]
21 pub fn arity(&self) -> usize {
22 self.terms.len()
23 }
24
25 #[must_use]
29 pub(super) fn variables(&self) -> BTreeSet<VariableSymbol> {
30 let mut acc = BTreeSet::new();
31 self.collect_variables(&mut acc);
32 acc
33 }
34
35 fn collect_variables(&self, acc: &mut BTreeSet<VariableSymbol>) {
36 for term in &self.terms {
37 collect_term_variables(term, acc);
38 }
39 }
40
41 #[must_use]
47 pub(super) fn contains_skolem(&self) -> bool {
48 self.terms.iter().any(term_contains_skolem)
49 }
50
51 #[must_use]
56 pub(super) fn nesting_depth(&self) -> usize {
57 self.terms
58 .iter()
59 .map(Term::nesting_depth)
60 .max()
61 .unwrap_or(0)
62 }
63}
64
65fn collect_term_variables(term: &Term, acc: &mut BTreeSet<VariableSymbol>) {
66 match term {
67 Term::Variable(var) => {
68 acc.insert(var.clone());
69 }
70 Term::Constant(_) => {}
71 Term::TripleTerm(inner) => {
72 for child in &inner.terms {
73 collect_term_variables(child, acc);
74 }
75 }
76 Term::Skolem { args, .. } => {
77 for arg in args {
78 collect_term_variables(arg, acc);
79 }
80 }
81 }
82}
83
84fn term_contains_skolem(term: &Term) -> bool {
85 match term {
86 Term::Skolem { .. } => true,
87 Term::TripleTerm(inner) => inner.terms.iter().any(term_contains_skolem),
88 Term::Variable(_) | Term::Constant(_) => false,
89 }
90}
91
92impl fmt::Display for Atom {
96 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
97 write!(f, "{}(", self.predicate.as_str())?;
98 for (idx, term) in self.terms.iter().enumerate() {
99 if idx > 0 {
100 write!(f, ", ")?;
101 }
102 write!(f, "{term}")?;
103 }
104 write!(f, ")")
105 }
106}