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