Skip to main content

trit_eval/
eval.rs

1//! 表达式求值:把 [`Expr`] 在给定赋值或全部赋值上求值。
2
3use std::collections::{HashMap, HashSet};
4
5use trit_core::algebra::Algebra;
6use trit_core::ast::Expr;
7use trit_core::bits::{Evaluator, TriBit, TruthTable};
8use trit_core::limits::{LimitError, Limits, check_expr};
9use trit_core::value::Ternary;
10
11/// 变量赋值:一组 `变量名 → 取值`。
12#[derive(Debug, Clone, Default, PartialEq, Eq)]
13pub struct Assignment {
14    entries: Vec<(String, Ternary)>,
15}
16
17impl Assignment {
18    /// 空赋值。
19    pub fn new() -> Self {
20        Self::default()
21    }
22
23    /// 绑定一个变量。
24    pub fn set(&mut self, name: impl Into<String>, value: Ternary) -> &mut Self {
25        let name = name.into();
26        match self.entries.iter_mut().find(|(n, _)| *n == name) {
27            Some(slot) => slot.1 = value,
28            None => self.entries.push((name, value)),
29        }
30        self
31    }
32
33    /// 查询变量的取值;未绑定时返回 `None`。
34    pub fn get(&self, name: &str) -> Option<Ternary> {
35        self.entries
36            .iter()
37            .find(|(n, _)| n == name)
38            .map(|(_, v)| *v)
39    }
40
41    /// 已绑定的变量名。
42    pub fn variables(&self) -> Vec<String> {
43        self.entries.iter().map(|(n, _)| n.clone()).collect()
44    }
45
46    /// 赋值条目数。
47    pub fn len(&self) -> usize {
48        self.entries.len()
49    }
50
51    /// 是否为空。
52    pub fn is_empty(&self) -> bool {
53        self.entries.is_empty()
54    }
55}
56
57/// 单点求值:按赋值计算表达式值。
58///
59/// 未在赋值中出现的变量视为 `X`(未知)。递归实现,要求 AST 深度有界
60/// (经 [`Parser`](trit_core::parser::Parser) 解析的表达式满足这一点;
61/// 手工构造的深树请先调用 `check_expr`)。
62pub fn eval(expr: &Expr, assignment: &Assignment, alg: Algebra) -> Ternary {
63    match expr {
64        Expr::Const(v) => *v,
65        Expr::Var(name) => assignment.get(name).unwrap_or(Ternary::Unknown),
66        Expr::Not(a) => alg.not(eval(a, assignment, alg)),
67        Expr::And(a, b) => alg.and(eval(a, assignment, alg), eval(b, assignment, alg)),
68        Expr::Or(a, b) => alg.or(eval(a, assignment, alg), eval(b, assignment, alg)),
69        Expr::Xor(a, b) => alg.strong_add(eval(a, assignment, alg), eval(b, assignment, alg)),
70        Expr::Implies(a, b) => alg.implies(eval(a, assignment, alg), eval(b, assignment, alg)),
71        Expr::Equiv(a, b) => alg.equiv(eval(a, assignment, alg), eval(b, assignment, alg)),
72    }
73}
74
75/// 变量名 → 位平面下标的映射。
76pub type VarMap = HashMap<String, usize>;
77
78/// 位并行求值:把表达式编译成对位平面的操作。
79pub fn eval_bitwise(expr: &Expr, planes: &[TriBit], vars: &VarMap, alg: Algebra) -> TriBit {
80    match expr {
81        Expr::Const(v) => TriBit::constant(*v),
82        Expr::Var(name) => match vars.get(name) {
83            Some(idx) => planes.get(*idx).copied().unwrap_or(TriBit::UNKNOWN),
84            None => TriBit::UNKNOWN,
85        },
86        Expr::Not(a) => eval_bitwise(a, planes, vars, alg).not(),
87        Expr::And(a, b) => {
88            let (x, y) = (
89                eval_bitwise(a, planes, vars, alg),
90                eval_bitwise(b, planes, vars, alg),
91            );
92            x.and(y, alg)
93        }
94        Expr::Or(a, b) => {
95            let (x, y) = (
96                eval_bitwise(a, planes, vars, alg),
97                eval_bitwise(b, planes, vars, alg),
98            );
99            x.or(y, alg)
100        }
101        Expr::Xor(a, b) => {
102            let (x, y) = (
103                eval_bitwise(a, planes, vars, alg),
104                eval_bitwise(b, planes, vars, alg),
105            );
106            x.strong_add(y, alg)
107        }
108        Expr::Implies(a, b) => {
109            let (x, y) = (
110                eval_bitwise(a, planes, vars, alg),
111                eval_bitwise(b, planes, vars, alg),
112            );
113            x.implies(y, alg)
114        }
115        Expr::Equiv(a, b) => {
116            let (x, y) = (
117                eval_bitwise(a, planes, vars, alg),
118                eval_bitwise(b, planes, vars, alg),
119            );
120            x.equiv(y, alg)
121        }
122    }
123}
124
125/// 构造求值器并返回「变量名 → 下标」映射。
126fn evaluator_for(vars: &[String], alg: Algebra) -> (Evaluator, VarMap) {
127    let mut ev = Evaluator::new(alg);
128    let mut map = VarMap::new();
129    for name in vars {
130        let idx = ev.declare(name.clone());
131        map.insert(name.clone(), idx);
132    }
133    (ev, map)
134}
135
136/// 全真值表求值(默认预算)。
137///
138/// 变量顺序取自 [`Expr::variables`](首次出现顺序)。默认预算限制为
139/// [`Limits::default`] 的变量数与行数,超出时返回错误而不是尝试分配。
140pub fn truth_table(expr: &Expr, alg: Algebra) -> Result<TruthTable, LimitError> {
141    truth_table_within(expr, alg, Limits::default())
142}
143
144/// 两个表达式在给定语义下是否等价(真值表完全相同)。
145#[derive(Debug, Clone, PartialEq, Eq)]
146pub struct EquivalenceResult {
147    /// 是否等价。
148    pub equivalent: bool,
149    /// 第一个反例的赋值编号(`None` 表示等价或编号超出 u64)。
150    pub counterexample: Option<u64>,
151    /// 第一个反例的完整赋值(等价时为 `None`)。
152    pub counterexample_assignment: Option<Assignment>,
153    /// 参与比较的变量数。
154    pub variable_count: usize,
155}
156
157/// 判断两个表达式在给定语义下是否逻辑等价(默认预算)。
158pub fn equivalent(a: &Expr, b: &Expr, alg: Algebra) -> Result<EquivalenceResult, LimitError> {
159    let limits = Limits::default();
160    check_expr(a, limits)?;
161    check_expr(b, limits)?;
162    // 变量取并集,保证两边在同一组赋值上比较
163    let vars = union_vars(a, b);
164    equivalent_with_vars(a, b, alg, &vars, limits)
165}
166
167fn union_vars(a: &Expr, b: &Expr) -> Vec<String> {
168    let mut vars = a.variables();
169    for v in b.variables() {
170        if !vars.contains(&v) {
171            vars.push(v);
172        }
173    }
174    vars
175}
176
177fn equivalent_with_vars(
178    a: &Expr,
179    b: &Expr,
180    alg: Algebra,
181    vars: &[String],
182    limits: Limits,
183) -> Result<EquivalenceResult, LimitError> {
184    if vars.len() > limits.max_vars {
185        return Err(LimitError::Vars {
186            limit: limits.max_vars,
187        });
188    }
189    let (ev, map) = evaluator_for(vars, alg);
190    let total = ev.assignment_count()?;
191    if total > limits.max_rows as u64 {
192        return Err(LimitError::Rows {
193            limit: limits.max_rows,
194        });
195    }
196    let mut base = 0u64;
197    while base < total {
198        let planes = ev.chunk_planes(base)?;
199        let va = eval_bitwise(a, &planes, &map, alg);
200        let vb = eval_bitwise(b, &planes, &map, alg);
201        let take = (total - base).min(64) as u32;
202        for bit in 0..take {
203            if va.get(bit) != vb.get(bit) {
204                let index = base + bit as u64;
205                return Ok(EquivalenceResult {
206                    equivalent: false,
207                    counterexample: Some(index),
208                    counterexample_assignment: Some(decode_assignment(index, vars)),
209                    variable_count: vars.len(),
210                });
211            }
212        }
213        base += 64;
214    }
215    Ok(EquivalenceResult {
216        equivalent: true,
217        counterexample: None,
218        counterexample_assignment: None,
219        variable_count: vars.len(),
220    })
221}
222
223/// 赋值编号编解码错误。
224#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
225pub enum AssignmentCodecError {
226    /// 具体编号超出 `u64`。
227    #[error("变量数 {vars} 的赋值编号超出 u64 可表示范围")]
228    Overflow {
229        /// 变量数。
230        vars: usize,
231    },
232    /// 编号超出该变量域。
233    #[error("赋值编号 {index} 超出 {vars} 个变量的有效域 3^{vars}")]
234    OutOfDomain {
235        /// 编号。
236        index: u64,
237        /// 变量数。
238        vars: usize,
239    },
240    /// 变量名重复,编码不是双射。
241    #[error("变量名重复:{0}")]
242    DuplicateVariable(String),
243}
244
245/// 把赋值编码成编号;无效域返回可分类的错误。
246///
247/// 编号约定:False=0、True=1、Unknown=2;变量 `i` 占第 `i` 个三进制位。
248pub fn try_assignment_index(
249    assignment: &Assignment,
250    vars: &[String],
251) -> Result<u64, AssignmentCodecError> {
252    let mut seen = HashSet::new();
253    let mut index = 0u64;
254    let mut power = 1u64;
255    let mut power_overflow = false;
256    for (i, name) in vars.iter().enumerate() {
257        if !seen.insert(name.as_str()) {
258            return Err(AssignmentCodecError::DuplicateVariable(name.clone()));
259        }
260        if i > 0 {
261            match power.checked_mul(3) {
262                Some(next) => power = next,
263                None => power_overflow = true,
264            }
265        }
266        let digit = match assignment.get(name).unwrap_or(Ternary::Unknown) {
267            Ternary::False => 0u64,
268            Ternary::True => 1u64,
269            Ternary::Unknown => 2u64,
270        };
271        if digit == 0 {
272            continue;
273        }
274        if power_overflow {
275            return Err(AssignmentCodecError::Overflow { vars: vars.len() });
276        }
277        let term = digit
278            .checked_mul(power)
279            .ok_or(AssignmentCodecError::Overflow { vars: vars.len() })?;
280        index = index
281            .checked_add(term)
282            .ok_or(AssignmentCodecError::Overflow { vars: vars.len() })?;
283    }
284    Ok(index)
285}
286
287/// 把赋值编码成编号;无效域返回 `None`。
288///
289/// 这是 [`try_assignment_index`] 的便捷包装;需要区分溢出与重复变量时用后者。
290pub fn assignment_index(assignment: &Assignment, vars: &[String]) -> Option<u64> {
291    try_assignment_index(assignment, vars).ok()
292}
293
294/// 把三进制赋值编号解码为各变量的取值;编号超出变量域时返回错误。
295///
296/// 与 [`decode_assignment`] 不同:拒绝重复变量名,并要求消费完 `vars.len()`
297/// 个三进制位后高位为 0。
298pub fn try_decode_assignment(
299    index: u64,
300    vars: &[String],
301) -> Result<Assignment, AssignmentCodecError> {
302    let mut seen = HashSet::new();
303    for name in vars {
304        if !seen.insert(name.as_str()) {
305            return Err(AssignmentCodecError::DuplicateVariable(name.clone()));
306        }
307    }
308    let mut asg = Assignment::new();
309    let mut t = index;
310    for name in vars {
311        let digit = t % 3;
312        t /= 3;
313        let v = match digit {
314            0 => Ternary::False,
315            1 => Ternary::True,
316            _ => Ternary::Unknown,
317        };
318        asg.set(name.clone(), v);
319    }
320    if t != 0 {
321        return Err(AssignmentCodecError::OutOfDomain {
322            index,
323            vars: vars.len(),
324        });
325    }
326    Ok(asg)
327}
328
329/// 把三进制赋值编号解码为各变量的取值。
330///
331/// **不检查有效域**:高位被忽略、重复变量名会覆盖前值。边界输入请用
332/// [`try_decode_assignment`]。
333pub fn decode_assignment(index: u64, vars: &[String]) -> Assignment {
334    let mut asg = Assignment::new();
335    let mut t = index;
336    for name in vars {
337        let digit = t % 3;
338        t /= 3;
339        let v = match digit {
340            0 => Ternary::False,
341            1 => Ternary::True,
342            _ => Ternary::Unknown,
343        };
344        asg.set(name.clone(), v);
345    }
346    asg
347}
348
349/// 带预算的单点求值。
350pub fn eval_within(
351    expr: &Expr,
352    assignment: &Assignment,
353    alg: Algebra,
354    limits: Limits,
355) -> Result<Ternary, LimitError> {
356    check_expr(expr, limits)?;
357    Ok(eval(expr, assignment, alg))
358}
359
360/// 带预算的真值表(限制 AST 深度/节点数、变量数与行数)。
361pub fn truth_table_within(
362    expr: &Expr,
363    alg: Algebra,
364    limits: Limits,
365) -> Result<TruthTable, LimitError> {
366    check_expr(expr, limits)?;
367    let vars = expr.variables();
368    if vars.len() > limits.max_vars {
369        return Err(LimitError::Vars {
370            limit: limits.max_vars,
371        });
372    }
373    let (ev, map) = evaluator_for(&vars, alg);
374    ev.evaluate_within(|planes| eval_bitwise(expr, planes, &map, alg), limits)
375}
376
377/// 带预算的穷举等价。
378pub fn equivalent_within(
379    a: &Expr,
380    b: &Expr,
381    alg: Algebra,
382    limits: Limits,
383) -> Result<EquivalenceResult, LimitError> {
384    check_expr(a, limits)?;
385    check_expr(b, limits)?;
386    let vars = union_vars(a, b);
387    equivalent_with_vars(a, b, alg, &vars, limits)
388}
389
390#[cfg(test)]
391mod tests {
392    use super::*;
393    use trit_core::parser::Parser;
394
395    #[test]
396    fn eval_single_assignment() {
397        let e = Parser::parse("a & b").unwrap();
398        let mut asg = Assignment::new();
399        asg.set("a", Ternary::True).set("b", Ternary::False);
400        assert_eq!(eval(&e, &asg, Algebra::Kleene), Ternary::False);
401    }
402
403    #[test]
404    fn unbound_variable_is_unknown() {
405        let e = Parser::parse("a").unwrap();
406        assert_eq!(
407            eval(&e, &Assignment::new(), Algebra::Kleene),
408            Ternary::Unknown
409        );
410    }
411
412    #[test]
413    fn truth_table_covers_all_rows() {
414        let e = Parser::parse("a | b").unwrap();
415        let tt = truth_table(&e, Algebra::Kleene).unwrap();
416        assert_eq!(tt.variables.len(), 2);
417        assert_eq!(tt.values.len(), 9);
418    }
419
420    #[test]
421    fn truth_table_matches_scalar_evaluation() {
422        let e = Parser::parse("(a & b) | (!a & c)").unwrap();
423        let vars = e.variables();
424        let tt = truth_table(&e, Algebra::Kleene).unwrap();
425        for (i, expected) in tt.values.iter().enumerate() {
426            let asg = decode_assignment(i as u64, &vars);
427            assert_eq!(eval(&e, &asg, Algebra::Kleene), *expected, "row {i}");
428        }
429    }
430
431    #[test]
432    fn truth_table_refuses_unbudgeted_variable_count() {
433        let e = Parser::parse(
434            &(0..13)
435                .map(|i| format!("v{i}"))
436                .collect::<Vec<_>>()
437                .join(" & "),
438        )
439        .unwrap();
440        assert_eq!(
441            truth_table(&e, Algebra::Kleene).unwrap_err(),
442            LimitError::Vars { limit: 12 }
443        );
444    }
445
446    #[test]
447    fn equivalent_detects_equal_expressions() {
448        let a = Parser::parse("a & b").unwrap();
449        let b = Parser::parse("b & a").unwrap();
450        let r = equivalent(&a, &b, Algebra::Kleene).unwrap();
451        assert!(r.equivalent);
452        assert!(r.counterexample.is_none());
453    }
454
455    #[test]
456    fn equivalent_finds_counterexample() {
457        let a = Parser::parse("a & b").unwrap();
458        let b = Parser::parse("a | b").unwrap();
459        let r = equivalent(&a, &b, Algebra::Kleene).unwrap();
460        assert!(!r.equivalent);
461        assert!(r.counterexample.is_some());
462    }
463
464    #[test]
465    fn decode_assignment_round_trips() {
466        let vars = vec!["a".to_string(), "b".to_string()];
467        let asg = decode_assignment(0, &vars);
468        assert_eq!(asg.get("a"), Some(Ternary::False));
469        assert_eq!(asg.get("b"), Some(Ternary::False));
470        let asg = decode_assignment(5, &vars);
471        // 变量 0 取最低三进制位:5 = 2 + 1*3 → a=2(unknown), b=1(true)
472        assert_eq!(asg.get("a"), Some(Ternary::Unknown));
473        assert_eq!(asg.get("b"), Some(Ternary::True));
474    }
475
476    #[test]
477    fn checked_codec_rejects_out_of_domain_and_duplicates() {
478        let one = vec!["a".to_string()];
479        assert_eq!(
480            try_decode_assignment(3, &one).unwrap_err(),
481            AssignmentCodecError::OutOfDomain { index: 3, vars: 1 }
482        );
483        assert!(try_decode_assignment(2, &one).is_ok());
484        let dup = vec!["a".to_string(), "a".to_string()];
485        assert!(matches!(
486            try_decode_assignment(0, &dup).unwrap_err(),
487            AssignmentCodecError::DuplicateVariable(_)
488        ));
489        let mut asg = Assignment::new();
490        asg.set("a", Ternary::False);
491        assert!(matches!(
492            try_assignment_index(&asg, &dup).unwrap_err(),
493            AssignmentCodecError::DuplicateVariable(_)
494        ));
495    }
496
497    #[test]
498    fn assignment_index_does_not_over_reject_high_zero_digits() {
499        // 42 个变量全 False:编号仍是 0,不应因 3^42 溢出而拒绝。
500        let vars: Vec<String> = (0..42).map(|i| format!("v{i}")).collect();
501        let mut all_false = Assignment::new();
502        for name in &vars {
503            all_false.set(name.clone(), Ternary::False);
504        }
505        assert_eq!(assignment_index(&all_false, &vars), Some(0));
506        // 3^40 仍可表示;3^41 起才真正溢出。
507        let mut high = all_false.clone();
508        high.set("v40", Ternary::True);
509        assert_eq!(assignment_index(&high, &vars), Some(3u64.pow(40)));
510        let mut over = all_false;
511        over.set("v41", Ternary::True);
512        assert!(matches!(
513            try_assignment_index(&over, &vars).unwrap_err(),
514            AssignmentCodecError::Overflow { .. }
515        ));
516    }
517}