Skip to main content

logicaffeine_proof/
lib.rs

1#![cfg_attr(docsrs, feature(doc_cfg))]
2#![doc = include_str!("../README.md")]
3
4// Number-theory / cryptanalysis substrate — factoring, elliptic/isogeny, lattice, order-finding.
5// These are prover tools (the hardness lens behind isogeny/ait/oracle), not runtime crypto; they
6// depend only on `logicaffeine_base::numeric`.
7pub mod cyclotomic;
8pub mod elliptic;
9pub mod factor;
10pub mod fp2;
11pub mod hyperelliptic;
12pub mod lattice;
13pub mod period;
14
15pub mod arith;
16pub mod cdcl;
17pub mod cnf;
18pub mod dimacs;
19pub mod proof;
20pub mod proof_emit;
21pub mod complexity;
22pub mod ait;
23pub mod isogeny;
24pub mod coalgebra;
25pub mod groupoid;
26pub mod category_collapse;
27pub mod two_group;
28pub mod proof_rewrite;
29pub mod trace_determinism;
30pub mod progress_complex;
31pub mod cubical;
32pub mod kan_complex;
33pub mod two_type;
34pub mod eilenberg_maclane;
35pub mod postnikov;
36pub mod steenrod;
37pub mod pr;
38pub mod affine;
39pub mod affine_gfp;
40pub mod families;
41pub mod gf2;
42pub mod hypercube;
43pub mod census;
44pub mod cofactor;
45pub mod res_width;
46pub mod rup;
47pub mod sat;
48pub mod satcli;
49pub mod solve;
50pub mod xor_drat;
51pub mod xor_engine;
52pub mod bmc;
53pub mod cardinality;
54pub mod counting_principle;
55pub mod matching;
56pub mod ordering;
57pub mod parity_cardinality;
58pub mod pigeonhole;
59pub mod pseudo_boolean;
60pub mod symmetry;
61pub mod symmetry_detect;
62pub mod sym_certify;
63pub mod sym_dynamic;
64pub mod lyapunov;
65pub mod inprocess;
66pub mod sdcl;
67pub mod xorsat;
68pub mod lll;
69pub mod modp;
70pub mod modm;
71pub mod orbit_stability;
72pub mod polycalc;
73pub mod polycalc_gfp;
74pub mod polycalc_zm;
75pub mod sos;
76pub mod permgroup;
77pub mod sym_break;
78pub mod hornsat;
79pub mod twosat;
80pub mod interval_sched;
81pub mod register_alloc;
82pub mod optimize;
83pub mod certifier;
84pub mod counterexample;
85pub mod crush;
86pub mod decide;
87pub mod development;
88pub mod discrimination;
89pub mod lemma_index;
90pub mod engine;
91pub mod simp;
92pub mod formula;
93pub mod tactic;
94pub mod tactic_script;
95pub mod rule_search;
96pub mod linarith_solve;
97pub mod omega_solve;
98pub mod grounding;
99pub mod grid_solver;
100pub mod error;
101pub mod hints;
102pub mod unify;
103pub mod verify;
104
105#[cfg(feature = "verification")]
106pub mod oracle;
107#[cfg(feature = "verification")]
108mod modal_translation;
109
110pub use engine::BackwardChainer;
111pub use error::ProofError;
112pub use hints::{suggest_hint, SocraticHint, SuggestedTactic};
113pub use unify::Substitution;
114
115use std::fmt;
116
117// =============================================================================
118// PROOF TERM - Owned representation of logical terms
119// =============================================================================
120
121/// Owned term representation for proof manipulation.
122///
123/// Decoupled from arena-allocated `Term<'a>` to allow proof trees to persist
124/// beyond the lifetime of the parsing arena.
125///
126/// # See Also
127///
128/// * [`ProofExpr`] - Expression-level representation containing `ProofTerm`s
129/// * [`unify::unify_terms`] - Unification algorithm for terms
130/// * [`unify::Substitution`] - Maps variables to terms
131/// * [`certifier::certify`] - Converts proof trees to kernel terms
132#[derive(Debug, Clone, PartialEq, Eq, Hash)]
133pub enum ProofTerm {
134    /// A constant symbol (e.g., "Socrates", "42")
135    Constant(String),
136
137    /// A variable symbol (e.g., "x", "y")
138    Variable(String),
139
140    /// A function application (e.g., "father(x)", "add(1, 2)")
141    Function(String, Vec<ProofTerm>),
142
143    /// A group/tuple of terms (e.g., "(x, y)")
144    Group(Vec<ProofTerm>),
145
146    /// Reference to a bound variable in a pattern context.
147    /// Distinct from Variable (unification var) and Constant (global name).
148    /// Prevents variable capture bugs during alpha-conversion.
149    BoundVarRef(String),
150}
151
152impl fmt::Display for ProofTerm {
153    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154        match self {
155            ProofTerm::Constant(s) => write!(f, "{}", s),
156            ProofTerm::Variable(s) => write!(f, "{}", s),
157            ProofTerm::Function(name, args) => {
158                write!(f, "{}(", name)?;
159                for (i, arg) in args.iter().enumerate() {
160                    if i > 0 {
161                        write!(f, ", ")?;
162                    }
163                    write!(f, "{}", arg)?;
164                }
165                write!(f, ")")
166            }
167            ProofTerm::Group(terms) => {
168                write!(f, "(")?;
169                for (i, t) in terms.iter().enumerate() {
170                    if i > 0 {
171                        write!(f, ", ")?;
172                    }
173                    write!(f, "{}", t)?;
174                }
175                write!(f, ")")
176            }
177            ProofTerm::BoundVarRef(s) => write!(f, "#{}", s),
178        }
179    }
180}
181
182// =============================================================================
183// PROOF EXPRESSION - Owned representation of logical expressions
184// =============================================================================
185
186/// Owned expression representation for proof manipulation.
187///
188/// Supports all `LogicExpr` variants to enable full language coverage.
189/// This is the "proposition" side of the Curry-Howard correspondence.
190///
191/// # See Also
192///
193/// * [`ProofTerm`] - Terms embedded within expressions (predicate arguments)
194/// * [`unify::unify_exprs`] - Expression-level unification with alpha-equivalence
195/// * [`unify::beta_reduce`] - Normalizes lambda applications
196/// * [`certifier::certify`] - Converts expressions to kernel types
197/// * [`DerivationTree`] - Proof trees conclude with a `ProofExpr`
198#[derive(Debug, Clone, PartialEq)]
199pub enum ProofExpr {
200    // --- Core FOL ---
201
202    /// Atomic predicate: P(t1, t2, ...)
203    Predicate {
204        name: String,
205        args: Vec<ProofTerm>,
206        world: Option<String>,
207    },
208
209    /// Identity: t1 = t2
210    Identity(ProofTerm, ProofTerm),
211
212    /// Propositional atom
213    Atom(String),
214
215    // --- Logical Connectives ---
216
217    /// Conjunction: P ∧ Q
218    And(Box<ProofExpr>, Box<ProofExpr>),
219
220    /// Disjunction: P ∨ Q
221    Or(Box<ProofExpr>, Box<ProofExpr>),
222
223    /// Implication: P → Q
224    Implies(Box<ProofExpr>, Box<ProofExpr>),
225
226    /// Biconditional: P ↔ Q
227    Iff(Box<ProofExpr>, Box<ProofExpr>),
228
229    /// Negation: ¬P
230    Not(Box<ProofExpr>),
231
232    // --- Quantifiers ---
233
234    /// Universal quantification: ∀x P(x)
235    ForAll {
236        variable: String,
237        body: Box<ProofExpr>,
238    },
239
240    /// Existential quantification: ∃x P(x)
241    Exists {
242        variable: String,
243        body: Box<ProofExpr>,
244    },
245
246    // --- Modal Logic ---
247
248    /// Modal operator: □P or ◇P (with world semantics)
249    Modal {
250        domain: String,
251        force: f32,
252        flavor: String,
253        body: Box<ProofExpr>,
254    },
255
256    /// Counterfactual conditional: P □→ Q. Quantifies the consequent over the
257    /// closest antecedent-worlds (a similarity ordering), so it is strictly
258    /// distinct from material implication in both directions.
259    Counterfactual {
260        antecedent: Box<ProofExpr>,
261        consequent: Box<ProofExpr>,
262    },
263
264    // --- Temporal Logic ---
265
266    /// Temporal operator: Past(P), Future(P), Always(P), Eventually(P), Next(P)
267    Temporal {
268        operator: String,
269        body: Box<ProofExpr>,
270    },
271
272    /// Binary temporal operator: Until(P,Q), Release(P,Q), WeakUntil(P,Q)
273    TemporalBinary {
274        operator: String,
275        left: Box<ProofExpr>,
276        right: Box<ProofExpr>,
277    },
278
279    // --- Lambda Calculus (CIC extension) ---
280
281    /// Lambda abstraction: λx.P
282    Lambda {
283        variable: String,
284        body: Box<ProofExpr>,
285    },
286
287    /// Function application: (f x)
288    App(Box<ProofExpr>, Box<ProofExpr>),
289
290    // --- Event Semantics ---
291
292    /// Neo-Davidsonian event: ∃e(Verb(e) ∧ Agent(e,x) ∧ ...)
293    NeoEvent {
294        event_var: String,
295        verb: String,
296        roles: Vec<(String, ProofTerm)>,
297    },
298
299    // --- Peano / Inductive Types (CIC Extension) ---
300
301    /// Data Constructor: Zero, Succ(n), Cons(h, t), etc.
302    /// The building blocks of inductive types.
303    Ctor {
304        name: String,
305        args: Vec<ProofExpr>,
306    },
307
308    /// Pattern Matching: match n { Zero => A, Succ(k) => B }
309    /// Eliminates inductive types by case analysis.
310    Match {
311        scrutinee: Box<ProofExpr>,
312        arms: Vec<MatchArm>,
313    },
314
315    /// Recursive Function (Fixpoint): fix f. λn. ...
316    /// Defines recursive functions over inductive types.
317    Fixpoint {
318        name: String,
319        body: Box<ProofExpr>,
320    },
321
322    /// Typed Variable: n : Nat
323    /// Signals to the prover that induction may be applicable.
324    TypedVar {
325        name: String,
326        typename: String,
327    },
328
329    // --- Higher-Order Pattern Unification ---
330
331    /// Meta-variable (unification hole) to be solved during proof search.
332    /// Represents an unknown expression, typically a function or predicate.
333    /// Example: Hole("P") in ?P(x) = Body, to be solved as P = λx.Body
334    Hole(String),
335
336    /// Embedded term (lifts ProofTerm into ProofExpr context).
337    /// Used when a term appears where an expression is expected.
338    /// Example: App(Hole("P"), Term(BoundVarRef("x")))
339    Term(ProofTerm),
340
341    // --- Fallback ---
342
343    /// Unsupported construct (with description for debugging)
344    Unsupported(String),
345}
346
347// =============================================================================
348// MATCH ARM - A single case in pattern matching
349// =============================================================================
350
351/// A single arm in a match expression.
352/// Example: Succ(k) => Add(k, m)
353#[derive(Debug, Clone, PartialEq)]
354pub struct MatchArm {
355    /// The constructor being matched: "Zero", "Succ", "Cons", etc.
356    pub ctor: String,
357
358    /// Variable bindings for constructor arguments: ["k"] for Succ(k)
359    pub bindings: Vec<String>,
360
361    /// The expression to evaluate when this arm matches
362    pub body: ProofExpr,
363}
364
365impl fmt::Display for ProofExpr {
366    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
367        match self {
368            ProofExpr::Predicate { name, args, world } => {
369                write!(f, "{}", name)?;
370                if !args.is_empty() {
371                    write!(f, "(")?;
372                    for (i, arg) in args.iter().enumerate() {
373                        if i > 0 {
374                            write!(f, ", ")?;
375                        }
376                        write!(f, "{}", arg)?;
377                    }
378                    write!(f, ")")?;
379                }
380                if let Some(w) = world {
381                    write!(f, " @{}", w)?;
382                }
383                Ok(())
384            }
385            ProofExpr::Identity(left, right) => write!(f, "{} = {}", left, right),
386            ProofExpr::Atom(s) => write!(f, "{}", s),
387            ProofExpr::And(left, right) => write!(f, "({} ∧ {})", left, right),
388            ProofExpr::Or(left, right) => write!(f, "({} ∨ {})", left, right),
389            ProofExpr::Implies(left, right) => write!(f, "({} → {})", left, right),
390            ProofExpr::Iff(left, right) => write!(f, "({} ↔ {})", left, right),
391            ProofExpr::Not(inner) => write!(f, "¬{}", inner),
392            ProofExpr::ForAll { variable, body } => write!(f, "∀{} {}", variable, body),
393            ProofExpr::Exists { variable, body } => write!(f, "∃{} {}", variable, body),
394            ProofExpr::Modal { domain, force, flavor, body } => {
395                write!(f, "□[{}/{}/{}]{}", domain, force, flavor, body)
396            }
397            ProofExpr::Counterfactual { antecedent, consequent } => {
398                write!(f, "({} □→ {})", antecedent, consequent)
399            }
400            ProofExpr::Temporal { operator, body } => write!(f, "{}({})", operator, body),
401            ProofExpr::TemporalBinary { operator, left, right } => {
402                write!(f, "TemporalBinary({}, {}, {})", operator, left, right)
403            }
404            ProofExpr::Lambda { variable, body } => write!(f, "λ{}.{}", variable, body),
405            ProofExpr::App(func, arg) => write!(f, "({} {})", func, arg),
406            ProofExpr::NeoEvent { event_var, verb, roles } => {
407                write!(f, "∃{}({}({})", event_var, verb, event_var)?;
408                for (role, term) in roles {
409                    write!(f, " ∧ {}({}, {})", role, event_var, term)?;
410                }
411                write!(f, ")")
412            }
413            ProofExpr::Ctor { name, args } => {
414                write!(f, "{}", name)?;
415                if !args.is_empty() {
416                    write!(f, "(")?;
417                    for (i, arg) in args.iter().enumerate() {
418                        if i > 0 {
419                            write!(f, ", ")?;
420                        }
421                        write!(f, "{}", arg)?;
422                    }
423                    write!(f, ")")?;
424                }
425                Ok(())
426            }
427            ProofExpr::Match { scrutinee, arms } => {
428                write!(f, "match {} {{ ", scrutinee)?;
429                for (i, arm) in arms.iter().enumerate() {
430                    if i > 0 {
431                        write!(f, ", ")?;
432                    }
433                    write!(f, "{}", arm.ctor)?;
434                    if !arm.bindings.is_empty() {
435                        write!(f, "({})", arm.bindings.join(", "))?;
436                    }
437                    write!(f, " => {}", arm.body)?;
438                }
439                write!(f, " }}")
440            }
441            ProofExpr::Fixpoint { name, body } => write!(f, "fix {}.{}", name, body),
442            ProofExpr::TypedVar { name, typename } => write!(f, "{}:{}", name, typename),
443            ProofExpr::Unsupported(desc) => write!(f, "⟨unsupported: {}⟩", desc),
444            ProofExpr::Hole(name) => write!(f, "?{}", name),
445            ProofExpr::Term(term) => write!(f, "{}", term),
446        }
447    }
448}
449
450// =============================================================================
451// INFERENCE RULE - The logical moves available to the prover
452// =============================================================================
453
454/// The "Lever" - The specific logical move made at each proof step.
455///
456/// This enum captures HOW we moved from premises to conclusion. Each variant
457/// corresponds to a different proof strategy or logical rule.
458///
459/// # See Also
460///
461/// * [`DerivationTree`] - Each node contains an `InferenceRule`
462/// * [`certifier::certify`] - Maps inference rules to kernel terms
463/// * [`hints::suggest_hint`] - Suggests applicable rules when stuck
464/// * [`BackwardChainer`] - The engine that selects and applies rules
465///
466/// One constructor's case in a generic induction scheme
467/// ([`InferenceRule::InductionScheme`]). The derivation's premises align 1:1 with
468/// the cases, in the inductive's constructor-registration order.
469#[derive(Debug, Clone, PartialEq)]
470pub struct InductionCase {
471    /// The constructor this case eliminates (e.g. `"Succ"`, `"Node"`).
472    pub constructor: String,
473    /// The constructor's arguments, in order — each bound in the case body.
474    pub args: Vec<InductionArg>,
475}
476
477/// One argument of a constructor in an [`InductionCase`].
478#[derive(Debug, Clone, PartialEq)]
479pub struct InductionArg {
480    /// The name bound for this argument in the case body.
481    pub name: String,
482    /// Whether this argument is itself of the inductive type — a recursive
483    /// position, which therefore carries an induction hypothesis.
484    pub recursive: bool,
485}
486
487#[derive(Debug, Clone, PartialEq)]
488pub enum InferenceRule {
489    // --- Basic FOL ---
490
491    /// Direct match with a known fact in the Context/KnowledgeBase.
492    /// Logic: Γ, P ⊢ P
493    PremiseMatch,
494
495    /// Logic: P → Q, P ⊢ Q
496    ModusPonens,
497
498    /// Logic: ¬Q, P → Q ⊢ ¬P
499    ModusTollens,
500
501    /// Logic: P, Q ⊢ P ∧ Q
502    ConjunctionIntro,
503
504    /// Logic: P ∧ Q ⊢ P (or Q)
505    ConjunctionElim,
506
507    /// Logic: P ⊢ P ∨ Q
508    DisjunctionIntro,
509
510    /// Logic: P ∨ Q, P → R, Q → R ⊢ R
511    DisjunctionElim,
512
513    /// Logic: ⊥ ⊢ anything (ex falso quodlibet). The single premise concludes `False`.
514    ExFalso,
515
516    /// Logic: assume P, derive Q ⊢ P → Q (implication introduction / →I). The
517    /// single premise proves Q with P bound as a local hypothesis.
518    ImpliesIntro,
519
520    /// Logic: prove P → Q and Q → P ⊢ P ↔ Q (biconditional introduction / ↔I).
521    BicondIntro,
522
523    /// Logic: ¬¬P ⊢ P (and P ⊢ ¬¬P)
524    DoubleNegation,
525
526    /// Logic: classical reductio (proof by contradiction) — assume ¬G, derive ⊥ ⊢ G,
527    /// discharged through the `dne` axiom. The single premise concludes `False` with
528    /// ¬G bound as a local hypothesis.
529    ClassicalReductio,
530
531    // --- Quantifiers ---
532
533    /// Logic: ∀x P(x) ⊢ P(c)
534    /// Stores the specific term 'c' used to instantiate the universal.
535    UniversalInst(String),
536
537    /// Logic: ∀x P(x) ⊢ P(t) at an arbitrary witness TERM (a compound like
538    /// `add(a, Zero)`, not just a name). `UniversalInst` keeps the name-only
539    /// fast path; this carries the full term for instantiations that
540    /// `simp`/`crush` produce by matching.
541    UniversalInstTerm(ProofTerm),
542
543    /// Logic: Γ, x:T ⊢ P(x) implies Γ ⊢ ∀x:T. P(x)
544    /// Stores variable name and type name for Lambda construction.
545    UniversalIntro { variable: String, var_type: String },
546
547    /// Logic: P(w) ⊢ ∃x.P(x)
548    /// Carries the witness and its type for kernel certification.
549    ExistentialIntro {
550        witness: String,
551        witness_type: String,
552    },
553
554    // --- Modal Logic (World Moves) ---
555
556    /// Logic: □P (in w0), Accessible(w0, w1) ⊢ P (in w1)
557    /// "Necessity Elimination" / "Distribution"
558    ModalAccess,
559
560    /// Logic: If P is true in ALL accessible worlds ⊢ □P
561    /// "Necessity Introduction"
562    ModalGeneralization,
563
564    // --- Temporal Logic ---
565
566    /// Logic: t1 < t2, t2 < t3 ⊢ t1 < t3
567    TemporalTransitivity,
568
569    /// Logic: P(s₀), ∀s(P(s) → P(next(s))) ⊢ G(P)
570    /// Standard k-induction for hardware safety properties.
571    TemporalInduction,
572
573    /// Logic: G(P) ⊢ P ∧ X(G(P))
574    /// Fixpoint unfolding of Always.
575    TemporalUnfolding,
576
577    /// Logic: P(w) ⊢ F(P) for witness world w
578    /// Prove Eventually by exhibiting a reachable witness.
579    EventualityProgress,
580
581    /// Logic: Induction on trace length for P U Q
582    UntilInduction,
583
584    // --- Peano / Inductive Reasoning (CIC seed) ---
585
586    /// Logic: P(0), ∀k(P(k) → P(S(k))) ⊢ ∀n P(n)
587    /// Stores the variable name, its inductive type, and the step variable used.
588    StructuralInduction {
589        variable: String,  // "n" - the induction variable
590        ind_type: String,  // "Nat" - the inductive type
591        step_var: String,  // "k" - the predecessor variable (for IH matching)
592    },
593
594    /// Logic: generic structural induction over ANY inductive type. Generalizes
595    /// [`InferenceRule::StructuralInduction`] (fixed to the nullary-base + unary-step
596    /// Nat shape) to an arbitrary constructor set — one premise per constructor, in
597    /// registration order, each recursive argument carrying its own induction
598    /// hypothesis. Certifies to a `Fix` over an N-ary `Match`: the dependent
599    /// eliminator the kernel re-checks for coverage, case types, and termination.
600    InductionScheme {
601        variable: String,          // the induction variable, e.g. "t"
602        ind_type: String,          // the inductive type, e.g. "Tree"
603        cases: Vec<InductionCase>, // one per constructor, in registration order
604    },
605
606    // --- Linear arithmetic (order) ---
607
608    /// `a ≤ b`, `b ≤ c` ⊢ `a ≤ c` over `Int`. The middle term is recovered from
609    /// the first premise's conclusion. Certifies to `le_trans a b c p₀ p₁`.
610    /// Inequalities are encoded as the Prop `Eq Bool (le a b) true`.
611    LeTrans,
612
613    /// `⊢ a ≤ a` over `Int`. Certifies to `le_refl a`.
614    LeRefl,
615
616    /// `a ≤ b`, `c ≤ d` ⊢ `a + c ≤ b + d` over `Int`. The four operands are read
617    /// from the conclusion `le(add a c, add b d) = true`; `premise[0]` proves
618    /// `a ≤ b`, `premise[1]` proves `c ≤ d`. Certifies to `le_add_mono a b c d p₀ p₁`.
619    LeAddMono,
620
621    /// Linear contradiction: `premise[0]` proves `le(m, n) = true` for ground `m > n`
622    /// (so `le m n ⇝ false`, the Prop is `Eq Bool false true`). Concludes `⊥` via the
623    /// `Bool` no-confusion discriminator. Lets contradictory bounds prove anything.
624    LinFalse,
625
626    /// `0 ≤ k`, `a ≤ b` ⊢ `k·a ≤ k·b` — scale an inequality by a non-negative `k`.
627    /// Operands from the conclusion `le(mul k a, mul k b) = true`; `premise[0]` proves
628    /// `0 ≤ k`, `premise[1]` proves `a ≤ b`. Certifies to `le_mul_nonneg k a b p₀ p₁`.
629    /// A Farkas-reconstruction primitive.
630    LeMulNonneg,
631
632    /// `a ≤ b` ⊢ `0 ≤ b - a` — move an inequality to one side. Operands from the
633    /// conclusion `le(0, sub b a) = true`; `premise[0]` proves `a ≤ b`. Certifies to
634    /// `le_sub a b p₀`. The Farkas "collect to a single side" primitive.
635    LeSub,
636
637    /// `a < b` ⊢ `(a + 1) ≤ b` — integer DISCRETENESS. Operands from the conclusion
638    /// `le(add a 1, b) = true`; `premise[0]` proves `a < b` (`lt(a,b) = true`).
639    /// Certifies to `lt_succ_le a b p₀`. This is the one step rational Fourier-Motzkin
640    /// lacks — the `omega` primitive that refutes strict systems the rational solver
641    /// reports satisfiable.
642    LtSuccLe,
643
644    /// `a < (b + 1)` ⊢ `a ≤ b` — the upper-side discreteness companion. Operands
645    /// from the conclusion `le(a, b) = true`; `premise[0]` proves `a < b+1`
646    /// (`lt(a, add b 1) = true`). Certifies to `lt_add1_le a b p₀`. Preferred over
647    /// `LtSuccLe` when the strict bound is already `b+1`, since it cancels the
648    /// constant instead of propagating it into the Farkas reconstruction.
649    LtAdd1Le,
650
651    // --- Equality ---
652
653    /// Leibniz's Law / Substitution of Equals
654    /// Logic: a = b, P(a) ⊢ P(b)
655    /// The equality proof is in `premise\[0\]`, the P(a) proof is in `premise\[1\]`.
656    /// Carries the original term and replacement term for certification.
657    Rewrite {
658        from: ProofTerm,
659        to: ProofTerm,
660    },
661
662    /// Symmetry of Equality: a = b ⊢ b = a
663    EqualitySymmetry,
664
665    /// Transitivity of Equality: a = b, b = c ⊢ a = c
666    EqualityTransitivity,
667
668    /// Reflexivity of Equality: a = a (after normalization)
669    /// Used when both sides of an identity reduce to the same normal form.
670    Reflexivity,
671
672    /// Arithmetic decision: an `Int` equality discharged by the proof-producing
673    /// arithmetic oracle ([`crate::arith::prove_int_eq`]) into a kernel-checked
674    /// proof (computation + the ring axioms). The conclusion is the `Identity`.
675    ArithDecision,
676
677    /// Proof by kernel evaluation: a closed decidable proposition (a ground
678    /// comparison or Bool/Nat equality) discharged via `native_decide`. The
679    /// leaf carries only the claim; certification re-runs the evaluator and
680    /// the kernel checks the resulting `of_decide_eq_true`/`ofReduceBool`
681    /// term, so a lying leaf is rejected.
682    NativeDecide,
683
684    // --- Fallbacks ---
685
686    /// "The User Said So." Used for top-level axioms.
687    Axiom,
688
689    /// "The Machine Said So." (Z3 Oracle)
690    /// The string contains the solver's justification.
691    OracleVerification(String),
692
693    /// Proof by Contradiction (Reductio ad Absurdum)
694    /// Logic: Assume ¬C, derive P ∧ ¬P (contradiction), conclude C
695    /// Or: Assume P, derive Q ∧ ¬Q, conclude ¬P
696    ReductioAdAbsurdum,
697
698    /// Contradiction detected in premises: P and ¬P both hold
699    /// Logic: P, ¬P ⊢ ⊥ (ex falso quodlibet)
700    Contradiction,
701
702    // --- Quantifier Elimination ---
703
704    /// Existential Elimination (Skolemization in a proof context)
705    /// Logic: ∃x.P(x), [c fresh] P(c) ⊢ Goal implies ∃x.P(x) ⊢ Goal
706    /// The witness c must be fresh (not appearing in Goal).
707    ExistentialElim { witness: String },
708
709    /// Case Analysis on a formula `C` whose two cases both reach absurdity.
710    /// Logic: (C → ⊥), (¬C → ⊥) ⊢ ⊥ — note this is the *intuitionistic* form
711    /// (build `¬C` and `¬¬C`, then apply), so certifying it needs no excluded
712    /// middle. Used for self-referential paradoxes like the Barber Paradox.
713    ///
714    /// `case_formula` carries the actual proposition `C` (not a rendered string)
715    /// so the certifier can build the case lambdas' parameter types and bind `C`
716    /// / `¬C` as local hypotheses in each branch.
717    CaseAnalysis { case_formula: Box<ProofExpr> },
718
719    /// Logic: `A ∨ B`, `A ⊢ C`, `B ⊢ C` ⊢ `C` — disjunction elimination to a common
720    /// conclusion (here always `⊥`, for the grounded-grid contradiction prover).
721    /// Premises: `[A∨B, left-branch (C assuming A), right-branch (C assuming B)]`.
722    /// Unlike `DisjunctionElim` (disjunctive syllogism, which needs a refuted
723    /// disjunct) this eliminates BOTH disjuncts by case analysis — the move a grid's
724    /// of-pair / either-or / closure clause needs. The disjuncts (and, when a disjunct
725    /// is a conjunction, each of its conjuncts) are bound as local hypotheses in the
726    /// respective branch, so a branch may reference them directly.
727    DisjunctionCases,
728}
729
730// =============================================================================
731// DERIVATION TREE - The recursive proof structure
732// =============================================================================
733
734/// The "Euclidean Structure" - A recursive tree representing the proof.
735///
736/// This is the object returned by the Prover. It allows the UI to render
737/// a step-by-step explanation (Natural Language Generation).
738///
739/// # Structure
740///
741/// Each node contains:
742/// - `conclusion`: The proposition proved at this step
743/// - `rule`: The logical rule applied (how we know the conclusion)
744/// - `premises`: Sub-proofs justifying the rule's requirements
745/// - `substitution`: Variable bindings from unification
746///
747/// # See Also
748///
749/// * [`BackwardChainer::prove`] - Creates derivation trees
750/// * [`InferenceRule`] - The rules that justify each step
751/// * [`ProofExpr`] - The conclusion type
752/// * [`certifier::certify`] - Converts trees to kernel terms
753/// * [`hints::suggest_hint`] - Suggests next steps when stuck
754#[derive(Debug, Clone)]
755pub struct DerivationTree {
756    /// The logical statement proved at this node.
757    pub conclusion: ProofExpr,
758
759    /// The rule applied to justify this conclusion.
760    pub rule: InferenceRule,
761
762    /// The sub-proofs that validate the requirements of the rule.
763    /// Example: ModusPonens will have 2 children (The Implication, The Antecedent).
764    pub premises: Vec<DerivationTree>,
765
766    /// The depth of the tree (used for complexity limits).
767    pub depth: usize,
768
769    /// Substitution applied at this step (for unification-based rules).
770    pub substitution: unify::Substitution,
771}
772
773impl DerivationTree {
774    /// Constructs a new Proof Node.
775    /// Automatically calculates depth based on children.
776    pub fn new(
777        conclusion: ProofExpr,
778        rule: InferenceRule,
779        premises: Vec<DerivationTree>,
780    ) -> Self {
781        let max_depth = premises.iter().map(|p| p.depth).max().unwrap_or(0);
782        Self {
783            conclusion,
784            rule,
785            premises,
786            depth: max_depth + 1,
787            substitution: unify::Substitution::new(),
788        }
789    }
790
791    /// A leaf node (usually a Premise, Axiom, or Oracle result).
792    pub fn leaf(conclusion: ProofExpr, rule: InferenceRule) -> Self {
793        Self::new(conclusion, rule, vec![])
794    }
795
796    /// Set the substitution for this derivation step.
797    pub fn with_substitution(mut self, subst: unify::Substitution) -> Self {
798        self.substitution = subst;
799        self
800    }
801
802    /// Renders the proof as a text-based tree (for debugging/CLI).
803    pub fn display_tree(&self) -> String {
804        self.display_recursive(0)
805    }
806
807    fn display_recursive(&self, indent: usize) -> String {
808        let prefix = "  ".repeat(indent);
809
810        let rule_name = match &self.rule {
811            InferenceRule::UniversalInst(var) => format!("UniversalInst({})", var),
812            InferenceRule::UniversalInstTerm(term) => format!("UniversalInst({})", term),
813            InferenceRule::UniversalIntro { variable, var_type } => {
814                format!("UniversalIntro({}:{})", variable, var_type)
815            }
816            InferenceRule::ExistentialIntro { witness, witness_type } => {
817                format!("∃Intro({}:{})", witness, witness_type)
818            }
819            InferenceRule::StructuralInduction { variable, ind_type, step_var } => {
820                format!("Induction({}:{}, step={})", variable, ind_type, step_var)
821            }
822            InferenceRule::OracleVerification(s) => format!("Oracle({})", s),
823            InferenceRule::Rewrite { from, to } => format!("Rewrite({} → {})", from, to),
824            InferenceRule::EqualitySymmetry => "EqSymmetry".to_string(),
825            InferenceRule::EqualityTransitivity => "EqTransitivity".to_string(),
826            r => format!("{:?}", r),
827        };
828
829        let mut output = format!("{}└─ [{}] {}\n", prefix, rule_name, self.conclusion);
830
831        for premise in &self.premises {
832            output.push_str(&premise.display_recursive(indent + 1));
833        }
834        output
835    }
836}
837
838impl fmt::Display for DerivationTree {
839    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
840        write!(f, "{}", self.display_tree())
841    }
842}
843
844// =============================================================================
845// PROOF GOAL - The target state for backward chaining
846// =============================================================================
847
848/// The Goal State for the Backward Chainer.
849///
850/// Represents a "hole" in the proof that needs to be filled. During backward
851/// chaining, goals are decomposed into subgoals until they match known facts.
852///
853/// # Fields
854///
855/// * `target` - What we are trying to prove
856/// * `context` - Local assumptions (e.g., antecedents of implications we've entered)
857///
858/// # See Also
859///
860/// * [`BackwardChainer::prove`] - Takes a goal and produces a derivation tree
861/// * [`DerivationTree`] - The result of successfully proving a goal
862/// * [`ProofExpr`] - The target type
863#[derive(Debug, Clone)]
864pub struct ProofGoal {
865    /// What we are trying to prove right now.
866    pub target: ProofExpr,
867
868    /// The local assumptions available (e.g., inside an implication).
869    pub context: Vec<ProofExpr>,
870}
871
872impl ProofGoal {
873    pub fn new(target: ProofExpr) -> Self {
874        Self {
875            target,
876            context: Vec::new(),
877        }
878    }
879
880    pub fn with_context(target: ProofExpr, context: Vec<ProofExpr>) -> Self {
881        Self { target, context }
882    }
883}