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