Skip to main content

oxilean_kernel/simp/
types.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use super::functions::*;
6use crate::{Expr, Literal, Name};
7use std::collections::HashMap;
8
9/// A generic counter that tracks min/max/sum for statistical summaries.
10#[allow(dead_code)]
11pub struct StatSummary {
12    count: u64,
13    sum: f64,
14    min: f64,
15    max: f64,
16}
17#[allow(dead_code)]
18impl StatSummary {
19    /// Creates an empty summary.
20    pub fn new() -> Self {
21        Self {
22            count: 0,
23            sum: 0.0,
24            min: f64::INFINITY,
25            max: f64::NEG_INFINITY,
26        }
27    }
28    /// Records a sample.
29    pub fn record(&mut self, val: f64) {
30        self.count += 1;
31        self.sum += val;
32        if val < self.min {
33            self.min = val;
34        }
35        if val > self.max {
36            self.max = val;
37        }
38    }
39    /// Returns the mean, or `None` if no samples.
40    pub fn mean(&self) -> Option<f64> {
41        if self.count == 0 {
42            None
43        } else {
44            Some(self.sum / self.count as f64)
45        }
46    }
47    /// Returns the minimum, or `None` if no samples.
48    pub fn min(&self) -> Option<f64> {
49        if self.count == 0 {
50            None
51        } else {
52            Some(self.min)
53        }
54    }
55    /// Returns the maximum, or `None` if no samples.
56    pub fn max(&self) -> Option<f64> {
57        if self.count == 0 {
58            None
59        } else {
60            Some(self.max)
61        }
62    }
63    /// Returns the count of recorded samples.
64    pub fn count(&self) -> u64 {
65        self.count
66    }
67}
68/// A set of rewrite rules.
69#[allow(dead_code)]
70pub struct RewriteRuleSet {
71    rules: Vec<RewriteRule>,
72}
73#[allow(dead_code)]
74impl RewriteRuleSet {
75    /// Creates an empty rule set.
76    pub fn new() -> Self {
77        Self { rules: Vec::new() }
78    }
79    /// Adds a rule.
80    pub fn add(&mut self, rule: RewriteRule) {
81        self.rules.push(rule);
82    }
83    /// Returns the number of rules.
84    pub fn len(&self) -> usize {
85        self.rules.len()
86    }
87    /// Returns `true` if the set is empty.
88    pub fn is_empty(&self) -> bool {
89        self.rules.is_empty()
90    }
91    /// Returns all conditional rules.
92    pub fn conditional_rules(&self) -> Vec<&RewriteRule> {
93        self.rules.iter().filter(|r| r.conditional).collect()
94    }
95    /// Returns all unconditional rules.
96    pub fn unconditional_rules(&self) -> Vec<&RewriteRule> {
97        self.rules.iter().filter(|r| !r.conditional).collect()
98    }
99    /// Looks up a rule by name.
100    pub fn get(&self, name: &str) -> Option<&RewriteRule> {
101        self.rules.iter().find(|r| r.name == name)
102    }
103}
104/// Direction of a simp rewrite.
105#[derive(Clone, Copy, Debug, PartialEq, Eq)]
106pub enum SimpDirection {
107    /// Rewrite left-to-right (standard).
108    Forward,
109    /// Rewrite right-to-left.
110    Backward,
111}
112/// A dependency closure builder (transitive closure via BFS).
113#[allow(dead_code)]
114pub struct TransitiveClosure {
115    adj: Vec<Vec<usize>>,
116    n: usize,
117}
118#[allow(dead_code)]
119impl TransitiveClosure {
120    /// Creates a transitive closure builder for `n` nodes.
121    pub fn new(n: usize) -> Self {
122        Self {
123            adj: vec![Vec::new(); n],
124            n,
125        }
126    }
127    /// Adds a direct edge.
128    pub fn add_edge(&mut self, from: usize, to: usize) {
129        if from < self.n {
130            self.adj[from].push(to);
131        }
132    }
133    /// Computes all nodes reachable from `start` (including `start`).
134    pub fn reachable_from(&self, start: usize) -> Vec<usize> {
135        let mut visited = vec![false; self.n];
136        let mut queue = std::collections::VecDeque::new();
137        queue.push_back(start);
138        while let Some(node) = queue.pop_front() {
139            if node >= self.n || visited[node] {
140                continue;
141            }
142            visited[node] = true;
143            for &next in &self.adj[node] {
144                queue.push_back(next);
145            }
146        }
147        (0..self.n).filter(|&i| visited[i]).collect()
148    }
149    /// Returns `true` if `from` can transitively reach `to`.
150    pub fn can_reach(&self, from: usize, to: usize) -> bool {
151        self.reachable_from(from).contains(&to)
152    }
153}
154/// A pair of `StatSummary` values tracking before/after a transformation.
155#[allow(dead_code)]
156pub struct TransformStat {
157    before: StatSummary,
158    after: StatSummary,
159}
160#[allow(dead_code)]
161impl TransformStat {
162    /// Creates a new transform stat recorder.
163    pub fn new() -> Self {
164        Self {
165            before: StatSummary::new(),
166            after: StatSummary::new(),
167        }
168    }
169    /// Records a before value.
170    pub fn record_before(&mut self, v: f64) {
171        self.before.record(v);
172    }
173    /// Records an after value.
174    pub fn record_after(&mut self, v: f64) {
175        self.after.record(v);
176    }
177    /// Returns the mean reduction ratio (after/before).
178    pub fn mean_ratio(&self) -> Option<f64> {
179        let b = self.before.mean()?;
180        let a = self.after.mean()?;
181        if b.abs() < f64::EPSILON {
182            return None;
183        }
184        Some(a / b)
185    }
186}
187/// A versioned record that stores a history of values.
188#[allow(dead_code)]
189pub struct VersionedRecord<T: Clone> {
190    history: Vec<T>,
191}
192#[allow(dead_code)]
193impl<T: Clone> VersionedRecord<T> {
194    /// Creates a new record with an initial value.
195    pub fn new(initial: T) -> Self {
196        Self {
197            history: vec![initial],
198        }
199    }
200    /// Updates the record with a new version.
201    pub fn update(&mut self, val: T) {
202        self.history.push(val);
203    }
204    /// Returns the current (latest) value.
205    pub fn current(&self) -> &T {
206        self.history
207            .last()
208            .expect("VersionedRecord history is always non-empty after construction")
209    }
210    /// Returns the value at version `n` (0-indexed), or `None`.
211    pub fn at_version(&self, n: usize) -> Option<&T> {
212        self.history.get(n)
213    }
214    /// Returns the version number of the current value.
215    pub fn version(&self) -> usize {
216        self.history.len() - 1
217    }
218    /// Returns `true` if more than one version exists.
219    pub fn has_history(&self) -> bool {
220        self.history.len() > 1
221    }
222}
223/// A simple decision tree node for rule dispatching.
224#[allow(dead_code)]
225#[allow(missing_docs)]
226pub enum DecisionNode {
227    /// A leaf with an action string.
228    Leaf(String),
229    /// An interior node: check `key` equals `val` → `yes_branch`, else `no_branch`.
230    Branch {
231        key: String,
232        val: String,
233        yes_branch: Box<DecisionNode>,
234        no_branch: Box<DecisionNode>,
235    },
236}
237#[allow(dead_code)]
238impl DecisionNode {
239    /// Evaluates the decision tree with the given context.
240    pub fn evaluate(&self, ctx: &std::collections::HashMap<String, String>) -> &str {
241        match self {
242            DecisionNode::Leaf(action) => action.as_str(),
243            DecisionNode::Branch {
244                key,
245                val,
246                yes_branch,
247                no_branch,
248            } => {
249                let actual = ctx.get(key).map(|s| s.as_str()).unwrap_or("");
250                if actual == val.as_str() {
251                    yes_branch.evaluate(ctx)
252                } else {
253                    no_branch.evaluate(ctx)
254                }
255            }
256        }
257    }
258    /// Returns the depth of the decision tree.
259    pub fn depth(&self) -> usize {
260        match self {
261            DecisionNode::Leaf(_) => 0,
262            DecisionNode::Branch {
263                yes_branch,
264                no_branch,
265                ..
266            } => 1 + yes_branch.depth().max(no_branch.depth()),
267        }
268    }
269}
270/// A simple stack-based calculator for arithmetic expressions.
271#[allow(dead_code)]
272pub struct StackCalc {
273    stack: Vec<i64>,
274}
275#[allow(dead_code)]
276impl StackCalc {
277    /// Creates a new empty calculator.
278    pub fn new() -> Self {
279        Self { stack: Vec::new() }
280    }
281    /// Pushes an integer literal.
282    pub fn push(&mut self, n: i64) {
283        self.stack.push(n);
284    }
285    /// Adds the top two values.  Panics if fewer than two values.
286    pub fn add(&mut self) {
287        let b = self
288            .stack
289            .pop()
290            .expect("stack must have at least two values for add");
291        let a = self
292            .stack
293            .pop()
294            .expect("stack must have at least two values for add");
295        self.stack.push(a + b);
296    }
297    /// Subtracts top from second.
298    pub fn sub(&mut self) {
299        let b = self
300            .stack
301            .pop()
302            .expect("stack must have at least two values for sub");
303        let a = self
304            .stack
305            .pop()
306            .expect("stack must have at least two values for sub");
307        self.stack.push(a - b);
308    }
309    /// Multiplies the top two values.
310    pub fn mul(&mut self) {
311        let b = self
312            .stack
313            .pop()
314            .expect("stack must have at least two values for mul");
315        let a = self
316            .stack
317            .pop()
318            .expect("stack must have at least two values for mul");
319        self.stack.push(a * b);
320    }
321    /// Peeks the top value.
322    pub fn peek(&self) -> Option<i64> {
323        self.stack.last().copied()
324    }
325    /// Returns the stack depth.
326    pub fn depth(&self) -> usize {
327        self.stack.len()
328    }
329}
330/// A trie-based prefix counter.
331#[allow(dead_code)]
332pub struct PrefixCounter {
333    children: std::collections::HashMap<char, PrefixCounter>,
334    count: usize,
335}
336#[allow(dead_code)]
337impl PrefixCounter {
338    /// Creates an empty prefix counter.
339    pub fn new() -> Self {
340        Self {
341            children: std::collections::HashMap::new(),
342            count: 0,
343        }
344    }
345    /// Records a string.
346    pub fn record(&mut self, s: &str) {
347        self.count += 1;
348        let mut node = self;
349        for c in s.chars() {
350            node = node.children.entry(c).or_default();
351            node.count += 1;
352        }
353    }
354    /// Returns how many strings have been recorded that start with `prefix`.
355    pub fn count_with_prefix(&self, prefix: &str) -> usize {
356        let mut node = self;
357        for c in prefix.chars() {
358            match node.children.get(&c) {
359                Some(n) => node = n,
360                None => return 0,
361            }
362        }
363        node.count
364    }
365}
366/// A simple key-value store backed by a sorted Vec for small maps.
367#[allow(dead_code)]
368pub struct SmallMap<K: Ord + Clone, V: Clone> {
369    entries: Vec<(K, V)>,
370}
371#[allow(dead_code)]
372impl<K: Ord + Clone, V: Clone> SmallMap<K, V> {
373    /// Creates a new empty small map.
374    pub fn new() -> Self {
375        Self {
376            entries: Vec::new(),
377        }
378    }
379    /// Inserts or replaces the value for `key`.
380    pub fn insert(&mut self, key: K, val: V) {
381        match self.entries.binary_search_by_key(&&key, |(k, _)| k) {
382            Ok(i) => self.entries[i].1 = val,
383            Err(i) => self.entries.insert(i, (key, val)),
384        }
385    }
386    /// Returns the value for `key`, or `None`.
387    pub fn get(&self, key: &K) -> Option<&V> {
388        self.entries
389            .binary_search_by_key(&key, |(k, _)| k)
390            .ok()
391            .map(|i| &self.entries[i].1)
392    }
393    /// Returns the number of entries.
394    pub fn len(&self) -> usize {
395        self.entries.len()
396    }
397    /// Returns `true` if empty.
398    pub fn is_empty(&self) -> bool {
399        self.entries.is_empty()
400    }
401    /// Returns all keys.
402    pub fn keys(&self) -> Vec<&K> {
403        self.entries.iter().map(|(k, _)| k).collect()
404    }
405    /// Returns all values.
406    pub fn values(&self) -> Vec<&V> {
407        self.entries.iter().map(|(_, v)| v).collect()
408    }
409}
410/// A write-once cell.
411#[allow(dead_code)]
412pub struct WriteOnce<T> {
413    value: std::cell::Cell<Option<T>>,
414}
415#[allow(dead_code)]
416impl<T: Copy> WriteOnce<T> {
417    /// Creates an empty write-once cell.
418    pub fn new() -> Self {
419        Self {
420            value: std::cell::Cell::new(None),
421        }
422    }
423    /// Writes a value.  Returns `false` if already written.
424    pub fn write(&self, val: T) -> bool {
425        if self.value.get().is_some() {
426            return false;
427        }
428        self.value.set(Some(val));
429        true
430    }
431    /// Returns the value if written.
432    pub fn read(&self) -> Option<T> {
433        self.value.get()
434    }
435    /// Returns `true` if the value has been written.
436    pub fn is_written(&self) -> bool {
437        self.value.get().is_some()
438    }
439}
440/// A type-erased function pointer with arity tracking.
441#[allow(dead_code)]
442pub struct RawFnPtr {
443    /// The raw function pointer (stored as usize for type erasure).
444    ptr: usize,
445    arity: usize,
446    name: String,
447}
448#[allow(dead_code)]
449impl RawFnPtr {
450    /// Creates a new raw function pointer descriptor.
451    pub fn new(ptr: usize, arity: usize, name: impl Into<String>) -> Self {
452        Self {
453            ptr,
454            arity,
455            name: name.into(),
456        }
457    }
458    /// Returns the arity.
459    pub fn arity(&self) -> usize {
460        self.arity
461    }
462    /// Returns the name.
463    pub fn name(&self) -> &str {
464        &self.name
465    }
466    /// Returns the raw pointer value.
467    pub fn raw(&self) -> usize {
468        self.ptr
469    }
470}
471/// A simplified expression with a trace of applied lemma names.
472#[derive(Debug, Clone)]
473pub struct SimpResult {
474    /// The simplified expression.
475    pub expr: Expr,
476    /// Names of lemmas that were applied (in order).
477    pub applied: Vec<Name>,
478    /// Whether any change was made.
479    pub changed: bool,
480}
481impl SimpResult {
482    /// Simplification had no effect.
483    pub fn unchanged(expr: Expr) -> Self {
484        Self {
485            expr,
486            applied: Vec::new(),
487            changed: false,
488        }
489    }
490    /// Simplification succeeded.
491    pub fn simplified(expr: Expr, applied: Vec<Name>) -> Self {
492        let changed = !applied.is_empty();
493        Self {
494            expr,
495            applied,
496            changed,
497        }
498    }
499}
500/// A non-empty list (at least one element guaranteed).
501#[allow(dead_code)]
502pub struct NonEmptyVec<T> {
503    head: T,
504    tail: Vec<T>,
505}
506#[allow(dead_code)]
507impl<T> NonEmptyVec<T> {
508    /// Creates a non-empty vec with a single element.
509    pub fn singleton(val: T) -> Self {
510        Self {
511            head: val,
512            tail: Vec::new(),
513        }
514    }
515    /// Pushes an element.
516    pub fn push(&mut self, val: T) {
517        self.tail.push(val);
518    }
519    /// Returns a reference to the first element.
520    pub fn first(&self) -> &T {
521        &self.head
522    }
523    /// Returns a reference to the last element.
524    pub fn last(&self) -> &T {
525        self.tail.last().unwrap_or(&self.head)
526    }
527    /// Returns the number of elements.
528    pub fn len(&self) -> usize {
529        1 + self.tail.len()
530    }
531    /// Returns whether the collection is empty.
532    pub fn is_empty(&self) -> bool {
533        self.len() == 0
534    }
535    /// Returns all elements as a Vec.
536    pub fn to_vec(&self) -> Vec<&T> {
537        let mut v = vec![&self.head];
538        v.extend(self.tail.iter());
539        v
540    }
541}
542/// A simple mutable key-value store for test fixtures.
543#[allow(dead_code)]
544pub struct Fixture {
545    data: std::collections::HashMap<String, String>,
546}
547#[allow(dead_code)]
548impl Fixture {
549    /// Creates an empty fixture.
550    pub fn new() -> Self {
551        Self {
552            data: std::collections::HashMap::new(),
553        }
554    }
555    /// Sets a key.
556    pub fn set(&mut self, key: impl Into<String>, val: impl Into<String>) {
557        self.data.insert(key.into(), val.into());
558    }
559    /// Gets a value.
560    pub fn get(&self, key: &str) -> Option<&str> {
561        self.data.get(key).map(|s| s.as_str())
562    }
563    /// Returns the number of entries.
564    pub fn len(&self) -> usize {
565        self.data.len()
566    }
567    /// Returns whether the collection is empty.
568    pub fn is_empty(&self) -> bool {
569        self.len() == 0
570    }
571}
572/// A reusable scratch buffer for path computations.
573#[allow(dead_code)]
574pub struct PathBuf {
575    components: Vec<String>,
576}
577#[allow(dead_code)]
578impl PathBuf {
579    /// Creates a new empty path buffer.
580    pub fn new() -> Self {
581        Self {
582            components: Vec::new(),
583        }
584    }
585    /// Pushes a component.
586    pub fn push(&mut self, comp: impl Into<String>) {
587        self.components.push(comp.into());
588    }
589    /// Pops the last component.
590    pub fn pop(&mut self) {
591        self.components.pop();
592    }
593    /// Returns the current path as a `/`-separated string.
594    pub fn as_str(&self) -> String {
595        self.components.join("/")
596    }
597    /// Returns the depth of the path.
598    pub fn depth(&self) -> usize {
599        self.components.len()
600    }
601    /// Clears the path.
602    pub fn clear(&mut self) {
603        self.components.clear();
604    }
605}
606/// A token bucket rate limiter.
607#[allow(dead_code)]
608pub struct TokenBucket {
609    capacity: u64,
610    tokens: u64,
611    refill_per_ms: u64,
612    last_refill: std::time::Instant,
613}
614#[allow(dead_code)]
615impl TokenBucket {
616    /// Creates a new token bucket.
617    pub fn new(capacity: u64, refill_per_ms: u64) -> Self {
618        Self {
619            capacity,
620            tokens: capacity,
621            refill_per_ms,
622            last_refill: std::time::Instant::now(),
623        }
624    }
625    /// Attempts to consume `n` tokens.  Returns `true` on success.
626    pub fn try_consume(&mut self, n: u64) -> bool {
627        self.refill();
628        if self.tokens >= n {
629            self.tokens -= n;
630            true
631        } else {
632            false
633        }
634    }
635    fn refill(&mut self) {
636        let now = std::time::Instant::now();
637        let elapsed_ms = now.duration_since(self.last_refill).as_millis() as u64;
638        if elapsed_ms > 0 {
639            let new_tokens = elapsed_ms * self.refill_per_ms;
640            self.tokens = (self.tokens + new_tokens).min(self.capacity);
641            self.last_refill = now;
642        }
643    }
644    /// Returns the number of currently available tokens.
645    pub fn available(&self) -> u64 {
646        self.tokens
647    }
648    /// Returns the bucket capacity.
649    pub fn capacity(&self) -> u64 {
650        self.capacity
651    }
652}
653/// A collection of simp lemmas that can be applied in sequence.
654pub struct SimpLemmaSet {
655    lemmas: Vec<SimpLemma>,
656}
657impl SimpLemmaSet {
658    /// Create an empty lemma set.
659    pub fn new() -> Self {
660        Self { lemmas: Vec::new() }
661    }
662    /// Add a lemma.
663    pub fn add(&mut self, lemma: SimpLemma) {
664        self.lemmas.push(lemma);
665    }
666    /// Number of lemmas.
667    pub fn len(&self) -> usize {
668        self.lemmas.len()
669    }
670    /// Check if empty.
671    pub fn is_empty(&self) -> bool {
672        self.lemmas.is_empty()
673    }
674    /// Apply all lemmas in order to an expression (one pass).
675    pub fn apply_once(&self, expr: &Expr) -> (Expr, bool) {
676        let mut current = expr.clone();
677        let mut changed = false;
678        for lemma in &self.lemmas {
679            let (new_expr, c) =
680                rewrite_once(&current, lemma.effective_lhs(), lemma.effective_rhs());
681            if c {
682                current = new_expr;
683                changed = true;
684            }
685        }
686        (current, changed)
687    }
688    /// Apply all lemmas exhaustively (until no changes).
689    pub fn apply_all(&self, expr: &Expr) -> Expr {
690        let mut current = expr.clone();
691        loop {
692            let (new_expr, changed) = self.apply_once(&current);
693            if !changed {
694                return current;
695            }
696            current = new_expr;
697        }
698    }
699    /// Iter over lemmas.
700    pub fn iter(&self) -> impl Iterator<Item = &SimpLemma> {
701        self.lemmas.iter()
702    }
703    /// Look up a lemma by name.
704    pub fn find(&self, name: &Name) -> Option<&SimpLemma> {
705        self.lemmas.iter().find(|l| &l.name == name)
706    }
707}
708/// A window iterator that yields overlapping windows of size `n`.
709#[allow(dead_code)]
710pub struct WindowIterator<'a, T> {
711    pub(super) data: &'a [T],
712    pub(super) pos: usize,
713    pub(super) window: usize,
714}
715#[allow(dead_code)]
716impl<'a, T> WindowIterator<'a, T> {
717    /// Creates a new window iterator.
718    pub fn new(data: &'a [T], window: usize) -> Self {
719        Self {
720            data,
721            pos: 0,
722            window,
723        }
724    }
725}
726/// A counter that can measure elapsed time between snapshots.
727#[allow(dead_code)]
728pub struct Stopwatch {
729    start: std::time::Instant,
730    splits: Vec<f64>,
731}
732#[allow(dead_code)]
733impl Stopwatch {
734    /// Creates and starts a new stopwatch.
735    pub fn start() -> Self {
736        Self {
737            start: std::time::Instant::now(),
738            splits: Vec::new(),
739        }
740    }
741    /// Records a split time (elapsed since start).
742    pub fn split(&mut self) {
743        self.splits.push(self.elapsed_ms());
744    }
745    /// Returns total elapsed milliseconds since start.
746    pub fn elapsed_ms(&self) -> f64 {
747        self.start.elapsed().as_secs_f64() * 1000.0
748    }
749    /// Returns all recorded split times.
750    pub fn splits(&self) -> &[f64] {
751        &self.splits
752    }
753    /// Returns the number of splits.
754    pub fn num_splits(&self) -> usize {
755        self.splits.len()
756    }
757}
758/// A simple directed acyclic graph.
759#[allow(dead_code)]
760pub struct SimpleDag {
761    /// `edges[i]` is the list of direct successors of node `i`.
762    edges: Vec<Vec<usize>>,
763}
764#[allow(dead_code)]
765impl SimpleDag {
766    /// Creates a DAG with `n` nodes and no edges.
767    pub fn new(n: usize) -> Self {
768        Self {
769            edges: vec![Vec::new(); n],
770        }
771    }
772    /// Adds an edge from `from` to `to`.
773    pub fn add_edge(&mut self, from: usize, to: usize) {
774        if from < self.edges.len() {
775            self.edges[from].push(to);
776        }
777    }
778    /// Returns the successors of `node`.
779    pub fn successors(&self, node: usize) -> &[usize] {
780        self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
781    }
782    /// Returns `true` if `from` can reach `to` via DFS.
783    pub fn can_reach(&self, from: usize, to: usize) -> bool {
784        let mut visited = vec![false; self.edges.len()];
785        self.dfs(from, to, &mut visited)
786    }
787    fn dfs(&self, cur: usize, target: usize, visited: &mut Vec<bool>) -> bool {
788        if cur == target {
789            return true;
790        }
791        if cur >= visited.len() || visited[cur] {
792            return false;
793        }
794        visited[cur] = true;
795        for &next in self.successors(cur) {
796            if self.dfs(next, target, visited) {
797                return true;
798            }
799        }
800        false
801    }
802    /// Returns the topological order of nodes, or `None` if a cycle is detected.
803    pub fn topological_sort(&self) -> Option<Vec<usize>> {
804        let n = self.edges.len();
805        let mut in_degree = vec![0usize; n];
806        for succs in &self.edges {
807            for &s in succs {
808                if s < n {
809                    in_degree[s] += 1;
810                }
811            }
812        }
813        let mut queue: std::collections::VecDeque<usize> =
814            (0..n).filter(|&i| in_degree[i] == 0).collect();
815        let mut order = Vec::new();
816        while let Some(node) = queue.pop_front() {
817            order.push(node);
818            for &s in self.successors(node) {
819                if s < n {
820                    in_degree[s] -= 1;
821                    if in_degree[s] == 0 {
822                        queue.push_back(s);
823                    }
824                }
825            }
826        }
827        if order.len() == n {
828            Some(order)
829        } else {
830            None
831        }
832    }
833    /// Returns the number of nodes.
834    pub fn num_nodes(&self) -> usize {
835        self.edges.len()
836    }
837}
838/// A pool of reusable string buffers.
839#[allow(dead_code)]
840pub struct StringPool {
841    free: Vec<String>,
842}
843#[allow(dead_code)]
844impl StringPool {
845    /// Creates a new empty string pool.
846    pub fn new() -> Self {
847        Self { free: Vec::new() }
848    }
849    /// Takes a string from the pool (may be empty).
850    pub fn take(&mut self) -> String {
851        self.free.pop().unwrap_or_default()
852    }
853    /// Returns a string to the pool.
854    pub fn give(&mut self, mut s: String) {
855        s.clear();
856        self.free.push(s);
857    }
858    /// Returns the number of free strings in the pool.
859    pub fn free_count(&self) -> usize {
860        self.free.len()
861    }
862}
863/// A label set for a graph node.
864#[allow(dead_code)]
865pub struct LabelSet {
866    labels: Vec<String>,
867}
868#[allow(dead_code)]
869impl LabelSet {
870    /// Creates a new empty label set.
871    pub fn new() -> Self {
872        Self { labels: Vec::new() }
873    }
874    /// Adds a label (deduplicates).
875    pub fn add(&mut self, label: impl Into<String>) {
876        let s = label.into();
877        if !self.labels.contains(&s) {
878            self.labels.push(s);
879        }
880    }
881    /// Returns `true` if `label` is present.
882    pub fn has(&self, label: &str) -> bool {
883        self.labels.iter().any(|l| l == label)
884    }
885    /// Returns the count of labels.
886    pub fn count(&self) -> usize {
887        self.labels.len()
888    }
889    /// Returns all labels.
890    pub fn all(&self) -> &[String] {
891        &self.labels
892    }
893}
894/// A mutable reference stack for tracking the current "focus" in a tree traversal.
895#[allow(dead_code)]
896pub struct FocusStack<T> {
897    items: Vec<T>,
898}
899#[allow(dead_code)]
900impl<T> FocusStack<T> {
901    /// Creates an empty focus stack.
902    pub fn new() -> Self {
903        Self { items: Vec::new() }
904    }
905    /// Focuses on `item`.
906    pub fn focus(&mut self, item: T) {
907        self.items.push(item);
908    }
909    /// Blurs (pops) the current focus.
910    pub fn blur(&mut self) -> Option<T> {
911        self.items.pop()
912    }
913    /// Returns the current focus, or `None`.
914    pub fn current(&self) -> Option<&T> {
915        self.items.last()
916    }
917    /// Returns the focus depth.
918    pub fn depth(&self) -> usize {
919        self.items.len()
920    }
921    /// Returns `true` if there is no current focus.
922    pub fn is_empty(&self) -> bool {
923        self.items.is_empty()
924    }
925}
926/// A flat list of substitution pairs `(from, to)`.
927#[allow(dead_code)]
928pub struct FlatSubstitution {
929    pairs: Vec<(String, String)>,
930}
931#[allow(dead_code)]
932impl FlatSubstitution {
933    /// Creates an empty substitution.
934    pub fn new() -> Self {
935        Self { pairs: Vec::new() }
936    }
937    /// Adds a pair.
938    pub fn add(&mut self, from: impl Into<String>, to: impl Into<String>) {
939        self.pairs.push((from.into(), to.into()));
940    }
941    /// Applies all substitutions to `s` (leftmost-first order).
942    pub fn apply(&self, s: &str) -> String {
943        let mut result = s.to_string();
944        for (from, to) in &self.pairs {
945            result = result.replace(from.as_str(), to.as_str());
946        }
947        result
948    }
949    /// Returns the number of pairs.
950    pub fn len(&self) -> usize {
951        self.pairs.len()
952    }
953    /// Returns `true` if empty.
954    pub fn is_empty(&self) -> bool {
955        self.pairs.is_empty()
956    }
957}
958/// A hierarchical configuration tree.
959#[allow(dead_code)]
960pub struct ConfigNode {
961    key: String,
962    value: Option<String>,
963    children: Vec<ConfigNode>,
964}
965#[allow(dead_code)]
966impl ConfigNode {
967    /// Creates a leaf config node with a value.
968    pub fn leaf(key: impl Into<String>, value: impl Into<String>) -> Self {
969        Self {
970            key: key.into(),
971            value: Some(value.into()),
972            children: Vec::new(),
973        }
974    }
975    /// Creates a section node with children.
976    pub fn section(key: impl Into<String>) -> Self {
977        Self {
978            key: key.into(),
979            value: None,
980            children: Vec::new(),
981        }
982    }
983    /// Adds a child node.
984    pub fn add_child(&mut self, child: ConfigNode) {
985        self.children.push(child);
986    }
987    /// Returns the key.
988    pub fn key(&self) -> &str {
989        &self.key
990    }
991    /// Returns the value, or `None` for section nodes.
992    pub fn value(&self) -> Option<&str> {
993        self.value.as_deref()
994    }
995    /// Returns the number of children.
996    pub fn num_children(&self) -> usize {
997        self.children.len()
998    }
999    /// Looks up a dot-separated path.
1000    pub fn lookup(&self, path: &str) -> Option<&str> {
1001        let mut parts = path.splitn(2, '.');
1002        let head = parts.next()?;
1003        let tail = parts.next();
1004        if head != self.key {
1005            return None;
1006        }
1007        match tail {
1008            None => self.value.as_deref(),
1009            Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
1010        }
1011    }
1012    fn lookup_relative(&self, path: &str) -> Option<&str> {
1013        let mut parts = path.splitn(2, '.');
1014        let head = parts.next()?;
1015        let tail = parts.next();
1016        if head != self.key {
1017            return None;
1018        }
1019        match tail {
1020            None => self.value.as_deref(),
1021            Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
1022        }
1023    }
1024}
1025/// A single simp lemma: a conditional rewrite rule `lhs = rhs`.
1026#[derive(Clone, Debug)]
1027pub struct SimpLemma {
1028    /// Name of the lemma.
1029    pub name: Name,
1030    /// Left-hand side pattern.
1031    pub lhs: Expr,
1032    /// Right-hand side replacement.
1033    pub rhs: Expr,
1034    /// Rewrite direction.
1035    pub direction: SimpDirection,
1036    /// Priority (higher = preferred).
1037    pub priority: i32,
1038}
1039impl SimpLemma {
1040    /// Create a forward simp lemma.
1041    pub fn forward(name: Name, lhs: Expr, rhs: Expr) -> Self {
1042        Self {
1043            name,
1044            lhs,
1045            rhs,
1046            direction: SimpDirection::Forward,
1047            priority: 1000,
1048        }
1049    }
1050    /// Create a backward simp lemma.
1051    pub fn backward(name: Name, lhs: Expr, rhs: Expr) -> Self {
1052        Self {
1053            name,
1054            lhs,
1055            rhs,
1056            direction: SimpDirection::Backward,
1057            priority: 1000,
1058        }
1059    }
1060    /// Swap the simp lemma direction.
1061    pub fn reversed(mut self) -> Self {
1062        self.direction = match self.direction {
1063            SimpDirection::Forward => SimpDirection::Backward,
1064            SimpDirection::Backward => SimpDirection::Forward,
1065        };
1066        std::mem::swap(&mut self.lhs, &mut self.rhs);
1067        self
1068    }
1069    /// Return the effective LHS (after direction is applied).
1070    pub fn effective_lhs(&self) -> &Expr {
1071        &self.lhs
1072    }
1073    /// Return the effective RHS (after direction is applied).
1074    pub fn effective_rhs(&self) -> &Expr {
1075        &self.rhs
1076    }
1077}
1078/// Represents a rewrite rule `lhs → rhs`.
1079#[allow(dead_code)]
1080#[allow(missing_docs)]
1081pub struct RewriteRule {
1082    /// The name of the rule.
1083    pub name: String,
1084    /// A string representation of the LHS pattern.
1085    pub lhs: String,
1086    /// A string representation of the RHS.
1087    pub rhs: String,
1088    /// Whether this is a conditional rule (has side conditions).
1089    pub conditional: bool,
1090}
1091#[allow(dead_code)]
1092impl RewriteRule {
1093    /// Creates an unconditional rewrite rule.
1094    pub fn unconditional(
1095        name: impl Into<String>,
1096        lhs: impl Into<String>,
1097        rhs: impl Into<String>,
1098    ) -> Self {
1099        Self {
1100            name: name.into(),
1101            lhs: lhs.into(),
1102            rhs: rhs.into(),
1103            conditional: false,
1104        }
1105    }
1106    /// Creates a conditional rewrite rule.
1107    pub fn conditional(
1108        name: impl Into<String>,
1109        lhs: impl Into<String>,
1110        rhs: impl Into<String>,
1111    ) -> Self {
1112        Self {
1113            name: name.into(),
1114            lhs: lhs.into(),
1115            rhs: rhs.into(),
1116            conditional: true,
1117        }
1118    }
1119    /// Returns a textual representation.
1120    pub fn display(&self) -> String {
1121        format!("{}: {} → {}", self.name, self.lhs, self.rhs)
1122    }
1123}
1124/// A fixed-size sliding window that computes a running sum.
1125#[allow(dead_code)]
1126pub struct SlidingSum {
1127    window: Vec<f64>,
1128    capacity: usize,
1129    pos: usize,
1130    sum: f64,
1131    count: usize,
1132}
1133#[allow(dead_code)]
1134impl SlidingSum {
1135    /// Creates a sliding sum with the given window size.
1136    pub fn new(capacity: usize) -> Self {
1137        Self {
1138            window: vec![0.0; capacity],
1139            capacity,
1140            pos: 0,
1141            sum: 0.0,
1142            count: 0,
1143        }
1144    }
1145    /// Adds a value to the window, removing the oldest if full.
1146    pub fn push(&mut self, val: f64) {
1147        let oldest = self.window[self.pos];
1148        self.sum -= oldest;
1149        self.sum += val;
1150        self.window[self.pos] = val;
1151        self.pos = (self.pos + 1) % self.capacity;
1152        if self.count < self.capacity {
1153            self.count += 1;
1154        }
1155    }
1156    /// Returns the current window sum.
1157    pub fn sum(&self) -> f64 {
1158        self.sum
1159    }
1160    /// Returns the window mean, or `None` if empty.
1161    pub fn mean(&self) -> Option<f64> {
1162        if self.count == 0 {
1163            None
1164        } else {
1165            Some(self.sum / self.count as f64)
1166        }
1167    }
1168    /// Returns the current window size (number of valid elements).
1169    pub fn count(&self) -> usize {
1170        self.count
1171    }
1172}
1173/// A min-heap implemented as a binary heap.
1174#[allow(dead_code)]
1175pub struct MinHeap<T: Ord> {
1176    data: Vec<T>,
1177}
1178#[allow(dead_code)]
1179impl<T: Ord> MinHeap<T> {
1180    /// Creates a new empty min-heap.
1181    pub fn new() -> Self {
1182        Self { data: Vec::new() }
1183    }
1184    /// Inserts an element.
1185    pub fn push(&mut self, val: T) {
1186        self.data.push(val);
1187        self.sift_up(self.data.len() - 1);
1188    }
1189    /// Removes and returns the minimum element.
1190    pub fn pop(&mut self) -> Option<T> {
1191        if self.data.is_empty() {
1192            return None;
1193        }
1194        let n = self.data.len();
1195        self.data.swap(0, n - 1);
1196        let min = self.data.pop();
1197        if !self.data.is_empty() {
1198            self.sift_down(0);
1199        }
1200        min
1201    }
1202    /// Returns a reference to the minimum element.
1203    pub fn peek(&self) -> Option<&T> {
1204        self.data.first()
1205    }
1206    /// Returns the number of elements.
1207    pub fn len(&self) -> usize {
1208        self.data.len()
1209    }
1210    /// Returns `true` if empty.
1211    pub fn is_empty(&self) -> bool {
1212        self.data.is_empty()
1213    }
1214    fn sift_up(&mut self, mut i: usize) {
1215        while i > 0 {
1216            let parent = (i - 1) / 2;
1217            if self.data[i] < self.data[parent] {
1218                self.data.swap(i, parent);
1219                i = parent;
1220            } else {
1221                break;
1222            }
1223        }
1224    }
1225    fn sift_down(&mut self, mut i: usize) {
1226        let n = self.data.len();
1227        loop {
1228            let left = 2 * i + 1;
1229            let right = 2 * i + 2;
1230            let mut smallest = i;
1231            if left < n && self.data[left] < self.data[smallest] {
1232                smallest = left;
1233            }
1234            if right < n && self.data[right] < self.data[smallest] {
1235                smallest = right;
1236            }
1237            if smallest == i {
1238                break;
1239            }
1240            self.data.swap(i, smallest);
1241            i = smallest;
1242        }
1243    }
1244}
1245/// A tagged union for representing a simple two-case discriminated union.
1246#[allow(dead_code)]
1247pub enum Either2<A, B> {
1248    /// The first alternative.
1249    First(A),
1250    /// The second alternative.
1251    Second(B),
1252}
1253#[allow(dead_code)]
1254impl<A, B> Either2<A, B> {
1255    /// Returns `true` if this is the first alternative.
1256    pub fn is_first(&self) -> bool {
1257        matches!(self, Either2::First(_))
1258    }
1259    /// Returns `true` if this is the second alternative.
1260    pub fn is_second(&self) -> bool {
1261        matches!(self, Either2::Second(_))
1262    }
1263    /// Returns the first value if present.
1264    pub fn first(self) -> Option<A> {
1265        match self {
1266            Either2::First(a) => Some(a),
1267            _ => None,
1268        }
1269    }
1270    /// Returns the second value if present.
1271    pub fn second(self) -> Option<B> {
1272        match self {
1273            Either2::Second(b) => Some(b),
1274            _ => None,
1275        }
1276    }
1277    /// Maps over the first alternative.
1278    pub fn map_first<C, F: FnOnce(A) -> C>(self, f: F) -> Either2<C, B> {
1279        match self {
1280            Either2::First(a) => Either2::First(f(a)),
1281            Either2::Second(b) => Either2::Second(b),
1282        }
1283    }
1284}
1285/// A sparse vector: stores only non-default elements.
1286#[allow(dead_code)]
1287pub struct SparseVec<T: Default + Clone + PartialEq> {
1288    entries: std::collections::HashMap<usize, T>,
1289    default_: T,
1290    logical_len: usize,
1291}
1292#[allow(dead_code)]
1293impl<T: Default + Clone + PartialEq> SparseVec<T> {
1294    /// Creates a new sparse vector with logical length `len`.
1295    pub fn new(len: usize) -> Self {
1296        Self {
1297            entries: std::collections::HashMap::new(),
1298            default_: T::default(),
1299            logical_len: len,
1300        }
1301    }
1302    /// Sets element at `idx`.
1303    pub fn set(&mut self, idx: usize, val: T) {
1304        if val == self.default_ {
1305            self.entries.remove(&idx);
1306        } else {
1307            self.entries.insert(idx, val);
1308        }
1309    }
1310    /// Gets element at `idx`.
1311    pub fn get(&self, idx: usize) -> &T {
1312        self.entries.get(&idx).unwrap_or(&self.default_)
1313    }
1314    /// Returns the logical length.
1315    pub fn len(&self) -> usize {
1316        self.logical_len
1317    }
1318    /// Returns whether the collection is empty.
1319    pub fn is_empty(&self) -> bool {
1320        self.len() == 0
1321    }
1322    /// Returns the number of non-default elements.
1323    pub fn nnz(&self) -> usize {
1324        self.entries.len()
1325    }
1326}