narust-158 0.3.1

A Rust reimplementation of OpenNARS 1.5.8
Documentation
//! 📄OpenNARS `nars.language.Term`
//! * ⚠️不包含与特定层数Narsese有关的逻辑
//!   * 📄事关NAL-6的`isConstant`、`renameVariables`方法,不予在此实现
//! * ⚠️不包含与「记忆区」有关的方法
//!   * 📄`make`
//!   * 📝OpenNARS中有关`make`的目的:避免在记忆区中**重复构造**词项
//!     * 🚩已经在概念区中⇒使用已有「概念」的词项
//!     * 📌本质上是「缓存」的需求与作用
//! * ✅【2024-06-14 16:33:57】基本完成对「基础词项」的属性检查

use crate::language::*;
use crate::symbols::*;
use narsese::api::{GetCategory, TermCategory};

/// 📄OpenNARS `nars.language.Term`
impl Term {
    /// 模拟`Term.getName`
    /// * 🆕使用自身内建的「获取名称」方法
    ///   * 相较OpenNARS更**短**
    ///   * 仍能满足OpenNARS的需求
    /// * 🎯OpenNARS原有需求
    ///   * 📌保证「词项不同 ⇔ 名称不同」
    ///   * 📌保证「可用于『概念』『记忆区』的索引」
    ///
    /// # 📄OpenNARS
    ///
    /// Reporting the name of the current Term.
    ///
    /// @return The name of the term as a String
    #[doc(alias = "get_name")]
    pub fn name(&self) -> String {
        self.format_name()
    }

    // * ✅`is_constant`已在别处定义
    // * ✅`is_placeholder`已在别处定义

    /// 模拟`Term.getComplexity`
    /// * 🚩逻辑 from OpenNARS
    ///   * 原子 ⇒ 1
    ///   * ~~变量 ⇒ 0~~
    ///   * 复合 ⇒ 1 + 所有组分复杂度之和
    ///
    /// # 📄OpenNARS
    ///
    /// - The syntactic complexity, for constant atomic Term, is 1.
    /// - The complexity of the term is the sum of those of the components plus 1
    /// - ~~The syntactic complexity of a variable is 0, because it does not refer to * any concept.~~
    ///
    /// @return The complexity of the term, an integer
    #[doc(alias = "get_complexity")]
    pub fn complexity(&self) -> usize {
        // 剩余类型
        use TermComponents::*;
        match self.components() {
            // 占位符 ⇒ 0
            Empty => 0,
            // 原子/变量 ⇒ 1 | 不包括「变量」
            // * 🚩目前遵照更新的PyNARS设置,将「变量词项」的复杂度定为1
            Word(..) | Variable(..) => 1,
            // 多元 ⇒ 1 + 内部所有词项复杂度之和
            Compound(terms) => 1 + terms.iter().map(Term::complexity).sum::<usize>(),
        }
    }

    /// 🆕判断是否为「零复杂度」
    /// * 🎯用于部分「除以复杂度」的函数
    #[doc(alias = "zero_complexity")]
    pub fn is_zero_complexity(&self) -> bool {
        self.complexity() == 0
    }

    /// 🆕用于替代Java的`x.getClass() == y.getClass()`
    #[inline(always)]
    pub fn is_same_type(&self, other: &Self) -> bool {
        self.identifier() == other.identifier()
    }
}

impl GetCategory for Term {
    fn get_category(&self) -> TermCategory {
        use TermCategory::*;
        match self.identifier() {
            // * 🚩原子:词语、占位符、变量
            WORD | PLACEHOLDER | VAR_INDEPENDENT | VAR_DEPENDENT | VAR_QUERY => Atom,
            // * 🚩陈述:继承、相似、蕴含、等价 | ❌不包括「实例」「属性」「实例属性」
            INHERITANCE_RELATION | IMPLICATION_RELATION | SIMILARITY_RELATION
            | EQUIVALENCE_RELATION => Statement,
            // * 🚩一元:否定
            NEGATION_OPERATOR |
            // * 🚩二元序列:差集
            DIFFERENCE_EXT_OPERATOR | DIFFERENCE_INT_OPERATOR |
            // * 🚩多元序列:乘积、像
            PRODUCT_OPERATOR | IMAGE_EXT_OPERATOR | IMAGE_INT_OPERATOR |
            // * 🚩多元集合:词项集、交集、合取、析取
            SET_EXT_OPERATOR
            | SET_INT_OPERATOR
            | INTERSECTION_EXT_OPERATOR
            | INTERSECTION_INT_OPERATOR
            | CONJUNCTION_OPERATOR
            | DISJUNCTION_OPERATOR => Compound,
            // * 🚩其它⇒panic(不应出现)
            id => panic!("Unexpected compound term identifier: {id}"),
        }
    }
}

/// 单元测试
#[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 name() -> AResult {
        macro_once! {
            // * 🚩模式:词项字符串 ⇒ 预期
            macro fmt($($term:literal => $expected:expr)*) {
                asserts! {$(
                    term!($term).to_string() => $expected
                )*}
            }
            // 占位符
            "_" => "_"
            // 原子词项
            "A" => "A"
            "$A" => "$1" // ! 🚩【2024-06-13 19:02:58】现在对「变量词项」会自动重命名
            "#A" => "#1" // ! 🚩【2024-06-13 19:02:58】现在对「变量词项」会自动重命名
            "?A" => "?1" // ! 🚩【2024-06-13 19:02:58】现在对「变量词项」会自动重命名
            // 复合词项
            "{A, B}" => "{}(A B)"
            "[A, B]" => "[](A B)"
            "(&, A, B)" => "&(A B)"
            "(|, A, B)" => "|(A B)"
            "(-, A, B)" => "(A - B)"
            "(~, A, B)" => "(A ~ B)"
            "(*, A, B)" => "*(A B)"
            r"(/, R, _)" => r"/(R _)"
            r"(\, R, _)" => r"\(R _)"
            r"(/, R, _, A)" => r"/(R _ A)"
            r"(\, R, _, A)" => r"\(R _ A)"
            r"(&&, A, B)" => r"&&(A B)"
            r"(||, A, B)" => r"||(A B)"
            r"(--, A)" => r"(-- A)"
            // 陈述
            "<A --> B>" => "(A --> B)"
            "<A <-> B>" => "(A <-> B)"
            "<A ==> B>" => "(A ==> B)"
            "<A <=> B>" => "(A <=> B)"
            // ! 自动排序
            "<B <-> A>" => "(A <-> B)"
            "<B <=> A>" => "(A <=> B)"
            // ! 变量重命名
            "(*, $e, #d, ?c, $b, #a)" => "*($1 #2 ?3 $4 #5)"
            "(/, $e, #d, ?c, $b, #a, _)" => "/($1 #2 ?3 $4 #5 _)"
        }
        ok!()
    }

    #[test]
    fn complexity() -> AResult {
        macro_once! {
            // * 🚩模式:词项字符串 ⇒ 预期
            macro fmt($($term:literal => $expected:expr)*) {
                asserts! {$(
                    term!($term).complexity() => $expected
                )*}
            }
            // 占位符
            "_" => 0
            // 词语
            "A" => 1
            // 变量
            "$A" => 1 // ! 🚩【2024-06-14 00:28:01】现在遵照PyNARS等更新版本的做法
            "#A" => 1
            "?A" => 1
            // 复合词项
            "{A}" => 2
            "[A]" => 2
            "(-, A, B)" => 3
            "(~, A, B)" => 3
            "(&, A, B, C)" => 4
            "(|, A, B, C)" => 4
            "(*, A, B, C, D)" => 5
            r"(/, R, _)" => 2
            r"(\, R, _)" => 2
            r"(/, R, _, A)" => 3
            r"(\, R, _, A)" => 3
            r"(&&, A, B)" => 3
            r"(||, A, B)" => 3
            r"(--, A)" => 2
            r"(*, (*, A))" => 3
            r"(*, (*, (*, A)))" => 4
            // 陈述
            "<A --> B>" => 3
            "<A <-> B>" => 3
            "<A ==> B>" => 3
            "<A <=> B>" => 3
            "<<A --> B> ==> X>" => 5
            "<<A <-> B> <=> X>" => 5
            "<<A --> B> ==> X>" => 5
            "<<A <-> B> <=> X>" => 5
            "<<A --> B> --> <C ==> D>>" => 7
            "<<A <-> B> <-> <C <=> D>>" => 7
            "<<A --> B> ==> <C ==> D>>" => 7
            "<<A <-> B> <=> <C <=> D>>" => 7
        }
        ok!()
    }

    /// * 【2024-04-25 16:17:17】📌直接参照的`identifier`
    #[test]
    fn is_same_type() -> AResult {
        macro_once! {
            // * 🚩模式:词项字符串 ⇒ 预期
            macro is_same_type($( $s:literal ~ $s2:literal => $id:expr )*) {
                $(
                    let term = term!($s);
                    let term2 = term!($s2);
                    assert!(term.is_same_type(&term2));
                    assert_eq!(term.identifier(), $id);
                    assert_eq!(term2.identifier(), $id);
                )*
            }
            // 占位符
            "_" ~ "_" => PLACEHOLDER
            // 原子词项
            "A" ~ "B" => WORD
            "$A" ~ "$x" => VAR_INDEPENDENT
            "#A" ~ "#1" => VAR_DEPENDENT
            "?A" ~ "?question" => VAR_QUERY
            // 复合词项
            "{A}" ~ "{x, y, z}" => SET_EXT_OPERATOR
            "[A]" ~ "[ㄚ, ㄛ, ㄜ]" => SET_INT_OPERATOR
            "(&, A, B)" ~ "(&, x, y)" => INTERSECTION_EXT_OPERATOR
            "(|, A, B)" ~ "(|, a, b)" => INTERSECTION_INT_OPERATOR
            "(-, A, B)" ~ "(-, B, A)" => DIFFERENCE_EXT_OPERATOR
            "(~, A, B)" ~ "(~, B, C)" => DIFFERENCE_INT_OPERATOR
            "(*, A)" ~ "(*, α, β, γ)" => PRODUCT_OPERATOR
            r"(/, R, _)" ~ r"(/, R, A, _, B)" => IMAGE_EXT_OPERATOR
            r"(\, R, _)" ~ r"(\, R, A, B, _)" => IMAGE_INT_OPERATOR
            r"(&&, A, B)" ~ r"(&&, X, Y, Z)" => CONJUNCTION_OPERATOR
            r"(||, A, B)" ~ r"(||, (||, A, B), C)" => DISJUNCTION_OPERATOR
            r"(--, A)" ~ r"(--, (~, B, A))" => NEGATION_OPERATOR
            // 陈述
            "<A --> B>" ~ "<<B ==> C> --> A>" => INHERITANCE_RELATION
            "<A <-> B>" ~ "<<B <=> C> <-> A>" => SIMILARITY_RELATION
            "<A ==> B>" ~ "<<B --> C> ==> A>" => IMPLICATION_RELATION
            "<A <=> B>" ~ "<<B <-> C> <=> A>" => EQUIVALENCE_RELATION
        }
        ok!()
    }
}