Skip to main content

oxilean_std/vec/
functions.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use oxilean_kernel::Node;
6use oxilean_kernel::{
7    BinderInfo, Declaration, Environment, Expr, InductiveEnv, InductiveType, IntroRule, Level, Name,
8};
9
10use super::types::{CircularBuffer, DList, FenwickTree, FixedVec, PrefixScan, SparseVec};
11
12/// Build Vec type in the environment.
13///
14/// Vec : (α : Type) → Nat → Type
15pub fn build_vec_env(env: &mut Environment, ind_env: &mut InductiveEnv) -> Result<(), String> {
16    let type1 = Expr::Sort(Level::succ(Level::zero()));
17    let vec_ty = Expr::Pi(
18        BinderInfo::Default,
19        Name::str("α"),
20        Node::new(type1.clone()),
21        Node::new(Expr::Pi(
22            BinderInfo::Default,
23            Name::str("n"),
24            Node::new(Expr::Const(Name::str("Nat"), vec![])),
25            Node::new(type1.clone()),
26        )),
27    );
28    let nil_ty = Expr::Pi(
29        BinderInfo::Implicit,
30        Name::str("α"),
31        Node::new(type1.clone()),
32        Node::new(Expr::App(
33            Node::new(Expr::App(
34                Node::new(Expr::Const(Name::str("Vec"), vec![])),
35                Node::new(Expr::BVar(0)),
36            )),
37            Node::new(Expr::Const(Name::str("Nat.zero"), vec![])),
38        )),
39    );
40    let cons_ty = Expr::Pi(
41        BinderInfo::Implicit,
42        Name::str("α"),
43        Node::new(type1.clone()),
44        Node::new(Expr::Pi(
45            BinderInfo::Implicit,
46            Name::str("n"),
47            Node::new(Expr::Const(Name::str("Nat"), vec![])),
48            Node::new(Expr::Pi(
49                BinderInfo::Default,
50                Name::str("head"),
51                Node::new(Expr::BVar(1)),
52                Node::new(Expr::Pi(
53                    BinderInfo::Default,
54                    Name::str("tail"),
55                    Node::new(Expr::App(
56                        Node::new(Expr::App(
57                            Node::new(Expr::Const(Name::str("Vec"), vec![])),
58                            Node::new(Expr::BVar(2)),
59                        )),
60                        Node::new(Expr::BVar(1)),
61                    )),
62                    Node::new(Expr::App(
63                        Node::new(Expr::App(
64                            Node::new(Expr::Const(Name::str("Vec"), vec![])),
65                            Node::new(Expr::BVar(3)),
66                        )),
67                        Node::new(Expr::App(
68                            Node::new(Expr::Const(Name::str("Nat.succ"), vec![])),
69                            Node::new(Expr::BVar(2)),
70                        )),
71                    )),
72                )),
73            )),
74        )),
75    );
76    let vec_ind = InductiveType::new(
77        Name::str("Vec"),
78        vec![],
79        1,
80        1,
81        vec_ty.clone(),
82        vec![
83            IntroRule {
84                name: Name::str("Vec.nil"),
85                ty: nil_ty.clone(),
86            },
87            IntroRule {
88                name: Name::str("Vec.cons"),
89                ty: cons_ty.clone(),
90            },
91        ],
92    );
93    ind_env.add(vec_ind).map_err(|e| format!("{}", e))?;
94    env.add(Declaration::Axiom {
95        name: Name::str("Vec"),
96        univ_params: vec![],
97        ty: vec_ty,
98    })
99    .map_err(|e| e.to_string())?;
100    env.add(Declaration::Axiom {
101        name: Name::str("Vec.nil"),
102        univ_params: vec![],
103        ty: nil_ty,
104    })
105    .map_err(|e| e.to_string())?;
106    env.add(Declaration::Axiom {
107        name: Name::str("Vec.cons"),
108        univ_params: vec![],
109        ty: cons_ty,
110    })
111    .map_err(|e| e.to_string())?;
112    Ok(())
113}
114#[cfg(test)]
115mod tests {
116    use super::*;
117    #[test]
118    fn test_build_vec_env() {
119        let mut env = Environment::new();
120        let mut ind_env = InductiveEnv::new();
121        let type1 = Expr::Sort(Level::succ(Level::zero()));
122        env.add(Declaration::Axiom {
123            name: Name::str("Nat"),
124            univ_params: vec![],
125            ty: type1.clone(),
126        })
127        .expect("operation should succeed");
128        env.add(Declaration::Axiom {
129            name: Name::str("Nat.zero"),
130            univ_params: vec![],
131            ty: Expr::Const(Name::str("Nat"), vec![]),
132        })
133        .expect("operation should succeed");
134        env.add(Declaration::Axiom {
135            name: Name::str("Nat.succ"),
136            univ_params: vec![],
137            ty: Expr::Pi(
138                BinderInfo::Default,
139                Name::str("n"),
140                Node::new(Expr::Const(Name::str("Nat"), vec![])),
141                Node::new(Expr::Const(Name::str("Nat"), vec![])),
142            ),
143        })
144        .expect("operation should succeed");
145        assert!(build_vec_env(&mut env, &mut ind_env).is_ok());
146        assert!(env.get(&Name::str("Vec")).is_some());
147        assert!(env.get(&Name::str("Vec.nil")).is_some());
148        assert!(env.get(&Name::str("Vec.cons")).is_some());
149    }
150}
151/// Concatenate two vectors into a new one.
152#[allow(dead_code)]
153pub fn vec_append<T: Clone>(a: &[T], b: &[T]) -> Vec<T> {
154    let mut result = a.to_vec();
155    result.extend_from_slice(b);
156    result
157}
158/// Return `true` if `v` contains `elem`.
159#[allow(dead_code)]
160pub fn vec_contains<T: PartialEq>(v: &[T], elem: &T) -> bool {
161    v.contains(elem)
162}
163/// Return the index of the first occurrence of `elem`, or `None`.
164#[allow(dead_code)]
165pub fn vec_index_of<T: PartialEq>(v: &[T], elem: &T) -> Option<usize> {
166    v.iter().position(|x| x == elem)
167}
168/// Remove all occurrences of `elem` from `v`.
169#[allow(dead_code)]
170pub fn vec_remove_all<T: PartialEq>(v: Vec<T>, elem: &T) -> Vec<T> {
171    v.into_iter().filter(|x| x != elem).collect()
172}
173/// Deduplicate a vector (keeping first occurrence), preserving order.
174#[allow(dead_code)]
175pub fn vec_dedup_stable<T: PartialEq + Clone>(v: &[T]) -> Vec<T> {
176    let mut seen = Vec::new();
177    for item in v {
178        if !seen.contains(item) {
179            seen.push(item.clone());
180        }
181    }
182    seen
183}
184/// Flatten a `Vec<Vec<T>>` into a `Vec<T>`.
185#[allow(dead_code)]
186pub fn vec_flatten<T>(v: Vec<Vec<T>>) -> Vec<T> {
187    v.into_iter().flatten().collect()
188}
189/// Return the last element of a slice, or `None`.
190#[allow(dead_code)]
191pub fn vec_last<T>(v: &[T]) -> Option<&T> {
192    v.last()
193}
194/// Return the first element of a slice, or `None`.
195#[allow(dead_code)]
196pub fn vec_head<T>(v: &[T]) -> Option<&T> {
197    v.first()
198}
199/// Return all but the last element (i.e. `init` of the vector).
200#[allow(dead_code)]
201pub fn vec_init<T: Clone>(v: &[T]) -> Vec<T> {
202    if v.is_empty() {
203        vec![]
204    } else {
205        v[..v.len() - 1].to_vec()
206    }
207}
208/// Return all but the first element (i.e. `tail` of the vector).
209#[allow(dead_code)]
210pub fn vec_tail<T: Clone>(v: &[T]) -> Vec<T> {
211    if v.is_empty() {
212        vec![]
213    } else {
214        v[1..].to_vec()
215    }
216}
217/// Split a vector at `index`, returning `(left, right)`.
218#[allow(dead_code)]
219pub fn vec_split_at<T: Clone>(v: &[T], index: usize) -> (Vec<T>, Vec<T>) {
220    let idx = index.min(v.len());
221    (v[..idx].to_vec(), v[idx..].to_vec())
222}
223/// Zip two vectors into a vector of pairs (up to the shorter length).
224#[allow(dead_code)]
225pub fn vec_zip<A: Clone, B: Clone>(a: &[A], b: &[B]) -> Vec<(A, B)> {
226    a.iter()
227        .zip(b.iter())
228        .map(|(x, y)| (x.clone(), y.clone()))
229        .collect()
230}
231/// Unzip a vector of pairs into two vectors.
232#[allow(dead_code)]
233pub fn vec_unzip<A, B>(v: Vec<(A, B)>) -> (Vec<A>, Vec<B>) {
234    v.into_iter().unzip()
235}
236/// Return the vector with element at `index` removed.
237#[allow(dead_code)]
238pub fn vec_remove_at<T: Clone>(v: &[T], index: usize) -> Vec<T> {
239    let mut result = v.to_vec();
240    if index < result.len() {
241        result.remove(index);
242    }
243    result
244}
245/// Insert `elem` at `index`, shifting subsequent elements right.
246#[allow(dead_code)]
247pub fn vec_insert_at<T: Clone>(v: &[T], index: usize, elem: T) -> Vec<T> {
248    let mut result = v.to_vec();
249    let idx = index.min(result.len());
250    result.insert(idx, elem);
251    result
252}
253/// Replace the element at `index` with `new_val`.
254#[allow(dead_code)]
255pub fn vec_set<T: Clone>(v: &[T], index: usize, new_val: T) -> Vec<T> {
256    let mut result = v.to_vec();
257    if index < result.len() {
258        result[index] = new_val;
259    }
260    result
261}
262/// Reverse a vector.
263#[allow(dead_code)]
264pub fn vec_reverse<T: Clone>(v: &[T]) -> Vec<T> {
265    let mut result = v.to_vec();
266    result.reverse();
267    result
268}
269/// Rotate a vector left by `n` positions.
270#[allow(dead_code)]
271pub fn vec_rotate_left<T: Clone>(v: &[T], n: usize) -> Vec<T> {
272    if v.is_empty() {
273        return vec![];
274    }
275    let n = n % v.len();
276    let mut result = v[n..].to_vec();
277    result.extend_from_slice(&v[..n]);
278    result
279}
280/// Rotate a vector right by `n` positions.
281#[allow(dead_code)]
282pub fn vec_rotate_right<T: Clone>(v: &[T], n: usize) -> Vec<T> {
283    if v.is_empty() {
284        return vec![];
285    }
286    let n = n % v.len();
287    vec_rotate_left(v, v.len() - n)
288}
289/// Return every `n`-th element starting from `start`.
290#[allow(dead_code)]
291pub fn vec_step_by<T: Clone>(v: &[T], start: usize, step: usize) -> Vec<T> {
292    if step == 0 {
293        return vec![];
294    }
295    v.iter()
296        .enumerate()
297        .filter(|(i, _)| i >= &start && (i - start) % step == 0)
298        .map(|(_, x)| x.clone())
299        .collect()
300}
301/// Count elements matching a predicate.
302#[allow(dead_code)]
303pub fn vec_count_where<T, F: Fn(&T) -> bool>(v: &[T], pred: F) -> usize {
304    v.iter().filter(|x| pred(x)).count()
305}
306/// Partition into matching and non-matching elements.
307#[allow(dead_code)]
308pub fn vec_partition<T, F: Fn(&T) -> bool>(v: Vec<T>, pred: F) -> (Vec<T>, Vec<T>) {
309    v.into_iter().partition(|x| pred(x))
310}
311/// Map a fallible function over a vector, returning early on error.
312#[allow(dead_code)]
313pub fn vec_try_map<T, U, E, F: Fn(T) -> Result<U, E>>(v: Vec<T>, f: F) -> Result<Vec<U>, E> {
314    v.into_iter().map(f).collect()
315}
316/// Interleave `sep` between elements of `v`.
317#[allow(dead_code)]
318pub fn vec_intersperse<T: Clone>(v: &[T], sep: T) -> Vec<T> {
319    if v.is_empty() {
320        return vec![];
321    }
322    let mut result = Vec::with_capacity(v.len() * 2 - 1);
323    for (i, x) in v.iter().enumerate() {
324        if i > 0 {
325            result.push(sep.clone());
326        }
327        result.push(x.clone());
328    }
329    result
330}
331/// Transpose a `Vec<Vec<T>>` (rows ↔ columns).
332///
333/// The input must be rectangular (all inner vecs same length).
334#[allow(dead_code)]
335pub fn vec_transpose<T: Clone>(matrix: &[Vec<T>]) -> Vec<Vec<T>> {
336    if matrix.is_empty() || matrix[0].is_empty() {
337        return vec![];
338    }
339    let rows = matrix.len();
340    let cols = matrix[0].len();
341    (0..cols)
342        .map(|c| (0..rows).map(|r| matrix[r][c].clone()).collect())
343        .collect()
344}
345/// Produce all combinations of one element from each inner slice.
346///
347/// E.g. `[\[1,2\],\[3,4\]]` → `[\[1,3\],\[1,4\],\[2,3\],\[2,4\]]`.
348#[allow(dead_code)]
349pub fn vec_cartesian_product<T: Clone>(vecs: &[Vec<T>]) -> Vec<Vec<T>> {
350    if vecs.is_empty() {
351        return vec![vec![]];
352    }
353    let mut result = vec![vec![]];
354    for row in vecs {
355        let mut new_result = Vec::new();
356        for prefix in &result {
357            for item in row {
358                let mut new_prefix = prefix.clone();
359                new_prefix.push(item.clone());
360                new_result.push(new_prefix);
361            }
362        }
363        result = new_result;
364    }
365    result
366}
367/// Return the maximum element of a non-empty slice, or `None`.
368#[allow(dead_code)]
369pub fn vec_max<T: Ord + Clone>(v: &[T]) -> Option<T> {
370    v.iter().max().cloned()
371}
372/// Return the minimum element of a non-empty slice, or `None`.
373#[allow(dead_code)]
374pub fn vec_min<T: Ord + Clone>(v: &[T]) -> Option<T> {
375    v.iter().min().cloned()
376}
377/// Sum all `u64` values in a slice.
378#[allow(dead_code)]
379pub fn vec_sum_u64(v: &[u64]) -> u64 {
380    v.iter().sum()
381}
382/// Product of all `u64` values in a slice.
383#[allow(dead_code)]
384pub fn vec_product_u64(v: &[u64]) -> u64 {
385    v.iter().product()
386}
387#[cfg(test)]
388mod vec_extra_tests {
389    use super::*;
390    #[test]
391    fn test_vec_append() {
392        let a = vec![1, 2];
393        let b = vec![3, 4];
394        assert_eq!(vec_append(&a, &b), vec![1, 2, 3, 4]);
395    }
396    #[test]
397    fn test_vec_dedup_stable() {
398        let v = vec![1, 2, 1, 3, 2, 4];
399        assert_eq!(vec_dedup_stable(&v), vec![1, 2, 3, 4]);
400    }
401    #[test]
402    fn test_vec_flatten() {
403        let v = vec![vec![1, 2], vec![3], vec![4, 5]];
404        assert_eq!(vec_flatten(v), vec![1, 2, 3, 4, 5]);
405    }
406    #[test]
407    fn test_vec_head_tail() {
408        let v = vec![10, 20, 30];
409        assert_eq!(vec_head(&v), Some(&10));
410        assert_eq!(vec_tail(&v), vec![20, 30]);
411        assert_eq!(vec_init(&v), vec![10, 20]);
412    }
413    #[test]
414    fn test_vec_zip_unzip() {
415        let a = vec![1, 2, 3];
416        let b = vec!["a", "b", "c"];
417        let zipped = vec_zip(&a, &b);
418        assert_eq!(zipped, vec![(1, "a"), (2, "b"), (3, "c")]);
419        let (a2, b2): (Vec<_>, Vec<_>) = vec_unzip(zipped);
420        assert_eq!(a2, a);
421        assert_eq!(b2, b);
422    }
423    #[test]
424    fn test_vec_rotate() {
425        let v = vec![1, 2, 3, 4, 5];
426        assert_eq!(vec_rotate_left(&v, 2), vec![3, 4, 5, 1, 2]);
427        assert_eq!(vec_rotate_right(&v, 2), vec![4, 5, 1, 2, 3]);
428    }
429    #[test]
430    fn test_vec_intersperse() {
431        let v = vec![1, 2, 3];
432        assert_eq!(vec_intersperse(&v, 0), vec![1, 0, 2, 0, 3]);
433    }
434    #[test]
435    fn test_vec_transpose() {
436        let m = vec![vec![1, 2, 3], vec![4, 5, 6]];
437        let t = vec_transpose(&m);
438        assert_eq!(t, vec![vec![1, 4], vec![2, 5], vec![3, 6]]);
439    }
440    #[test]
441    fn test_vec_cartesian_product() {
442        let vecs = vec![vec![1, 2], vec![3, 4]];
443        let product = vec_cartesian_product(&vecs);
444        assert_eq!(product.len(), 4);
445        assert!(product.contains(&vec![1, 3]));
446        assert!(product.contains(&vec![2, 4]));
447    }
448    #[test]
449    fn test_vec_partition() {
450        let v = vec![1, 2, 3, 4, 5, 6];
451        let (even, odd) = vec_partition(v, |x| x % 2 == 0);
452        assert_eq!(even, vec![2, 4, 6]);
453        assert_eq!(odd, vec![1, 3, 5]);
454    }
455    #[test]
456    fn test_fixed_vec() {
457        let fv = FixedVec::from_vec(vec![10, 20, 30]);
458        assert_eq!(fv.len(), 3);
459        assert_eq!(fv.get(1), Some(&20));
460        assert_eq!(fv.get(5), None);
461    }
462    #[test]
463    fn test_vec_step_by() {
464        let v = vec![0, 1, 2, 3, 4, 5, 6];
465        assert_eq!(vec_step_by(&v, 0, 2), vec![0, 2, 4, 6]);
466    }
467    #[test]
468    fn test_vec_count_where() {
469        let v = vec![1, 2, 3, 4, 5];
470        assert_eq!(vec_count_where(&v, |x| *x > 3), 2);
471    }
472    #[test]
473    fn test_vec_min_max() {
474        let v = vec![3, 1, 4, 1, 5, 9];
475        assert_eq!(vec_min(&v), Some(1));
476        assert_eq!(vec_max(&v), Some(9));
477    }
478    #[test]
479    fn test_vec_remove_at_insert_at() {
480        let v = vec![1, 2, 3, 4];
481        let removed = vec_remove_at(&v, 1);
482        assert_eq!(removed, vec![1, 3, 4]);
483        let inserted = vec_insert_at(&v, 2, 99);
484        assert_eq!(inserted, vec![1, 2, 99, 3, 4]);
485    }
486    #[test]
487    fn test_vec_try_map() {
488        let v = vec!["1", "2", "3"];
489        let result: Result<Vec<u32>, _> = vec_try_map(v, |s| s.parse::<u32>());
490        assert_eq!(result.expect("result should be valid"), vec![1, 2, 3]);
491    }
492}
493/// Assert that two slices have the same length and return an error otherwise.
494#[allow(dead_code)]
495pub fn same_length_check<A, B>(a: &[A], b: &[B]) -> Result<(), String> {
496    if a.len() == b.len() {
497        Ok(())
498    } else {
499        Err(format!("length mismatch: {} vs {}", a.len(), b.len()))
500    }
501}
502/// Zip two slices, failing if they have different lengths.
503#[allow(dead_code)]
504pub fn zip_exact<A: Clone, B: Clone>(a: &[A], b: &[B]) -> Result<Vec<(A, B)>, String> {
505    same_length_check(a, b)?;
506    Ok(vec_zip(a, b))
507}
508/// Map over a slice and collect the results, also returning the original indices.
509#[allow(dead_code)]
510pub fn indexed_map<T, U, F: Fn(usize, &T) -> U>(v: &[T], f: F) -> Vec<(usize, U)> {
511    v.iter().enumerate().map(|(i, x)| (i, f(i, x))).collect()
512}
513/// Find the index of the maximum element.
514#[allow(dead_code)]
515pub fn argmax<T: PartialOrd>(v: &[T]) -> Option<usize> {
516    if v.is_empty() {
517        return None;
518    }
519    let mut best = 0;
520    for (i, x) in v.iter().enumerate() {
521        if *x > v[best] {
522            best = i;
523        }
524    }
525    Some(best)
526}
527/// Find the index of the minimum element.
528#[allow(dead_code)]
529pub fn argmin<T: PartialOrd>(v: &[T]) -> Option<usize> {
530    if v.is_empty() {
531        return None;
532    }
533    let mut best = 0;
534    for (i, x) in v.iter().enumerate() {
535        if *x < v[best] {
536            best = i;
537        }
538    }
539    Some(best)
540}
541/// Run-length encode a slice: consecutive equal elements become `(value, count)`.
542#[allow(dead_code)]
543pub fn run_length_encode<T: PartialEq + Clone>(v: &[T]) -> Vec<(T, usize)> {
544    if v.is_empty() {
545        return vec![];
546    }
547    let mut result = Vec::new();
548    let mut current = v[0].clone();
549    let mut count = 1;
550    for item in &v[1..] {
551        if *item == current {
552            count += 1;
553        } else {
554            result.push((current.clone(), count));
555            current = item.clone();
556            count = 1;
557        }
558    }
559    result.push((current, count));
560    result
561}
562/// Decode a run-length encoded sequence back to a flat vector.
563#[allow(dead_code)]
564pub fn run_length_decode<T: Clone>(encoded: &[(T, usize)]) -> Vec<T> {
565    let mut result = Vec::new();
566    for (item, count) in encoded {
567        for _ in 0..*count {
568            result.push(item.clone());
569        }
570    }
571    result
572}
573/// Sliding window iterator: produce all sub-slices of length `window`.
574#[allow(dead_code)]
575pub fn windows_collect<T: Clone>(v: &[T], window: usize) -> Vec<Vec<T>> {
576    if window == 0 || window > v.len() {
577        return vec![];
578    }
579    v.windows(window).map(|w| w.to_vec()).collect()
580}
581/// Return `true` if `v` is a palindrome.
582#[allow(dead_code)]
583pub fn is_palindrome<T: PartialEq>(v: &[T]) -> bool {
584    let n = v.len();
585    for i in 0..n / 2 {
586        if v[i] != v[n - 1 - i] {
587            return false;
588        }
589    }
590    true
591}
592/// Flatten one level of nesting.
593#[allow(dead_code)]
594pub fn flatten_once<T: Clone>(v: &[Vec<T>]) -> Vec<T> {
595    v.iter().flat_map(|inner| inner.iter().cloned()).collect()
596}
597/// Group consecutive elements by a key function.
598#[allow(dead_code)]
599pub fn group_by<T: Clone, K: PartialEq, F: Fn(&T) -> K>(v: &[T], key: F) -> Vec<Vec<T>> {
600    if v.is_empty() {
601        return vec![];
602    }
603    let mut groups: Vec<Vec<T>> = Vec::new();
604    let mut current_group = vec![v[0].clone()];
605    let mut current_key = key(&v[0]);
606    for item in &v[1..] {
607        let k = key(item);
608        if k == current_key {
609            current_group.push(item.clone());
610        } else {
611            groups.push(current_group.clone());
612            current_group = vec![item.clone()];
613            current_key = k;
614        }
615    }
616    groups.push(current_group);
617    groups
618}
619#[cfg(test)]
620mod vec_extra_tests2 {
621    use super::*;
622    #[test]
623    fn test_same_length_check() {
624        assert!(same_length_check(&[1, 2], &[3, 4]).is_ok());
625        assert!(same_length_check(&[1], &[3, 4]).is_err());
626    }
627    #[test]
628    fn test_zip_exact() {
629        let a = vec![1, 2, 3];
630        let b = vec!["a", "b", "c"];
631        let z = zip_exact(&a, &b).expect("operation should succeed");
632        assert_eq!(z.len(), 3);
633        assert!(zip_exact(&[1], &[2, 3]).is_err());
634    }
635    #[test]
636    fn test_argmax_argmin() {
637        let v = vec![3.0f64, 1.0, 4.0, 1.0, 5.0, 9.0, 2.0, 6.0];
638        assert_eq!(argmax(&v), Some(5));
639        assert_eq!(argmin(&v), Some(1));
640        let empty: Vec<f64> = vec![];
641        assert!(argmax(&empty).is_none());
642    }
643    #[test]
644    fn test_run_length_encode_decode() {
645        let v = vec![1, 1, 2, 3, 3, 3, 1];
646        let enc = run_length_encode(&v);
647        assert_eq!(enc, vec![(1, 2), (2, 1), (3, 3), (1, 1)]);
648        let dec = run_length_decode(&enc);
649        assert_eq!(dec, v);
650    }
651    #[test]
652    fn test_windows_collect() {
653        let v = vec![1, 2, 3, 4];
654        let wins = windows_collect(&v, 2);
655        assert_eq!(wins, vec![vec![1, 2], vec![2, 3], vec![3, 4]]);
656    }
657    #[test]
658    fn test_is_palindrome() {
659        assert!(is_palindrome(&[1, 2, 1]));
660        assert!(is_palindrome(&[1, 2, 2, 1]));
661        assert!(!is_palindrome(&[1, 2, 3]));
662        assert!(is_palindrome::<i32>(&[]));
663    }
664    #[test]
665    fn test_flatten_once() {
666        let v = vec![vec![1, 2], vec![3], vec![4, 5]];
667        assert_eq!(flatten_once(&v), vec![1, 2, 3, 4, 5]);
668    }
669    #[test]
670    fn test_group_by() {
671        let v = vec![1, 1, 2, 3, 3, 1];
672        let groups = group_by(&v, |x| *x);
673        assert_eq!(groups.len(), 4);
674        assert_eq!(groups[0], vec![1, 1]);
675        assert_eq!(groups[2], vec![3, 3]);
676    }
677    #[test]
678    fn test_indexed_map() {
679        let v = vec![10, 20, 30];
680        let result = indexed_map(&v, |i, x| i + x);
681        assert_eq!(result, vec![(0, 10), (1, 21), (2, 32)]);
682    }
683}
684/// Return elements in `a` not in `b` (order-preserving, `O(n*m)`).
685#[allow(dead_code)]
686pub fn vec_difference<T: PartialEq + Clone>(a: &[T], b: &[T]) -> Vec<T> {
687    a.iter().filter(|x| !b.contains(x)).cloned().collect()
688}
689/// Return elements in both `a` and `b` (order-preserving, keeps first occurrence).
690#[allow(dead_code)]
691pub fn vec_intersection<T: PartialEq + Clone>(a: &[T], b: &[T]) -> Vec<T> {
692    a.iter().filter(|x| b.contains(x)).cloned().collect()
693}
694/// Return elements in either `a` or `b` but not both (symmetric difference).
695#[allow(dead_code)]
696pub fn vec_symmetric_difference<T: PartialEq + Clone>(a: &[T], b: &[T]) -> Vec<T> {
697    let mut result = vec_difference(a, b);
698    result.extend(vec_difference(b, a));
699    result
700}
701/// Return `true` if `a` and `b` are set-equal (same elements, any order).
702#[allow(dead_code)]
703pub fn vec_set_eq<T: PartialEq>(a: &[T], b: &[T]) -> bool {
704    if a.len() != b.len() {
705        return false;
706    }
707    a.iter().all(|x| b.contains(x))
708}
709/// Return `true` if `a` is a subset of `b` (all elements of `a` appear in `b`).
710#[allow(dead_code)]
711pub fn vec_is_subset<T: PartialEq>(a: &[T], b: &[T]) -> bool {
712    a.iter().all(|x| b.contains(x))
713}
714/// Compute the arithmetic mean of a `f64` slice.
715///
716/// Returns `f64::NAN` for an empty slice.
717#[allow(dead_code)]
718pub fn vec_mean_f64(v: &[f64]) -> f64 {
719    if v.is_empty() {
720        return f64::NAN;
721    }
722    v.iter().sum::<f64>() / v.len() as f64
723}
724/// Compute the variance (population) of a `f64` slice.
725#[allow(dead_code)]
726pub fn vec_variance_f64(v: &[f64]) -> f64 {
727    if v.is_empty() {
728        return f64::NAN;
729    }
730    let mean = vec_mean_f64(v);
731    v.iter().map(|x| (x - mean).powi(2)).sum::<f64>() / v.len() as f64
732}
733/// Compute the standard deviation (population) of a `f64` slice.
734#[allow(dead_code)]
735pub fn vec_std_dev_f64(v: &[f64]) -> f64 {
736    vec_variance_f64(v).sqrt()
737}
738/// Compute the median of a `f64` slice.
739///
740/// Returns `f64::NAN` for empty slices; averages the two middle elements for
741/// even-length slices.
742#[allow(dead_code)]
743pub fn vec_median_f64(v: &[f64]) -> f64 {
744    if v.is_empty() {
745        return f64::NAN;
746    }
747    let mut sorted = v.to_vec();
748    sorted.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
749    let n = sorted.len();
750    if n % 2 == 1 {
751        sorted[n / 2]
752    } else {
753        (sorted[n / 2 - 1] + sorted[n / 2]) / 2.0
754    }
755}
756/// Normalise a `f64` vector so that its values sum to 1.0.
757///
758/// Returns the vector unchanged if the sum is zero.
759#[allow(dead_code)]
760pub fn vec_normalize_f64(v: &[f64]) -> Vec<f64> {
761    let total: f64 = v.iter().sum();
762    if total == 0.0 {
763        return v.to_vec();
764    }
765    v.iter().map(|x| x / total).collect()
766}
767/// Split a slice into chunks of `size`.
768///
769/// The last chunk may be shorter than `size`.
770#[allow(dead_code)]
771pub fn vec_chunks<T: Clone>(v: &[T], size: usize) -> Vec<Vec<T>> {
772    if size == 0 {
773        return vec![];
774    }
775    v.chunks(size).map(|c| c.to_vec()).collect()
776}
777/// Take up to `n` elements from the front of a slice.
778#[allow(dead_code)]
779pub fn vec_take<T: Clone>(v: &[T], n: usize) -> Vec<T> {
780    v.iter().take(n).cloned().collect()
781}
782/// Drop the first `n` elements.
783#[allow(dead_code)]
784pub fn vec_drop<T: Clone>(v: &[T], n: usize) -> Vec<T> {
785    v.iter().skip(n).cloned().collect()
786}
787/// Take elements while a predicate is true.
788#[allow(dead_code)]
789pub fn vec_take_while<T: Clone, F: Fn(&T) -> bool>(v: &[T], pred: F) -> Vec<T> {
790    v.iter().take_while(|x| pred(x)).cloned().collect()
791}
792/// Drop elements while a predicate is true.
793#[allow(dead_code)]
794pub fn vec_drop_while<T: Clone, F: Fn(&T) -> bool>(v: &[T], pred: F) -> Vec<T> {
795    v.iter().skip_while(|x| pred(x)).cloned().collect()
796}
797#[cfg(test)]
798mod vec_set_op_tests {
799    use super::*;
800    #[test]
801    fn test_vec_difference() {
802        assert_eq!(vec_difference(&[1, 2, 3], &[2, 4]), vec![1, 3]);
803    }
804    #[test]
805    fn test_vec_intersection() {
806        assert_eq!(vec_intersection(&[1, 2, 3, 4], &[2, 4, 6]), vec![2, 4]);
807    }
808    #[test]
809    fn test_vec_symmetric_difference() {
810        let r = vec_symmetric_difference(&[1, 2, 3], &[2, 3, 4]);
811        assert!(r.contains(&1) && r.contains(&4));
812        assert!(!r.contains(&2));
813    }
814    #[test]
815    fn test_vec_set_eq() {
816        assert!(vec_set_eq(&[1, 2, 3], &[3, 1, 2]));
817        assert!(!vec_set_eq(&[1, 2], &[1, 2, 3]));
818    }
819    #[test]
820    fn test_vec_is_subset() {
821        assert!(vec_is_subset(&[1, 2], &[1, 2, 3]));
822        assert!(!vec_is_subset(&[1, 4], &[1, 2, 3]));
823    }
824    #[test]
825    fn test_vec_mean_f64() {
826        assert!((vec_mean_f64(&[1.0, 2.0, 3.0]) - 2.0).abs() < 1e-9);
827        assert!(vec_mean_f64(&[]).is_nan());
828    }
829    #[test]
830    fn test_vec_variance_f64() {
831        let v = vec![2.0, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0];
832        let var = vec_variance_f64(&v);
833        assert!((var - 4.0).abs() < 1e-9);
834    }
835    #[test]
836    fn test_vec_std_dev_f64() {
837        let v = vec![2.0, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0];
838        let std = vec_std_dev_f64(&v);
839        assert!((std - 2.0).abs() < 1e-9);
840    }
841    #[test]
842    fn test_vec_median_f64_odd() {
843        assert!((vec_median_f64(&[3.0, 1.0, 2.0]) - 2.0).abs() < 1e-9);
844    }
845    #[test]
846    fn test_vec_median_f64_even() {
847        assert!((vec_median_f64(&[1.0, 3.0, 5.0, 7.0]) - 4.0).abs() < 1e-9);
848    }
849    #[test]
850    fn test_vec_normalize_f64() {
851        let v = vec![1.0, 2.0, 3.0, 4.0];
852        let n = vec_normalize_f64(&v);
853        let sum: f64 = n.iter().sum();
854        assert!((sum - 1.0).abs() < 1e-9);
855    }
856    #[test]
857    fn test_vec_chunks() {
858        let v = vec![1, 2, 3, 4, 5];
859        let chunks = vec_chunks(&v, 2);
860        assert_eq!(chunks.len(), 3);
861        assert_eq!(chunks[2], vec![5]);
862    }
863    #[test]
864    fn test_vec_take_drop() {
865        let v = vec![1, 2, 3, 4, 5];
866        assert_eq!(vec_take(&v, 3), vec![1, 2, 3]);
867        assert_eq!(vec_drop(&v, 3), vec![4, 5]);
868    }
869    #[test]
870    fn test_vec_take_while_drop_while() {
871        let v = vec![1, 2, 3, 4, 5];
872        let tw = vec_take_while(&v, |x| *x < 4);
873        assert_eq!(tw, vec![1, 2, 3]);
874        let dw = vec_drop_while(&v, |x| *x < 4);
875        assert_eq!(dw, vec![4, 5]);
876    }
877    #[test]
878    fn test_vec_normalize_zero_sum() {
879        let v = vec![0.0, 0.0, 0.0];
880        let n = vec_normalize_f64(&v);
881        assert_eq!(n, v);
882    }
883    #[test]
884    fn test_vec_chunks_zero_size() {
885        let v = vec![1, 2, 3];
886        let chunks = vec_chunks(&v, 0);
887        assert!(chunks.is_empty());
888    }
889}
890pub fn vec_ext_prop_axiom(name: &str, env: &mut Environment) -> std::result::Result<(), String> {
891    let prop = Expr::Sort(Level::zero());
892    env.add(Declaration::Axiom {
893        name: Name::str(name),
894        univ_params: vec![],
895        ty: prop,
896    })
897    .map_err(|e| e.to_string())
898}
899/// Build `∀ (α : Type), Prop`.
900pub fn vec_ext_forall1_axiom(name: &str, env: &mut Environment) -> std::result::Result<(), String> {
901    let prop = Expr::Sort(Level::zero());
902    let type1 = Expr::Sort(Level::succ(Level::zero()));
903    let ty = Expr::Pi(
904        BinderInfo::Implicit,
905        Name::str("α"),
906        Node::new(type1),
907        Node::new(prop),
908    );
909    env.add(Declaration::Axiom {
910        name: Name::str(name),
911        univ_params: vec![],
912        ty,
913    })
914    .map_err(|e| e.to_string())
915}
916/// Build `∀ (α β : Type), Prop`.
917pub fn vec_ext_forall2_axiom(name: &str, env: &mut Environment) -> std::result::Result<(), String> {
918    let prop = Expr::Sort(Level::zero());
919    let type1 = Expr::Sort(Level::succ(Level::zero()));
920    let ty = Expr::Pi(
921        BinderInfo::Implicit,
922        Name::str("α"),
923        Node::new(type1.clone()),
924        Node::new(Expr::Pi(
925            BinderInfo::Implicit,
926            Name::str("β"),
927            Node::new(type1),
928            Node::new(prop),
929        )),
930    );
931    env.add(Declaration::Axiom {
932        name: Name::str(name),
933        univ_params: vec![],
934        ty,
935    })
936    .map_err(|e| e.to_string())
937}
938/// Build `∀ (α β γ : Type), Prop`.
939pub fn vec_ext_forall3_axiom(name: &str, env: &mut Environment) -> std::result::Result<(), String> {
940    let prop = Expr::Sort(Level::zero());
941    let type1 = Expr::Sort(Level::succ(Level::zero()));
942    let ty = Expr::Pi(
943        BinderInfo::Implicit,
944        Name::str("α"),
945        Node::new(type1.clone()),
946        Node::new(Expr::Pi(
947            BinderInfo::Implicit,
948            Name::str("β"),
949            Node::new(type1.clone()),
950            Node::new(Expr::Pi(
951                BinderInfo::Implicit,
952                Name::str("γ"),
953                Node::new(type1),
954                Node::new(prop),
955            )),
956        )),
957    );
958    env.add(Declaration::Axiom {
959        name: Name::str(name),
960        univ_params: vec![],
961        ty,
962    })
963    .map_err(|e| e.to_string())
964}
965/// `Vec.functor_map_id : ∀ α, map id xs = xs`
966pub fn vec_ext_build_functor_map_id(env: &mut Environment) -> std::result::Result<(), String> {
967    vec_ext_forall1_axiom("Vec.functor_map_id", env)
968}
969/// `Vec.functor_map_comp : ∀ α β γ (f : α → β) (g : β → γ), map (g ∘ f) = map g ∘ map f`
970pub fn vec_ext_build_functor_map_comp(env: &mut Environment) -> std::result::Result<(), String> {
971    vec_ext_forall3_axiom("Vec.functor_map_comp", env)
972}
973/// `Vec.monad_left_id : ∀ α β (a : α) (f : α → Vec β), andThen \[a\] f = f a`
974pub fn vec_ext_build_monad_left_id(env: &mut Environment) -> std::result::Result<(), String> {
975    vec_ext_forall2_axiom("Vec.monad_left_id", env)
976}
977/// `Vec.monad_right_id : ∀ α (xs : Vec α), andThen xs pure = xs`
978pub fn vec_ext_build_monad_right_id(env: &mut Environment) -> std::result::Result<(), String> {
979    vec_ext_forall1_axiom("Vec.monad_right_id", env)
980}
981/// `Vec.monad_assoc : ∀ α β γ, andThen (andThen xs f) g = andThen xs (fun x => andThen (f x) g)`
982pub fn vec_ext_build_monad_assoc(env: &mut Environment) -> std::result::Result<(), String> {
983    vec_ext_forall3_axiom("Vec.monad_assoc", env)
984}
985/// `Vec.ap_identity : ap [id] xs = xs`
986pub fn vec_ext_build_ap_identity(env: &mut Environment) -> std::result::Result<(), String> {
987    vec_ext_forall1_axiom("Vec.ap_identity", env)
988}
989/// `Vec.ap_homomorphism : ap \[f\] \[v\] = \[f v\]`
990pub fn vec_ext_build_ap_homomorphism(env: &mut Environment) -> std::result::Result<(), String> {
991    vec_ext_forall2_axiom("Vec.ap_homomorphism", env)
992}
993/// `Vec.ap_interchange : ap fs \[v\] = ap \[fun f => f v\] fs`
994pub fn vec_ext_build_ap_interchange(env: &mut Environment) -> std::result::Result<(), String> {
995    vec_ext_forall2_axiom("Vec.ap_interchange", env)
996}
997/// `Vec.ap_composition : ap (ap (ap [∘] fs) gs) xs = ap fs (ap gs xs)`
998pub fn vec_ext_build_ap_composition(env: &mut Environment) -> std::result::Result<(), String> {
999    vec_ext_forall3_axiom("Vec.ap_composition", env)
1000}
1001/// `Vec.foldr_nil : foldr f z [] = z`
1002pub fn vec_ext_build_foldr_nil(env: &mut Environment) -> std::result::Result<(), String> {
1003    vec_ext_forall2_axiom("Vec.foldr_nil", env)
1004}
1005/// `Vec.foldr_cons : foldr f z (x::xs) = f x (foldr f z xs)`
1006pub fn vec_ext_build_foldr_cons(env: &mut Environment) -> std::result::Result<(), String> {
1007    vec_ext_forall2_axiom("Vec.foldr_cons", env)
1008}
1009/// `Vec.foldl_nil : foldl f z [] = z`
1010pub fn vec_ext_build_foldl_nil(env: &mut Environment) -> std::result::Result<(), String> {
1011    vec_ext_forall2_axiom("Vec.foldl_nil", env)
1012}
1013/// `Vec.foldl_cons : foldl f z (x::xs) = foldl f (f z x) xs`
1014pub fn vec_ext_build_foldl_cons(env: &mut Environment) -> std::result::Result<(), String> {
1015    vec_ext_forall2_axiom("Vec.foldl_cons", env)
1016}
1017/// `Vec.foldl_foldr_duality : foldl f z xs = foldr (flip f) z (reverse xs)`
1018pub fn vec_ext_build_foldl_foldr_duality(env: &mut Environment) -> std::result::Result<(), String> {
1019    vec_ext_forall2_axiom("Vec.foldl_foldr_duality", env)
1020}
1021/// `Vec.scanl_nil : scanl f z [] = \[z\]`
1022pub fn vec_ext_build_scanl_nil(env: &mut Environment) -> std::result::Result<(), String> {
1023    vec_ext_forall2_axiom("Vec.scanl_nil", env)
1024}
1025/// `Vec.scanl_cons : scanl f z (x::xs) = z :: scanl f (f z x) xs`
1026pub fn vec_ext_build_scanl_cons(env: &mut Environment) -> std::result::Result<(), String> {
1027    vec_ext_forall2_axiom("Vec.scanl_cons", env)
1028}
1029/// `Vec.scanr_nil : scanr f z [] = \[z\]`
1030pub fn vec_ext_build_scanr_nil(env: &mut Environment) -> std::result::Result<(), String> {
1031    vec_ext_forall2_axiom("Vec.scanr_nil", env)
1032}
1033/// `Vec.scanr_cons : head (scanr f z (x::xs)) = f x (head (scanr f z xs))`
1034pub fn vec_ext_build_scanr_cons(env: &mut Environment) -> std::result::Result<(), String> {
1035    vec_ext_forall2_axiom("Vec.scanr_cons", env)
1036}
1037/// `Vec.scanl_last : last (scanl f z xs) = foldl f z xs`
1038pub fn vec_ext_build_scanl_last(env: &mut Environment) -> std::result::Result<(), String> {
1039    vec_ext_forall2_axiom("Vec.scanl_last", env)
1040}
1041/// `Vec.sort_is_permutation : sort xs is a permutation of xs`
1042pub fn vec_ext_build_sort_is_permutation(env: &mut Environment) -> std::result::Result<(), String> {
1043    vec_ext_forall1_axiom("Vec.sort_is_permutation", env)
1044}
1045/// `Vec.sort_is_sorted : ∀ α \[Ord α\] xs, isSorted (sort xs)`
1046pub fn vec_ext_build_sort_is_sorted(env: &mut Environment) -> std::result::Result<(), String> {
1047    vec_ext_forall1_axiom("Vec.sort_is_sorted", env)
1048}
1049/// `Vec.stable_sort_preserves_order : stable sort preserves relative order of equal elements`
1050pub fn vec_ext_build_stable_sort(env: &mut Environment) -> std::result::Result<(), String> {
1051    vec_ext_forall1_axiom("Vec.stable_sort_preserves_order", env)
1052}
1053/// `Vec.sort_idempotent : sort (sort xs) = sort xs`
1054pub fn vec_ext_build_sort_idempotent(env: &mut Environment) -> std::result::Result<(), String> {
1055    vec_ext_forall1_axiom("Vec.sort_idempotent", env)
1056}
1057/// `Vec.map_fusion : map f (map g xs) = map (f ∘ g) xs`
1058pub fn vec_ext_build_map_fusion(env: &mut Environment) -> std::result::Result<(), String> {
1059    vec_ext_forall3_axiom("Vec.map_fusion", env)
1060}
1061/// `Vec.filter_fusion : filter p (filter q xs) = filter (fun x => p x && q x) xs`
1062pub fn vec_ext_build_filter_fusion(env: &mut Environment) -> std::result::Result<(), String> {
1063    vec_ext_forall1_axiom("Vec.filter_fusion", env)
1064}
1065/// `Vec.map_filter_fusion : map f (filter p xs) = filterMap (fun x => if p x then Some (f x) else None) xs`
1066pub fn vec_ext_build_map_filter_fusion(env: &mut Environment) -> std::result::Result<(), String> {
1067    vec_ext_forall2_axiom("Vec.map_filter_fusion", env)
1068}
1069/// `Vec.fold_build_duality : foldr f z (build g) = g f z` (deforestation)
1070pub fn vec_ext_build_fold_build_duality(env: &mut Environment) -> std::result::Result<(), String> {
1071    vec_ext_forall2_axiom("Vec.fold_build_duality", env)
1072}
1073/// `Vec.fin_index_get : ∀ {α n} (xs : Vec α n) (i : Fin n), xs\[i\] is within bounds`
1074pub fn vec_ext_build_fin_index_get(env: &mut Environment) -> std::result::Result<(), String> {
1075    vec_ext_forall2_axiom("Vec.fin_index_get", env)
1076}
1077/// `Vec.fin_index_set : ∀ {α n} (xs : Vec α n) (i : Fin n) v, set xs i v has same length`
1078pub fn vec_ext_build_fin_index_set(env: &mut Environment) -> std::result::Result<(), String> {
1079    vec_ext_forall2_axiom("Vec.fin_index_set", env)
1080}
1081/// `Vec.fin_map_preserves_length : length (map f xs) = length xs`
1082pub fn vec_ext_build_fin_map_length(env: &mut Environment) -> std::result::Result<(), String> {
1083    vec_ext_forall2_axiom("Vec.fin_map_preserves_length", env)
1084}
1085/// `Vec.reverse_involutive : reverse (reverse xs) = xs`
1086pub fn vec_ext_build_reverse_involutive(env: &mut Environment) -> std::result::Result<(), String> {
1087    vec_ext_forall1_axiom("Vec.reverse_involutive", env)
1088}
1089/// `Vec.reverse_append : reverse (xs ++ ys) = reverse ys ++ reverse xs`
1090pub fn vec_ext_build_reverse_append(env: &mut Environment) -> std::result::Result<(), String> {
1091    vec_ext_forall1_axiom("Vec.reverse_append", env)
1092}
1093/// `Vec.reverse_map : reverse (map f xs) = map f (reverse xs)`
1094pub fn vec_ext_build_reverse_map(env: &mut Environment) -> std::result::Result<(), String> {
1095    vec_ext_forall2_axiom("Vec.reverse_map", env)
1096}
1097/// `Vec.take_drop_reconstruct : take n xs ++ drop n xs = xs`
1098pub fn vec_ext_build_take_drop_reconstruct(
1099    env: &mut Environment,
1100) -> std::result::Result<(), String> {
1101    vec_ext_forall1_axiom("Vec.take_drop_reconstruct", env)
1102}
1103/// `Vec.take_length : length (take n xs) = min n (length xs)`
1104pub fn vec_ext_build_take_length(env: &mut Environment) -> std::result::Result<(), String> {
1105    vec_ext_forall1_axiom("Vec.take_length", env)
1106}
1107/// `Vec.drop_length : length (drop n xs) = max 0 (length xs - n)`
1108pub fn vec_ext_build_drop_length(env: &mut Environment) -> std::result::Result<(), String> {
1109    vec_ext_forall1_axiom("Vec.drop_length", env)
1110}
1111/// `Vec.zip_length : length (zip xs ys) = min (length xs) (length ys)`
1112pub fn vec_ext_build_zip_length(env: &mut Environment) -> std::result::Result<(), String> {
1113    vec_ext_forall2_axiom("Vec.zip_length", env)
1114}
1115/// `Vec.unzip_zip : unzip (zip xs ys) = (take (min n m) xs, take (min n m) ys)`
1116pub fn vec_ext_build_unzip_zip(env: &mut Environment) -> std::result::Result<(), String> {
1117    vec_ext_forall2_axiom("Vec.unzip_zip", env)
1118}
1119/// `Vec.zip_map : zip (map f xs) (map g ys) = map (bimap f g) (zip xs ys)`
1120pub fn vec_ext_build_zip_map(env: &mut Environment) -> std::result::Result<(), String> {
1121    vec_ext_forall3_axiom("Vec.zip_map", env)
1122}
1123/// `Vec.chunks_flatten : flatten (chunks n xs) = xs`  (when n > 0)
1124pub fn vec_ext_build_chunks_flatten(env: &mut Environment) -> std::result::Result<(), String> {
1125    vec_ext_forall1_axiom("Vec.chunks_flatten", env)
1126}
1127/// `Vec.chunks_all_size : ∀ chunk ∈ init (chunks n xs), length chunk = n`
1128pub fn vec_ext_build_chunks_all_size(env: &mut Environment) -> std::result::Result<(), String> {
1129    vec_ext_forall1_axiom("Vec.chunks_all_size", env)
1130}
1131/// `Vec.chunks_count : length (chunks n xs) = ceil (length xs / n)`
1132pub fn vec_ext_build_chunks_count(env: &mut Environment) -> std::result::Result<(), String> {
1133    vec_ext_forall1_axiom("Vec.chunks_count", env)
1134}
1135/// `Vec.append_nil_left : [] ++ xs = xs`
1136pub fn vec_ext_build_append_nil_left(env: &mut Environment) -> std::result::Result<(), String> {
1137    vec_ext_forall1_axiom("Vec.append_nil_left", env)
1138}
1139/// `Vec.append_nil_right : xs ++ [] = xs`
1140pub fn vec_ext_build_append_nil_right(env: &mut Environment) -> std::result::Result<(), String> {
1141    vec_ext_forall1_axiom("Vec.append_nil_right", env)
1142}
1143/// `Vec.append_assoc : (xs ++ ys) ++ zs = xs ++ (ys ++ zs)`
1144pub fn vec_ext_build_append_assoc(env: &mut Environment) -> std::result::Result<(), String> {
1145    vec_ext_forall1_axiom("Vec.append_assoc", env)
1146}
1147/// `Vec.length_append : length (xs ++ ys) = length xs + length ys`
1148pub fn vec_ext_build_length_append(env: &mut Environment) -> std::result::Result<(), String> {
1149    vec_ext_forall1_axiom("Vec.length_append", env)
1150}
1151/// `Vec.rotate_left_right_inverse : rotateLeft n (rotateRight n xs) = xs`
1152pub fn vec_ext_build_rotate_left_right_inv(
1153    env: &mut Environment,
1154) -> std::result::Result<(), String> {
1155    vec_ext_forall1_axiom("Vec.rotate_left_right_inverse", env)
1156}
1157/// `Vec.rotate_length : length (rotateLeft n xs) = length xs`
1158pub fn vec_ext_build_rotate_length(env: &mut Environment) -> std::result::Result<(), String> {
1159    vec_ext_forall1_axiom("Vec.rotate_length", env)
1160}
1161/// `Vec.rotate_zero : rotateLeft 0 xs = xs`
1162pub fn vec_ext_build_rotate_zero(env: &mut Environment) -> std::result::Result<(), String> {
1163    vec_ext_forall1_axiom("Vec.rotate_zero", env)
1164}
1165/// `Vec.dlist_append_assoc : dlist append is associative`
1166pub fn vec_ext_build_dlist_append_assoc(env: &mut Environment) -> std::result::Result<(), String> {
1167    vec_ext_forall1_axiom("Vec.dlist_append_assoc", env)
1168}
1169/// `Vec.dlist_to_list_preserves : toList (dlist d) = d []`
1170pub fn vec_ext_build_dlist_to_list(env: &mut Environment) -> std::result::Result<(), String> {
1171    vec_ext_forall1_axiom("Vec.dlist_to_list_preserves", env)
1172}
1173/// `Vec.concat_map_id : concatMap pure xs = xs`
1174pub fn vec_ext_build_concat_map_id(env: &mut Environment) -> std::result::Result<(), String> {
1175    vec_ext_forall1_axiom("Vec.concat_map_id", env)
1176}
1177/// `Vec.concat_map_assoc : concatMap (concatMap f ∘ g) = concatMap f ∘ concatMap g`
1178pub fn vec_ext_build_concat_map_assoc(env: &mut Environment) -> std::result::Result<(), String> {
1179    vec_ext_forall3_axiom("Vec.concat_map_assoc", env)
1180}
1181/// `Vec.flatten_singleton : flatten [[x1], [x2], ...] = \[x1, x2, ...\]`
1182pub fn vec_ext_build_flatten_singleton(env: &mut Environment) -> std::result::Result<(), String> {
1183    vec_ext_forall1_axiom("Vec.flatten_singleton", env)
1184}
1185/// `Vec.flatten_map : flatten (map (map f) xss) = map f (flatten xss)`
1186pub fn vec_ext_build_flatten_map(env: &mut Environment) -> std::result::Result<(), String> {
1187    vec_ext_forall2_axiom("Vec.flatten_map", env)
1188}
1189/// `Vec.span_reconstruct : fst (span p xs) ++ snd (span p xs) = xs`
1190pub fn vec_ext_build_span_reconstruct(env: &mut Environment) -> std::result::Result<(), String> {
1191    vec_ext_forall1_axiom("Vec.span_reconstruct", env)
1192}
1193/// `Vec.partition_reconstruct : fst (partition p xs) ++ snd (partition p xs)` is permutation
1194pub fn vec_ext_build_partition_reconstruct(
1195    env: &mut Environment,
1196) -> std::result::Result<(), String> {
1197    vec_ext_forall1_axiom("Vec.partition_reconstruct", env)
1198}
1199/// `Vec.groupBy_flatten : flatten (groupBy eq xs) = xs`
1200pub fn vec_ext_build_groupby_flatten(env: &mut Environment) -> std::result::Result<(), String> {
1201    vec_ext_forall1_axiom("Vec.groupBy_flatten", env)
1202}
1203/// `Vec.prefix_sum_correct : prefixSum xs\[i\] = sum (take (i+1) xs)`
1204pub fn vec_ext_build_prefix_sum_correct(env: &mut Environment) -> std::result::Result<(), String> {
1205    vec_ext_prop_axiom("Vec.prefix_sum_correct", env)
1206}
1207/// `Vec.parallel_prefix_sequential_equiv : parallelPrefix f z xs = scanl f z xs`
1208pub fn vec_ext_build_parallel_prefix_equiv(
1209    env: &mut Environment,
1210) -> std::result::Result<(), String> {
1211    vec_ext_forall2_axiom("Vec.parallel_prefix_sequential_equiv", env)
1212}
1213/// `Vec.fenwick_prefix_sum_correct : query fenwick i = sum (take (i+1) original)`
1214pub fn vec_ext_build_fenwick_correct(env: &mut Environment) -> std::result::Result<(), String> {
1215    vec_ext_prop_axiom("Vec.fenwick_prefix_sum_correct", env)
1216}
1217/// `Vec.rle_decode_encode : decode (encode xs) = xs`
1218pub fn vec_ext_build_rle_roundtrip(env: &mut Environment) -> std::result::Result<(), String> {
1219    vec_ext_forall1_axiom("Vec.rle_decode_encode", env)
1220}
1221/// `Vec.rle_length : sum (map snd (rle xs)) = length xs`
1222pub fn vec_ext_build_rle_length(env: &mut Environment) -> std::result::Result<(), String> {
1223    vec_ext_forall1_axiom("Vec.rle_length", env)
1224}
1225/// `Vec.matrix_transpose_involutive : transpose (transpose m) = m`
1226pub fn vec_ext_build_matrix_transpose_invol(
1227    env: &mut Environment,
1228) -> std::result::Result<(), String> {
1229    vec_ext_forall1_axiom("Vec.matrix_transpose_involutive", env)
1230}
1231/// `Vec.matrix_row_count : length (transpose m) = length (head m)`
1232pub fn vec_ext_build_matrix_row_count(env: &mut Environment) -> std::result::Result<(), String> {
1233    vec_ext_forall1_axiom("Vec.matrix_row_count", env)
1234}
1235/// `Vec.matrix_col_count : length (head (transpose m)) = length m`
1236pub fn vec_ext_build_matrix_col_count(env: &mut Environment) -> std::result::Result<(), String> {
1237    vec_ext_forall1_axiom("Vec.matrix_col_count", env)
1238}
1239/// Register all extended Vec axioms into `env`.
1240///
1241/// Adds 35+ axioms covering:
1242/// - Vector functor/monad/applicative laws
1243/// - Fold laws (foldr, foldl)
1244/// - Scan operations (scanl, scanr)
1245/// - Sorting laws (stability, permutation)
1246/// - Fusion/deforestation
1247/// - Fin-indexed vectors
1248/// - Reverse, take/drop, zip/unzip laws
1249/// - Chunking operations
1250/// - Free monoid structure
1251/// - Rotations and circular buffers
1252/// - DList representation
1253/// - ConcatMap/flatten laws
1254/// - Span/partition/groupBy
1255/// - Parallel prefix operations
1256/// - Run-length encoding
1257/// - Matrix as nested vector
1258pub fn register_vec_extended_axioms(env: &mut Environment) {
1259    let builders: &[fn(&mut Environment) -> std::result::Result<(), String>] = &[
1260        vec_ext_build_functor_map_id,
1261        vec_ext_build_functor_map_comp,
1262        vec_ext_build_monad_left_id,
1263        vec_ext_build_monad_right_id,
1264        vec_ext_build_monad_assoc,
1265        vec_ext_build_ap_identity,
1266        vec_ext_build_ap_homomorphism,
1267        vec_ext_build_ap_interchange,
1268        vec_ext_build_ap_composition,
1269        vec_ext_build_foldr_nil,
1270        vec_ext_build_foldr_cons,
1271        vec_ext_build_foldl_nil,
1272        vec_ext_build_foldl_cons,
1273        vec_ext_build_foldl_foldr_duality,
1274        vec_ext_build_scanl_nil,
1275        vec_ext_build_scanl_cons,
1276        vec_ext_build_scanr_nil,
1277        vec_ext_build_scanr_cons,
1278        vec_ext_build_scanl_last,
1279        vec_ext_build_sort_is_permutation,
1280        vec_ext_build_sort_is_sorted,
1281        vec_ext_build_stable_sort,
1282        vec_ext_build_sort_idempotent,
1283        vec_ext_build_map_fusion,
1284        vec_ext_build_filter_fusion,
1285        vec_ext_build_map_filter_fusion,
1286        vec_ext_build_fold_build_duality,
1287        vec_ext_build_fin_index_get,
1288        vec_ext_build_fin_index_set,
1289        vec_ext_build_fin_map_length,
1290        vec_ext_build_reverse_involutive,
1291        vec_ext_build_reverse_append,
1292        vec_ext_build_reverse_map,
1293        vec_ext_build_take_drop_reconstruct,
1294        vec_ext_build_take_length,
1295        vec_ext_build_drop_length,
1296        vec_ext_build_zip_length,
1297        vec_ext_build_unzip_zip,
1298        vec_ext_build_zip_map,
1299        vec_ext_build_chunks_flatten,
1300        vec_ext_build_chunks_all_size,
1301        vec_ext_build_chunks_count,
1302        vec_ext_build_append_nil_left,
1303        vec_ext_build_append_nil_right,
1304        vec_ext_build_append_assoc,
1305        vec_ext_build_length_append,
1306        vec_ext_build_rotate_left_right_inv,
1307        vec_ext_build_rotate_length,
1308        vec_ext_build_rotate_zero,
1309        vec_ext_build_dlist_append_assoc,
1310        vec_ext_build_dlist_to_list,
1311        vec_ext_build_concat_map_id,
1312        vec_ext_build_concat_map_assoc,
1313        vec_ext_build_flatten_singleton,
1314        vec_ext_build_flatten_map,
1315        vec_ext_build_span_reconstruct,
1316        vec_ext_build_partition_reconstruct,
1317        vec_ext_build_groupby_flatten,
1318        vec_ext_build_prefix_sum_correct,
1319        vec_ext_build_parallel_prefix_equiv,
1320        vec_ext_build_fenwick_correct,
1321        vec_ext_build_rle_roundtrip,
1322        vec_ext_build_rle_length,
1323        vec_ext_build_matrix_transpose_invol,
1324        vec_ext_build_matrix_row_count,
1325        vec_ext_build_matrix_col_count,
1326    ];
1327    for builder in builders {
1328        let _ = builder(env);
1329    }
1330}
1331#[cfg(test)]
1332mod vec_extended_axiom_tests {
1333    use super::*;
1334    fn make_env() -> Environment {
1335        let mut env = Environment::new();
1336        let type1 = Expr::Sort(Level::succ(Level::zero()));
1337        env.add(Declaration::Axiom {
1338            name: Name::str("Nat"),
1339            univ_params: vec![],
1340            ty: type1.clone(),
1341        })
1342        .expect("operation should succeed");
1343        env.add(Declaration::Axiom {
1344            name: Name::str("Nat.zero"),
1345            univ_params: vec![],
1346            ty: Expr::Const(Name::str("Nat"), vec![]),
1347        })
1348        .expect("operation should succeed");
1349        env.add(Declaration::Axiom {
1350            name: Name::str("Nat.succ"),
1351            univ_params: vec![],
1352            ty: Expr::Pi(
1353                BinderInfo::Default,
1354                Name::str("n"),
1355                Node::new(Expr::Const(Name::str("Nat"), vec![])),
1356                Node::new(Expr::Const(Name::str("Nat"), vec![])),
1357            ),
1358        })
1359        .expect("operation should succeed");
1360        env
1361    }
1362    #[test]
1363    fn test_register_vec_extended_axioms_runs() {
1364        let mut env = make_env();
1365        register_vec_extended_axioms(&mut env);
1366        assert!(env.get(&Name::str("Vec.functor_map_id")).is_some());
1367        assert!(env.get(&Name::str("Vec.monad_left_id")).is_some());
1368        assert!(env.get(&Name::str("Vec.append_assoc")).is_some());
1369    }
1370    #[test]
1371    fn test_functor_laws_present() {
1372        let mut env = make_env();
1373        register_vec_extended_axioms(&mut env);
1374        assert!(env.get(&Name::str("Vec.functor_map_id")).is_some());
1375        assert!(env.get(&Name::str("Vec.functor_map_comp")).is_some());
1376    }
1377    #[test]
1378    fn test_monad_laws_present() {
1379        let mut env = make_env();
1380        register_vec_extended_axioms(&mut env);
1381        assert!(env.get(&Name::str("Vec.monad_left_id")).is_some());
1382        assert!(env.get(&Name::str("Vec.monad_right_id")).is_some());
1383        assert!(env.get(&Name::str("Vec.monad_assoc")).is_some());
1384    }
1385    #[test]
1386    fn test_applicative_laws_present() {
1387        let mut env = make_env();
1388        register_vec_extended_axioms(&mut env);
1389        assert!(env.get(&Name::str("Vec.ap_identity")).is_some());
1390        assert!(env.get(&Name::str("Vec.ap_homomorphism")).is_some());
1391        assert!(env.get(&Name::str("Vec.ap_interchange")).is_some());
1392        assert!(env.get(&Name::str("Vec.ap_composition")).is_some());
1393    }
1394    #[test]
1395    fn test_fold_laws_present() {
1396        let mut env = make_env();
1397        register_vec_extended_axioms(&mut env);
1398        assert!(env.get(&Name::str("Vec.foldr_nil")).is_some());
1399        assert!(env.get(&Name::str("Vec.foldr_cons")).is_some());
1400        assert!(env.get(&Name::str("Vec.foldl_nil")).is_some());
1401        assert!(env.get(&Name::str("Vec.foldl_cons")).is_some());
1402        assert!(env.get(&Name::str("Vec.foldl_foldr_duality")).is_some());
1403    }
1404    #[test]
1405    fn test_scan_laws_present() {
1406        let mut env = make_env();
1407        register_vec_extended_axioms(&mut env);
1408        assert!(env.get(&Name::str("Vec.scanl_nil")).is_some());
1409        assert!(env.get(&Name::str("Vec.scanl_cons")).is_some());
1410        assert!(env.get(&Name::str("Vec.scanr_nil")).is_some());
1411        assert!(env.get(&Name::str("Vec.scanr_cons")).is_some());
1412        assert!(env.get(&Name::str("Vec.scanl_last")).is_some());
1413    }
1414    #[test]
1415    fn test_sort_laws_present() {
1416        let mut env = make_env();
1417        register_vec_extended_axioms(&mut env);
1418        assert!(env.get(&Name::str("Vec.sort_is_permutation")).is_some());
1419        assert!(env.get(&Name::str("Vec.sort_is_sorted")).is_some());
1420        assert!(env
1421            .get(&Name::str("Vec.stable_sort_preserves_order"))
1422            .is_some());
1423        assert!(env.get(&Name::str("Vec.sort_idempotent")).is_some());
1424    }
1425    #[test]
1426    fn test_fusion_laws_present() {
1427        let mut env = make_env();
1428        register_vec_extended_axioms(&mut env);
1429        assert!(env.get(&Name::str("Vec.map_fusion")).is_some());
1430        assert!(env.get(&Name::str("Vec.filter_fusion")).is_some());
1431        assert!(env.get(&Name::str("Vec.map_filter_fusion")).is_some());
1432        assert!(env.get(&Name::str("Vec.fold_build_duality")).is_some());
1433    }
1434    #[test]
1435    fn test_fin_indexed_laws_present() {
1436        let mut env = make_env();
1437        register_vec_extended_axioms(&mut env);
1438        assert!(env.get(&Name::str("Vec.fin_index_get")).is_some());
1439        assert!(env.get(&Name::str("Vec.fin_index_set")).is_some());
1440        assert!(env
1441            .get(&Name::str("Vec.fin_map_preserves_length"))
1442            .is_some());
1443    }
1444    #[test]
1445    fn test_reverse_laws_present() {
1446        let mut env = make_env();
1447        register_vec_extended_axioms(&mut env);
1448        assert!(env.get(&Name::str("Vec.reverse_involutive")).is_some());
1449        assert!(env.get(&Name::str("Vec.reverse_append")).is_some());
1450        assert!(env.get(&Name::str("Vec.reverse_map")).is_some());
1451    }
1452    #[test]
1453    fn test_take_drop_laws_present() {
1454        let mut env = make_env();
1455        register_vec_extended_axioms(&mut env);
1456        assert!(env.get(&Name::str("Vec.take_drop_reconstruct")).is_some());
1457        assert!(env.get(&Name::str("Vec.take_length")).is_some());
1458        assert!(env.get(&Name::str("Vec.drop_length")).is_some());
1459    }
1460    #[test]
1461    fn test_zip_laws_present() {
1462        let mut env = make_env();
1463        register_vec_extended_axioms(&mut env);
1464        assert!(env.get(&Name::str("Vec.zip_length")).is_some());
1465        assert!(env.get(&Name::str("Vec.unzip_zip")).is_some());
1466        assert!(env.get(&Name::str("Vec.zip_map")).is_some());
1467    }
1468    #[test]
1469    fn test_chunking_laws_present() {
1470        let mut env = make_env();
1471        register_vec_extended_axioms(&mut env);
1472        assert!(env.get(&Name::str("Vec.chunks_flatten")).is_some());
1473        assert!(env.get(&Name::str("Vec.chunks_all_size")).is_some());
1474        assert!(env.get(&Name::str("Vec.chunks_count")).is_some());
1475    }
1476    #[test]
1477    fn test_free_monoid_laws_present() {
1478        let mut env = make_env();
1479        register_vec_extended_axioms(&mut env);
1480        assert!(env.get(&Name::str("Vec.append_nil_left")).is_some());
1481        assert!(env.get(&Name::str("Vec.append_nil_right")).is_some());
1482        assert!(env.get(&Name::str("Vec.append_assoc")).is_some());
1483        assert!(env.get(&Name::str("Vec.length_append")).is_some());
1484    }
1485    #[test]
1486    fn test_rotation_laws_present() {
1487        let mut env = make_env();
1488        register_vec_extended_axioms(&mut env);
1489        assert!(env
1490            .get(&Name::str("Vec.rotate_left_right_inverse"))
1491            .is_some());
1492        assert!(env.get(&Name::str("Vec.rotate_length")).is_some());
1493        assert!(env.get(&Name::str("Vec.rotate_zero")).is_some());
1494    }
1495    #[test]
1496    fn test_dlist_laws_present() {
1497        let mut env = make_env();
1498        register_vec_extended_axioms(&mut env);
1499        assert!(env.get(&Name::str("Vec.dlist_append_assoc")).is_some());
1500        assert!(env.get(&Name::str("Vec.dlist_to_list_preserves")).is_some());
1501    }
1502    #[test]
1503    fn test_concat_map_laws_present() {
1504        let mut env = make_env();
1505        register_vec_extended_axioms(&mut env);
1506        assert!(env.get(&Name::str("Vec.concat_map_id")).is_some());
1507        assert!(env.get(&Name::str("Vec.concat_map_assoc")).is_some());
1508        assert!(env.get(&Name::str("Vec.flatten_singleton")).is_some());
1509        assert!(env.get(&Name::str("Vec.flatten_map")).is_some());
1510    }
1511    #[test]
1512    fn test_span_partition_laws_present() {
1513        let mut env = make_env();
1514        register_vec_extended_axioms(&mut env);
1515        assert!(env.get(&Name::str("Vec.span_reconstruct")).is_some());
1516        assert!(env.get(&Name::str("Vec.partition_reconstruct")).is_some());
1517        assert!(env.get(&Name::str("Vec.groupBy_flatten")).is_some());
1518    }
1519    #[test]
1520    fn test_parallel_prefix_laws_present() {
1521        let mut env = make_env();
1522        register_vec_extended_axioms(&mut env);
1523        assert!(env.get(&Name::str("Vec.prefix_sum_correct")).is_some());
1524        assert!(env
1525            .get(&Name::str("Vec.parallel_prefix_sequential_equiv"))
1526            .is_some());
1527        assert!(env
1528            .get(&Name::str("Vec.fenwick_prefix_sum_correct"))
1529            .is_some());
1530    }
1531    #[test]
1532    fn test_rle_laws_present() {
1533        let mut env = make_env();
1534        register_vec_extended_axioms(&mut env);
1535        assert!(env.get(&Name::str("Vec.rle_decode_encode")).is_some());
1536        assert!(env.get(&Name::str("Vec.rle_length")).is_some());
1537    }
1538    #[test]
1539    fn test_matrix_laws_present() {
1540        let mut env = make_env();
1541        register_vec_extended_axioms(&mut env);
1542        assert!(env
1543            .get(&Name::str("Vec.matrix_transpose_involutive"))
1544            .is_some());
1545        assert!(env.get(&Name::str("Vec.matrix_row_count")).is_some());
1546        assert!(env.get(&Name::str("Vec.matrix_col_count")).is_some());
1547    }
1548    #[test]
1549    fn test_circular_buffer_basic() {
1550        let buf: CircularBuffer<i32> = CircularBuffer::new(8);
1551        assert_eq!(buf.capacity(), 8);
1552        assert!(buf.is_empty());
1553        assert!(!buf.is_full());
1554    }
1555    #[test]
1556    fn test_dlist_singleton_to_vec() {
1557        let d = DList::singleton(42i32);
1558        assert_eq!(d.to_vec(), vec![42]);
1559    }
1560    #[test]
1561    fn test_prefix_scan_inclusive() {
1562        let ps = PrefixScan::inclusive(vec![1, 3, 6, 10]);
1563        assert_eq!(ps.values(), &[1, 3, 6, 10]);
1564        assert!(ps.inclusive);
1565        assert_eq!(ps.len(), 4);
1566    }
1567    #[test]
1568    fn test_fenwick_tree_basic() {
1569        let mut ft = FenwickTree::new(5);
1570        ft.update(1, 3);
1571        ft.update(2, 2);
1572        ft.update(3, 7);
1573        assert_eq!(ft.query(1), 3);
1574        assert_eq!(ft.query(2), 5);
1575        assert_eq!(ft.query(3), 12);
1576    }
1577    #[test]
1578    fn test_sparse_vec_get_set() {
1579        let mut sv: SparseVec<i32> = SparseVec::new(10, 0);
1580        assert_eq!(*sv.get(5), 0);
1581        sv.set(5, 42);
1582        assert_eq!(*sv.get(5), 42);
1583        assert_eq!(*sv.get(3), 0);
1584        assert_eq!(sv.nnz(), 1);
1585    }
1586    #[test]
1587    fn test_all_35_plus_vec_axioms_registered() {
1588        let mut env = make_env();
1589        register_vec_extended_axioms(&mut env);
1590        let axiom_names = [
1591            "Vec.functor_map_id",
1592            "Vec.functor_map_comp",
1593            "Vec.monad_left_id",
1594            "Vec.monad_right_id",
1595            "Vec.monad_assoc",
1596            "Vec.ap_identity",
1597            "Vec.ap_homomorphism",
1598            "Vec.ap_interchange",
1599            "Vec.ap_composition",
1600            "Vec.foldr_nil",
1601            "Vec.foldr_cons",
1602            "Vec.foldl_nil",
1603            "Vec.foldl_cons",
1604            "Vec.foldl_foldr_duality",
1605            "Vec.scanl_nil",
1606            "Vec.scanl_cons",
1607            "Vec.scanr_nil",
1608            "Vec.scanr_cons",
1609            "Vec.scanl_last",
1610            "Vec.sort_is_permutation",
1611            "Vec.sort_is_sorted",
1612            "Vec.stable_sort_preserves_order",
1613            "Vec.sort_idempotent",
1614            "Vec.map_fusion",
1615            "Vec.filter_fusion",
1616            "Vec.map_filter_fusion",
1617            "Vec.fold_build_duality",
1618            "Vec.fin_index_get",
1619            "Vec.fin_index_set",
1620            "Vec.fin_map_preserves_length",
1621            "Vec.reverse_involutive",
1622            "Vec.reverse_append",
1623            "Vec.reverse_map",
1624            "Vec.take_drop_reconstruct",
1625            "Vec.take_length",
1626        ];
1627        let mut found = 0usize;
1628        for name in &axiom_names {
1629            if env.get(&Name::str(*name)).is_some() {
1630                found += 1;
1631            }
1632        }
1633        assert!(found >= 35, "Expected at least 35 axioms, found {}", found);
1634    }
1635}