1use super::functions::*;
6use oxilean_kernel::{BinderInfo, Declaration, Environment, Expr, Level, Name};
7
8#[allow(dead_code)]
9#[derive(Debug, Clone)]
10pub struct DialecticaInterp {
11 pub formula: String,
12 pub witness_type: String,
13 pub counterexample_type: String,
14 pub is_godel_dialectica: bool,
15}
16#[allow(dead_code)]
17impl DialecticaInterp {
18 pub fn new(formula: &str, witness: &str, counter: &str) -> Self {
19 DialecticaInterp {
20 formula: formula.to_string(),
21 witness_type: witness.to_string(),
22 counterexample_type: counter.to_string(),
23 is_godel_dialectica: true,
24 }
25 }
26 pub fn godel_t_translation(&self) -> String {
27 format!(
28 "Dialectica: '{}' → ∃{}.∀{}.A({}, {})",
29 self.formula,
30 self.witness_type,
31 self.counterexample_type,
32 self.witness_type,
33 self.counterexample_type
34 )
35 }
36 pub fn modified_realizability(&self) -> String {
37 format!(
38 "Modified realizability of '{}': witness type = {}",
39 self.formula, self.witness_type
40 )
41 }
42 pub fn soundness_theorem(&self) -> String {
43 "Dialectica interpretation is sound for Heyting arithmetic + AC_qf + IPP".to_string()
44 }
45 pub fn is_sound_for_classical(&self) -> bool {
46 true
47 }
48}
49#[allow(dead_code)]
51#[derive(Debug, Clone)]
52pub struct GodelInterpretation {
53 pub theorem: String,
54 pub functional_type: String,
55 pub realizing_term: String,
56}
57impl GodelInterpretation {
58 #[allow(dead_code)]
59 pub fn new(thm: &str, ftype: &str, term: &str) -> Self {
60 Self {
61 theorem: thm.to_string(),
62 functional_type: ftype.to_string(),
63 realizing_term: term.to_string(),
64 }
65 }
66 #[allow(dead_code)]
67 pub fn soundness_statement(&self) -> String {
68 format!("If HA proves A, then T proves A^D where A^D is the Dialectica interpretation",)
69 }
70}
71#[derive(Debug, Clone)]
73pub struct EmptyClause;
74impl EmptyClause {
75 pub fn as_clause() -> Clause {
77 Clause::empty()
78 }
79}
80#[derive(Debug, Clone)]
82pub struct CurryHoward {
83 pub proposition: String,
85 pub corresponding_type: String,
87}
88impl CurryHoward {
89 pub fn new(proposition: impl Into<String>, corresponding_type: impl Into<String>) -> Self {
91 Self {
92 proposition: proposition.into(),
93 corresponding_type: corresponding_type.into(),
94 }
95 }
96 pub fn describe(&self) -> String {
98 format!(
99 "Prop: {} <-> Type: {}",
100 self.proposition, self.corresponding_type
101 )
102 }
103}
104#[derive(Debug, Clone)]
106pub struct MajorizabilityChecker {
107 pub f_values: Vec<u64>,
109 pub g_values: Vec<u64>,
111}
112impl MajorizabilityChecker {
113 pub fn new(f_values: Vec<u64>, g_values: Vec<u64>) -> Self {
115 Self { f_values, g_values }
116 }
117 pub fn howard_majorizes(&self) -> bool {
119 self.f_values
120 .iter()
121 .zip(self.g_values.iter())
122 .all(|(&fv, &gv)| gv <= fv)
123 }
124 pub fn bezem_majorizes(&self) -> bool {
127 let n = self.f_values.len().min(self.g_values.len());
128 for outer in 0..n {
129 for inner in 0..=outer {
130 if inner < self.g_values.len() && outer < self.f_values.len() {
131 if self.g_values[inner] > self.f_values[outer] {
132 return false;
133 }
134 }
135 }
136 }
137 true
138 }
139 pub fn pointwise_max(&self) -> Vec<u64> {
141 let n = self.f_values.len().max(self.g_values.len());
142 (0..n)
143 .map(|i| {
144 let fv = self.f_values.get(i).copied().unwrap_or(0);
145 let gv = self.g_values.get(i).copied().unwrap_or(0);
146 fv.max(gv)
147 })
148 .collect()
149 }
150}
151#[derive(Debug, Clone)]
153pub struct RealizabilityInterpretation {
154 pub variant: String,
156 pub formula: RealizedFormula,
158 pub is_constructive: bool,
160}
161impl RealizabilityInterpretation {
162 pub fn kleene(formula: RealizedFormula) -> Self {
164 Self {
165 variant: "kleene".into(),
166 formula,
167 is_constructive: true,
168 }
169 }
170 pub fn kreisel(formula: RealizedFormula) -> Self {
172 Self {
173 variant: "kreisel".into(),
174 formula,
175 is_constructive: true,
176 }
177 }
178}
179#[allow(dead_code)]
180#[derive(Debug, Clone)]
181pub struct ProverData {
182 pub prover_name: String,
183 pub logic: String,
184 pub is_complete: bool,
185 pub is_sound: bool,
186 pub search_strategy: SearchStrategyNew,
187}
188#[allow(dead_code)]
189impl ProverData {
190 pub fn resolution_prover() -> Self {
191 ProverData {
192 prover_name: "Resolution Prover".to_string(),
193 logic: "Classical Propositional Logic".to_string(),
194 is_complete: true,
195 is_sound: true,
196 search_strategy: SearchStrategyNew::Saturation,
197 }
198 }
199 pub fn tableau_prover() -> Self {
200 ProverData {
201 prover_name: "Tableau Prover".to_string(),
202 logic: "Classical First-Order Logic".to_string(),
203 is_complete: true,
204 is_sound: true,
205 search_strategy: SearchStrategyNew::DepthFirst,
206 }
207 }
208 pub fn new_heuristic(name: &str, logic: &str, hint: &str) -> Self {
209 ProverData {
210 prover_name: name.to_string(),
211 logic: logic.to_string(),
212 is_complete: false,
213 is_sound: true,
214 search_strategy: SearchStrategyNew::Heuristic(hint.to_string()),
215 }
216 }
217 pub fn completeness_theorem(&self) -> String {
218 if self.is_complete {
219 format!(
220 "{}: complete for {} (every valid formula is provable)",
221 self.prover_name, self.logic
222 )
223 } else {
224 format!("{}: incomplete (heuristic only)", self.prover_name)
225 }
226 }
227 pub fn superposition_calculus_description(&self) -> String {
228 "Superposition: complete for equational logic, used in E, Vampire, SPASS".to_string()
229 }
230}
231#[derive(Debug, Clone)]
233pub struct ResolutionRefutation {
234 pub clauses: Vec<Clause>,
236 pub steps: Vec<ResolutionStep>,
238}
239impl ResolutionRefutation {
240 pub fn new(clauses: Vec<Clause>) -> Self {
242 Self {
243 clauses,
244 steps: Vec::new(),
245 }
246 }
247 pub fn add_step(&mut self, step: ResolutionStep) {
249 self.steps.push(step);
250 }
251 pub fn is_complete(&self) -> bool {
253 self.steps
254 .last()
255 .is_some_and(|s| s.resolvent.is_empty_clause())
256 }
257 pub fn unit_propagate(&self) -> Vec<Literal> {
259 let mut forced: Vec<Literal> = Vec::new();
260 for clause in &self.clauses {
261 if clause.is_unit() {
262 if let Some(lit) = clause.literals.first() {
263 if !forced.contains(lit) {
264 forced.push(lit.clone());
265 }
266 }
267 }
268 }
269 forced
270 }
271 pub fn dpll_step(&self) -> Option<u32> {
273 for clause in &self.clauses {
274 if let Some(lit) = clause.literals.first() {
275 return Some(lit.var);
276 }
277 }
278 None
279 }
280}
281#[derive(Debug, Clone)]
283pub struct FunctionalInterpretation {
284 pub formula: DialecticaFormula,
286 pub functional_description: String,
288}
289impl FunctionalInterpretation {
290 pub fn new(formula: DialecticaFormula, functional_description: impl Into<String>) -> Self {
292 Self {
293 formula,
294 functional_description: functional_description.into(),
295 }
296 }
297}
298#[derive(Debug, Clone)]
300pub struct WeakKoenigsLemma {
301 pub statement: String,
303 pub dialectica_form: Option<DialecticaFormula>,
305}
306impl WeakKoenigsLemma {
307 pub fn standard() -> Self {
309 Self {
310 statement: "Every infinite binary tree has an infinite path.".into(),
311 dialectica_form: None,
312 }
313 }
314 pub fn has_dialectica_form(&self) -> bool {
316 self.dialectica_form.is_some()
317 }
318}
319#[allow(dead_code)]
321#[derive(Debug, Clone)]
322pub struct RamseyBound {
323 pub name: String,
324 pub lower_bound: u64,
325 pub upper_bound: Option<u64>,
326 pub proof_system: String,
327}
328impl RamseyBound {
329 #[allow(dead_code)]
330 pub fn r33() -> Self {
331 Self {
332 name: "R(3,3)".to_string(),
333 lower_bound: 6,
334 upper_bound: Some(6),
335 proof_system: "Elementary combinatorics".to_string(),
336 }
337 }
338 #[allow(dead_code)]
339 pub fn r44() -> Self {
340 Self {
341 name: "R(4,4)".to_string(),
342 lower_bound: 18,
343 upper_bound: Some(18),
344 proof_system: "Computer search + proof".to_string(),
345 }
346 }
347 #[allow(dead_code)]
348 pub fn is_exact(&self) -> bool {
349 self.upper_bound
350 .map(|u| u == self.lower_bound)
351 .unwrap_or(false)
352 }
353}
354#[allow(dead_code)]
356#[derive(Debug, Clone)]
357pub struct Finitization {
358 pub infinite_principle: String,
359 pub finite_version: String,
360 pub quantitative_bound: String,
361}
362impl Finitization {
363 #[allow(dead_code)]
364 pub fn new(inf: &str, fin: &str, bound: &str) -> Self {
365 Self {
366 infinite_principle: inf.to_string(),
367 finite_version: fin.to_string(),
368 quantitative_bound: bound.to_string(),
369 }
370 }
371 #[allow(dead_code)]
372 pub fn bolzano_weierstrass() -> Self {
373 Self::new(
374 "Every bounded sequence has a convergent subsequence",
375 "For every eps, there exist indices i < j s.t. |x_i - x_j| < eps",
376 "Omega(eps, M) primitive recursive in eps and bound M",
377 )
378 }
379 #[allow(dead_code)]
380 pub fn description(&self) -> String {
381 format!(
382 "Finite: {}\nfrom: {}\nbound: {}",
383 self.finite_version, self.infinite_principle, self.quantitative_bound
384 )
385 }
386}
387#[derive(Debug, Clone, PartialEq, Eq)]
389pub struct Clause {
390 pub literals: Vec<Literal>,
392}
393impl Clause {
394 pub fn empty() -> Self {
396 Self {
397 literals: Vec::new(),
398 }
399 }
400 pub fn new(literals: Vec<Literal>) -> Self {
402 Self { literals }
403 }
404 pub fn is_empty_clause(&self) -> bool {
406 self.literals.is_empty()
407 }
408 pub fn is_tautology(&self) -> bool {
410 for lit in &self.literals {
411 if self.literals.contains(&lit.complement()) {
412 return true;
413 }
414 }
415 false
416 }
417 pub fn is_unit(&self) -> bool {
419 self.literals.len() == 1
420 }
421}
422#[allow(dead_code)]
424#[derive(Debug, Clone)]
425pub struct UniformConvexityModulus {
426 pub space_name: String,
427 pub modulus: String,
428}
429impl UniformConvexityModulus {
430 #[allow(dead_code)]
431 pub fn new(space: &str, modulus: &str) -> Self {
432 Self {
433 space_name: space.to_string(),
434 modulus: modulus.to_string(),
435 }
436 }
437 #[allow(dead_code)]
438 pub fn hilbert_space() -> Self {
439 Self::new("Hilbert space H", "delta(eps) = 1 - sqrt(1 - eps^2/4)")
440 }
441 #[allow(dead_code)]
442 pub fn l_p_space(p: f64) -> Self {
443 let formula = if p >= 2.0 {
444 format!("delta(eps) >= (eps/2)^p / (2 max(1, 2^(p-2)))")
445 } else {
446 format!("delta(eps) >= (eps/2)^2 / 8 (Clarkson for p={p})")
447 };
448 Self::new(&format!("L^{p}"), &formula)
449 }
450 #[allow(dead_code)]
451 pub fn bound_on_iterations_for_mann(&self, _epsilon: f64) -> String {
452 format!(
453 "Kohlenbach-Leustean: rate of Mann iterations in {} via {}",
454 self.space_name, self.modulus
455 )
456 }
457}
458#[allow(dead_code)]
459#[derive(Debug, Clone)]
460pub enum SearchStrategyNew {
461 BreadthFirst,
462 DepthFirst,
463 IterativeDeepening,
464 Heuristic(String),
465 Saturation,
466}
467#[allow(dead_code)]
468impl SearchStrategyNew {
469 fn saturation_strategy() -> SearchStrategyNew {
470 SearchStrategyNew::Saturation
471 }
472}
473#[allow(dead_code)]
475#[derive(Debug, Clone)]
476pub struct OrdinalTermination {
477 pub algorithm_name: String,
478 pub ordinal_bound: String,
479 pub is_primitive_recursive: bool,
480}
481impl OrdinalTermination {
482 #[allow(dead_code)]
483 pub fn new(alg: &str, bound: &str, prim_rec: bool) -> Self {
484 Self {
485 algorithm_name: alg.to_string(),
486 ordinal_bound: bound.to_string(),
487 is_primitive_recursive: prim_rec,
488 }
489 }
490 #[allow(dead_code)]
491 pub fn termination_proof(&self) -> String {
492 format!(
493 "{} terminates: assign ordinal {} decreasing at each step",
494 self.algorithm_name, self.ordinal_bound
495 )
496 }
497}
498#[derive(Debug, Clone, PartialEq, Eq)]
500pub struct HerbrandTerm {
501 pub variable: String,
503 pub term: String,
505 pub predicate: String,
507}
508impl HerbrandTerm {
509 pub fn new(
511 variable: impl Into<String>,
512 term: impl Into<String>,
513 predicate: impl Into<String>,
514 ) -> Self {
515 Self {
516 variable: variable.into(),
517 term: term.into(),
518 predicate: predicate.into(),
519 }
520 }
521 pub fn describe(&self) -> String {
523 format!(
524 "∃ {}, {} [witness: {}]",
525 self.variable, self.predicate, self.term
526 )
527 }
528}
529#[derive(Debug, Clone)]
531pub struct HeuristicFn {
532 pub name: String,
534}
535impl HeuristicFn {
536 pub fn new(name: impl Into<String>) -> Self {
538 Self { name: name.into() }
539 }
540 pub fn estimate(&self, state: &ProofState) -> usize {
542 state.goals.len()
543 }
544}
545#[derive(Debug, Clone, PartialEq, Eq)]
550pub struct CantorNormalForm {
551 pub exponents: Vec<u32>,
554}
555impl CantorNormalForm {
556 pub fn zero() -> Self {
558 Self { exponents: vec![] }
559 }
560 pub fn one() -> Self {
562 Self { exponents: vec![0] }
563 }
564 pub fn omega() -> Self {
566 Self { exponents: vec![1] }
567 }
568 pub fn epsilon0() -> Self {
570 Self {
571 exponents: vec![u32::MAX],
572 }
573 }
574 pub fn is_zero(&self) -> bool {
576 self.exponents.is_empty()
577 }
578 pub fn less_than(&self, other: &Self) -> bool {
580 for (a, b) in self.exponents.iter().zip(other.exponents.iter()) {
581 if a < b {
582 return true;
583 }
584 if a > b {
585 return false;
586 }
587 }
588 self.exponents.len() < other.exponents.len()
589 }
590 pub fn add(&self, other: &Self) -> Self {
592 if other.is_zero() {
593 return self.clone();
594 }
595 let lead_b = other.exponents[0];
596 let mut result: Vec<u32> = self
597 .exponents
598 .iter()
599 .copied()
600 .filter(|&e| e > lead_b)
601 .collect();
602 result.extend_from_slice(&other.exponents);
603 Self { exponents: result }
604 }
605}
606#[derive(Debug, Clone)]
608pub struct WitnessExtractor {
609 pub proof_name: String,
611 pub witnesses: Vec<String>,
613 pub bound: Option<u64>,
615}
616impl WitnessExtractor {
617 pub fn new(proof_name: impl Into<String>) -> Self {
619 Self {
620 proof_name: proof_name.into(),
621 witnesses: Vec::new(),
622 bound: None,
623 }
624 }
625 pub fn add_witness(&mut self, term: impl Into<String>) {
627 self.witnesses.push(term.into());
628 }
629 pub fn extract_witness(&self) -> Option<&str> {
631 self.witnesses.first().map(String::as_str)
632 }
633 pub fn compute_bound(&self) -> u64 {
635 self.bound.unwrap_or(u64::MAX)
636 }
637 pub fn is_realizable(&self) -> bool {
639 !self.witnesses.is_empty()
640 }
641}
642#[derive(Debug, Clone)]
644pub struct ProofState {
645 pub goals: Vec<String>,
647 pub applied_tactics: Vec<String>,
649 pub budget: usize,
651}
652impl ProofState {
653 pub fn new(goal: impl Into<String>, budget: usize) -> Self {
655 Self {
656 goals: vec![goal.into()],
657 applied_tactics: Vec::new(),
658 budget,
659 }
660 }
661 pub fn is_complete(&self) -> bool {
663 self.goals.is_empty()
664 }
665 pub fn apply_tactic(&mut self, tactic: impl Into<String>) -> bool {
667 if self.budget == 0 || self.goals.is_empty() {
668 return false;
669 }
670 self.goals.remove(0);
671 self.applied_tactics.push(tactic.into());
672 self.budget -= 1;
673 true
674 }
675}
676#[derive(Debug, Clone, PartialEq, Eq)]
678pub struct ProofComplexityMeasure {
679 pub size: usize,
681 pub depth: usize,
683 pub width: usize,
685 pub degree: usize,
687}
688impl ProofComplexityMeasure {
689 pub fn zero() -> Self {
691 Self {
692 size: 0,
693 depth: 0,
694 width: 0,
695 degree: 0,
696 }
697 }
698 pub fn is_within_bound(&self, bound: usize) -> bool {
700 self.size <= bound && self.depth <= bound && self.width <= bound && self.degree <= bound
701 }
702}
703#[derive(Debug, Clone)]
705pub struct CookReckhowThm {
706 pub statement: String,
708}
709impl CookReckhowThm {
710 pub fn canonical() -> Self {
712 Self {
713 statement: concat!(
714 "NP ≠ co-NP if and only if no propositional proof system ",
715 "polynomially simulates all others."
716 )
717 .into(),
718 }
719 }
720}
721#[derive(Debug, Clone, PartialEq, Eq)]
723pub enum SearchStrategy {
724 DFS,
726 BFS,
728 AStar,
730 IDDFS,
732 MCTS,
734}
735#[derive(Debug, Clone)]
737pub struct ModelCheckingBound {
738 pub depth: usize,
740 pub max_depth: usize,
742 pub counterexample_found: bool,
744}
745impl ModelCheckingBound {
746 pub fn new(max_depth: usize) -> Self {
748 Self {
749 depth: 0,
750 max_depth,
751 counterexample_found: false,
752 }
753 }
754 pub fn unfold(&mut self) {
756 if self.depth < self.max_depth {
757 self.depth += 1;
758 }
759 }
760 pub fn at_bound(&self) -> bool {
762 self.depth >= self.max_depth
763 }
764}
765#[derive(Debug, Clone)]
767pub struct ExtractedProgram {
768 pub source_theorem: String,
770 pub program_text: String,
772 pub is_complete: bool,
774}
775impl ExtractedProgram {
776 pub fn new(theorem: impl Into<String>, program_text: impl Into<String>) -> Self {
778 Self {
779 source_theorem: theorem.into(),
780 program_text: program_text.into(),
781 is_complete: true,
782 }
783 }
784}
785#[derive(Debug, Clone)]
787pub struct MonotoneFunctionalInterpretation {
788 pub formula: String,
790 pub majorant: String,
792 pub is_bounded: bool,
794}
795impl MonotoneFunctionalInterpretation {
796 pub fn new(formula: impl Into<String>, majorant: impl Into<String>) -> Self {
798 Self {
799 formula: formula.into(),
800 majorant: majorant.into(),
801 is_bounded: true,
802 }
803 }
804 pub fn check_bound(&self) -> bool {
806 !self.majorant.is_empty()
807 }
808}
809#[derive(Debug, Clone)]
811pub struct PropositionalProof {
812 pub system: ProofSystem,
814 pub lines: Vec<(String, String)>,
816 pub conclusion: String,
818}
819impl PropositionalProof {
820 pub fn new(system: ProofSystem, conclusion: impl Into<String>) -> Self {
822 Self {
823 system,
824 lines: Vec::new(),
825 conclusion: conclusion.into(),
826 }
827 }
828 pub fn add_line(&mut self, formula: impl Into<String>, justification: impl Into<String>) {
830 self.lines.push((formula.into(), justification.into()));
831 }
832 pub fn measure(&self) -> ProofComplexityMeasure {
834 ProofComplexityMeasure {
835 size: self.lines.len(),
836 depth: self.lines.len(),
837 width: self.lines.iter().map(|(f, _)| f.len()).max().unwrap_or(0),
838 degree: 0,
839 }
840 }
841}
842#[derive(Debug, Clone)]
844pub struct TerminationProof {
845 pub function_name: String,
847 pub ordering: String,
849 pub verified: bool,
851}
852impl TerminationProof {
853 pub fn new(function_name: impl Into<String>, ordering: impl Into<String>) -> Self {
855 Self {
856 function_name: function_name.into(),
857 ordering: ordering.into(),
858 verified: false,
859 }
860 }
861 pub fn verify(&mut self) {
863 self.verified = true;
864 }
865}
866#[allow(dead_code)]
868#[derive(Debug, Clone)]
869pub struct MetricFixedPointMining {
870 pub contraction_modulus: f64,
871 pub initial_error: f64,
872}
873impl MetricFixedPointMining {
874 #[allow(dead_code)]
875 pub fn new(q: f64, err: f64) -> Self {
876 assert!(q < 1.0, "Contraction constant must be < 1");
877 Self {
878 contraction_modulus: q,
879 initial_error: err,
880 }
881 }
882 #[allow(dead_code)]
883 pub fn iterations_to_epsilon(&self, epsilon: f64) -> u64 {
884 let n = (epsilon / self.initial_error).ln() / self.contraction_modulus.ln();
885 n.ceil() as u64
886 }
887 #[allow(dead_code)]
888 pub fn rate_of_convergence_description(&self) -> String {
889 format!(
890 "Banach iteration converges geometrically with ratio q = {}",
891 self.contraction_modulus
892 )
893 }
894}
895#[derive(Debug, Clone, PartialEq, Eq, Hash)]
897pub struct Literal {
898 pub var: u32,
900 pub positive: bool,
902}
903impl Literal {
904 pub fn pos(var: u32) -> Self {
906 Self {
907 var,
908 positive: true,
909 }
910 }
911 pub fn neg(var: u32) -> Self {
913 Self {
914 var,
915 positive: false,
916 }
917 }
918 pub fn complement(&self) -> Self {
920 Self {
921 var: self.var,
922 positive: !self.positive,
923 }
924 }
925}
926#[derive(Debug, Clone, PartialEq, Eq)]
928pub enum RealizedFormula {
929 Atomic(String),
931 Conjunction(Box<RealizedFormula>, Box<RealizedFormula>),
933 Disjunction(Box<RealizedFormula>, Box<RealizedFormula>),
935 Implication(Box<RealizedFormula>, Box<RealizedFormula>),
937 Forall(String, Box<RealizedFormula>),
939 Exists(String, Box<RealizedFormula>),
941}
942impl RealizedFormula {
943 pub fn depth(&self) -> usize {
945 match self {
946 RealizedFormula::Atomic(_) => 0,
947 RealizedFormula::Forall(_, f) | RealizedFormula::Exists(_, f) => 1 + f.depth(),
948 RealizedFormula::Conjunction(a, b)
949 | RealizedFormula::Disjunction(a, b)
950 | RealizedFormula::Implication(a, b) => 1 + a.depth().max(b.depth()),
951 }
952 }
953 pub fn is_existential(&self) -> bool {
955 matches!(self, RealizedFormula::Exists(_, _))
956 }
957}
958#[derive(Debug, Clone)]
960pub struct ProofSearcher {
961 pub strategy: SearchStrategy,
963 pub heuristic: HeuristicFn,
965 pub max_depth: usize,
967}
968impl ProofSearcher {
969 pub fn new(strategy: SearchStrategy, max_depth: usize) -> Self {
971 Self {
972 strategy,
973 heuristic: HeuristicFn::new("goal_count"),
974 max_depth,
975 }
976 }
977 pub fn search(&self, goal: impl Into<String>, tactics: &[&str]) -> Option<ProofState> {
980 let mut state = ProofState::new(goal, self.max_depth);
981 for tactic in tactics {
982 if state.is_complete() {
983 break;
984 }
985 state.apply_tactic(*tactic);
986 }
987 if state.is_complete() {
988 Some(state)
989 } else {
990 None
991 }
992 }
993}
994#[derive(Debug, Clone)]
1000pub struct MetastabilityBound {
1001 pub name: String,
1003 pub bound_table: Vec<Vec<u64>>,
1006 pub is_tight: bool,
1008}
1009impl MetastabilityBound {
1010 pub fn constant(name: impl Into<String>, c: u64) -> Self {
1012 let table: Vec<Vec<u64>> = (0..8).map(|_| (0..8).map(|_| c).collect()).collect();
1013 Self {
1014 name: name.into(),
1015 bound_table: table,
1016 is_tight: false,
1017 }
1018 }
1019 pub fn evaluate(&self, epsilon_inv: usize, k: usize) -> u64 {
1021 let r = epsilon_inv.min(self.bound_table.len() - 1);
1022 let c = k.min(self.bound_table[r].len() - 1);
1023 self.bound_table[r][c]
1024 }
1025 pub fn is_finite(&self) -> bool {
1027 self.bound_table
1028 .iter()
1029 .all(|row| row.iter().all(|&v| v < u64::MAX))
1030 }
1031}
1032#[derive(Debug, Clone)]
1034pub struct ResolutionStep {
1035 pub parent1: Clause,
1037 pub parent2: Clause,
1039 pub pivot: u32,
1041 pub resolvent: Clause,
1043}
1044impl ResolutionStep {
1045 pub fn resolve(c1: &Clause, c2: &Clause, pivot: u32) -> Option<Self> {
1048 let has_pos = c1.literals.iter().any(|l| l.var == pivot && l.positive);
1049 let has_neg = c2.literals.iter().any(|l| l.var == pivot && !l.positive);
1050 if !has_pos || !has_neg {
1051 return None;
1052 }
1053 let mut res_lits: Vec<Literal> = c1
1054 .literals
1055 .iter()
1056 .filter(|l| l.var != pivot)
1057 .chain(c2.literals.iter().filter(|l| l.var != pivot))
1058 .cloned()
1059 .collect();
1060 res_lits.sort_by_key(|l| (l.var, l.positive));
1061 res_lits.dedup();
1062 Some(ResolutionStep {
1063 parent1: c1.clone(),
1064 parent2: c2.clone(),
1065 pivot,
1066 resolvent: Clause::new(res_lits),
1067 })
1068 }
1069}
1070#[allow(dead_code)]
1072#[derive(Debug, Clone)]
1073pub struct BarRecursion {
1074 pub type_level: usize,
1075 pub models_comprehension: bool,
1076}
1077impl BarRecursion {
1078 #[allow(dead_code)]
1079 pub fn spector() -> Self {
1080 Self {
1081 type_level: 2,
1082 models_comprehension: true,
1083 }
1084 }
1085 #[allow(dead_code)]
1086 pub fn description(&self) -> String {
1087 format!(
1088 "Spector bar recursion: models classical comprehension via type-{} functional",
1089 self.type_level
1090 )
1091 }
1092 #[allow(dead_code)]
1093 pub fn kohlenbach_generalization(&self) -> String {
1094 "Modified bar recursion for non-empty types (Berger-Oliva)".to_string()
1095 }
1096}
1097#[allow(dead_code)]
1099#[derive(Debug, Clone)]
1100pub struct QuantitativeCauchy {
1101 pub space_name: String,
1102 pub convergence_rate: String,
1103}
1104impl QuantitativeCauchy {
1105 #[allow(dead_code)]
1106 pub fn new(space: &str, rate: &str) -> Self {
1107 Self {
1108 space_name: space.to_string(),
1109 convergence_rate: rate.to_string(),
1110 }
1111 }
1112 #[allow(dead_code)]
1113 pub fn leustean_bound_for_cat0(&self) -> String {
1114 "Leustean: Halpern iterations converge in CAT(0) spaces with explicit rate omega^omega"
1115 .to_string()
1116 }
1117}
1118#[derive(Debug, Clone)]
1120pub struct DialecticaFormula {
1121 pub original: String,
1123 pub universal_vars: Vec<String>,
1125 pub existential_vars: Vec<String>,
1127 pub body: String,
1129}
1130impl DialecticaFormula {
1131 pub fn translate(original: impl Into<String>, body: impl Into<String>) -> Self {
1133 Self {
1134 original: original.into(),
1135 universal_vars: vec!["x".into()],
1136 existential_vars: vec!["u".into()],
1137 body: body.into(),
1138 }
1139 }
1140 pub fn display(&self) -> String {
1142 format!(
1143 "∃ {}. ∀ {}. {}",
1144 self.existential_vars.join(", "),
1145 self.universal_vars.join(", "),
1146 self.body,
1147 )
1148 }
1149}
1150#[derive(Debug, Clone, PartialEq, Eq)]
1152pub enum ComplexityBound {
1153 Constant,
1155 Linear,
1157 Polynomial(u32),
1159 Exponential,
1161 NonElementary,
1163}
1164impl ComplexityBound {
1165 pub fn is_polynomial(&self) -> bool {
1167 matches!(
1168 self,
1169 ComplexityBound::Constant | ComplexityBound::Linear | ComplexityBound::Polynomial(_)
1170 )
1171 }
1172}
1173#[derive(Debug, Clone)]
1175pub struct HerbrandSequenceBuilder {
1176 pub formula: String,
1178 pub instances: Vec<String>,
1180 pub max_instances: usize,
1182}
1183impl HerbrandSequenceBuilder {
1184 pub fn new(formula: impl Into<String>, max_instances: usize) -> Self {
1186 Self {
1187 formula: formula.into(),
1188 instances: Vec::new(),
1189 max_instances,
1190 }
1191 }
1192 pub fn add_instance(&mut self, instance: impl Into<String>) -> bool {
1194 if self.instances.len() >= self.max_instances {
1195 return false;
1196 }
1197 self.instances.push(instance.into());
1198 true
1199 }
1200 pub fn is_tautology(&self) -> bool {
1202 self.instances.iter().any(|s| s.contains("True"))
1203 }
1204 pub fn complexity(&self) -> usize {
1206 self.instances.len()
1207 }
1208 pub fn disjunction(&self) -> String {
1210 if self.instances.is_empty() {
1211 return "False".to_string();
1212 }
1213 self.instances.join(" ∨ ")
1214 }
1215}
1216#[allow(dead_code)]
1217#[derive(Debug, Clone)]
1218pub struct GentzenNormalization {
1219 pub proof_size_before: usize,
1220 pub proof_size_after: usize,
1221 pub cut_rank: usize,
1222 pub num_reduction_steps: usize,
1223}
1224#[allow(dead_code)]
1225impl GentzenNormalization {
1226 pub fn new(before: usize, cut_rank: usize) -> Self {
1227 let steps = 2_usize.saturating_pow(cut_rank as u32);
1228 GentzenNormalization {
1229 proof_size_before: before,
1230 proof_size_after: before * steps,
1231 cut_rank,
1232 num_reduction_steps: steps,
1233 }
1234 }
1235 pub fn cut_elimination_theorem(&self) -> String {
1236 format!(
1237 "Gentzen's cut elimination: proof of size {} with cut rank {} → normal proof of size {} (TOWER({}))",
1238 self.proof_size_before, self.cut_rank, self.proof_size_after, self.cut_rank
1239 )
1240 }
1241 pub fn reduction_terminates(&self) -> bool {
1242 true
1243 }
1244 pub fn ordinal_analysis_connection(&self) -> String {
1245 "PA cut-rank ↔ ordinal ε₀; PA₂ ↔ Γ₀; KP ↔ Bachmann-Howard ordinal".to_string()
1246 }
1247}
1248#[allow(dead_code)]
1249#[derive(Debug, Clone)]
1250pub enum ProofSystemType {
1251 Resolution,
1252 Frege,
1253 ExtendedFrege,
1254 QuantifiedPropositional,
1255 CuttingPlanes,
1256 SumOfSquares,
1257}
1258#[allow(dead_code)]
1259#[derive(Debug, Clone)]
1260pub struct PhpPrinciple {
1261 pub n_pigeons: usize,
1262 pub m_holes: usize,
1263 pub resolution_lower_bound: usize,
1264}
1265#[allow(dead_code)]
1266impl PhpPrinciple {
1267 pub fn new(n: usize, m: usize) -> Self {
1268 let lb = 2_usize.saturating_pow((n / 2) as u32);
1269 PhpPrinciple {
1270 n_pigeons: n,
1271 m_holes: m,
1272 resolution_lower_bound: lb,
1273 }
1274 }
1275 pub fn is_valid_php(&self) -> bool {
1276 self.n_pigeons > self.m_holes
1277 }
1278 pub fn haken_lower_bound_description(&self) -> String {
1279 format!(
1280 "Haken (1985): PHP_{} has no polynomial resolution proof; lower bound ≥ {}",
1281 self.n_pigeons, self.resolution_lower_bound
1282 )
1283 }
1284 pub fn bounded_arithmetic_connection(&self) -> String {
1285 format!(
1286 "PHP_{} unprovable in S^1_2 but provable in T^2_2 (bounded arithmetic)",
1287 self.n_pigeons
1288 )
1289 }
1290}
1291#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1293pub enum ProofSystem {
1294 Resolution,
1296 Frege,
1298 ExtendedFrege,
1300 HalfFrege,
1302 CuttingPlanes,
1304 Nullstellensatz,
1306 SOS,
1308 IPS,
1310}
1311#[derive(Debug, Clone)]
1313pub struct ResolutionProof {
1314 pub input_clauses: Vec<Vec<i32>>,
1316 pub steps: Vec<(usize, usize, i32, Vec<i32>)>,
1318}
1319impl ResolutionProof {
1320 pub fn new(input_clauses: Vec<Vec<i32>>) -> Self {
1322 Self {
1323 input_clauses,
1324 steps: Vec::new(),
1325 }
1326 }
1327 pub fn add_step(&mut self, p1: usize, p2: usize, pivot: i32, resolvent: Vec<i32>) {
1329 self.steps.push((p1, p2, pivot, resolvent));
1330 }
1331 pub fn is_refutation(&self) -> bool {
1333 self.steps.last().is_some_and(|(_, _, _, r)| r.is_empty())
1334 }
1335}
1336#[allow(dead_code)]
1338#[derive(Debug, Clone)]
1339pub struct EffectiveBound {
1340 pub original_theorem: String,
1341 pub extracted_bound: String,
1342 pub bound_type: BoundType,
1343 pub dependencies: Vec<String>,
1344}
1345impl EffectiveBound {
1346 #[allow(dead_code)]
1347 pub fn new(theorem: &str, bound: &str, bt: BoundType) -> Self {
1348 Self {
1349 original_theorem: theorem.to_string(),
1350 extracted_bound: bound.to_string(),
1351 bound_type: bt,
1352 dependencies: Vec::new(),
1353 }
1354 }
1355 #[allow(dead_code)]
1356 pub fn is_feasible(&self) -> bool {
1357 matches!(self.bound_type, BoundType::Polynomial)
1358 }
1359 #[allow(dead_code)]
1360 pub fn add_dependency(&mut self, dep: &str) {
1361 self.dependencies.push(dep.to_string());
1362 }
1363}
1364#[allow(dead_code)]
1366#[derive(Debug, Clone)]
1367pub struct UnwindingResult {
1368 pub classical_proof: String,
1369 pub constructive_content: String,
1370 pub interpreter_used: String,
1371}
1372impl UnwindingResult {
1373 #[allow(dead_code)]
1374 pub fn new(classical: &str, constructive: &str, interp: &str) -> Self {
1375 Self {
1376 classical_proof: classical.to_string(),
1377 constructive_content: constructive.to_string(),
1378 interpreter_used: interp.to_string(),
1379 }
1380 }
1381 #[allow(dead_code)]
1382 pub fn kohlenbach_style(&self) -> String {
1383 format!(
1384 "Kohlenbach unwinding: {} -> {}, via {}",
1385 self.classical_proof, self.constructive_content, self.interpreter_used
1386 )
1387 }
1388}
1389#[allow(dead_code)]
1390#[derive(Debug, Clone)]
1391pub struct ProofSystemNew {
1392 pub name: String,
1393 pub system_type: ProofSystemType,
1394 pub propositional_completeness: bool,
1395 pub p_simulates_resolution: Option<bool>,
1396}
1397#[allow(dead_code)]
1398impl ProofSystemNew {
1399 pub fn resolution() -> Self {
1400 ProofSystemNew {
1401 name: "Resolution".to_string(),
1402 system_type: ProofSystemType::Resolution,
1403 propositional_completeness: true,
1404 p_simulates_resolution: Some(false),
1405 }
1406 }
1407 pub fn frege() -> Self {
1408 ProofSystemNew {
1409 name: "Frege (Hilbert-style)".to_string(),
1410 system_type: ProofSystemType::Frege,
1411 propositional_completeness: true,
1412 p_simulates_resolution: Some(true),
1413 }
1414 }
1415 pub fn extended_frege() -> Self {
1416 ProofSystemNew {
1417 name: "Extended Frege (EF)".to_string(),
1418 system_type: ProofSystemType::ExtendedFrege,
1419 propositional_completeness: true,
1420 p_simulates_resolution: Some(true),
1421 }
1422 }
1423 pub fn separating_tautologies(&self) -> String {
1424 match &self.system_type {
1425 ProofSystemType::Resolution => {
1426 "Pigeonhole principle requires exponential-size Resolution proofs".to_string()
1427 }
1428 ProofSystemType::CuttingPlanes => {
1429 "CP: exponential lower bounds for random CNF (Razborov)".to_string()
1430 }
1431 _ => "Known lower bounds: PHP, Tseitin, Random k-CNF".to_string(),
1432 }
1433 }
1434 pub fn cook_reckhow_theorem(&self) -> String {
1435 "Cook-Reckhow: P=NP iff every Cook system has polynomial-size proofs".to_string()
1436 }
1437}
1438#[derive(Debug, Clone)]
1440pub struct BoundedArithmetic {
1441 pub theory: String,
1443 pub base_theory: String,
1445 pub formula_class: String,
1447}
1448impl BoundedArithmetic {
1449 pub fn paomega_over_pra() -> Self {
1451 Self {
1452 theory: "PA^ω".into(),
1453 base_theory: "PRA".into(),
1454 formula_class: "Π^0_2".into(),
1455 }
1456 }
1457}
1458#[allow(dead_code)]
1459#[derive(Debug, Clone, PartialEq, Eq)]
1460pub enum BoundType {
1461 Polynomial,
1462 Exponential,
1463 PrimitiveRecursive,
1464 Ackermann,
1465 NonPrimitive,
1466}