1use crate::{Expr, Level, Name};
6use std::collections::{HashMap, HashSet};
7
8use super::functions::*;
9
10pub struct ProofTerm;
12impl ProofTerm {
13 pub fn is_proof(term: &Expr, prop: &Expr) -> bool {
19 if Self::could_be_prop(prop) {
20 Self::is_well_formed(term)
21 } else {
22 false
23 }
24 }
25 pub fn could_be_prop(ty: &Expr) -> bool {
29 match ty {
30 Expr::Sort(Level::Zero) => true,
31 Expr::Pi(_, _, _, body) => Self::could_be_prop(body),
32 Expr::Const(_, _) => true,
33 Expr::App(_, _) => true,
34 _ => false,
35 }
36 }
37 pub fn is_sort_zero(ty: &Expr) -> bool {
39 matches!(ty, Expr::Sort(Level::Zero))
40 }
41 pub fn get_proposition(term: &Expr) -> Option<Expr> {
45 match term {
46 Expr::Lam(_, _, ty, _) if Self::could_be_prop(ty) => Some((**ty).clone()),
47 _ => None,
48 }
49 }
50 pub fn is_constructive(term: &Expr) -> bool {
57 let deps = collect_axiom_deps(term);
58 !deps
59 .iter()
60 .any(|name: &Name| CLASSICAL_AXIOMS.contains(&name.to_string().as_str()))
61 }
62 pub fn collect_constants(term: &Expr) -> HashSet<Name> {
64 let mut result = HashSet::new();
65 collect_constants_impl(term, &mut result);
66 result
67 }
68 pub fn size(term: &Expr) -> usize {
70 match term {
71 Expr::BVar(_) | Expr::FVar(_) | Expr::Const(_, _) | Expr::Sort(_) | Expr::Lit(_) => 1,
72 Expr::App(f, a) => 1 + Self::size(f) + Self::size(a),
73 Expr::Lam(_, _, ty, body) => 1 + Self::size(ty) + Self::size(body),
74 Expr::Pi(_, _, ty, body) => 1 + Self::size(ty) + Self::size(body),
75 Expr::Let(_, ty, val, body) => 1 + Self::size(ty) + Self::size(val) + Self::size(body),
76 Expr::Proj(_, _, e) => 1 + Self::size(e),
77 }
78 }
79 pub fn depth(term: &Expr) -> usize {
81 match term {
82 Expr::BVar(_) | Expr::FVar(_) | Expr::Const(_, _) | Expr::Sort(_) | Expr::Lit(_) => 0,
83 Expr::App(f, a) => 1 + Self::depth(f).max(Self::depth(a)),
84 Expr::Lam(_, _, ty, body) => 1 + Self::depth(ty).max(Self::depth(body)),
85 Expr::Pi(_, _, ty, body) => 1 + Self::depth(ty).max(Self::depth(body)),
86 Expr::Let(_, ty, val, body) => {
87 1 + Self::depth(ty).max(Self::depth(val)).max(Self::depth(body))
88 }
89 Expr::Proj(_, _, e) => 1 + Self::depth(e),
90 }
91 }
92 fn is_well_formed(term: &Expr) -> bool {
94 match term {
95 Expr::BVar(_) | Expr::FVar(_) | Expr::Const(_, _) | Expr::Sort(_) | Expr::Lit(_) => {
96 true
97 }
98 Expr::App(f, a) => Self::is_well_formed(f) && Self::is_well_formed(a),
99 Expr::Lam(_, _, ty, body) => Self::is_well_formed(ty) && Self::is_well_formed(body),
100 Expr::Pi(_, _, ty, body) => Self::is_well_formed(ty) && Self::is_well_formed(body),
101 Expr::Let(_, ty, val, body) => {
102 Self::is_well_formed(ty) && Self::is_well_formed(val) && Self::is_well_formed(body)
103 }
104 Expr::Proj(_, _, e) => Self::is_well_formed(e),
105 }
106 }
107 pub fn same_proposition_structure(p1: &Expr, p2: &Expr) -> bool {
112 match (p1, p2) {
113 (Expr::Sort(l1), Expr::Sort(l2)) => l1 == l2,
114 (Expr::Const(n1, _), Expr::Const(n2, _)) => n1 == n2,
115 (Expr::App(f1, a1), Expr::App(f2, a2)) => {
116 Self::same_proposition_structure(f1, f2) && Self::same_proposition_structure(a1, a2)
117 }
118 (Expr::Pi(_, _, ty1, body1), Expr::Pi(_, _, ty2, body2)) => {
119 Self::same_proposition_structure(ty1, ty2)
120 && Self::same_proposition_structure(body1, body2)
121 }
122 _ => p1 == p2,
123 }
124 }
125}
126#[allow(dead_code)]
128pub struct FlatSubstitution {
129 pairs: Vec<(String, String)>,
130}
131#[allow(dead_code)]
132impl FlatSubstitution {
133 pub fn new() -> Self {
135 Self { pairs: Vec::new() }
136 }
137 pub fn add(&mut self, from: impl Into<String>, to: impl Into<String>) {
139 self.pairs.push((from.into(), to.into()));
140 }
141 pub fn apply(&self, s: &str) -> String {
143 let mut result = s.to_string();
144 for (from, to) in &self.pairs {
145 result = result.replace(from.as_str(), to.as_str());
146 }
147 result
148 }
149 pub fn len(&self) -> usize {
151 self.pairs.len()
152 }
153 pub fn is_empty(&self) -> bool {
155 self.pairs.is_empty()
156 }
157}
158#[allow(dead_code)]
160pub struct LabelSet {
161 labels: Vec<String>,
162}
163#[allow(dead_code)]
164impl LabelSet {
165 pub fn new() -> Self {
167 Self { labels: Vec::new() }
168 }
169 pub fn add(&mut self, label: impl Into<String>) {
171 let s = label.into();
172 if !self.labels.contains(&s) {
173 self.labels.push(s);
174 }
175 }
176 pub fn has(&self, label: &str) -> bool {
178 self.labels.iter().any(|l| l == label)
179 }
180 pub fn count(&self) -> usize {
182 self.labels.len()
183 }
184 pub fn all(&self) -> &[String] {
186 &self.labels
187 }
188}
189#[allow(dead_code)]
191pub struct SlidingSum {
192 window: Vec<f64>,
193 capacity: usize,
194 pos: usize,
195 sum: f64,
196 count: usize,
197}
198#[allow(dead_code)]
199impl SlidingSum {
200 pub fn new(capacity: usize) -> Self {
202 Self {
203 window: vec![0.0; capacity],
204 capacity,
205 pos: 0,
206 sum: 0.0,
207 count: 0,
208 }
209 }
210 pub fn push(&mut self, val: f64) {
212 let oldest = self.window[self.pos];
213 self.sum -= oldest;
214 self.sum += val;
215 self.window[self.pos] = val;
216 self.pos = (self.pos + 1) % self.capacity;
217 if self.count < self.capacity {
218 self.count += 1;
219 }
220 }
221 pub fn sum(&self) -> f64 {
223 self.sum
224 }
225 pub fn mean(&self) -> Option<f64> {
227 if self.count == 0 {
228 None
229 } else {
230 Some(self.sum / self.count as f64)
231 }
232 }
233 pub fn count(&self) -> usize {
235 self.count
236 }
237}
238#[allow(dead_code)]
240pub struct PrefixCounter {
241 children: std::collections::HashMap<char, PrefixCounter>,
242 count: usize,
243}
244#[allow(dead_code)]
245impl PrefixCounter {
246 pub fn new() -> Self {
248 Self {
249 children: std::collections::HashMap::new(),
250 count: 0,
251 }
252 }
253 pub fn record(&mut self, s: &str) {
255 self.count += 1;
256 let mut node = self;
257 for c in s.chars() {
258 node = node.children.entry(c).or_default();
259 node.count += 1;
260 }
261 }
262 pub fn count_with_prefix(&self, prefix: &str) -> usize {
264 let mut node = self;
265 for c in prefix.chars() {
266 match node.children.get(&c) {
267 Some(n) => node = n,
268 None => return 0,
269 }
270 }
271 node.count
272 }
273}
274#[allow(dead_code)]
276pub struct SmallMap<K: Ord + Clone, V: Clone> {
277 entries: Vec<(K, V)>,
278}
279#[allow(dead_code)]
280impl<K: Ord + Clone, V: Clone> SmallMap<K, V> {
281 pub fn new() -> Self {
283 Self {
284 entries: Vec::new(),
285 }
286 }
287 pub fn insert(&mut self, key: K, val: V) {
289 match self.entries.binary_search_by_key(&&key, |(k, _)| k) {
290 Ok(i) => self.entries[i].1 = val,
291 Err(i) => self.entries.insert(i, (key, val)),
292 }
293 }
294 pub fn get(&self, key: &K) -> Option<&V> {
296 self.entries
297 .binary_search_by_key(&key, |(k, _)| k)
298 .ok()
299 .map(|i| &self.entries[i].1)
300 }
301 pub fn len(&self) -> usize {
303 self.entries.len()
304 }
305 pub fn is_empty(&self) -> bool {
307 self.entries.is_empty()
308 }
309 pub fn keys(&self) -> Vec<&K> {
311 self.entries.iter().map(|(k, _)| k).collect()
312 }
313 pub fn values(&self) -> Vec<&V> {
315 self.entries.iter().map(|(_, v)| v).collect()
316 }
317}
318#[allow(dead_code)]
320pub struct WindowIterator<'a, T> {
321 pub(super) data: &'a [T],
322 pub(super) pos: usize,
323 pub(super) window: usize,
324}
325#[allow(dead_code)]
326impl<'a, T> WindowIterator<'a, T> {
327 pub fn new(data: &'a [T], window: usize) -> Self {
329 Self {
330 data,
331 pos: 0,
332 window,
333 }
334 }
335}
336#[allow(dead_code)]
338pub struct StatSummary {
339 count: u64,
340 sum: f64,
341 min: f64,
342 max: f64,
343}
344#[allow(dead_code)]
345impl StatSummary {
346 pub fn new() -> Self {
348 Self {
349 count: 0,
350 sum: 0.0,
351 min: f64::INFINITY,
352 max: f64::NEG_INFINITY,
353 }
354 }
355 pub fn record(&mut self, val: f64) {
357 self.count += 1;
358 self.sum += val;
359 if val < self.min {
360 self.min = val;
361 }
362 if val > self.max {
363 self.max = val;
364 }
365 }
366 pub fn mean(&self) -> Option<f64> {
368 if self.count == 0 {
369 None
370 } else {
371 Some(self.sum / self.count as f64)
372 }
373 }
374 pub fn min(&self) -> Option<f64> {
376 if self.count == 0 {
377 None
378 } else {
379 Some(self.min)
380 }
381 }
382 pub fn max(&self) -> Option<f64> {
384 if self.count == 0 {
385 None
386 } else {
387 Some(self.max)
388 }
389 }
390 pub fn count(&self) -> u64 {
392 self.count
393 }
394}
395#[allow(dead_code)]
397#[derive(Debug, Clone, Default)]
398pub struct ProofState {
399 pub obligations: Vec<ProofObligation>,
401}
402impl ProofState {
403 #[allow(dead_code)]
405 pub fn new() -> Self {
406 Self::default()
407 }
408 #[allow(dead_code)]
410 pub fn add_obligation(&mut self, label: impl Into<String>, proposition: Expr) {
411 self.obligations
412 .push(ProofObligation::new(label, proposition));
413 }
414 #[allow(dead_code)]
416 pub fn remaining(&self) -> usize {
417 self.obligations
418 .iter()
419 .filter(|o| !o.is_discharged())
420 .count()
421 }
422 #[allow(dead_code)]
424 pub fn is_complete(&self) -> bool {
425 self.remaining() == 0
426 }
427 #[allow(dead_code)]
431 pub fn discharge_next(&mut self, proof: Expr) -> bool {
432 for obl in self.obligations.iter_mut() {
433 if !obl.discharged {
434 obl.discharge(proof);
435 return true;
436 }
437 }
438 false
439 }
440 #[allow(dead_code)]
442 pub fn open_obligations(&self) -> Vec<&ProofObligation> {
443 self.obligations
444 .iter()
445 .filter(|o| !o.is_discharged())
446 .collect()
447 }
448}
449#[allow(dead_code)]
451pub struct SimpleDag {
452 edges: Vec<Vec<usize>>,
454}
455#[allow(dead_code)]
456impl SimpleDag {
457 pub fn new(n: usize) -> Self {
459 Self {
460 edges: vec![Vec::new(); n],
461 }
462 }
463 pub fn add_edge(&mut self, from: usize, to: usize) {
465 if from < self.edges.len() {
466 self.edges[from].push(to);
467 }
468 }
469 pub fn successors(&self, node: usize) -> &[usize] {
471 self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
472 }
473 pub fn can_reach(&self, from: usize, to: usize) -> bool {
475 let mut visited = vec![false; self.edges.len()];
476 self.dfs(from, to, &mut visited)
477 }
478 fn dfs(&self, cur: usize, target: usize, visited: &mut Vec<bool>) -> bool {
479 if cur == target {
480 return true;
481 }
482 if cur >= visited.len() || visited[cur] {
483 return false;
484 }
485 visited[cur] = true;
486 for &next in self.successors(cur) {
487 if self.dfs(next, target, visited) {
488 return true;
489 }
490 }
491 false
492 }
493 pub fn topological_sort(&self) -> Option<Vec<usize>> {
495 let n = self.edges.len();
496 let mut in_degree = vec![0usize; n];
497 for succs in &self.edges {
498 for &s in succs {
499 if s < n {
500 in_degree[s] += 1;
501 }
502 }
503 }
504 let mut queue: std::collections::VecDeque<usize> =
505 (0..n).filter(|&i| in_degree[i] == 0).collect();
506 let mut order = Vec::new();
507 while let Some(node) = queue.pop_front() {
508 order.push(node);
509 for &s in self.successors(node) {
510 if s < n {
511 in_degree[s] -= 1;
512 if in_degree[s] == 0 {
513 queue.push_back(s);
514 }
515 }
516 }
517 }
518 if order.len() == n {
519 Some(order)
520 } else {
521 None
522 }
523 }
524 pub fn num_nodes(&self) -> usize {
526 self.edges.len()
527 }
528}
529#[allow(dead_code)]
531pub struct TransitiveClosure {
532 adj: Vec<Vec<usize>>,
533 n: usize,
534}
535#[allow(dead_code)]
536impl TransitiveClosure {
537 pub fn new(n: usize) -> Self {
539 Self {
540 adj: vec![Vec::new(); n],
541 n,
542 }
543 }
544 pub fn add_edge(&mut self, from: usize, to: usize) {
546 if from < self.n {
547 self.adj[from].push(to);
548 }
549 }
550 pub fn reachable_from(&self, start: usize) -> Vec<usize> {
552 let mut visited = vec![false; self.n];
553 let mut queue = std::collections::VecDeque::new();
554 queue.push_back(start);
555 while let Some(node) = queue.pop_front() {
556 if node >= self.n || visited[node] {
557 continue;
558 }
559 visited[node] = true;
560 for &next in &self.adj[node] {
561 queue.push_back(next);
562 }
563 }
564 (0..self.n).filter(|&i| visited[i]).collect()
565 }
566 pub fn can_reach(&self, from: usize, to: usize) -> bool {
568 self.reachable_from(from).contains(&to)
569 }
570}
571#[allow(dead_code)]
573pub struct PathBuf {
574 components: Vec<String>,
575}
576#[allow(dead_code)]
577impl PathBuf {
578 pub fn new() -> Self {
580 Self {
581 components: Vec::new(),
582 }
583 }
584 pub fn push(&mut self, comp: impl Into<String>) {
586 self.components.push(comp.into());
587 }
588 pub fn pop(&mut self) {
590 self.components.pop();
591 }
592 pub fn as_str(&self) -> String {
594 self.components.join("/")
595 }
596 pub fn depth(&self) -> usize {
598 self.components.len()
599 }
600 pub fn clear(&mut self) {
602 self.components.clear();
603 }
604}
605#[allow(dead_code)]
607pub struct RewriteRuleSet {
608 rules: Vec<RewriteRule>,
609}
610#[allow(dead_code)]
611impl RewriteRuleSet {
612 pub fn new() -> Self {
614 Self { rules: Vec::new() }
615 }
616 pub fn add(&mut self, rule: RewriteRule) {
618 self.rules.push(rule);
619 }
620 pub fn len(&self) -> usize {
622 self.rules.len()
623 }
624 pub fn is_empty(&self) -> bool {
626 self.rules.is_empty()
627 }
628 pub fn conditional_rules(&self) -> Vec<&RewriteRule> {
630 self.rules.iter().filter(|r| r.conditional).collect()
631 }
632 pub fn unconditional_rules(&self) -> Vec<&RewriteRule> {
634 self.rules.iter().filter(|r| !r.conditional).collect()
635 }
636 pub fn get(&self, name: &str) -> Option<&RewriteRule> {
638 self.rules.iter().find(|r| r.name == name)
639 }
640}
641#[allow(dead_code)]
643#[derive(Debug, Clone, PartialEq, Eq)]
644pub enum ProofComplexity {
645 Atomic,
647 Abstraction,
649 Application,
651 LetBinding,
653 Projection,
655 Composite,
657}
658pub struct ProofAnalyzer;
660impl ProofAnalyzer {
661 pub fn is_constructive(term: &Expr) -> bool {
663 !Self::uses_classical(term)
664 }
665 pub fn uses_classical(term: &Expr) -> bool {
667 match term {
668 Expr::Const(n, _) => {
669 let s = n.to_string();
670 s == "Classical.choice" || s == "Classical.em" || s == "propext"
671 }
672 Expr::App(f, a) => Self::uses_classical(f) || Self::uses_classical(a),
673 Expr::Lam(_, _, ty, body) | Expr::Pi(_, _, ty, body) => {
674 Self::uses_classical(ty) || Self::uses_classical(body)
675 }
676 Expr::Let(_, ty, val, body) => {
677 Self::uses_classical(ty) || Self::uses_classical(val) || Self::uses_classical(body)
678 }
679 _ => false,
680 }
681 }
682 pub fn count_applications(term: &Expr) -> usize {
684 match term {
685 Expr::App(f, a) => 1 + Self::count_applications(f) + Self::count_applications(a),
686 Expr::Lam(_, _, ty, body) | Expr::Pi(_, _, ty, body) => {
687 Self::count_applications(ty) + Self::count_applications(body)
688 }
689 Expr::Let(_, ty, val, body) => {
690 Self::count_applications(ty)
691 + Self::count_applications(val)
692 + Self::count_applications(body)
693 }
694 _ => 0,
695 }
696 }
697}
698#[allow(dead_code)]
703pub struct ProofNormalizer;
704impl ProofNormalizer {
705 #[allow(dead_code)]
710 pub fn beta_reduce(term: &Expr) -> Expr {
711 match term {
712 Expr::App(f, arg) => {
713 let f_reduced = Self::beta_reduce(f);
714 let arg_reduced = Self::beta_reduce(arg);
715 if let Expr::Lam(_, _, _, body) = f_reduced {
716 let substituted = Self::subst_bvar(*body, 0, &arg_reduced);
717 Self::beta_reduce(&substituted)
718 } else {
719 Expr::App(Box::new(f_reduced), Box::new(arg_reduced))
720 }
721 }
722 Expr::Lam(bk, n, ty, body) => {
723 let ty_red = Self::beta_reduce(ty);
724 let body_red = Self::beta_reduce(body);
725 Expr::Lam(*bk, n.clone(), Box::new(ty_red), Box::new(body_red))
726 }
727 Expr::Pi(bk, n, ty, body) => {
728 let ty_red = Self::beta_reduce(ty);
729 let body_red = Self::beta_reduce(body);
730 Expr::Pi(*bk, n.clone(), Box::new(ty_red), Box::new(body_red))
731 }
732 Expr::Let(_n, _ty, val, body) => {
733 let val_red = Self::beta_reduce(val);
734 let body_subst = Self::subst_bvar(*body.clone(), 0, &val_red);
735 Self::beta_reduce(&body_subst)
736 }
737 Expr::Proj(idx, n, e) => Expr::Proj(idx.clone(), *n, Box::new(Self::beta_reduce(e))),
738 other => other.clone(),
739 }
740 }
741 #[allow(dead_code)]
745 pub fn subst_bvar(term: Expr, depth: u32, replacement: &Expr) -> Expr {
746 match term {
747 Expr::BVar(i) => {
748 if i == depth {
749 replacement.clone()
750 } else if i > depth {
751 Expr::BVar(i - 1)
752 } else {
753 Expr::BVar(i)
754 }
755 }
756 Expr::App(f, a) => Expr::App(
757 Box::new(Self::subst_bvar(*f, depth, replacement)),
758 Box::new(Self::subst_bvar(*a, depth, replacement)),
759 ),
760 Expr::Lam(bk, n, ty, body) => Expr::Lam(
761 bk,
762 n,
763 Box::new(Self::subst_bvar(*ty, depth, replacement)),
764 Box::new(Self::subst_bvar(*body, depth + 1, replacement)),
765 ),
766 Expr::Pi(bk, n, ty, body) => Expr::Pi(
767 bk,
768 n,
769 Box::new(Self::subst_bvar(*ty, depth, replacement)),
770 Box::new(Self::subst_bvar(*body, depth + 1, replacement)),
771 ),
772 Expr::Let(n, ty, val, body) => Expr::Let(
773 n,
774 Box::new(Self::subst_bvar(*ty, depth, replacement)),
775 Box::new(Self::subst_bvar(*val, depth, replacement)),
776 Box::new(Self::subst_bvar(*body, depth + 1, replacement)),
777 ),
778 Expr::Proj(idx, n, e) => {
779 Expr::Proj(idx, n, Box::new(Self::subst_bvar(*e, depth, replacement)))
780 }
781 other => other,
782 }
783 }
784 #[allow(dead_code)]
786 pub fn count_redexes(term: &Expr) -> usize {
787 match term {
788 Expr::App(f, a) => {
789 let in_f = Self::count_redexes(f);
790 let in_a = Self::count_redexes(a);
791 let is_redex = matches!(f.as_ref(), Expr::Lam(_, _, _, _));
792 in_f + in_a + if is_redex { 1 } else { 0 }
793 }
794 Expr::Lam(_, _, ty, body) => Self::count_redexes(ty) + Self::count_redexes(body),
795 Expr::Pi(_, _, ty, body) => Self::count_redexes(ty) + Self::count_redexes(body),
796 Expr::Let(_, ty, val, body) => {
797 Self::count_redexes(ty) + Self::count_redexes(val) + Self::count_redexes(body)
798 }
799 Expr::Proj(_, _, e) => Self::count_redexes(e),
800 _ => 0,
801 }
802 }
803 #[allow(dead_code)]
805 pub fn is_beta_normal(term: &Expr) -> bool {
806 Self::count_redexes(term) == 0
807 }
808}
809#[allow(dead_code)]
814#[derive(Clone, Debug)]
815pub struct ProofSkeleton {
816 pub term: Expr,
818 pub ty: Expr,
820 pub holes: Vec<Name>,
822}
823impl ProofSkeleton {
824 #[allow(dead_code)]
826 pub fn new(term: Expr, ty: Expr) -> Self {
827 let holes = Self::collect_holes(&term);
828 Self { term, ty, holes }
829 }
830 fn collect_holes(term: &Expr) -> Vec<Name> {
832 let mut holes = Vec::new();
833 Self::collect_holes_rec(term, &mut holes);
834 holes
835 }
836 fn collect_holes_rec(term: &Expr, holes: &mut Vec<Name>) {
837 match term {
838 Expr::Const(n, _) if n.to_string().contains("sorry") => {
839 holes.push(n.clone());
840 }
841 Expr::App(f, a) => {
842 Self::collect_holes_rec(f, holes);
843 Self::collect_holes_rec(a, holes);
844 }
845 Expr::Lam(_, _, ty, body) | Expr::Pi(_, _, ty, body) => {
846 Self::collect_holes_rec(ty, holes);
847 Self::collect_holes_rec(body, holes);
848 }
849 Expr::Let(_, ty, val, body) => {
850 Self::collect_holes_rec(ty, holes);
851 Self::collect_holes_rec(val, holes);
852 Self::collect_holes_rec(body, holes);
853 }
854 _ => {}
855 }
856 }
857 #[allow(dead_code)]
859 pub fn is_complete(&self) -> bool {
860 self.holes.is_empty()
861 }
862 #[allow(dead_code)]
864 pub fn num_holes(&self) -> usize {
865 self.holes.len()
866 }
867}
868#[allow(dead_code)]
870pub struct TransformStat {
871 before: StatSummary,
872 after: StatSummary,
873}
874#[allow(dead_code)]
875impl TransformStat {
876 pub fn new() -> Self {
878 Self {
879 before: StatSummary::new(),
880 after: StatSummary::new(),
881 }
882 }
883 pub fn record_before(&mut self, v: f64) {
885 self.before.record(v);
886 }
887 pub fn record_after(&mut self, v: f64) {
889 self.after.record(v);
890 }
891 pub fn mean_ratio(&self) -> Option<f64> {
893 let b = self.before.mean()?;
894 let a = self.after.mean()?;
895 if b.abs() < f64::EPSILON {
896 return None;
897 }
898 Some(a / b)
899 }
900}
901#[allow(dead_code)]
903pub struct NonEmptyVec<T> {
904 head: T,
905 tail: Vec<T>,
906}
907#[allow(dead_code)]
908impl<T> NonEmptyVec<T> {
909 pub fn singleton(val: T) -> Self {
911 Self {
912 head: val,
913 tail: Vec::new(),
914 }
915 }
916 pub fn push(&mut self, val: T) {
918 self.tail.push(val);
919 }
920 pub fn first(&self) -> &T {
922 &self.head
923 }
924 pub fn last(&self) -> &T {
926 self.tail.last().unwrap_or(&self.head)
927 }
928 pub fn len(&self) -> usize {
930 1 + self.tail.len()
931 }
932 pub fn is_empty(&self) -> bool {
934 self.len() == 0
935 }
936 pub fn to_vec(&self) -> Vec<&T> {
938 let mut v = vec![&self.head];
939 v.extend(self.tail.iter());
940 v
941 }
942}
943#[allow(dead_code)]
945pub struct StringPool {
946 free: Vec<String>,
947}
948#[allow(dead_code)]
949impl StringPool {
950 pub fn new() -> Self {
952 Self { free: Vec::new() }
953 }
954 pub fn take(&mut self) -> String {
956 self.free.pop().unwrap_or_default()
957 }
958 pub fn give(&mut self, mut s: String) {
960 s.clear();
961 self.free.push(s);
962 }
963 pub fn free_count(&self) -> usize {
965 self.free.len()
966 }
967}
968#[allow(dead_code)]
970#[allow(missing_docs)]
971pub struct RewriteRule {
972 pub name: String,
974 pub lhs: String,
976 pub rhs: String,
978 pub conditional: bool,
980}
981#[allow(dead_code)]
982impl RewriteRule {
983 pub fn unconditional(
985 name: impl Into<String>,
986 lhs: impl Into<String>,
987 rhs: impl Into<String>,
988 ) -> Self {
989 Self {
990 name: name.into(),
991 lhs: lhs.into(),
992 rhs: rhs.into(),
993 conditional: false,
994 }
995 }
996 pub fn conditional(
998 name: impl Into<String>,
999 lhs: impl Into<String>,
1000 rhs: impl Into<String>,
1001 ) -> Self {
1002 Self {
1003 name: name.into(),
1004 lhs: lhs.into(),
1005 rhs: rhs.into(),
1006 conditional: true,
1007 }
1008 }
1009 pub fn display(&self) -> String {
1011 format!("{}: {} → {}", self.name, self.lhs, self.rhs)
1012 }
1013}
1014#[allow(dead_code)]
1016pub struct RawFnPtr {
1017 ptr: usize,
1019 arity: usize,
1020 name: String,
1021}
1022#[allow(dead_code)]
1023impl RawFnPtr {
1024 pub fn new(ptr: usize, arity: usize, name: impl Into<String>) -> Self {
1026 Self {
1027 ptr,
1028 arity,
1029 name: name.into(),
1030 }
1031 }
1032 pub fn arity(&self) -> usize {
1034 self.arity
1035 }
1036 pub fn name(&self) -> &str {
1038 &self.name
1039 }
1040 pub fn raw(&self) -> usize {
1042 self.ptr
1043 }
1044}
1045#[allow(dead_code)]
1047pub struct WriteOnce<T> {
1048 value: std::cell::Cell<Option<T>>,
1049}
1050#[allow(dead_code)]
1051impl<T: Copy> WriteOnce<T> {
1052 pub fn new() -> Self {
1054 Self {
1055 value: std::cell::Cell::new(None),
1056 }
1057 }
1058 pub fn write(&self, val: T) -> bool {
1060 if self.value.get().is_some() {
1061 return false;
1062 }
1063 self.value.set(Some(val));
1064 true
1065 }
1066 pub fn read(&self) -> Option<T> {
1068 self.value.get()
1069 }
1070 pub fn is_written(&self) -> bool {
1072 self.value.get().is_some()
1073 }
1074}
1075#[allow(dead_code)]
1077#[derive(Debug, Clone)]
1078pub struct ProofAnalysis {
1079 pub size: usize,
1081 pub depth: usize,
1083 pub lambda_count: usize,
1085 pub app_count: usize,
1087 pub let_count: usize,
1089 pub fvar_count: usize,
1091 pub bvar_count: usize,
1093 pub uses_classical: bool,
1095 pub constants: HashSet<Name>,
1097}
1098impl ProofAnalysis {
1099 #[allow(dead_code)]
1101 pub fn analyse(term: &Expr) -> Self {
1102 let mut analysis = ProofAnalysis {
1103 size: 0,
1104 depth: 0,
1105 lambda_count: 0,
1106 app_count: 0,
1107 let_count: 0,
1108 fvar_count: 0,
1109 bvar_count: 0,
1110 uses_classical: false,
1111 constants: HashSet::new(),
1112 };
1113 analysis.visit(term, 0);
1114 analysis.depth = ProofTerm::depth(term);
1115 analysis.uses_classical = !ProofTerm::is_constructive(term);
1116 analysis
1117 }
1118 fn visit(&mut self, term: &Expr, _depth: usize) {
1119 self.size += 1;
1120 match term {
1121 Expr::BVar(_) => {
1122 self.bvar_count += 1;
1123 }
1124 Expr::FVar(_) => {
1125 self.fvar_count += 1;
1126 }
1127 Expr::Const(name, _) => {
1128 self.constants.insert(name.clone());
1129 }
1130 Expr::Sort(_) | Expr::Lit(_) => {}
1131 Expr::App(f, a) => {
1132 self.app_count += 1;
1133 self.visit(f, _depth + 1);
1134 self.visit(a, _depth + 1);
1135 }
1136 Expr::Lam(_, _, ty, body) => {
1137 self.lambda_count += 1;
1138 self.visit(ty, _depth + 1);
1139 self.visit(body, _depth + 1);
1140 }
1141 Expr::Pi(_, _, ty, body) => {
1142 self.visit(ty, _depth + 1);
1143 self.visit(body, _depth + 1);
1144 }
1145 Expr::Let(_, ty, val, body) => {
1146 self.let_count += 1;
1147 self.visit(ty, _depth + 1);
1148 self.visit(val, _depth + 1);
1149 self.visit(body, _depth + 1);
1150 }
1151 Expr::Proj(_, _, e) => {
1152 self.visit(e, _depth + 1);
1153 }
1154 }
1155 }
1156}
1157#[allow(dead_code)]
1159pub struct StackCalc {
1160 stack: Vec<i64>,
1161}
1162#[allow(dead_code)]
1163impl StackCalc {
1164 pub fn new() -> Self {
1166 Self { stack: Vec::new() }
1167 }
1168 pub fn push(&mut self, n: i64) {
1170 self.stack.push(n);
1171 }
1172 pub fn add(&mut self) {
1174 let b = self
1175 .stack
1176 .pop()
1177 .expect("stack must have at least two values for add");
1178 let a = self
1179 .stack
1180 .pop()
1181 .expect("stack must have at least two values for add");
1182 self.stack.push(a + b);
1183 }
1184 pub fn sub(&mut self) {
1186 let b = self
1187 .stack
1188 .pop()
1189 .expect("stack must have at least two values for sub");
1190 let a = self
1191 .stack
1192 .pop()
1193 .expect("stack must have at least two values for sub");
1194 self.stack.push(a - b);
1195 }
1196 pub fn mul(&mut self) {
1198 let b = self
1199 .stack
1200 .pop()
1201 .expect("stack must have at least two values for mul");
1202 let a = self
1203 .stack
1204 .pop()
1205 .expect("stack must have at least two values for mul");
1206 self.stack.push(a * b);
1207 }
1208 pub fn peek(&self) -> Option<i64> {
1210 self.stack.last().copied()
1211 }
1212 pub fn depth(&self) -> usize {
1214 self.stack.len()
1215 }
1216}
1217#[allow(dead_code)]
1219pub enum Either2<A, B> {
1220 First(A),
1222 Second(B),
1224}
1225#[allow(dead_code)]
1226impl<A, B> Either2<A, B> {
1227 pub fn is_first(&self) -> bool {
1229 matches!(self, Either2::First(_))
1230 }
1231 pub fn is_second(&self) -> bool {
1233 matches!(self, Either2::Second(_))
1234 }
1235 pub fn first(self) -> Option<A> {
1237 match self {
1238 Either2::First(a) => Some(a),
1239 _ => None,
1240 }
1241 }
1242 pub fn second(self) -> Option<B> {
1244 match self {
1245 Either2::Second(b) => Some(b),
1246 _ => None,
1247 }
1248 }
1249 pub fn map_first<C, F: FnOnce(A) -> C>(self, f: F) -> Either2<C, B> {
1251 match self {
1252 Either2::First(a) => Either2::First(f(a)),
1253 Either2::Second(b) => Either2::Second(b),
1254 }
1255 }
1256}
1257#[allow(dead_code)]
1259pub struct Fixture {
1260 data: std::collections::HashMap<String, String>,
1261}
1262#[allow(dead_code)]
1263impl Fixture {
1264 pub fn new() -> Self {
1266 Self {
1267 data: std::collections::HashMap::new(),
1268 }
1269 }
1270 pub fn set(&mut self, key: impl Into<String>, val: impl Into<String>) {
1272 self.data.insert(key.into(), val.into());
1273 }
1274 pub fn get(&self, key: &str) -> Option<&str> {
1276 self.data.get(key).map(|s| s.as_str())
1277 }
1278 pub fn len(&self) -> usize {
1280 self.data.len()
1281 }
1282 pub fn is_empty(&self) -> bool {
1284 self.len() == 0
1285 }
1286}
1287#[allow(dead_code)]
1289#[allow(missing_docs)]
1290pub enum DecisionNode {
1291 Leaf(String),
1293 Branch {
1295 key: String,
1296 val: String,
1297 yes_branch: Box<DecisionNode>,
1298 no_branch: Box<DecisionNode>,
1299 },
1300}
1301#[allow(dead_code)]
1302impl DecisionNode {
1303 pub fn evaluate(&self, ctx: &std::collections::HashMap<String, String>) -> &str {
1305 match self {
1306 DecisionNode::Leaf(action) => action.as_str(),
1307 DecisionNode::Branch {
1308 key,
1309 val,
1310 yes_branch,
1311 no_branch,
1312 } => {
1313 let actual = ctx.get(key).map(|s| s.as_str()).unwrap_or("");
1314 if actual == val.as_str() {
1315 yes_branch.evaluate(ctx)
1316 } else {
1317 no_branch.evaluate(ctx)
1318 }
1319 }
1320 }
1321 }
1322 pub fn depth(&self) -> usize {
1324 match self {
1325 DecisionNode::Leaf(_) => 0,
1326 DecisionNode::Branch {
1327 yes_branch,
1328 no_branch,
1329 ..
1330 } => 1 + yes_branch.depth().max(no_branch.depth()),
1331 }
1332 }
1333}
1334#[allow(dead_code)]
1336pub struct FocusStack<T> {
1337 items: Vec<T>,
1338}
1339#[allow(dead_code)]
1340impl<T> FocusStack<T> {
1341 pub fn new() -> Self {
1343 Self { items: Vec::new() }
1344 }
1345 pub fn focus(&mut self, item: T) {
1347 self.items.push(item);
1348 }
1349 pub fn blur(&mut self) -> Option<T> {
1351 self.items.pop()
1352 }
1353 pub fn current(&self) -> Option<&T> {
1355 self.items.last()
1356 }
1357 pub fn depth(&self) -> usize {
1359 self.items.len()
1360 }
1361 pub fn is_empty(&self) -> bool {
1363 self.items.is_empty()
1364 }
1365}
1366#[allow(dead_code)]
1368pub struct Stopwatch {
1369 start: std::time::Instant,
1370 splits: Vec<f64>,
1371}
1372#[allow(dead_code)]
1373impl Stopwatch {
1374 pub fn start() -> Self {
1376 Self {
1377 start: std::time::Instant::now(),
1378 splits: Vec::new(),
1379 }
1380 }
1381 pub fn split(&mut self) {
1383 self.splits.push(self.elapsed_ms());
1384 }
1385 pub fn elapsed_ms(&self) -> f64 {
1387 self.start.elapsed().as_secs_f64() * 1000.0
1388 }
1389 pub fn splits(&self) -> &[f64] {
1391 &self.splits
1392 }
1393 pub fn num_splits(&self) -> usize {
1395 self.splits.len()
1396 }
1397}
1398#[allow(dead_code)]
1400pub struct SparseVec<T: Default + Clone + PartialEq> {
1401 entries: std::collections::HashMap<usize, T>,
1402 default_: T,
1403 logical_len: usize,
1404}
1405#[allow(dead_code)]
1406impl<T: Default + Clone + PartialEq> SparseVec<T> {
1407 pub fn new(len: usize) -> Self {
1409 Self {
1410 entries: std::collections::HashMap::new(),
1411 default_: T::default(),
1412 logical_len: len,
1413 }
1414 }
1415 pub fn set(&mut self, idx: usize, val: T) {
1417 if val == self.default_ {
1418 self.entries.remove(&idx);
1419 } else {
1420 self.entries.insert(idx, val);
1421 }
1422 }
1423 pub fn get(&self, idx: usize) -> &T {
1425 self.entries.get(&idx).unwrap_or(&self.default_)
1426 }
1427 pub fn len(&self) -> usize {
1429 self.logical_len
1430 }
1431 pub fn is_empty(&self) -> bool {
1433 self.len() == 0
1434 }
1435 pub fn nnz(&self) -> usize {
1437 self.entries.len()
1438 }
1439}
1440#[allow(dead_code)]
1443#[derive(Clone, Debug)]
1444pub struct ProofCertificate {
1445 pub proposition: Expr,
1447 pub proof_term: Expr,
1449 pub is_constructive: bool,
1451 pub has_sorry: bool,
1453}
1454impl ProofCertificate {
1455 #[allow(dead_code)]
1457 pub fn new(proposition: Expr, proof_term: Expr) -> Self {
1458 let is_constructive = ProofAnalyzer::is_constructive(&proof_term);
1459 let has_sorry = crate::proof::contains_classical_sorry(&proof_term);
1460 Self {
1461 proposition,
1462 proof_term,
1463 is_constructive,
1464 has_sorry,
1465 }
1466 }
1467 #[allow(dead_code)]
1469 pub fn is_trusted(&self) -> bool {
1470 !self.has_sorry && self.is_constructive
1471 }
1472}
1473#[allow(dead_code)]
1475pub struct TokenBucket {
1476 capacity: u64,
1477 tokens: u64,
1478 refill_per_ms: u64,
1479 last_refill: std::time::Instant,
1480}
1481#[allow(dead_code)]
1482impl TokenBucket {
1483 pub fn new(capacity: u64, refill_per_ms: u64) -> Self {
1485 Self {
1486 capacity,
1487 tokens: capacity,
1488 refill_per_ms,
1489 last_refill: std::time::Instant::now(),
1490 }
1491 }
1492 pub fn try_consume(&mut self, n: u64) -> bool {
1494 self.refill();
1495 if self.tokens >= n {
1496 self.tokens -= n;
1497 true
1498 } else {
1499 false
1500 }
1501 }
1502 fn refill(&mut self) {
1503 let now = std::time::Instant::now();
1504 let elapsed_ms = now.duration_since(self.last_refill).as_millis() as u64;
1505 if elapsed_ms > 0 {
1506 let new_tokens = elapsed_ms * self.refill_per_ms;
1507 self.tokens = (self.tokens + new_tokens).min(self.capacity);
1508 self.last_refill = now;
1509 }
1510 }
1511 pub fn available(&self) -> u64 {
1513 self.tokens
1514 }
1515 pub fn capacity(&self) -> u64 {
1517 self.capacity
1518 }
1519}
1520#[allow(dead_code)]
1522pub struct ConfigNode {
1523 key: String,
1524 value: Option<String>,
1525 children: Vec<ConfigNode>,
1526}
1527#[allow(dead_code)]
1528impl ConfigNode {
1529 pub fn leaf(key: impl Into<String>, value: impl Into<String>) -> Self {
1531 Self {
1532 key: key.into(),
1533 value: Some(value.into()),
1534 children: Vec::new(),
1535 }
1536 }
1537 pub fn section(key: impl Into<String>) -> Self {
1539 Self {
1540 key: key.into(),
1541 value: None,
1542 children: Vec::new(),
1543 }
1544 }
1545 pub fn add_child(&mut self, child: ConfigNode) {
1547 self.children.push(child);
1548 }
1549 pub fn key(&self) -> &str {
1551 &self.key
1552 }
1553 pub fn value(&self) -> Option<&str> {
1555 self.value.as_deref()
1556 }
1557 pub fn num_children(&self) -> usize {
1559 self.children.len()
1560 }
1561 pub fn lookup(&self, path: &str) -> Option<&str> {
1563 let mut parts = path.splitn(2, '.');
1564 let head = parts.next()?;
1565 let tail = parts.next();
1566 if head != self.key {
1567 return None;
1568 }
1569 match tail {
1570 None => self.value.as_deref(),
1571 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
1572 }
1573 }
1574 fn lookup_relative(&self, path: &str) -> Option<&str> {
1575 let mut parts = path.splitn(2, '.');
1576 let head = parts.next()?;
1577 let tail = parts.next();
1578 if head != self.key {
1579 return None;
1580 }
1581 match tail {
1582 None => self.value.as_deref(),
1583 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
1584 }
1585 }
1586}
1587#[allow(dead_code)]
1589pub struct VersionedRecord<T: Clone> {
1590 history: Vec<T>,
1591}
1592#[allow(dead_code)]
1593impl<T: Clone> VersionedRecord<T> {
1594 pub fn new(initial: T) -> Self {
1596 Self {
1597 history: vec![initial],
1598 }
1599 }
1600 pub fn update(&mut self, val: T) {
1602 self.history.push(val);
1603 }
1604 pub fn current(&self) -> &T {
1606 self.history
1607 .last()
1608 .expect("VersionedRecord history is always non-empty after construction")
1609 }
1610 pub fn at_version(&self, n: usize) -> Option<&T> {
1612 self.history.get(n)
1613 }
1614 pub fn version(&self) -> usize {
1616 self.history.len() - 1
1617 }
1618 pub fn has_history(&self) -> bool {
1620 self.history.len() > 1
1621 }
1622}
1623#[allow(dead_code)]
1625pub struct MinHeap<T: Ord> {
1626 data: Vec<T>,
1627}
1628#[allow(dead_code)]
1629impl<T: Ord> MinHeap<T> {
1630 pub fn new() -> Self {
1632 Self { data: Vec::new() }
1633 }
1634 pub fn push(&mut self, val: T) {
1636 self.data.push(val);
1637 self.sift_up(self.data.len() - 1);
1638 }
1639 pub fn pop(&mut self) -> Option<T> {
1641 if self.data.is_empty() {
1642 return None;
1643 }
1644 let n = self.data.len();
1645 self.data.swap(0, n - 1);
1646 let min = self.data.pop();
1647 if !self.data.is_empty() {
1648 self.sift_down(0);
1649 }
1650 min
1651 }
1652 pub fn peek(&self) -> Option<&T> {
1654 self.data.first()
1655 }
1656 pub fn len(&self) -> usize {
1658 self.data.len()
1659 }
1660 pub fn is_empty(&self) -> bool {
1662 self.data.is_empty()
1663 }
1664 fn sift_up(&mut self, mut i: usize) {
1665 while i > 0 {
1666 let parent = (i - 1) / 2;
1667 if self.data[i] < self.data[parent] {
1668 self.data.swap(i, parent);
1669 i = parent;
1670 } else {
1671 break;
1672 }
1673 }
1674 }
1675 fn sift_down(&mut self, mut i: usize) {
1676 let n = self.data.len();
1677 loop {
1678 let left = 2 * i + 1;
1679 let right = 2 * i + 2;
1680 let mut smallest = i;
1681 if left < n && self.data[left] < self.data[smallest] {
1682 smallest = left;
1683 }
1684 if right < n && self.data[right] < self.data[smallest] {
1685 smallest = right;
1686 }
1687 if smallest == i {
1688 break;
1689 }
1690 self.data.swap(i, smallest);
1691 i = smallest;
1692 }
1693 }
1694}
1695#[allow(dead_code)]
1697#[derive(Debug, Clone)]
1698pub struct ProofObligation {
1699 pub label: String,
1701 pub proposition: Expr,
1703 pub discharged: bool,
1705 pub proof_term: Option<Expr>,
1707}
1708impl ProofObligation {
1709 #[allow(dead_code)]
1711 pub fn new(label: impl Into<String>, proposition: Expr) -> Self {
1712 ProofObligation {
1713 label: label.into(),
1714 proposition,
1715 discharged: false,
1716 proof_term: None,
1717 }
1718 }
1719 #[allow(dead_code)]
1721 pub fn discharge(&mut self, proof: Expr) {
1722 self.proof_term = Some(proof);
1723 self.discharged = true;
1724 }
1725 #[allow(dead_code)]
1727 pub fn is_discharged(&self) -> bool {
1728 self.discharged
1729 }
1730}