1use super::functions::*;
6use crate::expr_util::{get_app_args, get_app_fn, mk_app};
7use crate::instantiate::instantiate_type_lparams;
8use crate::subst::instantiate;
9use crate::{Environment, Expr, Literal, Name};
10use std::collections::HashMap;
11
12#[allow(dead_code)]
14pub enum Either2<A, B> {
15 First(A),
17 Second(B),
19}
20#[allow(dead_code)]
21impl<A, B> Either2<A, B> {
22 pub fn is_first(&self) -> bool {
24 matches!(self, Either2::First(_))
25 }
26 pub fn is_second(&self) -> bool {
28 matches!(self, Either2::Second(_))
29 }
30 pub fn first(self) -> Option<A> {
32 match self {
33 Either2::First(a) => Some(a),
34 _ => None,
35 }
36 }
37 pub fn second(self) -> Option<B> {
39 match self {
40 Either2::Second(b) => Some(b),
41 _ => None,
42 }
43 }
44 pub fn map_first<C, F: FnOnce(A) -> C>(self, f: F) -> Either2<C, B> {
46 match self {
47 Either2::First(a) => Either2::First(f(a)),
48 Either2::Second(b) => Either2::Second(b),
49 }
50 }
51}
52#[allow(dead_code)]
54pub struct StatSummary {
55 count: u64,
56 sum: f64,
57 min: f64,
58 max: f64,
59}
60#[allow(dead_code)]
61impl StatSummary {
62 pub fn new() -> Self {
64 Self {
65 count: 0,
66 sum: 0.0,
67 min: f64::INFINITY,
68 max: f64::NEG_INFINITY,
69 }
70 }
71 pub fn record(&mut self, val: f64) {
73 self.count += 1;
74 self.sum += val;
75 if val < self.min {
76 self.min = val;
77 }
78 if val > self.max {
79 self.max = val;
80 }
81 }
82 pub fn mean(&self) -> Option<f64> {
84 if self.count == 0 {
85 None
86 } else {
87 Some(self.sum / self.count as f64)
88 }
89 }
90 pub fn min(&self) -> Option<f64> {
92 if self.count == 0 {
93 None
94 } else {
95 Some(self.min)
96 }
97 }
98 pub fn max(&self) -> Option<f64> {
100 if self.count == 0 {
101 None
102 } else {
103 Some(self.max)
104 }
105 }
106 pub fn count(&self) -> u64 {
108 self.count
109 }
110}
111#[allow(dead_code)]
113pub struct TokenBucket {
114 capacity: u64,
115 tokens: u64,
116 refill_per_ms: u64,
117 last_refill: std::time::Instant,
118}
119#[allow(dead_code)]
120impl TokenBucket {
121 pub fn new(capacity: u64, refill_per_ms: u64) -> Self {
123 Self {
124 capacity,
125 tokens: capacity,
126 refill_per_ms,
127 last_refill: std::time::Instant::now(),
128 }
129 }
130 pub fn try_consume(&mut self, n: u64) -> bool {
132 self.refill();
133 if self.tokens >= n {
134 self.tokens -= n;
135 true
136 } else {
137 false
138 }
139 }
140 fn refill(&mut self) {
141 let now = std::time::Instant::now();
142 let elapsed_ms = now.duration_since(self.last_refill).as_millis() as u64;
143 if elapsed_ms > 0 {
144 let new_tokens = elapsed_ms * self.refill_per_ms;
145 self.tokens = (self.tokens + new_tokens).min(self.capacity);
146 self.last_refill = now;
147 }
148 }
149 pub fn available(&self) -> u64 {
151 self.tokens
152 }
153 pub fn capacity(&self) -> u64 {
155 self.capacity
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 StackCalc {
241 stack: Vec<i64>,
242}
243#[allow(dead_code)]
244impl StackCalc {
245 pub fn new() -> Self {
247 Self { stack: Vec::new() }
248 }
249 pub fn push(&mut self, n: i64) {
251 self.stack.push(n);
252 }
253 pub fn add(&mut self) {
255 let b = self
256 .stack
257 .pop()
258 .expect("stack must have at least two values for add");
259 let a = self
260 .stack
261 .pop()
262 .expect("stack must have at least two values for add");
263 self.stack.push(a + b);
264 }
265 pub fn sub(&mut self) {
267 let b = self
268 .stack
269 .pop()
270 .expect("stack must have at least two values for sub");
271 let a = self
272 .stack
273 .pop()
274 .expect("stack must have at least two values for sub");
275 self.stack.push(a - b);
276 }
277 pub fn mul(&mut self) {
279 let b = self
280 .stack
281 .pop()
282 .expect("stack must have at least two values for mul");
283 let a = self
284 .stack
285 .pop()
286 .expect("stack must have at least two values for mul");
287 self.stack.push(a * b);
288 }
289 pub fn peek(&self) -> Option<i64> {
291 self.stack.last().copied()
292 }
293 pub fn depth(&self) -> usize {
295 self.stack.len()
296 }
297}
298#[allow(dead_code)]
300#[allow(missing_docs)]
301pub enum DecisionNode {
302 Leaf(String),
304 Branch {
306 key: String,
307 val: String,
308 yes_branch: Box<DecisionNode>,
309 no_branch: Box<DecisionNode>,
310 },
311}
312#[allow(dead_code)]
313impl DecisionNode {
314 pub fn evaluate(&self, ctx: &std::collections::HashMap<String, String>) -> &str {
316 match self {
317 DecisionNode::Leaf(action) => action.as_str(),
318 DecisionNode::Branch {
319 key,
320 val,
321 yes_branch,
322 no_branch,
323 } => {
324 let actual = ctx.get(key).map(|s| s.as_str()).unwrap_or("");
325 if actual == val.as_str() {
326 yes_branch.evaluate(ctx)
327 } else {
328 no_branch.evaluate(ctx)
329 }
330 }
331 }
332 }
333 pub fn depth(&self) -> usize {
335 match self {
336 DecisionNode::Leaf(_) => 0,
337 DecisionNode::Branch {
338 yes_branch,
339 no_branch,
340 ..
341 } => 1 + yes_branch.depth().max(no_branch.depth()),
342 }
343 }
344}
345#[allow(dead_code)]
347pub struct SmallMap<K: Ord + Clone, V: Clone> {
348 entries: Vec<(K, V)>,
349}
350#[allow(dead_code)]
351impl<K: Ord + Clone, V: Clone> SmallMap<K, V> {
352 pub fn new() -> Self {
354 Self {
355 entries: Vec::new(),
356 }
357 }
358 pub fn insert(&mut self, key: K, val: V) {
360 match self.entries.binary_search_by_key(&&key, |(k, _)| k) {
361 Ok(i) => self.entries[i].1 = val,
362 Err(i) => self.entries.insert(i, (key, val)),
363 }
364 }
365 pub fn get(&self, key: &K) -> Option<&V> {
367 self.entries
368 .binary_search_by_key(&key, |(k, _)| k)
369 .ok()
370 .map(|i| &self.entries[i].1)
371 }
372 pub fn len(&self) -> usize {
374 self.entries.len()
375 }
376 pub fn is_empty(&self) -> bool {
378 self.entries.is_empty()
379 }
380 pub fn keys(&self) -> Vec<&K> {
382 self.entries.iter().map(|(k, _)| k).collect()
383 }
384 pub fn values(&self) -> Vec<&V> {
386 self.entries.iter().map(|(_, v)| v).collect()
387 }
388}
389#[allow(dead_code)]
391#[derive(Debug, Clone, PartialEq, Eq)]
392pub enum ReductionRule {
393 Beta,
395 Delta,
397 Zeta,
399 Iota,
401 Proj,
403 Quot,
405 NatLit,
407 StrLit,
409 None,
411}
412#[allow(dead_code)]
414pub struct WindowIterator<'a, T> {
415 pub(super) data: &'a [T],
416 pub(super) pos: usize,
417 pub(super) window: usize,
418}
419#[allow(dead_code)]
420impl<'a, T> WindowIterator<'a, T> {
421 pub fn new(data: &'a [T], window: usize) -> Self {
423 Self {
424 data,
425 pos: 0,
426 window,
427 }
428 }
429}
430#[allow(dead_code)]
432pub struct SparseVec<T: Default + Clone + PartialEq> {
433 entries: std::collections::HashMap<usize, T>,
434 default_: T,
435 logical_len: usize,
436}
437#[allow(dead_code)]
438impl<T: Default + Clone + PartialEq> SparseVec<T> {
439 pub fn new(len: usize) -> Self {
441 Self {
442 entries: std::collections::HashMap::new(),
443 default_: T::default(),
444 logical_len: len,
445 }
446 }
447 pub fn set(&mut self, idx: usize, val: T) {
449 if val == self.default_ {
450 self.entries.remove(&idx);
451 } else {
452 self.entries.insert(idx, val);
453 }
454 }
455 pub fn get(&self, idx: usize) -> &T {
457 self.entries.get(&idx).unwrap_or(&self.default_)
458 }
459 pub fn len(&self) -> usize {
461 self.logical_len
462 }
463 pub fn is_empty(&self) -> bool {
465 self.len() == 0
466 }
467 pub fn nnz(&self) -> usize {
469 self.entries.len()
470 }
471}
472#[allow(dead_code)]
474pub struct SimpleDag {
475 edges: Vec<Vec<usize>>,
477}
478#[allow(dead_code)]
479impl SimpleDag {
480 pub fn new(n: usize) -> Self {
482 Self {
483 edges: vec![Vec::new(); n],
484 }
485 }
486 pub fn add_edge(&mut self, from: usize, to: usize) {
488 if from < self.edges.len() {
489 self.edges[from].push(to);
490 }
491 }
492 pub fn successors(&self, node: usize) -> &[usize] {
494 self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
495 }
496 pub fn can_reach(&self, from: usize, to: usize) -> bool {
498 let mut visited = vec![false; self.edges.len()];
499 self.dfs(from, to, &mut visited)
500 }
501 fn dfs(&self, cur: usize, target: usize, visited: &mut Vec<bool>) -> bool {
502 if cur == target {
503 return true;
504 }
505 if cur >= visited.len() || visited[cur] {
506 return false;
507 }
508 visited[cur] = true;
509 for &next in self.successors(cur) {
510 if self.dfs(next, target, visited) {
511 return true;
512 }
513 }
514 false
515 }
516 pub fn topological_sort(&self) -> Option<Vec<usize>> {
518 let n = self.edges.len();
519 let mut in_degree = vec![0usize; n];
520 for succs in &self.edges {
521 for &s in succs {
522 if s < n {
523 in_degree[s] += 1;
524 }
525 }
526 }
527 let mut queue: std::collections::VecDeque<usize> =
528 (0..n).filter(|&i| in_degree[i] == 0).collect();
529 let mut order = Vec::new();
530 while let Some(node) = queue.pop_front() {
531 order.push(node);
532 for &s in self.successors(node) {
533 if s < n {
534 in_degree[s] -= 1;
535 if in_degree[s] == 0 {
536 queue.push_back(s);
537 }
538 }
539 }
540 }
541 if order.len() == n {
542 Some(order)
543 } else {
544 None
545 }
546 }
547 pub fn num_nodes(&self) -> usize {
549 self.edges.len()
550 }
551}
552#[allow(dead_code)]
554pub struct FocusStack<T> {
555 items: Vec<T>,
556}
557#[allow(dead_code)]
558impl<T> FocusStack<T> {
559 pub fn new() -> Self {
561 Self { items: Vec::new() }
562 }
563 pub fn focus(&mut self, item: T) {
565 self.items.push(item);
566 }
567 pub fn blur(&mut self) -> Option<T> {
569 self.items.pop()
570 }
571 pub fn current(&self) -> Option<&T> {
573 self.items.last()
574 }
575 pub fn depth(&self) -> usize {
577 self.items.len()
578 }
579 pub fn is_empty(&self) -> bool {
581 self.items.is_empty()
582 }
583}
584#[allow(dead_code)]
586pub struct VersionedRecord<T: Clone> {
587 history: Vec<T>,
588}
589#[allow(dead_code)]
590impl<T: Clone> VersionedRecord<T> {
591 pub fn new(initial: T) -> Self {
593 Self {
594 history: vec![initial],
595 }
596 }
597 pub fn update(&mut self, val: T) {
599 self.history.push(val);
600 }
601 pub fn current(&self) -> &T {
603 self.history
604 .last()
605 .expect("VersionedRecord history is always non-empty after construction")
606 }
607 pub fn at_version(&self, n: usize) -> Option<&T> {
609 self.history.get(n)
610 }
611 pub fn version(&self) -> usize {
613 self.history.len() - 1
614 }
615 pub fn has_history(&self) -> bool {
617 self.history.len() > 1
618 }
619}
620#[allow(dead_code)]
622#[allow(missing_docs)]
623pub struct RewriteRule {
624 pub name: String,
626 pub lhs: String,
628 pub rhs: String,
630 pub conditional: bool,
632}
633#[allow(dead_code)]
634impl RewriteRule {
635 pub fn unconditional(
637 name: impl Into<String>,
638 lhs: impl Into<String>,
639 rhs: impl Into<String>,
640 ) -> Self {
641 Self {
642 name: name.into(),
643 lhs: lhs.into(),
644 rhs: rhs.into(),
645 conditional: false,
646 }
647 }
648 pub fn conditional(
650 name: impl Into<String>,
651 lhs: impl Into<String>,
652 rhs: impl Into<String>,
653 ) -> Self {
654 Self {
655 name: name.into(),
656 lhs: lhs.into(),
657 rhs: rhs.into(),
658 conditional: true,
659 }
660 }
661 pub fn display(&self) -> String {
663 format!("{}: {} → {}", self.name, self.lhs, self.rhs)
664 }
665}
666#[allow(dead_code)]
668pub struct TransitiveClosure {
669 adj: Vec<Vec<usize>>,
670 n: usize,
671}
672#[allow(dead_code)]
673impl TransitiveClosure {
674 pub fn new(n: usize) -> Self {
676 Self {
677 adj: vec![Vec::new(); n],
678 n,
679 }
680 }
681 pub fn add_edge(&mut self, from: usize, to: usize) {
683 if from < self.n {
684 self.adj[from].push(to);
685 }
686 }
687 pub fn reachable_from(&self, start: usize) -> Vec<usize> {
689 let mut visited = vec![false; self.n];
690 let mut queue = std::collections::VecDeque::new();
691 queue.push_back(start);
692 while let Some(node) = queue.pop_front() {
693 if node >= self.n || visited[node] {
694 continue;
695 }
696 visited[node] = true;
697 for &next in &self.adj[node] {
698 queue.push_back(next);
699 }
700 }
701 (0..self.n).filter(|&i| visited[i]).collect()
702 }
703 pub fn can_reach(&self, from: usize, to: usize) -> bool {
705 self.reachable_from(from).contains(&to)
706 }
707}
708#[allow(dead_code)]
710#[derive(Debug, Default, Clone)]
711pub struct ReducerStats {
712 pub whnf_calls: u64,
714 pub cache_hits: u64,
716 pub beta_count: u64,
718 pub delta_count: u64,
720 pub iota_count: u64,
722 pub zeta_count: u64,
724 pub nat_lit_count: u64,
726}
727impl ReducerStats {
728 #[allow(dead_code)]
730 pub fn total_reductions(&self) -> u64 {
731 self.beta_count + self.delta_count + self.iota_count + self.zeta_count + self.nat_lit_count
732 }
733 #[allow(dead_code)]
735 pub fn cache_hit_rate(&self) -> f64 {
736 if self.whnf_calls == 0 {
737 0.0
738 } else {
739 self.cache_hits as f64 / self.whnf_calls as f64
740 }
741 }
742 #[allow(dead_code)]
744 pub fn display(&self) -> String {
745 format!(
746 "whnf:{} hits:{} β:{} δ:{} ι:{} ζ:{} lit:{}",
747 self.whnf_calls,
748 self.cache_hits,
749 self.beta_count,
750 self.delta_count,
751 self.iota_count,
752 self.zeta_count,
753 self.nat_lit_count,
754 )
755 }
756}
757#[allow(dead_code)]
759pub struct PathBuf {
760 components: Vec<String>,
761}
762#[allow(dead_code)]
763impl PathBuf {
764 pub fn new() -> Self {
766 Self {
767 components: Vec::new(),
768 }
769 }
770 pub fn push(&mut self, comp: impl Into<String>) {
772 self.components.push(comp.into());
773 }
774 pub fn pop(&mut self) {
776 self.components.pop();
777 }
778 pub fn as_str(&self) -> String {
780 self.components.join("/")
781 }
782 pub fn depth(&self) -> usize {
784 self.components.len()
785 }
786 pub fn clear(&mut self) {
788 self.components.clear();
789 }
790}
791#[allow(dead_code)]
793pub struct ConfigNode {
794 key: String,
795 value: Option<String>,
796 children: Vec<ConfigNode>,
797}
798#[allow(dead_code)]
799impl ConfigNode {
800 pub fn leaf(key: impl Into<String>, value: impl Into<String>) -> Self {
802 Self {
803 key: key.into(),
804 value: Some(value.into()),
805 children: Vec::new(),
806 }
807 }
808 pub fn section(key: impl Into<String>) -> Self {
810 Self {
811 key: key.into(),
812 value: None,
813 children: Vec::new(),
814 }
815 }
816 pub fn add_child(&mut self, child: ConfigNode) {
818 self.children.push(child);
819 }
820 pub fn key(&self) -> &str {
822 &self.key
823 }
824 pub fn value(&self) -> Option<&str> {
826 self.value.as_deref()
827 }
828 pub fn num_children(&self) -> usize {
830 self.children.len()
831 }
832 pub fn lookup(&self, path: &str) -> Option<&str> {
834 let mut parts = path.splitn(2, '.');
835 let head = parts.next()?;
836 let tail = parts.next();
837 if head != self.key {
838 return None;
839 }
840 match tail {
841 None => self.value.as_deref(),
842 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
843 }
844 }
845 fn lookup_relative(&self, path: &str) -> Option<&str> {
846 let mut parts = path.splitn(2, '.');
847 let head = parts.next()?;
848 let tail = parts.next();
849 if head != self.key {
850 return None;
851 }
852 match tail {
853 None => self.value.as_deref(),
854 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
855 }
856 }
857}
858#[allow(dead_code)]
860pub struct NonEmptyVec<T> {
861 head: T,
862 tail: Vec<T>,
863}
864#[allow(dead_code)]
865impl<T> NonEmptyVec<T> {
866 pub fn singleton(val: T) -> Self {
868 Self {
869 head: val,
870 tail: Vec::new(),
871 }
872 }
873 pub fn push(&mut self, val: T) {
875 self.tail.push(val);
876 }
877 pub fn first(&self) -> &T {
879 &self.head
880 }
881 pub fn last(&self) -> &T {
883 self.tail.last().unwrap_or(&self.head)
884 }
885 pub fn len(&self) -> usize {
887 1 + self.tail.len()
888 }
889 pub fn is_empty(&self) -> bool {
891 self.len() == 0
892 }
893 pub fn to_vec(&self) -> Vec<&T> {
895 let mut v = vec![&self.head];
896 v.extend(self.tail.iter());
897 v
898 }
899}
900#[allow(dead_code)]
902pub struct StringPool {
903 free: Vec<String>,
904}
905#[allow(dead_code)]
906impl StringPool {
907 pub fn new() -> Self {
909 Self { free: Vec::new() }
910 }
911 pub fn take(&mut self) -> String {
913 self.free.pop().unwrap_or_default()
914 }
915 pub fn give(&mut self, mut s: String) {
917 s.clear();
918 self.free.push(s);
919 }
920 pub fn free_count(&self) -> usize {
922 self.free.len()
923 }
924}
925pub struct Reducer {
927 pub(crate) cache: HashMap<Expr, Expr>,
929 max_depth: u32,
931 transparency: TransparencyMode,
933}
934impl Reducer {
935 pub fn new() -> Self {
937 Self {
938 cache: HashMap::new(),
939 max_depth: 10000,
940 transparency: TransparencyMode::Default,
941 }
942 }
943 pub fn with_max_depth(max_depth: u32) -> Self {
945 Self {
946 cache: HashMap::new(),
947 max_depth,
948 transparency: TransparencyMode::Default,
949 }
950 }
951 pub fn set_transparency(&mut self, mode: TransparencyMode) {
953 if self.transparency != mode {
954 self.transparency = mode;
955 self.cache.clear();
956 }
957 }
958 pub fn clear_cache(&mut self) {
960 self.cache.clear();
961 }
962 pub fn whnf(&mut self, expr: &Expr) -> Expr {
966 self.whnf_with_depth(expr, 0)
967 }
968 fn whnf_with_depth(&mut self, expr: &Expr, depth: u32) -> Expr {
969 if depth > self.max_depth {
970 return expr.clone();
971 }
972 if let Some(cached) = self.cache.get(expr) {
973 return cached.clone();
974 }
975 let result = match expr {
976 Expr::Sort(_)
977 | Expr::BVar(_)
978 | Expr::FVar(_)
979 | Expr::Const(_, _)
980 | Expr::Lam(_, _, _, _)
981 | Expr::Pi(_, _, _, _)
982 | Expr::Lit(_) => expr.clone(),
983 Expr::App(f, a) => {
984 let f_whnf = self.whnf_with_depth(f, depth + 1);
985 match f_whnf {
986 Expr::Lam(_, _, _, body) => {
987 let reduced = instantiate(&body, a);
988 self.whnf_with_depth(&reduced, depth + 1)
989 }
990 _ => Expr::App(Box::new(f_whnf), a.clone()),
991 }
992 }
993 Expr::Let(_, _, val, body) => {
994 let reduced = instantiate(body, val);
995 self.whnf_with_depth(&reduced, depth + 1)
996 }
997 Expr::Proj(struct_name, idx, struct_expr) => {
998 let struct_whnf = self.whnf_with_depth(struct_expr, depth + 1);
999 Expr::Proj(struct_name.clone(), *idx, Box::new(struct_whnf))
1000 }
1001 };
1002 self.cache.insert(expr.clone(), result.clone());
1003 result
1004 }
1005 pub fn whnf_delta<F>(&mut self, expr: &Expr, lookup: &F) -> Expr
1009 where
1010 F: Fn(&crate::Name) -> Option<(Expr, ReducibilityHint)>,
1011 {
1012 self.whnf_delta_with_depth(expr, lookup, 0)
1013 }
1014 fn whnf_delta_with_depth<F>(&mut self, expr: &Expr, lookup: &F, depth: u32) -> Expr
1015 where
1016 F: Fn(&crate::Name) -> Option<(Expr, ReducibilityHint)>,
1017 {
1018 if depth > self.max_depth {
1019 return expr.clone();
1020 }
1021 match expr {
1022 Expr::Sort(_)
1023 | Expr::BVar(_)
1024 | Expr::FVar(_)
1025 | Expr::Lam(_, _, _, _)
1026 | Expr::Pi(_, _, _, _)
1027 | Expr::Lit(_) => expr.clone(),
1028 Expr::Const(name, _levels) => {
1029 if let Some((defn, hint)) = lookup(name) {
1030 if self.should_unfold_hint(hint) {
1031 return self.whnf_delta_with_depth(&defn, lookup, depth + 1);
1032 }
1033 }
1034 expr.clone()
1035 }
1036 Expr::App(f, a) => {
1037 let f_whnf = self.whnf_delta_with_depth(f, lookup, depth + 1);
1038 match f_whnf {
1039 Expr::Lam(_, _, _, body) => {
1040 let reduced = instantiate(&body, a);
1041 self.whnf_delta_with_depth(&reduced, lookup, depth + 1)
1042 }
1043 _ => Expr::App(Box::new(f_whnf), a.clone()),
1044 }
1045 }
1046 Expr::Let(_, _, val, body) => {
1047 let reduced = instantiate(body, val);
1048 self.whnf_delta_with_depth(&reduced, lookup, depth + 1)
1049 }
1050 Expr::Proj(struct_name, idx, struct_expr) => {
1051 let struct_whnf = self.whnf_delta_with_depth(struct_expr, lookup, depth + 1);
1052 Expr::Proj(struct_name.clone(), *idx, Box::new(struct_whnf))
1053 }
1054 }
1055 }
1056 pub(crate) fn should_unfold_hint(&self, hint: ReducibilityHint) -> bool {
1058 match self.transparency {
1059 TransparencyMode::All => true,
1060 TransparencyMode::Default => hint.should_unfold(),
1061 TransparencyMode::Reducible => matches!(hint, ReducibilityHint::Abbrev),
1062 TransparencyMode::Instances => false,
1063 TransparencyMode::None => false,
1064 }
1065 }
1066 pub fn whnf_env(&mut self, expr: &Expr, env: &Environment) -> Expr {
1070 self.whnf_env_depth(expr, env, 0)
1071 }
1072 fn whnf_env_depth(&mut self, expr: &Expr, env: &Environment, depth: u32) -> Expr {
1073 if depth > self.max_depth {
1074 return expr.clone();
1075 }
1076 if let Some(cached) = self.cache.get(expr) {
1077 return cached.clone();
1078 }
1079 let result = self.whnf_core(expr, env, depth);
1080 self.cache.insert(expr.clone(), result.clone());
1081 result
1082 }
1083 fn whnf_core(&mut self, expr: &Expr, env: &Environment, depth: u32) -> Expr {
1084 match expr {
1085 Expr::Sort(_)
1086 | Expr::BVar(_)
1087 | Expr::FVar(_)
1088 | Expr::Lam(_, _, _, _)
1089 | Expr::Pi(_, _, _, _)
1090 | Expr::Lit(_) => expr.clone(),
1091 Expr::Let(_, _, val, body) => {
1092 let reduced = instantiate(body, val);
1093 self.whnf_env_depth(&reduced, env, depth + 1)
1094 }
1095 Expr::Const(name, levels) => {
1096 if let Some(ci) = env.find(name) {
1097 if let Some(val) = ci.value() {
1098 let hint = ci.reducibility_hint();
1099 if self.should_unfold_hint(hint) {
1100 let unfolded = if ci.level_params().is_empty() || levels.is_empty() {
1101 val.clone()
1102 } else {
1103 instantiate_type_lparams(val, ci.level_params(), levels)
1104 };
1105 return self.whnf_env_depth(&unfolded, env, depth + 1);
1106 }
1107 }
1108 }
1109 expr.clone()
1110 }
1111 Expr::App(_, _) => {
1112 let head = get_app_fn(expr);
1113 let args: Vec<Expr> = get_app_args(expr).into_iter().cloned().collect();
1114 let head_whnf = self.whnf_env_depth(head, env, depth + 1);
1115 if let Expr::Lam(_, _, _, _) = &head_whnf {
1116 let mut result = head_whnf;
1117 for arg in &args {
1118 match result {
1119 Expr::Lam(_, _, _, body) => {
1120 result = instantiate(&body, arg);
1121 }
1122 _ => {
1123 result = Expr::App(Box::new(result), Box::new(arg.clone()));
1124 }
1125 }
1126 }
1127 return self.whnf_env_depth(&result, env, depth + 1);
1128 }
1129 if let Some(reduced) = try_reduce_nat_app(&head_whnf, &args) {
1130 return self.whnf_env_depth(&reduced, env, depth + 1);
1131 }
1132 if let Expr::Const(name, levels) = &head_whnf {
1133 if let Some(reduced) = self.try_reduce_recursor(name, levels, &args, env, depth)
1134 {
1135 return self.whnf_env_depth(&reduced, env, depth + 1);
1136 }
1137 if let Some(reduced) = try_reduce_quot(name, &args, env) {
1138 return self.whnf_env_depth(&reduced, env, depth + 1);
1139 }
1140 }
1141 mk_app(head_whnf, &args)
1142 }
1143 Expr::Proj(struct_name, idx, struct_expr) => {
1144 let struct_whnf = self.whnf_env_depth(struct_expr, env, depth + 1);
1145 if let Some(reduced) = try_reduce_proj(struct_name, *idx, &struct_whnf, env) {
1146 return self.whnf_env_depth(&reduced, env, depth + 1);
1147 }
1148 Expr::Proj(struct_name.clone(), *idx, Box::new(struct_whnf))
1149 }
1150 }
1151 }
1152 fn try_reduce_recursor(
1154 &mut self,
1155 rec_name: &Name,
1156 rec_levels: &[crate::Level],
1157 args: &[Expr],
1158 env: &Environment,
1159 depth: u32,
1160 ) -> Option<Expr> {
1161 let rec_val = env.get_recursor_val(rec_name)?;
1162 let major_idx = rec_val.get_major_idx() as usize;
1163 if args.len() <= major_idx {
1164 return None;
1165 }
1166 let major = &args[major_idx];
1167 let major_whnf = self.whnf_env_depth(major, env, depth + 1);
1168 let ctor_fn = get_app_fn(&major_whnf);
1169 let ctor_name = if let Expr::Const(name, _) = ctor_fn {
1170 name
1171 } else {
1172 return None;
1173 };
1174 if !env.is_constructor(ctor_name) {
1175 return None;
1176 }
1177 let rule = rec_val.get_rule(ctor_name)?;
1178 let ctor_args: Vec<Expr> = get_app_args(&major_whnf).into_iter().cloned().collect();
1179 let rhs = instantiate_recursor_rhs(&rule.rhs, rec_val, rec_levels, args, &ctor_args);
1180 Some(rhs)
1181 }
1182 pub fn is_alpha_equiv(e1: &Expr, e2: &Expr) -> bool {
1184 e1 == e2
1185 }
1186}
1187#[allow(dead_code)]
1189pub struct RewriteRuleSet {
1190 rules: Vec<RewriteRule>,
1191}
1192#[allow(dead_code)]
1193impl RewriteRuleSet {
1194 pub fn new() -> Self {
1196 Self { rules: Vec::new() }
1197 }
1198 pub fn add(&mut self, rule: RewriteRule) {
1200 self.rules.push(rule);
1201 }
1202 pub fn len(&self) -> usize {
1204 self.rules.len()
1205 }
1206 pub fn is_empty(&self) -> bool {
1208 self.rules.is_empty()
1209 }
1210 pub fn conditional_rules(&self) -> Vec<&RewriteRule> {
1212 self.rules.iter().filter(|r| r.conditional).collect()
1213 }
1214 pub fn unconditional_rules(&self) -> Vec<&RewriteRule> {
1216 self.rules.iter().filter(|r| !r.conditional).collect()
1217 }
1218 pub fn get(&self, name: &str) -> Option<&RewriteRule> {
1220 self.rules.iter().find(|r| r.name == name)
1221 }
1222}
1223#[allow(dead_code)]
1225#[derive(Debug, Default)]
1226pub struct ReductionTrace {
1227 steps: Vec<ReductionStep>,
1228 enabled: bool,
1229}
1230impl ReductionTrace {
1231 #[allow(dead_code)]
1233 pub fn enabled() -> Self {
1234 Self {
1235 steps: Vec::new(),
1236 enabled: true,
1237 }
1238 }
1239 #[allow(dead_code)]
1241 pub fn disabled() -> Self {
1242 Self {
1243 steps: Vec::new(),
1244 enabled: false,
1245 }
1246 }
1247 #[allow(dead_code)]
1249 pub fn record(&mut self, rule: ReductionRule, before: Expr, after: Expr) {
1250 if self.enabled {
1251 self.steps.push(ReductionStep {
1252 rule,
1253 before,
1254 after,
1255 });
1256 }
1257 }
1258 #[allow(dead_code)]
1260 pub fn step_count(&self) -> usize {
1261 self.steps.len()
1262 }
1263 #[allow(dead_code)]
1265 pub fn steps(&self) -> &[ReductionStep] {
1266 &self.steps
1267 }
1268 #[allow(dead_code)]
1270 pub fn clear(&mut self) {
1271 self.steps.clear();
1272 }
1273 #[allow(dead_code)]
1275 pub fn count_rule(&self, rule: &ReductionRule) -> usize {
1276 self.steps.iter().filter(|s| &s.rule == rule).count()
1277 }
1278}
1279#[allow(dead_code)]
1281pub struct Stopwatch {
1282 start: std::time::Instant,
1283 splits: Vec<f64>,
1284}
1285#[allow(dead_code)]
1286impl Stopwatch {
1287 pub fn start() -> Self {
1289 Self {
1290 start: std::time::Instant::now(),
1291 splits: Vec::new(),
1292 }
1293 }
1294 pub fn split(&mut self) {
1296 self.splits.push(self.elapsed_ms());
1297 }
1298 pub fn elapsed_ms(&self) -> f64 {
1300 self.start.elapsed().as_secs_f64() * 1000.0
1301 }
1302 pub fn splits(&self) -> &[f64] {
1304 &self.splits
1305 }
1306 pub fn num_splits(&self) -> usize {
1308 self.splits.len()
1309 }
1310}
1311#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
1313pub enum TransparencyMode {
1314 All,
1316 Default,
1318 Reducible,
1320 Instances,
1322 None,
1324}
1325#[allow(dead_code)]
1327pub struct FlatSubstitution {
1328 pairs: Vec<(String, String)>,
1329}
1330#[allow(dead_code)]
1331impl FlatSubstitution {
1332 pub fn new() -> Self {
1334 Self { pairs: Vec::new() }
1335 }
1336 pub fn add(&mut self, from: impl Into<String>, to: impl Into<String>) {
1338 self.pairs.push((from.into(), to.into()));
1339 }
1340 pub fn apply(&self, s: &str) -> String {
1342 let mut result = s.to_string();
1343 for (from, to) in &self.pairs {
1344 result = result.replace(from.as_str(), to.as_str());
1345 }
1346 result
1347 }
1348 pub fn len(&self) -> usize {
1350 self.pairs.len()
1351 }
1352 pub fn is_empty(&self) -> bool {
1354 self.pairs.is_empty()
1355 }
1356}
1357#[allow(dead_code)]
1359pub struct WriteOnce<T> {
1360 value: std::cell::Cell<Option<T>>,
1361}
1362#[allow(dead_code)]
1363impl<T: Copy> WriteOnce<T> {
1364 pub fn new() -> Self {
1366 Self {
1367 value: std::cell::Cell::new(None),
1368 }
1369 }
1370 pub fn write(&self, val: T) -> bool {
1372 if self.value.get().is_some() {
1373 return false;
1374 }
1375 self.value.set(Some(val));
1376 true
1377 }
1378 pub fn read(&self) -> Option<T> {
1380 self.value.get()
1381 }
1382 pub fn is_written(&self) -> bool {
1384 self.value.get().is_some()
1385 }
1386}
1387#[allow(dead_code)]
1389pub struct TransformStat {
1390 before: StatSummary,
1391 after: StatSummary,
1392}
1393#[allow(dead_code)]
1394impl TransformStat {
1395 pub fn new() -> Self {
1397 Self {
1398 before: StatSummary::new(),
1399 after: StatSummary::new(),
1400 }
1401 }
1402 pub fn record_before(&mut self, v: f64) {
1404 self.before.record(v);
1405 }
1406 pub fn record_after(&mut self, v: f64) {
1408 self.after.record(v);
1409 }
1410 pub fn mean_ratio(&self) -> Option<f64> {
1412 let b = self.before.mean()?;
1413 let a = self.after.mean()?;
1414 if b.abs() < f64::EPSILON {
1415 return None;
1416 }
1417 Some(a / b)
1418 }
1419}
1420#[allow(dead_code)]
1422#[derive(Debug, Clone)]
1423pub struct ReductionStep {
1424 pub rule: ReductionRule,
1426 pub before: Expr,
1428 pub after: Expr,
1430}
1431#[allow(dead_code)]
1433pub struct RawFnPtr {
1434 ptr: usize,
1436 arity: usize,
1437 name: String,
1438}
1439#[allow(dead_code)]
1440impl RawFnPtr {
1441 pub fn new(ptr: usize, arity: usize, name: impl Into<String>) -> Self {
1443 Self {
1444 ptr,
1445 arity,
1446 name: name.into(),
1447 }
1448 }
1449 pub fn arity(&self) -> usize {
1451 self.arity
1452 }
1453 pub fn name(&self) -> &str {
1455 &self.name
1456 }
1457 pub fn raw(&self) -> usize {
1459 self.ptr
1460 }
1461}
1462#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1464pub enum ReducibilityHint {
1465 Opaque,
1467 Abbrev,
1469 Regular(u32),
1471}
1472impl ReducibilityHint {
1473 pub fn height(&self) -> u32 {
1475 match self {
1476 ReducibilityHint::Opaque => u32::MAX,
1477 ReducibilityHint::Abbrev => 0,
1478 ReducibilityHint::Regular(h) => *h,
1479 }
1480 }
1481 pub fn should_unfold(&self) -> bool {
1483 !matches!(self, ReducibilityHint::Opaque)
1484 }
1485}