use crate::language::*;
use crate::symbols::*;
use nar_dev_utils::matches_or;
impl Term {
pub fn instanceof_variable(&self) -> bool {
matches!(
self.identifier(),
VAR_INDEPENDENT | VAR_DEPENDENT | VAR_QUERY
)
}
pub fn instanceof_variable_i(&self) -> bool {
self.identifier() == VAR_INDEPENDENT
}
pub fn instanceof_variable_d(&self) -> bool {
self.identifier() == VAR_DEPENDENT
}
pub fn instanceof_variable_q(&self) -> bool {
self.identifier() == VAR_QUERY
}
pub fn as_variable(&self) -> Option<usize> {
matches_or!(
?self.components(),
TermComponents::Variable(n) => *n
)
}
#[inline(always)]
pub fn is_constant(&self) -> bool {
!self.instanceof_variable() && !self.is_placeholder() && !self.contains_sole_variable()
}
fn contains_sole_variable(&self) -> bool {
use std::collections::HashMap;
fn variable_count_map(this: &Term) -> HashMap<usize, usize> {
let mut var_count_map = HashMap::new();
this.for_each_atom(&mut |atom| {
if let Some(n) = atom.as_variable() {
if !atom.instanceof_variable_q() {
let new_value = match var_count_map.get(&n) {
Some(count) => count + 1,
None => 1,
};
var_count_map.insert(n, new_value);
}
}
});
var_count_map
}
let var_count_map = variable_count_map(self);
var_count_map.values().any(|&count| count < 2)
}
#[inline]
pub fn contain_var(&self) -> bool {
self.instanceof_variable() || self.components().contain_var()
}
pub fn contain_var_i(&self) -> bool {
self.contain_type(VAR_INDEPENDENT)
}
pub fn contain_var_d(&self) -> bool {
self.contain_type(VAR_DEPENDENT)
}
pub fn contain_var_q(&self) -> bool {
self.contain_type(VAR_QUERY)
}
#[inline(always)]
pub fn get_variable_type(&self) -> &str {
self.identifier()
}
pub fn maximum_variable_id_multi<'s>(terms: impl IntoIterator<Item = &'s Term>) -> usize {
terms
.into_iter()
.map(Term::maximum_variable_id) .max() .unwrap_or(0) }
}
pub trait MaximumVariableId {
fn maximum_variable_id(&self) -> usize;
}
impl MaximumVariableId for Term {
fn maximum_variable_id(&self) -> usize {
use TermComponents::*;
match self.components() {
Variable(id) => *id,
Compound(terms) => Term::maximum_variable_id_multi(terms.iter()),
Empty | Word(..) => 0,
}
}
}
impl MaximumVariableId for &Term {
fn maximum_variable_id(&self) -> usize {
Term::maximum_variable_id(*self)
}
}
impl<const N: usize> MaximumVariableId for [Term; N] {
fn maximum_variable_id(&self) -> usize {
Term::maximum_variable_id_multi(self)
}
}
impl<const N: usize> MaximumVariableId for [&Term; N] {
fn maximum_variable_id(&self) -> usize {
Term::maximum_variable_id_multi(self.iter().cloned())
}
}
impl MaximumVariableId for [Term] {
fn maximum_variable_id(&self) -> usize {
Term::maximum_variable_id_multi(self)
}
}
impl MaximumVariableId for [&Term] {
fn maximum_variable_id(&self) -> usize {
Term::maximum_variable_id_multi(self.iter().cloned())
}
}
impl TermComponents {
pub fn contain_var(&self) -> bool {
self.iter().any(Term::contain_var)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_term as term;
use crate::{ok, util::AResult};
use nar_dev_utils::{asserts, macro_once};
#[test]
fn contain_var() -> AResult {
macro_once! {
macro test($($term:expr => $expected:expr)*) {
asserts! {$(
term!($term).contain_var() => $expected
)*}
}
"<A --> var_word>"=> false
"<A --> $var_word>"=> true
"<A --> #var_word>"=> true
"<A --> ?var_word>"=> true
}
ok!()
}
#[test]
fn is_constant() -> AResult {
macro_once! {
macro test($($term:expr => $expected:expr)*) {
asserts! {$(
term!($term).is_constant() => $expected
)*}
}
"<A --> var_word>" => true
"<A --> $var_word>" => false
"<A --> #var_word>" => false
"<A --> ?var_word>" => true
"<?this --> ?that>" => true
"<<A --> $1> ==> <B --> $1>>" => true
"<<$2 --> $1> ==> <#1 --> #2>>" => true
"(*, $1, $1)" => true
}
ok!()
}
}