1use super::functions::*;
6use crate::equiv_manager::EquivManager;
7use crate::expr_util::{get_app_args, get_app_fn, has_loose_bvar};
8use crate::instantiate::instantiate_type_lparams;
9use crate::level;
10use crate::reduce::{Reducer, ReducibilityHint, TransparencyMode};
11use crate::subst::instantiate;
12use crate::{Environment, Expr, Level};
13use std::collections::HashMap;
14
15#[allow(dead_code)]
17pub enum Either2<A, B> {
18 First(A),
20 Second(B),
22}
23#[allow(dead_code)]
24impl<A, B> Either2<A, B> {
25 pub fn is_first(&self) -> bool {
27 matches!(self, Either2::First(_))
28 }
29 pub fn is_second(&self) -> bool {
31 matches!(self, Either2::Second(_))
32 }
33 pub fn first(self) -> Option<A> {
35 match self {
36 Either2::First(a) => Some(a),
37 _ => None,
38 }
39 }
40 pub fn second(self) -> Option<B> {
42 match self {
43 Either2::Second(b) => Some(b),
44 _ => None,
45 }
46 }
47 pub fn map_first<C, F: FnOnce(A) -> C>(self, f: F) -> Either2<C, B> {
49 match self {
50 Either2::First(a) => Either2::First(f(a)),
51 Either2::Second(b) => Either2::Second(b),
52 }
53 }
54}
55#[allow(dead_code)]
57pub struct FocusStack<T> {
58 items: Vec<T>,
59}
60#[allow(dead_code)]
61impl<T> FocusStack<T> {
62 pub fn new() -> Self {
64 Self { items: Vec::new() }
65 }
66 pub fn focus(&mut self, item: T) {
68 self.items.push(item);
69 }
70 pub fn blur(&mut self) -> Option<T> {
72 self.items.pop()
73 }
74 pub fn current(&self) -> Option<&T> {
76 self.items.last()
77 }
78 pub fn depth(&self) -> usize {
80 self.items.len()
81 }
82 pub fn is_empty(&self) -> bool {
84 self.items.is_empty()
85 }
86}
87#[allow(dead_code)]
89#[derive(Debug, Clone, Default)]
90pub struct NameIndex {
91 names: Vec<String>,
92 index: std::collections::HashMap<String, usize>,
93}
94impl NameIndex {
95 #[allow(dead_code)]
97 pub fn new() -> Self {
98 Self::default()
99 }
100 #[allow(dead_code)]
103 pub fn insert(&mut self, name: impl Into<String>) -> usize {
104 let name = name.into();
105 if let Some(&id) = self.index.get(&name) {
106 return id;
107 }
108 let id = self.names.len();
109 self.index.insert(name.clone(), id);
110 self.names.push(name);
111 id
112 }
113 #[allow(dead_code)]
115 pub fn get_id(&self, name: &str) -> Option<usize> {
116 self.index.get(name).copied()
117 }
118 #[allow(dead_code)]
120 pub fn get_name(&self, id: usize) -> Option<&str> {
121 self.names.get(id).map(|s| s.as_str())
122 }
123 #[allow(dead_code)]
125 pub fn len(&self) -> usize {
126 self.names.len()
127 }
128 #[allow(dead_code)]
130 pub fn is_empty(&self) -> bool {
131 self.names.is_empty()
132 }
133 #[allow(dead_code)]
135 pub fn all_names(&self) -> &[String] {
136 &self.names
137 }
138}
139#[allow(dead_code)]
141pub struct VersionedRecord<T: Clone> {
142 history: Vec<T>,
143}
144#[allow(dead_code)]
145impl<T: Clone> VersionedRecord<T> {
146 pub fn new(initial: T) -> Self {
148 Self {
149 history: vec![initial],
150 }
151 }
152 pub fn update(&mut self, val: T) {
154 self.history.push(val);
155 }
156 pub fn current(&self) -> &T {
158 self.history
159 .last()
160 .expect("VersionedRecord history is always non-empty after construction")
161 }
162 pub fn at_version(&self, n: usize) -> Option<&T> {
164 self.history.get(n)
165 }
166 pub fn version(&self) -> usize {
168 self.history.len() - 1
169 }
170 pub fn has_history(&self) -> bool {
172 self.history.len() > 1
173 }
174}
175#[allow(dead_code)]
177pub struct RawFnPtr {
178 ptr: usize,
180 arity: usize,
181 name: String,
182}
183#[allow(dead_code)]
184impl RawFnPtr {
185 pub fn new(ptr: usize, arity: usize, name: impl Into<String>) -> Self {
187 Self {
188 ptr,
189 arity,
190 name: name.into(),
191 }
192 }
193 pub fn arity(&self) -> usize {
195 self.arity
196 }
197 pub fn name(&self) -> &str {
199 &self.name
200 }
201 pub fn raw(&self) -> usize {
203 self.ptr
204 }
205}
206#[allow(dead_code)]
208pub struct BatchDefEqChecker<'env> {
209 checker: DefEqChecker<'env>,
210}
211impl<'env> BatchDefEqChecker<'env> {
212 #[allow(dead_code)]
214 pub fn new(env: &'env Environment) -> Self {
215 Self {
216 checker: DefEqChecker::new(env),
217 }
218 }
219 #[allow(dead_code)]
221 pub fn check(&mut self, t: &Expr, s: &Expr) -> bool {
222 self.checker.is_def_eq(t, s)
223 }
224 #[allow(dead_code)]
226 pub fn check_all(&mut self, pairs: &[(Expr, Expr)]) -> bool {
227 pairs.iter().all(|(t, s)| self.checker.is_def_eq(t, s))
228 }
229 #[allow(dead_code)]
231 pub fn check_any(&mut self, pairs: &[(Expr, Expr)]) -> bool {
232 pairs.iter().any(|(t, s)| self.checker.is_def_eq(t, s))
233 }
234 #[allow(dead_code)]
236 pub fn count_equal(&mut self, pairs: &[(Expr, Expr)]) -> usize {
237 pairs
238 .iter()
239 .filter(|(t, s)| self.checker.is_def_eq(t, s))
240 .count()
241 }
242 #[allow(dead_code)]
244 pub fn reset(&mut self) {
245 self.checker.cache.clear();
246 self.checker.equiv_manager.clear();
247 }
248}
249#[allow(dead_code)]
251pub struct StatSummary {
252 count: u64,
253 sum: f64,
254 min: f64,
255 max: f64,
256}
257#[allow(dead_code)]
258impl StatSummary {
259 pub fn new() -> Self {
261 Self {
262 count: 0,
263 sum: 0.0,
264 min: f64::INFINITY,
265 max: f64::NEG_INFINITY,
266 }
267 }
268 pub fn record(&mut self, val: f64) {
270 self.count += 1;
271 self.sum += val;
272 if val < self.min {
273 self.min = val;
274 }
275 if val > self.max {
276 self.max = val;
277 }
278 }
279 pub fn mean(&self) -> Option<f64> {
281 if self.count == 0 {
282 None
283 } else {
284 Some(self.sum / self.count as f64)
285 }
286 }
287 pub fn min(&self) -> Option<f64> {
289 if self.count == 0 {
290 None
291 } else {
292 Some(self.min)
293 }
294 }
295 pub fn max(&self) -> Option<f64> {
297 if self.count == 0 {
298 None
299 } else {
300 Some(self.max)
301 }
302 }
303 pub fn count(&self) -> u64 {
305 self.count
306 }
307}
308#[allow(dead_code)]
310pub struct TransformStat {
311 before: StatSummary,
312 after: StatSummary,
313}
314#[allow(dead_code)]
315impl TransformStat {
316 pub fn new() -> Self {
318 Self {
319 before: StatSummary::new(),
320 after: StatSummary::new(),
321 }
322 }
323 pub fn record_before(&mut self, v: f64) {
325 self.before.record(v);
326 }
327 pub fn record_after(&mut self, v: f64) {
329 self.after.record(v);
330 }
331 pub fn mean_ratio(&self) -> Option<f64> {
333 let b = self.before.mean()?;
334 let a = self.after.mean()?;
335 if b.abs() < f64::EPSILON {
336 return None;
337 }
338 Some(a / b)
339 }
340}
341#[allow(dead_code)]
343pub struct WriteOnce<T> {
344 value: std::cell::Cell<Option<T>>,
345}
346#[allow(dead_code)]
347impl<T: Copy> WriteOnce<T> {
348 pub fn new() -> Self {
350 Self {
351 value: std::cell::Cell::new(None),
352 }
353 }
354 pub fn write(&self, val: T) -> bool {
356 if self.value.get().is_some() {
357 return false;
358 }
359 self.value.set(Some(val));
360 true
361 }
362 pub fn read(&self) -> Option<T> {
364 self.value.get()
365 }
366 pub fn is_written(&self) -> bool {
368 self.value.get().is_some()
369 }
370}
371#[allow(dead_code)]
373pub struct ConfigNode {
374 key: String,
375 value: Option<String>,
376 children: Vec<ConfigNode>,
377}
378#[allow(dead_code)]
379impl ConfigNode {
380 pub fn leaf(key: impl Into<String>, value: impl Into<String>) -> Self {
382 Self {
383 key: key.into(),
384 value: Some(value.into()),
385 children: Vec::new(),
386 }
387 }
388 pub fn section(key: impl Into<String>) -> Self {
390 Self {
391 key: key.into(),
392 value: None,
393 children: Vec::new(),
394 }
395 }
396 pub fn add_child(&mut self, child: ConfigNode) {
398 self.children.push(child);
399 }
400 pub fn key(&self) -> &str {
402 &self.key
403 }
404 pub fn value(&self) -> Option<&str> {
406 self.value.as_deref()
407 }
408 pub fn num_children(&self) -> usize {
410 self.children.len()
411 }
412 pub fn lookup(&self, path: &str) -> Option<&str> {
414 let mut parts = path.splitn(2, '.');
415 let head = parts.next()?;
416 let tail = parts.next();
417 if head != self.key {
418 return None;
419 }
420 match tail {
421 None => self.value.as_deref(),
422 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
423 }
424 }
425 fn lookup_relative(&self, path: &str) -> Option<&str> {
426 let mut parts = path.splitn(2, '.');
427 let head = parts.next()?;
428 let tail = parts.next();
429 if head != self.key {
430 return None;
431 }
432 match tail {
433 None => self.value.as_deref(),
434 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
435 }
436 }
437}
438#[allow(dead_code)]
440#[derive(Debug, Clone, Default)]
441pub struct DefEqStats {
442 pub cache_hits: u64,
444 pub cache_misses: u64,
446 pub reduction_steps: u64,
448 pub delta_reductions: u64,
450 pub beta_reductions: u64,
452 pub eta_attempts: u64,
454 pub equiv_hits: u64,
456}
457impl DefEqStats {
458 #[allow(dead_code)]
460 pub fn cache_hit_rate(&self) -> f64 {
461 let total = self.cache_hits + self.cache_misses;
462 if total == 0 {
463 1.0
464 } else {
465 self.cache_hits as f64 / total as f64
466 }
467 }
468 #[allow(dead_code)]
470 pub fn total_cache_accesses(&self) -> u64 {
471 self.cache_hits + self.cache_misses
472 }
473 #[allow(dead_code)]
475 pub fn total_reductions(&self) -> u64 {
476 self.reduction_steps + self.delta_reductions + self.beta_reductions
477 }
478}
479#[allow(dead_code)]
481pub struct PathBuf {
482 components: Vec<String>,
483}
484#[allow(dead_code)]
485impl PathBuf {
486 pub fn new() -> Self {
488 Self {
489 components: Vec::new(),
490 }
491 }
492 pub fn push(&mut self, comp: impl Into<String>) {
494 self.components.push(comp.into());
495 }
496 pub fn pop(&mut self) {
498 self.components.pop();
499 }
500 pub fn as_str(&self) -> String {
502 self.components.join("/")
503 }
504 pub fn depth(&self) -> usize {
506 self.components.len()
507 }
508 pub fn clear(&mut self) {
510 self.components.clear();
511 }
512}
513#[allow(dead_code)]
515#[allow(missing_docs)]
516pub enum DecisionNode {
517 Leaf(String),
519 Branch {
521 key: String,
522 val: String,
523 yes_branch: Box<DecisionNode>,
524 no_branch: Box<DecisionNode>,
525 },
526}
527#[allow(dead_code)]
528impl DecisionNode {
529 pub fn evaluate(&self, ctx: &std::collections::HashMap<String, String>) -> &str {
531 match self {
532 DecisionNode::Leaf(action) => action.as_str(),
533 DecisionNode::Branch {
534 key,
535 val,
536 yes_branch,
537 no_branch,
538 } => {
539 let actual = ctx.get(key).map(|s| s.as_str()).unwrap_or("");
540 if actual == val.as_str() {
541 yes_branch.evaluate(ctx)
542 } else {
543 no_branch.evaluate(ctx)
544 }
545 }
546 }
547 }
548 pub fn depth(&self) -> usize {
550 match self {
551 DecisionNode::Leaf(_) => 0,
552 DecisionNode::Branch {
553 yes_branch,
554 no_branch,
555 ..
556 } => 1 + yes_branch.depth().max(no_branch.depth()),
557 }
558 }
559}
560#[allow(dead_code)]
562pub struct SparseVec<T: Default + Clone + PartialEq> {
563 entries: std::collections::HashMap<usize, T>,
564 default_: T,
565 logical_len: usize,
566}
567#[allow(dead_code)]
568impl<T: Default + Clone + PartialEq> SparseVec<T> {
569 pub fn new(len: usize) -> Self {
571 Self {
572 entries: std::collections::HashMap::new(),
573 default_: T::default(),
574 logical_len: len,
575 }
576 }
577 pub fn set(&mut self, idx: usize, val: T) {
579 if val == self.default_ {
580 self.entries.remove(&idx);
581 } else {
582 self.entries.insert(idx, val);
583 }
584 }
585 pub fn get(&self, idx: usize) -> &T {
587 self.entries.get(&idx).unwrap_or(&self.default_)
588 }
589 pub fn len(&self) -> usize {
591 self.logical_len
592 }
593 pub fn is_empty(&self) -> bool {
595 self.len() == 0
596 }
597 pub fn nnz(&self) -> usize {
599 self.entries.len()
600 }
601}
602#[allow(dead_code)]
604pub struct Stopwatch {
605 start: std::time::Instant,
606 splits: Vec<f64>,
607}
608#[allow(dead_code)]
609impl Stopwatch {
610 pub fn start() -> Self {
612 Self {
613 start: std::time::Instant::now(),
614 splits: Vec::new(),
615 }
616 }
617 pub fn split(&mut self) {
619 self.splits.push(self.elapsed_ms());
620 }
621 pub fn elapsed_ms(&self) -> f64 {
623 self.start.elapsed().as_secs_f64() * 1000.0
624 }
625 pub fn splits(&self) -> &[f64] {
627 &self.splits
628 }
629 pub fn num_splits(&self) -> usize {
631 self.splits.len()
632 }
633}
634#[allow(dead_code)]
636pub struct LabelSet {
637 labels: Vec<String>,
638}
639#[allow(dead_code)]
640impl LabelSet {
641 pub fn new() -> Self {
643 Self { labels: Vec::new() }
644 }
645 pub fn add(&mut self, label: impl Into<String>) {
647 let s = label.into();
648 if !self.labels.contains(&s) {
649 self.labels.push(s);
650 }
651 }
652 pub fn has(&self, label: &str) -> bool {
654 self.labels.iter().any(|l| l == label)
655 }
656 pub fn count(&self) -> usize {
658 self.labels.len()
659 }
660 pub fn all(&self) -> &[String] {
662 &self.labels
663 }
664}
665#[allow(dead_code)]
667pub struct StringPool {
668 free: Vec<String>,
669}
670#[allow(dead_code)]
671impl StringPool {
672 pub fn new() -> Self {
674 Self { free: Vec::new() }
675 }
676 pub fn take(&mut self) -> String {
678 self.free.pop().unwrap_or_default()
679 }
680 pub fn give(&mut self, mut s: String) {
682 s.clear();
683 self.free.push(s);
684 }
685 pub fn free_count(&self) -> usize {
687 self.free.len()
688 }
689}
690#[derive(Debug, PartialEq, Eq)]
692pub enum ReductionStatus {
693 Continue(Expr, Expr),
695 Equal,
697 Stuck,
699 Unknown,
701}
702#[allow(dead_code)]
704pub struct StackCalc {
705 stack: Vec<i64>,
706}
707#[allow(dead_code)]
708impl StackCalc {
709 pub fn new() -> Self {
711 Self { stack: Vec::new() }
712 }
713 pub fn push(&mut self, n: i64) {
715 self.stack.push(n);
716 }
717 pub fn add(&mut self) {
719 let b = self
720 .stack
721 .pop()
722 .expect("stack must have at least two values for add");
723 let a = self
724 .stack
725 .pop()
726 .expect("stack must have at least two values for add");
727 self.stack.push(a + b);
728 }
729 pub fn sub(&mut self) {
731 let b = self
732 .stack
733 .pop()
734 .expect("stack must have at least two values for sub");
735 let a = self
736 .stack
737 .pop()
738 .expect("stack must have at least two values for sub");
739 self.stack.push(a - b);
740 }
741 pub fn mul(&mut self) {
743 let b = self
744 .stack
745 .pop()
746 .expect("stack must have at least two values for mul");
747 let a = self
748 .stack
749 .pop()
750 .expect("stack must have at least two values for mul");
751 self.stack.push(a * b);
752 }
753 pub fn peek(&self) -> Option<i64> {
755 self.stack.last().copied()
756 }
757 pub fn depth(&self) -> usize {
759 self.stack.len()
760 }
761}
762#[allow(dead_code)]
764#[derive(Debug, Clone)]
765pub struct DefEqConfig {
766 pub max_steps: u32,
768 pub proof_irrelevance: bool,
770 pub eta: bool,
772 pub lazy_delta: bool,
774 pub transparency: TransparencyMode,
776}
777impl DefEqConfig {
778 #[allow(dead_code)]
780 pub fn full_transparency() -> Self {
781 Self {
782 transparency: TransparencyMode::All,
783 ..Self::default()
784 }
785 }
786 #[allow(dead_code)]
788 pub fn opaque() -> Self {
789 Self {
790 lazy_delta: false,
791 transparency: TransparencyMode::None,
792 ..Self::default()
793 }
794 }
795 #[allow(dead_code)]
797 pub fn no_proof_irrelevance() -> Self {
798 Self {
799 proof_irrelevance: false,
800 ..Self::default()
801 }
802 }
803}
804#[allow(dead_code)]
806pub struct TransitiveClosure {
807 adj: Vec<Vec<usize>>,
808 n: usize,
809}
810#[allow(dead_code)]
811impl TransitiveClosure {
812 pub fn new(n: usize) -> Self {
814 Self {
815 adj: vec![Vec::new(); n],
816 n,
817 }
818 }
819 pub fn add_edge(&mut self, from: usize, to: usize) {
821 if from < self.n {
822 self.adj[from].push(to);
823 }
824 }
825 pub fn reachable_from(&self, start: usize) -> Vec<usize> {
827 let mut visited = vec![false; self.n];
828 let mut queue = std::collections::VecDeque::new();
829 queue.push_back(start);
830 while let Some(node) = queue.pop_front() {
831 if node >= self.n || visited[node] {
832 continue;
833 }
834 visited[node] = true;
835 for &next in &self.adj[node] {
836 queue.push_back(next);
837 }
838 }
839 (0..self.n).filter(|&i| visited[i]).collect()
840 }
841 pub fn can_reach(&self, from: usize, to: usize) -> bool {
843 self.reachable_from(from).contains(&to)
844 }
845}
846#[allow(dead_code)]
848#[derive(Debug, Clone, Default)]
849pub struct StringTrie {
850 pub(super) children: std::collections::HashMap<char, StringTrie>,
851 is_end: bool,
852 pub(super) value: Option<String>,
853}
854impl StringTrie {
855 #[allow(dead_code)]
857 pub fn new() -> Self {
858 Self::default()
859 }
860 #[allow(dead_code)]
862 pub fn insert(&mut self, s: &str) {
863 let mut node = self;
864 for c in s.chars() {
865 node = node.children.entry(c).or_default();
866 }
867 node.is_end = true;
868 node.value = Some(s.to_string());
869 }
870 #[allow(dead_code)]
872 pub fn contains(&self, s: &str) -> bool {
873 let mut node = self;
874 for c in s.chars() {
875 match node.children.get(&c) {
876 Some(next) => node = next,
877 None => return false,
878 }
879 }
880 node.is_end
881 }
882 #[allow(dead_code)]
884 pub fn starts_with(&self, prefix: &str) -> Vec<String> {
885 let mut node = self;
886 for c in prefix.chars() {
887 match node.children.get(&c) {
888 Some(next) => node = next,
889 None => return vec![],
890 }
891 }
892 let mut results = Vec::new();
893 collect_strings(node, &mut results);
894 results
895 }
896 #[allow(dead_code)]
898 pub fn len(&self) -> usize {
899 let mut count = if self.is_end { 1 } else { 0 };
900 for child in self.children.values() {
901 count += child.len();
902 }
903 count
904 }
905 #[allow(dead_code)]
907 pub fn is_empty(&self) -> bool {
908 self.len() == 0
909 }
910}
911#[allow(dead_code)]
913pub struct WindowIterator<'a, T> {
914 pub(super) data: &'a [T],
915 pub(super) pos: usize,
916 pub(super) window: usize,
917}
918#[allow(dead_code)]
919impl<'a, T> WindowIterator<'a, T> {
920 pub fn new(data: &'a [T], window: usize) -> Self {
922 Self {
923 data,
924 pos: 0,
925 window,
926 }
927 }
928}
929#[allow(dead_code)]
931pub struct TokenBucket {
932 capacity: u64,
933 tokens: u64,
934 refill_per_ms: u64,
935 last_refill: std::time::Instant,
936}
937#[allow(dead_code)]
938impl TokenBucket {
939 pub fn new(capacity: u64, refill_per_ms: u64) -> Self {
941 Self {
942 capacity,
943 tokens: capacity,
944 refill_per_ms,
945 last_refill: std::time::Instant::now(),
946 }
947 }
948 pub fn try_consume(&mut self, n: u64) -> bool {
950 self.refill();
951 if self.tokens >= n {
952 self.tokens -= n;
953 true
954 } else {
955 false
956 }
957 }
958 fn refill(&mut self) {
959 let now = std::time::Instant::now();
960 let elapsed_ms = now.duration_since(self.last_refill).as_millis() as u64;
961 if elapsed_ms > 0 {
962 let new_tokens = elapsed_ms * self.refill_per_ms;
963 self.tokens = (self.tokens + new_tokens).min(self.capacity);
964 self.last_refill = now;
965 }
966 }
967 pub fn available(&self) -> u64 {
969 self.tokens
970 }
971 pub fn capacity(&self) -> u64 {
973 self.capacity
974 }
975}
976#[allow(dead_code)]
978pub struct RewriteRuleSet {
979 rules: Vec<RewriteRule>,
980}
981#[allow(dead_code)]
982impl RewriteRuleSet {
983 pub fn new() -> Self {
985 Self { rules: Vec::new() }
986 }
987 pub fn add(&mut self, rule: RewriteRule) {
989 self.rules.push(rule);
990 }
991 pub fn len(&self) -> usize {
993 self.rules.len()
994 }
995 pub fn is_empty(&self) -> bool {
997 self.rules.is_empty()
998 }
999 pub fn conditional_rules(&self) -> Vec<&RewriteRule> {
1001 self.rules.iter().filter(|r| r.conditional).collect()
1002 }
1003 pub fn unconditional_rules(&self) -> Vec<&RewriteRule> {
1005 self.rules.iter().filter(|r| !r.conditional).collect()
1006 }
1007 pub fn get(&self, name: &str) -> Option<&RewriteRule> {
1009 self.rules.iter().find(|r| r.name == name)
1010 }
1011}
1012#[allow(dead_code)]
1014pub struct SimpleDag {
1015 edges: Vec<Vec<usize>>,
1017}
1018#[allow(dead_code)]
1019impl SimpleDag {
1020 pub fn new(n: usize) -> Self {
1022 Self {
1023 edges: vec![Vec::new(); n],
1024 }
1025 }
1026 pub fn add_edge(&mut self, from: usize, to: usize) {
1028 if from < self.edges.len() {
1029 self.edges[from].push(to);
1030 }
1031 }
1032 pub fn successors(&self, node: usize) -> &[usize] {
1034 self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
1035 }
1036 pub fn can_reach(&self, from: usize, to: usize) -> bool {
1038 let mut visited = vec![false; self.edges.len()];
1039 self.dfs(from, to, &mut visited)
1040 }
1041 fn dfs(&self, cur: usize, target: usize, visited: &mut Vec<bool>) -> bool {
1042 if cur == target {
1043 return true;
1044 }
1045 if cur >= visited.len() || visited[cur] {
1046 return false;
1047 }
1048 visited[cur] = true;
1049 for &next in self.successors(cur) {
1050 if self.dfs(next, target, visited) {
1051 return true;
1052 }
1053 }
1054 false
1055 }
1056 pub fn topological_sort(&self) -> Option<Vec<usize>> {
1058 let n = self.edges.len();
1059 let mut in_degree = vec![0usize; n];
1060 for succs in &self.edges {
1061 for &s in succs {
1062 if s < n {
1063 in_degree[s] += 1;
1064 }
1065 }
1066 }
1067 let mut queue: std::collections::VecDeque<usize> =
1068 (0..n).filter(|&i| in_degree[i] == 0).collect();
1069 let mut order = Vec::new();
1070 while let Some(node) = queue.pop_front() {
1071 order.push(node);
1072 for &s in self.successors(node) {
1073 if s < n {
1074 in_degree[s] -= 1;
1075 if in_degree[s] == 0 {
1076 queue.push_back(s);
1077 }
1078 }
1079 }
1080 }
1081 if order.len() == n {
1082 Some(order)
1083 } else {
1084 None
1085 }
1086 }
1087 pub fn num_nodes(&self) -> usize {
1089 self.edges.len()
1090 }
1091}
1092#[allow(dead_code)]
1094pub struct FlatSubstitution {
1095 pairs: Vec<(String, String)>,
1096}
1097#[allow(dead_code)]
1098impl FlatSubstitution {
1099 pub fn new() -> Self {
1101 Self { pairs: Vec::new() }
1102 }
1103 pub fn add(&mut self, from: impl Into<String>, to: impl Into<String>) {
1105 self.pairs.push((from.into(), to.into()));
1106 }
1107 pub fn apply(&self, s: &str) -> String {
1109 let mut result = s.to_string();
1110 for (from, to) in &self.pairs {
1111 result = result.replace(from.as_str(), to.as_str());
1112 }
1113 result
1114 }
1115 pub fn len(&self) -> usize {
1117 self.pairs.len()
1118 }
1119 pub fn is_empty(&self) -> bool {
1121 self.pairs.is_empty()
1122 }
1123}
1124#[allow(dead_code)]
1126#[allow(missing_docs)]
1127pub struct RewriteRule {
1128 pub name: String,
1130 pub lhs: String,
1132 pub rhs: String,
1134 pub conditional: bool,
1136}
1137#[allow(dead_code)]
1138impl RewriteRule {
1139 pub fn unconditional(
1141 name: impl Into<String>,
1142 lhs: impl Into<String>,
1143 rhs: impl Into<String>,
1144 ) -> Self {
1145 Self {
1146 name: name.into(),
1147 lhs: lhs.into(),
1148 rhs: rhs.into(),
1149 conditional: false,
1150 }
1151 }
1152 pub fn conditional(
1154 name: impl Into<String>,
1155 lhs: impl Into<String>,
1156 rhs: impl Into<String>,
1157 ) -> Self {
1158 Self {
1159 name: name.into(),
1160 lhs: lhs.into(),
1161 rhs: rhs.into(),
1162 conditional: true,
1163 }
1164 }
1165 pub fn display(&self) -> String {
1167 format!("{}: {} → {}", self.name, self.lhs, self.rhs)
1168 }
1169}
1170#[allow(dead_code)]
1172pub struct NonEmptyVec<T> {
1173 head: T,
1174 tail: Vec<T>,
1175}
1176#[allow(dead_code)]
1177impl<T> NonEmptyVec<T> {
1178 pub fn singleton(val: T) -> Self {
1180 Self {
1181 head: val,
1182 tail: Vec::new(),
1183 }
1184 }
1185 pub fn push(&mut self, val: T) {
1187 self.tail.push(val);
1188 }
1189 pub fn first(&self) -> &T {
1191 &self.head
1192 }
1193 pub fn last(&self) -> &T {
1195 self.tail.last().unwrap_or(&self.head)
1196 }
1197 pub fn len(&self) -> usize {
1199 1 + self.tail.len()
1200 }
1201 pub fn is_empty(&self) -> bool {
1203 self.len() == 0
1204 }
1205 pub fn to_vec(&self) -> Vec<&T> {
1207 let mut v = vec![&self.head];
1208 v.extend(self.tail.iter());
1209 v
1210 }
1211}
1212#[allow(dead_code)]
1214pub struct SlidingSum {
1215 window: Vec<f64>,
1216 capacity: usize,
1217 pos: usize,
1218 sum: f64,
1219 count: usize,
1220}
1221#[allow(dead_code)]
1222impl SlidingSum {
1223 pub fn new(capacity: usize) -> Self {
1225 Self {
1226 window: vec![0.0; capacity],
1227 capacity,
1228 pos: 0,
1229 sum: 0.0,
1230 count: 0,
1231 }
1232 }
1233 pub fn push(&mut self, val: f64) {
1235 let oldest = self.window[self.pos];
1236 self.sum -= oldest;
1237 self.sum += val;
1238 self.window[self.pos] = val;
1239 self.pos = (self.pos + 1) % self.capacity;
1240 if self.count < self.capacity {
1241 self.count += 1;
1242 }
1243 }
1244 pub fn sum(&self) -> f64 {
1246 self.sum
1247 }
1248 pub fn mean(&self) -> Option<f64> {
1250 if self.count == 0 {
1251 None
1252 } else {
1253 Some(self.sum / self.count as f64)
1254 }
1255 }
1256 pub fn count(&self) -> usize {
1258 self.count
1259 }
1260}
1261pub struct DefEqChecker<'env> {
1263 env: &'env Environment,
1264 reducer: Reducer,
1265 cache: HashMap<(Expr, Expr), bool>,
1266 equiv_manager: EquivManager,
1267 proof_irrelevance: bool,
1268}
1269impl<'env> DefEqChecker<'env> {
1270 pub fn new(env: &'env Environment) -> Self {
1272 Self {
1273 env,
1274 reducer: Reducer::new(),
1275 cache: HashMap::new(),
1276 equiv_manager: EquivManager::new(),
1277 proof_irrelevance: true,
1278 }
1279 }
1280 pub fn set_proof_irrelevance(&mut self, enabled: bool) {
1282 self.proof_irrelevance = enabled;
1283 }
1284 pub fn set_transparency(&mut self, mode: TransparencyMode) {
1286 self.reducer.set_transparency(mode);
1287 self.cache.clear();
1288 self.equiv_manager.clear();
1289 }
1290 pub fn is_def_eq(&mut self, t: &Expr, s: &Expr) -> bool {
1292 if t == s {
1293 return true;
1294 }
1295 if self.equiv_manager.is_equiv(t, s) {
1296 return true;
1297 }
1298 if self.equiv_manager.is_failure(t, s) {
1299 return false;
1300 }
1301 let key = (t.clone(), s.clone());
1302 if let Some(&result) = self.cache.get(&key) {
1303 return result;
1304 }
1305 let result = self.is_def_eq_core(t, s);
1306 self.cache.insert(key, result);
1307 if result {
1308 self.equiv_manager.add_equiv(t, s);
1309 } else {
1310 self.equiv_manager.add_failure(t, s);
1311 }
1312 result
1313 }
1314 fn is_def_eq_core(&mut self, t: &Expr, s: &Expr) -> bool {
1315 let t_whnf = self.reducer.whnf_env(t, self.env);
1316 let s_whnf = self.reducer.whnf_env(s, self.env);
1317 if t_whnf == s_whnf {
1318 return true;
1319 }
1320 if self.is_proof_irrelevant_eq(&t_whnf, &s_whnf) {
1321 return true;
1322 }
1323 match (&t_whnf, &s_whnf) {
1324 (Expr::Sort(l1), Expr::Sort(l2)) => level::is_equivalent(l1, l2),
1325 (Expr::BVar(i1), Expr::BVar(i2)) => i1 == i2,
1326 (Expr::FVar(id1), Expr::FVar(id2)) => id1 == id2,
1327 (Expr::Const(n1, ls1), Expr::Const(n2, ls2)) => {
1328 n1 == n2
1329 && ls1.len() == ls2.len()
1330 && ls1
1331 .iter()
1332 .zip(ls2.iter())
1333 .all(|(l1, l2)| level::is_equivalent(l1, l2))
1334 }
1335 (Expr::App(f1, a1), Expr::App(f2, a2)) => {
1336 if self.is_def_eq_app(&t_whnf, &s_whnf) {
1337 return true;
1338 }
1339 self.is_def_eq(f1, f2) && self.is_def_eq(a1, a2)
1340 }
1341 (Expr::Lam(_, _, ty1, b1), Expr::Lam(_, _, ty2, b2)) => {
1342 self.is_def_eq(ty1, ty2) && self.is_def_eq(b1, b2)
1343 }
1344 (Expr::Pi(_, _, ty1, b1), Expr::Pi(_, _, ty2, b2)) => {
1345 self.is_def_eq(ty1, ty2) && self.is_def_eq(b1, b2)
1346 }
1347 (Expr::Let(_, ty1, v1, b1), Expr::Let(_, ty2, v2, b2)) => {
1348 self.is_def_eq(ty1, ty2) && self.is_def_eq(v1, v2) && self.is_def_eq(b1, b2)
1349 }
1350 (Expr::Lit(l1), Expr::Lit(l2)) => l1 == l2,
1351 (Expr::Proj(n1, i1, e1), Expr::Proj(n2, i2, e2)) => {
1352 n1 == n2 && i1 == i2 && self.is_def_eq(e1, e2)
1353 }
1354 (Expr::Lam(_, _, _, _), _) => self.try_eta_lhs(&t_whnf, &s_whnf),
1355 (_, Expr::Lam(_, _, _, _)) => self.try_eta_rhs(&t_whnf, &s_whnf),
1356 _ => self.try_lazy_delta(&t_whnf, &s_whnf),
1357 }
1358 }
1359 fn try_lazy_delta(&mut self, t: &Expr, s: &Expr) -> bool {
1364 let t_head = get_app_fn(t);
1365 let s_head = get_app_fn(s);
1366 let t_hint = self.get_hint(t_head);
1367 let s_hint = self.get_hint(s_head);
1368 match (t_hint, s_hint) {
1369 (Some(th), Some(sh)) => {
1370 if th.height() <= sh.height() {
1371 if let Some(t_unfolded) = self.unfold_definition(t) {
1372 let t_whnf = self.reducer.whnf_env(&t_unfolded, self.env);
1373 return self.is_def_eq(&t_whnf, s);
1374 }
1375 }
1376 if let Some(s_unfolded) = self.unfold_definition(s) {
1377 let s_whnf = self.reducer.whnf_env(&s_unfolded, self.env);
1378 return self.is_def_eq(t, &s_whnf);
1379 }
1380 false
1381 }
1382 (Some(_), None) => {
1383 if let Some(t_unfolded) = self.unfold_definition(t) {
1384 let t_whnf = self.reducer.whnf_env(&t_unfolded, self.env);
1385 return self.is_def_eq(&t_whnf, s);
1386 }
1387 false
1388 }
1389 (None, Some(_)) => {
1390 if let Some(s_unfolded) = self.unfold_definition(s) {
1391 let s_whnf = self.reducer.whnf_env(&s_unfolded, self.env);
1392 return self.is_def_eq(t, &s_whnf);
1393 }
1394 false
1395 }
1396 (None, None) => false,
1397 }
1398 }
1399 fn get_hint(&self, head: &Expr) -> Option<ReducibilityHint> {
1401 if let Expr::Const(name, _) = head {
1402 if let Some(ci) = self.env.find(name) {
1403 let hint = ci.reducibility_hint();
1404 if hint.should_unfold() {
1405 return Some(hint);
1406 }
1407 }
1408 }
1409 None
1410 }
1411 fn unfold_definition(&self, expr: &Expr) -> Option<Expr> {
1413 let head = get_app_fn(expr);
1414 if let Expr::Const(name, levels) = head {
1415 if let Some(ci) = self.env.find(name) {
1416 if let Some(val) = ci.value() {
1417 let val_inst = if ci.level_params().is_empty() || levels.is_empty() {
1418 val.clone()
1419 } else {
1420 crate::instantiate::instantiate_type_lparams(val, ci.level_params(), levels)
1421 };
1422 let args: Vec<Expr> = get_app_args(expr).into_iter().cloned().collect();
1423 return Some(crate::expr_util::mk_app(val_inst, &args));
1424 }
1425 }
1426 }
1427 None
1428 }
1429 fn is_def_eq_app(&mut self, t: &Expr, s: &Expr) -> bool {
1434 let t_head = get_app_fn(t);
1435 let s_head = get_app_fn(s);
1436 let t_args = get_app_args(t);
1437 let s_args = get_app_args(s);
1438 if t_args.len() != s_args.len() {
1439 return false;
1440 }
1441 if !self.is_def_eq(t_head, s_head) {
1442 return false;
1443 }
1444 t_args
1445 .iter()
1446 .zip(s_args.iter())
1447 .all(|(a, b)| self.is_def_eq(a, b))
1448 }
1449 fn quick_infer_type(&mut self, expr: &Expr) -> Option<Expr> {
1455 match expr {
1456 Expr::Sort(l) => Some(Expr::Sort(crate::level::Level::succ(l.clone()))),
1457 Expr::Lit(crate::Literal::Nat(_)) => Some(Expr::Const(crate::Name::str("Nat"), vec![])),
1458 Expr::Lit(crate::Literal::Str(_)) => {
1459 Some(Expr::Const(crate::Name::str("String"), vec![]))
1460 }
1461 Expr::Const(name, levels) => {
1462 let ci = self.env.find(name)?;
1463 let raw_ty = ci.ty().clone();
1464 let params = ci.level_params().to_vec();
1465 if params.is_empty() || levels.is_empty() {
1466 Some(raw_ty)
1467 } else {
1468 Some(crate::instantiate::instantiate_type_lparams(
1469 &raw_ty, ¶ms, levels,
1470 ))
1471 }
1472 }
1473 Expr::App(f, a) => {
1474 let f_ty = self.quick_infer_type(f)?;
1475 let f_ty_whnf = self.reducer.whnf_env(&f_ty, self.env);
1476 if let Expr::Pi(_, _, _, body) = f_ty_whnf {
1477 Some(crate::subst::instantiate(&body, a))
1478 } else {
1479 None
1480 }
1481 }
1482 Expr::Lam(bi, name, dom, body) => {
1483 let body_ty = self.quick_infer_type(body)?;
1484 Some(Expr::Pi(*bi, name.clone(), dom.clone(), Box::new(body_ty)))
1485 }
1486 Expr::Pi(_, _, dom, cod) => {
1487 let dom_ty = self.quick_infer_type(dom)?;
1488 let cod_ty = self.quick_infer_type(cod)?;
1489 let dom_whnf = self.reducer.whnf_env(&dom_ty, self.env);
1490 let cod_whnf = self.reducer.whnf_env(&cod_ty, self.env);
1491 match (dom_whnf, cod_whnf) {
1492 (Expr::Sort(l1), Expr::Sort(l2)) => {
1493 Some(Expr::Sort(crate::level::Level::imax(l1, l2)))
1494 }
1495 _ => None,
1496 }
1497 }
1498 Expr::Let(_, _ty, val, body) => {
1499 let body_subst = crate::subst::instantiate(body, val);
1500 self.quick_infer_type(&body_subst)
1501 }
1502 _ => None,
1503 }
1504 }
1505 fn is_proof_irrelevant_eq(&mut self, t: &Expr, s: &Expr) -> bool {
1511 if !self.proof_irrelevance {
1512 return false;
1513 }
1514 let ty_t = match self.quick_infer_type(t) {
1515 Some(ty) => ty,
1516 None => return false,
1517 };
1518 let ty_ty_t = match self.quick_infer_type(&ty_t) {
1519 Some(ty) => ty,
1520 None => return false,
1521 };
1522 let ty_ty_t_whnf = self.reducer.whnf_env(&ty_ty_t, self.env);
1523 if !matches!(& ty_ty_t_whnf, Expr::Sort(l) if l.is_zero()) {
1524 return false;
1525 }
1526 let ty_s = match self.quick_infer_type(s) {
1527 Some(ty) => ty,
1528 None => return false,
1529 };
1530 let ty_ty_s = match self.quick_infer_type(&ty_s) {
1531 Some(ty) => ty,
1532 None => return false,
1533 };
1534 let ty_ty_s_whnf = self.reducer.whnf_env(&ty_ty_s, self.env);
1535 if !matches!(& ty_ty_s_whnf, Expr::Sort(l) if l.is_zero()) {
1536 return false;
1537 }
1538 let ty_t_whnf = self.reducer.whnf_env(&ty_t, self.env);
1539 let ty_s_whnf = self.reducer.whnf_env(&ty_s, self.env);
1540 self.is_def_eq(&ty_t_whnf, &ty_s_whnf)
1541 }
1542 fn try_eta_lhs(&mut self, t: &Expr, s: &Expr) -> bool {
1546 if let Expr::Lam(_, _, _, body) = t {
1547 if let Expr::App(f, a) = body.as_ref() {
1548 if let Expr::BVar(0) = **a {
1549 if !has_loose_bvar(f, 0) {
1550 let f_shifted =
1551 crate::subst::instantiate(f, &Expr::FVar(crate::FVarId(u64::MAX)));
1552 return self.is_def_eq(&f_shifted, s);
1553 }
1554 }
1555 }
1556 }
1557 false
1558 }
1559 fn try_eta_rhs(&mut self, t: &Expr, s: &Expr) -> bool {
1561 if let Expr::Lam(_, _, _, body) = s {
1562 if let Expr::App(f, a) = body.as_ref() {
1563 if let Expr::BVar(0) = **a {
1564 if !has_loose_bvar(f, 0) {
1565 let f_shifted =
1566 crate::subst::instantiate(f, &Expr::FVar(crate::FVarId(u64::MAX)));
1567 return self.is_def_eq(t, &f_shifted);
1568 }
1569 }
1570 }
1571 }
1572 false
1573 }
1574}
1575#[allow(dead_code)]
1577pub struct SmallMap<K: Ord + Clone, V: Clone> {
1578 entries: Vec<(K, V)>,
1579}
1580#[allow(dead_code)]
1581impl<K: Ord + Clone, V: Clone> SmallMap<K, V> {
1582 pub fn new() -> Self {
1584 Self {
1585 entries: Vec::new(),
1586 }
1587 }
1588 pub fn insert(&mut self, key: K, val: V) {
1590 match self.entries.binary_search_by_key(&&key, |(k, _)| k) {
1591 Ok(i) => self.entries[i].1 = val,
1592 Err(i) => self.entries.insert(i, (key, val)),
1593 }
1594 }
1595 pub fn get(&self, key: &K) -> Option<&V> {
1597 self.entries
1598 .binary_search_by_key(&key, |(k, _)| k)
1599 .ok()
1600 .map(|i| &self.entries[i].1)
1601 }
1602 pub fn len(&self) -> usize {
1604 self.entries.len()
1605 }
1606 pub fn is_empty(&self) -> bool {
1608 self.entries.is_empty()
1609 }
1610 pub fn keys(&self) -> Vec<&K> {
1612 self.entries.iter().map(|(k, _)| k).collect()
1613 }
1614 pub fn values(&self) -> Vec<&V> {
1616 self.entries.iter().map(|(_, v)| v).collect()
1617 }
1618}