Skip to main content

oxilean_kernel/level/
functions.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use crate::Name;
6
7use super::types::{
8    ConfigNode, ConstraintSet, DecisionNode, Either2, Fixture, FlatSubstitution, FocusStack,
9    LabelSet, Level, LevelConstraint, LevelMVarId, MinHeap, NonEmptyVec, PathBuf, PrefixCounter,
10    RewriteRule, RewriteRuleSet, SimpleDag, SlidingSum, SmallMap, SparseVec, StackCalc,
11    StatSummary, Stopwatch, StringPool, TokenBucket, TransformStat, TransitiveClosure,
12    VersionedRecord, WindowIterator, WriteOnce,
13};
14
15/// Decompose a level into `(base, offset)` where level = succ^offset(base).
16///
17/// Strips all Succ wrappers. E.g., `succ(succ(param u))` -> `(param u, 2)`.
18pub fn to_offset(l: &Level) -> (&Level, u32) {
19    match l {
20        Level::Succ(inner) => {
21            let (base, k) = to_offset(inner);
22            (base, k + 1)
23        }
24        _ => (l, 0),
25    }
26}
27/// Reconstruct a level from `(base, offset)` as `succ^offset(base)`.
28pub(super) fn from_offset(base: Level, offset: u32) -> Level {
29    let mut result = base;
30    for _ in 0..offset {
31        result = Level::succ(result);
32    }
33    result
34}
35/// Collect all arguments of a nested max expression into a flat list.
36pub(super) fn push_max_args(l: &Level, args: &mut Vec<Level>) {
37    match l {
38        Level::Max(l1, l2) => {
39            push_max_args(l1, args);
40            push_max_args(l2, args);
41        }
42        _ => args.push(l.clone()),
43    }
44}
45/// Total order on levels for normalization.
46///
47/// This ordering ensures that normalization produces a canonical form.
48pub(super) fn is_norm_lt(l1: &Level, l2: &Level) -> bool {
49    let (b1, k1) = to_offset(l1);
50    let (b2, k2) = to_offset(l2);
51    fn kind_ord(l: &Level) -> u8 {
52        match l {
53            Level::Zero => 0,
54            Level::Param(_) => 1,
55            Level::MVar(_) => 2,
56            Level::Max(_, _) => 3,
57            Level::IMax(_, _) => 4,
58            Level::Succ(_) => 5,
59        }
60    }
61    let k1_ord = kind_ord(b1);
62    let k2_ord = kind_ord(b2);
63    if k1_ord != k2_ord {
64        return k1_ord < k2_ord;
65    }
66    match (b1, b2) {
67        (Level::Param(n1), Level::Param(n2)) => {
68            let s1 = n1.to_string();
69            let s2 = n2.to_string();
70            if s1 != s2 {
71                return s1 < s2;
72            }
73        }
74        (Level::MVar(m1), Level::MVar(m2)) if m1.0 != m2.0 => {
75            return m1.0 < m2.0;
76        }
77        (Level::MVar(_), Level::MVar(_)) => {}
78        (Level::Max(a1, a2), Level::Max(b1_inner, b2_inner))
79        | (Level::IMax(a1, a2), Level::IMax(b1_inner, b2_inner)) => {
80            if a1 != b1_inner {
81                return is_norm_lt(a1, b1_inner);
82            }
83            if a2 != b2_inner {
84                return is_norm_lt(a2, b2_inner);
85            }
86        }
87        _ => {}
88    }
89    k1 < k2
90}
91/// Normalize a universe level to canonical form.
92///
93/// Follows LEAN 4's normalization algorithm:
94/// 1. Flatten nested max expressions
95/// 2. Normalize each argument recursively
96/// 3. Sort arguments
97/// 4. Merge duplicates (keep larger offsets)
98/// 5. Remove subsumed explicit levels
99pub fn normalize(l: &Level) -> Level {
100    let (base, k) = to_offset(l);
101    match base {
102        Level::Zero | Level::Param(_) | Level::MVar(_) => l.clone(),
103        Level::Succ(_) => l.clone(),
104        Level::IMax(l1, l2) => {
105            let l1_norm = normalize(l1);
106            let l2_norm = normalize(l2);
107            if l2_norm.is_zero() {
108                // imax(_, 0) = 0; with offset: Succ^k(0)
109                return from_offset(Level::Zero, k);
110            }
111            if l2_norm.is_not_zero() {
112                // imax(u, v) = max(u, v) when v != 0.
113                // Distribute the outer offset k into each Max argument so the
114                // result is in the same canonical form as the Max branch
115                // (offsets are carried inside each component, not outside).
116                return normalize(&Level::max(
117                    from_offset(l1_norm, k),
118                    from_offset(l2_norm, k),
119                ));
120            }
121            if l1_norm.is_zero() {
122                // imax(0, v) = v; with offset: Succ^k(v).
123                // If v is a Max, from_offset produces Succ^k(Max(a,b)) which
124                // is not the same canonical form as Max(Succ^k(a), Succ^k(b)).
125                // Re-normalize to distribute the offset inside any Max.
126                let with_offset = from_offset(l2_norm, k);
127                return if k == 0 {
128                    with_offset
129                } else {
130                    normalize(&with_offset)
131                };
132            }
133            from_offset(Level::imax(l1_norm, l2_norm), k)
134        }
135        Level::Max(_, _) => {
136            let mut args = Vec::new();
137            push_max_args(base, &mut args);
138            // Normalize each argument.  A component such as Succ(Max(…)) may
139            // normalize to a fresh Max node; those must be re-flattened so the
140            // resulting list has no nested Max nodes (idempotency requirement).
141            let mut normed: Vec<Level> = Vec::new();
142            for a in args {
143                let normalized_a = normalize(&from_offset(a, k));
144                // Re-flatten in case normalization produced a new Max.
145                push_max_args(&normalized_a, &mut normed);
146            }
147            normed.sort_by(|a, b| {
148                if is_norm_lt(a, b) {
149                    std::cmp::Ordering::Less
150                } else if a == b {
151                    std::cmp::Ordering::Equal
152                } else {
153                    std::cmp::Ordering::Greater
154                }
155            });
156            let mut merged: Vec<Level> = Vec::new();
157            for arg in normed {
158                let dominated = if let Some(last) = merged.last() {
159                    let (base_last, k_last) = to_offset(last);
160                    let (base_arg, k_arg) = to_offset(&arg);
161                    if base_last == base_arg {
162                        if k_arg > k_last {
163                            merged.pop();
164                            false
165                        } else {
166                            true
167                        }
168                    } else {
169                        false
170                    }
171                } else {
172                    false
173                };
174                if !dominated {
175                    merged.push(arg);
176                }
177            }
178            if merged.len() > 1 {
179                let has_nonzero = merged.iter().any(|a| a.is_not_zero());
180                if has_nonzero {
181                    merged.retain(|a| !a.is_zero());
182                }
183            }
184            if merged.is_empty() {
185                Level::Zero
186            } else if merged.len() == 1 {
187                merged
188                    .into_iter()
189                    .next()
190                    .expect("merged set must be non-empty")
191            } else {
192                let mut result = merged.pop().expect("merged set must be non-empty");
193                while let Some(arg) = merged.pop() {
194                    result = Level::max(arg, result);
195                }
196                result
197            }
198        }
199    }
200}
201/// Check if two levels are semantically equivalent.
202///
203/// First tries structural equality, then falls back to normalization.
204pub fn is_equivalent(l1: &Level, l2: &Level) -> bool {
205    l1 == l2 || normalize(l1) == normalize(l2)
206}
207/// Check if `l1 >= l2` (level ordering).
208///
209/// Returns true if level `l1` is guaranteed to be >= `l2`
210/// for all possible assignments to parameters and metavariables.
211pub fn is_geq(l1: &Level, l2: &Level) -> bool {
212    is_geq_core(&normalize(l1), &normalize(l2))
213}
214pub(super) fn is_geq_core(l1: &Level, l2: &Level) -> bool {
215    if l1 == l2 {
216        return true;
217    }
218    if l2.is_zero() {
219        return true;
220    }
221    if let Level::Max(a, b) = l1 {
222        if is_geq_core(a, l2) || is_geq_core(b, l2) {
223            return true;
224        }
225    }
226    if let Level::Max(b, c) = l2 {
227        if is_geq_core(l1, b) && is_geq_core(l1, c) {
228            return true;
229        }
230    }
231    if let Level::IMax(b, c) = l2 {
232        if is_geq_core(l1, b) && is_geq_core(l1, c) {
233            return true;
234        }
235    }
236    if let Level::IMax(_, b) = l1 {
237        if is_geq_core(b, l2) {
238            return true;
239        }
240    }
241    let (b1, k1) = to_offset(l1);
242    let (b2, k2) = to_offset(l2);
243    if b1 == b2 {
244        return k1 >= k2;
245    }
246    false
247}
248/// Check if `l1 <= l2` (level ordering).
249pub fn is_leq(l1: &Level, l2: &Level) -> bool {
250    is_geq(l2, l1)
251}
252/// Instantiate level parameters using a substitution.
253///
254/// Replaces `Param(name)` with the corresponding level if `name` is found
255/// in `param_names`.
256pub fn instantiate_level(level: &Level, param_names: &[Name], levels: &[Level]) -> Level {
257    if param_names.is_empty() {
258        return level.clone();
259    }
260    match level {
261        Level::Param(name) => {
262            for (i, pn) in param_names.iter().enumerate() {
263                if pn == name {
264                    if let Some(l) = levels.get(i) {
265                        return l.clone();
266                    }
267                }
268            }
269            level.clone()
270        }
271        Level::Succ(l) => Level::succ(instantiate_level(l, param_names, levels)),
272        Level::Max(l1, l2) => Level::max(
273            instantiate_level(l1, param_names, levels),
274            instantiate_level(l2, param_names, levels),
275        ),
276        Level::IMax(l1, l2) => Level::imax(
277            instantiate_level(l1, param_names, levels),
278            instantiate_level(l2, param_names, levels),
279        ),
280        Level::Zero | Level::MVar(_) => level.clone(),
281    }
282}
283/// Collect all parameter names used in a level.
284pub fn collect_level_params(l: &Level, params: &mut Vec<Name>) {
285    match l {
286        Level::Param(name) => {
287            if !params.contains(name) {
288                params.push(name.clone());
289            }
290        }
291        Level::Succ(l) => collect_level_params(l, params),
292        Level::Max(l1, l2) | Level::IMax(l1, l2) => {
293            collect_level_params(l1, params);
294            collect_level_params(l2, params);
295        }
296        Level::Zero | Level::MVar(_) => {}
297    }
298}
299/// Collect all metavariable IDs used in a level.
300pub fn collect_level_mvars(l: &Level, mvars: &mut Vec<LevelMVarId>) {
301    match l {
302        Level::MVar(id) => {
303            if !mvars.contains(id) {
304                mvars.push(*id);
305            }
306        }
307        Level::Succ(l) => collect_level_mvars(l, mvars),
308        Level::Max(l1, l2) | Level::IMax(l1, l2) => {
309            collect_level_mvars(l1, mvars);
310            collect_level_mvars(l2, mvars);
311        }
312        Level::Zero | Level::Param(_) => {}
313    }
314}
315/// Replace level metavariables using a substitution function.
316pub fn instantiate_level_mvars(
317    level: &Level,
318    subst: &dyn Fn(LevelMVarId) -> Option<Level>,
319) -> Level {
320    match level {
321        Level::MVar(id) => {
322            if let Some(l) = subst(*id) {
323                instantiate_level_mvars(&l, subst)
324            } else {
325                level.clone()
326            }
327        }
328        Level::Succ(l) => Level::succ(instantiate_level_mvars(l, subst)),
329        Level::Max(l1, l2) => Level::max(
330            instantiate_level_mvars(l1, subst),
331            instantiate_level_mvars(l2, subst),
332        ),
333        Level::IMax(l1, l2) => Level::imax(
334            instantiate_level_mvars(l1, subst),
335            instantiate_level_mvars(l2, subst),
336        ),
337        Level::Zero | Level::Param(_) => level.clone(),
338    }
339}
340#[cfg(test)]
341mod tests {
342    use super::*;
343    #[test]
344    fn test_level_construction() {
345        let l0 = Level::zero();
346        let l1 = Level::succ(Level::zero());
347        let l_param = Level::param(Name::str("u"));
348        let l_max = Level::max(l1.clone(), l_param.clone());
349        assert!(l0.is_zero());
350        assert!(l_param.is_param());
351        assert!(!l_max.is_zero());
352    }
353    #[test]
354    fn test_level_display() {
355        let l0 = Level::zero();
356        let l1 = Level::succ(Level::zero());
357        let l_max = Level::max(l0.clone(), l1.clone());
358        let l_imax = Level::imax(l0, l1);
359        assert_eq!(l_max.to_string(), "max(0, 1)");
360        assert_eq!(l_imax.to_string(), "imax(0, 1)");
361    }
362    #[test]
363    fn test_level_mvar() {
364        let mv = Level::mvar(LevelMVarId(42));
365        assert!(mv.is_mvar());
366        assert!(mv.has_mvar());
367        assert!(!mv.has_param());
368        assert_eq!(mv.to_string(), "?u_42");
369    }
370    #[test]
371    fn test_is_not_zero() {
372        assert!(!Level::zero().is_not_zero());
373        assert!(Level::succ(Level::zero()).is_not_zero());
374        assert!(Level::succ(Level::param(Name::str("u"))).is_not_zero());
375        assert!(!Level::param(Name::str("u")).is_not_zero());
376        let m = Level::max(Level::zero(), Level::succ(Level::param(Name::str("u"))));
377        assert!(m.is_not_zero());
378    }
379    #[test]
380    fn test_to_offset() {
381        let l = Level::succ(Level::succ(Level::param(Name::str("u"))));
382        let (base, k) = to_offset(&l);
383        assert_eq!(*base, Level::param(Name::str("u")));
384        assert_eq!(k, 2);
385        let zero = Level::zero();
386        let (base0, k0) = to_offset(&zero);
387        assert_eq!(*base0, Level::zero());
388        assert_eq!(k0, 0);
389    }
390    #[test]
391    fn test_from_nat_to_nat() {
392        for n in 0..5 {
393            let l = Level::from_nat(n);
394            assert_eq!(l.to_nat(), Some(n));
395        }
396        assert_eq!(Level::param(Name::str("u")).to_nat(), None);
397    }
398    #[test]
399    fn test_normalize_zero() {
400        assert_eq!(normalize(&Level::zero()), Level::zero());
401    }
402    #[test]
403    fn test_normalize_succ() {
404        let l = Level::succ(Level::succ(Level::zero()));
405        assert_eq!(normalize(&l), l);
406    }
407    #[test]
408    fn test_normalize_max_same() {
409        let u = Level::param(Name::str("u"));
410        let m = Level::max(u.clone(), u.clone());
411        assert_eq!(normalize(&m), u);
412    }
413    #[test]
414    fn test_normalize_max_zero() {
415        let u = Level::param(Name::str("u"));
416        let m = Level::max(u.clone(), Level::zero());
417        let n = normalize(&m);
418        assert!(is_equivalent(&n, &u) || is_equivalent(&n, &m));
419    }
420    #[test]
421    fn test_normalize_max_ordering() {
422        let u = Level::param(Name::str("u"));
423        let v = Level::param(Name::str("v"));
424        let m1 = Level::max(u.clone(), v.clone());
425        let m2 = Level::max(v, u);
426        assert_eq!(normalize(&m1), normalize(&m2));
427    }
428    #[test]
429    fn test_normalize_imax_zero() {
430        let u = Level::param(Name::str("u"));
431        let im = Level::imax(u, Level::zero());
432        assert_eq!(normalize(&im), Level::zero());
433    }
434    #[test]
435    fn test_normalize_imax_succ() {
436        let u = Level::param(Name::str("u"));
437        let v = Level::param(Name::str("v"));
438        let im = Level::imax(u.clone(), Level::succ(v.clone()));
439        let expected = normalize(&Level::max(u, Level::succ(v)));
440        assert_eq!(normalize(&im), expected);
441    }
442    #[test]
443    fn test_is_equivalent() {
444        let u = Level::param(Name::str("u"));
445        let v = Level::param(Name::str("v"));
446        assert!(is_equivalent(
447            &Level::max(u.clone(), v.clone()),
448            &Level::max(v, u),
449        ));
450        assert!(!is_equivalent(
451            &Level::param(Name::str("u")),
452            &Level::param(Name::str("v")),
453        ));
454        assert!(is_equivalent(
455            &Level::succ(Level::zero()),
456            &Level::succ(Level::zero()),
457        ));
458    }
459    #[test]
460    fn test_is_geq() {
461        let u = Level::param(Name::str("u"));
462        let l0 = Level::zero();
463        let l1 = Level::succ(Level::zero());
464        let l2 = Level::succ(Level::succ(Level::zero()));
465        assert!(is_geq(&u, &l0));
466        assert!(is_geq(&l2, &l1));
467        assert!(!is_geq(&l1, &l2));
468        assert!(is_geq(&Level::succ(u.clone()), &u));
469        let v = Level::param(Name::str("v"));
470        assert!(is_geq(&Level::max(u.clone(), v.clone()), &u));
471        assert!(is_geq(&Level::max(u.clone(), v.clone()), &v));
472    }
473    #[test]
474    fn test_instantiate_level() {
475        let l = Level::max(
476            Level::param(Name::str("u")),
477            Level::succ(Level::param(Name::str("v"))),
478        );
479        let result = instantiate_level(
480            &l,
481            &[Name::str("u"), Name::str("v")],
482            &[Level::zero(), Level::succ(Level::zero())],
483        );
484        let expected = Level::max(Level::zero(), Level::succ(Level::succ(Level::zero())));
485        assert_eq!(result, expected);
486    }
487    #[test]
488    fn test_collect_level_params() {
489        let l = Level::max(
490            Level::param(Name::str("u")),
491            Level::succ(Level::param(Name::str("v"))),
492        );
493        let mut params = Vec::new();
494        collect_level_params(&l, &mut params);
495        assert_eq!(params.len(), 2);
496        assert!(params.contains(&Name::str("u")));
497        assert!(params.contains(&Name::str("v")));
498    }
499    #[test]
500    fn test_instantiate_level_mvars() {
501        let l = Level::max(
502            Level::mvar(LevelMVarId(0)),
503            Level::succ(Level::mvar(LevelMVarId(1))),
504        );
505        let result = instantiate_level_mvars(&l, &|id| {
506            if id.0 == 0 {
507                Some(Level::zero())
508            } else if id.0 == 1 {
509                Some(Level::param(Name::str("u")))
510            } else {
511                None
512            }
513        });
514        let expected = Level::max(Level::zero(), Level::succ(Level::param(Name::str("u"))));
515        assert_eq!(result, expected);
516    }
517    #[test]
518    fn test_depth() {
519        assert_eq!(Level::zero().depth(), 0);
520        assert_eq!(Level::succ(Level::zero()).depth(), 1);
521        assert_eq!(
522            Level::max(Level::param(Name::str("u")), Level::succ(Level::zero())).depth(),
523            2
524        );
525    }
526}
527/// Compute the minimum of two levels: min(l1, l2).
528///
529/// Defined as `imax(l1, succ(l2))` is NOT min; instead use:
530/// min(l1, l2) = l1 if l1 <= l2, else l2. This is approximate
531/// (returns a conservative lower bound for polymorphic levels).
532#[allow(dead_code)]
533pub fn level_min(l1: &Level, l2: &Level) -> Level {
534    if l1.is_zero() || l2.is_zero() {
535        return Level::Zero;
536    }
537    if is_leq(l1, l2) {
538        return l1.clone();
539    }
540    if is_leq(l2, l1) {
541        return l2.clone();
542    }
543    Level::Zero
544}
545/// Create `max(max(l1, l2), l3)` and normalize.
546#[allow(dead_code)]
547pub fn level_max3(l1: Level, l2: Level, l3: Level) -> Level {
548    normalize(&Level::max(Level::max(l1, l2), l3))
549}
550/// Bump a level by `n` successor applications.
551///
552/// `level_add(l, n)` = `succ^n(l)`.
553#[allow(dead_code)]
554pub fn level_add(l: Level, n: u32) -> Level {
555    let mut result = l;
556    for _ in 0..n {
557        result = Level::succ(result);
558    }
559    result
560}
561/// The universe level for `Type n` (= succ^(n+1)(0)).
562#[allow(dead_code)]
563pub fn type_level(n: u32) -> Level {
564    Level::from_nat(n + 1)
565}
566/// Check if `l` is definitely a successor (non-zero) level.
567/// Returns true for `succ(anything)`.
568#[allow(dead_code)]
569pub fn is_definitely_succ(l: &Level) -> bool {
570    matches!(l, Level::Succ(_))
571}
572/// Collect all levels appearing in a `Vec<Level>`, deduplicating by structural equality.
573#[allow(dead_code)]
574pub fn dedup_levels(levels: Vec<Level>) -> Vec<Level> {
575    let mut seen: Vec<Level> = Vec::new();
576    for l in levels {
577        if !seen.contains(&l) {
578            seen.push(l);
579        }
580    }
581    seen
582}
583#[cfg(test)]
584mod extra_level_tests {
585    use super::*;
586    #[test]
587    fn test_level_min_zeros() {
588        assert_eq!(
589            level_min(&Level::zero(), &Level::succ(Level::zero())),
590            Level::zero()
591        );
592    }
593    #[test]
594    fn test_level_min_equal() {
595        let l1 = Level::succ(Level::zero());
596        let l2 = Level::succ(Level::zero());
597        assert_eq!(level_min(&l1, &l2), l1);
598    }
599    #[test]
600    fn test_level_max3() {
601        let l0 = Level::zero();
602        let l1 = Level::succ(Level::zero());
603        let l2 = Level::succ(Level::succ(Level::zero()));
604        let result = level_max3(l0, l1, l2.clone());
605        assert!(is_equivalent(&result, &l2));
606    }
607    #[test]
608    fn test_level_add_zero_times() {
609        let l = Level::param(Name::str("u"));
610        assert_eq!(level_add(l.clone(), 0), l);
611    }
612    #[test]
613    fn test_level_add_two_times() {
614        let l = Level::zero();
615        let result = level_add(l, 2);
616        assert_eq!(result.to_nat(), Some(2));
617    }
618    #[test]
619    fn test_type_level_zero() {
620        assert_eq!(type_level(0), Level::succ(Level::zero()));
621    }
622    #[test]
623    fn test_type_level_two() {
624        assert_eq!(type_level(2).to_nat(), Some(3));
625    }
626    #[test]
627    fn test_is_definitely_succ_true() {
628        assert!(is_definitely_succ(&Level::succ(Level::zero())));
629    }
630    #[test]
631    fn test_is_definitely_succ_false() {
632        assert!(!is_definitely_succ(&Level::zero()));
633        assert!(!is_definitely_succ(&Level::param(Name::str("u"))));
634    }
635    #[test]
636    fn test_dedup_levels() {
637        let l0 = Level::zero();
638        let l1 = Level::succ(Level::zero());
639        let levels = vec![l0.clone(), l0.clone(), l1.clone(), l1.clone()];
640        let deduped = dedup_levels(levels);
641        assert_eq!(deduped.len(), 2);
642    }
643    #[test]
644    fn test_collect_level_mvars_multiple() {
645        let l = Level::max(Level::mvar(LevelMVarId(0)), Level::mvar(LevelMVarId(1)));
646        let mut mvars = Vec::new();
647        collect_level_mvars(&l, &mut mvars);
648        assert_eq!(mvars.len(), 2);
649    }
650    #[test]
651    fn test_level_is_leq() {
652        let l0 = Level::zero();
653        let l1 = Level::succ(Level::zero());
654        assert!(is_leq(&l0, &l1));
655        assert!(!is_leq(&l1, &l0));
656        assert!(is_leq(&l0, &l0));
657    }
658}
659/// Flatten a level to a list of `(base, offset)` pairs representing max arguments.
660///
661/// E.g., `max(max(u, v+1), w+2)` → `[(u,0), (v,1), (w,2)]`.
662#[allow(dead_code)]
663pub fn flatten_max(l: &Level) -> Vec<(Level, u32)> {
664    let norm = normalize(l);
665    let mut result = Vec::new();
666    push_flat(&norm, &mut result);
667    result
668}
669pub(super) fn push_flat(l: &Level, acc: &mut Vec<(Level, u32)>) {
670    match l {
671        Level::Max(l1, l2) => {
672            push_flat(l1, acc);
673            push_flat(l2, acc);
674        }
675        _ => {
676            let (base, k) = to_offset(l);
677            acc.push((base.clone(), k));
678        }
679    }
680}
681/// Check if the level is a concrete numeral (succ^n(zero)).
682#[allow(dead_code)]
683pub fn is_numeral(l: &Level) -> bool {
684    l.to_nat().is_some()
685}
686/// Check if a level expression is ground (no parameters, no mvars).
687#[allow(dead_code)]
688pub fn is_ground(l: &Level) -> bool {
689    !l.has_param() && !l.has_mvar()
690}
691/// Evaluate a ground (no params, no mvars) level to a concrete `u32`.
692///
693/// Returns `None` if the level has parameters or metavariables.
694#[allow(dead_code)]
695pub fn eval_ground_level(l: &Level) -> Option<u32> {
696    if !is_ground(l) {
697        return None;
698    }
699    let norm = normalize(l);
700    norm.to_nat()
701}
702/// Create a level that is the `max` of a slice of levels.
703///
704/// Returns `Level::Zero` for an empty slice.
705#[allow(dead_code)]
706pub fn max_of_slice(levels: &[Level]) -> Level {
707    let mut iter = levels.iter();
708    match iter.next() {
709        None => Level::Zero,
710        Some(first) => iter.fold(first.clone(), |acc, l| Level::max(acc, l.clone())),
711    }
712}
713/// Create a level that is the `imax` of a slice of levels, left-folded.
714///
715/// Useful for computing the sort level of Pi types.
716#[allow(dead_code)]
717pub fn imax_fold(levels: &[Level]) -> Level {
718    let mut iter = levels.iter();
719    match iter.next() {
720        None => Level::Zero,
721        Some(first) => iter.fold(first.clone(), |acc, l| Level::imax(acc, l.clone())),
722    }
723}
724/// Level of `Prop` (= 0).
725#[allow(dead_code)]
726pub const PROP_LEVEL: Level = Level::Zero;
727/// Level of `Type 0` (= 1).
728#[allow(dead_code)]
729pub fn type0_level() -> Level {
730    Level::succ(Level::Zero)
731}
732/// Level of `Type 1` (= 2).
733#[allow(dead_code)]
734pub fn type1_level() -> Level {
735    Level::succ(Level::succ(Level::Zero))
736}
737#[cfg(test)]
738mod extra2_level_tests {
739    use super::*;
740    #[test]
741    fn test_level_constraint_leq_satisfied() {
742        let l0 = Level::zero();
743        let l1 = Level::succ(Level::zero());
744        let c = LevelConstraint::Leq(l0, l1);
745        assert!(c.is_satisfied());
746    }
747    #[test]
748    fn test_level_constraint_leq_violated() {
749        let l1 = Level::succ(Level::zero());
750        let l0 = Level::zero();
751        let c = LevelConstraint::Leq(l1, l0);
752        assert!(!c.is_satisfied());
753    }
754    #[test]
755    fn test_level_constraint_eq_satisfied() {
756        let l = Level::succ(Level::zero());
757        let c = LevelConstraint::Eq(l.clone(), l);
758        assert!(c.is_satisfied());
759    }
760    #[test]
761    fn test_constraint_set_all_satisfied() {
762        let mut cs = ConstraintSet::new();
763        cs.add_leq(Level::zero(), Level::succ(Level::zero()));
764        cs.add_eq(Level::zero(), Level::zero());
765        assert!(cs.all_satisfied());
766    }
767    #[test]
768    fn test_constraint_set_unsatisfied() {
769        let mut cs = ConstraintSet::new();
770        cs.add_leq(Level::succ(Level::zero()), Level::zero());
771        assert!(!cs.all_satisfied());
772        assert_eq!(cs.unsatisfied().len(), 1);
773    }
774    #[test]
775    fn test_flatten_max_single() {
776        let l = Level::param(Name::str("u"));
777        let flat = flatten_max(&l);
778        assert_eq!(flat.len(), 1);
779    }
780    #[test]
781    fn test_flatten_max_binary() {
782        let u = Level::param(Name::str("u"));
783        let v = Level::param(Name::str("v"));
784        let m = Level::max(u, v);
785        let flat = flatten_max(&m);
786        assert_eq!(flat.len(), 2);
787    }
788    #[test]
789    fn test_is_numeral_true() {
790        assert!(is_numeral(&Level::zero()));
791        assert!(is_numeral(&Level::succ(Level::zero())));
792        assert!(is_numeral(&Level::from_nat(5)));
793    }
794    #[test]
795    fn test_is_numeral_false() {
796        assert!(!is_numeral(&Level::param(Name::str("u"))));
797    }
798    #[test]
799    fn test_is_ground_zero() {
800        assert!(is_ground(&Level::zero()));
801    }
802    #[test]
803    fn test_is_ground_param() {
804        assert!(!is_ground(&Level::param(Name::str("u"))));
805    }
806    #[test]
807    fn test_eval_ground_level_numeral() {
808        let l = Level::from_nat(3);
809        assert_eq!(eval_ground_level(&l), Some(3));
810    }
811    #[test]
812    fn test_eval_ground_level_param() {
813        let l = Level::param(Name::str("u"));
814        assert_eq!(eval_ground_level(&l), None);
815    }
816    #[test]
817    fn test_max_of_slice_empty() {
818        let result = max_of_slice(&[]);
819        assert_eq!(result, Level::zero());
820    }
821    #[test]
822    fn test_max_of_slice_single() {
823        let l = Level::succ(Level::zero());
824        let result = max_of_slice(std::slice::from_ref(&l));
825        assert_eq!(result, l);
826    }
827    #[test]
828    fn test_max_of_slice_multiple() {
829        let l0 = Level::zero();
830        let l1 = Level::succ(Level::zero());
831        let l2 = Level::succ(Level::succ(Level::zero()));
832        let result = max_of_slice(&[l0, l1, l2.clone()]);
833        assert!(is_equivalent(&normalize(&result), &l2));
834    }
835    #[test]
836    fn test_imax_fold_empty() {
837        assert_eq!(imax_fold(&[]), Level::zero());
838    }
839    #[test]
840    fn test_type0_level() {
841        assert_eq!(type0_level().to_nat(), Some(1));
842    }
843    #[test]
844    fn test_type1_level() {
845        assert_eq!(type1_level().to_nat(), Some(2));
846    }
847    #[test]
848    fn test_constraint_set_len() {
849        let mut cs = ConstraintSet::new();
850        cs.add_leq(Level::zero(), Level::succ(Level::zero()));
851        assert_eq!(cs.len(), 1);
852        assert!(!cs.is_empty());
853    }
854}
855#[cfg(test)]
856mod tests_padding_infra {
857    use super::*;
858    #[test]
859    fn test_stat_summary() {
860        let mut ss = StatSummary::new();
861        ss.record(10.0);
862        ss.record(20.0);
863        ss.record(30.0);
864        assert_eq!(ss.count(), 3);
865        assert!((ss.mean().expect("mean should succeed") - 20.0).abs() < 1e-9);
866        assert_eq!(ss.min().expect("min should succeed") as i64, 10);
867        assert_eq!(ss.max().expect("max should succeed") as i64, 30);
868    }
869    #[test]
870    fn test_transform_stat() {
871        let mut ts = TransformStat::new();
872        ts.record_before(100.0);
873        ts.record_after(80.0);
874        let ratio = ts.mean_ratio().expect("ratio should be present");
875        assert!((ratio - 0.8).abs() < 1e-9);
876    }
877    #[test]
878    fn test_small_map() {
879        let mut m: SmallMap<u32, &str> = SmallMap::new();
880        m.insert(3, "three");
881        m.insert(1, "one");
882        m.insert(2, "two");
883        assert_eq!(m.get(&2), Some(&"two"));
884        assert_eq!(m.len(), 3);
885        let keys = m.keys();
886        assert_eq!(*keys[0], 1);
887        assert_eq!(*keys[2], 3);
888    }
889    #[test]
890    fn test_label_set() {
891        let mut ls = LabelSet::new();
892        ls.add("foo");
893        ls.add("bar");
894        ls.add("foo");
895        assert_eq!(ls.count(), 2);
896        assert!(ls.has("bar"));
897        assert!(!ls.has("baz"));
898    }
899    #[test]
900    fn test_config_node() {
901        let mut root = ConfigNode::section("root");
902        let child = ConfigNode::leaf("key", "value");
903        root.add_child(child);
904        assert_eq!(root.num_children(), 1);
905    }
906    #[test]
907    fn test_versioned_record() {
908        let mut vr = VersionedRecord::new(0u32);
909        vr.update(1);
910        vr.update(2);
911        assert_eq!(*vr.current(), 2);
912        assert_eq!(vr.version(), 2);
913        assert!(vr.has_history());
914        assert_eq!(*vr.at_version(0).expect("value should be present"), 0);
915    }
916    #[test]
917    fn test_simple_dag() {
918        let mut dag = SimpleDag::new(4);
919        dag.add_edge(0, 1);
920        dag.add_edge(1, 2);
921        dag.add_edge(2, 3);
922        assert!(dag.can_reach(0, 3));
923        assert!(!dag.can_reach(3, 0));
924        let order = dag.topological_sort().expect("order should be present");
925        assert_eq!(order, vec![0, 1, 2, 3]);
926    }
927    #[test]
928    fn test_focus_stack() {
929        let mut fs: FocusStack<&str> = FocusStack::new();
930        fs.focus("a");
931        fs.focus("b");
932        assert_eq!(fs.current(), Some(&"b"));
933        assert_eq!(fs.depth(), 2);
934        fs.blur();
935        assert_eq!(fs.current(), Some(&"a"));
936    }
937}
938#[cfg(test)]
939mod tests_extra_iterators {
940    use super::*;
941    #[test]
942    fn test_window_iterator() {
943        let data = vec![1u32, 2, 3, 4, 5];
944        let windows: Vec<_> = WindowIterator::new(&data, 3).collect();
945        assert_eq!(windows.len(), 3);
946        assert_eq!(windows[0], &[1, 2, 3]);
947        assert_eq!(windows[2], &[3, 4, 5]);
948    }
949    #[test]
950    fn test_non_empty_vec() {
951        let mut nev = NonEmptyVec::singleton(10u32);
952        nev.push(20);
953        nev.push(30);
954        assert_eq!(nev.len(), 3);
955        assert_eq!(*nev.first(), 10);
956        assert_eq!(*nev.last(), 30);
957    }
958}
959#[cfg(test)]
960mod tests_padding2 {
961    use super::*;
962    #[test]
963    fn test_sliding_sum() {
964        let mut ss = SlidingSum::new(3);
965        ss.push(1.0);
966        ss.push(2.0);
967        ss.push(3.0);
968        assert!((ss.sum() - 6.0).abs() < 1e-9);
969        ss.push(4.0);
970        assert!((ss.sum() - 9.0).abs() < 1e-9);
971        assert_eq!(ss.count(), 3);
972    }
973    #[test]
974    fn test_path_buf() {
975        let mut pb = PathBuf::new();
976        pb.push("src");
977        pb.push("main");
978        assert_eq!(pb.as_str(), "src/main");
979        assert_eq!(pb.depth(), 2);
980        pb.pop();
981        assert_eq!(pb.as_str(), "src");
982    }
983    #[test]
984    fn test_string_pool() {
985        let mut pool = StringPool::new();
986        let s = pool.take();
987        assert!(s.is_empty());
988        pool.give("hello".to_string());
989        let s2 = pool.take();
990        assert!(s2.is_empty());
991        assert_eq!(pool.free_count(), 0);
992    }
993    #[test]
994    fn test_transitive_closure() {
995        let mut tc = TransitiveClosure::new(4);
996        tc.add_edge(0, 1);
997        tc.add_edge(1, 2);
998        tc.add_edge(2, 3);
999        assert!(tc.can_reach(0, 3));
1000        assert!(!tc.can_reach(3, 0));
1001        let r = tc.reachable_from(0);
1002        assert_eq!(r.len(), 4);
1003    }
1004    #[test]
1005    fn test_token_bucket() {
1006        let mut tb = TokenBucket::new(100, 10);
1007        assert_eq!(tb.available(), 100);
1008        assert!(tb.try_consume(50));
1009        assert_eq!(tb.available(), 50);
1010        assert!(!tb.try_consume(60));
1011        assert_eq!(tb.capacity(), 100);
1012    }
1013    #[test]
1014    fn test_rewrite_rule_set() {
1015        let mut rrs = RewriteRuleSet::new();
1016        rrs.add(RewriteRule::unconditional(
1017            "beta",
1018            "App(Lam(x, b), v)",
1019            "b[x:=v]",
1020        ));
1021        rrs.add(RewriteRule::conditional("comm", "a + b", "b + a"));
1022        assert_eq!(rrs.len(), 2);
1023        assert_eq!(rrs.unconditional_rules().len(), 1);
1024        assert_eq!(rrs.conditional_rules().len(), 1);
1025        assert!(rrs.get("beta").is_some());
1026        let disp = rrs
1027            .get("beta")
1028            .expect("element at \'beta\' should exist")
1029            .display();
1030        assert!(disp.contains("→"));
1031    }
1032}
1033#[cfg(test)]
1034mod tests_padding3 {
1035    use super::*;
1036    #[test]
1037    fn test_decision_node() {
1038        let tree = DecisionNode::Branch {
1039            key: "x".into(),
1040            val: "1".into(),
1041            yes_branch: Box::new(DecisionNode::Leaf("yes".into())),
1042            no_branch: Box::new(DecisionNode::Leaf("no".into())),
1043        };
1044        let mut ctx = std::collections::HashMap::new();
1045        ctx.insert("x".into(), "1".into());
1046        assert_eq!(tree.evaluate(&ctx), "yes");
1047        ctx.insert("x".into(), "2".into());
1048        assert_eq!(tree.evaluate(&ctx), "no");
1049        assert_eq!(tree.depth(), 1);
1050    }
1051    #[test]
1052    fn test_flat_substitution() {
1053        let mut sub = FlatSubstitution::new();
1054        sub.add("foo", "bar");
1055        sub.add("baz", "qux");
1056        assert_eq!(sub.apply("foo and baz"), "bar and qux");
1057        assert_eq!(sub.len(), 2);
1058    }
1059    #[test]
1060    fn test_stopwatch() {
1061        let mut sw = Stopwatch::start();
1062        sw.split();
1063        sw.split();
1064        assert_eq!(sw.num_splits(), 2);
1065        assert!(sw.elapsed_ms() >= 0.0);
1066        for &s in sw.splits() {
1067            assert!(s >= 0.0);
1068        }
1069    }
1070    #[test]
1071    fn test_either2() {
1072        let e: Either2<i32, &str> = Either2::First(42);
1073        assert!(e.is_first());
1074        let mapped = e.map_first(|x| x * 2);
1075        assert_eq!(mapped.first(), Some(84));
1076        let e2: Either2<i32, &str> = Either2::Second("hello");
1077        assert!(e2.is_second());
1078        assert_eq!(e2.second(), Some("hello"));
1079    }
1080    #[test]
1081    fn test_write_once() {
1082        let wo: WriteOnce<u32> = WriteOnce::new();
1083        assert!(!wo.is_written());
1084        assert!(wo.write(42));
1085        assert!(!wo.write(99));
1086        assert_eq!(wo.read(), Some(42));
1087    }
1088    #[test]
1089    fn test_sparse_vec() {
1090        let mut sv: SparseVec<i32> = SparseVec::new(100);
1091        sv.set(5, 10);
1092        sv.set(50, 20);
1093        assert_eq!(*sv.get(5), 10);
1094        assert_eq!(*sv.get(50), 20);
1095        assert_eq!(*sv.get(0), 0);
1096        assert_eq!(sv.nnz(), 2);
1097        sv.set(5, 0);
1098        assert_eq!(sv.nnz(), 1);
1099    }
1100    #[test]
1101    fn test_stack_calc() {
1102        let mut calc = StackCalc::new();
1103        calc.push(3);
1104        calc.push(4);
1105        calc.add();
1106        assert_eq!(calc.peek(), Some(7));
1107        calc.push(2);
1108        calc.mul();
1109        assert_eq!(calc.peek(), Some(14));
1110    }
1111}
1112#[cfg(test)]
1113mod tests_final_padding {
1114    use super::*;
1115    #[test]
1116    fn test_min_heap() {
1117        let mut h = MinHeap::new();
1118        h.push(5u32);
1119        h.push(1u32);
1120        h.push(3u32);
1121        assert_eq!(h.peek(), Some(&1));
1122        assert_eq!(h.pop(), Some(1));
1123        assert_eq!(h.pop(), Some(3));
1124        assert_eq!(h.pop(), Some(5));
1125        assert!(h.is_empty());
1126    }
1127    #[test]
1128    fn test_prefix_counter() {
1129        let mut pc = PrefixCounter::new();
1130        pc.record("hello");
1131        pc.record("help");
1132        pc.record("world");
1133        assert_eq!(pc.count_with_prefix("hel"), 2);
1134        assert_eq!(pc.count_with_prefix("wor"), 1);
1135        assert_eq!(pc.count_with_prefix("xyz"), 0);
1136    }
1137    #[test]
1138    fn test_fixture() {
1139        let mut f = Fixture::new();
1140        f.set("key1", "val1");
1141        f.set("key2", "val2");
1142        assert_eq!(f.get("key1"), Some("val1"));
1143        assert_eq!(f.get("key3"), None);
1144        assert_eq!(f.len(), 2);
1145    }
1146}