1use crate::{Environment, Expr, Reducer};
6use std::collections::HashMap;
7
8use super::types::{
9 ConfigNode, DecisionNode, Either2, Fixture, FlatSubstitution, FocusStack, LabelSet, LazyNormal,
10 MemoizedNormalizer, MinHeap, NonEmptyVec, NormStats, NormStrategy, PathBuf, PrefixCounter,
11 RewriteRule, RewriteRuleSet, SimpleDag, SlidingSum, SmallMap, SparseVec, StackCalc,
12 StatSummary, Stopwatch, StringPool, TokenBucket, TransformStat, TransitiveClosure,
13 VersionedRecord, WindowIterator, WriteOnce,
14};
15
16pub fn normalize(expr: &Expr) -> Expr {
20 let mut reducer = Reducer::new();
21 normalize_impl(&mut reducer, expr, None)
22}
23pub fn normalize_env(expr: &Expr, env: &Environment) -> Expr {
27 let mut reducer = Reducer::new();
28 normalize_impl(&mut reducer, expr, Some(env))
29}
30pub(super) fn normalize_impl(
32 reducer: &mut Reducer,
33 expr: &Expr,
34 env: Option<&Environment>,
35) -> Expr {
36 match expr {
37 Expr::Sort(_) | Expr::BVar(_) | Expr::FVar(_) | Expr::Lit(_) => expr.clone(),
38 Expr::Const(_, _) => {
39 let whnf = match env {
40 Some(e) => reducer.whnf_env(expr, e),
41 None => reducer.whnf(expr),
42 };
43 if whnf == *expr {
44 expr.clone()
45 } else {
46 normalize_impl(reducer, &whnf, env)
47 }
48 }
49 Expr::Lam(info, name, ty, body) => {
50 let ty_norm = normalize_impl(reducer, ty, env);
51 let body_norm = normalize_impl(reducer, body, env);
52 Expr::Lam(*info, name.clone(), Box::new(ty_norm), Box::new(body_norm))
53 }
54 Expr::Pi(info, name, ty, body) => {
55 let ty_norm = normalize_impl(reducer, ty, env);
56 let body_norm = normalize_impl(reducer, body, env);
57 Expr::Pi(*info, name.clone(), Box::new(ty_norm), Box::new(body_norm))
58 }
59 Expr::App(_, _) => {
60 let whnf = match env {
61 Some(e) => reducer.whnf_env(expr, e),
62 None => reducer.whnf(expr),
63 };
64 if let Expr::App(f_whnf, a_whnf) = whnf {
65 let f_norm = normalize_impl(reducer, &f_whnf, env);
66 let a_norm = normalize_impl(reducer, &a_whnf, env);
67 Expr::App(Box::new(f_norm), Box::new(a_norm))
68 } else {
69 normalize_impl(reducer, &whnf, env)
70 }
71 }
72 Expr::Let(_, _, _, _) => {
73 let whnf = match env {
74 Some(e) => reducer.whnf_env(expr, e),
75 None => reducer.whnf(expr),
76 };
77 normalize_impl(reducer, &whnf, env)
78 }
79 Expr::Proj(name, idx, e) => {
80 let whnf = match env {
81 Some(env) => reducer.whnf_env(expr, env),
82 None => reducer.whnf(expr),
83 };
84 if let Expr::Proj(_, _, _) = &whnf {
85 let e_norm = normalize_impl(reducer, e, env);
86 Expr::Proj(name.clone(), *idx, Box::new(e_norm))
87 } else {
88 normalize_impl(reducer, &whnf, env)
89 }
90 }
91 }
92}
93pub fn alpha_eq(e1: &Expr, e2: &Expr) -> bool {
95 let n1 = normalize(e1);
96 let n2 = normalize(e2);
97 n1 == n2
98}
99pub fn alpha_eq_env(e1: &Expr, e2: &Expr, env: &Environment) -> bool {
101 let n1 = normalize_env(e1, env);
102 let n2 = normalize_env(e2, env);
103 n1 == n2
104}
105pub fn normalize_whnf(expr: &Expr) -> Expr {
107 let mut reducer = Reducer::new();
108 let whnf = reducer.whnf(expr);
109 normalize_impl(&mut reducer, &whnf, None)
110}
111pub fn is_normal_form(expr: &Expr) -> bool {
116 let normalized = normalize(expr);
117 normalized == *expr
118}
119pub fn evaluate(expr: &Expr, env: &Environment) -> Expr {
124 let mut reducer = Reducer::new();
125 let whnf = reducer.whnf_env(expr, env);
126 match &whnf {
127 Expr::Lit(_) | Expr::Lam(_, _, _, _) | Expr::Sort(_) => whnf,
128 Expr::App(_, _) => {
129 let (head, args) = collect_app_parts(&whnf);
130 if is_constructor_head(head, env) {
131 let head_norm = head.clone();
132 let mut result = head_norm;
133 for arg in args {
134 let arg_eval = evaluate(arg, env);
135 result = Expr::App(Box::new(result), Box::new(arg_eval));
136 }
137 result
138 } else {
139 normalize_impl(&mut reducer, &whnf, Some(env))
140 }
141 }
142 _ => normalize_impl(&mut reducer, &whnf, Some(env)),
143 }
144}
145pub(super) fn collect_app_parts(expr: &Expr) -> (&Expr, Vec<&Expr>) {
147 let mut args = Vec::new();
148 let mut e = expr;
149 while let Expr::App(f, a) = e {
150 args.push(a.as_ref());
151 e = f;
152 }
153 args.reverse();
154 (e, args)
155}
156pub(super) fn is_constructor_head(head: &Expr, env: &Environment) -> bool {
158 if let Expr::Const(name, _) = head {
159 env.is_constructor(name)
160 } else {
161 false
162 }
163}
164#[cfg(test)]
165mod tests {
166 use super::*;
167 use crate::{BinderInfo, Level, Literal, Name};
168 #[test]
169 fn test_normalize_sort() {
170 let expr = Expr::Sort(Level::zero());
171 let norm = normalize(&expr);
172 assert_eq!(norm, expr);
173 }
174 #[test]
175 fn test_normalize_lit() {
176 let expr = Expr::Lit(Literal::Nat(42));
177 let norm = normalize(&expr);
178 assert_eq!(norm, expr);
179 }
180 #[test]
181 fn test_normalize_bvar() {
182 let expr = Expr::BVar(0);
183 let norm = normalize(&expr);
184 assert_eq!(norm, expr);
185 }
186 #[test]
187 fn test_normalize_lambda() {
188 let lam = Expr::Lam(
189 BinderInfo::Default,
190 Name::str("x"),
191 Box::new(Expr::Sort(Level::zero())),
192 Box::new(Expr::BVar(0)),
193 );
194 let norm = normalize(&lam);
195 assert!(matches!(norm, Expr::Lam(_, _, _, _)));
196 }
197 #[test]
198 fn test_normalize_beta() {
199 let lam = Expr::Lam(
200 BinderInfo::Default,
201 Name::str("x"),
202 Box::new(Expr::Sort(Level::zero())),
203 Box::new(Expr::BVar(0)),
204 );
205 let arg = Expr::Lit(Literal::Nat(42));
206 let app = Expr::App(Box::new(lam), Box::new(arg.clone()));
207 let norm = normalize(&app);
208 assert_eq!(norm, arg);
209 }
210 #[test]
211 fn test_alpha_eq_same() {
212 let e1 = Expr::Lit(Literal::Nat(42));
213 let e2 = Expr::Lit(Literal::Nat(42));
214 assert!(alpha_eq(&e1, &e2));
215 }
216 #[test]
217 fn test_alpha_eq_different() {
218 let e1 = Expr::Lit(Literal::Nat(42));
219 let e2 = Expr::Lit(Literal::Nat(43));
220 assert!(!alpha_eq(&e1, &e2));
221 }
222 #[test]
223 fn test_normalize_nested() {
224 let inner_lam = Expr::Lam(
225 BinderInfo::Default,
226 Name::str("y"),
227 Box::new(Expr::Sort(Level::zero())),
228 Box::new(Expr::BVar(1)),
229 );
230 let outer_lam = Expr::Lam(
231 BinderInfo::Default,
232 Name::str("x"),
233 Box::new(Expr::Sort(Level::zero())),
234 Box::new(inner_lam),
235 );
236 let arg = Expr::Lit(Literal::Nat(42));
237 let app = Expr::App(Box::new(outer_lam), Box::new(arg));
238 let norm = normalize(&app);
239 assert!(matches!(norm, Expr::Lam(_, _, _, _)));
240 }
241 #[test]
242 fn test_is_normal_form() {
243 assert!(is_normal_form(&Expr::Lit(Literal::Nat(42))));
244 assert!(is_normal_form(&Expr::BVar(0)));
245 assert!(is_normal_form(&Expr::Sort(Level::zero())));
246 }
247 #[test]
248 fn test_normalize_with_env() {
249 let mut env = Environment::new();
250 env.add(crate::Declaration::Definition {
251 name: Name::str("answer"),
252 univ_params: vec![],
253 ty: Expr::Const(Name::str("Nat"), vec![]),
254 val: Expr::Lit(Literal::Nat(42)),
255 hint: crate::ReducibilityHint::Regular(1),
256 })
257 .expect("value should be present");
258 let expr = Expr::Const(Name::str("answer"), vec![]);
259 let norm = normalize_env(&expr, &env);
260 assert_eq!(norm, Expr::Lit(Literal::Nat(42)));
261 }
262 #[test]
263 fn test_alpha_eq_env() {
264 let mut env = Environment::new();
265 env.add(crate::Declaration::Definition {
266 name: Name::str("a"),
267 univ_params: vec![],
268 ty: Expr::Const(Name::str("Nat"), vec![]),
269 val: Expr::Lit(Literal::Nat(42)),
270 hint: crate::ReducibilityHint::Regular(1),
271 })
272 .expect("value should be present");
273 env.add(crate::Declaration::Definition {
274 name: Name::str("b"),
275 univ_params: vec![],
276 ty: Expr::Const(Name::str("Nat"), vec![]),
277 val: Expr::Lit(Literal::Nat(42)),
278 hint: crate::ReducibilityHint::Regular(1),
279 })
280 .expect("value should be present");
281 let e1 = Expr::Const(Name::str("a"), vec![]);
282 let e2 = Expr::Const(Name::str("b"), vec![]);
283 assert!(alpha_eq_env(&e1, &e2, &env));
284 }
285}
286#[allow(dead_code)]
290pub fn normalize_types(expr: &Expr) -> Expr {
291 normalize_types_impl(expr)
292}
293pub(super) fn normalize_types_impl(expr: &Expr) -> Expr {
294 match expr {
295 Expr::Pi(bk, n, ty, body) => {
296 let ty2 = normalize_types_impl(ty);
297 let body2 = normalize_types_impl(body);
298 Expr::Pi(*bk, n.clone(), Box::new(ty2), Box::new(body2))
299 }
300 Expr::Sort(_) => expr.clone(),
301 Expr::App(f, a) => Expr::App(
302 Box::new(normalize_types_impl(f)),
303 Box::new(normalize_types_impl(a)),
304 ),
305 Expr::Lam(bk, n, ty, body) => {
306 let ty2 = normalize_types_impl(ty);
307 Expr::Lam(
308 *bk,
309 n.clone(),
310 Box::new(ty2),
311 Box::new(body.as_ref().clone()),
312 )
313 }
314 other => other.clone(),
315 }
316}
317#[allow(dead_code)]
323pub fn head_normal_form(expr: &Expr) -> Expr {
324 match expr {
325 Expr::App(f, arg) => {
326 let f_hnf = head_normal_form(f);
327 match f_hnf {
328 Expr::Lam(_, _, _, body) => {
329 let substituted = subst_bvar_norm(*body, 0, arg);
330 head_normal_form(&substituted)
331 }
332 other_f => Expr::App(Box::new(other_f), arg.clone()),
333 }
334 }
335 Expr::Let(_, _, val, body) => {
336 let substituted = subst_bvar_norm(*body.clone(), 0, val);
337 head_normal_form(&substituted)
338 }
339 other => other.clone(),
340 }
341}
342pub(super) fn subst_bvar_norm(term: Expr, depth: u32, replacement: &Expr) -> Expr {
343 match term {
344 Expr::BVar(i) => {
345 if i == depth {
346 replacement.clone()
347 } else if i > depth {
348 Expr::BVar(i - 1)
349 } else {
350 Expr::BVar(i)
351 }
352 }
353 Expr::App(f, a) => Expr::App(
354 Box::new(subst_bvar_norm(*f, depth, replacement)),
355 Box::new(subst_bvar_norm(*a, depth, replacement)),
356 ),
357 Expr::Lam(bk, n, ty, body) => Expr::Lam(
358 bk,
359 n,
360 Box::new(subst_bvar_norm(*ty, depth, replacement)),
361 Box::new(subst_bvar_norm(*body, depth + 1, replacement)),
362 ),
363 Expr::Pi(bk, n, ty, body) => Expr::Pi(
364 bk,
365 n,
366 Box::new(subst_bvar_norm(*ty, depth, replacement)),
367 Box::new(subst_bvar_norm(*body, depth + 1, replacement)),
368 ),
369 Expr::Let(n, ty, val, body) => Expr::Let(
370 n,
371 Box::new(subst_bvar_norm(*ty, depth, replacement)),
372 Box::new(subst_bvar_norm(*val, depth, replacement)),
373 Box::new(subst_bvar_norm(*body, depth + 1, replacement)),
374 ),
375 Expr::Proj(idx, n, e) => {
376 Expr::Proj(idx, n, Box::new(subst_bvar_norm(*e, depth, replacement)))
377 }
378 other => other,
379 }
380}
381#[allow(dead_code)]
385pub fn count_reduction_steps(expr: &Expr) -> (usize, Expr) {
386 let mut steps = 0usize;
387 let result = count_steps_impl(expr, &mut steps);
388 (steps, result)
389}
390pub(super) fn count_steps_impl(expr: &Expr, steps: &mut usize) -> Expr {
391 match expr {
392 Expr::App(f, arg) => {
393 let f_norm = count_steps_impl(f, steps);
394 let arg_norm = count_steps_impl(arg, steps);
395 if let Expr::Lam(_, _, _, body) = f_norm {
396 *steps += 1;
397 let substituted = subst_bvar_norm(*body, 0, &arg_norm);
398 count_steps_impl(&substituted, steps)
399 } else {
400 Expr::App(Box::new(f_norm), Box::new(arg_norm))
401 }
402 }
403 Expr::Let(_, _, val, body) => {
404 *steps += 1;
405 let substituted = subst_bvar_norm(*body.clone(), 0, val);
406 count_steps_impl(&substituted, steps)
407 }
408 Expr::Lam(bk, n, ty, body) => {
409 let ty2 = count_steps_impl(ty, steps);
410 let body2 = count_steps_impl(body, steps);
411 Expr::Lam(*bk, n.clone(), Box::new(ty2), Box::new(body2))
412 }
413 Expr::Pi(bk, n, ty, body) => {
414 let ty2 = count_steps_impl(ty, steps);
415 let body2 = count_steps_impl(body, steps);
416 Expr::Pi(*bk, n.clone(), Box::new(ty2), Box::new(body2))
417 }
418 Expr::Proj(idx, n, e) => Expr::Proj(idx.clone(), *n, Box::new(count_steps_impl(e, steps))),
419 other => other.clone(),
420 }
421}
422#[allow(dead_code)]
426pub fn normalize_many(exprs: &[Expr]) -> Vec<Expr> {
427 exprs.iter().map(normalize).collect()
428}
429#[allow(dead_code)]
431pub fn normalize_many_env(exprs: &[Expr], env: &Environment) -> Vec<Expr> {
432 exprs.iter().map(|e| normalize_env(e, env)).collect()
433}
434#[allow(dead_code)]
442pub fn is_in_whnf(expr: &Expr) -> bool {
443 match expr {
444 Expr::Sort(_) | Expr::Lit(_) | Expr::FVar(_) | Expr::Const(_, _) => true,
445 Expr::Lam(_, _, _, _) | Expr::Pi(_, _, _, _) => true,
446 Expr::App(f, _) => !matches!(f.as_ref(), Expr::Lam(_, _, _, _)),
447 Expr::BVar(_) => true,
448 Expr::Let(_, _, _, _) => false,
449 Expr::Proj(_, _, _) => false,
450 }
451}
452#[allow(dead_code)]
457pub fn normalize_fully(expr: &Expr, max_depth: usize) -> Expr {
458 normalize_fully_impl(expr, max_depth, 0)
459}
460pub(super) fn normalize_fully_impl(expr: &Expr, max_depth: usize, current: usize) -> Expr {
461 if current >= max_depth {
462 return expr.clone();
463 }
464 match expr {
465 Expr::App(f, arg) => {
466 let f2 = normalize_fully_impl(f, max_depth, current + 1);
467 let a2 = normalize_fully_impl(arg, max_depth, current + 1);
468 if let Expr::Lam(_, _, _, body) = f2 {
469 let sub = subst_bvar_norm(*body, 0, &a2);
470 normalize_fully_impl(&sub, max_depth, current + 1)
471 } else {
472 Expr::App(Box::new(f2), Box::new(a2))
473 }
474 }
475 Expr::Lam(bk, n, ty, body) => {
476 let ty2 = normalize_fully_impl(ty, max_depth, current + 1);
477 let b2 = normalize_fully_impl(body, max_depth, current + 1);
478 Expr::Lam(*bk, n.clone(), Box::new(ty2), Box::new(b2))
479 }
480 Expr::Pi(bk, n, ty, body) => {
481 let ty2 = normalize_fully_impl(ty, max_depth, current + 1);
482 let b2 = normalize_fully_impl(body, max_depth, current + 1);
483 Expr::Pi(*bk, n.clone(), Box::new(ty2), Box::new(b2))
484 }
485 Expr::Let(_, _, val, body) => {
486 let sub = subst_bvar_norm(*body.clone(), 0, val);
487 normalize_fully_impl(&sub, max_depth, current + 1)
488 }
489 other => other.clone(),
490 }
491}
492#[allow(dead_code)]
497pub fn reduce_n_steps(expr: &Expr, n: usize) -> Expr {
498 let mut current = expr.clone();
499 for _ in 0..n {
500 let next = reduce_one_step(¤t);
501 if next == current {
502 break;
503 }
504 current = next;
505 }
506 current
507}
508pub(super) fn reduce_one_step(expr: &Expr) -> Expr {
509 match expr {
510 Expr::App(f, arg) => {
511 if let Expr::Lam(_, _, _, body) = f.as_ref() {
512 subst_bvar_norm(*body.clone(), 0, arg)
513 } else {
514 let f2 = reduce_one_step(f);
515 Expr::App(Box::new(f2), arg.clone())
516 }
517 }
518 Expr::Let(_, _, val, body) => subst_bvar_norm(*body.clone(), 0, val),
519 other => other.clone(),
520 }
521}
522#[allow(dead_code)]
526pub fn normalize_selective(expr: &Expr, env: &Environment, whitelist: &[crate::Name]) -> Expr {
527 match expr {
528 Expr::Const(name, _) => {
529 if whitelist.contains(name) {
530 if let Some(ci) = env.find(name) {
531 if let Some(val) = ci.value() {
532 return normalize_selective(val, env, whitelist);
533 }
534 }
535 }
536 expr.clone()
537 }
538 Expr::App(f, a) => {
539 let f2 = normalize_selective(f, env, whitelist);
540 let a2 = normalize_selective(a, env, whitelist);
541 if let Expr::Lam(_, _, _, body) = f2 {
542 let sub = subst_bvar_norm(*body, 0, &a2);
543 normalize_selective(&sub, env, whitelist)
544 } else {
545 Expr::App(Box::new(f2), Box::new(a2))
546 }
547 }
548 Expr::Lam(bk, n, ty, body) => Expr::Lam(
549 *bk,
550 n.clone(),
551 Box::new(normalize_selective(ty, env, whitelist)),
552 Box::new(normalize_selective(body, env, whitelist)),
553 ),
554 Expr::Pi(bk, n, ty, body) => Expr::Pi(
555 *bk,
556 n.clone(),
557 Box::new(normalize_selective(ty, env, whitelist)),
558 Box::new(normalize_selective(body, env, whitelist)),
559 ),
560 Expr::Let(_n, _ty, val, body) => {
561 let sub = subst_bvar_norm(*body.clone(), 0, val);
562 normalize_selective(&sub, env, whitelist)
563 }
564 Expr::Proj(idx, n, e) => Expr::Proj(
565 idx.clone(),
566 *n,
567 Box::new(normalize_selective(e, env, whitelist)),
568 ),
569 other => other.clone(),
570 }
571}
572#[cfg(test)]
573mod extended_normalize_tests {
574 use super::*;
575 use crate::{BinderInfo as BinderKind, Expr, Level, Literal, Name};
576 fn mk_nat(n: u64) -> Expr {
577 Expr::Lit(Literal::Nat(n))
578 }
579 fn mk_const(s: &str) -> Expr {
580 Expr::Const(Name::str(s), vec![])
581 }
582 fn mk_sort(n: u32) -> Expr {
583 let mut l = Level::zero();
584 for _ in 0..n {
585 l = Level::succ(l);
586 }
587 Expr::Sort(l)
588 }
589 #[test]
590 fn test_normalize_types_pi() {
591 let pi = Expr::Pi(
592 BinderKind::Default,
593 Name::str("x"),
594 Box::new(mk_sort(0)),
595 Box::new(mk_sort(0)),
596 );
597 let result = normalize_types(&pi);
598 assert!(matches!(result, Expr::Pi(_, _, _, _)));
599 }
600 #[test]
601 fn test_head_normal_form_const() {
602 let c = mk_const("Nat");
603 let hnf = head_normal_form(&c);
604 assert_eq!(hnf, c);
605 }
606 #[test]
607 fn test_head_normal_form_app_lam() {
608 let body = Expr::BVar(0);
609 let lam = Expr::Lam(
610 BinderKind::Default,
611 Name::str("x"),
612 Box::new(mk_sort(0)),
613 Box::new(body),
614 );
615 let arg = mk_nat(5);
616 let app = Expr::App(Box::new(lam), Box::new(arg.clone()));
617 let hnf = head_normal_form(&app);
618 assert_eq!(hnf, arg);
619 }
620 #[test]
621 fn test_count_reduction_steps_zero() {
622 let c = mk_const("pure");
623 let (steps, result) = count_reduction_steps(&c);
624 assert_eq!(steps, 0);
625 assert_eq!(result, c);
626 }
627 #[test]
628 fn test_count_reduction_steps_one() {
629 let body = Expr::BVar(0);
630 let lam = Expr::Lam(
631 BinderKind::Default,
632 Name::str("x"),
633 Box::new(mk_sort(0)),
634 Box::new(body),
635 );
636 let arg = mk_nat(7);
637 let app = Expr::App(Box::new(lam), Box::new(arg.clone()));
638 let (steps, result) = count_reduction_steps(&app);
639 assert!(steps >= 1);
640 assert_eq!(result, arg);
641 }
642 #[test]
643 fn test_memoized_normalizer_cache() {
644 let mut memo = MemoizedNormalizer::new();
645 let c = mk_const("f");
646 assert_eq!(memo.cache_size(), 0);
647 memo.normalize(&c);
648 assert_eq!(memo.cache_size(), 1);
649 memo.normalize(&c);
650 assert_eq!(memo.cache_size(), 1);
651 memo.clear_cache();
652 assert_eq!(memo.cache_size(), 0);
653 }
654 #[test]
655 fn test_normalize_many() {
656 let exprs = vec![mk_nat(1), mk_const("True"), mk_nat(2)];
657 let results = normalize_many(&exprs);
658 assert_eq!(results.len(), 3);
659 }
660 #[test]
661 fn test_is_in_whnf_const() {
662 assert!(is_in_whnf(&mk_const("Nat")));
663 }
664 #[test]
665 fn test_is_in_whnf_let() {
666 let let_expr = Expr::Let(
667 Name::str("x"),
668 Box::new(mk_sort(0)),
669 Box::new(mk_nat(0)),
670 Box::new(Expr::BVar(0)),
671 );
672 assert!(!is_in_whnf(&let_expr));
673 }
674 #[test]
675 fn test_normalize_fully_depth_zero() {
676 let body = Expr::BVar(0);
677 let lam = Expr::Lam(
678 BinderKind::Default,
679 Name::str("x"),
680 Box::new(mk_sort(0)),
681 Box::new(body.clone()),
682 );
683 let arg = mk_nat(3);
684 let app = Expr::App(Box::new(lam), Box::new(arg));
685 let result = normalize_fully(&app, 0);
686 assert!(matches!(result, Expr::App(_, _)));
687 }
688 #[test]
689 fn test_reduce_n_steps_zero() {
690 let c = mk_const("x");
691 let result = reduce_n_steps(&c, 0);
692 assert_eq!(result, c);
693 }
694 #[test]
695 fn test_reduce_n_steps_one() {
696 let body = Expr::BVar(0);
697 let lam = Expr::Lam(
698 BinderKind::Default,
699 Name::str("x"),
700 Box::new(mk_sort(0)),
701 Box::new(body),
702 );
703 let arg = mk_nat(99);
704 let app = Expr::App(Box::new(lam), Box::new(arg.clone()));
705 let result = reduce_n_steps(&app, 1);
706 assert_eq!(result, arg);
707 }
708 #[test]
709 fn test_normalize_selective_no_env() {
710 let env = Environment::new();
711 let c = mk_const("myDef");
712 let whitelist = vec![Name::str("myDef")];
713 let result = normalize_selective(&c, &env, &whitelist);
714 assert_eq!(result, c);
715 }
716}
717pub fn normalize_with_strategy(expr: &Expr, strategy: NormStrategy) -> Expr {
719 match strategy {
720 NormStrategy::None => expr.clone(),
721 NormStrategy::Whnf => normalize_whnf(expr),
722 NormStrategy::Full => normalize(expr),
723 NormStrategy::Bounded(depth) => normalize_fully(expr, depth),
724 }
725}
726#[allow(dead_code)]
731pub fn normalize_binders(expr: &Expr, n: usize) -> Expr {
732 if n == 0 {
733 return expr.clone();
734 }
735 match expr {
736 Expr::Lam(bi, name, ty, body) => Expr::Lam(
737 *bi,
738 name.clone(),
739 Box::new(normalize(ty)),
740 Box::new(normalize_binders(body, n - 1)),
741 ),
742 Expr::Pi(bi, name, ty, body) => Expr::Pi(
743 *bi,
744 name.clone(),
745 Box::new(normalize(ty)),
746 Box::new(normalize_binders(body, n - 1)),
747 ),
748 other => normalize(other),
749 }
750}
751#[allow(dead_code)]
753pub fn normalize_with_stats(expr: &Expr) -> (Expr, NormStats) {
754 let mut stats = NormStats::new();
755 let result = norm_stats_impl(expr, &mut stats);
756 (result, stats)
757}
758pub(super) fn norm_stats_impl(expr: &Expr, stats: &mut NormStats) -> Expr {
759 stats.visited += 1;
760 match expr {
761 Expr::App(f, arg) => {
762 let f2 = norm_stats_impl(f, stats);
763 let a2 = norm_stats_impl(arg, stats);
764 if let Expr::Lam(_, _, _, body) = &f2 {
765 stats.beta_steps += 1;
766 let sub = subst_bvar_norm(*body.clone(), 0, &a2);
767 norm_stats_impl(&sub, stats)
768 } else {
769 Expr::App(Box::new(f2), Box::new(a2))
770 }
771 }
772 Expr::Let(_, _, val, body) => {
773 stats.let_steps += 1;
774 let v2 = norm_stats_impl(val, stats);
775 let sub = subst_bvar_norm(*body.clone(), 0, &v2);
776 norm_stats_impl(&sub, stats)
777 }
778 Expr::Lam(bk, n, ty, body) => {
779 let ty2 = norm_stats_impl(ty, stats);
780 let b2 = norm_stats_impl(body, stats);
781 Expr::Lam(*bk, n.clone(), Box::new(ty2), Box::new(b2))
782 }
783 Expr::Pi(bk, n, ty, body) => {
784 let ty2 = norm_stats_impl(ty, stats);
785 let b2 = norm_stats_impl(body, stats);
786 Expr::Pi(*bk, n.clone(), Box::new(ty2), Box::new(b2))
787 }
788 other => other.clone(),
789 }
790}
791#[cfg(test)]
792mod normalize_new_tests {
793 use super::*;
794 use crate::{BinderInfo, Level, Literal, Name};
795 fn mk_nat(n: u64) -> Expr {
796 Expr::Lit(Literal::Nat(n))
797 }
798 fn mk_sort0() -> Expr {
799 Expr::Sort(Level::zero())
800 }
801 #[test]
802 fn test_norm_strategy_none() {
803 let e = Expr::App(
804 Box::new(Expr::Lam(
805 BinderInfo::Default,
806 Name::str("x"),
807 Box::new(mk_sort0()),
808 Box::new(Expr::BVar(0)),
809 )),
810 Box::new(mk_nat(5)),
811 );
812 let result = normalize_with_strategy(&e, NormStrategy::None);
813 assert_eq!(result, e);
814 }
815 #[test]
816 fn test_norm_strategy_full() {
817 let e = Expr::App(
818 Box::new(Expr::Lam(
819 BinderInfo::Default,
820 Name::str("x"),
821 Box::new(mk_sort0()),
822 Box::new(Expr::BVar(0)),
823 )),
824 Box::new(mk_nat(7)),
825 );
826 let result = normalize_with_strategy(&e, NormStrategy::Full);
827 assert_eq!(result, mk_nat(7));
828 }
829 #[test]
830 fn test_norm_strategy_bounded() {
831 let e = mk_nat(3);
832 let result = normalize_with_strategy(&e, NormStrategy::Bounded(10));
833 assert_eq!(result, e);
834 }
835 #[test]
836 fn test_lazy_normal_basic() {
837 let e = mk_nat(42);
838 let lazy = LazyNormal::new(e.clone());
839 assert!(!lazy.is_evaluated());
840 assert_eq!(lazy.normalized(), &e);
841 assert!(lazy.is_evaluated());
842 }
843 #[test]
844 fn test_lazy_normal_normalizes() {
845 let body = Expr::BVar(0);
846 let lam = Expr::Lam(
847 BinderInfo::Default,
848 Name::str("x"),
849 Box::new(mk_sort0()),
850 Box::new(body),
851 );
852 let arg = mk_nat(10);
853 let app = Expr::App(Box::new(lam), Box::new(arg.clone()));
854 let lazy = LazyNormal::new(app);
855 assert_eq!(lazy.normalized(), &arg);
856 }
857 #[test]
858 fn test_normalize_with_stats_no_reductions() {
859 let e = mk_nat(1);
860 let (result, stats) = normalize_with_stats(&e);
861 assert_eq!(result, e);
862 assert_eq!(stats.beta_steps, 0);
863 assert_eq!(stats.let_steps, 0);
864 assert_eq!(stats.visited, 1);
865 }
866 #[test]
867 fn test_normalize_with_stats_beta() {
868 let body = Expr::BVar(0);
869 let lam = Expr::Lam(
870 BinderInfo::Default,
871 Name::str("x"),
872 Box::new(mk_sort0()),
873 Box::new(body),
874 );
875 let arg = mk_nat(3);
876 let app = Expr::App(Box::new(lam), Box::new(arg.clone()));
877 let (result, stats) = normalize_with_stats(&app);
878 assert_eq!(result, arg);
879 assert!(stats.beta_steps >= 1);
880 }
881 #[test]
882 fn test_normalize_with_stats_let() {
883 let val = mk_nat(5);
884 let let_expr = Expr::Let(
885 Name::str("x"),
886 Box::new(mk_sort0()),
887 Box::new(val.clone()),
888 Box::new(Expr::BVar(0)),
889 );
890 let (result, stats) = normalize_with_stats(&let_expr);
891 assert_eq!(result, val);
892 assert!(stats.let_steps >= 1);
893 }
894 #[test]
895 fn test_norm_stats_total_steps() {
896 let stats = NormStats {
897 beta_steps: 3,
898 let_steps: 2,
899 ..Default::default()
900 };
901 assert_eq!(stats.total_steps(), 5);
902 }
903 #[test]
904 fn test_normalize_binders_depth1() {
905 let nat = Expr::Const(Name::str("Nat"), vec![]);
906 let lam = Expr::Lam(
907 BinderInfo::Default,
908 Name::str("x"),
909 Box::new(nat.clone()),
910 Box::new(nat.clone()),
911 );
912 let result = normalize_binders(&lam, 1);
913 assert!(matches!(result, Expr::Lam(_, _, _, _)));
914 }
915 #[test]
916 fn test_norm_strategy_whnf() {
917 let e = mk_nat(1);
918 let result = normalize_with_strategy(&e, NormStrategy::Whnf);
919 assert_eq!(result, e);
920 }
921}
922#[cfg(test)]
923mod tests_padding_infra {
924 use super::*;
925 #[test]
926 fn test_stat_summary() {
927 let mut ss = StatSummary::new();
928 ss.record(10.0);
929 ss.record(20.0);
930 ss.record(30.0);
931 assert_eq!(ss.count(), 3);
932 assert!((ss.mean().expect("mean should succeed") - 20.0).abs() < 1e-9);
933 assert_eq!(ss.min().expect("min should succeed") as i64, 10);
934 assert_eq!(ss.max().expect("max should succeed") as i64, 30);
935 }
936 #[test]
937 fn test_transform_stat() {
938 let mut ts = TransformStat::new();
939 ts.record_before(100.0);
940 ts.record_after(80.0);
941 let ratio = ts.mean_ratio().expect("ratio should be present");
942 assert!((ratio - 0.8).abs() < 1e-9);
943 }
944 #[test]
945 fn test_small_map() {
946 let mut m: SmallMap<u32, &str> = SmallMap::new();
947 m.insert(3, "three");
948 m.insert(1, "one");
949 m.insert(2, "two");
950 assert_eq!(m.get(&2), Some(&"two"));
951 assert_eq!(m.len(), 3);
952 let keys = m.keys();
953 assert_eq!(*keys[0], 1);
954 assert_eq!(*keys[2], 3);
955 }
956 #[test]
957 fn test_label_set() {
958 let mut ls = LabelSet::new();
959 ls.add("foo");
960 ls.add("bar");
961 ls.add("foo");
962 assert_eq!(ls.count(), 2);
963 assert!(ls.has("bar"));
964 assert!(!ls.has("baz"));
965 }
966 #[test]
967 fn test_config_node() {
968 let mut root = ConfigNode::section("root");
969 let child = ConfigNode::leaf("key", "value");
970 root.add_child(child);
971 assert_eq!(root.num_children(), 1);
972 }
973 #[test]
974 fn test_versioned_record() {
975 let mut vr = VersionedRecord::new(0u32);
976 vr.update(1);
977 vr.update(2);
978 assert_eq!(*vr.current(), 2);
979 assert_eq!(vr.version(), 2);
980 assert!(vr.has_history());
981 assert_eq!(*vr.at_version(0).expect("value should be present"), 0);
982 }
983 #[test]
984 fn test_simple_dag() {
985 let mut dag = SimpleDag::new(4);
986 dag.add_edge(0, 1);
987 dag.add_edge(1, 2);
988 dag.add_edge(2, 3);
989 assert!(dag.can_reach(0, 3));
990 assert!(!dag.can_reach(3, 0));
991 let order = dag.topological_sort().expect("order should be present");
992 assert_eq!(order, vec![0, 1, 2, 3]);
993 }
994 #[test]
995 fn test_focus_stack() {
996 let mut fs: FocusStack<&str> = FocusStack::new();
997 fs.focus("a");
998 fs.focus("b");
999 assert_eq!(fs.current(), Some(&"b"));
1000 assert_eq!(fs.depth(), 2);
1001 fs.blur();
1002 assert_eq!(fs.current(), Some(&"a"));
1003 }
1004}
1005#[cfg(test)]
1006mod tests_extra_iterators {
1007 use super::*;
1008 #[test]
1009 fn test_window_iterator() {
1010 let data = vec![1u32, 2, 3, 4, 5];
1011 let windows: Vec<_> = WindowIterator::new(&data, 3).collect();
1012 assert_eq!(windows.len(), 3);
1013 assert_eq!(windows[0], &[1, 2, 3]);
1014 assert_eq!(windows[2], &[3, 4, 5]);
1015 }
1016 #[test]
1017 fn test_non_empty_vec() {
1018 let mut nev = NonEmptyVec::singleton(10u32);
1019 nev.push(20);
1020 nev.push(30);
1021 assert_eq!(nev.len(), 3);
1022 assert_eq!(*nev.first(), 10);
1023 assert_eq!(*nev.last(), 30);
1024 }
1025}
1026#[cfg(test)]
1027mod tests_padding2 {
1028 use super::*;
1029 #[test]
1030 fn test_sliding_sum() {
1031 let mut ss = SlidingSum::new(3);
1032 ss.push(1.0);
1033 ss.push(2.0);
1034 ss.push(3.0);
1035 assert!((ss.sum() - 6.0).abs() < 1e-9);
1036 ss.push(4.0);
1037 assert!((ss.sum() - 9.0).abs() < 1e-9);
1038 assert_eq!(ss.count(), 3);
1039 }
1040 #[test]
1041 fn test_path_buf() {
1042 let mut pb = PathBuf::new();
1043 pb.push("src");
1044 pb.push("main");
1045 assert_eq!(pb.as_str(), "src/main");
1046 assert_eq!(pb.depth(), 2);
1047 pb.pop();
1048 assert_eq!(pb.as_str(), "src");
1049 }
1050 #[test]
1051 fn test_string_pool() {
1052 let mut pool = StringPool::new();
1053 let s = pool.take();
1054 assert!(s.is_empty());
1055 pool.give("hello".to_string());
1056 let s2 = pool.take();
1057 assert!(s2.is_empty());
1058 assert_eq!(pool.free_count(), 0);
1059 }
1060 #[test]
1061 fn test_transitive_closure() {
1062 let mut tc = TransitiveClosure::new(4);
1063 tc.add_edge(0, 1);
1064 tc.add_edge(1, 2);
1065 tc.add_edge(2, 3);
1066 assert!(tc.can_reach(0, 3));
1067 assert!(!tc.can_reach(3, 0));
1068 let r = tc.reachable_from(0);
1069 assert_eq!(r.len(), 4);
1070 }
1071 #[test]
1072 fn test_token_bucket() {
1073 let mut tb = TokenBucket::new(100, 10);
1074 assert_eq!(tb.available(), 100);
1075 assert!(tb.try_consume(50));
1076 assert_eq!(tb.available(), 50);
1077 assert!(!tb.try_consume(60));
1078 assert_eq!(tb.capacity(), 100);
1079 }
1080 #[test]
1081 fn test_rewrite_rule_set() {
1082 let mut rrs = RewriteRuleSet::new();
1083 rrs.add(RewriteRule::unconditional(
1084 "beta",
1085 "App(Lam(x, b), v)",
1086 "b[x:=v]",
1087 ));
1088 rrs.add(RewriteRule::conditional("comm", "a + b", "b + a"));
1089 assert_eq!(rrs.len(), 2);
1090 assert_eq!(rrs.unconditional_rules().len(), 1);
1091 assert_eq!(rrs.conditional_rules().len(), 1);
1092 assert!(rrs.get("beta").is_some());
1093 let disp = rrs
1094 .get("beta")
1095 .expect("element at \'beta\' should exist")
1096 .display();
1097 assert!(disp.contains("→"));
1098 }
1099}
1100#[cfg(test)]
1101mod tests_padding3 {
1102 use super::*;
1103 #[test]
1104 fn test_decision_node() {
1105 let tree = DecisionNode::Branch {
1106 key: "x".into(),
1107 val: "1".into(),
1108 yes_branch: Box::new(DecisionNode::Leaf("yes".into())),
1109 no_branch: Box::new(DecisionNode::Leaf("no".into())),
1110 };
1111 let mut ctx = std::collections::HashMap::new();
1112 ctx.insert("x".into(), "1".into());
1113 assert_eq!(tree.evaluate(&ctx), "yes");
1114 ctx.insert("x".into(), "2".into());
1115 assert_eq!(tree.evaluate(&ctx), "no");
1116 assert_eq!(tree.depth(), 1);
1117 }
1118 #[test]
1119 fn test_flat_substitution() {
1120 let mut sub = FlatSubstitution::new();
1121 sub.add("foo", "bar");
1122 sub.add("baz", "qux");
1123 assert_eq!(sub.apply("foo and baz"), "bar and qux");
1124 assert_eq!(sub.len(), 2);
1125 }
1126 #[test]
1127 fn test_stopwatch() {
1128 let mut sw = Stopwatch::start();
1129 sw.split();
1130 sw.split();
1131 assert_eq!(sw.num_splits(), 2);
1132 assert!(sw.elapsed_ms() >= 0.0);
1133 for &s in sw.splits() {
1134 assert!(s >= 0.0);
1135 }
1136 }
1137 #[test]
1138 fn test_either2() {
1139 let e: Either2<i32, &str> = Either2::First(42);
1140 assert!(e.is_first());
1141 let mapped = e.map_first(|x| x * 2);
1142 assert_eq!(mapped.first(), Some(84));
1143 let e2: Either2<i32, &str> = Either2::Second("hello");
1144 assert!(e2.is_second());
1145 assert_eq!(e2.second(), Some("hello"));
1146 }
1147 #[test]
1148 fn test_write_once() {
1149 let wo: WriteOnce<u32> = WriteOnce::new();
1150 assert!(!wo.is_written());
1151 assert!(wo.write(42));
1152 assert!(!wo.write(99));
1153 assert_eq!(wo.read(), Some(42));
1154 }
1155 #[test]
1156 fn test_sparse_vec() {
1157 let mut sv: SparseVec<i32> = SparseVec::new(100);
1158 sv.set(5, 10);
1159 sv.set(50, 20);
1160 assert_eq!(*sv.get(5), 10);
1161 assert_eq!(*sv.get(50), 20);
1162 assert_eq!(*sv.get(0), 0);
1163 assert_eq!(sv.nnz(), 2);
1164 sv.set(5, 0);
1165 assert_eq!(sv.nnz(), 1);
1166 }
1167 #[test]
1168 fn test_stack_calc() {
1169 let mut calc = StackCalc::new();
1170 calc.push(3);
1171 calc.push(4);
1172 calc.add();
1173 assert_eq!(calc.peek(), Some(7));
1174 calc.push(2);
1175 calc.mul();
1176 assert_eq!(calc.peek(), Some(14));
1177 }
1178}
1179#[cfg(test)]
1180mod tests_final_padding {
1181 use super::*;
1182 #[test]
1183 fn test_min_heap() {
1184 let mut h = MinHeap::new();
1185 h.push(5u32);
1186 h.push(1u32);
1187 h.push(3u32);
1188 assert_eq!(h.peek(), Some(&1));
1189 assert_eq!(h.pop(), Some(1));
1190 assert_eq!(h.pop(), Some(3));
1191 assert_eq!(h.pop(), Some(5));
1192 assert!(h.is_empty());
1193 }
1194 #[test]
1195 fn test_prefix_counter() {
1196 let mut pc = PrefixCounter::new();
1197 pc.record("hello");
1198 pc.record("help");
1199 pc.record("world");
1200 assert_eq!(pc.count_with_prefix("hel"), 2);
1201 assert_eq!(pc.count_with_prefix("wor"), 1);
1202 assert_eq!(pc.count_with_prefix("xyz"), 0);
1203 }
1204 #[test]
1205 fn test_fixture() {
1206 let mut f = Fixture::new();
1207 f.set("key1", "val1");
1208 f.set("key2", "val2");
1209 assert_eq!(f.get("key1"), Some("val1"));
1210 assert_eq!(f.get("key3"), None);
1211 assert_eq!(f.len(), 2);
1212 }
1213}