1use super::functions::*;
6use crate::{Declaration, Environment, Expr, Name};
7use std::collections::{HashMap, HashSet};
8
9#[allow(dead_code)]
11pub struct VersionedRecord<T: Clone> {
12 history: Vec<T>,
13}
14#[allow(dead_code)]
15impl<T: Clone> VersionedRecord<T> {
16 pub fn new(initial: T) -> Self {
18 Self {
19 history: vec![initial],
20 }
21 }
22 pub fn update(&mut self, val: T) {
24 self.history.push(val);
25 }
26 pub fn current(&self) -> &T {
28 self.history
29 .last()
30 .expect("VersionedRecord history is always non-empty after construction")
31 }
32 pub fn at_version(&self, n: usize) -> Option<&T> {
34 self.history.get(n)
35 }
36 pub fn version(&self) -> usize {
38 self.history.len() - 1
39 }
40 pub fn has_history(&self) -> bool {
42 self.history.len() > 1
43 }
44}
45#[allow(dead_code)]
47pub struct StackCalc {
48 stack: Vec<i64>,
49}
50#[allow(dead_code)]
51impl StackCalc {
52 pub fn new() -> Self {
54 Self { stack: Vec::new() }
55 }
56 pub fn push(&mut self, n: i64) {
58 self.stack.push(n);
59 }
60 pub fn add(&mut self) {
62 let b = self
63 .stack
64 .pop()
65 .expect("stack must have at least two values for add");
66 let a = self
67 .stack
68 .pop()
69 .expect("stack must have at least two values for add");
70 self.stack.push(a + b);
71 }
72 pub fn sub(&mut self) {
74 let b = self
75 .stack
76 .pop()
77 .expect("stack must have at least two values for sub");
78 let a = self
79 .stack
80 .pop()
81 .expect("stack must have at least two values for sub");
82 self.stack.push(a - b);
83 }
84 pub fn mul(&mut self) {
86 let b = self
87 .stack
88 .pop()
89 .expect("stack must have at least two values for mul");
90 let a = self
91 .stack
92 .pop()
93 .expect("stack must have at least two values for mul");
94 self.stack.push(a * b);
95 }
96 pub fn peek(&self) -> Option<i64> {
98 self.stack.last().copied()
99 }
100 pub fn depth(&self) -> usize {
102 self.stack.len()
103 }
104}
105#[allow(dead_code)]
109pub struct AxiomSequence {
110 entries: Vec<(Name, AxiomCategory)>,
111}
112#[allow(dead_code)]
113impl AxiomSequence {
114 pub fn new() -> Self {
116 Self {
117 entries: Vec::new(),
118 }
119 }
120 pub fn push(&mut self, name: Name) {
122 let cat = classify_axiom_category(&name);
123 self.entries.push((name, cat));
124 }
125 pub fn len(&self) -> usize {
127 self.entries.len()
128 }
129 pub fn is_empty(&self) -> bool {
131 self.entries.is_empty()
132 }
133 pub fn get(&self, i: usize) -> Option<&(Name, AxiomCategory)> {
135 self.entries.get(i)
136 }
137 pub fn classical_axioms(&self) -> Vec<&Name> {
139 self.entries
140 .iter()
141 .filter(|(_, c)| c == &AxiomCategory::Classical)
142 .map(|(n, _)| n)
143 .collect()
144 }
145 pub fn user_axioms(&self) -> Vec<&Name> {
147 self.entries
148 .iter()
149 .filter(|(_, c)| c == &AxiomCategory::UserDefined)
150 .map(|(n, _)| n)
151 .collect()
152 }
153 pub fn contains(&self, name: &Name) -> bool {
155 self.entries.iter().any(|(n, _)| n == name)
156 }
157 pub fn remove_classical(&mut self) {
159 self.entries.retain(|(_, c)| c != &AxiomCategory::Classical);
160 }
161 pub fn clear(&mut self) {
163 self.entries.clear();
164 }
165}
166#[allow(dead_code)]
168pub struct WindowIterator<'a, T> {
169 pub(super) data: &'a [T],
170 pub(super) pos: usize,
171 pub(super) window: usize,
172}
173#[allow(dead_code)]
174impl<'a, T> WindowIterator<'a, T> {
175 pub fn new(data: &'a [T], window: usize) -> Self {
177 Self {
178 data,
179 pos: 0,
180 window,
181 }
182 }
183}
184#[allow(dead_code)]
186pub struct StringPool {
187 free: Vec<String>,
188}
189#[allow(dead_code)]
190impl StringPool {
191 pub fn new() -> Self {
193 Self { free: Vec::new() }
194 }
195 pub fn take(&mut self) -> String {
197 self.free.pop().unwrap_or_default()
198 }
199 pub fn give(&mut self, mut s: String) {
201 s.clear();
202 self.free.push(s);
203 }
204 pub fn free_count(&self) -> usize {
206 self.free.len()
207 }
208}
209#[allow(dead_code)]
211#[allow(missing_docs)]
212pub struct RewriteRule {
213 pub name: String,
215 pub lhs: String,
217 pub rhs: String,
219 pub conditional: bool,
221}
222#[allow(dead_code)]
223impl RewriteRule {
224 pub fn unconditional(
226 name: impl Into<String>,
227 lhs: impl Into<String>,
228 rhs: impl Into<String>,
229 ) -> Self {
230 Self {
231 name: name.into(),
232 lhs: lhs.into(),
233 rhs: rhs.into(),
234 conditional: false,
235 }
236 }
237 pub fn conditional(
239 name: impl Into<String>,
240 lhs: impl Into<String>,
241 rhs: impl Into<String>,
242 ) -> Self {
243 Self {
244 name: name.into(),
245 lhs: lhs.into(),
246 rhs: rhs.into(),
247 conditional: true,
248 }
249 }
250 pub fn display(&self) -> String {
252 format!("{}: {} → {}", self.name, self.lhs, self.rhs)
253 }
254}
255#[allow(dead_code)]
257pub struct BucketCounter<const N: usize> {
258 buckets: [u64; N],
259}
260#[allow(dead_code)]
261impl<const N: usize> BucketCounter<N> {
262 pub const fn new() -> Self {
264 Self { buckets: [0u64; N] }
265 }
266 pub fn inc(&mut self, i: usize) {
268 if i < N {
269 self.buckets[i] += 1;
270 }
271 }
272 pub fn get(&self, i: usize) -> u64 {
274 if i < N {
275 self.buckets[i]
276 } else {
277 0
278 }
279 }
280 pub fn total(&self) -> u64 {
282 self.buckets.iter().sum()
283 }
284 pub fn argmax(&self) -> usize {
286 self.buckets
287 .iter()
288 .enumerate()
289 .max_by_key(|(_, &v)| v)
290 .map(|(i, _)| i)
291 .unwrap_or(0)
292 }
293}
294#[allow(dead_code)]
296pub struct NonEmptyVec<T> {
297 head: T,
298 tail: Vec<T>,
299}
300#[allow(dead_code)]
301impl<T> NonEmptyVec<T> {
302 pub fn singleton(val: T) -> Self {
304 Self {
305 head: val,
306 tail: Vec::new(),
307 }
308 }
309 pub fn push(&mut self, val: T) {
311 self.tail.push(val);
312 }
313 pub fn first(&self) -> &T {
315 &self.head
316 }
317 pub fn last(&self) -> &T {
319 self.tail.last().unwrap_or(&self.head)
320 }
321 pub fn len(&self) -> usize {
323 1 + self.tail.len()
324 }
325 pub fn is_empty(&self) -> bool {
327 self.len() == 0
328 }
329 pub fn to_vec(&self) -> Vec<&T> {
331 let mut v = vec![&self.head];
332 v.extend(self.tail.iter());
333 v
334 }
335}
336#[allow(dead_code)]
338pub struct Stopwatch {
339 start: std::time::Instant,
340 splits: Vec<f64>,
341}
342#[allow(dead_code)]
343impl Stopwatch {
344 pub fn start() -> Self {
346 Self {
347 start: std::time::Instant::now(),
348 splits: Vec::new(),
349 }
350 }
351 pub fn split(&mut self) {
353 self.splits.push(self.elapsed_ms());
354 }
355 pub fn elapsed_ms(&self) -> f64 {
357 self.start.elapsed().as_secs_f64() * 1000.0
358 }
359 pub fn splits(&self) -> &[f64] {
361 &self.splits
362 }
363 pub fn num_splits(&self) -> usize {
365 self.splits.len()
366 }
367}
368#[allow(dead_code)]
370pub struct AxiomUsageRecord {
371 pub name: Name,
373 pub direct_uses: u32,
375 pub transitive_deps: u32,
377 pub in_prop_context: bool,
379}
380#[allow(dead_code)]
381impl AxiomUsageRecord {
382 pub fn new(name: Name) -> Self {
384 AxiomUsageRecord {
385 name,
386 direct_uses: 0,
387 transitive_deps: 0,
388 in_prop_context: false,
389 }
390 }
391 pub fn record_direct_use(&mut self) {
393 self.direct_uses += 1;
394 }
395 pub fn record_transitive_dep(&mut self) {
397 self.transitive_deps += 1;
398 }
399}
400#[allow(dead_code)]
402pub struct ConfigNode {
403 key: String,
404 value: Option<String>,
405 children: Vec<ConfigNode>,
406}
407#[allow(dead_code)]
408impl ConfigNode {
409 pub fn leaf(key: impl Into<String>, value: impl Into<String>) -> Self {
411 Self {
412 key: key.into(),
413 value: Some(value.into()),
414 children: Vec::new(),
415 }
416 }
417 pub fn section(key: impl Into<String>) -> Self {
419 Self {
420 key: key.into(),
421 value: None,
422 children: Vec::new(),
423 }
424 }
425 pub fn add_child(&mut self, child: ConfigNode) {
427 self.children.push(child);
428 }
429 pub fn key(&self) -> &str {
431 &self.key
432 }
433 pub fn value(&self) -> Option<&str> {
435 self.value.as_deref()
436 }
437 pub fn num_children(&self) -> usize {
439 self.children.len()
440 }
441 pub fn lookup(&self, path: &str) -> Option<&str> {
443 let mut parts = path.splitn(2, '.');
444 let head = parts.next()?;
445 let tail = parts.next();
446 if head != self.key {
447 return None;
448 }
449 match tail {
450 None => self.value.as_deref(),
451 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
452 }
453 }
454 fn lookup_relative(&self, path: &str) -> Option<&str> {
455 let mut parts = path.splitn(2, '.');
456 let head = parts.next()?;
457 let tail = parts.next();
458 if head != self.key {
459 return None;
460 }
461 match tail {
462 None => self.value.as_deref(),
463 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
464 }
465 }
466}
467#[allow(dead_code)]
469pub struct TokenBucket {
470 capacity: u64,
471 tokens: u64,
472 refill_per_ms: u64,
473 last_refill: std::time::Instant,
474}
475#[allow(dead_code)]
476impl TokenBucket {
477 pub fn new(capacity: u64, refill_per_ms: u64) -> Self {
479 Self {
480 capacity,
481 tokens: capacity,
482 refill_per_ms,
483 last_refill: std::time::Instant::now(),
484 }
485 }
486 pub fn try_consume(&mut self, n: u64) -> bool {
488 self.refill();
489 if self.tokens >= n {
490 self.tokens -= n;
491 true
492 } else {
493 false
494 }
495 }
496 fn refill(&mut self) {
497 let now = std::time::Instant::now();
498 let elapsed_ms = now.duration_since(self.last_refill).as_millis() as u64;
499 if elapsed_ms > 0 {
500 let new_tokens = elapsed_ms * self.refill_per_ms;
501 self.tokens = (self.tokens + new_tokens).min(self.capacity);
502 self.last_refill = now;
503 }
504 }
505 pub fn available(&self) -> u64 {
507 self.tokens
508 }
509 pub fn capacity(&self) -> u64 {
511 self.capacity
512 }
513}
514#[derive(Debug, Clone, Copy, PartialEq, Eq)]
516pub enum AxiomSafety {
517 Safe,
519 Questionable,
521 Unsafe,
523}
524#[allow(dead_code)]
526pub struct SimpleDag {
527 edges: Vec<Vec<usize>>,
529}
530#[allow(dead_code)]
531impl SimpleDag {
532 pub fn new(n: usize) -> Self {
534 Self {
535 edges: vec![Vec::new(); n],
536 }
537 }
538 pub fn add_edge(&mut self, from: usize, to: usize) {
540 if from < self.edges.len() {
541 self.edges[from].push(to);
542 }
543 }
544 pub fn successors(&self, node: usize) -> &[usize] {
546 self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
547 }
548 pub fn can_reach(&self, from: usize, to: usize) -> bool {
550 let mut visited = vec![false; self.edges.len()];
551 self.dfs(from, to, &mut visited)
552 }
553 fn dfs(&self, cur: usize, target: usize, visited: &mut Vec<bool>) -> bool {
554 if cur == target {
555 return true;
556 }
557 if cur >= visited.len() || visited[cur] {
558 return false;
559 }
560 visited[cur] = true;
561 for &next in self.successors(cur) {
562 if self.dfs(next, target, visited) {
563 return true;
564 }
565 }
566 false
567 }
568 pub fn topological_sort(&self) -> Option<Vec<usize>> {
570 let n = self.edges.len();
571 let mut in_degree = vec![0usize; n];
572 for succs in &self.edges {
573 for &s in succs {
574 if s < n {
575 in_degree[s] += 1;
576 }
577 }
578 }
579 let mut queue: std::collections::VecDeque<usize> =
580 (0..n).filter(|&i| in_degree[i] == 0).collect();
581 let mut order = Vec::new();
582 while let Some(node) = queue.pop_front() {
583 order.push(node);
584 for &s in self.successors(node) {
585 if s < n {
586 in_degree[s] -= 1;
587 if in_degree[s] == 0 {
588 queue.push_back(s);
589 }
590 }
591 }
592 }
593 if order.len() == n {
594 Some(order)
595 } else {
596 None
597 }
598 }
599 pub fn num_nodes(&self) -> usize {
601 self.edges.len()
602 }
603}
604#[allow(dead_code)]
606pub struct RewriteRuleSet {
607 rules: Vec<RewriteRule>,
608}
609#[allow(dead_code)]
610impl RewriteRuleSet {
611 pub fn new() -> Self {
613 Self { rules: Vec::new() }
614 }
615 pub fn add(&mut self, rule: RewriteRule) {
617 self.rules.push(rule);
618 }
619 pub fn len(&self) -> usize {
621 self.rules.len()
622 }
623 pub fn is_empty(&self) -> bool {
625 self.rules.is_empty()
626 }
627 pub fn conditional_rules(&self) -> Vec<&RewriteRule> {
629 self.rules.iter().filter(|r| r.conditional).collect()
630 }
631 pub fn unconditional_rules(&self) -> Vec<&RewriteRule> {
633 self.rules.iter().filter(|r| !r.conditional).collect()
634 }
635 pub fn get(&self, name: &str) -> Option<&RewriteRule> {
637 self.rules.iter().find(|r| r.name == name)
638 }
639}
640#[allow(dead_code)]
642#[derive(Debug, Clone, PartialEq, Eq, Hash)]
643pub enum AxiomCategory {
644 Classical,
646 Definitional,
648 External,
650 UserDefined,
652 Propositional,
654}
655#[allow(dead_code)]
657pub struct WriteOnce<T> {
658 value: std::cell::Cell<Option<T>>,
659}
660#[allow(dead_code)]
661impl<T: Copy> WriteOnce<T> {
662 pub fn new() -> Self {
664 Self {
665 value: std::cell::Cell::new(None),
666 }
667 }
668 pub fn write(&self, val: T) -> bool {
670 if self.value.get().is_some() {
671 return false;
672 }
673 self.value.set(Some(val));
674 true
675 }
676 pub fn read(&self) -> Option<T> {
678 self.value.get()
679 }
680 pub fn is_written(&self) -> bool {
682 self.value.get().is_some()
683 }
684}
685#[allow(dead_code)]
687pub struct MinHeap<T: Ord> {
688 data: Vec<T>,
689}
690#[allow(dead_code)]
691impl<T: Ord> MinHeap<T> {
692 pub fn new() -> Self {
694 Self { data: Vec::new() }
695 }
696 pub fn push(&mut self, val: T) {
698 self.data.push(val);
699 self.sift_up(self.data.len() - 1);
700 }
701 pub fn pop(&mut self) -> Option<T> {
703 if self.data.is_empty() {
704 return None;
705 }
706 let n = self.data.len();
707 self.data.swap(0, n - 1);
708 let min = self.data.pop();
709 if !self.data.is_empty() {
710 self.sift_down(0);
711 }
712 min
713 }
714 pub fn peek(&self) -> Option<&T> {
716 self.data.first()
717 }
718 pub fn len(&self) -> usize {
720 self.data.len()
721 }
722 pub fn is_empty(&self) -> bool {
724 self.data.is_empty()
725 }
726 fn sift_up(&mut self, mut i: usize) {
727 while i > 0 {
728 let parent = (i - 1) / 2;
729 if self.data[i] < self.data[parent] {
730 self.data.swap(i, parent);
731 i = parent;
732 } else {
733 break;
734 }
735 }
736 }
737 fn sift_down(&mut self, mut i: usize) {
738 let n = self.data.len();
739 loop {
740 let left = 2 * i + 1;
741 let right = 2 * i + 2;
742 let mut smallest = i;
743 if left < n && self.data[left] < self.data[smallest] {
744 smallest = left;
745 }
746 if right < n && self.data[right] < self.data[smallest] {
747 smallest = right;
748 }
749 if smallest == i {
750 break;
751 }
752 self.data.swap(i, smallest);
753 i = smallest;
754 }
755 }
756}
757#[allow(dead_code)]
759pub struct PrefixCounter {
760 children: std::collections::HashMap<char, PrefixCounter>,
761 count: usize,
762}
763#[allow(dead_code)]
764impl PrefixCounter {
765 pub fn new() -> Self {
767 Self {
768 children: std::collections::HashMap::new(),
769 count: 0,
770 }
771 }
772 pub fn record(&mut self, s: &str) {
774 self.count += 1;
775 let mut node = self;
776 for c in s.chars() {
777 node = node.children.entry(c).or_default();
778 node.count += 1;
779 }
780 }
781 pub fn count_with_prefix(&self, prefix: &str) -> usize {
783 let mut node = self;
784 for c in prefix.chars() {
785 match node.children.get(&c) {
786 Some(n) => node = n,
787 None => return 0,
788 }
789 }
790 node.count
791 }
792}
793#[allow(dead_code)]
795pub struct AxiomSafetyReport {
796 pub total_axioms: usize,
798 pub classical_count: usize,
800 pub external_count: usize,
802 pub classically_consistent: bool,
804 pub warnings: Vec<String>,
806}
807#[allow(dead_code)]
808impl AxiomSafetyReport {
809 pub fn empty() -> Self {
811 AxiomSafetyReport {
812 total_axioms: 0,
813 classical_count: 0,
814 external_count: 0,
815 classically_consistent: true,
816 warnings: Vec::new(),
817 }
818 }
819 pub fn is_axiom_free(&self) -> bool {
821 self.total_axioms == 0
822 }
823 pub fn warn(&mut self, msg: impl Into<String>) {
825 self.warnings.push(msg.into());
826 }
827}
828#[allow(dead_code)]
830pub struct SmallMap<K: Ord + Clone, V: Clone> {
831 entries: Vec<(K, V)>,
832}
833#[allow(dead_code)]
834impl<K: Ord + Clone, V: Clone> SmallMap<K, V> {
835 pub fn new() -> Self {
837 Self {
838 entries: Vec::new(),
839 }
840 }
841 pub fn insert(&mut self, key: K, val: V) {
843 match self.entries.binary_search_by_key(&&key, |(k, _)| k) {
844 Ok(i) => self.entries[i].1 = val,
845 Err(i) => self.entries.insert(i, (key, val)),
846 }
847 }
848 pub fn get(&self, key: &K) -> Option<&V> {
850 self.entries
851 .binary_search_by_key(&key, |(k, _)| k)
852 .ok()
853 .map(|i| &self.entries[i].1)
854 }
855 pub fn len(&self) -> usize {
857 self.entries.len()
858 }
859 pub fn is_empty(&self) -> bool {
861 self.entries.is_empty()
862 }
863 pub fn keys(&self) -> Vec<&K> {
865 self.entries.iter().map(|(k, _)| k).collect()
866 }
867 pub fn values(&self) -> Vec<&V> {
869 self.entries.iter().map(|(_, v)| v).collect()
870 }
871}
872#[allow(dead_code)]
874pub struct TransitiveClosure {
875 adj: Vec<Vec<usize>>,
876 n: usize,
877}
878#[allow(dead_code)]
879impl TransitiveClosure {
880 pub fn new(n: usize) -> Self {
882 Self {
883 adj: vec![Vec::new(); n],
884 n,
885 }
886 }
887 pub fn add_edge(&mut self, from: usize, to: usize) {
889 if from < self.n {
890 self.adj[from].push(to);
891 }
892 }
893 pub fn reachable_from(&self, start: usize) -> Vec<usize> {
895 let mut visited = vec![false; self.n];
896 let mut queue = std::collections::VecDeque::new();
897 queue.push_back(start);
898 while let Some(node) = queue.pop_front() {
899 if node >= self.n || visited[node] {
900 continue;
901 }
902 visited[node] = true;
903 for &next in &self.adj[node] {
904 queue.push_back(next);
905 }
906 }
907 (0..self.n).filter(|&i| visited[i]).collect()
908 }
909 pub fn can_reach(&self, from: usize, to: usize) -> bool {
911 self.reachable_from(from).contains(&to)
912 }
913}
914#[allow(dead_code)]
916pub struct FlatSubstitution {
917 pairs: Vec<(String, String)>,
918}
919#[allow(dead_code)]
920impl FlatSubstitution {
921 pub fn new() -> Self {
923 Self { pairs: Vec::new() }
924 }
925 pub fn add(&mut self, from: impl Into<String>, to: impl Into<String>) {
927 self.pairs.push((from.into(), to.into()));
928 }
929 pub fn apply(&self, s: &str) -> String {
931 let mut result = s.to_string();
932 for (from, to) in &self.pairs {
933 result = result.replace(from.as_str(), to.as_str());
934 }
935 result
936 }
937 pub fn len(&self) -> usize {
939 self.pairs.len()
940 }
941 pub fn is_empty(&self) -> bool {
943 self.pairs.is_empty()
944 }
945}
946#[allow(dead_code)]
948pub struct StatSummary {
949 count: u64,
950 sum: f64,
951 min: f64,
952 max: f64,
953}
954#[allow(dead_code)]
955impl StatSummary {
956 pub fn new() -> Self {
958 Self {
959 count: 0,
960 sum: 0.0,
961 min: f64::INFINITY,
962 max: f64::NEG_INFINITY,
963 }
964 }
965 pub fn record(&mut self, val: f64) {
967 self.count += 1;
968 self.sum += val;
969 if val < self.min {
970 self.min = val;
971 }
972 if val > self.max {
973 self.max = val;
974 }
975 }
976 pub fn mean(&self) -> Option<f64> {
978 if self.count == 0 {
979 None
980 } else {
981 Some(self.sum / self.count as f64)
982 }
983 }
984 pub fn min(&self) -> Option<f64> {
986 if self.count == 0 {
987 None
988 } else {
989 Some(self.min)
990 }
991 }
992 pub fn max(&self) -> Option<f64> {
994 if self.count == 0 {
995 None
996 } else {
997 Some(self.max)
998 }
999 }
1000 pub fn count(&self) -> u64 {
1002 self.count
1003 }
1004}
1005#[allow(dead_code)]
1007pub struct Fixture {
1008 data: std::collections::HashMap<String, String>,
1009}
1010#[allow(dead_code)]
1011impl Fixture {
1012 pub fn new() -> Self {
1014 Self {
1015 data: std::collections::HashMap::new(),
1016 }
1017 }
1018 pub fn set(&mut self, key: impl Into<String>, val: impl Into<String>) {
1020 self.data.insert(key.into(), val.into());
1021 }
1022 pub fn get(&self, key: &str) -> Option<&str> {
1024 self.data.get(key).map(|s| s.as_str())
1025 }
1026 pub fn len(&self) -> usize {
1028 self.data.len()
1029 }
1030 pub fn is_empty(&self) -> bool {
1032 self.len() == 0
1033 }
1034}
1035#[allow(dead_code)]
1037pub struct BitSet64 {
1038 bits: u64,
1039}
1040#[allow(dead_code)]
1041impl BitSet64 {
1042 pub const fn new() -> Self {
1044 Self { bits: 0 }
1045 }
1046 pub fn insert(&mut self, i: u32) {
1048 if i < 64 {
1049 self.bits |= 1u64 << i;
1050 }
1051 }
1052 pub fn remove(&mut self, i: u32) {
1054 if i < 64 {
1055 self.bits &= !(1u64 << i);
1056 }
1057 }
1058 pub fn contains(&self, i: u32) -> bool {
1060 i < 64 && (self.bits >> i) & 1 != 0
1061 }
1062 pub fn len(&self) -> u32 {
1064 self.bits.count_ones()
1065 }
1066 pub fn is_empty(&self) -> bool {
1068 self.bits == 0
1069 }
1070 pub fn union(self, other: BitSet64) -> BitSet64 {
1072 BitSet64 {
1073 bits: self.bits | other.bits,
1074 }
1075 }
1076 pub fn intersect(self, other: BitSet64) -> BitSet64 {
1078 BitSet64 {
1079 bits: self.bits & other.bits,
1080 }
1081 }
1082}
1083#[allow(dead_code)]
1085pub struct LabelSet {
1086 labels: Vec<String>,
1087}
1088#[allow(dead_code)]
1089impl LabelSet {
1090 pub fn new() -> Self {
1092 Self { labels: Vec::new() }
1093 }
1094 pub fn add(&mut self, label: impl Into<String>) {
1096 let s = label.into();
1097 if !self.labels.contains(&s) {
1098 self.labels.push(s);
1099 }
1100 }
1101 pub fn has(&self, label: &str) -> bool {
1103 self.labels.iter().any(|l| l == label)
1104 }
1105 pub fn count(&self) -> usize {
1107 self.labels.len()
1108 }
1109 pub fn all(&self) -> &[String] {
1111 &self.labels
1112 }
1113}
1114#[allow(dead_code)]
1116pub struct PathBuf {
1117 components: Vec<String>,
1118}
1119#[allow(dead_code)]
1120impl PathBuf {
1121 pub fn new() -> Self {
1123 Self {
1124 components: Vec::new(),
1125 }
1126 }
1127 pub fn push(&mut self, comp: impl Into<String>) {
1129 self.components.push(comp.into());
1130 }
1131 pub fn pop(&mut self) {
1133 self.components.pop();
1134 }
1135 pub fn as_str(&self) -> String {
1137 self.components.join("/")
1138 }
1139 pub fn depth(&self) -> usize {
1141 self.components.len()
1142 }
1143 pub fn clear(&mut self) {
1145 self.components.clear();
1146 }
1147}
1148#[allow(dead_code)]
1150#[allow(missing_docs)]
1151pub enum DecisionNode {
1152 Leaf(String),
1154 Branch {
1156 key: String,
1157 val: String,
1158 yes_branch: Box<DecisionNode>,
1159 no_branch: Box<DecisionNode>,
1160 },
1161}
1162#[allow(dead_code)]
1163impl DecisionNode {
1164 pub fn evaluate(&self, ctx: &std::collections::HashMap<String, String>) -> &str {
1166 match self {
1167 DecisionNode::Leaf(action) => action.as_str(),
1168 DecisionNode::Branch {
1169 key,
1170 val,
1171 yes_branch,
1172 no_branch,
1173 } => {
1174 let actual = ctx.get(key).map(|s| s.as_str()).unwrap_or("");
1175 if actual == val.as_str() {
1176 yes_branch.evaluate(ctx)
1177 } else {
1178 no_branch.evaluate(ctx)
1179 }
1180 }
1181 }
1182 }
1183 pub fn depth(&self) -> usize {
1185 match self {
1186 DecisionNode::Leaf(_) => 0,
1187 DecisionNode::Branch {
1188 yes_branch,
1189 no_branch,
1190 ..
1191 } => 1 + yes_branch.depth().max(no_branch.depth()),
1192 }
1193 }
1194}
1195#[allow(dead_code)]
1197pub struct TransformStat {
1198 before: StatSummary,
1199 after: StatSummary,
1200}
1201#[allow(dead_code)]
1202impl TransformStat {
1203 pub fn new() -> Self {
1205 Self {
1206 before: StatSummary::new(),
1207 after: StatSummary::new(),
1208 }
1209 }
1210 pub fn record_before(&mut self, v: f64) {
1212 self.before.record(v);
1213 }
1214 pub fn record_after(&mut self, v: f64) {
1216 self.after.record(v);
1217 }
1218 pub fn mean_ratio(&self) -> Option<f64> {
1220 let b = self.before.mean()?;
1221 let a = self.after.mean()?;
1222 if b.abs() < f64::EPSILON {
1223 return None;
1224 }
1225 Some(a / b)
1226 }
1227}
1228#[allow(dead_code)]
1230pub struct FocusStack<T> {
1231 items: Vec<T>,
1232}
1233#[allow(dead_code)]
1234impl<T> FocusStack<T> {
1235 pub fn new() -> Self {
1237 Self { items: Vec::new() }
1238 }
1239 pub fn focus(&mut self, item: T) {
1241 self.items.push(item);
1242 }
1243 pub fn blur(&mut self) -> Option<T> {
1245 self.items.pop()
1246 }
1247 pub fn current(&self) -> Option<&T> {
1249 self.items.last()
1250 }
1251 pub fn depth(&self) -> usize {
1253 self.items.len()
1254 }
1255 pub fn is_empty(&self) -> bool {
1257 self.items.is_empty()
1258 }
1259}
1260pub struct AxiomValidator {
1262 axioms: HashSet<Name>,
1264 unsafe_axioms: HashSet<Name>,
1266 pub(super) safe_axioms: HashSet<Name>,
1268 classical_axioms: HashSet<Name>,
1270}
1271impl AxiomValidator {
1272 pub fn new() -> Self {
1274 let mut classical = HashSet::new();
1275 classical.insert(Name::str("Classical.choice"));
1276 classical.insert(Name::str("Classical.em"));
1277 classical.insert(Name::str("Classical.byContradiction"));
1278 let mut safe = HashSet::new();
1279 safe.insert(Name::str("propext"));
1280 safe.insert(Name::str("Quot.mk"));
1281 safe.insert(Name::str("Quot.lift"));
1282 safe.insert(Name::str("Quot.ind"));
1283 safe.insert(Name::str("Quot.sound"));
1284 Self {
1285 axioms: HashSet::new(),
1286 unsafe_axioms: HashSet::new(),
1287 safe_axioms: safe,
1288 classical_axioms: classical,
1289 }
1290 }
1291 pub fn register(&mut self, name: Name) {
1293 self.axioms.insert(name);
1294 }
1295 pub fn mark_unsafe(&mut self, name: Name) {
1297 self.unsafe_axioms.insert(name);
1298 }
1299 pub fn mark_safe(&mut self, name: Name) {
1301 self.safe_axioms.insert(name);
1302 }
1303 pub fn is_axiom(&self, name: &Name) -> bool {
1305 self.axioms.contains(name)
1306 }
1307 pub fn is_unsafe(&self, name: &Name) -> bool {
1309 self.unsafe_axioms.contains(name)
1310 }
1311 pub fn is_classical(&self, name: &Name) -> bool {
1313 self.classical_axioms.contains(name)
1314 }
1315 pub fn all_axioms(&self) -> Vec<&Name> {
1317 self.axioms.iter().collect()
1318 }
1319 pub fn unsafe_axioms(&self) -> Vec<&Name> {
1321 self.unsafe_axioms.iter().collect()
1322 }
1323 pub fn classify(&self, name: &Name) -> AxiomSafety {
1325 if self.unsafe_axioms.contains(name) {
1326 AxiomSafety::Unsafe
1327 } else if self.classical_axioms.contains(name) {
1328 AxiomSafety::Questionable
1329 } else if self.safe_axioms.contains(name) {
1330 AxiomSafety::Safe
1331 } else {
1332 AxiomSafety::Questionable
1333 }
1334 }
1335 pub fn check_dependencies(&self, expr: &Expr) -> HashSet<Name> {
1337 let mut deps = HashSet::new();
1338 collect_const_deps(expr, &mut deps);
1339 deps
1340 }
1341 pub fn axiom_dependencies(&self, expr: &Expr) -> HashSet<Name> {
1343 let all_deps = self.check_dependencies(expr);
1344 all_deps
1345 .into_iter()
1346 .filter(|n| self.axioms.contains(n))
1347 .collect()
1348 }
1349 pub fn is_constructive(&self, expr: &Expr) -> bool {
1351 let deps = self.check_dependencies(expr);
1352 !deps.iter().any(|n| self.classical_axioms.contains(n))
1353 }
1354}
1355#[allow(dead_code)]
1357pub struct SlidingSum {
1358 window: Vec<f64>,
1359 capacity: usize,
1360 pos: usize,
1361 sum: f64,
1362 count: usize,
1363}
1364#[allow(dead_code)]
1365impl SlidingSum {
1366 pub fn new(capacity: usize) -> Self {
1368 Self {
1369 window: vec![0.0; capacity],
1370 capacity,
1371 pos: 0,
1372 sum: 0.0,
1373 count: 0,
1374 }
1375 }
1376 pub fn push(&mut self, val: f64) {
1378 let oldest = self.window[self.pos];
1379 self.sum -= oldest;
1380 self.sum += val;
1381 self.window[self.pos] = val;
1382 self.pos = (self.pos + 1) % self.capacity;
1383 if self.count < self.capacity {
1384 self.count += 1;
1385 }
1386 }
1387 pub fn sum(&self) -> f64 {
1389 self.sum
1390 }
1391 pub fn mean(&self) -> Option<f64> {
1393 if self.count == 0 {
1394 None
1395 } else {
1396 Some(self.sum / self.count as f64)
1397 }
1398 }
1399 pub fn count(&self) -> usize {
1401 self.count
1402 }
1403}
1404#[allow(dead_code)]
1406pub struct RawFnPtr {
1407 ptr: usize,
1409 arity: usize,
1410 name: String,
1411}
1412#[allow(dead_code)]
1413impl RawFnPtr {
1414 pub fn new(ptr: usize, arity: usize, name: impl Into<String>) -> Self {
1416 Self {
1417 ptr,
1418 arity,
1419 name: name.into(),
1420 }
1421 }
1422 pub fn arity(&self) -> usize {
1424 self.arity
1425 }
1426 pub fn name(&self) -> &str {
1428 &self.name
1429 }
1430 pub fn raw(&self) -> usize {
1432 self.ptr
1433 }
1434}
1435#[allow(dead_code)]
1437pub struct AxiomAllowlist {
1438 allowed: HashSet<Name>,
1440}
1441#[allow(dead_code)]
1442impl AxiomAllowlist {
1443 pub fn empty() -> Self {
1445 AxiomAllowlist {
1446 allowed: HashSet::new(),
1447 }
1448 }
1449 pub fn classical() -> Self {
1451 let mut al = Self::empty();
1452 al.allowed.insert(Name::str("Classical.em"));
1453 al.allowed.insert(Name::str("Classical.choice"));
1454 al.allowed.insert(Name::str("propext"));
1455 al.allowed.insert(Name::str("funext"));
1456 al
1457 }
1458 pub fn allow(&mut self, name: Name) {
1460 self.allowed.insert(name);
1461 }
1462 pub fn is_allowed(&self, name: &Name) -> bool {
1464 self.allowed.contains(name)
1465 }
1466 pub fn check_env(&self, env: &Environment) -> Result<(), Vec<Name>> {
1468 let disallowed: Vec<Name> = extract_axioms(env)
1469 .into_iter()
1470 .filter(|n| !self.is_allowed(n))
1471 .collect();
1472 if disallowed.is_empty() {
1473 Ok(())
1474 } else {
1475 Err(disallowed)
1476 }
1477 }
1478}
1479#[allow(dead_code)]
1481pub struct SparseVec<T: Default + Clone + PartialEq> {
1482 entries: std::collections::HashMap<usize, T>,
1483 default_: T,
1484 logical_len: usize,
1485}
1486#[allow(dead_code)]
1487impl<T: Default + Clone + PartialEq> SparseVec<T> {
1488 pub fn new(len: usize) -> Self {
1490 Self {
1491 entries: std::collections::HashMap::new(),
1492 default_: T::default(),
1493 logical_len: len,
1494 }
1495 }
1496 pub fn set(&mut self, idx: usize, val: T) {
1498 if val == self.default_ {
1499 self.entries.remove(&idx);
1500 } else {
1501 self.entries.insert(idx, val);
1502 }
1503 }
1504 pub fn get(&self, idx: usize) -> &T {
1506 self.entries.get(&idx).unwrap_or(&self.default_)
1507 }
1508 pub fn len(&self) -> usize {
1510 self.logical_len
1511 }
1512 pub fn is_empty(&self) -> bool {
1514 self.len() == 0
1515 }
1516 pub fn nnz(&self) -> usize {
1518 self.entries.len()
1519 }
1520}
1521#[allow(dead_code)]
1523pub enum Either2<A, B> {
1524 First(A),
1526 Second(B),
1528}
1529#[allow(dead_code)]
1530impl<A, B> Either2<A, B> {
1531 pub fn is_first(&self) -> bool {
1533 matches!(self, Either2::First(_))
1534 }
1535 pub fn is_second(&self) -> bool {
1537 matches!(self, Either2::Second(_))
1538 }
1539 pub fn first(self) -> Option<A> {
1541 match self {
1542 Either2::First(a) => Some(a),
1543 _ => None,
1544 }
1545 }
1546 pub fn second(self) -> Option<B> {
1548 match self {
1549 Either2::Second(b) => Some(b),
1550 _ => None,
1551 }
1552 }
1553 pub fn map_first<C, F: FnOnce(A) -> C>(self, f: F) -> Either2<C, B> {
1555 match self {
1556 Either2::First(a) => Either2::First(f(a)),
1557 Either2::Second(b) => Either2::Second(b),
1558 }
1559 }
1560}