1use crate::expr_util::has_any_fvar;
6use crate::subst::instantiate;
7use crate::Node;
8use crate::{Expr, FVarId, Name};
9use std::rc::Rc;
10
11use super::types::{
12 ConfigNode, DecisionNode, Either2, Fixture, FlatSubstitution, FocusStack, LabelSet, MinHeap,
13 NonEmptyVec, PathBuf, PrefixCounter, RewriteRule, RewriteRuleSet, SimpleDag, SlidingSum,
14 SmallMap, SparseVec, StackCalc, StatSummary, Stopwatch, StringPool, TokenBucket, TransformStat,
15 TransitiveClosure, VersionedRecord, WindowIterator, WriteOnce,
16};
17
18pub fn abstract_fvars(expr: &Expr, fvars: &[FVarId]) -> Expr {
28 if fvars.is_empty() || !has_any_fvar(expr) {
29 return expr.clone();
30 }
31 abstract_fvars_at(expr, fvars, 0)
32}
33fn abstract_fvars_at(expr: &Expr, fvars: &[FVarId], offset: u32) -> Expr {
34 match expr {
35 Expr::FVar(id) => {
36 let n = fvars.len();
37 for (i, fv) in fvars.iter().enumerate().rev() {
38 if id == fv {
39 return Expr::BVar(offset + (n - i - 1) as u32);
40 }
41 }
42 for (i, fv) in fvars.iter().enumerate() {
43 if id == fv {
44 return Expr::BVar(offset + (n - i - 1) as u32);
45 }
46 }
47 expr.clone()
48 }
49 Expr::BVar(_) | Expr::Sort(_) | Expr::Const(_, _) | Expr::Lit(_) => expr.clone(),
50 Expr::App(f, a) => {
51 let f_new = abstract_fvars_at(f, fvars, offset);
52 let a_new = abstract_fvars_at(a, fvars, offset);
53 Expr::App(Node::new(f_new), Node::new(a_new))
54 }
55 Expr::Lam(bi, name, ty, body) => {
56 let ty_new = abstract_fvars_at(ty, fvars, offset);
57 let body_new = abstract_fvars_at(body, fvars, offset + 1);
58 Expr::Lam(*bi, name.clone(), Node::new(ty_new), Node::new(body_new))
59 }
60 Expr::Pi(bi, name, ty, body) => {
61 let ty_new = abstract_fvars_at(ty, fvars, offset);
62 let body_new = abstract_fvars_at(body, fvars, offset + 1);
63 Expr::Pi(*bi, name.clone(), Node::new(ty_new), Node::new(body_new))
64 }
65 Expr::Let(name, ty, val, body) => {
66 let ty_new = abstract_fvars_at(ty, fvars, offset);
67 let val_new = abstract_fvars_at(val, fvars, offset);
68 let body_new = abstract_fvars_at(body, fvars, offset + 1);
69 Expr::Let(
70 name.clone(),
71 Node::new(ty_new),
72 Node::new(val_new),
73 Node::new(body_new),
74 )
75 }
76 Expr::Proj(name, idx, e) => {
77 let e_new = abstract_fvars_at(e, fvars, offset);
78 Expr::Proj(name.clone(), *idx, Node::new(e_new))
79 }
80 }
81}
82pub fn abstract_single(expr: &Expr, fvar: FVarId) -> Expr {
86 crate::subst::abstract_expr(expr, fvar)
87}
88pub fn cheap_beta_reduce(expr: &Expr) -> Expr {
93 match expr {
94 Expr::App(f, a) => {
95 if let Expr::Lam(_, _, _, body) = f.as_ref() {
96 let result = instantiate(body, a);
97 cheap_beta_reduce(&result)
98 } else {
99 expr.clone()
100 }
101 }
102 _ => expr.clone(),
103 }
104}
105pub fn apply_beta(mut expr: Expr, args: &[Expr]) -> Expr {
109 for arg in args {
110 match expr {
111 Expr::Lam(_, _, _, body) => {
112 expr = instantiate(&body, arg);
113 }
114 _ => {
115 expr = Expr::App(Node::new(expr), Node::new(arg.clone()));
116 }
117 }
118 }
119 expr
120}
121pub fn mk_lambda(fvars: &[(FVarId, Name, Expr)], body: &Expr) -> Expr {
126 let fvar_ids: Vec<FVarId> = fvars.iter().map(|(id, _, _)| *id).collect();
127 let mut result = abstract_fvars(body, &fvar_ids);
128 for (_, name, ty) in fvars.iter().rev() {
129 let ty_abs = abstract_fvars(ty, &fvar_ids);
130 result = Expr::Lam(
131 crate::BinderInfo::Default,
132 name.clone(),
133 Node::new(ty_abs),
134 Node::new(result),
135 );
136 }
137 result
138}
139pub fn mk_forall(fvars: &[(FVarId, Name, Expr)], body: &Expr) -> Expr {
144 let fvar_ids: Vec<FVarId> = fvars.iter().map(|(id, _, _)| *id).collect();
145 let mut result = abstract_fvars(body, &fvar_ids);
146 for (_, name, ty) in fvars.iter().rev() {
147 let ty_abs = abstract_fvars(ty, &fvar_ids);
148 result = Expr::Pi(
149 crate::BinderInfo::Default,
150 name.clone(),
151 Node::new(ty_abs),
152 Node::new(result),
153 );
154 }
155 result
156}
157#[cfg(test)]
158mod tests {
159 use super::*;
160 use crate::{BinderInfo, Level};
161 #[test]
162 fn test_abstract_fvars_single() {
163 let fvar = FVarId(42);
164 let e = Expr::FVar(fvar);
165 let result = abstract_fvars(&e, &[fvar]);
166 assert_eq!(result, Expr::BVar(0));
167 }
168 #[test]
169 fn test_abstract_fvars_multiple() {
170 let x = FVarId(1);
171 let y = FVarId(2);
172 let z = FVarId(3);
173 let e = Expr::App(
174 Node::new(Expr::App(
175 Node::new(Expr::App(
176 Node::new(Expr::Const(Name::str("f"), vec![])),
177 Node::new(Expr::FVar(x)),
178 )),
179 Node::new(Expr::FVar(y)),
180 )),
181 Node::new(Expr::FVar(z)),
182 );
183 let result = abstract_fvars(&e, &[x, y, z]);
184 let expected = Expr::App(
185 Node::new(Expr::App(
186 Node::new(Expr::App(
187 Node::new(Expr::Const(Name::str("f"), vec![])),
188 Node::new(Expr::BVar(2)),
189 )),
190 Node::new(Expr::BVar(1)),
191 )),
192 Node::new(Expr::BVar(0)),
193 );
194 assert_eq!(result, expected);
195 }
196 #[test]
197 fn test_abstract_fvars_under_binder() {
198 let x = FVarId(1);
199 let e = Expr::Lam(
200 BinderInfo::Default,
201 Name::str("a"),
202 Node::new(Expr::Sort(Level::zero())),
203 Node::new(Expr::App(
204 Node::new(Expr::Const(Name::str("f"), vec![])),
205 Node::new(Expr::FVar(x)),
206 )),
207 );
208 let result = abstract_fvars(&e, &[x]);
209 if let Expr::Lam(_, _, _, body) = &result {
210 if let Expr::App(_, arg) = body.as_ref() {
211 assert_eq!(**arg, Expr::BVar(1));
212 } else {
213 panic!("Expected App");
214 }
215 } else {
216 panic!("Expected Lam");
217 }
218 }
219 #[test]
220 fn test_abstract_no_fvars() {
221 let e = Expr::Const(Name::str("Nat"), vec![]);
222 let result = abstract_fvars(&e, &[FVarId(1)]);
223 assert_eq!(result, e);
224 }
225 #[test]
226 fn test_cheap_beta_reduce() {
227 let lam = Expr::Lam(
228 BinderInfo::Default,
229 Name::str("x"),
230 Node::new(Expr::Sort(Level::zero())),
231 Node::new(Expr::BVar(0)),
232 );
233 let a = Expr::FVar(FVarId(99));
234 let app = Expr::App(Node::new(lam), Node::new(a.clone()));
235 let result = cheap_beta_reduce(&app);
236 assert_eq!(result, a);
237 }
238 #[test]
239 fn test_cheap_beta_reduce_non_redex() {
240 let app = Expr::App(
241 Node::new(Expr::Const(Name::str("f"), vec![])),
242 Node::new(Expr::BVar(0)),
243 );
244 let result = cheap_beta_reduce(&app);
245 assert_eq!(result, app);
246 }
247 #[test]
248 fn test_apply_beta() {
249 let inner = Expr::Lam(
250 BinderInfo::Default,
251 Name::str("y"),
252 Node::new(Expr::Sort(Level::zero())),
253 Node::new(Expr::BVar(1)),
254 );
255 let lam = Expr::Lam(
256 BinderInfo::Default,
257 Name::str("x"),
258 Node::new(Expr::Sort(Level::zero())),
259 Node::new(inner),
260 );
261 let a = Expr::FVar(FVarId(1));
262 let b = Expr::FVar(FVarId(2));
263 let result = apply_beta(lam, &[a.clone(), b]);
264 assert_eq!(result, a);
265 }
266 #[test]
267 fn test_abstract_roundtrip() {
268 let x = FVarId(1);
269 let y = FVarId(2);
270 let e = Expr::App(Node::new(Expr::FVar(x)), Node::new(Expr::FVar(y)));
271 let abstracted = abstract_fvars(&e, &[x, y]);
272 let back =
273 crate::instantiate::instantiate_rev(&abstracted, &[Expr::FVar(x), Expr::FVar(y)]);
274 assert_eq!(back, e);
275 }
276}
277pub fn let_abstract(expr: &Expr, fvar: FVarId, ty: &Expr, val: &Expr) -> Expr {
279 let body = abstract_fvars(expr, &[fvar]);
280 Expr::Let(
281 Name::str("_let"),
282 Node::new(ty.clone()),
283 Node::new(val.clone()),
284 Node::new(body),
285 )
286}
287pub fn count_fvar_occurrences(expr: &Expr, fvar: FVarId) -> usize {
289 match expr {
290 Expr::FVar(id) => {
291 if *id == fvar {
292 1
293 } else {
294 0
295 }
296 }
297 Expr::BVar(_) | Expr::Sort(_) | Expr::Const(_, _) | Expr::Lit(_) => 0,
298 Expr::App(f, a) => count_fvar_occurrences(f, fvar) + count_fvar_occurrences(a, fvar),
299 Expr::Lam(_, _, ty, body) | Expr::Pi(_, _, ty, body) => {
300 count_fvar_occurrences(ty, fvar) + count_fvar_occurrences(body, fvar)
301 }
302 Expr::Let(_, ty, val, body) => {
303 count_fvar_occurrences(ty, fvar)
304 + count_fvar_occurrences(val, fvar)
305 + count_fvar_occurrences(body, fvar)
306 }
307 Expr::Proj(_, _, e) => count_fvar_occurrences(e, fvar),
308 }
309}
310pub fn collect_fvars(expr: &Expr) -> std::collections::HashSet<FVarId> {
312 let mut result = std::collections::HashSet::new();
313 collect_fvars_impl(expr, &mut result);
314 result
315}
316fn collect_fvars_impl(expr: &Expr, result: &mut std::collections::HashSet<FVarId>) {
317 match expr {
318 Expr::FVar(id) => {
319 result.insert(*id);
320 }
321 Expr::BVar(_) | Expr::Sort(_) | Expr::Const(_, _) | Expr::Lit(_) => {}
322 Expr::App(f, a) => {
323 collect_fvars_impl(f, result);
324 collect_fvars_impl(a, result);
325 }
326 Expr::Lam(_, _, ty, body) | Expr::Pi(_, _, ty, body) => {
327 collect_fvars_impl(ty, result);
328 collect_fvars_impl(body, result);
329 }
330 Expr::Let(_, ty, val, body) => {
331 collect_fvars_impl(ty, result);
332 collect_fvars_impl(val, result);
333 collect_fvars_impl(body, result);
334 }
335 Expr::Proj(_, _, e) => collect_fvars_impl(e, result),
336 }
337}
338pub fn is_closed_under(expr: &Expr, allowed_fvars: &[FVarId]) -> bool {
340 let free = collect_fvars(expr);
341 free.iter().all(|fv| allowed_fvars.contains(fv))
342}
343pub fn subst_fvar(expr: &Expr, fvar: FVarId, replacement: &Expr) -> Expr {
345 match expr {
346 Expr::FVar(id) => {
347 if *id == fvar {
348 replacement.clone()
349 } else {
350 expr.clone()
351 }
352 }
353 Expr::BVar(_) | Expr::Sort(_) | Expr::Const(_, _) | Expr::Lit(_) => expr.clone(),
354 Expr::App(f, a) => Expr::App(
355 Node::new(subst_fvar(f, fvar, replacement)),
356 Node::new(subst_fvar(a, fvar, replacement)),
357 ),
358 Expr::Lam(bi, name, ty, body) => {
359 let ty_new = subst_fvar(ty, fvar, replacement);
360 let shifted = shift_bvars(replacement, 1, 0);
361 Expr::Lam(
362 *bi,
363 name.clone(),
364 Node::new(ty_new),
365 Node::new(subst_fvar(body, fvar, &shifted)),
366 )
367 }
368 Expr::Pi(bi, name, ty, body) => {
369 let ty_new = subst_fvar(ty, fvar, replacement);
370 let shifted = shift_bvars(replacement, 1, 0);
371 Expr::Pi(
372 *bi,
373 name.clone(),
374 Node::new(ty_new),
375 Node::new(subst_fvar(body, fvar, &shifted)),
376 )
377 }
378 Expr::Let(name, ty, val, body) => {
379 let ty_new = subst_fvar(ty, fvar, replacement);
380 let val_new = subst_fvar(val, fvar, replacement);
381 let shifted = shift_bvars(replacement, 1, 0);
382 Expr::Let(
383 name.clone(),
384 Node::new(ty_new),
385 Node::new(val_new),
386 Node::new(subst_fvar(body, fvar, &shifted)),
387 )
388 }
389 Expr::Proj(name, idx, e) => Expr::Proj(
390 name.clone(),
391 *idx,
392 Node::new(subst_fvar(e, fvar, replacement)),
393 ),
394 }
395}
396pub fn shift_bvars(expr: &Expr, amount: u32, cutoff: u32) -> Expr {
398 match expr {
399 Expr::BVar(i) => {
400 if *i >= cutoff {
401 Expr::BVar(*i + amount)
402 } else {
403 expr.clone()
404 }
405 }
406 Expr::FVar(_) | Expr::Sort(_) | Expr::Const(_, _) | Expr::Lit(_) => expr.clone(),
407 Expr::App(f, a) => Expr::App(
408 Node::new(shift_bvars(f, amount, cutoff)),
409 Node::new(shift_bvars(a, amount, cutoff)),
410 ),
411 Expr::Lam(bi, name, ty, body) => Expr::Lam(
412 *bi,
413 name.clone(),
414 Node::new(shift_bvars(ty, amount, cutoff)),
415 Node::new(shift_bvars(body, amount, cutoff + 1)),
416 ),
417 Expr::Pi(bi, name, ty, body) => Expr::Pi(
418 *bi,
419 name.clone(),
420 Node::new(shift_bvars(ty, amount, cutoff)),
421 Node::new(shift_bvars(body, amount, cutoff + 1)),
422 ),
423 Expr::Let(name, ty, val, body) => Expr::Let(
424 name.clone(),
425 Node::new(shift_bvars(ty, amount, cutoff)),
426 Node::new(shift_bvars(val, amount, cutoff)),
427 Node::new(shift_bvars(body, amount, cutoff + 1)),
428 ),
429 Expr::Proj(name, idx, e) => Expr::Proj(
430 name.clone(),
431 *idx,
432 Node::new(shift_bvars(e, amount, cutoff)),
433 ),
434 }
435}
436pub fn split_pi(expr: &Expr) -> Option<(&Expr, &Expr)> {
438 if let Expr::Pi(_, _, ty, body) = expr {
439 Some((ty, body))
440 } else {
441 None
442 }
443}
444pub fn split_lam(expr: &Expr) -> Option<(&Expr, &Expr)> {
446 if let Expr::Lam(_, _, ty, body) = expr {
447 Some((ty, body))
448 } else {
449 None
450 }
451}
452pub fn mk_app(f: Expr, args: &[Expr]) -> Expr {
454 let mut result = f;
455 for arg in args {
456 result = Expr::App(Node::new(result), Node::new(arg.clone()));
457 }
458 result
459}
460pub fn collect_app(expr: &Expr) -> (&Expr, Vec<&Expr>) {
462 let mut args = Vec::new();
463 let mut e = expr;
464 while let Expr::App(f, a) = e {
465 args.push(a.as_ref());
466 e = f;
467 }
468 args.reverse();
469 (e, args)
470}
471pub fn pi_arity(expr: &Expr) -> usize {
473 let mut n = 0;
474 let mut e = expr;
475 while let Expr::Pi(_, _, _, body) = e {
476 n += 1;
477 e = body;
478 }
479 n
480}
481pub fn lam_arity(expr: &Expr) -> usize {
483 let mut n = 0;
484 let mut e = expr;
485 while let Expr::Lam(_, _, _, body) = e {
486 n += 1;
487 e = body;
488 }
489 n
490}
491#[cfg(test)]
492mod extended_tests {
493 use super::*;
494 use crate::{BinderInfo, Level};
495 #[test]
496 fn test_count_fvar_occurrences_zero() {
497 assert_eq!(count_fvar_occurrences(&Expr::BVar(0), FVarId(1)), 0);
498 }
499 #[test]
500 fn test_count_fvar_occurrences_one() {
501 let fv = FVarId(5);
502 assert_eq!(count_fvar_occurrences(&Expr::FVar(fv), fv), 1);
503 }
504 #[test]
505 fn test_count_fvar_occurrences_multiple() {
506 let fv = FVarId(5);
507 let e = Expr::App(Node::new(Expr::FVar(fv)), Node::new(Expr::FVar(fv)));
508 assert_eq!(count_fvar_occurrences(&e, fv), 2);
509 }
510 #[test]
511 fn test_collect_fvars_empty() {
512 assert!(collect_fvars(&Expr::BVar(0)).is_empty());
513 }
514 #[test]
515 fn test_collect_fvars_multi() {
516 let x = FVarId(1);
517 let y = FVarId(2);
518 let e = Expr::App(Node::new(Expr::FVar(x)), Node::new(Expr::FVar(y)));
519 let fvars = collect_fvars(&e);
520 assert!(fvars.contains(&x) && fvars.contains(&y));
521 }
522 #[test]
523 fn test_subst_fvar_replacement() {
524 let x = FVarId(1);
525 let replacement = Expr::Const(Name::str("Nat"), vec![]);
526 let result = subst_fvar(&Expr::FVar(x), x, &replacement);
527 assert_eq!(result, replacement);
528 }
529 #[test]
530 fn test_shift_bvars_above_cutoff() {
531 let shifted = shift_bvars(&Expr::BVar(2), 1, 0);
532 assert_eq!(shifted, Expr::BVar(3));
533 }
534 #[test]
535 fn test_shift_bvars_below_cutoff() {
536 let shifted = shift_bvars(&Expr::BVar(0), 5, 2);
537 assert_eq!(shifted, Expr::BVar(0));
538 }
539 #[test]
540 fn test_is_closed_under() {
541 let x = FVarId(1);
542 assert!(is_closed_under(&Expr::FVar(x), &[x]));
543 assert!(!is_closed_under(&Expr::FVar(x), &[]));
544 }
545 #[test]
546 fn test_split_pi() {
547 let ty = Expr::Sort(Level::zero());
548 let body = Expr::BVar(0);
549 let pi = Expr::Pi(
550 BinderInfo::Default,
551 Name::str("x"),
552 Node::new(ty.clone()),
553 Node::new(body.clone()),
554 );
555 let (d, c) = split_pi(&pi).expect("value should be present");
556 assert_eq!(d, &ty);
557 assert_eq!(c, &body);
558 }
559 #[test]
560 fn test_mk_app_multiple() {
561 let f = Expr::Const(Name::str("f"), vec![]);
562 let a = Expr::BVar(0);
563 let b = Expr::BVar(1);
564 let result = mk_app(f.clone(), &[a.clone(), b.clone()]);
565 let expected = Expr::App(
566 Node::new(Expr::App(Node::new(f), Node::new(a))),
567 Node::new(b),
568 );
569 assert_eq!(result, expected);
570 }
571 #[test]
572 fn test_collect_app() {
573 let f = Expr::Const(Name::str("f"), vec![]);
574 let a = Expr::BVar(0);
575 let b = Expr::BVar(1);
576 let app = Expr::App(
577 Node::new(Expr::App(Node::new(f.clone()), Node::new(a.clone()))),
578 Node::new(b.clone()),
579 );
580 let (head, args) = collect_app(&app);
581 assert_eq!(head, &f);
582 assert_eq!(args.len(), 2);
583 }
584 #[test]
585 fn test_pi_arity() {
586 let base = Expr::Sort(Level::zero());
587 let pi1 = Expr::Pi(
588 BinderInfo::Default,
589 Name::str("x"),
590 Node::new(base.clone()),
591 Node::new(base.clone()),
592 );
593 let pi2 = Expr::Pi(
594 BinderInfo::Default,
595 Name::str("y"),
596 Node::new(base.clone()),
597 Node::new(pi1),
598 );
599 assert_eq!(pi_arity(&pi2), 2);
600 }
601 #[test]
602 fn test_let_abstract() {
603 let x = FVarId(10);
604 let ty = Expr::Const(Name::str("Nat"), vec![]);
605 let val = Expr::Lit(crate::Literal::nat(42));
606 let result = let_abstract(&Expr::FVar(x), x, &ty, &val);
607 assert!(matches!(result, Expr::Let(_, _, _, _)));
608 }
609}
610pub fn topo_sort_fvars(fvars: &[(FVarId, Expr)]) -> Result<Vec<FVarId>, String> {
612 let n = fvars.len();
613 let mut result = Vec::with_capacity(n);
614 let mut visited = vec![false; n];
615 let id_to_idx: std::collections::HashMap<FVarId, usize> = fvars
616 .iter()
617 .enumerate()
618 .map(|(i, (id, _))| (*id, i))
619 .collect();
620 fn visit(
621 i: usize,
622 fvars: &[(FVarId, Expr)],
623 id_to_idx: &std::collections::HashMap<FVarId, usize>,
624 visited: &mut Vec<bool>,
625 in_stack: &mut Vec<bool>,
626 result: &mut Vec<FVarId>,
627 ) -> Result<(), String> {
628 if in_stack[i] {
629 return Err(format!("cycle involving {:?}", fvars[i].0));
630 }
631 if visited[i] {
632 return Ok(());
633 }
634 in_stack[i] = true;
635 let deps = {
636 let mut set = std::collections::HashSet::new();
637 collect_fvars_impl(&fvars[i].1, &mut set);
638 set
639 };
640 for dep in deps {
641 if let Some(&j) = id_to_idx.get(&dep) {
642 visit(j, fvars, id_to_idx, visited, in_stack, result)?;
643 }
644 }
645 in_stack[i] = false;
646 visited[i] = true;
647 result.push(fvars[i].0);
648 Ok(())
649 }
650 let mut in_stack = vec![false; n];
651 for i in 0..n {
652 visit(
653 i,
654 fvars,
655 &id_to_idx,
656 &mut visited,
657 &mut in_stack,
658 &mut result,
659 )?;
660 }
661 Ok(result)
662}
663pub fn abstract_fvars_ordered(
665 expr: &Expr,
666 fvars: &[(FVarId, Expr)],
667) -> Result<(Expr, Vec<FVarId>), String> {
668 let sorted = topo_sort_fvars(fvars)?;
669 let abstracted = abstract_fvars(expr, &sorted);
670 Ok((abstracted, sorted))
671}
672pub fn let_abstract_many(expr: &Expr, bindings: &[(FVarId, Name, Expr, Expr)]) -> Expr {
674 let fvar_ids: Vec<FVarId> = bindings.iter().map(|(id, _, _, _)| *id).collect();
675 let mut result = abstract_fvars(expr, &fvar_ids);
676 for (_, name, ty, val) in bindings.iter().rev() {
677 result = Expr::Let(
678 name.clone(),
679 Node::new(ty.clone()),
680 Node::new(val.clone()),
681 Node::new(result),
682 );
683 }
684 result
685}
686#[cfg(test)]
687mod topo_tests {
688 use super::*;
689 use crate::{BinderInfo, Level};
690 #[test]
691 fn test_topo_sort_no_deps() {
692 let x = FVarId(1);
693 let y = FVarId(2);
694 let fvars = vec![(x, Expr::BVar(0)), (y, Expr::Sort(Level::zero()))];
695 let sorted = topo_sort_fvars(&fvars).expect("sorted should be present");
696 assert_eq!(sorted.len(), 2);
697 }
698 #[test]
699 fn test_abstract_fvars_ordered_simple() {
700 let x = FVarId(1);
701 let fvars = vec![(x, Expr::Sort(Level::zero()))];
702 let (abstracted, order) =
703 abstract_fvars_ordered(&Expr::FVar(x), &fvars).expect("value should be present");
704 assert_eq!(abstracted, Expr::BVar(0));
705 assert_eq!(order, vec![x]);
706 }
707 #[test]
708 fn test_let_abstract_many_empty() {
709 let body = Expr::BVar(0);
710 let result = let_abstract_many(&body, &[]);
711 assert_eq!(result, body);
712 }
713 #[test]
714 fn test_lam_arity() {
715 let base = Expr::Sort(Level::zero());
716 let lam = Expr::Lam(
717 BinderInfo::Default,
718 Name::str("x"),
719 Node::new(base.clone()),
720 Node::new(base.clone()),
721 );
722 assert_eq!(lam_arity(&lam), 1);
723 assert_eq!(lam_arity(&base), 0);
724 }
725 #[test]
726 fn test_split_lam() {
727 let ty = Expr::Sort(Level::zero());
728 let body = Expr::BVar(0);
729 let lam = Expr::Lam(
730 BinderInfo::Default,
731 Name::str("x"),
732 Node::new(ty.clone()),
733 Node::new(body.clone()),
734 );
735 let (d, b) = split_lam(&lam).expect("value should be present");
736 assert_eq!(d, &ty);
737 assert_eq!(b, &body);
738 }
739 #[test]
740 fn test_split_pi_not_pi() {
741 assert!(split_pi(&Expr::BVar(0)).is_none());
742 }
743 #[test]
744 fn test_mk_app_empty() {
745 let f = Expr::Const(Name::str("f"), vec![]);
746 assert_eq!(mk_app(f.clone(), &[]), f);
747 }
748 #[test]
749 fn test_mk_forall_empty() {
750 let body = Expr::Sort(Level::zero());
751 assert_eq!(mk_forall(&[], &body), body);
752 }
753 #[test]
754 fn test_mk_lambda_empty() {
755 let body = Expr::BVar(0);
756 assert_eq!(mk_lambda(&[], &body), body);
757 }
758 #[test]
759 fn test_subst_fvar_identity() {
760 let x = FVarId(1);
761 let y = FVarId(2);
762 let e = Expr::FVar(x);
763 let result = subst_fvar(&e, y, &Expr::BVar(0));
764 assert_eq!(result, e);
765 }
766}
767pub fn is_ground(expr: &Expr) -> bool {
771 collect_fvars(expr).is_empty() && !has_any_bvar(expr)
772}
773fn has_any_bvar(expr: &Expr) -> bool {
774 match expr {
775 Expr::BVar(_) => true,
776 Expr::FVar(_) | Expr::Sort(_) | Expr::Const(_, _) | Expr::Lit(_) => false,
777 Expr::App(f, a) => has_any_bvar(f) || has_any_bvar(a),
778 Expr::Lam(_, _, ty, body) | Expr::Pi(_, _, ty, body) => {
779 has_any_bvar(ty) || has_any_bvar(body)
780 }
781 Expr::Let(_, ty, val, body) => has_any_bvar(ty) || has_any_bvar(val) || has_any_bvar(body),
782 Expr::Proj(_, _, e) => has_any_bvar(e),
783 }
784}
785pub fn max_bvar(expr: &Expr) -> Option<u32> {
789 match expr {
790 Expr::BVar(i) => Some(*i),
791 Expr::FVar(_) | Expr::Sort(_) | Expr::Const(_, _) | Expr::Lit(_) => None,
792 Expr::App(f, a) => match (max_bvar(f), max_bvar(a)) {
793 (Some(x), Some(y)) => Some(x.max(y)),
794 (Some(x), None) | (None, Some(x)) => Some(x),
795 (None, None) => None,
796 },
797 Expr::Lam(_, _, ty, body) | Expr::Pi(_, _, ty, body) => {
798 match (max_bvar(ty), max_bvar(body)) {
799 (Some(x), Some(y)) => Some(x.max(y)),
800 (Some(x), None) | (None, Some(x)) => Some(x),
801 (None, None) => None,
802 }
803 }
804 Expr::Let(_, ty, val, body) => {
805 let m1 = max_bvar(ty);
806 let m2 = max_bvar(val);
807 let m3 = max_bvar(body);
808 [m1, m2, m3].iter().filter_map(|&x| x).max()
809 }
810 Expr::Proj(_, _, e) => max_bvar(e),
811 }
812}
813#[cfg(test)]
814mod ground_tests {
815 use super::*;
816 use crate::Literal;
817 #[test]
818 fn test_is_ground_lit() {
819 assert!(is_ground(&Expr::Lit(Literal::nat(42))));
820 }
821 #[test]
822 fn test_is_ground_bvar() {
823 assert!(!is_ground(&Expr::BVar(0)));
824 }
825 #[test]
826 fn test_is_ground_fvar() {
827 assert!(!is_ground(&Expr::FVar(FVarId(1))));
828 }
829 #[test]
830 fn test_max_bvar_none() {
831 assert_eq!(max_bvar(&Expr::Lit(Literal::nat(0))), None);
832 }
833 #[test]
834 fn test_max_bvar_some() {
835 assert_eq!(max_bvar(&Expr::BVar(3)), Some(3));
836 }
837 #[test]
838 fn test_max_bvar_app() {
839 let e = Expr::App(Node::new(Expr::BVar(2)), Node::new(Expr::BVar(5)));
840 assert_eq!(max_bvar(&e), Some(5));
841 }
842}
843#[allow(dead_code)]
845pub fn distinct_const_count(expr: &Expr) -> usize {
846 let mut seen = std::collections::HashSet::new();
847 collect_const_names(expr, &mut seen);
848 seen.len()
849}
850fn collect_const_names(expr: &Expr, seen: &mut std::collections::HashSet<String>) {
851 match expr {
852 Expr::Const(name, _) => {
853 seen.insert(name.to_string());
854 }
855 Expr::App(f, a) => {
856 collect_const_names(f, seen);
857 collect_const_names(a, seen);
858 }
859 Expr::Lam(_, _, ty, body) | Expr::Pi(_, _, ty, body) => {
860 collect_const_names(ty, seen);
861 collect_const_names(body, seen);
862 }
863 Expr::Let(_, ty, val, body) => {
864 collect_const_names(ty, seen);
865 collect_const_names(val, seen);
866 collect_const_names(body, seen);
867 }
868 Expr::Proj(_, _, e) => collect_const_names(e, seen),
869 _ => {}
870 }
871}
872#[allow(dead_code)]
878pub fn bvars_in_range(expr: &Expr, open_binders: u32) -> bool {
879 check_bvars(expr, open_binders)
880}
881fn check_bvars(expr: &Expr, depth: u32) -> bool {
882 match expr {
883 Expr::BVar(i) => *i < depth,
884 Expr::FVar(_) | Expr::Sort(_) | Expr::Const(_, _) | Expr::Lit(_) => true,
885 Expr::App(f, a) => check_bvars(f, depth) && check_bvars(a, depth),
886 Expr::Lam(_, _, ty, body) | Expr::Pi(_, _, ty, body) => {
887 check_bvars(ty, depth) && check_bvars(body, depth + 1)
888 }
889 Expr::Let(_, ty, val, body) => {
890 check_bvars(ty, depth) && check_bvars(val, depth) && check_bvars(body, depth + 1)
891 }
892 Expr::Proj(_, _, e) => check_bvars(e, depth),
893 }
894}
895#[allow(dead_code)]
897pub fn rename_const(expr: &Expr, old_name: &Name, new_name: &Name) -> Expr {
898 match expr {
899 Expr::Const(n, ls) => {
900 if n == old_name {
901 Expr::Const(new_name.clone(), ls.clone())
902 } else {
903 expr.clone()
904 }
905 }
906 Expr::App(f, a) => Expr::App(
907 Node::new(rename_const(f, old_name, new_name)),
908 Node::new(rename_const(a, old_name, new_name)),
909 ),
910 Expr::Lam(bi, name, ty, body) => Expr::Lam(
911 *bi,
912 name.clone(),
913 Node::new(rename_const(ty, old_name, new_name)),
914 Node::new(rename_const(body, old_name, new_name)),
915 ),
916 Expr::Pi(bi, name, ty, body) => Expr::Pi(
917 *bi,
918 name.clone(),
919 Node::new(rename_const(ty, old_name, new_name)),
920 Node::new(rename_const(body, old_name, new_name)),
921 ),
922 Expr::Let(name, ty, val, body) => Expr::Let(
923 name.clone(),
924 Node::new(rename_const(ty, old_name, new_name)),
925 Node::new(rename_const(val, old_name, new_name)),
926 Node::new(rename_const(body, old_name, new_name)),
927 ),
928 Expr::Proj(n, i, e) => Expr::Proj(
929 n.clone(),
930 *i,
931 Node::new(rename_const(e, old_name, new_name)),
932 ),
933 _ => expr.clone(),
934 }
935}
936#[allow(dead_code)]
938pub fn replace_nat_lit(expr: &Expr, old: u64, new: u64) -> Expr {
939 match expr {
940 Expr::Lit(crate::Literal::Nat(n)) => {
941 if *n == old {
942 Expr::Lit(crate::Literal::nat(new))
943 } else {
944 expr.clone()
945 }
946 }
947 Expr::App(f, a) => Expr::App(
948 Node::new(replace_nat_lit(f, old, new)),
949 Node::new(replace_nat_lit(a, old, new)),
950 ),
951 Expr::Lam(bi, name, ty, body) => Expr::Lam(
952 *bi,
953 name.clone(),
954 Node::new(replace_nat_lit(ty, old, new)),
955 Node::new(replace_nat_lit(body, old, new)),
956 ),
957 Expr::Pi(bi, name, ty, body) => Expr::Pi(
958 *bi,
959 name.clone(),
960 Node::new(replace_nat_lit(ty, old, new)),
961 Node::new(replace_nat_lit(body, old, new)),
962 ),
963 Expr::Let(name, ty, val, body) => Expr::Let(
964 name.clone(),
965 Node::new(replace_nat_lit(ty, old, new)),
966 Node::new(replace_nat_lit(val, old, new)),
967 Node::new(replace_nat_lit(body, old, new)),
968 ),
969 Expr::Proj(n, i, e) => Expr::Proj(n.clone(), *i, Node::new(replace_nat_lit(e, old, new))),
970 _ => expr.clone(),
971 }
972}
973#[cfg(test)]
974mod extra_abstract_tests {
975 use super::*;
976 use crate::{BinderInfo, Level, Literal};
977 #[test]
978 fn test_distinct_const_count_zero() {
979 assert_eq!(distinct_const_count(&Expr::BVar(0)), 0);
980 }
981 #[test]
982 fn test_distinct_const_count_one() {
983 let e = Expr::Const(Name::str("Nat"), vec![]);
984 assert_eq!(distinct_const_count(&e), 1);
985 }
986 #[test]
987 fn test_distinct_const_count_dedup() {
988 let nat = Expr::Const(Name::str("Nat"), vec![]);
989 let e = Expr::App(Node::new(nat.clone()), Node::new(nat));
990 assert_eq!(distinct_const_count(&e), 1);
991 }
992 #[test]
993 fn test_bvars_in_range_closed() {
994 let e = Expr::Lit(Literal::nat(42));
995 assert!(bvars_in_range(&e, 0));
996 }
997 #[test]
998 fn test_bvars_in_range_bvar_ok() {
999 let e = Expr::Lam(
1000 BinderInfo::Default,
1001 Name::str("x"),
1002 Node::new(Expr::Sort(Level::zero())),
1003 Node::new(Expr::BVar(0)),
1004 );
1005 assert!(bvars_in_range(&e, 0));
1006 }
1007 #[test]
1008 fn test_bvars_in_range_bvar_out_of_range() {
1009 assert!(!bvars_in_range(&Expr::BVar(0), 0));
1010 }
1011 #[test]
1012 fn test_rename_const() {
1013 let e = Expr::Const(Name::str("Nat"), vec![]);
1014 let renamed = rename_const(&e, &Name::str("Nat"), &Name::str("Int"));
1015 assert!(matches!(renamed, Expr::Const(n, _) if n == Name::str("Int")));
1016 }
1017 #[test]
1018 fn test_rename_const_no_match() {
1019 let e = Expr::Const(Name::str("Bool"), vec![]);
1020 let renamed = rename_const(&e, &Name::str("Nat"), &Name::str("Int"));
1021 assert_eq!(renamed, e);
1022 }
1023 #[test]
1024 fn test_replace_nat_lit() {
1025 let e = Expr::Lit(Literal::nat(42));
1026 let replaced = replace_nat_lit(&e, 42, 0);
1027 assert_eq!(replaced, Expr::Lit(Literal::nat(0)));
1028 }
1029 #[test]
1030 fn test_replace_nat_lit_no_match() {
1031 let e = Expr::Lit(Literal::nat(1));
1032 let replaced = replace_nat_lit(&e, 42, 0);
1033 assert_eq!(replaced, e);
1034 }
1035 #[test]
1036 fn test_has_any_bvar_const() {
1037 assert!(!has_any_bvar(&Expr::Const(Name::str("Nat"), vec![])));
1038 }
1039 #[test]
1040 fn test_is_ground_sort() {
1041 assert!(is_ground(&Expr::Sort(Level::zero())));
1042 }
1043 #[test]
1044 fn test_max_bvar_app() {
1045 let e = Expr::App(Node::new(Expr::BVar(5)), Node::new(Expr::BVar(3)));
1046 assert_eq!(max_bvar(&e), Some(5));
1047 }
1048}
1049#[cfg(test)]
1050mod tests_padding_infra {
1051 use super::*;
1052 #[test]
1053 fn test_stat_summary() {
1054 let mut ss = StatSummary::new();
1055 ss.record(10.0);
1056 ss.record(20.0);
1057 ss.record(30.0);
1058 assert_eq!(ss.count(), 3);
1059 assert!((ss.mean().expect("mean should succeed") - 20.0).abs() < 1e-9);
1060 assert_eq!(ss.min().expect("min should succeed") as i64, 10);
1061 assert_eq!(ss.max().expect("max should succeed") as i64, 30);
1062 }
1063 #[test]
1064 fn test_transform_stat() {
1065 let mut ts = TransformStat::new();
1066 ts.record_before(100.0);
1067 ts.record_after(80.0);
1068 let ratio = ts.mean_ratio().expect("ratio should be present");
1069 assert!((ratio - 0.8).abs() < 1e-9);
1070 }
1071 #[test]
1072 fn test_small_map() {
1073 let mut m: SmallMap<u32, &str> = SmallMap::new();
1074 m.insert(3, "three");
1075 m.insert(1, "one");
1076 m.insert(2, "two");
1077 assert_eq!(m.get(&2), Some(&"two"));
1078 assert_eq!(m.len(), 3);
1079 let keys = m.keys();
1080 assert_eq!(*keys[0], 1);
1081 assert_eq!(*keys[2], 3);
1082 }
1083 #[test]
1084 fn test_label_set() {
1085 let mut ls = LabelSet::new();
1086 ls.add("foo");
1087 ls.add("bar");
1088 ls.add("foo");
1089 assert_eq!(ls.count(), 2);
1090 assert!(ls.has("bar"));
1091 assert!(!ls.has("baz"));
1092 }
1093 #[test]
1094 fn test_config_node() {
1095 let mut root = ConfigNode::section("root");
1096 let child = ConfigNode::leaf("key", "value");
1097 root.add_child(child);
1098 assert_eq!(root.num_children(), 1);
1099 }
1100 #[test]
1101 fn test_versioned_record() {
1102 let mut vr = VersionedRecord::new(0u32);
1103 vr.update(1);
1104 vr.update(2);
1105 assert_eq!(*vr.current(), 2);
1106 assert_eq!(vr.version(), 2);
1107 assert!(vr.has_history());
1108 assert_eq!(*vr.at_version(0).expect("value should be present"), 0);
1109 }
1110 #[test]
1111 fn test_simple_dag() {
1112 let mut dag = SimpleDag::new(4);
1113 dag.add_edge(0, 1);
1114 dag.add_edge(1, 2);
1115 dag.add_edge(2, 3);
1116 assert!(dag.can_reach(0, 3));
1117 assert!(!dag.can_reach(3, 0));
1118 let order = dag.topological_sort().expect("order should be present");
1119 assert_eq!(order, vec![0, 1, 2, 3]);
1120 }
1121 #[test]
1122 fn test_focus_stack() {
1123 let mut fs: FocusStack<&str> = FocusStack::new();
1124 fs.focus("a");
1125 fs.focus("b");
1126 assert_eq!(fs.current(), Some(&"b"));
1127 assert_eq!(fs.depth(), 2);
1128 fs.blur();
1129 assert_eq!(fs.current(), Some(&"a"));
1130 }
1131}
1132#[cfg(test)]
1133mod tests_extra_iterators {
1134 use super::*;
1135 #[test]
1136 fn test_window_iterator() {
1137 let data = vec![1u32, 2, 3, 4, 5];
1138 let windows: Vec<_> = WindowIterator::new(&data, 3).collect();
1139 assert_eq!(windows.len(), 3);
1140 assert_eq!(windows[0], &[1, 2, 3]);
1141 assert_eq!(windows[2], &[3, 4, 5]);
1142 }
1143 #[test]
1144 fn test_non_empty_vec() {
1145 let mut nev = NonEmptyVec::singleton(10u32);
1146 nev.push(20);
1147 nev.push(30);
1148 assert_eq!(nev.len(), 3);
1149 assert_eq!(*nev.first(), 10);
1150 assert_eq!(*nev.last(), 30);
1151 }
1152}
1153#[cfg(test)]
1154mod tests_padding2 {
1155 use super::*;
1156 #[test]
1157 fn test_sliding_sum() {
1158 let mut ss = SlidingSum::new(3);
1159 ss.push(1.0);
1160 ss.push(2.0);
1161 ss.push(3.0);
1162 assert!((ss.sum() - 6.0).abs() < 1e-9);
1163 ss.push(4.0);
1164 assert!((ss.sum() - 9.0).abs() < 1e-9);
1165 assert_eq!(ss.count(), 3);
1166 }
1167 #[test]
1168 fn test_path_buf() {
1169 let mut pb = PathBuf::new();
1170 pb.push("src");
1171 pb.push("main");
1172 assert_eq!(pb.as_str(), "src/main");
1173 assert_eq!(pb.depth(), 2);
1174 pb.pop();
1175 assert_eq!(pb.as_str(), "src");
1176 }
1177 #[test]
1178 fn test_string_pool() {
1179 let mut pool = StringPool::new();
1180 let s = pool.take();
1181 assert!(s.is_empty());
1182 pool.give("hello".to_string());
1183 let s2 = pool.take();
1184 assert!(s2.is_empty());
1185 assert_eq!(pool.free_count(), 0);
1186 }
1187 #[test]
1188 fn test_transitive_closure() {
1189 let mut tc = TransitiveClosure::new(4);
1190 tc.add_edge(0, 1);
1191 tc.add_edge(1, 2);
1192 tc.add_edge(2, 3);
1193 assert!(tc.can_reach(0, 3));
1194 assert!(!tc.can_reach(3, 0));
1195 let r = tc.reachable_from(0);
1196 assert_eq!(r.len(), 4);
1197 }
1198 #[test]
1199 fn test_token_bucket() {
1200 let mut tb = TokenBucket::new(100, 0);
1201 assert_eq!(tb.available(), 100);
1202 assert!(tb.try_consume(50));
1203 assert_eq!(tb.available(), 50);
1204 assert!(!tb.try_consume(60));
1205 assert_eq!(tb.capacity(), 100);
1206 }
1207 #[test]
1208 fn test_rewrite_rule_set() {
1209 let mut rrs = RewriteRuleSet::new();
1210 rrs.add(RewriteRule::unconditional(
1211 "beta",
1212 "App(Lam(x, b), v)",
1213 "b[x:=v]",
1214 ));
1215 rrs.add(RewriteRule::conditional("comm", "a + b", "b + a"));
1216 assert_eq!(rrs.len(), 2);
1217 assert_eq!(rrs.unconditional_rules().len(), 1);
1218 assert_eq!(rrs.conditional_rules().len(), 1);
1219 assert!(rrs.get("beta").is_some());
1220 let disp = rrs
1221 .get("beta")
1222 .expect("element at \'beta\' should exist")
1223 .display();
1224 assert!(disp.contains("→"));
1225 }
1226}
1227#[cfg(test)]
1228mod tests_padding3 {
1229 use super::*;
1230 #[test]
1231 fn test_decision_node() {
1232 let tree = DecisionNode::Branch {
1233 key: "x".into(),
1234 val: "1".into(),
1235 yes_branch: Box::new(DecisionNode::Leaf("yes".into())),
1236 no_branch: Box::new(DecisionNode::Leaf("no".into())),
1237 };
1238 let mut ctx = std::collections::HashMap::new();
1239 ctx.insert("x".into(), "1".into());
1240 assert_eq!(tree.evaluate(&ctx), "yes");
1241 ctx.insert("x".into(), "2".into());
1242 assert_eq!(tree.evaluate(&ctx), "no");
1243 assert_eq!(tree.depth(), 1);
1244 }
1245 #[test]
1246 fn test_flat_substitution() {
1247 let mut sub = FlatSubstitution::new();
1248 sub.add("foo", "bar");
1249 sub.add("baz", "qux");
1250 assert_eq!(sub.apply("foo and baz"), "bar and qux");
1251 assert_eq!(sub.len(), 2);
1252 }
1253 #[test]
1254 fn test_stopwatch() {
1255 let mut sw = Stopwatch::start();
1256 sw.split();
1257 sw.split();
1258 assert_eq!(sw.num_splits(), 2);
1259 assert!(sw.elapsed_ms() >= 0.0);
1260 for &s in sw.splits() {
1261 assert!(s >= 0.0);
1262 }
1263 }
1264 #[test]
1265 fn test_either2() {
1266 let e: Either2<i32, &str> = Either2::First(42);
1267 assert!(e.is_first());
1268 let mapped = e.map_first(|x| x * 2);
1269 assert_eq!(mapped.first(), Some(84));
1270 let e2: Either2<i32, &str> = Either2::Second("hello");
1271 assert!(e2.is_second());
1272 assert_eq!(e2.second(), Some("hello"));
1273 }
1274 #[test]
1275 fn test_write_once() {
1276 let wo: WriteOnce<u32> = WriteOnce::new();
1277 assert!(!wo.is_written());
1278 assert!(wo.write(42));
1279 assert!(!wo.write(99));
1280 assert_eq!(wo.read(), Some(42));
1281 }
1282 #[test]
1283 fn test_sparse_vec() {
1284 let mut sv: SparseVec<i32> = SparseVec::new(100);
1285 sv.set(5, 10);
1286 sv.set(50, 20);
1287 assert_eq!(*sv.get(5), 10);
1288 assert_eq!(*sv.get(50), 20);
1289 assert_eq!(*sv.get(0), 0);
1290 assert_eq!(sv.nnz(), 2);
1291 sv.set(5, 0);
1292 assert_eq!(sv.nnz(), 1);
1293 }
1294 #[test]
1295 fn test_stack_calc() {
1296 let mut calc = StackCalc::new();
1297 calc.push(3);
1298 calc.push(4);
1299 assert_eq!(calc.add(), Some(7));
1300 assert_eq!(calc.peek(), Some(7));
1301 calc.push(2);
1302 assert_eq!(calc.mul(), Some(14));
1303 assert_eq!(calc.peek(), Some(14));
1304 }
1305}
1306#[cfg(test)]
1307mod tests_final_padding {
1308 use super::*;
1309 #[test]
1310 fn test_min_heap() {
1311 let mut h = MinHeap::new();
1312 h.push(5u32);
1313 h.push(1u32);
1314 h.push(3u32);
1315 assert_eq!(h.peek(), Some(&1));
1316 assert_eq!(h.pop(), Some(1));
1317 assert_eq!(h.pop(), Some(3));
1318 assert_eq!(h.pop(), Some(5));
1319 assert!(h.is_empty());
1320 }
1321 #[test]
1322 fn test_prefix_counter() {
1323 let mut pc = PrefixCounter::new();
1324 pc.record("hello");
1325 pc.record("help");
1326 pc.record("world");
1327 assert_eq!(pc.count_with_prefix("hel"), 2);
1328 assert_eq!(pc.count_with_prefix("wor"), 1);
1329 assert_eq!(pc.count_with_prefix("xyz"), 0);
1330 }
1331 #[test]
1332 fn test_fixture() {
1333 let mut f = Fixture::new();
1334 f.set("key1", "val1");
1335 f.set("key2", "val2");
1336 assert_eq!(f.get("key1"), Some("val1"));
1337 assert_eq!(f.get("key3"), None);
1338 assert_eq!(f.len(), 2);
1339 }
1340}