1use crate::Node;
6use crate::{Expr, Name};
7use std::collections::{HashMap, HashSet};
8use std::rc::Rc;
9
10use super::functions::{mk_congr_theorem, TermIdx};
11
12#[allow(dead_code)]
14pub struct FlatSubstitution {
15 pairs: Vec<(String, String)>,
16}
17#[allow(dead_code)]
18impl FlatSubstitution {
19 pub fn new() -> Self {
21 Self { pairs: Vec::new() }
22 }
23 pub fn add(&mut self, from: impl Into<String>, to: impl Into<String>) {
25 self.pairs.push((from.into(), to.into()));
26 }
27 pub fn apply(&self, s: &str) -> String {
29 let mut result = s.to_string();
30 for (from, to) in &self.pairs {
31 result = result.replace(from.as_str(), to.as_str());
32 }
33 result
34 }
35 pub fn len(&self) -> usize {
37 self.pairs.len()
38 }
39 pub fn is_empty(&self) -> bool {
41 self.pairs.is_empty()
42 }
43}
44pub struct InstrumentedCC {
46 pub cc: CongruenceClosure,
48 pub stats: CongrClosureStats,
50}
51impl InstrumentedCC {
52 pub fn new() -> Self {
54 Self {
55 cc: CongruenceClosure::new(),
56 stats: CongrClosureStats::new(),
57 }
58 }
59 pub fn add_equality(&mut self, e1: Expr, e2: Expr) {
61 let before = self.cc.num_classes();
62 self.cc.add_equality(e1, e2);
63 let after = self.cc.num_classes();
64 if after < before {
65 self.stats.unions += 1;
66 }
67 self.stats.equalities_added += 1;
68 self.stats.apps_tracked = self.cc.apps.len();
69 }
70 pub fn are_equal(&mut self, e1: &Expr, e2: &Expr) -> bool {
72 self.cc.are_equal(e1, e2)
73 }
74 pub fn reset(&mut self) {
76 self.cc.clear();
77 self.stats = CongrClosureStats::new();
78 }
79 pub fn num_classes(&mut self) -> usize {
81 self.cc.num_classes()
82 }
83}
84pub struct EGraph {
88 nodes: Vec<ENode>,
90}
91impl EGraph {
92 pub fn new() -> Self {
94 Self { nodes: Vec::new() }
95 }
96 pub fn add_expr(&mut self, expr: Expr) -> usize {
98 for (i, node) in self.nodes.iter().enumerate() {
99 if node.contains(&expr) {
100 return i;
101 }
102 }
103 self.nodes.push(ENode::singleton(expr));
104 self.nodes.len() - 1
105 }
106 pub fn find_class(&self, expr: &Expr) -> Option<usize> {
108 self.nodes.iter().position(|n| n.contains(expr))
109 }
110 pub fn merge_classes(&mut self, id1: usize, id2: usize, proof: Option<Expr>) {
112 if id1 == id2 {
113 return;
114 }
115 let (small_id, large_id) = if id1 < id2 { (id2, id1) } else { (id1, id2) };
116 let small = self.nodes.remove(small_id);
117 for (m, p) in small.members.into_iter().zip(small.proofs) {
118 let proof_for = proof.clone().or(p);
119 self.nodes[large_id].add_member(m, proof_for);
120 }
121 }
122 pub fn are_equal(&self, e1: &Expr, e2: &Expr) -> bool {
124 match (self.find_class(e1), self.find_class(e2)) {
125 (Some(c1), Some(c2)) => c1 == c2,
126 _ => false,
127 }
128 }
129 pub fn add_equality(&mut self, e1: Expr, e2: Expr, proof: Option<Expr>) {
131 let c1 = self.add_expr(e1);
132 let c2 = self.add_expr(e2);
133 if c1 != c2 {
134 self.merge_classes(c1, c2, proof);
135 }
136 }
137 pub fn num_classes(&self) -> usize {
139 self.nodes.len()
140 }
141 pub fn get_class(&self, id: usize) -> Option<&ENode> {
143 self.nodes.get(id)
144 }
145 pub fn representative(&self, expr: &Expr) -> Option<&Expr> {
147 self.find_class(expr)
148 .and_then(|id| self.nodes.get(id))
149 .map(|n| &n.repr)
150 }
151 pub fn clear(&mut self) {
153 self.nodes.clear();
154 }
155}
156#[derive(Debug, Clone)]
158pub enum CongrProof {
159 Refl(Expr),
161 Symm(Box<CongrProof>),
163 Trans(Box<CongrProof>, Box<CongrProof>),
165 Congr(Box<CongrProof>, Box<CongrProof>),
167 Hyp(Name),
169}
170impl CongrProof {
171 pub fn depth(&self) -> usize {
173 match self {
174 CongrProof::Refl(_) | CongrProof::Hyp(_) => 0,
175 CongrProof::Symm(p) => 1 + p.depth(),
176 CongrProof::Trans(p, q) | CongrProof::Congr(p, q) => 1 + p.depth().max(q.depth()),
177 }
178 }
179 pub fn is_refl(&self) -> bool {
181 matches!(self, CongrProof::Refl(_))
182 }
183 pub fn hypothesis_count(&self) -> usize {
185 match self {
186 CongrProof::Hyp(_) => 1,
187 CongrProof::Refl(_) => 0,
188 CongrProof::Symm(p) => p.hypothesis_count(),
189 CongrProof::Trans(p, q) | CongrProof::Congr(p, q) => {
190 p.hypothesis_count() + q.hypothesis_count()
191 }
192 }
193 }
194 pub fn simplify(self) -> Self {
196 match self {
197 CongrProof::Symm(inner) => match *inner {
198 CongrProof::Symm(p) => p.simplify(),
199 other => CongrProof::Symm(Box::new(other.simplify())),
200 },
201 CongrProof::Trans(p, q) => {
202 CongrProof::Trans(Box::new(p.simplify()), Box::new(q.simplify()))
203 }
204 CongrProof::Congr(p, q) => {
205 CongrProof::Congr(Box::new(p.simplify()), Box::new(q.simplify()))
206 }
207 other => other,
208 }
209 }
210}
211#[allow(dead_code)]
213pub struct WindowIterator<'a, T> {
214 pub(super) data: &'a [T],
215 pub(super) pos: usize,
216 pub(super) window: usize,
217}
218#[allow(dead_code)]
219impl<'a, T> WindowIterator<'a, T> {
220 pub fn new(data: &'a [T], window: usize) -> Self {
222 Self {
223 data,
224 pos: 0,
225 window,
226 }
227 }
228}
229#[allow(dead_code)]
231#[allow(missing_docs)]
232pub struct RewriteRule {
233 pub name: String,
235 pub lhs: String,
237 pub rhs: String,
239 pub conditional: bool,
241}
242#[allow(dead_code)]
243impl RewriteRule {
244 pub fn unconditional(
246 name: impl Into<String>,
247 lhs: impl Into<String>,
248 rhs: impl Into<String>,
249 ) -> Self {
250 Self {
251 name: name.into(),
252 lhs: lhs.into(),
253 rhs: rhs.into(),
254 conditional: false,
255 }
256 }
257 pub fn conditional(
259 name: impl Into<String>,
260 lhs: impl Into<String>,
261 rhs: impl Into<String>,
262 ) -> Self {
263 Self {
264 name: name.into(),
265 lhs: lhs.into(),
266 rhs: rhs.into(),
267 conditional: true,
268 }
269 }
270 pub fn display(&self) -> String {
272 format!("{}: {} → {}", self.name, self.lhs, self.rhs)
273 }
274}
275#[allow(dead_code)]
277pub struct PrefixCounter {
278 children: std::collections::HashMap<char, PrefixCounter>,
279 count: usize,
280}
281#[allow(dead_code)]
282impl PrefixCounter {
283 pub fn new() -> Self {
285 Self {
286 children: std::collections::HashMap::new(),
287 count: 0,
288 }
289 }
290 pub fn record(&mut self, s: &str) {
292 self.count += 1;
293 let mut node = self;
294 for c in s.chars() {
295 node = node.children.entry(c).or_default();
296 node.count += 1;
297 }
298 }
299 pub fn count_with_prefix(&self, prefix: &str) -> usize {
301 let mut node = self;
302 for c in prefix.chars() {
303 match node.children.get(&c) {
304 Some(n) => node = n,
305 None => return 0,
306 }
307 }
308 node.count
309 }
310}
311#[allow(dead_code)]
313pub struct NonEmptyVec<T> {
314 head: T,
315 tail: Vec<T>,
316}
317#[allow(dead_code)]
318impl<T> NonEmptyVec<T> {
319 pub fn singleton(val: T) -> Self {
321 Self {
322 head: val,
323 tail: Vec::new(),
324 }
325 }
326 pub fn push(&mut self, val: T) {
328 self.tail.push(val);
329 }
330 pub fn first(&self) -> &T {
332 &self.head
333 }
334 pub fn last(&self) -> &T {
336 self.tail.last().unwrap_or(&self.head)
337 }
338 pub fn len(&self) -> usize {
340 1 + self.tail.len()
341 }
342 pub fn is_empty(&self) -> bool {
344 self.len() == 0
345 }
346 pub fn to_vec(&self) -> Vec<&T> {
348 let mut v = vec![&self.head];
349 v.extend(self.tail.iter());
350 v
351 }
352}
353#[allow(dead_code)]
355pub struct SlidingSum {
356 window: Vec<f64>,
357 capacity: usize,
358 pos: usize,
359 sum: f64,
360 count: usize,
361}
362#[allow(dead_code)]
363impl SlidingSum {
364 pub fn new(capacity: usize) -> Self {
366 Self {
367 window: vec![0.0; capacity],
368 capacity,
369 pos: 0,
370 sum: 0.0,
371 count: 0,
372 }
373 }
374 pub fn push(&mut self, val: f64) {
376 let oldest = self.window[self.pos];
377 self.sum -= oldest;
378 self.sum += val;
379 self.window[self.pos] = val;
380 self.pos = (self.pos + 1) % self.capacity;
381 if self.count < self.capacity {
382 self.count += 1;
383 }
384 }
385 pub fn sum(&self) -> f64 {
387 self.sum
388 }
389 pub fn mean(&self) -> Option<f64> {
391 if self.count == 0 {
392 None
393 } else {
394 Some(self.sum / self.count as f64)
395 }
396 }
397 pub fn count(&self) -> usize {
399 self.count
400 }
401}
402#[allow(dead_code)]
404pub struct RewriteRuleSet {
405 rules: Vec<RewriteRule>,
406}
407#[allow(dead_code)]
408impl RewriteRuleSet {
409 pub fn new() -> Self {
411 Self { rules: Vec::new() }
412 }
413 pub fn add(&mut self, rule: RewriteRule) {
415 self.rules.push(rule);
416 }
417 pub fn len(&self) -> usize {
419 self.rules.len()
420 }
421 pub fn is_empty(&self) -> bool {
423 self.rules.is_empty()
424 }
425 pub fn conditional_rules(&self) -> Vec<&RewriteRule> {
427 self.rules.iter().filter(|r| r.conditional).collect()
428 }
429 pub fn unconditional_rules(&self) -> Vec<&RewriteRule> {
431 self.rules.iter().filter(|r| !r.conditional).collect()
432 }
433 pub fn get(&self, name: &str) -> Option<&RewriteRule> {
435 self.rules.iter().find(|r| r.name == name)
436 }
437}
438#[allow(dead_code)]
440pub struct PathBuf {
441 components: Vec<String>,
442}
443#[allow(dead_code)]
444impl PathBuf {
445 pub fn new() -> Self {
447 Self {
448 components: Vec::new(),
449 }
450 }
451 pub fn push(&mut self, comp: impl Into<String>) {
453 self.components.push(comp.into());
454 }
455 pub fn pop(&mut self) {
457 self.components.pop();
458 }
459 pub fn as_str(&self) -> String {
461 self.components.join("/")
462 }
463 pub fn depth(&self) -> usize {
465 self.components.len()
466 }
467 pub fn clear(&mut self) {
469 self.components.clear();
470 }
471}
472#[allow(dead_code)]
474pub struct ConfigNode {
475 key: String,
476 value: Option<String>,
477 children: Vec<ConfigNode>,
478}
479#[allow(dead_code)]
480impl ConfigNode {
481 pub fn leaf(key: impl Into<String>, value: impl Into<String>) -> Self {
483 Self {
484 key: key.into(),
485 value: Some(value.into()),
486 children: Vec::new(),
487 }
488 }
489 pub fn section(key: impl Into<String>) -> Self {
491 Self {
492 key: key.into(),
493 value: None,
494 children: Vec::new(),
495 }
496 }
497 pub fn add_child(&mut self, child: ConfigNode) {
499 self.children.push(child);
500 }
501 pub fn key(&self) -> &str {
503 &self.key
504 }
505 pub fn value(&self) -> Option<&str> {
507 self.value.as_deref()
508 }
509 pub fn num_children(&self) -> usize {
511 self.children.len()
512 }
513 pub fn lookup(&self, path: &str) -> Option<&str> {
515 let mut parts = path.splitn(2, '.');
516 let head = parts.next()?;
517 let tail = parts.next();
518 if head != self.key {
519 return None;
520 }
521 match tail {
522 None => self.value.as_deref(),
523 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
524 }
525 }
526 fn lookup_relative(&self, path: &str) -> Option<&str> {
527 let mut parts = path.splitn(2, '.');
528 let head = parts.next()?;
529 let tail = parts.next();
530 if head != self.key {
531 return None;
532 }
533 match tail {
534 None => self.value.as_deref(),
535 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
536 }
537 }
538}
539#[allow(dead_code)]
541pub struct TokenBucket {
542 capacity: u64,
543 tokens: u64,
544 refill_per_ms: u64,
545 last_refill: crate::wall_clock::Instant,
546}
547#[allow(dead_code)]
548impl TokenBucket {
549 pub fn new(capacity: u64, refill_per_ms: u64) -> Self {
551 Self {
552 capacity,
553 tokens: capacity,
554 refill_per_ms,
555 last_refill: crate::wall_clock::Instant::now(),
556 }
557 }
558 pub fn try_consume(&mut self, n: u64) -> bool {
560 self.refill();
561 if self.tokens >= n {
562 self.tokens -= n;
563 true
564 } else {
565 false
566 }
567 }
568 fn refill(&mut self) {
569 let now = crate::wall_clock::Instant::now();
570 let elapsed_ms = now.duration_since(self.last_refill).as_millis() as u64;
571 if elapsed_ms > 0 {
572 let new_tokens = elapsed_ms * self.refill_per_ms;
573 self.tokens = (self.tokens + new_tokens).min(self.capacity);
574 self.last_refill = now;
575 }
576 }
577 pub fn available(&self) -> u64 {
579 self.tokens
580 }
581 pub fn capacity(&self) -> u64 {
583 self.capacity
584 }
585}
586#[allow(dead_code)]
588pub struct VersionedRecord<T: Clone> {
589 earlier: Vec<T>,
591 current: T,
593}
594#[allow(dead_code)]
595impl<T: Clone> VersionedRecord<T> {
596 pub fn new(initial: T) -> Self {
598 Self {
599 earlier: Vec::new(),
600 current: initial,
601 }
602 }
603 pub fn update(&mut self, val: T) {
605 let previous = std::mem::replace(&mut self.current, val);
606 self.earlier.push(previous);
607 }
608 pub fn current(&self) -> &T {
610 &self.current
611 }
612 pub fn at_version(&self, n: usize) -> Option<&T> {
614 match self.earlier.get(n) {
615 Some(value) => Some(value),
616 None if n == self.earlier.len() => Some(&self.current),
617 None => None,
618 }
619 }
620 pub fn version(&self) -> usize {
622 self.earlier.len()
623 }
624 pub fn has_history(&self) -> bool {
626 !self.earlier.is_empty()
627 }
628}
629#[allow(dead_code)]
631pub struct TransformStat {
632 before: StatSummary,
633 after: StatSummary,
634}
635#[allow(dead_code)]
636impl TransformStat {
637 pub fn new() -> Self {
639 Self {
640 before: StatSummary::new(),
641 after: StatSummary::new(),
642 }
643 }
644 pub fn record_before(&mut self, v: f64) {
646 self.before.record(v);
647 }
648 pub fn record_after(&mut self, v: f64) {
650 self.after.record(v);
651 }
652 pub fn mean_ratio(&self) -> Option<f64> {
654 let b = self.before.mean()?;
655 let a = self.after.mean()?;
656 if b.abs() < f64::EPSILON {
657 return None;
658 }
659 Some(a / b)
660 }
661}
662#[derive(Debug, Default)]
664pub struct CongrLemmaCache {
665 entries: std::collections::HashMap<(Name, usize), CongruenceTheorem>,
666}
667impl CongrLemmaCache {
668 pub fn new() -> Self {
670 Self::default()
671 }
672 pub fn get(&self, name: &Name, num_args: usize) -> Option<&CongruenceTheorem> {
674 self.entries.get(&(name.clone(), num_args))
675 }
676 pub fn insert(&mut self, thm: CongruenceTheorem) {
678 let key = (thm.fn_name.clone(), thm.num_args);
679 self.entries.insert(key, thm);
680 }
681 pub fn get_or_compute(&mut self, name: Name, num_args: usize) -> &CongruenceTheorem {
683 let key = (name.clone(), num_args);
684 self.entries
685 .entry(key)
686 .or_insert_with(|| mk_congr_theorem(name, num_args))
687 }
688 pub fn len(&self) -> usize {
690 self.entries.len()
691 }
692 pub fn clear(&mut self) {
694 self.entries.clear();
695 }
696 pub fn is_empty(&self) -> bool {
698 self.entries.is_empty()
699 }
700}
701#[allow(dead_code)]
703pub struct StatSummary {
704 count: u64,
705 sum: f64,
706 min: f64,
707 max: f64,
708}
709#[allow(dead_code)]
710impl StatSummary {
711 pub fn new() -> Self {
713 Self {
714 count: 0,
715 sum: 0.0,
716 min: f64::INFINITY,
717 max: f64::NEG_INFINITY,
718 }
719 }
720 pub fn record(&mut self, val: f64) {
722 self.count += 1;
723 self.sum += val;
724 if val < self.min {
725 self.min = val;
726 }
727 if val > self.max {
728 self.max = val;
729 }
730 }
731 pub fn mean(&self) -> Option<f64> {
733 if self.count == 0 {
734 None
735 } else {
736 Some(self.sum / self.count as f64)
737 }
738 }
739 pub fn min(&self) -> Option<f64> {
741 if self.count == 0 {
742 None
743 } else {
744 Some(self.min)
745 }
746 }
747 pub fn max(&self) -> Option<f64> {
749 if self.count == 0 {
750 None
751 } else {
752 Some(self.max)
753 }
754 }
755 pub fn count(&self) -> u64 {
757 self.count
758 }
759}
760#[allow(dead_code)]
762pub struct Stopwatch {
763 start: crate::wall_clock::Instant,
764 splits: Vec<f64>,
765}
766#[allow(dead_code)]
767impl Stopwatch {
768 pub fn start() -> Self {
770 Self {
771 start: crate::wall_clock::Instant::now(),
772 splits: Vec::new(),
773 }
774 }
775 pub fn split(&mut self) {
777 self.splits.push(self.elapsed_ms());
778 }
779 pub fn elapsed_ms(&self) -> f64 {
781 self.start.elapsed().as_secs_f64() * 1000.0
782 }
783 pub fn splits(&self) -> &[f64] {
785 &self.splits
786 }
787 pub fn num_splits(&self) -> usize {
789 self.splits.len()
790 }
791}
792#[allow(dead_code)]
794pub enum Either2<A, B> {
795 First(A),
797 Second(B),
799}
800#[allow(dead_code)]
801impl<A, B> Either2<A, B> {
802 pub fn is_first(&self) -> bool {
804 matches!(self, Either2::First(_))
805 }
806 pub fn is_second(&self) -> bool {
808 matches!(self, Either2::Second(_))
809 }
810 pub fn first(self) -> Option<A> {
812 match self {
813 Either2::First(a) => Some(a),
814 _ => None,
815 }
816 }
817 pub fn second(self) -> Option<B> {
819 match self {
820 Either2::Second(b) => Some(b),
821 _ => None,
822 }
823 }
824 pub fn map_first<C, F: FnOnce(A) -> C>(self, f: F) -> Either2<C, B> {
826 match self {
827 Either2::First(a) => Either2::First(f(a)),
828 Either2::Second(b) => Either2::Second(b),
829 }
830 }
831}
832#[allow(dead_code)]
834pub struct WriteOnce<T> {
835 value: std::cell::Cell<Option<T>>,
836}
837#[allow(dead_code)]
838impl<T: Copy> WriteOnce<T> {
839 pub fn new() -> Self {
841 Self {
842 value: std::cell::Cell::new(None),
843 }
844 }
845 pub fn write(&self, val: T) -> bool {
847 if self.value.get().is_some() {
848 return false;
849 }
850 self.value.set(Some(val));
851 true
852 }
853 pub fn read(&self) -> Option<T> {
855 self.value.get()
856 }
857 pub fn is_written(&self) -> bool {
859 self.value.get().is_some()
860 }
861}
862#[allow(dead_code)]
864#[allow(missing_docs)]
865pub enum DecisionNode {
866 Leaf(String),
868 Branch {
870 key: String,
871 val: String,
872 yes_branch: Box<DecisionNode>,
873 no_branch: Box<DecisionNode>,
874 },
875}
876#[allow(dead_code)]
877impl DecisionNode {
878 pub fn evaluate(&self, ctx: &std::collections::HashMap<String, String>) -> &str {
880 match self {
881 DecisionNode::Leaf(action) => action.as_str(),
882 DecisionNode::Branch {
883 key,
884 val,
885 yes_branch,
886 no_branch,
887 } => {
888 let actual = ctx.get(key).map(|s| s.as_str()).unwrap_or("");
889 if actual == val.as_str() {
890 yes_branch.evaluate(ctx)
891 } else {
892 no_branch.evaluate(ctx)
893 }
894 }
895 }
896 }
897 pub fn depth(&self) -> usize {
899 match self {
900 DecisionNode::Leaf(_) => 0,
901 DecisionNode::Branch {
902 yes_branch,
903 no_branch,
904 ..
905 } => 1 + yes_branch.depth().max(no_branch.depth()),
906 }
907 }
908}
909#[allow(dead_code)]
911pub struct TransitiveClosure {
912 adj: Vec<Vec<usize>>,
913 n: usize,
914}
915#[allow(dead_code)]
916impl TransitiveClosure {
917 pub fn new(n: usize) -> Self {
919 Self {
920 adj: vec![Vec::new(); n],
921 n,
922 }
923 }
924 pub fn add_edge(&mut self, from: usize, to: usize) {
926 if from < self.n {
927 self.adj[from].push(to);
928 }
929 }
930 pub fn reachable_from(&self, start: usize) -> Vec<usize> {
932 let mut visited = vec![false; self.n];
933 let mut queue = std::collections::VecDeque::new();
934 queue.push_back(start);
935 while let Some(node) = queue.pop_front() {
936 if node >= self.n || visited[node] {
937 continue;
938 }
939 visited[node] = true;
940 for &next in &self.adj[node] {
941 queue.push_back(next);
942 }
943 }
944 (0..self.n).filter(|&i| visited[i]).collect()
945 }
946 pub fn can_reach(&self, from: usize, to: usize) -> bool {
948 self.reachable_from(from).contains(&to)
949 }
950}
951#[allow(dead_code)]
953pub struct SimpleDag {
954 edges: Vec<Vec<usize>>,
956}
957#[allow(dead_code)]
958impl SimpleDag {
959 pub fn new(n: usize) -> Self {
961 Self {
962 edges: vec![Vec::new(); n],
963 }
964 }
965 pub fn add_edge(&mut self, from: usize, to: usize) {
967 if from < self.edges.len() {
968 self.edges[from].push(to);
969 }
970 }
971 pub fn successors(&self, node: usize) -> &[usize] {
973 self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
974 }
975 pub fn can_reach(&self, from: usize, to: usize) -> bool {
977 let mut visited = vec![false; self.edges.len()];
978 self.dfs(from, to, &mut visited)
979 }
980 fn dfs(&self, cur: usize, target: usize, visited: &mut Vec<bool>) -> bool {
981 if cur == target {
982 return true;
983 }
984 if cur >= visited.len() || visited[cur] {
985 return false;
986 }
987 visited[cur] = true;
988 for &next in self.successors(cur) {
989 if self.dfs(next, target, visited) {
990 return true;
991 }
992 }
993 false
994 }
995 pub fn topological_sort(&self) -> Option<Vec<usize>> {
997 let n = self.edges.len();
998 let mut in_degree = vec![0usize; n];
999 for succs in &self.edges {
1000 for &s in succs {
1001 if s < n {
1002 in_degree[s] += 1;
1003 }
1004 }
1005 }
1006 let mut queue: std::collections::VecDeque<usize> =
1007 (0..n).filter(|&i| in_degree[i] == 0).collect();
1008 let mut order = Vec::new();
1009 while let Some(node) = queue.pop_front() {
1010 order.push(node);
1011 for &s in self.successors(node) {
1012 if s < n {
1013 in_degree[s] -= 1;
1014 if in_degree[s] == 0 {
1015 queue.push_back(s);
1016 }
1017 }
1018 }
1019 }
1020 if order.len() == n {
1021 Some(order)
1022 } else {
1023 None
1024 }
1025 }
1026 pub fn num_nodes(&self) -> usize {
1028 self.edges.len()
1029 }
1030}
1031#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1036pub enum CongrArgKind {
1037 Fixed,
1039 Eq,
1041 HEq,
1043 Cast,
1045 Subsingle,
1048}
1049pub struct CongruenceClosure {
1055 parent: HashMap<Expr, Expr>,
1057 rank: HashMap<Expr, u32>,
1059 pending: Vec<(Expr, Expr)>,
1061 apps: HashSet<(Expr, Expr)>,
1063 proofs: HashMap<(Expr, Expr), Expr>,
1065}
1066impl CongruenceClosure {
1067 pub fn new() -> Self {
1069 Self {
1070 parent: HashMap::new(),
1071 rank: HashMap::new(),
1072 pending: Vec::new(),
1073 apps: HashSet::new(),
1074 proofs: HashMap::new(),
1075 }
1076 }
1077 pub fn find(&mut self, expr: &Expr) -> Expr {
1079 let Some(parent) = self.parent.get(expr).cloned() else {
1080 self.parent.insert(expr.clone(), expr.clone());
1081 self.rank.insert(expr.clone(), 0);
1082 return expr.clone();
1083 };
1084 if &parent == expr {
1085 return expr.clone();
1086 }
1087 let root = self.find(&parent);
1088 self.parent.insert(expr.clone(), root.clone());
1089 root
1090 }
1091 fn union(&mut self, e1: &Expr, e2: &Expr) {
1093 let r1 = self.find(e1);
1094 let r2 = self.find(e2);
1095 if r1 == r2 {
1096 return;
1097 }
1098 let rank1 = *self.rank.get(&r1).unwrap_or(&0);
1099 let rank2 = *self.rank.get(&r2).unwrap_or(&0);
1100 if rank1 < rank2 {
1101 self.parent.insert(r1, r2);
1102 } else if rank1 > rank2 {
1103 self.parent.insert(r2, r1);
1104 } else {
1105 self.parent.insert(r2, r1.clone());
1106 self.rank.insert(r1, rank1 + 1);
1107 }
1108 }
1109 fn register(&mut self, expr: &Expr) {
1111 if !self.parent.contains_key(expr) {
1112 self.parent.insert(expr.clone(), expr.clone());
1113 self.rank.insert(expr.clone(), 0);
1114 }
1115 if let Expr::App(f, a) = expr {
1116 self.apps.insert(((**f).clone(), (**a).clone()));
1117 self.register(f);
1118 self.register(a);
1119 }
1120 }
1121 pub fn add_equality(&mut self, e1: Expr, e2: Expr) {
1123 self.register(&e1);
1124 self.register(&e2);
1125 self.pending.push((e1, e2));
1126 self.process_pending();
1127 }
1128 pub fn add_equality_with_proof(&mut self, e1: Expr, e2: Expr, proof: Expr) {
1130 self.proofs.insert((e1.clone(), e2.clone()), proof);
1131 self.add_equality(e1, e2);
1132 }
1133 fn process_pending(&mut self) {
1135 while let Some((e1, e2)) = self.pending.pop() {
1136 let r1 = self.find(&e1);
1137 let r2 = self.find(&e2);
1138 if r1 == r2 {
1139 continue;
1140 }
1141 self.union(&e1, &e2);
1142 let apps_vec: Vec<_> = self.apps.iter().cloned().collect();
1143 for i in 0..apps_vec.len() {
1144 for j in (i + 1)..apps_vec.len() {
1145 let (f1, a1) = &apps_vec[i];
1146 let (f2, a2) = &apps_vec[j];
1147 let rf1 = self.find(f1);
1148 let rf2 = self.find(f2);
1149 let ra1 = self.find(a1);
1150 let ra2 = self.find(a2);
1151 if rf1 == rf2 && ra1 == ra2 {
1152 let app1 = Expr::App(Node::new(f1.clone()), Node::new(a1.clone()));
1153 let app2 = Expr::App(Node::new(f2.clone()), Node::new(a2.clone()));
1154 if self.find(&app1) != self.find(&app2) {
1155 self.pending.push((app1, app2));
1156 }
1157 }
1158 }
1159 }
1160 }
1161 }
1162 pub fn are_equal(&mut self, e1: &Expr, e2: &Expr) -> bool {
1164 if self.find(e1) == self.find(e2) {
1165 return true;
1166 }
1167 match (e1, e2) {
1168 (Expr::App(f1, a1), Expr::App(f2, a2)) => {
1169 self.are_equal(f1, f2) && self.are_equal(a1, a2)
1170 }
1171 _ => false,
1172 }
1173 }
1174 pub fn get_class(&mut self, expr: &Expr) -> Vec<Expr> {
1176 let root = self.find(expr);
1177 let keys: Vec<Expr> = self.parent.keys().cloned().collect();
1178 keys.into_iter().filter(|e| self.find(e) == root).collect()
1179 }
1180 pub fn num_classes(&mut self) -> usize {
1182 let keys: Vec<Expr> = self.parent.keys().cloned().collect();
1183 let mut roots = HashSet::new();
1184 for k in &keys {
1185 roots.insert(self.find(k));
1186 }
1187 roots.len()
1188 }
1189 pub fn get_proof(&self, e1: &Expr, e2: &Expr) -> Option<&Expr> {
1191 self.proofs
1192 .get(&(e1.clone(), e2.clone()))
1193 .or_else(|| self.proofs.get(&(e2.clone(), e1.clone())))
1194 }
1195 pub fn clear(&mut self) {
1197 self.parent.clear();
1198 self.rank.clear();
1199 self.pending.clear();
1200 self.apps.clear();
1201 self.proofs.clear();
1202 }
1203}
1204#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1206pub struct FlatApp {
1207 pub fn_idx: TermIdx,
1209 pub arg_idx: TermIdx,
1211 pub result_idx: Option<TermIdx>,
1214}
1215#[allow(dead_code)]
1217pub struct StringPool {
1218 free: Vec<String>,
1219}
1220#[allow(dead_code)]
1221impl StringPool {
1222 pub fn new() -> Self {
1224 Self { free: Vec::new() }
1225 }
1226 pub fn take(&mut self) -> String {
1228 self.free.pop().unwrap_or_default()
1229 }
1230 pub fn give(&mut self, mut s: String) {
1232 s.clear();
1233 self.free.push(s);
1234 }
1235 pub fn free_count(&self) -> usize {
1237 self.free.len()
1238 }
1239}
1240#[allow(dead_code)]
1242pub struct SparseVec<T: Default + Clone + PartialEq> {
1243 entries: std::collections::HashMap<usize, T>,
1244 default_: T,
1245 logical_len: usize,
1246}
1247#[allow(dead_code)]
1248impl<T: Default + Clone + PartialEq> SparseVec<T> {
1249 pub fn new(len: usize) -> Self {
1251 Self {
1252 entries: std::collections::HashMap::new(),
1253 default_: T::default(),
1254 logical_len: len,
1255 }
1256 }
1257 pub fn set(&mut self, idx: usize, val: T) {
1259 if val == self.default_ {
1260 self.entries.remove(&idx);
1261 } else {
1262 self.entries.insert(idx, val);
1263 }
1264 }
1265 pub fn get(&self, idx: usize) -> &T {
1267 self.entries.get(&idx).unwrap_or(&self.default_)
1268 }
1269 pub fn len(&self) -> usize {
1271 self.logical_len
1272 }
1273 pub fn is_empty(&self) -> bool {
1275 self.len() == 0
1276 }
1277 pub fn nnz(&self) -> usize {
1279 self.entries.len()
1280 }
1281}
1282#[allow(dead_code)]
1284pub struct StackCalc {
1285 stack: Vec<i64>,
1286}
1287#[allow(dead_code)]
1288impl StackCalc {
1289 pub fn new() -> Self {
1291 Self { stack: Vec::new() }
1292 }
1293 pub fn push(&mut self, n: i64) {
1295 self.stack.push(n);
1296 }
1297 fn apply_binary(&mut self, op: impl FnOnce(i64, i64) -> i64) -> Option<i64> {
1301 let (rest_len, a, b) = match self.stack[..] {
1302 [ref rest @ .., a, b] => (rest.len(), a, b),
1303 _ => return None,
1304 };
1305 let value = op(a, b);
1306 self.stack.truncate(rest_len);
1307 self.stack.push(value);
1308 Some(value)
1309 }
1310 pub fn add(&mut self) -> Option<i64> {
1314 self.apply_binary(|a, b| a + b)
1315 }
1316 pub fn sub(&mut self) -> Option<i64> {
1320 self.apply_binary(|a, b| a - b)
1321 }
1322 pub fn mul(&mut self) -> Option<i64> {
1326 self.apply_binary(|a, b| a * b)
1327 }
1328 pub fn peek(&self) -> Option<i64> {
1330 self.stack.last().copied()
1331 }
1332 pub fn depth(&self) -> usize {
1334 self.stack.len()
1335 }
1336}
1337#[derive(Debug, Clone)]
1339pub struct CongruenceTheorem {
1340 pub fn_name: Name,
1342 pub num_args: usize,
1344 pub arg_kinds: Vec<CongrArgKind>,
1346 pub proof: Option<Expr>,
1348 pub ty: Option<Expr>,
1350}
1351impl CongruenceTheorem {
1352 pub fn new(fn_name: Name, arg_kinds: Vec<CongrArgKind>) -> Self {
1354 let num_args = arg_kinds.len();
1355 Self {
1356 fn_name,
1357 num_args,
1358 arg_kinds,
1359 proof: None,
1360 ty: None,
1361 }
1362 }
1363 pub fn has_eq_args(&self) -> bool {
1365 self.arg_kinds
1366 .iter()
1367 .any(|k| matches!(k, CongrArgKind::Eq | CongrArgKind::HEq))
1368 }
1369 pub fn num_eq_hypotheses(&self) -> usize {
1371 self.arg_kinds
1372 .iter()
1373 .filter(|k| matches!(k, CongrArgKind::Eq | CongrArgKind::HEq))
1374 .count()
1375 }
1376}
1377#[allow(dead_code)]
1379pub struct FocusStack<T> {
1380 items: Vec<T>,
1381}
1382#[allow(dead_code)]
1383impl<T> FocusStack<T> {
1384 pub fn new() -> Self {
1386 Self { items: Vec::new() }
1387 }
1388 pub fn focus(&mut self, item: T) {
1390 self.items.push(item);
1391 }
1392 pub fn blur(&mut self) -> Option<T> {
1394 self.items.pop()
1395 }
1396 pub fn current(&self) -> Option<&T> {
1398 self.items.last()
1399 }
1400 pub fn depth(&self) -> usize {
1402 self.items.len()
1403 }
1404 pub fn is_empty(&self) -> bool {
1406 self.items.is_empty()
1407 }
1408}
1409#[allow(dead_code)]
1411pub struct Fixture {
1412 data: std::collections::HashMap<String, String>,
1413}
1414#[allow(dead_code)]
1415impl Fixture {
1416 pub fn new() -> Self {
1418 Self {
1419 data: std::collections::HashMap::new(),
1420 }
1421 }
1422 pub fn set(&mut self, key: impl Into<String>, val: impl Into<String>) {
1424 self.data.insert(key.into(), val.into());
1425 }
1426 pub fn get(&self, key: &str) -> Option<&str> {
1428 self.data.get(key).map(|s| s.as_str())
1429 }
1430 pub fn len(&self) -> usize {
1432 self.data.len()
1433 }
1434 pub fn is_empty(&self) -> bool {
1436 self.len() == 0
1437 }
1438}
1439#[derive(Debug, Clone)]
1443pub struct CongrHypothesis {
1444 pub lhs: Expr,
1446 pub rhs: Expr,
1448 pub is_heq: bool,
1450}
1451impl CongrHypothesis {
1452 pub fn eq(lhs: Expr, rhs: Expr) -> Self {
1454 Self {
1455 lhs,
1456 rhs,
1457 is_heq: false,
1458 }
1459 }
1460 pub fn heq(lhs: Expr, rhs: Expr) -> Self {
1462 Self {
1463 lhs,
1464 rhs,
1465 is_heq: true,
1466 }
1467 }
1468 pub fn is_trivial(&self) -> bool {
1470 self.lhs == self.rhs
1471 }
1472}
1473pub struct FlatCC {
1478 parent: Vec<TermIdx>,
1480 rank: Vec<u32>,
1482 apps: Vec<FlatApp>,
1484}
1485impl FlatCC {
1486 pub fn new(n: usize) -> Self {
1488 Self {
1489 parent: (0..n).collect(),
1490 rank: vec![0; n],
1491 apps: Vec::new(),
1492 }
1493 }
1494 pub fn find(&mut self, i: TermIdx) -> TermIdx {
1496 if self.parent[i] != i {
1497 self.parent[i] = self.find(self.parent[i]);
1498 }
1499 self.parent[i]
1500 }
1501 pub fn union(&mut self, i: TermIdx, j: TermIdx) {
1503 let ri = self.find(i);
1504 let rj = self.find(j);
1505 if ri == rj {
1506 return;
1507 }
1508 if self.rank[ri] < self.rank[rj] {
1509 self.parent[ri] = rj;
1510 } else if self.rank[ri] > self.rank[rj] {
1511 self.parent[rj] = ri;
1512 } else {
1513 self.parent[rj] = ri;
1514 self.rank[ri] += 1;
1515 }
1516 }
1517 pub fn add_node(&mut self) -> TermIdx {
1519 let idx = self.parent.len();
1520 self.parent.push(idx);
1521 self.rank.push(0);
1522 idx
1523 }
1524 pub fn add_app(&mut self, app: FlatApp) {
1526 self.apps.push(app);
1527 }
1528 pub fn are_equal(&mut self, i: TermIdx, j: TermIdx) -> bool {
1530 self.find(i) == self.find(j)
1531 }
1532 pub fn num_nodes(&self) -> usize {
1534 self.parent.len()
1535 }
1536 pub fn num_apps(&self) -> usize {
1538 self.apps.len()
1539 }
1540 pub fn propagate_congruences(&mut self) {
1546 let len = self.apps.len();
1547 for i in 0..len {
1548 for j in (i + 1)..len {
1549 let a = self.apps[i];
1550 let b = self.apps[j];
1551 if self.are_equal(a.fn_idx, b.fn_idx) && self.are_equal(a.arg_idx, b.arg_idx) {
1552 if let (Some(ra), Some(rb)) = (a.result_idx, b.result_idx) {
1553 self.union(ra, rb);
1554 }
1555 }
1556 }
1557 }
1558 }
1559}
1560#[derive(Debug, Clone)]
1562pub struct ENode {
1563 pub repr: Expr,
1565 pub members: Vec<Expr>,
1567 pub proofs: Vec<Option<Expr>>,
1569}
1570impl ENode {
1571 pub fn singleton(expr: Expr) -> Self {
1573 Self {
1574 repr: expr.clone(),
1575 members: vec![expr],
1576 proofs: vec![None],
1577 }
1578 }
1579 pub fn add_member(&mut self, expr: Expr, proof: Option<Expr>) {
1581 if !self.members.contains(&expr) {
1582 self.members.push(expr);
1583 self.proofs.push(proof);
1584 }
1585 }
1586 pub fn contains(&self, expr: &Expr) -> bool {
1588 self.members.contains(expr)
1589 }
1590 pub fn size(&self) -> usize {
1592 self.members.len()
1593 }
1594}
1595#[allow(dead_code)]
1597pub struct RawFnPtr {
1598 ptr: usize,
1600 arity: usize,
1601 name: String,
1602}
1603#[allow(dead_code)]
1604impl RawFnPtr {
1605 pub fn new(ptr: usize, arity: usize, name: impl Into<String>) -> Self {
1607 Self {
1608 ptr,
1609 arity,
1610 name: name.into(),
1611 }
1612 }
1613 pub fn arity(&self) -> usize {
1615 self.arity
1616 }
1617 pub fn name(&self) -> &str {
1619 &self.name
1620 }
1621 pub fn raw(&self) -> usize {
1623 self.ptr
1624 }
1625}
1626#[allow(dead_code)]
1628pub struct LabelSet {
1629 labels: Vec<String>,
1630}
1631#[allow(dead_code)]
1632impl LabelSet {
1633 pub fn new() -> Self {
1635 Self { labels: Vec::new() }
1636 }
1637 pub fn add(&mut self, label: impl Into<String>) {
1639 let s = label.into();
1640 if !self.labels.contains(&s) {
1641 self.labels.push(s);
1642 }
1643 }
1644 pub fn has(&self, label: &str) -> bool {
1646 self.labels.iter().any(|l| l == label)
1647 }
1648 pub fn count(&self) -> usize {
1650 self.labels.len()
1651 }
1652 pub fn all(&self) -> &[String] {
1654 &self.labels
1655 }
1656}
1657#[allow(dead_code)]
1659pub struct MinHeap<T: Ord> {
1660 data: Vec<T>,
1661}
1662#[allow(dead_code)]
1663impl<T: Ord> MinHeap<T> {
1664 pub fn new() -> Self {
1666 Self { data: Vec::new() }
1667 }
1668 pub fn push(&mut self, val: T) {
1670 self.data.push(val);
1671 self.sift_up(self.data.len() - 1);
1672 }
1673 pub fn pop(&mut self) -> Option<T> {
1675 if self.data.is_empty() {
1676 return None;
1677 }
1678 let n = self.data.len();
1679 self.data.swap(0, n - 1);
1680 let min = self.data.pop();
1681 if !self.data.is_empty() {
1682 self.sift_down(0);
1683 }
1684 min
1685 }
1686 pub fn peek(&self) -> Option<&T> {
1688 self.data.first()
1689 }
1690 pub fn len(&self) -> usize {
1692 self.data.len()
1693 }
1694 pub fn is_empty(&self) -> bool {
1696 self.data.is_empty()
1697 }
1698 fn sift_up(&mut self, mut i: usize) {
1699 while i > 0 {
1700 let parent = (i - 1) / 2;
1701 if self.data[i] < self.data[parent] {
1702 self.data.swap(i, parent);
1703 i = parent;
1704 } else {
1705 break;
1706 }
1707 }
1708 }
1709 fn sift_down(&mut self, mut i: usize) {
1710 let n = self.data.len();
1711 loop {
1712 let left = 2 * i + 1;
1713 let right = 2 * i + 2;
1714 let mut smallest = i;
1715 if left < n && self.data[left] < self.data[smallest] {
1716 smallest = left;
1717 }
1718 if right < n && self.data[right] < self.data[smallest] {
1719 smallest = right;
1720 }
1721 if smallest == i {
1722 break;
1723 }
1724 self.data.swap(i, smallest);
1725 i = smallest;
1726 }
1727 }
1728}
1729#[derive(Debug, Clone, Default)]
1731pub struct CongrClosureStats {
1732 pub equalities_added: usize,
1734 pub congruences_propagated: usize,
1736 pub unions: usize,
1738 pub apps_tracked: usize,
1740}
1741impl CongrClosureStats {
1742 pub fn new() -> Self {
1744 Self::default()
1745 }
1746}
1747#[allow(dead_code)]
1749pub struct SmallMap<K: Ord + Clone, V: Clone> {
1750 entries: Vec<(K, V)>,
1751}
1752#[allow(dead_code)]
1753impl<K: Ord + Clone, V: Clone> SmallMap<K, V> {
1754 pub fn new() -> Self {
1756 Self {
1757 entries: Vec::new(),
1758 }
1759 }
1760 pub fn insert(&mut self, key: K, val: V) {
1762 match self.entries.binary_search_by_key(&&key, |(k, _)| k) {
1763 Ok(i) => self.entries[i].1 = val,
1764 Err(i) => self.entries.insert(i, (key, val)),
1765 }
1766 }
1767 pub fn get(&self, key: &K) -> Option<&V> {
1769 self.entries
1770 .binary_search_by_key(&key, |(k, _)| k)
1771 .ok()
1772 .map(|i| &self.entries[i].1)
1773 }
1774 pub fn len(&self) -> usize {
1776 self.entries.len()
1777 }
1778 pub fn is_empty(&self) -> bool {
1780 self.entries.is_empty()
1781 }
1782 pub fn keys(&self) -> Vec<&K> {
1784 self.entries.iter().map(|(k, _)| k).collect()
1785 }
1786 pub fn values(&self) -> Vec<&V> {
1788 self.entries.iter().map(|(_, v)| v).collect()
1789 }
1790}
1791#[cfg(test)]
1792mod find_tests;