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//!   (例:`0 ∧ (0 ∨ 1) = 0`,但 `0 ∧ 0 ∨ 0 ∧ 1 = X`)。
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/// `∨` 的重写规则。
203fn rewrite_or(x: Expr, y: Expr, alg: Algebra) -> Expr {
204    if let (Expr::Const(a), Expr::Const(b)) = (&x, &y) {
205        return Expr::Const(alg.or(*a, *b));
206    }
207    if alg.is_poisonous() {
208        if x.is_unknown_const() || y.is_unknown_const() {
209            return Expr::Const(Ternary::Unknown);
210        }
211        if let Expr::Const(Ternary::False) = &x {
212            return y;
213        }
214        if let Expr::Const(Ternary::False) = &y {
215            return x;
216        }
217        // 毒值语义下无吸收律,只能做交换律规范化
218        let (a, b) = ordered(x, y);
219        return Expr::or(a, b);
220    }
221    if let Expr::Const(Ternary::True) = &x {
222        return Expr::Const(Ternary::True);
223    }
224    if let Expr::Const(Ternary::True) = &y {
225        return Expr::Const(Ternary::True);
226    }
227    if let Expr::Const(Ternary::False) = &x {
228        return y;
229    }
230    if let Expr::Const(Ternary::False) = &y {
231        return x;
232    }
233    if x == y {
234        return x;
235    }
236    if let Some(absorbed) = absorb(&x, &y) {
237        return absorbed;
238    }
239    if let Some(absorbed) = absorb(&y, &x) {
240        return absorbed;
241    }
242    let (a, b) = ordered(x, y);
243    Expr::or(a, b)
244}
245
246/// `⊕` 的重写规则。
247fn rewrite_xor(x: Expr, y: Expr, alg: Algebra) -> Expr {
248    if let (Expr::Const(a), Expr::Const(b)) = (&x, &y) {
249        return Expr::Const(alg.strong_add(*a, *b));
250    }
251    // Kleene 与 Bochvar 下 `X` 都传播为 `X`(Łukasiewicz 例外:X ⊕ X = 1)
252    if alg != Algebra::Lukasiewicz && (x.is_unknown_const() || y.is_unknown_const()) {
253        return Expr::Const(Ternary::Unknown);
254    }
255    // Ł3:X ⊕ X = 1
256    if alg == Algebra::Lukasiewicz && x.is_unknown_const() && y.is_unknown_const() {
257        return Expr::Const(Ternary::True);
258    }
259    if x == y && alg == Algebra::Kleene {
260        return Expr::Const(Ternary::Unknown);
261    }
262    let (a, b) = ordered(x, y);
263    Expr::xor(a, b)
264}
265
266/// `⇒` 的重写规则。
267fn rewrite_implies(x: Expr, y: Expr, alg: Algebra) -> Expr {
268    if let (Expr::Const(a), Expr::Const(b)) = (&x, &y) {
269        return Expr::Const(alg.implies(*a, *b));
270    }
271    // 0 ⇒ b = 1(K3 / Ł3);Bochvar 下 X 毒化
272    if alg != Algebra::Bochvar
273        && let Expr::Const(Ternary::False) = &x
274    {
275        return Expr::Const(Ternary::True);
276    }
277    Expr::implies(x, y)
278}
279
280/// `≡` 的重写规则。
281fn rewrite_equiv(x: Expr, y: Expr, alg: Algebra) -> Expr {
282    if let (Expr::Const(a), Expr::Const(b)) = (&x, &y) {
283        return Expr::Const(alg.equiv(*a, *b));
284    }
285    if x == y {
286        return Expr::Const(Ternary::True);
287    }
288    Expr::equiv(x, y)
289}
290
291/// 计算两个表达式的语义指纹(真值表摘要),用于快速判定等价。
292///
293/// 指纹相同当且仅当两表达式在给定语义下逻辑等价(变量集相同的前提下)。
294pub fn semantic_fingerprint(expr: &Expr, alg: Algebra) -> u64 {
295    let vars = expr.variables();
296    let tt = truth_table(expr, alg);
297    let mut hash = 1469598103934665603u64;
298    for v in &vars {
299        for b in v.as_bytes() {
300            hash ^= u64::from(*b);
301            hash = hash.wrapping_mul(1099511628211);
302        }
303        hash ^= 0xff;
304        hash = hash.wrapping_mul(1099511628211);
305    }
306    for val in &tt.values {
307        hash ^= u64::from(val.as_char() as u8);
308        hash = hash.wrapping_mul(1099511628211);
309    }
310    hash
311}
312
313/// 判断两个表达式在给定语义下语义等价(基于真值表指纹)。
314pub fn semantically_equal(a: &Expr, b: Expr, alg: Algebra) -> bool {
315    let mut va = a.variables();
316    for v in b.variables() {
317        if !va.contains(&v) {
318            va.push(v);
319        }
320    }
321    let mut vb = b.variables();
322    for v in va.iter() {
323        if !vb.contains(v) {
324            vb.push(v.clone());
325        }
326    }
327    // 变量集不同则不能直接比指纹,先做同变量集求值
328    let expr_a = rename_to(a, &va);
329    let expr_b = rename_to(&b, &vb);
330    semantic_fingerprint(&expr_a, alg) == semantic_fingerprint(&expr_b, alg)
331}
332
333/// 把表达式中的变量按给定顺序重命名到同名的规范位置。
334///
335/// 变量名本身已唯一,此函数仅用于确保两边按相同顺序求值;
336/// 由于指纹计算包含了变量名列表,实际只需保证两边变量集合一致。
337fn rename_to(expr: &Expr, vars: &[String]) -> Expr {
338    let _ = vars;
339    expr.clone()
340}
341
342/// 未使用的占位,保持 API 公开但标注用途。
343#[doc(hidden)]
344pub fn unused_var_map() -> VarMap {
345    VarMap::new()
346}
347
348#[cfg(test)]
349mod tests {
350    use super::*;
351    use trit_core::parser::Parser;
352
353    fn simp(src: &str, alg: Algebra) -> String {
354        let e = Parser::parse(src).unwrap();
355        simplify(&e, alg).to_infix()
356    }
357
358    #[test]
359    fn folds_constants() {
360        assert_eq!(simp("1 & 0", Algebra::Kleene), "0");
361        assert_eq!(simp("1 | 0", Algebra::Kleene), "1");
362        assert_eq!(simp("!1", Algebra::Kleene), "0");
363    }
364
365    #[test]
366    fn folds_semantic_constants() {
367        // 三值逻辑下的关键差异:`a ∨ ¬a` 不是重言式(a=X 时结果为 X),
368        // 因此不会被折叠成 1;而 `a ∧ ¬a` 同样不是恒假。
369        // 真正可折叠的语义常量需要用 X 安全前提,例如 `X ∨ 1 = 1`。
370        assert_eq!(simp("x | 1", Algebra::Kleene), "1");
371        assert_eq!(simp("x & 0", Algebra::Kleene), "0");
372        // 语义常量检测把恒定表达式折叠为常量
373        assert_eq!(simp("1 & 0 | 1", Algebra::Kleene), "1");
374        // 变量被吸收后,剩余部分仍是变量
375        let e = Parser::parse("a & 1 | b & 0").unwrap();
376        assert_eq!(simplify(&e, Algebra::Kleene), Expr::Var("a".into()));
377    }
378
379    #[test]
380    fn applies_idempotence_and_identity() {
381        assert_eq!(simp("a & a", Algebra::Kleene), "a");
382        assert_eq!(simp("a | a", Algebra::Kleene), "a");
383        assert_eq!(simp("a & 1", Algebra::Kleene), "a");
384        assert_eq!(simp("a | 0", Algebra::Kleene), "a");
385    }
386
387    #[test]
388    fn bochvar_poison_differs_from_kleene() {
389        // Bochvar: 0 ∧ X = X;Kleene: 0 ∧ X = 0
390        assert_eq!(simp("0 & x", Algebra::Bochvar), "X");
391        assert_eq!(simp("0 & x", Algebra::Kleene), "0");
392    }
393
394    #[test]
395    fn simplification_preserves_semantics() {
396        for src in [
397            "a & b | a",
398            "!(a & b)",
399            "(a => b) & (b => a)",
400            "a ^ b",
401            "a <=> b",
402            "a & 1 | b & 0",
403        ] {
404            let e = Parser::parse(src).unwrap();
405            let s = simplify(&e, Algebra::Kleene);
406            let r = crate::eval::equivalent(&e, &s, Algebra::Kleene);
407            assert!(r.equivalent, "simplify changed semantics: {src} -> {s}");
408        }
409    }
410
411    #[test]
412    fn simplification_preserves_semantics_in_bochvar() {
413        for src in ["a & b | a", "0 & x", "a | 1", "a & x"] {
414            let e = Parser::parse(src).unwrap();
415            let s = simplify(&e, Algebra::Bochvar);
416            let r = crate::eval::equivalent(&e, &s, Algebra::Bochvar);
417            assert!(
418                r.equivalent,
419                "bochvar simplify changed semantics: {src} -> {s}"
420            );
421        }
422    }
423}