1use crate::Node;
6use crate::{Expr, Literal, Name};
7use std::rc::Rc;
8
9use super::types::{
10 ConfigNode, DecisionNode, Either2, Fixture, FlatSubstitution, FocusStack, LabelSet, MinHeap,
11 NonEmptyVec, PathBuf, PrefixCounter, RewriteRule, RewriteRuleSet, SimpDirection, SimpLemma,
12 SimpLemmaSet, SimpResult, SimpleDag, SlidingSum, SmallMap, SparseVec, StackCalc, StatSummary,
13 Stopwatch, StringPool, TokenBucket, TransformStat, TransitiveClosure, VersionedRecord,
14 WindowIterator, WriteOnce,
15};
16
17pub fn simplify(expr: &Expr) -> Expr {
19 match expr {
20 Expr::App(f, a) => {
21 let f_simp = simplify(f);
22 let a_simp = simplify(a);
23 if let Expr::Const(name, _) = &f_simp {
24 if let Some(result) = try_simplify_nat_op(name, &a_simp) {
25 return result;
26 }
27 }
28 Expr::App(Node::new(f_simp), Node::new(a_simp))
29 }
30 Expr::Lam(bi, name, ty, body) => Expr::Lam(
31 *bi,
32 name.clone(),
33 Node::new(simplify(ty)),
34 Node::new(simplify(body)),
35 ),
36 Expr::Pi(bi, name, ty, body) => Expr::Pi(
37 *bi,
38 name.clone(),
39 Node::new(simplify(ty)),
40 Node::new(simplify(body)),
41 ),
42 Expr::Let(name, ty, val, body) => Expr::Let(
43 name.clone(),
44 Node::new(simplify(ty)),
45 Node::new(simplify(val)),
46 Node::new(simplify(body)),
47 ),
48 _ => expr.clone(),
49 }
50}
51fn try_simplify_nat_op(name: &Name, arg: &Expr) -> Option<Expr> {
52 match name.to_string().as_str() {
53 "Nat.succ" => {
54 if let Expr::Lit(Literal::Nat(n)) = arg {
55 Some(Expr::Lit(Literal::Nat(n.succ())))
56 } else {
57 None
58 }
59 }
60 _ => None,
61 }
62}
63pub fn normalize(expr: &Expr) -> Expr {
65 use crate::Reducer;
66 let mut reducer = Reducer::new();
67 let whnf = reducer.whnf(expr);
68 match &whnf {
69 Expr::Lam(bi, name, ty, body) => Expr::Lam(
70 *bi,
71 name.clone(),
72 Node::new(normalize(ty)),
73 Node::new(normalize(body)),
74 ),
75 Expr::Pi(bi, name, ty, body) => Expr::Pi(
76 *bi,
77 name.clone(),
78 Node::new(normalize(ty)),
79 Node::new(normalize(body)),
80 ),
81 Expr::App(f, a) => Expr::App(Node::new(normalize(f)), Node::new(normalize(a))),
82 _ => whnf,
83 }
84}
85pub fn alpha_eq(e1: &Expr, e2: &Expr) -> bool {
87 match (e1, e2) {
88 (Expr::Sort(l1), Expr::Sort(l2)) => l1 == l2,
89 (Expr::BVar(i1), Expr::BVar(i2)) => i1 == i2,
90 (Expr::FVar(f1), Expr::FVar(f2)) => f1 == f2,
91 (Expr::Const(n1, ls1), Expr::Const(n2, ls2)) => n1 == n2 && ls1 == ls2,
92 (Expr::App(f1, a1), Expr::App(f2, a2)) => alpha_eq(f1, f2) && alpha_eq(a1, a2),
93 (Expr::Lam(_, _, ty1, b1), Expr::Lam(_, _, ty2, b2)) => {
94 alpha_eq(ty1, ty2) && alpha_eq(b1, b2)
95 }
96 (Expr::Pi(_, _, ty1, b1), Expr::Pi(_, _, ty2, b2)) => {
97 alpha_eq(ty1, ty2) && alpha_eq(b1, b2)
98 }
99 (Expr::Let(_, ty1, v1, b1), Expr::Let(_, ty2, v2, b2)) => {
100 alpha_eq(ty1, ty2) && alpha_eq(v1, v2) && alpha_eq(b1, b2)
101 }
102 (Expr::Lit(l1), Expr::Lit(l2)) => l1 == l2,
103 (Expr::Proj(n1, i1, e1), Expr::Proj(n2, i2, e2)) => {
104 n1 == n2 && i1 == i2 && alpha_eq(e1, e2)
105 }
106 _ => false,
107 }
108}
109#[cfg(test)]
110mod tests {
111 use super::*;
112 use crate::{BinderInfo, Level, Literal, Name};
113 #[test]
114 fn test_simplify_nat_succ() {
115 let expr = Expr::App(
116 Node::new(Expr::Const(Name::str("Nat.succ"), vec![])),
117 Node::new(Expr::Lit(Literal::nat(5))),
118 );
119 let result = simplify(&expr);
120 assert_eq!(result, Expr::Lit(Literal::nat(6)));
121 }
122 #[test]
123 fn test_alpha_eq_bvar() {
124 let e1 = Expr::BVar(0);
125 let e2 = Expr::BVar(0);
126 assert!(alpha_eq(&e1, &e2));
127 }
128 #[test]
129 fn test_alpha_eq_lambda() {
130 let lam1 = Expr::Lam(
131 BinderInfo::Default,
132 Name::str("x"),
133 Node::new(Expr::Sort(Level::zero())),
134 Node::new(Expr::BVar(0)),
135 );
136 let lam2 = Expr::Lam(
137 BinderInfo::Default,
138 Name::str("y"),
139 Node::new(Expr::Sort(Level::zero())),
140 Node::new(Expr::BVar(0)),
141 );
142 assert!(alpha_eq(&lam1, &lam2));
143 }
144 #[test]
145 fn test_alpha_eq_different() {
146 let e1 = Expr::Lit(Literal::nat(1));
147 let e2 = Expr::Lit(Literal::nat(2));
148 assert!(!alpha_eq(&e1, &e2));
149 }
150}
151pub fn is_app_of(expr: &Expr, head_name: &str) -> bool {
153 match expr {
154 Expr::App(f, _) => is_app_of(f, head_name),
155 Expr::Const(n, _) => n.to_string() == head_name,
156 _ => false,
157 }
158}
159pub fn decompose_app(expr: &Expr) -> (&Expr, Vec<&Expr>) {
163 let mut args = Vec::new();
164 let mut current = expr;
165 while let Expr::App(f, a) = current {
166 args.push(a.as_ref());
167 current = f;
168 }
169 args.reverse();
170 (current, args)
171}
172pub fn mk_app(head: Expr, args: Vec<Expr>) -> Expr {
174 args.into_iter()
175 .fold(head, |f, a| Expr::App(Node::new(f), Node::new(a)))
176}
177pub fn eval_nat(expr: &Expr) -> Option<crate::bignat::BigNat> {
184 use crate::bignat::BigNat;
185 match expr {
186 Expr::Lit(Literal::Nat(n)) => Some(n.clone()),
187 Expr::Const(name, _) if name.to_string() == "Nat.zero" => Some(BigNat::zero()),
188 Expr::App(f, a) => {
189 if let Expr::Const(name, _) = f.as_ref() {
190 match name.to_string().as_str() {
191 "Nat.succ" => return eval_nat(a).map(|n| n.succ()),
192 "Nat.pred" => return eval_nat(a).map(|n| n.pred()),
193 _ => {}
194 }
195 }
196 if let Expr::App(f2, a2) = f.as_ref() {
197 if let Expr::Const(name, _) = f2.as_ref() {
198 let name_str = name.to_string();
199 let lhs = eval_nat(a2)?;
200 let rhs = eval_nat(a)?;
201 return match name_str.as_str() {
202 "Nat.min" => Some(if lhs <= rhs { lhs } else { rhs }),
205 "Nat.max" => Some(if lhs >= rhs { lhs } else { rhs }),
206 op => crate::reduce::eval_nat_binop(op, &lhs, &rhs),
207 };
208 }
209 }
210 None
211 }
212 _ => None,
213 }
214}
215pub fn simp_congruence(expr: &Expr) -> Expr {
217 match expr {
218 Expr::App(f, a) => Expr::App(Node::new(simplify(f)), Node::new(simplify(a))),
219 Expr::Lam(bi, name, ty, body) => Expr::Lam(
220 *bi,
221 name.clone(),
222 Node::new(simplify(ty)),
223 Node::new(simplify(body)),
224 ),
225 Expr::Pi(bi, name, ty, body) => Expr::Pi(
226 *bi,
227 name.clone(),
228 Node::new(simplify(ty)),
229 Node::new(simplify(body)),
230 ),
231 Expr::Let(name, ty, val, body) => Expr::Let(
232 name.clone(),
233 Node::new(simplify(ty)),
234 Node::new(simplify(val)),
235 Node::new(simplify(body)),
236 ),
237 other => other.clone(),
238 }
239}
240pub fn simplify_bounded(expr: &Expr, max_depth: usize) -> Expr {
242 if max_depth == 0 {
243 return expr.clone();
244 }
245 let simp_sub = |e: &Expr| simplify_bounded(e, max_depth - 1);
246 match expr {
247 Expr::App(f, a) => {
248 let f_s = simp_sub(f);
249 let a_s = simp_sub(a);
250 if let Expr::Const(name, _) = &f_s {
251 if let Some(r) = try_simplify_nat_op(name, &a_s) {
252 return r;
253 }
254 }
255 Expr::App(Node::new(f_s), Node::new(a_s))
256 }
257 Expr::Lam(bi, name, ty, body) => Expr::Lam(
258 *bi,
259 name.clone(),
260 Node::new(simp_sub(ty)),
261 Node::new(simp_sub(body)),
262 ),
263 Expr::Pi(bi, name, ty, body) => Expr::Pi(
264 *bi,
265 name.clone(),
266 Node::new(simp_sub(ty)),
267 Node::new(simp_sub(body)),
268 ),
269 other => other.clone(),
270 }
271}
272pub fn eta_reduce(expr: &Expr) -> Expr {
276 match expr {
277 Expr::Lam(_, _, _, body) => {
278 if let Expr::App(f, a) = body.as_ref() {
279 if matches!(a.as_ref(), Expr::BVar(0)) && !contains_bvar(f, 0) {
280 return shift_bvars(f, -1, 0);
281 }
282 }
283 expr.clone()
284 }
285 _ => expr.clone(),
286 }
287}
288pub fn contains_bvar(expr: &Expr, idx: u32) -> bool {
290 match expr {
291 Expr::BVar(i) => *i == idx,
292 Expr::App(f, a) => contains_bvar(f, idx) || contains_bvar(a, idx),
293 Expr::Lam(_, _, ty, body) => contains_bvar(ty, idx) || contains_bvar(body, idx + 1),
294 Expr::Pi(_, _, ty, body) => contains_bvar(ty, idx) || contains_bvar(body, idx + 1),
295 Expr::Let(_, ty, val, body) => {
296 contains_bvar(ty, idx) || contains_bvar(val, idx) || contains_bvar(body, idx + 1)
297 }
298 _ => false,
299 }
300}
301fn shift_bvars(expr: &Expr, shift: i32, cutoff: u32) -> Expr {
303 match expr {
304 Expr::BVar(i) => {
305 if *i >= cutoff {
306 let new_i = (*i as i32 + shift).max(0) as u32;
307 Expr::BVar(new_i)
308 } else {
309 expr.clone()
310 }
311 }
312 Expr::App(f, a) => Expr::App(
313 Node::new(shift_bvars(f, shift, cutoff)),
314 Node::new(shift_bvars(a, shift, cutoff)),
315 ),
316 Expr::Lam(bi, name, ty, body) => Expr::Lam(
317 *bi,
318 name.clone(),
319 Node::new(shift_bvars(ty, shift, cutoff)),
320 Node::new(shift_bvars(body, shift, cutoff + 1)),
321 ),
322 Expr::Pi(bi, name, ty, body) => Expr::Pi(
323 *bi,
324 name.clone(),
325 Node::new(shift_bvars(ty, shift, cutoff)),
326 Node::new(shift_bvars(body, shift, cutoff + 1)),
327 ),
328 other => other.clone(),
329 }
330}
331pub fn expr_size(expr: &Expr) -> usize {
333 match expr {
334 Expr::App(f, a) => 1 + expr_size(f) + expr_size(a),
335 Expr::Lam(_, _, ty, body) | Expr::Pi(_, _, ty, body) => 1 + expr_size(ty) + expr_size(body),
336 Expr::Let(_, ty, val, body) => 1 + expr_size(ty) + expr_size(val) + expr_size(body),
337 Expr::Proj(_, _, inner) => 1 + expr_size(inner),
338 _ => 1,
339 }
340}
341pub fn expr_depth(expr: &Expr) -> usize {
343 match expr {
344 Expr::App(f, a) => 1 + expr_depth(f).max(expr_depth(a)),
345 Expr::Lam(_, _, ty, body) | Expr::Pi(_, _, ty, body) => {
346 1 + expr_depth(ty).max(expr_depth(body))
347 }
348 Expr::Let(_, ty, val, body) => {
349 1 + expr_depth(ty).max(expr_depth(val)).max(expr_depth(body))
350 }
351 Expr::Proj(_, _, inner) => 1 + expr_depth(inner),
352 _ => 0,
353 }
354}
355#[cfg(test)]
356mod simp_extra_tests {
357 use super::*;
358 use crate::Name;
359 #[test]
360 fn test_is_app_of() {
361 let e = Expr::App(
362 Node::new(Expr::App(
363 Node::new(Expr::Const(Name::str("Nat.add"), vec![])),
364 Node::new(Expr::Lit(Literal::nat(1))),
365 )),
366 Node::new(Expr::Lit(Literal::nat(2))),
367 );
368 assert!(is_app_of(&e, "Nat.add"));
369 assert!(!is_app_of(&e, "Nat.mul"));
370 }
371 #[test]
372 fn test_decompose_app() {
373 let e = Expr::App(
374 Node::new(Expr::App(
375 Node::new(Expr::Const(Name::str("f"), vec![])),
376 Node::new(Expr::Lit(Literal::nat(1))),
377 )),
378 Node::new(Expr::Lit(Literal::nat(2))),
379 );
380 let (head, args) = decompose_app(&e);
381 assert!(matches!(head, Expr::Const(_, _)));
382 assert_eq!(args.len(), 2);
383 }
384 #[test]
385 fn test_eval_nat_literal() {
386 let e = Expr::Lit(Literal::nat(42));
387 assert_eq!(eval_nat(&e), Some(crate::bignat::BigNat::from(42u64)));
388 }
389 #[test]
390 fn test_eval_nat_succ() {
391 let e = Expr::App(
392 Node::new(Expr::Const(Name::str("Nat.succ"), vec![])),
393 Node::new(Expr::Lit(Literal::nat(4))),
394 );
395 assert_eq!(eval_nat(&e), Some(crate::bignat::BigNat::from(5u64)));
396 }
397 #[test]
398 fn test_eval_nat_add() {
399 let e = Expr::App(
400 Node::new(Expr::App(
401 Node::new(Expr::Const(Name::str("Nat.add"), vec![])),
402 Node::new(Expr::Lit(Literal::nat(3))),
403 )),
404 Node::new(Expr::Lit(Literal::nat(7))),
405 );
406 assert_eq!(eval_nat(&e), Some(crate::bignat::BigNat::from(10u64)));
407 }
408 #[test]
409 fn test_eval_nat_pred() {
410 let e = Expr::App(
411 Node::new(Expr::Const(Name::str("Nat.pred"), vec![])),
412 Node::new(Expr::Lit(Literal::nat(5))),
413 );
414 assert_eq!(eval_nat(&e), Some(crate::bignat::BigNat::from(4u64)));
415 let e_zero = Expr::App(
416 Node::new(Expr::Const(Name::str("Nat.pred"), vec![])),
417 Node::new(Expr::Lit(Literal::nat(0))),
418 );
419 assert_eq!(eval_nat(&e_zero), Some(crate::bignat::BigNat::from(0u64)));
420 }
421 #[test]
422 fn test_eval_nat_pow() {
423 let e = Expr::App(
424 Node::new(Expr::App(
425 Node::new(Expr::Const(Name::str("Nat.pow"), vec![])),
426 Node::new(Expr::Lit(Literal::nat(2))),
427 )),
428 Node::new(Expr::Lit(Literal::nat(3))),
429 );
430 assert_eq!(eval_nat(&e), Some(crate::bignat::BigNat::from(8u64)));
431 }
432 #[test]
433 fn test_simplify_nat_succ_chain() {
434 let e = Expr::App(
435 Node::new(Expr::Const(Name::str("Nat.succ"), vec![])),
436 Node::new(Expr::App(
437 Node::new(Expr::Const(Name::str("Nat.succ"), vec![])),
438 Node::new(Expr::Lit(Literal::nat(0))),
439 )),
440 );
441 let result = simplify(&e);
442 assert_eq!(result, Expr::Lit(Literal::nat(2)));
443 }
444 #[test]
445 fn test_contains_bvar() {
446 assert!(contains_bvar(&Expr::BVar(0), 0));
447 assert!(!contains_bvar(&Expr::BVar(1), 0));
448 let app = Expr::App(Node::new(Expr::BVar(0)), Node::new(Expr::BVar(1)));
449 assert!(contains_bvar(&app, 0));
450 assert!(contains_bvar(&app, 1));
451 assert!(!contains_bvar(&app, 2));
452 }
453 #[test]
454 fn test_expr_size() {
455 let lit = Expr::Lit(Literal::nat(1));
456 assert_eq!(expr_size(&lit), 1);
457 let app = Expr::App(Node::new(lit.clone()), Node::new(lit.clone()));
458 assert_eq!(expr_size(&app), 3);
459 }
460 #[test]
461 fn test_expr_depth() {
462 let lit = Expr::Lit(Literal::nat(1));
463 assert_eq!(expr_depth(&lit), 0);
464 let app = Expr::App(Node::new(lit.clone()), Node::new(lit.clone()));
465 assert_eq!(expr_depth(&app), 1);
466 }
467 #[test]
468 fn test_simp_lemma_reversed() {
469 let lhs = Expr::Lit(Literal::nat(1));
470 let rhs = Expr::Lit(Literal::nat(2));
471 let lemma = SimpLemma::forward(Name::str("test"), lhs.clone(), rhs.clone());
472 assert_eq!(lemma.direction, SimpDirection::Forward);
473 let rev = lemma.reversed();
474 assert_eq!(rev.direction, SimpDirection::Backward);
475 }
476 #[test]
477 fn test_mk_app() {
478 let head = Expr::Const(Name::str("f"), vec![]);
479 let args = vec![Expr::Lit(Literal::nat(1)), Expr::Lit(Literal::nat(2))];
480 let e = mk_app(head, args);
481 assert!(matches!(e, Expr::App(_, _)));
482 }
483 #[test]
484 fn test_simplify_bounded_depth_zero() {
485 let e = Expr::App(
486 Node::new(Expr::Const(Name::str("Nat.succ"), vec![])),
487 Node::new(Expr::Lit(Literal::nat(5))),
488 );
489 let result = simplify_bounded(&e, 0);
490 assert_eq!(result, e);
491 }
492 #[test]
493 fn test_alpha_eq_lit() {
494 let e1 = Expr::Lit(Literal::nat(42));
495 let e2 = Expr::Lit(Literal::nat(42));
496 let e3 = Expr::Lit(Literal::nat(43));
497 assert!(alpha_eq(&e1, &e2));
498 assert!(!alpha_eq(&e1, &e3));
499 }
500 #[test]
501 fn test_eta_reduce_no_change() {
502 let e = Expr::Lit(Literal::nat(5));
503 assert_eq!(eta_reduce(&e), e);
504 }
505}
506pub fn is_nat_lit(expr: &Expr, n: u64) -> bool {
508 matches!(expr, Expr::Lit(Literal::Nat(m)) if * m == n)
509}
510pub fn is_zero(expr: &Expr) -> bool {
512 is_nat_lit(expr, 0) || matches!(expr, Expr::Const(name, _) if name.to_string() == "Nat.zero")
513}
514pub fn is_succ(expr: &Expr) -> bool {
516 matches!(
517 expr, Expr::App(f, _) if matches!(f.as_ref(), Expr::Const(name, _) if name
518 .to_string() == "Nat.succ")
519 )
520}
521pub fn succ_of(expr: &Expr) -> Option<&Expr> {
523 if let Expr::App(f, a) = expr {
524 if matches!(f.as_ref(), Expr::Const(name, _) if name.to_string() == "Nat.succ") {
525 return Some(a);
526 }
527 }
528 None
529}
530pub fn rewrite_once(expr: &Expr, lhs: &Expr, rhs: &Expr) -> (Expr, bool) {
534 if alpha_eq(expr, lhs) {
535 return (rhs.clone(), true);
536 }
537 let mut changed = false;
538 let new_expr = match expr {
539 Expr::App(f, a) => {
540 let (new_f, c1) = rewrite_once(f, lhs, rhs);
541 let (new_a, c2) = rewrite_once(a, lhs, rhs);
542 changed = c1 || c2;
543 Expr::App(Node::new(new_f), Node::new(new_a))
544 }
545 Expr::Lam(bi, name, ty, body) => {
546 let (new_ty, c1) = rewrite_once(ty, lhs, rhs);
547 let (new_body, c2) = rewrite_once(body, lhs, rhs);
548 changed = c1 || c2;
549 Expr::Lam(*bi, name.clone(), Node::new(new_ty), Node::new(new_body))
550 }
551 Expr::Pi(bi, name, ty, body) => {
552 let (new_ty, c1) = rewrite_once(ty, lhs, rhs);
553 let (new_body, c2) = rewrite_once(body, lhs, rhs);
554 changed = c1 || c2;
555 Expr::Pi(*bi, name.clone(), Node::new(new_ty), Node::new(new_body))
556 }
557 other => other.clone(),
558 };
559 (new_expr, changed)
560}
561pub fn rewrite_all(expr: &Expr, lhs: &Expr, rhs: &Expr) -> Expr {
563 let mut current = expr.clone();
564 loop {
565 let (new_expr, changed) = rewrite_once(¤t, lhs, rhs);
566 if !changed {
567 return current;
568 }
569 current = new_expr;
570 }
571}
572pub fn free_vars(expr: &Expr) -> Vec<crate::FVarId> {
574 let mut result = Vec::new();
575 free_vars_rec(expr, &mut result);
576 result.sort_by_key(|fv| fv.0);
577 result.dedup_by_key(|fv| fv.0);
578 result
579}
580fn free_vars_rec(expr: &Expr, out: &mut Vec<crate::FVarId>) {
581 match expr {
582 Expr::FVar(fv) => out.push(*fv),
583 Expr::App(f, a) => {
584 free_vars_rec(f, out);
585 free_vars_rec(a, out);
586 }
587 Expr::Lam(_, _, ty, body) | Expr::Pi(_, _, ty, body) => {
588 free_vars_rec(ty, out);
589 free_vars_rec(body, out);
590 }
591 Expr::Let(_, ty, val, body) => {
592 free_vars_rec(ty, out);
593 free_vars_rec(val, out);
594 free_vars_rec(body, out);
595 }
596 Expr::Proj(_, _, inner) => free_vars_rec(inner, out),
597 _ => {}
598 }
599}
600pub fn is_closed(expr: &Expr) -> bool {
602 free_vars(expr).is_empty()
603}
604#[cfg(test)]
605mod simp_extra_tests2 {
606 use super::*;
607 use crate::{FVarId, Name};
608 #[test]
609 fn test_is_nat_lit() {
610 assert!(is_nat_lit(&Expr::Lit(Literal::nat(5)), 5));
611 assert!(!is_nat_lit(&Expr::Lit(Literal::nat(5)), 6));
612 }
613 #[test]
614 fn test_is_zero() {
615 assert!(is_zero(&Expr::Lit(Literal::nat(0))));
616 assert!(is_zero(&Expr::Const(Name::str("Nat.zero"), vec![])));
617 assert!(!is_zero(&Expr::Lit(Literal::nat(1))));
618 }
619 #[test]
620 fn test_is_succ_and_succ_of() {
621 let succ_n = Expr::App(
622 Node::new(Expr::Const(Name::str("Nat.succ"), vec![])),
623 Node::new(Expr::Lit(Literal::nat(3))),
624 );
625 assert!(is_succ(&succ_n));
626 assert!(succ_of(&succ_n).is_some());
627 assert!(!is_succ(&Expr::Lit(Literal::nat(5))));
628 assert!(succ_of(&Expr::Lit(Literal::nat(5))).is_none());
629 }
630 #[test]
631 fn test_rewrite_once() {
632 let lhs = Expr::Lit(Literal::nat(1));
633 let rhs = Expr::Lit(Literal::nat(99));
634 let expr = Expr::App(
635 Node::new(Expr::Const(Name::str("f"), vec![])),
636 Node::new(lhs.clone()),
637 );
638 let (new_expr, changed) = rewrite_once(&expr, &lhs, &rhs);
639 assert!(changed);
640 if let Expr::App(_, a) = &new_expr {
641 assert_eq!(a.as_ref(), &rhs);
642 } else {
643 panic!("expected App");
644 }
645 }
646 #[test]
647 fn test_rewrite_all() {
648 let lhs = Expr::Lit(Literal::nat(0));
649 let rhs = Expr::Lit(Literal::nat(100));
650 let expr = Expr::App(
651 Node::new(Expr::App(
652 Node::new(Expr::Const(Name::str("f"), vec![])),
653 Node::new(lhs.clone()),
654 )),
655 Node::new(lhs.clone()),
656 );
657 let result = rewrite_all(&expr, &lhs, &rhs);
658 let size = expr_size(&result);
659 assert!(size >= 3);
660 }
661 #[test]
662 fn test_free_vars() {
663 let expr = Expr::FVar(FVarId(42));
664 let fvs = free_vars(&expr);
665 assert_eq!(fvs.len(), 1);
666 assert_eq!(fvs[0].0, 42);
667 }
668 #[test]
669 fn test_is_closed() {
670 let lit = Expr::Lit(Literal::nat(5));
671 assert!(is_closed(&lit));
672 let fvar = Expr::FVar(FVarId(1));
673 assert!(!is_closed(&fvar));
674 }
675 #[test]
676 fn test_decompose_app_single() {
677 let e = Expr::Const(Name::str("x"), vec![]);
678 let (head, args) = decompose_app(&e);
679 assert!(matches!(head, Expr::Const(_, _)));
680 assert!(args.is_empty());
681 }
682}
683pub fn simp_with_trace(expr: &Expr, set: &SimpLemmaSet) -> SimpResult {
685 let mut current = expr.clone();
686 let mut applied = Vec::new();
687 let mut any_changed = false;
688 loop {
689 let mut pass_changed = false;
690 for lemma in set.iter() {
691 let (new_expr, c) =
692 rewrite_once(¤t, lemma.effective_lhs(), lemma.effective_rhs());
693 if c {
694 current = new_expr;
695 applied.push(lemma.name.clone());
696 pass_changed = true;
697 any_changed = true;
698 }
699 }
700 if !pass_changed {
701 break;
702 }
703 }
704 if any_changed {
705 SimpResult::simplified(current, applied)
706 } else {
707 SimpResult::unchanged(current)
708 }
709}
710pub fn is_true(expr: &Expr) -> bool {
712 matches!(expr, Expr::Const(name, _) if name.to_string() == "True")
713}
714pub fn is_false_expr(expr: &Expr) -> bool {
716 matches!(expr, Expr::Const(name, _) if name.to_string() == "False")
717}
718pub fn is_prop(expr: &Expr) -> bool {
720 matches!(expr, Expr::Sort(l) if l.is_zero())
721}
722pub fn fold_nat_constants(expr: &Expr) -> Expr {
727 match expr {
728 Expr::App(f, a) => {
729 let f2 = fold_nat_constants(f);
730 let a2 = fold_nat_constants(a);
731 if let Some(n) = eval_nat(&Expr::App(Node::new(f2.clone()), Node::new(a2.clone()))) {
732 Expr::Lit(Literal::Nat(n))
733 } else {
734 Expr::App(Node::new(f2), Node::new(a2))
735 }
736 }
737 Expr::Lam(bi, n, ty, body) => Expr::Lam(
738 *bi,
739 n.clone(),
740 Node::new(fold_nat_constants(ty)),
741 Node::new(fold_nat_constants(body)),
742 ),
743 Expr::Pi(bi, n, ty, body) => Expr::Pi(
744 *bi,
745 n.clone(),
746 Node::new(fold_nat_constants(ty)),
747 Node::new(fold_nat_constants(body)),
748 ),
749 other => other.clone(),
750 }
751}
752#[cfg(test)]
753mod simp_set_tests {
754 use super::*;
755 use crate::Name;
756 fn mk_lit(n: u64) -> Expr {
757 Expr::Lit(Literal::nat(n))
758 }
759 fn mk_c(s: &str) -> Expr {
760 Expr::Const(Name::str(s), vec![])
761 }
762 #[test]
763 fn test_simp_lemma_set_empty() {
764 let set = SimpLemmaSet::new();
765 assert!(set.is_empty());
766 let (result, changed) = set.apply_once(&mk_lit(1));
767 assert!(!changed);
768 assert_eq!(result, mk_lit(1));
769 }
770 #[test]
771 fn test_simp_lemma_set_apply_once() {
772 let mut set = SimpLemmaSet::new();
773 let lhs = mk_lit(0);
774 let rhs = mk_lit(100);
775 set.add(SimpLemma::forward(
776 Name::str("zero_to_hundred"),
777 lhs.clone(),
778 rhs.clone(),
779 ));
780 let (result, changed) = set.apply_once(&lhs);
781 assert!(changed);
782 assert_eq!(result, rhs);
783 }
784 #[test]
785 fn test_simp_lemma_set_apply_all() {
786 let mut set = SimpLemmaSet::new();
787 let a = mk_lit(1);
788 let b = mk_lit(2);
789 let c = mk_lit(3);
790 set.add(SimpLemma::forward(Name::str("r1"), a.clone(), b.clone()));
791 set.add(SimpLemma::forward(Name::str("r2"), b.clone(), c.clone()));
792 let result = set.apply_all(&a);
793 assert_eq!(result, c);
794 }
795 #[test]
796 fn test_simp_lemma_set_find() {
797 let mut set = SimpLemmaSet::new();
798 let lemma = SimpLemma::forward(Name::str("myRule"), mk_lit(0), mk_lit(1));
799 set.add(lemma);
800 assert!(set.find(&Name::str("myRule")).is_some());
801 assert!(set.find(&Name::str("unknownRule")).is_none());
802 }
803 #[test]
804 fn test_simp_with_trace_no_change() {
805 let set = SimpLemmaSet::new();
806 let e = mk_lit(5);
807 let result = simp_with_trace(&e, &set);
808 assert!(!result.changed);
809 assert_eq!(result.expr, e);
810 }
811 #[test]
812 fn test_simp_with_trace_change() {
813 let mut set = SimpLemmaSet::new();
814 let lhs = mk_lit(0);
815 let rhs = mk_lit(99);
816 set.add(SimpLemma::forward(Name::str("r"), lhs.clone(), rhs.clone()));
817 let result = simp_with_trace(&lhs, &set);
818 assert!(result.changed);
819 assert_eq!(result.expr, rhs);
820 assert_eq!(result.applied.len(), 1);
821 }
822 #[test]
823 fn test_is_true() {
824 assert!(is_true(&mk_c("True")));
825 assert!(!is_true(&mk_c("False")));
826 assert!(!is_true(&mk_lit(1)));
827 }
828 #[test]
829 fn test_is_false_expr() {
830 assert!(is_false_expr(&mk_c("False")));
831 assert!(!is_false_expr(&mk_c("True")));
832 }
833 #[test]
834 fn test_is_prop() {
835 use crate::Level;
836 assert!(is_prop(&Expr::Sort(Level::zero())));
837 assert!(!is_prop(&Expr::Sort(Level::succ(Level::zero()))));
838 }
839 #[test]
840 fn test_fold_nat_constants_succ() {
841 let e = Expr::App(
842 Node::new(Expr::Const(Name::str("Nat.succ"), vec![])),
843 Node::new(mk_lit(3)),
844 );
845 let result = fold_nat_constants(&e);
846 assert_eq!(result, mk_lit(4));
847 }
848 #[test]
849 fn test_fold_nat_constants_no_change() {
850 let e = mk_lit(7);
851 let result = fold_nat_constants(&e);
852 assert_eq!(result, e);
853 }
854 #[test]
855 fn test_simp_result_unchanged() {
856 let e = mk_lit(1);
857 let r = SimpResult::unchanged(e.clone());
858 assert!(!r.changed);
859 assert_eq!(r.expr, e);
860 }
861 #[test]
862 fn test_simp_result_simplified() {
863 let e = mk_lit(2);
864 let r = SimpResult::simplified(e.clone(), vec![Name::str("ruleX")]);
865 assert!(r.changed);
866 assert_eq!(r.applied.len(), 1);
867 }
868}
869#[cfg(test)]
870mod tests_padding_infra {
871 use super::*;
872 #[test]
873 fn test_stat_summary() {
874 let mut ss = StatSummary::new();
875 ss.record(10.0);
876 ss.record(20.0);
877 ss.record(30.0);
878 assert_eq!(ss.count(), 3);
879 assert!((ss.mean().expect("mean should succeed") - 20.0).abs() < 1e-9);
880 assert_eq!(ss.min().expect("min should succeed") as i64, 10);
881 assert_eq!(ss.max().expect("max should succeed") as i64, 30);
882 }
883 #[test]
884 fn test_transform_stat() {
885 let mut ts = TransformStat::new();
886 ts.record_before(100.0);
887 ts.record_after(80.0);
888 let ratio = ts.mean_ratio().expect("ratio should be present");
889 assert!((ratio - 0.8).abs() < 1e-9);
890 }
891 #[test]
892 fn test_small_map() {
893 let mut m: SmallMap<u32, &str> = SmallMap::new();
894 m.insert(3, "three");
895 m.insert(1, "one");
896 m.insert(2, "two");
897 assert_eq!(m.get(&2), Some(&"two"));
898 assert_eq!(m.len(), 3);
899 let keys = m.keys();
900 assert_eq!(*keys[0], 1);
901 assert_eq!(*keys[2], 3);
902 }
903 #[test]
904 fn test_label_set() {
905 let mut ls = LabelSet::new();
906 ls.add("foo");
907 ls.add("bar");
908 ls.add("foo");
909 assert_eq!(ls.count(), 2);
910 assert!(ls.has("bar"));
911 assert!(!ls.has("baz"));
912 }
913 #[test]
914 fn test_config_node() {
915 let mut root = ConfigNode::section("root");
916 let child = ConfigNode::leaf("key", "value");
917 root.add_child(child);
918 assert_eq!(root.num_children(), 1);
919 }
920 #[test]
921 fn test_versioned_record() {
922 let mut vr = VersionedRecord::new(0u32);
923 vr.update(1);
924 vr.update(2);
925 assert_eq!(*vr.current(), 2);
926 assert_eq!(vr.version(), 2);
927 assert!(vr.has_history());
928 assert_eq!(*vr.at_version(0).expect("value should be present"), 0);
929 }
930 #[test]
931 fn test_simple_dag() {
932 let mut dag = SimpleDag::new(4);
933 dag.add_edge(0, 1);
934 dag.add_edge(1, 2);
935 dag.add_edge(2, 3);
936 assert!(dag.can_reach(0, 3));
937 assert!(!dag.can_reach(3, 0));
938 let order = dag.topological_sort().expect("order should be present");
939 assert_eq!(order, vec![0, 1, 2, 3]);
940 }
941 #[test]
942 fn test_focus_stack() {
943 let mut fs: FocusStack<&str> = FocusStack::new();
944 fs.focus("a");
945 fs.focus("b");
946 assert_eq!(fs.current(), Some(&"b"));
947 assert_eq!(fs.depth(), 2);
948 fs.blur();
949 assert_eq!(fs.current(), Some(&"a"));
950 }
951}
952#[cfg(test)]
953mod tests_extra_iterators {
954 use super::*;
955 #[test]
956 fn test_window_iterator() {
957 let data = vec![1u32, 2, 3, 4, 5];
958 let windows: Vec<_> = WindowIterator::new(&data, 3).collect();
959 assert_eq!(windows.len(), 3);
960 assert_eq!(windows[0], &[1, 2, 3]);
961 assert_eq!(windows[2], &[3, 4, 5]);
962 }
963 #[test]
964 fn test_non_empty_vec() {
965 let mut nev = NonEmptyVec::singleton(10u32);
966 nev.push(20);
967 nev.push(30);
968 assert_eq!(nev.len(), 3);
969 assert_eq!(*nev.first(), 10);
970 assert_eq!(*nev.last(), 30);
971 }
972}
973#[cfg(test)]
974mod tests_padding2 {
975 use super::*;
976 #[test]
977 fn test_sliding_sum() {
978 let mut ss = SlidingSum::new(3);
979 ss.push(1.0);
980 ss.push(2.0);
981 ss.push(3.0);
982 assert!((ss.sum() - 6.0).abs() < 1e-9);
983 ss.push(4.0);
984 assert!((ss.sum() - 9.0).abs() < 1e-9);
985 assert_eq!(ss.count(), 3);
986 }
987 #[test]
988 fn test_path_buf() {
989 let mut pb = PathBuf::new();
990 pb.push("src");
991 pb.push("main");
992 assert_eq!(pb.as_str(), "src/main");
993 assert_eq!(pb.depth(), 2);
994 pb.pop();
995 assert_eq!(pb.as_str(), "src");
996 }
997 #[test]
998 fn test_string_pool() {
999 let mut pool = StringPool::new();
1000 let s = pool.take();
1001 assert!(s.is_empty());
1002 pool.give("hello".to_string());
1003 let s2 = pool.take();
1004 assert!(s2.is_empty());
1005 assert_eq!(pool.free_count(), 0);
1006 }
1007 #[test]
1008 fn test_transitive_closure() {
1009 let mut tc = TransitiveClosure::new(4);
1010 tc.add_edge(0, 1);
1011 tc.add_edge(1, 2);
1012 tc.add_edge(2, 3);
1013 assert!(tc.can_reach(0, 3));
1014 assert!(!tc.can_reach(3, 0));
1015 let r = tc.reachable_from(0);
1016 assert_eq!(r.len(), 4);
1017 }
1018 #[test]
1019 fn test_token_bucket() {
1020 let mut tb = TokenBucket::new(100, 0);
1021 assert_eq!(tb.available(), 100);
1022 assert!(tb.try_consume(50));
1023 assert_eq!(tb.available(), 50);
1024 assert!(!tb.try_consume(60));
1025 assert_eq!(tb.capacity(), 100);
1026 }
1027 #[test]
1028 fn test_rewrite_rule_set() {
1029 let mut rrs = RewriteRuleSet::new();
1030 rrs.add(RewriteRule::unconditional(
1031 "beta",
1032 "App(Lam(x, b), v)",
1033 "b[x:=v]",
1034 ));
1035 rrs.add(RewriteRule::conditional("comm", "a + b", "b + a"));
1036 assert_eq!(rrs.len(), 2);
1037 assert_eq!(rrs.unconditional_rules().len(), 1);
1038 assert_eq!(rrs.conditional_rules().len(), 1);
1039 assert!(rrs.get("beta").is_some());
1040 let disp = rrs
1041 .get("beta")
1042 .expect("element at \'beta\' should exist")
1043 .display();
1044 assert!(disp.contains("→"));
1045 }
1046}
1047#[cfg(test)]
1048mod tests_padding3 {
1049 use super::*;
1050 #[test]
1051 fn test_decision_node() {
1052 let tree = DecisionNode::Branch {
1053 key: "x".into(),
1054 val: "1".into(),
1055 yes_branch: Box::new(DecisionNode::Leaf("yes".into())),
1056 no_branch: Box::new(DecisionNode::Leaf("no".into())),
1057 };
1058 let mut ctx = std::collections::HashMap::new();
1059 ctx.insert("x".into(), "1".into());
1060 assert_eq!(tree.evaluate(&ctx), "yes");
1061 ctx.insert("x".into(), "2".into());
1062 assert_eq!(tree.evaluate(&ctx), "no");
1063 assert_eq!(tree.depth(), 1);
1064 }
1065 #[test]
1066 fn test_flat_substitution() {
1067 let mut sub = FlatSubstitution::new();
1068 sub.add("foo", "bar");
1069 sub.add("baz", "qux");
1070 assert_eq!(sub.apply("foo and baz"), "bar and qux");
1071 assert_eq!(sub.len(), 2);
1072 }
1073 #[test]
1074 fn test_stopwatch() {
1075 let mut sw = Stopwatch::start();
1076 sw.split();
1077 sw.split();
1078 assert_eq!(sw.num_splits(), 2);
1079 assert!(sw.elapsed_ms() >= 0.0);
1080 for &s in sw.splits() {
1081 assert!(s >= 0.0);
1082 }
1083 }
1084 #[test]
1085 fn test_either2() {
1086 let e: Either2<i32, &str> = Either2::First(42);
1087 assert!(e.is_first());
1088 let mapped = e.map_first(|x| x * 2);
1089 assert_eq!(mapped.first(), Some(84));
1090 let e2: Either2<i32, &str> = Either2::Second("hello");
1091 assert!(e2.is_second());
1092 assert_eq!(e2.second(), Some("hello"));
1093 }
1094 #[test]
1095 fn test_write_once() {
1096 let wo: WriteOnce<u32> = WriteOnce::new();
1097 assert!(!wo.is_written());
1098 assert!(wo.write(42));
1099 assert!(!wo.write(99));
1100 assert_eq!(wo.read(), Some(42));
1101 }
1102 #[test]
1103 fn test_sparse_vec() {
1104 let mut sv: SparseVec<i32> = SparseVec::new(100);
1105 sv.set(5, 10);
1106 sv.set(50, 20);
1107 assert_eq!(*sv.get(5), 10);
1108 assert_eq!(*sv.get(50), 20);
1109 assert_eq!(*sv.get(0), 0);
1110 assert_eq!(sv.nnz(), 2);
1111 sv.set(5, 0);
1112 assert_eq!(sv.nnz(), 1);
1113 }
1114 #[test]
1115 fn test_stack_calc() {
1116 let mut calc = StackCalc::new();
1117 calc.push(3);
1118 calc.push(4);
1119 assert_eq!(calc.add(), Some(7));
1120 assert_eq!(calc.peek(), Some(7));
1121 calc.push(2);
1122 assert_eq!(calc.mul(), Some(14));
1123 assert_eq!(calc.peek(), Some(14));
1124 }
1125}
1126#[cfg(test)]
1127mod tests_final_padding {
1128 use super::*;
1129 #[test]
1130 fn test_min_heap() {
1131 let mut h = MinHeap::new();
1132 h.push(5u32);
1133 h.push(1u32);
1134 h.push(3u32);
1135 assert_eq!(h.peek(), Some(&1));
1136 assert_eq!(h.pop(), Some(1));
1137 assert_eq!(h.pop(), Some(3));
1138 assert_eq!(h.pop(), Some(5));
1139 assert!(h.is_empty());
1140 }
1141 #[test]
1142 fn test_prefix_counter() {
1143 let mut pc = PrefixCounter::new();
1144 pc.record("hello");
1145 pc.record("help");
1146 pc.record("world");
1147 assert_eq!(pc.count_with_prefix("hel"), 2);
1148 assert_eq!(pc.count_with_prefix("wor"), 1);
1149 assert_eq!(pc.count_with_prefix("xyz"), 0);
1150 }
1151 #[test]
1152 fn test_fixture() {
1153 let mut f = Fixture::new();
1154 f.set("key1", "val1");
1155 f.set("key2", "val2");
1156 assert_eq!(f.get("key1"), Some("val1"));
1157 assert_eq!(f.get("key3"), None);
1158 assert_eq!(f.len(), 2);
1159 }
1160}