1use crate::tactic::TacticState;
6use std::collections::{HashMap, VecDeque};
7
8#[derive(Debug, Clone)]
10pub struct ProofStateReport {
11 pub open_goals: usize,
13 pub is_complete: bool,
15}
16impl ProofStateReport {
17 pub fn from_state(state: &TacticState) -> Self {
19 ProofStateReport {
20 open_goals: state.num_goals(),
21 is_complete: state.is_done(),
22 }
23 }
24}
25#[derive(Debug, Clone)]
27pub struct ScoredCandidate<T> {
28 pub candidate: T,
30 pub score: i64,
32}
33impl<T> ScoredCandidate<T> {
34 pub fn new(candidate: T, score: i64) -> Self {
36 Self { candidate, score }
37 }
38}
39#[allow(dead_code)]
40#[derive(Debug, Clone)]
41pub enum LibExtResult1300 {
42 Ok(String),
44 Err(String),
46 Partial { done: usize, total: usize },
48 Skipped,
50}
51impl LibExtResult1300 {
52 #[allow(dead_code)]
53 pub fn is_ok(&self) -> bool {
54 matches!(self, LibExtResult1300::Ok(_))
55 }
56 #[allow(dead_code)]
57 pub fn is_err(&self) -> bool {
58 matches!(self, LibExtResult1300::Err(_))
59 }
60 #[allow(dead_code)]
61 pub fn is_partial(&self) -> bool {
62 matches!(self, LibExtResult1300::Partial { .. })
63 }
64 #[allow(dead_code)]
65 pub fn is_skipped(&self) -> bool {
66 matches!(self, LibExtResult1300::Skipped)
67 }
68 #[allow(dead_code)]
69 pub fn ok_msg(&self) -> Option<&str> {
70 if let LibExtResult1300::Ok(s) = self {
71 Some(s)
72 } else {
73 None
74 }
75 }
76 #[allow(dead_code)]
77 pub fn err_msg(&self) -> Option<&str> {
78 if let LibExtResult1300::Err(s) = self {
79 Some(s)
80 } else {
81 None
82 }
83 }
84 #[allow(dead_code)]
85 pub fn progress(&self) -> f64 {
86 match self {
87 LibExtResult1300::Ok(_) => 1.0,
88 LibExtResult1300::Err(_) => 0.0,
89 LibExtResult1300::Partial { done, total } => {
90 if *total == 0 {
91 0.0
92 } else {
93 *done as f64 / *total as f64
94 }
95 }
96 LibExtResult1300::Skipped => 0.5,
97 }
98 }
99}
100#[allow(dead_code)]
102#[derive(Debug, Clone, PartialEq)]
103pub enum LibResult {
104 Ok(String),
105 Err(String),
106 Partial { done: usize, total: usize },
107 Skipped,
108}
109#[allow(dead_code)]
110impl LibResult {
111 pub fn is_ok(&self) -> bool {
112 matches!(self, LibResult::Ok(_))
113 }
114 pub fn is_err(&self) -> bool {
115 matches!(self, LibResult::Err(_))
116 }
117 pub fn is_partial(&self) -> bool {
118 matches!(self, LibResult::Partial { .. })
119 }
120 pub fn is_skipped(&self) -> bool {
121 matches!(self, LibResult::Skipped)
122 }
123 pub fn ok_msg(&self) -> Option<&str> {
124 match self {
125 LibResult::Ok(s) => Some(s),
126 _ => None,
127 }
128 }
129 pub fn err_msg(&self) -> Option<&str> {
130 match self {
131 LibResult::Err(s) => Some(s),
132 _ => None,
133 }
134 }
135 pub fn progress(&self) -> f64 {
136 match self {
137 LibResult::Ok(_) => 1.0,
138 LibResult::Err(_) => 0.0,
139 LibResult::Skipped => 0.0,
140 LibResult::Partial { done, total } => {
141 if *total == 0 {
142 0.0
143 } else {
144 *done as f64 / *total as f64
145 }
146 }
147 }
148 }
149}
150#[allow(dead_code)]
152pub struct MetaLibBuilder {
153 pub name: String,
154 pub items: Vec<String>,
155 pub config: std::collections::HashMap<String, String>,
156}
157#[allow(dead_code)]
158impl MetaLibBuilder {
159 pub fn new(name: &str) -> Self {
160 MetaLibBuilder {
161 name: name.to_string(),
162 items: Vec::new(),
163 config: std::collections::HashMap::new(),
164 }
165 }
166 pub fn add_item(mut self, item: &str) -> Self {
167 self.items.push(item.to_string());
168 self
169 }
170 pub fn set_config(mut self, key: &str, value: &str) -> Self {
171 self.config.insert(key.to_string(), value.to_string());
172 self
173 }
174 pub fn item_count(&self) -> usize {
175 self.items.len()
176 }
177 pub fn has_config(&self, key: &str) -> bool {
178 self.config.contains_key(key)
179 }
180 pub fn get_config(&self, key: &str) -> Option<&str> {
181 self.config.get(key).map(|s| s.as_str())
182 }
183 pub fn build_summary(&self) -> String {
184 format!(
185 "{}: {} items, {} config keys",
186 self.name,
187 self.items.len(),
188 self.config.len()
189 )
190 }
191}
192#[derive(Debug)]
194pub struct MetaCache<K, V> {
195 pub entries: std::collections::HashMap<K, V>,
196 pub capacity: usize,
197 pub hits: u64,
198 pub misses: u64,
199}
200impl<K: std::hash::Hash + Eq + Clone, V> MetaCache<K, V> {
201 pub fn with_capacity(capacity: usize) -> Self {
203 Self {
204 entries: std::collections::HashMap::with_capacity(capacity),
205 capacity,
206 hits: 0,
207 misses: 0,
208 }
209 }
210 pub fn insert(&mut self, key: K, value: V) {
212 if self.entries.len() >= self.capacity {
213 let len = self.entries.len();
214 if len > 0 {
215 let to_remove = len / 2;
216 let keys: Vec<K> = self.entries.keys().take(to_remove).cloned().collect();
217 for k in keys {
218 self.entries.remove(&k);
219 }
220 }
221 }
222 self.entries.insert(key, value);
223 }
224 pub fn get(&mut self, key: &K) -> Option<&V> {
226 if self.entries.contains_key(key) {
227 self.hits += 1;
228 self.entries.get(key)
229 } else {
230 self.misses += 1;
231 None
232 }
233 }
234 pub fn hit_rate(&self) -> f64 {
236 let total = self.hits + self.misses;
237 if total == 0 {
238 0.0
239 } else {
240 self.hits as f64 / total as f64
241 }
242 }
243 pub fn len(&self) -> usize {
245 self.entries.len()
246 }
247 pub fn is_empty(&self) -> bool {
249 self.entries.is_empty()
250 }
251 pub fn clear(&mut self) {
253 self.entries.clear();
254 self.hits = 0;
255 self.misses = 0;
256 }
257}
258#[allow(dead_code)]
260pub struct LibPipeline {
261 pub passes: Vec<LibAnalysisPass>,
262 pub name: String,
263 pub total_inputs_processed: usize,
264}
265#[allow(dead_code)]
266impl LibPipeline {
267 pub fn new(name: &str) -> Self {
268 LibPipeline {
269 passes: Vec::new(),
270 name: name.to_string(),
271 total_inputs_processed: 0,
272 }
273 }
274 pub fn add_pass(&mut self, pass: LibAnalysisPass) {
275 self.passes.push(pass);
276 }
277 pub fn run_all(&mut self, input: &str) -> Vec<LibResult> {
278 self.total_inputs_processed += 1;
279 self.passes
280 .iter_mut()
281 .filter(|p| p.enabled)
282 .map(|p| p.run(input))
283 .collect()
284 }
285 pub fn num_passes(&self) -> usize {
286 self.passes.len()
287 }
288 pub fn num_enabled_passes(&self) -> usize {
289 self.passes.iter().filter(|p| p.enabled).count()
290 }
291 pub fn total_success_rate(&self) -> f64 {
292 if self.passes.is_empty() {
293 0.0
294 } else {
295 let total_rate: f64 = self.passes.iter().map(|p| p.success_rate()).sum();
296 total_rate / self.passes.len() as f64
297 }
298 }
299}
300#[allow(dead_code)]
301pub struct LibExtDiff1300 {
302 pub added: Vec<String>,
303 pub removed: Vec<String>,
304 pub unchanged: Vec<String>,
305}
306impl LibExtDiff1300 {
307 #[allow(dead_code)]
308 pub fn new() -> Self {
309 Self {
310 added: Vec::new(),
311 removed: Vec::new(),
312 unchanged: Vec::new(),
313 }
314 }
315 #[allow(dead_code)]
316 pub fn add(&mut self, s: &str) {
317 self.added.push(s.to_string());
318 }
319 #[allow(dead_code)]
320 pub fn remove(&mut self, s: &str) {
321 self.removed.push(s.to_string());
322 }
323 #[allow(dead_code)]
324 pub fn keep(&mut self, s: &str) {
325 self.unchanged.push(s.to_string());
326 }
327 #[allow(dead_code)]
328 pub fn is_empty(&self) -> bool {
329 self.added.is_empty() && self.removed.is_empty()
330 }
331 #[allow(dead_code)]
332 pub fn total_changes(&self) -> usize {
333 self.added.len() + self.removed.len()
334 }
335 #[allow(dead_code)]
336 pub fn net_additions(&self) -> i64 {
337 self.added.len() as i64 - self.removed.len() as i64
338 }
339 #[allow(dead_code)]
340 pub fn summary(&self) -> String {
341 format!(
342 "+{} -{} =={}",
343 self.added.len(),
344 self.removed.len(),
345 self.unchanged.len()
346 )
347 }
348}
349#[derive(Clone, Debug)]
351pub struct TacticGroup {
352 pub name: String,
354 pub members: Vec<String>,
356 pub description: String,
358}
359impl TacticGroup {
360 pub fn new(name: &str, description: &str) -> Self {
362 Self {
363 name: name.to_string(),
364 members: Vec::new(),
365 description: description.to_string(),
366 }
367 }
368 #[allow(clippy::should_implement_trait)]
370 pub fn add(mut self, tactic: &str) -> Self {
371 self.members.push(tactic.to_string());
372 self
373 }
374 pub fn contains(&self, tactic: &str) -> bool {
376 self.members.iter().any(|m| m == tactic)
377 }
378}
379#[allow(dead_code)]
381pub struct MetaLibExtMap<V> {
382 pub data: std::collections::HashMap<String, V>,
383 pub default_key: Option<String>,
384}
385#[allow(dead_code)]
386impl<V: Clone + Default> MetaLibExtMap<V> {
387 pub fn new() -> Self {
388 MetaLibExtMap {
389 data: std::collections::HashMap::new(),
390 default_key: None,
391 }
392 }
393 pub fn insert(&mut self, key: &str, value: V) {
394 self.data.insert(key.to_string(), value);
395 }
396 pub fn get(&self, key: &str) -> Option<&V> {
397 self.data.get(key)
398 }
399 pub fn get_or_default(&self, key: &str) -> V {
400 self.data.get(key).cloned().unwrap_or_default()
401 }
402 pub fn contains(&self, key: &str) -> bool {
403 self.data.contains_key(key)
404 }
405 pub fn remove(&mut self, key: &str) -> Option<V> {
406 self.data.remove(key)
407 }
408 pub fn size(&self) -> usize {
409 self.data.len()
410 }
411 pub fn is_empty(&self) -> bool {
412 self.data.is_empty()
413 }
414 pub fn set_default(&mut self, key: &str) {
415 self.default_key = Some(key.to_string());
416 }
417 pub fn keys_sorted(&self) -> Vec<&String> {
418 let mut keys: Vec<&String> = self.data.keys().collect();
419 keys.sort();
420 keys
421 }
422}
423#[allow(dead_code)]
425pub struct MetaLibCounterMap {
426 pub counts: std::collections::HashMap<String, usize>,
427 pub total: usize,
428}
429#[allow(dead_code)]
430impl MetaLibCounterMap {
431 pub fn new() -> Self {
432 MetaLibCounterMap {
433 counts: std::collections::HashMap::new(),
434 total: 0,
435 }
436 }
437 pub fn increment(&mut self, key: &str) {
438 *self.counts.entry(key.to_string()).or_insert(0) += 1;
439 self.total += 1;
440 }
441 pub fn count(&self, key: &str) -> usize {
442 *self.counts.get(key).unwrap_or(&0)
443 }
444 pub fn frequency(&self, key: &str) -> f64 {
445 if self.total == 0 {
446 0.0
447 } else {
448 self.count(key) as f64 / self.total as f64
449 }
450 }
451 pub fn most_common(&self) -> Option<(&String, usize)> {
452 self.counts
453 .iter()
454 .max_by_key(|(_, &v)| v)
455 .map(|(k, &v)| (k, v))
456 }
457 pub fn num_unique(&self) -> usize {
458 self.counts.len()
459 }
460 pub fn is_empty(&self) -> bool {
461 self.counts.is_empty()
462 }
463}
464#[allow(dead_code)]
466pub struct MetaLibWindow {
467 pub buffer: std::collections::VecDeque<f64>,
468 pub capacity: usize,
469 pub running_sum: f64,
470}
471#[allow(dead_code)]
472impl MetaLibWindow {
473 pub fn new(capacity: usize) -> Self {
474 MetaLibWindow {
475 buffer: std::collections::VecDeque::new(),
476 capacity,
477 running_sum: 0.0,
478 }
479 }
480 pub fn push(&mut self, v: f64) {
481 if self.buffer.len() >= self.capacity {
482 if let Some(old) = self.buffer.pop_front() {
483 self.running_sum -= old;
484 }
485 }
486 self.buffer.push_back(v);
487 self.running_sum += v;
488 }
489 pub fn mean(&self) -> f64 {
490 if self.buffer.is_empty() {
491 0.0
492 } else {
493 self.running_sum / self.buffer.len() as f64
494 }
495 }
496 pub fn variance(&self) -> f64 {
497 if self.buffer.len() < 2 {
498 return 0.0;
499 }
500 let m = self.mean();
501 self.buffer.iter().map(|&x| (x - m).powi(2)).sum::<f64>() / self.buffer.len() as f64
502 }
503 pub fn std_dev(&self) -> f64 {
504 self.variance().sqrt()
505 }
506 pub fn len(&self) -> usize {
507 self.buffer.len()
508 }
509 pub fn is_full(&self) -> bool {
510 self.buffer.len() >= self.capacity
511 }
512 pub fn is_empty(&self) -> bool {
513 self.buffer.is_empty()
514 }
515}
516#[allow(dead_code)]
517pub struct LibExtConfig1300 {
518 pub values: std::collections::HashMap<String, LibExtConfigVal1300>,
519 pub read_only: bool,
520 pub name: String,
521}
522impl LibExtConfig1300 {
523 #[allow(dead_code)]
524 pub fn new() -> Self {
525 Self {
526 values: std::collections::HashMap::new(),
527 read_only: false,
528 name: String::new(),
529 }
530 }
531 #[allow(dead_code)]
532 pub fn named(name: &str) -> Self {
533 Self {
534 values: std::collections::HashMap::new(),
535 read_only: false,
536 name: name.to_string(),
537 }
538 }
539 #[allow(dead_code)]
540 pub fn set(&mut self, key: &str, value: LibExtConfigVal1300) -> bool {
541 if self.read_only {
542 return false;
543 }
544 self.values.insert(key.to_string(), value);
545 true
546 }
547 #[allow(dead_code)]
548 pub fn get(&self, key: &str) -> Option<&LibExtConfigVal1300> {
549 self.values.get(key)
550 }
551 #[allow(dead_code)]
552 pub fn get_bool(&self, key: &str) -> Option<bool> {
553 self.get(key)?.as_bool()
554 }
555 #[allow(dead_code)]
556 pub fn get_int(&self, key: &str) -> Option<i64> {
557 self.get(key)?.as_int()
558 }
559 #[allow(dead_code)]
560 pub fn get_str(&self, key: &str) -> Option<&str> {
561 self.get(key)?.as_str()
562 }
563 #[allow(dead_code)]
564 pub fn set_bool(&mut self, key: &str, v: bool) -> bool {
565 self.set(key, LibExtConfigVal1300::Bool(v))
566 }
567 #[allow(dead_code)]
568 pub fn set_int(&mut self, key: &str, v: i64) -> bool {
569 self.set(key, LibExtConfigVal1300::Int(v))
570 }
571 #[allow(dead_code)]
572 pub fn set_str(&mut self, key: &str, v: &str) -> bool {
573 self.set(key, LibExtConfigVal1300::Str(v.to_string()))
574 }
575 #[allow(dead_code)]
576 pub fn lock(&mut self) {
577 self.read_only = true;
578 }
579 #[allow(dead_code)]
580 pub fn unlock(&mut self) {
581 self.read_only = false;
582 }
583 #[allow(dead_code)]
584 pub fn size(&self) -> usize {
585 self.values.len()
586 }
587 #[allow(dead_code)]
588 pub fn has(&self, key: &str) -> bool {
589 self.values.contains_key(key)
590 }
591 #[allow(dead_code)]
592 pub fn remove(&mut self, key: &str) -> bool {
593 self.values.remove(key).is_some()
594 }
595}
596#[allow(dead_code)]
598pub struct MetaLibWorkQueue {
599 pub pending: std::collections::VecDeque<String>,
600 pub processed: Vec<String>,
601 pub capacity: usize,
602}
603#[allow(dead_code)]
604impl MetaLibWorkQueue {
605 pub fn new(capacity: usize) -> Self {
606 MetaLibWorkQueue {
607 pending: std::collections::VecDeque::new(),
608 processed: Vec::new(),
609 capacity,
610 }
611 }
612 pub fn enqueue(&mut self, item: String) -> bool {
613 if self.pending.len() >= self.capacity {
614 return false;
615 }
616 self.pending.push_back(item);
617 true
618 }
619 pub fn dequeue(&mut self) -> Option<String> {
620 let item = self.pending.pop_front()?;
621 self.processed.push(item.clone());
622 Some(item)
623 }
624 pub fn pending_count(&self) -> usize {
625 self.pending.len()
626 }
627 pub fn processed_count(&self) -> usize {
628 self.processed.len()
629 }
630 pub fn is_empty(&self) -> bool {
631 self.pending.is_empty()
632 }
633 pub fn is_full(&self) -> bool {
634 self.pending.len() >= self.capacity
635 }
636 pub fn total_processed(&self) -> usize {
637 self.processed.len()
638 }
639}
640#[allow(dead_code)]
641#[derive(Debug, Clone)]
642pub enum LibExtConfigVal1300 {
643 Bool(bool),
644 Int(i64),
645 Float(f64),
646 Str(String),
647 List(Vec<String>),
648}
649impl LibExtConfigVal1300 {
650 #[allow(dead_code)]
651 pub fn as_bool(&self) -> Option<bool> {
652 if let LibExtConfigVal1300::Bool(b) = self {
653 Some(*b)
654 } else {
655 None
656 }
657 }
658 #[allow(dead_code)]
659 pub fn as_int(&self) -> Option<i64> {
660 if let LibExtConfigVal1300::Int(i) = self {
661 Some(*i)
662 } else {
663 None
664 }
665 }
666 #[allow(dead_code)]
667 pub fn as_float(&self) -> Option<f64> {
668 if let LibExtConfigVal1300::Float(f) = self {
669 Some(*f)
670 } else {
671 None
672 }
673 }
674 #[allow(dead_code)]
675 pub fn as_str(&self) -> Option<&str> {
676 if let LibExtConfigVal1300::Str(s) = self {
677 Some(s)
678 } else {
679 None
680 }
681 }
682 #[allow(dead_code)]
683 pub fn as_list(&self) -> Option<&[String]> {
684 if let LibExtConfigVal1300::List(l) = self {
685 Some(l)
686 } else {
687 None
688 }
689 }
690 #[allow(dead_code)]
691 pub fn type_name(&self) -> &'static str {
692 match self {
693 LibExtConfigVal1300::Bool(_) => "bool",
694 LibExtConfigVal1300::Int(_) => "int",
695 LibExtConfigVal1300::Float(_) => "float",
696 LibExtConfigVal1300::Str(_) => "str",
697 LibExtConfigVal1300::List(_) => "list",
698 }
699 }
700}
701#[allow(dead_code)]
703#[derive(Debug, Clone)]
704pub enum LibConfigValue {
705 Bool(bool),
706 Int(i64),
707 Float(f64),
708 Str(String),
709 List(Vec<String>),
710}
711#[allow(dead_code)]
712impl LibConfigValue {
713 pub fn as_bool(&self) -> Option<bool> {
714 match self {
715 LibConfigValue::Bool(b) => Some(*b),
716 _ => None,
717 }
718 }
719 pub fn as_int(&self) -> Option<i64> {
720 match self {
721 LibConfigValue::Int(i) => Some(*i),
722 _ => None,
723 }
724 }
725 pub fn as_float(&self) -> Option<f64> {
726 match self {
727 LibConfigValue::Float(f) => Some(*f),
728 _ => None,
729 }
730 }
731 pub fn as_str(&self) -> Option<&str> {
732 match self {
733 LibConfigValue::Str(s) => Some(s),
734 _ => None,
735 }
736 }
737 pub fn as_list(&self) -> Option<&[String]> {
738 match self {
739 LibConfigValue::List(v) => Some(v),
740 _ => None,
741 }
742 }
743 pub fn type_name(&self) -> &'static str {
744 match self {
745 LibConfigValue::Bool(_) => "bool",
746 LibConfigValue::Int(_) => "int",
747 LibConfigValue::Float(_) => "float",
748 LibConfigValue::Str(_) => "str",
749 LibConfigValue::List(_) => "list",
750 }
751 }
752}
753#[allow(dead_code)]
755#[derive(Debug, Clone, Default)]
756pub struct MetaLibExtUtil {
757 pub key: String,
758 pub data: Vec<i64>,
759 pub active: bool,
760 pub flags: u32,
761}
762#[allow(dead_code)]
763impl MetaLibExtUtil {
764 pub fn new(key: &str) -> Self {
765 MetaLibExtUtil {
766 key: key.to_string(),
767 data: Vec::new(),
768 active: true,
769 flags: 0,
770 }
771 }
772 pub fn push(&mut self, v: i64) {
773 self.data.push(v);
774 }
775 pub fn pop(&mut self) -> Option<i64> {
776 self.data.pop()
777 }
778 pub fn sum(&self) -> i64 {
779 self.data.iter().sum()
780 }
781 pub fn min_val(&self) -> Option<i64> {
782 self.data.iter().copied().reduce(i64::min)
783 }
784 pub fn max_val(&self) -> Option<i64> {
785 self.data.iter().copied().reduce(i64::max)
786 }
787 pub fn len(&self) -> usize {
788 self.data.len()
789 }
790 pub fn is_empty(&self) -> bool {
791 self.data.is_empty()
792 }
793 pub fn clear(&mut self) {
794 self.data.clear();
795 }
796 pub fn set_flag(&mut self, bit: u32) {
797 self.flags |= 1 << bit;
798 }
799 pub fn has_flag(&self, bit: u32) -> bool {
800 self.flags & (1 << bit) != 0
801 }
802 pub fn deactivate(&mut self) {
803 self.active = false;
804 }
805 pub fn activate(&mut self) {
806 self.active = true;
807 }
808}
809#[derive(Debug, Clone, Default)]
811pub struct MetaStats {
812 pub num_expr_mvars: usize,
814 pub num_assigned_expr: usize,
816 pub num_level_mvars: usize,
818 pub num_assigned_levels: usize,
820 pub num_postponed: usize,
822}
823#[allow(dead_code)]
825pub struct LibAnalysisPass {
826 pub name: String,
827 pub enabled: bool,
828 pub results: Vec<LibResult>,
829 pub total_runs: usize,
830}
831#[allow(dead_code)]
832impl LibAnalysisPass {
833 pub fn new(name: &str) -> Self {
834 LibAnalysisPass {
835 name: name.to_string(),
836 enabled: true,
837 results: Vec::new(),
838 total_runs: 0,
839 }
840 }
841 pub fn run(&mut self, input: &str) -> LibResult {
842 self.total_runs += 1;
843 let result = if input.is_empty() {
844 LibResult::Err("empty input".to_string())
845 } else {
846 LibResult::Ok(format!("processed: {}", input))
847 };
848 self.results.push(result.clone());
849 result
850 }
851 pub fn success_count(&self) -> usize {
852 self.results.iter().filter(|r| r.is_ok()).count()
853 }
854 pub fn error_count(&self) -> usize {
855 self.results.iter().filter(|r| r.is_err()).count()
856 }
857 pub fn success_rate(&self) -> f64 {
858 if self.total_runs == 0 {
859 0.0
860 } else {
861 self.success_count() as f64 / self.total_runs as f64
862 }
863 }
864 pub fn disable(&mut self) {
865 self.enabled = false;
866 }
867 pub fn enable(&mut self) {
868 self.enabled = true;
869 }
870 pub fn clear_results(&mut self) {
871 self.results.clear();
872 }
873}
874#[allow(dead_code)]
876pub struct PerfStats {
877 pub elab_attempts: u64,
879 pub elab_successes: u64,
881 pub unif_attempts: u64,
883 pub unif_successes: u64,
885 pub elapsed_us: u64,
887}
888#[allow(dead_code)]
889impl PerfStats {
890 pub fn new() -> Self {
892 PerfStats {
893 elab_attempts: 0,
894 elab_successes: 0,
895 unif_attempts: 0,
896 unif_successes: 0,
897 elapsed_us: 0,
898 }
899 }
900 pub fn elab_success_rate(&self) -> f64 {
902 if self.elab_attempts == 0 {
903 return 0.0;
904 }
905 self.elab_successes as f64 / self.elab_attempts as f64
906 }
907 pub fn unif_success_rate(&self) -> f64 {
909 if self.unif_attempts == 0 {
910 return 0.0;
911 }
912 self.unif_successes as f64 / self.unif_attempts as f64
913 }
914 pub fn merge(&mut self, other: &PerfStats) {
916 self.elab_attempts += other.elab_attempts;
917 self.elab_successes += other.elab_successes;
918 self.unif_attempts += other.unif_attempts;
919 self.unif_successes += other.unif_successes;
920 self.elapsed_us += other.elapsed_us;
921 }
922}
923impl Default for PerfStats {
924 fn default() -> Self {
925 Self::new()
926 }
927}
928#[derive(Debug, Default)]
930pub struct TacticRegistry {
931 pub entries: std::collections::HashMap<String, usize>,
932 pub names: Vec<String>,
933}
934impl TacticRegistry {
935 pub fn new() -> Self {
937 Self::default()
938 }
939 pub fn register(&mut self, name: impl Into<String>) -> usize {
941 let name = name.into();
942 if let Some(&idx) = self.entries.get(&name) {
943 return idx;
944 }
945 let idx = self.names.len();
946 self.entries.insert(name.clone(), idx);
947 self.names.push(name);
948 idx
949 }
950 pub fn lookup(&self, name: &str) -> Option<usize> {
952 self.entries.get(name).copied()
953 }
954 pub fn name_of(&self, idx: usize) -> Option<&str> {
956 self.names.get(idx).map(String::as_str)
957 }
958 pub fn len(&self) -> usize {
960 self.names.len()
961 }
962 pub fn is_empty(&self) -> bool {
964 self.names.is_empty()
965 }
966 pub fn all_names(&self) -> &[String] {
968 &self.names
969 }
970}
971#[allow(dead_code)]
973#[derive(Debug, Clone, PartialEq)]
974pub enum MetaLibState {
975 Initial,
976 Running,
977 Paused,
978 Complete,
979 Failed(String),
980}
981#[allow(dead_code)]
982impl MetaLibState {
983 pub fn is_terminal(&self) -> bool {
984 matches!(self, MetaLibState::Complete | MetaLibState::Failed(_))
985 }
986 pub fn can_run(&self) -> bool {
987 matches!(self, MetaLibState::Initial | MetaLibState::Paused)
988 }
989 pub fn is_running(&self) -> bool {
990 matches!(self, MetaLibState::Running)
991 }
992 pub fn error_msg(&self) -> Option<&str> {
993 match self {
994 MetaLibState::Failed(s) => Some(s),
995 _ => None,
996 }
997 }
998}
999#[allow(dead_code)]
1001#[derive(Debug, Clone)]
1002pub struct LibDiff {
1003 pub added: Vec<String>,
1004 pub removed: Vec<String>,
1005 pub unchanged: Vec<String>,
1006}
1007#[allow(dead_code)]
1008impl LibDiff {
1009 pub fn new() -> Self {
1010 LibDiff {
1011 added: Vec::new(),
1012 removed: Vec::new(),
1013 unchanged: Vec::new(),
1014 }
1015 }
1016 pub fn add(&mut self, s: &str) {
1017 self.added.push(s.to_string());
1018 }
1019 pub fn remove(&mut self, s: &str) {
1020 self.removed.push(s.to_string());
1021 }
1022 pub fn keep(&mut self, s: &str) {
1023 self.unchanged.push(s.to_string());
1024 }
1025 pub fn is_empty(&self) -> bool {
1026 self.added.is_empty() && self.removed.is_empty()
1027 }
1028 pub fn total_changes(&self) -> usize {
1029 self.added.len() + self.removed.len()
1030 }
1031 pub fn net_additions(&self) -> i64 {
1032 self.added.len() as i64 - self.removed.len() as i64
1033 }
1034 pub fn summary(&self) -> String {
1035 format!(
1036 "+{} -{} =={}",
1037 self.added.len(),
1038 self.removed.len(),
1039 self.unchanged.len()
1040 )
1041 }
1042}
1043#[allow(dead_code)]
1045pub struct LibConfig {
1046 pub values: std::collections::HashMap<String, LibConfigValue>,
1047 pub read_only: bool,
1048}
1049#[allow(dead_code)]
1050impl LibConfig {
1051 pub fn new() -> Self {
1052 LibConfig {
1053 values: std::collections::HashMap::new(),
1054 read_only: false,
1055 }
1056 }
1057 pub fn set(&mut self, key: &str, value: LibConfigValue) -> bool {
1058 if self.read_only {
1059 return false;
1060 }
1061 self.values.insert(key.to_string(), value);
1062 true
1063 }
1064 pub fn get(&self, key: &str) -> Option<&LibConfigValue> {
1065 self.values.get(key)
1066 }
1067 pub fn get_bool(&self, key: &str) -> Option<bool> {
1068 self.get(key)?.as_bool()
1069 }
1070 pub fn get_int(&self, key: &str) -> Option<i64> {
1071 self.get(key)?.as_int()
1072 }
1073 pub fn get_str(&self, key: &str) -> Option<&str> {
1074 self.get(key)?.as_str()
1075 }
1076 pub fn set_bool(&mut self, key: &str, v: bool) -> bool {
1077 self.set(key, LibConfigValue::Bool(v))
1078 }
1079 pub fn set_int(&mut self, key: &str, v: i64) -> bool {
1080 self.set(key, LibConfigValue::Int(v))
1081 }
1082 pub fn set_str(&mut self, key: &str, v: &str) -> bool {
1083 self.set(key, LibConfigValue::Str(v.to_string()))
1084 }
1085 pub fn lock(&mut self) {
1086 self.read_only = true;
1087 }
1088 pub fn unlock(&mut self) {
1089 self.read_only = false;
1090 }
1091 pub fn size(&self) -> usize {
1092 self.values.len()
1093 }
1094 pub fn has(&self, key: &str) -> bool {
1095 self.values.contains_key(key)
1096 }
1097 pub fn remove(&mut self, key: &str) -> bool {
1098 self.values.remove(key).is_some()
1099 }
1100}
1101#[allow(dead_code)]
1102pub struct LibExtPass1300 {
1103 pub name: String,
1104 pub total_runs: usize,
1105 pub successes: usize,
1106 pub errors: usize,
1107 pub enabled: bool,
1108 pub results: Vec<LibExtResult1300>,
1109}
1110impl LibExtPass1300 {
1111 #[allow(dead_code)]
1112 pub fn new(name: &str) -> Self {
1113 Self {
1114 name: name.to_string(),
1115 total_runs: 0,
1116 successes: 0,
1117 errors: 0,
1118 enabled: true,
1119 results: Vec::new(),
1120 }
1121 }
1122 #[allow(dead_code)]
1123 pub fn run(&mut self, input: &str) -> LibExtResult1300 {
1124 if !self.enabled {
1125 return LibExtResult1300::Skipped;
1126 }
1127 self.total_runs += 1;
1128 let result = if input.is_empty() {
1129 self.errors += 1;
1130 LibExtResult1300::Err(format!("empty input in pass '{}'", self.name))
1131 } else {
1132 self.successes += 1;
1133 LibExtResult1300::Ok(format!(
1134 "processed {} chars in pass '{}'",
1135 input.len(),
1136 self.name
1137 ))
1138 };
1139 self.results.push(result.clone());
1140 result
1141 }
1142 #[allow(dead_code)]
1143 pub fn success_count(&self) -> usize {
1144 self.successes
1145 }
1146 #[allow(dead_code)]
1147 pub fn error_count(&self) -> usize {
1148 self.errors
1149 }
1150 #[allow(dead_code)]
1151 pub fn success_rate(&self) -> f64 {
1152 if self.total_runs == 0 {
1153 0.0
1154 } else {
1155 self.successes as f64 / self.total_runs as f64
1156 }
1157 }
1158 #[allow(dead_code)]
1159 pub fn disable(&mut self) {
1160 self.enabled = false;
1161 }
1162 #[allow(dead_code)]
1163 pub fn enable(&mut self) {
1164 self.enabled = true;
1165 }
1166 #[allow(dead_code)]
1167 pub fn clear_results(&mut self) {
1168 self.results.clear();
1169 }
1170}
1171#[allow(dead_code)]
1172pub struct LibExtPipeline1300 {
1173 pub name: String,
1174 pub passes: Vec<LibExtPass1300>,
1175 pub run_count: usize,
1176}
1177impl LibExtPipeline1300 {
1178 #[allow(dead_code)]
1179 pub fn new(name: &str) -> Self {
1180 Self {
1181 name: name.to_string(),
1182 passes: Vec::new(),
1183 run_count: 0,
1184 }
1185 }
1186 #[allow(dead_code)]
1187 pub fn add_pass(&mut self, pass: LibExtPass1300) {
1188 self.passes.push(pass);
1189 }
1190 #[allow(dead_code)]
1191 pub fn run_all(&mut self, input: &str) -> Vec<LibExtResult1300> {
1192 self.run_count += 1;
1193 self.passes
1194 .iter_mut()
1195 .filter(|p| p.enabled)
1196 .map(|p| p.run(input))
1197 .collect()
1198 }
1199 #[allow(dead_code)]
1200 pub fn num_passes(&self) -> usize {
1201 self.passes.len()
1202 }
1203 #[allow(dead_code)]
1204 pub fn num_enabled_passes(&self) -> usize {
1205 self.passes.iter().filter(|p| p.enabled).count()
1206 }
1207 #[allow(dead_code)]
1208 pub fn total_success_rate(&self) -> f64 {
1209 let total: usize = self.passes.iter().map(|p| p.total_runs).sum();
1210 let ok: usize = self.passes.iter().map(|p| p.successes).sum();
1211 if total == 0 {
1212 0.0
1213 } else {
1214 ok as f64 / total as f64
1215 }
1216 }
1217}
1218#[derive(Clone, Debug)]
1220pub struct MetaFeatures {
1221 pub discr_tree: bool,
1223 pub whnf_cache: bool,
1225 pub proof_recording: bool,
1227 pub instance_synth: bool,
1229 pub congr_lemmas: bool,
1231}
1232impl MetaFeatures {
1233 pub fn all_enabled() -> Self {
1235 Self {
1236 discr_tree: true,
1237 whnf_cache: true,
1238 proof_recording: true,
1239 instance_synth: true,
1240 congr_lemmas: true,
1241 }
1242 }
1243 pub fn minimal() -> Self {
1245 Self {
1246 discr_tree: false,
1247 whnf_cache: false,
1248 proof_recording: false,
1249 instance_synth: false,
1250 congr_lemmas: false,
1251 }
1252 }
1253 pub fn any_caching(&self) -> bool {
1255 self.whnf_cache || self.proof_recording
1256 }
1257}
1258impl Default for MetaFeatures {
1259 fn default() -> Self {
1260 Self {
1261 discr_tree: true,
1262 whnf_cache: true,
1263 proof_recording: false,
1264 instance_synth: true,
1265 congr_lemmas: true,
1266 }
1267 }
1268}
1269#[allow(dead_code)]
1271pub struct LibDiagnostics {
1272 pub errors: Vec<String>,
1273 pub warnings: Vec<String>,
1274 pub notes: Vec<String>,
1275 pub max_errors: usize,
1276}
1277#[allow(dead_code)]
1278impl LibDiagnostics {
1279 pub fn new(max_errors: usize) -> Self {
1280 LibDiagnostics {
1281 errors: Vec::new(),
1282 warnings: Vec::new(),
1283 notes: Vec::new(),
1284 max_errors,
1285 }
1286 }
1287 pub fn error(&mut self, msg: &str) {
1288 if self.errors.len() < self.max_errors {
1289 self.errors.push(msg.to_string());
1290 }
1291 }
1292 pub fn warning(&mut self, msg: &str) {
1293 self.warnings.push(msg.to_string());
1294 }
1295 pub fn note(&mut self, msg: &str) {
1296 self.notes.push(msg.to_string());
1297 }
1298 pub fn has_errors(&self) -> bool {
1299 !self.errors.is_empty()
1300 }
1301 pub fn num_errors(&self) -> usize {
1302 self.errors.len()
1303 }
1304 pub fn num_warnings(&self) -> usize {
1305 self.warnings.len()
1306 }
1307 pub fn is_clean(&self) -> bool {
1308 self.errors.is_empty() && self.warnings.is_empty()
1309 }
1310 pub fn at_error_limit(&self) -> bool {
1311 self.errors.len() >= self.max_errors
1312 }
1313 pub fn clear(&mut self) {
1314 self.errors.clear();
1315 self.warnings.clear();
1316 self.notes.clear();
1317 }
1318 pub fn summary(&self) -> String {
1319 format!(
1320 "{} error(s), {} warning(s)",
1321 self.errors.len(),
1322 self.warnings.len()
1323 )
1324 }
1325}
1326#[allow(dead_code)]
1327pub struct LibExtDiag1300 {
1328 pub errors: Vec<String>,
1329 pub warnings: Vec<String>,
1330 pub notes: Vec<String>,
1331 pub max_errors: usize,
1332}
1333impl LibExtDiag1300 {
1334 #[allow(dead_code)]
1335 pub fn new(max_errors: usize) -> Self {
1336 Self {
1337 errors: Vec::new(),
1338 warnings: Vec::new(),
1339 notes: Vec::new(),
1340 max_errors,
1341 }
1342 }
1343 #[allow(dead_code)]
1344 pub fn error(&mut self, msg: &str) {
1345 if self.errors.len() < self.max_errors {
1346 self.errors.push(msg.to_string());
1347 }
1348 }
1349 #[allow(dead_code)]
1350 pub fn warning(&mut self, msg: &str) {
1351 self.warnings.push(msg.to_string());
1352 }
1353 #[allow(dead_code)]
1354 pub fn note(&mut self, msg: &str) {
1355 self.notes.push(msg.to_string());
1356 }
1357 #[allow(dead_code)]
1358 pub fn has_errors(&self) -> bool {
1359 !self.errors.is_empty()
1360 }
1361 #[allow(dead_code)]
1362 pub fn num_errors(&self) -> usize {
1363 self.errors.len()
1364 }
1365 #[allow(dead_code)]
1366 pub fn num_warnings(&self) -> usize {
1367 self.warnings.len()
1368 }
1369 #[allow(dead_code)]
1370 pub fn is_clean(&self) -> bool {
1371 self.errors.is_empty() && self.warnings.is_empty()
1372 }
1373 #[allow(dead_code)]
1374 pub fn at_error_limit(&self) -> bool {
1375 self.errors.len() >= self.max_errors
1376 }
1377 #[allow(dead_code)]
1378 pub fn clear(&mut self) {
1379 self.errors.clear();
1380 self.warnings.clear();
1381 self.notes.clear();
1382 }
1383 #[allow(dead_code)]
1384 pub fn summary(&self) -> String {
1385 format!(
1386 "{} error(s), {} warning(s)",
1387 self.errors.len(),
1388 self.warnings.len()
1389 )
1390 }
1391}
1392#[allow(dead_code)]
1394pub struct MetaLibStateMachine {
1395 pub state: MetaLibState,
1396 pub transitions: usize,
1397 pub history: Vec<String>,
1398}
1399#[allow(dead_code)]
1400impl MetaLibStateMachine {
1401 pub fn new() -> Self {
1402 MetaLibStateMachine {
1403 state: MetaLibState::Initial,
1404 transitions: 0,
1405 history: Vec::new(),
1406 }
1407 }
1408 pub fn transition_to(&mut self, new_state: MetaLibState) -> bool {
1409 if self.state.is_terminal() {
1410 return false;
1411 }
1412 let desc = format!("{:?} -> {:?}", self.state, new_state);
1413 self.state = new_state;
1414 self.transitions += 1;
1415 self.history.push(desc);
1416 true
1417 }
1418 pub fn start(&mut self) -> bool {
1419 self.transition_to(MetaLibState::Running)
1420 }
1421 pub fn pause(&mut self) -> bool {
1422 self.transition_to(MetaLibState::Paused)
1423 }
1424 pub fn complete(&mut self) -> bool {
1425 self.transition_to(MetaLibState::Complete)
1426 }
1427 pub fn fail(&mut self, msg: &str) -> bool {
1428 self.transition_to(MetaLibState::Failed(msg.to_string()))
1429 }
1430 pub fn num_transitions(&self) -> usize {
1431 self.transitions
1432 }
1433}
1434
1435impl Default for LibExtDiff1300 {
1438 fn default() -> Self {
1439 Self::new()
1440 }
1441}
1442
1443impl<V: Clone + Default> Default for MetaLibExtMap<V> {
1444 fn default() -> Self {
1445 Self::new()
1446 }
1447}
1448
1449impl Default for MetaLibCounterMap {
1450 fn default() -> Self {
1451 Self::new()
1452 }
1453}
1454
1455impl Default for LibExtConfig1300 {
1456 fn default() -> Self {
1457 Self::new()
1458 }
1459}
1460
1461impl Default for LibDiff {
1462 fn default() -> Self {
1463 Self::new()
1464 }
1465}
1466
1467impl Default for LibConfig {
1468 fn default() -> Self {
1469 Self::new()
1470 }
1471}
1472
1473impl Default for MetaLibStateMachine {
1474 fn default() -> Self {
1475 Self::new()
1476 }
1477}