Skip to main content

trit_eval/
simplify.rs

1//! 表达式化简。
2//!
3//! 化简分两步:
4//!
5//! 1. **代数化简**:按当前语义可用的规则做结构重写(常量折叠、去重、
6//!    吸收、单位元、De Morgan、交换律规范化等)。
7//! 2. **语义常量检测**:若化简后的表达式在全部赋值下取同一个值,
8//!    直接替换为该常量。
9//!
10//! ⚠️ 规则的适用性依赖语义:
11//!
12//! - **Kleene / Łukasiewicz** 的 `X` 是链的中点,构成分配格,
13//!   因此吸收律、分配律、`a ∧ ¬a = 0` 之外的格性质成立。
14//! - **Bochvar** 的 `X` 是毒值:分配律仍成立,但吸收律**不成立**
15//!   (例:`a ∨ (a ∧ b)` 取 `a=0,b=X` 时左边为 `X`、右边为 `0`)。
16//! - 矛盾律 `a ∧ ¬a = 0` 在三种语义下**都不成立**
17//!   (取 `a = X` 时 `X ∧ X = X`),因此化简器不使用该规则。
18
19use crate::eval::{VarMap, truth_table};
20use trit_core::algebra::Algebra;
21use trit_core::ast::Expr;
22use trit_core::value::Ternary;
23
24/// 化简选项。
25#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26pub struct SimplifyOptions {
27    /// 是否做语义常量检测(把恒真/恒假/恒未知的表达式折叠成常量)。
28    pub fold_constants: bool,
29    /// 参与常量检测的最大变量数;超过则跳过该步(`3^n` 成本)。
30    pub max_vars_for_constant_fold: usize,
31    /// 是否把 `a ⇒ b` 展开为 `¬a ∨ b`(仅 Kleene 语义合法)。
32    pub expand_implies: bool,
33}
34
35impl Default for SimplifyOptions {
36    fn default() -> Self {
37        Self {
38            fold_constants: true,
39            max_vars_for_constant_fold: 8,
40            expand_implies: false,
41        }
42    }
43}
44
45/// 按当前语义化简表达式。
46///
47/// 递归重写;要求 AST 深度有界(`Parser` 产出的表达式满足)。手工构造的深树
48/// 请先调用 `check_expr`,否则可能栈溢出。
49pub fn simplify(expr: &Expr, alg: Algebra) -> Expr {
50    simplify_with(expr, alg, SimplifyOptions::default())
51}
52
53/// 带选项的化简。
54pub fn simplify_with(expr: &Expr, alg: Algebra, opts: SimplifyOptions) -> Expr {
55    let step1 = rewrite(expr, alg, opts);
56    if !opts.fold_constants {
57        return step1;
58    }
59    let var_count = step1.variables().len();
60    if var_count > opts.max_vars_for_constant_fold {
61        return step1;
62    }
63    match constant_value(&step1, alg) {
64        Some(v) => Expr::Const(v),
65        None => step1,
66    }
67}
68
69/// 判断表达式是否语义常量;是则返回该值。
70///
71/// 枚举超出默认预算时返回 `None`:这只表示“没有证明是常量”,调用方应保留原式。
72pub fn constant_value(expr: &Expr, alg: Algebra) -> Option<Ternary> {
73    if expr.variables().is_empty() {
74        let asg = crate::eval::Assignment::new();
75        return Some(crate::eval::eval(expr, &asg, alg));
76    }
77    let tt = truth_table(expr, alg).ok()?;
78    let first = *tt.values.first()?;
79    if tt.values.iter().all(|v| *v == first) {
80        Some(first)
81    } else {
82        None
83    }
84}
85
86/// 递归结构重写。
87fn rewrite(expr: &Expr, alg: Algebra, opts: SimplifyOptions) -> Expr {
88    match expr {
89        Expr::Const(_) | Expr::Var(_) => expr.clone(),
90        Expr::Not(a) => {
91            let inner = rewrite(a, alg, opts);
92            // 双否定消去
93            if let Expr::Not(x) = &inner {
94                return (**x).clone();
95            }
96            // ¬(常量)
97            if let Expr::Const(v) = inner {
98                return Expr::Const(alg.not(v));
99            }
100            Expr::logical_not(inner)
101        }
102        Expr::And(a, b) => {
103            let x = rewrite(a, alg, opts);
104            let y = rewrite(b, alg, opts);
105            rewrite_and(x, y, alg)
106        }
107        Expr::Or(a, b) => {
108            let x = rewrite(a, alg, opts);
109            let y = rewrite(b, alg, opts);
110            rewrite_or(x, y, alg)
111        }
112        Expr::Xor(a, b) => {
113            let x = rewrite(a, alg, opts);
114            let y = rewrite(b, alg, opts);
115            rewrite_xor(x, y, alg)
116        }
117        Expr::Implies(a, b) => {
118            let x = rewrite(a, alg, opts);
119            let y = rewrite(b, alg, opts);
120            if opts.expand_implies && alg == Algebra::Kleene {
121                // a ⇒ b ≡ ¬a ∨ b(仅 Kleene 材料蕴含成立)
122                return rewrite_or(Expr::logical_not(x), y, alg);
123            }
124            rewrite_implies(x, y, alg)
125        }
126        Expr::Equiv(a, b) => {
127            let x = rewrite(a, alg, opts);
128            let y = rewrite(b, alg, opts);
129            rewrite_equiv(x, y, alg)
130        }
131    }
132}
133
134/// 交换律规范化:把两个操作数按稳定顺序排列。
135fn ordered(a: Expr, b: Expr) -> (Expr, Expr) {
136    let ka = expr_key(&a);
137    let kb = expr_key(&b);
138    if kb < ka { (b, a) } else { (a, b) }
139}
140
141/// 表达式的结构排序键。
142fn expr_key(e: &Expr) -> String {
143    e.to_infix()
144}
145
146/// `∧` 的重写规则。
147fn rewrite_and(x: Expr, y: Expr, alg: Algebra) -> Expr {
148    // 常量折叠
149    if let (Expr::Const(a), Expr::Const(b)) = (&x, &y) {
150        return Expr::Const(alg.and(*a, *b));
151    }
152    // 毒值语义:Bochvar 下 `X` 吸收一切
153    if alg.is_poisonous() {
154        if x.is_unknown_const() || y.is_unknown_const() {
155            return Expr::Const(Ternary::Unknown);
156        }
157        if let Expr::Const(Ternary::True) = &x {
158            return y;
159        }
160        if let Expr::Const(Ternary::True) = &y {
161            return x;
162        }
163        // 毒值语义下无吸收律,只能做交换律规范化
164        let (a, b) = ordered(x, y);
165        return Expr::and(a, b);
166    }
167    // 格语义(K3 / Ł3)
168    if let Expr::Const(Ternary::False) = &x {
169        return Expr::Const(Ternary::False);
170    }
171    if let Expr::Const(Ternary::False) = &y {
172        return Expr::Const(Ternary::False);
173    }
174    if let Expr::Const(Ternary::True) = &x {
175        return y;
176    }
177    if let Expr::Const(Ternary::True) = &y {
178        return x;
179    }
180    // 幂等:a ∧ a = a
181    if x == y {
182        return x;
183    }
184    // 吸收:a ∧ (a ∨ b) = a
185    if let Some(absorbed) = absorb(&x, &y) {
186        return absorbed;
187    }
188    if let Some(absorbed) = absorb(&y, &x) {
189        return absorbed;
190    }
191    // 互补吸收:a ∧ ¬a 不成立(三值下不适用),跳过
192    // 交换律规范化
193    let (a, b) = ordered(x, y);
194    Expr::and(a, b)
195}
196
197/// 判断 `x` 是否吸收 `y`(即 `y = x ∨ c` 的形式,返回 `x`)。
198fn absorb(x: &Expr, y: &Expr) -> Option<Expr> {
199    if let Expr::Or(p, q) = y
200        && (**p == *x || **q == *x)
201    {
202        return Some(x.clone());
203    }
204    None
205}
206
207/// `∨` 的吸收:`a ∨ (a ∧ b) = a`。
208fn absorb_or(x: &Expr, y: &Expr) -> Option<Expr> {
209    if let Expr::And(p, q) = y
210        && (**p == *x || **q == *x)
211    {
212        return Some(x.clone());
213    }
214    None
215}
216
217/// `∨` 的重写规则。
218fn rewrite_or(x: Expr, y: Expr, alg: Algebra) -> Expr {
219    if let (Expr::Const(a), Expr::Const(b)) = (&x, &y) {
220        return Expr::Const(alg.or(*a, *b));
221    }
222    if alg.is_poisonous() {
223        if x.is_unknown_const() || y.is_unknown_const() {
224            return Expr::Const(Ternary::Unknown);
225        }
226        if let Expr::Const(Ternary::False) = &x {
227            return y;
228        }
229        if let Expr::Const(Ternary::False) = &y {
230            return x;
231        }
232        // 毒值语义下无吸收律,只能做交换律规范化
233        let (a, b) = ordered(x, y);
234        return Expr::or(a, b);
235    }
236    if let Expr::Const(Ternary::True) = &x {
237        return Expr::Const(Ternary::True);
238    }
239    if let Expr::Const(Ternary::True) = &y {
240        return Expr::Const(Ternary::True);
241    }
242    if let Expr::Const(Ternary::False) = &x {
243        return y;
244    }
245    if let Expr::Const(Ternary::False) = &y {
246        return x;
247    }
248    if x == y {
249        return x;
250    }
251    if let Some(absorbed) = absorb_or(&x, &y) {
252        return absorbed;
253    }
254    if let Some(absorbed) = absorb_or(&y, &x) {
255        return absorbed;
256    }
257    let (a, b) = ordered(x, y);
258    Expr::or(a, b)
259}
260
261/// `⊕` 的重写规则。
262fn rewrite_xor(x: Expr, y: Expr, alg: Algebra) -> Expr {
263    if let (Expr::Const(a), Expr::Const(b)) = (&x, &y) {
264        return Expr::Const(alg.strong_add(*a, *b));
265    }
266    // Kleene 与 Bochvar 下 `X` 都传播为 `X`(Łukasiewicz 例外:X ⊕ X = 1)
267    if alg != Algebra::Lukasiewicz && (x.is_unknown_const() || y.is_unknown_const()) {
268        return Expr::Const(Ternary::Unknown);
269    }
270    // Ł3:X ⊕ X = 1
271    if alg == Algebra::Lukasiewicz && x.is_unknown_const() && y.is_unknown_const() {
272        return Expr::Const(Ternary::True);
273    }
274    // K3/B3:a ⊕ a = a(X 也传播为 X);Ł3 只在 0/1 上相同,X ⊕ X = 1 已在上面处理。
275    if x == y && alg != Algebra::Lukasiewicz {
276        return x;
277    }
278    let (a, b) = ordered(x, y);
279    Expr::xor(a, b)
280}
281
282/// `⇒` 的重写规则。
283fn rewrite_implies(x: Expr, y: Expr, alg: Algebra) -> Expr {
284    if let (Expr::Const(a), Expr::Const(b)) = (&x, &y) {
285        return Expr::Const(alg.implies(*a, *b));
286    }
287    // 0 ⇒ b = 1(K3 / Ł3);Bochvar 下 X 毒化
288    if alg != Algebra::Bochvar
289        && let Expr::Const(Ternary::False) = &x
290    {
291        return Expr::Const(Ternary::True);
292    }
293    Expr::implies(x, y)
294}
295
296/// `≡` 的重写规则。
297fn rewrite_equiv(x: Expr, y: Expr, alg: Algebra) -> Expr {
298    if let (Expr::Const(a), Expr::Const(b)) = (&x, &y) {
299        return Expr::Const(alg.equiv(*a, *b));
300    }
301    // 只有 Ł3 的 a ≡ a 在 X 上仍为 1;K3/B3 在 a=X 时为 X。
302    if x == y && alg == Algebra::Lukasiewicz {
303        return Expr::Const(Ternary::True);
304    }
305    Expr::equiv(x, y)
306}
307
308/// 计算表达式的语义指纹(真值表摘要),仅用于缓存/预筛选。
309///
310/// 指纹依赖变量出现顺序且只有 64 位:**相同不保证等价,不同也不保证不等价**。
311/// 判定等价请用 [`semantically_equal`]。
312pub fn semantic_fingerprint(expr: &Expr, alg: Algebra) -> u64 {
313    let vars = expr.variables();
314    let Ok(tt) = truth_table(expr, alg) else {
315        // 超出预算时不产生指纹;0 只表示“无指纹”,不能当等价证据。
316        return 0;
317    };
318    let mut hash = 1469598103934665603u64;
319    for v in &vars {
320        for b in v.as_bytes() {
321            hash ^= u64::from(*b);
322            hash = hash.wrapping_mul(1099511628211);
323        }
324        hash ^= 0xff;
325        hash = hash.wrapping_mul(1099511628211);
326    }
327    for val in &tt.values {
328        hash ^= u64::from(val.as_char() as u8);
329        hash = hash.wrapping_mul(1099511628211);
330    }
331    hash
332}
333
334/// 判断两个表达式在给定语义下语义等价(`3^n` 穷举,变量取并集)。
335pub fn semantically_equal(
336    a: &Expr,
337    b: Expr,
338    alg: Algebra,
339) -> Result<bool, trit_core::limits::LimitError> {
340    Ok(crate::eval::equivalent(a, &b, alg)?.equivalent)
341}
342
343/// 未使用的占位,保持 API 公开但标注用途。
344#[doc(hidden)]
345pub fn unused_var_map() -> VarMap {
346    VarMap::new()
347}
348
349#[cfg(test)]
350mod tests {
351    use super::*;
352    use trit_core::parser::Parser;
353
354    fn simp(src: &str, alg: Algebra) -> String {
355        let e = Parser::parse(src).unwrap();
356        simplify(&e, alg).to_infix()
357    }
358
359    #[test]
360    fn folds_constants() {
361        assert_eq!(simp("1 & 0", Algebra::Kleene), "0");
362        assert_eq!(simp("1 | 0", Algebra::Kleene), "1");
363        assert_eq!(simp("!1", Algebra::Kleene), "0");
364    }
365
366    #[test]
367    fn folds_semantic_constants() {
368        // 三值逻辑下的关键差异:`a ∨ ¬a` 不是重言式(a=X 时结果为 X),
369        // 因此不会被折叠成 1;而 `a ∧ ¬a` 同样不是恒假。
370        // 真正可折叠的语义常量需要用 X 安全前提,例如 `X ∨ 1 = 1`。
371        assert_eq!(simp("x | 1", Algebra::Kleene), "1");
372        assert_eq!(simp("x & 0", Algebra::Kleene), "0");
373        // 语义常量检测把恒定表达式折叠为常量
374        assert_eq!(simp("1 & 0 | 1", Algebra::Kleene), "1");
375        // 变量被吸收后,剩余部分仍是变量
376        let e = Parser::parse("a & 1 | b & 0").unwrap();
377        assert_eq!(simplify(&e, Algebra::Kleene), Expr::Var("a".into()));
378    }
379
380    #[test]
381    fn applies_idempotence_and_identity() {
382        assert_eq!(simp("a & a", Algebra::Kleene), "a");
383        assert_eq!(simp("a | a", Algebra::Kleene), "a");
384        assert_eq!(simp("a & 1", Algebra::Kleene), "a");
385        assert_eq!(simp("a | 0", Algebra::Kleene), "a");
386    }
387
388    #[test]
389    fn bochvar_poison_differs_from_kleene() {
390        // Bochvar: 0 ∧ X = X;Kleene: 0 ∧ X = 0
391        assert_eq!(simp("0 & x", Algebra::Bochvar), "X");
392        assert_eq!(simp("0 & x", Algebra::Kleene), "0");
393    }
394
395    #[test]
396    fn simplification_preserves_semantics() {
397        for src in [
398            "a & b | a",
399            "!(a & b)",
400            "(a => b) & (b => a)",
401            "a ^ b",
402            "a <=> b",
403            "a & 1 | b & 0",
404        ] {
405            let e = Parser::parse(src).unwrap();
406            let s = simplify(&e, Algebra::Kleene);
407            let r = crate::eval::equivalent(&e, &s, Algebra::Kleene).unwrap();
408            assert!(r.equivalent, "simplify changed semantics: {src} -> {s}");
409        }
410    }
411
412    #[test]
413    fn simplification_preserves_semantics_in_bochvar() {
414        for src in ["a & b | a", "0 & x", "a | 1", "a & x"] {
415            let e = Parser::parse(src).unwrap();
416            let s = simplify(&e, Algebra::Bochvar);
417            let r = crate::eval::equivalent(&e, &s, Algebra::Bochvar).unwrap();
418            assert!(
419                r.equivalent,
420                "bochvar simplify changed semantics: {src} -> {s}"
421            );
422        }
423    }
424
425    #[test]
426    fn absorption_only_removes_matching_operator() {
427        // a | (a | b) 不能化简成 a;a | (a & b) 可以。
428        let e = Parser::parse("a | (a | b)").unwrap();
429        let s = simplify(&e, Algebra::Kleene);
430        assert!(
431            crate::eval::equivalent(&e, &s, Algebra::Kleene)
432                .unwrap()
433                .equivalent,
434            "a | (a | b) -> {s}"
435        );
436        assert_eq!(simp("a | (a & b)", Algebra::Kleene), "a");
437    }
438
439    #[test]
440    fn xor_and_equiv_self_respect_unknown() {
441        // K3/B3: a ⊕ a = a,a ≡ a 在 a=X 时为 X。
442        assert_eq!(simp("a ^ a", Algebra::Kleene), "a");
443        assert_eq!(simp("a ^ a", Algebra::Bochvar), "a");
444        let e = Parser::parse("a <=> a").unwrap();
445        let s = simplify(&e, Algebra::Kleene);
446        assert!(
447            crate::eval::equivalent(&e, &s, Algebra::Kleene)
448                .unwrap()
449                .equivalent,
450            "a ≡ a -> {s}"
451        );
452        // Ł3 的自等价恒为 1
453        assert_eq!(simp("a <=> a", Algebra::Lukasiewicz), "1");
454    }
455
456    #[test]
457    fn semantically_equal_uses_real_equivalence() {
458        let a = Parser::parse("a & b").unwrap();
459        let b = Parser::parse("b & a").unwrap();
460        assert!(semantically_equal(&a, b, Algebra::Kleene).unwrap());
461
462        let a = Parser::parse("a").unwrap();
463        let b = Parser::parse("a & (b | 1)").unwrap();
464        assert!(semantically_equal(&a, b, Algebra::Kleene).unwrap());
465
466        let a = Parser::parse("a | (a | b)").unwrap();
467        let b = Parser::parse("a").unwrap();
468        assert!(!semantically_equal(&a, b, Algebra::Kleene).unwrap());
469    }
470}