Skip to main content

oxilean_std/proof_theory/
functions.rs

1//! Auto-generated module
2//!
3//! πŸ€– Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use oxilean_kernel::{BinderInfo, Declaration, Environment, Expr, Level, Name};
6
7use super::types::{
8    Clause, Combinator, CutEliminator, Formula, HerbrandInstance, HerbrandInstanceGenerator,
9    HerbrandTerm, LKNode, LKRule, NDTerm, ResolutionProver, Sequent, SequentCalculusProof,
10};
11
12pub(super) fn app(f: Expr, a: Expr) -> Expr {
13    Expr::App(Box::new(f), Box::new(a))
14}
15pub fn app2(f: Expr, a: Expr, b: Expr) -> Expr {
16    app(app(f, a), b)
17}
18pub fn app3(f: Expr, a: Expr, b: Expr, c: Expr) -> Expr {
19    app(app2(f, a, b), c)
20}
21pub fn cst(s: &str) -> Expr {
22    Expr::Const(Name::str(s), vec![])
23}
24pub fn prop() -> Expr {
25    Expr::Sort(Level::zero())
26}
27pub fn type0() -> Expr {
28    Expr::Sort(Level::succ(Level::zero()))
29}
30pub fn pi(bi: BinderInfo, name: &str, dom: Expr, body: Expr) -> Expr {
31    Expr::Pi(bi, Name::str(name), Box::new(dom), Box::new(body))
32}
33pub fn arrow(a: Expr, b: Expr) -> Expr {
34    pi(BinderInfo::Default, "_", a, b)
35}
36pub fn impl_pi(name: &str, dom: Expr, body: Expr) -> Expr {
37    pi(BinderInfo::Implicit, name, dom, body)
38}
39pub fn bvar(n: u32) -> Expr {
40    Expr::BVar(n)
41}
42pub fn nat_ty() -> Expr {
43    cst("Nat")
44}
45pub fn bool_ty() -> Expr {
46    cst("Bool")
47}
48pub fn list_ty(elem: Expr) -> Expr {
49    app(cst("List"), elem)
50}
51/// Sequent type: Ξ“ ⊒ Ξ”
52pub fn sequent_ty() -> Expr {
53    type0()
54}
55/// Proof derivation type
56pub fn derivation_ty() -> Expr {
57    arrow(sequent_ty(), type0())
58}
59/// Cut rule: Ξ“βŠ’A,Ξ” and Ξ“',AβŠ’Ξ”' β†’ Ξ“,Ξ“'βŠ’Ξ”,Ξ”'
60pub fn cut_rule_ty() -> Expr {
61    let seq = sequent_ty();
62    arrow(seq.clone(), arrow(seq.clone(), arrow(seq, prop())))
63}
64/// Natural deduction system type
65pub fn natural_deduction_ty() -> Expr {
66    type0()
67}
68/// Typed lambda term (under Curry-Howard)
69pub fn lambda_term_ty() -> Expr {
70    arrow(type0(), type0())
71}
72/// Beta-normal form type
73pub fn normal_form_ty() -> Expr {
74    arrow(type0(), prop())
75}
76/// Gentzen's Hauptsatz: cut-free provability
77/// CutElimination : βˆ€ (seq : Sequent), Derivable seq β†’ CutFreeDer seq
78pub fn cut_elimination_ty() -> Expr {
79    let seq = cst("Sequent");
80    impl_pi(
81        "seq",
82        seq.clone(),
83        arrow(
84            app(cst("Derivable"), bvar(0)),
85            app(cst("CutFreeDerivable"), bvar(1)),
86        ),
87    )
88}
89/// Cut-free proofs use only subformulas
90/// SubformulaProperty : βˆ€ (seq : Sequent), CutFreeDerivable seq β†’ SubformulasClosed seq
91pub fn subformula_property_ty() -> Expr {
92    let seq = cst("Sequent");
93    impl_pi(
94        "seq",
95        seq.clone(),
96        arrow(
97            app(cst("CutFreeDerivable"), bvar(0)),
98            app(cst("SubformulasClosed"), bvar(1)),
99        ),
100    )
101}
102/// Strong normalization for STLC
103/// Normalization : βˆ€ (t : LambdaTerm), WellTyped t β†’ StronglyNormalizing t
104pub fn normalization_ty() -> Expr {
105    impl_pi(
106        "t",
107        cst("LambdaTerm"),
108        arrow(
109            app(cst("WellTyped"), bvar(0)),
110            app(cst("StronglyNormalizing"), bvar(1)),
111        ),
112    )
113}
114/// Consistency: ⊬ False
115/// Consistency : Β¬ Provable False
116pub fn consistency_ty() -> Expr {
117    arrow(app(cst("Provable"), cst("FalseFormula")), cst("False"))
118}
119/// Completeness of propositional calculus
120/// CompletenessPC : βˆ€ (f : Formula), Tautology f β†’ Provable f
121pub fn completeness_propositional_ty() -> Expr {
122    impl_pi(
123        "f",
124        cst("Formula"),
125        arrow(
126            app(cst("Tautology"), bvar(0)),
127            app(cst("Provable"), bvar(1)),
128        ),
129    )
130}
131/// Curry-Howard: propositions = types, proofs = programs
132/// CurryHoward : βˆ€ (P : Prop), Proof P ↔ (βˆƒ t : LambdaTerm, HasType t P)
133pub fn curry_howard_ty() -> Expr {
134    impl_pi(
135        "P",
136        prop(),
137        app2(
138            cst("Iff"),
139            app(cst("Proof"), bvar(0)),
140            app2(
141                cst("Exists"),
142                cst("LambdaTerm"),
143                app(cst("HasType"), bvar(1)),
144            ),
145        ),
146    )
147}
148/// LK system: classical sequent calculus type
149/// LKDerivable : Sequent β†’ Prop
150pub fn lk_derivable_ty() -> Expr {
151    arrow(cst("Sequent"), prop())
152}
153/// LJ system: intuitionistic sequent calculus (single-succedent sequents)
154/// LJDerivable : Sequent β†’ Prop
155pub fn lj_derivable_ty() -> Expr {
156    arrow(cst("Sequent"), prop())
157}
158/// LK init rule: A ⊒ A is derivable in LK
159/// LKInit : βˆ€ (A : Formula), LKDerivable (AxiomSeq A)
160pub fn lk_init_ty() -> Expr {
161    impl_pi(
162        "A",
163        cst("Formula"),
164        app(cst("LKDerivable"), app(cst("AxiomSeq"), bvar(0))),
165    )
166}
167/// LK left-contraction: Ξ“,A,A ⊒ Ξ” β†’ Ξ“,A ⊒ Ξ”
168/// LKLeftContraction : βˆ€ (s t : Sequent), LKDerivable s β†’ LKDerivable t
169pub fn lk_left_contraction_ty() -> Expr {
170    impl_pi(
171        "s",
172        cst("Sequent"),
173        impl_pi(
174            "t",
175            cst("Sequent"),
176            arrow(
177                app(cst("LKDerivable"), bvar(1)),
178                app(cst("LKDerivable"), bvar(1)),
179            ),
180        ),
181    )
182}
183/// LK right-weakening: Ξ“ ⊒ Ξ” β†’ Ξ“ ⊒ Ξ”,A
184/// LKRightWeakening : βˆ€ (s : Sequent) (A : Formula), LKDerivable s β†’ LKDerivable (WeakenRight s A)
185pub fn lk_right_weakening_ty() -> Expr {
186    impl_pi(
187        "s",
188        cst("Sequent"),
189        impl_pi(
190            "A",
191            cst("Formula"),
192            arrow(
193                app(cst("LKDerivable"), bvar(1)),
194                app(
195                    cst("LKDerivable"),
196                    app2(cst("WeakenRight"), bvar(2), bvar(0)),
197                ),
198            ),
199        ),
200    )
201}
202/// LK left-conjunction rule: Ξ“,A ⊒ Ξ” β†’ Ξ“,A∧B ⊒ Ξ”
203/// LKAndLeft1 : βˆ€ (s t : Sequent), LKDerivable s β†’ LKDerivable t
204pub fn lk_and_left1_ty() -> Expr {
205    impl_pi(
206        "s",
207        cst("Sequent"),
208        impl_pi(
209            "t",
210            cst("Sequent"),
211            arrow(
212                app(cst("LKDerivable"), bvar(1)),
213                app(cst("LKDerivable"), bvar(1)),
214            ),
215        ),
216    )
217}
218/// LK right-conjunction rule: Ξ“ ⊒ A,Ξ” and Ξ“ ⊒ B,Ξ” β†’ Ξ“ ⊒ A∧B,Ξ”
219/// LKAndRight : βˆ€ (s1 s2 s3 : Sequent), LKDerivable s1 β†’ LKDerivable s2 β†’ LKDerivable s3
220pub fn lk_and_right_ty() -> Expr {
221    impl_pi(
222        "s1",
223        cst("Sequent"),
224        impl_pi(
225            "s2",
226            cst("Sequent"),
227            impl_pi(
228                "s3",
229                cst("Sequent"),
230                arrow(
231                    app(cst("LKDerivable"), bvar(2)),
232                    arrow(
233                        app(cst("LKDerivable"), bvar(2)),
234                        app(cst("LKDerivable"), bvar(1)),
235                    ),
236                ),
237            ),
238        ),
239    )
240}
241/// LK cut rule (explicit): Ξ“ ⊒ A,Ξ” and Ξ“',A ⊒ Ξ”' β†’ Ξ“,Ξ“' ⊒ Ξ”,Ξ”'
242/// LKCut : βˆ€ (s1 s2 s3 : Sequent) (A : Formula), LKDerivable s1 β†’ LKDerivable s2 β†’ LKDerivable s3
243pub fn lk_cut_ty() -> Expr {
244    impl_pi(
245        "s1",
246        cst("Sequent"),
247        impl_pi(
248            "s2",
249            cst("Sequent"),
250            impl_pi(
251                "s3",
252                cst("Sequent"),
253                impl_pi(
254                    "A",
255                    cst("Formula"),
256                    arrow(
257                        app(cst("LKDerivable"), bvar(3)),
258                        arrow(
259                            app(cst("LKDerivable"), bvar(3)),
260                            app(cst("LKDerivable"), bvar(2)),
261                        ),
262                    ),
263                ),
264            ),
265        ),
266    )
267}
268/// LJ left-implication: Ξ“,Aβ†’B,Ξ“' ⊒ A and Ξ“,B,Ξ“' ⊒ C β†’ Ξ“,Aβ†’B,Ξ“' ⊒ C
269/// LJImpLeft : βˆ€ (s1 s2 s3 : Sequent), LJDerivable s1 β†’ LJDerivable s2 β†’ LJDerivable s3
270pub fn lj_imp_left_ty() -> Expr {
271    impl_pi(
272        "s1",
273        cst("Sequent"),
274        impl_pi(
275            "s2",
276            cst("Sequent"),
277            impl_pi(
278                "s3",
279                cst("Sequent"),
280                arrow(
281                    app(cst("LJDerivable"), bvar(2)),
282                    arrow(
283                        app(cst("LJDerivable"), bvar(2)),
284                        app(cst("LJDerivable"), bvar(1)),
285                    ),
286                ),
287            ),
288        ),
289    )
290}
291/// LJ right-implication: Ξ“,A ⊒ B β†’ Ξ“ ⊒ Aβ†’B
292/// LJImpRight : βˆ€ (s t : Sequent), LJDerivable s β†’ LJDerivable t
293pub fn lj_imp_right_ty() -> Expr {
294    impl_pi(
295        "s",
296        cst("Sequent"),
297        impl_pi(
298            "t",
299            cst("Sequent"),
300            arrow(
301                app(cst("LJDerivable"), bvar(1)),
302                app(cst("LJDerivable"), bvar(1)),
303            ),
304        ),
305    )
306}
307/// Natural deduction: β†’-introduction (deduction theorem)
308/// NDImpIntro : βˆ€ (A B : Formula), NDDerivable (cons A empty) B β†’ NDDerivable empty (imp A B)
309pub fn nd_imp_intro_ty() -> Expr {
310    impl_pi(
311        "A",
312        cst("Formula"),
313        impl_pi(
314            "B",
315            cst("Formula"),
316            arrow(
317                app2(
318                    cst("NDDerivable"),
319                    app2(cst("Cons"), bvar(1), cst("EmptyCtx")),
320                    bvar(1),
321                ),
322                app2(
323                    cst("NDDerivable"),
324                    cst("EmptyCtx"),
325                    app2(cst("ImpForm"), bvar(2), bvar(1)),
326                ),
327            ),
328        ),
329    )
330}
331/// Natural deduction: β†’-elimination (modus ponens)
332/// NDImpElim : βˆ€ (Ξ“ : Context) (A B : Formula),
333///   NDDerivable Ξ“ (imp A B) β†’ NDDerivable Ξ“ A β†’ NDDerivable Ξ“ B
334pub fn nd_imp_elim_ty() -> Expr {
335    impl_pi(
336        "ctx",
337        cst("Context"),
338        impl_pi(
339            "A",
340            cst("Formula"),
341            impl_pi(
342                "B",
343                cst("Formula"),
344                arrow(
345                    app2(
346                        cst("NDDerivable"),
347                        bvar(2),
348                        app2(cst("ImpForm"), bvar(1), bvar(0)),
349                    ),
350                    arrow(
351                        app2(cst("NDDerivable"), bvar(3), bvar(2)),
352                        app2(cst("NDDerivable"), bvar(4), bvar(2)),
353                    ),
354                ),
355            ),
356        ),
357    )
358}
359/// Natural deduction: ∧-introduction
360/// NDAndIntro : βˆ€ (Ξ“ : Context) (A B : Formula),
361///   NDDerivable Ξ“ A β†’ NDDerivable Ξ“ B β†’ NDDerivable Ξ“ (and A B)
362pub fn nd_and_intro_ty() -> Expr {
363    impl_pi(
364        "ctx",
365        cst("Context"),
366        impl_pi(
367            "A",
368            cst("Formula"),
369            impl_pi(
370                "B",
371                cst("Formula"),
372                arrow(
373                    app2(cst("NDDerivable"), bvar(2), bvar(1)),
374                    arrow(
375                        app2(cst("NDDerivable"), bvar(3), bvar(1)),
376                        app2(
377                            cst("NDDerivable"),
378                            bvar(4),
379                            app2(cst("AndForm"), bvar(2), bvar(1)),
380                        ),
381                    ),
382                ),
383            ),
384        ),
385    )
386}
387/// Natural deduction: ∧-elimination left
388/// NDAndElimLeft : βˆ€ (Ξ“ : Context) (A B : Formula),
389///   NDDerivable Ξ“ (and A B) β†’ NDDerivable Ξ“ A
390pub fn nd_and_elim_left_ty() -> Expr {
391    impl_pi(
392        "ctx",
393        cst("Context"),
394        impl_pi(
395            "A",
396            cst("Formula"),
397            impl_pi(
398                "B",
399                cst("Formula"),
400                arrow(
401                    app2(
402                        cst("NDDerivable"),
403                        bvar(2),
404                        app2(cst("AndForm"), bvar(1), bvar(0)),
405                    ),
406                    app2(cst("NDDerivable"), bvar(3), bvar(2)),
407                ),
408            ),
409        ),
410    )
411}
412/// Natural deduction: ∨-introduction left
413/// NDOrIntroLeft : βˆ€ (Ξ“ : Context) (A B : Formula),
414///   NDDerivable Ξ“ A β†’ NDDerivable Ξ“ (or A B)
415pub fn nd_or_intro_left_ty() -> Expr {
416    impl_pi(
417        "ctx",
418        cst("Context"),
419        impl_pi(
420            "A",
421            cst("Formula"),
422            impl_pi(
423                "B",
424                cst("Formula"),
425                arrow(
426                    app2(cst("NDDerivable"), bvar(2), bvar(1)),
427                    app2(
428                        cst("NDDerivable"),
429                        bvar(3),
430                        app2(cst("OrForm"), bvar(2), bvar(1)),
431                    ),
432                ),
433            ),
434        ),
435    )
436}
437/// Ordinal type
438pub fn ordinal_ty() -> Expr {
439    type0()
440}
441/// Epsilon-zero: Ξ΅β‚€ = ωᡒᡐᡉᡍᡃ^Ο‰ (the proof-theoretic ordinal of PA)
442/// EpsilonZero : Ordinal
443pub fn epsilon_zero_ty() -> Expr {
444    cst("Ordinal")
445}
446/// Proof-theoretic ordinal of a system S: |S| : Ordinal
447/// ProofTheoreticOrdinal : ProofSystem β†’ Ordinal
448pub fn proof_theoretic_ordinal_ty() -> Expr {
449    arrow(cst("ProofSystem"), cst("Ordinal"))
450}
451/// Ordinal of PA equals Ξ΅β‚€: |PA| = Ξ΅β‚€
452/// PAOrdinalEpsilonZero : Eq Ordinal (ProofTheoreticOrdinal PA) EpsilonZero
453pub fn pa_ordinal_epsilon_zero_ty() -> Expr {
454    app3(
455        cst("Eq"),
456        cst("Ordinal"),
457        app(cst("ProofTheoreticOrdinal"), cst("PA")),
458        cst("EpsilonZero"),
459    )
460}
461/// Ordinal induction up to Ξ΅β‚€
462/// OrdinalInductionEpsilonZero :
463///   βˆ€ (P : Ordinal β†’ Prop),
464///     (βˆ€ Ξ±, (βˆ€ Ξ² < Ξ±, P Ξ²) β†’ P Ξ±) β†’
465///     βˆ€ Ξ± < EpsilonZero, P Ξ±
466pub fn ordinal_induction_epsilon_zero_ty() -> Expr {
467    impl_pi(
468        "P",
469        arrow(cst("Ordinal"), prop()),
470        arrow(
471            impl_pi(
472                "alpha",
473                cst("Ordinal"),
474                arrow(
475                    impl_pi(
476                        "beta",
477                        cst("Ordinal"),
478                        arrow(app2(cst("OrdLt"), bvar(0), bvar(1)), app(bvar(3), bvar(1))),
479                    ),
480                    app(bvar(2), bvar(1)),
481                ),
482            ),
483            impl_pi(
484                "alpha",
485                cst("Ordinal"),
486                arrow(
487                    app2(cst("OrdLt"), bvar(0), cst("EpsilonZero")),
488                    app(bvar(3), bvar(1)),
489                ),
490            ),
491        ),
492    )
493}
494/// Gentzen's theorem: PA is consistent, proved in PRA + TI(Ξ΅β‚€)
495/// GentzenConsistency : ConsistentSystem PA
496pub fn gentzen_consistency_ty() -> Expr {
497    app(cst("ConsistentSystem"), cst("PA"))
498}
499/// Gentzen's Hauptsatz for LK: all LK derivations can be cut-eliminated
500/// GentzenHauptsatz : βˆ€ (s : Sequent), LKDerivable s β†’ CutFreeLKDerivable s
501pub fn gentzen_hauptsatz_ty() -> Expr {
502    impl_pi(
503        "s",
504        cst("Sequent"),
505        arrow(
506            app(cst("LKDerivable"), bvar(0)),
507            app(cst("CutFreeLKDerivable"), bvar(1)),
508        ),
509    )
510}
511/// First incompleteness theorem: βˆƒ statement undecidable in PA
512/// GodelFirstIncompleteness :
513///   βˆ€ (S : ConsistentRecEnum), βˆƒ (Ο† : Sentence), Β¬Provable S Ο† ∧ Β¬Provable S (neg Ο†)
514pub fn godel_first_incompleteness_ty() -> Expr {
515    impl_pi(
516        "S",
517        cst("ConsistentRecEnum"),
518        app2(
519            cst("Exists"),
520            cst("Sentence"),
521            app2(
522                cst("And"),
523                app2(cst("NotProvable"), bvar(1), bvar(0)),
524                app2(cst("NotProvable"), bvar(2), app(cst("NegForm"), bvar(1))),
525            ),
526        ),
527    )
528}
529/// Second incompleteness theorem: PA cannot prove its own consistency
530/// GodelSecondIncompleteness : Β¬Provable PA (ConsistStmt PA)
531pub fn godel_second_incompleteness_ty() -> Expr {
532    arrow(
533        app2(cst("ProvableIn"), cst("PA"), cst("ConPa")),
534        cst("False"),
535    )
536}
537/// Rosser's strengthening: stronger undecidable sentence without omega-consistency
538/// RosserSentence : βˆ€ (S : ConsistentRecEnum), βˆƒ (ρ : Sentence), Β¬Provable S ρ ∧ Β¬Provable S (neg ρ)
539pub fn rosser_sentence_ty() -> Expr {
540    impl_pi(
541        "S",
542        cst("ConsistentRecEnum"),
543        app2(
544            cst("Exists"),
545            cst("Sentence"),
546            app2(
547                cst("And"),
548                arrow(app2(cst("ProvableIn"), bvar(1), bvar(0)), cst("False")),
549                arrow(
550                    app2(cst("ProvableIn"), bvar(2), app(cst("NegForm"), bvar(1))),
551                    cst("False"),
552                ),
553            ),
554        ),
555    )
556}
557/// Diagonal lemma (self-reference / fixed-point lemma)
558/// DiagonalLemma :
559///   βˆ€ (Ο† : Formula β†’ Formula), βˆƒ (ψ : Sentence), Provable PA (iff ψ (Ο† (godel_num ψ)))
560pub fn diagonal_lemma_ty() -> Expr {
561    impl_pi(
562        "phi",
563        arrow(cst("Formula"), cst("Formula")),
564        app2(
565            cst("Exists"),
566            cst("Sentence"),
567            app2(
568                cst("ProvableIn"),
569                cst("PA"),
570                app2(
571                    cst("IffForm"),
572                    bvar(0),
573                    app(bvar(2), app(cst("GodelNum"), bvar(1))),
574                ),
575            ),
576        ),
577    )
578}
579/// Tarski's undefinability of truth
580/// TarskiUndefinability : Β¬βˆƒ (Ο† : Formula β†’ Bool), βˆ€ (ψ : Sentence), Ο† (godel_num ψ) = true ↔ TrueIn Std ψ
581pub fn tarski_undefinability_ty() -> Expr {
582    arrow(
583        app2(
584            cst("Exists"),
585            arrow(cst("Formula"), bool_ty()),
586            impl_pi(
587                "psi",
588                cst("Sentence"),
589                app2(
590                    cst("Iff"),
591                    app2(
592                        cst("BoolEq"),
593                        app(bvar(1), app(cst("GodelNum"), bvar(0))),
594                        cst("BoolTrue"),
595                    ),
596                    app2(cst("TrueIn"), cst("StandardModel"), bvar(1)),
597                ),
598            ),
599        ),
600        cst("False"),
601    )
602}
603/// GΓΆdel completeness theorem: semantic entailment implies syntactic provability
604/// GodelCompleteness :
605///   βˆ€ (T : Theory) (Ο† : Formula), Entails T Ο† β†’ ProvableIn T Ο†
606pub fn godel_completeness_ty() -> Expr {
607    impl_pi(
608        "T",
609        cst("Theory"),
610        impl_pi(
611            "phi",
612            cst("Formula"),
613            arrow(
614                app2(cst("Entails"), bvar(1), bvar(0)),
615                app2(cst("ProvableIn"), bvar(2), bvar(1)),
616            ),
617        ),
618    )
619}
620/// Henkin completeness: every consistent theory has a model
621/// HenkinCompleteness : βˆ€ (T : Theory), ConsistentTheory T β†’ βˆƒ M, ModelOf M T
622pub fn henkin_completeness_ty() -> Expr {
623    impl_pi(
624        "T",
625        cst("Theory"),
626        arrow(
627            app(cst("ConsistentTheory"), bvar(0)),
628            app2(cst("Exists"), cst("Model"), app(cst("ModelOf"), bvar(1))),
629        ),
630    )
631}
632/// Compactness theorem: if every finite subset has a model, T has a model
633/// Compactness :
634///   βˆ€ (T : Theory),
635///     (βˆ€ Ξ”, FiniteSubset Ξ” T β†’ βˆƒ M, ModelOf M Ξ”) β†’ βˆƒ M, ModelOf M T
636pub fn compactness_ty() -> Expr {
637    impl_pi(
638        "T",
639        cst("Theory"),
640        arrow(
641            impl_pi(
642                "Delta",
643                cst("Theory"),
644                arrow(
645                    app2(cst("FiniteSubset"), bvar(0), bvar(1)),
646                    app2(cst("Exists"), cst("Model"), app(cst("ModelOf"), bvar(1))),
647                ),
648            ),
649            app2(cst("Exists"), cst("Model"), app(cst("ModelOf"), bvar(1))),
650        ),
651    )
652}
653/// Herbrand's theorem: universal theory is unsatisfiable iff a ground instance is
654/// HerbrandTheorem :
655///   βˆ€ (T : UniversalTheory), Β¬Satisfiable T ↔ βˆƒ (I : HerbrandInstance), Refutes I T
656pub fn herbrand_theorem_ty() -> Expr {
657    impl_pi(
658        "T",
659        cst("UniversalTheory"),
660        app2(
661            cst("Iff"),
662            arrow(app(cst("Satisfiable"), bvar(0)), cst("False")),
663            app2(
664                cst("Exists"),
665                cst("HerbrandInstance"),
666                app(app(cst("Refutes"), bvar(0)), bvar(2)),
667            ),
668        ),
669    )
670}
671/// Craig interpolation theorem
672/// CraigInterpolation :
673///   βˆ€ (A B : Formula), Tautology (imp A B) β†’
674///     βˆƒ (I : Formula), SubformAtoms I A ∧ SubformAtoms I B ∧ Tautology (imp A I) ∧ Tautology (imp I B)
675pub fn craig_interpolation_ty() -> Expr {
676    impl_pi(
677        "A",
678        cst("Formula"),
679        impl_pi(
680            "B",
681            cst("Formula"),
682            arrow(
683                app(cst("Tautology"), app2(cst("ImpForm"), bvar(1), bvar(0))),
684                app2(
685                    cst("Exists"),
686                    cst("Formula"),
687                    app3(
688                        cst("And3"),
689                        app2(cst("SubformAtoms"), bvar(0), bvar(3)),
690                        app2(cst("SubformAtoms"), bvar(1), bvar(2)),
691                        app2(
692                            cst("And"),
693                            app(cst("Tautology"), app2(cst("ImpForm"), bvar(3), bvar(1))),
694                            app(cst("Tautology"), app2(cst("ImpForm"), bvar(1), bvar(2))),
695                        ),
696                    ),
697                ),
698            ),
699        ),
700    )
701}
702/// Lyndon interpolation: interpolant uses only positive/negative occurrences properly
703/// LyndonInterpolation :
704///   βˆ€ (A B : Formula), Tautology (imp A B) β†’
705///     βˆƒ (I : Formula), LyndonInterpolant A B I
706pub fn lyndon_interpolation_ty() -> Expr {
707    impl_pi(
708        "A",
709        cst("Formula"),
710        impl_pi(
711            "B",
712            cst("Formula"),
713            arrow(
714                app(cst("Tautology"), app2(cst("ImpForm"), bvar(1), bvar(0))),
715                app2(
716                    cst("Exists"),
717                    cst("Formula"),
718                    app3(cst("LyndonInterpolant"), bvar(2), bvar(1), bvar(0)),
719                ),
720            ),
721        ),
722    )
723}
724/// Beth's definability theorem: implicit definability implies explicit definability
725/// BethDefinability :
726///   βˆ€ (T : Theory) (P : Predicate),
727///     ImplicitlyDefines T P β†’ βˆƒ (Ο† : Formula), ExplicitlyDefines T P Ο†
728pub fn beth_definability_ty() -> Expr {
729    impl_pi(
730        "T",
731        cst("Theory"),
732        impl_pi(
733            "P",
734            cst("Predicate"),
735            arrow(
736                app2(cst("ImplicitlyDefines"), bvar(1), bvar(0)),
737                app2(
738                    cst("Exists"),
739                    cst("Formula"),
740                    app3(cst("ExplicitlyDefines"), bvar(2), bvar(2), bvar(0)),
741                ),
742            ),
743        ),
744    )
745}
746/// Robinson's resolution theorem: a set of clauses is unsatisfiable iff the empty clause is derivable
747/// ResolutionCompleteness :
748///   βˆ€ (Ξ¦ : ClauseSet), Β¬Satisfiable Ξ¦ ↔ ResolutionRefutable Ξ¦
749pub fn resolution_completeness_ty() -> Expr {
750    impl_pi(
751        "Phi",
752        cst("ClauseSet"),
753        app2(
754            cst("Iff"),
755            arrow(app(cst("Satisfiable"), bvar(0)), cst("False")),
756            app(cst("ResolutionRefutable"), bvar(1)),
757        ),
758    )
759}
760/// Frege proof system type
761/// FregeSystem : ProofSystem β†’ Prop (marks it as a Frege system)
762pub fn frege_system_ty() -> Expr {
763    arrow(cst("ProofSystem"), prop())
764}
765/// Extended Frege (EF) simulates Frege with polynomial overhead
766/// EFSimulatesFrege :
767///   βˆ€ (f : FregeProof), βˆƒ (e : ExtFregeProof), SimulatesWithBound f e Polynomial
768pub fn ef_simulates_frege_ty() -> Expr {
769    impl_pi(
770        "f",
771        cst("FregeProof"),
772        app2(
773            cst("Exists"),
774            cst("ExtFregeProof"),
775            app3(
776                cst("SimulatesWithBound"),
777                bvar(1),
778                bvar(0),
779                cst("Polynomial"),
780            ),
781        ),
782    )
783}
784/// Cook-Reckhow theorem: all Frege systems p-simulate each other
785/// CookReckhow :
786///   βˆ€ (F1 F2 : ProofSystem), FregeSystem F1 β†’ FregeSystem F2 β†’ PSimulate F1 F2
787pub fn cook_reckhow_ty() -> Expr {
788    impl_pi(
789        "F1",
790        cst("ProofSystem"),
791        impl_pi(
792            "F2",
793            cst("ProofSystem"),
794            arrow(
795                app(cst("FregeSystem"), bvar(1)),
796                arrow(
797                    app(cst("FregeSystem"), bvar(1)),
798                    app2(cst("PSimulate"), bvar(3), bvar(2)),
799                ),
800            ),
801        ),
802    )
803}
804/// Takeuti's conjecture (proved by Tait): cut elimination for higher-order logic
805/// TakeutiConjecture : βˆ€ (seq : HOSequent), HODerivable seq β†’ CutFreeHODerivable seq
806pub fn takeuti_conjecture_ty() -> Expr {
807    impl_pi(
808        "seq",
809        cst("HOSequent"),
810        arrow(
811            app(cst("HODerivable"), bvar(0)),
812            app(cst("CutFreeHODerivable"), bvar(1)),
813        ),
814    )
815}
816/// Weak normalization: every well-typed term has a normal form
817/// WeakNormalization : βˆ€ (t : LambdaTerm), WellTyped t β†’ βˆƒ (n : LambdaTerm), NormalForm n ∧ BetaReducesTo t n
818pub fn weak_normalization_ty() -> Expr {
819    impl_pi(
820        "t",
821        cst("LambdaTerm"),
822        arrow(
823            app(cst("WellTyped"), bvar(0)),
824            app2(
825                cst("Exists"),
826                cst("LambdaTerm"),
827                app2(
828                    cst("And"),
829                    app(cst("NormalForm"), bvar(0)),
830                    app2(cst("BetaReducesTo"), bvar(2), bvar(1)),
831                ),
832            ),
833        ),
834    )
835}
836/// Church-Rosser (confluence) property for beta-reduction
837/// ChurchRosser :
838///   βˆ€ (t s1 s2 : LambdaTerm), BetaReducesTo t s1 β†’ BetaReducesTo t s2 β†’
839///     βˆƒ u, BetaReducesTo s1 u ∧ BetaReducesTo s2 u
840pub fn church_rosser_ty() -> Expr {
841    impl_pi(
842        "t",
843        cst("LambdaTerm"),
844        impl_pi(
845            "s1",
846            cst("LambdaTerm"),
847            impl_pi(
848                "s2",
849                cst("LambdaTerm"),
850                arrow(
851                    app2(cst("BetaReducesTo"), bvar(2), bvar(1)),
852                    arrow(
853                        app2(cst("BetaReducesTo"), bvar(3), bvar(1)),
854                        app2(
855                            cst("Exists"),
856                            cst("LambdaTerm"),
857                            app2(
858                                cst("And"),
859                                app2(cst("BetaReducesTo"), bvar(4), bvar(0)),
860                                app2(cst("BetaReducesTo"), bvar(4), bvar(1)),
861                            ),
862                        ),
863                    ),
864                ),
865            ),
866        ),
867    )
868}
869/// Register all proof theory axioms into the kernel environment.
870pub fn build_proof_theory_env(env: &mut Environment) {
871    let axioms: &[(&str, Expr)] = &[
872        ("Sequent", sequent_ty()),
873        ("Derivation", derivation_ty()),
874        ("CutRule", cut_rule_ty()),
875        ("NaturalDeduction", natural_deduction_ty()),
876        ("LambdaTerm", lambda_term_ty()),
877        ("NormalForm", normal_form_ty()),
878        ("Ordinal", ordinal_ty()),
879        ("Formula", type0()),
880        ("Derivable", arrow(cst("Sequent"), prop())),
881        ("CutFreeDerivable", arrow(cst("Sequent"), prop())),
882        ("SubformulasClosed", arrow(cst("Sequent"), prop())),
883        ("WellTyped", arrow(type0(), prop())),
884        ("StronglyNormalizing", arrow(type0(), prop())),
885        ("Provable", arrow(cst("Formula"), prop())),
886        ("Tautology", arrow(cst("Formula"), prop())),
887        ("Proof", arrow(prop(), type0())),
888        ("HasType", arrow(cst("LambdaTerm"), arrow(prop(), prop()))),
889        ("FalseFormula", cst("Formula")),
890        ("LKDerivable", lk_derivable_ty()),
891        ("LJDerivable", lj_derivable_ty()),
892        ("AxiomSeq", arrow(cst("Formula"), cst("Sequent"))),
893        (
894            "WeakenRight",
895            arrow(cst("Sequent"), arrow(cst("Formula"), cst("Sequent"))),
896        ),
897        ("CutFreeLKDerivable", arrow(cst("Sequent"), prop())),
898        ("Context", type0()),
899        ("EmptyCtx", cst("Context")),
900        (
901            "Cons",
902            arrow(cst("Formula"), arrow(cst("Context"), cst("Context"))),
903        ),
904        (
905            "NDDerivable",
906            arrow(cst("Context"), arrow(cst("Formula"), prop())),
907        ),
908        (
909            "ImpForm",
910            arrow(cst("Formula"), arrow(cst("Formula"), cst("Formula"))),
911        ),
912        (
913            "AndForm",
914            arrow(cst("Formula"), arrow(cst("Formula"), cst("Formula"))),
915        ),
916        (
917            "OrForm",
918            arrow(cst("Formula"), arrow(cst("Formula"), cst("Formula"))),
919        ),
920        ("NegForm", arrow(cst("Formula"), cst("Formula"))),
921        (
922            "IffForm",
923            arrow(cst("Formula"), arrow(cst("Formula"), cst("Formula"))),
924        ),
925        (
926            "OrdLt",
927            arrow(cst("Ordinal"), arrow(cst("Ordinal"), prop())),
928        ),
929        ("EpsilonZero", epsilon_zero_ty()),
930        ("ProofSystem", type0()),
931        ("ProofTheoreticOrdinal", proof_theoretic_ordinal_ty()),
932        ("PA", cst("ProofSystem")),
933        ("ConsistentSystem", arrow(cst("ProofSystem"), prop())),
934        ("Sentence", type0()),
935        ("ConsistentRecEnum", type0()),
936        (
937            "NotProvable",
938            arrow(cst("ConsistentRecEnum"), arrow(cst("Sentence"), prop())),
939        ),
940        (
941            "ProvableIn",
942            arrow(cst("ProofSystem"), arrow(cst("Formula"), prop())),
943        ),
944        ("ConPa", cst("Formula")),
945        ("GodelNum", arrow(cst("Sentence"), cst("Formula"))),
946        (
947            "TrueIn",
948            arrow(cst("Model"), arrow(cst("Sentence"), prop())),
949        ),
950        ("StandardModel", cst("Model")),
951        ("BoolEq", arrow(bool_ty(), arrow(bool_ty(), prop()))),
952        ("BoolTrue", bool_ty()),
953        ("Theory", type0()),
954        (
955            "Entails",
956            arrow(cst("Theory"), arrow(cst("Formula"), prop())),
957        ),
958        ("ConsistentTheory", arrow(cst("Theory"), prop())),
959        ("Model", type0()),
960        ("ModelOf", arrow(cst("Model"), arrow(cst("Theory"), prop()))),
961        (
962            "FiniteSubset",
963            arrow(cst("Theory"), arrow(cst("Theory"), prop())),
964        ),
965        ("UniversalTheory", type0()),
966        ("Satisfiable", arrow(cst("UniversalTheory"), prop())),
967        ("HerbrandInstance", type0()),
968        (
969            "Refutes",
970            arrow(
971                cst("HerbrandInstance"),
972                arrow(cst("UniversalTheory"), prop()),
973            ),
974        ),
975        (
976            "SubformAtoms",
977            arrow(cst("Formula"), arrow(cst("Formula"), prop())),
978        ),
979        ("And3", arrow(prop(), arrow(prop(), arrow(prop(), prop())))),
980        (
981            "LyndonInterpolant",
982            arrow(
983                cst("Formula"),
984                arrow(cst("Formula"), arrow(cst("Formula"), prop())),
985            ),
986        ),
987        ("Predicate", type0()),
988        (
989            "ImplicitlyDefines",
990            arrow(cst("Theory"), arrow(cst("Predicate"), prop())),
991        ),
992        (
993            "ExplicitlyDefines",
994            arrow(
995                cst("Theory"),
996                arrow(cst("Predicate"), arrow(cst("Formula"), prop())),
997            ),
998        ),
999        ("ClauseSet", type0()),
1000        ("ResolutionRefutable", arrow(cst("ClauseSet"), prop())),
1001        ("FregeProof", type0()),
1002        ("ExtFregeProof", type0()),
1003        (
1004            "SimulatesWithBound",
1005            arrow(
1006                cst("FregeProof"),
1007                arrow(cst("ExtFregeProof"), arrow(cst("Bound"), prop())),
1008            ),
1009        ),
1010        ("Bound", type0()),
1011        ("Polynomial", cst("Bound")),
1012        (
1013            "PSimulate",
1014            arrow(cst("ProofSystem"), arrow(cst("ProofSystem"), prop())),
1015        ),
1016        ("HOSequent", type0()),
1017        ("HODerivable", arrow(cst("HOSequent"), prop())),
1018        ("CutFreeHODerivable", arrow(cst("HOSequent"), prop())),
1019        (
1020            "BetaReducesTo",
1021            arrow(cst("LambdaTerm"), arrow(cst("LambdaTerm"), prop())),
1022        ),
1023        ("cut_elimination", cut_elimination_ty()),
1024        ("subformula_property", subformula_property_ty()),
1025        ("normalization", normalization_ty()),
1026        ("consistency", consistency_ty()),
1027        (
1028            "completeness_propositional",
1029            completeness_propositional_ty(),
1030        ),
1031        ("curry_howard", curry_howard_ty()),
1032        ("lk_init", lk_init_ty()),
1033        ("lk_left_contraction", lk_left_contraction_ty()),
1034        ("lk_right_weakening", lk_right_weakening_ty()),
1035        ("lk_and_left1", lk_and_left1_ty()),
1036        ("lk_and_right", lk_and_right_ty()),
1037        ("lk_cut", lk_cut_ty()),
1038        ("lj_imp_left", lj_imp_left_ty()),
1039        ("lj_imp_right", lj_imp_right_ty()),
1040        ("nd_imp_intro", nd_imp_intro_ty()),
1041        ("nd_imp_elim", nd_imp_elim_ty()),
1042        ("nd_and_intro", nd_and_intro_ty()),
1043        ("nd_and_elim_left", nd_and_elim_left_ty()),
1044        ("nd_or_intro_left", nd_or_intro_left_ty()),
1045        ("pa_ordinal_epsilon_zero", pa_ordinal_epsilon_zero_ty()),
1046        (
1047            "ordinal_induction_epsilon_zero",
1048            ordinal_induction_epsilon_zero_ty(),
1049        ),
1050        ("gentzen_consistency", gentzen_consistency_ty()),
1051        ("gentzen_hauptsatz", gentzen_hauptsatz_ty()),
1052        (
1053            "godel_first_incompleteness",
1054            godel_first_incompleteness_ty(),
1055        ),
1056        (
1057            "godel_second_incompleteness",
1058            godel_second_incompleteness_ty(),
1059        ),
1060        ("rosser_sentence", rosser_sentence_ty()),
1061        ("diagonal_lemma", diagonal_lemma_ty()),
1062        ("tarski_undefinability", tarski_undefinability_ty()),
1063        ("godel_completeness", godel_completeness_ty()),
1064        ("henkin_completeness", henkin_completeness_ty()),
1065        ("compactness", compactness_ty()),
1066        ("herbrand_theorem", herbrand_theorem_ty()),
1067        ("craig_interpolation", craig_interpolation_ty()),
1068        ("lyndon_interpolation", lyndon_interpolation_ty()),
1069        ("beth_definability", beth_definability_ty()),
1070        ("resolution_completeness", resolution_completeness_ty()),
1071        ("frege_system", frege_system_ty()),
1072        ("ef_simulates_frege", ef_simulates_frege_ty()),
1073        ("cook_reckhow", cook_reckhow_ty()),
1074        ("takeuti_conjecture", takeuti_conjecture_ty()),
1075        ("weak_normalization", weak_normalization_ty()),
1076        ("church_rosser", church_rosser_ty()),
1077    ];
1078    for (name, ty) in axioms {
1079        env.add(Declaration::Axiom {
1080            name: Name::str(*name),
1081            univ_params: vec![],
1082            ty: ty.clone(),
1083        })
1084        .ok();
1085    }
1086}
1087/// Evaluate a formula under a truth assignment.
1088pub fn eval(f: &Formula, assignment: &std::collections::HashMap<String, bool>) -> bool {
1089    match f {
1090        Formula::Atom(s) => *assignment.get(s).unwrap_or(&false),
1091        Formula::True_ => true,
1092        Formula::False_ => false,
1093        Formula::Neg(inner) => !eval(inner, assignment),
1094        Formula::And(a, b) => eval(a, assignment) && eval(b, assignment),
1095        Formula::Or(a, b) => eval(a, assignment) || eval(b, assignment),
1096        Formula::Implies(a, b) => !eval(a, assignment) || eval(b, assignment),
1097        Formula::Iff(a, b) => eval(a, assignment) == eval(b, assignment),
1098    }
1099}
1100/// Generate all truth table rows for the formula.
1101/// Returns a vector of (assignment, value) pairs.
1102pub fn truth_table(f: &Formula) -> Vec<(std::collections::HashMap<String, bool>, bool)> {
1103    let atoms = f.atoms();
1104    let n = atoms.len();
1105    let mut rows = Vec::with_capacity(1 << n);
1106    for mask in 0u64..(1u64 << n) {
1107        let mut assignment = std::collections::HashMap::new();
1108        for (i, atom) in atoms.iter().enumerate() {
1109            assignment.insert(atom.clone(), (mask >> i) & 1 == 1);
1110        }
1111        let val = eval(f, &assignment);
1112        rows.push((assignment, val));
1113    }
1114    rows
1115}
1116/// DPLL SAT solver for propositional logic in CNF.
1117///
1118/// Clauses are represented as `Vec<i32>` where positive literals are variable
1119/// indices and negative literals are their negations.
1120/// Returns a satisfying partial assignment (as a list of literals) or `None`.
1121pub fn dpll_sat(clauses: &[Vec<i32>]) -> Option<Vec<i32>> {
1122    let mut assignment = Vec::new();
1123    if dpll_inner(&clauses.to_vec(), &mut assignment) {
1124        Some(assignment)
1125    } else {
1126        None
1127    }
1128}
1129pub fn dpll_inner(clauses: &Vec<Vec<i32>>, assignment: &mut Vec<i32>) -> bool {
1130    let mut clauses = clauses.clone();
1131    loop {
1132        let unit = clauses.iter().find(|c| c.len() == 1).map(|c| c[0]);
1133        match unit {
1134            None => break,
1135            Some(lit) => {
1136                assignment.push(lit);
1137                clauses = propagate(&clauses, lit);
1138            }
1139        }
1140    }
1141    if clauses.iter().any(|c| c.is_empty()) {
1142        return false;
1143    }
1144    if clauses.is_empty() {
1145        return true;
1146    }
1147    let lit = clauses[0][0];
1148    let mut pos_clauses = propagate(&clauses, lit);
1149    let mut pos_assign = assignment.clone();
1150    pos_assign.push(lit);
1151    if dpll_inner(&pos_clauses, &mut pos_assign) {
1152        assignment.clear();
1153        assignment.extend(pos_assign);
1154        return true;
1155    }
1156    let neg_lit = -lit;
1157    pos_clauses = propagate(&clauses, neg_lit);
1158    let mut neg_assign = assignment.clone();
1159    neg_assign.push(neg_lit);
1160    if dpll_inner(&pos_clauses, &mut neg_assign) {
1161        assignment.clear();
1162        assignment.extend(neg_assign);
1163        return true;
1164    }
1165    false
1166}
1167pub fn propagate(clauses: &[Vec<i32>], lit: i32) -> Vec<Vec<i32>> {
1168    let mut result = Vec::new();
1169    for clause in clauses {
1170        if clause.contains(&lit) {
1171            continue;
1172        }
1173        let new_clause: Vec<i32> = clause.iter().filter(|&&l| l != -lit).copied().collect();
1174        result.push(new_clause);
1175    }
1176    result
1177}
1178/// Convert a formula to CNF (simplified Tseitin-style).
1179/// Returns a list of clauses (each clause is a list of literals).
1180/// Atoms are assigned indices starting from 1.
1181pub fn to_cnf(f: &Formula) -> Vec<Vec<i32>> {
1182    let atoms = f.atoms();
1183    let atom_idx: std::collections::HashMap<String, i32> = atoms
1184        .iter()
1185        .enumerate()
1186        .map(|(i, s)| (s.clone(), (i + 1) as i32))
1187        .collect();
1188    let mut clauses = Vec::new();
1189    to_cnf_inner(f, &atom_idx, &mut clauses, true);
1190    clauses
1191}
1192pub fn to_cnf_inner(
1193    f: &Formula,
1194    idx: &std::collections::HashMap<String, i32>,
1195    clauses: &mut Vec<Vec<i32>>,
1196    polarity: bool,
1197) {
1198    match f {
1199        Formula::Atom(s) => {
1200            let lit = *idx.get(s).unwrap_or(&1);
1201            clauses.push(vec![if polarity { lit } else { -lit }]);
1202        }
1203        Formula::True_ => {
1204            if !polarity {
1205                clauses.push(vec![]);
1206            }
1207        }
1208        Formula::False_ => {
1209            if polarity {
1210                clauses.push(vec![]);
1211            }
1212        }
1213        Formula::Neg(inner) => {
1214            to_cnf_inner(inner, idx, clauses, !polarity);
1215        }
1216        Formula::And(a, b) => {
1217            if polarity {
1218                to_cnf_inner(a, idx, clauses, true);
1219                to_cnf_inner(b, idx, clauses, true);
1220            } else {
1221                to_cnf_inner(a, idx, clauses, false);
1222                to_cnf_inner(b, idx, clauses, false);
1223            }
1224        }
1225        Formula::Or(a, b) => {
1226            if polarity {
1227                to_cnf_inner(a, idx, clauses, true);
1228                to_cnf_inner(b, idx, clauses, true);
1229            } else {
1230                to_cnf_inner(a, idx, clauses, false);
1231                to_cnf_inner(b, idx, clauses, false);
1232            }
1233        }
1234        Formula::Implies(a, b) => {
1235            to_cnf_inner(
1236                &Formula::or(Formula::neg(*a.clone()), *b.clone()),
1237                idx,
1238                clauses,
1239                polarity,
1240            );
1241        }
1242        Formula::Iff(a, b) => {
1243            to_cnf_inner(
1244                &Formula::and(
1245                    Formula::implies(*a.clone(), *b.clone()),
1246                    Formula::implies(*b.clone(), *a.clone()),
1247                ),
1248                idx,
1249                clauses,
1250                polarity,
1251            );
1252        }
1253    }
1254}
1255/// Check if a propositional sequent is provable using truth tables.
1256/// For a sequent Ξ“ ⊒ Ξ” this checks β‹€Ξ“ β†’ ⋁Δ is a tautology.
1257pub fn is_provable_propositional(seq: &Sequent) -> bool {
1258    let premise = seq
1259        .antecedent
1260        .iter()
1261        .cloned()
1262        .reduce(Formula::and)
1263        .unwrap_or(Formula::True_);
1264    let conclusion = seq
1265        .succedent
1266        .iter()
1267        .cloned()
1268        .reduce(Formula::or)
1269        .unwrap_or(Formula::False_);
1270    Formula::implies(premise, conclusion).is_tautology()
1271}
1272#[cfg(test)]
1273mod tests {
1274    use super::*;
1275    #[test]
1276    fn test_formula_tautology() {
1277        let a = Formula::atom("A");
1278        let f = Formula::implies(a.clone(), a);
1279        assert!(f.is_tautology());
1280    }
1281    #[test]
1282    fn test_formula_not_tautology() {
1283        let a = Formula::atom("A");
1284        assert!(!a.is_tautology());
1285    }
1286    #[test]
1287    fn test_formula_satisfiable() {
1288        let a = Formula::atom("A");
1289        assert!(a.is_satisfiable());
1290        assert!(!Formula::False_.is_satisfiable());
1291    }
1292    #[test]
1293    fn test_formula_contradiction() {
1294        assert!(Formula::False_.is_contradiction());
1295        assert!(!Formula::atom("A").is_contradiction());
1296    }
1297    #[test]
1298    fn test_formula_atoms() {
1299        let f = Formula::and(Formula::atom("A"), Formula::atom("B"));
1300        let atoms = f.atoms();
1301        assert!(atoms.contains(&"A".to_string()));
1302        assert!(atoms.contains(&"B".to_string()));
1303        assert_eq!(atoms.len(), 2);
1304    }
1305    #[test]
1306    fn test_formula_depth() {
1307        let a = Formula::atom("A");
1308        assert_eq!(a.depth(), 0);
1309        let ab = Formula::and(Formula::atom("A"), Formula::atom("B"));
1310        assert_eq!(ab.depth(), 1);
1311    }
1312    #[test]
1313    fn test_sequent_is_axiom() {
1314        let a = Formula::atom("A");
1315        let seq = Sequent::new(vec![a.clone()], vec![a]);
1316        assert!(seq.is_axiom());
1317        let seq2 = Sequent::new(vec![Formula::atom("A")], vec![Formula::atom("B")]);
1318        assert!(!seq2.is_axiom());
1319    }
1320    #[test]
1321    fn test_dpll_sat_simple() {
1322        let result = dpll_sat(&[vec![1]]);
1323        assert!(result.is_some());
1324        let result2 = dpll_sat(&[vec![1], vec![-1]]);
1325        assert!(result2.is_none());
1326        let result3 = dpll_sat(&[vec![1, -1]]);
1327        assert!(result3.is_some());
1328    }
1329    #[test]
1330    fn test_combinator_i_reduce() {
1331        let ix = Combinator::app(Combinator::I, Combinator::K);
1332        let reduced = ix.reduce_step().expect("I x should reduce");
1333        assert!(matches!(reduced, Combinator::K));
1334    }
1335    #[test]
1336    fn test_combinator_k_reduce() {
1337        let kxy = Combinator::app(Combinator::app(Combinator::K, Combinator::I), Combinator::S);
1338        let reduced = kxy.reduce_step().expect("K x y should reduce");
1339        assert!(matches!(reduced, Combinator::I));
1340    }
1341    #[test]
1342    fn test_build_proof_theory_env() {
1343        let mut env = oxilean_kernel::Environment::new();
1344        build_proof_theory_env(&mut env);
1345    }
1346    #[test]
1347    fn test_formula_to_nnf_double_neg() {
1348        let a = Formula::atom("A");
1349        let nn_a = Formula::neg(Formula::neg(a.clone()));
1350        let nnf = nn_a.to_nnf();
1351        assert_eq!(nnf, a);
1352    }
1353    #[test]
1354    fn test_formula_to_nnf_de_morgan() {
1355        let a = Formula::atom("A");
1356        let b = Formula::atom("B");
1357        let f = Formula::neg(Formula::and(a.clone(), b.clone()));
1358        let nnf = f.to_nnf();
1359        assert_eq!(nnf, Formula::or(Formula::neg(a), Formula::neg(b)));
1360    }
1361    #[test]
1362    fn test_sequent_calculus_proof_valid() {
1363        let a = Formula::atom("A");
1364        let seq = Sequent::new(vec![a.clone()], vec![a]);
1365        let proof = SequentCalculusProof::new(LKNode::axiom(seq));
1366        assert!(proof.is_valid());
1367        assert!(proof.is_cut_free());
1368        assert_eq!(proof.size(), 1);
1369    }
1370    #[test]
1371    fn test_lk_node_cut_free() {
1372        let a = Formula::atom("A");
1373        let seq = Sequent::new(vec![a.clone()], vec![a.clone()]);
1374        let leaf = LKNode::axiom(seq.clone());
1375        let parent = LKNode::unary(seq, LKRule::LeftWeaken, leaf);
1376        assert!(parent.is_cut_free());
1377    }
1378    #[test]
1379    fn test_lk_node_not_cut_free() {
1380        let a = Formula::atom("A");
1381        let seq = Sequent::new(vec![a.clone()], vec![a.clone()]);
1382        let leaf1 = LKNode::axiom(seq.clone());
1383        let leaf2 = LKNode::axiom(seq.clone());
1384        let cut_node = LKNode::binary(seq, LKRule::Cut(a.clone()), leaf1, leaf2);
1385        assert!(!cut_node.is_cut_free());
1386    }
1387    #[test]
1388    fn test_nd_term_beta_reduction() {
1389        let id = NDTerm::Lam(
1390            "x".to_string(),
1391            Box::new(Formula::atom("A")),
1392            Box::new(NDTerm::Var("x".to_string())),
1393        );
1394        let applied = NDTerm::App(Box::new(id), Box::new(NDTerm::Var("K".to_string())));
1395        let reduced = applied.reduce_step().expect("beta-redex should reduce");
1396        assert_eq!(reduced, NDTerm::Var("K".to_string()));
1397    }
1398    #[test]
1399    fn test_nd_term_fst_reduction() {
1400        let pair = NDTerm::Pair(
1401            Box::new(NDTerm::Var("a".to_string())),
1402            Box::new(NDTerm::Var("b".to_string())),
1403        );
1404        let fst = NDTerm::Fst(Box::new(pair));
1405        let reduced = fst.reduce_step().expect("fst should reduce");
1406        assert_eq!(reduced, NDTerm::Var("a".to_string()));
1407    }
1408    #[test]
1409    fn test_nd_term_subst() {
1410        let lam = NDTerm::Lam(
1411            "y".to_string(),
1412            Box::new(Formula::atom("T")),
1413            Box::new(NDTerm::Var("y".to_string())),
1414        );
1415        let result = lam.subst("x", &NDTerm::Var("K".to_string()));
1416        assert_eq!(result, lam);
1417    }
1418    #[test]
1419    fn test_cut_eliminator_verify() {
1420        let a = Formula::atom("A");
1421        let seq = Sequent::new(vec![a.clone()], vec![a]);
1422        let proof = SequentCalculusProof::new(LKNode::axiom(seq));
1423        assert!(CutEliminator::verify(&proof));
1424    }
1425    #[test]
1426    fn test_resolution_prover_unsat() {
1427        let clauses = vec![Clause::new(&[1]), Clause::new(&[-1])];
1428        let prover = ResolutionProver::new(clauses);
1429        assert!(prover.refute(100));
1430    }
1431    #[test]
1432    fn test_resolution_prover_sat() {
1433        let clauses = vec![Clause::new(&[1])];
1434        let prover = ResolutionProver::new(clauses);
1435        assert!(!prover.refute(100));
1436    }
1437    #[test]
1438    fn test_clause_resolve() {
1439        let c1 = Clause::new(&[1, 2]);
1440        let c2 = Clause::new(&[-1, 3]);
1441        let resolvent = Clause::resolve(&c1, &c2, 1).expect("should resolve");
1442        assert!(resolvent.0.contains(&2));
1443        assert!(resolvent.0.contains(&3));
1444        assert!(!resolvent.0.contains(&1));
1445    }
1446    #[test]
1447    fn test_herbrand_terms_depth_zero() {
1448        let gen = HerbrandInstanceGenerator::new(vec!["a".to_string(), "b".to_string()], vec![]);
1449        let terms = gen.terms_up_to_depth(0);
1450        assert_eq!(terms.len(), 2);
1451    }
1452    #[test]
1453    fn test_herbrand_instance_bind() {
1454        let mut inst = HerbrandInstance::new();
1455        inst.bind("x", HerbrandTerm::constant("a"));
1456        assert_eq!(inst.lookup("x"), Some(&HerbrandTerm::constant("a")));
1457    }
1458    #[test]
1459    fn test_herbrand_instance_generator_next() {
1460        let mut gen =
1461            HerbrandInstanceGenerator::new(vec!["a".to_string()], vec![("f".to_string(), 1)]);
1462        let instances = gen.next_instances(&["x".to_string()]);
1463        assert!(!instances.is_empty());
1464    }
1465    #[test]
1466    fn test_is_provable_propositional() {
1467        let a = Formula::atom("A");
1468        let seq = Sequent::new(vec![], vec![Formula::implies(a.clone(), a)]);
1469        assert!(is_provable_propositional(&seq));
1470    }
1471    #[test]
1472    fn test_herbrand_term_display() {
1473        let t = HerbrandTerm::fun("f", vec![HerbrandTerm::constant("a")]);
1474        assert_eq!(t.to_string(), "f(a)");
1475    }
1476    #[test]
1477    fn test_clause_display_empty() {
1478        let c = Clause::new(&[]);
1479        assert_eq!(c.to_string(), "β–‘");
1480    }
1481}