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