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 earlier: Vec<T>,
14 current: T,
16}
17#[allow(dead_code)]
18impl<T: Clone> VersionedRecord<T> {
19 pub fn new(initial: T) -> Self {
21 Self {
22 earlier: Vec::new(),
23 current: initial,
24 }
25 }
26 pub fn update(&mut self, val: T) {
28 let previous = std::mem::replace(&mut self.current, val);
29 self.earlier.push(previous);
30 }
31 pub fn current(&self) -> &T {
33 &self.current
34 }
35 pub fn at_version(&self, n: usize) -> Option<&T> {
37 match self.earlier.get(n) {
38 Some(value) => Some(value),
39 None if n == self.earlier.len() => Some(&self.current),
40 None => None,
41 }
42 }
43 pub fn version(&self) -> usize {
45 self.earlier.len()
46 }
47 pub fn has_history(&self) -> bool {
49 !self.earlier.is_empty()
50 }
51}
52#[allow(dead_code)]
54pub struct StackCalc {
55 stack: Vec<i64>,
56}
57#[allow(dead_code)]
58impl StackCalc {
59 pub fn new() -> Self {
61 Self { stack: Vec::new() }
62 }
63 pub fn push(&mut self, n: i64) {
65 self.stack.push(n);
66 }
67 fn apply_binary(&mut self, op: impl FnOnce(i64, i64) -> i64) -> Option<i64> {
71 let (rest_len, a, b) = match self.stack[..] {
72 [ref rest @ .., a, b] => (rest.len(), a, b),
73 _ => return None,
74 };
75 let value = op(a, b);
76 self.stack.truncate(rest_len);
77 self.stack.push(value);
78 Some(value)
79 }
80 pub fn add(&mut self) -> Option<i64> {
84 self.apply_binary(|a, b| a + b)
85 }
86 pub fn sub(&mut self) -> Option<i64> {
90 self.apply_binary(|a, b| a - b)
91 }
92 pub fn mul(&mut self) -> Option<i64> {
96 self.apply_binary(|a, b| a * b)
97 }
98 pub fn peek(&self) -> Option<i64> {
100 self.stack.last().copied()
101 }
102 pub fn depth(&self) -> usize {
104 self.stack.len()
105 }
106}
107#[allow(dead_code)]
111pub struct AxiomSequence {
112 entries: Vec<(Name, AxiomCategory)>,
113}
114#[allow(dead_code)]
115impl AxiomSequence {
116 pub fn new() -> Self {
118 Self {
119 entries: Vec::new(),
120 }
121 }
122 pub fn push(&mut self, name: Name) {
124 let cat = classify_axiom_category(&name);
125 self.entries.push((name, cat));
126 }
127 pub fn len(&self) -> usize {
129 self.entries.len()
130 }
131 pub fn is_empty(&self) -> bool {
133 self.entries.is_empty()
134 }
135 pub fn get(&self, i: usize) -> Option<&(Name, AxiomCategory)> {
137 self.entries.get(i)
138 }
139 pub fn classical_axioms(&self) -> Vec<&Name> {
141 self.entries
142 .iter()
143 .filter(|(_, c)| c == &AxiomCategory::Classical)
144 .map(|(n, _)| n)
145 .collect()
146 }
147 pub fn user_axioms(&self) -> Vec<&Name> {
149 self.entries
150 .iter()
151 .filter(|(_, c)| c == &AxiomCategory::UserDefined)
152 .map(|(n, _)| n)
153 .collect()
154 }
155 pub fn contains(&self, name: &Name) -> bool {
157 self.entries.iter().any(|(n, _)| n == name)
158 }
159 pub fn remove_classical(&mut self) {
161 self.entries.retain(|(_, c)| c != &AxiomCategory::Classical);
162 }
163 pub fn clear(&mut self) {
165 self.entries.clear();
166 }
167}
168#[allow(dead_code)]
170pub struct WindowIterator<'a, T> {
171 pub(super) data: &'a [T],
172 pub(super) pos: usize,
173 pub(super) window: usize,
174}
175#[allow(dead_code)]
176impl<'a, T> WindowIterator<'a, T> {
177 pub fn new(data: &'a [T], window: usize) -> Self {
179 Self {
180 data,
181 pos: 0,
182 window,
183 }
184 }
185}
186#[allow(dead_code)]
188pub struct StringPool {
189 free: Vec<String>,
190}
191#[allow(dead_code)]
192impl StringPool {
193 pub fn new() -> Self {
195 Self { free: Vec::new() }
196 }
197 pub fn take(&mut self) -> String {
199 self.free.pop().unwrap_or_default()
200 }
201 pub fn give(&mut self, mut s: String) {
203 s.clear();
204 self.free.push(s);
205 }
206 pub fn free_count(&self) -> usize {
208 self.free.len()
209 }
210}
211#[allow(dead_code)]
213#[allow(missing_docs)]
214pub struct RewriteRule {
215 pub name: String,
217 pub lhs: String,
219 pub rhs: String,
221 pub conditional: bool,
223}
224#[allow(dead_code)]
225impl RewriteRule {
226 pub fn unconditional(
228 name: impl Into<String>,
229 lhs: impl Into<String>,
230 rhs: impl Into<String>,
231 ) -> Self {
232 Self {
233 name: name.into(),
234 lhs: lhs.into(),
235 rhs: rhs.into(),
236 conditional: false,
237 }
238 }
239 pub fn conditional(
241 name: impl Into<String>,
242 lhs: impl Into<String>,
243 rhs: impl Into<String>,
244 ) -> Self {
245 Self {
246 name: name.into(),
247 lhs: lhs.into(),
248 rhs: rhs.into(),
249 conditional: true,
250 }
251 }
252 pub fn display(&self) -> String {
254 format!("{}: {} → {}", self.name, self.lhs, self.rhs)
255 }
256}
257#[allow(dead_code)]
259pub struct BucketCounter<const N: usize> {
260 buckets: [u64; N],
261}
262#[allow(dead_code)]
263impl<const N: usize> BucketCounter<N> {
264 pub const fn new() -> Self {
266 Self { buckets: [0u64; N] }
267 }
268 pub fn inc(&mut self, i: usize) {
270 if i < N {
271 self.buckets[i] += 1;
272 }
273 }
274 pub fn get(&self, i: usize) -> u64 {
276 if i < N {
277 self.buckets[i]
278 } else {
279 0
280 }
281 }
282 pub fn total(&self) -> u64 {
284 self.buckets.iter().sum()
285 }
286 pub fn argmax(&self) -> usize {
288 self.buckets
289 .iter()
290 .enumerate()
291 .max_by_key(|(_, &v)| v)
292 .map(|(i, _)| i)
293 .unwrap_or(0)
294 }
295}
296#[allow(dead_code)]
298pub struct NonEmptyVec<T> {
299 head: T,
300 tail: Vec<T>,
301}
302#[allow(dead_code)]
303impl<T> NonEmptyVec<T> {
304 pub fn singleton(val: T) -> Self {
306 Self {
307 head: val,
308 tail: Vec::new(),
309 }
310 }
311 pub fn push(&mut self, val: T) {
313 self.tail.push(val);
314 }
315 pub fn first(&self) -> &T {
317 &self.head
318 }
319 pub fn last(&self) -> &T {
321 self.tail.last().unwrap_or(&self.head)
322 }
323 pub fn len(&self) -> usize {
325 1 + self.tail.len()
326 }
327 pub fn is_empty(&self) -> bool {
329 self.len() == 0
330 }
331 pub fn to_vec(&self) -> Vec<&T> {
333 let mut v = vec![&self.head];
334 v.extend(self.tail.iter());
335 v
336 }
337}
338#[allow(dead_code)]
340pub struct Stopwatch {
341 start: crate::wall_clock::Instant,
342 splits: Vec<f64>,
343}
344#[allow(dead_code)]
345impl Stopwatch {
346 pub fn start() -> Self {
348 Self {
349 start: crate::wall_clock::Instant::now(),
350 splits: Vec::new(),
351 }
352 }
353 pub fn split(&mut self) {
355 self.splits.push(self.elapsed_ms());
356 }
357 pub fn elapsed_ms(&self) -> f64 {
359 self.start.elapsed().as_secs_f64() * 1000.0
360 }
361 pub fn splits(&self) -> &[f64] {
363 &self.splits
364 }
365 pub fn num_splits(&self) -> usize {
367 self.splits.len()
368 }
369}
370#[allow(dead_code)]
372pub struct AxiomUsageRecord {
373 pub name: Name,
375 pub direct_uses: u32,
377 pub transitive_deps: u32,
379 pub in_prop_context: bool,
381}
382#[allow(dead_code)]
383impl AxiomUsageRecord {
384 pub fn new(name: Name) -> Self {
386 AxiomUsageRecord {
387 name,
388 direct_uses: 0,
389 transitive_deps: 0,
390 in_prop_context: false,
391 }
392 }
393 pub fn record_direct_use(&mut self) {
395 self.direct_uses += 1;
396 }
397 pub fn record_transitive_dep(&mut self) {
399 self.transitive_deps += 1;
400 }
401}
402#[allow(dead_code)]
404pub struct ConfigNode {
405 key: String,
406 value: Option<String>,
407 children: Vec<ConfigNode>,
408}
409#[allow(dead_code)]
410impl ConfigNode {
411 pub fn leaf(key: impl Into<String>, value: impl Into<String>) -> Self {
413 Self {
414 key: key.into(),
415 value: Some(value.into()),
416 children: Vec::new(),
417 }
418 }
419 pub fn section(key: impl Into<String>) -> Self {
421 Self {
422 key: key.into(),
423 value: None,
424 children: Vec::new(),
425 }
426 }
427 pub fn add_child(&mut self, child: ConfigNode) {
429 self.children.push(child);
430 }
431 pub fn key(&self) -> &str {
433 &self.key
434 }
435 pub fn value(&self) -> Option<&str> {
437 self.value.as_deref()
438 }
439 pub fn num_children(&self) -> usize {
441 self.children.len()
442 }
443 pub fn lookup(&self, path: &str) -> Option<&str> {
445 let mut parts = path.splitn(2, '.');
446 let head = parts.next()?;
447 let tail = parts.next();
448 if head != self.key {
449 return None;
450 }
451 match tail {
452 None => self.value.as_deref(),
453 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
454 }
455 }
456 fn lookup_relative(&self, path: &str) -> Option<&str> {
457 let mut parts = path.splitn(2, '.');
458 let head = parts.next()?;
459 let tail = parts.next();
460 if head != self.key {
461 return None;
462 }
463 match tail {
464 None => self.value.as_deref(),
465 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
466 }
467 }
468}
469#[allow(dead_code)]
471pub struct TokenBucket {
472 capacity: u64,
473 tokens: u64,
474 refill_per_ms: u64,
475 last_refill: crate::wall_clock::Instant,
476}
477#[allow(dead_code)]
478impl TokenBucket {
479 pub fn new(capacity: u64, refill_per_ms: u64) -> Self {
481 Self {
482 capacity,
483 tokens: capacity,
484 refill_per_ms,
485 last_refill: crate::wall_clock::Instant::now(),
486 }
487 }
488 pub fn try_consume(&mut self, n: u64) -> bool {
490 self.refill();
491 if self.tokens >= n {
492 self.tokens -= n;
493 true
494 } else {
495 false
496 }
497 }
498 fn refill(&mut self) {
499 let now = crate::wall_clock::Instant::now();
500 let elapsed_ms = now.duration_since(self.last_refill).as_millis() as u64;
501 if elapsed_ms > 0 {
502 let new_tokens = elapsed_ms * self.refill_per_ms;
503 self.tokens = (self.tokens + new_tokens).min(self.capacity);
504 self.last_refill = now;
505 }
506 }
507 pub fn available(&self) -> u64 {
509 self.tokens
510 }
511 pub fn capacity(&self) -> u64 {
513 self.capacity
514 }
515}
516#[derive(Debug, Clone, Copy, PartialEq, Eq)]
518pub enum AxiomSafety {
519 Safe,
521 Questionable,
523 Unsafe,
525}
526#[allow(dead_code)]
528pub struct SimpleDag {
529 edges: Vec<Vec<usize>>,
531}
532#[allow(dead_code)]
533impl SimpleDag {
534 pub fn new(n: usize) -> Self {
536 Self {
537 edges: vec![Vec::new(); n],
538 }
539 }
540 pub fn add_edge(&mut self, from: usize, to: usize) {
542 if from < self.edges.len() {
543 self.edges[from].push(to);
544 }
545 }
546 pub fn successors(&self, node: usize) -> &[usize] {
548 self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
549 }
550 pub fn can_reach(&self, from: usize, to: usize) -> bool {
552 let mut visited = vec![false; self.edges.len()];
553 self.dfs(from, to, &mut visited)
554 }
555 fn dfs(&self, cur: usize, target: usize, visited: &mut Vec<bool>) -> bool {
556 if cur == target {
557 return true;
558 }
559 if cur >= visited.len() || visited[cur] {
560 return false;
561 }
562 visited[cur] = true;
563 for &next in self.successors(cur) {
564 if self.dfs(next, target, visited) {
565 return true;
566 }
567 }
568 false
569 }
570 pub fn topological_sort(&self) -> Option<Vec<usize>> {
572 let n = self.edges.len();
573 let mut in_degree = vec![0usize; n];
574 for succs in &self.edges {
575 for &s in succs {
576 if s < n {
577 in_degree[s] += 1;
578 }
579 }
580 }
581 let mut queue: std::collections::VecDeque<usize> =
582 (0..n).filter(|&i| in_degree[i] == 0).collect();
583 let mut order = Vec::new();
584 while let Some(node) = queue.pop_front() {
585 order.push(node);
586 for &s in self.successors(node) {
587 if s < n {
588 in_degree[s] -= 1;
589 if in_degree[s] == 0 {
590 queue.push_back(s);
591 }
592 }
593 }
594 }
595 if order.len() == n {
596 Some(order)
597 } else {
598 None
599 }
600 }
601 pub fn num_nodes(&self) -> usize {
603 self.edges.len()
604 }
605}
606#[allow(dead_code)]
608pub struct RewriteRuleSet {
609 rules: Vec<RewriteRule>,
610}
611#[allow(dead_code)]
612impl RewriteRuleSet {
613 pub fn new() -> Self {
615 Self { rules: Vec::new() }
616 }
617 pub fn add(&mut self, rule: RewriteRule) {
619 self.rules.push(rule);
620 }
621 pub fn len(&self) -> usize {
623 self.rules.len()
624 }
625 pub fn is_empty(&self) -> bool {
627 self.rules.is_empty()
628 }
629 pub fn conditional_rules(&self) -> Vec<&RewriteRule> {
631 self.rules.iter().filter(|r| r.conditional).collect()
632 }
633 pub fn unconditional_rules(&self) -> Vec<&RewriteRule> {
635 self.rules.iter().filter(|r| !r.conditional).collect()
636 }
637 pub fn get(&self, name: &str) -> Option<&RewriteRule> {
639 self.rules.iter().find(|r| r.name == name)
640 }
641}
642#[allow(dead_code)]
644#[derive(Debug, Clone, PartialEq, Eq, Hash)]
645pub enum AxiomCategory {
646 Classical,
648 Definitional,
650 External,
652 UserDefined,
654 Propositional,
656}
657#[allow(dead_code)]
659pub struct WriteOnce<T> {
660 value: std::cell::Cell<Option<T>>,
661}
662#[allow(dead_code)]
663impl<T: Copy> WriteOnce<T> {
664 pub fn new() -> Self {
666 Self {
667 value: std::cell::Cell::new(None),
668 }
669 }
670 pub fn write(&self, val: T) -> bool {
672 if self.value.get().is_some() {
673 return false;
674 }
675 self.value.set(Some(val));
676 true
677 }
678 pub fn read(&self) -> Option<T> {
680 self.value.get()
681 }
682 pub fn is_written(&self) -> bool {
684 self.value.get().is_some()
685 }
686}
687#[allow(dead_code)]
689pub struct MinHeap<T: Ord> {
690 data: Vec<T>,
691}
692#[allow(dead_code)]
693impl<T: Ord> MinHeap<T> {
694 pub fn new() -> Self {
696 Self { data: Vec::new() }
697 }
698 pub fn push(&mut self, val: T) {
700 self.data.push(val);
701 self.sift_up(self.data.len() - 1);
702 }
703 pub fn pop(&mut self) -> Option<T> {
705 if self.data.is_empty() {
706 return None;
707 }
708 let n = self.data.len();
709 self.data.swap(0, n - 1);
710 let min = self.data.pop();
711 if !self.data.is_empty() {
712 self.sift_down(0);
713 }
714 min
715 }
716 pub fn peek(&self) -> Option<&T> {
718 self.data.first()
719 }
720 pub fn len(&self) -> usize {
722 self.data.len()
723 }
724 pub fn is_empty(&self) -> bool {
726 self.data.is_empty()
727 }
728 fn sift_up(&mut self, mut i: usize) {
729 while i > 0 {
730 let parent = (i - 1) / 2;
731 if self.data[i] < self.data[parent] {
732 self.data.swap(i, parent);
733 i = parent;
734 } else {
735 break;
736 }
737 }
738 }
739 fn sift_down(&mut self, mut i: usize) {
740 let n = self.data.len();
741 loop {
742 let left = 2 * i + 1;
743 let right = 2 * i + 2;
744 let mut smallest = i;
745 if left < n && self.data[left] < self.data[smallest] {
746 smallest = left;
747 }
748 if right < n && self.data[right] < self.data[smallest] {
749 smallest = right;
750 }
751 if smallest == i {
752 break;
753 }
754 self.data.swap(i, smallest);
755 i = smallest;
756 }
757 }
758}
759#[allow(dead_code)]
761pub struct PrefixCounter {
762 children: std::collections::HashMap<char, PrefixCounter>,
763 count: usize,
764}
765#[allow(dead_code)]
766impl PrefixCounter {
767 pub fn new() -> Self {
769 Self {
770 children: std::collections::HashMap::new(),
771 count: 0,
772 }
773 }
774 pub fn record(&mut self, s: &str) {
776 self.count += 1;
777 let mut node = self;
778 for c in s.chars() {
779 node = node.children.entry(c).or_default();
780 node.count += 1;
781 }
782 }
783 pub fn count_with_prefix(&self, prefix: &str) -> usize {
785 let mut node = self;
786 for c in prefix.chars() {
787 match node.children.get(&c) {
788 Some(n) => node = n,
789 None => return 0,
790 }
791 }
792 node.count
793 }
794}
795#[allow(dead_code)]
797pub struct AxiomSafetyReport {
798 pub total_axioms: usize,
800 pub classical_count: usize,
802 pub external_count: usize,
804 pub classically_consistent: bool,
806 pub warnings: Vec<String>,
808}
809#[allow(dead_code)]
810impl AxiomSafetyReport {
811 pub fn empty() -> Self {
813 AxiomSafetyReport {
814 total_axioms: 0,
815 classical_count: 0,
816 external_count: 0,
817 classically_consistent: true,
818 warnings: Vec::new(),
819 }
820 }
821 pub fn is_axiom_free(&self) -> bool {
823 self.total_axioms == 0
824 }
825 pub fn warn(&mut self, msg: impl Into<String>) {
827 self.warnings.push(msg.into());
828 }
829}
830#[allow(dead_code)]
832pub struct SmallMap<K: Ord + Clone, V: Clone> {
833 entries: Vec<(K, V)>,
834}
835#[allow(dead_code)]
836impl<K: Ord + Clone, V: Clone> SmallMap<K, V> {
837 pub fn new() -> Self {
839 Self {
840 entries: Vec::new(),
841 }
842 }
843 pub fn insert(&mut self, key: K, val: V) {
845 match self.entries.binary_search_by_key(&&key, |(k, _)| k) {
846 Ok(i) => self.entries[i].1 = val,
847 Err(i) => self.entries.insert(i, (key, val)),
848 }
849 }
850 pub fn get(&self, key: &K) -> Option<&V> {
852 self.entries
853 .binary_search_by_key(&key, |(k, _)| k)
854 .ok()
855 .map(|i| &self.entries[i].1)
856 }
857 pub fn len(&self) -> usize {
859 self.entries.len()
860 }
861 pub fn is_empty(&self) -> bool {
863 self.entries.is_empty()
864 }
865 pub fn keys(&self) -> Vec<&K> {
867 self.entries.iter().map(|(k, _)| k).collect()
868 }
869 pub fn values(&self) -> Vec<&V> {
871 self.entries.iter().map(|(_, v)| v).collect()
872 }
873}
874#[allow(dead_code)]
876pub struct TransitiveClosure {
877 adj: Vec<Vec<usize>>,
878 n: usize,
879}
880#[allow(dead_code)]
881impl TransitiveClosure {
882 pub fn new(n: usize) -> Self {
884 Self {
885 adj: vec![Vec::new(); n],
886 n,
887 }
888 }
889 pub fn add_edge(&mut self, from: usize, to: usize) {
891 if from < self.n {
892 self.adj[from].push(to);
893 }
894 }
895 pub fn reachable_from(&self, start: usize) -> Vec<usize> {
897 let mut visited = vec![false; self.n];
898 let mut queue = std::collections::VecDeque::new();
899 queue.push_back(start);
900 while let Some(node) = queue.pop_front() {
901 if node >= self.n || visited[node] {
902 continue;
903 }
904 visited[node] = true;
905 for &next in &self.adj[node] {
906 queue.push_back(next);
907 }
908 }
909 (0..self.n).filter(|&i| visited[i]).collect()
910 }
911 pub fn can_reach(&self, from: usize, to: usize) -> bool {
913 self.reachable_from(from).contains(&to)
914 }
915}
916#[allow(dead_code)]
918pub struct FlatSubstitution {
919 pairs: Vec<(String, String)>,
920}
921#[allow(dead_code)]
922impl FlatSubstitution {
923 pub fn new() -> Self {
925 Self { pairs: Vec::new() }
926 }
927 pub fn add(&mut self, from: impl Into<String>, to: impl Into<String>) {
929 self.pairs.push((from.into(), to.into()));
930 }
931 pub fn apply(&self, s: &str) -> String {
933 let mut result = s.to_string();
934 for (from, to) in &self.pairs {
935 result = result.replace(from.as_str(), to.as_str());
936 }
937 result
938 }
939 pub fn len(&self) -> usize {
941 self.pairs.len()
942 }
943 pub fn is_empty(&self) -> bool {
945 self.pairs.is_empty()
946 }
947}
948#[allow(dead_code)]
950pub struct StatSummary {
951 count: u64,
952 sum: f64,
953 min: f64,
954 max: f64,
955}
956#[allow(dead_code)]
957impl StatSummary {
958 pub fn new() -> Self {
960 Self {
961 count: 0,
962 sum: 0.0,
963 min: f64::INFINITY,
964 max: f64::NEG_INFINITY,
965 }
966 }
967 pub fn record(&mut self, val: f64) {
969 self.count += 1;
970 self.sum += val;
971 if val < self.min {
972 self.min = val;
973 }
974 if val > self.max {
975 self.max = val;
976 }
977 }
978 pub fn mean(&self) -> Option<f64> {
980 if self.count == 0 {
981 None
982 } else {
983 Some(self.sum / self.count as f64)
984 }
985 }
986 pub fn min(&self) -> Option<f64> {
988 if self.count == 0 {
989 None
990 } else {
991 Some(self.min)
992 }
993 }
994 pub fn max(&self) -> Option<f64> {
996 if self.count == 0 {
997 None
998 } else {
999 Some(self.max)
1000 }
1001 }
1002 pub fn count(&self) -> u64 {
1004 self.count
1005 }
1006}
1007#[allow(dead_code)]
1009pub struct Fixture {
1010 data: std::collections::HashMap<String, String>,
1011}
1012#[allow(dead_code)]
1013impl Fixture {
1014 pub fn new() -> Self {
1016 Self {
1017 data: std::collections::HashMap::new(),
1018 }
1019 }
1020 pub fn set(&mut self, key: impl Into<String>, val: impl Into<String>) {
1022 self.data.insert(key.into(), val.into());
1023 }
1024 pub fn get(&self, key: &str) -> Option<&str> {
1026 self.data.get(key).map(|s| s.as_str())
1027 }
1028 pub fn len(&self) -> usize {
1030 self.data.len()
1031 }
1032 pub fn is_empty(&self) -> bool {
1034 self.len() == 0
1035 }
1036}
1037#[allow(dead_code)]
1039pub struct BitSet64 {
1040 bits: u64,
1041}
1042#[allow(dead_code)]
1043impl BitSet64 {
1044 pub const fn new() -> Self {
1046 Self { bits: 0 }
1047 }
1048 pub fn insert(&mut self, i: u32) {
1050 if i < 64 {
1051 self.bits |= 1u64 << i;
1052 }
1053 }
1054 pub fn remove(&mut self, i: u32) {
1056 if i < 64 {
1057 self.bits &= !(1u64 << i);
1058 }
1059 }
1060 pub fn contains(&self, i: u32) -> bool {
1062 i < 64 && (self.bits >> i) & 1 != 0
1063 }
1064 pub fn len(&self) -> u32 {
1066 self.bits.count_ones()
1067 }
1068 pub fn is_empty(&self) -> bool {
1070 self.bits == 0
1071 }
1072 pub fn union(self, other: BitSet64) -> BitSet64 {
1074 BitSet64 {
1075 bits: self.bits | other.bits,
1076 }
1077 }
1078 pub fn intersect(self, other: BitSet64) -> BitSet64 {
1080 BitSet64 {
1081 bits: self.bits & other.bits,
1082 }
1083 }
1084}
1085#[allow(dead_code)]
1087pub struct LabelSet {
1088 labels: Vec<String>,
1089}
1090#[allow(dead_code)]
1091impl LabelSet {
1092 pub fn new() -> Self {
1094 Self { labels: Vec::new() }
1095 }
1096 pub fn add(&mut self, label: impl Into<String>) {
1098 let s = label.into();
1099 if !self.labels.contains(&s) {
1100 self.labels.push(s);
1101 }
1102 }
1103 pub fn has(&self, label: &str) -> bool {
1105 self.labels.iter().any(|l| l == label)
1106 }
1107 pub fn count(&self) -> usize {
1109 self.labels.len()
1110 }
1111 pub fn all(&self) -> &[String] {
1113 &self.labels
1114 }
1115}
1116#[allow(dead_code)]
1118pub struct PathBuf {
1119 components: Vec<String>,
1120}
1121#[allow(dead_code)]
1122impl PathBuf {
1123 pub fn new() -> Self {
1125 Self {
1126 components: Vec::new(),
1127 }
1128 }
1129 pub fn push(&mut self, comp: impl Into<String>) {
1131 self.components.push(comp.into());
1132 }
1133 pub fn pop(&mut self) {
1135 self.components.pop();
1136 }
1137 pub fn as_str(&self) -> String {
1139 self.components.join("/")
1140 }
1141 pub fn depth(&self) -> usize {
1143 self.components.len()
1144 }
1145 pub fn clear(&mut self) {
1147 self.components.clear();
1148 }
1149}
1150#[allow(dead_code)]
1152#[allow(missing_docs)]
1153pub enum DecisionNode {
1154 Leaf(String),
1156 Branch {
1158 key: String,
1159 val: String,
1160 yes_branch: Box<DecisionNode>,
1161 no_branch: Box<DecisionNode>,
1162 },
1163}
1164#[allow(dead_code)]
1165impl DecisionNode {
1166 pub fn evaluate(&self, ctx: &std::collections::HashMap<String, String>) -> &str {
1168 match self {
1169 DecisionNode::Leaf(action) => action.as_str(),
1170 DecisionNode::Branch {
1171 key,
1172 val,
1173 yes_branch,
1174 no_branch,
1175 } => {
1176 let actual = ctx.get(key).map(|s| s.as_str()).unwrap_or("");
1177 if actual == val.as_str() {
1178 yes_branch.evaluate(ctx)
1179 } else {
1180 no_branch.evaluate(ctx)
1181 }
1182 }
1183 }
1184 }
1185 pub fn depth(&self) -> usize {
1187 match self {
1188 DecisionNode::Leaf(_) => 0,
1189 DecisionNode::Branch {
1190 yes_branch,
1191 no_branch,
1192 ..
1193 } => 1 + yes_branch.depth().max(no_branch.depth()),
1194 }
1195 }
1196}
1197#[allow(dead_code)]
1199pub struct TransformStat {
1200 before: StatSummary,
1201 after: StatSummary,
1202}
1203#[allow(dead_code)]
1204impl TransformStat {
1205 pub fn new() -> Self {
1207 Self {
1208 before: StatSummary::new(),
1209 after: StatSummary::new(),
1210 }
1211 }
1212 pub fn record_before(&mut self, v: f64) {
1214 self.before.record(v);
1215 }
1216 pub fn record_after(&mut self, v: f64) {
1218 self.after.record(v);
1219 }
1220 pub fn mean_ratio(&self) -> Option<f64> {
1222 let b = self.before.mean()?;
1223 let a = self.after.mean()?;
1224 if b.abs() < f64::EPSILON {
1225 return None;
1226 }
1227 Some(a / b)
1228 }
1229}
1230#[allow(dead_code)]
1232pub struct FocusStack<T> {
1233 items: Vec<T>,
1234}
1235#[allow(dead_code)]
1236impl<T> FocusStack<T> {
1237 pub fn new() -> Self {
1239 Self { items: Vec::new() }
1240 }
1241 pub fn focus(&mut self, item: T) {
1243 self.items.push(item);
1244 }
1245 pub fn blur(&mut self) -> Option<T> {
1247 self.items.pop()
1248 }
1249 pub fn current(&self) -> Option<&T> {
1251 self.items.last()
1252 }
1253 pub fn depth(&self) -> usize {
1255 self.items.len()
1256 }
1257 pub fn is_empty(&self) -> bool {
1259 self.items.is_empty()
1260 }
1261}
1262pub struct AxiomValidator {
1264 axioms: HashSet<Name>,
1266 unsafe_axioms: HashSet<Name>,
1268 pub(super) safe_axioms: HashSet<Name>,
1270 classical_axioms: HashSet<Name>,
1272}
1273impl AxiomValidator {
1274 pub fn new() -> Self {
1276 let mut classical = HashSet::new();
1277 classical.insert(Name::str("Classical.choice"));
1278 classical.insert(Name::str("Classical.em"));
1279 classical.insert(Name::str("Classical.byContradiction"));
1280 let mut safe = HashSet::new();
1281 safe.insert(Name::str("propext"));
1282 safe.insert(Name::str("Quot.mk"));
1283 safe.insert(Name::str("Quot.lift"));
1284 safe.insert(Name::str("Quot.ind"));
1285 safe.insert(Name::str("Quot.sound"));
1286 Self {
1287 axioms: HashSet::new(),
1288 unsafe_axioms: HashSet::new(),
1289 safe_axioms: safe,
1290 classical_axioms: classical,
1291 }
1292 }
1293 pub fn register(&mut self, name: Name) {
1295 self.axioms.insert(name);
1296 }
1297 pub fn mark_unsafe(&mut self, name: Name) {
1299 self.unsafe_axioms.insert(name);
1300 }
1301 pub fn mark_safe(&mut self, name: Name) {
1303 self.safe_axioms.insert(name);
1304 }
1305 pub fn is_axiom(&self, name: &Name) -> bool {
1307 self.axioms.contains(name)
1308 }
1309 pub fn is_unsafe(&self, name: &Name) -> bool {
1311 self.unsafe_axioms.contains(name)
1312 }
1313 pub fn is_classical(&self, name: &Name) -> bool {
1315 self.classical_axioms.contains(name)
1316 }
1317 pub fn all_axioms(&self) -> Vec<&Name> {
1319 self.axioms.iter().collect()
1320 }
1321 pub fn unsafe_axioms(&self) -> Vec<&Name> {
1323 self.unsafe_axioms.iter().collect()
1324 }
1325 pub fn classify(&self, name: &Name) -> AxiomSafety {
1327 if self.unsafe_axioms.contains(name) {
1328 AxiomSafety::Unsafe
1329 } else if self.classical_axioms.contains(name) {
1330 AxiomSafety::Questionable
1331 } else if self.safe_axioms.contains(name) {
1332 AxiomSafety::Safe
1333 } else {
1334 AxiomSafety::Questionable
1335 }
1336 }
1337 pub fn check_dependencies(&self, expr: &Expr) -> HashSet<Name> {
1339 let mut deps = HashSet::new();
1340 collect_const_deps(expr, &mut deps);
1341 deps
1342 }
1343 pub fn axiom_dependencies(&self, expr: &Expr) -> HashSet<Name> {
1345 let all_deps = self.check_dependencies(expr);
1346 all_deps
1347 .into_iter()
1348 .filter(|n| self.axioms.contains(n))
1349 .collect()
1350 }
1351 pub fn is_constructive(&self, expr: &Expr) -> bool {
1353 let deps = self.check_dependencies(expr);
1354 !deps.iter().any(|n| self.classical_axioms.contains(n))
1355 }
1356}
1357#[allow(dead_code)]
1359pub struct SlidingSum {
1360 window: Vec<f64>,
1361 capacity: usize,
1362 pos: usize,
1363 sum: f64,
1364 count: usize,
1365}
1366#[allow(dead_code)]
1367impl SlidingSum {
1368 pub fn new(capacity: usize) -> Self {
1370 Self {
1371 window: vec![0.0; capacity],
1372 capacity,
1373 pos: 0,
1374 sum: 0.0,
1375 count: 0,
1376 }
1377 }
1378 pub fn push(&mut self, val: f64) {
1380 let oldest = self.window[self.pos];
1381 self.sum -= oldest;
1382 self.sum += val;
1383 self.window[self.pos] = val;
1384 self.pos = (self.pos + 1) % self.capacity;
1385 if self.count < self.capacity {
1386 self.count += 1;
1387 }
1388 }
1389 pub fn sum(&self) -> f64 {
1391 self.sum
1392 }
1393 pub fn mean(&self) -> Option<f64> {
1395 if self.count == 0 {
1396 None
1397 } else {
1398 Some(self.sum / self.count as f64)
1399 }
1400 }
1401 pub fn count(&self) -> usize {
1403 self.count
1404 }
1405}
1406#[allow(dead_code)]
1408pub struct RawFnPtr {
1409 ptr: usize,
1411 arity: usize,
1412 name: String,
1413}
1414#[allow(dead_code)]
1415impl RawFnPtr {
1416 pub fn new(ptr: usize, arity: usize, name: impl Into<String>) -> Self {
1418 Self {
1419 ptr,
1420 arity,
1421 name: name.into(),
1422 }
1423 }
1424 pub fn arity(&self) -> usize {
1426 self.arity
1427 }
1428 pub fn name(&self) -> &str {
1430 &self.name
1431 }
1432 pub fn raw(&self) -> usize {
1434 self.ptr
1435 }
1436}
1437#[allow(dead_code)]
1439pub struct AxiomAllowlist {
1440 allowed: HashSet<Name>,
1442}
1443#[allow(dead_code)]
1444impl AxiomAllowlist {
1445 pub fn empty() -> Self {
1447 AxiomAllowlist {
1448 allowed: HashSet::new(),
1449 }
1450 }
1451 pub fn classical() -> Self {
1453 let mut al = Self::empty();
1454 al.allowed.insert(Name::str("Classical.em"));
1455 al.allowed.insert(Name::str("Classical.choice"));
1456 al.allowed.insert(Name::str("propext"));
1457 al.allowed.insert(Name::str("funext"));
1458 al
1459 }
1460 pub fn allow(&mut self, name: Name) {
1462 self.allowed.insert(name);
1463 }
1464 pub fn is_allowed(&self, name: &Name) -> bool {
1466 self.allowed.contains(name)
1467 }
1468 pub fn check_env(&self, env: &Environment) -> Result<(), Vec<Name>> {
1470 let disallowed: Vec<Name> = extract_axioms(env)
1471 .into_iter()
1472 .filter(|n| !self.is_allowed(n))
1473 .collect();
1474 if disallowed.is_empty() {
1475 Ok(())
1476 } else {
1477 Err(disallowed)
1478 }
1479 }
1480}
1481#[allow(dead_code)]
1483pub struct SparseVec<T: Default + Clone + PartialEq> {
1484 entries: std::collections::HashMap<usize, T>,
1485 default_: T,
1486 logical_len: usize,
1487}
1488#[allow(dead_code)]
1489impl<T: Default + Clone + PartialEq> SparseVec<T> {
1490 pub fn new(len: usize) -> Self {
1492 Self {
1493 entries: std::collections::HashMap::new(),
1494 default_: T::default(),
1495 logical_len: len,
1496 }
1497 }
1498 pub fn set(&mut self, idx: usize, val: T) {
1500 if val == self.default_ {
1501 self.entries.remove(&idx);
1502 } else {
1503 self.entries.insert(idx, val);
1504 }
1505 }
1506 pub fn get(&self, idx: usize) -> &T {
1508 self.entries.get(&idx).unwrap_or(&self.default_)
1509 }
1510 pub fn len(&self) -> usize {
1512 self.logical_len
1513 }
1514 pub fn is_empty(&self) -> bool {
1516 self.len() == 0
1517 }
1518 pub fn nnz(&self) -> usize {
1520 self.entries.len()
1521 }
1522}
1523#[allow(dead_code)]
1525pub enum Either2<A, B> {
1526 First(A),
1528 Second(B),
1530}
1531#[allow(dead_code)]
1532impl<A, B> Either2<A, B> {
1533 pub fn is_first(&self) -> bool {
1535 matches!(self, Either2::First(_))
1536 }
1537 pub fn is_second(&self) -> bool {
1539 matches!(self, Either2::Second(_))
1540 }
1541 pub fn first(self) -> Option<A> {
1543 match self {
1544 Either2::First(a) => Some(a),
1545 _ => None,
1546 }
1547 }
1548 pub fn second(self) -> Option<B> {
1550 match self {
1551 Either2::Second(b) => Some(b),
1552 _ => None,
1553 }
1554 }
1555 pub fn map_first<C, F: FnOnce(A) -> C>(self, f: F) -> Either2<C, B> {
1557 match self {
1558 Either2::First(a) => Either2::First(f(a)),
1559 Either2::Second(b) => Either2::Second(b),
1560 }
1561 }
1562}