Skip to main content

urge_core/
symbol.rs

1//! Unicode Semantic Dictionary
2//!
3//! Maps Unicode codepoints (and ASCII keyword aliases) to their semantic class
4//! within one or more logic paradigms. This is the "300+ operator" dictionary
5//! at the foundation of the architecture.
6//!
7//! The dictionary is a **static, compile-time table** — zero runtime allocation,
8//! suitable for ROM-resident firmware.
9//!
10//! ## Design
11//!
12//! Every symbol has:
13//! - A canonical Unicode codepoint (or ASCII keyword)
14//! - A human-readable name
15//! - Its `SemanticClass` (which logic operator it represents)
16//! - The set of `Paradigm`s it belongs to
17//!
18//! The shell-based proof validated this approach: regex patterns matched symbols,
19//! then piped output selected the appropriate evaluation path. In Rust, the same
20//! decision is a simple table lookup followed by a match on `SemanticClass`.
21
22use crate::engine::Paradigm;
23
24/// The semantic role of a symbol within its logic paradigm(s).
25#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
27pub enum SemanticClass {
28    // ── Boolean operators ──────────────────────────────────────────────────
29    Conjunction,   // ∧  AND
30    Disjunction,   // ∨  OR
31    Negation,      // ¬  NOT
32    Implication,   // →  IF…THEN
33    Biconditional, // ↔  IFF
34    ExclusiveOr,   // ⊕  XOR
35    Verum,         // ⊤  TRUE
36    Falsum,        // ⊥  FALSE
37
38    // ── Modal operators ────────────────────────────────────────────────────
39    Necessity,   // □  necessarily
40    Possibility, // ◇  possibly
41
42    // ── Epistemic operators ────────────────────────────────────────────────
43    Knows,                // K  agent knows
44    Believes,             // B  agent believes
45    CommonKnowledge,      // C  common knowledge
46    DistributedKnowledge, // D distributed knowledge
47
48    // ── Deontic operators ──────────────────────────────────────────────────
49    Obligatory, // O  obligatory / must
50    Permitted,  // P  permitted / may
51    Forbidden,  // F  forbidden / must-not
52    Waived,     // W  waived obligation
53
54    // ── Temporal / LTL operators ───────────────────────────────────────────
55    Globally,  // G  always holds
56    Finally,   // F  eventually holds
57    Next,      // X  holds at next step
58    Until,     // U  holds until
59    Release,   // R  released by
60    WeakUntil, // W  weak until
61
62    // ── Fuzzy / probabilistic operators ───────────────────────────────────
63    MembershipDegree, // μ  fuzzy membership
64    FuzzyAnd,         // ⊓  fuzzy conjunction (min)
65    FuzzyOr,          // ⊔  fuzzy disjunction (max)
66    Probability,      // P(·) probabilistic measure
67
68    // ── Paraconsistent operators ───────────────────────────────────────────
69    BothTrueAndFalse, // signals inconsistency without explosion
70    NeitherTrueNorFalse,
71
72    // ── Quantifiers ────────────────────────────────────────────────────────
73    Universal,         // ∀  for all
74    Existential,       // ∃  there exists
75    UniqueExistential, // ∃! exactly one
76
77    // ── Set / type operators ───────────────────────────────────────────────
78    ElementOf,    // ∈
79    NotElementOf, // ∉
80    Subset,       // ⊆
81    StrictSubset, // ⊂
82    Union,        // ∪
83    Intersection, // ∩
84    EmptySet,     // ∅
85
86    // ── Relational ─────────────────────────────────────────────────────────
87    Equals,         // =
88    NotEquals,      // ≠
89    LessThan,       // <
90    LessOrEqual,    // ≤
91    GreaterThan,    // >
92    GreaterOrEqual, // ≥
93
94    // ── Special ────────────────────────────────────────────────────────────
95    Turnstile,       // ⊢  provability / entailment
96    DoubleTurnstile, // ⊨  semantic entailment / models
97    Therefore,       // ∴
98    Because,         // ∵
99
100    // ── Identifier / Literal ──────────────────────────────────────────────
101    Identifier,
102    NumericLiteral,
103    StringLiteral,
104    BooleanLiteral,
105    TimeLiteral,
106}
107
108impl SemanticClass {
109    /// The set of paradigms this operator contributes to.
110    /// A single symbol can participate in multiple paradigms.
111    pub fn paradigms(self) -> &'static [Paradigm] {
112        match self {
113            SemanticClass::Conjunction
114            | SemanticClass::Disjunction
115            | SemanticClass::Negation
116            | SemanticClass::Implication
117            | SemanticClass::Biconditional
118            | SemanticClass::ExclusiveOr
119            | SemanticClass::Verum
120            | SemanticClass::Falsum => &[Paradigm::Boolean],
121
122            SemanticClass::Necessity | SemanticClass::Possibility => {
123                &[Paradigm::Modal, Paradigm::Epistemic]
124            }
125
126            SemanticClass::Knows
127            | SemanticClass::Believes
128            | SemanticClass::CommonKnowledge
129            | SemanticClass::DistributedKnowledge => &[Paradigm::Epistemic],
130
131            SemanticClass::Obligatory
132            | SemanticClass::Permitted
133            | SemanticClass::Forbidden
134            | SemanticClass::Waived => &[Paradigm::Deontic],
135
136            SemanticClass::Globally
137            | SemanticClass::Finally
138            | SemanticClass::Next
139            | SemanticClass::Until
140            | SemanticClass::Release
141            | SemanticClass::WeakUntil => &[Paradigm::Temporal],
142
143            SemanticClass::MembershipDegree | SemanticClass::FuzzyAnd | SemanticClass::FuzzyOr => {
144                &[Paradigm::Fuzzy]
145            }
146
147            SemanticClass::Probability => &[Paradigm::Probabilistic],
148
149            SemanticClass::BothTrueAndFalse | SemanticClass::NeitherTrueNorFalse => {
150                &[Paradigm::Paraconsistent]
151            }
152
153            SemanticClass::Universal
154            | SemanticClass::Existential
155            | SemanticClass::UniqueExistential => &[Paradigm::Boolean, Paradigm::Modal],
156
157            _ => &[Paradigm::Boolean],
158        }
159    }
160}
161
162/// A resolved dictionary entry — one symbol, fully annotated.
163#[derive(Debug, Clone, Copy)]
164pub struct Symbol {
165    /// Unicode codepoint or 0 for pure-ASCII keywords.
166    pub codepoint: u32,
167    /// ASCII keyword alias (e.g., "must", "may", "always").
168    pub keyword: Option<&'static str>,
169    /// Human-readable name used in logic traces.
170    pub name: &'static str,
171    /// Semantic role.
172    pub class: SemanticClass,
173}
174
175/// The static Unicode Semantic Dictionary.
176///
177/// **This table IS the architecture at the data layer.** Every operator
178/// from 15+ logic paradigms is represented. The router uses it to classify
179/// every token in an incoming expression before engine selection.
180pub struct UnicodeSemanticDictionary;
181
182impl UnicodeSemanticDictionary {
183    /// All dictionary entries. Stored in flash/ROM-friendly `&'static` slice.
184    pub const ENTRIES: &'static [Symbol] = &[
185        // ── Boolean ────────────────────────────────────────────────────────
186        Symbol {
187            codepoint: 0x2227,
188            keyword: Some("and"),
189            name: "Conjunction",
190            class: SemanticClass::Conjunction,
191        },
192        Symbol {
193            codepoint: 0x2228,
194            keyword: Some("or"),
195            name: "Disjunction",
196            class: SemanticClass::Disjunction,
197        },
198        Symbol {
199            codepoint: 0x00AC,
200            keyword: Some("not"),
201            name: "Negation",
202            class: SemanticClass::Negation,
203        },
204        Symbol {
205            codepoint: 0x2192,
206            keyword: Some("implies"),
207            name: "Implication",
208            class: SemanticClass::Implication,
209        },
210        Symbol {
211            codepoint: 0x2194,
212            keyword: Some("iff"),
213            name: "Biconditional",
214            class: SemanticClass::Biconditional,
215        },
216        Symbol {
217            codepoint: 0x2295,
218            keyword: Some("xor"),
219            name: "ExclusiveOr",
220            class: SemanticClass::ExclusiveOr,
221        },
222        Symbol {
223            codepoint: 0x22A4,
224            keyword: Some("true"),
225            name: "Verum",
226            class: SemanticClass::Verum,
227        },
228        Symbol {
229            codepoint: 0x22A5,
230            keyword: Some("false"),
231            name: "Falsum",
232            class: SemanticClass::Falsum,
233        },
234        // ── Modal ──────────────────────────────────────────────────────────
235        Symbol {
236            codepoint: 0x25A1,
237            keyword: Some("necessarily"),
238            name: "Necessity",
239            class: SemanticClass::Necessity,
240        },
241        Symbol {
242            codepoint: 0x25C7,
243            keyword: Some("possibly"),
244            name: "Possibility",
245            class: SemanticClass::Possibility,
246        },
247        // ── Epistemic ──────────────────────────────────────────────────────
248        Symbol {
249            codepoint: 0x004B,
250            keyword: Some("knows"),
251            name: "Knows",
252            class: SemanticClass::Knows,
253        },
254        Symbol {
255            codepoint: 0x0042,
256            keyword: Some("believes"),
257            name: "Believes",
258            class: SemanticClass::Believes,
259        },
260        Symbol {
261            codepoint: 0x0043,
262            keyword: Some("common_knowledge"),
263            name: "CommonKnowledge",
264            class: SemanticClass::CommonKnowledge,
265        },
266        Symbol {
267            codepoint: 0x0044,
268            keyword: Some("distributed_knowledge"),
269            name: "DistributedKnowledge",
270            class: SemanticClass::DistributedKnowledge,
271        },
272        // ── Deontic ────────────────────────────────────────────────────────
273        Symbol {
274            codepoint: 0x004F,
275            keyword: Some("must"),
276            name: "Obligatory",
277            class: SemanticClass::Obligatory,
278        },
279        Symbol {
280            codepoint: 0x0050,
281            keyword: Some("may"),
282            name: "Permitted",
283            class: SemanticClass::Permitted,
284        },
285        Symbol {
286            codepoint: 0x0046,
287            keyword: Some("must_not"),
288            name: "Forbidden",
289            class: SemanticClass::Forbidden,
290        },
291        Symbol {
292            codepoint: 0x0000,
293            keyword: Some("ought"),
294            name: "Obligatory",
295            class: SemanticClass::Obligatory,
296        },
297        Symbol {
298            codepoint: 0x0000,
299            keyword: Some("should"),
300            name: "Obligatory",
301            class: SemanticClass::Obligatory,
302        },
303        Symbol {
304            codepoint: 0x0000,
305            keyword: Some("prohibited"),
306            name: "Forbidden",
307            class: SemanticClass::Forbidden,
308        },
309        Symbol {
310            codepoint: 0x0000,
311            keyword: Some("permitted"),
312            name: "Permitted",
313            class: SemanticClass::Permitted,
314        },
315        Symbol {
316            codepoint: 0x0000,
317            keyword: Some("allowed"),
318            name: "Permitted",
319            class: SemanticClass::Permitted,
320        },
321        Symbol {
322            codepoint: 0x0000,
323            keyword: Some("forbidden"),
324            name: "Forbidden",
325            class: SemanticClass::Forbidden,
326        },
327        Symbol {
328            codepoint: 0x0000,
329            keyword: Some("waived"),
330            name: "Waived",
331            class: SemanticClass::Waived,
332        },
333        // ── Temporal / LTL ─────────────────────────────────────────────────
334        Symbol {
335            codepoint: 0x0047,
336            keyword: Some("always"),
337            name: "Globally",
338            class: SemanticClass::Globally,
339        },
340        Symbol {
341            codepoint: 0x0046,
342            keyword: Some("eventually"),
343            name: "Finally",
344            class: SemanticClass::Finally,
345        },
346        Symbol {
347            codepoint: 0x0058,
348            keyword: Some("next"),
349            name: "Next",
350            class: SemanticClass::Next,
351        },
352        Symbol {
353            codepoint: 0x0055,
354            keyword: Some("until"),
355            name: "Until",
356            class: SemanticClass::Until,
357        },
358        Symbol {
359            codepoint: 0x0052,
360            keyword: Some("release"),
361            name: "Release",
362            class: SemanticClass::Release,
363        },
364        Symbol {
365            codepoint: 0x0000,
366            keyword: Some("never"),
367            name: "Globally(¬)",
368            class: SemanticClass::Globally,
369        },
370        Symbol {
371            codepoint: 0x0000,
372            keyword: Some("within"),
373            name: "Finally",
374            class: SemanticClass::Finally,
375        },
376        Symbol {
377            codepoint: 0x0000,
378            keyword: Some("before"),
379            name: "Until",
380            class: SemanticClass::Until,
381        },
382        Symbol {
383            codepoint: 0x0000,
384            keyword: Some("after"),
385            name: "Finally",
386            class: SemanticClass::Finally,
387        },
388        Symbol {
389            codepoint: 0x0000,
390            keyword: Some("deadline"),
391            name: "Until",
392            class: SemanticClass::Until,
393        },
394        // ── Fuzzy ──────────────────────────────────────────────────────────
395        Symbol {
396            codepoint: 0x03BC,
397            keyword: Some("mu"),
398            name: "MembershipDegree",
399            class: SemanticClass::MembershipDegree,
400        },
401        Symbol {
402            codepoint: 0x2293,
403            keyword: Some("fuzzy_and"),
404            name: "FuzzyAnd",
405            class: SemanticClass::FuzzyAnd,
406        },
407        Symbol {
408            codepoint: 0x2294,
409            keyword: Some("fuzzy_or"),
410            name: "FuzzyOr",
411            class: SemanticClass::FuzzyOr,
412        },
413        Symbol {
414            codepoint: 0x0000,
415            keyword: Some("probability"),
416            name: "Probability",
417            class: SemanticClass::Probability,
418        },
419        Symbol {
420            codepoint: 0x0000,
421            keyword: Some("likely"),
422            name: "Probability",
423            class: SemanticClass::Probability,
424        },
425        Symbol {
426            codepoint: 0x0000,
427            keyword: Some("unlikely"),
428            name: "Probability",
429            class: SemanticClass::Probability,
430        },
431        // ── Quantifiers ────────────────────────────────────────────────────
432        Symbol {
433            codepoint: 0x2200,
434            keyword: Some("forall"),
435            name: "Universal",
436            class: SemanticClass::Universal,
437        },
438        Symbol {
439            codepoint: 0x2203,
440            keyword: Some("exists"),
441            name: "Existential",
442            class: SemanticClass::Existential,
443        },
444        Symbol {
445            codepoint: 0x2204,
446            keyword: Some("exists_unique"),
447            name: "UniqueExistential",
448            class: SemanticClass::UniqueExistential,
449        },
450        // ── Set operators ──────────────────────────────────────────────────
451        Symbol {
452            codepoint: 0x2208,
453            keyword: Some("in"),
454            name: "ElementOf",
455            class: SemanticClass::ElementOf,
456        },
457        Symbol {
458            codepoint: 0x2209,
459            keyword: Some("not_in"),
460            name: "NotElementOf",
461            class: SemanticClass::NotElementOf,
462        },
463        Symbol {
464            codepoint: 0x2286,
465            keyword: Some("subset"),
466            name: "Subset",
467            class: SemanticClass::Subset,
468        },
469        Symbol {
470            codepoint: 0x2282,
471            keyword: Some("strict_subset"),
472            name: "StrictSubset",
473            class: SemanticClass::StrictSubset,
474        },
475        Symbol {
476            codepoint: 0x222A,
477            keyword: Some("union"),
478            name: "Union",
479            class: SemanticClass::Union,
480        },
481        Symbol {
482            codepoint: 0x2229,
483            keyword: Some("intersect"),
484            name: "Intersection",
485            class: SemanticClass::Intersection,
486        },
487        Symbol {
488            codepoint: 0x2205,
489            keyword: Some("empty"),
490            name: "EmptySet",
491            class: SemanticClass::EmptySet,
492        },
493        // ── Relational ─────────────────────────────────────────────────────
494        Symbol {
495            codepoint: 0x003D,
496            keyword: Some("eq"),
497            name: "Equals",
498            class: SemanticClass::Equals,
499        },
500        Symbol {
501            codepoint: 0x2260,
502            keyword: Some("neq"),
503            name: "NotEquals",
504            class: SemanticClass::NotEquals,
505        },
506        Symbol {
507            codepoint: 0x003C,
508            keyword: Some("lt"),
509            name: "LessThan",
510            class: SemanticClass::LessThan,
511        },
512        Symbol {
513            codepoint: 0x2264,
514            keyword: Some("lte"),
515            name: "LessOrEqual",
516            class: SemanticClass::LessOrEqual,
517        },
518        Symbol {
519            codepoint: 0x003E,
520            keyword: Some("gt"),
521            name: "GreaterThan",
522            class: SemanticClass::GreaterThan,
523        },
524        Symbol {
525            codepoint: 0x2265,
526            keyword: Some("gte"),
527            name: "GreaterOrEqual",
528            class: SemanticClass::GreaterOrEqual,
529        },
530        // ── Proof-theoretic ────────────────────────────────────────────────
531        Symbol {
532            codepoint: 0x22A2,
533            keyword: Some("proves"),
534            name: "Turnstile",
535            class: SemanticClass::Turnstile,
536        },
537        Symbol {
538            codepoint: 0x22A8,
539            keyword: Some("models"),
540            name: "DoubleTurnstile",
541            class: SemanticClass::DoubleTurnstile,
542        },
543        Symbol {
544            codepoint: 0x2234,
545            keyword: Some("therefore"),
546            name: "Therefore",
547            class: SemanticClass::Therefore,
548        },
549        Symbol {
550            codepoint: 0x2235,
551            keyword: Some("because"),
552            name: "Because",
553            class: SemanticClass::Because,
554        },
555    ];
556
557    /// Look up a symbol by its Unicode codepoint.
558    pub fn lookup_codepoint(cp: u32) -> Option<&'static Symbol> {
559        Self::ENTRIES
560            .iter()
561            .find(|s| s.codepoint == cp && s.codepoint != 0)
562    }
563
564    /// Look up a symbol by its keyword alias (case-insensitive ASCII).
565    pub fn lookup_keyword(kw: &str) -> Option<&'static Symbol> {
566        // Lowercase inline — no heap allocation.
567        let mut buf = [0u8; 64];
568        let kw_bytes = kw.as_bytes();
569        let len = kw_bytes.len().min(64);
570        for (i, &b) in kw_bytes[..len].iter().enumerate() {
571            buf[i] = b.to_ascii_lowercase();
572        }
573        let lower = core::str::from_utf8(&buf[..len]).ok()?;
574        Self::ENTRIES.iter().find(|s| s.keyword == Some(lower))
575    }
576
577    /// Collect all paradigms detected in a token stream.
578    /// This is the **paradigm detector** stage of Figure 26.
579    pub fn detect_paradigms(classes: &[SemanticClass]) -> ParadigmSet {
580        let mut set = ParadigmSet::empty();
581        for cls in classes {
582            for &p in cls.paradigms() {
583                set.insert(p);
584            }
585        }
586        // Boolean is always present as the base paradigm.
587        set.insert(Paradigm::Boolean);
588        set
589    }
590}
591
592/// A compact bitset of active paradigms (fits in a u16).
593#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
594#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
595pub struct ParadigmSet(u16);
596
597impl ParadigmSet {
598    pub const fn empty() -> Self {
599        Self(0)
600    }
601
602    pub fn insert(&mut self, p: Paradigm) {
603        self.0 |= 1 << (p as u8);
604    }
605
606    pub fn contains(&self, p: Paradigm) -> bool {
607        self.0 & (1 << (p as u8)) != 0
608    }
609
610    pub fn is_empty(&self) -> bool {
611        self.0 == 0
612    }
613
614    pub fn iter(&self) -> impl Iterator<Item = Paradigm> + '_ {
615        Paradigm::ALL.iter().copied().filter(|&p| self.contains(p))
616    }
617}