1use crate::{Expr, Name};
6use std::collections::{HashMap, HashSet};
7
8use super::functions::{mk_congr_theorem, TermIdx};
9
10#[allow(dead_code)]
12pub struct FlatSubstitution {
13 pairs: Vec<(String, String)>,
14}
15#[allow(dead_code)]
16impl FlatSubstitution {
17 pub fn new() -> Self {
19 Self { pairs: Vec::new() }
20 }
21 pub fn add(&mut self, from: impl Into<String>, to: impl Into<String>) {
23 self.pairs.push((from.into(), to.into()));
24 }
25 pub fn apply(&self, s: &str) -> String {
27 let mut result = s.to_string();
28 for (from, to) in &self.pairs {
29 result = result.replace(from.as_str(), to.as_str());
30 }
31 result
32 }
33 pub fn len(&self) -> usize {
35 self.pairs.len()
36 }
37 pub fn is_empty(&self) -> bool {
39 self.pairs.is_empty()
40 }
41}
42pub struct InstrumentedCC {
44 pub cc: CongruenceClosure,
46 pub stats: CongrClosureStats,
48}
49impl InstrumentedCC {
50 pub fn new() -> Self {
52 Self {
53 cc: CongruenceClosure::new(),
54 stats: CongrClosureStats::new(),
55 }
56 }
57 pub fn add_equality(&mut self, e1: Expr, e2: Expr) {
59 let before = self.cc.num_classes();
60 self.cc.add_equality(e1, e2);
61 let after = self.cc.num_classes();
62 if after < before {
63 self.stats.unions += 1;
64 }
65 self.stats.equalities_added += 1;
66 self.stats.apps_tracked = self.cc.apps.len();
67 }
68 pub fn are_equal(&mut self, e1: &Expr, e2: &Expr) -> bool {
70 self.cc.are_equal(e1, e2)
71 }
72 pub fn reset(&mut self) {
74 self.cc.clear();
75 self.stats = CongrClosureStats::new();
76 }
77 pub fn num_classes(&mut self) -> usize {
79 self.cc.num_classes()
80 }
81}
82pub struct EGraph {
86 nodes: Vec<ENode>,
88}
89impl EGraph {
90 pub fn new() -> Self {
92 Self { nodes: Vec::new() }
93 }
94 pub fn add_expr(&mut self, expr: Expr) -> usize {
96 for (i, node) in self.nodes.iter().enumerate() {
97 if node.contains(&expr) {
98 return i;
99 }
100 }
101 self.nodes.push(ENode::singleton(expr));
102 self.nodes.len() - 1
103 }
104 pub fn find_class(&self, expr: &Expr) -> Option<usize> {
106 self.nodes.iter().position(|n| n.contains(expr))
107 }
108 pub fn merge_classes(&mut self, id1: usize, id2: usize, proof: Option<Expr>) {
110 if id1 == id2 {
111 return;
112 }
113 let (small_id, large_id) = if id1 < id2 { (id2, id1) } else { (id1, id2) };
114 let small = self.nodes.remove(small_id);
115 for (m, p) in small.members.into_iter().zip(small.proofs.into_iter()) {
116 let proof_for = proof.clone().or(p);
117 self.nodes[large_id].add_member(m, proof_for);
118 }
119 }
120 pub fn are_equal(&self, e1: &Expr, e2: &Expr) -> bool {
122 match (self.find_class(e1), self.find_class(e2)) {
123 (Some(c1), Some(c2)) => c1 == c2,
124 _ => false,
125 }
126 }
127 pub fn add_equality(&mut self, e1: Expr, e2: Expr, proof: Option<Expr>) {
129 let c1 = self.add_expr(e1);
130 let c2 = self.add_expr(e2);
131 if c1 != c2 {
132 self.merge_classes(c1, c2, proof);
133 }
134 }
135 pub fn num_classes(&self) -> usize {
137 self.nodes.len()
138 }
139 pub fn get_class(&self, id: usize) -> Option<&ENode> {
141 self.nodes.get(id)
142 }
143 pub fn representative(&self, expr: &Expr) -> Option<&Expr> {
145 self.find_class(expr)
146 .and_then(|id| self.nodes.get(id))
147 .map(|n| &n.repr)
148 }
149 pub fn clear(&mut self) {
151 self.nodes.clear();
152 }
153}
154#[derive(Debug, Clone)]
156pub enum CongrProof {
157 Refl(Expr),
159 Symm(Box<CongrProof>),
161 Trans(Box<CongrProof>, Box<CongrProof>),
163 Congr(Box<CongrProof>, Box<CongrProof>),
165 Hyp(Name),
167}
168impl CongrProof {
169 pub fn depth(&self) -> usize {
171 match self {
172 CongrProof::Refl(_) | CongrProof::Hyp(_) => 0,
173 CongrProof::Symm(p) => 1 + p.depth(),
174 CongrProof::Trans(p, q) | CongrProof::Congr(p, q) => 1 + p.depth().max(q.depth()),
175 }
176 }
177 pub fn is_refl(&self) -> bool {
179 matches!(self, CongrProof::Refl(_))
180 }
181 pub fn hypothesis_count(&self) -> usize {
183 match self {
184 CongrProof::Hyp(_) => 1,
185 CongrProof::Refl(_) => 0,
186 CongrProof::Symm(p) => p.hypothesis_count(),
187 CongrProof::Trans(p, q) | CongrProof::Congr(p, q) => {
188 p.hypothesis_count() + q.hypothesis_count()
189 }
190 }
191 }
192 pub fn simplify(self) -> Self {
194 match self {
195 CongrProof::Symm(inner) => match *inner {
196 CongrProof::Symm(p) => p.simplify(),
197 other => CongrProof::Symm(Box::new(other.simplify())),
198 },
199 CongrProof::Trans(p, q) => {
200 CongrProof::Trans(Box::new(p.simplify()), Box::new(q.simplify()))
201 }
202 CongrProof::Congr(p, q) => {
203 CongrProof::Congr(Box::new(p.simplify()), Box::new(q.simplify()))
204 }
205 other => other,
206 }
207 }
208}
209#[allow(dead_code)]
211pub struct WindowIterator<'a, T> {
212 pub(super) data: &'a [T],
213 pub(super) pos: usize,
214 pub(super) window: usize,
215}
216#[allow(dead_code)]
217impl<'a, T> WindowIterator<'a, T> {
218 pub fn new(data: &'a [T], window: usize) -> Self {
220 Self {
221 data,
222 pos: 0,
223 window,
224 }
225 }
226}
227#[allow(dead_code)]
229#[allow(missing_docs)]
230pub struct RewriteRule {
231 pub name: String,
233 pub lhs: String,
235 pub rhs: String,
237 pub conditional: bool,
239}
240#[allow(dead_code)]
241impl RewriteRule {
242 pub fn unconditional(
244 name: impl Into<String>,
245 lhs: impl Into<String>,
246 rhs: impl Into<String>,
247 ) -> Self {
248 Self {
249 name: name.into(),
250 lhs: lhs.into(),
251 rhs: rhs.into(),
252 conditional: false,
253 }
254 }
255 pub fn conditional(
257 name: impl Into<String>,
258 lhs: impl Into<String>,
259 rhs: impl Into<String>,
260 ) -> Self {
261 Self {
262 name: name.into(),
263 lhs: lhs.into(),
264 rhs: rhs.into(),
265 conditional: true,
266 }
267 }
268 pub fn display(&self) -> String {
270 format!("{}: {} → {}", self.name, self.lhs, self.rhs)
271 }
272}
273#[allow(dead_code)]
275pub struct PrefixCounter {
276 children: std::collections::HashMap<char, PrefixCounter>,
277 count: usize,
278}
279#[allow(dead_code)]
280impl PrefixCounter {
281 pub fn new() -> Self {
283 Self {
284 children: std::collections::HashMap::new(),
285 count: 0,
286 }
287 }
288 pub fn record(&mut self, s: &str) {
290 self.count += 1;
291 let mut node = self;
292 for c in s.chars() {
293 node = node.children.entry(c).or_default();
294 node.count += 1;
295 }
296 }
297 pub fn count_with_prefix(&self, prefix: &str) -> usize {
299 let mut node = self;
300 for c in prefix.chars() {
301 match node.children.get(&c) {
302 Some(n) => node = n,
303 None => return 0,
304 }
305 }
306 node.count
307 }
308}
309#[allow(dead_code)]
311pub struct NonEmptyVec<T> {
312 head: T,
313 tail: Vec<T>,
314}
315#[allow(dead_code)]
316impl<T> NonEmptyVec<T> {
317 pub fn singleton(val: T) -> Self {
319 Self {
320 head: val,
321 tail: Vec::new(),
322 }
323 }
324 pub fn push(&mut self, val: T) {
326 self.tail.push(val);
327 }
328 pub fn first(&self) -> &T {
330 &self.head
331 }
332 pub fn last(&self) -> &T {
334 self.tail.last().unwrap_or(&self.head)
335 }
336 pub fn len(&self) -> usize {
338 1 + self.tail.len()
339 }
340 pub fn is_empty(&self) -> bool {
342 self.len() == 0
343 }
344 pub fn to_vec(&self) -> Vec<&T> {
346 let mut v = vec![&self.head];
347 v.extend(self.tail.iter());
348 v
349 }
350}
351#[allow(dead_code)]
353pub struct SlidingSum {
354 window: Vec<f64>,
355 capacity: usize,
356 pos: usize,
357 sum: f64,
358 count: usize,
359}
360#[allow(dead_code)]
361impl SlidingSum {
362 pub fn new(capacity: usize) -> Self {
364 Self {
365 window: vec![0.0; capacity],
366 capacity,
367 pos: 0,
368 sum: 0.0,
369 count: 0,
370 }
371 }
372 pub fn push(&mut self, val: f64) {
374 let oldest = self.window[self.pos];
375 self.sum -= oldest;
376 self.sum += val;
377 self.window[self.pos] = val;
378 self.pos = (self.pos + 1) % self.capacity;
379 if self.count < self.capacity {
380 self.count += 1;
381 }
382 }
383 pub fn sum(&self) -> f64 {
385 self.sum
386 }
387 pub fn mean(&self) -> Option<f64> {
389 if self.count == 0 {
390 None
391 } else {
392 Some(self.sum / self.count as f64)
393 }
394 }
395 pub fn count(&self) -> usize {
397 self.count
398 }
399}
400#[allow(dead_code)]
402pub struct RewriteRuleSet {
403 rules: Vec<RewriteRule>,
404}
405#[allow(dead_code)]
406impl RewriteRuleSet {
407 pub fn new() -> Self {
409 Self { rules: Vec::new() }
410 }
411 pub fn add(&mut self, rule: RewriteRule) {
413 self.rules.push(rule);
414 }
415 pub fn len(&self) -> usize {
417 self.rules.len()
418 }
419 pub fn is_empty(&self) -> bool {
421 self.rules.is_empty()
422 }
423 pub fn conditional_rules(&self) -> Vec<&RewriteRule> {
425 self.rules.iter().filter(|r| r.conditional).collect()
426 }
427 pub fn unconditional_rules(&self) -> Vec<&RewriteRule> {
429 self.rules.iter().filter(|r| !r.conditional).collect()
430 }
431 pub fn get(&self, name: &str) -> Option<&RewriteRule> {
433 self.rules.iter().find(|r| r.name == name)
434 }
435}
436#[allow(dead_code)]
438pub struct PathBuf {
439 components: Vec<String>,
440}
441#[allow(dead_code)]
442impl PathBuf {
443 pub fn new() -> Self {
445 Self {
446 components: Vec::new(),
447 }
448 }
449 pub fn push(&mut self, comp: impl Into<String>) {
451 self.components.push(comp.into());
452 }
453 pub fn pop(&mut self) {
455 self.components.pop();
456 }
457 pub fn as_str(&self) -> String {
459 self.components.join("/")
460 }
461 pub fn depth(&self) -> usize {
463 self.components.len()
464 }
465 pub fn clear(&mut self) {
467 self.components.clear();
468 }
469}
470#[allow(dead_code)]
472pub struct ConfigNode {
473 key: String,
474 value: Option<String>,
475 children: Vec<ConfigNode>,
476}
477#[allow(dead_code)]
478impl ConfigNode {
479 pub fn leaf(key: impl Into<String>, value: impl Into<String>) -> Self {
481 Self {
482 key: key.into(),
483 value: Some(value.into()),
484 children: Vec::new(),
485 }
486 }
487 pub fn section(key: impl Into<String>) -> Self {
489 Self {
490 key: key.into(),
491 value: None,
492 children: Vec::new(),
493 }
494 }
495 pub fn add_child(&mut self, child: ConfigNode) {
497 self.children.push(child);
498 }
499 pub fn key(&self) -> &str {
501 &self.key
502 }
503 pub fn value(&self) -> Option<&str> {
505 self.value.as_deref()
506 }
507 pub fn num_children(&self) -> usize {
509 self.children.len()
510 }
511 pub fn lookup(&self, path: &str) -> Option<&str> {
513 let mut parts = path.splitn(2, '.');
514 let head = parts.next()?;
515 let tail = parts.next();
516 if head != self.key {
517 return None;
518 }
519 match tail {
520 None => self.value.as_deref(),
521 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
522 }
523 }
524 fn lookup_relative(&self, path: &str) -> Option<&str> {
525 let mut parts = path.splitn(2, '.');
526 let head = parts.next()?;
527 let tail = parts.next();
528 if head != self.key {
529 return None;
530 }
531 match tail {
532 None => self.value.as_deref(),
533 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
534 }
535 }
536}
537#[allow(dead_code)]
539pub struct TokenBucket {
540 capacity: u64,
541 tokens: u64,
542 refill_per_ms: u64,
543 last_refill: std::time::Instant,
544}
545#[allow(dead_code)]
546impl TokenBucket {
547 pub fn new(capacity: u64, refill_per_ms: u64) -> Self {
549 Self {
550 capacity,
551 tokens: capacity,
552 refill_per_ms,
553 last_refill: std::time::Instant::now(),
554 }
555 }
556 pub fn try_consume(&mut self, n: u64) -> bool {
558 self.refill();
559 if self.tokens >= n {
560 self.tokens -= n;
561 true
562 } else {
563 false
564 }
565 }
566 fn refill(&mut self) {
567 let now = std::time::Instant::now();
568 let elapsed_ms = now.duration_since(self.last_refill).as_millis() as u64;
569 if elapsed_ms > 0 {
570 let new_tokens = elapsed_ms * self.refill_per_ms;
571 self.tokens = (self.tokens + new_tokens).min(self.capacity);
572 self.last_refill = now;
573 }
574 }
575 pub fn available(&self) -> u64 {
577 self.tokens
578 }
579 pub fn capacity(&self) -> u64 {
581 self.capacity
582 }
583}
584#[allow(dead_code)]
586pub struct VersionedRecord<T: Clone> {
587 history: Vec<T>,
588}
589#[allow(dead_code)]
590impl<T: Clone> VersionedRecord<T> {
591 pub fn new(initial: T) -> Self {
593 Self {
594 history: vec![initial],
595 }
596 }
597 pub fn update(&mut self, val: T) {
599 self.history.push(val);
600 }
601 pub fn current(&self) -> &T {
603 self.history
604 .last()
605 .expect("VersionedRecord history is always non-empty after construction")
606 }
607 pub fn at_version(&self, n: usize) -> Option<&T> {
609 self.history.get(n)
610 }
611 pub fn version(&self) -> usize {
613 self.history.len() - 1
614 }
615 pub fn has_history(&self) -> bool {
617 self.history.len() > 1
618 }
619}
620#[allow(dead_code)]
622pub struct TransformStat {
623 before: StatSummary,
624 after: StatSummary,
625}
626#[allow(dead_code)]
627impl TransformStat {
628 pub fn new() -> Self {
630 Self {
631 before: StatSummary::new(),
632 after: StatSummary::new(),
633 }
634 }
635 pub fn record_before(&mut self, v: f64) {
637 self.before.record(v);
638 }
639 pub fn record_after(&mut self, v: f64) {
641 self.after.record(v);
642 }
643 pub fn mean_ratio(&self) -> Option<f64> {
645 let b = self.before.mean()?;
646 let a = self.after.mean()?;
647 if b.abs() < f64::EPSILON {
648 return None;
649 }
650 Some(a / b)
651 }
652}
653#[derive(Debug, Default)]
655pub struct CongrLemmaCache {
656 entries: std::collections::HashMap<(Name, usize), CongruenceTheorem>,
657}
658impl CongrLemmaCache {
659 pub fn new() -> Self {
661 Self::default()
662 }
663 pub fn get(&self, name: &Name, num_args: usize) -> Option<&CongruenceTheorem> {
665 self.entries.get(&(name.clone(), num_args))
666 }
667 pub fn insert(&mut self, thm: CongruenceTheorem) {
669 let key = (thm.fn_name.clone(), thm.num_args);
670 self.entries.insert(key, thm);
671 }
672 pub fn get_or_compute(&mut self, name: Name, num_args: usize) -> &CongruenceTheorem {
674 let key = (name.clone(), num_args);
675 self.entries
676 .entry(key)
677 .or_insert_with(|| mk_congr_theorem(name, num_args))
678 }
679 pub fn len(&self) -> usize {
681 self.entries.len()
682 }
683 pub fn clear(&mut self) {
685 self.entries.clear();
686 }
687 pub fn is_empty(&self) -> bool {
689 self.entries.is_empty()
690 }
691}
692#[allow(dead_code)]
694pub struct StatSummary {
695 count: u64,
696 sum: f64,
697 min: f64,
698 max: f64,
699}
700#[allow(dead_code)]
701impl StatSummary {
702 pub fn new() -> Self {
704 Self {
705 count: 0,
706 sum: 0.0,
707 min: f64::INFINITY,
708 max: f64::NEG_INFINITY,
709 }
710 }
711 pub fn record(&mut self, val: f64) {
713 self.count += 1;
714 self.sum += val;
715 if val < self.min {
716 self.min = val;
717 }
718 if val > self.max {
719 self.max = val;
720 }
721 }
722 pub fn mean(&self) -> Option<f64> {
724 if self.count == 0 {
725 None
726 } else {
727 Some(self.sum / self.count as f64)
728 }
729 }
730 pub fn min(&self) -> Option<f64> {
732 if self.count == 0 {
733 None
734 } else {
735 Some(self.min)
736 }
737 }
738 pub fn max(&self) -> Option<f64> {
740 if self.count == 0 {
741 None
742 } else {
743 Some(self.max)
744 }
745 }
746 pub fn count(&self) -> u64 {
748 self.count
749 }
750}
751#[allow(dead_code)]
753pub struct Stopwatch {
754 start: std::time::Instant,
755 splits: Vec<f64>,
756}
757#[allow(dead_code)]
758impl Stopwatch {
759 pub fn start() -> Self {
761 Self {
762 start: std::time::Instant::now(),
763 splits: Vec::new(),
764 }
765 }
766 pub fn split(&mut self) {
768 self.splits.push(self.elapsed_ms());
769 }
770 pub fn elapsed_ms(&self) -> f64 {
772 self.start.elapsed().as_secs_f64() * 1000.0
773 }
774 pub fn splits(&self) -> &[f64] {
776 &self.splits
777 }
778 pub fn num_splits(&self) -> usize {
780 self.splits.len()
781 }
782}
783#[allow(dead_code)]
785pub enum Either2<A, B> {
786 First(A),
788 Second(B),
790}
791#[allow(dead_code)]
792impl<A, B> Either2<A, B> {
793 pub fn is_first(&self) -> bool {
795 matches!(self, Either2::First(_))
796 }
797 pub fn is_second(&self) -> bool {
799 matches!(self, Either2::Second(_))
800 }
801 pub fn first(self) -> Option<A> {
803 match self {
804 Either2::First(a) => Some(a),
805 _ => None,
806 }
807 }
808 pub fn second(self) -> Option<B> {
810 match self {
811 Either2::Second(b) => Some(b),
812 _ => None,
813 }
814 }
815 pub fn map_first<C, F: FnOnce(A) -> C>(self, f: F) -> Either2<C, B> {
817 match self {
818 Either2::First(a) => Either2::First(f(a)),
819 Either2::Second(b) => Either2::Second(b),
820 }
821 }
822}
823#[allow(dead_code)]
825pub struct WriteOnce<T> {
826 value: std::cell::Cell<Option<T>>,
827}
828#[allow(dead_code)]
829impl<T: Copy> WriteOnce<T> {
830 pub fn new() -> Self {
832 Self {
833 value: std::cell::Cell::new(None),
834 }
835 }
836 pub fn write(&self, val: T) -> bool {
838 if self.value.get().is_some() {
839 return false;
840 }
841 self.value.set(Some(val));
842 true
843 }
844 pub fn read(&self) -> Option<T> {
846 self.value.get()
847 }
848 pub fn is_written(&self) -> bool {
850 self.value.get().is_some()
851 }
852}
853#[allow(dead_code)]
855#[allow(missing_docs)]
856pub enum DecisionNode {
857 Leaf(String),
859 Branch {
861 key: String,
862 val: String,
863 yes_branch: Box<DecisionNode>,
864 no_branch: Box<DecisionNode>,
865 },
866}
867#[allow(dead_code)]
868impl DecisionNode {
869 pub fn evaluate(&self, ctx: &std::collections::HashMap<String, String>) -> &str {
871 match self {
872 DecisionNode::Leaf(action) => action.as_str(),
873 DecisionNode::Branch {
874 key,
875 val,
876 yes_branch,
877 no_branch,
878 } => {
879 let actual = ctx.get(key).map(|s| s.as_str()).unwrap_or("");
880 if actual == val.as_str() {
881 yes_branch.evaluate(ctx)
882 } else {
883 no_branch.evaluate(ctx)
884 }
885 }
886 }
887 }
888 pub fn depth(&self) -> usize {
890 match self {
891 DecisionNode::Leaf(_) => 0,
892 DecisionNode::Branch {
893 yes_branch,
894 no_branch,
895 ..
896 } => 1 + yes_branch.depth().max(no_branch.depth()),
897 }
898 }
899}
900#[allow(dead_code)]
902pub struct TransitiveClosure {
903 adj: Vec<Vec<usize>>,
904 n: usize,
905}
906#[allow(dead_code)]
907impl TransitiveClosure {
908 pub fn new(n: usize) -> Self {
910 Self {
911 adj: vec![Vec::new(); n],
912 n,
913 }
914 }
915 pub fn add_edge(&mut self, from: usize, to: usize) {
917 if from < self.n {
918 self.adj[from].push(to);
919 }
920 }
921 pub fn reachable_from(&self, start: usize) -> Vec<usize> {
923 let mut visited = vec![false; self.n];
924 let mut queue = std::collections::VecDeque::new();
925 queue.push_back(start);
926 while let Some(node) = queue.pop_front() {
927 if node >= self.n || visited[node] {
928 continue;
929 }
930 visited[node] = true;
931 for &next in &self.adj[node] {
932 queue.push_back(next);
933 }
934 }
935 (0..self.n).filter(|&i| visited[i]).collect()
936 }
937 pub fn can_reach(&self, from: usize, to: usize) -> bool {
939 self.reachable_from(from).contains(&to)
940 }
941}
942#[allow(dead_code)]
944pub struct SimpleDag {
945 edges: Vec<Vec<usize>>,
947}
948#[allow(dead_code)]
949impl SimpleDag {
950 pub fn new(n: usize) -> Self {
952 Self {
953 edges: vec![Vec::new(); n],
954 }
955 }
956 pub fn add_edge(&mut self, from: usize, to: usize) {
958 if from < self.edges.len() {
959 self.edges[from].push(to);
960 }
961 }
962 pub fn successors(&self, node: usize) -> &[usize] {
964 self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
965 }
966 pub fn can_reach(&self, from: usize, to: usize) -> bool {
968 let mut visited = vec![false; self.edges.len()];
969 self.dfs(from, to, &mut visited)
970 }
971 fn dfs(&self, cur: usize, target: usize, visited: &mut Vec<bool>) -> bool {
972 if cur == target {
973 return true;
974 }
975 if cur >= visited.len() || visited[cur] {
976 return false;
977 }
978 visited[cur] = true;
979 for &next in self.successors(cur) {
980 if self.dfs(next, target, visited) {
981 return true;
982 }
983 }
984 false
985 }
986 pub fn topological_sort(&self) -> Option<Vec<usize>> {
988 let n = self.edges.len();
989 let mut in_degree = vec![0usize; n];
990 for succs in &self.edges {
991 for &s in succs {
992 if s < n {
993 in_degree[s] += 1;
994 }
995 }
996 }
997 let mut queue: std::collections::VecDeque<usize> =
998 (0..n).filter(|&i| in_degree[i] == 0).collect();
999 let mut order = Vec::new();
1000 while let Some(node) = queue.pop_front() {
1001 order.push(node);
1002 for &s in self.successors(node) {
1003 if s < n {
1004 in_degree[s] -= 1;
1005 if in_degree[s] == 0 {
1006 queue.push_back(s);
1007 }
1008 }
1009 }
1010 }
1011 if order.len() == n {
1012 Some(order)
1013 } else {
1014 None
1015 }
1016 }
1017 pub fn num_nodes(&self) -> usize {
1019 self.edges.len()
1020 }
1021}
1022#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1027pub enum CongrArgKind {
1028 Fixed,
1030 Eq,
1032 HEq,
1034 Cast,
1036 Subsingle,
1039}
1040pub struct CongruenceClosure {
1046 parent: HashMap<Expr, Expr>,
1048 rank: HashMap<Expr, u32>,
1050 pending: Vec<(Expr, Expr)>,
1052 apps: HashSet<(Expr, Expr)>,
1054 proofs: HashMap<(Expr, Expr), Expr>,
1056}
1057impl CongruenceClosure {
1058 pub fn new() -> Self {
1060 Self {
1061 parent: HashMap::new(),
1062 rank: HashMap::new(),
1063 pending: Vec::new(),
1064 apps: HashSet::new(),
1065 proofs: HashMap::new(),
1066 }
1067 }
1068 pub fn find(&mut self, expr: &Expr) -> Expr {
1070 if !self.parent.contains_key(expr) {
1071 self.parent.insert(expr.clone(), expr.clone());
1072 self.rank.insert(expr.clone(), 0);
1073 return expr.clone();
1074 }
1075 let parent = self
1076 .parent
1077 .get(expr)
1078 .cloned()
1079 .expect("expr must have a parent in the union-find structure");
1080 if &parent == expr {
1081 return expr.clone();
1082 }
1083 let root = self.find(&parent);
1084 self.parent.insert(expr.clone(), root.clone());
1085 root
1086 }
1087 fn union(&mut self, e1: &Expr, e2: &Expr) {
1089 let r1 = self.find(e1);
1090 let r2 = self.find(e2);
1091 if r1 == r2 {
1092 return;
1093 }
1094 let rank1 = *self.rank.get(&r1).unwrap_or(&0);
1095 let rank2 = *self.rank.get(&r2).unwrap_or(&0);
1096 if rank1 < rank2 {
1097 self.parent.insert(r1, r2);
1098 } else if rank1 > rank2 {
1099 self.parent.insert(r2, r1);
1100 } else {
1101 self.parent.insert(r2, r1.clone());
1102 self.rank.insert(r1, rank1 + 1);
1103 }
1104 }
1105 fn register(&mut self, expr: &Expr) {
1107 if !self.parent.contains_key(expr) {
1108 self.parent.insert(expr.clone(), expr.clone());
1109 self.rank.insert(expr.clone(), 0);
1110 }
1111 if let Expr::App(f, a) = expr {
1112 self.apps.insert(((**f).clone(), (**a).clone()));
1113 self.register(f);
1114 self.register(a);
1115 }
1116 }
1117 pub fn add_equality(&mut self, e1: Expr, e2: Expr) {
1119 self.register(&e1);
1120 self.register(&e2);
1121 self.pending.push((e1, e2));
1122 self.process_pending();
1123 }
1124 pub fn add_equality_with_proof(&mut self, e1: Expr, e2: Expr, proof: Expr) {
1126 self.proofs.insert((e1.clone(), e2.clone()), proof);
1127 self.add_equality(e1, e2);
1128 }
1129 fn process_pending(&mut self) {
1131 while let Some((e1, e2)) = self.pending.pop() {
1132 let r1 = self.find(&e1);
1133 let r2 = self.find(&e2);
1134 if r1 == r2 {
1135 continue;
1136 }
1137 self.union(&e1, &e2);
1138 let apps_vec: Vec<_> = self.apps.iter().cloned().collect();
1139 for i in 0..apps_vec.len() {
1140 for j in (i + 1)..apps_vec.len() {
1141 let (f1, a1) = &apps_vec[i];
1142 let (f2, a2) = &apps_vec[j];
1143 let rf1 = self.find(f1);
1144 let rf2 = self.find(f2);
1145 let ra1 = self.find(a1);
1146 let ra2 = self.find(a2);
1147 if rf1 == rf2 && ra1 == ra2 {
1148 let app1 = Expr::App(Box::new(f1.clone()), Box::new(a1.clone()));
1149 let app2 = Expr::App(Box::new(f2.clone()), Box::new(a2.clone()));
1150 if self.find(&app1) != self.find(&app2) {
1151 self.pending.push((app1, app2));
1152 }
1153 }
1154 }
1155 }
1156 }
1157 }
1158 pub fn are_equal(&mut self, e1: &Expr, e2: &Expr) -> bool {
1160 if self.find(e1) == self.find(e2) {
1161 return true;
1162 }
1163 match (e1, e2) {
1164 (Expr::App(f1, a1), Expr::App(f2, a2)) => {
1165 self.are_equal(f1, f2) && self.are_equal(a1, a2)
1166 }
1167 _ => false,
1168 }
1169 }
1170 pub fn get_class(&mut self, expr: &Expr) -> Vec<Expr> {
1172 let root = self.find(expr);
1173 let keys: Vec<Expr> = self.parent.keys().cloned().collect();
1174 keys.into_iter().filter(|e| self.find(e) == root).collect()
1175 }
1176 pub fn num_classes(&mut self) -> usize {
1178 let keys: Vec<Expr> = self.parent.keys().cloned().collect();
1179 let mut roots = HashSet::new();
1180 for k in &keys {
1181 roots.insert(self.find(k));
1182 }
1183 roots.len()
1184 }
1185 pub fn get_proof(&self, e1: &Expr, e2: &Expr) -> Option<&Expr> {
1187 self.proofs
1188 .get(&(e1.clone(), e2.clone()))
1189 .or_else(|| self.proofs.get(&(e2.clone(), e1.clone())))
1190 }
1191 pub fn clear(&mut self) {
1193 self.parent.clear();
1194 self.rank.clear();
1195 self.pending.clear();
1196 self.apps.clear();
1197 self.proofs.clear();
1198 }
1199}
1200#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1202pub struct FlatApp {
1203 pub fn_idx: TermIdx,
1205 pub arg_idx: TermIdx,
1207 pub result_idx: Option<TermIdx>,
1210}
1211#[allow(dead_code)]
1213pub struct StringPool {
1214 free: Vec<String>,
1215}
1216#[allow(dead_code)]
1217impl StringPool {
1218 pub fn new() -> Self {
1220 Self { free: Vec::new() }
1221 }
1222 pub fn take(&mut self) -> String {
1224 self.free.pop().unwrap_or_default()
1225 }
1226 pub fn give(&mut self, mut s: String) {
1228 s.clear();
1229 self.free.push(s);
1230 }
1231 pub fn free_count(&self) -> usize {
1233 self.free.len()
1234 }
1235}
1236#[allow(dead_code)]
1238pub struct SparseVec<T: Default + Clone + PartialEq> {
1239 entries: std::collections::HashMap<usize, T>,
1240 default_: T,
1241 logical_len: usize,
1242}
1243#[allow(dead_code)]
1244impl<T: Default + Clone + PartialEq> SparseVec<T> {
1245 pub fn new(len: usize) -> Self {
1247 Self {
1248 entries: std::collections::HashMap::new(),
1249 default_: T::default(),
1250 logical_len: len,
1251 }
1252 }
1253 pub fn set(&mut self, idx: usize, val: T) {
1255 if val == self.default_ {
1256 self.entries.remove(&idx);
1257 } else {
1258 self.entries.insert(idx, val);
1259 }
1260 }
1261 pub fn get(&self, idx: usize) -> &T {
1263 self.entries.get(&idx).unwrap_or(&self.default_)
1264 }
1265 pub fn len(&self) -> usize {
1267 self.logical_len
1268 }
1269 pub fn is_empty(&self) -> bool {
1271 self.len() == 0
1272 }
1273 pub fn nnz(&self) -> usize {
1275 self.entries.len()
1276 }
1277}
1278#[allow(dead_code)]
1280pub struct StackCalc {
1281 stack: Vec<i64>,
1282}
1283#[allow(dead_code)]
1284impl StackCalc {
1285 pub fn new() -> Self {
1287 Self { stack: Vec::new() }
1288 }
1289 pub fn push(&mut self, n: i64) {
1291 self.stack.push(n);
1292 }
1293 pub fn add(&mut self) {
1295 let b = self
1296 .stack
1297 .pop()
1298 .expect("stack must have at least two values for add");
1299 let a = self
1300 .stack
1301 .pop()
1302 .expect("stack must have at least two values for add");
1303 self.stack.push(a + b);
1304 }
1305 pub fn sub(&mut self) {
1307 let b = self
1308 .stack
1309 .pop()
1310 .expect("stack must have at least two values for sub");
1311 let a = self
1312 .stack
1313 .pop()
1314 .expect("stack must have at least two values for sub");
1315 self.stack.push(a - b);
1316 }
1317 pub fn mul(&mut self) {
1319 let b = self
1320 .stack
1321 .pop()
1322 .expect("stack must have at least two values for mul");
1323 let a = self
1324 .stack
1325 .pop()
1326 .expect("stack must have at least two values for mul");
1327 self.stack.push(a * b);
1328 }
1329 pub fn peek(&self) -> Option<i64> {
1331 self.stack.last().copied()
1332 }
1333 pub fn depth(&self) -> usize {
1335 self.stack.len()
1336 }
1337}
1338#[derive(Debug, Clone)]
1340pub struct CongruenceTheorem {
1341 pub fn_name: Name,
1343 pub num_args: usize,
1345 pub arg_kinds: Vec<CongrArgKind>,
1347 pub proof: Option<Expr>,
1349 pub ty: Option<Expr>,
1351}
1352impl CongruenceTheorem {
1353 pub fn new(fn_name: Name, arg_kinds: Vec<CongrArgKind>) -> Self {
1355 let num_args = arg_kinds.len();
1356 Self {
1357 fn_name,
1358 num_args,
1359 arg_kinds,
1360 proof: None,
1361 ty: None,
1362 }
1363 }
1364 pub fn has_eq_args(&self) -> bool {
1366 self.arg_kinds
1367 .iter()
1368 .any(|k| matches!(k, CongrArgKind::Eq | CongrArgKind::HEq))
1369 }
1370 pub fn num_eq_hypotheses(&self) -> usize {
1372 self.arg_kinds
1373 .iter()
1374 .filter(|k| matches!(k, CongrArgKind::Eq | CongrArgKind::HEq))
1375 .count()
1376 }
1377}
1378#[allow(dead_code)]
1380pub struct FocusStack<T> {
1381 items: Vec<T>,
1382}
1383#[allow(dead_code)]
1384impl<T> FocusStack<T> {
1385 pub fn new() -> Self {
1387 Self { items: Vec::new() }
1388 }
1389 pub fn focus(&mut self, item: T) {
1391 self.items.push(item);
1392 }
1393 pub fn blur(&mut self) -> Option<T> {
1395 self.items.pop()
1396 }
1397 pub fn current(&self) -> Option<&T> {
1399 self.items.last()
1400 }
1401 pub fn depth(&self) -> usize {
1403 self.items.len()
1404 }
1405 pub fn is_empty(&self) -> bool {
1407 self.items.is_empty()
1408 }
1409}
1410#[allow(dead_code)]
1412pub struct Fixture {
1413 data: std::collections::HashMap<String, String>,
1414}
1415#[allow(dead_code)]
1416impl Fixture {
1417 pub fn new() -> Self {
1419 Self {
1420 data: std::collections::HashMap::new(),
1421 }
1422 }
1423 pub fn set(&mut self, key: impl Into<String>, val: impl Into<String>) {
1425 self.data.insert(key.into(), val.into());
1426 }
1427 pub fn get(&self, key: &str) -> Option<&str> {
1429 self.data.get(key).map(|s| s.as_str())
1430 }
1431 pub fn len(&self) -> usize {
1433 self.data.len()
1434 }
1435 pub fn is_empty(&self) -> bool {
1437 self.len() == 0
1438 }
1439}
1440#[derive(Debug, Clone)]
1444pub struct CongrHypothesis {
1445 pub lhs: Expr,
1447 pub rhs: Expr,
1449 pub is_heq: bool,
1451}
1452impl CongrHypothesis {
1453 pub fn eq(lhs: Expr, rhs: Expr) -> Self {
1455 Self {
1456 lhs,
1457 rhs,
1458 is_heq: false,
1459 }
1460 }
1461 pub fn heq(lhs: Expr, rhs: Expr) -> Self {
1463 Self {
1464 lhs,
1465 rhs,
1466 is_heq: true,
1467 }
1468 }
1469 pub fn is_trivial(&self) -> bool {
1471 self.lhs == self.rhs
1472 }
1473}
1474pub struct FlatCC {
1479 parent: Vec<TermIdx>,
1481 rank: Vec<u32>,
1483 apps: Vec<FlatApp>,
1485}
1486impl FlatCC {
1487 pub fn new(n: usize) -> Self {
1489 Self {
1490 parent: (0..n).collect(),
1491 rank: vec![0; n],
1492 apps: Vec::new(),
1493 }
1494 }
1495 pub fn find(&mut self, i: TermIdx) -> TermIdx {
1497 if self.parent[i] != i {
1498 self.parent[i] = self.find(self.parent[i]);
1499 }
1500 self.parent[i]
1501 }
1502 pub fn union(&mut self, i: TermIdx, j: TermIdx) {
1504 let ri = self.find(i);
1505 let rj = self.find(j);
1506 if ri == rj {
1507 return;
1508 }
1509 if self.rank[ri] < self.rank[rj] {
1510 self.parent[ri] = rj;
1511 } else if self.rank[ri] > self.rank[rj] {
1512 self.parent[rj] = ri;
1513 } else {
1514 self.parent[rj] = ri;
1515 self.rank[ri] += 1;
1516 }
1517 }
1518 pub fn add_node(&mut self) -> TermIdx {
1520 let idx = self.parent.len();
1521 self.parent.push(idx);
1522 self.rank.push(0);
1523 idx
1524 }
1525 pub fn add_app(&mut self, app: FlatApp) {
1527 self.apps.push(app);
1528 }
1529 pub fn are_equal(&mut self, i: TermIdx, j: TermIdx) -> bool {
1531 self.find(i) == self.find(j)
1532 }
1533 pub fn num_nodes(&self) -> usize {
1535 self.parent.len()
1536 }
1537 pub fn num_apps(&self) -> usize {
1539 self.apps.len()
1540 }
1541 pub fn propagate_congruences(&mut self) {
1547 let len = self.apps.len();
1548 for i in 0..len {
1549 for j in (i + 1)..len {
1550 let a = self.apps[i];
1551 let b = self.apps[j];
1552 if self.are_equal(a.fn_idx, b.fn_idx) && self.are_equal(a.arg_idx, b.arg_idx) {
1553 if let (Some(ra), Some(rb)) = (a.result_idx, b.result_idx) {
1554 self.union(ra, rb);
1555 }
1556 }
1557 }
1558 }
1559 }
1560}
1561#[derive(Debug, Clone)]
1563pub struct ENode {
1564 pub repr: Expr,
1566 pub members: Vec<Expr>,
1568 pub proofs: Vec<Option<Expr>>,
1570}
1571impl ENode {
1572 pub fn singleton(expr: Expr) -> Self {
1574 Self {
1575 repr: expr.clone(),
1576 members: vec![expr],
1577 proofs: vec![None],
1578 }
1579 }
1580 pub fn add_member(&mut self, expr: Expr, proof: Option<Expr>) {
1582 if !self.members.contains(&expr) {
1583 self.members.push(expr);
1584 self.proofs.push(proof);
1585 }
1586 }
1587 pub fn contains(&self, expr: &Expr) -> bool {
1589 self.members.contains(expr)
1590 }
1591 pub fn size(&self) -> usize {
1593 self.members.len()
1594 }
1595}
1596#[allow(dead_code)]
1598pub struct RawFnPtr {
1599 ptr: usize,
1601 arity: usize,
1602 name: String,
1603}
1604#[allow(dead_code)]
1605impl RawFnPtr {
1606 pub fn new(ptr: usize, arity: usize, name: impl Into<String>) -> Self {
1608 Self {
1609 ptr,
1610 arity,
1611 name: name.into(),
1612 }
1613 }
1614 pub fn arity(&self) -> usize {
1616 self.arity
1617 }
1618 pub fn name(&self) -> &str {
1620 &self.name
1621 }
1622 pub fn raw(&self) -> usize {
1624 self.ptr
1625 }
1626}
1627#[allow(dead_code)]
1629pub struct LabelSet {
1630 labels: Vec<String>,
1631}
1632#[allow(dead_code)]
1633impl LabelSet {
1634 pub fn new() -> Self {
1636 Self { labels: Vec::new() }
1637 }
1638 pub fn add(&mut self, label: impl Into<String>) {
1640 let s = label.into();
1641 if !self.labels.contains(&s) {
1642 self.labels.push(s);
1643 }
1644 }
1645 pub fn has(&self, label: &str) -> bool {
1647 self.labels.iter().any(|l| l == label)
1648 }
1649 pub fn count(&self) -> usize {
1651 self.labels.len()
1652 }
1653 pub fn all(&self) -> &[String] {
1655 &self.labels
1656 }
1657}
1658#[allow(dead_code)]
1660pub struct MinHeap<T: Ord> {
1661 data: Vec<T>,
1662}
1663#[allow(dead_code)]
1664impl<T: Ord> MinHeap<T> {
1665 pub fn new() -> Self {
1667 Self { data: Vec::new() }
1668 }
1669 pub fn push(&mut self, val: T) {
1671 self.data.push(val);
1672 self.sift_up(self.data.len() - 1);
1673 }
1674 pub fn pop(&mut self) -> Option<T> {
1676 if self.data.is_empty() {
1677 return None;
1678 }
1679 let n = self.data.len();
1680 self.data.swap(0, n - 1);
1681 let min = self.data.pop();
1682 if !self.data.is_empty() {
1683 self.sift_down(0);
1684 }
1685 min
1686 }
1687 pub fn peek(&self) -> Option<&T> {
1689 self.data.first()
1690 }
1691 pub fn len(&self) -> usize {
1693 self.data.len()
1694 }
1695 pub fn is_empty(&self) -> bool {
1697 self.data.is_empty()
1698 }
1699 fn sift_up(&mut self, mut i: usize) {
1700 while i > 0 {
1701 let parent = (i - 1) / 2;
1702 if self.data[i] < self.data[parent] {
1703 self.data.swap(i, parent);
1704 i = parent;
1705 } else {
1706 break;
1707 }
1708 }
1709 }
1710 fn sift_down(&mut self, mut i: usize) {
1711 let n = self.data.len();
1712 loop {
1713 let left = 2 * i + 1;
1714 let right = 2 * i + 2;
1715 let mut smallest = i;
1716 if left < n && self.data[left] < self.data[smallest] {
1717 smallest = left;
1718 }
1719 if right < n && self.data[right] < self.data[smallest] {
1720 smallest = right;
1721 }
1722 if smallest == i {
1723 break;
1724 }
1725 self.data.swap(i, smallest);
1726 i = smallest;
1727 }
1728 }
1729}
1730#[derive(Debug, Clone, Default)]
1732pub struct CongrClosureStats {
1733 pub equalities_added: usize,
1735 pub congruences_propagated: usize,
1737 pub unions: usize,
1739 pub apps_tracked: usize,
1741}
1742impl CongrClosureStats {
1743 pub fn new() -> Self {
1745 Self::default()
1746 }
1747}
1748#[allow(dead_code)]
1750pub struct SmallMap<K: Ord + Clone, V: Clone> {
1751 entries: Vec<(K, V)>,
1752}
1753#[allow(dead_code)]
1754impl<K: Ord + Clone, V: Clone> SmallMap<K, V> {
1755 pub fn new() -> Self {
1757 Self {
1758 entries: Vec::new(),
1759 }
1760 }
1761 pub fn insert(&mut self, key: K, val: V) {
1763 match self.entries.binary_search_by_key(&&key, |(k, _)| k) {
1764 Ok(i) => self.entries[i].1 = val,
1765 Err(i) => self.entries.insert(i, (key, val)),
1766 }
1767 }
1768 pub fn get(&self, key: &K) -> Option<&V> {
1770 self.entries
1771 .binary_search_by_key(&key, |(k, _)| k)
1772 .ok()
1773 .map(|i| &self.entries[i].1)
1774 }
1775 pub fn len(&self) -> usize {
1777 self.entries.len()
1778 }
1779 pub fn is_empty(&self) -> bool {
1781 self.entries.is_empty()
1782 }
1783 pub fn keys(&self) -> Vec<&K> {
1785 self.entries.iter().map(|(k, _)| k).collect()
1786 }
1787 pub fn values(&self) -> Vec<&V> {
1789 self.entries.iter().map(|(_, v)| v).collect()
1790 }
1791}