1use crate::Node;
6use crate::{Expr, LevelView, Name};
7use std::collections::{HashMap, HashSet};
8use std::rc::Rc;
9
10use super::functions::*;
11
12pub struct ProofTerm;
14impl ProofTerm {
15 pub fn is_proof(term: &Expr, prop: &Expr) -> bool {
21 if Self::could_be_prop(prop) {
22 Self::is_well_formed(term)
23 } else {
24 false
25 }
26 }
27 pub fn could_be_prop(ty: &Expr) -> bool {
31 match ty {
32 Expr::Sort(l) if matches!(l.view(), LevelView::Zero) => true,
33 Expr::Pi(_, _, _, body) => Self::could_be_prop(body),
34 Expr::Const(_, _) => true,
35 Expr::App(_, _) => true,
36 _ => false,
37 }
38 }
39 pub fn is_sort_zero(ty: &Expr) -> bool {
41 matches!(ty, Expr::Sort(l) if matches!(l.view(), LevelView::Zero))
42 }
43 pub fn get_proposition(term: &Expr) -> Option<Expr> {
47 match term {
48 Expr::Lam(_, _, ty, _) if Self::could_be_prop(ty) => Some((**ty).clone()),
49 _ => None,
50 }
51 }
52 pub fn is_constructive(term: &Expr) -> bool {
59 let deps = collect_axiom_deps(term);
60 !deps
61 .iter()
62 .any(|name: &Name| CLASSICAL_AXIOMS.contains(&name.to_string().as_str()))
63 }
64 pub fn collect_constants(term: &Expr) -> HashSet<Name> {
66 let mut result = HashSet::new();
67 collect_constants_impl(term, &mut result);
68 result
69 }
70 pub fn size(term: &Expr) -> usize {
72 match term {
73 Expr::BVar(_) | Expr::FVar(_) | Expr::Const(_, _) | Expr::Sort(_) | Expr::Lit(_) => 1,
74 Expr::App(f, a) => 1 + Self::size(f) + Self::size(a),
75 Expr::Lam(_, _, ty, body) => 1 + Self::size(ty) + Self::size(body),
76 Expr::Pi(_, _, ty, body) => 1 + Self::size(ty) + Self::size(body),
77 Expr::Let(_, ty, val, body) => 1 + Self::size(ty) + Self::size(val) + Self::size(body),
78 Expr::Proj(_, _, e) => 1 + Self::size(e),
79 }
80 }
81 pub fn depth(term: &Expr) -> usize {
83 match term {
84 Expr::BVar(_) | Expr::FVar(_) | Expr::Const(_, _) | Expr::Sort(_) | Expr::Lit(_) => 0,
85 Expr::App(f, a) => 1 + Self::depth(f).max(Self::depth(a)),
86 Expr::Lam(_, _, ty, body) => 1 + Self::depth(ty).max(Self::depth(body)),
87 Expr::Pi(_, _, ty, body) => 1 + Self::depth(ty).max(Self::depth(body)),
88 Expr::Let(_, ty, val, body) => {
89 1 + Self::depth(ty).max(Self::depth(val)).max(Self::depth(body))
90 }
91 Expr::Proj(_, _, e) => 1 + Self::depth(e),
92 }
93 }
94 fn is_well_formed(term: &Expr) -> bool {
96 match term {
97 Expr::BVar(_) | Expr::FVar(_) | Expr::Const(_, _) | Expr::Sort(_) | Expr::Lit(_) => {
98 true
99 }
100 Expr::App(f, a) => Self::is_well_formed(f) && Self::is_well_formed(a),
101 Expr::Lam(_, _, ty, body) => Self::is_well_formed(ty) && Self::is_well_formed(body),
102 Expr::Pi(_, _, ty, body) => Self::is_well_formed(ty) && Self::is_well_formed(body),
103 Expr::Let(_, ty, val, body) => {
104 Self::is_well_formed(ty) && Self::is_well_formed(val) && Self::is_well_formed(body)
105 }
106 Expr::Proj(_, _, e) => Self::is_well_formed(e),
107 }
108 }
109 pub fn same_proposition_structure(p1: &Expr, p2: &Expr) -> bool {
114 match (p1, p2) {
115 (Expr::Sort(l1), Expr::Sort(l2)) => l1 == l2,
116 (Expr::Const(n1, _), Expr::Const(n2, _)) => n1 == n2,
117 (Expr::App(f1, a1), Expr::App(f2, a2)) => {
118 Self::same_proposition_structure(f1, f2) && Self::same_proposition_structure(a1, a2)
119 }
120 (Expr::Pi(_, _, ty1, body1), Expr::Pi(_, _, ty2, body2)) => {
121 Self::same_proposition_structure(ty1, ty2)
122 && Self::same_proposition_structure(body1, body2)
123 }
124 _ => p1 == p2,
125 }
126 }
127}
128#[allow(dead_code)]
130pub struct FlatSubstitution {
131 pairs: Vec<(String, String)>,
132}
133#[allow(dead_code)]
134impl FlatSubstitution {
135 pub fn new() -> Self {
137 Self { pairs: Vec::new() }
138 }
139 pub fn add(&mut self, from: impl Into<String>, to: impl Into<String>) {
141 self.pairs.push((from.into(), to.into()));
142 }
143 pub fn apply(&self, s: &str) -> String {
145 let mut result = s.to_string();
146 for (from, to) in &self.pairs {
147 result = result.replace(from.as_str(), to.as_str());
148 }
149 result
150 }
151 pub fn len(&self) -> usize {
153 self.pairs.len()
154 }
155 pub fn is_empty(&self) -> bool {
157 self.pairs.is_empty()
158 }
159}
160#[allow(dead_code)]
162pub struct LabelSet {
163 labels: Vec<String>,
164}
165#[allow(dead_code)]
166impl LabelSet {
167 pub fn new() -> Self {
169 Self { labels: Vec::new() }
170 }
171 pub fn add(&mut self, label: impl Into<String>) {
173 let s = label.into();
174 if !self.labels.contains(&s) {
175 self.labels.push(s);
176 }
177 }
178 pub fn has(&self, label: &str) -> bool {
180 self.labels.iter().any(|l| l == label)
181 }
182 pub fn count(&self) -> usize {
184 self.labels.len()
185 }
186 pub fn all(&self) -> &[String] {
188 &self.labels
189 }
190}
191#[allow(dead_code)]
193pub struct SlidingSum {
194 window: Vec<f64>,
195 capacity: usize,
196 pos: usize,
197 sum: f64,
198 count: usize,
199}
200#[allow(dead_code)]
201impl SlidingSum {
202 pub fn new(capacity: usize) -> Self {
204 Self {
205 window: vec![0.0; capacity],
206 capacity,
207 pos: 0,
208 sum: 0.0,
209 count: 0,
210 }
211 }
212 pub fn push(&mut self, val: f64) {
214 let oldest = self.window[self.pos];
215 self.sum -= oldest;
216 self.sum += val;
217 self.window[self.pos] = val;
218 self.pos = (self.pos + 1) % self.capacity;
219 if self.count < self.capacity {
220 self.count += 1;
221 }
222 }
223 pub fn sum(&self) -> f64 {
225 self.sum
226 }
227 pub fn mean(&self) -> Option<f64> {
229 if self.count == 0 {
230 None
231 } else {
232 Some(self.sum / self.count as f64)
233 }
234 }
235 pub fn count(&self) -> usize {
237 self.count
238 }
239}
240#[allow(dead_code)]
242pub struct PrefixCounter {
243 children: std::collections::HashMap<char, PrefixCounter>,
244 count: usize,
245}
246#[allow(dead_code)]
247impl PrefixCounter {
248 pub fn new() -> Self {
250 Self {
251 children: std::collections::HashMap::new(),
252 count: 0,
253 }
254 }
255 pub fn record(&mut self, s: &str) {
257 self.count += 1;
258 let mut node = self;
259 for c in s.chars() {
260 node = node.children.entry(c).or_default();
261 node.count += 1;
262 }
263 }
264 pub fn count_with_prefix(&self, prefix: &str) -> usize {
266 let mut node = self;
267 for c in prefix.chars() {
268 match node.children.get(&c) {
269 Some(n) => node = n,
270 None => return 0,
271 }
272 }
273 node.count
274 }
275}
276#[allow(dead_code)]
278pub struct SmallMap<K: Ord + Clone, V: Clone> {
279 entries: Vec<(K, V)>,
280}
281#[allow(dead_code)]
282impl<K: Ord + Clone, V: Clone> SmallMap<K, V> {
283 pub fn new() -> Self {
285 Self {
286 entries: Vec::new(),
287 }
288 }
289 pub fn insert(&mut self, key: K, val: V) {
291 match self.entries.binary_search_by_key(&&key, |(k, _)| k) {
292 Ok(i) => self.entries[i].1 = val,
293 Err(i) => self.entries.insert(i, (key, val)),
294 }
295 }
296 pub fn get(&self, key: &K) -> Option<&V> {
298 self.entries
299 .binary_search_by_key(&key, |(k, _)| k)
300 .ok()
301 .map(|i| &self.entries[i].1)
302 }
303 pub fn len(&self) -> usize {
305 self.entries.len()
306 }
307 pub fn is_empty(&self) -> bool {
309 self.entries.is_empty()
310 }
311 pub fn keys(&self) -> Vec<&K> {
313 self.entries.iter().map(|(k, _)| k).collect()
314 }
315 pub fn values(&self) -> Vec<&V> {
317 self.entries.iter().map(|(_, v)| v).collect()
318 }
319}
320#[allow(dead_code)]
322pub struct WindowIterator<'a, T> {
323 pub(super) data: &'a [T],
324 pub(super) pos: usize,
325 pub(super) window: usize,
326}
327#[allow(dead_code)]
328impl<'a, T> WindowIterator<'a, T> {
329 pub fn new(data: &'a [T], window: usize) -> Self {
331 Self {
332 data,
333 pos: 0,
334 window,
335 }
336 }
337}
338#[allow(dead_code)]
340pub struct StatSummary {
341 count: u64,
342 sum: f64,
343 min: f64,
344 max: f64,
345}
346#[allow(dead_code)]
347impl StatSummary {
348 pub fn new() -> Self {
350 Self {
351 count: 0,
352 sum: 0.0,
353 min: f64::INFINITY,
354 max: f64::NEG_INFINITY,
355 }
356 }
357 pub fn record(&mut self, val: f64) {
359 self.count += 1;
360 self.sum += val;
361 if val < self.min {
362 self.min = val;
363 }
364 if val > self.max {
365 self.max = val;
366 }
367 }
368 pub fn mean(&self) -> Option<f64> {
370 if self.count == 0 {
371 None
372 } else {
373 Some(self.sum / self.count as f64)
374 }
375 }
376 pub fn min(&self) -> Option<f64> {
378 if self.count == 0 {
379 None
380 } else {
381 Some(self.min)
382 }
383 }
384 pub fn max(&self) -> Option<f64> {
386 if self.count == 0 {
387 None
388 } else {
389 Some(self.max)
390 }
391 }
392 pub fn count(&self) -> u64 {
394 self.count
395 }
396}
397#[allow(dead_code)]
399#[derive(Debug, Clone, Default)]
400pub struct ProofState {
401 pub obligations: Vec<ProofObligation>,
403}
404impl ProofState {
405 #[allow(dead_code)]
407 pub fn new() -> Self {
408 Self::default()
409 }
410 #[allow(dead_code)]
412 pub fn add_obligation(&mut self, label: impl Into<String>, proposition: Expr) {
413 self.obligations
414 .push(ProofObligation::new(label, proposition));
415 }
416 #[allow(dead_code)]
418 pub fn remaining(&self) -> usize {
419 self.obligations
420 .iter()
421 .filter(|o| !o.is_discharged())
422 .count()
423 }
424 #[allow(dead_code)]
426 pub fn is_complete(&self) -> bool {
427 self.remaining() == 0
428 }
429 #[allow(dead_code)]
433 pub fn discharge_next(&mut self, proof: Expr) -> bool {
434 for obl in self.obligations.iter_mut() {
435 if !obl.discharged {
436 obl.discharge(proof);
437 return true;
438 }
439 }
440 false
441 }
442 #[allow(dead_code)]
444 pub fn open_obligations(&self) -> Vec<&ProofObligation> {
445 self.obligations
446 .iter()
447 .filter(|o| !o.is_discharged())
448 .collect()
449 }
450}
451#[allow(dead_code)]
453pub struct SimpleDag {
454 edges: Vec<Vec<usize>>,
456}
457#[allow(dead_code)]
458impl SimpleDag {
459 pub fn new(n: usize) -> Self {
461 Self {
462 edges: vec![Vec::new(); n],
463 }
464 }
465 pub fn add_edge(&mut self, from: usize, to: usize) {
467 if from < self.edges.len() {
468 self.edges[from].push(to);
469 }
470 }
471 pub fn successors(&self, node: usize) -> &[usize] {
473 self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
474 }
475 pub fn can_reach(&self, from: usize, to: usize) -> bool {
477 let mut visited = vec![false; self.edges.len()];
478 self.dfs(from, to, &mut visited)
479 }
480 fn dfs(&self, cur: usize, target: usize, visited: &mut Vec<bool>) -> bool {
481 if cur == target {
482 return true;
483 }
484 if cur >= visited.len() || visited[cur] {
485 return false;
486 }
487 visited[cur] = true;
488 for &next in self.successors(cur) {
489 if self.dfs(next, target, visited) {
490 return true;
491 }
492 }
493 false
494 }
495 pub fn topological_sort(&self) -> Option<Vec<usize>> {
497 let n = self.edges.len();
498 let mut in_degree = vec![0usize; n];
499 for succs in &self.edges {
500 for &s in succs {
501 if s < n {
502 in_degree[s] += 1;
503 }
504 }
505 }
506 let mut queue: std::collections::VecDeque<usize> =
507 (0..n).filter(|&i| in_degree[i] == 0).collect();
508 let mut order = Vec::new();
509 while let Some(node) = queue.pop_front() {
510 order.push(node);
511 for &s in self.successors(node) {
512 if s < n {
513 in_degree[s] -= 1;
514 if in_degree[s] == 0 {
515 queue.push_back(s);
516 }
517 }
518 }
519 }
520 if order.len() == n {
521 Some(order)
522 } else {
523 None
524 }
525 }
526 pub fn num_nodes(&self) -> usize {
528 self.edges.len()
529 }
530}
531#[allow(dead_code)]
533pub struct TransitiveClosure {
534 adj: Vec<Vec<usize>>,
535 n: usize,
536}
537#[allow(dead_code)]
538impl TransitiveClosure {
539 pub fn new(n: usize) -> Self {
541 Self {
542 adj: vec![Vec::new(); n],
543 n,
544 }
545 }
546 pub fn add_edge(&mut self, from: usize, to: usize) {
548 if from < self.n {
549 self.adj[from].push(to);
550 }
551 }
552 pub fn reachable_from(&self, start: usize) -> Vec<usize> {
554 let mut visited = vec![false; self.n];
555 let mut queue = std::collections::VecDeque::new();
556 queue.push_back(start);
557 while let Some(node) = queue.pop_front() {
558 if node >= self.n || visited[node] {
559 continue;
560 }
561 visited[node] = true;
562 for &next in &self.adj[node] {
563 queue.push_back(next);
564 }
565 }
566 (0..self.n).filter(|&i| visited[i]).collect()
567 }
568 pub fn can_reach(&self, from: usize, to: usize) -> bool {
570 self.reachable_from(from).contains(&to)
571 }
572}
573#[allow(dead_code)]
575pub struct PathBuf {
576 components: Vec<String>,
577}
578#[allow(dead_code)]
579impl PathBuf {
580 pub fn new() -> Self {
582 Self {
583 components: Vec::new(),
584 }
585 }
586 pub fn push(&mut self, comp: impl Into<String>) {
588 self.components.push(comp.into());
589 }
590 pub fn pop(&mut self) {
592 self.components.pop();
593 }
594 pub fn as_str(&self) -> String {
596 self.components.join("/")
597 }
598 pub fn depth(&self) -> usize {
600 self.components.len()
601 }
602 pub fn clear(&mut self) {
604 self.components.clear();
605 }
606}
607#[allow(dead_code)]
609pub struct RewriteRuleSet {
610 rules: Vec<RewriteRule>,
611}
612#[allow(dead_code)]
613impl RewriteRuleSet {
614 pub fn new() -> Self {
616 Self { rules: Vec::new() }
617 }
618 pub fn add(&mut self, rule: RewriteRule) {
620 self.rules.push(rule);
621 }
622 pub fn len(&self) -> usize {
624 self.rules.len()
625 }
626 pub fn is_empty(&self) -> bool {
628 self.rules.is_empty()
629 }
630 pub fn conditional_rules(&self) -> Vec<&RewriteRule> {
632 self.rules.iter().filter(|r| r.conditional).collect()
633 }
634 pub fn unconditional_rules(&self) -> Vec<&RewriteRule> {
636 self.rules.iter().filter(|r| !r.conditional).collect()
637 }
638 pub fn get(&self, name: &str) -> Option<&RewriteRule> {
640 self.rules.iter().find(|r| r.name == name)
641 }
642}
643#[allow(dead_code)]
645#[derive(Debug, Clone, PartialEq, Eq)]
646pub enum ProofComplexity {
647 Atomic,
649 Abstraction,
651 Application,
653 LetBinding,
655 Projection,
657 Composite,
659}
660pub struct ProofAnalyzer;
662impl ProofAnalyzer {
663 pub fn is_constructive(term: &Expr) -> bool {
665 !Self::uses_classical(term)
666 }
667 pub fn uses_classical(term: &Expr) -> bool {
669 match term {
670 Expr::Const(n, _) => {
671 let s = n.to_string();
672 s == "Classical.choice" || s == "Classical.em" || s == "propext"
673 }
674 Expr::App(f, a) => Self::uses_classical(f) || Self::uses_classical(a),
675 Expr::Lam(_, _, ty, body) | Expr::Pi(_, _, ty, body) => {
676 Self::uses_classical(ty) || Self::uses_classical(body)
677 }
678 Expr::Let(_, ty, val, body) => {
679 Self::uses_classical(ty) || Self::uses_classical(val) || Self::uses_classical(body)
680 }
681 _ => false,
682 }
683 }
684 pub fn count_applications(term: &Expr) -> usize {
686 match term {
687 Expr::App(f, a) => 1 + Self::count_applications(f) + Self::count_applications(a),
688 Expr::Lam(_, _, ty, body) | Expr::Pi(_, _, ty, body) => {
689 Self::count_applications(ty) + Self::count_applications(body)
690 }
691 Expr::Let(_, ty, val, body) => {
692 Self::count_applications(ty)
693 + Self::count_applications(val)
694 + Self::count_applications(body)
695 }
696 _ => 0,
697 }
698 }
699}
700#[allow(dead_code)]
705pub struct ProofNormalizer;
706impl ProofNormalizer {
707 #[allow(dead_code)]
712 pub fn beta_reduce(term: &Expr) -> Expr {
713 match term {
714 Expr::App(f, arg) => {
715 let f_reduced = Self::beta_reduce(f);
716 let arg_reduced = Self::beta_reduce(arg);
717 if let Expr::Lam(_, _, _, body) = f_reduced {
718 let substituted = Self::subst_bvar((*body).clone(), 0, &arg_reduced);
719 Self::beta_reduce(&substituted)
720 } else {
721 Expr::App(Node::new(f_reduced), Node::new(arg_reduced))
722 }
723 }
724 Expr::Lam(bk, n, ty, body) => {
725 let ty_red = Self::beta_reduce(ty);
726 let body_red = Self::beta_reduce(body);
727 Expr::Lam(*bk, n.clone(), Node::new(ty_red), Node::new(body_red))
728 }
729 Expr::Pi(bk, n, ty, body) => {
730 let ty_red = Self::beta_reduce(ty);
731 let body_red = Self::beta_reduce(body);
732 Expr::Pi(*bk, n.clone(), Node::new(ty_red), Node::new(body_red))
733 }
734 Expr::Let(_n, _ty, val, body) => {
735 let val_red = Self::beta_reduce(val);
736 let body_subst = Self::subst_bvar((**body).clone(), 0, &val_red);
737 Self::beta_reduce(&body_subst)
738 }
739 Expr::Proj(idx, n, e) => Expr::Proj(idx.clone(), *n, Node::new(Self::beta_reduce(e))),
740 other => other.clone(),
741 }
742 }
743 #[allow(dead_code)]
747 pub fn subst_bvar(term: Expr, depth: u32, replacement: &Expr) -> Expr {
748 match term {
749 Expr::BVar(i) => {
750 if i == depth {
751 replacement.clone()
752 } else if i > depth {
753 Expr::BVar(i - 1)
754 } else {
755 Expr::BVar(i)
756 }
757 }
758 Expr::App(f, a) => Expr::App(
759 Node::new(Self::subst_bvar((*f).clone(), depth, replacement)),
760 Node::new(Self::subst_bvar((*a).clone(), depth, replacement)),
761 ),
762 Expr::Lam(bk, n, ty, body) => Expr::Lam(
763 bk,
764 n,
765 Node::new(Self::subst_bvar((*ty).clone(), depth, replacement)),
766 Node::new(Self::subst_bvar((*body).clone(), depth + 1, replacement)),
767 ),
768 Expr::Pi(bk, n, ty, body) => Expr::Pi(
769 bk,
770 n,
771 Node::new(Self::subst_bvar((*ty).clone(), depth, replacement)),
772 Node::new(Self::subst_bvar((*body).clone(), depth + 1, replacement)),
773 ),
774 Expr::Let(n, ty, val, body) => Expr::Let(
775 n,
776 Node::new(Self::subst_bvar((*ty).clone(), depth, replacement)),
777 Node::new(Self::subst_bvar((*val).clone(), depth, replacement)),
778 Node::new(Self::subst_bvar((*body).clone(), depth + 1, replacement)),
779 ),
780 Expr::Proj(idx, n, e) => Expr::Proj(
781 idx,
782 n,
783 Node::new(Self::subst_bvar((*e).clone(), depth, replacement)),
784 ),
785 other => other,
786 }
787 }
788 #[allow(dead_code)]
790 pub fn count_redexes(term: &Expr) -> usize {
791 match term {
792 Expr::App(f, a) => {
793 let in_f = Self::count_redexes(f);
794 let in_a = Self::count_redexes(a);
795 let is_redex = matches!(f.as_ref(), Expr::Lam(_, _, _, _));
796 in_f + in_a + if is_redex { 1 } else { 0 }
797 }
798 Expr::Lam(_, _, ty, body) => Self::count_redexes(ty) + Self::count_redexes(body),
799 Expr::Pi(_, _, ty, body) => Self::count_redexes(ty) + Self::count_redexes(body),
800 Expr::Let(_, ty, val, body) => {
801 Self::count_redexes(ty) + Self::count_redexes(val) + Self::count_redexes(body)
802 }
803 Expr::Proj(_, _, e) => Self::count_redexes(e),
804 _ => 0,
805 }
806 }
807 #[allow(dead_code)]
809 pub fn is_beta_normal(term: &Expr) -> bool {
810 Self::count_redexes(term) == 0
811 }
812}
813#[allow(dead_code)]
818#[derive(Clone, Debug)]
819pub struct ProofSkeleton {
820 pub term: Expr,
822 pub ty: Expr,
824 pub holes: Vec<Name>,
826}
827impl ProofSkeleton {
828 #[allow(dead_code)]
830 pub fn new(term: Expr, ty: Expr) -> Self {
831 let holes = Self::collect_holes(&term);
832 Self { term, ty, holes }
833 }
834 fn collect_holes(term: &Expr) -> Vec<Name> {
836 let mut holes = Vec::new();
837 Self::collect_holes_rec(term, &mut holes);
838 holes
839 }
840 fn collect_holes_rec(term: &Expr, holes: &mut Vec<Name>) {
841 match term {
842 Expr::Const(n, _) if n.to_string().contains("sorry") => {
843 holes.push(n.clone());
844 }
845 Expr::App(f, a) => {
846 Self::collect_holes_rec(f, holes);
847 Self::collect_holes_rec(a, holes);
848 }
849 Expr::Lam(_, _, ty, body) | Expr::Pi(_, _, ty, body) => {
850 Self::collect_holes_rec(ty, holes);
851 Self::collect_holes_rec(body, holes);
852 }
853 Expr::Let(_, ty, val, body) => {
854 Self::collect_holes_rec(ty, holes);
855 Self::collect_holes_rec(val, holes);
856 Self::collect_holes_rec(body, holes);
857 }
858 _ => {}
859 }
860 }
861 #[allow(dead_code)]
863 pub fn is_complete(&self) -> bool {
864 self.holes.is_empty()
865 }
866 #[allow(dead_code)]
868 pub fn num_holes(&self) -> usize {
869 self.holes.len()
870 }
871}
872#[allow(dead_code)]
874pub struct TransformStat {
875 before: StatSummary,
876 after: StatSummary,
877}
878#[allow(dead_code)]
879impl TransformStat {
880 pub fn new() -> Self {
882 Self {
883 before: StatSummary::new(),
884 after: StatSummary::new(),
885 }
886 }
887 pub fn record_before(&mut self, v: f64) {
889 self.before.record(v);
890 }
891 pub fn record_after(&mut self, v: f64) {
893 self.after.record(v);
894 }
895 pub fn mean_ratio(&self) -> Option<f64> {
897 let b = self.before.mean()?;
898 let a = self.after.mean()?;
899 if b.abs() < f64::EPSILON {
900 return None;
901 }
902 Some(a / b)
903 }
904}
905#[allow(dead_code)]
907pub struct NonEmptyVec<T> {
908 head: T,
909 tail: Vec<T>,
910}
911#[allow(dead_code)]
912impl<T> NonEmptyVec<T> {
913 pub fn singleton(val: T) -> Self {
915 Self {
916 head: val,
917 tail: Vec::new(),
918 }
919 }
920 pub fn push(&mut self, val: T) {
922 self.tail.push(val);
923 }
924 pub fn first(&self) -> &T {
926 &self.head
927 }
928 pub fn last(&self) -> &T {
930 self.tail.last().unwrap_or(&self.head)
931 }
932 pub fn len(&self) -> usize {
934 1 + self.tail.len()
935 }
936 pub fn is_empty(&self) -> bool {
938 self.len() == 0
939 }
940 pub fn to_vec(&self) -> Vec<&T> {
942 let mut v = vec![&self.head];
943 v.extend(self.tail.iter());
944 v
945 }
946}
947#[allow(dead_code)]
949pub struct StringPool {
950 free: Vec<String>,
951}
952#[allow(dead_code)]
953impl StringPool {
954 pub fn new() -> Self {
956 Self { free: Vec::new() }
957 }
958 pub fn take(&mut self) -> String {
960 self.free.pop().unwrap_or_default()
961 }
962 pub fn give(&mut self, mut s: String) {
964 s.clear();
965 self.free.push(s);
966 }
967 pub fn free_count(&self) -> usize {
969 self.free.len()
970 }
971}
972#[allow(dead_code)]
974#[allow(missing_docs)]
975pub struct RewriteRule {
976 pub name: String,
978 pub lhs: String,
980 pub rhs: String,
982 pub conditional: bool,
984}
985#[allow(dead_code)]
986impl RewriteRule {
987 pub fn unconditional(
989 name: impl Into<String>,
990 lhs: impl Into<String>,
991 rhs: impl Into<String>,
992 ) -> Self {
993 Self {
994 name: name.into(),
995 lhs: lhs.into(),
996 rhs: rhs.into(),
997 conditional: false,
998 }
999 }
1000 pub fn conditional(
1002 name: impl Into<String>,
1003 lhs: impl Into<String>,
1004 rhs: impl Into<String>,
1005 ) -> Self {
1006 Self {
1007 name: name.into(),
1008 lhs: lhs.into(),
1009 rhs: rhs.into(),
1010 conditional: true,
1011 }
1012 }
1013 pub fn display(&self) -> String {
1015 format!("{}: {} → {}", self.name, self.lhs, self.rhs)
1016 }
1017}
1018#[allow(dead_code)]
1020pub struct RawFnPtr {
1021 ptr: usize,
1023 arity: usize,
1024 name: String,
1025}
1026#[allow(dead_code)]
1027impl RawFnPtr {
1028 pub fn new(ptr: usize, arity: usize, name: impl Into<String>) -> Self {
1030 Self {
1031 ptr,
1032 arity,
1033 name: name.into(),
1034 }
1035 }
1036 pub fn arity(&self) -> usize {
1038 self.arity
1039 }
1040 pub fn name(&self) -> &str {
1042 &self.name
1043 }
1044 pub fn raw(&self) -> usize {
1046 self.ptr
1047 }
1048}
1049#[allow(dead_code)]
1051pub struct WriteOnce<T> {
1052 value: std::cell::Cell<Option<T>>,
1053}
1054#[allow(dead_code)]
1055impl<T: Copy> WriteOnce<T> {
1056 pub fn new() -> Self {
1058 Self {
1059 value: std::cell::Cell::new(None),
1060 }
1061 }
1062 pub fn write(&self, val: T) -> bool {
1064 if self.value.get().is_some() {
1065 return false;
1066 }
1067 self.value.set(Some(val));
1068 true
1069 }
1070 pub fn read(&self) -> Option<T> {
1072 self.value.get()
1073 }
1074 pub fn is_written(&self) -> bool {
1076 self.value.get().is_some()
1077 }
1078}
1079#[allow(dead_code)]
1081#[derive(Debug, Clone)]
1082pub struct ProofAnalysis {
1083 pub size: usize,
1085 pub depth: usize,
1087 pub lambda_count: usize,
1089 pub app_count: usize,
1091 pub let_count: usize,
1093 pub fvar_count: usize,
1095 pub bvar_count: usize,
1097 pub uses_classical: bool,
1099 pub constants: HashSet<Name>,
1101}
1102impl ProofAnalysis {
1103 #[allow(dead_code)]
1105 pub fn analyse(term: &Expr) -> Self {
1106 let mut analysis = ProofAnalysis {
1107 size: 0,
1108 depth: 0,
1109 lambda_count: 0,
1110 app_count: 0,
1111 let_count: 0,
1112 fvar_count: 0,
1113 bvar_count: 0,
1114 uses_classical: false,
1115 constants: HashSet::new(),
1116 };
1117 analysis.visit(term, 0);
1118 analysis.depth = ProofTerm::depth(term);
1119 analysis.uses_classical = !ProofTerm::is_constructive(term);
1120 analysis
1121 }
1122 fn visit(&mut self, term: &Expr, _depth: usize) {
1123 self.size += 1;
1124 match term {
1125 Expr::BVar(_) => {
1126 self.bvar_count += 1;
1127 }
1128 Expr::FVar(_) => {
1129 self.fvar_count += 1;
1130 }
1131 Expr::Const(name, _) => {
1132 self.constants.insert(name.clone());
1133 }
1134 Expr::Sort(_) | Expr::Lit(_) => {}
1135 Expr::App(f, a) => {
1136 self.app_count += 1;
1137 self.visit(f, _depth + 1);
1138 self.visit(a, _depth + 1);
1139 }
1140 Expr::Lam(_, _, ty, body) => {
1141 self.lambda_count += 1;
1142 self.visit(ty, _depth + 1);
1143 self.visit(body, _depth + 1);
1144 }
1145 Expr::Pi(_, _, ty, body) => {
1146 self.visit(ty, _depth + 1);
1147 self.visit(body, _depth + 1);
1148 }
1149 Expr::Let(_, ty, val, body) => {
1150 self.let_count += 1;
1151 self.visit(ty, _depth + 1);
1152 self.visit(val, _depth + 1);
1153 self.visit(body, _depth + 1);
1154 }
1155 Expr::Proj(_, _, e) => {
1156 self.visit(e, _depth + 1);
1157 }
1158 }
1159 }
1160}
1161#[allow(dead_code)]
1163pub struct StackCalc {
1164 stack: Vec<i64>,
1165}
1166#[allow(dead_code)]
1167impl StackCalc {
1168 pub fn new() -> Self {
1170 Self { stack: Vec::new() }
1171 }
1172 pub fn push(&mut self, n: i64) {
1174 self.stack.push(n);
1175 }
1176 fn apply_binary(&mut self, op: impl FnOnce(i64, i64) -> i64) -> Option<i64> {
1180 let (rest_len, a, b) = match self.stack[..] {
1181 [ref rest @ .., a, b] => (rest.len(), a, b),
1182 _ => return None,
1183 };
1184 let value = op(a, b);
1185 self.stack.truncate(rest_len);
1186 self.stack.push(value);
1187 Some(value)
1188 }
1189 pub fn add(&mut self) -> Option<i64> {
1193 self.apply_binary(|a, b| a + b)
1194 }
1195 pub fn sub(&mut self) -> Option<i64> {
1199 self.apply_binary(|a, b| a - b)
1200 }
1201 pub fn mul(&mut self) -> Option<i64> {
1205 self.apply_binary(|a, b| a * b)
1206 }
1207 pub fn peek(&self) -> Option<i64> {
1209 self.stack.last().copied()
1210 }
1211 pub fn depth(&self) -> usize {
1213 self.stack.len()
1214 }
1215}
1216#[allow(dead_code)]
1218pub enum Either2<A, B> {
1219 First(A),
1221 Second(B),
1223}
1224#[allow(dead_code)]
1225impl<A, B> Either2<A, B> {
1226 pub fn is_first(&self) -> bool {
1228 matches!(self, Either2::First(_))
1229 }
1230 pub fn is_second(&self) -> bool {
1232 matches!(self, Either2::Second(_))
1233 }
1234 pub fn first(self) -> Option<A> {
1236 match self {
1237 Either2::First(a) => Some(a),
1238 _ => None,
1239 }
1240 }
1241 pub fn second(self) -> Option<B> {
1243 match self {
1244 Either2::Second(b) => Some(b),
1245 _ => None,
1246 }
1247 }
1248 pub fn map_first<C, F: FnOnce(A) -> C>(self, f: F) -> Either2<C, B> {
1250 match self {
1251 Either2::First(a) => Either2::First(f(a)),
1252 Either2::Second(b) => Either2::Second(b),
1253 }
1254 }
1255}
1256#[allow(dead_code)]
1258pub struct Fixture {
1259 data: std::collections::HashMap<String, String>,
1260}
1261#[allow(dead_code)]
1262impl Fixture {
1263 pub fn new() -> Self {
1265 Self {
1266 data: std::collections::HashMap::new(),
1267 }
1268 }
1269 pub fn set(&mut self, key: impl Into<String>, val: impl Into<String>) {
1271 self.data.insert(key.into(), val.into());
1272 }
1273 pub fn get(&self, key: &str) -> Option<&str> {
1275 self.data.get(key).map(|s| s.as_str())
1276 }
1277 pub fn len(&self) -> usize {
1279 self.data.len()
1280 }
1281 pub fn is_empty(&self) -> bool {
1283 self.len() == 0
1284 }
1285}
1286#[allow(dead_code)]
1288#[allow(missing_docs)]
1289pub enum DecisionNode {
1290 Leaf(String),
1292 Branch {
1294 key: String,
1295 val: String,
1296 yes_branch: Box<DecisionNode>,
1297 no_branch: Box<DecisionNode>,
1298 },
1299}
1300#[allow(dead_code)]
1301impl DecisionNode {
1302 pub fn evaluate(&self, ctx: &std::collections::HashMap<String, String>) -> &str {
1304 match self {
1305 DecisionNode::Leaf(action) => action.as_str(),
1306 DecisionNode::Branch {
1307 key,
1308 val,
1309 yes_branch,
1310 no_branch,
1311 } => {
1312 let actual = ctx.get(key).map(|s| s.as_str()).unwrap_or("");
1313 if actual == val.as_str() {
1314 yes_branch.evaluate(ctx)
1315 } else {
1316 no_branch.evaluate(ctx)
1317 }
1318 }
1319 }
1320 }
1321 pub fn depth(&self) -> usize {
1323 match self {
1324 DecisionNode::Leaf(_) => 0,
1325 DecisionNode::Branch {
1326 yes_branch,
1327 no_branch,
1328 ..
1329 } => 1 + yes_branch.depth().max(no_branch.depth()),
1330 }
1331 }
1332}
1333#[allow(dead_code)]
1335pub struct FocusStack<T> {
1336 items: Vec<T>,
1337}
1338#[allow(dead_code)]
1339impl<T> FocusStack<T> {
1340 pub fn new() -> Self {
1342 Self { items: Vec::new() }
1343 }
1344 pub fn focus(&mut self, item: T) {
1346 self.items.push(item);
1347 }
1348 pub fn blur(&mut self) -> Option<T> {
1350 self.items.pop()
1351 }
1352 pub fn current(&self) -> Option<&T> {
1354 self.items.last()
1355 }
1356 pub fn depth(&self) -> usize {
1358 self.items.len()
1359 }
1360 pub fn is_empty(&self) -> bool {
1362 self.items.is_empty()
1363 }
1364}
1365#[allow(dead_code)]
1367pub struct Stopwatch {
1368 start: crate::wall_clock::Instant,
1369 splits: Vec<f64>,
1370}
1371#[allow(dead_code)]
1372impl Stopwatch {
1373 pub fn start() -> Self {
1375 Self {
1376 start: crate::wall_clock::Instant::now(),
1377 splits: Vec::new(),
1378 }
1379 }
1380 pub fn split(&mut self) {
1382 self.splits.push(self.elapsed_ms());
1383 }
1384 pub fn elapsed_ms(&self) -> f64 {
1386 self.start.elapsed().as_secs_f64() * 1000.0
1387 }
1388 pub fn splits(&self) -> &[f64] {
1390 &self.splits
1391 }
1392 pub fn num_splits(&self) -> usize {
1394 self.splits.len()
1395 }
1396}
1397#[allow(dead_code)]
1399pub struct SparseVec<T: Default + Clone + PartialEq> {
1400 entries: std::collections::HashMap<usize, T>,
1401 default_: T,
1402 logical_len: usize,
1403}
1404#[allow(dead_code)]
1405impl<T: Default + Clone + PartialEq> SparseVec<T> {
1406 pub fn new(len: usize) -> Self {
1408 Self {
1409 entries: std::collections::HashMap::new(),
1410 default_: T::default(),
1411 logical_len: len,
1412 }
1413 }
1414 pub fn set(&mut self, idx: usize, val: T) {
1416 if val == self.default_ {
1417 self.entries.remove(&idx);
1418 } else {
1419 self.entries.insert(idx, val);
1420 }
1421 }
1422 pub fn get(&self, idx: usize) -> &T {
1424 self.entries.get(&idx).unwrap_or(&self.default_)
1425 }
1426 pub fn len(&self) -> usize {
1428 self.logical_len
1429 }
1430 pub fn is_empty(&self) -> bool {
1432 self.len() == 0
1433 }
1434 pub fn nnz(&self) -> usize {
1436 self.entries.len()
1437 }
1438}
1439#[allow(dead_code)]
1442#[derive(Clone, Debug)]
1443pub struct ProofCertificate {
1444 pub proposition: Expr,
1446 pub proof_term: Expr,
1448 pub is_constructive: bool,
1450 pub has_sorry: bool,
1452}
1453impl ProofCertificate {
1454 #[allow(dead_code)]
1456 pub fn new(proposition: Expr, proof_term: Expr) -> Self {
1457 let is_constructive = ProofAnalyzer::is_constructive(&proof_term);
1458 let has_sorry = crate::proof::contains_classical_sorry(&proof_term);
1459 Self {
1460 proposition,
1461 proof_term,
1462 is_constructive,
1463 has_sorry,
1464 }
1465 }
1466 #[allow(dead_code)]
1468 pub fn is_trusted(&self) -> bool {
1469 !self.has_sorry && self.is_constructive
1470 }
1471}
1472#[allow(dead_code)]
1474pub struct TokenBucket {
1475 capacity: u64,
1476 tokens: u64,
1477 refill_per_ms: u64,
1478 last_refill: crate::wall_clock::Instant,
1479}
1480#[allow(dead_code)]
1481impl TokenBucket {
1482 pub fn new(capacity: u64, refill_per_ms: u64) -> Self {
1484 Self {
1485 capacity,
1486 tokens: capacity,
1487 refill_per_ms,
1488 last_refill: crate::wall_clock::Instant::now(),
1489 }
1490 }
1491 pub fn try_consume(&mut self, n: u64) -> bool {
1493 self.refill();
1494 if self.tokens >= n {
1495 self.tokens -= n;
1496 true
1497 } else {
1498 false
1499 }
1500 }
1501 fn refill(&mut self) {
1502 let now = crate::wall_clock::Instant::now();
1503 let elapsed_ms = now.duration_since(self.last_refill).as_millis() as u64;
1504 if elapsed_ms > 0 {
1505 let new_tokens = elapsed_ms * self.refill_per_ms;
1506 self.tokens = (self.tokens + new_tokens).min(self.capacity);
1507 self.last_refill = now;
1508 }
1509 }
1510 pub fn available(&self) -> u64 {
1512 self.tokens
1513 }
1514 pub fn capacity(&self) -> u64 {
1516 self.capacity
1517 }
1518}
1519#[allow(dead_code)]
1521pub struct ConfigNode {
1522 key: String,
1523 value: Option<String>,
1524 children: Vec<ConfigNode>,
1525}
1526#[allow(dead_code)]
1527impl ConfigNode {
1528 pub fn leaf(key: impl Into<String>, value: impl Into<String>) -> Self {
1530 Self {
1531 key: key.into(),
1532 value: Some(value.into()),
1533 children: Vec::new(),
1534 }
1535 }
1536 pub fn section(key: impl Into<String>) -> Self {
1538 Self {
1539 key: key.into(),
1540 value: None,
1541 children: Vec::new(),
1542 }
1543 }
1544 pub fn add_child(&mut self, child: ConfigNode) {
1546 self.children.push(child);
1547 }
1548 pub fn key(&self) -> &str {
1550 &self.key
1551 }
1552 pub fn value(&self) -> Option<&str> {
1554 self.value.as_deref()
1555 }
1556 pub fn num_children(&self) -> usize {
1558 self.children.len()
1559 }
1560 pub fn lookup(&self, path: &str) -> Option<&str> {
1562 let mut parts = path.splitn(2, '.');
1563 let head = parts.next()?;
1564 let tail = parts.next();
1565 if head != self.key {
1566 return None;
1567 }
1568 match tail {
1569 None => self.value.as_deref(),
1570 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
1571 }
1572 }
1573 fn lookup_relative(&self, path: &str) -> Option<&str> {
1574 let mut parts = path.splitn(2, '.');
1575 let head = parts.next()?;
1576 let tail = parts.next();
1577 if head != self.key {
1578 return None;
1579 }
1580 match tail {
1581 None => self.value.as_deref(),
1582 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
1583 }
1584 }
1585}
1586#[allow(dead_code)]
1588pub struct VersionedRecord<T: Clone> {
1589 earlier: Vec<T>,
1591 current: T,
1593}
1594#[allow(dead_code)]
1595impl<T: Clone> VersionedRecord<T> {
1596 pub fn new(initial: T) -> Self {
1598 Self {
1599 earlier: Vec::new(),
1600 current: initial,
1601 }
1602 }
1603 pub fn update(&mut self, val: T) {
1605 let previous = std::mem::replace(&mut self.current, val);
1606 self.earlier.push(previous);
1607 }
1608 pub fn current(&self) -> &T {
1610 &self.current
1611 }
1612 pub fn at_version(&self, n: usize) -> Option<&T> {
1614 match self.earlier.get(n) {
1615 Some(value) => Some(value),
1616 None if n == self.earlier.len() => Some(&self.current),
1617 None => None,
1618 }
1619 }
1620 pub fn version(&self) -> usize {
1622 self.earlier.len()
1623 }
1624 pub fn has_history(&self) -> bool {
1626 !self.earlier.is_empty()
1627 }
1628}
1629#[allow(dead_code)]
1631pub struct MinHeap<T: Ord> {
1632 data: Vec<T>,
1633}
1634#[allow(dead_code)]
1635impl<T: Ord> MinHeap<T> {
1636 pub fn new() -> Self {
1638 Self { data: Vec::new() }
1639 }
1640 pub fn push(&mut self, val: T) {
1642 self.data.push(val);
1643 self.sift_up(self.data.len() - 1);
1644 }
1645 pub fn pop(&mut self) -> Option<T> {
1647 if self.data.is_empty() {
1648 return None;
1649 }
1650 let n = self.data.len();
1651 self.data.swap(0, n - 1);
1652 let min = self.data.pop();
1653 if !self.data.is_empty() {
1654 self.sift_down(0);
1655 }
1656 min
1657 }
1658 pub fn peek(&self) -> Option<&T> {
1660 self.data.first()
1661 }
1662 pub fn len(&self) -> usize {
1664 self.data.len()
1665 }
1666 pub fn is_empty(&self) -> bool {
1668 self.data.is_empty()
1669 }
1670 fn sift_up(&mut self, mut i: usize) {
1671 while i > 0 {
1672 let parent = (i - 1) / 2;
1673 if self.data[i] < self.data[parent] {
1674 self.data.swap(i, parent);
1675 i = parent;
1676 } else {
1677 break;
1678 }
1679 }
1680 }
1681 fn sift_down(&mut self, mut i: usize) {
1682 let n = self.data.len();
1683 loop {
1684 let left = 2 * i + 1;
1685 let right = 2 * i + 2;
1686 let mut smallest = i;
1687 if left < n && self.data[left] < self.data[smallest] {
1688 smallest = left;
1689 }
1690 if right < n && self.data[right] < self.data[smallest] {
1691 smallest = right;
1692 }
1693 if smallest == i {
1694 break;
1695 }
1696 self.data.swap(i, smallest);
1697 i = smallest;
1698 }
1699 }
1700}
1701#[allow(dead_code)]
1703#[derive(Debug, Clone)]
1704pub struct ProofObligation {
1705 pub label: String,
1707 pub proposition: Expr,
1709 pub discharged: bool,
1711 pub proof_term: Option<Expr>,
1713}
1714impl ProofObligation {
1715 #[allow(dead_code)]
1717 pub fn new(label: impl Into<String>, proposition: Expr) -> Self {
1718 ProofObligation {
1719 label: label.into(),
1720 proposition,
1721 discharged: false,
1722 proof_term: None,
1723 }
1724 }
1725 #[allow(dead_code)]
1727 pub fn discharge(&mut self, proof: Expr) {
1728 self.proof_term = Some(proof);
1729 self.discharged = true;
1730 }
1731 #[allow(dead_code)]
1733 pub fn is_discharged(&self) -> bool {
1734 self.discharged
1735 }
1736}